summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2017-04-02 17:24:58 +0000
committerdim <dim@FreeBSD.org>2017-04-02 17:24:58 +0000
commit60b571e49a90d38697b3aca23020d9da42fc7d7f (patch)
tree99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/lib/Target
parentbea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff)
downloadFreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip
FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste): Add WITH_LLD_AS_LD build knob If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not capable of linking the world and kernel, but can self-host and link many substantial applications. GNU ld continues to be used for the world and kernel build, regardless of how this knob is set. It is on by default for arm64, and off for all other CPU architectures. Sponsored by: The FreeBSD Foundation MFC r310840: Reapply 310775, now it also builds correctly if lldb is disabled: Move llvm-objdump from CLANG_EXTRAS to installed by default We currently install three tools from binutils 2.17.50: as, ld, and objdump. Work is underway to migrate to a permissively-licensed tool-chain, with one goal being the retirement of binutils 2.17.50. LLVM's llvm-objdump is intended to be compatible with GNU objdump although it is currently missing some options and may have formatting differences. Enable it by default for testing and further investigation. It may later be changed to install as /usr/bin/objdump, it becomes a fully viable replacement. Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D8879 MFC r312855 (by emaste): Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC Reported by: Dan McGregor <dan.mcgregor usask.ca> MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines Don't check struct rtentry on FreeBSD, it is an internal kernel structure. On other systems it may be API structure for SIOCADDRT/SIOCDELRT. Reviewed by: emaste, dim MFC r314152 (by jkim): Remove an assembler flag, which is redundant since r309124. The upstream took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE. http://llvm.org/viewvc/llvm-project?rev=273500&view=rev Reviewed by: dim MFC r314564: Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 (branches/release_40 296509). The release will follow soon. Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11 support to build; see UPDATING for more information. Also note that as of 4.0.0, lld should be able to link the base system on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5). Though please be aware that this is work in progress. Release notes for llvm, clang and lld will be available here: <http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html> <http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html> <http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html> Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for their help. Relnotes: yes Exp-run: antoine PR: 215969, 216008 MFC r314708: For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov): [SCEV] limit recursion depth of CompareSCEVComplexity Summary: CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled loop) and runs almost infinite time. Added cache of "equal" SCEV pairs to earlier cutoff of further estimation. Recursion depth limit was also introduced as a parameter. Reviewers: sanjoy Subscribers: mzolotukhin, tstellarAMD, llvm-commits Differential Revision: https://reviews.llvm.org/D26389 This commit is the cause of excessive compile times on skein_block.c (and possibly other files) during kernel builds on amd64. We never saw the problematic behavior described in this upstream commit, so for now it is better to revert it. An upstream bug has been filed here: https://bugs.llvm.org/show_bug.cgi?id=32142 Reported by: mjg MFC r314795: Reapply r287232 from upstream llvm trunk (by Daniil Fukalov): [SCEV] limit recursion depth of CompareSCEVComplexity Summary: CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled loop) and runs almost infinite time. Added cache of "equal" SCEV pairs to earlier cutoff of further estimation. Recursion depth limit was also introduced as a parameter. Reviewers: sanjoy Subscribers: mzolotukhin, tstellarAMD, llvm-commits Differential Revision: https://reviews.llvm.org/D26389 Pull in r296992 from upstream llvm trunk (by Sanjoy Das): [SCEV] Decrease the recursion threshold for CompareValueComplexity Fixes PR32142. r287232 accidentally increased the recursion threshold for CompareValueComplexity from 2 to 32. This change reverses that change by introducing a separate flag for CompareValueComplexity's threshold. The latter revision fixes the excessive compile times for skein_block.c. MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines Unbreak ARMv6 world. The new compiler_rt library imported with clang 4.0.0 have several fatal issues (non-functional __udivsi3 for example) with ARM specific instrict functions. As temporary workaround, until upstream solve these problems, disable all thumb[1][2] related feature. MFC r315016: Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release. We were already very close to the last release candidate, so this is a pretty minor update. Relnotes: yes MFC r316005: Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by Weiming Zhao): builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA. Summary: Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation mode (-mthumb, -marm), it reflect's capability of given CPU. Due to this: - use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB - use '.thumb' directive consistently in all affected files - decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION() --------- Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 ! Reviewers: weimingz, rengolin, compnerd Subscribers: aemerson, dim Differential Revision: https://reviews.llvm.org/D30938 Discussed with: mmel
Diffstat (limited to 'contrib/llvm/lib/Target')
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64.h16
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64.td89
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp11
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64A57FPLoadBalancing.cpp8
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64AddressTypePromotion.cpp14
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64AdvSIMDScalarPass.cpp8
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp99
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64BranchRelaxation.cpp520
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64CallLowering.cpp329
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64CallLowering.h28
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64CallingConvention.td15
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp13
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp1129
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp10
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp14
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp136
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp25
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64FastISel.cpp123
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp77
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64GenRegisterBankInfo.def296
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp77
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp837
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.h45
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td14
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstrFormats.td23
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp466
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h65
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.td70
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp1165
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.h49
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp204
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.h30
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp405
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp7
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h50
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64PromoteConstant.cpp10
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp19
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp470
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.h39
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp45
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.h10
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.td2
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td22
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64SchedA57WriteRes.td14
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64SchedFalkor.td26
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64SchedM1.td98
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64SchedVulcan.td13
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64StorePairSuppress.cpp13
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64Subtarget.cpp23
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64Subtarget.h30
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp262
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.h2
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp13
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h4
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp35
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h12
-rw-r--r--contrib/llvm/lib/Target/AArch64/AArch64VectorByElementOpt.cpp371
-rw-r--r--contrib/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp621
-rw-r--r--contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp24
-rw-r--r--contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h10
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp33
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp213
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp3
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp52
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp16
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h16
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp2
-rw-r--r--contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp3
-rw-r--r--contrib/llvm/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp25
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPU.h33
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPU.td166
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp14
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp8
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp100
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp425
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h33
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp8
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.h6
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp301
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.cpp22
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.h9
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp324
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp1078
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h85
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp5
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.h18
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td77
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td125
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUIntrinsics.td5
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp137
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.h15
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.cpp44
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h47
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp2
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUPTNote.h42
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp31
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h203
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp189
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h254
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp169
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h23
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp13
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.h3
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp5
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h12
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp149
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp49
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp1626
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td1350
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/CIInstructions.td336
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/CaymanInstructions.td139
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/DSInstructions.td906
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp238
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h173
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/EvergreenInstructions.td143
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td530
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp258
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h9
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp312
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h54
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp485
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h200
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp137
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUELFObjectWriter.cpp26
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h13
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp13
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.h11
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp408
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.h26
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp306
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h37
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp18
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp129
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/MIMGInstructions.td763
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Processors.td70
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp4
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp38
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp4
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp81
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.cpp3
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.h12
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp688
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600InstrFormats.td4
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.cpp66
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.h27
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600Instructions.td83
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.h7
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600MachineScheduler.h20
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp75
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/R600Packetizer.cpp6
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIAnnotateControlFlow.cpp11
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIDebuggerInsertNops.cpp2
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIDefines.h196
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp4
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp160
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp668
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp455
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h30
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp1954
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h44
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInsertSkips.cpp329
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInsertWaits.cpp130
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInstrFormats.td716
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp1260
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h214
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td3192
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIInstructions.td3193
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIIntrinsics.td29
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp300
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp930
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp32
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp57
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h142
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.cpp80
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.h58
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIOptimizeExecMasking.cpp304
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp1233
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h152
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.td178
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SISchedule.td6
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp208
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SITypeRewriter.cpp4
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp424
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SMInstructions.td535
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/SOPInstructions.td1232
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/TargetInfo/AMDGPUTargetInfo.cpp17
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp282
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h151
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTInfo.h131
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTUtils.cpp29
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VIInstrFormats.td277
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VIInstructions.td150
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td615
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td757
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VOP3Instructions.td451
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td1144
-rw-r--r--contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td350
-rw-r--r--contrib/llvm/lib/Target/ARM/A15SDOptimizer.cpp4
-rw-r--r--contrib/llvm/lib/Target/ARM/ARM.h5
-rw-r--r--contrib/llvm/lib/Target/ARM/ARM.td84
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp247
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMAsmPrinter.h27
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp91
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.h16
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp63
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h3
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMBasicBlockInfo.h110
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMCallLowering.cpp203
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMCallLowering.h42
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMCallingConv.td29
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMComputeBlockSize.cpp72
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp295
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp33
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.h31
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp45
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMFastISel.cpp51
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp333
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp362
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp1020
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMISelLowering.h60
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrFormats.td17
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrInfo.td57
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrNEON.td14
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrThumb.td105
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td525
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstrVFP.td8
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp109
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMInstructionSelector.h39
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp44
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.h29
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp14
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMMCInstLower.cpp75
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp12
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h25
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMOptimizeBarriersPass.cpp6
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp150
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.h41
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMSchedule.td1
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMScheduleR52.td983
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMSubtarget.cpp71
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMSubtarget.h44
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp105
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp45
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.h17
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp31
-rw-r--r--contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.h23
-rw-r--r--contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp1384
-rw-r--r--contrib/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp14
-rw-r--r--contrib/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp6
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp58
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp29
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp4
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp1
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp11
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp21
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h20
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp2
-rw-r--r--contrib/llvm/lib/Target/ARM/MLxExpansionPass.cpp13
-rw-r--r--contrib/llvm/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp34
-rw-r--r--contrib/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp323
-rw-r--r--contrib/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/ARM/Thumb2ITBlockPass.cpp4
-rw-r--r--contrib/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/ARM/Thumb2SizeReduction.cpp10
-rw-r--r--contrib/llvm/lib/Target/ARM/ThumbRegisterInfo.cpp16
-rw-r--r--contrib/llvm/lib/Target/AVR/AVR.h6
-rw-r--r--contrib/llvm/lib/Target/AVR/AVR.td526
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp184
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRCallingConv.td11
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRDevices.td491
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp1515
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp538
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp565
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp1978
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRISelLowering.h18
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrFormats.td2
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp82
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrInfo.h12
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrInfo.td114
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp222
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp100
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRMCInstLower.h43
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp20
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h6
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp149
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp25
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp9
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h3
-rw-r--r--contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp631
-rw-r--r--contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp156
-rw-r--r--contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp171
-rw-r--r--contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h54
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp473
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h78
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp127
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h149
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp304
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h115
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp189
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h88
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp121
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h6
-rw-r--r--contrib/llvm/lib/Target/AVR/README.md8
-rw-r--r--contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp14
-rw-r--r--contrib/llvm/lib/Target/BPF/BPF.td6
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFAsmPrinter.cpp8
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp2
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFInstrInfo.cpp30
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFInstrInfo.h8
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFInstrInfo.td114
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFRegisterInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/BPF/BPFTargetMachine.cpp6
-rw-r--r--contrib/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp154
-rw-r--r--contrib/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp18
-rw-r--r--contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp26
-rw-r--r--contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp19
-rw-r--r--contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h9
-rw-r--r--contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp38
-rw-r--r--contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp36
-rw-r--r--contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h13
-rw-r--r--contrib/llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp26
-rw-r--r--contrib/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp402
-rw-r--r--contrib/llvm/lib/Target/Hexagon/BitTracker.cpp89
-rw-r--r--contrib/llvm/lib/Target/Hexagon/BitTracker.h56
-rw-r--r--contrib/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp752
-rw-r--r--contrib/llvm/lib/Target/Hexagon/Hexagon.td20
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp73
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h2
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonBitSimplify.cpp539
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.cpp109
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.h22
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.cpp74
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.h49
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp46
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp20
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonCommonGEP.cpp196
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonConstPropagation.cpp3149
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonCopyToCombine.cpp95
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp266
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp390
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp8
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp689
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.h17
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonGenExtract.cpp49
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonGenInsert.cpp199
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp75
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonGenPredicate.cpp81
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonHardwareLoops.cpp143
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.cpp140
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.h78
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp1226
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp731
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.h50
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrAlias.td64
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrFormats.td5
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV4.td4
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV60.td4
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp1609
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.h254
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.td1167
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV3.td72
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV4.td1289
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV5.td568
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV60.td399
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoVector.td420
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonIntrinsics.td57
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td18
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV4.td18
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV60.td81
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonIsetDx.td138
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonMachineFunctionInfo.h35
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp18
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.h4
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp60
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonOperands.td365
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp125
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonOptimizeSZextends.cpp7
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonPatterns.td3347
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp19
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonRDF.cpp60
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonRDF.h28
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonRDFOpt.cpp46
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp27
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.h9
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.td33
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSelectCCInfo.td121
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.cpp7
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.h2
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSplitConst32AndConst64.cpp126
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSplitDouble.cpp120
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonStoreWidening.cpp70
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp72
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h13
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonSystemInst.td2
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp38
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp126
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.h18
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.cpp33
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.h13
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp446
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.h44
-rw-r--r--contrib/llvm/lib/Target/Hexagon/HexagonVectorPrint.cpp209
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp7
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h9
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp1
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp4
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h5
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp51
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp240
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp23
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h17
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp111
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h3
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp58
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h20
-rw-r--r--contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp10
-rw-r--r--contrib/llvm/lib/Target/Hexagon/RDFCopy.cpp69
-rw-r--r--contrib/llvm/lib/Target/Hexagon/RDFCopy.h20
-rw-r--r--contrib/llvm/lib/Target/Hexagon/RDFGraph.cpp715
-rw-r--r--contrib/llvm/lib/Target/Hexagon/RDFGraph.h344
-rw-r--r--contrib/llvm/lib/Target/Hexagon/RDFLiveness.cpp538
-rw-r--r--contrib/llvm/lib/Target/Hexagon/RDFLiveness.h44
-rw-r--r--contrib/llvm/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp8
-rw-r--r--contrib/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp54
-rw-r--r--contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp10
-rw-r--r--contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.h7
-rw-r--r--contrib/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h13
-rw-r--r--contrib/llvm/lib/Target/Lanai/Lanai.h2
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiAluCode.h4
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp8
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp15
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiFrameLowering.cpp32
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiISelDAGToDAG.cpp26
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiISelLowering.cpp117
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiISelLowering.h1
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp19
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.h10
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.td8
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.cpp1
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.h3
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiMemAluCombiner.cpp7
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp8
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.h9
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp3
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp51
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h14
-rw-r--r--contrib/llvm/lib/Target/Lanai/LanaiTargetTransformInfo.h8
-rw-r--r--contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp8
-rw-r--r--contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp12
-rw-r--r--contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp46
-rw-r--r--contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp44
-rw-r--r--contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h6
-rw-r--r--contrib/llvm/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp9
-rw-r--r--contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.cpp11
-rw-r--r--contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.h2
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430AsmPrinter.cpp6
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp308
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp26
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp2
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp35
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp21
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h12
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp2
-rw-r--r--contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp11
-rw-r--r--contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp1127
-rw-r--r--contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp184
-rw-r--r--contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp1
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp7
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp26
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h7
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp21
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h4
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp9
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp40
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h7
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp17
-rw-r--r--contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h21
-rw-r--r--contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td579
-rw-r--r--contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td46
-rw-r--r--contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td117
-rw-r--r--contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td128
-rw-r--r--contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td31
-rw-r--r--contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td280
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips.td6
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp28
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp4
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp7
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp14
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td16
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td192
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td81
-rw-r--r--contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td60
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp49
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h5
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp27
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp62
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td4
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsFastISel.cpp241
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp26
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsHazardSchedule.cpp75
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp22
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h15
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp132
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsISelLowering.h7
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsInstrFPU.td252
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsInstrFormats.td12
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp85
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsInstrInfo.h12
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsInstrInfo.td322
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp12
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td90
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp8
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp2
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp2
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsOs16.cpp4
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp6
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td6
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp62
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp84
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h21
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp520
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h14
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp41
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp8
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsSchedule.td83
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsScheduleGeneric.td1048
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td254
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp17
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp48
-rw-r--r--contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h16
-rw-r--r--contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp31
-rw-r--r--contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXBaseInfo.h58
-rw-r--r--contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.cpp2
-rw-r--r--contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.h4
-rw-r--r--contrib/llvm/lib/Target/NVPTX/ManagedStringPool.h7
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTX.h7
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTX.td9
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXAllocaHoisting.cpp4
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp218
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h60
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp289
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp2
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp37
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp59
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.h2
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp289
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.h3
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp3
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.cpp28
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.h9
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td163
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td196
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXLowerAggrCopies.cpp4
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXLowerAlloca.cpp8
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXLowerArgs.cpp (renamed from contrib/llvm/lib/Target/NVPTX/NVPTXLowerKernelArgs.cpp)85
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXMCExpr.cpp4
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXPeephole.cpp2
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp52
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp26
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp2
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXSection.h10
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp2
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.h8
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp77
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h16
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp25
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h10
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp247
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.h61
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVVMIntrRange.cpp4
-rw-r--r--contrib/llvm/lib/Target/NVPTX/NVVMReflect.cpp1
-rw-r--r--contrib/llvm/lib/Target/NVPTX/TargetInfo/NVPTXTargetInfo.cpp14
-rw-r--r--contrib/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp369
-rw-r--r--contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp39
-rw-r--r--contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp61
-rw-r--r--contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h1
-rw-r--r--contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp3
-rw-r--r--contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp22
-rw-r--r--contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp3
-rw-r--r--contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h10
-rw-r--r--contrib/llvm/lib/Target/PowerPC/P9InstrResources.td808
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPC.td6
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp209
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp80
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCBranchSelector.cpp81
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCCTRLoops.cpp8
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCCallingConv.td26
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp4
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCFastISel.cpp85
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp212
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCHazardRecognizers.cpp2
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp222
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp955
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCISelLowering.h78
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td13
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrAltivec.td142
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrFormats.td65
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp262
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h29
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td156
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrQPX.td10
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCInstrVSX.td775
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp38
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp8
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp164
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCQPXLoadSplat.cpp2
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp31
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.h2
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.td35
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCSchedule.td4
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCScheduleE500mc.td8
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCScheduleE5500.td10
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCScheduleP9.td335
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCSubtarget.h3
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp26
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp27
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.cpp8
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.h3
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp28
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h10
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCVSXCopy.cpp42
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCVSXFMAMutate.cpp78
-rw-r--r--contrib/llvm/lib/Target/PowerPC/PPCVSXSwapRemoval.cpp3
-rw-r--r--contrib/llvm/lib/Target/PowerPC/TargetInfo/PowerPCTargetInfo.cpp25
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp91
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp47
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp25
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h31
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp91
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp59
-rw-r--r--contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h58
-rw-r--r--contrib/llvm/lib/Target/RISCV/RISCV.td27
-rw-r--r--contrib/llvm/lib/Target/RISCV/RISCVInstrFormats.td152
-rw-r--r--contrib/llvm/lib/Target/RISCV/RISCVInstrInfo.td55
-rw-r--r--contrib/llvm/lib/Target/RISCV/RISCVRegisterInfo.td90
-rw-r--r--contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp58
-rw-r--r--contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.h40
-rw-r--r--contrib/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp30
-rw-r--r--contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp32
-rw-r--r--contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp6
-rw-r--r--contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp10
-rwxr-xr-xcontrib/llvm/lib/Target/Sparc/LeonFeatures.td131
-rwxr-xr-xcontrib/llvm/lib/Target/Sparc/LeonPasses.cpp645
-rwxr-xr-xcontrib/llvm/lib/Target/Sparc/LeonPasses.h114
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp3
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp17
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp15
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h10
-rw-r--r--contrib/llvm/lib/Target/Sparc/Sparc.td147
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp10
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp49
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp21
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp151
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp46
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h10
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td24
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td1
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp9
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcSubtarget.h20
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp57
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp13
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h10
-rw-r--r--contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp21
-rw-r--r--contrib/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp590
-rw-r--r--contrib/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp45
-rw-r--r--contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp19
-rw-r--r--contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h3
-rw-r--r--contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp12
-rw-r--r--contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp41
-rw-r--r--contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h4
-rw-r--r--contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp4
-rw-r--r--contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp24
-rw-r--r--contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h7
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZ.h1
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZ.td14
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp6
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h4
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp92
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZExpandPseudo.cpp153
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZFeatures.td171
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp40
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp337
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.h128
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp148
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp156
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h10
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h4
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td250
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td2023
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp341
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h54
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td1223
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZInstrVector.td237
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZLDCleanup.cpp2
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp10
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp153
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h112
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZOperands.td47
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZOperators.td24
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZProcessors.td103
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp5
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td28
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZSchedule.td77
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td1064
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td769
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td807
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZShortenInst.cpp6
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp8
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h17
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp26
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp57
-rw-r--r--contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.h9
-rw-r--r--contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp9
-rw-r--r--contrib/llvm/lib/Target/TargetIntrinsicInfo.cpp2
-rw-r--r--contrib/llvm/lib/Target/TargetLoweringObjectFile.cpp61
-rw-r--r--contrib/llvm/lib/Target/TargetMachine.cpp41
-rw-r--r--contrib/llvm/lib/Target/TargetMachineC.cpp9
-rw-r--r--contrib/llvm/lib/Target/TargetRecip.cpp225
-rw-r--r--contrib/llvm/lib/Target/TargetSubtargetInfo.cpp54
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp9
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp60
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp6
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp58
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp16
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h84
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp56
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h19
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/README.txt52
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.cpp14
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssembly.h7
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssembly.td2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyArgumentMove.cpp25
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp92
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp148
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp120
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp308
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp164
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp166
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp104
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h1
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp43
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td76
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td49
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td54
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td44
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td67
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp26
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h10
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td98
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td64
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td627
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td7
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp6
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp1184
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp37
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h26
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp53
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp28
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp22
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp139
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp22
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td10
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp6
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp47
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp26
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp59
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp2
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h10
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp71
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h34
-rw-r--r--contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt1
-rw-r--r--contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp585
-rw-r--r--contrib/llvm/lib/Target/X86/AsmParser/X86Operand.h4
-rw-r--r--contrib/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp24
-rw-r--r--contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp12
-rw-r--r--contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h2
-rw-r--r--contrib/llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp3
-rw-r--r--contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.cpp254
-rw-r--r--contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.h5
-rw-r--r--contrib/llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp3
-rw-r--r--contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp18
-rw-r--r--contrib/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h244
-rw-r--r--contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp3
-rw-r--r--contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp195
-rw-r--r--contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp6
-rw-r--r--contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h10
-rw-r--r--contrib/llvm/lib/Target/X86/TargetInfo/X86TargetInfo.cpp17
-rw-r--r--contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.cpp26
-rw-r--r--contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.h2
-rw-r--r--contrib/llvm/lib/Target/X86/X86.h7
-rw-r--r--contrib/llvm/lib/Target/X86/X86.td75
-rw-r--r--contrib/llvm/lib/Target/X86/X86AsmPrinter.cpp18
-rw-r--r--contrib/llvm/lib/Target/X86/X86AsmPrinter.h27
-rw-r--r--contrib/llvm/lib/Target/X86/X86CallFrameOptimization.cpp14
-rw-r--r--contrib/llvm/lib/Target/X86/X86CallLowering.cpp46
-rw-r--r--contrib/llvm/lib/Target/X86/X86CallLowering.h39
-rw-r--r--contrib/llvm/lib/Target/X86/X86CallingConv.cpp208
-rw-r--r--contrib/llvm/lib/Target/X86/X86CallingConv.h38
-rw-r--r--contrib/llvm/lib/Target/X86/X86CallingConv.td276
-rwxr-xr-xcontrib/llvm/lib/Target/X86/X86EvexToVex.cpp213
-rw-r--r--contrib/llvm/lib/Target/X86/X86ExpandPseudo.cpp24
-rw-r--r--contrib/llvm/lib/Target/X86/X86FastISel.cpp331
-rw-r--r--contrib/llvm/lib/Target/X86/X86FixupBWInsts.cpp10
-rw-r--r--contrib/llvm/lib/Target/X86/X86FixupLEAs.cpp4
-rw-r--r--contrib/llvm/lib/Target/X86/X86FixupSetCC.cpp5
-rw-r--r--contrib/llvm/lib/Target/X86/X86FloatingPoint.cpp51
-rw-r--r--contrib/llvm/lib/Target/X86/X86FrameLowering.cpp273
-rw-r--r--contrib/llvm/lib/Target/X86/X86FrameLowering.h30
-rw-r--r--contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp140
-rw-r--r--contrib/llvm/lib/Target/X86/X86ISelLowering.cpp8595
-rw-r--r--contrib/llvm/lib/Target/X86/X86ISelLowering.h209
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrAVX512.td3131
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrArithmetic.td2
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrBuilder.h74
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrCompiler.td74
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrControl.td22
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrFMA.td176
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrFMA3Info.cpp285
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrFMA3Info.h315
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrFPStack.td12
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrFormats.td149
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td311
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrInfo.cpp3727
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrInfo.h76
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrInfo.td47
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrMMX.td9
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrSSE.td2029
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrShiftRotate.td37
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrSystem.td9
-rwxr-xr-xcontrib/llvm/lib/Target/X86/X86InstrTablesInfo.h1162
-rw-r--r--contrib/llvm/lib/Target/X86/X86InstrXOP.td87
-rw-r--r--contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp221
-rw-r--r--contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h782
-rw-r--r--contrib/llvm/lib/Target/X86/X86MCInstLower.cpp264
-rw-r--r--contrib/llvm/lib/Target/X86/X86OptimizeLEAs.cpp18
-rw-r--r--contrib/llvm/lib/Target/X86/X86PadShortFunction.cpp4
-rw-r--r--contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp133
-rw-r--r--contrib/llvm/lib/Target/X86/X86RegisterInfo.h5
-rw-r--r--contrib/llvm/lib/Target/X86/X86RegisterInfo.td2
-rw-r--r--contrib/llvm/lib/Target/X86/X86SelectionDAGInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.cpp403
-rw-r--r--contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.h4
-rw-r--r--contrib/llvm/lib/Target/X86/X86Subtarget.cpp28
-rw-r--r--contrib/llvm/lib/Target/X86/X86Subtarget.h38
-rw-r--r--contrib/llvm/lib/Target/X86/X86TargetMachine.cpp105
-rw-r--r--contrib/llvm/lib/Target/X86/X86TargetMachine.h2
-rw-r--r--contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp34
-rw-r--r--contrib/llvm/lib/Target/X86/X86TargetObjectFile.h24
-rw-r--r--contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp1144
-rw-r--r--contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h22
-rw-r--r--contrib/llvm/lib/Target/X86/X86VZeroUpper.cpp4
-rw-r--r--contrib/llvm/lib/Target/X86/X86WinAllocaExpander.cpp3
-rw-r--r--contrib/llvm/lib/Target/X86/X86WinEHState.cpp2
-rw-r--r--contrib/llvm/lib/Target/XCore/Disassembler/XCoreDisassembler.cpp4
-rw-r--r--contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp16
-rw-r--r--contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.h3
-rw-r--r--contrib/llvm/lib/Target/XCore/TargetInfo/XCoreTargetInfo.cpp7
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreAsmPrinter.cpp16
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreFrameLowering.cpp110
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp12
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreISelDAGToDAG.cpp2
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreISelLowering.cpp20
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreInstrInfo.cpp32
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreInstrInfo.h10
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreInstrInfo.td8
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreMCInstLower.cpp7
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreMCInstLower.h3
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreMachineFunctionInfo.cpp18
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreRegisterInfo.cpp4
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreSelectionDAGInfo.cpp2
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreTargetMachine.cpp2
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp20
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.h6
-rw-r--r--contrib/llvm/lib/Target/XCore/XCoreTargetTransformInfo.h7
884 files changed, 101757 insertions, 45299 deletions
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64.h b/contrib/llvm/lib/Target/AArch64/AArch64.h
index c767c75..fd106a8 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64.h
@@ -30,12 +30,12 @@ FunctionPass *createAArch64DeadRegisterDefinitions();
FunctionPass *createAArch64RedundantCopyEliminationPass();
FunctionPass *createAArch64ConditionalCompares();
FunctionPass *createAArch64AdvSIMDScalar();
-FunctionPass *createAArch64BranchRelaxation();
FunctionPass *createAArch64ISelDag(AArch64TargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createAArch64StorePairSuppressPass();
FunctionPass *createAArch64ExpandPseudoPass();
FunctionPass *createAArch64LoadStoreOptimizationPass();
+FunctionPass *createAArch64VectorByElementOptPass();
ModulePass *createAArch64PromoteConstantPass();
FunctionPass *createAArch64ConditionOptimizerPass();
FunctionPass *createAArch64AddressTypePromotionPass();
@@ -46,7 +46,21 @@ FunctionPass *createAArch64CleanupLocalDynamicTLSPass();
FunctionPass *createAArch64CollectLOHPass();
+void initializeAArch64A53Fix835769Pass(PassRegistry&);
+void initializeAArch64A57FPLoadBalancingPass(PassRegistry&);
+void initializeAArch64AddressTypePromotionPass(PassRegistry&);
+void initializeAArch64AdvSIMDScalarPass(PassRegistry&);
+void initializeAArch64CollectLOHPass(PassRegistry&);
+void initializeAArch64ConditionalComparesPass(PassRegistry&);
+void initializeAArch64ConditionOptimizerPass(PassRegistry&);
+void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry&);
void initializeAArch64ExpandPseudoPass(PassRegistry&);
+void initializeAArch64LoadStoreOptPass(PassRegistry&);
+void initializeAArch64VectorByElementOptPass(PassRegistry&);
+void initializeAArch64PromoteConstantPass(PassRegistry&);
+void initializeAArch64RedundantCopyEliminationPass(PassRegistry&);
+void initializeAArch64StorePairSuppressPass(PassRegistry&);
+void initializeLDTLSCleanupPass(PassRegistry&);
} // end namespace llvm
#endif
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64.td b/contrib/llvm/lib/Target/AArch64/AArch64.td
index b97a0f1..91c335f 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64.td
@@ -35,6 +35,9 @@ def FeatureCRC : SubtargetFeature<"crc", "HasCRC", "true",
def FeatureRAS : SubtargetFeature<"ras", "HasRAS", "true",
"Enable ARMv8 Reliability, Availability and Serviceability Extensions">;
+def FeatureLSE : SubtargetFeature<"lse", "HasLSE", "true",
+ "Enable ARMv8.1 Large System Extension (LSE) atomic instructions">;
+
def FeaturePerfMon : SubtargetFeature<"perfmon", "HasPerfMon", "true",
"Enable ARMv8 PMUv3 Performance Monitors extension">;
@@ -61,10 +64,6 @@ def FeatureReserveX18 : SubtargetFeature<"reserve-x18", "ReserveX18", "true",
"Reserve X18, making it unavailable "
"as a GPR">;
-def FeatureMergeNarrowLd : SubtargetFeature<"merge-narrow-ld",
- "MergeNarrowLoads", "true",
- "Merge narrow load instructions">;
-
def FeatureUseAA : SubtargetFeature<"use-aa", "UseAA", "true",
"Use alias analysis during codegen">;
@@ -86,31 +85,35 @@ def FeaturePostRAScheduler : SubtargetFeature<"use-postra-scheduler",
def FeatureSlowMisaligned128Store : SubtargetFeature<"slow-misaligned-128store",
"Misaligned128StoreIsSlow", "true", "Misaligned 128 bit stores are slow">;
-def FeatureAvoidQuadLdStPairs : SubtargetFeature<"no-quad-ldst-pairs",
- "AvoidQuadLdStPairs", "true",
- "Do not form quad load/store pair operations">;
+def FeatureSlowPaired128 : SubtargetFeature<"slow-paired-128",
+ "Paired128IsSlow", "true", "Paired 128 bit loads and stores are slow">;
def FeatureAlternateSExtLoadCVTF32Pattern : SubtargetFeature<
"alternate-sextload-cvt-f32-pattern", "UseAlternateSExtLoadCVTF32Pattern",
"true", "Use alternative pattern for sextload convert to f32">;
-def FeatureMacroOpFusion : SubtargetFeature<
- "macroop-fusion", "HasMacroOpFusion", "true",
- "CPU supports macro op fusion">;
+def FeatureArithmeticBccFusion : SubtargetFeature<
+ "arith-bcc-fusion", "HasArithmeticBccFusion", "true",
+ "CPU fuses arithmetic+bcc operations">;
+
+def FeatureArithmeticCbzFusion : SubtargetFeature<
+ "arith-cbz-fusion", "HasArithmeticCbzFusion", "true",
+ "CPU fuses arithmetic + cbz/cbnz operations">;
def FeatureDisableLatencySchedHeuristic : SubtargetFeature<
"disable-latency-sched-heuristic", "DisableLatencySchedHeuristic", "true",
"Disable latency scheduling heuristic">;
def FeatureUseRSqrt : SubtargetFeature<
- "use-reverse-square-root", "UseRSqrt", "true", "Use reverse square root">;
+ "use-reciprocal-square-root", "UseRSqrt", "true",
+ "Use the reciprocal square root approximation">;
//===----------------------------------------------------------------------===//
// Architectures.
//
def HasV8_1aOps : SubtargetFeature<"v8.1a", "HasV8_1aOps", "true",
- "Support ARM v8.1a instructions", [FeatureCRC]>;
+ "Support ARM v8.1a instructions", [FeatureCRC, FeatureLSE]>;
def HasV8_2aOps : SubtargetFeature<"v8.2a", "HasV8_2aOps", "true",
"Support ARM v8.2a instructions", [HasV8_1aOps, FeatureRAS]>;
@@ -143,8 +146,9 @@ include "AArch64SystemOperands.td"
include "AArch64SchedA53.td"
include "AArch64SchedA57.td"
include "AArch64SchedCyclone.td"
-include "AArch64SchedM1.td"
+include "AArch64SchedFalkor.td"
include "AArch64SchedKryo.td"
+include "AArch64SchedM1.td"
include "AArch64SchedVulcan.td"
def ProcA35 : SubtargetFeature<"a35", "ARMProcFamily", "CortexA35",
@@ -176,7 +180,6 @@ def ProcA57 : SubtargetFeature<"a57", "ARMProcFamily", "CortexA57",
FeatureCrypto,
FeatureCustomCheapAsMoveHandling,
FeatureFPARMv8,
- FeatureMergeNarrowLd,
FeatureNEON,
FeaturePerfMon,
FeaturePostRAScheduler,
@@ -207,7 +210,8 @@ def ProcCyclone : SubtargetFeature<"cyclone", "ARMProcFamily", "Cyclone",
FeatureCrypto,
FeatureDisableLatencySchedHeuristic,
FeatureFPARMv8,
- FeatureMacroOpFusion,
+ FeatureArithmeticBccFusion,
+ FeatureArithmeticCbzFusion,
FeatureNEON,
FeaturePerfMon,
FeatureSlowMisaligned128Store,
@@ -216,17 +220,31 @@ def ProcCyclone : SubtargetFeature<"cyclone", "ARMProcFamily", "Cyclone",
]>;
def ProcExynosM1 : SubtargetFeature<"exynosm1", "ARMProcFamily", "ExynosM1",
- "Samsung Exynos-M1 processors", [
- FeatureAvoidQuadLdStPairs,
- FeatureCRC,
- FeatureCrypto,
- FeatureCustomCheapAsMoveHandling,
- FeatureFPARMv8,
- FeatureNEON,
- FeaturePerfMon,
- FeaturePostRAScheduler,
- FeatureUseRSqrt
- ]>;
+ "Samsung Exynos-M1 processors",
+ [FeatureSlowPaired128,
+ FeatureCRC,
+ FeatureCrypto,
+ FeatureCustomCheapAsMoveHandling,
+ FeatureFPARMv8,
+ FeatureNEON,
+ FeaturePerfMon,
+ FeaturePostRAScheduler,
+ FeatureSlowMisaligned128Store,
+ FeatureUseRSqrt,
+ FeatureZCZeroing]>;
+
+def ProcExynosM2 : SubtargetFeature<"exynosm2", "ARMProcFamily", "ExynosM1",
+ "Samsung Exynos-M2/M3 processors",
+ [FeatureSlowPaired128,
+ FeatureCRC,
+ FeatureCrypto,
+ FeatureCustomCheapAsMoveHandling,
+ FeatureFPARMv8,
+ FeatureNEON,
+ FeaturePerfMon,
+ FeaturePostRAScheduler,
+ FeatureSlowMisaligned128Store,
+ FeatureZCZeroing]>;
def ProcKryo : SubtargetFeature<"kryo", "ARMProcFamily", "Kryo",
"Qualcomm Kryo processors", [
@@ -234,7 +252,19 @@ def ProcKryo : SubtargetFeature<"kryo", "ARMProcFamily", "Kryo",
FeatureCrypto,
FeatureCustomCheapAsMoveHandling,
FeatureFPARMv8,
- FeatureMergeNarrowLd,
+ FeatureNEON,
+ FeaturePerfMon,
+ FeaturePostRAScheduler,
+ FeaturePredictableSelectIsExpensive,
+ FeatureZCZeroing
+ ]>;
+
+def ProcFalkor : SubtargetFeature<"falkor", "ARMProcFamily", "Falkor",
+ "Qualcomm Falkor processors", [
+ FeatureCRC,
+ FeatureCrypto,
+ FeatureCustomCheapAsMoveHandling,
+ FeatureFPARMv8,
FeatureNEON,
FeaturePerfMon,
FeaturePostRAScheduler,
@@ -247,7 +277,7 @@ def ProcVulcan : SubtargetFeature<"vulcan", "ARMProcFamily", "Vulcan",
FeatureCRC,
FeatureCrypto,
FeatureFPARMv8,
- FeatureMacroOpFusion,
+ FeatureArithmeticBccFusion,
FeatureNEON,
FeaturePostRAScheduler,
FeaturePredictableSelectIsExpensive,
@@ -270,6 +300,9 @@ def : ProcessorModel<"cortex-a72", CortexA57Model, [ProcA72]>;
def : ProcessorModel<"cortex-a73", CortexA57Model, [ProcA73]>;
def : ProcessorModel<"cyclone", CycloneModel, [ProcCyclone]>;
def : ProcessorModel<"exynos-m1", ExynosM1Model, [ProcExynosM1]>;
+def : ProcessorModel<"exynos-m2", ExynosM1Model, [ProcExynosM2]>;
+def : ProcessorModel<"exynos-m3", ExynosM1Model, [ProcExynosM2]>;
+def : ProcessorModel<"falkor", FalkorModel, [ProcFalkor]>;
def : ProcessorModel<"kryo", KryoModel, [ProcKryo]>;
def : ProcessorModel<"vulcan", VulcanModel, [ProcVulcan]>;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp b/contrib/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp
index c2cca63..e6afb42 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp
@@ -82,16 +82,18 @@ class AArch64A53Fix835769 : public MachineFunctionPass {
public:
static char ID;
- explicit AArch64A53Fix835769() : MachineFunctionPass(ID) {}
+ explicit AArch64A53Fix835769() : MachineFunctionPass(ID) {
+ initializeAArch64A53Fix835769Pass(*PassRegistry::getPassRegistry());
+ }
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Workaround A53 erratum 835769 pass";
}
@@ -107,6 +109,9 @@ char AArch64A53Fix835769::ID = 0;
} // end anonymous namespace
+INITIALIZE_PASS(AArch64A53Fix835769, "aarch64-fix-cortex-a53-835769-pass",
+ "AArch64 fix for A53 erratum 835769", false, false)
+
//===----------------------------------------------------------------------===//
bool
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64A57FPLoadBalancing.cpp b/contrib/llvm/lib/Target/AArch64/AArch64A57FPLoadBalancing.cpp
index 0465e59..0aa597b 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64A57FPLoadBalancing.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64A57FPLoadBalancing.cpp
@@ -95,10 +95,6 @@ static bool isMla(MachineInstr *MI) {
}
}
-namespace llvm {
-static void initializeAArch64A57FPLoadBalancingPass(PassRegistry &);
-}
-
//===----------------------------------------------------------------------===//
namespace {
@@ -126,10 +122,10 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "A57 FP Anti-dependency breaker";
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64AddressTypePromotion.cpp b/contrib/llvm/lib/Target/AArch64/AArch64AddressTypePromotion.cpp
index 4846ef0..0cbb2db 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64AddressTypePromotion.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64AddressTypePromotion.cpp
@@ -47,10 +47,6 @@ using namespace llvm;
#define DEBUG_TYPE "aarch64-type-promotion"
static cl::opt<bool>
-EnableAddressTypePromotion("aarch64-type-promotion", cl::Hidden,
- cl::desc("Enable the type promotion pass"),
- cl::init(true));
-static cl::opt<bool>
EnableMerge("aarch64-type-promotion-merge", cl::Hidden,
cl::desc("Enable merging of redundant sexts when one is dominating"
" the other."),
@@ -62,10 +58,6 @@ EnableMerge("aarch64-type-promotion-merge", cl::Hidden,
// AArch64AddressTypePromotion
//===----------------------------------------------------------------------===//
-namespace llvm {
-void initializeAArch64AddressTypePromotionPass(PassRegistry &);
-}
-
namespace {
class AArch64AddressTypePromotion : public FunctionPass {
@@ -76,9 +68,7 @@ public:
initializeAArch64AddressTypePromotionPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
- return AARCH64_TYPE_PROMO_NAME;
- }
+ StringRef getPassName() const override { return AARCH64_TYPE_PROMO_NAME; }
/// Iterate over the functions and promote the computation of interesting
// sext instructions.
@@ -481,7 +471,7 @@ bool AArch64AddressTypePromotion::runOnFunction(Function &F) {
if (skipFunction(F))
return false;
- if (!EnableAddressTypePromotion || F.isDeclaration())
+ if (F.isDeclaration())
return false;
Func = &F;
ConsideredSExtType = Type::getInt64Ty(Func->getContext());
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64AdvSIMDScalarPass.cpp b/contrib/llvm/lib/Target/AArch64/AArch64AdvSIMDScalarPass.cpp
index d0a2dd3..bc2320d 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64AdvSIMDScalarPass.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64AdvSIMDScalarPass.cpp
@@ -61,10 +61,6 @@ STATISTIC(NumScalarInsnsUsed, "Number of scalar instructions used");
STATISTIC(NumCopiesDeleted, "Number of cross-class copies deleted");
STATISTIC(NumCopiesInserted, "Number of cross-class copies inserted");
-namespace llvm {
-void initializeAArch64AdvSIMDScalarPass(PassRegistry &);
-}
-
#define AARCH64_ADVSIMD_NAME "AdvSIMD Scalar Operation Optimization"
namespace {
@@ -94,9 +90,7 @@ public:
bool runOnMachineFunction(MachineFunction &F) override;
- const char *getPassName() const override {
- return AARCH64_ADVSIMD_NAME;
- }
+ StringRef getPassName() const override { return AARCH64_ADVSIMD_NAME; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/contrib/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 22374f7..efc2218 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -37,6 +37,9 @@
#include "llvm/MC/MCLinkerOptimizationHint.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
@@ -56,9 +59,7 @@ public:
: AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this),
SM(*this), AArch64FI(nullptr) {}
- const char *getPassName() const override {
- return "AArch64 Assembly Printer";
- }
+ StringRef getPassName() const override { return "AArch64 Assembly Printer"; }
/// \brief Wrapper for MCInstLowering.lowerOperand() for the
/// tblgen'erated pseudo lowering.
@@ -70,6 +71,13 @@ public:
const MachineInstr &MI);
void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
const MachineInstr &MI);
+
+ void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
+ void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
+ void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
+
+ void EmitSled(const MachineInstr &MI, SledKind Kind);
+
/// \brief tblgen'erated driver function for lowering simple MI->MC
/// pseudo instructions.
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
@@ -85,7 +93,9 @@ public:
bool runOnMachineFunction(MachineFunction &F) override {
AArch64FI = F.getInfo<AArch64FunctionInfo>();
STI = static_cast<const AArch64Subtarget*>(&F.getSubtarget());
- return AsmPrinter::runOnMachineFunction(F);
+ bool Result = AsmPrinter::runOnMachineFunction(F);
+ emitXRayTable();
+ return Result;
}
private:
@@ -124,6 +134,61 @@ private:
//===----------------------------------------------------------------------===//
+void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
+{
+ EmitSled(MI, SledKind::FUNCTION_ENTER);
+}
+
+void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
+{
+ EmitSled(MI, SledKind::FUNCTION_EXIT);
+}
+
+void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
+{
+ EmitSled(MI, SledKind::TAIL_CALL);
+}
+
+void AArch64AsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
+{
+ static const int8_t NoopsInSledCount = 7;
+ // We want to emit the following pattern:
+ //
+ // .Lxray_sled_N:
+ // ALIGN
+ // B #32
+ // ; 7 NOP instructions (28 bytes)
+ // .tmpN
+ //
+ // We need the 28 bytes (7 instructions) because at runtime, we'd be patching
+ // over the full 32 bytes (8 instructions) with the following pattern:
+ //
+ // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack
+ // LDR W0, #12 ; W0 := function ID
+ // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit
+ // BLR X16 ; call the tracing trampoline
+ // ;DATA: 32 bits of function ID
+ // ;DATA: lower 32 bits of the address of the trampoline
+ // ;DATA: higher 32 bits of the address of the trampoline
+ // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack
+ //
+ OutStreamer->EmitCodeAlignment(4);
+ auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
+ OutStreamer->EmitLabel(CurSled);
+ auto Target = OutContext.createTempSymbol();
+
+ // Emit "B #32" instruction, which jumps over the next 28 bytes.
+ // The operand has to be the number of 4-byte instructions to jump over,
+ // including the current instruction.
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8));
+
+ for (int8_t I = 0; I < NoopsInSledCount; I++)
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
+
+ OutStreamer->EmitLabel(Target);
+ recordSled(CurSled, MI, Kind);
+}
+
void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
const Triple &TT = TM.getTargetTriple();
if (TT.isOSBinFormatMachO()) {
@@ -162,7 +227,7 @@ MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const {
// Darwin uses a linker-private symbol name for constant-pools (to
// avoid addends on the relocation?), ELF has no such concept and
// uses a normal private symbol.
- if (getDataLayout().getLinkerPrivateGlobalPrefix()[0])
+ if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty())
return OutContext.getOrCreateSymbol(
Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" +
Twine(getFunctionNumber()) + "_" + Twine(CPID));
@@ -354,7 +419,7 @@ void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
const MachineInstr &MI) {
- unsigned NumNOPBytes = MI.getOperand(1).getImm();
+ unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
SM.recordStackMap(MI);
assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
@@ -386,7 +451,7 @@ void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
PatchPointOpers Opers(&MI);
- int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm();
+ int64_t CallTarget = Opers.getCallTarget().getImm();
unsigned EncodedBytes = 0;
if (CallTarget) {
assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
@@ -411,7 +476,7 @@ void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg));
}
// Emit padding.
- unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
+ unsigned NumBytes = Opers.getNumPatchBytes();
assert(NumBytes >= EncodedBytes &&
"Patchpoint can't request size less than the length of a call.");
assert((NumBytes - EncodedBytes) % 4 == 0 &&
@@ -569,6 +634,18 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
case TargetOpcode::PATCHPOINT:
return LowerPATCHPOINT(*OutStreamer, SM, *MI);
+
+ case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
+ LowerPATCHABLE_FUNCTION_ENTER(*MI);
+ return;
+
+ case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
+ LowerPATCHABLE_FUNCTION_EXIT(*MI);
+ return;
+
+ case TargetOpcode::PATCHABLE_TAIL_CALL:
+ LowerPATCHABLE_TAIL_CALL(*MI);
+ return;
}
// Finally, do the automated lowerings for everything else.
@@ -579,7 +656,7 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Force static initialization.
extern "C" void LLVMInitializeAArch64AsmPrinter() {
- RegisterAsmPrinter<AArch64AsmPrinter> X(TheAArch64leTarget);
- RegisterAsmPrinter<AArch64AsmPrinter> Y(TheAArch64beTarget);
- RegisterAsmPrinter<AArch64AsmPrinter> Z(TheARM64Target);
+ RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
+ RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget());
+ RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target());
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64BranchRelaxation.cpp b/contrib/llvm/lib/Target/AArch64/AArch64BranchRelaxation.cpp
deleted file mode 100644
index 9ec6ae4..0000000
--- a/contrib/llvm/lib/Target/AArch64/AArch64BranchRelaxation.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-//===-- AArch64BranchRelaxation.cpp - AArch64 branch relaxation -----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-//===----------------------------------------------------------------------===//
-
-#include "AArch64.h"
-#include "AArch64InstrInfo.h"
-#include "AArch64MachineFunctionInfo.h"
-#include "AArch64Subtarget.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
-
-#define DEBUG_TYPE "aarch64-branch-relax"
-
-static cl::opt<bool>
-BranchRelaxation("aarch64-branch-relax", cl::Hidden, cl::init(true),
- cl::desc("Relax out of range conditional branches"));
-
-static cl::opt<unsigned>
-TBZDisplacementBits("aarch64-tbz-offset-bits", cl::Hidden, cl::init(14),
- cl::desc("Restrict range of TB[N]Z instructions (DEBUG)"));
-
-static cl::opt<unsigned>
-CBZDisplacementBits("aarch64-cbz-offset-bits", cl::Hidden, cl::init(19),
- cl::desc("Restrict range of CB[N]Z instructions (DEBUG)"));
-
-static cl::opt<unsigned>
-BCCDisplacementBits("aarch64-bcc-offset-bits", cl::Hidden, cl::init(19),
- cl::desc("Restrict range of Bcc instructions (DEBUG)"));
-
-STATISTIC(NumSplit, "Number of basic blocks split");
-STATISTIC(NumRelaxed, "Number of conditional branches relaxed");
-
-namespace llvm {
-void initializeAArch64BranchRelaxationPass(PassRegistry &);
-}
-
-#define AARCH64_BR_RELAX_NAME "AArch64 branch relaxation pass"
-
-namespace {
-class AArch64BranchRelaxation : public MachineFunctionPass {
- /// BasicBlockInfo - Information about the offset and size of a single
- /// basic block.
- struct BasicBlockInfo {
- /// Offset - Distance from the beginning of the function to the beginning
- /// of this basic block.
- ///
- /// The offset is always aligned as required by the basic block.
- unsigned Offset;
-
- /// Size - Size of the basic block in bytes. If the block contains
- /// inline assembly, this is a worst case estimate.
- ///
- /// The size does not include any alignment padding whether from the
- /// beginning of the block, or from an aligned jump table at the end.
- unsigned Size;
-
- BasicBlockInfo() : Offset(0), Size(0) {}
-
- /// Compute the offset immediately following this block. If LogAlign is
- /// specified, return the offset the successor block will get if it has
- /// this alignment.
- unsigned postOffset(unsigned LogAlign = 0) const {
- unsigned PO = Offset + Size;
- unsigned Align = 1 << LogAlign;
- return (PO + Align - 1) / Align * Align;
- }
- };
-
- SmallVector<BasicBlockInfo, 16> BlockInfo;
-
- MachineFunction *MF;
- const AArch64InstrInfo *TII;
-
- bool relaxBranchInstructions();
- void scanFunction();
- MachineBasicBlock *splitBlockBeforeInstr(MachineInstr *MI);
- void adjustBlockOffsets(MachineBasicBlock &MBB);
- bool isBlockInRange(MachineInstr *MI, MachineBasicBlock *BB, unsigned Disp);
- bool fixupConditionalBranch(MachineInstr *MI);
- void computeBlockSize(const MachineBasicBlock &MBB);
- unsigned getInstrOffset(MachineInstr *MI) const;
- void dumpBBs();
- void verify();
-
-public:
- static char ID;
- AArch64BranchRelaxation() : MachineFunctionPass(ID) {
- initializeAArch64BranchRelaxationPass(*PassRegistry::getPassRegistry());
- }
-
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return AARCH64_BR_RELAX_NAME;
- }
-};
-char AArch64BranchRelaxation::ID = 0;
-}
-
-INITIALIZE_PASS(AArch64BranchRelaxation, "aarch64-branch-relax",
- AARCH64_BR_RELAX_NAME, false, false)
-
-/// verify - check BBOffsets, BBSizes, alignment of islands
-void AArch64BranchRelaxation::verify() {
-#ifndef NDEBUG
- unsigned PrevNum = MF->begin()->getNumber();
- for (MachineBasicBlock &MBB : *MF) {
- unsigned Align = MBB.getAlignment();
- unsigned Num = MBB.getNumber();
- assert(BlockInfo[Num].Offset % (1u << Align) == 0);
- assert(!Num || BlockInfo[PrevNum].postOffset() <= BlockInfo[Num].Offset);
- PrevNum = Num;
- }
-#endif
-}
-
-/// print block size and offset information - debugging
-void AArch64BranchRelaxation::dumpBBs() {
- for (auto &MBB : *MF) {
- const BasicBlockInfo &BBI = BlockInfo[MBB.getNumber()];
- dbgs() << format("BB#%u\toffset=%08x\t", MBB.getNumber(), BBI.Offset)
- << format("size=%#x\n", BBI.Size);
- }
-}
-
-/// BBHasFallthrough - Return true if the specified basic block can fallthrough
-/// into the block immediately after it.
-static bool BBHasFallthrough(MachineBasicBlock *MBB) {
- // Get the next machine basic block in the function.
- MachineFunction::iterator MBBI(MBB);
- // Can't fall off end of function.
- auto NextBB = std::next(MBBI);
- if (NextBB == MBB->getParent()->end())
- return false;
-
- for (MachineBasicBlock *S : MBB->successors())
- if (S == &*NextBB)
- return true;
-
- return false;
-}
-
-/// scanFunction - Do the initial scan of the function, building up
-/// information about each block.
-void AArch64BranchRelaxation::scanFunction() {
- BlockInfo.clear();
- BlockInfo.resize(MF->getNumBlockIDs());
-
- // First thing, compute the size of all basic blocks, and see if the function
- // has any inline assembly in it. If so, we have to be conservative about
- // alignment assumptions, as we don't know for sure the size of any
- // instructions in the inline assembly.
- for (MachineBasicBlock &MBB : *MF)
- computeBlockSize(MBB);
-
- // Compute block offsets and known bits.
- adjustBlockOffsets(*MF->begin());
-}
-
-/// computeBlockSize - Compute the size for MBB.
-/// This function updates BlockInfo directly.
-void AArch64BranchRelaxation::computeBlockSize(const MachineBasicBlock &MBB) {
- unsigned Size = 0;
- for (const MachineInstr &MI : MBB)
- Size += TII->GetInstSizeInBytes(MI);
- BlockInfo[MBB.getNumber()].Size = Size;
-}
-
-/// getInstrOffset - Return the current offset of the specified machine
-/// instruction from the start of the function. This offset changes as stuff is
-/// moved around inside the function.
-unsigned AArch64BranchRelaxation::getInstrOffset(MachineInstr *MI) const {
- MachineBasicBlock *MBB = MI->getParent();
-
- // The offset is composed of two things: the sum of the sizes of all MBB's
- // before this instruction's block, and the offset from the start of the block
- // it is in.
- unsigned Offset = BlockInfo[MBB->getNumber()].Offset;
-
- // Sum instructions before MI in MBB.
- for (MachineBasicBlock::iterator I = MBB->begin(); &*I != MI; ++I) {
- assert(I != MBB->end() && "Didn't find MI in its own basic block?");
- Offset += TII->GetInstSizeInBytes(*I);
- }
- return Offset;
-}
-
-void AArch64BranchRelaxation::adjustBlockOffsets(MachineBasicBlock &Start) {
- unsigned PrevNum = Start.getNumber();
- for (auto &MBB : make_range(MachineFunction::iterator(Start), MF->end())) {
- unsigned Num = MBB.getNumber();
- if (!Num) // block zero is never changed from offset zero.
- continue;
- // Get the offset and known bits at the end of the layout predecessor.
- // Include the alignment of the current block.
- unsigned LogAlign = MBB.getAlignment();
- BlockInfo[Num].Offset = BlockInfo[PrevNum].postOffset(LogAlign);
- PrevNum = Num;
- }
-}
-
-/// Split the basic block containing MI into two blocks, which are joined by
-/// an unconditional branch. Update data structures and renumber blocks to
-/// account for this change and returns the newly created block.
-/// NOTE: Successor list of the original BB is out of date after this function,
-/// and must be updated by the caller! Other transforms follow using this
-/// utility function, so no point updating now rather than waiting.
-MachineBasicBlock *
-AArch64BranchRelaxation::splitBlockBeforeInstr(MachineInstr *MI) {
- MachineBasicBlock *OrigBB = MI->getParent();
-
- // Create a new MBB for the code after the OrigBB.
- MachineBasicBlock *NewBB =
- MF->CreateMachineBasicBlock(OrigBB->getBasicBlock());
- MF->insert(++OrigBB->getIterator(), NewBB);
-
- // Splice the instructions starting with MI over to NewBB.
- NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end());
-
- // Add an unconditional branch from OrigBB to NewBB.
- // Note the new unconditional branch is not being recorded.
- // There doesn't seem to be meaningful DebugInfo available; this doesn't
- // correspond to anything in the source.
- BuildMI(OrigBB, DebugLoc(), TII->get(AArch64::B)).addMBB(NewBB);
-
- // Insert an entry into BlockInfo to align it properly with the block numbers.
- BlockInfo.insert(BlockInfo.begin() + NewBB->getNumber(), BasicBlockInfo());
-
- // Figure out how large the OrigBB is. As the first half of the original
- // block, it cannot contain a tablejump. The size includes
- // the new jump we added. (It should be possible to do this without
- // recounting everything, but it's very confusing, and this is rarely
- // executed.)
- computeBlockSize(*OrigBB);
-
- // Figure out how large the NewMBB is. As the second half of the original
- // block, it may contain a tablejump.
- computeBlockSize(*NewBB);
-
- // All BBOffsets following these blocks must be modified.
- adjustBlockOffsets(*OrigBB);
-
- ++NumSplit;
-
- return NewBB;
-}
-
-/// isBlockInRange - Returns true if the distance between specific MI and
-/// specific BB can fit in MI's displacement field.
-bool AArch64BranchRelaxation::isBlockInRange(MachineInstr *MI,
- MachineBasicBlock *DestBB,
- unsigned Bits) {
- unsigned MaxOffs = ((1 << (Bits - 1)) - 1) << 2;
- unsigned BrOffset = getInstrOffset(MI);
- unsigned DestOffset = BlockInfo[DestBB->getNumber()].Offset;
-
- DEBUG(dbgs() << "Branch of destination BB#" << DestBB->getNumber()
- << " from BB#" << MI->getParent()->getNumber()
- << " max delta=" << MaxOffs << " from " << getInstrOffset(MI)
- << " to " << DestOffset << " offset "
- << int(DestOffset - BrOffset) << "\t" << *MI);
-
- // Branch before the Dest.
- if (BrOffset <= DestOffset)
- return (DestOffset - BrOffset <= MaxOffs);
- return (BrOffset - DestOffset <= MaxOffs);
-}
-
-static bool isConditionalBranch(unsigned Opc) {
- switch (Opc) {
- default:
- return false;
- case AArch64::TBZW:
- case AArch64::TBNZW:
- case AArch64::TBZX:
- case AArch64::TBNZX:
- case AArch64::CBZW:
- case AArch64::CBNZW:
- case AArch64::CBZX:
- case AArch64::CBNZX:
- case AArch64::Bcc:
- return true;
- }
-}
-
-static MachineBasicBlock *getDestBlock(MachineInstr *MI) {
- switch (MI->getOpcode()) {
- default:
- llvm_unreachable("unexpected opcode!");
- case AArch64::TBZW:
- case AArch64::TBNZW:
- case AArch64::TBZX:
- case AArch64::TBNZX:
- return MI->getOperand(2).getMBB();
- case AArch64::CBZW:
- case AArch64::CBNZW:
- case AArch64::CBZX:
- case AArch64::CBNZX:
- case AArch64::Bcc:
- return MI->getOperand(1).getMBB();
- }
-}
-
-static unsigned getOppositeConditionOpcode(unsigned Opc) {
- switch (Opc) {
- default:
- llvm_unreachable("unexpected opcode!");
- case AArch64::TBNZW: return AArch64::TBZW;
- case AArch64::TBNZX: return AArch64::TBZX;
- case AArch64::TBZW: return AArch64::TBNZW;
- case AArch64::TBZX: return AArch64::TBNZX;
- case AArch64::CBNZW: return AArch64::CBZW;
- case AArch64::CBNZX: return AArch64::CBZX;
- case AArch64::CBZW: return AArch64::CBNZW;
- case AArch64::CBZX: return AArch64::CBNZX;
- case AArch64::Bcc: return AArch64::Bcc; // Condition is an operand for Bcc.
- }
-}
-
-static unsigned getBranchDisplacementBits(unsigned Opc) {
- switch (Opc) {
- default:
- llvm_unreachable("unexpected opcode!");
- case AArch64::TBNZW:
- case AArch64::TBZW:
- case AArch64::TBNZX:
- case AArch64::TBZX:
- return TBZDisplacementBits;
- case AArch64::CBNZW:
- case AArch64::CBZW:
- case AArch64::CBNZX:
- case AArch64::CBZX:
- return CBZDisplacementBits;
- case AArch64::Bcc:
- return BCCDisplacementBits;
- }
-}
-
-static inline void invertBccCondition(MachineInstr *MI) {
- assert(MI->getOpcode() == AArch64::Bcc && "Unexpected opcode!");
- AArch64CC::CondCode CC = (AArch64CC::CondCode)MI->getOperand(0).getImm();
- CC = AArch64CC::getInvertedCondCode(CC);
- MI->getOperand(0).setImm((int64_t)CC);
-}
-
-/// fixupConditionalBranch - Fix up a conditional branch whose destination is
-/// too far away to fit in its displacement field. It is converted to an inverse
-/// conditional branch + an unconditional branch to the destination.
-bool AArch64BranchRelaxation::fixupConditionalBranch(MachineInstr *MI) {
- MachineBasicBlock *DestBB = getDestBlock(MI);
-
- // Add an unconditional branch to the destination and invert the branch
- // condition to jump over it:
- // tbz L1
- // =>
- // tbnz L2
- // b L1
- // L2:
-
- // If the branch is at the end of its MBB and that has a fall-through block,
- // direct the updated conditional branch to the fall-through block. Otherwise,
- // split the MBB before the next instruction.
- MachineBasicBlock *MBB = MI->getParent();
- MachineInstr *BMI = &MBB->back();
- bool NeedSplit = (BMI != MI) || !BBHasFallthrough(MBB);
-
- if (BMI != MI) {
- if (std::next(MachineBasicBlock::iterator(MI)) ==
- std::prev(MBB->getLastNonDebugInstr()) &&
- BMI->getOpcode() == AArch64::B) {
- // Last MI in the BB is an unconditional branch. Can we simply invert the
- // condition and swap destinations:
- // beq L1
- // b L2
- // =>
- // bne L2
- // b L1
- MachineBasicBlock *NewDest = BMI->getOperand(0).getMBB();
- if (isBlockInRange(MI, NewDest,
- getBranchDisplacementBits(MI->getOpcode()))) {
- DEBUG(dbgs() << " Invert condition and swap its destination with "
- << *BMI);
- BMI->getOperand(0).setMBB(DestBB);
- unsigned OpNum = (MI->getOpcode() == AArch64::TBZW ||
- MI->getOpcode() == AArch64::TBNZW ||
- MI->getOpcode() == AArch64::TBZX ||
- MI->getOpcode() == AArch64::TBNZX)
- ? 2
- : 1;
- MI->getOperand(OpNum).setMBB(NewDest);
- MI->setDesc(TII->get(getOppositeConditionOpcode(MI->getOpcode())));
- if (MI->getOpcode() == AArch64::Bcc)
- invertBccCondition(MI);
- return true;
- }
- }
- }
-
- if (NeedSplit) {
- // Analyze the branch so we know how to update the successor lists.
- MachineBasicBlock *TBB, *FBB;
- SmallVector<MachineOperand, 2> Cond;
- TII->analyzeBranch(*MBB, TBB, FBB, Cond, false);
-
- MachineBasicBlock *NewBB = splitBlockBeforeInstr(MI);
- // No need for the branch to the next block. We're adding an unconditional
- // branch to the destination.
- int delta = TII->GetInstSizeInBytes(MBB->back());
- BlockInfo[MBB->getNumber()].Size -= delta;
- MBB->back().eraseFromParent();
- // BlockInfo[SplitBB].Offset is wrong temporarily, fixed below
-
- // Update the successor lists according to the transformation to follow.
- // Do it here since if there's no split, no update is needed.
- MBB->replaceSuccessor(FBB, NewBB);
- NewBB->addSuccessor(FBB);
- }
- MachineBasicBlock *NextBB = &*std::next(MachineFunction::iterator(MBB));
-
- DEBUG(dbgs() << " Insert B to BB#" << DestBB->getNumber()
- << ", invert condition and change dest. to BB#"
- << NextBB->getNumber() << "\n");
-
- // Insert a new conditional branch and a new unconditional branch.
- MachineInstrBuilder MIB = BuildMI(
- MBB, DebugLoc(), TII->get(getOppositeConditionOpcode(MI->getOpcode())))
- .addOperand(MI->getOperand(0));
- if (MI->getOpcode() == AArch64::TBZW || MI->getOpcode() == AArch64::TBNZW ||
- MI->getOpcode() == AArch64::TBZX || MI->getOpcode() == AArch64::TBNZX)
- MIB.addOperand(MI->getOperand(1));
- if (MI->getOpcode() == AArch64::Bcc)
- invertBccCondition(MIB);
- MIB.addMBB(NextBB);
- BlockInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(MBB->back());
- BuildMI(MBB, DebugLoc(), TII->get(AArch64::B)).addMBB(DestBB);
- BlockInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(MBB->back());
-
- // Remove the old conditional branch. It may or may not still be in MBB.
- BlockInfo[MI->getParent()->getNumber()].Size -= TII->GetInstSizeInBytes(*MI);
- MI->eraseFromParent();
-
- // Finally, keep the block offsets up to date.
- adjustBlockOffsets(*MBB);
- return true;
-}
-
-bool AArch64BranchRelaxation::relaxBranchInstructions() {
- bool Changed = false;
- // Relaxing branches involves creating new basic blocks, so re-eval
- // end() for termination.
- for (MachineFunction::iterator I = MF->begin(); I != MF->end(); ++I) {
- MachineBasicBlock &MBB = *I;
- MachineInstr &MI = *MBB.getFirstTerminator();
- if (isConditionalBranch(MI.getOpcode()) &&
- !isBlockInRange(&MI, getDestBlock(&MI),
- getBranchDisplacementBits(MI.getOpcode()))) {
- fixupConditionalBranch(&MI);
- ++NumRelaxed;
- Changed = true;
- }
- }
- return Changed;
-}
-
-bool AArch64BranchRelaxation::runOnMachineFunction(MachineFunction &mf) {
- MF = &mf;
-
- // If the pass is disabled, just bail early.
- if (!BranchRelaxation)
- return false;
-
- DEBUG(dbgs() << "***** AArch64BranchRelaxation *****\n");
-
- TII = (const AArch64InstrInfo *)MF->getSubtarget().getInstrInfo();
-
- // Renumber all of the machine basic blocks in the function, guaranteeing that
- // the numbers agree with the position of the block in the function.
- MF->RenumberBlocks();
-
- // Do the initial scan of the function, building up information about the
- // sizes of each block.
- scanFunction();
-
- DEBUG(dbgs() << " Basic blocks before relaxation\n");
- DEBUG(dumpBBs());
-
- bool MadeChange = false;
- while (relaxBranchInstructions())
- MadeChange = true;
-
- // After a while, this might be made debug-only, but it is not expensive.
- verify();
-
- DEBUG(dbgs() << " Basic blocks after relaxation\n");
- DEBUG(dbgs() << '\n'; dumpBBs());
-
- BlockInfo.clear();
-
- return MadeChange;
-}
-
-/// Returns an instance of the AArch64 Branch Relaxation pass.
-FunctionPass *llvm::createAArch64BranchRelaxation() {
- return new AArch64BranchRelaxation();
-}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.cpp b/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.cpp
index e3522e6..a4950af 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.cpp
@@ -16,9 +16,14 @@
#include "AArch64CallLowering.h"
#include "AArch64ISelLowering.h"
+#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
+#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
#ifndef LLVM_BUILD_GLOBAL_ISEL
@@ -29,76 +34,284 @@ AArch64CallLowering::AArch64CallLowering(const AArch64TargetLowering &TLI)
: CallLowering(&TLI) {
}
+struct IncomingArgHandler : public CallLowering::ValueHandler {
+ IncomingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
+ : ValueHandler(MIRBuilder, MRI) {}
+
+ unsigned getStackAddress(uint64_t Size, int64_t Offset,
+ MachinePointerInfo &MPO) override {
+ auto &MFI = MIRBuilder.getMF().getFrameInfo();
+ int FI = MFI.CreateFixedObject(Size, Offset, true);
+ MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
+ unsigned AddrReg = MRI.createGenericVirtualRegister(LLT::pointer(0, 64));
+ MIRBuilder.buildFrameIndex(AddrReg, FI);
+ return AddrReg;
+ }
+
+ void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
+ CCValAssign &VA) override {
+ markPhysRegUsed(PhysReg);
+ MIRBuilder.buildCopy(ValVReg, PhysReg);
+ // FIXME: assert extension
+ }
+
+ void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
+ MachinePointerInfo &MPO, CCValAssign &VA) override {
+ auto MMO = MIRBuilder.getMF().getMachineMemOperand(
+ MPO, MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant, Size,
+ 0);
+ MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
+ }
+
+ /// How the physical register gets marked varies between formal
+ /// parameters (it's a basic-block live-in), and a call instruction
+ /// (it's an implicit-def of the BL).
+ virtual void markPhysRegUsed(unsigned PhysReg) = 0;
+};
+
+struct FormalArgHandler : public IncomingArgHandler {
+ FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
+ : IncomingArgHandler(MIRBuilder, MRI) {}
+
+ void markPhysRegUsed(unsigned PhysReg) override {
+ MIRBuilder.getMBB().addLiveIn(PhysReg);
+ }
+};
+
+struct CallReturnHandler : public IncomingArgHandler {
+ CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+ MachineInstrBuilder MIB)
+ : IncomingArgHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+ void markPhysRegUsed(unsigned PhysReg) override {
+ MIB.addDef(PhysReg, RegState::Implicit);
+ }
+
+ MachineInstrBuilder MIB;
+};
+
+struct OutgoingArgHandler : public CallLowering::ValueHandler {
+ OutgoingArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+ MachineInstrBuilder MIB)
+ : ValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+ unsigned getStackAddress(uint64_t Size, int64_t Offset,
+ MachinePointerInfo &MPO) override {
+ LLT p0 = LLT::pointer(0, 64);
+ LLT s64 = LLT::scalar(64);
+ unsigned SPReg = MRI.createGenericVirtualRegister(p0);
+ MIRBuilder.buildCopy(SPReg, AArch64::SP);
+
+ unsigned OffsetReg = MRI.createGenericVirtualRegister(s64);
+ MIRBuilder.buildConstant(OffsetReg, Offset);
+
+ unsigned AddrReg = MRI.createGenericVirtualRegister(p0);
+ MIRBuilder.buildGEP(AddrReg, SPReg, OffsetReg);
+
+ MPO = MachinePointerInfo::getStack(MIRBuilder.getMF(), Offset);
+ return AddrReg;
+ }
+
+ void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
+ CCValAssign &VA) override {
+ MIB.addUse(PhysReg, RegState::Implicit);
+ unsigned ExtReg = extendRegister(ValVReg, VA);
+ MIRBuilder.buildCopy(PhysReg, ExtReg);
+ }
+
+ void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
+ MachinePointerInfo &MPO, CCValAssign &VA) override {
+ auto MMO = MIRBuilder.getMF().getMachineMemOperand(
+ MPO, MachineMemOperand::MOStore, Size, 0);
+ MIRBuilder.buildStore(ValVReg, Addr, *MMO);
+ }
+
+ MachineInstrBuilder MIB;
+};
+
+void AArch64CallLowering::splitToValueTypes(const ArgInfo &OrigArg,
+ SmallVectorImpl<ArgInfo> &SplitArgs,
+ const DataLayout &DL,
+ MachineRegisterInfo &MRI,
+ SplitArgTy PerformArgSplit) const {
+ const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
+ LLVMContext &Ctx = OrigArg.Ty->getContext();
+
+ SmallVector<EVT, 4> SplitVTs;
+ SmallVector<uint64_t, 4> Offsets;
+ ComputeValueVTs(TLI, DL, OrigArg.Ty, SplitVTs, &Offsets, 0);
+
+ if (SplitVTs.size() == 1) {
+ // No splitting to do, but we want to replace the original type (e.g. [1 x
+ // double] -> double).
+ SplitArgs.emplace_back(OrigArg.Reg, SplitVTs[0].getTypeForEVT(Ctx),
+ OrigArg.Flags);
+ return;
+ }
+
+ unsigned FirstRegIdx = SplitArgs.size();
+ for (auto SplitVT : SplitVTs) {
+ // FIXME: set split flags if they're actually used (e.g. i128 on AAPCS).
+ Type *SplitTy = SplitVT.getTypeForEVT(Ctx);
+ SplitArgs.push_back(
+ ArgInfo{MRI.createGenericVirtualRegister(LLT{*SplitTy, DL}), SplitTy,
+ OrigArg.Flags});
+ }
+
+ SmallVector<uint64_t, 4> BitOffsets;
+ for (auto Offset : Offsets)
+ BitOffsets.push_back(Offset * 8);
+
+ SmallVector<unsigned, 8> SplitRegs;
+ for (auto I = &SplitArgs[FirstRegIdx]; I != SplitArgs.end(); ++I)
+ SplitRegs.push_back(I->Reg);
+
+ PerformArgSplit(SplitRegs, BitOffsets);
+}
+
bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
- const Value *Val, unsigned VReg) const {
- MachineInstr *Return = MIRBuilder.buildInstr(AArch64::RET_ReallyLR);
- assert(Return && "Unable to build a return instruction?!");
+ const Value *Val, unsigned VReg) const {
+ MachineFunction &MF = MIRBuilder.getMF();
+ const Function &F = *MF.getFunction();
+ auto MIB = MIRBuilder.buildInstrNoInsert(AArch64::RET_ReallyLR);
assert(((Val && VReg) || (!Val && !VReg)) && "Return value without a vreg");
+ bool Success = true;
if (VReg) {
- assert(Val->getType()->isIntegerTy() && "Type not supported yet");
- unsigned Size = Val->getType()->getPrimitiveSizeInBits();
- assert((Size == 64 || Size == 32) && "Size not supported yet");
- unsigned ResReg = (Size == 32) ? AArch64::W0 : AArch64::X0;
- // Set the insertion point to be right before Return.
- MIRBuilder.setInstr(*Return, /* Before */ true);
- MachineInstr *Copy =
- MIRBuilder.buildInstr(TargetOpcode::COPY, ResReg, VReg);
- (void)Copy;
- assert(Copy->getNextNode() == Return &&
- "The insertion did not happen where we expected");
- MachineInstrBuilder(MIRBuilder.getMF(), Return)
- .addReg(ResReg, RegState::Implicit);
+ const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
+ CCAssignFn *AssignFn = TLI.CCAssignFnForReturn(F.getCallingConv());
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ auto &DL = F.getParent()->getDataLayout();
+
+ ArgInfo OrigArg{VReg, Val->getType()};
+ setArgFlags(OrigArg, AttributeSet::ReturnIndex, DL, F);
+
+ SmallVector<ArgInfo, 8> SplitArgs;
+ splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
+ [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+ MIRBuilder.buildExtract(Regs, Offsets, VReg);
+ });
+
+ OutgoingArgHandler Handler(MIRBuilder, MRI, MIB);
+ Success = handleAssignments(MIRBuilder, AssignFn, SplitArgs, Handler);
}
+
+ MIRBuilder.insertInstr(MIB);
+ return Success;
+}
+
+bool AArch64CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
+ const Function &F,
+ ArrayRef<unsigned> VRegs) const {
+ auto &Args = F.getArgumentList();
+ MachineFunction &MF = MIRBuilder.getMF();
+ MachineBasicBlock &MBB = MIRBuilder.getMBB();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ auto &DL = F.getParent()->getDataLayout();
+
+ SmallVector<ArgInfo, 8> SplitArgs;
+ unsigned i = 0;
+ for (auto &Arg : Args) {
+ ArgInfo OrigArg{VRegs[i], Arg.getType()};
+ setArgFlags(OrigArg, i + 1, DL, F);
+ splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
+ [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+ MIRBuilder.buildSequence(VRegs[i], Regs, Offsets);
+ });
+ ++i;
+ }
+
+ if (!MBB.empty())
+ MIRBuilder.setInstr(*MBB.begin());
+
+ const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
+ CCAssignFn *AssignFn =
+ TLI.CCAssignFnForCall(F.getCallingConv(), /*IsVarArg=*/false);
+
+ FormalArgHandler Handler(MIRBuilder, MRI);
+ if (!handleAssignments(MIRBuilder, AssignFn, SplitArgs, Handler))
+ return false;
+
+ // Move back to the end of the basic block.
+ MIRBuilder.setMBB(MBB);
+
return true;
}
-bool AArch64CallLowering::lowerFormalArguments(
- MachineIRBuilder &MIRBuilder, const Function::ArgumentListType &Args,
- const SmallVectorImpl<unsigned> &VRegs) const {
+bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
+ const MachineOperand &Callee,
+ const ArgInfo &OrigRet,
+ ArrayRef<ArgInfo> OrigArgs) const {
MachineFunction &MF = MIRBuilder.getMF();
const Function &F = *MF.getFunction();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ auto &DL = F.getParent()->getDataLayout();
- SmallVector<CCValAssign, 16> ArgLocs;
- CCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, F.getContext());
+ SmallVector<ArgInfo, 8> SplitArgs;
+ for (auto &OrigArg : OrigArgs) {
+ splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
+ [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+ MIRBuilder.buildExtract(Regs, Offsets, OrigArg.Reg);
+ });
+ }
- unsigned NumArgs = Args.size();
- Function::const_arg_iterator CurOrigArg = Args.begin();
+ // Find out which ABI gets to decide where things go.
const AArch64TargetLowering &TLI = *getTLI<AArch64TargetLowering>();
- for (unsigned i = 0; i != NumArgs; ++i, ++CurOrigArg) {
- MVT ValVT = MVT::getVT(CurOrigArg->getType());
- CCAssignFn *AssignFn =
- TLI.CCAssignFnForCall(F.getCallingConv(), /*IsVarArg=*/false);
- bool Res =
- AssignFn(i, ValVT, ValVT, CCValAssign::Full, ISD::ArgFlagsTy(), CCInfo);
- assert(!Res && "Call operand has unhandled type");
- (void)Res;
- }
- assert(ArgLocs.size() == Args.size() &&
- "We have a different number of location and args?!");
- for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
- CCValAssign &VA = ArgLocs[i];
-
- assert(VA.isRegLoc() && "Not yet implemented");
- // Transform the arguments in physical registers into virtual ones.
- MIRBuilder.getMBB().addLiveIn(VA.getLocReg());
- MIRBuilder.buildInstr(TargetOpcode::COPY, VRegs[i], VA.getLocReg());
-
- switch (VA.getLocInfo()) {
- default:
- llvm_unreachable("Unknown loc info!");
- case CCValAssign::Full:
- break;
- case CCValAssign::BCvt:
- // We don't care about bitcast.
- break;
- case CCValAssign::AExt:
- case CCValAssign::SExt:
- case CCValAssign::ZExt:
- // Zero/Sign extend the register.
- assert(0 && "Not yet implemented");
- break;
- }
+ CCAssignFn *CallAssignFn =
+ TLI.CCAssignFnForCall(F.getCallingConv(), /*IsVarArg=*/false);
+
+ // Create a temporarily-floating call instruction so we can add the implicit
+ // uses of arg registers.
+ auto MIB = MIRBuilder.buildInstrNoInsert(Callee.isReg() ? AArch64::BLR
+ : AArch64::BL);
+ MIB.addOperand(Callee);
+
+ // Tell the call which registers are clobbered.
+ auto TRI = MF.getSubtarget().getRegisterInfo();
+ MIB.addRegMask(TRI->getCallPreservedMask(MF, F.getCallingConv()));
+
+ // Do the actual argument marshalling.
+ SmallVector<unsigned, 8> PhysRegs;
+ OutgoingArgHandler Handler(MIRBuilder, MRI, MIB);
+ if (!handleAssignments(MIRBuilder, CallAssignFn, SplitArgs, Handler))
+ return false;
+
+ // Now we can add the actual call instruction to the correct basic block.
+ MIRBuilder.insertInstr(MIB);
+
+ // If Callee is a reg, since it is used by a target specific
+ // instruction, it must have a register class matching the
+ // constraint of that instruction.
+ if (Callee.isReg())
+ MIB->getOperand(0).setReg(constrainOperandRegClass(
+ MF, *TRI, MRI, *MF.getSubtarget().getInstrInfo(),
+ *MF.getSubtarget().getRegBankInfo(), *MIB, MIB->getDesc(),
+ Callee.getReg(), 0));
+
+ // Finally we can copy the returned value back into its virtual-register. In
+ // symmetry with the arugments, the physical register must be an
+ // implicit-define of the call instruction.
+ CCAssignFn *RetAssignFn = TLI.CCAssignFnForReturn(F.getCallingConv());
+ if (OrigRet.Reg) {
+ SplitArgs.clear();
+
+ SmallVector<uint64_t, 8> RegOffsets;
+ SmallVector<unsigned, 8> SplitRegs;
+ splitToValueTypes(OrigRet, SplitArgs, DL, MRI,
+ [&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
+ std::copy(Offsets.begin(), Offsets.end(),
+ std::back_inserter(RegOffsets));
+ std::copy(Regs.begin(), Regs.end(),
+ std::back_inserter(SplitRegs));
+ });
+
+ CallReturnHandler Handler(MIRBuilder, MRI, MIB);
+ if (!handleAssignments(MIRBuilder, RetAssignFn, SplitArgs, Handler))
+ return false;
+
+ if (!RegOffsets.empty())
+ MIRBuilder.buildSequence(OrigRet.Reg, SplitRegs, RegOffsets);
}
+
return true;
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.h b/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.h
index 4116228..ce66762 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64CallLowering.h
@@ -16,6 +16,7 @@
#define LLVM_LIB_TARGET_AARCH64_AARCH64CALLLOWERING
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/CodeGen/ValueTypes.h"
namespace llvm {
@@ -27,10 +28,29 @@ class AArch64CallLowering: public CallLowering {
bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val,
unsigned VReg) const override;
- bool
- lowerFormalArguments(MachineIRBuilder &MIRBuilder,
- const Function::ArgumentListType &Args,
- const SmallVectorImpl<unsigned> &VRegs) const override;
+
+ bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
+ ArrayRef<unsigned> VRegs) const override;
+
+ bool lowerCall(MachineIRBuilder &MIRBuilder, const MachineOperand &Callee,
+ const ArgInfo &OrigRet,
+ ArrayRef<ArgInfo> OrigArgs) const override;
+
+private:
+ typedef std::function<void(MachineIRBuilder &, Type *, unsigned,
+ CCValAssign &)>
+ RegHandler;
+
+ typedef std::function<void(MachineIRBuilder &, int, CCValAssign &)>
+ MemHandler;
+
+ typedef std::function<void(ArrayRef<unsigned>, ArrayRef<uint64_t>)>
+ SplitArgTy;
+
+ void splitToValueTypes(const ArgInfo &OrigArgInfo,
+ SmallVectorImpl<ArgInfo> &SplitArgs,
+ const DataLayout &DL, MachineRegisterInfo &MRI,
+ SplitArgTy SplitArg) const;
};
} // End of namespace llvm;
#endif
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/contrib/llvm/lib/Target/AArch64/AArch64CallingConvention.td
index 178e397..938779d 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64CallingConvention.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64CallingConvention.td
@@ -23,6 +23,7 @@ class CCIfBigEndian<CCAction A> :
//===----------------------------------------------------------------------===//
def CC_AArch64_AAPCS : CallingConv<[
+ CCIfType<[iPTR], CCBitConvertToType<i64>>,
CCIfType<[v2f32], CCBitConvertToType<v2i32>>,
CCIfType<[v2f64, v4f32], CCBitConvertToType<v2i64>>,
@@ -86,10 +87,11 @@ def CC_AArch64_AAPCS : CallingConv<[
]>;
def RetCC_AArch64_AAPCS : CallingConv<[
+ CCIfType<[iPTR], CCBitConvertToType<i64>>,
CCIfType<[v2f32], CCBitConvertToType<v2i32>>,
CCIfType<[v2f64, v4f32], CCBitConvertToType<v2i64>>,
- CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X19], [W19]>>>,
+ CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X21], [W21]>>>,
// Big endian vectors must be passed as if they were 1-element vectors so that
// their lanes are in a consistent order.
@@ -98,6 +100,7 @@ def RetCC_AArch64_AAPCS : CallingConv<[
CCIfBigEndian<CCIfType<[v2i64, v2f64, v4i32, v4f32, v8i16, v8f16, v16i8],
CCBitConvertToType<f128>>>,
+ CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
CCIfType<[i32], CCAssignToRegWithShadow<[W0, W1, W2, W3, W4, W5, W6, W7],
[X0, X1, X2, X3, X4, X5, X6, X7]>>,
CCIfType<[i64], CCAssignToRegWithShadow<[X0, X1, X2, X3, X4, X5, X6, X7],
@@ -121,6 +124,7 @@ def RetCC_AArch64_AAPCS : CallingConv<[
// + i128s (i.e. split i64s) don't need even registers.
// + Stack slots are sized as needed rather than being at least 64-bit.
def CC_AArch64_DarwinPCS : CallingConv<[
+ CCIfType<[iPTR], CCBitConvertToType<i64>>,
CCIfType<[v2f32], CCBitConvertToType<v2i32>>,
CCIfType<[v2f64, v4f32, f128], CCBitConvertToType<v2i64>>,
@@ -134,8 +138,8 @@ def CC_AArch64_DarwinPCS : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i64], CCAssignToRegWithShadow<[X20], [W20]>>>,
- // A SwiftError is passed in X19.
- CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X19], [W19]>>>,
+ // A SwiftError is passed in X21.
+ CCIfSwiftError<CCIfType<[i64], CCAssignToRegWithShadow<[X21], [W21]>>>,
CCIfConsecutiveRegs<CCCustom<"CC_AArch64_Custom_Block">>,
@@ -176,6 +180,7 @@ def CC_AArch64_DarwinPCS : CallingConv<[
]>;
def CC_AArch64_DarwinPCS_VarArg : CallingConv<[
+ CCIfType<[iPTR], CCBitConvertToType<i64>>,
CCIfType<[v2f32], CCBitConvertToType<v2i32>>,
CCIfType<[v2f64, v4f32, f128], CCBitConvertToType<v2i64>>,
@@ -243,6 +248,8 @@ def RetCC_AArch64_WebKit_JS : CallingConv<[
// register mapping".
def CC_AArch64_GHC : CallingConv<[
+ CCIfType<[iPTR], CCBitConvertToType<i64>>,
+
// Handle all vector types as either f64 or v2f64.
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32, f128], CCBitConvertToType<v2f64>>,
@@ -282,7 +289,7 @@ def CSR_AArch64_AAPCS : CalleeSavedRegs<(add LR, FP, X19, X20, X21, X22,
def CSR_AArch64_AAPCS_ThisReturn : CalleeSavedRegs<(add CSR_AArch64_AAPCS, X0)>;
def CSR_AArch64_AAPCS_SwiftError
- : CalleeSavedRegs<(sub CSR_AArch64_AAPCS, X19)>;
+ : CalleeSavedRegs<(sub CSR_AArch64_AAPCS, X21)>;
// The function used by Darwin to obtain the address of a thread-local variable
// guarantees more than a normal AAPCS function. x16 and x17 are used on the
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp b/contrib/llvm/lib/Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp
index 011a036..6f8dd3e 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp
@@ -33,10 +33,14 @@
#include "llvm/CodeGen/MachineRegisterInfo.h"
using namespace llvm;
+#define TLSCLEANUP_PASS_NAME "AArch64 Local Dynamic TLS Access Clean-up"
+
namespace {
struct LDTLSCleanup : public MachineFunctionPass {
static char ID;
- LDTLSCleanup() : MachineFunctionPass(ID) {}
+ LDTLSCleanup() : MachineFunctionPass(ID) {
+ initializeLDTLSCleanupPass(*PassRegistry::getPassRegistry());
+ }
bool runOnMachineFunction(MachineFunction &MF) override {
if (skipFunction(*MF.getFunction()))
@@ -128,9 +132,7 @@ struct LDTLSCleanup : public MachineFunctionPass {
return Copy;
}
- const char *getPassName() const override {
- return "Local Dynamic TLS Access Clean-up";
- }
+ StringRef getPassName() const override { return TLSCLEANUP_PASS_NAME; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -140,6 +142,9 @@ struct LDTLSCleanup : public MachineFunctionPass {
};
}
+INITIALIZE_PASS(LDTLSCleanup, "aarch64-local-dynamic-tls-cleanup",
+ TLSCLEANUP_PASS_NAME, false, false)
+
char LDTLSCleanup::ID = 0;
FunctionPass *llvm::createAArch64CleanupLocalDynamicTLSPass() {
return new LDTLSCleanup();
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp b/contrib/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
index 5eecb3a..17aafa0 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64CollectLOH.cpp
@@ -110,430 +110,96 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
#define DEBUG_TYPE "aarch64-collect-loh"
-static cl::opt<bool>
-PreCollectRegister("aarch64-collect-loh-pre-collect-register", cl::Hidden,
- cl::desc("Restrict analysis to registers invovled"
- " in LOHs"),
- cl::init(true));
-
-static cl::opt<bool>
-BasicBlockScopeOnly("aarch64-collect-loh-bb-only", cl::Hidden,
- cl::desc("Restrict analysis at basic block scope"),
- cl::init(true));
-
STATISTIC(NumADRPSimpleCandidate,
"Number of simplifiable ADRP dominate by another");
-STATISTIC(NumADRPComplexCandidate2,
- "Number of simplifiable ADRP reachable by 2 defs");
-STATISTIC(NumADRPComplexCandidate3,
- "Number of simplifiable ADRP reachable by 3 defs");
-STATISTIC(NumADRPComplexCandidateOther,
- "Number of simplifiable ADRP reachable by 4 or more defs");
-STATISTIC(NumADDToSTRWithImm,
- "Number of simplifiable STR with imm reachable by ADD");
-STATISTIC(NumLDRToSTRWithImm,
- "Number of simplifiable STR with imm reachable by LDR");
STATISTIC(NumADDToSTR, "Number of simplifiable STR reachable by ADD");
STATISTIC(NumLDRToSTR, "Number of simplifiable STR reachable by LDR");
-STATISTIC(NumADDToLDRWithImm,
- "Number of simplifiable LDR with imm reachable by ADD");
-STATISTIC(NumLDRToLDRWithImm,
- "Number of simplifiable LDR with imm reachable by LDR");
STATISTIC(NumADDToLDR, "Number of simplifiable LDR reachable by ADD");
STATISTIC(NumLDRToLDR, "Number of simplifiable LDR reachable by LDR");
STATISTIC(NumADRPToLDR, "Number of simplifiable LDR reachable by ADRP");
-STATISTIC(NumCplxLvl1, "Number of complex case of level 1");
-STATISTIC(NumTooCplxLvl1, "Number of too complex case of level 1");
-STATISTIC(NumCplxLvl2, "Number of complex case of level 2");
-STATISTIC(NumTooCplxLvl2, "Number of too complex case of level 2");
STATISTIC(NumADRSimpleCandidate, "Number of simplifiable ADRP + ADD");
-STATISTIC(NumADRComplexCandidate, "Number of too complex ADRP + ADD");
-
-namespace llvm {
-void initializeAArch64CollectLOHPass(PassRegistry &);
-}
#define AARCH64_COLLECT_LOH_NAME "AArch64 Collect Linker Optimization Hint (LOH)"
namespace {
+
struct AArch64CollectLOH : public MachineFunctionPass {
static char ID;
- AArch64CollectLOH() : MachineFunctionPass(ID) {
- initializeAArch64CollectLOHPass(*PassRegistry::getPassRegistry());
- }
+ AArch64CollectLOH() : MachineFunctionPass(ID) {}
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
- return AARCH64_COLLECT_LOH_NAME;
- }
+ StringRef getPassName() const override { return AARCH64_COLLECT_LOH_NAME; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
- AU.addRequired<MachineDominatorTree>();
+ AU.setPreservesAll();
}
-
-private:
};
-/// A set of MachineInstruction.
-typedef SetVector<const MachineInstr *> SetOfMachineInstr;
-/// Map a basic block to a set of instructions per register.
-/// This is used to represent the exposed uses of a basic block
-/// per register.
-typedef MapVector<const MachineBasicBlock *,
- std::unique_ptr<SetOfMachineInstr[]>>
-BlockToSetOfInstrsPerColor;
-/// Map a basic block to an instruction per register.
-/// This is used to represent the live-out definitions of a basic block
-/// per register.
-typedef MapVector<const MachineBasicBlock *,
- std::unique_ptr<const MachineInstr *[]>>
-BlockToInstrPerColor;
-/// Map an instruction to a set of instructions. Used to represent the
-/// mapping def to reachable uses or use to definitions.
-typedef MapVector<const MachineInstr *, SetOfMachineInstr> InstrToInstrs;
-/// Map a basic block to a BitVector.
-/// This is used to record the kill registers per basic block.
-typedef MapVector<const MachineBasicBlock *, BitVector> BlockToRegSet;
-
-/// Map a register to a dense id.
-typedef DenseMap<unsigned, unsigned> MapRegToId;
-/// Map a dense id to a register. Used for debug purposes.
-typedef SmallVector<unsigned, 32> MapIdToReg;
-} // end anonymous namespace.
-
char AArch64CollectLOH::ID = 0;
-INITIALIZE_PASS_BEGIN(AArch64CollectLOH, "aarch64-collect-loh",
- AARCH64_COLLECT_LOH_NAME, false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
-INITIALIZE_PASS_END(AArch64CollectLOH, "aarch64-collect-loh",
- AARCH64_COLLECT_LOH_NAME, false, false)
-
-/// Given a couple (MBB, reg) get the corresponding set of instruction from
-/// the given "sets".
-/// If this couple does not reference any set, an empty set is added to "sets"
-/// for this couple and returned.
-/// \param nbRegs is used internally allocate some memory. It must be consistent
-/// with the way sets is used.
-static SetOfMachineInstr &getSet(BlockToSetOfInstrsPerColor &sets,
- const MachineBasicBlock &MBB, unsigned reg,
- unsigned nbRegs) {
- SetOfMachineInstr *result;
- BlockToSetOfInstrsPerColor::iterator it = sets.find(&MBB);
- if (it != sets.end())
- result = it->second.get();
- else
- result = (sets[&MBB] = make_unique<SetOfMachineInstr[]>(nbRegs)).get();
-
- return result[reg];
-}
-
-/// Given a couple (reg, MI) get the corresponding set of instructions from the
-/// the given "sets".
-/// This is used to get the uses record in sets of a definition identified by
-/// MI and reg, i.e., MI defines reg.
-/// If the couple does not reference anything, an empty set is added to
-/// "sets[reg]".
-/// \pre set[reg] is valid.
-static SetOfMachineInstr &getUses(InstrToInstrs *sets, unsigned reg,
- const MachineInstr &MI) {
- return sets[reg][&MI];
-}
-
-/// Same as getUses but does not modify the input map: sets.
-/// \return NULL if the couple (reg, MI) is not in sets.
-static const SetOfMachineInstr *getUses(const InstrToInstrs *sets, unsigned reg,
- const MachineInstr &MI) {
- InstrToInstrs::const_iterator Res = sets[reg].find(&MI);
- if (Res != sets[reg].end())
- return &(Res->second);
- return nullptr;
-}
-
-/// Initialize the reaching definition algorithm:
-/// For each basic block BB in MF, record:
-/// - its kill set.
-/// - its reachable uses (uses that are exposed to BB's predecessors).
-/// - its the generated definitions.
-/// \param DummyOp if not NULL, specifies a Dummy Operation to be added to
-/// the list of uses of exposed defintions.
-/// \param ADRPMode specifies to only consider ADRP instructions for generated
-/// definition. It also consider definitions of ADRP instructions as uses and
-/// ignore other uses. The ADRPMode is used to collect the information for LHO
-/// that involve ADRP operation only.
-static void initReachingDef(const MachineFunction &MF,
- InstrToInstrs *ColorOpToReachedUses,
- BlockToInstrPerColor &Gen, BlockToRegSet &Kill,
- BlockToSetOfInstrsPerColor &ReachableUses,
- const MapRegToId &RegToId,
- const MachineInstr *DummyOp, bool ADRPMode) {
- const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
- unsigned NbReg = RegToId.size();
-
- for (const MachineBasicBlock &MBB : MF) {
- auto &BBGen = Gen[&MBB];
- BBGen = make_unique<const MachineInstr *[]>(NbReg);
- std::fill(BBGen.get(), BBGen.get() + NbReg, nullptr);
-
- BitVector &BBKillSet = Kill[&MBB];
- BBKillSet.resize(NbReg);
- for (const MachineInstr &MI : MBB) {
- bool IsADRP = MI.getOpcode() == AArch64::ADRP;
-
- // Process uses first.
- if (IsADRP || !ADRPMode)
- for (const MachineOperand &MO : MI.operands()) {
- // Treat ADRP def as use, as the goal of the analysis is to find
- // ADRP defs reached by other ADRP defs.
- if (!MO.isReg() || (!ADRPMode && !MO.isUse()) ||
- (ADRPMode && (!IsADRP || !MO.isDef())))
- continue;
- unsigned CurReg = MO.getReg();
- MapRegToId::const_iterator ItCurRegId = RegToId.find(CurReg);
- if (ItCurRegId == RegToId.end())
- continue;
- CurReg = ItCurRegId->second;
-
- // if CurReg has not been defined, this use is reachable.
- if (!BBGen[CurReg] && !BBKillSet.test(CurReg))
- getSet(ReachableUses, MBB, CurReg, NbReg).insert(&MI);
- // current basic block definition for this color, if any, is in Gen.
- if (BBGen[CurReg])
- getUses(ColorOpToReachedUses, CurReg, *BBGen[CurReg]).insert(&MI);
- }
-
- // Process clobbers.
- for (const MachineOperand &MO : MI.operands()) {
- if (!MO.isRegMask())
- continue;
- // Clobbers kill the related colors.
- const uint32_t *PreservedRegs = MO.getRegMask();
-
- // Set generated regs.
- for (const auto &Entry : RegToId) {
- unsigned Reg = Entry.second;
- // Use the global register ID when querying APIs external to this
- // pass.
- if (MachineOperand::clobbersPhysReg(PreservedRegs, Entry.first)) {
- // Do not register clobbered definition for no ADRP.
- // This definition is not used anyway (otherwise register
- // allocation is wrong).
- BBGen[Reg] = ADRPMode ? &MI : nullptr;
- BBKillSet.set(Reg);
- }
- }
- }
-
- // Process register defs.
- for (const MachineOperand &MO : MI.operands()) {
- if (!MO.isReg() || !MO.isDef())
- continue;
- unsigned CurReg = MO.getReg();
- MapRegToId::const_iterator ItCurRegId = RegToId.find(CurReg);
- if (ItCurRegId == RegToId.end())
- continue;
-
- for (MCRegAliasIterator AI(CurReg, TRI, true); AI.isValid(); ++AI) {
- MapRegToId::const_iterator ItRegId = RegToId.find(*AI);
- // If this alias has not been recorded, then it is not interesting
- // for the current analysis.
- // We can end up in this situation because of tuple registers.
- // E.g., Let say we are interested in S1. When we register
- // S1, we will also register its aliases and in particular
- // the tuple Q1_Q2.
- // Now, when we encounter Q1_Q2, we will look through its aliases
- // and will find that S2 is not registered.
- if (ItRegId == RegToId.end())
- continue;
-
- BBKillSet.set(ItRegId->second);
- BBGen[ItRegId->second] = &MI;
- }
- BBGen[ItCurRegId->second] = &MI;
- }
- }
-
- // If we restrict our analysis to basic block scope, conservatively add a
- // dummy
- // use for each generated value.
- if (!ADRPMode && DummyOp && !MBB.succ_empty())
- for (unsigned CurReg = 0; CurReg < NbReg; ++CurReg)
- if (BBGen[CurReg])
- getUses(ColorOpToReachedUses, CurReg, *BBGen[CurReg]).insert(DummyOp);
- }
-}
-
-/// Reaching def core algorithm:
-/// while an Out has changed
-/// for each bb
-/// for each color
-/// In[bb][color] = U Out[bb.predecessors][color]
-/// insert reachableUses[bb][color] in each in[bb][color]
-/// op.reachedUses
-///
-/// Out[bb] = Gen[bb] U (In[bb] - Kill[bb])
-static void reachingDefAlgorithm(const MachineFunction &MF,
- InstrToInstrs *ColorOpToReachedUses,
- BlockToSetOfInstrsPerColor &In,
- BlockToSetOfInstrsPerColor &Out,
- BlockToInstrPerColor &Gen, BlockToRegSet &Kill,
- BlockToSetOfInstrsPerColor &ReachableUses,
- unsigned NbReg) {
- bool HasChanged;
- do {
- HasChanged = false;
- for (const MachineBasicBlock &MBB : MF) {
- unsigned CurReg;
- for (CurReg = 0; CurReg < NbReg; ++CurReg) {
- SetOfMachineInstr &BBInSet = getSet(In, MBB, CurReg, NbReg);
- SetOfMachineInstr &BBReachableUses =
- getSet(ReachableUses, MBB, CurReg, NbReg);
- SetOfMachineInstr &BBOutSet = getSet(Out, MBB, CurReg, NbReg);
- unsigned Size = BBOutSet.size();
- // In[bb][color] = U Out[bb.predecessors][color]
- for (const MachineBasicBlock *PredMBB : MBB.predecessors()) {
- SetOfMachineInstr &PredOutSet = getSet(Out, *PredMBB, CurReg, NbReg);
- BBInSet.insert(PredOutSet.begin(), PredOutSet.end());
- }
- // insert reachableUses[bb][color] in each in[bb][color] op.reachedses
- for (const MachineInstr *MI : BBInSet) {
- SetOfMachineInstr &OpReachedUses =
- getUses(ColorOpToReachedUses, CurReg, *MI);
- OpReachedUses.insert(BBReachableUses.begin(), BBReachableUses.end());
- }
- // Out[bb] = Gen[bb] U (In[bb] - Kill[bb])
- if (!Kill[&MBB].test(CurReg))
- BBOutSet.insert(BBInSet.begin(), BBInSet.end());
- if (Gen[&MBB][CurReg])
- BBOutSet.insert(Gen[&MBB][CurReg]);
- HasChanged |= BBOutSet.size() != Size;
- }
- }
- } while (HasChanged);
-}
-
-/// Reaching definition algorithm.
-/// \param MF function on which the algorithm will operate.
-/// \param[out] ColorOpToReachedUses will contain the result of the reaching
-/// def algorithm.
-/// \param ADRPMode specify whether the reaching def algorithm should be tuned
-/// for ADRP optimization. \see initReachingDef for more details.
-/// \param DummyOp if not NULL, the algorithm will work at
-/// basic block scope and will set for every exposed definition a use to
-/// @p DummyOp.
-/// \pre ColorOpToReachedUses is an array of at least number of registers of
-/// InstrToInstrs.
-static void reachingDef(const MachineFunction &MF,
- InstrToInstrs *ColorOpToReachedUses,
- const MapRegToId &RegToId, bool ADRPMode = false,
- const MachineInstr *DummyOp = nullptr) {
- // structures:
- // For each basic block.
- // Out: a set per color of definitions that reach the
- // out boundary of this block.
- // In: Same as Out but for in boundary.
- // Gen: generated color in this block (one operation per color).
- // Kill: register set of killed color in this block.
- // ReachableUses: a set per color of uses (operation) reachable
- // for "In" definitions.
- BlockToSetOfInstrsPerColor Out, In, ReachableUses;
- BlockToInstrPerColor Gen;
- BlockToRegSet Kill;
-
- // Initialize Gen, kill and reachableUses.
- initReachingDef(MF, ColorOpToReachedUses, Gen, Kill, ReachableUses, RegToId,
- DummyOp, ADRPMode);
-
- // Algo.
- if (!DummyOp)
- reachingDefAlgorithm(MF, ColorOpToReachedUses, In, Out, Gen, Kill,
- ReachableUses, RegToId.size());
-}
+} // end anonymous namespace.
-#ifndef NDEBUG
-/// print the result of the reaching definition algorithm.
-static void printReachingDef(const InstrToInstrs *ColorOpToReachedUses,
- unsigned NbReg, const TargetRegisterInfo *TRI,
- const MapIdToReg &IdToReg) {
- unsigned CurReg;
- for (CurReg = 0; CurReg < NbReg; ++CurReg) {
- if (ColorOpToReachedUses[CurReg].empty())
- continue;
- DEBUG(dbgs() << "*** Reg " << PrintReg(IdToReg[CurReg], TRI) << " ***\n");
+INITIALIZE_PASS(AArch64CollectLOH, "aarch64-collect-loh",
+ AARCH64_COLLECT_LOH_NAME, false, false)
- for (const auto &DefsIt : ColorOpToReachedUses[CurReg]) {
- DEBUG(dbgs() << "Def:\n");
- DEBUG(DefsIt.first->print(dbgs()));
- DEBUG(dbgs() << "Reachable uses:\n");
- for (const MachineInstr *MI : DefsIt.second) {
- DEBUG(MI->print(dbgs()));
- }
- }
+static bool canAddBePartOfLOH(const MachineInstr &MI) {
+ // Check immediate to see if the immediate is an address.
+ switch (MI.getOperand(2).getType()) {
+ default:
+ return false;
+ case MachineOperand::MO_GlobalAddress:
+ case MachineOperand::MO_JumpTableIndex:
+ case MachineOperand::MO_ConstantPoolIndex:
+ case MachineOperand::MO_BlockAddress:
+ return true;
}
}
-#endif // NDEBUG
/// Answer the following question: Can Def be one of the definition
/// involved in a part of a LOH?
-static bool canDefBePartOfLOH(const MachineInstr *Def) {
- unsigned Opc = Def->getOpcode();
+static bool canDefBePartOfLOH(const MachineInstr &MI) {
// Accept ADRP, ADDLow and LOADGot.
- switch (Opc) {
+ switch (MI.getOpcode()) {
default:
return false;
case AArch64::ADRP:
return true;
case AArch64::ADDXri:
- // Check immediate to see if the immediate is an address.
- switch (Def->getOperand(2).getType()) {
- default:
- return false;
- case MachineOperand::MO_GlobalAddress:
- case MachineOperand::MO_JumpTableIndex:
- case MachineOperand::MO_ConstantPoolIndex:
- case MachineOperand::MO_BlockAddress:
- return true;
- }
+ return canAddBePartOfLOH(MI);
case AArch64::LDRXui:
// Check immediate to see if the immediate is an address.
- switch (Def->getOperand(2).getType()) {
+ switch (MI.getOperand(2).getType()) {
default:
return false;
case MachineOperand::MO_GlobalAddress:
- return true;
+ return MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT;
}
}
- // Unreachable.
- return false;
}
/// Check whether the given instruction can the end of a LOH chain involving a
/// store.
-static bool isCandidateStore(const MachineInstr *Instr) {
- switch (Instr->getOpcode()) {
+static bool isCandidateStore(const MachineInstr &MI, const MachineOperand &MO) {
+ switch (MI.getOpcode()) {
default:
return false;
case AArch64::STRBBui:
@@ -545,109 +211,19 @@ static bool isCandidateStore(const MachineInstr *Instr) {
case AArch64::STRSui:
case AArch64::STRDui:
case AArch64::STRQui:
+ // We can only optimize the index operand.
// In case we have str xA, [xA, #imm], this is two different uses
// of xA and we cannot fold, otherwise the xA stored may be wrong,
// even if #imm == 0.
- if (Instr->getOperand(0).getReg() != Instr->getOperand(1).getReg())
- return true;
- }
- return false;
-}
-
-/// Given the result of a reaching definition algorithm in ColorOpToReachedUses,
-/// Build the Use to Defs information and filter out obvious non-LOH candidates.
-/// In ADRPMode, non-LOH candidates are "uses" with non-ADRP definitions.
-/// In non-ADRPMode, non-LOH candidates are "uses" with several definition,
-/// i.e., no simple chain.
-/// \param ADRPMode -- \see initReachingDef.
-static void reachedUsesToDefs(InstrToInstrs &UseToReachingDefs,
- const InstrToInstrs *ColorOpToReachedUses,
- const MapRegToId &RegToId,
- bool ADRPMode = false) {
-
- SetOfMachineInstr NotCandidate;
- unsigned NbReg = RegToId.size();
- MapRegToId::const_iterator EndIt = RegToId.end();
- for (unsigned CurReg = 0; CurReg < NbReg; ++CurReg) {
- // If this color is never defined, continue.
- if (ColorOpToReachedUses[CurReg].empty())
- continue;
-
- for (const auto &DefsIt : ColorOpToReachedUses[CurReg]) {
- for (const MachineInstr *MI : DefsIt.second) {
- const MachineInstr *Def = DefsIt.first;
- MapRegToId::const_iterator It;
- // if all the reaching defs are not adrp, this use will not be
- // simplifiable.
- if ((ADRPMode && Def->getOpcode() != AArch64::ADRP) ||
- (!ADRPMode && !canDefBePartOfLOH(Def)) ||
- (!ADRPMode && isCandidateStore(MI) &&
- // store are LOH candidate iff the end of the chain is used as
- // base.
- ((It = RegToId.find((MI)->getOperand(1).getReg())) == EndIt ||
- It->second != CurReg))) {
- NotCandidate.insert(MI);
- continue;
- }
- // Do not consider self reaching as a simplifiable case for ADRP.
- if (!ADRPMode || MI != DefsIt.first) {
- UseToReachingDefs[MI].insert(DefsIt.first);
- // If UsesIt has several reaching definitions, it is not
- // candidate for simplificaton in non-ADRPMode.
- if (!ADRPMode && UseToReachingDefs[MI].size() > 1)
- NotCandidate.insert(MI);
- }
- }
- }
- }
- for (const MachineInstr *Elem : NotCandidate) {
- DEBUG(dbgs() << "Too many reaching defs: " << *Elem << "\n");
- // It would have been better if we could just remove the entry
- // from the map. Because of that, we have to filter the garbage
- // (second.empty) in the subsequence analysis.
- UseToReachingDefs[Elem].clear();
- }
-}
-
-/// Based on the use to defs information (in ADRPMode), compute the
-/// opportunities of LOH ADRP-related.
-static void computeADRP(const InstrToInstrs &UseToDefs,
- AArch64FunctionInfo &AArch64FI,
- const MachineDominatorTree *MDT) {
- DEBUG(dbgs() << "*** Compute LOH for ADRP\n");
- for (const auto &Entry : UseToDefs) {
- unsigned Size = Entry.second.size();
- if (Size == 0)
- continue;
- if (Size == 1) {
- const MachineInstr *L2 = *Entry.second.begin();
- const MachineInstr *L1 = Entry.first;
- if (!MDT->dominates(L2, L1)) {
- DEBUG(dbgs() << "Dominance check failed:\n" << *L2 << '\n' << *L1
- << '\n');
- continue;
- }
- DEBUG(dbgs() << "Record AdrpAdrp:\n" << *L2 << '\n' << *L1 << '\n');
- AArch64FI.addLOHDirective(MCLOH_AdrpAdrp, {L2, L1});
- ++NumADRPSimpleCandidate;
- }
-#ifdef DEBUG
- else if (Size == 2)
- ++NumADRPComplexCandidate2;
- else if (Size == 3)
- ++NumADRPComplexCandidate3;
- else
- ++NumADRPComplexCandidateOther;
-#endif
- // if Size < 1, the use should have been removed from the candidates
- assert(Size >= 1 && "No reaching defs for that use!");
+ return MI.getOperandNo(&MO) == 1 &&
+ MI.getOperand(0).getReg() != MI.getOperand(1).getReg();
}
}
/// Check whether the given instruction can be the end of a LOH chain
/// involving a load.
-static bool isCandidateLoad(const MachineInstr *Instr) {
- switch (Instr->getOpcode()) {
+static bool isCandidateLoad(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
default:
return false;
case AArch64::LDRSBWui:
@@ -662,17 +238,13 @@ static bool isCandidateLoad(const MachineInstr *Instr) {
case AArch64::LDRSui:
case AArch64::LDRDui:
case AArch64::LDRQui:
- if (Instr->getOperand(2).getTargetFlags() & AArch64II::MO_GOT)
- return false;
- return true;
+ return !(MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT);
}
- // Unreachable.
- return false;
}
/// Check whether the given instruction can load a litteral.
-static bool supportLoadFromLiteral(const MachineInstr *Instr) {
- switch (Instr->getOpcode()) {
+static bool supportLoadFromLiteral(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
default:
return false;
case AArch64::LDRSWui:
@@ -683,353 +255,233 @@ static bool supportLoadFromLiteral(const MachineInstr *Instr) {
case AArch64::LDRQui:
return true;
}
- // Unreachable.
- return false;
}
-/// Check whether the given instruction is a LOH candidate.
-/// \param UseToDefs is used to check that Instr is at the end of LOH supported
-/// chain.
-/// \pre UseToDefs contains only on def per use, i.e., obvious non candidate are
-/// already been filtered out.
-static bool isCandidate(const MachineInstr *Instr,
- const InstrToInstrs &UseToDefs,
- const MachineDominatorTree *MDT) {
- if (!isCandidateLoad(Instr) && !isCandidateStore(Instr))
- return false;
+/// Number of GPR registers traked by mapRegToGPRIndex()
+static const unsigned N_GPR_REGS = 31;
+/// Map register number to index from 0-30.
+static int mapRegToGPRIndex(MCPhysReg Reg) {
+ static_assert(AArch64::X28 - AArch64::X0 + 3 == N_GPR_REGS, "Number of GPRs");
+ static_assert(AArch64::W30 - AArch64::W0 + 1 == N_GPR_REGS, "Number of GPRs");
+ if (AArch64::X0 <= Reg && Reg <= AArch64::X28)
+ return Reg - AArch64::X0;
+ if (AArch64::W0 <= Reg && Reg <= AArch64::W30)
+ return Reg - AArch64::W0;
+ // TableGen gives "FP" and "LR" an index not adjacent to X28 so we have to
+ // handle them as special cases.
+ if (Reg == AArch64::FP)
+ return 29;
+ if (Reg == AArch64::LR)
+ return 30;
+ return -1;
+}
- const MachineInstr *Def = *UseToDefs.find(Instr)->second.begin();
- if (Def->getOpcode() != AArch64::ADRP) {
- // At this point, Def is ADDXri or LDRXui of the right type of
- // symbol, because we filtered out the uses that were not defined
- // by these kind of instructions (+ ADRP).
+/// State tracked per register.
+/// The main algorithm walks backwards over a basic block maintaining this
+/// datastructure for each tracked general purpose register.
+struct LOHInfo {
+ MCLOHType Type : 8; ///< "Best" type of LOH possible.
+ bool IsCandidate : 1; ///< Possible LOH candidate.
+ bool OneUser : 1; ///< Found exactly one user (yet).
+ bool MultiUsers : 1; ///< Found multiple users.
+ const MachineInstr *MI0; ///< First instruction involved in the LOH.
+ const MachineInstr *MI1; ///< Second instruction involved in the LOH
+ /// (if any).
+ const MachineInstr *LastADRP; ///< Last ADRP in same register.
+};
- // Check if this forms a simple chain: each intermediate node must
- // dominates the next one.
- if (!MDT->dominates(Def, Instr))
- return false;
- // Move one node up in the simple chain.
- if (UseToDefs.find(Def) ==
- UseToDefs.end()
- // The map may contain garbage we have to ignore.
- ||
- UseToDefs.find(Def)->second.empty())
- return false;
- Instr = Def;
- Def = *UseToDefs.find(Def)->second.begin();
+/// Update state \p Info given \p MI uses the tracked register.
+static void handleUse(const MachineInstr &MI, const MachineOperand &MO,
+ LOHInfo &Info) {
+ // We have multiple uses if we already found one before.
+ if (Info.MultiUsers || Info.OneUser) {
+ Info.IsCandidate = false;
+ Info.MultiUsers = true;
+ return;
}
- // Check if we reached the top of the simple chain:
- // - top is ADRP.
- // - check the simple chain property: each intermediate node must
- // dominates the next one.
- if (Def->getOpcode() == AArch64::ADRP)
- return MDT->dominates(Def, Instr);
- return false;
-}
-
-static bool registerADRCandidate(const MachineInstr &Use,
- const InstrToInstrs &UseToDefs,
- const InstrToInstrs *DefsPerColorToUses,
- AArch64FunctionInfo &AArch64FI,
- SetOfMachineInstr *InvolvedInLOHs,
- const MapRegToId &RegToId) {
- // Look for opportunities to turn ADRP -> ADD or
- // ADRP -> LDR GOTPAGEOFF into ADR.
- // If ADRP has more than one use. Give up.
- if (Use.getOpcode() != AArch64::ADDXri &&
- (Use.getOpcode() != AArch64::LDRXui ||
- !(Use.getOperand(2).getTargetFlags() & AArch64II::MO_GOT)))
- return false;
- InstrToInstrs::const_iterator It = UseToDefs.find(&Use);
- // The map may contain garbage that we need to ignore.
- if (It == UseToDefs.end() || It->second.empty())
- return false;
- const MachineInstr &Def = **It->second.begin();
- if (Def.getOpcode() != AArch64::ADRP)
- return false;
- // Check the number of users of ADRP.
- const SetOfMachineInstr *Users =
- getUses(DefsPerColorToUses,
- RegToId.find(Def.getOperand(0).getReg())->second, Def);
- if (Users->size() > 1) {
- ++NumADRComplexCandidate;
- return false;
+ Info.OneUser = true;
+
+ // Start new LOHInfo if applicable.
+ if (isCandidateLoad(MI)) {
+ Info.Type = MCLOH_AdrpLdr;
+ Info.IsCandidate = true;
+ Info.MI0 = &MI;
+ // Note that even this is AdrpLdr now, we can switch to a Ldr variant
+ // later.
+ } else if (isCandidateStore(MI, MO)) {
+ Info.Type = MCLOH_AdrpAddStr;
+ Info.IsCandidate = true;
+ Info.MI0 = &MI;
+ Info.MI1 = nullptr;
+ } else if (MI.getOpcode() == AArch64::ADDXri) {
+ Info.Type = MCLOH_AdrpAdd;
+ Info.IsCandidate = true;
+ Info.MI0 = &MI;
+ } else if (MI.getOpcode() == AArch64::LDRXui &&
+ MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) {
+ Info.Type = MCLOH_AdrpLdrGot;
+ Info.IsCandidate = true;
+ Info.MI0 = &MI;
}
- ++NumADRSimpleCandidate;
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(&Def)) &&
- "ADRP already involved in LOH.");
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(&Use)) &&
- "ADD already involved in LOH.");
- DEBUG(dbgs() << "Record AdrpAdd\n" << Def << '\n' << Use << '\n');
-
- AArch64FI.addLOHDirective(
- Use.getOpcode() == AArch64::ADDXri ? MCLOH_AdrpAdd : MCLOH_AdrpLdrGot,
- {&Def, &Use});
- return true;
}
-/// Based on the use to defs information (in non-ADRPMode), compute the
-/// opportunities of LOH non-ADRP-related
-static void computeOthers(const InstrToInstrs &UseToDefs,
- const InstrToInstrs *DefsPerColorToUses,
- AArch64FunctionInfo &AArch64FI, const MapRegToId &RegToId,
- const MachineDominatorTree *MDT) {
- SetOfMachineInstr *InvolvedInLOHs = nullptr;
-#ifdef DEBUG
- SetOfMachineInstr InvolvedInLOHsStorage;
- InvolvedInLOHs = &InvolvedInLOHsStorage;
-#endif // DEBUG
- DEBUG(dbgs() << "*** Compute LOH for Others\n");
- // ADRP -> ADD/LDR -> LDR/STR pattern.
- // Fall back to ADRP -> ADD pattern if we fail to catch the bigger pattern.
+/// Update state \p Info given the tracked register is clobbered.
+static void handleClobber(LOHInfo &Info) {
+ Info.IsCandidate = false;
+ Info.OneUser = false;
+ Info.MultiUsers = false;
+ Info.LastADRP = nullptr;
+}
- // FIXME: When the statistics are not important,
- // This initial filtering loop can be merged into the next loop.
- // Currently, we didn't do it to have the same code for both DEBUG and
- // NDEBUG builds. Indeed, the iterator of the second loop would need
- // to be changed.
- SetOfMachineInstr PotentialCandidates;
- SetOfMachineInstr PotentialADROpportunities;
- for (auto &Use : UseToDefs) {
- // If no definition is available, this is a non candidate.
- if (Use.second.empty())
- continue;
- // Keep only instructions that are load or store and at the end of
- // a ADRP -> ADD/LDR/Nothing chain.
- // We already filtered out the no-chain cases.
- if (!isCandidate(Use.first, UseToDefs, MDT)) {
- PotentialADROpportunities.insert(Use.first);
- continue;
+/// Update state \p Info given that \p MI is possibly the middle instruction
+/// of an LOH involving 3 instructions.
+static bool handleMiddleInst(const MachineInstr &MI, LOHInfo &DefInfo,
+ LOHInfo &OpInfo) {
+ if (!DefInfo.IsCandidate || (&DefInfo != &OpInfo && OpInfo.OneUser))
+ return false;
+ // Copy LOHInfo for dest register to LOHInfo for source register.
+ if (&DefInfo != &OpInfo) {
+ OpInfo = DefInfo;
+ // Invalidate \p DefInfo because we track it in \p OpInfo now.
+ handleClobber(DefInfo);
+ } else
+ DefInfo.LastADRP = nullptr;
+
+ // Advance state machine.
+ assert(OpInfo.IsCandidate && "Expect valid state");
+ if (MI.getOpcode() == AArch64::ADDXri && canAddBePartOfLOH(MI)) {
+ if (OpInfo.Type == MCLOH_AdrpLdr) {
+ OpInfo.Type = MCLOH_AdrpAddLdr;
+ OpInfo.IsCandidate = true;
+ OpInfo.MI1 = &MI;
+ return true;
+ } else if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) {
+ OpInfo.Type = MCLOH_AdrpAddStr;
+ OpInfo.IsCandidate = true;
+ OpInfo.MI1 = &MI;
+ return true;
}
- PotentialCandidates.insert(Use.first);
- }
-
- // Make the following distinctions for statistics as the linker does
- // know how to decode instructions:
- // - ADD/LDR/Nothing make there different patterns.
- // - LDR/STR make two different patterns.
- // Hence, 6 - 1 base patterns.
- // (because ADRP-> Nothing -> STR is not simplifiable)
-
- // The linker is only able to have a simple semantic, i.e., if pattern A
- // do B.
- // However, we want to see the opportunity we may miss if we were able to
- // catch more complex cases.
-
- // PotentialCandidates are result of a chain ADRP -> ADD/LDR ->
- // A potential candidate becomes a candidate, if its current immediate
- // operand is zero and all nodes of the chain have respectively only one user
-#ifdef DEBUG
- SetOfMachineInstr DefsOfPotentialCandidates;
-#endif
- for (const MachineInstr *Candidate : PotentialCandidates) {
- // Get the definition of the candidate i.e., ADD or LDR.
- const MachineInstr *Def = *UseToDefs.find(Candidate)->second.begin();
- // Record the elements of the chain.
- const MachineInstr *L1 = Def;
- const MachineInstr *L2 = nullptr;
- unsigned ImmediateDefOpc = Def->getOpcode();
- if (Def->getOpcode() != AArch64::ADRP) {
- // Check the number of users of this node.
- const SetOfMachineInstr *Users =
- getUses(DefsPerColorToUses,
- RegToId.find(Def->getOperand(0).getReg())->second, *Def);
- if (Users->size() > 1) {
-#ifdef DEBUG
- // if all the uses of this def are in potential candidate, this is
- // a complex candidate of level 2.
- bool IsLevel2 = true;
- for (const MachineInstr *MI : *Users) {
- if (!PotentialCandidates.count(MI)) {
- ++NumTooCplxLvl2;
- IsLevel2 = false;
- break;
- }
- }
- if (IsLevel2)
- ++NumCplxLvl2;
-#endif // DEBUG
- PotentialADROpportunities.insert(Def);
- continue;
- }
- L2 = Def;
- Def = *UseToDefs.find(Def)->second.begin();
- L1 = Def;
- } // else the element in the middle of the chain is nothing, thus
- // Def already contains the first element of the chain.
-
- // Check the number of users of the first node in the chain, i.e., ADRP
- const SetOfMachineInstr *Users =
- getUses(DefsPerColorToUses,
- RegToId.find(Def->getOperand(0).getReg())->second, *Def);
- if (Users->size() > 1) {
-#ifdef DEBUG
- // if all the uses of this def are in the defs of the potential candidate,
- // this is a complex candidate of level 1
- if (DefsOfPotentialCandidates.empty()) {
- // lazy init
- DefsOfPotentialCandidates = PotentialCandidates;
- for (const MachineInstr *Candidate : PotentialCandidates) {
- if (!UseToDefs.find(Candidate)->second.empty())
- DefsOfPotentialCandidates.insert(
- *UseToDefs.find(Candidate)->second.begin());
- }
- }
- bool Found = false;
- for (auto &Use : *Users) {
- if (!DefsOfPotentialCandidates.count(Use)) {
- ++NumTooCplxLvl1;
- Found = true;
- break;
- }
- }
- if (!Found)
- ++NumCplxLvl1;
-#endif // DEBUG
- continue;
+ } else {
+ assert(MI.getOpcode() == AArch64::LDRXui && "Expect LDRXui");
+ assert((MI.getOperand(2).getTargetFlags() & AArch64II::MO_GOT) &&
+ "Expected GOT relocation");
+ if (OpInfo.Type == MCLOH_AdrpAddStr && OpInfo.MI1 == nullptr) {
+ OpInfo.Type = MCLOH_AdrpLdrGotStr;
+ OpInfo.IsCandidate = true;
+ OpInfo.MI1 = &MI;
+ return true;
+ } else if (OpInfo.Type == MCLOH_AdrpLdr) {
+ OpInfo.Type = MCLOH_AdrpLdrGotLdr;
+ OpInfo.IsCandidate = true;
+ OpInfo.MI1 = &MI;
+ return true;
}
+ }
+ return false;
+}
- bool IsL2Add = (ImmediateDefOpc == AArch64::ADDXri);
- // If the chain is three instructions long and ldr is the second element,
- // then this ldr must load form GOT, otherwise this is not a correct chain.
- if (L2 && !IsL2Add &&
- !(L2->getOperand(2).getTargetFlags() & AArch64II::MO_GOT))
- continue;
- SmallVector<const MachineInstr *, 3> Args;
- MCLOHType Kind;
- if (isCandidateLoad(Candidate)) {
- if (!L2) {
- // At this point, the candidate LOH indicates that the ldr instruction
- // may use a direct access to the symbol. There is not such encoding
- // for loads of byte and half.
- if (!supportLoadFromLiteral(Candidate))
- continue;
+/// Update state when seeing and ADRP instruction.
+static void handleADRP(const MachineInstr &MI, AArch64FunctionInfo &AFI,
+ LOHInfo &Info) {
+ if (Info.LastADRP != nullptr) {
+ DEBUG(dbgs() << "Adding MCLOH_AdrpAdrp:\n" << '\t' << MI << '\t'
+ << *Info.LastADRP);
+ AFI.addLOHDirective(MCLOH_AdrpAdrp, {&MI, Info.LastADRP});
+ ++NumADRPSimpleCandidate;
+ }
- DEBUG(dbgs() << "Record AdrpLdr:\n" << *L1 << '\n' << *Candidate
- << '\n');
- Kind = MCLOH_AdrpLdr;
- Args.push_back(L1);
- Args.push_back(Candidate);
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L1)) &&
- "L1 already involved in LOH.");
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Candidate)) &&
- "Candidate already involved in LOH.");
+ // Produce LOH directive if possible.
+ if (Info.IsCandidate) {
+ switch (Info.Type) {
+ case MCLOH_AdrpAdd:
+ DEBUG(dbgs() << "Adding MCLOH_AdrpAdd:\n" << '\t' << MI << '\t'
+ << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpAdd, {&MI, Info.MI0});
+ ++NumADRSimpleCandidate;
+ break;
+ case MCLOH_AdrpLdr:
+ if (supportLoadFromLiteral(*Info.MI0)) {
+ DEBUG(dbgs() << "Adding MCLOH_AdrpLdr:\n" << '\t' << MI << '\t'
+ << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpLdr, {&MI, Info.MI0});
++NumADRPToLDR;
- } else {
- DEBUG(dbgs() << "Record Adrp" << (IsL2Add ? "Add" : "LdrGot")
- << "Ldr:\n" << *L1 << '\n' << *L2 << '\n' << *Candidate
- << '\n');
-
- Kind = IsL2Add ? MCLOH_AdrpAddLdr : MCLOH_AdrpLdrGotLdr;
- Args.push_back(L1);
- Args.push_back(L2);
- Args.push_back(Candidate);
-
- PotentialADROpportunities.remove(L2);
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L1)) &&
- "L1 already involved in LOH.");
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L2)) &&
- "L2 already involved in LOH.");
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Candidate)) &&
- "Candidate already involved in LOH.");
-#ifdef DEBUG
- // get the immediate of the load
- if (Candidate->getOperand(2).getImm() == 0)
- if (ImmediateDefOpc == AArch64::ADDXri)
- ++NumADDToLDR;
- else
- ++NumLDRToLDR;
- else if (ImmediateDefOpc == AArch64::ADDXri)
- ++NumADDToLDRWithImm;
- else
- ++NumLDRToLDRWithImm;
-#endif // DEBUG
}
- } else {
- if (ImmediateDefOpc == AArch64::ADRP)
- continue;
- else {
-
- DEBUG(dbgs() << "Record Adrp" << (IsL2Add ? "Add" : "LdrGot")
- << "Str:\n" << *L1 << '\n' << *L2 << '\n' << *Candidate
- << '\n');
-
- Kind = IsL2Add ? MCLOH_AdrpAddStr : MCLOH_AdrpLdrGotStr;
- Args.push_back(L1);
- Args.push_back(L2);
- Args.push_back(Candidate);
-
- PotentialADROpportunities.remove(L2);
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L1)) &&
- "L1 already involved in LOH.");
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L2)) &&
- "L2 already involved in LOH.");
- assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Candidate)) &&
- "Candidate already involved in LOH.");
-#ifdef DEBUG
- // get the immediate of the store
- if (Candidate->getOperand(2).getImm() == 0)
- if (ImmediateDefOpc == AArch64::ADDXri)
- ++NumADDToSTR;
- else
- ++NumLDRToSTR;
- else if (ImmediateDefOpc == AArch64::ADDXri)
- ++NumADDToSTRWithImm;
- else
- ++NumLDRToSTRWithImm;
-#endif // DEBUG
+ break;
+ case MCLOH_AdrpAddLdr:
+ DEBUG(dbgs() << "Adding MCLOH_AdrpAddLdr:\n" << '\t' << MI << '\t'
+ << *Info.MI1 << '\t' << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpAddLdr, {&MI, Info.MI1, Info.MI0});
+ ++NumADDToLDR;
+ break;
+ case MCLOH_AdrpAddStr:
+ if (Info.MI1 != nullptr) {
+ DEBUG(dbgs() << "Adding MCLOH_AdrpAddStr:\n" << '\t' << MI << '\t'
+ << *Info.MI1 << '\t' << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpAddStr, {&MI, Info.MI1, Info.MI0});
+ ++NumADDToSTR;
}
+ break;
+ case MCLOH_AdrpLdrGotLdr:
+ DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotLdr:\n" << '\t' << MI << '\t'
+ << *Info.MI1 << '\t' << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpLdrGotLdr, {&MI, Info.MI1, Info.MI0});
+ ++NumLDRToLDR;
+ break;
+ case MCLOH_AdrpLdrGotStr:
+ DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGotStr:\n" << '\t' << MI << '\t'
+ << *Info.MI1 << '\t' << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpLdrGotStr, {&MI, Info.MI1, Info.MI0});
+ ++NumLDRToSTR;
+ break;
+ case MCLOH_AdrpLdrGot:
+ DEBUG(dbgs() << "Adding MCLOH_AdrpLdrGot:\n" << '\t' << MI << '\t'
+ << *Info.MI0);
+ AFI.addLOHDirective(MCLOH_AdrpLdrGot, {&MI, Info.MI0});
+ break;
+ case MCLOH_AdrpAdrp:
+ llvm_unreachable("MCLOH_AdrpAdrp not used in state machine");
}
- AArch64FI.addLOHDirective(Kind, Args);
}
- // Now, we grabbed all the big patterns, check ADR opportunities.
- for (const MachineInstr *Candidate : PotentialADROpportunities)
- registerADRCandidate(*Candidate, UseToDefs, DefsPerColorToUses, AArch64FI,
- InvolvedInLOHs, RegToId);
+ handleClobber(Info);
+ Info.LastADRP = &MI;
}
-/// Look for every register defined by potential LOHs candidates.
-/// Map these registers with dense id in @p RegToId and vice-versa in
-/// @p IdToReg. @p IdToReg is populated only in DEBUG mode.
-static void collectInvolvedReg(const MachineFunction &MF, MapRegToId &RegToId,
- MapIdToReg &IdToReg,
- const TargetRegisterInfo *TRI) {
- unsigned CurRegId = 0;
- if (!PreCollectRegister) {
- unsigned NbReg = TRI->getNumRegs();
- for (; CurRegId < NbReg; ++CurRegId) {
- RegToId[CurRegId] = CurRegId;
- DEBUG(IdToReg.push_back(CurRegId));
- DEBUG(assert(IdToReg[CurRegId] == CurRegId && "Reg index mismatches"));
- }
+static void handleRegMaskClobber(const uint32_t *RegMask, MCPhysReg Reg,
+ LOHInfo *LOHInfos) {
+ if (!MachineOperand::clobbersPhysReg(RegMask, Reg))
return;
- }
-
- DEBUG(dbgs() << "** Collect Involved Register\n");
- for (const auto &MBB : MF) {
- for (const MachineInstr &MI : MBB) {
- if (!canDefBePartOfLOH(&MI) &&
- !isCandidateLoad(&MI) && !isCandidateStore(&MI))
- continue;
+ int Idx = mapRegToGPRIndex(Reg);
+ if (Idx >= 0)
+ handleClobber(LOHInfos[Idx]);
+}
- // Process defs
- for (MachineInstr::const_mop_iterator IO = MI.operands_begin(),
- IOEnd = MI.operands_end();
- IO != IOEnd; ++IO) {
- if (!IO->isReg() || !IO->isDef())
- continue;
- unsigned CurReg = IO->getReg();
- for (MCRegAliasIterator AI(CurReg, TRI, true); AI.isValid(); ++AI)
- if (RegToId.find(*AI) == RegToId.end()) {
- DEBUG(IdToReg.push_back(*AI);
- assert(IdToReg[CurRegId] == *AI &&
- "Reg index mismatches insertion index."));
- RegToId[*AI] = CurRegId++;
- DEBUG(dbgs() << "Register: " << PrintReg(*AI, TRI) << '\n');
- }
- }
+static void handleNormalInst(const MachineInstr &MI, LOHInfo *LOHInfos) {
+ // Handle defs and regmasks.
+ for (const MachineOperand &MO : MI.operands()) {
+ if (MO.isRegMask()) {
+ const uint32_t *RegMask = MO.getRegMask();
+ for (MCPhysReg Reg : AArch64::GPR32RegClass)
+ handleRegMaskClobber(RegMask, Reg, LOHInfos);
+ for (MCPhysReg Reg : AArch64::GPR64RegClass)
+ handleRegMaskClobber(RegMask, Reg, LOHInfos);
+ continue;
}
+ if (!MO.isReg() || !MO.isDef())
+ continue;
+ int Idx = mapRegToGPRIndex(MO.getReg());
+ if (Idx < 0)
+ continue;
+ handleClobber(LOHInfos[Idx]);
+ }
+ // Handle uses.
+ for (const MachineOperand &MO : MI.uses()) {
+ if (!MO.isReg() || !MO.readsReg())
+ continue;
+ int Idx = mapRegToGPRIndex(MO.getReg());
+ if (Idx < 0)
+ continue;
+ handleUse(MI, MO, LOHInfos[Idx]);
}
}
@@ -1037,74 +489,59 @@ bool AArch64CollectLOH::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
- const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
- const MachineDominatorTree *MDT = &getAnalysis<MachineDominatorTree>();
-
- MapRegToId RegToId;
- MapIdToReg IdToReg;
- AArch64FunctionInfo *AArch64FI = MF.getInfo<AArch64FunctionInfo>();
- assert(AArch64FI && "No MachineFunctionInfo for this function!");
-
- DEBUG(dbgs() << "Looking for LOH in " << MF.getName() << '\n');
+ DEBUG(dbgs() << "********** AArch64 Collect LOH **********\n"
+ << "Looking in function " << MF.getName() << '\n');
- collectInvolvedReg(MF, RegToId, IdToReg, TRI);
- if (RegToId.empty())
- return false;
+ LOHInfo LOHInfos[N_GPR_REGS];
+ AArch64FunctionInfo &AFI = *MF.getInfo<AArch64FunctionInfo>();
+ for (const MachineBasicBlock &MBB : MF) {
+ // Reset register tracking state.
+ memset(LOHInfos, 0, sizeof(LOHInfos));
+ // Live-out registers are used.
+ for (const MachineBasicBlock *Succ : MBB.successors()) {
+ for (const auto &LI : Succ->liveins()) {
+ int RegIdx = mapRegToGPRIndex(LI.PhysReg);
+ if (RegIdx >= 0)
+ LOHInfos[RegIdx].OneUser = true;
+ }
+ }
- MachineInstr *DummyOp = nullptr;
- if (BasicBlockScopeOnly) {
- const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
- // For local analysis, create a dummy operation to record uses that are not
- // local.
- DummyOp = MF.CreateMachineInstr(TII->get(AArch64::COPY), DebugLoc());
+ // Walk the basic block backwards and update the per register state machine
+ // in the process.
+ for (const MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) {
+ unsigned Opcode = MI.getOpcode();
+ switch (Opcode) {
+ case AArch64::ADDXri:
+ case AArch64::LDRXui:
+ if (canDefBePartOfLOH(MI)) {
+ const MachineOperand &Def = MI.getOperand(0);
+ const MachineOperand &Op = MI.getOperand(1);
+ assert(Def.isReg() && Def.isDef() && "Expected reg def");
+ assert(Op.isReg() && Op.isUse() && "Expected reg use");
+ int DefIdx = mapRegToGPRIndex(Def.getReg());
+ int OpIdx = mapRegToGPRIndex(Op.getReg());
+ if (DefIdx >= 0 && OpIdx >= 0 &&
+ handleMiddleInst(MI, LOHInfos[DefIdx], LOHInfos[OpIdx]))
+ continue;
+ }
+ break;
+ case AArch64::ADRP:
+ const MachineOperand &Op0 = MI.getOperand(0);
+ int Idx = mapRegToGPRIndex(Op0.getReg());
+ if (Idx >= 0) {
+ handleADRP(MI, AFI, LOHInfos[Idx]);
+ continue;
+ }
+ break;
+ }
+ handleNormalInst(MI, LOHInfos);
+ }
}
- unsigned NbReg = RegToId.size();
- bool Modified = false;
-
- // Start with ADRP.
- InstrToInstrs *ColorOpToReachedUses = new InstrToInstrs[NbReg];
-
- // Compute the reaching def in ADRP mode, meaning ADRP definitions
- // are first considered as uses.
- reachingDef(MF, ColorOpToReachedUses, RegToId, true, DummyOp);
- DEBUG(dbgs() << "ADRP reaching defs\n");
- DEBUG(printReachingDef(ColorOpToReachedUses, NbReg, TRI, IdToReg));
-
- // Translate the definition to uses map into a use to definitions map to ease
- // statistic computation.
- InstrToInstrs ADRPToReachingDefs;
- reachedUsesToDefs(ADRPToReachingDefs, ColorOpToReachedUses, RegToId, true);
-
- // Compute LOH for ADRP.
- computeADRP(ADRPToReachingDefs, *AArch64FI, MDT);
- delete[] ColorOpToReachedUses;
-
- // Continue with general ADRP -> ADD/LDR -> LDR/STR pattern.
- ColorOpToReachedUses = new InstrToInstrs[NbReg];
-
- // first perform a regular reaching def analysis.
- reachingDef(MF, ColorOpToReachedUses, RegToId, false, DummyOp);
- DEBUG(dbgs() << "All reaching defs\n");
- DEBUG(printReachingDef(ColorOpToReachedUses, NbReg, TRI, IdToReg));
-
- // Turn that into a use to defs to ease statistic computation.
- InstrToInstrs UsesToReachingDefs;
- reachedUsesToDefs(UsesToReachingDefs, ColorOpToReachedUses, RegToId, false);
-
- // Compute other than AdrpAdrp LOH.
- computeOthers(UsesToReachingDefs, ColorOpToReachedUses, *AArch64FI, RegToId,
- MDT);
- delete[] ColorOpToReachedUses;
-
- if (BasicBlockScopeOnly)
- MF.DeleteMachineInstr(DummyOp);
-
- return Modified;
+ // Return "no change": The pass only collects information.
+ return false;
}
-/// createAArch64CollectLOHPass - returns an instance of the Statistic for
-/// linker optimization pass.
FunctionPass *llvm::createAArch64CollectLOHPass() {
return new AArch64CollectLOH();
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
index 8fff381..8b18632 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64ConditionOptimizer.cpp
@@ -95,7 +95,9 @@ public:
typedef std::tuple<int, unsigned, AArch64CC::CondCode> CmpInfo;
static char ID;
- AArch64ConditionOptimizer() : MachineFunctionPass(ID) {}
+ AArch64ConditionOptimizer() : MachineFunctionPass(ID) {
+ initializeAArch64ConditionOptimizerPass(*PassRegistry::getPassRegistry());
+ }
void getAnalysisUsage(AnalysisUsage &AU) const override;
MachineInstr *findSuitableCompare(MachineBasicBlock *MBB);
CmpInfo adjustCmp(MachineInstr *CmpMI, AArch64CC::CondCode Cmp);
@@ -103,7 +105,7 @@ public:
bool adjustTo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp, MachineInstr *To,
int ToImm);
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AArch64 Condition Optimizer";
}
};
@@ -111,10 +113,6 @@ public:
char AArch64ConditionOptimizer::ID = 0;
-namespace llvm {
-void initializeAArch64ConditionOptimizerPass(PassRegistry &);
-}
-
INITIALIZE_PASS_BEGIN(AArch64ConditionOptimizer, "aarch64-condopt",
"AArch64 CondOpt Pass", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
index e1b0dc7..da09b36 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
@@ -329,7 +329,7 @@ MachineInstr *SSACCmpConv::findConvertibleCompare(MachineBasicBlock *MBB) {
++NumImmRangeRejs;
return nullptr;
}
- // Fall through.
+ LLVM_FALLTHROUGH;
case AArch64::SUBSWrr:
case AArch64::SUBSXrr:
case AArch64::ADDSWrr:
@@ -568,7 +568,7 @@ void SSACCmpConv::convert(SmallVectorImpl<MachineBasicBlock *> &RemovedBlocks) {
CmpBB->removeSuccessor(Tail, true);
Head->transferSuccessorsAndUpdatePHIs(CmpBB);
DebugLoc TermDL = Head->getFirstTerminator()->getDebugLoc();
- TII->RemoveBranch(*Head);
+ TII->removeBranch(*Head);
// If the Head terminator was one of the cbz / tbz branches with built-in
// compare, we need to insert an explicit compare instruction in its place.
@@ -732,10 +732,12 @@ class AArch64ConditionalCompares : public MachineFunctionPass {
public:
static char ID;
- AArch64ConditionalCompares() : MachineFunctionPass(ID) {}
+ AArch64ConditionalCompares() : MachineFunctionPass(ID) {
+ initializeAArch64ConditionalComparesPass(*PassRegistry::getPassRegistry());
+ }
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AArch64 Conditional Compares";
}
@@ -750,10 +752,6 @@ private:
char AArch64ConditionalCompares::ID = 0;
-namespace llvm {
-void initializeAArch64ConditionalComparesPass(PassRegistry &);
-}
-
INITIALIZE_PASS_BEGIN(AArch64ConditionalCompares, "aarch64-ccmp",
"AArch64 CCMP Pass", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp b/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp
index 7a6f766..30e2b23 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp
@@ -6,9 +6,9 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-// When allowed by the instruction, replace a dead definition of a GPR with
-// the zero register. This makes the code a bit friendlier towards the
-// hardware's register renamer.
+/// \file When allowed by the instruction, replace a dead definition of a GPR
+/// with the zero register. This makes the code a bit friendlier towards the
+/// hardware's register renamer.
//===----------------------------------------------------------------------===//
#include "AArch64.h"
@@ -17,43 +17,37 @@
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetSubtargetInfo.h"
+#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;
#define DEBUG_TYPE "aarch64-dead-defs"
STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");
-namespace llvm {
-void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry &);
-}
-
#define AARCH64_DEAD_REG_DEF_NAME "AArch64 Dead register definitions"
namespace {
class AArch64DeadRegisterDefinitions : public MachineFunctionPass {
private:
const TargetRegisterInfo *TRI;
- bool implicitlyDefinesOverlappingReg(unsigned Reg, const MachineInstr &MI);
- bool processMachineBasicBlock(MachineBasicBlock &MBB);
- bool usesFrameIndex(const MachineInstr &MI);
+ const MachineRegisterInfo *MRI;
+ const TargetInstrInfo *TII;
+ bool Changed;
+ void processMachineBasicBlock(MachineBasicBlock &MBB);
public:
static char ID; // Pass identification, replacement for typeid.
- explicit AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) {
+ AArch64DeadRegisterDefinitions() : MachineFunctionPass(ID) {
initializeAArch64DeadRegisterDefinitionsPass(
*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &F) override;
- MachineFunctionProperties getRequiredProperties() const override {
- return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
- }
-
- const char *getPassName() const override { return AARCH64_DEAD_REG_DEF_NAME; }
+ StringRef getPassName() const override { return AARCH64_DEAD_REG_DEF_NAME; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -66,25 +60,16 @@ char AArch64DeadRegisterDefinitions::ID = 0;
INITIALIZE_PASS(AArch64DeadRegisterDefinitions, "aarch64-dead-defs",
AARCH64_DEAD_REG_DEF_NAME, false, false)
-bool AArch64DeadRegisterDefinitions::implicitlyDefinesOverlappingReg(
- unsigned Reg, const MachineInstr &MI) {
- for (const MachineOperand &MO : MI.implicit_operands())
- if (MO.isReg() && MO.isDef())
- if (TRI->regsOverlap(Reg, MO.getReg()))
- return true;
- return false;
-}
-
-bool AArch64DeadRegisterDefinitions::usesFrameIndex(const MachineInstr &MI) {
- for (const MachineOperand &Op : MI.uses())
- if (Op.isFI())
+static bool usesFrameIndex(const MachineInstr &MI) {
+ for (const MachineOperand &MO : MI.uses())
+ if (MO.isFI())
return true;
return false;
}
-bool AArch64DeadRegisterDefinitions::processMachineBasicBlock(
+void AArch64DeadRegisterDefinitions::processMachineBasicBlock(
MachineBasicBlock &MBB) {
- bool Changed = false;
+ const MachineFunction &MF = *MBB.getParent();
for (MachineInstr &MI : MBB) {
if (usesFrameIndex(MI)) {
// We need to skip this instruction because while it appears to have a
@@ -99,62 +84,63 @@ bool AArch64DeadRegisterDefinitions::processMachineBasicBlock(
DEBUG(dbgs() << " Ignoring, XZR or WZR already used by the instruction\n");
continue;
}
- for (int i = 0, e = MI.getDesc().getNumDefs(); i != e; ++i) {
- MachineOperand &MO = MI.getOperand(i);
- if (MO.isReg() && MO.isDead() && MO.isDef()) {
- assert(!MO.isImplicit() && "Unexpected implicit def!");
- DEBUG(dbgs() << " Dead def operand #" << i << " in:\n ";
- MI.print(dbgs()));
- // Be careful not to change the register if it's a tied operand.
- if (MI.isRegTiedToUseOperand(i)) {
- DEBUG(dbgs() << " Ignoring, def is tied operand.\n");
- continue;
- }
- // Don't change the register if there's an implicit def of a subreg or
- // superreg.
- if (implicitlyDefinesOverlappingReg(MO.getReg(), MI)) {
- DEBUG(dbgs() << " Ignoring, implicitly defines overlap reg.\n");
- continue;
- }
- // Make sure the instruction take a register class that contains
- // the zero register and replace it if so.
- unsigned NewReg;
- switch (MI.getDesc().OpInfo[i].RegClass) {
- default:
- DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
- continue;
- case AArch64::GPR32RegClassID:
- NewReg = AArch64::WZR;
- break;
- case AArch64::GPR64RegClassID:
- NewReg = AArch64::XZR;
- break;
- }
- DEBUG(dbgs() << " Replacing with zero register. New:\n ");
- MO.setReg(NewReg);
- DEBUG(MI.print(dbgs()));
- ++NumDeadDefsReplaced;
- // Only replace one dead register, see check for zero register above.
- break;
+ const MCInstrDesc &Desc = MI.getDesc();
+ for (int I = 0, E = Desc.getNumDefs(); I != E; ++I) {
+ MachineOperand &MO = MI.getOperand(I);
+ if (!MO.isReg() || !MO.isDef())
+ continue;
+ // We should not have any relevant physreg defs that are replacable by
+ // zero before register allocation. So we just check for dead vreg defs.
+ unsigned Reg = MO.getReg();
+ if (!TargetRegisterInfo::isVirtualRegister(Reg) ||
+ (!MO.isDead() && !MRI->use_nodbg_empty(Reg)))
+ continue;
+ assert(!MO.isImplicit() && "Unexpected implicit def!");
+ DEBUG(dbgs() << " Dead def operand #" << I << " in:\n ";
+ MI.print(dbgs()));
+ // Be careful not to change the register if it's a tied operand.
+ if (MI.isRegTiedToUseOperand(I)) {
+ DEBUG(dbgs() << " Ignoring, def is tied operand.\n");
+ continue;
+ }
+ const TargetRegisterClass *RC = TII->getRegClass(Desc, I, TRI, MF);
+ unsigned NewReg;
+ if (RC == nullptr) {
+ DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
+ continue;
+ } else if (RC->contains(AArch64::WZR))
+ NewReg = AArch64::WZR;
+ else if (RC->contains(AArch64::XZR))
+ NewReg = AArch64::XZR;
+ else {
+ DEBUG(dbgs() << " Ignoring, register is not a GPR.\n");
+ continue;
}
+ DEBUG(dbgs() << " Replacing with zero register. New:\n ");
+ MO.setReg(NewReg);
+ MO.setIsDead();
+ DEBUG(MI.print(dbgs()));
+ ++NumDeadDefsReplaced;
+ Changed = true;
+ // Only replace one dead register, see check for zero register above.
+ break;
}
}
- return Changed;
}
// Scan the function for instructions that have a dead definition of a
// register. Replace that register with the zero register when possible.
bool AArch64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &MF) {
- TRI = MF.getSubtarget().getRegisterInfo();
- bool Changed = false;
- DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n");
-
if (skipFunction(*MF.getFunction()))
return false;
+ TRI = MF.getSubtarget().getRegisterInfo();
+ TII = MF.getSubtarget().getInstrInfo();
+ MRI = &MF.getRegInfo();
+ DEBUG(dbgs() << "***** AArch64DeadRegisterDefinitions *****\n");
+ Changed = false;
for (auto &MBB : MF)
- if (processMachineBasicBlock(MBB))
- Changed = true;
+ processMachineBasicBlock(MBB);
return Changed;
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
index a1c9825..fe1c0be 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
@@ -23,10 +23,6 @@
#include "llvm/Support/MathExtras.h"
using namespace llvm;
-namespace llvm {
-void initializeAArch64ExpandPseudoPass(PassRegistry &);
-}
-
#define AARCH64_EXPAND_PSEUDO_NAME "AArch64 pseudo instruction expansion pass"
namespace {
@@ -41,9 +37,7 @@ public:
bool runOnMachineFunction(MachineFunction &Fn) override;
- const char *getPassName() const override {
- return AARCH64_EXPAND_PSEUDO_NAME;
- }
+ StringRef getPassName() const override { return AARCH64_EXPAND_PSEUDO_NAME; }
private:
bool expandMBB(MachineBasicBlock &MBB);
@@ -719,19 +713,19 @@ bool AArch64ExpandPseudo::expandCMP_SWAP_128(
.addOperand(DesiredLo)
.addImm(0);
BuildMI(LoadCmpBB, DL, TII->get(AArch64::CSINCWr), StatusReg)
- .addReg(AArch64::WZR)
- .addReg(AArch64::WZR)
+ .addUse(AArch64::WZR)
+ .addUse(AArch64::WZR)
.addImm(AArch64CC::EQ);
BuildMI(LoadCmpBB, DL, TII->get(AArch64::SUBSXrs), AArch64::XZR)
.addReg(DestHi.getReg(), getKillRegState(DestHi.isDead()))
.addOperand(DesiredHi)
.addImm(0);
BuildMI(LoadCmpBB, DL, TII->get(AArch64::CSINCWr), StatusReg)
- .addReg(StatusReg, RegState::Kill)
- .addReg(StatusReg, RegState::Kill)
+ .addUse(StatusReg, RegState::Kill)
+ .addUse(StatusReg, RegState::Kill)
.addImm(AArch64CC::EQ);
BuildMI(LoadCmpBB, DL, TII->get(AArch64::CBNZW))
- .addReg(StatusReg, RegState::Kill)
+ .addUse(StatusReg, RegState::Kill)
.addMBB(DoneBB);
LoadCmpBB->addSuccessor(DoneBB);
LoadCmpBB->addSuccessor(StoreBB);
@@ -903,9 +897,14 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
case AArch64::MOVi64imm:
return expandMOVImm(MBB, MBBI, 64);
case AArch64::RET_ReallyLR: {
+ // Hiding the LR use with RET_ReallyLR may lead to extra kills in the
+ // function and missing live-ins. We are fine in practice because callee
+ // saved register handling ensures the register value is restored before
+ // RET, but we need the undef flag here to appease the MachineVerifier
+ // liveness checks.
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::RET))
- .addReg(AArch64::LR);
+ .addReg(AArch64::LR, RegState::Undef);
transferImpOps(MI, MIB, MIB);
MI.eraseFromParent();
return true;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/contrib/llvm/lib/Target/AArch64/AArch64FastISel.cpp
index e2ab7ab..fe2c2d4 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64FastISel.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64FastISel.cpp
@@ -134,6 +134,7 @@ private:
bool selectFRem(const Instruction *I);
bool selectSDiv(const Instruction *I);
bool selectGetElementPtr(const Instruction *I);
+ bool selectAtomicCmpXchg(const AtomicCmpXchgInst *I);
// Utility helper routines.
bool isTypeLegal(Type *Ty, MVT &VT);
@@ -185,6 +186,8 @@ private:
MachineMemOperand *MMO = nullptr);
bool emitStore(MVT VT, unsigned SrcReg, Address Addr,
MachineMemOperand *MMO = nullptr);
+ bool emitStoreRelease(MVT VT, unsigned SrcReg, unsigned AddrReg,
+ MachineMemOperand *MMO = nullptr);
unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt);
unsigned emiti1Ext(unsigned SrcReg, MVT DestVT, bool isZExt);
unsigned emitAdd(MVT RetVT, const Value *LHS, const Value *RHS,
@@ -554,7 +557,7 @@ bool AArch64FastISel::computeAddress(const Value *Obj, Address &Addr, Type *Ty)
for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
GTI != E; ++GTI) {
const Value *Op = GTI.getOperand();
- if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
@@ -1997,6 +2000,28 @@ bool AArch64FastISel::selectLoad(const Instruction *I) {
return true;
}
+bool AArch64FastISel::emitStoreRelease(MVT VT, unsigned SrcReg,
+ unsigned AddrReg,
+ MachineMemOperand *MMO) {
+ unsigned Opc;
+ switch (VT.SimpleTy) {
+ default: return false;
+ case MVT::i8: Opc = AArch64::STLRB; break;
+ case MVT::i16: Opc = AArch64::STLRH; break;
+ case MVT::i32: Opc = AArch64::STLRW; break;
+ case MVT::i64: Opc = AArch64::STLRX; break;
+ }
+
+ const MCInstrDesc &II = TII.get(Opc);
+ SrcReg = constrainOperandRegClass(II, SrcReg, 0);
+ AddrReg = constrainOperandRegClass(II, AddrReg, 1);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+ .addReg(SrcReg)
+ .addReg(AddrReg)
+ .addMemOperand(MMO);
+ return true;
+}
+
bool AArch64FastISel::emitStore(MVT VT, unsigned SrcReg, Address Addr,
MachineMemOperand *MMO) {
if (!TLI.allowsMisalignedMemoryAccesses(VT))
@@ -2071,8 +2096,7 @@ bool AArch64FastISel::selectStore(const Instruction *I) {
// Verify we have a legal type before going any further. Currently, we handle
// simple types that will directly fit in a register (i32/f32/i64/f64) or
// those that can be sign or zero-extended to a basic operation (i1/i8/i16).
- if (!isTypeSupported(Op0->getType(), VT, /*IsVectorAllowed=*/true) ||
- cast<StoreInst>(I)->isAtomic())
+ if (!isTypeSupported(Op0->getType(), VT, /*IsVectorAllowed=*/true))
return false;
const Value *PtrV = I->getOperand(1);
@@ -2109,9 +2133,23 @@ bool AArch64FastISel::selectStore(const Instruction *I) {
if (!SrcReg)
return false;
+ auto *SI = cast<StoreInst>(I);
+
+ // Try to emit a STLR for seq_cst/release.
+ if (SI->isAtomic()) {
+ AtomicOrdering Ord = SI->getOrdering();
+ // The non-atomic instructions are sufficient for relaxed stores.
+ if (isReleaseOrStronger(Ord)) {
+ // The STLR addressing mode only supports a base reg; pass that directly.
+ unsigned AddrReg = getRegForValue(PtrV);
+ return emitStoreRelease(VT, SrcReg, AddrReg,
+ createMachineMemOperandFor(I));
+ }
+ }
+
// See if we can handle this address.
Address Addr;
- if (!computeAddress(I->getOperand(1), Addr, I->getOperand(0)->getType()))
+ if (!computeAddress(PtrV, Addr, Op0->getType()))
return false;
if (!emitStore(VT, SrcReg, Addr, createMachineMemOperandFor(I)))
@@ -2822,7 +2860,7 @@ bool AArch64FastISel::fastLowerArguments() {
return false;
CallingConv::ID CC = F->getCallingConv();
- if (CC != CallingConv::C)
+ if (CC != CallingConv::C && CC != CallingConv::Swift)
return false;
// Only handle simple cases of up to 8 GPR and FPR each.
@@ -3328,8 +3366,8 @@ bool AArch64FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
switch (II->getIntrinsicID()) {
default: return false;
case Intrinsic::frameaddress: {
- MachineFrameInfo *MFI = FuncInfo.MF->getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = FuncInfo.MF->getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
const AArch64RegisterInfo *RegInfo =
static_cast<const AArch64RegisterInfo *>(Subtarget->getRegisterInfo());
@@ -4847,7 +4885,7 @@ bool AArch64FastISel::selectGetElementPtr(const Instruction *I) {
for (gep_type_iterator GTI = gep_type_begin(I), E = gep_type_end(I);
GTI != E; ++GTI) {
const Value *Idx = GTI.getOperand();
- if (auto *StTy = dyn_cast<StructType>(*GTI)) {
+ if (auto *StTy = GTI.getStructTypeOrNull()) {
unsigned Field = cast<ConstantInt>(Idx)->getZExtValue();
// N = N + Offset
if (Field)
@@ -4903,6 +4941,73 @@ bool AArch64FastISel::selectGetElementPtr(const Instruction *I) {
return true;
}
+bool AArch64FastISel::selectAtomicCmpXchg(const AtomicCmpXchgInst *I) {
+ assert(TM.getOptLevel() == CodeGenOpt::None &&
+ "cmpxchg survived AtomicExpand at optlevel > -O0");
+
+ auto *RetPairTy = cast<StructType>(I->getType());
+ Type *RetTy = RetPairTy->getTypeAtIndex(0U);
+ assert(RetPairTy->getTypeAtIndex(1U)->isIntegerTy(1) &&
+ "cmpxchg has a non-i1 status result");
+
+ MVT VT;
+ if (!isTypeLegal(RetTy, VT))
+ return false;
+
+ const TargetRegisterClass *ResRC;
+ unsigned Opc, CmpOpc;
+ // This only supports i32/i64, because i8/i16 aren't legal, and the generic
+ // extractvalue selection doesn't support that.
+ if (VT == MVT::i32) {
+ Opc = AArch64::CMP_SWAP_32;
+ CmpOpc = AArch64::SUBSWrs;
+ ResRC = &AArch64::GPR32RegClass;
+ } else if (VT == MVT::i64) {
+ Opc = AArch64::CMP_SWAP_64;
+ CmpOpc = AArch64::SUBSXrs;
+ ResRC = &AArch64::GPR64RegClass;
+ } else {
+ return false;
+ }
+
+ const MCInstrDesc &II = TII.get(Opc);
+
+ const unsigned AddrReg = constrainOperandRegClass(
+ II, getRegForValue(I->getPointerOperand()), II.getNumDefs());
+ const unsigned DesiredReg = constrainOperandRegClass(
+ II, getRegForValue(I->getCompareOperand()), II.getNumDefs() + 1);
+ const unsigned NewReg = constrainOperandRegClass(
+ II, getRegForValue(I->getNewValOperand()), II.getNumDefs() + 2);
+
+ const unsigned ResultReg1 = createResultReg(ResRC);
+ const unsigned ResultReg2 = createResultReg(&AArch64::GPR32RegClass);
+ const unsigned ScratchReg = createResultReg(&AArch64::GPR32RegClass);
+
+ // FIXME: MachineMemOperand doesn't support cmpxchg yet.
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+ .addDef(ResultReg1)
+ .addDef(ScratchReg)
+ .addUse(AddrReg)
+ .addUse(DesiredReg)
+ .addUse(NewReg);
+
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CmpOpc))
+ .addDef(VT == MVT::i32 ? AArch64::WZR : AArch64::XZR)
+ .addUse(ResultReg1)
+ .addUse(DesiredReg)
+ .addImm(0);
+
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::CSINCWr))
+ .addDef(ResultReg2)
+ .addUse(AArch64::WZR)
+ .addUse(AArch64::WZR)
+ .addImm(AArch64CC::NE);
+
+ assert((ResultReg1 + 1) == ResultReg2 && "Nonconsecutive result registers.");
+ updateValueMap(I, ResultReg1, 2);
+ return true;
+}
+
bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
switch (I->getOpcode()) {
default:
@@ -4976,6 +5081,8 @@ bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
return selectFRem(I);
case Instruction::GetElementPtr:
return selectGetElementPtr(I);
+ case Instruction::AtomicCmpXchg:
+ return selectAtomicCmpXchg(cast<AtomicCmpXchgInst>(I));
}
// fall-back to target-independent instruction selection.
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/contrib/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 82111e5..f5b8c35 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -124,23 +124,23 @@ bool AArch64FrameLowering::canUseRedZone(const MachineFunction &MF) const {
if (MF.getFunction()->hasFnAttribute(Attribute::NoRedZone))
return false;
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
unsigned NumBytes = AFI->getLocalStackSize();
- return !(MFI->hasCalls() || hasFP(MF) || NumBytes > 128);
+ return !(MFI.hasCalls() || hasFP(MF) || NumBytes > 128);
}
/// hasFP - Return true if the specified function should have a dedicated frame
/// pointer register.
bool AArch64FrameLowering::hasFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
// Retain behavior of always omitting the FP for leaf functions when possible.
- return (MFI->hasCalls() &&
+ return (MFI.hasCalls() &&
MF.getTarget().Options.DisableFramePointerElim(MF)) ||
- MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() ||
- MFI->hasStackMap() || MFI->hasPatchPoint() ||
+ MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() ||
+ MFI.hasStackMap() || MFI.hasPatchPoint() ||
RegInfo->needsStackRealignment(MF);
}
@@ -151,7 +151,7 @@ bool AArch64FrameLowering::hasFP(const MachineFunction &MF) const {
/// included as part of the stack frame.
bool
AArch64FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- return !MF.getFrameInfo()->hasVarSizedObjects();
+ return !MF.getFrameInfo().hasVarSizedObjects();
}
MachineBasicBlock::iterator AArch64FrameLowering::eliminateCallFramePseudoInstr(
@@ -203,23 +203,23 @@ MachineBasicBlock::iterator AArch64FrameLowering::eliminateCallFramePseudoInstr(
void AArch64FrameLowering::emitCalleeSavedFrameMoves(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const {
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MachineModuleInfo &MMI = MF.getMMI();
- const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
- const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const TargetSubtargetInfo &STI = MF.getSubtarget();
+ const MCRegisterInfo *MRI = STI.getRegisterInfo();
+ const TargetInstrInfo *TII = STI.getInstrInfo();
DebugLoc DL = MBB.findDebugLoc(MBBI);
// Add callee saved registers to move list.
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
if (CSI.empty())
return;
for (const auto &Info : CSI) {
unsigned Reg = Info.getReg();
int64_t Offset =
- MFI->getObjectOffset(Info.getFrameIdx()) - getOffsetOfLocalArea();
+ MFI.getObjectOffset(Info.getFrameIdx()) - getOffsetOfLocalArea();
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -286,7 +286,7 @@ bool AArch64FrameLowering::canUseAsPrologue(
bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
MachineFunction &MF, unsigned StackBumpBytes) const {
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
const AArch64RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
@@ -298,7 +298,7 @@ bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
if (StackBumpBytes >= 512)
return false;
- if (MFI->hasVarSizedObjects())
+ if (MFI.hasVarSizedObjects())
return false;
if (RegInfo->needsStackRealignment(MF))
@@ -407,7 +407,7 @@ static void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI,
void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const Function *Fn = MF.getFunction();
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
const AArch64RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
@@ -426,7 +426,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
if (MF.getFunction()->getCallingConv() == CallingConv::GHC)
return;
- int NumBytes = (int)MFI->getStackSize();
+ int NumBytes = (int)MFI.getStackSize();
if (!AFI->hasStackFrame()) {
assert(!HasFP && "unexpected function without stack frame but with FP");
@@ -446,7 +446,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
// Label used to tie together the PROLOG_LABEL and the MachineMoves.
MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
// Encode the stack size of the leaf function.
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(FrameLabel, -NumBytes));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -513,7 +513,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
MachineInstr::FrameSetup);
if (NeedsRealignment) {
- const unsigned Alignment = MFI->getMaxAlignment();
+ const unsigned Alignment = MFI.getMaxAlignment();
const unsigned NrBitsToZero = countTrailingZeros(Alignment);
assert(NrBitsToZero > 1);
assert(scratchSPReg != AArch64::SP);
@@ -621,15 +621,15 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
if (HasFP) {
// Define the current CFA rule to use the provided FP.
unsigned Reg = RegInfo->getDwarfRegNum(FramePtr, true);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfa(nullptr, Reg, 2 * StackGrowth));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
} else {
// Encode the stack size of the leaf function.
- unsigned CFIIndex = MMI.addFrameInst(
- MCCFIInstruction::createDefCfaOffset(nullptr, -MFI->getStackSize()));
+ unsigned CFIIndex = MF.addFrameInst(
+ MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize()));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
@@ -644,7 +644,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
DebugLoc DL;
@@ -655,7 +655,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
IsTailCallReturn = RetOpcode == AArch64::TCRETURNdi ||
RetOpcode == AArch64::TCRETURNri;
}
- int NumBytes = MFI->getStackSize();
+ int NumBytes = MFI.getStackSize();
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
// All calls are tail calls in GHC calling conv, and functions have no
@@ -762,7 +762,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
// FIXME: Rather than doing the math here, we should instead just use
// non-post-indexed loads for the restores if we aren't actually going to
// be able to save any instructions.
- if (MFI->hasVarSizedObjects() || AFI->isStackRealigned())
+ if (MFI.hasVarSizedObjects() || AFI->isStackRealigned())
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP,
-CSStackSize + 16, TII, MachineInstr::FrameDestroy);
else if (NumBytes)
@@ -790,13 +790,13 @@ int AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF,
int AArch64FrameLowering::resolveFrameIndexReference(const MachineFunction &MF,
int FI, unsigned &FrameReg,
bool PreferFP) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const AArch64RegisterInfo *RegInfo = static_cast<const AArch64RegisterInfo *>(
MF.getSubtarget().getRegisterInfo());
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
- int FPOffset = MFI->getObjectOffset(FI) + 16;
- int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize();
- bool isFixed = MFI->isFixedObjectIndex(FI);
+ int FPOffset = MFI.getObjectOffset(FI) + 16;
+ int Offset = MFI.getObjectOffset(FI) + MFI.getStackSize();
+ bool isFixed = MFI.isFixedObjectIndex(FI);
// Use frame pointer to reference fixed objects. Use it for locals if
// there are VLAs or a dynamically realigned SP (and thus the SP isn't
@@ -821,7 +821,7 @@ int AArch64FrameLowering::resolveFrameIndexReference(const MachineFunction &MF,
// using the FP regardless, though, as the SP offset is unknown
// and we don't have a base pointer available. If an offset is
// available via the FP and the SP, use whichever is closest.
- if (PreferFP || MFI->hasVarSizedObjects() || FPOffset >= 0 ||
+ if (PreferFP || MFI.hasVarSizedObjects() || FPOffset >= 0 ||
(FPOffset >= -256 && Offset > -FPOffset))
UseFP = true;
}
@@ -869,7 +869,7 @@ static bool produceCompactUnwindFrame(MachineFunction &MF) {
Attrs.hasAttrSomewhere(Attribute::SwiftError));
}
-
+namespace {
struct RegPairInfo {
RegPairInfo() : Reg1(AArch64::NoRegister), Reg2(AArch64::NoRegister) {}
unsigned Reg1;
@@ -879,6 +879,7 @@ struct RegPairInfo {
bool IsGPR;
bool isPaired() const { return Reg2 != AArch64::NoRegister; }
};
+} // end anonymous namespace
static void computeCalleeSaveRegisterPairs(
MachineFunction &MF, const std::vector<CalleeSavedInfo> &CSI,
@@ -888,7 +889,7 @@ static void computeCalleeSaveRegisterPairs(
return;
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
CallingConv::ID CC = MF.getFunction()->getCallingConv();
unsigned Count = CSI.size();
(void)CC;
@@ -941,8 +942,8 @@ static void computeCalleeSaveRegisterPairs(
// Round up size of non-pair to pair size if we need to pad the
// callee-save area to ensure 16-byte alignment.
Offset -= 16;
- assert(MFI->getObjectAlignment(RPI.FrameIdx) <= 16);
- MFI->setObjectAlignment(RPI.FrameIdx, 16);
+ assert(MFI.getObjectAlignment(RPI.FrameIdx) <= 16);
+ MFI.setObjectAlignment(RPI.FrameIdx, 16);
AFI->setCalleeSaveStackHasFreeSpace(true);
} else
Offset -= RPI.isPaired() ? 16 : 8;
@@ -1149,8 +1150,8 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
// realistically that's not a big deal at this stage of the game.
// The CSR spill slots have not been allocated yet, so estimateStackSize
// won't include them.
- MachineFrameInfo *MFI = MF.getFrameInfo();
- unsigned CFSize = MFI->estimateStackSize(MF) + 8 * NumRegsSpilled;
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned CFSize = MFI.estimateStackSize(MF) + 8 * NumRegsSpilled;
DEBUG(dbgs() << "Estimated stack frame size: " << CFSize << " bytes.\n");
bool BigStack = (CFSize >= 256);
if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF))
@@ -1180,7 +1181,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
// an emergency spill slot.
if (!ExtraCSSpill) {
const TargetRegisterClass *RC = &AArch64::GPR64RegClass;
- int FI = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), false);
+ int FI = MFI.CreateStackObject(RC->getSize(), RC->getAlignment(), false);
RS->addScavengingFrameIndex(FI);
DEBUG(dbgs() << "No available CS registers, allocated fi#" << FI
<< " as the emergency spill slot.\n");
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64GenRegisterBankInfo.def b/contrib/llvm/lib/Target/AArch64/AArch64GenRegisterBankInfo.def
new file mode 100644
index 0000000..d472a54
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64GenRegisterBankInfo.def
@@ -0,0 +1,296 @@
+//===- AArch64GenRegisterBankInfo.def ----------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines all the static objects used by AArch64RegisterBankInfo.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+namespace llvm {
+namespace AArch64 {
+
+const uint32_t GPRCoverageData[] = {
+ // Classes 0-31
+ (1u << AArch64::GPR32allRegClassID) | (1u << AArch64::GPR32RegClassID) |
+ (1u << AArch64::GPR32spRegClassID) |
+ (1u << AArch64::GPR32commonRegClassID) |
+ (1u << AArch64::GPR32sponlyRegClassID) |
+ (1u << AArch64::GPR64allRegClassID) | (1u << AArch64::GPR64RegClassID) |
+ (1u << AArch64::GPR64spRegClassID) |
+ (1u << AArch64::GPR64commonRegClassID) |
+ (1u << AArch64::tcGPR64RegClassID) |
+ (1u << AArch64::GPR64sponlyRegClassID),
+ // Classes 32-63
+ 0,
+ // FIXME: The entries below this point can be safely removed once this is
+ // tablegenerated. It's only needed because of the hardcoded register class
+ // limit.
+ // Classes 64-96
+ 0,
+ // Classes 97-128
+ 0,
+ // Classes 129-160
+ 0,
+ // Classes 161-192
+ 0,
+ // Classes 193-224
+ 0,
+};
+
+const uint32_t FPRCoverageData[] = {
+ // Classes 0-31
+ (1u << AArch64::FPR8RegClassID) | (1u << AArch64::FPR16RegClassID) |
+ (1u << AArch64::FPR32RegClassID) | (1u << AArch64::FPR64RegClassID) |
+ (1u << AArch64::DDRegClassID) | (1u << AArch64::FPR128RegClassID) |
+ (1u << AArch64::FPR128_loRegClassID) | (1u << AArch64::DDDRegClassID) |
+ (1u << AArch64::DDDDRegClassID),
+ // Classes 32-63
+ (1u << (AArch64::QQRegClassID - 32)) |
+ (1u << (AArch64::QQ_with_qsub0_in_FPR128_loRegClassID - 32)) |
+ (1u << (AArch64::QQ_with_qsub1_in_FPR128_loRegClassID - 32)) |
+ (1u
+ << (AArch64::
+ QQQ_with_qsub1_in_FPR128_lo_and_QQQ_with_qsub2_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQQ_with_qsub0_in_FPR128_lo_and_QQQ_with_qsub2_in_FPR128_loRegClassID -
+ 32)) |
+ (1u << (AArch64::QQQQRegClassID - 32)) |
+ (1u << (AArch64::QQQQ_with_qsub0_in_FPR128_loRegClassID - 32)) |
+ (1u << (AArch64::QQQQ_with_qsub1_in_FPR128_loRegClassID - 32)) |
+ (1u << (AArch64::QQQQ_with_qsub2_in_FPR128_loRegClassID - 32)) |
+ (1u << (AArch64::QQQQ_with_qsub3_in_FPR128_loRegClassID - 32)) |
+ (1u
+ << (AArch64::
+ QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub1_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQQQ_with_qsub1_in_FPR128_lo_and_QQQQ_with_qsub2_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQQQ_with_qsub2_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub2_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQQQ_with_qsub1_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID -
+ 32)) |
+ (1u
+ << (AArch64::
+ QQ_with_qsub0_in_FPR128_lo_and_QQ_with_qsub1_in_FPR128_loRegClassID -
+ 32)) |
+ (1u << (AArch64::QQQRegClassID - 32)) |
+ (1u << (AArch64::QQQ_with_qsub0_in_FPR128_loRegClassID - 32)) |
+ (1u << (AArch64::QQQ_with_qsub1_in_FPR128_loRegClassID - 32)) |
+ (1u << (AArch64::QQQ_with_qsub2_in_FPR128_loRegClassID - 32)) |
+ (1u
+ << (AArch64::
+ QQQ_with_qsub0_in_FPR128_lo_and_QQQ_with_qsub1_in_FPR128_loRegClassID -
+ 32)),
+ // FIXME: The entries below this point can be safely removed once this
+ // is tablegenerated. It's only needed because of the hardcoded register
+ // class limit.
+ // Classes 64-96
+ 0,
+ // Classes 97-128
+ 0,
+ // Classes 129-160
+ 0,
+ // Classes 161-192
+ 0,
+ // Classes 193-224
+ 0,
+};
+
+const uint32_t CCRCoverageData[] = {
+ // Classes 0-31
+ 1u << AArch64::CCRRegClassID,
+ // Classes 32-63
+ 0,
+ // FIXME: The entries below this point can be safely removed once this
+ // is tablegenerated. It's only needed because of the hardcoded register
+ // class limit.
+ // Classes 64-96
+ 0,
+ // Classes 97-128
+ 0,
+ // Classes 129-160
+ 0,
+ // Classes 161-192
+ 0,
+ // Classes 193-224
+ 0,
+};
+
+RegisterBank GPRRegBank(AArch64::GPRRegBankID, "GPR", 64, GPRCoverageData);
+RegisterBank FPRRegBank(AArch64::FPRRegBankID, "FPR", 512, FPRCoverageData);
+RegisterBank CCRRegBank(AArch64::CCRRegBankID, "CCR", 32, CCRCoverageData);
+
+RegisterBank *RegBanks[] = {&GPRRegBank, &FPRRegBank, &CCRRegBank};
+
+// PartialMappings.
+enum PartialMappingIdx {
+ PMI_None = -1,
+ PMI_GPR32 = 1,
+ PMI_GPR64,
+ PMI_FPR32,
+ PMI_FPR64,
+ PMI_FPR128,
+ PMI_FPR256,
+ PMI_FPR512,
+ PMI_FirstGPR = PMI_GPR32,
+ PMI_LastGPR = PMI_GPR64,
+ PMI_FirstFPR = PMI_FPR32,
+ PMI_LastFPR = PMI_FPR512,
+ PMI_Min = PMI_FirstGPR,
+};
+
+static unsigned getRegBankBaseIdxOffset(unsigned Size) {
+ assert(Size && "0-sized type!!");
+ // Make anything smaller than 32 gets 32
+ Size = ((Size + 31) / 32) * 32;
+ // 32 is 0, 64 is 1, 128 is 2, and so on.
+ return Log2_32(Size) - /*Log2_32(32)=*/ 5;
+}
+
+RegisterBankInfo::PartialMapping PartMappings[] {
+ /* StartIdx, Length, RegBank */
+ // 0: GPR 32-bit value.
+ {0, 32, GPRRegBank},
+ // 1: GPR 64-bit value.
+ {0, 64, GPRRegBank},
+ // 2: FPR 32-bit value.
+ {0, 32, FPRRegBank},
+ // 3: FPR 64-bit value.
+ {0, 64, FPRRegBank},
+ // 4: FPR 128-bit value.
+ {0, 128, FPRRegBank},
+ // 5: FPR 256-bit value.
+ {0, 256, FPRRegBank},
+ // 6: FPR 512-bit value.
+ {0, 512, FPRRegBank}
+};
+
+enum ValueMappingIdx {
+ First3OpsIdx = 0,
+ Last3OpsIdx = 18,
+ DistanceBetweenRegBanks = 3,
+ FirstCrossRegCpyIdx = 21,
+ LastCrossRegCpyIdx = 27,
+ DistanceBetweenCrossRegCpy = 2
+};
+
+// ValueMappings.
+RegisterBankInfo::ValueMapping ValMappings[]{
+ /* BreakDown, NumBreakDowns */
+ // 3-operands instructions (all binary operations should end up with one of
+ // those mapping).
+ // 0: GPR 32-bit value. <-- This must match First3OpsIdx.
+ {&PartMappings[PMI_GPR32 - PMI_Min], 1},
+ {&PartMappings[PMI_GPR32 - PMI_Min], 1},
+ {&PartMappings[PMI_GPR32 - PMI_Min], 1},
+ // 3: GPR 64-bit value.
+ {&PartMappings[PMI_GPR64 - PMI_Min], 1},
+ {&PartMappings[PMI_GPR64 - PMI_Min], 1},
+ {&PartMappings[PMI_GPR64 - PMI_Min], 1},
+ // 6: FPR 32-bit value.
+ {&PartMappings[PMI_FPR32 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR32 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR32 - PMI_Min], 1},
+ // 9: FPR 64-bit value.
+ {&PartMappings[PMI_FPR64 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR64 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR64 - PMI_Min], 1},
+ // 12: FPR 128-bit value.
+ {&PartMappings[PMI_FPR128 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR128 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR128 - PMI_Min], 1},
+ // 15: FPR 256-bit value.
+ {&PartMappings[PMI_FPR256 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR256 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR256 - PMI_Min], 1},
+ // 18: FPR 512-bit value. <-- This must match Last3OpsIdx.
+ {&PartMappings[PMI_FPR512 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR512 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR512 - PMI_Min], 1},
+ // Cross register bank copies.
+ // 21: GPR 32-bit value to FPR 32-bit value. <-- This must match
+ // FirstCrossRegCpyIdx.
+ {&PartMappings[PMI_GPR32 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR32 - PMI_Min], 1},
+ // 23: GPR 64-bit value to FPR 64-bit value.
+ {&PartMappings[PMI_GPR64 - PMI_Min], 1},
+ {&PartMappings[PMI_FPR64 - PMI_Min], 1},
+ // 25: FPR 32-bit value to GPR 32-bit value.
+ {&PartMappings[PMI_FPR32 - PMI_Min], 1},
+ {&PartMappings[PMI_GPR32 - PMI_Min], 1},
+ // 27: FPR 64-bit value to GPR 64-bit value. <-- This must match
+ // LastCrossRegCpyIdx.
+ {&PartMappings[PMI_FPR64 - PMI_Min], 1},
+ {&PartMappings[PMI_GPR64 - PMI_Min], 1}
+};
+
+/// Get the pointer to the ValueMapping representing the RegisterBank
+/// at \p RBIdx with a size of \p Size.
+///
+/// The returned mapping works for instructions with the same kind of
+/// operands for up to 3 operands.
+///
+/// \pre \p RBIdx != PartialMappingIdx::None
+const RegisterBankInfo::ValueMapping *
+getValueMapping(PartialMappingIdx RBIdx, unsigned Size) {
+ assert(RBIdx != PartialMappingIdx::PMI_None && "No mapping needed for that");
+ unsigned ValMappingIdx = First3OpsIdx +
+ (RBIdx - AArch64::PartialMappingIdx::PMI_Min +
+ getRegBankBaseIdxOffset(Size)) *
+ ValueMappingIdx::DistanceBetweenRegBanks;
+ assert(ValMappingIdx >= AArch64::First3OpsIdx &&
+ ValMappingIdx <= AArch64::Last3OpsIdx && "Mapping out of bound");
+
+ return &ValMappings[ValMappingIdx];
+}
+
+/// Get the pointer to the ValueMapping of the operands of a copy
+/// instruction from a GPR or FPR register to a GPR or FPR register
+/// with a size of \p Size.
+///
+/// If \p DstIsGPR is true, the destination of the copy is on GPR,
+/// otherwise it is on FPR. Same thing for \p SrcIsGPR.
+const RegisterBankInfo::ValueMapping *
+getCopyMapping(bool DstIsGPR, bool SrcIsGPR, unsigned Size) {
+ PartialMappingIdx DstRBIdx = DstIsGPR ? PMI_FirstGPR : PMI_FirstFPR;
+ PartialMappingIdx SrcRBIdx = SrcIsGPR ? PMI_FirstGPR : PMI_FirstFPR;
+ if (DstRBIdx == SrcRBIdx)
+ return getValueMapping(DstRBIdx, Size);
+ assert(Size <= 64 && "GPR cannot handle that size");
+ unsigned ValMappingIdx =
+ FirstCrossRegCpyIdx +
+ (DstRBIdx - PMI_Min + getRegBankBaseIdxOffset(Size)) *
+ ValueMappingIdx::DistanceBetweenCrossRegCpy;
+ assert(ValMappingIdx >= AArch64::FirstCrossRegCpyIdx &&
+ ValMappingIdx <= AArch64::LastCrossRegCpyIdx &&
+ "Mapping out of bound");
+ return &ValMappings[ValMappingIdx];
+}
+
+} // End AArch64 namespace.
+} // End llvm namespace.
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 8d64925..3099383 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -47,7 +47,7 @@ public:
: SelectionDAGISel(tm, OptLevel), Subtarget(nullptr),
ForCodeSize(false) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AArch64 Instruction Selection";
}
@@ -349,7 +349,7 @@ bool AArch64DAGToDAGISel::SelectShiftedRegister(SDValue N, bool AllowROR,
return false;
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
- unsigned BitSize = N.getValueType().getSizeInBits();
+ unsigned BitSize = N.getValueSizeInBits();
unsigned Val = RHS->getZExtValue() & (BitSize - 1);
unsigned ShVal = AArch64_AM::getShifterImm(ShType, Val);
@@ -586,6 +586,11 @@ bool AArch64DAGToDAGISel::SelectArithExtendedRegister(SDValue N, SDValue &Reg,
return false;
Reg = N.getOperand(0);
+
+ // Don't match if free 32-bit -> 64-bit zext can be used instead.
+ if (Ext == AArch64_AM::UXTW &&
+ Reg->getValueType(0).getSizeInBits() == 32 && isDef32(*Reg.getNode()))
+ return false;
}
// AArch64 mandates that the RHS of the operation must use the smallest
@@ -1149,6 +1154,12 @@ void AArch64DAGToDAGISel::SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc,
CurDAG->getTargetExtractSubreg(SubRegIdx + i, dl, VT, SuperReg));
ReplaceUses(SDValue(N, NumVecs), SDValue(Ld, 1));
+
+ // Transfer memoperands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
+ cast<MachineSDNode>(Ld)->setMemRefs(MemOp, MemOp + 1);
+
CurDAG->RemoveDeadNode(N);
}
@@ -1197,6 +1208,11 @@ void AArch64DAGToDAGISel::SelectStore(SDNode *N, unsigned NumVecs,
SDValue Ops[] = {RegSeq, N->getOperand(NumVecs + 2), N->getOperand(0)};
SDNode *St = CurDAG->getMachineNode(Opc, dl, N->getValueType(0), Ops);
+ // Transfer memoperands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
+ cast<MachineSDNode>(St)->setMemRefs(MemOp, MemOp + 1);
+
ReplaceNode(N, St);
}
@@ -1266,7 +1282,7 @@ void AArch64DAGToDAGISel::SelectLoadLane(SDNode *N, unsigned NumVecs,
SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs);
if (Narrow)
- std::transform(Regs.begin(), Regs.end(), Regs.begin(),
+ transform(Regs, Regs.begin(),
WidenVector(*CurDAG));
SDValue RegSeq = createQTuple(Regs);
@@ -1305,7 +1321,7 @@ void AArch64DAGToDAGISel::SelectPostLoadLane(SDNode *N, unsigned NumVecs,
SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs);
if (Narrow)
- std::transform(Regs.begin(), Regs.end(), Regs.begin(),
+ transform(Regs, Regs.begin(),
WidenVector(*CurDAG));
SDValue RegSeq = createQTuple(Regs);
@@ -1360,7 +1376,7 @@ void AArch64DAGToDAGISel::SelectStoreLane(SDNode *N, unsigned NumVecs,
SmallVector<SDValue, 4> Regs(N->op_begin() + 2, N->op_begin() + 2 + NumVecs);
if (Narrow)
- std::transform(Regs.begin(), Regs.end(), Regs.begin(),
+ transform(Regs, Regs.begin(),
WidenVector(*CurDAG));
SDValue RegSeq = createQTuple(Regs);
@@ -1390,7 +1406,7 @@ void AArch64DAGToDAGISel::SelectPostStoreLane(SDNode *N, unsigned NumVecs,
SmallVector<SDValue, 4> Regs(N->op_begin() + 1, N->op_begin() + 1 + NumVecs);
if (Narrow)
- std::transform(Regs.begin(), Regs.end(), Regs.begin(),
+ transform(Regs, Regs.begin(),
WidenVector(*CurDAG));
SDValue RegSeq = createQTuple(Regs);
@@ -1859,23 +1875,52 @@ static void getUsefulBitsFromBFM(SDValue Op, SDValue Orig, APInt &UsefulBits,
uint64_t MSB =
cast<const ConstantSDNode>(Op.getOperand(3).getNode())->getZExtValue();
- if (Op.getOperand(1) == Orig)
- return getUsefulBitsFromBitfieldMoveOpd(Op, UsefulBits, Imm, MSB, Depth);
-
APInt OpUsefulBits(UsefulBits);
OpUsefulBits = 1;
+ APInt ResultUsefulBits(UsefulBits.getBitWidth(), 0);
+ ResultUsefulBits.flipAllBits();
+ APInt Mask(UsefulBits.getBitWidth(), 0);
+
+ getUsefulBits(Op, ResultUsefulBits, Depth + 1);
+
if (MSB >= Imm) {
- OpUsefulBits = OpUsefulBits.shl(MSB - Imm + 1);
+ // The instruction is a BFXIL.
+ uint64_t Width = MSB - Imm + 1;
+ uint64_t LSB = Imm;
+
+ OpUsefulBits = OpUsefulBits.shl(Width);
--OpUsefulBits;
- UsefulBits &= ~OpUsefulBits;
- getUsefulBits(Op, UsefulBits, Depth + 1);
+
+ if (Op.getOperand(1) == Orig) {
+ // Copy the low bits from the result to bits starting from LSB.
+ Mask = ResultUsefulBits & OpUsefulBits;
+ Mask = Mask.shl(LSB);
+ }
+
+ if (Op.getOperand(0) == Orig)
+ // Bits starting from LSB in the input contribute to the result.
+ Mask |= (ResultUsefulBits & ~OpUsefulBits);
} else {
- OpUsefulBits = OpUsefulBits.shl(MSB + 1);
+ // The instruction is a BFI.
+ uint64_t Width = MSB + 1;
+ uint64_t LSB = UsefulBits.getBitWidth() - Imm;
+
+ OpUsefulBits = OpUsefulBits.shl(Width);
--OpUsefulBits;
- UsefulBits = ~(OpUsefulBits.shl(OpUsefulBits.getBitWidth() - Imm));
- getUsefulBits(Op, UsefulBits, Depth + 1);
+ OpUsefulBits = OpUsefulBits.shl(LSB);
+
+ if (Op.getOperand(1) == Orig) {
+ // Copy the bits from the result to the zero bits.
+ Mask = ResultUsefulBits & OpUsefulBits;
+ Mask = Mask.lshr(LSB);
+ }
+
+ if (Op.getOperand(0) == Orig)
+ Mask |= (ResultUsefulBits & ~OpUsefulBits);
}
+
+ UsefulBits &= Mask;
}
static void getUsefulBitsForUse(SDNode *UserNode, APInt &UsefulBits,
@@ -1931,7 +1976,7 @@ static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth) {
return;
// Initialize UsefulBits
if (!Depth) {
- unsigned Bitwidth = Op.getValueType().getScalarType().getSizeInBits();
+ unsigned Bitwidth = Op.getScalarValueSizeInBits();
// At the beginning, assume every produced bits is useful
UsefulBits = APInt(Bitwidth, 0);
UsefulBits.flipAllBits();
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 06bfe34..849058b 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -11,28 +11,79 @@
//
//===----------------------------------------------------------------------===//
-#include "AArch64ISelLowering.h"
#include "AArch64CallingConvention.h"
#include "AArch64MachineFunctionInfo.h"
+#include "AArch64ISelLowering.h"
#include "AArch64PerfectShuffle.h"
+#include "AArch64RegisterInfo.h"
#include "AArch64Subtarget.h"
-#include "AArch64TargetMachine.h"
-#include "AArch64TargetObjectFile.h"
#include "MCTargetDesc/AArch64AddressingModes.h"
+#include "Utils/AArch64BaseInfo.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.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"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/OperandTraits.h"
#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/Value.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetCallingConv.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
+#include <algorithm>
+#include <bitset>
+#include <cassert>
+#include <cctype>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+#include <limits>
+#include <tuple>
+#include <utility>
+#include <vector>
+
using namespace llvm;
#define DEBUG_TYPE "aarch64-lower"
@@ -53,20 +104,12 @@ cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration(
cl::desc("Allow AArch64 Local Dynamic TLS code generation"),
cl::init(false));
-// Disabled for causing self-hosting failures once returned-attribute inference
-// was enabled.
-static cl::opt<bool>
-EnableThisRetForwarding("aarch64-this-return-forwarding", cl::Hidden,
- cl::desc("Directly forward this return"),
- cl::init(false));
-
/// Value type used for condition codes.
static const MVT MVT_CC = MVT::i32;
AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
const AArch64Subtarget &STI)
: TargetLowering(TM), Subtarget(&STI) {
-
// AArch64 doesn't have comparisons which set GPRs or setcc instructions, so
// we have to make something up. Arbitrarily, choose ZeroOrOne.
setBooleanContents(ZeroOrOneBooleanContent);
@@ -116,6 +159,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SETCC, MVT::i64, Custom);
setOperationAction(ISD::SETCC, MVT::f32, Custom);
setOperationAction(ISD::SETCC, MVT::f64, Custom);
+ setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
+ setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
@@ -225,7 +270,6 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
-
setOperationAction(ISD::CTPOP, MVT::i32, Custom);
setOperationAction(ISD::CTPOP, MVT::i64, Custom);
@@ -520,6 +564,12 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setPrefFunctionAlignment(STI.getPrefFunctionAlignment());
setPrefLoopAlignment(STI.getPrefLoopAlignment());
+ // Only change the limit for entries in a jump table if specified by
+ // the subtarget, but not at the command line.
+ unsigned MaxJT = STI.getMaximumJumpTableSize();
+ if (MaxJT && getMaximumJumpTableSize() == 0)
+ setMaximumJumpTableSize(MaxJT);
+
setHasExtractBitsInsn(true);
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
@@ -764,7 +814,7 @@ void AArch64TargetLowering::computeKnownBitsForTargetNode(
case Intrinsic::aarch64_ldxr: {
unsigned BitWidth = KnownOne.getBitWidth();
EVT VT = cast<MemIntrinsicSDNode>(Op)->getMemoryVT();
- unsigned MemBits = VT.getScalarType().getSizeInBits();
+ unsigned MemBits = VT.getScalarSizeInBits();
KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - MemBits);
return;
}
@@ -960,8 +1010,10 @@ const char *AArch64TargetLowering::getTargetNodeName(unsigned Opcode) const {
case AArch64ISD::ST4LANEpost: return "AArch64ISD::ST4LANEpost";
case AArch64ISD::SMULL: return "AArch64ISD::SMULL";
case AArch64ISD::UMULL: return "AArch64ISD::UMULL";
- case AArch64ISD::FRSQRTE: return "AArch64ISD::FRSQRTE";
case AArch64ISD::FRECPE: return "AArch64ISD::FRECPE";
+ case AArch64ISD::FRECPS: return "AArch64ISD::FRECPS";
+ case AArch64ISD::FRSQRTE: return "AArch64ISD::FRSQRTE";
+ case AArch64ISD::FRSQRTS: return "AArch64ISD::FRSQRTS";
}
return nullptr;
}
@@ -1186,7 +1238,8 @@ static void changeVectorFPCCToAArch64CC(ISD::CondCode CC,
changeFPCCToAArch64CC(CC, CondCode, CondCode2);
break;
case ISD::SETUO:
- Invert = true; // Fallthrough
+ Invert = true;
+ LLVM_FALLTHROUGH;
case ISD::SETO:
CondCode = AArch64CC::MI;
CondCode2 = AArch64CC::GE;
@@ -2136,7 +2189,7 @@ static bool isExtendedBUILD_VECTOR(SDNode *N, SelectionDAG &DAG,
for (const SDValue &Elt : N->op_values()) {
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Elt)) {
- unsigned EltSize = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSize = VT.getScalarSizeInBits();
unsigned HalfSize = EltSize / 2;
if (isSigned) {
if (!isIntN(HalfSize, C->getSExtValue()))
@@ -2163,7 +2216,7 @@ static SDValue skipExtensionForVectorMULL(SDNode *N, SelectionDAG &DAG) {
assert(N->getOpcode() == ISD::BUILD_VECTOR && "expected BUILD_VECTOR");
EVT VT = N->getValueType(0);
SDLoc dl(N);
- unsigned EltSize = VT.getVectorElementType().getSizeInBits() / 2;
+ unsigned EltSize = VT.getScalarSizeInBits() / 2;
unsigned NumElts = VT.getVectorNumElements();
MVT TruncVT = MVT::getIntegerVT(EltSize);
SmallVector<SDValue, 8> Ops;
@@ -2435,18 +2488,25 @@ CCAssignFn *AArch64TargetLowering::CCAssignFnForCall(CallingConv::ID CC,
case CallingConv::Fast:
case CallingConv::PreserveMost:
case CallingConv::CXX_FAST_TLS:
+ case CallingConv::Swift:
if (!Subtarget->isTargetDarwin())
return CC_AArch64_AAPCS;
return IsVarArg ? CC_AArch64_DarwinPCS_VarArg : CC_AArch64_DarwinPCS;
}
}
+CCAssignFn *
+AArch64TargetLowering::CCAssignFnForReturn(CallingConv::ID CC) const {
+ return CC == CallingConv::WebKit_JS ? RetCC_AArch64_WebKit_JS
+ : RetCC_AArch64_AAPCS;
+}
+
SDValue AArch64TargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
@@ -2499,7 +2559,7 @@ SDValue AArch64TargetLowering::LowerFormalArguments(
// FIXME: This works on big-endian for composite byvals, which are the common
// case. It should also work for fundamental types too.
unsigned FrameIdx =
- MFI->CreateFixedObject(8 * NumRegs, VA.getLocMemOffset(), false);
+ MFI.CreateFixedObject(8 * NumRegs, VA.getLocMemOffset(), false);
SDValue FrameIdxN = DAG.getFrameIndex(FrameIdx, PtrVT);
InVals.push_back(FrameIdxN);
@@ -2564,7 +2624,7 @@ SDValue AArch64TargetLowering::LowerFormalArguments(
!Ins[i].Flags.isInConsecutiveRegs())
BEAlign = 8 - ArgSize;
- int FI = MFI->CreateFixedObject(ArgSize, ArgOffset + BEAlign, true);
+ int FI = MFI.CreateFixedObject(ArgSize, ArgOffset + BEAlign, true);
// Create load nodes to retrieve arguments from the stack.
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
@@ -2614,7 +2674,7 @@ SDValue AArch64TargetLowering::LowerFormalArguments(
unsigned StackOffset = CCInfo.getNextStackOffset();
// We currently pass all varargs at 8-byte alignment.
StackOffset = ((StackOffset + 7) & ~7);
- FuncInfo->setVarArgsStackIndex(MFI->CreateFixedObject(4, StackOffset, true));
+ FuncInfo->setVarArgsStackIndex(MFI.CreateFixedObject(4, StackOffset, true));
}
unsigned StackArgSize = CCInfo.getNextStackOffset();
@@ -2645,7 +2705,7 @@ void AArch64TargetLowering::saveVarArgRegisters(CCState &CCInfo,
const SDLoc &DL,
SDValue &Chain) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
auto PtrVT = getPointerTy(DAG.getDataLayout());
@@ -2660,7 +2720,7 @@ void AArch64TargetLowering::saveVarArgRegisters(CCState &CCInfo,
unsigned GPRSaveSize = 8 * (NumGPRArgRegs - FirstVariadicGPR);
int GPRIdx = 0;
if (GPRSaveSize != 0) {
- GPRIdx = MFI->CreateStackObject(GPRSaveSize, 8, false);
+ GPRIdx = MFI.CreateStackObject(GPRSaveSize, 8, false);
SDValue FIN = DAG.getFrameIndex(GPRIdx, PtrVT);
@@ -2688,7 +2748,7 @@ void AArch64TargetLowering::saveVarArgRegisters(CCState &CCInfo,
unsigned FPRSaveSize = 16 * (NumFPRArgRegs - FirstVariadicFPR);
int FPRIdx = 0;
if (FPRSaveSize != 0) {
- FPRIdx = MFI->CreateStackObject(FPRSaveSize, 16, false);
+ FPRIdx = MFI.CreateStackObject(FPRSaveSize, 16, false);
SDValue FIN = DAG.getFrameIndex(FPRIdx, PtrVT);
@@ -2735,7 +2795,7 @@ SDValue AArch64TargetLowering::LowerCallResult(
// Pass 'this' value directly from the argument to return value, to avoid
// reg unit interference
- if (i == 0 && isThisReturn && EnableThisRetForwarding) {
+ if (i == 0 && isThisReturn) {
assert(!VA.needsCustom() && VA.getLocVT() == MVT::i64 &&
"unexpected return calling convention register assignment");
InVals.push_back(ThisVal);
@@ -2763,15 +2823,29 @@ SDValue AArch64TargetLowering::LowerCallResult(
return Chain;
}
+/// Return true if the calling convention is one that we can guarantee TCO for.
+static bool canGuaranteeTCO(CallingConv::ID CC) {
+ return CC == CallingConv::Fast;
+}
+
+/// Return true if we might ever do TCO for calls with this calling convention.
+static bool mayTailCallThisCC(CallingConv::ID CC) {
+ switch (CC) {
+ case CallingConv::C:
+ case CallingConv::PreserveMost:
+ case CallingConv::Swift:
+ return true;
+ default:
+ return canGuaranteeTCO(CC);
+ }
+}
+
bool AArch64TargetLowering::isEligibleForTailCallOptimization(
SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SmallVectorImpl<ISD::InputArg> &Ins, SelectionDAG &DAG) const {
- // For CallingConv::C this function knows whether the ABI needs
- // changing. That's not true for other conventions so they will have to opt in
- // manually.
- if (!IsTailCallConvention(CalleeCC) && CalleeCC != CallingConv::C)
+ if (!mayTailCallThisCC(CalleeCC))
return false;
MachineFunction &MF = DAG.getMachineFunction();
@@ -2788,9 +2862,8 @@ bool AArch64TargetLowering::isEligibleForTailCallOptimization(
if (i->hasByValAttr())
return false;
- if (getTargetMachine().Options.GuaranteedTailCallOpt) {
- return IsTailCallConvention(CalleeCC) && CCMatch;
- }
+ if (getTargetMachine().Options.GuaranteedTailCallOpt)
+ return canGuaranteeTCO(CalleeCC) && CCMatch;
// Externally-defined functions with weak linkage should not be
// tail-called on AArch64 when the OS does not support dynamic
@@ -2872,11 +2945,11 @@ bool AArch64TargetLowering::isEligibleForTailCallOptimization(
SDValue AArch64TargetLowering::addTokenForArgument(SDValue Chain,
SelectionDAG &DAG,
- MachineFrameInfo *MFI,
+ MachineFrameInfo &MFI,
int ClobberedFI) const {
SmallVector<SDValue, 8> ArgChains;
- int64_t FirstByte = MFI->getObjectOffset(ClobberedFI);
- int64_t LastByte = FirstByte + MFI->getObjectSize(ClobberedFI) - 1;
+ int64_t FirstByte = MFI.getObjectOffset(ClobberedFI);
+ int64_t LastByte = FirstByte + MFI.getObjectSize(ClobberedFI) - 1;
// Include the original chain at the beginning of the list. When this is
// used by target LowerCall hooks, this helps legalize find the
@@ -2890,9 +2963,9 @@ SDValue AArch64TargetLowering::addTokenForArgument(SDValue Chain,
if (LoadSDNode *L = dyn_cast<LoadSDNode>(*U))
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(L->getBasePtr()))
if (FI->getIndex() < 0) {
- int64_t InFirstByte = MFI->getObjectOffset(FI->getIndex());
+ int64_t InFirstByte = MFI.getObjectOffset(FI->getIndex());
int64_t InLastByte = InFirstByte;
- InLastByte += MFI->getObjectSize(FI->getIndex()) - 1;
+ InLastByte += MFI.getObjectSize(FI->getIndex()) - 1;
if ((InFirstByte <= FirstByte && FirstByte <= InLastByte) ||
(FirstByte <= InFirstByte && InFirstByte <= LastByte))
@@ -2908,11 +2981,6 @@ bool AArch64TargetLowering::DoesCalleeRestoreStack(CallingConv::ID CallCC,
return CallCC == CallingConv::Fast && TailCallOpt;
}
-bool AArch64TargetLowering::IsTailCallConvention(CallingConv::ID CallCC) const {
- return CallCC == CallingConv::Fast ||
- CallCC == CallingConv::PreserveMost;
-}
-
/// LowerCall - Lower a call to a callseq_start + CALL + callseq_end chain,
/// and add input and output parameter nodes.
SDValue
@@ -3087,7 +3155,8 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
}
if (VA.isRegLoc()) {
- if (realArgIdx == 0 && Flags.isReturned() && Outs[0].VT == MVT::i64) {
+ if (realArgIdx == 0 && Flags.isReturned() && !Flags.isSwiftSelf() &&
+ Outs[0].VT == MVT::i64) {
assert(VA.getLocVT() == MVT::i64 &&
"unexpected calling convention register assignment");
assert(!Ins.empty() && Ins[0].VT == MVT::i64 &&
@@ -3119,7 +3188,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
if (IsTailCall) {
Offset = Offset + FPDiff;
- int FI = MF.getFrameInfo()->CreateFixedObject(OpSize, Offset, true);
+ int FI = MF.getFrameInfo().CreateFixedObject(OpSize, Offset, true);
DstAddr = DAG.getFrameIndex(FI, PtrVT);
DstInfo =
@@ -3253,7 +3322,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
// If we're doing a tall call, use a TC_RETURN here rather than an
// actual call instruction.
if (IsTailCall) {
- MF.getFrameInfo()->setHasTailCall();
+ MF.getFrameInfo().setHasTailCall();
return DAG.getNode(AArch64ISD::TC_RETURN, DL, NodeTys, Ops);
}
@@ -3444,15 +3513,16 @@ AArch64TargetLowering::LowerDarwinGlobalTLSAddress(SDValue Op,
// The first entry in the descriptor is a function pointer that we must call
// to obtain the address of the variable.
SDValue Chain = DAG.getEntryNode();
- SDValue FuncTLVGet =
- DAG.getLoad(MVT::i64, DL, Chain, DescAddr,
- MachinePointerInfo::getGOT(DAG.getMachineFunction()),
- /* Alignment = */ 8, MachineMemOperand::MONonTemporal |
- MachineMemOperand::MOInvariant);
+ SDValue FuncTLVGet = DAG.getLoad(
+ MVT::i64, DL, Chain, DescAddr,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()),
+ /* Alignment = */ 8,
+ MachineMemOperand::MONonTemporal | MachineMemOperand::MOInvariant |
+ MachineMemOperand::MODereferenceable);
Chain = FuncTLVGet.getValue(1);
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setAdjustsStack(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setAdjustsStack(true);
// TLS calls preserve all registers except those that absolutely must be
// trashed: X0 (it takes an argument), LR (it's a call) and NZCV (let's not be
@@ -3614,6 +3684,7 @@ SDValue AArch64TargetLowering::LowerGlobalTLSAddress(SDValue Op,
llvm_unreachable("Unexpected platform trying to use TLS");
}
+
SDValue AArch64TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
@@ -3705,7 +3776,7 @@ SDValue AArch64TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
// Don't combine AND since emitComparison converts the AND to an ANDS
// (a.k.a. TST) and the test in the test bit and branch instruction
// becomes redundant. This would also increase register pressure.
- uint64_t Mask = LHS.getValueType().getSizeInBits() - 1;
+ uint64_t Mask = LHS.getValueSizeInBits() - 1;
return DAG.getNode(AArch64ISD::TBNZ, dl, MVT::Other, Chain, LHS,
DAG.getConstant(Mask, dl, MVT::i64), Dest);
}
@@ -3715,7 +3786,7 @@ SDValue AArch64TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
// Don't combine AND since emitComparison converts the AND to an ANDS
// (a.k.a. TST) and the test in the test bit and branch instruction
// becomes redundant. This would also increase register pressure.
- uint64_t Mask = LHS.getValueType().getSizeInBits() - 1;
+ uint64_t Mask = LHS.getValueSizeInBits() - 1;
return DAG.getNode(AArch64ISD::TBZ, dl, MVT::Other, Chain, LHS,
DAG.getConstant(Mask, dl, MVT::i64), Dest);
}
@@ -4036,6 +4107,33 @@ SDValue AArch64TargetLowering::LowerSELECT_CC(ISD::CondCode CC, SDValue LHS,
}
}
+ // Avoid materializing a constant when possible by reusing a known value in
+ // a register. However, don't perform this optimization if the known value
+ // is one, zero or negative one in the case of a CSEL. We can always
+ // materialize these values using CSINC, CSEL and CSINV with wzr/xzr as the
+ // FVal, respectively.
+ ConstantSDNode *RHSVal = dyn_cast<ConstantSDNode>(RHS);
+ if (Opcode == AArch64ISD::CSEL && RHSVal && !RHSVal->isOne() &&
+ !RHSVal->isNullValue() && !RHSVal->isAllOnesValue()) {
+ AArch64CC::CondCode AArch64CC = changeIntCCToAArch64CC(CC);
+ // Transform "a == C ? C : x" to "a == C ? a : x" and "a != C ? x : C" to
+ // "a != C ? x : a" to avoid materializing C.
+ if (CTVal && CTVal == RHSVal && AArch64CC == AArch64CC::EQ)
+ TVal = LHS;
+ else if (CFVal && CFVal == RHSVal && AArch64CC == AArch64CC::NE)
+ FVal = LHS;
+ } else if (Opcode == AArch64ISD::CSNEG && RHSVal && RHSVal->isOne()) {
+ assert (CTVal && CFVal && "Expected constant operands for CSNEG.");
+ // Use a CSINV to transform "a == C ? 1 : -1" to "a == C ? a : -1" to
+ // avoid materializing C.
+ AArch64CC::CondCode AArch64CC = changeIntCCToAArch64CC(CC);
+ if (CTVal == RHSVal && AArch64CC == AArch64CC::EQ) {
+ Opcode = AArch64ISD::CSINV;
+ TVal = LHS;
+ FVal = DAG.getConstant(0, dl, FVal.getValueType());
+ }
+ }
+
SDValue CCVal;
SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl);
@@ -4053,6 +4151,26 @@ SDValue AArch64TargetLowering::LowerSELECT_CC(ISD::CondCode CC, SDValue LHS,
// clean. Some of them require two CSELs to implement.
AArch64CC::CondCode CC1, CC2;
changeFPCCToAArch64CC(CC, CC1, CC2);
+
+ if (DAG.getTarget().Options.UnsafeFPMath) {
+ // Transform "a == 0.0 ? 0.0 : x" to "a == 0.0 ? a : x" and
+ // "a != 0.0 ? x : 0.0" to "a != 0.0 ? x : a" to avoid materializing 0.0.
+ ConstantFPSDNode *RHSVal = dyn_cast<ConstantFPSDNode>(RHS);
+ if (RHSVal && RHSVal->isZero()) {
+ ConstantFPSDNode *CFVal = dyn_cast<ConstantFPSDNode>(FVal);
+ ConstantFPSDNode *CTVal = dyn_cast<ConstantFPSDNode>(TVal);
+
+ if ((CC == ISD::SETEQ || CC == ISD::SETOEQ || CC == ISD::SETUEQ) &&
+ CTVal && CTVal->isZero() && TVal.getValueType() == LHS.getValueType())
+ TVal = LHS;
+ else if ((CC == ISD::SETNE || CC == ISD::SETONE || CC == ISD::SETUNE) &&
+ CFVal && CFVal->isZero() &&
+ FVal.getValueType() == LHS.getValueType())
+ FVal = LHS;
+ }
+ }
+
+ // Emit first, and possibly only, CSEL.
SDValue CC1Val = DAG.getConstant(CC1, dl, MVT::i32);
SDValue CS1 = DAG.getNode(AArch64ISD::CSEL, dl, VT, TVal, FVal, CC1Val, Cmp);
@@ -4378,8 +4496,8 @@ SDValue AArch64TargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
SDValue AArch64TargetLowering::LowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc DL(Op);
@@ -4408,8 +4526,8 @@ unsigned AArch64TargetLowering::getRegisterByName(const char* RegName, EVT VT,
SDValue AArch64TargetLowering::LowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc DL(Op);
@@ -4484,7 +4602,6 @@ SDValue AArch64TargetLowering::LowerShiftRightParts(SDValue Op,
return DAG.getMergeValues(Ops, dl);
}
-
/// LowerShiftLeftParts - Lower SHL_PARTS, which returns two
/// i64 values and take a 2 x i64 value to shift plus a shift amount.
SDValue AArch64TargetLowering::LowerShiftLeftParts(SDValue Op,
@@ -4559,38 +4676,96 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
// AArch64 Optimization Hooks
//===----------------------------------------------------------------------===//
-/// getEstimate - Return the appropriate estimate DAG for either the reciprocal
-/// or the reciprocal square root.
-static SDValue getEstimate(const AArch64Subtarget &ST,
- const AArch64TargetLowering::DAGCombinerInfo &DCI, unsigned Opcode,
- const SDValue &Operand, unsigned &ExtraSteps) {
- if (!ST.hasNEON())
- return SDValue();
-
+static SDValue getEstimate(const AArch64Subtarget *ST, unsigned Opcode,
+ SDValue Operand, SelectionDAG &DAG,
+ int &ExtraSteps) {
EVT VT = Operand.getValueType();
+ if (ST->hasNEON() &&
+ (VT == MVT::f64 || VT == MVT::v1f64 || VT == MVT::v2f64 ||
+ VT == MVT::f32 || VT == MVT::v1f32 ||
+ VT == MVT::v2f32 || VT == MVT::v4f32)) {
+ if (ExtraSteps == TargetLoweringBase::ReciprocalEstimate::Unspecified)
+ // For the reciprocal estimates, convergence is quadratic, so the number
+ // of digits is doubled after each iteration. In ARMv8, the accuracy of
+ // the initial estimate is 2^-8. Thus the number of extra steps to refine
+ // the result for float (23 mantissa bits) is 2 and for double (52
+ // mantissa bits) is 3.
+ ExtraSteps = VT == MVT::f64 ? 3 : 2;
- std::string RecipOp;
- RecipOp = Opcode == (AArch64ISD::FRECPE) ? "div": "sqrt";
- RecipOp = ((VT.isVector()) ? "vec-": "") + RecipOp;
- RecipOp += (VT.getScalarType() == MVT::f64) ? "d": "f";
+ return DAG.getNode(Opcode, SDLoc(Operand), VT, Operand);
+ }
- TargetRecip Recips = DCI.DAG.getTarget().Options.Reciprocals;
- if (!Recips.isEnabled(RecipOp))
- return SDValue();
+ return SDValue();
+}
+
+SDValue AArch64TargetLowering::getSqrtEstimate(SDValue Operand,
+ SelectionDAG &DAG, int Enabled,
+ int &ExtraSteps,
+ bool &UseOneConst,
+ bool Reciprocal) const {
+ if (Enabled == ReciprocalEstimate::Enabled ||
+ (Enabled == ReciprocalEstimate::Unspecified && Subtarget->useRSqrt()))
+ if (SDValue Estimate = getEstimate(Subtarget, AArch64ISD::FRSQRTE, Operand,
+ DAG, ExtraSteps)) {
+ SDLoc DL(Operand);
+ EVT VT = Operand.getValueType();
+
+ SDNodeFlags Flags;
+ Flags.setUnsafeAlgebra(true);
+
+ // Newton reciprocal square root iteration: E * 0.5 * (3 - X * E^2)
+ // AArch64 reciprocal square root iteration instruction: 0.5 * (3 - M * N)
+ for (int i = ExtraSteps; i > 0; --i) {
+ SDValue Step = DAG.getNode(ISD::FMUL, DL, VT, Estimate, Estimate,
+ &Flags);
+ Step = DAG.getNode(AArch64ISD::FRSQRTS, DL, VT, Operand, Step, &Flags);
+ Estimate = DAG.getNode(ISD::FMUL, DL, VT, Estimate, Step, &Flags);
+ }
+
+ if (!Reciprocal) {
+ EVT CCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(),
+ VT);
+ SDValue FPZero = DAG.getConstantFP(0.0, DL, VT);
+ SDValue Eq = DAG.getSetCC(DL, CCVT, Operand, FPZero, ISD::SETEQ);
+
+ Estimate = DAG.getNode(ISD::FMUL, DL, VT, Operand, Estimate, &Flags);
+ // Correct the result if the operand is 0.0.
+ Estimate = DAG.getNode(VT.isVector() ? ISD::VSELECT : ISD::SELECT, DL,
+ VT, Eq, Operand, Estimate);
+ }
+
+ ExtraSteps = 0;
+ return Estimate;
+ }
- ExtraSteps = Recips.getRefinementSteps(RecipOp);
- return DCI.DAG.getNode(Opcode, SDLoc(Operand), VT, Operand);
+ return SDValue();
}
SDValue AArch64TargetLowering::getRecipEstimate(SDValue Operand,
- DAGCombinerInfo &DCI, unsigned &ExtraSteps) const {
- return getEstimate(*Subtarget, DCI, AArch64ISD::FRECPE, Operand, ExtraSteps);
-}
+ SelectionDAG &DAG, int Enabled,
+ int &ExtraSteps) const {
+ if (Enabled == ReciprocalEstimate::Enabled)
+ if (SDValue Estimate = getEstimate(Subtarget, AArch64ISD::FRECPE, Operand,
+ DAG, ExtraSteps)) {
+ SDLoc DL(Operand);
+ EVT VT = Operand.getValueType();
+
+ SDNodeFlags Flags;
+ Flags.setUnsafeAlgebra(true);
+
+ // Newton reciprocal iteration: E * (2 - X * E)
+ // AArch64 reciprocal iteration instruction: (2 - M * N)
+ for (int i = ExtraSteps; i > 0; --i) {
+ SDValue Step = DAG.getNode(AArch64ISD::FRECPS, DL, VT, Operand,
+ Estimate, &Flags);
+ Estimate = DAG.getNode(ISD::FMUL, DL, VT, Estimate, Step, &Flags);
+ }
-SDValue AArch64TargetLowering::getRsqrtEstimate(SDValue Operand,
- DAGCombinerInfo &DCI, unsigned &ExtraSteps, bool &UseOneConst) const {
- UseOneConst = true;
- return getEstimate(*Subtarget, DCI, AArch64ISD::FRSQRTE, Operand, ExtraSteps);
+ ExtraSteps = 0;
+ return Estimate;
+ }
+
+ return SDValue();
}
//===----------------------------------------------------------------------===//
@@ -4704,7 +4879,9 @@ AArch64TargetLowering::getRegForInlineAsmConstraint(
return std::make_pair(0U, &AArch64::GPR64commonRegClass);
return std::make_pair(0U, &AArch64::GPR32commonRegClass);
case 'w':
- if (VT == MVT::f32)
+ if (VT.getSizeInBits() == 16)
+ return std::make_pair(0U, &AArch64::FPR16RegClass);
+ if (VT.getSizeInBits() == 32)
return std::make_pair(0U, &AArch64::FPR32RegClass);
if (VT.getSizeInBits() == 64)
return std::make_pair(0U, &AArch64::FPR64RegClass);
@@ -4949,10 +5126,11 @@ SDValue AArch64TargetLowering::ReconstructShuffle(SDValue Op,
int WindowBase;
int WindowScale;
- bool operator ==(SDValue OtherVec) { return Vec == OtherVec; }
ShuffleSourceInfo(SDValue Vec)
- : Vec(Vec), MinElt(UINT_MAX), MaxElt(0), ShuffleVec(Vec), WindowBase(0),
- WindowScale(1) {}
+ : Vec(Vec), MinElt(std::numeric_limits<unsigned>::max()), MaxElt(0),
+ ShuffleVec(Vec), WindowBase(0), WindowScale(1) {}
+
+ bool operator ==(SDValue OtherVec) { return Vec == OtherVec; }
};
// First gather all vectors used as an immediate source for this BUILD_VECTOR
@@ -4971,7 +5149,7 @@ SDValue AArch64TargetLowering::ReconstructShuffle(SDValue Op,
// Add this element source to the list if it's not already there.
SDValue SourceVec = V.getOperand(0);
- auto Source = std::find(Sources.begin(), Sources.end(), SourceVec);
+ auto Source = find(Sources, SourceVec);
if (Source == Sources.end())
Source = Sources.insert(Sources.end(), ShuffleSourceInfo(SourceVec));
@@ -4996,7 +5174,7 @@ SDValue AArch64TargetLowering::ReconstructShuffle(SDValue Op,
}
}
unsigned ResMultiplier =
- VT.getVectorElementType().getSizeInBits() / SmallestEltTy.getSizeInBits();
+ VT.getScalarSizeInBits() / SmallestEltTy.getSizeInBits();
NumElts = VT.getSizeInBits() / SmallestEltTy.getSizeInBits();
EVT ShuffleVT = EVT::getVectorVT(*DAG.getContext(), SmallestEltTy, NumElts);
@@ -5081,21 +5259,21 @@ SDValue AArch64TargetLowering::ReconstructShuffle(SDValue Op,
// The stars all align, our next step is to produce the mask for the shuffle.
SmallVector<int, 8> Mask(ShuffleVT.getVectorNumElements(), -1);
- int BitsPerShuffleLane = ShuffleVT.getVectorElementType().getSizeInBits();
+ int BitsPerShuffleLane = ShuffleVT.getScalarSizeInBits();
for (unsigned i = 0; i < VT.getVectorNumElements(); ++i) {
SDValue Entry = Op.getOperand(i);
if (Entry.isUndef())
continue;
- auto Src = std::find(Sources.begin(), Sources.end(), Entry.getOperand(0));
+ auto Src = find(Sources, Entry.getOperand(0));
int EltNo = cast<ConstantSDNode>(Entry.getOperand(1))->getSExtValue();
// EXTRACT_VECTOR_ELT performs an implicit any_ext; BUILD_VECTOR an implicit
// trunc. So only std::min(SrcBits, DestBits) actually get defined in this
// segment.
EVT OrigEltTy = Entry.getOperand(0).getValueType().getVectorElementType();
- int BitsDefined = std::min(OrigEltTy.getSizeInBits(),
- VT.getVectorElementType().getSizeInBits());
+ int BitsDefined =
+ std::min(OrigEltTy.getSizeInBits(), VT.getScalarSizeInBits());
int LanesDefined = BitsDefined / BitsPerShuffleLane;
// This source is expected to fill ResMultiplier lanes of the final shuffle,
@@ -5157,8 +5335,7 @@ static bool isSingletonEXTMask(ArrayRef<int> M, EVT VT, unsigned &Imm) {
static bool isEXTMask(ArrayRef<int> M, EVT VT, bool &ReverseEXT,
unsigned &Imm) {
// Look for the first non-undef element.
- const int *FirstRealElt = std::find_if(M.begin(), M.end(),
- [](int Elt) {return Elt >= 0;});
+ const int *FirstRealElt = find_if(M, [](int Elt) { return Elt >= 0; });
// Benefit form APInt to handle overflow when calculating expected element.
unsigned NumElts = VT.getVectorNumElements();
@@ -5200,7 +5377,7 @@ static bool isREVMask(ArrayRef<int> M, EVT VT, unsigned BlockSize) {
assert((BlockSize == 16 || BlockSize == 32 || BlockSize == 64) &&
"Only possible block sizes for REV are: 16, 32, 64");
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5381,7 +5558,7 @@ static SDValue tryFormConcatFromShuffle(SDValue Op, SelectionDAG &DAG) {
VT.getVectorElementType() != V1.getValueType().getVectorElementType())
return SDValue();
- bool SplitV0 = V0.getValueType().getSizeInBits() == 128;
+ bool SplitV0 = V0.getValueSizeInBits() == 128;
if (!isConcatMask(Mask, VT, SplitV0))
return SDValue();
@@ -5392,7 +5569,7 @@ static SDValue tryFormConcatFromShuffle(SDValue Op, SelectionDAG &DAG) {
V0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, CastVT, V0,
DAG.getConstant(0, DL, MVT::i64));
}
- if (V1.getValueType().getSizeInBits() == 128) {
+ if (V1.getValueSizeInBits() == 128) {
V1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, CastVT, V1,
DAG.getConstant(0, DL, MVT::i64));
}
@@ -5523,7 +5700,7 @@ static SDValue GenerateTBL(SDValue Op, ArrayRef<int> ShuffleMask,
MVT IndexVT = MVT::v8i8;
unsigned IndexLen = 8;
- if (Op.getValueType().getSizeInBits() == 128) {
+ if (Op.getValueSizeInBits() == 128) {
IndexVT = MVT::v16i8;
IndexLen = 16;
}
@@ -5918,7 +6095,7 @@ static SDValue tryLowerToSLI(SDNode *N, SelectionDAG &DAG) {
// Is C1 == ~C2, taking into account how much one can shift elements of a
// particular size?
uint64_t C2 = C2node->getZExtValue();
- unsigned ElemSizeInBits = VT.getVectorElementType().getSizeInBits();
+ unsigned ElemSizeInBits = VT.getScalarSizeInBits();
if (C2 > ElemSizeInBits)
return SDValue();
unsigned ElemMask = (1 << ElemSizeInBits) - 1;
@@ -6351,7 +6528,7 @@ FailedModImm:
// DUPLANE works on 128-bit vectors, widen it if necessary.
SDValue Lane = Value.getOperand(1);
Value = Value.getOperand(0);
- if (Value.getValueType().getSizeInBits() == 64)
+ if (Value.getValueSizeInBits() == 64)
Value = WidenVector(Value, DAG);
unsigned Opcode = getDUPLANEOp(VT.getVectorElementType());
@@ -6414,7 +6591,7 @@ FailedModImm:
if (!isConstant && !usesOnlyOneValue) {
SDValue Vec = DAG.getUNDEF(VT);
SDValue Op0 = Op.getOperand(0);
- unsigned ElemSize = VT.getVectorElementType().getSizeInBits();
+ unsigned ElemSize = VT.getScalarSizeInBits();
unsigned i = 0;
// For 32 and 64 bit types, use INSERT_SUBREG for lane zero to
// a) Avoid a RMW dependency on the full vector register, and
@@ -6528,7 +6705,7 @@ SDValue AArch64TargetLowering::LowerEXTRACT_SUBVECTOR(SDValue Op,
return SDValue();
unsigned Val = Cst->getZExtValue();
- unsigned Size = Op.getValueType().getSizeInBits();
+ unsigned Size = Op.getValueSizeInBits();
// This will get lowered to an appropriate EXTRACT_SUBREG in ISel.
if (Val == 0)
@@ -6536,7 +6713,7 @@ SDValue AArch64TargetLowering::LowerEXTRACT_SUBVECTOR(SDValue Op,
// If this is extracting the upper 64-bits of a 128-bit vector, we match
// that directly.
- if (Size == 64 && Val * VT.getVectorElementType().getSizeInBits() == 64)
+ if (Size == 64 && Val * VT.getScalarSizeInBits() == 64)
return Op;
return SDValue();
@@ -6606,7 +6783,7 @@ static bool getVShiftImm(SDValue Op, unsigned ElementBits, int64_t &Cnt) {
/// 0 <= Value <= ElementBits for a long left shift.
static bool isVShiftLImm(SDValue Op, EVT VT, bool isLong, int64_t &Cnt) {
assert(VT.isVector() && "vector shift count is not a vector type");
- int64_t ElementBits = VT.getVectorElementType().getSizeInBits();
+ int64_t ElementBits = VT.getScalarSizeInBits();
if (!getVShiftImm(Op, ElementBits, Cnt))
return false;
return (Cnt >= 0 && (isLong ? Cnt - 1 : Cnt) < ElementBits);
@@ -6617,7 +6794,7 @@ static bool isVShiftLImm(SDValue Op, EVT VT, bool isLong, int64_t &Cnt) {
/// 1 <= Value <= ElementBits for a right shift; or
static bool isVShiftRImm(SDValue Op, EVT VT, bool isNarrow, int64_t &Cnt) {
assert(VT.isVector() && "vector shift count is not a vector type");
- int64_t ElementBits = VT.getVectorElementType().getSizeInBits();
+ int64_t ElementBits = VT.getScalarSizeInBits();
if (!getVShiftImm(Op, ElementBits, Cnt))
return false;
return (Cnt >= 1 && Cnt <= (isNarrow ? ElementBits / 2 : ElementBits));
@@ -6631,7 +6808,7 @@ SDValue AArch64TargetLowering::LowerVectorSRA_SRL_SHL(SDValue Op,
if (!Op.getOperand(1).getValueType().isVector())
return Op;
- unsigned EltSize = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSize = VT.getScalarSizeInBits();
switch (Op.getOpcode()) {
default:
@@ -6716,8 +6893,8 @@ static SDValue EmitVectorComparison(SDValue LHS, SDValue RHS,
case AArch64CC::LT:
if (!NoNans)
return SDValue();
- // If we ignore NaNs then we can use to the MI implementation.
- // Fallthrough.
+ // If we ignore NaNs then we can use to the MI implementation.
+ LLVM_FALLTHROUGH;
case AArch64CC::MI:
if (IsZero)
return DAG.getNode(AArch64ISD::FCMLTz, dl, VT, LHS);
@@ -6904,7 +7081,7 @@ bool AArch64TargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
return true;
}
case Intrinsic::aarch64_ldaxp:
- case Intrinsic::aarch64_ldxp: {
+ case Intrinsic::aarch64_ldxp:
Info.opc = ISD::INTRINSIC_W_CHAIN;
Info.memVT = MVT::i128;
Info.ptrVal = I.getArgOperand(0);
@@ -6914,9 +7091,8 @@ bool AArch64TargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
Info.readMem = true;
Info.writeMem = false;
return true;
- }
case Intrinsic::aarch64_stlxp:
- case Intrinsic::aarch64_stxp: {
+ case Intrinsic::aarch64_stxp:
Info.opc = ISD::INTRINSIC_W_CHAIN;
Info.memVT = MVT::i128;
Info.ptrVal = I.getArgOperand(2);
@@ -6926,7 +7102,6 @@ bool AArch64TargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
Info.readMem = false;
Info.writeMem = true;
return true;
- }
default:
break;
}
@@ -7033,8 +7208,8 @@ bool AArch64TargetLowering::isExtFreeImpl(const Instruction *Ext) const {
case Instruction::GetElementPtr: {
gep_type_iterator GTI = gep_type_begin(Instr);
auto &DL = Ext->getModule()->getDataLayout();
- std::advance(GTI, U.getOperandNo());
- Type *IdxTy = *GTI;
+ std::advance(GTI, U.getOperandNo()-1);
+ Type *IdxTy = GTI.getIndexedType();
// This extension will end up with a shift because of the scaling factor.
// 8-bit sized types have a scaling factor of 1, thus a shift amount of 0.
// Get the shift amount based on the scaling factor:
@@ -7052,7 +7227,7 @@ bool AArch64TargetLowering::isExtFreeImpl(const Instruction *Ext) const {
// trunc(sext ty1 to ty2) to ty1.
if (Instr->getType() == Ext->getOperand(0)->getType())
continue;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
default:
return false;
}
@@ -7063,16 +7238,6 @@ bool AArch64TargetLowering::isExtFreeImpl(const Instruction *Ext) const {
return true;
}
-bool AArch64TargetLowering::hasPairedLoad(Type *LoadedType,
- unsigned &RequiredAligment) const {
- if (!LoadedType->isIntegerTy() && !LoadedType->isFloatTy())
- return false;
- // Cyclone supports unaligned accesses.
- RequiredAligment = 0;
- unsigned NumBits = LoadedType->getPrimitiveSizeInBits();
- return NumBits == 32 || NumBits == 64;
-}
-
bool AArch64TargetLowering::hasPairedLoad(EVT LoadedType,
unsigned &RequiredAligment) const {
if (!LoadedType.isSimple() ||
@@ -7167,7 +7332,7 @@ static Constant *getSequentialMask(IRBuilder<> &Builder, unsigned Start,
///
/// E.g. Lower an interleaved store (Factor = 3):
/// %i.vec = shuffle <8 x i32> %v0, <8 x i32> %v1,
-/// <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11>
+/// <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11>
/// store <12 x i32> %i.vec, <12 x i32>* %ptr
///
/// Into:
@@ -7178,6 +7343,17 @@ static Constant *getSequentialMask(IRBuilder<> &Builder, unsigned Start,
///
/// Note that the new shufflevectors will be removed and we'll only generate one
/// st3 instruction in CodeGen.
+///
+/// Example for a more general valid mask (Factor 3). Lower:
+/// %i.vec = shuffle <32 x i32> %v0, <32 x i32> %v1,
+/// <4, 32, 16, 5, 33, 17, 6, 34, 18, 7, 35, 19>
+/// store <12 x i32> %i.vec, <12 x i32>* %ptr
+///
+/// Into:
+/// %sub.v0 = shuffle <32 x i32> %v0, <32 x i32> v1, <4, 5, 6, 7>
+/// %sub.v1 = shuffle <32 x i32> %v0, <32 x i32> v1, <32, 33, 34, 35>
+/// %sub.v2 = shuffle <32 x i32> %v0, <32 x i32> v1, <16, 17, 18, 19>
+/// call void llvm.aarch64.neon.st3(%sub.v0, %sub.v1, %sub.v2, %ptr)
bool AArch64TargetLowering::lowerInterleavedStore(StoreInst *SI,
ShuffleVectorInst *SVI,
unsigned Factor) const {
@@ -7188,9 +7364,9 @@ bool AArch64TargetLowering::lowerInterleavedStore(StoreInst *SI,
assert(VecTy->getVectorNumElements() % Factor == 0 &&
"Invalid interleaved store");
- unsigned NumSubElts = VecTy->getVectorNumElements() / Factor;
+ unsigned LaneLen = VecTy->getVectorNumElements() / Factor;
Type *EltTy = VecTy->getVectorElementType();
- VectorType *SubVecTy = VectorType::get(EltTy, NumSubElts);
+ VectorType *SubVecTy = VectorType::get(EltTy, LaneLen);
const DataLayout &DL = SI->getModule()->getDataLayout();
unsigned SubVecSize = DL.getTypeSizeInBits(SubVecTy);
@@ -7215,7 +7391,7 @@ bool AArch64TargetLowering::lowerInterleavedStore(StoreInst *SI,
Op0 = Builder.CreatePtrToInt(Op0, IntVecTy);
Op1 = Builder.CreatePtrToInt(Op1, IntVecTy);
- SubVecTy = VectorType::get(IntTy, NumSubElts);
+ SubVecTy = VectorType::get(IntTy, LaneLen);
}
Type *PtrTy = SubVecTy->getPointerTo(SI->getPointerAddressSpace());
@@ -7229,9 +7405,28 @@ bool AArch64TargetLowering::lowerInterleavedStore(StoreInst *SI,
SmallVector<Value *, 5> Ops;
// Split the shufflevector operands into sub vectors for the new stN call.
- for (unsigned i = 0; i < Factor; i++)
- Ops.push_back(Builder.CreateShuffleVector(
- Op0, Op1, getSequentialMask(Builder, NumSubElts * i, NumSubElts)));
+ auto Mask = SVI->getShuffleMask();
+ for (unsigned i = 0; i < Factor; i++) {
+ if (Mask[i] >= 0) {
+ Ops.push_back(Builder.CreateShuffleVector(
+ Op0, Op1, getSequentialMask(Builder, Mask[i], LaneLen)));
+ } else {
+ unsigned StartMask = 0;
+ for (unsigned j = 1; j < LaneLen; j++) {
+ if (Mask[j*Factor + i] >= 0) {
+ StartMask = Mask[j*Factor + i] - j;
+ break;
+ }
+ }
+ // Note: If all elements in a chunk are undefs, StartMask=0!
+ // Note: Filling undef gaps with random elements is ok, since
+ // those elements were being written anyway (with undefs).
+ // In the case of all undefs we're defaulting to using elems from 0
+ // Note: StartMask cannot be negative, it's checked in isReInterleaveMask
+ Ops.push_back(Builder.CreateShuffleVector(
+ Op0, Op1, getSequentialMask(Builder, StartMask, LaneLen)));
+ }
+ }
Ops.push_back(Builder.CreateBitCast(SI->getPointerOperand(), PtrTy));
Builder.CreateCall(StNFunc, Ops);
@@ -7323,7 +7518,7 @@ bool AArch64TargetLowering::isLegalAddressingMode(const DataLayout &DL,
int64_t Offset = AM.BaseOffs;
// 9-bit signed offset
- if (Offset >= -(1LL << 9) && Offset <= (1LL << 9) - 1)
+ if (isInt<9>(Offset))
return true;
// 12-bit unsigned offset
@@ -7337,8 +7532,7 @@ bool AArch64TargetLowering::isLegalAddressingMode(const DataLayout &DL,
// Check reg1 + SIZE_IN_BYTES * reg2 and reg1 + reg2
- return !AM.Scale || AM.Scale == 1 ||
- (AM.Scale > 0 && (uint64_t)AM.Scale == NumBytes);
+ return AM.Scale == 1 || (AM.Scale > 0 && (uint64_t)AM.Scale == NumBytes);
}
int AArch64TargetLowering::getScalingFactorCost(const DataLayout &DL,
@@ -7544,57 +7738,98 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
if (DCI.isBeforeLegalizeOps())
return SDValue();
+ // The below optimizations require a constant RHS.
+ if (!isa<ConstantSDNode>(N->getOperand(1)))
+ return SDValue();
+
+ ConstantSDNode *C = cast<ConstantSDNode>(N->getOperand(1));
+ const APInt &ConstValue = C->getAPIntValue();
+
// Multiplication of a power of two plus/minus one can be done more
// cheaply as as shift+add/sub. For now, this is true unilaterally. If
// future CPUs have a cheaper MADD instruction, this may need to be
// gated on a subtarget feature. For Cyclone, 32-bit MADD is 4 cycles and
// 64-bit is 5 cycles, so this is always a win.
- if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
- const APInt &Value = C->getAPIntValue();
- EVT VT = N->getValueType(0);
- SDLoc DL(N);
- if (Value.isNonNegative()) {
- // (mul x, 2^N + 1) => (add (shl x, N), x)
- APInt VM1 = Value - 1;
- if (VM1.isPowerOf2()) {
- SDValue ShiftedVal =
- DAG.getNode(ISD::SHL, DL, VT, N->getOperand(0),
- DAG.getConstant(VM1.logBase2(), DL, MVT::i64));
- return DAG.getNode(ISD::ADD, DL, VT, ShiftedVal,
- N->getOperand(0));
- }
- // (mul x, 2^N - 1) => (sub (shl x, N), x)
- APInt VP1 = Value + 1;
- if (VP1.isPowerOf2()) {
- SDValue ShiftedVal =
- DAG.getNode(ISD::SHL, DL, VT, N->getOperand(0),
- DAG.getConstant(VP1.logBase2(), DL, MVT::i64));
- return DAG.getNode(ISD::SUB, DL, VT, ShiftedVal,
- N->getOperand(0));
- }
- } else {
- // (mul x, -(2^N - 1)) => (sub x, (shl x, N))
- APInt VNP1 = -Value + 1;
- if (VNP1.isPowerOf2()) {
- SDValue ShiftedVal =
- DAG.getNode(ISD::SHL, DL, VT, N->getOperand(0),
- DAG.getConstant(VNP1.logBase2(), DL, MVT::i64));
- return DAG.getNode(ISD::SUB, DL, VT, N->getOperand(0),
- ShiftedVal);
- }
- // (mul x, -(2^N + 1)) => - (add (shl x, N), x)
- APInt VNM1 = -Value - 1;
- if (VNM1.isPowerOf2()) {
- SDValue ShiftedVal =
- DAG.getNode(ISD::SHL, DL, VT, N->getOperand(0),
- DAG.getConstant(VNM1.logBase2(), DL, MVT::i64));
- SDValue Add =
- DAG.getNode(ISD::ADD, DL, VT, ShiftedVal, N->getOperand(0));
- return DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT), Add);
- }
- }
+ // More aggressively, some multiplications N0 * C can be lowered to
+ // shift+add+shift if the constant C = A * B where A = 2^N + 1 and B = 2^M,
+ // e.g. 6=3*2=(2+1)*2.
+ // TODO: consider lowering more cases, e.g. C = 14, -6, -14 or even 45
+ // which equals to (1+2)*16-(1+2).
+ SDValue N0 = N->getOperand(0);
+ // TrailingZeroes is used to test if the mul can be lowered to
+ // shift+add+shift.
+ unsigned TrailingZeroes = ConstValue.countTrailingZeros();
+ if (TrailingZeroes) {
+ // Conservatively do not lower to shift+add+shift if the mul might be
+ // folded into smul or umul.
+ if (N0->hasOneUse() && (isSignExtended(N0.getNode(), DAG) ||
+ isZeroExtended(N0.getNode(), DAG)))
+ return SDValue();
+ // Conservatively do not lower to shift+add+shift if the mul might be
+ // folded into madd or msub.
+ if (N->hasOneUse() && (N->use_begin()->getOpcode() == ISD::ADD ||
+ N->use_begin()->getOpcode() == ISD::SUB))
+ return SDValue();
}
- return SDValue();
+ // Use ShiftedConstValue instead of ConstValue to support both shift+add/sub
+ // and shift+add+shift.
+ APInt ShiftedConstValue = ConstValue.ashr(TrailingZeroes);
+
+ unsigned ShiftAmt, AddSubOpc;
+ // Is the shifted value the LHS operand of the add/sub?
+ bool ShiftValUseIsN0 = true;
+ // Do we need to negate the result?
+ bool NegateResult = false;
+
+ if (ConstValue.isNonNegative()) {
+ // (mul x, 2^N + 1) => (add (shl x, N), x)
+ // (mul x, 2^N - 1) => (sub (shl x, N), x)
+ // (mul x, (2^N + 1) * 2^M) => (shl (add (shl x, N), x), M)
+ APInt SCVMinus1 = ShiftedConstValue - 1;
+ APInt CVPlus1 = ConstValue + 1;
+ if (SCVMinus1.isPowerOf2()) {
+ ShiftAmt = SCVMinus1.logBase2();
+ AddSubOpc = ISD::ADD;
+ } else if (CVPlus1.isPowerOf2()) {
+ ShiftAmt = CVPlus1.logBase2();
+ AddSubOpc = ISD::SUB;
+ } else
+ return SDValue();
+ } else {
+ // (mul x, -(2^N - 1)) => (sub x, (shl x, N))
+ // (mul x, -(2^N + 1)) => - (add (shl x, N), x)
+ APInt CVNegPlus1 = -ConstValue + 1;
+ APInt CVNegMinus1 = -ConstValue - 1;
+ if (CVNegPlus1.isPowerOf2()) {
+ ShiftAmt = CVNegPlus1.logBase2();
+ AddSubOpc = ISD::SUB;
+ ShiftValUseIsN0 = false;
+ } else if (CVNegMinus1.isPowerOf2()) {
+ ShiftAmt = CVNegMinus1.logBase2();
+ AddSubOpc = ISD::ADD;
+ NegateResult = true;
+ } else
+ return SDValue();
+ }
+
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+ SDValue ShiftedVal = DAG.getNode(ISD::SHL, DL, VT, N0,
+ DAG.getConstant(ShiftAmt, DL, MVT::i64));
+
+ SDValue AddSubN0 = ShiftValUseIsN0 ? ShiftedVal : N0;
+ SDValue AddSubN1 = ShiftValUseIsN0 ? N0 : ShiftedVal;
+ SDValue Res = DAG.getNode(AddSubOpc, DL, VT, AddSubN0, AddSubN1);
+ assert(!(NegateResult && TrailingZeroes) &&
+ "NegateResult and TrailingZeroes cannot both be true for now.");
+ // Negate the result.
+ if (NegateResult)
+ return DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT), Res);
+ // Shift the result.
+ if (TrailingZeroes)
+ return DAG.getNode(ISD::SHL, DL, VT, Res,
+ DAG.getConstant(TrailingZeroes, DL, MVT::i64));
+ return Res;
}
static SDValue performVectorCompareAndMaskUnaryOpCombine(SDNode *N,
@@ -7655,7 +7890,7 @@ static SDValue performIntToFpCombine(SDNode *N, SelectionDAG &DAG,
return SDValue();
// Only optimize when the source and destination types have the same width.
- if (VT.getSizeInBits() != N->getOperand(0).getValueType().getSizeInBits())
+ if (VT.getSizeInBits() != N->getOperand(0).getValueSizeInBits())
return SDValue();
// If the result of an integer load is only used by an integer-to-float
@@ -7757,13 +7992,15 @@ static SDValue performFpToIntCombine(SDNode *N, SelectionDAG &DAG,
/// Fold a floating-point divide by power of two into fixed-point to
/// floating-point conversion.
static SDValue performFDivCombine(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
const AArch64Subtarget *Subtarget) {
if (!Subtarget->hasNEON())
return SDValue();
SDValue Op = N->getOperand(0);
unsigned Opc = Op->getOpcode();
- if (!Op.getValueType().isVector() ||
+ if (!Op.getValueType().isVector() || !Op.getValueType().isSimple() ||
+ !Op.getOperand(0).getValueType().isSimple() ||
(Opc != ISD::SINT_TO_FP && Opc != ISD::UINT_TO_FP))
return SDValue();
@@ -7800,10 +8037,13 @@ static SDValue performFDivCombine(SDNode *N, SelectionDAG &DAG,
ResTy = FloatBits == 32 ? MVT::v2i32 : MVT::v2i64;
break;
case 4:
- ResTy = MVT::v4i32;
+ ResTy = FloatBits == 32 ? MVT::v4i32 : MVT::v4i64;
break;
}
+ if (ResTy == MVT::v4i64 && DCI.isBeforeLegalizeOps())
+ return SDValue();
+
SDLoc DL(N);
SDValue ConvInput = Op.getOperand(0);
bool IsSigned = Opc == ISD::SINT_TO_FP;
@@ -7855,13 +8095,13 @@ static SDValue tryCombineToEXTR(SDNode *N,
SDValue LHS;
uint32_t ShiftLHS = 0;
- bool LHSFromHi = 0;
+ bool LHSFromHi = false;
if (!findEXTRHalf(N->getOperand(0), LHS, ShiftLHS, LHSFromHi))
return SDValue();
SDValue RHS;
uint32_t ShiftRHS = 0;
- bool RHSFromHi = 0;
+ bool RHSFromHi = false;
if (!findEXTRHalf(N->getOperand(1), RHS, ShiftRHS, RHSFromHi))
return SDValue();
@@ -7901,7 +8141,7 @@ static SDValue tryCombineToBSL(SDNode *N,
// We only have to look for constant vectors here since the general, variable
// case can be handled in TableGen.
- unsigned Bits = VT.getVectorElementType().getSizeInBits();
+ unsigned Bits = VT.getScalarSizeInBits();
uint64_t BitMask = Bits == 64 ? -1ULL : ((1ULL << Bits) - 1);
for (int i = 1; i >= 0; --i)
for (int j = 1; j >= 0; --j) {
@@ -8090,7 +8330,7 @@ static SDValue performConcatVectorsCombine(SDNode *N,
// splat. The indexed instructions are going to be expecting a DUPLANE64, so
// canonicalise to that.
if (N0 == N1 && VT.getVectorNumElements() == 2) {
- assert(VT.getVectorElementType().getSizeInBits() == 64);
+ assert(VT.getScalarSizeInBits() == 64);
return DAG.getNode(AArch64ISD::DUPLANE64, dl, VT, WidenVector(N0, DAG),
DAG.getConstant(0, dl, MVT::i64));
}
@@ -8153,7 +8393,7 @@ static SDValue tryCombineFixedPointConvert(SDNode *N,
// The vector width should be 128 bits by the time we get here, even
// if it started as 64 bits (the extract_vector handling will have
// done so).
- assert(Vec.getValueType().getSizeInBits() == 128 &&
+ assert(Vec.getValueSizeInBits() == 128 &&
"unexpected vector size on extract_vector_elt!");
if (Vec.getValueType() == MVT::v4i32)
VecResTy = MVT::v4f32;
@@ -8655,7 +8895,7 @@ static SDValue performExtendCombine(SDNode *N,
if (SrcVT.getSizeInBits() != 64)
return SDValue();
- unsigned SrcEltSize = SrcVT.getVectorElementType().getSizeInBits();
+ unsigned SrcEltSize = SrcVT.getScalarSizeInBits();
unsigned ElementCount = SrcVT.getVectorNumElements();
SrcVT = MVT::getVectorVT(MVT::getIntegerVT(SrcEltSize * 2), ElementCount);
SDLoc DL(N);
@@ -8684,13 +8924,101 @@ static SDValue performExtendCombine(SDNode *N,
return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi);
}
+static SDValue splitStoreSplat(SelectionDAG &DAG, StoreSDNode &St,
+ SDValue SplatVal, unsigned NumVecElts) {
+ unsigned OrigAlignment = St.getAlignment();
+ unsigned EltOffset = SplatVal.getValueType().getSizeInBits() / 8;
+
+ // Create scalar stores. This is at least as good as the code sequence for a
+ // split unaligned store which is a dup.s, ext.b, and two stores.
+ // Most of the time the three stores should be replaced by store pair
+ // instructions (stp).
+ SDLoc DL(&St);
+ SDValue BasePtr = St.getBasePtr();
+ const MachinePointerInfo &PtrInfo = St.getPointerInfo();
+ SDValue NewST1 =
+ DAG.getStore(St.getChain(), DL, SplatVal, BasePtr, PtrInfo,
+ OrigAlignment, St.getMemOperand()->getFlags());
+
+ unsigned Offset = EltOffset;
+ while (--NumVecElts) {
+ unsigned Alignment = MinAlign(OrigAlignment, Offset);
+ SDValue OffsetPtr = DAG.getNode(ISD::ADD, DL, MVT::i64, BasePtr,
+ DAG.getConstant(Offset, DL, MVT::i64));
+ NewST1 = DAG.getStore(NewST1.getValue(0), DL, SplatVal, OffsetPtr,
+ PtrInfo.getWithOffset(Offset), Alignment,
+ St.getMemOperand()->getFlags());
+ Offset += EltOffset;
+ }
+ return NewST1;
+}
+
+/// Replace a splat of zeros to a vector store by scalar stores of WZR/XZR. The
+/// load store optimizer pass will merge them to store pair stores. This should
+/// be better than a movi to create the vector zero followed by a vector store
+/// if the zero constant is not re-used, since one instructions and one register
+/// live range will be removed.
+///
+/// For example, the final generated code should be:
+///
+/// stp xzr, xzr, [x0]
+///
+/// instead of:
+///
+/// movi v0.2d, #0
+/// str q0, [x0]
+///
+static SDValue replaceZeroVectorStore(SelectionDAG &DAG, StoreSDNode &St) {
+ SDValue StVal = St.getValue();
+ EVT VT = StVal.getValueType();
+
+ // It is beneficial to scalarize a zero splat store for 2 or 3 i64 elements or
+ // 2, 3 or 4 i32 elements.
+ int NumVecElts = VT.getVectorNumElements();
+ if (!(((NumVecElts == 2 || NumVecElts == 3) &&
+ VT.getVectorElementType().getSizeInBits() == 64) ||
+ ((NumVecElts == 2 || NumVecElts == 3 || NumVecElts == 4) &&
+ VT.getVectorElementType().getSizeInBits() == 32)))
+ return SDValue();
+
+ if (StVal.getOpcode() != ISD::BUILD_VECTOR)
+ return SDValue();
+
+ // If the zero constant has more than one use then the vector store could be
+ // better since the constant mov will be amortized and stp q instructions
+ // should be able to be formed.
+ if (!StVal.hasOneUse())
+ return SDValue();
+
+ // If the immediate offset of the address operand is too large for the stp
+ // instruction, then bail out.
+ if (DAG.isBaseWithConstantOffset(St.getBasePtr())) {
+ int64_t Offset = St.getBasePtr()->getConstantOperandVal(1);
+ if (Offset < -512 || Offset > 504)
+ return SDValue();
+ }
+
+ for (int I = 0; I < NumVecElts; ++I) {
+ SDValue EltVal = StVal.getOperand(I);
+ if (!isNullConstant(EltVal) && !isNullFPConstant(EltVal))
+ return SDValue();
+ }
+
+ // Use WZR/XZR here to prevent DAGCombiner::MergeConsecutiveStores from
+ // undoing this transformation.
+ SDValue SplatVal = VT.getVectorElementType().getSizeInBits() == 32
+ ? DAG.getRegister(AArch64::WZR, MVT::i32)
+ : DAG.getRegister(AArch64::XZR, MVT::i64);
+ return splitStoreSplat(DAG, St, SplatVal, NumVecElts);
+}
+
/// Replace a splat of a scalar to a vector store by scalar stores of the scalar
/// value. The load store optimizer pass will merge them to store pair stores.
/// This has better performance than a splat of the scalar followed by a split
/// vector store. Even if the stores are not merged it is four stores vs a dup,
/// followed by an ext.b and two stores.
-static SDValue replaceSplatVectorStore(SelectionDAG &DAG, StoreSDNode *St) {
- SDValue StVal = St->getValue();
+static SDValue replaceSplatVectorStore(SelectionDAG &DAG, StoreSDNode &St) {
+ SDValue StVal = St.getValue();
EVT VT = StVal.getValueType();
// Don't replace floating point stores, they possibly won't be transformed to
@@ -8698,55 +9026,48 @@ static SDValue replaceSplatVectorStore(SelectionDAG &DAG, StoreSDNode *St) {
if (VT.isFloatingPoint())
return SDValue();
- // Check for insert vector elements.
- if (StVal.getOpcode() != ISD::INSERT_VECTOR_ELT)
- return SDValue();
-
// We can express a splat as store pair(s) for 2 or 4 elements.
unsigned NumVecElts = VT.getVectorNumElements();
if (NumVecElts != 4 && NumVecElts != 2)
return SDValue();
- SDValue SplatVal = StVal.getOperand(1);
- unsigned RemainInsertElts = NumVecElts - 1;
// Check that this is a splat.
- while (--RemainInsertElts) {
- SDValue NextInsertElt = StVal.getOperand(0);
- if (NextInsertElt.getOpcode() != ISD::INSERT_VECTOR_ELT)
+ // Make sure that each of the relevant vector element locations are inserted
+ // to, i.e. 0 and 1 for v2i64 and 0, 1, 2, 3 for v4i32.
+ std::bitset<4> IndexNotInserted((1 << NumVecElts) - 1);
+ SDValue SplatVal;
+ for (unsigned I = 0; I < NumVecElts; ++I) {
+ // Check for insert vector elements.
+ if (StVal.getOpcode() != ISD::INSERT_VECTOR_ELT)
return SDValue();
- if (NextInsertElt.getOperand(1) != SplatVal)
+
+ // Check that same value is inserted at each vector element.
+ if (I == 0)
+ SplatVal = StVal.getOperand(1);
+ else if (StVal.getOperand(1) != SplatVal)
return SDValue();
- StVal = NextInsertElt;
- }
- unsigned OrigAlignment = St->getAlignment();
- unsigned EltOffset = NumVecElts == 4 ? 4 : 8;
- unsigned Alignment = std::min(OrigAlignment, EltOffset);
- // Create scalar stores. This is at least as good as the code sequence for a
- // split unaligned store which is a dup.s, ext.b, and two stores.
- // Most of the time the three stores should be replaced by store pair
- // instructions (stp).
- SDLoc DL(St);
- SDValue BasePtr = St->getBasePtr();
- SDValue NewST1 =
- DAG.getStore(St->getChain(), DL, SplatVal, BasePtr, St->getPointerInfo(),
- St->getAlignment(), St->getMemOperand()->getFlags());
+ // Check insert element index.
+ ConstantSDNode *CIndex = dyn_cast<ConstantSDNode>(StVal.getOperand(2));
+ if (!CIndex)
+ return SDValue();
+ uint64_t IndexVal = CIndex->getZExtValue();
+ if (IndexVal >= NumVecElts)
+ return SDValue();
+ IndexNotInserted.reset(IndexVal);
- unsigned Offset = EltOffset;
- while (--NumVecElts) {
- SDValue OffsetPtr = DAG.getNode(ISD::ADD, DL, MVT::i64, BasePtr,
- DAG.getConstant(Offset, DL, MVT::i64));
- NewST1 = DAG.getStore(NewST1.getValue(0), DL, SplatVal, OffsetPtr,
- St->getPointerInfo(), Alignment,
- St->getMemOperand()->getFlags());
- Offset += EltOffset;
+ StVal = StVal.getOperand(0);
}
- return NewST1;
+ // Check that all vector element locations were inserted to.
+ if (IndexNotInserted.any())
+ return SDValue();
+
+ return splitStoreSplat(DAG, St, SplatVal, NumVecElts);
}
-static SDValue split16BStores(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
- SelectionDAG &DAG,
- const AArch64Subtarget *Subtarget) {
+static SDValue splitStores(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
+ SelectionDAG &DAG,
+ const AArch64Subtarget *Subtarget) {
if (!DCI.isBeforeLegalize())
return SDValue();
@@ -8754,6 +9075,17 @@ static SDValue split16BStores(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
if (S->isVolatile())
return SDValue();
+ SDValue StVal = S->getValue();
+ EVT VT = StVal.getValueType();
+ if (!VT.isVector())
+ return SDValue();
+
+ // If we get a splat of zeros, convert this vector store to a store of
+ // scalars. They will be merged into store pairs of xzr thereby removing one
+ // instruction and one register.
+ if (SDValue ReplacedZeroSplat = replaceZeroVectorStore(DAG, *S))
+ return ReplacedZeroSplat;
+
// FIXME: The logic for deciding if an unaligned store should be split should
// be included in TLI.allowsMisalignedMemoryAccesses(), and there should be
// a call to that function here.
@@ -8765,12 +9097,9 @@ static SDValue split16BStores(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
if (DAG.getMachineFunction().getFunction()->optForMinSize())
return SDValue();
- SDValue StVal = S->getValue();
- EVT VT = StVal.getValueType();
-
// Don't split v2i64 vectors. Memcpy lowering produces those and splitting
// those up regresses performance on micro-benchmarks and olden/bh.
- if (!VT.isVector() || VT.getVectorNumElements() < 2 || VT == MVT::v2i64)
+ if (VT.getVectorNumElements() < 2 || VT == MVT::v2i64)
return SDValue();
// Split unaligned 16B stores. They are terrible for performance.
@@ -8785,7 +9114,7 @@ static SDValue split16BStores(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
// If we get a splat of a scalar convert this vector store to a store of
// scalars. They will be merged into store pairs thereby removing two
// instructions.
- if (SDValue ReplacedSplat = replaceSplatVectorStore(DAG, S))
+ if (SDValue ReplacedSplat = replaceSplatVectorStore(DAG, *S))
return ReplacedSplat;
SDLoc DL(S);
@@ -8928,7 +9257,7 @@ static SDValue performSTORECombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
SelectionDAG &DAG,
const AArch64Subtarget *Subtarget) {
- if (SDValue Split = split16BStores(N, DCI, DAG, Subtarget))
+ if (SDValue Split = splitStores(N, DCI, DAG, Subtarget))
return Split;
if (Subtarget->supportsAddressTopByteIgnored() &&
@@ -9455,52 +9784,51 @@ static bool isEquivalentMaskless(unsigned CC, unsigned width,
switch(CC) {
case AArch64CC::LE:
- case AArch64CC::GT: {
+ case AArch64CC::GT:
if ((AddConstant == 0) ||
(CompConstant == MaxUInt - 1 && AddConstant < 0) ||
(AddConstant >= 0 && CompConstant < 0) ||
(AddConstant <= 0 && CompConstant <= 0 && CompConstant < AddConstant))
return true;
- } break;
+ break;
case AArch64CC::LT:
- case AArch64CC::GE: {
+ case AArch64CC::GE:
if ((AddConstant == 0) ||
(AddConstant >= 0 && CompConstant <= 0) ||
(AddConstant <= 0 && CompConstant <= 0 && CompConstant <= AddConstant))
return true;
- } break;
+ break;
case AArch64CC::HI:
- case AArch64CC::LS: {
+ case AArch64CC::LS:
if ((AddConstant >= 0 && CompConstant < 0) ||
(AddConstant <= 0 && CompConstant >= -1 &&
CompConstant < AddConstant + MaxUInt))
return true;
- } break;
+ break;
case AArch64CC::PL:
- case AArch64CC::MI: {
+ case AArch64CC::MI:
if ((AddConstant == 0) ||
(AddConstant > 0 && CompConstant <= 0) ||
(AddConstant < 0 && CompConstant <= AddConstant))
return true;
- } break;
+ break;
case AArch64CC::LO:
- case AArch64CC::HS: {
+ case AArch64CC::HS:
if ((AddConstant >= 0 && CompConstant <= 0) ||
(AddConstant <= 0 && CompConstant >= 0 &&
CompConstant <= AddConstant + MaxUInt))
return true;
- } break;
+ break;
case AArch64CC::EQ:
- case AArch64CC::NE: {
+ case AArch64CC::NE:
if ((AddConstant > 0 && CompConstant < 0) ||
(AddConstant < 0 && CompConstant >= 0 &&
CompConstant < AddConstant + MaxUInt) ||
(AddConstant >= 0 && CompConstant >= 0 &&
CompConstant >= AddConstant) ||
(AddConstant <= 0 && CompConstant < 0 && CompConstant < AddConstant))
-
return true;
- } break;
+ break;
case AArch64CC::VS:
case AArch64CC::VC:
case AArch64CC::AL:
@@ -9862,7 +10190,7 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
case ISD::FP_TO_UINT:
return performFpToIntCombine(N, DAG, DCI, Subtarget);
case ISD::FDIV:
- return performFDivCombine(N, DAG, Subtarget);
+ return performFDivCombine(N, DAG, DCI, Subtarget);
case ISD::OR:
return performORCombine(N, DCI, Subtarget);
case ISD::SRL:
@@ -9995,8 +10323,10 @@ bool AArch64TargetLowering::getIndexedAddressParts(SDNode *Op, SDValue &Base,
// All of the indexed addressing mode instructions take a signed
// 9 bit immediate offset.
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
- int64_t RHSC = (int64_t)RHS->getZExtValue();
- if (RHSC >= 256 || RHSC <= -256)
+ int64_t RHSC = RHS->getSExtValue();
+ if (Op->getOpcode() == ISD::SUB)
+ RHSC = -(uint64_t)RHSC;
+ if (!isInt<9>(RHSC))
return false;
IsInc = (Op->getOpcode() == ISD::ADD);
Offset = Op->getOperand(1);
@@ -10222,7 +10552,7 @@ Value *AArch64TargetLowering::emitLoadLinked(IRBuilder<> &Builder, Value *Addr,
if (ValTy->getPrimitiveSizeInBits() == 128) {
Intrinsic::ID Int =
IsAcquire ? Intrinsic::aarch64_ldaxp : Intrinsic::aarch64_ldxp;
- Function *Ldxr = llvm::Intrinsic::getDeclaration(M, Int);
+ Function *Ldxr = Intrinsic::getDeclaration(M, Int);
Addr = Builder.CreateBitCast(Addr, Type::getInt8PtrTy(M->getContext()));
Value *LoHi = Builder.CreateCall(Ldxr, Addr, "lohi");
@@ -10238,7 +10568,7 @@ Value *AArch64TargetLowering::emitLoadLinked(IRBuilder<> &Builder, Value *Addr,
Type *Tys[] = { Addr->getType() };
Intrinsic::ID Int =
IsAcquire ? Intrinsic::aarch64_ldaxr : Intrinsic::aarch64_ldxr;
- Function *Ldxr = llvm::Intrinsic::getDeclaration(M, Int, Tys);
+ Function *Ldxr = Intrinsic::getDeclaration(M, Int, Tys);
return Builder.CreateTruncOrBitCast(
Builder.CreateCall(Ldxr, Addr),
@@ -10248,8 +10578,7 @@ Value *AArch64TargetLowering::emitLoadLinked(IRBuilder<> &Builder, Value *Addr,
void AArch64TargetLowering::emitAtomicCmpXchgNoStoreLLBalance(
IRBuilder<> &Builder) const {
Module *M = Builder.GetInsertBlock()->getParent()->getParent();
- Builder.CreateCall(
- llvm::Intrinsic::getDeclaration(M, Intrinsic::aarch64_clrex));
+ Builder.CreateCall(Intrinsic::getDeclaration(M, Intrinsic::aarch64_clrex));
}
Value *AArch64TargetLowering::emitStoreConditional(IRBuilder<> &Builder,
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index c87cfed..054ccc3 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -187,9 +187,9 @@ enum NodeType : unsigned {
SMULL,
UMULL,
- // Reciprocal estimates.
- FRECPE,
- FRSQRTE,
+ // Reciprocal estimates and steps.
+ FRECPE, FRECPS,
+ FRSQRTE, FRSQRTS,
// NEON Load/Store with post-increment base updates
LD2post = ISD::FIRST_TARGET_MEMORY_OPCODE,
@@ -219,6 +219,21 @@ enum NodeType : unsigned {
} // end namespace AArch64ISD
+namespace {
+
+// Any instruction that defines a 32-bit result zeros out the high half of the
+// register. Truncate can be lowered to EXTRACT_SUBREG. CopyFromReg may
+// be copying from a truncate. But any other 32-bit operation will zero-extend
+// up to 64 bits.
+// FIXME: X86 also checks for CMOV here. Do we need something similar?
+static inline bool isDef32(const SDNode &N) {
+ unsigned Opc = N.getOpcode();
+ return Opc != ISD::TRUNCATE && Opc != TargetOpcode::EXTRACT_SUBREG &&
+ Opc != ISD::CopyFromReg;
+}
+
+} // end anonymous namespace
+
class AArch64Subtarget;
class AArch64TargetMachine;
@@ -230,6 +245,9 @@ public:
/// Selects the correct CCAssignFn for a given CallingConvention value.
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const;
+ /// Selects the correct CCAssignFn for a given CallingConvention value.
+ CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC) const;
+
/// Determine which of the bits specified in Mask are known to be either zero
/// or one and return them in the KnownZero/KnownOne bitsets.
void computeKnownBitsForTargetNode(const SDValue Op, APInt &KnownZero,
@@ -295,8 +313,6 @@ public:
bool isZExtFree(EVT VT1, EVT VT2) const override;
bool isZExtFree(SDValue Val, EVT VT2) const override;
- bool hasPairedLoad(Type *LoadedType,
- unsigned &RequiredAligment) const override;
bool hasPairedLoad(EVT LoadedType, unsigned &RequiredAligment) const override;
unsigned getMaxSupportedInterleaveFactor() const override { return 4; }
@@ -396,6 +412,11 @@ public:
return true;
}
+ bool hasAndNotCompare(SDValue) const override {
+ // 'bics'
+ return true;
+ }
+
bool hasBitPreservingFPLogic(EVT VT) const override {
// FIXME: Is this always true? It should be true for vectors at least.
return VT == MVT::f32 || VT == MVT::f64;
@@ -453,12 +474,10 @@ private:
/// object and incorporates their load into the current chain. This prevents
/// an upcoming store from clobbering the stack argument before it's used.
SDValue addTokenForArgument(SDValue Chain, SelectionDAG &DAG,
- MachineFrameInfo *MFI, int ClobberedFI) const;
+ MachineFrameInfo &MFI, int ClobberedFI) const;
bool DoesCalleeRestoreStack(CallingConv::ID CallCC, bool TailCallOpt) const;
- bool IsTailCallConvention(CallingConv::ID CallCC) const;
-
void saveVarArgRegisters(CCState &CCInfo, SelectionDAG &DAG, const SDLoc &DL,
SDValue &Chain) const;
@@ -520,11 +539,11 @@ private:
SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG,
std::vector<SDNode *> *Created) const override;
- SDValue getRsqrtEstimate(SDValue Operand, DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const override;
- SDValue getRecipEstimate(SDValue Operand, DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const override;
+ SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &ExtraSteps, bool &UseOneConst,
+ bool Reciprocal) const override;
+ SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &ExtraSteps) const override;
unsigned combineRepeatedFPDivisors() const override;
ConstraintType getConstraintType(StringRef Constraint) const override;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td b/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td
index 59de62a..867074c 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td
@@ -377,28 +377,28 @@ def : Pat<(int_aarch64_clrex), (CLREX 0xf)>;
// significantly more naive than the standard expansion: we conservatively
// assume seq_cst, strong cmpxchg and omit clrex on failure.
-let Constraints = "@earlyclobber $Rd,@earlyclobber $status",
+let Constraints = "@earlyclobber $Rd,@earlyclobber $scratch",
mayLoad = 1, mayStore = 1 in {
-def CMP_SWAP_8 : Pseudo<(outs GPR32:$Rd, GPR32:$status),
+def CMP_SWAP_8 : Pseudo<(outs GPR32:$Rd, GPR32:$scratch),
(ins GPR64:$addr, GPR32:$desired, GPR32:$new), []>,
Sched<[WriteAtomic]>;
-def CMP_SWAP_16 : Pseudo<(outs GPR32:$Rd, GPR32:$status),
+def CMP_SWAP_16 : Pseudo<(outs GPR32:$Rd, GPR32:$scratch),
(ins GPR64:$addr, GPR32:$desired, GPR32:$new), []>,
Sched<[WriteAtomic]>;
-def CMP_SWAP_32 : Pseudo<(outs GPR32:$Rd, GPR32:$status),
+def CMP_SWAP_32 : Pseudo<(outs GPR32:$Rd, GPR32:$scratch),
(ins GPR64:$addr, GPR32:$desired, GPR32:$new), []>,
Sched<[WriteAtomic]>;
-def CMP_SWAP_64 : Pseudo<(outs GPR64:$Rd, GPR32:$status),
+def CMP_SWAP_64 : Pseudo<(outs GPR64:$Rd, GPR32:$scratch),
(ins GPR64:$addr, GPR64:$desired, GPR64:$new), []>,
Sched<[WriteAtomic]>;
}
-let Constraints = "@earlyclobber $RdLo,@earlyclobber $RdHi,@earlyclobber $status",
+let Constraints = "@earlyclobber $RdLo,@earlyclobber $RdHi,@earlyclobber $scratch",
mayLoad = 1, mayStore = 1 in
-def CMP_SWAP_128 : Pseudo<(outs GPR64:$RdLo, GPR64:$RdHi, GPR32:$status),
+def CMP_SWAP_128 : Pseudo<(outs GPR64:$RdLo, GPR64:$RdHi, GPR32:$scratch),
(ins GPR64:$addr, GPR64:$desiredLo, GPR64:$desiredHi,
GPR64:$newLo, GPR64:$newHi), []>,
Sched<[WriteAtomic]>;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/contrib/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 34d35e9..cefdf51 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -3936,27 +3936,27 @@ class BaseFPConversion<bits<2> type, bits<2> opcode, RegisterClass dstType,
multiclass FPConversion<string asm> {
// Double-precision to Half-precision
def HDr : BaseFPConversion<0b01, 0b11, FPR16, FPR64, asm,
- [(set FPR16:$Rd, (fround FPR64:$Rn))]>;
+ [(set FPR16:$Rd, (fpround FPR64:$Rn))]>;
// Double-precision to Single-precision
def SDr : BaseFPConversion<0b01, 0b00, FPR32, FPR64, asm,
- [(set FPR32:$Rd, (fround FPR64:$Rn))]>;
+ [(set FPR32:$Rd, (fpround FPR64:$Rn))]>;
// Half-precision to Double-precision
def DHr : BaseFPConversion<0b11, 0b01, FPR64, FPR16, asm,
- [(set FPR64:$Rd, (fextend FPR16:$Rn))]>;
+ [(set FPR64:$Rd, (fpextend FPR16:$Rn))]>;
// Half-precision to Single-precision
def SHr : BaseFPConversion<0b11, 0b00, FPR32, FPR16, asm,
- [(set FPR32:$Rd, (fextend FPR16:$Rn))]>;
+ [(set FPR32:$Rd, (fpextend FPR16:$Rn))]>;
// Single-precision to Double-precision
def DSr : BaseFPConversion<0b00, 0b01, FPR64, FPR32, asm,
- [(set FPR64:$Rd, (fextend FPR32:$Rn))]>;
+ [(set FPR64:$Rd, (fpextend FPR32:$Rn))]>;
// Single-precision to Half-precision
def HSr : BaseFPConversion<0b00, 0b11, FPR16, FPR32, asm,
- [(set FPR16:$Rd, (fround FPR32:$Rn))]>;
+ [(set FPR16:$Rd, (fpround FPR32:$Rn))]>;
}
//---
@@ -9348,7 +9348,7 @@ class SHAInstSS<bits<4> opc, string asm, Intrinsic OpNode>
// ST<OP>{<order>}[<size>] <Ws>, [<Xn|SP>]
// ST<OP>{<order>} <Xs>, [<Xn|SP>]
-let Predicates = [HasV8_1a], mayLoad = 1, mayStore = 1, hasSideEffects = 1 in
+let Predicates = [HasLSE], mayLoad = 1, mayStore = 1, hasSideEffects = 1 in
class BaseCASEncoding<dag oops, dag iops, string asm, string operands,
string cstr, list<dag> pattern>
: I<oops, iops, asm, operands, cstr, pattern> {
@@ -9369,6 +9369,7 @@ class BaseCASEncoding<dag oops, dag iops, string asm, string operands,
let Inst{14-10} = 0b11111;
let Inst{9-5} = Rn;
let Inst{4-0} = Rt;
+ let Predicates = [HasLSE];
}
class BaseCAS<string order, string size, RegisterClass RC>
@@ -9401,7 +9402,7 @@ multiclass CompareAndSwapPair<bits<1> Acq, bits<1> Rel, string order> {
def d : BaseCASP<order, "", XSeqPairClassOperand>;
}
-let Predicates = [HasV8_1a] in
+let Predicates = [HasLSE] in
class BaseSWP<string order, string size, RegisterClass RC>
: I<(outs RC:$Rt),(ins RC:$Rs, GPR64sp:$Rn), "swp" # order # size,
"\t$Rs, $Rt, [$Rn]","",[]>,
@@ -9424,6 +9425,7 @@ class BaseSWP<string order, string size, RegisterClass RC>
let Inst{11-10} = 0b00;
let Inst{9-5} = Rn;
let Inst{4-0} = Rt;
+ let Predicates = [HasLSE];
}
multiclass Swap<bits<1> Acq, bits<1> Rel, string order> {
@@ -9433,7 +9435,7 @@ multiclass Swap<bits<1> Acq, bits<1> Rel, string order> {
let Sz = 0b11, Acq = Acq, Rel = Rel in def d : BaseSWP<order, "", GPR64>;
}
-let Predicates = [HasV8_1a], mayLoad = 1, mayStore = 1, hasSideEffects = 1 in
+let Predicates = [HasLSE], mayLoad = 1, mayStore = 1, hasSideEffects = 1 in
class BaseLDOPregister<string op, string order, string size, RegisterClass RC>
: I<(outs RC:$Rt),(ins RC:$Rs, GPR64sp:$Rn), "ld" # op # order # size,
"\t$Rs, $Rt, [$Rn]","",[]>,
@@ -9456,6 +9458,7 @@ class BaseLDOPregister<string op, string order, string size, RegisterClass RC>
let Inst{11-10} = 0b00;
let Inst{9-5} = Rn;
let Inst{4-0} = Rt;
+ let Predicates = [HasLSE];
}
multiclass LDOPregister<bits<3> opc, string op, bits<1> Acq, bits<1> Rel,
@@ -9470,7 +9473,7 @@ multiclass LDOPregister<bits<3> opc, string op, bits<1> Acq, bits<1> Rel,
def d : BaseLDOPregister<op, order, "", GPR64>;
}
-let Predicates = [HasV8_1a] in
+let Predicates = [HasLSE] in
class BaseSTOPregister<string asm, RegisterClass OP, Register Reg,
Instruction inst> :
InstAlias<asm # "\t$Rs, [$Rn]", (inst Reg, OP:$Rs, GPR64sp:$Rn)>;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index d39542a..4c78992 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -14,31 +14,65 @@
#include "AArch64InstrInfo.h"
#include "AArch64Subtarget.h"
#include "MCTargetDesc/AArch64AddressingModes.h"
+#include "Utils/AArch64BaseInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/PseudoSourceValue.h"
+#include "llvm/CodeGen/StackMaps.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/TargetRegistry.h"
-#include <algorithm>
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <utility>
using namespace llvm;
#define GET_INSTRINFO_CTOR_DTOR
#include "AArch64GenInstrInfo.inc"
-static LLVM_CONSTEXPR MachineMemOperand::Flags MOSuppressPair =
+static const MachineMemOperand::Flags MOSuppressPair =
MachineMemOperand::MOTargetFlag1;
+static cl::opt<unsigned>
+TBZDisplacementBits("aarch64-tbz-offset-bits", cl::Hidden, cl::init(14),
+ cl::desc("Restrict range of TB[N]Z instructions (DEBUG)"));
+
+static cl::opt<unsigned>
+CBZDisplacementBits("aarch64-cbz-offset-bits", cl::Hidden, cl::init(19),
+ cl::desc("Restrict range of CB[N]Z instructions (DEBUG)"));
+
+static cl::opt<unsigned>
+BCCDisplacementBits("aarch64-bcc-offset-bits", cl::Hidden, cl::init(19),
+ cl::desc("Restrict range of Bcc instructions (DEBUG)"));
+
AArch64InstrInfo::AArch64InstrInfo(const AArch64Subtarget &STI)
: AArch64GenInstrInfo(AArch64::ADJCALLSTACKDOWN, AArch64::ADJCALLSTACKUP),
RI(STI.getTargetTriple()), Subtarget(STI) {}
/// GetInstSize - Return the number of bytes of code the specified
/// instruction may be. This returns the maximum number of bytes.
-unsigned AArch64InstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
+unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
const MachineBasicBlock &MBB = *MI.getParent();
const MachineFunction *MF = MBB.getParent();
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
@@ -46,22 +80,38 @@ unsigned AArch64InstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
if (MI.getOpcode() == AArch64::INLINEASM)
return getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
+ // FIXME: We currently only handle pseudoinstructions that don't get expanded
+ // before the assembly printer.
+ unsigned NumBytes = 0;
const MCInstrDesc &Desc = MI.getDesc();
switch (Desc.getOpcode()) {
default:
- // Anything not explicitly designated otherwise is a nomal 4-byte insn.
- return 4;
+ // Anything not explicitly designated otherwise is a normal 4-byte insn.
+ NumBytes = 4;
+ break;
case TargetOpcode::DBG_VALUE:
case TargetOpcode::EH_LABEL:
case TargetOpcode::IMPLICIT_DEF:
case TargetOpcode::KILL:
- return 0;
+ NumBytes = 0;
+ break;
+ case TargetOpcode::STACKMAP:
+ // The upper bound for a stackmap intrinsic is the full length of its shadow
+ NumBytes = StackMapOpers(&MI).getNumPatchBytes();
+ assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
+ break;
+ case TargetOpcode::PATCHPOINT:
+ // The size of the patchpoint intrinsic is the number of bytes requested
+ NumBytes = PatchPointOpers(&MI).getNumPatchBytes();
+ assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
+ break;
case AArch64::TLSDESC_CALLSEQ:
// This gets lowered to an instruction sequence which takes 16 bytes
- return 16;
+ NumBytes = 16;
+ break;
}
- llvm_unreachable("GetInstSizeInBytes()- Unable to determin insn size");
+ return NumBytes;
}
static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
@@ -95,6 +145,56 @@ static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
}
}
+static unsigned getBranchDisplacementBits(unsigned Opc) {
+ switch (Opc) {
+ default:
+ llvm_unreachable("unexpected opcode!");
+ case AArch64::B:
+ return 64;
+ case AArch64::TBNZW:
+ case AArch64::TBZW:
+ case AArch64::TBNZX:
+ case AArch64::TBZX:
+ return TBZDisplacementBits;
+ case AArch64::CBNZW:
+ case AArch64::CBZW:
+ case AArch64::CBNZX:
+ case AArch64::CBZX:
+ return CBZDisplacementBits;
+ case AArch64::Bcc:
+ return BCCDisplacementBits;
+ }
+}
+
+bool AArch64InstrInfo::isBranchOffsetInRange(unsigned BranchOp,
+ int64_t BrOffset) const {
+ unsigned Bits = getBranchDisplacementBits(BranchOp);
+ assert(Bits >= 3 && "max branch displacement must be enough to jump"
+ "over conditional branch expansion");
+ return isIntN(Bits, BrOffset / 4);
+}
+
+MachineBasicBlock *AArch64InstrInfo::getBranchDestBlock(
+ const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
+ default:
+ llvm_unreachable("unexpected opcode!");
+ case AArch64::B:
+ return MI.getOperand(0).getMBB();
+ case AArch64::TBZW:
+ case AArch64::TBNZW:
+ case AArch64::TBZX:
+ case AArch64::TBNZX:
+ return MI.getOperand(2).getMBB();
+ case AArch64::CBZW:
+ case AArch64::CBNZW:
+ case AArch64::CBZX:
+ case AArch64::CBNZX:
+ case AArch64::Bcc:
+ return MI.getOperand(1).getMBB();
+ }
+}
+
// Branch analysis.
bool AArch64InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
@@ -183,7 +283,7 @@ bool AArch64InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}
-bool AArch64InstrInfo::ReverseBranchCondition(
+bool AArch64InstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
if (Cond[0].getImm() != -1) {
// Regular Bcc
@@ -224,7 +324,8 @@ bool AArch64InstrInfo::ReverseBranchCondition(
return false;
}
-unsigned AArch64InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned AArch64InstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end())
return 0;
@@ -238,14 +339,23 @@ unsigned AArch64InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
I = MBB.end();
- if (I == MBB.begin())
+ if (I == MBB.begin()) {
+ if (BytesRemoved)
+ *BytesRemoved = 4;
return 1;
+ }
--I;
- if (!isCondBranchOpcode(I->getOpcode()))
+ if (!isCondBranchOpcode(I->getOpcode())) {
+ if (BytesRemoved)
+ *BytesRemoved = 4;
return 1;
+ }
// Remove the branch.
I->eraseFromParent();
+ if (BytesRemoved)
+ *BytesRemoved = 8;
+
return 2;
}
@@ -266,25 +376,34 @@ void AArch64InstrInfo::instantiateCondBranch(
}
}
-unsigned AArch64InstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned AArch64InstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
if (!FBB) {
if (Cond.empty()) // Unconditional branch?
BuildMI(&MBB, DL, get(AArch64::B)).addMBB(TBB);
else
instantiateCondBranch(MBB, DL, TBB, Cond);
+
+ if (BytesAdded)
+ *BytesAdded = 4;
+
return 1;
}
// Two-way conditional branch.
instantiateCondBranch(MBB, DL, TBB, Cond);
BuildMI(&MBB, DL, get(AArch64::B)).addMBB(FBB);
+
+ if (BytesAdded)
+ *BytesAdded = 8;
+
return 2;
}
@@ -318,7 +437,8 @@ static unsigned canFoldIntoCSel(const MachineRegisterInfo &MRI, unsigned VReg,
// if NZCV is used, do not fold.
if (DefMI->findRegisterDefOperandIdx(AArch64::NZCV, true) == -1)
return 0;
- // fall-through to ADDXri and ADDWri.
+ // fall-through to ADDXri and ADDWri.
+ LLVM_FALLTHROUGH;
case AArch64::ADDXri:
case AArch64::ADDWri:
// add x, 1 -> csinc.
@@ -345,7 +465,8 @@ static unsigned canFoldIntoCSel(const MachineRegisterInfo &MRI, unsigned VReg,
// if NZCV is used, do not fold.
if (DefMI->findRegisterDefOperandIdx(AArch64::NZCV, true) == -1)
return 0;
- // fall-through to SUBXrr and SUBWrr.
+ // fall-through to SUBXrr and SUBWrr.
+ LLVM_FALLTHROUGH;
case AArch64::SUBXrr:
case AArch64::SUBWrr: {
// neg x -> csneg, represented as sub dst, xzr, src.
@@ -429,19 +550,19 @@ void AArch64InstrInfo::insertSelect(MachineBasicBlock &MBB,
default:
llvm_unreachable("Unknown branch opcode in Cond");
case AArch64::CBZW:
- Is64Bit = 0;
+ Is64Bit = false;
CC = AArch64CC::EQ;
break;
case AArch64::CBZX:
- Is64Bit = 1;
+ Is64Bit = true;
CC = AArch64CC::EQ;
break;
case AArch64::CBNZW:
- Is64Bit = 0;
+ Is64Bit = false;
CC = AArch64CC::NE;
break;
case AArch64::CBNZX:
- Is64Bit = 1;
+ Is64Bit = true;
CC = AArch64CC::NE;
break;
}
@@ -861,9 +982,9 @@ static bool areCFlagsAccessedBetweenInstrs(
return true;
// From must be above To.
- assert(std::find_if(MachineBasicBlock::reverse_iterator(To),
- To->getParent()->rend(), [From](MachineInstr &MI) {
- return MachineBasicBlock::iterator(MI) == From;
+ assert(std::find_if(++To.getReverse(), To->getParent()->rend(),
+ [From](MachineInstr &MI) {
+ return MI.getIterator() == From;
}) != To->getParent()->rend());
// We iterate backward starting \p To until we hit \p From.
@@ -944,7 +1065,7 @@ static unsigned sForm(MachineInstr &Instr) {
case AArch64::SUBSWri:
case AArch64::SUBSXrr:
case AArch64::SUBSXri:
- return Instr.getOpcode();;
+ return Instr.getOpcode();
case AArch64::ADDWrr: return AArch64::ADDSWrr;
case AArch64::ADDWri: return AArch64::ADDSWri;
@@ -971,12 +1092,16 @@ static bool areCFlagsAliveInSuccessors(MachineBasicBlock *MBB) {
return false;
}
+namespace {
+
struct UsedNZCV {
- bool N;
- bool Z;
- bool C;
- bool V;
- UsedNZCV(): N(false), Z(false), C(false), V(false) {}
+ bool N = false;
+ bool Z = false;
+ bool C = false;
+ bool V = false;
+
+ UsedNZCV() = default;
+
UsedNZCV& operator |=(const UsedNZCV& UsedFlags) {
this->N |= UsedFlags.N;
this->Z |= UsedFlags.Z;
@@ -986,6 +1111,8 @@ struct UsedNZCV {
}
};
+} // end anonymous namespace
+
/// Find a condition code used by the instruction.
/// Returns AArch64CC::Invalid if either the instruction does not use condition
/// codes or we don't optimize CmpInstr in the presence of such instructions.
@@ -1459,7 +1586,7 @@ bool AArch64InstrInfo::isScaledAddr(const MachineInstr &MI) const {
/// Check all MachineMemOperands for a hint to suppress pairing.
bool AArch64InstrInfo::isLdStPairSuppressed(const MachineInstr &MI) const {
- return any_of(MI.memoperands(), [](MachineMemOperand *MMO) {
+ return llvm::any_of(MI.memoperands(), [](MachineMemOperand *MMO) {
return MMO->getFlags() & MOSuppressPair;
});
}
@@ -1525,11 +1652,10 @@ bool AArch64InstrInfo::isCandidateToMergeOrPair(MachineInstr &MI) const {
return false;
// On some CPUs quad load/store pairs are slower than two single load/stores.
- if (Subtarget.avoidQuadLdStPairs()) {
+ if (Subtarget.isPaired128Slow()) {
switch (MI.getOpcode()) {
default:
break;
-
case AArch64::LDURQi:
case AArch64::STURQi:
case AArch64::LDRQui:
@@ -1544,36 +1670,8 @@ bool AArch64InstrInfo::isCandidateToMergeOrPair(MachineInstr &MI) const {
bool AArch64InstrInfo::getMemOpBaseRegImmOfs(
MachineInstr &LdSt, unsigned &BaseReg, int64_t &Offset,
const TargetRegisterInfo *TRI) const {
- switch (LdSt.getOpcode()) {
- default:
- return false;
- // Scaled instructions.
- case AArch64::STRSui:
- case AArch64::STRDui:
- case AArch64::STRQui:
- case AArch64::STRXui:
- case AArch64::STRWui:
- case AArch64::LDRSui:
- case AArch64::LDRDui:
- case AArch64::LDRQui:
- case AArch64::LDRXui:
- case AArch64::LDRWui:
- case AArch64::LDRSWui:
- // Unscaled instructions.
- case AArch64::STURSi:
- case AArch64::STURDi:
- case AArch64::STURQi:
- case AArch64::STURXi:
- case AArch64::STURWi:
- case AArch64::LDURSi:
- case AArch64::LDURDi:
- case AArch64::LDURQi:
- case AArch64::LDURWi:
- case AArch64::LDURXi:
- case AArch64::LDURSWi:
- unsigned Width;
- return getMemOpBaseRegImmOfsWidth(LdSt, BaseReg, Offset, Width, TRI);
- };
+ unsigned Width;
+ return getMemOpBaseRegImmOfsWidth(LdSt, BaseReg, Offset, Width, TRI);
}
bool AArch64InstrInfo::getMemOpBaseRegImmOfsWidth(
@@ -1772,6 +1870,9 @@ bool AArch64InstrInfo::shouldClusterMemOps(MachineInstr &FirstLdSt,
if (NumLoads > 1)
return false;
+ if (!isPairableLdStInst(FirstLdSt) || !isPairableLdStInst(SecondLdSt))
+ return false;
+
// Can we pair these instructions based on their opcodes?
unsigned FirstOpc = FirstLdSt.getOpcode();
unsigned SecondOpc = SecondLdSt.getOpcode();
@@ -1802,41 +1903,82 @@ bool AArch64InstrInfo::shouldClusterMemOps(MachineInstr &FirstLdSt,
return Offset1 + 1 == Offset2;
}
-bool AArch64InstrInfo::shouldScheduleAdjacent(MachineInstr &First,
- MachineInstr &Second) const {
- if (Subtarget.hasMacroOpFusion()) {
+bool AArch64InstrInfo::shouldScheduleAdjacent(
+ const MachineInstr &First, const MachineInstr &Second) const {
+ if (Subtarget.hasArithmeticBccFusion()) {
// Fuse CMN, CMP, TST followed by Bcc.
unsigned SecondOpcode = Second.getOpcode();
if (SecondOpcode == AArch64::Bcc) {
switch (First.getOpcode()) {
default:
return false;
- case AArch64::SUBSWri:
case AArch64::ADDSWri:
- case AArch64::ANDSWri:
- case AArch64::SUBSXri:
+ case AArch64::ADDSWrr:
case AArch64::ADDSXri:
+ case AArch64::ADDSXrr:
+ case AArch64::ANDSWri:
+ case AArch64::ANDSWrr:
case AArch64::ANDSXri:
+ case AArch64::ANDSXrr:
+ case AArch64::SUBSWri:
+ case AArch64::SUBSWrr:
+ case AArch64::SUBSXri:
+ case AArch64::SUBSXrr:
+ case AArch64::BICSWrr:
+ case AArch64::BICSXrr:
return true;
+ case AArch64::ADDSWrs:
+ case AArch64::ADDSXrs:
+ case AArch64::ANDSWrs:
+ case AArch64::ANDSXrs:
+ case AArch64::SUBSWrs:
+ case AArch64::SUBSXrs:
+ case AArch64::BICSWrs:
+ case AArch64::BICSXrs:
+ // Shift value can be 0 making these behave like the "rr" variant...
+ return !hasShiftedReg(Second);
}
}
+ }
+ if (Subtarget.hasArithmeticCbzFusion()) {
// Fuse ALU operations followed by CBZ/CBNZ.
+ unsigned SecondOpcode = Second.getOpcode();
if (SecondOpcode == AArch64::CBNZW || SecondOpcode == AArch64::CBNZX ||
SecondOpcode == AArch64::CBZW || SecondOpcode == AArch64::CBZX) {
switch (First.getOpcode()) {
default:
return false;
case AArch64::ADDWri:
+ case AArch64::ADDWrr:
case AArch64::ADDXri:
+ case AArch64::ADDXrr:
case AArch64::ANDWri:
+ case AArch64::ANDWrr:
case AArch64::ANDXri:
+ case AArch64::ANDXrr:
case AArch64::EORWri:
+ case AArch64::EORWrr:
case AArch64::EORXri:
+ case AArch64::EORXrr:
case AArch64::ORRWri:
+ case AArch64::ORRWrr:
case AArch64::ORRXri:
+ case AArch64::ORRXrr:
case AArch64::SUBWri:
+ case AArch64::SUBWrr:
case AArch64::SUBXri:
+ case AArch64::SUBXrr:
return true;
+ case AArch64::ADDWrs:
+ case AArch64::ADDXrs:
+ case AArch64::ANDWrs:
+ case AArch64::ANDXrs:
+ case AArch64::SUBWrs:
+ case AArch64::SUBXrs:
+ case AArch64::BICWrs:
+ case AArch64::BICXrs:
+ // Shift value can be 0 making these behave like the "rr" variant...
+ return !hasShiftedReg(Second);
}
}
}
@@ -1877,7 +2019,7 @@ static bool forwardCopyWillClobberTuple(unsigned DestReg, unsigned SrcReg,
void AArch64InstrInfo::copyPhysRegTuple(
MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL,
unsigned DestReg, unsigned SrcReg, bool KillSrc, unsigned Opcode,
- llvm::ArrayRef<unsigned> Indices) const {
+ ArrayRef<unsigned> Indices) const {
assert(Subtarget.hasNEON() &&
"Unexpected register copy without NEON");
const TargetRegisterInfo *TRI = &getRegisterInfo();
@@ -2189,7 +2331,7 @@ void AArch64InstrInfo::storeRegToStackSlot(
if (MBBI != MBB.end())
DL = MBBI->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, FI);
@@ -2293,7 +2435,7 @@ void AArch64InstrInfo::loadRegFromStackSlot(
if (MBBI != MBB.end())
DL = MBBI->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, FI);
MachineMemOperand *MMO = MF.getMachineMemOperand(
@@ -2466,7 +2608,7 @@ MachineInstr *AArch64InstrInfo::foldMemoryOperandImpl(
//
// <rdar://problem/11522048>
//
- if (MI.isCopy()) {
+ if (MI.isFullCopy()) {
unsigned DstReg = MI.getOperand(0).getReg();
unsigned SrcReg = MI.getOperand(1).getReg();
if (SrcReg == AArch64::SP &&
@@ -2481,6 +2623,150 @@ MachineInstr *AArch64InstrInfo::foldMemoryOperandImpl(
}
}
+ // Handle the case where a copy is being spilled or filled but the source
+ // and destination register class don't match. For example:
+ //
+ // %vreg0<def> = COPY %XZR; GPR64common:%vreg0
+ //
+ // In this case we can still safely fold away the COPY and generate the
+ // following spill code:
+ //
+ // STRXui %XZR, <fi#0>
+ //
+ // This also eliminates spilled cross register class COPYs (e.g. between x and
+ // d regs) of the same size. For example:
+ //
+ // %vreg0<def> = COPY %vreg1; GPR64:%vreg0, FPR64:%vreg1
+ //
+ // will be filled as
+ //
+ // LDRDui %vreg0, fi<#0>
+ //
+ // instead of
+ //
+ // LDRXui %vregTemp, fi<#0>
+ // %vreg0 = FMOV %vregTemp
+ //
+ if (MI.isCopy() && Ops.size() == 1 &&
+ // Make sure we're only folding the explicit COPY defs/uses.
+ (Ops[0] == 0 || Ops[0] == 1)) {
+ bool IsSpill = Ops[0] == 0;
+ bool IsFill = !IsSpill;
+ const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+ MachineBasicBlock &MBB = *MI.getParent();
+ const MachineOperand &DstMO = MI.getOperand(0);
+ const MachineOperand &SrcMO = MI.getOperand(1);
+ unsigned DstReg = DstMO.getReg();
+ unsigned SrcReg = SrcMO.getReg();
+ // This is slightly expensive to compute for physical regs since
+ // getMinimalPhysRegClass is slow.
+ auto getRegClass = [&](unsigned Reg) {
+ return TargetRegisterInfo::isVirtualRegister(Reg)
+ ? MRI.getRegClass(Reg)
+ : TRI.getMinimalPhysRegClass(Reg);
+ };
+
+ if (DstMO.getSubReg() == 0 && SrcMO.getSubReg() == 0) {
+ assert(getRegClass(DstReg)->getSize() == getRegClass(SrcReg)->getSize() &&
+ "Mismatched register size in non subreg COPY");
+ if (IsSpill)
+ storeRegToStackSlot(MBB, InsertPt, SrcReg, SrcMO.isKill(), FrameIndex,
+ getRegClass(SrcReg), &TRI);
+ else
+ loadRegFromStackSlot(MBB, InsertPt, DstReg, FrameIndex,
+ getRegClass(DstReg), &TRI);
+ return &*--InsertPt;
+ }
+
+ // Handle cases like spilling def of:
+ //
+ // %vreg0:sub_32<def,read-undef> = COPY %WZR; GPR64common:%vreg0
+ //
+ // where the physical register source can be widened and stored to the full
+ // virtual reg destination stack slot, in this case producing:
+ //
+ // STRXui %XZR, <fi#0>
+ //
+ if (IsSpill && DstMO.isUndef() &&
+ TargetRegisterInfo::isPhysicalRegister(SrcReg)) {
+ assert(SrcMO.getSubReg() == 0 &&
+ "Unexpected subreg on physical register");
+ const TargetRegisterClass *SpillRC;
+ unsigned SpillSubreg;
+ switch (DstMO.getSubReg()) {
+ default:
+ SpillRC = nullptr;
+ break;
+ case AArch64::sub_32:
+ case AArch64::ssub:
+ if (AArch64::GPR32RegClass.contains(SrcReg)) {
+ SpillRC = &AArch64::GPR64RegClass;
+ SpillSubreg = AArch64::sub_32;
+ } else if (AArch64::FPR32RegClass.contains(SrcReg)) {
+ SpillRC = &AArch64::FPR64RegClass;
+ SpillSubreg = AArch64::ssub;
+ } else
+ SpillRC = nullptr;
+ break;
+ case AArch64::dsub:
+ if (AArch64::FPR64RegClass.contains(SrcReg)) {
+ SpillRC = &AArch64::FPR128RegClass;
+ SpillSubreg = AArch64::dsub;
+ } else
+ SpillRC = nullptr;
+ break;
+ }
+
+ if (SpillRC)
+ if (unsigned WidenedSrcReg =
+ TRI.getMatchingSuperReg(SrcReg, SpillSubreg, SpillRC)) {
+ storeRegToStackSlot(MBB, InsertPt, WidenedSrcReg, SrcMO.isKill(),
+ FrameIndex, SpillRC, &TRI);
+ return &*--InsertPt;
+ }
+ }
+
+ // Handle cases like filling use of:
+ //
+ // %vreg0:sub_32<def,read-undef> = COPY %vreg1; GPR64:%vreg0, GPR32:%vreg1
+ //
+ // where we can load the full virtual reg source stack slot, into the subreg
+ // destination, in this case producing:
+ //
+ // LDRWui %vreg0:sub_32<def,read-undef>, <fi#0>
+ //
+ if (IsFill && SrcMO.getSubReg() == 0 && DstMO.isUndef()) {
+ const TargetRegisterClass *FillRC;
+ switch (DstMO.getSubReg()) {
+ default:
+ FillRC = nullptr;
+ break;
+ case AArch64::sub_32:
+ FillRC = &AArch64::GPR32RegClass;
+ break;
+ case AArch64::ssub:
+ FillRC = &AArch64::FPR32RegClass;
+ break;
+ case AArch64::dsub:
+ FillRC = &AArch64::FPR64RegClass;
+ break;
+ }
+
+ if (FillRC) {
+ assert(getRegClass(SrcReg)->getSize() == FillRC->getSize() &&
+ "Mismatched regclass size on folded subreg COPY");
+ loadRegFromStackSlot(MBB, InsertPt, DstReg, FrameIndex, FillRC, &TRI);
+ MachineInstr &LoadMI = *--InsertPt;
+ MachineOperand &LoadDst = LoadMI.getOperand(0);
+ assert(LoadDst.getSubReg() == 0 && "unexpected subreg on fill load");
+ LoadDst.setSubReg(DstMO.getSubReg());
+ LoadDst.setIsUndef();
+ return &LoadMI;
+ }
+ }
+ }
+
// Cannot fold.
return nullptr;
}
@@ -2768,7 +3054,7 @@ bool AArch64InstrInfo::useMachineCombiner() const {
return true;
}
-//
+
// True when Opc sets flag
static bool isCombineInstrSettingFlag(unsigned Opc) {
switch (Opc) {
@@ -2787,7 +3073,7 @@ static bool isCombineInstrSettingFlag(unsigned Opc) {
}
return false;
}
-//
+
// 32b Opcodes that can be combined with a MUL
static bool isCombineInstrCandidate32(unsigned Opc) {
switch (Opc) {
@@ -2806,7 +3092,7 @@ static bool isCombineInstrCandidate32(unsigned Opc) {
}
return false;
}
-//
+
// 64b Opcodes that can be combined with a MUL
static bool isCombineInstrCandidate64(unsigned Opc) {
switch (Opc) {
@@ -2825,10 +3111,12 @@ static bool isCombineInstrCandidate64(unsigned Opc) {
}
return false;
}
-//
+
// FP Opcodes that can be combined with a FMUL
static bool isCombineInstrCandidateFP(const MachineInstr &Inst) {
switch (Inst.getOpcode()) {
+ default:
+ break;
case AArch64::FADDSrr:
case AArch64::FADDDrr:
case AArch64::FADDv2f32:
@@ -2839,13 +3127,13 @@ static bool isCombineInstrCandidateFP(const MachineInstr &Inst) {
case AArch64::FSUBv2f32:
case AArch64::FSUBv2f64:
case AArch64::FSUBv4f32:
- return Inst.getParent()->getParent()->getTarget().Options.UnsafeFPMath;
- default:
- break;
+ TargetOptions Options = Inst.getParent()->getParent()->getTarget().Options;
+ return (Options.UnsafeFPMath ||
+ Options.AllowFPOpFusion == FPOpFusion::Fast);
}
return false;
}
-//
+
// Opcodes that can be combined with a MUL
static bool isCombineInstrCandidate(unsigned Opc) {
return (isCombineInstrCandidate32(Opc) || isCombineInstrCandidate64(Opc));
@@ -3035,7 +3323,7 @@ static bool getFMAPatterns(MachineInstr &Root,
SmallVectorImpl<MachineCombinerPattern> &Patterns) {
if (!isCombineInstrCandidateFP(Root))
- return 0;
+ return false;
MachineBasicBlock &MBB = *Root.getParent();
bool Found = false;
@@ -3465,7 +3753,7 @@ void AArch64InstrInfo::genAlternativeCodeSequence(
unsigned Val = Root.getOperand(3).getImm();
Imm = Imm << Val;
}
- uint64_t UImm = Imm << (64 - BitSize) >> (64 - BitSize);
+ uint64_t UImm = SignExtend64(Imm, BitSize);
uint64_t Encoding;
if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) {
MachineInstrBuilder MIB1 =
@@ -3551,12 +3839,12 @@ void AArch64InstrInfo::genAlternativeCodeSequence(
RC = &AArch64::GPR64RegClass;
}
unsigned NewVR = MRI.createVirtualRegister(OrrRC);
- int Imm = Root.getOperand(2).getImm();
+ uint64_t Imm = Root.getOperand(2).getImm();
if (Root.getOperand(3).isImm()) {
unsigned Val = Root.getOperand(3).getImm();
Imm = Imm << Val;
}
- uint64_t UImm = -Imm << (64 - BitSize) >> (64 - BitSize);
+ uint64_t UImm = SignExtend64(-Imm, BitSize);
uint64_t Encoding;
if (AArch64_AM::processLogicalImmediate(UImm, BitSize, Encoding)) {
MachineInstrBuilder MIB1 =
@@ -3801,8 +4089,6 @@ void AArch64InstrInfo::genAlternativeCodeSequence(
// Record MUL and ADD/SUB for deletion
DelInstrs.push_back(MUL);
DelInstrs.push_back(&Root);
-
- return;
}
/// \brief Replace csincr-branch sequence by simple conditional branch
@@ -3978,6 +4264,7 @@ AArch64InstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
ArrayRef<std::pair<unsigned, const char *>>
AArch64InstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
using namespace AArch64II;
+
static const std::pair<unsigned, const char *> TargetFlags[] = {
{MO_PAGE, "aarch64-page"},
{MO_PAGEOFF, "aarch64-pageoff"},
@@ -3992,6 +4279,7 @@ AArch64InstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
ArrayRef<std::pair<unsigned, const char *>>
AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
using namespace AArch64II;
+
static const std::pair<unsigned, const char *> TargetFlags[] = {
{MO_GOT, "aarch64-got"},
{MO_NC, "aarch64-nc"},
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h
index 24bc0e6..5037866 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -27,7 +27,7 @@ namespace llvm {
class AArch64Subtarget;
class AArch64TargetMachine;
-class AArch64InstrInfo : public AArch64GenInstrInfo {
+class AArch64InstrInfo final : public AArch64GenInstrInfo {
const AArch64RegisterInfo RI;
const AArch64Subtarget &Subtarget;
@@ -39,7 +39,7 @@ public:
/// always be able to get register info as well (through this method).
const AArch64RegisterInfo &getRegisterInfo() const { return RI; }
- unsigned GetInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
bool isAsCheapAsAMove(const MachineInstr &MI) const override;
@@ -87,6 +87,38 @@ public:
/// Return true if this is an unscaled load/store.
bool isUnscaledLdSt(MachineInstr &MI) const;
+ static bool isPairableLdStInst(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ default:
+ return false;
+ // Scaled instructions.
+ case AArch64::STRSui:
+ case AArch64::STRDui:
+ case AArch64::STRQui:
+ case AArch64::STRXui:
+ case AArch64::STRWui:
+ case AArch64::LDRSui:
+ case AArch64::LDRDui:
+ case AArch64::LDRQui:
+ case AArch64::LDRXui:
+ case AArch64::LDRWui:
+ case AArch64::LDRSWui:
+ // Unscaled instructions.
+ case AArch64::STURSi:
+ case AArch64::STURDi:
+ case AArch64::STURQi:
+ case AArch64::STURWi:
+ case AArch64::STURXi:
+ case AArch64::LDURSi:
+ case AArch64::LDURDi:
+ case AArch64::LDURQi:
+ case AArch64::LDURWi:
+ case AArch64::LDURXi:
+ case AArch64::LDURSWi:
+ return true;
+ }
+ }
+
/// Return true if this is a load/store that can be potentially paired/merged.
bool isCandidateToMergeOrPair(MachineInstr &MI) const;
@@ -101,15 +133,11 @@ public:
int64_t &Offset, unsigned &Width,
const TargetRegisterInfo *TRI) const;
- bool enableClusterLoads() const override { return true; }
-
- bool enableClusterStores() const override { return true; }
-
bool shouldClusterMemOps(MachineInstr &FirstLdSt, MachineInstr &SecondLdSt,
unsigned NumLoads) const override;
- bool shouldScheduleAdjacent(MachineInstr &First,
- MachineInstr &Second) const override;
+ bool shouldScheduleAdjacent(const MachineInstr &First,
+ const MachineInstr &Second) const override;
MachineInstr *emitFrameIndexDebugValue(MachineFunction &MF, int FrameIx,
uint64_t Offset, const MDNode *Var,
@@ -134,6 +162,10 @@ public:
int FrameIndex, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
+ // This tells target independent code that it is okay to pass instructions
+ // with subreg operands to foldMemoryOperandImpl.
+ bool isSubregFoldable() const override { return true; }
+
using TargetInstrInfo::foldMemoryOperandImpl;
MachineInstr *
foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI,
@@ -141,16 +173,25 @@ public:
MachineBasicBlock::iterator InsertPt, int FrameIndex,
LiveIntervals *LIS = nullptr) const override;
+ /// \returns true if a branch from an instruction with opcode \p BranchOpc
+ /// bytes is capable of jumping to a position \p BrOffset bytes away.
+ bool isBranchOffsetInRange(unsigned BranchOpc,
+ int64_t BrOffset) const override;
+
+ MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
+
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
bool canInsertSelect(const MachineBasicBlock &, ArrayRef<MachineOperand> Cond,
unsigned, unsigned, int &, int &, int &) const override;
void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index af9ed81..2244baa 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -26,6 +26,8 @@ def HasCrypto : Predicate<"Subtarget->hasCrypto()">,
AssemblerPredicate<"FeatureCrypto", "crypto">;
def HasCRC : Predicate<"Subtarget->hasCRC()">,
AssemblerPredicate<"FeatureCRC", "crc">;
+def HasLSE : Predicate<"Subtarget->hasLSE()">,
+ AssemblerPredicate<"FeatureLSE", "lse">;
def HasRAS : Predicate<"Subtarget->hasRAS()">,
AssemblerPredicate<"FeatureRAS", "ras">;
def HasPerfMon : Predicate<"Subtarget->hasPerfMon()">;
@@ -287,7 +289,9 @@ def AArch64smull : SDNode<"AArch64ISD::SMULL", SDT_AArch64mull>;
def AArch64umull : SDNode<"AArch64ISD::UMULL", SDT_AArch64mull>;
def AArch64frecpe : SDNode<"AArch64ISD::FRECPE", SDTFPUnaryOp>;
+def AArch64frecps : SDNode<"AArch64ISD::FRECPS", SDTFPBinOp>;
def AArch64frsqrte : SDNode<"AArch64ISD::FRSQRTE", SDTFPUnaryOp>;
+def AArch64frsqrts : SDNode<"AArch64ISD::FRSQRTS", SDTFPBinOp>;
def AArch64saddv : SDNode<"AArch64ISD::SADDV", SDT_AArch64UnaryVec>;
def AArch64uaddv : SDNode<"AArch64ISD::UADDV", SDT_AArch64UnaryVec>;
@@ -947,10 +951,7 @@ def : Pat<(not GPR64:$Xm), (ORNXrr XZR, GPR64:$Xm)>;
defm CLS : OneOperandData<0b101, "cls">;
defm CLZ : OneOperandData<0b100, "clz", ctlz>;
-defm RBIT : OneOperandData<0b000, "rbit">;
-
-def : Pat<(int_aarch64_rbit GPR32:$Rn), (RBITWr $Rn)>;
-def : Pat<(int_aarch64_rbit GPR64:$Rn), (RBITXr $Rn)>;
+defm RBIT : OneOperandData<0b000, "rbit", bitreverse>;
def REV16Wr : OneWRegData<0b001, "rev16",
UnOpFrag<(rotr (bswap node:$LHS), (i64 16))>>;
@@ -1133,6 +1134,14 @@ def : Pat<(AArch64csel (i32 0), (i32 1), (i32 imm:$cc), NZCV),
(CSINCWr WZR, WZR, (i32 imm:$cc))>;
def : Pat<(AArch64csel (i64 0), (i64 1), (i32 imm:$cc), NZCV),
(CSINCXr XZR, XZR, (i32 imm:$cc))>;
+def : Pat<(AArch64csel GPR32:$tval, (i32 1), (i32 imm:$cc), NZCV),
+ (CSINCWr GPR32:$tval, WZR, (i32 imm:$cc))>;
+def : Pat<(AArch64csel GPR64:$tval, (i64 1), (i32 imm:$cc), NZCV),
+ (CSINCXr GPR64:$tval, XZR, (i32 imm:$cc))>;
+def : Pat<(AArch64csel (i32 1), GPR32:$fval, (i32 imm:$cc), NZCV),
+ (CSINCWr GPR32:$fval, WZR, (i32 (inv_cond_XFORM imm:$cc)))>;
+def : Pat<(AArch64csel (i64 1), GPR64:$fval, (i32 imm:$cc), NZCV),
+ (CSINCXr GPR64:$fval, XZR, (i32 (inv_cond_XFORM imm:$cc)))>;
def : Pat<(AArch64csel (i32 0), (i32 -1), (i32 imm:$cc), NZCV),
(CSINVWr WZR, WZR, (i32 imm:$cc))>;
def : Pat<(AArch64csel (i64 0), (i64 -1), (i32 imm:$cc), NZCV),
@@ -2545,8 +2554,8 @@ defm : FPToIntegerPats<fp_to_sint, ffloor, "FCVTMS">;
defm : FPToIntegerPats<fp_to_uint, ffloor, "FCVTMU">;
defm : FPToIntegerPats<fp_to_sint, ftrunc, "FCVTZS">;
defm : FPToIntegerPats<fp_to_uint, ftrunc, "FCVTZU">;
-defm : FPToIntegerPats<fp_to_sint, frnd, "FCVTAS">;
-defm : FPToIntegerPats<fp_to_uint, frnd, "FCVTAU">;
+defm : FPToIntegerPats<fp_to_sint, fround, "FCVTAS">;
+defm : FPToIntegerPats<fp_to_uint, fround, "FCVTAU">;
//===----------------------------------------------------------------------===//
// Scaled integer to floating point conversion instructions.
@@ -2582,7 +2591,7 @@ defm FCVT : FPConversion<"fcvt">;
defm FABS : SingleOperandFPData<0b0001, "fabs", fabs>;
defm FMOV : SingleOperandFPData<0b0000, "fmov">;
defm FNEG : SingleOperandFPData<0b0010, "fneg", fneg>;
-defm FRINTA : SingleOperandFPData<0b1100, "frinta", frnd>;
+defm FRINTA : SingleOperandFPData<0b1100, "frinta", fround>;
defm FRINTI : SingleOperandFPData<0b1111, "frinti", fnearbyint>;
defm FRINTM : SingleOperandFPData<0b1010, "frintm", ffloor>;
defm FRINTN : SingleOperandFPData<0b1000, "frintn", int_aarch64_neon_frintn>;
@@ -2788,13 +2797,13 @@ def : Pat<(v4f32 (int_aarch64_neon_vcvthf2fp (v4i16 V64:$Rn))),
def : Pat<(v4f32 (int_aarch64_neon_vcvthf2fp (extract_subvector (v8i16 V128:$Rn),
(i64 4)))),
(FCVTLv8i16 V128:$Rn)>;
-def : Pat<(v2f64 (fextend (v2f32 V64:$Rn))), (FCVTLv2i32 V64:$Rn)>;
-def : Pat<(v2f64 (fextend (v2f32 (extract_subvector (v4f32 V128:$Rn),
+def : Pat<(v2f64 (fpextend (v2f32 V64:$Rn))), (FCVTLv2i32 V64:$Rn)>;
+def : Pat<(v2f64 (fpextend (v2f32 (extract_subvector (v4f32 V128:$Rn),
(i64 2))))),
(FCVTLv4i32 V128:$Rn)>;
-def : Pat<(v4f32 (fextend (v4f16 V64:$Rn))), (FCVTLv4i16 V64:$Rn)>;
-def : Pat<(v4f32 (fextend (v4f16 (extract_subvector (v8f16 V128:$Rn),
+def : Pat<(v4f32 (fpextend (v4f16 V64:$Rn))), (FCVTLv4i16 V64:$Rn)>;
+def : Pat<(v4f32 (fpextend (v4f16 (extract_subvector (v8f16 V128:$Rn),
(i64 4))))),
(FCVTLv8i16 V128:$Rn)>;
@@ -2808,9 +2817,9 @@ def : Pat<(v4i16 (int_aarch64_neon_vcvtfp2hf (v4f32 V128:$Rn))),
def : Pat<(concat_vectors V64:$Rd,
(v4i16 (int_aarch64_neon_vcvtfp2hf (v4f32 V128:$Rn)))),
(FCVTNv8i16 (INSERT_SUBREG (IMPLICIT_DEF), V64:$Rd, dsub), V128:$Rn)>;
-def : Pat<(v2f32 (fround (v2f64 V128:$Rn))), (FCVTNv2i32 V128:$Rn)>;
-def : Pat<(v4f16 (fround (v4f32 V128:$Rn))), (FCVTNv4i16 V128:$Rn)>;
-def : Pat<(concat_vectors V64:$Rd, (v2f32 (fround (v2f64 V128:$Rn)))),
+def : Pat<(v2f32 (fpround (v2f64 V128:$Rn))), (FCVTNv2i32 V128:$Rn)>;
+def : Pat<(v4f16 (fpround (v4f32 V128:$Rn))), (FCVTNv4i16 V128:$Rn)>;
+def : Pat<(concat_vectors V64:$Rd, (v2f32 (fpround (v2f64 V128:$Rn)))),
(FCVTNv4i32 (INSERT_SUBREG (IMPLICIT_DEF), V64:$Rd, dsub), V128:$Rn)>;
defm FCVTPS : SIMDTwoVectorFPToInt<0,1,0b11010, "fcvtps",int_aarch64_neon_fcvtps>;
defm FCVTPU : SIMDTwoVectorFPToInt<1,1,0b11010, "fcvtpu",int_aarch64_neon_fcvtpu>;
@@ -2833,7 +2842,7 @@ def : Pat<(v2i64 (int_aarch64_neon_fcvtzu v2f64:$Rn)), (FCVTZUv2f64 $Rn)>;
defm FNEG : SIMDTwoVectorFP<1, 1, 0b01111, "fneg", fneg>;
defm FRECPE : SIMDTwoVectorFP<0, 1, 0b11101, "frecpe", int_aarch64_neon_frecpe>;
-defm FRINTA : SIMDTwoVectorFP<1, 0, 0b11000, "frinta", frnd>;
+defm FRINTA : SIMDTwoVectorFP<1, 0, 0b11000, "frinta", fround>;
defm FRINTI : SIMDTwoVectorFP<1, 1, 0b11001, "frinti", fnearbyint>;
defm FRINTM : SIMDTwoVectorFP<0, 0, 0b11001, "frintm", ffloor>;
defm FRINTN : SIMDTwoVectorFP<0, 0, 0b11000, "frintn", int_aarch64_neon_frintn>;
@@ -3414,6 +3423,17 @@ def : Pat<(v1f64 (AArch64frecpe (v1f64 FPR64:$Rn))),
def : Pat<(v2f64 (AArch64frecpe (v2f64 FPR128:$Rn))),
(FRECPEv2f64 FPR128:$Rn)>;
+def : Pat<(f32 (AArch64frecps (f32 FPR32:$Rn), (f32 FPR32:$Rm))),
+ (FRECPS32 FPR32:$Rn, FPR32:$Rm)>;
+def : Pat<(v2f32 (AArch64frecps (v2f32 V64:$Rn), (v2f32 V64:$Rm))),
+ (FRECPSv2f32 V64:$Rn, V64:$Rm)>;
+def : Pat<(v4f32 (AArch64frecps (v4f32 FPR128:$Rn), (v4f32 FPR128:$Rm))),
+ (FRECPSv4f32 FPR128:$Rn, FPR128:$Rm)>;
+def : Pat<(f64 (AArch64frecps (f64 FPR64:$Rn), (f64 FPR64:$Rm))),
+ (FRECPS64 FPR64:$Rn, FPR64:$Rm)>;
+def : Pat<(v2f64 (AArch64frecps (v2f64 FPR128:$Rn), (v2f64 FPR128:$Rm))),
+ (FRECPSv2f64 FPR128:$Rn, FPR128:$Rm)>;
+
def : Pat<(f32 (int_aarch64_neon_frecpx (f32 FPR32:$Rn))),
(FRECPXv1i32 FPR32:$Rn)>;
def : Pat<(f64 (int_aarch64_neon_frecpx (f64 FPR64:$Rn))),
@@ -3439,6 +3459,17 @@ def : Pat<(v1f64 (AArch64frsqrte (v1f64 FPR64:$Rn))),
def : Pat<(v2f64 (AArch64frsqrte (v2f64 FPR128:$Rn))),
(FRSQRTEv2f64 FPR128:$Rn)>;
+def : Pat<(f32 (AArch64frsqrts (f32 FPR32:$Rn), (f32 FPR32:$Rm))),
+ (FRSQRTS32 FPR32:$Rn, FPR32:$Rm)>;
+def : Pat<(v2f32 (AArch64frsqrts (v2f32 V64:$Rn), (v2f32 V64:$Rm))),
+ (FRSQRTSv2f32 V64:$Rn, V64:$Rm)>;
+def : Pat<(v4f32 (AArch64frsqrts (v4f32 FPR128:$Rn), (v4f32 FPR128:$Rm))),
+ (FRSQRTSv4f32 FPR128:$Rn, FPR128:$Rm)>;
+def : Pat<(f64 (AArch64frsqrts (f64 FPR64:$Rn), (f64 FPR64:$Rm))),
+ (FRSQRTS64 FPR64:$Rn, FPR64:$Rm)>;
+def : Pat<(v2f64 (AArch64frsqrts (v2f64 FPR128:$Rn), (v2f64 FPR128:$Rm))),
+ (FRSQRTSv2f64 FPR128:$Rn, FPR128:$Rm)>;
+
// If an integer is about to be converted to a floating point value,
// just load it on the floating point unit.
// Here are the patterns for 8 and 16-bits to float.
@@ -5293,15 +5324,8 @@ def SHA256SU0rr : SHATiedInstVV<0b0010, "sha256su0",int_aarch64_crypto_sha256su0
//----------------------------------------------------------------------------
// FIXME: Like for X86, these should go in their own separate .td file.
-// Any instruction that defines a 32-bit result leaves the high half of the
-// register. Truncate can be lowered to EXTRACT_SUBREG. CopyFromReg may
-// be copying from a truncate. But any other 32-bit operation will zero-extend
-// up to 64 bits.
-// FIXME: X86 also checks for CMOV here. Do we need something similar?
def def32 : PatLeaf<(i32 GPR32:$src), [{
- return N->getOpcode() != ISD::TRUNCATE &&
- N->getOpcode() != TargetOpcode::EXTRACT_SUBREG &&
- N->getOpcode() != ISD::CopyFromReg;
+ return isDef32(*N);
}]>;
// In the case of a 32-bit def that is known to implicitly zero-extend,
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
new file mode 100644
index 0000000..b514735
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
@@ -0,0 +1,1165 @@
+//===- AArch64InstructionSelector.cpp ----------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the InstructionSelector class for
+/// AArch64.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#include "AArch64InstructionSelector.h"
+#include "AArch64InstrInfo.h"
+#include "AArch64RegisterBankInfo.h"
+#include "AArch64RegisterInfo.h"
+#include "AArch64Subtarget.h"
+#include "AArch64TargetMachine.h"
+#include "MCTargetDesc/AArch64AddressingModes.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "aarch64-isel"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+#include "AArch64GenGlobalISel.inc"
+
+AArch64InstructionSelector::AArch64InstructionSelector(
+ const AArch64TargetMachine &TM, const AArch64Subtarget &STI,
+ const AArch64RegisterBankInfo &RBI)
+ : InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
+ TRI(*STI.getRegisterInfo()), RBI(RBI) {}
+
+// FIXME: This should be target-independent, inferred from the types declared
+// for each class in the bank.
+static const TargetRegisterClass *
+getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB,
+ const RegisterBankInfo &RBI) {
+ if (RB.getID() == AArch64::GPRRegBankID) {
+ if (Ty.getSizeInBits() <= 32)
+ return &AArch64::GPR32RegClass;
+ if (Ty.getSizeInBits() == 64)
+ return &AArch64::GPR64RegClass;
+ return nullptr;
+ }
+
+ if (RB.getID() == AArch64::FPRRegBankID) {
+ if (Ty.getSizeInBits() == 32)
+ return &AArch64::FPR32RegClass;
+ if (Ty.getSizeInBits() == 64)
+ return &AArch64::FPR64RegClass;
+ if (Ty.getSizeInBits() == 128)
+ return &AArch64::FPR128RegClass;
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+/// Check whether \p I is a currently unsupported binary operation:
+/// - it has an unsized type
+/// - an operand is not a vreg
+/// - all operands are not in the same bank
+/// These are checks that should someday live in the verifier, but right now,
+/// these are mostly limitations of the aarch64 selector.
+static bool unsupportedBinOp(const MachineInstr &I,
+ const AArch64RegisterBankInfo &RBI,
+ const MachineRegisterInfo &MRI,
+ const AArch64RegisterInfo &TRI) {
+ LLT Ty = MRI.getType(I.getOperand(0).getReg());
+ if (!Ty.isValid()) {
+ DEBUG(dbgs() << "Generic binop register should be typed\n");
+ return true;
+ }
+
+ const RegisterBank *PrevOpBank = nullptr;
+ for (auto &MO : I.operands()) {
+ // FIXME: Support non-register operands.
+ if (!MO.isReg()) {
+ DEBUG(dbgs() << "Generic inst non-reg operands are unsupported\n");
+ return true;
+ }
+
+ // FIXME: Can generic operations have physical registers operands? If
+ // so, this will need to be taught about that, and we'll need to get the
+ // bank out of the minimal class for the register.
+ // Either way, this needs to be documented (and possibly verified).
+ if (!TargetRegisterInfo::isVirtualRegister(MO.getReg())) {
+ DEBUG(dbgs() << "Generic inst has physical register operand\n");
+ return true;
+ }
+
+ const RegisterBank *OpBank = RBI.getRegBank(MO.getReg(), MRI, TRI);
+ if (!OpBank) {
+ DEBUG(dbgs() << "Generic register has no bank or class\n");
+ return true;
+ }
+
+ if (PrevOpBank && OpBank != PrevOpBank) {
+ DEBUG(dbgs() << "Generic inst operands have different banks\n");
+ return true;
+ }
+ PrevOpBank = OpBank;
+ }
+ return false;
+}
+
+/// Select the AArch64 opcode for the basic binary operation \p GenericOpc
+/// (such as G_OR or G_ADD), appropriate for the register bank \p RegBankID
+/// and of size \p OpSize.
+/// \returns \p GenericOpc if the combination is unsupported.
+static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID,
+ unsigned OpSize) {
+ switch (RegBankID) {
+ case AArch64::GPRRegBankID:
+ if (OpSize <= 32) {
+ assert((OpSize == 32 || (GenericOpc != TargetOpcode::G_SDIV &&
+ GenericOpc != TargetOpcode::G_UDIV &&
+ GenericOpc != TargetOpcode::G_LSHR &&
+ GenericOpc != TargetOpcode::G_ASHR)) &&
+ "operation should have been legalized before now");
+
+ switch (GenericOpc) {
+ case TargetOpcode::G_OR:
+ return AArch64::ORRWrr;
+ case TargetOpcode::G_XOR:
+ return AArch64::EORWrr;
+ case TargetOpcode::G_AND:
+ return AArch64::ANDWrr;
+ case TargetOpcode::G_ADD:
+ assert(OpSize != 32 && "s32 G_ADD should have been selected");
+ return AArch64::ADDWrr;
+ case TargetOpcode::G_SUB:
+ return AArch64::SUBWrr;
+ case TargetOpcode::G_SHL:
+ return AArch64::LSLVWr;
+ case TargetOpcode::G_LSHR:
+ return AArch64::LSRVWr;
+ case TargetOpcode::G_ASHR:
+ return AArch64::ASRVWr;
+ case TargetOpcode::G_SDIV:
+ return AArch64::SDIVWr;
+ case TargetOpcode::G_UDIV:
+ return AArch64::UDIVWr;
+ default:
+ return GenericOpc;
+ }
+ } else if (OpSize == 64) {
+ switch (GenericOpc) {
+ case TargetOpcode::G_OR:
+ return AArch64::ORRXrr;
+ case TargetOpcode::G_XOR:
+ return AArch64::EORXrr;
+ case TargetOpcode::G_AND:
+ return AArch64::ANDXrr;
+ case TargetOpcode::G_GEP:
+ return AArch64::ADDXrr;
+ case TargetOpcode::G_SUB:
+ return AArch64::SUBXrr;
+ case TargetOpcode::G_SHL:
+ return AArch64::LSLVXr;
+ case TargetOpcode::G_LSHR:
+ return AArch64::LSRVXr;
+ case TargetOpcode::G_ASHR:
+ return AArch64::ASRVXr;
+ case TargetOpcode::G_SDIV:
+ return AArch64::SDIVXr;
+ case TargetOpcode::G_UDIV:
+ return AArch64::UDIVXr;
+ default:
+ return GenericOpc;
+ }
+ }
+ case AArch64::FPRRegBankID:
+ switch (OpSize) {
+ case 32:
+ switch (GenericOpc) {
+ case TargetOpcode::G_FADD:
+ return AArch64::FADDSrr;
+ case TargetOpcode::G_FSUB:
+ return AArch64::FSUBSrr;
+ case TargetOpcode::G_FMUL:
+ return AArch64::FMULSrr;
+ case TargetOpcode::G_FDIV:
+ return AArch64::FDIVSrr;
+ default:
+ return GenericOpc;
+ }
+ case 64:
+ switch (GenericOpc) {
+ case TargetOpcode::G_FADD:
+ return AArch64::FADDDrr;
+ case TargetOpcode::G_FSUB:
+ return AArch64::FSUBDrr;
+ case TargetOpcode::G_FMUL:
+ return AArch64::FMULDrr;
+ case TargetOpcode::G_FDIV:
+ return AArch64::FDIVDrr;
+ case TargetOpcode::G_OR:
+ return AArch64::ORRv8i8;
+ default:
+ return GenericOpc;
+ }
+ }
+ };
+ return GenericOpc;
+}
+
+/// Select the AArch64 opcode for the G_LOAD or G_STORE operation \p GenericOpc,
+/// appropriate for the (value) register bank \p RegBankID and of memory access
+/// size \p OpSize. This returns the variant with the base+unsigned-immediate
+/// addressing mode (e.g., LDRXui).
+/// \returns \p GenericOpc if the combination is unsupported.
+static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID,
+ unsigned OpSize) {
+ const bool isStore = GenericOpc == TargetOpcode::G_STORE;
+ switch (RegBankID) {
+ case AArch64::GPRRegBankID:
+ switch (OpSize) {
+ case 8:
+ return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
+ case 16:
+ return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
+ case 32:
+ return isStore ? AArch64::STRWui : AArch64::LDRWui;
+ case 64:
+ return isStore ? AArch64::STRXui : AArch64::LDRXui;
+ }
+ case AArch64::FPRRegBankID:
+ switch (OpSize) {
+ case 8:
+ return isStore ? AArch64::STRBui : AArch64::LDRBui;
+ case 16:
+ return isStore ? AArch64::STRHui : AArch64::LDRHui;
+ case 32:
+ return isStore ? AArch64::STRSui : AArch64::LDRSui;
+ case 64:
+ return isStore ? AArch64::STRDui : AArch64::LDRDui;
+ }
+ };
+ return GenericOpc;
+}
+
+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)) {
+ assert(I.isCopy() && "Generic operators do not allow physical registers");
+ return true;
+ }
+
+ const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI);
+ const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
+ unsigned SrcReg = I.getOperand(1).getReg();
+ const unsigned SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI);
+ (void)SrcSize;
+ assert((!TargetRegisterInfo::isPhysicalRegister(SrcReg) || I.isCopy()) &&
+ "No phys reg on generic operators");
+ assert(
+ (DstSize == SrcSize ||
+ // Copies are a mean to setup initial types, the number of
+ // bits may not exactly match.
+ (TargetRegisterInfo::isPhysicalRegister(SrcReg) &&
+ DstSize <= RBI.getSizeInBits(SrcReg, MRI, TRI)) ||
+ // Copies are a mean to copy bits around, as long as we are
+ // on the same register class, that's fine. Otherwise, that
+ // means we need some SUBREG_TO_REG or AND & co.
+ (((DstSize + 31) / 32 == (SrcSize + 31) / 32) && DstSize > SrcSize)) &&
+ "Copy with different width?!");
+ assert((DstSize <= 64 || RegBank.getID() == AArch64::FPRRegBankID) &&
+ "GPRs cannot get more than 64-bit width values");
+ const TargetRegisterClass *RC = nullptr;
+
+ if (RegBank.getID() == AArch64::FPRRegBankID) {
+ if (DstSize <= 32)
+ RC = &AArch64::FPR32RegClass;
+ else if (DstSize <= 64)
+ RC = &AArch64::FPR64RegClass;
+ else if (DstSize <= 128)
+ RC = &AArch64::FPR128RegClass;
+ else {
+ DEBUG(dbgs() << "Unexpected bitcast size " << DstSize << '\n');
+ return false;
+ }
+ } else {
+ assert(RegBank.getID() == AArch64::GPRRegBankID &&
+ "Bitcast for the flags?");
+ RC =
+ DstSize <= 32 ? &AArch64::GPR32allRegClass : &AArch64::GPR64allRegClass;
+ }
+
+ // No need to constrain SrcReg. It will get constrained when
+ // we hit another of its use 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");
+ return false;
+ }
+ I.setDesc(TII.get(AArch64::COPY));
+ return true;
+}
+
+static unsigned selectFPConvOpc(unsigned GenericOpc, LLT DstTy, LLT SrcTy) {
+ if (!DstTy.isScalar() || !SrcTy.isScalar())
+ return GenericOpc;
+
+ const unsigned DstSize = DstTy.getSizeInBits();
+ const unsigned SrcSize = SrcTy.getSizeInBits();
+
+ switch (DstSize) {
+ case 32:
+ switch (SrcSize) {
+ case 32:
+ switch (GenericOpc) {
+ case TargetOpcode::G_SITOFP:
+ return AArch64::SCVTFUWSri;
+ case TargetOpcode::G_UITOFP:
+ return AArch64::UCVTFUWSri;
+ case TargetOpcode::G_FPTOSI:
+ return AArch64::FCVTZSUWSr;
+ case TargetOpcode::G_FPTOUI:
+ return AArch64::FCVTZUUWSr;
+ default:
+ return GenericOpc;
+ }
+ case 64:
+ switch (GenericOpc) {
+ case TargetOpcode::G_SITOFP:
+ return AArch64::SCVTFUXSri;
+ case TargetOpcode::G_UITOFP:
+ return AArch64::UCVTFUXSri;
+ case TargetOpcode::G_FPTOSI:
+ return AArch64::FCVTZSUWDr;
+ case TargetOpcode::G_FPTOUI:
+ return AArch64::FCVTZUUWDr;
+ default:
+ return GenericOpc;
+ }
+ default:
+ return GenericOpc;
+ }
+ case 64:
+ switch (SrcSize) {
+ case 32:
+ switch (GenericOpc) {
+ case TargetOpcode::G_SITOFP:
+ return AArch64::SCVTFUWDri;
+ case TargetOpcode::G_UITOFP:
+ return AArch64::UCVTFUWDri;
+ case TargetOpcode::G_FPTOSI:
+ return AArch64::FCVTZSUXSr;
+ case TargetOpcode::G_FPTOUI:
+ return AArch64::FCVTZUUXSr;
+ default:
+ return GenericOpc;
+ }
+ case 64:
+ switch (GenericOpc) {
+ case TargetOpcode::G_SITOFP:
+ return AArch64::SCVTFUXDri;
+ case TargetOpcode::G_UITOFP:
+ return AArch64::UCVTFUXDri;
+ case TargetOpcode::G_FPTOSI:
+ return AArch64::FCVTZSUXDr;
+ case TargetOpcode::G_FPTOUI:
+ return AArch64::FCVTZUUXDr;
+ default:
+ return GenericOpc;
+ }
+ default:
+ return GenericOpc;
+ }
+ default:
+ return GenericOpc;
+ };
+ return GenericOpc;
+}
+
+static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P) {
+ switch (P) {
+ default:
+ llvm_unreachable("Unknown condition code!");
+ case CmpInst::ICMP_NE:
+ return AArch64CC::NE;
+ case CmpInst::ICMP_EQ:
+ return AArch64CC::EQ;
+ case CmpInst::ICMP_SGT:
+ return AArch64CC::GT;
+ case CmpInst::ICMP_SGE:
+ return AArch64CC::GE;
+ case CmpInst::ICMP_SLT:
+ return AArch64CC::LT;
+ case CmpInst::ICMP_SLE:
+ return AArch64CC::LE;
+ case CmpInst::ICMP_UGT:
+ return AArch64CC::HI;
+ case CmpInst::ICMP_UGE:
+ return AArch64CC::HS;
+ case CmpInst::ICMP_ULT:
+ return AArch64CC::LO;
+ case CmpInst::ICMP_ULE:
+ return AArch64CC::LS;
+ }
+}
+
+static void changeFCMPPredToAArch64CC(CmpInst::Predicate P,
+ AArch64CC::CondCode &CondCode,
+ AArch64CC::CondCode &CondCode2) {
+ CondCode2 = AArch64CC::AL;
+ switch (P) {
+ default:
+ llvm_unreachable("Unknown FP condition!");
+ case CmpInst::FCMP_OEQ:
+ CondCode = AArch64CC::EQ;
+ break;
+ case CmpInst::FCMP_OGT:
+ CondCode = AArch64CC::GT;
+ break;
+ case CmpInst::FCMP_OGE:
+ CondCode = AArch64CC::GE;
+ break;
+ case CmpInst::FCMP_OLT:
+ CondCode = AArch64CC::MI;
+ break;
+ case CmpInst::FCMP_OLE:
+ CondCode = AArch64CC::LS;
+ break;
+ case CmpInst::FCMP_ONE:
+ CondCode = AArch64CC::MI;
+ CondCode2 = AArch64CC::GT;
+ break;
+ case CmpInst::FCMP_ORD:
+ CondCode = AArch64CC::VC;
+ break;
+ case CmpInst::FCMP_UNO:
+ CondCode = AArch64CC::VS;
+ break;
+ case CmpInst::FCMP_UEQ:
+ CondCode = AArch64CC::EQ;
+ CondCode2 = AArch64CC::VS;
+ break;
+ case CmpInst::FCMP_UGT:
+ CondCode = AArch64CC::HI;
+ break;
+ case CmpInst::FCMP_UGE:
+ CondCode = AArch64CC::PL;
+ break;
+ case CmpInst::FCMP_ULT:
+ CondCode = AArch64CC::LT;
+ break;
+ case CmpInst::FCMP_ULE:
+ CondCode = AArch64CC::LE;
+ break;
+ case CmpInst::FCMP_UNE:
+ CondCode = AArch64CC::NE;
+ break;
+ }
+}
+
+bool AArch64InstructionSelector::select(MachineInstr &I) const {
+ assert(I.getParent() && "Instruction should be in a basic block!");
+ assert(I.getParent()->getParent() && "Instruction should be in a function!");
+
+ MachineBasicBlock &MBB = *I.getParent();
+ MachineFunction &MF = *MBB.getParent();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ unsigned Opcode = I.getOpcode();
+ if (!isPreISelGenericOpcode(I.getOpcode())) {
+ // Certain non-generic instructions also need some special handling.
+
+ if (Opcode == TargetOpcode::LOAD_STACK_GUARD)
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+
+ if (Opcode == TargetOpcode::PHI) {
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const LLT DefTy = MRI.getType(DefReg);
+
+ const TargetRegisterClass *DefRC = nullptr;
+ if (TargetRegisterInfo::isPhysicalRegister(DefReg)) {
+ DefRC = TRI.getRegClass(DefReg);
+ } else {
+ const RegClassOrRegBank &RegClassOrBank =
+ MRI.getRegClassOrRegBank(DefReg);
+
+ DefRC = RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
+ if (!DefRC) {
+ if (!DefTy.isValid()) {
+ DEBUG(dbgs() << "PHI operand has no type, not a gvreg?\n");
+ return false;
+ }
+ const RegisterBank &RB = *RegClassOrBank.get<const RegisterBank *>();
+ DefRC = getRegClassForTypeOnBank(DefTy, RB, RBI);
+ if (!DefRC) {
+ DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
+ return false;
+ }
+ }
+ }
+
+ return RBI.constrainGenericRegister(DefReg, *DefRC, MRI);
+ }
+
+ if (I.isCopy())
+ return selectCopy(I, TII, MRI, TRI, RBI);
+
+ return true;
+ }
+
+
+ if (I.getNumOperands() != I.getNumExplicitOperands()) {
+ DEBUG(dbgs() << "Generic instruction has unexpected implicit operands\n");
+ return false;
+ }
+
+ if (selectImpl(I))
+ return true;
+
+ LLT Ty =
+ I.getOperand(0).isReg() ? MRI.getType(I.getOperand(0).getReg()) : LLT{};
+
+ switch (Opcode) {
+ case TargetOpcode::G_BRCOND: {
+ if (Ty.getSizeInBits() > 32) {
+ // We shouldn't need this on AArch64, but it would be implemented as an
+ // EXTRACT_SUBREG followed by a TBNZW because TBNZX has no encoding if the
+ // bit being tested is < 32.
+ DEBUG(dbgs() << "G_BRCOND has type: " << Ty
+ << ", expected at most 32-bits");
+ return false;
+ }
+
+ const unsigned CondReg = I.getOperand(0).getReg();
+ MachineBasicBlock *DestMBB = I.getOperand(1).getMBB();
+
+ auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::TBNZW))
+ .addUse(CondReg)
+ .addImm(/*bit offset=*/0)
+ .addMBB(DestMBB);
+
+ I.eraseFromParent();
+ return constrainSelectedInstRegOperands(*MIB.getInstr(), TII, TRI, RBI);
+ }
+
+ case TargetOpcode::G_FCONSTANT:
+ case TargetOpcode::G_CONSTANT: {
+ const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
+
+ const LLT s32 = LLT::scalar(32);
+ const LLT s64 = LLT::scalar(64);
+ const LLT p0 = LLT::pointer(0, 64);
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const LLT DefTy = MRI.getType(DefReg);
+ const unsigned DefSize = DefTy.getSizeInBits();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ // FIXME: Redundant check, but even less readable when factored out.
+ if (isFP) {
+ if (Ty != s32 && Ty != s64) {
+ DEBUG(dbgs() << "Unable to materialize FP " << Ty
+ << " constant, expected: " << s32 << " or " << s64
+ << '\n');
+ return false;
+ }
+
+ if (RB.getID() != AArch64::FPRRegBankID) {
+ DEBUG(dbgs() << "Unable to materialize FP " << Ty
+ << " constant on bank: " << RB << ", expected: FPR\n");
+ return false;
+ }
+ } else {
+ if (Ty != s32 && Ty != s64 && Ty != p0) {
+ DEBUG(dbgs() << "Unable to materialize integer " << Ty
+ << " constant, expected: " << s32 << ", " << s64 << ", or "
+ << p0 << '\n');
+ return false;
+ }
+
+ if (RB.getID() != AArch64::GPRRegBankID) {
+ DEBUG(dbgs() << "Unable to materialize integer " << Ty
+ << " constant on bank: " << RB << ", expected: GPR\n");
+ return false;
+ }
+ }
+
+ const unsigned MovOpc =
+ DefSize == 32 ? AArch64::MOVi32imm : AArch64::MOVi64imm;
+
+ I.setDesc(TII.get(MovOpc));
+
+ if (isFP) {
+ const TargetRegisterClass &GPRRC =
+ DefSize == 32 ? AArch64::GPR32RegClass : AArch64::GPR64RegClass;
+ const TargetRegisterClass &FPRRC =
+ DefSize == 32 ? AArch64::FPR32RegClass : AArch64::FPR64RegClass;
+
+ const unsigned DefGPRReg = MRI.createVirtualRegister(&GPRRC);
+ MachineOperand &RegOp = I.getOperand(0);
+ RegOp.setReg(DefGPRReg);
+
+ BuildMI(MBB, std::next(I.getIterator()), I.getDebugLoc(),
+ TII.get(AArch64::COPY))
+ .addDef(DefReg)
+ .addUse(DefGPRReg);
+
+ if (!RBI.constrainGenericRegister(DefReg, FPRRC, MRI)) {
+ DEBUG(dbgs() << "Failed to constrain G_FCONSTANT def operand\n");
+ return false;
+ }
+
+ MachineOperand &ImmOp = I.getOperand(1);
+ // FIXME: Is going through int64_t always correct?
+ ImmOp.ChangeToImmediate(
+ ImmOp.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
+ } else {
+ uint64_t Val = I.getOperand(1).getCImm()->getZExtValue();
+ I.getOperand(1).ChangeToImmediate(Val);
+ }
+
+ constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ return true;
+ }
+
+ case TargetOpcode::G_FRAME_INDEX: {
+ // allocas and G_FRAME_INDEX are only supported in addrspace(0).
+ if (Ty != LLT::pointer(0, 64)) {
+ DEBUG(dbgs() << "G_FRAME_INDEX pointer has type: " << Ty
+ << ", expected: " << LLT::pointer(0, 64) << '\n');
+ return false;
+ }
+
+ I.setDesc(TII.get(AArch64::ADDXri));
+
+ // MOs for a #0 shifted immediate.
+ I.addOperand(MachineOperand::CreateImm(0));
+ I.addOperand(MachineOperand::CreateImm(0));
+
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ }
+
+ case TargetOpcode::G_GLOBAL_VALUE: {
+ auto GV = I.getOperand(1).getGlobal();
+ if (GV->isThreadLocal()) {
+ // FIXME: we don't support TLS yet.
+ return false;
+ }
+ unsigned char OpFlags = STI.ClassifyGlobalReference(GV, TM);
+ if (OpFlags & AArch64II::MO_GOT) {
+ I.setDesc(TII.get(AArch64::LOADgot));
+ I.getOperand(1).setTargetFlags(OpFlags);
+ } else {
+ I.setDesc(TII.get(AArch64::MOVaddr));
+ I.getOperand(1).setTargetFlags(OpFlags | AArch64II::MO_PAGE);
+ MachineInstrBuilder MIB(MF, I);
+ MIB.addGlobalAddress(GV, I.getOperand(1).getOffset(),
+ OpFlags | AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+ }
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ }
+
+ case TargetOpcode::G_LOAD:
+ case TargetOpcode::G_STORE: {
+ LLT MemTy = Ty;
+ LLT PtrTy = MRI.getType(I.getOperand(1).getReg());
+
+ if (PtrTy != LLT::pointer(0, 64)) {
+ DEBUG(dbgs() << "Load/Store pointer has type: " << PtrTy
+ << ", expected: " << LLT::pointer(0, 64) << '\n');
+ return false;
+ }
+
+#ifndef NDEBUG
+ // Sanity-check the pointer register.
+ const unsigned PtrReg = I.getOperand(1).getReg();
+ const RegisterBank &PtrRB = *RBI.getRegBank(PtrReg, MRI, TRI);
+ assert(PtrRB.getID() == AArch64::GPRRegBankID &&
+ "Load/Store pointer operand isn't a GPR");
+ assert(MRI.getType(PtrReg).isPointer() &&
+ "Load/Store pointer operand isn't a pointer");
+#endif
+
+ const unsigned ValReg = I.getOperand(0).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(ValReg, MRI, TRI);
+
+ const unsigned NewOpc =
+ selectLoadStoreUIOp(I.getOpcode(), RB.getID(), MemTy.getSizeInBits());
+ if (NewOpc == I.getOpcode())
+ return false;
+
+ I.setDesc(TII.get(NewOpc));
+
+ I.addOperand(MachineOperand::CreateImm(0));
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ }
+
+ case TargetOpcode::G_MUL: {
+ // Reject the various things we don't support yet.
+ if (unsupportedBinOp(I, RBI, MRI, TRI))
+ return false;
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ if (RB.getID() != AArch64::GPRRegBankID) {
+ DEBUG(dbgs() << "G_MUL on bank: " << RB << ", expected: GPR\n");
+ return false;
+ }
+
+ unsigned ZeroReg;
+ unsigned NewOpc;
+ if (Ty.isScalar() && Ty.getSizeInBits() <= 32) {
+ NewOpc = AArch64::MADDWrrr;
+ ZeroReg = AArch64::WZR;
+ } else if (Ty == LLT::scalar(64)) {
+ NewOpc = AArch64::MADDXrrr;
+ ZeroReg = AArch64::XZR;
+ } else {
+ DEBUG(dbgs() << "G_MUL has type: " << Ty << ", expected: "
+ << LLT::scalar(32) << " or " << LLT::scalar(64) << '\n');
+ return false;
+ }
+
+ I.setDesc(TII.get(NewOpc));
+
+ I.addOperand(MachineOperand::CreateReg(ZeroReg, /*isDef=*/false));
+
+ // Now that we selected an opcode, we need to constrain the register
+ // operands to use appropriate classes.
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ }
+
+ case TargetOpcode::G_FADD:
+ case TargetOpcode::G_FSUB:
+ case TargetOpcode::G_FMUL:
+ case TargetOpcode::G_FDIV:
+
+ case TargetOpcode::G_OR:
+ case TargetOpcode::G_XOR:
+ case TargetOpcode::G_AND:
+ case TargetOpcode::G_SHL:
+ case TargetOpcode::G_LSHR:
+ case TargetOpcode::G_ASHR:
+ case TargetOpcode::G_SDIV:
+ case TargetOpcode::G_UDIV:
+ case TargetOpcode::G_ADD:
+ case TargetOpcode::G_SUB:
+ case TargetOpcode::G_GEP: {
+ // Reject the various things we don't support yet.
+ if (unsupportedBinOp(I, RBI, MRI, TRI))
+ return false;
+
+ const unsigned OpSize = Ty.getSizeInBits();
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ const unsigned NewOpc = selectBinaryOp(I.getOpcode(), RB.getID(), OpSize);
+ if (NewOpc == I.getOpcode())
+ return false;
+
+ I.setDesc(TII.get(NewOpc));
+ // FIXME: Should the type be always reset in setDesc?
+
+ // Now that we selected an opcode, we need to constrain the register
+ // operands to use appropriate classes.
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ }
+
+ case TargetOpcode::G_PTRTOINT:
+ case TargetOpcode::G_TRUNC: {
+ const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
+ const LLT SrcTy = MRI.getType(I.getOperand(1).getReg());
+
+ const unsigned DstReg = I.getOperand(0).getReg();
+ const unsigned SrcReg = I.getOperand(1).getReg();
+
+ const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
+ const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI);
+
+ if (DstRB.getID() != SrcRB.getID()) {
+ DEBUG(dbgs() << "G_TRUNC input/output on different banks\n");
+ return false;
+ }
+
+ if (DstRB.getID() == AArch64::GPRRegBankID) {
+ const TargetRegisterClass *DstRC =
+ getRegClassForTypeOnBank(DstTy, DstRB, RBI);
+ if (!DstRC)
+ return false;
+
+ const TargetRegisterClass *SrcRC =
+ getRegClassForTypeOnBank(SrcTy, SrcRB, RBI);
+ if (!SrcRC)
+ return false;
+
+ if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) ||
+ !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {
+ DEBUG(dbgs() << "Failed to constrain G_TRUNC\n");
+ return false;
+ }
+
+ if (DstRC == SrcRC) {
+ // Nothing to be done
+ } else if (DstRC == &AArch64::GPR32RegClass &&
+ SrcRC == &AArch64::GPR64RegClass) {
+ I.getOperand(1).setSubReg(AArch64::sub_32);
+ } else {
+ return false;
+ }
+
+ I.setDesc(TII.get(TargetOpcode::COPY));
+ return true;
+ } else if (DstRB.getID() == AArch64::FPRRegBankID) {
+ if (DstTy == LLT::vector(4, 16) && SrcTy == LLT::vector(4, 32)) {
+ I.setDesc(TII.get(AArch64::XTNv4i16));
+ constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ case TargetOpcode::G_ANYEXT: {
+ const unsigned DstReg = I.getOperand(0).getReg();
+ const unsigned SrcReg = I.getOperand(1).getReg();
+
+ const RegisterBank &RBDst = *RBI.getRegBank(DstReg, MRI, TRI);
+ if (RBDst.getID() != AArch64::GPRRegBankID) {
+ DEBUG(dbgs() << "G_ANYEXT on bank: " << RBDst << ", expected: GPR\n");
+ return false;
+ }
+
+ const RegisterBank &RBSrc = *RBI.getRegBank(SrcReg, MRI, TRI);
+ if (RBSrc.getID() != AArch64::GPRRegBankID) {
+ DEBUG(dbgs() << "G_ANYEXT on bank: " << RBSrc << ", expected: GPR\n");
+ return false;
+ }
+
+ const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
+
+ if (DstSize == 0) {
+ DEBUG(dbgs() << "G_ANYEXT operand has no size, not a gvreg?\n");
+ return false;
+ }
+
+ if (DstSize != 64 && DstSize > 32) {
+ DEBUG(dbgs() << "G_ANYEXT to size: " << DstSize
+ << ", expected: 32 or 64\n");
+ return false;
+ }
+ // At this point G_ANYEXT is just like a plain COPY, but we need
+ // to explicitly form the 64-bit value if any.
+ if (DstSize > 32) {
+ unsigned ExtSrc = MRI.createVirtualRegister(&AArch64::GPR64allRegClass);
+ BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::SUBREG_TO_REG))
+ .addDef(ExtSrc)
+ .addImm(0)
+ .addUse(SrcReg)
+ .addImm(AArch64::sub_32);
+ I.getOperand(1).setReg(ExtSrc);
+ }
+ return selectCopy(I, TII, MRI, TRI, RBI);
+ }
+
+ case TargetOpcode::G_ZEXT:
+ case TargetOpcode::G_SEXT: {
+ unsigned Opcode = I.getOpcode();
+ const LLT DstTy = MRI.getType(I.getOperand(0).getReg()),
+ SrcTy = MRI.getType(I.getOperand(1).getReg());
+ const bool isSigned = Opcode == TargetOpcode::G_SEXT;
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const unsigned SrcReg = I.getOperand(1).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ if (RB.getID() != AArch64::GPRRegBankID) {
+ DEBUG(dbgs() << TII.getName(I.getOpcode()) << " on bank: " << RB
+ << ", expected: GPR\n");
+ return false;
+ }
+
+ MachineInstr *ExtI;
+ if (DstTy == LLT::scalar(64)) {
+ // FIXME: Can we avoid manually doing this?
+ if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass, MRI)) {
+ DEBUG(dbgs() << "Failed to constrain " << TII.getName(Opcode)
+ << " operand\n");
+ return false;
+ }
+
+ const unsigned SrcXReg =
+ MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+ BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::SUBREG_TO_REG))
+ .addDef(SrcXReg)
+ .addImm(0)
+ .addUse(SrcReg)
+ .addImm(AArch64::sub_32);
+
+ const unsigned NewOpc = isSigned ? AArch64::SBFMXri : AArch64::UBFMXri;
+ ExtI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
+ .addDef(DefReg)
+ .addUse(SrcXReg)
+ .addImm(0)
+ .addImm(SrcTy.getSizeInBits() - 1);
+ } else if (DstTy.isScalar() && DstTy.getSizeInBits() <= 32) {
+ const unsigned NewOpc = isSigned ? AArch64::SBFMWri : AArch64::UBFMWri;
+ ExtI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
+ .addDef(DefReg)
+ .addUse(SrcReg)
+ .addImm(0)
+ .addImm(SrcTy.getSizeInBits() - 1);
+ } else {
+ return false;
+ }
+
+ constrainSelectedInstRegOperands(*ExtI, TII, TRI, RBI);
+
+ I.eraseFromParent();
+ return true;
+ }
+
+ case TargetOpcode::G_SITOFP:
+ case TargetOpcode::G_UITOFP:
+ case TargetOpcode::G_FPTOSI:
+ case TargetOpcode::G_FPTOUI: {
+ const LLT DstTy = MRI.getType(I.getOperand(0).getReg()),
+ SrcTy = MRI.getType(I.getOperand(1).getReg());
+ const unsigned NewOpc = selectFPConvOpc(Opcode, DstTy, SrcTy);
+ if (NewOpc == Opcode)
+ return false;
+
+ I.setDesc(TII.get(NewOpc));
+ constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+
+ return true;
+ }
+
+
+ case TargetOpcode::G_INTTOPTR:
+ case TargetOpcode::G_BITCAST:
+ return selectCopy(I, TII, MRI, TRI, RBI);
+
+ case TargetOpcode::G_FPEXT: {
+ if (MRI.getType(I.getOperand(0).getReg()) != LLT::scalar(64)) {
+ DEBUG(dbgs() << "G_FPEXT to type " << Ty
+ << ", expected: " << LLT::scalar(64) << '\n');
+ return false;
+ }
+
+ if (MRI.getType(I.getOperand(1).getReg()) != LLT::scalar(32)) {
+ DEBUG(dbgs() << "G_FPEXT from type " << Ty
+ << ", expected: " << LLT::scalar(32) << '\n');
+ return false;
+ }
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ if (RB.getID() != AArch64::FPRRegBankID) {
+ DEBUG(dbgs() << "G_FPEXT on bank: " << RB << ", expected: FPR\n");
+ return false;
+ }
+
+ I.setDesc(TII.get(AArch64::FCVTDSr));
+ constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+
+ return true;
+ }
+
+ case TargetOpcode::G_FPTRUNC: {
+ if (MRI.getType(I.getOperand(0).getReg()) != LLT::scalar(32)) {
+ DEBUG(dbgs() << "G_FPTRUNC to type " << Ty
+ << ", expected: " << LLT::scalar(32) << '\n');
+ return false;
+ }
+
+ if (MRI.getType(I.getOperand(1).getReg()) != LLT::scalar(64)) {
+ DEBUG(dbgs() << "G_FPTRUNC from type " << Ty
+ << ", expected: " << LLT::scalar(64) << '\n');
+ return false;
+ }
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
+
+ if (RB.getID() != AArch64::FPRRegBankID) {
+ DEBUG(dbgs() << "G_FPTRUNC on bank: " << RB << ", expected: FPR\n");
+ return false;
+ }
+
+ I.setDesc(TII.get(AArch64::FCVTSDr));
+ constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+
+ return true;
+ }
+
+ case TargetOpcode::G_SELECT: {
+ if (MRI.getType(I.getOperand(1).getReg()) != LLT::scalar(1)) {
+ DEBUG(dbgs() << "G_SELECT cond has type: " << Ty
+ << ", expected: " << LLT::scalar(1) << '\n');
+ return false;
+ }
+
+ const unsigned CondReg = I.getOperand(1).getReg();
+ const unsigned TReg = I.getOperand(2).getReg();
+ const unsigned FReg = I.getOperand(3).getReg();
+
+ unsigned CSelOpc = 0;
+
+ if (Ty == LLT::scalar(32)) {
+ CSelOpc = AArch64::CSELWr;
+ } else if (Ty == LLT::scalar(64)) {
+ CSelOpc = AArch64::CSELXr;
+ } else {
+ return false;
+ }
+
+ MachineInstr &TstMI =
+ *BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::ANDSWri))
+ .addDef(AArch64::WZR)
+ .addUse(CondReg)
+ .addImm(AArch64_AM::encodeLogicalImmediate(1, 32));
+
+ MachineInstr &CSelMI = *BuildMI(MBB, I, I.getDebugLoc(), TII.get(CSelOpc))
+ .addDef(I.getOperand(0).getReg())
+ .addUse(TReg)
+ .addUse(FReg)
+ .addImm(AArch64CC::NE);
+
+ constrainSelectedInstRegOperands(TstMI, TII, TRI, RBI);
+ constrainSelectedInstRegOperands(CSelMI, TII, TRI, RBI);
+
+ I.eraseFromParent();
+ return true;
+ }
+ case TargetOpcode::G_ICMP: {
+ if (Ty != LLT::scalar(1)) {
+ DEBUG(dbgs() << "G_ICMP result has type: " << Ty
+ << ", expected: " << LLT::scalar(1) << '\n');
+ return false;
+ }
+
+ unsigned CmpOpc = 0;
+ unsigned ZReg = 0;
+
+ LLT CmpTy = MRI.getType(I.getOperand(2).getReg());
+ if (CmpTy == LLT::scalar(32)) {
+ CmpOpc = AArch64::SUBSWrr;
+ ZReg = AArch64::WZR;
+ } else if (CmpTy == LLT::scalar(64) || CmpTy.isPointer()) {
+ CmpOpc = AArch64::SUBSXrr;
+ ZReg = AArch64::XZR;
+ } else {
+ return false;
+ }
+
+ // CSINC increments the result by one when the condition code is false.
+ // Therefore, we have to invert the predicate to get an increment by 1 when
+ // the predicate is true.
+ const AArch64CC::CondCode invCC =
+ changeICMPPredToAArch64CC(CmpInst::getInversePredicate(
+ (CmpInst::Predicate)I.getOperand(1).getPredicate()));
+
+ MachineInstr &CmpMI = *BuildMI(MBB, I, I.getDebugLoc(), TII.get(CmpOpc))
+ .addDef(ZReg)
+ .addUse(I.getOperand(2).getReg())
+ .addUse(I.getOperand(3).getReg());
+
+ MachineInstr &CSetMI =
+ *BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::CSINCWr))
+ .addDef(I.getOperand(0).getReg())
+ .addUse(AArch64::WZR)
+ .addUse(AArch64::WZR)
+ .addImm(invCC);
+
+ constrainSelectedInstRegOperands(CmpMI, TII, TRI, RBI);
+ constrainSelectedInstRegOperands(CSetMI, TII, TRI, RBI);
+
+ I.eraseFromParent();
+ return true;
+ }
+
+ case TargetOpcode::G_FCMP: {
+ if (Ty != LLT::scalar(1)) {
+ DEBUG(dbgs() << "G_FCMP result has type: " << Ty
+ << ", expected: " << LLT::scalar(1) << '\n');
+ return false;
+ }
+
+ unsigned CmpOpc = 0;
+ LLT CmpTy = MRI.getType(I.getOperand(2).getReg());
+ if (CmpTy == LLT::scalar(32)) {
+ CmpOpc = AArch64::FCMPSrr;
+ } else if (CmpTy == LLT::scalar(64)) {
+ CmpOpc = AArch64::FCMPDrr;
+ } else {
+ return false;
+ }
+
+ // FIXME: regbank
+
+ AArch64CC::CondCode CC1, CC2;
+ changeFCMPPredToAArch64CC(
+ (CmpInst::Predicate)I.getOperand(1).getPredicate(), CC1, CC2);
+
+ MachineInstr &CmpMI = *BuildMI(MBB, I, I.getDebugLoc(), TII.get(CmpOpc))
+ .addUse(I.getOperand(2).getReg())
+ .addUse(I.getOperand(3).getReg());
+
+ const unsigned DefReg = I.getOperand(0).getReg();
+ unsigned Def1Reg = DefReg;
+ if (CC2 != AArch64CC::AL)
+ Def1Reg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
+
+ MachineInstr &CSetMI =
+ *BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::CSINCWr))
+ .addDef(Def1Reg)
+ .addUse(AArch64::WZR)
+ .addUse(AArch64::WZR)
+ .addImm(CC1);
+
+ if (CC2 != AArch64CC::AL) {
+ unsigned Def2Reg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
+ MachineInstr &CSet2MI =
+ *BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::CSINCWr))
+ .addDef(Def2Reg)
+ .addUse(AArch64::WZR)
+ .addUse(AArch64::WZR)
+ .addImm(CC2);
+ MachineInstr &OrMI =
+ *BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::ORRWrr))
+ .addDef(DefReg)
+ .addUse(Def1Reg)
+ .addUse(Def2Reg);
+ constrainSelectedInstRegOperands(OrMI, TII, TRI, RBI);
+ constrainSelectedInstRegOperands(CSet2MI, TII, TRI, RBI);
+ }
+
+ constrainSelectedInstRegOperands(CmpMI, TII, TRI, RBI);
+ constrainSelectedInstRegOperands(CSetMI, TII, TRI, RBI);
+
+ I.eraseFromParent();
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.h b/contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.h
new file mode 100644
index 0000000..2c6e5a9
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64InstructionSelector.h
@@ -0,0 +1,49 @@
+//===- AArch64InstructionSelector --------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares the targeting of the InstructionSelector class for
+/// AArch64.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64INSTRUCTIONSELECTOR_H
+#define LLVM_LIB_TARGET_AARCH64_AARCH64INSTRUCTIONSELECTOR_H
+
+#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+
+namespace llvm {
+
+class AArch64InstrInfo;
+class AArch64RegisterBankInfo;
+class AArch64RegisterInfo;
+class AArch64Subtarget;
+class AArch64TargetMachine;
+
+class AArch64InstructionSelector : public InstructionSelector {
+public:
+ AArch64InstructionSelector(const AArch64TargetMachine &TM,
+ const AArch64Subtarget &STI,
+ const AArch64RegisterBankInfo &RBI);
+
+ bool select(MachineInstr &I) const override;
+
+private:
+ /// tblgen-erated 'select' implementation, used as the initial selector for
+ /// the patterns that don't require complex C++.
+ bool selectImpl(MachineInstr &I) const;
+
+ const AArch64TargetMachine &TM;
+ const AArch64Subtarget &STI;
+ const AArch64InstrInfo &TII;
+ const AArch64RegisterInfo &TRI;
+ const AArch64RegisterBankInfo &RBI;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_AARCH64_AARCH64INSTRUCTIONSELECTOR_H
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp
new file mode 100644
index 0000000..83f276a
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp
@@ -0,0 +1,204 @@
+//===- AArch64LegalizerInfo.cpp ----------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the Machinelegalizer class for
+/// AArch64.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#include "AArch64LegalizerInfo.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/Target/TargetOpcodes.h"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+AArch64LegalizerInfo::AArch64LegalizerInfo() {
+ using namespace TargetOpcode;
+ const LLT p0 = LLT::pointer(0, 64);
+ const LLT s1 = LLT::scalar(1);
+ const LLT s8 = LLT::scalar(8);
+ const LLT s16 = LLT::scalar(16);
+ const LLT s32 = LLT::scalar(32);
+ const LLT s64 = LLT::scalar(64);
+ const LLT v2s32 = LLT::vector(2, 32);
+ const LLT v4s32 = LLT::vector(4, 32);
+ const LLT v2s64 = LLT::vector(2, 64);
+
+ for (auto BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR, G_SHL}) {
+ // These operations naturally get the right answer when used on
+ // GPR32, even if the actual type is narrower.
+ for (auto Ty : {s1, s8, s16, s32, s64, v2s32, v4s32, v2s64})
+ setAction({BinOp, Ty}, Legal);
+ }
+
+ setAction({G_GEP, p0}, Legal);
+ setAction({G_GEP, 1, s64}, Legal);
+
+ for (auto Ty : {s1, s8, s16, s32})
+ setAction({G_GEP, 1, Ty}, WidenScalar);
+
+ for (auto BinOp : {G_LSHR, G_ASHR, G_SDIV, G_UDIV}) {
+ for (auto Ty : {s32, s64})
+ setAction({BinOp, Ty}, Legal);
+
+ for (auto Ty : {s1, s8, s16})
+ setAction({BinOp, Ty}, WidenScalar);
+ }
+
+ for (auto BinOp : { G_SREM, G_UREM })
+ for (auto Ty : { s1, s8, s16, s32, s64 })
+ setAction({BinOp, Ty}, Lower);
+
+ for (auto Op : { G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_SMULO, G_UMULO }) {
+ for (auto Ty : { s32, s64 })
+ setAction({Op, Ty}, Legal);
+
+ setAction({Op, 1, s1}, Legal);
+ }
+
+ for (auto BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
+ for (auto Ty : {s32, s64})
+ setAction({BinOp, Ty}, Legal);
+
+ setAction({G_FREM, s32}, Libcall);
+ setAction({G_FREM, s64}, Libcall);
+
+ for (auto MemOp : {G_LOAD, G_STORE}) {
+ for (auto Ty : {s8, s16, s32, s64, p0, v2s32})
+ setAction({MemOp, Ty}, Legal);
+
+ setAction({MemOp, s1}, WidenScalar);
+
+ // And everything's fine in addrspace 0.
+ setAction({MemOp, 1, p0}, Legal);
+ }
+
+ // Constants
+ for (auto Ty : {s32, s64}) {
+ setAction({TargetOpcode::G_CONSTANT, Ty}, Legal);
+ setAction({TargetOpcode::G_FCONSTANT, Ty}, Legal);
+ }
+
+ setAction({G_CONSTANT, p0}, Legal);
+
+ for (auto Ty : {s1, s8, s16})
+ setAction({TargetOpcode::G_CONSTANT, Ty}, WidenScalar);
+
+ setAction({TargetOpcode::G_FCONSTANT, s16}, WidenScalar);
+
+ setAction({G_ICMP, s1}, Legal);
+ setAction({G_ICMP, 1, s32}, Legal);
+ setAction({G_ICMP, 1, s64}, Legal);
+ setAction({G_ICMP, 1, p0}, Legal);
+
+ for (auto Ty : {s1, s8, s16}) {
+ setAction({G_ICMP, 1, Ty}, WidenScalar);
+ }
+
+ setAction({G_FCMP, s1}, Legal);
+ setAction({G_FCMP, 1, s32}, Legal);
+ setAction({G_FCMP, 1, s64}, Legal);
+
+ // Extensions
+ for (auto Ty : { s1, s8, s16, s32, s64 }) {
+ setAction({G_ZEXT, Ty}, Legal);
+ setAction({G_SEXT, Ty}, Legal);
+ setAction({G_ANYEXT, Ty}, Legal);
+ }
+
+ for (auto Ty : { s1, s8, s16, s32 }) {
+ setAction({G_ZEXT, 1, Ty}, Legal);
+ setAction({G_SEXT, 1, Ty}, Legal);
+ setAction({G_ANYEXT, 1, Ty}, Legal);
+ }
+
+ setAction({G_FPEXT, s64}, Legal);
+ setAction({G_FPEXT, 1, s32}, Legal);
+
+ // Truncations
+ for (auto Ty : { s16, s32 })
+ setAction({G_FPTRUNC, Ty}, Legal);
+
+ for (auto Ty : { s32, s64 })
+ setAction({G_FPTRUNC, 1, Ty}, Legal);
+
+ for (auto Ty : { s1, s8, s16, s32 })
+ setAction({G_TRUNC, Ty}, Legal);
+
+ for (auto Ty : { s8, s16, s32, s64 })
+ setAction({G_TRUNC, 1, Ty}, Legal);
+
+ // Conversions
+ for (auto Ty : { s1, s8, s16, s32, s64 }) {
+ setAction({G_FPTOSI, 0, Ty}, Legal);
+ setAction({G_FPTOUI, 0, Ty}, Legal);
+ setAction({G_SITOFP, 1, Ty}, Legal);
+ setAction({G_UITOFP, 1, Ty}, Legal);
+ }
+
+ for (auto Ty : { s32, s64 }) {
+ setAction({G_FPTOSI, 1, Ty}, Legal);
+ setAction({G_FPTOUI, 1, Ty}, Legal);
+ setAction({G_SITOFP, 0, Ty}, Legal);
+ setAction({G_UITOFP, 0, Ty}, Legal);
+ }
+
+ // Control-flow
+ for (auto Ty : {s1, s8, s16, s32})
+ setAction({G_BRCOND, Ty}, Legal);
+
+ // Select
+ for (auto Ty : {s1, s8, s16, s32, s64})
+ setAction({G_SELECT, Ty}, Legal);
+
+ setAction({G_SELECT, 1, s1}, Legal);
+
+ // Pointer-handling
+ setAction({G_FRAME_INDEX, p0}, Legal);
+ setAction({G_GLOBAL_VALUE, p0}, Legal);
+
+ for (auto Ty : {s1, s8, s16, s32, s64})
+ setAction({G_PTRTOINT, 0, Ty}, Legal);
+
+ setAction({G_PTRTOINT, 1, p0}, Legal);
+
+ setAction({G_INTTOPTR, 0, p0}, Legal);
+ setAction({G_INTTOPTR, 1, s64}, Legal);
+
+ // Casts for 32 and 64-bit width type are just copies.
+ for (auto Ty : {s1, s8, s16, s32, s64}) {
+ setAction({G_BITCAST, 0, Ty}, Legal);
+ setAction({G_BITCAST, 1, Ty}, Legal);
+ }
+
+ // For the sake of copying bits around, the type does not really
+ // matter as long as it fits a register.
+ for (int EltSize = 8; EltSize <= 64; EltSize *= 2) {
+ setAction({G_BITCAST, 0, LLT::vector(128/EltSize, EltSize)}, Legal);
+ setAction({G_BITCAST, 1, LLT::vector(128/EltSize, EltSize)}, Legal);
+ if (EltSize >= 64)
+ continue;
+
+ setAction({G_BITCAST, 0, LLT::vector(64/EltSize, EltSize)}, Legal);
+ setAction({G_BITCAST, 1, LLT::vector(64/EltSize, EltSize)}, Legal);
+ if (EltSize >= 32)
+ continue;
+
+ setAction({G_BITCAST, 0, LLT::vector(32/EltSize, EltSize)}, Legal);
+ setAction({G_BITCAST, 1, LLT::vector(32/EltSize, EltSize)}, Legal);
+ }
+
+ computeTables();
+}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.h
new file mode 100644
index 0000000..feacbef
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64LegalizerInfo.h
@@ -0,0 +1,30 @@
+//===- AArch64LegalizerInfo --------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares the targeting of the Machinelegalizer class for
+/// AArch64.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINELEGALIZER_H
+#define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINELEGALIZER_H
+
+#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
+
+namespace llvm {
+
+class LLVMContext;
+
+/// This class provides the information for the target register banks.
+class AArch64LegalizerInfo : public LegalizerInfo {
+public:
+ AArch64LegalizerInfo();
+};
+} // End llvm namespace.
+#endif
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
index dd2ea6a..8e312dc 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
@@ -38,7 +38,6 @@ STATISTIC(NumPostFolded, "Number of post-index updates folded");
STATISTIC(NumPreFolded, "Number of pre-index updates folded");
STATISTIC(NumUnscaledPairCreated,
"Number of load/store from unscaled generated");
-STATISTIC(NumNarrowLoadsPromoted, "Number of narrow loads promoted");
STATISTIC(NumZeroStoresPromoted, "Number of narrow zero stores promoted");
STATISTIC(NumLoadsFromStoresPromoted, "Number of loads from stores promoted");
@@ -51,14 +50,6 @@ static cl::opt<unsigned> LdStLimit("aarch64-load-store-scan-limit",
static cl::opt<unsigned> UpdateLimit("aarch64-update-scan-limit", cl::init(100),
cl::Hidden);
-static cl::opt<bool> EnableNarrowLdMerge("enable-narrow-ld-merge", cl::Hidden,
- cl::init(false),
- cl::desc("Enable narrow load merge"));
-
-namespace llvm {
-void initializeAArch64LoadStoreOptPass(PassRegistry &);
-}
-
#define AARCH64_LOAD_STORE_OPT_NAME "AArch64 load / store optimization pass"
namespace {
@@ -111,11 +102,11 @@ struct AArch64LoadStoreOpt : public MachineFunctionPass {
bool findMatchingStore(MachineBasicBlock::iterator I, unsigned Limit,
MachineBasicBlock::iterator &StoreI);
- // Merge the two instructions indicated into a wider instruction.
+ // Merge the two instructions indicated into a wider narrow store instruction.
MachineBasicBlock::iterator
- mergeNarrowInsns(MachineBasicBlock::iterator I,
- MachineBasicBlock::iterator MergeMI,
- const LdStPairFlags &Flags);
+ mergeNarrowZeroStores(MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator MergeMI,
+ const LdStPairFlags &Flags);
// Merge the two instructions indicated into a single pair-wise instruction.
MachineBasicBlock::iterator
@@ -151,8 +142,8 @@ struct AArch64LoadStoreOpt : public MachineFunctionPass {
mergeUpdateInsn(MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Update, bool IsPreIdx);
- // Find and merge foldable ldr/str instructions.
- bool tryToMergeLdStInst(MachineBasicBlock::iterator &MBBI);
+ // Find and merge zero store instructions.
+ bool tryToMergeZeroStInst(MachineBasicBlock::iterator &MBBI);
// Find and pair ldr/str instructions.
bool tryToPairLdStInst(MachineBasicBlock::iterator &MBBI);
@@ -160,18 +151,16 @@ struct AArch64LoadStoreOpt : public MachineFunctionPass {
// Find and promote load instructions which read directly from store.
bool tryToPromoteLoadFromStore(MachineBasicBlock::iterator &MBBI);
- bool optimizeBlock(MachineBasicBlock &MBB, bool enableNarrowLdOpt);
+ bool optimizeBlock(MachineBasicBlock &MBB, bool EnableNarrowZeroStOpt);
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
- return AARCH64_LOAD_STORE_OPT_NAME;
- }
+ StringRef getPassName() const override { return AARCH64_LOAD_STORE_OPT_NAME; }
};
char AArch64LoadStoreOpt::ID = 0;
} // namespace
@@ -179,23 +168,6 @@ char AArch64LoadStoreOpt::ID = 0;
INITIALIZE_PASS(AArch64LoadStoreOpt, "aarch64-ldst-opt",
AARCH64_LOAD_STORE_OPT_NAME, false, false)
-static unsigned getBitExtrOpcode(MachineInstr &MI) {
- switch (MI.getOpcode()) {
- default:
- llvm_unreachable("Unexpected opcode.");
- case AArch64::LDRBBui:
- case AArch64::LDURBBi:
- case AArch64::LDRHHui:
- case AArch64::LDURHHi:
- return AArch64::UBFMWri;
- case AArch64::LDRSBWui:
- case AArch64::LDURSBWi:
- case AArch64::LDRSHWui:
- case AArch64::LDURSHWi:
- return AArch64::SBFMWri;
- }
-}
-
static bool isNarrowStore(unsigned Opc) {
switch (Opc) {
default:
@@ -208,30 +180,6 @@ static bool isNarrowStore(unsigned Opc) {
}
}
-static bool isNarrowLoad(unsigned Opc) {
- switch (Opc) {
- default:
- return false;
- case AArch64::LDRHHui:
- case AArch64::LDURHHi:
- case AArch64::LDRBBui:
- case AArch64::LDURBBi:
- case AArch64::LDRSHWui:
- case AArch64::LDURSHWi:
- case AArch64::LDRSBWui:
- case AArch64::LDURSBWi:
- return true;
- }
-}
-
-static bool isNarrowLoad(MachineInstr &MI) {
- return isNarrowLoad(MI.getOpcode());
-}
-
-static bool isNarrowLoadOrStore(unsigned Opc) {
- return isNarrowLoad(Opc) || isNarrowStore(Opc);
-}
-
// Scaling factor for unscaled load or store.
static int getMemScale(MachineInstr &MI) {
switch (MI.getOpcode()) {
@@ -323,23 +271,11 @@ static unsigned getMatchingNonSExtOpcode(unsigned Opc,
case AArch64::STURSi:
case AArch64::LDRSui:
case AArch64::LDURSi:
- case AArch64::LDRHHui:
- case AArch64::LDURHHi:
- case AArch64::LDRBBui:
- case AArch64::LDURBBi:
return Opc;
case AArch64::LDRSWui:
return AArch64::LDRWui;
case AArch64::LDURSWi:
return AArch64::LDURWi;
- case AArch64::LDRSBWui:
- return AArch64::LDRBBui;
- case AArch64::LDRSHWui:
- return AArch64::LDRHHui;
- case AArch64::LDURSBWi:
- return AArch64::LDURBBi;
- case AArch64::LDURSHWi:
- return AArch64::LDURHHi;
}
}
@@ -359,18 +295,6 @@ static unsigned getMatchingWideOpcode(unsigned Opc) {
return AArch64::STURXi;
case AArch64::STRWui:
return AArch64::STRXui;
- case AArch64::LDRHHui:
- case AArch64::LDRSHWui:
- return AArch64::LDRWui;
- case AArch64::LDURHHi:
- case AArch64::LDURSHWi:
- return AArch64::LDURWi;
- case AArch64::LDRBBui:
- case AArch64::LDRSBWui:
- return AArch64::LDRHHui;
- case AArch64::LDURBBi:
- case AArch64::LDURSBWi:
- return AArch64::LDURHHi;
}
}
@@ -614,23 +538,20 @@ static bool isLdOffsetInRangeOfSt(MachineInstr &LoadInst,
(UnscaledLdOffset + LoadSize <= (UnscaledStOffset + StoreSize));
}
-static bool isPromotableZeroStoreOpcode(unsigned Opc) {
- return isNarrowStore(Opc) || Opc == AArch64::STRWui || Opc == AArch64::STURWi;
-}
-
-static bool isPromotableZeroStoreOpcode(MachineInstr &MI) {
- return isPromotableZeroStoreOpcode(MI.getOpcode());
-}
-
static bool isPromotableZeroStoreInst(MachineInstr &MI) {
- return (isPromotableZeroStoreOpcode(MI)) &&
+ unsigned Opc = MI.getOpcode();
+ return (Opc == AArch64::STRWui || Opc == AArch64::STURWi ||
+ isNarrowStore(Opc)) &&
getLdStRegOp(MI).getReg() == AArch64::WZR;
}
MachineBasicBlock::iterator
-AArch64LoadStoreOpt::mergeNarrowInsns(MachineBasicBlock::iterator I,
- MachineBasicBlock::iterator MergeMI,
- const LdStPairFlags &Flags) {
+AArch64LoadStoreOpt::mergeNarrowZeroStores(MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator MergeMI,
+ const LdStPairFlags &Flags) {
+ assert(isPromotableZeroStoreInst(*I) && isPromotableZeroStoreInst(*MergeMI) &&
+ "Expected promotable zero stores.");
+
MachineBasicBlock::iterator NextI = I;
++NextI;
// If NextI is the second of the two instructions to be merged, we need
@@ -654,15 +575,12 @@ AArch64LoadStoreOpt::mergeNarrowInsns(MachineBasicBlock::iterator I,
MergeForward ? getLdStBaseOp(*MergeMI) : getLdStBaseOp(*I);
// Which register is Rt and which is Rt2 depends on the offset order.
- MachineInstr *RtMI, *Rt2MI;
+ MachineInstr *RtMI;
if (getLdStOffsetOp(*I).getImm() ==
- getLdStOffsetOp(*MergeMI).getImm() + OffsetStride) {
+ getLdStOffsetOp(*MergeMI).getImm() + OffsetStride)
RtMI = &*MergeMI;
- Rt2MI = &*I;
- } else {
+ else
RtMI = &*I;
- Rt2MI = &*MergeMI;
- }
int OffsetImm = getLdStOffsetOp(*RtMI).getImm();
// Change the scaled offset from small to large type.
@@ -671,105 +589,9 @@ AArch64LoadStoreOpt::mergeNarrowInsns(MachineBasicBlock::iterator I,
OffsetImm /= 2;
}
+ // Construct the new instruction.
DebugLoc DL = I->getDebugLoc();
MachineBasicBlock *MBB = I->getParent();
- if (isNarrowLoad(Opc)) {
- MachineInstr *RtNewDest = &*(MergeForward ? I : MergeMI);
- // When merging small (< 32 bit) loads for big-endian targets, the order of
- // the component parts gets swapped.
- if (!Subtarget->isLittleEndian())
- std::swap(RtMI, Rt2MI);
- // Construct the new load instruction.
- MachineInstr *NewMemMI, *BitExtMI1, *BitExtMI2;
- NewMemMI =
- BuildMI(*MBB, InsertionPoint, DL, TII->get(getMatchingWideOpcode(Opc)))
- .addOperand(getLdStRegOp(*RtNewDest))
- .addOperand(BaseRegOp)
- .addImm(OffsetImm)
- .setMemRefs(I->mergeMemRefsWith(*MergeMI));
- (void)NewMemMI;
-
- DEBUG(
- dbgs()
- << "Creating the new load and extract. Replacing instructions:\n ");
- DEBUG(I->print(dbgs()));
- DEBUG(dbgs() << " ");
- DEBUG(MergeMI->print(dbgs()));
- DEBUG(dbgs() << " with instructions:\n ");
- DEBUG((NewMemMI)->print(dbgs()));
-
- int Width = getMemScale(*I) == 1 ? 8 : 16;
- int LSBLow = 0;
- int LSBHigh = Width;
- int ImmsLow = LSBLow + Width - 1;
- int ImmsHigh = LSBHigh + Width - 1;
- MachineInstr *ExtDestMI = &*(MergeForward ? MergeMI : I);
- if ((ExtDestMI == Rt2MI) == Subtarget->isLittleEndian()) {
- // Create the bitfield extract for high bits.
- BitExtMI1 =
- BuildMI(*MBB, InsertionPoint, DL, TII->get(getBitExtrOpcode(*Rt2MI)))
- .addOperand(getLdStRegOp(*Rt2MI))
- .addReg(getLdStRegOp(*RtNewDest).getReg())
- .addImm(LSBHigh)
- .addImm(ImmsHigh);
- // Create the bitfield extract for low bits.
- if (RtMI->getOpcode() == getMatchingNonSExtOpcode(RtMI->getOpcode())) {
- // For unsigned, prefer to use AND for low bits.
- BitExtMI2 = BuildMI(*MBB, InsertionPoint, DL, TII->get(AArch64::ANDWri))
- .addOperand(getLdStRegOp(*RtMI))
- .addReg(getLdStRegOp(*RtNewDest).getReg())
- .addImm(ImmsLow);
- } else {
- BitExtMI2 =
- BuildMI(*MBB, InsertionPoint, DL, TII->get(getBitExtrOpcode(*RtMI)))
- .addOperand(getLdStRegOp(*RtMI))
- .addReg(getLdStRegOp(*RtNewDest).getReg())
- .addImm(LSBLow)
- .addImm(ImmsLow);
- }
- } else {
- // Create the bitfield extract for low bits.
- if (RtMI->getOpcode() == getMatchingNonSExtOpcode(RtMI->getOpcode())) {
- // For unsigned, prefer to use AND for low bits.
- BitExtMI1 = BuildMI(*MBB, InsertionPoint, DL, TII->get(AArch64::ANDWri))
- .addOperand(getLdStRegOp(*RtMI))
- .addReg(getLdStRegOp(*RtNewDest).getReg())
- .addImm(ImmsLow);
- } else {
- BitExtMI1 =
- BuildMI(*MBB, InsertionPoint, DL, TII->get(getBitExtrOpcode(*RtMI)))
- .addOperand(getLdStRegOp(*RtMI))
- .addReg(getLdStRegOp(*RtNewDest).getReg())
- .addImm(LSBLow)
- .addImm(ImmsLow);
- }
-
- // Create the bitfield extract for high bits.
- BitExtMI2 =
- BuildMI(*MBB, InsertionPoint, DL, TII->get(getBitExtrOpcode(*Rt2MI)))
- .addOperand(getLdStRegOp(*Rt2MI))
- .addReg(getLdStRegOp(*RtNewDest).getReg())
- .addImm(LSBHigh)
- .addImm(ImmsHigh);
- }
- (void)BitExtMI1;
- (void)BitExtMI2;
-
- DEBUG(dbgs() << " ");
- DEBUG((BitExtMI1)->print(dbgs()));
- DEBUG(dbgs() << " ");
- DEBUG((BitExtMI2)->print(dbgs()));
- DEBUG(dbgs() << "\n");
-
- // Erase the old instructions.
- I->eraseFromParent();
- MergeMI->eraseFromParent();
- return NextI;
- }
- assert(isPromotableZeroStoreInst(*I) && isPromotableZeroStoreInst(*MergeMI) &&
- "Expected promotable zero store");
-
- // Construct the new instruction.
MachineInstrBuilder MIB;
MIB = BuildMI(*MBB, InsertionPoint, DL, TII->get(getMatchingWideOpcode(Opc)))
.addReg(isNarrowStore(Opc) ? AArch64::WZR : AArch64::XZR)
@@ -778,7 +600,7 @@ AArch64LoadStoreOpt::mergeNarrowInsns(MachineBasicBlock::iterator I,
.setMemRefs(I->mergeMemRefsWith(*MergeMI));
(void)MIB;
- DEBUG(dbgs() << "Creating wider load/store. Replacing instructions:\n ");
+ DEBUG(dbgs() << "Creating wider store. Replacing instructions:\n ");
DEBUG(I->print(dbgs()));
DEBUG(dbgs() << " ");
DEBUG(MergeMI->print(dbgs()));
@@ -865,9 +687,30 @@ AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
MachineInstrBuilder MIB;
DebugLoc DL = I->getDebugLoc();
MachineBasicBlock *MBB = I->getParent();
+ MachineOperand RegOp0 = getLdStRegOp(*RtMI);
+ MachineOperand RegOp1 = getLdStRegOp(*Rt2MI);
+ // Kill flags may become invalid when moving stores for pairing.
+ if (RegOp0.isUse()) {
+ if (!MergeForward) {
+ // Clear kill flags on store if moving upwards. Example:
+ // STRWui %w0, ...
+ // USE %w1
+ // STRWui kill %w1 ; need to clear kill flag when moving STRWui upwards
+ RegOp0.setIsKill(false);
+ RegOp1.setIsKill(false);
+ } else {
+ // Clear kill flags of the first stores register. Example:
+ // STRWui %w1, ...
+ // USE kill %w1 ; need to clear kill flag when moving STRWui downwards
+ // STRW %w0
+ unsigned Reg = getLdStRegOp(*I).getReg();
+ for (MachineInstr &MI : make_range(std::next(I), Paired))
+ MI.clearRegisterKills(Reg, TRI);
+ }
+ }
MIB = BuildMI(*MBB, InsertionPoint, DL, TII->get(getMatchingPairOpcode(Opc)))
- .addOperand(getLdStRegOp(*RtMI))
- .addOperand(getLdStRegOp(*Rt2MI))
+ .addOperand(RegOp0)
+ .addOperand(RegOp1)
.addOperand(BaseRegOp)
.addImm(OffsetImm)
.setMemRefs(I->mergeMemRefsWith(*Paired));
@@ -945,6 +788,7 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI,
// Remove the load, if the destination register of the loads is the same
// register for stored value.
if (StRt == LdRt && LoadSize == 8) {
+ StoreI->clearRegisterKills(StRt, TRI);
DEBUG(dbgs() << "Remove load instruction:\n ");
DEBUG(LoadI->print(dbgs()));
DEBUG(dbgs() << "\n");
@@ -1009,7 +853,11 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI,
.addImm(Imms);
}
}
- (void)BitExtMI;
+
+ // Clear kill flags between store and load.
+ for (MachineInstr &MI : make_range(StoreI->getIterator(),
+ BitExtMI->getIterator()))
+ MI.clearRegisterKills(StRt, TRI);
DEBUG(dbgs() << "Promoting load by replacing :\n ");
DEBUG(StoreI->print(dbgs()));
@@ -1041,8 +889,10 @@ static void trackRegDefsUses(const MachineInstr &MI, BitVector &ModifiedRegs,
if (!Reg)
continue;
if (MO.isDef()) {
- for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
- ModifiedRegs.set(*AI);
+ // WZR/XZR are not modified even when used as a destination register.
+ if (Reg != AArch64::WZR && Reg != AArch64::XZR)
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
+ ModifiedRegs.set(*AI);
} else {
assert(MO.isUse() && "Reg operand not a def and not a use?!?");
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
@@ -1118,8 +968,9 @@ bool AArch64LoadStoreOpt::findMatchingStore(
--MBBI;
MachineInstr &MI = *MBBI;
- // Don't count DBG_VALUE instructions towards the search limit.
- if (!MI.isDebugValue())
+ // Don't count transient instructions towards the search limit since there
+ // may be different numbers of them if e.g. debug information is present.
+ if (!MI.isTransient())
++Count;
// If the load instruction reads directly from the address to which the
@@ -1184,13 +1035,14 @@ static bool areCandidatesToMergeOrPair(MachineInstr &FirstMI, MachineInstr &MI,
return true;
}
- // If the second instruction isn't even a load/store, bail out.
+ // If the second instruction isn't even a mergable/pairable load/store, bail
+ // out.
if (!PairIsValidLdStrOpc)
return false;
- // FIXME: We don't support merging narrow loads/stores with mixed
- // scaled/unscaled offsets.
- if (isNarrowLoadOrStore(OpcA) || isNarrowLoadOrStore(OpcB))
+ // FIXME: We don't support merging narrow stores with mixed scaled/unscaled
+ // offsets.
+ if (isNarrowStore(OpcA) || isNarrowStore(OpcB))
return false;
// Try to match an unscaled load/store with a scaled load/store.
@@ -1229,13 +1081,11 @@ AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
for (unsigned Count = 0; MBBI != E && Count < Limit; ++MBBI) {
MachineInstr &MI = *MBBI;
- // Skip DBG_VALUE instructions. Otherwise debug info can affect the
- // optimization by changing how far we scan.
- if (MI.isDebugValue())
- continue;
- // Now that we know this is a real instruction, count it.
- ++Count;
+ // Don't count transient instructions towards the search limit since there
+ // may be different numbers of them if e.g. debug information is present.
+ if (!MI.isTransient())
+ ++Count;
Flags.setSExtIdx(-1);
if (areCandidatesToMergeOrPair(FirstMI, MI, Flags, TII) &&
@@ -1505,12 +1355,11 @@ MachineBasicBlock::iterator AArch64LoadStoreOpt::findMatchingUpdateInsnForward(
++MBBI;
for (unsigned Count = 0; MBBI != E && Count < Limit; ++MBBI) {
MachineInstr &MI = *MBBI;
- // Skip DBG_VALUE instructions.
- if (MI.isDebugValue())
- continue;
- // Now that we know this is a real instruction, count it.
- ++Count;
+ // Don't count transient instructions towards the search limit since there
+ // may be different numbers of them if e.g. debug information is present.
+ if (!MI.isTransient())
+ ++Count;
// If we found a match, return it.
if (isMatchingUpdateInsn(*I, MI, BaseReg, UnscaledOffset))
@@ -1559,8 +1408,9 @@ MachineBasicBlock::iterator AArch64LoadStoreOpt::findMatchingUpdateInsnBackward(
--MBBI;
MachineInstr &MI = *MBBI;
- // Don't count DBG_VALUE instructions towards the search limit.
- if (!MI.isDebugValue())
+ // Don't count transient instructions towards the search limit since there
+ // may be different numbers of them if e.g. debug information is present.
+ if (!MI.isTransient())
++Count;
// If we found a match, return it.
@@ -1603,37 +1453,26 @@ bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
return false;
}
-// Find narrow loads that can be converted into a single wider load with
-// bitfield extract instructions. Also merge adjacent zero stores into a wider
-// store.
-bool AArch64LoadStoreOpt::tryToMergeLdStInst(
+// Merge adjacent zero stores into a wider store.
+bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
MachineBasicBlock::iterator &MBBI) {
- assert((isNarrowLoad(*MBBI) || isPromotableZeroStoreOpcode(*MBBI)) &&
- "Expected narrow op.");
+ assert(isPromotableZeroStoreInst(*MBBI) && "Expected narrow store.");
MachineInstr &MI = *MBBI;
MachineBasicBlock::iterator E = MI.getParent()->end();
if (!TII->isCandidateToMergeOrPair(MI))
return false;
- // For promotable zero stores, the stored value should be WZR.
- if (isPromotableZeroStoreOpcode(MI) &&
- getLdStRegOp(MI).getReg() != AArch64::WZR)
- return false;
-
// Look ahead up to LdStLimit instructions for a mergable instruction.
LdStPairFlags Flags;
MachineBasicBlock::iterator MergeMI =
findMatchingInsn(MBBI, Flags, LdStLimit, /* FindNarrowMerge = */ true);
if (MergeMI != E) {
- if (isNarrowLoad(MI)) {
- ++NumNarrowLoadsPromoted;
- } else if (isPromotableZeroStoreInst(MI)) {
- ++NumZeroStoresPromoted;
- }
+ ++NumZeroStoresPromoted;
+
// Keeping the iterator straight is a pain, so we let the merge routine tell
// us what the next instruction is after it's done mucking about.
- MBBI = mergeNarrowInsns(MBBI, MergeMI, Flags);
+ MBBI = mergeNarrowZeroStores(MBBI, MergeMI, Flags);
return true;
}
return false;
@@ -1654,6 +1493,9 @@ bool AArch64LoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
bool IsUnscaled = TII->isUnscaledLdSt(MI);
int Offset = getLdStOffsetOp(MI).getImm();
int OffsetStride = IsUnscaled ? getMemScale(MI) : 1;
+ // Allow one more for offset.
+ if (Offset > 0)
+ Offset -= OffsetStride;
if (!inBoundsForPair(IsUnscaled, Offset, OffsetStride))
return false;
@@ -1674,7 +1516,7 @@ bool AArch64LoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) {
}
bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
- bool enableNarrowLdOpt) {
+ bool EnableNarrowZeroStOpt) {
bool Modified = false;
// Four tranformations to do here:
// 1) Find loads that directly read from stores and promote them by
@@ -1713,29 +1555,21 @@ bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
}
}
}
- // 2) Find narrow loads that can be converted into a single wider load
- // with bitfield extract instructions.
- // e.g.,
- // ldrh w0, [x2]
- // ldrh w1, [x2, #2]
- // ; becomes
- // ldr w0, [x2]
- // ubfx w1, w0, #16, #16
- // and w0, w0, #ffff
- //
- // Also merge adjacent zero stores into a wider store.
+ // 2) Merge adjacent zero stores into a wider store.
// e.g.,
// strh wzr, [x0]
// strh wzr, [x0, #2]
// ; becomes
// str wzr, [x0]
+ // e.g.,
+ // str wzr, [x0]
+ // str wzr, [x0, #4]
+ // ; becomes
+ // str xzr, [x0]
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
- enableNarrowLdOpt && MBBI != E;) {
- MachineInstr &MI = *MBBI;
- unsigned Opc = MI.getOpcode();
- if (isPromotableZeroStoreOpcode(Opc) ||
- (EnableNarrowLdMerge && isNarrowLoad(Opc))) {
- if (tryToMergeLdStInst(MBBI)) {
+ EnableNarrowZeroStOpt && MBBI != E;) {
+ if (isPromotableZeroStoreInst(*MBBI)) {
+ if (tryToMergeZeroStInst(MBBI)) {
Modified = true;
} else
++MBBI;
@@ -1752,44 +1586,10 @@ bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
// ldp x0, x1, [x2]
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
MBBI != E;) {
- MachineInstr &MI = *MBBI;
- switch (MI.getOpcode()) {
- default:
- // Just move on to the next instruction.
- ++MBBI;
- break;
- // Scaled instructions.
- case AArch64::STRSui:
- case AArch64::STRDui:
- case AArch64::STRQui:
- case AArch64::STRXui:
- case AArch64::STRWui:
- case AArch64::LDRSui:
- case AArch64::LDRDui:
- case AArch64::LDRQui:
- case AArch64::LDRXui:
- case AArch64::LDRWui:
- case AArch64::LDRSWui:
- // Unscaled instructions.
- case AArch64::STURSi:
- case AArch64::STURDi:
- case AArch64::STURQi:
- case AArch64::STURWi:
- case AArch64::STURXi:
- case AArch64::LDURSi:
- case AArch64::LDURDi:
- case AArch64::LDURQi:
- case AArch64::LDURWi:
- case AArch64::LDURXi:
- case AArch64::LDURSWi: {
- if (tryToPairLdStInst(MBBI)) {
- Modified = true;
- break;
- }
+ if (TII->isPairableLdStInst(*MBBI) && tryToPairLdStInst(MBBI))
+ Modified = true;
+ else
++MBBI;
- break;
- }
- }
}
// 4) Find base register updates that can be merged into the load or store
// as a base-reg writeback.
@@ -1930,16 +1730,17 @@ bool AArch64LoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
UsedRegs.resize(TRI->getNumRegs());
bool Modified = false;
- bool enableNarrowLdOpt =
- Subtarget->mergeNarrowLoads() && !Subtarget->requiresStrictAlign();
+ bool enableNarrowZeroStOpt = !Subtarget->requiresStrictAlign();
for (auto &MBB : Fn)
- Modified |= optimizeBlock(MBB, enableNarrowLdOpt);
+ Modified |= optimizeBlock(MBB, enableNarrowZeroStOpt);
return Modified;
}
-// FIXME: Do we need/want a pre-alloc pass like ARM has to try to keep
-// loads and stores near one another?
+// FIXME: Do we need/want a pre-alloc pass like ARM has to try to keep loads and
+// stores near one another? Note: The pre-RA instruction scheduler already has
+// hooks to try and schedule pairable loads/stores together to improve pairing
+// opportunities. Thus, pre-RA pairing pass may not be worth the effort.
// FIXME: When pairing store instructions it's very possible for this pass to
// hoist a store with a KILL marker above another use (without a KILL marker).
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp b/contrib/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
index 2b4cdf1..45083df 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp
@@ -29,7 +29,7 @@ using namespace llvm;
extern cl::opt<bool> EnableAArch64ELFLocalDynamicTLSGeneration;
AArch64MCInstLower::AArch64MCInstLower(MCContext &ctx, AsmPrinter &printer)
- : Ctx(ctx), Printer(printer), TargetTriple(printer.getTargetTriple()) {}
+ : Ctx(ctx), Printer(printer) {}
MCSymbol *
AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
@@ -153,10 +153,11 @@ MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO,
MCOperand AArch64MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
MCSymbol *Sym) const {
- if (TargetTriple.isOSDarwin())
+ if (Printer.TM.getTargetTriple().isOSDarwin())
return lowerSymbolOperandDarwin(MO, Sym);
- assert(TargetTriple.isOSBinFormatELF() && "Expect Darwin or ELF target");
+ assert(Printer.TM.getTargetTriple().isOSBinFormatELF() &&
+ "Expect Darwin or ELF target");
return lowerSymbolOperandELF(MO, Sym);
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 49e7767..f0bffe5 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -14,17 +14,18 @@
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEFUNCTIONINFO_H
#define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEFUNCTIONINFO_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/MC/MCLinkerOptimizationHint.h"
+#include <cassert>
namespace llvm {
/// AArch64FunctionInfo - This class is derived from MachineFunctionInfo and
/// contains private AArch64-specific information for each MachineFunction.
-class AArch64FunctionInfo : public MachineFunctionInfo {
-
+class AArch64FunctionInfo final : public MachineFunctionInfo {
/// Number of bytes of arguments this function has on the stack. If the callee
/// is expected to restore the argument stack this should be a multiple of 16,
/// all usable during a tail call.
@@ -34,16 +35,16 @@ class AArch64FunctionInfo : public MachineFunctionInfo {
/// space to a function with 16-bytes then misalignment of this value would
/// make a stack adjustment necessary, which could not be undone by the
/// callee.
- unsigned BytesInStackArgArea;
+ unsigned BytesInStackArgArea = 0;
/// The number of bytes to restore to deallocate space for incoming
/// arguments. Canonically 0 in the C calling convention, but non-zero when
/// callee is expected to pop the args.
- unsigned ArgumentStackToRestore;
+ unsigned ArgumentStackToRestore = 0;
/// HasStackFrame - True if this function has a stack frame. Set by
/// determineCalleeSaves().
- bool HasStackFrame;
+ bool HasStackFrame = false;
/// \brief Amount of stack frame size, not including callee-saved registers.
unsigned LocalStackSize;
@@ -53,54 +54,44 @@ class AArch64FunctionInfo : public MachineFunctionInfo {
/// \brief Number of TLS accesses using the special (combinable)
/// _TLS_MODULE_BASE_ symbol.
- unsigned NumLocalDynamicTLSAccesses;
+ unsigned NumLocalDynamicTLSAccesses = 0;
/// \brief FrameIndex for start of varargs area for arguments passed on the
/// stack.
- int VarArgsStackIndex;
+ int VarArgsStackIndex = 0;
/// \brief FrameIndex for start of varargs area for arguments passed in
/// general purpose registers.
- int VarArgsGPRIndex;
+ int VarArgsGPRIndex = 0;
/// \brief Size of the varargs area for arguments passed in general purpose
/// registers.
- unsigned VarArgsGPRSize;
+ unsigned VarArgsGPRSize = 0;
/// \brief FrameIndex for start of varargs area for arguments passed in
/// floating-point registers.
- int VarArgsFPRIndex;
+ int VarArgsFPRIndex = 0;
/// \brief Size of the varargs area for arguments passed in floating-point
/// registers.
- unsigned VarArgsFPRSize;
+ unsigned VarArgsFPRSize = 0;
/// True if this function has a subset of CSRs that is handled explicitly via
/// copies.
- bool IsSplitCSR;
+ bool IsSplitCSR = false;
/// True when the stack gets realigned dynamically because the size of stack
/// frame is unknown at compile time. e.g., in case of VLAs.
- bool StackRealigned;
+ bool StackRealigned = false;
/// True when the callee-save stack area has unused gaps that may be used for
/// other stack allocations.
- bool CalleeSaveStackHasFreeSpace;
+ bool CalleeSaveStackHasFreeSpace = false;
public:
- AArch64FunctionInfo()
- : BytesInStackArgArea(0), ArgumentStackToRestore(0), HasStackFrame(false),
- NumLocalDynamicTLSAccesses(0), VarArgsStackIndex(0), VarArgsGPRIndex(0),
- VarArgsGPRSize(0), VarArgsFPRIndex(0), VarArgsFPRSize(0),
- IsSplitCSR(false), StackRealigned(false),
- CalleeSaveStackHasFreeSpace(false) {}
-
- explicit AArch64FunctionInfo(MachineFunction &MF)
- : BytesInStackArgArea(0), ArgumentStackToRestore(0), HasStackFrame(false),
- NumLocalDynamicTLSAccesses(0), VarArgsStackIndex(0), VarArgsGPRIndex(0),
- VarArgsGPRSize(0), VarArgsFPRIndex(0), VarArgsFPRSize(0),
- IsSplitCSR(false), StackRealigned(false),
- CalleeSaveStackHasFreeSpace(false) {
+ AArch64FunctionInfo() = default;
+
+ explicit AArch64FunctionInfo(MachineFunction &MF) {
(void)MF;
}
@@ -193,6 +184,7 @@ private:
MILOHContainer LOHContainerSet;
SetOfInstructions LOHRelated;
};
-} // End llvm namespace
-#endif
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEFUNCTIONINFO_H
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64PromoteConstant.cpp b/contrib/llvm/lib/Target/AArch64/AArch64PromoteConstant.cpp
index b1e4051..8693f76 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64PromoteConstant.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64PromoteConstant.cpp
@@ -101,9 +101,11 @@ public:
};
static char ID;
- AArch64PromoteConstant() : ModulePass(ID) {}
+ AArch64PromoteConstant() : ModulePass(ID) {
+ initializeAArch64PromoteConstantPass(*PassRegistry::getPassRegistry());
+ }
- const char *getPassName() const override { return "AArch64 Promote Constant"; }
+ StringRef getPassName() const override { return "AArch64 Promote Constant"; }
/// Iterate over the functions and promote the interesting constants into
/// global variables with module scope.
@@ -214,10 +216,6 @@ private:
char AArch64PromoteConstant::ID = 0;
-namespace llvm {
-void initializeAArch64PromoteConstantPass(PassRegistry &);
-}
-
INITIALIZE_PASS_BEGIN(AArch64PromoteConstant, "aarch64-promote-const",
"AArch64 Promote Constant Pass", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp b/contrib/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
index 60d8bbd..8f45e6a 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64RedundantCopyElimination.cpp
@@ -39,10 +39,6 @@ using namespace llvm;
STATISTIC(NumCopiesRemoved, "Number of copies removed.");
-namespace llvm {
-void initializeAArch64RedundantCopyEliminationPass(PassRegistry &);
-}
-
namespace {
class AArch64RedundantCopyElimination : public MachineFunctionPass {
const MachineRegisterInfo *MRI;
@@ -50,14 +46,17 @@ class AArch64RedundantCopyElimination : public MachineFunctionPass {
public:
static char ID;
- AArch64RedundantCopyElimination() : MachineFunctionPass(ID) {}
+ AArch64RedundantCopyElimination() : MachineFunctionPass(ID) {
+ initializeAArch64RedundantCopyEliminationPass(
+ *PassRegistry::getPassRegistry());
+ }
bool optimizeCopy(MachineBasicBlock *MBB);
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AArch64 Redundant Copy Elimination";
}
};
@@ -153,13 +152,11 @@ bool AArch64RedundantCopyElimination::optimizeCopy(MachineBasicBlock *MBB) {
// CBZ/CBNZ. Conservatively mark as much as we can live.
CompBr->clearRegisterKills(SmallestDef, TRI);
- if (std::none_of(TargetRegs.begin(), TargetRegs.end(),
- [&](unsigned Reg) { return MBB->isLiveIn(Reg); }))
+ if (none_of(TargetRegs, [&](unsigned Reg) { return MBB->isLiveIn(Reg); }))
MBB->addLiveIn(TargetReg);
// Clear any kills of TargetReg between CompBr and the last removed COPY.
- for (MachineInstr &MMI :
- make_range(MBB->begin()->getIterator(), LastChange->getIterator()))
+ for (MachineInstr &MMI : make_range(MBB->begin(), LastChange))
MMI.clearRegisterKills(SmallestDef, TRI);
return true;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp
index 0a1831b..b292c9c 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp
@@ -14,11 +14,16 @@
#include "AArch64RegisterBankInfo.h"
#include "AArch64InstrInfo.h" // For XXXRegClassID.
+#include "llvm/CodeGen/LowLevelType.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
+// This file will be TableGen'ed at some point.
+#include "AArch64GenRegisterBankInfo.def"
+
using namespace llvm;
#ifndef LLVM_BUILD_GLOBAL_ISEL
@@ -26,25 +31,40 @@ using namespace llvm;
#endif
AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI)
- : RegisterBankInfo(AArch64::NumRegisterBanks) {
- // Initialize the GPR bank.
- createRegisterBank(AArch64::GPRRegBankID, "GPR");
- // The GPR register bank is fully defined by all the registers in
- // GR64all + its subclasses.
- addRegBankCoverage(AArch64::GPRRegBankID, AArch64::GPR64allRegClassID, TRI);
+ : RegisterBankInfo(AArch64::RegBanks, AArch64::NumRegisterBanks) {
+ static bool AlreadyInit = false;
+ // We have only one set of register banks, whatever the subtarget
+ // is. Therefore, the initialization of the RegBanks table should be
+ // done only once. Indeed the table of all register banks
+ // (AArch64::RegBanks) is unique in the compiler. At some point, it
+ // will get tablegen'ed and the whole constructor becomes empty.
+ if (AlreadyInit)
+ return;
+ AlreadyInit = true;
+
const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID);
(void)RBGPR;
+ assert(&AArch64::GPRRegBank == &RBGPR &&
+ "The order in RegBanks is messed up");
+
+ const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID);
+ (void)RBFPR;
+ assert(&AArch64::FPRRegBank == &RBFPR &&
+ "The order in RegBanks is messed up");
+
+ const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID);
+ (void)RBCCR;
+ assert(&AArch64::CCRRegBank == &RBCCR &&
+ "The order in RegBanks is messed up");
+
+ // The GPR register bank is fully defined by all the registers in
+ // GR64all + its subclasses.
assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) &&
"Subclass not added?");
assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit");
- // Initialize the FPR bank.
- createRegisterBank(AArch64::FPRRegBankID, "FPR");
// The FPR register bank is fully defined by all the registers in
// GR64all + its subclasses.
- addRegBankCoverage(AArch64::FPRRegBankID, AArch64::QQQQRegClassID, TRI);
- const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID);
- (void)RBFPR;
assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) &&
"Subclass not added?");
assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) &&
@@ -52,15 +72,131 @@ AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI)
assert(RBFPR.getSize() == 512 &&
"FPRs should hold up to 512-bit via QQQQ sequence");
- // Initialize the CCR bank.
- createRegisterBank(AArch64::CCRRegBankID, "CCR");
- addRegBankCoverage(AArch64::CCRRegBankID, AArch64::CCRRegClassID, TRI);
- const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID);
- (void)RBCCR;
assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) &&
"Class not added?");
assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit");
+ // Check that the TableGen'ed like file is in sync we our expectations.
+ // First, the Idx.
+ assert(AArch64::PartialMappingIdx::PMI_GPR32 ==
+ AArch64::PartialMappingIdx::PMI_FirstGPR &&
+ "GPR32 index not first in the GPR list");
+ assert(AArch64::PartialMappingIdx::PMI_GPR64 ==
+ AArch64::PartialMappingIdx::PMI_LastGPR &&
+ "GPR64 index not last in the GPR list");
+ assert(AArch64::PartialMappingIdx::PMI_FirstGPR <=
+ AArch64::PartialMappingIdx::PMI_LastGPR &&
+ "GPR list is backward");
+ assert(AArch64::PartialMappingIdx::PMI_FPR32 ==
+ AArch64::PartialMappingIdx::PMI_FirstFPR &&
+ "FPR32 index not first in the FPR list");
+ assert(AArch64::PartialMappingIdx::PMI_FPR512 ==
+ AArch64::PartialMappingIdx::PMI_LastFPR &&
+ "FPR512 index not last in the FPR list");
+ assert(AArch64::PartialMappingIdx::PMI_FirstFPR <=
+ AArch64::PartialMappingIdx::PMI_LastFPR &&
+ "FPR list is backward");
+ assert(AArch64::PartialMappingIdx::PMI_FPR32 + 1 ==
+ AArch64::PartialMappingIdx::PMI_FPR64 &&
+ AArch64::PartialMappingIdx::PMI_FPR64 + 1 ==
+ AArch64::PartialMappingIdx::PMI_FPR128 &&
+ AArch64::PartialMappingIdx::PMI_FPR128 + 1 ==
+ AArch64::PartialMappingIdx::PMI_FPR256 &&
+ AArch64::PartialMappingIdx::PMI_FPR256 + 1 ==
+ AArch64::PartialMappingIdx::PMI_FPR512 &&
+ "FPR indices not properly ordered");
+// Now, the content.
+// Check partial mapping.
+#define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \
+ do { \
+ const PartialMapping &Map = \
+ AArch64::PartMappings[AArch64::PartialMappingIdx::Idx - \
+ AArch64::PartialMappingIdx::PMI_Min]; \
+ (void)Map; \
+ assert(Map.StartIdx == ValStartIdx && Map.Length == ValLength && \
+ Map.RegBank == &RB && #Idx " is incorrectly initialized"); \
+ } while (0)
+
+ CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR);
+ CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR);
+ CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR);
+ CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR);
+ CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR);
+ CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR);
+ CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR);
+
+// Check value mapping.
+#define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \
+ do { \
+ unsigned PartialMapBaseIdx = \
+ AArch64::PartialMappingIdx::PMI_##RBName##Size - \
+ AArch64::PartialMappingIdx::PMI_Min; \
+ (void)PartialMapBaseIdx; \
+ const ValueMapping &Map = AArch64::getValueMapping( \
+ AArch64::PartialMappingIdx::PMI_First##RBName, Size)[Offset]; \
+ (void)Map; \
+ assert(Map.BreakDown == &AArch64::PartMappings[PartialMapBaseIdx] && \
+ Map.NumBreakDowns == 1 && #RBName #Size \
+ " " #Offset " is incorrectly initialized"); \
+ } while (0)
+
+#define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0)
+
+ CHECK_VALUEMAP(GPR, 32);
+ CHECK_VALUEMAP(GPR, 64);
+ CHECK_VALUEMAP(FPR, 32);
+ CHECK_VALUEMAP(FPR, 64);
+ CHECK_VALUEMAP(FPR, 128);
+ CHECK_VALUEMAP(FPR, 256);
+ CHECK_VALUEMAP(FPR, 512);
+
+// Check the value mapping for 3-operands instructions where all the operands
+// map to the same value mapping.
+#define CHECK_VALUEMAP_3OPS(RBName, Size) \
+ do { \
+ CHECK_VALUEMAP_IMPL(RBName, Size, 0); \
+ CHECK_VALUEMAP_IMPL(RBName, Size, 1); \
+ CHECK_VALUEMAP_IMPL(RBName, Size, 2); \
+ } while (0)
+
+ CHECK_VALUEMAP_3OPS(GPR, 32);
+ CHECK_VALUEMAP_3OPS(GPR, 64);
+ CHECK_VALUEMAP_3OPS(FPR, 32);
+ CHECK_VALUEMAP_3OPS(FPR, 64);
+ CHECK_VALUEMAP_3OPS(FPR, 128);
+ CHECK_VALUEMAP_3OPS(FPR, 256);
+ CHECK_VALUEMAP_3OPS(FPR, 512);
+
+#define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \
+ do { \
+ unsigned PartialMapDstIdx = \
+ AArch64::PMI_##RBNameDst##Size - AArch64::PMI_Min; \
+ unsigned PartialMapSrcIdx = \
+ AArch64::PMI_##RBNameSrc##Size - AArch64::PMI_Min; \
+ (void) PartialMapDstIdx; \
+ (void) PartialMapSrcIdx; \
+ const ValueMapping *Map = AArch64::getCopyMapping( \
+ AArch64::PMI_First##RBNameDst == AArch64::PMI_FirstGPR, \
+ AArch64::PMI_First##RBNameSrc == AArch64::PMI_FirstGPR, Size); \
+ (void) Map; \
+ assert(Map[0].BreakDown == &AArch64::PartMappings[PartialMapDstIdx] && \
+ Map[0].NumBreakDowns == 1 && #RBNameDst #Size \
+ " Dst is incorrectly initialized"); \
+ assert(Map[1].BreakDown == &AArch64::PartMappings[PartialMapSrcIdx] && \
+ Map[1].NumBreakDowns == 1 && #RBNameSrc #Size \
+ " Src is incorrectly initialized"); \
+ \
+ } while (0)
+
+ CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32);
+ CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32);
+ CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64);
+ CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64);
+ CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32);
+ CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32);
+ CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64);
+ CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64);
+
assert(verify(TRI) && "Invalid register bank information");
}
@@ -72,7 +208,16 @@ unsigned AArch64RegisterBankInfo::copyCost(const RegisterBank &A,
// Will introduce other hooks for different size:
// * extract cost.
// * build_sequence cost.
- // TODO: Add more accurate cost for FPR to/from GPR.
+
+ // Copy from (resp. to) GPR to (resp. from) FPR involves FMOV.
+ // FIXME: This should be deduced from the scheduling model.
+ if (&A == &AArch64::GPRRegBank && &B == &AArch64::FPRRegBank)
+ // FMOVXDr or FMOVWSr.
+ return 5;
+ if (&A == &AArch64::FPRRegBank && &B == &AArch64::GPRRegBank)
+ // FMOVDXr or FMOVSWr.
+ return 4;
+
return RegisterBankInfo::copyCost(A, B, Size);
}
@@ -116,15 +261,15 @@ const RegisterBank &AArch64RegisterBankInfo::getRegBankFromRegClass(
RegisterBankInfo::InstructionMappings
AArch64RegisterBankInfo::getInstrAlternativeMappings(
const MachineInstr &MI) const {
+ const MachineFunction &MF = *MI.getParent()->getParent();
+ const TargetSubtargetInfo &STI = MF.getSubtarget();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+
switch (MI.getOpcode()) {
case TargetOpcode::G_OR: {
// 32 and 64-bit or can be mapped on either FPR or
// GPR for the same cost.
- const MachineFunction &MF = *MI.getParent()->getParent();
- const TargetSubtargetInfo &STI = MF.getSubtarget();
- const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
- const MachineRegisterInfo &MRI = MF.getRegInfo();
-
unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
if (Size != 32 && Size != 64)
break;
@@ -134,14 +279,81 @@ AArch64RegisterBankInfo::getInstrAlternativeMappings(
if (MI.getNumOperands() != 3)
break;
InstructionMappings AltMappings;
- InstructionMapping GPRMapping(/*ID*/ 1, /*Cost*/ 1, /*NumOperands*/ 3);
- InstructionMapping FPRMapping(/*ID*/ 2, /*Cost*/ 1, /*NumOperands*/ 3);
- for (unsigned Idx = 0; Idx != 3; ++Idx) {
- GPRMapping.setOperandMapping(Idx, Size,
- getRegBank(AArch64::GPRRegBankID));
- FPRMapping.setOperandMapping(Idx, Size,
- getRegBank(AArch64::FPRRegBankID));
- }
+ InstructionMapping GPRMapping(
+ /*ID*/ 1, /*Cost*/ 1,
+ AArch64::getValueMapping(AArch64::PMI_FirstGPR, Size),
+ /*NumOperands*/ 3);
+ InstructionMapping FPRMapping(
+ /*ID*/ 2, /*Cost*/ 1,
+ AArch64::getValueMapping(AArch64::PMI_FirstFPR, Size),
+ /*NumOperands*/ 3);
+
+ AltMappings.emplace_back(std::move(GPRMapping));
+ AltMappings.emplace_back(std::move(FPRMapping));
+ return AltMappings;
+ }
+ case TargetOpcode::G_BITCAST: {
+ unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
+ if (Size != 32 && Size != 64)
+ break;
+
+ // If the instruction has any implicit-defs or uses,
+ // do not mess with it.
+ if (MI.getNumOperands() != 2)
+ break;
+
+ InstructionMappings AltMappings;
+ InstructionMapping GPRMapping(
+ /*ID*/ 1, /*Cost*/ 1,
+ AArch64::getCopyMapping(/*DstIsGPR*/ true, /*SrcIsGPR*/ true, Size),
+ /*NumOperands*/ 2);
+ InstructionMapping FPRMapping(
+ /*ID*/ 2, /*Cost*/ 1,
+ AArch64::getCopyMapping(/*DstIsGPR*/ false, /*SrcIsGPR*/ false, Size),
+ /*NumOperands*/ 2);
+ InstructionMapping GPRToFPRMapping(
+ /*ID*/ 3,
+ /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size),
+ AArch64::getCopyMapping(/*DstIsGPR*/ false, /*SrcIsGPR*/ true, Size),
+ /*NumOperands*/ 2);
+ InstructionMapping FPRToGPRMapping(
+ /*ID*/ 3,
+ /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size),
+ AArch64::getCopyMapping(/*DstIsGPR*/ true, /*SrcIsGPR*/ false, Size),
+ /*NumOperands*/ 2);
+
+ AltMappings.emplace_back(std::move(GPRMapping));
+ AltMappings.emplace_back(std::move(FPRMapping));
+ AltMappings.emplace_back(std::move(GPRToFPRMapping));
+ AltMappings.emplace_back(std::move(FPRToGPRMapping));
+ return AltMappings;
+ }
+ case TargetOpcode::G_LOAD: {
+ unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
+ if (Size != 64)
+ break;
+
+ // If the instruction has any implicit-defs or uses,
+ // do not mess with it.
+ if (MI.getNumOperands() != 2)
+ break;
+
+ InstructionMappings AltMappings;
+ InstructionMapping GPRMapping(
+ /*ID*/ 1, /*Cost*/ 1,
+ getOperandsMapping(
+ {AArch64::getValueMapping(AArch64::PMI_FirstGPR, Size),
+ // Addresses are GPR 64-bit.
+ AArch64::getValueMapping(AArch64::PMI_FirstGPR, 64)}),
+ /*NumOperands*/ 2);
+ InstructionMapping FPRMapping(
+ /*ID*/ 2, /*Cost*/ 1,
+ getOperandsMapping(
+ {AArch64::getValueMapping(AArch64::PMI_FirstFPR, Size),
+ // Addresses are GPR 64-bit.
+ AArch64::getValueMapping(AArch64::PMI_FirstGPR, 64)}),
+ /*NumOperands*/ 2);
+
AltMappings.emplace_back(std::move(GPRMapping));
AltMappings.emplace_back(std::move(FPRMapping));
return AltMappings;
@@ -155,10 +367,12 @@ AArch64RegisterBankInfo::getInstrAlternativeMappings(
void AArch64RegisterBankInfo::applyMappingImpl(
const OperandsMapper &OpdMapper) const {
switch (OpdMapper.getMI().getOpcode()) {
- case TargetOpcode::G_OR: {
+ case TargetOpcode::G_OR:
+ case TargetOpcode::G_BITCAST:
+ case TargetOpcode::G_LOAD: {
// Those ID must match getInstrAlternativeMappings.
- assert((OpdMapper.getInstrMapping().getID() == 1 ||
- OpdMapper.getInstrMapping().getID() == 2) &&
+ assert((OpdMapper.getInstrMapping().getID() >= 1 &&
+ OpdMapper.getInstrMapping().getID() <= 4) &&
"Don't know how to handle that ID");
return applyDefaultMapping(OpdMapper);
}
@@ -166,3 +380,193 @@ void AArch64RegisterBankInfo::applyMappingImpl(
llvm_unreachable("Don't know how to handle that operation");
}
}
+
+/// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode,
+/// having only floating-point operands.
+static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) {
+ switch (Opc) {
+ case TargetOpcode::G_FADD:
+ case TargetOpcode::G_FSUB:
+ case TargetOpcode::G_FMUL:
+ case TargetOpcode::G_FDIV:
+ case TargetOpcode::G_FCONSTANT:
+ case TargetOpcode::G_FPEXT:
+ case TargetOpcode::G_FPTRUNC:
+ return true;
+ }
+ return false;
+}
+
+RegisterBankInfo::InstructionMapping
+AArch64RegisterBankInfo::getSameKindOfOperandsMapping(const MachineInstr &MI) {
+ const unsigned Opc = MI.getOpcode();
+ const MachineFunction &MF = *MI.getParent()->getParent();
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ unsigned NumOperands = MI.getNumOperands();
+ assert(NumOperands <= 3 &&
+ "This code is for instructions with 3 or less operands");
+
+ LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+ unsigned Size = Ty.getSizeInBits();
+ bool IsFPR = Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc);
+
+#ifndef NDEBUG
+ // Make sure all the operands are using similar size and type.
+ // Should probably be checked by the machine verifier.
+ // This code won't catch cases where the number of lanes is
+ // different between the operands.
+ // If we want to go to that level of details, it is probably
+ // best to check that the types are the same, period.
+ // Currently, we just check that the register banks are the same
+ // for each types.
+ for (unsigned Idx = 1; Idx != NumOperands; ++Idx) {
+ LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg());
+ assert(AArch64::getRegBankBaseIdxOffset(OpTy.getSizeInBits()) ==
+ AArch64::getRegBankBaseIdxOffset(Size) &&
+ "Operand has incompatible size");
+ bool OpIsFPR = OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc);
+ (void)OpIsFPR;
+ assert(IsFPR == OpIsFPR && "Operand has incompatible type");
+ }
+#endif // End NDEBUG.
+
+ AArch64::PartialMappingIdx RBIdx =
+ IsFPR ? AArch64::PMI_FirstFPR : AArch64::PMI_FirstGPR;
+
+ return InstructionMapping{DefaultMappingID, 1,
+ AArch64::getValueMapping(RBIdx, Size), NumOperands};
+}
+
+RegisterBankInfo::InstructionMapping
+AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
+ const unsigned Opc = MI.getOpcode();
+ const MachineFunction &MF = *MI.getParent()->getParent();
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ // Try the default logic for non-generic instructions that are either copies
+ // or already have some operands assigned to banks.
+ if (!isPreISelGenericOpcode(Opc)) {
+ RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI);
+ if (Mapping.isValid())
+ return Mapping;
+ }
+
+ switch (Opc) {
+ // G_{F|S|U}REM are not listed because they are not legal.
+ // Arithmetic ops.
+ case TargetOpcode::G_ADD:
+ case TargetOpcode::G_SUB:
+ case TargetOpcode::G_GEP:
+ case TargetOpcode::G_MUL:
+ case TargetOpcode::G_SDIV:
+ case TargetOpcode::G_UDIV:
+ // Bitwise ops.
+ case TargetOpcode::G_AND:
+ case TargetOpcode::G_OR:
+ case TargetOpcode::G_XOR:
+ // Shifts.
+ case TargetOpcode::G_SHL:
+ case TargetOpcode::G_LSHR:
+ case TargetOpcode::G_ASHR:
+ // Floating point ops.
+ case TargetOpcode::G_FADD:
+ case TargetOpcode::G_FSUB:
+ case TargetOpcode::G_FMUL:
+ case TargetOpcode::G_FDIV:
+ return getSameKindOfOperandsMapping(MI);
+ case TargetOpcode::G_BITCAST: {
+ LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
+ unsigned Size = DstTy.getSizeInBits();
+ bool DstIsGPR = !DstTy.isVector();
+ bool SrcIsGPR = !SrcTy.isVector();
+ const RegisterBank &DstRB =
+ DstIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank;
+ const RegisterBank &SrcRB =
+ SrcIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank;
+ return InstructionMapping{DefaultMappingID, copyCost(DstRB, SrcRB, Size),
+ AArch64::getCopyMapping(DstIsGPR, SrcIsGPR, Size),
+ /*NumOperands*/ 2};
+ }
+ case TargetOpcode::G_SEQUENCE:
+ // FIXME: support this, but the generic code is really not going to do
+ // anything sane.
+ return InstructionMapping();
+ default:
+ break;
+ }
+
+ unsigned NumOperands = MI.getNumOperands();
+
+ // Track the size and bank of each register. We don't do partial mappings.
+ SmallVector<unsigned, 4> OpSize(NumOperands);
+ SmallVector<AArch64::PartialMappingIdx, 4> OpRegBankIdx(NumOperands);
+ for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
+ auto &MO = MI.getOperand(Idx);
+ if (!MO.isReg())
+ continue;
+
+ LLT Ty = MRI.getType(MO.getReg());
+ OpSize[Idx] = Ty.getSizeInBits();
+
+ // As a top-level guess, vectors go in FPRs, scalars and pointers in GPRs.
+ // For floating-point instructions, scalars go in FPRs.
+ if (Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc))
+ OpRegBankIdx[Idx] = AArch64::PMI_FirstFPR;
+ else
+ OpRegBankIdx[Idx] = AArch64::PMI_FirstGPR;
+ }
+
+ unsigned Cost = 1;
+ // Some of the floating-point instructions have mixed GPR and FPR operands:
+ // fine-tune the computed mapping.
+ switch (Opc) {
+ case TargetOpcode::G_SITOFP:
+ case TargetOpcode::G_UITOFP: {
+ OpRegBankIdx = {AArch64::PMI_FirstFPR, AArch64::PMI_FirstGPR};
+ break;
+ }
+ case TargetOpcode::G_FPTOSI:
+ case TargetOpcode::G_FPTOUI: {
+ OpRegBankIdx = {AArch64::PMI_FirstGPR, AArch64::PMI_FirstFPR};
+ break;
+ }
+ case TargetOpcode::G_FCMP: {
+ OpRegBankIdx = {AArch64::PMI_FirstGPR,
+ /* Predicate */ AArch64::PMI_None, AArch64::PMI_FirstFPR,
+ AArch64::PMI_FirstFPR};
+ break;
+ }
+ case TargetOpcode::G_BITCAST: {
+ // This is going to be a cross register bank copy and this is expensive.
+ if (OpRegBankIdx[0] != OpRegBankIdx[1])
+ Cost =
+ copyCost(*AArch64::PartMappings[OpRegBankIdx[0]].RegBank,
+ *AArch64::PartMappings[OpRegBankIdx[1]].RegBank, OpSize[0]);
+ break;
+ }
+ case TargetOpcode::G_LOAD: {
+ // Loading in vector unit is slightly more expensive.
+ // This is actually only true for the LD1R and co instructions,
+ // but anyway for the fast mode this number does not matter and
+ // for the greedy mode the cost of the cross bank copy will
+ // offset this number.
+ // FIXME: Should be derived from the scheduling model.
+ if (OpRegBankIdx[0] >= AArch64::PMI_FirstFPR)
+ Cost = 2;
+ }
+ }
+
+ // Finally construct the computed mapping.
+ RegisterBankInfo::InstructionMapping Mapping =
+ InstructionMapping{DefaultMappingID, Cost, nullptr, NumOperands};
+ SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
+ for (unsigned Idx = 0; Idx < NumOperands; ++Idx)
+ if (MI.getOperand(Idx).isReg())
+ OpdsMapping[Idx] =
+ AArch64::getValueMapping(OpRegBankIdx[Idx], OpSize[Idx]);
+
+ Mapping.setOperandsMapping(getOperandsMapping(OpdsMapping));
+ return Mapping;
+}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.h
index 907bcfd..f763235 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.h
@@ -27,43 +27,40 @@ enum {
CCRRegBankID = 2, /// Conditional register: NZCV.
NumRegisterBanks
};
+
+extern RegisterBank GPRRegBank;
+extern RegisterBank FPRRegBank;
+extern RegisterBank CCRRegBank;
} // End AArch64 namespace.
/// This class provides the information for the target register banks.
-class AArch64RegisterBankInfo : public RegisterBankInfo {
+class AArch64RegisterBankInfo final : public RegisterBankInfo {
/// See RegisterBankInfo::applyMapping.
void applyMappingImpl(const OperandsMapper &OpdMapper) const override;
+ /// Get an instruction mapping where all the operands map to
+ /// the same register bank and have similar size.
+ ///
+ /// \pre MI.getNumOperands() <= 3
+ ///
+ /// \return An InstructionMappings with a statically allocated
+ /// OperandsMapping.
+ static InstructionMapping
+ getSameKindOfOperandsMapping(const MachineInstr &MI);
+
public:
AArch64RegisterBankInfo(const TargetRegisterInfo &TRI);
- /// Get the cost of a copy from \p B to \p A, or put differently,
- /// get the cost of A = COPY B. Since register banks may cover
- /// different size, \p Size specifies what will be the size in bits
- /// that will be copied around.
- ///
- /// \note Since this is a copy, both registers have the same size.
+
unsigned copyCost(const RegisterBank &A, const RegisterBank &B,
unsigned Size) const override;
- /// Get a register bank that covers \p RC.
- ///
- /// \pre \p RC is a user-defined register class (as opposed as one
- /// generated by TableGen).
- ///
- /// \note The mapping RC -> RegBank could be built while adding the
- /// coverage for the register banks. However, we do not do it, because,
- /// at least for now, we only need this information for register classes
- /// that are used in the description of instruction. In other words,
- /// there are just a handful of them and we do not want to waste space.
- ///
- /// \todo This should be TableGen'ed.
const RegisterBank &
getRegBankFromRegClass(const TargetRegisterClass &RC) const override;
- /// Get the alternative mappings for \p MI.
- /// Alternative in the sense different from getInstrMapping.
InstructionMappings
getInstrAlternativeMappings(const MachineInstr &MI) const override;
+
+ InstructionMapping getInstrMapping(const MachineInstr &MI) const override;
};
} // End llvm namespace.
#endif
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index af867da..98fad71 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -118,26 +118,27 @@ AArch64RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
// FIXME: avoid re-calculating this every time.
BitVector Reserved(getNumRegs());
- Reserved.set(AArch64::SP);
- Reserved.set(AArch64::XZR);
- Reserved.set(AArch64::WSP);
- Reserved.set(AArch64::WZR);
+ markSuperRegs(Reserved, AArch64::SP);
+ markSuperRegs(Reserved, AArch64::XZR);
+ markSuperRegs(Reserved, AArch64::WSP);
+ markSuperRegs(Reserved, AArch64::WZR);
if (TFI->hasFP(MF) || TT.isOSDarwin()) {
- Reserved.set(AArch64::FP);
- Reserved.set(AArch64::W29);
+ markSuperRegs(Reserved, AArch64::FP);
+ markSuperRegs(Reserved, AArch64::W29);
}
if (MF.getSubtarget<AArch64Subtarget>().isX18Reserved()) {
- Reserved.set(AArch64::X18); // Platform register
- Reserved.set(AArch64::W18);
+ markSuperRegs(Reserved, AArch64::X18); // Platform register
+ markSuperRegs(Reserved, AArch64::W18);
}
if (hasBasePointer(MF)) {
- Reserved.set(AArch64::X19);
- Reserved.set(AArch64::W19);
+ markSuperRegs(Reserved, AArch64::X19);
+ markSuperRegs(Reserved, AArch64::W19);
}
+ assert(checkAllSuperRegsMarked(Reserved));
return Reserved;
}
@@ -167,6 +168,10 @@ bool AArch64RegisterInfo::isReservedReg(const MachineFunction &MF,
return false;
}
+bool AArch64RegisterInfo::isConstantPhysReg(unsigned PhysReg) const {
+ return PhysReg == AArch64::WZR || PhysReg == AArch64::XZR;
+}
+
const TargetRegisterClass *
AArch64RegisterInfo::getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const {
@@ -183,7 +188,7 @@ AArch64RegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const {
unsigned AArch64RegisterInfo::getBaseRegister() const { return AArch64::X19; }
bool AArch64RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// In the presence of variable sized objects, if the fixed stack size is
// large enough that referencing from the FP won't result in things being
@@ -192,7 +197,7 @@ bool AArch64RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
// Furthermore, if both variable sized objects are present, and the
// stack needs to be dynamically re-aligned, the base pointer is the only
// reliable way to reference the locals.
- if (MFI->hasVarSizedObjects()) {
+ if (MFI.hasVarSizedObjects()) {
if (needsStackRealignment(MF))
return true;
// Conservatively estimate whether the negative offset from the frame
@@ -202,7 +207,7 @@ bool AArch64RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
// If it's wrong, we'll materialize the constant and still get to the
// object; it's just suboptimal. Negative offsets use the unscaled
// load/store instructions, which have a 9-bit signed immediate.
- return MFI->getLocalFrameSize() >= 256;
+ return MFI.getLocalFrameSize() >= 256;
}
return false;
@@ -226,11 +231,11 @@ bool AArch64RegisterInfo::requiresVirtualBaseRegisters(
bool
AArch64RegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// AArch64FrameLowering::resolveFrameIndexReference() can always fall back
// to the stack pointer, so only put the emergency spill slot next to the
// FP when there's no better way to access it (SP or base pointer).
- return MFI->hasVarSizedObjects() && !hasBasePointer(MF);
+ return MFI.hasVarSizedObjects() && !hasBasePointer(MF);
}
bool AArch64RegisterInfo::requiresFrameIndexScavenging(
@@ -240,10 +245,10 @@ bool AArch64RegisterInfo::requiresFrameIndexScavenging(
bool
AArch64RegisterInfo::cannotEliminateFrame(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- if (MF.getTarget().Options.DisableFramePointerElim(MF) && MFI->adjustsStack())
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (MF.getTarget().Options.DisableFramePointerElim(MF) && MFI.adjustsStack())
return true;
- return MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken();
+ return MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken();
}
/// needsFrameBaseReg - Returns true if the instruction's frame index
@@ -275,7 +280,7 @@ bool AArch64RegisterInfo::needsFrameBaseReg(MachineInstr *MI,
// so it'll be negative.
MachineFunction &MF = *MI->getParent()->getParent();
const AArch64FrameLowering *TFI = getFrameLowering(MF);
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
// Estimate an offset from the frame pointer.
// Conservatively assume all GPR callee-saved registers get pushed.
@@ -285,7 +290,7 @@ bool AArch64RegisterInfo::needsFrameBaseReg(MachineInstr *MI,
// The incoming offset is relating to the SP at the start of the function,
// but when we access the local it'll be relative to the SP after local
// allocation, so adjust our SP-relative offset by that allocation size.
- Offset += MFI->getLocalFrameSize();
+ Offset += MFI.getLocalFrameSize();
// Assume that we'll have at least some spill slots allocated.
// FIXME: This is a total SWAG number. We should run some statistics
// and pick a real one.
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
index f33f788..8ce8935 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.h
@@ -24,8 +24,7 @@ class RegScavenger;
class TargetRegisterClass;
class Triple;
-struct AArch64RegisterInfo : public AArch64GenRegisterInfo {
-private:
+class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
const Triple &TT;
public:
@@ -36,7 +35,7 @@ public:
/// Code Generation virtual methods...
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
const MCPhysReg *
- getCalleeSavedRegsViaCopy(const MachineFunction *MF) const override;
+ getCalleeSavedRegsViaCopy(const MachineFunction *MF) const;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const override;
@@ -63,6 +62,7 @@ public:
CallingConv::ID) const;
BitVector getReservedRegs(const MachineFunction &MF) const override;
+ bool isConstantPhysReg(unsigned PhysReg) const override;
const TargetRegisterClass *
getPointerRegClass(const MachineFunction &MF,
unsigned Kind = 0) const override;
@@ -95,6 +95,10 @@ public:
unsigned getRegPressureLimit(const TargetRegisterClass *RC,
MachineFunction &MF) const override;
+
+ bool trackLivenessAfterRegAlloc(const MachineFunction&) const override {
+ return true;
+ }
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 5fbaff0..7e29ee5 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -422,7 +422,7 @@ def DD : RegisterClass<"AArch64", [untyped], 64, (add DSeqPairs)> {
let Size = 128;
}
def DDD : RegisterClass<"AArch64", [untyped], 64, (add DSeqTriples)> {
- let Size = 196;
+ let Size = 192;
}
def DDDD : RegisterClass<"AArch64", [untyped], 64, (add DSeqQuads)> {
let Size = 256;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td
index a266351..99c48d0 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td
@@ -92,7 +92,7 @@ def : SchedAlias<WriteFCvt, A57Write_5cyc_1V>;
def : SchedAlias<WriteFCopy, A57Write_5cyc_1L>;
def : SchedAlias<WriteFImm, A57Write_3cyc_1V>;
def : SchedAlias<WriteFMul, A57Write_5cyc_1V>;
-def : SchedAlias<WriteFDiv, A57Write_18cyc_1X>;
+def : SchedAlias<WriteFDiv, A57Write_17cyc_1W>;
def : SchedAlias<WriteV, A57Write_3cyc_1V>;
def : SchedAlias<WriteVLD, A57Write_5cyc_1L>;
def : SchedAlias<WriteVST, A57Write_1cyc_1S>;
@@ -444,19 +444,19 @@ def : InstRW<[A57Write_5cyc_1V], (instregex "^[FVSU]CVT([AMNPZ][SU])?(_Int)?(v2f
def : InstRW<[A57Write_5cyc_2V], (instregex "^[FVSU]CVT([AMNPZ][SU])?(_Int)?(v4f32|v2f64|v4i32|v2i64)")>;
// ASIMD FP divide, D-form, F32
-def : InstRW<[A57Write_18cyc_1X], (instregex "FDIVv2f32")>;
+def : InstRW<[A57Write_17cyc_1W], (instregex "FDIVv2f32")>;
// ASIMD FP divide, Q-form, F32
-def : InstRW<[A57Write_36cyc_2X], (instregex "FDIVv4f32")>;
+def : InstRW<[A57Write_34cyc_2W], (instregex "FDIVv4f32")>;
// ASIMD FP divide, Q-form, F64
-def : InstRW<[A57Write_64cyc_2X], (instregex "FDIVv2f64")>;
+def : InstRW<[A57Write_64cyc_2W], (instregex "FDIVv2f64")>;
// Note: These were simply duplicated from ASIMD FDIV because of missing documentation
// ASIMD FP square root, D-form, F32
-def : InstRW<[A57Write_18cyc_1X], (instregex "FSQRTv2f32")>;
+def : InstRW<[A57Write_17cyc_1W], (instregex "FSQRTv2f32")>;
// ASIMD FP square root, Q-form, F32
-def : InstRW<[A57Write_36cyc_2X], (instregex "FSQRTv4f32")>;
+def : InstRW<[A57Write_34cyc_2W], (instregex "FSQRTv4f32")>;
// ASIMD FP square root, Q-form, F64
-def : InstRW<[A57Write_64cyc_2X], (instregex "FSQRTv2f64")>;
+def : InstRW<[A57Write_64cyc_2W], (instregex "FSQRTv2f64")>;
// ASIMD FP max/min, normal, D-form
def : InstRW<[A57Write_5cyc_1V], (instregex "^(FMAX|FMIN)(NM)?(v2f32)")>;
@@ -551,15 +551,15 @@ def : InstRW<[A57WriteFPMA, A57ReadFPM, A57ReadFPM, A57ReadFPMA5], (instregex "^
def : InstRW<[A57Write_10cyc_1L_1V], (instregex "^[FSU]CVT[AMNPZ][SU](_Int)?[SU]?[XW]?[DS]?[rds]i?")>;
def : InstRW<[A57Write_10cyc_1L_1V], (instregex "^[SU]CVTF")>;
-def : InstRW<[A57Write_32cyc_1X], (instrs FDIVDrr)>;
-def : InstRW<[A57Write_18cyc_1X], (instrs FDIVSrr)>;
+def : InstRW<[A57Write_32cyc_1W], (instrs FDIVDrr)>;
+def : InstRW<[A57Write_17cyc_1W], (instrs FDIVSrr)>;
def : InstRW<[A57Write_5cyc_1V], (instregex "^F(MAX|MIN).+rr")>;
def : InstRW<[A57Write_5cyc_1V], (instregex "^FRINT.+r")>;
-def : InstRW<[A57Write_32cyc_1X], (instrs FSQRTDr)>;
-def : InstRW<[A57Write_18cyc_1X], (instrs FSQRTSr)>;
+def : InstRW<[A57Write_32cyc_1W], (instrs FSQRTDr)>;
+def : InstRW<[A57Write_17cyc_1W], (instrs FSQRTSr)>;
def : InstRW<[A57Write_5cyc_1L, WriteLDHi], (instrs LDNPDi)>;
def : InstRW<[A57Write_6cyc_2L, WriteLDHi], (instrs LDNPQi)>;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedA57WriteRes.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedA57WriteRes.td
index 6f30108..55005e1 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64SchedA57WriteRes.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedA57WriteRes.td
@@ -28,15 +28,15 @@ def A57Write_5cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 5; }
def A57Write_5cyc_1V : SchedWriteRes<[A57UnitV]> { let Latency = 5; }
def A57Write_5cyc_1W : SchedWriteRes<[A57UnitW]> { let Latency = 5; }
def A57Write_10cyc_1V : SchedWriteRes<[A57UnitV]> { let Latency = 10; }
-def A57Write_18cyc_1X : SchedWriteRes<[A57UnitX]> { let Latency = 18;
- let ResourceCycles = [18]; }
+def A57Write_17cyc_1W : SchedWriteRes<[A57UnitW]> { let Latency = 17;
+ let ResourceCycles = [17]; }
def A57Write_19cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 19;
let ResourceCycles = [19]; }
def A57Write_1cyc_1B : SchedWriteRes<[A57UnitB]> { let Latency = 1; }
def A57Write_1cyc_1I : SchedWriteRes<[A57UnitI]> { let Latency = 1; }
def A57Write_1cyc_1S : SchedWriteRes<[A57UnitS]> { let Latency = 1; }
def A57Write_2cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 2; }
-def A57Write_32cyc_1X : SchedWriteRes<[A57UnitX]> { let Latency = 32;
+def A57Write_32cyc_1W : SchedWriteRes<[A57UnitW]> { let Latency = 32;
let ResourceCycles = [32]; }
def A57Write_35cyc_1M : SchedWriteRes<[A57UnitM]> { let Latency = 35;
let ResourceCycles = [35]; }
@@ -54,7 +54,7 @@ def A57Write_6cyc_1V : SchedWriteRes<[A57UnitV]> { let Latency = 6; }
//===----------------------------------------------------------------------===//
// Define Generic 2 micro-op types
-def A57Write_64cyc_2X : SchedWriteRes<[A57UnitX, A57UnitX]> {
+def A57Write_64cyc_2W : SchedWriteRes<[A57UnitW, A57UnitW]> {
let Latency = 64;
let NumMicroOps = 2;
let ResourceCycles = [32, 32];
@@ -139,10 +139,10 @@ def A57Write_2cyc_2V : SchedWriteRes<[A57UnitV, A57UnitV]> {
let Latency = 2;
let NumMicroOps = 2;
}
-def A57Write_36cyc_2X : SchedWriteRes<[A57UnitX, A57UnitX]> {
- let Latency = 36;
+def A57Write_34cyc_2W : SchedWriteRes<[A57UnitW, A57UnitW]> {
+ let Latency = 34;
let NumMicroOps = 2;
- let ResourceCycles = [18, 18];
+ let ResourceCycles = [17, 17];
}
def A57Write_3cyc_1I_1M : SchedWriteRes<[A57UnitI,
A57UnitM]> {
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkor.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkor.td
new file mode 100644
index 0000000..19a6d6f
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkor.td
@@ -0,0 +1,26 @@
+//==- AArch64SchedFalkor.td - Falkor Scheduling Definitions -*- tablegen -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the machine model for Qualcomm Falkor to support
+// instruction scheduling and other instruction cost heuristics.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Define the SchedMachineModel and provide basic properties for coarse grained
+// instruction cost model.
+
+def FalkorModel : SchedMachineModel {
+ let IssueWidth = 4; // 4-wide issue for expanded uops.
+ let MicroOpBufferSize = 128; // Out-of-order with temporary unified issue buffer.
+ let LoopMicroOpBufferSize = 16;
+ let LoadLatency = 3; // Optimistic load latency.
+ let MispredictPenalty = 11; // Minimum branch misprediction penalty.
+ let CompleteModel = 0;
+}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedM1.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedM1.td
index 2288b8d..14d6891 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64SchedM1.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedM1.td
@@ -32,33 +32,31 @@ def ExynosM1Model : SchedMachineModel {
def M1UnitA : ProcResource<2>; // Simple integer
def M1UnitC : ProcResource<1>; // Simple and complex integer
+def M1UnitD : ProcResource<1>; // Integer division (inside C, serialized)
def M1UnitB : ProcResource<2>; // Branch
def M1UnitL : ProcResource<1>; // Load
def M1UnitS : ProcResource<1>; // Store
def M1PipeF0 : ProcResource<1>; // FP #0
-def M1PipeF1 : ProcResource<1>; // FP #1
-
let Super = M1PipeF0 in {
def M1UnitFMAC : ProcResource<1>; // FP multiplication
- def M1UnitFCVT : ProcResource<1>; // FP conversion
- def M1UnitNAL0 : ProcResource<1>; // Simple vector.
+ def M1UnitNAL0 : ProcResource<1>; // Simple vector
def M1UnitNMISC : ProcResource<1>; // Miscellanea
+ def M1UnitFCVT : ProcResource<1>; // FP conversion
def M1UnitNCRYPT : ProcResource<1>; // Cryptographic
}
-
+def M1PipeF1 : ProcResource<1>; // FP #1
let Super = M1PipeF1 in {
def M1UnitFADD : ProcResource<1>; // Simple FP
- let BufferSize = 1 in
+ def M1UnitNAL1 : ProcResource<1>; // Simple vector
def M1UnitFVAR : ProcResource<1>; // FP division & square root (serialized)
- def M1UnitNAL1 : ProcResource<1>; // Simple vector.
def M1UnitFST : ProcResource<1>; // FP store
}
let SchedModel = ExynosM1Model in {
def M1UnitALU : ProcResGroup<[M1UnitA,
- M1UnitC]>; // All simple integer.
+ M1UnitC]>; // All integer
def M1UnitNALU : ProcResGroup<[M1UnitNAL0,
- M1UnitNAL1]>; // All simple vector.
+ M1UnitNAL1]>; // All simple vector
}
let SchedModel = ExynosM1Model in {
@@ -66,11 +64,33 @@ let SchedModel = ExynosM1Model in {
//===----------------------------------------------------------------------===//
// Coarse scheduling model for the Exynos-M1.
+def M1WriteA1 : SchedWriteRes<[M1UnitALU]> { let Latency = 1; }
+def M1WriteA2 : SchedWriteRes<[M1UnitALU]> { let Latency = 2; }
+def M1WriteC1 : SchedWriteRes<[M1UnitC]> { let Latency = 1; }
+def M1WriteC2 : SchedWriteRes<[M1UnitC]> { let Latency = 2; }
+
+def M1WriteB1 : SchedWriteRes<[M1UnitB]> { let Latency = 1; }
+
+def M1WriteL5 : SchedWriteRes<[M1UnitL]> { let Latency = 5; }
+def M1WriteLA : SchedWriteVariant<[SchedVar<ScaledIdxPred, [M1WriteL5,
+ M1WriteA1]>,
+ SchedVar<NoSchedPred, [M1WriteL5]>]>;
+
+def M1WriteS1 : SchedWriteRes<[M1UnitS]> { let Latency = 1; }
+def M1WriteS2 : SchedWriteRes<[M1UnitS]> { let Latency = 2; }
+def M1WriteS4 : SchedWriteRes<[M1UnitS]> { let Latency = 4; }
+def M1WriteSA : SchedWriteVariant<[SchedVar<ScaledIdxPred, [M1WriteS2,
+ M1WriteA1]>,
+ SchedVar<NoSchedPred, [M1WriteS1]>]>;
+
+def M1ReadAdrBase : SchedReadVariant<[SchedVar<ScaledIdxPred, [ReadDefault]>,
+ SchedVar<NoSchedPred, [ReadDefault]>]>;
+def : SchedAlias<ReadAdrBase, M1ReadAdrBase>;
+
// Branch instructions.
-// TODO: Non-conditional direct branches take zero cycles and units.
+// NOTE: Unconditional direct branches actually take neither cycles nor units.
def : WriteRes<WriteBr, [M1UnitB]> { let Latency = 1; }
def : WriteRes<WriteBrReg, [M1UnitC]> { let Latency = 1; }
-// TODO: Branch and link is much different.
// Arithmetic and logical integer instructions.
def : WriteRes<WriteI, [M1UnitALU]> { let Latency = 1; }
@@ -83,9 +103,12 @@ def : WriteRes<WriteIS, [M1UnitALU]> { let Latency = 1; }
def : WriteRes<WriteImm, [M1UnitALU]> { let Latency = 1; }
// Divide and multiply instructions.
-// TODO: Division blocks the divider inside C.
-def : WriteRes<WriteID32, [M1UnitC]> { let Latency = 13; }
-def : WriteRes<WriteID64, [M1UnitC]> { let Latency = 21; }
+def : WriteRes<WriteID32, [M1UnitC,
+ M1UnitD]> { let Latency = 13;
+ let ResourceCycles = [1, 13]; }
+def : WriteRes<WriteID64, [M1UnitC,
+ M1UnitD]> { let Latency = 21;
+ let ResourceCycles = [1, 21]; }
// TODO: Long multiplication take 5 cycles and also the ALU.
// TODO: Multiplication with accumulation can be advanced.
def : WriteRes<WriteIM32, [M1UnitC]> { let Latency = 3; }
@@ -101,31 +124,27 @@ def : WriteRes<WriteAdr, []> { let Latency = 0; }
// Load instructions.
def : WriteRes<WriteLD, [M1UnitL]> { let Latency = 4; }
-// TODO: Extended address requires also the ALU.
-def : WriteRes<WriteLDIdx, [M1UnitL]> { let Latency = 5; }
def : WriteRes<WriteLDHi, [M1UnitALU]> { let Latency = 4; }
+def : SchedAlias<WriteLDIdx, M1WriteLA>;
// Store instructions.
def : WriteRes<WriteST, [M1UnitS]> { let Latency = 1; }
-// TODO: Extended address requires also the ALU.
-def : WriteRes<WriteSTIdx, [M1UnitS]> { let Latency = 1; }
def : WriteRes<WriteSTP, [M1UnitS]> { let Latency = 1; }
def : WriteRes<WriteSTX, [M1UnitS]> { let Latency = 1; }
+def : SchedAlias<WriteSTIdx, M1WriteSA>;
// FP data instructions.
def : WriteRes<WriteF, [M1UnitFADD]> { let Latency = 3; }
// TODO: FCCMP is much different.
def : WriteRes<WriteFCmp, [M1UnitNMISC]> { let Latency = 4; }
-// TODO: DP takes longer.
-def : WriteRes<WriteFDiv, [M1UnitFVAR]> { let Latency = 15; }
-// TODO: MACC takes longer.
+def : WriteRes<WriteFDiv, [M1UnitFVAR]> { let Latency = 15;
+ let ResourceCycles = [15]; }
def : WriteRes<WriteFMul, [M1UnitFMAC]> { let Latency = 4; }
// FP miscellaneous instructions.
// TODO: Conversion between register files is much different.
def : WriteRes<WriteFCvt, [M1UnitFCVT]> { let Latency = 3; }
def : WriteRes<WriteFImm, [M1UnitNALU]> { let Latency = 1; }
-// TODO: Copy from FPR to GPR is much different.
def : WriteRes<WriteFCopy, [M1UnitS]> { let Latency = 4; }
// FP load instructions.
@@ -137,7 +156,6 @@ def : WriteRes<WriteVLD, [M1UnitL]> { let Latency = 5; }
def : WriteRes<WriteVST, [M1UnitS, M1UnitFST]> { let Latency = 1; }
// ASIMD FP instructions.
-// TODO: Other operations are much different.
def : WriteRes<WriteV, [M1UnitFADD]> { let Latency = 3; }
// Other miscellaneous instructions.
@@ -191,24 +209,15 @@ def M1WriteNEONJ : SchedWriteRes<[M1UnitNMISC,
M1UnitFMAC]> { let Latency = 6; }
def M1WriteNEONK : SchedWriteRes<[M1UnitNMISC,
M1UnitFMAC]> { let Latency = 7; }
-def M1WriteALU1 : SchedWriteRes<[M1UnitALU]> { let Latency = 1; }
-def M1WriteB : SchedWriteRes<[M1UnitB]> { let Latency = 1; }
-// FIXME: This is the worst case, conditional branch and link.
-def M1WriteBL : SchedWriteRes<[M1UnitB,
- M1UnitALU]> { let Latency = 1; }
-// FIXME: This is the worst case, when using LR.
-def M1WriteBLR : SchedWriteRes<[M1UnitB,
- M1UnitALU,
- M1UnitALU]> { let Latency = 2; }
-def M1WriteC1 : SchedWriteRes<[M1UnitC]> { let Latency = 1; }
-def M1WriteC2 : SchedWriteRes<[M1UnitC]> { let Latency = 2; }
def M1WriteFADD3 : SchedWriteRes<[M1UnitFADD]> { let Latency = 3; }
def M1WriteFCVT3 : SchedWriteRes<[M1UnitFCVT]> { let Latency = 3; }
def M1WriteFCVT4 : SchedWriteRes<[M1UnitFCVT]> { let Latency = 4; }
def M1WriteFMAC4 : SchedWriteRes<[M1UnitFMAC]> { let Latency = 4; }
def M1WriteFMAC5 : SchedWriteRes<[M1UnitFMAC]> { let Latency = 5; }
-def M1WriteFVAR15 : SchedWriteRes<[M1UnitFVAR]> { let Latency = 15; }
-def M1WriteFVAR23 : SchedWriteRes<[M1UnitFVAR]> { let Latency = 23; }
+def M1WriteFVAR15 : SchedWriteRes<[M1UnitFVAR]> { let Latency = 15;
+ let ResourceCycles = [15]; }
+def M1WriteFVAR23 : SchedWriteRes<[M1UnitFVAR]> { let Latency = 23;
+ let ResourceCycles = [23]; }
def M1WriteNALU1 : SchedWriteRes<[M1UnitNALU]> { let Latency = 1; }
def M1WriteNALU2 : SchedWriteRes<[M1UnitNALU]> { let Latency = 2; }
def M1WriteNAL11 : SchedWriteRes<[M1UnitNAL1]> { let Latency = 1; }
@@ -220,19 +229,22 @@ def M1WriteNMISC1 : SchedWriteRes<[M1UnitNMISC]> { let Latency = 1; }
def M1WriteNMISC2 : SchedWriteRes<[M1UnitNMISC]> { let Latency = 2; }
def M1WriteNMISC3 : SchedWriteRes<[M1UnitNMISC]> { let Latency = 3; }
def M1WriteNMISC4 : SchedWriteRes<[M1UnitNMISC]> { let Latency = 4; }
-def M1WriteS4 : SchedWriteRes<[M1UnitS]> { let Latency = 4; }
def M1WriteTB : SchedWriteRes<[M1UnitC,
M1UnitALU]> { let Latency = 2; }
// Branch instructions
-def : InstRW<[M1WriteB ], (instrs Bcc)>;
-def : InstRW<[M1WriteBL], (instrs BL)>;
-def : InstRW<[M1WriteBLR], (instrs BLR)>;
-def : InstRW<[M1WriteC1], (instregex "^CBN?Z[WX]")>;
-def : InstRW<[M1WriteTB], (instregex "^TBN?Z[WX]")>;
+def : InstRW<[M1WriteB1], (instrs Bcc)>;
+// NOTE: Conditional branch and link adds a B uop.
+def : InstRW<[M1WriteA1], (instrs BL)>;
+// NOTE: Indirect branch and link with LR adds an ALU uop.
+def : InstRW<[M1WriteA1,
+ M1WriteC1], (instrs BLR)>;
+def : InstRW<[M1WriteC1], (instregex "^CBN?Z[WX]")>;
+def : InstRW<[M1WriteC1,
+ M1WriteA2], (instregex "^TBN?Z[WX]")>;
// Arithmetic and logical integer instructions.
-def : InstRW<[M1WriteALU1], (instrs COPY)>;
+def : InstRW<[M1WriteA1], (instrs COPY)>;
// Divide and multiply instructions.
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedVulcan.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedVulcan.td
index 0aa2462..35a40c3 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64SchedVulcan.td
+++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedVulcan.td
@@ -49,15 +49,12 @@ def VulcanP5 : ProcResource<1>;
let SchedModel = VulcanModel in {
-// Define groups for the functional units on each
-// issue port. Each group created will be used
-// by a WriteRes later on.
+// Define groups for the functional units on each issue port. Each group
+// created will be used by a WriteRes later on.
//
-// NOTE: Some groups only contain one member. This
-// is a way to create names for the various functional
-// units that share a single issue port. For example,
-// "VulcanI1" for ALU ops on port 1 and "VulcanF1" for
-// FP ops on port 1.
+// NOTE: Some groups only contain one member. This is a way to create names for
+// the various functional units that share a single issue port. For example,
+// "VulcanI1" for ALU ops on port 1 and "VulcanF1" for FP ops on port 1.
// Integer divide and multiply micro-ops only on port 1.
def VulcanI1 : ProcResGroup<[VulcanP1]>;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64StorePairSuppress.cpp b/contrib/llvm/lib/Target/AArch64/AArch64StorePairSuppress.cpp
index f904b23..fe984cc 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64StorePairSuppress.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64StorePairSuppress.cpp
@@ -25,6 +25,8 @@ using namespace llvm;
#define DEBUG_TYPE "aarch64-stp-suppress"
+#define STPSUPPRESS_PASS_NAME "AArch64 Store Pair Suppression"
+
namespace {
class AArch64StorePairSuppress : public MachineFunctionPass {
const AArch64InstrInfo *TII;
@@ -36,12 +38,12 @@ class AArch64StorePairSuppress : public MachineFunctionPass {
public:
static char ID;
- AArch64StorePairSuppress() : MachineFunctionPass(ID) {}
-
- const char *getPassName() const override {
- return "AArch64 Store Pair Suppression";
+ AArch64StorePairSuppress() : MachineFunctionPass(ID) {
+ initializeAArch64StorePairSuppressPass(*PassRegistry::getPassRegistry());
}
+ StringRef getPassName() const override { return STPSUPPRESS_PASS_NAME; }
+
bool runOnMachineFunction(MachineFunction &F) override;
private:
@@ -59,6 +61,9 @@ private:
char AArch64StorePairSuppress::ID = 0;
} // anonymous
+INITIALIZE_PASS(AArch64StorePairSuppress, "aarch64-stp-suppress",
+ STPSUPPRESS_PASS_NAME, false, false)
+
FunctionPass *llvm::createAArch64StorePairSuppressPass() {
return new AArch64StorePairSuppress();
}
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index 7dd8ccb..03e0132 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
@@ -36,7 +36,8 @@ UseAddressTopByteIgnored("aarch64-use-tbi", cl::desc("Assume that top byte of "
"an address is ignored"), cl::init(false), cl::Hidden);
AArch64Subtarget &
-AArch64Subtarget::initializeSubtargetDependencies(StringRef FS) {
+AArch64Subtarget::initializeSubtargetDependencies(StringRef FS,
+ StringRef CPUString) {
// Determine default and user-specified characteristics
if (CPUString.empty())
@@ -63,9 +64,15 @@ void AArch64Subtarget::initializeProperties() {
MaxInterleaveFactor = 4;
break;
case ExynosM1:
+ MaxInterleaveFactor = 4;
+ MaxJumpTableSize = 8;
PrefFunctionAlignment = 4;
PrefLoopAlignment = 3;
break;
+ case Falkor:
+ MaxInterleaveFactor = 4;
+ VectorInsertExtractBaseCost = 2;
+ break;
case Kryo:
MaxInterleaveFactor = 4;
VectorInsertExtractBaseCost = 2;
@@ -89,8 +96,8 @@ AArch64Subtarget::AArch64Subtarget(const Triple &TT, const std::string &CPU,
const std::string &FS,
const TargetMachine &TM, bool LittleEndian)
: AArch64GenSubtargetInfo(TT, CPU, FS), ReserveX18(TT.isOSDarwin()),
- IsLittle(LittleEndian), CPUString(CPU), TargetTriple(TT), FrameLowering(),
- InstrInfo(initializeSubtargetDependencies(FS)), TSInfo(),
+ IsLittle(LittleEndian), TargetTriple(TT), FrameLowering(),
+ InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(),
TLInfo(TM, *this), GISel() {}
const CallLowering *AArch64Subtarget::getCallLowering() const {
@@ -98,6 +105,16 @@ const CallLowering *AArch64Subtarget::getCallLowering() const {
return GISel->getCallLowering();
}
+const InstructionSelector *AArch64Subtarget::getInstructionSelector() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getInstructionSelector();
+}
+
+const LegalizerInfo *AArch64Subtarget::getLegalizerInfo() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getLegalizerInfo();
+}
+
const RegisterBankInfo *AArch64Subtarget::getRegBankInfo() const {
assert(GISel && "Access to GlobalISel APIs not set");
return GISel->getRegBankInfo();
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.h b/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.h
index 16a3540..a993402 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -32,7 +32,7 @@ class GlobalValue;
class StringRef;
class Triple;
-class AArch64Subtarget : public AArch64GenSubtargetInfo {
+class AArch64Subtarget final : public AArch64GenSubtargetInfo {
public:
enum ARMProcFamilyEnum : uint8_t {
Others,
@@ -43,6 +43,7 @@ public:
CortexA73,
Cyclone,
ExynosM1,
+ Falkor,
Kryo,
Vulcan
};
@@ -58,6 +59,7 @@ protected:
bool HasNEON = false;
bool HasCrypto = false;
bool HasCRC = false;
+ bool HasLSE = false;
bool HasRAS = false;
bool HasPerfMon = false;
bool HasFullFP16 = false;
@@ -71,16 +73,16 @@ protected:
// StrictAlign - Disallow unaligned memory accesses.
bool StrictAlign = false;
- bool MergeNarrowLoads = false;
bool UseAA = false;
bool PredictableSelectIsExpensive = false;
bool BalanceFPOps = false;
bool CustomAsCheapAsMove = false;
bool UsePostRAScheduler = false;
bool Misaligned128StoreIsSlow = false;
- bool AvoidQuadLdStPairs = false;
+ bool Paired128IsSlow = false;
bool UseAlternateSExtLoadCVTF32Pattern = false;
- bool HasMacroOpFusion = false;
+ bool HasArithmeticBccFusion = false;
+ bool HasArithmeticCbzFusion = false;
bool DisableLatencySchedHeuristic = false;
bool UseRSqrt = false;
uint8_t MaxInterleaveFactor = 2;
@@ -91,15 +93,13 @@ protected:
unsigned MaxPrefetchIterationsAhead = UINT_MAX;
unsigned PrefFunctionAlignment = 0;
unsigned PrefLoopAlignment = 0;
+ unsigned MaxJumpTableSize = 0;
// ReserveX18 - X18 is not available as a general purpose register.
bool ReserveX18;
bool IsLittle;
- /// CPUString - String name of used CPU.
- std::string CPUString;
-
/// TargetTriple - What processor and OS we're targeting.
Triple TargetTriple;
@@ -116,7 +116,8 @@ private:
/// initializeSubtargetDependencies - Initializes using CPUString and the
/// passed in feature string so that we can use initializer lists for
/// subtarget initialization.
- AArch64Subtarget &initializeSubtargetDependencies(StringRef FS);
+ AArch64Subtarget &initializeSubtargetDependencies(StringRef FS,
+ StringRef CPUString);
/// Initialize properties based on the selected processor family.
void initializeProperties();
@@ -147,6 +148,8 @@ public:
return &getInstrInfo()->getRegisterInfo();
}
const CallLowering *getCallLowering() const override;
+ const InstructionSelector *getInstructionSelector() const override;
+ const LegalizerInfo *getLegalizerInfo() const override;
const RegisterBankInfo *getRegBankInfo() const override;
const Triple &getTargetTriple() const { return TargetTriple; }
bool enableMachineScheduler() const override { return true; }
@@ -171,24 +174,27 @@ public:
bool requiresStrictAlign() const { return StrictAlign; }
+ bool isXRaySupported() const override { return true; }
+
bool isX18Reserved() const { return ReserveX18; }
bool hasFPARMv8() const { return HasFPARMv8; }
bool hasNEON() const { return HasNEON; }
bool hasCrypto() const { return HasCrypto; }
bool hasCRC() const { return HasCRC; }
+ bool hasLSE() const { return HasLSE; }
bool hasRAS() const { return HasRAS; }
- bool mergeNarrowLoads() const { return MergeNarrowLoads; }
bool balanceFPOps() const { return BalanceFPOps; }
bool predictableSelectIsExpensive() const {
return PredictableSelectIsExpensive;
}
bool hasCustomCheapAsMoveHandling() const { return CustomAsCheapAsMove; }
bool isMisaligned128StoreSlow() const { return Misaligned128StoreIsSlow; }
- bool avoidQuadLdStPairs() const { return AvoidQuadLdStPairs; }
+ bool isPaired128Slow() const { return Paired128IsSlow; }
bool useAlternateSExtLoadCVTF32Pattern() const {
return UseAlternateSExtLoadCVTF32Pattern;
}
- bool hasMacroOpFusion() const { return HasMacroOpFusion; }
+ bool hasArithmeticBccFusion() const { return HasArithmeticBccFusion; }
+ bool hasArithmeticCbzFusion() const { return HasArithmeticCbzFusion; }
bool useRSqrt() const { return UseRSqrt; }
unsigned getMaxInterleaveFactor() const { return MaxInterleaveFactor; }
unsigned getVectorInsertExtractBaseCost() const {
@@ -203,6 +209,8 @@ public:
unsigned getPrefFunctionAlignment() const { return PrefFunctionAlignment; }
unsigned getPrefLoopAlignment() const { return PrefLoopAlignment; }
+ unsigned getMaximumJumpTableSize() const { return MaxJumpTableSize; }
+
/// CPU has TBI (top byte of addresses is ignored during HW address
/// translation) and OS enables it.
bool supportsAddressTopByteIgnored() const;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 0b6345f..d288394 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -12,71 +12,90 @@
#include "AArch64.h"
#include "AArch64CallLowering.h"
+#include "AArch64InstructionSelector.h"
+#include "AArch64LegalizerInfo.h"
#include "AArch64RegisterBankInfo.h"
+#include "AArch64Subtarget.h"
#include "AArch64TargetMachine.h"
#include "AArch64TargetObjectFile.h"
#include "AArch64TargetTransformInfo.h"
+#include "MCTargetDesc/AArch64MCTargetDesc.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
+#include "llvm/CodeGen/GlobalISel/Legalizer.h"
#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
+#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/Attributes.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/InitializePasses.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
+#include <memory>
+#include <string>
+
using namespace llvm;
-static cl::opt<bool>
-EnableCCMP("aarch64-ccmp", cl::desc("Enable the CCMP formation pass"),
- cl::init(true), cl::Hidden);
+static cl::opt<bool> EnableCCMP("aarch64-enable-ccmp",
+ cl::desc("Enable the CCMP formation pass"),
+ cl::init(true), cl::Hidden);
-static cl::opt<bool> EnableMCR("aarch64-mcr",
+static cl::opt<bool> EnableMCR("aarch64-enable-mcr",
cl::desc("Enable the machine combiner pass"),
cl::init(true), cl::Hidden);
-static cl::opt<bool>
-EnableStPairSuppress("aarch64-stp-suppress", cl::desc("Suppress STP for AArch64"),
- cl::init(true), cl::Hidden);
-
-static cl::opt<bool>
-EnableAdvSIMDScalar("aarch64-simd-scalar", cl::desc("Enable use of AdvSIMD scalar"
- " integer instructions"), cl::init(false), cl::Hidden);
-
-static cl::opt<bool>
-EnablePromoteConstant("aarch64-promote-const", cl::desc("Enable the promote "
- "constant pass"), cl::init(true), cl::Hidden);
-
-static cl::opt<bool>
-EnableCollectLOH("aarch64-collect-loh", cl::desc("Enable the pass that emits the"
- " linker optimization hints (LOH)"), cl::init(true),
- cl::Hidden);
+static cl::opt<bool> EnableStPairSuppress("aarch64-enable-stp-suppress",
+ cl::desc("Suppress STP for AArch64"),
+ cl::init(true), cl::Hidden);
-static cl::opt<bool>
-EnableDeadRegisterElimination("aarch64-dead-def-elimination", cl::Hidden,
- cl::desc("Enable the pass that removes dead"
- " definitons and replaces stores to"
- " them with stores to the zero"
- " register"),
- cl::init(true));
+static cl::opt<bool> EnableAdvSIMDScalar(
+ "aarch64-enable-simd-scalar",
+ cl::desc("Enable use of AdvSIMD scalar integer instructions"),
+ cl::init(false), cl::Hidden);
static cl::opt<bool>
-EnableRedundantCopyElimination("aarch64-redundant-copy-elim",
- cl::desc("Enable the redundant copy elimination pass"),
- cl::init(true), cl::Hidden);
+ EnablePromoteConstant("aarch64-enable-promote-const",
+ cl::desc("Enable the promote constant pass"),
+ cl::init(true), cl::Hidden);
-static cl::opt<bool>
-EnableLoadStoreOpt("aarch64-load-store-opt", cl::desc("Enable the load/store pair"
- " optimization pass"), cl::init(true), cl::Hidden);
+static cl::opt<bool> EnableCollectLOH(
+ "aarch64-enable-collect-loh",
+ cl::desc("Enable the pass that emits the linker optimization hints (LOH)"),
+ cl::init(true), cl::Hidden);
static cl::opt<bool>
-EnableAtomicTidy("aarch64-atomic-cfg-tidy", cl::Hidden,
- cl::desc("Run SimplifyCFG after expanding atomic operations"
- " to make use of cmpxchg flow-based information"),
- cl::init(true));
+ EnableDeadRegisterElimination("aarch64-enable-dead-defs", cl::Hidden,
+ cl::desc("Enable the pass that removes dead"
+ " definitons and replaces stores to"
+ " them with stores to the zero"
+ " register"),
+ cl::init(true));
+
+static cl::opt<bool> EnableRedundantCopyElimination(
+ "aarch64-enable-copyelim",
+ cl::desc("Enable the redundant copy elimination pass"), cl::init(true),
+ cl::Hidden);
+
+static cl::opt<bool> EnableLoadStoreOpt("aarch64-enable-ldst-opt",
+ cl::desc("Enable the load/store pair"
+ " optimization pass"),
+ cl::init(true), cl::Hidden);
+
+static cl::opt<bool> EnableAtomicTidy(
+ "aarch64-enable-atomic-cfg-tidy", cl::Hidden,
+ cl::desc("Run SimplifyCFG after expanding atomic operations"
+ " to make use of cmpxchg flow-based information"),
+ cl::init(true));
static cl::opt<bool>
EnableEarlyIfConversion("aarch64-enable-early-ifcvt", cl::Hidden,
@@ -84,9 +103,9 @@ EnableEarlyIfConversion("aarch64-enable-early-ifcvt", cl::Hidden,
cl::init(true));
static cl::opt<bool>
-EnableCondOpt("aarch64-condopt",
- cl::desc("Enable the condition optimizer pass"),
- cl::init(true), cl::Hidden);
+ EnableCondOpt("aarch64-enable-condopt",
+ cl::desc("Enable the condition optimizer pass"),
+ cl::init(true), cl::Hidden);
static cl::opt<bool>
EnableA53Fix835769("aarch64-fix-cortex-a53-835769", cl::Hidden,
@@ -94,28 +113,51 @@ EnableA53Fix835769("aarch64-fix-cortex-a53-835769", cl::Hidden,
cl::init(false));
static cl::opt<bool>
-EnableGEPOpt("aarch64-gep-opt", cl::Hidden,
- cl::desc("Enable optimizations on complex GEPs"),
- cl::init(false));
+ EnableAddressTypePromotion("aarch64-enable-type-promotion", cl::Hidden,
+ cl::desc("Enable the type promotion pass"),
+ cl::init(true));
+
+static cl::opt<bool>
+ EnableGEPOpt("aarch64-enable-gep-opt", cl::Hidden,
+ cl::desc("Enable optimizations on complex GEPs"),
+ cl::init(false));
+
+static cl::opt<bool>
+ BranchRelaxation("aarch64-enable-branch-relax", cl::Hidden, cl::init(true),
+ cl::desc("Relax out of range conditional branches"));
// FIXME: Unify control over GlobalMerge.
static cl::opt<cl::boolOrDefault>
-EnableGlobalMerge("aarch64-global-merge", cl::Hidden,
- cl::desc("Enable the global merge pass"));
+ EnableGlobalMerge("aarch64-enable-global-merge", cl::Hidden,
+ cl::desc("Enable the global merge pass"));
static cl::opt<bool>
- EnableLoopDataPrefetch("aarch64-loop-data-prefetch", cl::Hidden,
+ EnableLoopDataPrefetch("aarch64-enable-loop-data-prefetch", cl::Hidden,
cl::desc("Enable the loop data prefetch pass"),
cl::init(true));
extern "C" void LLVMInitializeAArch64Target() {
// Register the target.
- RegisterTargetMachine<AArch64leTargetMachine> X(TheAArch64leTarget);
- RegisterTargetMachine<AArch64beTargetMachine> Y(TheAArch64beTarget);
- RegisterTargetMachine<AArch64leTargetMachine> Z(TheARM64Target);
+ RegisterTargetMachine<AArch64leTargetMachine> X(getTheAArch64leTarget());
+ RegisterTargetMachine<AArch64beTargetMachine> Y(getTheAArch64beTarget());
+ RegisterTargetMachine<AArch64leTargetMachine> Z(getTheARM64Target());
auto PR = PassRegistry::getPassRegistry();
initializeGlobalISel(*PR);
+ initializeAArch64A53Fix835769Pass(*PR);
+ initializeAArch64A57FPLoadBalancingPass(*PR);
+ initializeAArch64AddressTypePromotionPass(*PR);
+ initializeAArch64AdvSIMDScalarPass(*PR);
+ initializeAArch64CollectLOHPass(*PR);
+ initializeAArch64ConditionalComparesPass(*PR);
+ initializeAArch64ConditionOptimizerPass(*PR);
+ initializeAArch64DeadRegisterDefinitionsPass(*PR);
initializeAArch64ExpandPseudoPass(*PR);
+ initializeAArch64LoadStoreOptPass(*PR);
+ initializeAArch64VectorByElementOptPass(*PR);
+ initializeAArch64PromoteConstantPass(*PR);
+ initializeAArch64RedundantCopyEliminationPass(*PR);
+ initializeAArch64StorePairSuppressPass(*PR);
+ initializeLDTLSCleanupPass(*PR);
}
//===----------------------------------------------------------------------===//
@@ -123,13 +165,17 @@ extern "C" void LLVMInitializeAArch64Target() {
//===----------------------------------------------------------------------===//
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
if (TT.isOSBinFormatMachO())
- return make_unique<AArch64_MachoTargetObjectFile>();
+ return llvm::make_unique<AArch64_MachoTargetObjectFile>();
- return make_unique<AArch64_ELFTargetObjectFile>();
+ return llvm::make_unique<AArch64_ELFTargetObjectFile>();
}
// Helper function to build a DataLayout string
-static std::string computeDataLayout(const Triple &TT, bool LittleEndian) {
+static std::string computeDataLayout(const Triple &TT,
+ const MCTargetOptions &Options,
+ bool LittleEndian) {
+ if (Options.getABIName() == "ilp32")
+ return "e-m:e-p:32:32-i8:8-i16:16-i64:64-S128";
if (TT.isOSBinFormatMachO())
return "e-m:o-i64:64-i128:128-n32:64-S128";
if (LittleEndian)
@@ -137,29 +183,6 @@ static std::string computeDataLayout(const Triple &TT, bool LittleEndian) {
return "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
}
-// Helper function to set up the defaults for reciprocals.
-static void initReciprocals(AArch64TargetMachine& TM, AArch64Subtarget& ST)
-{
- // For the estimates, convergence is quadratic, so essentially the number of
- // digits is doubled after each iteration. ARMv8, the minimum architected
- // accuracy of the initial estimate is 2^-8. Therefore, the number of extra
- // steps to refine the result for float (23 mantissa bits) and for double
- // (52 mantissa bits) are 2 and 3, respectively.
- unsigned ExtraStepsF = 2,
- ExtraStepsD = ExtraStepsF + 1;
- bool UseRsqrt = ST.useRSqrt();
-
- TM.Options.Reciprocals.setDefaults("sqrtf", UseRsqrt, ExtraStepsF);
- TM.Options.Reciprocals.setDefaults("sqrtd", UseRsqrt, ExtraStepsD);
- TM.Options.Reciprocals.setDefaults("vec-sqrtf", UseRsqrt, ExtraStepsF);
- TM.Options.Reciprocals.setDefaults("vec-sqrtd", UseRsqrt, ExtraStepsD);
-
- TM.Options.Reciprocals.setDefaults("divf", false, ExtraStepsF);
- TM.Options.Reciprocals.setDefaults("divd", false, ExtraStepsD);
- TM.Options.Reciprocals.setDefaults("vec-divf", false, ExtraStepsF);
- TM.Options.Reciprocals.setDefaults("vec-divd", false, ExtraStepsD);
-}
-
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
Optional<Reloc::Model> RM) {
// AArch64 Darwin is always PIC.
@@ -181,29 +204,44 @@ AArch64TargetMachine::AArch64TargetMachine(
CodeModel::Model CM, CodeGenOpt::Level OL, bool LittleEndian)
// This nested ternary is horrible, but DL needs to be properly
// initialized before TLInfo is constructed.
- : LLVMTargetMachine(T, computeDataLayout(TT, LittleEndian), TT, CPU, FS,
- Options, getEffectiveRelocModel(TT, RM), CM, OL),
+ : LLVMTargetMachine(T, computeDataLayout(TT, Options.MCOptions,
+ LittleEndian),
+ TT, CPU, FS, Options,
+ getEffectiveRelocModel(TT, RM), CM, OL),
TLOF(createTLOF(getTargetTriple())),
- Subtarget(TT, CPU, FS, *this, LittleEndian) {
- initReciprocals(*this, Subtarget);
+ isLittle(LittleEndian) {
initAsmInfo();
}
-AArch64TargetMachine::~AArch64TargetMachine() {}
+AArch64TargetMachine::~AArch64TargetMachine() = default;
#ifdef LLVM_BUILD_GLOBAL_ISEL
namespace {
+
struct AArch64GISelActualAccessor : public GISelAccessor {
std::unique_ptr<CallLowering> CallLoweringInfo;
+ std::unique_ptr<InstructionSelector> InstSelector;
+ std::unique_ptr<LegalizerInfo> Legalizer;
std::unique_ptr<RegisterBankInfo> RegBankInfo;
+
const CallLowering *getCallLowering() const override {
return CallLoweringInfo.get();
}
+
+ const InstructionSelector *getInstructionSelector() const override {
+ return InstSelector.get();
+ }
+
+ const LegalizerInfo *getLegalizerInfo() const override {
+ return Legalizer.get();
+ }
+
const RegisterBankInfo *getRegBankInfo() const override {
return RegBankInfo.get();
}
};
-} // End anonymous namespace.
+
+} // end anonymous namespace
#endif
const AArch64Subtarget *
@@ -225,16 +263,24 @@ AArch64TargetMachine::getSubtargetImpl(const Function &F) const {
// function that reside in TargetOptions.
resetTargetOptions(F);
I = llvm::make_unique<AArch64Subtarget>(TargetTriple, CPU, FS, *this,
- Subtarget.isLittleEndian());
+ isLittle);
#ifndef LLVM_BUILD_GLOBAL_ISEL
- GISelAccessor *GISel = new GISelAccessor();
+ GISelAccessor *GISel = new GISelAccessor();
#else
AArch64GISelActualAccessor *GISel =
new AArch64GISelActualAccessor();
GISel->CallLoweringInfo.reset(
new AArch64CallLowering(*I->getTargetLowering()));
- GISel->RegBankInfo.reset(
- new AArch64RegisterBankInfo(*I->getRegisterInfo()));
+ GISel->Legalizer.reset(new AArch64LegalizerInfo());
+
+ auto *RBI = new AArch64RegisterBankInfo(*I->getRegisterInfo());
+
+ // FIXME: At this point, we can't rely on Subtarget having RBI.
+ // It's awkward to mix passing RBI and the Subtarget; should we pass
+ // TII/TRI as well?
+ GISel->InstSelector.reset(new AArch64InstructionSelector(*this, *I, *RBI));
+
+ GISel->RegBankInfo.reset(RBI);
#endif
I->setGISelAccessor(*GISel);
}
@@ -258,6 +304,7 @@ AArch64beTargetMachine::AArch64beTargetMachine(
: AArch64TargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
namespace {
+
/// AArch64 Code Generator Pass Configuration Options.
class AArch64PassConfig : public TargetPassConfig {
public:
@@ -271,12 +318,23 @@ public:
return getTM<AArch64TargetMachine>();
}
+ ScheduleDAGInstrs *
+ createMachineScheduler(MachineSchedContext *C) const override {
+ ScheduleDAGMILive *DAG = createGenericSchedLive(C);
+ DAG->addMutation(createLoadClusterDAGMutation(DAG->TII, DAG->TRI));
+ DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI));
+ DAG->addMutation(createMacroFusionDAGMutation(DAG->TII));
+ return DAG;
+ }
+
void addIRPasses() override;
bool addPreISel() override;
bool addInstSelector() override;
#ifdef LLVM_BUILD_GLOBAL_ISEL
bool addIRTranslator() override;
+ bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
+ bool addGlobalInstructionSelect() override;
#endif
bool addILPOpts() override;
void addPreRegAlloc() override;
@@ -284,7 +342,8 @@ public:
void addPreSched2() override;
void addPreEmitPass() override;
};
-} // namespace
+
+} // end anonymous namespace
TargetIRAnalysis AArch64TargetMachine::getTargetIRAnalysis() {
return TargetIRAnalysis([this](const Function &F) {
@@ -351,7 +410,7 @@ bool AArch64PassConfig::addPreISel() {
addPass(createGlobalMergePass(TM, 4095, OnlyOptimizeForSize));
}
- if (TM->getOptLevel() != CodeGenOpt::None)
+ if (TM->getOptLevel() != CodeGenOpt::None && EnableAddressTypePromotion)
addPass(createAArch64AddressTypePromotionPass());
return false;
@@ -374,10 +433,21 @@ bool AArch64PassConfig::addIRTranslator() {
addPass(new IRTranslator());
return false;
}
+
+bool AArch64PassConfig::addLegalizeMachineIR() {
+ addPass(new Legalizer());
+ return false;
+}
+
bool AArch64PassConfig::addRegBankSelect() {
addPass(new RegBankSelect());
return false;
}
+
+bool AArch64PassConfig::addGlobalInstructionSelect() {
+ addPass(new InstructionSelect());
+ return false;
+}
#endif
bool AArch64PassConfig::addILPOpts() {
@@ -391,10 +461,15 @@ bool AArch64PassConfig::addILPOpts() {
addPass(&EarlyIfConverterID);
if (EnableStPairSuppress)
addPass(createAArch64StorePairSuppressPass());
+ addPass(createAArch64VectorByElementOptPass());
return true;
}
void AArch64PassConfig::addPreRegAlloc() {
+ // Change dead register definitions to refer to the zero register.
+ if (TM->getOptLevel() != CodeGenOpt::None && EnableDeadRegisterElimination)
+ addPass(createAArch64DeadRegisterDefinitions());
+
// Use AdvSIMD scalar instructions whenever profitable.
if (TM->getOptLevel() != CodeGenOpt::None && EnableAdvSIMDScalar) {
addPass(createAArch64AdvSIMDScalar());
@@ -409,9 +484,6 @@ void AArch64PassConfig::addPostRegAlloc() {
if (TM->getOptLevel() != CodeGenOpt::None && EnableRedundantCopyElimination)
addPass(createAArch64RedundantCopyEliminationPass());
- // Change dead register definitions to refer to the zero register.
- if (TM->getOptLevel() != CodeGenOpt::None && EnableDeadRegisterElimination)
- addPass(createAArch64DeadRegisterDefinitions());
if (TM->getOptLevel() != CodeGenOpt::None && usingDefaultRegAlloc())
// Improve performance for some FP/SIMD code for A57.
addPass(createAArch64A57FPLoadBalancing());
@@ -430,7 +502,9 @@ void AArch64PassConfig::addPreEmitPass() {
addPass(createAArch64A53Fix835769());
// Relax conditional branch instructions if they're otherwise out of
// range of their destination.
- addPass(createAArch64BranchRelaxation());
+ if (BranchRelaxation)
+ addPass(&BranchRelaxationPassID);
+
if (TM->getOptLevel() != CodeGenOpt::None && EnableCollectLOH &&
TM->getTargetTriple().isOSBinFormatMachO())
addPass(createAArch64CollectLOHPass());
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.h b/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.h
index b44107b..6fa5e83 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.h
@@ -46,7 +46,7 @@ public:
}
private:
- AArch64Subtarget Subtarget;
+ bool isLittle;
};
// AArch64 little endian target machine.
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index 18ee4a9..8875f9b 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -30,15 +30,14 @@ AArch64_MachoTargetObjectFile::AArch64_MachoTargetObjectFile()
}
const MCExpr *AArch64_MachoTargetObjectFile::getTTypeGlobalReference(
- const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
- const TargetMachine &TM, MachineModuleInfo *MMI,
- MCStreamer &Streamer) const {
+ const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM,
+ MachineModuleInfo *MMI, MCStreamer &Streamer) const {
// On Darwin, we can reference dwarf symbols with foo@GOT-., which
// is an indirect pc-relative reference. The default implementation
// won't reference using the GOT, so we need this target-specific
// version.
if (Encoding & (DW_EH_PE_indirect | DW_EH_PE_pcrel)) {
- const MCSymbol *Sym = TM.getSymbol(GV, Mang);
+ const MCSymbol *Sym = TM.getSymbol(GV);
const MCExpr *Res =
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_GOT, getContext());
MCSymbol *PCSym = getContext().createTempSymbol();
@@ -48,13 +47,13 @@ const MCExpr *AArch64_MachoTargetObjectFile::getTTypeGlobalReference(
}
return TargetLoweringObjectFileMachO::getTTypeGlobalReference(
- GV, Encoding, Mang, TM, MMI, Streamer);
+ GV, Encoding, TM, MMI, Streamer);
}
MCSymbol *AArch64_MachoTargetObjectFile::getCFIPersonalitySymbol(
- const GlobalValue *GV, Mangler &Mang, const TargetMachine &TM,
+ const GlobalValue *GV, const TargetMachine &TM,
MachineModuleInfo *MMI) const {
- return TM.getSymbol(GV, Mang);
+ return TM.getSymbol(GV);
}
const MCExpr *AArch64_MachoTargetObjectFile::getIndirectSymViaGOTPCRel(
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
index d41f445..05e1dfa 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
@@ -27,12 +27,12 @@ public:
AArch64_MachoTargetObjectFile();
const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
- unsigned Encoding, Mangler &Mang,
+ unsigned Encoding,
const TargetMachine &TM,
MachineModuleInfo *MMI,
MCStreamer &Streamer) const override;
- MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, Mangler &Mang,
+ MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV,
const TargetMachine &TM,
MachineModuleInfo *MMI) const override;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index ecf4d93..b8833e5 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -374,7 +374,7 @@ int AArch64TTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val,
int AArch64TTIImpl::getArithmeticInstrCost(
unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info,
TTI::OperandValueKind Opd2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ TTI::OperandValueProperties Opd2PropInfo, ArrayRef<const Value *> Args) {
// Legalize the type.
std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Ty);
@@ -417,14 +417,17 @@ int AArch64TTIImpl::getArithmeticInstrCost(
}
}
-int AArch64TTIImpl::getAddressComputationCost(Type *Ty, bool IsComplex) {
+int AArch64TTIImpl::getAddressComputationCost(Type *Ty, ScalarEvolution *SE,
+ const SCEV *Ptr) {
// Address computations in vectorized code with non-consecutive addresses will
// likely result in more instructions compared to scalar code where the
// computation can more often be merged into the index mode. The resulting
// extra micro-ops can significantly decrease throughput.
unsigned NumVectorInstToHideOverhead = 10;
+ int MaxMergeDistance = 64;
- if (Ty->isVectorTy() && IsComplex)
+ if (Ty->isVectorTy() && SE &&
+ !BaseT::isConstantStridedAccessLessThan(SE, Ptr, MaxMergeDistance + 1))
return NumVectorInstToHideOverhead;
// In many cases the address computation is not merged into the instruction
@@ -463,27 +466,27 @@ int AArch64TTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy);
}
-int AArch64TTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src,
+int AArch64TTIImpl::getMemoryOpCost(unsigned Opcode, Type *Ty,
unsigned Alignment, unsigned AddressSpace) {
- std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Src);
-
- if (Opcode == Instruction::Store && Src->isVectorTy() && Alignment != 16 &&
- Src->getVectorElementType()->isIntegerTy(64)) {
- // Unaligned stores are extremely inefficient. We don't split
- // unaligned v2i64 stores because the negative impact that has shown in
- // practice on inlined memcpy code.
- // We make v2i64 stores expensive so that we will only vectorize if there
+ auto LT = TLI->getTypeLegalizationCost(DL, Ty);
+
+ if (ST->isMisaligned128StoreSlow() && Opcode == Instruction::Store &&
+ LT.second.is128BitVector() && Alignment < 16) {
+ // Unaligned stores are extremely inefficient. We don't split all
+ // unaligned 128-bit stores because the negative impact that has shown in
+ // practice on inlined block copy code.
+ // We make such stores expensive so that we will only vectorize if there
// are 6 other instructions getting vectorized.
- int AmortizationCost = 6;
+ const int AmortizationCost = 6;
return LT.first * 2 * AmortizationCost;
}
- if (Src->isVectorTy() && Src->getVectorElementType()->isIntegerTy(8) &&
- Src->getVectorNumElements() < 8) {
+ if (Ty->isVectorTy() && Ty->getVectorElementType()->isIntegerTy(8) &&
+ Ty->getVectorNumElements() < 8) {
// We scalarize the loads/stores because there is not v.4b register and we
// have to promote the elements to v.4h.
- unsigned NumVecElts = Src->getVectorNumElements();
+ unsigned NumVecElts = Ty->getVectorNumElements();
unsigned NumVectorizableInstsToAmortize = NumVecElts * 2;
// We generate 2 instructions per vector element.
return NumVectorizableInstsToAmortize * NumVecElts * 2;
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
index 4f2e831..18287ed 100644
--- a/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
@@ -52,13 +52,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- AArch64TTIImpl(const AArch64TTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- AArch64TTIImpl(AArch64TTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
/// \name Scalar TTI Implementations
/// @{
@@ -109,9 +102,10 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
- int getAddressComputationCost(Type *Ty, bool IsComplex);
+ int getAddressComputationCost(Type *Ty, ScalarEvolution *SE, const SCEV *Ptr);
int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy);
diff --git a/contrib/llvm/lib/Target/AArch64/AArch64VectorByElementOpt.cpp b/contrib/llvm/lib/Target/AArch64/AArch64VectorByElementOpt.cpp
new file mode 100644
index 0000000..e3b1d7c
--- /dev/null
+++ b/contrib/llvm/lib/Target/AArch64/AArch64VectorByElementOpt.cpp
@@ -0,0 +1,371 @@
+//=- AArch64VectorByElementOpt.cpp - AArch64 vector by element inst opt pass =//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass that performs optimization for vector by element
+// SIMD instructions.
+//
+// Certain SIMD instructions with vector element operand are not efficient.
+// Rewrite them into SIMD instructions with vector operands. This rewrite
+// is driven by the latency of the instructions.
+//
+// Example:
+// fmla v0.4s, v1.4s, v2.s[1]
+// is rewritten into
+// dup v3.4s, v2.s[1]
+// fmla v0.4s, v1.4s, v3.4s
+//===----------------------------------------------------------------------===//
+
+#include "AArch64InstrInfo.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetSchedule.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "aarch64-vectorbyelement-opt"
+
+STATISTIC(NumModifiedInstr,
+ "Number of vector by element instructions modified");
+
+#define AARCH64_VECTOR_BY_ELEMENT_OPT_NAME \
+ "AArch64 vector by element instruction optimization pass"
+
+namespace {
+
+struct AArch64VectorByElementOpt : public MachineFunctionPass {
+ static char ID;
+ AArch64VectorByElementOpt() : MachineFunctionPass(ID) {
+ initializeAArch64VectorByElementOptPass(*PassRegistry::getPassRegistry());
+ }
+
+ const TargetInstrInfo *TII;
+ MachineRegisterInfo *MRI;
+ TargetSchedModel SchedModel;
+
+ /// Based only on latency of instructions, determine if it is cost efficient
+ /// to replace the instruction InstDesc by the two instructions InstDescRep1
+ /// and InstDescRep2.
+ /// Return true if replacement is recommended.
+ bool
+ shouldReplaceInstruction(MachineFunction *MF, const MCInstrDesc *InstDesc,
+ const MCInstrDesc *InstDescRep1,
+ const MCInstrDesc *InstDescRep2,
+ std::map<unsigned, bool> &VecInstElemTable) const;
+
+ /// Determine if we need to exit the vector by element instruction
+ /// optimization pass early. This makes sure that Targets with no need
+ /// for this optimization do not spent any compile time on this pass.
+ /// This check is done by comparing the latency of an indexed FMLA
+ /// instruction to the latency of the DUP + the latency of a vector
+ /// FMLA instruction. We do not check on other related instructions such
+ /// as FMLS as we assume that if the situation shows up for one
+ /// instruction, then it is likely to show up for the related ones.
+ /// Return true if early exit of the pass is recommended.
+ bool earlyExitVectElement(MachineFunction *MF);
+
+ /// Check whether an equivalent DUP instruction has already been
+ /// created or not.
+ /// Return true when the dup instruction already exists. In this case,
+ /// DestReg will point to the destination of the already created DUP.
+ bool reuseDUP(MachineInstr &MI, unsigned DupOpcode, unsigned SrcReg,
+ unsigned LaneNumber, unsigned *DestReg) const;
+
+ /// Certain SIMD instructions with vector element operand are not efficient.
+ /// Rewrite them into SIMD instructions with vector operands. This rewrite
+ /// is driven by the latency of the instructions.
+ /// Return true if the SIMD instruction is modified.
+ bool optimizeVectElement(MachineInstr &MI,
+ std::map<unsigned, bool> *VecInstElemTable) const;
+
+ bool runOnMachineFunction(MachineFunction &Fn) override;
+
+ StringRef getPassName() const override {
+ return AARCH64_VECTOR_BY_ELEMENT_OPT_NAME;
+ }
+};
+char AArch64VectorByElementOpt::ID = 0;
+} // namespace
+
+INITIALIZE_PASS(AArch64VectorByElementOpt, "aarch64-vectorbyelement-opt",
+ AARCH64_VECTOR_BY_ELEMENT_OPT_NAME, false, false)
+
+/// Based only on latency of instructions, determine if it is cost efficient
+/// to replace the instruction InstDesc by the two instructions InstDescRep1
+/// and InstDescRep2. Note that it is assumed in this fuction that an
+/// instruction of type InstDesc is always replaced by the same two
+/// instructions as results are cached here.
+/// Return true if replacement is recommended.
+bool AArch64VectorByElementOpt::shouldReplaceInstruction(
+ MachineFunction *MF, const MCInstrDesc *InstDesc,
+ const MCInstrDesc *InstDescRep1, const MCInstrDesc *InstDescRep2,
+ std::map<unsigned, bool> &VecInstElemTable) const {
+ // Check if replacment decision is alredy available in the cached table.
+ // if so, return it.
+ if (!VecInstElemTable.empty() &&
+ VecInstElemTable.find(InstDesc->getOpcode()) != VecInstElemTable.end())
+ return VecInstElemTable[InstDesc->getOpcode()];
+
+ unsigned SCIdx = InstDesc->getSchedClass();
+ unsigned SCIdxRep1 = InstDescRep1->getSchedClass();
+ unsigned SCIdxRep2 = InstDescRep2->getSchedClass();
+ const MCSchedClassDesc *SCDesc =
+ SchedModel.getMCSchedModel()->getSchedClassDesc(SCIdx);
+ const MCSchedClassDesc *SCDescRep1 =
+ SchedModel.getMCSchedModel()->getSchedClassDesc(SCIdxRep1);
+ const MCSchedClassDesc *SCDescRep2 =
+ SchedModel.getMCSchedModel()->getSchedClassDesc(SCIdxRep2);
+
+ // If a subtarget does not define resources for any of the instructions
+ // of interest, then return false for no replacement.
+ if (!SCDesc->isValid() || SCDesc->isVariant() || !SCDescRep1->isValid() ||
+ SCDescRep1->isVariant() || !SCDescRep2->isValid() ||
+ SCDescRep2->isVariant()) {
+ VecInstElemTable[InstDesc->getOpcode()] = false;
+ return false;
+ }
+
+ if (SchedModel.computeInstrLatency(InstDesc->getOpcode()) >
+ SchedModel.computeInstrLatency(InstDescRep1->getOpcode()) +
+ SchedModel.computeInstrLatency(InstDescRep2->getOpcode())) {
+ VecInstElemTable[InstDesc->getOpcode()] = true;
+ return true;
+ }
+ VecInstElemTable[InstDesc->getOpcode()] = false;
+ return false;
+}
+
+/// Determine if we need to exit the vector by element instruction
+/// optimization pass early. This makes sure that Targets with no need
+/// for this optimization do not spent any compile time on this pass.
+/// This check is done by comparing the latency of an indexed FMLA
+/// instruction to the latency of the DUP + the latency of a vector
+/// FMLA instruction. We do not check on other related instructions such
+/// as FMLS as we assume that if the situation shows up for one
+/// instruction, then it is likely to show up for the related ones.
+/// Return true if early exit of the pass is recommended.
+bool AArch64VectorByElementOpt::earlyExitVectElement(MachineFunction *MF) {
+ std::map<unsigned, bool> VecInstElemTable;
+ const MCInstrDesc *IndexMulMCID = &TII->get(AArch64::FMLAv4i32_indexed);
+ const MCInstrDesc *DupMCID = &TII->get(AArch64::DUPv4i32lane);
+ const MCInstrDesc *MulMCID = &TII->get(AArch64::FMULv4f32);
+
+ if (!shouldReplaceInstruction(MF, IndexMulMCID, DupMCID, MulMCID,
+ VecInstElemTable))
+ return true;
+ return false;
+}
+
+/// Check whether an equivalent DUP instruction has already been
+/// created or not.
+/// Return true when the dup instruction already exists. In this case,
+/// DestReg will point to the destination of the already created DUP.
+bool AArch64VectorByElementOpt::reuseDUP(MachineInstr &MI, unsigned DupOpcode,
+ unsigned SrcReg, unsigned LaneNumber,
+ unsigned *DestReg) const {
+ for (MachineBasicBlock::iterator MII = MI, MIE = MI.getParent()->begin();
+ MII != MIE;) {
+ MII--;
+ MachineInstr *CurrentMI = &*MII;
+
+ if (CurrentMI->getOpcode() == DupOpcode &&
+ CurrentMI->getNumOperands() == 3 &&
+ CurrentMI->getOperand(1).getReg() == SrcReg &&
+ CurrentMI->getOperand(2).getImm() == LaneNumber) {
+ *DestReg = CurrentMI->getOperand(0).getReg();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/// Certain SIMD instructions with vector element operand are not efficient.
+/// Rewrite them into SIMD instructions with vector operands. This rewrite
+/// is driven by the latency of the instructions.
+/// The instruction of concerns are for the time being fmla, fmls, fmul,
+/// and fmulx and hence they are hardcoded.
+///
+/// Example:
+/// fmla v0.4s, v1.4s, v2.s[1]
+/// is rewritten into
+/// dup v3.4s, v2.s[1] // dup not necessary if redundant
+/// fmla v0.4s, v1.4s, v3.4s
+/// Return true if the SIMD instruction is modified.
+bool AArch64VectorByElementOpt::optimizeVectElement(
+ MachineInstr &MI, std::map<unsigned, bool> *VecInstElemTable) const {
+ const MCInstrDesc *MulMCID, *DupMCID;
+ const TargetRegisterClass *RC = &AArch64::FPR128RegClass;
+
+ switch (MI.getOpcode()) {
+ default:
+ return false;
+
+ // 4X32 instructions
+ case AArch64::FMLAv4i32_indexed:
+ DupMCID = &TII->get(AArch64::DUPv4i32lane);
+ MulMCID = &TII->get(AArch64::FMLAv4f32);
+ break;
+ case AArch64::FMLSv4i32_indexed:
+ DupMCID = &TII->get(AArch64::DUPv4i32lane);
+ MulMCID = &TII->get(AArch64::FMLSv4f32);
+ break;
+ case AArch64::FMULXv4i32_indexed:
+ DupMCID = &TII->get(AArch64::DUPv4i32lane);
+ MulMCID = &TII->get(AArch64::FMULXv4f32);
+ break;
+ case AArch64::FMULv4i32_indexed:
+ DupMCID = &TII->get(AArch64::DUPv4i32lane);
+ MulMCID = &TII->get(AArch64::FMULv4f32);
+ break;
+
+ // 2X64 instructions
+ case AArch64::FMLAv2i64_indexed:
+ DupMCID = &TII->get(AArch64::DUPv2i64lane);
+ MulMCID = &TII->get(AArch64::FMLAv2f64);
+ break;
+ case AArch64::FMLSv2i64_indexed:
+ DupMCID = &TII->get(AArch64::DUPv2i64lane);
+ MulMCID = &TII->get(AArch64::FMLSv2f64);
+ break;
+ case AArch64::FMULXv2i64_indexed:
+ DupMCID = &TII->get(AArch64::DUPv2i64lane);
+ MulMCID = &TII->get(AArch64::FMULXv2f64);
+ break;
+ case AArch64::FMULv2i64_indexed:
+ DupMCID = &TII->get(AArch64::DUPv2i64lane);
+ MulMCID = &TII->get(AArch64::FMULv2f64);
+ break;
+
+ // 2X32 instructions
+ case AArch64::FMLAv2i32_indexed:
+ RC = &AArch64::FPR64RegClass;
+ DupMCID = &TII->get(AArch64::DUPv2i32lane);
+ MulMCID = &TII->get(AArch64::FMLAv2f32);
+ break;
+ case AArch64::FMLSv2i32_indexed:
+ RC = &AArch64::FPR64RegClass;
+ DupMCID = &TII->get(AArch64::DUPv2i32lane);
+ MulMCID = &TII->get(AArch64::FMLSv2f32);
+ break;
+ case AArch64::FMULXv2i32_indexed:
+ RC = &AArch64::FPR64RegClass;
+ DupMCID = &TII->get(AArch64::DUPv2i32lane);
+ MulMCID = &TII->get(AArch64::FMULXv2f32);
+ break;
+ case AArch64::FMULv2i32_indexed:
+ RC = &AArch64::FPR64RegClass;
+ DupMCID = &TII->get(AArch64::DUPv2i32lane);
+ MulMCID = &TII->get(AArch64::FMULv2f32);
+ break;
+ }
+
+ if (!shouldReplaceInstruction(MI.getParent()->getParent(),
+ &TII->get(MI.getOpcode()), DupMCID, MulMCID,
+ *VecInstElemTable))
+ return false;
+
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock &MBB = *MI.getParent();
+ MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+
+ // get the operands of the current SIMD arithmetic instruction.
+ unsigned MulDest = MI.getOperand(0).getReg();
+ unsigned SrcReg0 = MI.getOperand(1).getReg();
+ unsigned Src0IsKill = getKillRegState(MI.getOperand(1).isKill());
+ unsigned SrcReg1 = MI.getOperand(2).getReg();
+ unsigned Src1IsKill = getKillRegState(MI.getOperand(2).isKill());
+ unsigned DupDest;
+
+ // Instructions of interest have either 4 or 5 operands.
+ if (MI.getNumOperands() == 5) {
+ unsigned SrcReg2 = MI.getOperand(3).getReg();
+ unsigned Src2IsKill = getKillRegState(MI.getOperand(3).isKill());
+ unsigned LaneNumber = MI.getOperand(4).getImm();
+
+ // Create a new DUP instruction. Note that if an equivalent DUP instruction
+ // has already been created before, then use that one instread of creating
+ // a new one.
+ if (!reuseDUP(MI, DupMCID->getOpcode(), SrcReg2, LaneNumber, &DupDest)) {
+ DupDest = MRI.createVirtualRegister(RC);
+ BuildMI(MBB, MI, DL, *DupMCID, DupDest)
+ .addReg(SrcReg2, Src2IsKill)
+ .addImm(LaneNumber);
+ }
+ BuildMI(MBB, MI, DL, *MulMCID, MulDest)
+ .addReg(SrcReg0, Src0IsKill)
+ .addReg(SrcReg1, Src1IsKill)
+ .addReg(DupDest, Src2IsKill);
+ } else if (MI.getNumOperands() == 4) {
+ unsigned LaneNumber = MI.getOperand(3).getImm();
+ if (!reuseDUP(MI, DupMCID->getOpcode(), SrcReg1, LaneNumber, &DupDest)) {
+ DupDest = MRI.createVirtualRegister(RC);
+ BuildMI(MBB, MI, DL, *DupMCID, DupDest)
+ .addReg(SrcReg1, Src1IsKill)
+ .addImm(LaneNumber);
+ }
+ BuildMI(MBB, MI, DL, *MulMCID, MulDest)
+ .addReg(SrcReg0, Src0IsKill)
+ .addReg(DupDest, Src1IsKill);
+ } else {
+ return false;
+ }
+
+ ++NumModifiedInstr;
+ return true;
+}
+
+bool AArch64VectorByElementOpt::runOnMachineFunction(MachineFunction &MF) {
+ if (skipFunction(*MF.getFunction()))
+ return false;
+
+ TII = MF.getSubtarget().getInstrInfo();
+ MRI = &MF.getRegInfo();
+ const TargetSubtargetInfo &ST = MF.getSubtarget();
+ const AArch64InstrInfo *AAII =
+ static_cast<const AArch64InstrInfo *>(ST.getInstrInfo());
+ if (!AAII)
+ return false;
+ SchedModel.init(ST.getSchedModel(), &ST, AAII);
+ if (!SchedModel.hasInstrSchedModel())
+ return false;
+
+ // A simple check to exit this pass early for targets that do not need it.
+ if (earlyExitVectElement(&MF))
+ return false;
+
+ bool Changed = false;
+ std::map<unsigned, bool> VecInstElemTable;
+ SmallVector<MachineInstr *, 8> RemoveMIs;
+
+ for (MachineBasicBlock &MBB : MF) {
+ for (MachineBasicBlock::iterator MII = MBB.begin(), MIE = MBB.end();
+ MII != MIE;) {
+ MachineInstr &MI = *MII;
+ if (optimizeVectElement(MI, &VecInstElemTable)) {
+ // Add MI to the list of instructions to be removed given that it has
+ // been replaced.
+ RemoveMIs.push_back(&MI);
+ Changed = true;
+ }
+ ++MII;
+ }
+ }
+
+ for (MachineInstr *MI : RemoveMIs)
+ MI->eraseFromParent();
+
+ return Changed;
+}
+
+/// createAArch64VectorByElementOptPass - returns an instance of the
+/// vector by element optimization pass.
+FunctionPass *llvm::createAArch64VectorByElementOptPass() {
+ return new AArch64VectorByElementOpt();
+}
diff --git a/contrib/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/contrib/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index aebc370..b86a283 100644
--- a/contrib/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/contrib/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -9,43 +9,62 @@
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "MCTargetDesc/AArch64MCExpr.h"
+#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "MCTargetDesc/AArch64TargetStreamer.h"
#include "Utils/AArch64BaseInfo.h"
+#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCLinkerOptimizationHint.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SMLoc.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cctype>
+#include <cstdint>
#include <cstdio>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
using namespace llvm;
namespace {
-class AArch64Operand;
-
class AArch64AsmParser : public MCTargetAsmParser {
private:
StringRef Mnemonic; ///< Instruction mnemonic.
// Map of register aliases registers via the .req directive.
- StringMap<std::pair<bool, unsigned> > RegisterReqs;
+ StringMap<std::pair<bool, unsigned>> RegisterReqs;
AArch64TargetStreamer &getTargetStreamer() {
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
@@ -66,8 +85,6 @@ private:
bool parseOperand(OperandVector &Operands, bool isCondCode,
bool invertCondCode);
- void Warning(SMLoc L, const Twine &Msg) { getParser().Warning(L, Msg); }
- bool Error(SMLoc L, const Twine &Msg) { return getParser().Error(L, Msg); }
bool showMatchError(SMLoc Loc, unsigned ErrCode);
bool parseDirectiveArch(SMLoc L);
@@ -117,9 +134,12 @@ public:
#define GET_OPERAND_DIAGNOSTIC_TYPES
#include "AArch64GenAsmMatcher.inc"
};
+ bool IsILP32;
+
AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
: MCTargetAsmParser(Options, STI) {
+ IsILP32 = Options.getABIName() == "ilp32";
MCAsmParserExtension::Initialize(Parser);
MCStreamer &S = getParser().getStreamer();
if (S.getTargetStreamer() == nullptr)
@@ -141,9 +161,6 @@ public:
MCSymbolRefExpr::VariantKind &DarwinRefKind,
int64_t &Addend);
};
-} // end anonymous namespace
-
-namespace {
/// AArch64Operand - Instances of this class represent a parsed AArch64 machine
/// instruction.
@@ -208,9 +225,9 @@ private:
};
struct BarrierOp {
- unsigned Val; // Not the enum since not all values have names.
const char *Data;
unsigned Length;
+ unsigned Val; // Not the enum since not all values have names.
};
struct SysRegOp {
@@ -226,15 +243,15 @@ private:
};
struct PrefetchOp {
- unsigned Val;
const char *Data;
unsigned Length;
+ unsigned Val;
};
struct PSBHintOp {
- unsigned Val;
const char *Data;
unsigned Length;
+ unsigned Val;
};
struct ShiftExtendOp {
@@ -529,6 +546,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 2);
}
+
bool isImm0_7() const {
if (!isImm())
return false;
@@ -538,6 +556,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 8);
}
+
bool isImm1_8() const {
if (!isImm())
return false;
@@ -547,6 +566,7 @@ public:
int64_t Val = MCE->getValue();
return (Val > 0 && Val < 9);
}
+
bool isImm0_15() const {
if (!isImm())
return false;
@@ -556,6 +576,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 16);
}
+
bool isImm1_16() const {
if (!isImm())
return false;
@@ -565,6 +586,7 @@ public:
int64_t Val = MCE->getValue();
return (Val > 0 && Val < 17);
}
+
bool isImm0_31() const {
if (!isImm())
return false;
@@ -574,6 +596,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 32);
}
+
bool isImm1_31() const {
if (!isImm())
return false;
@@ -583,6 +606,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 1 && Val < 32);
}
+
bool isImm1_32() const {
if (!isImm())
return false;
@@ -592,6 +616,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 1 && Val < 33);
}
+
bool isImm0_63() const {
if (!isImm())
return false;
@@ -601,6 +626,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 64);
}
+
bool isImm1_63() const {
if (!isImm())
return false;
@@ -610,6 +636,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 1 && Val < 64);
}
+
bool isImm1_64() const {
if (!isImm())
return false;
@@ -619,6 +646,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 1 && Val < 65);
}
+
bool isImm0_127() const {
if (!isImm())
return false;
@@ -628,6 +656,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 128);
}
+
bool isImm0_255() const {
if (!isImm())
return false;
@@ -637,6 +666,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 256);
}
+
bool isImm0_65535() const {
if (!isImm())
return false;
@@ -646,6 +676,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 0 && Val < 65536);
}
+
bool isImm32_63() const {
if (!isImm())
return false;
@@ -655,6 +686,7 @@ public:
int64_t Val = MCE->getValue();
return (Val >= 32 && Val < 64);
}
+
bool isLogicalImm32() const {
if (!isImm())
return false;
@@ -667,6 +699,7 @@ public:
Val &= 0xFFFFFFFF;
return AArch64_AM::isLogicalImmediate(Val, 32);
}
+
bool isLogicalImm64() const {
if (!isImm())
return false;
@@ -675,6 +708,7 @@ public:
return false;
return AArch64_AM::isLogicalImmediate(MCE->getValue(), 64);
}
+
bool isLogicalImm32Not() const {
if (!isImm())
return false;
@@ -684,6 +718,7 @@ public:
int64_t Val = ~MCE->getValue() & 0xFFFFFFFF;
return AArch64_AM::isLogicalImmediate(Val, 32);
}
+
bool isLogicalImm64Not() const {
if (!isImm())
return false;
@@ -692,7 +727,9 @@ public:
return false;
return AArch64_AM::isLogicalImmediate(~MCE->getValue(), 64);
}
+
bool isShiftedImm() const { return Kind == k_ShiftedImm; }
+
bool isAddSubImm() const {
if (!isShiftedImm() && !isImm())
return false;
@@ -727,10 +764,15 @@ public:
|| ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12;
}
- // Otherwise it should be a real immediate in range:
- const MCConstantExpr *CE = cast<MCConstantExpr>(Expr);
- return CE->getValue() >= 0 && CE->getValue() <= 0xfff;
+ // If it's a constant, it should be a real immediate in range:
+ if (auto *CE = dyn_cast<MCConstantExpr>(Expr))
+ return CE->getValue() >= 0 && CE->getValue() <= 0xfff;
+
+ // If it's an expression, we hope for the best and let the fixup/relocation
+ // code deal with it.
+ return true;
}
+
bool isAddSubImmNeg() const {
if (!isShiftedImm() && !isImm())
return false;
@@ -750,7 +792,9 @@ public:
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr);
return CE != nullptr && CE->getValue() < 0 && -CE->getValue() <= 0xfff;
}
+
bool isCondCode() const { return Kind == k_CondCode; }
+
bool isSIMDImmType10() const {
if (!isImm())
return false;
@@ -759,6 +803,7 @@ public:
return false;
return AArch64_AM::isAdvSIMDModImmType10(MCE->getValue());
}
+
bool isBranchTarget26() const {
if (!isImm())
return false;
@@ -770,6 +815,7 @@ public:
return false;
return (Val >= -(0x2000000 << 2) && Val <= (0x1ffffff << 2));
}
+
bool isPCRelLabel19() const {
if (!isImm())
return false;
@@ -781,6 +827,7 @@ public:
return false;
return (Val >= -(0x40000 << 2) && Val <= (0x3ffff << 2));
}
+
bool isBranchTarget14() const {
if (!isImm())
return false;
@@ -885,40 +932,49 @@ public:
bool isFPImm() const { return Kind == k_FPImm; }
bool isBarrier() const { return Kind == k_Barrier; }
bool isSysReg() const { return Kind == k_SysReg; }
+
bool isMRSSystemRegister() const {
if (!isSysReg()) return false;
return SysReg.MRSReg != -1U;
}
+
bool isMSRSystemRegister() const {
if (!isSysReg()) return false;
return SysReg.MSRReg != -1U;
}
+
bool isSystemPStateFieldWithImm0_1() const {
if (!isSysReg()) return false;
return (SysReg.PStateField == AArch64PState::PAN ||
SysReg.PStateField == AArch64PState::UAO);
}
+
bool isSystemPStateFieldWithImm0_15() const {
if (!isSysReg() || isSystemPStateFieldWithImm0_1()) return false;
return SysReg.PStateField != -1U;
}
+
bool isReg() const override { return Kind == k_Register && !Reg.isVector; }
bool isVectorReg() const { return Kind == k_Register && Reg.isVector; }
+
bool isVectorRegLo() const {
return Kind == k_Register && Reg.isVector &&
AArch64MCRegisterClasses[AArch64::FPR128_loRegClassID].contains(
Reg.RegNum);
}
+
bool isGPR32as64() const {
return Kind == k_Register && !Reg.isVector &&
AArch64MCRegisterClasses[AArch64::GPR64RegClassID].contains(Reg.RegNum);
}
+
bool isWSeqPair() const {
return Kind == k_Register && !Reg.isVector &&
AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID].contains(
Reg.RegNum);
}
+
bool isXSeqPair() const {
return Kind == k_Register && !Reg.isVector &&
AArch64MCRegisterClasses[AArch64::XSeqPairsClassRegClassID].contains(
@@ -951,19 +1007,25 @@ public:
bool isVectorIndex1() const {
return Kind == k_VectorIndex && VectorIndex.Val == 1;
}
+
bool isVectorIndexB() const {
return Kind == k_VectorIndex && VectorIndex.Val < 16;
}
+
bool isVectorIndexH() const {
return Kind == k_VectorIndex && VectorIndex.Val < 8;
}
+
bool isVectorIndexS() const {
return Kind == k_VectorIndex && VectorIndex.Val < 4;
}
+
bool isVectorIndexD() const {
return Kind == k_VectorIndex && VectorIndex.Val < 2;
}
+
bool isToken() const override { return Kind == k_Token; }
+
bool isTokenEqual(StringRef Str) const {
return Kind == k_Token && getToken() == Str;
}
@@ -1000,6 +1062,7 @@ public:
AArch64_AM::ShiftExtendType ET = getShiftExtendType();
return ET != AArch64_AM::UXTX && ET != AArch64_AM::SXTX;
}
+
bool isExtendLSL64() const {
if (!isExtend())
return false;
@@ -1830,11 +1893,10 @@ void AArch64Operand::print(raw_ostream &OS) const {
OS << "<prfop invalid #" << getPrefetch() << ">";
break;
}
- case k_PSBHint: {
+ case k_PSBHint:
OS << getPSBHintName();
break;
- }
- case k_ShiftExtend: {
+ case k_ShiftExtend:
OS << "<" << AArch64_AM::getShiftExtendName(getShiftExtendType()) << " #"
<< getShiftExtendAmount();
if (!hasShiftExtendAmount())
@@ -1842,7 +1904,6 @@ void AArch64Operand::print(raw_ostream &OS) const {
OS << '>';
break;
}
- }
}
/// @name Auto-generated Match Functions
@@ -1964,7 +2025,8 @@ unsigned AArch64AsmParser::matchRegisterNameAlias(StringRef Name,
int AArch64AsmParser::tryParseRegister() {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
- assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
+ if (Tok.isNot(AsmToken::Identifier))
+ return -1;
std::string lowerCase = Tok.getString().lower();
unsigned RegNum = matchRegisterNameAlias(lowerCase, false);
@@ -2018,7 +2080,7 @@ int AArch64AsmParser::tryMatchVectorRegister(StringRef &Kind, bool expected) {
}
/// tryParseSysCROperand - Try to parse a system instruction CR operand name.
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseSysCROperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
@@ -2048,16 +2110,15 @@ AArch64AsmParser::tryParseSysCROperand(OperandVector &Operands) {
}
/// tryParsePrefetch - Try to parse a prefetch operand.
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
const AsmToken &Tok = Parser.getTok();
// Either an identifier for named values or a 5-bit immediate.
- bool Hash = Tok.is(AsmToken::Hash);
- if (Hash || Tok.is(AsmToken::Integer)) {
- if (Hash)
- Parser.Lex(); // Eat hash token.
+ // Eat optional hash.
+ if (parseOptionalToken(AsmToken::Hash) ||
+ Tok.is(AsmToken::Integer)) {
const MCExpr *ImmVal;
if (getParser().parseExpression(ImmVal))
return MatchOperand_ParseFail;
@@ -2097,7 +2158,7 @@ AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
}
/// tryParsePSBHint - Try to parse a PSB operand, mapped to Hint command
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
@@ -2121,7 +2182,7 @@ AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
/// tryParseAdrpLabel - Parse and validate a source label for the ADRP
/// instruction.
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
@@ -2172,16 +2233,12 @@ AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) {
/// tryParseAdrLabel - Parse and validate a source label for the ADR
/// instruction.
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
const MCExpr *Expr;
- if (Parser.getTok().is(AsmToken::Hash)) {
- Parser.Lex(); // Eat hash token.
- }
-
+ parseOptionalToken(AsmToken::Hash);
if (getParser().parseExpression(Expr))
return MatchOperand_ParseFail;
@@ -2192,26 +2249,19 @@ AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
}
/// tryParseFPImm - A floating point immediate expression operand.
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
- bool Hash = false;
- if (Parser.getTok().is(AsmToken::Hash)) {
- Parser.Lex(); // Eat '#'
- Hash = true;
- }
+ bool Hash = parseOptionalToken(AsmToken::Hash);
// Handle negation, as that still comes through as a separate token.
- bool isNegative = false;
- if (Parser.getTok().is(AsmToken::Minus)) {
- isNegative = true;
- Parser.Lex();
- }
+ bool isNegative = parseOptionalToken(AsmToken::Minus);
+
const AsmToken &Tok = Parser.getTok();
if (Tok.is(AsmToken::Real)) {
- APFloat RealVal(APFloat::IEEEdouble, Tok.getString());
+ APFloat RealVal(APFloat::IEEEdouble(), Tok.getString());
if (isNegative)
RealVal.changeSign();
@@ -2237,7 +2287,7 @@ AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
return MatchOperand_ParseFail;
}
} else {
- APFloat RealVal(APFloat::IEEEdouble, Tok.getString());
+ APFloat RealVal(APFloat::IEEEdouble(), Tok.getString());
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
// If we had a '-' in front, toggle the sign bit.
IntVal ^= (uint64_t)isNegative << 63;
@@ -2256,7 +2306,7 @@ AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
}
/// tryParseAddSubImm - Parse ADD/SUB shifted immediate operand
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseAddSubImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = getLoc();
@@ -2299,9 +2349,7 @@ AArch64AsmParser::tryParseAddSubImm(OperandVector &Operands) {
// Eat 'lsl'
Parser.Lex();
- if (Parser.getTok().is(AsmToken::Hash)) {
- Parser.Lex();
- }
+ parseOptionalToken(AsmToken::Hash);
if (Parser.getTok().isNot(AsmToken::Integer)) {
Error(Parser.getTok().getLoc(), "only 'lsl #+N' valid after immediate");
@@ -2374,7 +2422,7 @@ bool AArch64AsmParser::parseCondCode(OperandVector &Operands,
/// tryParseOptionalShift - Some operands take an optional shift argument. Parse
/// them if present.
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseOptionalShiftExtend(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -2402,7 +2450,8 @@ AArch64AsmParser::tryParseOptionalShiftExtend(OperandVector &Operands) {
SMLoc S = Tok.getLoc();
Parser.Lex();
- bool Hash = getLexer().is(AsmToken::Hash);
+ bool Hash = parseOptionalToken(AsmToken::Hash);
+
if (!Hash && getLexer().isNot(AsmToken::Integer)) {
if (ShOp == AArch64_AM::LSL || ShOp == AArch64_AM::LSR ||
ShOp == AArch64_AM::ASR || ShOp == AArch64_AM::ROR ||
@@ -2412,20 +2461,19 @@ AArch64AsmParser::tryParseOptionalShiftExtend(OperandVector &Operands) {
return MatchOperand_ParseFail;
}
- // "extend" type operatoins don't need an immediate, #0 is implicit.
+ // "extend" type operations don't need an immediate, #0 is implicit.
SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
Operands.push_back(
AArch64Operand::CreateShiftExtend(ShOp, 0, false, S, E, getContext()));
return MatchOperand_Success;
}
- if (Hash)
- Parser.Lex(); // Eat the '#'.
-
- // Make sure we do actually have a number or a parenthesized expression.
+ // Make sure we do actually have a number, identifier or a parenthesized
+ // expression.
SMLoc E = Parser.getTok().getLoc();
if (!Parser.getTok().is(AsmToken::Integer) &&
- !Parser.getTok().is(AsmToken::LParen)) {
+ !Parser.getTok().is(AsmToken::LParen) &&
+ !Parser.getTok().is(AsmToken::Identifier)) {
Error(E, "expected integer shift amount");
return MatchOperand_ParseFail;
}
@@ -2476,7 +2524,7 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
Expr = MCConstantExpr::create(op2, getContext()); \
Operands.push_back( \
AArch64Operand::CreateImm(Expr, S, getLoc(), getContext())); \
- } while (0)
+ } while (false)
if (Mnemonic == "ic") {
if (!Op.compare_lower("ialluis")) {
@@ -2690,20 +2738,12 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
bool HasRegister = false;
// Check for the optional register operand.
- if (getLexer().is(AsmToken::Comma)) {
- Parser.Lex(); // Eat comma.
-
+ if (parseOptionalToken(AsmToken::Comma)) {
if (Tok.isNot(AsmToken::Identifier) || parseRegister(Operands))
return TokError("expected register operand");
-
HasRegister = true;
}
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Parser.eatToEndOfStatement();
- return TokError("unexpected token in argument list");
- }
-
if (ExpectRegister && !HasRegister) {
return TokError("specified " + Mnemonic + " op requires a register");
}
@@ -2711,21 +2751,21 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
return TokError("specified " + Mnemonic + " op does not use a register");
}
- Parser.Lex(); // Consume the EndOfStatement
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
+ return true;
+
return false;
}
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
// Can be either a #imm style literal or an option name
- bool Hash = Tok.is(AsmToken::Hash);
- if (Hash || Tok.is(AsmToken::Integer)) {
+ if (parseOptionalToken(AsmToken::Hash) ||
+ Tok.is(AsmToken::Integer)) {
// Immediate operand.
- if (Hash)
- Parser.Lex(); // Eat the '#'
const MCExpr *ImmVal;
SMLoc ExprLoc = getLoc();
if (getParser().parseExpression(ImmVal))
@@ -2769,7 +2809,7 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
return MatchOperand_Success;
}
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseSysReg(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -2819,10 +2859,8 @@ bool AArch64AsmParser::tryParseVectorRegister(OperandVector &Operands) {
AArch64Operand::CreateToken(Kind, false, S, getContext()));
// If there is an index specifier following the register, parse that too.
- if (Parser.getTok().is(AsmToken::LBrac)) {
- SMLoc SIdx = getLoc();
- Parser.Lex(); // Eat left bracket token.
-
+ SMLoc SIdx = getLoc();
+ if (parseOptionalToken(AsmToken::LBrac)) {
const MCExpr *ImmVal;
if (getParser().parseExpression(ImmVal))
return false;
@@ -2833,12 +2871,9 @@ bool AArch64AsmParser::tryParseVectorRegister(OperandVector &Operands) {
}
SMLoc E = getLoc();
- if (Parser.getTok().isNot(AsmToken::RBrac)) {
- Error(E, "']' expected");
- return false;
- }
- Parser.Lex(); // Eat right bracket token.
+ if (parseToken(AsmToken::RBrac, "']' expected"))
+ return false;
Operands.push_back(AArch64Operand::CreateVectorIndex(MCE->getValue(), SIdx,
E, getContext()));
@@ -2864,18 +2899,16 @@ bool AArch64AsmParser::parseRegister(OperandVector &Operands) {
// A small number of instructions (FMOVXDhighr, for example) have "[1]"
// as a string token in the instruction itself.
- if (getLexer().getKind() == AsmToken::LBrac) {
- SMLoc LBracS = getLoc();
- Parser.Lex();
- const AsmToken &Tok = Parser.getTok();
+ SMLoc LBracS = getLoc();
+ const AsmToken &Tok = Parser.getTok();
+ if (parseOptionalToken(AsmToken::LBrac)) {
if (Tok.is(AsmToken::Integer)) {
SMLoc IntS = getLoc();
int64_t Val = Tok.getIntVal();
if (Val == 1) {
Parser.Lex();
- if (getLexer().getKind() == AsmToken::RBrac) {
- SMLoc RBracS = getLoc();
- Parser.Lex();
+ SMLoc RBracS = getLoc();
+ if (parseOptionalToken(AsmToken::RBrac)) {
Operands.push_back(
AArch64Operand::CreateToken("[", false, LBracS, getContext()));
Operands.push_back(
@@ -2896,15 +2929,11 @@ bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) {
bool HasELFModifier = false;
AArch64MCExpr::VariantKind RefKind;
- if (Parser.getTok().is(AsmToken::Colon)) {
- Parser.Lex(); // Eat ':"
+ if (parseOptionalToken(AsmToken::Colon)) {
HasELFModifier = true;
- if (Parser.getTok().isNot(AsmToken::Identifier)) {
- Error(Parser.getTok().getLoc(),
- "expect relocation specifier in operand after ':'");
- return true;
- }
+ if (Parser.getTok().isNot(AsmToken::Identifier))
+ return TokError("expect relocation specifier in operand after ':'");
std::string LowerCase = Parser.getTok().getIdentifier().lower();
RefKind = StringSwitch<AArch64MCExpr::VariantKind>(LowerCase)
@@ -2945,19 +2974,13 @@ bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) {
.Case("tlsdesc", AArch64MCExpr::VK_TLSDESC_PAGE)
.Default(AArch64MCExpr::VK_INVALID);
- if (RefKind == AArch64MCExpr::VK_INVALID) {
- Error(Parser.getTok().getLoc(),
- "expect relocation specifier in operand after ':'");
- return true;
- }
+ if (RefKind == AArch64MCExpr::VK_INVALID)
+ return TokError("expect relocation specifier in operand after ':'");
Parser.Lex(); // Eat identifier
- if (Parser.getTok().isNot(AsmToken::Colon)) {
- Error(Parser.getTok().getLoc(), "expect ':' after relocation specifier");
+ if (parseToken(AsmToken::Colon, "expect ':' after relocation specifier"))
return true;
- }
- Parser.Lex(); // Eat ':'
}
if (getParser().parseExpression(ImmVal))
@@ -2982,9 +3005,7 @@ bool AArch64AsmParser::parseVectorList(OperandVector &Operands) {
int64_t PrevReg = FirstReg;
unsigned Count = 1;
- if (Parser.getTok().is(AsmToken::Minus)) {
- Parser.Lex(); // Eat the minus.
-
+ if (parseOptionalToken(AsmToken::Minus)) {
SMLoc Loc = getLoc();
StringRef NextKind;
int64_t Reg = tryMatchVectorRegister(NextKind, true);
@@ -3003,9 +3024,7 @@ bool AArch64AsmParser::parseVectorList(OperandVector &Operands) {
Count += Space;
}
else {
- while (Parser.getTok().is(AsmToken::Comma)) {
- Parser.Lex(); // Eat the comma token.
-
+ while (parseOptionalToken(AsmToken::Comma)) {
SMLoc Loc = getLoc();
StringRef NextKind;
int64_t Reg = tryMatchVectorRegister(NextKind, true);
@@ -3025,9 +3044,8 @@ bool AArch64AsmParser::parseVectorList(OperandVector &Operands) {
}
}
- if (Parser.getTok().isNot(AsmToken::RCurly))
- return Error(getLoc(), "'}' expected");
- Parser.Lex(); // Eat the '}' token.
+ if (parseToken(AsmToken::RCurly, "'}' expected"))
+ return true;
if (Count > 4)
return Error(S, "invalid number of vectors");
@@ -3041,10 +3059,8 @@ bool AArch64AsmParser::parseVectorList(OperandVector &Operands) {
FirstReg, Count, NumElements, ElementKind, S, getLoc(), getContext()));
// If there is an index specifier following the list, parse that too.
- if (Parser.getTok().is(AsmToken::LBrac)) {
- SMLoc SIdx = getLoc();
- Parser.Lex(); // Eat left bracket token.
-
+ SMLoc SIdx = getLoc();
+ if (parseOptionalToken(AsmToken::LBrac)) { // Eat left bracket token.
const MCExpr *ImmVal;
if (getParser().parseExpression(ImmVal))
return false;
@@ -3055,12 +3071,8 @@ bool AArch64AsmParser::parseVectorList(OperandVector &Operands) {
}
SMLoc E = getLoc();
- if (Parser.getTok().isNot(AsmToken::RBrac)) {
- Error(E, "']' expected");
+ if (parseToken(AsmToken::RBrac, "']' expected"))
return false;
- }
-
- Parser.Lex(); // Eat right bracket token.
Operands.push_back(AArch64Operand::CreateVectorIndex(MCE->getValue(), SIdx,
E, getContext()));
@@ -3068,7 +3080,7 @@ bool AArch64AsmParser::parseVectorList(OperandVector &Operands) {
return false;
}
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -3085,15 +3097,13 @@ AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) {
SMLoc S = getLoc();
Parser.Lex(); // Eat register
- if (Parser.getTok().isNot(AsmToken::Comma)) {
+ if (!parseOptionalToken(AsmToken::Comma)) {
Operands.push_back(
AArch64Operand::CreateReg(RegNum, false, S, getLoc(), Ctx));
return MatchOperand_Success;
}
- Parser.Lex(); // Eat comma.
- if (Parser.getTok().is(AsmToken::Hash))
- Parser.Lex(); // Eat hash
+ parseOptionalToken(AsmToken::Hash);
if (Parser.getTok().isNot(AsmToken::Integer)) {
Error(getLoc(), "index must be absent or #0");
@@ -3174,7 +3184,6 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
S = getLoc();
if (getParser().parseExpression(IdVal))
return true;
-
E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
Operands.push_back(AArch64Operand::CreateImm(IdVal, S, E, getContext()));
return false;
@@ -3184,8 +3193,8 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
case AsmToken::Hash: {
// #42 -> immediate.
S = getLoc();
- if (getLexer().is(AsmToken::Hash))
- Parser.Lex();
+
+ parseOptionalToken(AsmToken::Hash);
// Parse a negative sign
bool isNegative = false;
@@ -3202,7 +3211,7 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
// so convert the value.
const AsmToken &Tok = Parser.getTok();
if (Tok.is(AsmToken::Real)) {
- APFloat RealVal(APFloat::IEEEdouble, Tok.getString());
+ APFloat RealVal(APFloat::IEEEdouble(), Tok.getString());
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
if (Mnemonic != "fcmp" && Mnemonic != "fcmpe" && Mnemonic != "fcmeq" &&
Mnemonic != "fcmge" && Mnemonic != "fcmgt" && Mnemonic != "fcmle" &&
@@ -3228,9 +3237,9 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
return false;
}
case AsmToken::Equal: {
- SMLoc Loc = Parser.getTok().getLoc();
+ SMLoc Loc = getLoc();
if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val)
- return Error(Loc, "unexpected token in operand");
+ return TokError("unexpected token in operand");
Parser.Lex(); // Eat '='
const MCExpr *SubExprVal;
if (getParser().parseExpression(SubExprVal))
@@ -3318,12 +3327,8 @@ bool AArch64AsmParser::ParseInstruction(ParseInstructionInfo &Info,
StringRef Head = Name.slice(Start, Next);
// IC, DC, AT, and TLBI instructions are aliases for the SYS instruction.
- if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi") {
- bool IsError = parseSysAlias(Head, NameLoc, Operands);
- if (IsError && getLexer().isNot(AsmToken::EndOfStatement))
- Parser.eatToEndOfStatement();
- return IsError;
- }
+ if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi")
+ return parseSysAlias(Head, NameLoc, Operands);
Operands.push_back(
AArch64Operand::CreateToken(Head, false, NameLoc, getContext()));
@@ -3378,20 +3383,16 @@ bool AArch64AsmParser::ParseInstruction(ParseInstructionInfo &Info,
if (getLexer().isNot(AsmToken::EndOfStatement)) {
// Read the first operand.
if (parseOperand(Operands, false, false)) {
- Parser.eatToEndOfStatement();
return true;
}
unsigned N = 2;
- while (getLexer().is(AsmToken::Comma)) {
- Parser.Lex(); // Eat the comma.
-
+ while (parseOptionalToken(AsmToken::Comma)) {
// Parse and remember the operand.
if (parseOperand(Operands, (N == 4 && condCodeFourthOperand) ||
(N == 3 && condCodeThirdOperand) ||
(N == 2 && condCodeSecondOperand),
condCodeSecondOperand || condCodeThirdOperand)) {
- Parser.eatToEndOfStatement();
return true;
}
@@ -3403,31 +3404,23 @@ bool AArch64AsmParser::ParseInstruction(ParseInstructionInfo &Info,
//
// It's someone else's responsibility to make sure these tokens are sane
// in the given context!
- if (Parser.getTok().is(AsmToken::RBrac)) {
- SMLoc Loc = Parser.getTok().getLoc();
- Operands.push_back(AArch64Operand::CreateToken("]", false, Loc,
- getContext()));
- Parser.Lex();
- }
- if (Parser.getTok().is(AsmToken::Exclaim)) {
- SMLoc Loc = Parser.getTok().getLoc();
- Operands.push_back(AArch64Operand::CreateToken("!", false, Loc,
- getContext()));
- Parser.Lex();
- }
+ SMLoc RLoc = Parser.getTok().getLoc();
+ if (parseOptionalToken(AsmToken::RBrac))
+ Operands.push_back(
+ AArch64Operand::CreateToken("]", false, RLoc, getContext()));
+ SMLoc ELoc = Parser.getTok().getLoc();
+ if (parseOptionalToken(AsmToken::Exclaim))
+ Operands.push_back(
+ AArch64Operand::CreateToken("!", false, ELoc, getContext()));
++N;
}
}
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- SMLoc Loc = Parser.getTok().getLoc();
- Parser.eatToEndOfStatement();
- return Error(Loc, "unexpected token in argument list");
- }
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
+ return true;
- Parser.Lex(); // Consume the EndOfStatement
return false;
}
@@ -3455,7 +3448,7 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst,
if (RI->isSubRegisterEq(Rn, Rt2))
return Error(Loc[1], "unpredictable LDP instruction, writeback base "
"is also a destination");
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
case AArch64::LDPDi:
case AArch64::LDPQi:
@@ -3572,31 +3565,34 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst,
AArch64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind;
int64_t Addend;
- if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
- return Error(Loc[2], "invalid immediate expression");
- }
+ if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
- // Only allow these with ADDXri.
- if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
- DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
- Inst.getOpcode() == AArch64::ADDXri)
- return false;
+ // Only allow these with ADDXri.
+ if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF ||
+ DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) &&
+ Inst.getOpcode() == AArch64::ADDXri)
+ return false;
- // Only allow these with ADDXri/ADDWri
- if ((ELFRefKind == AArch64MCExpr::VK_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
- ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
- ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12) &&
- (Inst.getOpcode() == AArch64::ADDXri ||
- Inst.getOpcode() == AArch64::ADDWri))
- return false;
+ // Only allow these with ADDXri/ADDWri
+ if ((ELFRefKind == AArch64MCExpr::VK_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 ||
+ ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC ||
+ ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12) &&
+ (Inst.getOpcode() == AArch64::ADDXri ||
+ Inst.getOpcode() == AArch64::ADDWri))
+ return false;
- // Don't allow expressions in the immediate field otherwise
- return Error(Loc[2], "invalid immediate expression");
+ // Don't allow symbol refs in the immediate field otherwise
+ // Note: Loc.back() may be Loc[1] or Loc[2] depending on the number of
+ // operands of the original instruction (i.e. 'add w0, w1, borked' vs
+ // 'cmp w0, 'borked')
+ return Error(Loc.back(), "invalid immediate expression");
+ }
+ // We don't validate more complex expressions here
}
return false;
}
@@ -4038,7 +4034,6 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
}
}
-
switch (MatchResult) {
case Match_Success: {
// Perform range checking and other semantic validations
@@ -4075,7 +4070,8 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
if (ErrorInfo != ~0ULL) {
if (ErrorInfo >= Operands.size())
- return Error(IDLoc, "too few operands for instruction");
+ return Error(IDLoc, "too few operands for instruction",
+ SMRange(IDLoc, getTok().getLoc()));
ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc();
if (ErrorLoc == SMLoc())
@@ -4138,7 +4134,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_MSR:
case Match_MRS: {
if (ErrorInfo >= Operands.size())
- return Error(IDLoc, "too few operands for instruction");
+ return Error(IDLoc, "too few operands for instruction", SMRange(IDLoc, (*Operands.back()).getEndLoc()));
// Any time we get here, there's nothing fancy to do. Just get the
// operand SMLoc and display the diagnostic.
SMLoc ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc();
@@ -4161,28 +4157,31 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
SMLoc Loc = DirectiveID.getLoc();
if (IDVal == ".arch")
- return parseDirectiveArch(Loc);
- if (IDVal == ".cpu")
- return parseDirectiveCPU(Loc);
- if (IDVal == ".hword")
- return parseDirectiveWord(2, Loc);
- if (IDVal == ".word")
- return parseDirectiveWord(4, Loc);
- if (IDVal == ".xword")
- return parseDirectiveWord(8, Loc);
- if (IDVal == ".tlsdesccall")
- return parseDirectiveTLSDescCall(Loc);
- if (IDVal == ".ltorg" || IDVal == ".pool")
- return parseDirectiveLtorg(Loc);
- if (IDVal == ".unreq")
- return parseDirectiveUnreq(Loc);
-
- if (!IsMachO && !IsCOFF) {
+ parseDirectiveArch(Loc);
+ else if (IDVal == ".cpu")
+ parseDirectiveCPU(Loc);
+ else if (IDVal == ".hword")
+ parseDirectiveWord(2, Loc);
+ else if (IDVal == ".word")
+ parseDirectiveWord(4, Loc);
+ else if (IDVal == ".xword")
+ parseDirectiveWord(8, Loc);
+ else if (IDVal == ".tlsdesccall")
+ parseDirectiveTLSDescCall(Loc);
+ else if (IDVal == ".ltorg" || IDVal == ".pool")
+ parseDirectiveLtorg(Loc);
+ else if (IDVal == ".unreq")
+ parseDirectiveUnreq(Loc);
+ else if (!IsMachO && !IsCOFF) {
if (IDVal == ".inst")
- return parseDirectiveInst(Loc);
- }
-
- return parseDirectiveLOH(IDVal, Loc);
+ parseDirectiveInst(Loc);
+ else
+ return true;
+ } else if (IDVal == MCLOHDirectiveName())
+ parseDirectiveLOH(IDVal, Loc);
+ else
+ return true;
+ return false;
}
static const struct {
@@ -4193,9 +4192,10 @@ static const struct {
{ "crypto", {AArch64::FeatureCrypto} },
{ "fp", {AArch64::FeatureFPARMv8} },
{ "simd", {AArch64::FeatureNEON} },
+ { "ras", {AArch64::FeatureRAS} },
+ { "lse", {AArch64::FeatureLSE} },
// FIXME: Unsupported extensions
- { "lse", {} },
{ "pan", {} },
{ "lor", {} },
{ "rdma", {} },
@@ -4212,17 +4212,51 @@ bool AArch64AsmParser::parseDirectiveArch(SMLoc L) {
getParser().parseStringToEndOfStatement().trim().split('+');
unsigned ID = AArch64::parseArch(Arch);
- if (ID == ARM::AK_INVALID) {
- Error(ArchLoc, "unknown arch name");
- return false;
- }
+ if (ID == static_cast<unsigned>(AArch64::ArchKind::AK_INVALID))
+ return Error(ArchLoc, "unknown arch name");
+
+ if (parseToken(AsmToken::EndOfStatement))
+ return true;
+
+ // Get the architecture and extension features.
+ std::vector<StringRef> AArch64Features;
+ AArch64::getArchFeatures(ID, AArch64Features);
+ AArch64::getExtensionFeatures(AArch64::getDefaultExtensions("generic", ID),
+ AArch64Features);
MCSubtargetInfo &STI = copySTI();
- STI.setDefaultFeatures("", "");
+ std::vector<std::string> ArchFeatures(AArch64Features.begin(), AArch64Features.end());
+ STI.setDefaultFeatures("generic", join(ArchFeatures.begin(), ArchFeatures.end(), ","));
+
+ SmallVector<StringRef, 4> RequestedExtensions;
if (!ExtensionString.empty())
- STI.setDefaultFeatures("", ("+" + ExtensionString).str());
- setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+ ExtensionString.split(RequestedExtensions, '+');
+ FeatureBitset Features = STI.getFeatureBits();
+ for (auto Name : RequestedExtensions) {
+ bool EnableFeature = true;
+
+ if (Name.startswith_lower("no")) {
+ EnableFeature = false;
+ Name = Name.substr(2);
+ }
+
+ for (const auto &Extension : ExtensionMap) {
+ if (Extension.Name != Name)
+ continue;
+
+ if (Extension.Features.none())
+ report_fatal_error("unsupported architectural extension: " + Name);
+
+ FeatureBitset ToggleFeatures = EnableFeature
+ ? (~Features & Extension.Features)
+ : ( Features & Extension.Features);
+ uint64_t Features =
+ ComputeAvailableFeatures(STI.ToggleFeature(ToggleFeatures));
+ setAvailableFeatures(Features);
+ break;
+ }
+ }
return false;
}
@@ -4235,6 +4269,9 @@ bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) {
std::tie(CPU, ExtensionString) =
getParser().parseStringToEndOfStatement().trim().split('+');
+ if (parseToken(AsmToken::EndOfStatement))
+ return true;
+
SmallVector<StringRef, 4> RequestedExtensions;
if (!ExtensionString.empty())
ExtensionString.split(RequestedExtensions, '+');
@@ -4281,67 +4318,39 @@ bool AArch64AsmParser::parseDirectiveCPU(SMLoc L) {
/// parseDirectiveWord
/// ::= .word [ expression (, expression)* ]
bool AArch64AsmParser::parseDirectiveWord(unsigned Size, SMLoc L) {
- MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- for (;;) {
- const MCExpr *Value;
- if (getParser().parseExpression(Value))
- return true;
-
- getParser().getStreamer().EmitValue(Value, Size, L);
-
- if (getLexer().is(AsmToken::EndOfStatement))
- break;
-
- // FIXME: Improve diagnostic.
- if (getLexer().isNot(AsmToken::Comma))
- return Error(L, "unexpected token in directive");
- Parser.Lex();
- }
- }
+ auto parseOp = [&]() -> bool {
+ const MCExpr *Value;
+ if (getParser().parseExpression(Value))
+ return true;
+ getParser().getStreamer().EmitValue(Value, Size, L);
+ return false;
+ };
- Parser.Lex();
+ if (parseMany(parseOp))
+ return true;
return false;
}
/// parseDirectiveInst
/// ::= .inst opcode [, ...]
bool AArch64AsmParser::parseDirectiveInst(SMLoc Loc) {
- MCAsmParser &Parser = getParser();
- if (getLexer().is(AsmToken::EndOfStatement)) {
- Parser.eatToEndOfStatement();
- Error(Loc, "expected expression following directive");
- return false;
- }
+ if (getLexer().is(AsmToken::EndOfStatement))
+ return Error(Loc, "expected expression following '.inst' directive");
- for (;;) {
+ auto parseOp = [&]() -> bool {
+ SMLoc L = getLoc();
const MCExpr *Expr;
-
- if (getParser().parseExpression(Expr)) {
- Error(Loc, "expected expression");
- return false;
- }
-
+ if (check(getParser().parseExpression(Expr), L, "expected expression"))
+ return true;
const MCConstantExpr *Value = dyn_cast_or_null<MCConstantExpr>(Expr);
- if (!Value) {
- Error(Loc, "expected constant expression");
- return false;
- }
-
+ if (check(!Value, L, "expected constant expression"))
+ return true;
getTargetStreamer().emitInst(Value->getValue());
+ return false;
+ };
- if (getLexer().is(AsmToken::EndOfStatement))
- break;
-
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(Loc, "unexpected token in directive");
- return false;
- }
-
- Parser.Lex(); // Eat comma.
- }
-
- Parser.Lex();
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '.inst' directive");
return false;
}
@@ -4349,8 +4358,10 @@ bool AArch64AsmParser::parseDirectiveInst(SMLoc Loc) {
// ::= .tlsdesccall symbol
bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) {
StringRef Name;
- if (getParser().parseIdentifier(Name))
- return Error(L, "expected symbol after directive");
+ if (check(getParser().parseIdentifier(Name), L,
+ "expected symbol after directive") ||
+ parseToken(AsmToken::EndOfStatement))
+ return true;
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());
@@ -4367,8 +4378,6 @@ bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) {
/// ::= .loh <lohName | lohId> label1, ..., labelN
/// The number of arguments depends on the loh identifier.
bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) {
- if (IDVal != MCLOHDirectiveName())
- return true;
MCLOHType Kind;
if (getParser().getTok().isNot(AsmToken::Identifier)) {
if (getParser().getTok().isNot(AsmToken::Integer))
@@ -4405,12 +4414,13 @@ bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) {
if (Idx + 1 == NbArgs)
break;
- if (getLexer().isNot(AsmToken::Comma))
- return TokError("unexpected token in '" + Twine(IDVal) + "' directive");
- Lex();
+ if (parseToken(AsmToken::Comma,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
}
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return TokError("unexpected token in '" + Twine(IDVal) + "' directive");
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
getStreamer().EmitLOHDirective((MCLOHType)Kind, Args);
return false;
@@ -4419,6 +4429,8 @@ bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) {
/// parseDirectiveLtorg
/// ::= .ltorg | .pool
bool AArch64AsmParser::parseDirectiveLtorg(SMLoc L) {
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
getTargetStreamer().emitCurrentConstantPool();
return false;
}
@@ -4435,46 +4447,36 @@ bool AArch64AsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
if (RegNum == static_cast<unsigned>(-1)) {
StringRef Kind;
RegNum = tryMatchVectorRegister(Kind, false);
- if (!Kind.empty()) {
- Error(SRegLoc, "vector register without type specifier expected");
- return false;
- }
+ if (!Kind.empty())
+ return Error(SRegLoc, "vector register without type specifier expected");
IsVector = true;
}
- if (RegNum == static_cast<unsigned>(-1)) {
- Parser.eatToEndOfStatement();
- Error(SRegLoc, "register name or alias expected");
- return false;
- }
+ if (RegNum == static_cast<unsigned>(-1))
+ return Error(SRegLoc, "register name or alias expected");
// Shouldn't be anything else.
- if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(), "unexpected input in .req directive");
- Parser.eatToEndOfStatement();
- return false;
- }
-
- Parser.Lex(); // Consume the EndOfStatement
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected input in .req directive"))
+ return true;
auto pair = std::make_pair(IsVector, RegNum);
if (RegisterReqs.insert(std::make_pair(Name, pair)).first->second != pair)
Warning(L, "ignoring redefinition of register alias '" + Name + "'");
- return true;
+ return false;
}
/// parseDirectiveUneq
/// ::= .unreq registername
bool AArch64AsmParser::parseDirectiveUnreq(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (Parser.getTok().isNot(AsmToken::Identifier)) {
- Error(Parser.getTok().getLoc(), "unexpected input in .unreq directive.");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (getTok().isNot(AsmToken::Identifier))
+ return TokError("unexpected input in .unreq directive.");
RegisterReqs.erase(Parser.getTok().getIdentifier().lower());
Parser.Lex(); // Eat the identifier.
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix("in '.unreq' directive");
return false;
}
@@ -4530,9 +4532,9 @@ AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
/// Force static initialization.
extern "C" void LLVMInitializeAArch64AsmParser() {
- RegisterMCAsmParser<AArch64AsmParser> X(TheAArch64leTarget);
- RegisterMCAsmParser<AArch64AsmParser> Y(TheAArch64beTarget);
- RegisterMCAsmParser<AArch64AsmParser> Z(TheARM64Target);
+ RegisterMCAsmParser<AArch64AsmParser> X(getTheAArch64leTarget());
+ RegisterMCAsmParser<AArch64AsmParser> Y(getTheAArch64beTarget());
+ RegisterMCAsmParser<AArch64AsmParser> Z(getTheARM64Target());
}
#define GET_REGISTER_MATCHER
@@ -4602,8 +4604,7 @@ unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
return Match_InvalidOperand;
}
-
-AArch64AsmParser::OperandMatchResultTy
+OperandMatchResultTy
AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
SMLoc S = getLoc();
@@ -4653,16 +4654,16 @@ AArch64AsmParser::tryParseGPRSeqPair(OperandVector &Operands) {
return MatchOperand_ParseFail;
}
- if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1 ||
+ if (RI->getEncodingValue(SecondReg) != FirstEncoding + 1 ||
(isXReg && !XRegClass.contains(SecondReg)) ||
(isWReg && !WRegClass.contains(SecondReg))) {
Error(E,"expected second odd register of a "
"consecutive same-size even/odd register pair");
return MatchOperand_ParseFail;
}
-
+
unsigned Pair = 0;
- if(isXReg) {
+ if (isXReg) {
Pair = RI->getMatchingSuperReg(FirstReg, AArch64::sube64,
&AArch64MCRegisterClasses[AArch64::XSeqPairsClassRegClassID]);
} else {
diff --git a/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index fe6ea31..0d860a7 100644
--- a/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -237,18 +237,18 @@ createAArch64ExternalSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo,
}
extern "C" void LLVMInitializeAArch64Disassembler() {
- TargetRegistry::RegisterMCDisassembler(TheAArch64leTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheAArch64leTarget(),
createAArch64Disassembler);
- TargetRegistry::RegisterMCDisassembler(TheAArch64beTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheAArch64beTarget(),
createAArch64Disassembler);
- TargetRegistry::RegisterMCSymbolizer(TheAArch64leTarget,
+ TargetRegistry::RegisterMCSymbolizer(getTheAArch64leTarget(),
createAArch64ExternalSymbolizer);
- TargetRegistry::RegisterMCSymbolizer(TheAArch64beTarget,
+ TargetRegistry::RegisterMCSymbolizer(getTheAArch64beTarget(),
createAArch64ExternalSymbolizer);
- TargetRegistry::RegisterMCDisassembler(TheARM64Target,
+ TargetRegistry::RegisterMCDisassembler(getTheARM64Target(),
createAArch64Disassembler);
- TargetRegistry::RegisterMCSymbolizer(TheARM64Target,
+ TargetRegistry::RegisterMCSymbolizer(getTheARM64Target(),
createAArch64ExternalSymbolizer);
}
@@ -1097,7 +1097,7 @@ static DecodeStatus DecodeExclusiveLdStInstruction(llvm::MCInst &Inst,
case AArch64::STXRB:
case AArch64::STXRH:
DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case AArch64::LDARW:
case AArch64::LDARB:
case AArch64::LDARH:
@@ -1121,7 +1121,7 @@ static DecodeStatus DecodeExclusiveLdStInstruction(llvm::MCInst &Inst,
case AArch64::STLXRX:
case AArch64::STXRX:
DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case AArch64::LDARX:
case AArch64::LDAXRX:
case AArch64::LDXRX:
@@ -1133,7 +1133,7 @@ static DecodeStatus DecodeExclusiveLdStInstruction(llvm::MCInst &Inst,
case AArch64::STLXPW:
case AArch64::STXPW:
DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case AArch64::LDAXPW:
case AArch64::LDXPW:
DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder);
@@ -1142,7 +1142,7 @@ static DecodeStatus DecodeExclusiveLdStInstruction(llvm::MCInst &Inst,
case AArch64::STLXPX:
case AArch64::STXPX:
DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case AArch64::LDAXPX:
case AArch64::LDXPX:
DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder);
@@ -1218,7 +1218,7 @@ static DecodeStatus DecodePairLdStInstruction(llvm::MCInst &Inst, uint32_t insn,
case AArch64::STPXpre:
case AArch64::LDPSWpre:
NeedsDisjointWritebackTransfer = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case AArch64::LDNPXi:
case AArch64::STNPXi:
case AArch64::LDPXi:
@@ -1232,7 +1232,7 @@ static DecodeStatus DecodePairLdStInstruction(llvm::MCInst &Inst, uint32_t insn,
case AArch64::LDPWpre:
case AArch64::STPWpre:
NeedsDisjointWritebackTransfer = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case AArch64::LDNPWi:
case AArch64::STNPWi:
case AArch64::LDPWi:
diff --git a/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h b/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h
index e475e50..bc2f7f1 100644
--- a/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h
+++ b/contrib/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.h
@@ -17,16 +17,12 @@
namespace llvm {
-class MCInst;
-class MemoryObject;
-class raw_ostream;
-
class AArch64Disassembler : public MCDisassembler {
public:
AArch64Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
: MCDisassembler(STI, Ctx) {}
- ~AArch64Disassembler() {}
+ ~AArch64Disassembler() override = default;
MCDisassembler::DecodeStatus
getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes,
@@ -34,6 +30,6 @@ public:
raw_ostream &CStream) const override;
};
-} // namespace llvm
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_AARCH64_DISASSEMBLER_AARCH64DISASSEMBLER_H
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
index 2799324..14c0327 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
@@ -11,6 +11,7 @@
#include "AArch64RegisterInfo.h"
#include "MCTargetDesc/AArch64FixupKinds.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDirectives.h"
@@ -520,6 +521,17 @@ public:
return CompactUnwindEncoding;
}
+
+ void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) override {
+ // Try to get the encoded value for the fixup as-if we're mapping it into
+ // the instruction. This allows adjustFixupValue() to issue a diagnostic
+ // if the value is invalid.
+ if (IsResolved)
+ (void)adjustFixupValue(Fixup, Value, &Asm.getContext());
+ }
};
} // end anonymous namespace
@@ -529,12 +541,14 @@ namespace {
class ELFAArch64AsmBackend : public AArch64AsmBackend {
public:
uint8_t OSABI;
+ bool IsILP32;
- ELFAArch64AsmBackend(const Target &T, uint8_t OSABI, bool IsLittleEndian)
- : AArch64AsmBackend(T, IsLittleEndian), OSABI(OSABI) {}
+ ELFAArch64AsmBackend(const Target &T, uint8_t OSABI, bool IsLittleEndian,
+ bool IsILP32)
+ : AArch64AsmBackend(T, IsLittleEndian), OSABI(OSABI), IsILP32(IsILP32) {}
MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
- return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian);
+ return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian, IsILP32);
}
void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
@@ -574,22 +588,25 @@ void ELFAArch64AsmBackend::processFixupValue(
MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const Triple &TheTriple,
- StringRef CPU) {
+ StringRef CPU,
+ const MCTargetOptions &Options) {
if (TheTriple.isOSBinFormatMachO())
return new DarwinAArch64AsmBackend(T, MRI);
assert(TheTriple.isOSBinFormatELF() && "Expect either MachO or ELF target");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
- return new ELFAArch64AsmBackend(T, OSABI, /*IsLittleEndian=*/true);
+ bool IsILP32 = Options.getABIName() == "ilp32";
+ return new ELFAArch64AsmBackend(T, OSABI, /*IsLittleEndian=*/true, IsILP32);
}
MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const Triple &TheTriple,
- StringRef CPU) {
+ StringRef CPU,
+ const MCTargetOptions &Options) {
assert(TheTriple.isOSBinFormatELF() &&
"Big endian is only supported for ELF targets!");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
- return new ELFAArch64AsmBackend(T, OSABI,
- /*IsLittleEndian=*/false);
+ bool IsILP32 = Options.getABIName() == "ilp32";
+ return new ELFAArch64AsmBackend(T, OSABI, /*IsLittleEndian=*/false, IsILP32);
}
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
index 4b4c409..c954c0e 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
@@ -17,32 +17,90 @@
#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+#include <cstdint>
using namespace llvm;
namespace {
+
class AArch64ELFObjectWriter : public MCELFObjectTargetWriter {
public:
- AArch64ELFObjectWriter(uint8_t OSABI, bool IsLittleEndian);
+ AArch64ELFObjectWriter(uint8_t OSABI, bool IsLittleEndian, bool IsILP32);
- ~AArch64ELFObjectWriter() override;
+ ~AArch64ELFObjectWriter() override = default;
protected:
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
const MCFixup &Fixup, bool IsPCRel) const override;
-
-private:
+ bool IsILP32;
};
-}
+
+} // end anonymous namespace
AArch64ELFObjectWriter::AArch64ELFObjectWriter(uint8_t OSABI,
- bool IsLittleEndian)
+ bool IsLittleEndian,
+ bool IsILP32)
: MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_AARCH64,
- /*HasRelocationAddend*/ true) {}
+ /*HasRelocationAddend*/ true),
+ IsILP32(IsILP32) {}
+
+#define R_CLS(rtype) \
+ IsILP32 ? ELF::R_AARCH64_P32_##rtype : ELF::R_AARCH64_##rtype
+#define BAD_ILP32_MOV(lp64rtype) "ILP32 absolute MOV relocation not "\
+ "supported (LP64 eqv: " #lp64rtype ")"
-AArch64ELFObjectWriter::~AArch64ELFObjectWriter() {}
+// assumes IsILP32 is true
+static bool isNonILP32reloc(const MCFixup &Fixup,
+ AArch64MCExpr::VariantKind RefKind,
+ MCContext &Ctx) {
+ if ((unsigned)Fixup.getKind() != AArch64::fixup_aarch64_movw)
+ return false;
+ switch(RefKind) {
+ case AArch64MCExpr::VK_ABS_G3:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G3));
+ return true;
+ case AArch64MCExpr::VK_ABS_G2:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G2));
+ return true;
+ case AArch64MCExpr::VK_ABS_G2_S:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_SABS_G2));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_ABS_G2_NC:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G2_NC));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_ABS_G1_S:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_SABS_G1));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_ABS_G1_NC:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(MOVW_UABS_G1_NC));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_DTPREL_G2:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLD_MOVW_DTPREL_G2));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_DTPREL_G1_NC:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLD_MOVW_DTPREL_G1_NC));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_TPREL_G2:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLE_MOVW_TPREL_G2));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_TPREL_G1_NC:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSLE_MOVW_TPREL_G1_NC));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_GOTTPREL_G1:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSIE_MOVW_GOTTPREL_G1));
+ return ELF::R_AARCH64_NONE;
+ case AArch64MCExpr::VK_GOTTPREL_G0_NC:
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(TLSIE_MOVW_GOTTPREL_G0_NC));
+ return ELF::R_AARCH64_NONE;
+ default: return false;
+ }
+ return false;
+}
unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
const MCValue &Target,
@@ -67,147 +125,161 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
return ELF::R_AARCH64_NONE;
case FK_Data_2:
- return ELF::R_AARCH64_PREL16;
+ return R_CLS(PREL16);
case FK_Data_4:
- return ELF::R_AARCH64_PREL32;
+ return R_CLS(PREL32);
case FK_Data_8:
- return ELF::R_AARCH64_PREL64;
+ if (IsILP32) {
+ Ctx.reportError(Fixup.getLoc(), "ILP32 8 byte PC relative data "
+ "relocation not supported (LP64 eqv: PREL64)");
+ return ELF::R_AARCH64_NONE;
+ } else
+ return ELF::R_AARCH64_PREL64;
case AArch64::fixup_aarch64_pcrel_adr_imm21:
assert(SymLoc == AArch64MCExpr::VK_NONE && "unexpected ADR relocation");
- return ELF::R_AARCH64_ADR_PREL_LO21;
+ return R_CLS(ADR_PREL_LO21);
case AArch64::fixup_aarch64_pcrel_adrp_imm21:
if (SymLoc == AArch64MCExpr::VK_ABS && !IsNC)
- return ELF::R_AARCH64_ADR_PREL_PG_HI21;
+ return R_CLS(ADR_PREL_PG_HI21);
if (SymLoc == AArch64MCExpr::VK_GOT && !IsNC)
- return ELF::R_AARCH64_ADR_GOT_PAGE;
+ return R_CLS(ADR_GOT_PAGE);
if (SymLoc == AArch64MCExpr::VK_GOTTPREL && !IsNC)
- return ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21;
+ return R_CLS(TLSIE_ADR_GOTTPREL_PAGE21);
if (SymLoc == AArch64MCExpr::VK_TLSDESC && !IsNC)
- return ELF::R_AARCH64_TLSDESC_ADR_PAGE21;
+ return R_CLS(TLSDESC_ADR_PAGE21);
Ctx.reportError(Fixup.getLoc(),
"invalid symbol kind for ADRP relocation");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_pcrel_branch26:
- return ELF::R_AARCH64_JUMP26;
+ return R_CLS(JUMP26);
case AArch64::fixup_aarch64_pcrel_call26:
- return ELF::R_AARCH64_CALL26;
+ return R_CLS(CALL26);
case AArch64::fixup_aarch64_ldr_pcrel_imm19:
if (SymLoc == AArch64MCExpr::VK_GOTTPREL)
- return ELF::R_AARCH64_TLSIE_LD_GOTTPREL_PREL19;
- return ELF::R_AARCH64_LD_PREL_LO19;
+ return R_CLS(TLSIE_LD_GOTTPREL_PREL19);
+ return R_CLS(LD_PREL_LO19);
case AArch64::fixup_aarch64_pcrel_branch14:
- return ELF::R_AARCH64_TSTBR14;
+ return R_CLS(TSTBR14);
case AArch64::fixup_aarch64_pcrel_branch19:
- return ELF::R_AARCH64_CONDBR19;
+ return R_CLS(CONDBR19);
default:
Ctx.reportError(Fixup.getLoc(), "Unsupported pc-relative fixup kind");
return ELF::R_AARCH64_NONE;
}
} else {
+ if (IsILP32 && isNonILP32reloc(Fixup, RefKind, Ctx))
+ return ELF::R_AARCH64_NONE;
switch ((unsigned)Fixup.getKind()) {
case FK_Data_1:
Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
return ELF::R_AARCH64_NONE;
case FK_Data_2:
- return ELF::R_AARCH64_ABS16;
+ return R_CLS(ABS16);
case FK_Data_4:
- return ELF::R_AARCH64_ABS32;
+ return R_CLS(ABS32);
case FK_Data_8:
- return ELF::R_AARCH64_ABS64;
+ if (IsILP32) {
+ Ctx.reportError(Fixup.getLoc(), BAD_ILP32_MOV(ABS64));
+ return ELF::R_AARCH64_NONE;
+ } else
+ return ELF::R_AARCH64_ABS64;
case AArch64::fixup_aarch64_add_imm12:
if (RefKind == AArch64MCExpr::VK_DTPREL_HI12)
- return ELF::R_AARCH64_TLSLD_ADD_DTPREL_HI12;
+ return R_CLS(TLSLD_ADD_DTPREL_HI12);
if (RefKind == AArch64MCExpr::VK_TPREL_HI12)
- return ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12;
+ return R_CLS(TLSLE_ADD_TPREL_HI12);
if (RefKind == AArch64MCExpr::VK_DTPREL_LO12_NC)
- return ELF::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC;
+ return R_CLS(TLSLD_ADD_DTPREL_LO12_NC);
if (RefKind == AArch64MCExpr::VK_DTPREL_LO12)
- return ELF::R_AARCH64_TLSLD_ADD_DTPREL_LO12;
+ return R_CLS(TLSLD_ADD_DTPREL_LO12);
if (RefKind == AArch64MCExpr::VK_TPREL_LO12_NC)
- return ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC;
+ return R_CLS(TLSLE_ADD_TPREL_LO12_NC);
if (RefKind == AArch64MCExpr::VK_TPREL_LO12)
- return ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12;
+ return R_CLS(TLSLE_ADD_TPREL_LO12);
if (RefKind == AArch64MCExpr::VK_TLSDESC_LO12)
- return ELF::R_AARCH64_TLSDESC_ADD_LO12_NC;
+ return R_CLS(TLSDESC_ADD_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_ABS && IsNC)
- return ELF::R_AARCH64_ADD_ABS_LO12_NC;
+ return R_CLS(ADD_ABS_LO12_NC);
Ctx.reportError(Fixup.getLoc(),
"invalid fixup for add (uimm12) instruction");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_ldst_imm12_scale1:
if (SymLoc == AArch64MCExpr::VK_ABS && IsNC)
- return ELF::R_AARCH64_LDST8_ABS_LO12_NC;
+ return R_CLS(LDST8_ABS_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC)
- return ELF::R_AARCH64_TLSLD_LDST8_DTPREL_LO12;
+ return R_CLS(TLSLD_LDST8_DTPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC)
- return ELF::R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC;
+ return R_CLS(TLSLD_LDST8_DTPREL_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC)
- return ELF::R_AARCH64_TLSLE_LDST8_TPREL_LO12;
+ return R_CLS(TLSLE_LDST8_TPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC)
- return ELF::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC;
+ return R_CLS(TLSLE_LDST8_TPREL_LO12_NC);
Ctx.reportError(Fixup.getLoc(),
"invalid fixup for 8-bit load/store instruction");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_ldst_imm12_scale2:
if (SymLoc == AArch64MCExpr::VK_ABS && IsNC)
- return ELF::R_AARCH64_LDST16_ABS_LO12_NC;
+ return R_CLS(LDST16_ABS_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC)
- return ELF::R_AARCH64_TLSLD_LDST16_DTPREL_LO12;
+ return R_CLS(TLSLD_LDST16_DTPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC)
- return ELF::R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC;
+ return R_CLS(TLSLD_LDST16_DTPREL_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC)
- return ELF::R_AARCH64_TLSLE_LDST16_TPREL_LO12;
+ return R_CLS(TLSLE_LDST16_TPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC)
- return ELF::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC;
+ return R_CLS(TLSLE_LDST16_TPREL_LO12_NC);
Ctx.reportError(Fixup.getLoc(),
"invalid fixup for 16-bit load/store instruction");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_ldst_imm12_scale4:
if (SymLoc == AArch64MCExpr::VK_ABS && IsNC)
- return ELF::R_AARCH64_LDST32_ABS_LO12_NC;
+ return R_CLS(LDST32_ABS_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC)
- return ELF::R_AARCH64_TLSLD_LDST32_DTPREL_LO12;
+ return R_CLS(TLSLD_LDST32_DTPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC)
- return ELF::R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC;
+ return R_CLS(TLSLD_LDST32_DTPREL_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC)
- return ELF::R_AARCH64_TLSLE_LDST32_TPREL_LO12;
+ return R_CLS(TLSLE_LDST32_TPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC)
- return ELF::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC;
+ return R_CLS(TLSLE_LDST32_TPREL_LO12_NC);
Ctx.reportError(Fixup.getLoc(),
"invalid fixup for 32-bit load/store instruction");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_ldst_imm12_scale8:
if (SymLoc == AArch64MCExpr::VK_ABS && IsNC)
- return ELF::R_AARCH64_LDST64_ABS_LO12_NC;
+ return R_CLS(LDST64_ABS_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_GOT && IsNC)
- return ELF::R_AARCH64_LD64_GOT_LO12_NC;
+ return R_CLS(LD64_GOT_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC)
- return ELF::R_AARCH64_TLSLD_LDST64_DTPREL_LO12;
+ return R_CLS(TLSLD_LDST64_DTPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_DTPREL && IsNC)
- return ELF::R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC;
+ return R_CLS(TLSLD_LDST64_DTPREL_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_TPREL && !IsNC)
- return ELF::R_AARCH64_TLSLE_LDST64_TPREL_LO12;
+ return R_CLS(TLSLE_LDST64_TPREL_LO12);
if (SymLoc == AArch64MCExpr::VK_TPREL && IsNC)
- return ELF::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC;
+ return R_CLS(TLSLE_LDST64_TPREL_LO12_NC);
if (SymLoc == AArch64MCExpr::VK_GOTTPREL && IsNC)
- return ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
+ return IsILP32 ? ELF::R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC
+ : ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
if (SymLoc == AArch64MCExpr::VK_TLSDESC && IsNC)
- return ELF::R_AARCH64_TLSDESC_LD64_LO12_NC;
+ return IsILP32 ? ELF::R_AARCH64_P32_TLSDESC_LD32_LO12_NC
+ : ELF::R_AARCH64_TLSDESC_LD64_LO12_NC;
Ctx.reportError(Fixup.getLoc(),
"invalid fixup for 64-bit load/store instruction");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_ldst_imm12_scale16:
if (SymLoc == AArch64MCExpr::VK_ABS && IsNC)
- return ELF::R_AARCH64_LDST128_ABS_LO12_NC;
+ return R_CLS(LDST128_ABS_LO12_NC);
Ctx.reportError(Fixup.getLoc(),
"invalid fixup for 128-bit load/store instruction");
return ELF::R_AARCH64_NONE;
+ // ILP32 case not reached here, tested with isNonILP32reloc
case AArch64::fixup_aarch64_movw:
if (RefKind == AArch64MCExpr::VK_ABS_G3)
return ELF::R_AARCH64_MOVW_UABS_G3;
@@ -218,37 +290,37 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
if (RefKind == AArch64MCExpr::VK_ABS_G2_NC)
return ELF::R_AARCH64_MOVW_UABS_G2_NC;
if (RefKind == AArch64MCExpr::VK_ABS_G1)
- return ELF::R_AARCH64_MOVW_UABS_G1;
+ return R_CLS(MOVW_UABS_G1);
if (RefKind == AArch64MCExpr::VK_ABS_G1_S)
return ELF::R_AARCH64_MOVW_SABS_G1;
if (RefKind == AArch64MCExpr::VK_ABS_G1_NC)
return ELF::R_AARCH64_MOVW_UABS_G1_NC;
if (RefKind == AArch64MCExpr::VK_ABS_G0)
- return ELF::R_AARCH64_MOVW_UABS_G0;
+ return R_CLS(MOVW_UABS_G0);
if (RefKind == AArch64MCExpr::VK_ABS_G0_S)
- return ELF::R_AARCH64_MOVW_SABS_G0;
+ return R_CLS(MOVW_SABS_G0);
if (RefKind == AArch64MCExpr::VK_ABS_G0_NC)
- return ELF::R_AARCH64_MOVW_UABS_G0_NC;
+ return R_CLS(MOVW_UABS_G0_NC);
if (RefKind == AArch64MCExpr::VK_DTPREL_G2)
return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G2;
if (RefKind == AArch64MCExpr::VK_DTPREL_G1)
- return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G1;
+ return R_CLS(TLSLD_MOVW_DTPREL_G1);
if (RefKind == AArch64MCExpr::VK_DTPREL_G1_NC)
return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC;
if (RefKind == AArch64MCExpr::VK_DTPREL_G0)
- return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G0;
+ return R_CLS(TLSLD_MOVW_DTPREL_G0);
if (RefKind == AArch64MCExpr::VK_DTPREL_G0_NC)
- return ELF::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC;
+ return R_CLS(TLSLD_MOVW_DTPREL_G0_NC);
if (RefKind == AArch64MCExpr::VK_TPREL_G2)
return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G2;
if (RefKind == AArch64MCExpr::VK_TPREL_G1)
- return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G1;
+ return R_CLS(TLSLE_MOVW_TPREL_G1);
if (RefKind == AArch64MCExpr::VK_TPREL_G1_NC)
return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC;
if (RefKind == AArch64MCExpr::VK_TPREL_G0)
- return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0;
+ return R_CLS(TLSLE_MOVW_TPREL_G0);
if (RefKind == AArch64MCExpr::VK_TPREL_G0_NC)
- return ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC;
+ return R_CLS(TLSLE_MOVW_TPREL_G0_NC);
if (RefKind == AArch64MCExpr::VK_GOTTPREL_G1)
return ELF::R_AARCH64_TLSIE_MOVW_GOTTPREL_G1;
if (RefKind == AArch64MCExpr::VK_GOTTPREL_G0_NC)
@@ -257,7 +329,7 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
"invalid fixup for movz/movk instruction");
return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_tlsdesc_call:
- return ELF::R_AARCH64_TLSDESC_CALL;
+ return R_CLS(TLSDESC_CALL);
default:
Ctx.reportError(Fixup.getLoc(), "Unknown ELF relocation type");
return ELF::R_AARCH64_NONE;
@@ -269,8 +341,9 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
MCObjectWriter *llvm::createAArch64ELFObjectWriter(raw_pwrite_stream &OS,
uint8_t OSABI,
- bool IsLittleEndian) {
+ bool IsLittleEndian,
+ bool IsILP32) {
MCELFObjectTargetWriter *MOTW =
- new AArch64ELFObjectWriter(OSABI, IsLittleEndian);
+ new AArch64ELFObjectWriter(OSABI, IsLittleEndian, IsILP32);
return createELFObjectWriter(MOTW, OS, IsLittleEndian);
}
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
index fbce26e..8fc8223 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
@@ -29,8 +29,7 @@ static cl::opt<AsmWriterVariantTy> AsmWriterVariant(
"aarch64-neon-syntax", cl::init(Default),
cl::desc("Choose style of NEON code to emit from AArch64 backend:"),
cl::values(clEnumValN(Generic, "generic", "Emit generic NEON assembly"),
- clEnumValN(Apple, "apple", "Emit Apple-style NEON assembly"),
- clEnumValEnd));
+ clEnumValN(Apple, "apple", "Emit Apple-style NEON assembly")));
AArch64MCAsmInfoDarwin::AArch64MCAsmInfoDarwin() {
// We prefer NEON instructions to be printed in the short form.
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index 7b9ff8f..62dfa59 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -15,15 +15,23 @@
#include "MCTargetDesc/AArch64FixupKinds.h"
#include "MCTargetDesc/AArch64MCExpr.h"
#include "Utils/AArch64BaseInfo.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+
using namespace llvm;
#define DEBUG_TYPE "mccodeemitter"
@@ -35,13 +43,14 @@ namespace {
class AArch64MCCodeEmitter : public MCCodeEmitter {
MCContext &Ctx;
+ const MCInstrInfo &MCII;
- AArch64MCCodeEmitter(const AArch64MCCodeEmitter &); // DO NOT IMPLEMENT
- void operator=(const AArch64MCCodeEmitter &); // DO NOT IMPLEMENT
public:
- AArch64MCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) : Ctx(ctx) {}
-
- ~AArch64MCCodeEmitter() override {}
+ AArch64MCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
+ : Ctx(ctx), MCII(mcii) {}
+ AArch64MCCodeEmitter(const AArch64MCCodeEmitter &) = delete;
+ void operator=(const AArch64MCCodeEmitter &) = delete;
+ ~AArch64MCCodeEmitter() override = default;
// getBinaryCodeForInstr - TableGen'erated function for getting the
// binary encoding for an instruction.
@@ -170,16 +179,15 @@ public:
unsigned fixOneOperandFPComparison(const MCInst &MI, unsigned EncodedValue,
const MCSubtargetInfo &STI) const;
+
+private:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
};
} // end anonymous namespace
-MCCodeEmitter *llvm::createAArch64MCCodeEmitter(const MCInstrInfo &MCII,
- const MCRegisterInfo &MRI,
- MCContext &Ctx) {
- return new AArch64MCCodeEmitter(MCII, Ctx);
-}
-
/// getMachineOpValue - Return binary encoding of operand. If the machine
/// operand requires relocation, record the relocation and return zero.
unsigned
@@ -253,7 +261,7 @@ AArch64MCCodeEmitter::getAddSubImmOpValue(const MCInst &MI, unsigned OpIdx,
assert((ShiftVal == 0 || ShiftVal == 12) &&
"unexpected shift value for add/sub immediate");
if (MO.isImm())
- return MO.getImm() | (ShiftVal == 0 ? 0 : (1 << 12));
+ return MO.getImm() | (ShiftVal == 0 ? 0 : (1 << ShiftVal));
assert(MO.isExpr() && "Unable to encode MCOperand!");
const MCExpr *Expr = MO.getExpr();
@@ -263,7 +271,15 @@ AArch64MCCodeEmitter::getAddSubImmOpValue(const MCInst &MI, unsigned OpIdx,
++MCNumFixups;
- return 0;
+ // Set the shift bit of the add instruction for relocation types
+ // R_AARCH64_TLSLE_ADD_TPREL_HI12 and R_AARCH64_TLSLD_ADD_DTPREL_HI12.
+ if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Expr)) {
+ AArch64MCExpr::VariantKind RefKind = A64E->getKind();
+ if (RefKind == AArch64MCExpr::VK_TPREL_HI12 ||
+ RefKind == AArch64MCExpr::VK_DTPREL_HI12)
+ ShiftVal = 12;
+ }
+ return ShiftVal == 0 ? 0 : (1 << ShiftVal);
}
/// getCondBranchTargetOpValue - Return the encoded value for a conditional
@@ -539,6 +555,9 @@ unsigned AArch64MCCodeEmitter::fixMOVZ(const MCInst &MI, unsigned EncodedValue,
void AArch64MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
if (MI.getOpcode() == AArch64::TLSDESCCALL) {
// This is a directive which applies an R_AARCH64_TLSDESC_CALL to the
// following (BLR) instruction. It doesn't emit any code itself so it
@@ -581,4 +600,11 @@ unsigned AArch64MCCodeEmitter::fixOneOperandFPComparison(
return EncodedValue;
}
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "AArch64GenMCCodeEmitter.inc"
+
+MCCodeEmitter *llvm::createAArch64MCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx) {
+ return new AArch64MCCodeEmitter(MCII, Ctx);
+}
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
index 7027806..e9d38d3 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
@@ -15,6 +15,7 @@
#include "AArch64ELFStreamer.h"
#include "AArch64MCAsmInfo.h"
#include "InstPrinter/AArch64InstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
@@ -116,10 +117,14 @@ static MCStreamer *createMachOStreamer(MCContext &Ctx, MCAsmBackend &TAB,
/*LabelSections*/ true);
}
+static MCInstrAnalysis *createAArch64InstrAnalysis(const MCInstrInfo *Info) {
+ return new MCInstrAnalysis(Info);
+}
+
// Force static initialization.
extern "C" void LLVMInitializeAArch64TargetMC() {
- for (Target *T :
- {&TheAArch64leTarget, &TheAArch64beTarget, &TheARM64Target}) {
+ for (Target *T : {&getTheAArch64leTarget(), &getTheAArch64beTarget(),
+ &getTheARM64Target()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createAArch64MCAsmInfo);
@@ -135,6 +140,9 @@ extern "C" void LLVMInitializeAArch64TargetMC() {
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(*T, createAArch64MCSubtargetInfo);
+ // Register the MC instruction analyzer.
+ TargetRegistry::RegisterMCInstrAnalysis(*T, createAArch64InstrAnalysis);
+
// Register the MC Code Emitter
TargetRegistry::RegisterMCCodeEmitter(*T, createAArch64MCCodeEmitter);
@@ -154,8 +162,8 @@ extern "C" void LLVMInitializeAArch64TargetMC() {
}
// Register the asm backend.
- for (Target *T : {&TheAArch64leTarget, &TheARM64Target})
+ for (Target *T : {&getTheAArch64leTarget(), &getTheARM64Target()})
TargetRegistry::RegisterMCAsmBackend(*T, createAArch64leAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(TheAArch64beTarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheAArch64beTarget(),
createAArch64beAsmBackend);
}
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
index 39414cc0..615d7da 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
@@ -27,6 +27,7 @@ class MCRegisterInfo;
class MCObjectWriter;
class MCStreamer;
class MCSubtargetInfo;
+class MCTargetOptions;
class MCTargetStreamer;
class StringRef;
class Target;
@@ -34,23 +35,26 @@ class Triple;
class raw_ostream;
class raw_pwrite_stream;
-extern Target TheAArch64leTarget;
-extern Target TheAArch64beTarget;
-extern Target TheARM64Target;
+Target &getTheAArch64leTarget();
+Target &getTheAArch64beTarget();
+Target &getTheARM64Target();
MCCodeEmitter *createAArch64MCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx);
MCAsmBackend *createAArch64leAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createAArch64beAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createAArch64ELFObjectWriter(raw_pwrite_stream &OS,
uint8_t OSABI,
- bool IsLittleEndian);
+ bool IsLittleEndian,
+ bool IsILP32);
MCObjectWriter *createAArch64MachObjectWriter(raw_pwrite_stream &OS,
uint32_t CPUType,
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp
index 61c96f1..53a6852 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp
@@ -75,7 +75,7 @@ bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo(
Log2Size = llvm::Log2_32(4);
switch (Sym->getKind()) {
default:
- llvm_unreachable("Unexpected symbol reference variant kind!");
+ return false;
case MCSymbolRefExpr::VK_PAGEOFF:
RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
return true;
diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
index 3e86a42..1b949b5 100644
--- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
+++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
@@ -13,6 +13,7 @@
#include "AArch64TargetStreamer.h"
#include "llvm/MC/ConstantPools.h"
+
using namespace llvm;
//
@@ -21,7 +22,7 @@ using namespace llvm;
AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)
: MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {}
-AArch64TargetStreamer::~AArch64TargetStreamer() {}
+AArch64TargetStreamer::~AArch64TargetStreamer() = default;
// The constant pool handling is shared by all AArch64TargetStreamer
// implementations.
diff --git a/contrib/llvm/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp b/contrib/llvm/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp
index f42ecb1..7ac9a5a 100644
--- a/contrib/llvm/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp
+++ b/contrib/llvm/lib/Target/AArch64/TargetInfo/AArch64TargetInfo.cpp
@@ -10,23 +10,30 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-
namespace llvm {
-Target TheAArch64leTarget;
-Target TheAArch64beTarget;
-Target TheARM64Target;
-} // end namespace llvm
+Target &getTheAArch64leTarget() {
+ static Target TheAArch64leTarget;
+ return TheAArch64leTarget;
+}
+Target &getTheAArch64beTarget() {
+ static Target TheAArch64beTarget;
+ return TheAArch64beTarget;
+}
+Target &getTheARM64Target() {
+ static Target TheARM64Target;
+ return TheARM64Target;
+}
+} // namespace llvm
extern "C" void LLVMInitializeAArch64TargetInfo() {
// Now register the "arm64" name for use with "-march". We don't want it to
// take possession of the Triple::aarch64 tag though.
- TargetRegistry::RegisterTarget(TheARM64Target, "arm64",
+ TargetRegistry::RegisterTarget(getTheARM64Target(), "arm64",
"ARM64 (little endian)",
[](Triple::ArchType) { return false; }, true);
RegisterTarget<Triple::aarch64, /*HasJIT=*/true> Z(
- TheAArch64leTarget, "aarch64", "AArch64 (little endian)");
+ getTheAArch64leTarget(), "aarch64", "AArch64 (little endian)");
RegisterTarget<Triple::aarch64_be, /*HasJIT=*/true> W(
- TheAArch64beTarget, "aarch64_be", "AArch64 (big endian)");
-
+ getTheAArch64beTarget(), "aarch64_be", "AArch64 (big endian)");
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPU.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPU.h
index d4784b5..7b0a7f4 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPU.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPU.h
@@ -11,22 +11,18 @@
#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPU_H
#define LLVM_LIB_TARGET_AMDGPU_AMDGPU_H
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
-class AMDGPUInstrPrinter;
-class AMDGPUSubtarget;
class AMDGPUTargetMachine;
class FunctionPass;
class GCNTargetMachine;
-struct MachineSchedContext;
-class MCAsmInfo;
-class raw_ostream;
-class ScheduleDAGInstrs;
+class ModulePass;
+class Pass;
class Target;
class TargetMachine;
+class PassRegistry;
// R600 Passes
FunctionPass *createR600VectorRegMerger(TargetMachine &tm);
@@ -45,16 +41,12 @@ FunctionPass *createSILowerI1CopiesPass();
FunctionPass *createSIShrinkInstructionsPass();
FunctionPass *createSILoadStoreOptimizerPass(TargetMachine &tm);
FunctionPass *createSIWholeQuadModePass();
-FunctionPass *createSILowerControlFlowPass();
FunctionPass *createSIFixControlFlowLiveIntervalsPass();
FunctionPass *createSIFixSGPRCopiesPass();
-FunctionPass *createSICodeEmitterPass(formatted_raw_ostream &OS);
FunctionPass *createSIDebuggerInsertNopsPass();
FunctionPass *createSIInsertWaitsPass();
FunctionPass *createAMDGPUCodeGenPreparePass(const GCNTargetMachine *TM = nullptr);
-ScheduleDAGInstrs *createSIMachineScheduler(MachineSchedContext *C);
-
ModulePass *createAMDGPUAnnotateKernelFeaturesPass();
void initializeAMDGPUAnnotateKernelFeaturesPass(PassRegistry &);
extern char &AMDGPUAnnotateKernelFeaturesID;
@@ -78,21 +70,30 @@ void initializeSIWholeQuadModePass(PassRegistry &);
extern char &SIWholeQuadModeID;
void initializeSILowerControlFlowPass(PassRegistry &);
-extern char &SILowerControlFlowPassID;
+extern char &SILowerControlFlowID;
+
+void initializeSIInsertSkipsPass(PassRegistry &);
+extern char &SIInsertSkipsPassID;
+void initializeSIOptimizeExecMaskingPass(PassRegistry &);
+extern char &SIOptimizeExecMaskingID;
// Passes common to R600 and SI
FunctionPass *createAMDGPUPromoteAlloca(const TargetMachine *TM = nullptr);
void initializeAMDGPUPromoteAllocaPass(PassRegistry&);
extern char &AMDGPUPromoteAllocaID;
-FunctionPass *createAMDGPUAddDivergenceMetadata(const AMDGPUSubtarget &ST);
Pass *createAMDGPUStructurizeCFGPass();
-FunctionPass *createAMDGPUISelDag(TargetMachine &tm);
+FunctionPass *createAMDGPUISelDag(TargetMachine &TM,
+ CodeGenOpt::Level OptLevel);
ModulePass *createAMDGPUAlwaysInlinePass();
ModulePass *createAMDGPUOpenCLImageTypeLoweringPass();
FunctionPass *createAMDGPUAnnotateUniformValues();
+FunctionPass* createAMDGPUUnifyMetadataPass();
+void initializeAMDGPUUnifyMetadataPass(PassRegistry&);
+extern char &AMDGPUUnifyMetadataID;
+
void initializeSIFixControlFlowLiveIntervalsPass(PassRegistry&);
extern char &SIFixControlFlowLiveIntervalsID;
@@ -111,8 +112,8 @@ extern char &SIDebuggerInsertNopsID;
void initializeSIInsertWaitsPass(PassRegistry&);
extern char &SIInsertWaitsID;
-extern Target TheAMDGPUTarget;
-extern Target TheGCNTarget;
+Target &getTheAMDGPUTarget();
+Target &getTheGCNTarget();
namespace AMDGPU {
enum TargetIndex {
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td b/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td
index 72c4553..1302200 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -67,6 +67,19 @@ def FeatureUnalignedBufferAccess : SubtargetFeature<"unaligned-buffer-access",
"Support unaligned global loads and stores"
>;
+def FeatureUnalignedScratchAccess : SubtargetFeature<"unaligned-scratch-access",
+ "UnalignedScratchAccess",
+ "true",
+ "Support unaligned scratch loads and stores"
+>;
+
+// XNACK is disabled if SH_MEM_CONFIG.ADDRESS_MODE = GPUVM on chips that support
+// XNACK. The current default kernel driver setting is:
+// - graphics ring: XNACK disabled
+// - compute ring: XNACK enabled
+//
+// If XNACK is enabled, the VMEM latency can be worse.
+// If XNACK is disabled, the 2 SGPRs can be used for general purposes.
def FeatureXNACK : SubtargetFeature<"xnack",
"EnableXNACK",
"true",
@@ -110,20 +123,6 @@ class SubtargetFeatureLDSBankCount <int Value> : SubtargetFeature <
def FeatureLDSBankCount16 : SubtargetFeatureLDSBankCount<16>;
def FeatureLDSBankCount32 : SubtargetFeatureLDSBankCount<32>;
-class SubtargetFeatureISAVersion <int Major, int Minor, int Stepping>
- : SubtargetFeature <
- "isaver"#Major#"."#Minor#"."#Stepping,
- "IsaVersion",
- "ISAVersion"#Major#"_"#Minor#"_"#Stepping,
- "Instruction set version number"
->;
-
-def FeatureISAVersion7_0_0 : SubtargetFeatureISAVersion <7,0,0>;
-def FeatureISAVersion7_0_1 : SubtargetFeatureISAVersion <7,0,1>;
-def FeatureISAVersion8_0_0 : SubtargetFeatureISAVersion <8,0,0>;
-def FeatureISAVersion8_0_1 : SubtargetFeatureISAVersion <8,0,1>;
-def FeatureISAVersion8_0_3 : SubtargetFeatureISAVersion <8,0,3>;
-
class SubtargetFeatureLocalMemorySize <int Value> : SubtargetFeature<
"localmemorysize"#Value,
"LocalMemorySize",
@@ -161,16 +160,46 @@ def FeatureSMemRealTime : SubtargetFeature<"s-memrealtime",
"Has s_memrealtime instruction"
>;
+def FeatureInv2PiInlineImm : SubtargetFeature<"inv-2pi-inline-imm",
+ "HasInv2PiInlineImm",
+ "true",
+ "Has 1 / (2 * pi) as inline immediate"
+>;
+
def Feature16BitInsts : SubtargetFeature<"16-bit-insts",
"Has16BitInsts",
"true",
"Has i16/f16 instructions"
>;
+def FeatureMovrel : SubtargetFeature<"movrel",
+ "HasMovrel",
+ "true",
+ "Has v_movrel*_b32 instructions"
+>;
+
+def FeatureVGPRIndexMode : SubtargetFeature<"vgpr-index-mode",
+ "HasVGPRIndexMode",
+ "true",
+ "Has VGPR mode register indexing"
+>;
+
+def FeatureScalarStores : SubtargetFeature<"scalar-stores",
+ "HasScalarStores",
+ "true",
+ "Has store scalar memory instructions"
+>;
+
//===------------------------------------------------------------===//
// Subtarget Features (options and debugging)
//===------------------------------------------------------------===//
+def FeatureFP16Denormals : SubtargetFeature<"fp16-denormals",
+ "FP16Denormals",
+ "true",
+ "Enable half precision denormal handling"
+>;
+
// Some instructions do not support denormals despite this flag. Using
// fp32 denormals also causes instructions to run at the double
// precision rate for the device.
@@ -253,6 +282,12 @@ def FeatureEnableSIScheduler : SubtargetFeature<"si-scheduler",
"Enable SI Machine Scheduler"
>;
+// Unless +-flat-for-global is specified, turn on FlatForGlobal for
+// all OS-es on VI and newer hardware to avoid assertion failures due
+// to missing ADDR64 variants of MUBUF instructions.
+// FIXME: moveToVALU should be able to handle converting addr64 MUBUF
+// instructions.
+
def FeatureFlatForGlobal : SubtargetFeature<"flat-for-global",
"FlatForGlobal",
"true",
@@ -294,23 +329,76 @@ def FeatureNorthernIslands : SubtargetFeatureGeneration<"NORTHERN_ISLANDS",
def FeatureSouthernIslands : SubtargetFeatureGeneration<"SOUTHERN_ISLANDS",
[FeatureFP64, FeatureLocalMemorySize32768,
FeatureWavefrontSize64, FeatureGCN, FeatureGCN1Encoding,
- FeatureLDSBankCount32]
+ FeatureLDSBankCount32, FeatureMovrel]
>;
def FeatureSeaIslands : SubtargetFeatureGeneration<"SEA_ISLANDS",
[FeatureFP64, FeatureLocalMemorySize65536,
FeatureWavefrontSize64, FeatureGCN, FeatureFlatAddressSpace,
- FeatureGCN1Encoding, FeatureCIInsts]
+ FeatureGCN1Encoding, FeatureCIInsts, FeatureMovrel]
>;
def FeatureVolcanicIslands : SubtargetFeatureGeneration<"VOLCANIC_ISLANDS",
[FeatureFP64, FeatureLocalMemorySize65536,
FeatureWavefrontSize64, FeatureFlatAddressSpace, FeatureGCN,
FeatureGCN3Encoding, FeatureCIInsts, Feature16BitInsts,
- FeatureSMemRealTime
+ FeatureSMemRealTime, FeatureVGPRIndexMode, FeatureMovrel,
+ FeatureScalarStores, FeatureInv2PiInlineImm
]
>;
+class SubtargetFeatureISAVersion <int Major, int Minor, int Stepping,
+ list<SubtargetFeature> Implies>
+ : SubtargetFeature <
+ "isaver"#Major#"."#Minor#"."#Stepping,
+ "IsaVersion",
+ "ISAVersion"#Major#"_"#Minor#"_"#Stepping,
+ "Instruction set version number",
+ Implies
+>;
+
+def FeatureISAVersion7_0_0 : SubtargetFeatureISAVersion <7,0,0,
+ [FeatureSeaIslands,
+ FeatureLDSBankCount32]>;
+
+def FeatureISAVersion7_0_1 : SubtargetFeatureISAVersion <7,0,1,
+ [FeatureSeaIslands,
+ HalfRate64Ops,
+ FeatureLDSBankCount32,
+ FeatureFastFMAF32]>;
+
+def FeatureISAVersion7_0_2 : SubtargetFeatureISAVersion <7,0,2,
+ [FeatureSeaIslands,
+ FeatureLDSBankCount16]>;
+
+def FeatureISAVersion8_0_0 : SubtargetFeatureISAVersion <8,0,0,
+ [FeatureVolcanicIslands,
+ FeatureLDSBankCount32,
+ FeatureSGPRInitBug]>;
+
+def FeatureISAVersion8_0_1 : SubtargetFeatureISAVersion <8,0,1,
+ [FeatureVolcanicIslands,
+ FeatureLDSBankCount32,
+ FeatureXNACK]>;
+
+def FeatureISAVersion8_0_2 : SubtargetFeatureISAVersion <8,0,2,
+ [FeatureVolcanicIslands,
+ FeatureLDSBankCount32,
+ FeatureSGPRInitBug]>;
+
+def FeatureISAVersion8_0_3 : SubtargetFeatureISAVersion <8,0,3,
+ [FeatureVolcanicIslands,
+ FeatureLDSBankCount32]>;
+
+def FeatureISAVersion8_0_4 : SubtargetFeatureISAVersion <8,0,4,
+ [FeatureVolcanicIslands,
+ FeatureLDSBankCount32]>;
+
+def FeatureISAVersion8_1_0 : SubtargetFeatureISAVersion <8,1,0,
+ [FeatureVolcanicIslands,
+ FeatureLDSBankCount16,
+ FeatureXNACK]>;
+
//===----------------------------------------------------------------------===//
// Debugger related subtarget features.
//===----------------------------------------------------------------------===//
@@ -349,10 +437,52 @@ def AMDGPUAsmParser : AsmParser {
let ShouldEmitMatchRegisterName = 0;
}
+def AMDGPUAsmWriter : AsmWriter {
+ int PassSubtarget = 1;
+}
+
+def AMDGPUAsmVariants {
+ string Default = "Default";
+ int Default_ID = 0;
+ string VOP3 = "VOP3";
+ int VOP3_ID = 1;
+ string SDWA = "SDWA";
+ int SDWA_ID = 2;
+ string DPP = "DPP";
+ int DPP_ID = 3;
+ string Disable = "Disable";
+ int Disable_ID = 4;
+}
+
+def DefaultAMDGPUAsmParserVariant : AsmParserVariant {
+ let Variant = AMDGPUAsmVariants.Default_ID;
+ let Name = AMDGPUAsmVariants.Default;
+}
+
+def VOP3AsmParserVariant : AsmParserVariant {
+ let Variant = AMDGPUAsmVariants.VOP3_ID;
+ let Name = AMDGPUAsmVariants.VOP3;
+}
+
+def SDWAAsmParserVariant : AsmParserVariant {
+ let Variant = AMDGPUAsmVariants.SDWA_ID;
+ let Name = AMDGPUAsmVariants.SDWA;
+}
+
+def DPPAsmParserVariant : AsmParserVariant {
+ let Variant = AMDGPUAsmVariants.DPP_ID;
+ let Name = AMDGPUAsmVariants.DPP;
+}
+
def AMDGPU : Target {
// Pull in Instruction Info:
let InstructionSet = AMDGPUInstrInfo;
let AssemblyParsers = [AMDGPUAsmParser];
+ let AssemblyParserVariants = [DefaultAMDGPUAsmParserVariant,
+ VOP3AsmParserVariant,
+ SDWAAsmParserVariant,
+ DPPAsmParserVariant];
+ let AssemblyWriters = [AMDGPUAsmWriter];
}
// Dummy Instruction itineraries for pseudo instructions
@@ -381,6 +511,8 @@ def isCIVI : Predicate <
def HasFlatAddressSpace : Predicate<"Subtarget->hasFlatAddressSpace()">;
+def Has16BitInsts : Predicate<"Subtarget->has16BitInsts()">;
+
class PredicateControl {
Predicate SubtargetPredicate;
Predicate SIAssemblerPredicate = isSICI;
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp
index 63f5fb3..067a16a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAlwaysInlinePass.cpp
@@ -27,7 +27,7 @@ class AMDGPUAlwaysInline : public ModulePass {
public:
AMDGPUAlwaysInline() : ModulePass(ID) { }
bool runOnModule(Module &M) override;
- const char *getPassName() const override { return "AMDGPU Always Inline Pass"; }
+ StringRef getPassName() const override { return "AMDGPU Always Inline Pass"; }
};
} // End anonymous namespace
@@ -35,8 +35,20 @@ public:
char AMDGPUAlwaysInline::ID = 0;
bool AMDGPUAlwaysInline::runOnModule(Module &M) {
+ std::vector<GlobalAlias*> AliasesToRemove;
std::vector<Function *> FuncsToClone;
+ for (GlobalAlias &A : M.aliases()) {
+ if (Function* F = dyn_cast<Function>(A.getAliasee())) {
+ A.replaceAllUsesWith(F);
+ AliasesToRemove.push_back(&A);
+ }
+ }
+
+ for (GlobalAlias* A : AliasesToRemove) {
+ A->eraseFromParent();
+ }
+
for (Function &F : M) {
if (!F.hasLocalLinkage() && !F.isDeclaration() && !F.use_empty() &&
!F.hasFnAttribute(Attribute::NoInline))
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp
index 0910b28..c98d25e2 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "AMDGPU.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
@@ -35,7 +36,7 @@ public:
AMDGPUAnnotateKernelFeatures() : ModulePass(ID) { }
bool runOnModule(Module &M) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AMDGPU Annotate Kernel Features";
}
@@ -188,7 +189,8 @@ bool AMDGPUAnnotateKernelFeatures::runOnModule(Module &M) {
static const StringRef HSAIntrinsicToAttr[][2] = {
{ "llvm.amdgcn.dispatch.ptr", "amdgpu-dispatch-ptr" },
- { "llvm.amdgcn.queue.ptr", "amdgpu-queue-ptr" }
+ { "llvm.amdgcn.queue.ptr", "amdgpu-queue-ptr" },
+ { "llvm.amdgcn.dispatch.id", "amdgpu-dispatch-id" }
};
// TODO: We should not add the attributes if the known compile time workgroup
@@ -200,7 +202,7 @@ bool AMDGPUAnnotateKernelFeatures::runOnModule(Module &M) {
// always initialized.
bool Changed = addAttrsForIntrinsics(M, IntrinsicToAttr);
- if (TT.getOS() == Triple::AMDHSA) {
+ if (TT.getOS() == Triple::AMDHSA || TT.getOS() == Triple::Mesa3D) {
Changed |= addAttrsForIntrinsics(M, HSAIntrinsicToAttr);
for (Function &F : M) {
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
index 2010cc9..c011be6 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAnnotateUniformValues.cpp
@@ -15,7 +15,10 @@
#include "AMDGPU.h"
#include "AMDGPUIntrinsicInfo.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Analysis/DivergenceAnalysis.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/Debug.h"
@@ -30,6 +33,10 @@ namespace {
class AMDGPUAnnotateUniformValues : public FunctionPass,
public InstVisitor<AMDGPUAnnotateUniformValues> {
DivergenceAnalysis *DA;
+ MemoryDependenceResults *MDR;
+ LoopInfo *LI;
+ DenseMap<Value*, GetElementPtrInst*> noClobberClones;
+ bool isKernelFunc;
public:
static char ID;
@@ -37,15 +44,19 @@ public:
FunctionPass(ID) { }
bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
- const char *getPassName() const override { return "AMDGPU Annotate Uniform Values"; }
+ StringRef getPassName() const override {
+ return "AMDGPU Annotate Uniform Values";
+ }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DivergenceAnalysis>();
+ AU.addRequired<MemoryDependenceWrapperPass>();
+ AU.addRequired<LoopInfoWrapperPass>();
AU.setPreservesAll();
}
void visitBranchInst(BranchInst &I);
void visitLoadInst(LoadInst &I);
-
+ bool isClobberedInFunction(LoadInst * Load);
};
} // End anonymous namespace
@@ -53,6 +64,8 @@ public:
INITIALIZE_PASS_BEGIN(AMDGPUAnnotateUniformValues, DEBUG_TYPE,
"Add AMDGPU uniform metadata", false, false)
INITIALIZE_PASS_DEPENDENCY(DivergenceAnalysis)
+INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_END(AMDGPUAnnotateUniformValues, DEBUG_TYPE,
"Add AMDGPU uniform metadata", false, false)
@@ -61,6 +74,46 @@ char AMDGPUAnnotateUniformValues::ID = 0;
static void setUniformMetadata(Instruction *I) {
I->setMetadata("amdgpu.uniform", MDNode::get(I->getContext(), {}));
}
+static void setNoClobberMetadata(Instruction *I) {
+ I->setMetadata("amdgpu.noclobber", MDNode::get(I->getContext(), {}));
+}
+
+static void DFS(BasicBlock *Root, SetVector<BasicBlock*> & Set) {
+ for (auto I : predecessors(Root))
+ if (Set.insert(I))
+ DFS(I, Set);
+}
+
+bool AMDGPUAnnotateUniformValues::isClobberedInFunction(LoadInst * Load) {
+ // 1. get Loop for the Load->getparent();
+ // 2. if it exists, collect all the BBs from the most outer
+ // loop and check for the writes. If NOT - start DFS over all preds.
+ // 3. Start DFS over all preds from the most outer loop header.
+ SetVector<BasicBlock *> Checklist;
+ BasicBlock *Start = Load->getParent();
+ Checklist.insert(Start);
+ const Value *Ptr = Load->getPointerOperand();
+ const Loop *L = LI->getLoopFor(Start);
+ if (L) {
+ const Loop *P = L;
+ do {
+ L = P;
+ P = P->getParentLoop();
+ } while (P);
+ Checklist.insert(L->block_begin(), L->block_end());
+ Start = L->getHeader();
+ }
+
+ DFS(Start, Checklist);
+ for (auto &BB : Checklist) {
+ BasicBlock::iterator StartIt = (BB == Load->getParent()) ?
+ BasicBlock::iterator(Load) : BB->end();
+ if (MDR->getPointerDependencyFrom(MemoryLocation(Ptr),
+ true, StartIt, BB, Load).isClobber())
+ return true;
+ }
+ return false;
+}
void AMDGPUAnnotateUniformValues::visitBranchInst(BranchInst &I) {
if (I.isUnconditional())
@@ -77,10 +130,39 @@ void AMDGPUAnnotateUniformValues::visitLoadInst(LoadInst &I) {
Value *Ptr = I.getPointerOperand();
if (!DA->isUniform(Ptr))
return;
-
- if (Instruction *PtrI = dyn_cast<Instruction>(Ptr))
+ auto isGlobalLoad = [](LoadInst &Load)->bool {
+ return Load.getPointerAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS;
+ };
+ // We're tracking up to the Function boundaries
+ // We cannot go beyond because of FunctionPass restrictions
+ // Thus we can ensure that memory not clobbered for memory
+ // operations that live in kernel only.
+ bool NotClobbered = isKernelFunc && !isClobberedInFunction(&I);
+ Instruction *PtrI = dyn_cast<Instruction>(Ptr);
+ if (!PtrI && NotClobbered && isGlobalLoad(I)) {
+ if (isa<Argument>(Ptr) || isa<GlobalValue>(Ptr)) {
+ // Lookup for the existing GEP
+ if (noClobberClones.count(Ptr)) {
+ PtrI = noClobberClones[Ptr];
+ } else {
+ // Create GEP of the Value
+ Function *F = I.getParent()->getParent();
+ Value *Idx = Constant::getIntegerValue(
+ Type::getInt32Ty(Ptr->getContext()), APInt(64, 0));
+ // Insert GEP at the entry to make it dominate all uses
+ PtrI = GetElementPtrInst::Create(
+ Ptr->getType()->getPointerElementType(), Ptr,
+ ArrayRef<Value*>(Idx), Twine(""), F->getEntryBlock().getFirstNonPHI());
+ }
+ I.replaceUsesOfWith(Ptr, PtrI);
+ }
+ }
+
+ if (PtrI) {
setUniformMetadata(PtrI);
-
+ if (NotClobbered)
+ setNoClobberMetadata(PtrI);
+ }
}
bool AMDGPUAnnotateUniformValues::doInitialization(Module &M) {
@@ -91,9 +173,13 @@ bool AMDGPUAnnotateUniformValues::runOnFunction(Function &F) {
if (skipFunction(F))
return false;
- DA = &getAnalysis<DivergenceAnalysis>();
- visit(F);
+ DA = &getAnalysis<DivergenceAnalysis>();
+ MDR = &getAnalysis<MemoryDependenceWrapperPass>().getMemDep();
+ LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+ isKernelFunc = F.getCallingConv() == CallingConv::AMDGPU_KERNEL;
+ visit(F);
+ noClobberClones.clear();
return true;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index c9c95c7..974e79f 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -39,9 +39,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
-#include "AMDGPURuntimeMetadata.h"
-using namespace ::AMDGPU;
using namespace llvm;
// TODO: This should get the default rounding mode from the kernel. We just set
@@ -87,13 +85,19 @@ createAMDGPUAsmPrinterPass(TargetMachine &tm,
}
extern "C" void LLVMInitializeAMDGPUAsmPrinter() {
- TargetRegistry::RegisterAsmPrinter(TheAMDGPUTarget, createAMDGPUAsmPrinterPass);
- TargetRegistry::RegisterAsmPrinter(TheGCNTarget, createAMDGPUAsmPrinterPass);
+ TargetRegistry::RegisterAsmPrinter(getTheAMDGPUTarget(),
+ createAMDGPUAsmPrinterPass);
+ TargetRegistry::RegisterAsmPrinter(getTheGCNTarget(),
+ createAMDGPUAsmPrinterPass);
}
AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer)
- : AsmPrinter(TM, std::move(Streamer)) {}
+ : AsmPrinter(TM, std::move(Streamer)) {}
+
+StringRef AMDGPUAsmPrinter::getPassName() const {
+ return "AMDGPU Assembly Printer";
+}
void AMDGPUAsmPrinter::EmitStartOfAsmFile(Module &M) {
if (TM.getTargetTriple().getOS() != Triple::AMDHSA)
@@ -113,13 +117,30 @@ void AMDGPUAsmPrinter::EmitStartOfAsmFile(Module &M) {
AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(STI->getFeatureBits());
TS->EmitDirectiveHSACodeObjectISA(ISA.Major, ISA.Minor, ISA.Stepping,
"AMD", "AMDGPU");
- emitStartOfRuntimeMetadata(M);
+
+ // Emit runtime metadata.
+ TS->EmitRuntimeMetadata(M);
}
+bool AMDGPUAsmPrinter::isBlockOnlyReachableByFallthrough(
+ const MachineBasicBlock *MBB) const {
+ if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB))
+ return false;
+
+ if (MBB->empty())
+ return true;
+
+ // If this is a block implementing a long branch, an expression relative to
+ // the start of the block is needed. to the start of the block.
+ // XXX - Is there a smarter way to check this?
+ return (MBB->back().getOpcode() != AMDGPU::S_SETPC_B64);
+}
+
+
void AMDGPUAsmPrinter::EmitFunctionBodyStart() {
const AMDGPUSubtarget &STM = MF->getSubtarget<AMDGPUSubtarget>();
SIProgramInfo KernelInfo;
- if (STM.isAmdHsaOS()) {
+ if (STM.isAmdCodeObjectV2(*MF)) {
getSIProgramInfo(KernelInfo, *MF);
EmitAmdKernelCodeT(*MF, KernelInfo);
}
@@ -128,11 +149,12 @@ void AMDGPUAsmPrinter::EmitFunctionBodyStart() {
void AMDGPUAsmPrinter::EmitFunctionEntryLabel() {
const SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
const AMDGPUSubtarget &STM = MF->getSubtarget<AMDGPUSubtarget>();
- if (MFI->isKernel() && STM.isAmdHsaOS()) {
+ if (MFI->isKernel() && STM.isAmdCodeObjectV2(*MF)) {
AMDGPUTargetStreamer *TS =
static_cast<AMDGPUTargetStreamer *>(OutStreamer->getTargetStreamer());
- TS->EmitAMDGPUSymbolType(CurrentFnSym->getName(),
- ELF::STT_AMDGPU_HSA_KERNEL);
+ SmallString<128> SymbolName;
+ getNameWithPrefix(SymbolName, MF->getFunction()),
+ TS->EmitAMDGPUSymbolType(SymbolName, ELF::STT_AMDGPU_HSA_KERNEL);
}
AsmPrinter::EmitFunctionEntryLabel();
@@ -154,12 +176,14 @@ bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
SetupMachineFunction(MF);
+ const AMDGPUSubtarget &STM = MF.getSubtarget<AMDGPUSubtarget>();
MCContext &Context = getObjFileLowering().getContext();
- MCSectionELF *ConfigSection =
- Context.getELFSection(".AMDGPU.config", ELF::SHT_PROGBITS, 0);
- OutStreamer->SwitchSection(ConfigSection);
+ if (!STM.isAmdHsaOS()) {
+ MCSectionELF *ConfigSection =
+ Context.getELFSection(".AMDGPU.config", ELF::SHT_PROGBITS, 0);
+ OutStreamer->SwitchSection(ConfigSection);
+ }
- const AMDGPUSubtarget &STM = MF.getSubtarget<AMDGPUSubtarget>();
SIProgramInfo KernelInfo;
if (STM.getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) {
getSIProgramInfo(KernelInfo, MF);
@@ -198,6 +222,16 @@ bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
OutStreamer->emitRawComment(" LDSByteSize: " + Twine(KernelInfo.LDSSize) +
" bytes/workgroup (compile time only)", false);
+ OutStreamer->emitRawComment(" SGPRBlocks: " +
+ Twine(KernelInfo.SGPRBlocks), false);
+ OutStreamer->emitRawComment(" VGPRBlocks: " +
+ Twine(KernelInfo.VGPRBlocks), false);
+
+ OutStreamer->emitRawComment(" NumSGPRsForWavesPerEU: " +
+ Twine(KernelInfo.NumSGPRsForWavesPerEU), false);
+ OutStreamer->emitRawComment(" NumVGPRsForWavesPerEU: " +
+ Twine(KernelInfo.NumVGPRsForWavesPerEU), false);
+
OutStreamer->emitRawComment(" ReservedVGPRFirst: " + Twine(KernelInfo.ReservedVGPRFirst),
false);
OutStreamer->emitRawComment(" ReservedVGPRCount: " + Twine(KernelInfo.ReservedVGPRCount),
@@ -229,7 +263,7 @@ bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
} else {
R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
OutStreamer->emitRawComment(
- Twine("SQ_PGM_RESOURCES:STACK_SIZE = " + Twine(MFI->StackSize)));
+ Twine("SQ_PGM_RESOURCES:STACK_SIZE = " + Twine(MFI->CFStackSize)));
}
}
@@ -247,8 +281,6 @@ bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
}
}
- emitRuntimeMetadata(*MF.getFunction());
-
return false;
}
@@ -282,7 +314,7 @@ void AMDGPUAsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) {
if (STM.getGeneration() >= R600Subtarget::EVERGREEN) {
// Evergreen / Northern Islands
switch (MF.getFunction()->getCallingConv()) {
- default: // Fall through
+ default: LLVM_FALLTHROUGH;
case CallingConv::AMDGPU_CS: RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break;
case CallingConv::AMDGPU_GS: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break;
case CallingConv::AMDGPU_PS: RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break;
@@ -291,9 +323,9 @@ void AMDGPUAsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) {
} else {
// R600 / R700
switch (MF.getFunction()->getCallingConv()) {
- default: // Fall through
- case CallingConv::AMDGPU_GS: // Fall through
- case CallingConv::AMDGPU_CS: // Fall through
+ default: LLVM_FALLTHROUGH;
+ case CallingConv::AMDGPU_GS: LLVM_FALLTHROUGH;
+ case CallingConv::AMDGPU_CS: LLVM_FALLTHROUGH;
case CallingConv::AMDGPU_VS: RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break;
case CallingConv::AMDGPU_PS: RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break;
}
@@ -301,13 +333,13 @@ void AMDGPUAsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) {
OutStreamer->EmitIntValue(RsrcReg, 4);
OutStreamer->EmitIntValue(S_NUM_GPRS(MaxGPR + 1) |
- S_STACK_SIZE(MFI->StackSize), 4);
+ S_STACK_SIZE(MFI->CFStackSize), 4);
OutStreamer->EmitIntValue(R_02880C_DB_SHADER_CONTROL, 4);
OutStreamer->EmitIntValue(S_02880C_KILL_ENABLE(killPixel), 4);
if (AMDGPU::isCompute(MF.getFunction()->getCallingConv())) {
OutStreamer->EmitIntValue(R_0288E8_SQ_LDS_ALLOC, 4);
- OutStreamer->EmitIntValue(alignTo(MFI->LDSSize, 4) >> 2, 4);
+ OutStreamer->EmitIntValue(alignTo(MFI->getLDSSize(), 4) >> 2, 4);
}
}
@@ -331,7 +363,8 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
if (MI.isDebugValue())
continue;
- CodeSize += TII->getInstSizeInBytes(MI);
+ if (isVerbose())
+ CodeSize += TII->getInstSizeInBytes(MI);
unsigned numOperands = MI.getNumOperands();
for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
@@ -360,7 +393,10 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
case AMDGPU::FLAT_SCR:
case AMDGPU::FLAT_SCR_LO:
case AMDGPU::FLAT_SCR_HI:
- FlatUsed = true;
+ // Even if FLAT_SCRATCH is implicitly used, it has no effect if flat
+ // instructions aren't used to access the scratch buffer.
+ if (MFI->hasFlatScratchInit())
+ FlatUsed = true;
continue;
case AMDGPU::TBA:
@@ -369,26 +405,23 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
case AMDGPU::TMA:
case AMDGPU::TMA_LO:
case AMDGPU::TMA_HI:
- llvm_unreachable("Trap Handler registers should not be used");
- continue;
+ llvm_unreachable("trap handler registers should not be used");
default:
break;
}
if (AMDGPU::SReg_32RegClass.contains(reg)) {
- if (AMDGPU::TTMP_32RegClass.contains(reg)) {
- llvm_unreachable("Trap Handler registers should not be used");
- }
+ assert(!AMDGPU::TTMP_32RegClass.contains(reg) &&
+ "trap handler registers should not be used");
isSGPR = true;
width = 1;
} else if (AMDGPU::VGPR_32RegClass.contains(reg)) {
isSGPR = false;
width = 1;
} else if (AMDGPU::SReg_64RegClass.contains(reg)) {
- if (AMDGPU::TTMP_64RegClass.contains(reg)) {
- llvm_unreachable("Trap Handler registers should not be used");
- }
+ assert(!AMDGPU::TTMP_64RegClass.contains(reg) &&
+ "trap handler registers should not be used");
isSGPR = true;
width = 2;
} else if (AMDGPU::VReg_64RegClass.contains(reg)) {
@@ -445,20 +478,15 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
ExtraSGPRs = 6;
}
- MaxSGPR += ExtraSGPRs;
-
// Record first reserved register and reserved register count fields, and
// update max register counts if "amdgpu-debugger-reserve-regs" attribute was
- // specified.
- if (STM.debuggerReserveRegs()) {
- ProgInfo.ReservedVGPRFirst = MaxVGPR + 1;
- ProgInfo.ReservedVGPRCount = MFI->getDebuggerReservedVGPRCount();
- MaxVGPR += MFI->getDebuggerReservedVGPRCount();
- }
+ // requested.
+ ProgInfo.ReservedVGPRFirst = STM.debuggerReserveRegs() ? MaxVGPR + 1 : 0;
+ ProgInfo.ReservedVGPRCount = RI->getNumDebuggerReservedVGPRs(STM);
// Update DebuggerWavefrontPrivateSegmentOffsetSGPR and
// DebuggerPrivateSegmentBufferSGPR fields if "amdgpu-debugger-emit-prologue"
- // attribute was specified.
+ // attribute was requested.
if (STM.debuggerEmitPrologue()) {
ProgInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR =
RI->getHWRegIndex(MFI->getScratchWaveOffsetReg());
@@ -466,21 +494,59 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
RI->getHWRegIndex(MFI->getScratchRSrcReg());
}
+ // Check the addressable register limit before we add ExtraSGPRs.
+ if (STM.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS &&
+ !STM.hasSGPRInitBug()) {
+ unsigned MaxAddressableNumSGPRs = STM.getMaxNumSGPRs();
+ if (MaxSGPR + 1 > MaxAddressableNumSGPRs) {
+ // This can happen due to a compiler bug or when using inline asm.
+ LLVMContext &Ctx = MF.getFunction()->getContext();
+ DiagnosticInfoResourceLimit Diag(*MF.getFunction(),
+ "addressable scalar registers",
+ MaxSGPR + 1, DS_Error,
+ DK_ResourceLimit, MaxAddressableNumSGPRs);
+ Ctx.diagnose(Diag);
+ MaxSGPR = MaxAddressableNumSGPRs - 1;
+ }
+ }
+
+ // Account for extra SGPRs and VGPRs reserved for debugger use.
+ MaxSGPR += ExtraSGPRs;
+ MaxVGPR += RI->getNumDebuggerReservedVGPRs(STM);
+
// We found the maximum register index. They start at 0, so add one to get the
// number of registers.
ProgInfo.NumVGPR = MaxVGPR + 1;
ProgInfo.NumSGPR = MaxSGPR + 1;
- if (STM.hasSGPRInitBug()) {
- if (ProgInfo.NumSGPR > SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG) {
+ // Adjust number of registers used to meet default/requested minimum/maximum
+ // number of waves per execution unit request.
+ ProgInfo.NumSGPRsForWavesPerEU = std::max(
+ ProgInfo.NumSGPR, RI->getMinNumSGPRs(STM, MFI->getMaxWavesPerEU()));
+ ProgInfo.NumVGPRsForWavesPerEU = std::max(
+ ProgInfo.NumVGPR, RI->getMinNumVGPRs(MFI->getMaxWavesPerEU()));
+
+ if (STM.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS ||
+ STM.hasSGPRInitBug()) {
+ unsigned MaxNumSGPRs = STM.getMaxNumSGPRs();
+ if (ProgInfo.NumSGPR > MaxNumSGPRs) {
+ // This can happen due to a compiler bug or when using inline asm to use the
+ // registers which are usually reserved for vcc etc.
+
LLVMContext &Ctx = MF.getFunction()->getContext();
DiagnosticInfoResourceLimit Diag(*MF.getFunction(),
- "SGPRs with SGPR init bug",
- ProgInfo.NumSGPR, DS_Error);
+ "scalar registers",
+ ProgInfo.NumSGPR, DS_Error,
+ DK_ResourceLimit, MaxNumSGPRs);
Ctx.diagnose(Diag);
+ ProgInfo.NumSGPR = MaxNumSGPRs;
+ ProgInfo.NumSGPRsForWavesPerEU = MaxNumSGPRs;
}
+ }
+ if (STM.hasSGPRInitBug()) {
ProgInfo.NumSGPR = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG;
+ ProgInfo.NumSGPRsForWavesPerEU = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG;
}
if (MFI->NumUserSGPRs > STM.getMaxNumUserSGPRs()) {
@@ -490,26 +556,34 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
Ctx.diagnose(Diag);
}
- if (MFI->LDSSize > static_cast<unsigned>(STM.getLocalMemorySize())) {
+ if (MFI->getLDSSize() > static_cast<unsigned>(STM.getLocalMemorySize())) {
LLVMContext &Ctx = MF.getFunction()->getContext();
DiagnosticInfoResourceLimit Diag(*MF.getFunction(), "local memory",
- MFI->LDSSize, DS_Error);
+ MFI->getLDSSize(), DS_Error);
Ctx.diagnose(Diag);
}
- ProgInfo.VGPRBlocks = (ProgInfo.NumVGPR - 1) / 4;
- ProgInfo.SGPRBlocks = (ProgInfo.NumSGPR - 1) / 8;
+ // SGPRBlocks is actual number of SGPR blocks minus 1.
+ ProgInfo.SGPRBlocks = alignTo(ProgInfo.NumSGPRsForWavesPerEU,
+ RI->getSGPRAllocGranule());
+ ProgInfo.SGPRBlocks = ProgInfo.SGPRBlocks / RI->getSGPRAllocGranule() - 1;
+
+ // VGPRBlocks is actual number of VGPR blocks minus 1.
+ ProgInfo.VGPRBlocks = alignTo(ProgInfo.NumVGPRsForWavesPerEU,
+ RI->getVGPRAllocGranule());
+ ProgInfo.VGPRBlocks = ProgInfo.VGPRBlocks / RI->getVGPRAllocGranule() - 1;
+
// Set the value to initialize FP_ROUND and FP_DENORM parts of the mode
// register.
ProgInfo.FloatMode = getFPMode(MF);
- ProgInfo.IEEEMode = 0;
+ ProgInfo.IEEEMode = STM.enableIEEEBit(MF);
// Make clamp modifier on NaN input returns 0.
ProgInfo.DX10Clamp = 1;
- const MachineFrameInfo *FrameInfo = MF.getFrameInfo();
- ProgInfo.ScratchSize = FrameInfo->getStackSize();
+ const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
+ ProgInfo.ScratchSize = FrameInfo.getStackSize();
ProgInfo.FlatUsed = FlatUsed;
ProgInfo.VCCUsed = VCCUsed;
@@ -524,10 +598,10 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
LDSAlignShift = 9;
}
- unsigned LDSSpillSize = MFI->LDSWaveSpillSize *
- MFI->getMaximumWorkGroupSize(MF);
+ unsigned LDSSpillSize =
+ MFI->LDSWaveSpillSize * MFI->getMaxFlatWorkGroupSize();
- ProgInfo.LDSSize = MFI->LDSSize + LDSSpillSize;
+ ProgInfo.LDSSize = MFI->getLDSSize() + LDSSpillSize;
ProgInfo.LDSBlocks =
alignTo(ProgInfo.LDSSize, 1ULL << LDSAlignShift) >> LDSAlignShift;
@@ -573,7 +647,7 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
static unsigned getRsrcReg(CallingConv::ID CallConv) {
switch (CallConv) {
- default: // Fall through
+ default: LLVM_FALLTHROUGH;
case CallingConv::AMDGPU_CS: return R_00B848_COMPUTE_PGM_RSRC1;
case CallingConv::AMDGPU_GS: return R_00B228_SPI_SHADER_PGM_RSRC1_GS;
case CallingConv::AMDGPU_PS: return R_00B028_SPI_SHADER_PGM_RSRC1_PS;
@@ -703,7 +777,9 @@ void AMDGPUAsmPrinter::EmitAmdKernelCodeT(const MachineFunction &MF,
if (STM.isXNACKEnabled())
header.code_properties |= AMD_CODE_PROPERTY_IS_XNACK_SUPPORTED;
- header.kernarg_segment_byte_size = MFI->ABIArgOffset;
+ // FIXME: Should use getKernArgSize
+ header.kernarg_segment_byte_size =
+ STM.getKernArgSegmentSize(MF, MFI->getABIArgOffset());
header.wavefront_sgpr_count = KernelInfo.NumSGPR;
header.workitem_vgpr_count = KernelInfo.NumVGPR;
header.workitem_private_segment_byte_size = KernelInfo.ScratchSize;
@@ -711,6 +787,11 @@ void AMDGPUAsmPrinter::EmitAmdKernelCodeT(const MachineFunction &MF,
header.reserved_vgpr_first = KernelInfo.ReservedVGPRFirst;
header.reserved_vgpr_count = KernelInfo.ReservedVGPRCount;
+ // These alignment values are specified in powers of two, so alignment =
+ // 2^n. The minimum alignment is 2^4 = 16.
+ header.kernarg_segment_alignment = std::max((size_t)4,
+ countTrailingZeros(MFI->getMaxKernArgAlign()));
+
if (STM.debuggerEmitPrologue()) {
header.debug_wavefront_private_segment_offset_sgpr =
KernelInfo.DebuggerWavefrontPrivateSegmentOffsetSGPR;
@@ -745,231 +826,3 @@ bool AMDGPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
*TM.getSubtargetImpl(*MF->getFunction())->getRegisterInfo());
return false;
}
-
-// Emit a key and an integer value for runtime metadata.
-static void emitRuntimeMDIntValue(std::unique_ptr<MCStreamer> &Streamer,
- RuntimeMD::Key K, uint64_t V,
- unsigned Size) {
- Streamer->EmitIntValue(K, 1);
- Streamer->EmitIntValue(V, Size);
-}
-
-// Emit a key and a string value for runtime metadata.
-static void emitRuntimeMDStringValue(std::unique_ptr<MCStreamer> &Streamer,
- RuntimeMD::Key K, StringRef S) {
- Streamer->EmitIntValue(K, 1);
- Streamer->EmitIntValue(S.size(), 4);
- Streamer->EmitBytes(S);
-}
-
-// Emit a key and three integer values for runtime metadata.
-// The three integer values are obtained from MDNode \p Node;
-static void emitRuntimeMDThreeIntValues(std::unique_ptr<MCStreamer> &Streamer,
- RuntimeMD::Key K, MDNode *Node,
- unsigned Size) {
- Streamer->EmitIntValue(K, 1);
- Streamer->EmitIntValue(mdconst::extract<ConstantInt>(
- Node->getOperand(0))->getZExtValue(), Size);
- Streamer->EmitIntValue(mdconst::extract<ConstantInt>(
- Node->getOperand(1))->getZExtValue(), Size);
- Streamer->EmitIntValue(mdconst::extract<ConstantInt>(
- Node->getOperand(2))->getZExtValue(), Size);
-}
-
-void AMDGPUAsmPrinter::emitStartOfRuntimeMetadata(const Module &M) {
- OutStreamer->SwitchSection(getObjFileLowering().getContext()
- .getELFSection(RuntimeMD::SectionName, ELF::SHT_PROGBITS, 0));
-
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyMDVersion,
- RuntimeMD::MDVersion << 8 | RuntimeMD::MDRevision, 2);
- if (auto MD = M.getNamedMetadata("opencl.ocl.version")) {
- if (MD->getNumOperands()) {
- auto Node = MD->getOperand(0);
- if (Node->getNumOperands() > 1) {
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyLanguage,
- RuntimeMD::OpenCL_C, 1);
- uint16_t Major = mdconst::extract<ConstantInt>(Node->getOperand(0))
- ->getZExtValue();
- uint16_t Minor = mdconst::extract<ConstantInt>(Node->getOperand(1))
- ->getZExtValue();
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyLanguageVersion,
- Major * 100 + Minor * 10, 2);
- }
- }
- }
-}
-
-static std::string getOCLTypeName(Type *Ty, bool isSigned) {
- if (VectorType* VecTy = dyn_cast<VectorType>(Ty)) {
- Type* EleTy = VecTy->getElementType();
- unsigned Size = VecTy->getVectorNumElements();
- return (Twine(getOCLTypeName(EleTy, isSigned)) + Twine(Size)).str();
- }
- switch (Ty->getTypeID()) {
- case Type::HalfTyID: return "half";
- case Type::FloatTyID: return "float";
- case Type::DoubleTyID: return "double";
- case Type::IntegerTyID: {
- if (!isSigned)
- return (Twine('u') + Twine(getOCLTypeName(Ty, true))).str();
- auto IntTy = cast<IntegerType>(Ty);
- auto BW = IntTy->getIntegerBitWidth();
- switch (BW) {
- case 8:
- return "char";
- case 16:
- return "short";
- case 32:
- return "int";
- case 64:
- return "long";
- default:
- return (Twine('i') + Twine(BW)).str();
- }
- }
- default:
- llvm_unreachable("invalid type");
- }
-}
-
-static RuntimeMD::KernelArg::ValueType getRuntimeMDValueType(
- Type *Ty, StringRef TypeName) {
- if (auto VT = dyn_cast<VectorType>(Ty))
- return getRuntimeMDValueType(VT->getElementType(), TypeName);
- else if (auto PT = dyn_cast<PointerType>(Ty))
- return getRuntimeMDValueType(PT->getElementType(), TypeName);
- else if (Ty->isHalfTy())
- return RuntimeMD::KernelArg::F16;
- else if (Ty->isFloatTy())
- return RuntimeMD::KernelArg::F32;
- else if (Ty->isDoubleTy())
- return RuntimeMD::KernelArg::F64;
- else if (IntegerType* intTy = dyn_cast<IntegerType>(Ty)) {
- bool Signed = !TypeName.startswith("u");
- switch (intTy->getIntegerBitWidth()) {
- case 8:
- return Signed ? RuntimeMD::KernelArg::I8 : RuntimeMD::KernelArg::U8;
- case 16:
- return Signed ? RuntimeMD::KernelArg::I16 : RuntimeMD::KernelArg::U16;
- case 32:
- return Signed ? RuntimeMD::KernelArg::I32 : RuntimeMD::KernelArg::U32;
- case 64:
- return Signed ? RuntimeMD::KernelArg::I64 : RuntimeMD::KernelArg::U64;
- default:
- // Runtime does not recognize other integer types. Report as
- // struct type.
- return RuntimeMD::KernelArg::Struct;
- }
- } else
- return RuntimeMD::KernelArg::Struct;
-}
-
-void AMDGPUAsmPrinter::emitRuntimeMetadata(const Function &F) {
- if (!F.getMetadata("kernel_arg_type"))
- return;
-
- MCContext &Context = getObjFileLowering().getContext();
- OutStreamer->SwitchSection(
- Context.getELFSection(RuntimeMD::SectionName, ELF::SHT_PROGBITS, 0));
- OutStreamer->EmitIntValue(RuntimeMD::KeyKernelBegin, 1);
- emitRuntimeMDStringValue(OutStreamer, RuntimeMD::KeyKernelName, F.getName());
-
- for (auto &Arg:F.args()) {
- // Emit KeyArgBegin.
- unsigned I = Arg.getArgNo();
- OutStreamer->EmitIntValue(RuntimeMD::KeyArgBegin, 1);
-
- // Emit KeyArgSize and KeyArgAlign.
- auto T = Arg.getType();
- auto DL = F.getParent()->getDataLayout();
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyArgSize,
- DL.getTypeAllocSize(T), 4);
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyArgAlign,
- DL.getABITypeAlignment(T), 4);
-
- // Emit KeyArgTypeName.
- auto TypeName = dyn_cast<MDString>(F.getMetadata(
- "kernel_arg_type")->getOperand(I))->getString();
- emitRuntimeMDStringValue(OutStreamer, RuntimeMD::KeyArgTypeName, TypeName);
-
- // Emit KeyArgName.
- if (auto ArgNameMD = F.getMetadata("kernel_arg_name")) {
- auto ArgName = cast<MDString>(ArgNameMD->getOperand(
- I))->getString();
- emitRuntimeMDStringValue(OutStreamer, RuntimeMD::KeyArgName, ArgName);
- }
-
- // Emit KeyArgIsVolatile, KeyArgIsRestrict, KeyArgIsConst and KeyArgIsPipe.
- auto TypeQual = cast<MDString>(F.getMetadata(
- "kernel_arg_type_qual")->getOperand(I))->getString();
- SmallVector<StringRef, 1> SplitQ;
- TypeQual.split(SplitQ, " ", -1, false/* drop empty entry*/);
- for (auto &I:SplitQ) {
- auto Key = StringSwitch<RuntimeMD::Key>(I)
- .Case("volatile", RuntimeMD::KeyArgIsVolatile)
- .Case("restrict", RuntimeMD::KeyArgIsRestrict)
- .Case("const", RuntimeMD::KeyArgIsConst)
- .Case("pipe", RuntimeMD::KeyArgIsPipe)
- .Default(RuntimeMD::KeyNull);
- OutStreamer->EmitIntValue(Key, 1);
- }
-
- // Emit KeyArgTypeKind.
- auto BaseTypeName = cast<MDString>(
- F.getMetadata("kernel_arg_base_type")->getOperand(I))->getString();
- auto TypeKind = StringSwitch<RuntimeMD::KernelArg::TypeKind>(BaseTypeName)
- .Case("sampler_t", RuntimeMD::KernelArg::Sampler)
- .Case("queue_t", RuntimeMD::KernelArg::Queue)
- .Cases("image1d_t", "image1d_array_t", "image1d_buffer_t",
- "image2d_t" , "image2d_array_t", RuntimeMD::KernelArg::Image)
- .Cases("image2d_depth_t", "image2d_array_depth_t",
- "image2d_msaa_t", "image2d_array_msaa_t",
- "image2d_msaa_depth_t", RuntimeMD::KernelArg::Image)
- .Cases("image2d_array_msaa_depth_t", "image3d_t",
- RuntimeMD::KernelArg::Image)
- .Default(isa<PointerType>(T) ? RuntimeMD::KernelArg::Pointer :
- RuntimeMD::KernelArg::Value);
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyArgTypeKind, TypeKind, 1);
-
- // Emit KeyArgValueType.
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyArgValueType,
- getRuntimeMDValueType(T, BaseTypeName), 2);
-
- // Emit KeyArgAccQual.
- auto AccQual = cast<MDString>(F.getMetadata(
- "kernel_arg_access_qual")->getOperand(I))->getString();
- auto AQ = StringSwitch<RuntimeMD::KernelArg::AccessQualifer>(AccQual)
- .Case("read_only", RuntimeMD::KernelArg::ReadOnly)
- .Case("write_only", RuntimeMD::KernelArg::WriteOnly)
- .Case("read_write", RuntimeMD::KernelArg::ReadWrite)
- .Default(RuntimeMD::KernelArg::None);
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyArgAccQual,
- AQ, 1);
-
- // Emit KeyArgAddrQual.
- if (isa<PointerType>(T))
- emitRuntimeMDIntValue(OutStreamer, RuntimeMD::KeyArgAddrQual,
- T->getPointerAddressSpace(), 1);
-
- // Emit KeyArgEnd
- OutStreamer->EmitIntValue(RuntimeMD::KeyArgEnd, 1);
- }
-
- // Emit KeyReqdWorkGroupSize, KeyWorkGroupSizeHint, and KeyVecTypeHint.
- if (auto RWGS = F.getMetadata("reqd_work_group_size"))
- emitRuntimeMDThreeIntValues(OutStreamer, RuntimeMD::KeyReqdWorkGroupSize,
- RWGS, 4);
- if (auto WGSH = F.getMetadata("work_group_size_hint"))
- emitRuntimeMDThreeIntValues(OutStreamer, RuntimeMD::KeyWorkGroupSizeHint,
- WGSH, 4);
- if (auto VTH = F.getMetadata("vec_type_hint")) {
- auto TypeName = getOCLTypeName(cast<ValueAsMetadata>(
- VTH->getOperand(0))->getType(), mdconst::extract<ConstantInt>(
- VTH->getOperand(1))->getZExtValue());
- emitRuntimeMDStringValue(OutStreamer, RuntimeMD::KeyVecTypeHint,
- TypeName);
- }
-
- // Emit KeyKernelEnd
- OutStreamer->EmitIntValue(RuntimeMD::KeyKernelEnd, 1);
-}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h
index 7b04c53..9a4bafe 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.h
@@ -15,10 +15,13 @@
#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPUASMPRINTER_H
#define LLVM_LIB_TARGET_AMDGPU_AMDGPUASMPRINTER_H
+#include "AMDGPUMCInstLower.h"
+
#include "llvm/CodeGen/AsmPrinter.h"
#include <vector>
namespace llvm {
+class MCOperand;
class AMDGPUAsmPrinter final : public AsmPrinter {
private:
@@ -40,6 +43,8 @@ private:
NumVGPR(0),
NumSGPR(0),
FlatUsed(false),
+ NumSGPRsForWavesPerEU(0),
+ NumVGPRsForWavesPerEU(0),
ReservedVGPRFirst(0),
ReservedVGPRCount(0),
DebuggerWavefrontPrivateSegmentOffsetSGPR((uint16_t)-1),
@@ -71,15 +76,23 @@ private:
uint32_t LDSSize;
bool FlatUsed;
+ // Number of SGPRs that meets number of waves per execution unit request.
+ uint32_t NumSGPRsForWavesPerEU;
+
+ // Number of VGPRs that meets number of waves per execution unit request.
+ uint32_t NumVGPRsForWavesPerEU;
+
// If ReservedVGPRCount is 0 then must be 0. Otherwise, this is the first
// fixed VGPR number reserved.
uint16_t ReservedVGPRFirst;
+
// The number of consecutive VGPRs reserved.
uint16_t ReservedVGPRCount;
// Fixed SGPR number used to hold wave scratch offset for entire kernel
// execution, or uint16_t(-1) if the register is not used or not known.
uint16_t DebuggerWavefrontPrivateSegmentOffsetSGPR;
+
// Fixed SGPR number of the first 4 SGPRs used to hold scratch V# for entire
// kernel execution, or uint16_t(-1) if the register is not used or not
// known.
@@ -108,9 +121,16 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "AMDGPU Assembly Printer";
- }
+ StringRef getPassName() const override;
+
+ /// \brief Wrapper for MCInstLowering.lowerOperand() for the tblgen'erated
+ /// pseudo lowering.
+ bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
+
+ /// \brief tblgen'erated driver function for lowering simple MI->MC pseudo
+ /// instructions.
+ bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
+ const MachineInstr *MI);
/// Implemented in AMDGPUMCInstLower.cpp
void EmitInstruction(const MachineInstr *MI) override;
@@ -123,14 +143,13 @@ public:
void EmitStartOfAsmFile(Module &M) override;
+ bool isBlockOnlyReachableByFallthrough(
+ const MachineBasicBlock *MBB) const override;
+
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O) override;
- void emitStartOfRuntimeMetadata(const Module &M);
-
- void emitRuntimeMetadata(const Function &F);
-
protected:
std::vector<std::string> DisasmLines, HexLines;
size_t DisasmLineMaxLen;
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
index 1a1da8a..d53cc15 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
@@ -1,4 +1,4 @@
-//===-- llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp - Call lowering ---===//
+//===-- llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp - Call lowering -----===//
//
// The LLVM Compiler Infrastructure
//
@@ -34,9 +34,9 @@ bool AMDGPUCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
return true;
}
-bool AMDGPUCallLowering::lowerFormalArguments(
- MachineIRBuilder &MIRBuilder, const Function::ArgumentListType &Args,
- const SmallVectorImpl<unsigned> &VRegs) const {
+bool AMDGPUCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
+ const Function &F,
+ ArrayRef<unsigned> VRegs) const {
// TODO: Implement once there are generic loads/stores.
return true;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.h
index 61174ba..9ae87c9 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.h
@@ -27,10 +27,8 @@ class AMDGPUCallLowering: public CallLowering {
bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val,
unsigned VReg) const override;
- bool
- lowerFormalArguments(MachineIRBuilder &MIRBuilder,
- const Function::ArgumentListType &Args,
- const SmallVectorImpl<unsigned> &VRegs) const override;
+ bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
+ ArrayRef<unsigned> VRegs) const override;
};
} // End of namespace llvm;
#endif
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
index b955e23..e623054 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
@@ -39,6 +39,78 @@ class AMDGPUCodeGenPrepare : public FunctionPass,
Module *Mod;
bool HasUnsafeFPMath;
+ /// \brief Copies exact/nsw/nuw flags (if any) from binary operation \p I to
+ /// binary operation \p V.
+ ///
+ /// \returns Binary operation \p V.
+ Value *copyFlags(const BinaryOperator &I, Value *V) const;
+
+ /// \returns \p T's base element bit width.
+ unsigned getBaseElementBitWidth(const Type *T) const;
+
+ /// \returns Equivalent 32 bit integer type for given type \p T. For example,
+ /// if \p T is i7, then i32 is returned; if \p T is <3 x i12>, then <3 x i32>
+ /// is returned.
+ Type *getI32Ty(IRBuilder<> &B, const Type *T) const;
+
+ /// \returns True if binary operation \p I is a signed binary operation, false
+ /// otherwise.
+ bool isSigned(const BinaryOperator &I) const;
+
+ /// \returns True if the condition of 'select' operation \p I comes from a
+ /// signed 'icmp' operation, false otherwise.
+ bool isSigned(const SelectInst &I) const;
+
+ /// \returns True if type \p T needs to be promoted to 32 bit integer type,
+ /// false otherwise.
+ bool needsPromotionToI32(const Type *T) const;
+
+ /// \brief Promotes uniform binary operation \p I to equivalent 32 bit binary
+ /// operation.
+ ///
+ /// \details \p I's base element bit width must be greater than 1 and less
+ /// than or equal 16. Promotion is done by sign or zero extending operands to
+ /// 32 bits, replacing \p I with equivalent 32 bit binary operation, and
+ /// truncating the result of 32 bit binary operation back to \p I's original
+ /// type. Division operation is not promoted.
+ ///
+ /// \returns True if \p I is promoted to equivalent 32 bit binary operation,
+ /// false otherwise.
+ bool promoteUniformOpToI32(BinaryOperator &I) const;
+
+ /// \brief Promotes uniform 'icmp' operation \p I to 32 bit 'icmp' operation.
+ ///
+ /// \details \p I's base element bit width must be greater than 1 and less
+ /// than or equal 16. Promotion is done by sign or zero extending operands to
+ /// 32 bits, and replacing \p I with 32 bit 'icmp' operation.
+ ///
+ /// \returns True.
+ bool promoteUniformOpToI32(ICmpInst &I) const;
+
+ /// \brief Promotes uniform 'select' operation \p I to 32 bit 'select'
+ /// operation.
+ ///
+ /// \details \p I's base element bit width must be greater than 1 and less
+ /// than or equal 16. Promotion is done by sign or zero extending operands to
+ /// 32 bits, replacing \p I with 32 bit 'select' operation, and truncating the
+ /// result of 32 bit 'select' operation back to \p I's original type.
+ ///
+ /// \returns True.
+ bool promoteUniformOpToI32(SelectInst &I) const;
+
+ /// \brief Promotes uniform 'bitreverse' intrinsic \p I to 32 bit 'bitreverse'
+ /// intrinsic.
+ ///
+ /// \details \p I's base element bit width must be greater than 1 and less
+ /// than or equal 16. Promotion is done by zero extending the operand to 32
+ /// bits, replacing \p I with 32 bit 'bitreverse' intrinsic, shifting the
+ /// result of 32 bit 'bitreverse' intrinsic to the right with zero fill (the
+ /// shift amount is 32 minus \p I's base element bit width), and truncating
+ /// the result of the shift operation back to \p I's original type.
+ ///
+ /// \returns True.
+ bool promoteUniformBitreverseToI32(IntrinsicInst &I) const;
+
public:
static char ID;
AMDGPUCodeGenPrepare(const TargetMachine *TM = nullptr) :
@@ -51,16 +123,18 @@ public:
bool visitFDiv(BinaryOperator &I);
- bool visitInstruction(Instruction &I) {
- return false;
- }
+ bool visitInstruction(Instruction &I) { return false; }
+ bool visitBinaryOperator(BinaryOperator &I);
+ bool visitICmpInst(ICmpInst &I);
+ bool visitSelectInst(SelectInst &I);
+
+ bool visitIntrinsicInst(IntrinsicInst &I);
+ bool visitBitreverseIntrinsicInst(IntrinsicInst &I);
bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
- const char *getPassName() const override {
- return "AMDGPU IR optimizations";
- }
+ StringRef getPassName() const override { return "AMDGPU IR optimizations"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DivergenceAnalysis>();
@@ -70,6 +144,171 @@ public:
} // End anonymous namespace
+Value *AMDGPUCodeGenPrepare::copyFlags(
+ const BinaryOperator &I, Value *V) const {
+ BinaryOperator *BinOp = dyn_cast<BinaryOperator>(V);
+ if (!BinOp) // Possibly constant expression.
+ return V;
+
+ if (isa<OverflowingBinaryOperator>(BinOp)) {
+ BinOp->setHasNoSignedWrap(I.hasNoSignedWrap());
+ BinOp->setHasNoUnsignedWrap(I.hasNoUnsignedWrap());
+ } else if (isa<PossiblyExactOperator>(BinOp))
+ BinOp->setIsExact(I.isExact());
+
+ return V;
+}
+
+unsigned AMDGPUCodeGenPrepare::getBaseElementBitWidth(const Type *T) const {
+ assert(needsPromotionToI32(T) && "T does not need promotion to i32");
+
+ if (T->isIntegerTy())
+ return T->getIntegerBitWidth();
+ return cast<VectorType>(T)->getElementType()->getIntegerBitWidth();
+}
+
+Type *AMDGPUCodeGenPrepare::getI32Ty(IRBuilder<> &B, const Type *T) const {
+ assert(needsPromotionToI32(T) && "T does not need promotion to i32");
+
+ if (T->isIntegerTy())
+ return B.getInt32Ty();
+ return VectorType::get(B.getInt32Ty(), cast<VectorType>(T)->getNumElements());
+}
+
+bool AMDGPUCodeGenPrepare::isSigned(const BinaryOperator &I) const {
+ return I.getOpcode() == Instruction::AShr ||
+ I.getOpcode() == Instruction::SDiv || I.getOpcode() == Instruction::SRem;
+}
+
+bool AMDGPUCodeGenPrepare::isSigned(const SelectInst &I) const {
+ return isa<ICmpInst>(I.getOperand(0)) ?
+ cast<ICmpInst>(I.getOperand(0))->isSigned() : false;
+}
+
+bool AMDGPUCodeGenPrepare::needsPromotionToI32(const Type *T) const {
+ if (T->isIntegerTy() && T->getIntegerBitWidth() > 1 &&
+ T->getIntegerBitWidth() <= 16)
+ return true;
+ if (!T->isVectorTy())
+ return false;
+ return needsPromotionToI32(cast<VectorType>(T)->getElementType());
+}
+
+bool AMDGPUCodeGenPrepare::promoteUniformOpToI32(BinaryOperator &I) const {
+ assert(needsPromotionToI32(I.getType()) &&
+ "I does not need promotion to i32");
+
+ if (I.getOpcode() == Instruction::SDiv ||
+ I.getOpcode() == Instruction::UDiv)
+ return false;
+
+ IRBuilder<> Builder(&I);
+ Builder.SetCurrentDebugLocation(I.getDebugLoc());
+
+ Type *I32Ty = getI32Ty(Builder, I.getType());
+ Value *ExtOp0 = nullptr;
+ Value *ExtOp1 = nullptr;
+ Value *ExtRes = nullptr;
+ Value *TruncRes = nullptr;
+
+ if (isSigned(I)) {
+ ExtOp0 = Builder.CreateSExt(I.getOperand(0), I32Ty);
+ ExtOp1 = Builder.CreateSExt(I.getOperand(1), I32Ty);
+ } else {
+ ExtOp0 = Builder.CreateZExt(I.getOperand(0), I32Ty);
+ ExtOp1 = Builder.CreateZExt(I.getOperand(1), I32Ty);
+ }
+ ExtRes = copyFlags(I, Builder.CreateBinOp(I.getOpcode(), ExtOp0, ExtOp1));
+ TruncRes = Builder.CreateTrunc(ExtRes, I.getType());
+
+ I.replaceAllUsesWith(TruncRes);
+ I.eraseFromParent();
+
+ return true;
+}
+
+bool AMDGPUCodeGenPrepare::promoteUniformOpToI32(ICmpInst &I) const {
+ assert(needsPromotionToI32(I.getOperand(0)->getType()) &&
+ "I does not need promotion to i32");
+
+ IRBuilder<> Builder(&I);
+ Builder.SetCurrentDebugLocation(I.getDebugLoc());
+
+ Type *I32Ty = getI32Ty(Builder, I.getOperand(0)->getType());
+ Value *ExtOp0 = nullptr;
+ Value *ExtOp1 = nullptr;
+ Value *NewICmp = nullptr;
+
+ if (I.isSigned()) {
+ ExtOp0 = Builder.CreateSExt(I.getOperand(0), I32Ty);
+ ExtOp1 = Builder.CreateSExt(I.getOperand(1), I32Ty);
+ } else {
+ ExtOp0 = Builder.CreateZExt(I.getOperand(0), I32Ty);
+ ExtOp1 = Builder.CreateZExt(I.getOperand(1), I32Ty);
+ }
+ NewICmp = Builder.CreateICmp(I.getPredicate(), ExtOp0, ExtOp1);
+
+ I.replaceAllUsesWith(NewICmp);
+ I.eraseFromParent();
+
+ return true;
+}
+
+bool AMDGPUCodeGenPrepare::promoteUniformOpToI32(SelectInst &I) const {
+ assert(needsPromotionToI32(I.getType()) &&
+ "I does not need promotion to i32");
+
+ IRBuilder<> Builder(&I);
+ Builder.SetCurrentDebugLocation(I.getDebugLoc());
+
+ Type *I32Ty = getI32Ty(Builder, I.getType());
+ Value *ExtOp1 = nullptr;
+ Value *ExtOp2 = nullptr;
+ Value *ExtRes = nullptr;
+ Value *TruncRes = nullptr;
+
+ if (isSigned(I)) {
+ ExtOp1 = Builder.CreateSExt(I.getOperand(1), I32Ty);
+ ExtOp2 = Builder.CreateSExt(I.getOperand(2), I32Ty);
+ } else {
+ ExtOp1 = Builder.CreateZExt(I.getOperand(1), I32Ty);
+ ExtOp2 = Builder.CreateZExt(I.getOperand(2), I32Ty);
+ }
+ ExtRes = Builder.CreateSelect(I.getOperand(0), ExtOp1, ExtOp2);
+ TruncRes = Builder.CreateTrunc(ExtRes, I.getType());
+
+ I.replaceAllUsesWith(TruncRes);
+ I.eraseFromParent();
+
+ return true;
+}
+
+bool AMDGPUCodeGenPrepare::promoteUniformBitreverseToI32(
+ IntrinsicInst &I) const {
+ assert(I.getIntrinsicID() == Intrinsic::bitreverse &&
+ "I must be bitreverse intrinsic");
+ assert(needsPromotionToI32(I.getType()) &&
+ "I does not need promotion to i32");
+
+ IRBuilder<> Builder(&I);
+ Builder.SetCurrentDebugLocation(I.getDebugLoc());
+
+ Type *I32Ty = getI32Ty(Builder, I.getType());
+ Function *I32 =
+ Intrinsic::getDeclaration(Mod, Intrinsic::bitreverse, { I32Ty });
+ Value *ExtOp = Builder.CreateZExt(I.getOperand(0), I32Ty);
+ Value *ExtRes = Builder.CreateCall(I32, { ExtOp });
+ Value *LShrOp =
+ Builder.CreateLShr(ExtRes, 32 - getBaseElementBitWidth(I.getType()));
+ Value *TruncRes =
+ Builder.CreateTrunc(LShrOp, I.getType());
+
+ I.replaceAllUsesWith(TruncRes);
+ I.eraseFromParent();
+
+ return true;
+}
+
static bool shouldKeepFDivF32(Value *Num, bool UnsafeDiv) {
const ConstantFP *CNum = dyn_cast<ConstantFP>(Num);
if (!CNum)
@@ -85,7 +324,6 @@ static bool shouldKeepFDivF32(Value *Num, bool UnsafeDiv) {
bool AMDGPUCodeGenPrepare::visitFDiv(BinaryOperator &FDiv) {
Type *Ty = FDiv.getType();
- // TODO: Handle half
if (!Ty->getScalarType()->isFloatTy())
return false;
@@ -154,6 +392,55 @@ static bool hasUnsafeFPMath(const Function &F) {
return Attr.getValueAsString() == "true";
}
+bool AMDGPUCodeGenPrepare::visitBinaryOperator(BinaryOperator &I) {
+ bool Changed = false;
+
+ if (ST->has16BitInsts() && needsPromotionToI32(I.getType()) &&
+ DA->isUniform(&I))
+ Changed |= promoteUniformOpToI32(I);
+
+ return Changed;
+}
+
+bool AMDGPUCodeGenPrepare::visitICmpInst(ICmpInst &I) {
+ bool Changed = false;
+
+ if (ST->has16BitInsts() && needsPromotionToI32(I.getOperand(0)->getType()) &&
+ DA->isUniform(&I))
+ Changed |= promoteUniformOpToI32(I);
+
+ return Changed;
+}
+
+bool AMDGPUCodeGenPrepare::visitSelectInst(SelectInst &I) {
+ bool Changed = false;
+
+ if (ST->has16BitInsts() && needsPromotionToI32(I.getType()) &&
+ DA->isUniform(&I))
+ Changed |= promoteUniformOpToI32(I);
+
+ return Changed;
+}
+
+bool AMDGPUCodeGenPrepare::visitIntrinsicInst(IntrinsicInst &I) {
+ switch (I.getIntrinsicID()) {
+ case Intrinsic::bitreverse:
+ return visitBitreverseIntrinsicInst(I);
+ default:
+ return false;
+ }
+}
+
+bool AMDGPUCodeGenPrepare::visitBitreverseIntrinsicInst(IntrinsicInst &I) {
+ bool Changed = false;
+
+ if (ST->has16BitInsts() && needsPromotionToI32(I.getType()) &&
+ DA->isUniform(&I))
+ Changed |= promoteUniformBitreverseToI32(I);
+
+ return Changed;
+}
+
bool AMDGPUCodeGenPrepare::doInitialization(Module &M) {
Mod = &M;
return false;
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.cpp
index bbc28b8..805fb71 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.cpp
@@ -10,23 +10,22 @@
// Interface to describe a layout of a stack frame on a AMDGPU target machine.
//
//===----------------------------------------------------------------------===//
+
#include "AMDGPUFrameLowering.h"
#include "AMDGPURegisterInfo.h"
#include "AMDGPUSubtarget.h"
-
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/IR/Instructions.h"
+#include "llvm/Support/MathExtras.h"
using namespace llvm;
AMDGPUFrameLowering::AMDGPUFrameLowering(StackDirection D, unsigned StackAl,
int LAO, unsigned TransAl)
: TargetFrameLowering(D, StackAl, LAO, TransAl) { }
-AMDGPUFrameLowering::~AMDGPUFrameLowering() { }
+AMDGPUFrameLowering::~AMDGPUFrameLowering() = default;
unsigned AMDGPUFrameLowering::getStackWidth(const MachineFunction &MF) const {
-
// XXX: Hardcoding to 1 for now.
//
// I think the StackWidth should stored as metadata associated with the
@@ -75,7 +74,7 @@ unsigned AMDGPUFrameLowering::getStackWidth(const MachineFunction &MF) const {
int AMDGPUFrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI,
unsigned &FrameReg) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const AMDGPURegisterInfo *RI
= MF.getSubtarget<AMDGPUSubtarget>().getRegisterInfo();
@@ -86,19 +85,18 @@ int AMDGPUFrameLowering::getFrameIndexReference(const MachineFunction &MF,
// XXX: We should only do this when the shader actually uses this
// information.
unsigned OffsetBytes = 2 * (getStackWidth(MF) * 4);
- int UpperBound = FI == -1 ? MFI->getNumObjects() : FI;
+ int UpperBound = FI == -1 ? MFI.getNumObjects() : FI;
- for (int i = MFI->getObjectIndexBegin(); i < UpperBound; ++i) {
- OffsetBytes = alignTo(OffsetBytes, MFI->getObjectAlignment(i));
- OffsetBytes += MFI->getObjectSize(i);
+ for (int i = MFI.getObjectIndexBegin(); i < UpperBound; ++i) {
+ OffsetBytes = alignTo(OffsetBytes, MFI.getObjectAlignment(i));
+ OffsetBytes += MFI.getObjectSize(i);
// Each register holds 4 bytes, so we must always align the offset to at
// least 4 bytes, so that 2 frame objects won't share the same register.
OffsetBytes = alignTo(OffsetBytes, 4);
}
if (FI != -1)
- OffsetBytes = alignTo(OffsetBytes, MFI->getObjectAlignment(FI));
+ OffsetBytes = alignTo(OffsetBytes, MFI.getObjectAlignment(FI));
return OffsetBytes / (getStackWidth(MF) * 4);
}
-
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.h
index 513848a..5d51351 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUFrameLowering.h
@@ -11,6 +11,7 @@
/// \brief Interface to describe a layout of a stack frame on an AMDGPU target.
//
//===----------------------------------------------------------------------===//
+
#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPUFRAMELOWERING_H
#define LLVM_LIB_TARGET_AMDGPU_AMDGPUFRAMELOWERING_H
@@ -27,7 +28,7 @@ class AMDGPUFrameLowering : public TargetFrameLowering {
public:
AMDGPUFrameLowering(StackDirection D, unsigned StackAl, int LAO,
unsigned TransAl = 1);
- virtual ~AMDGPUFrameLowering();
+ ~AMDGPUFrameLowering() override;
/// \returns The number of 32-bit sub-registers that are used when storing
/// values to the stack.
@@ -40,5 +41,7 @@ public:
return false;
}
};
-} // namespace llvm
-#endif
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_AMDGPU_AMDGPUFRAMELOWERING_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp
index 23c9352..5bf347e 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp
@@ -12,25 +12,48 @@
//
//===----------------------------------------------------------------------===//
+#include "AMDGPU.h"
#include "AMDGPUInstrInfo.h"
-#include "AMDGPUIntrinsicInfo.h"
+#include "AMDGPURegisterInfo.h"
#include "AMDGPUISelLowering.h" // For AMDGPUISD
#include "AMDGPUSubtarget.h"
+#include "SIDefines.h"
+#include "SIInstrInfo.h"
+#include "SIRegisterInfo.h"
#include "SIISelLowering.h"
#include "SIMachineFunctionInfo.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
-#include "llvm/CodeGen/MachineFrameInfo.h"
-#include "llvm/CodeGen/PseudoSourceValue.h"
+#include "llvm/CodeGen/ISDOpcodes.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
-#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/CodeGen/SelectionDAGNodes.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstdint>
+#include <new>
+#include <vector>
using namespace llvm;
namespace llvm {
+
class R600InstrInfo;
-}
+
+} // end namespace llvm
//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
@@ -38,18 +61,6 @@ class R600InstrInfo;
namespace {
-static bool isCBranchSCC(const SDNode *N) {
- assert(N->getOpcode() == ISD::BRCOND);
- if (!N->hasOneUse())
- return false;
-
- SDValue Cond = N->getOperand(1);
- if (Cond.getOpcode() == ISD::CopyToReg)
- Cond = Cond.getOperand(2);
- return Cond.getOpcode() == ISD::SETCC &&
- Cond.getOperand(0).getValueType() == MVT::i32 && Cond.hasOneUse();
-}
-
/// AMDGPU specific code to select AMDGPU machine instructions for
/// SelectionDAG operations.
class AMDGPUDAGToDAGISel : public SelectionDAGISel {
@@ -58,16 +69,18 @@ class AMDGPUDAGToDAGISel : public SelectionDAGISel {
const AMDGPUSubtarget *Subtarget;
public:
- AMDGPUDAGToDAGISel(TargetMachine &TM);
- virtual ~AMDGPUDAGToDAGISel();
+ explicit AMDGPUDAGToDAGISel(TargetMachine &TM, CodeGenOpt::Level OptLevel)
+ : SelectionDAGISel(TM, OptLevel) {}
+ ~AMDGPUDAGToDAGISel() override = default;
+
bool runOnMachineFunction(MachineFunction &MF) override;
void Select(SDNode *N) override;
- const char *getPassName() const override;
- void PreprocessISelDAG() override;
+ StringRef getPassName() const override;
void PostprocessISelDAG() override;
private:
- bool isInlineImmediate(SDNode *N) const;
+ SDValue foldFrameIndex(SDValue N) const;
+ bool isInlineImmediate(const SDNode *N) const;
bool FoldOperand(SDValue &Src, SDValue &Sel, SDValue &Neg, SDValue &Abs,
const R600InstrInfo *TII);
bool FoldOperands(unsigned, const R600InstrInfo *, std::vector<SDValue> &);
@@ -145,40 +158,46 @@ private:
void SelectADD_SUB_I64(SDNode *N);
void SelectDIV_SCALE(SDNode *N);
+ void SelectFMA_W_CHAIN(SDNode *N);
+ void SelectFMUL_W_CHAIN(SDNode *N);
SDNode *getS_BFE(unsigned Opcode, const SDLoc &DL, SDValue Val,
uint32_t Offset, uint32_t Width);
void SelectS_BFEFromShifts(SDNode *N);
void SelectS_BFE(SDNode *N);
+ bool isCBranchSCC(const SDNode *N) const;
void SelectBRCOND(SDNode *N);
void SelectATOMIC_CMP_SWAP(SDNode *N);
// Include the pieces autogenerated from the target description.
#include "AMDGPUGenDAGISel.inc"
};
+
} // end anonymous namespace
/// \brief This pass converts a legalized DAG into a AMDGPU-specific
// DAG, ready for instruction scheduling.
-FunctionPass *llvm::createAMDGPUISelDag(TargetMachine &TM) {
- return new AMDGPUDAGToDAGISel(TM);
+FunctionPass *llvm::createAMDGPUISelDag(TargetMachine &TM,
+ CodeGenOpt::Level OptLevel) {
+ return new AMDGPUDAGToDAGISel(TM, OptLevel);
}
-AMDGPUDAGToDAGISel::AMDGPUDAGToDAGISel(TargetMachine &TM)
- : SelectionDAGISel(TM) {}
-
bool AMDGPUDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
Subtarget = &MF.getSubtarget<AMDGPUSubtarget>();
return SelectionDAGISel::runOnMachineFunction(MF);
}
-AMDGPUDAGToDAGISel::~AMDGPUDAGToDAGISel() {
-}
+bool AMDGPUDAGToDAGISel::isInlineImmediate(const SDNode *N) const {
+ const SIInstrInfo *TII
+ = static_cast<const SISubtarget *>(Subtarget)->getInstrInfo();
+
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(N))
+ return TII->isInlineConstant(C->getAPIntValue());
+
+ if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N))
+ return TII->isInlineConstant(C->getValueAPF().bitcastToAPInt());
-bool AMDGPUDAGToDAGISel::isInlineImmediate(SDNode *N) const {
- const SITargetLowering *TL
- = static_cast<const SITargetLowering *>(getTargetLowering());
- return TL->analyzeImmediate(N) == 0;
+ return false;
}
/// \brief Determine the register class for \p OpNo
@@ -187,8 +206,21 @@ bool AMDGPUDAGToDAGISel::isInlineImmediate(SDNode *N) const {
/// determined.
const TargetRegisterClass *AMDGPUDAGToDAGISel::getOperandRegClass(SDNode *N,
unsigned OpNo) const {
- if (!N->isMachineOpcode())
+ if (!N->isMachineOpcode()) {
+ if (N->getOpcode() == ISD::CopyToReg) {
+ unsigned Reg = cast<RegisterSDNode>(N->getOperand(1))->getReg();
+ if (TargetRegisterInfo::isVirtualRegister(Reg)) {
+ MachineRegisterInfo &MRI = CurDAG->getMachineFunction().getRegInfo();
+ return MRI.getRegClass(Reg);
+ }
+
+ const SIRegisterInfo *TRI
+ = static_cast<const SISubtarget *>(Subtarget)->getRegisterInfo();
+ return TRI->getPhysRegClass(Reg);
+ }
+
return nullptr;
+ }
switch (N->getMachineOpcode()) {
default: {
@@ -244,7 +276,7 @@ SDNode *AMDGPUDAGToDAGISel::glueCopyToM0(SDNode *N) const {
static unsigned selectSGPRVectorRegClassID(unsigned NumVectorElts) {
switch (NumVectorElts) {
case 1:
- return AMDGPU::SReg_32RegClassID;
+ return AMDGPU::SReg_32_XM0RegClassID;
case 2:
return AMDGPU::SReg_64RegClassID;
case 4:
@@ -275,7 +307,11 @@ void AMDGPUDAGToDAGISel::Select(SDNode *N) {
// DAG legalization, so we can fold some i64 ADDs used for address
// calculation into the LOAD and STORE instructions.
case ISD::ADD:
- case ISD::SUB: {
+ case ISD::ADDC:
+ case ISD::ADDE:
+ case ISD::SUB:
+ case ISD::SUBC:
+ case ISD::SUBE: {
if (N->getValueType(0) != MVT::i64 ||
Subtarget->getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
break;
@@ -283,6 +319,15 @@ void AMDGPUDAGToDAGISel::Select(SDNode *N) {
SelectADD_SUB_I64(N);
return;
}
+ case AMDGPUISD::FMUL_W_CHAIN: {
+ SelectFMUL_W_CHAIN(N);
+ return;
+ }
+ case AMDGPUISD::FMA_W_CHAIN: {
+ SelectFMA_W_CHAIN(N);
+ return;
+ }
+
case ISD::SCALAR_TO_VECTOR:
case AMDGPUISD::BUILD_VERTICAL_VECTOR:
case ISD::BUILD_VECTOR: {
@@ -498,7 +543,7 @@ bool AMDGPUDAGToDAGISel::isUniformBr(const SDNode *N) const {
Term->getMetadata("structurizecfg.uniform");
}
-const char *AMDGPUDAGToDAGISel::getPassName() const {
+StringRef AMDGPUDAGToDAGISel::getPassName() const {
return "AMDGPU DAG->DAG Pattern Instruction Selection";
}
@@ -563,6 +608,10 @@ bool AMDGPUDAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,
if ((C = dyn_cast<ConstantSDNode>(Addr))) {
Base = CurDAG->getRegister(AMDGPU::INDIRECT_BASE_ADDR, MVT::i32);
Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
+ } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) &&
+ (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) {
+ Base = CurDAG->getRegister(AMDGPU::INDIRECT_BASE_ADDR, MVT::i32);
+ Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
} else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) &&
(C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) {
Base = Addr.getOperand(0);
@@ -580,7 +629,12 @@ void AMDGPUDAGToDAGISel::SelectADD_SUB_I64(SDNode *N) {
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
- bool IsAdd = (N->getOpcode() == ISD::ADD);
+ unsigned Opcode = N->getOpcode();
+ bool ConsumeCarry = (Opcode == ISD::ADDE || Opcode == ISD::SUBE);
+ bool ProduceCarry =
+ ConsumeCarry || Opcode == ISD::ADDC || Opcode == ISD::SUBC;
+ bool IsAdd =
+ (Opcode == ISD::ADD || Opcode == ISD::ADDC || Opcode == ISD::ADDE);
SDValue Sub0 = CurDAG->getTargetConstant(AMDGPU::sub0, DL, MVT::i32);
SDValue Sub1 = CurDAG->getTargetConstant(AMDGPU::sub1, DL, MVT::i32);
@@ -596,25 +650,70 @@ void AMDGPUDAGToDAGISel::SelectADD_SUB_I64(SDNode *N) {
DL, MVT::i32, RHS, Sub1);
SDVTList VTList = CurDAG->getVTList(MVT::i32, MVT::Glue);
- SDValue AddLoArgs[] = { SDValue(Lo0, 0), SDValue(Lo1, 0) };
unsigned Opc = IsAdd ? AMDGPU::S_ADD_U32 : AMDGPU::S_SUB_U32;
unsigned CarryOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;
- SDNode *AddLo = CurDAG->getMachineNode( Opc, DL, VTList, AddLoArgs);
- SDValue Carry(AddLo, 1);
- SDNode *AddHi
- = CurDAG->getMachineNode(CarryOpc, DL, MVT::i32,
- SDValue(Hi0, 0), SDValue(Hi1, 0), Carry);
+ SDNode *AddLo;
+ if (!ConsumeCarry) {
+ SDValue Args[] = { SDValue(Lo0, 0), SDValue(Lo1, 0) };
+ AddLo = CurDAG->getMachineNode(Opc, DL, VTList, Args);
+ } else {
+ SDValue Args[] = { SDValue(Lo0, 0), SDValue(Lo1, 0), N->getOperand(2) };
+ AddLo = CurDAG->getMachineNode(CarryOpc, DL, VTList, Args);
+ }
+ SDValue AddHiArgs[] = {
+ SDValue(Hi0, 0),
+ SDValue(Hi1, 0),
+ SDValue(AddLo, 1)
+ };
+ SDNode *AddHi = CurDAG->getMachineNode(CarryOpc, DL, VTList, AddHiArgs);
- SDValue Args[5] = {
+ SDValue RegSequenceArgs[] = {
CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, DL, MVT::i32),
SDValue(AddLo,0),
Sub0,
SDValue(AddHi,0),
Sub1,
};
- CurDAG->SelectNodeTo(N, AMDGPU::REG_SEQUENCE, MVT::i64, Args);
+ SDNode *RegSequence = CurDAG->getMachineNode(AMDGPU::REG_SEQUENCE, DL,
+ MVT::i64, RegSequenceArgs);
+
+ if (ProduceCarry) {
+ // Replace the carry-use
+ CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 1), SDValue(AddHi, 1));
+ }
+
+ // Replace the remaining uses.
+ CurDAG->ReplaceAllUsesWith(N, RegSequence);
+ CurDAG->RemoveDeadNode(N);
+}
+
+void AMDGPUDAGToDAGISel::SelectFMA_W_CHAIN(SDNode *N) {
+ SDLoc SL(N);
+ // src0_modifiers, src0, src1_modifiers, src1, src2_modifiers, src2, clamp, omod
+ SDValue Ops[10];
+
+ SelectVOP3Mods0(N->getOperand(1), Ops[1], Ops[0], Ops[6], Ops[7]);
+ SelectVOP3Mods(N->getOperand(2), Ops[3], Ops[2]);
+ SelectVOP3Mods(N->getOperand(3), Ops[5], Ops[4]);
+ Ops[8] = N->getOperand(0);
+ Ops[9] = N->getOperand(4);
+
+ CurDAG->SelectNodeTo(N, AMDGPU::V_FMA_F32, N->getVTList(), Ops);
+}
+
+void AMDGPUDAGToDAGISel::SelectFMUL_W_CHAIN(SDNode *N) {
+ SDLoc SL(N);
+ // src0_modifiers, src0, src1_modifiers, src1, clamp, omod
+ SDValue Ops[8];
+
+ SelectVOP3Mods0(N->getOperand(1), Ops[1], Ops[0], Ops[4], Ops[5]);
+ SelectVOP3Mods(N->getOperand(2), Ops[3], Ops[2]);
+ Ops[6] = N->getOperand(0);
+ Ops[7] = N->getOperand(3);
+
+ CurDAG->SelectNodeTo(N, AMDGPU::V_MUL_F32_e64, N->getVTList(), Ops);
}
// We need to handle this here because tablegen doesn't support matching
@@ -628,14 +727,8 @@ void AMDGPUDAGToDAGISel::SelectDIV_SCALE(SDNode *N) {
unsigned Opc
= (VT == MVT::f64) ? AMDGPU::V_DIV_SCALE_F64 : AMDGPU::V_DIV_SCALE_F32;
- // src0_modifiers, src0, src1_modifiers, src1, src2_modifiers, src2, clamp,
- // omod
- SDValue Ops[8];
-
- SelectVOP3Mods0(N->getOperand(0), Ops[1], Ops[0], Ops[6], Ops[7]);
- SelectVOP3Mods(N->getOperand(1), Ops[3], Ops[2]);
- SelectVOP3Mods(N->getOperand(2), Ops[5], Ops[4]);
- CurDAG->SelectNodeTo(N, Opc, VT, MVT::i1, Ops);
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
+ CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops);
}
bool AMDGPUDAGToDAGISel::isDSOffsetLegal(const SDValue &Base, unsigned Offset,
@@ -779,6 +872,9 @@ bool AMDGPUDAGToDAGISel::SelectDS64Bit4ByteAligned(SDValue Addr, SDValue &Base,
}
// default case
+
+ // FIXME: This is broken on SI where we still need to check if the base
+ // pointer is positive here.
Base = Addr;
Offset0 = CurDAG->getTargetConstant(0, DL, MVT::i8);
Offset1 = CurDAG->getTargetConstant(1, DL, MVT::i8);
@@ -825,7 +921,6 @@ bool AMDGPUDAGToDAGISel::SelectMUBUF(SDValue Addr, SDValue &Ptr,
Ptr = N2;
VAddr = N3;
} else {
-
// (add N0, C1) -> offset
VAddr = CurDAG->getTargetConstant(0, DL, MVT::i32);
Ptr = N0;
@@ -903,6 +998,12 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc,
return SelectMUBUFAddr64(Addr, SRsrc, VAddr, SOffset, Offset, GLC, SLC, TFE);
}
+SDValue AMDGPUDAGToDAGISel::foldFrameIndex(SDValue N) const {
+ if (auto FI = dyn_cast<FrameIndexSDNode>(N))
+ return CurDAG->getTargetFrameIndex(FI->getIndex(), FI->getValueType(0));
+ return N;
+}
+
bool AMDGPUDAGToDAGISel::SelectMUBUFScratch(SDValue Addr, SDValue &Rsrc,
SDValue &VAddr, SDValue &SOffset,
SDValue &ImmOffset) const {
@@ -922,14 +1023,14 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFScratch(SDValue Addr, SDValue &Rsrc,
// Offsets in vaddr must be positive.
ConstantSDNode *C1 = cast<ConstantSDNode>(N1);
if (isLegalMUBUFImmOffset(C1)) {
- VAddr = N0;
+ VAddr = foldFrameIndex(N0);
ImmOffset = CurDAG->getTargetConstant(C1->getZExtValue(), DL, MVT::i16);
return true;
}
}
// (node)
- VAddr = Addr;
+ VAddr = foldFrameIndex(Addr);
ImmOffset = CurDAG->getTargetConstant(0, DL, MVT::i16);
return true;
}
@@ -1122,7 +1223,6 @@ bool AMDGPUDAGToDAGISel::SelectSMRDOffset(SDValue ByteOffsetNode,
bool AMDGPUDAGToDAGISel::SelectSMRD(SDValue Addr, SDValue &SBase,
SDValue &Offset, bool &Imm) const {
-
SDLoc SL(Addr);
if (CurDAG->isBaseWithConstantOffset(Addr)) {
SDValue N0 = Addr.getOperand(0);
@@ -1327,36 +1427,53 @@ void AMDGPUDAGToDAGISel::SelectS_BFE(SDNode *N) {
SelectCode(N);
}
+bool AMDGPUDAGToDAGISel::isCBranchSCC(const SDNode *N) const {
+ assert(N->getOpcode() == ISD::BRCOND);
+ if (!N->hasOneUse())
+ return false;
+
+ SDValue Cond = N->getOperand(1);
+ if (Cond.getOpcode() == ISD::CopyToReg)
+ Cond = Cond.getOperand(2);
+
+ if (Cond.getOpcode() != ISD::SETCC || !Cond.hasOneUse())
+ return false;
+
+ MVT VT = Cond.getOperand(0).getSimpleValueType();
+ if (VT == MVT::i32)
+ return true;
+
+ if (VT == MVT::i64) {
+ auto ST = static_cast<const SISubtarget *>(Subtarget);
+
+ ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();
+ return (CC == ISD::SETEQ || CC == ISD::SETNE) && ST->hasScalarCompareEq64();
+ }
+
+ return false;
+}
+
void AMDGPUDAGToDAGISel::SelectBRCOND(SDNode *N) {
SDValue Cond = N->getOperand(1);
+ if (Cond.isUndef()) {
+ CurDAG->SelectNodeTo(N, AMDGPU::SI_BR_UNDEF, MVT::Other,
+ N->getOperand(2), N->getOperand(0));
+ return;
+ }
+
if (isCBranchSCC(N)) {
// This brcond will use S_CBRANCH_SCC*, so let tablegen handle it.
SelectCode(N);
return;
}
- // The result of VOPC instructions is or'd against ~EXEC before it is
- // written to vcc or another SGPR. This means that the value '1' is always
- // written to the corresponding bit for results that are masked. In order
- // to correctly check against vccz, we need to and VCC with the EXEC
- // register in order to clear the value from the masked bits.
-
SDLoc SL(N);
- SDNode *MaskedCond =
- CurDAG->getMachineNode(AMDGPU::S_AND_B64, SL, MVT::i1,
- CurDAG->getRegister(AMDGPU::EXEC, MVT::i1),
- Cond);
- SDValue VCC = CurDAG->getCopyToReg(N->getOperand(0), SL, AMDGPU::VCC,
- SDValue(MaskedCond, 0),
- SDValue()); // Passing SDValue() adds a
- // glue output.
+ SDValue VCC = CurDAG->getCopyToReg(N->getOperand(0), SL, AMDGPU::VCC, Cond);
CurDAG->SelectNodeTo(N, AMDGPU::S_CBRANCH_VCCNZ, MVT::Other,
N->getOperand(2), // Basic Block
- VCC.getValue(0), // Chain
- VCC.getValue(1)); // Glue
- return;
+ VCC.getValue(0));
}
// This is here because there isn't a way to use the generated sub0_sub1 as the
@@ -1427,7 +1544,6 @@ void AMDGPUDAGToDAGISel::SelectATOMIC_CMP_SWAP(SDNode *N) {
bool AMDGPUDAGToDAGISel::SelectVOP3Mods(SDValue In, SDValue &Src,
SDValue &SrcMods) const {
-
unsigned Mods = 0;
Src = In;
@@ -1491,62 +1607,6 @@ bool AMDGPUDAGToDAGISel::SelectVOP3Mods0Clamp0OMod(SDValue In, SDValue &Src,
return SelectVOP3Mods(In, Src, SrcMods);
}
-void AMDGPUDAGToDAGISel::PreprocessISelDAG() {
- MachineFrameInfo *MFI = CurDAG->getMachineFunction().getFrameInfo();
-
- // Handle the perverse case where a frame index is being stored. We don't
- // want to see multiple frame index operands on the same instruction since
- // it complicates things and violates some assumptions about frame index
- // lowering.
- for (int I = MFI->getObjectIndexBegin(), E = MFI->getObjectIndexEnd();
- I != E; ++I) {
- SDValue FI = CurDAG->getTargetFrameIndex(I, MVT::i32);
-
- // It's possible that we have a frame index defined in the function that
- // isn't used in this block.
- if (FI.use_empty())
- continue;
-
- // Skip over the AssertZext inserted during lowering.
- SDValue EffectiveFI = FI;
- auto It = FI->use_begin();
- if (It->getOpcode() == ISD::AssertZext && FI->hasOneUse()) {
- EffectiveFI = SDValue(*It, 0);
- It = EffectiveFI->use_begin();
- }
-
- for (auto It = EffectiveFI->use_begin(); !It.atEnd(); ) {
- SDUse &Use = It.getUse();
- SDNode *User = Use.getUser();
- unsigned OpIdx = It.getOperandNo();
- ++It;
-
- if (MemSDNode *M = dyn_cast<MemSDNode>(User)) {
- unsigned PtrIdx = M->getOpcode() == ISD::STORE ? 2 : 1;
- if (OpIdx == PtrIdx)
- continue;
-
- unsigned OpN = M->getNumOperands();
- SDValue NewOps[8];
-
- assert(OpN < array_lengthof(NewOps));
- for (unsigned Op = 0; Op != OpN; ++Op) {
- if (Op != OpIdx) {
- NewOps[Op] = M->getOperand(Op);
- continue;
- }
-
- MachineSDNode *Mov = CurDAG->getMachineNode(AMDGPU::V_MOV_B32_e32,
- SDLoc(M), MVT::i32, FI);
- NewOps[Op] = SDValue(Mov, 0);
- }
-
- CurDAG->UpdateNodeOperands(M, makeArrayRef(NewOps, OpN));
- }
- }
- }
-}
-
void AMDGPUDAGToDAGISel::PostprocessISelDAG() {
const AMDGPUTargetLowering& Lowering =
*static_cast<const AMDGPUTargetLowering*>(getTargetLowering());
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index 352423ed..54caa2c 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -37,7 +37,7 @@ static bool allocateKernArg(unsigned ValNo, MVT ValVT, MVT LocVT,
MachineFunction &MF = State.getMachineFunction();
AMDGPUMachineFunction *MFI = MF.getInfo<AMDGPUMachineFunction>();
- uint64_t Offset = MFI->allocateKernArg(ValVT.getStoreSize(),
+ uint64_t Offset = MFI->allocateKernArg(LocVT.getStoreSize(),
ArgFlags.getOrigAlign());
State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return true;
@@ -55,14 +55,6 @@ EVT AMDGPUTargetLowering::getEquivalentMemType(LLVMContext &Ctx, EVT VT) {
return EVT::getVectorVT(Ctx, MVT::i32, StoreSize / 32);
}
-EVT AMDGPUTargetLowering::getEquivalentBitType(LLVMContext &Ctx, EVT VT) {
- unsigned StoreSize = VT.getStoreSizeInBits();
- if (StoreSize <= 32)
- return EVT::getIntegerVT(Ctx, StoreSize);
-
- return EVT::getVectorVT(Ctx, MVT::i32, StoreSize / 32);
-}
-
AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
const AMDGPUSubtarget &STI)
: TargetLowering(TM), Subtarget(&STI) {
@@ -180,16 +172,6 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STORE, MVT::v2f64, Promote);
AddPromotedToType(ISD::STORE, MVT::v2f64, MVT::v4i32);
- setTruncStoreAction(MVT::v2i32, MVT::v2i8, Custom);
- setTruncStoreAction(MVT::v2i32, MVT::v2i16, Custom);
-
- setTruncStoreAction(MVT::v4i32, MVT::v4i8, Custom);
- setTruncStoreAction(MVT::v4i32, MVT::v4i16, Expand);
-
- setTruncStoreAction(MVT::v8i32, MVT::v8i16, Expand);
- setTruncStoreAction(MVT::v16i32, MVT::v16i8, Expand);
- setTruncStoreAction(MVT::v16i32, MVT::v16i16, Expand);
-
setTruncStoreAction(MVT::i64, MVT::i1, Expand);
setTruncStoreAction(MVT::i64, MVT::i8, Expand);
setTruncStoreAction(MVT::i64, MVT::i16, Expand);
@@ -287,6 +269,7 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
}
setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
+ setOperationAction(ISD::FP_TO_FP16, MVT::f64, Custom);
const MVT ScalarIntVTs[] = { MVT::i32, MVT::i64 };
for (MVT VT : ScalarIntVTs) {
@@ -367,6 +350,8 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FP_TO_SINT, VT, Expand);
setOperationAction(ISD::FP_TO_UINT, VT, Expand);
setOperationAction(ISD::MUL, VT, Expand);
+ setOperationAction(ISD::MULHU, VT, Expand);
+ setOperationAction(ISD::MULHS, VT, Expand);
setOperationAction(ISD::OR, VT, Expand);
setOperationAction(ISD::SHL, VT, Expand);
setOperationAction(ISD::SRA, VT, Expand);
@@ -440,22 +425,31 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SELECT, MVT::v4f32, Promote);
AddPromotedToType(ISD::SELECT, MVT::v4f32, MVT::v4i32);
+ // There are no libcalls of any kind.
+ for (int I = 0; I < RTLIB::UNKNOWN_LIBCALL; ++I)
+ setLibcallName(static_cast<RTLIB::Libcall>(I), nullptr);
+
setBooleanContents(ZeroOrNegativeOneBooleanContent);
setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
setSchedulingPreference(Sched::RegPressure);
setJumpIsExpensive(true);
+ // FIXME: This is only partially true. If we have to do vector compares, any
+ // SGPR pair can be a condition register. If we have a uniform condition, we
+ // are better off doing SALU operations, where there is only one SCC. For now,
+ // we don't have a way of knowing during instruction selection if a condition
+ // will be uniform and we always use vector compares. Assume we are using
+ // vector compares until that is fixed.
+ setHasMultipleConditionRegisters(true);
+
// SI at least has hardware support for floating point exceptions, but no way
// of using or handling them is implemented. They are also optional in OpenCL
// (Section 7.3)
setHasFloatingPointExceptions(Subtarget->hasFPExceptions());
- setSelectIsExpensive(false);
PredictableSelectIsExpensive = false;
- setFsqrtIsCheap(true);
-
// We want to find all load dependencies for long chains of stores to enable
// merging into very wide vectors. The problem is with vectors with > 4
// elements. MergeConsecutiveStores will attempt to merge these because x8/x16
@@ -472,22 +466,42 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
MaxStoresPerMemset = 4096;
setTargetDAGCombine(ISD::BITCAST);
- setTargetDAGCombine(ISD::AND);
setTargetDAGCombine(ISD::SHL);
setTargetDAGCombine(ISD::SRA);
setTargetDAGCombine(ISD::SRL);
setTargetDAGCombine(ISD::MUL);
+ setTargetDAGCombine(ISD::MULHU);
+ setTargetDAGCombine(ISD::MULHS);
setTargetDAGCombine(ISD::SELECT);
setTargetDAGCombine(ISD::SELECT_CC);
setTargetDAGCombine(ISD::STORE);
setTargetDAGCombine(ISD::FADD);
setTargetDAGCombine(ISD::FSUB);
+ setTargetDAGCombine(ISD::FNEG);
}
//===----------------------------------------------------------------------===//
// Target Information
//===----------------------------------------------------------------------===//
+static bool fnegFoldsIntoOp(unsigned Opc) {
+ switch (Opc) {
+ case ISD::FADD:
+ case ISD::FSUB:
+ case ISD::FMUL:
+ case ISD::FMA:
+ case ISD::FMAD:
+ case ISD::FSIN:
+ case AMDGPUISD::RCP:
+ case AMDGPUISD::RCP_LEGACY:
+ case AMDGPUISD::SIN_HW:
+ case AMDGPUISD::FMUL_LEGACY:
+ return true;
+ default:
+ return false;
+ }
+}
+
MVT AMDGPUTargetLowering::getVectorIdxTy(const DataLayout &) const {
return MVT::i32;
}
@@ -500,7 +514,8 @@ bool AMDGPUTargetLowering::isSelectSupported(SelectSupportKind SelType) const {
// FIXME: Why are we reporting vectors of FP immediates as legal?
bool AMDGPUTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
EVT ScalarVT = VT.getScalarType();
- return (ScalarVT == MVT::f32 || ScalarVT == MVT::f64);
+ return (ScalarVT == MVT::f32 || ScalarVT == MVT::f64 ||
+ (ScalarVT == MVT::f16 && Subtarget->has16BitInsts()));
}
// We don't want to shrink f64 / f32 constants.
@@ -565,12 +580,12 @@ bool AMDGPUTargetLowering::isCheapToSpeculateCtlz() const {
bool AMDGPUTargetLowering::isFAbsFree(EVT VT) const {
assert(VT.isFloatingPoint());
- return VT == MVT::f32 || VT == MVT::f64;
+ return VT == MVT::f32 || VT == MVT::f64 || (Subtarget->has16BitInsts() &&
+ VT == MVT::f16);
}
bool AMDGPUTargetLowering::isFNegFree(EVT VT) const {
- assert(VT.isFloatingPoint());
- return VT == MVT::f32 || VT == MVT::f64;
+ return isFAbsFree(VT);
}
bool AMDGPUTargetLowering:: storeOfVectorConstantIsCheap(EVT MemVT,
@@ -593,19 +608,32 @@ bool AMDGPUTargetLowering::aggressivelyPreferBuildVectorSources(EVT VecVT) const
bool AMDGPUTargetLowering::isTruncateFree(EVT Source, EVT Dest) const {
// Truncate is just accessing a subregister.
- return Dest.bitsLT(Source) && (Dest.getSizeInBits() % 32 == 0);
+
+ unsigned SrcSize = Source.getSizeInBits();
+ unsigned DestSize = Dest.getSizeInBits();
+
+ return DestSize < SrcSize && DestSize % 32 == 0 ;
}
bool AMDGPUTargetLowering::isTruncateFree(Type *Source, Type *Dest) const {
// Truncate is just accessing a subregister.
- return Dest->getPrimitiveSizeInBits() < Source->getPrimitiveSizeInBits() &&
- (Dest->getPrimitiveSizeInBits() % 32 == 0);
+
+ unsigned SrcSize = Source->getScalarSizeInBits();
+ unsigned DestSize = Dest->getScalarSizeInBits();
+
+ if (DestSize== 16 && Subtarget->has16BitInsts())
+ return SrcSize >= 32;
+
+ return DestSize < SrcSize && DestSize % 32 == 0;
}
bool AMDGPUTargetLowering::isZExtFree(Type *Src, Type *Dest) const {
unsigned SrcSize = Src->getScalarSizeInBits();
unsigned DestSize = Dest->getScalarSizeInBits();
+ if (SrcSize == 16 && Subtarget->has16BitInsts())
+ return DestSize >= 32;
+
return SrcSize == 32 && DestSize == 64;
}
@@ -614,6 +642,10 @@ bool AMDGPUTargetLowering::isZExtFree(EVT Src, EVT Dest) const {
// practical purposes, the extra mov 0 to load a 64-bit is free. As used,
// this will enable reducing 64-bit operations the 32-bit, which is always
// good.
+
+ if (Src == MVT::i16)
+ return Dest == MVT::i32 ||Dest == MVT::i64 ;
+
return Src == MVT::i32 && Dest == MVT::i64;
}
@@ -635,9 +667,105 @@ bool AMDGPUTargetLowering::isNarrowingProfitable(EVT SrcVT, EVT DestVT) const {
// TargetLowering Callbacks
//===---------------------------------------------------------------------===//
-void AMDGPUTargetLowering::AnalyzeFormalArguments(CCState &State,
+/// The SelectionDAGBuilder will automatically promote function arguments
+/// with illegal types. However, this does not work for the AMDGPU targets
+/// since the function arguments are stored in memory as these illegal types.
+/// In order to handle this properly we need to get the original types sizes
+/// from the LLVM IR Function and fixup the ISD:InputArg values before
+/// passing them to AnalyzeFormalArguments()
+
+/// When the SelectionDAGBuilder computes the Ins, it takes care of splitting
+/// input values across multiple registers. Each item in the Ins array
+/// represents a single value that will be stored in regsters. Ins[x].VT is
+/// the value type of the value that will be stored in the register, so
+/// whatever SDNode we lower the argument to needs to be this type.
+///
+/// In order to correctly lower the arguments we need to know the size of each
+/// argument. Since Ins[x].VT gives us the size of the register that will
+/// hold the value, we need to look at Ins[x].ArgVT to see the 'real' type
+/// for the orignal function argument so that we can deduce the correct memory
+/// type to use for Ins[x]. In most cases the correct memory type will be
+/// Ins[x].ArgVT. However, this will not always be the case. If, for example,
+/// we have a kernel argument of type v8i8, this argument will be split into
+/// 8 parts and each part will be represented by its own item in the Ins array.
+/// For each part the Ins[x].ArgVT will be the v8i8, which is the full type of
+/// the argument before it was split. From this, we deduce that the memory type
+/// for each individual part is i8. We pass the memory type as LocVT to the
+/// calling convention analysis function and the register type (Ins[x].VT) as
+/// the ValVT.
+void AMDGPUTargetLowering::analyzeFormalArgumentsCompute(CCState &State,
const SmallVectorImpl<ISD::InputArg> &Ins) const {
+ for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
+ const ISD::InputArg &In = Ins[i];
+ EVT MemVT;
+
+ unsigned NumRegs = getNumRegisters(State.getContext(), In.ArgVT);
+
+ if (!Subtarget->isAmdHsaOS() &&
+ (In.ArgVT == MVT::i16 || In.ArgVT == MVT::i8 || In.ArgVT == MVT::f16)) {
+ // The ABI says the caller will extend these values to 32-bits.
+ MemVT = In.ArgVT.isInteger() ? MVT::i32 : MVT::f32;
+ } else if (NumRegs == 1) {
+ // This argument is not split, so the IR type is the memory type.
+ assert(!In.Flags.isSplit());
+ if (In.ArgVT.isExtended()) {
+ // We have an extended type, like i24, so we should just use the register type
+ MemVT = In.VT;
+ } else {
+ MemVT = In.ArgVT;
+ }
+ } else if (In.ArgVT.isVector() && In.VT.isVector() &&
+ In.ArgVT.getScalarType() == In.VT.getScalarType()) {
+ assert(In.ArgVT.getVectorNumElements() > In.VT.getVectorNumElements());
+ // We have a vector value which has been split into a vector with
+ // the same scalar type, but fewer elements. This should handle
+ // all the floating-point vector types.
+ MemVT = In.VT;
+ } else if (In.ArgVT.isVector() &&
+ In.ArgVT.getVectorNumElements() == NumRegs) {
+ // This arg has been split so that each element is stored in a separate
+ // register.
+ MemVT = In.ArgVT.getScalarType();
+ } else if (In.ArgVT.isExtended()) {
+ // We have an extended type, like i65.
+ MemVT = In.VT;
+ } else {
+ unsigned MemoryBits = In.ArgVT.getStoreSizeInBits() / NumRegs;
+ assert(In.ArgVT.getStoreSizeInBits() % NumRegs == 0);
+ if (In.VT.isInteger()) {
+ MemVT = EVT::getIntegerVT(State.getContext(), MemoryBits);
+ } else if (In.VT.isVector()) {
+ assert(!In.VT.getScalarType().isFloatingPoint());
+ unsigned NumElements = In.VT.getVectorNumElements();
+ assert(MemoryBits % NumElements == 0);
+ // This vector type has been split into another vector type with
+ // a different elements size.
+ EVT ScalarVT = EVT::getIntegerVT(State.getContext(),
+ MemoryBits / NumElements);
+ MemVT = EVT::getVectorVT(State.getContext(), ScalarVT, NumElements);
+ } else {
+ llvm_unreachable("cannot deduce memory type.");
+ }
+ }
+ // Convert one element vectors to scalar.
+ if (MemVT.isVector() && MemVT.getVectorNumElements() == 1)
+ MemVT = MemVT.getScalarType();
+
+ if (MemVT.isExtended()) {
+ // This should really only happen if we have vec3 arguments
+ assert(MemVT.isVector() && MemVT.getVectorNumElements() == 3);
+ MemVT = MemVT.getPow2VectorType(State.getContext());
+ }
+
+ assert(MemVT.isSimple());
+ allocateKernArg(i, In.VT, MemVT.getSimpleVT(), CCValAssign::Full, In.Flags,
+ State);
+ }
+}
+
+void AMDGPUTargetLowering::AnalyzeFormalArguments(CCState &State,
+ const SmallVectorImpl<ISD::InputArg> &Ins) const {
State.AnalyzeFormalArguments(Ins, CC_AMDGPU);
}
@@ -678,8 +806,10 @@ SDValue AMDGPUTargetLowering::LowerCall(CallLoweringInfo &CLI,
Fn, "unsupported call to function " + FuncName, CLI.DL.getDebugLoc());
DAG.getContext()->diagnose(NoCalls);
- for (unsigned I = 0, E = CLI.Ins.size(); I != E; ++I)
- InVals.push_back(DAG.getUNDEF(CLI.Ins[I].VT));
+ if (!CLI.IsTailCall) {
+ for (unsigned I = 0, E = CLI.Ins.size(); I != E; ++I)
+ InVals.push_back(DAG.getUNDEF(CLI.Ins[I].VT));
+ }
return DAG.getEntryNode();
}
@@ -718,6 +848,7 @@ SDValue AMDGPUTargetLowering::LowerOperation(SDValue Op,
case ISD::FFLOOR: return LowerFFLOOR(Op, DAG);
case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG);
case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG);
+ case ISD::FP_TO_FP16: return LowerFP_TO_FP16(Op, DAG);
case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG);
case ISD::CTLZ:
@@ -745,94 +876,6 @@ void AMDGPUTargetLowering::ReplaceNodeResults(SDNode *N,
}
}
-// FIXME: This implements accesses to initialized globals in the constant
-// address space by copying them to private and accessing that. It does not
-// properly handle illegal types or vectors. The private vector loads are not
-// scalarized, and the illegal scalars hit an assertion. This technique will not
-// work well with large initializers, and this should eventually be
-// removed. Initialized globals should be placed into a data section that the
-// runtime will load into a buffer before the kernel is executed. Uses of the
-// global need to be replaced with a pointer loaded from an implicit kernel
-// argument into this buffer holding the copy of the data, which will remove the
-// need for any of this.
-SDValue AMDGPUTargetLowering::LowerConstantInitializer(const Constant* Init,
- const GlobalValue *GV,
- const SDValue &InitPtr,
- SDValue Chain,
- SelectionDAG &DAG) const {
- const DataLayout &TD = DAG.getDataLayout();
- SDLoc DL(InitPtr);
- Type *InitTy = Init->getType();
-
- if (const ConstantInt *CI = dyn_cast<ConstantInt>(Init)) {
- EVT VT = EVT::getEVT(InitTy);
- PointerType *PtrTy = PointerType::get(InitTy, AMDGPUAS::PRIVATE_ADDRESS);
- return DAG.getStore(Chain, DL, DAG.getConstant(*CI, DL, VT), InitPtr,
- MachinePointerInfo(UndefValue::get(PtrTy)),
- TD.getPrefTypeAlignment(InitTy));
- }
-
- if (const ConstantFP *CFP = dyn_cast<ConstantFP>(Init)) {
- EVT VT = EVT::getEVT(CFP->getType());
- PointerType *PtrTy = PointerType::get(CFP->getType(), 0);
- return DAG.getStore(Chain, DL, DAG.getConstantFP(*CFP, DL, VT), InitPtr,
- MachinePointerInfo(UndefValue::get(PtrTy)),
- TD.getPrefTypeAlignment(CFP->getType()));
- }
-
- if (StructType *ST = dyn_cast<StructType>(InitTy)) {
- const StructLayout *SL = TD.getStructLayout(ST);
-
- EVT PtrVT = InitPtr.getValueType();
- SmallVector<SDValue, 8> Chains;
-
- for (unsigned I = 0, N = ST->getNumElements(); I != N; ++I) {
- SDValue Offset = DAG.getConstant(SL->getElementOffset(I), DL, PtrVT);
- SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, InitPtr, Offset);
-
- Constant *Elt = Init->getAggregateElement(I);
- Chains.push_back(LowerConstantInitializer(Elt, GV, Ptr, Chain, DAG));
- }
-
- return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
- }
-
- if (SequentialType *SeqTy = dyn_cast<SequentialType>(InitTy)) {
- EVT PtrVT = InitPtr.getValueType();
-
- unsigned NumElements;
- if (ArrayType *AT = dyn_cast<ArrayType>(SeqTy))
- NumElements = AT->getNumElements();
- else if (VectorType *VT = dyn_cast<VectorType>(SeqTy))
- NumElements = VT->getNumElements();
- else
- llvm_unreachable("Unexpected type");
-
- unsigned EltSize = TD.getTypeAllocSize(SeqTy->getElementType());
- SmallVector<SDValue, 8> Chains;
- for (unsigned i = 0; i < NumElements; ++i) {
- SDValue Offset = DAG.getConstant(i * EltSize, DL, PtrVT);
- SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, InitPtr, Offset);
-
- Constant *Elt = Init->getAggregateElement(i);
- Chains.push_back(LowerConstantInitializer(Elt, GV, Ptr, Chain, DAG));
- }
-
- return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);
- }
-
- if (isa<UndefValue>(Init)) {
- EVT VT = EVT::getEVT(InitTy);
- PointerType *PtrTy = PointerType::get(InitTy, AMDGPUAS::PRIVATE_ADDRESS);
- return DAG.getStore(Chain, DL, DAG.getUNDEF(VT), InitPtr,
- MachinePointerInfo(UndefValue::get(PtrTy)),
- TD.getPrefTypeAlignment(InitTy));
- }
-
- Init->dump();
- llvm_unreachable("Unhandled constant initializer");
-}
-
static bool hasDefinedInitializer(const GlobalValue *GV) {
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
if (!GVar || !GVar->hasInitializer())
@@ -850,11 +893,6 @@ SDValue AMDGPUTargetLowering::LowerGlobalAddress(AMDGPUMachineFunction* MFI,
const GlobalValue *GV = G->getGlobal();
switch (G->getAddressSpace()) {
- case AMDGPUAS::CONSTANT_ADDRESS: {
- MVT ConstPtrVT = getPointerTy(DL, AMDGPUAS::CONSTANT_ADDRESS);
- SDValue GA = DAG.getTargetGlobalAddress(GV, SDLoc(G), ConstPtrVT);
- return DAG.getNode(AMDGPUISD::CONST_DATA_PTR, SDLoc(G), ConstPtrVT, GA);
- }
case AMDGPUAS::LOCAL_ADDRESS: {
// XXX: What does the value of G->getOffset() mean?
assert(G->getOffset() == 0 &&
@@ -864,24 +902,8 @@ SDValue AMDGPUTargetLowering::LowerGlobalAddress(AMDGPUMachineFunction* MFI,
if (hasDefinedInitializer(GV))
break;
- unsigned Offset;
- if (MFI->LocalMemoryObjects.count(GV) == 0) {
- unsigned Align = GV->getAlignment();
- if (Align == 0)
- Align = DL.getABITypeAlignment(GV->getValueType());
-
- /// TODO: We should sort these to minimize wasted space due to alignment
- /// padding. Currently the padding is decided by the first encountered use
- /// during lowering.
- Offset = MFI->LDSSize = alignTo(MFI->LDSSize, Align);
- MFI->LocalMemoryObjects[GV] = Offset;
- MFI->LDSSize += DL.getTypeAllocSize(GV->getValueType());
- } else {
- Offset = MFI->LocalMemoryObjects[GV];
- }
-
- return DAG.getConstant(Offset, SDLoc(Op),
- getPointerTy(DL, AMDGPUAS::LOCAL_ADDRESS));
+ unsigned Offset = MFI->allocateLDSGlobal(DL, *GV);
+ return DAG.getConstant(Offset, SDLoc(Op), Op.getValueType());
}
}
@@ -1097,65 +1119,6 @@ SDValue AMDGPUTargetLowering::SplitVectorLoad(const SDValue Op,
return DAG.getMergeValues(Ops, SL);
}
-// FIXME: This isn't doing anything for SI. This should be used in a target
-// combine during type legalization.
-SDValue AMDGPUTargetLowering::MergeVectorStore(const SDValue &Op,
- SelectionDAG &DAG) const {
- StoreSDNode *Store = cast<StoreSDNode>(Op);
- EVT MemVT = Store->getMemoryVT();
- unsigned MemBits = MemVT.getSizeInBits();
-
- // Byte stores are really expensive, so if possible, try to pack 32-bit vector
- // truncating store into an i32 store.
- // XXX: We could also handle optimize other vector bitwidths.
- if (!MemVT.isVector() || MemBits > 32) {
- return SDValue();
- }
-
- SDLoc DL(Op);
- SDValue Value = Store->getValue();
- EVT VT = Value.getValueType();
- EVT ElemVT = VT.getVectorElementType();
- SDValue Ptr = Store->getBasePtr();
- EVT MemEltVT = MemVT.getVectorElementType();
- unsigned MemEltBits = MemEltVT.getSizeInBits();
- unsigned MemNumElements = MemVT.getVectorNumElements();
- unsigned PackedSize = MemVT.getStoreSizeInBits();
- SDValue Mask = DAG.getConstant((1 << MemEltBits) - 1, DL, MVT::i32);
-
- assert(Value.getValueType().getScalarSizeInBits() >= 32);
-
- SDValue PackedValue;
- for (unsigned i = 0; i < MemNumElements; ++i) {
- SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ElemVT, Value,
- DAG.getConstant(i, DL, MVT::i32));
- Elt = DAG.getZExtOrTrunc(Elt, DL, MVT::i32);
- Elt = DAG.getNode(ISD::AND, DL, MVT::i32, Elt, Mask); // getZeroExtendInReg
-
- SDValue Shift = DAG.getConstant(MemEltBits * i, DL, MVT::i32);
- Elt = DAG.getNode(ISD::SHL, DL, MVT::i32, Elt, Shift);
-
- if (i == 0) {
- PackedValue = Elt;
- } else {
- PackedValue = DAG.getNode(ISD::OR, DL, MVT::i32, PackedValue, Elt);
- }
- }
-
- if (PackedSize < 32) {
- EVT PackedVT = EVT::getIntegerVT(*DAG.getContext(), PackedSize);
- return DAG.getTruncStore(Store->getChain(), DL, PackedValue, Ptr,
- Store->getMemOperand()->getPointerInfo(), PackedVT,
- Store->getAlignment(),
- Store->getMemOperand()->getFlags());
- }
-
- return DAG.getStore(Store->getChain(), DL, PackedValue, Ptr,
- Store->getMemOperand()->getPointerInfo(),
- Store->getAlignment(),
- Store->getMemOperand()->getFlags());
-}
-
SDValue AMDGPUTargetLowering::SplitVectorStore(SDValue Op,
SelectionDAG &DAG) const {
StoreSDNode *Store = cast<StoreSDNode>(Op);
@@ -1670,7 +1633,7 @@ SDValue AMDGPUTargetLowering::LowerFRINT(SDValue Op, SelectionDAG &DAG) const {
assert(Op.getValueType() == MVT::f64);
- APFloat C1Val(APFloat::IEEEdouble, "0x1.0p+52");
+ APFloat C1Val(APFloat::IEEEdouble(), "0x1.0p+52");
SDValue C1 = DAG.getConstantFP(C1Val, SL, MVT::f64);
SDValue CopySign = DAG.getNode(ISD::FCOPYSIGN, SL, MVT::f64, C1, Src);
@@ -1681,7 +1644,7 @@ SDValue AMDGPUTargetLowering::LowerFRINT(SDValue Op, SelectionDAG &DAG) const {
SDValue Fabs = DAG.getNode(ISD::FABS, SL, MVT::f64, Src);
- APFloat C2Val(APFloat::IEEEdouble, "0x1.fffffffffffffp+51");
+ APFloat C2Val(APFloat::IEEEdouble(), "0x1.fffffffffffffp+51");
SDValue C2 = DAG.getConstantFP(C2Val, SL, MVT::f64);
EVT SetCCVT =
@@ -1988,14 +1951,26 @@ SDValue AMDGPUTargetLowering::LowerUINT_TO_FP(SDValue Op,
assert(Op.getOperand(0).getValueType() == MVT::i64 &&
"operation should be legal");
+ // TODO: Factor out code common with LowerSINT_TO_FP.
+
EVT DestVT = Op.getValueType();
- if (DestVT == MVT::f64)
- return LowerINT_TO_FP64(Op, DAG, false);
+ if (Subtarget->has16BitInsts() && DestVT == MVT::f16) {
+ SDLoc DL(Op);
+ SDValue Src = Op.getOperand(0);
+
+ SDValue IntToFp32 = DAG.getNode(Op.getOpcode(), DL, MVT::f32, Src);
+ SDValue FPRoundFlag = DAG.getIntPtrConstant(0, SDLoc(Op));
+ SDValue FPRound =
+ DAG.getNode(ISD::FP_ROUND, DL, MVT::f16, IntToFp32, FPRoundFlag);
+
+ return FPRound;
+ }
if (DestVT == MVT::f32)
return LowerINT_TO_FP32(Op, DAG, false);
- return SDValue();
+ assert(DestVT == MVT::f64);
+ return LowerINT_TO_FP64(Op, DAG, false);
}
SDValue AMDGPUTargetLowering::LowerSINT_TO_FP(SDValue Op,
@@ -2003,14 +1978,26 @@ SDValue AMDGPUTargetLowering::LowerSINT_TO_FP(SDValue Op,
assert(Op.getOperand(0).getValueType() == MVT::i64 &&
"operation should be legal");
+ // TODO: Factor out code common with LowerUINT_TO_FP.
+
EVT DestVT = Op.getValueType();
+ if (Subtarget->has16BitInsts() && DestVT == MVT::f16) {
+ SDLoc DL(Op);
+ SDValue Src = Op.getOperand(0);
+
+ SDValue IntToFp32 = DAG.getNode(Op.getOpcode(), DL, MVT::f32, Src);
+ SDValue FPRoundFlag = DAG.getIntPtrConstant(0, SDLoc(Op));
+ SDValue FPRound =
+ DAG.getNode(ISD::FP_ROUND, DL, MVT::f16, IntToFp32, FPRoundFlag);
+
+ return FPRound;
+ }
+
if (DestVT == MVT::f32)
return LowerINT_TO_FP32(Op, DAG, true);
- if (DestVT == MVT::f64)
- return LowerINT_TO_FP64(Op, DAG, true);
-
- return SDValue();
+ assert(DestVT == MVT::f64);
+ return LowerINT_TO_FP64(Op, DAG, true);
}
SDValue AMDGPUTargetLowering::LowerFP64_TO_INT(SDValue Op, SelectionDAG &DAG,
@@ -2042,10 +2029,118 @@ SDValue AMDGPUTargetLowering::LowerFP64_TO_INT(SDValue Op, SelectionDAG &DAG,
return DAG.getNode(ISD::BITCAST, SL, MVT::i64, Result);
}
+SDValue AMDGPUTargetLowering::LowerFP_TO_FP16(SDValue Op, SelectionDAG &DAG) const {
+
+ if (getTargetMachine().Options.UnsafeFPMath) {
+ // There is a generic expand for FP_TO_FP16 with unsafe fast math.
+ return SDValue();
+ }
+
+ SDLoc DL(Op);
+ SDValue N0 = Op.getOperand(0);
+ assert (N0.getSimpleValueType() == MVT::f64);
+
+ // f64 -> f16 conversion using round-to-nearest-even rounding mode.
+ const unsigned ExpMask = 0x7ff;
+ const unsigned ExpBiasf64 = 1023;
+ const unsigned ExpBiasf16 = 15;
+ SDValue Zero = DAG.getConstant(0, DL, MVT::i32);
+ SDValue One = DAG.getConstant(1, DL, MVT::i32);
+ SDValue U = DAG.getNode(ISD::BITCAST, DL, MVT::i64, N0);
+ SDValue UH = DAG.getNode(ISD::SRL, DL, MVT::i64, U,
+ DAG.getConstant(32, DL, MVT::i64));
+ UH = DAG.getZExtOrTrunc(UH, DL, MVT::i32);
+ U = DAG.getZExtOrTrunc(U, DL, MVT::i32);
+ SDValue E = DAG.getNode(ISD::SRL, DL, MVT::i32, UH,
+ DAG.getConstant(20, DL, MVT::i64));
+ E = DAG.getNode(ISD::AND, DL, MVT::i32, E,
+ DAG.getConstant(ExpMask, DL, MVT::i32));
+ // Subtract the fp64 exponent bias (1023) to get the real exponent and
+ // add the f16 bias (15) to get the biased exponent for the f16 format.
+ E = DAG.getNode(ISD::ADD, DL, MVT::i32, E,
+ DAG.getConstant(-ExpBiasf64 + ExpBiasf16, DL, MVT::i32));
+
+ SDValue M = DAG.getNode(ISD::SRL, DL, MVT::i32, UH,
+ DAG.getConstant(8, DL, MVT::i32));
+ M = DAG.getNode(ISD::AND, DL, MVT::i32, M,
+ DAG.getConstant(0xffe, DL, MVT::i32));
+
+ SDValue MaskedSig = DAG.getNode(ISD::AND, DL, MVT::i32, UH,
+ DAG.getConstant(0x1ff, DL, MVT::i32));
+ MaskedSig = DAG.getNode(ISD::OR, DL, MVT::i32, MaskedSig, U);
+
+ SDValue Lo40Set = DAG.getSelectCC(DL, MaskedSig, Zero, Zero, One, ISD::SETEQ);
+ M = DAG.getNode(ISD::OR, DL, MVT::i32, M, Lo40Set);
+
+ // (M != 0 ? 0x0200 : 0) | 0x7c00;
+ SDValue I = DAG.getNode(ISD::OR, DL, MVT::i32,
+ DAG.getSelectCC(DL, M, Zero, DAG.getConstant(0x0200, DL, MVT::i32),
+ Zero, ISD::SETNE), DAG.getConstant(0x7c00, DL, MVT::i32));
+
+ // N = M | (E << 12);
+ SDValue N = DAG.getNode(ISD::OR, DL, MVT::i32, M,
+ DAG.getNode(ISD::SHL, DL, MVT::i32, E,
+ DAG.getConstant(12, DL, MVT::i32)));
+
+ // B = clamp(1-E, 0, 13);
+ SDValue OneSubExp = DAG.getNode(ISD::SUB, DL, MVT::i32,
+ One, E);
+ SDValue B = DAG.getNode(ISD::SMAX, DL, MVT::i32, OneSubExp, Zero);
+ B = DAG.getNode(ISD::SMIN, DL, MVT::i32, B,
+ DAG.getConstant(13, DL, MVT::i32));
+
+ SDValue SigSetHigh = DAG.getNode(ISD::OR, DL, MVT::i32, M,
+ DAG.getConstant(0x1000, DL, MVT::i32));
+
+ SDValue D = DAG.getNode(ISD::SRL, DL, MVT::i32, SigSetHigh, B);
+ SDValue D0 = DAG.getNode(ISD::SHL, DL, MVT::i32, D, B);
+ SDValue D1 = DAG.getSelectCC(DL, D0, SigSetHigh, One, Zero, ISD::SETNE);
+ D = DAG.getNode(ISD::OR, DL, MVT::i32, D, D1);
+
+ SDValue V = DAG.getSelectCC(DL, E, One, D, N, ISD::SETLT);
+ SDValue VLow3 = DAG.getNode(ISD::AND, DL, MVT::i32, V,
+ DAG.getConstant(0x7, DL, MVT::i32));
+ V = DAG.getNode(ISD::SRL, DL, MVT::i32, V,
+ DAG.getConstant(2, DL, MVT::i32));
+ SDValue V0 = DAG.getSelectCC(DL, VLow3, DAG.getConstant(3, DL, MVT::i32),
+ One, Zero, ISD::SETEQ);
+ SDValue V1 = DAG.getSelectCC(DL, VLow3, DAG.getConstant(5, DL, MVT::i32),
+ One, Zero, ISD::SETGT);
+ V1 = DAG.getNode(ISD::OR, DL, MVT::i32, V0, V1);
+ V = DAG.getNode(ISD::ADD, DL, MVT::i32, V, V1);
+
+ V = DAG.getSelectCC(DL, E, DAG.getConstant(30, DL, MVT::i32),
+ DAG.getConstant(0x7c00, DL, MVT::i32), V, ISD::SETGT);
+ V = DAG.getSelectCC(DL, E, DAG.getConstant(1039, DL, MVT::i32),
+ I, V, ISD::SETEQ);
+
+ // Extract the sign bit.
+ SDValue Sign = DAG.getNode(ISD::SRL, DL, MVT::i32, UH,
+ DAG.getConstant(16, DL, MVT::i32));
+ Sign = DAG.getNode(ISD::AND, DL, MVT::i32, Sign,
+ DAG.getConstant(0x8000, DL, MVT::i32));
+
+ V = DAG.getNode(ISD::OR, DL, MVT::i32, Sign, V);
+ return DAG.getZExtOrTrunc(V, DL, Op.getValueType());
+}
+
SDValue AMDGPUTargetLowering::LowerFP_TO_SINT(SDValue Op,
SelectionDAG &DAG) const {
SDValue Src = Op.getOperand(0);
+ // TODO: Factor out code common with LowerFP_TO_UINT.
+
+ EVT SrcVT = Src.getValueType();
+ if (Subtarget->has16BitInsts() && SrcVT == MVT::f16) {
+ SDLoc DL(Op);
+
+ SDValue FPExtend = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
+ SDValue FpToInt32 =
+ DAG.getNode(Op.getOpcode(), DL, MVT::i64, FPExtend);
+
+ return FpToInt32;
+ }
+
if (Op.getValueType() == MVT::i64 && Src.getValueType() == MVT::f64)
return LowerFP64_TO_INT(Op, DAG, true);
@@ -2056,6 +2151,19 @@ SDValue AMDGPUTargetLowering::LowerFP_TO_UINT(SDValue Op,
SelectionDAG &DAG) const {
SDValue Src = Op.getOperand(0);
+ // TODO: Factor out code common with LowerFP_TO_SINT.
+
+ EVT SrcVT = Src.getValueType();
+ if (Subtarget->has16BitInsts() && SrcVT == MVT::f16) {
+ SDLoc DL(Op);
+
+ SDValue FPExtend = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, Src);
+ SDValue FpToInt32 =
+ DAG.getNode(Op.getOpcode(), DL, MVT::i64, FPExtend);
+
+ return FpToInt32;
+ }
+
if (Op.getValueType() == MVT::i64 && Src.getValueType() == MVT::f64)
return LowerFP64_TO_INT(Op, DAG, false);
@@ -2068,8 +2176,7 @@ SDValue AMDGPUTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
MVT VT = Op.getSimpleValueType();
MVT ScalarVT = VT.getScalarType();
- if (!VT.isVector())
- return SDValue();
+ assert(VT.isVector());
SDValue Src = Op.getOperand(0);
SDLoc DL(Op);
@@ -2108,17 +2215,20 @@ static bool isI24(SDValue Op, SelectionDAG &DAG) {
(VT.getSizeInBits() - DAG.ComputeNumSignBits(Op)) < 24;
}
-static void simplifyI24(SDValue Op, TargetLowering::DAGCombinerInfo &DCI) {
+static bool simplifyI24(SDNode *Node24, unsigned OpIdx,
+ TargetLowering::DAGCombinerInfo &DCI) {
SelectionDAG &DAG = DCI.DAG;
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ SDValue Op = Node24->getOperand(OpIdx);
EVT VT = Op.getValueType();
APInt Demanded = APInt::getLowBitsSet(VT.getSizeInBits(), 24);
APInt KnownZero, KnownOne;
TargetLowering::TargetLoweringOpt TLO(DAG, true, true);
- if (TLI.SimplifyDemandedBits(Op, Demanded, KnownZero, KnownOne, TLO))
- DCI.CommitTargetLoweringOpt(TLO);
+ if (TLO.SimplifyDemandedBits(Node24, OpIdx, Demanded, DCI))
+ return true;
+
+ return false;
}
template <typename IntTy>
@@ -2188,6 +2298,9 @@ SDValue AMDGPUTargetLowering::performLoadCombine(SDNode *N,
// problems during legalization, the emitted instructions to pack and unpack
// the bytes again are not eliminated in the case of an unaligned copy.
if (!allowsMisalignedMemoryAccesses(VT, AS, Align, &IsFast)) {
+ if (VT.isVector())
+ return scalarizeVectorLoad(LN, DAG);
+
SDValue Ops[2];
std::tie(Ops[0], Ops[1]) = expandUnalignedLoad(LN, DAG);
return DAG.getMergeValues(Ops, SDLoc(N));
@@ -2236,8 +2349,12 @@ SDValue AMDGPUTargetLowering::performStoreCombine(SDNode *N,
// order problems during legalization, the emitted instructions to pack and
// unpack the bytes again are not eliminated in the case of an unaligned
// copy.
- if (!allowsMisalignedMemoryAccesses(VT, AS, Align, &IsFast))
+ if (!allowsMisalignedMemoryAccesses(VT, AS, Align, &IsFast)) {
+ if (VT.isVector())
+ return scalarizeVectorStore(SN, DAG);
+
return expandUnalignedStore(SN, DAG);
+ }
if (!IsFast)
return SDValue();
@@ -2262,38 +2379,21 @@ SDValue AMDGPUTargetLowering::performStoreCombine(SDNode *N,
SN->getBasePtr(), SN->getMemOperand());
}
-// TODO: Should repeat for other bit ops.
-SDValue AMDGPUTargetLowering::performAndCombine(SDNode *N,
- DAGCombinerInfo &DCI) const {
- if (N->getValueType(0) != MVT::i64)
- return SDValue();
-
- // Break up 64-bit and of a constant into two 32-bit ands. This will typically
- // happen anyway for a VALU 64-bit and. This exposes other 32-bit integer
- // combine opportunities since most 64-bit operations are decomposed this way.
- // TODO: We won't want this for SALU especially if it is an inline immediate.
- const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1));
- if (!RHS)
- return SDValue();
-
- uint64_t Val = RHS->getZExtValue();
- if (Lo_32(Val) != 0 && Hi_32(Val) != 0 && !RHS->hasOneUse()) {
- // If either half of the constant is 0, this is really a 32-bit and, so
- // split it. If we can re-use the full materialized constant, keep it.
- return SDValue();
- }
-
- SDLoc SL(N);
+/// Split the 64-bit value \p LHS into two 32-bit components, and perform the
+/// binary operation \p Opc to it with the corresponding constant operands.
+SDValue AMDGPUTargetLowering::splitBinaryBitConstantOpImpl(
+ DAGCombinerInfo &DCI, const SDLoc &SL,
+ unsigned Opc, SDValue LHS,
+ uint32_t ValLo, uint32_t ValHi) const {
SelectionDAG &DAG = DCI.DAG;
-
SDValue Lo, Hi;
- std::tie(Lo, Hi) = split64BitValue(N->getOperand(0), DAG);
+ std::tie(Lo, Hi) = split64BitValue(LHS, DAG);
- SDValue LoRHS = DAG.getConstant(Lo_32(Val), SL, MVT::i32);
- SDValue HiRHS = DAG.getConstant(Hi_32(Val), SL, MVT::i32);
+ SDValue LoRHS = DAG.getConstant(ValLo, SL, MVT::i32);
+ SDValue HiRHS = DAG.getConstant(ValHi, SL, MVT::i32);
- SDValue LoAnd = DAG.getNode(ISD::AND, SL, MVT::i32, Lo, LoRHS);
- SDValue HiAnd = DAG.getNode(ISD::AND, SL, MVT::i32, Hi, HiRHS);
+ SDValue LoAnd = DAG.getNode(Opc, SL, MVT::i32, Lo, LoRHS);
+ SDValue HiAnd = DAG.getNode(Opc, SL, MVT::i32, Hi, HiRHS);
// Re-visit the ands. It's possible we eliminated one of them and it could
// simplify the vector.
@@ -2408,11 +2508,40 @@ SDValue AMDGPUTargetLowering::performSrlCombine(SDNode *N,
return DAG.getNode(ISD::BITCAST, SL, MVT::i64, BuildPair);
}
+// We need to specifically handle i64 mul here to avoid unnecessary conversion
+// instructions. If we only match on the legalized i64 mul expansion,
+// SimplifyDemandedBits will be unable to remove them because there will be
+// multiple uses due to the separate mul + mulh[su].
+static SDValue getMul24(SelectionDAG &DAG, const SDLoc &SL,
+ SDValue N0, SDValue N1, unsigned Size, bool Signed) {
+ if (Size <= 32) {
+ unsigned MulOpc = Signed ? AMDGPUISD::MUL_I24 : AMDGPUISD::MUL_U24;
+ return DAG.getNode(MulOpc, SL, MVT::i32, N0, N1);
+ }
+
+ // Because we want to eliminate extension instructions before the
+ // operation, we need to create a single user here (i.e. not the separate
+ // mul_lo + mul_hi) so that SimplifyDemandedBits will deal with it.
+
+ unsigned MulOpc = Signed ? AMDGPUISD::MUL_LOHI_I24 : AMDGPUISD::MUL_LOHI_U24;
+
+ SDValue Mul = DAG.getNode(MulOpc, SL,
+ DAG.getVTList(MVT::i32, MVT::i32), N0, N1);
+
+ return DAG.getNode(ISD::BUILD_PAIR, SL, MVT::i64,
+ Mul.getValue(0), Mul.getValue(1));
+}
+
SDValue AMDGPUTargetLowering::performMulCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
EVT VT = N->getValueType(0);
- if (VT.isVector() || VT.getSizeInBits() > 32)
+ unsigned Size = VT.getSizeInBits();
+ if (VT.isVector() || Size > 64)
+ return SDValue();
+
+ // There are i16 integer mul/mad.
+ if (Subtarget->has16BitInsts() && VT.getScalarType().bitsLE(MVT::i16))
return SDValue();
SelectionDAG &DAG = DCI.DAG;
@@ -2425,11 +2554,11 @@ SDValue AMDGPUTargetLowering::performMulCombine(SDNode *N,
if (Subtarget->hasMulU24() && isU24(N0, DAG) && isU24(N1, DAG)) {
N0 = DAG.getZExtOrTrunc(N0, DL, MVT::i32);
N1 = DAG.getZExtOrTrunc(N1, DL, MVT::i32);
- Mul = DAG.getNode(AMDGPUISD::MUL_U24, DL, MVT::i32, N0, N1);
+ Mul = getMul24(DAG, DL, N0, N1, Size, false);
} else if (Subtarget->hasMulI24() && isI24(N0, DAG) && isI24(N1, DAG)) {
N0 = DAG.getSExtOrTrunc(N0, DL, MVT::i32);
N1 = DAG.getSExtOrTrunc(N1, DL, MVT::i32);
- Mul = DAG.getNode(AMDGPUISD::MUL_I24, DL, MVT::i32, N0, N1);
+ Mul = getMul24(DAG, DL, N0, N1, Size, true);
} else {
return SDValue();
}
@@ -2439,6 +2568,77 @@ SDValue AMDGPUTargetLowering::performMulCombine(SDNode *N,
return DAG.getSExtOrTrunc(Mul, DL, VT);
}
+SDValue AMDGPUTargetLowering::performMulhsCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ EVT VT = N->getValueType(0);
+
+ if (!Subtarget->hasMulI24() || VT.isVector())
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
+
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+
+ if (!isI24(N0, DAG) || !isI24(N1, DAG))
+ return SDValue();
+
+ N0 = DAG.getSExtOrTrunc(N0, DL, MVT::i32);
+ N1 = DAG.getSExtOrTrunc(N1, DL, MVT::i32);
+
+ SDValue Mulhi = DAG.getNode(AMDGPUISD::MULHI_I24, DL, MVT::i32, N0, N1);
+ DCI.AddToWorklist(Mulhi.getNode());
+ return DAG.getSExtOrTrunc(Mulhi, DL, VT);
+}
+
+SDValue AMDGPUTargetLowering::performMulhuCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ EVT VT = N->getValueType(0);
+
+ if (!Subtarget->hasMulU24() || VT.isVector() || VT.getSizeInBits() > 32)
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
+
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+
+ if (!isU24(N0, DAG) || !isU24(N1, DAG))
+ return SDValue();
+
+ N0 = DAG.getZExtOrTrunc(N0, DL, MVT::i32);
+ N1 = DAG.getZExtOrTrunc(N1, DL, MVT::i32);
+
+ SDValue Mulhi = DAG.getNode(AMDGPUISD::MULHI_U24, DL, MVT::i32, N0, N1);
+ DCI.AddToWorklist(Mulhi.getNode());
+ return DAG.getZExtOrTrunc(Mulhi, DL, VT);
+}
+
+SDValue AMDGPUTargetLowering::performMulLoHi24Combine(
+ SDNode *N, DAGCombinerInfo &DCI) const {
+ SelectionDAG &DAG = DCI.DAG;
+
+ // Simplify demanded bits before splitting into multiple users.
+ if (simplifyI24(N, 0, DCI) || simplifyI24(N, 1, DCI))
+ return SDValue();
+
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+
+ bool Signed = (N->getOpcode() == AMDGPUISD::MUL_LOHI_I24);
+
+ unsigned MulLoOpc = Signed ? AMDGPUISD::MUL_I24 : AMDGPUISD::MUL_U24;
+ unsigned MulHiOpc = Signed ? AMDGPUISD::MULHI_I24 : AMDGPUISD::MULHI_U24;
+
+ SDLoc SL(N);
+
+ SDValue MulLo = DAG.getNode(MulLoOpc, SL, MVT::i32, N0, N1);
+ SDValue MulHi = DAG.getNode(MulHiOpc, SL, MVT::i32, N0, N1);
+ return DAG.getMergeValues({ MulLo, MulHi }, SL);
+}
+
static bool isNegativeOne(SDValue Val) {
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val))
return C->isAllOnesValue();
@@ -2449,23 +2649,21 @@ static bool isCtlzOpc(unsigned Opc) {
return Opc == ISD::CTLZ || Opc == ISD::CTLZ_ZERO_UNDEF;
}
-// Get FFBH node if the incoming op may have been type legalized from a smaller
-// type VT.
-// Need to match pre-legalized type because the generic legalization inserts the
-// add/sub between the select and compare.
-static SDValue getFFBH_U32(const TargetLowering &TLI, SelectionDAG &DAG,
- const SDLoc &SL, SDValue Op) {
+SDValue AMDGPUTargetLowering::getFFBH_U32(SelectionDAG &DAG,
+ SDValue Op,
+ const SDLoc &DL) const {
EVT VT = Op.getValueType();
- EVT LegalVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
- if (LegalVT != MVT::i32)
+ EVT LegalVT = getTypeToTransformTo(*DAG.getContext(), VT);
+ if (LegalVT != MVT::i32 && (Subtarget->has16BitInsts() &&
+ LegalVT != MVT::i16))
return SDValue();
if (VT != MVT::i32)
- Op = DAG.getNode(ISD::ZERO_EXTEND, SL, MVT::i32, Op);
+ Op = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i32, Op);
- SDValue FFBH = DAG.getNode(AMDGPUISD::FFBH_U32, SL, MVT::i32, Op);
+ SDValue FFBH = DAG.getNode(AMDGPUISD::FFBH_U32, DL, MVT::i32, Op);
if (VT != MVT::i32)
- FFBH = DAG.getNode(ISD::TRUNCATE, SL, VT, FFBH);
+ FFBH = DAG.getNode(ISD::TRUNCATE, DL, VT, FFBH);
return FFBH;
}
@@ -2493,7 +2691,7 @@ SDValue AMDGPUTargetLowering::performCtlzCombine(const SDLoc &SL, SDValue Cond,
isCtlzOpc(RHS.getOpcode()) &&
RHS.getOperand(0) == CmpLHS &&
isNegativeOne(LHS)) {
- return getFFBH_U32(*this, DAG, SL, CmpLHS);
+ return getFFBH_U32(DAG, CmpLHS, SL);
}
// select (setcc x, 0, ne), (ctlz_zero_undef x), -1 -> ffbh_u32 x
@@ -2501,14 +2699,99 @@ SDValue AMDGPUTargetLowering::performCtlzCombine(const SDLoc &SL, SDValue Cond,
isCtlzOpc(LHS.getOpcode()) &&
LHS.getOperand(0) == CmpLHS &&
isNegativeOne(RHS)) {
- return getFFBH_U32(*this, DAG, SL, CmpLHS);
+ return getFFBH_U32(DAG, CmpLHS, SL);
+ }
+
+ return SDValue();
+}
+
+static SDValue distributeOpThroughSelect(TargetLowering::DAGCombinerInfo &DCI,
+ unsigned Op,
+ const SDLoc &SL,
+ SDValue Cond,
+ SDValue N1,
+ SDValue N2) {
+ SelectionDAG &DAG = DCI.DAG;
+ EVT VT = N1.getValueType();
+
+ SDValue NewSelect = DAG.getNode(ISD::SELECT, SL, VT, Cond,
+ N1.getOperand(0), N2.getOperand(0));
+ DCI.AddToWorklist(NewSelect.getNode());
+ return DAG.getNode(Op, SL, VT, NewSelect);
+}
+
+// Pull a free FP operation out of a select so it may fold into uses.
+//
+// select c, (fneg x), (fneg y) -> fneg (select c, x, y)
+// select c, (fneg x), k -> fneg (select c, x, (fneg k))
+//
+// select c, (fabs x), (fabs y) -> fabs (select c, x, y)
+// select c, (fabs x), +k -> fabs (select c, x, k)
+static SDValue foldFreeOpFromSelect(TargetLowering::DAGCombinerInfo &DCI,
+ SDValue N) {
+ SelectionDAG &DAG = DCI.DAG;
+ SDValue Cond = N.getOperand(0);
+ SDValue LHS = N.getOperand(1);
+ SDValue RHS = N.getOperand(2);
+
+ EVT VT = N.getValueType();
+ if ((LHS.getOpcode() == ISD::FABS && RHS.getOpcode() == ISD::FABS) ||
+ (LHS.getOpcode() == ISD::FNEG && RHS.getOpcode() == ISD::FNEG)) {
+ return distributeOpThroughSelect(DCI, LHS.getOpcode(),
+ SDLoc(N), Cond, LHS, RHS);
+ }
+
+ bool Inv = false;
+ if (RHS.getOpcode() == ISD::FABS || RHS.getOpcode() == ISD::FNEG) {
+ std::swap(LHS, RHS);
+ Inv = true;
+ }
+
+ // TODO: Support vector constants.
+ ConstantFPSDNode *CRHS = dyn_cast<ConstantFPSDNode>(RHS);
+ if ((LHS.getOpcode() == ISD::FNEG || LHS.getOpcode() == ISD::FABS) && CRHS) {
+ SDLoc SL(N);
+ // If one side is an fneg/fabs and the other is a constant, we can push the
+ // fneg/fabs down. If it's an fabs, the constant needs to be non-negative.
+ SDValue NewLHS = LHS.getOperand(0);
+ SDValue NewRHS = RHS;
+
+ // Careful: if the neg can be folded up, don't try to pull it back down.
+ bool ShouldFoldNeg = true;
+
+ if (NewLHS.hasOneUse()) {
+ unsigned Opc = NewLHS.getOpcode();
+ if (LHS.getOpcode() == ISD::FNEG && fnegFoldsIntoOp(Opc))
+ ShouldFoldNeg = false;
+ if (LHS.getOpcode() == ISD::FABS && Opc == ISD::FMUL)
+ ShouldFoldNeg = false;
+ }
+
+ if (ShouldFoldNeg) {
+ if (LHS.getOpcode() == ISD::FNEG)
+ NewRHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);
+ else if (CRHS->isNegative())
+ return SDValue();
+
+ if (Inv)
+ std::swap(NewLHS, NewRHS);
+
+ SDValue NewSelect = DAG.getNode(ISD::SELECT, SL, VT,
+ Cond, NewLHS, NewRHS);
+ DCI.AddToWorklist(NewSelect.getNode());
+ return DAG.getNode(LHS.getOpcode(), SL, VT, NewSelect);
+ }
}
return SDValue();
}
+
SDValue AMDGPUTargetLowering::performSelectCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
+ if (SDValue Folded = foldFreeOpFromSelect(DCI, SDValue(N, 0)))
+ return Folded;
+
SDValue Cond = N->getOperand(0);
if (Cond.getOpcode() != ISD::SETCC)
return SDValue();
@@ -2521,6 +2804,25 @@ SDValue AMDGPUTargetLowering::performSelectCombine(SDNode *N,
SDValue True = N->getOperand(1);
SDValue False = N->getOperand(2);
+ if (Cond.hasOneUse()) { // TODO: Look for multiple select uses.
+ SelectionDAG &DAG = DCI.DAG;
+ if ((DAG.isConstantValueOfAnyType(True) ||
+ DAG.isConstantValueOfAnyType(True)) &&
+ (!DAG.isConstantValueOfAnyType(False) &&
+ !DAG.isConstantValueOfAnyType(False))) {
+ // Swap cmp + select pair to move constant to false input.
+ // This will allow using VOPC cndmasks more often.
+ // select (setcc x, y), k, x -> select (setcc y, x) x, x
+
+ SDLoc SL(N);
+ ISD::CondCode NewCC = getSetCCInverse(cast<CondCodeSDNode>(CC)->get(),
+ LHS.getValueType().isInteger());
+
+ SDValue NewCond = DAG.getSetCC(SL, Cond.getValueType(), LHS, RHS, NewCC);
+ return DAG.getNode(ISD::SELECT, SL, VT, NewCond, False, True);
+ }
+ }
+
if (VT == MVT::f32 && Cond.hasOneUse()) {
SDValue MinMax
= CombineFMinMaxLegacy(SDLoc(N), VT, LHS, RHS, True, False, CC, DCI);
@@ -2533,6 +2835,135 @@ SDValue AMDGPUTargetLowering::performSelectCombine(SDNode *N,
return performCtlzCombine(SDLoc(N), Cond, True, False, DCI);
}
+SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ SelectionDAG &DAG = DCI.DAG;
+ SDValue N0 = N->getOperand(0);
+ EVT VT = N->getValueType(0);
+
+ unsigned Opc = N0.getOpcode();
+
+ // If the input has multiple uses and we can either fold the negate down, or
+ // the other uses cannot, give up. This both prevents unprofitable
+ // transformations and infinite loops: we won't repeatedly try to fold around
+ // a negate that has no 'good' form.
+ //
+ // TODO: Check users can fold
+ if (fnegFoldsIntoOp(Opc) && !N0.hasOneUse())
+ return SDValue();
+
+ SDLoc SL(N);
+ switch (Opc) {
+ case ISD::FADD: {
+ if (!mayIgnoreSignedZero(N0))
+ return SDValue();
+
+ // (fneg (fadd x, y)) -> (fadd (fneg x), (fneg y))
+ SDValue LHS = N0.getOperand(0);
+ SDValue RHS = N0.getOperand(1);
+
+ if (LHS.getOpcode() != ISD::FNEG)
+ LHS = DAG.getNode(ISD::FNEG, SL, VT, LHS);
+ else
+ LHS = LHS.getOperand(0);
+
+ if (RHS.getOpcode() != ISD::FNEG)
+ RHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);
+ else
+ RHS = RHS.getOperand(0);
+
+ SDValue Res = DAG.getNode(ISD::FADD, SL, VT, LHS, RHS);
+ if (!N0.hasOneUse())
+ DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res));
+ return Res;
+ }
+ case ISD::FMUL:
+ case AMDGPUISD::FMUL_LEGACY: {
+ // (fneg (fmul x, y)) -> (fmul x, (fneg y))
+ // (fneg (fmul_legacy x, y)) -> (fmul_legacy x, (fneg y))
+ SDValue LHS = N0.getOperand(0);
+ SDValue RHS = N0.getOperand(1);
+
+ if (LHS.getOpcode() == ISD::FNEG)
+ LHS = LHS.getOperand(0);
+ else if (RHS.getOpcode() == ISD::FNEG)
+ RHS = RHS.getOperand(0);
+ else
+ RHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);
+
+ SDValue Res = DAG.getNode(Opc, SL, VT, LHS, RHS);
+ if (!N0.hasOneUse())
+ DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res));
+ return Res;
+ }
+ case ISD::FMA:
+ case ISD::FMAD: {
+ if (!mayIgnoreSignedZero(N0))
+ return SDValue();
+
+ // (fneg (fma x, y, z)) -> (fma x, (fneg y), (fneg z))
+ SDValue LHS = N0.getOperand(0);
+ SDValue MHS = N0.getOperand(1);
+ SDValue RHS = N0.getOperand(2);
+
+ if (LHS.getOpcode() == ISD::FNEG)
+ LHS = LHS.getOperand(0);
+ else if (MHS.getOpcode() == ISD::FNEG)
+ MHS = MHS.getOperand(0);
+ else
+ MHS = DAG.getNode(ISD::FNEG, SL, VT, MHS);
+
+ if (RHS.getOpcode() != ISD::FNEG)
+ RHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);
+ else
+ RHS = RHS.getOperand(0);
+
+ SDValue Res = DAG.getNode(Opc, SL, VT, LHS, MHS, RHS);
+ if (!N0.hasOneUse())
+ DAG.ReplaceAllUsesWith(N0, DAG.getNode(ISD::FNEG, SL, VT, Res));
+ return Res;
+ }
+ case ISD::FP_EXTEND:
+ case AMDGPUISD::RCP:
+ case AMDGPUISD::RCP_LEGACY:
+ case ISD::FSIN:
+ case AMDGPUISD::SIN_HW: {
+ SDValue CvtSrc = N0.getOperand(0);
+ if (CvtSrc.getOpcode() == ISD::FNEG) {
+ // (fneg (fp_extend (fneg x))) -> (fp_extend x)
+ // (fneg (rcp (fneg x))) -> (rcp x)
+ return DAG.getNode(Opc, SL, VT, CvtSrc.getOperand(0));
+ }
+
+ if (!N0.hasOneUse())
+ return SDValue();
+
+ // (fneg (fp_extend x)) -> (fp_extend (fneg x))
+ // (fneg (rcp x)) -> (rcp (fneg x))
+ SDValue Neg = DAG.getNode(ISD::FNEG, SL, CvtSrc.getValueType(), CvtSrc);
+ return DAG.getNode(Opc, SL, VT, Neg);
+ }
+ case ISD::FP_ROUND: {
+ SDValue CvtSrc = N0.getOperand(0);
+
+ if (CvtSrc.getOpcode() == ISD::FNEG) {
+ // (fneg (fp_round (fneg x))) -> (fp_round x)
+ return DAG.getNode(ISD::FP_ROUND, SL, VT,
+ CvtSrc.getOperand(0), N0.getOperand(1));
+ }
+
+ if (!N0.hasOneUse())
+ return SDValue();
+
+ // (fneg (fp_round x)) -> (fp_round (fneg x))
+ SDValue Neg = DAG.getNode(ISD::FNEG, SL, CvtSrc.getValueType(), CvtSrc);
+ return DAG.getNode(ISD::FP_ROUND, SL, VT, Neg, N0.getOperand(1));
+ }
+ default:
+ return SDValue();
+ }
+}
+
SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
@@ -2543,6 +2974,33 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
break;
case ISD::BITCAST: {
EVT DestVT = N->getValueType(0);
+
+ // Push casts through vector builds. This helps avoid emitting a large
+ // number of copies when materializing floating point vector constants.
+ //
+ // vNt1 bitcast (vNt0 (build_vector t0:x, t0:y)) =>
+ // vnt1 = build_vector (t1 (bitcast t0:x)), (t1 (bitcast t0:y))
+ if (DestVT.isVector()) {
+ SDValue Src = N->getOperand(0);
+ if (Src.getOpcode() == ISD::BUILD_VECTOR) {
+ EVT SrcVT = Src.getValueType();
+ unsigned NElts = DestVT.getVectorNumElements();
+
+ if (SrcVT.getVectorNumElements() == NElts) {
+ EVT DestEltVT = DestVT.getVectorElementType();
+
+ SmallVector<SDValue, 8> CastedElts;
+ SDLoc SL(N);
+ for (unsigned I = 0, E = SrcVT.getVectorNumElements(); I != E; ++I) {
+ SDValue Elt = Src.getOperand(I);
+ CastedElts.push_back(DAG.getNode(ISD::BITCAST, DL, DestEltVT, Elt));
+ }
+
+ return DAG.getBuildVector(DestVT, SL, CastedElts);
+ }
+ }
+ }
+
if (DestVT.getSizeInBits() != 64 && !DestVT.isVector())
break;
@@ -2591,24 +3049,28 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
return performSraCombine(N, DCI);
}
- case ISD::AND: {
- if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
- break;
-
- return performAndCombine(N, DCI);
- }
case ISD::MUL:
return performMulCombine(N, DCI);
+ case ISD::MULHS:
+ return performMulhsCombine(N, DCI);
+ case ISD::MULHU:
+ return performMulhuCombine(N, DCI);
case AMDGPUISD::MUL_I24:
- case AMDGPUISD::MUL_U24: {
- SDValue N0 = N->getOperand(0);
- SDValue N1 = N->getOperand(1);
- simplifyI24(N0, DCI);
- simplifyI24(N1, DCI);
+ case AMDGPUISD::MUL_U24:
+ case AMDGPUISD::MULHI_I24:
+ case AMDGPUISD::MULHI_U24: {
+ // If the first call to simplify is successfull, then N may end up being
+ // deleted, so we shouldn't call simplifyI24 again.
+ simplifyI24(N, 0, DCI) || simplifyI24(N, 1, DCI);
return SDValue();
}
+ case AMDGPUISD::MUL_LOHI_I24:
+ case AMDGPUISD::MUL_LOHI_U24:
+ return performMulLoHi24Combine(N, DCI);
case ISD::SELECT:
return performSelectCombine(N, DCI);
+ case ISD::FNEG:
+ return performFNegCombine(N, DCI);
case AMDGPUISD::BFE_I32:
case AMDGPUISD::BFE_U32: {
assert(!N->getValueType(0).isVector() &&
@@ -2705,38 +3167,6 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N,
// Helper functions
//===----------------------------------------------------------------------===//
-void AMDGPUTargetLowering::getOriginalFunctionArgs(
- SelectionDAG &DAG,
- const Function *F,
- const SmallVectorImpl<ISD::InputArg> &Ins,
- SmallVectorImpl<ISD::InputArg> &OrigIns) const {
-
- for (unsigned i = 0, e = Ins.size(); i < e; ++i) {
- if (Ins[i].ArgVT == Ins[i].VT) {
- OrigIns.push_back(Ins[i]);
- continue;
- }
-
- EVT VT;
- if (Ins[i].ArgVT.isVector() && !Ins[i].VT.isVector()) {
- // Vector has been split into scalars.
- VT = Ins[i].ArgVT.getVectorElementType();
- } else if (Ins[i].VT.isVector() && Ins[i].ArgVT.isVector() &&
- Ins[i].ArgVT.getVectorElementType() !=
- Ins[i].VT.getVectorElementType()) {
- // Vector elements have been promoted
- VT = Ins[i].ArgVT;
- } else {
- // Vector has been spilt into smaller vectors.
- VT = Ins[i].VT;
- }
-
- ISD::InputArg Arg(Ins[i].Flags, VT, VT, Ins[i].Used,
- Ins[i].OrigArgIndex, Ins[i].PartOffset);
- OrigIns.push_back(Arg);
- }
-}
-
SDValue AMDGPUTargetLowering::CreateLiveInRegister(SelectionDAG &DAG,
const TargetRegisterClass *RC,
unsigned Reg, EVT VT) const {
@@ -2754,7 +3184,8 @@ SDValue AMDGPUTargetLowering::CreateLiveInRegister(SelectionDAG &DAG,
uint32_t AMDGPUTargetLowering::getImplicitParameterOffset(
const AMDGPUMachineFunction *MFI, const ImplicitParameter Param) const {
- uint64_t ArgOffset = MFI->ABIArgOffset;
+ unsigned Alignment = Subtarget->getAlignmentForImplicitArgPtr();
+ uint64_t ArgOffset = alignTo(MFI->getABIArgOffset(), Alignment);
switch (Param) {
case GRID_DIM:
return ArgOffset;
@@ -2779,6 +3210,10 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(RETURN)
NODE_NAME_CASE(DWORDADDR)
NODE_NAME_CASE(FRACT)
+ NODE_NAME_CASE(SETCC)
+ NODE_NAME_CASE(SETREG)
+ NODE_NAME_CASE(FMA_W_CHAIN)
+ NODE_NAME_CASE(FMUL_W_CHAIN)
NODE_NAME_CASE(CLAMP)
NODE_NAME_CASE(COS_HW)
NODE_NAME_CASE(SIN_HW)
@@ -2800,7 +3235,9 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(TRIG_PREOP)
NODE_NAME_CASE(RCP)
NODE_NAME_CASE(RSQ)
+ NODE_NAME_CASE(RCP_LEGACY)
NODE_NAME_CASE(RSQ_LEGACY)
+ NODE_NAME_CASE(FMUL_LEGACY)
NODE_NAME_CASE(RSQ_CLAMP)
NODE_NAME_CASE(LDEXP)
NODE_NAME_CASE(FP_CLASS)
@@ -2812,12 +3249,19 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(BFI)
NODE_NAME_CASE(BFM)
NODE_NAME_CASE(FFBH_U32)
+ NODE_NAME_CASE(FFBH_I32)
NODE_NAME_CASE(MUL_U24)
NODE_NAME_CASE(MUL_I24)
+ NODE_NAME_CASE(MULHI_U24)
+ NODE_NAME_CASE(MULHI_I24)
+ NODE_NAME_CASE(MUL_LOHI_U24)
+ NODE_NAME_CASE(MUL_LOHI_I24)
NODE_NAME_CASE(MAD_U24)
NODE_NAME_CASE(MAD_I24)
NODE_NAME_CASE(TEXTURE_FETCH)
NODE_NAME_CASE(EXPORT)
+ NODE_NAME_CASE(EXPORT_DONE)
+ NODE_NAME_CASE(R600_EXPORT)
NODE_NAME_CASE(CONST_ADDRESS)
NODE_NAME_CASE(REGISTER_LOAD)
NODE_NAME_CASE(REGISTER_STORE)
@@ -2833,8 +3277,11 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(BUILD_VERTICAL_VECTOR)
NODE_NAME_CASE(CONST_DATA_PTR)
NODE_NAME_CASE(PC_ADD_REL_OFFSET)
+ NODE_NAME_CASE(KILL)
+ NODE_NAME_CASE(DUMMY_CHAIN)
case AMDGPUISD::FIRST_MEM_OPCODE_NUMBER: break;
NODE_NAME_CASE(SENDMSG)
+ NODE_NAME_CASE(SENDMSGHALT)
NODE_NAME_CASE(INTERP_MOV)
NODE_NAME_CASE(INTERP_P1)
NODE_NAME_CASE(INTERP_P2)
@@ -2844,16 +3291,18 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(ATOMIC_CMP_SWAP)
NODE_NAME_CASE(ATOMIC_INC)
NODE_NAME_CASE(ATOMIC_DEC)
+ NODE_NAME_CASE(BUFFER_LOAD)
+ NODE_NAME_CASE(BUFFER_LOAD_FORMAT)
case AMDGPUISD::LAST_AMDGPU_ISD_NUMBER: break;
}
return nullptr;
}
-SDValue AMDGPUTargetLowering::getRsqrtEstimate(SDValue Operand,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const {
- SelectionDAG &DAG = DCI.DAG;
+SDValue AMDGPUTargetLowering::getSqrtEstimate(SDValue Operand,
+ SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps,
+ bool &UseOneConstNR,
+ bool Reciprocal) const {
EVT VT = Operand.getValueType();
if (VT == MVT::f32) {
@@ -2868,9 +3317,8 @@ SDValue AMDGPUTargetLowering::getRsqrtEstimate(SDValue Operand,
}
SDValue AMDGPUTargetLowering::getRecipEstimate(SDValue Operand,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const {
- SelectionDAG &DAG = DCI.DAG;
+ SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps) const {
EVT VT = Operand.getValueType();
if (VT == MVT::f32) {
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
index c2c7585..f6adcea 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h
@@ -25,19 +25,19 @@ class AMDGPUSubtarget;
class MachineRegisterInfo;
class AMDGPUTargetLowering : public TargetLowering {
+private:
+ /// \returns AMDGPUISD::FFBH_U32 node if the incoming \p Op may have been
+ /// legalized from a smaller type VT. Need to match pre-legalized type because
+ /// the generic legalization inserts the add/sub between the select and
+ /// compare.
+ SDValue getFFBH_U32(SelectionDAG &DAG, SDValue Op, const SDLoc &DL) const;
+
protected:
const AMDGPUSubtarget *Subtarget;
- SDValue LowerConstantInitializer(const Constant* Init, const GlobalValue *GV,
- const SDValue &InitPtr,
- SDValue Chain,
- SelectionDAG &DAG) const;
SDValue LowerEXTRACT_SUBVECTOR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
- /// \brief Lower vector stores by merging the vector elements into an integer
- /// of the same bitwidth.
- SDValue MergeVectorStore(const SDValue &Op, SelectionDAG &DAG) const;
/// \brief Split a vector store into multiple scalar stores.
/// \returns The resulting chain.
@@ -60,6 +60,7 @@ protected:
SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFP64_TO_INT(SDValue Op, SelectionDAG &DAG, bool Signed) const;
+ SDValue LowerFP_TO_FP16(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFP_TO_UINT(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const;
@@ -69,17 +70,23 @@ protected:
bool shouldCombineMemoryType(EVT VT) const;
SDValue performLoadCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performStoreCombine(SDNode *N, DAGCombinerInfo &DCI) const;
- SDValue performAndCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+
+ SDValue splitBinaryBitConstantOpImpl(DAGCombinerInfo &DCI, const SDLoc &SL,
+ unsigned Opc, SDValue LHS,
+ uint32_t ValLo, uint32_t ValHi) const;
SDValue performShlCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performSraCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performSrlCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performMulCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performMulhsCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performMulhuCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performMulLoHi24Combine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performCtlzCombine(const SDLoc &SL, SDValue Cond, SDValue LHS,
SDValue RHS, DAGCombinerInfo &DCI) const;
SDValue performSelectCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performFNegCombine(SDNode *N, DAGCombinerInfo &DCI) const;
static EVT getEquivalentMemType(LLVMContext &Context, EVT VT);
- static EVT getEquivalentBitType(LLVMContext &Context, EVT VT);
virtual SDValue LowerGlobalAddress(AMDGPUMachineFunction *MFI, SDValue Op,
SelectionDAG &DAG) const;
@@ -102,16 +109,8 @@ protected:
SDValue LowerDIVREM24(SDValue Op, SelectionDAG &DAG, bool sign) const;
void LowerUDIVREM64(SDValue Op, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &Results) const;
- /// The SelectionDAGBuilder will automatically promote function arguments
- /// with illegal types. However, this does not work for the AMDGPU targets
- /// since the function arguments are stored in memory as these illegal types.
- /// In order to handle this properly we need to get the origianl types sizes
- /// from the LLVM IR Function and fixup the ISD:InputArg values before
- /// passing them to AnalyzeFormalArguments()
- void getOriginalFunctionArgs(SelectionDAG &DAG,
- const Function *F,
- const SmallVectorImpl<ISD::InputArg> &Ins,
- SmallVectorImpl<ISD::InputArg> &OrigIns) const;
+ void analyzeFormalArgumentsCompute(CCState &State,
+ const SmallVectorImpl<ISD::InputArg> &Ins) const;
void AnalyzeFormalArguments(CCState &State,
const SmallVectorImpl<ISD::InputArg> &Ins) const;
void AnalyzeReturn(CCState &State,
@@ -120,6 +119,16 @@ protected:
public:
AMDGPUTargetLowering(const TargetMachine &TM, const AMDGPUSubtarget &STI);
+ bool mayIgnoreSignedZero(SDValue Op) const {
+ if (getTargetMachine().Options.UnsafeFPMath) // FIXME: nsz only
+ return true;
+
+ if (const auto *BO = dyn_cast<BinaryWithFlagsSDNode>(Op))
+ return BO->Flags.hasNoSignedZeros();
+
+ return false;
+ }
+
bool isFAbsFree(EVT VT) const override;
bool isFNegFree(EVT VT) const override;
bool isTruncateFree(EVT Src, EVT Dest) const override;
@@ -171,13 +180,14 @@ public:
const char* getTargetNodeName(unsigned Opcode) const override;
- SDValue getRsqrtEstimate(SDValue Operand,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const override;
- SDValue getRecipEstimate(SDValue Operand,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const override;
+ bool isFsqrtCheap(SDValue Operand, SelectionDAG &DAG) const override {
+ return true;
+ }
+ SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps, bool &UseOneConstNR,
+ bool Reciprocal) const override;
+ SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps) const override;
virtual SDNode *PostISelFolding(MachineSDNode *N,
SelectionDAG &DAG) const = 0;
@@ -228,6 +238,13 @@ enum NodeType : unsigned {
DWORDADDR,
FRACT,
CLAMP,
+ // This is SETCC with the full mask result which is used for a compare with a
+ // result bit per item in the wavefront.
+ SETCC,
+ SETREG,
+ // FP ops with input and output chain.
+ FMA_W_CHAIN,
+ FMUL_W_CHAIN,
// SIN_HW, COS_HW - f32 for SI, 1 ULP max error, valid from -100 pi to 100 pi.
// Denormals handled on some parts.
@@ -254,7 +271,9 @@ enum NodeType : unsigned {
// For f64, max error 2^29 ULP, handles denormals.
RCP,
RSQ,
+ RCP_LEGACY,
RSQ_LEGACY,
+ FMUL_LEGACY,
RSQ_CLAMP,
LDEXP,
FP_CLASS,
@@ -266,12 +285,19 @@ enum NodeType : unsigned {
BFI, // (src0 & src1) | (~src0 & src2)
BFM, // Insert a range of bits into a 32-bit word.
FFBH_U32, // ctlz with -1 if input is zero.
+ FFBH_I32,
MUL_U24,
MUL_I24,
+ MULHI_U24,
+ MULHI_I24,
MAD_U24,
MAD_I24,
+ MUL_LOHI_I24,
+ MUL_LOHI_U24,
TEXTURE_FETCH,
- EXPORT,
+ EXPORT, // exp on SI+
+ EXPORT_DONE, // exp on SI+ with done bit set
+ R600_EXPORT,
CONST_ADDRESS,
REGISTER_LOAD,
REGISTER_STORE,
@@ -298,10 +324,13 @@ enum NodeType : unsigned {
/// Pointer to the start of the shader's constant data.
CONST_DATA_PTR,
SENDMSG,
+ SENDMSGHALT,
INTERP_MOV,
INTERP_P1,
INTERP_P2,
PC_ADD_REL_OFFSET,
+ KILL,
+ DUMMY_CHAIN,
FIRST_MEM_OPCODE_NUMBER = ISD::FIRST_TARGET_MEMORY_OPCODE,
STORE_MSKOR,
LOAD_CONSTANT,
@@ -309,6 +338,8 @@ enum NodeType : unsigned {
ATOMIC_CMP_SWAP,
ATOMIC_INC,
ATOMIC_DEC,
+ BUFFER_LOAD,
+ BUFFER_LOAD_FORMAT,
LAST_AMDGPU_ISD_NUMBER
};
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp
index 9a00ecb..e4dc659 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp
@@ -23,7 +23,6 @@
using namespace llvm;
#define GET_INSTRINFO_CTOR_DTOR
-#define GET_INSTRINFO_NAMED_OPS
#define GET_INSTRMAP_INFO
#include "AMDGPUGenInstrInfo.inc"
@@ -33,10 +32,6 @@ void AMDGPUInstrInfo::anchor() {}
AMDGPUInstrInfo::AMDGPUInstrInfo(const AMDGPUSubtarget &ST)
: AMDGPUGenInstrInfo(-1, -1), ST(ST) {}
-bool AMDGPUInstrInfo::enableClusterLoads() const {
- return true;
-}
-
// FIXME: This behaves strangely. If, for example, you have 32 load + stores,
// the first 16 loads will be interleaved with the stores, and the next 16 will
// be clustered as expected. It should really split into 2 16 store batches.
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.h
index a59eafa..bd8e389 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.h
@@ -17,17 +17,12 @@
#define LLVM_LIB_TARGET_AMDGPU_AMDGPUINSTRINFO_H
#include "llvm/Target/TargetInstrInfo.h"
+#include "Utils/AMDGPUBaseInfo.h"
#define GET_INSTRINFO_HEADER
#define GET_INSTRINFO_ENUM
-#define GET_INSTRINFO_OPERAND_ENUM
#include "AMDGPUGenInstrInfo.inc"
-#define OPCODE_IS_ZERO_INT AMDGPU::PRED_SETE_INT
-#define OPCODE_IS_NOT_ZERO_INT AMDGPU::PRED_SETNE_INT
-#define OPCODE_IS_ZERO AMDGPU::PRED_SETE
-#define OPCODE_IS_NOT_ZERO AMDGPU::PRED_SETNE
-
namespace llvm {
class AMDGPUSubtarget;
@@ -44,8 +39,6 @@ private:
public:
explicit AMDGPUInstrInfo(const AMDGPUSubtarget &st);
- bool enableClusterLoads() const override;
-
bool shouldScheduleLoadsNear(SDNode *Load1, SDNode *Load2,
int64_t Offset1, int64_t Offset2,
unsigned NumLoads) const override;
@@ -59,15 +52,6 @@ public:
/// equivalent opcode that writes \p Channels Channels.
int getMaskedMIMGOp(uint16_t Opcode, unsigned Channels) const;
};
-
-namespace AMDGPU {
- LLVM_READONLY
- int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIndex);
-} // End namespace AMDGPU
-
} // End llvm namespace
-#define AMDGPU_FLAG_REGISTER_LOAD (UINT64_C(1) << 63)
-#define AMDGPU_FLAG_REGISTER_STORE (UINT64_C(1) << 62)
-
#endif
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td
index 2b13bb9..d7fa28b 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td
@@ -40,6 +40,8 @@ def AMDGPUFmasOp : SDTypeProfile<1, 4,
[SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisInt<4>]
>;
+def AMDGPUKillSDT : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
+
//===----------------------------------------------------------------------===//
// AMDGPU DAG Nodes
//
@@ -52,6 +54,9 @@ def AMDGPUconstdata_ptr : SDNode<
// This argument to this node is a dword address.
def AMDGPUdwordaddr : SDNode<"AMDGPUISD::DWORDADDR", SDTIntUnaryOp>;
+// Force dependencies for vector trunc stores
+def R600dummy_chain : SDNode<"AMDGPUISD::DUMMY_CHAIN", SDTNone, [SDNPHasChain]>;
+
def AMDGPUcos : SDNode<"AMDGPUISD::COS_HW", SDTFPUnaryOp>;
def AMDGPUsin : SDNode<"AMDGPUISD::SIN_HW", SDTFPUnaryOp>;
@@ -65,6 +70,7 @@ def AMDGPUrcp : SDNode<"AMDGPUISD::RCP", SDTFPUnaryOp>;
def AMDGPUrsq : SDNode<"AMDGPUISD::RSQ", SDTFPUnaryOp>;
// out = 1.0 / sqrt(a)
+def AMDGPUrcp_legacy : SDNode<"AMDGPUISD::RCP_LEGACY", SDTFPUnaryOp>;
def AMDGPUrsq_legacy : SDNode<"AMDGPUISD::RSQ_LEGACY", SDTFPUnaryOp>;
// out = 1.0 / sqrt(a) result clamped to +/- max_float.
@@ -82,6 +88,10 @@ def AMDGPUfmax_legacy : SDNode<"AMDGPUISD::FMAX_LEGACY", SDTFPBinOp,
[]
>;
+def AMDGPUfmul_legacy : SDNode<"AMDGPUISD::FMUL_LEGACY", SDTFPBinOp,
+ [SDNPCommutative, SDNPAssociative]
+>;
+
def AMDGPUclamp : SDNode<"AMDGPUISD::CLAMP", SDTFPTernaryOp, []>;
// out = max(a, b) a and b are signed ints
@@ -137,6 +147,24 @@ def AMDGPUcarry : SDNode<"AMDGPUISD::CARRY", SDTIntBinOp, []>;
// out = (src1 > src0) ? 1 : 0
def AMDGPUborrow : SDNode<"AMDGPUISD::BORROW", SDTIntBinOp, []>;
+def AMDGPUSetCCOp : SDTypeProfile<1, 3, [ // setcc
+ SDTCisVT<0, i64>, SDTCisSameAs<1, 2>, SDTCisVT<3, OtherVT>
+]>;
+
+def AMDGPUsetcc : SDNode<"AMDGPUISD::SETCC", AMDGPUSetCCOp>;
+
+def AMDGPUSetRegOp : SDTypeProfile<0, 2, [
+ SDTCisInt<0>, SDTCisInt<1>
+]>;
+
+def AMDGPUsetreg : SDNode<"AMDGPUISD::SETREG", AMDGPUSetRegOp, [
+ SDNPHasChain, SDNPSideEffect, SDNPOptInGlue, SDNPOutGlue]>;
+
+def AMDGPUfma : SDNode<"AMDGPUISD::FMA_W_CHAIN", SDTFPTernaryOp, [
+ SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
+
+def AMDGPUmul : SDNode<"AMDGPUISD::FMUL_W_CHAIN", SDTFPBinOp, [
+ SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
def AMDGPUcvt_f32_ubyte0 : SDNode<"AMDGPUISD::CVT_F32_UBYTE0",
SDTIntToFPOp, []>;
@@ -202,14 +230,22 @@ def AMDGPUbfi : SDNode<"AMDGPUISD::BFI", AMDGPUDTIntTernaryOp>;
def AMDGPUbfm : SDNode<"AMDGPUISD::BFM", SDTIntBinOp>;
def AMDGPUffbh_u32 : SDNode<"AMDGPUISD::FFBH_U32", SDTIntUnaryOp>;
+def AMDGPUffbh_i32 : SDNode<"AMDGPUISD::FFBH_I32", SDTIntUnaryOp>;
-// Signed and unsigned 24-bit mulitply. The highest 8-bits are ignore when
-// performing the mulitply. The result is a 32-bit value.
+// Signed and unsigned 24-bit multiply. The highest 8-bits are ignore
+// when performing the mulitply. The result is a 32-bit value.
def AMDGPUmul_u24 : SDNode<"AMDGPUISD::MUL_U24", SDTIntBinOp,
- [SDNPCommutative]
+ [SDNPCommutative, SDNPAssociative]
>;
def AMDGPUmul_i24 : SDNode<"AMDGPUISD::MUL_I24", SDTIntBinOp,
- [SDNPCommutative]
+ [SDNPCommutative, SDNPAssociative]
+>;
+
+def AMDGPUmulhi_u24 : SDNode<"AMDGPUISD::MULHI_U24", SDTIntBinOp,
+ [SDNPCommutative, SDNPAssociative]
+>;
+def AMDGPUmulhi_i24 : SDNode<"AMDGPUISD::MULHI_I24", SDTIntBinOp,
+ [SDNPCommutative, SDNPAssociative]
>;
def AMDGPUmad_u24 : SDNode<"AMDGPUISD::MAD_U24", AMDGPUDTIntTernaryOp,
@@ -233,6 +269,10 @@ def AMDGPUsendmsg : SDNode<"AMDGPUISD::SENDMSG",
SDTypeProfile<0, 1, [SDTCisInt<0>]>,
[SDNPHasChain, SDNPInGlue]>;
+def AMDGPUsendmsghalt : SDNode<"AMDGPUISD::SENDMSGHALT",
+ SDTypeProfile<0, 1, [SDTCisInt<0>]>,
+ [SDNPHasChain, SDNPInGlue]>;
+
def AMDGPUinterp_mov : SDNode<"AMDGPUISD::INTERP_MOV",
SDTypeProfile<1, 3, [SDTCisFP<0>]>,
[SDNPInGlue]>;
@@ -245,6 +285,35 @@ def AMDGPUinterp_p2 : SDNode<"AMDGPUISD::INTERP_P2",
SDTypeProfile<1, 4, [SDTCisFP<0>]>,
[SDNPInGlue]>;
+
+def AMDGPUkill : SDNode<"AMDGPUISD::KILL", AMDGPUKillSDT,
+ [SDNPHasChain, SDNPSideEffect]>;
+
+// SI+ export
+def AMDGPUExportOp : SDTypeProfile<0, 8, [
+ SDTCisInt<0>, // i8 en
+ SDTCisInt<1>, // i1 vm
+ // skip done
+ SDTCisInt<2>, // i8 tgt
+ SDTCisSameAs<3, 1>, // i1 compr
+ SDTCisFP<4>, // f32 src0
+ SDTCisSameAs<5, 4>, // f32 src1
+ SDTCisSameAs<6, 4>, // f32 src2
+ SDTCisSameAs<7, 4> // f32 src3
+]>;
+
+def AMDGPUexport: SDNode<"AMDGPUISD::EXPORT", AMDGPUExportOp,
+ [SDNPHasChain, SDNPMayStore]>;
+
+def AMDGPUexport_done: SDNode<"AMDGPUISD::EXPORT_DONE", AMDGPUExportOp,
+ [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>;
+
+
+def R600ExportOp : SDTypeProfile<0, 7, [SDTCisFP<0>, SDTCisInt<1>]>;
+
+def R600_EXPORT: SDNode<"AMDGPUISD::R600_EXPORT", R600ExportOp,
+ [SDNPHasChain, SDNPSideEffect]>;
+
//===----------------------------------------------------------------------===//
// Flow Control Profile Types
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
index 3944fdb..59cba63 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
@@ -42,6 +42,7 @@ class AMDGPUShaderInst <dag outs, dag ins, string asm = "",
field bits<32> Inst = 0xffffffff;
}
+def FP16Denormals : Predicate<"Subtarget.hasFP16Denormals()">;
def FP32Denormals : Predicate<"Subtarget.hasFP32Denormals()">;
def FP64Denormals : Predicate<"Subtarget.hasFP64Denormals()">;
def UnsafeFPMath : Predicate<"TM.Options.UnsafeFPMath">;
@@ -49,13 +50,6 @@ def UnsafeFPMath : Predicate<"TM.Options.UnsafeFPMath">;
def InstFlag : OperandWithDefaultOps <i32, (ops (i32 0))>;
def ADDRIndirect : ComplexPattern<iPTR, 2, "SelectADDRIndirect", [], []>;
-// 32-bit VALU immediate operand that uses the constant bus.
-def u32kimm : Operand<i32> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_KIMM32";
- let PrintMethod = "printU32ImmOperand";
-}
-
let OperandType = "OPERAND_IMMEDIATE" in {
def u32imm : Operand<i32> {
@@ -172,6 +166,12 @@ class HasOneUseBinOp<SDPatternOperator op> : PatFrag<
[{ return N->hasOneUse(); }]
>;
+class HasOneUseTernaryOp<SDPatternOperator op> : PatFrag<
+ (ops node:$src0, node:$src1, node:$src2),
+ (op $src0, $src1, $src2),
+ [{ return N->hasOneUse(); }]
+>;
+
//===----------------------------------------------------------------------===//
// Load/Store Pattern Fragments
//===----------------------------------------------------------------------===//
@@ -363,53 +363,54 @@ multiclass AtomicCmpSwapLocal <SDNode cmp_swap_node> {
defm atomic_cmp_swap : AtomicCmpSwapLocal <atomic_cmp_swap>;
-def mskor_flat : PatFrag<(ops node:$val, node:$ptr),
- (AMDGPUstore_mskor node:$val, node:$ptr), [{
- return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::FLAT_ADDRESS;
-}]>;
+multiclass global_binary_atomic_op<SDNode atomic_op> {
+ def "" : PatFrag<
+ (ops node:$ptr, node:$value),
+ (atomic_op node:$ptr, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS;}]>;
+
+ def _noret : PatFrag<
+ (ops node:$ptr, node:$value),
+ (atomic_op node:$ptr, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS && (SDValue(N, 0).use_empty());}]>;
+
+ def _ret : PatFrag<
+ (ops node:$ptr, node:$value),
+ (atomic_op node:$ptr, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS && (!SDValue(N, 0).use_empty());}]>;
+}
-class global_binary_atomic_op<SDNode atomic_op> : PatFrag<
- (ops node:$ptr, node:$value),
- (atomic_op node:$ptr, node:$value),
- [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS;}]
->;
-
-class flat_binary_atomic_op<SDNode atomic_op> : PatFrag<
- (ops node:$ptr, node:$value),
- (atomic_op node:$ptr, node:$value),
- [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::FLAT_ADDRESS;}]
->;
-
-def atomic_swap_global : global_binary_atomic_op<atomic_swap>;
-def atomic_add_global : global_binary_atomic_op<atomic_load_add>;
-def atomic_and_global : global_binary_atomic_op<atomic_load_and>;
-def atomic_max_global : global_binary_atomic_op<atomic_load_max>;
-def atomic_min_global : global_binary_atomic_op<atomic_load_min>;
-def atomic_or_global : global_binary_atomic_op<atomic_load_or>;
-def atomic_sub_global : global_binary_atomic_op<atomic_load_sub>;
-def atomic_umax_global : global_binary_atomic_op<atomic_load_umax>;
-def atomic_umin_global : global_binary_atomic_op<atomic_load_umin>;
-def atomic_xor_global : global_binary_atomic_op<atomic_load_xor>;
-
-def atomic_cmp_swap_global : global_binary_atomic_op<AMDGPUatomic_cmp_swap>;
-def atomic_cmp_swap_global_nortn : PatFrag<
- (ops node:$ptr, node:$value),
- (atomic_cmp_swap_global node:$ptr, node:$value),
- [{ return SDValue(N, 0).use_empty(); }]
->;
-
-def atomic_swap_flat : flat_binary_atomic_op<atomic_swap>;
-def atomic_add_flat : flat_binary_atomic_op<atomic_load_add>;
-def atomic_and_flat : flat_binary_atomic_op<atomic_load_and>;
-def atomic_max_flat : flat_binary_atomic_op<atomic_load_max>;
-def atomic_min_flat : flat_binary_atomic_op<atomic_load_min>;
-def atomic_or_flat : flat_binary_atomic_op<atomic_load_or>;
-def atomic_sub_flat : flat_binary_atomic_op<atomic_load_sub>;
-def atomic_umax_flat : flat_binary_atomic_op<atomic_load_umax>;
-def atomic_umin_flat : flat_binary_atomic_op<atomic_load_umin>;
-def atomic_xor_flat : flat_binary_atomic_op<atomic_load_xor>;
-
-def atomic_cmp_swap_flat : flat_binary_atomic_op<AMDGPUatomic_cmp_swap>;
+defm atomic_swap_global : global_binary_atomic_op<atomic_swap>;
+defm atomic_add_global : global_binary_atomic_op<atomic_load_add>;
+defm atomic_and_global : global_binary_atomic_op<atomic_load_and>;
+defm atomic_max_global : global_binary_atomic_op<atomic_load_max>;
+defm atomic_min_global : global_binary_atomic_op<atomic_load_min>;
+defm atomic_or_global : global_binary_atomic_op<atomic_load_or>;
+defm atomic_sub_global : global_binary_atomic_op<atomic_load_sub>;
+defm atomic_umax_global : global_binary_atomic_op<atomic_load_umax>;
+defm atomic_umin_global : global_binary_atomic_op<atomic_load_umin>;
+defm atomic_xor_global : global_binary_atomic_op<atomic_load_xor>;
+
+//legacy
+def AMDGPUatomic_cmp_swap_global : PatFrag<
+ (ops node:$ptr, node:$value),
+ (AMDGPUatomic_cmp_swap node:$ptr, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS;}]>;
+
+def atomic_cmp_swap_global : PatFrag<
+ (ops node:$ptr, node:$cmp, node:$value),
+ (atomic_cmp_swap node:$ptr, node:$cmp, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS;}]>;
+
+def atomic_cmp_swap_global_noret : PatFrag<
+ (ops node:$ptr, node:$cmp, node:$value),
+ (atomic_cmp_swap node:$ptr, node:$cmp, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS && (SDValue(N, 0).use_empty());}]>;
+
+def atomic_cmp_swap_global_ret : PatFrag<
+ (ops node:$ptr, node:$cmp, node:$value),
+ (atomic_cmp_swap node:$ptr, node:$cmp, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS && (!SDValue(N, 0).use_empty());}]>;
//===----------------------------------------------------------------------===//
// Misc Pattern Fragments
@@ -420,6 +421,7 @@ int TWO_PI = 0x40c90fdb;
int PI = 0x40490fdb;
int TWO_PI_INV = 0x3e22f983;
int FP_UINT_MAX_PLUS_1 = 0x4f800000; // 1 << 32 in floating point encoding
+int FP16_ONE = 0x3C00;
int FP32_ONE = 0x3f800000;
int FP32_NEG_ONE = 0xbf800000;
int FP64_ONE = 0x3ff0000000000000;
@@ -559,17 +561,26 @@ multiclass BFIPatterns <Instruction BFI_INT,
def : Pat <
(fcopysign f32:$src0, f32:$src1),
- (BFI_INT (LoadImm32 0x7fffffff), $src0, $src1)
+ (BFI_INT (LoadImm32 (i32 0x7fffffff)), $src0, $src1)
>;
def : Pat <
(f64 (fcopysign f64:$src0, f64:$src1)),
(REG_SEQUENCE RC64,
(i32 (EXTRACT_SUBREG $src0, sub0)), sub0,
- (BFI_INT (LoadImm32 0x7fffffff),
+ (BFI_INT (LoadImm32 (i32 0x7fffffff)),
(i32 (EXTRACT_SUBREG $src0, sub1)),
(i32 (EXTRACT_SUBREG $src1, sub1))), sub1)
>;
+
+ def : Pat <
+ (f64 (fcopysign f64:$src0, f32:$src1)),
+ (REG_SEQUENCE RC64,
+ (i32 (EXTRACT_SUBREG $src0, sub0)), sub0,
+ (BFI_INT (LoadImm32 (i32 0x7fffffff)),
+ (i32 (EXTRACT_SUBREG $src0, sub1)),
+ $src1), sub1)
+ >;
}
// SHA-256 Ma patterns
@@ -620,9 +631,9 @@ def umax_oneuse : HasOneUseBinOp<umax>;
def umin_oneuse : HasOneUseBinOp<umin>;
} // Properties = [SDNPCommutative, SDNPAssociative]
+def sub_oneuse : HasOneUseBinOp<sub>;
-// 24-bit arithmetic patterns
-def umul24 : PatFrag <(ops node:$x, node:$y), (mul node:$x, node:$y)>;
+def select_oneuse : HasOneUseTernaryOp<select>;
// Special conversion patterns
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUIntrinsics.td b/contrib/llvm/lib/Target/AMDGPU/AMDGPUIntrinsics.td
index 2127391..ceae0b5 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUIntrinsics.td
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUIntrinsics.td
@@ -16,6 +16,8 @@ let TargetPrefix = "AMDGPU", isTarget = 1 in {
def int_AMDGPU_kill : Intrinsic<[], [llvm_float_ty], []>;
def int_AMDGPU_kilp : Intrinsic<[], [], []>;
+
+ // Deprecated in favor of llvm.amdgcn.sffbh
def int_AMDGPU_flbit_i32 : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
// Deprecated in favor of separate int_amdgcn_cube* intrinsics.
@@ -29,9 +31,6 @@ let TargetPrefix = "AMDGPU", isTarget = 1 in {
def int_AMDGPU_rsq : Intrinsic<
[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]
>;
-
- // Deprecated in favor of llvm.amdgcn.read.workdim
- def int_AMDGPU_read_workdim : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>;
}
include "SIIntrinsics.td"
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp
index ad8d3e4..7d56355 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.cpp
@@ -36,13 +36,92 @@
using namespace llvm;
-AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext &ctx, const AMDGPUSubtarget &st):
- Ctx(ctx), ST(st) { }
+#include "AMDGPUGenMCPseudoLowering.inc"
+
+
+AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext &ctx, const AMDGPUSubtarget &st,
+ const AsmPrinter &ap):
+ Ctx(ctx), ST(st), AP(ap) { }
static MCSymbolRefExpr::VariantKind getVariantKind(unsigned MOFlags) {
switch (MOFlags) {
- default: return MCSymbolRefExpr::VK_None;
- case SIInstrInfo::MO_GOTPCREL: return MCSymbolRefExpr::VK_GOTPCREL;
+ default:
+ return MCSymbolRefExpr::VK_None;
+ case SIInstrInfo::MO_GOTPCREL:
+ return MCSymbolRefExpr::VK_GOTPCREL;
+ case SIInstrInfo::MO_GOTPCREL32_LO:
+ return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO;
+ case SIInstrInfo::MO_GOTPCREL32_HI:
+ return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI;
+ case SIInstrInfo::MO_REL32_LO:
+ return MCSymbolRefExpr::VK_AMDGPU_REL32_LO;
+ case SIInstrInfo::MO_REL32_HI:
+ return MCSymbolRefExpr::VK_AMDGPU_REL32_HI;
+ }
+}
+
+const MCExpr *AMDGPUMCInstLower::getLongBranchBlockExpr(
+ const MachineBasicBlock &SrcBB,
+ const MachineOperand &MO) const {
+ const MCExpr *DestBBSym
+ = MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx);
+ const MCExpr *SrcBBSym = MCSymbolRefExpr::create(SrcBB.getSymbol(), Ctx);
+
+ assert(SrcBB.front().getOpcode() == AMDGPU::S_GETPC_B64 &&
+ ST.getInstrInfo()->get(AMDGPU::S_GETPC_B64).Size == 4);
+
+ // s_getpc_b64 returns the address of next instruction.
+ const MCConstantExpr *One = MCConstantExpr::create(4, Ctx);
+ SrcBBSym = MCBinaryExpr::createAdd(SrcBBSym, One, Ctx);
+
+ if (MO.getTargetFlags() == AMDGPU::TF_LONG_BRANCH_FORWARD)
+ return MCBinaryExpr::createSub(DestBBSym, SrcBBSym, Ctx);
+
+ assert(MO.getTargetFlags() == AMDGPU::TF_LONG_BRANCH_BACKWARD);
+ return MCBinaryExpr::createSub(SrcBBSym, DestBBSym, Ctx);
+}
+
+bool AMDGPUMCInstLower::lowerOperand(const MachineOperand &MO,
+ MCOperand &MCOp) const {
+ switch (MO.getType()) {
+ default:
+ llvm_unreachable("unknown operand type");
+ case MachineOperand::MO_Immediate:
+ MCOp = MCOperand::createImm(MO.getImm());
+ return true;
+ case MachineOperand::MO_Register:
+ MCOp = MCOperand::createReg(AMDGPU::getMCReg(MO.getReg(), ST));
+ return true;
+ case MachineOperand::MO_MachineBasicBlock: {
+ if (MO.getTargetFlags() != 0) {
+ MCOp = MCOperand::createExpr(
+ getLongBranchBlockExpr(*MO.getParent()->getParent(), MO));
+ } else {
+ MCOp = MCOperand::createExpr(
+ MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
+ }
+
+ return true;
+ }
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MO.getGlobal();
+ SmallString<128> SymbolName;
+ AP.getNameWithPrefix(SymbolName, GV);
+ MCSymbol *Sym = Ctx.getOrCreateSymbol(SymbolName);
+ const MCExpr *SymExpr =
+ MCSymbolRefExpr::create(Sym, getVariantKind(MO.getTargetFlags()),Ctx);
+ const MCExpr *Expr = MCBinaryExpr::createAdd(SymExpr,
+ MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
+ MCOp = MCOperand::createExpr(Expr);
+ return true;
+ }
+ case MachineOperand::MO_ExternalSymbol: {
+ MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(MO.getSymbolName()));
+ Sym->setExternal(true);
+ const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
+ MCOp = MCOperand::createExpr(Expr);
+ return true;
+ }
}
}
@@ -60,44 +139,24 @@ void AMDGPUMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const {
for (const MachineOperand &MO : MI->explicit_operands()) {
MCOperand MCOp;
- switch (MO.getType()) {
- default:
- llvm_unreachable("unknown operand type");
- case MachineOperand::MO_Immediate:
- MCOp = MCOperand::createImm(MO.getImm());
- break;
- case MachineOperand::MO_Register:
- MCOp = MCOperand::createReg(AMDGPU::getMCReg(MO.getReg(), ST));
- break;
- case MachineOperand::MO_MachineBasicBlock:
- MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
- MO.getMBB()->getSymbol(), Ctx));
- break;
- case MachineOperand::MO_GlobalAddress: {
- const GlobalValue *GV = MO.getGlobal();
- MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(GV->getName()));
- const MCExpr *SymExpr =
- MCSymbolRefExpr::create(Sym, getVariantKind(MO.getTargetFlags()),Ctx);
- const MCExpr *Expr = MCBinaryExpr::createAdd(SymExpr,
- MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
- MCOp = MCOperand::createExpr(Expr);
- break;
- }
- case MachineOperand::MO_ExternalSymbol: {
- MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(MO.getSymbolName()));
- Sym->setExternal(true);
- const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
- MCOp = MCOperand::createExpr(Expr);
- break;
- }
- }
+ lowerOperand(MO, MCOp);
OutMI.addOperand(MCOp);
}
}
+bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand &MO,
+ MCOperand &MCOp) const {
+ const AMDGPUSubtarget &STI = MF->getSubtarget<AMDGPUSubtarget>();
+ AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this);
+ return MCInstLowering.lowerOperand(MO, MCOp);
+}
+
void AMDGPUAsmPrinter::EmitInstruction(const MachineInstr *MI) {
+ if (emitPseudoExpansionLowering(*OutStreamer, MI))
+ return;
+
const AMDGPUSubtarget &STI = MF->getSubtarget<AMDGPUSubtarget>();
- AMDGPUMCInstLower MCInstLowering(OutContext, STI);
+ AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this);
StringRef Err;
if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) {
@@ -137,6 +196,12 @@ void AMDGPUAsmPrinter::EmitInstruction(const MachineInstr *MI) {
return;
}
+ if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) {
+ if (isVerbose())
+ OutStreamer->emitRawComment(" wave barrier");
+ return;
+ }
+
MCInst TmpInst;
MCInstLowering.lower(MI, TmpInst);
EmitToStreamer(*OutStreamer, TmpInst);
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.h
index 957dcd0..57d2d85 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMCInstLower.h
@@ -5,7 +5,6 @@
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
-/// \file
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPUMCINSTLOWER_H
@@ -14,16 +13,28 @@
namespace llvm {
class AMDGPUSubtarget;
+class AsmPrinter;
+class MachineBasicBlock;
class MachineInstr;
+class MachineOperand;
class MCContext;
+class MCExpr;
class MCInst;
+class MCOperand;
class AMDGPUMCInstLower {
MCContext &Ctx;
const AMDGPUSubtarget &ST;
+ const AsmPrinter &AP;
+
+ const MCExpr *getLongBranchBlockExpr(const MachineBasicBlock &SrcBB,
+ const MachineOperand &MO) const;
public:
- AMDGPUMCInstLower(MCContext &ctx, const AMDGPUSubtarget &ST);
+ AMDGPUMCInstLower(MCContext &ctx, const AMDGPUSubtarget &ST,
+ const AsmPrinter &AP);
+
+ bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
/// \brief Lower a MachineInstr to an MCInst
void lower(const MachineInstr *MI, MCInst &OutMI) const;
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.cpp
index 44516da..40c3327 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.cpp
@@ -1,23 +1,47 @@
+//===-- AMDGPUMachineFunctionInfo.cpp ---------------------------------------=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
#include "AMDGPUMachineFunction.h"
+#include "AMDGPUSubtarget.h"
using namespace llvm;
-// Pin the vtable to this file.
-void AMDGPUMachineFunction::anchor() {}
-
AMDGPUMachineFunction::AMDGPUMachineFunction(const MachineFunction &MF) :
MachineFunctionInfo(),
+ LocalMemoryObjects(),
KernArgSize(0),
MaxKernArgAlign(0),
LDSSize(0),
ABIArgOffset(0),
- ScratchSize(0),
- IsKernel(MF.getFunction()->getCallingConv() == llvm::CallingConv::AMDGPU_KERNEL ||
- MF.getFunction()->getCallingConv() == llvm::CallingConv::SPIR_KERNEL)
-{
+ IsKernel(MF.getFunction()->getCallingConv() == CallingConv::AMDGPU_KERNEL ||
+ MF.getFunction()->getCallingConv() == CallingConv::SPIR_KERNEL) {
+ // FIXME: Should initialize KernArgSize based on ExplicitKernelArgOffset,
+ // except reserved size is not correctly aligned.
}
-bool AMDGPUMachineFunction::isKernel() const
-{
- return IsKernel;
+unsigned AMDGPUMachineFunction::allocateLDSGlobal(const DataLayout &DL,
+ const GlobalValue &GV) {
+ auto Entry = LocalMemoryObjects.insert(std::make_pair(&GV, 0));
+ if (!Entry.second)
+ return Entry.first->second;
+
+ unsigned Align = GV.getAlignment();
+ if (Align == 0)
+ Align = DL.getABITypeAlignment(GV.getValueType());
+
+ /// TODO: We should sort these to minimize wasted space due to alignment
+ /// padding. Currently the padding is decided by the first encountered use
+ /// during lowering.
+ unsigned Offset = LDSSize = alignTo(LDSSize, Align);
+
+ Entry.first->second = Offset;
+ LDSSize += DL.getTypeAllocSize(GV.getValueType());
+
+ return Offset;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h
index 6b31f63..5d0640b 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUMachineFunction.h
@@ -11,15 +11,26 @@
#define LLVM_LIB_TARGET_AMDGPU_AMDGPUMACHINEFUNCTION_H
#include "llvm/CodeGen/MachineFunction.h"
-#include <map>
+#include "llvm/ADT/DenseMap.h"
namespace llvm {
class AMDGPUMachineFunction : public MachineFunctionInfo {
+ /// A map to keep track of local memory objects and their offsets within the
+ /// local memory space.
+ SmallDenseMap<const GlobalValue *, unsigned, 4> LocalMemoryObjects;
+
uint64_t KernArgSize;
unsigned MaxKernArgAlign;
- virtual void anchor();
+ /// Number of bytes in the LDS that are being used.
+ unsigned LDSSize;
+
+ // FIXME: This should probably be removed.
+ /// Start of implicit kernel args
+ unsigned ABIArgOffset;
+
+ bool IsKernel;
public:
AMDGPUMachineFunction(const MachineFunction &MF);
@@ -35,19 +46,31 @@ public:
return Result;
}
- /// A map to keep track of local memory objects and their offsets within
- /// the local memory space.
- std::map<const GlobalValue *, unsigned> LocalMemoryObjects;
- /// Number of bytes in the LDS that are being used.
- unsigned LDSSize;
+ uint64_t getKernArgSize() const {
+ return KernArgSize;
+ }
- /// Start of implicit kernel args
- unsigned ABIArgOffset;
+ unsigned getMaxKernArgAlign() const {
+ return MaxKernArgAlign;
+ }
- bool isKernel() const;
+ void setABIArgOffset(unsigned NewOffset) {
+ ABIArgOffset = NewOffset;
+ }
- unsigned ScratchSize;
- bool IsKernel;
+ unsigned getABIArgOffset() const {
+ return ABIArgOffset;
+ }
+
+ unsigned getLDSSize() const {
+ return LDSSize;
+ }
+
+ bool isKernel() const {
+ return IsKernel;
+ }
+
+ unsigned allocateLDSGlobal(const DataLayout &DL, const GlobalValue &GV);
};
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp
index 8bc7b53..410bd52 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp
@@ -358,7 +358,7 @@ class AMDGPUOpenCLImageTypeLoweringPass : public ModulePass {
return transformKernels(M);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AMDGPU OpenCL Image Type Pass";
}
};
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUPTNote.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUPTNote.h
new file mode 100644
index 0000000..947d45b
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUPTNote.h
@@ -0,0 +1,42 @@
+//===-- AMDGPUNoteType.h - AMDGPU ELF PT_NOTE section info-------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// Enums and constants for AMDGPU PT_NOTE sections.
+///
+//
+//===----------------------------------------------------------------------===//
+//
+#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPUPTNOTE_H
+#define LLVM_LIB_TARGET_AMDGPU_AMDGPUPTNOTE_H
+
+namespace AMDGPU {
+
+namespace PT_NOTE {
+
+const char SectionName[] = ".note";
+
+const char NoteName[] = "AMD";
+
+enum NoteType{
+ NT_AMDGPU_HSA_CODE_OBJECT_VERSION = 1,
+ NT_AMDGPU_HSA_HSAIL = 2,
+ NT_AMDGPU_HSA_ISA = 3,
+ NT_AMDGPU_HSA_PRODUCER = 4,
+ NT_AMDGPU_HSA_PRODUCER_OPTIONS = 5,
+ NT_AMDGPU_HSA_EXTENSION = 6,
+ NT_AMDGPU_HSA_RUNTIME_METADATA = 7,
+ NT_AMDGPU_HSA_HLDEBUG_DEBUG = 101,
+ NT_AMDGPU_HSA_HLDEBUG_TARGET = 102
+};
+}
+}
+
+#endif // LLVM_LIB_TARGET_AMDGPU_AMDGPUNOTETYPE_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp
index 0bad63f..baa28de 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUPromoteAlloca.cpp
@@ -76,9 +76,7 @@ public:
bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
- const char *getPassName() const override {
- return "AMDGPU Promote Alloca";
- }
+ StringRef getPassName() const override { return "AMDGPU Promote Alloca"; }
void handleAlloca(AllocaInst &I);
@@ -184,13 +182,12 @@ bool AMDGPUPromoteAlloca::runOnFunction(Function &F) {
// TODO: Have some sort of hint or other heuristics to guess occupancy based
// on other factors..
- unsigned OccupancyHint
- = AMDGPU::getIntegerAttribute(F, "amdgpu-max-waves-per-eu", 0);
+ unsigned OccupancyHint = ST.getWavesPerEU(F).second;
if (OccupancyHint == 0)
OccupancyHint = 7;
// Clamp to max value.
- OccupancyHint = std::min(OccupancyHint, ST.getMaxWavesPerCU());
+ OccupancyHint = std::min(OccupancyHint, ST.getMaxWavesPerEU());
// Check the hint but ignore it if it's obviously wrong from the existing LDS
// usage.
@@ -535,7 +532,7 @@ bool AMDGPUPromoteAlloca::collectUsesWithPtrTypes(
std::vector<Value*> &WorkList) const {
for (User *User : Val->users()) {
- if (std::find(WorkList.begin(), WorkList.end(), User) != WorkList.end())
+ if (is_contained(WorkList, User))
continue;
if (CallInst *CI = dyn_cast<CallInst>(User)) {
@@ -550,7 +547,7 @@ bool AMDGPUPromoteAlloca::collectUsesWithPtrTypes(
if (UseInst->getOpcode() == Instruction::PtrToInt)
return false;
- if (LoadInst *LI = dyn_cast_or_null<LoadInst>(UseInst)) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(UseInst)) {
if (LI->isVolatile())
return false;
@@ -564,11 +561,10 @@ bool AMDGPUPromoteAlloca::collectUsesWithPtrTypes(
// Reject if the stored value is not the pointer operand.
if (SI->getPointerOperand() != Val)
return false;
- } else if (AtomicRMWInst *RMW = dyn_cast_or_null<AtomicRMWInst>(UseInst)) {
+ } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(UseInst)) {
if (RMW->isVolatile())
return false;
- } else if (AtomicCmpXchgInst *CAS
- = dyn_cast_or_null<AtomicCmpXchgInst>(UseInst)) {
+ } else if (AtomicCmpXchgInst *CAS = dyn_cast<AtomicCmpXchgInst>(UseInst)) {
if (CAS->isVolatile())
return false;
}
@@ -583,6 +579,12 @@ bool AMDGPUPromoteAlloca::collectUsesWithPtrTypes(
WorkList.push_back(ICmp);
}
+ if (UseInst->getOpcode() == Instruction::AddrSpaceCast) {
+ // Don't collect the users of this.
+ WorkList.push_back(User);
+ continue;
+ }
+
if (!User->getType()->isPointerTy())
continue;
@@ -651,9 +653,11 @@ void AMDGPUPromoteAlloca::handleAlloca(AllocaInst &I) {
if (AMDGPU::isShader(ContainingFunction.getCallingConv()))
return;
+ const AMDGPUSubtarget &ST =
+ TM->getSubtarget<AMDGPUSubtarget>(ContainingFunction);
// FIXME: We should also try to get this value from the reqd_work_group_size
// function attribute if it is available.
- unsigned WorkGroupSize = AMDGPU::getMaximumWorkGroupSize(ContainingFunction);
+ unsigned WorkGroupSize = ST.getFlatWorkGroupSizes(ContainingFunction).second;
const DataLayout &DL = Mod->getDataLayout();
@@ -741,7 +745,8 @@ void AMDGPUPromoteAlloca::handleAlloca(AllocaInst &I) {
continue;
}
- // The operand's value should be corrected on its own.
+ // The operand's value should be corrected on its own and we don't want to
+ // touch the users.
if (isa<AddrSpaceCastInst>(V))
continue;
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h
index 40f6394..ecd2ac7 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPURuntimeMetadata.h
@@ -13,18 +13,13 @@
///
/// Runtime requests certain information (metadata) about kernels to be able
/// to execute the kernels and answer the queries about the kernels.
-/// The metadata is represented as a byte stream in an ELF section of a
-/// binary (code object). The byte stream consists of key-value pairs.
-/// Each key is an 8 bit unsigned integer. Each value can be an integer,
-/// a string, or a stream of key-value pairs. There are 3 levels of key-value
-/// pair streams. At the beginning of the ELF section is the top level
-/// key-value pair stream. A kernel-level key-value pair stream starts after
-/// encountering KeyKernelBegin and ends immediately before encountering
-/// KeyKernelEnd. A kernel-argument-level key-value pair stream starts
-/// after encountering KeyArgBegin and ends immediately before encountering
-/// KeyArgEnd. A kernel-level key-value pair stream can only appear in a top
-/// level key-value pair stream. A kernel-argument-level key-value pair stream
-/// can only appear in a kernel-level key-value pair stream.
+/// The metadata is represented as a note element in the .note ELF section of a
+/// binary (code object). The desc field of the note element is a YAML string
+/// consisting of key-value pairs. Each key is a string. Each value can be
+/// an integer, a string, or an YAML sequence. There are 3 levels of YAML maps.
+/// At the beginning of the YAML string is the module level YAML map. A
+/// kernel-level YAML map is in the amd.Kernels sequence. A
+/// kernel-argument-level map is in the amd.Args sequence.
///
/// The format should be kept backward compatible. New enum values and bit
/// fields should be appended at the end. It is suggested to bump up the
@@ -37,77 +32,64 @@
#ifndef LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H
#define LLVM_LIB_TARGET_AMDGPU_AMDGPURUNTIMEMETADATA_H
-#include <stdint.h>
+#include <cstdint>
+#include <vector>
+#include <string>
namespace AMDGPU {
namespace RuntimeMD {
// Version and revision of runtime metadata
- const unsigned char MDVersion = 1;
+ const unsigned char MDVersion = 2;
const unsigned char MDRevision = 0;
- // ELF section name containing runtime metadata
- const char SectionName[] = ".AMDGPU.runtime_metadata";
-
- // Enumeration values of keys in runtime metadata.
- enum Key {
- KeyNull = 0, // Place holder. Ignored when encountered
- KeyMDVersion = 1, // Runtime metadata version
- KeyLanguage = 2, // Language
- KeyLanguageVersion = 3, // Language version
- KeyKernelBegin = 4, // Beginning of kernel-level stream
- KeyKernelEnd = 5, // End of kernel-level stream
- KeyKernelName = 6, // Kernel name
- KeyArgBegin = 7, // Beginning of kernel-arg-level stream
- KeyArgEnd = 8, // End of kernel-arg-level stream
- KeyArgSize = 9, // Kernel arg size
- KeyArgAlign = 10, // Kernel arg alignment
- KeyArgTypeName = 11, // Kernel type name
- KeyArgName = 12, // Kernel name
- KeyArgTypeKind = 13, // Kernel argument type kind
- KeyArgValueType = 14, // Kernel argument value type
- KeyArgAddrQual = 15, // Kernel argument address qualifier
- KeyArgAccQual = 16, // Kernel argument access qualifier
- KeyArgIsConst = 17, // Kernel argument is const qualified
- KeyArgIsRestrict = 18, // Kernel argument is restrict qualified
- KeyArgIsVolatile = 19, // Kernel argument is volatile qualified
- KeyArgIsPipe = 20, // Kernel argument is pipe qualified
- KeyReqdWorkGroupSize = 21, // Required work group size
- KeyWorkGroupSizeHint = 22, // Work group size hint
- KeyVecTypeHint = 23, // Vector type hint
- KeyKernelIndex = 24, // Kernel index for device enqueue
- KeySGPRs = 25, // Number of SGPRs
- KeyVGPRs = 26, // Number of VGPRs
- KeyMinWavesPerSIMD = 27, // Minimum number of waves per SIMD
- KeyMaxWavesPerSIMD = 28, // Maximum number of waves per SIMD
- KeyFlatWorkGroupSizeLimits = 29, // Flat work group size limits
- KeyMaxWorkGroupSize = 30, // Maximum work group size
- KeyNoPartialWorkGroups = 31, // No partial work groups
- };
-
- enum Language : uint8_t {
- OpenCL_C = 0,
- HCC = 1,
- OpenMP = 2,
- OpenCL_CPP = 3,
-};
-
- enum LanguageVersion : uint16_t {
- V100 = 100,
- V110 = 110,
- V120 = 120,
- V200 = 200,
- V210 = 210,
- };
+ // Name of keys for runtime metadata.
+ namespace KeyName {
+ const char MDVersion[] = "amd.MDVersion"; // Runtime metadata version
+ const char Language[] = "amd.Language"; // Language
+ const char LanguageVersion[] = "amd.LanguageVersion"; // Language version
+ const char Kernels[] = "amd.Kernels"; // Kernels
+ const char KernelName[] = "amd.KernelName"; // Kernel name
+ const char Args[] = "amd.Args"; // Kernel arguments
+ const char ArgSize[] = "amd.ArgSize"; // Kernel arg size
+ const char ArgAlign[] = "amd.ArgAlign"; // Kernel arg alignment
+ const char ArgTypeName[] = "amd.ArgTypeName"; // Kernel type name
+ const char ArgName[] = "amd.ArgName"; // Kernel name
+ const char ArgKind[] = "amd.ArgKind"; // Kernel argument kind
+ const char ArgValueType[] = "amd.ArgValueType"; // Kernel argument value type
+ const char ArgAddrQual[] = "amd.ArgAddrQual"; // Kernel argument address qualifier
+ const char ArgAccQual[] = "amd.ArgAccQual"; // Kernel argument access qualifier
+ const char ArgIsConst[] = "amd.ArgIsConst"; // Kernel argument is const qualified
+ const char ArgIsRestrict[] = "amd.ArgIsRestrict"; // Kernel argument is restrict qualified
+ const char ArgIsVolatile[] = "amd.ArgIsVolatile"; // Kernel argument is volatile qualified
+ const char ArgIsPipe[] = "amd.ArgIsPipe"; // Kernel argument is pipe qualified
+ const char ReqdWorkGroupSize[] = "amd.ReqdWorkGroupSize"; // Required work group size
+ const char WorkGroupSizeHint[] = "amd.WorkGroupSizeHint"; // Work group size hint
+ const char VecTypeHint[] = "amd.VecTypeHint"; // Vector type hint
+ const char KernelIndex[] = "amd.KernelIndex"; // Kernel index for device enqueue
+ const char NoPartialWorkGroups[] = "amd.NoPartialWorkGroups"; // No partial work groups
+ const char PrintfInfo[] = "amd.PrintfInfo"; // Prinf function call information
+ const char ArgActualAcc[] = "amd.ArgActualAcc"; // The actual kernel argument access qualifier
+ const char ArgPointeeAlign[] = "amd.ArgPointeeAlign"; // Alignment of pointee type
+ }
namespace KernelArg {
- enum TypeKind : uint8_t {
- Value = 0,
- Pointer = 1,
- Image = 2,
- Sampler = 3,
- Queue = 4,
+ enum Kind : uint8_t {
+ ByValue = 0,
+ GlobalBuffer = 1,
+ DynamicSharedPointer = 2,
+ Sampler = 3,
+ Image = 4,
+ Pipe = 5,
+ Queue = 6,
+ HiddenGlobalOffsetX = 7,
+ HiddenGlobalOffsetY = 8,
+ HiddenGlobalOffsetZ = 9,
+ HiddenNone = 10,
+ HiddenPrintfBuffer = 11,
+ HiddenDefaultQueue = 12,
+ HiddenCompletionAction = 13,
};
enum ValueType : uint16_t {
@@ -125,13 +107,86 @@ namespace RuntimeMD {
F64 = 11,
};
+ // Avoid using 'None' since it conflicts with a macro in X11 header file.
enum AccessQualifer : uint8_t {
- None = 0,
+ AccNone = 0,
ReadOnly = 1,
WriteOnly = 2,
ReadWrite = 3,
};
+
+ enum AddressSpaceQualifer : uint8_t {
+ Private = 0,
+ Global = 1,
+ Constant = 2,
+ Local = 3,
+ Generic = 4,
+ Region = 5,
+ };
} // namespace KernelArg
+
+ // Invalid values are used to indicate an optional key should not be emitted.
+ const uint8_t INVALID_ADDR_QUAL = 0xff;
+ const uint8_t INVALID_ACC_QUAL = 0xff;
+ const uint32_t INVALID_KERNEL_INDEX = ~0U;
+
+ namespace KernelArg {
+ // In-memory representation of kernel argument information.
+ struct Metadata {
+ uint32_t Size;
+ uint32_t Align;
+ uint32_t PointeeAlign;
+ uint8_t Kind;
+ uint16_t ValueType;
+ std::string TypeName;
+ std::string Name;
+ uint8_t AddrQual;
+ uint8_t AccQual;
+ uint8_t IsVolatile;
+ uint8_t IsConst;
+ uint8_t IsRestrict;
+ uint8_t IsPipe;
+ Metadata() : Size(0), Align(0), PointeeAlign(0), Kind(0), ValueType(0),
+ AddrQual(INVALID_ADDR_QUAL), AccQual(INVALID_ACC_QUAL), IsVolatile(0),
+ IsConst(0), IsRestrict(0), IsPipe(0) {}
+ };
+ }
+
+ namespace Kernel {
+ // In-memory representation of kernel information.
+ struct Metadata {
+ std::string Name;
+ std::string Language;
+ std::vector<uint8_t> LanguageVersion;
+ std::vector<uint32_t> ReqdWorkGroupSize;
+ std::vector<uint32_t> WorkGroupSizeHint;
+ std::string VecTypeHint;
+ uint32_t KernelIndex;
+ uint8_t NoPartialWorkGroups;
+ std::vector<KernelArg::Metadata> Args;
+ Metadata() : KernelIndex(INVALID_KERNEL_INDEX), NoPartialWorkGroups(0) {}
+ };
+ }
+
+ namespace Program {
+ // In-memory representation of program information.
+ struct Metadata {
+ std::vector<uint8_t> MDVersionSeq;
+ std::vector<std::string> PrintfInfo;
+ std::vector<Kernel::Metadata> Kernels;
+
+ explicit Metadata(){}
+
+ // Construct from an YAML string.
+ explicit Metadata(const std::string &YAML);
+
+ // Convert to YAML string.
+ std::string toYAML();
+
+ // Convert from YAML string.
+ static Metadata fromYAML(const std::string &S);
+ };
+ }
} // namespace RuntimeMD
} // namespace AMDGPU
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
index 10fa9cf..c35a67d 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
@@ -13,14 +13,10 @@
//===----------------------------------------------------------------------===//
#include "AMDGPUSubtarget.h"
-#include "R600ISelLowering.h"
-#include "R600InstrInfo.h"
-#include "SIFrameLowering.h"
-#include "SIISelLowering.h"
-#include "SIInstrInfo.h"
-#include "SIMachineFunctionInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/MachineScheduler.h"
+#include "llvm/Target/TargetFrameLowering.h"
+#include <algorithm>
using namespace llvm;
@@ -31,7 +27,7 @@ using namespace llvm;
#define GET_SUBTARGETINFO_CTOR
#include "AMDGPUGenSubtargetInfo.inc"
-AMDGPUSubtarget::~AMDGPUSubtarget() {}
+AMDGPUSubtarget::~AMDGPUSubtarget() = default;
AMDGPUSubtarget &
AMDGPUSubtarget::initializeSubtargetDependencies(const Triple &TT,
@@ -52,10 +48,18 @@ AMDGPUSubtarget::initializeSubtargetDependencies(const Triple &TT,
ParseSubtargetFeatures(GPU, FullFS);
+ // Unless +-flat-for-global is specified, turn on FlatForGlobal for all OS-es
+ // on VI and newer hardware to avoid assertion failures due to missing ADDR64
+ // variants of MUBUF instructions.
+ if (!hasAddr64() && !FS.contains("flat-for-global")) {
+ FlatForGlobal = true;
+ }
+
// FIXME: I don't think think Evergreen has any useful support for
// denormals, but should be checked. Should we issue a warning somewhere
// if someone tries to enable these?
if (getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS) {
+ FP16Denormals = false;
FP32Denormals = false;
FP64Denormals = false;
}
@@ -81,10 +85,12 @@ AMDGPUSubtarget::AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
FastFMAF32(false),
HalfRate64Ops(false),
+ FP16Denormals(false),
FP32Denormals(false),
FP64Denormals(false),
FPExceptions(false),
FlatForGlobal(false),
+ UnalignedScratchAccess(false),
UnalignedBufferAccess(false),
EnableXNACK(false),
@@ -107,6 +113,10 @@ AMDGPUSubtarget::AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
SGPRInitBug(false),
HasSMemRealTime(false),
Has16BitInsts(false),
+ HasMovrel(false),
+ HasVGPRIndexMode(false),
+ HasScalarStores(false),
+ HasInv2PiInlineImm(false),
FlatAddressSpace(false),
R600ALUInst(false),
@@ -114,6 +124,7 @@ AMDGPUSubtarget::AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
CFALUBug(false),
HasVertexCache(false),
TexVTXClauseSize(0),
+ ScalarizeGlobal(false),
FeatureDisable(false),
InstrItins(getInstrItineraryForCPU(GPU)) {
@@ -178,6 +189,86 @@ unsigned AMDGPUSubtarget::getOccupancyWithLocalMemSize(uint32_t Bytes) const {
return 1;
}
+std::pair<unsigned, unsigned> AMDGPUSubtarget::getFlatWorkGroupSizes(
+ const Function &F) const {
+ // Default minimum/maximum flat work group sizes.
+ std::pair<unsigned, unsigned> Default =
+ AMDGPU::isCompute(F.getCallingConv()) ?
+ std::pair<unsigned, unsigned>(getWavefrontSize() * 2,
+ getWavefrontSize() * 4) :
+ std::pair<unsigned, unsigned>(1, getWavefrontSize());
+
+ // TODO: Do not process "amdgpu-max-work-group-size" attribute once mesa
+ // starts using "amdgpu-flat-work-group-size" attribute.
+ Default.second = AMDGPU::getIntegerAttribute(
+ F, "amdgpu-max-work-group-size", Default.second);
+ Default.first = std::min(Default.first, Default.second);
+
+ // Requested minimum/maximum flat work group sizes.
+ std::pair<unsigned, unsigned> Requested = AMDGPU::getIntegerPairAttribute(
+ F, "amdgpu-flat-work-group-size", Default);
+
+ // Make sure requested minimum is less than requested maximum.
+ if (Requested.first > Requested.second)
+ return Default;
+
+ // Make sure requested values do not violate subtarget's specifications.
+ if (Requested.first < getMinFlatWorkGroupSize())
+ return Default;
+ if (Requested.second > getMaxFlatWorkGroupSize())
+ return Default;
+
+ return Requested;
+}
+
+std::pair<unsigned, unsigned> AMDGPUSubtarget::getWavesPerEU(
+ const Function &F) const {
+ // Default minimum/maximum number of waves per execution unit.
+ std::pair<unsigned, unsigned> Default(1, 0);
+
+ // Default/requested minimum/maximum flat work group sizes.
+ std::pair<unsigned, unsigned> FlatWorkGroupSizes = getFlatWorkGroupSizes(F);
+
+ // If minimum/maximum flat work group sizes were explicitly requested using
+ // "amdgpu-flat-work-group-size" attribute, then set default minimum/maximum
+ // number of waves per execution unit to values implied by requested
+ // minimum/maximum flat work group sizes.
+ unsigned MinImpliedByFlatWorkGroupSize =
+ getMaxWavesPerEU(FlatWorkGroupSizes.second);
+ bool RequestedFlatWorkGroupSize = false;
+
+ // TODO: Do not process "amdgpu-max-work-group-size" attribute once mesa
+ // starts using "amdgpu-flat-work-group-size" attribute.
+ if (F.hasFnAttribute("amdgpu-max-work-group-size") ||
+ F.hasFnAttribute("amdgpu-flat-work-group-size")) {
+ Default.first = MinImpliedByFlatWorkGroupSize;
+ RequestedFlatWorkGroupSize = true;
+ }
+
+ // Requested minimum/maximum number of waves per execution unit.
+ std::pair<unsigned, unsigned> Requested = AMDGPU::getIntegerPairAttribute(
+ F, "amdgpu-waves-per-eu", Default, true);
+
+ // Make sure requested minimum is less than requested maximum.
+ if (Requested.second && Requested.first > Requested.second)
+ return Default;
+
+ // Make sure requested values do not violate subtarget's specifications.
+ if (Requested.first < getMinWavesPerEU() ||
+ Requested.first > getMaxWavesPerEU())
+ return Default;
+ if (Requested.second > getMaxWavesPerEU())
+ return Default;
+
+ // Make sure requested values are compatible with values implied by requested
+ // minimum/maximum flat work group sizes.
+ if (RequestedFlatWorkGroupSize &&
+ Requested.first > MinImpliedByFlatWorkGroupSize)
+ return Default;
+
+ return Requested;
+}
+
R600Subtarget::R600Subtarget(const Triple &TT, StringRef GPU, StringRef FS,
const TargetMachine &TM) :
AMDGPUSubtarget(TT, GPU, FS, TM),
@@ -190,21 +281,7 @@ SISubtarget::SISubtarget(const Triple &TT, StringRef GPU, StringRef FS,
AMDGPUSubtarget(TT, GPU, FS, TM),
InstrInfo(*this),
FrameLowering(TargetFrameLowering::StackGrowsUp, getStackAlignment(), 0),
- TLInfo(TM, *this),
- GISel() {}
-
-unsigned R600Subtarget::getStackEntrySize() const {
- switch (getWavefrontSize()) {
- case 16:
- return 8;
- case 32:
- return hasCaymanISA() ? 4 : 8;
- case 64:
- return 4;
- default:
- llvm_unreachable("Illegal wavefront size.");
- }
-}
+ TLInfo(TM, *this) {}
void SISubtarget::overrideSchedPolicy(MachineSchedPolicy &Policy,
unsigned NumRegionInstrs) const {
@@ -227,15 +304,67 @@ bool SISubtarget::isVGPRSpillingEnabled(const Function& F) const {
return EnableVGPRSpilling || !AMDGPU::isShader(F.getCallingConv());
}
-unsigned SISubtarget::getAmdKernelCodeChipID() const {
- switch (getGeneration()) {
- case SEA_ISLANDS:
- return 12;
- default:
- llvm_unreachable("ChipID unknown");
+unsigned SISubtarget::getKernArgSegmentSize(const MachineFunction &MF,
+ unsigned ExplicitArgBytes) const {
+ unsigned ImplicitBytes = getImplicitArgNumBytes(MF);
+ if (ImplicitBytes == 0)
+ return ExplicitArgBytes;
+
+ unsigned Alignment = getAlignmentForImplicitArgPtr();
+ return alignTo(ExplicitArgBytes, Alignment) + ImplicitBytes;
+}
+
+unsigned SISubtarget::getOccupancyWithNumSGPRs(unsigned SGPRs) const {
+ if (getGeneration() >= SISubtarget::VOLCANIC_ISLANDS) {
+ if (SGPRs <= 80)
+ return 10;
+ if (SGPRs <= 88)
+ return 9;
+ if (SGPRs <= 100)
+ return 8;
+ return 7;
}
+ if (SGPRs <= 48)
+ return 10;
+ if (SGPRs <= 56)
+ return 9;
+ if (SGPRs <= 64)
+ return 8;
+ if (SGPRs <= 72)
+ return 7;
+ if (SGPRs <= 80)
+ return 6;
+ return 5;
}
-AMDGPU::IsaVersion SISubtarget::getIsaVersion() const {
- return AMDGPU::getIsaVersion(getFeatureBits());
+unsigned SISubtarget::getOccupancyWithNumVGPRs(unsigned VGPRs) const {
+ if (VGPRs <= 24)
+ return 10;
+ if (VGPRs <= 28)
+ return 9;
+ if (VGPRs <= 32)
+ return 8;
+ if (VGPRs <= 36)
+ return 7;
+ if (VGPRs <= 40)
+ return 6;
+ if (VGPRs <= 48)
+ return 5;
+ if (VGPRs <= 64)
+ return 4;
+ if (VGPRs <= 84)
+ return 3;
+ if (VGPRs <= 128)
+ return 2;
+ return 1;
+}
+
+unsigned SISubtarget::getMaxNumSGPRs() const {
+ if (hasSGPRInitBug())
+ return SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG;
+
+ if (getGeneration() >= VOLCANIC_ISLANDS)
+ return 102;
+
+ return 104;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h
index 3fe61aa..0e3cb7d 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h
@@ -23,15 +23,22 @@
#include "SIISelLowering.h"
#include "SIFrameLowering.h"
#include "Utils/AMDGPUBaseInfo.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
+#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <utility>
#define GET_SUBTARGETINFO_HEADER
#include "AMDGPUGenSubtargetInfo.inc"
namespace llvm {
-class SIMachineFunctionInfo;
class StringRef;
class AMDGPUSubtarget : public AMDGPUGenSubtargetInfo {
@@ -50,9 +57,13 @@ public:
ISAVersion0_0_0,
ISAVersion7_0_0,
ISAVersion7_0_1,
+ ISAVersion7_0_2,
ISAVersion8_0_0,
ISAVersion8_0_1,
- ISAVersion8_0_3
+ ISAVersion8_0_2,
+ ISAVersion8_0_3,
+ ISAVersion8_0_4,
+ ISAVersion8_1_0,
};
protected:
@@ -70,10 +81,12 @@ protected:
bool HalfRate64Ops;
// Dynamially set bits that enable features.
+ bool FP16Denormals;
bool FP32Denormals;
bool FP64Denormals;
bool FPExceptions;
bool FlatForGlobal;
+ bool UnalignedScratchAccess;
bool UnalignedBufferAccess;
bool EnableXNACK;
bool DebuggerInsertNops;
@@ -97,40 +110,60 @@ protected:
bool SGPRInitBug;
bool HasSMemRealTime;
bool Has16BitInsts;
+ bool HasMovrel;
+ bool HasVGPRIndexMode;
+ bool HasScalarStores;
+ bool HasInv2PiInlineImm;
bool FlatAddressSpace;
bool R600ALUInst;
bool CaymanISA;
bool CFALUBug;
bool HasVertexCache;
short TexVTXClauseSize;
+ bool ScalarizeGlobal;
// Dummy feature to use for assembler in tablegen.
bool FeatureDisable;
InstrItineraryData InstrItins;
+ SelectionDAGTargetInfo TSInfo;
public:
AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
const TargetMachine &TM);
- virtual ~AMDGPUSubtarget();
+ ~AMDGPUSubtarget() override;
+
AMDGPUSubtarget &initializeSubtargetDependencies(const Triple &TT,
StringRef GPU, StringRef FS);
- const AMDGPUInstrInfo *getInstrInfo() const override;
- const AMDGPUFrameLowering *getFrameLowering() const override;
- const AMDGPUTargetLowering *getTargetLowering() const override;
- const AMDGPURegisterInfo *getRegisterInfo() const override;
+ const AMDGPUInstrInfo *getInstrInfo() const override = 0;
+ const AMDGPUFrameLowering *getFrameLowering() const override = 0;
+ const AMDGPUTargetLowering *getTargetLowering() const override = 0;
+ const AMDGPURegisterInfo *getRegisterInfo() const override = 0;
const InstrItineraryData *getInstrItineraryData() const override {
return &InstrItins;
}
+ // Nothing implemented, just prevent crashes on use.
+ const SelectionDAGTargetInfo *getSelectionDAGInfo() const override {
+ return &TSInfo;
+ }
+
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
bool isAmdHsaOS() const {
return TargetTriple.getOS() == Triple::AMDHSA;
}
+ bool isMesa3DOS() const {
+ return TargetTriple.getOS() == Triple::Mesa3D;
+ }
+
+ bool isOpenCLEnv() const {
+ return TargetTriple.getEnvironment() == Triple::OpenCL;
+ }
+
Generation getGeneration() const {
return Gen;
}
@@ -151,6 +184,10 @@ public:
return MaxPrivateElementSize;
}
+ bool has16BitInsts() const {
+ return Has16BitInsts;
+ }
+
bool hasHWFP64() const {
return FP64;
}
@@ -230,6 +267,10 @@ public:
return DumpCode;
}
+ bool enableIEEEBit(const MachineFunction &MF) const {
+ return AMDGPU::isCompute(MF.getFunction()->getCallingConv());
+ }
+
/// Return the amount of LDS that can be used that will not restrict the
/// occupancy lower than WaveCount.
unsigned getMaxLocalMemSizeWithWaveCount(unsigned WaveCount) const;
@@ -238,6 +279,9 @@ public:
/// the given LDS memory size is the only constraint.
unsigned getOccupancyWithLocalMemSize(uint32_t Bytes) const;
+ bool hasFP16Denormals() const {
+ return FP16Denormals;
+ }
bool hasFP32Denormals() const {
return FP32Denormals;
@@ -259,22 +303,43 @@ public:
return UnalignedBufferAccess;
}
+ bool hasUnalignedScratchAccess() const {
+ return UnalignedScratchAccess;
+ }
+
bool isXNACKEnabled() const {
return EnableXNACK;
}
- unsigned getMaxWavesPerCU() const {
- if (getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS)
- return 10;
+ bool isMesaKernel(const MachineFunction &MF) const {
+ return isMesa3DOS() && !AMDGPU::isShader(MF.getFunction()->getCallingConv());
+ }
- // FIXME: Not sure what this is for other subtagets.
- return 8;
+ // Covers VS/PS/CS graphics shaders
+ bool isMesaGfxShader(const MachineFunction &MF) const {
+ return isMesa3DOS() && AMDGPU::isShader(MF.getFunction()->getCallingConv());
+ }
+
+ bool isAmdCodeObjectV2(const MachineFunction &MF) const {
+ return isAmdHsaOS() || isMesaKernel(MF);
}
/// \brief Returns the offset in bytes from the start of the input buffer
/// of the first explicit kernel argument.
- unsigned getExplicitKernelArgOffset() const {
- return isAmdHsaOS() ? 0 : 36;
+ unsigned getExplicitKernelArgOffset(const MachineFunction &MF) const {
+ return isAmdCodeObjectV2(MF) ? 0 : 36;
+ }
+
+ unsigned getAlignmentForImplicitArgPtr() const {
+ return isAmdHsaOS() ? 8 : 4;
+ }
+
+ unsigned getImplicitArgNumBytes(const MachineFunction &MF) const {
+ if (isMesaKernel(MF))
+ return 16;
+ if (isAmdHsaOS() && isOpenCLEnv())
+ return 32;
+ return 0;
}
unsigned getStackAlignment() const {
@@ -289,6 +354,92 @@ public:
bool enableSubRegLiveness() const override {
return true;
}
+
+ /// \returns Number of execution units per compute unit supported by the
+ /// subtarget.
+ unsigned getEUsPerCU() const {
+ return 4;
+ }
+
+ /// \returns Maximum number of work groups per compute unit supported by the
+ /// subtarget and limited by given flat work group size.
+ unsigned getMaxWorkGroupsPerCU(unsigned FlatWorkGroupSize) const {
+ if (getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
+ return 8;
+ return getWavesPerWorkGroup(FlatWorkGroupSize) == 1 ? 40 : 16;
+ }
+
+ /// \returns Maximum number of waves per compute unit supported by the
+ /// subtarget without any kind of limitation.
+ unsigned getMaxWavesPerCU() const {
+ return getMaxWavesPerEU() * getEUsPerCU();
+ }
+
+ /// \returns Maximum number of waves per compute unit supported by the
+ /// subtarget and limited by given flat work group size.
+ unsigned getMaxWavesPerCU(unsigned FlatWorkGroupSize) const {
+ return getWavesPerWorkGroup(FlatWorkGroupSize);
+ }
+
+ /// \returns Minimum number of waves per execution unit supported by the
+ /// subtarget.
+ unsigned getMinWavesPerEU() const {
+ return 1;
+ }
+
+ /// \returns Maximum number of waves per execution unit supported by the
+ /// subtarget without any kind of limitation.
+ unsigned getMaxWavesPerEU() const {
+ if (getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
+ return 8;
+ // FIXME: Need to take scratch memory into account.
+ return 10;
+ }
+
+ /// \returns Maximum number of waves per execution unit supported by the
+ /// subtarget and limited by given flat work group size.
+ unsigned getMaxWavesPerEU(unsigned FlatWorkGroupSize) const {
+ return alignTo(getMaxWavesPerCU(FlatWorkGroupSize), getEUsPerCU()) /
+ getEUsPerCU();
+ }
+
+ /// \returns Minimum flat work group size supported by the subtarget.
+ unsigned getMinFlatWorkGroupSize() const {
+ return 1;
+ }
+
+ /// \returns Maximum flat work group size supported by the subtarget.
+ unsigned getMaxFlatWorkGroupSize() const {
+ return 2048;
+ }
+
+ /// \returns Number of waves per work group given the flat work group size.
+ unsigned getWavesPerWorkGroup(unsigned FlatWorkGroupSize) const {
+ return alignTo(FlatWorkGroupSize, getWavefrontSize()) / getWavefrontSize();
+ }
+
+ void setScalarizeGlobalBehavior(bool b) { ScalarizeGlobal = b;}
+ bool getScalarizeGlobalBehavior() const { return ScalarizeGlobal;}
+
+ /// \returns Subtarget's default pair of minimum/maximum flat work group sizes
+ /// for function \p F, or minimum/maximum flat work group sizes explicitly
+ /// requested using "amdgpu-flat-work-group-size" attribute attached to
+ /// function \p F.
+ ///
+ /// \returns Subtarget's default values if explicitly requested values cannot
+ /// be converted to integer, or violate subtarget's specifications.
+ std::pair<unsigned, unsigned> getFlatWorkGroupSizes(const Function &F) const;
+
+ /// \returns Subtarget's default pair of minimum/maximum number of waves per
+ /// execution unit for function \p F, or minimum/maximum number of waves per
+ /// execution unit explicitly requested using "amdgpu-waves-per-eu" attribute
+ /// attached to function \p F.
+ ///
+ /// \returns Subtarget's default values if explicitly requested values cannot
+ /// be converted to integer, violate subtarget's specifications, or are not
+ /// compatible with minimum/maximum number of waves limited by flat work group
+ /// size, register usage, and/or lds usage.
+ std::pair<unsigned, unsigned> getWavesPerEU(const Function &F) const;
};
class R600Subtarget final : public AMDGPUSubtarget {
@@ -328,14 +479,14 @@ public:
short getTexVTXClauseSize() const {
return TexVTXClauseSize;
}
-
- unsigned getStackEntrySize() const;
};
class SISubtarget final : public AMDGPUSubtarget {
public:
enum {
- FIXED_SGPR_COUNT_FOR_INIT_BUG = 80
+ // The closed Vulkan driver sets 96, which limits the wave count to 8 but
+ // doesn't spill SGPRs as much as when 80 is set.
+ FIXED_SGPR_COUNT_FOR_INIT_BUG = 96
};
private:
@@ -378,10 +529,6 @@ public:
bool isVGPRSpillingEnabled(const Function& F) const;
- unsigned getAmdKernelCodeChipID() const;
-
- AMDGPU::IsaVersion getIsaVersion() const;
-
unsigned getMaxNumUserSGPRs() const {
return 16;
}
@@ -394,8 +541,24 @@ public:
return HasSMemRealTime;
}
- bool has16BitInsts() const {
- return Has16BitInsts;
+ bool hasMovrel() const {
+ return HasMovrel;
+ }
+
+ bool hasVGPRIndexMode() const {
+ return HasVGPRIndexMode;
+ }
+
+ bool hasScalarCompareEq64() const {
+ return getGeneration() >= VOLCANIC_ISLANDS;
+ }
+
+ bool hasScalarStores() const {
+ return HasScalarStores;
+ }
+
+ bool hasInv2PiInlineImm() const {
+ return HasInv2PiInlineImm;
}
bool enableSIScheduler() const {
@@ -426,37 +589,28 @@ public:
bool hasSGPRInitBug() const {
return SGPRInitBug;
}
-};
-
-
-inline const AMDGPUInstrInfo *AMDGPUSubtarget::getInstrInfo() const {
- if (getGeneration() >= SOUTHERN_ISLANDS)
- return static_cast<const SISubtarget *>(this)->getInstrInfo();
-
- return static_cast<const R600Subtarget *>(this)->getInstrInfo();
-}
-inline const AMDGPUFrameLowering *AMDGPUSubtarget::getFrameLowering() const {
- if (getGeneration() >= SOUTHERN_ISLANDS)
- return static_cast<const SISubtarget *>(this)->getFrameLowering();
+ bool has12DWordStoreHazard() const {
+ return getGeneration() != AMDGPUSubtarget::SOUTHERN_ISLANDS;
+ }
- return static_cast<const R600Subtarget *>(this)->getFrameLowering();
-}
+ unsigned getKernArgSegmentSize(const MachineFunction &MF, unsigned ExplictArgBytes) const;
-inline const AMDGPUTargetLowering *AMDGPUSubtarget::getTargetLowering() const {
- if (getGeneration() >= SOUTHERN_ISLANDS)
- return static_cast<const SISubtarget *>(this)->getTargetLowering();
+ /// Return the maximum number of waves per SIMD for kernels using \p SGPRs SGPRs
+ unsigned getOccupancyWithNumSGPRs(unsigned SGPRs) const;
- return static_cast<const R600Subtarget *>(this)->getTargetLowering();
-}
+ /// Return the maximum number of waves per SIMD for kernels using \p VGPRs VGPRs
+ unsigned getOccupancyWithNumVGPRs(unsigned VGPRs) const;
-inline const AMDGPURegisterInfo *AMDGPUSubtarget::getRegisterInfo() const {
- if (getGeneration() >= SOUTHERN_ISLANDS)
- return static_cast<const SISubtarget *>(this)->getRegisterInfo();
+ /// \returns True if waitcnt instruction is needed before barrier instruction,
+ /// false otherwise.
+ bool needWaitcntBeforeBarrier() const {
+ return true;
+ }
- return static_cast<const R600Subtarget *>(this)->getRegisterInfo();
-}
+ unsigned getMaxNumSGPRs() const;
+};
-} // End namespace llvm
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_AMDGPU_AMDGPUSUBTARGET_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index b2d4e11..d8a0c71 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -18,28 +18,32 @@
#include "AMDGPUCallLowering.h"
#include "AMDGPUTargetObjectFile.h"
#include "AMDGPUTargetTransformInfo.h"
-#include "R600ISelLowering.h"
-#include "R600InstrInfo.h"
+#include "GCNSchedStrategy.h"
#include "R600MachineScheduler.h"
-#include "SIISelLowering.h"
-#include "SIInstrInfo.h"
-
-#include "llvm/Analysis/Passes.h"
+#include "SIMachineScheduler.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/CodeGen/TargetPassConfig.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Vectorize.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include <memory>
using namespace llvm;
@@ -64,13 +68,20 @@ static cl::opt<bool> EnableR600IfConvert(
static cl::opt<bool> EnableLoadStoreVectorizer(
"amdgpu-load-store-vectorizer",
cl::desc("Enable load store vectorizer"),
+ cl::init(true),
+ cl::Hidden);
+
+// Option to to control global loads scalarization
+static cl::opt<bool> ScalarizeGlobal(
+ "amdgpu-scalarize-global-loads",
+ cl::desc("Enable global load scalarization"),
cl::init(false),
cl::Hidden);
extern "C" void LLVMInitializeAMDGPUTarget() {
// Register the target
- RegisterTargetMachine<R600TargetMachine> X(TheAMDGPUTarget);
- RegisterTargetMachine<GCNTargetMachine> Y(TheGCNTarget);
+ RegisterTargetMachine<R600TargetMachine> X(getTheAMDGPUTarget());
+ RegisterTargetMachine<GCNTargetMachine> Y(getTheGCNTarget());
PassRegistry *PR = PassRegistry::getPassRegistry();
initializeSILowerI1CopiesPass(*PR);
@@ -83,20 +94,36 @@ extern "C" void LLVMInitializeAMDGPUTarget() {
initializeAMDGPUAnnotateUniformValuesPass(*PR);
initializeAMDGPUPromoteAllocaPass(*PR);
initializeAMDGPUCodeGenPreparePass(*PR);
+ initializeAMDGPUUnifyMetadataPass(*PR);
initializeSIAnnotateControlFlowPass(*PR);
- initializeSIDebuggerInsertNopsPass(*PR);
initializeSIInsertWaitsPass(*PR);
initializeSIWholeQuadModePass(*PR);
initializeSILowerControlFlowPass(*PR);
+ initializeSIInsertSkipsPass(*PR);
initializeSIDebuggerInsertNopsPass(*PR);
+ initializeSIOptimizeExecMaskingPass(*PR);
}
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
- return make_unique<AMDGPUTargetObjectFile>();
+ return llvm::make_unique<AMDGPUTargetObjectFile>();
}
static ScheduleDAGInstrs *createR600MachineScheduler(MachineSchedContext *C) {
- return new ScheduleDAGMILive(C, make_unique<R600SchedStrategy>());
+ return new ScheduleDAGMILive(C, llvm::make_unique<R600SchedStrategy>());
+}
+
+static ScheduleDAGInstrs *createSIMachineScheduler(MachineSchedContext *C) {
+ return new SIScheduleDAGMI(C);
+}
+
+static ScheduleDAGInstrs *
+createGCNMaxOccupancyMachineScheduler(MachineSchedContext *C) {
+ ScheduleDAGMILive *DAG =
+ new ScheduleDAGMILive(C,
+ llvm::make_unique<GCNMaxOccupancySchedStrategy>(C));
+ DAG->addMutation(createLoadClusterDAGMutation(DAG->TII, DAG->TRI));
+ DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI));
+ return DAG;
}
static MachineSchedRegistry
@@ -107,6 +134,11 @@ static MachineSchedRegistry
SISchedRegistry("si", "Run SI's custom scheduler",
createSIMachineScheduler);
+static MachineSchedRegistry
+GCNMaxOccupancySchedRegistry("gcn-max-occupancy",
+ "Run GCN scheduler to maximize occupancy",
+ createGCNMaxOccupancyMachineScheduler);
+
static StringRef computeDataLayout(const Triple &TT) {
if (TT.getArch() == Triple::r600) {
// 32-bit pointers.
@@ -147,13 +179,11 @@ AMDGPUTargetMachine::AMDGPUTargetMachine(const Target &T, const Triple &TT,
CodeGenOpt::Level OptLevel)
: LLVMTargetMachine(T, computeDataLayout(TT), TT, getGPUOrDefault(TT, CPU),
FS, Options, getEffectiveRelocModel(RM), CM, OptLevel),
- TLOF(createTLOF(getTargetTriple())),
- IntrinsicInfo() {
- setRequiresStructuredCFG(true);
+ TLOF(createTLOF(getTargetTriple())) {
initAsmInfo();
}
-AMDGPUTargetMachine::~AMDGPUTargetMachine() { }
+AMDGPUTargetMachine::~AMDGPUTargetMachine() = default;
StringRef AMDGPUTargetMachine::getGPUName(const Function &F) const {
Attribute GPUAttr = F.getFnAttribute("target-cpu");
@@ -169,6 +199,10 @@ StringRef AMDGPUTargetMachine::getFeatureString(const Function &F) const {
FSAttr.getValueAsString();
}
+void AMDGPUTargetMachine::addEarlyAsPossiblePasses(PassManagerBase &PM) {
+ PM.add(createAMDGPUUnifyMetadataPass());
+}
+
//===----------------------------------------------------------------------===//
// R600 Target Machine (R600 -> Cayman)
//===----------------------------------------------------------------------===//
@@ -178,7 +212,9 @@ R600TargetMachine::R600TargetMachine(const Target &T, const Triple &TT,
TargetOptions Options,
Optional<Reloc::Model> RM,
CodeModel::Model CM, CodeGenOpt::Level OL)
- : AMDGPUTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL) {}
+ : AMDGPUTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL) {
+ setRequiresStructuredCFG(true);
+}
const R600Subtarget *R600TargetMachine::getSubtargetImpl(
const Function &F) const {
@@ -206,13 +242,15 @@ const R600Subtarget *R600TargetMachine::getSubtargetImpl(
#ifdef LLVM_BUILD_GLOBAL_ISEL
namespace {
+
struct SIGISelActualAccessor : public GISelAccessor {
std::unique_ptr<AMDGPUCallLowering> CallLoweringInfo;
const AMDGPUCallLowering *getCallLowering() const override {
return CallLoweringInfo.get();
}
};
-} // End anonymous namespace.
+
+} // end anonymous namespace
#endif
GCNTargetMachine::GCNTargetMachine(const Target &T, const Triple &TT,
@@ -248,6 +286,8 @@ const SISubtarget *GCNTargetMachine::getSubtargetImpl(const Function &F) const {
I->setGISelAccessor(*GISel);
}
+ I->setScalarizeGlobalBehavior(ScalarizeGlobal);
+
return I.get();
}
@@ -261,7 +301,6 @@ class AMDGPUPassConfig : public TargetPassConfig {
public:
AMDGPUPassConfig(TargetMachine *TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {
-
// Exceptions and StackMaps are not supported, so these passes will never do
// anything.
disablePass(&StackMapLivenessID);
@@ -272,6 +311,14 @@ public:
return getTM<AMDGPUTargetMachine>();
}
+ ScheduleDAGInstrs *
+ createMachineScheduler(MachineSchedContext *C) const override {
+ ScheduleDAGMILive *DAG = createGenericSchedLive(C);
+ DAG->addMutation(createLoadClusterDAGMutation(DAG->TII, DAG->TRI));
+ DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI));
+ return DAG;
+ }
+
void addEarlyCSEOrGVNPass();
void addStraightLineScalarOptimizationPasses();
void addIRPasses() override;
@@ -284,7 +331,7 @@ public:
class R600PassConfig final : public AMDGPUPassConfig {
public:
R600PassConfig(TargetMachine *TM, PassManagerBase &PM)
- : AMDGPUPassConfig(TM, PM) { }
+ : AMDGPUPassConfig(TM, PM) {}
ScheduleDAGInstrs *createMachineScheduler(
MachineSchedContext *C) const override {
@@ -300,7 +347,7 @@ public:
class GCNPassConfig final : public AMDGPUPassConfig {
public:
GCNPassConfig(TargetMachine *TM, PassManagerBase &PM)
- : AMDGPUPassConfig(TM, PM) { }
+ : AMDGPUPassConfig(TM, PM) {}
GCNTargetMachine &getGCNTargetMachine() const {
return getTM<GCNTargetMachine>();
@@ -315,16 +362,19 @@ public:
bool addInstSelector() override;
#ifdef LLVM_BUILD_GLOBAL_ISEL
bool addIRTranslator() override;
+ bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
+ bool addGlobalInstructionSelect() override;
#endif
void addFastRegAlloc(FunctionPass *RegAllocPass) override;
void addOptimizedRegAlloc(FunctionPass *RegAllocPass) override;
void addPreRegAlloc() override;
+ void addPostRegAlloc() override;
void addPreSched2() override;
void addPreEmitPass() override;
};
-} // End of anonymous namespace
+} // end anonymous namespace
TargetIRAnalysis AMDGPUTargetMachine::getTargetIRAnalysis() {
return TargetIRAnalysis([this](const Function &F) {
@@ -363,7 +413,7 @@ void AMDGPUPassConfig::addIRPasses() {
// Function calls are not supported, so make sure we inline everything.
addPass(createAMDGPUAlwaysInlinePass());
- addPass(createAlwaysInlinerPass());
+ addPass(createAlwaysInlinerLegacyPass());
// We need to add the barrier noop pass, otherwise adding the function
// inlining pass will cause all of the PassConfigs passes to be run
// one function at a time, which means if we have a nodule with two
@@ -380,9 +430,9 @@ void AMDGPUPassConfig::addIRPasses() {
if (EnableSROA)
addPass(createSROAPass());
- }
- addStraightLineScalarOptimizationPasses();
+ addStraightLineScalarOptimizationPasses();
+ }
TargetPassConfig::addIRPasses();
@@ -415,7 +465,7 @@ bool AMDGPUPassConfig::addPreISel() {
}
bool AMDGPUPassConfig::addInstSelector() {
- addPass(createAMDGPUISelDag(getAMDGPUTargetMachine()));
+ addPass(createAMDGPUISelDag(getAMDGPUTargetMachine(), getOptLevel()));
return false;
}
@@ -468,7 +518,7 @@ ScheduleDAGInstrs *GCNPassConfig::createMachineScheduler(
const SISubtarget &ST = C->MF->getSubtarget<SISubtarget>();
if (ST.enableSIScheduler())
return createSIMachineScheduler(C);
- return nullptr;
+ return createGCNMaxOccupancyMachineScheduler(C);
}
bool GCNPassConfig::addPreISel() {
@@ -498,6 +548,7 @@ void GCNPassConfig::addMachineSSAOptimization() {
// XXX - Can we get away without running DeadMachineInstructionElim again?
addPass(&SIFoldOperandsID);
addPass(&DeadMachineInstructionElimID);
+ addPass(&SILoadStoreOptimizerID);
}
void GCNPassConfig::addIRPasses() {
@@ -520,43 +571,54 @@ bool GCNPassConfig::addIRTranslator() {
return false;
}
+bool GCNPassConfig::addLegalizeMachineIR() {
+ return false;
+}
+
bool GCNPassConfig::addRegBankSelect() {
return false;
}
+
+bool GCNPassConfig::addGlobalInstructionSelect() {
+ return false;
+}
#endif
void GCNPassConfig::addPreRegAlloc() {
- // This needs to be run directly before register allocation because
- // earlier passes might recompute live intervals.
- // TODO: handle CodeGenOpt::None; fast RA ignores spill weights set by the pass
- if (getOptLevel() > CodeGenOpt::None) {
- insertPass(&MachineSchedulerID, &SIFixControlFlowLiveIntervalsID);
- }
-
- if (getOptLevel() > CodeGenOpt::None) {
- // Don't do this with no optimizations since it throws away debug info by
- // merging nonadjacent loads.
-
- // This should be run after scheduling, but before register allocation. It
- // also need extra copies to the address operand to be eliminated.
-
- // FIXME: Move pre-RA and remove extra reg coalescer run.
- insertPass(&MachineSchedulerID, &SILoadStoreOptimizerID);
- insertPass(&MachineSchedulerID, &RegisterCoalescerID);
- }
-
addPass(createSIShrinkInstructionsPass());
addPass(createSIWholeQuadModePass());
}
void GCNPassConfig::addFastRegAlloc(FunctionPass *RegAllocPass) {
+ // FIXME: We have to disable the verifier here because of PHIElimination +
+ // TwoAddressInstructions disabling it.
+
+ // This must be run immediately after phi elimination and before
+ // TwoAddressInstructions, otherwise the processing of the tied operand of
+ // SI_ELSE will introduce a copy of the tied operand source after the else.
+ insertPass(&PHIEliminationID, &SILowerControlFlowID, false);
+
TargetPassConfig::addFastRegAlloc(RegAllocPass);
}
void GCNPassConfig::addOptimizedRegAlloc(FunctionPass *RegAllocPass) {
+ // This needs to be run directly before register allocation because earlier
+ // passes might recompute live intervals.
+ insertPass(&MachineSchedulerID, &SIFixControlFlowLiveIntervalsID);
+
+ // This must be run immediately after phi elimination and before
+ // TwoAddressInstructions, otherwise the processing of the tied operand of
+ // SI_ELSE will introduce a copy of the tied operand source after the else.
+ insertPass(&PHIEliminationID, &SILowerControlFlowID, false);
+
TargetPassConfig::addOptimizedRegAlloc(RegAllocPass);
}
+void GCNPassConfig::addPostRegAlloc() {
+ addPass(&SIOptimizeExecMaskingID);
+ TargetPassConfig::addPostRegAlloc();
+}
+
void GCNPassConfig::addPreSched2() {
}
@@ -573,8 +635,9 @@ void GCNPassConfig::addPreEmitPass() {
addPass(createSIInsertWaitsPass());
addPass(createSIShrinkInstructionsPass());
- addPass(createSILowerControlFlowPass());
+ addPass(&SIInsertSkipsPassID);
addPass(createSIDebuggerInsertNopsPass());
+ addPass(&BranchRelaxationPassID);
}
TargetPassConfig *GCNTargetMachine::createPassConfig(PassManagerBase &PM) {
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
index b0eb3a9..9496773 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
@@ -17,6 +17,13 @@
#include "AMDGPUIntrinsicInfo.h"
#include "AMDGPUSubtarget.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Target/TargetMachine.h"
+#include <memory>
namespace llvm {
@@ -37,10 +44,10 @@ public:
StringRef FS, TargetOptions Options,
Optional<Reloc::Model> RM, CodeModel::Model CM,
CodeGenOpt::Level OL);
- ~AMDGPUTargetMachine();
+ ~AMDGPUTargetMachine() override;
const AMDGPUSubtarget *getSubtargetImpl() const;
- const AMDGPUSubtarget *getSubtargetImpl(const Function &) const override;
+ const AMDGPUSubtarget *getSubtargetImpl(const Function &) const override = 0;
const AMDGPUIntrinsicInfo *getIntrinsicInfo() const override {
return &IntrinsicInfo;
@@ -50,6 +57,7 @@ public:
TargetLoweringObjectFile *getObjFileLowering() const override {
return TLOF.get();
}
+ void addEarlyAsPossiblePasses(PassManagerBase &PM) override;
};
//===----------------------------------------------------------------------===//
@@ -90,13 +98,6 @@ public:
const SISubtarget *getSubtargetImpl(const Function &) const override;
};
-inline const AMDGPUSubtarget *AMDGPUTargetMachine::getSubtargetImpl(
- const Function &F) const {
- if (getTargetTriple().getArch() == Triple::amdgcn)
- return static_cast<const GCNTargetMachine *>(this)->getSubtargetImpl(F);
- return static_cast<const R600TargetMachine *>(this)->getSubtargetImpl(F);
-}
+} // end namespace llvm
-} // End namespace llvm
-
-#endif
+#endif // LLVM_LIB_TARGET_AMDGPU_AMDGPUTARGETMACHINE_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp
index 03d1e2c..1fddc88 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.cpp
@@ -9,10 +9,10 @@
#include "AMDGPUTargetObjectFile.h"
#include "AMDGPU.h"
-#include "Utils/AMDGPUBaseInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/Support/ELF.h"
+#include "Utils/AMDGPUBaseInfo.h"
using namespace llvm;
@@ -20,12 +20,11 @@ using namespace llvm;
// Generic Object File
//===----------------------------------------------------------------------===//
-MCSection *AMDGPUTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind,
- Mangler &Mang,
- const TargetMachine &TM) const {
- if (Kind.isReadOnly() && AMDGPU::isReadOnlySegment(GV))
+MCSection *AMDGPUTargetObjectFile::SelectSectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ if (Kind.isReadOnly() && AMDGPU::isReadOnlySegment(GO) &&
+ AMDGPU::shouldEmitConstantsToTextSection(TM.getTargetTriple()))
return TextSection;
- return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang, TM);
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.h
index f530e09..de32778 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetObjectFile.h
@@ -23,8 +23,7 @@ namespace llvm {
class AMDGPUTargetObjectFile : public TargetLoweringObjectFileELF {
public:
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
};
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
index 3d630fe..e904870 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp
@@ -80,7 +80,7 @@ unsigned AMDGPUTTIImpl::getRegisterBitWidth(bool Vector) {
return Vector ? 0 : 32;
}
-unsigned AMDGPUTTIImpl::getLoadStoreVecRegBitWidth(unsigned AddrSpace) {
+unsigned AMDGPUTTIImpl::getLoadStoreVecRegBitWidth(unsigned AddrSpace) const {
switch (AddrSpace) {
case AMDGPUAS::GLOBAL_ADDRESS:
case AMDGPUAS::CONSTANT_ADDRESS:
@@ -110,7 +110,7 @@ unsigned AMDGPUTTIImpl::getMaxInterleaveFactor(unsigned VF) {
int AMDGPUTTIImpl::getArithmeticInstrCost(
unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info,
TTI::OperandValueKind Opd2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ TTI::OperandValueProperties Opd2PropInfo, ArrayRef<const Value *> Args ) {
EVT OrigTy = TLI->getValueType(DL, Ty);
if (!OrigTy.isSimple()) {
@@ -241,6 +241,7 @@ static bool isIntrinsicSourceOfDivergence(const TargetIntrinsicInfo *TII,
case Intrinsic::amdgcn_workitem_id_x:
case Intrinsic::amdgcn_workitem_id_y:
case Intrinsic::amdgcn_workitem_id_z:
+ case Intrinsic::amdgcn_interp_mov:
case Intrinsic::amdgcn_interp_p1:
case Intrinsic::amdgcn_interp_p2:
case Intrinsic::amdgcn_mbcnt_hi:
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
index a82a074..0d83b2a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h
@@ -64,13 +64,6 @@ public:
ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- AMDGPUTTIImpl(const AMDGPUTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- AMDGPUTTIImpl(AMDGPUTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
bool hasBranchDivergence() { return true; }
void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP);
@@ -82,7 +75,7 @@ public:
unsigned getNumberOfRegisters(bool Vector);
unsigned getRegisterBitWidth(bool Vector);
- unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace);
+ unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const;
unsigned getMaxInterleaveFactor(unsigned VF);
int getArithmeticInstrCost(
@@ -90,7 +83,8 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
unsigned getCFInstrCost(unsigned Opcode);
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp
new file mode 100644
index 0000000..bf501a1
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUUnifyMetadata.cpp
@@ -0,0 +1,149 @@
+//===-- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// \brief This pass that unifies multiple OpenCL metadata due to linking.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+
+using namespace llvm;
+
+namespace {
+ namespace kOCLMD {
+ const char SpirVer[] = "opencl.spir.version";
+ const char OCLVer[] = "opencl.ocl.version";
+ const char UsedExt[] = "opencl.used.extensions";
+ const char UsedOptCoreFeat[] = "opencl.used.optional.core.features";
+ const char CompilerOptions[] = "opencl.compiler.options";
+ const char LLVMIdent[] = "llvm.ident";
+ }
+
+ /// \brief Unify multiple OpenCL metadata due to linking.
+ class AMDGPUUnifyMetadata : public FunctionPass {
+ public:
+ static char ID;
+ explicit AMDGPUUnifyMetadata() : FunctionPass(ID) {};
+
+ private:
+ // This should really be a module pass but we have to run it as early
+ // as possible, so given function passes are executed first and
+ // TargetMachine::addEarlyAsPossiblePasses() expects only function passes
+ // it has to be a function pass.
+ virtual bool runOnModule(Module &M);
+
+ // \todo: Convert to a module pass.
+ virtual bool runOnFunction(Function &F);
+
+ /// \brief Unify version metadata.
+ /// \return true if changes are made.
+ /// Assume the named metadata has operands each of which is a pair of
+ /// integer constant, e.g.
+ /// !Name = {!n1, !n2}
+ /// !n1 = {i32 1, i32 2}
+ /// !n2 = {i32 2, i32 0}
+ /// Keep the largest version as the sole operand if PickFirst is false.
+ /// Otherwise pick it from the first value, representing kernel module.
+ bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) {
+ auto NamedMD = M.getNamedMetadata(Name);
+ if (!NamedMD || NamedMD->getNumOperands() <= 1)
+ return false;
+ MDNode *MaxMD = nullptr;
+ auto MaxVer = 0U;
+ for (const auto &VersionMD : NamedMD->operands()) {
+ assert(VersionMD->getNumOperands() == 2);
+ auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0));
+ auto VersionMajor = CMajor->getZExtValue();
+ auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1));
+ auto VersionMinor = CMinor->getZExtValue();
+ auto Ver = (VersionMajor * 100) + (VersionMinor * 10);
+ if (Ver > MaxVer) {
+ MaxVer = Ver;
+ MaxMD = VersionMD;
+ }
+ if (PickFirst)
+ break;
+ }
+ NamedMD->eraseFromParent();
+ NamedMD = M.getOrInsertNamedMetadata(Name);
+ NamedMD->addOperand(MaxMD);
+ return true;
+ }
+
+ /// \brief Unify version metadata.
+ /// \return true if changes are made.
+ /// Assume the named metadata has operands each of which is a list e.g.
+ /// !Name = {!n1, !n2}
+ /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}}
+ /// !n2 = !{!"cl_khr_image"}
+ /// Combine it into a single list with unique operands.
+ bool unifyExtensionMD(Module &M, StringRef Name) {
+ auto NamedMD = M.getNamedMetadata(Name);
+ if (!NamedMD || NamedMD->getNumOperands() == 1)
+ return false;
+
+ SmallVector<Metadata *, 4> All;
+ for (const auto &MD : NamedMD->operands())
+ for (const auto &Op : MD->operands())
+ if (std::find(All.begin(), All.end(), Op.get()) == All.end())
+ All.push_back(Op.get());
+
+ NamedMD->eraseFromParent();
+ NamedMD = M.getOrInsertNamedMetadata(Name);
+ for (const auto &MD : All)
+ NamedMD->addOperand(MDNode::get(M.getContext(), MD));
+
+ return true;
+ }
+};
+
+} // end anonymous namespace
+
+char AMDGPUUnifyMetadata::ID = 0;
+
+char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
+
+INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
+ "Unify multiple OpenCL metadata due to linking",
+ false, false)
+
+FunctionPass* llvm::createAMDGPUUnifyMetadataPass() {
+ return new AMDGPUUnifyMetadata();
+}
+
+bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
+ const char* Vers[] = {
+ kOCLMD::SpirVer,
+ kOCLMD::OCLVer
+ };
+ const char* Exts[] = {
+ kOCLMD::UsedExt,
+ kOCLMD::UsedOptCoreFeat,
+ kOCLMD::CompilerOptions,
+ kOCLMD::LLVMIdent
+ };
+
+ bool Changed = false;
+
+ for (auto &I : Vers)
+ Changed |= unifyVersionMD(M, I, true);
+
+ for (auto &I : Exts)
+ Changed |= unifyExtensionMD(M, I);
+
+ return Changed;
+}
+
+bool AMDGPUUnifyMetadata::runOnFunction(Function &F) {
+ return runOnModule(*F.getParent());
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp
index 21de763..7faeccd 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AMDILCFGStructurizer.cpp
@@ -18,7 +18,6 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
@@ -139,16 +138,15 @@ public:
initializeAMDGPUCFGStructurizerPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "AMDGPU Control Flow Graph structurizer Pass";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addPreserved<MachineFunctionAnalysis>();
- AU.addRequired<MachineFunctionAnalysis>();
AU.addRequired<MachineDominatorTree>();
AU.addRequired<MachinePostDominatorTree>();
AU.addRequired<MachineLoopInfo>();
+ MachineFunctionPass::getAnalysisUsage(AU);
}
/// Perform the CFG structurization
@@ -220,7 +218,8 @@ protected:
bool needMigrateBlock(MachineBasicBlock *MBB) const;
// Utility Functions
- void reversePredicateSetter(MachineBasicBlock::iterator I);
+ void reversePredicateSetter(MachineBasicBlock::iterator I,
+ MachineBasicBlock &MBB);
/// Compute the reversed DFS post order of Blocks
void orderBlocks(MachineFunction *MF);
@@ -422,26 +421,24 @@ bool AMDGPUCFGStructurizer::needMigrateBlock(MachineBasicBlock *MBB) const {
}
void AMDGPUCFGStructurizer::reversePredicateSetter(
- MachineBasicBlock::iterator I) {
- assert(static_cast<MachineInstr *>(I) && "Expected valid iterator");
+ MachineBasicBlock::iterator I, MachineBasicBlock &MBB) {
+ assert(I.isValid() && "Expected valid iterator");
for (;; --I) {
+ if (I == MBB.end())
+ continue;
if (I->getOpcode() == AMDGPU::PRED_X) {
- switch (static_cast<MachineInstr *>(I)->getOperand(2).getImm()) {
- case OPCODE_IS_ZERO_INT:
- static_cast<MachineInstr *>(I)->getOperand(2)
- .setImm(OPCODE_IS_NOT_ZERO_INT);
+ switch (I->getOperand(2).getImm()) {
+ case AMDGPU::PRED_SETE_INT:
+ I->getOperand(2).setImm(AMDGPU::PRED_SETNE_INT);
return;
- case OPCODE_IS_NOT_ZERO_INT:
- static_cast<MachineInstr *>(I)->getOperand(2)
- .setImm(OPCODE_IS_ZERO_INT);
+ case AMDGPU::PRED_SETNE_INT:
+ I->getOperand(2).setImm(AMDGPU::PRED_SETE_INT);
return;
- case OPCODE_IS_ZERO:
- static_cast<MachineInstr *>(I)->getOperand(2)
- .setImm(OPCODE_IS_NOT_ZERO);
+ case AMDGPU::PRED_SETE:
+ I->getOperand(2).setImm(AMDGPU::PRED_SETNE);
return;
- case OPCODE_IS_NOT_ZERO:
- static_cast<MachineInstr *>(I)->getOperand(2)
- .setImm(OPCODE_IS_ZERO);
+ case AMDGPU::PRED_SETNE:
+ I->getOperand(2).setImm(AMDGPU::PRED_SETE);
return;
default:
llvm_unreachable("PRED_X Opcode invalid!");
@@ -841,7 +838,7 @@ bool AMDGPUCFGStructurizer::run() {
} //while, "one iteration" over the function.
MachineBasicBlock *EntryMBB =
- &*GraphTraits<MachineFunction *>::nodes_begin(FuncRep);
+ *GraphTraits<MachineFunction *>::nodes_begin(FuncRep);
if (EntryMBB->succ_size() == 0) {
Finish = true;
DEBUG(
@@ -864,7 +861,7 @@ bool AMDGPUCFGStructurizer::run() {
} while (!Finish && MakeProgress);
// Misc wrap up to maintain the consistency of the Function representation.
- wrapup(&*GraphTraits<MachineFunction *>::nodes_begin(FuncRep));
+ wrapup(*GraphTraits<MachineFunction *>::nodes_begin(FuncRep));
// Detach retired Block, release memory.
for (MBBInfoMap::iterator It = BlockInfoMap.begin(), E = BlockInfoMap.end();
@@ -908,9 +905,9 @@ void AMDGPUCFGStructurizer::orderBlocks(MachineFunction *MF) {
//walk through all the block in func to check for unreachable
typedef GraphTraits<MachineFunction *> GTM;
- MachineFunction::iterator It = GTM::nodes_begin(MF), E = GTM::nodes_end(MF);
+ auto It = GTM::nodes_begin(MF), E = GTM::nodes_end(MF);
for (; It != E; ++It) {
- MachineBasicBlock *MBB = &(*It);
+ MachineBasicBlock *MBB = *It;
SccNum = getSCCNum(MBB);
if (SccNum == INVALIDSCCNUM)
dbgs() << "unreachable block BB" << MBB->getNumber() << "\n";
@@ -995,7 +992,7 @@ int AMDGPUCFGStructurizer::ifPatternMatch(MachineBasicBlock *MBB) {
// Triangle pattern, true is empty
// We reverse the predicate to make a triangle, empty false pattern;
std::swap(TrueMBB, FalseMBB);
- reversePredicateSetter(MBB->end());
+ reversePredicateSetter(MBB->end(), *MBB);
LandBlk = FalseMBB;
FalseMBB = nullptr;
} else if (FalseMBB->succ_size() == 1
@@ -1505,7 +1502,7 @@ void AMDGPUCFGStructurizer::mergeLoopbreakBlock(MachineBasicBlock *ExitingMBB,
MachineBasicBlock *TrueBranch = getTrueBranch(BranchMI);
MachineBasicBlock::iterator I = BranchMI;
if (TrueBranch != LandMBB)
- reversePredicateSetter(I);
+ reversePredicateSetter(I, *I->getParent());
insertCondBranchBefore(ExitingMBB, I, AMDGPU::IF_PREDICATE_SET, AMDGPU::PREDICATE_BIT, DL);
insertInstrBefore(I, AMDGPU::BREAK);
insertInstrBefore(I, AMDGPU::ENDIF);
diff --git a/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
index efcf1b2..3cf9a1d 100644
--- a/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp
@@ -15,38 +15,62 @@
#include "Utils/AMDKernelCodeTUtils.h"
#include "Utils/AMDGPUAsmUtils.h"
#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
-#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SMLoc.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
using namespace llvm;
+using namespace llvm::AMDGPU;
namespace {
-struct OptionalOperand;
+class AMDGPUAsmParser;
enum RegisterKind { IS_UNKNOWN, IS_VGPR, IS_SGPR, IS_TTMP, IS_SPECIAL };
+//===----------------------------------------------------------------------===//
+// Operand
+//===----------------------------------------------------------------------===//
+
class AMDGPUOperand : public MCParsedAsmOperand {
enum KindTy {
Token,
@@ -56,16 +80,18 @@ class AMDGPUOperand : public MCParsedAsmOperand {
} Kind;
SMLoc StartLoc, EndLoc;
+ const AMDGPUAsmParser *AsmParser;
public:
- AMDGPUOperand(enum KindTy K) : MCParsedAsmOperand(), Kind(K) {}
+ AMDGPUOperand(enum KindTy Kind_, const AMDGPUAsmParser *AsmParser_)
+ : MCParsedAsmOperand(), Kind(Kind_), AsmParser(AsmParser_) {}
typedef std::unique_ptr<AMDGPUOperand> Ptr;
struct Modifiers {
- bool Abs;
- bool Neg;
- bool Sext;
+ bool Abs = false;
+ bool Neg = false;
+ bool Sext = false;
bool hasFPModifiers() const { return Abs || Neg; }
bool hasIntModifiers() const { return Sext; }
@@ -126,8 +152,15 @@ public:
ImmTyDA,
ImmTyR128,
ImmTyLWE,
+ ImmTyExpTgt,
+ ImmTyExpCompr,
+ ImmTyExpVM,
ImmTyHwreg,
+ ImmTyOff,
ImmTySendMsg,
+ ImmTyInterpSlot,
+ ImmTyInterpAttr,
+ ImmTyAttrChan
};
struct TokOp {
@@ -136,18 +169,16 @@ public:
};
struct ImmOp {
- bool IsFPImm;
- ImmTy Type;
int64_t Val;
+ ImmTy Type;
+ bool IsFPImm;
Modifiers Mods;
};
struct RegOp {
unsigned RegNo;
- Modifiers Mods;
- const MCRegisterInfo *TRI;
- const MCSubtargetInfo *STI;
bool IsForcedVOP3;
+ Modifiers Mods;
};
union {
@@ -175,41 +206,66 @@ public:
return Kind == Immediate;
}
- bool isInlinableImm() const {
- if (!isImmTy(ImmTyNone)) {
- // Only plain immediates are inlinable (e.g. "clamp" attribute is not)
- return false;
- }
- // TODO: We should avoid using host float here. It would be better to
- // check the float bit values which is what a few other places do.
- // We've had bot failures before due to weird NaN support on mips hosts.
- const float F = BitsToFloat(Imm.Val);
- // TODO: Add 1/(2*pi) for VI
- return (Imm.Val <= 64 && Imm.Val >= -16) ||
- (F == 0.0 || F == 0.5 || F == -0.5 || F == 1.0 || F == -1.0 ||
- F == 2.0 || F == -2.0 || F == 4.0 || F == -4.0);
- }
+ bool isInlinableImm(MVT type) const;
+ bool isLiteralImm(MVT type) const;
bool isRegKind() const {
return Kind == Register;
}
bool isReg() const override {
- return isRegKind() && !Reg.Mods.hasModifiers();
+ return isRegKind() && !hasModifiers();
+ }
+
+ bool isRegOrImmWithInputMods(MVT type) const {
+ return isRegKind() || isInlinableImm(type);
+ }
+
+ bool isRegOrImmWithInt16InputMods() const {
+ return isRegOrImmWithInputMods(MVT::i16);
+ }
+
+ bool isRegOrImmWithInt32InputMods() const {
+ return isRegOrImmWithInputMods(MVT::i32);
+ }
+
+ bool isRegOrImmWithInt64InputMods() const {
+ return isRegOrImmWithInputMods(MVT::i64);
+ }
+
+ bool isRegOrImmWithFP16InputMods() const {
+ return isRegOrImmWithInputMods(MVT::f16);
}
- bool isRegOrImmWithInputMods() const {
- return isRegKind() || isInlinableImm();
+ bool isRegOrImmWithFP32InputMods() const {
+ return isRegOrImmWithInputMods(MVT::f32);
+ }
+
+ bool isRegOrImmWithFP64InputMods() const {
+ return isRegOrImmWithInputMods(MVT::f64);
+ }
+
+ bool isVReg() const {
+ return isRegClass(AMDGPU::VGPR_32RegClassID) ||
+ isRegClass(AMDGPU::VReg_64RegClassID) ||
+ isRegClass(AMDGPU::VReg_96RegClassID) ||
+ isRegClass(AMDGPU::VReg_128RegClassID) ||
+ isRegClass(AMDGPU::VReg_256RegClassID) ||
+ isRegClass(AMDGPU::VReg_512RegClassID);
+ }
+
+ bool isVReg32OrOff() const {
+ return isOff() || isRegClass(AMDGPU::VGPR_32RegClassID);
}
bool isImmTy(ImmTy ImmT) const {
return isImm() && Imm.Type == ImmT;
}
-
+
bool isImmModifier() const {
return isImm() && Imm.Type != ImmTyNone;
}
-
+
bool isClampSI() const { return isImmTy(ImmTyClampSI); }
bool isOModSI() const { return isImmTy(ImmTyOModSI); }
bool isDMask() const { return isImmTy(ImmTyDMask); }
@@ -217,6 +273,10 @@ public:
bool isDA() const { return isImmTy(ImmTyDA); }
bool isR128() const { return isImmTy(ImmTyUNorm); }
bool isLWE() const { return isImmTy(ImmTyLWE); }
+ bool isOff() const { return isImmTy(ImmTyOff); }
+ bool isExpTgt() const { return isImmTy(ImmTyExpTgt); }
+ bool isExpVM() const { return isImmTy(ImmTyExpVM); }
+ bool isExpCompr() const { return isImmTy(ImmTyExpCompr); }
bool isOffen() const { return isImmTy(ImmTyOffen); }
bool isIdxen() const { return isImmTy(ImmTyIdxen); }
bool isAddr64() const { return isImmTy(ImmTyAddr64); }
@@ -234,7 +294,10 @@ public:
bool isSDWASrc0Sel() const { return isImmTy(ImmTySdwaSrc0Sel); }
bool isSDWASrc1Sel() const { return isImmTy(ImmTySdwaSrc1Sel); }
bool isSDWADstUnused() const { return isImmTy(ImmTySdwaDstUnused); }
-
+ bool isInterpSlot() const { return isImmTy(ImmTyInterpSlot); }
+ bool isInterpAttr() const { return isImmTy(ImmTyInterpAttr); }
+ bool isAttrChan() const { return isImmTy(ImmTyAttrChan); }
+
bool isMod() const {
return isClampSI() || isOModSI();
}
@@ -243,47 +306,116 @@ public:
return isReg() || isImm();
}
- bool isRegClass(unsigned RCID) const {
- return isReg() && Reg.TRI->getRegClass(RCID).contains(getReg());
+ bool isRegClass(unsigned RCID) const;
+
+ bool isRegOrInlineNoMods(unsigned RCID, MVT type) const {
+ return (isRegClass(RCID) || isInlinableImm(type)) && !hasModifiers();
}
- bool isSCSrc32() const {
- return isInlinableImm() || isRegClass(AMDGPU::SReg_32RegClassID);
+ bool isSCSrcB16() const {
+ return isRegOrInlineNoMods(AMDGPU::SReg_32RegClassID, MVT::i16);
}
- bool isSCSrc64() const {
- return isInlinableImm() || isRegClass(AMDGPU::SReg_64RegClassID);
+ bool isSCSrcB32() const {
+ return isRegOrInlineNoMods(AMDGPU::SReg_32RegClassID, MVT::i32);
}
- bool isSSrc32() const {
- return isImm() || isSCSrc32() || isExpr();
+ bool isSCSrcB64() const {
+ return isRegOrInlineNoMods(AMDGPU::SReg_64RegClassID, MVT::i64);
}
- bool isSSrc64() const {
+ bool isSCSrcF16() const {
+ return isRegOrInlineNoMods(AMDGPU::SReg_32RegClassID, MVT::f16);
+ }
+
+ bool isSCSrcF32() const {
+ return isRegOrInlineNoMods(AMDGPU::SReg_32RegClassID, MVT::f32);
+ }
+
+ bool isSCSrcF64() const {
+ return isRegOrInlineNoMods(AMDGPU::SReg_64RegClassID, MVT::f64);
+ }
+
+ bool isSSrcB32() const {
+ return isSCSrcB32() || isLiteralImm(MVT::i32) || isExpr();
+ }
+
+ bool isSSrcB16() const {
+ return isSCSrcB16() || isLiteralImm(MVT::i16);
+ }
+
+ bool isSSrcB64() const {
// TODO: Find out how SALU supports extension of 32-bit literals to 64 bits.
// See isVSrc64().
- return isImm() || isSCSrc64();
+ return isSCSrcB64() || isLiteralImm(MVT::i64);
+ }
+
+ bool isSSrcF32() const {
+ return isSCSrcB32() || isLiteralImm(MVT::f32) || isExpr();
+ }
+
+ bool isSSrcF64() const {
+ return isSCSrcB64() || isLiteralImm(MVT::f64);
+ }
+
+ bool isSSrcF16() const {
+ return isSCSrcB16() || isLiteralImm(MVT::f16);
+ }
+
+ bool isVCSrcB32() const {
+ return isRegOrInlineNoMods(AMDGPU::VS_32RegClassID, MVT::i32);
+ }
+
+ bool isVCSrcB64() const {
+ return isRegOrInlineNoMods(AMDGPU::VS_64RegClassID, MVT::i64);
+ }
+
+ bool isVCSrcB16() const {
+ return isRegOrInlineNoMods(AMDGPU::VS_32RegClassID, MVT::i16);
+ }
+
+ bool isVCSrcF32() const {
+ return isRegOrInlineNoMods(AMDGPU::VS_32RegClassID, MVT::f32);
+ }
+
+ bool isVCSrcF64() const {
+ return isRegOrInlineNoMods(AMDGPU::VS_64RegClassID, MVT::f64);
+ }
+
+ bool isVCSrcF16() const {
+ return isRegOrInlineNoMods(AMDGPU::VS_32RegClassID, MVT::f16);
+ }
+
+ bool isVSrcB32() const {
+ return isVCSrcF32() || isLiteralImm(MVT::i32);
+ }
+
+ bool isVSrcB64() const {
+ return isVCSrcF64() || isLiteralImm(MVT::i64);
}
- bool isVCSrc32() const {
- return isInlinableImm() || isRegClass(AMDGPU::VS_32RegClassID);
+ bool isVSrcB16() const {
+ return isVCSrcF16() || isLiteralImm(MVT::i16);
}
- bool isVCSrc64() const {
- return isInlinableImm() || isRegClass(AMDGPU::VS_64RegClassID);
+ bool isVSrcF32() const {
+ return isVCSrcF32() || isLiteralImm(MVT::f32);
}
- bool isVSrc32() const {
- return isImm() || isVCSrc32();
+ bool isVSrcF64() const {
+ return isVCSrcF64() || isLiteralImm(MVT::f64);
}
- bool isVSrc64() const {
- // TODO: Check if the 64-bit value (coming from assembly source) can be
- // narrowed to 32 bits (in the instruction stream). That require knowledge
- // of instruction type (unsigned/signed, floating or "untyped"/B64),
- // see [AMD GCN3 ISA 6.3.1].
- // TODO: How 64-bit values are formed from 32-bit literals in _B64 insns?
- return isImm() || isVCSrc64();
+ bool isVSrcF16() const {
+ return isVCSrcF16() || isLiteralImm(MVT::f16);
+ }
+
+ bool isKImmFP32() const {
+ return isLiteralImm(MVT::f32);
+ }
+
+ bool isKImmFP16() const {
+ return isLiteralImm(MVT::f16);
}
bool isMem() const override {
@@ -301,9 +433,11 @@ public:
bool isSWaitCnt() const;
bool isHwreg() const;
bool isSendMsg() const;
- bool isSMRDOffset() const;
+ bool isSMRDOffset8() const;
+ bool isSMRDOffset20() const;
bool isSMRDLiteralOffset() const;
bool isDPPCtrl() const;
+ bool isGPRIdxMode() const;
StringRef getExpressionAsToken() const {
assert(isExpr());
@@ -311,7 +445,6 @@ public:
return S->getSymbol().getName();
}
-
StringRef getToken() const {
assert(isToken());
@@ -359,7 +492,7 @@ public:
bool hasModifiers() const {
return getModifiers().hasModifiers();
}
-
+
bool hasFPModifiers() const {
return getModifiers().hasFPModifiers();
}
@@ -368,30 +501,23 @@ public:
return getModifiers().hasIntModifiers();
}
- void addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers = true) const {
- if (isImmTy(ImmTyNone) && ApplyModifiers && Imm.Mods.hasFPModifiers()) {
- // Apply modifiers to immediate value
- int64_t Val = Imm.Val;
- bool Negate = Imm.Mods.Neg; // Only negate can get here
- if (Imm.IsFPImm) {
- APFloat F(BitsToFloat(Val));
- if (Negate) {
- F.changeSign();
- }
- Val = F.bitcastToAPInt().getZExtValue();
- } else {
- Val = Negate ? -Val : Val;
- }
- Inst.addOperand(MCOperand::createImm(Val));
- } else {
- Inst.addOperand(MCOperand::createImm(getImm()));
- }
+ void addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers = true) const;
+
+ void addLiteralImmOperand(MCInst &Inst, int64_t Val) const;
+
+ template <unsigned Bitwidth>
+ void addKImmFPOperands(MCInst &Inst, unsigned N) const;
+
+ void addKImmFP16Operands(MCInst &Inst, unsigned N) const {
+ addKImmFPOperands<16>(Inst, N);
}
- void addRegOperands(MCInst &Inst, unsigned N) const {
- Inst.addOperand(MCOperand::createReg(AMDGPU::getMCReg(getReg(), *Reg.STI)));
+ void addKImmFP32Operands(MCInst &Inst, unsigned N) const {
+ addKImmFPOperands<32>(Inst, N);
}
+ void addRegOperands(MCInst &Inst, unsigned N) const;
+
void addRegOrImmOperands(MCInst &Inst, unsigned N) const {
if (isRegKind())
addRegOperands(Inst, N);
@@ -421,6 +547,23 @@ public:
addRegOrImmWithInputModsOperands(Inst, N);
}
+ void addRegWithInputModsOperands(MCInst &Inst, unsigned N) const {
+ Modifiers Mods = getModifiers();
+ Inst.addOperand(MCOperand::createImm(Mods.getModifiersOperand()));
+ assert(isRegKind());
+ addRegOperands(Inst, N);
+ }
+
+ void addRegWithFPInputModsOperands(MCInst &Inst, unsigned N) const {
+ assert(!hasIntModifiers());
+ addRegWithInputModsOperands(Inst, N);
+ }
+
+ void addRegWithIntInputModsOperands(MCInst &Inst, unsigned N) const {
+ assert(!hasFPModifiers());
+ addRegWithInputModsOperands(Inst, N);
+ }
+
void addSoppBrTargetOperands(MCInst &Inst, unsigned N) const {
if (isImm())
addImmOperands(Inst, N);
@@ -430,7 +573,7 @@ public:
}
}
- void printImmTy(raw_ostream& OS, ImmTy Type) const {
+ static void printImmTy(raw_ostream& OS, ImmTy Type) {
switch (Type) {
case ImmTyNone: OS << "None"; break;
case ImmTyGDS: OS << "GDS"; break;
@@ -458,8 +601,15 @@ public:
case ImmTyDA: OS << "DA"; break;
case ImmTyR128: OS << "R128"; break;
case ImmTyLWE: OS << "LWE"; break;
+ case ImmTyOff: OS << "Off"; break;
+ case ImmTyExpTgt: OS << "ExpTgt"; break;
+ case ImmTyExpCompr: OS << "ExpCompr"; break;
+ case ImmTyExpVM: OS << "ExpVM"; break;
case ImmTyHwreg: OS << "Hwreg"; break;
case ImmTySendMsg: OS << "SendMsg"; break;
+ case ImmTyInterpSlot: OS << "InterpSlot"; break;
+ case ImmTyInterpAttr: OS << "InterpAttr"; break;
+ case ImmTyAttrChan: OS << "AttrChan"; break;
}
}
@@ -484,22 +634,24 @@ public:
}
}
- static AMDGPUOperand::Ptr CreateImm(int64_t Val, SMLoc Loc,
+ static AMDGPUOperand::Ptr CreateImm(const AMDGPUAsmParser *AsmParser,
+ int64_t Val, SMLoc Loc,
enum ImmTy Type = ImmTyNone,
bool IsFPImm = false) {
- auto Op = llvm::make_unique<AMDGPUOperand>(Immediate);
+ auto Op = llvm::make_unique<AMDGPUOperand>(Immediate, AsmParser);
Op->Imm.Val = Val;
Op->Imm.IsFPImm = IsFPImm;
Op->Imm.Type = Type;
- Op->Imm.Mods = {false, false, false};
+ Op->Imm.Mods = Modifiers();
Op->StartLoc = Loc;
Op->EndLoc = Loc;
return Op;
}
- static AMDGPUOperand::Ptr CreateToken(StringRef Str, SMLoc Loc,
+ static AMDGPUOperand::Ptr CreateToken(const AMDGPUAsmParser *AsmParser,
+ StringRef Str, SMLoc Loc,
bool HasExplicitEncodingSize = true) {
- auto Res = llvm::make_unique<AMDGPUOperand>(Token);
+ auto Res = llvm::make_unique<AMDGPUOperand>(Token, AsmParser);
Res->Tok.Data = Str.data();
Res->Tok.Length = Str.size();
Res->StartLoc = Loc;
@@ -507,24 +659,22 @@ public:
return Res;
}
- static AMDGPUOperand::Ptr CreateReg(unsigned RegNo, SMLoc S,
+ static AMDGPUOperand::Ptr CreateReg(const AMDGPUAsmParser *AsmParser,
+ unsigned RegNo, SMLoc S,
SMLoc E,
- const MCRegisterInfo *TRI,
- const MCSubtargetInfo *STI,
bool ForceVOP3) {
- auto Op = llvm::make_unique<AMDGPUOperand>(Register);
+ auto Op = llvm::make_unique<AMDGPUOperand>(Register, AsmParser);
Op->Reg.RegNo = RegNo;
- Op->Reg.TRI = TRI;
- Op->Reg.STI = STI;
- Op->Reg.Mods = {false, false, false};
+ Op->Reg.Mods = Modifiers();
Op->Reg.IsForcedVOP3 = ForceVOP3;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
- static AMDGPUOperand::Ptr CreateExpr(const class MCExpr *Expr, SMLoc S) {
- auto Op = llvm::make_unique<AMDGPUOperand>(Expression);
+ static AMDGPUOperand::Ptr CreateExpr(const AMDGPUAsmParser *AsmParser,
+ const class MCExpr *Expr, SMLoc S) {
+ auto Op = llvm::make_unique<AMDGPUOperand>(Expression, AsmParser);
Op->Expr = Expr;
Op->StartLoc = S;
Op->EndLoc = S;
@@ -537,6 +687,53 @@ raw_ostream &operator <<(raw_ostream &OS, AMDGPUOperand::Modifiers Mods) {
return OS;
}
+//===----------------------------------------------------------------------===//
+// AsmParser
+//===----------------------------------------------------------------------===//
+
+// Holds info related to the current kernel, e.g. count of SGPRs used.
+// Kernel scope begins at .amdgpu_hsa_kernel directive, ends at next
+// .amdgpu_hsa_kernel or at EOF.
+class KernelScopeInfo {
+ int SgprIndexUnusedMin;
+ int VgprIndexUnusedMin;
+ MCContext *Ctx;
+
+ void usesSgprAt(int i) {
+ if (i >= SgprIndexUnusedMin) {
+ SgprIndexUnusedMin = ++i;
+ if (Ctx) {
+ MCSymbol * const Sym = Ctx->getOrCreateSymbol(Twine(".kernel.sgpr_count"));
+ Sym->setVariableValue(MCConstantExpr::create(SgprIndexUnusedMin, *Ctx));
+ }
+ }
+ }
+ void usesVgprAt(int i) {
+ if (i >= VgprIndexUnusedMin) {
+ VgprIndexUnusedMin = ++i;
+ if (Ctx) {
+ MCSymbol * const Sym = Ctx->getOrCreateSymbol(Twine(".kernel.vgpr_count"));
+ Sym->setVariableValue(MCConstantExpr::create(VgprIndexUnusedMin, *Ctx));
+ }
+ }
+ }
+public:
+ KernelScopeInfo() : SgprIndexUnusedMin(-1), VgprIndexUnusedMin(-1), Ctx(nullptr)
+ {}
+ void initialize(MCContext &Context) {
+ Ctx = &Context;
+ usesSgprAt(SgprIndexUnusedMin = -1);
+ usesVgprAt(VgprIndexUnusedMin = -1);
+ }
+ void usesRegister(RegisterKind RegKind, unsigned DwordRegIndex, unsigned RegWidth) {
+ switch (RegKind) {
+ case IS_SGPR: usesSgprAt(DwordRegIndex + RegWidth - 1); break;
+ case IS_VGPR: usesVgprAt(DwordRegIndex + RegWidth - 1); break;
+ default: break;
+ }
+ }
+};
+
class AMDGPUAsmParser : public MCTargetAsmParser {
const MCInstrInfo &MII;
MCAsmParser &Parser;
@@ -544,22 +741,7 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
unsigned ForcedEncodingSize;
bool ForcedDPP;
bool ForcedSDWA;
-
- bool isSI() const {
- return AMDGPU::isSI(getSTI());
- }
-
- bool isCI() const {
- return AMDGPU::isCI(getSTI());
- }
-
- bool isVI() const {
- return AMDGPU::isVI(getSTI());
- }
-
- bool hasSGPR102_SGPR103() const {
- return !isVI();
- }
+ KernelScopeInfo KernelScope;
/// @name Auto-generated Match Functions
/// {
@@ -570,9 +752,11 @@ class AMDGPUAsmParser : public MCTargetAsmParser {
/// }
private:
+ bool ParseAsAbsoluteExpression(uint32_t &Ret);
bool ParseDirectiveMajorMinor(uint32_t &Major, uint32_t &Minor);
bool ParseDirectiveHSACodeObjectVersion();
bool ParseDirectiveHSACodeObjectISA();
+ bool ParseDirectiveRuntimeMetadata();
bool ParseAMDKernelCodeTValue(StringRef ID, amd_kernel_code_t &Header);
bool ParseDirectiveAMDKernelCodeT();
bool ParseSectionDirectiveHSAText();
@@ -584,7 +768,7 @@ private:
bool ParseSectionDirectiveHSADataGlobalProgram();
bool ParseSectionDirectiveHSARodataReadonlyAgent();
bool AddNextRegisterToList(unsigned& Reg, unsigned& RegWidth, RegisterKind RegKind, unsigned Reg1, unsigned RegNum);
- bool ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg, unsigned& RegNum, unsigned& RegWidth);
+ bool ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg, unsigned& RegNum, unsigned& RegWidth, unsigned *DwordRegIndex);
void cvtMubufImpl(MCInst &Inst, const OperandVector &Operands, bool IsAtomic, bool IsAtomicReturn);
public:
@@ -622,6 +806,27 @@ public:
Sym = Ctx.getOrCreateSymbol(Twine(".option.machine_version_stepping"));
Sym->setVariableValue(MCConstantExpr::create(Isa.Stepping, Ctx));
}
+ KernelScope.initialize(getContext());
+ }
+
+ bool isSI() const {
+ return AMDGPU::isSI(getSTI());
+ }
+
+ bool isCI() const {
+ return AMDGPU::isCI(getSTI());
+ }
+
+ bool isVI() const {
+ return AMDGPU::isVI(getSTI());
+ }
+
+ bool hasInv2PiInlineImm() const {
+ return getSTI().getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm];
+ }
+
+ bool hasSGPR102_SGPR103() const {
+ return !isVI();
}
AMDGPUTargetStreamer &getTargetStreamer() {
@@ -629,6 +834,16 @@ public:
return static_cast<AMDGPUTargetStreamer &>(TS);
}
+ const MCRegisterInfo *getMRI() const {
+ // We need this const_cast because for some reason getContext() is not const
+ // in MCAsmParser.
+ return const_cast<AMDGPUAsmParser*>(this)->getContext().getRegisterInfo();
+ }
+
+ const MCInstrInfo *getMII() const {
+ return &MII;
+ }
+
void setForcedEncodingSize(unsigned Size) { ForcedEncodingSize = Size; }
void setForcedDPP(bool ForceDPP_) { ForcedDPP = ForceDPP_; }
void setForcedSDWA(bool ForceSDWA_) { ForcedSDWA = ForceSDWA_; }
@@ -637,6 +852,7 @@ public:
bool isForcedVOP3() const { return ForcedEncodingSize == 64; }
bool isForcedDPP() const { return ForcedDPP; }
bool isForcedSDWA() const { return ForcedSDWA; }
+ ArrayRef<unsigned> getMatchedVariants() const;
std::unique_ptr<AMDGPUOperand> parseRegister();
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
@@ -652,23 +868,31 @@ public:
StringRef parseMnemonicSuffix(StringRef Name);
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
+ //bool ProcessInstruction(MCInst &Inst);
OperandMatchResultTy parseIntWithPrefix(const char *Prefix, int64_t &Int);
- OperandMatchResultTy parseIntWithPrefix(const char *Prefix,
- OperandVector &Operands,
- enum AMDGPUOperand::ImmTy ImmTy = AMDGPUOperand::ImmTyNone,
- bool (*ConvertResult)(int64_t&) = 0);
- OperandMatchResultTy parseNamedBit(const char *Name, OperandVector &Operands,
- enum AMDGPUOperand::ImmTy ImmTy = AMDGPUOperand::ImmTyNone);
- OperandMatchResultTy parseStringWithPrefix(StringRef Prefix, StringRef &Value);
+ OperandMatchResultTy
+ parseIntWithPrefix(const char *Prefix, OperandVector &Operands,
+ enum AMDGPUOperand::ImmTy ImmTy = AMDGPUOperand::ImmTyNone,
+ bool (*ConvertResult)(int64_t &) = nullptr);
+ OperandMatchResultTy
+ parseNamedBit(const char *Name, OperandVector &Operands,
+ enum AMDGPUOperand::ImmTy ImmTy = AMDGPUOperand::ImmTyNone);
+ OperandMatchResultTy parseStringWithPrefix(StringRef Prefix,
+ StringRef &Value);
OperandMatchResultTy parseImm(OperandVector &Operands);
+ OperandMatchResultTy parseReg(OperandVector &Operands);
OperandMatchResultTy parseRegOrImm(OperandVector &Operands);
- OperandMatchResultTy parseRegOrImmWithFPInputMods(OperandVector &Operands);
- OperandMatchResultTy parseRegOrImmWithIntInputMods(OperandVector &Operands);
+ OperandMatchResultTy parseRegOrImmWithFPInputMods(OperandVector &Operands, bool AllowImm = true);
+ OperandMatchResultTy parseRegOrImmWithIntInputMods(OperandVector &Operands, bool AllowImm = true);
+ OperandMatchResultTy parseRegWithFPInputMods(OperandVector &Operands);
+ OperandMatchResultTy parseRegWithIntInputMods(OperandVector &Operands);
+ OperandMatchResultTy parseVReg32OrOff(OperandVector &Operands);
void cvtDSOffset01(MCInst &Inst, const OperandVector &Operands);
void cvtDS(MCInst &Inst, const OperandVector &Operands);
+ void cvtExp(MCInst &Inst, const OperandVector &Operands);
bool parseCnt(int64_t &IntVal);
OperandMatchResultTy parseSWaitCntOps(OperandVector &Operands);
@@ -683,10 +907,17 @@ private:
bool parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &Operation, int64_t &StreamId);
bool parseHwregConstruct(OperandInfoTy &HwReg, int64_t &Offset, int64_t &Width);
+
+ void errorExpTgt();
+ OperandMatchResultTy parseExpTgtImpl(StringRef Str, uint8_t &Val);
+
public:
OperandMatchResultTy parseOptionalOperand(OperandVector &Operands);
+ OperandMatchResultTy parseExpTgt(OperandVector &Operands);
OperandMatchResultTy parseSendMsgOp(OperandVector &Operands);
+ OperandMatchResultTy parseInterpSlot(OperandVector &Operands);
+ OperandMatchResultTy parseInterpAttr(OperandVector &Operands);
OperandMatchResultTy parseSOppBrTarget(OperandVector &Operands);
void cvtMubuf(MCInst &Inst, const OperandVector &Operands) { cvtMubufImpl(Inst, Operands, false, false); }
@@ -701,7 +932,8 @@ public:
AMDGPUOperand::Ptr defaultDA() const;
AMDGPUOperand::Ptr defaultR128() const;
AMDGPUOperand::Ptr defaultLWE() const;
- AMDGPUOperand::Ptr defaultSMRDOffset() const;
+ AMDGPUOperand::Ptr defaultSMRDOffset8() const;
+ AMDGPUOperand::Ptr defaultSMRDOffset20() const;
AMDGPUOperand::Ptr defaultSMRDLiteralOffset() const;
OperandMatchResultTy parseOModOperand(OperandVector &Operands);
@@ -736,8 +968,274 @@ struct OptionalOperand {
bool (*ConvertResult)(int64_t&);
};
+} // end anonymous namespace
+
+// May be called with integer type with equivalent bitwidth.
+static const fltSemantics *getFltSemantics(unsigned Size) {
+ switch (Size) {
+ case 4:
+ return &APFloat::IEEEsingle();
+ case 8:
+ return &APFloat::IEEEdouble();
+ case 2:
+ return &APFloat::IEEEhalf();
+ default:
+ llvm_unreachable("unsupported fp type");
+ }
+}
+
+static const fltSemantics *getFltSemantics(MVT VT) {
+ return getFltSemantics(VT.getSizeInBits() / 8);
+}
+
+//===----------------------------------------------------------------------===//
+// Operand
+//===----------------------------------------------------------------------===//
+
+static bool canLosslesslyConvertToFPType(APFloat &FPLiteral, MVT VT) {
+ bool Lost;
+
+ // Convert literal to single precision
+ APFloat::opStatus Status = FPLiteral.convert(*getFltSemantics(VT),
+ APFloat::rmNearestTiesToEven,
+ &Lost);
+ // We allow precision lost but not overflow or underflow
+ if (Status != APFloat::opOK &&
+ Lost &&
+ ((Status & APFloat::opOverflow) != 0 ||
+ (Status & APFloat::opUnderflow) != 0)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool AMDGPUOperand::isInlinableImm(MVT type) const {
+ if (!isImmTy(ImmTyNone)) {
+ // Only plain immediates are inlinable (e.g. "clamp" attribute is not)
+ return false;
+ }
+ // TODO: We should avoid using host float here. It would be better to
+ // check the float bit values which is what a few other places do.
+ // We've had bot failures before due to weird NaN support on mips hosts.
+
+ APInt Literal(64, Imm.Val);
+
+ if (Imm.IsFPImm) { // We got fp literal token
+ if (type == MVT::f64 || type == MVT::i64) { // Expected 64-bit operand
+ return AMDGPU::isInlinableLiteral64(Imm.Val,
+ AsmParser->hasInv2PiInlineImm());
+ }
+
+ APFloat FPLiteral(APFloat::IEEEdouble(), APInt(64, Imm.Val));
+ if (!canLosslesslyConvertToFPType(FPLiteral, type))
+ return false;
+
+ // Check if single precision literal is inlinable
+ return AMDGPU::isInlinableLiteral32(
+ static_cast<int32_t>(FPLiteral.bitcastToAPInt().getZExtValue()),
+ AsmParser->hasInv2PiInlineImm());
+ }
+
+
+ // We got int literal token.
+ if (type == MVT::f64 || type == MVT::i64) { // Expected 64-bit operand
+ return AMDGPU::isInlinableLiteral64(Imm.Val,
+ AsmParser->hasInv2PiInlineImm());
+ }
+
+ if (type.getScalarSizeInBits() == 16) {
+ return AMDGPU::isInlinableLiteral16(
+ static_cast<int16_t>(Literal.getLoBits(16).getSExtValue()),
+ AsmParser->hasInv2PiInlineImm());
+ }
+
+ return AMDGPU::isInlinableLiteral32(
+ static_cast<int32_t>(Literal.getLoBits(32).getZExtValue()),
+ AsmParser->hasInv2PiInlineImm());
+}
+
+bool AMDGPUOperand::isLiteralImm(MVT type) const {
+ // Check that this imediate can be added as literal
+ if (!isImmTy(ImmTyNone)) {
+ return false;
+ }
+
+ if (!Imm.IsFPImm) {
+ // We got int literal token.
+
+ unsigned Size = type.getSizeInBits();
+ if (Size == 64)
+ Size = 32;
+
+ // FIXME: 64-bit operands can zero extend, sign extend, or pad zeroes for FP
+ // types.
+ return isUIntN(Size, Imm.Val) || isIntN(Size, Imm.Val);
+ }
+
+ // We got fp literal token
+ if (type == MVT::f64) { // Expected 64-bit fp operand
+ // We would set low 64-bits of literal to zeroes but we accept this literals
+ return true;
+ }
+
+ if (type == MVT::i64) { // Expected 64-bit int operand
+ // We don't allow fp literals in 64-bit integer instructions. It is
+ // unclear how we should encode them.
+ return false;
+ }
+
+ APFloat FPLiteral(APFloat::IEEEdouble(), APInt(64, Imm.Val));
+ return canLosslesslyConvertToFPType(FPLiteral, type);
+}
+
+bool AMDGPUOperand::isRegClass(unsigned RCID) const {
+ return isRegKind() && AsmParser->getMRI()->getRegClass(RCID).contains(getReg());
}
+void AMDGPUOperand::addImmOperands(MCInst &Inst, unsigned N, bool ApplyModifiers) const {
+ int64_t Val = Imm.Val;
+ if (isImmTy(ImmTyNone) && ApplyModifiers && Imm.Mods.hasFPModifiers() && Imm.Mods.Neg) {
+ // Apply modifiers to immediate value. Only negate can get here
+ if (Imm.IsFPImm) {
+ APFloat F(BitsToDouble(Val));
+ F.changeSign();
+ Val = F.bitcastToAPInt().getZExtValue();
+ } else {
+ Val = -Val;
+ }
+ }
+
+ if (AMDGPU::isSISrcOperand(AsmParser->getMII()->get(Inst.getOpcode()),
+ Inst.getNumOperands())) {
+ addLiteralImmOperand(Inst, Val);
+ } else {
+ Inst.addOperand(MCOperand::createImm(Val));
+ }
+}
+
+void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val) const {
+ const auto& InstDesc = AsmParser->getMII()->get(Inst.getOpcode());
+ auto OpNum = Inst.getNumOperands();
+ // Check that this operand accepts literals
+ assert(AMDGPU::isSISrcOperand(InstDesc, OpNum));
+
+ auto OpSize = AMDGPU::getOperandSize(InstDesc, OpNum); // expected operand size
+
+ if (Imm.IsFPImm) { // We got fp literal token
+ APInt Literal(64, Val);
+
+ switch (OpSize) {
+ case 8: {
+ if (AMDGPU::isInlinableLiteral64(Literal.getZExtValue(),
+ AsmParser->hasInv2PiInlineImm())) {
+ Inst.addOperand(MCOperand::createImm(Literal.getZExtValue()));
+ return;
+ }
+
+ // Non-inlineable
+ if (AMDGPU::isSISrcFPOperand(InstDesc, OpNum)) { // Expected 64-bit fp operand
+ // For fp operands we check if low 32 bits are zeros
+ if (Literal.getLoBits(32) != 0) {
+ const_cast<AMDGPUAsmParser *>(AsmParser)->Warning(Inst.getLoc(),
+ "Can't encode literal as exact 64-bit floating-point operand. "
+ "Low 32-bits will be set to zero");
+ }
+
+ Inst.addOperand(MCOperand::createImm(Literal.lshr(32).getZExtValue()));
+ return;
+ }
+
+ // We don't allow fp literals in 64-bit integer instructions. It is
+ // unclear how we should encode them. This case should be checked earlier
+ // in predicate methods (isLiteralImm())
+ llvm_unreachable("fp literal in 64-bit integer instruction.");
+ }
+ case 4:
+ case 2: {
+ bool lost;
+ APFloat FPLiteral(APFloat::IEEEdouble(), Literal);
+ // Convert literal to single precision
+ FPLiteral.convert(*getFltSemantics(OpSize),
+ APFloat::rmNearestTiesToEven, &lost);
+ // We allow precision lost but not overflow or underflow. This should be
+ // checked earlier in isLiteralImm()
+ Inst.addOperand(MCOperand::createImm(FPLiteral.bitcastToAPInt().getZExtValue()));
+ return;
+ }
+ default:
+ llvm_unreachable("invalid operand size");
+ }
+
+ return;
+ }
+
+ // We got int literal token.
+ // Only sign extend inline immediates.
+ // FIXME: No errors on truncation
+ switch (OpSize) {
+ case 4: {
+ if (isInt<32>(Val) &&
+ AMDGPU::isInlinableLiteral32(static_cast<int32_t>(Val),
+ AsmParser->hasInv2PiInlineImm())) {
+ Inst.addOperand(MCOperand::createImm(Val));
+ return;
+ }
+
+ Inst.addOperand(MCOperand::createImm(Val & 0xffffffff));
+ return;
+ }
+ case 8: {
+ if (AMDGPU::isInlinableLiteral64(Val,
+ AsmParser->hasInv2PiInlineImm())) {
+ Inst.addOperand(MCOperand::createImm(Val));
+ return;
+ }
+
+ Inst.addOperand(MCOperand::createImm(Lo_32(Val)));
+ return;
+ }
+ case 2: {
+ if (isInt<16>(Val) &&
+ AMDGPU::isInlinableLiteral16(static_cast<int16_t>(Val),
+ AsmParser->hasInv2PiInlineImm())) {
+ Inst.addOperand(MCOperand::createImm(Val));
+ return;
+ }
+
+ Inst.addOperand(MCOperand::createImm(Val & 0xffff));
+ return;
+ }
+ default:
+ llvm_unreachable("invalid operand size");
+ }
+}
+
+template <unsigned Bitwidth>
+void AMDGPUOperand::addKImmFPOperands(MCInst &Inst, unsigned N) const {
+ APInt Literal(64, Imm.Val);
+
+ if (!Imm.IsFPImm) {
+ // We got int literal token.
+ Inst.addOperand(MCOperand::createImm(Literal.getLoBits(Bitwidth).getZExtValue()));
+ return;
+ }
+
+ bool Lost;
+ APFloat FPLiteral(APFloat::IEEEdouble(), Literal);
+ FPLiteral.convert(*getFltSemantics(Bitwidth / 8),
+ APFloat::rmNearestTiesToEven, &Lost);
+ Inst.addOperand(MCOperand::createImm(FPLiteral.bitcastToAPInt().getZExtValue()));
+}
+
+void AMDGPUOperand::addRegOperands(MCInst &Inst, unsigned N) const {
+ Inst.addOperand(MCOperand::createReg(AMDGPU::getMCReg(getReg(), AsmParser->getSTI())));
+}
+
+//===----------------------------------------------------------------------===//
+// AsmParser
+//===----------------------------------------------------------------------===//
+
static int getRegClass(RegisterKind Is, unsigned RegWidth) {
if (Is == IS_VGPR) {
switch (RegWidth) {
@@ -818,12 +1316,13 @@ bool AMDGPUAsmParser::AddNextRegisterToList(unsigned& Reg, unsigned& RegWidth, R
RegWidth++;
return true;
default:
- assert(false); return false;
+ llvm_unreachable("unexpected register kind");
}
}
-bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg, unsigned& RegNum, unsigned& RegWidth)
+bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg, unsigned& RegNum, unsigned& RegWidth, unsigned *DwordRegIndex)
{
+ if (DwordRegIndex) { *DwordRegIndex = 0; }
const MCRegisterInfo *TRI = getContext().getRegisterInfo();
if (getLexer().is(AsmToken::Identifier)) {
StringRef RegName = Parser.getTok().getString();
@@ -883,7 +1382,7 @@ bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg,
} else if (getLexer().is(AsmToken::LBrac)) {
// List of consecutive registers: [s0,s1,s2,s3]
Parser.Lex();
- if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth))
+ if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth, nullptr))
return false;
if (RegWidth != 1)
return false;
@@ -895,7 +1394,7 @@ bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg,
} else if (getLexer().is(AsmToken::RBrac)) {
Parser.Lex();
break;
- } else if (ParseAMDGPURegister(RegKind1, Reg1, RegNum1, RegWidth1)) {
+ } else if (ParseAMDGPURegister(RegKind1, Reg1, RegNum1, RegWidth1, nullptr)) {
if (RegWidth1 != 1) {
return false;
}
@@ -923,11 +1422,12 @@ bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg,
{
unsigned Size = 1;
if (RegKind == IS_SGPR || RegKind == IS_TTMP) {
- // SGPR and TTMP registers must be are aligned. Max required alignment is 4 dwords.
+ // SGPR and TTMP registers must be aligned. Max required alignment is 4 dwords.
Size = std::min(RegWidth, 4u);
}
if (RegNum % Size != 0)
return false;
+ if (DwordRegIndex) { *DwordRegIndex = RegNum; }
RegNum = RegNum / Size;
int RCID = getRegClass(RegKind, RegWidth);
if (RCID == -1)
@@ -940,7 +1440,7 @@ bool AMDGPUAsmParser::ParseAMDGPURegister(RegisterKind& RegKind, unsigned& Reg,
}
default:
- assert(false); return false;
+ llvm_unreachable("unexpected register kind");
}
if (!subtargetHasRegister(*TRI, Reg))
@@ -952,20 +1452,19 @@ std::unique_ptr<AMDGPUOperand> AMDGPUAsmParser::parseRegister() {
const auto &Tok = Parser.getTok();
SMLoc StartLoc = Tok.getLoc();
SMLoc EndLoc = Tok.getEndLoc();
- const MCRegisterInfo *TRI = getContext().getRegisterInfo();
-
RegisterKind RegKind;
- unsigned Reg, RegNum, RegWidth;
+ unsigned Reg, RegNum, RegWidth, DwordRegIndex;
- if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth)) {
+ if (!ParseAMDGPURegister(RegKind, Reg, RegNum, RegWidth, &DwordRegIndex)) {
return nullptr;
}
- return AMDGPUOperand::CreateReg(Reg, StartLoc, EndLoc,
- TRI, &getSTI(), false);
+ KernelScope.usesRegister(RegKind, DwordRegIndex, RegWidth);
+ return AMDGPUOperand::CreateReg(this, Reg, StartLoc, EndLoc, false);
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseImm(OperandVector &Operands) {
+ // TODO: add syntactic sugar for 1/(2*PI)
bool Minus = false;
if (getLexer().getKind() == AsmToken::Minus) {
Minus = true;
@@ -978,28 +1477,21 @@ AMDGPUAsmParser::parseImm(OperandVector &Operands) {
int64_t IntVal;
if (getParser().parseAbsoluteExpression(IntVal))
return MatchOperand_ParseFail;
- if (!isInt<32>(IntVal) && !isUInt<32>(IntVal)) {
- Error(S, "invalid immediate: only 32-bit values are legal");
- return MatchOperand_ParseFail;
- }
-
if (Minus)
IntVal *= -1;
- Operands.push_back(AMDGPUOperand::CreateImm(IntVal, S));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, IntVal, S));
return MatchOperand_Success;
}
case AsmToken::Real: {
- // FIXME: We should emit an error if a double precisions floating-point
- // value is used. I'm not sure the best way to detect this.
int64_t IntVal;
if (getParser().parseAbsoluteExpression(IntVal))
return MatchOperand_ParseFail;
- APFloat F((float)BitsToDouble(IntVal));
+ APFloat F(BitsToDouble(IntVal));
if (Minus)
F.changeSign();
Operands.push_back(
- AMDGPUOperand::CreateImm(F.bitcastToAPInt().getZExtValue(), S,
+ AMDGPUOperand::CreateImm(this, F.bitcastToAPInt().getZExtValue(), S,
AMDGPUOperand::ImmTyNone, true));
return MatchOperand_Success;
}
@@ -1008,24 +1500,29 @@ AMDGPUAsmParser::parseImm(OperandVector &Operands) {
}
}
-AMDGPUAsmParser::OperandMatchResultTy
-AMDGPUAsmParser::parseRegOrImm(OperandVector &Operands) {
- auto res = parseImm(Operands);
- if (res != MatchOperand_NoMatch) {
- return res;
- }
-
+OperandMatchResultTy
+AMDGPUAsmParser::parseReg(OperandVector &Operands) {
if (auto R = parseRegister()) {
assert(R->isReg());
R->Reg.IsForcedVOP3 = isForcedVOP3();
Operands.push_back(std::move(R));
return MatchOperand_Success;
}
- return MatchOperand_ParseFail;
+ return MatchOperand_NoMatch;
}
-AMDGPUAsmParser::OperandMatchResultTy
-AMDGPUAsmParser::parseRegOrImmWithFPInputMods(OperandVector &Operands) {
+OperandMatchResultTy
+AMDGPUAsmParser::parseRegOrImm(OperandVector &Operands) {
+ auto res = parseImm(Operands);
+ if (res != MatchOperand_NoMatch) {
+ return res;
+ }
+
+ return parseReg(Operands);
+}
+
+OperandMatchResultTy
+AMDGPUAsmParser::parseRegOrImmWithFPInputMods(OperandVector &Operands, bool AllowImm) {
// XXX: During parsing we can't determine if minus sign means
// negate-modifier or negative immediate value.
// By default we suppose it is modifier.
@@ -1055,12 +1552,17 @@ AMDGPUAsmParser::parseRegOrImmWithFPInputMods(OperandVector &Operands) {
Abs = true;
}
- auto Res = parseRegOrImm(Operands);
+ OperandMatchResultTy Res;
+ if (AllowImm) {
+ Res = parseRegOrImm(Operands);
+ } else {
+ Res = parseReg(Operands);
+ }
if (Res != MatchOperand_Success) {
return Res;
}
- AMDGPUOperand::Modifiers Mods = {false, false, false};
+ AMDGPUOperand::Modifiers Mods;
if (Negate) {
Mods.Neg = true;
}
@@ -1088,8 +1590,8 @@ AMDGPUAsmParser::parseRegOrImmWithFPInputMods(OperandVector &Operands) {
return MatchOperand_Success;
}
-AMDGPUAsmParser::OperandMatchResultTy
-AMDGPUAsmParser::parseRegOrImmWithIntInputMods(OperandVector &Operands) {
+OperandMatchResultTy
+AMDGPUAsmParser::parseRegOrImmWithIntInputMods(OperandVector &Operands, bool AllowImm) {
bool Sext = false;
if (getLexer().getKind() == AsmToken::Identifier && Parser.getTok().getString() == "sext") {
@@ -1102,12 +1604,17 @@ AMDGPUAsmParser::parseRegOrImmWithIntInputMods(OperandVector &Operands) {
Parser.Lex();
}
- auto Res = parseRegOrImm(Operands);
+ OperandMatchResultTy Res;
+ if (AllowImm) {
+ Res = parseRegOrImm(Operands);
+ } else {
+ Res = parseReg(Operands);
+ }
if (Res != MatchOperand_Success) {
return Res;
}
- AMDGPUOperand::Modifiers Mods = {false, false, false};
+ AMDGPUOperand::Modifiers Mods;
if (Sext) {
if (getLexer().isNot(AsmToken::RParen)) {
Error(Parser.getTok().getLoc(), "expected closing parentheses");
@@ -1116,14 +1623,43 @@ AMDGPUAsmParser::parseRegOrImmWithIntInputMods(OperandVector &Operands) {
Parser.Lex();
Mods.Sext = true;
}
-
+
if (Mods.hasIntModifiers()) {
AMDGPUOperand &Op = static_cast<AMDGPUOperand &>(*Operands.back());
Op.setModifiers(Mods);
}
+
return MatchOperand_Success;
}
+OperandMatchResultTy
+AMDGPUAsmParser::parseRegWithFPInputMods(OperandVector &Operands) {
+ return parseRegOrImmWithFPInputMods(Operands, false);
+}
+
+OperandMatchResultTy
+AMDGPUAsmParser::parseRegWithIntInputMods(OperandVector &Operands) {
+ return parseRegOrImmWithIntInputMods(Operands, false);
+}
+
+OperandMatchResultTy AMDGPUAsmParser::parseVReg32OrOff(OperandVector &Operands) {
+ std::unique_ptr<AMDGPUOperand> Reg = parseRegister();
+ if (Reg) {
+ Operands.push_back(std::move(Reg));
+ return MatchOperand_Success;
+ }
+
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.getString() == "off") {
+ Operands.push_back(AMDGPUOperand::CreateImm(this, 0, Tok.getLoc(),
+ AMDGPUOperand::ImmTyOff, false));
+ Parser.Lex();
+ return MatchOperand_Success;
+ }
+
+ return MatchOperand_NoMatch;
+}
+
unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
uint64_t TSFlags = MII.get(Inst.getOpcode()).TSFlags;
@@ -1139,65 +1675,137 @@ unsigned AMDGPUAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
getForcedEncodingSize() != 64)
return Match_PreferE32;
+ if (Inst.getOpcode() == AMDGPU::V_MAC_F32_sdwa_vi ||
+ Inst.getOpcode() == AMDGPU::V_MAC_F16_sdwa_vi) {
+ // v_mac_f32/16 allow only dst_sel == DWORD;
+ auto OpNum =
+ AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::dst_sel);
+ const auto &Op = Inst.getOperand(OpNum);
+ if (!Op.isImm() || Op.getImm() != AMDGPU::SDWA::SdwaSel::DWORD) {
+ return Match_InvalidOperand;
+ }
+ }
+
return Match_Success;
}
+// What asm variants we should check
+ArrayRef<unsigned> AMDGPUAsmParser::getMatchedVariants() const {
+ if (getForcedEncodingSize() == 32) {
+ static const unsigned Variants[] = {AMDGPUAsmVariants::DEFAULT};
+ return makeArrayRef(Variants);
+ }
+
+ if (isForcedVOP3()) {
+ static const unsigned Variants[] = {AMDGPUAsmVariants::VOP3};
+ return makeArrayRef(Variants);
+ }
+
+ if (isForcedSDWA()) {
+ static const unsigned Variants[] = {AMDGPUAsmVariants::SDWA};
+ return makeArrayRef(Variants);
+ }
+
+ if (isForcedDPP()) {
+ static const unsigned Variants[] = {AMDGPUAsmVariants::DPP};
+ return makeArrayRef(Variants);
+ }
+
+ static const unsigned Variants[] = {
+ AMDGPUAsmVariants::DEFAULT, AMDGPUAsmVariants::VOP3,
+ AMDGPUAsmVariants::SDWA, AMDGPUAsmVariants::DPP
+ };
+
+ return makeArrayRef(Variants);
+}
+
bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) {
MCInst Inst;
+ unsigned Result = Match_Success;
+ for (auto Variant : getMatchedVariants()) {
+ uint64_t EI;
+ auto R = MatchInstructionImpl(Operands, Inst, EI, MatchingInlineAsm,
+ Variant);
+ // We order match statuses from least to most specific. We use most specific
+ // status as resulting
+ // Match_MnemonicFail < Match_InvalidOperand < Match_MissingFeature < Match_PreferE32
+ if ((R == Match_Success) ||
+ (R == Match_PreferE32) ||
+ (R == Match_MissingFeature && Result != Match_PreferE32) ||
+ (R == Match_InvalidOperand && Result != Match_MissingFeature
+ && Result != Match_PreferE32) ||
+ (R == Match_MnemonicFail && Result != Match_InvalidOperand
+ && Result != Match_MissingFeature
+ && Result != Match_PreferE32)) {
+ Result = R;
+ ErrorInfo = EI;
+ }
+ if (R == Match_Success)
+ break;
+ }
- switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
- default: break;
- case Match_Success:
- Inst.setLoc(IDLoc);
- Out.EmitInstruction(Inst, getSTI());
- return false;
- case Match_MissingFeature:
- return Error(IDLoc, "instruction not supported on this GPU");
+ switch (Result) {
+ default: break;
+ case Match_Success:
+ Inst.setLoc(IDLoc);
+ Out.EmitInstruction(Inst, getSTI());
+ return false;
- case Match_MnemonicFail:
- return Error(IDLoc, "unrecognized instruction mnemonic");
+ case Match_MissingFeature:
+ return Error(IDLoc, "instruction not supported on this GPU");
- case Match_InvalidOperand: {
- SMLoc ErrorLoc = IDLoc;
- if (ErrorInfo != ~0ULL) {
- if (ErrorInfo >= Operands.size()) {
- return Error(IDLoc, "too few operands for instruction");
- }
- ErrorLoc = ((AMDGPUOperand &)*Operands[ErrorInfo]).getStartLoc();
- if (ErrorLoc == SMLoc())
- ErrorLoc = IDLoc;
+ case Match_MnemonicFail:
+ return Error(IDLoc, "unrecognized instruction mnemonic");
+
+ case Match_InvalidOperand: {
+ SMLoc ErrorLoc = IDLoc;
+ if (ErrorInfo != ~0ULL) {
+ if (ErrorInfo >= Operands.size()) {
+ return Error(IDLoc, "too few operands for instruction");
}
- return Error(ErrorLoc, "invalid operand for instruction");
+ ErrorLoc = ((AMDGPUOperand &)*Operands[ErrorInfo]).getStartLoc();
+ if (ErrorLoc == SMLoc())
+ ErrorLoc = IDLoc;
}
- case Match_PreferE32:
- return Error(IDLoc, "internal error: instruction without _e64 suffix "
- "should be encoded as e32");
+ return Error(ErrorLoc, "invalid operand for instruction");
+ }
+
+ case Match_PreferE32:
+ return Error(IDLoc, "internal error: instruction without _e64 suffix "
+ "should be encoded as e32");
}
llvm_unreachable("Implement any new match types added!");
}
+bool AMDGPUAsmParser::ParseAsAbsoluteExpression(uint32_t &Ret) {
+ int64_t Tmp = -1;
+ if (getLexer().isNot(AsmToken::Integer) && getLexer().isNot(AsmToken::Identifier)) {
+ return true;
+ }
+ if (getParser().parseAbsoluteExpression(Tmp)) {
+ return true;
+ }
+ Ret = static_cast<uint32_t>(Tmp);
+ return false;
+}
+
+
bool AMDGPUAsmParser::ParseDirectiveMajorMinor(uint32_t &Major,
uint32_t &Minor) {
- if (getLexer().isNot(AsmToken::Integer))
+ if (ParseAsAbsoluteExpression(Major))
return TokError("invalid major version");
- Major = getLexer().getTok().getIntVal();
- Lex();
-
if (getLexer().isNot(AsmToken::Comma))
return TokError("minor version number required, comma expected");
Lex();
- if (getLexer().isNot(AsmToken::Integer))
+ if (ParseAsAbsoluteExpression(Minor))
return TokError("invalid minor version");
- Minor = getLexer().getTok().getIntVal();
- Lex();
-
return false;
}
@@ -1214,7 +1822,6 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectVersion() {
}
bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() {
-
uint32_t Major;
uint32_t Minor;
uint32_t Stepping;
@@ -1231,7 +1838,6 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() {
return false;
}
-
if (ParseDirectiveMajorMinor(Major, Minor))
return true;
@@ -1239,12 +1845,9 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() {
return TokError("stepping version number required, comma expected");
Lex();
- if (getLexer().isNot(AsmToken::Integer))
+ if (ParseAsAbsoluteExpression(Stepping))
return TokError("invalid stepping version");
- Stepping = getLexer().getTok().getIntVal();
- Lex();
-
if (getLexer().isNot(AsmToken::Comma))
return TokError("vendor name required, comma expected");
Lex();
@@ -1270,6 +1873,46 @@ bool AMDGPUAsmParser::ParseDirectiveHSACodeObjectISA() {
return false;
}
+bool AMDGPUAsmParser::ParseDirectiveRuntimeMetadata() {
+ std::string Metadata;
+ raw_string_ostream MS(Metadata);
+
+ getLexer().setSkipSpace(false);
+
+ bool FoundEnd = false;
+ while (!getLexer().is(AsmToken::Eof)) {
+ while (getLexer().is(AsmToken::Space)) {
+ MS << ' ';
+ Lex();
+ }
+
+ if (getLexer().is(AsmToken::Identifier)) {
+ StringRef ID = getLexer().getTok().getIdentifier();
+ if (ID == ".end_amdgpu_runtime_metadata") {
+ Lex();
+ FoundEnd = true;
+ break;
+ }
+ }
+
+ MS << Parser.parseStringToEndOfStatement()
+ << getContext().getAsmInfo()->getSeparatorString();
+
+ Parser.eatToEndOfStatement();
+ }
+
+ getLexer().setSkipSpace(true);
+
+ if (getLexer().is(AsmToken::Eof) && !FoundEnd)
+ return TokError("expected directive .end_amdgpu_runtime_metadata not found");
+
+ MS.flush();
+
+ getTargetStreamer().EmitRuntimeMetadata(Metadata);
+
+ return false;
+}
+
bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID,
amd_kernel_code_t &Header) {
SmallString<40> ErrStr;
@@ -1282,12 +1925,10 @@ bool AMDGPUAsmParser::ParseAMDKernelCodeTValue(StringRef ID,
}
bool AMDGPUAsmParser::ParseDirectiveAMDKernelCodeT() {
-
amd_kernel_code_t Header;
AMDGPU::initDefaultAMDKernelCodeT(Header, getSTI().getFeatureBits());
while (true) {
-
// Lex EndOfStatement. This is in a while loop, because lexing a comment
// will set the current token to EndOfStatement.
while(getLexer().is(AsmToken::EndOfStatement))
@@ -1326,6 +1967,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDGPUHsaKernel() {
getTargetStreamer().EmitAMDGPUSymbolType(KernelName,
ELF::STT_AMDGPU_HSA_KERNEL);
Lex();
+ KernelScope.initialize(getContext());
return false;
}
@@ -1378,6 +2020,9 @@ bool AMDGPUAsmParser::ParseDirective(AsmToken DirectiveID) {
if (IDVal == ".hsa_code_object_isa")
return ParseDirectiveHSACodeObjectISA();
+ if (IDVal == ".amdgpu_runtime_metadata")
+ return ParseDirectiveRuntimeMetadata();
+
if (IDVal == ".amd_kernel_code_t")
return ParseDirectiveAMDKernelCodeT();
@@ -1433,7 +2078,7 @@ bool AMDGPUAsmParser::subtargetHasRegister(const MCRegisterInfo &MRI,
return true;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
// Try to parse with a custom parser
@@ -1464,11 +2109,11 @@ AMDGPUAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
SMLoc S = Tok.getLoc();
const MCExpr *Expr = nullptr;
if (!Parser.parseExpression(Expr)) {
- Operands.push_back(AMDGPUOperand::CreateExpr(Expr, S));
+ Operands.push_back(AMDGPUOperand::CreateExpr(this, Expr, S));
return MatchOperand_Success;
}
- Operands.push_back(AMDGPUOperand::CreateToken(Tok.getString(), Tok.getLoc()));
+ Operands.push_back(AMDGPUOperand::CreateToken(this, Tok.getString(), Tok.getLoc()));
Parser.Lex();
return MatchOperand_Success;
}
@@ -1502,10 +2147,10 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info,
SMLoc NameLoc, OperandVector &Operands) {
// Add the instruction mnemonic
Name = parseMnemonicSuffix(Name);
- Operands.push_back(AMDGPUOperand::CreateToken(Name, NameLoc));
+ Operands.push_back(AMDGPUOperand::CreateToken(this, Name, NameLoc));
while (!getLexer().is(AsmToken::EndOfStatement)) {
- AMDGPUAsmParser::OperandMatchResultTy Res = parseOperand(Operands, Name);
+ OperandMatchResultTy Res = parseOperand(Operands, Name);
// Eat the comma or space if there is one.
if (getLexer().is(AsmToken::Comma))
@@ -1535,7 +2180,7 @@ bool AMDGPUAsmParser::ParseInstruction(ParseInstructionInfo &Info,
// Utility functions
//===----------------------------------------------------------------------===//
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseIntWithPrefix(const char *Prefix, int64_t &Int) {
switch(getLexer().getKind()) {
default: return MatchOperand_NoMatch;
@@ -1561,15 +2206,14 @@ AMDGPUAsmParser::parseIntWithPrefix(const char *Prefix, int64_t &Int) {
return MatchOperand_Success;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseIntWithPrefix(const char *Prefix, OperandVector &Operands,
enum AMDGPUOperand::ImmTy ImmTy,
bool (*ConvertResult)(int64_t&)) {
-
SMLoc S = Parser.getTok().getLoc();
int64_t Value = 0;
- AMDGPUAsmParser::OperandMatchResultTy Res = parseIntWithPrefix(Prefix, Value);
+ OperandMatchResultTy Res = parseIntWithPrefix(Prefix, Value);
if (Res != MatchOperand_Success)
return Res;
@@ -1577,11 +2221,11 @@ AMDGPUAsmParser::parseIntWithPrefix(const char *Prefix, OperandVector &Operands,
return MatchOperand_ParseFail;
}
- Operands.push_back(AMDGPUOperand::CreateImm(Value, S, ImmTy));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Value, S, ImmTy));
return MatchOperand_Success;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseNamedBit(const char *Name, OperandVector &Operands,
enum AMDGPUOperand::ImmTy ImmTy) {
int64_t Bit = 0;
@@ -1609,7 +2253,7 @@ AMDGPUAsmParser::parseNamedBit(const char *Name, OperandVector &Operands,
}
}
- Operands.push_back(AMDGPUOperand::CreateImm(Bit, S, ImmTy));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Bit, S, ImmTy));
return MatchOperand_Success;
}
@@ -1627,7 +2271,7 @@ void addOptionalImmOperand(MCInst& Inst, const OperandVector& Operands,
}
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseStringWithPrefix(StringRef Prefix, StringRef &Value) {
if (getLexer().isNot(AsmToken::Identifier)) {
return MatchOperand_NoMatch;
@@ -1657,7 +2301,6 @@ AMDGPUAsmParser::parseStringWithPrefix(StringRef Prefix, StringRef &Value) {
void AMDGPUAsmParser::cvtDSOffset01(MCInst &Inst,
const OperandVector &Operands) {
-
OptionalImmIndexMap OptionalIdx;
for (unsigned i = 1, e = Operands.size(); i != e; ++i) {
@@ -1681,7 +2324,6 @@ void AMDGPUAsmParser::cvtDSOffset01(MCInst &Inst,
}
void AMDGPUAsmParser::cvtDS(MCInst &Inst, const OperandVector &Operands) {
-
std::map<enum AMDGPUOperand::ImmTy, unsigned> OptionalIdx;
bool GDSOnly = false;
@@ -1712,6 +2354,46 @@ void AMDGPUAsmParser::cvtDS(MCInst &Inst, const OperandVector &Operands) {
Inst.addOperand(MCOperand::createReg(AMDGPU::M0)); // m0
}
+void AMDGPUAsmParser::cvtExp(MCInst &Inst, const OperandVector &Operands) {
+ OptionalImmIndexMap OptionalIdx;
+
+ unsigned EnMask = 0;
+ int SrcIdx = 0;
+
+ for (unsigned i = 1, e = Operands.size(); i != e; ++i) {
+ AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[i]);
+
+ // Add the register arguments
+ if (Op.isReg()) {
+ EnMask |= (1 << SrcIdx);
+ Op.addRegOperands(Inst, 1);
+ ++SrcIdx;
+ continue;
+ }
+
+ if (Op.isOff()) {
+ ++SrcIdx;
+ Inst.addOperand(MCOperand::createReg(AMDGPU::NoRegister));
+ continue;
+ }
+
+ if (Op.isImm() && Op.getImmTy() == AMDGPUOperand::ImmTyExpTgt) {
+ Op.addImmOperands(Inst, 1);
+ continue;
+ }
+
+ if (Op.isToken() && Op.getToken() == "done")
+ continue;
+
+ // Handle optional arguments
+ OptionalIdx[Op.getImmTy()] = i;
+ }
+
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyExpVM);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyExpCompr);
+
+ Inst.addOperand(MCOperand::createImm(EnMask));
+}
//===----------------------------------------------------------------------===//
// s_waitcnt
@@ -1739,52 +2421,41 @@ bool AMDGPUAsmParser::parseCnt(int64_t &IntVal) {
if (getLexer().is(AsmToken::Amp) || getLexer().is(AsmToken::Comma))
Parser.Lex();
- int CntShift;
- int CntMask;
-
- if (CntName == "vmcnt") {
- CntMask = 0xf;
- CntShift = 0;
- } else if (CntName == "expcnt") {
- CntMask = 0x7;
- CntShift = 4;
- } else if (CntName == "lgkmcnt") {
- CntMask = 0xf;
- CntShift = 8;
- } else {
+ IsaVersion IV = getIsaVersion(getSTI().getFeatureBits());
+ if (CntName == "vmcnt")
+ IntVal = encodeVmcnt(IV, IntVal, CntVal);
+ else if (CntName == "expcnt")
+ IntVal = encodeExpcnt(IV, IntVal, CntVal);
+ else if (CntName == "lgkmcnt")
+ IntVal = encodeLgkmcnt(IV, IntVal, CntVal);
+ else
return true;
- }
- IntVal &= ~(CntMask << CntShift);
- IntVal |= (CntVal << CntShift);
return false;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseSWaitCntOps(OperandVector &Operands) {
- // Disable all counters by default.
- // vmcnt [3:0]
- // expcnt [6:4]
- // lgkmcnt [11:8]
- int64_t CntVal = 0xf7f;
+ IsaVersion IV = getIsaVersion(getSTI().getFeatureBits());
+ int64_t Waitcnt = getWaitcntBitMask(IV);
SMLoc S = Parser.getTok().getLoc();
switch(getLexer().getKind()) {
default: return MatchOperand_ParseFail;
case AsmToken::Integer:
// The operand can be an integer value.
- if (getParser().parseAbsoluteExpression(CntVal))
+ if (getParser().parseAbsoluteExpression(Waitcnt))
return MatchOperand_ParseFail;
break;
case AsmToken::Identifier:
do {
- if (parseCnt(CntVal))
+ if (parseCnt(Waitcnt))
return MatchOperand_ParseFail;
} while(getLexer().isNot(AsmToken::EndOfStatement));
break;
}
- Operands.push_back(AMDGPUOperand::CreateImm(CntVal, S));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Waitcnt, S));
return MatchOperand_Success;
}
@@ -1849,7 +2520,7 @@ bool AMDGPUAsmParser::parseHwregConstruct(OperandInfoTy &HwReg, int64_t &Offset,
return false;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
using namespace llvm::AMDGPU::Hwreg;
@@ -1889,7 +2560,7 @@ AMDGPUAsmParser::parseHwreg(OperandVector &Operands) {
}
break;
}
- Operands.push_back(AMDGPUOperand::CreateImm(Imm16Val, S, AMDGPUOperand::ImmTyHwreg));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Imm16Val, S, AMDGPUOperand::ImmTyHwreg));
return MatchOperand_Success;
}
@@ -1997,7 +2668,147 @@ bool AMDGPUAsmParser::parseSendMsgConstruct(OperandInfoTy &Msg, OperandInfoTy &O
return false;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy AMDGPUAsmParser::parseInterpSlot(OperandVector &Operands) {
+ if (getLexer().getKind() != AsmToken::Identifier)
+ return MatchOperand_NoMatch;
+
+ StringRef Str = Parser.getTok().getString();
+ int Slot = StringSwitch<int>(Str)
+ .Case("p10", 0)
+ .Case("p20", 1)
+ .Case("p0", 2)
+ .Default(-1);
+
+ SMLoc S = Parser.getTok().getLoc();
+ if (Slot == -1)
+ return MatchOperand_ParseFail;
+
+ Parser.Lex();
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Slot, S,
+ AMDGPUOperand::ImmTyInterpSlot));
+ return MatchOperand_Success;
+}
+
+OperandMatchResultTy AMDGPUAsmParser::parseInterpAttr(OperandVector &Operands) {
+ if (getLexer().getKind() != AsmToken::Identifier)
+ return MatchOperand_NoMatch;
+
+ StringRef Str = Parser.getTok().getString();
+ if (!Str.startswith("attr"))
+ return MatchOperand_NoMatch;
+
+ StringRef Chan = Str.take_back(2);
+ int AttrChan = StringSwitch<int>(Chan)
+ .Case(".x", 0)
+ .Case(".y", 1)
+ .Case(".z", 2)
+ .Case(".w", 3)
+ .Default(-1);
+ if (AttrChan == -1)
+ return MatchOperand_ParseFail;
+
+ Str = Str.drop_back(2).drop_front(4);
+
+ uint8_t Attr;
+ if (Str.getAsInteger(10, Attr))
+ return MatchOperand_ParseFail;
+
+ SMLoc S = Parser.getTok().getLoc();
+ Parser.Lex();
+ if (Attr > 63) {
+ Error(S, "out of bounds attr");
+ return MatchOperand_Success;
+ }
+
+ SMLoc SChan = SMLoc::getFromPointer(Chan.data());
+
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Attr, S,
+ AMDGPUOperand::ImmTyInterpAttr));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, AttrChan, SChan,
+ AMDGPUOperand::ImmTyAttrChan));
+ return MatchOperand_Success;
+}
+
+void AMDGPUAsmParser::errorExpTgt() {
+ Error(Parser.getTok().getLoc(), "invalid exp target");
+}
+
+OperandMatchResultTy AMDGPUAsmParser::parseExpTgtImpl(StringRef Str,
+ uint8_t &Val) {
+ if (Str == "null") {
+ Val = 9;
+ return MatchOperand_Success;
+ }
+
+ if (Str.startswith("mrt")) {
+ Str = Str.drop_front(3);
+ if (Str == "z") { // == mrtz
+ Val = 8;
+ return MatchOperand_Success;
+ }
+
+ if (Str.getAsInteger(10, Val))
+ return MatchOperand_ParseFail;
+
+ if (Val > 7)
+ errorExpTgt();
+
+ return MatchOperand_Success;
+ }
+
+ if (Str.startswith("pos")) {
+ Str = Str.drop_front(3);
+ if (Str.getAsInteger(10, Val))
+ return MatchOperand_ParseFail;
+
+ if (Val > 3)
+ errorExpTgt();
+
+ Val += 12;
+ return MatchOperand_Success;
+ }
+
+ if (Str.startswith("param")) {
+ Str = Str.drop_front(5);
+ if (Str.getAsInteger(10, Val))
+ return MatchOperand_ParseFail;
+
+ if (Val >= 32)
+ errorExpTgt();
+
+ Val += 32;
+ return MatchOperand_Success;
+ }
+
+ if (Str.startswith("invalid_target_")) {
+ Str = Str.drop_front(15);
+ if (Str.getAsInteger(10, Val))
+ return MatchOperand_ParseFail;
+
+ errorExpTgt();
+ return MatchOperand_Success;
+ }
+
+ return MatchOperand_NoMatch;
+}
+
+OperandMatchResultTy AMDGPUAsmParser::parseExpTgt(OperandVector &Operands) {
+ uint8_t Val;
+ StringRef Str = Parser.getTok().getString();
+
+ auto Res = parseExpTgtImpl(Str, Val);
+ if (Res != MatchOperand_Success)
+ return Res;
+
+ SMLoc S = Parser.getTok().getLoc();
+ Parser.Lex();
+
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Val, S,
+ AMDGPUOperand::ImmTyExpTgt));
+ return MatchOperand_Success;
+}
+
+OperandMatchResultTy
AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
using namespace llvm::AMDGPU::SendMsg;
@@ -2068,11 +2879,11 @@ AMDGPUAsmParser::parseSendMsgOp(OperandVector &Operands) {
}
Imm16Val |= (StreamId << STREAM_ID_SHIFT_);
}
- } while (0);
+ } while (false);
}
break;
}
- Operands.push_back(AMDGPUOperand::CreateImm(Imm16Val, S, AMDGPUOperand::ImmTySendMsg));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Imm16Val, S, AMDGPUOperand::ImmTySendMsg));
return MatchOperand_Success;
}
@@ -2084,7 +2895,7 @@ bool AMDGPUOperand::isSendMsg() const {
// sopp branch targets
//===----------------------------------------------------------------------===//
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseSOppBrTarget(OperandVector &Operands) {
SMLoc S = Parser.getTok().getLoc();
@@ -2094,12 +2905,12 @@ AMDGPUAsmParser::parseSOppBrTarget(OperandVector &Operands) {
int64_t Imm;
if (getParser().parseAbsoluteExpression(Imm))
return MatchOperand_ParseFail;
- Operands.push_back(AMDGPUOperand::CreateImm(Imm, S));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Imm, S));
return MatchOperand_Success;
}
case AsmToken::Identifier:
- Operands.push_back(AMDGPUOperand::CreateExpr(
+ Operands.push_back(AMDGPUOperand::CreateExpr(this,
MCSymbolRefExpr::create(getContext().getOrCreateSymbol(
Parser.getTok().getString()), getContext()), S));
Parser.Lex();
@@ -2112,15 +2923,15 @@ AMDGPUAsmParser::parseSOppBrTarget(OperandVector &Operands) {
//===----------------------------------------------------------------------===//
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultGLC() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyGLC);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyGLC);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSLC() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTySLC);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTySLC);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultTFE() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyTFE);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyTFE);
}
void AMDGPUAsmParser::cvtMubufImpl(MCInst &Inst,
@@ -2192,7 +3003,7 @@ void AMDGPUAsmParser::cvtMIMG(MCInst &Inst, const OperandVector &Operands) {
} else if (Op.isImmModifier()) {
OptionalIdx[Op.getImmTy()] = I;
} else {
- assert(false);
+ llvm_unreachable("unexpected operand type");
}
}
@@ -2228,7 +3039,7 @@ void AMDGPUAsmParser::cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands)
} else if (Op.isImmModifier()) {
OptionalIdx[Op.getImmTy()] = I;
} else {
- assert(false);
+ llvm_unreachable("unexpected operand type");
}
}
@@ -2243,48 +3054,53 @@ void AMDGPUAsmParser::cvtMIMGAtomic(MCInst &Inst, const OperandVector &Operands)
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultDMask() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyDMask);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyDMask);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultUNorm() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyUNorm);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyUNorm);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultDA() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyDA);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyDA);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultR128() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyR128);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyR128);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultLWE() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyLWE);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyLWE);
}
//===----------------------------------------------------------------------===//
// smrd
//===----------------------------------------------------------------------===//
-bool AMDGPUOperand::isSMRDOffset() const {
-
- // FIXME: Support 20-bit offsets on VI. We need to to pass subtarget
- // information here.
+bool AMDGPUOperand::isSMRDOffset8() const {
return isImm() && isUInt<8>(getImm());
}
+bool AMDGPUOperand::isSMRDOffset20() const {
+ return isImm() && isUInt<20>(getImm());
+}
+
bool AMDGPUOperand::isSMRDLiteralOffset() const {
// 32-bit literals are only supported on CI and we only want to use them
// when the offset is > 8-bits.
return isImm() && !isUInt<8>(getImm()) && isUInt<32>(getImm());
}
-AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSMRDOffset() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyOffset);
+AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSMRDOffset8() const {
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset);
+}
+
+AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSMRDOffset20() const {
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSMRDLiteralOffset() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyOffset);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset);
}
//===----------------------------------------------------------------------===//
@@ -2317,10 +3133,13 @@ static bool ConvertBoundCtrl(int64_t &BoundCtrl) {
if (BoundCtrl == 0) {
BoundCtrl = 1;
return true;
- } else if (BoundCtrl == -1) {
+ }
+
+ if (BoundCtrl == -1) {
BoundCtrl = 0;
return true;
}
+
return false;
}
@@ -2350,9 +3169,10 @@ static const OptionalOperand AMDGPUOptionalOperandTable[] = {
{"src0_sel", AMDGPUOperand::ImmTySdwaSrc0Sel, false, nullptr},
{"src1_sel", AMDGPUOperand::ImmTySdwaSrc1Sel, false, nullptr},
{"dst_unused", AMDGPUOperand::ImmTySdwaDstUnused, false, nullptr},
+ {"vm", AMDGPUOperand::ImmTyExpVM, true, nullptr},
};
-AMDGPUAsmParser::OperandMatchResultTy AMDGPUAsmParser::parseOptionalOperand(OperandVector &Operands) {
+OperandMatchResultTy AMDGPUAsmParser::parseOptionalOperand(OperandVector &Operands) {
OperandMatchResultTy res;
for (const OptionalOperand &Op : AMDGPUOptionalOperandTable) {
// try to parse any optional operand here
@@ -2376,16 +3196,19 @@ AMDGPUAsmParser::OperandMatchResultTy AMDGPUAsmParser::parseOptionalOperand(Oper
return MatchOperand_NoMatch;
}
-AMDGPUAsmParser::OperandMatchResultTy AMDGPUAsmParser::parseOModOperand(OperandVector &Operands)
-{
+OperandMatchResultTy AMDGPUAsmParser::parseOModOperand(OperandVector &Operands) {
StringRef Name = Parser.getTok().getString();
if (Name == "mul") {
- return parseIntWithPrefix("mul", Operands, AMDGPUOperand::ImmTyOModSI, ConvertOmodMul);
- } else if (Name == "div") {
- return parseIntWithPrefix("div", Operands, AMDGPUOperand::ImmTyOModSI, ConvertOmodDiv);
- } else {
- return MatchOperand_NoMatch;
+ return parseIntWithPrefix("mul", Operands,
+ AMDGPUOperand::ImmTyOModSI, ConvertOmodMul);
+ }
+
+ if (Name == "div") {
+ return parseIntWithPrefix("div", Operands,
+ AMDGPUOperand::ImmTyOModSI, ConvertOmodDiv);
}
+
+ return MatchOperand_NoMatch;
}
void AMDGPUAsmParser::cvtId(MCInst &Inst, const OperandVector &Operands) {
@@ -2407,6 +3230,17 @@ void AMDGPUAsmParser::cvtVOP3_2_mod(MCInst &Inst, const OperandVector &Operands)
}
}
+static bool isRegOrImmWithInputMods(const MCInstrDesc &Desc, unsigned OpNum) {
+ // 1. This operand is input modifiers
+ return Desc.OpInfo[OpNum].OperandType == AMDGPU::OPERAND_INPUT_MODS
+ // 2. This is not last operand
+ && Desc.NumOperands > (OpNum + 1)
+ // 3. Next operand is register class
+ && Desc.OpInfo[OpNum + 1].RegClass != -1
+ // 4. Next register is not tied to any other operand
+ && Desc.getOperandConstraint(OpNum + 1, MCOI::OperandConstraint::TIED_TO) == -1;
+}
+
void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands) {
OptionalImmIndexMap OptionalIdx;
unsigned I = 1;
@@ -2417,18 +3251,36 @@ void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands) {
for (unsigned E = Operands.size(); I != E; ++I) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]);
- if (Op.isRegOrImmWithInputMods()) {
- // only fp modifiers allowed in VOP3
+ if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) {
Op.addRegOrImmWithFPInputModsOperands(Inst, 2);
} else if (Op.isImm()) {
OptionalIdx[Op.getImmTy()] = I;
} else {
- assert(false);
+ llvm_unreachable("unhandled operand type");
}
}
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI);
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyOModSI);
+
+ // special case v_mac_{f16, f32}:
+ // it has src2 register operand that is tied to dst operand
+ // we don't allow modifiers for this operand in assembler so src2_modifiers
+ // should be 0
+ if (Inst.getOpcode() == AMDGPU::V_MAC_F32_e64_si ||
+ Inst.getOpcode() == AMDGPU::V_MAC_F32_e64_vi ||
+ Inst.getOpcode() == AMDGPU::V_MAC_F16_e64_vi) {
+ auto it = Inst.begin();
+ std::advance(
+ it,
+ AMDGPU::getNamedOperandIdx(Inst.getOpcode() == AMDGPU::V_MAC_F16_e64_vi ?
+ AMDGPU::V_MAC_F16_e64 :
+ AMDGPU::V_MAC_F32_e64,
+ AMDGPU::OpName::src2_modifiers));
+ it = Inst.insert(it, MCOperand::createImm(0)); // no modifiers for src2
+ ++it;
+ Inst.insert(it, Inst.getOperand(0)); // src2 = dst
+ }
}
//===----------------------------------------------------------------------===//
@@ -2455,7 +3307,11 @@ bool AMDGPUOperand::isDPPCtrl() const {
return false;
}
-AMDGPUAsmParser::OperandMatchResultTy
+bool AMDGPUOperand::isGPRIdxMode() const {
+ return isImm() && isUInt<4>(getImm());
+}
+
+OperandMatchResultTy
AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) {
SMLoc S = Parser.getTok().getLoc();
StringRef Prefix;
@@ -2469,8 +3325,10 @@ AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) {
if (Prefix == "row_mirror") {
Int = 0x140;
+ Parser.Lex();
} else if (Prefix == "row_half_mirror") {
Int = 0x141;
+ Parser.Lex();
} else {
// Check to prevent parseDPPCtrlOps from eating invalid tokens
if (Prefix != "quad_perm"
@@ -2494,60 +3352,46 @@ AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) {
Parser.Lex();
if (getLexer().isNot(AsmToken::LBrac))
return MatchOperand_ParseFail;
-
Parser.Lex();
- if (getLexer().isNot(AsmToken::Integer))
- return MatchOperand_ParseFail;
- Int = getLexer().getTok().getIntVal();
- Parser.Lex();
- if (getLexer().isNot(AsmToken::Comma))
- return MatchOperand_ParseFail;
- Parser.Lex();
- if (getLexer().isNot(AsmToken::Integer))
+ if (getParser().parseAbsoluteExpression(Int) || !(0 <= Int && Int <=3))
return MatchOperand_ParseFail;
- Int += (getLexer().getTok().getIntVal() << 2);
- Parser.Lex();
- if (getLexer().isNot(AsmToken::Comma))
- return MatchOperand_ParseFail;
- Parser.Lex();
- if (getLexer().isNot(AsmToken::Integer))
- return MatchOperand_ParseFail;
- Int += (getLexer().getTok().getIntVal() << 4);
+ for (int i = 0; i < 3; ++i) {
+ if (getLexer().isNot(AsmToken::Comma))
+ return MatchOperand_ParseFail;
+ Parser.Lex();
- Parser.Lex();
- if (getLexer().isNot(AsmToken::Comma))
- return MatchOperand_ParseFail;
- Parser.Lex();
- if (getLexer().isNot(AsmToken::Integer))
- return MatchOperand_ParseFail;
- Int += (getLexer().getTok().getIntVal() << 6);
+ int64_t Temp;
+ if (getParser().parseAbsoluteExpression(Temp) || !(0 <= Temp && Temp <=3))
+ return MatchOperand_ParseFail;
+ const int shift = i*2 + 2;
+ Int += (Temp << shift);
+ }
- Parser.Lex();
if (getLexer().isNot(AsmToken::RBrac))
return MatchOperand_ParseFail;
+ Parser.Lex();
} else {
// sel:%d
Parser.Lex();
- if (getLexer().isNot(AsmToken::Integer))
+ if (getParser().parseAbsoluteExpression(Int))
return MatchOperand_ParseFail;
- Int = getLexer().getTok().getIntVal();
- if (Prefix == "row_shl") {
+ if (Prefix == "row_shl" && 1 <= Int && Int <= 15) {
Int |= 0x100;
- } else if (Prefix == "row_shr") {
+ } else if (Prefix == "row_shr" && 1 <= Int && Int <= 15) {
Int |= 0x110;
- } else if (Prefix == "row_ror") {
+ } else if (Prefix == "row_ror" && 1 <= Int && Int <= 15) {
Int |= 0x120;
- } else if (Prefix == "wave_shl") {
+ } else if (Prefix == "wave_shl" && 1 == Int) {
Int = 0x130;
- } else if (Prefix == "wave_rol") {
+ } else if (Prefix == "wave_rol" && 1 == Int) {
Int = 0x134;
- } else if (Prefix == "wave_shr") {
+ } else if (Prefix == "wave_shr" && 1 == Int) {
Int = 0x138;
- } else if (Prefix == "wave_ror") {
+ } else if (Prefix == "wave_ror" && 1 == Int) {
Int = 0x13C;
} else if (Prefix == "row_bcast") {
if (Int == 15) {
@@ -2562,23 +3406,21 @@ AMDGPUAsmParser::parseDPPCtrl(OperandVector &Operands) {
}
}
}
- Parser.Lex(); // eat last token
- Operands.push_back(AMDGPUOperand::CreateImm(Int, S,
- AMDGPUOperand::ImmTyDppCtrl));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Int, S, AMDGPUOperand::ImmTyDppCtrl));
return MatchOperand_Success;
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultRowMask() const {
- return AMDGPUOperand::CreateImm(0xf, SMLoc(), AMDGPUOperand::ImmTyDppRowMask);
+ return AMDGPUOperand::CreateImm(this, 0xf, SMLoc(), AMDGPUOperand::ImmTyDppRowMask);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultBankMask() const {
- return AMDGPUOperand::CreateImm(0xf, SMLoc(), AMDGPUOperand::ImmTyDppBankMask);
+ return AMDGPUOperand::CreateImm(this, 0xf, SMLoc(), AMDGPUOperand::ImmTyDppBankMask);
}
AMDGPUOperand::Ptr AMDGPUAsmParser::defaultBoundCtrl() const {
- return AMDGPUOperand::CreateImm(0, SMLoc(), AMDGPUOperand::ImmTyDppBoundCtrl);
+ return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyDppBoundCtrl);
}
void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) {
@@ -2593,9 +3435,12 @@ void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) {
for (unsigned E = Operands.size(); I != E; ++I) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]);
// Add the register arguments
- if (Op.isRegOrImmWithInputMods()) {
- // Only float modifiers supported in DPP
- Op.addRegOrImmWithFPInputModsOperands(Inst, 2);
+ if (Op.isReg() && Op.Reg.RegNo == AMDGPU::VCC) {
+ // VOP2b (v_add_u32, v_sub_u32 ...) sdwa use "vcc" token.
+ // Skip it.
+ continue;
+ } if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) {
+ Op.addRegWithFPInputModsOperands(Inst, 2);
} else if (Op.isDPPCtrl()) {
Op.addImmOperands(Inst, 1);
} else if (Op.isImm()) {
@@ -2609,18 +3454,30 @@ void AMDGPUAsmParser::cvtDPP(MCInst &Inst, const OperandVector &Operands) {
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppRowMask, 0xf);
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppBankMask, 0xf);
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDppBoundCtrl);
+
+ // special case v_mac_{f16, f32}:
+ // it has src2 register operand that is tied to dst operand
+ if (Inst.getOpcode() == AMDGPU::V_MAC_F32_dpp ||
+ Inst.getOpcode() == AMDGPU::V_MAC_F16_dpp) {
+ auto it = Inst.begin();
+ std::advance(
+ it, AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::src2));
+ Inst.insert(it, Inst.getOperand(0)); // src2 = dst
+ }
}
//===----------------------------------------------------------------------===//
// sdwa
//===----------------------------------------------------------------------===//
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseSDWASel(OperandVector &Operands, StringRef Prefix,
AMDGPUOperand::ImmTy Type) {
+ using namespace llvm::AMDGPU::SDWA;
+
SMLoc S = Parser.getTok().getLoc();
StringRef Value;
- AMDGPUAsmParser::OperandMatchResultTy res;
+ OperandMatchResultTy res;
res = parseStringWithPrefix(Prefix, Value);
if (res != MatchOperand_Success) {
@@ -2629,13 +3486,13 @@ AMDGPUAsmParser::parseSDWASel(OperandVector &Operands, StringRef Prefix,
int64_t Int;
Int = StringSwitch<int64_t>(Value)
- .Case("BYTE_0", 0)
- .Case("BYTE_1", 1)
- .Case("BYTE_2", 2)
- .Case("BYTE_3", 3)
- .Case("WORD_0", 4)
- .Case("WORD_1", 5)
- .Case("DWORD", 6)
+ .Case("BYTE_0", SdwaSel::BYTE_0)
+ .Case("BYTE_1", SdwaSel::BYTE_1)
+ .Case("BYTE_2", SdwaSel::BYTE_2)
+ .Case("BYTE_3", SdwaSel::BYTE_3)
+ .Case("WORD_0", SdwaSel::WORD_0)
+ .Case("WORD_1", SdwaSel::WORD_1)
+ .Case("DWORD", SdwaSel::DWORD)
.Default(0xffffffff);
Parser.Lex(); // eat last token
@@ -2643,15 +3500,17 @@ AMDGPUAsmParser::parseSDWASel(OperandVector &Operands, StringRef Prefix,
return MatchOperand_ParseFail;
}
- Operands.push_back(AMDGPUOperand::CreateImm(Int, S, Type));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Int, S, Type));
return MatchOperand_Success;
}
-AMDGPUAsmParser::OperandMatchResultTy
+OperandMatchResultTy
AMDGPUAsmParser::parseSDWADstUnused(OperandVector &Operands) {
+ using namespace llvm::AMDGPU::SDWA;
+
SMLoc S = Parser.getTok().getLoc();
StringRef Value;
- AMDGPUAsmParser::OperandMatchResultTy res;
+ OperandMatchResultTy res;
res = parseStringWithPrefix("dst_unused", Value);
if (res != MatchOperand_Success) {
@@ -2660,9 +3519,9 @@ AMDGPUAsmParser::parseSDWADstUnused(OperandVector &Operands) {
int64_t Int;
Int = StringSwitch<int64_t>(Value)
- .Case("UNUSED_PAD", 0)
- .Case("UNUSED_SEXT", 1)
- .Case("UNUSED_PRESERVE", 2)
+ .Case("UNUSED_PAD", DstUnused::UNUSED_PAD)
+ .Case("UNUSED_SEXT", DstUnused::UNUSED_SEXT)
+ .Case("UNUSED_PRESERVE", DstUnused::UNUSED_PRESERVE)
.Default(0xffffffff);
Parser.Lex(); // eat last token
@@ -2670,8 +3529,7 @@ AMDGPUAsmParser::parseSDWADstUnused(OperandVector &Operands) {
return MatchOperand_ParseFail;
}
- Operands.push_back(AMDGPUOperand::CreateImm(Int, S,
- AMDGPUOperand::ImmTySdwaDstUnused));
+ Operands.push_back(AMDGPUOperand::CreateImm(this, Int, S, AMDGPUOperand::ImmTySdwaDstUnused));
return MatchOperand_Success;
}
@@ -2700,13 +3558,15 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands,
for (unsigned E = Operands.size(); I != E; ++I) {
AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[I]);
// Add the register arguments
- if (BasicInstType == SIInstrFlags::VOPC &&
+ if ((BasicInstType == SIInstrFlags::VOPC ||
+ BasicInstType == SIInstrFlags::VOP2)&&
Op.isReg() &&
Op.Reg.RegNo == AMDGPU::VCC) {
- // VOPC sdwa use "vcc" token as dst. Skip it.
+ // VOPC and VOP2b (v_add_u32, v_sub_u32 ...) sdwa use "vcc" token as dst.
+ // Skip it.
continue;
- } else if (Op.isRegOrImmWithInputMods()) {
- Op.addRegOrImmWithInputModsOperands(Inst, 2);
+ } else if (isRegOrImmWithInputMods(Desc, Inst.getNumOperands())) {
+ Op.addRegWithInputModsOperands(Inst, 2);
} else if (Op.isImm()) {
// Handle optional arguments
OptionalIdx[Op.getImmTy()] = I;
@@ -2716,46 +3576,55 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands,
}
addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0);
-
- if (Inst.getOpcode() == AMDGPU::V_NOP_sdwa) {
- // V_NOP_sdwa has no optional sdwa arguments
- return;
- }
- switch (BasicInstType) {
- case SIInstrFlags::VOP1: {
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstSel, 6);
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstUnused, 2);
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, 6);
- break;
- }
- case SIInstrFlags::VOP2: {
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstSel, 6);
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstUnused, 2);
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, 6);
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc1Sel, 6);
- break;
- }
- case SIInstrFlags::VOPC: {
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, 6);
- addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc1Sel, 6);
- break;
+
+ if (Inst.getOpcode() != AMDGPU::V_NOP_sdwa_vi) {
+ // V_NOP_sdwa_vi has no optional sdwa arguments
+ switch (BasicInstType) {
+ case SIInstrFlags::VOP1:
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstSel, 6);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstUnused, 2);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, 6);
+ break;
+
+ case SIInstrFlags::VOP2:
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstSel, 6);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstUnused, 2);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, 6);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc1Sel, 6);
+ break;
+
+ case SIInstrFlags::VOPC:
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, 6);
+ addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc1Sel, 6);
+ break;
+
+ default:
+ llvm_unreachable("Invalid instruction type. Only VOP1, VOP2 and VOPC allowed");
+ }
}
- default:
- llvm_unreachable("Invalid instruction type. Only VOP1, VOP2 and VOPC allowed");
+
+ // special case v_mac_{f16, f32}:
+ // it has src2 register operand that is tied to dst operand
+ if (Inst.getOpcode() == AMDGPU::V_MAC_F32_sdwa_vi ||
+ Inst.getOpcode() == AMDGPU::V_MAC_F16_sdwa_vi) {
+ auto it = Inst.begin();
+ std::advance(
+ it, AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::src2));
+ Inst.insert(it, Inst.getOperand(0)); // src2 = dst
}
+
}
/// Force static initialization.
extern "C" void LLVMInitializeAMDGPUAsmParser() {
- RegisterMCAsmParser<AMDGPUAsmParser> A(TheAMDGPUTarget);
- RegisterMCAsmParser<AMDGPUAsmParser> B(TheGCNTarget);
+ RegisterMCAsmParser<AMDGPUAsmParser> A(getTheAMDGPUTarget());
+ RegisterMCAsmParser<AMDGPUAsmParser> B(getTheGCNTarget());
}
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#include "AMDGPUGenAsmMatcher.inc"
-
// This fuction should be defined after auto-generated include so that we have
// MatchClassKind enum defined
unsigned AMDGPUAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
@@ -2776,16 +3645,27 @@ unsigned AMDGPUAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
return Operand.isIdxen() ? Match_Success : Match_InvalidOperand;
case MCK_offen:
return Operand.isOffen() ? Match_Success : Match_InvalidOperand;
- case MCK_SSrc32:
+ case MCK_SSrcB32:
// When operands have expression values, they will return true for isToken,
// because it is not possible to distinguish between a token and an
// expression at parse time. MatchInstructionImpl() will always try to
// match an operand as a token, when isToken returns true, and when the
// name of the expression is not a valid token, the match will fail,
// so we need to handle it here.
- return Operand.isSSrc32() ? Match_Success : Match_InvalidOperand;
+ return Operand.isSSrcB32() ? Match_Success : Match_InvalidOperand;
+ case MCK_SSrcF32:
+ return Operand.isSSrcF32() ? Match_Success : Match_InvalidOperand;
case MCK_SoppBrTarget:
return Operand.isSoppBrTarget() ? Match_Success : Match_InvalidOperand;
- default: return Match_InvalidOperand;
+ case MCK_VReg32OrOff:
+ return Operand.isVReg32OrOff() ? Match_Success : Match_InvalidOperand;
+ case MCK_InterpSlot:
+ return Operand.isInterpSlot() ? Match_Success : Match_InvalidOperand;
+ case MCK_Attr:
+ return Operand.isInterpAttr() ? Match_Success : Match_InvalidOperand;
+ case MCK_AttrChan:
+ return Operand.isAttrChan() ? Match_Success : Match_InvalidOperand;
+ default:
+ return Match_InvalidOperand;
}
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td b/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td
new file mode 100644
index 0000000..45a7fe6
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td
@@ -0,0 +1,1350 @@
+//===-- BUFInstructions.td - Buffer Instruction Defintions ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def MUBUFAddr32 : ComplexPattern<i64, 9, "SelectMUBUFAddr32">;
+def MUBUFAddr64 : ComplexPattern<i64, 7, "SelectMUBUFAddr64">;
+def MUBUFAddr64Atomic : ComplexPattern<i64, 5, "SelectMUBUFAddr64">;
+
+def MUBUFScratch : ComplexPattern<i64, 4, "SelectMUBUFScratch">;
+def MUBUFOffset : ComplexPattern<i64, 6, "SelectMUBUFOffset">;
+def MUBUFOffsetNoGLC : ComplexPattern<i64, 3, "SelectMUBUFOffset">;
+def MUBUFOffsetAtomic : ComplexPattern<i64, 4, "SelectMUBUFOffset">;
+def MUBUFIntrinsicOffset : ComplexPattern<i32, 2, "SelectMUBUFIntrinsicOffset">;
+def MUBUFIntrinsicVOffset : ComplexPattern<i32, 3, "SelectMUBUFIntrinsicVOffset">;
+
+class MubufLoad <SDPatternOperator op> : PatFrag <
+ (ops node:$ptr), (op node:$ptr), [{
+ auto const AS = cast<MemSDNode>(N)->getAddressSpace();
+ return AS == AMDGPUAS::GLOBAL_ADDRESS ||
+ AS == AMDGPUAS::CONSTANT_ADDRESS;
+}]>;
+
+def mubuf_load : MubufLoad <load>;
+def mubuf_az_extloadi8 : MubufLoad <az_extloadi8>;
+def mubuf_sextloadi8 : MubufLoad <sextloadi8>;
+def mubuf_az_extloadi16 : MubufLoad <az_extloadi16>;
+def mubuf_sextloadi16 : MubufLoad <sextloadi16>;
+def mubuf_load_atomic : MubufLoad <atomic_load>;
+
+def BUFAddrKind {
+ int Offset = 0;
+ int OffEn = 1;
+ int IdxEn = 2;
+ int BothEn = 3;
+ int Addr64 = 4;
+}
+
+class getAddrName<int addrKind> {
+ string ret =
+ !if(!eq(addrKind, BUFAddrKind.Offset), "offset",
+ !if(!eq(addrKind, BUFAddrKind.OffEn), "offen",
+ !if(!eq(addrKind, BUFAddrKind.IdxEn), "idxen",
+ !if(!eq(addrKind, BUFAddrKind.BothEn), "bothen",
+ !if(!eq(addrKind, BUFAddrKind.Addr64), "addr64",
+ "")))));
+}
+
+class MUBUFAddr64Table <bit is_addr64, string suffix = ""> {
+ bit IsAddr64 = is_addr64;
+ string OpName = NAME # suffix;
+}
+
+//===----------------------------------------------------------------------===//
+// MTBUF classes
+//===----------------------------------------------------------------------===//
+
+class MTBUF_Pseudo <string opName, dag outs, dag ins,
+ string asmOps, list<dag> pattern=[]> :
+ InstSI<outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let Size = 8;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ let VM_CNT = 1;
+ let EXP_CNT = 1;
+ let MTBUF = 1;
+ let Uses = [EXEC];
+
+ let hasSideEffects = 0;
+ let SchedRW = [WriteVMEM];
+}
+
+class MTBUF_Real <MTBUF_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
+ Enc64 {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+
+ bits<8> vdata;
+ bits<12> offset;
+ bits<1> offen;
+ bits<1> idxen;
+ bits<1> glc;
+ bits<1> addr64;
+ bits<4> dfmt;
+ bits<3> nfmt;
+ bits<8> vaddr;
+ bits<7> srsrc;
+ bits<1> slc;
+ bits<1> tfe;
+ bits<8> soffset;
+
+ let Inst{11-0} = offset;
+ let Inst{12} = offen;
+ let Inst{13} = idxen;
+ let Inst{14} = glc;
+ let Inst{22-19} = dfmt;
+ let Inst{25-23} = nfmt;
+ let Inst{31-26} = 0x3a; //encoding
+ let Inst{39-32} = vaddr;
+ let Inst{47-40} = vdata;
+ let Inst{52-48} = srsrc{6-2};
+ let Inst{54} = slc;
+ let Inst{55} = tfe;
+ let Inst{63-56} = soffset;
+}
+
+class MTBUF_Load_Pseudo <string opName, RegisterClass regClass> : MTBUF_Pseudo <
+ opName, (outs regClass:$dst),
+ (ins u16imm:$offset, i1imm:$offen, i1imm:$idxen, i1imm:$glc, i1imm:$addr64,
+ i8imm:$dfmt, i8imm:$nfmt, VGPR_32:$vaddr, SReg_128:$srsrc,
+ i1imm:$slc, i1imm:$tfe, SCSrc_b32:$soffset),
+ " $dst, $offset, $offen, $idxen, $glc, $addr64, $dfmt,"#
+ " $nfmt, $vaddr, $srsrc, $slc, $tfe, $soffset"> {
+ let mayLoad = 1;
+ let mayStore = 0;
+}
+
+class MTBUF_Store_Pseudo <string opName, RegisterClass regClass> : MTBUF_Pseudo <
+ opName, (outs),
+ (ins regClass:$vdata, u16imm:$offset, i1imm:$offen, i1imm:$idxen, i1imm:$glc,
+ i1imm:$addr64, i8imm:$dfmt, i8imm:$nfmt, VGPR_32:$vaddr,
+ SReg_128:$srsrc, i1imm:$slc, i1imm:$tfe, SCSrc_b32:$soffset),
+ " $vdata, $offset, $offen, $idxen, $glc, $addr64, $dfmt,"#
+ " $nfmt, $vaddr, $srsrc, $slc, $tfe, $soffset"> {
+ let mayLoad = 0;
+ let mayStore = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// MUBUF classes
+//===----------------------------------------------------------------------===//
+
+class MUBUF_Pseudo <string opName, dag outs, dag ins,
+ string asmOps, list<dag> pattern=[]> :
+ InstSI<outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let Size = 8;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ let VM_CNT = 1;
+ let EXP_CNT = 1;
+ let MUBUF = 1;
+ let Uses = [EXEC];
+ let hasSideEffects = 0;
+ let SchedRW = [WriteVMEM];
+
+ let AsmMatchConverter = "cvtMubuf";
+
+ bits<1> offen = 0;
+ bits<1> idxen = 0;
+ bits<1> addr64 = 0;
+ bits<1> has_vdata = 1;
+ bits<1> has_vaddr = 1;
+ bits<1> has_glc = 1;
+ bits<1> glc_value = 0; // the value for glc if no such operand
+ bits<1> has_srsrc = 1;
+ bits<1> has_soffset = 1;
+ bits<1> has_offset = 1;
+ bits<1> has_slc = 1;
+ bits<1> has_tfe = 1;
+}
+
+class MUBUF_Real <bits<7> op, MUBUF_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+
+ bits<12> offset;
+ bits<1> glc;
+ bits<1> lds = 0;
+ bits<8> vaddr;
+ bits<8> vdata;
+ bits<7> srsrc;
+ bits<1> slc;
+ bits<1> tfe;
+ bits<8> soffset;
+}
+
+
+// For cache invalidation instructions.
+class MUBUF_Invalidate <string opName, SDPatternOperator node> :
+ MUBUF_Pseudo<opName, (outs), (ins), "", [(node)]> {
+
+ let AsmMatchConverter = "";
+
+ let hasSideEffects = 1;
+ let mayStore = 1;
+
+ // Set everything to 0.
+ let offen = 0;
+ let idxen = 0;
+ let addr64 = 0;
+ let has_vdata = 0;
+ let has_vaddr = 0;
+ let has_glc = 0;
+ let glc_value = 0;
+ let has_srsrc = 0;
+ let has_soffset = 0;
+ let has_offset = 0;
+ let has_slc = 0;
+ let has_tfe = 0;
+}
+
+class getMUBUFInsDA<list<RegisterClass> vdataList,
+ list<RegisterClass> vaddrList=[]> {
+ RegisterClass vdataClass = !if(!empty(vdataList), ?, !head(vdataList));
+ RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
+ dag InsNoData = !if(!empty(vaddrList),
+ (ins SReg_128:$srsrc, SCSrc_b32:$soffset,
+ offset:$offset, GLC:$glc, slc:$slc, tfe:$tfe),
+ (ins vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset,
+ offset:$offset, GLC:$glc, slc:$slc, tfe:$tfe)
+ );
+ dag InsData = !if(!empty(vaddrList),
+ (ins vdataClass:$vdata, SReg_128:$srsrc,
+ SCSrc_b32:$soffset, offset:$offset, GLC:$glc, slc:$slc, tfe:$tfe),
+ (ins vdataClass:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc,
+ SCSrc_b32:$soffset, offset:$offset, GLC:$glc, slc:$slc, tfe:$tfe)
+ );
+ dag ret = !if(!empty(vdataList), InsNoData, InsData);
+}
+
+class getMUBUFIns<int addrKind, list<RegisterClass> vdataList=[]> {
+ dag ret =
+ !if(!eq(addrKind, BUFAddrKind.Offset), getMUBUFInsDA<vdataList>.ret,
+ !if(!eq(addrKind, BUFAddrKind.OffEn), getMUBUFInsDA<vdataList, [VGPR_32]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.IdxEn), getMUBUFInsDA<vdataList, [VGPR_32]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.BothEn), getMUBUFInsDA<vdataList, [VReg_64]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.Addr64), getMUBUFInsDA<vdataList, [VReg_64]>.ret,
+ (ins))))));
+}
+
+class getMUBUFAsmOps<int addrKind> {
+ string Pfx =
+ !if(!eq(addrKind, BUFAddrKind.Offset), "off, $srsrc, $soffset",
+ !if(!eq(addrKind, BUFAddrKind.OffEn), "$vaddr, $srsrc, $soffset offen",
+ !if(!eq(addrKind, BUFAddrKind.IdxEn), "$vaddr, $srsrc, $soffset idxen",
+ !if(!eq(addrKind, BUFAddrKind.BothEn), "$vaddr, $srsrc, $soffset idxen offen",
+ !if(!eq(addrKind, BUFAddrKind.Addr64), "$vaddr, $srsrc, $soffset addr64",
+ "")))));
+ string ret = Pfx # "$offset";
+}
+
+class MUBUF_SetupAddr<int addrKind> {
+ bits<1> offen = !if(!eq(addrKind, BUFAddrKind.OffEn), 1,
+ !if(!eq(addrKind, BUFAddrKind.BothEn), 1 , 0));
+
+ bits<1> idxen = !if(!eq(addrKind, BUFAddrKind.IdxEn), 1,
+ !if(!eq(addrKind, BUFAddrKind.BothEn), 1 , 0));
+
+ bits<1> addr64 = !if(!eq(addrKind, BUFAddrKind.Addr64), 1, 0);
+
+ bits<1> has_vaddr = !if(!eq(addrKind, BUFAddrKind.Offset), 0, 1);
+}
+
+class MUBUF_Load_Pseudo <string opName,
+ int addrKind,
+ RegisterClass vdataClass,
+ list<dag> pattern=[],
+ // Workaround bug bz30254
+ int addrKindCopy = addrKind>
+ : MUBUF_Pseudo<opName,
+ (outs vdataClass:$vdata),
+ getMUBUFIns<addrKindCopy>.ret,
+ " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe",
+ pattern>,
+ MUBUF_SetupAddr<addrKindCopy> {
+ let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret;
+ let mayLoad = 1;
+ let mayStore = 0;
+}
+
+// FIXME: tfe can't be an operand because it requires a separate
+// opcode because it needs an N+1 register class dest register.
+multiclass MUBUF_Pseudo_Loads<string opName, RegisterClass vdataClass,
+ ValueType load_vt = i32,
+ SDPatternOperator ld = null_frag> {
+
+ def _OFFSET : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, vdataClass,
+ [(set load_vt:$vdata,
+ (ld (MUBUFOffset v4i32:$srsrc, i32:$soffset, i16:$offset, i1:$glc, i1:$slc, i1:$tfe)))]>,
+ MUBUFAddr64Table<0>;
+
+ def _ADDR64 : MUBUF_Load_Pseudo <opName, BUFAddrKind.Addr64, vdataClass,
+ [(set load_vt:$vdata,
+ (ld (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset, i16:$offset, i1:$glc, i1:$slc, i1:$tfe)))]>,
+ MUBUFAddr64Table<1>;
+
+ def _OFFEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
+ def _IDXEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
+ def _BOTHEN : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+
+ let DisableWQM = 1 in {
+ def _OFFSET_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.Offset, vdataClass>;
+ def _OFFEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
+ def _IDXEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
+ def _BOTHEN_exact : MUBUF_Load_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+ }
+}
+
+class MUBUF_Store_Pseudo <string opName,
+ int addrKind,
+ RegisterClass vdataClass,
+ list<dag> pattern=[],
+ // Workaround bug bz30254
+ int addrKindCopy = addrKind,
+ RegisterClass vdataClassCopy = vdataClass>
+ : MUBUF_Pseudo<opName,
+ (outs),
+ getMUBUFIns<addrKindCopy, [vdataClassCopy]>.ret,
+ " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe",
+ pattern>,
+ MUBUF_SetupAddr<addrKindCopy> {
+ let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret;
+ let mayLoad = 0;
+ let mayStore = 1;
+}
+
+multiclass MUBUF_Pseudo_Stores<string opName, RegisterClass vdataClass,
+ ValueType store_vt = i32,
+ SDPatternOperator st = null_frag> {
+
+ def _OFFSET : MUBUF_Store_Pseudo <opName, BUFAddrKind.Offset, vdataClass,
+ [(st store_vt:$vdata, (MUBUFOffset v4i32:$srsrc, i32:$soffset,
+ i16:$offset, i1:$glc, i1:$slc, i1:$tfe))]>,
+ MUBUFAddr64Table<0>;
+
+ def _ADDR64 : MUBUF_Store_Pseudo <opName, BUFAddrKind.Addr64, vdataClass,
+ [(st store_vt:$vdata, (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
+ i16:$offset, i1:$glc, i1:$slc, i1:$tfe))]>,
+ MUBUFAddr64Table<1>;
+
+ def _OFFEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
+ def _IDXEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
+ def _BOTHEN : MUBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+
+ let DisableWQM = 1 in {
+ def _OFFSET_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.Offset, vdataClass>;
+ def _OFFEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
+ def _IDXEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
+ def _BOTHEN_exact : MUBUF_Store_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+ }
+}
+
+
+class getMUBUFAtomicInsDA<RegisterClass vdataClass, bit vdata_in,
+ list<RegisterClass> vaddrList=[]> {
+ RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
+ dag ret = !if(vdata_in,
+ !if(!empty(vaddrList),
+ (ins vdataClass:$vdata_in,
+ SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, slc:$slc),
+ (ins vdataClass:$vdata_in, vaddrClass:$vaddr,
+ SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, slc:$slc)
+ ),
+ !if(!empty(vaddrList),
+ (ins vdataClass:$vdata,
+ SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, slc:$slc),
+ (ins vdataClass:$vdata, vaddrClass:$vaddr,
+ SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, slc:$slc)
+ ));
+}
+
+class getMUBUFAtomicIns<int addrKind,
+ RegisterClass vdataClass,
+ bit vdata_in,
+ // Workaround bug bz30254
+ RegisterClass vdataClassCopy=vdataClass> {
+ dag ret =
+ !if(!eq(addrKind, BUFAddrKind.Offset),
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in>.ret,
+ !if(!eq(addrKind, BUFAddrKind.OffEn),
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VGPR_32]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.IdxEn),
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VGPR_32]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.BothEn),
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VReg_64]>.ret,
+ !if(!eq(addrKind, BUFAddrKind.Addr64),
+ getMUBUFAtomicInsDA<vdataClassCopy, vdata_in, [VReg_64]>.ret,
+ (ins))))));
+}
+
+class MUBUF_Atomic_Pseudo<string opName,
+ int addrKind,
+ dag outs,
+ dag ins,
+ string asmOps,
+ list<dag> pattern=[],
+ // Workaround bug bz30254
+ int addrKindCopy = addrKind>
+ : MUBUF_Pseudo<opName, outs, ins, asmOps, pattern>,
+ MUBUF_SetupAddr<addrKindCopy> {
+ let mayStore = 1;
+ let mayLoad = 1;
+ let hasPostISelHook = 1;
+ let hasSideEffects = 1;
+ let DisableWQM = 1;
+ let has_glc = 0;
+ let has_tfe = 0;
+}
+
+class MUBUF_AtomicNoRet_Pseudo<string opName, int addrKind,
+ RegisterClass vdataClass,
+ list<dag> pattern=[],
+ // Workaround bug bz30254
+ int addrKindCopy = addrKind,
+ RegisterClass vdataClassCopy = vdataClass>
+ : MUBUF_Atomic_Pseudo<opName, addrKindCopy,
+ (outs),
+ getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 0>.ret,
+ " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$slc",
+ pattern>,
+ AtomicNoRet<opName # "_" # getAddrName<addrKindCopy>.ret, 0> {
+ let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret;
+ let glc_value = 0;
+ let AsmMatchConverter = "cvtMubufAtomic";
+}
+
+class MUBUF_AtomicRet_Pseudo<string opName, int addrKind,
+ RegisterClass vdataClass,
+ list<dag> pattern=[],
+ // Workaround bug bz30254
+ int addrKindCopy = addrKind,
+ RegisterClass vdataClassCopy = vdataClass>
+ : MUBUF_Atomic_Pseudo<opName, addrKindCopy,
+ (outs vdataClassCopy:$vdata),
+ getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 1>.ret,
+ " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # " glc$slc",
+ pattern>,
+ AtomicNoRet<opName # "_" # getAddrName<addrKindCopy>.ret, 1> {
+ let PseudoInstr = opName # "_rtn_" # getAddrName<addrKindCopy>.ret;
+ let glc_value = 1;
+ let Constraints = "$vdata = $vdata_in";
+ let DisableEncoding = "$vdata_in";
+ let AsmMatchConverter = "cvtMubufAtomicReturn";
+}
+
+multiclass MUBUF_Pseudo_Atomics <string opName,
+ RegisterClass vdataClass,
+ ValueType vdataType,
+ SDPatternOperator atomic> {
+
+ def _OFFSET : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.Offset, vdataClass>,
+ MUBUFAddr64Table <0>;
+ def _ADDR64 : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.Addr64, vdataClass>,
+ MUBUFAddr64Table <1>;
+ def _OFFEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
+ def _IDXEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
+ def _BOTHEN : MUBUF_AtomicNoRet_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+
+ def _RTN_OFFSET : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.Offset, vdataClass,
+ [(set vdataType:$vdata,
+ (atomic (MUBUFOffsetAtomic v4i32:$srsrc, i32:$soffset, i16:$offset, i1:$slc),
+ vdataType:$vdata_in))]>,
+ MUBUFAddr64Table <0, "_RTN">;
+
+ def _RTN_ADDR64 : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.Addr64, vdataClass,
+ [(set vdataType:$vdata,
+ (atomic (MUBUFAddr64Atomic v4i32:$srsrc, i64:$vaddr, i32:$soffset, i16:$offset, i1:$slc),
+ vdataType:$vdata_in))]>,
+ MUBUFAddr64Table <1, "_RTN">;
+
+ def _RTN_OFFEN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.OffEn, vdataClass>;
+ def _RTN_IDXEN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.IdxEn, vdataClass>;
+ def _RTN_BOTHEN : MUBUF_AtomicRet_Pseudo <opName, BUFAddrKind.BothEn, vdataClass>;
+}
+
+
+//===----------------------------------------------------------------------===//
+// MUBUF Instructions
+//===----------------------------------------------------------------------===//
+
+let SubtargetPredicate = isGCN in {
+
+defm BUFFER_LOAD_FORMAT_X : MUBUF_Pseudo_Loads <
+ "buffer_load_format_x", VGPR_32
+>;
+defm BUFFER_LOAD_FORMAT_XY : MUBUF_Pseudo_Loads <
+ "buffer_load_format_xy", VReg_64
+>;
+defm BUFFER_LOAD_FORMAT_XYZ : MUBUF_Pseudo_Loads <
+ "buffer_load_format_xyz", VReg_96
+>;
+defm BUFFER_LOAD_FORMAT_XYZW : MUBUF_Pseudo_Loads <
+ "buffer_load_format_xyzw", VReg_128
+>;
+defm BUFFER_STORE_FORMAT_X : MUBUF_Pseudo_Stores <
+ "buffer_store_format_x", VGPR_32
+>;
+defm BUFFER_STORE_FORMAT_XY : MUBUF_Pseudo_Stores <
+ "buffer_store_format_xy", VReg_64
+>;
+defm BUFFER_STORE_FORMAT_XYZ : MUBUF_Pseudo_Stores <
+ "buffer_store_format_xyz", VReg_96
+>;
+defm BUFFER_STORE_FORMAT_XYZW : MUBUF_Pseudo_Stores <
+ "buffer_store_format_xyzw", VReg_128
+>;
+defm BUFFER_LOAD_UBYTE : MUBUF_Pseudo_Loads <
+ "buffer_load_ubyte", VGPR_32, i32, mubuf_az_extloadi8
+>;
+defm BUFFER_LOAD_SBYTE : MUBUF_Pseudo_Loads <
+ "buffer_load_sbyte", VGPR_32, i32, mubuf_sextloadi8
+>;
+defm BUFFER_LOAD_USHORT : MUBUF_Pseudo_Loads <
+ "buffer_load_ushort", VGPR_32, i32, mubuf_az_extloadi16
+>;
+defm BUFFER_LOAD_SSHORT : MUBUF_Pseudo_Loads <
+ "buffer_load_sshort", VGPR_32, i32, mubuf_sextloadi16
+>;
+defm BUFFER_LOAD_DWORD : MUBUF_Pseudo_Loads <
+ "buffer_load_dword", VGPR_32, i32, mubuf_load
+>;
+defm BUFFER_LOAD_DWORDX2 : MUBUF_Pseudo_Loads <
+ "buffer_load_dwordx2", VReg_64, v2i32, mubuf_load
+>;
+defm BUFFER_LOAD_DWORDX3 : MUBUF_Pseudo_Loads <
+ "buffer_load_dwordx3", VReg_96, untyped, mubuf_load
+>;
+defm BUFFER_LOAD_DWORDX4 : MUBUF_Pseudo_Loads <
+ "buffer_load_dwordx4", VReg_128, v4i32, mubuf_load
+>;
+defm BUFFER_STORE_BYTE : MUBUF_Pseudo_Stores <
+ "buffer_store_byte", VGPR_32, i32, truncstorei8_global
+>;
+defm BUFFER_STORE_SHORT : MUBUF_Pseudo_Stores <
+ "buffer_store_short", VGPR_32, i32, truncstorei16_global
+>;
+defm BUFFER_STORE_DWORD : MUBUF_Pseudo_Stores <
+ "buffer_store_dword", VGPR_32, i32, global_store
+>;
+defm BUFFER_STORE_DWORDX2 : MUBUF_Pseudo_Stores <
+ "buffer_store_dwordx2", VReg_64, v2i32, global_store
+>;
+defm BUFFER_STORE_DWORDX3 : MUBUF_Pseudo_Stores <
+ "buffer_store_dwordx3", VReg_96, untyped, global_store
+>;
+defm BUFFER_STORE_DWORDX4 : MUBUF_Pseudo_Stores <
+ "buffer_store_dwordx4", VReg_128, v4i32, global_store
+>;
+defm BUFFER_ATOMIC_SWAP : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_swap", VGPR_32, i32, atomic_swap_global
+>;
+defm BUFFER_ATOMIC_CMPSWAP : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_cmpswap", VReg_64, v2i32, null_frag
+>;
+defm BUFFER_ATOMIC_ADD : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_add", VGPR_32, i32, atomic_add_global
+>;
+defm BUFFER_ATOMIC_SUB : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_sub", VGPR_32, i32, atomic_sub_global
+>;
+defm BUFFER_ATOMIC_SMIN : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_smin", VGPR_32, i32, atomic_min_global
+>;
+defm BUFFER_ATOMIC_UMIN : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_umin", VGPR_32, i32, atomic_umin_global
+>;
+defm BUFFER_ATOMIC_SMAX : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_smax", VGPR_32, i32, atomic_max_global
+>;
+defm BUFFER_ATOMIC_UMAX : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_umax", VGPR_32, i32, atomic_umax_global
+>;
+defm BUFFER_ATOMIC_AND : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_and", VGPR_32, i32, atomic_and_global
+>;
+defm BUFFER_ATOMIC_OR : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_or", VGPR_32, i32, atomic_or_global
+>;
+defm BUFFER_ATOMIC_XOR : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_xor", VGPR_32, i32, atomic_xor_global
+>;
+defm BUFFER_ATOMIC_INC : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_inc", VGPR_32, i32, atomic_inc_global
+>;
+defm BUFFER_ATOMIC_DEC : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_dec", VGPR_32, i32, atomic_dec_global
+>;
+defm BUFFER_ATOMIC_SWAP_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_swap_x2", VReg_64, i64, atomic_swap_global
+>;
+defm BUFFER_ATOMIC_CMPSWAP_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_cmpswap_x2", VReg_128, v2i64, null_frag
+>;
+defm BUFFER_ATOMIC_ADD_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_add_x2", VReg_64, i64, atomic_add_global
+>;
+defm BUFFER_ATOMIC_SUB_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_sub_x2", VReg_64, i64, atomic_sub_global
+>;
+defm BUFFER_ATOMIC_SMIN_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_smin_x2", VReg_64, i64, atomic_min_global
+>;
+defm BUFFER_ATOMIC_UMIN_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_umin_x2", VReg_64, i64, atomic_umin_global
+>;
+defm BUFFER_ATOMIC_SMAX_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_smax_x2", VReg_64, i64, atomic_max_global
+>;
+defm BUFFER_ATOMIC_UMAX_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_umax_x2", VReg_64, i64, atomic_umax_global
+>;
+defm BUFFER_ATOMIC_AND_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_and_x2", VReg_64, i64, atomic_and_global
+>;
+defm BUFFER_ATOMIC_OR_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_or_x2", VReg_64, i64, atomic_or_global
+>;
+defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_xor_x2", VReg_64, i64, atomic_xor_global
+>;
+defm BUFFER_ATOMIC_INC_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_inc_x2", VReg_64, i64, atomic_inc_global
+>;
+defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Pseudo_Atomics <
+ "buffer_atomic_dec_x2", VReg_64, i64, atomic_dec_global
+>;
+
+let SubtargetPredicate = isSI in { // isn't on CI & VI
+/*
+defm BUFFER_ATOMIC_RSUB : MUBUF_Pseudo_Atomics <"buffer_atomic_rsub">;
+defm BUFFER_ATOMIC_FCMPSWAP : MUBUF_Pseudo_Atomics <"buffer_atomic_fcmpswap">;
+defm BUFFER_ATOMIC_FMIN : MUBUF_Pseudo_Atomics <"buffer_atomic_fmin">;
+defm BUFFER_ATOMIC_FMAX : MUBUF_Pseudo_Atomics <"buffer_atomic_fmax">;
+defm BUFFER_ATOMIC_RSUB_X2 : MUBUF_Pseudo_Atomics <"buffer_atomic_rsub_x2">;
+defm BUFFER_ATOMIC_FCMPSWAP_X2 : MUBUF_Pseudo_Atomics <"buffer_atomic_fcmpswap_x2">;
+defm BUFFER_ATOMIC_FMIN_X2 : MUBUF_Pseudo_Atomics <"buffer_atomic_fmin_x2">;
+defm BUFFER_ATOMIC_FMAX_X2 : MUBUF_Pseudo_Atomics <"buffer_atomic_fmax_x2">;
+*/
+
+def BUFFER_WBINVL1_SC : MUBUF_Invalidate <"buffer_wbinvl1_sc",
+ int_amdgcn_buffer_wbinvl1_sc>;
+}
+
+def BUFFER_WBINVL1 : MUBUF_Invalidate <"buffer_wbinvl1",
+ int_amdgcn_buffer_wbinvl1>;
+
+//===----------------------------------------------------------------------===//
+// MTBUF Instructions
+//===----------------------------------------------------------------------===//
+
+//def TBUFFER_LOAD_FORMAT_X : MTBUF_ <0, "tbuffer_load_format_x", []>;
+//def TBUFFER_LOAD_FORMAT_XY : MTBUF_ <1, "tbuffer_load_format_xy", []>;
+//def TBUFFER_LOAD_FORMAT_XYZ : MTBUF_ <2, "tbuffer_load_format_xyz", []>;
+def TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Load_Pseudo <"tbuffer_load_format_xyzw", VReg_128>;
+def TBUFFER_STORE_FORMAT_X : MTBUF_Store_Pseudo <"tbuffer_store_format_x", VGPR_32>;
+def TBUFFER_STORE_FORMAT_XY : MTBUF_Store_Pseudo <"tbuffer_store_format_xy", VReg_64>;
+def TBUFFER_STORE_FORMAT_XYZ : MTBUF_Store_Pseudo <"tbuffer_store_format_xyz", VReg_128>;
+def TBUFFER_STORE_FORMAT_XYZW : MTBUF_Store_Pseudo <"tbuffer_store_format_xyzw", VReg_128>;
+
+} // End let SubtargetPredicate = isGCN
+
+let SubtargetPredicate = isCIVI in {
+
+//===----------------------------------------------------------------------===//
+// Instruction definitions for CI and newer.
+//===----------------------------------------------------------------------===//
+// Remaining instructions:
+// BUFFER_LOAD_DWORDX3
+// BUFFER_STORE_DWORDX3
+
+def BUFFER_WBINVL1_VOL : MUBUF_Invalidate <"buffer_wbinvl1_vol",
+ int_amdgcn_buffer_wbinvl1_vol>;
+
+} // End let SubtargetPredicate = isCIVI
+
+//===----------------------------------------------------------------------===//
+// MUBUF Patterns
+//===----------------------------------------------------------------------===//
+
+let Predicates = [isGCN] in {
+
+// int_SI_vs_load_input
+def : Pat<
+ (SIload_input v4i32:$tlst, imm:$attr_offset, i32:$buf_idx_vgpr),
+ (BUFFER_LOAD_FORMAT_XYZW_IDXEN $buf_idx_vgpr, $tlst, (i32 0), imm:$attr_offset, 0, 0, 0)
+>;
+
+// Offset in an 32-bit VGPR
+def : Pat <
+ (SIload_constant v4i32:$sbase, i32:$voff),
+ (BUFFER_LOAD_DWORD_OFFEN $voff, $sbase, (i32 0), 0, 0, 0, 0)
+>;
+
+
+//===----------------------------------------------------------------------===//
+// buffer_load/store_format patterns
+//===----------------------------------------------------------------------===//
+
+multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
+ string opcode> {
+ def : Pat<
+ (vt (name v4i32:$rsrc, 0,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$glc, imm:$slc)),
+ (!cast<MUBUF_Pseudo>(opcode # _OFFSET) $rsrc, $soffset, (as_i16imm $offset),
+ (as_i1imm $glc), (as_i1imm $slc), 0)
+ >;
+
+ def : Pat<
+ (vt (name v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$glc, imm:$slc)),
+ (!cast<MUBUF_Pseudo>(opcode # _IDXEN) $vindex, $rsrc, $soffset, (as_i16imm $offset),
+ (as_i1imm $glc), (as_i1imm $slc), 0)
+ >;
+
+ def : Pat<
+ (vt (name v4i32:$rsrc, 0,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$glc, imm:$slc)),
+ (!cast<MUBUF_Pseudo>(opcode # _OFFEN) $voffset, $rsrc, $soffset, (as_i16imm $offset),
+ (as_i1imm $glc), (as_i1imm $slc), 0)
+ >;
+
+ def : Pat<
+ (vt (name v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$glc, imm:$slc)),
+ (!cast<MUBUF_Pseudo>(opcode # _BOTHEN)
+ (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
+ $rsrc, $soffset, (as_i16imm $offset),
+ (as_i1imm $glc), (as_i1imm $slc), 0)
+ >;
+}
+
+defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format, f32, "BUFFER_LOAD_FORMAT_X">;
+defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format, v2f32, "BUFFER_LOAD_FORMAT_XY">;
+defm : MUBUF_LoadIntrinsicPat<SIbuffer_load_format, v4f32, "BUFFER_LOAD_FORMAT_XYZW">;
+defm : MUBUF_LoadIntrinsicPat<SIbuffer_load, f32, "BUFFER_LOAD_DWORD">;
+defm : MUBUF_LoadIntrinsicPat<SIbuffer_load, v2f32, "BUFFER_LOAD_DWORDX2">;
+defm : MUBUF_LoadIntrinsicPat<SIbuffer_load, v4f32, "BUFFER_LOAD_DWORDX4">;
+
+multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
+ string opcode> {
+ def : Pat<
+ (name vt:$vdata, v4i32:$rsrc, 0,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$glc, imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _OFFSET_exact) $vdata, $rsrc, $soffset, (as_i16imm $offset),
+ (as_i1imm $glc), (as_i1imm $slc), 0)
+ >;
+
+ def : Pat<
+ (name vt:$vdata, v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$glc, imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _IDXEN_exact) $vdata, $vindex, $rsrc, $soffset,
+ (as_i16imm $offset), (as_i1imm $glc),
+ (as_i1imm $slc), 0)
+ >;
+
+ def : Pat<
+ (name vt:$vdata, v4i32:$rsrc, 0,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$glc, imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _OFFEN_exact) $vdata, $voffset, $rsrc, $soffset,
+ (as_i16imm $offset), (as_i1imm $glc),
+ (as_i1imm $slc), 0)
+ >;
+
+ def : Pat<
+ (name vt:$vdata, v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$glc, imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _BOTHEN_exact)
+ $vdata,
+ (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
+ $rsrc, $soffset, (as_i16imm $offset),
+ (as_i1imm $glc), (as_i1imm $slc), 0)
+ >;
+}
+
+defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store_format, f32, "BUFFER_STORE_FORMAT_X">;
+defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store_format, v2f32, "BUFFER_STORE_FORMAT_XY">;
+defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store_format, v4f32, "BUFFER_STORE_FORMAT_XYZW">;
+defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store, f32, "BUFFER_STORE_DWORD">;
+defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store, v2f32, "BUFFER_STORE_DWORDX2">;
+defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store, v4f32, "BUFFER_STORE_DWORDX4">;
+
+//===----------------------------------------------------------------------===//
+// buffer_atomic patterns
+//===----------------------------------------------------------------------===//
+
+multiclass BufferAtomicPatterns<SDPatternOperator name, string opcode> {
+ def : Pat<
+ (name i32:$vdata_in, v4i32:$rsrc, 0,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _RTN_OFFSET) $vdata_in, $rsrc, $soffset,
+ (as_i16imm $offset), (as_i1imm $slc))
+ >;
+
+ def : Pat<
+ (name i32:$vdata_in, v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _RTN_IDXEN) $vdata_in, $vindex, $rsrc, $soffset,
+ (as_i16imm $offset), (as_i1imm $slc))
+ >;
+
+ def : Pat<
+ (name i32:$vdata_in, v4i32:$rsrc, 0,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _RTN_OFFEN) $vdata_in, $voffset, $rsrc, $soffset,
+ (as_i16imm $offset), (as_i1imm $slc))
+ >;
+
+ def : Pat<
+ (name i32:$vdata_in, v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$slc),
+ (!cast<MUBUF_Pseudo>(opcode # _RTN_BOTHEN)
+ $vdata_in,
+ (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
+ $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc))
+ >;
+}
+
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_swap, "BUFFER_ATOMIC_SWAP">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_add, "BUFFER_ATOMIC_ADD">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_sub, "BUFFER_ATOMIC_SUB">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_smin, "BUFFER_ATOMIC_SMIN">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_umin, "BUFFER_ATOMIC_UMIN">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_smax, "BUFFER_ATOMIC_SMAX">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_umax, "BUFFER_ATOMIC_UMAX">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_and, "BUFFER_ATOMIC_AND">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_or, "BUFFER_ATOMIC_OR">;
+defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_xor, "BUFFER_ATOMIC_XOR">;
+
+def : Pat<
+ (int_amdgcn_buffer_atomic_cmpswap
+ i32:$data, i32:$cmp, v4i32:$rsrc, 0,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$slc),
+ (EXTRACT_SUBREG
+ (BUFFER_ATOMIC_CMPSWAP_RTN_OFFSET
+ (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
+ $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
+ sub0)
+>;
+
+def : Pat<
+ (int_amdgcn_buffer_atomic_cmpswap
+ i32:$data, i32:$cmp, v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
+ imm:$slc),
+ (EXTRACT_SUBREG
+ (BUFFER_ATOMIC_CMPSWAP_RTN_IDXEN
+ (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
+ $vindex, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
+ sub0)
+>;
+
+def : Pat<
+ (int_amdgcn_buffer_atomic_cmpswap
+ i32:$data, i32:$cmp, v4i32:$rsrc, 0,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$slc),
+ (EXTRACT_SUBREG
+ (BUFFER_ATOMIC_CMPSWAP_RTN_OFFEN
+ (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
+ $voffset, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
+ sub0)
+>;
+
+def : Pat<
+ (int_amdgcn_buffer_atomic_cmpswap
+ i32:$data, i32:$cmp, v4i32:$rsrc, i32:$vindex,
+ (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
+ imm:$slc),
+ (EXTRACT_SUBREG
+ (BUFFER_ATOMIC_CMPSWAP_RTN_BOTHEN
+ (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
+ (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
+ $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
+ sub0)
+>;
+
+
+class MUBUFLoad_PatternADDR64 <MUBUF_Pseudo Instr_ADDR64, ValueType vt,
+ PatFrag constant_ld> : Pat <
+ (vt (constant_ld (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
+ i16:$offset, i1:$glc, i1:$slc, i1:$tfe))),
+ (Instr_ADDR64 $vaddr, $srsrc, $soffset, $offset, $glc, $slc, $tfe)
+ >;
+
+multiclass MUBUFLoad_Atomic_Pattern <MUBUF_Pseudo Instr_ADDR64, MUBUF_Pseudo Instr_OFFSET,
+ ValueType vt, PatFrag atomic_ld> {
+ def : Pat <
+ (vt (atomic_ld (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
+ i16:$offset, i1:$slc))),
+ (Instr_ADDR64 $vaddr, $srsrc, $soffset, $offset, 1, $slc, 0)
+ >;
+
+ def : Pat <
+ (vt (atomic_ld (MUBUFOffsetNoGLC v4i32:$rsrc, i32:$soffset, i16:$offset))),
+ (Instr_OFFSET $rsrc, $soffset, (as_i16imm $offset), 1, 0, 0)
+ >;
+}
+
+let Predicates = [isSICI] in {
+def : MUBUFLoad_PatternADDR64 <BUFFER_LOAD_SBYTE_ADDR64, i32, sextloadi8_constant>;
+def : MUBUFLoad_PatternADDR64 <BUFFER_LOAD_UBYTE_ADDR64, i32, az_extloadi8_constant>;
+def : MUBUFLoad_PatternADDR64 <BUFFER_LOAD_SSHORT_ADDR64, i32, sextloadi16_constant>;
+def : MUBUFLoad_PatternADDR64 <BUFFER_LOAD_USHORT_ADDR64, i32, az_extloadi16_constant>;
+
+defm : MUBUFLoad_Atomic_Pattern <BUFFER_LOAD_DWORD_ADDR64, BUFFER_LOAD_DWORD_OFFSET, i32, mubuf_load_atomic>;
+defm : MUBUFLoad_Atomic_Pattern <BUFFER_LOAD_DWORDX2_ADDR64, BUFFER_LOAD_DWORDX2_OFFSET, i64, mubuf_load_atomic>;
+} // End Predicates = [isSICI]
+
+multiclass MUBUFLoad_Pattern <MUBUF_Pseudo Instr_OFFSET, ValueType vt,
+ PatFrag ld> {
+
+ def : Pat <
+ (vt (ld (MUBUFOffset v4i32:$srsrc, i32:$soffset,
+ i16:$offset, i1:$glc, i1:$slc, i1:$tfe))),
+ (Instr_OFFSET $srsrc, $soffset, $offset, $glc, $slc, $tfe)
+ >;
+}
+
+let Predicates = [Has16BitInsts] in {
+
+defm : MUBUFLoad_Pattern <BUFFER_LOAD_SBYTE_OFFSET, i16, sextloadi8_constant>;
+defm : MUBUFLoad_Pattern <BUFFER_LOAD_UBYTE_OFFSET, i16, az_extloadi8_constant>;
+defm : MUBUFLoad_Pattern <BUFFER_LOAD_SBYTE_OFFSET, i16, mubuf_sextloadi8>;
+defm : MUBUFLoad_Pattern <BUFFER_LOAD_UBYTE_OFFSET, i16, mubuf_az_extloadi8>;
+
+} // End Predicates = [Has16BitInsts]
+
+class MUBUFScratchLoadPat <MUBUF_Pseudo Instr, ValueType vt, PatFrag ld> : Pat <
+ (vt (ld (MUBUFScratch v4i32:$srsrc, i32:$vaddr,
+ i32:$soffset, u16imm:$offset))),
+ (Instr $vaddr, $srsrc, $soffset, $offset, 0, 0, 0)
+>;
+
+def : MUBUFScratchLoadPat <BUFFER_LOAD_SBYTE_OFFEN, i32, sextloadi8_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_UBYTE_OFFEN, i32, extloadi8_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_SBYTE_OFFEN, i16, sextloadi8_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_UBYTE_OFFEN, i16, extloadi8_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_SSHORT_OFFEN, i32, sextloadi16_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_USHORT_OFFEN, i32, extloadi16_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_DWORD_OFFEN, i32, load_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_DWORDX2_OFFEN, v2i32, load_private>;
+def : MUBUFScratchLoadPat <BUFFER_LOAD_DWORDX4_OFFEN, v4i32, load_private>;
+
+// BUFFER_LOAD_DWORD*, addr64=0
+multiclass MUBUF_Load_Dword <ValueType vt,
+ MUBUF_Pseudo offset,
+ MUBUF_Pseudo offen,
+ MUBUF_Pseudo idxen,
+ MUBUF_Pseudo bothen> {
+
+ def : Pat <
+ (vt (int_SI_buffer_load_dword v4i32:$rsrc, (i32 imm), i32:$soffset,
+ imm:$offset, 0, 0, imm:$glc, imm:$slc,
+ imm:$tfe)),
+ (offset $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc),
+ (as_i1imm $slc), (as_i1imm $tfe))
+ >;
+
+ def : Pat <
+ (vt (int_SI_buffer_load_dword v4i32:$rsrc, i32:$vaddr, i32:$soffset,
+ imm:$offset, 1, 0, imm:$glc, imm:$slc,
+ imm:$tfe)),
+ (offen $vaddr, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc), (as_i1imm $slc),
+ (as_i1imm $tfe))
+ >;
+
+ def : Pat <
+ (vt (int_SI_buffer_load_dword v4i32:$rsrc, i32:$vaddr, i32:$soffset,
+ imm:$offset, 0, 1, imm:$glc, imm:$slc,
+ imm:$tfe)),
+ (idxen $vaddr, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc),
+ (as_i1imm $slc), (as_i1imm $tfe))
+ >;
+
+ def : Pat <
+ (vt (int_SI_buffer_load_dword v4i32:$rsrc, v2i32:$vaddr, i32:$soffset,
+ imm:$offset, 1, 1, imm:$glc, imm:$slc,
+ imm:$tfe)),
+ (bothen $vaddr, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc), (as_i1imm $slc),
+ (as_i1imm $tfe))
+ >;
+}
+
+defm : MUBUF_Load_Dword <i32, BUFFER_LOAD_DWORD_OFFSET, BUFFER_LOAD_DWORD_OFFEN,
+ BUFFER_LOAD_DWORD_IDXEN, BUFFER_LOAD_DWORD_BOTHEN>;
+defm : MUBUF_Load_Dword <v2i32, BUFFER_LOAD_DWORDX2_OFFSET, BUFFER_LOAD_DWORDX2_OFFEN,
+ BUFFER_LOAD_DWORDX2_IDXEN, BUFFER_LOAD_DWORDX2_BOTHEN>;
+defm : MUBUF_Load_Dword <v4i32, BUFFER_LOAD_DWORDX4_OFFSET, BUFFER_LOAD_DWORDX4_OFFEN,
+ BUFFER_LOAD_DWORDX4_IDXEN, BUFFER_LOAD_DWORDX4_BOTHEN>;
+
+multiclass MUBUFStore_Atomic_Pattern <MUBUF_Pseudo Instr_ADDR64, MUBUF_Pseudo Instr_OFFSET,
+ ValueType vt, PatFrag atomic_st> {
+ // Store follows atomic op convention so address is forst
+ def : Pat <
+ (atomic_st (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
+ i16:$offset, i1:$slc), vt:$val),
+ (Instr_ADDR64 $val, $vaddr, $srsrc, $soffset, $offset, 1, $slc, 0)
+ >;
+
+ def : Pat <
+ (atomic_st (MUBUFOffsetNoGLC v4i32:$rsrc, i32:$soffset, i16:$offset), vt:$val),
+ (Instr_OFFSET $val, $rsrc, $soffset, (as_i16imm $offset), 1, 0, 0)
+ >;
+}
+let Predicates = [isSICI] in {
+defm : MUBUFStore_Atomic_Pattern <BUFFER_STORE_DWORD_ADDR64, BUFFER_STORE_DWORD_OFFSET, i32, global_store_atomic>;
+defm : MUBUFStore_Atomic_Pattern <BUFFER_STORE_DWORDX2_ADDR64, BUFFER_STORE_DWORDX2_OFFSET, i64, global_store_atomic>;
+} // End Predicates = [isSICI]
+
+
+multiclass MUBUFStore_Pattern <MUBUF_Pseudo Instr_OFFSET, ValueType vt,
+ PatFrag st> {
+
+ def : Pat <
+ (st vt:$vdata, (MUBUFOffset v4i32:$srsrc, i32:$soffset,
+ i16:$offset, i1:$glc, i1:$slc, i1:$tfe)),
+ (Instr_OFFSET $vdata, $srsrc, $soffset, $offset, $glc, $slc, $tfe)
+ >;
+}
+
+defm : MUBUFStore_Pattern <BUFFER_STORE_BYTE_OFFSET, i16, truncstorei8_global>;
+defm : MUBUFStore_Pattern <BUFFER_STORE_SHORT_OFFSET, i16, global_store>;
+
+class MUBUFScratchStorePat <MUBUF_Pseudo Instr, ValueType vt, PatFrag st> : Pat <
+ (st vt:$value, (MUBUFScratch v4i32:$srsrc, i32:$vaddr, i32:$soffset,
+ u16imm:$offset)),
+ (Instr $value, $vaddr, $srsrc, $soffset, $offset, 0, 0, 0)
+>;
+
+def : MUBUFScratchStorePat <BUFFER_STORE_BYTE_OFFEN, i32, truncstorei8_private>;
+def : MUBUFScratchStorePat <BUFFER_STORE_SHORT_OFFEN, i32, truncstorei16_private>;
+def : MUBUFScratchStorePat <BUFFER_STORE_BYTE_OFFEN, i16, truncstorei8_private>;
+def : MUBUFScratchStorePat <BUFFER_STORE_SHORT_OFFEN, i16, store_private>;
+def : MUBUFScratchStorePat <BUFFER_STORE_DWORD_OFFEN, i32, store_private>;
+def : MUBUFScratchStorePat <BUFFER_STORE_DWORDX2_OFFEN, v2i32, store_private>;
+def : MUBUFScratchStorePat <BUFFER_STORE_DWORDX4_OFFEN, v4i32, store_private>;
+
+//===----------------------------------------------------------------------===//
+// MTBUF Patterns
+//===----------------------------------------------------------------------===//
+
+// TBUFFER_STORE_FORMAT_*, addr64=0
+class MTBUF_StoreResource <ValueType vt, int num_channels, MTBUF_Pseudo opcode> : Pat<
+ (SItbuffer_store v4i32:$rsrc, vt:$vdata, num_channels, i32:$vaddr,
+ i32:$soffset, imm:$inst_offset, imm:$dfmt,
+ imm:$nfmt, imm:$offen, imm:$idxen,
+ imm:$glc, imm:$slc, imm:$tfe),
+ (opcode
+ $vdata, (as_i16imm $inst_offset), (as_i1imm $offen), (as_i1imm $idxen),
+ (as_i1imm $glc), 0, (as_i8imm $dfmt), (as_i8imm $nfmt), $vaddr, $rsrc,
+ (as_i1imm $slc), (as_i1imm $tfe), $soffset)
+>;
+
+def : MTBUF_StoreResource <i32, 1, TBUFFER_STORE_FORMAT_X>;
+def : MTBUF_StoreResource <v2i32, 2, TBUFFER_STORE_FORMAT_XY>;
+def : MTBUF_StoreResource <v4i32, 3, TBUFFER_STORE_FORMAT_XYZ>;
+def : MTBUF_StoreResource <v4i32, 4, TBUFFER_STORE_FORMAT_XYZW>;
+
+} // End let Predicates = [isGCN]
+
+//===----------------------------------------------------------------------===//
+// Target instructions, move to the appropriate target TD file
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SI
+//===----------------------------------------------------------------------===//
+
+class MUBUF_Real_si <bits<7> op, MUBUF_Pseudo ps> :
+ MUBUF_Real<op, ps>,
+ Enc64,
+ SIMCInstr<ps.PseudoInstr, SIEncodingFamily.SI> {
+ let AssemblerPredicate=isSICI;
+ let DecoderNamespace="SICI";
+
+ let Inst{11-0} = !if(ps.has_offset, offset, ?);
+ let Inst{12} = ps.offen;
+ let Inst{13} = ps.idxen;
+ let Inst{14} = !if(ps.has_glc, glc, ps.glc_value);
+ let Inst{15} = ps.addr64;
+ let Inst{16} = lds;
+ let Inst{24-18} = op;
+ let Inst{31-26} = 0x38; //encoding
+ let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?);
+ let Inst{47-40} = !if(ps.has_vdata, vdata, ?);
+ let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?);
+ let Inst{54} = !if(ps.has_slc, slc, ?);
+ let Inst{55} = !if(ps.has_tfe, tfe, ?);
+ let Inst{63-56} = !if(ps.has_soffset, soffset, ?);
+}
+
+multiclass MUBUF_Real_AllAddr_si<bits<7> op> {
+ def _OFFSET_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET")>;
+ def _ADDR64_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_ADDR64")>;
+ def _OFFEN_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN")>;
+ def _IDXEN_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN")>;
+ def _BOTHEN_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN")>;
+}
+
+multiclass MUBUF_Real_Atomic_si<bits<7> op> : MUBUF_Real_AllAddr_si<op> {
+ def _RTN_OFFSET_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_OFFSET")>;
+ def _RTN_ADDR64_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_ADDR64")>;
+ def _RTN_OFFEN_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_OFFEN")>;
+ def _RTN_IDXEN_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_IDXEN")>;
+ def _RTN_BOTHEN_si : MUBUF_Real_si <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_BOTHEN")>;
+}
+
+defm BUFFER_LOAD_FORMAT_X : MUBUF_Real_AllAddr_si <0x00>;
+defm BUFFER_LOAD_FORMAT_XY : MUBUF_Real_AllAddr_si <0x01>;
+defm BUFFER_LOAD_FORMAT_XYZ : MUBUF_Real_AllAddr_si <0x02>;
+defm BUFFER_LOAD_FORMAT_XYZW : MUBUF_Real_AllAddr_si <0x03>;
+defm BUFFER_STORE_FORMAT_X : MUBUF_Real_AllAddr_si <0x04>;
+defm BUFFER_STORE_FORMAT_XY : MUBUF_Real_AllAddr_si <0x05>;
+defm BUFFER_STORE_FORMAT_XYZ : MUBUF_Real_AllAddr_si <0x06>;
+defm BUFFER_STORE_FORMAT_XYZW : MUBUF_Real_AllAddr_si <0x07>;
+defm BUFFER_LOAD_UBYTE : MUBUF_Real_AllAddr_si <0x08>;
+defm BUFFER_LOAD_SBYTE : MUBUF_Real_AllAddr_si <0x09>;
+defm BUFFER_LOAD_USHORT : MUBUF_Real_AllAddr_si <0x0a>;
+defm BUFFER_LOAD_SSHORT : MUBUF_Real_AllAddr_si <0x0b>;
+defm BUFFER_LOAD_DWORD : MUBUF_Real_AllAddr_si <0x0c>;
+defm BUFFER_LOAD_DWORDX2 : MUBUF_Real_AllAddr_si <0x0d>;
+defm BUFFER_LOAD_DWORDX4 : MUBUF_Real_AllAddr_si <0x0e>;
+defm BUFFER_LOAD_DWORDX3 : MUBUF_Real_AllAddr_si <0x0f>;
+defm BUFFER_STORE_BYTE : MUBUF_Real_AllAddr_si <0x18>;
+defm BUFFER_STORE_SHORT : MUBUF_Real_AllAddr_si <0x1a>;
+defm BUFFER_STORE_DWORD : MUBUF_Real_AllAddr_si <0x1c>;
+defm BUFFER_STORE_DWORDX2 : MUBUF_Real_AllAddr_si <0x1d>;
+defm BUFFER_STORE_DWORDX4 : MUBUF_Real_AllAddr_si <0x1e>;
+defm BUFFER_STORE_DWORDX3 : MUBUF_Real_AllAddr_si <0x1f>;
+
+defm BUFFER_ATOMIC_SWAP : MUBUF_Real_Atomic_si <0x30>;
+defm BUFFER_ATOMIC_CMPSWAP : MUBUF_Real_Atomic_si <0x31>;
+defm BUFFER_ATOMIC_ADD : MUBUF_Real_Atomic_si <0x32>;
+defm BUFFER_ATOMIC_SUB : MUBUF_Real_Atomic_si <0x33>;
+//defm BUFFER_ATOMIC_RSUB : MUBUF_Real_Atomic_si <0x34>; // isn't on CI & VI
+defm BUFFER_ATOMIC_SMIN : MUBUF_Real_Atomic_si <0x35>;
+defm BUFFER_ATOMIC_UMIN : MUBUF_Real_Atomic_si <0x36>;
+defm BUFFER_ATOMIC_SMAX : MUBUF_Real_Atomic_si <0x37>;
+defm BUFFER_ATOMIC_UMAX : MUBUF_Real_Atomic_si <0x38>;
+defm BUFFER_ATOMIC_AND : MUBUF_Real_Atomic_si <0x39>;
+defm BUFFER_ATOMIC_OR : MUBUF_Real_Atomic_si <0x3a>;
+defm BUFFER_ATOMIC_XOR : MUBUF_Real_Atomic_si <0x3b>;
+defm BUFFER_ATOMIC_INC : MUBUF_Real_Atomic_si <0x3c>;
+defm BUFFER_ATOMIC_DEC : MUBUF_Real_Atomic_si <0x3d>;
+
+//defm BUFFER_ATOMIC_FCMPSWAP : MUBUF_Real_Atomic_si <0x3e>; // isn't on VI
+//defm BUFFER_ATOMIC_FMIN : MUBUF_Real_Atomic_si <0x3f>; // isn't on VI
+//defm BUFFER_ATOMIC_FMAX : MUBUF_Real_Atomic_si <0x40>; // isn't on VI
+defm BUFFER_ATOMIC_SWAP_X2 : MUBUF_Real_Atomic_si <0x50>;
+defm BUFFER_ATOMIC_CMPSWAP_X2 : MUBUF_Real_Atomic_si <0x51>;
+defm BUFFER_ATOMIC_ADD_X2 : MUBUF_Real_Atomic_si <0x52>;
+defm BUFFER_ATOMIC_SUB_X2 : MUBUF_Real_Atomic_si <0x53>;
+//defm BUFFER_ATOMIC_RSUB_X2 : MUBUF_Real_Atomic_si <0x54>; // isn't on CI & VI
+defm BUFFER_ATOMIC_SMIN_X2 : MUBUF_Real_Atomic_si <0x55>;
+defm BUFFER_ATOMIC_UMIN_X2 : MUBUF_Real_Atomic_si <0x56>;
+defm BUFFER_ATOMIC_SMAX_X2 : MUBUF_Real_Atomic_si <0x57>;
+defm BUFFER_ATOMIC_UMAX_X2 : MUBUF_Real_Atomic_si <0x58>;
+defm BUFFER_ATOMIC_AND_X2 : MUBUF_Real_Atomic_si <0x59>;
+defm BUFFER_ATOMIC_OR_X2 : MUBUF_Real_Atomic_si <0x5a>;
+defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Real_Atomic_si <0x5b>;
+defm BUFFER_ATOMIC_INC_X2 : MUBUF_Real_Atomic_si <0x5c>;
+defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Real_Atomic_si <0x5d>;
+// FIXME: Need to handle hazard for BUFFER_ATOMIC_FCMPSWAP_X2 on CI.
+//defm BUFFER_ATOMIC_FCMPSWAP_X2 : MUBUF_Real_Atomic_si <0x5e">; // isn't on VI
+//defm BUFFER_ATOMIC_FMIN_X2 : MUBUF_Real_Atomic_si <0x5f>; // isn't on VI
+//defm BUFFER_ATOMIC_FMAX_X2 : MUBUF_Real_Atomic_si <0x60>; // isn't on VI
+
+def BUFFER_WBINVL1_SC_si : MUBUF_Real_si <0x70, BUFFER_WBINVL1_SC>;
+def BUFFER_WBINVL1_si : MUBUF_Real_si <0x71, BUFFER_WBINVL1>;
+
+class MTBUF_Real_si <bits<3> op, MTBUF_Pseudo ps> :
+ MTBUF_Real<ps>,
+ SIMCInstr<ps.PseudoInstr, SIEncodingFamily.SI> {
+ let AssemblerPredicate=isSICI;
+ let DecoderNamespace="SICI";
+
+ bits<1> addr64;
+ let Inst{15} = addr64;
+ let Inst{18-16} = op;
+}
+
+def TBUFFER_LOAD_FORMAT_XYZW_si : MTBUF_Real_si <3, TBUFFER_LOAD_FORMAT_XYZW>;
+def TBUFFER_STORE_FORMAT_X_si : MTBUF_Real_si <4, TBUFFER_STORE_FORMAT_X>;
+def TBUFFER_STORE_FORMAT_XY_si : MTBUF_Real_si <5, TBUFFER_STORE_FORMAT_XY>;
+def TBUFFER_STORE_FORMAT_XYZ_si : MTBUF_Real_si <6, TBUFFER_STORE_FORMAT_XYZ>;
+def TBUFFER_STORE_FORMAT_XYZW_si : MTBUF_Real_si <7, TBUFFER_STORE_FORMAT_XYZW>;
+
+
+//===----------------------------------------------------------------------===//
+// CI
+//===----------------------------------------------------------------------===//
+
+class MUBUF_Real_ci <bits<7> op, MUBUF_Pseudo ps> :
+ MUBUF_Real_si<op, ps> {
+ let AssemblerPredicate=isCIOnly;
+ let DecoderNamespace="CI";
+}
+
+def BUFFER_WBINVL1_VOL_ci : MUBUF_Real_ci <0x70, BUFFER_WBINVL1_VOL>;
+
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+class MUBUF_Real_vi <bits<7> op, MUBUF_Pseudo ps> :
+ MUBUF_Real<op, ps>,
+ Enc64,
+ SIMCInstr<ps.PseudoInstr, SIEncodingFamily.VI> {
+ let AssemblerPredicate=isVI;
+ let DecoderNamespace="VI";
+
+ let Inst{11-0} = !if(ps.has_offset, offset, ?);
+ let Inst{12} = ps.offen;
+ let Inst{13} = ps.idxen;
+ let Inst{14} = !if(ps.has_glc, glc, ps.glc_value);
+ let Inst{16} = lds;
+ let Inst{17} = !if(ps.has_slc, slc, ?);
+ let Inst{24-18} = op;
+ let Inst{31-26} = 0x38; //encoding
+ let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?);
+ let Inst{47-40} = !if(ps.has_vdata, vdata, ?);
+ let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?);
+ let Inst{55} = !if(ps.has_tfe, tfe, ?);
+ let Inst{63-56} = !if(ps.has_soffset, soffset, ?);
+}
+
+multiclass MUBUF_Real_AllAddr_vi<bits<7> op> {
+ def _OFFSET_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET")>;
+ def _OFFEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN")>;
+ def _IDXEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN")>;
+ def _BOTHEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN")>;
+}
+
+multiclass MUBUF_Real_Atomic_vi<bits<7> op> :
+ MUBUF_Real_AllAddr_vi<op> {
+ def _RTN_OFFSET_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_OFFSET")>;
+ def _RTN_OFFEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_OFFEN")>;
+ def _RTN_IDXEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_IDXEN")>;
+ def _RTN_BOTHEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_RTN_BOTHEN")>;
+}
+
+defm BUFFER_LOAD_FORMAT_X : MUBUF_Real_AllAddr_vi <0x00>;
+defm BUFFER_LOAD_FORMAT_XY : MUBUF_Real_AllAddr_vi <0x01>;
+defm BUFFER_LOAD_FORMAT_XYZ : MUBUF_Real_AllAddr_vi <0x02>;
+defm BUFFER_LOAD_FORMAT_XYZW : MUBUF_Real_AllAddr_vi <0x03>;
+defm BUFFER_STORE_FORMAT_X : MUBUF_Real_AllAddr_vi <0x04>;
+defm BUFFER_STORE_FORMAT_XY : MUBUF_Real_AllAddr_vi <0x05>;
+defm BUFFER_STORE_FORMAT_XYZ : MUBUF_Real_AllAddr_vi <0x06>;
+defm BUFFER_STORE_FORMAT_XYZW : MUBUF_Real_AllAddr_vi <0x07>;
+defm BUFFER_LOAD_UBYTE : MUBUF_Real_AllAddr_vi <0x10>;
+defm BUFFER_LOAD_SBYTE : MUBUF_Real_AllAddr_vi <0x11>;
+defm BUFFER_LOAD_USHORT : MUBUF_Real_AllAddr_vi <0x12>;
+defm BUFFER_LOAD_SSHORT : MUBUF_Real_AllAddr_vi <0x13>;
+defm BUFFER_LOAD_DWORD : MUBUF_Real_AllAddr_vi <0x14>;
+defm BUFFER_LOAD_DWORDX2 : MUBUF_Real_AllAddr_vi <0x15>;
+defm BUFFER_LOAD_DWORDX3 : MUBUF_Real_AllAddr_vi <0x16>;
+defm BUFFER_LOAD_DWORDX4 : MUBUF_Real_AllAddr_vi <0x17>;
+defm BUFFER_STORE_BYTE : MUBUF_Real_AllAddr_vi <0x18>;
+defm BUFFER_STORE_SHORT : MUBUF_Real_AllAddr_vi <0x1a>;
+defm BUFFER_STORE_DWORD : MUBUF_Real_AllAddr_vi <0x1c>;
+defm BUFFER_STORE_DWORDX2 : MUBUF_Real_AllAddr_vi <0x1d>;
+defm BUFFER_STORE_DWORDX3 : MUBUF_Real_AllAddr_vi <0x1e>;
+defm BUFFER_STORE_DWORDX4 : MUBUF_Real_AllAddr_vi <0x1f>;
+
+defm BUFFER_ATOMIC_SWAP : MUBUF_Real_Atomic_vi <0x40>;
+defm BUFFER_ATOMIC_CMPSWAP : MUBUF_Real_Atomic_vi <0x41>;
+defm BUFFER_ATOMIC_ADD : MUBUF_Real_Atomic_vi <0x42>;
+defm BUFFER_ATOMIC_SUB : MUBUF_Real_Atomic_vi <0x43>;
+defm BUFFER_ATOMIC_SMIN : MUBUF_Real_Atomic_vi <0x44>;
+defm BUFFER_ATOMIC_UMIN : MUBUF_Real_Atomic_vi <0x45>;
+defm BUFFER_ATOMIC_SMAX : MUBUF_Real_Atomic_vi <0x46>;
+defm BUFFER_ATOMIC_UMAX : MUBUF_Real_Atomic_vi <0x47>;
+defm BUFFER_ATOMIC_AND : MUBUF_Real_Atomic_vi <0x48>;
+defm BUFFER_ATOMIC_OR : MUBUF_Real_Atomic_vi <0x49>;
+defm BUFFER_ATOMIC_XOR : MUBUF_Real_Atomic_vi <0x4a>;
+defm BUFFER_ATOMIC_INC : MUBUF_Real_Atomic_vi <0x4b>;
+defm BUFFER_ATOMIC_DEC : MUBUF_Real_Atomic_vi <0x4c>;
+
+defm BUFFER_ATOMIC_SWAP_X2 : MUBUF_Real_Atomic_vi <0x60>;
+defm BUFFER_ATOMIC_CMPSWAP_X2 : MUBUF_Real_Atomic_vi <0x61>;
+defm BUFFER_ATOMIC_ADD_X2 : MUBUF_Real_Atomic_vi <0x62>;
+defm BUFFER_ATOMIC_SUB_X2 : MUBUF_Real_Atomic_vi <0x63>;
+defm BUFFER_ATOMIC_SMIN_X2 : MUBUF_Real_Atomic_vi <0x64>;
+defm BUFFER_ATOMIC_UMIN_X2 : MUBUF_Real_Atomic_vi <0x65>;
+defm BUFFER_ATOMIC_SMAX_X2 : MUBUF_Real_Atomic_vi <0x66>;
+defm BUFFER_ATOMIC_UMAX_X2 : MUBUF_Real_Atomic_vi <0x67>;
+defm BUFFER_ATOMIC_AND_X2 : MUBUF_Real_Atomic_vi <0x68>;
+defm BUFFER_ATOMIC_OR_X2 : MUBUF_Real_Atomic_vi <0x69>;
+defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Real_Atomic_vi <0x6a>;
+defm BUFFER_ATOMIC_INC_X2 : MUBUF_Real_Atomic_vi <0x6b>;
+defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Real_Atomic_vi <0x6c>;
+
+def BUFFER_WBINVL1_vi : MUBUF_Real_vi <0x3e, BUFFER_WBINVL1>;
+def BUFFER_WBINVL1_VOL_vi : MUBUF_Real_vi <0x3f, BUFFER_WBINVL1_VOL>;
+
+class MTBUF_Real_vi <bits<4> op, MTBUF_Pseudo ps> :
+ MTBUF_Real<ps>,
+ SIMCInstr<ps.PseudoInstr, SIEncodingFamily.VI> {
+ let AssemblerPredicate=isVI;
+ let DecoderNamespace="VI";
+
+ let Inst{18-15} = op;
+}
+
+def TBUFFER_LOAD_FORMAT_XYZW_vi : MTBUF_Real_vi <3, TBUFFER_LOAD_FORMAT_XYZW>;
+def TBUFFER_STORE_FORMAT_X_vi : MTBUF_Real_vi <4, TBUFFER_STORE_FORMAT_X>;
+def TBUFFER_STORE_FORMAT_XY_vi : MTBUF_Real_vi <5, TBUFFER_STORE_FORMAT_XY>;
+def TBUFFER_STORE_FORMAT_XYZ_vi : MTBUF_Real_vi <6, TBUFFER_STORE_FORMAT_XYZ>;
+def TBUFFER_STORE_FORMAT_XYZW_vi : MTBUF_Real_vi <7, TBUFFER_STORE_FORMAT_XYZW>;
+
diff --git a/contrib/llvm/lib/Target/AMDGPU/CIInstructions.td b/contrib/llvm/lib/Target/AMDGPU/CIInstructions.td
index f9a9f79..26a483a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/CIInstructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/CIInstructions.td
@@ -12,338 +12,4 @@
// S_CBRANCH_CDBGUSER
// S_CBRANCH_CDBGSYS
// S_CBRANCH_CDBGSYS_OR_USER
-// S_CBRANCH_CDBGSYS_AND_USER
-// DS_NOP
-// DS_GWS_SEMA_RELEASE_ALL
-// DS_WRAP_RTN_B32
-// DS_CNDXCHG32_RTN_B64
-// DS_WRITE_B96
-// DS_WRITE_B128
-// DS_CONDXCHG32_RTN_B128
-// DS_READ_B96
-// DS_READ_B128
-// BUFFER_LOAD_DWORDX3
-// BUFFER_STORE_DWORDX3
-
-//===----------------------------------------------------------------------===//
-// VOP1 Instructions
-//===----------------------------------------------------------------------===//
-
-let SubtargetPredicate = isCIVI in {
-
-let SchedRW = [WriteDoubleAdd] in {
-defm V_TRUNC_F64 : VOP1Inst <vop1<0x17>, "v_trunc_f64",
- VOP_F64_F64, ftrunc
->;
-defm V_CEIL_F64 : VOP1Inst <vop1<0x18>, "v_ceil_f64",
- VOP_F64_F64, fceil
->;
-defm V_FLOOR_F64 : VOP1Inst <vop1<0x1A>, "v_floor_f64",
- VOP_F64_F64, ffloor
->;
-defm V_RNDNE_F64 : VOP1Inst <vop1<0x19>, "v_rndne_f64",
- VOP_F64_F64, frint
->;
-} // End SchedRW = [WriteDoubleAdd]
-
-let SchedRW = [WriteQuarterRate32] in {
-defm V_LOG_LEGACY_F32 : VOP1Inst <vop1<0x45, 0x4c>, "v_log_legacy_f32",
- VOP_F32_F32
->;
-defm V_EXP_LEGACY_F32 : VOP1Inst <vop1<0x46, 0x4b>, "v_exp_legacy_f32",
- VOP_F32_F32
->;
-} // End SchedRW = [WriteQuarterRate32]
-
-//===----------------------------------------------------------------------===//
-// VOP3 Instructions
-//===----------------------------------------------------------------------===//
-
-defm V_QSAD_PK_U16_U8 : VOP3Inst <vop3<0x173>, "v_qsad_pk_u16_u8",
- VOP_I32_I32_I32
->;
-defm V_MQSAD_U16_U8 : VOP3Inst <vop3<0x172>, "v_mqsad_u16_u8",
- VOP_I32_I32_I32
->;
-defm V_MQSAD_U32_U8 : VOP3Inst <vop3<0x175>, "v_mqsad_u32_u8",
- VOP_I32_I32_I32
->;
-
-let isCommutable = 1 in {
-defm V_MAD_U64_U32 : VOP3Inst <vop3<0x176>, "v_mad_u64_u32",
- VOP_I64_I32_I32_I64
->;
-
-// XXX - Does this set VCC?
-defm V_MAD_I64_I32 : VOP3Inst <vop3<0x177>, "v_mad_i64_i32",
- VOP_I64_I32_I32_I64
->;
-} // End isCommutable = 1
-
-
-//===----------------------------------------------------------------------===//
-// DS Instructions
-//===----------------------------------------------------------------------===//
-defm DS_WRAP_RTN_F32 : DS_1A1D_RET <0x34, "ds_wrap_rtn_f32", VGPR_32, "ds_wrap_f32">;
-
-// DS_CONDXCHG32_RTN_B64
-// DS_CONDXCHG32_RTN_B128
-
-//===----------------------------------------------------------------------===//
-// SMRD Instructions
-//===----------------------------------------------------------------------===//
-
-defm S_DCACHE_INV_VOL : SMRD_Inval <smrd<0x1d, 0x22>,
- "s_dcache_inv_vol", int_amdgcn_s_dcache_inv_vol>;
-
-//===----------------------------------------------------------------------===//
-// MUBUF Instructions
-//===----------------------------------------------------------------------===//
-
-let DisableSIDecoder = 1 in {
-defm BUFFER_WBINVL1_VOL : MUBUF_Invalidate <mubuf<0x70, 0x3f>,
- "buffer_wbinvl1_vol", int_amdgcn_buffer_wbinvl1_vol
->;
-}
-
-//===----------------------------------------------------------------------===//
-// Flat Instructions
-//===----------------------------------------------------------------------===//
-
-defm FLAT_LOAD_UBYTE : FLAT_Load_Helper <
- flat<0x8, 0x10>, "flat_load_ubyte", VGPR_32
->;
-defm FLAT_LOAD_SBYTE : FLAT_Load_Helper <
- flat<0x9, 0x11>, "flat_load_sbyte", VGPR_32
->;
-defm FLAT_LOAD_USHORT : FLAT_Load_Helper <
- flat<0xa, 0x12>, "flat_load_ushort", VGPR_32
->;
-defm FLAT_LOAD_SSHORT : FLAT_Load_Helper <
- flat<0xb, 0x13>, "flat_load_sshort", VGPR_32>
-;
-defm FLAT_LOAD_DWORD : FLAT_Load_Helper <
- flat<0xc, 0x14>, "flat_load_dword", VGPR_32
->;
-defm FLAT_LOAD_DWORDX2 : FLAT_Load_Helper <
- flat<0xd, 0x15>, "flat_load_dwordx2", VReg_64
->;
-defm FLAT_LOAD_DWORDX4 : FLAT_Load_Helper <
- flat<0xe, 0x17>, "flat_load_dwordx4", VReg_128
->;
-defm FLAT_LOAD_DWORDX3 : FLAT_Load_Helper <
- flat<0xf, 0x16>, "flat_load_dwordx3", VReg_96
->;
-defm FLAT_STORE_BYTE : FLAT_Store_Helper <
- flat<0x18>, "flat_store_byte", VGPR_32
->;
-defm FLAT_STORE_SHORT : FLAT_Store_Helper <
- flat <0x1a>, "flat_store_short", VGPR_32
->;
-defm FLAT_STORE_DWORD : FLAT_Store_Helper <
- flat<0x1c>, "flat_store_dword", VGPR_32
->;
-defm FLAT_STORE_DWORDX2 : FLAT_Store_Helper <
- flat<0x1d>, "flat_store_dwordx2", VReg_64
->;
-defm FLAT_STORE_DWORDX4 : FLAT_Store_Helper <
- flat<0x1e, 0x1f>, "flat_store_dwordx4", VReg_128
->;
-defm FLAT_STORE_DWORDX3 : FLAT_Store_Helper <
- flat<0x1f, 0x1e>, "flat_store_dwordx3", VReg_96
->;
-defm FLAT_ATOMIC_SWAP : FLAT_ATOMIC <
- flat<0x30, 0x40>, "flat_atomic_swap", VGPR_32, i32, atomic_swap_flat
->;
-defm FLAT_ATOMIC_CMPSWAP : FLAT_ATOMIC <
- flat<0x31, 0x41>, "flat_atomic_cmpswap", VGPR_32, i32,
- atomic_cmp_swap_flat, v2i32, VReg_64
->;
-defm FLAT_ATOMIC_ADD : FLAT_ATOMIC <
- flat<0x32, 0x42>, "flat_atomic_add", VGPR_32, i32, atomic_add_flat
->;
-defm FLAT_ATOMIC_SUB : FLAT_ATOMIC <
- flat<0x33, 0x43>, "flat_atomic_sub", VGPR_32, i32, atomic_sub_flat
->;
-defm FLAT_ATOMIC_SMIN : FLAT_ATOMIC <
- flat<0x35, 0x44>, "flat_atomic_smin", VGPR_32, i32, atomic_min_flat
->;
-defm FLAT_ATOMIC_UMIN : FLAT_ATOMIC <
- flat<0x36, 0x45>, "flat_atomic_umin", VGPR_32, i32, atomic_umin_flat
->;
-defm FLAT_ATOMIC_SMAX : FLAT_ATOMIC <
- flat<0x37, 0x46>, "flat_atomic_smax", VGPR_32, i32, atomic_max_flat
->;
-defm FLAT_ATOMIC_UMAX : FLAT_ATOMIC <
- flat<0x38, 0x47>, "flat_atomic_umax", VGPR_32, i32, atomic_umax_flat
->;
-defm FLAT_ATOMIC_AND : FLAT_ATOMIC <
- flat<0x39, 0x48>, "flat_atomic_and", VGPR_32, i32, atomic_and_flat
->;
-defm FLAT_ATOMIC_OR : FLAT_ATOMIC <
- flat<0x3a, 0x49>, "flat_atomic_or", VGPR_32, i32, atomic_or_flat
->;
-defm FLAT_ATOMIC_XOR : FLAT_ATOMIC <
- flat<0x3b, 0x4a>, "flat_atomic_xor", VGPR_32, i32, atomic_xor_flat
->;
-defm FLAT_ATOMIC_INC : FLAT_ATOMIC <
- flat<0x3c, 0x4b>, "flat_atomic_inc", VGPR_32, i32, atomic_inc_flat
->;
-defm FLAT_ATOMIC_DEC : FLAT_ATOMIC <
- flat<0x3d, 0x4c>, "flat_atomic_dec", VGPR_32, i32, atomic_dec_flat
->;
-defm FLAT_ATOMIC_SWAP_X2 : FLAT_ATOMIC <
- flat<0x50, 0x60>, "flat_atomic_swap_x2", VReg_64, i64, atomic_swap_flat
->;
-defm FLAT_ATOMIC_CMPSWAP_X2 : FLAT_ATOMIC <
- flat<0x51, 0x61>, "flat_atomic_cmpswap_x2", VReg_64, i64,
- atomic_cmp_swap_flat, v2i64, VReg_128
->;
-defm FLAT_ATOMIC_ADD_X2 : FLAT_ATOMIC <
- flat<0x52, 0x62>, "flat_atomic_add_x2", VReg_64, i64, atomic_add_flat
->;
-defm FLAT_ATOMIC_SUB_X2 : FLAT_ATOMIC <
- flat<0x53, 0x63>, "flat_atomic_sub_x2", VReg_64, i64, atomic_sub_flat
->;
-defm FLAT_ATOMIC_SMIN_X2 : FLAT_ATOMIC <
- flat<0x55, 0x64>, "flat_atomic_smin_x2", VReg_64, i64, atomic_min_flat
->;
-defm FLAT_ATOMIC_UMIN_X2 : FLAT_ATOMIC <
- flat<0x56, 0x65>, "flat_atomic_umin_x2", VReg_64, i64, atomic_umin_flat
->;
-defm FLAT_ATOMIC_SMAX_X2 : FLAT_ATOMIC <
- flat<0x57, 0x66>, "flat_atomic_smax_x2", VReg_64, i64, atomic_max_flat
->;
-defm FLAT_ATOMIC_UMAX_X2 : FLAT_ATOMIC <
- flat<0x58, 0x67>, "flat_atomic_umax_x2", VReg_64, i64, atomic_umax_flat
->;
-defm FLAT_ATOMIC_AND_X2 : FLAT_ATOMIC <
- flat<0x59, 0x68>, "flat_atomic_and_x2", VReg_64, i64, atomic_and_flat
->;
-defm FLAT_ATOMIC_OR_X2 : FLAT_ATOMIC <
- flat<0x5a, 0x69>, "flat_atomic_or_x2", VReg_64, i64, atomic_or_flat
->;
-defm FLAT_ATOMIC_XOR_X2 : FLAT_ATOMIC <
- flat<0x5b, 0x6a>, "flat_atomic_xor_x2", VReg_64, i64, atomic_xor_flat
->;
-defm FLAT_ATOMIC_INC_X2 : FLAT_ATOMIC <
- flat<0x5c, 0x6b>, "flat_atomic_inc_x2", VReg_64, i64, atomic_inc_flat
->;
-defm FLAT_ATOMIC_DEC_X2 : FLAT_ATOMIC <
- flat<0x5d, 0x6c>, "flat_atomic_dec_x2", VReg_64, i64, atomic_dec_flat
->;
-
-} // End SubtargetPredicate = isCIVI
-
-// CI Only flat instructions
-
-let SubtargetPredicate = isCI, VIAssemblerPredicate = DisableInst, DisableVIDecoder = 1 in {
-
-defm FLAT_ATOMIC_FCMPSWAP : FLAT_ATOMIC <
- flat<0x3e>, "flat_atomic_fcmpswap", VGPR_32, f32,
- null_frag, v2f32, VReg_64
->;
-defm FLAT_ATOMIC_FMIN : FLAT_ATOMIC <
- flat<0x3f>, "flat_atomic_fmin", VGPR_32, f32
->;
-defm FLAT_ATOMIC_FMAX : FLAT_ATOMIC <
- flat<0x40>, "flat_atomic_fmax", VGPR_32, f32
->;
-defm FLAT_ATOMIC_FCMPSWAP_X2 : FLAT_ATOMIC <
- flat<0x5e>, "flat_atomic_fcmpswap_x2", VReg_64, f64,
- null_frag, v2f64, VReg_128
->;
-defm FLAT_ATOMIC_FMIN_X2 : FLAT_ATOMIC <
- flat<0x5f>, "flat_atomic_fmin_x2", VReg_64, f64
->;
-defm FLAT_ATOMIC_FMAX_X2 : FLAT_ATOMIC <
- flat<0x60>, "flat_atomic_fmax_x2", VReg_64, f64
->;
-
-} // End SubtargetPredicate = isCI, VIAssemblerPredicate = DisableInst, DisableVIDecoder = 1
-
-//===----------------------------------------------------------------------===//
-// Flat Patterns
-//===----------------------------------------------------------------------===//
-
-let Predicates = [isCIVI] in {
-
-// Patterns for global loads with no offset.
-class FlatLoadPat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat <
- (vt (node i64:$addr)),
- (inst $addr, 0, 0, 0)
->;
-
-class FlatLoadAtomicPat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat <
- (vt (node i64:$addr)),
- (inst $addr, 1, 0, 0)
->;
-
-def : FlatLoadPat <FLAT_LOAD_UBYTE, flat_az_extloadi8, i32>;
-def : FlatLoadPat <FLAT_LOAD_SBYTE, flat_sextloadi8, i32>;
-def : FlatLoadPat <FLAT_LOAD_USHORT, flat_az_extloadi16, i32>;
-def : FlatLoadPat <FLAT_LOAD_SSHORT, flat_sextloadi16, i32>;
-def : FlatLoadPat <FLAT_LOAD_DWORD, flat_load, i32>;
-def : FlatLoadPat <FLAT_LOAD_DWORDX2, flat_load, v2i32>;
-def : FlatLoadPat <FLAT_LOAD_DWORDX4, flat_load, v4i32>;
-
-def : FlatLoadAtomicPat <FLAT_LOAD_DWORD, atomic_flat_load, i32>;
-def : FlatLoadAtomicPat <FLAT_LOAD_DWORDX2, atomic_flat_load, i64>;
-
-
-class FlatStorePat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat <
- (node vt:$data, i64:$addr),
- (inst $addr, $data, 0, 0, 0)
->;
-
-class FlatStoreAtomicPat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat <
- // atomic store follows atomic binop convention so the address comes
- // first.
- (node i64:$addr, vt:$data),
- (inst $addr, $data, 1, 0, 0)
->;
-
-def : FlatStorePat <FLAT_STORE_BYTE, flat_truncstorei8, i32>;
-def : FlatStorePat <FLAT_STORE_SHORT, flat_truncstorei16, i32>;
-def : FlatStorePat <FLAT_STORE_DWORD, flat_store, i32>;
-def : FlatStorePat <FLAT_STORE_DWORDX2, flat_store, v2i32>;
-def : FlatStorePat <FLAT_STORE_DWORDX4, flat_store, v4i32>;
-
-def : FlatStoreAtomicPat <FLAT_STORE_DWORD, atomic_flat_store, i32>;
-def : FlatStoreAtomicPat <FLAT_STORE_DWORDX2, atomic_flat_store, i64>;
-
-class FlatAtomicPat <FLAT inst, SDPatternOperator node, ValueType vt,
- ValueType data_vt = vt> : Pat <
- (vt (node i64:$addr, data_vt:$data)),
- (inst $addr, $data, 0, 0)
->;
-
-def : FlatAtomicPat <FLAT_ATOMIC_ADD_RTN, atomic_add_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_SUB_RTN, atomic_sub_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_INC_RTN, atomic_inc_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_DEC_RTN, atomic_dec_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_AND_RTN, atomic_and_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_SMAX_RTN, atomic_max_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_UMAX_RTN, atomic_umax_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_SMIN_RTN, atomic_min_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_UMIN_RTN, atomic_umin_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_OR_RTN, atomic_or_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_SWAP_RTN, atomic_swap_global, i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_CMPSWAP_RTN, atomic_cmp_swap_global, i32, v2i32>;
-def : FlatAtomicPat <FLAT_ATOMIC_XOR_RTN, atomic_xor_global, i32>;
-
-def : FlatAtomicPat <FLAT_ATOMIC_ADD_X2_RTN, atomic_add_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_SUB_X2_RTN, atomic_sub_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_INC_X2_RTN, atomic_inc_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_DEC_X2_RTN, atomic_dec_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_AND_X2_RTN, atomic_and_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_SMAX_X2_RTN, atomic_max_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_UMAX_X2_RTN, atomic_umax_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_SMIN_X2_RTN, atomic_min_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_UMIN_X2_RTN, atomic_umin_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_OR_X2_RTN, atomic_or_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_SWAP_X2_RTN, atomic_swap_global, i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_CMPSWAP_X2_RTN, atomic_cmp_swap_global, i64, v2i64>;
-def : FlatAtomicPat <FLAT_ATOMIC_XOR_X2_RTN, atomic_xor_global, i64>;
-
-} // End Predicates = [isCIVI]
+// S_CBRANCH_CDBGSYS_AND_USER \ No newline at end of file
diff --git a/contrib/llvm/lib/Target/AMDGPU/CaymanInstructions.td b/contrib/llvm/lib/Target/AMDGPU/CaymanInstructions.td
index 98bc6e8..6b8e85a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/CaymanInstructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/CaymanInstructions.td
@@ -37,6 +37,9 @@ def MULLO_INT_cm : MULLO_INT_Common<0x8F>;
def MULHI_INT_cm : MULHI_INT_Common<0x90>;
def MULLO_UINT_cm : MULLO_UINT_Common<0x91>;
def MULHI_UINT_cm : MULHI_UINT_Common<0x92>;
+def MULHI_INT_cm24 : MULHI_INT24_Common<0x5c>;
+def MULHI_UINT_cm24 : MULHI_UINT24_Common<0xb2>;
+
def RECIPSQRT_CLAMPED_cm : RECIPSQRT_CLAMPED_Common<0x87>;
def EXP_IEEE_cm : EXP_IEEE_Common<0x81>;
def LOG_IEEE_cm : LOG_IEEE_Common<0x83>;
@@ -85,14 +88,13 @@ def RAT_STORE_TYPED_cm: CF_MEM_RAT_STORE_TYPED<0> {
let eop = 0; // This bit is not used on Cayman.
}
-class VTX_READ_cm <string name, bits<8> buffer_id, dag outs, list<dag> pattern>
- : VTX_WORD0_cm, VTX_READ<name, buffer_id, outs, pattern> {
+class VTX_READ_cm <string name, dag outs>
+ : VTX_WORD0_cm, VTX_READ<name, outs, []> {
// Static fields
let VC_INST = 0;
let FETCH_TYPE = 2;
let FETCH_WHOLE_QUAD = 0;
- let BUFFER_ID = buffer_id;
let SRC_REL = 0;
// XXX: We can infer this field based on the SRC_GPR. This would allow us
// to store vertex addresses in any channel, not just X.
@@ -105,9 +107,9 @@ class VTX_READ_cm <string name, bits<8> buffer_id, dag outs, list<dag> pattern>
let Inst{31-0} = Word0;
}
-class VTX_READ_8_cm <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_cm <"VTX_READ_8 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_TReg32_X:$dst_gpr), pattern> {
+def VTX_READ_8_cm
+ : VTX_READ_cm <"VTX_READ_8 $dst_gpr, $src_gpr",
+ (outs R600_TReg32_X:$dst_gpr)> {
let DST_SEL_X = 0;
let DST_SEL_Y = 7; // Masked
@@ -116,9 +118,9 @@ class VTX_READ_8_cm <bits<8> buffer_id, list<dag> pattern>
let DATA_FORMAT = 1; // FMT_8
}
-class VTX_READ_16_cm <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_cm <"VTX_READ_16 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_TReg32_X:$dst_gpr), pattern> {
+def VTX_READ_16_cm
+ : VTX_READ_cm <"VTX_READ_16 $dst_gpr, $src_gpr",
+ (outs R600_TReg32_X:$dst_gpr)> {
let DST_SEL_X = 0;
let DST_SEL_Y = 7; // Masked
let DST_SEL_Z = 7; // Masked
@@ -127,9 +129,9 @@ class VTX_READ_16_cm <bits<8> buffer_id, list<dag> pattern>
}
-class VTX_READ_32_cm <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_cm <"VTX_READ_32 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_TReg32_X:$dst_gpr), pattern> {
+def VTX_READ_32_cm
+ : VTX_READ_cm <"VTX_READ_32 $dst_gpr, $src_gpr",
+ (outs R600_TReg32_X:$dst_gpr)> {
let DST_SEL_X = 0;
let DST_SEL_Y = 7; // Masked
@@ -147,9 +149,9 @@ class VTX_READ_32_cm <bits<8> buffer_id, list<dag> pattern>
let Constraints = "$src_gpr.ptr = $dst_gpr";
}
-class VTX_READ_64_cm <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_cm <"VTX_READ_64 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_Reg64:$dst_gpr), pattern> {
+def VTX_READ_64_cm
+ : VTX_READ_cm <"VTX_READ_64 $dst_gpr.XY, $src_gpr",
+ (outs R600_Reg64:$dst_gpr)> {
let DST_SEL_X = 0;
let DST_SEL_Y = 1;
@@ -158,9 +160,9 @@ class VTX_READ_64_cm <bits<8> buffer_id, list<dag> pattern>
let DATA_FORMAT = 0x1D; // COLOR_32_32
}
-class VTX_READ_128_cm <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_cm <"VTX_READ_128 $dst_gpr.XYZW, $src_gpr", buffer_id,
- (outs R600_Reg128:$dst_gpr), pattern> {
+def VTX_READ_128_cm
+ : VTX_READ_cm <"VTX_READ_128 $dst_gpr.XYZW, $src_gpr",
+ (outs R600_Reg128:$dst_gpr)> {
let DST_SEL_X = 0;
let DST_SEL_Y = 1;
@@ -177,79 +179,44 @@ class VTX_READ_128_cm <bits<8> buffer_id, list<dag> pattern>
//===----------------------------------------------------------------------===//
// VTX Read from parameter memory space
//===----------------------------------------------------------------------===//
-def VTX_READ_PARAM_8_cm : VTX_READ_8_cm <0,
- [(set i32:$dst_gpr, (load_param_exti8 ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_16_cm : VTX_READ_16_cm <0,
- [(set i32:$dst_gpr, (load_param_exti16 ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_32_cm : VTX_READ_32_cm <0,
- [(set i32:$dst_gpr, (load_param ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_64_cm : VTX_READ_64_cm <0,
- [(set v2i32:$dst_gpr, (load_param ADDRVTX_READ:$src_gpr))]
->;
+def : Pat<(i32:$dst_gpr (vtx_id3_az_extloadi8 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_8_cm MEMxi:$src_gpr, 3)>;
+def : Pat<(i32:$dst_gpr (vtx_id3_az_extloadi16 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_16_cm MEMxi:$src_gpr, 3)>;
+def : Pat<(i32:$dst_gpr (vtx_id3_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_32_cm MEMxi:$src_gpr, 3)>;
+def : Pat<(v2i32:$dst_gpr (vtx_id3_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_64_cm MEMxi:$src_gpr, 3)>;
+def : Pat<(v4i32:$dst_gpr (vtx_id3_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_128_cm MEMxi:$src_gpr, 3)>;
-def VTX_READ_PARAM_128_cm : VTX_READ_128_cm <0,
- [(set v4i32:$dst_gpr, (load_param ADDRVTX_READ:$src_gpr))]
->;
+//===----------------------------------------------------------------------===//
+// VTX Read from constant memory space
+//===----------------------------------------------------------------------===//
+def : Pat<(i32:$dst_gpr (vtx_id2_az_extloadi8 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_8_cm MEMxi:$src_gpr, 2)>;
+def : Pat<(i32:$dst_gpr (vtx_id2_az_extloadi16 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_16_cm MEMxi:$src_gpr, 2)>;
+def : Pat<(i32:$dst_gpr (vtx_id2_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_32_cm MEMxi:$src_gpr, 2)>;
+def : Pat<(v2i32:$dst_gpr (vtx_id2_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_64_cm MEMxi:$src_gpr, 2)>;
+def : Pat<(v4i32:$dst_gpr (vtx_id2_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_128_cm MEMxi:$src_gpr, 2)>;
//===----------------------------------------------------------------------===//
// VTX Read from global memory space
//===----------------------------------------------------------------------===//
-
-// 8-bit reads
-def VTX_READ_ID1_8_cm : VTX_READ_8_cm <1,
- [(set i32:$dst_gpr, (vtx_id1_az_extloadi8 ADDRVTX_READ:$src_gpr))]
->;
-
-// 16-bit reads
-def VTX_READ_ID1_16_cm : VTX_READ_16_cm <1,
- [(set i32:$dst_gpr, (vtx_id1_az_extloadi16 ADDRVTX_READ:$src_gpr))]
->;
-
-// 32-bit reads
-def VTX_READ_ID1_32_cm : VTX_READ_32_cm <1,
- [(set i32:$dst_gpr, (vtx_id1_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 64-bit reads
-def VTX_READ_ID1_64_cm : VTX_READ_64_cm <1,
- [(set v2i32:$dst_gpr, (vtx_id1_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 128-bit reads
-def VTX_READ_ID1_128_cm : VTX_READ_128_cm <1,
- [(set v4i32:$dst_gpr, (vtx_id1_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 8-bit reads
-def VTX_READ_ID2_8_cm : VTX_READ_8_cm <2,
- [(set i32:$dst_gpr, (vtx_id2_az_extloadi8 ADDRVTX_READ:$src_gpr))]
->;
-
-// 16-bit reads
-def VTX_READ_ID2_16_cm : VTX_READ_16_cm <2,
- [(set i32:$dst_gpr, (vtx_id2_az_extloadi16 ADDRVTX_READ:$src_gpr))]
->;
-
-// 32-bit reads
-def VTX_READ_ID2_32_cm : VTX_READ_32_cm <2,
- [(set i32:$dst_gpr, (vtx_id2_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 64-bit reads
-def VTX_READ_ID2_64_cm : VTX_READ_64_cm <2,
- [(set v2i32:$dst_gpr, (vtx_id2_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 128-bit reads
-def VTX_READ_ID2_128_cm : VTX_READ_128_cm <2,
- [(set v4i32:$dst_gpr, (vtx_id2_load ADDRVTX_READ:$src_gpr))]
->;
+def : Pat<(i32:$dst_gpr (vtx_id1_az_extloadi8 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_8_cm MEMxi:$src_gpr, 1)>;
+def : Pat<(i32:$dst_gpr (vtx_id1_az_extloadi16 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_16_cm MEMxi:$src_gpr, 1)>;
+def : Pat<(i32:$dst_gpr (vtx_id1_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_32_cm MEMxi:$src_gpr, 1)>;
+def : Pat<(v2i32:$dst_gpr (vtx_id1_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_64_cm MEMxi:$src_gpr, 1)>;
+def : Pat<(v4i32:$dst_gpr (vtx_id1_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_128_cm MEMxi:$src_gpr, 1)>;
} // End isCayman
diff --git a/contrib/llvm/lib/Target/AMDGPU/DSInstructions.td b/contrib/llvm/lib/Target/AMDGPU/DSInstructions.td
new file mode 100644
index 0000000..a077001
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/DSInstructions.td
@@ -0,0 +1,906 @@
+//===-- DSInstructions.td - DS Instruction Defintions ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+class DS_Pseudo <string opName, dag outs, dag ins, string asmOps, list<dag> pattern=[]> :
+ InstSI <outs, ins, "", pattern>,
+ SIMCInstr <opName, SIEncodingFamily.NONE> {
+
+ let SubtargetPredicate = isGCN;
+
+ let LGKM_CNT = 1;
+ let DS = 1;
+ let Size = 8;
+ let UseNamedOperandTable = 1;
+ let Uses = [M0, EXEC];
+
+ // Most instruction load and store data, so set this as the default.
+ let mayLoad = 1;
+ let mayStore = 1;
+
+ let hasSideEffects = 0;
+ let SchedRW = [WriteLDS];
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+
+ let AsmMatchConverter = "cvtDS";
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ // Well these bits a kind of hack because it would be more natural
+ // to test "outs" and "ins" dags for the presence of particular operands
+ bits<1> has_vdst = 1;
+ bits<1> has_addr = 1;
+ bits<1> has_data0 = 1;
+ bits<1> has_data1 = 1;
+
+ bits<1> has_offset = 1; // has "offset" that should be split to offset0,1
+ bits<1> has_offset0 = 1;
+ bits<1> has_offset1 = 1;
+
+ bits<1> has_gds = 1;
+ bits<1> gdsValue = 0; // if has_gds == 0 set gds to this value
+}
+
+class DS_Real <DS_Pseudo ds> :
+ InstSI <ds.OutOperandList, ds.InOperandList, ds.Mnemonic # " " # ds.AsmOperands, []>,
+ Enc64 {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ds.SubtargetPredicate;
+ let AsmMatchConverter = ds.AsmMatchConverter;
+
+ // encoding fields
+ bits<8> vdst;
+ bits<1> gds;
+ bits<8> addr;
+ bits<8> data0;
+ bits<8> data1;
+ bits<8> offset0;
+ bits<8> offset1;
+
+ bits<16> offset;
+ let offset0 = !if(ds.has_offset, offset{7-0}, ?);
+ let offset1 = !if(ds.has_offset, offset{15-8}, ?);
+}
+
+
+// DS Pseudo instructions
+
+class DS_1A1D_NORET<string opName, RegisterClass rc = VGPR_32>
+: DS_Pseudo<opName,
+ (outs),
+ (ins VGPR_32:$addr, rc:$data0, offset:$offset, gds:$gds),
+ "$addr, $data0$offset$gds">,
+ AtomicNoRet<opName, 0> {
+
+ let has_data1 = 0;
+ let has_vdst = 0;
+}
+
+class DS_1A_Off8_NORET<string opName> : DS_Pseudo<opName,
+ (outs),
+ (ins VGPR_32:$addr, offset0:$offset0, offset1:$offset1, gds:$gds),
+ "$addr $offset0$offset1$gds"> {
+
+ let has_data0 = 0;
+ let has_data1 = 0;
+ let has_vdst = 0;
+ let has_offset = 0;
+ let AsmMatchConverter = "cvtDSOffset01";
+}
+
+class DS_1A2D_NORET<string opName, RegisterClass rc = VGPR_32>
+: DS_Pseudo<opName,
+ (outs),
+ (ins VGPR_32:$addr, rc:$data0, rc:$data1, offset:$offset, gds:$gds),
+ "$addr, $data0, $data1"#"$offset"#"$gds">,
+ AtomicNoRet<opName, 0> {
+
+ let has_vdst = 0;
+}
+
+class DS_1A2D_Off8_NORET <string opName, RegisterClass rc = VGPR_32>
+: DS_Pseudo<opName,
+ (outs),
+ (ins VGPR_32:$addr, rc:$data0, rc:$data1,
+ offset0:$offset0, offset1:$offset1, gds:$gds),
+ "$addr, $data0, $data1$offset0$offset1$gds"> {
+
+ let has_vdst = 0;
+ let has_offset = 0;
+ let AsmMatchConverter = "cvtDSOffset01";
+}
+
+class DS_1A1D_RET <string opName, RegisterClass rc = VGPR_32>
+: DS_Pseudo<opName,
+ (outs rc:$vdst),
+ (ins VGPR_32:$addr, rc:$data0, offset:$offset, gds:$gds),
+ "$vdst, $addr, $data0$offset$gds"> {
+
+ let hasPostISelHook = 1;
+ let has_data1 = 0;
+}
+
+class DS_1A2D_RET<string opName,
+ RegisterClass rc = VGPR_32,
+ RegisterClass src = rc>
+: DS_Pseudo<opName,
+ (outs rc:$vdst),
+ (ins VGPR_32:$addr, src:$data0, src:$data1, offset:$offset, gds:$gds),
+ "$vdst, $addr, $data0, $data1$offset$gds"> {
+
+ let hasPostISelHook = 1;
+}
+
+class DS_1A_RET<string opName, RegisterClass rc = VGPR_32>
+: DS_Pseudo<opName,
+ (outs rc:$vdst),
+ (ins VGPR_32:$addr, offset:$offset, gds:$gds),
+ "$vdst, $addr$offset$gds"> {
+
+ let has_data0 = 0;
+ let has_data1 = 0;
+}
+
+class DS_1A_Off8_RET <string opName, RegisterClass rc = VGPR_32>
+: DS_Pseudo<opName,
+ (outs rc:$vdst),
+ (ins VGPR_32:$addr, offset0:$offset0, offset1:$offset1, gds:$gds),
+ "$vdst, $addr$offset0$offset1$gds"> {
+
+ let has_offset = 0;
+ let has_data0 = 0;
+ let has_data1 = 0;
+ let AsmMatchConverter = "cvtDSOffset01";
+}
+
+class DS_1A_RET_GDS <string opName> : DS_Pseudo<opName,
+ (outs VGPR_32:$vdst),
+ (ins VGPR_32:$addr, offset:$offset),
+ "$vdst, $addr$offset gds"> {
+
+ let has_data0 = 0;
+ let has_data1 = 0;
+ let has_gds = 0;
+ let gdsValue = 1;
+}
+
+class DS_0A_RET <string opName> : DS_Pseudo<opName,
+ (outs VGPR_32:$vdst),
+ (ins offset:$offset, gds:$gds),
+ "$vdst$offset$gds"> {
+
+ let mayLoad = 1;
+ let mayStore = 1;
+
+ let has_addr = 0;
+ let has_data0 = 0;
+ let has_data1 = 0;
+}
+
+class DS_1A <string opName> : DS_Pseudo<opName,
+ (outs),
+ (ins VGPR_32:$addr, offset:$offset, gds:$gds),
+ "$addr$offset$gds"> {
+
+ let mayLoad = 1;
+ let mayStore = 1;
+
+ let has_vdst = 0;
+ let has_data0 = 0;
+ let has_data1 = 0;
+}
+
+class DS_1A_GDS <string opName> : DS_Pseudo<opName,
+ (outs),
+ (ins VGPR_32:$addr),
+ "$addr gds"> {
+
+ let has_vdst = 0;
+ let has_data0 = 0;
+ let has_data1 = 0;
+ let has_offset = 0;
+ let has_offset0 = 0;
+ let has_offset1 = 0;
+
+ let has_gds = 0;
+ let gdsValue = 1;
+}
+
+class DS_1A1D_PERMUTE <string opName, SDPatternOperator node = null_frag>
+: DS_Pseudo<opName,
+ (outs VGPR_32:$vdst),
+ (ins VGPR_32:$addr, VGPR_32:$data0, offset:$offset),
+ "$vdst, $addr, $data0$offset",
+ [(set i32:$vdst,
+ (node (DS1Addr1Offset i32:$addr, i16:$offset), i32:$data0))] > {
+
+ let mayLoad = 0;
+ let mayStore = 0;
+ let isConvergent = 1;
+
+ let has_data1 = 0;
+ let has_gds = 0;
+}
+
+def DS_ADD_U32 : DS_1A1D_NORET<"ds_add_u32">;
+def DS_SUB_U32 : DS_1A1D_NORET<"ds_sub_u32">;
+def DS_RSUB_U32 : DS_1A1D_NORET<"ds_rsub_u32">;
+def DS_INC_U32 : DS_1A1D_NORET<"ds_inc_u32">;
+def DS_DEC_U32 : DS_1A1D_NORET<"ds_dec_u32">;
+def DS_MIN_I32 : DS_1A1D_NORET<"ds_min_i32">;
+def DS_MAX_I32 : DS_1A1D_NORET<"ds_max_i32">;
+def DS_MIN_U32 : DS_1A1D_NORET<"ds_min_u32">;
+def DS_MAX_U32 : DS_1A1D_NORET<"ds_max_u32">;
+def DS_AND_B32 : DS_1A1D_NORET<"ds_and_b32">;
+def DS_OR_B32 : DS_1A1D_NORET<"ds_or_b32">;
+def DS_XOR_B32 : DS_1A1D_NORET<"ds_xor_b32">;
+def DS_ADD_F32 : DS_1A1D_NORET<"ds_add_f32">;
+def DS_MIN_F32 : DS_1A1D_NORET<"ds_min_f32">;
+def DS_MAX_F32 : DS_1A1D_NORET<"ds_max_f32">;
+
+let mayLoad = 0 in {
+def DS_WRITE_B8 : DS_1A1D_NORET<"ds_write_b8">;
+def DS_WRITE_B16 : DS_1A1D_NORET<"ds_write_b16">;
+def DS_WRITE_B32 : DS_1A1D_NORET<"ds_write_b32">;
+def DS_WRITE2_B32 : DS_1A2D_Off8_NORET<"ds_write2_b32">;
+def DS_WRITE2ST64_B32 : DS_1A2D_Off8_NORET<"ds_write2st64_b32">;
+}
+
+def DS_MSKOR_B32 : DS_1A2D_NORET<"ds_mskor_b32">;
+def DS_CMPST_B32 : DS_1A2D_NORET<"ds_cmpst_b32">;
+def DS_CMPST_F32 : DS_1A2D_NORET<"ds_cmpst_f32">;
+
+def DS_ADD_U64 : DS_1A1D_NORET<"ds_add_u64", VReg_64>;
+def DS_SUB_U64 : DS_1A1D_NORET<"ds_sub_u64", VReg_64>;
+def DS_RSUB_U64 : DS_1A1D_NORET<"ds_rsub_u64", VReg_64>;
+def DS_INC_U64 : DS_1A1D_NORET<"ds_inc_u64", VReg_64>;
+def DS_DEC_U64 : DS_1A1D_NORET<"ds_dec_u64", VReg_64>;
+def DS_MIN_I64 : DS_1A1D_NORET<"ds_min_i64", VReg_64>;
+def DS_MAX_I64 : DS_1A1D_NORET<"ds_max_i64", VReg_64>;
+def DS_MIN_U64 : DS_1A1D_NORET<"ds_min_u64", VReg_64>;
+def DS_MAX_U64 : DS_1A1D_NORET<"ds_max_u64", VReg_64>;
+def DS_AND_B64 : DS_1A1D_NORET<"ds_and_b64", VReg_64>;
+def DS_OR_B64 : DS_1A1D_NORET<"ds_or_b64", VReg_64>;
+def DS_XOR_B64 : DS_1A1D_NORET<"ds_xor_b64", VReg_64>;
+def DS_MSKOR_B64 : DS_1A2D_NORET<"ds_mskor_b64", VReg_64>;
+let mayLoad = 0 in {
+def DS_WRITE_B64 : DS_1A1D_NORET<"ds_write_b64", VReg_64>;
+def DS_WRITE2_B64 : DS_1A2D_Off8_NORET<"ds_write2_b64", VReg_64>;
+def DS_WRITE2ST64_B64 : DS_1A2D_Off8_NORET<"ds_write2st64_b64", VReg_64>;
+}
+def DS_CMPST_B64 : DS_1A2D_NORET<"ds_cmpst_b64", VReg_64>;
+def DS_CMPST_F64 : DS_1A2D_NORET<"ds_cmpst_f64", VReg_64>;
+def DS_MIN_F64 : DS_1A1D_NORET<"ds_min_f64", VReg_64>;
+def DS_MAX_F64 : DS_1A1D_NORET<"ds_max_f64", VReg_64>;
+
+def DS_ADD_RTN_U32 : DS_1A1D_RET<"ds_add_rtn_u32">,
+ AtomicNoRet<"ds_add_u32", 1>;
+def DS_ADD_RTN_F32 : DS_1A1D_RET<"ds_add_rtn_f32">,
+ AtomicNoRet<"ds_add_f32", 1>;
+def DS_SUB_RTN_U32 : DS_1A1D_RET<"ds_sub_rtn_u32">,
+ AtomicNoRet<"ds_sub_u32", 1>;
+def DS_RSUB_RTN_U32 : DS_1A1D_RET<"ds_rsub_rtn_u32">,
+ AtomicNoRet<"ds_rsub_u32", 1>;
+def DS_INC_RTN_U32 : DS_1A1D_RET<"ds_inc_rtn_u32">,
+ AtomicNoRet<"ds_inc_u32", 1>;
+def DS_DEC_RTN_U32 : DS_1A1D_RET<"ds_dec_rtn_u32">,
+ AtomicNoRet<"ds_dec_u32", 1>;
+def DS_MIN_RTN_I32 : DS_1A1D_RET<"ds_min_rtn_i32">,
+ AtomicNoRet<"ds_min_i32", 1>;
+def DS_MAX_RTN_I32 : DS_1A1D_RET<"ds_max_rtn_i32">,
+ AtomicNoRet<"ds_max_i32", 1>;
+def DS_MIN_RTN_U32 : DS_1A1D_RET<"ds_min_rtn_u32">,
+ AtomicNoRet<"ds_min_u32", 1>;
+def DS_MAX_RTN_U32 : DS_1A1D_RET<"ds_max_rtn_u32">,
+ AtomicNoRet<"ds_max_u32", 1>;
+def DS_AND_RTN_B32 : DS_1A1D_RET<"ds_and_rtn_b32">,
+ AtomicNoRet<"ds_and_b32", 1>;
+def DS_OR_RTN_B32 : DS_1A1D_RET<"ds_or_rtn_b32">,
+ AtomicNoRet<"ds_or_b32", 1>;
+def DS_XOR_RTN_B32 : DS_1A1D_RET<"ds_xor_rtn_b32">,
+ AtomicNoRet<"ds_xor_b32", 1>;
+def DS_MSKOR_RTN_B32 : DS_1A2D_RET<"ds_mskor_rtn_b32">,
+ AtomicNoRet<"ds_mskor_b32", 1>;
+def DS_CMPST_RTN_B32 : DS_1A2D_RET <"ds_cmpst_rtn_b32">,
+ AtomicNoRet<"ds_cmpst_b32", 1>;
+def DS_CMPST_RTN_F32 : DS_1A2D_RET <"ds_cmpst_rtn_f32">,
+ AtomicNoRet<"ds_cmpst_f32", 1>;
+def DS_MIN_RTN_F32 : DS_1A1D_RET <"ds_min_rtn_f32">,
+ AtomicNoRet<"ds_min_f32", 1>;
+def DS_MAX_RTN_F32 : DS_1A1D_RET <"ds_max_rtn_f32">,
+ AtomicNoRet<"ds_max_f32", 1>;
+
+def DS_WRXCHG_RTN_B32 : DS_1A1D_RET<"ds_wrxchg_rtn_b32">,
+ AtomicNoRet<"", 1>;
+def DS_WRXCHG2_RTN_B32 : DS_1A2D_RET<"ds_wrxchg2_rtn_b32", VReg_64, VGPR_32>,
+ AtomicNoRet<"", 1>;
+def DS_WRXCHG2ST64_RTN_B32 : DS_1A2D_RET<"ds_wrxchg2st64_rtn_b32", VReg_64, VGPR_32>,
+ AtomicNoRet<"", 1>;
+
+def DS_ADD_RTN_U64 : DS_1A1D_RET<"ds_add_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_add_u64", 1>;
+def DS_SUB_RTN_U64 : DS_1A1D_RET<"ds_sub_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_sub_u64", 1>;
+def DS_RSUB_RTN_U64 : DS_1A1D_RET<"ds_rsub_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_rsub_u64", 1>;
+def DS_INC_RTN_U64 : DS_1A1D_RET<"ds_inc_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_inc_u64", 1>;
+def DS_DEC_RTN_U64 : DS_1A1D_RET<"ds_dec_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_dec_u64", 1>;
+def DS_MIN_RTN_I64 : DS_1A1D_RET<"ds_min_rtn_i64", VReg_64>,
+ AtomicNoRet<"ds_min_i64", 1>;
+def DS_MAX_RTN_I64 : DS_1A1D_RET<"ds_max_rtn_i64", VReg_64>,
+ AtomicNoRet<"ds_max_i64", 1>;
+def DS_MIN_RTN_U64 : DS_1A1D_RET<"ds_min_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_min_u64", 1>;
+def DS_MAX_RTN_U64 : DS_1A1D_RET<"ds_max_rtn_u64", VReg_64>,
+ AtomicNoRet<"ds_max_u64", 1>;
+def DS_AND_RTN_B64 : DS_1A1D_RET<"ds_and_rtn_b64", VReg_64>,
+ AtomicNoRet<"ds_and_b64", 1>;
+def DS_OR_RTN_B64 : DS_1A1D_RET<"ds_or_rtn_b64", VReg_64>,
+ AtomicNoRet<"ds_or_b64", 1>;
+def DS_XOR_RTN_B64 : DS_1A1D_RET<"ds_xor_rtn_b64", VReg_64>,
+ AtomicNoRet<"ds_xor_b64", 1>;
+def DS_MSKOR_RTN_B64 : DS_1A2D_RET<"ds_mskor_rtn_b64", VReg_64>,
+ AtomicNoRet<"ds_mskor_b64", 1>;
+def DS_CMPST_RTN_B64 : DS_1A2D_RET<"ds_cmpst_rtn_b64", VReg_64>,
+ AtomicNoRet<"ds_cmpst_b64", 1>;
+def DS_CMPST_RTN_F64 : DS_1A2D_RET<"ds_cmpst_rtn_f64", VReg_64>,
+ AtomicNoRet<"ds_cmpst_f64", 1>;
+def DS_MIN_RTN_F64 : DS_1A1D_RET<"ds_min_rtn_f64", VReg_64>,
+ AtomicNoRet<"ds_min_f64", 1>;
+def DS_MAX_RTN_F64 : DS_1A1D_RET<"ds_max_rtn_f64", VReg_64>,
+ AtomicNoRet<"ds_max_f64", 1>;
+
+def DS_WRXCHG_RTN_B64 : DS_1A1D_RET<"ds_wrxchg_rtn_b64", VReg_64>,
+ AtomicNoRet<"ds_wrxchg_b64", 1>;
+def DS_WRXCHG2_RTN_B64 : DS_1A2D_RET<"ds_wrxchg2_rtn_b64", VReg_128, VReg_64>,
+ AtomicNoRet<"ds_wrxchg2_b64", 1>;
+def DS_WRXCHG2ST64_RTN_B64 : DS_1A2D_RET<"ds_wrxchg2st64_rtn_b64", VReg_128, VReg_64>,
+ AtomicNoRet<"ds_wrxchg2st64_b64", 1>;
+
+def DS_GWS_INIT : DS_1A_GDS<"ds_gws_init">;
+def DS_GWS_SEMA_V : DS_1A_GDS<"ds_gws_sema_v">;
+def DS_GWS_SEMA_BR : DS_1A_GDS<"ds_gws_sema_br">;
+def DS_GWS_SEMA_P : DS_1A_GDS<"ds_gws_sema_p">;
+def DS_GWS_BARRIER : DS_1A_GDS<"ds_gws_barrier">;
+
+def DS_ADD_SRC2_U32 : DS_1A<"ds_add_src2_u32">;
+def DS_SUB_SRC2_U32 : DS_1A<"ds_sub_src2_u32">;
+def DS_RSUB_SRC2_U32 : DS_1A<"ds_rsub_src2_u32">;
+def DS_INC_SRC2_U32 : DS_1A<"ds_inc_src2_u32">;
+def DS_DEC_SRC2_U32 : DS_1A<"ds_dec_src2_u32">;
+def DS_MIN_SRC2_I32 : DS_1A<"ds_min_src2_i32">;
+def DS_MAX_SRC2_I32 : DS_1A<"ds_max_src2_i32">;
+def DS_MIN_SRC2_U32 : DS_1A<"ds_min_src2_u32">;
+def DS_MAX_SRC2_U32 : DS_1A<"ds_max_src2_u32">;
+def DS_AND_SRC2_B32 : DS_1A<"ds_and_src_b32">;
+def DS_OR_SRC2_B32 : DS_1A<"ds_or_src2_b32">;
+def DS_XOR_SRC2_B32 : DS_1A<"ds_xor_src2_b32">;
+def DS_MIN_SRC2_F32 : DS_1A<"ds_min_src2_f32">;
+def DS_MAX_SRC2_F32 : DS_1A<"ds_max_src2_f32">;
+
+def DS_ADD_SRC2_U64 : DS_1A<"ds_add_src2_u64">;
+def DS_SUB_SRC2_U64 : DS_1A<"ds_sub_src2_u64">;
+def DS_RSUB_SRC2_U64 : DS_1A<"ds_rsub_src2_u64">;
+def DS_INC_SRC2_U64 : DS_1A<"ds_inc_src2_u64">;
+def DS_DEC_SRC2_U64 : DS_1A<"ds_dec_src2_u64">;
+def DS_MIN_SRC2_I64 : DS_1A<"ds_min_src2_i64">;
+def DS_MAX_SRC2_I64 : DS_1A<"ds_max_src2_i64">;
+def DS_MIN_SRC2_U64 : DS_1A<"ds_min_src2_u64">;
+def DS_MAX_SRC2_U64 : DS_1A<"ds_max_src2_u64">;
+def DS_AND_SRC2_B64 : DS_1A<"ds_and_src2_b64">;
+def DS_OR_SRC2_B64 : DS_1A<"ds_or_src2_b64">;
+def DS_XOR_SRC2_B64 : DS_1A<"ds_xor_src2_b64">;
+def DS_MIN_SRC2_F64 : DS_1A<"ds_min_src2_f64">;
+def DS_MAX_SRC2_F64 : DS_1A<"ds_max_src2_f64">;
+
+def DS_WRITE_SRC2_B32 : DS_1A_Off8_NORET<"ds_write_src2_b32">;
+def DS_WRITE_SRC2_B64 : DS_1A_Off8_NORET<"ds_write_src2_b64">;
+
+let Uses = [EXEC], mayLoad = 0, mayStore = 0, isConvergent = 1 in {
+def DS_SWIZZLE_B32 : DS_1A_RET <"ds_swizzle_b32">;
+}
+
+let mayStore = 0 in {
+def DS_READ_I8 : DS_1A_RET<"ds_read_i8">;
+def DS_READ_U8 : DS_1A_RET<"ds_read_u8">;
+def DS_READ_I16 : DS_1A_RET<"ds_read_i16">;
+def DS_READ_U16 : DS_1A_RET<"ds_read_u16">;
+def DS_READ_B32 : DS_1A_RET<"ds_read_b32">;
+def DS_READ_B64 : DS_1A_RET<"ds_read_b64", VReg_64>;
+
+def DS_READ2_B32 : DS_1A_Off8_RET<"ds_read2_b32", VReg_64>;
+def DS_READ2ST64_B32 : DS_1A_Off8_RET<"ds_read2st64_b32", VReg_64>;
+
+def DS_READ2_B64 : DS_1A_Off8_RET<"ds_read2_b64", VReg_128>;
+def DS_READ2ST64_B64 : DS_1A_Off8_RET<"ds_read2st64_b64", VReg_128>;
+}
+
+let SubtargetPredicate = isSICI in {
+def DS_CONSUME : DS_0A_RET<"ds_consume">;
+def DS_APPEND : DS_0A_RET<"ds_append">;
+def DS_ORDERED_COUNT : DS_1A_RET_GDS<"ds_ordered_count">;
+}
+
+//===----------------------------------------------------------------------===//
+// Instruction definitions for CI and newer.
+//===----------------------------------------------------------------------===//
+// Remaining instructions:
+// DS_NOP
+// DS_GWS_SEMA_RELEASE_ALL
+// DS_WRAP_RTN_B32
+// DS_CNDXCHG32_RTN_B64
+// DS_WRITE_B96
+// DS_WRITE_B128
+// DS_CONDXCHG32_RTN_B128
+// DS_READ_B96
+// DS_READ_B128
+
+let SubtargetPredicate = isCIVI in {
+
+def DS_WRAP_RTN_F32 : DS_1A1D_RET <"ds_wrap_rtn_f32">,
+ AtomicNoRet<"ds_wrap_f32", 1>;
+
+} // let SubtargetPredicate = isCIVI
+
+//===----------------------------------------------------------------------===//
+// Instruction definitions for VI and newer.
+//===----------------------------------------------------------------------===//
+
+let SubtargetPredicate = isVI in {
+
+let Uses = [EXEC] in {
+def DS_PERMUTE_B32 : DS_1A1D_PERMUTE <"ds_permute_b32",
+ int_amdgcn_ds_permute>;
+def DS_BPERMUTE_B32 : DS_1A1D_PERMUTE <"ds_bpermute_b32",
+ int_amdgcn_ds_bpermute>;
+}
+
+} // let SubtargetPredicate = isVI
+
+//===----------------------------------------------------------------------===//
+// DS Patterns
+//===----------------------------------------------------------------------===//
+
+let Predicates = [isGCN] in {
+
+def : Pat <
+ (int_amdgcn_ds_swizzle i32:$src, imm:$offset16),
+ (DS_SWIZZLE_B32 $src, (as_i16imm $offset16), (i1 0))
+>;
+
+class DSReadPat <DS_Pseudo inst, ValueType vt, PatFrag frag> : Pat <
+ (vt (frag (DS1Addr1Offset i32:$ptr, i32:$offset))),
+ (inst $ptr, (as_i16imm $offset), (i1 0))
+>;
+
+def : DSReadPat <DS_READ_I8, i32, si_sextload_local_i8>;
+def : DSReadPat <DS_READ_U8, i32, si_az_extload_local_i8>;
+def : DSReadPat <DS_READ_I8, i16, si_sextload_local_i8>;
+def : DSReadPat <DS_READ_U8, i16, si_az_extload_local_i8>;
+def : DSReadPat <DS_READ_I16, i32, si_sextload_local_i16>;
+def : DSReadPat <DS_READ_I16, i32, si_sextload_local_i16>;
+def : DSReadPat <DS_READ_U16, i32, si_az_extload_local_i16>;
+def : DSReadPat <DS_READ_U16, i16, si_load_local>;
+def : DSReadPat <DS_READ_B32, i32, si_load_local>;
+
+let AddedComplexity = 100 in {
+
+def : DSReadPat <DS_READ_B64, v2i32, si_load_local_align8>;
+
+} // End AddedComplexity = 100
+
+def : Pat <
+ (v2i32 (si_load_local (DS64Bit4ByteAligned i32:$ptr, i8:$offset0,
+ i8:$offset1))),
+ (DS_READ2_B32 $ptr, $offset0, $offset1, (i1 0))
+>;
+
+class DSWritePat <DS_Pseudo inst, ValueType vt, PatFrag frag> : Pat <
+ (frag vt:$value, (DS1Addr1Offset i32:$ptr, i32:$offset)),
+ (inst $ptr, $value, (as_i16imm $offset), (i1 0))
+>;
+
+def : DSWritePat <DS_WRITE_B8, i32, si_truncstore_local_i8>;
+def : DSWritePat <DS_WRITE_B16, i32, si_truncstore_local_i16>;
+def : DSWritePat <DS_WRITE_B8, i16, si_truncstore_local_i8>;
+def : DSWritePat <DS_WRITE_B16, i16, si_store_local>;
+def : DSWritePat <DS_WRITE_B32, i32, si_store_local>;
+
+let AddedComplexity = 100 in {
+
+def : DSWritePat <DS_WRITE_B64, v2i32, si_store_local_align8>;
+} // End AddedComplexity = 100
+
+def : Pat <
+ (si_store_local v2i32:$value, (DS64Bit4ByteAligned i32:$ptr, i8:$offset0,
+ i8:$offset1)),
+ (DS_WRITE2_B32 $ptr, (i32 (EXTRACT_SUBREG $value, sub0)),
+ (i32 (EXTRACT_SUBREG $value, sub1)), $offset0, $offset1,
+ (i1 0))
+>;
+
+class DSAtomicRetPat<DS_Pseudo inst, ValueType vt, PatFrag frag> : Pat <
+ (frag (DS1Addr1Offset i32:$ptr, i32:$offset), vt:$value),
+ (inst $ptr, $value, (as_i16imm $offset), (i1 0))
+>;
+
+class DSAtomicCmpXChg<DS_Pseudo inst, ValueType vt, PatFrag frag> : Pat <
+ (frag (DS1Addr1Offset i32:$ptr, i32:$offset), vt:$cmp, vt:$swap),
+ (inst $ptr, $cmp, $swap, (as_i16imm $offset), (i1 0))
+>;
+
+
+// 32-bit atomics.
+def : DSAtomicRetPat<DS_WRXCHG_RTN_B32, i32, si_atomic_swap_local>;
+def : DSAtomicRetPat<DS_ADD_RTN_U32, i32, si_atomic_load_add_local>;
+def : DSAtomicRetPat<DS_SUB_RTN_U32, i32, si_atomic_load_sub_local>;
+def : DSAtomicRetPat<DS_INC_RTN_U32, i32, si_atomic_inc_local>;
+def : DSAtomicRetPat<DS_DEC_RTN_U32, i32, si_atomic_dec_local>;
+def : DSAtomicRetPat<DS_AND_RTN_B32, i32, si_atomic_load_and_local>;
+def : DSAtomicRetPat<DS_OR_RTN_B32, i32, si_atomic_load_or_local>;
+def : DSAtomicRetPat<DS_XOR_RTN_B32, i32, si_atomic_load_xor_local>;
+def : DSAtomicRetPat<DS_MIN_RTN_I32, i32, si_atomic_load_min_local>;
+def : DSAtomicRetPat<DS_MAX_RTN_I32, i32, si_atomic_load_max_local>;
+def : DSAtomicRetPat<DS_MIN_RTN_U32, i32, si_atomic_load_umin_local>;
+def : DSAtomicRetPat<DS_MAX_RTN_U32, i32, si_atomic_load_umax_local>;
+def : DSAtomicCmpXChg<DS_CMPST_RTN_B32, i32, si_atomic_cmp_swap_32_local>;
+
+// 64-bit atomics.
+def : DSAtomicRetPat<DS_WRXCHG_RTN_B64, i64, si_atomic_swap_local>;
+def : DSAtomicRetPat<DS_ADD_RTN_U64, i64, si_atomic_load_add_local>;
+def : DSAtomicRetPat<DS_SUB_RTN_U64, i64, si_atomic_load_sub_local>;
+def : DSAtomicRetPat<DS_INC_RTN_U64, i64, si_atomic_inc_local>;
+def : DSAtomicRetPat<DS_DEC_RTN_U64, i64, si_atomic_dec_local>;
+def : DSAtomicRetPat<DS_AND_RTN_B64, i64, si_atomic_load_and_local>;
+def : DSAtomicRetPat<DS_OR_RTN_B64, i64, si_atomic_load_or_local>;
+def : DSAtomicRetPat<DS_XOR_RTN_B64, i64, si_atomic_load_xor_local>;
+def : DSAtomicRetPat<DS_MIN_RTN_I64, i64, si_atomic_load_min_local>;
+def : DSAtomicRetPat<DS_MAX_RTN_I64, i64, si_atomic_load_max_local>;
+def : DSAtomicRetPat<DS_MIN_RTN_U64, i64, si_atomic_load_umin_local>;
+def : DSAtomicRetPat<DS_MAX_RTN_U64, i64, si_atomic_load_umax_local>;
+
+def : DSAtomicCmpXChg<DS_CMPST_RTN_B64, i64, si_atomic_cmp_swap_64_local>;
+
+} // let Predicates = [isGCN]
+
+//===----------------------------------------------------------------------===//
+// Real instructions
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SIInstructions.td
+//===----------------------------------------------------------------------===//
+
+class DS_Real_si <bits<8> op, DS_Pseudo ds> :
+ DS_Real <ds>,
+ SIMCInstr <ds.Mnemonic, SIEncodingFamily.SI> {
+ let AssemblerPredicates=[isSICI];
+ let DecoderNamespace="SICI";
+
+ // encoding
+ let Inst{7-0} = !if(ds.has_offset0, offset0, 0);
+ let Inst{15-8} = !if(ds.has_offset1, offset1, 0);
+ let Inst{17} = !if(ds.has_gds, gds, ds.gdsValue);
+ let Inst{25-18} = op;
+ let Inst{31-26} = 0x36; // ds prefix
+ let Inst{39-32} = !if(ds.has_addr, addr, 0);
+ let Inst{47-40} = !if(ds.has_data0, data0, 0);
+ let Inst{55-48} = !if(ds.has_data1, data1, 0);
+ let Inst{63-56} = !if(ds.has_vdst, vdst, 0);
+}
+
+def DS_ADD_U32_si : DS_Real_si<0x0, DS_ADD_U32>;
+def DS_SUB_U32_si : DS_Real_si<0x1, DS_SUB_U32>;
+def DS_RSUB_U32_si : DS_Real_si<0x2, DS_RSUB_U32>;
+def DS_INC_U32_si : DS_Real_si<0x3, DS_INC_U32>;
+def DS_DEC_U32_si : DS_Real_si<0x4, DS_DEC_U32>;
+def DS_MIN_I32_si : DS_Real_si<0x5, DS_MIN_I32>;
+def DS_MAX_I32_si : DS_Real_si<0x6, DS_MAX_I32>;
+def DS_MIN_U32_si : DS_Real_si<0x7, DS_MIN_U32>;
+def DS_MAX_U32_si : DS_Real_si<0x8, DS_MAX_U32>;
+def DS_AND_B32_si : DS_Real_si<0x9, DS_AND_B32>;
+def DS_OR_B32_si : DS_Real_si<0xa, DS_OR_B32>;
+def DS_XOR_B32_si : DS_Real_si<0xb, DS_XOR_B32>;
+def DS_MSKOR_B32_si : DS_Real_si<0xc, DS_MSKOR_B32>;
+def DS_WRITE_B32_si : DS_Real_si<0xd, DS_WRITE_B32>;
+def DS_WRITE2_B32_si : DS_Real_si<0xe, DS_WRITE2_B32>;
+def DS_WRITE2ST64_B32_si : DS_Real_si<0xf, DS_WRITE2ST64_B32>;
+def DS_CMPST_B32_si : DS_Real_si<0x10, DS_CMPST_B32>;
+def DS_CMPST_F32_si : DS_Real_si<0x11, DS_CMPST_F32>;
+def DS_MIN_F32_si : DS_Real_si<0x12, DS_MIN_F32>;
+def DS_MAX_F32_si : DS_Real_si<0x13, DS_MAX_F32>;
+def DS_GWS_INIT_si : DS_Real_si<0x19, DS_GWS_INIT>;
+def DS_GWS_SEMA_V_si : DS_Real_si<0x1a, DS_GWS_SEMA_V>;
+def DS_GWS_SEMA_BR_si : DS_Real_si<0x1b, DS_GWS_SEMA_BR>;
+def DS_GWS_SEMA_P_si : DS_Real_si<0x1c, DS_GWS_SEMA_P>;
+def DS_GWS_BARRIER_si : DS_Real_si<0x1d, DS_GWS_BARRIER>;
+def DS_WRITE_B8_si : DS_Real_si<0x1e, DS_WRITE_B8>;
+def DS_WRITE_B16_si : DS_Real_si<0x1f, DS_WRITE_B16>;
+def DS_ADD_RTN_U32_si : DS_Real_si<0x20, DS_ADD_RTN_U32>;
+def DS_SUB_RTN_U32_si : DS_Real_si<0x21, DS_SUB_RTN_U32>;
+def DS_RSUB_RTN_U32_si : DS_Real_si<0x22, DS_RSUB_RTN_U32>;
+def DS_INC_RTN_U32_si : DS_Real_si<0x23, DS_INC_RTN_U32>;
+def DS_DEC_RTN_U32_si : DS_Real_si<0x24, DS_DEC_RTN_U32>;
+def DS_MIN_RTN_I32_si : DS_Real_si<0x25, DS_MIN_RTN_I32>;
+def DS_MAX_RTN_I32_si : DS_Real_si<0x26, DS_MAX_RTN_I32>;
+def DS_MIN_RTN_U32_si : DS_Real_si<0x27, DS_MIN_RTN_U32>;
+def DS_MAX_RTN_U32_si : DS_Real_si<0x28, DS_MAX_RTN_U32>;
+def DS_AND_RTN_B32_si : DS_Real_si<0x29, DS_AND_RTN_B32>;
+def DS_OR_RTN_B32_si : DS_Real_si<0x2a, DS_OR_RTN_B32>;
+def DS_XOR_RTN_B32_si : DS_Real_si<0x2b, DS_XOR_RTN_B32>;
+def DS_MSKOR_RTN_B32_si : DS_Real_si<0x2c, DS_MSKOR_RTN_B32>;
+def DS_WRXCHG_RTN_B32_si : DS_Real_si<0x2d, DS_WRXCHG_RTN_B32>;
+def DS_WRXCHG2_RTN_B32_si : DS_Real_si<0x2e, DS_WRXCHG2_RTN_B32>;
+def DS_WRXCHG2ST64_RTN_B32_si : DS_Real_si<0x2f, DS_WRXCHG2ST64_RTN_B32>;
+def DS_CMPST_RTN_B32_si : DS_Real_si<0x30, DS_CMPST_RTN_B32>;
+def DS_CMPST_RTN_F32_si : DS_Real_si<0x31, DS_CMPST_RTN_F32>;
+def DS_MIN_RTN_F32_si : DS_Real_si<0x32, DS_MIN_RTN_F32>;
+def DS_MAX_RTN_F32_si : DS_Real_si<0x33, DS_MAX_RTN_F32>;
+
+// FIXME: this instruction is actually CI/VI
+def DS_WRAP_RTN_F32_si : DS_Real_si<0x34, DS_WRAP_RTN_F32>;
+
+def DS_SWIZZLE_B32_si : DS_Real_si<0x35, DS_SWIZZLE_B32>;
+def DS_READ_B32_si : DS_Real_si<0x36, DS_READ_B32>;
+def DS_READ2_B32_si : DS_Real_si<0x37, DS_READ2_B32>;
+def DS_READ2ST64_B32_si : DS_Real_si<0x38, DS_READ2ST64_B32>;
+def DS_READ_I8_si : DS_Real_si<0x39, DS_READ_I8>;
+def DS_READ_U8_si : DS_Real_si<0x3a, DS_READ_U8>;
+def DS_READ_I16_si : DS_Real_si<0x3b, DS_READ_I16>;
+def DS_READ_U16_si : DS_Real_si<0x3c, DS_READ_U16>;
+def DS_CONSUME_si : DS_Real_si<0x3d, DS_CONSUME>;
+def DS_APPEND_si : DS_Real_si<0x3e, DS_APPEND>;
+def DS_ORDERED_COUNT_si : DS_Real_si<0x3f, DS_ORDERED_COUNT>;
+def DS_ADD_U64_si : DS_Real_si<0x40, DS_ADD_U64>;
+def DS_SUB_U64_si : DS_Real_si<0x41, DS_SUB_U64>;
+def DS_RSUB_U64_si : DS_Real_si<0x42, DS_RSUB_U64>;
+def DS_INC_U64_si : DS_Real_si<0x43, DS_INC_U64>;
+def DS_DEC_U64_si : DS_Real_si<0x44, DS_DEC_U64>;
+def DS_MIN_I64_si : DS_Real_si<0x45, DS_MIN_I64>;
+def DS_MAX_I64_si : DS_Real_si<0x46, DS_MAX_I64>;
+def DS_MIN_U64_si : DS_Real_si<0x47, DS_MIN_U64>;
+def DS_MAX_U64_si : DS_Real_si<0x48, DS_MAX_U64>;
+def DS_AND_B64_si : DS_Real_si<0x49, DS_AND_B64>;
+def DS_OR_B64_si : DS_Real_si<0x4a, DS_OR_B64>;
+def DS_XOR_B64_si : DS_Real_si<0x4b, DS_XOR_B64>;
+def DS_MSKOR_B64_si : DS_Real_si<0x4c, DS_MSKOR_B64>;
+def DS_WRITE_B64_si : DS_Real_si<0x4d, DS_WRITE_B64>;
+def DS_WRITE2_B64_si : DS_Real_si<0x4E, DS_WRITE2_B64>;
+def DS_WRITE2ST64_B64_si : DS_Real_si<0x4f, DS_WRITE2ST64_B64>;
+def DS_CMPST_B64_si : DS_Real_si<0x50, DS_CMPST_B64>;
+def DS_CMPST_F64_si : DS_Real_si<0x51, DS_CMPST_F64>;
+def DS_MIN_F64_si : DS_Real_si<0x52, DS_MIN_F64>;
+def DS_MAX_F64_si : DS_Real_si<0x53, DS_MAX_F64>;
+
+def DS_ADD_RTN_U64_si : DS_Real_si<0x60, DS_ADD_RTN_U64>;
+def DS_SUB_RTN_U64_si : DS_Real_si<0x61, DS_SUB_RTN_U64>;
+def DS_RSUB_RTN_U64_si : DS_Real_si<0x62, DS_RSUB_RTN_U64>;
+def DS_INC_RTN_U64_si : DS_Real_si<0x63, DS_INC_RTN_U64>;
+def DS_DEC_RTN_U64_si : DS_Real_si<0x64, DS_DEC_RTN_U64>;
+def DS_MIN_RTN_I64_si : DS_Real_si<0x65, DS_MIN_RTN_I64>;
+def DS_MAX_RTN_I64_si : DS_Real_si<0x66, DS_MAX_RTN_I64>;
+def DS_MIN_RTN_U64_si : DS_Real_si<0x67, DS_MIN_RTN_U64>;
+def DS_MAX_RTN_U64_si : DS_Real_si<0x68, DS_MAX_RTN_U64>;
+def DS_AND_RTN_B64_si : DS_Real_si<0x69, DS_AND_RTN_B64>;
+def DS_OR_RTN_B64_si : DS_Real_si<0x6a, DS_OR_RTN_B64>;
+def DS_XOR_RTN_B64_si : DS_Real_si<0x6b, DS_XOR_RTN_B64>;
+def DS_MSKOR_RTN_B64_si : DS_Real_si<0x6c, DS_MSKOR_RTN_B64>;
+def DS_WRXCHG_RTN_B64_si : DS_Real_si<0x6d, DS_WRXCHG_RTN_B64>;
+def DS_WRXCHG2_RTN_B64_si : DS_Real_si<0x6e, DS_WRXCHG2_RTN_B64>;
+def DS_WRXCHG2ST64_RTN_B64_si : DS_Real_si<0x6f, DS_WRXCHG2ST64_RTN_B64>;
+def DS_CMPST_RTN_B64_si : DS_Real_si<0x70, DS_CMPST_RTN_B64>;
+def DS_CMPST_RTN_F64_si : DS_Real_si<0x71, DS_CMPST_RTN_F64>;
+def DS_MIN_RTN_F64_si : DS_Real_si<0x72, DS_MIN_RTN_F64>;
+def DS_MAX_RTN_F64_si : DS_Real_si<0x73, DS_MAX_RTN_F64>;
+
+def DS_READ_B64_si : DS_Real_si<0x76, DS_READ_B64>;
+def DS_READ2_B64_si : DS_Real_si<0x77, DS_READ2_B64>;
+def DS_READ2ST64_B64_si : DS_Real_si<0x78, DS_READ2ST64_B64>;
+
+def DS_ADD_SRC2_U32_si : DS_Real_si<0x80, DS_ADD_SRC2_U32>;
+def DS_SUB_SRC2_U32_si : DS_Real_si<0x81, DS_SUB_SRC2_U32>;
+def DS_RSUB_SRC2_U32_si : DS_Real_si<0x82, DS_RSUB_SRC2_U32>;
+def DS_INC_SRC2_U32_si : DS_Real_si<0x83, DS_INC_SRC2_U32>;
+def DS_DEC_SRC2_U32_si : DS_Real_si<0x84, DS_DEC_SRC2_U32>;
+def DS_MIN_SRC2_I32_si : DS_Real_si<0x85, DS_MIN_SRC2_I32>;
+def DS_MAX_SRC2_I32_si : DS_Real_si<0x86, DS_MAX_SRC2_I32>;
+def DS_MIN_SRC2_U32_si : DS_Real_si<0x87, DS_MIN_SRC2_U32>;
+def DS_MAX_SRC2_U32_si : DS_Real_si<0x88, DS_MAX_SRC2_U32>;
+def DS_AND_SRC2_B32_si : DS_Real_si<0x89, DS_AND_SRC2_B32>;
+def DS_OR_SRC2_B32_si : DS_Real_si<0x8a, DS_OR_SRC2_B32>;
+def DS_XOR_SRC2_B32_si : DS_Real_si<0x8b, DS_XOR_SRC2_B32>;
+def DS_WRITE_SRC2_B32_si : DS_Real_si<0x8d, DS_WRITE_SRC2_B32>;
+
+def DS_MIN_SRC2_F32_si : DS_Real_si<0x92, DS_MIN_SRC2_F32>;
+def DS_MAX_SRC2_F32_si : DS_Real_si<0x93, DS_MAX_SRC2_F32>;
+
+def DS_ADD_SRC2_U64_si : DS_Real_si<0xc0, DS_ADD_SRC2_U64>;
+def DS_SUB_SRC2_U64_si : DS_Real_si<0xc1, DS_SUB_SRC2_U64>;
+def DS_RSUB_SRC2_U64_si : DS_Real_si<0xc2, DS_RSUB_SRC2_U64>;
+def DS_INC_SRC2_U64_si : DS_Real_si<0xc3, DS_INC_SRC2_U64>;
+def DS_DEC_SRC2_U64_si : DS_Real_si<0xc4, DS_DEC_SRC2_U64>;
+def DS_MIN_SRC2_I64_si : DS_Real_si<0xc5, DS_MIN_SRC2_I64>;
+def DS_MAX_SRC2_I64_si : DS_Real_si<0xc6, DS_MAX_SRC2_I64>;
+def DS_MIN_SRC2_U64_si : DS_Real_si<0xc7, DS_MIN_SRC2_U64>;
+def DS_MAX_SRC2_U64_si : DS_Real_si<0xc8, DS_MAX_SRC2_U64>;
+def DS_AND_SRC2_B64_si : DS_Real_si<0xc9, DS_AND_SRC2_B64>;
+def DS_OR_SRC2_B64_si : DS_Real_si<0xca, DS_OR_SRC2_B64>;
+def DS_XOR_SRC2_B64_si : DS_Real_si<0xcb, DS_XOR_SRC2_B64>;
+def DS_WRITE_SRC2_B64_si : DS_Real_si<0xcd, DS_WRITE_SRC2_B64>;
+
+def DS_MIN_SRC2_F64_si : DS_Real_si<0xd2, DS_MIN_SRC2_F64>;
+def DS_MAX_SRC2_F64_si : DS_Real_si<0xd3, DS_MAX_SRC2_F64>;
+
+//===----------------------------------------------------------------------===//
+// VIInstructions.td
+//===----------------------------------------------------------------------===//
+
+class DS_Real_vi <bits<8> op, DS_Pseudo ds> :
+ DS_Real <ds>,
+ SIMCInstr <ds.Mnemonic, SIEncodingFamily.VI> {
+ let AssemblerPredicates = [isVI];
+ let DecoderNamespace="VI";
+
+ // encoding
+ let Inst{7-0} = !if(ds.has_offset0, offset0, 0);
+ let Inst{15-8} = !if(ds.has_offset1, offset1, 0);
+ let Inst{16} = !if(ds.has_gds, gds, ds.gdsValue);
+ let Inst{24-17} = op;
+ let Inst{31-26} = 0x36; // ds prefix
+ let Inst{39-32} = !if(ds.has_addr, addr, 0);
+ let Inst{47-40} = !if(ds.has_data0, data0, 0);
+ let Inst{55-48} = !if(ds.has_data1, data1, 0);
+ let Inst{63-56} = !if(ds.has_vdst, vdst, 0);
+}
+
+def DS_ADD_U32_vi : DS_Real_vi<0x0, DS_ADD_U32>;
+def DS_SUB_U32_vi : DS_Real_vi<0x1, DS_SUB_U32>;
+def DS_RSUB_U32_vi : DS_Real_vi<0x2, DS_RSUB_U32>;
+def DS_INC_U32_vi : DS_Real_vi<0x3, DS_INC_U32>;
+def DS_DEC_U32_vi : DS_Real_vi<0x4, DS_DEC_U32>;
+def DS_MIN_I32_vi : DS_Real_vi<0x5, DS_MIN_I32>;
+def DS_MAX_I32_vi : DS_Real_vi<0x6, DS_MAX_I32>;
+def DS_MIN_U32_vi : DS_Real_vi<0x7, DS_MIN_U32>;
+def DS_MAX_U32_vi : DS_Real_vi<0x8, DS_MAX_U32>;
+def DS_AND_B32_vi : DS_Real_vi<0x9, DS_AND_B32>;
+def DS_OR_B32_vi : DS_Real_vi<0xa, DS_OR_B32>;
+def DS_XOR_B32_vi : DS_Real_vi<0xb, DS_XOR_B32>;
+def DS_MSKOR_B32_vi : DS_Real_vi<0xc, DS_MSKOR_B32>;
+def DS_WRITE_B32_vi : DS_Real_vi<0xd, DS_WRITE_B32>;
+def DS_WRITE2_B32_vi : DS_Real_vi<0xe, DS_WRITE2_B32>;
+def DS_WRITE2ST64_B32_vi : DS_Real_vi<0xf, DS_WRITE2ST64_B32>;
+def DS_CMPST_B32_vi : DS_Real_vi<0x10, DS_CMPST_B32>;
+def DS_CMPST_F32_vi : DS_Real_vi<0x11, DS_CMPST_F32>;
+def DS_MIN_F32_vi : DS_Real_vi<0x12, DS_MIN_F32>;
+def DS_MAX_F32_vi : DS_Real_vi<0x13, DS_MAX_F32>;
+def DS_ADD_F32_vi : DS_Real_vi<0x15, DS_ADD_F32>;
+def DS_GWS_INIT_vi : DS_Real_vi<0x19, DS_GWS_INIT>;
+def DS_GWS_SEMA_V_vi : DS_Real_vi<0x1a, DS_GWS_SEMA_V>;
+def DS_GWS_SEMA_BR_vi : DS_Real_vi<0x1b, DS_GWS_SEMA_BR>;
+def DS_GWS_SEMA_P_vi : DS_Real_vi<0x1c, DS_GWS_SEMA_P>;
+def DS_GWS_BARRIER_vi : DS_Real_vi<0x1d, DS_GWS_BARRIER>;
+def DS_WRITE_B8_vi : DS_Real_vi<0x1e, DS_WRITE_B8>;
+def DS_WRITE_B16_vi : DS_Real_vi<0x1f, DS_WRITE_B16>;
+def DS_ADD_RTN_U32_vi : DS_Real_vi<0x20, DS_ADD_RTN_U32>;
+def DS_SUB_RTN_U32_vi : DS_Real_vi<0x21, DS_SUB_RTN_U32>;
+def DS_RSUB_RTN_U32_vi : DS_Real_vi<0x22, DS_RSUB_RTN_U32>;
+def DS_INC_RTN_U32_vi : DS_Real_vi<0x23, DS_INC_RTN_U32>;
+def DS_DEC_RTN_U32_vi : DS_Real_vi<0x24, DS_DEC_RTN_U32>;
+def DS_MIN_RTN_I32_vi : DS_Real_vi<0x25, DS_MIN_RTN_I32>;
+def DS_MAX_RTN_I32_vi : DS_Real_vi<0x26, DS_MAX_RTN_I32>;
+def DS_MIN_RTN_U32_vi : DS_Real_vi<0x27, DS_MIN_RTN_U32>;
+def DS_MAX_RTN_U32_vi : DS_Real_vi<0x28, DS_MAX_RTN_U32>;
+def DS_AND_RTN_B32_vi : DS_Real_vi<0x29, DS_AND_RTN_B32>;
+def DS_OR_RTN_B32_vi : DS_Real_vi<0x2a, DS_OR_RTN_B32>;
+def DS_XOR_RTN_B32_vi : DS_Real_vi<0x2b, DS_XOR_RTN_B32>;
+def DS_MSKOR_RTN_B32_vi : DS_Real_vi<0x2c, DS_MSKOR_RTN_B32>;
+def DS_WRXCHG_RTN_B32_vi : DS_Real_vi<0x2d, DS_WRXCHG_RTN_B32>;
+def DS_WRXCHG2_RTN_B32_vi : DS_Real_vi<0x2e, DS_WRXCHG2_RTN_B32>;
+def DS_WRXCHG2ST64_RTN_B32_vi : DS_Real_vi<0x2f, DS_WRXCHG2ST64_RTN_B32>;
+def DS_CMPST_RTN_B32_vi : DS_Real_vi<0x30, DS_CMPST_RTN_B32>;
+def DS_CMPST_RTN_F32_vi : DS_Real_vi<0x31, DS_CMPST_RTN_F32>;
+def DS_MIN_RTN_F32_vi : DS_Real_vi<0x32, DS_MIN_RTN_F32>;
+def DS_MAX_RTN_F32_vi : DS_Real_vi<0x33, DS_MAX_RTN_F32>;
+def DS_WRAP_RTN_F32_vi : DS_Real_vi<0x34, DS_WRAP_RTN_F32>;
+def DS_ADD_RTN_F32_vi : DS_Real_vi<0x35, DS_ADD_RTN_F32>;
+def DS_READ_B32_vi : DS_Real_vi<0x36, DS_READ_B32>;
+def DS_READ2_B32_vi : DS_Real_vi<0x37, DS_READ2_B32>;
+def DS_READ2ST64_B32_vi : DS_Real_vi<0x38, DS_READ2ST64_B32>;
+def DS_READ_I8_vi : DS_Real_vi<0x39, DS_READ_I8>;
+def DS_READ_U8_vi : DS_Real_vi<0x3a, DS_READ_U8>;
+def DS_READ_I16_vi : DS_Real_vi<0x3b, DS_READ_I16>;
+def DS_READ_U16_vi : DS_Real_vi<0x3c, DS_READ_U16>;
+def DS_SWIZZLE_B32_vi : DS_Real_vi<0x3d, DS_SWIZZLE_B32>;
+def DS_PERMUTE_B32_vi : DS_Real_vi<0x3e, DS_PERMUTE_B32>;
+def DS_BPERMUTE_B32_vi : DS_Real_vi<0x3f, DS_BPERMUTE_B32>;
+
+def DS_ADD_U64_vi : DS_Real_vi<0x40, DS_ADD_U64>;
+def DS_SUB_U64_vi : DS_Real_vi<0x41, DS_SUB_U64>;
+def DS_RSUB_U64_vi : DS_Real_vi<0x42, DS_RSUB_U64>;
+def DS_INC_U64_vi : DS_Real_vi<0x43, DS_INC_U64>;
+def DS_DEC_U64_vi : DS_Real_vi<0x44, DS_DEC_U64>;
+def DS_MIN_I64_vi : DS_Real_vi<0x45, DS_MIN_I64>;
+def DS_MAX_I64_vi : DS_Real_vi<0x46, DS_MAX_I64>;
+def DS_MIN_U64_vi : DS_Real_vi<0x47, DS_MIN_U64>;
+def DS_MAX_U64_vi : DS_Real_vi<0x48, DS_MAX_U64>;
+def DS_AND_B64_vi : DS_Real_vi<0x49, DS_AND_B64>;
+def DS_OR_B64_vi : DS_Real_vi<0x4a, DS_OR_B64>;
+def DS_XOR_B64_vi : DS_Real_vi<0x4b, DS_XOR_B64>;
+def DS_MSKOR_B64_vi : DS_Real_vi<0x4c, DS_MSKOR_B64>;
+def DS_WRITE_B64_vi : DS_Real_vi<0x4d, DS_WRITE_B64>;
+def DS_WRITE2_B64_vi : DS_Real_vi<0x4E, DS_WRITE2_B64>;
+def DS_WRITE2ST64_B64_vi : DS_Real_vi<0x4f, DS_WRITE2ST64_B64>;
+def DS_CMPST_B64_vi : DS_Real_vi<0x50, DS_CMPST_B64>;
+def DS_CMPST_F64_vi : DS_Real_vi<0x51, DS_CMPST_F64>;
+def DS_MIN_F64_vi : DS_Real_vi<0x52, DS_MIN_F64>;
+def DS_MAX_F64_vi : DS_Real_vi<0x53, DS_MAX_F64>;
+
+def DS_ADD_RTN_U64_vi : DS_Real_vi<0x60, DS_ADD_RTN_U64>;
+def DS_SUB_RTN_U64_vi : DS_Real_vi<0x61, DS_SUB_RTN_U64>;
+def DS_RSUB_RTN_U64_vi : DS_Real_vi<0x62, DS_RSUB_RTN_U64>;
+def DS_INC_RTN_U64_vi : DS_Real_vi<0x63, DS_INC_RTN_U64>;
+def DS_DEC_RTN_U64_vi : DS_Real_vi<0x64, DS_DEC_RTN_U64>;
+def DS_MIN_RTN_I64_vi : DS_Real_vi<0x65, DS_MIN_RTN_I64>;
+def DS_MAX_RTN_I64_vi : DS_Real_vi<0x66, DS_MAX_RTN_I64>;
+def DS_MIN_RTN_U64_vi : DS_Real_vi<0x67, DS_MIN_RTN_U64>;
+def DS_MAX_RTN_U64_vi : DS_Real_vi<0x68, DS_MAX_RTN_U64>;
+def DS_AND_RTN_B64_vi : DS_Real_vi<0x69, DS_AND_RTN_B64>;
+def DS_OR_RTN_B64_vi : DS_Real_vi<0x6a, DS_OR_RTN_B64>;
+def DS_XOR_RTN_B64_vi : DS_Real_vi<0x6b, DS_XOR_RTN_B64>;
+def DS_MSKOR_RTN_B64_vi : DS_Real_vi<0x6c, DS_MSKOR_RTN_B64>;
+def DS_WRXCHG_RTN_B64_vi : DS_Real_vi<0x6d, DS_WRXCHG_RTN_B64>;
+def DS_WRXCHG2_RTN_B64_vi : DS_Real_vi<0x6e, DS_WRXCHG2_RTN_B64>;
+def DS_WRXCHG2ST64_RTN_B64_vi : DS_Real_vi<0x6f, DS_WRXCHG2ST64_RTN_B64>;
+def DS_CMPST_RTN_B64_vi : DS_Real_vi<0x70, DS_CMPST_RTN_B64>;
+def DS_CMPST_RTN_F64_vi : DS_Real_vi<0x71, DS_CMPST_RTN_F64>;
+def DS_MIN_RTN_F64_vi : DS_Real_vi<0x72, DS_MIN_RTN_F64>;
+def DS_MAX_RTN_F64_vi : DS_Real_vi<0x73, DS_MAX_RTN_F64>;
+
+def DS_READ_B64_vi : DS_Real_vi<0x76, DS_READ_B64>;
+def DS_READ2_B64_vi : DS_Real_vi<0x77, DS_READ2_B64>;
+def DS_READ2ST64_B64_vi : DS_Real_vi<0x78, DS_READ2ST64_B64>;
+
+def DS_ADD_SRC2_U32_vi : DS_Real_vi<0x80, DS_ADD_SRC2_U32>;
+def DS_SUB_SRC2_U32_vi : DS_Real_vi<0x81, DS_SUB_SRC2_U32>;
+def DS_RSUB_SRC2_U32_vi : DS_Real_vi<0x82, DS_RSUB_SRC2_U32>;
+def DS_INC_SRC2_U32_vi : DS_Real_vi<0x83, DS_INC_SRC2_U32>;
+def DS_DEC_SRC2_U32_vi : DS_Real_vi<0x84, DS_DEC_SRC2_U32>;
+def DS_MIN_SRC2_I32_vi : DS_Real_vi<0x85, DS_MIN_SRC2_I32>;
+def DS_MAX_SRC2_I32_vi : DS_Real_vi<0x86, DS_MAX_SRC2_I32>;
+def DS_MIN_SRC2_U32_vi : DS_Real_vi<0x87, DS_MIN_SRC2_U32>;
+def DS_MAX_SRC2_U32_vi : DS_Real_vi<0x88, DS_MAX_SRC2_U32>;
+def DS_AND_SRC2_B32_vi : DS_Real_vi<0x89, DS_AND_SRC2_B32>;
+def DS_OR_SRC2_B32_vi : DS_Real_vi<0x8a, DS_OR_SRC2_B32>;
+def DS_XOR_SRC2_B32_vi : DS_Real_vi<0x8b, DS_XOR_SRC2_B32>;
+def DS_WRITE_SRC2_B32_vi : DS_Real_vi<0x8d, DS_WRITE_SRC2_B32>;
+def DS_MIN_SRC2_F32_vi : DS_Real_vi<0x92, DS_MIN_SRC2_F32>;
+def DS_MAX_SRC2_F32_vi : DS_Real_vi<0x93, DS_MAX_SRC2_F32>;
+def DS_ADD_SRC2_U64_vi : DS_Real_vi<0xc0, DS_ADD_SRC2_U64>;
+def DS_SUB_SRC2_U64_vi : DS_Real_vi<0xc1, DS_SUB_SRC2_U64>;
+def DS_RSUB_SRC2_U64_vi : DS_Real_vi<0xc2, DS_RSUB_SRC2_U64>;
+def DS_INC_SRC2_U64_vi : DS_Real_vi<0xc3, DS_INC_SRC2_U64>;
+def DS_DEC_SRC2_U64_vi : DS_Real_vi<0xc4, DS_DEC_SRC2_U64>;
+def DS_MIN_SRC2_I64_vi : DS_Real_vi<0xc5, DS_MIN_SRC2_I64>;
+def DS_MAX_SRC2_I64_vi : DS_Real_vi<0xc6, DS_MAX_SRC2_I64>;
+def DS_MIN_SRC2_U64_vi : DS_Real_vi<0xc7, DS_MIN_SRC2_U64>;
+def DS_MAX_SRC2_U64_vi : DS_Real_vi<0xc8, DS_MAX_SRC2_U64>;
+def DS_AND_SRC2_B64_vi : DS_Real_vi<0xc9, DS_AND_SRC2_B64>;
+def DS_OR_SRC2_B64_vi : DS_Real_vi<0xca, DS_OR_SRC2_B64>;
+def DS_XOR_SRC2_B64_vi : DS_Real_vi<0xcb, DS_XOR_SRC2_B64>;
+def DS_WRITE_SRC2_B64_vi : DS_Real_vi<0xcd, DS_WRITE_SRC2_B64>;
+def DS_MIN_SRC2_F64_vi : DS_Real_vi<0xd2, DS_MIN_SRC2_F64>;
+def DS_MAX_SRC2_F64_vi : DS_Real_vi<0xd3, DS_MAX_SRC2_F64>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index e11de85..2247cad 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -28,6 +28,7 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetRegistry.h"
@@ -48,6 +49,18 @@ addOperand(MCInst &Inst, const MCOperand& Opnd) {
MCDisassembler::SoftFail;
}
+static DecodeStatus decodeSoppBrTarget(MCInst &Inst, unsigned Imm,
+ uint64_t Addr, const void *Decoder) {
+ auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder);
+
+ APInt SignedOffset(18, Imm * 4, true);
+ int64_t Offset = (SignedOffset.sext(64) + 4 + Addr).getSExtValue();
+
+ if (DAsm->tryAddingSymbolicOperand(Inst, Offset, Addr, true, 2, 2))
+ return MCDisassembler::Success;
+ return addOperand(Inst, MCOperand::createImm(Imm));
+}
+
#define DECODE_OPERAND2(RegClass, DecName) \
static DecodeStatus Decode##RegClass##RegisterClass(MCInst &Inst, \
unsigned Imm, \
@@ -68,12 +81,22 @@ DECODE_OPERAND(VReg_96)
DECODE_OPERAND(VReg_128)
DECODE_OPERAND(SReg_32)
-DECODE_OPERAND(SReg_32_XM0)
+DECODE_OPERAND(SReg_32_XM0_XEXEC)
DECODE_OPERAND(SReg_64)
+DECODE_OPERAND(SReg_64_XEXEC)
DECODE_OPERAND(SReg_128)
DECODE_OPERAND(SReg_256)
DECODE_OPERAND(SReg_512)
+
+static DecodeStatus decodeOperand_VSrc16(MCInst &Inst,
+ unsigned Imm,
+ uint64_t Addr,
+ const void *Decoder) {
+ auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder);
+ return addOperand(Inst, DAsm->decodeOperand_VSrc16(Imm));
+}
+
#define GET_SUBTARGETINFO_ENUM
#include "AMDGPUGenSubtargetInfo.inc"
#undef GET_SUBTARGETINFO_ENUM
@@ -217,12 +240,14 @@ MCOperand AMDGPUDisassembler::createSRegOperand(unsigned SRegClassID,
// ToDo: unclear if s[88:104] is available on VI. Can we use VCC as SGPR in
// this bundle?
default:
- assert(false);
- break;
+ llvm_unreachable("unhandled register class");
}
- if (Val % (1 << shift))
+
+ if (Val % (1 << shift)) {
*CommentStream << "Warning: " << getRegClassName(SRegClassID)
<< ": scalar reg isn't aligned " << Val;
+ }
+
return createRegOperand(SRegClassID, Val >> shift);
}
@@ -234,7 +259,16 @@ MCOperand AMDGPUDisassembler::decodeOperand_VS_64(unsigned Val) const {
return decodeSrcOp(OPW64, Val);
}
+MCOperand AMDGPUDisassembler::decodeOperand_VSrc16(unsigned Val) const {
+ return decodeSrcOp(OPW16, Val);
+}
+
MCOperand AMDGPUDisassembler::decodeOperand_VGPR_32(unsigned Val) const {
+ // Some instructions have operand restrictions beyond what the encoding
+ // allows. Some ordinarily VSrc_32 operands are VGPR_32, so clear the extra
+ // high bit.
+ Val &= 255;
+
return createRegOperand(AMDGPU::VGPR_32RegClassID, Val);
}
@@ -257,13 +291,17 @@ MCOperand AMDGPUDisassembler::decodeOperand_SReg_32(unsigned Val) const {
return decodeSrcOp(OPW32, Val);
}
-MCOperand AMDGPUDisassembler::decodeOperand_SReg_32_XM0(unsigned Val) const {
- // SReg_32_XM0 is SReg_32 without M0
+MCOperand AMDGPUDisassembler::decodeOperand_SReg_32_XM0_XEXEC(
+ unsigned Val) const {
+ // SReg_32_XM0 is SReg_32 without M0 or EXEC_LO/EXEC_HI
return decodeOperand_SReg_32(Val);
}
MCOperand AMDGPUDisassembler::decodeOperand_SReg_64(unsigned Val) const {
- // see decodeOperand_SReg_32 comment
+ return decodeSrcOp(OPW64, Val);
+}
+
+MCOperand AMDGPUDisassembler::decodeOperand_SReg_64_XEXEC(unsigned Val) const {
return decodeSrcOp(OPW64, Val);
}
@@ -299,28 +337,96 @@ MCOperand AMDGPUDisassembler::decodeIntImmed(unsigned Imm) {
// Cast prevents negative overflow.
}
-MCOperand AMDGPUDisassembler::decodeFPImmed(bool Is32, unsigned Imm) {
+static int64_t getInlineImmVal32(unsigned Imm) {
+ switch (Imm) {
+ case 240:
+ return FloatToBits(0.5f);
+ case 241:
+ return FloatToBits(-0.5f);
+ case 242:
+ return FloatToBits(1.0f);
+ case 243:
+ return FloatToBits(-1.0f);
+ case 244:
+ return FloatToBits(2.0f);
+ case 245:
+ return FloatToBits(-2.0f);
+ case 246:
+ return FloatToBits(4.0f);
+ case 247:
+ return FloatToBits(-4.0f);
+ case 248: // 1 / (2 * PI)
+ return 0x3e22f983;
+ default:
+ llvm_unreachable("invalid fp inline imm");
+ }
+}
+
+static int64_t getInlineImmVal64(unsigned Imm) {
+ switch (Imm) {
+ case 240:
+ return DoubleToBits(0.5);
+ case 241:
+ return DoubleToBits(-0.5);
+ case 242:
+ return DoubleToBits(1.0);
+ case 243:
+ return DoubleToBits(-1.0);
+ case 244:
+ return DoubleToBits(2.0);
+ case 245:
+ return DoubleToBits(-2.0);
+ case 246:
+ return DoubleToBits(4.0);
+ case 247:
+ return DoubleToBits(-4.0);
+ case 248: // 1 / (2 * PI)
+ return 0x3fc45f306dc9c882;
+ default:
+ llvm_unreachable("invalid fp inline imm");
+ }
+}
+
+static int64_t getInlineImmVal16(unsigned Imm) {
+ switch (Imm) {
+ case 240:
+ return 0x3800;
+ case 241:
+ return 0xB800;
+ case 242:
+ return 0x3C00;
+ case 243:
+ return 0xBC00;
+ case 244:
+ return 0x4000;
+ case 245:
+ return 0xC000;
+ case 246:
+ return 0x4400;
+ case 247:
+ return 0xC400;
+ case 248: // 1 / (2 * PI)
+ return 0x3118;
+ default:
+ llvm_unreachable("invalid fp inline imm");
+ }
+}
+
+MCOperand AMDGPUDisassembler::decodeFPImmed(OpWidthTy Width, unsigned Imm) {
assert(Imm >= AMDGPU::EncValues::INLINE_FLOATING_C_MIN
&& Imm <= AMDGPU::EncValues::INLINE_FLOATING_C_MAX);
+
// ToDo: case 248: 1/(2*PI) - is allowed only on VI
- // ToDo: AMDGPUInstPrinter does not support 1/(2*PI). It consider 1/(2*PI) as
- // literal constant.
- float V = 0.0f;
- switch (Imm) {
- case 240: V = 0.5f; break;
- case 241: V = -0.5f; break;
- case 242: V = 1.0f; break;
- case 243: V = -1.0f; break;
- case 244: V = 2.0f; break;
- case 245: V = -2.0f; break;
- case 246: V = 4.0f; break;
- case 247: V = -4.0f; break;
- case 248: return MCOperand::createImm(Is32 ? // 1/(2*PI)
- 0x3e22f983 :
- 0x3fc45f306dc9c882);
- default: break;
+ switch (Width) {
+ case OPW32:
+ return MCOperand::createImm(getInlineImmVal32(Imm));
+ case OPW64:
+ return MCOperand::createImm(getInlineImmVal64(Imm));
+ case OPW16:
+ return MCOperand::createImm(getInlineImmVal16(Imm));
+ default:
+ llvm_unreachable("implement me");
}
- return MCOperand::createImm(Is32? FloatToBits(V) : DoubleToBits(V));
}
unsigned AMDGPUDisassembler::getVgprClassId(const OpWidthTy Width) const {
@@ -328,7 +434,9 @@ unsigned AMDGPUDisassembler::getVgprClassId(const OpWidthTy Width) const {
assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
switch (Width) {
default: // fall
- case OPW32: return VGPR_32RegClassID;
+ case OPW32:
+ case OPW16:
+ return VGPR_32RegClassID;
case OPW64: return VReg_64RegClassID;
case OPW128: return VReg_128RegClassID;
}
@@ -339,7 +447,9 @@ unsigned AMDGPUDisassembler::getSgprClassId(const OpWidthTy Width) const {
assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
switch (Width) {
default: // fall
- case OPW32: return SGPR_32RegClassID;
+ case OPW32:
+ case OPW16:
+ return SGPR_32RegClassID;
case OPW64: return SGPR_64RegClassID;
case OPW128: return SGPR_128RegClassID;
}
@@ -350,7 +460,9 @@ unsigned AMDGPUDisassembler::getTtmpClassId(const OpWidthTy Width) const {
assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
switch (Width) {
default: // fall
- case OPW32: return TTMP_32RegClassID;
+ case OPW32:
+ case OPW16:
+ return TTMP_32RegClassID;
case OPW64: return TTMP_64RegClassID;
case OPW128: return TTMP_128RegClassID;
}
@@ -371,19 +483,26 @@ MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) c
return createSRegOperand(getTtmpClassId(Width), Val - TTMP_MIN);
}
- assert(Width == OPW32 || Width == OPW64);
- const bool Is32 = (Width == OPW32);
+ assert(Width == OPW16 || Width == OPW32 || Width == OPW64);
if (INLINE_INTEGER_C_MIN <= Val && Val <= INLINE_INTEGER_C_MAX)
return decodeIntImmed(Val);
if (INLINE_FLOATING_C_MIN <= Val && Val <= INLINE_FLOATING_C_MAX)
- return decodeFPImmed(Is32, Val);
+ return decodeFPImmed(Width, Val);
if (Val == LITERAL_CONST)
return decodeLiteralConstant();
- return Is32 ? decodeSpecialReg32(Val) : decodeSpecialReg64(Val);
+ switch (Width) {
+ case OPW32:
+ case OPW16:
+ return decodeSpecialReg32(Val);
+ case OPW64:
+ return decodeSpecialReg64(Val);
+ default:
+ llvm_unreachable("unexpected immediate type");
+ }
}
MCOperand AMDGPUDisassembler::decodeSpecialReg32(unsigned Val) const {
@@ -426,6 +545,56 @@ MCOperand AMDGPUDisassembler::decodeSpecialReg64(unsigned Val) const {
return errOperand(Val, "unknown operand encoding " + Twine(Val));
}
+//===----------------------------------------------------------------------===//
+// AMDGPUSymbolizer
+//===----------------------------------------------------------------------===//
+
+// Try to find symbol name for specified label
+bool AMDGPUSymbolizer::tryAddingSymbolicOperand(MCInst &Inst,
+ raw_ostream &/*cStream*/, int64_t Value,
+ uint64_t /*Address*/, bool IsBranch,
+ uint64_t /*Offset*/, uint64_t /*InstSize*/) {
+ typedef std::tuple<uint64_t, StringRef, uint8_t> SymbolInfoTy;
+ typedef std::vector<SymbolInfoTy> SectionSymbolsTy;
+
+ if (!IsBranch) {
+ return false;
+ }
+
+ auto *Symbols = static_cast<SectionSymbolsTy *>(DisInfo);
+ auto Result = std::find_if(Symbols->begin(), Symbols->end(),
+ [Value](const SymbolInfoTy& Val) {
+ return std::get<0>(Val) == static_cast<uint64_t>(Value)
+ && std::get<2>(Val) == ELF::STT_NOTYPE;
+ });
+ if (Result != Symbols->end()) {
+ auto *Sym = Ctx.getOrCreateSymbol(std::get<1>(*Result));
+ const auto *Add = MCSymbolRefExpr::create(Sym, Ctx);
+ Inst.addOperand(MCOperand::createExpr(Add));
+ return true;
+ }
+ return false;
+}
+
+void AMDGPUSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &cStream,
+ int64_t Value,
+ uint64_t Address) {
+ llvm_unreachable("unimplemented");
+}
+
+//===----------------------------------------------------------------------===//
+// Initialization
+//===----------------------------------------------------------------------===//
+
+static MCSymbolizer *createAMDGPUSymbolizer(const Triple &/*TT*/,
+ LLVMOpInfoCallback /*GetOpInfo*/,
+ LLVMSymbolLookupCallback /*SymbolLookUp*/,
+ void *DisInfo,
+ MCContext *Ctx,
+ std::unique_ptr<MCRelocationInfo> &&RelInfo) {
+ return new AMDGPUSymbolizer(*Ctx, std::move(RelInfo), DisInfo);
+}
+
static MCDisassembler *createAMDGPUDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
@@ -433,5 +602,8 @@ static MCDisassembler *createAMDGPUDisassembler(const Target &T,
}
extern "C" void LLVMInitializeAMDGPUDisassembler() {
- TargetRegistry::RegisterMCDisassembler(TheGCNTarget, createAMDGPUDisassembler);
+ TargetRegistry::RegisterMCDisassembler(getTheGCNTarget(),
+ createAMDGPUDisassembler);
+ TargetRegistry::RegisterMCSymbolizer(getTheGCNTarget(),
+ createAMDGPUSymbolizer);
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
index dff26a0..ee5883a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
+++ b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
@@ -18,76 +18,113 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
+#include "llvm/MC/MCDisassembler/MCSymbolizer.h"
+#include <cstdint>
+#include <algorithm>
+#include <memory>
namespace llvm {
- class MCContext;
- class MCInst;
- class MCOperand;
- class MCSubtargetInfo;
- class Twine;
-
- class AMDGPUDisassembler : public MCDisassembler {
- private:
- mutable ArrayRef<uint8_t> Bytes;
-
- public:
- AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) :
- MCDisassembler(STI, Ctx) {}
-
- ~AMDGPUDisassembler() {}
-
- DecodeStatus getInstruction(MCInst &MI, uint64_t &Size,
- ArrayRef<uint8_t> Bytes, uint64_t Address,
- raw_ostream &WS, raw_ostream &CS) const override;
-
- const char* getRegClassName(unsigned RegClassID) const;
-
- MCOperand createRegOperand(unsigned int RegId) const;
- MCOperand createRegOperand(unsigned RegClassID, unsigned Val) const;
- MCOperand createSRegOperand(unsigned SRegClassID, unsigned Val) const;
-
- MCOperand errOperand(unsigned V, const llvm::Twine& ErrMsg) const;
-
- DecodeStatus tryDecodeInst(const uint8_t* Table,
- MCInst &MI,
- uint64_t Inst,
- uint64_t Address) const;
-
- MCOperand decodeOperand_VGPR_32(unsigned Val) const;
- MCOperand decodeOperand_VS_32(unsigned Val) const;
- MCOperand decodeOperand_VS_64(unsigned Val) const;
-
- MCOperand decodeOperand_VReg_64(unsigned Val) const;
- MCOperand decodeOperand_VReg_96(unsigned Val) const;
- MCOperand decodeOperand_VReg_128(unsigned Val) const;
-
- MCOperand decodeOperand_SReg_32(unsigned Val) const;
- MCOperand decodeOperand_SReg_32_XM0(unsigned Val) const;
- MCOperand decodeOperand_SReg_64(unsigned Val) const;
- MCOperand decodeOperand_SReg_128(unsigned Val) const;
- MCOperand decodeOperand_SReg_256(unsigned Val) const;
- MCOperand decodeOperand_SReg_512(unsigned Val) const;
-
- enum OpWidthTy {
- OPW32,
- OPW64,
- OPW128,
- OPW_LAST_,
- OPW_FIRST_ = OPW32
- };
- unsigned getVgprClassId(const OpWidthTy Width) const;
- unsigned getSgprClassId(const OpWidthTy Width) const;
- unsigned getTtmpClassId(const OpWidthTy Width) const;
-
- static MCOperand decodeIntImmed(unsigned Imm);
- static MCOperand decodeFPImmed(bool Is32, unsigned Imm);
- MCOperand decodeLiteralConstant() const;
-
- MCOperand decodeSrcOp(const OpWidthTy Width, unsigned Val) const;
- MCOperand decodeSpecialReg32(unsigned Val) const;
- MCOperand decodeSpecialReg64(unsigned Val) const;
+class MCContext;
+class MCInst;
+class MCOperand;
+class MCSubtargetInfo;
+class Twine;
+
+//===----------------------------------------------------------------------===//
+// AMDGPUDisassembler
+//===----------------------------------------------------------------------===//
+
+class AMDGPUDisassembler : public MCDisassembler {
+private:
+ mutable ArrayRef<uint8_t> Bytes;
+
+public:
+ AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) :
+ MCDisassembler(STI, Ctx) {}
+
+ ~AMDGPUDisassembler() override = default;
+
+ DecodeStatus getInstruction(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &WS, raw_ostream &CS) const override;
+
+ const char* getRegClassName(unsigned RegClassID) const;
+
+ MCOperand createRegOperand(unsigned int RegId) const;
+ MCOperand createRegOperand(unsigned RegClassID, unsigned Val) const;
+ MCOperand createSRegOperand(unsigned SRegClassID, unsigned Val) const;
+
+ MCOperand errOperand(unsigned V, const Twine& ErrMsg) const;
+
+ DecodeStatus tryDecodeInst(const uint8_t* Table,
+ MCInst &MI,
+ uint64_t Inst,
+ uint64_t Address) const;
+
+ MCOperand decodeOperand_VGPR_32(unsigned Val) const;
+ MCOperand decodeOperand_VS_32(unsigned Val) const;
+ MCOperand decodeOperand_VS_64(unsigned Val) const;
+ MCOperand decodeOperand_VSrc16(unsigned Val) const;
+
+ MCOperand decodeOperand_VReg_64(unsigned Val) const;
+ MCOperand decodeOperand_VReg_96(unsigned Val) const;
+ MCOperand decodeOperand_VReg_128(unsigned Val) const;
+
+ MCOperand decodeOperand_SReg_32(unsigned Val) const;
+ MCOperand decodeOperand_SReg_32_XM0_XEXEC(unsigned Val) const;
+ MCOperand decodeOperand_SReg_64(unsigned Val) const;
+ MCOperand decodeOperand_SReg_64_XEXEC(unsigned Val) const;
+ MCOperand decodeOperand_SReg_128(unsigned Val) const;
+ MCOperand decodeOperand_SReg_256(unsigned Val) const;
+ MCOperand decodeOperand_SReg_512(unsigned Val) const;
+
+ enum OpWidthTy {
+ OPW32,
+ OPW64,
+ OPW128,
+ OPW16,
+ OPW_LAST_,
+ OPW_FIRST_ = OPW32
};
-} // namespace llvm
-#endif //LLVM_LIB_TARGET_AMDGPU_DISASSEMBLER_AMDGPUDISASSEMBLER_H
+ unsigned getVgprClassId(const OpWidthTy Width) const;
+ unsigned getSgprClassId(const OpWidthTy Width) const;
+ unsigned getTtmpClassId(const OpWidthTy Width) const;
+
+ static MCOperand decodeIntImmed(unsigned Imm);
+ static MCOperand decodeFPImmed(OpWidthTy Width, unsigned Imm);
+ MCOperand decodeLiteralConstant() const;
+
+ MCOperand decodeSrcOp(const OpWidthTy Width, unsigned Val) const;
+ MCOperand decodeSpecialReg32(unsigned Val) const;
+ MCOperand decodeSpecialReg64(unsigned Val) const;
+};
+
+//===----------------------------------------------------------------------===//
+// AMDGPUSymbolizer
+//===----------------------------------------------------------------------===//
+
+class AMDGPUSymbolizer : public MCSymbolizer {
+private:
+ void *DisInfo;
+
+public:
+ AMDGPUSymbolizer(MCContext &Ctx, std::unique_ptr<MCRelocationInfo> &&RelInfo,
+ void *disInfo)
+ : MCSymbolizer(Ctx, std::move(RelInfo)), DisInfo(disInfo) {}
+
+ bool tryAddingSymbolicOperand(MCInst &Inst, raw_ostream &cStream,
+ int64_t Value, uint64_t Address,
+ bool IsBranch, uint64_t Offset,
+ uint64_t InstSize) override;
+
+ void tryAddingPcLoadReferenceComment(raw_ostream &cStream,
+ int64_t Value,
+ uint64_t Address) override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_AMDGPU_DISASSEMBLER_AMDGPUDISASSEMBLER_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/EvergreenInstructions.td b/contrib/llvm/lib/Target/AMDGPU/EvergreenInstructions.td
index 94f05cc..48c6592 100644
--- a/contrib/llvm/lib/Target/AMDGPU/EvergreenInstructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/EvergreenInstructions.td
@@ -72,6 +72,8 @@ def MULLO_INT_eg : MULLO_INT_Common<0x8F>;
def MULHI_INT_eg : MULHI_INT_Common<0x90>;
def MULLO_UINT_eg : MULLO_UINT_Common<0x91>;
def MULHI_UINT_eg : MULHI_UINT_Common<0x92>;
+def MULHI_UINT24_eg : MULHI_UINT24_Common<0xb2>;
+
def RECIP_UINT_eg : RECIP_UINT_Common<0x94>;
def RECIPSQRT_CLAMPED_eg : RECIPSQRT_CLAMPED_Common<0x87>;
def EXP_IEEE_eg : EXP_IEEE_Common<0x81>;
@@ -116,14 +118,13 @@ def RAT_STORE_TYPED_eg: CF_MEM_RAT_STORE_TYPED<1>;
} // End usesCustomInserter = 1
-class VTX_READ_eg <string name, bits<8> buffer_id, dag outs, list<dag> pattern>
- : VTX_WORD0_eg, VTX_READ<name, buffer_id, outs, pattern> {
+class VTX_READ_eg <string name, dag outs>
+ : VTX_WORD0_eg, VTX_READ<name, outs, []> {
// Static fields
let VC_INST = 0;
let FETCH_TYPE = 2;
let FETCH_WHOLE_QUAD = 0;
- let BUFFER_ID = buffer_id;
let SRC_REL = 0;
// XXX: We can infer this field based on the SRC_GPR. This would allow us
// to store vertex addresses in any channel, not just X.
@@ -132,9 +133,9 @@ class VTX_READ_eg <string name, bits<8> buffer_id, dag outs, list<dag> pattern>
let Inst{31-0} = Word0;
}
-class VTX_READ_8_eg <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_eg <"VTX_READ_8 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_TReg32_X:$dst_gpr), pattern> {
+def VTX_READ_8_eg
+ : VTX_READ_eg <"VTX_READ_8 $dst_gpr, $src_gpr",
+ (outs R600_TReg32_X:$dst_gpr)> {
let MEGA_FETCH_COUNT = 1;
let DST_SEL_X = 0;
@@ -144,9 +145,9 @@ class VTX_READ_8_eg <bits<8> buffer_id, list<dag> pattern>
let DATA_FORMAT = 1; // FMT_8
}
-class VTX_READ_16_eg <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_eg <"VTX_READ_16 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_TReg32_X:$dst_gpr), pattern> {
+def VTX_READ_16_eg
+ : VTX_READ_eg <"VTX_READ_16 $dst_gpr, $src_gpr",
+ (outs R600_TReg32_X:$dst_gpr)> {
let MEGA_FETCH_COUNT = 2;
let DST_SEL_X = 0;
let DST_SEL_Y = 7; // Masked
@@ -156,9 +157,9 @@ class VTX_READ_16_eg <bits<8> buffer_id, list<dag> pattern>
}
-class VTX_READ_32_eg <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_eg <"VTX_READ_32 $dst_gpr, $src_gpr", buffer_id,
- (outs R600_TReg32_X:$dst_gpr), pattern> {
+def VTX_READ_32_eg
+ : VTX_READ_eg <"VTX_READ_32 $dst_gpr, $src_gpr",
+ (outs R600_TReg32_X:$dst_gpr)> {
let MEGA_FETCH_COUNT = 4;
let DST_SEL_X = 0;
@@ -177,9 +178,9 @@ class VTX_READ_32_eg <bits<8> buffer_id, list<dag> pattern>
let Constraints = "$src_gpr.ptr = $dst_gpr";
}
-class VTX_READ_64_eg <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_eg <"VTX_READ_64 $dst_gpr.XY, $src_gpr", buffer_id,
- (outs R600_Reg64:$dst_gpr), pattern> {
+def VTX_READ_64_eg
+ : VTX_READ_eg <"VTX_READ_64 $dst_gpr.XY, $src_gpr",
+ (outs R600_Reg64:$dst_gpr)> {
let MEGA_FETCH_COUNT = 8;
let DST_SEL_X = 0;
@@ -189,9 +190,9 @@ class VTX_READ_64_eg <bits<8> buffer_id, list<dag> pattern>
let DATA_FORMAT = 0x1D; // COLOR_32_32
}
-class VTX_READ_128_eg <bits<8> buffer_id, list<dag> pattern>
- : VTX_READ_eg <"VTX_READ_128 $dst_gpr.XYZW, $src_gpr", buffer_id,
- (outs R600_Reg128:$dst_gpr), pattern> {
+def VTX_READ_128_eg
+ : VTX_READ_eg <"VTX_READ_128 $dst_gpr.XYZW, $src_gpr",
+ (outs R600_Reg128:$dst_gpr)> {
let MEGA_FETCH_COUNT = 16;
let DST_SEL_X = 0;
@@ -209,80 +210,44 @@ class VTX_READ_128_eg <bits<8> buffer_id, list<dag> pattern>
//===----------------------------------------------------------------------===//
// VTX Read from parameter memory space
//===----------------------------------------------------------------------===//
+def : Pat<(i32:$dst_gpr (vtx_id3_az_extloadi8 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_8_eg MEMxi:$src_gpr, 3)>;
+def : Pat<(i32:$dst_gpr (vtx_id3_az_extloadi16 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_16_eg MEMxi:$src_gpr, 3)>;
+def : Pat<(i32:$dst_gpr (vtx_id3_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_32_eg MEMxi:$src_gpr, 3)>;
+def : Pat<(v2i32:$dst_gpr (vtx_id3_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_64_eg MEMxi:$src_gpr, 3)>;
+def : Pat<(v4i32:$dst_gpr (vtx_id3_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_128_eg MEMxi:$src_gpr, 3)>;
-def VTX_READ_PARAM_8_eg : VTX_READ_8_eg <3,
- [(set i32:$dst_gpr, (load_param_exti8 ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_16_eg : VTX_READ_16_eg <3,
- [(set i32:$dst_gpr, (load_param_exti16 ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_32_eg : VTX_READ_32_eg <3,
- [(set i32:$dst_gpr, (load_param ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_64_eg : VTX_READ_64_eg <3,
- [(set v2i32:$dst_gpr, (load_param ADDRVTX_READ:$src_gpr))]
->;
-
-def VTX_READ_PARAM_128_eg : VTX_READ_128_eg <3,
- [(set v4i32:$dst_gpr, (load_param ADDRVTX_READ:$src_gpr))]
->;
+//===----------------------------------------------------------------------===//
+// VTX Read from constant memory space
+//===----------------------------------------------------------------------===//
+def : Pat<(i32:$dst_gpr (vtx_id2_az_extloadi8 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_8_eg MEMxi:$src_gpr, 2)>;
+def : Pat<(i32:$dst_gpr (vtx_id2_az_extloadi16 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_16_eg MEMxi:$src_gpr, 2)>;
+def : Pat<(i32:$dst_gpr (vtx_id2_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_32_eg MEMxi:$src_gpr, 2)>;
+def : Pat<(v2i32:$dst_gpr (vtx_id2_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_64_eg MEMxi:$src_gpr, 2)>;
+def : Pat<(v4i32:$dst_gpr (vtx_id2_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_128_eg MEMxi:$src_gpr, 2)>;
//===----------------------------------------------------------------------===//
// VTX Read from global memory space
//===----------------------------------------------------------------------===//
-
-// 8-bit reads
-def VTX_READ_ID1_8_eg : VTX_READ_8_eg <1,
- [(set i32:$dst_gpr, (vtx_id1_az_extloadi8 ADDRVTX_READ:$src_gpr))]
->;
-
-// 16-bit reads
-def VTX_READ_ID1_16_eg : VTX_READ_16_eg <1,
- [(set i32:$dst_gpr, (vtx_id1_az_extloadi16 ADDRVTX_READ:$src_gpr))]
->;
-
-// 32-bit reads
-def VTX_READ_ID1_32_eg : VTX_READ_32_eg <1,
- [(set i32:$dst_gpr, (vtx_id1_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 64-bit reads
-def VTX_READ_ID1_64_eg : VTX_READ_64_eg <1,
- [(set v2i32:$dst_gpr, (vtx_id1_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 128-bit reads
-def VTX_READ_ID1_128_eg : VTX_READ_128_eg <1,
- [(set v4i32:$dst_gpr, (vtx_id1_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 8-bit reads
-def VTX_READ_ID2_8_eg : VTX_READ_8_eg <2,
- [(set i32:$dst_gpr, (vtx_id2_az_extloadi8 ADDRVTX_READ:$src_gpr))]
->;
-
-// 16-bit reads
-def VTX_READ_ID2_16_eg : VTX_READ_16_eg <2,
- [(set i32:$dst_gpr, (vtx_id2_az_extloadi16 ADDRVTX_READ:$src_gpr))]
->;
-
-// 32-bit reads
-def VTX_READ_ID2_32_eg : VTX_READ_32_eg <2,
- [(set i32:$dst_gpr, (vtx_id2_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 64-bit reads
-def VTX_READ_ID2_64_eg : VTX_READ_64_eg <2,
- [(set v2i32:$dst_gpr, (vtx_id2_load ADDRVTX_READ:$src_gpr))]
->;
-
-// 128-bit reads
-def VTX_READ_ID2_128_eg : VTX_READ_128_eg <2,
- [(set v4i32:$dst_gpr, (vtx_id2_load ADDRVTX_READ:$src_gpr))]
->;
+def : Pat<(i32:$dst_gpr (vtx_id1_az_extloadi8 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_8_eg MEMxi:$src_gpr, 1)>;
+def : Pat<(i32:$dst_gpr (vtx_id1_az_extloadi16 ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_16_eg MEMxi:$src_gpr, 1)>;
+def : Pat<(i32:$dst_gpr (vtx_id1_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_32_eg MEMxi:$src_gpr, 1)>;
+def : Pat<(v2i32:$dst_gpr (vtx_id1_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_64_eg MEMxi:$src_gpr, 1)>;
+def : Pat<(v4i32:$dst_gpr (vtx_id1_load ADDRVTX_READ:$src_gpr)),
+ (VTX_READ_128_eg MEMxi:$src_gpr, 1)>;
} // End Predicates = [isEG]
@@ -368,11 +333,13 @@ def MUL_UINT24_eg : R600_2OP <0xB5, "MUL_UINT24",
def DOT4_eg : DOT4_Common<0xBE>;
defm CUBE_eg : CUBE_Common<0xC0>;
-def BCNT_INT : R600_1OP_Helper <0xAA, "BCNT_INT", ctpop, VecALU>;
def ADDC_UINT : R600_2OP_Helper <0x52, "ADDC_UINT", AMDGPUcarry>;
def SUBB_UINT : R600_2OP_Helper <0x53, "SUBB_UINT", AMDGPUborrow>;
+def FLT32_TO_FLT16 : R600_1OP_Helper <0xA2, "FLT32_TO_FLT16", fp_to_f16, VecALU>;
+def FLT16_TO_FLT32 : R600_1OP_Helper <0xA3, "FLT16_TO_FLT32", f16_to_fp, VecALU>;
+def BCNT_INT : R600_1OP_Helper <0xAA, "BCNT_INT", ctpop, VecALU>;
def FFBH_UINT : R600_1OP_Helper <0xAB, "FFBH_UINT", AMDGPUffbh_u32, VecALU>;
def FFBL_INT : R600_1OP_Helper <0xAC, "FFBL_INT", cttz_zero_undef, VecALU>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td b/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td
new file mode 100644
index 0000000..849fb8a
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td
@@ -0,0 +1,530 @@
+//===-- FLATInstructions.td - FLAT Instruction Defintions -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def FLATAtomic : ComplexPattern<i64, 3, "SelectFlat">;
+
+//===----------------------------------------------------------------------===//
+// FLAT classes
+//===----------------------------------------------------------------------===//
+
+class FLAT_Pseudo<string opName, dag outs, dag ins,
+ string asmOps, list<dag> pattern=[]> :
+ InstSI<outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+
+ let SubtargetPredicate = isCIVI;
+
+ let FLAT = 1;
+ // Internally, FLAT instruction are executed as both an LDS and a
+ // Buffer instruction; so, they increment both VM_CNT and LGKM_CNT
+ // and are not considered done until both have been decremented.
+ let VM_CNT = 1;
+ let LGKM_CNT = 1;
+
+ let Uses = [EXEC, FLAT_SCR]; // M0
+
+ let UseNamedOperandTable = 1;
+ let hasSideEffects = 0;
+ let SchedRW = [WriteVMEM];
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ bits<1> has_vdst = 1;
+ bits<1> has_data = 1;
+ bits<1> has_glc = 1;
+ bits<1> glcValue = 0;
+}
+
+class FLAT_Real <bits<7> op, FLAT_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
+ Enc64 {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+
+ // encoding fields
+ bits<8> vaddr;
+ bits<8> vdata;
+ bits<8> vdst;
+ bits<1> slc;
+ bits<1> glc;
+ bits<1> tfe;
+
+ // 15-0 is reserved.
+ let Inst{16} = !if(ps.has_glc, glc, ps.glcValue);
+ let Inst{17} = slc;
+ let Inst{24-18} = op;
+ let Inst{31-26} = 0x37; // Encoding.
+ let Inst{39-32} = vaddr;
+ let Inst{47-40} = !if(ps.has_data, vdata, ?);
+ // 54-48 is reserved.
+ let Inst{55} = tfe;
+ let Inst{63-56} = !if(ps.has_vdst, vdst, ?);
+}
+
+class FLAT_Load_Pseudo <string opName, RegisterClass regClass> : FLAT_Pseudo<
+ opName,
+ (outs regClass:$vdst),
+ (ins VReg_64:$vaddr, GLC:$glc, slc:$slc, tfe:$tfe),
+ " $vdst, $vaddr$glc$slc$tfe"> {
+ let has_data = 0;
+ let mayLoad = 1;
+}
+
+class FLAT_Store_Pseudo <string opName, RegisterClass vdataClass> : FLAT_Pseudo<
+ opName,
+ (outs),
+ (ins VReg_64:$vaddr, vdataClass:$vdata, GLC:$glc, slc:$slc, tfe:$tfe),
+ " $vaddr, $vdata$glc$slc$tfe"> {
+ let mayLoad = 0;
+ let mayStore = 1;
+ let has_vdst = 0;
+}
+
+multiclass FLAT_Atomic_Pseudo<
+ string opName,
+ RegisterClass vdst_rc,
+ ValueType vt,
+ SDPatternOperator atomic = null_frag,
+ ValueType data_vt = vt,
+ RegisterClass data_rc = vdst_rc> {
+
+ def "" : FLAT_Pseudo <opName,
+ (outs),
+ (ins VReg_64:$vaddr, data_rc:$vdata, slc:$slc, tfe:$tfe),
+ " $vaddr, $vdata$slc$tfe",
+ []>,
+ AtomicNoRet <NAME, 0> {
+ let mayLoad = 1;
+ let mayStore = 1;
+ let has_glc = 0;
+ let glcValue = 0;
+ let has_vdst = 0;
+ let PseudoInstr = NAME;
+ }
+
+ def _RTN : FLAT_Pseudo <opName,
+ (outs vdst_rc:$vdst),
+ (ins VReg_64:$vaddr, data_rc:$vdata, slc:$slc, tfe:$tfe),
+ " $vdst, $vaddr, $vdata glc$slc$tfe",
+ [(set vt:$vdst,
+ (atomic (FLATAtomic i64:$vaddr, i1:$slc, i1:$tfe), data_vt:$vdata))]>,
+ AtomicNoRet <NAME, 1> {
+ let mayLoad = 1;
+ let mayStore = 1;
+ let hasPostISelHook = 1;
+ let has_glc = 0;
+ let glcValue = 1;
+ let PseudoInstr = NAME # "_RTN";
+ }
+}
+
+class flat_binary_atomic_op<SDNode atomic_op> : PatFrag<
+ (ops node:$ptr, node:$value),
+ (atomic_op node:$ptr, node:$value),
+ [{return cast<MemSDNode>(N)->getAddressSpace() == AMDGPUAS::FLAT_ADDRESS;}]
+>;
+
+def atomic_cmp_swap_flat : flat_binary_atomic_op<AMDGPUatomic_cmp_swap>;
+def atomic_swap_flat : flat_binary_atomic_op<atomic_swap>;
+def atomic_add_flat : flat_binary_atomic_op<atomic_load_add>;
+def atomic_and_flat : flat_binary_atomic_op<atomic_load_and>;
+def atomic_max_flat : flat_binary_atomic_op<atomic_load_max>;
+def atomic_min_flat : flat_binary_atomic_op<atomic_load_min>;
+def atomic_or_flat : flat_binary_atomic_op<atomic_load_or>;
+def atomic_sub_flat : flat_binary_atomic_op<atomic_load_sub>;
+def atomic_umax_flat : flat_binary_atomic_op<atomic_load_umax>;
+def atomic_umin_flat : flat_binary_atomic_op<atomic_load_umin>;
+def atomic_xor_flat : flat_binary_atomic_op<atomic_load_xor>;
+def atomic_inc_flat : flat_binary_atomic_op<SIatomic_inc>;
+def atomic_dec_flat : flat_binary_atomic_op<SIatomic_dec>;
+
+
+
+//===----------------------------------------------------------------------===//
+// Flat Instructions
+//===----------------------------------------------------------------------===//
+
+def FLAT_LOAD_UBYTE : FLAT_Load_Pseudo <"flat_load_ubyte", VGPR_32>;
+def FLAT_LOAD_SBYTE : FLAT_Load_Pseudo <"flat_load_sbyte", VGPR_32>;
+def FLAT_LOAD_USHORT : FLAT_Load_Pseudo <"flat_load_ushort", VGPR_32>;
+def FLAT_LOAD_SSHORT : FLAT_Load_Pseudo <"flat_load_sshort", VGPR_32>;
+def FLAT_LOAD_DWORD : FLAT_Load_Pseudo <"flat_load_dword", VGPR_32>;
+def FLAT_LOAD_DWORDX2 : FLAT_Load_Pseudo <"flat_load_dwordx2", VReg_64>;
+def FLAT_LOAD_DWORDX4 : FLAT_Load_Pseudo <"flat_load_dwordx4", VReg_128>;
+def FLAT_LOAD_DWORDX3 : FLAT_Load_Pseudo <"flat_load_dwordx3", VReg_96>;
+
+def FLAT_STORE_BYTE : FLAT_Store_Pseudo <"flat_store_byte", VGPR_32>;
+def FLAT_STORE_SHORT : FLAT_Store_Pseudo <"flat_store_short", VGPR_32>;
+def FLAT_STORE_DWORD : FLAT_Store_Pseudo <"flat_store_dword", VGPR_32>;
+def FLAT_STORE_DWORDX2 : FLAT_Store_Pseudo <"flat_store_dwordx2", VReg_64>;
+def FLAT_STORE_DWORDX4 : FLAT_Store_Pseudo <"flat_store_dwordx4", VReg_128>;
+def FLAT_STORE_DWORDX3 : FLAT_Store_Pseudo <"flat_store_dwordx3", VReg_96>;
+
+defm FLAT_ATOMIC_CMPSWAP : FLAT_Atomic_Pseudo <"flat_atomic_cmpswap",
+ VGPR_32, i32, atomic_cmp_swap_flat,
+ v2i32, VReg_64>;
+
+defm FLAT_ATOMIC_CMPSWAP_X2 : FLAT_Atomic_Pseudo <"flat_atomic_cmpswap_x2",
+ VReg_64, i64, atomic_cmp_swap_flat,
+ v2i64, VReg_128>;
+
+defm FLAT_ATOMIC_SWAP : FLAT_Atomic_Pseudo <"flat_atomic_swap",
+ VGPR_32, i32, atomic_swap_flat>;
+
+defm FLAT_ATOMIC_SWAP_X2 : FLAT_Atomic_Pseudo <"flat_atomic_swap_x2",
+ VReg_64, i64, atomic_swap_flat>;
+
+defm FLAT_ATOMIC_ADD : FLAT_Atomic_Pseudo <"flat_atomic_add",
+ VGPR_32, i32, atomic_add_flat>;
+
+defm FLAT_ATOMIC_SUB : FLAT_Atomic_Pseudo <"flat_atomic_sub",
+ VGPR_32, i32, atomic_sub_flat>;
+
+defm FLAT_ATOMIC_SMIN : FLAT_Atomic_Pseudo <"flat_atomic_smin",
+ VGPR_32, i32, atomic_min_flat>;
+
+defm FLAT_ATOMIC_UMIN : FLAT_Atomic_Pseudo <"flat_atomic_umin",
+ VGPR_32, i32, atomic_umin_flat>;
+
+defm FLAT_ATOMIC_SMAX : FLAT_Atomic_Pseudo <"flat_atomic_smax",
+ VGPR_32, i32, atomic_max_flat>;
+
+defm FLAT_ATOMIC_UMAX : FLAT_Atomic_Pseudo <"flat_atomic_umax",
+ VGPR_32, i32, atomic_umax_flat>;
+
+defm FLAT_ATOMIC_AND : FLAT_Atomic_Pseudo <"flat_atomic_and",
+ VGPR_32, i32, atomic_and_flat>;
+
+defm FLAT_ATOMIC_OR : FLAT_Atomic_Pseudo <"flat_atomic_or",
+ VGPR_32, i32, atomic_or_flat>;
+
+defm FLAT_ATOMIC_XOR : FLAT_Atomic_Pseudo <"flat_atomic_xor",
+ VGPR_32, i32, atomic_xor_flat>;
+
+defm FLAT_ATOMIC_INC : FLAT_Atomic_Pseudo <"flat_atomic_inc",
+ VGPR_32, i32, atomic_inc_flat>;
+
+defm FLAT_ATOMIC_DEC : FLAT_Atomic_Pseudo <"flat_atomic_dec",
+ VGPR_32, i32, atomic_dec_flat>;
+
+defm FLAT_ATOMIC_ADD_X2 : FLAT_Atomic_Pseudo <"flat_atomic_add_x2",
+ VReg_64, i64, atomic_add_flat>;
+
+defm FLAT_ATOMIC_SUB_X2 : FLAT_Atomic_Pseudo <"flat_atomic_sub_x2",
+ VReg_64, i64, atomic_sub_flat>;
+
+defm FLAT_ATOMIC_SMIN_X2 : FLAT_Atomic_Pseudo <"flat_atomic_smin_x2",
+ VReg_64, i64, atomic_min_flat>;
+
+defm FLAT_ATOMIC_UMIN_X2 : FLAT_Atomic_Pseudo <"flat_atomic_umin_x2",
+ VReg_64, i64, atomic_umin_flat>;
+
+defm FLAT_ATOMIC_SMAX_X2 : FLAT_Atomic_Pseudo <"flat_atomic_smax_x2",
+ VReg_64, i64, atomic_max_flat>;
+
+defm FLAT_ATOMIC_UMAX_X2 : FLAT_Atomic_Pseudo <"flat_atomic_umax_x2",
+ VReg_64, i64, atomic_umax_flat>;
+
+defm FLAT_ATOMIC_AND_X2 : FLAT_Atomic_Pseudo <"flat_atomic_and_x2",
+ VReg_64, i64, atomic_and_flat>;
+
+defm FLAT_ATOMIC_OR_X2 : FLAT_Atomic_Pseudo <"flat_atomic_or_x2",
+ VReg_64, i64, atomic_or_flat>;
+
+defm FLAT_ATOMIC_XOR_X2 : FLAT_Atomic_Pseudo <"flat_atomic_xor_x2",
+ VReg_64, i64, atomic_xor_flat>;
+
+defm FLAT_ATOMIC_INC_X2 : FLAT_Atomic_Pseudo <"flat_atomic_inc_x2",
+ VReg_64, i64, atomic_inc_flat>;
+
+defm FLAT_ATOMIC_DEC_X2 : FLAT_Atomic_Pseudo <"flat_atomic_dec_x2",
+ VReg_64, i64, atomic_dec_flat>;
+
+let SubtargetPredicate = isCI in { // CI Only flat instructions : FIXME Only?
+
+defm FLAT_ATOMIC_FCMPSWAP : FLAT_Atomic_Pseudo <"flat_atomic_fcmpswap",
+ VGPR_32, f32, null_frag, v2f32, VReg_64>;
+
+defm FLAT_ATOMIC_FCMPSWAP_X2 : FLAT_Atomic_Pseudo <"flat_atomic_fcmpswap_x2",
+ VReg_64, f64, null_frag, v2f64, VReg_128>;
+
+defm FLAT_ATOMIC_FMIN : FLAT_Atomic_Pseudo <"flat_atomic_fmin",
+ VGPR_32, f32>;
+
+defm FLAT_ATOMIC_FMAX : FLAT_Atomic_Pseudo <"flat_atomic_fmax",
+ VGPR_32, f32>;
+
+defm FLAT_ATOMIC_FMIN_X2 : FLAT_Atomic_Pseudo <"flat_atomic_fmin_x2",
+ VReg_64, f64>;
+
+defm FLAT_ATOMIC_FMAX_X2 : FLAT_Atomic_Pseudo <"flat_atomic_fmax_x2",
+ VReg_64, f64>;
+
+} // End SubtargetPredicate = isCI
+
+//===----------------------------------------------------------------------===//
+// Flat Patterns
+//===----------------------------------------------------------------------===//
+
+class flat_ld <SDPatternOperator ld> : PatFrag<(ops node:$ptr),
+ (ld node:$ptr), [{
+ auto const AS = cast<MemSDNode>(N)->getAddressSpace();
+ return AS == AMDGPUAS::FLAT_ADDRESS ||
+ AS == AMDGPUAS::GLOBAL_ADDRESS ||
+ AS == AMDGPUAS::CONSTANT_ADDRESS;
+}]>;
+
+class flat_st <SDPatternOperator st> : PatFrag<(ops node:$val, node:$ptr),
+ (st node:$val, node:$ptr), [{
+ auto const AS = cast<MemSDNode>(N)->getAddressSpace();
+ return AS == AMDGPUAS::FLAT_ADDRESS ||
+ AS == AMDGPUAS::GLOBAL_ADDRESS;
+}]>;
+
+def atomic_flat_load : flat_ld <atomic_load>;
+def flat_load : flat_ld <load>;
+def flat_az_extloadi8 : flat_ld <az_extloadi8>;
+def flat_sextloadi8 : flat_ld <sextloadi8>;
+def flat_az_extloadi16 : flat_ld <az_extloadi16>;
+def flat_sextloadi16 : flat_ld <sextloadi16>;
+
+def atomic_flat_store : flat_st <atomic_store>;
+def flat_store : flat_st <store>;
+def flat_truncstorei8 : flat_st <truncstorei8>;
+def flat_truncstorei16 : flat_st <truncstorei16>;
+
+// Patterns for global loads with no offset.
+class FlatLoadPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : Pat <
+ (vt (node i64:$addr)),
+ (inst $addr, 0, 0, 0)
+>;
+
+class FlatLoadAtomicPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : Pat <
+ (vt (node i64:$addr)),
+ (inst $addr, 1, 0, 0)
+>;
+
+class FlatStorePat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : Pat <
+ (node vt:$data, i64:$addr),
+ (inst $addr, $data, 0, 0, 0)
+>;
+
+class FlatStoreAtomicPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : Pat <
+ // atomic store follows atomic binop convention so the address comes
+ // first.
+ (node i64:$addr, vt:$data),
+ (inst $addr, $data, 1, 0, 0)
+>;
+
+class FlatAtomicPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt,
+ ValueType data_vt = vt> : Pat <
+ (vt (node i64:$addr, data_vt:$data)),
+ (inst $addr, $data, 0, 0)
+>;
+
+let Predicates = [isCIVI] in {
+
+def : FlatLoadPat <FLAT_LOAD_UBYTE, flat_az_extloadi8, i32>;
+def : FlatLoadPat <FLAT_LOAD_SBYTE, flat_sextloadi8, i32>;
+def : FlatLoadPat <FLAT_LOAD_UBYTE, flat_az_extloadi8, i16>;
+def : FlatLoadPat <FLAT_LOAD_SBYTE, flat_sextloadi8, i16>;
+def : FlatLoadPat <FLAT_LOAD_USHORT, flat_az_extloadi16, i32>;
+def : FlatLoadPat <FLAT_LOAD_SSHORT, flat_sextloadi16, i32>;
+def : FlatLoadPat <FLAT_LOAD_DWORD, flat_load, i32>;
+def : FlatLoadPat <FLAT_LOAD_DWORDX2, flat_load, v2i32>;
+def : FlatLoadPat <FLAT_LOAD_DWORDX4, flat_load, v4i32>;
+
+def : FlatLoadAtomicPat <FLAT_LOAD_DWORD, atomic_flat_load, i32>;
+def : FlatLoadAtomicPat <FLAT_LOAD_DWORDX2, atomic_flat_load, i64>;
+
+def : FlatStorePat <FLAT_STORE_BYTE, flat_truncstorei8, i32>;
+def : FlatStorePat <FLAT_STORE_SHORT, flat_truncstorei16, i32>;
+def : FlatStorePat <FLAT_STORE_DWORD, flat_store, i32>;
+def : FlatStorePat <FLAT_STORE_DWORDX2, flat_store, v2i32>;
+def : FlatStorePat <FLAT_STORE_DWORDX4, flat_store, v4i32>;
+
+def : FlatStoreAtomicPat <FLAT_STORE_DWORD, atomic_flat_store, i32>;
+def : FlatStoreAtomicPat <FLAT_STORE_DWORDX2, atomic_flat_store, i64>;
+
+def : FlatAtomicPat <FLAT_ATOMIC_ADD_RTN, atomic_add_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_SUB_RTN, atomic_sub_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_INC_RTN, atomic_inc_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_DEC_RTN, atomic_dec_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_AND_RTN, atomic_and_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_SMAX_RTN, atomic_max_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_UMAX_RTN, atomic_umax_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_SMIN_RTN, atomic_min_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_UMIN_RTN, atomic_umin_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_OR_RTN, atomic_or_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_SWAP_RTN, atomic_swap_global, i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_CMPSWAP_RTN, AMDGPUatomic_cmp_swap_global, i32, v2i32>;
+def : FlatAtomicPat <FLAT_ATOMIC_XOR_RTN, atomic_xor_global, i32>;
+
+def : FlatAtomicPat <FLAT_ATOMIC_ADD_X2_RTN, atomic_add_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_SUB_X2_RTN, atomic_sub_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_INC_X2_RTN, atomic_inc_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_DEC_X2_RTN, atomic_dec_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_AND_X2_RTN, atomic_and_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_SMAX_X2_RTN, atomic_max_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_UMAX_X2_RTN, atomic_umax_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_SMIN_X2_RTN, atomic_min_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_UMIN_X2_RTN, atomic_umin_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_OR_X2_RTN, atomic_or_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_SWAP_X2_RTN, atomic_swap_global, i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_CMPSWAP_X2_RTN, AMDGPUatomic_cmp_swap_global, i64, v2i64>;
+def : FlatAtomicPat <FLAT_ATOMIC_XOR_X2_RTN, atomic_xor_global, i64>;
+
+} // End Predicates = [isCIVI]
+
+let Predicates = [isVI] in {
+ def : FlatStorePat <FLAT_STORE_BYTE, flat_truncstorei8, i16>;
+ def : FlatStorePat <FLAT_STORE_SHORT, flat_store, i16>;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Target
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// CI
+//===----------------------------------------------------------------------===//
+
+class FLAT_Real_ci <bits<7> op, FLAT_Pseudo ps> :
+ FLAT_Real <op, ps>,
+ SIMCInstr <ps.PseudoInstr, SIEncodingFamily.SI> {
+ let AssemblerPredicate = isCIOnly;
+ let DecoderNamespace="CI";
+}
+
+def FLAT_LOAD_UBYTE_ci : FLAT_Real_ci <0x8, FLAT_LOAD_UBYTE>;
+def FLAT_LOAD_SBYTE_ci : FLAT_Real_ci <0x9, FLAT_LOAD_SBYTE>;
+def FLAT_LOAD_USHORT_ci : FLAT_Real_ci <0xa, FLAT_LOAD_USHORT>;
+def FLAT_LOAD_SSHORT_ci : FLAT_Real_ci <0xb, FLAT_LOAD_SSHORT>;
+def FLAT_LOAD_DWORD_ci : FLAT_Real_ci <0xc, FLAT_LOAD_DWORD>;
+def FLAT_LOAD_DWORDX2_ci : FLAT_Real_ci <0xd, FLAT_LOAD_DWORDX2>;
+def FLAT_LOAD_DWORDX4_ci : FLAT_Real_ci <0xe, FLAT_LOAD_DWORDX4>;
+def FLAT_LOAD_DWORDX3_ci : FLAT_Real_ci <0xf, FLAT_LOAD_DWORDX3>;
+
+def FLAT_STORE_BYTE_ci : FLAT_Real_ci <0x18, FLAT_STORE_BYTE>;
+def FLAT_STORE_SHORT_ci : FLAT_Real_ci <0x1a, FLAT_STORE_SHORT>;
+def FLAT_STORE_DWORD_ci : FLAT_Real_ci <0x1c, FLAT_STORE_DWORD>;
+def FLAT_STORE_DWORDX2_ci : FLAT_Real_ci <0x1d, FLAT_STORE_DWORDX2>;
+def FLAT_STORE_DWORDX4_ci : FLAT_Real_ci <0x1e, FLAT_STORE_DWORDX4>;
+def FLAT_STORE_DWORDX3_ci : FLAT_Real_ci <0x1f, FLAT_STORE_DWORDX3>;
+
+multiclass FLAT_Real_Atomics_ci <bits<7> op, FLAT_Pseudo ps> {
+ def _ci : FLAT_Real_ci<op, !cast<FLAT_Pseudo>(ps.PseudoInstr)>;
+ def _RTN_ci : FLAT_Real_ci<op, !cast<FLAT_Pseudo>(ps.PseudoInstr # "_RTN")>;
+}
+
+defm FLAT_ATOMIC_SWAP : FLAT_Real_Atomics_ci <0x30, FLAT_ATOMIC_SWAP>;
+defm FLAT_ATOMIC_CMPSWAP : FLAT_Real_Atomics_ci <0x31, FLAT_ATOMIC_CMPSWAP>;
+defm FLAT_ATOMIC_ADD : FLAT_Real_Atomics_ci <0x32, FLAT_ATOMIC_ADD>;
+defm FLAT_ATOMIC_SUB : FLAT_Real_Atomics_ci <0x33, FLAT_ATOMIC_SUB>;
+defm FLAT_ATOMIC_SMIN : FLAT_Real_Atomics_ci <0x35, FLAT_ATOMIC_SMIN>;
+defm FLAT_ATOMIC_UMIN : FLAT_Real_Atomics_ci <0x36, FLAT_ATOMIC_UMIN>;
+defm FLAT_ATOMIC_SMAX : FLAT_Real_Atomics_ci <0x37, FLAT_ATOMIC_SMAX>;
+defm FLAT_ATOMIC_UMAX : FLAT_Real_Atomics_ci <0x38, FLAT_ATOMIC_UMAX>;
+defm FLAT_ATOMIC_AND : FLAT_Real_Atomics_ci <0x39, FLAT_ATOMIC_AND>;
+defm FLAT_ATOMIC_OR : FLAT_Real_Atomics_ci <0x3a, FLAT_ATOMIC_OR>;
+defm FLAT_ATOMIC_XOR : FLAT_Real_Atomics_ci <0x3b, FLAT_ATOMIC_XOR>;
+defm FLAT_ATOMIC_INC : FLAT_Real_Atomics_ci <0x3c, FLAT_ATOMIC_INC>;
+defm FLAT_ATOMIC_DEC : FLAT_Real_Atomics_ci <0x3d, FLAT_ATOMIC_DEC>;
+defm FLAT_ATOMIC_SWAP_X2 : FLAT_Real_Atomics_ci <0x50, FLAT_ATOMIC_SWAP_X2>;
+defm FLAT_ATOMIC_CMPSWAP_X2 : FLAT_Real_Atomics_ci <0x51, FLAT_ATOMIC_CMPSWAP_X2>;
+defm FLAT_ATOMIC_ADD_X2 : FLAT_Real_Atomics_ci <0x52, FLAT_ATOMIC_ADD_X2>;
+defm FLAT_ATOMIC_SUB_X2 : FLAT_Real_Atomics_ci <0x53, FLAT_ATOMIC_SUB_X2>;
+defm FLAT_ATOMIC_SMIN_X2 : FLAT_Real_Atomics_ci <0x55, FLAT_ATOMIC_SMIN_X2>;
+defm FLAT_ATOMIC_UMIN_X2 : FLAT_Real_Atomics_ci <0x56, FLAT_ATOMIC_UMIN_X2>;
+defm FLAT_ATOMIC_SMAX_X2 : FLAT_Real_Atomics_ci <0x57, FLAT_ATOMIC_SMAX_X2>;
+defm FLAT_ATOMIC_UMAX_X2 : FLAT_Real_Atomics_ci <0x58, FLAT_ATOMIC_UMAX_X2>;
+defm FLAT_ATOMIC_AND_X2 : FLAT_Real_Atomics_ci <0x59, FLAT_ATOMIC_AND_X2>;
+defm FLAT_ATOMIC_OR_X2 : FLAT_Real_Atomics_ci <0x5a, FLAT_ATOMIC_OR_X2>;
+defm FLAT_ATOMIC_XOR_X2 : FLAT_Real_Atomics_ci <0x5b, FLAT_ATOMIC_XOR_X2>;
+defm FLAT_ATOMIC_INC_X2 : FLAT_Real_Atomics_ci <0x5c, FLAT_ATOMIC_INC_X2>;
+defm FLAT_ATOMIC_DEC_X2 : FLAT_Real_Atomics_ci <0x5d, FLAT_ATOMIC_DEC_X2>;
+
+// CI Only flat instructions
+defm FLAT_ATOMIC_FCMPSWAP : FLAT_Real_Atomics_ci <0x3e, FLAT_ATOMIC_FCMPSWAP>;
+defm FLAT_ATOMIC_FMIN : FLAT_Real_Atomics_ci <0x3f, FLAT_ATOMIC_FMIN>;
+defm FLAT_ATOMIC_FMAX : FLAT_Real_Atomics_ci <0x40, FLAT_ATOMIC_FMAX>;
+defm FLAT_ATOMIC_FCMPSWAP_X2 : FLAT_Real_Atomics_ci <0x5e, FLAT_ATOMIC_FCMPSWAP_X2>;
+defm FLAT_ATOMIC_FMIN_X2 : FLAT_Real_Atomics_ci <0x5f, FLAT_ATOMIC_FMIN_X2>;
+defm FLAT_ATOMIC_FMAX_X2 : FLAT_Real_Atomics_ci <0x60, FLAT_ATOMIC_FMAX_X2>;
+
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+class FLAT_Real_vi <bits<7> op, FLAT_Pseudo ps> :
+ FLAT_Real <op, ps>,
+ SIMCInstr <ps.PseudoInstr, SIEncodingFamily.VI> {
+ let AssemblerPredicate = isVI;
+ let DecoderNamespace="VI";
+}
+
+def FLAT_LOAD_UBYTE_vi : FLAT_Real_vi <0x10, FLAT_LOAD_UBYTE>;
+def FLAT_LOAD_SBYTE_vi : FLAT_Real_vi <0x11, FLAT_LOAD_SBYTE>;
+def FLAT_LOAD_USHORT_vi : FLAT_Real_vi <0x12, FLAT_LOAD_USHORT>;
+def FLAT_LOAD_SSHORT_vi : FLAT_Real_vi <0x13, FLAT_LOAD_SSHORT>;
+def FLAT_LOAD_DWORD_vi : FLAT_Real_vi <0x14, FLAT_LOAD_DWORD>;
+def FLAT_LOAD_DWORDX2_vi : FLAT_Real_vi <0x15, FLAT_LOAD_DWORDX2>;
+def FLAT_LOAD_DWORDX4_vi : FLAT_Real_vi <0x17, FLAT_LOAD_DWORDX4>;
+def FLAT_LOAD_DWORDX3_vi : FLAT_Real_vi <0x16, FLAT_LOAD_DWORDX3>;
+
+def FLAT_STORE_BYTE_vi : FLAT_Real_vi <0x18, FLAT_STORE_BYTE>;
+def FLAT_STORE_SHORT_vi : FLAT_Real_vi <0x1a, FLAT_STORE_SHORT>;
+def FLAT_STORE_DWORD_vi : FLAT_Real_vi <0x1c, FLAT_STORE_DWORD>;
+def FLAT_STORE_DWORDX2_vi : FLAT_Real_vi <0x1d, FLAT_STORE_DWORDX2>;
+def FLAT_STORE_DWORDX4_vi : FLAT_Real_vi <0x1f, FLAT_STORE_DWORDX4>;
+def FLAT_STORE_DWORDX3_vi : FLAT_Real_vi <0x1e, FLAT_STORE_DWORDX3>;
+
+multiclass FLAT_Real_Atomics_vi <bits<7> op, FLAT_Pseudo ps> {
+ def _vi : FLAT_Real_vi<op, !cast<FLAT_Pseudo>(ps.PseudoInstr)>;
+ def _RTN_vi : FLAT_Real_vi<op, !cast<FLAT_Pseudo>(ps.PseudoInstr # "_RTN")>;
+}
+
+defm FLAT_ATOMIC_SWAP : FLAT_Real_Atomics_vi <0x40, FLAT_ATOMIC_SWAP>;
+defm FLAT_ATOMIC_CMPSWAP : FLAT_Real_Atomics_vi <0x41, FLAT_ATOMIC_CMPSWAP>;
+defm FLAT_ATOMIC_ADD : FLAT_Real_Atomics_vi <0x42, FLAT_ATOMIC_ADD>;
+defm FLAT_ATOMIC_SUB : FLAT_Real_Atomics_vi <0x43, FLAT_ATOMIC_SUB>;
+defm FLAT_ATOMIC_SMIN : FLAT_Real_Atomics_vi <0x44, FLAT_ATOMIC_SMIN>;
+defm FLAT_ATOMIC_UMIN : FLAT_Real_Atomics_vi <0x45, FLAT_ATOMIC_UMIN>;
+defm FLAT_ATOMIC_SMAX : FLAT_Real_Atomics_vi <0x46, FLAT_ATOMIC_SMAX>;
+defm FLAT_ATOMIC_UMAX : FLAT_Real_Atomics_vi <0x47, FLAT_ATOMIC_UMAX>;
+defm FLAT_ATOMIC_AND : FLAT_Real_Atomics_vi <0x48, FLAT_ATOMIC_AND>;
+defm FLAT_ATOMIC_OR : FLAT_Real_Atomics_vi <0x49, FLAT_ATOMIC_OR>;
+defm FLAT_ATOMIC_XOR : FLAT_Real_Atomics_vi <0x4a, FLAT_ATOMIC_XOR>;
+defm FLAT_ATOMIC_INC : FLAT_Real_Atomics_vi <0x4b, FLAT_ATOMIC_INC>;
+defm FLAT_ATOMIC_DEC : FLAT_Real_Atomics_vi <0x4c, FLAT_ATOMIC_DEC>;
+defm FLAT_ATOMIC_SWAP_X2 : FLAT_Real_Atomics_vi <0x60, FLAT_ATOMIC_SWAP_X2>;
+defm FLAT_ATOMIC_CMPSWAP_X2 : FLAT_Real_Atomics_vi <0x61, FLAT_ATOMIC_CMPSWAP_X2>;
+defm FLAT_ATOMIC_ADD_X2 : FLAT_Real_Atomics_vi <0x62, FLAT_ATOMIC_ADD_X2>;
+defm FLAT_ATOMIC_SUB_X2 : FLAT_Real_Atomics_vi <0x63, FLAT_ATOMIC_SUB_X2>;
+defm FLAT_ATOMIC_SMIN_X2 : FLAT_Real_Atomics_vi <0x64, FLAT_ATOMIC_SMIN_X2>;
+defm FLAT_ATOMIC_UMIN_X2 : FLAT_Real_Atomics_vi <0x65, FLAT_ATOMIC_UMIN_X2>;
+defm FLAT_ATOMIC_SMAX_X2 : FLAT_Real_Atomics_vi <0x66, FLAT_ATOMIC_SMAX_X2>;
+defm FLAT_ATOMIC_UMAX_X2 : FLAT_Real_Atomics_vi <0x67, FLAT_ATOMIC_UMAX_X2>;
+defm FLAT_ATOMIC_AND_X2 : FLAT_Real_Atomics_vi <0x68, FLAT_ATOMIC_AND_X2>;
+defm FLAT_ATOMIC_OR_X2 : FLAT_Real_Atomics_vi <0x69, FLAT_ATOMIC_OR_X2>;
+defm FLAT_ATOMIC_XOR_X2 : FLAT_Real_Atomics_vi <0x6a, FLAT_ATOMIC_XOR_X2>;
+defm FLAT_ATOMIC_INC_X2 : FLAT_Real_Atomics_vi <0x6b, FLAT_ATOMIC_INC_X2>;
+defm FLAT_ATOMIC_DEC_X2 : FLAT_Real_Atomics_vi <0x6c, FLAT_ATOMIC_DEC_X2>;
+
diff --git a/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp b/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp
index 29b1f79..dd3b46f 100644
--- a/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp
@@ -38,6 +38,33 @@ void GCNHazardRecognizer::EmitInstruction(MachineInstr *MI) {
CurrCycleInstr = MI;
}
+static bool isDivFMas(unsigned Opcode) {
+ return Opcode == AMDGPU::V_DIV_FMAS_F32 || Opcode == AMDGPU::V_DIV_FMAS_F64;
+}
+
+static bool isSGetReg(unsigned Opcode) {
+ return Opcode == AMDGPU::S_GETREG_B32;
+}
+
+static bool isSSetReg(unsigned Opcode) {
+ return Opcode == AMDGPU::S_SETREG_B32 || Opcode == AMDGPU::S_SETREG_IMM32_B32;
+}
+
+static bool isRWLane(unsigned Opcode) {
+ return Opcode == AMDGPU::V_READLANE_B32 || Opcode == AMDGPU::V_WRITELANE_B32;
+}
+
+static bool isRFE(unsigned Opcode) {
+ return Opcode == AMDGPU::S_RFE_B64;
+}
+
+static unsigned getHWReg(const SIInstrInfo *TII, const MachineInstr &RegInstr) {
+
+ const MachineOperand *RegOp = TII->getNamedOperand(RegInstr,
+ AMDGPU::OpName::simm16);
+ return RegOp->getImm() & AMDGPU::Hwreg::ID_MASK_;
+}
+
ScheduleHazardRecognizer::HazardType
GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
MachineInstr *MI = SU->getInstr();
@@ -48,9 +75,27 @@ GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
if (SIInstrInfo::isVMEM(*MI) && checkVMEMHazards(MI) > 0)
return NoopHazard;
+ if (SIInstrInfo::isVALU(*MI) && checkVALUHazards(MI) > 0)
+ return NoopHazard;
+
if (SIInstrInfo::isDPP(*MI) && checkDPPHazards(MI) > 0)
return NoopHazard;
+ if (isDivFMas(MI->getOpcode()) && checkDivFMasHazards(MI) > 0)
+ return NoopHazard;
+
+ if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0)
+ return NoopHazard;
+
+ if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0)
+ return NoopHazard;
+
+ if (isSSetReg(MI->getOpcode()) && checkSetRegHazards(MI) > 0)
+ return NoopHazard;
+
+ if (isRFE(MI->getOpcode()) && checkRFEHazards(MI) > 0)
+ return NoopHazard;
+
return NoHazard;
}
@@ -62,11 +107,32 @@ unsigned GCNHazardRecognizer::PreEmitNoops(MachineInstr *MI) {
if (SIInstrInfo::isSMRD(*MI))
return std::max(0, checkSMRDHazards(MI));
- if (SIInstrInfo::isVMEM(*MI))
- return std::max(0, checkVMEMHazards(MI));
+ if (SIInstrInfo::isVALU(*MI)) {
+ int WaitStates = std::max(0, checkVALUHazards(MI));
- if (SIInstrInfo::isDPP(*MI))
- return std::max(0, checkDPPHazards(MI));
+ if (SIInstrInfo::isVMEM(*MI))
+ WaitStates = std::max(WaitStates, checkVMEMHazards(MI));
+
+ if (SIInstrInfo::isDPP(*MI))
+ WaitStates = std::max(WaitStates, checkDPPHazards(MI));
+
+ if (isDivFMas(MI->getOpcode()))
+ WaitStates = std::max(WaitStates, checkDivFMasHazards(MI));
+
+ if (isRWLane(MI->getOpcode()))
+ WaitStates = std::max(WaitStates, checkRWLaneHazards(MI));
+
+ return WaitStates;
+ }
+
+ if (isSGetReg(MI->getOpcode()))
+ return std::max(0, checkGetRegHazards(MI));
+
+ if (isSSetReg(MI->getOpcode()))
+ return std::max(0, checkSetRegHazards(MI));
+
+ if (isRFE(MI->getOpcode()))
+ return std::max(0, checkRFEHazards(MI));
return 0;
}
@@ -112,21 +178,40 @@ void GCNHazardRecognizer::RecedeCycle() {
// Helper Functions
//===----------------------------------------------------------------------===//
-int GCNHazardRecognizer::getWaitStatesSinceDef(
- unsigned Reg, function_ref<bool(MachineInstr *)> IsHazardDef) {
- const SIRegisterInfo *TRI = ST.getRegisterInfo();
+int GCNHazardRecognizer::getWaitStatesSince(
+ function_ref<bool(MachineInstr *)> IsHazard) {
int WaitStates = -1;
for (MachineInstr *MI : EmittedInstrs) {
++WaitStates;
- if (!MI || !IsHazardDef(MI))
+ if (!MI || !IsHazard(MI))
continue;
- if (MI->modifiesRegister(Reg, TRI))
- return WaitStates;
+ return WaitStates;
}
return std::numeric_limits<int>::max();
}
+int GCNHazardRecognizer::getWaitStatesSinceDef(
+ unsigned Reg, function_ref<bool(MachineInstr *)> IsHazardDef) {
+ const SIRegisterInfo *TRI = ST.getRegisterInfo();
+
+ auto IsHazardFn = [IsHazardDef, TRI, Reg] (MachineInstr *MI) {
+ return IsHazardDef(MI) && MI->modifiesRegister(Reg, TRI);
+ };
+
+ return getWaitStatesSince(IsHazardFn);
+}
+
+int GCNHazardRecognizer::getWaitStatesSinceSetReg(
+ function_ref<bool(MachineInstr *)> IsHazard) {
+
+ auto IsHazardFn = [IsHazard] (MachineInstr *MI) {
+ return isSSetReg(MI->getOpcode()) && IsHazard(MI);
+ };
+
+ return getWaitStatesSince(IsHazardFn);
+}
+
//===----------------------------------------------------------------------===//
// No-op Hazard Detection
//===----------------------------------------------------------------------===//
@@ -262,3 +347,156 @@ int GCNHazardRecognizer::checkDPPHazards(MachineInstr *DPP) {
return WaitStatesNeeded;
}
+
+int GCNHazardRecognizer::checkDivFMasHazards(MachineInstr *DivFMas) {
+ const SIInstrInfo *TII = ST.getInstrInfo();
+
+ // v_div_fmas requires 4 wait states after a write to vcc from a VALU
+ // instruction.
+ const int DivFMasWaitStates = 4;
+ auto IsHazardDefFn = [TII] (MachineInstr *MI) { return TII->isVALU(*MI); };
+ int WaitStatesNeeded = getWaitStatesSinceDef(AMDGPU::VCC, IsHazardDefFn);
+
+ return DivFMasWaitStates - WaitStatesNeeded;
+}
+
+int GCNHazardRecognizer::checkGetRegHazards(MachineInstr *GetRegInstr) {
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ unsigned GetRegHWReg = getHWReg(TII, *GetRegInstr);
+
+ const int GetRegWaitStates = 2;
+ auto IsHazardFn = [TII, GetRegHWReg] (MachineInstr *MI) {
+ return GetRegHWReg == getHWReg(TII, *MI);
+ };
+ int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn);
+
+ return GetRegWaitStates - WaitStatesNeeded;
+}
+
+int GCNHazardRecognizer::checkSetRegHazards(MachineInstr *SetRegInstr) {
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ unsigned HWReg = getHWReg(TII, *SetRegInstr);
+
+ const int SetRegWaitStates =
+ ST.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS ? 1 : 2;
+ auto IsHazardFn = [TII, HWReg] (MachineInstr *MI) {
+ return HWReg == getHWReg(TII, *MI);
+ };
+ int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn);
+ return SetRegWaitStates - WaitStatesNeeded;
+}
+
+int GCNHazardRecognizer::createsVALUHazard(const MachineInstr &MI) {
+ if (!MI.mayStore())
+ return -1;
+
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ unsigned Opcode = MI.getOpcode();
+ const MCInstrDesc &Desc = MI.getDesc();
+
+ int VDataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
+ int VDataRCID = -1;
+ if (VDataIdx != -1)
+ VDataRCID = Desc.OpInfo[VDataIdx].RegClass;
+
+ if (TII->isMUBUF(MI) || TII->isMTBUF(MI)) {
+ // There is no hazard if the instruction does not use vector regs
+ // (like wbinvl1)
+ if (VDataIdx == -1)
+ return -1;
+ // For MUBUF/MTBUF instructions this hazard only exists if the
+ // instruction is not using a register in the soffset field.
+ const MachineOperand *SOffset =
+ TII->getNamedOperand(MI, AMDGPU::OpName::soffset);
+ // If we have no soffset operand, then assume this field has been
+ // hardcoded to zero.
+ if (AMDGPU::getRegBitWidth(VDataRCID) > 64 &&
+ (!SOffset || !SOffset->isReg()))
+ return VDataIdx;
+ }
+
+ // MIMG instructions create a hazard if they don't use a 256-bit T# and
+ // the store size is greater than 8 bytes and they have more than two bits
+ // of their dmask set.
+ // All our MIMG definitions use a 256-bit T#, so we can skip checking for them.
+ if (TII->isMIMG(MI)) {
+ int SRsrcIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::srsrc);
+ assert(SRsrcIdx != -1 &&
+ AMDGPU::getRegBitWidth(Desc.OpInfo[SRsrcIdx].RegClass) == 256);
+ (void)SRsrcIdx;
+ }
+
+ if (TII->isFLAT(MI)) {
+ int DataIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdata);
+ if (AMDGPU::getRegBitWidth(Desc.OpInfo[DataIdx].RegClass) > 64)
+ return DataIdx;
+ }
+
+ return -1;
+}
+
+int GCNHazardRecognizer::checkVALUHazards(MachineInstr *VALU) {
+ // This checks for the hazard where VMEM instructions that store more than
+ // 8 bytes can have there store data over written by the next instruction.
+ if (!ST.has12DWordStoreHazard())
+ return 0;
+
+ const SIRegisterInfo *TRI = ST.getRegisterInfo();
+ const MachineRegisterInfo &MRI = VALU->getParent()->getParent()->getRegInfo();
+
+ const int VALUWaitStates = 1;
+ int WaitStatesNeeded = 0;
+
+ for (const MachineOperand &Def : VALU->defs()) {
+ if (!TRI->isVGPR(MRI, Def.getReg()))
+ continue;
+ unsigned Reg = Def.getReg();
+ auto IsHazardFn = [this, Reg, TRI] (MachineInstr *MI) {
+ int DataIdx = createsVALUHazard(*MI);
+ return DataIdx >= 0 &&
+ TRI->regsOverlap(MI->getOperand(DataIdx).getReg(), Reg);
+ };
+ int WaitStatesNeededForDef =
+ VALUWaitStates - getWaitStatesSince(IsHazardFn);
+ WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForDef);
+ }
+ return WaitStatesNeeded;
+}
+
+int GCNHazardRecognizer::checkRWLaneHazards(MachineInstr *RWLane) {
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ const SIRegisterInfo *TRI = ST.getRegisterInfo();
+ const MachineRegisterInfo &MRI =
+ RWLane->getParent()->getParent()->getRegInfo();
+
+ const MachineOperand *LaneSelectOp =
+ TII->getNamedOperand(*RWLane, AMDGPU::OpName::src1);
+
+ if (!LaneSelectOp->isReg() || !TRI->isSGPRReg(MRI, LaneSelectOp->getReg()))
+ return 0;
+
+ unsigned LaneSelectReg = LaneSelectOp->getReg();
+ auto IsHazardFn = [TII] (MachineInstr *MI) {
+ return TII->isVALU(*MI);
+ };
+
+ const int RWLaneWaitStates = 4;
+ int WaitStatesSince = getWaitStatesSinceDef(LaneSelectReg, IsHazardFn);
+ return RWLaneWaitStates - WaitStatesSince;
+}
+
+int GCNHazardRecognizer::checkRFEHazards(MachineInstr *RFE) {
+
+ if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)
+ return 0;
+
+ const SIInstrInfo *TII = ST.getInstrInfo();
+
+ const int RFEWaitStates = 1;
+
+ auto IsHazardFn = [TII] (MachineInstr *MI) {
+ return getHWReg(TII, *MI) == AMDGPU::Hwreg::ID_TRAPSTS;
+ };
+ int WaitStatesNeeded = getWaitStatesSinceSetReg(IsHazardFn);
+ return RFEWaitStates - WaitStatesNeeded;
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h b/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h
index d82041c..0ab82ff 100644
--- a/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h
+++ b/contrib/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h
@@ -35,14 +35,23 @@ class GCNHazardRecognizer final : public ScheduleHazardRecognizer {
const MachineFunction &MF;
const SISubtarget &ST;
+ int getWaitStatesSince(function_ref<bool(MachineInstr *)> IsHazard);
int getWaitStatesSinceDef(unsigned Reg,
function_ref<bool(MachineInstr *)> IsHazardDef =
[](MachineInstr *) { return true; });
+ int getWaitStatesSinceSetReg(function_ref<bool(MachineInstr *)> IsHazard);
int checkSMEMSoftClauseHazards(MachineInstr *SMEM);
int checkSMRDHazards(MachineInstr *SMRD);
int checkVMEMHazards(MachineInstr* VMEM);
int checkDPPHazards(MachineInstr *DPP);
+ int checkDivFMasHazards(MachineInstr *DivFMas);
+ int checkGetRegHazards(MachineInstr *GetRegInstr);
+ int checkSetRegHazards(MachineInstr *SetRegInstr);
+ int createsVALUHazard(const MachineInstr &MI);
+ int checkVALUHazards(MachineInstr *VALU);
+ int checkRWLaneHazards(MachineInstr *RWLane);
+ int checkRFEHazards(MachineInstr *RFE);
public:
GCNHazardRecognizer(const MachineFunction &MF);
// We can only issue one instruction per cycle.
diff --git a/contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp b/contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp
new file mode 100644
index 0000000..2f88033
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp
@@ -0,0 +1,312 @@
+//===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This contains a MachineSchedStrategy implementation for maximizing wave
+/// occupancy on GCN hardware.
+//===----------------------------------------------------------------------===//
+
+#include "GCNSchedStrategy.h"
+#include "AMDGPUSubtarget.h"
+#include "SIInstrInfo.h"
+#include "SIMachineFunctionInfo.h"
+#include "SIRegisterInfo.h"
+#include "llvm/CodeGen/RegisterClassInfo.h"
+
+#define DEBUG_TYPE "misched"
+
+using namespace llvm;
+
+GCNMaxOccupancySchedStrategy::GCNMaxOccupancySchedStrategy(
+ const MachineSchedContext *C) :
+ GenericScheduler(C) { }
+
+static unsigned getMaxWaves(unsigned SGPRs, unsigned VGPRs,
+ const MachineFunction &MF) {
+
+ const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
+ const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+ unsigned MinRegOccupancy = std::min(ST.getOccupancyWithNumSGPRs(SGPRs),
+ ST.getOccupancyWithNumVGPRs(VGPRs));
+ return std::min(MinRegOccupancy,
+ ST.getOccupancyWithLocalMemSize(MFI->getLDSSize()));
+}
+
+void GCNMaxOccupancySchedStrategy::initCandidate(SchedCandidate &Cand, SUnit *SU,
+ bool AtTop, const RegPressureTracker &RPTracker,
+ const SIRegisterInfo *SRI,
+ int SGPRPressure,
+ int VGPRPressure,
+ int SGPRExcessLimit,
+ int VGPRExcessLimit,
+ int SGPRCriticalLimit,
+ int VGPRCriticalLimit) {
+
+ Cand.SU = SU;
+ Cand.AtTop = AtTop;
+
+ // getDownwardPressure() and getUpwardPressure() make temporary changes to
+ // the the tracker, so we need to pass those function a non-const copy.
+ RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);
+
+ std::vector<unsigned> Pressure;
+ std::vector<unsigned> MaxPressure;
+
+ if (AtTop)
+ TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure);
+ else {
+ // FIXME: I think for bottom up scheduling, the register pressure is cached
+ // and can be retrieved by DAG->getPressureDif(SU).
+ TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
+ }
+
+ int NewSGPRPressure = Pressure[SRI->getSGPRPressureSet()];
+ int NewVGPRPressure = Pressure[SRI->getVGPRPressureSet()];
+
+ // If two instructions increase the pressure of different register sets
+ // by the same amount, the generic scheduler will prefer to schedule the
+ // instruction that increases the set with the least amount of registers,
+ // which in our case would be SGPRs. This is rarely what we want, so
+ // when we report excess/critical register pressure, we do it either
+ // only for VGPRs or only for SGPRs.
+
+ // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
+ const int MaxVGPRPressureInc = 16;
+ bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
+ bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit;
+
+
+ // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
+ // to increase the likelihood we don't go over the limits. We should improve
+ // the analysis to look through dependencies to find the path with the least
+ // register pressure.
+ // FIXME: This is also necessary, because some passes that run after
+ // scheduling and before regalloc increase register pressure.
+ const int ErrorMargin = 3;
+ VGPRExcessLimit -= ErrorMargin;
+ SGPRExcessLimit -= ErrorMargin;
+
+ // We only need to update the RPDelata for instructions that increase
+ // register pressure. Instructions that decrease or keep reg pressure
+ // the same will be marked as RegExcess in tryCandidate() when they
+ // are compared with instructions that increase the register pressure.
+ if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
+ Cand.RPDelta.Excess = PressureChange(SRI->getVGPRPressureSet());
+ Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
+ }
+
+ if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
+ Cand.RPDelta.Excess = PressureChange(SRI->getSGPRPressureSet());
+ Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure = SGPRExcessLimit);
+ }
+
+ // Register pressure is considered 'CRITICAL' if it is approaching a value
+ // that would reduce the wave occupancy for the execution unit. When
+ // register pressure is 'CRITICAL', increading SGPR and VGPR pressure both
+ // has the same cost, so we don't need to prefer one over the other.
+
+ VGPRCriticalLimit -= ErrorMargin;
+ SGPRCriticalLimit -= ErrorMargin;
+
+ int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
+ int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit;
+
+ if (SGPRDelta >= 0 || VGPRDelta >= 0) {
+ if (SGPRDelta > VGPRDelta) {
+ Cand.RPDelta.CriticalMax = PressureChange(SRI->getSGPRPressureSet());
+ Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
+ } else {
+ Cand.RPDelta.CriticalMax = PressureChange(SRI->getVGPRPressureSet());
+ Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
+ }
+ }
+}
+
+// This function is mostly cut and pasted from
+// GenericScheduler::pickNodeFromQueue()
+void GCNMaxOccupancySchedStrategy::pickNodeFromQueue(SchedBoundary &Zone,
+ const CandPolicy &ZonePolicy,
+ const RegPressureTracker &RPTracker,
+ SchedCandidate &Cand) {
+ const SISubtarget &ST = DAG->MF.getSubtarget<SISubtarget>();
+ const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo*>(TRI);
+ ArrayRef<unsigned> Pressure = RPTracker.getRegSetPressureAtPos();
+ unsigned SGPRPressure = Pressure[SRI->getSGPRPressureSet()];
+ unsigned VGPRPressure = Pressure[SRI->getVGPRPressureSet()];
+ unsigned SGPRExcessLimit =
+ Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
+ unsigned VGPRExcessLimit =
+ Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
+ unsigned MaxWaves = getMaxWaves(SGPRPressure, VGPRPressure, DAG->MF);
+ unsigned SGPRCriticalLimit = SRI->getMaxNumSGPRs(ST, MaxWaves, true);
+ unsigned VGPRCriticalLimit = SRI->getMaxNumVGPRs(MaxWaves);
+
+ ReadyQueue &Q = Zone.Available;
+ for (SUnit *SU : Q) {
+
+ SchedCandidate TryCand(ZonePolicy);
+ initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI,
+ SGPRPressure, VGPRPressure,
+ SGPRExcessLimit, VGPRExcessLimit,
+ SGPRCriticalLimit, VGPRCriticalLimit);
+ // Pass SchedBoundary only when comparing nodes from the same boundary.
+ SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
+ GenericScheduler::tryCandidate(Cand, TryCand, ZoneArg);
+ if (TryCand.Reason != NoCand) {
+ // Initialize resource delta if needed in case future heuristics query it.
+ if (TryCand.ResDelta == SchedResourceDelta())
+ TryCand.initResourceDelta(Zone.DAG, SchedModel);
+ Cand.setBest(TryCand);
+ }
+ }
+}
+
+static int getBidirectionalReasonRank(GenericSchedulerBase::CandReason Reason) {
+ switch (Reason) {
+ default:
+ return Reason;
+ case GenericSchedulerBase::RegCritical:
+ case GenericSchedulerBase::RegExcess:
+ return -Reason;
+ }
+}
+
+// This function is mostly cut and pasted from
+// GenericScheduler::pickNodeBidirectional()
+SUnit *GCNMaxOccupancySchedStrategy::pickNodeBidirectional(bool &IsTopNode) {
+ // Schedule as far as possible in the direction of no choice. This is most
+ // efficient, but also provides the best heuristics for CriticalPSets.
+ if (SUnit *SU = Bot.pickOnlyChoice()) {
+ IsTopNode = false;
+ return SU;
+ }
+ if (SUnit *SU = Top.pickOnlyChoice()) {
+ IsTopNode = true;
+ return SU;
+ }
+ // Set the bottom-up policy based on the state of the current bottom zone and
+ // the instructions outside the zone, including the top zone.
+ CandPolicy BotPolicy;
+ setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
+ // Set the top-down policy based on the state of the current top zone and
+ // the instructions outside the zone, including the bottom zone.
+ CandPolicy TopPolicy;
+ setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
+
+ // See if BotCand is still valid (because we previously scheduled from Top).
+ DEBUG(dbgs() << "Picking from Bot:\n");
+ if (!BotCand.isValid() || BotCand.SU->isScheduled ||
+ BotCand.Policy != BotPolicy) {
+ BotCand.reset(CandPolicy());
+ pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
+ assert(BotCand.Reason != NoCand && "failed to find the first candidate");
+ } else {
+ DEBUG(traceCandidate(BotCand));
+ }
+
+ // Check if the top Q has a better candidate.
+ DEBUG(dbgs() << "Picking from Top:\n");
+ if (!TopCand.isValid() || TopCand.SU->isScheduled ||
+ TopCand.Policy != TopPolicy) {
+ TopCand.reset(CandPolicy());
+ pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
+ assert(TopCand.Reason != NoCand && "failed to find the first candidate");
+ } else {
+ DEBUG(traceCandidate(TopCand));
+ }
+
+ // Pick best from BotCand and TopCand.
+ DEBUG(
+ dbgs() << "Top Cand: ";
+ traceCandidate(BotCand);
+ dbgs() << "Bot Cand: ";
+ traceCandidate(TopCand);
+ );
+ SchedCandidate Cand;
+ if (TopCand.Reason == BotCand.Reason) {
+ Cand = BotCand;
+ GenericSchedulerBase::CandReason TopReason = TopCand.Reason;
+ TopCand.Reason = NoCand;
+ GenericScheduler::tryCandidate(Cand, TopCand, nullptr);
+ if (TopCand.Reason != NoCand) {
+ Cand.setBest(TopCand);
+ } else {
+ TopCand.Reason = TopReason;
+ }
+ } else {
+ if (TopCand.Reason == RegExcess && TopCand.RPDelta.Excess.getUnitInc() <= 0) {
+ Cand = TopCand;
+ } else if (BotCand.Reason == RegExcess && BotCand.RPDelta.Excess.getUnitInc() <= 0) {
+ Cand = BotCand;
+ } else if (TopCand.Reason == RegCritical && TopCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
+ Cand = TopCand;
+ } else if (BotCand.Reason == RegCritical && BotCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
+ Cand = BotCand;
+ } else {
+ int TopRank = getBidirectionalReasonRank(TopCand.Reason);
+ int BotRank = getBidirectionalReasonRank(BotCand.Reason);
+ if (TopRank > BotRank) {
+ Cand = TopCand;
+ } else {
+ Cand = BotCand;
+ }
+ }
+ }
+ DEBUG(
+ dbgs() << "Picking: ";
+ traceCandidate(Cand);
+ );
+
+ IsTopNode = Cand.AtTop;
+ return Cand.SU;
+}
+
+// This function is mostly cut and pasted from
+// GenericScheduler::pickNode()
+SUnit *GCNMaxOccupancySchedStrategy::pickNode(bool &IsTopNode) {
+ if (DAG->top() == DAG->bottom()) {
+ assert(Top.Available.empty() && Top.Pending.empty() &&
+ Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
+ return nullptr;
+ }
+ SUnit *SU;
+ do {
+ if (RegionPolicy.OnlyTopDown) {
+ SU = Top.pickOnlyChoice();
+ if (!SU) {
+ CandPolicy NoPolicy;
+ TopCand.reset(NoPolicy);
+ pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
+ assert(TopCand.Reason != NoCand && "failed to find a candidate");
+ SU = TopCand.SU;
+ }
+ IsTopNode = true;
+ } else if (RegionPolicy.OnlyBottomUp) {
+ SU = Bot.pickOnlyChoice();
+ if (!SU) {
+ CandPolicy NoPolicy;
+ BotCand.reset(NoPolicy);
+ pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
+ assert(BotCand.Reason != NoCand && "failed to find a candidate");
+ SU = BotCand.SU;
+ }
+ IsTopNode = false;
+ } else {
+ SU = pickNodeBidirectional(IsTopNode);
+ }
+ } while (SU->isScheduled);
+
+ if (SU->isTopReady())
+ Top.removeReady(SU);
+ if (SU->isBottomReady())
+ Bot.removeReady(SU);
+
+ DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " << *SU->getInstr());
+ return SU;
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h b/contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h
new file mode 100644
index 0000000..4cfc0ce
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/GCNSchedStrategy.h
@@ -0,0 +1,54 @@
+//===-- GCNSchedStrategy.h - GCN Scheduler Strategy -*- C++ -*-------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
+#define LLVM_LIB_TARGET_AMDGPU_GCNSCHEDSTRATEGY_H
+
+#include "llvm/CodeGen/MachineScheduler.h"
+
+namespace llvm {
+
+class SIRegisterInfo;
+
+/// This is a minimal scheduler strategy. The main difference between this
+/// and the GenericScheduler is that GCNSchedStrategy uses different
+/// heuristics to determine excess/critical pressure sets. Its goal is to
+/// maximize kernel occupancy (i.e. maximum number of waves per simd).
+class GCNMaxOccupancySchedStrategy : public GenericScheduler {
+
+ SUnit *pickNodeBidirectional(bool &IsTopNode);
+
+ void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy,
+ const RegPressureTracker &RPTracker,
+ SchedCandidate &Cand);
+
+ void initCandidate(SchedCandidate &Cand, SUnit *SU,
+ bool AtTop, const RegPressureTracker &RPTracker,
+ const SIRegisterInfo *SRI,
+ int SGPRPressure, int VGPRPressure,
+ int SGPRExcessLimit, int VGPRExcessLimit,
+ int SGPRCriticalLimit, int VGPRCriticalLimit);
+
+ void tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand,
+ SchedBoundary *Zone, const SIRegisterInfo *SRI,
+ unsigned SGPRPressure, unsigned VGPRPressure);
+
+public:
+ GCNMaxOccupancySchedStrategy(const MachineSchedContext *C);
+
+ SUnit *pickNode(bool &IsTopNode) override;
+};
+
+} // End namespace llvm
+
+#endif // GCNSCHEDSTRATEGY_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp
index 2932d3b..7172a0a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp
@@ -9,46 +9,52 @@
//===----------------------------------------------------------------------===//
#include "AMDGPUInstPrinter.h"
-#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "SIDefines.h"
+#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "Utils/AMDGPUAsmUtils.h"
+#include "Utils/AMDGPUBaseInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-
-#include <string>
+#include <cassert>
using namespace llvm;
+using namespace llvm::AMDGPU;
void AMDGPUInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
StringRef Annot, const MCSubtargetInfo &STI) {
OS.flush();
- printInstruction(MI, OS);
-
+ printInstruction(MI, STI, OS);
printAnnotation(OS, Annot);
}
void AMDGPUInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
O << formatHex(MI->getOperand(OpNo).getImm() & 0xf);
}
void AMDGPUInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ raw_ostream &O) {
O << formatHex(MI->getOperand(OpNo).getImm() & 0xff);
}
void AMDGPUInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
- O << formatHex(MI->getOperand(OpNo).getImm() & 0xffff);
-}
-
-void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
- O << formatHex(MI->getOperand(OpNo).getImm() & 0xffffffff);
+ // It's possible to end up with a 32-bit literal used with a 16-bit operand
+ // with ignored high bits. Print as 32-bit anyway in that case.
+ int64_t Imm = MI->getOperand(OpNo).getImm();
+ if (isInt<16>(Imm) || isUInt<16>(Imm))
+ O << formatHex(static_cast<uint64_t>(Imm & 0xffff));
+ else
+ printU32ImmOperand(MI, OpNo, STI, O);
}
void AMDGPUInstPrinter::printU4ImmDecOperand(const MCInst *MI, unsigned OpNo,
@@ -66,8 +72,14 @@ void AMDGPUInstPrinter::printU16ImmDecOperand(const MCInst *MI, unsigned OpNo,
O << formatDec(MI->getOperand(OpNo).getImm() & 0xffff);
}
-void AMDGPUInstPrinter::printNamedBit(const MCInst* MI, unsigned OpNo,
- raw_ostream& O, StringRef BitName) {
+void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ O << formatHex(MI->getOperand(OpNo).getImm() & 0xffffffff);
+}
+
+void AMDGPUInstPrinter::printNamedBit(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O, StringRef BitName) {
if (MI->getOperand(OpNo).getImm()) {
O << ' ' << BitName;
}
@@ -97,7 +109,8 @@ void AMDGPUInstPrinter::printMBUFOffset(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printOffset(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
uint16_t Imm = MI->getOperand(OpNo).getImm();
if (Imm != 0) {
O << " offset:";
@@ -106,7 +119,8 @@ void AMDGPUInstPrinter::printOffset(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printOffset0(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
if (MI->getOperand(OpNo).getImm()) {
O << " offset0:";
printU8ImmDecOperand(MI, OpNo, O);
@@ -114,74 +128,97 @@ void AMDGPUInstPrinter::printOffset0(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printOffset1(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
if (MI->getOperand(OpNo).getImm()) {
O << " offset1:";
printU8ImmDecOperand(MI, OpNo, O);
}
}
-void AMDGPUInstPrinter::printSMRDOffset(const MCInst *MI, unsigned OpNo,
+void AMDGPUInstPrinter::printSMRDOffset8(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ printU32ImmOperand(MI, OpNo, STI, O);
+}
+
+void AMDGPUInstPrinter::printSMRDOffset20(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
- printU32ImmOperand(MI, OpNo, O);
+ printU32ImmOperand(MI, OpNo, STI, O);
}
void AMDGPUInstPrinter::printSMRDLiteralOffset(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
- printU32ImmOperand(MI, OpNo, O);
+ printU32ImmOperand(MI, OpNo, STI, O);
}
void AMDGPUInstPrinter::printGDS(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "gds");
}
void AMDGPUInstPrinter::printGLC(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "glc");
}
void AMDGPUInstPrinter::printSLC(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "slc");
}
void AMDGPUInstPrinter::printTFE(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "tfe");
}
void AMDGPUInstPrinter::printDMask(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
if (MI->getOperand(OpNo).getImm()) {
O << " dmask:";
- printU16ImmOperand(MI, OpNo, O);
+ printU16ImmOperand(MI, OpNo, STI, O);
}
}
void AMDGPUInstPrinter::printUNorm(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "unorm");
}
void AMDGPUInstPrinter::printDA(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "da");
}
void AMDGPUInstPrinter::printR128(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "r128");
}
void AMDGPUInstPrinter::printLWE(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printNamedBit(MI, OpNo, O, "lwe");
}
-void AMDGPUInstPrinter::printRegOperand(unsigned reg, raw_ostream &O,
+void AMDGPUInstPrinter::printExpCompr(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ if (MI->getOperand(OpNo).getImm())
+ O << " compr";
+}
+
+void AMDGPUInstPrinter::printExpVM(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ if (MI->getOperand(OpNo).getImm())
+ O << " vm";
+}
+
+void AMDGPUInstPrinter::printRegOperand(unsigned RegNo, raw_ostream &O,
const MCRegisterInfo &MRI) {
- switch (reg) {
+ switch (RegNo) {
case AMDGPU::VCC:
O << "vcc";
return;
@@ -233,52 +270,54 @@ void AMDGPUInstPrinter::printRegOperand(unsigned reg, raw_ostream &O,
// The low 8 bits of the encoding value is the register index, for both VGPRs
// and SGPRs.
- unsigned RegIdx = MRI.getEncodingValue(reg) & ((1 << 8) - 1);
+ unsigned RegIdx = MRI.getEncodingValue(RegNo) & ((1 << 8) - 1);
unsigned NumRegs;
- if (MRI.getRegClass(AMDGPU::VGPR_32RegClassID).contains(reg)) {
+ if (MRI.getRegClass(AMDGPU::VGPR_32RegClassID).contains(RegNo)) {
O << 'v';
NumRegs = 1;
- } else if (MRI.getRegClass(AMDGPU::SGPR_32RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::SGPR_32RegClassID).contains(RegNo)) {
O << 's';
NumRegs = 1;
- } else if (MRI.getRegClass(AMDGPU::VReg_64RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::VReg_64RegClassID).contains(RegNo)) {
O <<'v';
NumRegs = 2;
- } else if (MRI.getRegClass(AMDGPU::SGPR_64RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::SGPR_64RegClassID).contains(RegNo)) {
O << 's';
NumRegs = 2;
- } else if (MRI.getRegClass(AMDGPU::VReg_128RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::VReg_128RegClassID).contains(RegNo)) {
O << 'v';
NumRegs = 4;
- } else if (MRI.getRegClass(AMDGPU::SGPR_128RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::SGPR_128RegClassID).contains(RegNo)) {
O << 's';
NumRegs = 4;
- } else if (MRI.getRegClass(AMDGPU::VReg_96RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::VReg_96RegClassID).contains(RegNo)) {
O << 'v';
NumRegs = 3;
- } else if (MRI.getRegClass(AMDGPU::VReg_256RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::VReg_256RegClassID).contains(RegNo)) {
O << 'v';
NumRegs = 8;
- } else if (MRI.getRegClass(AMDGPU::SReg_256RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::SReg_256RegClassID).contains(RegNo)) {
O << 's';
NumRegs = 8;
- } else if (MRI.getRegClass(AMDGPU::VReg_512RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::VReg_512RegClassID).contains(RegNo)) {
O << 'v';
NumRegs = 16;
- } else if (MRI.getRegClass(AMDGPU::SReg_512RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::SReg_512RegClassID).contains(RegNo)) {
O << 's';
NumRegs = 16;
- } else if (MRI.getRegClass(AMDGPU::TTMP_64RegClassID).contains(reg)) {
+ } else if (MRI.getRegClass(AMDGPU::TTMP_64RegClassID).contains(RegNo)) {
O << "ttmp";
NumRegs = 2;
- RegIdx -= 112; // Trap temps start at offset 112. TODO: Get this from tablegen.
- } else if (MRI.getRegClass(AMDGPU::TTMP_128RegClassID).contains(reg)) {
+ // Trap temps start at offset 112. TODO: Get this from tablegen.
+ RegIdx -= 112;
+ } else if (MRI.getRegClass(AMDGPU::TTMP_128RegClassID).contains(RegNo)) {
O << "ttmp";
NumRegs = 4;
- RegIdx -= 112; // Trap temps start at offset 112. TODO: Get this from tablegen.
+ // Trap temps start at offset 112. TODO: Get this from tablegen.
+ RegIdx -= 112;
} else {
- O << getRegisterName(reg);
+ O << getRegisterName(RegNo);
return;
}
@@ -291,7 +330,7 @@ void AMDGPUInstPrinter::printRegOperand(unsigned reg, raw_ostream &O,
}
void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
if (MII.get(MI->getOpcode()).TSFlags & SIInstrFlags::VOP3)
O << "_e64 ";
else if (MII.get(MI->getOpcode()).TSFlags & SIInstrFlags::DPP)
@@ -301,10 +340,44 @@ void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo,
else
O << "_e32 ";
- printOperand(MI, OpNo, O);
+ printOperand(MI, OpNo, STI, O);
+}
+
+void AMDGPUInstPrinter::printImmediate16(uint32_t Imm,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ int16_t SImm = static_cast<int16_t>(Imm);
+ if (SImm >= -16 && SImm <= 64) {
+ O << SImm;
+ return;
+ }
+
+ if (Imm == 0x3C00)
+ O<< "1.0";
+ else if (Imm == 0xBC00)
+ O<< "-1.0";
+ else if (Imm == 0x3800)
+ O<< "0.5";
+ else if (Imm == 0xB800)
+ O<< "-0.5";
+ else if (Imm == 0x4000)
+ O<< "2.0";
+ else if (Imm == 0xC000)
+ O<< "-2.0";
+ else if (Imm == 0x4400)
+ O<< "4.0";
+ else if (Imm == 0xC400)
+ O<< "-4.0";
+ else if (Imm == 0x3118) {
+ assert(STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm]);
+ O << "0.15915494";
+ } else
+ O << formatHex(static_cast<uint64_t>(Imm));
}
-void AMDGPUInstPrinter::printImmediate32(uint32_t Imm, raw_ostream &O) {
+void AMDGPUInstPrinter::printImmediate32(uint32_t Imm,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
int32_t SImm = static_cast<int32_t>(Imm);
if (SImm >= -16 && SImm <= 64) {
O << SImm;
@@ -329,11 +402,16 @@ void AMDGPUInstPrinter::printImmediate32(uint32_t Imm, raw_ostream &O) {
O << "4.0";
else if (Imm == FloatToBits(-4.0f))
O << "-4.0";
+ else if (Imm == 0x3e22f983 &&
+ STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
+ O << "0.15915494";
else
O << formatHex(static_cast<uint64_t>(Imm));
}
-void AMDGPUInstPrinter::printImmediate64(uint64_t Imm, raw_ostream &O) {
+void AMDGPUInstPrinter::printImmediate64(uint64_t Imm,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
int64_t SImm = static_cast<int64_t>(Imm);
if (SImm >= -16 && SImm <= 64) {
O << SImm;
@@ -358,8 +436,11 @@ void AMDGPUInstPrinter::printImmediate64(uint64_t Imm, raw_ostream &O) {
O << "4.0";
else if (Imm == DoubleToBits(-4.0))
O << "-4.0";
+ else if (Imm == 0x3fc45f306dc9c882 &&
+ STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
+ O << "0.15915494";
else {
- assert(isUInt<32>(Imm));
+ assert(isUInt<32>(Imm) || Imm == 0x3fc45f306dc9c882);
// In rare situations, we will have a 32-bit literal in a 64-bit
// operand. This is technically allowed for the encoding of s_mov_b64.
@@ -368,7 +449,12 @@ void AMDGPUInstPrinter::printImmediate64(uint64_t Imm, raw_ostream &O) {
}
void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
+ if (OpNo >= MI->getNumOperands()) {
+ O << "/*Missing OP" << OpNo << "*/";
+ return;
+ }
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg()) {
@@ -383,22 +469,39 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
}
} else if (Op.isImm()) {
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
- int RCID = Desc.OpInfo[OpNo].RegClass;
- if (RCID != -1) {
- const MCRegisterClass &ImmRC = MRI.getRegClass(RCID);
- if (ImmRC.getSize() == 4)
- printImmediate32(Op.getImm(), O);
- else if (ImmRC.getSize() == 8)
- printImmediate64(Op.getImm(), O);
- else
- llvm_unreachable("Invalid register class size");
- } else if (Desc.OpInfo[OpNo].OperandType == MCOI::OPERAND_IMMEDIATE) {
- printImmediate32(Op.getImm(), O);
- } else {
+ switch (Desc.OpInfo[OpNo].OperandType) {
+ case AMDGPU::OPERAND_REG_IMM_INT32:
+ case AMDGPU::OPERAND_REG_IMM_FP32:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT32:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP32:
+ case MCOI::OPERAND_IMMEDIATE:
+ printImmediate32(Op.getImm(), STI, O);
+ break;
+ case AMDGPU::OPERAND_REG_IMM_INT64:
+ case AMDGPU::OPERAND_REG_IMM_FP64:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT64:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP64:
+ printImmediate64(Op.getImm(), STI, O);
+ break;
+ case AMDGPU::OPERAND_REG_INLINE_C_INT16:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP16:
+ case AMDGPU::OPERAND_REG_IMM_INT16:
+ case AMDGPU::OPERAND_REG_IMM_FP16:
+ printImmediate16(Op.getImm(), STI, O);
+ break;
+ case MCOI::OPERAND_UNKNOWN:
+ case MCOI::OPERAND_PCREL:
+ O << formatDec(Op.getImm());
+ break;
+ case MCOI::OPERAND_REGISTER:
+ // FIXME: This should be removed and handled somewhere else. Seems to come
+ // from a disassembler bug.
+ O << "/*invalid immediate*/";
+ break;
+ default:
// We hit this for the immediate instruction bits that don't yet have a
// custom printer.
- // TODO: Eventually this should be unnecessary.
- O << formatDec(Op.getImm());
+ llvm_unreachable("unexpected immediate operand type");
}
} else if (Op.isFPImm()) {
// We special case 0.0 because otherwise it will be printed as an integer.
@@ -406,12 +509,12 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
O << "0.0";
else {
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
- const MCRegisterClass &ImmRC = MRI.getRegClass(Desc.OpInfo[OpNo].RegClass);
-
- if (ImmRC.getSize() == 4)
- printImmediate32(FloatToBits(Op.getFPImm()), O);
- else if (ImmRC.getSize() == 8)
- printImmediate64(DoubleToBits(Op.getFPImm()), O);
+ int RCID = Desc.OpInfo[OpNo].RegClass;
+ unsigned RCBits = AMDGPU::getRegBitWidth(MRI.getRegClass(RCID));
+ if (RCBits == 32)
+ printImmediate32(FloatToBits(Op.getFPImm()), STI, O);
+ else if (RCBits == 64)
+ printImmediate64(DoubleToBits(Op.getFPImm()), STI, O);
else
llvm_unreachable("Invalid register class size");
}
@@ -424,32 +527,34 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printOperandAndFPInputMods(const MCInst *MI,
- unsigned OpNo,
- raw_ostream &O) {
+ unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
unsigned InputModifiers = MI->getOperand(OpNo).getImm();
if (InputModifiers & SISrcMods::NEG)
O << '-';
if (InputModifiers & SISrcMods::ABS)
O << '|';
- printOperand(MI, OpNo + 1, O);
+ printOperand(MI, OpNo + 1, STI, O);
if (InputModifiers & SISrcMods::ABS)
O << '|';
}
void AMDGPUInstPrinter::printOperandAndIntInputMods(const MCInst *MI,
- unsigned OpNo,
- raw_ostream &O) {
+ unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
unsigned InputModifiers = MI->getOperand(OpNo).getImm();
if (InputModifiers & SISrcMods::SEXT)
O << "sext(";
- printOperand(MI, OpNo + 1, O);
+ printOperand(MI, OpNo + 1, STI, O);
if (InputModifiers & SISrcMods::SEXT)
O << ')';
}
-
void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNo).getImm();
if (Imm <= 0x0ff) {
O << " quad_perm:[";
@@ -488,19 +593,22 @@ void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printRowMask(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
O << " row_mask:";
- printU4ImmOperand(MI, OpNo, O);
+ printU4ImmOperand(MI, OpNo, STI, O);
}
void AMDGPUInstPrinter::printBankMask(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
O << " bank_mask:";
- printU4ImmOperand(MI, OpNo, O);
+ printU4ImmOperand(MI, OpNo, STI, O);
}
void AMDGPUInstPrinter::printBoundCtrl(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNo).getImm();
if (Imm) {
O << " bound_ctrl:0"; // XXX - this syntax is used in sp3
@@ -509,69 +617,180 @@ void AMDGPUInstPrinter::printBoundCtrl(const MCInst *MI, unsigned OpNo,
void AMDGPUInstPrinter::printSDWASel(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
+ using namespace llvm::AMDGPU::SDWA;
+
unsigned Imm = MI->getOperand(OpNo).getImm();
switch (Imm) {
- case 0: O << "BYTE_0"; break;
- case 1: O << "BYTE_1"; break;
- case 2: O << "BYTE_2"; break;
- case 3: O << "BYTE_3"; break;
- case 4: O << "WORD_0"; break;
- case 5: O << "WORD_1"; break;
- case 6: O << "DWORD"; break;
+ case SdwaSel::BYTE_0: O << "BYTE_0"; break;
+ case SdwaSel::BYTE_1: O << "BYTE_1"; break;
+ case SdwaSel::BYTE_2: O << "BYTE_2"; break;
+ case SdwaSel::BYTE_3: O << "BYTE_3"; break;
+ case SdwaSel::WORD_0: O << "WORD_0"; break;
+ case SdwaSel::WORD_1: O << "WORD_1"; break;
+ case SdwaSel::DWORD: O << "DWORD"; break;
default: llvm_unreachable("Invalid SDWA data select operand");
}
}
void AMDGPUInstPrinter::printSDWADstSel(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
O << "dst_sel:";
printSDWASel(MI, OpNo, O);
}
void AMDGPUInstPrinter::printSDWASrc0Sel(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
O << "src0_sel:";
printSDWASel(MI, OpNo, O);
}
void AMDGPUInstPrinter::printSDWASrc1Sel(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
O << "src1_sel:";
printSDWASel(MI, OpNo, O);
}
void AMDGPUInstPrinter::printSDWADstUnused(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
+ using namespace llvm::AMDGPU::SDWA;
+
O << "dst_unused:";
unsigned Imm = MI->getOperand(OpNo).getImm();
switch (Imm) {
- case 0: O << "UNUSED_PAD"; break;
- case 1: O << "UNUSED_SEXT"; break;
- case 2: O << "UNUSED_PRESERVE"; break;
+ case DstUnused::UNUSED_PAD: O << "UNUSED_PAD"; break;
+ case DstUnused::UNUSED_SEXT: O << "UNUSED_SEXT"; break;
+ case DstUnused::UNUSED_PRESERVE: O << "UNUSED_PRESERVE"; break;
default: llvm_unreachable("Invalid SDWA dest_unused operand");
}
}
+template <unsigned N>
+void AMDGPUInstPrinter::printExpSrcN(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ int EnIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), AMDGPU::OpName::en);
+ unsigned En = MI->getOperand(EnIdx).getImm();
+
+ // FIXME: What do we do with compr? The meaning of en changes depending on if
+ // compr is set.
+
+ if (En & (1 << N))
+ printRegOperand(MI->getOperand(OpNo).getReg(), O, MRI);
+ else
+ O << "off";
+}
+
+void AMDGPUInstPrinter::printExpSrc0(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ printExpSrcN<0>(MI, OpNo, STI, O);
+}
+
+void AMDGPUInstPrinter::printExpSrc1(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ printExpSrcN<1>(MI, OpNo, STI, O);
+}
+
+void AMDGPUInstPrinter::printExpSrc2(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ printExpSrcN<2>(MI, OpNo, STI, O);
+}
+
+void AMDGPUInstPrinter::printExpSrc3(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ printExpSrcN<3>(MI, OpNo, STI, O);
+}
+
+void AMDGPUInstPrinter::printExpTgt(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ // This is really a 6 bit field.
+ uint32_t Tgt = MI->getOperand(OpNo).getImm() & ((1 << 6) - 1);
+
+ if (Tgt <= 7)
+ O << " mrt" << Tgt;
+ else if (Tgt == 8)
+ O << " mrtz";
+ else if (Tgt == 9)
+ O << " null";
+ else if (Tgt >= 12 && Tgt <= 15)
+ O << " pos" << Tgt - 12;
+ else if (Tgt >= 32 && Tgt <= 63)
+ O << " param" << Tgt - 32;
+ else {
+ // Reserved values 10, 11
+ O << " invalid_target_" << Tgt;
+ }
+}
+
void AMDGPUInstPrinter::printInterpSlot(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNum).getImm();
+ switch (Imm) {
+ case 0:
+ O << "p10";
+ break;
+ case 1:
+ O << "p20";
+ break;
+ case 2:
+ O << "p0";
+ break;
+ default:
+ O << "invalid_param_" << Imm;
+ }
+}
- if (Imm == 2) {
- O << "P0";
- } else if (Imm == 1) {
- O << "P20";
- } else if (Imm == 0) {
- O << "P10";
- } else {
- llvm_unreachable("Invalid interpolation parameter slot");
+void AMDGPUInstPrinter::printInterpAttr(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ unsigned Attr = MI->getOperand(OpNum).getImm();
+ O << "attr" << Attr;
+}
+
+void AMDGPUInstPrinter::printInterpAttrChan(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ unsigned Chan = MI->getOperand(OpNum).getImm();
+ O << '.' << "xyzw"[Chan & 0x3];
+}
+
+void AMDGPUInstPrinter::printVGPRIndexMode(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ unsigned Val = MI->getOperand(OpNo).getImm();
+ if (Val == 0) {
+ O << " 0";
+ return;
}
+
+ if (Val & VGPRIndexMode::DST_ENABLE)
+ O << " dst";
+
+ if (Val & VGPRIndexMode::SRC0_ENABLE)
+ O << " src0";
+
+ if (Val & VGPRIndexMode::SRC1_ENABLE)
+ O << " src1";
+
+ if (Val & VGPRIndexMode::SRC2_ENABLE)
+ O << " src2";
}
void AMDGPUInstPrinter::printMemOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
- printOperand(MI, OpNo, O);
+ printOperand(MI, OpNo, STI, O);
O << ", ";
- printOperand(MI, OpNo + 1, O);
+ printOperand(MI, OpNo + 1, STI, O);
}
void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo,
@@ -595,23 +814,25 @@ void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printAbs(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printIfSet(MI, OpNo, O, '|');
}
void AMDGPUInstPrinter::printClamp(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printIfSet(MI, OpNo, O, "_SAT");
}
void AMDGPUInstPrinter::printClampSI(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
if (MI->getOperand(OpNo).getImm())
O << " clamp";
}
void AMDGPUInstPrinter::printOModSI(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
int Imm = MI->getOperand(OpNo).getImm();
if (Imm == SIOutMods::MUL2)
O << " mul:2";
@@ -622,6 +843,7 @@ void AMDGPUInstPrinter::printOModSI(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printLiteral(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
assert(Op.isImm() || Op.isExpr());
@@ -635,17 +857,17 @@ void AMDGPUInstPrinter::printLiteral(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printLast(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printIfSet(MI, OpNo, O, "*", " ");
}
void AMDGPUInstPrinter::printNeg(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printIfSet(MI, OpNo, O, '-');
}
void AMDGPUInstPrinter::printOMOD(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
switch (MI->getOperand(OpNo).getImm()) {
default: break;
case 1:
@@ -661,22 +883,24 @@ void AMDGPUInstPrinter::printOMOD(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printRel(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
printIfSet(MI, OpNo, O, '+');
}
void AMDGPUInstPrinter::printUpdateExecMask(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
printIfSet(MI, OpNo, O, "ExecMask,");
}
void AMDGPUInstPrinter::printUpdatePred(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
printIfSet(MI, OpNo, O, "Pred,");
}
void AMDGPUInstPrinter::printWrite(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.getImm() == 0) {
O << " (MASKED)";
@@ -684,7 +908,7 @@ void AMDGPUInstPrinter::printWrite(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printSel(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ raw_ostream &O) {
const char * chans = "XYZW";
int sel = MI->getOperand(OpNo).getImm();
@@ -708,6 +932,7 @@ void AMDGPUInstPrinter::printSel(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printBankSwizzle(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
int BankSwizzle = MI->getOperand(OpNo).getImm();
switch (BankSwizzle) {
@@ -729,11 +954,10 @@ void AMDGPUInstPrinter::printBankSwizzle(const MCInst *MI, unsigned OpNo,
default:
break;
}
- return;
}
void AMDGPUInstPrinter::printRSel(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
unsigned Sel = MI->getOperand(OpNo).getImm();
switch (Sel) {
case 0:
@@ -763,7 +987,7 @@ void AMDGPUInstPrinter::printRSel(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printCT(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
unsigned CT = MI->getOperand(OpNo).getImm();
switch (CT) {
case 0:
@@ -778,7 +1002,7 @@ void AMDGPUInstPrinter::printCT(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printKCache(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
int KCacheMode = MI->getOperand(OpNo).getImm();
if (KCacheMode > 0) {
int KCacheBank = MI->getOperand(OpNo - 2).getImm();
@@ -790,6 +1014,7 @@ void AMDGPUInstPrinter::printKCache(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printSendMsg(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
using namespace llvm::AMDGPU::SendMsg;
@@ -825,32 +1050,34 @@ void AMDGPUInstPrinter::printSendMsg(const MCInst *MI, unsigned OpNo,
O << "sendmsg(" << IdSymbolic[Id] << ", " << OpSysSymbolic[OpSys] << ')';
return;
}
- } while (0);
+ } while (false);
O << SImm16; // Unknown simm16 code.
}
void AMDGPUInstPrinter::printWaitFlag(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI,
raw_ostream &O) {
+ IsaVersion IV = getIsaVersion(STI.getFeatureBits());
+
unsigned SImm16 = MI->getOperand(OpNo).getImm();
- unsigned Vmcnt = SImm16 & 0xF;
- unsigned Expcnt = (SImm16 >> 4) & 0x7;
- unsigned Lgkmcnt = (SImm16 >> 8) & 0xF;
+ unsigned Vmcnt, Expcnt, Lgkmcnt;
+ decodeWaitcnt(IV, SImm16, Vmcnt, Expcnt, Lgkmcnt);
bool NeedSpace = false;
- if (Vmcnt != 0xF) {
+ if (Vmcnt != getVmcntBitMask(IV)) {
O << "vmcnt(" << Vmcnt << ')';
NeedSpace = true;
}
- if (Expcnt != 0x7) {
+ if (Expcnt != getExpcntBitMask(IV)) {
if (NeedSpace)
O << ' ';
O << "expcnt(" << Expcnt << ')';
NeedSpace = true;
}
- if (Lgkmcnt != 0xF) {
+ if (Lgkmcnt != getLgkmcntBitMask(IV)) {
if (NeedSpace)
O << ' ';
O << "lgkmcnt(" << Lgkmcnt << ')';
@@ -858,7 +1085,7 @@ void AMDGPUInstPrinter::printWaitFlag(const MCInst *MI, unsigned OpNo,
}
void AMDGPUInstPrinter::printHwreg(const MCInst *MI, unsigned OpNo,
- raw_ostream &O) {
+ const MCSubtargetInfo &STI, raw_ostream &O) {
using namespace llvm::AMDGPU::Hwreg;
unsigned SImm16 = MI->getOperand(OpNo).getImm();
diff --git a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h
index f5a290f..a6d348f 100644
--- a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h
+++ b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h
@@ -24,7 +24,8 @@ public:
: MCInstPrinter(MAI, MII, MRI) {}
//Autogenerated by tblgen
- void printInstruction(const MCInst *MI, raw_ostream &O);
+ void printInstruction(const MCInst *MI, const MCSubtargetInfo &STI,
+ raw_ostream &O);
static const char *getRegisterName(unsigned RegNo);
void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
@@ -33,76 +34,159 @@ public:
const MCRegisterInfo &MRI);
private:
- void printU4ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printU4ImmOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
void printU8ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printU16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printU16ImmOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
void printU4ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU8ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU16ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printU32ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printNamedBit(const MCInst* MI, unsigned OpNo, raw_ostream& O,
+ void printU32ImmOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printNamedBit(const MCInst *MI, unsigned OpNo, raw_ostream &O,
StringRef BitName);
void printOffen(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printIdxen(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printAddr64(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printMBUFOffset(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printOffset(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printOffset0(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printOffset1(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSMRDOffset(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSMRDLiteralOffset(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printGDS(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printGLC(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSLC(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printTFE(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printDMask(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printUNorm(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printDA(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printR128(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printLWE(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printOffset(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printOffset0(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printOffset1(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printSMRDOffset8(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printSMRDOffset20(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printSMRDLiteralOffset(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printGDS(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printGLC(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printSLC(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printTFE(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printDMask(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printUNorm(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printDA(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printR128(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printLWE(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpCompr(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpVM(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+
void printRegOperand(unsigned RegNo, raw_ostream &O);
- void printVOPDst(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printImmediate32(uint32_t I, raw_ostream &O);
- void printImmediate64(uint64_t I, raw_ostream &O);
- void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printOperandAndFPInputMods(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printOperandAndIntInputMods(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printDPPCtrl(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printRowMask(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printBankMask(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printBoundCtrl(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printVOPDst(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printImmediate16(uint32_t Imm, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printImmediate32(uint32_t Imm, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printImmediate64(uint64_t Imm, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printOperandAndFPInputMods(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printOperandAndIntInputMods(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printDPPCtrl(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printRowMask(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printBankMask(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printBoundCtrl(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
void printSDWASel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSDWADstSel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSDWASrc0Sel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSDWASrc1Sel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printSDWADstUnused(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printInterpSlot(const MCInst *MI, unsigned OpNum, raw_ostream &O);
- void printMemOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printSDWADstSel(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printSDWASrc0Sel(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printSDWASrc1Sel(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printSDWADstUnused(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printInterpSlot(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printInterpAttr(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printInterpAttrChan(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+
+ void printVGPRIndexMode(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printMemOperand(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+
+
+ template <unsigned N>
+ void printExpSrcN(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpSrc0(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpSrc1(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpSrc2(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpSrc3(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printExpTgt(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+
static void printIfSet(const MCInst *MI, unsigned OpNo, raw_ostream &O,
StringRef Asm, StringRef Default = "");
- static void printIfSet(const MCInst *MI, unsigned OpNo,
- raw_ostream &O, char Asm);
- static void printAbs(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printClamp(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printClampSI(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printOModSI(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- void printLiteral(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printLast(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printNeg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printOMOD(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printRel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printUpdateExecMask(const MCInst *MI, unsigned OpNo,
- raw_ostream &O);
- static void printUpdatePred(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printWrite(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printSel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printBankSwizzle(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printRSel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printCT(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printKCache(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printSendMsg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printWaitFlag(const MCInst *MI, unsigned OpNo, raw_ostream &O);
- static void printHwreg(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ static void printIfSet(const MCInst *MI, unsigned OpNo, raw_ostream &O,
+ char Asm);
+ void printAbs(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printClamp(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printClampSI(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printOModSI(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printLiteral(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printLast(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printNeg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printOMOD(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printRel(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printUpdateExecMask(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printUpdatePred(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printWrite(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printSel(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printBankSwizzle(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printRSel(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printCT(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printKCache(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printSendMsg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printWaitFlag(const MCInst *MI, unsigned OpNo,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ void printHwreg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &O);
};
} // End namespace llvm
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
index 1cb9d21..ffb92aa 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCValue.h"
@@ -22,30 +23,19 @@ using namespace llvm;
namespace {
-class AMDGPUMCObjectWriter : public MCObjectWriter {
-public:
- AMDGPUMCObjectWriter(raw_pwrite_stream &OS) : MCObjectWriter(OS, true) {}
- void executePostLayoutBinding(MCAssembler &Asm,
- const MCAsmLayout &Layout) override {
- //XXX: Implement if necessary.
- }
- void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
- const MCFragment *Fragment, const MCFixup &Fixup,
- MCValue Target, bool &IsPCRel,
- uint64_t &FixedValue) override {
- assert(!"Not implemented");
- }
-
- void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
-
-};
-
class AMDGPUAsmBackend : public MCAsmBackend {
public:
AMDGPUAsmBackend(const Target &T)
: MCAsmBackend() {}
unsigned getNumFixupKinds() const override { return AMDGPU::NumTargetFixupKinds; };
+
+ void processFixupValue(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) override;
+
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
uint64_t Value, bool IsPCRel) const override;
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
@@ -55,7 +45,7 @@ public:
}
void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
MCInst &Res) const override {
- assert(!"Not implemented");
+ llvm_unreachable("Not implemented");
}
bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
@@ -65,15 +55,10 @@ public:
} //End anonymous namespace
-void AMDGPUMCObjectWriter::writeObject(MCAssembler &Asm,
- const MCAsmLayout &Layout) {
- for (MCAssembler::iterator I = Asm.begin(), E = Asm.end(); I != E; ++I) {
- Asm.writeSectionData(&*I, Layout);
- }
-}
-
static unsigned getFixupKindNumBytes(unsigned Kind) {
switch (Kind) {
+ case AMDGPU::fixup_si_sopp_br:
+ return 2;
case FK_SecRel_1:
case FK_Data_1:
return 1;
@@ -92,40 +77,77 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
}
}
+static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
+ MCContext *Ctx) {
+ int64_t SignedValue = static_cast<int64_t>(Value);
+
+ switch (Fixup.getKind()) {
+ case AMDGPU::fixup_si_sopp_br: {
+ int64_t BrImm = (SignedValue - 4) / 4;
+
+ if (Ctx && !isInt<16>(BrImm))
+ Ctx->reportError(Fixup.getLoc(), "branch size exceeds simm16");
+
+ return BrImm;
+ }
+ case FK_Data_1:
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ case FK_PCRel_4:
+ case FK_SecRel_4:
+ return Value;
+ default:
+ llvm_unreachable("unhandled fixup kind");
+ }
+}
+
+void AMDGPUAsmBackend::processFixupValue(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) {
+ MCValue Res;
+
+ // When we have complex expressions like: BB0_1 + (BB0_2 - 4), which are
+ // used for long branches, this function will be called with
+ // IsResolved = false and Value set to some pre-computed value. In
+ // the example above, the value would be:
+ // (BB0_1 + (BB0_2 - 4)) - CurrentOffsetFromStartOfFunction.
+ // This is not what we want. We just want the expression computation
+ // only. The reason the MC layer subtracts the current offset from the
+ // expression is because the fixup is of kind FK_PCRel_4.
+ // For these scenarios, evaluateAsValue gives us the computation that we
+ // want.
+ if (!IsResolved && Fixup.getValue()->evaluateAsValue(Res, Layout) &&
+ Res.isAbsolute()) {
+ Value = Res.getConstant();
+ IsResolved = true;
+
+ }
+ if (IsResolved)
+ Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
+}
+
void AMDGPUAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
unsigned DataSize, uint64_t Value,
bool IsPCRel) const {
+ if (!Value)
+ return; // Doesn't change encoding.
- switch ((unsigned)Fixup.getKind()) {
- case AMDGPU::fixup_si_sopp_br: {
- int64_t BrImm = ((int64_t)Value - 4) / 4;
- if (!isInt<16>(BrImm))
- report_fatal_error("branch size exceeds simm16");
-
- uint16_t *Dst = (uint16_t*)(Data + Fixup.getOffset());
- *Dst = BrImm;
- break;
- }
-
- default: {
- // FIXME: Copied from AArch64
- unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
- if (!Value)
- return; // Doesn't change encoding.
- MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
-
- // Shift the value into position.
- Value <<= Info.TargetOffset;
-
- unsigned Offset = Fixup.getOffset();
- assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
-
- // For each byte of the fragment that the fixup touches, mask in the
- // bits from the fixup value.
- for (unsigned i = 0; i != NumBytes; ++i)
- Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
- }
- }
+ MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
+
+ // Shift the value into position.
+ Value <<= Info.TargetOffset;
+
+ unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
+ uint32_t Offset = Fixup.getOffset();
+ assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
+
+ // For each byte of the fragment that the fixup touches, mask in the bits from
+ // the fixup value.
+ for (unsigned i = 0; i != NumBytes; ++i)
+ Data[Offset + i] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
}
const MCFixupKindInfo &AMDGPUAsmBackend::getFixupKindInfo(
@@ -171,7 +193,8 @@ public:
MCAsmBackend *llvm::createAMDGPUAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
// Use 64-bit ELF for amdgcn
return new ELFAMDGPUAsmBackend(T, TT);
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUELFObjectWriter.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUELFObjectWriter.cpp
index b4e3b8e..1847d7a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUELFObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUELFObjectWriter.cpp
@@ -38,26 +38,40 @@ unsigned AMDGPUELFObjectWriter::getRelocType(MCContext &Ctx,
const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
- // SCRATCH_RSRC_DWORD[01] is a special global variable that represents
- // the scratch buffer.
- if (Target.getSymA()->getSymbol().getName() == "SCRATCH_RSRC_DWORD0")
- return ELF::R_AMDGPU_ABS32_LO;
- if (Target.getSymA()->getSymbol().getName() == "SCRATCH_RSRC_DWORD1")
- return ELF::R_AMDGPU_ABS32_HI;
+ if (const auto *SymA = Target.getSymA()) {
+ // SCRATCH_RSRC_DWORD[01] is a special global variable that represents
+ // the scratch buffer.
+ if (SymA->getSymbol().getName() == "SCRATCH_RSRC_DWORD0")
+ return ELF::R_AMDGPU_ABS32_LO;
+
+ if (SymA->getSymbol().getName() == "SCRATCH_RSRC_DWORD1")
+ return ELF::R_AMDGPU_ABS32_HI;
+ }
switch (Target.getAccessVariant()) {
default:
break;
case MCSymbolRefExpr::VK_GOTPCREL:
return ELF::R_AMDGPU_GOTPCREL;
+ case MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO:
+ return ELF::R_AMDGPU_GOTPCREL32_LO;
+ case MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI:
+ return ELF::R_AMDGPU_GOTPCREL32_HI;
+ case MCSymbolRefExpr::VK_AMDGPU_REL32_LO:
+ return ELF::R_AMDGPU_REL32_LO;
+ case MCSymbolRefExpr::VK_AMDGPU_REL32_HI:
+ return ELF::R_AMDGPU_REL32_HI;
}
switch (Fixup.getKind()) {
default: break;
case FK_PCRel_4:
return ELF::R_AMDGPU_REL32;
+ case FK_Data_4:
case FK_SecRel_4:
return ELF::R_AMDGPU_ABS32;
+ case FK_Data_8:
+ return ELF::R_AMDGPU_ABS64;
}
llvm_unreachable("unhandled relocation type");
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h
index c942ea9..3d3858a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h
@@ -21,11 +21,19 @@
namespace llvm {
class MCInst;
+class MCInstrInfo;
class MCOperand;
class MCSubtargetInfo;
+class FeatureBitset;
class AMDGPUMCCodeEmitter : public MCCodeEmitter {
virtual void anchor();
+
+protected:
+ const MCInstrInfo &MCII;
+
+ AMDGPUMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
+
public:
uint64_t getBinaryCodeForInstr(const MCInst &MI,
@@ -43,6 +51,11 @@ public:
const MCSubtargetInfo &STI) const {
return 0;
}
+
+protected:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
};
} // End namespace llvm
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp
index a0d9aab..136e6ec 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.cpp
@@ -86,7 +86,7 @@ static MCStreamer *createMCStreamer(const Triple &T, MCContext &Context,
}
extern "C" void LLVMInitializeAMDGPUTargetMC() {
- for (Target *T : {&TheAMDGPUTarget, &TheGCNTarget}) {
+ for (Target *T : {&getTheAMDGPUTarget(), &getTheGCNTarget()}) {
RegisterMCAsmInfo<AMDGPUMCAsmInfo> X(*T);
TargetRegistry::RegisterMCInstrInfo(*T, createAMDGPUMCInstrInfo);
@@ -98,14 +98,15 @@ extern "C" void LLVMInitializeAMDGPUTargetMC() {
}
// R600 specific registration
- TargetRegistry::RegisterMCCodeEmitter(TheAMDGPUTarget,
+ TargetRegistry::RegisterMCCodeEmitter(getTheAMDGPUTarget(),
createR600MCCodeEmitter);
// GCN specific registration
- TargetRegistry::RegisterMCCodeEmitter(TheGCNTarget, createSIMCCodeEmitter);
+ TargetRegistry::RegisterMCCodeEmitter(getTheGCNTarget(),
+ createSIMCCodeEmitter);
- TargetRegistry::RegisterAsmTargetStreamer(TheGCNTarget,
+ TargetRegistry::RegisterAsmTargetStreamer(getTheGCNTarget(),
createAMDGPUAsmTargetStreamer);
- TargetRegistry::RegisterObjectTargetStreamer(TheGCNTarget,
- createAMDGPUObjectTargetStreamer);
+ TargetRegistry::RegisterObjectTargetStreamer(
+ getTheGCNTarget(), createAMDGPUObjectTargetStreamer);
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.h b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.h
index 9ab7940..548bad5 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCTargetDesc.h
@@ -19,7 +19,6 @@
#include "llvm/Support/DataTypes.h"
namespace llvm {
-class StringRef;
class MCAsmBackend;
class MCCodeEmitter;
class MCContext;
@@ -27,13 +26,14 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
+class StringRef;
class Target;
class Triple;
class raw_pwrite_stream;
-class raw_ostream;
-extern Target TheAMDGPUTarget;
-extern Target TheGCNTarget;
+Target &getTheAMDGPUTarget();
+Target &getTheGCNTarget();
MCCodeEmitter *createR600MCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
@@ -44,7 +44,8 @@ MCCodeEmitter *createSIMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx);
MCAsmBackend *createAMDGPUAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createAMDGPUELFObjectWriter(bool Is64Bit,
bool HasRelocationAddend,
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp
new file mode 100644
index 0000000..95387ad
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.cpp
@@ -0,0 +1,408 @@
+//===-- AMDGPURuntimeMD.cpp - Generates runtime metadata ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// Generates AMDGPU runtime metadata for YAML mapping.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#include "AMDGPU.h"
+#include "AMDGPURuntimeMetadata.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <vector>
+#include "AMDGPURuntimeMD.h"
+
+using namespace llvm;
+using namespace ::AMDGPU::RuntimeMD;
+
+static cl::opt<bool>
+DumpRuntimeMD("amdgpu-dump-rtmd",
+ cl::desc("Dump AMDGPU runtime metadata"));
+
+static cl::opt<bool>
+CheckRuntimeMDParser("amdgpu-check-rtmd-parser", cl::Hidden,
+ cl::desc("Check AMDGPU runtime metadata YAML parser"));
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint8_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Kernel::Metadata)
+LLVM_YAML_IS_SEQUENCE_VECTOR(KernelArg::Metadata)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<KernelArg::Metadata> {
+ static void mapping(IO &YamlIO, KernelArg::Metadata &A) {
+ YamlIO.mapRequired(KeyName::ArgSize, A.Size);
+ YamlIO.mapRequired(KeyName::ArgAlign, A.Align);
+ YamlIO.mapOptional(KeyName::ArgPointeeAlign, A.PointeeAlign, 0U);
+ YamlIO.mapRequired(KeyName::ArgKind, A.Kind);
+ YamlIO.mapRequired(KeyName::ArgValueType, A.ValueType);
+ YamlIO.mapOptional(KeyName::ArgTypeName, A.TypeName, std::string());
+ YamlIO.mapOptional(KeyName::ArgName, A.Name, std::string());
+ YamlIO.mapOptional(KeyName::ArgAddrQual, A.AddrQual, INVALID_ADDR_QUAL);
+ YamlIO.mapOptional(KeyName::ArgAccQual, A.AccQual, INVALID_ACC_QUAL);
+ YamlIO.mapOptional(KeyName::ArgIsVolatile, A.IsVolatile, uint8_t(0));
+ YamlIO.mapOptional(KeyName::ArgIsConst, A.IsConst, uint8_t(0));
+ YamlIO.mapOptional(KeyName::ArgIsRestrict, A.IsRestrict, uint8_t(0));
+ YamlIO.mapOptional(KeyName::ArgIsPipe, A.IsPipe, uint8_t(0));
+ }
+ static const bool flow = true;
+};
+
+template <> struct MappingTraits<Kernel::Metadata> {
+ static void mapping(IO &YamlIO, Kernel::Metadata &K) {
+ YamlIO.mapRequired(KeyName::KernelName, K.Name);
+ YamlIO.mapOptional(KeyName::Language, K.Language, std::string());
+ YamlIO.mapOptional(KeyName::LanguageVersion, K.LanguageVersion);
+ YamlIO.mapOptional(KeyName::ReqdWorkGroupSize, K.ReqdWorkGroupSize);
+ YamlIO.mapOptional(KeyName::WorkGroupSizeHint, K.WorkGroupSizeHint);
+ YamlIO.mapOptional(KeyName::VecTypeHint, K.VecTypeHint, std::string());
+ YamlIO.mapOptional(KeyName::KernelIndex, K.KernelIndex,
+ INVALID_KERNEL_INDEX);
+ YamlIO.mapOptional(KeyName::NoPartialWorkGroups, K.NoPartialWorkGroups,
+ uint8_t(0));
+ YamlIO.mapRequired(KeyName::Args, K.Args);
+ }
+ static const bool flow = true;
+};
+
+template <> struct MappingTraits<Program::Metadata> {
+ static void mapping(IO &YamlIO, Program::Metadata &Prog) {
+ YamlIO.mapRequired(KeyName::MDVersion, Prog.MDVersionSeq);
+ YamlIO.mapOptional(KeyName::PrintfInfo, Prog.PrintfInfo);
+ YamlIO.mapOptional(KeyName::Kernels, Prog.Kernels);
+ }
+ static const bool flow = true;
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+// Get a vector of three integer values from MDNode \p Node;
+static std::vector<uint32_t> getThreeInt32(MDNode *Node) {
+ assert(Node->getNumOperands() == 3);
+ std::vector<uint32_t> V;
+ for (const MDOperand &Op : Node->operands()) {
+ const ConstantInt *CI = mdconst::extract<ConstantInt>(Op);
+ V.push_back(CI->getZExtValue());
+ }
+ return V;
+}
+
+static std::string getOCLTypeName(Type *Ty, bool Signed) {
+ switch (Ty->getTypeID()) {
+ case Type::HalfTyID:
+ return "half";
+ case Type::FloatTyID:
+ return "float";
+ case Type::DoubleTyID:
+ return "double";
+ case Type::IntegerTyID: {
+ if (!Signed)
+ return (Twine('u') + getOCLTypeName(Ty, true)).str();
+ unsigned BW = Ty->getIntegerBitWidth();
+ switch (BW) {
+ case 8:
+ return "char";
+ case 16:
+ return "short";
+ case 32:
+ return "int";
+ case 64:
+ return "long";
+ default:
+ return (Twine('i') + Twine(BW)).str();
+ }
+ }
+ case Type::VectorTyID: {
+ VectorType *VecTy = cast<VectorType>(Ty);
+ Type *EleTy = VecTy->getElementType();
+ unsigned Size = VecTy->getVectorNumElements();
+ return (Twine(getOCLTypeName(EleTy, Signed)) + Twine(Size)).str();
+ }
+ default:
+ return "unknown";
+ }
+}
+
+static KernelArg::ValueType getRuntimeMDValueType(
+ Type *Ty, StringRef TypeName) {
+ switch (Ty->getTypeID()) {
+ case Type::HalfTyID:
+ return KernelArg::F16;
+ case Type::FloatTyID:
+ return KernelArg::F32;
+ case Type::DoubleTyID:
+ return KernelArg::F64;
+ case Type::IntegerTyID: {
+ bool Signed = !TypeName.startswith("u");
+ switch (Ty->getIntegerBitWidth()) {
+ case 8:
+ return Signed ? KernelArg::I8 : KernelArg::U8;
+ case 16:
+ return Signed ? KernelArg::I16 : KernelArg::U16;
+ case 32:
+ return Signed ? KernelArg::I32 : KernelArg::U32;
+ case 64:
+ return Signed ? KernelArg::I64 : KernelArg::U64;
+ default:
+ // Runtime does not recognize other integer types. Report as struct type.
+ return KernelArg::Struct;
+ }
+ }
+ case Type::VectorTyID:
+ return getRuntimeMDValueType(Ty->getVectorElementType(), TypeName);
+ case Type::PointerTyID:
+ return getRuntimeMDValueType(Ty->getPointerElementType(), TypeName);
+ default:
+ return KernelArg::Struct;
+ }
+}
+
+static KernelArg::AddressSpaceQualifer getRuntimeAddrSpace(
+ AMDGPUAS::AddressSpaces A) {
+ switch (A) {
+ case AMDGPUAS::GLOBAL_ADDRESS:
+ return KernelArg::Global;
+ case AMDGPUAS::CONSTANT_ADDRESS:
+ return KernelArg::Constant;
+ case AMDGPUAS::LOCAL_ADDRESS:
+ return KernelArg::Local;
+ case AMDGPUAS::FLAT_ADDRESS:
+ return KernelArg::Generic;
+ case AMDGPUAS::REGION_ADDRESS:
+ return KernelArg::Region;
+ default:
+ return KernelArg::Private;
+ }
+}
+
+static KernelArg::Metadata getRuntimeMDForKernelArg(const DataLayout &DL,
+ Type *T, KernelArg::Kind Kind, StringRef BaseTypeName = "",
+ StringRef TypeName = "", StringRef ArgName = "", StringRef TypeQual = "",
+ StringRef AccQual = "") {
+
+ KernelArg::Metadata Arg;
+
+ // Set ArgSize and ArgAlign.
+ Arg.Size = DL.getTypeAllocSize(T);
+ Arg.Align = DL.getABITypeAlignment(T);
+ if (auto PT = dyn_cast<PointerType>(T)) {
+ auto ET = PT->getElementType();
+ if (PT->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS && ET->isSized())
+ Arg.PointeeAlign = DL.getABITypeAlignment(ET);
+ }
+
+ // Set ArgTypeName.
+ Arg.TypeName = TypeName;
+
+ // Set ArgName.
+ Arg.Name = ArgName;
+
+ // Set ArgIsVolatile, ArgIsRestrict, ArgIsConst and ArgIsPipe.
+ SmallVector<StringRef, 1> SplitQ;
+ TypeQual.split(SplitQ, " ", -1, false /* Drop empty entry */);
+
+ for (StringRef KeyName : SplitQ) {
+ auto *P = StringSwitch<uint8_t *>(KeyName)
+ .Case("volatile", &Arg.IsVolatile)
+ .Case("restrict", &Arg.IsRestrict)
+ .Case("const", &Arg.IsConst)
+ .Case("pipe", &Arg.IsPipe)
+ .Default(nullptr);
+ if (P)
+ *P = 1;
+ }
+
+ // Set ArgKind.
+ Arg.Kind = Kind;
+
+ // Set ArgValueType.
+ Arg.ValueType = getRuntimeMDValueType(T, BaseTypeName);
+
+ // Set ArgAccQual.
+ if (!AccQual.empty()) {
+ Arg.AccQual = StringSwitch<KernelArg::AccessQualifer>(AccQual)
+ .Case("read_only", KernelArg::ReadOnly)
+ .Case("write_only", KernelArg::WriteOnly)
+ .Case("read_write", KernelArg::ReadWrite)
+ .Default(KernelArg::AccNone);
+ }
+
+ // Set ArgAddrQual.
+ if (auto *PT = dyn_cast<PointerType>(T)) {
+ Arg.AddrQual = getRuntimeAddrSpace(static_cast<AMDGPUAS::AddressSpaces>(
+ PT->getAddressSpace()));
+ }
+
+ return Arg;
+}
+
+static Kernel::Metadata getRuntimeMDForKernel(const Function &F) {
+ Kernel::Metadata Kernel;
+ Kernel.Name = F.getName();
+ auto &M = *F.getParent();
+
+ // Set Language and LanguageVersion.
+ if (auto MD = M.getNamedMetadata("opencl.ocl.version")) {
+ if (MD->getNumOperands() != 0) {
+ auto Node = MD->getOperand(0);
+ if (Node->getNumOperands() > 1) {
+ Kernel.Language = "OpenCL C";
+ uint16_t Major = mdconst::extract<ConstantInt>(Node->getOperand(0))
+ ->getZExtValue();
+ uint16_t Minor = mdconst::extract<ConstantInt>(Node->getOperand(1))
+ ->getZExtValue();
+ Kernel.LanguageVersion.push_back(Major);
+ Kernel.LanguageVersion.push_back(Minor);
+ }
+ }
+ }
+
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ for (auto &Arg : F.args()) {
+ unsigned I = Arg.getArgNo();
+ Type *T = Arg.getType();
+ auto TypeName = dyn_cast<MDString>(F.getMetadata(
+ "kernel_arg_type")->getOperand(I))->getString();
+ auto BaseTypeName = cast<MDString>(F.getMetadata(
+ "kernel_arg_base_type")->getOperand(I))->getString();
+ StringRef ArgName;
+ if (auto ArgNameMD = F.getMetadata("kernel_arg_name"))
+ ArgName = cast<MDString>(ArgNameMD->getOperand(I))->getString();
+ auto TypeQual = cast<MDString>(F.getMetadata(
+ "kernel_arg_type_qual")->getOperand(I))->getString();
+ auto AccQual = cast<MDString>(F.getMetadata(
+ "kernel_arg_access_qual")->getOperand(I))->getString();
+ KernelArg::Kind Kind;
+ if (TypeQual.find("pipe") != StringRef::npos)
+ Kind = KernelArg::Pipe;
+ else Kind = StringSwitch<KernelArg::Kind>(BaseTypeName)
+ .Case("sampler_t", KernelArg::Sampler)
+ .Case("queue_t", KernelArg::Queue)
+ .Cases("image1d_t", "image1d_array_t", "image1d_buffer_t",
+ "image2d_t" , "image2d_array_t", KernelArg::Image)
+ .Cases("image2d_depth_t", "image2d_array_depth_t",
+ "image2d_msaa_t", "image2d_array_msaa_t",
+ "image2d_msaa_depth_t", KernelArg::Image)
+ .Cases("image2d_array_msaa_depth_t", "image3d_t",
+ KernelArg::Image)
+ .Default(isa<PointerType>(T) ?
+ (T->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS ?
+ KernelArg::DynamicSharedPointer :
+ KernelArg::GlobalBuffer) :
+ KernelArg::ByValue);
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, T, Kind,
+ BaseTypeName, TypeName, ArgName, TypeQual, AccQual));
+ }
+
+ // Emit hidden kernel arguments for OpenCL kernels.
+ if (F.getParent()->getNamedMetadata("opencl.ocl.version")) {
+ auto Int64T = Type::getInt64Ty(F.getContext());
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int64T,
+ KernelArg::HiddenGlobalOffsetX));
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int64T,
+ KernelArg::HiddenGlobalOffsetY));
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int64T,
+ KernelArg::HiddenGlobalOffsetZ));
+ if (F.getParent()->getNamedMetadata("llvm.printf.fmts")) {
+ auto Int8PtrT = Type::getInt8PtrTy(F.getContext(),
+ KernelArg::Global);
+ Kernel.Args.emplace_back(getRuntimeMDForKernelArg(DL, Int8PtrT,
+ KernelArg::HiddenPrintfBuffer));
+ }
+ }
+
+ // Set ReqdWorkGroupSize, WorkGroupSizeHint, and VecTypeHint.
+ if (auto RWGS = F.getMetadata("reqd_work_group_size"))
+ Kernel.ReqdWorkGroupSize = getThreeInt32(RWGS);
+
+ if (auto WGSH = F.getMetadata("work_group_size_hint"))
+ Kernel.WorkGroupSizeHint = getThreeInt32(WGSH);
+
+ if (auto VTH = F.getMetadata("vec_type_hint"))
+ Kernel.VecTypeHint = getOCLTypeName(cast<ValueAsMetadata>(
+ VTH->getOperand(0))->getType(), mdconst::extract<ConstantInt>(
+ VTH->getOperand(1))->getZExtValue());
+
+ return Kernel;
+}
+
+Program::Metadata::Metadata(const std::string &YAML) {
+ yaml::Input Input(YAML);
+ Input >> *this;
+}
+
+std::string Program::Metadata::toYAML(void) {
+ std::string Text;
+ raw_string_ostream Stream(Text);
+ yaml::Output Output(Stream, nullptr, INT_MAX /* do not wrap line */);
+ Output << *this;
+ return Stream.str();
+}
+
+Program::Metadata Program::Metadata::fromYAML(const std::string &S) {
+ return Program::Metadata(S);
+}
+
+// Check if the YAML string can be parsed.
+static void checkRuntimeMDYAMLString(const std::string &YAML) {
+ auto P = Program::Metadata::fromYAML(YAML);
+ auto S = P.toYAML();
+ llvm::errs() << "AMDGPU runtime metadata parser test "
+ << (YAML == S ? "passes" : "fails") << ".\n";
+ if (YAML != S) {
+ llvm::errs() << "First output: " << YAML << '\n'
+ << "Second output: " << S << '\n';
+ }
+}
+
+std::string llvm::getRuntimeMDYAMLString(Module &M) {
+ Program::Metadata Prog;
+ Prog.MDVersionSeq.push_back(MDVersion);
+ Prog.MDVersionSeq.push_back(MDRevision);
+
+ // Set PrintfInfo.
+ if (auto MD = M.getNamedMetadata("llvm.printf.fmts")) {
+ for (unsigned I = 0; I < MD->getNumOperands(); ++I) {
+ auto Node = MD->getOperand(I);
+ if (Node->getNumOperands() > 0)
+ Prog.PrintfInfo.push_back(cast<MDString>(Node->getOperand(0))
+ ->getString());
+ }
+ }
+
+ // Set Kernels.
+ for (auto &F: M.functions()) {
+ if (!F.getMetadata("kernel_arg_type"))
+ continue;
+ Prog.Kernels.emplace_back(getRuntimeMDForKernel(F));
+ }
+
+ auto YAML = Prog.toYAML();
+
+ if (DumpRuntimeMD)
+ llvm::errs() << "AMDGPU runtime metadata:\n" << YAML << '\n';
+
+ if (CheckRuntimeMDParser)
+ checkRuntimeMDYAMLString(YAML);
+
+ return YAML;
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.h b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.h
new file mode 100644
index 0000000..a92fdd4
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPURuntimeMD.h
@@ -0,0 +1,26 @@
+//===- AMDGPURuntimeMD.h - Generate runtime metadata ---------------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares functions for generating runtime metadata.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPURUNTIMEMD_H
+#define LLVM_LIB_TARGET_AMDGPU_MCTARGETDESC_AMDGPURUNTIMEMD_H
+
+#include <string>
+
+namespace llvm {
+class Module;
+
+// Get runtime metadata as YAML string.
+std::string getRuntimeMDYAMLString(Module &M);
+
+}
+#endif
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
index 83dcaac..3392183 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp
@@ -11,21 +11,33 @@
//
//===----------------------------------------------------------------------===//
+#include "AMDGPU.h"
#include "AMDGPUTargetStreamer.h"
#include "SIDefines.h"
#include "Utils/AMDGPUBaseInfo.h"
+#include "Utils/AMDKernelCodeTUtils.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/FormattedStream.h"
+#include "AMDGPURuntimeMD.h"
+
+namespace llvm {
+#include "AMDGPUPTNote.h"
+}
using namespace llvm;
+using namespace llvm::AMDGPU;
AMDGPUTargetStreamer::AMDGPUTargetStreamer(MCStreamer &S)
- : MCTargetStreamer(S) { }
+ : MCTargetStreamer(S) {}
//===----------------------------------------------------------------------===//
// AMDGPUTargetAsmStreamer
@@ -56,169 +68,9 @@ AMDGPUTargetAsmStreamer::EmitDirectiveHSACodeObjectISA(uint32_t Major,
void
AMDGPUTargetAsmStreamer::EmitAMDKernelCodeT(const amd_kernel_code_t &Header) {
- uint64_t ComputePgmRsrc2 = (Header.compute_pgm_resource_registers >> 32);
- bool EnableSGPRPrivateSegmentBuffer = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER);
- bool EnableSGPRDispatchPtr = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR);
- bool EnableSGPRQueuePtr = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR);
- bool EnableSGPRKernargSegmentPtr = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR);
- bool EnableSGPRDispatchID = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID);
- bool EnableSGPRFlatScratchInit = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT);
- bool EnableSGPRPrivateSegmentSize = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE);
- bool EnableSGPRGridWorkgroupCountX = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_GRID_WORKGROUP_COUNT_X);
- bool EnableSGPRGridWorkgroupCountY = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_GRID_WORKGROUP_COUNT_Y);
- bool EnableSGPRGridWorkgroupCountZ = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_SGPR_GRID_WORKGROUP_COUNT_Z);
- bool EnableOrderedAppendGDS = (Header.code_properties &
- AMD_CODE_PROPERTY_ENABLE_ORDERED_APPEND_GDS);
- uint32_t PrivateElementSize = (Header.code_properties &
- AMD_CODE_PROPERTY_PRIVATE_ELEMENT_SIZE) >>
- AMD_CODE_PROPERTY_PRIVATE_ELEMENT_SIZE_SHIFT;
- bool IsPtr64 = (Header.code_properties & AMD_CODE_PROPERTY_IS_PTR64);
- bool IsDynamicCallstack = (Header.code_properties &
- AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK);
- bool IsDebugEnabled = (Header.code_properties &
- AMD_CODE_PROPERTY_IS_DEBUG_SUPPORTED);
- bool IsXNackEnabled = (Header.code_properties &
- AMD_CODE_PROPERTY_IS_XNACK_SUPPORTED);
-
- OS << "\t.amd_kernel_code_t\n" <<
- "\t\tkernel_code_version_major = " <<
- Header.amd_kernel_code_version_major << '\n' <<
- "\t\tkernel_code_version_minor = " <<
- Header.amd_kernel_code_version_minor << '\n' <<
- "\t\tmachine_kind = " <<
- Header.amd_machine_kind << '\n' <<
- "\t\tmachine_version_major = " <<
- Header.amd_machine_version_major << '\n' <<
- "\t\tmachine_version_minor = " <<
- Header.amd_machine_version_minor << '\n' <<
- "\t\tmachine_version_stepping = " <<
- Header.amd_machine_version_stepping << '\n' <<
- "\t\tkernel_code_entry_byte_offset = " <<
- Header.kernel_code_entry_byte_offset << '\n' <<
- "\t\tkernel_code_prefetch_byte_size = " <<
- Header.kernel_code_prefetch_byte_size << '\n' <<
- "\t\tmax_scratch_backing_memory_byte_size = " <<
- Header.max_scratch_backing_memory_byte_size << '\n' <<
- "\t\tcompute_pgm_rsrc1_vgprs = " <<
- G_00B848_VGPRS(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_sgprs = " <<
- G_00B848_SGPRS(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_priority = " <<
- G_00B848_PRIORITY(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_float_mode = " <<
- G_00B848_FLOAT_MODE(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_priv = " <<
- G_00B848_PRIV(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_dx10_clamp = " <<
- G_00B848_DX10_CLAMP(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_debug_mode = " <<
- G_00B848_DEBUG_MODE(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc1_ieee_mode = " <<
- G_00B848_IEEE_MODE(Header.compute_pgm_resource_registers) << '\n' <<
- "\t\tcompute_pgm_rsrc2_scratch_en = " <<
- G_00B84C_SCRATCH_EN(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_user_sgpr = " <<
- G_00B84C_USER_SGPR(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_tgid_x_en = " <<
- G_00B84C_TGID_X_EN(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_tgid_y_en = " <<
- G_00B84C_TGID_Y_EN(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_tgid_z_en = " <<
- G_00B84C_TGID_Z_EN(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_tg_size_en = " <<
- G_00B84C_TG_SIZE_EN(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_tidig_comp_cnt = " <<
- G_00B84C_TIDIG_COMP_CNT(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_excp_en_msb = " <<
- G_00B84C_EXCP_EN_MSB(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_lds_size = " <<
- G_00B84C_LDS_SIZE(ComputePgmRsrc2) << '\n' <<
- "\t\tcompute_pgm_rsrc2_excp_en = " <<
- G_00B84C_EXCP_EN(ComputePgmRsrc2) << '\n' <<
-
- "\t\tenable_sgpr_private_segment_buffer = " <<
- EnableSGPRPrivateSegmentBuffer << '\n' <<
- "\t\tenable_sgpr_dispatch_ptr = " <<
- EnableSGPRDispatchPtr << '\n' <<
- "\t\tenable_sgpr_queue_ptr = " <<
- EnableSGPRQueuePtr << '\n' <<
- "\t\tenable_sgpr_kernarg_segment_ptr = " <<
- EnableSGPRKernargSegmentPtr << '\n' <<
- "\t\tenable_sgpr_dispatch_id = " <<
- EnableSGPRDispatchID << '\n' <<
- "\t\tenable_sgpr_flat_scratch_init = " <<
- EnableSGPRFlatScratchInit << '\n' <<
- "\t\tenable_sgpr_private_segment_size = " <<
- EnableSGPRPrivateSegmentSize << '\n' <<
- "\t\tenable_sgpr_grid_workgroup_count_x = " <<
- EnableSGPRGridWorkgroupCountX << '\n' <<
- "\t\tenable_sgpr_grid_workgroup_count_y = " <<
- EnableSGPRGridWorkgroupCountY << '\n' <<
- "\t\tenable_sgpr_grid_workgroup_count_z = " <<
- EnableSGPRGridWorkgroupCountZ << '\n' <<
- "\t\tenable_ordered_append_gds = " <<
- EnableOrderedAppendGDS << '\n' <<
- "\t\tprivate_element_size = " <<
- PrivateElementSize << '\n' <<
- "\t\tis_ptr64 = " <<
- IsPtr64 << '\n' <<
- "\t\tis_dynamic_callstack = " <<
- IsDynamicCallstack << '\n' <<
- "\t\tis_debug_enabled = " <<
- IsDebugEnabled << '\n' <<
- "\t\tis_xnack_enabled = " <<
- IsXNackEnabled << '\n' <<
- "\t\tworkitem_private_segment_byte_size = " <<
- Header.workitem_private_segment_byte_size << '\n' <<
- "\t\tworkgroup_group_segment_byte_size = " <<
- Header.workgroup_group_segment_byte_size << '\n' <<
- "\t\tgds_segment_byte_size = " <<
- Header.gds_segment_byte_size << '\n' <<
- "\t\tkernarg_segment_byte_size = " <<
- Header.kernarg_segment_byte_size << '\n' <<
- "\t\tworkgroup_fbarrier_count = " <<
- Header.workgroup_fbarrier_count << '\n' <<
- "\t\twavefront_sgpr_count = " <<
- Header.wavefront_sgpr_count << '\n' <<
- "\t\tworkitem_vgpr_count = " <<
- Header.workitem_vgpr_count << '\n' <<
- "\t\treserved_vgpr_first = " <<
- Header.reserved_vgpr_first << '\n' <<
- "\t\treserved_vgpr_count = " <<
- Header.reserved_vgpr_count << '\n' <<
- "\t\treserved_sgpr_first = " <<
- Header.reserved_sgpr_first << '\n' <<
- "\t\treserved_sgpr_count = " <<
- Header.reserved_sgpr_count << '\n' <<
- "\t\tdebug_wavefront_private_segment_offset_sgpr = " <<
- Header.debug_wavefront_private_segment_offset_sgpr << '\n' <<
- "\t\tdebug_private_segment_buffer_sgpr = " <<
- Header.debug_private_segment_buffer_sgpr << '\n' <<
- "\t\tkernarg_segment_alignment = " <<
- (uint32_t)Header.kernarg_segment_alignment << '\n' <<
- "\t\tgroup_segment_alignment = " <<
- (uint32_t)Header.group_segment_alignment << '\n' <<
- "\t\tprivate_segment_alignment = " <<
- (uint32_t)Header.private_segment_alignment << '\n' <<
- "\t\twavefront_size = " <<
- (uint32_t)Header.wavefront_size << '\n' <<
- "\t\tcall_convention = " <<
- Header.call_convention << '\n' <<
- "\t\truntime_loader_kernel_symbol = " <<
- Header.runtime_loader_kernel_symbol << '\n' <<
- // TODO: control_directives
- "\t.end_amd_kernel_code_t\n";
-
+ OS << "\t.amd_kernel_code_t\n";
+ dumpAmdKernelCode(&Header, OS, "\t\t");
+ OS << "\t.end_amd_kernel_code_t\n";
}
void AMDGPUTargetAsmStreamer::EmitAMDGPUSymbolType(StringRef SymbolName,
@@ -241,35 +93,63 @@ void AMDGPUTargetAsmStreamer::EmitAMDGPUHsaProgramScopeGlobal(
OS << "\t.amdgpu_hsa_program_global " << GlobalName << '\n';
}
+void AMDGPUTargetAsmStreamer::EmitRuntimeMetadata(Module &M) {
+ OS << "\t.amdgpu_runtime_metadata\n";
+ OS << getRuntimeMDYAMLString(M);
+ OS << "\n\t.end_amdgpu_runtime_metadata\n";
+}
+
+void AMDGPUTargetAsmStreamer::EmitRuntimeMetadata(StringRef Metadata) {
+ OS << "\t.amdgpu_runtime_metadata";
+ OS << Metadata;
+ OS << "\t.end_amdgpu_runtime_metadata\n";
+}
+
//===----------------------------------------------------------------------===//
// AMDGPUTargetELFStreamer
//===----------------------------------------------------------------------===//
AMDGPUTargetELFStreamer::AMDGPUTargetELFStreamer(MCStreamer &S)
- : AMDGPUTargetStreamer(S), Streamer(S) { }
+ : AMDGPUTargetStreamer(S), Streamer(S) {}
MCELFStreamer &AMDGPUTargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}
void
+AMDGPUTargetELFStreamer::EmitAMDGPUNote(const MCExpr* DescSZ,
+ PT_NOTE::NoteType Type,
+ std::function<void(MCELFStreamer &)> EmitDesc) {
+ auto &S = getStreamer();
+ auto &Context = S.getContext();
+
+ auto NameSZ = sizeof(PT_NOTE::NoteName);
+
+ S.PushSection();
+ S.SwitchSection(Context.getELFSection(
+ PT_NOTE::SectionName, ELF::SHT_NOTE, ELF::SHF_ALLOC));
+ S.EmitIntValue(NameSZ, 4); // namesz
+ S.EmitValue(DescSZ, 4); // descz
+ S.EmitIntValue(Type, 4); // type
+ S.EmitBytes(StringRef(PT_NOTE::NoteName, NameSZ)); // name
+ S.EmitValueToAlignment(4, 0, 1, 0); // padding 0
+ EmitDesc(S); // desc
+ S.EmitValueToAlignment(4, 0, 1, 0); // padding 0
+ S.PopSection();
+}
+
+void
AMDGPUTargetELFStreamer::EmitDirectiveHSACodeObjectVersion(uint32_t Major,
uint32_t Minor) {
- MCStreamer &OS = getStreamer();
- MCSectionELF *Note = OS.getContext().getELFSection(".note", ELF::SHT_NOTE, 0);
-
- unsigned NameSZ = 4;
- OS.PushSection();
- OS.SwitchSection(Note);
- OS.EmitIntValue(NameSZ, 4); // namesz
- OS.EmitIntValue(8, 4); // descz
- OS.EmitIntValue(NT_AMDGPU_HSA_CODE_OBJECT_VERSION, 4); // type
- OS.EmitBytes(StringRef("AMD", NameSZ)); // name
- OS.EmitIntValue(Major, 4); // desc
- OS.EmitIntValue(Minor, 4);
- OS.EmitValueToAlignment(4);
- OS.PopSection();
+ EmitAMDGPUNote(
+ MCConstantExpr::create(8, getContext()),
+ PT_NOTE::NT_AMDGPU_HSA_CODE_OBJECT_VERSION,
+ [&](MCELFStreamer &OS){
+ OS.EmitIntValue(Major, 4);
+ OS.EmitIntValue(Minor, 4);
+ }
+ );
}
void
@@ -278,33 +158,28 @@ AMDGPUTargetELFStreamer::EmitDirectiveHSACodeObjectISA(uint32_t Major,
uint32_t Stepping,
StringRef VendorName,
StringRef ArchName) {
- MCStreamer &OS = getStreamer();
- MCSectionELF *Note = OS.getContext().getELFSection(".note", ELF::SHT_NOTE, 0);
-
- unsigned NameSZ = 4;
uint16_t VendorNameSize = VendorName.size() + 1;
uint16_t ArchNameSize = ArchName.size() + 1;
+
unsigned DescSZ = sizeof(VendorNameSize) + sizeof(ArchNameSize) +
- sizeof(Major) + sizeof(Minor) + sizeof(Stepping) +
- VendorNameSize + ArchNameSize;
-
- OS.PushSection();
- OS.SwitchSection(Note);
- OS.EmitIntValue(NameSZ, 4); // namesz
- OS.EmitIntValue(DescSZ, 4); // descsz
- OS.EmitIntValue(NT_AMDGPU_HSA_ISA, 4); // type
- OS.EmitBytes(StringRef("AMD", 4)); // name
- OS.EmitIntValue(VendorNameSize, 2); // desc
- OS.EmitIntValue(ArchNameSize, 2);
- OS.EmitIntValue(Major, 4);
- OS.EmitIntValue(Minor, 4);
- OS.EmitIntValue(Stepping, 4);
- OS.EmitBytes(VendorName);
- OS.EmitIntValue(0, 1); // NULL terminate VendorName
- OS.EmitBytes(ArchName);
- OS.EmitIntValue(0, 1); // NULL terminte ArchName
- OS.EmitValueToAlignment(4);
- OS.PopSection();
+ sizeof(Major) + sizeof(Minor) + sizeof(Stepping) +
+ VendorNameSize + ArchNameSize;
+
+ EmitAMDGPUNote(
+ MCConstantExpr::create(DescSZ, getContext()),
+ PT_NOTE::NT_AMDGPU_HSA_ISA,
+ [&](MCELFStreamer &OS) {
+ OS.EmitIntValue(VendorNameSize, 2);
+ OS.EmitIntValue(ArchNameSize, 2);
+ OS.EmitIntValue(Major, 4);
+ OS.EmitIntValue(Minor, 4);
+ OS.EmitIntValue(Stepping, 4);
+ OS.EmitBytes(VendorName);
+ OS.EmitIntValue(0, 1); // NULL terminate VendorName
+ OS.EmitBytes(ArchName);
+ OS.EmitIntValue(0, 1); // NULL terminte ArchName
+ }
+ );
}
void
@@ -340,3 +215,28 @@ void AMDGPUTargetELFStreamer::EmitAMDGPUHsaProgramScopeGlobal(
Symbol->setType(ELF::STT_OBJECT);
Symbol->setBinding(ELF::STB_GLOBAL);
}
+
+void AMDGPUTargetELFStreamer::EmitRuntimeMetadata(StringRef Metadata) {
+ // Create two labels to mark the beginning and end of the desc field
+ // and a MCExpr to calculate the size of the desc field.
+ auto &Context = getContext();
+ auto *DescBegin = Context.createTempSymbol();
+ auto *DescEnd = Context.createTempSymbol();
+ auto *DescSZ = MCBinaryExpr::createSub(
+ MCSymbolRefExpr::create(DescEnd, Context),
+ MCSymbolRefExpr::create(DescBegin, Context), Context);
+
+ EmitAMDGPUNote(
+ DescSZ,
+ PT_NOTE::NT_AMDGPU_HSA_RUNTIME_METADATA,
+ [&](MCELFStreamer &OS) {
+ OS.EmitLabel(DescBegin);
+ OS.EmitBytes(Metadata);
+ OS.EmitLabel(DescEnd);
+ }
+ );
+}
+
+void AMDGPUTargetELFStreamer::EmitRuntimeMetadata(Module &M) {
+ EmitRuntimeMetadata(getRuntimeMDYAMLString(M));
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h
index b3d59e8..e2f2058 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h
@@ -14,11 +14,20 @@
#include "llvm/MC/MCStreamer.h"
namespace llvm {
+#include "AMDGPUPTNote.h"
+class DataLayout;
+class Function;
class MCELFStreamer;
class MCSymbol;
+class MDNode;
+class Module;
+class Type;
class AMDGPUTargetStreamer : public MCTargetStreamer {
+protected:
+ MCContext &getContext() const { return Streamer.getContext(); }
+
public:
AMDGPUTargetStreamer(MCStreamer &S);
virtual void EmitDirectiveHSACodeObjectVersion(uint32_t Major,
@@ -36,6 +45,10 @@ public:
virtual void EmitAMDGPUHsaModuleScopeGlobal(StringRef GlobalName) = 0;
virtual void EmitAMDGPUHsaProgramScopeGlobal(StringRef GlobalName) = 0;
+
+ virtual void EmitRuntimeMetadata(Module &M) = 0;
+
+ virtual void EmitRuntimeMetadata(StringRef Metadata) = 0;
};
class AMDGPUTargetAsmStreamer : public AMDGPUTargetStreamer {
@@ -56,23 +69,19 @@ public:
void EmitAMDGPUHsaModuleScopeGlobal(StringRef GlobalName) override;
void EmitAMDGPUHsaProgramScopeGlobal(StringRef GlobalName) override;
-};
-class AMDGPUTargetELFStreamer : public AMDGPUTargetStreamer {
+ void EmitRuntimeMetadata(Module &M) override;
- enum NoteType {
- NT_AMDGPU_HSA_CODE_OBJECT_VERSION = 1,
- NT_AMDGPU_HSA_HSAIL = 2,
- NT_AMDGPU_HSA_ISA = 3,
- NT_AMDGPU_HSA_PRODUCER = 4,
- NT_AMDGPU_HSA_PRODUCER_OPTIONS = 5,
- NT_AMDGPU_HSA_EXTENSION = 6,
- NT_AMDGPU_HSA_HLDEBUG_DEBUG = 101,
- NT_AMDGPU_HSA_HLDEBUG_TARGET = 102
- };
+ void EmitRuntimeMetadata(StringRef Metadata) override;
+};
+class AMDGPUTargetELFStreamer : public AMDGPUTargetStreamer {
MCStreamer &Streamer;
+ void EmitAMDGPUNote(const MCExpr* DescSize,
+ AMDGPU::PT_NOTE::NoteType Type,
+ std::function<void(MCELFStreamer &)> EmitDesc);
+
public:
AMDGPUTargetELFStreamer(MCStreamer &S);
@@ -92,6 +101,10 @@ public:
void EmitAMDGPUHsaModuleScopeGlobal(StringRef GlobalName) override;
void EmitAMDGPUHsaProgramScopeGlobal(StringRef GlobalName) override;
+
+ void EmitRuntimeMetadata(Module &M) override;
+
+ void EmitRuntimeMetadata(StringRef Metadata) override;
};
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp
index 5e8e6ce..6015ec1 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/R600MCCodeEmitter.cpp
@@ -20,26 +20,30 @@
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
using namespace llvm;
namespace {
class R600MCCodeEmitter : public AMDGPUMCCodeEmitter {
- R600MCCodeEmitter(const R600MCCodeEmitter &) = delete;
- void operator=(const R600MCCodeEmitter &) = delete;
- const MCInstrInfo &MCII;
const MCRegisterInfo &MRI;
public:
R600MCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri)
- : MCII(mcii), MRI(mri) { }
+ : AMDGPUMCCodeEmitter(mcii), MRI(mri) {}
+ R600MCCodeEmitter(const R600MCCodeEmitter &) = delete;
+ R600MCCodeEmitter &operator=(const R600MCCodeEmitter &) = delete;
/// \brief Encode the instruction and write it to the OS.
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
@@ -58,7 +62,7 @@ private:
unsigned getHWReg(unsigned regNo) const;
};
-} // End anonymous namespace
+} // end anonymous namespace
enum RegElement {
ELEMENT_X = 0,
@@ -86,6 +90,9 @@ MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII,
void R600MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
if (MI.getOpcode() == AMDGPU::RETURN ||
MI.getOpcode() == AMDGPU::FETCH_CLAUSE ||
@@ -178,4 +185,5 @@ uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI,
return MO.getImm();
}
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "AMDGPUGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
index 71b585c..0c5bb06 100644
--- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp
@@ -1,4 +1,4 @@
-//===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===//
+//===-- SIMCCodeEmitter.cpp - SI Code Emitter -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -17,38 +17,42 @@
#include "MCTargetDesc/AMDGPUFixupKinds.h"
#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
-#include "SIDefines.h"
+#include "Utils/AMDGPUBaseInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
using namespace llvm;
namespace {
class SIMCCodeEmitter : public AMDGPUMCCodeEmitter {
- SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
- void operator=(const SIMCCodeEmitter &) = delete;
- const MCInstrInfo &MCII;
const MCRegisterInfo &MRI;
- /// \brief Can this operand also contain immediate values?
- bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
-
/// \brief Encode an fp or int literal
- uint32_t getLitEncoding(const MCOperand &MO, unsigned OpSize) const;
+ uint32_t getLitEncoding(const MCOperand &MO, const MCOperandInfo &OpInfo,
+ const MCSubtargetInfo &STI) const;
public:
SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
MCContext &ctx)
- : MCII(mcii), MRI(mri) { }
-
- ~SIMCCodeEmitter() override {}
+ : AMDGPUMCCodeEmitter(mcii), MRI(mri) {}
+ SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
+ SIMCCodeEmitter &operator=(const SIMCCodeEmitter &) = delete;
/// \brief Encode the instruction and write it to the OS.
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
@@ -67,7 +71,7 @@ public:
const MCSubtargetInfo &STI) const override;
};
-} // End anonymous namespace
+} // end anonymous namespace
MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
@@ -75,14 +79,6 @@ MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
return new SIMCCodeEmitter(MCII, MRI, Ctx);
}
-bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
- unsigned OpNo) const {
- unsigned OpType = Desc.OpInfo[OpNo].OperandType;
-
- return OpType == AMDGPU::OPERAND_REG_IMM32 ||
- OpType == AMDGPU::OPERAND_REG_INLINE_C;
-}
-
// Returns the encoding value to use if the given integer is an integer inline
// immediate value, or 0 if it is not.
template <typename IntTy>
@@ -96,7 +92,43 @@ static uint32_t getIntInlineImmEncoding(IntTy Imm) {
return 0;
}
-static uint32_t getLit32Encoding(uint32_t Val) {
+static uint32_t getLit16Encoding(uint16_t Val, const MCSubtargetInfo &STI) {
+ uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
+ if (IntImm != 0)
+ return IntImm;
+
+ if (Val == 0x3800) // 0.5
+ return 240;
+
+ if (Val == 0xB800) // -0.5
+ return 241;
+
+ if (Val == 0x3C00) // 1.0
+ return 242;
+
+ if (Val == 0xBC00) // -1.0
+ return 243;
+
+ if (Val == 0x4000) // 2.0
+ return 244;
+
+ if (Val == 0xC000) // -2.0
+ return 245;
+
+ if (Val == 0x4400) // 4.0
+ return 246;
+
+ if (Val == 0xC400) // -4.0
+ return 247;
+
+ if (Val == 0x3118 && // 1.0 / (2.0 * pi)
+ STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
+ return 248;
+
+ return 255;
+}
+
+static uint32_t getLit32Encoding(uint32_t Val, const MCSubtargetInfo &STI) {
uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
if (IntImm != 0)
return IntImm;
@@ -125,10 +157,14 @@ static uint32_t getLit32Encoding(uint32_t Val) {
if (Val == FloatToBits(-4.0f))
return 247;
+ if (Val == 0x3e22f983 && // 1.0 / (2.0 * pi)
+ STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
+ return 248;
+
return 255;
}
-static uint32_t getLit64Encoding(uint64_t Val) {
+static uint32_t getLit64Encoding(uint64_t Val, const MCSubtargetInfo &STI) {
uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
if (IntImm != 0)
return IntImm;
@@ -157,15 +193,19 @@ static uint32_t getLit64Encoding(uint64_t Val) {
if (Val == DoubleToBits(-4.0))
return 247;
+ if (Val == 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
+ STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
+ return 248;
+
return 255;
}
uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
- unsigned OpSize) const {
-
+ const MCOperandInfo &OpInfo,
+ const MCSubtargetInfo &STI) const {
int64_t Imm;
if (MO.isExpr()) {
- const MCConstantExpr *C = dyn_cast<MCConstantExpr>(MO.getExpr());
+ const auto *C = dyn_cast<MCConstantExpr>(MO.getExpr());
if (!C)
return 255;
@@ -180,17 +220,23 @@ uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
Imm = MO.getImm();
}
- if (OpSize == 4)
- return getLit32Encoding(static_cast<uint32_t>(Imm));
-
- assert(OpSize == 8);
-
- return getLit64Encoding(static_cast<uint64_t>(Imm));
+ switch (AMDGPU::getOperandSize(OpInfo)) {
+ case 4:
+ return getLit32Encoding(static_cast<uint32_t>(Imm), STI);
+ case 8:
+ return getLit64Encoding(static_cast<uint64_t>(Imm), STI);
+ case 2:
+ return getLit16Encoding(static_cast<uint16_t>(Imm), STI);
+ default:
+ llvm_unreachable("invalid operand size");
+ }
}
void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
@@ -207,15 +253,12 @@ void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
// Check if this operand should be encoded as [SV]Src
- if (!isSrcOperand(Desc, i))
+ if (!AMDGPU::isSISrcOperand(Desc, i))
continue;
- int RCID = Desc.OpInfo[i].RegClass;
- const MCRegisterClass &RC = MRI.getRegClass(RCID);
-
// Is this operand a literal immediate?
const MCOperand &Op = MI.getOperand(i);
- if (getLitEncoding(Op, RC.getSize()) != 255)
+ if (getLitEncoding(Op, Desc.OpInfo[i], STI) != 255)
continue;
// Yes! Encode it
@@ -224,7 +267,7 @@ void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
if (Op.isImm())
Imm = Op.getImm();
else if (Op.isExpr()) {
- if (const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Op.getExpr()))
+ if (const auto *C = dyn_cast<MCConstantExpr>(Op.getExpr()))
Imm = C->getValue();
} else if (!Op.isExpr()) // Exprs will be replaced with a fixup value.
@@ -262,7 +305,7 @@ uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
return MRI.getEncodingValue(MO.getReg());
if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) {
- const MCSymbolRefExpr *Expr = dyn_cast<MCSymbolRefExpr>(MO.getExpr());
+ const auto *Expr = dyn_cast<MCSymbolRefExpr>(MO.getExpr());
MCFixupKind Kind;
if (Expr && Expr->getSymbol().isExternal())
Kind = FK_Data_4;
@@ -279,11 +322,8 @@ uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
}
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
- if (isSrcOperand(Desc, OpNo)) {
- int RCID = Desc.OpInfo[OpNo].RegClass;
- const MCRegisterClass &RC = MRI.getRegClass(RCID);
-
- uint32_t Enc = getLitEncoding(MO, RC.getSize());
+ if (AMDGPU::isSISrcOperand(Desc, OpNo)) {
+ uint32_t Enc = getLitEncoding(MO, Desc.OpInfo[OpNo], STI);
if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
return Enc;
@@ -293,4 +333,3 @@ uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
llvm_unreachable("Encoding of this operand type is not supported yet.");
return 0;
}
-
diff --git a/contrib/llvm/lib/Target/AMDGPU/MIMGInstructions.td b/contrib/llvm/lib/Target/AMDGPU/MIMGInstructions.td
new file mode 100644
index 0000000..46803e5
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/MIMGInstructions.td
@@ -0,0 +1,763 @@
+//===-- MIMGInstructions.td - MIMG Instruction Defintions -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+class MIMG_Mask <string op, int channels> {
+ string Op = op;
+ int Channels = channels;
+}
+
+class mimg <bits<7> si, bits<7> vi = si> {
+ field bits<7> SI = si;
+ field bits<7> VI = vi;
+}
+
+class MIMG_Helper <dag outs, dag ins, string asm,
+ string dns=""> : MIMG<outs, ins, asm,[]> {
+ let mayLoad = 1;
+ let mayStore = 0;
+ let hasPostISelHook = 1;
+ let DecoderNamespace = dns;
+ let isAsmParserOnly = !if(!eq(dns,""), 1, 0);
+ let AsmMatchConverter = "cvtMIMG";
+ let usesCustomInserter = 1;
+}
+
+class MIMG_NoSampler_Helper <bits<7> op, string asm,
+ RegisterClass dst_rc,
+ RegisterClass addr_rc,
+ string dns=""> : MIMG_Helper <
+ (outs dst_rc:$vdata),
+ (ins addr_rc:$vaddr, SReg_256:$srsrc,
+ dmask:$dmask, unorm:$unorm, GLC:$glc, slc:$slc,
+ r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
+ asm#" $vdata, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da",
+ dns>, MIMGe<op> {
+ let ssamp = 0;
+}
+
+multiclass MIMG_NoSampler_Src_Helper <bits<7> op, string asm,
+ RegisterClass dst_rc,
+ int channels> {
+ def _V1 : MIMG_NoSampler_Helper <op, asm, dst_rc, VGPR_32,
+ !if(!eq(channels, 1), "AMDGPU", "")>,
+ MIMG_Mask<asm#"_V1", channels>;
+ def _V2 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_64>,
+ MIMG_Mask<asm#"_V2", channels>;
+ def _V4 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_128>,
+ MIMG_Mask<asm#"_V4", channels>;
+}
+
+multiclass MIMG_NoSampler <bits<7> op, string asm> {
+ defm _V1 : MIMG_NoSampler_Src_Helper <op, asm, VGPR_32, 1>;
+ defm _V2 : MIMG_NoSampler_Src_Helper <op, asm, VReg_64, 2>;
+ defm _V3 : MIMG_NoSampler_Src_Helper <op, asm, VReg_96, 3>;
+ defm _V4 : MIMG_NoSampler_Src_Helper <op, asm, VReg_128, 4>;
+}
+
+class MIMG_Store_Helper <bits<7> op, string asm,
+ RegisterClass data_rc,
+ RegisterClass addr_rc> : MIMG_Helper <
+ (outs),
+ (ins data_rc:$vdata, addr_rc:$vaddr, SReg_256:$srsrc,
+ dmask:$dmask, unorm:$unorm, GLC:$glc, slc:$slc,
+ r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
+ asm#" $vdata, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da"
+ >, MIMGe<op> {
+ let ssamp = 0;
+ let mayLoad = 1; // TableGen requires this for matching with the intrinsics
+ let mayStore = 1;
+ let hasSideEffects = 1;
+ let hasPostISelHook = 0;
+ let DisableWQM = 1;
+}
+
+multiclass MIMG_Store_Addr_Helper <bits<7> op, string asm,
+ RegisterClass data_rc,
+ int channels> {
+ def _V1 : MIMG_Store_Helper <op, asm, data_rc, VGPR_32>,
+ MIMG_Mask<asm#"_V1", channels>;
+ def _V2 : MIMG_Store_Helper <op, asm, data_rc, VReg_64>,
+ MIMG_Mask<asm#"_V2", channels>;
+ def _V4 : MIMG_Store_Helper <op, asm, data_rc, VReg_128>,
+ MIMG_Mask<asm#"_V4", channels>;
+}
+
+multiclass MIMG_Store <bits<7> op, string asm> {
+ defm _V1 : MIMG_Store_Addr_Helper <op, asm, VGPR_32, 1>;
+ defm _V2 : MIMG_Store_Addr_Helper <op, asm, VReg_64, 2>;
+ defm _V3 : MIMG_Store_Addr_Helper <op, asm, VReg_96, 3>;
+ defm _V4 : MIMG_Store_Addr_Helper <op, asm, VReg_128, 4>;
+}
+
+class MIMG_Atomic_Helper <string asm, RegisterClass data_rc,
+ RegisterClass addr_rc> : MIMG_Helper <
+ (outs data_rc:$vdst),
+ (ins data_rc:$vdata, addr_rc:$vaddr, SReg_256:$srsrc,
+ dmask:$dmask, unorm:$unorm, GLC:$glc, slc:$slc,
+ r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
+ asm#" $vdst, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da"
+ > {
+ let mayStore = 1;
+ let hasSideEffects = 1;
+ let hasPostISelHook = 0;
+ let DisableWQM = 1;
+ let Constraints = "$vdst = $vdata";
+ let AsmMatchConverter = "cvtMIMGAtomic";
+}
+
+class MIMG_Atomic_Real_si<mimg op, string name, string asm,
+ RegisterClass data_rc, RegisterClass addr_rc> :
+ MIMG_Atomic_Helper<asm, data_rc, addr_rc>,
+ SIMCInstr<name, SIEncodingFamily.SI>,
+ MIMGe<op.SI> {
+ let isCodeGenOnly = 0;
+ let AssemblerPredicates = [isSICI];
+ let DecoderNamespace = "SICI";
+ let DisableDecoder = DisableSIDecoder;
+}
+
+class MIMG_Atomic_Real_vi<mimg op, string name, string asm,
+ RegisterClass data_rc, RegisterClass addr_rc> :
+ MIMG_Atomic_Helper<asm, data_rc, addr_rc>,
+ SIMCInstr<name, SIEncodingFamily.VI>,
+ MIMGe<op.VI> {
+ let isCodeGenOnly = 0;
+ let AssemblerPredicates = [isVI];
+ let DecoderNamespace = "VI";
+ let DisableDecoder = DisableVIDecoder;
+}
+
+multiclass MIMG_Atomic_Helper_m <mimg op, string name, string asm,
+ RegisterClass data_rc, RegisterClass addr_rc> {
+ let isPseudo = 1, isCodeGenOnly = 1 in {
+ def "" : MIMG_Atomic_Helper<asm, data_rc, addr_rc>,
+ SIMCInstr<name, SIEncodingFamily.NONE>;
+ }
+
+ let ssamp = 0 in {
+ def _si : MIMG_Atomic_Real_si<op, name, asm, data_rc, addr_rc>;
+
+ def _vi : MIMG_Atomic_Real_vi<op, name, asm, data_rc, addr_rc>;
+ }
+}
+
+multiclass MIMG_Atomic <mimg op, string asm, RegisterClass data_rc = VGPR_32> {
+ defm _V1 : MIMG_Atomic_Helper_m <op, asm # "_V1", asm, data_rc, VGPR_32>;
+ defm _V2 : MIMG_Atomic_Helper_m <op, asm # "_V2", asm, data_rc, VReg_64>;
+ defm _V4 : MIMG_Atomic_Helper_m <op, asm # "_V3", asm, data_rc, VReg_128>;
+}
+
+class MIMG_Sampler_Helper <bits<7> op, string asm,
+ RegisterClass dst_rc,
+ RegisterClass src_rc,
+ bit wqm,
+ string dns=""> : MIMG_Helper <
+ (outs dst_rc:$vdata),
+ (ins src_rc:$vaddr, SReg_256:$srsrc, SReg_128:$ssamp,
+ dmask:$dmask, unorm:$unorm, GLC:$glc, slc:$slc,
+ r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
+ asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$glc$slc$r128$tfe$lwe$da",
+ dns>, MIMGe<op> {
+ let WQM = wqm;
+}
+
+multiclass MIMG_Sampler_Src_Helper <bits<7> op, string asm,
+ RegisterClass dst_rc,
+ int channels, bit wqm> {
+ def _V1 : MIMG_Sampler_Helper <op, asm, dst_rc, VGPR_32, wqm,
+ !if(!eq(channels, 1), "AMDGPU", "")>,
+ MIMG_Mask<asm#"_V1", channels>;
+ def _V2 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_64, wqm>,
+ MIMG_Mask<asm#"_V2", channels>;
+ def _V4 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_128, wqm>,
+ MIMG_Mask<asm#"_V4", channels>;
+ def _V8 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_256, wqm>,
+ MIMG_Mask<asm#"_V8", channels>;
+ def _V16 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_512, wqm>,
+ MIMG_Mask<asm#"_V16", channels>;
+}
+
+multiclass MIMG_Sampler <bits<7> op, string asm, bit wqm=0> {
+ defm _V1 : MIMG_Sampler_Src_Helper<op, asm, VGPR_32, 1, wqm>;
+ defm _V2 : MIMG_Sampler_Src_Helper<op, asm, VReg_64, 2, wqm>;
+ defm _V3 : MIMG_Sampler_Src_Helper<op, asm, VReg_96, 3, wqm>;
+ defm _V4 : MIMG_Sampler_Src_Helper<op, asm, VReg_128, 4, wqm>;
+}
+
+multiclass MIMG_Sampler_WQM <bits<7> op, string asm> : MIMG_Sampler<op, asm, 1>;
+
+class MIMG_Gather_Helper <bits<7> op, string asm,
+ RegisterClass dst_rc,
+ RegisterClass src_rc, bit wqm> : MIMG <
+ (outs dst_rc:$vdata),
+ (ins src_rc:$vaddr, SReg_256:$srsrc, SReg_128:$ssamp,
+ dmask:$dmask, unorm:$unorm, GLC:$glc, slc:$slc,
+ r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
+ asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$glc$slc$r128$tfe$lwe$da",
+ []>, MIMGe<op> {
+ let mayLoad = 1;
+ let mayStore = 0;
+
+ // DMASK was repurposed for GATHER4. 4 components are always
+ // returned and DMASK works like a swizzle - it selects
+ // the component to fetch. The only useful DMASK values are
+ // 1=red, 2=green, 4=blue, 8=alpha. (e.g. 1 returns
+ // (red,red,red,red) etc.) The ISA document doesn't mention
+ // this.
+ // Therefore, disable all code which updates DMASK by setting this:
+ let Gather4 = 1;
+ let hasPostISelHook = 0;
+ let WQM = wqm;
+
+ let isAsmParserOnly = 1; // TBD: fix it later
+}
+
+multiclass MIMG_Gather_Src_Helper <bits<7> op, string asm,
+ RegisterClass dst_rc,
+ int channels, bit wqm> {
+ def _V1 : MIMG_Gather_Helper <op, asm, dst_rc, VGPR_32, wqm>,
+ MIMG_Mask<asm#"_V1", channels>;
+ def _V2 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_64, wqm>,
+ MIMG_Mask<asm#"_V2", channels>;
+ def _V4 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_128, wqm>,
+ MIMG_Mask<asm#"_V4", channels>;
+ def _V8 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_256, wqm>,
+ MIMG_Mask<asm#"_V8", channels>;
+ def _V16 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_512, wqm>,
+ MIMG_Mask<asm#"_V16", channels>;
+}
+
+multiclass MIMG_Gather <bits<7> op, string asm, bit wqm=0> {
+ defm _V1 : MIMG_Gather_Src_Helper<op, asm, VGPR_32, 1, wqm>;
+ defm _V2 : MIMG_Gather_Src_Helper<op, asm, VReg_64, 2, wqm>;
+ defm _V3 : MIMG_Gather_Src_Helper<op, asm, VReg_96, 3, wqm>;
+ defm _V4 : MIMG_Gather_Src_Helper<op, asm, VReg_128, 4, wqm>;
+}
+
+multiclass MIMG_Gather_WQM <bits<7> op, string asm> : MIMG_Gather<op, asm, 1>;
+
+//===----------------------------------------------------------------------===//
+// MIMG Instructions
+//===----------------------------------------------------------------------===//
+let SubtargetPredicate = isGCN in {
+defm IMAGE_LOAD : MIMG_NoSampler <0x00000000, "image_load">;
+defm IMAGE_LOAD_MIP : MIMG_NoSampler <0x00000001, "image_load_mip">;
+//def IMAGE_LOAD_PCK : MIMG_NoPattern_ <"image_load_pck", 0x00000002>;
+//def IMAGE_LOAD_PCK_SGN : MIMG_NoPattern_ <"image_load_pck_sgn", 0x00000003>;
+//def IMAGE_LOAD_MIP_PCK : MIMG_NoPattern_ <"image_load_mip_pck", 0x00000004>;
+//def IMAGE_LOAD_MIP_PCK_SGN : MIMG_NoPattern_ <"image_load_mip_pck_sgn", 0x00000005>;
+defm IMAGE_STORE : MIMG_Store <0x00000008, "image_store">;
+defm IMAGE_STORE_MIP : MIMG_Store <0x00000009, "image_store_mip">;
+//def IMAGE_STORE_PCK : MIMG_NoPattern_ <"image_store_pck", 0x0000000a>;
+//def IMAGE_STORE_MIP_PCK : MIMG_NoPattern_ <"image_store_mip_pck", 0x0000000b>;
+defm IMAGE_GET_RESINFO : MIMG_NoSampler <0x0000000e, "image_get_resinfo">;
+defm IMAGE_ATOMIC_SWAP : MIMG_Atomic <mimg<0x0f, 0x10>, "image_atomic_swap">;
+defm IMAGE_ATOMIC_CMPSWAP : MIMG_Atomic <mimg<0x10, 0x11>, "image_atomic_cmpswap", VReg_64>;
+defm IMAGE_ATOMIC_ADD : MIMG_Atomic <mimg<0x11, 0x12>, "image_atomic_add">;
+defm IMAGE_ATOMIC_SUB : MIMG_Atomic <mimg<0x12, 0x13>, "image_atomic_sub">;
+//def IMAGE_ATOMIC_RSUB : MIMG_NoPattern_ <"image_atomic_rsub", 0x00000013>; -- not on VI
+defm IMAGE_ATOMIC_SMIN : MIMG_Atomic <mimg<0x14>, "image_atomic_smin">;
+defm IMAGE_ATOMIC_UMIN : MIMG_Atomic <mimg<0x15>, "image_atomic_umin">;
+defm IMAGE_ATOMIC_SMAX : MIMG_Atomic <mimg<0x16>, "image_atomic_smax">;
+defm IMAGE_ATOMIC_UMAX : MIMG_Atomic <mimg<0x17>, "image_atomic_umax">;
+defm IMAGE_ATOMIC_AND : MIMG_Atomic <mimg<0x18>, "image_atomic_and">;
+defm IMAGE_ATOMIC_OR : MIMG_Atomic <mimg<0x19>, "image_atomic_or">;
+defm IMAGE_ATOMIC_XOR : MIMG_Atomic <mimg<0x1a>, "image_atomic_xor">;
+defm IMAGE_ATOMIC_INC : MIMG_Atomic <mimg<0x1b>, "image_atomic_inc">;
+defm IMAGE_ATOMIC_DEC : MIMG_Atomic <mimg<0x1c>, "image_atomic_dec">;
+//def IMAGE_ATOMIC_FCMPSWAP : MIMG_NoPattern_ <"image_atomic_fcmpswap", 0x0000001d>; -- not on VI
+//def IMAGE_ATOMIC_FMIN : MIMG_NoPattern_ <"image_atomic_fmin", 0x0000001e>; -- not on VI
+//def IMAGE_ATOMIC_FMAX : MIMG_NoPattern_ <"image_atomic_fmax", 0x0000001f>; -- not on VI
+defm IMAGE_SAMPLE : MIMG_Sampler_WQM <0x00000020, "image_sample">;
+defm IMAGE_SAMPLE_CL : MIMG_Sampler_WQM <0x00000021, "image_sample_cl">;
+defm IMAGE_SAMPLE_D : MIMG_Sampler <0x00000022, "image_sample_d">;
+defm IMAGE_SAMPLE_D_CL : MIMG_Sampler <0x00000023, "image_sample_d_cl">;
+defm IMAGE_SAMPLE_L : MIMG_Sampler <0x00000024, "image_sample_l">;
+defm IMAGE_SAMPLE_B : MIMG_Sampler_WQM <0x00000025, "image_sample_b">;
+defm IMAGE_SAMPLE_B_CL : MIMG_Sampler_WQM <0x00000026, "image_sample_b_cl">;
+defm IMAGE_SAMPLE_LZ : MIMG_Sampler <0x00000027, "image_sample_lz">;
+defm IMAGE_SAMPLE_C : MIMG_Sampler_WQM <0x00000028, "image_sample_c">;
+defm IMAGE_SAMPLE_C_CL : MIMG_Sampler_WQM <0x00000029, "image_sample_c_cl">;
+defm IMAGE_SAMPLE_C_D : MIMG_Sampler <0x0000002a, "image_sample_c_d">;
+defm IMAGE_SAMPLE_C_D_CL : MIMG_Sampler <0x0000002b, "image_sample_c_d_cl">;
+defm IMAGE_SAMPLE_C_L : MIMG_Sampler <0x0000002c, "image_sample_c_l">;
+defm IMAGE_SAMPLE_C_B : MIMG_Sampler_WQM <0x0000002d, "image_sample_c_b">;
+defm IMAGE_SAMPLE_C_B_CL : MIMG_Sampler_WQM <0x0000002e, "image_sample_c_b_cl">;
+defm IMAGE_SAMPLE_C_LZ : MIMG_Sampler <0x0000002f, "image_sample_c_lz">;
+defm IMAGE_SAMPLE_O : MIMG_Sampler_WQM <0x00000030, "image_sample_o">;
+defm IMAGE_SAMPLE_CL_O : MIMG_Sampler_WQM <0x00000031, "image_sample_cl_o">;
+defm IMAGE_SAMPLE_D_O : MIMG_Sampler <0x00000032, "image_sample_d_o">;
+defm IMAGE_SAMPLE_D_CL_O : MIMG_Sampler <0x00000033, "image_sample_d_cl_o">;
+defm IMAGE_SAMPLE_L_O : MIMG_Sampler <0x00000034, "image_sample_l_o">;
+defm IMAGE_SAMPLE_B_O : MIMG_Sampler_WQM <0x00000035, "image_sample_b_o">;
+defm IMAGE_SAMPLE_B_CL_O : MIMG_Sampler_WQM <0x00000036, "image_sample_b_cl_o">;
+defm IMAGE_SAMPLE_LZ_O : MIMG_Sampler <0x00000037, "image_sample_lz_o">;
+defm IMAGE_SAMPLE_C_O : MIMG_Sampler_WQM <0x00000038, "image_sample_c_o">;
+defm IMAGE_SAMPLE_C_CL_O : MIMG_Sampler_WQM <0x00000039, "image_sample_c_cl_o">;
+defm IMAGE_SAMPLE_C_D_O : MIMG_Sampler <0x0000003a, "image_sample_c_d_o">;
+defm IMAGE_SAMPLE_C_D_CL_O : MIMG_Sampler <0x0000003b, "image_sample_c_d_cl_o">;
+defm IMAGE_SAMPLE_C_L_O : MIMG_Sampler <0x0000003c, "image_sample_c_l_o">;
+defm IMAGE_SAMPLE_C_B_O : MIMG_Sampler_WQM <0x0000003d, "image_sample_c_b_o">;
+defm IMAGE_SAMPLE_C_B_CL_O : MIMG_Sampler_WQM <0x0000003e, "image_sample_c_b_cl_o">;
+defm IMAGE_SAMPLE_C_LZ_O : MIMG_Sampler <0x0000003f, "image_sample_c_lz_o">;
+defm IMAGE_GATHER4 : MIMG_Gather_WQM <0x00000040, "image_gather4">;
+defm IMAGE_GATHER4_CL : MIMG_Gather_WQM <0x00000041, "image_gather4_cl">;
+defm IMAGE_GATHER4_L : MIMG_Gather <0x00000044, "image_gather4_l">;
+defm IMAGE_GATHER4_B : MIMG_Gather_WQM <0x00000045, "image_gather4_b">;
+defm IMAGE_GATHER4_B_CL : MIMG_Gather_WQM <0x00000046, "image_gather4_b_cl">;
+defm IMAGE_GATHER4_LZ : MIMG_Gather <0x00000047, "image_gather4_lz">;
+defm IMAGE_GATHER4_C : MIMG_Gather_WQM <0x00000048, "image_gather4_c">;
+defm IMAGE_GATHER4_C_CL : MIMG_Gather_WQM <0x00000049, "image_gather4_c_cl">;
+defm IMAGE_GATHER4_C_L : MIMG_Gather <0x0000004c, "image_gather4_c_l">;
+defm IMAGE_GATHER4_C_B : MIMG_Gather_WQM <0x0000004d, "image_gather4_c_b">;
+defm IMAGE_GATHER4_C_B_CL : MIMG_Gather_WQM <0x0000004e, "image_gather4_c_b_cl">;
+defm IMAGE_GATHER4_C_LZ : MIMG_Gather <0x0000004f, "image_gather4_c_lz">;
+defm IMAGE_GATHER4_O : MIMG_Gather_WQM <0x00000050, "image_gather4_o">;
+defm IMAGE_GATHER4_CL_O : MIMG_Gather_WQM <0x00000051, "image_gather4_cl_o">;
+defm IMAGE_GATHER4_L_O : MIMG_Gather <0x00000054, "image_gather4_l_o">;
+defm IMAGE_GATHER4_B_O : MIMG_Gather_WQM <0x00000055, "image_gather4_b_o">;
+defm IMAGE_GATHER4_B_CL_O : MIMG_Gather <0x00000056, "image_gather4_b_cl_o">;
+defm IMAGE_GATHER4_LZ_O : MIMG_Gather <0x00000057, "image_gather4_lz_o">;
+defm IMAGE_GATHER4_C_O : MIMG_Gather_WQM <0x00000058, "image_gather4_c_o">;
+defm IMAGE_GATHER4_C_CL_O : MIMG_Gather_WQM <0x00000059, "image_gather4_c_cl_o">;
+defm IMAGE_GATHER4_C_L_O : MIMG_Gather <0x0000005c, "image_gather4_c_l_o">;
+defm IMAGE_GATHER4_C_B_O : MIMG_Gather_WQM <0x0000005d, "image_gather4_c_b_o">;
+defm IMAGE_GATHER4_C_B_CL_O : MIMG_Gather_WQM <0x0000005e, "image_gather4_c_b_cl_o">;
+defm IMAGE_GATHER4_C_LZ_O : MIMG_Gather <0x0000005f, "image_gather4_c_lz_o">;
+defm IMAGE_GET_LOD : MIMG_Sampler_WQM <0x00000060, "image_get_lod">;
+defm IMAGE_SAMPLE_CD : MIMG_Sampler <0x00000068, "image_sample_cd">;
+defm IMAGE_SAMPLE_CD_CL : MIMG_Sampler <0x00000069, "image_sample_cd_cl">;
+defm IMAGE_SAMPLE_C_CD : MIMG_Sampler <0x0000006a, "image_sample_c_cd">;
+defm IMAGE_SAMPLE_C_CD_CL : MIMG_Sampler <0x0000006b, "image_sample_c_cd_cl">;
+defm IMAGE_SAMPLE_CD_O : MIMG_Sampler <0x0000006c, "image_sample_cd_o">;
+defm IMAGE_SAMPLE_CD_CL_O : MIMG_Sampler <0x0000006d, "image_sample_cd_cl_o">;
+defm IMAGE_SAMPLE_C_CD_O : MIMG_Sampler <0x0000006e, "image_sample_c_cd_o">;
+defm IMAGE_SAMPLE_C_CD_CL_O : MIMG_Sampler <0x0000006f, "image_sample_c_cd_cl_o">;
+//def IMAGE_RSRC256 : MIMG_NoPattern_RSRC256 <"image_rsrc256", 0x0000007e>;
+//def IMAGE_SAMPLER : MIMG_NoPattern_ <"image_sampler", 0x0000007f>;
+}
+
+/********** ======================= **********/
+/********** Image sampling patterns **********/
+/********** ======================= **********/
+
+// Image + sampler
+class SampleRawPattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, i32:$dmask, i32:$unorm,
+ i32:$r128, i32:$da, i32:$glc, i32:$slc, i32:$tfe, i32:$lwe),
+ (opcode $addr, $rsrc, $sampler,
+ (as_i32imm $dmask), (as_i1imm $unorm), (as_i1imm $glc), (as_i1imm $slc),
+ (as_i1imm $r128), (as_i1imm $tfe), (as_i1imm $lwe), (as_i1imm $da))
+>;
+
+multiclass SampleRawPatterns<SDPatternOperator name, string opcode> {
+ def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V1), i32>;
+ def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V2), v2i32>;
+ def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V4), v4i32>;
+ def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V8), v8i32>;
+ def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V16), v16i32>;
+}
+
+// Image + sampler for amdgcn
+// TODO:
+// 1. Handle half data type like v4f16, and add D16 bit support;
+// 2. Handle v4i32 rsrc type (Register Class for the instruction to be SReg_128).
+// 3. Add A16 support when we pass address of half type.
+multiclass AMDGCNSamplePattern<SDPatternOperator name, MIMG opcode, ValueType dt, ValueType vt> {
+ def : Pat<
+ (dt (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, i32:$dmask, i1:$unorm, i1:$glc,
+ i1:$slc, i1:$lwe, i1:$da)),
+ (opcode $addr, $rsrc, $sampler,
+ (as_i32imm $dmask), (as_i1imm $unorm), (as_i1imm $glc), (as_i1imm $slc),
+ 0, 0, (as_i1imm $lwe), (as_i1imm $da))
+ >;
+}
+
+multiclass AMDGCNSampleDataPatterns<SDPatternOperator name, string opcode, ValueType dt> {
+ defm : AMDGCNSamplePattern<name, !cast<MIMG>(opcode # _V1), dt, f32>;
+ defm : AMDGCNSamplePattern<name, !cast<MIMG>(opcode # _V2), dt, v2f32>;
+ defm : AMDGCNSamplePattern<name, !cast<MIMG>(opcode # _V4), dt, v4f32>;
+ defm : AMDGCNSamplePattern<name, !cast<MIMG>(opcode # _V8), dt, v8f32>;
+ defm : AMDGCNSamplePattern<name, !cast<MIMG>(opcode # _V16), dt, v16f32>;
+}
+
+// TODO: support v3f32.
+multiclass AMDGCNSamplePatterns<SDPatternOperator name, string opcode> {
+ defm : AMDGCNSampleDataPatterns<name, !cast<string>(opcode # _V1), f32>;
+ defm : AMDGCNSampleDataPatterns<name, !cast<string>(opcode # _V2), v2f32>;
+ defm : AMDGCNSampleDataPatterns<name, !cast<string>(opcode # _V4), v4f32>;
+}
+
+// Image only
+class ImagePattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, imm:$dmask, imm:$unorm,
+ imm:$r128, imm:$da, imm:$glc, imm:$slc, imm:$tfe, imm:$lwe),
+ (opcode $addr, $rsrc,
+ (as_i32imm $dmask), (as_i1imm $unorm), (as_i1imm $glc), (as_i1imm $slc),
+ (as_i1imm $r128), (as_i1imm $tfe), (as_i1imm $lwe), (as_i1imm $da))
+>;
+
+multiclass ImagePatterns<SDPatternOperator name, string opcode> {
+ def : ImagePattern<name, !cast<MIMG>(opcode # _V4_V1), i32>;
+ def : ImagePattern<name, !cast<MIMG>(opcode # _V4_V2), v2i32>;
+ def : ImagePattern<name, !cast<MIMG>(opcode # _V4_V4), v4i32>;
+}
+
+multiclass ImageLoadPattern<SDPatternOperator name, MIMG opcode, ValueType dt, ValueType vt> {
+ def : Pat <
+ (dt (name vt:$addr, v8i32:$rsrc, i32:$dmask, i1:$glc, i1:$slc, i1:$lwe,
+ i1:$da)),
+ (opcode $addr, $rsrc,
+ (as_i32imm $dmask), 1, (as_i1imm $glc), (as_i1imm $slc),
+ 0, 0, (as_i1imm $lwe), (as_i1imm $da))
+ >;
+}
+
+multiclass ImageLoadDataPatterns<SDPatternOperator name, string opcode, ValueType dt> {
+ defm : ImageLoadPattern<name, !cast<MIMG>(opcode # _V1), dt, i32>;
+ defm : ImageLoadPattern<name, !cast<MIMG>(opcode # _V2), dt, v2i32>;
+ defm : ImageLoadPattern<name, !cast<MIMG>(opcode # _V4), dt, v4i32>;
+}
+
+// TODO: support v3f32.
+multiclass ImageLoadPatterns<SDPatternOperator name, string opcode> {
+ defm : ImageLoadDataPatterns<name, !cast<string>(opcode # _V1), f32>;
+ defm : ImageLoadDataPatterns<name, !cast<string>(opcode # _V2), v2f32>;
+ defm : ImageLoadDataPatterns<name, !cast<string>(opcode # _V4), v4f32>;
+}
+
+multiclass ImageStorePattern<SDPatternOperator name, MIMG opcode, ValueType dt, ValueType vt> {
+ def : Pat <
+ (name dt:$data, vt:$addr, v8i32:$rsrc, i32:$dmask, i1:$glc, i1:$slc,
+ i1:$lwe, i1:$da),
+ (opcode $data, $addr, $rsrc,
+ (as_i32imm $dmask), 1, (as_i1imm $glc), (as_i1imm $slc),
+ 0, 0, (as_i1imm $lwe), (as_i1imm $da))
+ >;
+}
+
+multiclass ImageStoreDataPatterns<SDPatternOperator name, string opcode, ValueType dt> {
+ defm : ImageStorePattern<name, !cast<MIMG>(opcode # _V1), dt, i32>;
+ defm : ImageStorePattern<name, !cast<MIMG>(opcode # _V2), dt, v2i32>;
+ defm : ImageStorePattern<name, !cast<MIMG>(opcode # _V4), dt, v4i32>;
+}
+
+// TODO: support v3f32.
+multiclass ImageStorePatterns<SDPatternOperator name, string opcode> {
+ defm : ImageStoreDataPatterns<name, !cast<string>(opcode # _V1), f32>;
+ defm : ImageStoreDataPatterns<name, !cast<string>(opcode # _V2), v2f32>;
+ defm : ImageStoreDataPatterns<name, !cast<string>(opcode # _V4), v4f32>;
+}
+
+class ImageAtomicPattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
+ (name i32:$vdata, vt:$addr, v8i32:$rsrc, imm:$r128, imm:$da, imm:$slc),
+ (opcode $vdata, $addr, $rsrc, 1, 1, 1, (as_i1imm $slc), (as_i1imm $r128), 0, 0, (as_i1imm $da))
+>;
+
+multiclass ImageAtomicPatterns<SDPatternOperator name, string opcode> {
+ def : ImageAtomicPattern<name, !cast<MIMG>(opcode # _V1), i32>;
+ def : ImageAtomicPattern<name, !cast<MIMG>(opcode # _V2), v2i32>;
+ def : ImageAtomicPattern<name, !cast<MIMG>(opcode # _V4), v4i32>;
+}
+
+class ImageAtomicCmpSwapPattern<MIMG opcode, ValueType vt> : Pat <
+ (int_amdgcn_image_atomic_cmpswap i32:$vsrc, i32:$vcmp, vt:$addr, v8i32:$rsrc,
+ imm:$r128, imm:$da, imm:$slc),
+ (EXTRACT_SUBREG
+ (opcode (REG_SEQUENCE VReg_64, $vsrc, sub0, $vcmp, sub1),
+ $addr, $rsrc, 3, 1, 1, (as_i1imm $slc), (as_i1imm $r128), 0, 0, (as_i1imm $da)),
+ sub0)
+>;
+
+// ======= SI Image Intrinsics ================
+
+// Image load
+defm : ImagePatterns<int_SI_image_load, "IMAGE_LOAD">;
+defm : ImagePatterns<int_SI_image_load_mip, "IMAGE_LOAD_MIP">;
+def : ImagePattern<int_SI_getresinfo, IMAGE_GET_RESINFO_V4_V1, i32>;
+
+// Basic sample
+defm : SampleRawPatterns<int_SI_image_sample, "IMAGE_SAMPLE">;
+defm : SampleRawPatterns<int_SI_image_sample_cl, "IMAGE_SAMPLE_CL">;
+defm : SampleRawPatterns<int_SI_image_sample_d, "IMAGE_SAMPLE_D">;
+defm : SampleRawPatterns<int_SI_image_sample_d_cl, "IMAGE_SAMPLE_D_CL">;
+defm : SampleRawPatterns<int_SI_image_sample_l, "IMAGE_SAMPLE_L">;
+defm : SampleRawPatterns<int_SI_image_sample_b, "IMAGE_SAMPLE_B">;
+defm : SampleRawPatterns<int_SI_image_sample_b_cl, "IMAGE_SAMPLE_B_CL">;
+defm : SampleRawPatterns<int_SI_image_sample_lz, "IMAGE_SAMPLE_LZ">;
+defm : SampleRawPatterns<int_SI_image_sample_cd, "IMAGE_SAMPLE_CD">;
+defm : SampleRawPatterns<int_SI_image_sample_cd_cl, "IMAGE_SAMPLE_CD_CL">;
+
+// Sample with comparison
+defm : SampleRawPatterns<int_SI_image_sample_c, "IMAGE_SAMPLE_C">;
+defm : SampleRawPatterns<int_SI_image_sample_c_cl, "IMAGE_SAMPLE_C_CL">;
+defm : SampleRawPatterns<int_SI_image_sample_c_d, "IMAGE_SAMPLE_C_D">;
+defm : SampleRawPatterns<int_SI_image_sample_c_d_cl, "IMAGE_SAMPLE_C_D_CL">;
+defm : SampleRawPatterns<int_SI_image_sample_c_l, "IMAGE_SAMPLE_C_L">;
+defm : SampleRawPatterns<int_SI_image_sample_c_b, "IMAGE_SAMPLE_C_B">;
+defm : SampleRawPatterns<int_SI_image_sample_c_b_cl, "IMAGE_SAMPLE_C_B_CL">;
+defm : SampleRawPatterns<int_SI_image_sample_c_lz, "IMAGE_SAMPLE_C_LZ">;
+defm : SampleRawPatterns<int_SI_image_sample_c_cd, "IMAGE_SAMPLE_C_CD">;
+defm : SampleRawPatterns<int_SI_image_sample_c_cd_cl, "IMAGE_SAMPLE_C_CD_CL">;
+
+// Sample with offsets
+defm : SampleRawPatterns<int_SI_image_sample_o, "IMAGE_SAMPLE_O">;
+defm : SampleRawPatterns<int_SI_image_sample_cl_o, "IMAGE_SAMPLE_CL_O">;
+defm : SampleRawPatterns<int_SI_image_sample_d_o, "IMAGE_SAMPLE_D_O">;
+defm : SampleRawPatterns<int_SI_image_sample_d_cl_o, "IMAGE_SAMPLE_D_CL_O">;
+defm : SampleRawPatterns<int_SI_image_sample_l_o, "IMAGE_SAMPLE_L_O">;
+defm : SampleRawPatterns<int_SI_image_sample_b_o, "IMAGE_SAMPLE_B_O">;
+defm : SampleRawPatterns<int_SI_image_sample_b_cl_o, "IMAGE_SAMPLE_B_CL_O">;
+defm : SampleRawPatterns<int_SI_image_sample_lz_o, "IMAGE_SAMPLE_LZ_O">;
+defm : SampleRawPatterns<int_SI_image_sample_cd_o, "IMAGE_SAMPLE_CD_O">;
+defm : SampleRawPatterns<int_SI_image_sample_cd_cl_o, "IMAGE_SAMPLE_CD_CL_O">;
+
+// Sample with comparison and offsets
+defm : SampleRawPatterns<int_SI_image_sample_c_o, "IMAGE_SAMPLE_C_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_cl_o, "IMAGE_SAMPLE_C_CL_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_d_o, "IMAGE_SAMPLE_C_D_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_d_cl_o, "IMAGE_SAMPLE_C_D_CL_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_l_o, "IMAGE_SAMPLE_C_L_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_b_o, "IMAGE_SAMPLE_C_B_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_b_cl_o, "IMAGE_SAMPLE_C_B_CL_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_lz_o, "IMAGE_SAMPLE_C_LZ_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_cd_o, "IMAGE_SAMPLE_C_CD_O">;
+defm : SampleRawPatterns<int_SI_image_sample_c_cd_cl_o, "IMAGE_SAMPLE_C_CD_CL_O">;
+
+// Gather opcodes
+// Only the variants which make sense are defined.
+def : SampleRawPattern<int_SI_gather4, IMAGE_GATHER4_V4_V2, v2i32>;
+def : SampleRawPattern<int_SI_gather4, IMAGE_GATHER4_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_cl, IMAGE_GATHER4_CL_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_l, IMAGE_GATHER4_L_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_b, IMAGE_GATHER4_B_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_b_cl, IMAGE_GATHER4_B_CL_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_b_cl, IMAGE_GATHER4_B_CL_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_lz, IMAGE_GATHER4_LZ_V4_V2, v2i32>;
+def : SampleRawPattern<int_SI_gather4_lz, IMAGE_GATHER4_LZ_V4_V4, v4i32>;
+
+def : SampleRawPattern<int_SI_gather4_c, IMAGE_GATHER4_C_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_c_cl, IMAGE_GATHER4_C_CL_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_c_cl, IMAGE_GATHER4_C_CL_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_l, IMAGE_GATHER4_C_L_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_c_l, IMAGE_GATHER4_C_L_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_b, IMAGE_GATHER4_C_B_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_c_b, IMAGE_GATHER4_C_B_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_b_cl, IMAGE_GATHER4_C_B_CL_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_lz, IMAGE_GATHER4_C_LZ_V4_V4, v4i32>;
+
+def : SampleRawPattern<int_SI_gather4_o, IMAGE_GATHER4_O_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_cl_o, IMAGE_GATHER4_CL_O_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_cl_o, IMAGE_GATHER4_CL_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_l_o, IMAGE_GATHER4_L_O_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_l_o, IMAGE_GATHER4_L_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_b_o, IMAGE_GATHER4_B_O_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_b_o, IMAGE_GATHER4_B_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_b_cl_o, IMAGE_GATHER4_B_CL_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_lz_o, IMAGE_GATHER4_LZ_O_V4_V4, v4i32>;
+
+def : SampleRawPattern<int_SI_gather4_c_o, IMAGE_GATHER4_C_O_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_c_o, IMAGE_GATHER4_C_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_cl_o, IMAGE_GATHER4_C_CL_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_l_o, IMAGE_GATHER4_C_L_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_b_o, IMAGE_GATHER4_C_B_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_b_cl_o, IMAGE_GATHER4_C_B_CL_O_V4_V8, v8i32>;
+def : SampleRawPattern<int_SI_gather4_c_lz_o, IMAGE_GATHER4_C_LZ_O_V4_V4, v4i32>;
+def : SampleRawPattern<int_SI_gather4_c_lz_o, IMAGE_GATHER4_C_LZ_O_V4_V8, v8i32>;
+
+def : SampleRawPattern<int_SI_getlod, IMAGE_GET_LOD_V4_V1, i32>;
+def : SampleRawPattern<int_SI_getlod, IMAGE_GET_LOD_V4_V2, v2i32>;
+def : SampleRawPattern<int_SI_getlod, IMAGE_GET_LOD_V4_V4, v4i32>;
+
+// ======= amdgcn Image Intrinsics ==============
+
+// Image load
+defm : ImageLoadPatterns<int_amdgcn_image_load, "IMAGE_LOAD">;
+defm : ImageLoadPatterns<int_amdgcn_image_load_mip, "IMAGE_LOAD_MIP">;
+defm : ImageLoadPatterns<int_amdgcn_image_getresinfo, "IMAGE_GET_RESINFO">;
+
+// Image store
+defm : ImageStorePatterns<int_amdgcn_image_store, "IMAGE_STORE">;
+defm : ImageStorePatterns<int_amdgcn_image_store_mip, "IMAGE_STORE_MIP">;
+
+// Basic sample
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample, "IMAGE_SAMPLE">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_cl, "IMAGE_SAMPLE_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_d, "IMAGE_SAMPLE_D">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_d_cl, "IMAGE_SAMPLE_D_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_l, "IMAGE_SAMPLE_L">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_b, "IMAGE_SAMPLE_B">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_b_cl, "IMAGE_SAMPLE_B_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_lz, "IMAGE_SAMPLE_LZ">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_cd, "IMAGE_SAMPLE_CD">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_cd_cl, "IMAGE_SAMPLE_CD_CL">;
+
+// Sample with comparison
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c, "IMAGE_SAMPLE_C">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_cl, "IMAGE_SAMPLE_C_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_d, "IMAGE_SAMPLE_C_D">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_d_cl, "IMAGE_SAMPLE_C_D_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_l, "IMAGE_SAMPLE_C_L">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_b, "IMAGE_SAMPLE_C_B">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_b_cl, "IMAGE_SAMPLE_C_B_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_lz, "IMAGE_SAMPLE_C_LZ">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_cd, "IMAGE_SAMPLE_C_CD">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_cd_cl, "IMAGE_SAMPLE_C_CD_CL">;
+
+// Sample with offsets
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_o, "IMAGE_SAMPLE_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_cl_o, "IMAGE_SAMPLE_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_d_o, "IMAGE_SAMPLE_D_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_d_cl_o, "IMAGE_SAMPLE_D_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_l_o, "IMAGE_SAMPLE_L_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_b_o, "IMAGE_SAMPLE_B_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_b_cl_o, "IMAGE_SAMPLE_B_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_lz_o, "IMAGE_SAMPLE_LZ_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_cd_o, "IMAGE_SAMPLE_CD_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_cd_cl_o, "IMAGE_SAMPLE_CD_CL_O">;
+
+// Sample with comparison and offsets
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_o, "IMAGE_SAMPLE_C_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_cl_o, "IMAGE_SAMPLE_C_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_d_o, "IMAGE_SAMPLE_C_D_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_d_cl_o, "IMAGE_SAMPLE_C_D_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_l_o, "IMAGE_SAMPLE_C_L_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_b_o, "IMAGE_SAMPLE_C_B_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_b_cl_o, "IMAGE_SAMPLE_C_B_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_lz_o, "IMAGE_SAMPLE_C_LZ_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_cd_o, "IMAGE_SAMPLE_C_CD_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_sample_c_cd_cl_o, "IMAGE_SAMPLE_C_CD_CL_O">;
+
+// Gather opcodes
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4, "IMAGE_GATHER4">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_cl, "IMAGE_GATHER4_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_l, "IMAGE_GATHER4_L">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_b, "IMAGE_GATHER4_B">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_b_cl, "IMAGE_GATHER4_B_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_lz, "IMAGE_GATHER4_LZ">;
+
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c, "IMAGE_GATHER4_C">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_cl, "IMAGE_GATHER4_C_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_l, "IMAGE_GATHER4_C_L">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_b, "IMAGE_GATHER4_C_B">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_b_cl, "IMAGE_GATHER4_C_B_CL">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_lz, "IMAGE_GATHER4_C_LZ">;
+
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_o, "IMAGE_GATHER4_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_cl_o, "IMAGE_GATHER4_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_l_o, "IMAGE_GATHER4_L_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_b_o, "IMAGE_GATHER4_B_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_b_cl_o, "IMAGE_GATHER4_B_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_lz_o, "IMAGE_GATHER4_LZ_O">;
+
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_o, "IMAGE_GATHER4_C_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_cl_o, "IMAGE_GATHER4_C_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_l_o, "IMAGE_GATHER4_C_L_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_b_o, "IMAGE_GATHER4_C_B_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_b_cl_o, "IMAGE_GATHER4_C_B_CL_O">;
+defm : AMDGCNSamplePatterns<int_amdgcn_image_gather4_c_lz_o, "IMAGE_GATHER4_C_LZ_O">;
+
+defm : AMDGCNSamplePatterns<int_amdgcn_image_getlod, "IMAGE_GET_LOD">;
+
+// Image atomics
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_swap, "IMAGE_ATOMIC_SWAP">;
+def : ImageAtomicCmpSwapPattern<IMAGE_ATOMIC_CMPSWAP_V1, i32>;
+def : ImageAtomicCmpSwapPattern<IMAGE_ATOMIC_CMPSWAP_V2, v2i32>;
+def : ImageAtomicCmpSwapPattern<IMAGE_ATOMIC_CMPSWAP_V4, v4i32>;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_add, "IMAGE_ATOMIC_ADD">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_sub, "IMAGE_ATOMIC_SUB">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_smin, "IMAGE_ATOMIC_SMIN">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_umin, "IMAGE_ATOMIC_UMIN">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_smax, "IMAGE_ATOMIC_SMAX">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_umax, "IMAGE_ATOMIC_UMAX">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_and, "IMAGE_ATOMIC_AND">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_or, "IMAGE_ATOMIC_OR">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_xor, "IMAGE_ATOMIC_XOR">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_inc, "IMAGE_ATOMIC_INC">;
+defm : ImageAtomicPatterns<int_amdgcn_image_atomic_dec, "IMAGE_ATOMIC_DEC">;
+
+/* SIsample for simple 1D texture lookup */
+def : Pat <
+ (SIsample i32:$addr, v8i32:$rsrc, v4i32:$sampler, imm),
+ (IMAGE_SAMPLE_V4_V1 $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 0)
+>;
+
+class SamplePattern<SDNode name, MIMG opcode, ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, imm),
+ (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 0)
+>;
+
+class SampleRectPattern<SDNode name, MIMG opcode, ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_RECT),
+ (opcode $addr, $rsrc, $sampler, 0xf, 1, 0, 0, 0, 0, 0, 0)
+>;
+
+class SampleArrayPattern<SDNode name, MIMG opcode, ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_ARRAY),
+ (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 1)
+>;
+
+class SampleShadowPattern<SDNode name, MIMG opcode,
+ ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_SHADOW),
+ (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 0)
+>;
+
+class SampleShadowArrayPattern<SDNode name, MIMG opcode,
+ ValueType vt> : Pat <
+ (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_SHADOW_ARRAY),
+ (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 1)
+>;
+
+/* SIsample* for texture lookups consuming more address parameters */
+multiclass SamplePatterns<MIMG sample, MIMG sample_c, MIMG sample_l,
+ MIMG sample_c_l, MIMG sample_b, MIMG sample_c_b,
+MIMG sample_d, MIMG sample_c_d, ValueType addr_type> {
+ def : SamplePattern <SIsample, sample, addr_type>;
+ def : SampleRectPattern <SIsample, sample, addr_type>;
+ def : SampleArrayPattern <SIsample, sample, addr_type>;
+ def : SampleShadowPattern <SIsample, sample_c, addr_type>;
+ def : SampleShadowArrayPattern <SIsample, sample_c, addr_type>;
+
+ def : SamplePattern <SIsamplel, sample_l, addr_type>;
+ def : SampleArrayPattern <SIsamplel, sample_l, addr_type>;
+ def : SampleShadowPattern <SIsamplel, sample_c_l, addr_type>;
+ def : SampleShadowArrayPattern <SIsamplel, sample_c_l, addr_type>;
+
+ def : SamplePattern <SIsampleb, sample_b, addr_type>;
+ def : SampleArrayPattern <SIsampleb, sample_b, addr_type>;
+ def : SampleShadowPattern <SIsampleb, sample_c_b, addr_type>;
+ def : SampleShadowArrayPattern <SIsampleb, sample_c_b, addr_type>;
+
+ def : SamplePattern <SIsampled, sample_d, addr_type>;
+ def : SampleArrayPattern <SIsampled, sample_d, addr_type>;
+ def : SampleShadowPattern <SIsampled, sample_c_d, addr_type>;
+ def : SampleShadowArrayPattern <SIsampled, sample_c_d, addr_type>;
+}
+
+defm : SamplePatterns<IMAGE_SAMPLE_V4_V2, IMAGE_SAMPLE_C_V4_V2,
+ IMAGE_SAMPLE_L_V4_V2, IMAGE_SAMPLE_C_L_V4_V2,
+ IMAGE_SAMPLE_B_V4_V2, IMAGE_SAMPLE_C_B_V4_V2,
+ IMAGE_SAMPLE_D_V4_V2, IMAGE_SAMPLE_C_D_V4_V2,
+ v2i32>;
+defm : SamplePatterns<IMAGE_SAMPLE_V4_V4, IMAGE_SAMPLE_C_V4_V4,
+ IMAGE_SAMPLE_L_V4_V4, IMAGE_SAMPLE_C_L_V4_V4,
+ IMAGE_SAMPLE_B_V4_V4, IMAGE_SAMPLE_C_B_V4_V4,
+ IMAGE_SAMPLE_D_V4_V4, IMAGE_SAMPLE_C_D_V4_V4,
+ v4i32>;
+defm : SamplePatterns<IMAGE_SAMPLE_V4_V8, IMAGE_SAMPLE_C_V4_V8,
+ IMAGE_SAMPLE_L_V4_V8, IMAGE_SAMPLE_C_L_V4_V8,
+ IMAGE_SAMPLE_B_V4_V8, IMAGE_SAMPLE_C_B_V4_V8,
+ IMAGE_SAMPLE_D_V4_V8, IMAGE_SAMPLE_C_D_V4_V8,
+ v8i32>;
+defm : SamplePatterns<IMAGE_SAMPLE_V4_V16, IMAGE_SAMPLE_C_V4_V16,
+ IMAGE_SAMPLE_L_V4_V16, IMAGE_SAMPLE_C_L_V4_V16,
+ IMAGE_SAMPLE_B_V4_V16, IMAGE_SAMPLE_C_B_V4_V16,
+ IMAGE_SAMPLE_D_V4_V16, IMAGE_SAMPLE_C_D_V4_V16,
+ v16i32>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/Processors.td b/contrib/llvm/lib/Target/AMDGPU/Processors.td
index f5f1eb1..3c07cc7 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Processors.td
+++ b/contrib/llvm/lib/Target/AMDGPU/Processors.td
@@ -101,55 +101,89 @@ def : ProcessorModel<"hainan", SIQuarterSpeedModel, [FeatureSouthernIslands]>;
//===----------------------------------------------------------------------===//
def : ProcessorModel<"bonaire", SIQuarterSpeedModel,
- [FeatureSeaIslands, FeatureLDSBankCount32, FeatureISAVersion7_0_0]
+ [FeatureISAVersion7_0_0]
>;
def : ProcessorModel<"kabini", SIQuarterSpeedModel,
- [FeatureSeaIslands, FeatureLDSBankCount16]
+ [FeatureISAVersion7_0_2]
>;
def : ProcessorModel<"kaveri", SIQuarterSpeedModel,
- [FeatureSeaIslands, FeatureLDSBankCount32, FeatureISAVersion7_0_0]
+ [FeatureISAVersion7_0_0]
>;
-def : ProcessorModel<"hawaii", SIFullSpeedModel,
- [FeatureSeaIslands, FeatureFastFMAF32, HalfRate64Ops,
- FeatureLDSBankCount32, FeatureISAVersion7_0_1]
+def : ProcessorModel<"hawaii", SIFullSpeedModel,
+ [FeatureISAVersion7_0_1]
>;
def : ProcessorModel<"mullins", SIQuarterSpeedModel,
- [FeatureSeaIslands, FeatureLDSBankCount16]>;
+ [FeatureISAVersion7_0_2]>;
+
+def : ProcessorModel<"gfx700", SIQuarterSpeedModel,
+ [FeatureISAVersion7_0_0]
+>;
+
+def : ProcessorModel<"gfx701", SIFullSpeedModel,
+ [FeatureISAVersion7_0_1]
+>;
+
+def : ProcessorModel<"gfx702", SIQuarterSpeedModel,
+ [FeatureISAVersion7_0_2]
+>;
//===----------------------------------------------------------------------===//
// Volcanic Islands
//===----------------------------------------------------------------------===//
def : ProcessorModel<"tonga", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureSGPRInitBug, FeatureISAVersion8_0_0,
- FeatureLDSBankCount32]
+ [FeatureISAVersion8_0_2]
>;
def : ProcessorModel<"iceland", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureSGPRInitBug, FeatureISAVersion8_0_0,
- FeatureLDSBankCount32]
+ [FeatureISAVersion8_0_0]
>;
def : ProcessorModel<"carrizo", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureISAVersion8_0_1, FeatureLDSBankCount32]
+ [FeatureISAVersion8_0_1]
>;
-def : ProcessorModel<"fiji", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureISAVersion8_0_3, FeatureLDSBankCount32]
+def : ProcessorModel<"fiji", SIQuarterSpeedModel,
+ [FeatureISAVersion8_0_3]
>;
-def : ProcessorModel<"stoney", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureISAVersion8_0_1, FeatureLDSBankCount16]
+def : ProcessorModel<"stoney", SIQuarterSpeedModel,
+ [FeatureISAVersion8_1_0]
>;
def : ProcessorModel<"polaris10", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureISAVersion8_0_1, FeatureLDSBankCount32]
+ [FeatureISAVersion8_0_3]
>;
def : ProcessorModel<"polaris11", SIQuarterSpeedModel,
- [FeatureVolcanicIslands, FeatureISAVersion8_0_1, FeatureLDSBankCount32]
+ [FeatureISAVersion8_0_3]
+>;
+
+def : ProcessorModel<"gfx800", SIQuarterSpeedModel,
+ [FeatureISAVersion8_0_0]
+>;
+
+def : ProcessorModel<"gfx801", SIQuarterSpeedModel,
+ [FeatureISAVersion8_0_1]
>;
+
+def : ProcessorModel<"gfx802", SIQuarterSpeedModel,
+ [FeatureISAVersion8_0_2]
+>;
+
+def : ProcessorModel<"gfx803", SIQuarterSpeedModel,
+ [FeatureISAVersion8_0_3]
+>;
+
+def : ProcessorModel<"gfx804", SIQuarterSpeedModel,
+ [FeatureISAVersion8_0_4]
+>;
+
+def : ProcessorModel<"gfx810", SIQuarterSpeedModel,
+ [FeatureISAVersion8_1_0]
+>;
+
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp b/contrib/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp
index 3ccde79..d0aba38 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600ClauseMergePass.cpp
@@ -66,7 +66,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override;
+ StringRef getPassName() const override;
};
char R600ClauseMergePass::ID = 0;
@@ -201,7 +201,7 @@ bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) {
return false;
}
-const char *R600ClauseMergePass::getPassName() const {
+StringRef R600ClauseMergePass::getPassName() const {
return "R600 Merge Clause Markers Pass";
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp b/contrib/llvm/lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp
index d5bda4a..45b36d3 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp
@@ -354,10 +354,10 @@ private:
if (Src.first->getReg() != AMDGPU::ALU_LITERAL_X)
continue;
int64_t Imm = Src.second;
- std::vector<MachineOperand*>::iterator It =
- std::find_if(Lits.begin(), Lits.end(),
- [&](MachineOperand* val)
- { return val->isImm() && (val->getImm() == Imm);});
+ std::vector<MachineOperand *>::iterator It =
+ find_if(Lits, [&](MachineOperand *val) {
+ return val->isImm() && (val->getImm() == Imm);
+ });
// Get corresponding Operand
MachineOperand &Operand = MI.getOperand(
@@ -450,27 +450,24 @@ private:
return ClauseFile(&ClauseHead, std::move(ClauseContent));
}
- void
- EmitFetchClause(MachineBasicBlock::iterator InsertPos, ClauseFile &Clause,
- unsigned &CfCount) {
+ void EmitFetchClause(MachineBasicBlock::iterator InsertPos,
+ const DebugLoc &DL, ClauseFile &Clause,
+ unsigned &CfCount) {
CounterPropagateAddr(*Clause.first, CfCount);
MachineBasicBlock *BB = Clause.first->getParent();
- BuildMI(BB, InsertPos->getDebugLoc(), TII->get(AMDGPU::FETCH_CLAUSE))
- .addImm(CfCount);
+ BuildMI(BB, DL, TII->get(AMDGPU::FETCH_CLAUSE)).addImm(CfCount);
for (unsigned i = 0, e = Clause.second.size(); i < e; ++i) {
BB->splice(InsertPos, BB, Clause.second[i]);
}
CfCount += 2 * Clause.second.size();
}
- void
- EmitALUClause(MachineBasicBlock::iterator InsertPos, ClauseFile &Clause,
- unsigned &CfCount) {
+ void EmitALUClause(MachineBasicBlock::iterator InsertPos, const DebugLoc &DL,
+ ClauseFile &Clause, unsigned &CfCount) {
Clause.first->getOperand(0).setImm(0);
CounterPropagateAddr(*Clause.first, CfCount);
MachineBasicBlock *BB = Clause.first->getParent();
- BuildMI(BB, InsertPos->getDebugLoc(), TII->get(AMDGPU::ALU_CLAUSE))
- .addImm(CfCount);
+ BuildMI(BB, DL, TII->get(AMDGPU::ALU_CLAUSE)).addImm(CfCount);
for (unsigned i = 0, e = Clause.second.size(); i < e; ++i) {
BB->splice(InsertPos, BB, Clause.second[i]);
}
@@ -644,17 +641,18 @@ public:
break;
}
case AMDGPU::RETURN: {
- BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END));
+ DebugLoc DL = MBB.findDebugLoc(MI);
+ BuildMI(MBB, MI, DL, getHWInstrDesc(CF_END));
CfCount++;
if (CfCount % 2) {
- BuildMI(MBB, I, MBB.findDebugLoc(MI), TII->get(AMDGPU::PAD));
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::PAD));
CfCount++;
}
MI->eraseFromParent();
for (unsigned i = 0, e = FetchClauses.size(); i < e; i++)
- EmitFetchClause(I, FetchClauses[i], CfCount);
+ EmitFetchClause(I, DL, FetchClauses[i], CfCount);
for (unsigned i = 0, e = AluClauses.size(); i < e; i++)
- EmitALUClause(I, AluClauses[i], CfCount);
+ EmitALUClause(I, DL, AluClauses[i], CfCount);
break;
}
default:
@@ -680,13 +678,13 @@ public:
.addImm(Alu->getOperand(8).getImm());
Alu->eraseFromParent();
}
- MFI->StackSize = CFStack.MaxStackSize;
+ MFI->CFStackSize = CFStack.MaxStackSize;
}
return false;
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "R600 Control Flow Finalizer Pass";
}
};
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp b/contrib/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp
index 93ed5be..9a5db6c 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600EmitClauseMarkers.cpp
@@ -307,7 +307,7 @@ public:
BB != BB_E; ++BB) {
MachineBasicBlock &MBB = *BB;
MachineBasicBlock::iterator I = MBB.begin();
- if (I->getOpcode() == AMDGPU::CF_ALU)
+ if (I != MBB.end() && I->getOpcode() == AMDGPU::CF_ALU)
continue; // BB was already parsed
for (MachineBasicBlock::iterator E = MBB.end(); I != E;) {
if (isALU(*I))
@@ -319,7 +319,7 @@ public:
return false;
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "R600 Emit Clause Markers Pass";
}
};
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp b/contrib/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp
index 0385b62..3e46e63 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600ExpandSpecialInstrs.cpp
@@ -42,7 +42,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "R600 Expand special instructions pass";
}
};
@@ -116,85 +116,6 @@ bool R600ExpandSpecialInstrsPass::runOnMachineFunction(MachineFunction &MF) {
MI.eraseFromParent();
continue;
}
-
- case AMDGPU::INTERP_PAIR_XY: {
- MachineInstr *BMI;
- unsigned PReg = AMDGPU::R600_ArrayBaseRegClass.getRegister(
- MI.getOperand(2).getImm());
-
- for (unsigned Chan = 0; Chan < 4; ++Chan) {
- unsigned DstReg;
-
- if (Chan < 2)
- DstReg = MI.getOperand(Chan).getReg();
- else
- DstReg = Chan == 2 ? AMDGPU::T0_Z : AMDGPU::T0_W;
-
- BMI = TII->buildDefaultInstruction(MBB, I, AMDGPU::INTERP_XY,
- DstReg, MI.getOperand(3 + (Chan % 2)).getReg(), PReg);
-
- if (Chan > 0) {
- BMI->bundleWithPred();
- }
- if (Chan >= 2)
- TII->addFlag(*BMI, 0, MO_FLAG_MASK);
- if (Chan != 3)
- TII->addFlag(*BMI, 0, MO_FLAG_NOT_LAST);
- }
-
- MI.eraseFromParent();
- continue;
- }
-
- case AMDGPU::INTERP_PAIR_ZW: {
- MachineInstr *BMI;
- unsigned PReg = AMDGPU::R600_ArrayBaseRegClass.getRegister(
- MI.getOperand(2).getImm());
-
- for (unsigned Chan = 0; Chan < 4; ++Chan) {
- unsigned DstReg;
-
- if (Chan < 2)
- DstReg = Chan == 0 ? AMDGPU::T0_X : AMDGPU::T0_Y;
- else
- DstReg = MI.getOperand(Chan-2).getReg();
-
- BMI = TII->buildDefaultInstruction(MBB, I, AMDGPU::INTERP_ZW,
- DstReg, MI.getOperand(3 + (Chan % 2)).getReg(), PReg);
-
- if (Chan > 0) {
- BMI->bundleWithPred();
- }
- if (Chan < 2)
- TII->addFlag(*BMI, 0, MO_FLAG_MASK);
- if (Chan != 3)
- TII->addFlag(*BMI, 0, MO_FLAG_NOT_LAST);
- }
-
- MI.eraseFromParent();
- continue;
- }
-
- case AMDGPU::INTERP_VEC_LOAD: {
- const R600RegisterInfo &TRI = TII->getRegisterInfo();
- MachineInstr *BMI;
- unsigned PReg = AMDGPU::R600_ArrayBaseRegClass.getRegister(
- MI.getOperand(1).getImm());
- unsigned DstReg = MI.getOperand(0).getReg();
-
- for (unsigned Chan = 0; Chan < 4; ++Chan) {
- BMI = TII->buildDefaultInstruction(MBB, I, AMDGPU::INTERP_LOAD_P0,
- TRI.getSubReg(DstReg, TRI.getSubRegFromChannel(Chan)), PReg);
- if (Chan > 0) {
- BMI->bundleWithPred();
- }
- if (Chan != 3)
- TII->addFlag(*BMI, 0, MO_FLAG_NOT_LAST);
- }
-
- MI.eraseFromParent();
- continue;
- }
case AMDGPU::DOT_4: {
const R600RegisterInfo &TRI = TII->getRegisterInfo();
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.cpp
index dd5681f..5813786 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.cpp
@@ -11,5 +11,4 @@
using namespace llvm;
-R600FrameLowering::~R600FrameLowering() {
-}
+R600FrameLowering::~R600FrameLowering() = default;
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.h b/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.h
index 5fe4e0d..874435f 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.h
+++ b/contrib/llvm/lib/Target/AMDGPU/R600FrameLowering.h
@@ -19,12 +19,14 @@ public:
R600FrameLowering(StackDirection D, unsigned StackAl, int LAO,
unsigned TransAl = 1) :
AMDGPUFrameLowering(D, StackAl, LAO, TransAl) {}
- virtual ~R600FrameLowering();
+ ~R600FrameLowering() override;
- void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const {}
- void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const {}
+ void emitPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const override {}
+ void emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const override {}
};
-}
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_AMDGPU_R600FRAMELOWERING_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp
index 8ccd176..77fee435 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp
@@ -17,16 +17,36 @@
#include "AMDGPUIntrinsicInfo.h"
#include "AMDGPUSubtarget.h"
#include "R600Defines.h"
+#include "R600FrameLowering.h"
#include "R600InstrInfo.h"
#include "R600MachineFunctionInfo.h"
-#include "llvm/Analysis/ValueTracking.h"
+#include "Utils/AMDGPUBaseInfo.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/CallingConvLower.h"
-#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/DAGCombine.h"
+#include "llvm/CodeGen/ISDOpcodes.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/SelectionDAG.h"
-#include "llvm/IR/Argument.h"
-#include "llvm/IR/Function.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <utility>
+#include <vector>
using namespace llvm;
@@ -72,7 +92,6 @@ R600TargetLowering::R600TargetLowering(const TargetMachine &TM,
setLoadExtAction(ISD::SEXTLOAD, MVT::v4i32, MVT::v4i1, Expand);
setLoadExtAction(ISD::ZEXTLOAD, MVT::v4i32, MVT::v4i1, Expand);
-
setOperationAction(ISD::STORE, MVT::i8, Custom);
setOperationAction(ISD::STORE, MVT::i32, Custom);
setOperationAction(ISD::STORE, MVT::v2i32, Custom);
@@ -80,6 +99,18 @@ R600TargetLowering::R600TargetLowering(const TargetMachine &TM,
setTruncStoreAction(MVT::i32, MVT::i8, Custom);
setTruncStoreAction(MVT::i32, MVT::i16, Custom);
+ // We need to include these since trunc STORES to PRIVATE need
+ // special handling to accommodate RMW
+ setTruncStoreAction(MVT::v2i32, MVT::v2i16, Custom);
+ setTruncStoreAction(MVT::v4i32, MVT::v4i16, Custom);
+ setTruncStoreAction(MVT::v8i32, MVT::v8i16, Custom);
+ setTruncStoreAction(MVT::v16i32, MVT::v16i16, Custom);
+ setTruncStoreAction(MVT::v32i32, MVT::v32i16, Custom);
+ setTruncStoreAction(MVT::v2i32, MVT::v2i8, Custom);
+ setTruncStoreAction(MVT::v4i32, MVT::v4i8, Custom);
+ setTruncStoreAction(MVT::v8i32, MVT::v8i8, Custom);
+ setTruncStoreAction(MVT::v16i32, MVT::v16i8, Custom);
+ setTruncStoreAction(MVT::v32i32, MVT::v32i8, Custom);
// Workaround for LegalizeDAG asserting on expansion of i1 vector stores.
setTruncStoreAction(MVT::v2i32, MVT::v2i1, Expand);
@@ -192,12 +223,12 @@ R600TargetLowering::R600TargetLowering(const TargetMachine &TM,
setSchedulingPreference(Sched::Source);
-
setTargetDAGCombine(ISD::FP_ROUND);
setTargetDAGCombine(ISD::FP_TO_SINT);
setTargetDAGCombine(ISD::EXTRACT_VECTOR_ELT);
setTargetDAGCombine(ISD::SELECT_CC);
setTargetDAGCombine(ISD::INSERT_VECTOR_ELT);
+ setTargetDAGCombine(ISD::LOAD);
}
const R600Subtarget *R600TargetLowering::getSubtarget() const {
@@ -205,13 +236,15 @@ const R600Subtarget *R600TargetLowering::getSubtarget() const {
}
static inline bool isEOP(MachineBasicBlock::iterator I) {
+ if (std::next(I) == I->getParent()->end())
+ return false;
return std::next(I)->getOpcode() == AMDGPU::RETURN;
}
MachineBasicBlock *
R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const {
- MachineFunction * MF = BB->getParent();
+ MachineFunction *MF = BB->getParent();
MachineRegisterInfo &MRI = MF->getRegInfo();
MachineBasicBlock::iterator I = MI;
const R600InstrInfo *TII = getSubtarget()->getInstrInfo();
@@ -278,10 +311,12 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
.bitcastToAPInt()
.getZExtValue());
break;
+
case AMDGPU::MOV_IMM_I32:
TII->buildMovImm(*BB, I, MI.getOperand(0).getReg(),
MI.getOperand(1).getImm());
break;
+
case AMDGPU::MOV_IMM_GLOBAL_ADDR: {
//TODO: Perhaps combine this instruction with the next if possible
auto MIB = TII->buildDefaultInstruction(
@@ -291,6 +326,7 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MIB->getOperand(Idx) = MI.getOperand(1);
break;
}
+
case AMDGPU::CONST_COPY: {
MachineInstr *NewMI = TII->buildDefaultInstruction(
*BB, MI, AMDGPU::MOV, MI.getOperand(0).getReg(), AMDGPU::ALU_CONST);
@@ -301,228 +337,20 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case AMDGPU::RAT_WRITE_CACHELESS_32_eg:
case AMDGPU::RAT_WRITE_CACHELESS_64_eg:
- case AMDGPU::RAT_WRITE_CACHELESS_128_eg: {
+ case AMDGPU::RAT_WRITE_CACHELESS_128_eg:
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(MI.getOpcode()))
.addOperand(MI.getOperand(0))
.addOperand(MI.getOperand(1))
.addImm(isEOP(I)); // Set End of program bit
break;
- }
- case AMDGPU::RAT_STORE_TYPED_eg: {
+
+ case AMDGPU::RAT_STORE_TYPED_eg:
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(MI.getOpcode()))
.addOperand(MI.getOperand(0))
.addOperand(MI.getOperand(1))
.addOperand(MI.getOperand(2))
.addImm(isEOP(I)); // Set End of program bit
break;
- }
-
- case AMDGPU::TXD: {
- unsigned T0 = MRI.createVirtualRegister(&AMDGPU::R600_Reg128RegClass);
- unsigned T1 = MRI.createVirtualRegister(&AMDGPU::R600_Reg128RegClass);
- MachineOperand &RID = MI.getOperand(4);
- MachineOperand &SID = MI.getOperand(5);
- unsigned TextureId = MI.getOperand(6).getImm();
- unsigned SrcX = 0, SrcY = 1, SrcZ = 2, SrcW = 3;
- unsigned CTX = 1, CTY = 1, CTZ = 1, CTW = 1;
-
- switch (TextureId) {
- case 5: // Rect
- CTX = CTY = 0;
- break;
- case 6: // Shadow1D
- SrcW = SrcZ;
- break;
- case 7: // Shadow2D
- SrcW = SrcZ;
- break;
- case 8: // ShadowRect
- CTX = CTY = 0;
- SrcW = SrcZ;
- break;
- case 9: // 1DArray
- SrcZ = SrcY;
- CTZ = 0;
- break;
- case 10: // 2DArray
- CTZ = 0;
- break;
- case 11: // Shadow1DArray
- SrcZ = SrcY;
- CTZ = 0;
- break;
- case 12: // Shadow2DArray
- CTZ = 0;
- break;
- }
- BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::TEX_SET_GRADIENTS_H),
- T0)
- .addOperand(MI.getOperand(3))
- .addImm(SrcX)
- .addImm(SrcY)
- .addImm(SrcZ)
- .addImm(SrcW)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(1)
- .addImm(2)
- .addImm(3)
- .addOperand(RID)
- .addOperand(SID)
- .addImm(CTX)
- .addImm(CTY)
- .addImm(CTZ)
- .addImm(CTW);
- BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::TEX_SET_GRADIENTS_V),
- T1)
- .addOperand(MI.getOperand(2))
- .addImm(SrcX)
- .addImm(SrcY)
- .addImm(SrcZ)
- .addImm(SrcW)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(1)
- .addImm(2)
- .addImm(3)
- .addOperand(RID)
- .addOperand(SID)
- .addImm(CTX)
- .addImm(CTY)
- .addImm(CTZ)
- .addImm(CTW);
- BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::TEX_SAMPLE_G))
- .addOperand(MI.getOperand(0))
- .addOperand(MI.getOperand(1))
- .addImm(SrcX)
- .addImm(SrcY)
- .addImm(SrcZ)
- .addImm(SrcW)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(1)
- .addImm(2)
- .addImm(3)
- .addOperand(RID)
- .addOperand(SID)
- .addImm(CTX)
- .addImm(CTY)
- .addImm(CTZ)
- .addImm(CTW)
- .addReg(T0, RegState::Implicit)
- .addReg(T1, RegState::Implicit);
- break;
- }
-
- case AMDGPU::TXD_SHADOW: {
- unsigned T0 = MRI.createVirtualRegister(&AMDGPU::R600_Reg128RegClass);
- unsigned T1 = MRI.createVirtualRegister(&AMDGPU::R600_Reg128RegClass);
- MachineOperand &RID = MI.getOperand(4);
- MachineOperand &SID = MI.getOperand(5);
- unsigned TextureId = MI.getOperand(6).getImm();
- unsigned SrcX = 0, SrcY = 1, SrcZ = 2, SrcW = 3;
- unsigned CTX = 1, CTY = 1, CTZ = 1, CTW = 1;
-
- switch (TextureId) {
- case 5: // Rect
- CTX = CTY = 0;
- break;
- case 6: // Shadow1D
- SrcW = SrcZ;
- break;
- case 7: // Shadow2D
- SrcW = SrcZ;
- break;
- case 8: // ShadowRect
- CTX = CTY = 0;
- SrcW = SrcZ;
- break;
- case 9: // 1DArray
- SrcZ = SrcY;
- CTZ = 0;
- break;
- case 10: // 2DArray
- CTZ = 0;
- break;
- case 11: // Shadow1DArray
- SrcZ = SrcY;
- CTZ = 0;
- break;
- case 12: // Shadow2DArray
- CTZ = 0;
- break;
- }
-
- BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::TEX_SET_GRADIENTS_H),
- T0)
- .addOperand(MI.getOperand(3))
- .addImm(SrcX)
- .addImm(SrcY)
- .addImm(SrcZ)
- .addImm(SrcW)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(1)
- .addImm(2)
- .addImm(3)
- .addOperand(RID)
- .addOperand(SID)
- .addImm(CTX)
- .addImm(CTY)
- .addImm(CTZ)
- .addImm(CTW);
- BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::TEX_SET_GRADIENTS_V),
- T1)
- .addOperand(MI.getOperand(2))
- .addImm(SrcX)
- .addImm(SrcY)
- .addImm(SrcZ)
- .addImm(SrcW)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(1)
- .addImm(2)
- .addImm(3)
- .addOperand(RID)
- .addOperand(SID)
- .addImm(CTX)
- .addImm(CTY)
- .addImm(CTZ)
- .addImm(CTW);
- BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::TEX_SAMPLE_C_G))
- .addOperand(MI.getOperand(0))
- .addOperand(MI.getOperand(1))
- .addImm(SrcX)
- .addImm(SrcY)
- .addImm(SrcZ)
- .addImm(SrcW)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(0)
- .addImm(1)
- .addImm(2)
- .addImm(3)
- .addOperand(RID)
- .addOperand(SID)
- .addImm(CTX)
- .addImm(CTY)
- .addImm(CTZ)
- .addImm(CTW)
- .addReg(T0, RegState::Implicit)
- .addReg(T1, RegState::Implicit);
- break;
- }
case AMDGPU::BRANCH:
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::JUMP))
@@ -534,7 +362,7 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::PRED_X),
AMDGPU::PREDICATE_BIT)
.addOperand(MI.getOperand(1))
- .addImm(OPCODE_IS_NOT_ZERO)
+ .addImm(AMDGPU::PRED_SETNE)
.addImm(0); // Flags
TII->addFlag(*NewMI, 0, MO_FLAG_PUSH);
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::JUMP_COND))
@@ -548,7 +376,7 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::PRED_X),
AMDGPU::PREDICATE_BIT)
.addOperand(MI.getOperand(1))
- .addImm(OPCODE_IS_NOT_ZERO_INT)
+ .addImm(AMDGPU::PRED_SETNE_INT)
.addImm(0); // Flags
TII->addFlag(*NewMI, 0, MO_FLAG_PUSH);
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::JUMP_COND))
@@ -592,12 +420,6 @@ R600TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
break;
}
case AMDGPU::RETURN: {
- // RETURN instructions must have the live-out registers as implicit uses,
- // otherwise they appear dead.
- R600MachineFunctionInfo *MFI = MF->getInfo<R600MachineFunctionInfo>();
- MachineInstrBuilder MIB(*MF, MI);
- for (unsigned i = 0, e = MFI->LiveOuts.size(); i != e; ++i)
- MIB.addReg(MFI->LiveOuts[i], RegState::Implicit);
return BB;
}
}
@@ -654,7 +476,7 @@ SDValue R600TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const
DAG.getConstant(2, DL, MVT::i32), // SWZ_Z
DAG.getConstant(3, DL, MVT::i32) // SWZ_W
};
- return DAG.getNode(AMDGPUISD::EXPORT, DL, Op.getValueType(), Args);
+ return DAG.getNode(AMDGPUISD::R600_EXPORT, DL, Op.getValueType(), Args);
}
// default for switch(IntrinsicID)
@@ -671,15 +493,7 @@ SDValue R600TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const
switch(IntrinsicID) {
default: return AMDGPUTargetLowering::LowerOperation(Op, DAG);
case AMDGPUIntrinsic::r600_tex:
- case AMDGPUIntrinsic::r600_texc:
- case AMDGPUIntrinsic::r600_txl:
- case AMDGPUIntrinsic::r600_txlc:
- case AMDGPUIntrinsic::r600_txb:
- case AMDGPUIntrinsic::r600_txbc:
- case AMDGPUIntrinsic::r600_txf:
- case AMDGPUIntrinsic::r600_txq:
- case AMDGPUIntrinsic::r600_ddx:
- case AMDGPUIntrinsic::r600_ddy: {
+ case AMDGPUIntrinsic::r600_texc: {
unsigned TextureOp;
switch (IntrinsicID) {
case AMDGPUIntrinsic::r600_tex:
@@ -688,32 +502,8 @@ SDValue R600TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const
case AMDGPUIntrinsic::r600_texc:
TextureOp = 1;
break;
- case AMDGPUIntrinsic::r600_txl:
- TextureOp = 2;
- break;
- case AMDGPUIntrinsic::r600_txlc:
- TextureOp = 3;
- break;
- case AMDGPUIntrinsic::r600_txb:
- TextureOp = 4;
- break;
- case AMDGPUIntrinsic::r600_txbc:
- TextureOp = 5;
- break;
- case AMDGPUIntrinsic::r600_txf:
- TextureOp = 6;
- break;
- case AMDGPUIntrinsic::r600_txq:
- TextureOp = 7;
- break;
- case AMDGPUIntrinsic::r600_ddx:
- TextureOp = 8;
- break;
- case AMDGPUIntrinsic::r600_ddy:
- TextureOp = 9;
- break;
default:
- llvm_unreachable("Unknow Texture Operation");
+ llvm_unreachable("unhandled texture operation");
}
SDValue TexArgs[19] = {
@@ -785,12 +575,6 @@ SDValue R600TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const
case Intrinsic::r600_read_local_size_z:
return LowerImplicitParameter(DAG, VT, DL, 8);
- case Intrinsic::r600_read_workdim:
- case AMDGPUIntrinsic::AMDGPU_read_workdim: { // Legacy name.
- uint32_t ByteOffset = getImplicitParameterOffset(MFI, GRID_DIM);
- return LowerImplicitParameter(DAG, VT, DL, ByteOffset / 4);
- }
-
case Intrinsic::r600_read_tgid_x:
return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass,
AMDGPU::T1_X, VT);
@@ -836,9 +620,10 @@ void R600TargetLowering::ReplaceNodeResults(SDNode *N,
Results.push_back(lowerFP_TO_UINT(N->getOperand(0), DAG));
return;
}
- // Fall-through. Since we don't care about out of bounds values
- // we can use FP_TO_SINT for uints too. The DAGLegalizer code for uint
- // considers some extra cases which are not necessary here.
+ // Since we don't care about out of bounds values we can use FP_TO_SINT for
+ // uints too. The DAGLegalizer code for uint considers some extra cases
+ // which are not necessary here.
+ LLVM_FALLTHROUGH;
case ISD::FP_TO_SINT: {
if (N->getValueType(0) == MVT::i1) {
Results.push_back(lowerFP_TO_SINT(N->getOperand(0), DAG));
@@ -867,14 +652,12 @@ void R600TargetLowering::ReplaceNodeResults(SDNode *N,
SDValue R600TargetLowering::vectorToVerticalVector(SelectionDAG &DAG,
SDValue Vector) const {
-
SDLoc DL(Vector);
EVT VecVT = Vector.getValueType();
EVT EltVT = VecVT.getVectorElementType();
SmallVector<SDValue, 8> Args;
- for (unsigned i = 0, e = VecVT.getVectorNumElements();
- i != e; ++i) {
+ for (unsigned i = 0, e = VecVT.getVectorNumElements(); i != e; ++i) {
Args.push_back(DAG.getNode(
ISD::EXTRACT_VECTOR_ELT, DL, EltVT, Vector,
DAG.getConstant(i, DL, getVectorIdxTy(DAG.getDataLayout()))));
@@ -885,7 +668,6 @@ SDValue R600TargetLowering::vectorToVerticalVector(SelectionDAG &DAG,
SDValue R600TargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
SelectionDAG &DAG) const {
-
SDLoc DL(Op);
SDValue Vector = Op.getOperand(0);
SDValue Index = Op.getOperand(1);
@@ -919,7 +701,6 @@ SDValue R600TargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op,
SDValue R600TargetLowering::LowerGlobalAddress(AMDGPUMachineFunction *MFI,
SDValue Op,
SelectionDAG &DAG) const {
-
GlobalAddressSDNode *GSD = cast<GlobalAddressSDNode>(Op);
if (GSD->getAddressSpace() != AMDGPUAS::CONSTANT_ADDRESS)
return AMDGPUTargetLowering::LowerGlobalAddress(MFI, Op, DAG);
@@ -1318,90 +1099,158 @@ void R600TargetLowering::getStackAddress(unsigned StackWidth,
SDValue R600TargetLowering::lowerPrivateTruncStore(StoreSDNode *Store,
SelectionDAG &DAG) const {
SDLoc DL(Store);
+ //TODO: Who creates the i8 stores?
+ assert(Store->isTruncatingStore()
+ || Store->getValue().getValueType() == MVT::i8);
+ assert(Store->getAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS);
- unsigned Mask = 0;
+ SDValue Mask;
if (Store->getMemoryVT() == MVT::i8) {
- Mask = 0xff;
+ assert(Store->getAlignment() >= 1);
+ Mask = DAG.getConstant(0xff, DL, MVT::i32);
} else if (Store->getMemoryVT() == MVT::i16) {
- Mask = 0xffff;
+ assert(Store->getAlignment() >= 2);
+ Mask = DAG.getConstant(0xffff, DL, MVT::i32);;
+ } else {
+ llvm_unreachable("Unsupported private trunc store");
}
- SDValue Chain = Store->getChain();
+ SDValue OldChain = Store->getChain();
+ bool VectorTrunc = (OldChain.getOpcode() == AMDGPUISD::DUMMY_CHAIN);
+ // Skip dummy
+ SDValue Chain = VectorTrunc ? OldChain->getOperand(0) : OldChain;
SDValue BasePtr = Store->getBasePtr();
+ SDValue Offset = Store->getOffset();
EVT MemVT = Store->getMemoryVT();
- SDValue Ptr = DAG.getNode(ISD::SRL, DL, MVT::i32, BasePtr,
- DAG.getConstant(2, DL, MVT::i32));
- SDValue Dst = DAG.getNode(AMDGPUISD::REGISTER_LOAD, DL, MVT::i32,
- Chain, Ptr,
- DAG.getTargetConstant(0, DL, MVT::i32));
+ SDValue LoadPtr = BasePtr;
+ if (!Offset.isUndef()) {
+ LoadPtr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr, Offset);
+ }
+
+ // Get dword location
+ // TODO: this should be eliminated by the future SHR ptr, 2
+ SDValue Ptr = DAG.getNode(ISD::AND, DL, MVT::i32, LoadPtr,
+ DAG.getConstant(0xfffffffc, DL, MVT::i32));
+
+ // Load dword
+ // TODO: can we be smarter about machine pointer info?
+ SDValue Dst = DAG.getLoad(MVT::i32, DL, Chain, Ptr, MachinePointerInfo());
+
+ Chain = Dst.getValue(1);
- SDValue ByteIdx = DAG.getNode(ISD::AND, DL, MVT::i32, BasePtr,
+ // Get offset in dword
+ SDValue ByteIdx = DAG.getNode(ISD::AND, DL, MVT::i32, LoadPtr,
DAG.getConstant(0x3, DL, MVT::i32));
+ // Convert byte offset to bit shift
SDValue ShiftAmt = DAG.getNode(ISD::SHL, DL, MVT::i32, ByteIdx,
DAG.getConstant(3, DL, MVT::i32));
+ // TODO: Contrary to the name of the functiom,
+ // it also handles sub i32 non-truncating stores (like i1)
SDValue SExtValue = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i32,
Store->getValue());
+ // Mask the value to the right type
SDValue MaskedValue = DAG.getZeroExtendInReg(SExtValue, DL, MemVT);
+ // Shift the value in place
SDValue ShiftedValue = DAG.getNode(ISD::SHL, DL, MVT::i32,
MaskedValue, ShiftAmt);
- SDValue DstMask = DAG.getNode(ISD::SHL, DL, MVT::i32,
- DAG.getConstant(Mask, DL, MVT::i32),
- ShiftAmt);
- DstMask = DAG.getNode(ISD::XOR, DL, MVT::i32, DstMask,
- DAG.getConstant(0xffffffff, DL, MVT::i32));
+ // Shift the mask in place
+ SDValue DstMask = DAG.getNode(ISD::SHL, DL, MVT::i32, Mask, ShiftAmt);
+
+ // Invert the mask. NOTE: if we had native ROL instructions we could
+ // use inverted mask
+ DstMask = DAG.getNOT(DL, DstMask, MVT::i32);
+
+ // Cleanup the target bits
Dst = DAG.getNode(ISD::AND, DL, MVT::i32, Dst, DstMask);
+ // Add the new bits
SDValue Value = DAG.getNode(ISD::OR, DL, MVT::i32, Dst, ShiftedValue);
- return DAG.getNode(AMDGPUISD::REGISTER_STORE, DL, MVT::Other,
- Chain, Value, Ptr,
- DAG.getTargetConstant(0, DL, MVT::i32));
+
+ // Store dword
+ // TODO: Can we be smarter about MachinePointerInfo?
+ SDValue NewStore = DAG.getStore(Chain, DL, Value, Ptr, MachinePointerInfo());
+
+ // If we are part of expanded vector, make our neighbors depend on this store
+ if (VectorTrunc) {
+ // Make all other vector elements depend on this store
+ Chain = DAG.getNode(AMDGPUISD::DUMMY_CHAIN, DL, MVT::Other, NewStore);
+ DAG.ReplaceAllUsesOfValueWith(OldChain, Chain);
+ }
+ return NewStore;
}
SDValue R600TargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
- if (SDValue Result = AMDGPUTargetLowering::MergeVectorStore(Op, DAG))
- return Result;
-
StoreSDNode *StoreNode = cast<StoreSDNode>(Op);
unsigned AS = StoreNode->getAddressSpace();
+
+ SDValue Chain = StoreNode->getChain();
+ SDValue Ptr = StoreNode->getBasePtr();
SDValue Value = StoreNode->getValue();
- EVT ValueVT = Value.getValueType();
+ EVT VT = Value.getValueType();
+ EVT MemVT = StoreNode->getMemoryVT();
+ EVT PtrVT = Ptr.getValueType();
+
+ SDLoc DL(Op);
+
+ // Neither LOCAL nor PRIVATE can do vectors at the moment
if ((AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::PRIVATE_ADDRESS) &&
- ValueVT.isVector()) {
- return SplitVectorStore(Op, DAG);
+ VT.isVector()) {
+ if ((AS == AMDGPUAS::PRIVATE_ADDRESS) && StoreNode->isTruncatingStore()) {
+ // Add an extra level of chain to isolate this vector
+ SDValue NewChain = DAG.getNode(AMDGPUISD::DUMMY_CHAIN, DL, MVT::Other, Chain);
+ // TODO: can the chain be replaced without creating a new store?
+ SDValue NewStore = DAG.getTruncStore(
+ NewChain, DL, Value, Ptr, StoreNode->getPointerInfo(),
+ MemVT, StoreNode->getAlignment(),
+ StoreNode->getMemOperand()->getFlags(), StoreNode->getAAInfo());
+ StoreNode = cast<StoreSDNode>(NewStore);
+ }
+
+ return scalarizeVectorStore(StoreNode, DAG);
}
- SDLoc DL(Op);
- SDValue Chain = StoreNode->getChain();
- SDValue Ptr = StoreNode->getBasePtr();
+ unsigned Align = StoreNode->getAlignment();
+ if (Align < MemVT.getStoreSize() &&
+ !allowsMisalignedMemoryAccesses(MemVT, AS, Align, nullptr)) {
+ return expandUnalignedStore(StoreNode, DAG);
+ }
+
+ SDValue DWordAddr = DAG.getNode(ISD::SRL, DL, PtrVT, Ptr,
+ DAG.getConstant(2, DL, PtrVT));
if (AS == AMDGPUAS::GLOBAL_ADDRESS) {
+ // It is beneficial to create MSKOR here instead of combiner to avoid
+ // artificial dependencies introduced by RMW
if (StoreNode->isTruncatingStore()) {
- EVT VT = Value.getValueType();
assert(VT.bitsLE(MVT::i32));
- EVT MemVT = StoreNode->getMemoryVT();
SDValue MaskConstant;
if (MemVT == MVT::i8) {
MaskConstant = DAG.getConstant(0xFF, DL, MVT::i32);
} else {
assert(MemVT == MVT::i16);
+ assert(StoreNode->getAlignment() >= 2);
MaskConstant = DAG.getConstant(0xFFFF, DL, MVT::i32);
}
- SDValue DWordAddr = DAG.getNode(ISD::SRL, DL, VT, Ptr,
- DAG.getConstant(2, DL, MVT::i32));
- SDValue ByteIndex = DAG.getNode(ISD::AND, DL, Ptr.getValueType(), Ptr,
- DAG.getConstant(0x00000003, DL, VT));
+
+ SDValue ByteIndex = DAG.getNode(ISD::AND, DL, PtrVT, Ptr,
+ DAG.getConstant(0x00000003, DL, PtrVT));
+ SDValue BitShift = DAG.getNode(ISD::SHL, DL, VT, ByteIndex,
+ DAG.getConstant(3, DL, VT));
+
+ // Put the mask in correct place
+ SDValue Mask = DAG.getNode(ISD::SHL, DL, VT, MaskConstant, BitShift);
+
+ // Put the value bits in correct place
SDValue TruncValue = DAG.getNode(ISD::AND, DL, VT, Value, MaskConstant);
- SDValue Shift = DAG.getNode(ISD::SHL, DL, VT, ByteIndex,
- DAG.getConstant(3, DL, VT));
- SDValue ShiftedValue = DAG.getNode(ISD::SHL, DL, VT, TruncValue, Shift);
- SDValue Mask = DAG.getNode(ISD::SHL, DL, VT, MaskConstant, Shift);
+ SDValue ShiftedValue = DAG.getNode(ISD::SHL, DL, VT, TruncValue, BitShift);
+
// XXX: If we add a 64-bit ZW register class, then we could use a 2 x i32
// vector instead.
SDValue Src[4] = {
@@ -1415,12 +1264,9 @@ SDValue R600TargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
return DAG.getMemIntrinsicNode(AMDGPUISD::STORE_MSKOR, DL,
Op->getVTList(), Args, MemVT,
StoreNode->getMemOperand());
- } else if (Ptr->getOpcode() != AMDGPUISD::DWORDADDR &&
- ValueVT.bitsGE(MVT::i32)) {
+ } else if (Ptr->getOpcode() != AMDGPUISD::DWORDADDR && VT.bitsGE(MVT::i32)) {
// Convert pointer from byte address to dword address.
- Ptr = DAG.getNode(AMDGPUISD::DWORDADDR, DL, Ptr.getValueType(),
- DAG.getNode(ISD::SRL, DL, Ptr.getValueType(),
- Ptr, DAG.getConstant(2, DL, MVT::i32)));
+ Ptr = DAG.getNode(AMDGPUISD::DWORDADDR, DL, PtrVT, DWordAddr);
if (StoreNode->isTruncatingStore() || StoreNode->isIndexed()) {
llvm_unreachable("Truncated and indexed stores not supported yet");
@@ -1431,50 +1277,22 @@ SDValue R600TargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
}
}
+ // GLOBAL_ADDRESS has been handled above, LOCAL_ADDRESS allows all sizes
if (AS != AMDGPUAS::PRIVATE_ADDRESS)
return SDValue();
- EVT MemVT = StoreNode->getMemoryVT();
if (MemVT.bitsLT(MVT::i32))
return lowerPrivateTruncStore(StoreNode, DAG);
- // Lowering for indirect addressing
- const MachineFunction &MF = DAG.getMachineFunction();
- const R600FrameLowering *TFL = getSubtarget()->getFrameLowering();
- unsigned StackWidth = TFL->getStackWidth(MF);
-
- Ptr = stackPtrToRegIndex(Ptr, StackWidth, DAG);
-
- if (ValueVT.isVector()) {
- unsigned NumElemVT = ValueVT.getVectorNumElements();
- EVT ElemVT = ValueVT.getVectorElementType();
- SmallVector<SDValue, 4> Stores(NumElemVT);
-
- assert(NumElemVT >= StackWidth && "Stack width cannot be greater than "
- "vector width in load");
-
- for (unsigned i = 0; i < NumElemVT; ++i) {
- unsigned Channel, PtrIncr;
- getStackAddress(StackWidth, i, Channel, PtrIncr);
- Ptr = DAG.getNode(ISD::ADD, DL, MVT::i32, Ptr,
- DAG.getConstant(PtrIncr, DL, MVT::i32));
- SDValue Elem = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ElemVT,
- Value, DAG.getConstant(i, DL, MVT::i32));
-
- Stores[i] = DAG.getNode(AMDGPUISD::REGISTER_STORE, DL, MVT::Other,
- Chain, Elem, Ptr,
- DAG.getTargetConstant(Channel, DL, MVT::i32));
- }
- Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Stores);
- } else {
- if (ValueVT == MVT::i8) {
- Value = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i32, Value);
- }
- Chain = DAG.getNode(AMDGPUISD::REGISTER_STORE, DL, MVT::Other, Chain, Value, Ptr,
- DAG.getTargetConstant(0, DL, MVT::i32)); // Channel
+ // Standard i32+ store, tag it with DWORDADDR to note that the address
+ // has been shifted
+ if (Ptr.getOpcode() != AMDGPUISD::DWORDADDR) {
+ Ptr = DAG.getNode(AMDGPUISD::DWORDADDR, DL, PtrVT, DWordAddr);
+ return DAG.getStore(Chain, DL, Value, Ptr, StoreNode->getMemOperand());
}
- return Chain;
+ // Tagged i32+ stores will be matched by patterns
+ return SDValue();
}
// return (512 + (kc_bank << 12)
@@ -1524,51 +1342,50 @@ SDValue R600TargetLowering::lowerPrivateExtLoad(SDValue Op,
LoadSDNode *Load = cast<LoadSDNode>(Op);
ISD::LoadExtType ExtType = Load->getExtensionType();
EVT MemVT = Load->getMemoryVT();
+ assert(Load->getAlignment() >= MemVT.getStoreSize());
+
+ SDValue BasePtr = Load->getBasePtr();
+ SDValue Chain = Load->getChain();
+ SDValue Offset = Load->getOffset();
+
+ SDValue LoadPtr = BasePtr;
+ if (!Offset.isUndef()) {
+ LoadPtr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr, Offset);
+ }
- // <SI && AS=PRIVATE && EXTLOAD && size < 32bit,
- // register (2-)byte extract.
+ // Get dword location
+ // NOTE: this should be eliminated by the future SHR ptr, 2
+ SDValue Ptr = DAG.getNode(ISD::AND, DL, MVT::i32, LoadPtr,
+ DAG.getConstant(0xfffffffc, DL, MVT::i32));
- // Get Register holding the target.
- SDValue Ptr = DAG.getNode(ISD::SRL, DL, MVT::i32, Load->getBasePtr(),
- DAG.getConstant(2, DL, MVT::i32));
- // Load the Register.
- SDValue Ret = DAG.getNode(AMDGPUISD::REGISTER_LOAD, DL, Op.getValueType(),
- Load->getChain(),
- Ptr,
- DAG.getTargetConstant(0, DL, MVT::i32),
- Op.getOperand(2));
+ // Load dword
+ // TODO: can we be smarter about machine pointer info?
+ SDValue Read = DAG.getLoad(MVT::i32, DL, Chain, Ptr, MachinePointerInfo());
// Get offset within the register.
SDValue ByteIdx = DAG.getNode(ISD::AND, DL, MVT::i32,
- Load->getBasePtr(),
- DAG.getConstant(0x3, DL, MVT::i32));
+ LoadPtr, DAG.getConstant(0x3, DL, MVT::i32));
// Bit offset of target byte (byteIdx * 8).
SDValue ShiftAmt = DAG.getNode(ISD::SHL, DL, MVT::i32, ByteIdx,
DAG.getConstant(3, DL, MVT::i32));
// Shift to the right.
- Ret = DAG.getNode(ISD::SRL, DL, MVT::i32, Ret, ShiftAmt);
+ SDValue Ret = DAG.getNode(ISD::SRL, DL, MVT::i32, Read, ShiftAmt);
// Eliminate the upper bits by setting them to ...
EVT MemEltVT = MemVT.getScalarType();
- // ... ones.
- if (ExtType == ISD::SEXTLOAD) {
+ if (ExtType == ISD::SEXTLOAD) { // ... ones.
SDValue MemEltVTNode = DAG.getValueType(MemEltVT);
-
- SDValue Ops[] = {
- DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, Ret, MemEltVTNode),
- Load->getChain()
- };
-
- return DAG.getMergeValues(Ops, DL);
+ Ret = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i32, Ret, MemEltVTNode);
+ } else { // ... or zeros.
+ Ret = DAG.getZeroExtendInReg(Ret, DL, MemEltVT);
}
- // ... or zeros.
SDValue Ops[] = {
- DAG.getZeroExtendInReg(Ret, DL, MemEltVT),
- Load->getChain()
+ Ret,
+ Read.getValue(1) // This should be our output chain
};
return DAG.getMergeValues(Ops, DL);
@@ -1590,12 +1407,10 @@ SDValue R600TargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = LoadNode->getChain();
SDValue Ptr = LoadNode->getBasePtr();
- if (LoadNode->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS && VT.isVector()) {
- SDValue MergedValues[2] = {
- scalarizeVectorLoad(LoadNode, DAG),
- Chain
- };
- return DAG.getMergeValues(MergedValues, DL);
+ if ((LoadNode->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS ||
+ LoadNode->getAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS) &&
+ VT.isVector()) {
+ return scalarizeVectorLoad(LoadNode, DAG);
}
int ConstantBlock = ConstantAddressBlock(LoadNode->getAddressSpace());
@@ -1646,8 +1461,6 @@ SDValue R600TargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
return DAG.getMergeValues(MergedValues, DL);
}
- SDValue LoweredLoad;
-
// For most operations returning SDValue() will result in the node being
// expanded by the DAG Legalizer. This is not the case for ISD::LOAD, so we
// need to manually expand loads that may be legal in some address spaces and
@@ -1672,47 +1485,14 @@ SDValue R600TargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
return SDValue();
}
- // Lowering for indirect addressing
- const MachineFunction &MF = DAG.getMachineFunction();
- const R600FrameLowering *TFL = getSubtarget()->getFrameLowering();
- unsigned StackWidth = TFL->getStackWidth(MF);
-
- Ptr = stackPtrToRegIndex(Ptr, StackWidth, DAG);
-
- if (VT.isVector()) {
- unsigned NumElemVT = VT.getVectorNumElements();
- EVT ElemVT = VT.getVectorElementType();
- SDValue Loads[4];
-
- assert(NumElemVT <= 4);
- assert(NumElemVT >= StackWidth && "Stack width cannot be greater than "
- "vector width in load");
-
- for (unsigned i = 0; i < NumElemVT; ++i) {
- unsigned Channel, PtrIncr;
- getStackAddress(StackWidth, i, Channel, PtrIncr);
- Ptr = DAG.getNode(ISD::ADD, DL, MVT::i32, Ptr,
- DAG.getConstant(PtrIncr, DL, MVT::i32));
- Loads[i] = DAG.getNode(AMDGPUISD::REGISTER_LOAD, DL, ElemVT,
- Chain, Ptr,
- DAG.getTargetConstant(Channel, DL, MVT::i32),
- Op.getOperand(2));
- }
- EVT TargetVT = EVT::getVectorVT(*DAG.getContext(), ElemVT, NumElemVT);
- LoweredLoad = DAG.getBuildVector(TargetVT, DL, makeArrayRef(Loads, NumElemVT));
- } else {
- LoweredLoad = DAG.getNode(AMDGPUISD::REGISTER_LOAD, DL, VT,
- Chain, Ptr,
- DAG.getTargetConstant(0, DL, MVT::i32), // Channel
- Op.getOperand(2));
+ // DWORDADDR ISD marks already shifted address
+ if (Ptr.getOpcode() != AMDGPUISD::DWORDADDR) {
+ assert(VT == MVT::i32);
+ Ptr = DAG.getNode(ISD::SRL, DL, MVT::i32, Ptr, DAG.getConstant(2, DL, MVT::i32));
+ Ptr = DAG.getNode(AMDGPUISD::DWORDADDR, DL, MVT::i32, Ptr);
+ return DAG.getLoad(MVT::i32, DL, Chain, Ptr, LoadNode->getMemOperand());
}
-
- SDValue Ops[2] = {
- LoweredLoad,
- Chain
- };
-
- return DAG.getMergeValues(Ops, DL);
+ return SDValue();
}
SDValue R600TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
@@ -1754,9 +1534,11 @@ SDValue R600TargetLowering::LowerFormalArguments(
SmallVector<ISD::InputArg, 8> LocalIns;
- getOriginalFunctionArgs(DAG, MF.getFunction(), Ins, LocalIns);
-
- AnalyzeFormalArguments(CCInfo, LocalIns);
+ if (AMDGPU::isShader(CallConv)) {
+ AnalyzeFormalArguments(CCInfo, Ins);
+ } else {
+ analyzeFormalArgumentsCompute(CCInfo, Ins);
+ }
for (unsigned i = 0, e = Ins.size(); i < e; ++i) {
CCValAssign &VA = ArgLocs[i];
@@ -1800,18 +1582,19 @@ SDValue R600TargetLowering::LowerFormalArguments(
unsigned ValBase = ArgLocs[In.getOrigArgIndex()].getLocMemOffset();
unsigned PartOffset = VA.getLocMemOffset();
- unsigned Offset = 36 + VA.getLocMemOffset();
+ unsigned Offset = Subtarget->getExplicitKernelArgOffset(MF) + VA.getLocMemOffset();
MachinePointerInfo PtrInfo(UndefValue::get(PtrTy), PartOffset - ValBase);
SDValue Arg = DAG.getLoad(
ISD::UNINDEXED, Ext, VT, DL, Chain,
DAG.getConstant(Offset, DL, MVT::i32), DAG.getUNDEF(MVT::i32), PtrInfo,
- MemVT, /* Alignment = */ 4,
- MachineMemOperand::MONonTemporal | MachineMemOperand::MOInvariant);
+ MemVT, /* Alignment = */ 4, MachineMemOperand::MONonTemporal |
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
// 4 is the preferred alignment for the CONSTANT memory space.
InVals.push_back(Arg);
- MFI->ABIArgOffset = Offset + MemVT.getStoreSize();
+ MFI->setABIArgOffset(Offset + MemVT.getStoreSize());
}
return Chain;
}
@@ -1949,7 +1732,6 @@ SDValue R600TargetLowering::OptimizeSwizzle(SDValue BuildVector, SDValue Swz[4],
return BuildVector;
}
-
//===----------------------------------------------------------------------===//
// Custom DAG Optimizations
//===----------------------------------------------------------------------===//
@@ -1957,14 +1739,14 @@ SDValue R600TargetLowering::OptimizeSwizzle(SDValue BuildVector, SDValue Swz[4],
SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
switch (N->getOpcode()) {
- default: return AMDGPUTargetLowering::PerformDAGCombine(N, DCI);
// (f32 fp_round (f64 uint_to_fp a)) -> (f32 uint_to_fp a)
case ISD::FP_ROUND: {
SDValue Arg = N->getOperand(0);
if (Arg.getOpcode() == ISD::UINT_TO_FP && Arg.getValueType() == MVT::f64) {
- return DAG.getNode(ISD::UINT_TO_FP, SDLoc(N), N->getValueType(0),
+ return DAG.getNode(ISD::UINT_TO_FP, DL, N->getValueType(0),
Arg.getOperand(0));
}
break;
@@ -1989,12 +1771,11 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
return SDValue();
}
- SDLoc dl(N);
- return DAG.getNode(ISD::SELECT_CC, dl, N->getValueType(0),
+ return DAG.getNode(ISD::SELECT_CC, DL, N->getValueType(0),
SelectCC.getOperand(0), // LHS
SelectCC.getOperand(1), // RHS
- DAG.getConstant(-1, dl, MVT::i32), // True
- DAG.getConstant(0, dl, MVT::i32), // False
+ DAG.getConstant(-1, DL, MVT::i32), // True
+ DAG.getConstant(0, DL, MVT::i32), // False
SelectCC.getOperand(4)); // CC
break;
@@ -2006,7 +1787,6 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
SDValue InVec = N->getOperand(0);
SDValue InVal = N->getOperand(1);
SDValue EltNo = N->getOperand(2);
- SDLoc dl(N);
// If the inserted element is an UNDEF, just use the input vector.
if (InVal.isUndef())
@@ -2044,13 +1824,13 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
EVT OpVT = Ops[0].getValueType();
if (InVal.getValueType() != OpVT)
InVal = OpVT.bitsGT(InVal.getValueType()) ?
- DAG.getNode(ISD::ANY_EXTEND, dl, OpVT, InVal) :
- DAG.getNode(ISD::TRUNCATE, dl, OpVT, InVal);
+ DAG.getNode(ISD::ANY_EXTEND, DL, OpVT, InVal) :
+ DAG.getNode(ISD::TRUNCATE, DL, OpVT, InVal);
Ops[Elt] = InVal;
}
// Return the new vector
- return DAG.getBuildVector(VT, dl, Ops);
+ return DAG.getBuildVector(VT, DL, Ops);
}
// Extract_vec (Build_vector) generated by custom lowering
@@ -2064,11 +1844,13 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
}
}
if (Arg.getOpcode() == ISD::BITCAST &&
- Arg.getOperand(0).getOpcode() == ISD::BUILD_VECTOR) {
+ Arg.getOperand(0).getOpcode() == ISD::BUILD_VECTOR &&
+ (Arg.getOperand(0).getValueType().getVectorNumElements() ==
+ Arg.getValueType().getVectorNumElements())) {
if (ConstantSDNode *Const = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
unsigned Element = Const->getZExtValue();
- return DAG.getNode(ISD::BITCAST, SDLoc(N), N->getVTList(),
- Arg->getOperand(0).getOperand(Element));
+ return DAG.getNode(ISD::BITCAST, DL, N->getVTList(),
+ Arg->getOperand(0).getOperand(Element));
}
}
break;
@@ -2109,7 +1891,7 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
LHS.getOperand(0).getValueType().isInteger());
if (DCI.isBeforeLegalizeOps() ||
isCondCodeLegal(LHSCC, LHS.getOperand(0).getSimpleValueType()))
- return DAG.getSelectCC(SDLoc(N),
+ return DAG.getSelectCC(DL,
LHS.getOperand(0),
LHS.getOperand(1),
LHS.getOperand(2),
@@ -2121,7 +1903,7 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
return SDValue();
}
- case AMDGPUISD::EXPORT: {
+ case AMDGPUISD::R600_EXPORT: {
SDValue Arg = N->getOperand(1);
if (Arg.getOpcode() != ISD::BUILD_VECTOR)
break;
@@ -2136,9 +1918,8 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
N->getOperand(6), // SWZ_Z
N->getOperand(7) // SWZ_W
};
- SDLoc DL(N);
NewArgs[1] = OptimizeSwizzle(N->getOperand(1), &NewArgs[4], DAG, DL);
- return DAG.getNode(AMDGPUISD::EXPORT, DL, N->getVTList(), NewArgs);
+ return DAG.getNode(AMDGPUISD::R600_EXPORT, DL, N->getVTList(), NewArgs);
}
case AMDGPUISD::TEXTURE_FETCH: {
SDValue Arg = N->getOperand(1);
@@ -2166,10 +1947,10 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
N->getOperand(17),
N->getOperand(18),
};
- SDLoc DL(N);
NewArgs[1] = OptimizeSwizzle(N->getOperand(1), &NewArgs[2], DAG, DL);
return DAG.getNode(AMDGPUISD::TEXTURE_FETCH, DL, N->getVTList(), NewArgs);
}
+ default: break;
}
return AMDGPUTargetLowering::PerformDAGCombine(N, DCI);
@@ -2262,7 +2043,6 @@ bool R600TargetLowering::FoldOperand(SDNode *ParentNode, unsigned SrcIdx,
unsigned ImmReg = AMDGPU::ALU_LITERAL_X;
uint64_t ImmValue = 0;
-
if (Src.getMachineOpcode() == AMDGPU::MOV_IMM_F32) {
ConstantFPSDNode *FPC = dyn_cast<ConstantFPSDNode>(Src.getOperand(0));
float FloatValue = FPC->getValueAPF().convertToFloat();
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600InstrFormats.td b/contrib/llvm/lib/Target/AMDGPU/R600InstrFormats.td
index 0ffd485..68fcc54 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600InstrFormats.td
+++ b/contrib/llvm/lib/Target/AMDGPU/R600InstrFormats.td
@@ -210,14 +210,14 @@ class VTX_WORD0 {
bits<5> VC_INST;
bits<2> FETCH_TYPE;
bits<1> FETCH_WHOLE_QUAD;
- bits<8> BUFFER_ID;
+ bits<8> buffer_id;
bits<1> SRC_REL;
bits<2> SRC_SEL_X;
let Word0{4-0} = VC_INST;
let Word0{6-5} = FETCH_TYPE;
let Word0{7} = FETCH_WHOLE_QUAD;
- let Word0{15-8} = BUFFER_ID;
+ let Word0{15-8} = buffer_id;
let Word0{22-16} = src_gpr;
let Word0{23} = SRC_REL;
let Word0{25-24} = SRC_SEL_X;
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.cpp
index 1c5f7ec..e88bd07 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.cpp
@@ -320,12 +320,12 @@ R600InstrInfo::ExtractSrcs(MachineInstr &MI,
const DenseMap<unsigned, unsigned> &PV,
unsigned &ConstCount) const {
ConstCount = 0;
- ArrayRef<std::pair<MachineOperand *, int64_t>> Srcs = getSrcs(MI);
const std::pair<int, unsigned> DummyPair(-1, 0);
std::vector<std::pair<int, unsigned> > Result;
unsigned i = 0;
- for (unsigned n = Srcs.size(); i < n; ++i) {
- unsigned Reg = Srcs[i].first->getReg();
+ for (const auto &Src : getSrcs(MI)) {
+ ++i;
+ unsigned Reg = Src.first->getReg();
int Index = RI.getEncodingValue(Reg) & 0xff;
if (Reg == AMDGPU::OQAP) {
Result.push_back(std::make_pair(Index, 0U));
@@ -592,9 +592,7 @@ R600InstrInfo::fitsConstReadLimitations(const std::vector<MachineInstr *> &MIs)
if (!isALUInstr(MI.getOpcode()))
continue;
- ArrayRef<std::pair<MachineOperand *, int64_t>> Srcs = getSrcs(MI);
-
- for (const auto &Src:Srcs) {
+ for (const auto &Src : getSrcs(MI)) {
if (Src.first->getReg() == AMDGPU::ALU_LITERAL_X)
Literals.insert(Src.second);
if (Literals.size() > 4)
@@ -667,7 +665,7 @@ bool R600InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
// handled
if (isBranch(I->getOpcode()))
return true;
- if (!isJump(static_cast<MachineInstr *>(I)->getOpcode())) {
+ if (!isJump(I->getOpcode())) {
return false;
}
@@ -682,8 +680,7 @@ bool R600InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
// If there is only one terminator instruction, process it.
unsigned LastOpc = LastInst.getOpcode();
- if (I == MBB.begin() ||
- !isJump(static_cast<MachineInstr *>(--I)->getOpcode())) {
+ if (I == MBB.begin() || !isJump((--I)->getOpcode())) {
if (LastOpc == AMDGPU::JUMP) {
TBB = LastInst.getOperand(0).getMBB();
return false;
@@ -729,17 +726,19 @@ MachineBasicBlock::iterator FindLastAluClause(MachineBasicBlock &MBB) {
It != E; ++It) {
if (It->getOpcode() == AMDGPU::CF_ALU ||
It->getOpcode() == AMDGPU::CF_ALU_PUSH_BEFORE)
- return std::prev(It.base());
+ return It.getReverse();
}
return MBB.end();
}
-unsigned R600InstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned R600InstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
+ assert(!BytesAdded && "code size not handled");
if (!FBB) {
if (Cond.empty()) {
@@ -779,8 +778,9 @@ unsigned R600InstrInfo::InsertBranch(MachineBasicBlock &MBB,
}
}
-unsigned
-R600InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned R600InstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
// Note : we leave PRED* instructions there.
// They may be needed when predicating instructions.
@@ -910,20 +910,20 @@ R600InstrInfo::isProfitableToUnpredicate(MachineBasicBlock &TMBB,
bool
-R600InstrInfo::ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+R600InstrInfo::reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
MachineOperand &MO = Cond[1];
switch (MO.getImm()) {
- case OPCODE_IS_ZERO_INT:
- MO.setImm(OPCODE_IS_NOT_ZERO_INT);
+ case AMDGPU::PRED_SETE_INT:
+ MO.setImm(AMDGPU::PRED_SETNE_INT);
break;
- case OPCODE_IS_NOT_ZERO_INT:
- MO.setImm(OPCODE_IS_ZERO_INT);
+ case AMDGPU::PRED_SETNE_INT:
+ MO.setImm(AMDGPU::PRED_SETE_INT);
break;
- case OPCODE_IS_ZERO:
- MO.setImm(OPCODE_IS_NOT_ZERO);
+ case AMDGPU::PRED_SETE:
+ MO.setImm(AMDGPU::PRED_SETNE);
break;
- case OPCODE_IS_NOT_ZERO:
- MO.setImm(OPCODE_IS_ZERO);
+ case AMDGPU::PRED_SETNE:
+ MO.setImm(AMDGPU::PRED_SETE);
break;
default:
return true;
@@ -1160,10 +1160,10 @@ MachineInstrBuilder R600InstrInfo::buildIndirectRead(MachineBasicBlock *MBB,
int R600InstrInfo::getIndirectIndexBegin(const MachineFunction &MF) const {
const MachineRegisterInfo &MRI = MF.getRegInfo();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
int Offset = -1;
- if (MFI->getNumObjects() == 0) {
+ if (MFI.getNumObjects() == 0) {
return -1;
}
@@ -1195,14 +1195,14 @@ int R600InstrInfo::getIndirectIndexBegin(const MachineFunction &MF) const {
int R600InstrInfo::getIndirectIndexEnd(const MachineFunction &MF) const {
int Offset = 0;
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Variable sized objects are not supported
- if (MFI->hasVarSizedObjects()) {
+ if (MFI.hasVarSizedObjects()) {
return -1;
}
- if (MFI->getNumObjects() == 0) {
+ if (MFI.getNumObjects() == 0) {
return -1;
}
@@ -1481,11 +1481,3 @@ void R600InstrInfo::clearFlag(MachineInstr &MI, unsigned Operand,
FlagOp.setImm(InstFlags);
}
}
-
-bool R600InstrInfo::isRegisterStore(const MachineInstr &MI) const {
- return get(MI.getOpcode()).TSFlags & AMDGPU_FLAG_REGISTER_STORE;
-}
-
-bool R600InstrInfo::isRegisterLoad(const MachineInstr &MI) const {
- return get(MI.getOpcode()).TSFlags & AMDGPU_FLAG_REGISTER_LOAD;
-}
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.h b/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.h
index feaca98..a280052 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/R600InstrInfo.h
@@ -19,6 +19,14 @@
#include "R600RegisterInfo.h"
namespace llvm {
+
+namespace R600InstrFlags {
+enum : uint64_t {
+ REGISTER_STORE = UINT64_C(1) << 62,
+ REGISTER_LOAD = UINT64_C(1) << 63
+};
+}
+
class AMDGPUTargetMachine;
class DFAPacketizer;
class MachineFunction;
@@ -151,7 +159,7 @@ public:
DFAPacketizer *
CreateTargetScheduleState(const TargetSubtargetInfo &) const override;
- bool ReverseBranchCondition(
+ bool reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const override;
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
@@ -159,11 +167,13 @@ public:
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemvoed = nullptr) const override;
bool isPredicated(const MachineInstr &MI) const override;
@@ -301,8 +311,13 @@ public:
void clearFlag(MachineInstr &MI, unsigned Operand, unsigned Flag) const;
// Helper functions that check the opcode for status information
- bool isRegisterStore(const MachineInstr &MI) const;
- bool isRegisterLoad(const MachineInstr &MI) const;
+ bool isRegisterStore(const MachineInstr &MI) const {
+ return get(MI.getOpcode()).TSFlags & R600InstrFlags::REGISTER_STORE;
+ }
+
+ bool isRegisterLoad(const MachineInstr &MI) const {
+ return get(MI.getOpcode()).TSFlags & R600InstrFlags::REGISTER_LOAD;
+ }
};
namespace AMDGPU {
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600Instructions.td b/contrib/llvm/lib/Target/AMDGPU/R600Instructions.td
index b6b576d..9210e66 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600Instructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/R600Instructions.td
@@ -242,20 +242,6 @@ def TEX_SHADOW_ARRAY : PatLeaf<
}]
>;
-def TEX_MSAA : PatLeaf<
- (imm),
- [{uint32_t TType = (uint32_t)N->getZExtValue();
- return TType == 14;
- }]
->;
-
-def TEX_ARRAY_MSAA : PatLeaf<
- (imm),
- [{uint32_t TType = (uint32_t)N->getZExtValue();
- return TType == 15;
- }]
->;
-
class EG_CF_RAT <bits <8> cfinst, bits <6> ratinst, bits<4> ratid, bits<4> mask,
dag outs, dag ins, string asm, list<dag> pattern> :
InstR600ISA <outs, ins, asm, pattern>,
@@ -283,8 +269,8 @@ class EG_CF_RAT <bits <8> cfinst, bits <6> ratinst, bits<4> ratid, bits<4> mask,
}
-class VTX_READ <string name, bits<8> buffer_id, dag outs, list<dag> pattern>
- : InstR600ISA <outs, (ins MEMxi:$src_gpr), !strconcat(" ", name), pattern>,
+class VTX_READ <string name, dag outs, list<dag> pattern>
+ : InstR600ISA <outs, (ins MEMxi:$src_gpr, i8imm:$buffer_id), !strconcat(" ", name, ", #$buffer_id"), pattern>,
VTX_WORD1_GPR {
// Static fields
@@ -333,9 +319,9 @@ class LoadParamFrag <PatFrag load_type> : PatFrag <
(cast<LoadSDNode>(N)->getAddressSpace() == AMDGPUAS::PARAM_I_ADDRESS); }]
>;
-def load_param : LoadParamFrag<load>;
-def load_param_exti8 : LoadParamFrag<az_extloadi8>;
-def load_param_exti16 : LoadParamFrag<az_extloadi16>;
+def vtx_id3_az_extloadi8 : LoadParamFrag<az_extloadi8>;
+def vtx_id3_az_extloadi16 : LoadParamFrag<az_extloadi16>;
+def vtx_id3_load : LoadParamFrag<load>;
class LoadVtxId1 <PatFrag load> : PatFrag <
(ops node:$ptr), (load node:$ptr), [{
@@ -450,11 +436,6 @@ def INTERP_LOAD_P0 : R600_1OP <0xE0, "INTERP_LOAD_P0", []>;
// Export Instructions
//===----------------------------------------------------------------------===//
-def ExportType : SDTypeProfile<0, 7, [SDTCisFP<0>, SDTCisInt<1>]>;
-
-def EXPORT: SDNode<"AMDGPUISD::EXPORT", ExportType,
- [SDNPHasChain, SDNPSideEffect]>;
-
class ExportWord0 {
field bits<32> Word0;
@@ -500,7 +481,7 @@ class ExportBufWord1 {
}
multiclass ExportPattern<Instruction ExportInst, bits<8> cf_inst> {
- def : Pat<(EXPORT (v4f32 R600_Reg128:$src), (i32 imm:$base), (i32 imm:$type),
+ def : Pat<(R600_EXPORT (v4f32 R600_Reg128:$src), (i32 imm:$base), (i32 imm:$type),
(i32 imm:$swz_x), (i32 imm:$swz_y), (i32 imm:$swz_z), (i32 imm:$swz_w)),
(ExportInst R600_Reg128:$src, imm:$type, imm:$base,
imm:$swz_x, imm:$swz_y, imm:$swz_z, imm:$swz_w, cf_inst, 0)
@@ -746,6 +727,20 @@ def FLOOR : R600_1OP_Helper <0x14, "FLOOR", ffloor>;
def MOV : R600_1OP <0x19, "MOV", []>;
+
+// This is a hack to get rid of DUMMY_CHAIN nodes.
+// Most DUMMY_CHAINs should be eliminated during legalization, but undef
+// values can sneak in some to selection.
+let isPseudo = 1, isCodeGenOnly = 1 in {
+def DUMMY_CHAIN : AMDGPUInst <
+ (outs),
+ (ins),
+ "DUMMY_CHAIN",
+ [(R600dummy_chain)]
+>;
+} // end let isPseudo = 1, isCodeGenOnly = 1
+
+
let isPseudo = 1, isCodeGenOnly = 1, usesCustomInserter = 1 in {
class MOV_IMM <ValueType vt, Operand immType> : AMDGPUInst <
@@ -1073,18 +1068,27 @@ class LSHL_Common <bits<11> inst> : R600_2OP_Helper <inst, "LSHL", shl>;
class LSHR_Common <bits<11> inst> : R600_2OP_Helper <inst, "LSHR", srl>;
class ASHR_Common <bits<11> inst> : R600_2OP_Helper <inst, "ASHR", sra>;
class MULHI_INT_Common <bits<11> inst> : R600_2OP_Helper <
- inst, "MULHI_INT", mulhs
-> {
+ inst, "MULHI_INT", mulhs> {
let Itinerary = TransALU;
}
+
+class MULHI_INT24_Common <bits<11> inst> : R600_2OP_Helper <
+ inst, "MULHI_INT24", AMDGPUmulhi_i24> {
+ let Itinerary = VecALU;
+}
+
class MULHI_UINT_Common <bits<11> inst> : R600_2OP_Helper <
- inst, "MULHI", mulhu
-> {
+ inst, "MULHI", mulhu> {
let Itinerary = TransALU;
}
+
+class MULHI_UINT24_Common <bits<11> inst> : R600_2OP_Helper <
+ inst, "MULHI_UINT24", AMDGPUmulhi_u24> {
+ let Itinerary = VecALU;
+}
+
class MULLO_INT_Common <bits<11> inst> : R600_2OP_Helper <
- inst, "MULLO_INT", mul
-> {
+ inst, "MULLO_INT", mul> {
let Itinerary = TransALU;
}
class MULLO_UINT_Common <bits<11> inst> : R600_2OP <inst, "MULLO_UINT", []> {
@@ -1278,6 +1282,17 @@ let Predicates = [isR600] in {
defm R600_ : RegisterLoadStore <R600_Reg32, FRAMEri, ADDRIndirect>;
+// Hardcode channel to 0
+// NOTE: LSHR is not available here. LSHR is per family instruction
+def : Pat <
+ (i32 (load_private ADDRIndirect:$addr) ),
+ (R600_RegisterLoad FRAMEri:$addr, (i32 0))
+>;
+def : Pat <
+ (store_private i32:$val, ADDRIndirect:$addr),
+ (R600_RegisterStore i32:$val, FRAMEri:$addr, (i32 0))
+>;
+
//===----------------------------------------------------------------------===//
// Pseudo instructions
@@ -1366,8 +1381,8 @@ def CONST_COPY : Instruction {
} // end usesCustomInserter = 1, isCodeGenOnly = 1, isPseudo = 1, Namespace = "AMDGPU"
def TEX_VTX_CONSTBUF :
- InstR600ISA <(outs R600_Reg128:$dst), (ins MEMxi:$ptr, i32imm:$BUFFER_ID), "VTX_READ_eg $dst, $ptr",
- [(set v4i32:$dst, (CONST_ADDRESS ADDRGA_VAR_OFFSET:$ptr, (i32 imm:$BUFFER_ID)))]>,
+ InstR600ISA <(outs R600_Reg128:$dst), (ins MEMxi:$ptr, i32imm:$buffer_id), "VTX_READ_eg $dst, $ptr",
+ [(set v4i32:$dst, (CONST_ADDRESS ADDRGA_VAR_OFFSET:$ptr, (i32 imm:$buffer_id)))]>,
VTX_WORD1_GPR, VTX_WORD0_eg {
let VC_INST = 0;
@@ -1420,7 +1435,7 @@ def TEX_VTX_CONSTBUF :
}
def TEX_VTX_TEXBUF:
- InstR600ISA <(outs R600_Reg128:$dst), (ins MEMxi:$ptr, i32imm:$BUFFER_ID), "TEX_VTX_EXPLICIT_READ $dst, $ptr">,
+ InstR600ISA <(outs R600_Reg128:$dst), (ins MEMxi:$ptr, i32imm:$buffer_id), "TEX_VTX_EXPLICIT_READ $dst, $ptr">,
VTX_WORD1_GPR, VTX_WORD0_eg {
let VC_INST = 0;
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.cpp
index 01105c6..3ca319c 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.cpp
@@ -12,9 +12,5 @@
using namespace llvm;
-
-// Pin the vtable to this file.
-void R600MachineFunctionInfo::anchor() {}
-
R600MachineFunctionInfo::R600MachineFunctionInfo(const MachineFunction &MF)
: AMDGPUMachineFunction(MF) { }
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.h b/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.h
index 04a4436..29ac092 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/R600MachineFunctionInfo.h
@@ -14,18 +14,13 @@
#define LLVM_LIB_TARGET_AMDGPU_R600MACHINEFUNCTIONINFO_H
#include "AMDGPUMachineFunction.h"
-#include "llvm/CodeGen/SelectionDAG.h"
-#include <vector>
namespace llvm {
class R600MachineFunctionInfo final : public AMDGPUMachineFunction {
- void anchor() override;
public:
R600MachineFunctionInfo(const MachineFunction &MF);
- SmallVector<unsigned, 4> LiveOuts;
- std::vector<unsigned> IndirectRegs;
- unsigned StackSize;
+ unsigned CFStackSize;
};
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600MachineScheduler.h b/contrib/llvm/lib/Target/AMDGPU/R600MachineScheduler.h
index 16d5d93..9a67705 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600MachineScheduler.h
+++ b/contrib/llvm/lib/Target/AMDGPU/R600MachineScheduler.h
@@ -16,6 +16,7 @@
#define LLVM_LIB_TARGET_AMDGPU_R600MACHINESCHEDULER_H
#include "llvm/CodeGen/MachineScheduler.h"
+#include <vector>
using namespace llvm;
@@ -25,10 +26,10 @@ class R600InstrInfo;
struct R600RegisterInfo;
class R600SchedStrategy final : public MachineSchedStrategy {
- const ScheduleDAGMILive *DAG;
- const R600InstrInfo *TII;
- const R600RegisterInfo *TRI;
- MachineRegisterInfo *MRI;
+ const ScheduleDAGMILive *DAG = nullptr;
+ const R600InstrInfo *TII = nullptr;
+ const R600RegisterInfo *TRI = nullptr;
+ MachineRegisterInfo *MRI = nullptr;
enum InstKind {
IDAlu,
@@ -66,11 +67,8 @@ class R600SchedStrategy final : public MachineSchedStrategy {
int OccupedSlotsMask;
public:
- R600SchedStrategy() :
- DAG(nullptr), TII(nullptr), TRI(nullptr), MRI(nullptr) {
- }
-
- virtual ~R600SchedStrategy() {}
+ R600SchedStrategy() = default;
+ ~R600SchedStrategy() override = default;
void initialize(ScheduleDAGMI *dag) override;
SUnit *pickNode(bool &IsTopNode) override;
@@ -97,6 +95,6 @@ private:
void MoveUnits(std::vector<SUnit *> &QSrc, std::vector<SUnit *> &QDst);
};
-} // namespace llvm
+} // end namespace llvm
-#endif /* R600MACHINESCHEDULER_H_ */
+#endif // LLVM_LIB_TARGET_AMDGPU_R600MACHINESCHEDULER_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp b/contrib/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp
index ecae27d..d90008a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600OptimizeVectorRegisters.cpp
@@ -31,22 +31,31 @@
#include "AMDGPUSubtarget.h"
#include "R600Defines.h"
#include "R600InstrInfo.h"
-#include "llvm/CodeGen/DFAPacketizer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/PassAnalysisSupport.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <utility>
+#include <vector>
using namespace llvm;
#define DEBUG_TYPE "vec-merger"
-namespace {
-
static bool
isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) {
for (MachineRegisterInfo::def_instr_iterator It = MRI.def_instr_begin(Reg),
@@ -60,11 +69,14 @@ isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) {
return false;
}
+namespace {
+
class RegSeqInfo {
public:
MachineInstr *Instr;
DenseMap<unsigned, unsigned> RegToChan;
std::vector<unsigned> UndefReg;
+
RegSeqInfo(MachineRegisterInfo &MRI, MachineInstr *MI) : Instr(MI) {
assert(MI->getOpcode() == AMDGPU::REG_SEQUENCE);
for (unsigned i = 1, e = Instr->getNumOperands(); i < e; i+=2) {
@@ -76,7 +88,8 @@ public:
RegToChan[MO.getReg()] = Chan;
}
}
- RegSeqInfo() {}
+
+ RegSeqInfo() = default;
bool operator==(const RegSeqInfo &RSI) const {
return RSI.Instr == Instr;
@@ -87,28 +100,30 @@ class R600VectorRegMerger : public MachineFunctionPass {
private:
MachineRegisterInfo *MRI;
const R600InstrInfo *TII;
- bool canSwizzle(const MachineInstr &) const;
+
+ bool canSwizzle(const MachineInstr &MI) const;
bool areAllUsesSwizzeable(unsigned Reg) const;
void SwizzleInput(MachineInstr &,
- const std::vector<std::pair<unsigned, unsigned> > &) const;
- bool tryMergeVector(const RegSeqInfo *, RegSeqInfo *,
- std::vector<std::pair<unsigned, unsigned> > &Remap) const;
+ const std::vector<std::pair<unsigned, unsigned>> &RemapChan) const;
+ bool tryMergeVector(const RegSeqInfo *Untouched, RegSeqInfo *ToMerge,
+ std::vector<std::pair<unsigned, unsigned>> &Remap) const;
bool tryMergeUsingCommonSlot(RegSeqInfo &RSI, RegSeqInfo &CompatibleRSI,
- std::vector<std::pair<unsigned, unsigned> > &RemapChan);
+ std::vector<std::pair<unsigned, unsigned>> &RemapChan);
bool tryMergeUsingFreeSlot(RegSeqInfo &RSI, RegSeqInfo &CompatibleRSI,
- std::vector<std::pair<unsigned, unsigned> > &RemapChan);
- MachineInstr *RebuildVector(RegSeqInfo *MI,
- const RegSeqInfo *BaseVec,
- const std::vector<std::pair<unsigned, unsigned> > &RemapChan) const;
+ std::vector<std::pair<unsigned, unsigned>> &RemapChan);
+ MachineInstr *RebuildVector(RegSeqInfo *MI, const RegSeqInfo *BaseVec,
+ const std::vector<std::pair<unsigned, unsigned>> &RemapChan) const;
void RemoveMI(MachineInstr *);
void trackRSI(const RegSeqInfo &RSI);
- typedef DenseMap<unsigned, std::vector<MachineInstr *> > InstructionSetMap;
+ typedef DenseMap<unsigned, std::vector<MachineInstr *>> InstructionSetMap;
DenseMap<MachineInstr *, RegSeqInfo> PreviousRegSeq;
InstructionSetMap PreviousRegSeqByReg;
InstructionSetMap PreviousRegSeqByUndefCount;
+
public:
static char ID;
+
R600VectorRegMerger(TargetMachine &tm) : MachineFunctionPass(ID),
TII(nullptr) { }
@@ -121,13 +136,15 @@ public:
MachineFunctionPass::getAnalysisUsage(AU);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "R600 Vector Registers Merge Pass";
}
bool runOnMachineFunction(MachineFunction &Fn) override;
};
+} // end anonymous namespace.
+
char R600VectorRegMerger::ID = 0;
bool R600VectorRegMerger::canSwizzle(const MachineInstr &MI)
@@ -144,7 +161,7 @@ bool R600VectorRegMerger::canSwizzle(const MachineInstr &MI)
}
bool R600VectorRegMerger::tryMergeVector(const RegSeqInfo *Untouched,
- RegSeqInfo *ToMerge, std::vector< std::pair<unsigned, unsigned> > &Remap)
+ RegSeqInfo *ToMerge, std::vector< std::pair<unsigned, unsigned>> &Remap)
const {
unsigned CurrentUndexIdx = 0;
for (DenseMap<unsigned, unsigned>::iterator It = ToMerge->RegToChan.begin(),
@@ -167,7 +184,7 @@ bool R600VectorRegMerger::tryMergeVector(const RegSeqInfo *Untouched,
static
unsigned getReassignedChan(
- const std::vector<std::pair<unsigned, unsigned> > &RemapChan,
+ const std::vector<std::pair<unsigned, unsigned>> &RemapChan,
unsigned Chan) {
for (unsigned j = 0, je = RemapChan.size(); j < je; j++) {
if (RemapChan[j].first == Chan)
@@ -178,7 +195,7 @@ unsigned getReassignedChan(
MachineInstr *R600VectorRegMerger::RebuildVector(
RegSeqInfo *RSI, const RegSeqInfo *BaseRSI,
- const std::vector<std::pair<unsigned, unsigned> > &RemapChan) const {
+ const std::vector<std::pair<unsigned, unsigned>> &RemapChan) const {
unsigned Reg = RSI->Instr->getOperand(0).getReg();
MachineBasicBlock::iterator Pos = RSI->Instr;
MachineBasicBlock &MBB = *Pos->getParent();
@@ -200,12 +217,10 @@ MachineInstr *R600VectorRegMerger::RebuildVector(
.addReg(SubReg)
.addImm(Chan);
UpdatedRegToChan[SubReg] = Chan;
- std::vector<unsigned>::iterator ChanPos =
- std::find(UpdatedUndef.begin(), UpdatedUndef.end(), Chan);
+ std::vector<unsigned>::iterator ChanPos = llvm::find(UpdatedUndef, Chan);
if (ChanPos != UpdatedUndef.end())
UpdatedUndef.erase(ChanPos);
- assert(std::find(UpdatedUndef.begin(), UpdatedUndef.end(), Chan) ==
- UpdatedUndef.end() &&
+ assert(!is_contained(UpdatedUndef, Chan) &&
"UpdatedUndef shouldn't contain Chan more than once!");
DEBUG(dbgs() << " ->"; Tmp->dump(););
(void)Tmp;
@@ -236,17 +251,17 @@ void R600VectorRegMerger::RemoveMI(MachineInstr *MI) {
for (InstructionSetMap::iterator It = PreviousRegSeqByReg.begin(),
E = PreviousRegSeqByReg.end(); It != E; ++It) {
std::vector<MachineInstr *> &MIs = (*It).second;
- MIs.erase(std::find(MIs.begin(), MIs.end(), MI), MIs.end());
+ MIs.erase(llvm::find(MIs, MI), MIs.end());
}
for (InstructionSetMap::iterator It = PreviousRegSeqByUndefCount.begin(),
E = PreviousRegSeqByUndefCount.end(); It != E; ++It) {
std::vector<MachineInstr *> &MIs = (*It).second;
- MIs.erase(std::find(MIs.begin(), MIs.end(), MI), MIs.end());
+ MIs.erase(llvm::find(MIs, MI), MIs.end());
}
}
void R600VectorRegMerger::SwizzleInput(MachineInstr &MI,
- const std::vector<std::pair<unsigned, unsigned> > &RemapChan) const {
+ const std::vector<std::pair<unsigned, unsigned>> &RemapChan) const {
unsigned Offset;
if (TII->get(MI.getOpcode()).TSFlags & R600_InstFlag::TEX_INST)
Offset = 2;
@@ -274,7 +289,7 @@ bool R600VectorRegMerger::areAllUsesSwizzeable(unsigned Reg) const {
bool R600VectorRegMerger::tryMergeUsingCommonSlot(RegSeqInfo &RSI,
RegSeqInfo &CompatibleRSI,
- std::vector<std::pair<unsigned, unsigned> > &RemapChan) {
+ std::vector<std::pair<unsigned, unsigned>> &RemapChan) {
for (MachineInstr::mop_iterator MOp = RSI.Instr->operands_begin(),
MOE = RSI.Instr->operands_end(); MOp != MOE; ++MOp) {
if (!MOp->isReg())
@@ -294,7 +309,7 @@ bool R600VectorRegMerger::tryMergeUsingCommonSlot(RegSeqInfo &RSI,
bool R600VectorRegMerger::tryMergeUsingFreeSlot(RegSeqInfo &RSI,
RegSeqInfo &CompatibleRSI,
- std::vector<std::pair<unsigned, unsigned> > &RemapChan) {
+ std::vector<std::pair<unsigned, unsigned>> &RemapChan) {
unsigned NeededUndefs = 4 - RSI.UndefReg.size();
if (PreviousRegSeqByUndefCount[NeededUndefs].empty())
return false;
@@ -357,7 +372,7 @@ bool R600VectorRegMerger::runOnMachineFunction(MachineFunction &Fn) {
});
RegSeqInfo CandidateRSI;
- std::vector<std::pair<unsigned, unsigned> > RemapChan;
+ std::vector<std::pair<unsigned, unsigned>> RemapChan;
DEBUG(dbgs() << "Using common slots...\n";);
if (tryMergeUsingCommonSlot(RSI, CandidateRSI, RemapChan)) {
// Remove CandidateRSI mapping
@@ -381,8 +396,6 @@ bool R600VectorRegMerger::runOnMachineFunction(MachineFunction &Fn) {
return false;
}
-}
-
llvm::FunctionPass *llvm::createR600VectorRegMerger(TargetMachine &tm) {
return new R600VectorRegMerger(tm);
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/R600Packetizer.cpp b/contrib/llvm/lib/Target/AMDGPU/R600Packetizer.cpp
index c848664..5b6dd1e 100644
--- a/contrib/llvm/lib/Target/AMDGPU/R600Packetizer.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/R600Packetizer.cpp
@@ -47,9 +47,7 @@ public:
MachineFunctionPass::getAnalysisUsage(AU);
}
- const char *getPassName() const override {
- return "R600 Packetizer";
- }
+ StringRef getPassName() const override { return "R600 Packetizer"; }
bool runOnMachineFunction(MachineFunction &Fn) override;
};
@@ -283,7 +281,7 @@ public:
return false;
}
- // We cannot read LDS source registrs from the Trans slot.
+ // We cannot read LDS source registers from the Trans slot.
if (isTransSlot && TII->readsLDSSrcReg(MI))
return false;
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIAnnotateControlFlow.cpp b/contrib/llvm/lib/Target/AMDGPU/SIAnnotateControlFlow.cpp
index 5f182c5..d70f52e 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIAnnotateControlFlow.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIAnnotateControlFlow.cpp
@@ -102,9 +102,7 @@ public:
bool runOnFunction(Function &F) override;
- const char *getPassName() const override {
- return "SI annotate control flow";
- }
+ StringRef getPassName() const override { return "SI annotate control flow"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LoopInfoWrapperPass>();
@@ -148,12 +146,15 @@ bool SIAnnotateControlFlow::doInitialization(Module &M) {
Break = M.getOrInsertFunction(
BreakIntrinsic, Int64, Int64, (Type *)nullptr);
+ cast<Function>(Break)->setDoesNotAccessMemory();
IfBreak = M.getOrInsertFunction(
IfBreakIntrinsic, Int64, Boolean, Int64, (Type *)nullptr);
+ cast<Function>(IfBreak)->setDoesNotAccessMemory();;
ElseBreak = M.getOrInsertFunction(
ElseBreakIntrinsic, Int64, Int64, Int64, (Type *)nullptr);
+ cast<Function>(ElseBreak)->setDoesNotAccessMemory();
Loop = M.getOrInsertFunction(
LoopIntrinsic, Boolean, Int64, (Type *)nullptr);
@@ -331,6 +332,8 @@ void SIAnnotateControlFlow::handleLoop(BranchInst *Term) {
BasicBlock *BB = Term->getParent();
llvm::Loop *L = LI->getLoopFor(BB);
+ if (!L)
+ return;
BasicBlock *Target = Term->getSuccessor(1);
PHINode *Broken = PHINode::Create(Int64, 0, "", &Target->front());
@@ -361,7 +364,7 @@ void SIAnnotateControlFlow::closeControlFlow(BasicBlock *BB) {
std::vector<BasicBlock*> Preds;
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) {
- if (std::find(Latches.begin(), Latches.end(), *PI) == Latches.end())
+ if (!is_contained(Latches, *PI))
Preds.push_back(*PI);
}
BB = llvm::SplitBlockPredecessors(BB, Preds, "endcf.split", DT, LI, false);
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIDebuggerInsertNops.cpp b/contrib/llvm/lib/Target/AMDGPU/SIDebuggerInsertNops.cpp
index 65ceff3..62ebef8 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIDebuggerInsertNops.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIDebuggerInsertNops.cpp
@@ -38,7 +38,7 @@ public:
static char ID;
SIDebuggerInsertNops() : MachineFunctionPass(ID) { }
- const char *getPassName() const override { return PASS_NAME; }
+ StringRef getPassName() const override { return PASS_NAME; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIDefines.h b/contrib/llvm/lib/Target/AMDGPU/SIDefines.h
index f4b04e3..ff4e321 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIDefines.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIDefines.h
@@ -13,76 +13,111 @@
#ifndef LLVM_LIB_TARGET_AMDGPU_SIDEFINES_H
#define LLVM_LIB_TARGET_AMDGPU_SIDEFINES_H
+namespace llvm {
+
namespace SIInstrFlags {
// This needs to be kept in sync with the field bits in InstSI.
-enum {
- SALU = 1 << 3,
- VALU = 1 << 4,
-
- SOP1 = 1 << 5,
- SOP2 = 1 << 6,
- SOPC = 1 << 7,
- SOPK = 1 << 8,
- SOPP = 1 << 9,
-
- VOP1 = 1 << 10,
- VOP2 = 1 << 11,
- VOP3 = 1 << 12,
- VOPC = 1 << 13,
+enum : uint64_t {
+ // Low bits - basic encoding information.
+ SALU = 1 << 0,
+ VALU = 1 << 1,
+
+ // SALU instruction formats.
+ SOP1 = 1 << 2,
+ SOP2 = 1 << 3,
+ SOPC = 1 << 4,
+ SOPK = 1 << 5,
+ SOPP = 1 << 6,
+
+ // VALU instruction formats.
+ VOP1 = 1 << 7,
+ VOP2 = 1 << 8,
+ VOPC = 1 << 9,
+
+ // TODO: Should this be spilt into VOP3 a and b?
+ VOP3 = 1 << 10,
+
+ VINTRP = 1 << 13,
SDWA = 1 << 14,
DPP = 1 << 15,
+ // Memory instruction formats.
MUBUF = 1 << 16,
MTBUF = 1 << 17,
SMRD = 1 << 18,
- DS = 1 << 19,
- MIMG = 1 << 20,
+ MIMG = 1 << 19,
+ EXP = 1 << 20,
FLAT = 1 << 21,
- WQM = 1 << 22,
+ DS = 1 << 22,
+
+ // Pseudo instruction formats.
VGPRSpill = 1 << 23,
- VOPAsmPrefer32Bit = 1 << 24,
- Gather4 = 1 << 25,
- DisableWQM = 1 << 26
+ SGPRSpill = 1 << 24,
+
+ // High bits - other information.
+ VM_CNT = UINT64_C(1) << 32,
+ EXP_CNT = UINT64_C(1) << 33,
+ LGKM_CNT = UINT64_C(1) << 34,
+
+ WQM = UINT64_C(1) << 35,
+ DisableWQM = UINT64_C(1) << 36,
+ Gather4 = UINT64_C(1) << 37,
+ SOPK_ZEXT = UINT64_C(1) << 38,
+ SCALAR_STORE = UINT64_C(1) << 39,
+ FIXED_SIZE = UINT64_C(1) << 40,
+ VOPAsmPrefer32Bit = UINT64_C(1) << 41
+
+};
+
+// v_cmp_class_* etc. use a 10-bit mask for what operation is checked.
+// The result is true if any of these tests are true.
+enum ClassFlags {
+ S_NAN = 1 << 0, // Signaling NaN
+ Q_NAN = 1 << 1, // Quiet NaN
+ N_INFINITY = 1 << 2, // Negative infinity
+ N_NORMAL = 1 << 3, // Negative normal
+ N_SUBNORMAL = 1 << 4, // Negative subnormal
+ N_ZERO = 1 << 5, // Negative zero
+ P_ZERO = 1 << 6, // Positive zero
+ P_SUBNORMAL = 1 << 7, // Positive subnormal
+ P_NORMAL = 1 << 8, // Positive normal
+ P_INFINITY = 1 << 9 // Positive infinity
};
}
-namespace llvm {
namespace AMDGPU {
enum OperandType {
- /// Operand with register or 32-bit immediate
- OPERAND_REG_IMM32 = MCOI::OPERAND_FIRST_TARGET,
- /// Operand with register or inline constant
- OPERAND_REG_INLINE_C,
-
- /// Operand with 32-bit immediate that uses the constant bus. The standard
- /// OPERAND_IMMEDIATE should be used for special immediates such as source
- /// modifiers.
- OPERAND_KIMM32
- };
-}
-}
-
-namespace SIInstrFlags {
- enum Flags {
- // First 4 bits are the instruction encoding
- VM_CNT = 1 << 0,
- EXP_CNT = 1 << 1,
- LGKM_CNT = 1 << 2
- };
-
- // v_cmp_class_* etc. use a 10-bit mask for what operation is checked.
- // The result is true if any of these tests are true.
- enum ClassFlags {
- S_NAN = 1 << 0, // Signaling NaN
- Q_NAN = 1 << 1, // Quiet NaN
- N_INFINITY = 1 << 2, // Negative infinity
- N_NORMAL = 1 << 3, // Negative normal
- N_SUBNORMAL = 1 << 4, // Negative subnormal
- N_ZERO = 1 << 5, // Negative zero
- P_ZERO = 1 << 6, // Positive zero
- P_SUBNORMAL = 1 << 7, // Positive subnormal
- P_NORMAL = 1 << 8, // Positive normal
- P_INFINITY = 1 << 9 // Positive infinity
+ /// Operands with register or 32-bit immediate
+ OPERAND_REG_IMM_INT32 = MCOI::OPERAND_FIRST_TARGET,
+ OPERAND_REG_IMM_INT64,
+ OPERAND_REG_IMM_INT16,
+ OPERAND_REG_IMM_FP32,
+ OPERAND_REG_IMM_FP64,
+ OPERAND_REG_IMM_FP16,
+
+ /// Operands with register or inline constant
+ OPERAND_REG_INLINE_C_INT16,
+ OPERAND_REG_INLINE_C_INT32,
+ OPERAND_REG_INLINE_C_INT64,
+ OPERAND_REG_INLINE_C_FP16,
+ OPERAND_REG_INLINE_C_FP32,
+ OPERAND_REG_INLINE_C_FP64,
+
+ OPERAND_REG_IMM_FIRST = OPERAND_REG_IMM_INT32,
+ OPERAND_REG_IMM_LAST = OPERAND_REG_IMM_FP16,
+
+ OPERAND_REG_INLINE_C_FIRST = OPERAND_REG_INLINE_C_INT16,
+ OPERAND_REG_INLINE_C_LAST = OPERAND_REG_INLINE_C_FP64,
+
+ OPERAND_SRC_FIRST = OPERAND_REG_IMM_INT32,
+ OPERAND_SRC_LAST = OPERAND_REG_INLINE_C_LAST,
+
+ // Operand for source modifiers for VOP instructions
+ OPERAND_INPUT_MODS,
+
+ /// Operand with 32-bit immediate that uses the constant bus.
+ OPERAND_KIMM32,
+ OPERAND_KIMM16
};
}
@@ -105,7 +140,24 @@ namespace SIOutMods {
};
}
-namespace llvm {
+namespace VGPRIndexMode {
+ enum {
+ SRC0_ENABLE = 1 << 0,
+ SRC1_ENABLE = 1 << 1,
+ SRC2_ENABLE = 1 << 2,
+ DST_ENABLE = 1 << 3
+ };
+}
+
+namespace AMDGPUAsmVariants {
+ enum {
+ DEFAULT = 0,
+ VOP3 = 1,
+ SDWA = 2,
+ DPP = 3
+ };
+}
+
namespace AMDGPU {
namespace EncValues { // Encoding values of enum9/8/7 operands
@@ -126,9 +178,7 @@ enum {
} // namespace EncValues
} // namespace AMDGPU
-} // namespace llvm
-namespace llvm {
namespace AMDGPU {
namespace SendMsg { // Encoding of SIMM16 used in s_sendmsg* insns.
@@ -184,6 +234,13 @@ namespace Hwreg { // Encoding of SIMM16 used in s_setreg/getreg* insns.
enum Id { // HwRegCode, (6) [5:0]
ID_UNKNOWN_ = -1,
ID_SYMBOLIC_FIRST_ = 1, // There are corresponding symbolic names defined.
+ ID_MODE = 1,
+ ID_STATUS = 2,
+ ID_TRAPSTS = 3,
+ ID_HW_ID = 4,
+ ID_GPR_ALLOC = 5,
+ ID_LDS_ALLOC = 6,
+ ID_IB_STS = 7,
ID_SYMBOLIC_LAST_ = 8,
ID_SHIFT_ = 0,
ID_WIDTH_ = 6,
@@ -205,8 +262,27 @@ enum WidthMinusOne { // WidthMinusOne, (5) [15:11]
};
} // namespace Hwreg
+
+namespace SDWA {
+
+enum SdwaSel {
+ BYTE_0 = 0,
+ BYTE_1 = 1,
+ BYTE_2 = 2,
+ BYTE_3 = 3,
+ WORD_0 = 4,
+ WORD_1 = 5,
+ DWORD = 6,
+};
+
+enum DstUnused {
+ UNUSED_PAD = 0,
+ UNUSED_SEXT = 1,
+ UNUSED_PRESERVE = 2,
+};
+
+} // namespace SDWA
} // namespace AMDGPU
-} // namespace llvm
#define R_00B028_SPI_SHADER_PGM_RSRC1_PS 0x00B028
#define R_00B02C_SPI_SHADER_PGM_RSRC2_PS 0x00B02C
@@ -312,4 +388,6 @@ enum WidthMinusOne { // WidthMinusOne, (5) [15:11]
#define R_SPILLED_SGPRS 0x4
#define R_SPILLED_VGPRS 0x8
+} // End namespace llvm
+
#endif
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp
index 636750d..d4d3959 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp
@@ -37,9 +37,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Fix CF Live Intervals";
- }
+ StringRef getPassName() const override { return "SI Fix CF Live Intervals"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LiveIntervals>();
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp
index 9e0086b..6a422e7 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp
@@ -68,6 +68,7 @@
#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
+#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
@@ -82,6 +83,9 @@ using namespace llvm;
namespace {
class SIFixSGPRCopies : public MachineFunctionPass {
+
+ MachineDominatorTree *MDT;
+
public:
static char ID;
@@ -89,11 +93,11 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Fix SGPR copies";
- }
+ StringRef getPassName() const override { return "SI Fix SGPR copies"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<MachineDominatorTree>();
+ AU.addPreserved<MachineDominatorTree>();
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
@@ -101,8 +105,12 @@ public:
} // End anonymous namespace
-INITIALIZE_PASS(SIFixSGPRCopies, DEBUG_TYPE,
- "SI Fix SGPR copies", false, false)
+INITIALIZE_PASS_BEGIN(SIFixSGPRCopies, DEBUG_TYPE,
+ "SI Fix SGPR copies", false, false)
+INITIALIZE_PASS_DEPENDENCY(MachinePostDominatorTree)
+INITIALIZE_PASS_END(SIFixSGPRCopies, DEBUG_TYPE,
+ "SI Fix SGPR copies", false, false)
+
char SIFixSGPRCopies::ID = 0;
@@ -236,11 +244,94 @@ static bool foldVGPRCopyIntoRegSequence(MachineInstr &MI,
return true;
}
+static bool phiHasVGPROperands(const MachineInstr &PHI,
+ const MachineRegisterInfo &MRI,
+ const SIRegisterInfo *TRI,
+ const SIInstrInfo *TII) {
+
+ for (unsigned i = 1; i < PHI.getNumOperands(); i += 2) {
+ unsigned Reg = PHI.getOperand(i).getReg();
+ if (TRI->hasVGPRs(MRI.getRegClass(Reg)))
+ return true;
+ }
+ return false;
+}
+static bool phiHasBreakDef(const MachineInstr &PHI,
+ const MachineRegisterInfo &MRI,
+ SmallSet<unsigned, 8> &Visited) {
+
+ for (unsigned i = 1; i < PHI.getNumOperands(); i += 2) {
+ unsigned Reg = PHI.getOperand(i).getReg();
+ if (Visited.count(Reg))
+ continue;
+
+ Visited.insert(Reg);
+
+ MachineInstr *DefInstr = MRI.getUniqueVRegDef(Reg);
+ assert(DefInstr);
+ switch (DefInstr->getOpcode()) {
+ default:
+ break;
+ case AMDGPU::SI_BREAK:
+ case AMDGPU::SI_IF_BREAK:
+ case AMDGPU::SI_ELSE_BREAK:
+ return true;
+ case AMDGPU::PHI:
+ if (phiHasBreakDef(*DefInstr, MRI, Visited))
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool hasTerminatorThatModifiesExec(const MachineBasicBlock &MBB,
+ const TargetRegisterInfo &TRI) {
+ for (MachineBasicBlock::const_iterator I = MBB.getFirstTerminator(),
+ E = MBB.end(); I != E; ++I) {
+ if (I->modifiesRegister(AMDGPU::EXEC, &TRI))
+ return true;
+ }
+ return false;
+}
+
+static bool isSafeToFoldImmIntoCopy(const MachineInstr *Copy,
+ const MachineInstr *MoveImm,
+ const SIInstrInfo *TII,
+ unsigned &SMovOp,
+ int64_t &Imm) {
+
+ if (!MoveImm->isMoveImmediate())
+ return false;
+
+ const MachineOperand *ImmOp =
+ TII->getNamedOperand(*MoveImm, AMDGPU::OpName::src0);
+ if (!ImmOp->isImm())
+ return false;
+
+ // FIXME: Handle copies with sub-regs.
+ if (Copy->getOperand(0).getSubReg())
+ return false;
+
+ switch (MoveImm->getOpcode()) {
+ default:
+ return false;
+ case AMDGPU::V_MOV_B32_e32:
+ SMovOp = AMDGPU::S_MOV_B32;
+ break;
+ case AMDGPU::V_MOV_B64_PSEUDO:
+ SMovOp = AMDGPU::S_MOV_B64;
+ break;
+ }
+ Imm = ImmOp->getImm();
+ return true;
+}
+
bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) {
const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
MachineRegisterInfo &MRI = MF.getRegInfo();
const SIRegisterInfo *TRI = ST.getRegisterInfo();
const SIInstrInfo *TII = ST.getInstrInfo();
+ MDT = &getAnalysis<MachineDominatorTree>();
SmallVector<MachineInstr *, 16> Worklist;
@@ -264,18 +355,40 @@ bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) {
const TargetRegisterClass *SrcRC, *DstRC;
std::tie(SrcRC, DstRC) = getCopyRegClasses(MI, *TRI, MRI);
if (isVGPRToSGPRCopy(SrcRC, DstRC, *TRI)) {
- DEBUG(dbgs() << "Fixing VGPR -> SGPR copy: " << MI);
+ MachineInstr *DefMI = MRI.getVRegDef(MI.getOperand(1).getReg());
+ unsigned SMovOp;
+ int64_t Imm;
+ // If we are just copying an immediate, we can replace the copy with
+ // s_mov_b32.
+ if (isSafeToFoldImmIntoCopy(&MI, DefMI, TII, SMovOp, Imm)) {
+ MI.getOperand(1).ChangeToImmediate(Imm);
+ MI.addImplicitDefUseOperands(MF);
+ MI.setDesc(TII->get(SMovOp));
+ break;
+ }
TII->moveToVALU(MI);
}
break;
}
case AMDGPU::PHI: {
- DEBUG(dbgs() << "Fixing PHI: " << MI);
unsigned Reg = MI.getOperand(0).getReg();
if (!TRI->isSGPRClass(MRI.getRegClass(Reg)))
break;
+ // We don't need to fix the PHI if the common dominator of the
+ // two incoming blocks terminates with a uniform branch.
+ if (MI.getNumExplicitOperands() == 5) {
+ MachineBasicBlock *MBB0 = MI.getOperand(2).getMBB();
+ MachineBasicBlock *MBB1 = MI.getOperand(4).getMBB();
+
+ MachineBasicBlock *NCD = MDT->findNearestCommonDominator(MBB0, MBB1);
+ if (NCD && !hasTerminatorThatModifiesExec(*NCD, *TRI)) {
+ DEBUG(dbgs() << "Not fixing PHI for uniform branch: " << MI << '\n');
+ break;
+ }
+ }
+
// If a PHI node defines an SGPR and any of its operands are VGPRs,
// then we need to move it to the VALU.
//
@@ -302,10 +415,6 @@ bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) {
// ...
// use sgpr2
//
- // FIXME: This is OK if the branching decision is made based on an
- // SGPR value.
- bool SGPRBranch = false;
-
// The one exception to this rule is when one of the operands
// is defined by a SI_BREAK, SI_IF_BREAK, or SI_ELSE_BREAK
// instruction. In this case, there we know the program will
@@ -313,31 +422,12 @@ bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) {
// the first block (where the condition is computed), so there
// is no chance for values to be over-written.
- bool HasBreakDef = false;
- for (unsigned i = 1; i < MI.getNumOperands(); i+=2) {
- unsigned Reg = MI.getOperand(i).getReg();
- if (TRI->hasVGPRs(MRI.getRegClass(Reg))) {
- TII->moveToVALU(MI);
- break;
- }
- MachineInstr *DefInstr = MRI.getUniqueVRegDef(Reg);
- assert(DefInstr);
- switch(DefInstr->getOpcode()) {
-
- case AMDGPU::SI_BREAK:
- case AMDGPU::SI_IF_BREAK:
- case AMDGPU::SI_ELSE_BREAK:
- // If we see a PHI instruction that defines an SGPR, then that PHI
- // instruction has already been considered and should have
- // a *_BREAK as an operand.
- case AMDGPU::PHI:
- HasBreakDef = true;
- break;
- }
- }
-
- if (!SGPRBranch && !HasBreakDef)
+ SmallSet<unsigned, 8> Visited;
+ if (phiHasVGPROperands(MI, MRI, TRI, TII) ||
+ !phiHasBreakDef(MI, MRI, Visited)) {
+ DEBUG(dbgs() << "Fixing PHI: " << MI);
TII->moveToVALU(MI);
+ }
break;
}
case AMDGPU::REG_SEQUENCE: {
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
index 4ecc0fc..a5c0d49 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
@@ -25,9 +25,55 @@ using namespace llvm;
namespace {
+struct FoldCandidate {
+ MachineInstr *UseMI;
+ union {
+ MachineOperand *OpToFold;
+ uint64_t ImmToFold;
+ int FrameIndexToFold;
+ };
+ unsigned char UseOpNo;
+ MachineOperand::MachineOperandType Kind;
+
+ FoldCandidate(MachineInstr *MI, unsigned OpNo, MachineOperand *FoldOp) :
+ UseMI(MI), OpToFold(nullptr), UseOpNo(OpNo), Kind(FoldOp->getType()) {
+ if (FoldOp->isImm()) {
+ ImmToFold = FoldOp->getImm();
+ } else if (FoldOp->isFI()) {
+ FrameIndexToFold = FoldOp->getIndex();
+ } else {
+ assert(FoldOp->isReg());
+ OpToFold = FoldOp;
+ }
+ }
+
+ bool isFI() const {
+ return Kind == MachineOperand::MO_FrameIndex;
+ }
+
+ bool isImm() const {
+ return Kind == MachineOperand::MO_Immediate;
+ }
+
+ bool isReg() const {
+ return Kind == MachineOperand::MO_Register;
+ }
+};
+
class SIFoldOperands : public MachineFunctionPass {
public:
static char ID;
+ MachineRegisterInfo *MRI;
+ const SIInstrInfo *TII;
+ const SIRegisterInfo *TRI;
+
+ void foldOperand(MachineOperand &OpToFold,
+ MachineInstr *UseMI,
+ unsigned UseOpIdx,
+ SmallVectorImpl<FoldCandidate> &FoldList,
+ SmallVectorImpl<MachineInstr *> &CopiesToReplace) const;
+
+ void foldInstOperand(MachineInstr &MI, MachineOperand &OpToFold) const;
public:
SIFoldOperands() : MachineFunctionPass(ID) {
@@ -36,9 +82,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Fold Operands";
- }
+ StringRef getPassName() const override { return "SI Fold Operands"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -46,29 +90,6 @@ public:
}
};
-struct FoldCandidate {
- MachineInstr *UseMI;
- unsigned UseOpNo;
- MachineOperand *OpToFold;
- uint64_t ImmToFold;
-
- FoldCandidate(MachineInstr *MI, unsigned OpNo, MachineOperand *FoldOp) :
- UseMI(MI), UseOpNo(OpNo) {
-
- if (FoldOp->isImm()) {
- OpToFold = nullptr;
- ImmToFold = FoldOp->getImm();
- } else {
- assert(FoldOp->isReg());
- OpToFold = FoldOp;
- }
- }
-
- bool isImm() const {
- return !OpToFold;
- }
-};
-
} // End anonymous namespace.
INITIALIZE_PASS(SIFoldOperands, DEBUG_TYPE,
@@ -78,15 +99,50 @@ char SIFoldOperands::ID = 0;
char &llvm::SIFoldOperandsID = SIFoldOperands::ID;
+// Wrapper around isInlineConstant that understands special cases when
+// instruction types are replaced during operand folding.
+static bool isInlineConstantIfFolded(const SIInstrInfo *TII,
+ const MachineInstr &UseMI,
+ unsigned OpNo,
+ const MachineOperand &OpToFold) {
+ if (TII->isInlineConstant(UseMI, OpNo, OpToFold))
+ return true;
+
+ unsigned Opc = UseMI.getOpcode();
+ switch (Opc) {
+ case AMDGPU::V_MAC_F32_e64:
+ case AMDGPU::V_MAC_F16_e64: {
+ // Special case for mac. Since this is replaced with mad when folded into
+ // src2, we need to check the legality for the final instruction.
+ int Src2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2);
+ if (static_cast<int>(OpNo) == Src2Idx) {
+ bool IsF32 = Opc == AMDGPU::V_MAC_F32_e64;
+ const MCInstrDesc &MadDesc
+ = TII->get(IsF32 ? AMDGPU::V_MAD_F32 : AMDGPU::V_MAD_F16);
+ return TII->isInlineConstant(OpToFold, MadDesc.OpInfo[OpNo].OperandType);
+ }
+ }
+ default:
+ return false;
+ }
+}
+
FunctionPass *llvm::createSIFoldOperandsPass() {
return new SIFoldOperands();
}
-static bool isSafeToFold(unsigned Opcode) {
- switch(Opcode) {
+static bool isSafeToFold(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
case AMDGPU::V_MOV_B32_e32:
case AMDGPU::V_MOV_B32_e64:
- case AMDGPU::V_MOV_B64_PSEUDO:
+ case AMDGPU::V_MOV_B64_PSEUDO: {
+ // If there are additional implicit register operands, this may be used for
+ // register indexing so the source register operand isn't simply copied.
+ unsigned NumOps = MI.getDesc().getNumOperands() +
+ MI.getDesc().getNumImplicitUses();
+
+ return MI.getNumOperands() == NumOps;
+ }
case AMDGPU::S_MOV_B32:
case AMDGPU::S_MOV_B64:
case AMDGPU::COPY:
@@ -107,6 +163,11 @@ static bool updateOperand(FoldCandidate &Fold,
return true;
}
+ if (Fold.isFI()) {
+ Old.ChangeToFrameIndex(Fold.FrameIndexToFold);
+ return true;
+ }
+
MachineOperand *New = Fold.OpToFold;
if (TargetRegisterInfo::isVirtualRegister(Old.getReg()) &&
TargetRegisterInfo::isVirtualRegister(New->getReg())) {
@@ -119,7 +180,7 @@ static bool updateOperand(FoldCandidate &Fold,
return false;
}
-static bool isUseMIInFoldList(const std::vector<FoldCandidate> &FoldList,
+static bool isUseMIInFoldList(ArrayRef<FoldCandidate> FoldList,
const MachineInstr *MI) {
for (auto Candidate : FoldList) {
if (Candidate.UseMI == MI)
@@ -128,19 +189,21 @@ static bool isUseMIInFoldList(const std::vector<FoldCandidate> &FoldList,
return false;
}
-static bool tryAddToFoldList(std::vector<FoldCandidate> &FoldList,
+static bool tryAddToFoldList(SmallVectorImpl<FoldCandidate> &FoldList,
MachineInstr *MI, unsigned OpNo,
MachineOperand *OpToFold,
const SIInstrInfo *TII) {
if (!TII->isOperandLegal(*MI, OpNo, OpToFold)) {
- // Special case for v_mac_f32_e64 if we are trying to fold into src2
+ // Special case for v_mac_{f16, f32}_e64 if we are trying to fold into src2
unsigned Opc = MI->getOpcode();
- if (Opc == AMDGPU::V_MAC_F32_e64 &&
+ if ((Opc == AMDGPU::V_MAC_F32_e64 || Opc == AMDGPU::V_MAC_F16_e64) &&
(int)OpNo == AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2)) {
- // Check if changing this to a v_mad_f32 instruction will allow us to
- // fold the operand.
- MI->setDesc(TII->get(AMDGPU::V_MAD_F32));
+ bool IsF32 = Opc == AMDGPU::V_MAC_F32_e64;
+
+ // Check if changing this to a v_mad_{f16, f32} instruction will allow us
+ // to fold the operand.
+ MI->setDesc(TII->get(IsF32 ? AMDGPU::V_MAD_F32 : AMDGPU::V_MAD_F16));
bool FoldAsMAD = tryAddToFoldList(FoldList, MI, OpNo, OpToFold, TII);
if (FoldAsMAD) {
MI->untieRegOperand(OpNo);
@@ -149,6 +212,13 @@ static bool tryAddToFoldList(std::vector<FoldCandidate> &FoldList,
MI->setDesc(TII->get(Opc));
}
+ // Special case for s_setreg_b32
+ if (Opc == AMDGPU::S_SETREG_B32 && OpToFold->isImm()) {
+ MI->setDesc(TII->get(AMDGPU::S_SETREG_IMM32_B32));
+ FoldList.push_back(FoldCandidate(MI, OpNo, OpToFold));
+ return true;
+ }
+
// If we are already folding into another operand of MI, then
// we can't commute the instruction, otherwise we risk making the
// other fold illegal.
@@ -188,108 +258,432 @@ static bool tryAddToFoldList(std::vector<FoldCandidate> &FoldList,
return true;
}
-static void foldOperand(MachineOperand &OpToFold, MachineInstr *UseMI,
- unsigned UseOpIdx,
- std::vector<FoldCandidate> &FoldList,
- SmallVectorImpl<MachineInstr *> &CopiesToReplace,
- const SIInstrInfo *TII, const SIRegisterInfo &TRI,
- MachineRegisterInfo &MRI) {
+// If the use operand doesn't care about the value, this may be an operand only
+// used for register indexing, in which case it is unsafe to fold.
+static bool isUseSafeToFold(const MachineInstr &MI,
+ const MachineOperand &UseMO) {
+ return !UseMO.isUndef();
+ //return !MI.hasRegisterImplicitUseOperand(UseMO.getReg());
+}
+
+void SIFoldOperands::foldOperand(
+ MachineOperand &OpToFold,
+ MachineInstr *UseMI,
+ unsigned UseOpIdx,
+ SmallVectorImpl<FoldCandidate> &FoldList,
+ SmallVectorImpl<MachineInstr *> &CopiesToReplace) const {
const MachineOperand &UseOp = UseMI->getOperand(UseOpIdx);
+ if (!isUseSafeToFold(*UseMI, UseOp))
+ return;
+
// FIXME: Fold operands with subregs.
- if (UseOp.isReg() && ((UseOp.getSubReg() && OpToFold.isReg()) ||
- UseOp.isImplicit())) {
+ if (UseOp.isReg() && OpToFold.isReg()) {
+ if (UseOp.isImplicit() || UseOp.getSubReg() != AMDGPU::NoSubRegister)
+ return;
+
+ // Don't fold subregister extracts into tied operands, only if it is a full
+ // copy since a subregister use tied to a full register def doesn't really
+ // make sense. e.g. don't fold:
+ //
+ // %vreg1 = COPY %vreg0:sub1
+ // %vreg2<tied3> = V_MAC_{F16, F32} %vreg3, %vreg4, %vreg1<tied0>
+ //
+ // into
+ // %vreg2<tied3> = V_MAC_{F16, F32} %vreg3, %vreg4, %vreg0:sub1<tied0>
+ if (UseOp.isTied() && OpToFold.getSubReg() != AMDGPU::NoSubRegister)
+ return;
+ }
+
+ // Special case for REG_SEQUENCE: We can't fold literals into
+ // REG_SEQUENCE instructions, so we have to fold them into the
+ // uses of REG_SEQUENCE.
+ if (UseMI->isRegSequence()) {
+ unsigned RegSeqDstReg = UseMI->getOperand(0).getReg();
+ unsigned RegSeqDstSubReg = UseMI->getOperand(UseOpIdx + 1).getImm();
+
+ for (MachineRegisterInfo::use_iterator
+ RSUse = MRI->use_begin(RegSeqDstReg), RSE = MRI->use_end();
+ RSUse != RSE; ++RSUse) {
+
+ MachineInstr *RSUseMI = RSUse->getParent();
+ if (RSUse->getSubReg() != RegSeqDstSubReg)
+ continue;
+
+ foldOperand(OpToFold, RSUseMI, RSUse.getOperandNo(), FoldList,
+ CopiesToReplace);
+ }
+
return;
}
+
bool FoldingImm = OpToFold.isImm();
- APInt Imm;
- if (FoldingImm) {
+ // In order to fold immediates into copies, we need to change the
+ // copy to a MOV.
+ if (FoldingImm && UseMI->isCopy()) {
+ unsigned DestReg = UseMI->getOperand(0).getReg();
+ const TargetRegisterClass *DestRC
+ = TargetRegisterInfo::isVirtualRegister(DestReg) ?
+ MRI->getRegClass(DestReg) :
+ TRI->getPhysRegClass(DestReg);
+
+ unsigned MovOp = TII->getMovOpcode(DestRC);
+ if (MovOp == AMDGPU::COPY)
+ return;
+
+ UseMI->setDesc(TII->get(MovOp));
+ CopiesToReplace.push_back(UseMI);
+ } else {
+ const MCInstrDesc &UseDesc = UseMI->getDesc();
+
+ // Don't fold into target independent nodes. Target independent opcodes
+ // don't have defined register classes.
+ if (UseDesc.isVariadic() ||
+ UseDesc.OpInfo[UseOpIdx].RegClass == -1)
+ return;
+ }
+
+ if (!FoldingImm) {
+ tryAddToFoldList(FoldList, UseMI, UseOpIdx, &OpToFold, TII);
+
+ // FIXME: We could try to change the instruction from 64-bit to 32-bit
+ // to enable more folding opportunites. The shrink operands pass
+ // already does this.
+ return;
+ }
+
+
+ const MCInstrDesc &FoldDesc = OpToFold.getParent()->getDesc();
+ const TargetRegisterClass *FoldRC =
+ TRI->getRegClass(FoldDesc.OpInfo[0].RegClass);
+
+ APInt Imm(TII->operandBitWidth(FoldDesc.OpInfo[1].OperandType),
+ OpToFold.getImm());
+
+ // Split 64-bit constants into 32-bits for folding.
+ if (UseOp.getSubReg() && AMDGPU::getRegBitWidth(FoldRC->getID()) == 64) {
unsigned UseReg = UseOp.getReg();
const TargetRegisterClass *UseRC
= TargetRegisterInfo::isVirtualRegister(UseReg) ?
- MRI.getRegClass(UseReg) :
- TRI.getPhysRegClass(UseReg);
-
- Imm = APInt(64, OpToFold.getImm());
+ MRI->getRegClass(UseReg) :
+ TRI->getPhysRegClass(UseReg);
- const MCInstrDesc &FoldDesc = TII->get(OpToFold.getParent()->getOpcode());
- const TargetRegisterClass *FoldRC =
- TRI.getRegClass(FoldDesc.OpInfo[0].RegClass);
+ assert(Imm.getBitWidth() == 64);
- // Split 64-bit constants into 32-bits for folding.
- if (FoldRC->getSize() == 8 && UseOp.getSubReg()) {
- if (UseRC->getSize() != 8)
- return;
+ if (AMDGPU::getRegBitWidth(UseRC->getID()) != 64)
+ return;
- if (UseOp.getSubReg() == AMDGPU::sub0) {
- Imm = Imm.getLoBits(32);
- } else {
- assert(UseOp.getSubReg() == AMDGPU::sub1);
- Imm = Imm.getHiBits(32);
- }
+ if (UseOp.getSubReg() == AMDGPU::sub0) {
+ Imm = Imm.getLoBits(32);
+ } else {
+ assert(UseOp.getSubReg() == AMDGPU::sub1);
+ Imm = Imm.getHiBits(32);
}
+ }
- // In order to fold immediates into copies, we need to change the
- // copy to a MOV.
- if (UseMI->getOpcode() == AMDGPU::COPY) {
- unsigned DestReg = UseMI->getOperand(0).getReg();
- const TargetRegisterClass *DestRC
- = TargetRegisterInfo::isVirtualRegister(DestReg) ?
- MRI.getRegClass(DestReg) :
- TRI.getPhysRegClass(DestReg);
-
- unsigned MovOp = TII->getMovOpcode(DestRC);
- if (MovOp == AMDGPU::COPY)
- return;
-
- UseMI->setDesc(TII->get(MovOp));
- CopiesToReplace.push_back(UseMI);
+ MachineOperand ImmOp = MachineOperand::CreateImm(Imm.getSExtValue());
+ tryAddToFoldList(FoldList, UseMI, UseOpIdx, &ImmOp, TII);
+}
+
+static bool evalBinaryInstruction(unsigned Opcode, int32_t &Result,
+ uint32_t LHS, uint32_t RHS) {
+ switch (Opcode) {
+ case AMDGPU::V_AND_B32_e64:
+ case AMDGPU::V_AND_B32_e32:
+ case AMDGPU::S_AND_B32:
+ Result = LHS & RHS;
+ return true;
+ case AMDGPU::V_OR_B32_e64:
+ case AMDGPU::V_OR_B32_e32:
+ case AMDGPU::S_OR_B32:
+ Result = LHS | RHS;
+ return true;
+ case AMDGPU::V_XOR_B32_e64:
+ case AMDGPU::V_XOR_B32_e32:
+ case AMDGPU::S_XOR_B32:
+ Result = LHS ^ RHS;
+ return true;
+ case AMDGPU::V_LSHL_B32_e64:
+ case AMDGPU::V_LSHL_B32_e32:
+ case AMDGPU::S_LSHL_B32:
+ // The instruction ignores the high bits for out of bounds shifts.
+ Result = LHS << (RHS & 31);
+ return true;
+ case AMDGPU::V_LSHLREV_B32_e64:
+ case AMDGPU::V_LSHLREV_B32_e32:
+ Result = RHS << (LHS & 31);
+ return true;
+ case AMDGPU::V_LSHR_B32_e64:
+ case AMDGPU::V_LSHR_B32_e32:
+ case AMDGPU::S_LSHR_B32:
+ Result = LHS >> (RHS & 31);
+ return true;
+ case AMDGPU::V_LSHRREV_B32_e64:
+ case AMDGPU::V_LSHRREV_B32_e32:
+ Result = RHS >> (LHS & 31);
+ return true;
+ case AMDGPU::V_ASHR_I32_e64:
+ case AMDGPU::V_ASHR_I32_e32:
+ case AMDGPU::S_ASHR_I32:
+ Result = static_cast<int32_t>(LHS) >> (RHS & 31);
+ return true;
+ case AMDGPU::V_ASHRREV_I32_e64:
+ case AMDGPU::V_ASHRREV_I32_e32:
+ Result = static_cast<int32_t>(RHS) >> (LHS & 31);
+ return true;
+ default:
+ return false;
+ }
+}
+
+static unsigned getMovOpc(bool IsScalar) {
+ return IsScalar ? AMDGPU::S_MOV_B32 : AMDGPU::V_MOV_B32_e32;
+}
+
+/// Remove any leftover implicit operands from mutating the instruction. e.g.
+/// if we replace an s_and_b32 with a copy, we don't need the implicit scc def
+/// anymore.
+static void stripExtraCopyOperands(MachineInstr &MI) {
+ const MCInstrDesc &Desc = MI.getDesc();
+ unsigned NumOps = Desc.getNumOperands() +
+ Desc.getNumImplicitUses() +
+ Desc.getNumImplicitDefs();
+
+ for (unsigned I = MI.getNumOperands() - 1; I >= NumOps; --I)
+ MI.RemoveOperand(I);
+}
+
+static void mutateCopyOp(MachineInstr &MI, const MCInstrDesc &NewDesc) {
+ MI.setDesc(NewDesc);
+ stripExtraCopyOperands(MI);
+}
+
+static MachineOperand *getImmOrMaterializedImm(MachineRegisterInfo &MRI,
+ MachineOperand &Op) {
+ if (Op.isReg()) {
+ // If this has a subregister, it obviously is a register source.
+ if (Op.getSubReg() != AMDGPU::NoSubRegister)
+ return &Op;
+
+ MachineInstr *Def = MRI.getVRegDef(Op.getReg());
+ if (Def->isMoveImmediate()) {
+ MachineOperand &ImmSrc = Def->getOperand(1);
+ if (ImmSrc.isImm())
+ return &ImmSrc;
}
}
- // Special case for REG_SEQUENCE: We can't fold literals into
- // REG_SEQUENCE instructions, so we have to fold them into the
- // uses of REG_SEQUENCE.
- if (UseMI->getOpcode() == AMDGPU::REG_SEQUENCE) {
- unsigned RegSeqDstReg = UseMI->getOperand(0).getReg();
- unsigned RegSeqDstSubReg = UseMI->getOperand(UseOpIdx + 1).getImm();
+ return &Op;
+}
- for (MachineRegisterInfo::use_iterator
- RSUse = MRI.use_begin(RegSeqDstReg),
- RSE = MRI.use_end(); RSUse != RSE; ++RSUse) {
+// Try to simplify operations with a constant that may appear after instruction
+// selection.
+// TODO: See if a frame index with a fixed offset can fold.
+static bool tryConstantFoldOp(MachineRegisterInfo &MRI,
+ const SIInstrInfo *TII,
+ MachineInstr *MI,
+ MachineOperand *ImmOp) {
+ unsigned Opc = MI->getOpcode();
+ if (Opc == AMDGPU::V_NOT_B32_e64 || Opc == AMDGPU::V_NOT_B32_e32 ||
+ Opc == AMDGPU::S_NOT_B32) {
+ MI->getOperand(1).ChangeToImmediate(~ImmOp->getImm());
+ mutateCopyOp(*MI, TII->get(getMovOpc(Opc == AMDGPU::S_NOT_B32)));
+ return true;
+ }
- MachineInstr *RSUseMI = RSUse->getParent();
- if (RSUse->getSubReg() != RegSeqDstSubReg)
- continue;
+ int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
+ if (Src1Idx == -1)
+ return false;
- foldOperand(OpToFold, RSUseMI, RSUse.getOperandNo(), FoldList,
- CopiesToReplace, TII, TRI, MRI);
+ int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
+ MachineOperand *Src0 = getImmOrMaterializedImm(MRI, MI->getOperand(Src0Idx));
+ MachineOperand *Src1 = getImmOrMaterializedImm(MRI, MI->getOperand(Src1Idx));
+
+ if (!Src0->isImm() && !Src1->isImm())
+ return false;
+
+ // and k0, k1 -> v_mov_b32 (k0 & k1)
+ // or k0, k1 -> v_mov_b32 (k0 | k1)
+ // xor k0, k1 -> v_mov_b32 (k0 ^ k1)
+ if (Src0->isImm() && Src1->isImm()) {
+ int32_t NewImm;
+ if (!evalBinaryInstruction(Opc, NewImm, Src0->getImm(), Src1->getImm()))
+ return false;
+
+ const SIRegisterInfo &TRI = TII->getRegisterInfo();
+ bool IsSGPR = TRI.isSGPRReg(MRI, MI->getOperand(0).getReg());
+
+ // Be careful to change the right operand, src0 may belong to a different
+ // instruction.
+ MI->getOperand(Src0Idx).ChangeToImmediate(NewImm);
+ MI->RemoveOperand(Src1Idx);
+ mutateCopyOp(*MI, TII->get(getMovOpc(IsSGPR)));
+ return true;
+ }
+
+ if (!MI->isCommutable())
+ return false;
+
+ if (Src0->isImm() && !Src1->isImm()) {
+ std::swap(Src0, Src1);
+ std::swap(Src0Idx, Src1Idx);
+ }
+
+ int32_t Src1Val = static_cast<int32_t>(Src1->getImm());
+ if (Opc == AMDGPU::V_OR_B32_e64 ||
+ Opc == AMDGPU::V_OR_B32_e32 ||
+ Opc == AMDGPU::S_OR_B32) {
+ if (Src1Val == 0) {
+ // y = or x, 0 => y = copy x
+ MI->RemoveOperand(Src1Idx);
+ mutateCopyOp(*MI, TII->get(AMDGPU::COPY));
+ } else if (Src1Val == -1) {
+ // y = or x, -1 => y = v_mov_b32 -1
+ MI->RemoveOperand(Src1Idx);
+ mutateCopyOp(*MI, TII->get(getMovOpc(Opc == AMDGPU::S_OR_B32)));
+ } else
+ return false;
+
+ return true;
+ }
+
+ if (MI->getOpcode() == AMDGPU::V_AND_B32_e64 ||
+ MI->getOpcode() == AMDGPU::V_AND_B32_e32 ||
+ MI->getOpcode() == AMDGPU::S_AND_B32) {
+ if (Src1Val == 0) {
+ // y = and x, 0 => y = v_mov_b32 0
+ MI->RemoveOperand(Src0Idx);
+ mutateCopyOp(*MI, TII->get(getMovOpc(Opc == AMDGPU::S_AND_B32)));
+ } else if (Src1Val == -1) {
+ // y = and x, -1 => y = copy x
+ MI->RemoveOperand(Src1Idx);
+ mutateCopyOp(*MI, TII->get(AMDGPU::COPY));
+ stripExtraCopyOperands(*MI);
+ } else
+ return false;
+
+ return true;
+ }
+
+ if (MI->getOpcode() == AMDGPU::V_XOR_B32_e64 ||
+ MI->getOpcode() == AMDGPU::V_XOR_B32_e32 ||
+ MI->getOpcode() == AMDGPU::S_XOR_B32) {
+ if (Src1Val == 0) {
+ // y = xor x, 0 => y = copy x
+ MI->RemoveOperand(Src1Idx);
+ mutateCopyOp(*MI, TII->get(AMDGPU::COPY));
+ return true;
}
- return;
}
- const MCInstrDesc &UseDesc = UseMI->getDesc();
+ return false;
+}
- // Don't fold into target independent nodes. Target independent opcodes
- // don't have defined register classes.
- if (UseDesc.isVariadic() ||
- UseDesc.OpInfo[UseOpIdx].RegClass == -1)
- return;
+void SIFoldOperands::foldInstOperand(MachineInstr &MI,
+ MachineOperand &OpToFold) const {
+ // We need mutate the operands of new mov instructions to add implicit
+ // uses of EXEC, but adding them invalidates the use_iterator, so defer
+ // this.
+ SmallVector<MachineInstr *, 4> CopiesToReplace;
+ SmallVector<FoldCandidate, 4> FoldList;
+ MachineOperand &Dst = MI.getOperand(0);
+ bool FoldingImm = OpToFold.isImm() || OpToFold.isFI();
if (FoldingImm) {
- MachineOperand ImmOp = MachineOperand::CreateImm(Imm.getSExtValue());
- tryAddToFoldList(FoldList, UseMI, UseOpIdx, &ImmOp, TII);
- return;
- }
+ unsigned NumLiteralUses = 0;
+ MachineOperand *NonInlineUse = nullptr;
+ int NonInlineUseOpNo = -1;
+
+ MachineRegisterInfo::use_iterator NextUse, NextInstUse;
+ for (MachineRegisterInfo::use_iterator
+ Use = MRI->use_begin(Dst.getReg()), E = MRI->use_end();
+ Use != E; Use = NextUse) {
+ NextUse = std::next(Use);
+ MachineInstr *UseMI = Use->getParent();
+ unsigned OpNo = Use.getOperandNo();
+
+ // Folding the immediate may reveal operations that can be constant
+ // folded or replaced with a copy. This can happen for example after
+ // frame indices are lowered to constants or from splitting 64-bit
+ // constants.
+ //
+ // We may also encounter cases where one or both operands are
+ // immediates materialized into a register, which would ordinarily not
+ // be folded due to multiple uses or operand constraints.
+
+ if (OpToFold.isImm() && tryConstantFoldOp(*MRI, TII, UseMI, &OpToFold)) {
+ DEBUG(dbgs() << "Constant folded " << *UseMI <<'\n');
+
+ // Some constant folding cases change the same immediate's use to a new
+ // instruction, e.g. and x, 0 -> 0. Make sure we re-visit the user
+ // again. The same constant folded instruction could also have a second
+ // use operand.
+ NextUse = MRI->use_begin(Dst.getReg());
+ continue;
+ }
+
+ // Try to fold any inline immediate uses, and then only fold other
+ // constants if they have one use.
+ //
+ // The legality of the inline immediate must be checked based on the use
+ // operand, not the defining instruction, because 32-bit instructions
+ // with 32-bit inline immediate sources may be used to materialize
+ // constants used in 16-bit operands.
+ //
+ // e.g. it is unsafe to fold:
+ // s_mov_b32 s0, 1.0 // materializes 0x3f800000
+ // v_add_f16 v0, v1, s0 // 1.0 f16 inline immediate sees 0x00003c00
+
+ // Folding immediates with more than one use will increase program size.
+ // FIXME: This will also reduce register usage, which may be better
+ // in some cases. A better heuristic is needed.
+ if (isInlineConstantIfFolded(TII, *UseMI, OpNo, OpToFold)) {
+ foldOperand(OpToFold, UseMI, OpNo, FoldList, CopiesToReplace);
+ } else {
+ if (++NumLiteralUses == 1) {
+ NonInlineUse = &*Use;
+ NonInlineUseOpNo = OpNo;
+ }
+ }
+ }
+
+ if (NumLiteralUses == 1) {
+ MachineInstr *UseMI = NonInlineUse->getParent();
+ foldOperand(OpToFold, UseMI, NonInlineUseOpNo, FoldList, CopiesToReplace);
+ }
+ } else {
+ // Folding register.
+ for (MachineRegisterInfo::use_iterator
+ Use = MRI->use_begin(Dst.getReg()), E = MRI->use_end();
+ Use != E; ++Use) {
+ MachineInstr *UseMI = Use->getParent();
- tryAddToFoldList(FoldList, UseMI, UseOpIdx, &OpToFold, TII);
+ foldOperand(OpToFold, UseMI, Use.getOperandNo(),
+ FoldList, CopiesToReplace);
+ }
+ }
- // FIXME: We could try to change the instruction from 64-bit to 32-bit
- // to enable more folding opportunites. The shrink operands pass
- // already does this.
- return;
+ MachineFunction *MF = MI.getParent()->getParent();
+ // Make sure we add EXEC uses to any new v_mov instructions created.
+ for (MachineInstr *Copy : CopiesToReplace)
+ Copy->addImplicitDefUseOperands(*MF);
+
+ for (FoldCandidate &Fold : FoldList) {
+ if (updateOperand(Fold, *TRI)) {
+ // Clear kill flags.
+ if (Fold.isReg()) {
+ assert(Fold.OpToFold && Fold.OpToFold->isReg());
+ // FIXME: Probably shouldn't bother trying to fold if not an
+ // SGPR. PeepholeOptimizer can eliminate redundant VGPR->VGPR
+ // copies.
+ MRI->clearKillFlags(Fold.OpToFold->getReg());
+ }
+ DEBUG(dbgs() << "Folded source from " << MI << " into OpNo " <<
+ static_cast<int>(Fold.UseOpNo) << " of " << *Fold.UseMI << '\n');
+ }
+ }
}
bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) {
@@ -298,12 +692,12 @@ bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) {
const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
- MachineRegisterInfo &MRI = MF.getRegInfo();
- const SIInstrInfo *TII = ST.getInstrInfo();
- const SIRegisterInfo &TRI = TII->getRegisterInfo();
+ MRI = &MF.getRegInfo();
+ TII = ST.getInstrInfo();
+ TRI = &TII->getRegisterInfo();
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
- BI != BE; ++BI) {
+ BI != BE; ++BI) {
MachineBasicBlock &MBB = *BI;
MachineBasicBlock::iterator I, Next;
@@ -311,25 +705,16 @@ bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) {
Next = std::next(I);
MachineInstr &MI = *I;
- if (!isSafeToFold(MI.getOpcode()))
+ if (!isSafeToFold(MI))
continue;
- unsigned OpSize = TII->getOpSize(MI, 1);
MachineOperand &OpToFold = MI.getOperand(1);
- bool FoldingImm = OpToFold.isImm();
+ bool FoldingImm = OpToFold.isImm() || OpToFold.isFI();
- // FIXME: We could also be folding things like FrameIndexes and
- // TargetIndexes.
+ // FIXME: We could also be folding things like TargetIndexes.
if (!FoldingImm && !OpToFold.isReg())
continue;
- // Folding immediates with more than one use will increase program size.
- // FIXME: This will also reduce register usage, which may be better
- // in some cases. A better heuristic is needed.
- if (FoldingImm && !TII->isInlineConstant(OpToFold, OpSize) &&
- !MRI.hasOneUse(MI.getOperand(0).getReg()))
- continue;
-
if (OpToFold.isReg() &&
!TargetRegisterInfo::isVirtualRegister(OpToFold.getReg()))
continue;
@@ -345,40 +730,7 @@ bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) {
!TargetRegisterInfo::isVirtualRegister(Dst.getReg()))
continue;
- // We need mutate the operands of new mov instructions to add implicit
- // uses of EXEC, but adding them invalidates the use_iterator, so defer
- // this.
- SmallVector<MachineInstr *, 4> CopiesToReplace;
-
- std::vector<FoldCandidate> FoldList;
- for (MachineRegisterInfo::use_iterator
- Use = MRI.use_begin(MI.getOperand(0).getReg()), E = MRI.use_end();
- Use != E; ++Use) {
-
- MachineInstr *UseMI = Use->getParent();
-
- foldOperand(OpToFold, UseMI, Use.getOperandNo(), FoldList,
- CopiesToReplace, TII, TRI, MRI);
- }
-
- // Make sure we add EXEC uses to any new v_mov instructions created.
- for (MachineInstr *Copy : CopiesToReplace)
- Copy->addImplicitDefUseOperands(MF);
-
- for (FoldCandidate &Fold : FoldList) {
- if (updateOperand(Fold, TRI)) {
- // Clear kill flags.
- if (!Fold.isImm()) {
- assert(Fold.OpToFold && Fold.OpToFold->isReg());
- // FIXME: Probably shouldn't bother trying to fold if not an
- // SGPR. PeepholeOptimizer can eliminate redundant VGPR->VGPR
- // copies.
- MRI.clearKillFlags(Fold.OpToFold->getReg());
- }
- DEBUG(dbgs() << "Folded source from " << MI << " into OpNo " <<
- Fold.UseOpNo << " of " << *Fold.UseMI << '\n');
- }
- }
+ foldInstOperand(MI, OpToFold);
}
}
return false;
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index 03b11f0..0b57155 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -21,20 +21,168 @@
using namespace llvm;
-static bool hasOnlySGPRSpills(const SIMachineFunctionInfo *FuncInfo,
- const MachineFrameInfo *FrameInfo) {
- return FuncInfo->hasSpilledSGPRs() &&
- (!FuncInfo->hasSpilledVGPRs() && !FuncInfo->hasNonSpillStackObjects());
-}
-
-static ArrayRef<MCPhysReg> getAllSGPR128() {
+static ArrayRef<MCPhysReg> getAllSGPR128(const MachineFunction &MF,
+ const SIRegisterInfo *TRI) {
return makeArrayRef(AMDGPU::SGPR_128RegClass.begin(),
- AMDGPU::SGPR_128RegClass.getNumRegs());
+ TRI->getMaxNumSGPRs(MF) / 4);
}
-static ArrayRef<MCPhysReg> getAllSGPRs() {
+static ArrayRef<MCPhysReg> getAllSGPRs(const MachineFunction &MF,
+ const SIRegisterInfo *TRI) {
return makeArrayRef(AMDGPU::SGPR_32RegClass.begin(),
- AMDGPU::SGPR_32RegClass.getNumRegs());
+ TRI->getMaxNumSGPRs(MF));
+}
+
+void SIFrameLowering::emitFlatScratchInit(const SIInstrInfo *TII,
+ const SIRegisterInfo* TRI,
+ MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ // We don't need this if we only have spills since there is no user facing
+ // scratch.
+
+ // TODO: If we know we don't have flat instructions earlier, we can omit
+ // this from the input registers.
+ //
+ // TODO: We only need to know if we access scratch space through a flat
+ // pointer. Because we only detect if flat instructions are used at all,
+ // this will be used more often than necessary on VI.
+
+ // Debug location must be unknown since the first debug location is used to
+ // determine the end of the prologue.
+ DebugLoc DL;
+ MachineBasicBlock::iterator I = MBB.begin();
+
+ unsigned FlatScratchInitReg
+ = TRI->getPreloadedValue(MF, SIRegisterInfo::FLAT_SCRATCH_INIT);
+
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ MRI.addLiveIn(FlatScratchInitReg);
+ MBB.addLiveIn(FlatScratchInitReg);
+
+ // Copy the size in bytes.
+ unsigned FlatScrInitHi = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub1);
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::COPY), AMDGPU::FLAT_SCR_LO)
+ .addReg(FlatScrInitHi, RegState::Kill);
+
+ unsigned FlatScrInitLo = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub0);
+
+ const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+ unsigned ScratchWaveOffsetReg = MFI->getScratchWaveOffsetReg();
+
+ // Add wave offset in bytes to private base offset.
+ // See comment in AMDKernelCodeT.h for enable_sgpr_flat_scratch_init.
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADD_U32), FlatScrInitLo)
+ .addReg(FlatScrInitLo)
+ .addReg(ScratchWaveOffsetReg);
+
+ // Convert offset to 256-byte units.
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_LSHR_B32), AMDGPU::FLAT_SCR_HI)
+ .addReg(FlatScrInitLo, RegState::Kill)
+ .addImm(8);
+}
+
+unsigned SIFrameLowering::getReservedPrivateSegmentBufferReg(
+ const SISubtarget &ST,
+ const SIInstrInfo *TII,
+ const SIRegisterInfo *TRI,
+ SIMachineFunctionInfo *MFI,
+ MachineFunction &MF) const {
+
+ // We need to insert initialization of the scratch resource descriptor.
+ unsigned ScratchRsrcReg = MFI->getScratchRSrcReg();
+ if (ScratchRsrcReg == AMDGPU::NoRegister)
+ return AMDGPU::NoRegister;
+
+ if (ST.hasSGPRInitBug() ||
+ ScratchRsrcReg != TRI->reservedPrivateSegmentBufferReg(MF))
+ return ScratchRsrcReg;
+
+ // We reserved the last registers for this. Shift it down to the end of those
+ // which were actually used.
+ //
+ // FIXME: It might be safer to use a pseudoregister before replacement.
+
+ // FIXME: We should be able to eliminate unused input registers. We only
+ // cannot do this for the resources required for scratch access. For now we
+ // skip over user SGPRs and may leave unused holes.
+
+ // We find the resource first because it has an alignment requirement.
+
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ unsigned NumPreloaded = (MFI->getNumPreloadedSGPRs() + 3) / 4;
+ ArrayRef<MCPhysReg> AllSGPR128s = getAllSGPR128(MF, TRI);
+ AllSGPR128s = AllSGPR128s.slice(std::min(static_cast<unsigned>(AllSGPR128s.size()), NumPreloaded));
+
+ // Skip the last 2 elements because the last one is reserved for VCC, and
+ // this is the 2nd to last element already.
+ for (MCPhysReg Reg : AllSGPR128s) {
+ // Pick the first unallocated one. Make sure we don't clobber the other
+ // reserved input we needed.
+ if (!MRI.isPhysRegUsed(Reg) && MRI.isAllocatable(Reg)) {
+ //assert(MRI.isAllocatable(Reg));
+ MRI.replaceRegWith(ScratchRsrcReg, Reg);
+ MFI->setScratchRSrcReg(Reg);
+ return Reg;
+ }
+ }
+
+ return ScratchRsrcReg;
+}
+
+unsigned SIFrameLowering::getReservedPrivateSegmentWaveByteOffsetReg(
+ const SISubtarget &ST,
+ const SIInstrInfo *TII,
+ const SIRegisterInfo *TRI,
+ SIMachineFunctionInfo *MFI,
+ MachineFunction &MF) const {
+ unsigned ScratchWaveOffsetReg = MFI->getScratchWaveOffsetReg();
+ if (ST.hasSGPRInitBug() ||
+ ScratchWaveOffsetReg != TRI->reservedPrivateSegmentWaveByteOffsetReg(MF))
+ return ScratchWaveOffsetReg;
+
+ unsigned ScratchRsrcReg = MFI->getScratchRSrcReg();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ unsigned NumPreloaded = MFI->getNumPreloadedSGPRs();
+
+ ArrayRef<MCPhysReg> AllSGPRs = getAllSGPRs(MF, TRI);
+ if (NumPreloaded > AllSGPRs.size())
+ return ScratchWaveOffsetReg;
+
+ AllSGPRs = AllSGPRs.slice(NumPreloaded);
+
+ // We need to drop register from the end of the list that we cannot use
+ // for the scratch wave offset.
+ // + 2 s102 and s103 do not exist on VI.
+ // + 2 for vcc
+ // + 2 for xnack_mask
+ // + 2 for flat_scratch
+ // + 4 for registers reserved for scratch resource register
+ // + 1 for register reserved for scratch wave offset. (By exluding this
+ // register from the list to consider, it means that when this
+ // register is being used for the scratch wave offset and there
+ // are no other free SGPRs, then the value will stay in this register.
+ // ----
+ // 13
+ if (AllSGPRs.size() < 13)
+ return ScratchWaveOffsetReg;
+
+ for (MCPhysReg Reg : AllSGPRs.drop_back(13)) {
+ // Pick the first unallocated SGPR. Be careful not to pick an alias of the
+ // scratch descriptor, since we haven’t added its uses yet.
+ if (!MRI.isPhysRegUsed(Reg)) {
+ if (!MRI.isAllocatable(Reg) ||
+ TRI->isSubRegisterEq(ScratchRsrcReg, Reg))
+ continue;
+
+ MRI.replaceRegWith(ScratchWaveOffsetReg, Reg);
+ MFI->setScratchWaveOffsetReg(Reg);
+ return Reg;
+ }
+ }
+
+ return ScratchWaveOffsetReg;
}
void SIFrameLowering::emitPrologue(MachineFunction &MF,
@@ -45,9 +193,6 @@ void SIFrameLowering::emitPrologue(MachineFunction &MF,
if (ST.debuggerEmitPrologue())
emitDebuggerPrologue(MF, MBB);
- if (!MF.getFrameInfo()->hasStackObjects())
- return;
-
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
@@ -57,200 +202,159 @@ void SIFrameLowering::emitPrologue(MachineFunction &MF,
//
// FIXME: We should be cleaning up these unused SGPR spill frame indices
// somewhere.
- if (hasOnlySGPRSpills(MFI, MF.getFrameInfo()))
- return;
const SIInstrInfo *TII = ST.getInstrInfo();
const SIRegisterInfo *TRI = &TII->getRegisterInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
- MachineBasicBlock::iterator I = MBB.begin();
-
- // We need to insert initialization of the scratch resource descriptor.
- unsigned ScratchRsrcReg = MFI->getScratchRSrcReg();
- assert(ScratchRsrcReg != AMDGPU::NoRegister);
-
- unsigned ScratchWaveOffsetReg = MFI->getScratchWaveOffsetReg();
- assert(ScratchWaveOffsetReg != AMDGPU::NoRegister);
- unsigned PreloadedScratchWaveOffsetReg = TRI->getPreloadedValue(
- MF, SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET);
+ unsigned ScratchRsrcReg
+ = getReservedPrivateSegmentBufferReg(ST, TII, TRI, MFI, MF);
+ unsigned ScratchWaveOffsetReg
+ = getReservedPrivateSegmentWaveByteOffsetReg(ST, TII, TRI, MFI, MF);
- unsigned PreloadedPrivateBufferReg = AMDGPU::NoRegister;
- if (ST.isAmdHsaOS()) {
- PreloadedPrivateBufferReg = TRI->getPreloadedValue(
- MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER);
+ if (ScratchRsrcReg == AMDGPU::NoRegister) {
+ assert(ScratchWaveOffsetReg == AMDGPU::NoRegister);
+ return;
}
- if (MFI->hasFlatScratchInit()) {
- // We don't need this if we only have spills since there is no user facing
- // scratch.
-
- // TODO: If we know we don't have flat instructions earlier, we can omit
- // this from the input registers.
- //
- // TODO: We only need to know if we access scratch space through a flat
- // pointer. Because we only detect if flat instructions are used at all,
- // this will be used more often than necessary on VI.
-
- // Debug location must be unknown since the first debug location is used to
- // determine the end of the prologue.
- DebugLoc DL;
-
- unsigned FlatScratchInitReg
- = TRI->getPreloadedValue(MF, SIRegisterInfo::FLAT_SCRATCH_INIT);
+ assert(!TRI->isSubRegister(ScratchRsrcReg, ScratchWaveOffsetReg));
- MRI.addLiveIn(FlatScratchInitReg);
- MBB.addLiveIn(FlatScratchInitReg);
+ // We need to do the replacement of the private segment buffer and wave offset
+ // register even if there are no stack objects. There could be stores to undef
+ // or a constant without an associated object.
- // Copy the size in bytes.
- unsigned FlatScrInitHi = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub1);
- BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::FLAT_SCR_LO)
- .addReg(FlatScrInitHi, RegState::Kill);
+ // FIXME: We still have implicit uses on SGPR spill instructions in case they
+ // need to spill to vector memory. It's likely that will not happen, but at
+ // this point it appears we need the setup. This part of the prolog should be
+ // emitted after frame indices are eliminated.
- unsigned FlatScrInitLo = TRI->getSubReg(FlatScratchInitReg, AMDGPU::sub0);
+ if (MF.getFrameInfo().hasStackObjects() && MFI->hasFlatScratchInit())
+ emitFlatScratchInit(TII, TRI, MF, MBB);
- // Add wave offset in bytes to private base offset.
- // See comment in AMDKernelCodeT.h for enable_sgpr_flat_scratch_init.
- BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADD_U32), FlatScrInitLo)
- .addReg(FlatScrInitLo)
- .addReg(ScratchWaveOffsetReg);
+ // We need to insert initialization of the scratch resource descriptor.
+ unsigned PreloadedScratchWaveOffsetReg = TRI->getPreloadedValue(
+ MF, SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET);
- // Convert offset to 256-byte units.
- BuildMI(MBB, I, DL, TII->get(AMDGPU::S_LSHR_B32), AMDGPU::FLAT_SCR_HI)
- .addReg(FlatScrInitLo, RegState::Kill)
- .addImm(8);
- }
- // If we reserved the original input registers, we don't need to copy to the
- // reserved registers.
- if (ScratchRsrcReg == PreloadedPrivateBufferReg) {
- // We should always reserve these 5 registers at the same time.
- assert(ScratchWaveOffsetReg == PreloadedScratchWaveOffsetReg &&
- "scratch wave offset and private segment buffer inconsistent");
- return;
+ unsigned PreloadedPrivateBufferReg = AMDGPU::NoRegister;
+ if (ST.isAmdCodeObjectV2(MF) || ST.isMesaGfxShader(MF)) {
+ PreloadedPrivateBufferReg = TRI->getPreloadedValue(
+ MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER);
}
+ bool OffsetRegUsed = !MRI.use_empty(ScratchWaveOffsetReg);
+ bool ResourceRegUsed = !MRI.use_empty(ScratchRsrcReg);
// We added live-ins during argument lowering, but since they were not used
// they were deleted. We're adding the uses now, so add them back.
- MRI.addLiveIn(PreloadedScratchWaveOffsetReg);
- MBB.addLiveIn(PreloadedScratchWaveOffsetReg);
+ if (OffsetRegUsed) {
+ assert(PreloadedScratchWaveOffsetReg != AMDGPU::NoRegister &&
+ "scratch wave offset input is required");
+ MRI.addLiveIn(PreloadedScratchWaveOffsetReg);
+ MBB.addLiveIn(PreloadedScratchWaveOffsetReg);
+ }
- if (ST.isAmdHsaOS()) {
+ if (ResourceRegUsed && PreloadedPrivateBufferReg != AMDGPU::NoRegister) {
+ assert(ST.isAmdCodeObjectV2(MF) || ST.isMesaGfxShader(MF));
MRI.addLiveIn(PreloadedPrivateBufferReg);
MBB.addLiveIn(PreloadedPrivateBufferReg);
}
- if (!ST.hasSGPRInitBug()) {
- // We reserved the last registers for this. Shift it down to the end of those
- // which were actually used.
- //
- // FIXME: It might be safer to use a pseudoregister before replacement.
-
- // FIXME: We should be able to eliminate unused input registers. We only
- // cannot do this for the resources required for scratch access. For now we
- // skip over user SGPRs and may leave unused holes.
-
- // We find the resource first because it has an alignment requirement.
- if (ScratchRsrcReg == TRI->reservedPrivateSegmentBufferReg(MF)) {
- MachineRegisterInfo &MRI = MF.getRegInfo();
-
- unsigned NumPreloaded = MFI->getNumPreloadedSGPRs() / 4;
- // Skip the last 2 elements because the last one is reserved for VCC, and
- // this is the 2nd to last element already.
- for (MCPhysReg Reg : getAllSGPR128().drop_back(2).slice(NumPreloaded)) {
- // Pick the first unallocated one. Make sure we don't clobber the other
- // reserved input we needed.
- if (!MRI.isPhysRegUsed(Reg)) {
- assert(MRI.isAllocatable(Reg));
- MRI.replaceRegWith(ScratchRsrcReg, Reg);
- ScratchRsrcReg = Reg;
- MFI->setScratchRSrcReg(ScratchRsrcReg);
- break;
- }
- }
- }
+ // Make the register selected live throughout the function.
+ for (MachineBasicBlock &OtherBB : MF) {
+ if (&OtherBB == &MBB)
+ continue;
- if (ScratchWaveOffsetReg == TRI->reservedPrivateSegmentWaveByteOffsetReg(MF)) {
- MachineRegisterInfo &MRI = MF.getRegInfo();
- unsigned NumPreloaded = MFI->getNumPreloadedSGPRs();
-
- // We need to drop register from the end of the list that we cannot use
- // for the scratch wave offset.
- // + 2 s102 and s103 do not exist on VI.
- // + 2 for vcc
- // + 2 for xnack_mask
- // + 2 for flat_scratch
- // + 4 for registers reserved for scratch resource register
- // + 1 for register reserved for scratch wave offset. (By exluding this
- // register from the list to consider, it means that when this
- // register is being used for the scratch wave offset and there
- // are no other free SGPRs, then the value will stay in this register.
- // ----
- // 13
- for (MCPhysReg Reg : getAllSGPRs().drop_back(13).slice(NumPreloaded)) {
- // Pick the first unallocated SGPR. Be careful not to pick an alias of the
- // scratch descriptor, since we haven’t added its uses yet.
- if (!MRI.isPhysRegUsed(Reg)) {
- if (!MRI.isAllocatable(Reg) ||
- TRI->isSubRegisterEq(ScratchRsrcReg, Reg))
- continue;
-
- MRI.replaceRegWith(ScratchWaveOffsetReg, Reg);
- ScratchWaveOffsetReg = Reg;
- MFI->setScratchWaveOffsetReg(ScratchWaveOffsetReg);
- break;
- }
- }
- }
+ if (OffsetRegUsed)
+ OtherBB.addLiveIn(ScratchWaveOffsetReg);
+
+ if (ResourceRegUsed)
+ OtherBB.addLiveIn(ScratchRsrcReg);
}
+ DebugLoc DL;
+ MachineBasicBlock::iterator I = MBB.begin();
- assert(!TRI->isSubRegister(ScratchRsrcReg, ScratchWaveOffsetReg));
+ // If we reserved the original input registers, we don't need to copy to the
+ // reserved registers.
- const MCInstrDesc &SMovB32 = TII->get(AMDGPU::S_MOV_B32);
- DebugLoc DL;
+ bool CopyBuffer = ResourceRegUsed &&
+ PreloadedPrivateBufferReg != AMDGPU::NoRegister &&
+ ST.isAmdCodeObjectV2(MF) &&
+ ScratchRsrcReg != PreloadedPrivateBufferReg;
+
+ // This needs to be careful of the copying order to avoid overwriting one of
+ // the input registers before it's been copied to it's final
+ // destination. Usually the offset should be copied first.
+ bool CopyBufferFirst = TRI->isSubRegisterEq(PreloadedPrivateBufferReg,
+ ScratchWaveOffsetReg);
+ if (CopyBuffer && CopyBufferFirst) {
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::COPY), ScratchRsrcReg)
+ .addReg(PreloadedPrivateBufferReg, RegState::Kill);
+ }
- if (PreloadedScratchWaveOffsetReg != ScratchWaveOffsetReg) {
- // Make sure we emit the copy for the offset first. We may have chosen to copy
- // the buffer resource into a register that aliases the input offset register.
- BuildMI(MBB, I, DL, SMovB32, ScratchWaveOffsetReg)
+ if (OffsetRegUsed &&
+ PreloadedScratchWaveOffsetReg != ScratchWaveOffsetReg) {
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::COPY), ScratchWaveOffsetReg)
.addReg(PreloadedScratchWaveOffsetReg, RegState::Kill);
}
- if (ST.isAmdHsaOS()) {
- // Insert copies from argument register.
- assert(
- !TRI->isSubRegisterEq(PreloadedPrivateBufferReg, ScratchRsrcReg) &&
- !TRI->isSubRegisterEq(PreloadedPrivateBufferReg, ScratchWaveOffsetReg));
-
- unsigned Rsrc01 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0_sub1);
- unsigned Rsrc23 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2_sub3);
-
- unsigned Lo = TRI->getSubReg(PreloadedPrivateBufferReg, AMDGPU::sub0_sub1);
- unsigned Hi = TRI->getSubReg(PreloadedPrivateBufferReg, AMDGPU::sub2_sub3);
+ if (CopyBuffer && !CopyBufferFirst) {
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::COPY), ScratchRsrcReg)
+ .addReg(PreloadedPrivateBufferReg, RegState::Kill);
+ }
- const MCInstrDesc &SMovB64 = TII->get(AMDGPU::S_MOV_B64);
+ if (ResourceRegUsed && (ST.isMesaGfxShader(MF) || (PreloadedPrivateBufferReg == AMDGPU::NoRegister))) {
+ assert(!ST.isAmdCodeObjectV2(MF));
+ const MCInstrDesc &SMovB32 = TII->get(AMDGPU::S_MOV_B32);
- BuildMI(MBB, I, DL, SMovB64, Rsrc01)
- .addReg(Lo, RegState::Kill);
- BuildMI(MBB, I, DL, SMovB64, Rsrc23)
- .addReg(Hi, RegState::Kill);
- } else {
- unsigned Rsrc0 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0);
- unsigned Rsrc1 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub1);
unsigned Rsrc2 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2);
unsigned Rsrc3 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub3);
// Use relocations to get the pointer, and setup the other bits manually.
uint64_t Rsrc23 = TII->getScratchRsrcWords23();
- BuildMI(MBB, I, DL, SMovB32, Rsrc0)
- .addExternalSymbol("SCRATCH_RSRC_DWORD0")
- .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
- BuildMI(MBB, I, DL, SMovB32, Rsrc1)
- .addExternalSymbol("SCRATCH_RSRC_DWORD1")
- .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
+ if (MFI->hasPrivateMemoryInputPtr()) {
+ unsigned Rsrc01 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0_sub1);
+
+ if (AMDGPU::isCompute(MF.getFunction()->getCallingConv())) {
+ const MCInstrDesc &Mov64 = TII->get(AMDGPU::S_MOV_B64);
+
+ BuildMI(MBB, I, DL, Mov64, Rsrc01)
+ .addReg(PreloadedPrivateBufferReg)
+ .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
+ } else {
+ const MCInstrDesc &LoadDwordX2 = TII->get(AMDGPU::S_LOAD_DWORDX2_IMM);
+
+ PointerType *PtrTy =
+ PointerType::get(Type::getInt64Ty(MF.getFunction()->getContext()),
+ AMDGPUAS::CONSTANT_ADDRESS);
+ MachinePointerInfo PtrInfo(UndefValue::get(PtrTy));
+ auto MMO = MF.getMachineMemOperand(PtrInfo,
+ MachineMemOperand::MOLoad |
+ MachineMemOperand::MOInvariant |
+ MachineMemOperand::MODereferenceable,
+ 0, 0);
+ BuildMI(MBB, I, DL, LoadDwordX2, Rsrc01)
+ .addReg(PreloadedPrivateBufferReg)
+ .addImm(0) // offset
+ .addImm(0) // glc
+ .addMemOperand(MMO)
+ .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
+ }
+ } else {
+ unsigned Rsrc0 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0);
+ unsigned Rsrc1 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub1);
+
+ BuildMI(MBB, I, DL, SMovB32, Rsrc0)
+ .addExternalSymbol("SCRATCH_RSRC_DWORD0")
+ .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
+
+ BuildMI(MBB, I, DL, SMovB32, Rsrc1)
+ .addExternalSymbol("SCRATCH_RSRC_DWORD1")
+ .addReg(ScratchRsrcReg, RegState::ImplicitDefine);
+
+ }
BuildMI(MBB, I, DL, SMovB32, Rsrc2)
.addImm(Rsrc23 & 0xffffffff)
@@ -260,15 +364,6 @@ void SIFrameLowering::emitPrologue(MachineFunction &MF,
.addImm(Rsrc23 >> 32)
.addReg(ScratchRsrcReg, RegState::ImplicitDefine);
}
-
- // Make the register selected live throughout the function.
- for (MachineBasicBlock &OtherBB : MF) {
- if (&OtherBB == &MBB)
- continue;
-
- OtherBB.addLiveIn(ScratchRsrcReg);
- OtherBB.addLiveIn(ScratchWaveOffsetReg);
- }
}
void SIFrameLowering::emitEpilogue(MachineFunction &MF,
@@ -279,20 +374,20 @@ void SIFrameLowering::emitEpilogue(MachineFunction &MF,
void SIFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF,
RegScavenger *RS) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
- if (!MFI->hasStackObjects())
+ if (!MFI.hasStackObjects())
return;
- bool MayNeedScavengingEmergencySlot = MFI->hasStackObjects();
+ bool MayNeedScavengingEmergencySlot = MFI.hasStackObjects();
assert((RS || !MayNeedScavengingEmergencySlot) &&
"RegScavenger required if spilling");
if (MayNeedScavengingEmergencySlot) {
- int ScavengeFI = MFI->CreateSpillStackObject(
+ int ScavengeFI = MFI.CreateStackObject(
AMDGPU::SGPR_32RegClass.getSize(),
- AMDGPU::SGPR_32RegClass.getAlignment());
+ AMDGPU::SGPR_32RegClass.getAlignment(), false);
RS->addScavengingFrameIndex(ScavengeFI);
}
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index 37417d0..7657b4e 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -14,12 +14,17 @@
namespace llvm {
+class SIInstrInfo;
+class SIMachineFunctionInfo;
+class SIRegisterInfo;
+class SISubtarget;
+
class SIFrameLowering final : public AMDGPUFrameLowering {
public:
SIFrameLowering(StackDirection D, unsigned StackAl, int LAO,
unsigned TransAl = 1) :
AMDGPUFrameLowering(D, StackAl, LAO, TransAl) {}
- ~SIFrameLowering() override {}
+ ~SIFrameLowering() override = default;
void emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const override;
@@ -31,10 +36,29 @@ public:
RegScavenger *RS = nullptr) const override;
private:
+ void emitFlatScratchInit(const SIInstrInfo *TII,
+ const SIRegisterInfo* TRI,
+ MachineFunction &MF,
+ MachineBasicBlock &MBB) const;
+
+ unsigned getReservedPrivateSegmentBufferReg(
+ const SISubtarget &ST,
+ const SIInstrInfo *TII,
+ const SIRegisterInfo *TRI,
+ SIMachineFunctionInfo *MFI,
+ MachineFunction &MF) const;
+
+ unsigned getReservedPrivateSegmentWaveByteOffsetReg(
+ const SISubtarget &ST,
+ const SIInstrInfo *TII,
+ const SIRegisterInfo *TRI,
+ SIMachineFunctionInfo *MFI,
+ MachineFunction &MF) const;
+
/// \brief Emits debugger prologue.
void emitDebuggerPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const;
};
-}
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_AMDGPU_SIFRAMELOWERING_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 80d4435..b98f9f4 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -21,6 +21,7 @@
#include "AMDGPU.h"
#include "AMDGPUIntrinsicInfo.h"
#include "AMDGPUSubtarget.h"
+#include "SIDefines.h"
#include "SIISelLowering.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
@@ -31,17 +32,18 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/Analysis.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
using namespace llvm;
-// -amdgpu-fast-fdiv - Command line option to enable faster 2.5 ulp fdiv.
-static cl::opt<bool> EnableAMDGPUFastFDIV(
- "amdgpu-fast-fdiv",
- cl::desc("Enable faster 2.5 ulp fdiv"),
+static cl::opt<bool> EnableVGPRIndexMode(
+ "amdgpu-vgpr-index-mode",
+ cl::desc("Use GPR indexing mode instead of movrel for vector indexing"),
cl::init(false));
+
static unsigned findFirstFreeSGPR(CCState &CCInfo) {
unsigned NumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs();
for (unsigned Reg = 0; Reg < NumSGPRs; ++Reg) {
@@ -58,7 +60,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::i1, &AMDGPU::VReg_1RegClass);
addRegisterClass(MVT::i64, &AMDGPU::SReg_64RegClass);
- addRegisterClass(MVT::i32, &AMDGPU::SReg_32RegClass);
+ addRegisterClass(MVT::i32, &AMDGPU::SReg_32_XM0RegClass);
addRegisterClass(MVT::f32, &AMDGPU::VGPR_32RegClass);
addRegisterClass(MVT::f64, &AMDGPU::VReg_64RegClass);
@@ -77,6 +79,11 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::v16i32, &AMDGPU::SReg_512RegClass);
addRegisterClass(MVT::v16f32, &AMDGPU::VReg_512RegClass);
+ if (Subtarget->has16BitInsts()) {
+ addRegisterClass(MVT::i16, &AMDGPU::SReg_32_XM0RegClass);
+ addRegisterClass(MVT::f16, &AMDGPU::SReg_32_XM0RegClass);
+ }
+
computeRegisterProperties(STI.getRegisterInfo());
// We need to custom lower vector stores from local memory
@@ -92,9 +99,20 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STORE, MVT::v16i32, Custom);
setOperationAction(ISD::STORE, MVT::i1, Custom);
+ setTruncStoreAction(MVT::v2i32, MVT::v2i16, Expand);
+ setTruncStoreAction(MVT::v4i32, MVT::v4i16, Expand);
+ setTruncStoreAction(MVT::v8i32, MVT::v8i16, Expand);
+ setTruncStoreAction(MVT::v16i32, MVT::v16i16, Expand);
+ setTruncStoreAction(MVT::v32i32, MVT::v32i16, Expand);
+ setTruncStoreAction(MVT::v2i32, MVT::v2i8, Expand);
+ setTruncStoreAction(MVT::v4i32, MVT::v4i8, Expand);
+ setTruncStoreAction(MVT::v8i32, MVT::v8i8, Expand);
+ setTruncStoreAction(MVT::v16i32, MVT::v16i8, Expand);
+ setTruncStoreAction(MVT::v32i32, MVT::v32i8, Expand);
+
+
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::GlobalAddress, MVT::i64, Custom);
- setOperationAction(ISD::FrameIndex, MVT::i32, Custom);
setOperationAction(ISD::ConstantPool, MVT::v2i64, Expand);
setOperationAction(ISD::SELECT, MVT::i1, Promote);
@@ -111,6 +129,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SETCC, MVT::i1, Promote);
setOperationAction(ISD::SETCC, MVT::v2i1, Expand);
setOperationAction(ISD::SETCC, MVT::v4i1, Expand);
+ AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32);
setOperationAction(ISD::TRUNCATE, MVT::v2i32, Expand);
setOperationAction(ISD::FP_ROUND, MVT::v2f32, Expand);
@@ -159,6 +178,9 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
}
}
+ // TODO: For dynamic 64-bit vector inserts/extracts, should emit a pseudo that
+ // is expanded to avoid having two separate loops in case the index is a VGPR.
+
// Most operations are naturally 32-bit vector operations. We only support
// load and store of i64 vectors, so promote v2i64 vector operations to v4i32.
for (MVT Vec64 : { MVT::v2i64, MVT::v2f64 }) {
@@ -218,6 +240,83 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FDIV, MVT::f32, Custom);
setOperationAction(ISD::FDIV, MVT::f64, Custom);
+ if (Subtarget->has16BitInsts()) {
+ setOperationAction(ISD::Constant, MVT::i16, Legal);
+
+ setOperationAction(ISD::SMIN, MVT::i16, Legal);
+ setOperationAction(ISD::SMAX, MVT::i16, Legal);
+
+ setOperationAction(ISD::UMIN, MVT::i16, Legal);
+ setOperationAction(ISD::UMAX, MVT::i16, Legal);
+
+ setOperationAction(ISD::SIGN_EXTEND, MVT::i16, Promote);
+ AddPromotedToType(ISD::SIGN_EXTEND, MVT::i16, MVT::i32);
+
+ setOperationAction(ISD::ROTR, MVT::i16, Promote);
+ setOperationAction(ISD::ROTL, MVT::i16, Promote);
+
+ setOperationAction(ISD::SDIV, MVT::i16, Promote);
+ setOperationAction(ISD::UDIV, MVT::i16, Promote);
+ setOperationAction(ISD::SREM, MVT::i16, Promote);
+ setOperationAction(ISD::UREM, MVT::i16, Promote);
+
+ setOperationAction(ISD::BSWAP, MVT::i16, Promote);
+ setOperationAction(ISD::BITREVERSE, MVT::i16, Promote);
+
+ setOperationAction(ISD::CTTZ, MVT::i16, Promote);
+ setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i16, Promote);
+ setOperationAction(ISD::CTLZ, MVT::i16, Promote);
+ setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i16, Promote);
+
+ setOperationAction(ISD::SELECT_CC, MVT::i16, Expand);
+
+ setOperationAction(ISD::BR_CC, MVT::i16, Expand);
+
+ setOperationAction(ISD::LOAD, MVT::i16, Custom);
+
+ setTruncStoreAction(MVT::i64, MVT::i16, Expand);
+
+ setOperationAction(ISD::FP16_TO_FP, MVT::i16, Promote);
+ AddPromotedToType(ISD::FP16_TO_FP, MVT::i16, MVT::i32);
+ setOperationAction(ISD::FP_TO_FP16, MVT::i16, Promote);
+ AddPromotedToType(ISD::FP_TO_FP16, MVT::i16, MVT::i32);
+
+ setOperationAction(ISD::FP_TO_SINT, MVT::i16, Promote);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i16, Promote);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i16, Promote);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i16, Promote);
+
+ // F16 - Constant Actions.
+ setOperationAction(ISD::ConstantFP, MVT::f16, Legal);
+
+ // F16 - Load/Store Actions.
+ setOperationAction(ISD::LOAD, MVT::f16, Promote);
+ AddPromotedToType(ISD::LOAD, MVT::f16, MVT::i16);
+ setOperationAction(ISD::STORE, MVT::f16, Promote);
+ AddPromotedToType(ISD::STORE, MVT::f16, MVT::i16);
+
+ // F16 - VOP1 Actions.
+ setOperationAction(ISD::FP_ROUND, MVT::f16, Custom);
+ setOperationAction(ISD::FCOS, MVT::f16, Promote);
+ setOperationAction(ISD::FSIN, MVT::f16, Promote);
+ setOperationAction(ISD::FP_TO_SINT, MVT::f16, Promote);
+ setOperationAction(ISD::FP_TO_UINT, MVT::f16, Promote);
+ setOperationAction(ISD::SINT_TO_FP, MVT::f16, Promote);
+ setOperationAction(ISD::UINT_TO_FP, MVT::f16, Promote);
+
+ // F16 - VOP2 Actions.
+ setOperationAction(ISD::BR_CC, MVT::f16, Expand);
+ setOperationAction(ISD::SELECT_CC, MVT::f16, Expand);
+ setOperationAction(ISD::FMAXNUM, MVT::f16, Legal);
+ setOperationAction(ISD::FMINNUM, MVT::f16, Legal);
+ setOperationAction(ISD::FDIV, MVT::f16, Custom);
+
+ // F16 - VOP3 Actions.
+ setOperationAction(ISD::FMA, MVT::f16, Legal);
+ if (!Subtarget->hasFP16Denormals())
+ setOperationAction(ISD::FMAD, MVT::f16, Legal);
+ }
+
setTargetDAGCombine(ISD::FADD);
setTargetDAGCombine(ISD::FSUB);
setTargetDAGCombine(ISD::FMINNUM);
@@ -229,6 +328,8 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
setTargetDAGCombine(ISD::SETCC);
setTargetDAGCombine(ISD::AND);
setTargetDAGCombine(ISD::OR);
+ setTargetDAGCombine(ISD::XOR);
+ setTargetDAGCombine(ISD::SINT_TO_FP);
setTargetDAGCombine(ISD::UINT_TO_FP);
setTargetDAGCombine(ISD::FCANONICALIZE);
@@ -357,6 +458,7 @@ bool SITargetLowering::isLegalAddressingMode(const DataLayout &DL,
case AMDGPUAS::CONSTANT_ADDRESS: {
// If the offset isn't a multiple of 4, it probably isn't going to be
// correctly aligned.
+ // FIXME: Can we get the real alignment here?
if (AM.BaseOffs % 4 != 0)
return isLegalMUBUFAddressingMode(AM);
@@ -435,8 +537,12 @@ bool SITargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
// TODO: I think v3i32 should allow unaligned accesses on CI with DS_READ_B96,
// which isn't a simple VT.
- if (!VT.isSimple() || VT == MVT::Other)
+ // Until MVT is extended to handle this, simply check for the size and
+ // rely on the condition below: allow accesses if the size is a multiple of 4.
+ if (VT == MVT::Other || (VT != MVT::Other && VT.getSizeInBits() > 1024 &&
+ VT.getStoreSize() > 16)) {
return false;
+ }
if (AddrSpace == AMDGPUAS::LOCAL_ADDRESS ||
AddrSpace == AMDGPUAS::REGION_ADDRESS) {
@@ -450,6 +556,15 @@ bool SITargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
return AlignedBy4;
}
+ // FIXME: We have to be conservative here and assume that flat operations
+ // will access scratch. If we had access to the IR function, then we
+ // could determine if any private memory was used in the function.
+ if (!Subtarget->hasUnalignedScratchAccess() &&
+ (AddrSpace == AMDGPUAS::PRIVATE_ADDRESS ||
+ AddrSpace == AMDGPUAS::FLAT_ADDRESS)) {
+ return false;
+ }
+
if (Subtarget->hasUnalignedBufferAccess()) {
// If we have an uniform constant load, it still requires using a slow
// buffer instruction if unaligned.
@@ -496,8 +611,8 @@ EVT SITargetLowering::getOptimalMemOpType(uint64_t Size, unsigned DstAlign,
static bool isFlatGlobalAddrSpace(unsigned AS) {
return AS == AMDGPUAS::GLOBAL_ADDRESS ||
- AS == AMDGPUAS::FLAT_ADDRESS ||
- AS == AMDGPUAS::CONSTANT_ADDRESS;
+ AS == AMDGPUAS::FLAT_ADDRESS ||
+ AS == AMDGPUAS::CONSTANT_ADDRESS;
}
bool SITargetLowering::isNoopAddrSpaceCast(unsigned SrcAS,
@@ -505,6 +620,23 @@ bool SITargetLowering::isNoopAddrSpaceCast(unsigned SrcAS,
return isFlatGlobalAddrSpace(SrcAS) && isFlatGlobalAddrSpace(DestAS);
}
+bool SITargetLowering::isMemOpHasNoClobberedMemOperand(const SDNode *N) const {
+ const MemSDNode *MemNode = cast<MemSDNode>(N);
+ const Value *Ptr = MemNode->getMemOperand()->getValue();
+ const Instruction *I = dyn_cast<Instruction>(Ptr);
+ return I && I->getMetadata("amdgpu.noclobber");
+}
+
+bool SITargetLowering::isCheapAddrSpaceCast(unsigned SrcAS,
+ unsigned DestAS) const {
+ // Flat -> private/local is a simple truncate.
+ // Flat -> global is no-op
+ if (SrcAS == AMDGPUAS::FLAT_ADDRESS)
+ return true;
+
+ return isNoopAddrSpaceCast(SrcAS, DestAS);
+}
+
bool SITargetLowering::isMemOpUniform(const SDNode *N) const {
const MemSDNode *MemNode = cast<MemSDNode>(N);
const Value *Ptr = MemNode->getMemOperand()->getValue();
@@ -531,11 +663,27 @@ SITargetLowering::getPreferredVectorAction(EVT VT) const {
bool SITargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,
Type *Ty) const {
- const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
- return TII->isInlineConstant(Imm);
+ // FIXME: Could be smarter if called for vector constants.
+ return true;
}
bool SITargetLowering::isTypeDesirableForOp(unsigned Op, EVT VT) const {
+ if (Subtarget->has16BitInsts() && VT == MVT::i16) {
+ switch (Op) {
+ case ISD::LOAD:
+ case ISD::STORE:
+
+ // These operations are done with 32-bit instructions anyway.
+ case ISD::AND:
+ case ISD::OR:
+ case ISD::XOR:
+ case ISD::SELECT:
+ // TODO: Extensions?
+ return true;
+ default:
+ return false;
+ }
+ }
// SimplifySetCC uses this function to determine whether or not it should
// create setcc with i1 operands. We don't have instructions for i1 setcc.
@@ -560,26 +708,39 @@ SDValue SITargetLowering::LowerParameterPtr(SelectionDAG &DAG,
return DAG.getNode(ISD::ADD, SL, PtrVT, BasePtr,
DAG.getConstant(Offset, SL, PtrVT));
}
+
SDValue SITargetLowering::LowerParameter(SelectionDAG &DAG, EVT VT, EVT MemVT,
const SDLoc &SL, SDValue Chain,
- unsigned Offset, bool Signed) const {
+ unsigned Offset, bool Signed,
+ const ISD::InputArg *Arg) const {
const DataLayout &DL = DAG.getDataLayout();
- Type *Ty = VT.getTypeForEVT(*DAG.getContext());
- MVT PtrVT = getPointerTy(DL, AMDGPUAS::CONSTANT_ADDRESS);
+ Type *Ty = MemVT.getTypeForEVT(*DAG.getContext());
PointerType *PtrTy = PointerType::get(Ty, AMDGPUAS::CONSTANT_ADDRESS);
- SDValue PtrOffset = DAG.getUNDEF(PtrVT);
MachinePointerInfo PtrInfo(UndefValue::get(PtrTy));
unsigned Align = DL.getABITypeAlignment(Ty);
- ISD::LoadExtType ExtTy = Signed ? ISD::SEXTLOAD : ISD::ZEXTLOAD;
+ SDValue Ptr = LowerParameterPtr(DAG, SL, Chain, Offset);
+ SDValue Load = DAG.getLoad(MemVT, SL, Chain, Ptr, PtrInfo, Align,
+ MachineMemOperand::MONonTemporal |
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
+
+ SDValue Val = Load;
+ if (Arg && (Arg->Flags.isSExt() || Arg->Flags.isZExt()) &&
+ VT.bitsLT(MemVT)) {
+ unsigned Opc = Arg->Flags.isZExt() ? ISD::AssertZext : ISD::AssertSext;
+ Val = DAG.getNode(Opc, SL, MemVT, Val, DAG.getValueType(VT));
+ }
+
if (MemVT.isFloatingPoint())
- ExtTy = ISD::EXTLOAD;
+ Val = getFPExtOrFPTrunc(DAG, Val, SL, VT);
+ else if (Signed)
+ Val = DAG.getSExtOrTrunc(Val, SL, VT);
+ else
+ Val = DAG.getZExtOrTrunc(Val, SL, VT);
- SDValue Ptr = LowerParameterPtr(DAG, SL, Chain, Offset);
- return DAG.getLoad(ISD::UNINDEXED, ExtTy, VT, SL, Chain, Ptr, PtrOffset,
- PtrInfo, MemVT, Align, MachineMemOperand::MONonTemporal |
- MachineMemOperand::MOInvariant);
+ return DAG.getMergeValues({ Val, Load.getValue(1) }, SL);
}
SDValue SITargetLowering::LowerFormalArguments(
@@ -679,12 +840,9 @@ SDValue SITargetLowering::LowerFormalArguments(
}
if (!AMDGPU::isShader(CallConv)) {
- getOriginalFunctionArgs(DAG, DAG.getMachineFunction().getFunction(), Ins,
- Splits);
-
assert(Info->hasWorkGroupIDX() && Info->hasWorkItemIDX());
} else {
- assert(!Info->hasPrivateSegmentBuffer() && !Info->hasDispatchPtr() &&
+ assert(!Info->hasDispatchPtr() &&
!Info->hasKernargSegmentPtr() && !Info->hasFlatScratchInit() &&
!Info->hasWorkGroupIDX() && !Info->hasWorkGroupIDY() &&
!Info->hasWorkGroupIDZ() && !Info->hasWorkGroupInfo() &&
@@ -692,6 +850,12 @@ SDValue SITargetLowering::LowerFormalArguments(
!Info->hasWorkItemIDZ());
}
+ if (Info->hasPrivateMemoryInputPtr()) {
+ unsigned PrivateMemoryPtrReg = Info->addPrivateMemoryPtr(*TRI);
+ MF.addLiveIn(PrivateMemoryPtrReg, &AMDGPU::SReg_64RegClass);
+ CCInfo.AllocateReg(PrivateMemoryPtrReg);
+ }
+
// FIXME: How should these inputs interact with inreg / custom SGPR inputs?
if (Info->hasPrivateSegmentBuffer()) {
unsigned PrivateSegmentBufferReg = Info->addPrivateSegmentBuffer(*TRI);
@@ -701,29 +865,38 @@ SDValue SITargetLowering::LowerFormalArguments(
if (Info->hasDispatchPtr()) {
unsigned DispatchPtrReg = Info->addDispatchPtr(*TRI);
- MF.addLiveIn(DispatchPtrReg, &AMDGPU::SReg_64RegClass);
+ MF.addLiveIn(DispatchPtrReg, &AMDGPU::SGPR_64RegClass);
CCInfo.AllocateReg(DispatchPtrReg);
}
if (Info->hasQueuePtr()) {
unsigned QueuePtrReg = Info->addQueuePtr(*TRI);
- MF.addLiveIn(QueuePtrReg, &AMDGPU::SReg_64RegClass);
+ MF.addLiveIn(QueuePtrReg, &AMDGPU::SGPR_64RegClass);
CCInfo.AllocateReg(QueuePtrReg);
}
if (Info->hasKernargSegmentPtr()) {
unsigned InputPtrReg = Info->addKernargSegmentPtr(*TRI);
- MF.addLiveIn(InputPtrReg, &AMDGPU::SReg_64RegClass);
+ MF.addLiveIn(InputPtrReg, &AMDGPU::SGPR_64RegClass);
CCInfo.AllocateReg(InputPtrReg);
}
+ if (Info->hasDispatchID()) {
+ unsigned DispatchIDReg = Info->addDispatchID(*TRI);
+ MF.addLiveIn(DispatchIDReg, &AMDGPU::SGPR_64RegClass);
+ CCInfo.AllocateReg(DispatchIDReg);
+ }
+
if (Info->hasFlatScratchInit()) {
unsigned FlatScratchInitReg = Info->addFlatScratchInit(*TRI);
- MF.addLiveIn(FlatScratchInitReg, &AMDGPU::SReg_64RegClass);
+ MF.addLiveIn(FlatScratchInitReg, &AMDGPU::SGPR_64RegClass);
CCInfo.AllocateReg(FlatScratchInitReg);
}
- AnalyzeFormalArguments(CCInfo, Splits);
+ if (!AMDGPU::isShader(CallConv))
+ analyzeFormalArgumentsCompute(CCInfo, Ins);
+ else
+ AnalyzeFormalArguments(CCInfo, Splits);
SmallVector<SDValue, 16> Chains;
@@ -740,13 +913,14 @@ SDValue SITargetLowering::LowerFormalArguments(
if (VA.isMemLoc()) {
VT = Ins[i].VT;
- EVT MemVT = Splits[i].VT;
- const unsigned Offset = Subtarget->getExplicitKernelArgOffset() +
+ EVT MemVT = VA.getLocVT();
+ const unsigned Offset = Subtarget->getExplicitKernelArgOffset(MF) +
VA.getLocMemOffset();
// The first 36 bytes of the input buffer contains information about
// thread group and global sizes.
SDValue Arg = LowerParameter(DAG, VT, MemVT, DL, Chain,
- Offset, Ins[i].Flags.isSExt());
+ Offset, Ins[i].Flags.isSExt(),
+ &Ins[i]);
Chains.push_back(Arg.getValue(1));
auto *ParamTy =
@@ -761,7 +935,7 @@ SDValue SITargetLowering::LowerFormalArguments(
}
InVals.push_back(Arg);
- Info->ABIArgOffset = Offset + MemVT.getStoreSize();
+ Info->setABIArgOffset(Offset + MemVT.getStoreSize());
continue;
}
assert(VA.isRegLoc() && "Parameter must be in a register!");
@@ -771,8 +945,8 @@ SDValue SITargetLowering::LowerFormalArguments(
if (VT == MVT::i64) {
// For now assume it is a pointer
Reg = TRI->getMatchingSuperReg(Reg, AMDGPU::sub0,
- &AMDGPU::SReg_64RegClass);
- Reg = MF.addLiveIn(Reg, &AMDGPU::SReg_64RegClass);
+ &AMDGPU::SGPR_64RegClass);
+ Reg = MF.addLiveIn(Reg, &AMDGPU::SGPR_64RegClass);
SDValue Copy = DAG.getCopyFromReg(Chain, DL, Reg, VT);
InVals.push_back(Copy);
continue;
@@ -816,25 +990,25 @@ SDValue SITargetLowering::LowerFormalArguments(
// Start adding system SGPRs.
if (Info->hasWorkGroupIDX()) {
unsigned Reg = Info->addWorkGroupIDX();
- MF.addLiveIn(Reg, &AMDGPU::SReg_32RegClass);
+ MF.addLiveIn(Reg, &AMDGPU::SReg_32_XM0RegClass);
CCInfo.AllocateReg(Reg);
}
if (Info->hasWorkGroupIDY()) {
unsigned Reg = Info->addWorkGroupIDY();
- MF.addLiveIn(Reg, &AMDGPU::SReg_32RegClass);
+ MF.addLiveIn(Reg, &AMDGPU::SReg_32_XM0RegClass);
CCInfo.AllocateReg(Reg);
}
if (Info->hasWorkGroupIDZ()) {
unsigned Reg = Info->addWorkGroupIDZ();
- MF.addLiveIn(Reg, &AMDGPU::SReg_32RegClass);
+ MF.addLiveIn(Reg, &AMDGPU::SReg_32_XM0RegClass);
CCInfo.AllocateReg(Reg);
}
if (Info->hasWorkGroupInfo()) {
unsigned Reg = Info->addWorkGroupInfo();
- MF.addLiveIn(Reg, &AMDGPU::SReg_32RegClass);
+ MF.addLiveIn(Reg, &AMDGPU::SReg_32_XM0RegClass);
CCInfo.AllocateReg(Reg);
}
@@ -854,18 +1028,22 @@ SDValue SITargetLowering::LowerFormalArguments(
// Now that we've figured out where the scratch register inputs are, see if
// should reserve the arguments and use them directly.
- bool HasStackObjects = MF.getFrameInfo()->hasStackObjects();
+ bool HasStackObjects = MF.getFrameInfo().hasStackObjects();
// Record that we know we have non-spill stack objects so we don't need to
// check all stack objects later.
if (HasStackObjects)
Info->setHasNonSpillStackObjects(true);
- if (ST.isAmdHsaOS()) {
- // TODO: Assume we will spill without optimizations.
+ // Everything live out of a block is spilled with fast regalloc, so it's
+ // almost certain that spilling will be required.
+ if (getTargetMachine().getOptLevel() == CodeGenOpt::None)
+ HasStackObjects = true;
+
+ if (ST.isAmdCodeObjectV2(MF)) {
if (HasStackObjects) {
// If we have stack objects, we unquestionably need the private buffer
- // resource. For the HSA ABI, this will be the first 4 user SGPR
- // inputs. We can reserve those and use them directly.
+ // resource. For the Code Object V2 ABI, this will be the first 4 user
+ // SGPR inputs. We can reserve those and use them directly.
unsigned PrivateSegmentBufferReg = TRI->getPreloadedValue(
MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER);
@@ -1088,64 +1266,551 @@ MachineBasicBlock *SITargetLowering::splitKillBlock(MachineInstr &MI,
MachineBasicBlock *SplitBB
= MF->CreateMachineBasicBlock(BB->getBasicBlock());
- // Fix the block phi references to point to the new block for the defs in the
- // second piece of the block.
- for (MachineBasicBlock *Succ : BB->successors()) {
- for (MachineInstr &MI : *Succ) {
- if (!MI.isPHI())
- break;
-
- for (unsigned I = 2, E = MI.getNumOperands(); I != E; I += 2) {
- MachineOperand &FromBB = MI.getOperand(I);
- if (BB == FromBB.getMBB()) {
- FromBB.setMBB(SplitBB);
- break;
- }
- }
- }
- }
-
MF->insert(++MachineFunction::iterator(BB), SplitBB);
SplitBB->splice(SplitBB->begin(), BB, SplitPoint, BB->end());
- SplitBB->transferSuccessors(BB);
+ SplitBB->transferSuccessorsAndUpdatePHIs(BB);
BB->addSuccessor(SplitBB);
MI.setDesc(TII->get(AMDGPU::SI_KILL_TERMINATOR));
return SplitBB;
}
+// Do a v_movrels_b32 or v_movreld_b32 for each unique value of \p IdxReg in the
+// wavefront. If the value is uniform and just happens to be in a VGPR, this
+// will only do one iteration. In the worst case, this will loop 64 times.
+//
+// TODO: Just use v_readlane_b32 if we know the VGPR has a uniform value.
+static MachineBasicBlock::iterator emitLoadM0FromVGPRLoop(
+ const SIInstrInfo *TII,
+ MachineRegisterInfo &MRI,
+ MachineBasicBlock &OrigBB,
+ MachineBasicBlock &LoopBB,
+ const DebugLoc &DL,
+ const MachineOperand &IdxReg,
+ unsigned InitReg,
+ unsigned ResultReg,
+ unsigned PhiReg,
+ unsigned InitSaveExecReg,
+ int Offset,
+ bool UseGPRIdxMode) {
+ MachineBasicBlock::iterator I = LoopBB.begin();
+
+ unsigned PhiExec = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
+ unsigned NewExec = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
+ unsigned CurrentIdxReg = MRI.createVirtualRegister(&AMDGPU::SGPR_32RegClass);
+ unsigned CondReg = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
+
+ BuildMI(LoopBB, I, DL, TII->get(TargetOpcode::PHI), PhiReg)
+ .addReg(InitReg)
+ .addMBB(&OrigBB)
+ .addReg(ResultReg)
+ .addMBB(&LoopBB);
+
+ BuildMI(LoopBB, I, DL, TII->get(TargetOpcode::PHI), PhiExec)
+ .addReg(InitSaveExecReg)
+ .addMBB(&OrigBB)
+ .addReg(NewExec)
+ .addMBB(&LoopBB);
+
+ // Read the next variant <- also loop target.
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), CurrentIdxReg)
+ .addReg(IdxReg.getReg(), getUndefRegState(IdxReg.isUndef()));
+
+ // Compare the just read M0 value to all possible Idx values.
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::V_CMP_EQ_U32_e64), CondReg)
+ .addReg(CurrentIdxReg)
+ .addReg(IdxReg.getReg(), 0, IdxReg.getSubReg());
+
+ if (UseGPRIdxMode) {
+ unsigned IdxReg;
+ if (Offset == 0) {
+ IdxReg = CurrentIdxReg;
+ } else {
+ IdxReg = MRI.createVirtualRegister(&AMDGPU::SGPR_32RegClass);
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_ADD_I32), IdxReg)
+ .addReg(CurrentIdxReg, RegState::Kill)
+ .addImm(Offset);
+ }
+
+ MachineInstr *SetIdx =
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_IDX))
+ .addReg(IdxReg, RegState::Kill);
+ SetIdx->getOperand(2).setIsUndef();
+ } else {
+ // Move index from VCC into M0
+ if (Offset == 0) {
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0)
+ .addReg(CurrentIdxReg, RegState::Kill);
+ } else {
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0)
+ .addReg(CurrentIdxReg, RegState::Kill)
+ .addImm(Offset);
+ }
+ }
+
+ // Update EXEC, save the original EXEC value to VCC.
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_AND_SAVEEXEC_B64), NewExec)
+ .addReg(CondReg, RegState::Kill);
+
+ MRI.setSimpleHint(NewExec, CondReg);
+
+ // Update EXEC, switch all done bits to 0 and all todo bits to 1.
+ MachineInstr *InsertPt =
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_XOR_B64), AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC)
+ .addReg(NewExec);
+
+ // XXX - s_xor_b64 sets scc to 1 if the result is nonzero, so can we use
+ // s_cbranch_scc0?
+
+ // Loop back to V_READFIRSTLANE_B32 if there are still variants to cover.
+ BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))
+ .addMBB(&LoopBB);
+
+ return InsertPt->getIterator();
+}
+
+// This has slightly sub-optimal regalloc when the source vector is killed by
+// the read. The register allocator does not understand that the kill is
+// per-workitem, so is kept alive for the whole loop so we end up not re-using a
+// subregister from it, using 1 more VGPR than necessary. This was saved when
+// this was expanded after register allocation.
+static MachineBasicBlock::iterator loadM0FromVGPR(const SIInstrInfo *TII,
+ MachineBasicBlock &MBB,
+ MachineInstr &MI,
+ unsigned InitResultReg,
+ unsigned PhiReg,
+ int Offset,
+ bool UseGPRIdxMode) {
+ MachineFunction *MF = MBB.getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock::iterator I(&MI);
+
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SaveExec = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
+ unsigned TmpExec = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
+
+ BuildMI(MBB, I, DL, TII->get(TargetOpcode::IMPLICIT_DEF), TmpExec);
+
+ // Save the EXEC mask
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B64), SaveExec)
+ .addReg(AMDGPU::EXEC);
+
+ // To insert the loop we need to split the block. Move everything after this
+ // point to a new block, and insert a new empty block between the two.
+ MachineBasicBlock *LoopBB = MF->CreateMachineBasicBlock();
+ MachineBasicBlock *RemainderBB = MF->CreateMachineBasicBlock();
+ MachineFunction::iterator MBBI(MBB);
+ ++MBBI;
+
+ MF->insert(MBBI, LoopBB);
+ MF->insert(MBBI, RemainderBB);
+
+ LoopBB->addSuccessor(LoopBB);
+ LoopBB->addSuccessor(RemainderBB);
+
+ // Move the rest of the block into a new block.
+ RemainderBB->transferSuccessorsAndUpdatePHIs(&MBB);
+ RemainderBB->splice(RemainderBB->begin(), &MBB, I, MBB.end());
+
+ MBB.addSuccessor(LoopBB);
+
+ const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);
+
+ auto InsPt = emitLoadM0FromVGPRLoop(TII, MRI, MBB, *LoopBB, DL, *Idx,
+ InitResultReg, DstReg, PhiReg, TmpExec,
+ Offset, UseGPRIdxMode);
+
+ MachineBasicBlock::iterator First = RemainderBB->begin();
+ BuildMI(*RemainderBB, First, DL, TII->get(AMDGPU::S_MOV_B64), AMDGPU::EXEC)
+ .addReg(SaveExec);
+
+ return InsPt;
+}
+
+// Returns subreg index, offset
+static std::pair<unsigned, int>
+computeIndirectRegAndOffset(const SIRegisterInfo &TRI,
+ const TargetRegisterClass *SuperRC,
+ unsigned VecReg,
+ int Offset) {
+ int NumElts = SuperRC->getSize() / 4;
+
+ // Skip out of bounds offsets, or else we would end up using an undefined
+ // register.
+ if (Offset >= NumElts || Offset < 0)
+ return std::make_pair(AMDGPU::sub0, Offset);
+
+ return std::make_pair(AMDGPU::sub0 + Offset, 0);
+}
+
+// Return true if the index is an SGPR and was set.
+static bool setM0ToIndexFromSGPR(const SIInstrInfo *TII,
+ MachineRegisterInfo &MRI,
+ MachineInstr &MI,
+ int Offset,
+ bool UseGPRIdxMode,
+ bool IsIndirectSrc) {
+ MachineBasicBlock *MBB = MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock::iterator I(&MI);
+
+ const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);
+ const TargetRegisterClass *IdxRC = MRI.getRegClass(Idx->getReg());
+
+ assert(Idx->getReg() != AMDGPU::NoRegister);
+
+ if (!TII->getRegisterInfo().isSGPRClass(IdxRC))
+ return false;
+
+ if (UseGPRIdxMode) {
+ unsigned IdxMode = IsIndirectSrc ?
+ VGPRIndexMode::SRC0_ENABLE : VGPRIndexMode::DST_ENABLE;
+ if (Offset == 0) {
+ MachineInstr *SetOn =
+ BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_ON))
+ .addOperand(*Idx)
+ .addImm(IdxMode);
+
+ SetOn->getOperand(3).setIsUndef();
+ } else {
+ unsigned Tmp = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+ BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_ADD_I32), Tmp)
+ .addOperand(*Idx)
+ .addImm(Offset);
+ MachineInstr *SetOn =
+ BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_ON))
+ .addReg(Tmp, RegState::Kill)
+ .addImm(IdxMode);
+
+ SetOn->getOperand(3).setIsUndef();
+ }
+
+ return true;
+ }
+
+ if (Offset == 0) {
+ BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0)
+ .addOperand(*Idx);
+ } else {
+ BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0)
+ .addOperand(*Idx)
+ .addImm(Offset);
+ }
+
+ return true;
+}
+
+// Control flow needs to be inserted if indexing with a VGPR.
+static MachineBasicBlock *emitIndirectSrc(MachineInstr &MI,
+ MachineBasicBlock &MBB,
+ const SISubtarget &ST) {
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ const SIRegisterInfo &TRI = TII->getRegisterInfo();
+ MachineFunction *MF = MBB.getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+
+ unsigned Dst = MI.getOperand(0).getReg();
+ unsigned SrcReg = TII->getNamedOperand(MI, AMDGPU::OpName::src)->getReg();
+ int Offset = TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm();
+
+ const TargetRegisterClass *VecRC = MRI.getRegClass(SrcReg);
+
+ unsigned SubReg;
+ std::tie(SubReg, Offset)
+ = computeIndirectRegAndOffset(TRI, VecRC, SrcReg, Offset);
+
+ bool UseGPRIdxMode = ST.hasVGPRIndexMode() && EnableVGPRIndexMode;
+
+ if (setM0ToIndexFromSGPR(TII, MRI, MI, Offset, UseGPRIdxMode, true)) {
+ MachineBasicBlock::iterator I(&MI);
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ if (UseGPRIdxMode) {
+ // TODO: Look at the uses to avoid the copy. This may require rescheduling
+ // to avoid interfering with other uses, so probably requires a new
+ // optimization pass.
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::V_MOV_B32_e32), Dst)
+ .addReg(SrcReg, RegState::Undef, SubReg)
+ .addReg(SrcReg, RegState::Implicit)
+ .addReg(AMDGPU::M0, RegState::Implicit);
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_OFF));
+ } else {
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::V_MOVRELS_B32_e32), Dst)
+ .addReg(SrcReg, RegState::Undef, SubReg)
+ .addReg(SrcReg, RegState::Implicit);
+ }
+
+ MI.eraseFromParent();
+
+ return &MBB;
+ }
+
+
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock::iterator I(&MI);
+
+ unsigned PhiReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ unsigned InitReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+
+ BuildMI(MBB, I, DL, TII->get(TargetOpcode::IMPLICIT_DEF), InitReg);
+
+ if (UseGPRIdxMode) {
+ MachineInstr *SetOn = BuildMI(MBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_ON))
+ .addImm(0) // Reset inside loop.
+ .addImm(VGPRIndexMode::SRC0_ENABLE);
+ SetOn->getOperand(3).setIsUndef();
+
+ // Disable again after the loop.
+ BuildMI(MBB, std::next(I), DL, TII->get(AMDGPU::S_SET_GPR_IDX_OFF));
+ }
+
+ auto InsPt = loadM0FromVGPR(TII, MBB, MI, InitReg, PhiReg, Offset, UseGPRIdxMode);
+ MachineBasicBlock *LoopBB = InsPt->getParent();
+
+ if (UseGPRIdxMode) {
+ BuildMI(*LoopBB, InsPt, DL, TII->get(AMDGPU::V_MOV_B32_e32), Dst)
+ .addReg(SrcReg, RegState::Undef, SubReg)
+ .addReg(SrcReg, RegState::Implicit)
+ .addReg(AMDGPU::M0, RegState::Implicit);
+ } else {
+ BuildMI(*LoopBB, InsPt, DL, TII->get(AMDGPU::V_MOVRELS_B32_e32), Dst)
+ .addReg(SrcReg, RegState::Undef, SubReg)
+ .addReg(SrcReg, RegState::Implicit);
+ }
+
+ MI.eraseFromParent();
+
+ return LoopBB;
+}
+
+static unsigned getMOVRELDPseudo(const TargetRegisterClass *VecRC) {
+ switch (VecRC->getSize()) {
+ case 4:
+ return AMDGPU::V_MOVRELD_B32_V1;
+ case 8:
+ return AMDGPU::V_MOVRELD_B32_V2;
+ case 16:
+ return AMDGPU::V_MOVRELD_B32_V4;
+ case 32:
+ return AMDGPU::V_MOVRELD_B32_V8;
+ case 64:
+ return AMDGPU::V_MOVRELD_B32_V16;
+ default:
+ llvm_unreachable("unsupported size for MOVRELD pseudos");
+ }
+}
+
+static MachineBasicBlock *emitIndirectDst(MachineInstr &MI,
+ MachineBasicBlock &MBB,
+ const SISubtarget &ST) {
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ const SIRegisterInfo &TRI = TII->getRegisterInfo();
+ MachineFunction *MF = MBB.getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+
+ unsigned Dst = MI.getOperand(0).getReg();
+ const MachineOperand *SrcVec = TII->getNamedOperand(MI, AMDGPU::OpName::src);
+ const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);
+ const MachineOperand *Val = TII->getNamedOperand(MI, AMDGPU::OpName::val);
+ int Offset = TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm();
+ const TargetRegisterClass *VecRC = MRI.getRegClass(SrcVec->getReg());
+
+ // This can be an immediate, but will be folded later.
+ assert(Val->getReg());
+
+ unsigned SubReg;
+ std::tie(SubReg, Offset) = computeIndirectRegAndOffset(TRI, VecRC,
+ SrcVec->getReg(),
+ Offset);
+ bool UseGPRIdxMode = ST.hasVGPRIndexMode() && EnableVGPRIndexMode;
+
+ if (Idx->getReg() == AMDGPU::NoRegister) {
+ MachineBasicBlock::iterator I(&MI);
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ assert(Offset == 0);
+
+ BuildMI(MBB, I, DL, TII->get(TargetOpcode::INSERT_SUBREG), Dst)
+ .addOperand(*SrcVec)
+ .addOperand(*Val)
+ .addImm(SubReg);
+
+ MI.eraseFromParent();
+ return &MBB;
+ }
+
+ if (setM0ToIndexFromSGPR(TII, MRI, MI, Offset, UseGPRIdxMode, false)) {
+ MachineBasicBlock::iterator I(&MI);
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ if (UseGPRIdxMode) {
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::V_MOV_B32_indirect))
+ .addReg(SrcVec->getReg(), RegState::Undef, SubReg) // vdst
+ .addOperand(*Val)
+ .addReg(Dst, RegState::ImplicitDefine)
+ .addReg(SrcVec->getReg(), RegState::Implicit)
+ .addReg(AMDGPU::M0, RegState::Implicit);
+
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_OFF));
+ } else {
+ const MCInstrDesc &MovRelDesc = TII->get(getMOVRELDPseudo(VecRC));
+
+ BuildMI(MBB, I, DL, MovRelDesc)
+ .addReg(Dst, RegState::Define)
+ .addReg(SrcVec->getReg())
+ .addOperand(*Val)
+ .addImm(SubReg - AMDGPU::sub0);
+ }
+
+ MI.eraseFromParent();
+ return &MBB;
+ }
+
+ if (Val->isReg())
+ MRI.clearKillFlags(Val->getReg());
+
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ if (UseGPRIdxMode) {
+ MachineBasicBlock::iterator I(&MI);
+
+ MachineInstr *SetOn = BuildMI(MBB, I, DL, TII->get(AMDGPU::S_SET_GPR_IDX_ON))
+ .addImm(0) // Reset inside loop.
+ .addImm(VGPRIndexMode::DST_ENABLE);
+ SetOn->getOperand(3).setIsUndef();
+
+ // Disable again after the loop.
+ BuildMI(MBB, std::next(I), DL, TII->get(AMDGPU::S_SET_GPR_IDX_OFF));
+ }
+
+ unsigned PhiReg = MRI.createVirtualRegister(VecRC);
+
+ auto InsPt = loadM0FromVGPR(TII, MBB, MI, SrcVec->getReg(), PhiReg,
+ Offset, UseGPRIdxMode);
+ MachineBasicBlock *LoopBB = InsPt->getParent();
+
+ if (UseGPRIdxMode) {
+ BuildMI(*LoopBB, InsPt, DL, TII->get(AMDGPU::V_MOV_B32_indirect))
+ .addReg(PhiReg, RegState::Undef, SubReg) // vdst
+ .addOperand(*Val) // src0
+ .addReg(Dst, RegState::ImplicitDefine)
+ .addReg(PhiReg, RegState::Implicit)
+ .addReg(AMDGPU::M0, RegState::Implicit);
+ } else {
+ const MCInstrDesc &MovRelDesc = TII->get(getMOVRELDPseudo(VecRC));
+
+ BuildMI(*LoopBB, InsPt, DL, MovRelDesc)
+ .addReg(Dst, RegState::Define)
+ .addReg(PhiReg)
+ .addOperand(*Val)
+ .addImm(SubReg - AMDGPU::sub0);
+ }
+
+ MI.eraseFromParent();
+
+ return LoopBB;
+}
+
MachineBasicBlock *SITargetLowering::EmitInstrWithCustomInserter(
MachineInstr &MI, MachineBasicBlock *BB) const {
+
+ const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
+ MachineFunction *MF = BB->getParent();
+ SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
+
+ if (TII->isMIMG(MI)) {
+ if (!MI.memoperands_empty())
+ return BB;
+ // Add a memoperand for mimg instructions so that they aren't assumed to
+ // be ordered memory instuctions.
+
+ MachinePointerInfo PtrInfo(MFI->getImagePSV());
+ MachineMemOperand::Flags Flags = MachineMemOperand::MODereferenceable;
+ if (MI.mayStore())
+ Flags |= MachineMemOperand::MOStore;
+
+ if (MI.mayLoad())
+ Flags |= MachineMemOperand::MOLoad;
+
+ auto MMO = MF->getMachineMemOperand(PtrInfo, Flags, 0, 0);
+ MI.addMemOperand(*MF, MMO);
+ return BB;
+ }
+
switch (MI.getOpcode()) {
case AMDGPU::SI_INIT_M0: {
- const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
BuildMI(*BB, MI.getIterator(), MI.getDebugLoc(),
TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0)
- .addOperand(MI.getOperand(0));
+ .addOperand(MI.getOperand(0));
MI.eraseFromParent();
- break;
- }
- case AMDGPU::BRANCH:
return BB;
+ }
case AMDGPU::GET_GROUPSTATICSIZE: {
- const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
-
- MachineFunction *MF = BB->getParent();
- SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
DebugLoc DL = MI.getDebugLoc();
BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_MOV_B32))
.addOperand(MI.getOperand(0))
- .addImm(MFI->LDSSize);
+ .addImm(MFI->getLDSSize());
MI.eraseFromParent();
return BB;
}
+ case AMDGPU::SI_INDIRECT_SRC_V1:
+ case AMDGPU::SI_INDIRECT_SRC_V2:
+ case AMDGPU::SI_INDIRECT_SRC_V4:
+ case AMDGPU::SI_INDIRECT_SRC_V8:
+ case AMDGPU::SI_INDIRECT_SRC_V16:
+ return emitIndirectSrc(MI, *BB, *getSubtarget());
+ case AMDGPU::SI_INDIRECT_DST_V1:
+ case AMDGPU::SI_INDIRECT_DST_V2:
+ case AMDGPU::SI_INDIRECT_DST_V4:
+ case AMDGPU::SI_INDIRECT_DST_V8:
+ case AMDGPU::SI_INDIRECT_DST_V16:
+ return emitIndirectDst(MI, *BB, *getSubtarget());
case AMDGPU::SI_KILL:
return splitKillBlock(MI, BB);
+ case AMDGPU::V_CNDMASK_B64_PSEUDO: {
+ MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
+
+ unsigned Dst = MI.getOperand(0).getReg();
+ unsigned Src0 = MI.getOperand(1).getReg();
+ unsigned Src1 = MI.getOperand(2).getReg();
+ const DebugLoc &DL = MI.getDebugLoc();
+ unsigned SrcCond = MI.getOperand(3).getReg();
+
+ unsigned DstLo = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ unsigned DstHi = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+
+ BuildMI(*BB, MI, DL, TII->get(AMDGPU::V_CNDMASK_B32_e64), DstLo)
+ .addReg(Src0, 0, AMDGPU::sub0)
+ .addReg(Src1, 0, AMDGPU::sub0)
+ .addReg(SrcCond);
+ BuildMI(*BB, MI, DL, TII->get(AMDGPU::V_CNDMASK_B32_e64), DstHi)
+ .addReg(Src0, 0, AMDGPU::sub1)
+ .addReg(Src1, 0, AMDGPU::sub1)
+ .addReg(SrcCond);
+
+ BuildMI(*BB, MI, DL, TII->get(AMDGPU::REG_SEQUENCE), Dst)
+ .addReg(DstLo)
+ .addImm(AMDGPU::sub0)
+ .addReg(DstHi)
+ .addImm(AMDGPU::sub1);
+ MI.eraseFromParent();
+ return BB;
+ }
+ case AMDGPU::SI_BR_UNDEF: {
+ const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineInstr *Br = BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_CBRANCH_SCC1))
+ .addOperand(MI.getOperand(0));
+ Br->getOperand(1).setIsUndef(true); // read undef SCC
+ MI.eraseFromParent();
+ return BB;
+ }
default:
return AMDGPUTargetLowering::EmitInstrWithCustomInserter(MI, BB);
}
- return BB;
}
bool SITargetLowering::enableAggressiveFMAFusion(EVT VT) const {
@@ -1167,8 +1832,10 @@ EVT SITargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &Ctx,
return EVT::getVectorVT(Ctx, MVT::i1, VT.getVectorNumElements());
}
-MVT SITargetLowering::getScalarShiftAmountTy(const DataLayout &, EVT) const {
- return MVT::i32;
+MVT SITargetLowering::getScalarShiftAmountTy(const DataLayout &, EVT VT) const {
+ // TODO: Should i16 be used always if legal? For now it would force VALU
+ // shifts.
+ return (VT == MVT::i16) ? MVT::i16 : MVT::i32;
}
// Answering this is somewhat tricky and depends on the specific device which
@@ -1201,6 +1868,8 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(EVT VT) const {
return Subtarget->hasFP32Denormals() && Subtarget->hasFastFMAF32();
case MVT::f64:
return true;
+ case MVT::f16:
+ return Subtarget->has16BitInsts() && Subtarget->hasFP16Denormals();
default:
break;
}
@@ -1215,7 +1884,6 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(EVT VT) const {
SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
default: return AMDGPUTargetLowering::LowerOperation(Op, DAG);
- case ISD::FrameIndex: return LowerFrameIndex(Op, DAG);
case ISD::BRCOND: return LowerBRCOND(Op, DAG);
case ISD::LOAD: {
SDValue Result = LowerLOAD(Op, DAG);
@@ -1242,6 +1910,8 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG);
case ISD::ADDRSPACECAST: return lowerADDRSPACECAST(Op, DAG);
case ISD::TRAP: return lowerTRAP(Op, DAG);
+ case ISD::FP_ROUND:
+ return lowerFP_ROUND(Op, DAG);
}
return SDValue();
}
@@ -1262,58 +1932,31 @@ static SDNode *findUser(SDValue Value, unsigned Opcode) {
return nullptr;
}
-SDValue SITargetLowering::LowerFrameIndex(SDValue Op, SelectionDAG &DAG) const {
-
- SDLoc SL(Op);
- FrameIndexSDNode *FINode = cast<FrameIndexSDNode>(Op);
- unsigned FrameIndex = FINode->getIndex();
-
- // A FrameIndex node represents a 32-bit offset into scratch memory. If the
- // high bit of a frame index offset were to be set, this would mean that it
- // represented an offset of ~2GB * 64 = ~128GB from the start of the scratch
- // buffer, with 64 being the number of threads per wave.
- //
- // The maximum private allocation for the entire GPU is 4G, and we are
- // concerned with the largest the index could ever be for an individual
- // workitem. This will occur with the minmum dispatch size. If a program
- // requires more, the dispatch size will be reduced.
- //
- // With this limit, we can mark the high bit of the FrameIndex node as known
- // zero, which is important, because it means in most situations we can prove
- // that values derived from FrameIndex nodes are non-negative. This enables us
- // to take advantage of more addressing modes when accessing scratch buffers,
- // since for scratch reads/writes, the register offset must always be
- // positive.
-
- uint64_t MaxGPUAlloc = UINT64_C(4) * 1024 * 1024 * 1024;
-
- // XXX - It is unclear if partial dispatch works. Assume it works at half wave
- // granularity. It is probably a full wave.
- uint64_t MinGranularity = 32;
-
- unsigned KnownBits = Log2_64(MaxGPUAlloc / MinGranularity);
- EVT ExtVT = EVT::getIntegerVT(*DAG.getContext(), KnownBits);
-
- SDValue TFI = DAG.getTargetFrameIndex(FrameIndex, MVT::i32);
- return DAG.getNode(ISD::AssertZext, SL, MVT::i32, TFI,
- DAG.getValueType(ExtVT));
-}
-
bool SITargetLowering::isCFIntrinsic(const SDNode *Intr) const {
- if (Intr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
- return false;
+ if (Intr->getOpcode() == ISD::INTRINSIC_W_CHAIN) {
+ switch (cast<ConstantSDNode>(Intr->getOperand(1))->getZExtValue()) {
+ case AMDGPUIntrinsic::amdgcn_if:
+ case AMDGPUIntrinsic::amdgcn_else:
+ case AMDGPUIntrinsic::amdgcn_end_cf:
+ case AMDGPUIntrinsic::amdgcn_loop:
+ return true;
+ default:
+ return false;
+ }
+ }
- switch (cast<ConstantSDNode>(Intr->getOperand(1))->getZExtValue()) {
- default: return false;
- case AMDGPUIntrinsic::amdgcn_if:
- case AMDGPUIntrinsic::amdgcn_else:
- case AMDGPUIntrinsic::amdgcn_break:
- case AMDGPUIntrinsic::amdgcn_if_break:
- case AMDGPUIntrinsic::amdgcn_else_break:
- case AMDGPUIntrinsic::amdgcn_loop:
- case AMDGPUIntrinsic::amdgcn_end_cf:
- return true;
+ if (Intr->getOpcode() == ISD::INTRINSIC_WO_CHAIN) {
+ switch (cast<ConstantSDNode>(Intr->getOperand(0))->getZExtValue()) {
+ case AMDGPUIntrinsic::amdgcn_break:
+ case AMDGPUIntrinsic::amdgcn_if_break:
+ case AMDGPUIntrinsic::amdgcn_else_break:
+ return true;
+ default:
+ return false;
+ }
}
+
+ return false;
}
void SITargetLowering::createDebuggerPrologueStackObjects(
@@ -1334,14 +1977,31 @@ void SITargetLowering::createDebuggerPrologueStackObjects(
// For each dimension:
for (unsigned i = 0; i < 3; ++i) {
// Create fixed stack object for work group ID.
- ObjectIdx = MF.getFrameInfo()->CreateFixedObject(4, i * 4, true);
+ ObjectIdx = MF.getFrameInfo().CreateFixedObject(4, i * 4, true);
Info->setDebuggerWorkGroupIDStackObjectIndex(i, ObjectIdx);
// Create fixed stack object for work item ID.
- ObjectIdx = MF.getFrameInfo()->CreateFixedObject(4, i * 4 + 16, true);
+ ObjectIdx = MF.getFrameInfo().CreateFixedObject(4, i * 4 + 16, true);
Info->setDebuggerWorkItemIDStackObjectIndex(i, ObjectIdx);
}
}
+bool SITargetLowering::shouldEmitFixup(const GlobalValue *GV) const {
+ const Triple &TT = getTargetMachine().getTargetTriple();
+ return GV->getType()->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS &&
+ AMDGPU::shouldEmitConstantsToTextSection(TT);
+}
+
+bool SITargetLowering::shouldEmitGOTReloc(const GlobalValue *GV) const {
+ return (GV->getType()->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS ||
+ GV->getType()->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS) &&
+ !shouldEmitFixup(GV) &&
+ !getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV);
+}
+
+bool SITargetLowering::shouldEmitPCReloc(const GlobalValue *GV) const {
+ return !shouldEmitFixup(GV) && !shouldEmitGOTReloc(GV);
+}
+
/// This transforms the control flow intrinsics to get the branch destination as
/// last parameter, also switches branch target with BR if the need arise
SDValue SITargetLowering::LowerBRCOND(SDValue BRCOND,
@@ -1365,30 +2025,50 @@ SDValue SITargetLowering::LowerBRCOND(SDValue BRCOND,
Target = BR->getOperand(1);
}
+ // FIXME: This changes the types of the intrinsics instead of introducing new
+ // nodes with the correct types.
+ // e.g. llvm.amdgcn.loop
+
+ // eg: i1,ch = llvm.amdgcn.loop t0, TargetConstant:i32<6271>, t3
+ // => t9: ch = llvm.amdgcn.loop t0, TargetConstant:i32<6271>, t3, BasicBlock:ch<bb1 0x7fee5286d088>
+
if (!isCFIntrinsic(Intr)) {
// This is a uniform branch so we don't need to legalize.
return BRCOND;
}
+ bool HaveChain = Intr->getOpcode() == ISD::INTRINSIC_VOID ||
+ Intr->getOpcode() == ISD::INTRINSIC_W_CHAIN;
+
assert(!SetCC ||
(SetCC->getConstantOperandVal(1) == 1 &&
cast<CondCodeSDNode>(SetCC->getOperand(2).getNode())->get() ==
ISD::SETNE));
- // Build the result and
- ArrayRef<EVT> Res(Intr->value_begin() + 1, Intr->value_end());
-
// operands of the new intrinsic call
SmallVector<SDValue, 4> Ops;
- Ops.push_back(BRCOND.getOperand(0));
- Ops.append(Intr->op_begin() + 1, Intr->op_end());
+ if (HaveChain)
+ Ops.push_back(BRCOND.getOperand(0));
+
+ Ops.append(Intr->op_begin() + (HaveChain ? 1 : 0), Intr->op_end());
Ops.push_back(Target);
+ ArrayRef<EVT> Res(Intr->value_begin() + 1, Intr->value_end());
+
// build the new intrinsic call
SDNode *Result = DAG.getNode(
Res.size() > 1 ? ISD::INTRINSIC_W_CHAIN : ISD::INTRINSIC_VOID, DL,
DAG.getVTList(Res), Ops).getNode();
+ if (!HaveChain) {
+ SDValue Ops[] = {
+ SDValue(Result, 0),
+ BRCOND.getOperand(0)
+ };
+
+ Result = DAG.getMergeValues(Ops, DL).getNode();
+ }
+
if (BR) {
// Give the branch instruction our target
SDValue Ops[] = {
@@ -1425,6 +2105,31 @@ SDValue SITargetLowering::LowerBRCOND(SDValue BRCOND,
return Chain;
}
+SDValue SITargetLowering::getFPExtOrFPTrunc(SelectionDAG &DAG,
+ SDValue Op,
+ const SDLoc &DL,
+ EVT VT) const {
+ return Op.getValueType().bitsLE(VT) ?
+ DAG.getNode(ISD::FP_EXTEND, DL, VT, Op) :
+ DAG.getNode(ISD::FTRUNC, DL, VT, Op);
+}
+
+SDValue SITargetLowering::lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const {
+ assert(Op.getValueType() == MVT::f16 &&
+ "Do not know how to custom lower FP_ROUND for non-f16 type");
+
+ SDValue Src = Op.getOperand(0);
+ EVT SrcVT = Src.getValueType();
+ if (SrcVT != MVT::f64)
+ return Op;
+
+ SDLoc DL(Op);
+
+ SDValue FpToFp16 = DAG.getNode(ISD::FP_TO_FP16, DL, MVT::i32, Src);
+ SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FpToFp16);
+ return DAG.getNode(ISD::BITCAST, DL, MVT::f16, Trunc);;
+}
+
SDValue SITargetLowering::getSegmentAperture(unsigned AS,
SelectionDAG &DAG) const {
SDLoc SL;
@@ -1452,7 +2157,8 @@ SDValue SITargetLowering::getSegmentAperture(unsigned AS,
MachinePointerInfo PtrInfo(V, StructOffset);
return DAG.getLoad(MVT::i32, SL, QueuePtr.getValue(1), Ptr, PtrInfo,
MinAlign(64, StructOffset),
- MachineMemOperand::MOInvariant);
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
}
SDValue SITargetLowering::lowerADDRSPACECAST(SDValue Op,
@@ -1505,17 +2211,12 @@ SDValue SITargetLowering::lowerADDRSPACECAST(SDValue Op,
return DAG.getUNDEF(ASC->getValueType(0));
}
-static bool shouldEmitGOTReloc(const GlobalValue *GV,
- const TargetMachine &TM) {
- return GV->getType()->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS &&
- !TM.shouldAssumeDSOLocal(*GV->getParent(), GV);
-}
-
bool
SITargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
// We can fold offsets for anything that doesn't require a GOT relocation.
- return GA->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS &&
- !shouldEmitGOTReloc(GA->getGlobal(), getTargetMachine());
+ return (GA->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS ||
+ GA->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS) &&
+ !shouldEmitGOTReloc(GA->getGlobal());
}
static SDValue buildPCRelGlobalAddress(SelectionDAG &DAG, const GlobalValue *GV,
@@ -1523,14 +2224,27 @@ static SDValue buildPCRelGlobalAddress(SelectionDAG &DAG, const GlobalValue *GV,
unsigned GAFlags = SIInstrInfo::MO_NONE) {
// In order to support pc-relative addressing, the PC_ADD_REL_OFFSET SDNode is
// lowered to the following code sequence:
- // s_getpc_b64 s[0:1]
- // s_add_u32 s0, s0, $symbol
- // s_addc_u32 s1, s1, 0
//
- // s_getpc_b64 returns the address of the s_add_u32 instruction and then
- // a fixup or relocation is emitted to replace $symbol with a literal
- // constant, which is a pc-relative offset from the encoding of the $symbol
- // operand to the global variable.
+ // For constant address space:
+ // s_getpc_b64 s[0:1]
+ // s_add_u32 s0, s0, $symbol
+ // s_addc_u32 s1, s1, 0
+ //
+ // s_getpc_b64 returns the address of the s_add_u32 instruction and then
+ // a fixup or relocation is emitted to replace $symbol with a literal
+ // constant, which is a pc-relative offset from the encoding of the $symbol
+ // operand to the global variable.
+ //
+ // For global address space:
+ // s_getpc_b64 s[0:1]
+ // s_add_u32 s0, s0, $symbol@{gotpc}rel32@lo
+ // s_addc_u32 s1, s1, $symbol@{gotpc}rel32@hi
+ //
+ // s_getpc_b64 returns the address of the s_add_u32 instruction and then
+ // fixups or relocations are emitted to replace $symbol@*@lo and
+ // $symbol@*@hi with lower 32 bits and higher 32 bits of a literal constant,
+ // which is a 64-bit pc-relative offset from the encoding of the $symbol
+ // operand to the global variable.
//
// What we want here is an offset from the value returned by s_getpc
// (which is the address of the s_add_u32 instruction) to the global
@@ -1538,9 +2252,12 @@ static SDValue buildPCRelGlobalAddress(SelectionDAG &DAG, const GlobalValue *GV,
// of the s_add_u32 instruction, we end up with an offset that is 4 bytes too
// small. This requires us to add 4 to the global variable offset in order to
// compute the correct address.
- SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, Offset + 4,
- GAFlags);
- return DAG.getNode(AMDGPUISD::PC_ADD_REL_OFFSET, DL, PtrVT, GA);
+ SDValue PtrLo = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, Offset + 4,
+ GAFlags);
+ SDValue PtrHi = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, Offset + 4,
+ GAFlags == SIInstrInfo::MO_NONE ?
+ GAFlags : GAFlags + 1);
+ return DAG.getNode(AMDGPUISD::PC_ADD_REL_OFFSET, DL, PtrVT, PtrLo, PtrHi);
}
SDValue SITargetLowering::LowerGlobalAddress(AMDGPUMachineFunction *MFI,
@@ -1556,11 +2273,14 @@ SDValue SITargetLowering::LowerGlobalAddress(AMDGPUMachineFunction *MFI,
const GlobalValue *GV = GSD->getGlobal();
EVT PtrVT = Op.getValueType();
- if (!shouldEmitGOTReloc(GV, getTargetMachine()))
+ if (shouldEmitFixup(GV))
return buildPCRelGlobalAddress(DAG, GV, DL, GSD->getOffset(), PtrVT);
+ else if (shouldEmitPCReloc(GV))
+ return buildPCRelGlobalAddress(DAG, GV, DL, GSD->getOffset(), PtrVT,
+ SIInstrInfo::MO_REL32);
SDValue GOTAddr = buildPCRelGlobalAddress(DAG, GV, DL, 0, PtrVT,
- SIInstrInfo::MO_GOTPCREL);
+ SIInstrInfo::MO_GOTPCREL32);
Type *Ty = PtrVT.getTypeForEVT(*DAG.getContext());
PointerType *PtrTy = PointerType::get(Ty, AMDGPUAS::CONSTANT_ADDRESS);
@@ -1570,7 +2290,8 @@ SDValue SITargetLowering::LowerGlobalAddress(AMDGPUMachineFunction *MFI,
MachinePointerInfo PtrInfo(UndefValue::get(PtrTy));
return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), GOTAddr, PtrInfo, Align,
- MachineMemOperand::MOInvariant);
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
}
SDValue SITargetLowering::lowerTRAP(SDValue Op,
@@ -1647,9 +2368,13 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
// TODO: Should this propagate fast-math-flags?
switch (IntrinsicID) {
+ case Intrinsic::amdgcn_implicit_buffer_ptr: {
+ unsigned Reg = TRI->getPreloadedValue(MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER);
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_64RegClass, Reg, VT);
+ }
case Intrinsic::amdgcn_dispatch_ptr:
case Intrinsic::amdgcn_queue_ptr: {
- if (!Subtarget->isAmdHsaOS()) {
+ if (!Subtarget->isAmdCodeObjectV2(MF)) {
DiagnosticInfoUnsupported BadIntrin(
*MF.getFunction(), "unsupported hsa intrinsic without hsa target",
DL.getDebugLoc());
@@ -1671,6 +2396,10 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
= TRI->getPreloadedValue(MF, SIRegisterInfo::KERNARG_SEGMENT_PTR);
return CreateLiveInRegister(DAG, &AMDGPU::SReg_64RegClass, Reg, VT);
}
+ case Intrinsic::amdgcn_dispatch_id: {
+ unsigned Reg = TRI->getPreloadedValue(MF, SIRegisterInfo::DISPATCH_ID);
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_64RegClass, Reg, VT);
+ }
case Intrinsic::amdgcn_rcp:
return DAG.getNode(AMDGPUISD::RCP, DL, VT, Op.getOperand(1));
case Intrinsic::amdgcn_rsq:
@@ -1682,6 +2411,11 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return DAG.getNode(AMDGPUISD::RSQ_LEGACY, DL, VT, Op.getOperand(1));
}
+ case Intrinsic::amdgcn_rcp_legacy: {
+ if (Subtarget->getGeneration() >= SISubtarget::VOLCANIC_ISLANDS)
+ return emitRemovedIntrinsicError(DAG, DL, VT);
+ return DAG.getNode(AMDGPUISD::RCP_LEGACY, DL, VT, Op.getOperand(1));
+ }
case Intrinsic::amdgcn_rsq_clamp: {
if (Subtarget->getGeneration() < SISubtarget::VOLCANIC_ISLANDS)
return DAG.getNode(AMDGPUISD::RSQ_CLAMP, DL, VT, Op.getOperand(1));
@@ -1750,22 +2484,17 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return lowerImplicitZextParam(DAG, Op, MVT::i16,
SI::KernelInputOffsets::LOCAL_SIZE_Z);
- case Intrinsic::amdgcn_read_workdim:
- case AMDGPUIntrinsic::AMDGPU_read_workdim: // Legacy name.
- // Really only 2 bits.
- return lowerImplicitZextParam(DAG, Op, MVT::i8,
- getImplicitParameterOffset(MFI, GRID_DIM));
case Intrinsic::amdgcn_workgroup_id_x:
case Intrinsic::r600_read_tgid_x:
- return CreateLiveInRegister(DAG, &AMDGPU::SReg_32RegClass,
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_32_XM0RegClass,
TRI->getPreloadedValue(MF, SIRegisterInfo::WORKGROUP_ID_X), VT);
case Intrinsic::amdgcn_workgroup_id_y:
case Intrinsic::r600_read_tgid_y:
- return CreateLiveInRegister(DAG, &AMDGPU::SReg_32RegClass,
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_32_XM0RegClass,
TRI->getPreloadedValue(MF, SIRegisterInfo::WORKGROUP_ID_Y), VT);
case Intrinsic::amdgcn_workgroup_id_z:
case Intrinsic::r600_read_tgid_z:
- return CreateLiveInRegister(DAG, &AMDGPU::SReg_32RegClass,
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_32_XM0RegClass,
TRI->getPreloadedValue(MF, SIRegisterInfo::WORKGROUP_ID_Z), VT);
case Intrinsic::amdgcn_workitem_id_x:
case Intrinsic::r600_read_tidig_x:
@@ -1786,9 +2515,10 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
};
MachineMemOperand *MMO = MF.getMachineMemOperand(
- MachinePointerInfo(),
- MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant,
- VT.getStoreSize(), 4);
+ MachinePointerInfo(),
+ MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant,
+ VT.getStoreSize(), 4);
return DAG.getMemIntrinsicNode(AMDGPUISD::LOAD_CONSTANT, DL,
Op->getVTList(), Ops, VT, MMO);
}
@@ -1818,6 +2548,8 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
DAG.getConstant(0, DL, MVT::i32));
SDValue J = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, IJ,
DAG.getConstant(1, DL, MVT::i32));
+ I = DAG.getNode(ISD::BITCAST, DL, MVT::f32, I);
+ J = DAG.getNode(ISD::BITCAST, DL, MVT::f32, J);
SDValue M0 = copyToM0(DAG, DAG.getEntryNode(), DL, Op.getOperand(3));
SDValue Glue = M0.getValue(1);
SDValue P1 = DAG.getNode(AMDGPUISD::INTERP_P1, DL,
@@ -1827,6 +2559,12 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return DAG.getNode(AMDGPUISD::INTERP_P2, DL, MVT::f32, P1, J,
Op.getOperand(1), Op.getOperand(2), Glue);
}
+ case Intrinsic::amdgcn_interp_mov: {
+ SDValue M0 = copyToM0(DAG, DAG.getEntryNode(), DL, Op.getOperand(4));
+ SDValue Glue = M0.getValue(1);
+ return DAG.getNode(AMDGPUISD::INTERP_MOV, DL, MVT::f32, Op.getOperand(1),
+ Op.getOperand(2), Op.getOperand(3), Glue);
+ }
case Intrinsic::amdgcn_interp_p1: {
SDValue M0 = copyToM0(DAG, DAG.getEntryNode(), DL, Op.getOperand(4));
SDValue Glue = M0.getValue(1);
@@ -1899,6 +2637,38 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
return DAG.getNode(AMDGPUISD::DIV_SCALE, DL, Op->getVTList(), Src0,
Denominator, Numerator);
}
+ case Intrinsic::amdgcn_icmp: {
+ const auto *CD = dyn_cast<ConstantSDNode>(Op.getOperand(3));
+ int CondCode = CD->getSExtValue();
+
+ if (CondCode < ICmpInst::Predicate::FIRST_ICMP_PREDICATE ||
+ CondCode >= ICmpInst::Predicate::BAD_ICMP_PREDICATE)
+ return DAG.getUNDEF(VT);
+
+ ICmpInst::Predicate IcInput = static_cast<ICmpInst::Predicate>(CondCode);
+ ISD::CondCode CCOpcode = getICmpCondCode(IcInput);
+ return DAG.getNode(AMDGPUISD::SETCC, DL, VT, Op.getOperand(1),
+ Op.getOperand(2), DAG.getCondCode(CCOpcode));
+ }
+ case Intrinsic::amdgcn_fcmp: {
+ const auto *CD = dyn_cast<ConstantSDNode>(Op.getOperand(3));
+ int CondCode = CD->getSExtValue();
+
+ if (CondCode <= FCmpInst::Predicate::FCMP_FALSE ||
+ CondCode >= FCmpInst::Predicate::FCMP_TRUE)
+ return DAG.getUNDEF(VT);
+
+ FCmpInst::Predicate IcInput = static_cast<FCmpInst::Predicate>(CondCode);
+ ISD::CondCode CCOpcode = getFCmpCondCode(IcInput);
+ return DAG.getNode(AMDGPUISD::SETCC, DL, VT, Op.getOperand(1),
+ Op.getOperand(2), DAG.getCondCode(CCOpcode));
+ }
+ case Intrinsic::amdgcn_fmul_legacy:
+ return DAG.getNode(AMDGPUISD::FMUL_LEGACY, DL, VT,
+ Op.getOperand(1), Op.getOperand(2));
+ case Intrinsic::amdgcn_sffbh:
+ case AMDGPUIntrinsic::AMDGPU_flbit_i32: // Legacy name.
+ return DAG.getNode(AMDGPUISD::FFBH_I32, DL, VT, Op.getOperand(1));
default:
return AMDGPUTargetLowering::LowerOperation(Op, DAG);
}
@@ -1907,6 +2677,7 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
unsigned IntrID = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
+ SDLoc DL(Op);
switch (IntrID) {
case Intrinsic::amdgcn_atomic_inc:
case Intrinsic::amdgcn_atomic_dec: {
@@ -1922,6 +2693,31 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,
return DAG.getMemIntrinsicNode(Opc, SDLoc(Op), M->getVTList(), Ops,
M->getMemoryVT(), M->getMemOperand());
}
+ case Intrinsic::amdgcn_buffer_load:
+ case Intrinsic::amdgcn_buffer_load_format: {
+ SDValue Ops[] = {
+ Op.getOperand(0), // Chain
+ Op.getOperand(2), // rsrc
+ Op.getOperand(3), // vindex
+ Op.getOperand(4), // offset
+ Op.getOperand(5), // glc
+ Op.getOperand(6) // slc
+ };
+ MachineFunction &MF = DAG.getMachineFunction();
+ SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+
+ unsigned Opc = (IntrID == Intrinsic::amdgcn_buffer_load) ?
+ AMDGPUISD::BUFFER_LOAD : AMDGPUISD::BUFFER_LOAD_FORMAT;
+ EVT VT = Op.getValueType();
+ EVT IntVT = VT.changeTypeToInteger();
+
+ MachineMemOperand *MMO = MF.getMachineMemOperand(
+ MachinePointerInfo(MFI->getBufferPSV()),
+ MachineMemOperand::MOLoad,
+ VT.getStoreSize(), VT.getStoreSize());
+
+ return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops, IntVT, MMO);
+ }
default:
return SDValue();
}
@@ -1935,12 +2731,19 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
unsigned IntrinsicID = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
switch (IntrinsicID) {
- case AMDGPUIntrinsic::SI_sendmsg: {
+ case AMDGPUIntrinsic::SI_sendmsg:
+ case Intrinsic::amdgcn_s_sendmsg: {
Chain = copyToM0(DAG, Chain, DL, Op.getOperand(3));
SDValue Glue = Chain.getValue(1);
return DAG.getNode(AMDGPUISD::SENDMSG, DL, MVT::Other, Chain,
Op.getOperand(2), Glue);
}
+ case Intrinsic::amdgcn_s_sendmsghalt: {
+ Chain = copyToM0(DAG, Chain, DL, Op.getOperand(3));
+ SDValue Glue = Chain.getValue(1);
+ return DAG.getNode(AMDGPUISD::SENDMSGHALT, DL, MVT::Other, Chain,
+ Op.getOperand(2), Glue);
+ }
case AMDGPUIntrinsic::SI_tbuffer_store: {
SDValue Ops[] = {
Chain,
@@ -1969,12 +2772,40 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,
Op->getVTList(), Ops, VT, MMO);
}
case AMDGPUIntrinsic::AMDGPU_kill: {
- if (const ConstantFPSDNode *K = dyn_cast<ConstantFPSDNode>(Op.getOperand(2))) {
+ SDValue Src = Op.getOperand(2);
+ if (const ConstantFPSDNode *K = dyn_cast<ConstantFPSDNode>(Src)) {
if (!K->isNegative())
return Chain;
+
+ SDValue NegOne = DAG.getTargetConstant(FloatToBits(-1.0f), DL, MVT::i32);
+ return DAG.getNode(AMDGPUISD::KILL, DL, MVT::Other, Chain, NegOne);
}
- return Op;
+ SDValue Cast = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Src);
+ return DAG.getNode(AMDGPUISD::KILL, DL, MVT::Other, Chain, Cast);
+ }
+ case AMDGPUIntrinsic::SI_export: {
+ const ConstantSDNode *En = cast<ConstantSDNode>(Op.getOperand(2));
+ const ConstantSDNode *VM = cast<ConstantSDNode>(Op.getOperand(3));
+ const ConstantSDNode *Done = cast<ConstantSDNode>(Op.getOperand(4));
+ const ConstantSDNode *Tgt = cast<ConstantSDNode>(Op.getOperand(5));
+ const ConstantSDNode *Compr = cast<ConstantSDNode>(Op.getOperand(6));
+
+ const SDValue Ops[] = {
+ Chain,
+ DAG.getTargetConstant(En->getZExtValue(), DL, MVT::i8),
+ DAG.getTargetConstant(VM->getZExtValue(), DL, MVT::i1),
+ DAG.getTargetConstant(Tgt->getZExtValue(), DL, MVT::i8),
+ DAG.getTargetConstant(Compr->getZExtValue(), DL, MVT::i1),
+ Op.getOperand(7), // src0
+ Op.getOperand(8), // src1
+ Op.getOperand(9), // src2
+ Op.getOperand(10) // src3
+ };
+
+ unsigned Opc = Done->isNullValue() ?
+ AMDGPUISD::EXPORT : AMDGPUISD::EXPORT_DONE;
+ return DAG.getNode(Opc, DL, Op->getVTList(), Ops);
}
default:
return SDValue();
@@ -1988,7 +2819,6 @@ SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
EVT MemVT = Load->getMemoryVT();
if (ExtType == ISD::NON_EXTLOAD && MemVT.getSizeInBits() < 32) {
- assert(MemVT == MVT::i1 && "Only i1 non-extloads expected");
// FIXME: Copied from PPC
// First, load into 32 bits, then truncate to 1 bit.
@@ -1996,8 +2826,10 @@ SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
SDValue BasePtr = Load->getBasePtr();
MachineMemOperand *MMO = Load->getMemOperand();
+ EVT RealMemVT = (MemVT == MVT::i1) ? MVT::i8 : MVT::i16;
+
SDValue NewLD = DAG.getExtLoad(ISD::EXTLOAD, DL, MVT::i32, Chain,
- BasePtr, MVT::i8, MMO);
+ BasePtr, RealMemVT, MMO);
SDValue Ops[] = {
DAG.getNode(ISD::TRUNCATE, DL, MemVT, NewLD),
@@ -2021,17 +2853,34 @@ SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
return DAG.getMergeValues(Ops, DL);
}
+ MachineFunction &MF = DAG.getMachineFunction();
+ SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+ // If there is a possibilty that flat instruction access scratch memory
+ // then we need to use the same legalization rules we use for private.
+ if (AS == AMDGPUAS::FLAT_ADDRESS)
+ AS = MFI->hasFlatScratchInit() ?
+ AMDGPUAS::PRIVATE_ADDRESS : AMDGPUAS::GLOBAL_ADDRESS;
+
unsigned NumElements = MemVT.getVectorNumElements();
switch (AS) {
case AMDGPUAS::CONSTANT_ADDRESS:
if (isMemOpUniform(Load))
return SDValue();
// Non-uniform loads will be selected to MUBUF instructions, so they
- // have the same legalization requires ments as global and private
+ // have the same legalization requirements as global and private
// loads.
//
- // Fall-through
- case AMDGPUAS::GLOBAL_ADDRESS:
+ LLVM_FALLTHROUGH;
+ case AMDGPUAS::GLOBAL_ADDRESS: {
+ if (Subtarget->getScalarizeGlobalBehavior() && isMemOpUniform(Load) &&
+ isMemOpHasNoClobberedMemOperand(Load))
+ return SDValue();
+ // Non-uniform loads will be selected to MUBUF instructions, so they
+ // have the same legalization requirements as global and private
+ // loads.
+ //
+ }
+ LLVM_FALLTHROUGH;
case AMDGPUAS::FLAT_ADDRESS:
if (NumElements > 4)
return SplitVectorLoad(Op, DAG);
@@ -2110,22 +2959,33 @@ SDValue SITargetLowering::lowerFastUnsafeFDIV(SDValue Op,
bool Unsafe = DAG.getTarget().Options.UnsafeFPMath;
if (const ConstantFPSDNode *CLHS = dyn_cast<ConstantFPSDNode>(LHS)) {
- if ((Unsafe || (VT == MVT::f32 && !Subtarget->hasFP32Denormals())) &&
- CLHS->isExactlyValue(1.0)) {
- // v_rcp_f32 and v_rsq_f32 do not support denormals, and according to
- // the CI documentation has a worst case error of 1 ulp.
- // OpenCL requires <= 2.5 ulp for 1.0 / x, so it should always be OK to
- // use it as long as we aren't trying to use denormals.
-
- // 1.0 / sqrt(x) -> rsq(x)
- //
- // XXX - Is UnsafeFPMath sufficient to do this for f64? The maximum ULP
- // error seems really high at 2^29 ULP.
- if (RHS.getOpcode() == ISD::FSQRT)
- return DAG.getNode(AMDGPUISD::RSQ, SL, VT, RHS.getOperand(0));
-
- // 1.0 / x -> rcp(x)
- return DAG.getNode(AMDGPUISD::RCP, SL, VT, RHS);
+ if (Unsafe || (VT == MVT::f32 && !Subtarget->hasFP32Denormals()) ||
+ VT == MVT::f16) {
+ if (CLHS->isExactlyValue(1.0)) {
+ // v_rcp_f32 and v_rsq_f32 do not support denormals, and according to
+ // the CI documentation has a worst case error of 1 ulp.
+ // OpenCL requires <= 2.5 ulp for 1.0 / x, so it should always be OK to
+ // use it as long as we aren't trying to use denormals.
+ //
+ // v_rcp_f16 and v_rsq_f16 DO support denormals.
+
+ // 1.0 / sqrt(x) -> rsq(x)
+
+ // XXX - Is UnsafeFPMath sufficient to do this for f64? The maximum ULP
+ // error seems really high at 2^29 ULP.
+ if (RHS.getOpcode() == ISD::FSQRT)
+ return DAG.getNode(AMDGPUISD::RSQ, SL, VT, RHS.getOperand(0));
+
+ // 1.0 / x -> rcp(x)
+ return DAG.getNode(AMDGPUISD::RCP, SL, VT, RHS);
+ }
+
+ // Same as for 1.0, but expand the sign out of the constant.
+ if (CLHS->isExactlyValue(-1.0)) {
+ // -1.0 / x -> rcp (fneg x)
+ SDValue FNegRHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);
+ return DAG.getNode(AMDGPUISD::RCP, SL, VT, FNegRHS);
+ }
}
}
@@ -2143,6 +3003,67 @@ SDValue SITargetLowering::lowerFastUnsafeFDIV(SDValue Op,
return SDValue();
}
+static SDValue getFPBinOp(SelectionDAG &DAG, unsigned Opcode, const SDLoc &SL,
+ EVT VT, SDValue A, SDValue B, SDValue GlueChain) {
+ if (GlueChain->getNumValues() <= 1) {
+ return DAG.getNode(Opcode, SL, VT, A, B);
+ }
+
+ assert(GlueChain->getNumValues() == 3);
+
+ SDVTList VTList = DAG.getVTList(VT, MVT::Other, MVT::Glue);
+ switch (Opcode) {
+ default: llvm_unreachable("no chain equivalent for opcode");
+ case ISD::FMUL:
+ Opcode = AMDGPUISD::FMUL_W_CHAIN;
+ break;
+ }
+
+ return DAG.getNode(Opcode, SL, VTList, GlueChain.getValue(1), A, B,
+ GlueChain.getValue(2));
+}
+
+static SDValue getFPTernOp(SelectionDAG &DAG, unsigned Opcode, const SDLoc &SL,
+ EVT VT, SDValue A, SDValue B, SDValue C,
+ SDValue GlueChain) {
+ if (GlueChain->getNumValues() <= 1) {
+ return DAG.getNode(Opcode, SL, VT, A, B, C);
+ }
+
+ assert(GlueChain->getNumValues() == 3);
+
+ SDVTList VTList = DAG.getVTList(VT, MVT::Other, MVT::Glue);
+ switch (Opcode) {
+ default: llvm_unreachable("no chain equivalent for opcode");
+ case ISD::FMA:
+ Opcode = AMDGPUISD::FMA_W_CHAIN;
+ break;
+ }
+
+ return DAG.getNode(Opcode, SL, VTList, GlueChain.getValue(1), A, B, C,
+ GlueChain.getValue(2));
+}
+
+SDValue SITargetLowering::LowerFDIV16(SDValue Op, SelectionDAG &DAG) const {
+ if (SDValue FastLowered = lowerFastUnsafeFDIV(Op, DAG))
+ return FastLowered;
+
+ SDLoc SL(Op);
+ SDValue Src0 = Op.getOperand(0);
+ SDValue Src1 = Op.getOperand(1);
+
+ SDValue CvtSrc0 = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Src0);
+ SDValue CvtSrc1 = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Src1);
+
+ SDValue RcpSrc1 = DAG.getNode(AMDGPUISD::RCP, SL, MVT::f32, CvtSrc1);
+ SDValue Quot = DAG.getNode(ISD::FMUL, SL, MVT::f32, CvtSrc0, RcpSrc1);
+
+ SDValue FPRoundFlag = DAG.getTargetConstant(0, SL, MVT::i32);
+ SDValue BestQuot = DAG.getNode(ISD::FP_ROUND, SL, MVT::f16, Quot, FPRoundFlag);
+
+ return DAG.getNode(AMDGPUISD::DIV_FIXUP, SL, MVT::f16, BestQuot, Src1, Src0);
+}
+
// Faster 2.5 ULP division that does not support denormals.
SDValue SITargetLowering::lowerFDIV_FAST(SDValue Op, SelectionDAG &DAG) const {
SDLoc SL(Op);
@@ -2189,25 +3110,73 @@ SDValue SITargetLowering::LowerFDIV32(SDValue Op, SelectionDAG &DAG) const {
SDVTList ScaleVT = DAG.getVTList(MVT::f32, MVT::i1);
- SDValue DenominatorScaled = DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT, RHS, RHS, LHS);
- SDValue NumeratorScaled = DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT, LHS, RHS, LHS);
+ SDValue DenominatorScaled = DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT,
+ RHS, RHS, LHS);
+ SDValue NumeratorScaled = DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT,
+ LHS, RHS, LHS);
// Denominator is scaled to not be denormal, so using rcp is ok.
- SDValue ApproxRcp = DAG.getNode(AMDGPUISD::RCP, SL, MVT::f32, DenominatorScaled);
+ SDValue ApproxRcp = DAG.getNode(AMDGPUISD::RCP, SL, MVT::f32,
+ DenominatorScaled);
+ SDValue NegDivScale0 = DAG.getNode(ISD::FNEG, SL, MVT::f32,
+ DenominatorScaled);
+
+ const unsigned Denorm32Reg = AMDGPU::Hwreg::ID_MODE |
+ (4 << AMDGPU::Hwreg::OFFSET_SHIFT_) |
+ (1 << AMDGPU::Hwreg::WIDTH_M1_SHIFT_);
+
+ const SDValue BitField = DAG.getTargetConstant(Denorm32Reg, SL, MVT::i16);
+
+ if (!Subtarget->hasFP32Denormals()) {
+ SDVTList BindParamVTs = DAG.getVTList(MVT::Other, MVT::Glue);
+ const SDValue EnableDenormValue = DAG.getConstant(FP_DENORM_FLUSH_NONE,
+ SL, MVT::i32);
+ SDValue EnableDenorm = DAG.getNode(AMDGPUISD::SETREG, SL, BindParamVTs,
+ DAG.getEntryNode(),
+ EnableDenormValue, BitField);
+ SDValue Ops[3] = {
+ NegDivScale0,
+ EnableDenorm.getValue(0),
+ EnableDenorm.getValue(1)
+ };
+
+ NegDivScale0 = DAG.getMergeValues(Ops, SL);
+ }
- SDValue NegDivScale0 = DAG.getNode(ISD::FNEG, SL, MVT::f32, DenominatorScaled);
+ SDValue Fma0 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, NegDivScale0,
+ ApproxRcp, One, NegDivScale0);
- SDValue Fma0 = DAG.getNode(ISD::FMA, SL, MVT::f32, NegDivScale0, ApproxRcp, One);
- SDValue Fma1 = DAG.getNode(ISD::FMA, SL, MVT::f32, Fma0, ApproxRcp, ApproxRcp);
+ SDValue Fma1 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, Fma0, ApproxRcp,
+ ApproxRcp, Fma0);
- SDValue Mul = DAG.getNode(ISD::FMUL, SL, MVT::f32, NumeratorScaled, Fma1);
+ SDValue Mul = getFPBinOp(DAG, ISD::FMUL, SL, MVT::f32, NumeratorScaled,
+ Fma1, Fma1);
- SDValue Fma2 = DAG.getNode(ISD::FMA, SL, MVT::f32, NegDivScale0, Mul, NumeratorScaled);
- SDValue Fma3 = DAG.getNode(ISD::FMA, SL, MVT::f32, Fma2, Fma1, Mul);
- SDValue Fma4 = DAG.getNode(ISD::FMA, SL, MVT::f32, NegDivScale0, Fma3, NumeratorScaled);
+ SDValue Fma2 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, NegDivScale0, Mul,
+ NumeratorScaled, Mul);
+
+ SDValue Fma3 = getFPTernOp(DAG, ISD::FMA,SL, MVT::f32, Fma2, Fma1, Mul, Fma2);
+
+ SDValue Fma4 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, NegDivScale0, Fma3,
+ NumeratorScaled, Fma3);
+
+ if (!Subtarget->hasFP32Denormals()) {
+ const SDValue DisableDenormValue =
+ DAG.getConstant(FP_DENORM_FLUSH_IN_FLUSH_OUT, SL, MVT::i32);
+ SDValue DisableDenorm = DAG.getNode(AMDGPUISD::SETREG, SL, MVT::Other,
+ Fma4.getValue(1),
+ DisableDenormValue,
+ BitField,
+ Fma4.getValue(2));
+
+ SDValue OutputChain = DAG.getNode(ISD::TokenFactor, SL, MVT::Other,
+ DisableDenorm, DAG.getRoot());
+ DAG.setRoot(OutputChain);
+ }
SDValue Scale = NumeratorScaled.getValue(1);
- SDValue Fmas = DAG.getNode(AMDGPUISD::DIV_FMAS, SL, MVT::f32, Fma4, Fma1, Fma3, Scale);
+ SDValue Fmas = DAG.getNode(AMDGPUISD::DIV_FMAS, SL, MVT::f32,
+ Fma4, Fma1, Fma3, Scale);
return DAG.getNode(AMDGPUISD::DIV_FIXUP, SL, MVT::f32, Fmas, RHS, LHS);
}
@@ -2288,6 +3257,9 @@ SDValue SITargetLowering::LowerFDIV(SDValue Op, SelectionDAG &DAG) const {
if (VT == MVT::f64)
return LowerFDIV64(Op, DAG);
+ if (VT == MVT::f16)
+ return LowerFDIV16(Op, DAG);
+
llvm_unreachable("Unexpected type for fdiv");
}
@@ -2311,6 +3283,14 @@ SDValue SITargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
return expandUnalignedStore(Store, DAG);
}
+ MachineFunction &MF = DAG.getMachineFunction();
+ SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+ // If there is a possibilty that flat instruction access scratch memory
+ // then we need to use the same legalization rules we use for private.
+ if (AS == AMDGPUAS::FLAT_ADDRESS)
+ AS = MFI->hasFlatScratchInit() ?
+ AMDGPUAS::PRIVATE_ADDRESS : AMDGPUAS::GLOBAL_ADDRESS;
+
unsigned NumElements = VT.getVectorNumElements();
switch (AS) {
case AMDGPUAS::GLOBAL_ADDRESS:
@@ -2504,23 +3484,83 @@ SDValue SITargetLowering::performSHLPtrCombine(SDNode *N,
return DAG.getNode(ISD::ADD, SL, VT, ShlX, COffset);
}
+SDValue SITargetLowering::performMemSDNodeCombine(MemSDNode *N,
+ DAGCombinerInfo &DCI) const {
+ SDValue Ptr = N->getBasePtr();
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc SL(N);
+
+ // TODO: We could also do this for multiplies.
+ unsigned AS = N->getAddressSpace();
+ if (Ptr.getOpcode() == ISD::SHL && AS != AMDGPUAS::PRIVATE_ADDRESS) {
+ SDValue NewPtr = performSHLPtrCombine(Ptr.getNode(), AS, DCI);
+ if (NewPtr) {
+ SmallVector<SDValue, 8> NewOps(N->op_begin(), N->op_end());
+
+ NewOps[N->getOpcode() == ISD::STORE ? 2 : 1] = NewPtr;
+ return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0);
+ }
+ }
+
+ return SDValue();
+}
+
+static bool bitOpWithConstantIsReducible(unsigned Opc, uint32_t Val) {
+ return (Opc == ISD::AND && (Val == 0 || Val == 0xffffffff)) ||
+ (Opc == ISD::OR && (Val == 0xffffffff || Val == 0)) ||
+ (Opc == ISD::XOR && Val == 0);
+}
+
+// Break up 64-bit bit operation of a constant into two 32-bit and/or/xor. This
+// will typically happen anyway for a VALU 64-bit and. This exposes other 32-bit
+// integer combine opportunities since most 64-bit operations are decomposed
+// this way. TODO: We won't want this for SALU especially if it is an inline
+// immediate.
+SDValue SITargetLowering::splitBinaryBitConstantOp(
+ DAGCombinerInfo &DCI,
+ const SDLoc &SL,
+ unsigned Opc, SDValue LHS,
+ const ConstantSDNode *CRHS) const {
+ uint64_t Val = CRHS->getZExtValue();
+ uint32_t ValLo = Lo_32(Val);
+ uint32_t ValHi = Hi_32(Val);
+ const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
+
+ if ((bitOpWithConstantIsReducible(Opc, ValLo) ||
+ bitOpWithConstantIsReducible(Opc, ValHi)) ||
+ (CRHS->hasOneUse() && !TII->isInlineConstant(CRHS->getAPIntValue()))) {
+ // If we need to materialize a 64-bit immediate, it will be split up later
+ // anyway. Avoid creating the harder to understand 64-bit immediate
+ // materialization.
+ return splitBinaryBitConstantOpImpl(DCI, SL, Opc, LHS, ValLo, ValHi);
+ }
+
+ return SDValue();
+}
+
SDValue SITargetLowering::performAndCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
if (DCI.isBeforeLegalize())
return SDValue();
- if (SDValue Base = AMDGPUTargetLowering::performAndCombine(N, DCI))
- return Base;
-
SelectionDAG &DAG = DCI.DAG;
-
- // (and (fcmp ord x, x), (fcmp une (fabs x), inf)) ->
- // fp_class x, ~(s_nan | q_nan | n_infinity | p_infinity)
+ EVT VT = N->getValueType(0);
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
- if (LHS.getOpcode() == ISD::SETCC &&
- RHS.getOpcode() == ISD::SETCC) {
+
+ if (VT == MVT::i64) {
+ const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS);
+ if (CRHS) {
+ if (SDValue Split
+ = splitBinaryBitConstantOp(DCI, SDLoc(N), ISD::AND, LHS, CRHS))
+ return Split;
+ }
+ }
+
+ // (and (fcmp ord x, x), (fcmp une (fabs x), inf)) ->
+ // fp_class x, ~(s_nan | q_nan | n_infinity | p_infinity)
+ if (LHS.getOpcode() == ISD::SETCC && RHS.getOpcode() == ISD::SETCC) {
ISD::CondCode LCC = cast<CondCodeSDNode>(LHS.getOperand(2))->get();
ISD::CondCode RCC = cast<CondCodeSDNode>(RHS.getOperand(2))->get();
@@ -2568,54 +3608,85 @@ SDValue SITargetLowering::performOrCombine(SDNode *N,
SDValue RHS = N->getOperand(1);
EVT VT = N->getValueType(0);
- if (VT == MVT::i64) {
- // TODO: This could be a generic combine with a predicate for extracting the
- // high half of an integer being free.
-
- // (or i64:x, (zero_extend i32:y)) ->
- // i64 (bitcast (v2i32 build_vector (or i32:y, lo_32(x)), hi_32(x)))
- if (LHS.getOpcode() == ISD::ZERO_EXTEND &&
- RHS.getOpcode() != ISD::ZERO_EXTEND)
- std::swap(LHS, RHS);
-
- if (RHS.getOpcode() == ISD::ZERO_EXTEND) {
- SDValue ExtSrc = RHS.getOperand(0);
- EVT SrcVT = ExtSrc.getValueType();
- if (SrcVT == MVT::i32) {
- SDLoc SL(N);
- SDValue LowLHS, HiBits;
- std::tie(LowLHS, HiBits) = split64BitValue(LHS, DAG);
- SDValue LowOr = DAG.getNode(ISD::OR, SL, MVT::i32, LowLHS, ExtSrc);
-
- DCI.AddToWorklist(LowOr.getNode());
- DCI.AddToWorklist(HiBits.getNode());
-
- SDValue Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32,
- LowOr, HiBits);
- return DAG.getNode(ISD::BITCAST, SL, MVT::i64, Vec);
- }
+ if (VT == MVT::i1) {
+ // or (fp_class x, c1), (fp_class x, c2) -> fp_class x, (c1 | c2)
+ if (LHS.getOpcode() == AMDGPUISD::FP_CLASS &&
+ RHS.getOpcode() == AMDGPUISD::FP_CLASS) {
+ SDValue Src = LHS.getOperand(0);
+ if (Src != RHS.getOperand(0))
+ return SDValue();
+
+ const ConstantSDNode *CLHS = dyn_cast<ConstantSDNode>(LHS.getOperand(1));
+ const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS.getOperand(1));
+ if (!CLHS || !CRHS)
+ return SDValue();
+
+ // Only 10 bits are used.
+ static const uint32_t MaxMask = 0x3ff;
+
+ uint32_t NewMask = (CLHS->getZExtValue() | CRHS->getZExtValue()) & MaxMask;
+ SDLoc DL(N);
+ return DAG.getNode(AMDGPUISD::FP_CLASS, DL, MVT::i1,
+ Src, DAG.getConstant(NewMask, DL, MVT::i32));
}
+
+ return SDValue();
}
- // or (fp_class x, c1), (fp_class x, c2) -> fp_class x, (c1 | c2)
- if (LHS.getOpcode() == AMDGPUISD::FP_CLASS &&
- RHS.getOpcode() == AMDGPUISD::FP_CLASS) {
- SDValue Src = LHS.getOperand(0);
- if (Src != RHS.getOperand(0))
- return SDValue();
+ if (VT != MVT::i64)
+ return SDValue();
- const ConstantSDNode *CLHS = dyn_cast<ConstantSDNode>(LHS.getOperand(1));
- const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS.getOperand(1));
- if (!CLHS || !CRHS)
- return SDValue();
+ // TODO: This could be a generic combine with a predicate for extracting the
+ // high half of an integer being free.
+
+ // (or i64:x, (zero_extend i32:y)) ->
+ // i64 (bitcast (v2i32 build_vector (or i32:y, lo_32(x)), hi_32(x)))
+ if (LHS.getOpcode() == ISD::ZERO_EXTEND &&
+ RHS.getOpcode() != ISD::ZERO_EXTEND)
+ std::swap(LHS, RHS);
+
+ if (RHS.getOpcode() == ISD::ZERO_EXTEND) {
+ SDValue ExtSrc = RHS.getOperand(0);
+ EVT SrcVT = ExtSrc.getValueType();
+ if (SrcVT == MVT::i32) {
+ SDLoc SL(N);
+ SDValue LowLHS, HiBits;
+ std::tie(LowLHS, HiBits) = split64BitValue(LHS, DAG);
+ SDValue LowOr = DAG.getNode(ISD::OR, SL, MVT::i32, LowLHS, ExtSrc);
+
+ DCI.AddToWorklist(LowOr.getNode());
+ DCI.AddToWorklist(HiBits.getNode());
+
+ SDValue Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32,
+ LowOr, HiBits);
+ return DAG.getNode(ISD::BITCAST, SL, MVT::i64, Vec);
+ }
+ }
- // Only 10 bits are used.
- static const uint32_t MaxMask = 0x3ff;
+ const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (CRHS) {
+ if (SDValue Split
+ = splitBinaryBitConstantOp(DCI, SDLoc(N), ISD::OR, LHS, CRHS))
+ return Split;
+ }
+
+ return SDValue();
+}
+
+SDValue SITargetLowering::performXorCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ EVT VT = N->getValueType(0);
+ if (VT != MVT::i64)
+ return SDValue();
- uint32_t NewMask = (CLHS->getZExtValue() | CRHS->getZExtValue()) & MaxMask;
- SDLoc DL(N);
- return DAG.getNode(AMDGPUISD::FP_CLASS, DL, MVT::i1,
- Src, DAG.getConstant(NewMask, DL, MVT::i32));
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+
+ const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS);
+ if (CRHS) {
+ if (SDValue Split
+ = splitBinaryBitConstantOp(DCI, SDLoc(N), ISD::XOR, LHS, CRHS))
+ return Split;
}
return SDValue();
@@ -2657,6 +3728,9 @@ SDValue SITargetLowering::performFCanonicalizeCombine(
if (VT == MVT::f64 && !Subtarget->hasFP64Denormals())
return DAG.getConstantFP(0.0, SDLoc(N), VT);
+
+ if (VT == MVT::f16 && !Subtarget->hasFP16Denormals())
+ return DAG.getConstantFP(0.0, SDLoc(N), VT);
}
if (C.isNaN()) {
@@ -2716,8 +3790,23 @@ static SDValue performIntMed3ImmCombine(SelectionDAG &DAG, const SDLoc &SL,
}
EVT VT = K0->getValueType(0);
- return DAG.getNode(Signed ? AMDGPUISD::SMED3 : AMDGPUISD::UMED3, SL, VT,
- Op0.getOperand(0), SDValue(K0, 0), SDValue(K1, 0));
+
+ MVT NVT = MVT::i32;
+ unsigned ExtOp = Signed ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+
+ SDValue Tmp1, Tmp2, Tmp3;
+ Tmp1 = DAG.getNode(ExtOp, SL, NVT, Op0->getOperand(0));
+ Tmp2 = DAG.getNode(ExtOp, SL, NVT, Op0->getOperand(1));
+ Tmp3 = DAG.getNode(ExtOp, SL, NVT, Op1);
+
+ if (VT == MVT::i16) {
+ Tmp1 = DAG.getNode(Signed ? AMDGPUISD::SMED3 : AMDGPUISD::UMED3, SL, NVT,
+ Tmp1, Tmp2, Tmp3);
+
+ return DAG.getNode(ISD::TRUNCATE, SL, VT, Tmp1);
+ } else
+ return DAG.getNode(Signed ? AMDGPUISD::SMED3 : AMDGPUISD::UMED3, SL, VT,
+ Op0.getOperand(0), SDValue(K0, 0), SDValue(K1, 0));
}
static bool isKnownNeverSNan(SelectionDAG &DAG, SDValue Op) {
@@ -2814,6 +3903,119 @@ SDValue SITargetLowering::performMinMaxCombine(SDNode *N,
return SDValue();
}
+unsigned SITargetLowering::getFusedOpcode(const SelectionDAG &DAG,
+ const SDNode *N0,
+ const SDNode *N1) const {
+ EVT VT = N0->getValueType(0);
+
+ // Only do this if we are not trying to support denormals. v_mad_f32 does not
+ // support denormals ever.
+ if ((VT == MVT::f32 && !Subtarget->hasFP32Denormals()) ||
+ (VT == MVT::f16 && !Subtarget->hasFP16Denormals()))
+ return ISD::FMAD;
+
+ const TargetOptions &Options = DAG.getTarget().Options;
+ if ((Options.AllowFPOpFusion == FPOpFusion::Fast ||
+ Options.UnsafeFPMath ||
+ (cast<BinaryWithFlagsSDNode>(N0)->Flags.hasUnsafeAlgebra() &&
+ cast<BinaryWithFlagsSDNode>(N1)->Flags.hasUnsafeAlgebra())) &&
+ isFMAFasterThanFMulAndFAdd(VT)) {
+ return ISD::FMA;
+ }
+
+ return 0;
+}
+
+SDValue SITargetLowering::performFAddCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ EVT VT = N->getValueType(0);
+ assert(!VT.isVector());
+
+ SDLoc SL(N);
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+
+ // These should really be instruction patterns, but writing patterns with
+ // source modiifiers is a pain.
+
+ // fadd (fadd (a, a), b) -> mad 2.0, a, b
+ if (LHS.getOpcode() == ISD::FADD) {
+ SDValue A = LHS.getOperand(0);
+ if (A == LHS.getOperand(1)) {
+ unsigned FusedOp = getFusedOpcode(DAG, N, LHS.getNode());
+ if (FusedOp != 0) {
+ const SDValue Two = DAG.getConstantFP(2.0, SL, VT);
+ return DAG.getNode(FusedOp, SL, VT, A, Two, RHS);
+ }
+ }
+ }
+
+ // fadd (b, fadd (a, a)) -> mad 2.0, a, b
+ if (RHS.getOpcode() == ISD::FADD) {
+ SDValue A = RHS.getOperand(0);
+ if (A == RHS.getOperand(1)) {
+ unsigned FusedOp = getFusedOpcode(DAG, N, RHS.getNode());
+ if (FusedOp != 0) {
+ const SDValue Two = DAG.getConstantFP(2.0, SL, VT);
+ return DAG.getNode(FusedOp, SL, VT, A, Two, LHS);
+ }
+ }
+ }
+
+ return SDValue();
+}
+
+SDValue SITargetLowering::performFSubCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc SL(N);
+ EVT VT = N->getValueType(0);
+ assert(!VT.isVector());
+
+ // Try to get the fneg to fold into the source modifier. This undoes generic
+ // DAG combines and folds them into the mad.
+ //
+ // Only do this if we are not trying to support denormals. v_mad_f32 does
+ // not support denormals ever.
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+ if (LHS.getOpcode() == ISD::FADD) {
+ // (fsub (fadd a, a), c) -> mad 2.0, a, (fneg c)
+ SDValue A = LHS.getOperand(0);
+ if (A == LHS.getOperand(1)) {
+ unsigned FusedOp = getFusedOpcode(DAG, N, LHS.getNode());
+ if (FusedOp != 0){
+ const SDValue Two = DAG.getConstantFP(2.0, SL, VT);
+ SDValue NegRHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);
+
+ return DAG.getNode(FusedOp, SL, VT, A, Two, NegRHS);
+ }
+ }
+ }
+
+ if (RHS.getOpcode() == ISD::FADD) {
+ // (fsub c, (fadd a, a)) -> mad -2.0, a, c
+
+ SDValue A = RHS.getOperand(0);
+ if (A == RHS.getOperand(1)) {
+ unsigned FusedOp = getFusedOpcode(DAG, N, RHS.getNode());
+ if (FusedOp != 0){
+ const SDValue NegTwo = DAG.getConstantFP(-2.0, SL, VT);
+ return DAG.getNode(FusedOp, SL, VT, A, NegTwo, LHS);
+ }
+ }
+ }
+
+ return SDValue();
+}
+
SDValue SITargetLowering::performSetCCCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
@@ -2823,7 +4025,8 @@ SDValue SITargetLowering::performSetCCCombine(SDNode *N,
SDValue RHS = N->getOperand(1);
EVT VT = LHS.getValueType();
- if (VT != MVT::f32 && VT != MVT::f64)
+ if (VT != MVT::f32 && VT != MVT::f64 && (Subtarget->has16BitInsts() &&
+ VT != MVT::f16))
return SDValue();
// Match isinf pattern
@@ -2845,14 +4048,59 @@ SDValue SITargetLowering::performSetCCCombine(SDNode *N,
return SDValue();
}
-SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
- DAGCombinerInfo &DCI) const {
+SDValue SITargetLowering::performCvtF32UByteNCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
- SDLoc DL(N);
+ SDLoc SL(N);
+ unsigned Offset = N->getOpcode() - AMDGPUISD::CVT_F32_UBYTE0;
+
+ SDValue Src = N->getOperand(0);
+ SDValue Srl = N->getOperand(0);
+ if (Srl.getOpcode() == ISD::ZERO_EXTEND)
+ Srl = Srl.getOperand(0);
+
+ // TODO: Handle (or x, (srl y, 8)) pattern when known bits are zero.
+ if (Srl.getOpcode() == ISD::SRL) {
+ // cvt_f32_ubyte0 (srl x, 16) -> cvt_f32_ubyte2 x
+ // cvt_f32_ubyte1 (srl x, 16) -> cvt_f32_ubyte3 x
+ // cvt_f32_ubyte0 (srl x, 8) -> cvt_f32_ubyte1 x
+
+ if (const ConstantSDNode *C =
+ dyn_cast<ConstantSDNode>(Srl.getOperand(1))) {
+ Srl = DAG.getZExtOrTrunc(Srl.getOperand(0), SDLoc(Srl.getOperand(0)),
+ EVT(MVT::i32));
+
+ unsigned SrcOffset = C->getZExtValue() + 8 * Offset;
+ if (SrcOffset < 32 && SrcOffset % 8 == 0) {
+ return DAG.getNode(AMDGPUISD::CVT_F32_UBYTE0 + SrcOffset / 8, SL,
+ MVT::f32, Srl);
+ }
+ }
+ }
+
+ APInt Demanded = APInt::getBitsSet(32, 8 * Offset, 8 * Offset + 8);
+ APInt KnownZero, KnownOne;
+ TargetLowering::TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(),
+ !DCI.isBeforeLegalizeOps());
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ if (TLO.ShrinkDemandedConstant(Src, Demanded) ||
+ TLI.SimplifyDemandedBits(Src, Demanded, KnownZero, KnownOne, TLO)) {
+ DCI.CommitTargetLoweringOpt(TLO);
+ }
+
+ return SDValue();
+}
+
+SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
switch (N->getOpcode()) {
default:
return AMDGPUTargetLowering::PerformDAGCombine(N, DCI);
+ case ISD::FADD:
+ return performFAddCombine(N, DCI);
+ case ISD::FSUB:
+ return performFSubCombine(N, DCI);
case ISD::SETCC:
return performSetCCCombine(N, DCI);
case ISD::FMAXNUM:
@@ -2869,127 +4117,6 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
return performMinMaxCombine(N, DCI);
break;
}
-
- case AMDGPUISD::CVT_F32_UBYTE0:
- case AMDGPUISD::CVT_F32_UBYTE1:
- case AMDGPUISD::CVT_F32_UBYTE2:
- case AMDGPUISD::CVT_F32_UBYTE3: {
- unsigned Offset = N->getOpcode() - AMDGPUISD::CVT_F32_UBYTE0;
- SDValue Src = N->getOperand(0);
-
- // TODO: Handle (or x, (srl y, 8)) pattern when known bits are zero.
- if (Src.getOpcode() == ISD::SRL) {
- // cvt_f32_ubyte0 (srl x, 16) -> cvt_f32_ubyte2 x
- // cvt_f32_ubyte1 (srl x, 16) -> cvt_f32_ubyte3 x
- // cvt_f32_ubyte0 (srl x, 8) -> cvt_f32_ubyte1 x
-
- if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Src.getOperand(1))) {
- unsigned SrcOffset = C->getZExtValue() + 8 * Offset;
- if (SrcOffset < 32 && SrcOffset % 8 == 0) {
- return DAG.getNode(AMDGPUISD::CVT_F32_UBYTE0 + SrcOffset / 8, DL,
- MVT::f32, Src.getOperand(0));
- }
- }
- }
-
- APInt Demanded = APInt::getBitsSet(32, 8 * Offset, 8 * Offset + 8);
-
- APInt KnownZero, KnownOne;
- TargetLowering::TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(),
- !DCI.isBeforeLegalizeOps());
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- if (TLO.ShrinkDemandedConstant(Src, Demanded) ||
- TLI.SimplifyDemandedBits(Src, Demanded, KnownZero, KnownOne, TLO)) {
- DCI.CommitTargetLoweringOpt(TLO);
- }
-
- break;
- }
-
- case ISD::UINT_TO_FP: {
- return performUCharToFloatCombine(N, DCI);
- }
- case ISD::FADD: {
- if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
- break;
-
- EVT VT = N->getValueType(0);
- if (VT != MVT::f32)
- break;
-
- // Only do this if we are not trying to support denormals. v_mad_f32 does
- // not support denormals ever.
- if (Subtarget->hasFP32Denormals())
- break;
-
- SDValue LHS = N->getOperand(0);
- SDValue RHS = N->getOperand(1);
-
- // These should really be instruction patterns, but writing patterns with
- // source modiifiers is a pain.
-
- // fadd (fadd (a, a), b) -> mad 2.0, a, b
- if (LHS.getOpcode() == ISD::FADD) {
- SDValue A = LHS.getOperand(0);
- if (A == LHS.getOperand(1)) {
- const SDValue Two = DAG.getConstantFP(2.0, DL, MVT::f32);
- return DAG.getNode(ISD::FMAD, DL, VT, Two, A, RHS);
- }
- }
-
- // fadd (b, fadd (a, a)) -> mad 2.0, a, b
- if (RHS.getOpcode() == ISD::FADD) {
- SDValue A = RHS.getOperand(0);
- if (A == RHS.getOperand(1)) {
- const SDValue Two = DAG.getConstantFP(2.0, DL, MVT::f32);
- return DAG.getNode(ISD::FMAD, DL, VT, Two, A, LHS);
- }
- }
-
- return SDValue();
- }
- case ISD::FSUB: {
- if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)
- break;
-
- EVT VT = N->getValueType(0);
-
- // Try to get the fneg to fold into the source modifier. This undoes generic
- // DAG combines and folds them into the mad.
- //
- // Only do this if we are not trying to support denormals. v_mad_f32 does
- // not support denormals ever.
- if (VT == MVT::f32 &&
- !Subtarget->hasFP32Denormals()) {
- SDValue LHS = N->getOperand(0);
- SDValue RHS = N->getOperand(1);
- if (LHS.getOpcode() == ISD::FADD) {
- // (fsub (fadd a, a), c) -> mad 2.0, a, (fneg c)
-
- SDValue A = LHS.getOperand(0);
- if (A == LHS.getOperand(1)) {
- const SDValue Two = DAG.getConstantFP(2.0, DL, MVT::f32);
- SDValue NegRHS = DAG.getNode(ISD::FNEG, DL, VT, RHS);
-
- return DAG.getNode(ISD::FMAD, DL, VT, Two, A, NegRHS);
- }
- }
-
- if (RHS.getOpcode() == ISD::FADD) {
- // (fsub c, (fadd a, a)) -> mad -2.0, a, c
-
- SDValue A = RHS.getOperand(0);
- if (A == RHS.getOperand(1)) {
- const SDValue NegTwo = DAG.getConstantFP(-2.0, DL, MVT::f32);
- return DAG.getNode(ISD::FMAD, DL, VT, NegTwo, A, LHS);
- }
- }
-
- return SDValue();
- }
-
- break;
- }
case ISD::LOAD:
case ISD::STORE:
case ISD::ATOMIC_LOAD:
@@ -3011,27 +4138,14 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
case AMDGPUISD::ATOMIC_DEC: { // TODO: Target mem intrinsics.
if (DCI.isBeforeLegalize())
break;
-
- MemSDNode *MemNode = cast<MemSDNode>(N);
- SDValue Ptr = MemNode->getBasePtr();
-
- // TODO: We could also do this for multiplies.
- unsigned AS = MemNode->getAddressSpace();
- if (Ptr.getOpcode() == ISD::SHL && AS != AMDGPUAS::PRIVATE_ADDRESS) {
- SDValue NewPtr = performSHLPtrCombine(Ptr.getNode(), AS, DCI);
- if (NewPtr) {
- SmallVector<SDValue, 8> NewOps(MemNode->op_begin(), MemNode->op_end());
-
- NewOps[N->getOpcode() == ISD::STORE ? 2 : 1] = NewPtr;
- return SDValue(DAG.UpdateNodeOperands(MemNode, NewOps), 0);
- }
- }
- break;
+ return performMemSDNodeCombine(cast<MemSDNode>(N), DCI);
}
case ISD::AND:
return performAndCombine(N, DCI);
case ISD::OR:
return performOrCombine(N, DCI);
+ case ISD::XOR:
+ return performXorCombine(N, DCI);
case AMDGPUISD::FP_CLASS:
return performClassCombine(N, DCI);
case ISD::FCANONICALIZE:
@@ -3039,6 +4153,7 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
case AMDGPUISD::FRACT:
case AMDGPUISD::RCP:
case AMDGPUISD::RSQ:
+ case AMDGPUISD::RCP_LEGACY:
case AMDGPUISD::RSQ_LEGACY:
case AMDGPUISD::RSQ_CLAMP:
case AMDGPUISD::LDEXP: {
@@ -3047,38 +4162,18 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
return Src;
break;
}
+ case ISD::SINT_TO_FP:
+ case ISD::UINT_TO_FP:
+ return performUCharToFloatCombine(N, DCI);
+ case AMDGPUISD::CVT_F32_UBYTE0:
+ case AMDGPUISD::CVT_F32_UBYTE1:
+ case AMDGPUISD::CVT_F32_UBYTE2:
+ case AMDGPUISD::CVT_F32_UBYTE3:
+ return performCvtF32UByteNCombine(N, DCI);
}
return AMDGPUTargetLowering::PerformDAGCombine(N, DCI);
}
-/// \brief Analyze the possible immediate value Op
-///
-/// Returns -1 if it isn't an immediate, 0 if it's and inline immediate
-/// and the immediate value if it's a literal immediate
-int32_t SITargetLowering::analyzeImmediate(const SDNode *N) const {
- const SIInstrInfo *TII = getSubtarget()->getInstrInfo();
-
- if (const ConstantSDNode *Node = dyn_cast<ConstantSDNode>(N)) {
- if (TII->isInlineConstant(Node->getAPIntValue()))
- return 0;
-
- uint64_t Val = Node->getZExtValue();
- return isUInt<32>(Val) ? Val : -1;
- }
-
- if (const ConstantFPSDNode *Node = dyn_cast<ConstantFPSDNode>(N)) {
- if (TII->isInlineConstant(Node->getValueAPF().bitcastToAPInt()))
- return 0;
-
- if (Node->getValueType(0) == MVT::f32)
- return FloatToBits(Node->getValueAPF().convertToFloat());
-
- return -1;
- }
-
- return -1;
-}
-
/// \brief Helper function for adjustWritemask
static unsigned SubIdx2Lane(unsigned Idx) {
switch (Idx) {
@@ -3235,13 +4330,16 @@ void SITargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,
if (TII->isMIMG(MI)) {
unsigned VReg = MI.getOperand(0).getReg();
+ const TargetRegisterClass *RC = MRI.getRegClass(VReg);
+ // TODO: Need mapping tables to handle other cases (register classes).
+ if (RC != &AMDGPU::VReg_128RegClass)
+ return;
+
unsigned DmaskIdx = MI.getNumOperands() == 12 ? 3 : 4;
unsigned Writemask = MI.getOperand(DmaskIdx).getImm();
unsigned BitsSet = 0;
for (unsigned i = 0; i < 4; ++i)
BitsSet += Writemask & (1 << i) ? 1 : 0;
-
- const TargetRegisterClass *RC;
switch (BitsSet) {
default: return;
case 1: RC = &AMDGPU::VGPR_32RegClass; break;
@@ -3379,6 +4477,8 @@ std::pair<unsigned, const TargetRegisterClass *>
SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint,
MVT VT) const {
+ if (!isTypeLegal(VT))
+ return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
if (Constraint.size() == 1) {
switch (Constraint[0]) {
@@ -3388,7 +4488,8 @@ SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
default:
return std::make_pair(0U, nullptr);
case 32:
- return std::make_pair(0U, &AMDGPU::SGPR_32RegClass);
+ case 16:
+ return std::make_pair(0U, &AMDGPU::SReg_32_XM0RegClass);
case 64:
return std::make_pair(0U, &AMDGPU::SGPR_64RegClass);
case 128:
@@ -3402,6 +4503,7 @@ SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
default:
return std::make_pair(0U, nullptr);
case 32:
+ case 16:
return std::make_pair(0U, &AMDGPU::VGPR_32RegClass);
case 64:
return std::make_pair(0U, &AMDGPU::VReg_64RegClass);
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h
index 1d349fa..6c04e4f 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -24,7 +24,8 @@ class SITargetLowering final : public AMDGPUTargetLowering {
SDValue LowerParameterPtr(SelectionDAG &DAG, const SDLoc &SL, SDValue Chain,
unsigned Offset) const;
SDValue LowerParameter(SelectionDAG &DAG, EVT VT, EVT MemVT, const SDLoc &SL,
- SDValue Chain, unsigned Offset, bool Signed) const;
+ SDValue Chain, unsigned Offset, bool Signed,
+ const ISD::InputArg *Arg = nullptr) const;
SDValue LowerGlobalAddress(AMDGPUMachineFunction *MFI, SDValue Op,
SelectionDAG &DAG) const override;
SDValue lowerImplicitZextParam(SelectionDAG &DAG, SDValue Op,
@@ -33,11 +34,11 @@ class SITargetLowering final : public AMDGPUTargetLowering {
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerFrameIndex(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFastUnsafeFDIV(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFDIV_FAST(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerFDIV16(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFDIV32(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFDIV64(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFDIV(SDValue Op, SelectionDAG &DAG) const;
@@ -47,6 +48,16 @@ class SITargetLowering final : public AMDGPUTargetLowering {
SDValue LowerATOMIC_CMP_SWAP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBRCOND(SDValue Op, SelectionDAG &DAG) const;
+ /// \brief Converts \p Op, which must be of floating point type, to the
+ /// floating point type \p VT, by either extending or truncating it.
+ SDValue getFPExtOrFPTrunc(SelectionDAG &DAG,
+ SDValue Op,
+ const SDLoc &DL,
+ EVT VT) const;
+
+ /// \brief Custom lowering for ISD::FP_ROUND for MVT::f16.
+ SDValue lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const;
+
SDValue getSegmentAperture(unsigned AS, SelectionDAG &DAG) const;
SDValue lowerADDRSPACECAST(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerTRAP(SDValue Op, SelectionDAG &DAG) const;
@@ -58,14 +69,27 @@ class SITargetLowering final : public AMDGPUTargetLowering {
SDValue performSHLPtrCombine(SDNode *N,
unsigned AS,
DAGCombinerInfo &DCI) const;
+
+ SDValue performMemSDNodeCombine(MemSDNode *N, DAGCombinerInfo &DCI) const;
+
+ SDValue splitBinaryBitConstantOp(DAGCombinerInfo &DCI, const SDLoc &SL,
+ unsigned Opc, SDValue LHS,
+ const ConstantSDNode *CRHS) const;
+
SDValue performAndCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performOrCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performXorCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performClassCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performFCanonicalizeCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performMinMaxCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ unsigned getFusedOpcode(const SelectionDAG &DAG,
+ const SDNode *N0, const SDNode *N1) const;
+ SDValue performFAddCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performFSubCombine(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue performSetCCCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+ SDValue performCvtF32UByteNCombine(SDNode *N, DAGCombinerInfo &DCI) const;
bool isLegalFlatAddressingMode(const AddrMode &AM) const;
bool isLegalMUBUFAddressingMode(const AddrMode &AM) const;
@@ -73,6 +97,19 @@ class SITargetLowering final : public AMDGPUTargetLowering {
bool isCFIntrinsic(const SDNode *Intr) const;
void createDebuggerPrologueStackObjects(MachineFunction &MF) const;
+
+ /// \returns True if fixup needs to be emitted for given global value \p GV,
+ /// false otherwise.
+ bool shouldEmitFixup(const GlobalValue *GV) const;
+
+ /// \returns True if GOT relocation needs to be emitted for given global value
+ /// \p GV, false otherwise.
+ bool shouldEmitGOTReloc(const GlobalValue *GV) const;
+
+ /// \returns True if PC-relative relocation needs to be emitted for given
+ /// global value \p GV, false otherwise.
+ bool shouldEmitPCReloc(const GlobalValue *GV) const;
+
public:
SITargetLowering(const TargetMachine &tm, const SISubtarget &STI);
@@ -98,7 +135,9 @@ public:
MachineFunction &MF) const override;
bool isMemOpUniform(const SDNode *N) const;
+ bool isMemOpHasNoClobberedMemOperand(const SDNode *N) const;
bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override;
+ bool isCheapAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override;
TargetLoweringBase::LegalizeTypeAction
getPreferredVectorAction(EVT VT) const override;
@@ -141,7 +180,6 @@ public:
void AdjustInstrPostInstrSelection(MachineInstr &MI,
SDNode *Node) const override;
- int32_t analyzeImmediate(const SDNode *N) const;
SDValue CreateLiveInRegister(SelectionDAG &DAG, const TargetRegisterClass *RC,
unsigned Reg, EVT VT) const override;
void legalizeTargetIndependentNode(SDNode *Node, SelectionDAG &DAG) const;
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInsertSkips.cpp b/contrib/llvm/lib/Target/AMDGPU/SIInsertSkips.cpp
new file mode 100644
index 0000000..91e4bf7
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInsertSkips.cpp
@@ -0,0 +1,329 @@
+//===-- SIInsertSkips.cpp - Use predicates for control flow ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// \brief This pass inserts branches on the 0 exec mask over divergent branches
+/// branches when it's expected that jumping over the untaken control flow will
+/// be cheaper than having every workitem no-op through it.
+//
+
+#include "AMDGPU.h"
+#include "AMDGPUSubtarget.h"
+#include "SIInstrInfo.h"
+#include "SIMachineFunctionInfo.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/MC/MCAsmInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "si-insert-skips"
+
+namespace {
+
+static cl::opt<unsigned> SkipThresholdFlag(
+ "amdgpu-skip-threshold",
+ cl::desc("Number of instructions before jumping over divergent control flow"),
+ cl::init(12), cl::Hidden);
+
+class SIInsertSkips : public MachineFunctionPass {
+private:
+ const SIRegisterInfo *TRI;
+ const SIInstrInfo *TII;
+ unsigned SkipThreshold;
+
+ bool shouldSkip(const MachineBasicBlock &From,
+ const MachineBasicBlock &To) const;
+
+ bool skipIfDead(MachineInstr &MI, MachineBasicBlock &NextBB);
+
+ void kill(MachineInstr &MI);
+
+ MachineBasicBlock *insertSkipBlock(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const;
+
+ bool skipMaskBranch(MachineInstr &MI, MachineBasicBlock &MBB);
+
+public:
+ static char ID;
+
+ SIInsertSkips() :
+ MachineFunctionPass(ID), TRI(nullptr), TII(nullptr), SkipThreshold(0) { }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override {
+ return "SI insert s_cbranch_execz instructions";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+};
+
+} // End anonymous namespace
+
+char SIInsertSkips::ID = 0;
+
+INITIALIZE_PASS(SIInsertSkips, DEBUG_TYPE,
+ "SI insert s_cbranch_execz instructions", false, false)
+
+char &llvm::SIInsertSkipsPassID = SIInsertSkips::ID;
+
+static bool opcodeEmitsNoInsts(unsigned Opc) {
+ switch (Opc) {
+ case TargetOpcode::IMPLICIT_DEF:
+ case TargetOpcode::KILL:
+ case TargetOpcode::BUNDLE:
+ case TargetOpcode::CFI_INSTRUCTION:
+ case TargetOpcode::EH_LABEL:
+ case TargetOpcode::GC_LABEL:
+ case TargetOpcode::DBG_VALUE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool SIInsertSkips::shouldSkip(const MachineBasicBlock &From,
+ const MachineBasicBlock &To) const {
+ if (From.succ_empty())
+ return false;
+
+ unsigned NumInstr = 0;
+ const MachineFunction *MF = From.getParent();
+
+ for (MachineFunction::const_iterator MBBI(&From), ToI(&To), End = MF->end();
+ MBBI != End && MBBI != ToI; ++MBBI) {
+ const MachineBasicBlock &MBB = *MBBI;
+
+ for (MachineBasicBlock::const_iterator I = MBB.begin(), E = MBB.end();
+ NumInstr < SkipThreshold && I != E; ++I) {
+ if (opcodeEmitsNoInsts(I->getOpcode()))
+ continue;
+
+ // FIXME: Since this is required for correctness, this should be inserted
+ // during SILowerControlFlow.
+
+ // When a uniform loop is inside non-uniform control flow, the branch
+ // leaving the loop might be an S_CBRANCH_VCCNZ, which is never taken
+ // when EXEC = 0. We should skip the loop lest it becomes infinite.
+ if (I->getOpcode() == AMDGPU::S_CBRANCH_VCCNZ ||
+ I->getOpcode() == AMDGPU::S_CBRANCH_VCCZ)
+ return true;
+
+ if (I->isInlineAsm()) {
+ const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
+ const char *AsmStr = I->getOperand(0).getSymbolName();
+
+ // inlineasm length estimate is number of bytes assuming the longest
+ // instruction.
+ uint64_t MaxAsmSize = TII->getInlineAsmLength(AsmStr, *MAI);
+ NumInstr += MaxAsmSize / MAI->getMaxInstLength();
+ } else {
+ ++NumInstr;
+ }
+
+ if (NumInstr >= SkipThreshold)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SIInsertSkips::skipIfDead(MachineInstr &MI, MachineBasicBlock &NextBB) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ MachineFunction *MF = MBB.getParent();
+
+ if (MF->getFunction()->getCallingConv() != CallingConv::AMDGPU_PS ||
+ !shouldSkip(MBB, MBB.getParent()->back()))
+ return false;
+
+ MachineBasicBlock *SkipBB = insertSkipBlock(MBB, MI.getIterator());
+
+ const DebugLoc &DL = MI.getDebugLoc();
+
+ // If the exec mask is non-zero, skip the next two instructions
+ BuildMI(&MBB, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))
+ .addMBB(&NextBB);
+
+ MachineBasicBlock::iterator Insert = SkipBB->begin();
+
+ // Exec mask is zero: Export to NULL target...
+ BuildMI(*SkipBB, Insert, DL, TII->get(AMDGPU::EXP_DONE))
+ .addImm(0x09) // V_008DFC_SQ_EXP_NULL
+ .addReg(AMDGPU::VGPR0, RegState::Undef)
+ .addReg(AMDGPU::VGPR0, RegState::Undef)
+ .addReg(AMDGPU::VGPR0, RegState::Undef)
+ .addReg(AMDGPU::VGPR0, RegState::Undef)
+ .addImm(1) // vm
+ .addImm(0) // compr
+ .addImm(0); // en
+
+ // ... and terminate wavefront.
+ BuildMI(*SkipBB, Insert, DL, TII->get(AMDGPU::S_ENDPGM));
+
+ return true;
+}
+
+void SIInsertSkips::kill(MachineInstr &MI) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ DebugLoc DL = MI.getDebugLoc();
+ const MachineOperand &Op = MI.getOperand(0);
+
+#ifndef NDEBUG
+ CallingConv::ID CallConv = MBB.getParent()->getFunction()->getCallingConv();
+ // Kill is only allowed in pixel / geometry shaders.
+ assert(CallConv == CallingConv::AMDGPU_PS ||
+ CallConv == CallingConv::AMDGPU_GS);
+#endif
+ // Clear this thread from the exec mask if the operand is negative.
+ if (Op.isImm()) {
+ // Constant operand: Set exec mask to 0 or do nothing
+ if (Op.getImm() & 0x80000000) {
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_MOV_B64), AMDGPU::EXEC)
+ .addImm(0);
+ }
+ } else {
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::V_CMPX_LE_F32_e32))
+ .addImm(0)
+ .addOperand(Op);
+ }
+}
+
+MachineBasicBlock *SIInsertSkips::insertSkipBlock(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const {
+ MachineFunction *MF = MBB.getParent();
+
+ MachineBasicBlock *SkipBB = MF->CreateMachineBasicBlock();
+ MachineFunction::iterator MBBI(MBB);
+ ++MBBI;
+
+ MF->insert(MBBI, SkipBB);
+ MBB.addSuccessor(SkipBB);
+
+ return SkipBB;
+}
+
+// Returns true if a branch over the block was inserted.
+bool SIInsertSkips::skipMaskBranch(MachineInstr &MI,
+ MachineBasicBlock &SrcMBB) {
+ MachineBasicBlock *DestBB = MI.getOperand(0).getMBB();
+
+ if (!shouldSkip(**SrcMBB.succ_begin(), *DestBB))
+ return false;
+
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock::iterator InsPt = std::next(MI.getIterator());
+
+ BuildMI(SrcMBB, InsPt, DL, TII->get(AMDGPU::S_CBRANCH_EXECZ))
+ .addMBB(DestBB);
+
+ return true;
+}
+
+bool SIInsertSkips::runOnMachineFunction(MachineFunction &MF) {
+ const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
+ TII = ST.getInstrInfo();
+ TRI = &TII->getRegisterInfo();
+ SkipThreshold = SkipThresholdFlag;
+
+ bool HaveKill = false;
+ bool MadeChange = false;
+
+ // Track depth of exec mask, divergent branches.
+ SmallVector<MachineBasicBlock *, 16> ExecBranchStack;
+
+ MachineFunction::iterator NextBB;
+
+ MachineBasicBlock *EmptyMBBAtEnd = nullptr;
+
+ for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
+ BI != BE; BI = NextBB) {
+ NextBB = std::next(BI);
+ MachineBasicBlock &MBB = *BI;
+
+ if (!ExecBranchStack.empty() && ExecBranchStack.back() == &MBB) {
+ // Reached convergence point for last divergent branch.
+ ExecBranchStack.pop_back();
+ }
+
+ if (HaveKill && ExecBranchStack.empty()) {
+ HaveKill = false;
+
+ // TODO: Insert skip if exec is 0?
+ }
+
+ MachineBasicBlock::iterator I, Next;
+ for (I = MBB.begin(); I != MBB.end(); I = Next) {
+ Next = std::next(I);
+
+ MachineInstr &MI = *I;
+
+ switch (MI.getOpcode()) {
+ case AMDGPU::SI_MASK_BRANCH: {
+ ExecBranchStack.push_back(MI.getOperand(0).getMBB());
+ MadeChange |= skipMaskBranch(MI, MBB);
+ break;
+ }
+ case AMDGPU::S_BRANCH: {
+ // Optimize out branches to the next block.
+ // FIXME: Shouldn't this be handled by BranchFolding?
+ if (MBB.isLayoutSuccessor(MI.getOperand(0).getMBB()))
+ MI.eraseFromParent();
+ break;
+ }
+ case AMDGPU::SI_KILL_TERMINATOR: {
+ MadeChange = true;
+ kill(MI);
+
+ if (ExecBranchStack.empty()) {
+ if (skipIfDead(MI, *NextBB)) {
+ NextBB = std::next(BI);
+ BE = MF.end();
+ Next = MBB.end();
+ }
+ } else {
+ HaveKill = true;
+ }
+
+ MI.eraseFromParent();
+ break;
+ }
+ case AMDGPU::SI_RETURN: {
+ // FIXME: Should move somewhere else
+ assert(!MF.getInfo<SIMachineFunctionInfo>()->returnsVoid());
+
+ // Graphics shaders returning non-void shouldn't contain S_ENDPGM,
+ // because external bytecode will be appended at the end.
+ if (BI != --MF.end() || I != MBB.getFirstTerminator()) {
+ // SI_RETURN is not the last instruction. Add an empty block at
+ // the end and jump there.
+ if (!EmptyMBBAtEnd) {
+ EmptyMBBAtEnd = MF.CreateMachineBasicBlock();
+ MF.insert(MF.end(), EmptyMBBAtEnd);
+ }
+
+ MBB.addSuccessor(EmptyMBBAtEnd);
+ BuildMI(*BI, I, MI.getDebugLoc(), TII->get(AMDGPU::S_BRANCH))
+ .addMBB(EmptyMBBAtEnd);
+ I->eraseFromParent();
+ }
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ return MadeChange;
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInsertWaits.cpp b/contrib/llvm/lib/Target/AMDGPU/SIInsertWaits.cpp
index d24588d..fceabd7 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIInsertWaits.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInsertWaits.cpp
@@ -21,6 +21,7 @@
#include "SIDefines.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
+#include "Utils/AMDGPUBaseInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -29,6 +30,7 @@
#define DEBUG_TYPE "si-insert-waits"
using namespace llvm;
+using namespace llvm::AMDGPU;
namespace {
@@ -59,13 +61,14 @@ private:
const SIInstrInfo *TII;
const SIRegisterInfo *TRI;
const MachineRegisterInfo *MRI;
-
- /// \brief Constant hardware limits
- static const Counters WaitCounts;
+ IsaVersion IV;
/// \brief Constant zero value
static const Counters ZeroCounts;
+ /// \brief Hardware limits
+ Counters HardwareLimits;
+
/// \brief Counter values we have already waited on.
Counters WaitedOn;
@@ -90,6 +93,9 @@ private:
bool LastInstWritesM0;
+ /// Whether or not we have flat operations outstanding.
+ bool IsFlatOutstanding;
+
/// \brief Whether the machine function returns void
bool ReturnsVoid;
@@ -145,7 +151,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SI insert wait instructions";
}
@@ -170,11 +176,12 @@ FunctionPass *llvm::createSIInsertWaitsPass() {
return new SIInsertWaits();
}
-const Counters SIInsertWaits::WaitCounts = { { 15, 7, 15 } };
const Counters SIInsertWaits::ZeroCounts = { { 0, 0, 0 } };
-static bool readsVCCZ(unsigned Opcode) {
- return Opcode == AMDGPU::S_CBRANCH_VCCNZ || Opcode == AMDGPU::S_CBRANCH_VCCZ;
+static bool readsVCCZ(const MachineInstr &MI) {
+ unsigned Opc = MI.getOpcode();
+ return (Opc == AMDGPU::S_CBRANCH_VCCNZ || Opc == AMDGPU::S_CBRANCH_VCCZ) &&
+ !MI.getOperand(1).isUndef();
}
bool SIInsertWaits::hasOutstandingLGKM() const {
@@ -188,8 +195,7 @@ Counters SIInsertWaits::getHwCounts(MachineInstr &MI) {
Result.Named.VM = !!(TSFlags & SIInstrFlags::VM_CNT);
// Only consider stores or EXP for EXP_CNT
- Result.Named.EXP = !!(TSFlags & SIInstrFlags::EXP_CNT &&
- (MI.getOpcode() == AMDGPU::EXP || MI.getDesc().mayStore()));
+ Result.Named.EXP = !!(TSFlags & SIInstrFlags::EXP_CNT) && MI.mayStore();
// LGKM may uses larger values
if (TSFlags & SIInstrFlags::LGKM_CNT) {
@@ -231,9 +237,10 @@ bool SIInsertWaits::isOpRelevant(MachineOperand &Op) {
if (Op.isDef())
return true;
- // For exports all registers are relevant
+ // For exports all registers are relevant.
+ // TODO: Skip undef/disabled registers.
MachineInstr &MI = *Op.getParent();
- if (MI.getOpcode() == AMDGPU::EXP)
+ if (TII->isEXP(MI))
return true;
// For stores the stored value is also relevant
@@ -245,12 +252,6 @@ bool SIInsertWaits::isOpRelevant(MachineOperand &Op) {
// operand comes before the value operand and it may have
// multiple data operands.
- if (TII->isDS(MI) || TII->isFLAT(MI)) {
- MachineOperand *Data = TII->getNamedOperand(MI, AMDGPU::OpName::data);
- if (Data && Op.isIdenticalTo(*Data))
- return true;
- }
-
if (TII->isDS(MI)) {
MachineOperand *Data0 = TII->getNamedOperand(MI, AMDGPU::OpName::data0);
if (Data0 && Op.isIdenticalTo(*Data0))
@@ -260,6 +261,12 @@ bool SIInsertWaits::isOpRelevant(MachineOperand &Op) {
return Data1 && Op.isIdenticalTo(*Data1);
}
+ if (TII->isFLAT(MI)) {
+ MachineOperand *Data = TII->getNamedOperand(MI, AMDGPU::OpName::vdata);
+ if (Data && Op.isIdenticalTo(*Data))
+ return true;
+ }
+
// NOTE: This assumes that the value operand is before the
// address operand, and that there is only one value operand.
for (MachineInstr::mop_iterator I = MI.operands_begin(),
@@ -292,6 +299,9 @@ void SIInsertWaits::pushInstruction(MachineBasicBlock &MBB,
Counters Limit = ZeroCounts;
unsigned Sum = 0;
+ if (TII->mayAccessFlatAddressSpace(*I))
+ IsFlatOutstanding = true;
+
for (unsigned i = 0; i < 3; ++i) {
LastIssued.Array[i] += Increment.Array[i];
if (Increment.Array[i])
@@ -330,7 +340,7 @@ void SIInsertWaits::pushInstruction(MachineBasicBlock &MBB,
// Remember which export instructions we have seen
if (Increment.Named.EXP) {
- ExpInstrTypesSeen |= I->getOpcode() == AMDGPU::EXP ? 1 : 2;
+ ExpInstrTypesSeen |= TII->isEXP(*I) ? 1 : 2;
}
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
@@ -366,8 +376,9 @@ bool SIInsertWaits::insertWait(MachineBasicBlock &MBB,
// Figure out if the async instructions execute in order
bool Ordered[3];
- // VM_CNT is always ordered
- Ordered[0] = true;
+ // VM_CNT is always ordered except when there are flat instructions, which
+ // can return out of order.
+ Ordered[0] = !IsFlatOutstanding;
// EXP_CNT is unordered if we have both EXP & VM-writes
Ordered[1] = ExpInstrTypesSeen == 3;
@@ -376,7 +387,7 @@ bool SIInsertWaits::insertWait(MachineBasicBlock &MBB,
Ordered[2] = false;
// The values we are going to put into the S_WAITCNT instruction
- Counters Counts = WaitCounts;
+ Counters Counts = HardwareLimits;
// Do we really need to wait?
bool NeedWait = false;
@@ -392,7 +403,7 @@ bool SIInsertWaits::insertWait(MachineBasicBlock &MBB,
unsigned Value = LastIssued.Array[i] - Required.Array[i];
// Adjust the value to the real hardware possibilities.
- Counts.Array[i] = std::min(Value, WaitCounts.Array[i]);
+ Counts.Array[i] = std::min(Value, HardwareLimits.Array[i]);
} else
Counts.Array[i] = 0;
@@ -410,12 +421,14 @@ bool SIInsertWaits::insertWait(MachineBasicBlock &MBB,
// Build the wait instruction
BuildMI(MBB, I, DebugLoc(), TII->get(AMDGPU::S_WAITCNT))
- .addImm((Counts.Named.VM & 0xF) |
- ((Counts.Named.EXP & 0x7) << 4) |
- ((Counts.Named.LGKM & 0xF) << 8));
+ .addImm(encodeWaitcnt(IV,
+ Counts.Named.VM,
+ Counts.Named.EXP,
+ Counts.Named.LGKM));
LastOpcodeType = OTHER;
LastInstWritesM0 = false;
+ IsFlatOutstanding = false;
return true;
}
@@ -440,9 +453,9 @@ void SIInsertWaits::handleExistingWait(MachineBasicBlock::iterator I) {
unsigned Imm = I->getOperand(0).getImm();
Counters Counts, WaitOn;
- Counts.Named.VM = Imm & 0xF;
- Counts.Named.EXP = (Imm >> 4) & 0x7;
- Counts.Named.LGKM = (Imm >> 8) & 0xF;
+ Counts.Named.VM = decodeVmcnt(IV, Imm);
+ Counts.Named.EXP = decodeExpcnt(IV, Imm);
+ Counts.Named.LGKM = decodeLgkmcnt(IV, Imm);
for (unsigned i = 0; i < 3; ++i) {
if (Counts.Array[i] <= LastIssued.Array[i])
@@ -491,7 +504,7 @@ void SIInsertWaits::handleSendMsg(MachineBasicBlock &MBB,
return;
// There must be "S_NOP 0" between an instruction writing M0 and S_SENDMSG.
- if (LastInstWritesM0 && I->getOpcode() == AMDGPU::S_SENDMSG) {
+ if (LastInstWritesM0 && (I->getOpcode() == AMDGPU::S_SENDMSG || I->getOpcode() == AMDGPU::S_SENDMSGHALT)) {
BuildMI(MBB, I, DebugLoc(), TII->get(AMDGPU::S_NOP)).addImm(0);
LastInstWritesM0 = false;
return;
@@ -518,26 +531,40 @@ bool SIInsertWaits::runOnMachineFunction(MachineFunction &MF) {
TII = ST->getInstrInfo();
TRI = &TII->getRegisterInfo();
MRI = &MF.getRegInfo();
+ IV = getIsaVersion(ST->getFeatureBits());
+ const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+
+ HardwareLimits.Named.VM = getVmcntBitMask(IV);
+ HardwareLimits.Named.EXP = getExpcntBitMask(IV);
+ HardwareLimits.Named.LGKM = getLgkmcntBitMask(IV);
WaitedOn = ZeroCounts;
DelayedWaitOn = ZeroCounts;
LastIssued = ZeroCounts;
LastOpcodeType = OTHER;
LastInstWritesM0 = false;
- ReturnsVoid = MF.getInfo<SIMachineFunctionInfo>()->returnsVoid();
+ IsFlatOutstanding = false;
+ ReturnsVoid = MFI->returnsVoid();
memset(&UsedRegs, 0, sizeof(UsedRegs));
memset(&DefinedRegs, 0, sizeof(DefinedRegs));
SmallVector<MachineInstr *, 4> RemoveMI;
+ SmallVector<MachineBasicBlock *, 4> EndPgmBlocks;
+
+ bool HaveScalarStores = false;
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
BI != BE; ++BI) {
MachineBasicBlock &MBB = *BI;
+
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
I != E; ++I) {
+ if (!HaveScalarStores && TII->isScalarStore(*I))
+ HaveScalarStores = true;
+
if (ST->getGeneration() <= SISubtarget::SEA_ISLANDS) {
// There is a hardware bug on CI/SI where SMRD instruction may corrupt
// vccz bit, so when we detect that an instruction may read from a
@@ -557,7 +584,7 @@ bool SIInsertWaits::runOnMachineFunction(MachineFunction &MF) {
}
// Check if we need to apply the bug work-around
- if (readsVCCZ(I->getOpcode()) && VCCZCorrupt) {
+ if (VCCZCorrupt && readsVCCZ(*I)) {
DEBUG(dbgs() << "Inserting vccz bug work-around before: " << *I << '\n');
// Wait on everything, not just LGKM. vccz reads usually come from
@@ -572,7 +599,7 @@ bool SIInsertWaits::runOnMachineFunction(MachineFunction &MF) {
// vcc and then writing it back to the register.
BuildMI(MBB, I, I->getDebugLoc(), TII->get(AMDGPU::S_MOV_B64),
AMDGPU::VCC)
- .addReg(AMDGPU::VCC);
+ .addReg(AMDGPU::VCC);
}
}
@@ -590,8 +617,10 @@ bool SIInsertWaits::runOnMachineFunction(MachineFunction &MF) {
// S_SENDMSG implicitly waits for all outstanding LGKM transfers to finish,
// but we also want to wait for any other outstanding transfers before
// signalling other hardware blocks
- if (I->getOpcode() == AMDGPU::S_BARRIER ||
- I->getOpcode() == AMDGPU::S_SENDMSG)
+ if ((I->getOpcode() == AMDGPU::S_BARRIER &&
+ ST->needWaitcntBeforeBarrier()) ||
+ I->getOpcode() == AMDGPU::S_SENDMSG ||
+ I->getOpcode() == AMDGPU::S_SENDMSGHALT)
Required = LastIssued;
else
Required = handleOperands(*I);
@@ -605,12 +634,45 @@ bool SIInsertWaits::runOnMachineFunction(MachineFunction &MF) {
pushInstruction(MBB, I, Increment);
handleSendMsg(MBB, I);
+
+ if (I->getOpcode() == AMDGPU::S_ENDPGM ||
+ I->getOpcode() == AMDGPU::SI_RETURN)
+ EndPgmBlocks.push_back(&MBB);
}
// Wait for everything at the end of the MBB
Changes |= insertWait(MBB, MBB.getFirstTerminator(), LastIssued);
}
+ if (HaveScalarStores) {
+ // If scalar writes are used, the cache must be flushed or else the next
+ // wave to reuse the same scratch memory can be clobbered.
+ //
+ // Insert s_dcache_wb at wave termination points if there were any scalar
+ // stores, and only if the cache hasn't already been flushed. This could be
+ // improved by looking across blocks for flushes in postdominating blocks
+ // from the stores but an explicitly requested flush is probably very rare.
+ for (MachineBasicBlock *MBB : EndPgmBlocks) {
+ bool SeenDCacheWB = false;
+
+ for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
+ I != E; ++I) {
+
+ if (I->getOpcode() == AMDGPU::S_DCACHE_WB)
+ SeenDCacheWB = true;
+ else if (TII->isScalarStore(*I))
+ SeenDCacheWB = false;
+
+ // FIXME: It would be better to insert this before a waitcnt if any.
+ if ((I->getOpcode() == AMDGPU::S_ENDPGM ||
+ I->getOpcode() == AMDGPU::SI_RETURN) && !SeenDCacheWB) {
+ Changes = true;
+ BuildMI(*MBB, I, I->getDebugLoc(), TII->get(AMDGPU::S_DCACHE_WB));
+ }
+ }
+ }
+ }
+
for (MachineInstr *I : RemoveMI)
I->eraseFromParent();
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrFormats.td b/contrib/llvm/lib/Target/AMDGPU/SIInstrFormats.td
index 6163f05..5523ec1 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIInstrFormats.td
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrFormats.td
@@ -15,78 +15,111 @@ class InstSI <dag outs, dag ins, string asm = "",
list<dag> pattern = []> :
AMDGPUInst<outs, ins, asm, pattern>, PredicateControl {
- field bits<1> VM_CNT = 0;
- field bits<1> EXP_CNT = 0;
- field bits<1> LGKM_CNT = 0;
-
- field bits<1> SALU = 0;
- field bits<1> VALU = 0;
-
- field bits<1> SOP1 = 0;
- field bits<1> SOP2 = 0;
- field bits<1> SOPC = 0;
- field bits<1> SOPK = 0;
- field bits<1> SOPP = 0;
-
- field bits<1> VOP1 = 0;
- field bits<1> VOP2 = 0;
- field bits<1> VOP3 = 0;
- field bits<1> VOPC = 0;
- field bits<1> SDWA = 0;
- field bits<1> DPP = 0;
-
- field bits<1> MUBUF = 0;
- field bits<1> MTBUF = 0;
- field bits<1> SMRD = 0;
- field bits<1> DS = 0;
- field bits<1> MIMG = 0;
- field bits<1> FLAT = 0;
+ // Low bits - basic encoding information.
+ field bit SALU = 0;
+ field bit VALU = 0;
+
+ // SALU instruction formats.
+ field bit SOP1 = 0;
+ field bit SOP2 = 0;
+ field bit SOPC = 0;
+ field bit SOPK = 0;
+ field bit SOPP = 0;
+
+ // VALU instruction formats.
+ field bit VOP1 = 0;
+ field bit VOP2 = 0;
+ field bit VOPC = 0;
+ field bit VOP3 = 0;
+ field bit VINTRP = 0;
+ field bit SDWA = 0;
+ field bit DPP = 0;
+
+ // Memory instruction formats.
+ field bit MUBUF = 0;
+ field bit MTBUF = 0;
+ field bit SMRD = 0;
+ field bit MIMG = 0;
+ field bit EXP = 0;
+ field bit FLAT = 0;
+ field bit DS = 0;
+
+ // Pseudo instruction formats.
+ field bit VGPRSpill = 0;
+ field bit SGPRSpill = 0;
+
+ // High bits - other information.
+ field bit VM_CNT = 0;
+ field bit EXP_CNT = 0;
+ field bit LGKM_CNT = 0;
// Whether WQM _must_ be enabled for this instruction.
- field bits<1> WQM = 0;
- field bits<1> VGPRSpill = 0;
+ field bit WQM = 0;
+
+ // Whether WQM _must_ be disabled for this instruction.
+ field bit DisableWQM = 0;
+
+ field bit Gather4 = 0;
+
+ // Most sopk treat the immediate as a signed 16-bit, however some
+ // use it as unsigned.
+ field bit SOPKZext = 0;
+
+ // This is an s_store_dword* instruction that requires a cache flush
+ // on wave termination. It is necessary to distinguish from mayStore
+ // SMEM instructions like the cache flush ones.
+ field bit ScalarStore = 0;
+
+ // Whether the operands can be ignored when computing the
+ // instruction size.
+ field bit FixedSize = 0;
// This bit tells the assembler to use the 32-bit encoding in case it
// is unable to infer the encoding from the operands.
- field bits<1> VOPAsmPrefer32Bit = 0;
+ field bit VOPAsmPrefer32Bit = 0;
- field bits<1> Gather4 = 0;
+ // These need to be kept in sync with the enum in SIInstrFlags.
+ let TSFlags{0} = SALU;
+ let TSFlags{1} = VALU;
- // Whether WQM _must_ be disabled for this instruction.
- field bits<1> DisableWQM = 0;
+ let TSFlags{2} = SOP1;
+ let TSFlags{3} = SOP2;
+ let TSFlags{4} = SOPC;
+ let TSFlags{5} = SOPK;
+ let TSFlags{6} = SOPP;
- // These need to be kept in sync with the enum in SIInstrFlags.
- let TSFlags{0} = VM_CNT;
- let TSFlags{1} = EXP_CNT;
- let TSFlags{2} = LGKM_CNT;
-
- let TSFlags{3} = SALU;
- let TSFlags{4} = VALU;
-
- let TSFlags{5} = SOP1;
- let TSFlags{6} = SOP2;
- let TSFlags{7} = SOPC;
- let TSFlags{8} = SOPK;
- let TSFlags{9} = SOPP;
-
- let TSFlags{10} = VOP1;
- let TSFlags{11} = VOP2;
- let TSFlags{12} = VOP3;
- let TSFlags{13} = VOPC;
+ let TSFlags{7} = VOP1;
+ let TSFlags{8} = VOP2;
+ let TSFlags{9} = VOPC;
+ let TSFlags{10} = VOP3;
+
+ let TSFlags{13} = VINTRP;
let TSFlags{14} = SDWA;
let TSFlags{15} = DPP;
let TSFlags{16} = MUBUF;
let TSFlags{17} = MTBUF;
let TSFlags{18} = SMRD;
- let TSFlags{19} = DS;
- let TSFlags{20} = MIMG;
+ let TSFlags{19} = MIMG;
+ let TSFlags{20} = EXP;
let TSFlags{21} = FLAT;
- let TSFlags{22} = WQM;
+ let TSFlags{22} = DS;
+
let TSFlags{23} = VGPRSpill;
- let TSFlags{24} = VOPAsmPrefer32Bit;
- let TSFlags{25} = Gather4;
- let TSFlags{26} = DisableWQM;
+ let TSFlags{24} = SGPRSpill;
+
+ let TSFlags{32} = VM_CNT;
+ let TSFlags{33} = EXP_CNT;
+ let TSFlags{34} = LGKM_CNT;
+
+ let TSFlags{35} = WQM;
+ let TSFlags{36} = DisableWQM;
+ let TSFlags{37} = Gather4;
+
+ let TSFlags{38} = SOPKZext;
+ let TSFlags{39} = ScalarStore;
+ let TSFlags{40} = FixedSize;
+ let TSFlags{41} = VOPAsmPrefer32Bit;
let SchedRW = [Write32Bit];
@@ -95,6 +128,7 @@ class InstSI <dag outs, dag ins, string asm = "",
field bits<1> DisableDecoder = 0;
let isAsmParserOnly = !if(!eq(DisableDecoder{0}, {0}), 0, 1);
+ let AsmVariantName = AMDGPUAsmVariants.Default;
}
class PseudoInstSI<dag outs, dag ins, list<dag> pattern = []>
@@ -103,376 +137,39 @@ class PseudoInstSI<dag outs, dag ins, list<dag> pattern = []>
let isCodeGenOnly = 1;
}
-class Enc32 {
- field bits<32> Inst;
- int Size = 4;
-}
-
-class Enc64 {
- field bits<64> Inst;
- int Size = 8;
-}
-
-class VOPDstOperand <RegisterClass rc> : RegisterOperand <rc, "printVOPDst">;
-
-let Uses = [EXEC] in {
-
-class VOPAnyCommon <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI <outs, ins, asm, pattern> {
-
- let mayLoad = 0;
- let mayStore = 0;
- let hasSideEffects = 0;
- let UseNamedOperandTable = 1;
- let VALU = 1;
-}
-
-class VOPCCommon <dag ins, string asm, list<dag> pattern> :
- VOPAnyCommon <(outs), ins, asm, pattern> {
-
- let VOPC = 1;
- let Size = 4;
- let Defs = [VCC];
-}
-
-class VOP1Common <dag outs, dag ins, string asm, list<dag> pattern> :
- VOPAnyCommon <outs, ins, asm, pattern> {
-
- let VOP1 = 1;
- let Size = 4;
-}
-
-class VOP2Common <dag outs, dag ins, string asm, list<dag> pattern> :
- VOPAnyCommon <outs, ins, asm, pattern> {
-
- let VOP2 = 1;
- let Size = 4;
-}
-
-class VOP3Common <dag outs, dag ins, string asm = "",
- list<dag> pattern = [], bit HasMods = 0,
- bit VOP3Only = 0> :
- VOPAnyCommon <outs, ins, asm, pattern> {
-
- // Using complex patterns gives VOP3 patterns a very high complexity rating,
- // but standalone patterns are almost always prefered, so we need to adjust the
- // priority lower. The goal is to use a high number to reduce complexity to
- // zero (or less than zero).
- let AddedComplexity = -1000;
-
- let VOP3 = 1;
- let VALU = 1;
-
- let AsmMatchConverter =
- !if(!eq(VOP3Only,1),
- "cvtVOP3",
- !if(!eq(HasMods,1), "cvtVOP3_2_mod", ""));
-
- let isCodeGenOnly = 0;
-
- int Size = 8;
-
- // Because SGPRs may be allowed if there are multiple operands, we
- // need a post-isel hook to insert copies in order to avoid
- // violating constant bus requirements.
- let hasPostISelHook = 1;
-}
-
-} // End Uses = [EXEC]
-
-//===----------------------------------------------------------------------===//
-// Scalar operations
-//===----------------------------------------------------------------------===//
-
-class SOP1e <bits<8> op> : Enc32 {
- bits<7> sdst;
- bits<8> src0;
-
- let Inst{7-0} = src0;
- let Inst{15-8} = op;
- let Inst{22-16} = sdst;
- let Inst{31-23} = 0x17d; //encoding;
-}
-
-class SOP2e <bits<7> op> : Enc32 {
- bits<7> sdst;
- bits<8> src0;
- bits<8> src1;
-
- let Inst{7-0} = src0;
- let Inst{15-8} = src1;
- let Inst{22-16} = sdst;
- let Inst{29-23} = op;
- let Inst{31-30} = 0x2; // encoding
-}
-
-class SOPCe <bits<7> op> : Enc32 {
- bits<8> src0;
- bits<8> src1;
-
- let Inst{7-0} = src0;
- let Inst{15-8} = src1;
- let Inst{22-16} = op;
- let Inst{31-23} = 0x17e;
-}
-
-class SOPKe <bits<5> op> : Enc32 {
- bits <7> sdst;
- bits <16> simm16;
-
- let Inst{15-0} = simm16;
- let Inst{22-16} = sdst;
- let Inst{27-23} = op;
- let Inst{31-28} = 0xb; //encoding
-}
-
-class SOPK64e <bits<5> op> : Enc64 {
- bits <7> sdst = 0;
- bits <16> simm16;
- bits <32> imm;
-
- let Inst{15-0} = simm16;
- let Inst{22-16} = sdst;
- let Inst{27-23} = op;
- let Inst{31-28} = 0xb;
-
- let Inst{63-32} = imm;
-}
-
-class SOPPe <bits<7> op> : Enc32 {
- bits <16> simm16;
-
- let Inst{15-0} = simm16;
- let Inst{22-16} = op;
- let Inst{31-23} = 0x17f; // encoding
-}
-
-class SMRDe <bits<5> op, bits<1> imm> : Enc32 {
- bits<7> sdst;
- bits<7> sbase;
-
- let Inst{8} = imm;
- let Inst{14-9} = sbase{6-1};
- let Inst{21-15} = sdst;
- let Inst{26-22} = op;
- let Inst{31-27} = 0x18; //encoding
-}
-
-class SMRD_IMMe <bits<5> op> : SMRDe<op, 1> {
- bits<8> offset;
- let Inst{7-0} = offset;
-}
-
-class SMRD_SOFFe <bits<5> op> : SMRDe<op, 0> {
- bits<8> soff;
- let Inst{7-0} = soff;
-}
-
-
-
-class SMRD_IMMe_ci <bits<5> op> : Enc64 {
- bits<7> sdst;
- bits<7> sbase;
- bits<32> offset;
-
- let Inst{7-0} = 0xff;
- let Inst{8} = 0;
- let Inst{14-9} = sbase{6-1};
- let Inst{21-15} = sdst;
- let Inst{26-22} = op;
- let Inst{31-27} = 0x18; //encoding
- let Inst{63-32} = offset;
-}
-
-let SchedRW = [WriteSALU] in {
-class SOP1 <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI<outs, ins, asm, pattern> {
- let mayLoad = 0;
- let mayStore = 0;
- let hasSideEffects = 0;
- let isCodeGenOnly = 0;
- let SALU = 1;
- let SOP1 = 1;
-}
-
-class SOP2 <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI <outs, ins, asm, pattern> {
-
- let mayLoad = 0;
- let mayStore = 0;
- let hasSideEffects = 0;
- let isCodeGenOnly = 0;
- let SALU = 1;
- let SOP2 = 1;
-
- let UseNamedOperandTable = 1;
-}
-
-class SOPC <bits<7> op, dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI<outs, ins, asm, pattern>, SOPCe <op> {
-
- let mayLoad = 0;
- let mayStore = 0;
- let hasSideEffects = 0;
+class SPseudoInstSI<dag outs, dag ins, list<dag> pattern = []>
+ : PseudoInstSI<outs, ins, pattern> {
let SALU = 1;
- let SOPC = 1;
- let isCodeGenOnly = 0;
- let Defs = [SCC];
-
- let UseNamedOperandTable = 1;
}
-class SOPK <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI <outs, ins , asm, pattern> {
-
- let mayLoad = 0;
- let mayStore = 0;
- let hasSideEffects = 0;
- let SALU = 1;
- let SOPK = 1;
-
- let UseNamedOperandTable = 1;
+class VPseudoInstSI<dag outs, dag ins, list<dag> pattern = []>
+ : PseudoInstSI<outs, ins, pattern> {
+ let VALU = 1;
+ let Uses = [EXEC];
}
-class SOPP <bits<7> op, dag ins, string asm, list<dag> pattern = []> :
- InstSI <(outs), ins, asm, pattern >, SOPPe <op> {
+class CFPseudoInstSI<dag outs, dag ins, list<dag> pattern = [],
+ bit UseExec = 0, bit DefExec = 0> :
+ SPseudoInstSI<outs, ins, pattern> {
+ let Uses = !if(UseExec, [EXEC], []);
+ let Defs = !if(DefExec, [EXEC, SCC], [SCC]);
let mayLoad = 0;
let mayStore = 0;
let hasSideEffects = 0;
- let SALU = 1;
- let SOPP = 1;
-
- let UseNamedOperandTable = 1;
-}
-
-} // let SchedRW = [WriteSALU]
-
-class SMRD <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI<outs, ins, asm, pattern> {
-
- let LGKM_CNT = 1;
- let SMRD = 1;
- let mayStore = 0;
- let mayLoad = 1;
- let hasSideEffects = 0;
- let UseNamedOperandTable = 1;
- let SchedRW = [WriteSMEM];
-}
-
-//===----------------------------------------------------------------------===//
-// Vector ALU operations
-//===----------------------------------------------------------------------===//
-
-class VOP1e <bits<8> op> : Enc32 {
- bits<8> vdst;
- bits<9> src0;
-
- let Inst{8-0} = src0;
- let Inst{16-9} = op;
- let Inst{24-17} = vdst;
- let Inst{31-25} = 0x3f; //encoding
-}
-
-class VOP2e <bits<6> op> : Enc32 {
- bits<8> vdst;
- bits<9> src0;
- bits<8> src1;
-
- let Inst{8-0} = src0;
- let Inst{16-9} = src1;
- let Inst{24-17} = vdst;
- let Inst{30-25} = op;
- let Inst{31} = 0x0; //encoding
-}
-
-class VOP2_MADKe <bits<6> op> : Enc64 {
-
- bits<8> vdst;
- bits<9> src0;
- bits<8> src1;
- bits<32> imm;
-
- let Inst{8-0} = src0;
- let Inst{16-9} = src1;
- let Inst{24-17} = vdst;
- let Inst{30-25} = op;
- let Inst{31} = 0x0; // encoding
- let Inst{63-32} = imm;
-}
-
-class VOP3a <bits<9> op> : Enc64 {
- bits<2> src0_modifiers;
- bits<9> src0;
- bits<2> src1_modifiers;
- bits<9> src1;
- bits<2> src2_modifiers;
- bits<9> src2;
- bits<1> clamp;
- bits<2> omod;
-
- let Inst{8} = src0_modifiers{1};
- let Inst{9} = src1_modifiers{1};
- let Inst{10} = src2_modifiers{1};
- let Inst{11} = clamp;
- let Inst{25-17} = op;
- let Inst{31-26} = 0x34; //encoding
- let Inst{40-32} = src0;
- let Inst{49-41} = src1;
- let Inst{58-50} = src2;
- let Inst{60-59} = omod;
- let Inst{61} = src0_modifiers{0};
- let Inst{62} = src1_modifiers{0};
- let Inst{63} = src2_modifiers{0};
-}
-
-class VOP3e <bits<9> op> : VOP3a <op> {
- bits<8> vdst;
-
- let Inst{7-0} = vdst;
}
-// Encoding used for VOPC instructions encoded as VOP3
-// Differs from VOP3e by destination name (sdst) as VOPC doesn't have vector dst
-class VOP3ce <bits<9> op> : VOP3a <op> {
- bits<8> sdst;
-
- let Inst{7-0} = sdst;
+class Enc32 {
+ field bits<32> Inst;
+ int Size = 4;
}
-class VOP3be <bits<9> op> : Enc64 {
- bits<8> vdst;
- bits<2> src0_modifiers;
- bits<9> src0;
- bits<2> src1_modifiers;
- bits<9> src1;
- bits<2> src2_modifiers;
- bits<9> src2;
- bits<7> sdst;
- bits<2> omod;
-
- let Inst{7-0} = vdst;
- let Inst{14-8} = sdst;
- let Inst{25-17} = op;
- let Inst{31-26} = 0x34; //encoding
- let Inst{40-32} = src0;
- let Inst{49-41} = src1;
- let Inst{58-50} = src2;
- let Inst{60-59} = omod;
- let Inst{61} = src0_modifiers{0};
- let Inst{62} = src1_modifiers{0};
- let Inst{63} = src2_modifiers{0};
+class Enc64 {
+ field bits<64> Inst;
+ int Size = 8;
}
-class VOPCe <bits<8> op> : Enc32 {
- bits<9> src0;
- bits<8> src1;
-
- let Inst{8-0} = src0;
- let Inst{16-9} = src1;
- let Inst{24-17} = op;
- let Inst{31-25} = 0x3e;
-}
+class VOPDstOperand <RegisterClass rc> : RegisterOperand <rc, "printVOPDst">;
class VINTRPe <bits<2> op> : Enc32 {
bits<8> vdst;
@@ -488,88 +185,6 @@ class VINTRPe <bits<2> op> : Enc32 {
let Inst{31-26} = 0x32; // encoding
}
-class DSe <bits<8> op> : Enc64 {
- bits<8> vdst;
- bits<1> gds;
- bits<8> addr;
- bits<8> data0;
- bits<8> data1;
- bits<8> offset0;
- bits<8> offset1;
-
- let Inst{7-0} = offset0;
- let Inst{15-8} = offset1;
- let Inst{17} = gds;
- let Inst{25-18} = op;
- let Inst{31-26} = 0x36; //encoding
- let Inst{39-32} = addr;
- let Inst{47-40} = data0;
- let Inst{55-48} = data1;
- let Inst{63-56} = vdst;
-}
-
-class MUBUFe <bits<7> op> : Enc64 {
- bits<12> offset;
- bits<1> offen;
- bits<1> idxen;
- bits<1> glc;
- bits<1> addr64;
- bits<1> lds;
- bits<8> vaddr;
- bits<8> vdata;
- bits<7> srsrc;
- bits<1> slc;
- bits<1> tfe;
- bits<8> soffset;
-
- let Inst{11-0} = offset;
- let Inst{12} = offen;
- let Inst{13} = idxen;
- let Inst{14} = glc;
- let Inst{15} = addr64;
- let Inst{16} = lds;
- let Inst{24-18} = op;
- let Inst{31-26} = 0x38; //encoding
- let Inst{39-32} = vaddr;
- let Inst{47-40} = vdata;
- let Inst{52-48} = srsrc{6-2};
- let Inst{54} = slc;
- let Inst{55} = tfe;
- let Inst{63-56} = soffset;
-}
-
-class MTBUFe <bits<3> op> : Enc64 {
- bits<8> vdata;
- bits<12> offset;
- bits<1> offen;
- bits<1> idxen;
- bits<1> glc;
- bits<1> addr64;
- bits<4> dfmt;
- bits<3> nfmt;
- bits<8> vaddr;
- bits<7> srsrc;
- bits<1> slc;
- bits<1> tfe;
- bits<8> soffset;
-
- let Inst{11-0} = offset;
- let Inst{12} = offen;
- let Inst{13} = idxen;
- let Inst{14} = glc;
- let Inst{15} = addr64;
- let Inst{18-16} = op;
- let Inst{22-19} = dfmt;
- let Inst{25-23} = nfmt;
- let Inst{31-26} = 0x3a; //encoding
- let Inst{39-32} = vaddr;
- let Inst{47-40} = vdata;
- let Inst{52-48} = srsrc{6-2};
- let Inst{54} = slc;
- let Inst{55} = tfe;
- let Inst{63-56} = soffset;
-}
-
class MIMGe <bits<7> op> : Enc64 {
bits<8> vdata;
bits<4> dmask;
@@ -600,26 +215,6 @@ class MIMGe <bits<7> op> : Enc64 {
let Inst{57-53} = ssamp{6-2};
}
-class FLATe<bits<7> op> : Enc64 {
- bits<8> addr;
- bits<8> data;
- bits<8> vdst;
- bits<1> slc;
- bits<1> glc;
- bits<1> tfe;
-
- // 15-0 is reserved.
- let Inst{16} = glc;
- let Inst{17} = slc;
- let Inst{24-18} = op;
- let Inst{31-26} = 0x37; // Encoding.
- let Inst{39-32} = addr;
- let Inst{47-40} = data;
- // 54-48 is reserved.
- let Inst{55} = tfe;
- let Inst{63-56} = vdst;
-}
-
class EXPe : Enc64 {
bits<4> en;
bits<6> tgt;
@@ -645,92 +240,37 @@ class EXPe : Enc64 {
let Uses = [EXEC] in {
-class VOP1 <bits<8> op, dag outs, dag ins, string asm, list<dag> pattern> :
- VOP1Common <outs, ins, asm, pattern>,
- VOP1e<op> {
- let isCodeGenOnly = 0;
-}
-
-class VOP2 <bits<6> op, dag outs, dag ins, string asm, list<dag> pattern> :
- VOP2Common <outs, ins, asm, pattern>, VOP2e<op> {
- let isCodeGenOnly = 0;
-}
-
-class VOPC <bits<8> op, dag ins, string asm, list<dag> pattern> :
- VOPCCommon <ins, asm, pattern>, VOPCe <op>;
-
class VINTRPCommon <dag outs, dag ins, string asm, list<dag> pattern> :
InstSI <outs, ins, asm, pattern> {
- let mayLoad = 1;
+ let VINTRP = 1;
+ // VINTRP instructions read parameter values from LDS, but these parameter
+ // values are stored outside of the LDS memory that is allocated to the
+ // shader for general purpose use.
+ //
+ // While it may be possible for ds_read/ds_write instructions to access
+ // the parameter values in LDS, this would essentially be an out-of-bounds
+ // memory access which we consider to be undefined behavior.
+ //
+ // So even though these instructions read memory, this memory is outside the
+ // addressable memory space for the shader, and we consider these instructions
+ // to be readnone.
+ let mayLoad = 0;
let mayStore = 0;
let hasSideEffects = 0;
}
-} // End Uses = [EXEC]
-
-//===----------------------------------------------------------------------===//
-// Vector I/O operations
-//===----------------------------------------------------------------------===//
-
-class DS <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI <outs, ins, asm, pattern> {
-
- let LGKM_CNT = 1;
- let DS = 1;
- let UseNamedOperandTable = 1;
- let Uses = [M0, EXEC];
-
- // Most instruction load and store data, so set this as the default.
- let mayLoad = 1;
- let mayStore = 1;
-
- let hasSideEffects = 0;
- let AsmMatchConverter = "cvtDS";
- let SchedRW = [WriteLDS];
-}
-
-class MUBUF <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI<outs, ins, asm, pattern> {
-
- let VM_CNT = 1;
+class EXPCommon<dag outs, dag ins, string asm, list<dag> pattern> :
+ InstSI<outs, ins, asm, pattern> {
+ let EXP = 1;
let EXP_CNT = 1;
- let MUBUF = 1;
- let Uses = [EXEC];
-
- let hasSideEffects = 0;
+ let mayLoad = 0; // Set to 1 if done bit is set.
+ let mayStore = 1;
let UseNamedOperandTable = 1;
- let AsmMatchConverter = "cvtMubuf";
- let SchedRW = [WriteVMEM];
-}
-
-class MTBUF <dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI<outs, ins, asm, pattern> {
-
- let VM_CNT = 1;
- let EXP_CNT = 1;
- let MTBUF = 1;
let Uses = [EXEC];
-
- let hasSideEffects = 0;
- let UseNamedOperandTable = 1;
- let SchedRW = [WriteVMEM];
+ let SchedRW = [WriteExport];
}
-class FLAT <bits<7> op, dag outs, dag ins, string asm, list<dag> pattern> :
- InstSI<outs, ins, asm, pattern>, FLATe <op> {
- let FLAT = 1;
- // Internally, FLAT instruction are executed as both an LDS and a
- // Buffer instruction; so, they increment both VM_CNT and LGKM_CNT
- // and are not considered done until both have been decremented.
- let VM_CNT = 1;
- let LGKM_CNT = 1;
-
- let Uses = [EXEC, FLAT_SCR]; // M0
-
- let UseNamedOperandTable = 1;
- let hasSideEffects = 0;
- let SchedRW = [WriteVMEM];
-}
+} // End Uses = [EXEC]
class MIMG <dag outs, dag ins, string asm, list<dag> pattern> :
InstSI <outs, ins, asm, pattern> {
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
index 9190819..26a8d22 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
@@ -28,6 +28,13 @@
using namespace llvm;
+// Must be at least 4 to be able to branch over minimum unconditional branch
+// code. This is only for making it possible to write reasonably small tests for
+// long branches.
+static cl::opt<unsigned>
+BranchOffsetBits("amdgpu-s-branch-bits", cl::ReallyHidden, cl::init(16),
+ cl::desc("Restrict range of branch instructions (DEBUG)"));
+
SIInstrInfo::SIInstrInfo(const SISubtarget &ST)
: AMDGPUInstrInfo(ST), RI(), ST(ST) {}
@@ -258,7 +265,8 @@ bool SIInstrInfo::getMemOpBaseRegImmOfs(MachineInstr &LdSt, unsigned &BaseReg,
}
if (isMUBUF(LdSt) || isMTBUF(LdSt)) {
- if (AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::soffset) != -1)
+ const MachineOperand *SOffset = getNamedOperand(LdSt, AMDGPU::OpName::soffset);
+ if (SOffset && SOffset->isReg())
return false;
const MachineOperand *AddrReg =
@@ -270,6 +278,10 @@ bool SIInstrInfo::getMemOpBaseRegImmOfs(MachineInstr &LdSt, unsigned &BaseReg,
getNamedOperand(LdSt, AMDGPU::OpName::offset);
BaseReg = AddrReg->getReg();
Offset = OffsetImm->getImm();
+
+ if (SOffset) // soffset can be an inline immediate.
+ Offset += SOffset->getImm();
+
return true;
}
@@ -287,7 +299,7 @@ bool SIInstrInfo::getMemOpBaseRegImmOfs(MachineInstr &LdSt, unsigned &BaseReg,
}
if (isFLAT(LdSt)) {
- const MachineOperand *AddrReg = getNamedOperand(LdSt, AMDGPU::OpName::addr);
+ const MachineOperand *AddrReg = getNamedOperand(LdSt, AMDGPU::OpName::vaddr);
BaseReg = AddrReg->getReg();
Offset = 0;
return true;
@@ -302,20 +314,16 @@ bool SIInstrInfo::shouldClusterMemOps(MachineInstr &FirstLdSt,
const MachineOperand *FirstDst = nullptr;
const MachineOperand *SecondDst = nullptr;
- if (isDS(FirstLdSt) && isDS(SecondLdSt)) {
- FirstDst = getNamedOperand(FirstLdSt, AMDGPU::OpName::vdst);
- SecondDst = getNamedOperand(SecondLdSt, AMDGPU::OpName::vdst);
- }
-
- if (isSMRD(FirstLdSt) && isSMRD(SecondLdSt)) {
- FirstDst = getNamedOperand(FirstLdSt, AMDGPU::OpName::sdst);
- SecondDst = getNamedOperand(SecondLdSt, AMDGPU::OpName::sdst);
- }
-
if ((isMUBUF(FirstLdSt) && isMUBUF(SecondLdSt)) ||
(isMTBUF(FirstLdSt) && isMTBUF(SecondLdSt))) {
FirstDst = getNamedOperand(FirstLdSt, AMDGPU::OpName::vdata);
SecondDst = getNamedOperand(SecondLdSt, AMDGPU::OpName::vdata);
+ } else if (isSMRD(FirstLdSt) && isSMRD(SecondLdSt)) {
+ FirstDst = getNamedOperand(FirstLdSt, AMDGPU::OpName::sdst);
+ SecondDst = getNamedOperand(SecondLdSt, AMDGPU::OpName::sdst);
+ } else if (isDS(FirstLdSt) && isDS(SecondLdSt)) {
+ FirstDst = getNamedOperand(FirstLdSt, AMDGPU::OpName::vdst);
+ SecondDst = getNamedOperand(SecondLdSt, AMDGPU::OpName::vdst);
}
if (!FirstDst || !SecondDst)
@@ -342,62 +350,32 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg,
unsigned SrcReg, bool KillSrc) const {
+ const TargetRegisterClass *RC = RI.getPhysRegClass(DestReg);
- // If we are trying to copy to or from SCC, there is a bug somewhere else in
- // the backend. While it may be theoretically possible to do this, it should
- // never be necessary.
- assert(DestReg != AMDGPU::SCC && SrcReg != AMDGPU::SCC);
-
- static const int16_t Sub0_15[] = {
- AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2, AMDGPU::sub3,
- AMDGPU::sub4, AMDGPU::sub5, AMDGPU::sub6, AMDGPU::sub7,
- AMDGPU::sub8, AMDGPU::sub9, AMDGPU::sub10, AMDGPU::sub11,
- AMDGPU::sub12, AMDGPU::sub13, AMDGPU::sub14, AMDGPU::sub15,
- };
-
- static const int16_t Sub0_15_64[] = {
- AMDGPU::sub0_sub1, AMDGPU::sub2_sub3,
- AMDGPU::sub4_sub5, AMDGPU::sub6_sub7,
- AMDGPU::sub8_sub9, AMDGPU::sub10_sub11,
- AMDGPU::sub12_sub13, AMDGPU::sub14_sub15,
- };
-
- static const int16_t Sub0_7[] = {
- AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2, AMDGPU::sub3,
- AMDGPU::sub4, AMDGPU::sub5, AMDGPU::sub6, AMDGPU::sub7,
- };
-
- static const int16_t Sub0_7_64[] = {
- AMDGPU::sub0_sub1, AMDGPU::sub2_sub3,
- AMDGPU::sub4_sub5, AMDGPU::sub6_sub7,
- };
-
- static const int16_t Sub0_3[] = {
- AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2, AMDGPU::sub3,
- };
-
- static const int16_t Sub0_3_64[] = {
- AMDGPU::sub0_sub1, AMDGPU::sub2_sub3,
- };
-
- static const int16_t Sub0_2[] = {
- AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2,
- };
-
- static const int16_t Sub0_1[] = {
- AMDGPU::sub0, AMDGPU::sub1,
- };
+ if (RC == &AMDGPU::VGPR_32RegClass) {
+ assert(AMDGPU::VGPR_32RegClass.contains(SrcReg) ||
+ AMDGPU::SReg_32RegClass.contains(SrcReg));
+ BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ return;
+ }
- unsigned Opcode;
- ArrayRef<int16_t> SubIndices;
+ if (RC == &AMDGPU::SReg_32_XM0RegClass ||
+ RC == &AMDGPU::SReg_32RegClass) {
+ if (SrcReg == AMDGPU::SCC) {
+ BuildMI(MBB, MI, DL, get(AMDGPU::S_CSELECT_B32), DestReg)
+ .addImm(-1)
+ .addImm(0);
+ return;
+ }
- if (AMDGPU::SReg_32RegClass.contains(DestReg)) {
assert(AMDGPU::SReg_32RegClass.contains(SrcReg));
BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B32), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
return;
+ }
- } else if (AMDGPU::SReg_64RegClass.contains(DestReg)) {
+ if (RC == &AMDGPU::SReg_64RegClass) {
if (DestReg == AMDGPU::VCC) {
if (AMDGPU::SReg_64RegClass.contains(SrcReg)) {
BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B64), AMDGPU::VCC)
@@ -405,7 +383,7 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
} else {
// FIXME: Hack until VReg_1 removed.
assert(AMDGPU::VGPR_32RegClass.contains(SrcReg));
- BuildMI(MBB, MI, DL, get(AMDGPU::V_CMP_NE_I32_e32))
+ BuildMI(MBB, MI, DL, get(AMDGPU::V_CMP_NE_U32_e32))
.addImm(0)
.addReg(SrcReg, getKillRegState(KillSrc));
}
@@ -417,62 +395,29 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
BuildMI(MBB, MI, DL, get(AMDGPU::S_MOV_B64), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
return;
+ }
- } else if (AMDGPU::SReg_128RegClass.contains(DestReg)) {
- assert(AMDGPU::SReg_128RegClass.contains(SrcReg));
- Opcode = AMDGPU::S_MOV_B64;
- SubIndices = Sub0_3_64;
-
- } else if (AMDGPU::SReg_256RegClass.contains(DestReg)) {
- assert(AMDGPU::SReg_256RegClass.contains(SrcReg));
- Opcode = AMDGPU::S_MOV_B64;
- SubIndices = Sub0_7_64;
-
- } else if (AMDGPU::SReg_512RegClass.contains(DestReg)) {
- assert(AMDGPU::SReg_512RegClass.contains(SrcReg));
- Opcode = AMDGPU::S_MOV_B64;
- SubIndices = Sub0_15_64;
-
- } else if (AMDGPU::VGPR_32RegClass.contains(DestReg)) {
- assert(AMDGPU::VGPR_32RegClass.contains(SrcReg) ||
- AMDGPU::SReg_32RegClass.contains(SrcReg));
- BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DestReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
+ if (DestReg == AMDGPU::SCC) {
+ assert(AMDGPU::SReg_32RegClass.contains(SrcReg));
+ BuildMI(MBB, MI, DL, get(AMDGPU::S_CMP_LG_U32))
+ .addReg(SrcReg, getKillRegState(KillSrc))
+ .addImm(0);
return;
+ }
- } else if (AMDGPU::VReg_64RegClass.contains(DestReg)) {
- assert(AMDGPU::VReg_64RegClass.contains(SrcReg) ||
- AMDGPU::SReg_64RegClass.contains(SrcReg));
- Opcode = AMDGPU::V_MOV_B32_e32;
- SubIndices = Sub0_1;
-
- } else if (AMDGPU::VReg_96RegClass.contains(DestReg)) {
- assert(AMDGPU::VReg_96RegClass.contains(SrcReg));
- Opcode = AMDGPU::V_MOV_B32_e32;
- SubIndices = Sub0_2;
-
- } else if (AMDGPU::VReg_128RegClass.contains(DestReg)) {
- assert(AMDGPU::VReg_128RegClass.contains(SrcReg) ||
- AMDGPU::SReg_128RegClass.contains(SrcReg));
- Opcode = AMDGPU::V_MOV_B32_e32;
- SubIndices = Sub0_3;
-
- } else if (AMDGPU::VReg_256RegClass.contains(DestReg)) {
- assert(AMDGPU::VReg_256RegClass.contains(SrcReg) ||
- AMDGPU::SReg_256RegClass.contains(SrcReg));
- Opcode = AMDGPU::V_MOV_B32_e32;
- SubIndices = Sub0_7;
-
- } else if (AMDGPU::VReg_512RegClass.contains(DestReg)) {
- assert(AMDGPU::VReg_512RegClass.contains(SrcReg) ||
- AMDGPU::SReg_512RegClass.contains(SrcReg));
- Opcode = AMDGPU::V_MOV_B32_e32;
- SubIndices = Sub0_15;
-
- } else {
- llvm_unreachable("Can't copy register!");
+ unsigned EltSize = 4;
+ unsigned Opcode = AMDGPU::V_MOV_B32_e32;
+ if (RI.isSGPRClass(RC)) {
+ if (RC->getSize() > 4) {
+ Opcode = AMDGPU::S_MOV_B64;
+ EltSize = 8;
+ } else {
+ Opcode = AMDGPU::S_MOV_B32;
+ EltSize = 4;
+ }
}
+ ArrayRef<int16_t> SubIndices = RI.getRegSplitParts(RC, EltSize);
bool Forward = RI.getHWRegIndex(DestReg) <= RI.getHWRegIndex(SrcReg);
for (unsigned Idx = 0; Idx < SubIndices.size(); ++Idx) {
@@ -497,9 +442,7 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
}
}
-int SIInstrInfo::commuteOpcode(const MachineInstr &MI) const {
- const unsigned Opcode = MI.getOpcode();
-
+int SIInstrInfo::commuteOpcode(unsigned Opcode) const {
int NewOpc;
// Try to map original to commuted opcode
@@ -573,11 +516,11 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
- MachineFrameInfo *FrameInfo = MF->getFrameInfo();
+ MachineFrameInfo &FrameInfo = MF->getFrameInfo();
DebugLoc DL = MBB.findDebugLoc(MI);
- unsigned Size = FrameInfo->getObjectSize(FrameIndex);
- unsigned Align = FrameInfo->getObjectAlignment(FrameIndex);
+ unsigned Size = FrameInfo.getObjectSize(FrameIndex);
+ unsigned Align = FrameInfo.getObjectAlignment(FrameIndex);
MachinePointerInfo PtrInfo
= MachinePointerInfo::getFixedStack(*MF, FrameIndex);
MachineMemOperand *MMO
@@ -587,20 +530,31 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
if (RI.isSGPRClass(RC)) {
MFI->setHasSpilledSGPRs();
+ // We are only allowed to create one new instruction when spilling
+ // registers, so we need to use pseudo instruction for spilling SGPRs.
+ const MCInstrDesc &OpDesc = get(getSGPRSpillSaveOpcode(RC->getSize()));
+
+ // The SGPR spill/restore instructions only work on number sgprs, so we need
+ // to make sure we are using the correct register class.
if (TargetRegisterInfo::isVirtualRegister(SrcReg) && RC->getSize() == 4) {
- // m0 may not be allowed for readlane.
MachineRegisterInfo &MRI = MF->getRegInfo();
MRI.constrainRegClass(SrcReg, &AMDGPU::SReg_32_XM0RegClass);
}
- // We are only allowed to create one new instruction when spilling
- // registers, so we need to use pseudo instruction for spilling
- // SGPRs.
- unsigned Opcode = getSGPRSpillSaveOpcode(RC->getSize());
- BuildMI(MBB, MI, DL, get(Opcode))
- .addReg(SrcReg, getKillRegState(isKill)) // src
- .addFrameIndex(FrameIndex) // frame_idx
- .addMemOperand(MMO);
+ MachineInstrBuilder Spill = BuildMI(MBB, MI, DL, OpDesc)
+ .addReg(SrcReg, getKillRegState(isKill)) // data
+ .addFrameIndex(FrameIndex) // addr
+ .addMemOperand(MMO)
+ .addReg(MFI->getScratchRSrcReg(), RegState::Implicit)
+ .addReg(MFI->getScratchWaveOffsetReg(), RegState::Implicit);
+ // Add the scratch resource registers as implicit uses because we may end up
+ // needing them, and need to ensure that the reserved registers are
+ // correctly handled.
+
+ if (ST.hasScalarStores()) {
+ // m0 is used for offset to scalar stores if used to spill.
+ Spill.addReg(AMDGPU::M0, RegState::ImplicitDefine);
+ }
return;
}
@@ -620,11 +574,11 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
unsigned Opcode = getVGPRSpillSaveOpcode(RC->getSize());
MFI->setHasSpilledVGPRs();
BuildMI(MBB, MI, DL, get(Opcode))
- .addReg(SrcReg, getKillRegState(isKill)) // src
- .addFrameIndex(FrameIndex) // frame_idx
- .addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
- .addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
- .addImm(0) // offset
+ .addReg(SrcReg, getKillRegState(isKill)) // data
+ .addFrameIndex(FrameIndex) // addr
+ .addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
+ .addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
+ .addImm(0) // offset
.addMemOperand(MMO);
}
@@ -671,10 +625,10 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
- MachineFrameInfo *FrameInfo = MF->getFrameInfo();
+ MachineFrameInfo &FrameInfo = MF->getFrameInfo();
DebugLoc DL = MBB.findDebugLoc(MI);
- unsigned Align = FrameInfo->getObjectAlignment(FrameIndex);
- unsigned Size = FrameInfo->getObjectSize(FrameIndex);
+ unsigned Align = FrameInfo.getObjectAlignment(FrameIndex);
+ unsigned Size = FrameInfo.getObjectSize(FrameIndex);
MachinePointerInfo PtrInfo
= MachinePointerInfo::getFixedStack(*MF, FrameIndex);
@@ -685,17 +639,22 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
if (RI.isSGPRClass(RC)) {
// FIXME: Maybe this should not include a memoperand because it will be
// lowered to non-memory instructions.
- unsigned Opcode = getSGPRSpillRestoreOpcode(RC->getSize());
-
+ const MCInstrDesc &OpDesc = get(getSGPRSpillRestoreOpcode(RC->getSize()));
if (TargetRegisterInfo::isVirtualRegister(DestReg) && RC->getSize() == 4) {
- // m0 may not be allowed for readlane.
MachineRegisterInfo &MRI = MF->getRegInfo();
MRI.constrainRegClass(DestReg, &AMDGPU::SReg_32_XM0RegClass);
}
- BuildMI(MBB, MI, DL, get(Opcode), DestReg)
- .addFrameIndex(FrameIndex) // frame_idx
- .addMemOperand(MMO);
+ MachineInstrBuilder Spill = BuildMI(MBB, MI, DL, OpDesc, DestReg)
+ .addFrameIndex(FrameIndex) // addr
+ .addMemOperand(MMO)
+ .addReg(MFI->getScratchRSrcReg(), RegState::Implicit)
+ .addReg(MFI->getScratchWaveOffsetReg(), RegState::Implicit);
+
+ if (ST.hasScalarStores()) {
+ // m0 is used for offset to scalar stores if used to spill.
+ Spill.addReg(AMDGPU::M0, RegState::ImplicitDefine);
+ }
return;
}
@@ -713,7 +672,7 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
unsigned Opcode = getVGPRSpillRestoreOpcode(RC->getSize());
BuildMI(MBB, MI, DL, get(Opcode), DestReg)
- .addFrameIndex(FrameIndex) // frame_idx
+ .addFrameIndex(FrameIndex) // vaddr
.addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
.addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
.addImm(0) // offset
@@ -729,7 +688,7 @@ unsigned SIInstrInfo::calculateLDSSpillAddress(
const SISubtarget &ST = MF->getSubtarget<SISubtarget>();
const SIRegisterInfo *TRI = ST.getRegisterInfo();
DebugLoc DL = MBB.findDebugLoc(MI);
- unsigned WorkGroupSize = MFI->getMaximumWorkGroupSize(*MF);
+ unsigned WorkGroupSize = MFI->getMaxFlatWorkGroupSize();
unsigned WavefrontSize = ST.getWavefrontSize();
unsigned TIDReg = MFI->getTIDReg();
@@ -808,7 +767,7 @@ unsigned SIInstrInfo::calculateLDSSpillAddress(
}
// Add FrameIndex to LDS offset
- unsigned LDSOffset = MFI->LDSSize + (FrameOffset * WorkGroupSize);
+ unsigned LDSOffset = MFI->getLDSSize() + (FrameOffset * WorkGroupSize);
BuildMI(MBB, MI, DL, get(AMDGPU::V_ADD_I32_e32), TmpReg)
.addImm(LDSOffset)
.addReg(TIDReg);
@@ -851,7 +810,24 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
DebugLoc DL = MBB.findDebugLoc(MI);
switch (MI.getOpcode()) {
default: return AMDGPUInstrInfo::expandPostRAPseudo(MI);
-
+ case AMDGPU::S_MOV_B64_term: {
+ // This is only a terminator to get the correct spill code placement during
+ // register allocation.
+ MI.setDesc(get(AMDGPU::S_MOV_B64));
+ break;
+ }
+ case AMDGPU::S_XOR_B64_term: {
+ // This is only a terminator to get the correct spill code placement during
+ // register allocation.
+ MI.setDesc(get(AMDGPU::S_XOR_B64));
+ break;
+ }
+ case AMDGPU::S_ANDN2_B64_term: {
+ // This is only a terminator to get the correct spill code placement during
+ // register allocation.
+ MI.setDesc(get(AMDGPU::S_ANDN2_B64));
+ break;
+ }
case AMDGPU::V_MOV_B64_PSEUDO: {
unsigned Dst = MI.getOperand(0).getReg();
unsigned DstLo = RI.getSubReg(Dst, AMDGPU::sub0);
@@ -880,36 +856,37 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MI.eraseFromParent();
break;
}
+ case AMDGPU::V_MOVRELD_B32_V1:
+ case AMDGPU::V_MOVRELD_B32_V2:
+ case AMDGPU::V_MOVRELD_B32_V4:
+ case AMDGPU::V_MOVRELD_B32_V8:
+ case AMDGPU::V_MOVRELD_B32_V16: {
+ const MCInstrDesc &MovRelDesc = get(AMDGPU::V_MOVRELD_B32_e32);
+ unsigned VecReg = MI.getOperand(0).getReg();
+ bool IsUndef = MI.getOperand(1).isUndef();
+ unsigned SubReg = AMDGPU::sub0 + MI.getOperand(3).getImm();
+ assert(VecReg == MI.getOperand(1).getReg());
+
+ MachineInstr *MovRel =
+ BuildMI(MBB, MI, DL, MovRelDesc)
+ .addReg(RI.getSubReg(VecReg, SubReg), RegState::Undef)
+ .addOperand(MI.getOperand(2))
+ .addReg(VecReg, RegState::ImplicitDefine)
+ .addReg(VecReg, RegState::Implicit | (IsUndef ? RegState::Undef : 0));
+
+ const int ImpDefIdx =
+ MovRelDesc.getNumOperands() + MovRelDesc.getNumImplicitUses();
+ const int ImpUseIdx = ImpDefIdx + 1;
+ MovRel->tieOperands(ImpDefIdx, ImpUseIdx);
- case AMDGPU::V_CNDMASK_B64_PSEUDO: {
- unsigned Dst = MI.getOperand(0).getReg();
- unsigned DstLo = RI.getSubReg(Dst, AMDGPU::sub0);
- unsigned DstHi = RI.getSubReg(Dst, AMDGPU::sub1);
- unsigned Src0 = MI.getOperand(1).getReg();
- unsigned Src1 = MI.getOperand(2).getReg();
- const MachineOperand &SrcCond = MI.getOperand(3);
-
- BuildMI(MBB, MI, DL, get(AMDGPU::V_CNDMASK_B32_e64), DstLo)
- .addReg(RI.getSubReg(Src0, AMDGPU::sub0))
- .addReg(RI.getSubReg(Src1, AMDGPU::sub0))
- .addReg(SrcCond.getReg())
- .addReg(Dst, RegState::Implicit | RegState::Define);
- BuildMI(MBB, MI, DL, get(AMDGPU::V_CNDMASK_B32_e64), DstHi)
- .addReg(RI.getSubReg(Src0, AMDGPU::sub1))
- .addReg(RI.getSubReg(Src1, AMDGPU::sub1))
- .addReg(SrcCond.getReg(), getKillRegState(SrcCond.isKill()))
- .addReg(Dst, RegState::Implicit | RegState::Define);
MI.eraseFromParent();
break;
}
-
case AMDGPU::SI_PC_ADD_REL_OFFSET: {
- const SIRegisterInfo *TRI
- = static_cast<const SIRegisterInfo *>(ST.getRegisterInfo());
MachineFunction &MF = *MBB.getParent();
unsigned Reg = MI.getOperand(0).getReg();
- unsigned RegLo = TRI->getSubReg(Reg, AMDGPU::sub0);
- unsigned RegHi = TRI->getSubReg(Reg, AMDGPU::sub1);
+ unsigned RegLo = RI.getSubReg(Reg, AMDGPU::sub0);
+ unsigned RegHi = RI.getSubReg(Reg, AMDGPU::sub1);
// Create a bundle so these instructions won't be re-ordered by the
// post-RA scheduler.
@@ -921,10 +898,15 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
Bundler.append(BuildMI(MF, DL, get(AMDGPU::S_ADD_U32), RegLo)
.addReg(RegLo)
.addOperand(MI.getOperand(1)));
- Bundler.append(BuildMI(MF, DL, get(AMDGPU::S_ADDC_U32), RegHi)
- .addReg(RegHi)
- .addImm(0));
+ MachineInstrBuilder MIB = BuildMI(MF, DL, get(AMDGPU::S_ADDC_U32), RegHi)
+ .addReg(RegHi);
+ if (MI.getOperand(2).getTargetFlags() == SIInstrInfo::MO_NONE)
+ MIB.addImm(0);
+ else
+ MIB.addOperand(MI.getOperand(2));
+
+ Bundler.append(MIB);
llvm::finalizeBundle(MBB, Bundler.begin());
MI.eraseFromParent();
@@ -934,91 +916,96 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
return true;
}
-/// Commutes the operands in the given instruction.
-/// The commutable operands are specified by their indices OpIdx0 and OpIdx1.
-///
-/// Do not call this method for a non-commutable instruction or for
-/// non-commutable pair of operand indices OpIdx0 and OpIdx1.
-/// Even though the instruction is commutable, the method may still
-/// fail to commute the operands, null pointer is returned in such cases.
-MachineInstr *SIInstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
- unsigned OpIdx0,
- unsigned OpIdx1) const {
- int CommutedOpcode = commuteOpcode(MI);
- if (CommutedOpcode == -1)
- return nullptr;
+bool SIInstrInfo::swapSourceModifiers(MachineInstr &MI,
+ MachineOperand &Src0,
+ unsigned Src0OpName,
+ MachineOperand &Src1,
+ unsigned Src1OpName) const {
+ MachineOperand *Src0Mods = getNamedOperand(MI, Src0OpName);
+ if (!Src0Mods)
+ return false;
- int Src0Idx =
- AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
- MachineOperand &Src0 = MI.getOperand(Src0Idx);
- if (!Src0.isReg())
+ MachineOperand *Src1Mods = getNamedOperand(MI, Src1OpName);
+ assert(Src1Mods &&
+ "All commutable instructions have both src0 and src1 modifiers");
+
+ int Src0ModsVal = Src0Mods->getImm();
+ int Src1ModsVal = Src1Mods->getImm();
+
+ Src1Mods->setImm(Src0ModsVal);
+ Src0Mods->setImm(Src1ModsVal);
+ return true;
+}
+
+static MachineInstr *swapRegAndNonRegOperand(MachineInstr &MI,
+ MachineOperand &RegOp,
+ MachineOperand &NonRegOp) {
+ unsigned Reg = RegOp.getReg();
+ unsigned SubReg = RegOp.getSubReg();
+ bool IsKill = RegOp.isKill();
+ bool IsDead = RegOp.isDead();
+ bool IsUndef = RegOp.isUndef();
+ bool IsDebug = RegOp.isDebug();
+
+ if (NonRegOp.isImm())
+ RegOp.ChangeToImmediate(NonRegOp.getImm());
+ else if (NonRegOp.isFI())
+ RegOp.ChangeToFrameIndex(NonRegOp.getIndex());
+ else
return nullptr;
- int Src1Idx =
- AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src1);
+ NonRegOp.ChangeToRegister(Reg, false, false, IsKill, IsDead, IsUndef, IsDebug);
+ NonRegOp.setSubReg(SubReg);
- if ((OpIdx0 != static_cast<unsigned>(Src0Idx) ||
- OpIdx1 != static_cast<unsigned>(Src1Idx)) &&
- (OpIdx0 != static_cast<unsigned>(Src1Idx) ||
- OpIdx1 != static_cast<unsigned>(Src0Idx)))
+ return &MI;
+}
+
+MachineInstr *SIInstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
+ unsigned Src0Idx,
+ unsigned Src1Idx) const {
+ assert(!NewMI && "this should never be used");
+
+ unsigned Opc = MI.getOpcode();
+ int CommutedOpcode = commuteOpcode(Opc);
+ if (CommutedOpcode == -1)
return nullptr;
- MachineOperand &Src1 = MI.getOperand(Src1Idx);
+ assert(AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0) ==
+ static_cast<int>(Src0Idx) &&
+ AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1) ==
+ static_cast<int>(Src1Idx) &&
+ "inconsistency with findCommutedOpIndices");
- if (isVOP2(MI) || isVOPC(MI)) {
- const MCInstrDesc &InstrDesc = MI.getDesc();
- // For VOP2 and VOPC instructions, any operand type is valid to use for
- // src0. Make sure we can use the src0 as src1.
- //
- // We could be stricter here and only allow commuting if there is a reason
- // to do so. i.e. if both operands are VGPRs there is no real benefit,
- // although MachineCSE attempts to find matches by commuting.
- const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
- if (!isLegalRegOperand(MRI, InstrDesc.OpInfo[Src1Idx], Src0))
- return nullptr;
- }
+ MachineOperand &Src0 = MI.getOperand(Src0Idx);
+ MachineOperand &Src1 = MI.getOperand(Src1Idx);
- MachineInstr *CommutedMI = &MI;
- if (!Src1.isReg()) {
- // Allow commuting instructions with Imm operands.
- if (NewMI || !Src1.isImm() || (!isVOP2(MI) && !isVOP3(MI))) {
- return nullptr;
+ MachineInstr *CommutedMI = nullptr;
+ if (Src0.isReg() && Src1.isReg()) {
+ if (isOperandLegal(MI, Src1Idx, &Src0)) {
+ // Be sure to copy the source modifiers to the right place.
+ CommutedMI
+ = TargetInstrInfo::commuteInstructionImpl(MI, NewMI, Src0Idx, Src1Idx);
}
- // Be sure to copy the source modifiers to the right place.
- if (MachineOperand *Src0Mods =
- getNamedOperand(MI, AMDGPU::OpName::src0_modifiers)) {
- MachineOperand *Src1Mods =
- getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
-
- int Src0ModsVal = Src0Mods->getImm();
- if (!Src1Mods && Src0ModsVal != 0)
- return nullptr;
-
- // XXX - This assert might be a lie. It might be useful to have a neg
- // modifier with 0.0.
- int Src1ModsVal = Src1Mods->getImm();
- assert((Src1ModsVal == 0) && "Not expecting modifiers with immediates");
-
- Src1Mods->setImm(Src0ModsVal);
- Src0Mods->setImm(Src1ModsVal);
- }
-
- unsigned Reg = Src0.getReg();
- unsigned SubReg = Src0.getSubReg();
- if (Src1.isImm())
- Src0.ChangeToImmediate(Src1.getImm());
- else
- llvm_unreachable("Should only have immediates");
- Src1.ChangeToRegister(Reg, false);
- Src1.setSubReg(SubReg);
+ } else if (Src0.isReg() && !Src1.isReg()) {
+ // src0 should always be able to support any operand type, so no need to
+ // check operand legality.
+ CommutedMI = swapRegAndNonRegOperand(MI, Src0, Src1);
+ } else if (!Src0.isReg() && Src1.isReg()) {
+ if (isOperandLegal(MI, Src1Idx, &Src0))
+ CommutedMI = swapRegAndNonRegOperand(MI, Src1, Src0);
} else {
- CommutedMI =
- TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx0, OpIdx1);
+ // FIXME: Found two non registers to commute. This does happen.
+ return nullptr;
}
- if (CommutedMI)
+
+ if (CommutedMI) {
+ swapSourceModifiers(MI, Src0, AMDGPU::OpName::src0_modifiers,
+ Src1, AMDGPU::OpName::src1_modifiers);
+
CommutedMI->setDesc(get(CommutedOpcode));
+ }
return CommutedMI;
}
@@ -1028,8 +1015,7 @@ MachineInstr *SIInstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
// TargetInstrInfo::commuteInstruction uses it.
bool SIInstrInfo::findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx0,
unsigned &SrcOpIdx1) const {
- const MCInstrDesc &MCID = MI.getDesc();
- if (!MCID.isCommutable())
+ if (!MI.isCommutable())
return false;
unsigned Opc = MI.getOpcode();
@@ -1037,34 +1023,135 @@ bool SIInstrInfo::findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx0,
if (Src0Idx == -1)
return false;
- // FIXME: Workaround TargetInstrInfo::commuteInstruction asserting on
- // immediate. Also, immediate src0 operand is not handled in
- // SIInstrInfo::commuteInstruction();
- if (!MI.getOperand(Src0Idx).isReg())
- return false;
-
int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
if (Src1Idx == -1)
return false;
- MachineOperand &Src1 = MI.getOperand(Src1Idx);
- if (Src1.isImm()) {
- // SIInstrInfo::commuteInstruction() does support commuting the immediate
- // operand src1 in 2 and 3 operand instructions.
- if (!isVOP2(MI.getOpcode()) && !isVOP3(MI.getOpcode()))
- return false;
- } else if (Src1.isReg()) {
- // If any source modifiers are set, the generic instruction commuting won't
- // understand how to copy the source modifiers.
- if (hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers) ||
- hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers))
- return false;
- } else
- return false;
-
return fixCommutedOpIndices(SrcOpIdx0, SrcOpIdx1, Src0Idx, Src1Idx);
}
+bool SIInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
+ int64_t BrOffset) const {
+ // BranchRelaxation should never have to check s_setpc_b64 because its dest
+ // block is unanalyzable.
+ assert(BranchOp != AMDGPU::S_SETPC_B64);
+
+ // Convert to dwords.
+ BrOffset /= 4;
+
+ // The branch instructions do PC += signext(SIMM16 * 4) + 4, so the offset is
+ // from the next instruction.
+ BrOffset -= 1;
+
+ return isIntN(BranchOffsetBits, BrOffset);
+}
+
+MachineBasicBlock *SIInstrInfo::getBranchDestBlock(
+ const MachineInstr &MI) const {
+ if (MI.getOpcode() == AMDGPU::S_SETPC_B64) {
+ // This would be a difficult analysis to perform, but can always be legal so
+ // there's no need to analyze it.
+ return nullptr;
+ }
+
+ return MI.getOperand(0).getMBB();
+}
+
+unsigned SIInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock &DestBB,
+ const DebugLoc &DL,
+ int64_t BrOffset,
+ RegScavenger *RS) const {
+ assert(RS && "RegScavenger required for long branching");
+ assert(MBB.empty() &&
+ "new block should be inserted for expanding unconditional branch");
+ assert(MBB.pred_size() == 1);
+
+ MachineFunction *MF = MBB.getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+
+ // FIXME: Virtual register workaround for RegScavenger not working with empty
+ // blocks.
+ unsigned PCReg = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
+
+ auto I = MBB.end();
+
+ // We need to compute the offset relative to the instruction immediately after
+ // s_getpc_b64. Insert pc arithmetic code before last terminator.
+ MachineInstr *GetPC = BuildMI(MBB, I, DL, get(AMDGPU::S_GETPC_B64), PCReg);
+
+ // TODO: Handle > 32-bit block address.
+ if (BrOffset >= 0) {
+ BuildMI(MBB, I, DL, get(AMDGPU::S_ADD_U32))
+ .addReg(PCReg, RegState::Define, AMDGPU::sub0)
+ .addReg(PCReg, 0, AMDGPU::sub0)
+ .addMBB(&DestBB, AMDGPU::TF_LONG_BRANCH_FORWARD);
+ BuildMI(MBB, I, DL, get(AMDGPU::S_ADDC_U32))
+ .addReg(PCReg, RegState::Define, AMDGPU::sub1)
+ .addReg(PCReg, 0, AMDGPU::sub1)
+ .addImm(0);
+ } else {
+ // Backwards branch.
+ BuildMI(MBB, I, DL, get(AMDGPU::S_SUB_U32))
+ .addReg(PCReg, RegState::Define, AMDGPU::sub0)
+ .addReg(PCReg, 0, AMDGPU::sub0)
+ .addMBB(&DestBB, AMDGPU::TF_LONG_BRANCH_BACKWARD);
+ BuildMI(MBB, I, DL, get(AMDGPU::S_SUBB_U32))
+ .addReg(PCReg, RegState::Define, AMDGPU::sub1)
+ .addReg(PCReg, 0, AMDGPU::sub1)
+ .addImm(0);
+ }
+
+ // Insert the indirect branch after the other terminator.
+ BuildMI(&MBB, DL, get(AMDGPU::S_SETPC_B64))
+ .addReg(PCReg);
+
+ // FIXME: If spilling is necessary, this will fail because this scavenger has
+ // no emergency stack slots. It is non-trivial to spill in this situation,
+ // because the restore code needs to be specially placed after the
+ // jump. BranchRelaxation then needs to be made aware of the newly inserted
+ // block.
+ //
+ // If a spill is needed for the pc register pair, we need to insert a spill
+ // restore block right before the destination block, and insert a short branch
+ // into the old destination block's fallthrough predecessor.
+ // e.g.:
+ //
+ // s_cbranch_scc0 skip_long_branch:
+ //
+ // long_branch_bb:
+ // spill s[8:9]
+ // s_getpc_b64 s[8:9]
+ // s_add_u32 s8, s8, restore_bb
+ // s_addc_u32 s9, s9, 0
+ // s_setpc_b64 s[8:9]
+ //
+ // skip_long_branch:
+ // foo;
+ //
+ // .....
+ //
+ // dest_bb_fallthrough_predecessor:
+ // bar;
+ // s_branch dest_bb
+ //
+ // restore_bb:
+ // restore s[8:9]
+ // fallthrough dest_bb
+ ///
+ // dest_bb:
+ // buzz;
+
+ RS->enterBasicBlockEnd(MBB);
+ unsigned Scav = RS->scavengeRegister(&AMDGPU::SReg_64RegClass,
+ MachineBasicBlock::iterator(GetPC), 0);
+ MRI.replaceRegWith(PCReg, Scav);
+ MRI.clearVirtRegs();
+ RS->setRegUsed(Scav);
+
+ return 4 + 8 + 4 + 4;
+}
+
unsigned SIInstrInfo::getBranchOpcode(SIInstrInfo::BranchPredicate Cond) {
switch (Cond) {
case SIInstrInfo::SCC_TRUE:
@@ -1103,15 +1190,12 @@ SIInstrInfo::BranchPredicate SIInstrInfo::getBranchPredicate(unsigned Opcode) {
}
}
-bool SIInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
- MachineBasicBlock *&FBB,
- SmallVectorImpl<MachineOperand> &Cond,
- bool AllowModify) const {
- MachineBasicBlock::iterator I = MBB.getFirstTerminator();
-
- if (I == MBB.end())
- return false;
-
+bool SIInstrInfo::analyzeBranchImpl(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock *&TBB,
+ MachineBasicBlock *&FBB,
+ SmallVectorImpl<MachineOperand> &Cond,
+ bool AllowModify) const {
if (I->getOpcode() == AMDGPU::S_BRANCH) {
// Unconditional Branch
TBB = I->getOperand(0).getMBB();
@@ -1124,6 +1208,7 @@ bool SIInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *CondBB = I->getOperand(0).getMBB();
Cond.push_back(MachineOperand::CreateImm(Pred));
+ Cond.push_back(I->getOperand(1)); // Save the branch register.
++I;
@@ -1142,29 +1227,81 @@ bool SIInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
return true;
}
-unsigned SIInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+bool SIInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
+ MachineBasicBlock *&FBB,
+ SmallVectorImpl<MachineOperand> &Cond,
+ bool AllowModify) const {
+ MachineBasicBlock::iterator I = MBB.getFirstTerminator();
+ if (I == MBB.end())
+ return false;
+
+ if (I->getOpcode() != AMDGPU::SI_MASK_BRANCH)
+ return analyzeBranchImpl(MBB, I, TBB, FBB, Cond, AllowModify);
+
+ ++I;
+
+ // TODO: Should be able to treat as fallthrough?
+ if (I == MBB.end())
+ return true;
+
+ if (analyzeBranchImpl(MBB, I, TBB, FBB, Cond, AllowModify))
+ return true;
+
+ MachineBasicBlock *MaskBrDest = I->getOperand(0).getMBB();
+
+ // Specifically handle the case where the conditional branch is to the same
+ // destination as the mask branch. e.g.
+ //
+ // si_mask_branch BB8
+ // s_cbranch_execz BB8
+ // s_cbranch BB9
+ //
+ // This is required to understand divergent loops which may need the branches
+ // to be relaxed.
+ if (TBB != MaskBrDest || Cond.empty())
+ return true;
+
+ auto Pred = Cond[0].getImm();
+ return (Pred != EXECZ && Pred != EXECNZ);
+}
+
+unsigned SIInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
MachineBasicBlock::iterator I = MBB.getFirstTerminator();
unsigned Count = 0;
+ unsigned RemovedSize = 0;
while (I != MBB.end()) {
MachineBasicBlock::iterator Next = std::next(I);
+ if (I->getOpcode() == AMDGPU::SI_MASK_BRANCH) {
+ I = Next;
+ continue;
+ }
+
+ RemovedSize += getInstSizeInBytes(*I);
I->eraseFromParent();
++Count;
I = Next;
}
+ if (BytesRemoved)
+ *BytesRemoved = RemovedSize;
+
return Count;
}
-unsigned SIInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned SIInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
if (!FBB && Cond.empty()) {
BuildMI(&MBB, DL, get(AMDGPU::S_BRANCH))
.addMBB(TBB);
+ if (BytesAdded)
+ *BytesAdded = 4;
return 1;
}
@@ -1174,24 +1311,42 @@ unsigned SIInstrInfo::InsertBranch(MachineBasicBlock &MBB,
= getBranchOpcode(static_cast<BranchPredicate>(Cond[0].getImm()));
if (!FBB) {
- BuildMI(&MBB, DL, get(Opcode))
+ Cond[1].isUndef();
+ MachineInstr *CondBr =
+ BuildMI(&MBB, DL, get(Opcode))
.addMBB(TBB);
+
+ // Copy the flags onto the implicit condition register operand.
+ MachineOperand &CondReg = CondBr->getOperand(1);
+ CondReg.setIsUndef(Cond[1].isUndef());
+ CondReg.setIsKill(Cond[1].isKill());
+
+ if (BytesAdded)
+ *BytesAdded = 4;
return 1;
}
assert(TBB && FBB);
- BuildMI(&MBB, DL, get(Opcode))
+ MachineInstr *CondBr =
+ BuildMI(&MBB, DL, get(Opcode))
.addMBB(TBB);
BuildMI(&MBB, DL, get(AMDGPU::S_BRANCH))
.addMBB(FBB);
+ MachineOperand &CondReg = CondBr->getOperand(1);
+ CondReg.setIsUndef(Cond[1].isUndef());
+ CondReg.setIsKill(Cond[1].isKill());
+
+ if (BytesAdded)
+ *BytesAdded = 8;
+
return 2;
}
-bool SIInstrInfo::ReverseBranchCondition(
+bool SIInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
- assert(Cond.size() == 1);
+ assert(Cond.size() == 2);
Cond[0].setImm(-Cond[0].getImm());
return false;
}
@@ -1210,15 +1365,43 @@ static void removeModOperands(MachineInstr &MI) {
MI.RemoveOperand(Src0ModIdx);
}
-// TODO: Maybe this should be removed this and custom fold everything in
-// SIFoldOperands?
bool SIInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
unsigned Reg, MachineRegisterInfo *MRI) const {
if (!MRI->hasOneNonDBGUse(Reg))
return false;
unsigned Opc = UseMI.getOpcode();
- if (Opc == AMDGPU::V_MAD_F32 || Opc == AMDGPU::V_MAC_F32_e64) {
+ if (Opc == AMDGPU::COPY) {
+ bool isVGPRCopy = RI.isVGPR(*MRI, UseMI.getOperand(0).getReg());
+ switch (DefMI.getOpcode()) {
+ default:
+ return false;
+ case AMDGPU::S_MOV_B64:
+ // TODO: We could fold 64-bit immediates, but this get compilicated
+ // when there are sub-registers.
+ return false;
+
+ case AMDGPU::V_MOV_B32_e32:
+ case AMDGPU::S_MOV_B32:
+ break;
+ }
+ unsigned NewOpc = isVGPRCopy ? AMDGPU::V_MOV_B32_e32 : AMDGPU::S_MOV_B32;
+ const MachineOperand *ImmOp = getNamedOperand(DefMI, AMDGPU::OpName::src0);
+ assert(ImmOp);
+ // FIXME: We could handle FrameIndex values here.
+ if (!ImmOp->isImm()) {
+ return false;
+ }
+ UseMI.setDesc(get(NewOpc));
+ UseMI.getOperand(1).ChangeToImmediate(ImmOp->getImm());
+ UseMI.addImplicitDefUseOperands(*UseMI.getParent()->getParent());
+ return true;
+ }
+
+ if (Opc == AMDGPU::V_MAD_F32 || Opc == AMDGPU::V_MAC_F32_e64 ||
+ Opc == AMDGPU::V_MAD_F16 || Opc == AMDGPU::V_MAC_F16_e64) {
+ bool IsF32 = Opc == AMDGPU::V_MAD_F32 || Opc == AMDGPU::V_MAC_F32_e64;
+
// Don't fold if we are using source modifiers. The new VOP2 instructions
// don't have them.
if (hasModifiersSet(UseMI, AMDGPU::OpName::src0_modifiers) ||
@@ -1232,14 +1415,16 @@ bool SIInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
// If this is a free constant, there's no reason to do this.
// TODO: We could fold this here instead of letting SIFoldOperands do it
// later.
- if (isInlineConstant(ImmOp, 4))
+ MachineOperand *Src0 = getNamedOperand(UseMI, AMDGPU::OpName::src0);
+
+ // Any src operand can be used for the legality check.
+ if (isInlineConstant(UseMI, *Src0, ImmOp))
return false;
- MachineOperand *Src0 = getNamedOperand(UseMI, AMDGPU::OpName::src0);
MachineOperand *Src1 = getNamedOperand(UseMI, AMDGPU::OpName::src1);
MachineOperand *Src2 = getNamedOperand(UseMI, AMDGPU::OpName::src2);
- // Multiplied part is the constant: Use v_madmk_f32
+ // Multiplied part is the constant: Use v_madmk_{f16, f32}.
// We should only expect these to be on src0 due to canonicalizations.
if (Src0->isReg() && Src0->getReg() == Reg) {
if (!Src1->isReg() || RI.isSGPRClass(MRI->getRegClass(Src1->getReg())))
@@ -1267,15 +1452,15 @@ bool SIInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
Src0->setSubReg(Src1SubReg);
Src0->setIsKill(Src1->isKill());
- if (Opc == AMDGPU::V_MAC_F32_e64) {
+ if (Opc == AMDGPU::V_MAC_F32_e64 ||
+ Opc == AMDGPU::V_MAC_F16_e64)
UseMI.untieRegOperand(
AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2));
- }
Src1->ChangeToImmediate(Imm);
removeModOperands(UseMI);
- UseMI.setDesc(get(AMDGPU::V_MADMK_F32));
+ UseMI.setDesc(get(IsF32 ? AMDGPU::V_MADMK_F32 : AMDGPU::V_MADMK_F16));
bool DeleteDef = MRI->hasOneNonDBGUse(Reg);
if (DeleteDef)
@@ -1284,7 +1469,7 @@ bool SIInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
return true;
}
- // Added part is the constant: Use v_madak_f32
+ // Added part is the constant: Use v_madak_{f16, f32}.
if (Src2->isReg() && Src2->getReg() == Reg) {
// Not allowed to use constant bus for another operand.
// We can however allow an inline immediate as src0.
@@ -1306,17 +1491,17 @@ bool SIInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
UseMI.RemoveOperand(
AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::clamp));
- if (Opc == AMDGPU::V_MAC_F32_e64) {
+ if (Opc == AMDGPU::V_MAC_F32_e64 ||
+ Opc == AMDGPU::V_MAC_F16_e64)
UseMI.untieRegOperand(
AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2));
- }
// ChangingToImmediate adds Src2 back to the instruction.
Src2->ChangeToImmediate(Imm);
// These come before src2.
removeModOperands(UseMI);
- UseMI.setDesc(get(AMDGPU::V_MADAK_F32));
+ UseMI.setDesc(get(IsF32 ? AMDGPU::V_MADAK_F32 : AMDGPU::V_MADAK_F16));
bool DeleteDef = MRI->hasOneNonDBGUse(Reg);
if (DeleteDef)
@@ -1375,6 +1560,17 @@ bool SIInstrInfo::areMemAccessesTriviallyDisjoint(MachineInstr &MIa,
if (MIa.hasOrderedMemoryRef() || MIb.hasOrderedMemoryRef())
return false;
+ if (AA && MIa.hasOneMemOperand() && MIb.hasOneMemOperand()) {
+ const MachineMemOperand *MMOa = *MIa.memoperands_begin();
+ const MachineMemOperand *MMOb = *MIb.memoperands_begin();
+ if (MMOa->getValue() && MMOb->getValue()) {
+ MemoryLocation LocA(MMOa->getValue(), MMOa->getSize(), MMOa->getAAInfo());
+ MemoryLocation LocB(MMOb->getValue(), MMOb->getSize(), MMOb->getAAInfo());
+ if (!AA->alias(LocA, LocB))
+ return true;
+ }
+ }
+
// TODO: Should we check the address space from the MachineMemOperand? That
// would allow us to distinguish objects we know don't alias based on the
// underlying address space, even if it was lowered to a different one,
@@ -1414,15 +1610,22 @@ bool SIInstrInfo::areMemAccessesTriviallyDisjoint(MachineInstr &MIa,
MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB,
MachineInstr &MI,
LiveVariables *LV) const {
+ bool IsF16 = false;
switch (MI.getOpcode()) {
default:
return nullptr;
+ case AMDGPU::V_MAC_F16_e64:
+ IsF16 = true;
case AMDGPU::V_MAC_F32_e64:
break;
+ case AMDGPU::V_MAC_F16_e32:
+ IsF16 = true;
case AMDGPU::V_MAC_F32_e32: {
- const MachineOperand *Src0 = getNamedOperand(MI, AMDGPU::OpName::src0);
- if (Src0->isImm() && !isInlineConstant(*Src0, 4))
+ int Src0Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
+ AMDGPU::OpName::src0);
+ const MachineOperand *Src0 = &MI.getOperand(Src0Idx);
+ if (Src0->isImm() && !isInlineConstant(MI, Src0Idx, *Src0))
return nullptr;
break;
}
@@ -1433,7 +1636,8 @@ MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB,
const MachineOperand *Src1 = getNamedOperand(MI, AMDGPU::OpName::src1);
const MachineOperand *Src2 = getNamedOperand(MI, AMDGPU::OpName::src2);
- return BuildMI(*MBB, MI, MI.getDebugLoc(), get(AMDGPU::V_MAD_F32))
+ return BuildMI(*MBB, MI, MI.getDebugLoc(),
+ get(IsF16 ? AMDGPU::V_MAD_F16 : AMDGPU::V_MAD_F32))
.addOperand(*Dst)
.addImm(0) // Src0 mods
.addOperand(*Src0)
@@ -1445,6 +1649,20 @@ MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB,
.addImm(0); // omod
}
+// It's not generally safe to move VALU instructions across these since it will
+// start using the register as a base index rather than directly.
+// XXX - Why isn't hasSideEffects sufficient for these?
+static bool changesVGPRIndexingMode(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case AMDGPU::S_SET_GPR_IDX_ON:
+ case AMDGPU::S_SET_GPR_IDX_MODE:
+ case AMDGPU::S_SET_GPR_IDX_OFF:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool SIInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
const MachineBasicBlock *MBB,
const MachineFunction &MF) const {
@@ -1454,67 +1672,78 @@ bool SIInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
// when they operate on VGPRs. Treating EXEC modifications as scheduling
// boundaries prevents incorrect movements of such instructions.
return TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF) ||
- MI.modifiesRegister(AMDGPU::EXEC, &RI);
+ MI.modifiesRegister(AMDGPU::EXEC, &RI) ||
+ MI.getOpcode() == AMDGPU::S_SETREG_IMM32_B32 ||
+ MI.getOpcode() == AMDGPU::S_SETREG_B32 ||
+ changesVGPRIndexingMode(MI);
}
bool SIInstrInfo::isInlineConstant(const APInt &Imm) const {
- int64_t SVal = Imm.getSExtValue();
- if (SVal >= -16 && SVal <= 64)
- return true;
-
- if (Imm.getBitWidth() == 64) {
- uint64_t Val = Imm.getZExtValue();
- return (DoubleToBits(0.0) == Val) ||
- (DoubleToBits(1.0) == Val) ||
- (DoubleToBits(-1.0) == Val) ||
- (DoubleToBits(0.5) == Val) ||
- (DoubleToBits(-0.5) == Val) ||
- (DoubleToBits(2.0) == Val) ||
- (DoubleToBits(-2.0) == Val) ||
- (DoubleToBits(4.0) == Val) ||
- (DoubleToBits(-4.0) == Val);
- }
-
- // The actual type of the operand does not seem to matter as long
- // as the bits match one of the inline immediate values. For example:
- //
- // -nan has the hexadecimal encoding of 0xfffffffe which is -2 in decimal,
- // so it is a legal inline immediate.
- //
- // 1065353216 has the hexadecimal encoding 0x3f800000 which is 1.0f in
- // floating-point, so it is a legal inline immediate.
- uint32_t Val = Imm.getZExtValue();
-
- return (FloatToBits(0.0f) == Val) ||
- (FloatToBits(1.0f) == Val) ||
- (FloatToBits(-1.0f) == Val) ||
- (FloatToBits(0.5f) == Val) ||
- (FloatToBits(-0.5f) == Val) ||
- (FloatToBits(2.0f) == Val) ||
- (FloatToBits(-2.0f) == Val) ||
- (FloatToBits(4.0f) == Val) ||
- (FloatToBits(-4.0f) == Val);
+ switch (Imm.getBitWidth()) {
+ case 32:
+ return AMDGPU::isInlinableLiteral32(Imm.getSExtValue(),
+ ST.hasInv2PiInlineImm());
+ case 64:
+ return AMDGPU::isInlinableLiteral64(Imm.getSExtValue(),
+ ST.hasInv2PiInlineImm());
+ case 16:
+ return AMDGPU::isInlinableLiteral16(Imm.getSExtValue(),
+ ST.hasInv2PiInlineImm());
+ default:
+ llvm_unreachable("invalid bitwidth");
+ }
}
bool SIInstrInfo::isInlineConstant(const MachineOperand &MO,
- unsigned OpSize) const {
- if (MO.isImm()) {
- // MachineOperand provides no way to tell the true operand size, since it
- // only records a 64-bit value. We need to know the size to determine if a
- // 32-bit floating point immediate bit pattern is legal for an integer
- // immediate. It would be for any 32-bit integer operand, but would not be
- // for a 64-bit one.
+ uint8_t OperandType) const {
+ if (!MO.isImm() || OperandType < MCOI::OPERAND_FIRST_TARGET)
+ return false;
- unsigned BitSize = 8 * OpSize;
- return isInlineConstant(APInt(BitSize, MO.getImm(), true));
- }
+ // MachineOperand provides no way to tell the true operand size, since it only
+ // records a 64-bit value. We need to know the size to determine if a 32-bit
+ // floating point immediate bit pattern is legal for an integer immediate. It
+ // would be for any 32-bit integer operand, but would not be for a 64-bit one.
+
+ int64_t Imm = MO.getImm();
+ switch (operandBitWidth(OperandType)) {
+ case 32: {
+ int32_t Trunc = static_cast<int32_t>(Imm);
+ return Trunc == Imm &&
+ AMDGPU::isInlinableLiteral32(Trunc, ST.hasInv2PiInlineImm());
+ }
+ case 64: {
+ return AMDGPU::isInlinableLiteral64(MO.getImm(),
+ ST.hasInv2PiInlineImm());
+ }
+ case 16: {
+ if (isInt<16>(Imm) || isUInt<16>(Imm)) {
+ int16_t Trunc = static_cast<int16_t>(Imm);
+ return AMDGPU::isInlinableLiteral16(Trunc, ST.hasInv2PiInlineImm());
+ }
- return false;
+ return false;
+ }
+ default:
+ llvm_unreachable("invalid bitwidth");
+ }
}
-bool SIInstrInfo::isLiteralConstant(const MachineOperand &MO,
- unsigned OpSize) const {
- return MO.isImm() && !isInlineConstant(MO, OpSize);
+bool SIInstrInfo::isLiteralConstantLike(const MachineOperand &MO,
+ const MCOperandInfo &OpInfo) const {
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ return false;
+ case MachineOperand::MO_Immediate:
+ return !isInlineConstant(MO, OpInfo);
+ case MachineOperand::MO_FrameIndex:
+ case MachineOperand::MO_MachineBasicBlock:
+ case MachineOperand::MO_ExternalSymbol:
+ case MachineOperand::MO_GlobalAddress:
+ case MachineOperand::MO_MCSymbol:
+ return true;
+ default:
+ llvm_unreachable("unexpected operand type");
+ }
}
static bool compareMachineOp(const MachineOperand &Op0,
@@ -1544,11 +1773,10 @@ bool SIInstrInfo::isImmOperandLegal(const MachineInstr &MI, unsigned OpNo,
if (OpInfo.RegClass < 0)
return false;
- unsigned OpSize = RI.getRegClass(OpInfo.RegClass)->getSize();
- if (isLiteralConstant(MO, OpSize))
- return RI.opCanUseLiteralConstant(OpInfo.OperandType);
+ if (MO.isImm() && isInlineConstant(MO, OpInfo))
+ return RI.opCanUseInlineConstant(OpInfo.OperandType);
- return RI.opCanUseInlineConstant(OpInfo.OperandType);
+ return RI.opCanUseLiteralConstant(OpInfo.OperandType);
}
bool SIInstrInfo::hasVALU32BitEncoding(unsigned Opcode) const {
@@ -1575,12 +1803,17 @@ bool SIInstrInfo::hasModifiersSet(const MachineInstr &MI,
bool SIInstrInfo::usesConstantBus(const MachineRegisterInfo &MRI,
const MachineOperand &MO,
- unsigned OpSize) const {
+ const MCOperandInfo &OpInfo) const {
// Literal constants use the constant bus.
- if (isLiteralConstant(MO, OpSize))
- return true;
+ //if (isLiteralConstantLike(MO, OpInfo))
+ // return true;
+ if (MO.isImm())
+ return !isInlineConstant(MO, OpInfo);
+
+ if (!MO.isReg())
+ return true; // Misc other operands like FrameIndex
- if (!MO.isReg() || !MO.isUse())
+ if (!MO.isUse())
return false;
if (TargetRegisterInfo::isVirtualRegister(MO.getReg()))
@@ -1644,6 +1877,16 @@ static bool shouldReadExec(const MachineInstr &MI) {
return true;
}
+static bool isSubRegOf(const SIRegisterInfo &TRI,
+ const MachineOperand &SuperVec,
+ const MachineOperand &SubReg) {
+ if (TargetRegisterInfo::isPhysicalRegister(SubReg.getReg()))
+ return TRI.isSubRegister(SuperVec.getReg(), SubReg.getReg());
+
+ return SubReg.getSubReg() != AMDGPU::NoSubRegister &&
+ SubReg.getReg() == SuperVec.getReg();
+}
+
bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
StringRef &ErrInfo) const {
uint16_t Opcode = MI.getOpcode();
@@ -1660,6 +1903,28 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
return false;
}
+ if (MI.isInlineAsm()) {
+ // Verify register classes for inlineasm constraints.
+ for (unsigned I = InlineAsm::MIOp_FirstOperand, E = MI.getNumOperands();
+ I != E; ++I) {
+ const TargetRegisterClass *RC = MI.getRegClassConstraint(I, this, &RI);
+ if (!RC)
+ continue;
+
+ const MachineOperand &Op = MI.getOperand(I);
+ if (!Op.isReg())
+ continue;
+
+ unsigned Reg = Op.getReg();
+ if (!TargetRegisterInfo::isVirtualRegister(Reg) && !RC->contains(Reg)) {
+ ErrInfo = "inlineasm operand has incorrect register class.";
+ return false;
+ }
+ }
+
+ return true;
+ }
+
// Make sure the register classes are correct.
for (int i = 0, e = Desc.getNumOperands(); i != e; ++i) {
if (MI.getOperand(i).isFPImm()) {
@@ -1677,15 +1942,22 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
return false;
}
break;
- case AMDGPU::OPERAND_REG_IMM32:
+ case AMDGPU::OPERAND_REG_IMM_INT32:
+ case AMDGPU::OPERAND_REG_IMM_FP32:
break;
- case AMDGPU::OPERAND_REG_INLINE_C:
- if (isLiteralConstant(MI.getOperand(i),
- RI.getRegClass(RegClass)->getSize())) {
+ case AMDGPU::OPERAND_REG_INLINE_C_INT32:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP32:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT64:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP64:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT16:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP16: {
+ const MachineOperand &MO = MI.getOperand(i);
+ if (!MO.isReg() && (!MO.isImm() || !isInlineConstant(MI, i))) {
ErrInfo = "Illegal immediate value for operand.";
return false;
}
break;
+ }
case MCOI::OPERAND_IMMEDIATE:
case AMDGPU::OPERAND_KIMM32:
// Check if this operand is an immediate.
@@ -1695,7 +1967,7 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
ErrInfo = "Expected immediate, but got non-immediate";
return false;
}
- // Fall-through
+ LLVM_FALLTHROUGH;
default:
continue;
}
@@ -1737,7 +2009,7 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
if (OpIdx == -1)
break;
const MachineOperand &MO = MI.getOperand(OpIdx);
- if (usesConstantBus(MRI, MO, getOpSize(Opcode, OpIdx))) {
+ if (usesConstantBus(MRI, MO, MI.getDesc().OpInfo[OpIdx])) {
if (MO.isReg()) {
if (MO.getReg() != SGPRUsed)
++ConstantBusCount;
@@ -1768,6 +2040,65 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
}
}
+ if (isSOPK(MI)) {
+ int64_t Imm = getNamedOperand(MI, AMDGPU::OpName::simm16)->getImm();
+ if (sopkIsZext(MI)) {
+ if (!isUInt<16>(Imm)) {
+ ErrInfo = "invalid immediate for SOPK instruction";
+ return false;
+ }
+ } else {
+ if (!isInt<16>(Imm)) {
+ ErrInfo = "invalid immediate for SOPK instruction";
+ return false;
+ }
+ }
+ }
+
+ if (Desc.getOpcode() == AMDGPU::V_MOVRELS_B32_e32 ||
+ Desc.getOpcode() == AMDGPU::V_MOVRELS_B32_e64 ||
+ Desc.getOpcode() == AMDGPU::V_MOVRELD_B32_e32 ||
+ Desc.getOpcode() == AMDGPU::V_MOVRELD_B32_e64) {
+ const bool IsDst = Desc.getOpcode() == AMDGPU::V_MOVRELD_B32_e32 ||
+ Desc.getOpcode() == AMDGPU::V_MOVRELD_B32_e64;
+
+ const unsigned StaticNumOps = Desc.getNumOperands() +
+ Desc.getNumImplicitUses();
+ const unsigned NumImplicitOps = IsDst ? 2 : 1;
+
+ // Allow additional implicit operands. This allows a fixup done by the post
+ // RA scheduler where the main implicit operand is killed and implicit-defs
+ // are added for sub-registers that remain live after this instruction.
+ if (MI.getNumOperands() < StaticNumOps + NumImplicitOps) {
+ ErrInfo = "missing implicit register operands";
+ return false;
+ }
+
+ const MachineOperand *Dst = getNamedOperand(MI, AMDGPU::OpName::vdst);
+ if (IsDst) {
+ if (!Dst->isUse()) {
+ ErrInfo = "v_movreld_b32 vdst should be a use operand";
+ return false;
+ }
+
+ unsigned UseOpIdx;
+ if (!MI.isRegTiedToUseOperand(StaticNumOps, &UseOpIdx) ||
+ UseOpIdx != StaticNumOps + 1) {
+ ErrInfo = "movrel implicit operands should be tied";
+ return false;
+ }
+ }
+
+ const MachineOperand &Src0 = MI.getOperand(Src0Idx);
+ const MachineOperand &ImpUse
+ = MI.getOperand(StaticNumOps + NumImplicitOps - 1);
+ if (!ImpUse.isReg() || !ImpUse.isUse() ||
+ !isSubRegOf(RI, ImpUse, IsDst ? *Dst : Src0)) {
+ ErrInfo = "src0 should be subreg of implicit vector use";
+ return false;
+ }
+ }
+
// Make sure we aren't losing exec uses in the td files. This mostly requires
// being careful when using let Uses to try to add other use registers.
if (shouldReadExec(MI)) {
@@ -1777,6 +2108,18 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI,
}
}
+ if (isSMRD(MI)) {
+ if (MI.mayStore()) {
+ // The register offset form of scalar stores may only use m0 as the
+ // soffset register.
+ const MachineOperand *Soff = getNamedOperand(MI, AMDGPU::OpName::soff);
+ if (Soff && Soff->getReg() != AMDGPU::M0) {
+ ErrInfo = "scalar stores must use m0 as offset register";
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -1797,13 +2140,13 @@ unsigned SIInstrInfo::getVALUOp(const MachineInstr &MI) {
case AMDGPU::S_SUB_U32: return AMDGPU::V_SUB_I32_e32;
case AMDGPU::S_SUBB_U32: return AMDGPU::V_SUBB_U32_e32;
case AMDGPU::S_MUL_I32: return AMDGPU::V_MUL_LO_I32;
- case AMDGPU::S_AND_B32: return AMDGPU::V_AND_B32_e32;
- case AMDGPU::S_OR_B32: return AMDGPU::V_OR_B32_e32;
- case AMDGPU::S_XOR_B32: return AMDGPU::V_XOR_B32_e32;
- case AMDGPU::S_MIN_I32: return AMDGPU::V_MIN_I32_e32;
- case AMDGPU::S_MIN_U32: return AMDGPU::V_MIN_U32_e32;
- case AMDGPU::S_MAX_I32: return AMDGPU::V_MAX_I32_e32;
- case AMDGPU::S_MAX_U32: return AMDGPU::V_MAX_U32_e32;
+ case AMDGPU::S_AND_B32: return AMDGPU::V_AND_B32_e64;
+ case AMDGPU::S_OR_B32: return AMDGPU::V_OR_B32_e64;
+ case AMDGPU::S_XOR_B32: return AMDGPU::V_XOR_B32_e64;
+ case AMDGPU::S_MIN_I32: return AMDGPU::V_MIN_I32_e64;
+ case AMDGPU::S_MIN_U32: return AMDGPU::V_MIN_U32_e64;
+ case AMDGPU::S_MAX_I32: return AMDGPU::V_MAX_I32_e64;
+ case AMDGPU::S_MAX_U32: return AMDGPU::V_MAX_U32_e64;
case AMDGPU::S_ASHR_I32: return AMDGPU::V_ASHR_I32_e32;
case AMDGPU::S_ASHR_I64: return AMDGPU::V_ASHR_I64;
case AMDGPU::S_LSHL_B32: return AMDGPU::V_LSHL_B32_e32;
@@ -1830,6 +2173,8 @@ unsigned SIInstrInfo::getVALUOp(const MachineInstr &MI) {
case AMDGPU::S_CMP_GE_U32: return AMDGPU::V_CMP_GE_U32_e32;
case AMDGPU::S_CMP_LT_U32: return AMDGPU::V_CMP_LT_U32_e32;
case AMDGPU::S_CMP_LE_U32: return AMDGPU::V_CMP_LE_U32_e32;
+ case AMDGPU::S_CMP_EQ_U64: return AMDGPU::V_CMP_EQ_U64_e32;
+ case AMDGPU::S_CMP_LG_U64: return AMDGPU::V_CMP_NE_U64_e32;
case AMDGPU::S_BCNT1_I32_B32: return AMDGPU::V_BCNT_U32_B32_e64;
case AMDGPU::S_FF1_I32_B32: return AMDGPU::V_FFBL_B32_e32;
case AMDGPU::S_FLBIT_I32_B32: return AMDGPU::V_FFBH_U32_e32;
@@ -1937,11 +2282,10 @@ MachineOperand SIInstrInfo::buildExtractSubRegOrImm(
unsigned SubIdx,
const TargetRegisterClass *SubRC) const {
if (Op.isImm()) {
- // XXX - Is there a better way to do this?
if (SubIdx == AMDGPU::sub0)
- return MachineOperand::CreateImm(Op.getImm() & 0xFFFFFFFF);
+ return MachineOperand::CreateImm(static_cast<int32_t>(Op.getImm()));
if (SubIdx == AMDGPU::sub1)
- return MachineOperand::CreateImm(Op.getImm() >> 32);
+ return MachineOperand::CreateImm(static_cast<int32_t>(Op.getImm() >> 32));
llvm_unreachable("Unhandled register index for immediate");
}
@@ -1978,8 +2322,8 @@ bool SIInstrInfo::isLegalRegOperand(const MachineRegisterInfo &MRI,
// In order to be legal, the common sub-class must be equal to the
// class of the current operand. For example:
//
- // v_mov_b32 s0 ; Operand defined as vsrc_32
- // ; RI.getCommonSubClass(s0,vsrc_32) = sgpr ; LEGAL
+ // v_mov_b32 s0 ; Operand defined as vsrc_b32
+ // ; RI.getCommonSubClass(s0,vsrc_b32) = sgpr ; LEGAL
//
// s_sendmsg 0, s0 ; Operand defined as m0reg
// ; RI.getCommonSubClass(s0,m0reg) = m0reg ; NOT LEGAL
@@ -2008,7 +2352,7 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr &MI, unsigned OpIdx,
if (!MO)
MO = &MI.getOperand(OpIdx);
- if (isVALU(MI) && usesConstantBus(MRI, *MO, DefinedRC->getSize())) {
+ if (isVALU(MI) && usesConstantBus(MRI, *MO, OpInfo)) {
RegSubRegPair SGPRUsed;
if (MO->isReg())
@@ -2020,7 +2364,7 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr &MI, unsigned OpIdx,
const MachineOperand &Op = MI.getOperand(i);
if (Op.isReg()) {
if ((Op.getReg() != SGPRUsed.Reg || Op.getSubReg() != SGPRUsed.SubReg) &&
- usesConstantBus(MRI, Op, getOpSize(MI, i))) {
+ usesConstantBus(MRI, Op, InstDesc.OpInfo[i])) {
return false;
}
} else if (InstDesc.OpInfo[i].OperandType == AMDGPU::OPERAND_KIMM32) {
@@ -2202,6 +2546,39 @@ void SIInstrInfo::legalizeOperandsSMRD(MachineRegisterInfo &MRI,
}
}
+void SIInstrInfo::legalizeGenericOperand(MachineBasicBlock &InsertMBB,
+ MachineBasicBlock::iterator I,
+ const TargetRegisterClass *DstRC,
+ MachineOperand &Op,
+ MachineRegisterInfo &MRI,
+ const DebugLoc &DL) const {
+
+ unsigned OpReg = Op.getReg();
+ unsigned OpSubReg = Op.getSubReg();
+
+ const TargetRegisterClass *OpRC = RI.getSubClassWithSubReg(
+ RI.getRegClassForReg(MRI, OpReg), OpSubReg);
+
+ // Check if operand is already the correct register class.
+ if (DstRC == OpRC)
+ return;
+
+ unsigned DstReg = MRI.createVirtualRegister(DstRC);
+ MachineInstr *Copy = BuildMI(InsertMBB, I, DL, get(AMDGPU::COPY), DstReg)
+ .addOperand(Op);
+
+ Op.setReg(DstReg);
+ Op.setSubReg(0);
+
+ MachineInstr *Def = MRI.getVRegDef(OpReg);
+ if (!Def)
+ return;
+
+ // Try to eliminate the copy if it is copying an immediate value.
+ if (Def->isMoveImmediate())
+ FoldImmediate(*Copy, *Def, OpReg, &MRI);
+}
+
void SIInstrInfo::legalizeOperands(MachineInstr &MI) const {
MachineFunction &MF = *MI.getParent()->getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();
@@ -2260,15 +2637,14 @@ void SIInstrInfo::legalizeOperands(MachineInstr &MI) const {
MachineOperand &Op = MI.getOperand(I);
if (!Op.isReg() || !TargetRegisterInfo::isVirtualRegister(Op.getReg()))
continue;
- unsigned DstReg = MRI.createVirtualRegister(RC);
// MI is a PHI instruction.
MachineBasicBlock *InsertBB = MI.getOperand(I + 1).getMBB();
MachineBasicBlock::iterator Insert = InsertBB->getFirstTerminator();
- BuildMI(*InsertBB, Insert, MI.getDebugLoc(), get(AMDGPU::COPY), DstReg)
- .addOperand(Op);
- Op.setReg(DstReg);
+ // Avoid creating no-op copies with the same src and dst reg class. These
+ // confuse some of the machine passes.
+ legalizeGenericOperand(*InsertBB, Insert, RC, Op, MRI, MI.getDebugLoc());
}
}
@@ -2292,12 +2668,7 @@ void SIInstrInfo::legalizeOperands(MachineInstr &MI) const {
if (VRC == OpRC)
continue;
- unsigned DstReg = MRI.createVirtualRegister(VRC);
-
- BuildMI(*MBB, MI, MI.getDebugLoc(), get(AMDGPU::COPY), DstReg)
- .addOperand(Op);
-
- Op.setReg(DstReg);
+ legalizeGenericOperand(*MBB, MI, VRC, Op, MRI, MI.getDebugLoc());
Op.setIsKill();
}
}
@@ -2313,11 +2684,9 @@ void SIInstrInfo::legalizeOperands(MachineInstr &MI) const {
const TargetRegisterClass *DstRC = MRI.getRegClass(Dst);
const TargetRegisterClass *Src0RC = MRI.getRegClass(Src0);
if (DstRC != Src0RC) {
- MachineBasicBlock &MBB = *MI.getParent();
- unsigned NewSrc0 = MRI.createVirtualRegister(DstRC);
- BuildMI(MBB, MI, MI.getDebugLoc(), get(AMDGPU::COPY), NewSrc0)
- .addReg(Src0);
- MI.getOperand(1).setReg(NewSrc0);
+ MachineBasicBlock *MBB = MI.getParent();
+ MachineOperand &Op = MI.getOperand(1);
+ legalizeGenericOperand(*MBB, MI, DstRC, Op, MRI, MI.getDebugLoc());
}
return;
}
@@ -2664,6 +3033,22 @@ void SIInstrInfo::moveToVALU(MachineInstr &TopInst) const {
continue;
unsigned DstReg = Inst.getOperand(0).getReg();
+ if (Inst.isCopy() &&
+ TargetRegisterInfo::isVirtualRegister(Inst.getOperand(1).getReg()) &&
+ NewDstRC == RI.getRegClassForReg(MRI, Inst.getOperand(1).getReg())) {
+ // Instead of creating a copy where src and dst are the same register
+ // class, we just replace all uses of dst with src. These kinds of
+ // copies interfere with the heuristics MachineSink uses to decide
+ // whether or not to split a critical edge. Since the pass assumes
+ // that copies will end up as machine instructions and not be
+ // eliminated.
+ addUsersToMoveToVALUWorklist(DstReg, MRI, Worklist);
+ MRI.replaceRegWith(DstReg, Inst.getOperand(1).getReg());
+ MRI.clearKillFlags(Inst.getOperand(1).getReg());
+ Inst.getOperand(0).setReg(DstReg);
+ continue;
+ }
+
NewDstReg = MRI.createVirtualRegister(NewDstRC);
MRI.replaceRegWith(DstReg, NewDstReg);
}
@@ -2927,10 +3312,16 @@ void SIInstrInfo::addUsersToMoveToVALUWorklist(
MachineRegisterInfo &MRI,
SmallVectorImpl<MachineInstr *> &Worklist) const {
for (MachineRegisterInfo::use_iterator I = MRI.use_begin(DstReg),
- E = MRI.use_end(); I != E; ++I) {
+ E = MRI.use_end(); I != E;) {
MachineInstr &UseMI = *I->getParent();
if (!canReadVGPR(UseMI, I.getOperandNo())) {
Worklist.push_back(&UseMI);
+
+ do {
+ ++I;
+ } while (I != E && I->getParent() == &UseMI);
+ } else {
+ ++I;
}
}
}
@@ -3098,6 +3489,56 @@ bool SIInstrInfo::isHighLatencyInstruction(const MachineInstr &MI) const {
return isMUBUF(Opc) || isMTBUF(Opc) || isMIMG(Opc);
}
+unsigned SIInstrInfo::isStackAccess(const MachineInstr &MI,
+ int &FrameIndex) const {
+ const MachineOperand *Addr = getNamedOperand(MI, AMDGPU::OpName::vaddr);
+ if (!Addr || !Addr->isFI())
+ return AMDGPU::NoRegister;
+
+ assert(!MI.memoperands_empty() &&
+ (*MI.memoperands_begin())->getAddrSpace() == AMDGPUAS::PRIVATE_ADDRESS);
+
+ FrameIndex = Addr->getIndex();
+ return getNamedOperand(MI, AMDGPU::OpName::vdata)->getReg();
+}
+
+unsigned SIInstrInfo::isSGPRStackAccess(const MachineInstr &MI,
+ int &FrameIndex) const {
+ const MachineOperand *Addr = getNamedOperand(MI, AMDGPU::OpName::addr);
+ assert(Addr && Addr->isFI());
+ FrameIndex = Addr->getIndex();
+ return getNamedOperand(MI, AMDGPU::OpName::data)->getReg();
+}
+
+unsigned SIInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const {
+
+ if (!MI.mayLoad())
+ return AMDGPU::NoRegister;
+
+ if (isMUBUF(MI) || isVGPRSpill(MI))
+ return isStackAccess(MI, FrameIndex);
+
+ if (isSGPRSpill(MI))
+ return isSGPRStackAccess(MI, FrameIndex);
+
+ return AMDGPU::NoRegister;
+}
+
+unsigned SIInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const {
+ if (!MI.mayStore())
+ return AMDGPU::NoRegister;
+
+ if (isMUBUF(MI) || isVGPRSpill(MI))
+ return isStackAccess(MI, FrameIndex);
+
+ if (isSGPRSpill(MI))
+ return isSGPRStackAccess(MI, FrameIndex);
+
+ return AMDGPU::NoRegister;
+}
+
unsigned SIInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
unsigned Opc = MI.getOpcode();
const MCInstrDesc &Desc = getMCOpcodeFromPseudo(Opc);
@@ -3105,32 +3546,45 @@ unsigned SIInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
// If we have a definitive size, we can use it. Otherwise we need to inspect
// the operands to know the size.
- if (DescSize == 8 || DescSize == 4)
+ //
+ // FIXME: Instructions that have a base 32-bit encoding report their size as
+ // 4, even though they are really 8 bytes if they have a literal operand.
+ if (DescSize != 0 && DescSize != 4)
return DescSize;
- assert(DescSize == 0);
+ if (Opc == AMDGPU::WAVE_BARRIER)
+ return 0;
// 4-byte instructions may have a 32-bit literal encoded after them. Check
// operands that coud ever be literals.
if (isVALU(MI) || isSALU(MI)) {
+ if (isFixedSize(MI)) {
+ assert(DescSize == 4);
+ return DescSize;
+ }
+
int Src0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0);
if (Src0Idx == -1)
return 4; // No operands.
- if (isLiteralConstant(MI.getOperand(Src0Idx), getOpSize(MI, Src0Idx)))
+ if (isLiteralConstantLike(MI.getOperand(Src0Idx), Desc.OpInfo[Src0Idx]))
return 8;
int Src1Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src1);
if (Src1Idx == -1)
return 4;
- if (isLiteralConstant(MI.getOperand(Src1Idx), getOpSize(MI, Src1Idx)))
+ if (isLiteralConstantLike(MI.getOperand(Src1Idx), Desc.OpInfo[Src1Idx]))
return 8;
return 4;
}
+ if (DescSize == 4)
+ return 4;
+
switch (Opc) {
+ case AMDGPU::SI_MASK_BRANCH:
case TargetOpcode::IMPLICIT_DEF:
case TargetOpcode::KILL:
case TargetOpcode::DBG_VALUE:
@@ -3147,6 +3601,20 @@ unsigned SIInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
}
}
+bool SIInstrInfo::mayAccessFlatAddressSpace(const MachineInstr &MI) const {
+ if (!isFLAT(MI))
+ return false;
+
+ if (MI.memoperands_empty())
+ return true;
+
+ for (const MachineMemOperand *MMO : MI.memoperands()) {
+ if (MMO->getAddrSpace() == AMDGPUAS::FLAT_ADDRESS)
+ return true;
+ }
+ return false;
+}
+
ArrayRef<std::pair<int, const char *>>
SIInstrInfo::getSerializableTargetIndices() const {
static const std::pair<int, const char *> TargetIndices[] = {
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h
index fef8904..e68f6f9 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h
@@ -86,6 +86,10 @@ private:
unsigned findUsedSGPR(const MachineInstr &MI, int OpIndices[3]) const;
protected:
+ bool swapSourceModifiers(MachineInstr &MI,
+ MachineOperand &Src0, unsigned Src0OpName,
+ MachineOperand &Src1, unsigned Src1OpName) const;
+
MachineInstr *commuteInstructionImpl(MachineInstr &MI, bool NewMI,
unsigned OpIdx0,
unsigned OpIdx1) const override;
@@ -94,7 +98,18 @@ public:
enum TargetOperandFlags {
MO_NONE = 0,
- MO_GOTPCREL = 1
+ // MO_GOTPCREL -> symbol@GOTPCREL -> R_AMDGPU_GOTPCREL.
+ MO_GOTPCREL = 1,
+ // MO_GOTPCREL32_LO -> symbol@gotpcrel32@lo -> R_AMDGPU_GOTPCREL32_LO.
+ MO_GOTPCREL32 = 2,
+ MO_GOTPCREL32_LO = 2,
+ // MO_GOTPCREL32_HI -> symbol@gotpcrel32@hi -> R_AMDGPU_GOTPCREL32_HI.
+ MO_GOTPCREL32_HI = 3,
+ // MO_REL32_LO -> symbol@rel32@lo -> R_AMDGPU_REL32_LO.
+ MO_REL32 = 4,
+ MO_REL32_LO = 4,
+ // MO_REL32_HI -> symbol@rel32@hi -> R_AMDGPU_REL32_HI.
+ MO_REL32_HI = 5
};
explicit SIInstrInfo(const SISubtarget &);
@@ -144,23 +159,48 @@ public:
unsigned getMovOpcode(const TargetRegisterClass *DstRC) const;
LLVM_READONLY
- int commuteOpcode(const MachineInstr &MI) const;
+ int commuteOpcode(unsigned Opc) const;
+
+ LLVM_READONLY
+ inline int commuteOpcode(const MachineInstr &MI) const {
+ return commuteOpcode(MI.getOpcode());
+ }
bool findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx1,
unsigned &SrcOpIdx2) const override;
+ bool isBranchOffsetInRange(unsigned BranchOpc,
+ int64_t BrOffset) const override;
+
+ MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
+
+ unsigned insertIndirectBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock &NewDestBB,
+ const DebugLoc &DL,
+ int64_t BrOffset,
+ RegScavenger *RS = nullptr) const override;
+
+ bool analyzeBranchImpl(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock *&TBB,
+ MachineBasicBlock *&FBB,
+ SmallVectorImpl<MachineOperand> &Cond,
+ bool AllowModify) const;
+
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
- bool ReverseBranchCondition(
+ bool reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const override;
bool
@@ -332,6 +372,14 @@ public:
return get(Opcode).TSFlags & SIInstrFlags::FLAT;
}
+ static bool isEXP(const MachineInstr &MI) {
+ return MI.getDesc().TSFlags & SIInstrFlags::EXP;
+ }
+
+ bool isEXP(uint16_t Opcode) const {
+ return get(Opcode).TSFlags & SIInstrFlags::EXP;
+ }
+
static bool isWQM(const MachineInstr &MI) {
return MI.getDesc().TSFlags & SIInstrFlags::WQM;
}
@@ -356,6 +404,14 @@ public:
return get(Opcode).TSFlags & SIInstrFlags::VGPRSpill;
}
+ static bool isSGPRSpill(const MachineInstr &MI) {
+ return MI.getDesc().TSFlags & SIInstrFlags::SGPRSpill;
+ }
+
+ bool isSGPRSpill(uint16_t Opcode) const {
+ return get(Opcode).TSFlags & SIInstrFlags::SGPRSpill;
+ }
+
static bool isDPP(const MachineInstr &MI) {
return MI.getDesc().TSFlags & SIInstrFlags::DPP;
}
@@ -372,6 +428,32 @@ public:
return MI.getDesc().TSFlags & SIInstrFlags::VM_CNT;
}
+ static bool sopkIsZext(const MachineInstr &MI) {
+ return MI.getDesc().TSFlags & SIInstrFlags::SOPK_ZEXT;
+ }
+
+ bool sopkIsZext(uint16_t Opcode) const {
+ return get(Opcode).TSFlags & SIInstrFlags::SOPK_ZEXT;
+ }
+
+ /// \returns true if this is an s_store_dword* instruction. This is more
+ /// specific than than isSMEM && mayStore.
+ static bool isScalarStore(const MachineInstr &MI) {
+ return MI.getDesc().TSFlags & SIInstrFlags::SCALAR_STORE;
+ }
+
+ bool isScalarStore(uint16_t Opcode) const {
+ return get(Opcode).TSFlags & SIInstrFlags::SCALAR_STORE;
+ }
+
+ static bool isFixedSize(const MachineInstr &MI) {
+ return MI.getDesc().TSFlags & SIInstrFlags::FIXED_SIZE;
+ }
+
+ bool isFixedSize(uint16_t Opcode) const {
+ return get(Opcode).TSFlags & SIInstrFlags::FIXED_SIZE;
+ }
+
bool isVGPRCopy(const MachineInstr &MI) const {
assert(MI.isCopy());
unsigned Dest = MI.getOperand(0).getReg();
@@ -380,9 +462,96 @@ public:
return !RI.isSGPRReg(MRI, Dest);
}
+ static int operandBitWidth(uint8_t OperandType) {
+ switch (OperandType) {
+ case AMDGPU::OPERAND_REG_IMM_INT32:
+ case AMDGPU::OPERAND_REG_IMM_FP32:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT32:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP32:
+ return 32;
+ case AMDGPU::OPERAND_REG_IMM_INT64:
+ case AMDGPU::OPERAND_REG_IMM_FP64:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT64:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP64:
+ return 64;
+ case AMDGPU::OPERAND_REG_INLINE_C_INT16:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP16:
+ case AMDGPU::OPERAND_REG_IMM_INT16:
+ case AMDGPU::OPERAND_REG_IMM_FP16:
+ return 16;
+ default:
+ llvm_unreachable("unexpected operand type");
+ }
+ }
+
bool isInlineConstant(const APInt &Imm) const;
- bool isInlineConstant(const MachineOperand &MO, unsigned OpSize) const;
- bool isLiteralConstant(const MachineOperand &MO, unsigned OpSize) const;
+
+ bool isInlineConstant(const MachineOperand &MO, uint8_t OperandType) const;
+
+ bool isInlineConstant(const MachineOperand &MO,
+ const MCOperandInfo &OpInfo) const {
+ return isInlineConstant(MO, OpInfo.OperandType);
+ }
+
+ /// \p returns true if \p UseMO is substituted with \p DefMO in \p MI it would
+ /// be an inline immediate.
+ bool isInlineConstant(const MachineInstr &MI,
+ const MachineOperand &UseMO,
+ const MachineOperand &DefMO) const {
+ assert(UseMO.getParent() == &MI);
+ int OpIdx = MI.getOperandNo(&UseMO);
+ if (!MI.getDesc().OpInfo || OpIdx >= MI.getDesc().NumOperands) {
+ return false;
+ }
+
+ return isInlineConstant(DefMO, MI.getDesc().OpInfo[OpIdx]);
+ }
+
+ /// \p returns true if the operand \p OpIdx in \p MI is a valid inline
+ /// immediate.
+ bool isInlineConstant(const MachineInstr &MI, unsigned OpIdx) const {
+ const MachineOperand &MO = MI.getOperand(OpIdx);
+ return isInlineConstant(MO, MI.getDesc().OpInfo[OpIdx].OperandType);
+ }
+
+ bool isInlineConstant(const MachineInstr &MI, unsigned OpIdx,
+ const MachineOperand &MO) const {
+ if (!MI.getDesc().OpInfo || OpIdx >= MI.getDesc().NumOperands)
+ return false;
+
+ if (MI.isCopy()) {
+ unsigned Size = getOpSize(MI, OpIdx);
+ assert(Size == 8 || Size == 4);
+
+ uint8_t OpType = (Size == 8) ?
+ AMDGPU::OPERAND_REG_IMM_INT64 : AMDGPU::OPERAND_REG_IMM_INT32;
+ return isInlineConstant(MO, OpType);
+ }
+
+ return isInlineConstant(MO, MI.getDesc().OpInfo[OpIdx].OperandType);
+ }
+
+ bool isInlineConstant(const MachineOperand &MO) const {
+ const MachineInstr *Parent = MO.getParent();
+ return isInlineConstant(*Parent, Parent->getOperandNo(&MO));
+ }
+
+ bool isLiteralConstant(const MachineOperand &MO,
+ const MCOperandInfo &OpInfo) const {
+ return MO.isImm() && !isInlineConstant(MO, OpInfo.OperandType);
+ }
+
+ bool isLiteralConstant(const MachineInstr &MI, int OpIdx) const {
+ const MachineOperand &MO = MI.getOperand(OpIdx);
+ return MO.isImm() && !isInlineConstant(MI, OpIdx);
+ }
+
+ // Returns true if this operand could potentially require a 32-bit literal
+ // operand, but not necessarily. A FrameIndex for example could resolve to an
+ // inline immediate value that will not require an additional 4-bytes; this
+ // assumes that it will.
+ bool isLiteralConstantLike(const MachineOperand &MO,
+ const MCOperandInfo &OpInfo) const;
bool isImmOperandLegal(const MachineInstr &MI, unsigned OpNo,
const MachineOperand &MO) const;
@@ -394,7 +563,7 @@ public:
/// \brief Returns true if this operand uses the constant bus.
bool usesConstantBus(const MachineRegisterInfo &MRI,
const MachineOperand &MO,
- unsigned OpSize) const;
+ const MCOperandInfo &OpInfo) const;
/// \brief Return true if this instruction has any modifiers.
/// e.g. src[012]_mod, omod, clamp.
@@ -487,6 +656,12 @@ public:
void legalizeOperandsSMRD(MachineRegisterInfo &MRI, MachineInstr &MI) const;
+ void legalizeGenericOperand(MachineBasicBlock &InsertMBB,
+ MachineBasicBlock::iterator I,
+ const TargetRegisterClass *DstRC,
+ MachineOperand &Op, MachineRegisterInfo &MRI,
+ const DebugLoc &DL) const;
+
/// \brief Legalize all operands in this instruction. This function may
/// create new instruction and insert them before \p MI.
void legalizeOperands(MachineInstr &MI) const;
@@ -535,7 +710,17 @@ public:
return get(pseudoToMCOpcode(Opcode));
}
- unsigned getInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned isStackAccess(const MachineInstr &MI, int &FrameIndex) const;
+ unsigned isSGPRStackAccess(const MachineInstr &MI, int &FrameIndex) const;
+
+ unsigned isLoadFromStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const override;
+ unsigned isStoreToStackSlot(const MachineInstr &MI,
+ int &FrameIndex) const override;
+
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
+
+ bool mayAccessFlatAddressSpace(const MachineInstr &MI) const;
ArrayRef<std::pair<int, const char *>>
getSerializableTargetIndices() const override;
@@ -570,10 +755,19 @@ namespace AMDGPU {
LLVM_READONLY
int getAtomicNoRetOp(uint16_t Opcode);
+ LLVM_READONLY
+ int getSOPKOp(uint16_t Opcode);
+
const uint64_t RSRC_DATA_FORMAT = 0xf00000000000LL;
const uint64_t RSRC_ELEMENT_SIZE_SHIFT = (32 + 19);
const uint64_t RSRC_INDEX_STRIDE_SHIFT = (32 + 21);
const uint64_t RSRC_TID_ENABLE = UINT64_C(1) << (32 + 23);
+
+ // For MachineOperands.
+ enum TargetFlags {
+ TF_LONG_BRANCH_FORWARD = 1 << 0,
+ TF_LONG_BRANCH_BACKWARD = 1 << 1
+ };
} // End namespace AMDGPU
namespace SI {
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index 00f53e8..ebaefae 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -14,75 +14,6 @@ def isCIOnly : Predicate<"Subtarget->getGeneration() =="
def DisableInst : Predicate <"false">, AssemblerPredicate<"FeatureDisable">;
-class vop {
- field bits<9> SI3;
- field bits<10> VI3;
-}
-
-class vopc <bits<8> si, bits<8> vi = !add(0x40, si)> : vop {
- field bits<8> SI = si;
- field bits<8> VI = vi;
-
- field bits<9> SI3 = {0, si{7-0}};
- field bits<10> VI3 = {0, 0, vi{7-0}};
-}
-
-class vop1 <bits<8> si, bits<8> vi = si> : vop {
- field bits<8> SI = si;
- field bits<8> VI = vi;
-
- field bits<9> SI3 = {1, 1, si{6-0}};
- field bits<10> VI3 = !add(0x140, vi);
-}
-
-class vop2 <bits<6> si, bits<6> vi = si> : vop {
- field bits<6> SI = si;
- field bits<6> VI = vi;
-
- field bits<9> SI3 = {1, 0, 0, si{5-0}};
- field bits<10> VI3 = {0, 1, 0, 0, vi{5-0}};
-}
-
-// Specify a VOP2 opcode for SI and VOP3 opcode for VI
-// that doesn't have VOP2 encoding on VI
-class vop23 <bits<6> si, bits<10> vi> : vop2 <si> {
- let VI3 = vi;
-}
-
-class vop3 <bits<9> si, bits<10> vi = {0, si}> : vop {
- let SI3 = si;
- let VI3 = vi;
-}
-
-class sop1 <bits<8> si, bits<8> vi = si> {
- field bits<8> SI = si;
- field bits<8> VI = vi;
-}
-
-class sop2 <bits<7> si, bits<7> vi = si> {
- field bits<7> SI = si;
- field bits<7> VI = vi;
-}
-
-class sopk <bits<5> si, bits<5> vi = si> {
- field bits<5> SI = si;
- field bits<5> VI = vi;
-}
-
-class dsop <bits<8> si, bits<8> vi = si> {
- field bits<8> SI = si;
- field bits<8> VI = vi;
-}
-
-// Specify an SMRD opcode for SI and SMEM opcode for VI
-
-// FIXME: This should really be bits<5> si, Tablegen crashes if
-// parameter default value is other parameter with different bit size
-class smrd<bits<8> si, bits<8> vi = si> {
- field bits<5> SI = si{4-0};
- field bits<8> VI = vi;
-}
-
// Execpt for the NONE field, this must be kept in sync with the
// SIEncodingFamily enum in AMDGPUInstrInfo.cpp
def SIEncodingFamily {
@@ -127,6 +58,19 @@ def SItbuffer_store : SDNode<"AMDGPUISD::TBUFFER_STORE_FORMAT",
[SDNPMayStore, SDNPMemOperand, SDNPHasChain]
>;
+def SDTBufferLoad : SDTypeProfile<1, 5,
+ [ // vdata
+ SDTCisVT<1, v4i32>, // rsrc
+ SDTCisVT<2, i32>, // vindex
+ SDTCisVT<3, i32>, // offset
+ SDTCisVT<4, i1>, // glc
+ SDTCisVT<5, i1>]>; // slc
+
+def SIbuffer_load : SDNode <"AMDGPUISD::BUFFER_LOAD", SDTBufferLoad,
+ [SDNPMemOperand, SDNPHasChain, SDNPMayLoad]>;
+def SIbuffer_load_format : SDNode <"AMDGPUISD::BUFFER_LOAD_FORMAT", SDTBufferLoad,
+ [SDNPMemOperand, SDNPHasChain, SDNPMayLoad]>;
+
def SIload_input : SDNode<"AMDGPUISD::LOAD_INPUT",
SDTypeProfile<1, 3, [SDTCisVT<0, v4f32>, SDTCisVT<1, v4i32>, SDTCisVT<2, i16>,
SDTCisVT<3, i32>]>
@@ -143,72 +87,15 @@ def SIsampled : SDSample<"AMDGPUISD::SAMPLED">;
def SIsamplel : SDSample<"AMDGPUISD::SAMPLEL">;
def SIpc_add_rel_offset : SDNode<"AMDGPUISD::PC_ADD_REL_OFFSET",
- SDTypeProfile<1, 1, [SDTCisVT<0, iPTR>, SDTCisSameAs<0,1>]>
+ SDTypeProfile<1, 2, [SDTCisVT<0, iPTR>, SDTCisSameAs<0,1>, SDTCisSameAs<0,2>]>
>;
//===----------------------------------------------------------------------===//
-// PatFrags for FLAT instructions
-//===----------------------------------------------------------------------===//
-
-class flat_ld <SDPatternOperator ld> : PatFrag<(ops node:$ptr),
- (ld node:$ptr), [{
- const MemSDNode *LD = cast<MemSDNode>(N);
- return LD->getAddressSpace() == AMDGPUAS::FLAT_ADDRESS ||
- LD->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS ||
- LD->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS;
-}]>;
-
-def flat_load : flat_ld <load>;
-def atomic_flat_load : flat_ld<atomic_load>;
-def flat_az_extloadi8 : flat_ld <az_extloadi8>;
-def flat_sextloadi8 : flat_ld <sextloadi8>;
-def flat_az_extloadi16 : flat_ld <az_extloadi16>;
-def flat_sextloadi16 : flat_ld <sextloadi16>;
-
-class flat_st <SDPatternOperator st> : PatFrag<(ops node:$val, node:$ptr),
- (st node:$val, node:$ptr), [{
- const MemSDNode *ST = cast<MemSDNode>(N);
- return ST->getAddressSpace() == AMDGPUAS::FLAT_ADDRESS ||
- ST->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS;
-}]>;
-
-def flat_store: flat_st <store>;
-def atomic_flat_store: flat_st <atomic_store>;
-def flat_truncstorei8 : flat_st <truncstorei8>;
-def flat_truncstorei16 : flat_st <truncstorei16>;
-
-class MubufLoad <SDPatternOperator op> : PatFrag <
- (ops node:$ptr), (op node:$ptr), [{
-
- const MemSDNode *LD = cast<MemSDNode>(N);
- return LD->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS ||
- LD->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS;
-}]>;
-
-def mubuf_load : MubufLoad <load>;
-def mubuf_az_extloadi8 : MubufLoad <az_extloadi8>;
-def mubuf_sextloadi8 : MubufLoad <sextloadi8>;
-def mubuf_az_extloadi16 : MubufLoad <az_extloadi16>;
-def mubuf_sextloadi16 : MubufLoad <sextloadi16>;
-
-def mubuf_load_atomic : MubufLoad <atomic_load>;
-
-def smrd_load : PatFrag <(ops node:$ptr), (load node:$ptr), [{
- auto Ld = cast<LoadSDNode>(N);
- return Ld->getAlignment() >= 4 &&
- Ld->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS &&
- static_cast<const SITargetLowering *>(getTargetLowering())->isMemOpUniform(N);
-}]>;
-
-//===----------------------------------------------------------------------===//
// PatFrags for global memory operations
//===----------------------------------------------------------------------===//
-def atomic_inc_global : global_binary_atomic_op<SIatomic_inc>;
-def atomic_dec_global : global_binary_atomic_op<SIatomic_dec>;
-
-def atomic_inc_flat : flat_binary_atomic_op<SIatomic_inc>;
-def atomic_dec_flat : flat_binary_atomic_op<SIatomic_dec>;
+defm atomic_inc_global : global_binary_atomic_op<SIatomic_inc>;
+defm atomic_dec_global : global_binary_atomic_op<SIatomic_dec>;
//===----------------------------------------------------------------------===//
// SDNodes and PatFrag for local loads and stores to enable s_mov_b32 m0, -1
@@ -338,36 +225,6 @@ def si_atomic_cmp_swap_glue : SDNode <"ISD::ATOMIC_CMP_SWAP", SDTAtomic3,
defm si_atomic_cmp_swap : AtomicCmpSwapLocal <si_atomic_cmp_swap_glue>;
-// Transformation function, extract the lower 32bit of a 64bit immediate
-def LO32 : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(N->getZExtValue() & 0xffffffff, SDLoc(N),
- MVT::i32);
-}]>;
-
-def LO32f : SDNodeXForm<fpimm, [{
- APInt V = N->getValueAPF().bitcastToAPInt().trunc(32);
- return CurDAG->getTargetConstantFP(APFloat(APFloat::IEEEsingle, V), MVT::f32);
-}]>;
-
-// Transformation function, extract the upper 32bit of a 64bit immediate
-def HI32 : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(N->getZExtValue() >> 32, SDLoc(N), MVT::i32);
-}]>;
-
-def HI32f : SDNodeXForm<fpimm, [{
- APInt V = N->getValueAPF().bitcastToAPInt().lshr(32).trunc(32);
- return CurDAG->getTargetConstantFP(APFloat(APFloat::IEEEsingle, V), SDLoc(N),
- MVT::f32);
-}]>;
-
-def IMM8bitDWORD : PatLeaf <(imm),
- [{return (N->getZExtValue() & ~0x3FC) == 0;}]
->;
-
-def as_dword_i32imm : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(N->getZExtValue() >> 2, SDLoc(N), MVT::i32);
-}]>;
-
def as_i1imm : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(N->getZExtValue(), SDLoc(N), MVT::i1);
}]>;
@@ -394,24 +251,17 @@ return CurDAG->getTargetConstant(
N->getValueAPF().bitcastToAPInt().getZExtValue(), SDLoc(N), MVT::i32);
}]>;
+def frameindex_to_targetframeindex : SDNodeXForm<frameindex, [{
+ auto FI = cast<FrameIndexSDNode>(N);
+ return CurDAG->getTargetFrameIndex(FI->getIndex(), MVT::i32);
+}]>;
+
// Copied from the AArch64 backend:
def bitcast_fpimm_to_i64 : SDNodeXForm<fpimm, [{
return CurDAG->getTargetConstant(
N->getValueAPF().bitcastToAPInt().getZExtValue(), SDLoc(N), MVT::i64);
}]>;
-def IMM8bit : PatLeaf <(imm),
- [{return isUInt<8>(N->getZExtValue());}]
->;
-
-def IMM12bit : PatLeaf <(imm),
- [{return isUInt<12>(N->getZExtValue());}]
->;
-
-def IMM16bit : PatLeaf <(imm),
- [{return isUInt<16>(N->getZExtValue());}]
->;
-
def SIMM16bit : PatLeaf <(imm),
[{return isInt<16>(N->getSExtValue());}]
>;
@@ -420,15 +270,6 @@ def IMM20bit : PatLeaf <(imm),
[{return isUInt<20>(N->getZExtValue());}]
>;
-def IMM32bit : PatLeaf <(imm),
- [{return isUInt<32>(N->getZExtValue());}]
->;
-
-def mubuf_vaddr_offset : PatFrag<
- (ops node:$ptr, node:$offset, node:$imm_offset),
- (add (add node:$ptr, node:$offset), node:$imm_offset)
->;
-
class InlineImm <ValueType vt> : PatLeaf <(vt imm), [{
return isInlineImmediate(N);
}]>;
@@ -437,29 +278,31 @@ class InlineFPImm <ValueType vt> : PatLeaf <(vt fpimm), [{
return isInlineImmediate(N);
}]>;
-class SGPRImm <dag frag> : PatLeaf<frag, [{
+class VGPRImm <dag frag> : PatLeaf<frag, [{
if (Subtarget->getGeneration() < SISubtarget::SOUTHERN_ISLANDS) {
return false;
}
const SIRegisterInfo *SIRI =
static_cast<const SIRegisterInfo *>(Subtarget->getRegisterInfo());
+ unsigned Limit = 0;
for (SDNode::use_iterator U = N->use_begin(), E = SDNode::use_end();
- U != E; ++U) {
+ Limit < 10 && U != E; ++U, ++Limit) {
const TargetRegisterClass *RC = getOperandRegClass(*U, U.getOperandNo());
- if (RC && SIRI->isSGPRClass(RC))
- return true;
+
+ // If the register class is unknown, it could be an unknown
+ // register class that needs to be an SGPR, e.g. an inline asm
+ // constraint
+ if (!RC || SIRI->isSGPRClass(RC))
+ return false;
}
- return false;
+
+ return Limit < 10;
}]>;
//===----------------------------------------------------------------------===//
// Custom Operands
//===----------------------------------------------------------------------===//
-def FRAMEri32 : Operand<iPTR> {
- let MIOperandInfo = (ops i32:$ptr, i32imm:$index);
-}
-
def SoppBrTarget : AsmOperandClass {
let Name = "SoppBrTarget";
let ParserMethod = "parseSOppBrTarget";
@@ -467,14 +310,51 @@ def SoppBrTarget : AsmOperandClass {
def sopp_brtarget : Operand<OtherVT> {
let EncoderMethod = "getSOPPBrEncoding";
+ let DecoderMethod = "decodeSoppBrTarget";
let OperandType = "OPERAND_PCREL";
let ParserMatchClass = SoppBrTarget;
}
def si_ga : Operand<iPTR>;
+def InterpSlotMatchClass : AsmOperandClass {
+ let Name = "InterpSlot";
+ let PredicateMethod = "isInterpSlot";
+ let ParserMethod = "parseInterpSlot";
+ let RenderMethod = "addImmOperands";
+}
+
def InterpSlot : Operand<i32> {
let PrintMethod = "printInterpSlot";
+ let ParserMatchClass = InterpSlotMatchClass;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def AttrMatchClass : AsmOperandClass {
+ let Name = "Attr";
+ let PredicateMethod = "isInterpAttr";
+ let ParserMethod = "parseInterpAttr";
+ let RenderMethod = "addImmOperands";
+}
+
+// It appears to be necessary to create a separate operand for this to
+// be able to parse attr<num> with no space.
+def Attr : Operand<i32> {
+ let PrintMethod = "printInterpAttr";
+ let ParserMatchClass = AttrMatchClass;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def AttrChanMatchClass : AsmOperandClass {
+ let Name = "AttrChan";
+ let PredicateMethod = "isAttrChan";
+ let RenderMethod = "addImmOperands";
+}
+
+def AttrChan : Operand<i32> {
+ let PrintMethod = "printInterpAttrChan";
+ let ParserMatchClass = AttrChanMatchClass;
+ let OperandType = "OPERAND_IMMEDIATE";
}
def SendMsgMatchClass : AsmOperandClass {
@@ -484,6 +364,13 @@ def SendMsgMatchClass : AsmOperandClass {
let RenderMethod = "addImmOperands";
}
+def ExpTgtMatchClass : AsmOperandClass {
+ let Name = "ExpTgt";
+ let PredicateMethod = "isExpTgt";
+ let ParserMethod = "parseExpTgt";
+ let RenderMethod = "printExpTgt";
+}
+
def SendMsgImm : Operand<i32> {
let PrintMethod = "printSendMsg";
let ParserMatchClass = SendMsgMatchClass;
@@ -495,6 +382,11 @@ def SWaitMatchClass : AsmOperandClass {
let ParserMethod = "parseSWaitCntOps";
}
+def VReg32OrOffClass : AsmOperandClass {
+ let Name = "VReg32OrOff";
+ let ParserMethod = "parseVReg32OrOff";
+}
+
def WAIT_FLAG : Operand <i32> {
let ParserMatchClass = SWaitMatchClass;
let PrintMethod = "printWaitFlag";
@@ -503,6 +395,31 @@ def WAIT_FLAG : Operand <i32> {
include "SIInstrFormats.td"
include "VIInstrFormats.td"
+// ===----------------------------------------------------------------------===//
+// ExpSrc* Special cases for exp src operands which are printed as
+// "off" depending on en operand.
+// ===----------------------------------------------------------------------===//
+
+def ExpSrc0 : RegisterOperand<VGPR_32> {
+ let PrintMethod = "printExpSrc0";
+ let ParserMatchClass = VReg32OrOffClass;
+}
+
+def ExpSrc1 : RegisterOperand<VGPR_32> {
+ let PrintMethod = "printExpSrc1";
+ let ParserMatchClass = VReg32OrOffClass;
+}
+
+def ExpSrc2 : RegisterOperand<VGPR_32> {
+ let PrintMethod = "printExpSrc2";
+ let ParserMatchClass = VReg32OrOffClass;
+}
+
+def ExpSrc3 : RegisterOperand<VGPR_32> {
+ let PrintMethod = "printExpSrc3";
+ let ParserMatchClass = VReg32OrOffClass;
+}
+
class NamedMatchClass<string CName, bit Optional = 1> : AsmOperandClass {
let Name = "Imm"#CName;
let PredicateMethod = "is"#CName;
@@ -547,16 +464,15 @@ def gds : NamedOperandBit<"GDS", NamedMatchClass<"GDS">>;
def omod : NamedOperandU32<"OModSI", NamedMatchClass<"OModSI">>;
def clampmod : NamedOperandBit<"ClampSI", NamedMatchClass<"ClampSI">>;
-def smrd_offset : NamedOperandU32<"SMRDOffset", NamedMatchClass<"SMRDOffset">>;
-def smrd_literal_offset : NamedOperandU32<"SMRDLiteralOffset", NamedMatchClass<"SMRDLiteralOffset">>;
-
-def glc : NamedOperandBit<"GLC", NamedMatchClass<"GLC">>;
+def GLC : NamedOperandBit<"GLC", NamedMatchClass<"GLC">>;
def slc : NamedOperandBit<"SLC", NamedMatchClass<"SLC">>;
def tfe : NamedOperandBit<"TFE", NamedMatchClass<"TFE">>;
def unorm : NamedOperandBit<"UNorm", NamedMatchClass<"UNorm">>;
def da : NamedOperandBit<"DA", NamedMatchClass<"DA">>;
def r128 : NamedOperandBit<"R128", NamedMatchClass<"R128">>;
def lwe : NamedOperandBit<"LWE", NamedMatchClass<"LWE">>;
+def exp_compr : NamedOperandBit<"ExpCompr", NamedMatchClass<"ExpCompr">>;
+def exp_vm : NamedOperandBit<"ExpVM", NamedMatchClass<"ExpVM">>;
def dmask : NamedOperandU16<"DMask", NamedMatchClass<"DMask">>;
@@ -572,33 +488,96 @@ def dst_unused : NamedOperandU32<"SDWADstUnused", NamedMatchClass<"SDWADstUnused
def hwreg : NamedOperandU16<"Hwreg", NamedMatchClass<"Hwreg", 0>>;
+def exp_tgt : NamedOperandU8<"ExpTgt", NamedMatchClass<"ExpTgt", 0>> {
+
+}
+
} // End OperandType = "OPERAND_IMMEDIATE"
+class KImmMatchClass<int size> : AsmOperandClass {
+ let Name = "KImmFP"#size;
+ let PredicateMethod = "isKImmFP"#size;
+ let ParserMethod = "parseImm";
+ let RenderMethod = "addKImmFP"#size#"Operands";
+}
+
+class kimmOperand<ValueType vt> : Operand<vt> {
+ let OperandNamespace = "AMDGPU";
+ let OperandType = "OPERAND_KIMM"#vt.Size;
+ let PrintMethod = "printU"#vt.Size#"ImmOperand";
+ let ParserMatchClass = !cast<AsmOperandClass>("KImmFP"#vt.Size#"MatchClass");
+}
+
+// 32-bit VALU immediate operand that uses the constant bus.
+def KImmFP32MatchClass : KImmMatchClass<32>;
+def f32kimm : kimmOperand<i32>;
+
+// 32-bit VALU immediate operand with a 16-bit value that uses the
+// constant bus.
+def KImmFP16MatchClass : KImmMatchClass<16>;
+def f16kimm : kimmOperand<i16>;
+
def VOPDstS64 : VOPDstOperand <SReg_64>;
-def FPInputModsMatchClass : AsmOperandClass {
- let Name = "RegOrImmWithFPInputMods";
+class FPInputModsMatchClass <int opSize> : AsmOperandClass {
+ let Name = "RegOrImmWithFP"#opSize#"InputMods";
let ParserMethod = "parseRegOrImmWithFPInputMods";
- let PredicateMethod = "isRegOrImmWithInputMods";
+ let PredicateMethod = "isRegOrImmWithFP"#opSize#"InputMods";
}
+def FP16InputModsMatchClass : FPInputModsMatchClass<16>;
+def FP32InputModsMatchClass : FPInputModsMatchClass<32>;
+def FP64InputModsMatchClass : FPInputModsMatchClass<64>;
-def FPInputMods : Operand <i32> {
+class InputMods <AsmOperandClass matchClass> : Operand <i32> {
+ let OperandNamespace = "AMDGPU";
+ let OperandType = "OPERAND_INPUT_MODS";
+ let ParserMatchClass = matchClass;
+}
+
+class FPInputMods <FPInputModsMatchClass matchClass> : InputMods <matchClass> {
let PrintMethod = "printOperandAndFPInputMods";
- let ParserMatchClass = FPInputModsMatchClass;
}
-def IntInputModsMatchClass : AsmOperandClass {
- let Name = "RegOrImmWithIntInputMods";
+def FP16InputMods : FPInputMods<FP16InputModsMatchClass>;
+def FP32InputMods : FPInputMods<FP32InputModsMatchClass>;
+def FP64InputMods : FPInputMods<FP64InputModsMatchClass>;
+
+class IntInputModsMatchClass <int opSize> : AsmOperandClass {
+ let Name = "RegOrImmWithInt"#opSize#"InputMods";
let ParserMethod = "parseRegOrImmWithIntInputMods";
- let PredicateMethod = "isRegOrImmWithInputMods";
+ let PredicateMethod = "isRegOrImmWithInt"#opSize#"InputMods";
+}
+def Int32InputModsMatchClass : IntInputModsMatchClass<32>;
+def Int64InputModsMatchClass : IntInputModsMatchClass<64>;
+
+class IntInputMods <IntInputModsMatchClass matchClass> : InputMods <matchClass> {
+ let PrintMethod = "printOperandAndIntInputMods";
+}
+def Int32InputMods : IntInputMods<Int32InputModsMatchClass>;
+def Int64InputMods : IntInputMods<Int64InputModsMatchClass>;
+
+def FPVRegInputModsMatchClass : AsmOperandClass {
+ let Name = "VRegWithFPInputMods";
+ let ParserMethod = "parseRegWithFPInputMods";
+ let PredicateMethod = "isVReg";
}
-def IntInputMods: Operand <i32> {
+def FPVRegInputMods : InputMods <FPVRegInputModsMatchClass> {
+ let PrintMethod = "printOperandAndFPInputMods";
+}
+
+def IntVRegInputModsMatchClass : AsmOperandClass {
+ let Name = "VRegWithIntInputMods";
+ let ParserMethod = "parseRegWithIntInputMods";
+ let PredicateMethod = "isVReg";
+}
+
+def IntVRegInputMods : InputMods <IntVRegInputModsMatchClass> {
let PrintMethod = "printOperandAndIntInputMods";
- let ParserMatchClass = IntInputModsMatchClass;
}
+
//===----------------------------------------------------------------------===//
// Complex patterns
//===----------------------------------------------------------------------===//
@@ -606,24 +585,6 @@ def IntInputMods: Operand <i32> {
def DS1Addr1Offset : ComplexPattern<i32, 2, "SelectDS1Addr1Offset">;
def DS64Bit4ByteAligned : ComplexPattern<i32, 3, "SelectDS64Bit4ByteAligned">;
-def MUBUFAddr32 : ComplexPattern<i64, 9, "SelectMUBUFAddr32">;
-def MUBUFAddr64 : ComplexPattern<i64, 7, "SelectMUBUFAddr64">;
-def MUBUFAddr64Atomic : ComplexPattern<i64, 5, "SelectMUBUFAddr64">;
-def FLATAtomic : ComplexPattern<i64, 3, "SelectFlat">;
-def MUBUFScratch : ComplexPattern<i64, 4, "SelectMUBUFScratch">;
-def MUBUFOffset : ComplexPattern<i64, 6, "SelectMUBUFOffset">;
-def MUBUFOffsetNoGLC : ComplexPattern<i64, 3, "SelectMUBUFOffset">;
-def MUBUFOffsetAtomic : ComplexPattern<i64, 4, "SelectMUBUFOffset">;
-def MUBUFIntrinsicOffset : ComplexPattern<i32, 2, "SelectMUBUFIntrinsicOffset">;
-def MUBUFIntrinsicVOffset : ComplexPattern<i32, 3, "SelectMUBUFIntrinsicVOffset">;
-
-def SMRDImm : ComplexPattern<i64, 2, "SelectSMRDImm">;
-def SMRDImm32 : ComplexPattern<i64, 2, "SelectSMRDImm32">;
-def SMRDSgpr : ComplexPattern<i64, 2, "SelectSMRDSgpr">;
-def SMRDBufferImm : ComplexPattern<i32, 1, "SelectSMRDBufferImm">;
-def SMRDBufferImm32 : ComplexPattern<i32, 1, "SelectSMRDBufferImm32">;
-def SMRDBufferSgpr : ComplexPattern<i32, 1, "SelectSMRDBufferSgpr">;
-
def MOVRELOffset : ComplexPattern<i32, 2, "SelectMOVRELOffset">;
def VOP3Mods0 : ComplexPattern<untyped, 4, "SelectVOP3Mods0">;
@@ -681,455 +642,44 @@ class SIMCInstr <string pseudo, int subtarget> {
// EXP classes
//===----------------------------------------------------------------------===//
-class EXPCommon : InstSI<
+class EXP_Helper<bit done, SDPatternOperator node = null_frag> : EXPCommon<
(outs),
- (ins i32imm:$en, i32imm:$tgt, i32imm:$compr, i32imm:$done, i32imm:$vm,
- VGPR_32:$src0, VGPR_32:$src1, VGPR_32:$src2, VGPR_32:$src3),
- "exp $en, $tgt, $compr, $done, $vm, $src0, $src1, $src2, $src3",
- [] > {
-
- let EXP_CNT = 1;
- let Uses = [EXEC];
- let SchedRW = [WriteExport];
-}
-
-multiclass EXP_m {
-
- let isPseudo = 1, isCodeGenOnly = 1 in {
- def "" : EXPCommon, SIMCInstr <"exp", SIEncodingFamily.NONE> ;
- }
-
- def _si : EXPCommon, SIMCInstr <"exp", SIEncodingFamily.SI>, EXPe {
- let DecoderNamespace="SICI";
- let DisableDecoder = DisableSIDecoder;
- }
-
- def _vi : EXPCommon, SIMCInstr <"exp", SIEncodingFamily.VI>, EXPe_vi {
- let DecoderNamespace="VI";
- let DisableDecoder = DisableVIDecoder;
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Scalar classes
-//===----------------------------------------------------------------------===//
-
-class SOP1_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- SOP1 <outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class SOP1_Real_si <sop1 op, string opName, dag outs, dag ins, string asm> :
- SOP1 <outs, ins, asm, []>,
- SOP1e <op.SI>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let isCodeGenOnly = 0;
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class SOP1_Real_vi <sop1 op, string opName, dag outs, dag ins, string asm> :
- SOP1 <outs, ins, asm, []>,
- SOP1e <op.VI>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let isCodeGenOnly = 0;
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass SOP1_m <sop1 op, string opName, dag outs, dag ins, string asm,
- list<dag> pattern> {
-
- def "" : SOP1_Pseudo <opName, outs, ins, pattern>;
-
- def _si : SOP1_Real_si <op, opName, outs, ins, asm>;
-
- def _vi : SOP1_Real_vi <op, opName, outs, ins, asm>;
-
-}
-
-multiclass SOP1_32 <sop1 op, string opName, list<dag> pattern> : SOP1_m <
- op, opName, (outs SReg_32:$sdst), (ins SSrc_32:$src0),
- opName#" $sdst, $src0", pattern
->;
-
-multiclass SOP1_64 <sop1 op, string opName, list<dag> pattern> : SOP1_m <
- op, opName, (outs SReg_64:$sdst), (ins SSrc_64:$src0),
- opName#" $sdst, $src0", pattern
->;
-
-// no input, 64-bit output.
-multiclass SOP1_64_0 <sop1 op, string opName, list<dag> pattern> {
- def "" : SOP1_Pseudo <opName, (outs SReg_64:$sdst), (ins), pattern>;
-
- def _si : SOP1_Real_si <op, opName, (outs SReg_64:$sdst), (ins),
- opName#" $sdst"> {
- let src0 = 0;
- }
-
- def _vi : SOP1_Real_vi <op, opName, (outs SReg_64:$sdst), (ins),
- opName#" $sdst"> {
- let src0 = 0;
- }
-}
-
-// 64-bit input, no output
-multiclass SOP1_1 <sop1 op, string opName, list<dag> pattern> {
- def "" : SOP1_Pseudo <opName, (outs), (ins SReg_64:$src0), pattern>;
-
- def _si : SOP1_Real_si <op, opName, (outs), (ins SReg_64:$src0),
- opName#" $src0"> {
- let sdst = 0;
- }
-
- def _vi : SOP1_Real_vi <op, opName, (outs), (ins SReg_64:$src0),
- opName#" $src0"> {
- let sdst = 0;
- }
-}
-
-// 64-bit input, 32-bit output.
-multiclass SOP1_32_64 <sop1 op, string opName, list<dag> pattern> : SOP1_m <
- op, opName, (outs SReg_32:$sdst), (ins SSrc_64:$src0),
- opName#" $sdst, $src0", pattern
->;
-
-// 32-bit input, 64-bit output.
-multiclass SOP1_64_32 <sop1 op, string opName, list<dag> pattern> : SOP1_m <
- op, opName, (outs SReg_64:$sdst), (ins SSrc_32:$src0),
- opName#" $sdst, $src0", pattern
->;
-
-class SOP2_Pseudo<string opName, dag outs, dag ins, list<dag> pattern> :
- SOP2<outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
- let Size = 4;
-
- // Pseudo instructions have no encodings, but adding this field here allows
- // us to do:
- // let sdst = xxx in {
- // for multiclasses that include both real and pseudo instructions.
- field bits<7> sdst = 0;
-}
-
-class SOP2_Real_si<sop2 op, string opName, dag outs, dag ins, string asm> :
- SOP2<outs, ins, asm, []>,
- SOP2e<op.SI>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class SOP2_Real_vi<sop2 op, string opName, dag outs, dag ins, string asm> :
- SOP2<outs, ins, asm, []>,
- SOP2e<op.VI>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass SOP2_m <sop2 op, string opName, dag outs, dag ins, string asm,
- list<dag> pattern> {
-
- def "" : SOP2_Pseudo <opName, outs, ins, pattern>;
-
- def _si : SOP2_Real_si <op, opName, outs, ins, asm>;
-
- def _vi : SOP2_Real_vi <op, opName, outs, ins, asm>;
-
-}
-
-multiclass SOP2_32 <sop2 op, string opName, list<dag> pattern> : SOP2_m <
- op, opName, (outs SReg_32:$sdst), (ins SSrc_32:$src0, SSrc_32:$src1),
- opName#" $sdst, $src0, $src1", pattern
->;
-
-multiclass SOP2_64 <sop2 op, string opName, list<dag> pattern> : SOP2_m <
- op, opName, (outs SReg_64:$sdst), (ins SSrc_64:$src0, SSrc_64:$src1),
- opName#" $sdst, $src0, $src1", pattern
->;
-
-multiclass SOP2_64_32 <sop2 op, string opName, list<dag> pattern> : SOP2_m <
- op, opName, (outs SReg_64:$sdst), (ins SSrc_64:$src0, SSrc_32:$src1),
- opName#" $sdst, $src0, $src1", pattern
->;
-
-multiclass SOP2_64_32_32 <sop2 op, string opName, list<dag> pattern> : SOP2_m <
- op, opName, (outs SReg_64:$sdst), (ins SSrc_32:$src0, SSrc_32:$src1),
- opName#" $sdst, $src0, $src1", pattern
->;
-
-class SOPC_Base <bits<7> op, RegisterOperand rc0, RegisterOperand rc1,
- string opName, list<dag> pattern = []> : SOPC <
- op, (outs), (ins rc0:$src0, rc1:$src1),
- opName#" $src0, $src1", pattern > {
- let Defs = [SCC];
-}
-class SOPC_Helper <bits<7> op, RegisterOperand rc, ValueType vt,
- string opName, PatLeaf cond> : SOPC_Base <
- op, rc, rc, opName,
- [(set SCC, (si_setcc_uniform vt:$src0, vt:$src1, cond))] > {
-}
-
-class SOPC_CMP_32<bits<7> op, string opName, PatLeaf cond = COND_NULL>
- : SOPC_Helper<op, SSrc_32, i32, opName, cond>;
-
-class SOPC_32<bits<7> op, string opName, list<dag> pattern = []>
- : SOPC_Base<op, SSrc_32, SSrc_32, opName, pattern>;
-
-class SOPC_64_32<bits<7> op, string opName, list<dag> pattern = []>
- : SOPC_Base<op, SSrc_64, SSrc_32, opName, pattern>;
-
-class SOPK_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- SOPK <outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class SOPK_Real_si <sopk op, string opName, dag outs, dag ins, string asm> :
- SOPK <outs, ins, asm, []>,
- SOPKe <op.SI>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
- let isCodeGenOnly = 0;
-}
-
-class SOPK_Real_vi <sopk op, string opName, dag outs, dag ins, string asm> :
- SOPK <outs, ins, asm, []>,
- SOPKe <op.VI>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
- let isCodeGenOnly = 0;
-}
-
-multiclass SOPK_m <sopk op, string opName, dag outs, dag ins, string opAsm,
- string asm = opName#opAsm> {
- def "" : SOPK_Pseudo <opName, outs, ins, []>;
-
- def _si : SOPK_Real_si <op, opName, outs, ins, asm>;
-
- def _vi : SOPK_Real_vi <op, opName, outs, ins, asm>;
-
-}
-
-multiclass SOPK_32 <sopk op, string opName, list<dag> pattern> {
- def "" : SOPK_Pseudo <opName, (outs SReg_32:$sdst), (ins u16imm:$simm16),
- pattern>;
-
- def _si : SOPK_Real_si <op, opName, (outs SReg_32:$sdst), (ins u16imm:$simm16),
- opName#" $sdst, $simm16">;
-
- def _vi : SOPK_Real_vi <op, opName, (outs SReg_32:$sdst), (ins u16imm:$simm16),
- opName#" $sdst, $simm16">;
-}
-
-multiclass SOPK_SCC <sopk op, string opName, list<dag> pattern> {
- def "" : SOPK_Pseudo <opName, (outs),
- (ins SReg_32:$src0, u16imm:$src1), pattern> {
- let Defs = [SCC];
- }
-
-
- def _si : SOPK_Real_si <op, opName, (outs),
- (ins SReg_32:$sdst, u16imm:$simm16), opName#" $sdst, $simm16"> {
- let Defs = [SCC];
- }
-
- def _vi : SOPK_Real_vi <op, opName, (outs),
- (ins SReg_32:$sdst, u16imm:$simm16), opName#" $sdst, $simm16"> {
- let Defs = [SCC];
- }
-}
-
-multiclass SOPK_32TIE <sopk op, string opName, list<dag> pattern> : SOPK_m <
- op, opName, (outs SReg_32:$sdst), (ins SReg_32:$src0, u16imm:$simm16),
- " $sdst, $simm16"
->;
-
-multiclass SOPK_IMM32 <sopk op, string opName, dag outs, dag ins,
- string argAsm, string asm = opName#argAsm> {
-
- def "" : SOPK_Pseudo <opName, outs, ins, []>;
-
- def _si : SOPK <outs, ins, asm, []>,
- SOPK64e <op.SI>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
- let isCodeGenOnly = 0;
- }
-
- def _vi : SOPK <outs, ins, asm, []>,
- SOPK64e <op.VI>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
- let isCodeGenOnly = 0;
- }
-}
-//===----------------------------------------------------------------------===//
-// SMRD classes
-//===----------------------------------------------------------------------===//
-
-class SMRD_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- SMRD <outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class SMRD_IMM_Real_si <bits<5> op, string opName, dag outs, dag ins,
- string asm> :
- SMRD <outs, ins, asm, []>,
- SMRD_IMMe <op>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class SMRD_SOFF_Real_si <bits<5> op, string opName, dag outs, dag ins,
- string asm> :
- SMRD <outs, ins, asm, []>,
- SMRD_SOFFe <op>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-
-class SMRD_IMM_Real_vi <bits<8> op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern = []> :
- SMRD <outs, ins, asm, pattern>,
- SMEM_IMMe_vi <op>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-class SMRD_SOFF_Real_vi <bits<8> op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern = []> :
- SMRD <outs, ins, asm, pattern>,
- SMEM_SOFFe_vi <op>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-
-multiclass SMRD_IMM_m <smrd op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern> {
-
- def "" : SMRD_Pseudo <opName, outs, ins, pattern>;
-
- def _si : SMRD_IMM_Real_si <op.SI, opName, outs, ins, asm>;
-
- // glc is only applicable to scalar stores, which are not yet
- // implemented.
- let glc = 0 in {
- def _vi : SMRD_IMM_Real_vi <op.VI, opName, outs, ins, asm>;
- }
-}
-
-multiclass SMRD_SOFF_m <smrd op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern> {
-
- def "" : SMRD_Pseudo <opName, outs, ins, pattern>;
-
- def _si : SMRD_SOFF_Real_si <op.SI, opName, outs, ins, asm>;
-
- // glc is only applicable to scalar stores, which are not yet
- // implemented.
- let glc = 0 in {
- def _vi : SMRD_SOFF_Real_vi <op.VI, opName, outs, ins, asm>;
- }
-}
-
-multiclass SMRD_Special <smrd op, string opName, dag outs,
- int sdst_ = ?,
- string opStr = "",
- list<dag> pattern = []> {
- let hasSideEffects = 1 in {
- def "" : SMRD_Pseudo <opName, outs, (ins), pattern>;
+ (ins exp_tgt:$tgt,
+ ExpSrc0:$src0, ExpSrc1:$src1, ExpSrc2:$src2, ExpSrc3:$src3,
+ exp_vm:$vm, exp_compr:$compr, i8imm:$en),
+ "exp$tgt $src0, $src1, $src2, $src3"#!if(done, " done", "")#"$compr$vm",
+ [(node (i8 timm:$en), (i1 timm:$vm), (i8 timm:$tgt), (i1 timm:$compr),
+ f32:$src0, f32:$src1, f32:$src2, f32:$src3)]> {
+ let AsmMatchConverter = "cvtExp";
+}
+
+// Split EXP instruction into EXP and EXP_DONE so we can set
+// mayLoad for done=1.
+multiclass EXP_m<bit done, SDPatternOperator node> {
+ let mayLoad = done in {
+ let isPseudo = 1, isCodeGenOnly = 1 in {
+ def "" : EXP_Helper<done, node>,
+ SIMCInstr <"exp"#!if(done, "_done", ""), SIEncodingFamily.NONE>;
+ }
- let sbase = 0, soff = 0, sdst = sdst_ in {
- def _si : SMRD_SOFF_Real_si <op.SI, opName, outs, (ins), opName#opStr>;
+ let done = done in {
+ def _si : EXP_Helper<done>,
+ SIMCInstr <"exp"#!if(done, "_done", ""), SIEncodingFamily.SI>,
+ EXPe {
+ let DecoderNamespace = "SICI";
+ let DisableDecoder = DisableSIDecoder;
+ }
- let glc = 0 in {
- def _vi : SMRD_SOFF_Real_vi <op.VI, opName, outs, (ins), opName#opStr>;
+ def _vi : EXP_Helper<done>,
+ SIMCInstr <"exp"#!if(done, "_done", ""), SIEncodingFamily.VI>,
+ EXPe_vi {
+ let DecoderNamespace = "VI";
+ let DisableDecoder = DisableVIDecoder;
}
}
}
}
-multiclass SMRD_Inval <smrd op, string opName,
- SDPatternOperator node> {
- let mayStore = 1 in {
- defm : SMRD_Special<op, opName, (outs), 0, "", [(node)]>;
- }
-}
-
-class SMEM_Inval <bits<8> op, string opName, SDPatternOperator node> :
- SMRD_SOFF_Real_vi<op, opName, (outs), (ins), opName, [(node)]> {
- let hasSideEffects = 1;
- let mayStore = 1;
- let sbase = 0;
- let sdst = 0;
- let glc = 0;
- let soff = 0;
-}
-
-class SMEM_Ret <bits<8> op, string opName, SDPatternOperator node> :
- SMRD_SOFF_Real_vi<op, opName, (outs SReg_64:$sdst), (ins),
- opName#" $sdst", [(set i64:$sdst, (node))]> {
- let hasSideEffects = 1;
- let mayStore = ?;
- let mayLoad = ?;
- let sbase = 0;
- let glc = 0;
- let soff = 0;
-}
-
-multiclass SMRD_Helper <smrd op, string opName, RegisterClass baseClass,
- RegisterClass dstClass> {
- defm _IMM : SMRD_IMM_m <
- op, opName#"_IMM", (outs dstClass:$sdst),
- (ins baseClass:$sbase, smrd_offset:$offset),
- opName#" $sdst, $sbase, $offset", []
- >;
-
- def _IMM_ci : SMRD <
- (outs dstClass:$sdst), (ins baseClass:$sbase, smrd_literal_offset:$offset),
- opName#" $sdst, $sbase, $offset", []>, SMRD_IMMe_ci <op.SI> {
- let AssemblerPredicates = [isCIOnly];
- let DecoderNamespace = "CI";
- }
-
- defm _SGPR : SMRD_SOFF_m <
- op, opName#"_SGPR", (outs dstClass:$sdst),
- (ins baseClass:$sbase, SReg_32:$soff),
- opName#" $sdst, $sbase, $soff", []
- >;
-}
-
//===----------------------------------------------------------------------===//
// Vector ALU classes
//===----------------------------------------------------------------------===//
@@ -1146,43 +696,99 @@ class getNumSrcArgs<ValueType Src0, ValueType Src1, ValueType Src2> {
// instructions for the given VT.
class getVALUDstForVT<ValueType VT> {
RegisterOperand ret = !if(!eq(VT.Size, 32), VOPDstOperand<VGPR_32>,
- !if(!eq(VT.Size, 64), VOPDstOperand<VReg_64>,
- !if(!eq(VT.Size, 16), VOPDstOperand<VGPR_32>,
- VOPDstOperand<SReg_64>))); // else VT == i1
+ !if(!eq(VT.Size, 128), VOPDstOperand<VReg_128>,
+ !if(!eq(VT.Size, 64), VOPDstOperand<VReg_64>,
+ !if(!eq(VT.Size, 16), VOPDstOperand<VGPR_32>,
+ VOPDstOperand<SReg_64>)))); // else VT == i1
}
// Returns the register class to use for source 0 of VOP[12C]
// instructions for the given VT.
class getVOPSrc0ForVT<ValueType VT> {
- RegisterOperand ret = !if(!eq(VT.Size, 64), VSrc_64, VSrc_32);
+ bit isFP = !if(!eq(VT.Value, f16.Value), 1,
+ !if(!eq(VT.Value, f32.Value), 1,
+ !if(!eq(VT.Value, f64.Value), 1,
+ 0)));
+ RegisterOperand ret = !if(isFP,
+ !if(!eq(VT.Size, 64), VSrc_f64, !if(!eq(VT.Size, 16), VSrc_f16, VSrc_f32)),
+ !if(!eq(VT.Size, 64), VSrc_b64, !if(!eq(VT.Size, 16), VSrc_b16, VSrc_b32)));
}
// Returns the vreg register class to use for source operand given VT
class getVregSrcForVT<ValueType VT> {
- RegisterClass ret = !if(!eq(VT.Size, 64), VReg_64, VGPR_32);
+ RegisterClass ret = !if(!eq(VT.Size, 128), VReg_128,
+ !if(!eq(VT.Size, 64), VReg_64, VGPR_32));
}
// Returns the register class to use for sources of VOP3 instructions for the
// given VT.
class getVOP3SrcForVT<ValueType VT> {
+ bit isFP = !if(!eq(VT.Value, f16.Value), 1,
+ !if(!eq(VT.Value, f32.Value), 1,
+ !if(!eq(VT.Value, f64.Value), 1,
+ 0)));
RegisterOperand ret =
- !if(!eq(VT.Size, 64),
- VCSrc_64,
- !if(!eq(VT.Value, i1.Value),
- SCSrc_64,
- VCSrc_32
- )
- );
+ !if(!eq(VT.Size, 128),
+ VSrc_128,
+ !if(!eq(VT.Size, 64),
+ !if(isFP,
+ VCSrc_f64,
+ VCSrc_b64),
+ !if(!eq(VT.Value, i1.Value),
+ SCSrc_b64,
+ !if(isFP,
+ !if(!eq(VT.Size, 16), VCSrc_f16, VCSrc_f32),
+ !if(!eq(VT.Size, 16), VCSrc_b16, VCSrc_b32)
+ )
+ )
+ )
+ );
}
// Returns 1 if the source arguments have modifiers, 0 if they do not.
// XXX - do f16 instructions?
-class hasModifiers<ValueType SrcVT> {
+class isFloatType<ValueType SrcVT> {
bit ret =
+ !if(!eq(SrcVT.Value, f16.Value), 1,
!if(!eq(SrcVT.Value, f32.Value), 1,
!if(!eq(SrcVT.Value, f64.Value), 1,
- 0));
+ 0)));
+}
+
+class isIntType<ValueType SrcVT> {
+ bit ret =
+ !if(!eq(SrcVT.Value, i16.Value), 1,
+ !if(!eq(SrcVT.Value, i32.Value), 1,
+ !if(!eq(SrcVT.Value, i64.Value), 1,
+ 0)));
+}
+
+
+// Return type of input modifiers operand for specified input operand
+class getSrcMod <ValueType VT> {
+ bit isFP = !if(!eq(VT.Value, f16.Value), 1,
+ !if(!eq(VT.Value, f32.Value), 1,
+ !if(!eq(VT.Value, f64.Value), 1,
+ 0)));
+ Operand ret = !if(!eq(VT.Size, 64),
+ !if(isFP, FP64InputMods, Int64InputMods),
+ !if(isFP,
+ !if(!eq(VT.Value, f16.Value),
+ FP16InputMods,
+ FP32InputMods
+ ),
+ Int32InputMods)
+ );
+}
+
+// Return type of input modifiers operand specified input operand for SDWA/DPP
+class getSrcModExt <ValueType VT> {
+ bit isFP = !if(!eq(VT.Value, f16.Value), 1,
+ !if(!eq(VT.Value, f32.Value), 1,
+ !if(!eq(VT.Value, f64.Value), 1,
+ 0)));
+ Operand ret = !if(isFP, FPVRegInputMods, IntVRegInputMods);
}
// Returns the input arguments for VOP[12C] instructions for the given SrcVT.
@@ -1195,7 +801,8 @@ class getIns32 <RegisterOperand Src0RC, RegisterClass Src1RC, int NumSrcArgs> {
// Returns the input arguments for VOP3 instructions for the given SrcVT.
class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
RegisterOperand Src2RC, int NumSrcArgs,
- bit HasModifiers> {
+ bit HasModifiers, Operand Src0Mod, Operand Src1Mod,
+ Operand Src2Mod> {
dag ret =
!if (!eq(NumSrcArgs, 0),
@@ -1205,7 +812,7 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
!if (!eq(NumSrcArgs, 1),
!if (!eq(HasModifiers, 1),
// VOP1 with modifiers
- (ins FPInputMods:$src0_modifiers, Src0RC:$src0,
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
clampmod:$clamp, omod:$omod)
/* else */,
// VOP1 without modifiers
@@ -1214,8 +821,8 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
!if (!eq(NumSrcArgs, 2),
!if (!eq(HasModifiers, 1),
// VOP 2 with modifiers
- (ins FPInputMods:$src0_modifiers, Src0RC:$src0,
- FPInputMods:$src1_modifiers, Src1RC:$src1,
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
+ Src1Mod:$src1_modifiers, Src1RC:$src1,
clampmod:$clamp, omod:$omod)
/* else */,
// VOP2 without modifiers
@@ -1224,9 +831,9 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
/* NumSrcArgs == 3 */,
!if (!eq(HasModifiers, 1),
// VOP3 with modifiers
- (ins FPInputMods:$src0_modifiers, Src0RC:$src0,
- FPInputMods:$src1_modifiers, Src1RC:$src1,
- FPInputMods:$src2_modifiers, Src2RC:$src2,
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
+ Src1Mod:$src1_modifiers, Src1RC:$src1,
+ Src2Mod:$src2_modifiers, Src2RC:$src2,
clampmod:$clamp, omod:$omod)
/* else */,
// VOP3 without modifiers
@@ -1235,7 +842,7 @@ class getIns64 <RegisterOperand Src0RC, RegisterOperand Src1RC,
}
class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
- bit HasModifiers> {
+ bit HasModifiers, Operand Src0Mod, Operand Src1Mod> {
dag ret = !if (!eq(NumSrcArgs, 0),
// VOP1 without input operands (V_NOP)
@@ -1244,7 +851,7 @@ class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
!if (!eq(NumSrcArgs, 1),
!if (!eq(HasModifiers, 1),
// VOP1_DPP with modifiers
- (ins FPInputMods:$src0_modifiers, Src0RC:$src0,
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl)
/* else */,
@@ -1255,8 +862,8 @@ class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
/* NumSrcArgs == 2 */,
!if (!eq(HasModifiers, 1),
// VOP2_DPP with modifiers
- (ins FPInputMods:$src0_modifiers, Src0RC:$src0,
- FPInputMods:$src1_modifiers, Src1RC:$src1,
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
+ Src1Mod:$src1_modifiers, Src1RC:$src1,
dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
bank_mask:$bank_mask, bound_ctrl:$bound_ctrl)
/* else */,
@@ -1268,49 +875,28 @@ class getInsDPP <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
}
class getInsSDWA <RegisterClass Src0RC, RegisterClass Src1RC, int NumSrcArgs,
- bit HasFloatModifiers, ValueType DstVT> {
+ bit HasFloatModifiers, Operand Src0Mod, Operand Src1Mod,
+ ValueType DstVT> {
dag ret = !if(!eq(NumSrcArgs, 0),
// VOP1 without input operands (V_NOP)
(ins),
!if(!eq(NumSrcArgs, 1),
- !if(HasFloatModifiers,
- // VOP1_SDWA with float modifiers
- (ins FPInputMods:$src0_fmodifiers, Src0RC:$src0,
- clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
- src0_sel:$src0_sel)
- /* else */,
- // VOP1_SDWA with sext modifier
- (ins IntInputMods:$src0_imodifiers, Src0RC:$src0,
- clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
- src0_sel:$src0_sel)
- /* endif */)
- /* NumSrcArgs == 2 */,
- !if(HasFloatModifiers,
- !if(!eq(DstVT.Size, 1),
- // VOPC_SDWA with float modifiers
- (ins FPInputMods:$src0_fmodifiers, Src0RC:$src0,
- FPInputMods:$src1_fmodifiers, Src1RC:$src1,
- clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel),
- // VOP2_SDWA or VOPC_SDWA with float modifiers
- (ins FPInputMods:$src0_fmodifiers, Src0RC:$src0,
- FPInputMods:$src1_fmodifiers, Src1RC:$src1,
- clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
- src0_sel:$src0_sel, src1_sel:$src1_sel)
- ),
- /* else */
- !if(!eq(DstVT.Size, 1),
- // VOPC_SDWA with sext modifiers
- (ins IntInputMods:$src0_imodifiers, Src0RC:$src0,
- IntInputMods:$src1_imodifiers, Src1RC:$src1,
- clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel),
- // VOP2_SDWA or VOPC_SDWA with sext modifier
- (ins IntInputMods:$src0_imodifiers, Src0RC:$src0,
- IntInputMods:$src1_imodifiers, Src1RC:$src1,
- clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
- src0_sel:$src0_sel, src1_sel:$src1_sel)
- )
- /* endif */)));
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
+ clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
+ src0_sel:$src0_sel),
+ !if(!eq(NumSrcArgs, 2),
+ !if(!eq(DstVT.Size, 1),
+ // VOPC_SDWA with modifiers
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
+ Src1Mod:$src1_modifiers, Src1RC:$src1,
+ clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel),
+ // VOP2_SDWA or VOPC_SDWA with modifiers
+ (ins Src0Mod:$src0_modifiers, Src0RC:$src0,
+ Src1Mod:$src1_modifiers, Src1RC:$src1,
+ clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
+ src0_sel:$src0_sel, src1_sel:$src1_sel)),
+ (ins)/* endif */)));
}
// Outs for DPP and SDWA
@@ -1374,8 +960,8 @@ class getAsmSDWA <bit HasDst, int NumSrcArgs, bit HasFloatModifiers,
" vcc", // use vcc token as dst for VOPC instructioins
"$vdst"),
"");
- string src0 = !if(HasFloatModifiers, "$src0_fmodifiers", "$src0_imodifiers");
- string src1 = !if(HasFloatModifiers, "$src1_fmodifiers", "$src1_imodifiers");
+ string src0 = "$src0_modifiers";
+ string src1 = "$src1_modifiers";
string args = !if(!eq(NumSrcArgs, 0),
"",
!if(!eq(NumSrcArgs, 1),
@@ -1414,6 +1000,14 @@ class getHasExt <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32,
);
}
+class BitOr<bit a, bit b> {
+ bit ret = !if(a, 1, !if(b, 1, 0));
+}
+
+class BitAnd<bit a, bit b> {
+ bit ret = !if(a, !if(b, 1, 0), 0);
+}
+
class VOPProfile <list<ValueType> _ArgVT> {
field list<ValueType> ArgVT = _ArgVT;
@@ -1434,11 +1028,41 @@ class VOPProfile <list<ValueType> _ArgVT> {
field RegisterClass Src1DPP = getVregSrcForVT<Src1VT>.ret;
field RegisterClass Src0SDWA = getVregSrcForVT<Src0VT>.ret;
field RegisterClass Src1SDWA = getVregSrcForVT<Src1VT>.ret;
+ field Operand Src0Mod = getSrcMod<Src0VT>.ret;
+ field Operand Src1Mod = getSrcMod<Src1VT>.ret;
+ field Operand Src2Mod = getSrcMod<Src2VT>.ret;
+ field Operand Src0ModDPP = getSrcModExt<Src0VT>.ret;
+ field Operand Src1ModDPP = getSrcModExt<Src1VT>.ret;
+ field Operand Src0ModSDWA = getSrcModExt<Src0VT>.ret;
+ field Operand Src1ModSDWA = getSrcModExt<Src1VT>.ret;
+
field bit HasDst = !if(!eq(DstVT.Value, untyped.Value), 0, 1);
field bit HasDst32 = HasDst;
+ field bit EmitDst = HasDst; // force dst encoding, see v_movreld_b32 special case
field int NumSrcArgs = getNumSrcArgs<Src0VT, Src1VT, Src2VT>.ret;
- field bit HasModifiers = hasModifiers<Src0VT>.ret;
+ field bit HasSrc0 = !if(!eq(Src0VT.Value, untyped.Value), 0, 1);
+ field bit HasSrc1 = !if(!eq(Src1VT.Value, untyped.Value), 0, 1);
+ field bit HasSrc2 = !if(!eq(Src2VT.Value, untyped.Value), 0, 1);
+
+ // TODO: Modifiers logic is somewhat adhoc here, to be refined later
+ field bit HasModifiers = isFloatType<Src0VT>.ret;
+
+ field bit HasSrc0FloatMods = isFloatType<Src0VT>.ret;
+ field bit HasSrc1FloatMods = isFloatType<Src1VT>.ret;
+ field bit HasSrc2FloatMods = isFloatType<Src2VT>.ret;
+
+ field bit HasSrc0IntMods = isIntType<Src0VT>.ret;
+ field bit HasSrc1IntMods = isIntType<Src1VT>.ret;
+ field bit HasSrc2IntMods = isIntType<Src2VT>.ret;
+
+ field bit HasSrc0Mods = HasModifiers;
+ field bit HasSrc1Mods = !if(HasModifiers, BitOr<HasSrc1FloatMods, HasSrc1IntMods>.ret, 0);
+ field bit HasSrc2Mods = !if(HasModifiers, BitOr<HasSrc2FloatMods, HasSrc2IntMods>.ret, 0);
+
+ field bit HasOMod = HasModifiers;
+ field bit HasClamp = HasModifiers;
+ field bit HasSDWAClamp = HasSrc0;
field bit HasExt = getHasExt<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret;
@@ -1449,13 +1073,16 @@ class VOPProfile <list<ValueType> _ArgVT> {
field dag Outs32 = Outs;
field dag Outs64 = Outs;
field dag OutsDPP = getOutsExt<HasDst, DstVT, DstRCDPP>.ret;
- field dag OutsSDWA = getOutsExt<HasDst, DstVT, DstRCDPP>.ret;
+ field dag OutsSDWA = getOutsExt<HasDst, DstVT, DstRCSDWA>.ret;
field dag Ins32 = getIns32<Src0RC32, Src1RC32, NumSrcArgs>.ret;
field dag Ins64 = getIns64<Src0RC64, Src1RC64, Src2RC64, NumSrcArgs,
- HasModifiers>.ret;
- field dag InsDPP = getInsDPP<Src0DPP, Src1DPP, NumSrcArgs, HasModifiers>.ret;
- field dag InsSDWA = getInsSDWA<Src0SDWA, Src1SDWA, NumSrcArgs, HasModifiers, DstVT>.ret;
+ HasModifiers, Src0Mod, Src1Mod, Src2Mod>.ret;
+ field dag InsDPP = getInsDPP<Src0DPP, Src1DPP, NumSrcArgs,
+ HasModifiers, Src0ModDPP, Src1ModDPP>.ret;
+ field dag InsSDWA = getInsSDWA<Src0SDWA, Src1SDWA, NumSrcArgs,
+ HasModifiers, Src0ModSDWA, Src1ModSDWA,
+ DstVT>.ret;
field string Asm32 = getAsm32<HasDst, NumSrcArgs, DstVT>.ret;
field string Asm64 = getAsm64<HasDst, NumSrcArgs, HasModifiers, DstVT>.ret;
@@ -1467,14 +1094,13 @@ class VOP_NO_EXT <VOPProfile p> : VOPProfile <p.ArgVT> {
let HasExt = 0;
}
-// FIXME: I think these F16/I16 profiles will need to use f16/i16 types in order
-// for the instruction patterns to work.
def VOP_F16_F16 : VOPProfile <[f16, f16, untyped, untyped]>;
-def VOP_F16_I16 : VOPProfile <[f16, i32, untyped, untyped]>;
-def VOP_I16_F16 : VOPProfile <[i32, f16, untyped, untyped]>;
+def VOP_F16_I16 : VOPProfile <[f16, i16, untyped, untyped]>;
+def VOP_I16_F16 : VOPProfile <[i16, f16, untyped, untyped]>;
def VOP_F16_F16_F16 : VOPProfile <[f16, f16, f16, untyped]>;
-def VOP_F16_F16_I16 : VOPProfile <[f16, f16, i32, untyped]>;
+def VOP_F16_F16_I16 : VOPProfile <[f16, f16, i16, untyped]>;
+def VOP_F16_F16_I32 : VOPProfile <[f16, f16, i32, untyped]>;
def VOP_I16_I16_I16 : VOPProfile <[i32, i32, i32, untyped]>;
def VOP_I16_I16_I16_I16 : VOPProfile <[i32, i32, i32, i32, untyped]>;
@@ -1492,6 +1118,7 @@ def VOP_I32_F32 : VOPProfile <[i32, f32, untyped, untyped]>;
def VOP_I32_F64 : VOPProfile <[i32, f64, untyped, untyped]>;
def VOP_I32_I32 : VOPProfile <[i32, i32, untyped, untyped]>;
+def VOP_F32_F32_F16 : VOPProfile <[f32, f32, f16, untyped]>;
def VOP_F32_F32_F32 : VOPProfile <[f32, f32, f32, untyped]>;
def VOP_F32_F32_I32 : VOPProfile <[f32, f32, i32, untyped]>;
def VOP_F64_F64_F64 : VOPProfile <[f64, f64, f64, untyped]>;
@@ -1500,181 +1127,21 @@ def VOP_I32_F32_F32 : VOPProfile <[i32, f32, f32, untyped]>;
def VOP_I32_F32_I32 : VOPProfile <[i32, f32, i32, untyped]>;
def VOP_I32_I32_I32 : VOPProfile <[i32, i32, i32, untyped]>;
-// Write out to vcc or arbitrary SGPR.
-def VOP2b_I32_I1_I32_I32 : VOPProfile<[i32, i32, i32, untyped]> {
- let Asm32 = "$vdst, vcc, $src0, $src1";
- let Asm64 = "$vdst, $sdst, $src0, $src1";
- let Outs32 = (outs DstRC:$vdst);
- let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
-}
-
-// Write out to vcc or arbitrary SGPR and read in from vcc or
-// arbitrary SGPR.
-def VOP2b_I32_I1_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> {
- // We use VCSrc_32 to exclude literal constants, even though the
- // encoding normally allows them since the implicit VCC use means
- // using one would always violate the constant bus
- // restriction. SGPRs are still allowed because it should
- // technically be possible to use VCC again as src0.
- let Src0RC32 = VCSrc_32;
- let Asm32 = "$vdst, vcc, $src0, $src1, vcc";
- let Asm64 = "$vdst, $sdst, $src0, $src1, $src2";
- let Outs32 = (outs DstRC:$vdst);
- let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
-
- // Suppress src2 implied by type since the 32-bit encoding uses an
- // implicit VCC use.
- let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1);
-}
-
-// Read in from vcc or arbitrary SGPR
-def VOP2e_I32_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> {
- let Src0RC32 = VCSrc_32; // See comment in def VOP2b_I32_I1_I32_I32_I1 above.
- let Asm32 = "$vdst, $src0, $src1, vcc";
- let Asm64 = "$vdst, $src0, $src1, $src2";
- let Outs32 = (outs DstRC:$vdst);
- let Outs64 = (outs DstRC:$vdst);
-
- // Suppress src2 implied by type since the 32-bit encoding uses an
- // implicit VCC use.
- let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1);
-}
-
-class VOP3b_Profile<ValueType vt> : VOPProfile<[vt, vt, vt, vt]> {
- let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
- let Asm64 = "$vdst, $sdst, $src0_modifiers, $src1_modifiers, $src2_modifiers"#"$clamp"#"$omod";
-}
-
-def VOP3b_F32_I1_F32_F32_F32 : VOP3b_Profile<f32> {
- // FIXME: Hack to stop printing _e64
- let DstRC = RegisterOperand<VGPR_32>;
-}
-
-def VOP3b_F64_I1_F64_F64_F64 : VOP3b_Profile<f64> {
- // FIXME: Hack to stop printing _e64
- let DstRC = RegisterOperand<VReg_64>;
-}
-
-// VOPC instructions are a special case because for the 32-bit
-// encoding, we want to display the implicit vcc write as if it were
-// an explicit $dst.
-class VOPC_Profile<ValueType vt0, ValueType vt1 = vt0> : VOPProfile <[i1, vt0, vt1, untyped]> {
- let Asm32 = "vcc, $src0, $src1";
- // The destination for 32-bit encoding is implicit.
- let HasDst32 = 0;
- let Outs64 = (outs DstRC:$sdst);
-}
-
-class VOPC_Class_Profile<ValueType vt> : VOPC_Profile<vt, i32> {
- let Ins64 = (ins FPInputMods:$src0_modifiers, Src0RC64:$src0, Src1RC64:$src1);
- let Asm64 = "$sdst, $src0_modifiers, $src1";
- let InsSDWA = (ins FPInputMods:$src0_fmodifiers, Src0RC64:$src0,
- IntInputMods:$src1_imodifiers, Src1RC64:$src1,
- clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel);
- let AsmSDWA = " vcc, $src0_fmodifiers, $src1_imodifiers$clamp $src0_sel $src1_sel";
-
-}
-
-def VOPC_I1_F32_F32 : VOPC_Profile<f32>;
-def VOPC_I1_F64_F64 : VOPC_Profile<f64>;
-def VOPC_I1_I32_I32 : VOPC_Profile<i32>;
-def VOPC_I1_I64_I64 : VOPC_Profile<i64>;
-
-def VOPC_I1_F32_I32 : VOPC_Class_Profile<f32>;
-def VOPC_I1_F64_I32 : VOPC_Class_Profile<f64>;
-
def VOP_I64_I64_I32 : VOPProfile <[i64, i64, i32, untyped]>;
def VOP_I64_I32_I64 : VOPProfile <[i64, i32, i64, untyped]>;
def VOP_I64_I64_I64 : VOPProfile <[i64, i64, i64, untyped]>;
+def VOP_F16_F32_F16_F32 : VOPProfile <[f16, f32, f16, f32]>;
+def VOP_F32_F32_F16_F16 : VOPProfile <[f32, f32, f16, f16]>;
def VOP_F32_F32_F32_F32 : VOPProfile <[f32, f32, f32, f32]>;
-def VOP_MADAK : VOPProfile <[f32, f32, f32, f32]> {
- field dag Ins32 = (ins VCSrc_32:$src0, VGPR_32:$src1, u32kimm:$imm);
- field string Asm32 = "$vdst, $src0, $src1, $imm";
- field bit HasExt = 0;
-}
-def VOP_MADMK : VOPProfile <[f32, f32, f32, f32]> {
- field dag Ins32 = (ins VCSrc_32:$src0, u32kimm:$imm, VGPR_32:$src1);
- field string Asm32 = "$vdst, $src0, $imm, $src1";
- field bit HasExt = 0;
-}
-def VOP_MAC : VOPProfile <[f32, f32, f32, f32]> {
- let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1, VGPR_32:$src2);
- let Ins64 = getIns64<Src0RC64, Src1RC64, RegisterOperand<VGPR_32>, 3,
- HasModifiers>.ret;
- let InsDPP = (ins FPInputMods:$src0_modifiers, Src0RC32:$src0,
- FPInputMods:$src1_modifiers, Src1RC32:$src1,
- VGPR_32:$src2, // stub argument
- dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
- bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
- let InsSDWA = (ins FPInputMods:$src0_fmodifiers, Src0RC32:$src0,
- FPInputMods:$src1_fmodifiers, Src1RC32:$src1,
- VGPR_32:$src2, // stub argument
- clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
- src0_sel:$src0_sel, src1_sel:$src1_sel);
- let Asm32 = getAsm32<1, 2, f32>.ret;
- let Asm64 = getAsm64<1, 2, HasModifiers, f32>.ret;
- let AsmDPP = getAsmDPP<1, 2, HasModifiers, f32>.ret;
- let AsmSDWA = getAsmSDWA<1, 2, HasModifiers, f32>.ret;
-}
def VOP_F64_F64_F64_F64 : VOPProfile <[f64, f64, f64, f64]>;
def VOP_I32_I32_I32_I32 : VOPProfile <[i32, i32, i32, i32]>;
def VOP_I64_I32_I32_I64 : VOPProfile <[i64, i32, i32, i64]>;
+def VOP_I32_F32_I32_I32 : VOPProfile <[i32, f32, i32, i32]>;
+def VOP_I64_I64_I32_I64 : VOPProfile <[i64, i64, i32, i64]>;
+def VOP_V4I32_I64_I32_V4I32 : VOPProfile <[v4i32, i64, i32, v4i32]>;
-// This class is used only with VOPC instructions. Use $sdst for out operand
-class SIInstAlias <string asm, Instruction inst, VOPProfile p> :
- InstAlias <asm, (inst)>, PredicateControl {
-
- field bit isCompare;
- field bit isCommutable;
-
- let ResultInst =
- !if (p.HasDst32,
- !if (!eq(p.NumSrcArgs, 0),
- // 1 dst, 0 src
- (inst p.DstRC:$sdst),
- !if (!eq(p.NumSrcArgs, 1),
- // 1 dst, 1 src
- (inst p.DstRC:$sdst, p.Src0RC32:$src0),
- !if (!eq(p.NumSrcArgs, 2),
- // 1 dst, 2 src
- (inst p.DstRC:$sdst, p.Src0RC32:$src0, p.Src1RC32:$src1),
- // else - unreachable
- (inst)))),
- // else
- !if (!eq(p.NumSrcArgs, 2),
- // 0 dst, 2 src
- (inst p.Src0RC32:$src0, p.Src1RC32:$src1),
- !if (!eq(p.NumSrcArgs, 1),
- // 0 dst, 1 src
- (inst p.Src0RC32:$src1),
- // else
- // 0 dst, 0 src
- (inst))));
-}
-
-class SIInstAliasSI <string asm, string op_name, VOPProfile p> :
- SIInstAlias <asm, !cast<Instruction>(op_name#"_e32_si"), p> {
- let AssemblerPredicate = SIAssemblerPredicate;
-}
-
-class SIInstAliasVI <string asm, string op_name, VOPProfile p> :
- SIInstAlias <asm, !cast<Instruction>(op_name#"_e32_vi"), p> {
- let AssemblerPredicates = [isVI];
-}
-
-multiclass SIInstAliasBuilder <string asm, VOPProfile p> {
-
- def : SIInstAliasSI <asm, NAME, p>;
-
- def : SIInstAliasVI <asm, NAME, p>;
-}
-
-class VOP <string opName> {
- string OpName = opName;
-}
-
-class VOP2_REV <string revOp, bit isOrig> {
+class Commutable_REV <string revOp, bit isOrig> {
string RevOp = revOp;
bit IsOrig = isOrig;
}
@@ -1684,832 +1151,6 @@ class AtomicNoRet <string noRetOp, bit isRet> {
bit IsRet = isRet;
}
-class VOP1_Pseudo <dag outs, dag ins, list<dag> pattern, string opName> :
- VOP1Common <outs, ins, "", pattern>,
- VOP <opName>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.NONE>,
- MnemonicAlias<opName#"_e32", opName> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-
- field bits<8> vdst;
- field bits<9> src0;
-}
-
-class VOP1_Real_si <string opName, vop1 op, dag outs, dag ins, string asm> :
- VOP1<op.SI, outs, ins, asm, []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.SI> {
- let AssemblerPredicate = SIAssemblerPredicate;
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class VOP1_Real_vi <string opName, vop1 op, dag outs, dag ins, string asm> :
- VOP1<op.VI, outs, ins, asm, []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass VOP1_m <vop1 op, string opName, VOPProfile p, list<dag> pattern,
- string asm = opName#p.Asm32> {
- def "" : VOP1_Pseudo <p.Outs, p.Ins32, pattern, opName>;
-
- def _si : VOP1_Real_si <opName, op, p.Outs, p.Ins32, asm>;
-
- def _vi : VOP1_Real_vi <opName, op, p.Outs, p.Ins32, asm>;
-
-}
-
-class VOP1_DPP <vop1 op, string opName, VOPProfile p> :
- VOP1_DPPe <op.VI>,
- VOP_DPP <p.OutsDPP, p.InsDPP, opName#p.AsmDPP, [], p.HasModifiers> {
- let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
- let DecoderNamespace = "DPP";
- let DisableDecoder = DisableVIDecoder;
- let src0_modifiers = !if(p.HasModifiers, ?, 0);
- let src1_modifiers = 0;
-}
-
-class SDWADisableFields <VOPProfile p> {
- bits<8> src0 = !if(!eq(p.NumSrcArgs, 0), 0, ?);
- bits<3> src0_sel = !if(!eq(p.NumSrcArgs, 0), 6, ?);
- bits<2> src0_fmodifiers = !if(!eq(p.NumSrcArgs, 0),
- 0,
- !if(p.HasModifiers, ?, 0));
- bits<1> src0_imodifiers = !if(!eq(p.NumSrcArgs, 0),
- 0,
- !if(p.HasModifiers, 0, ?));
- bits<3> src1_sel = !if(!eq(p.NumSrcArgs, 0), 6,
- !if(!eq(p.NumSrcArgs, 1), 6,
- ?));
- bits<2> src1_fmodifiers = !if(!eq(p.NumSrcArgs, 0), 0,
- !if(!eq(p.NumSrcArgs, 1), 0,
- !if(p.HasModifiers, ?, 0)));
- bits<1> src1_imodifiers = !if(!eq(p.NumSrcArgs, 0), 0,
- !if(!eq(p.NumSrcArgs, 1), 0,
- !if(p.HasModifiers, 0, ?)));
- bits<3> dst_sel = !if(p.HasDst, ?, 6);
- bits<2> dst_unused = !if(p.HasDst, ?, 2);
- bits<1> clamp = !if(!eq(p.NumSrcArgs, 0), 0, ?);
-}
-
-class VOP1_SDWA <vop1 op, string opName, VOPProfile p> :
- VOP1_SDWAe <op.VI>,
- VOP_SDWA <p.OutsSDWA, p.InsSDWA, opName#p.AsmSDWA, [], p.HasModifiers>,
- SDWADisableFields <p> {
- let AsmMatchConverter = "cvtSdwaVOP1";
- let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
- let DecoderNamespace = "SDWA";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass VOP1SI_m <vop1 op, string opName, VOPProfile p, list<dag> pattern,
- string asm = opName#p.Asm32> {
-
- def "" : VOP1_Pseudo <p.Outs, p.Ins32, pattern, opName>;
-
- def _si : VOP1_Real_si <opName, op, p.Outs, p.Ins32, asm>;
-}
-
-class VOP2_Pseudo <dag outs, dag ins, list<dag> pattern, string opName> :
- VOP2Common <outs, ins, "", pattern>,
- VOP <opName>,
- SIMCInstr<opName#"_e32", SIEncodingFamily.NONE>,
- MnemonicAlias<opName#"_e32", opName> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class VOP2_Real_si <string opName, vop2 op, dag outs, dag ins, string asm> :
- VOP2 <op.SI, outs, ins, opName#asm, []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class VOP2_Real_vi <string opName, vop2 op, dag outs, dag ins, string asm> :
- VOP2 <op.VI, outs, ins, opName#asm, []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass VOP2SI_m <vop2 op, string opName, VOPProfile p, list<dag> pattern,
- string revOp> {
-
- def "" : VOP2_Pseudo <p.Outs32, p.Ins32, pattern, opName>,
- VOP2_REV<revOp#"_e32", !eq(revOp, opName)>;
-
- def _si : VOP2_Real_si <opName, op, p.Outs32, p.Ins32, p.Asm32>;
-}
-
-multiclass VOP2_m <vop2 op, string opName, VOPProfile p, list <dag> pattern,
- string revOp> {
-
- def "" : VOP2_Pseudo <p.Outs32, p.Ins32, pattern, opName>,
- VOP2_REV<revOp#"_e32", !eq(revOp, opName)>;
-
- def _si : VOP2_Real_si <opName, op, p.Outs32, p.Ins32, p.Asm32>;
-
- def _vi : VOP2_Real_vi <opName, op, p.Outs32, p.Ins32, p.Asm32>;
-
-}
-
-class VOP2_DPP <vop2 op, string opName, VOPProfile p> :
- VOP2_DPPe <op.VI>,
- VOP_DPP <p.OutsDPP, p.InsDPP, opName#p.AsmDPP, [], p.HasModifiers> {
- let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
- let DecoderNamespace = "DPP";
- let DisableDecoder = DisableVIDecoder;
- let src0_modifiers = !if(p.HasModifiers, ?, 0);
- let src1_modifiers = !if(p.HasModifiers, ?, 0);
-}
-
-class VOP2_SDWA <vop2 op, string opName, VOPProfile p> :
- VOP2_SDWAe <op.VI>,
- VOP_SDWA <p.OutsSDWA, p.InsSDWA, opName#p.AsmSDWA, [], p.HasModifiers>,
- SDWADisableFields <p> {
- let AsmMatchConverter = "cvtSdwaVOP2";
- let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
- let DecoderNamespace = "SDWA";
- let DisableDecoder = DisableVIDecoder;
-}
-
-class VOP3DisableFields <bit HasSrc1, bit HasSrc2, bit HasModifiers> {
-
- bits<2> src0_modifiers = !if(HasModifiers, ?, 0);
- bits<2> src1_modifiers = !if(HasModifiers, !if(HasSrc1, ?, 0), 0);
- bits<2> src2_modifiers = !if(HasModifiers, !if(HasSrc2, ?, 0), 0);
- bits<2> omod = !if(HasModifiers, ?, 0);
- bits<1> clamp = !if(HasModifiers, ?, 0);
- bits<9> src1 = !if(HasSrc1, ?, 0);
- bits<9> src2 = !if(HasSrc2, ?, 0);
-}
-
-class VOP3DisableModFields <bit HasSrc0Mods,
- bit HasSrc1Mods = 0,
- bit HasSrc2Mods = 0,
- bit HasOutputMods = 0> {
- bits<2> src0_modifiers = !if(HasSrc0Mods, ?, 0);
- bits<2> src1_modifiers = !if(HasSrc1Mods, ?, 0);
- bits<2> src2_modifiers = !if(HasSrc2Mods, ?, 0);
- bits<2> omod = !if(HasOutputMods, ?, 0);
- bits<1> clamp = !if(HasOutputMods, ?, 0);
-}
-
-class VOP3_Pseudo <dag outs, dag ins, list<dag> pattern, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, "", pattern, HasMods, VOP3Only>,
- VOP <opName>,
- SIMCInstr<opName#"_e64", SIEncodingFamily.NONE>,
- MnemonicAlias<opName#"_e64", opName> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-
- field bit vdst;
- field bit src0;
-}
-
-class VOP3_Real_si <bits<9> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3e <op>,
- SIMCInstr<opName#"_e64", SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class VOP3_Real_vi <bits<10> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3e_vi <op>,
- SIMCInstr <opName#"_e64", SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-class VOP3_C_Real_si <bits<9> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3ce <op>,
- SIMCInstr<opName#"_e64", SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class VOP3_C_Real_vi <bits<10> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3ce_vi <op>,
- SIMCInstr <opName#"_e64", SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-class VOP3b_Real_si <bits<9> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3be <op>,
- SIMCInstr<opName#"_e64", SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class VOP3b_Real_vi <bits<10> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3be_vi <op>,
- SIMCInstr <opName#"_e64", SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-class VOP3e_Real_si <bits<9> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3e <op>,
- SIMCInstr<opName#"_e64", SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class VOP3e_Real_vi <bits<10> op, dag outs, dag ins, string asm, string opName,
- bit HasMods = 0, bit VOP3Only = 0> :
- VOP3Common <outs, ins, asm, [], HasMods, VOP3Only>,
- VOP3e_vi <op>,
- SIMCInstr <opName#"_e64", SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass VOP3_m <vop op, dag outs, dag ins, string asm, list<dag> pattern,
- string opName, int NumSrcArgs, bit HasMods = 1, bit VOP3Only = 0> {
-
- def "" : VOP3_Pseudo <outs, ins, pattern, opName>;
-
- def _si : VOP3_Real_si <op.SI3, outs, ins, asm, opName, HasMods, VOP3Only>,
- VOP3DisableFields<!if(!eq(NumSrcArgs, 1), 0, 1),
- !if(!eq(NumSrcArgs, 2), 0, 1),
- HasMods>;
- def _vi : VOP3_Real_vi <op.VI3, outs, ins, asm, opName, HasMods, VOP3Only>,
- VOP3DisableFields<!if(!eq(NumSrcArgs, 1), 0, 1),
- !if(!eq(NumSrcArgs, 2), 0, 1),
- HasMods>;
-}
-
-multiclass VOP3_1_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName, bit HasMods = 1> {
-
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods>;
-
- def _si : VOP3_Real_si <op.SI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<0, 0, HasMods>;
-
- def _vi : VOP3_Real_vi <op.VI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<0, 0, HasMods>;
-}
-
-multiclass VOP3SI_1_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName, bit HasMods = 1> {
-
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods>;
-
- def _si : VOP3_Real_si <op.SI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<0, 0, HasMods>;
- // No VI instruction. This class is for SI only.
-}
-
-multiclass VOP3_2_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName, string revOp,
- bit HasMods = 1> {
-
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods>,
- VOP2_REV<revOp#"_e64", !eq(revOp, opName)>;
-
- def _si : VOP3_Real_si <op.SI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<1, 0, HasMods>;
-
- def _vi : VOP3_Real_vi <op.VI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<1, 0, HasMods>;
-}
-
-multiclass VOP3SI_2_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName, string revOp,
- bit HasMods = 1> {
-
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods>,
- VOP2_REV<revOp#"_e64", !eq(revOp, opName)>;
-
- def _si : VOP3_Real_si <op.SI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<1, 0, HasMods>;
-
- // No VI instruction. This class is for SI only.
-}
-
-// Two operand VOP3b instruction that may have a 3rd SGPR bool operand
-// instead of an implicit VCC as in the VOP2b format.
-multiclass VOP3b_2_3_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName, string revOp,
- bit HasMods = 1, bit useSrc2Input = 0, bit VOP3Only = 0> {
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods, VOP3Only>;
-
- def _si : VOP3b_Real_si <op.SI3, outs, ins, asm, opName, HasMods, VOP3Only>,
- VOP3DisableFields<1, useSrc2Input, HasMods>;
-
- def _vi : VOP3b_Real_vi <op.VI3, outs, ins, asm, opName, HasMods, VOP3Only>,
- VOP3DisableFields<1, useSrc2Input, HasMods>;
-}
-
-// Same as VOP3b_2_3_m but no 2nd destination (sdst), e.g. v_cndmask_b32.
-multiclass VOP3e_2_3_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName, string revOp,
- bit HasMods = 1, bit useSrc2Input = 0, bit VOP3Only = 0> {
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods, VOP3Only>;
-
- def _si : VOP3e_Real_si <op.SI3, outs, ins, asm, opName, HasMods, VOP3Only>,
- VOP3DisableFields<1, useSrc2Input, HasMods>;
-
- def _vi : VOP3e_Real_vi <op.VI3, outs, ins, asm, opName, HasMods, VOP3Only>,
- VOP3DisableFields<1, useSrc2Input, HasMods>;
-}
-
-multiclass VOP3_C_m <vop op, dag outs, dag ins, string asm,
- list<dag> pattern, string opName,
- bit HasMods, bit defExec,
- string revOp, list<SchedReadWrite> sched> {
-
- def "" : VOP3_Pseudo <outs, ins, pattern, opName, HasMods>,
- VOP2_REV<revOp#"_e64", !eq(revOp, opName)> {
- let Defs = !if(defExec, [EXEC], []);
- let SchedRW = sched;
- }
-
- def _si : VOP3_C_Real_si <op.SI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<1, 0, HasMods> {
- let Defs = !if(defExec, [EXEC], []);
- let SchedRW = sched;
- }
-
- def _vi : VOP3_C_Real_vi <op.VI3, outs, ins, asm, opName, HasMods>,
- VOP3DisableFields<1, 0, HasMods> {
- let Defs = !if(defExec, [EXEC], []);
- let SchedRW = sched;
- }
-}
-
-// An instruction that is VOP2 on SI and VOP3 on VI, no modifiers.
-multiclass VOP2SI_3VI_m <vop3 op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern = []> {
- let isPseudo = 1, isCodeGenOnly = 1 in {
- def "" : VOPAnyCommon <outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE>;
- }
-
- def _si : VOP2 <op.SI3{5-0}, outs, ins, asm, []>,
- SIMCInstr <opName, SIEncodingFamily.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
- }
-
- def _vi : VOP3Common <outs, ins, asm, []>,
- VOP3e_vi <op.VI3>,
- VOP3DisableFields <1, 0, 0>,
- SIMCInstr <opName, SIEncodingFamily.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
- }
-}
-
-multiclass VOP1_Helper <vop1 op, string opName, VOPProfile p, list<dag> pat32,
- list<dag> pat64> {
-
- defm _e32 : VOP1_m <op, opName, p, pat32>;
-
- defm _e64 : VOP3_1_m <op, p.Outs, p.Ins64, opName#p.Asm64, pat64, opName,
- p.HasModifiers>;
-
- def _dpp : VOP1_DPP <op, opName, p>;
-
- def _sdwa : VOP1_SDWA <op, opName, p>;
-}
-
-multiclass VOP1Inst <vop1 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag> : VOP1_Helper <
- op, opName, P, [],
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst, (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0,
- i32:$src0_modifiers, i1:$clamp, i32:$omod))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0))])
->;
-
-multiclass VOP1InstSI <vop1 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag> {
-
- defm _e32 : VOP1SI_m <op, opName, P, []>;
-
- defm _e64 : VOP3SI_1_m <op, P.Outs, P.Ins64, opName#P.Asm64,
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst, (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0,
- i32:$src0_modifiers, i1:$clamp, i32:$omod))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0))]),
- opName, P.HasModifiers>;
-}
-
-multiclass VOP2_Helper <vop2 op, string opName, VOPProfile p, list<dag> pat32,
- list<dag> pat64, string revOp> {
-
- defm _e32 : VOP2_m <op, opName, p, pat32, revOp>;
-
- defm _e64 : VOP3_2_m <op, p.Outs, p.Ins64, opName#p.Asm64, pat64, opName,
- revOp, p.HasModifiers>;
-
- def _dpp : VOP2_DPP <op, opName, p>;
-
- def _sdwa : VOP2_SDWA <op, opName, p>;
-}
-
-multiclass VOP2Inst <vop2 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag,
- string revOp = opName> : VOP2_Helper <
- op, opName, P, [],
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]),
- revOp
->;
-
-multiclass VOP2InstSI <vop2 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag,
- string revOp = opName> {
-
- defm _e32 : VOP2SI_m <op, opName, P, [], revOp>;
-
- defm _e64 : VOP3SI_2_m <op, P.Outs, P.Ins64, opName#P.Asm64,
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]),
- opName, revOp, P.HasModifiers>;
-}
-
-multiclass VOP2e_Helper <vop2 op, string opName, VOPProfile p,
- list<dag> pat32, list<dag> pat64,
- string revOp, bit useSGPRInput> {
-
- let SchedRW = [Write32Bit] in {
- let Uses = !if(useSGPRInput, [VCC, EXEC], [EXEC]) in {
- defm _e32 : VOP2_m <op, opName, p, pat32, revOp>;
- }
-
- defm _e64 : VOP3e_2_3_m <op, p.Outs64, p.Ins64, opName#p.Asm64, pat64,
- opName, revOp, p.HasModifiers, useSGPRInput>;
- }
-}
-
-multiclass VOP2eInst <vop2 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag,
- string revOp = opName> : VOP2e_Helper <
- op, opName, P, [],
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]),
- revOp, !eq(P.NumSrcArgs, 3)
->;
-
-multiclass VOP2b_Helper <vop2 op, string opName, VOPProfile p,
- list<dag> pat32, list<dag> pat64,
- string revOp, bit useSGPRInput> {
-
- let SchedRW = [Write32Bit, WriteSALU] in {
- let Uses = !if(useSGPRInput, [VCC, EXEC], [EXEC]), Defs = [VCC] in {
- defm _e32 : VOP2_m <op, opName, p, pat32, revOp>;
- }
-
- defm _e64 : VOP3b_2_3_m <op, p.Outs64, p.Ins64, opName#p.Asm64, pat64,
- opName, revOp, p.HasModifiers, useSGPRInput>;
- }
-}
-
-multiclass VOP2bInst <vop2 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag,
- string revOp = opName> : VOP2b_Helper <
- op, opName, P, [],
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]),
- revOp, !eq(P.NumSrcArgs, 3)
->;
-
-// A VOP2 instruction that is VOP3-only on VI.
-multiclass VOP2_VI3_Helper <vop23 op, string opName, VOPProfile p,
- list<dag> pat32, list<dag> pat64, string revOp> {
-
- defm _e32 : VOP2SI_m <op, opName, p, pat32, revOp>;
-
- defm _e64 : VOP3_2_m <op, p.Outs, p.Ins64, opName#p.Asm64, pat64, opName,
- revOp, p.HasModifiers>;
-}
-
-multiclass VOP2_VI3_Inst <vop23 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag,
- string revOp = opName>
- : VOP2_VI3_Helper <
- op, opName, P, [],
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]),
- revOp
->;
-
-multiclass VOP2MADK <vop2 op, string opName, VOPProfile P, list<dag> pattern = []> {
-
- def "" : VOP2_Pseudo <P.Outs, P.Ins32, pattern, opName>;
-
-let isCodeGenOnly = 0 in {
- def _si : VOP2Common <P.Outs, P.Ins32,
- !strconcat(opName, P.Asm32), []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.SI>,
- VOP2_MADKe <op.SI> {
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
- }
-
- def _vi : VOP2Common <P.Outs, P.Ins32,
- !strconcat(opName, P.Asm32), []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.VI>,
- VOP2_MADKe <op.VI> {
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
- }
-} // End isCodeGenOnly = 0
-}
-
-class VOPC_Pseudo <dag ins, list<dag> pattern, string opName> :
- VOPCCommon <ins, "", pattern>,
- VOP <opName>,
- SIMCInstr<opName#"_e32", SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class VOPC_SDWA <vopc op, string opName, bit DefExec, VOPProfile p> :
- VOPC_SDWAe <op.VI>,
- VOP_SDWA <p.OutsSDWA, p.InsSDWA, opName#p.AsmSDWA, [], p.HasModifiers>,
- SDWADisableFields <p> {
- let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
- let hasSideEffects = DefExec;
- let AsmMatchConverter = "cvtSdwaVOPC";
- let AssemblerPredicates = !if(p.HasExt, [isVI], [DisableInst]);
- let DecoderNamespace = "SDWA";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass VOPC_m <vopc op, dag ins, string op_asm, list<dag> pattern,
- string opName, bit DefExec, VOPProfile p,
- list<SchedReadWrite> sched,
- string revOpName = "", string asm = opName#"_e32 "#op_asm,
- string alias_asm = opName#" "#op_asm> {
- def "" : VOPC_Pseudo <ins, pattern, opName>,
- VOP2_REV<revOpName#"_e32", !eq(revOpName, opName)> {
- let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
- let SchedRW = sched;
- let isConvergent = DefExec;
- }
-
- let AssemblerPredicates = [isSICI] in {
- def _si : VOPC<op.SI, ins, asm, []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.SI> {
- let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
- let isConvergent = DefExec;
- let SchedRW = sched;
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
- }
-
- } // End AssemblerPredicates = [isSICI]
-
- let AssemblerPredicates = [isVI] in {
- def _vi : VOPC<op.VI, ins, asm, []>,
- SIMCInstr <opName#"_e32", SIEncodingFamily.VI> {
- let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
- let isConvergent = DefExec;
- let SchedRW = sched;
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
- }
-
- } // End AssemblerPredicates = [isVI]
-
- defm : SIInstAliasBuilder<alias_asm, p>;
-}
-
-multiclass VOPC_Helper <vopc op, string opName, list<dag> pat32,
- list<dag> pat64, bit DefExec, string revOp,
- VOPProfile p, list<SchedReadWrite> sched> {
- defm _e32 : VOPC_m <op, p.Ins32, p.Asm32, pat32, opName, DefExec, p, sched,
- revOp>;
-
- defm _e64 : VOP3_C_m <op, (outs VOPDstS64:$sdst), p.Ins64, opName#p.Asm64, pat64,
- opName, p.HasModifiers, DefExec, revOp, sched>;
-
- def _sdwa : VOPC_SDWA <op, opName, DefExec, p>;
-}
-
-// Special case for class instructions which only have modifiers on
-// the 1st source operand.
-multiclass VOPC_Class_Helper <vopc op, string opName, list<dag> pat32,
- list<dag> pat64, bit DefExec, string revOp,
- VOPProfile p, list<SchedReadWrite> sched> {
- defm _e32 : VOPC_m <op, p.Ins32, p.Asm32, pat32, opName, DefExec, p, sched>;
-
- defm _e64 : VOP3_C_m <op, (outs VOPDstS64:$sdst), p.Ins64, opName#p.Asm64, pat64,
- opName, p.HasModifiers, DefExec, revOp, sched>,
- VOP3DisableModFields<1, 0, 0>;
-
- def _sdwa : VOPC_SDWA <op, opName, DefExec, p> {
- let src1_fmodifiers = 0;
- let src1_imodifiers = ?;
- }
-}
-
-multiclass VOPCInst <vopc op, string opName,
- VOPProfile P, PatLeaf cond = COND_NULL,
- string revOp = opName,
- bit DefExec = 0,
- list<SchedReadWrite> sched = [Write32Bit]> :
- VOPC_Helper <
- op, opName, [],
- !if(P.HasModifiers,
- [(set i1:$sdst,
- (setcc (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
- cond))],
- [(set i1:$sdst, (setcc P.Src0VT:$src0, P.Src1VT:$src1, cond))]),
- DefExec, revOp, P, sched
->;
-
-multiclass VOPCClassInst <vopc op, string opName, VOPProfile P,
- bit DefExec = 0,
- list<SchedReadWrite> sched> : VOPC_Class_Helper <
- op, opName, [],
- !if(P.HasModifiers,
- [(set i1:$sdst,
- (AMDGPUfp_class (P.Src0VT (VOP3Mods0Clamp0OMod P.Src0VT:$src0, i32:$src0_modifiers)), P.Src1VT:$src1))],
- [(set i1:$sdst, (AMDGPUfp_class P.Src0VT:$src0, P.Src1VT:$src1))]),
- DefExec, opName, P, sched
->;
-
-
-multiclass VOPC_F32 <vopc op, string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
- VOPCInst <op, opName, VOPC_I1_F32_F32, cond, revOp>;
-
-multiclass VOPC_F64 <vopc op, string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
- VOPCInst <op, opName, VOPC_I1_F64_F64, cond, revOp, 0, [WriteDoubleAdd]>;
-
-multiclass VOPC_I32 <vopc op, string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
- VOPCInst <op, opName, VOPC_I1_I32_I32, cond, revOp>;
-
-multiclass VOPC_I64 <vopc op, string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
- VOPCInst <op, opName, VOPC_I1_I64_I64, cond, revOp, 0, [Write64Bit]>;
-
-
-multiclass VOPCX <vopc op, string opName, VOPProfile P,
- PatLeaf cond = COND_NULL,
- list<SchedReadWrite> sched,
- string revOp = "">
- : VOPCInst <op, opName, P, cond, revOp, 1, sched>;
-
-multiclass VOPCX_F32 <vopc op, string opName, string revOp = opName> :
- VOPCX <op, opName, VOPC_I1_F32_F32, COND_NULL, [Write32Bit], revOp>;
-
-multiclass VOPCX_F64 <vopc op, string opName, string revOp = opName> :
- VOPCX <op, opName, VOPC_I1_F64_F64, COND_NULL, [WriteDoubleAdd], revOp>;
-
-multiclass VOPCX_I32 <vopc op, string opName, string revOp = opName> :
- VOPCX <op, opName, VOPC_I1_I32_I32, COND_NULL, [Write32Bit], revOp>;
-
-multiclass VOPCX_I64 <vopc op, string opName, string revOp = opName> :
- VOPCX <op, opName, VOPC_I1_I64_I64, COND_NULL, [Write64Bit], revOp>;
-
-
-multiclass VOPC_CLASS_F32 <vopc op, string opName> :
- VOPCClassInst <op, opName, VOPC_I1_F32_I32, 0, [Write32Bit]>;
-
-multiclass VOPCX_CLASS_F32 <vopc op, string opName> :
- VOPCClassInst <op, opName, VOPC_I1_F32_I32, 1, [Write32Bit]>;
-
-multiclass VOPC_CLASS_F64 <vopc op, string opName> :
- VOPCClassInst <op, opName, VOPC_I1_F64_I32, 0, [WriteDoubleAdd]>;
-
-multiclass VOPCX_CLASS_F64 <vopc op, string opName> :
- VOPCClassInst <op, opName, VOPC_I1_F64_I32, 1, [WriteDoubleAdd]>;
-
-
-multiclass VOP3_Helper <vop3 op, string opName, dag outs, dag ins, string asm,
- list<dag> pat, int NumSrcArgs, bit HasMods,
- bit VOP3Only = 0> : VOP3_m <
- op, outs, ins, opName#" "#asm, pat, opName, NumSrcArgs, HasMods, VOP3Only
->;
-
-multiclass VOP3Inst <vop3 op, string opName, VOPProfile P,
- SDPatternOperator node = null_frag, bit VOP3Only = 0> :
- VOP3_Helper <
- op, opName, (outs P.DstRC.RegClass:$vdst), P.Ins64, P.Asm64,
- !if(!eq(P.NumSrcArgs, 3),
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
- (P.Src2VT (VOP3Mods P.Src2VT:$src2, i32:$src2_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1,
- P.Src2VT:$src2))]),
- !if(!eq(P.NumSrcArgs, 2),
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))])
- /* P.NumSrcArgs == 1 */,
- !if(P.HasModifiers,
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod))))],
- [(set P.DstVT:$vdst, (node P.Src0VT:$src0))]))),
- P.NumSrcArgs, P.HasModifiers, VOP3Only
->;
-
-// Special case for v_div_fmas_{f32|f64}, since it seems to be the
-// only VOP instruction that implicitly reads VCC.
-multiclass VOP3_VCC_Inst <vop3 op, string opName,
- VOPProfile P,
- SDPatternOperator node = null_frag> : VOP3_Helper <
- op, opName,
- (outs P.DstRC.RegClass:$vdst),
- (ins FPInputMods:$src0_modifiers, P.Src0RC64:$src0,
- FPInputMods:$src1_modifiers, P.Src1RC64:$src1,
- FPInputMods:$src2_modifiers, P.Src2RC64:$src2,
- clampmod:$clamp,
- omod:$omod),
- "$vdst, $src0_modifiers, $src1_modifiers, $src2_modifiers"#"$clamp"#"$omod",
- [(set P.DstVT:$vdst,
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
- i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
- (P.Src2VT (VOP3Mods P.Src2VT:$src2, i32:$src2_modifiers)),
- (i1 VCC)))],
- 3, 1
->;
-
-multiclass VOP3bInst <vop op, string opName, VOPProfile P, list<dag> pattern = [], bit VOP3Only = 0> :
- VOP3b_2_3_m <
- op, P.Outs64, P.Ins64,
- opName#" "#P.Asm64, pattern,
- opName, "", 1, 1, VOP3Only
->;
-
-class Vop3ModPat<Instruction Inst, VOPProfile P, SDPatternOperator node> : Pat<
- (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)),
- (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
- (P.Src2VT (VOP3Mods P.Src2VT:$src2, i32:$src2_modifiers))),
- (Inst i32:$src0_modifiers, P.Src0VT:$src0,
- i32:$src1_modifiers, P.Src1VT:$src1,
- i32:$src2_modifiers, P.Src2VT:$src2,
- i1:$clamp,
- i32:$omod)>;
-
//===----------------------------------------------------------------------===//
// Interpolation opcodes
//===----------------------------------------------------------------------===//
@@ -2551,1052 +1192,6 @@ multiclass VINTRP_m <bits <2> op, dag outs, dag ins, string asm,
}
//===----------------------------------------------------------------------===//
-// Vector I/O classes
-//===----------------------------------------------------------------------===//
-
-class DS_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- DS <outs, ins, "", pattern>,
- SIMCInstr <opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class DS_Real_si <bits<8> op, string opName, dag outs, dag ins, string asm> :
- DS <outs, ins, asm, []>,
- DSe <op>,
- SIMCInstr <opName, SIEncodingFamily.SI> {
- let isCodeGenOnly = 0;
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace="SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class DS_Real_vi <bits<8> op, string opName, dag outs, dag ins, string asm> :
- DS <outs, ins, asm, []>,
- DSe_vi <op>,
- SIMCInstr <opName, SIEncodingFamily.VI> {
- let isCodeGenOnly = 0;
- let AssemblerPredicates = [isVI];
- let DecoderNamespace="VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-class DS_Off16_Real_si <bits<8> op, string opName, dag outs, dag ins, string asm> :
- DS_Real_si <op,opName, outs, ins, asm> {
-
- // Single load interpret the 2 i8imm operands as a single i16 offset.
- bits<16> offset;
- let offset0 = offset{7-0};
- let offset1 = offset{15-8};
-}
-
-class DS_Off16_Real_vi <bits<8> op, string opName, dag outs, dag ins, string asm> :
- DS_Real_vi <op, opName, outs, ins, asm> {
-
- // Single load interpret the 2 i8imm operands as a single i16 offset.
- bits<16> offset;
- let offset0 = offset{7-0};
- let offset1 = offset{15-8};
-}
-
-multiclass DS_1A_RET_ <dsop op, string opName, RegisterClass rc,
- dag outs = (outs rc:$vdst),
- dag ins = (ins VGPR_32:$addr, offset:$offset, gds:$gds),
- string asm = opName#" $vdst, $addr"#"$offset$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let data0 = 0, data1 = 0 in {
- def _si : DS_Off16_Real_si <op.SI, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op.VI, opName, outs, ins, asm>;
- }
-}
-
-// TODO: DS_1A_RET can be inherited from DS_1A_RET_ but its not working
-// for some reason. In fact we can remove this class if use dsop everywhere
-multiclass DS_1A_RET <bits<8> op, string opName, RegisterClass rc,
- dag outs = (outs rc:$vdst),
- dag ins = (ins VGPR_32:$addr, offset:$offset, gds:$gds),
- string asm = opName#" $vdst, $addr"#"$offset$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let data0 = 0, data1 = 0 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_1A_Off8_RET <bits<8> op, string opName, RegisterClass rc,
- dag outs = (outs rc:$vdst),
- dag ins = (ins VGPR_32:$addr, offset0:$offset0, offset1:$offset1,
- gds:$gds),
- string asm = opName#" $vdst, $addr"#"$offset0"#"$offset1$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let data0 = 0, data1 = 0, AsmMatchConverter = "cvtDSOffset01" in {
- def _si : DS_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_1A1D_NORET <bits<8> op, string opName, RegisterClass rc,
- dag outs = (outs),
- dag ins = (ins VGPR_32:$addr, rc:$data0, offset:$offset, gds:$gds),
- string asm = opName#" $addr, $data0"#"$offset$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>,
- AtomicNoRet<opName, 0>;
-
- let data1 = 0, vdst = 0 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_1A_Off8_NORET <bits<8> op, string opName,
- dag outs = (outs),
- dag ins = (ins VGPR_32:$addr,
- offset0:$offset0, offset1:$offset1, gds:$gds),
- string asm = opName#" $addr $offset0"#"$offset1$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let data0 = 0, data1 = 0, vdst = 0, AsmMatchConverter = "cvtDSOffset01" in {
- def _si : DS_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_1A2D_Off8_NORET <bits<8> op, string opName, RegisterClass rc,
- dag outs = (outs),
- dag ins = (ins VGPR_32:$addr, rc:$data0, rc:$data1,
- offset0:$offset0, offset1:$offset1, gds:$gds),
- string asm = opName#" $addr, $data0, $data1$offset0$offset1$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let vdst = 0, AsmMatchConverter = "cvtDSOffset01" in {
- def _si : DS_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_1A1D_RET <bits<8> op, string opName, RegisterClass rc,
- string noRetOp = "",
- dag outs = (outs rc:$vdst),
- dag ins = (ins VGPR_32:$addr, rc:$data0, offset:$offset, gds:$gds),
- string asm = opName#" $vdst, $addr, $data0"#"$offset$gds"> {
-
- let hasPostISelHook = 1 in {
- def "" : DS_Pseudo <opName, outs, ins, []>,
- AtomicNoRet<noRetOp, 1>;
-
- let data1 = 0 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- }
- }
-}
-
-multiclass DS_1A1D_PERMUTE <bits<8> op, string opName, RegisterClass rc,
- SDPatternOperator node = null_frag,
- dag outs = (outs rc:$vdst),
- dag ins = (ins VGPR_32:$addr, rc:$data0, offset:$offset),
- string asm = opName#" $vdst, $addr, $data0"#"$offset"> {
-
- let mayLoad = 0, mayStore = 0, isConvergent = 1 in {
- def "" : DS_Pseudo <opName, outs, ins,
- [(set i32:$vdst,
- (node (DS1Addr1Offset i32:$addr, i16:$offset), i32:$data0))]>;
-
- let data1 = 0, gds = 0 in {
- def "_vi" : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- }
- }
-}
-
-multiclass DS_1A2D_RET_m <bits<8> op, string opName, RegisterClass rc,
- string noRetOp = "", dag ins,
- dag outs = (outs rc:$vdst),
- string asm = opName#" $vdst, $addr, $data0, $data1"#"$offset"#"$gds"> {
-
- let hasPostISelHook = 1 in {
- def "" : DS_Pseudo <opName, outs, ins, []>,
- AtomicNoRet<noRetOp, 1>;
-
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_1A2D_RET <bits<8> op, string asm, RegisterClass rc,
- string noRetOp = "", RegisterClass src = rc> :
- DS_1A2D_RET_m <op, asm, rc, noRetOp,
- (ins VGPR_32:$addr, src:$data0, src:$data1,
- offset:$offset, gds:$gds)
->;
-
-multiclass DS_1A2D_NORET <bits<8> op, string opName, RegisterClass rc,
- string noRetOp = opName,
- dag outs = (outs),
- dag ins = (ins VGPR_32:$addr, rc:$data0, rc:$data1,
- offset:$offset, gds:$gds),
- string asm = opName#" $addr, $data0, $data1"#"$offset"#"$gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>,
- AtomicNoRet<noRetOp, 0>;
-
- let vdst = 0 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass DS_0A_RET <bits<8> op, string opName,
- dag outs = (outs VGPR_32:$vdst),
- dag ins = (ins offset:$offset, gds:$gds),
- string asm = opName#" $vdst"#"$offset"#"$gds"> {
-
- let mayLoad = 1, mayStore = 1 in {
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let addr = 0, data0 = 0, data1 = 0 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- } // end addr = 0, data0 = 0, data1 = 0
- } // end mayLoad = 1, mayStore = 1
-}
-
-multiclass DS_1A_RET_GDS <bits<8> op, string opName,
- dag outs = (outs VGPR_32:$vdst),
- dag ins = (ins VGPR_32:$addr, offset:$offset),
- string asm = opName#" $vdst, $addr"#"$offset gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let data0 = 0, data1 = 0, gds = 1 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- } // end data0 = 0, data1 = 0, gds = 1
-}
-
-multiclass DS_1A_GDS <bits<8> op, string opName,
- dag outs = (outs),
- dag ins = (ins VGPR_32:$addr),
- string asm = opName#" $addr gds"> {
-
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let vdst = 0, data0 = 0, data1 = 0, offset0 = 0, offset1 = 0, gds = 1 in {
- def _si : DS_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Real_vi <op, opName, outs, ins, asm>;
- } // end vdst = 0, data = 0, data1 = 0, gds = 1
-}
-
-multiclass DS_1A <bits<8> op, string opName,
- dag outs = (outs),
- dag ins = (ins VGPR_32:$addr, offset:$offset, gds:$gds),
- string asm = opName#" $addr"#"$offset"#"$gds"> {
-
- let mayLoad = 1, mayStore = 1 in {
- def "" : DS_Pseudo <opName, outs, ins, []>;
-
- let vdst = 0, data0 = 0, data1 = 0 in {
- def _si : DS_Off16_Real_si <op, opName, outs, ins, asm>;
- def _vi : DS_Off16_Real_vi <op, opName, outs, ins, asm>;
- } // let vdst = 0, data0 = 0, data1 = 0
- } // end mayLoad = 1, mayStore = 1
-}
-
-//===----------------------------------------------------------------------===//
-// MTBUF classes
-//===----------------------------------------------------------------------===//
-
-class MTBUF_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- MTBUF <outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class MTBUF_Real_si <bits<3> op, string opName, dag outs, dag ins,
- string asm> :
- MTBUF <outs, ins, asm, []>,
- MTBUFe <op>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let DecoderNamespace="SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class MTBUF_Real_vi <bits<4> op, string opName, dag outs, dag ins, string asm> :
- MTBUF <outs, ins, asm, []>,
- MTBUFe_vi <op>,
- SIMCInstr <opName, SIEncodingFamily.VI> {
- let DecoderNamespace="VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass MTBUF_m <bits<3> op, string opName, dag outs, dag ins, string asm,
- list<dag> pattern> {
-
- def "" : MTBUF_Pseudo <opName, outs, ins, pattern>;
-
- def _si : MTBUF_Real_si <op, opName, outs, ins, asm>;
-
- def _vi : MTBUF_Real_vi <{0, op{2}, op{1}, op{0}}, opName, outs, ins, asm>;
-
-}
-
-let mayStore = 1, mayLoad = 0 in {
-
-multiclass MTBUF_Store_Helper <bits<3> op, string opName,
- RegisterClass regClass> : MTBUF_m <
- op, opName, (outs),
- (ins regClass:$vdata, u16imm:$offset, i1imm:$offen, i1imm:$idxen, i1imm:$glc,
- i1imm:$addr64, i8imm:$dfmt, i8imm:$nfmt, VGPR_32:$vaddr,
- SReg_128:$srsrc, i1imm:$slc, i1imm:$tfe, SCSrc_32:$soffset),
- opName#" $vdata, $offset, $offen, $idxen, $glc, $addr64, $dfmt,"
- #" $nfmt, $vaddr, $srsrc, $slc, $tfe, $soffset", []
->;
-
-} // mayStore = 1, mayLoad = 0
-
-let mayLoad = 1, mayStore = 0 in {
-
-multiclass MTBUF_Load_Helper <bits<3> op, string opName,
- RegisterClass regClass> : MTBUF_m <
- op, opName, (outs regClass:$dst),
- (ins u16imm:$offset, i1imm:$offen, i1imm:$idxen, i1imm:$glc, i1imm:$addr64,
- i8imm:$dfmt, i8imm:$nfmt, VGPR_32:$vaddr, SReg_128:$srsrc,
- i1imm:$slc, i1imm:$tfe, SCSrc_32:$soffset),
- opName#" $dst, $offset, $offen, $idxen, $glc, $addr64, $dfmt,"
- #" $nfmt, $vaddr, $srsrc, $slc, $tfe, $soffset", []
->;
-
-} // mayLoad = 1, mayStore = 0
-
-//===----------------------------------------------------------------------===//
-// MUBUF classes
-//===----------------------------------------------------------------------===//
-
-class mubuf <bits<7> si, bits<7> vi = si> {
- field bits<7> SI = si;
- field bits<7> VI = vi;
-}
-
-let isCodeGenOnly = 0 in {
-
-class MUBUF_si <bits<7> op, dag outs, dag ins, string asm, list<dag> pattern> :
- MUBUF <outs, ins, asm, pattern>, MUBUFe <op> {
- let lds = 0;
-}
-
-} // End let isCodeGenOnly = 0
-
-class MUBUF_vi <bits<7> op, dag outs, dag ins, string asm, list<dag> pattern> :
- MUBUF <outs, ins, asm, pattern>, MUBUFe_vi <op> {
- let lds = 0;
-}
-
-class MUBUFAddr64Table <bit is_addr64, string suffix = ""> {
- bit IsAddr64 = is_addr64;
- string OpName = NAME # suffix;
-}
-
-class MUBUF_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- MUBUF <outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-
- // dummy fields, so that we can use let statements around multiclasses
- bits<1> offen;
- bits<1> idxen;
- bits<8> vaddr;
- bits<1> glc;
- bits<1> slc;
- bits<1> tfe;
- bits<8> soffset;
-}
-
-class MUBUF_Real_si <mubuf op, string opName, dag outs, dag ins,
- string asm> :
- MUBUF <outs, ins, asm, []>,
- MUBUFe <op.SI>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let lds = 0;
- let AssemblerPredicate = SIAssemblerPredicate;
- let DecoderNamespace="SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class MUBUF_Real_vi <mubuf op, string opName, dag outs, dag ins,
- string asm> :
- MUBUF <outs, ins, asm, []>,
- MUBUFe_vi <op.VI>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let lds = 0;
- let AssemblerPredicate = VIAssemblerPredicate;
- let DecoderNamespace="VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass MUBUF_m <mubuf op, string opName, dag outs, dag ins, string asm,
- list<dag> pattern> {
-
- def "" : MUBUF_Pseudo <opName, outs, ins, pattern>,
- MUBUFAddr64Table <0>;
-
- let DisableWQM = 1 in {
- def "_exact" : MUBUF_Pseudo <opName, outs, ins, []>;
- }
-
- let addr64 = 0, isCodeGenOnly = 0 in {
- def _si : MUBUF_Real_si <op, opName, outs, ins, asm>;
- }
-
- def _vi : MUBUF_Real_vi <op, opName, outs, ins, asm>;
-}
-
-multiclass MUBUFAddr64_m <mubuf op, string opName, dag outs,
- dag ins, string asm, list<dag> pattern> {
-
- def "" : MUBUF_Pseudo <opName, outs, ins, pattern>,
- MUBUFAddr64Table <1>;
-
- let addr64 = 1, isCodeGenOnly = 0 in {
- def _si : MUBUF_Real_si <op, opName, outs, ins, asm>;
- }
-
- // There is no VI version. If the pseudo is selected, it should be lowered
- // for VI appropriately.
-}
-
-multiclass MUBUFAtomicOffset_m <mubuf op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern, bit is_return> {
-
- def "" : MUBUF_Pseudo <opName, outs, ins, pattern>,
- MUBUFAddr64Table <0, !if(is_return, "_RTN", "")>,
- AtomicNoRet<NAME#"_OFFSET", is_return>;
-
- let offen = 0, idxen = 0, tfe = 0, vaddr = 0 in {
- let addr64 = 0 in {
- def _si : MUBUF_Real_si <op, opName, outs, ins, asm>;
- }
-
- def _vi : MUBUF_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass MUBUFAtomicAddr64_m <mubuf op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern, bit is_return> {
-
- def "" : MUBUF_Pseudo <opName, outs, ins, pattern>,
- MUBUFAddr64Table <1, !if(is_return, "_RTN", "")>,
- AtomicNoRet<NAME#"_ADDR64", is_return>;
-
- let offen = 0, idxen = 0, addr64 = 1, tfe = 0 in {
- def _si : MUBUF_Real_si <op, opName, outs, ins, asm>;
- }
-
- // There is no VI version. If the pseudo is selected, it should be lowered
- // for VI appropriately.
-}
-
-multiclass MUBUFAtomicOther_m <mubuf op, string opName, dag outs, dag ins,
- string asm, list<dag> pattern, bit is_return> {
-
- def "" : MUBUF_Pseudo <opName, outs, ins, pattern>,
- AtomicNoRet<opName, is_return>;
-
- let tfe = 0 in {
- let addr64 = 0 in {
- def _si : MUBUF_Real_si <op, opName, outs, ins, asm>;
- }
-
- def _vi : MUBUF_Real_vi <op, opName, outs, ins, asm>;
- }
-}
-
-multiclass MUBUF_Atomic <mubuf op, string name, RegisterClass rc,
- ValueType vt, SDPatternOperator atomic> {
-
- let mayStore = 1, mayLoad = 1, hasPostISelHook = 1, hasSideEffects = 1,
- DisableWQM = 1 in {
-
- // No return variants
- let glc = 0, AsmMatchConverter = "cvtMubufAtomic" in {
-
- defm _ADDR64 : MUBUFAtomicAddr64_m <
- op, name#"_addr64", (outs),
- (ins rc:$vdata, VReg_64:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset addr64$offset$slc", [], 0
- >;
-
- defm _OFFSET : MUBUFAtomicOffset_m <
- op, name#"_offset", (outs),
- (ins rc:$vdata, SReg_128:$srsrc, SCSrc_32:$soffset, offset:$offset,
- slc:$slc),
- name#" $vdata, off, $srsrc, $soffset$offset$slc", [], 0
- >;
-
- let offen = 1, idxen = 0 in {
- defm _OFFEN : MUBUFAtomicOther_m <
- op, name#"_offen", (outs),
- (ins rc:$vdata, VGPR_32:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset offen$offset$slc", [], 0
- >;
- }
-
- let offen = 0, idxen = 1 in {
- defm _IDXEN : MUBUFAtomicOther_m <
- op, name#"_idxen", (outs),
- (ins rc:$vdata, VGPR_32:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen$offset$slc", [], 0
- >;
- }
-
- let offen = 1, idxen = 1 in {
- defm _BOTHEN : MUBUFAtomicOther_m <
- op, name#"_bothen", (outs),
- (ins rc:$vdata, VReg_64:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen offen$offset$slc",
- [], 0
- >;
- }
- } // glc = 0
-
- // Variant that return values
- let glc = 1, Constraints = "$vdata = $vdata_in",
- AsmMatchConverter = "cvtMubufAtomicReturn",
- DisableEncoding = "$vdata_in" in {
-
- defm _RTN_ADDR64 : MUBUFAtomicAddr64_m <
- op, name#"_rtn_addr64", (outs rc:$vdata),
- (ins rc:$vdata_in, VReg_64:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset addr64$offset glc$slc",
- [(set vt:$vdata,
- (atomic (MUBUFAddr64Atomic v4i32:$srsrc, i64:$vaddr, i32:$soffset,
- i16:$offset, i1:$slc), vt:$vdata_in))], 1
- >;
-
- defm _RTN_OFFSET : MUBUFAtomicOffset_m <
- op, name#"_rtn_offset", (outs rc:$vdata),
- (ins rc:$vdata_in, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, off, $srsrc, $soffset$offset glc$slc",
- [(set vt:$vdata,
- (atomic (MUBUFOffsetAtomic v4i32:$srsrc, i32:$soffset, i16:$offset,
- i1:$slc), vt:$vdata_in))], 1
- >;
-
- let offen = 1, idxen = 0 in {
- defm _RTN_OFFEN : MUBUFAtomicOther_m <
- op, name#"_rtn_offen", (outs rc:$vdata),
- (ins rc:$vdata_in, VGPR_32:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset offen$offset glc$slc",
- [], 1
- >;
- }
-
- let offen = 0, idxen = 1 in {
- defm _RTN_IDXEN : MUBUFAtomicOther_m <
- op, name#"_rtn_idxen", (outs rc:$vdata),
- (ins rc:$vdata_in, VGPR_32:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen$offset glc$slc",
- [], 1
- >;
- }
-
- let offen = 1, idxen = 1 in {
- defm _RTN_BOTHEN : MUBUFAtomicOther_m <
- op, name#"_rtn_bothen", (outs rc:$vdata),
- (ins rc:$vdata_in, VReg_64:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, slc:$slc),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen offen$offset glc$slc",
- [], 1
- >;
- }
- } // glc = 1
-
- } // mayStore = 1, mayLoad = 1, hasPostISelHook = 1
-}
-
-// FIXME: tfe can't be an operand because it requires a separate
-// opcode because it needs an N+1 register class dest register.
-multiclass MUBUF_Load_Helper <mubuf op, string name, RegisterClass regClass,
- ValueType load_vt = i32,
- SDPatternOperator ld = null_frag> {
-
- let mayLoad = 1, mayStore = 0 in {
- let offen = 0, idxen = 0, vaddr = 0 in {
- defm _OFFSET : MUBUF_m <op, name#"_offset", (outs regClass:$vdata),
- (ins SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, glc:$glc, slc:$slc, tfe:$tfe),
- name#" $vdata, off, $srsrc, $soffset$offset$glc$slc$tfe",
- [(set load_vt:$vdata, (ld (MUBUFOffset v4i32:$srsrc,
- i32:$soffset, i16:$offset,
- i1:$glc, i1:$slc, i1:$tfe)))]>;
- }
-
- let offen = 1, idxen = 0 in {
- defm _OFFEN : MUBUF_m <op, name#"_offen", (outs regClass:$vdata),
- (ins VGPR_32:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset, glc:$glc, slc:$slc,
- tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset offen$offset$glc$slc$tfe", []>;
- }
-
- let offen = 0, idxen = 1 in {
- defm _IDXEN : MUBUF_m <op, name#"_idxen", (outs regClass:$vdata),
- (ins VGPR_32:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset, glc:$glc,
- slc:$slc, tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen$offset$glc$slc$tfe", []>;
- }
-
- let offen = 1, idxen = 1 in {
- defm _BOTHEN : MUBUF_m <op, name#"_bothen", (outs regClass:$vdata),
- (ins VReg_64:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, glc:$glc, slc:$slc, tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen offen$offset$glc$slc$tfe", []>;
- }
-
- let offen = 0, idxen = 0 in {
- defm _ADDR64 : MUBUFAddr64_m <op, name#"_addr64", (outs regClass:$vdata),
- (ins VReg_64:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset,
- glc:$glc, slc:$slc, tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset addr64$offset$glc$slc$tfe",
- [(set load_vt:$vdata, (ld (MUBUFAddr64 v4i32:$srsrc,
- i64:$vaddr, i32:$soffset,
- i16:$offset, i1:$glc, i1:$slc,
- i1:$tfe)))]>;
- }
- }
-}
-
-multiclass MUBUF_Store_Helper <mubuf op, string name, RegisterClass vdataClass,
- ValueType store_vt = i32, SDPatternOperator st = null_frag> {
- let mayLoad = 0, mayStore = 1 in {
- let offen = 0, idxen = 0, vaddr = 0 in {
- defm _OFFSET : MUBUF_m <op, name#"_offset",(outs),
- (ins vdataClass:$vdata, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, glc:$glc, slc:$slc, tfe:$tfe),
- name#" $vdata, off, $srsrc, $soffset$offset$glc$slc$tfe",
- [(st store_vt:$vdata, (MUBUFOffset v4i32:$srsrc, i32:$soffset,
- i16:$offset, i1:$glc, i1:$slc, i1:$tfe))]>;
- } // offen = 0, idxen = 0, vaddr = 0
-
- let offen = 1, idxen = 0 in {
- defm _OFFEN : MUBUF_m <op, name#"_offen", (outs),
- (ins vdataClass:$vdata, VGPR_32:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset, glc:$glc,
- slc:$slc, tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset offen"#
- "$offset$glc$slc$tfe", []>;
- } // end offen = 1, idxen = 0
-
- let offen = 0, idxen = 1 in {
- defm _IDXEN : MUBUF_m <op, name#"_idxen", (outs),
- (ins vdataClass:$vdata, VGPR_32:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset, offset:$offset, glc:$glc,
- slc:$slc, tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen$offset$glc$slc$tfe", []>;
- }
-
- let offen = 1, idxen = 1 in {
- defm _BOTHEN : MUBUF_m <op, name#"_bothen", (outs),
- (ins vdataClass:$vdata, VReg_64:$vaddr, SReg_128:$srsrc, SCSrc_32:$soffset,
- offset:$offset, glc:$glc, slc:$slc, tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset idxen offen$offset$glc$slc$tfe", []>;
- }
-
- let offen = 0, idxen = 0 in {
- defm _ADDR64 : MUBUFAddr64_m <op, name#"_addr64", (outs),
- (ins vdataClass:$vdata, VReg_64:$vaddr, SReg_128:$srsrc,
- SCSrc_32:$soffset,
- offset:$offset, glc:$glc, slc:$slc,
- tfe:$tfe),
- name#" $vdata, $vaddr, $srsrc, $soffset addr64"#
- "$offset$glc$slc$tfe",
- [(st store_vt:$vdata,
- (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr,
- i32:$soffset, i16:$offset,
- i1:$glc, i1:$slc, i1:$tfe))]>;
- }
- } // End mayLoad = 0, mayStore = 1
-}
-
-// For cache invalidation instructions.
-multiclass MUBUF_Invalidate <mubuf op, string opName, SDPatternOperator node> {
- let hasSideEffects = 1, mayStore = 1, AsmMatchConverter = "" in {
- def "" : MUBUF_Pseudo <opName, (outs), (ins), [(node)]>;
-
- // Set everything to 0.
- let offset = 0, offen = 0, idxen = 0, glc = 0, vaddr = 0,
- vdata = 0, srsrc = 0, slc = 0, tfe = 0, soffset = 0 in {
- let addr64 = 0 in {
- def _si : MUBUF_Real_si <op, opName, (outs), (ins), opName>;
- }
-
- def _vi : MUBUF_Real_vi <op, opName, (outs), (ins), opName>;
- }
- } // End hasSideEffects = 1, mayStore = 1, AsmMatchConverter = ""
-}
-
-//===----------------------------------------------------------------------===//
-// FLAT classes
-//===----------------------------------------------------------------------===//
-
-class flat <bits<7> ci, bits<7> vi = ci> {
- field bits<7> CI = ci;
- field bits<7> VI = vi;
-}
-
-class FLAT_Pseudo <string opName, dag outs, dag ins, list<dag> pattern> :
- FLAT <0, outs, ins, "", pattern>,
- SIMCInstr<opName, SIEncodingFamily.NONE> {
- let isPseudo = 1;
- let isCodeGenOnly = 1;
-}
-
-class FLAT_Real_ci <bits<7> op, string opName, dag outs, dag ins, string asm> :
- FLAT <op, outs, ins, asm, []>,
- SIMCInstr<opName, SIEncodingFamily.SI> {
- let AssemblerPredicate = isCIOnly;
- let DecoderNamespace="CI";
-}
-
-class FLAT_Real_vi <bits<7> op, string opName, dag outs, dag ins, string asm> :
- FLAT <op, outs, ins, asm, []>,
- SIMCInstr<opName, SIEncodingFamily.VI> {
- let AssemblerPredicate = VIAssemblerPredicate;
- let DecoderNamespace="VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass FLAT_AtomicRet_m <flat op, dag outs, dag ins, string asm,
- list<dag> pattern> {
- def "" : FLAT_Pseudo <NAME#"_RTN", outs, ins, pattern>,
- AtomicNoRet <NAME, 1>;
-
- def _ci : FLAT_Real_ci <op.CI, NAME#"_RTN", outs, ins, asm>;
-
- def _vi : FLAT_Real_vi <op.VI, NAME#"_RTN", outs, ins, asm>;
-}
-
-multiclass FLAT_Load_Helper <flat op, string asm_name,
- RegisterClass regClass,
- dag outs = (outs regClass:$vdst),
- dag ins = (ins VReg_64:$addr, glc:$glc, slc:$slc, tfe:$tfe),
- string asm = asm_name#" $vdst, $addr$glc$slc$tfe"> {
-
- let data = 0, mayLoad = 1 in {
-
- def "" : FLAT_Pseudo <NAME, outs, ins, []>;
-
- def _ci : FLAT_Real_ci <op.CI, NAME, outs, ins, asm>;
-
- def _vi : FLAT_Real_vi <op.VI, NAME, outs, ins, asm>;
- }
-}
-
-multiclass FLAT_Store_Helper <flat op, string asm_name,
- RegisterClass vdataClass,
- dag outs = (outs),
- dag ins = (ins VReg_64:$addr, vdataClass:$data, glc:$glc,
- slc:$slc, tfe:$tfe),
- string asm = asm_name#" $addr, $data$glc$slc$tfe"> {
-
- let mayLoad = 0, mayStore = 1, vdst = 0 in {
-
- def "" : FLAT_Pseudo <NAME, outs, ins, []>;
-
- def _ci : FLAT_Real_ci <op.CI, NAME, outs, ins, asm>;
-
- def _vi : FLAT_Real_vi <op.VI, NAME, outs, ins, asm>;
- }
-}
-
-multiclass FLAT_ATOMIC <flat op, string asm_name, RegisterClass vdst_rc,
- ValueType vt, SDPatternOperator atomic = null_frag,
- ValueType data_vt = vt,
- RegisterClass data_rc = vdst_rc,
- string asm_noret = asm_name#" $addr, $data"#"$slc"#"$tfe"> {
-
- let mayLoad = 1, mayStore = 1, glc = 0, vdst = 0 in {
- def "" : FLAT_Pseudo <NAME, (outs),
- (ins VReg_64:$addr, data_rc:$data,
- slc:$slc, tfe:$tfe), []>,
- AtomicNoRet <NAME, 0>;
-
- def _ci : FLAT_Real_ci <op.CI, NAME, (outs),
- (ins VReg_64:$addr, data_rc:$data,
- slc:$slc, tfe:$tfe),
- asm_noret>;
-
- def _vi : FLAT_Real_vi <op.VI, NAME, (outs),
- (ins VReg_64:$addr, data_rc:$data,
- slc:$slc, tfe:$tfe),
- asm_noret>;
- }
-
- let glc = 1, hasPostISelHook = 1 in {
- defm _RTN : FLAT_AtomicRet_m <
- op, (outs vdst_rc:$vdst),
- (ins VReg_64:$addr, data_rc:$data, slc:$slc, tfe:$tfe),
- asm_name#" $vdst, $addr, $data glc$slc$tfe",
- [(set vt:$vdst,
- (atomic (FLATAtomic i64:$addr, i1:$slc, i1:$tfe), data_vt:$data))]
- >;
- }
-}
-
-class MIMG_Mask <string op, int channels> {
- string Op = op;
- int Channels = channels;
-}
-
-class mimg <bits<7> si, bits<7> vi = si> {
- field bits<7> SI = si;
- field bits<7> VI = vi;
-}
-
-class MIMG_Helper <dag outs, dag ins, string asm,
- string dns=""> : MIMG<outs, ins, asm,[]> {
- let mayLoad = 1;
- let mayStore = 0;
- let hasPostISelHook = 1;
- let DecoderNamespace = dns;
- let isAsmParserOnly = !if(!eq(dns,""), 1, 0);
- let AsmMatchConverter = "cvtMIMG";
-}
-
-class MIMG_NoSampler_Helper <bits<7> op, string asm,
- RegisterClass dst_rc,
- RegisterClass addr_rc,
- string dns=""> : MIMG_Helper <
- (outs dst_rc:$vdata),
- (ins addr_rc:$vaddr, SReg_256:$srsrc,
- dmask:$dmask, unorm:$unorm, glc:$glc, slc:$slc,
- r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
- asm#" $vdata, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da",
- dns>, MIMGe<op> {
- let ssamp = 0;
-}
-
-multiclass MIMG_NoSampler_Src_Helper <bits<7> op, string asm,
- RegisterClass dst_rc,
- int channels> {
- def _V1 : MIMG_NoSampler_Helper <op, asm, dst_rc, VGPR_32,
- !if(!eq(channels, 1), "AMDGPU", "")>,
- MIMG_Mask<asm#"_V1", channels>;
- def _V2 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_64>,
- MIMG_Mask<asm#"_V2", channels>;
- def _V4 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_128>,
- MIMG_Mask<asm#"_V4", channels>;
-}
-
-multiclass MIMG_NoSampler <bits<7> op, string asm> {
- defm _V1 : MIMG_NoSampler_Src_Helper <op, asm, VGPR_32, 1>;
- defm _V2 : MIMG_NoSampler_Src_Helper <op, asm, VReg_64, 2>;
- defm _V3 : MIMG_NoSampler_Src_Helper <op, asm, VReg_96, 3>;
- defm _V4 : MIMG_NoSampler_Src_Helper <op, asm, VReg_128, 4>;
-}
-
-class MIMG_Store_Helper <bits<7> op, string asm,
- RegisterClass data_rc,
- RegisterClass addr_rc> : MIMG_Helper <
- (outs),
- (ins data_rc:$vdata, addr_rc:$vaddr, SReg_256:$srsrc,
- dmask:$dmask, unorm:$unorm, glc:$glc, slc:$slc,
- r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
- asm#" $vdata, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da"
- >, MIMGe<op> {
- let ssamp = 0;
- let mayLoad = 1; // TableGen requires this for matching with the intrinsics
- let mayStore = 1;
- let hasSideEffects = 1;
- let hasPostISelHook = 0;
- let DisableWQM = 1;
-}
-
-multiclass MIMG_Store_Addr_Helper <bits<7> op, string asm,
- RegisterClass data_rc,
- int channels> {
- def _V1 : MIMG_Store_Helper <op, asm, data_rc, VGPR_32>,
- MIMG_Mask<asm#"_V1", channels>;
- def _V2 : MIMG_Store_Helper <op, asm, data_rc, VReg_64>,
- MIMG_Mask<asm#"_V2", channels>;
- def _V4 : MIMG_Store_Helper <op, asm, data_rc, VReg_128>,
- MIMG_Mask<asm#"_V4", channels>;
-}
-
-multiclass MIMG_Store <bits<7> op, string asm> {
- defm _V1 : MIMG_Store_Addr_Helper <op, asm, VGPR_32, 1>;
- defm _V2 : MIMG_Store_Addr_Helper <op, asm, VReg_64, 2>;
- defm _V3 : MIMG_Store_Addr_Helper <op, asm, VReg_96, 3>;
- defm _V4 : MIMG_Store_Addr_Helper <op, asm, VReg_128, 4>;
-}
-
-class MIMG_Atomic_Helper <string asm, RegisterClass data_rc,
- RegisterClass addr_rc> : MIMG_Helper <
- (outs data_rc:$vdst),
- (ins data_rc:$vdata, addr_rc:$vaddr, SReg_256:$srsrc,
- dmask:$dmask, unorm:$unorm, glc:$glc, slc:$slc,
- r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
- asm#" $vdst, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da"
- > {
- let mayStore = 1;
- let hasSideEffects = 1;
- let hasPostISelHook = 0;
- let DisableWQM = 1;
- let Constraints = "$vdst = $vdata";
- let AsmMatchConverter = "cvtMIMGAtomic";
-}
-
-class MIMG_Atomic_Real_si<mimg op, string name, string asm,
- RegisterClass data_rc, RegisterClass addr_rc> :
- MIMG_Atomic_Helper<asm, data_rc, addr_rc>,
- SIMCInstr<name, SIEncodingFamily.SI>,
- MIMGe<op.SI> {
- let isCodeGenOnly = 0;
- let AssemblerPredicates = [isSICI];
- let DecoderNamespace = "SICI";
- let DisableDecoder = DisableSIDecoder;
-}
-
-class MIMG_Atomic_Real_vi<mimg op, string name, string asm,
- RegisterClass data_rc, RegisterClass addr_rc> :
- MIMG_Atomic_Helper<asm, data_rc, addr_rc>,
- SIMCInstr<name, SIEncodingFamily.VI>,
- MIMGe<op.VI> {
- let isCodeGenOnly = 0;
- let AssemblerPredicates = [isVI];
- let DecoderNamespace = "VI";
- let DisableDecoder = DisableVIDecoder;
-}
-
-multiclass MIMG_Atomic_Helper_m <mimg op, string name, string asm,
- RegisterClass data_rc, RegisterClass addr_rc> {
- let isPseudo = 1, isCodeGenOnly = 1 in {
- def "" : MIMG_Atomic_Helper<asm, data_rc, addr_rc>,
- SIMCInstr<name, SIEncodingFamily.NONE>;
- }
-
- let ssamp = 0 in {
- def _si : MIMG_Atomic_Real_si<op, name, asm, data_rc, addr_rc>;
-
- def _vi : MIMG_Atomic_Real_vi<op, name, asm, data_rc, addr_rc>;
- }
-}
-
-multiclass MIMG_Atomic <mimg op, string asm, RegisterClass data_rc = VGPR_32> {
- defm _V1 : MIMG_Atomic_Helper_m <op, asm # "_V1", asm, data_rc, VGPR_32>;
- defm _V2 : MIMG_Atomic_Helper_m <op, asm # "_V2", asm, data_rc, VReg_64>;
- defm _V4 : MIMG_Atomic_Helper_m <op, asm # "_V3", asm, data_rc, VReg_128>;
-}
-
-class MIMG_Sampler_Helper <bits<7> op, string asm,
- RegisterClass dst_rc,
- RegisterClass src_rc,
- int wqm,
- string dns=""> : MIMG_Helper <
- (outs dst_rc:$vdata),
- (ins src_rc:$vaddr, SReg_256:$srsrc, SReg_128:$ssamp,
- dmask:$dmask, unorm:$unorm, glc:$glc, slc:$slc,
- r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
- asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$glc$slc$r128$tfe$lwe$da",
- dns>, MIMGe<op> {
- let WQM = wqm;
-}
-
-multiclass MIMG_Sampler_Src_Helper <bits<7> op, string asm,
- RegisterClass dst_rc,
- int channels, int wqm> {
- def _V1 : MIMG_Sampler_Helper <op, asm, dst_rc, VGPR_32, wqm,
- !if(!eq(channels, 1), "AMDGPU", "")>,
- MIMG_Mask<asm#"_V1", channels>;
- def _V2 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_64, wqm>,
- MIMG_Mask<asm#"_V2", channels>;
- def _V4 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_128, wqm>,
- MIMG_Mask<asm#"_V4", channels>;
- def _V8 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_256, wqm>,
- MIMG_Mask<asm#"_V8", channels>;
- def _V16 : MIMG_Sampler_Helper <op, asm, dst_rc, VReg_512, wqm>,
- MIMG_Mask<asm#"_V16", channels>;
-}
-
-multiclass MIMG_Sampler <bits<7> op, string asm, int wqm=0> {
- defm _V1 : MIMG_Sampler_Src_Helper<op, asm, VGPR_32, 1, wqm>;
- defm _V2 : MIMG_Sampler_Src_Helper<op, asm, VReg_64, 2, wqm>;
- defm _V3 : MIMG_Sampler_Src_Helper<op, asm, VReg_96, 3, wqm>;
- defm _V4 : MIMG_Sampler_Src_Helper<op, asm, VReg_128, 4, wqm>;
-}
-
-multiclass MIMG_Sampler_WQM <bits<7> op, string asm> : MIMG_Sampler<op, asm, 1>;
-
-class MIMG_Gather_Helper <bits<7> op, string asm,
- RegisterClass dst_rc,
- RegisterClass src_rc, int wqm> : MIMG <
- (outs dst_rc:$vdata),
- (ins src_rc:$vaddr, SReg_256:$srsrc, SReg_128:$ssamp,
- dmask:$dmask, unorm:$unorm, glc:$glc, slc:$slc,
- r128:$r128, tfe:$tfe, lwe:$lwe, da:$da),
- asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$glc$slc$r128$tfe$lwe$da",
- []>, MIMGe<op> {
- let mayLoad = 1;
- let mayStore = 0;
-
- // DMASK was repurposed for GATHER4. 4 components are always
- // returned and DMASK works like a swizzle - it selects
- // the component to fetch. The only useful DMASK values are
- // 1=red, 2=green, 4=blue, 8=alpha. (e.g. 1 returns
- // (red,red,red,red) etc.) The ISA document doesn't mention
- // this.
- // Therefore, disable all code which updates DMASK by setting this:
- let Gather4 = 1;
- let hasPostISelHook = 0;
- let WQM = wqm;
-
- let isAsmParserOnly = 1; // TBD: fix it later
-}
-
-multiclass MIMG_Gather_Src_Helper <bits<7> op, string asm,
- RegisterClass dst_rc,
- int channels, int wqm> {
- def _V1 : MIMG_Gather_Helper <op, asm, dst_rc, VGPR_32, wqm>,
- MIMG_Mask<asm#"_V1", channels>;
- def _V2 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_64, wqm>,
- MIMG_Mask<asm#"_V2", channels>;
- def _V4 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_128, wqm>,
- MIMG_Mask<asm#"_V4", channels>;
- def _V8 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_256, wqm>,
- MIMG_Mask<asm#"_V8", channels>;
- def _V16 : MIMG_Gather_Helper <op, asm, dst_rc, VReg_512, wqm>,
- MIMG_Mask<asm#"_V16", channels>;
-}
-
-multiclass MIMG_Gather <bits<7> op, string asm, int wqm=0> {
- defm _V1 : MIMG_Gather_Src_Helper<op, asm, VGPR_32, 1, wqm>;
- defm _V2 : MIMG_Gather_Src_Helper<op, asm, VReg_64, 2, wqm>;
- defm _V3 : MIMG_Gather_Src_Helper<op, asm, VReg_96, 3, wqm>;
- defm _V4 : MIMG_Gather_Src_Helper<op, asm, VReg_128, 4, wqm>;
-}
-
-multiclass MIMG_Gather_WQM <bits<7> op, string asm> : MIMG_Gather<op, asm, 1>;
-
-//===----------------------------------------------------------------------===//
// Vector instruction mappings
//===----------------------------------------------------------------------===//
@@ -3604,18 +1199,18 @@ multiclass MIMG_Gather_WQM <bits<7> op, string asm> : MIMG_Gather<op, asm, 1>;
def getVOPe64 : InstrMapping {
let FilterClass = "VOP";
let RowFields = ["OpName"];
- let ColFields = ["Size"];
- let KeyCol = ["4"];
- let ValueCols = [["8"]];
+ let ColFields = ["Size", "VOP3"];
+ let KeyCol = ["4", "0"];
+ let ValueCols = [["8", "1"]];
}
// Maps an opcode in e64 form to its e32 equivalent
def getVOPe32 : InstrMapping {
let FilterClass = "VOP";
let RowFields = ["OpName"];
- let ColFields = ["Size"];
- let KeyCol = ["8"];
- let ValueCols = [["4"]];
+ let ColFields = ["Size", "VOP3"];
+ let KeyCol = ["8", "1"];
+ let ValueCols = [["4", "0"]];
}
def getMaskedMIMGOp : InstrMapping {
@@ -3628,7 +1223,7 @@ def getMaskedMIMGOp : InstrMapping {
// Maps an commuted opcode to its original version
def getCommuteOrig : InstrMapping {
- let FilterClass = "VOP2_REV";
+ let FilterClass = "Commutable_REV";
let RowFields = ["RevOp"];
let ColFields = ["IsOrig"];
let KeyCol = ["0"];
@@ -3637,31 +1232,13 @@ def getCommuteOrig : InstrMapping {
// Maps an original opcode to its commuted version
def getCommuteRev : InstrMapping {
- let FilterClass = "VOP2_REV";
- let RowFields = ["RevOp"];
- let ColFields = ["IsOrig"];
- let KeyCol = ["1"];
- let ValueCols = [["0"]];
-}
-
-def getCommuteCmpOrig : InstrMapping {
- let FilterClass = "VOP2_REV";
- let RowFields = ["RevOp"];
- let ColFields = ["IsOrig"];
- let KeyCol = ["0"];
- let ValueCols = [["1"]];
-}
-
-// Maps an original opcode to its commuted version
-def getCommuteCmpRev : InstrMapping {
- let FilterClass = "VOP2_REV";
+ let FilterClass = "Commutable_REV";
let RowFields = ["RevOp"];
let ColFields = ["IsOrig"];
let KeyCol = ["1"];
let ValueCols = [["0"]];
}
-
def getMCOpcodeGen : InstrMapping {
let FilterClass = "SIMCInstr";
let RowFields = ["PseudoInstr"];
@@ -3671,6 +1248,15 @@ def getMCOpcodeGen : InstrMapping {
[!cast<string>(SIEncodingFamily.VI)]];
}
+// Get equivalent SOPK instruction.
+def getSOPKOp : InstrMapping {
+ let FilterClass = "SOPKInstTable";
+ let RowFields = ["BaseCmpOp"];
+ let ColFields = ["IsSOPK"];
+ let KeyCol = ["0"];
+ let ValueCols = [["1"]];
+}
+
def getAddr64Inst : InstrMapping {
let FilterClass = "MUBUFAddr64Table";
let RowFields = ["OpName"];
@@ -3699,4 +1285,6 @@ def getAtomicNoRetOp : InstrMapping {
include "SIInstructions.td"
include "CIInstructions.td"
-include "VIInstructions.td"
+
+include "DSInstructions.td"
+include "MIMGInstructions.td"
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstructions.td b/contrib/llvm/lib/Target/AMDGPU/SIInstructions.td
index dde5f2f..38e31e7 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -11,13 +11,6 @@
// that are not yet supported remain commented out.
//===----------------------------------------------------------------------===//
-class InterpSlots {
-int P0 = 2;
-int P10 = 0;
-int P20 = 1;
-}
-def INTERP : InterpSlots;
-
def isGCN : Predicate<"Subtarget->getGeneration() "
">= SISubtarget::SOUTHERN_ISLANDS">,
AssemblerPredicate<"FeatureGCN">;
@@ -25,9 +18,18 @@ def isSI : Predicate<"Subtarget->getGeneration() "
"== SISubtarget::SOUTHERN_ISLANDS">,
AssemblerPredicate<"FeatureSouthernIslands">;
-
def has16BankLDS : Predicate<"Subtarget->getLDSBankCount() == 16">;
def has32BankLDS : Predicate<"Subtarget->getLDSBankCount() == 32">;
+def HasVGPRIndexMode : Predicate<"Subtarget->hasVGPRIndexMode()">,
+ AssemblerPredicate<"FeatureVGPRIndexMode">;
+def HasMovrel : Predicate<"Subtarget->hasMovrel()">,
+ AssemblerPredicate<"FeatureMovrel">;
+
+include "VOPInstructions.td"
+include "SOPInstructions.td"
+include "SMInstructions.td"
+include "FLATInstructions.td"
+include "BUFInstructions.td"
let SubtargetPredicate = isGCN in {
@@ -35,1393 +37,8 @@ let SubtargetPredicate = isGCN in {
// EXP Instructions
//===----------------------------------------------------------------------===//
-defm EXP : EXP_m;
-
-//===----------------------------------------------------------------------===//
-// SMRD Instructions
-//===----------------------------------------------------------------------===//
-
-// We are using the SReg_32_XM0 and not the SReg_32 register class for 32-bit
-// SMRD instructions, because the SReg_32_XM0 register class does not include M0
-// and writing to M0 from an SMRD instruction will hang the GPU.
-defm S_LOAD_DWORD : SMRD_Helper <smrd<0x00>, "s_load_dword", SReg_64, SReg_32_XM0>;
-defm S_LOAD_DWORDX2 : SMRD_Helper <smrd<0x01>, "s_load_dwordx2", SReg_64, SReg_64>;
-defm S_LOAD_DWORDX4 : SMRD_Helper <smrd<0x02>, "s_load_dwordx4", SReg_64, SReg_128>;
-defm S_LOAD_DWORDX8 : SMRD_Helper <smrd<0x03>, "s_load_dwordx8", SReg_64, SReg_256>;
-defm S_LOAD_DWORDX16 : SMRD_Helper <smrd<0x04>, "s_load_dwordx16", SReg_64, SReg_512>;
-
-defm S_BUFFER_LOAD_DWORD : SMRD_Helper <
- smrd<0x08>, "s_buffer_load_dword", SReg_128, SReg_32_XM0
->;
-
-defm S_BUFFER_LOAD_DWORDX2 : SMRD_Helper <
- smrd<0x09>, "s_buffer_load_dwordx2", SReg_128, SReg_64
->;
-
-defm S_BUFFER_LOAD_DWORDX4 : SMRD_Helper <
- smrd<0x0a>, "s_buffer_load_dwordx4", SReg_128, SReg_128
->;
-
-defm S_BUFFER_LOAD_DWORDX8 : SMRD_Helper <
- smrd<0x0b>, "s_buffer_load_dwordx8", SReg_128, SReg_256
->;
-
-defm S_BUFFER_LOAD_DWORDX16 : SMRD_Helper <
- smrd<0x0c>, "s_buffer_load_dwordx16", SReg_128, SReg_512
->;
-
-let mayStore = ? in {
-// FIXME: mayStore = ? is a workaround for tablegen bug for different
-// inferred mayStore flags for the instruction pattern vs. standalone
-// Pat. Each considers the other contradictory.
-
-defm S_MEMTIME : SMRD_Special <smrd<0x1e, 0x24>, "s_memtime",
- (outs SReg_64:$sdst), ?, " $sdst", [(set i64:$sdst, (int_amdgcn_s_memtime))]
->;
-}
-
-defm S_DCACHE_INV : SMRD_Inval <smrd<0x1f, 0x20>, "s_dcache_inv",
- int_amdgcn_s_dcache_inv>;
-
-//===----------------------------------------------------------------------===//
-// SOP1 Instructions
-//===----------------------------------------------------------------------===//
-
-let isMoveImm = 1 in {
- let isReMaterializable = 1, isAsCheapAsAMove = 1 in {
- defm S_MOV_B32 : SOP1_32 <sop1<0x03, 0x00>, "s_mov_b32", []>;
- defm S_MOV_B64 : SOP1_64 <sop1<0x04, 0x01>, "s_mov_b64", []>;
- } // End isRematerializeable = 1
-
- let Uses = [SCC] in {
- defm S_CMOV_B32 : SOP1_32 <sop1<0x05, 0x02>, "s_cmov_b32", []>;
- defm S_CMOV_B64 : SOP1_64 <sop1<0x06, 0x03>, "s_cmov_b64", []>;
- } // End Uses = [SCC]
-} // End isMoveImm = 1
-
-let Defs = [SCC] in {
- defm S_NOT_B32 : SOP1_32 <sop1<0x07, 0x04>, "s_not_b32",
- [(set i32:$sdst, (not i32:$src0))]
- >;
-
- defm S_NOT_B64 : SOP1_64 <sop1<0x08, 0x05>, "s_not_b64",
- [(set i64:$sdst, (not i64:$src0))]
- >;
- defm S_WQM_B32 : SOP1_32 <sop1<0x09, 0x06>, "s_wqm_b32", []>;
- defm S_WQM_B64 : SOP1_64 <sop1<0x0a, 0x07>, "s_wqm_b64", []>;
-} // End Defs = [SCC]
-
-
-defm S_BREV_B32 : SOP1_32 <sop1<0x0b, 0x08>, "s_brev_b32",
- [(set i32:$sdst, (bitreverse i32:$src0))]
->;
-defm S_BREV_B64 : SOP1_64 <sop1<0x0c, 0x09>, "s_brev_b64", []>;
-
-let Defs = [SCC] in {
- defm S_BCNT0_I32_B32 : SOP1_32 <sop1<0x0d, 0x0a>, "s_bcnt0_i32_b32", []>;
- defm S_BCNT0_I32_B64 : SOP1_32_64 <sop1<0x0e, 0x0b>, "s_bcnt0_i32_b64", []>;
- defm S_BCNT1_I32_B32 : SOP1_32 <sop1<0x0f, 0x0c>, "s_bcnt1_i32_b32",
- [(set i32:$sdst, (ctpop i32:$src0))]
- >;
- defm S_BCNT1_I32_B64 : SOP1_32_64 <sop1<0x10, 0x0d>, "s_bcnt1_i32_b64", []>;
-} // End Defs = [SCC]
-
-defm S_FF0_I32_B32 : SOP1_32 <sop1<0x11, 0x0e>, "s_ff0_i32_b32", []>;
-defm S_FF0_I32_B64 : SOP1_32_64 <sop1<0x12, 0x0f>, "s_ff0_i32_b64", []>;
-defm S_FF1_I32_B32 : SOP1_32 <sop1<0x13, 0x10>, "s_ff1_i32_b32",
- [(set i32:$sdst, (cttz_zero_undef i32:$src0))]
->;
-defm S_FF1_I32_B64 : SOP1_32_64 <sop1<0x14, 0x11>, "s_ff1_i32_b64", []>;
-
-defm S_FLBIT_I32_B32 : SOP1_32 <sop1<0x15, 0x12>, "s_flbit_i32_b32",
- [(set i32:$sdst, (AMDGPUffbh_u32 i32:$src0))]
->;
-
-defm S_FLBIT_I32_B64 : SOP1_32_64 <sop1<0x16, 0x13>, "s_flbit_i32_b64", []>;
-defm S_FLBIT_I32 : SOP1_32 <sop1<0x17, 0x14>, "s_flbit_i32",
- [(set i32:$sdst, (int_AMDGPU_flbit_i32 i32:$src0))]
->;
-defm S_FLBIT_I32_I64 : SOP1_32_64 <sop1<0x18, 0x15>, "s_flbit_i32_i64", []>;
-defm S_SEXT_I32_I8 : SOP1_32 <sop1<0x19, 0x16>, "s_sext_i32_i8",
- [(set i32:$sdst, (sext_inreg i32:$src0, i8))]
->;
-defm S_SEXT_I32_I16 : SOP1_32 <sop1<0x1a, 0x17>, "s_sext_i32_i16",
- [(set i32:$sdst, (sext_inreg i32:$src0, i16))]
->;
-
-defm S_BITSET0_B32 : SOP1_32 <sop1<0x1b, 0x18>, "s_bitset0_b32", []>;
-defm S_BITSET0_B64 : SOP1_64_32 <sop1<0x1c, 0x19>, "s_bitset0_b64", []>;
-defm S_BITSET1_B32 : SOP1_32 <sop1<0x1d, 0x1a>, "s_bitset1_b32", []>;
-defm S_BITSET1_B64 : SOP1_64_32 <sop1<0x1e, 0x1b>, "s_bitset1_b64", []>;
-defm S_GETPC_B64 : SOP1_64_0 <sop1<0x1f, 0x1c>, "s_getpc_b64", []>;
-defm S_SETPC_B64 : SOP1_1 <sop1<0x20, 0x1d>, "s_setpc_b64", []>;
-defm S_SWAPPC_B64 : SOP1_64 <sop1<0x21, 0x1e>, "s_swappc_b64", []>;
-defm S_RFE_B64 : SOP1_1 <sop1<0x22, 0x1f>, "s_rfe_b64", []>;
-
-let hasSideEffects = 1, Uses = [EXEC], Defs = [EXEC, SCC] in {
-
-defm S_AND_SAVEEXEC_B64 : SOP1_64 <sop1<0x24, 0x20>, "s_and_saveexec_b64", []>;
-defm S_OR_SAVEEXEC_B64 : SOP1_64 <sop1<0x25, 0x21>, "s_or_saveexec_b64", []>;
-defm S_XOR_SAVEEXEC_B64 : SOP1_64 <sop1<0x26, 0x22>, "s_xor_saveexec_b64", []>;
-defm S_ANDN2_SAVEEXEC_B64 : SOP1_64 <sop1<0x27, 0x23>, "s_andn2_saveexec_b64", []>;
-defm S_ORN2_SAVEEXEC_B64 : SOP1_64 <sop1<0x28, 0x24>, "s_orn2_saveexec_b64", []>;
-defm S_NAND_SAVEEXEC_B64 : SOP1_64 <sop1<0x29, 0x25>, "s_nand_saveexec_b64", []>;
-defm S_NOR_SAVEEXEC_B64 : SOP1_64 <sop1<0x2a, 0x26>, "s_nor_saveexec_b64", []>;
-defm S_XNOR_SAVEEXEC_B64 : SOP1_64 <sop1<0x2b, 0x27>, "s_xnor_saveexec_b64", []>;
-
-} // End hasSideEffects = 1, Uses = [EXEC], Defs = [EXEC, SCC]
-
-defm S_QUADMASK_B32 : SOP1_32 <sop1<0x2c, 0x28>, "s_quadmask_b32", []>;
-defm S_QUADMASK_B64 : SOP1_64 <sop1<0x2d, 0x29>, "s_quadmask_b64", []>;
-
-let Uses = [M0] in {
-defm S_MOVRELS_B32 : SOP1_32 <sop1<0x2e, 0x2a>, "s_movrels_b32", []>;
-defm S_MOVRELS_B64 : SOP1_64 <sop1<0x2f, 0x2b>, "s_movrels_b64", []>;
-defm S_MOVRELD_B32 : SOP1_32 <sop1<0x30, 0x2c>, "s_movreld_b32", []>;
-defm S_MOVRELD_B64 : SOP1_64 <sop1<0x31, 0x2d>, "s_movreld_b64", []>;
-} // End Uses = [M0]
-
-defm S_CBRANCH_JOIN : SOP1_1 <sop1<0x32, 0x2e>, "s_cbranch_join", []>;
-defm S_MOV_REGRD_B32 : SOP1_32 <sop1<0x33, 0x2f>, "s_mov_regrd_b32", []>;
-let Defs = [SCC] in {
- defm S_ABS_I32 : SOP1_32 <sop1<0x34, 0x30>, "s_abs_i32", []>;
-} // End Defs = [SCC]
-defm S_MOV_FED_B32 : SOP1_32 <sop1<0x35, 0x31>, "s_mov_fed_b32", []>;
-
-//===----------------------------------------------------------------------===//
-// SOP2 Instructions
-//===----------------------------------------------------------------------===//
-
-let Defs = [SCC] in { // Carry out goes to SCC
-let isCommutable = 1 in {
-defm S_ADD_U32 : SOP2_32 <sop2<0x00>, "s_add_u32", []>;
-defm S_ADD_I32 : SOP2_32 <sop2<0x02>, "s_add_i32",
- [(set i32:$sdst, (add SSrc_32:$src0, SSrc_32:$src1))]
->;
-} // End isCommutable = 1
-
-defm S_SUB_U32 : SOP2_32 <sop2<0x01>, "s_sub_u32", []>;
-defm S_SUB_I32 : SOP2_32 <sop2<0x03>, "s_sub_i32",
- [(set i32:$sdst, (sub SSrc_32:$src0, SSrc_32:$src1))]
->;
-
-let Uses = [SCC] in { // Carry in comes from SCC
-let isCommutable = 1 in {
-defm S_ADDC_U32 : SOP2_32 <sop2<0x04>, "s_addc_u32",
- [(set i32:$sdst, (adde (i32 SSrc_32:$src0), (i32 SSrc_32:$src1)))]>;
-} // End isCommutable = 1
-
-defm S_SUBB_U32 : SOP2_32 <sop2<0x05>, "s_subb_u32",
- [(set i32:$sdst, (sube (i32 SSrc_32:$src0), (i32 SSrc_32:$src1)))]>;
-} // End Uses = [SCC]
-
-defm S_MIN_I32 : SOP2_32 <sop2<0x06>, "s_min_i32",
- [(set i32:$sdst, (smin i32:$src0, i32:$src1))]
->;
-defm S_MIN_U32 : SOP2_32 <sop2<0x07>, "s_min_u32",
- [(set i32:$sdst, (umin i32:$src0, i32:$src1))]
->;
-defm S_MAX_I32 : SOP2_32 <sop2<0x08>, "s_max_i32",
- [(set i32:$sdst, (smax i32:$src0, i32:$src1))]
->;
-defm S_MAX_U32 : SOP2_32 <sop2<0x09>, "s_max_u32",
- [(set i32:$sdst, (umax i32:$src0, i32:$src1))]
->;
-} // End Defs = [SCC]
-
-
-let Uses = [SCC] in {
- defm S_CSELECT_B32 : SOP2_32 <sop2<0x0a>, "s_cselect_b32", []>;
- defm S_CSELECT_B64 : SOP2_64 <sop2<0x0b>, "s_cselect_b64", []>;
-} // End Uses = [SCC]
-
-let Defs = [SCC] in {
-defm S_AND_B32 : SOP2_32 <sop2<0x0e, 0x0c>, "s_and_b32",
- [(set i32:$sdst, (and i32:$src0, i32:$src1))]
->;
-
-defm S_AND_B64 : SOP2_64 <sop2<0x0f, 0x0d>, "s_and_b64",
- [(set i64:$sdst, (and i64:$src0, i64:$src1))]
->;
-
-defm S_OR_B32 : SOP2_32 <sop2<0x10, 0x0e>, "s_or_b32",
- [(set i32:$sdst, (or i32:$src0, i32:$src1))]
->;
-
-defm S_OR_B64 : SOP2_64 <sop2<0x11, 0x0f>, "s_or_b64",
- [(set i64:$sdst, (or i64:$src0, i64:$src1))]
->;
-
-defm S_XOR_B32 : SOP2_32 <sop2<0x12, 0x10>, "s_xor_b32",
- [(set i32:$sdst, (xor i32:$src0, i32:$src1))]
->;
-
-defm S_XOR_B64 : SOP2_64 <sop2<0x13, 0x11>, "s_xor_b64",
- [(set i64:$sdst, (xor i64:$src0, i64:$src1))]
->;
-defm S_ANDN2_B32 : SOP2_32 <sop2<0x14, 0x12>, "s_andn2_b32", []>;
-defm S_ANDN2_B64 : SOP2_64 <sop2<0x15, 0x13>, "s_andn2_b64", []>;
-defm S_ORN2_B32 : SOP2_32 <sop2<0x16, 0x14>, "s_orn2_b32", []>;
-defm S_ORN2_B64 : SOP2_64 <sop2<0x17, 0x15>, "s_orn2_b64", []>;
-defm S_NAND_B32 : SOP2_32 <sop2<0x18, 0x16>, "s_nand_b32", []>;
-defm S_NAND_B64 : SOP2_64 <sop2<0x19, 0x17>, "s_nand_b64", []>;
-defm S_NOR_B32 : SOP2_32 <sop2<0x1a, 0x18>, "s_nor_b32", []>;
-defm S_NOR_B64 : SOP2_64 <sop2<0x1b, 0x19>, "s_nor_b64", []>;
-defm S_XNOR_B32 : SOP2_32 <sop2<0x1c, 0x1a>, "s_xnor_b32", []>;
-defm S_XNOR_B64 : SOP2_64 <sop2<0x1d, 0x1b>, "s_xnor_b64", []>;
-} // End Defs = [SCC]
-
-// Use added complexity so these patterns are preferred to the VALU patterns.
-let AddedComplexity = 1 in {
-let Defs = [SCC] in {
-
-defm S_LSHL_B32 : SOP2_32 <sop2<0x1e, 0x1c>, "s_lshl_b32",
- [(set i32:$sdst, (shl i32:$src0, i32:$src1))]
->;
-defm S_LSHL_B64 : SOP2_64_32 <sop2<0x1f, 0x1d>, "s_lshl_b64",
- [(set i64:$sdst, (shl i64:$src0, i32:$src1))]
->;
-defm S_LSHR_B32 : SOP2_32 <sop2<0x20, 0x1e>, "s_lshr_b32",
- [(set i32:$sdst, (srl i32:$src0, i32:$src1))]
->;
-defm S_LSHR_B64 : SOP2_64_32 <sop2<0x21, 0x1f>, "s_lshr_b64",
- [(set i64:$sdst, (srl i64:$src0, i32:$src1))]
->;
-defm S_ASHR_I32 : SOP2_32 <sop2<0x22, 0x20>, "s_ashr_i32",
- [(set i32:$sdst, (sra i32:$src0, i32:$src1))]
->;
-defm S_ASHR_I64 : SOP2_64_32 <sop2<0x23, 0x21>, "s_ashr_i64",
- [(set i64:$sdst, (sra i64:$src0, i32:$src1))]
->;
-} // End Defs = [SCC]
-
-defm S_BFM_B32 : SOP2_32 <sop2<0x24, 0x22>, "s_bfm_b32",
- [(set i32:$sdst, (AMDGPUbfm i32:$src0, i32:$src1))]>;
-defm S_BFM_B64 : SOP2_64_32_32 <sop2<0x25, 0x23>, "s_bfm_b64", []>;
-defm S_MUL_I32 : SOP2_32 <sop2<0x26, 0x24>, "s_mul_i32",
- [(set i32:$sdst, (mul i32:$src0, i32:$src1))]
->;
-
-} // End AddedComplexity = 1
-
-let Defs = [SCC] in {
-defm S_BFE_U32 : SOP2_32 <sop2<0x27, 0x25>, "s_bfe_u32", []>;
-defm S_BFE_I32 : SOP2_32 <sop2<0x28, 0x26>, "s_bfe_i32", []>;
-defm S_BFE_U64 : SOP2_64_32 <sop2<0x29, 0x27>, "s_bfe_u64", []>;
-defm S_BFE_I64 : SOP2_64_32 <sop2<0x2a, 0x28>, "s_bfe_i64", []>;
-} // End Defs = [SCC]
-
-let sdst = 0 in {
-defm S_CBRANCH_G_FORK : SOP2_m <
- sop2<0x2b, 0x29>, "s_cbranch_g_fork", (outs),
- (ins SReg_64:$src0, SReg_64:$src1), "s_cbranch_g_fork $src0, $src1", []
->;
-}
-
-let Defs = [SCC] in {
-defm S_ABSDIFF_I32 : SOP2_32 <sop2<0x2c, 0x2a>, "s_absdiff_i32", []>;
-} // End Defs = [SCC]
-
-//===----------------------------------------------------------------------===//
-// SOPC Instructions
-//===----------------------------------------------------------------------===//
-
-def S_CMP_EQ_I32 : SOPC_CMP_32 <0x00000000, "s_cmp_eq_i32", COND_EQ>;
-def S_CMP_LG_I32 : SOPC_CMP_32 <0x00000001, "s_cmp_lg_i32", COND_NE>;
-def S_CMP_GT_I32 : SOPC_CMP_32 <0x00000002, "s_cmp_gt_i32", COND_SGT>;
-def S_CMP_GE_I32 : SOPC_CMP_32 <0x00000003, "s_cmp_ge_i32", COND_SGE>;
-def S_CMP_LT_I32 : SOPC_CMP_32 <0x00000004, "s_cmp_lt_i32", COND_SLT>;
-def S_CMP_LE_I32 : SOPC_CMP_32 <0x00000005, "s_cmp_le_i32", COND_SLE>;
-def S_CMP_EQ_U32 : SOPC_CMP_32 <0x00000006, "s_cmp_eq_u32", COND_EQ>;
-def S_CMP_LG_U32 : SOPC_CMP_32 <0x00000007, "s_cmp_lg_u32", COND_NE >;
-def S_CMP_GT_U32 : SOPC_CMP_32 <0x00000008, "s_cmp_gt_u32", COND_UGT>;
-def S_CMP_GE_U32 : SOPC_CMP_32 <0x00000009, "s_cmp_ge_u32", COND_UGE>;
-def S_CMP_LT_U32 : SOPC_CMP_32 <0x0000000a, "s_cmp_lt_u32", COND_ULT>;
-def S_CMP_LE_U32 : SOPC_CMP_32 <0x0000000b, "s_cmp_le_u32", COND_ULE>;
-def S_BITCMP0_B32 : SOPC_32 <0x0000000c, "s_bitcmp0_b32">;
-def S_BITCMP1_B32 : SOPC_32 <0x0000000d, "s_bitcmp1_b32">;
-def S_BITCMP0_B64 : SOPC_64_32 <0x0000000e, "s_bitcmp0_b64">;
-def S_BITCMP1_B64 : SOPC_64_32 <0x0000000f, "s_bitcmp1_b64">;
-def S_SETVSKIP : SOPC_32 <0x00000010, "s_setvskip">;
-
-//===----------------------------------------------------------------------===//
-// SOPK Instructions
-//===----------------------------------------------------------------------===//
-
-let isReMaterializable = 1, isMoveImm = 1 in {
-defm S_MOVK_I32 : SOPK_32 <sopk<0x00>, "s_movk_i32", []>;
-} // End isReMaterializable = 1
-let Uses = [SCC] in {
- defm S_CMOVK_I32 : SOPK_32 <sopk<0x02, 0x01>, "s_cmovk_i32", []>;
-}
-
-let isCompare = 1 in {
-
-/*
-This instruction is disabled for now until we can figure out how to teach
-the instruction selector to correctly use the S_CMP* vs V_CMP*
-instructions.
-
-When this instruction is enabled the code generator sometimes produces this
-invalid sequence:
-
-SCC = S_CMPK_EQ_I32 SGPR0, imm
-VCC = COPY SCC
-VGPR0 = V_CNDMASK VCC, VGPR0, VGPR1
-
-defm S_CMPK_EQ_I32 : SOPK_SCC <sopk<0x03, 0x02>, "s_cmpk_eq_i32",
- [(set i1:$dst, (setcc i32:$src0, imm:$src1, SETEQ))]
->;
-*/
-
-defm S_CMPK_EQ_I32 : SOPK_SCC <sopk<0x03, 0x02>, "s_cmpk_eq_i32", []>;
-defm S_CMPK_LG_I32 : SOPK_SCC <sopk<0x04, 0x03>, "s_cmpk_lg_i32", []>;
-defm S_CMPK_GT_I32 : SOPK_SCC <sopk<0x05, 0x04>, "s_cmpk_gt_i32", []>;
-defm S_CMPK_GE_I32 : SOPK_SCC <sopk<0x06, 0x05>, "s_cmpk_ge_i32", []>;
-defm S_CMPK_LT_I32 : SOPK_SCC <sopk<0x07, 0x06>, "s_cmpk_lt_i32", []>;
-defm S_CMPK_LE_I32 : SOPK_SCC <sopk<0x08, 0x07>, "s_cmpk_le_i32", []>;
-defm S_CMPK_EQ_U32 : SOPK_SCC <sopk<0x09, 0x08>, "s_cmpk_eq_u32", []>;
-defm S_CMPK_LG_U32 : SOPK_SCC <sopk<0x0a, 0x09>, "s_cmpk_lg_u32", []>;
-defm S_CMPK_GT_U32 : SOPK_SCC <sopk<0x0b, 0x0a>, "s_cmpk_gt_u32", []>;
-defm S_CMPK_GE_U32 : SOPK_SCC <sopk<0x0c, 0x0b>, "s_cmpk_ge_u32", []>;
-defm S_CMPK_LT_U32 : SOPK_SCC <sopk<0x0d, 0x0c>, "s_cmpk_lt_u32", []>;
-defm S_CMPK_LE_U32 : SOPK_SCC <sopk<0x0e, 0x0d>, "s_cmpk_le_u32", []>;
-} // End isCompare = 1
-
-let Defs = [SCC], isCommutable = 1, DisableEncoding = "$src0",
- Constraints = "$sdst = $src0" in {
- defm S_ADDK_I32 : SOPK_32TIE <sopk<0x0f, 0x0e>, "s_addk_i32", []>;
- defm S_MULK_I32 : SOPK_32TIE <sopk<0x10, 0x0f>, "s_mulk_i32", []>;
-}
-
-defm S_CBRANCH_I_FORK : SOPK_m <
- sopk<0x11, 0x10>, "s_cbranch_i_fork", (outs),
- (ins SReg_64:$sdst, u16imm:$simm16), " $sdst, $simm16"
->;
-
-let mayLoad = 1 in {
-defm S_GETREG_B32 : SOPK_m <
- sopk<0x12, 0x11>, "s_getreg_b32", (outs SReg_32:$sdst),
- (ins hwreg:$simm16), " $sdst, $simm16"
->;
-}
-
-defm S_SETREG_B32 : SOPK_m <
- sopk<0x13, 0x12>, "s_setreg_b32", (outs),
- (ins SReg_32:$sdst, hwreg:$simm16), " $simm16, $sdst"
->;
-// FIXME: Not on SI?
-//defm S_GETREG_REGRD_B32 : SOPK_32 <sopk<0x14, 0x13>, "s_getreg_regrd_b32", []>;
-defm S_SETREG_IMM32_B32 : SOPK_IMM32 <
- sopk<0x15, 0x14>, "s_setreg_imm32_b32", (outs),
- (ins i32imm:$imm, hwreg:$simm16), " $simm16, $imm"
->;
-
-//===----------------------------------------------------------------------===//
-// SOPP Instructions
-//===----------------------------------------------------------------------===//
-
-def S_NOP : SOPP <0x00000000, (ins i16imm:$simm16), "s_nop $simm16">;
-
-let isTerminator = 1 in {
-
-def S_ENDPGM : SOPP <0x00000001, (ins), "s_endpgm",
- [(AMDGPUendpgm)]> {
- let simm16 = 0;
- let isBarrier = 1;
- let hasCtrlDep = 1;
- let hasSideEffects = 1;
-}
-
-let isBranch = 1 in {
-def S_BRANCH : SOPP <
- 0x00000002, (ins sopp_brtarget:$simm16), "s_branch $simm16",
- [(br bb:$simm16)]> {
- let isBarrier = 1;
-}
-
-let Uses = [SCC] in {
-def S_CBRANCH_SCC0 : SOPP <
- 0x00000004, (ins sopp_brtarget:$simm16),
- "s_cbranch_scc0 $simm16"
->;
-def S_CBRANCH_SCC1 : SOPP <
- 0x00000005, (ins sopp_brtarget:$simm16),
- "s_cbranch_scc1 $simm16",
- [(si_uniform_br_scc SCC, bb:$simm16)]
->;
-} // End Uses = [SCC]
-
-let Uses = [VCC] in {
-def S_CBRANCH_VCCZ : SOPP <
- 0x00000006, (ins sopp_brtarget:$simm16),
- "s_cbranch_vccz $simm16"
->;
-def S_CBRANCH_VCCNZ : SOPP <
- 0x00000007, (ins sopp_brtarget:$simm16),
- "s_cbranch_vccnz $simm16"
->;
-} // End Uses = [VCC]
-
-let Uses = [EXEC] in {
-def S_CBRANCH_EXECZ : SOPP <
- 0x00000008, (ins sopp_brtarget:$simm16),
- "s_cbranch_execz $simm16"
->;
-def S_CBRANCH_EXECNZ : SOPP <
- 0x00000009, (ins sopp_brtarget:$simm16),
- "s_cbranch_execnz $simm16"
->;
-} // End Uses = [EXEC]
-
-
-} // End isBranch = 1
-} // End isTerminator = 1
-
-let hasSideEffects = 1 in {
-def S_BARRIER : SOPP <0x0000000a, (ins), "s_barrier",
- [(int_amdgcn_s_barrier)]
-> {
- let SchedRW = [WriteBarrier];
- let simm16 = 0;
- let mayLoad = 1;
- let mayStore = 1;
- let isConvergent = 1;
-}
-
-let mayLoad = 1, mayStore = 1, hasSideEffects = 1 in
-def S_WAITCNT : SOPP <0x0000000c, (ins WAIT_FLAG:$simm16), "s_waitcnt $simm16">;
-def S_SETHALT : SOPP <0x0000000d, (ins i16imm:$simm16), "s_sethalt $simm16">;
-
-// On SI the documentation says sleep for approximately 64 * low 2
-// bits, consistent with the reported maximum of 448. On VI the
-// maximum reported is 960 cycles, so 960 / 64 = 15 max, so is the
-// maximum really 15 on VI?
-def S_SLEEP : SOPP <0x0000000e, (ins i32imm:$simm16),
- "s_sleep $simm16", [(int_amdgcn_s_sleep SIMM16bit:$simm16)]> {
- let hasSideEffects = 1;
- let mayLoad = 1;
- let mayStore = 1;
-}
-
-def S_SETPRIO : SOPP <0x0000000f, (ins i16imm:$simm16), "s_setprio $simm16">;
-
-let Uses = [EXEC, M0] in {
- // FIXME: Should this be mayLoad+mayStore?
- def S_SENDMSG : SOPP <0x00000010, (ins SendMsgImm:$simm16), "s_sendmsg $simm16",
- [(AMDGPUsendmsg (i32 imm:$simm16))]
- >;
-} // End Uses = [EXEC, M0]
-
-def S_SENDMSGHALT : SOPP <0x00000011, (ins SendMsgImm:$simm16), "s_sendmsghalt $simm16">;
-def S_TRAP : SOPP <0x00000012, (ins i16imm:$simm16), "s_trap $simm16">;
-def S_ICACHE_INV : SOPP <0x00000013, (ins), "s_icache_inv"> {
- let simm16 = 0;
-}
-def S_INCPERFLEVEL : SOPP <0x00000014, (ins i16imm:$simm16), "s_incperflevel $simm16">;
-def S_DECPERFLEVEL : SOPP <0x00000015, (ins i16imm:$simm16), "s_decperflevel $simm16">;
-def S_TTRACEDATA : SOPP <0x00000016, (ins), "s_ttracedata"> {
- let simm16 = 0;
-}
-} // End hasSideEffects
-
-//===----------------------------------------------------------------------===//
-// VOPC Instructions
-//===----------------------------------------------------------------------===//
-
-let isCompare = 1, isCommutable = 1 in {
-
-defm V_CMP_F_F32 : VOPC_F32 <vopc<0x0, 0x40>, "v_cmp_f_f32">;
-defm V_CMP_LT_F32 : VOPC_F32 <vopc<0x1, 0x41>, "v_cmp_lt_f32", COND_OLT, "v_cmp_gt_f32">;
-defm V_CMP_EQ_F32 : VOPC_F32 <vopc<0x2, 0x42>, "v_cmp_eq_f32", COND_OEQ>;
-defm V_CMP_LE_F32 : VOPC_F32 <vopc<0x3, 0x43>, "v_cmp_le_f32", COND_OLE, "v_cmp_ge_f32">;
-defm V_CMP_GT_F32 : VOPC_F32 <vopc<0x4, 0x44>, "v_cmp_gt_f32", COND_OGT>;
-defm V_CMP_LG_F32 : VOPC_F32 <vopc<0x5, 0x45>, "v_cmp_lg_f32", COND_ONE>;
-defm V_CMP_GE_F32 : VOPC_F32 <vopc<0x6, 0x46>, "v_cmp_ge_f32", COND_OGE>;
-defm V_CMP_O_F32 : VOPC_F32 <vopc<0x7, 0x47>, "v_cmp_o_f32", COND_O>;
-defm V_CMP_U_F32 : VOPC_F32 <vopc<0x8, 0x48>, "v_cmp_u_f32", COND_UO>;
-defm V_CMP_NGE_F32 : VOPC_F32 <vopc<0x9, 0x49>, "v_cmp_nge_f32", COND_ULT, "v_cmp_nle_f32">;
-defm V_CMP_NLG_F32 : VOPC_F32 <vopc<0xa, 0x4a>, "v_cmp_nlg_f32", COND_UEQ>;
-defm V_CMP_NGT_F32 : VOPC_F32 <vopc<0xb, 0x4b>, "v_cmp_ngt_f32", COND_ULE, "v_cmp_nlt_f32">;
-defm V_CMP_NLE_F32 : VOPC_F32 <vopc<0xc, 0x4c>, "v_cmp_nle_f32", COND_UGT>;
-defm V_CMP_NEQ_F32 : VOPC_F32 <vopc<0xd, 0x4d>, "v_cmp_neq_f32", COND_UNE>;
-defm V_CMP_NLT_F32 : VOPC_F32 <vopc<0xe, 0x4e>, "v_cmp_nlt_f32", COND_UGE>;
-defm V_CMP_TRU_F32 : VOPC_F32 <vopc<0xf, 0x4f>, "v_cmp_tru_f32">;
-
-
-defm V_CMPX_F_F32 : VOPCX_F32 <vopc<0x10, 0x50>, "v_cmpx_f_f32">;
-defm V_CMPX_LT_F32 : VOPCX_F32 <vopc<0x11, 0x51>, "v_cmpx_lt_f32", "v_cmpx_gt_f32">;
-defm V_CMPX_EQ_F32 : VOPCX_F32 <vopc<0x12, 0x52>, "v_cmpx_eq_f32">;
-defm V_CMPX_LE_F32 : VOPCX_F32 <vopc<0x13, 0x53>, "v_cmpx_le_f32", "v_cmpx_ge_f32">;
-defm V_CMPX_GT_F32 : VOPCX_F32 <vopc<0x14, 0x54>, "v_cmpx_gt_f32">;
-defm V_CMPX_LG_F32 : VOPCX_F32 <vopc<0x15, 0x55>, "v_cmpx_lg_f32">;
-defm V_CMPX_GE_F32 : VOPCX_F32 <vopc<0x16, 0x56>, "v_cmpx_ge_f32">;
-defm V_CMPX_O_F32 : VOPCX_F32 <vopc<0x17, 0x57>, "v_cmpx_o_f32">;
-defm V_CMPX_U_F32 : VOPCX_F32 <vopc<0x18, 0x58>, "v_cmpx_u_f32">;
-defm V_CMPX_NGE_F32 : VOPCX_F32 <vopc<0x19, 0x59>, "v_cmpx_nge_f32">;
-defm V_CMPX_NLG_F32 : VOPCX_F32 <vopc<0x1a, 0x5a>, "v_cmpx_nlg_f32">;
-defm V_CMPX_NGT_F32 : VOPCX_F32 <vopc<0x1b, 0x5b>, "v_cmpx_ngt_f32">;
-defm V_CMPX_NLE_F32 : VOPCX_F32 <vopc<0x1c, 0x5c>, "v_cmpx_nle_f32">;
-defm V_CMPX_NEQ_F32 : VOPCX_F32 <vopc<0x1d, 0x5d>, "v_cmpx_neq_f32">;
-defm V_CMPX_NLT_F32 : VOPCX_F32 <vopc<0x1e, 0x5e>, "v_cmpx_nlt_f32">;
-defm V_CMPX_TRU_F32 : VOPCX_F32 <vopc<0x1f, 0x5f>, "v_cmpx_tru_f32">;
-
-
-defm V_CMP_F_F64 : VOPC_F64 <vopc<0x20, 0x60>, "v_cmp_f_f64">;
-defm V_CMP_LT_F64 : VOPC_F64 <vopc<0x21, 0x61>, "v_cmp_lt_f64", COND_OLT, "v_cmp_gt_f64">;
-defm V_CMP_EQ_F64 : VOPC_F64 <vopc<0x22, 0x62>, "v_cmp_eq_f64", COND_OEQ>;
-defm V_CMP_LE_F64 : VOPC_F64 <vopc<0x23, 0x63>, "v_cmp_le_f64", COND_OLE, "v_cmp_ge_f64">;
-defm V_CMP_GT_F64 : VOPC_F64 <vopc<0x24, 0x64>, "v_cmp_gt_f64", COND_OGT>;
-defm V_CMP_LG_F64 : VOPC_F64 <vopc<0x25, 0x65>, "v_cmp_lg_f64", COND_ONE>;
-defm V_CMP_GE_F64 : VOPC_F64 <vopc<0x26, 0x66>, "v_cmp_ge_f64", COND_OGE>;
-defm V_CMP_O_F64 : VOPC_F64 <vopc<0x27, 0x67>, "v_cmp_o_f64", COND_O>;
-defm V_CMP_U_F64 : VOPC_F64 <vopc<0x28, 0x68>, "v_cmp_u_f64", COND_UO>;
-defm V_CMP_NGE_F64 : VOPC_F64 <vopc<0x29, 0x69>, "v_cmp_nge_f64", COND_ULT, "v_cmp_nle_f64">;
-defm V_CMP_NLG_F64 : VOPC_F64 <vopc<0x2a, 0x6a>, "v_cmp_nlg_f64", COND_UEQ>;
-defm V_CMP_NGT_F64 : VOPC_F64 <vopc<0x2b, 0x6b>, "v_cmp_ngt_f64", COND_ULE, "v_cmp_nlt_f64">;
-defm V_CMP_NLE_F64 : VOPC_F64 <vopc<0x2c, 0x6c>, "v_cmp_nle_f64", COND_UGT>;
-defm V_CMP_NEQ_F64 : VOPC_F64 <vopc<0x2d, 0x6d>, "v_cmp_neq_f64", COND_UNE>;
-defm V_CMP_NLT_F64 : VOPC_F64 <vopc<0x2e, 0x6e>, "v_cmp_nlt_f64", COND_UGE>;
-defm V_CMP_TRU_F64 : VOPC_F64 <vopc<0x2f, 0x6f>, "v_cmp_tru_f64">;
-
-
-defm V_CMPX_F_F64 : VOPCX_F64 <vopc<0x30, 0x70>, "v_cmpx_f_f64">;
-defm V_CMPX_LT_F64 : VOPCX_F64 <vopc<0x31, 0x71>, "v_cmpx_lt_f64", "v_cmpx_gt_f64">;
-defm V_CMPX_EQ_F64 : VOPCX_F64 <vopc<0x32, 0x72>, "v_cmpx_eq_f64">;
-defm V_CMPX_LE_F64 : VOPCX_F64 <vopc<0x33, 0x73>, "v_cmpx_le_f64", "v_cmpx_ge_f64">;
-defm V_CMPX_GT_F64 : VOPCX_F64 <vopc<0x34, 0x74>, "v_cmpx_gt_f64">;
-defm V_CMPX_LG_F64 : VOPCX_F64 <vopc<0x35, 0x75>, "v_cmpx_lg_f64">;
-defm V_CMPX_GE_F64 : VOPCX_F64 <vopc<0x36, 0x76>, "v_cmpx_ge_f64">;
-defm V_CMPX_O_F64 : VOPCX_F64 <vopc<0x37, 0x77>, "v_cmpx_o_f64">;
-defm V_CMPX_U_F64 : VOPCX_F64 <vopc<0x38, 0x78>, "v_cmpx_u_f64">;
-defm V_CMPX_NGE_F64 : VOPCX_F64 <vopc<0x39, 0x79>, "v_cmpx_nge_f64", "v_cmpx_nle_f64">;
-defm V_CMPX_NLG_F64 : VOPCX_F64 <vopc<0x3a, 0x7a>, "v_cmpx_nlg_f64">;
-defm V_CMPX_NGT_F64 : VOPCX_F64 <vopc<0x3b, 0x7b>, "v_cmpx_ngt_f64", "v_cmpx_nlt_f64">;
-defm V_CMPX_NLE_F64 : VOPCX_F64 <vopc<0x3c, 0x7c>, "v_cmpx_nle_f64">;
-defm V_CMPX_NEQ_F64 : VOPCX_F64 <vopc<0x3d, 0x7d>, "v_cmpx_neq_f64">;
-defm V_CMPX_NLT_F64 : VOPCX_F64 <vopc<0x3e, 0x7e>, "v_cmpx_nlt_f64">;
-defm V_CMPX_TRU_F64 : VOPCX_F64 <vopc<0x3f, 0x7f>, "v_cmpx_tru_f64">;
-
-
-let SubtargetPredicate = isSICI in {
-
-defm V_CMPS_F_F32 : VOPC_F32 <vopc<0x40>, "v_cmps_f_f32">;
-defm V_CMPS_LT_F32 : VOPC_F32 <vopc<0x41>, "v_cmps_lt_f32", COND_NULL, "v_cmps_gt_f32">;
-defm V_CMPS_EQ_F32 : VOPC_F32 <vopc<0x42>, "v_cmps_eq_f32">;
-defm V_CMPS_LE_F32 : VOPC_F32 <vopc<0x43>, "v_cmps_le_f32", COND_NULL, "v_cmps_ge_f32">;
-defm V_CMPS_GT_F32 : VOPC_F32 <vopc<0x44>, "v_cmps_gt_f32">;
-defm V_CMPS_LG_F32 : VOPC_F32 <vopc<0x45>, "v_cmps_lg_f32">;
-defm V_CMPS_GE_F32 : VOPC_F32 <vopc<0x46>, "v_cmps_ge_f32">;
-defm V_CMPS_O_F32 : VOPC_F32 <vopc<0x47>, "v_cmps_o_f32">;
-defm V_CMPS_U_F32 : VOPC_F32 <vopc<0x48>, "v_cmps_u_f32">;
-defm V_CMPS_NGE_F32 : VOPC_F32 <vopc<0x49>, "v_cmps_nge_f32", COND_NULL, "v_cmps_nle_f32">;
-defm V_CMPS_NLG_F32 : VOPC_F32 <vopc<0x4a>, "v_cmps_nlg_f32">;
-defm V_CMPS_NGT_F32 : VOPC_F32 <vopc<0x4b>, "v_cmps_ngt_f32", COND_NULL, "v_cmps_nlt_f32">;
-defm V_CMPS_NLE_F32 : VOPC_F32 <vopc<0x4c>, "v_cmps_nle_f32">;
-defm V_CMPS_NEQ_F32 : VOPC_F32 <vopc<0x4d>, "v_cmps_neq_f32">;
-defm V_CMPS_NLT_F32 : VOPC_F32 <vopc<0x4e>, "v_cmps_nlt_f32">;
-defm V_CMPS_TRU_F32 : VOPC_F32 <vopc<0x4f>, "v_cmps_tru_f32">;
-
-
-defm V_CMPSX_F_F32 : VOPCX_F32 <vopc<0x50>, "v_cmpsx_f_f32">;
-defm V_CMPSX_LT_F32 : VOPCX_F32 <vopc<0x51>, "v_cmpsx_lt_f32", "v_cmpsx_gt_f32">;
-defm V_CMPSX_EQ_F32 : VOPCX_F32 <vopc<0x52>, "v_cmpsx_eq_f32">;
-defm V_CMPSX_LE_F32 : VOPCX_F32 <vopc<0x53>, "v_cmpsx_le_f32", "v_cmpsx_ge_f32">;
-defm V_CMPSX_GT_F32 : VOPCX_F32 <vopc<0x54>, "v_cmpsx_gt_f32">;
-defm V_CMPSX_LG_F32 : VOPCX_F32 <vopc<0x55>, "v_cmpsx_lg_f32">;
-defm V_CMPSX_GE_F32 : VOPCX_F32 <vopc<0x56>, "v_cmpsx_ge_f32">;
-defm V_CMPSX_O_F32 : VOPCX_F32 <vopc<0x57>, "v_cmpsx_o_f32">;
-defm V_CMPSX_U_F32 : VOPCX_F32 <vopc<0x58>, "v_cmpsx_u_f32">;
-defm V_CMPSX_NGE_F32 : VOPCX_F32 <vopc<0x59>, "v_cmpsx_nge_f32", "v_cmpsx_nle_f32">;
-defm V_CMPSX_NLG_F32 : VOPCX_F32 <vopc<0x5a>, "v_cmpsx_nlg_f32">;
-defm V_CMPSX_NGT_F32 : VOPCX_F32 <vopc<0x5b>, "v_cmpsx_ngt_f32", "v_cmpsx_nlt_f32">;
-defm V_CMPSX_NLE_F32 : VOPCX_F32 <vopc<0x5c>, "v_cmpsx_nle_f32">;
-defm V_CMPSX_NEQ_F32 : VOPCX_F32 <vopc<0x5d>, "v_cmpsx_neq_f32">;
-defm V_CMPSX_NLT_F32 : VOPCX_F32 <vopc<0x5e>, "v_cmpsx_nlt_f32">;
-defm V_CMPSX_TRU_F32 : VOPCX_F32 <vopc<0x5f>, "v_cmpsx_tru_f32">;
-
-
-defm V_CMPS_F_F64 : VOPC_F64 <vopc<0x60>, "v_cmps_f_f64">;
-defm V_CMPS_LT_F64 : VOPC_F64 <vopc<0x61>, "v_cmps_lt_f64", COND_NULL, "v_cmps_gt_f64">;
-defm V_CMPS_EQ_F64 : VOPC_F64 <vopc<0x62>, "v_cmps_eq_f64">;
-defm V_CMPS_LE_F64 : VOPC_F64 <vopc<0x63>, "v_cmps_le_f64", COND_NULL, "v_cmps_ge_f64">;
-defm V_CMPS_GT_F64 : VOPC_F64 <vopc<0x64>, "v_cmps_gt_f64">;
-defm V_CMPS_LG_F64 : VOPC_F64 <vopc<0x65>, "v_cmps_lg_f64">;
-defm V_CMPS_GE_F64 : VOPC_F64 <vopc<0x66>, "v_cmps_ge_f64">;
-defm V_CMPS_O_F64 : VOPC_F64 <vopc<0x67>, "v_cmps_o_f64">;
-defm V_CMPS_U_F64 : VOPC_F64 <vopc<0x68>, "v_cmps_u_f64">;
-defm V_CMPS_NGE_F64 : VOPC_F64 <vopc<0x69>, "v_cmps_nge_f64", COND_NULL, "v_cmps_nle_f64">;
-defm V_CMPS_NLG_F64 : VOPC_F64 <vopc<0x6a>, "v_cmps_nlg_f64">;
-defm V_CMPS_NGT_F64 : VOPC_F64 <vopc<0x6b>, "v_cmps_ngt_f64", COND_NULL, "v_cmps_nlt_f64">;
-defm V_CMPS_NLE_F64 : VOPC_F64 <vopc<0x6c>, "v_cmps_nle_f64">;
-defm V_CMPS_NEQ_F64 : VOPC_F64 <vopc<0x6d>, "v_cmps_neq_f64">;
-defm V_CMPS_NLT_F64 : VOPC_F64 <vopc<0x6e>, "v_cmps_nlt_f64">;
-defm V_CMPS_TRU_F64 : VOPC_F64 <vopc<0x6f>, "v_cmps_tru_f64">;
-
-
-defm V_CMPSX_F_F64 : VOPCX_F64 <vopc<0x70>, "v_cmpsx_f_f64">;
-defm V_CMPSX_LT_F64 : VOPCX_F64 <vopc<0x71>, "v_cmpsx_lt_f64", "v_cmpsx_gt_f64">;
-defm V_CMPSX_EQ_F64 : VOPCX_F64 <vopc<0x72>, "v_cmpsx_eq_f64">;
-defm V_CMPSX_LE_F64 : VOPCX_F64 <vopc<0x73>, "v_cmpsx_le_f64", "v_cmpsx_ge_f64">;
-defm V_CMPSX_GT_F64 : VOPCX_F64 <vopc<0x74>, "v_cmpsx_gt_f64">;
-defm V_CMPSX_LG_F64 : VOPCX_F64 <vopc<0x75>, "v_cmpsx_lg_f64">;
-defm V_CMPSX_GE_F64 : VOPCX_F64 <vopc<0x76>, "v_cmpsx_ge_f64">;
-defm V_CMPSX_O_F64 : VOPCX_F64 <vopc<0x77>, "v_cmpsx_o_f64">;
-defm V_CMPSX_U_F64 : VOPCX_F64 <vopc<0x78>, "v_cmpsx_u_f64">;
-defm V_CMPSX_NGE_F64 : VOPCX_F64 <vopc<0x79>, "v_cmpsx_nge_f64", "v_cmpsx_nle_f64">;
-defm V_CMPSX_NLG_F64 : VOPCX_F64 <vopc<0x7a>, "v_cmpsx_nlg_f64">;
-defm V_CMPSX_NGT_F64 : VOPCX_F64 <vopc<0x7b>, "v_cmpsx_ngt_f64", "v_cmpsx_nlt_f64">;
-defm V_CMPSX_NLE_F64 : VOPCX_F64 <vopc<0x7c>, "v_cmpsx_nle_f64">;
-defm V_CMPSX_NEQ_F64 : VOPCX_F64 <vopc<0x7d>, "v_cmpsx_neq_f64">;
-defm V_CMPSX_NLT_F64 : VOPCX_F64 <vopc<0x7e>, "v_cmpsx_nlt_f64">;
-defm V_CMPSX_TRU_F64 : VOPCX_F64 <vopc<0x7f>, "v_cmpsx_tru_f64">;
-
-} // End SubtargetPredicate = isSICI
-
-defm V_CMP_F_I32 : VOPC_I32 <vopc<0x80, 0xc0>, "v_cmp_f_i32">;
-defm V_CMP_LT_I32 : VOPC_I32 <vopc<0x81, 0xc1>, "v_cmp_lt_i32", COND_SLT, "v_cmp_gt_i32">;
-defm V_CMP_EQ_I32 : VOPC_I32 <vopc<0x82, 0xc2>, "v_cmp_eq_i32", COND_EQ>;
-defm V_CMP_LE_I32 : VOPC_I32 <vopc<0x83, 0xc3>, "v_cmp_le_i32", COND_SLE, "v_cmp_ge_i32">;
-defm V_CMP_GT_I32 : VOPC_I32 <vopc<0x84, 0xc4>, "v_cmp_gt_i32", COND_SGT>;
-defm V_CMP_NE_I32 : VOPC_I32 <vopc<0x85, 0xc5>, "v_cmp_ne_i32", COND_NE>;
-defm V_CMP_GE_I32 : VOPC_I32 <vopc<0x86, 0xc6>, "v_cmp_ge_i32", COND_SGE>;
-defm V_CMP_T_I32 : VOPC_I32 <vopc<0x87, 0xc7>, "v_cmp_t_i32">;
-
-
-defm V_CMPX_F_I32 : VOPCX_I32 <vopc<0x90, 0xd0>, "v_cmpx_f_i32">;
-defm V_CMPX_LT_I32 : VOPCX_I32 <vopc<0x91, 0xd1>, "v_cmpx_lt_i32", "v_cmpx_gt_i32">;
-defm V_CMPX_EQ_I32 : VOPCX_I32 <vopc<0x92, 0xd2>, "v_cmpx_eq_i32">;
-defm V_CMPX_LE_I32 : VOPCX_I32 <vopc<0x93, 0xd3>, "v_cmpx_le_i32", "v_cmpx_ge_i32">;
-defm V_CMPX_GT_I32 : VOPCX_I32 <vopc<0x94, 0xd4>, "v_cmpx_gt_i32">;
-defm V_CMPX_NE_I32 : VOPCX_I32 <vopc<0x95, 0xd5>, "v_cmpx_ne_i32">;
-defm V_CMPX_GE_I32 : VOPCX_I32 <vopc<0x96, 0xd6>, "v_cmpx_ge_i32">;
-defm V_CMPX_T_I32 : VOPCX_I32 <vopc<0x97, 0xd7>, "v_cmpx_t_i32">;
-
-
-defm V_CMP_F_I64 : VOPC_I64 <vopc<0xa0, 0xe0>, "v_cmp_f_i64">;
-defm V_CMP_LT_I64 : VOPC_I64 <vopc<0xa1, 0xe1>, "v_cmp_lt_i64", COND_SLT, "v_cmp_gt_i64">;
-defm V_CMP_EQ_I64 : VOPC_I64 <vopc<0xa2, 0xe2>, "v_cmp_eq_i64", COND_EQ>;
-defm V_CMP_LE_I64 : VOPC_I64 <vopc<0xa3, 0xe3>, "v_cmp_le_i64", COND_SLE, "v_cmp_ge_i64">;
-defm V_CMP_GT_I64 : VOPC_I64 <vopc<0xa4, 0xe4>, "v_cmp_gt_i64", COND_SGT>;
-defm V_CMP_NE_I64 : VOPC_I64 <vopc<0xa5, 0xe5>, "v_cmp_ne_i64", COND_NE>;
-defm V_CMP_GE_I64 : VOPC_I64 <vopc<0xa6, 0xe6>, "v_cmp_ge_i64", COND_SGE>;
-defm V_CMP_T_I64 : VOPC_I64 <vopc<0xa7, 0xe7>, "v_cmp_t_i64">;
-
-
-defm V_CMPX_F_I64 : VOPCX_I64 <vopc<0xb0, 0xf0>, "v_cmpx_f_i64">;
-defm V_CMPX_LT_I64 : VOPCX_I64 <vopc<0xb1, 0xf1>, "v_cmpx_lt_i64", "v_cmpx_gt_i64">;
-defm V_CMPX_EQ_I64 : VOPCX_I64 <vopc<0xb2, 0xf2>, "v_cmpx_eq_i64">;
-defm V_CMPX_LE_I64 : VOPCX_I64 <vopc<0xb3, 0xf3>, "v_cmpx_le_i64", "v_cmpx_ge_i64">;
-defm V_CMPX_GT_I64 : VOPCX_I64 <vopc<0xb4, 0xf4>, "v_cmpx_gt_i64">;
-defm V_CMPX_NE_I64 : VOPCX_I64 <vopc<0xb5, 0xf5>, "v_cmpx_ne_i64">;
-defm V_CMPX_GE_I64 : VOPCX_I64 <vopc<0xb6, 0xf6>, "v_cmpx_ge_i64">;
-defm V_CMPX_T_I64 : VOPCX_I64 <vopc<0xb7, 0xf7>, "v_cmpx_t_i64">;
-
-
-defm V_CMP_F_U32 : VOPC_I32 <vopc<0xc0, 0xc8>, "v_cmp_f_u32">;
-defm V_CMP_LT_U32 : VOPC_I32 <vopc<0xc1, 0xc9>, "v_cmp_lt_u32", COND_ULT, "v_cmp_gt_u32">;
-defm V_CMP_EQ_U32 : VOPC_I32 <vopc<0xc2, 0xca>, "v_cmp_eq_u32", COND_EQ>;
-defm V_CMP_LE_U32 : VOPC_I32 <vopc<0xc3, 0xcb>, "v_cmp_le_u32", COND_ULE, "v_cmp_ge_u32">;
-defm V_CMP_GT_U32 : VOPC_I32 <vopc<0xc4, 0xcc>, "v_cmp_gt_u32", COND_UGT>;
-defm V_CMP_NE_U32 : VOPC_I32 <vopc<0xc5, 0xcd>, "v_cmp_ne_u32", COND_NE>;
-defm V_CMP_GE_U32 : VOPC_I32 <vopc<0xc6, 0xce>, "v_cmp_ge_u32", COND_UGE>;
-defm V_CMP_T_U32 : VOPC_I32 <vopc<0xc7, 0xcf>, "v_cmp_t_u32">;
-
-
-defm V_CMPX_F_U32 : VOPCX_I32 <vopc<0xd0, 0xd8>, "v_cmpx_f_u32">;
-defm V_CMPX_LT_U32 : VOPCX_I32 <vopc<0xd1, 0xd9>, "v_cmpx_lt_u32", "v_cmpx_gt_u32">;
-defm V_CMPX_EQ_U32 : VOPCX_I32 <vopc<0xd2, 0xda>, "v_cmpx_eq_u32">;
-defm V_CMPX_LE_U32 : VOPCX_I32 <vopc<0xd3, 0xdb>, "v_cmpx_le_u32", "v_cmpx_le_u32">;
-defm V_CMPX_GT_U32 : VOPCX_I32 <vopc<0xd4, 0xdc>, "v_cmpx_gt_u32">;
-defm V_CMPX_NE_U32 : VOPCX_I32 <vopc<0xd5, 0xdd>, "v_cmpx_ne_u32">;
-defm V_CMPX_GE_U32 : VOPCX_I32 <vopc<0xd6, 0xde>, "v_cmpx_ge_u32">;
-defm V_CMPX_T_U32 : VOPCX_I32 <vopc<0xd7, 0xdf>, "v_cmpx_t_u32">;
-
-
-defm V_CMP_F_U64 : VOPC_I64 <vopc<0xe0, 0xe8>, "v_cmp_f_u64">;
-defm V_CMP_LT_U64 : VOPC_I64 <vopc<0xe1, 0xe9>, "v_cmp_lt_u64", COND_ULT, "v_cmp_gt_u64">;
-defm V_CMP_EQ_U64 : VOPC_I64 <vopc<0xe2, 0xea>, "v_cmp_eq_u64", COND_EQ>;
-defm V_CMP_LE_U64 : VOPC_I64 <vopc<0xe3, 0xeb>, "v_cmp_le_u64", COND_ULE, "v_cmp_ge_u64">;
-defm V_CMP_GT_U64 : VOPC_I64 <vopc<0xe4, 0xec>, "v_cmp_gt_u64", COND_UGT>;
-defm V_CMP_NE_U64 : VOPC_I64 <vopc<0xe5, 0xed>, "v_cmp_ne_u64", COND_NE>;
-defm V_CMP_GE_U64 : VOPC_I64 <vopc<0xe6, 0xee>, "v_cmp_ge_u64", COND_UGE>;
-defm V_CMP_T_U64 : VOPC_I64 <vopc<0xe7, 0xef>, "v_cmp_t_u64">;
-
-defm V_CMPX_F_U64 : VOPCX_I64 <vopc<0xf0, 0xf8>, "v_cmpx_f_u64">;
-defm V_CMPX_LT_U64 : VOPCX_I64 <vopc<0xf1, 0xf9>, "v_cmpx_lt_u64", "v_cmpx_gt_u64">;
-defm V_CMPX_EQ_U64 : VOPCX_I64 <vopc<0xf2, 0xfa>, "v_cmpx_eq_u64">;
-defm V_CMPX_LE_U64 : VOPCX_I64 <vopc<0xf3, 0xfb>, "v_cmpx_le_u64", "v_cmpx_ge_u64">;
-defm V_CMPX_GT_U64 : VOPCX_I64 <vopc<0xf4, 0xfc>, "v_cmpx_gt_u64">;
-defm V_CMPX_NE_U64 : VOPCX_I64 <vopc<0xf5, 0xfd>, "v_cmpx_ne_u64">;
-defm V_CMPX_GE_U64 : VOPCX_I64 <vopc<0xf6, 0xfe>, "v_cmpx_ge_u64">;
-defm V_CMPX_T_U64 : VOPCX_I64 <vopc<0xf7, 0xff>, "v_cmpx_t_u64">;
-
-} // End isCompare = 1, isCommutable = 1
-
-defm V_CMP_CLASS_F32 : VOPC_CLASS_F32 <vopc<0x88, 0x10>, "v_cmp_class_f32">;
-defm V_CMPX_CLASS_F32 : VOPCX_CLASS_F32 <vopc<0x98, 0x11>, "v_cmpx_class_f32">;
-defm V_CMP_CLASS_F64 : VOPC_CLASS_F64 <vopc<0xa8, 0x12>, "v_cmp_class_f64">;
-defm V_CMPX_CLASS_F64 : VOPCX_CLASS_F64 <vopc<0xb8, 0x13>, "v_cmpx_class_f64">;
-
-//===----------------------------------------------------------------------===//
-// DS Instructions
-//===----------------------------------------------------------------------===//
-
-defm DS_ADD_U32 : DS_1A1D_NORET <0x0, "ds_add_u32", VGPR_32>;
-defm DS_SUB_U32 : DS_1A1D_NORET <0x1, "ds_sub_u32", VGPR_32>;
-defm DS_RSUB_U32 : DS_1A1D_NORET <0x2, "ds_rsub_u32", VGPR_32>;
-defm DS_INC_U32 : DS_1A1D_NORET <0x3, "ds_inc_u32", VGPR_32>;
-defm DS_DEC_U32 : DS_1A1D_NORET <0x4, "ds_dec_u32", VGPR_32>;
-defm DS_MIN_I32 : DS_1A1D_NORET <0x5, "ds_min_i32", VGPR_32>;
-defm DS_MAX_I32 : DS_1A1D_NORET <0x6, "ds_max_i32", VGPR_32>;
-defm DS_MIN_U32 : DS_1A1D_NORET <0x7, "ds_min_u32", VGPR_32>;
-defm DS_MAX_U32 : DS_1A1D_NORET <0x8, "ds_max_u32", VGPR_32>;
-defm DS_AND_B32 : DS_1A1D_NORET <0x9, "ds_and_b32", VGPR_32>;
-defm DS_OR_B32 : DS_1A1D_NORET <0xa, "ds_or_b32", VGPR_32>;
-defm DS_XOR_B32 : DS_1A1D_NORET <0xb, "ds_xor_b32", VGPR_32>;
-defm DS_MSKOR_B32 : DS_1A2D_NORET <0xc, "ds_mskor_b32", VGPR_32>;
-let mayLoad = 0 in {
-defm DS_WRITE_B32 : DS_1A1D_NORET <0xd, "ds_write_b32", VGPR_32>;
-defm DS_WRITE2_B32 : DS_1A2D_Off8_NORET <0xe, "ds_write2_b32", VGPR_32>;
-defm DS_WRITE2ST64_B32 : DS_1A2D_Off8_NORET <0xf, "ds_write2st64_b32", VGPR_32>;
-}
-defm DS_CMPST_B32 : DS_1A2D_NORET <0x10, "ds_cmpst_b32", VGPR_32>;
-defm DS_CMPST_F32 : DS_1A2D_NORET <0x11, "ds_cmpst_f32", VGPR_32>;
-defm DS_MIN_F32 : DS_1A2D_NORET <0x12, "ds_min_f32", VGPR_32>;
-defm DS_MAX_F32 : DS_1A2D_NORET <0x13, "ds_max_f32", VGPR_32>;
-
-defm DS_GWS_INIT : DS_1A_GDS <0x19, "ds_gws_init">;
-defm DS_GWS_SEMA_V : DS_1A_GDS <0x1a, "ds_gws_sema_v">;
-defm DS_GWS_SEMA_BR : DS_1A_GDS <0x1b, "ds_gws_sema_br">;
-defm DS_GWS_SEMA_P : DS_1A_GDS <0x1c, "ds_gws_sema_p">;
-defm DS_GWS_BARRIER : DS_1A_GDS <0x1d, "ds_gws_barrier">;
-let mayLoad = 0 in {
-defm DS_WRITE_B8 : DS_1A1D_NORET <0x1e, "ds_write_b8", VGPR_32>;
-defm DS_WRITE_B16 : DS_1A1D_NORET <0x1f, "ds_write_b16", VGPR_32>;
-}
-defm DS_ADD_RTN_U32 : DS_1A1D_RET <0x20, "ds_add_rtn_u32", VGPR_32, "ds_add_u32">;
-defm DS_SUB_RTN_U32 : DS_1A1D_RET <0x21, "ds_sub_rtn_u32", VGPR_32, "ds_sub_u32">;
-defm DS_RSUB_RTN_U32 : DS_1A1D_RET <0x22, "ds_rsub_rtn_u32", VGPR_32, "ds_rsub_u32">;
-defm DS_INC_RTN_U32 : DS_1A1D_RET <0x23, "ds_inc_rtn_u32", VGPR_32, "ds_inc_u32">;
-defm DS_DEC_RTN_U32 : DS_1A1D_RET <0x24, "ds_dec_rtn_u32", VGPR_32, "ds_dec_u32">;
-defm DS_MIN_RTN_I32 : DS_1A1D_RET <0x25, "ds_min_rtn_i32", VGPR_32, "ds_min_i32">;
-defm DS_MAX_RTN_I32 : DS_1A1D_RET <0x26, "ds_max_rtn_i32", VGPR_32, "ds_max_i32">;
-defm DS_MIN_RTN_U32 : DS_1A1D_RET <0x27, "ds_min_rtn_u32", VGPR_32, "ds_min_u32">;
-defm DS_MAX_RTN_U32 : DS_1A1D_RET <0x28, "ds_max_rtn_u32", VGPR_32, "ds_max_u32">;
-defm DS_AND_RTN_B32 : DS_1A1D_RET <0x29, "ds_and_rtn_b32", VGPR_32, "ds_and_b32">;
-defm DS_OR_RTN_B32 : DS_1A1D_RET <0x2a, "ds_or_rtn_b32", VGPR_32, "ds_or_b32">;
-defm DS_XOR_RTN_B32 : DS_1A1D_RET <0x2b, "ds_xor_rtn_b32", VGPR_32, "ds_xor_b32">;
-defm DS_MSKOR_RTN_B32 : DS_1A2D_RET <0x2c, "ds_mskor_rtn_b32", VGPR_32, "ds_mskor_b32">;
-defm DS_WRXCHG_RTN_B32 : DS_1A1D_RET <0x2d, "ds_wrxchg_rtn_b32", VGPR_32>;
-defm DS_WRXCHG2_RTN_B32 : DS_1A2D_RET <
- 0x2e, "ds_wrxchg2_rtn_b32", VReg_64, "", VGPR_32
->;
-defm DS_WRXCHG2ST64_RTN_B32 : DS_1A2D_RET <
- 0x2f, "ds_wrxchg2st64_rtn_b32", VReg_64, "", VGPR_32
->;
-defm DS_CMPST_RTN_B32 : DS_1A2D_RET <0x30, "ds_cmpst_rtn_b32", VGPR_32, "ds_cmpst_b32">;
-defm DS_CMPST_RTN_F32 : DS_1A2D_RET <0x31, "ds_cmpst_rtn_f32", VGPR_32, "ds_cmpst_f32">;
-defm DS_MIN_RTN_F32 : DS_1A2D_RET <0x32, "ds_min_rtn_f32", VGPR_32, "ds_min_f32">;
-defm DS_MAX_RTN_F32 : DS_1A2D_RET <0x33, "ds_max_rtn_f32", VGPR_32, "ds_max_f32">;
-
-let Uses = [EXEC], mayLoad =0, mayStore = 0, isConvergent = 1 in {
-defm DS_SWIZZLE_B32 : DS_1A_RET_ <dsop<0x35, 0x3d>, "ds_swizzle_b32", VGPR_32>;
-}
-
-let mayStore = 0 in {
-defm DS_READ_B32 : DS_1A_RET <0x36, "ds_read_b32", VGPR_32>;
-defm DS_READ2_B32 : DS_1A_Off8_RET <0x37, "ds_read2_b32", VReg_64>;
-defm DS_READ2ST64_B32 : DS_1A_Off8_RET <0x38, "ds_read2st64_b32", VReg_64>;
-defm DS_READ_I8 : DS_1A_RET <0x39, "ds_read_i8", VGPR_32>;
-defm DS_READ_U8 : DS_1A_RET <0x3a, "ds_read_u8", VGPR_32>;
-defm DS_READ_I16 : DS_1A_RET <0x3b, "ds_read_i16", VGPR_32>;
-defm DS_READ_U16 : DS_1A_RET <0x3c, "ds_read_u16", VGPR_32>;
-}
-defm DS_CONSUME : DS_0A_RET <0x3d, "ds_consume">;
-defm DS_APPEND : DS_0A_RET <0x3e, "ds_append">;
-defm DS_ORDERED_COUNT : DS_1A_RET_GDS <0x3f, "ds_ordered_count">;
-defm DS_ADD_U64 : DS_1A1D_NORET <0x40, "ds_add_u64", VReg_64>;
-defm DS_SUB_U64 : DS_1A1D_NORET <0x41, "ds_sub_u64", VReg_64>;
-defm DS_RSUB_U64 : DS_1A1D_NORET <0x42, "ds_rsub_u64", VReg_64>;
-defm DS_INC_U64 : DS_1A1D_NORET <0x43, "ds_inc_u64", VReg_64>;
-defm DS_DEC_U64 : DS_1A1D_NORET <0x44, "ds_dec_u64", VReg_64>;
-defm DS_MIN_I64 : DS_1A1D_NORET <0x45, "ds_min_i64", VReg_64>;
-defm DS_MAX_I64 : DS_1A1D_NORET <0x46, "ds_max_i64", VReg_64>;
-defm DS_MIN_U64 : DS_1A1D_NORET <0x47, "ds_min_u64", VReg_64>;
-defm DS_MAX_U64 : DS_1A1D_NORET <0x48, "ds_max_u64", VReg_64>;
-defm DS_AND_B64 : DS_1A1D_NORET <0x49, "ds_and_b64", VReg_64>;
-defm DS_OR_B64 : DS_1A1D_NORET <0x4a, "ds_or_b64", VReg_64>;
-defm DS_XOR_B64 : DS_1A1D_NORET <0x4b, "ds_xor_b64", VReg_64>;
-defm DS_MSKOR_B64 : DS_1A2D_NORET <0x4c, "ds_mskor_b64", VReg_64>;
-let mayLoad = 0 in {
-defm DS_WRITE_B64 : DS_1A1D_NORET <0x4d, "ds_write_b64", VReg_64>;
-defm DS_WRITE2_B64 : DS_1A2D_Off8_NORET <0x4E, "ds_write2_b64", VReg_64>;
-defm DS_WRITE2ST64_B64 : DS_1A2D_Off8_NORET <0x4f, "ds_write2st64_b64", VReg_64>;
-}
-defm DS_CMPST_B64 : DS_1A2D_NORET <0x50, "ds_cmpst_b64", VReg_64>;
-defm DS_CMPST_F64 : DS_1A2D_NORET <0x51, "ds_cmpst_f64", VReg_64>;
-defm DS_MIN_F64 : DS_1A1D_NORET <0x52, "ds_min_f64", VReg_64>;
-defm DS_MAX_F64 : DS_1A1D_NORET <0x53, "ds_max_f64", VReg_64>;
-
-defm DS_ADD_RTN_U64 : DS_1A1D_RET <0x60, "ds_add_rtn_u64", VReg_64, "ds_add_u64">;
-defm DS_SUB_RTN_U64 : DS_1A1D_RET <0x61, "ds_sub_rtn_u64", VReg_64, "ds_sub_u64">;
-defm DS_RSUB_RTN_U64 : DS_1A1D_RET <0x62, "ds_rsub_rtn_u64", VReg_64, "ds_rsub_u64">;
-defm DS_INC_RTN_U64 : DS_1A1D_RET <0x63, "ds_inc_rtn_u64", VReg_64, "ds_inc_u64">;
-defm DS_DEC_RTN_U64 : DS_1A1D_RET <0x64, "ds_dec_rtn_u64", VReg_64, "ds_dec_u64">;
-defm DS_MIN_RTN_I64 : DS_1A1D_RET <0x65, "ds_min_rtn_i64", VReg_64, "ds_min_i64">;
-defm DS_MAX_RTN_I64 : DS_1A1D_RET <0x66, "ds_max_rtn_i64", VReg_64, "ds_max_i64">;
-defm DS_MIN_RTN_U64 : DS_1A1D_RET <0x67, "ds_min_rtn_u64", VReg_64, "ds_min_u64">;
-defm DS_MAX_RTN_U64 : DS_1A1D_RET <0x68, "ds_max_rtn_u64", VReg_64, "ds_max_u64">;
-defm DS_AND_RTN_B64 : DS_1A1D_RET <0x69, "ds_and_rtn_b64", VReg_64, "ds_and_b64">;
-defm DS_OR_RTN_B64 : DS_1A1D_RET <0x6a, "ds_or_rtn_b64", VReg_64, "ds_or_b64">;
-defm DS_XOR_RTN_B64 : DS_1A1D_RET <0x6b, "ds_xor_rtn_b64", VReg_64, "ds_xor_b64">;
-defm DS_MSKOR_RTN_B64 : DS_1A2D_RET <0x6c, "ds_mskor_rtn_b64", VReg_64, "ds_mskor_b64">;
-defm DS_WRXCHG_RTN_B64 : DS_1A1D_RET <0x6d, "ds_wrxchg_rtn_b64", VReg_64, "ds_wrxchg_b64">;
-defm DS_WRXCHG2_RTN_B64 : DS_1A2D_RET <0x6e, "ds_wrxchg2_rtn_b64", VReg_128, "ds_wrxchg2_b64", VReg_64>;
-defm DS_WRXCHG2ST64_RTN_B64 : DS_1A2D_RET <0x6f, "ds_wrxchg2st64_rtn_b64", VReg_128, "ds_wrxchg2st64_b64", VReg_64>;
-defm DS_CMPST_RTN_B64 : DS_1A2D_RET <0x70, "ds_cmpst_rtn_b64", VReg_64, "ds_cmpst_b64">;
-defm DS_CMPST_RTN_F64 : DS_1A2D_RET <0x71, "ds_cmpst_rtn_f64", VReg_64, "ds_cmpst_f64">;
-defm DS_MIN_RTN_F64 : DS_1A1D_RET <0x72, "ds_min_rtn_f64", VReg_64, "ds_min_f64">;
-defm DS_MAX_RTN_F64 : DS_1A1D_RET <0x73, "ds_max_rtn_f64", VReg_64, "ds_max_f64">;
-
-let mayStore = 0 in {
-defm DS_READ_B64 : DS_1A_RET <0x76, "ds_read_b64", VReg_64>;
-defm DS_READ2_B64 : DS_1A_Off8_RET <0x77, "ds_read2_b64", VReg_128>;
-defm DS_READ2ST64_B64 : DS_1A_Off8_RET <0x78, "ds_read2st64_b64", VReg_128>;
-}
-
-defm DS_ADD_SRC2_U32 : DS_1A <0x80, "ds_add_src2_u32">;
-defm DS_SUB_SRC2_U32 : DS_1A <0x81, "ds_sub_src2_u32">;
-defm DS_RSUB_SRC2_U32 : DS_1A <0x82, "ds_rsub_src2_u32">;
-defm DS_INC_SRC2_U32 : DS_1A <0x83, "ds_inc_src2_u32">;
-defm DS_DEC_SRC2_U32 : DS_1A <0x84, "ds_dec_src2_u32">;
-defm DS_MIN_SRC2_I32 : DS_1A <0x85, "ds_min_src2_i32">;
-defm DS_MAX_SRC2_I32 : DS_1A <0x86, "ds_max_src2_i32">;
-defm DS_MIN_SRC2_U32 : DS_1A <0x87, "ds_min_src2_u32">;
-defm DS_MAX_SRC2_U32 : DS_1A <0x88, "ds_max_src2_u32">;
-defm DS_AND_SRC2_B32 : DS_1A <0x89, "ds_and_src_b32">;
-defm DS_OR_SRC2_B32 : DS_1A <0x8a, "ds_or_src2_b32">;
-defm DS_XOR_SRC2_B32 : DS_1A <0x8b, "ds_xor_src2_b32">;
-defm DS_WRITE_SRC2_B32 : DS_1A_Off8_NORET <0x8d, "ds_write_src2_b32">;
-
-defm DS_MIN_SRC2_F32 : DS_1A <0x92, "ds_min_src2_f32">;
-defm DS_MAX_SRC2_F32 : DS_1A <0x93, "ds_max_src2_f32">;
-
-defm DS_ADD_SRC2_U64 : DS_1A <0xc0, "ds_add_src2_u64">;
-defm DS_SUB_SRC2_U64 : DS_1A <0xc1, "ds_sub_src2_u64">;
-defm DS_RSUB_SRC2_U64 : DS_1A <0xc2, "ds_rsub_src2_u64">;
-defm DS_INC_SRC2_U64 : DS_1A <0xc3, "ds_inc_src2_u64">;
-defm DS_DEC_SRC2_U64 : DS_1A <0xc4, "ds_dec_src2_u64">;
-defm DS_MIN_SRC2_I64 : DS_1A <0xc5, "ds_min_src2_i64">;
-defm DS_MAX_SRC2_I64 : DS_1A <0xc6, "ds_max_src2_i64">;
-defm DS_MIN_SRC2_U64 : DS_1A <0xc7, "ds_min_src2_u64">;
-defm DS_MAX_SRC2_U64 : DS_1A <0xc8, "ds_max_src2_u64">;
-defm DS_AND_SRC2_B64 : DS_1A <0xc9, "ds_and_src2_b64">;
-defm DS_OR_SRC2_B64 : DS_1A <0xca, "ds_or_src2_b64">;
-defm DS_XOR_SRC2_B64 : DS_1A <0xcb, "ds_xor_src2_b64">;
-defm DS_WRITE_SRC2_B64 : DS_1A_Off8_NORET <0xcd, "ds_write_src2_b64">;
-
-defm DS_MIN_SRC2_F64 : DS_1A <0xd2, "ds_min_src2_f64">;
-defm DS_MAX_SRC2_F64 : DS_1A <0xd3, "ds_max_src2_f64">;
-
-//===----------------------------------------------------------------------===//
-// MUBUF Instructions
-//===----------------------------------------------------------------------===//
-
-defm BUFFER_LOAD_FORMAT_X : MUBUF_Load_Helper <
- mubuf<0x00>, "buffer_load_format_x", VGPR_32
->;
-defm BUFFER_LOAD_FORMAT_XY : MUBUF_Load_Helper <
- mubuf<0x01>, "buffer_load_format_xy", VReg_64
->;
-defm BUFFER_LOAD_FORMAT_XYZ : MUBUF_Load_Helper <
- mubuf<0x02>, "buffer_load_format_xyz", VReg_96
->;
-defm BUFFER_LOAD_FORMAT_XYZW : MUBUF_Load_Helper <
- mubuf<0x03>, "buffer_load_format_xyzw", VReg_128
->;
-defm BUFFER_STORE_FORMAT_X : MUBUF_Store_Helper <
- mubuf<0x04>, "buffer_store_format_x", VGPR_32
->;
-defm BUFFER_STORE_FORMAT_XY : MUBUF_Store_Helper <
- mubuf<0x05>, "buffer_store_format_xy", VReg_64
->;
-defm BUFFER_STORE_FORMAT_XYZ : MUBUF_Store_Helper <
- mubuf<0x06>, "buffer_store_format_xyz", VReg_96
->;
-defm BUFFER_STORE_FORMAT_XYZW : MUBUF_Store_Helper <
- mubuf<0x07>, "buffer_store_format_xyzw", VReg_128
->;
-defm BUFFER_LOAD_UBYTE : MUBUF_Load_Helper <
- mubuf<0x08, 0x10>, "buffer_load_ubyte", VGPR_32, i32, mubuf_az_extloadi8
->;
-defm BUFFER_LOAD_SBYTE : MUBUF_Load_Helper <
- mubuf<0x09, 0x11>, "buffer_load_sbyte", VGPR_32, i32, mubuf_sextloadi8
->;
-defm BUFFER_LOAD_USHORT : MUBUF_Load_Helper <
- mubuf<0x0a, 0x12>, "buffer_load_ushort", VGPR_32, i32, mubuf_az_extloadi16
->;
-defm BUFFER_LOAD_SSHORT : MUBUF_Load_Helper <
- mubuf<0x0b, 0x13>, "buffer_load_sshort", VGPR_32, i32, mubuf_sextloadi16
->;
-defm BUFFER_LOAD_DWORD : MUBUF_Load_Helper <
- mubuf<0x0c, 0x14>, "buffer_load_dword", VGPR_32, i32, mubuf_load
->;
-defm BUFFER_LOAD_DWORDX2 : MUBUF_Load_Helper <
- mubuf<0x0d, 0x15>, "buffer_load_dwordx2", VReg_64, v2i32, mubuf_load
->;
-defm BUFFER_LOAD_DWORDX4 : MUBUF_Load_Helper <
- mubuf<0x0e, 0x17>, "buffer_load_dwordx4", VReg_128, v4i32, mubuf_load
->;
-
-defm BUFFER_STORE_BYTE : MUBUF_Store_Helper <
- mubuf<0x18>, "buffer_store_byte", VGPR_32, i32, truncstorei8_global
->;
-
-defm BUFFER_STORE_SHORT : MUBUF_Store_Helper <
- mubuf<0x1a>, "buffer_store_short", VGPR_32, i32, truncstorei16_global
->;
-
-defm BUFFER_STORE_DWORD : MUBUF_Store_Helper <
- mubuf<0x1c>, "buffer_store_dword", VGPR_32, i32, global_store
->;
-
-defm BUFFER_STORE_DWORDX2 : MUBUF_Store_Helper <
- mubuf<0x1d>, "buffer_store_dwordx2", VReg_64, v2i32, global_store
->;
-
-defm BUFFER_STORE_DWORDX4 : MUBUF_Store_Helper <
- mubuf<0x1e, 0x1f>, "buffer_store_dwordx4", VReg_128, v4i32, global_store
->;
-
-defm BUFFER_ATOMIC_SWAP : MUBUF_Atomic <
- mubuf<0x30, 0x40>, "buffer_atomic_swap", VGPR_32, i32, atomic_swap_global
->;
-defm BUFFER_ATOMIC_CMPSWAP : MUBUF_Atomic <
- mubuf<0x31, 0x41>, "buffer_atomic_cmpswap", VReg_64, v2i32, null_frag
->;
-defm BUFFER_ATOMIC_ADD : MUBUF_Atomic <
- mubuf<0x32, 0x42>, "buffer_atomic_add", VGPR_32, i32, atomic_add_global
->;
-defm BUFFER_ATOMIC_SUB : MUBUF_Atomic <
- mubuf<0x33, 0x43>, "buffer_atomic_sub", VGPR_32, i32, atomic_sub_global
->;
-//def BUFFER_ATOMIC_RSUB : MUBUF_ <mubuf<0x34>, "buffer_atomic_rsub", []>; // isn't on CI & VI
-defm BUFFER_ATOMIC_SMIN : MUBUF_Atomic <
- mubuf<0x35, 0x44>, "buffer_atomic_smin", VGPR_32, i32, atomic_min_global
->;
-defm BUFFER_ATOMIC_UMIN : MUBUF_Atomic <
- mubuf<0x36, 0x45>, "buffer_atomic_umin", VGPR_32, i32, atomic_umin_global
->;
-defm BUFFER_ATOMIC_SMAX : MUBUF_Atomic <
- mubuf<0x37, 0x46>, "buffer_atomic_smax", VGPR_32, i32, atomic_max_global
->;
-defm BUFFER_ATOMIC_UMAX : MUBUF_Atomic <
- mubuf<0x38, 0x47>, "buffer_atomic_umax", VGPR_32, i32, atomic_umax_global
->;
-defm BUFFER_ATOMIC_AND : MUBUF_Atomic <
- mubuf<0x39, 0x48>, "buffer_atomic_and", VGPR_32, i32, atomic_and_global
->;
-defm BUFFER_ATOMIC_OR : MUBUF_Atomic <
- mubuf<0x3a, 0x49>, "buffer_atomic_or", VGPR_32, i32, atomic_or_global
->;
-defm BUFFER_ATOMIC_XOR : MUBUF_Atomic <
- mubuf<0x3b, 0x4a>, "buffer_atomic_xor", VGPR_32, i32, atomic_xor_global
->;
-defm BUFFER_ATOMIC_INC : MUBUF_Atomic <
- mubuf<0x3c, 0x4b>, "buffer_atomic_inc", VGPR_32, i32, atomic_inc_global
->;
-defm BUFFER_ATOMIC_DEC : MUBUF_Atomic <
- mubuf<0x3d, 0x4c>, "buffer_atomic_dec", VGPR_32, i32, atomic_dec_global
->;
-
-//def BUFFER_ATOMIC_FCMPSWAP : MUBUF_Atomic <mubuf<0x3e>, "buffer_atomic_fcmpswap", []>; // isn't on VI
-//def BUFFER_ATOMIC_FMIN : MUBUF_Atomic <mubuf<0x3f>, "buffer_atomic_fmin", []>; // isn't on VI
-//def BUFFER_ATOMIC_FMAX : MUBUF_Atomic <mubuf<0x40>, "buffer_atomic_fmax", []>; // isn't on VI
-defm BUFFER_ATOMIC_SWAP_X2 : MUBUF_Atomic <
- mubuf<0x50, 0x60>, "buffer_atomic_swap_x2", VReg_64, i64, atomic_swap_global
->;
-defm BUFFER_ATOMIC_CMPSWAP_X2 : MUBUF_Atomic <
- mubuf<0x51, 0x61>, "buffer_atomic_cmpswap_x2", VReg_128, v2i64, null_frag
->;
-defm BUFFER_ATOMIC_ADD_X2 : MUBUF_Atomic <
- mubuf<0x52, 0x62>, "buffer_atomic_add_x2", VReg_64, i64, atomic_add_global
->;
-defm BUFFER_ATOMIC_SUB_X2 : MUBUF_Atomic <
- mubuf<0x53, 0x63>, "buffer_atomic_sub_x2", VReg_64, i64, atomic_sub_global
->;
-//defm BUFFER_ATOMIC_RSUB_X2 : MUBUF_Atomic <mubuf<0x54>, "buffer_atomic_rsub_x2", []>; // isn't on CI & VI
-defm BUFFER_ATOMIC_SMIN_X2 : MUBUF_Atomic <
- mubuf<0x55, 0x64>, "buffer_atomic_smin_x2", VReg_64, i64, atomic_min_global
->;
-defm BUFFER_ATOMIC_UMIN_X2 : MUBUF_Atomic <
- mubuf<0x56, 0x65>, "buffer_atomic_umin_x2", VReg_64, i64, atomic_umin_global
->;
-defm BUFFER_ATOMIC_SMAX_X2 : MUBUF_Atomic <
- mubuf<0x57, 0x66>, "buffer_atomic_smax_x2", VReg_64, i64, atomic_max_global
->;
-defm BUFFER_ATOMIC_UMAX_X2 : MUBUF_Atomic <
- mubuf<0x58, 0x67>, "buffer_atomic_umax_x2", VReg_64, i64, atomic_umax_global
->;
-defm BUFFER_ATOMIC_AND_X2 : MUBUF_Atomic <
- mubuf<0x59, 0x68>, "buffer_atomic_and_x2", VReg_64, i64, atomic_and_global
->;
-defm BUFFER_ATOMIC_OR_X2 : MUBUF_Atomic <
- mubuf<0x5a, 0x69>, "buffer_atomic_or_x2", VReg_64, i64, atomic_or_global
->;
-defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Atomic <
- mubuf<0x5b, 0x6a>, "buffer_atomic_xor_x2", VReg_64, i64, atomic_xor_global
->;
-defm BUFFER_ATOMIC_INC_X2 : MUBUF_Atomic <
- mubuf<0x5c, 0x6b>, "buffer_atomic_inc_x2", VReg_64, i64, atomic_inc_global
->;
-defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Atomic <
- mubuf<0x5d, 0x6c>, "buffer_atomic_dec_x2", VReg_64, i64, atomic_dec_global
->;
-//def BUFFER_ATOMIC_FCMPSWAP_X2 : MUBUF_X2 <mubuf<0x5e>, "buffer_atomic_fcmpswap_x2", []>; // isn't on VI
-//def BUFFER_ATOMIC_FMIN_X2 : MUBUF_X2 <mubuf<0x5f>, "buffer_atomic_fmin_x2", []>; // isn't on VI
-//def BUFFER_ATOMIC_FMAX_X2 : MUBUF_X2 <mubuf<0x60>, "buffer_atomic_fmax_x2", []>; // isn't on VI
-
-let SubtargetPredicate = isSI, DisableVIDecoder = 1 in {
-defm BUFFER_WBINVL1_SC : MUBUF_Invalidate <mubuf<0x70>, "buffer_wbinvl1_sc", int_amdgcn_buffer_wbinvl1_sc>; // isn't on CI & VI
-}
-
-defm BUFFER_WBINVL1 : MUBUF_Invalidate <mubuf<0x71, 0x3e>, "buffer_wbinvl1", int_amdgcn_buffer_wbinvl1>;
-
-//===----------------------------------------------------------------------===//
-// MTBUF Instructions
-//===----------------------------------------------------------------------===//
-
-//def TBUFFER_LOAD_FORMAT_X : MTBUF_ <0x00000000, "tbuffer_load_format_x", []>;
-//def TBUFFER_LOAD_FORMAT_XY : MTBUF_ <0x00000001, "tbuffer_load_format_xy", []>;
-//def TBUFFER_LOAD_FORMAT_XYZ : MTBUF_ <0x00000002, "tbuffer_load_format_xyz", []>;
-defm TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Load_Helper <0x00000003, "tbuffer_load_format_xyzw", VReg_128>;
-defm TBUFFER_STORE_FORMAT_X : MTBUF_Store_Helper <0x00000004, "tbuffer_store_format_x", VGPR_32>;
-defm TBUFFER_STORE_FORMAT_XY : MTBUF_Store_Helper <0x00000005, "tbuffer_store_format_xy", VReg_64>;
-defm TBUFFER_STORE_FORMAT_XYZ : MTBUF_Store_Helper <0x00000006, "tbuffer_store_format_xyz", VReg_128>;
-defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Store_Helper <0x00000007, "tbuffer_store_format_xyzw", VReg_128>;
-
-//===----------------------------------------------------------------------===//
-// MIMG Instructions
-//===----------------------------------------------------------------------===//
-
-defm IMAGE_LOAD : MIMG_NoSampler <0x00000000, "image_load">;
-defm IMAGE_LOAD_MIP : MIMG_NoSampler <0x00000001, "image_load_mip">;
-//def IMAGE_LOAD_PCK : MIMG_NoPattern_ <"image_load_pck", 0x00000002>;
-//def IMAGE_LOAD_PCK_SGN : MIMG_NoPattern_ <"image_load_pck_sgn", 0x00000003>;
-//def IMAGE_LOAD_MIP_PCK : MIMG_NoPattern_ <"image_load_mip_pck", 0x00000004>;
-//def IMAGE_LOAD_MIP_PCK_SGN : MIMG_NoPattern_ <"image_load_mip_pck_sgn", 0x00000005>;
-defm IMAGE_STORE : MIMG_Store <0x00000008, "image_store">;
-defm IMAGE_STORE_MIP : MIMG_Store <0x00000009, "image_store_mip">;
-//def IMAGE_STORE_PCK : MIMG_NoPattern_ <"image_store_pck", 0x0000000a>;
-//def IMAGE_STORE_MIP_PCK : MIMG_NoPattern_ <"image_store_mip_pck", 0x0000000b>;
-defm IMAGE_GET_RESINFO : MIMG_NoSampler <0x0000000e, "image_get_resinfo">;
-defm IMAGE_ATOMIC_SWAP : MIMG_Atomic <mimg<0x0f, 0x10>, "image_atomic_swap">;
-defm IMAGE_ATOMIC_CMPSWAP : MIMG_Atomic <mimg<0x10, 0x11>, "image_atomic_cmpswap", VReg_64>;
-defm IMAGE_ATOMIC_ADD : MIMG_Atomic <mimg<0x11, 0x12>, "image_atomic_add">;
-defm IMAGE_ATOMIC_SUB : MIMG_Atomic <mimg<0x12, 0x13>, "image_atomic_sub">;
-//def IMAGE_ATOMIC_RSUB : MIMG_NoPattern_ <"image_atomic_rsub", 0x00000013>; -- not on VI
-defm IMAGE_ATOMIC_SMIN : MIMG_Atomic <mimg<0x14>, "image_atomic_smin">;
-defm IMAGE_ATOMIC_UMIN : MIMG_Atomic <mimg<0x15>, "image_atomic_umin">;
-defm IMAGE_ATOMIC_SMAX : MIMG_Atomic <mimg<0x16>, "image_atomic_smax">;
-defm IMAGE_ATOMIC_UMAX : MIMG_Atomic <mimg<0x17>, "image_atomic_umax">;
-defm IMAGE_ATOMIC_AND : MIMG_Atomic <mimg<0x18>, "image_atomic_and">;
-defm IMAGE_ATOMIC_OR : MIMG_Atomic <mimg<0x19>, "image_atomic_or">;
-defm IMAGE_ATOMIC_XOR : MIMG_Atomic <mimg<0x1a>, "image_atomic_xor">;
-defm IMAGE_ATOMIC_INC : MIMG_Atomic <mimg<0x1b>, "image_atomic_inc">;
-defm IMAGE_ATOMIC_DEC : MIMG_Atomic <mimg<0x1c>, "image_atomic_dec">;
-//def IMAGE_ATOMIC_FCMPSWAP : MIMG_NoPattern_ <"image_atomic_fcmpswap", 0x0000001d>; -- not on VI
-//def IMAGE_ATOMIC_FMIN : MIMG_NoPattern_ <"image_atomic_fmin", 0x0000001e>; -- not on VI
-//def IMAGE_ATOMIC_FMAX : MIMG_NoPattern_ <"image_atomic_fmax", 0x0000001f>; -- not on VI
-defm IMAGE_SAMPLE : MIMG_Sampler_WQM <0x00000020, "image_sample">;
-defm IMAGE_SAMPLE_CL : MIMG_Sampler_WQM <0x00000021, "image_sample_cl">;
-defm IMAGE_SAMPLE_D : MIMG_Sampler <0x00000022, "image_sample_d">;
-defm IMAGE_SAMPLE_D_CL : MIMG_Sampler <0x00000023, "image_sample_d_cl">;
-defm IMAGE_SAMPLE_L : MIMG_Sampler <0x00000024, "image_sample_l">;
-defm IMAGE_SAMPLE_B : MIMG_Sampler_WQM <0x00000025, "image_sample_b">;
-defm IMAGE_SAMPLE_B_CL : MIMG_Sampler_WQM <0x00000026, "image_sample_b_cl">;
-defm IMAGE_SAMPLE_LZ : MIMG_Sampler <0x00000027, "image_sample_lz">;
-defm IMAGE_SAMPLE_C : MIMG_Sampler_WQM <0x00000028, "image_sample_c">;
-defm IMAGE_SAMPLE_C_CL : MIMG_Sampler_WQM <0x00000029, "image_sample_c_cl">;
-defm IMAGE_SAMPLE_C_D : MIMG_Sampler <0x0000002a, "image_sample_c_d">;
-defm IMAGE_SAMPLE_C_D_CL : MIMG_Sampler <0x0000002b, "image_sample_c_d_cl">;
-defm IMAGE_SAMPLE_C_L : MIMG_Sampler <0x0000002c, "image_sample_c_l">;
-defm IMAGE_SAMPLE_C_B : MIMG_Sampler_WQM <0x0000002d, "image_sample_c_b">;
-defm IMAGE_SAMPLE_C_B_CL : MIMG_Sampler_WQM <0x0000002e, "image_sample_c_b_cl">;
-defm IMAGE_SAMPLE_C_LZ : MIMG_Sampler <0x0000002f, "image_sample_c_lz">;
-defm IMAGE_SAMPLE_O : MIMG_Sampler_WQM <0x00000030, "image_sample_o">;
-defm IMAGE_SAMPLE_CL_O : MIMG_Sampler_WQM <0x00000031, "image_sample_cl_o">;
-defm IMAGE_SAMPLE_D_O : MIMG_Sampler <0x00000032, "image_sample_d_o">;
-defm IMAGE_SAMPLE_D_CL_O : MIMG_Sampler <0x00000033, "image_sample_d_cl_o">;
-defm IMAGE_SAMPLE_L_O : MIMG_Sampler <0x00000034, "image_sample_l_o">;
-defm IMAGE_SAMPLE_B_O : MIMG_Sampler_WQM <0x00000035, "image_sample_b_o">;
-defm IMAGE_SAMPLE_B_CL_O : MIMG_Sampler_WQM <0x00000036, "image_sample_b_cl_o">;
-defm IMAGE_SAMPLE_LZ_O : MIMG_Sampler <0x00000037, "image_sample_lz_o">;
-defm IMAGE_SAMPLE_C_O : MIMG_Sampler_WQM <0x00000038, "image_sample_c_o">;
-defm IMAGE_SAMPLE_C_CL_O : MIMG_Sampler_WQM <0x00000039, "image_sample_c_cl_o">;
-defm IMAGE_SAMPLE_C_D_O : MIMG_Sampler <0x0000003a, "image_sample_c_d_o">;
-defm IMAGE_SAMPLE_C_D_CL_O : MIMG_Sampler <0x0000003b, "image_sample_c_d_cl_o">;
-defm IMAGE_SAMPLE_C_L_O : MIMG_Sampler <0x0000003c, "image_sample_c_l_o">;
-defm IMAGE_SAMPLE_C_B_O : MIMG_Sampler_WQM <0x0000003d, "image_sample_c_b_o">;
-defm IMAGE_SAMPLE_C_B_CL_O : MIMG_Sampler_WQM <0x0000003e, "image_sample_c_b_cl_o">;
-defm IMAGE_SAMPLE_C_LZ_O : MIMG_Sampler <0x0000003f, "image_sample_c_lz_o">;
-defm IMAGE_GATHER4 : MIMG_Gather_WQM <0x00000040, "image_gather4">;
-defm IMAGE_GATHER4_CL : MIMG_Gather_WQM <0x00000041, "image_gather4_cl">;
-defm IMAGE_GATHER4_L : MIMG_Gather <0x00000044, "image_gather4_l">;
-defm IMAGE_GATHER4_B : MIMG_Gather_WQM <0x00000045, "image_gather4_b">;
-defm IMAGE_GATHER4_B_CL : MIMG_Gather_WQM <0x00000046, "image_gather4_b_cl">;
-defm IMAGE_GATHER4_LZ : MIMG_Gather <0x00000047, "image_gather4_lz">;
-defm IMAGE_GATHER4_C : MIMG_Gather_WQM <0x00000048, "image_gather4_c">;
-defm IMAGE_GATHER4_C_CL : MIMG_Gather_WQM <0x00000049, "image_gather4_c_cl">;
-defm IMAGE_GATHER4_C_L : MIMG_Gather <0x0000004c, "image_gather4_c_l">;
-defm IMAGE_GATHER4_C_B : MIMG_Gather_WQM <0x0000004d, "image_gather4_c_b">;
-defm IMAGE_GATHER4_C_B_CL : MIMG_Gather_WQM <0x0000004e, "image_gather4_c_b_cl">;
-defm IMAGE_GATHER4_C_LZ : MIMG_Gather <0x0000004f, "image_gather4_c_lz">;
-defm IMAGE_GATHER4_O : MIMG_Gather_WQM <0x00000050, "image_gather4_o">;
-defm IMAGE_GATHER4_CL_O : MIMG_Gather_WQM <0x00000051, "image_gather4_cl_o">;
-defm IMAGE_GATHER4_L_O : MIMG_Gather <0x00000054, "image_gather4_l_o">;
-defm IMAGE_GATHER4_B_O : MIMG_Gather_WQM <0x00000055, "image_gather4_b_o">;
-defm IMAGE_GATHER4_B_CL_O : MIMG_Gather <0x00000056, "image_gather4_b_cl_o">;
-defm IMAGE_GATHER4_LZ_O : MIMG_Gather <0x00000057, "image_gather4_lz_o">;
-defm IMAGE_GATHER4_C_O : MIMG_Gather_WQM <0x00000058, "image_gather4_c_o">;
-defm IMAGE_GATHER4_C_CL_O : MIMG_Gather_WQM <0x00000059, "image_gather4_c_cl_o">;
-defm IMAGE_GATHER4_C_L_O : MIMG_Gather <0x0000005c, "image_gather4_c_l_o">;
-defm IMAGE_GATHER4_C_B_O : MIMG_Gather_WQM <0x0000005d, "image_gather4_c_b_o">;
-defm IMAGE_GATHER4_C_B_CL_O : MIMG_Gather_WQM <0x0000005e, "image_gather4_c_b_cl_o">;
-defm IMAGE_GATHER4_C_LZ_O : MIMG_Gather <0x0000005f, "image_gather4_c_lz_o">;
-defm IMAGE_GET_LOD : MIMG_Sampler_WQM <0x00000060, "image_get_lod">;
-defm IMAGE_SAMPLE_CD : MIMG_Sampler <0x00000068, "image_sample_cd">;
-defm IMAGE_SAMPLE_CD_CL : MIMG_Sampler <0x00000069, "image_sample_cd_cl">;
-defm IMAGE_SAMPLE_C_CD : MIMG_Sampler <0x0000006a, "image_sample_c_cd">;
-defm IMAGE_SAMPLE_C_CD_CL : MIMG_Sampler <0x0000006b, "image_sample_c_cd_cl">;
-defm IMAGE_SAMPLE_CD_O : MIMG_Sampler <0x0000006c, "image_sample_cd_o">;
-defm IMAGE_SAMPLE_CD_CL_O : MIMG_Sampler <0x0000006d, "image_sample_cd_cl_o">;
-defm IMAGE_SAMPLE_C_CD_O : MIMG_Sampler <0x0000006e, "image_sample_c_cd_o">;
-defm IMAGE_SAMPLE_C_CD_CL_O : MIMG_Sampler <0x0000006f, "image_sample_c_cd_cl_o">;
-//def IMAGE_RSRC256 : MIMG_NoPattern_RSRC256 <"image_rsrc256", 0x0000007e>;
-//def IMAGE_SAMPLER : MIMG_NoPattern_ <"image_sampler", 0x0000007f>;
-
-//===----------------------------------------------------------------------===//
-// VOP1 Instructions
-//===----------------------------------------------------------------------===//
-
-let vdst = 0, src0 = 0, VOPAsmPrefer32Bit = 1 in {
-defm V_NOP : VOP1Inst <vop1<0x0>, "v_nop", VOP_NONE>;
-}
-
-let isMoveImm = 1, isReMaterializable = 1, isAsCheapAsAMove = 1 in {
-defm V_MOV_B32 : VOP1Inst <vop1<0x1>, "v_mov_b32", VOP_I32_I32>;
-} // End isMoveImm = 1
-
-let Uses = [EXEC] in {
-
-// FIXME: Specify SchedRW for READFIRSTLANE_B32
-
-def V_READFIRSTLANE_B32 : VOP1 <
- 0x00000002,
- (outs SReg_32:$vdst),
- (ins VS_32:$src0),
- "v_readfirstlane_b32 $vdst, $src0",
- []
-> {
- let isConvergent = 1;
-}
-
-}
-
-let SchedRW = [WriteQuarterRate32] in {
-
-defm V_CVT_I32_F64 : VOP1Inst <vop1<0x3>, "v_cvt_i32_f64",
- VOP_I32_F64, fp_to_sint
->;
-defm V_CVT_F64_I32 : VOP1Inst <vop1<0x4>, "v_cvt_f64_i32",
- VOP_F64_I32, sint_to_fp
->;
-defm V_CVT_F32_I32 : VOP1Inst <vop1<0x5>, "v_cvt_f32_i32",
- VOP_F32_I32, sint_to_fp
->;
-defm V_CVT_F32_U32 : VOP1Inst <vop1<0x6>, "v_cvt_f32_u32",
- VOP_F32_I32, uint_to_fp
->;
-defm V_CVT_U32_F32 : VOP1Inst <vop1<0x7>, "v_cvt_u32_f32",
- VOP_I32_F32, fp_to_uint
->;
-defm V_CVT_I32_F32 : VOP1Inst <vop1<0x8>, "v_cvt_i32_f32",
- VOP_I32_F32, fp_to_sint
->;
-defm V_CVT_F16_F32 : VOP1Inst <vop1<0xa>, "v_cvt_f16_f32",
- VOP_I32_F32, fp_to_f16
->;
-defm V_CVT_F32_F16 : VOP1Inst <vop1<0xb>, "v_cvt_f32_f16",
- VOP_F32_I32, f16_to_fp
->;
-defm V_CVT_RPI_I32_F32 : VOP1Inst <vop1<0xc>, "v_cvt_rpi_i32_f32",
- VOP_I32_F32, cvt_rpi_i32_f32>;
-defm V_CVT_FLR_I32_F32 : VOP1Inst <vop1<0xd>, "v_cvt_flr_i32_f32",
- VOP_I32_F32, cvt_flr_i32_f32>;
-defm V_CVT_OFF_F32_I4 : VOP1Inst <vop1<0x0e>, "v_cvt_off_f32_i4", VOP_F32_I32>;
-defm V_CVT_F32_F64 : VOP1Inst <vop1<0xf>, "v_cvt_f32_f64",
- VOP_F32_F64, fround
->;
-defm V_CVT_F64_F32 : VOP1Inst <vop1<0x10>, "v_cvt_f64_f32",
- VOP_F64_F32, fextend
->;
-defm V_CVT_F32_UBYTE0 : VOP1Inst <vop1<0x11>, "v_cvt_f32_ubyte0",
- VOP_F32_I32, AMDGPUcvt_f32_ubyte0
->;
-defm V_CVT_F32_UBYTE1 : VOP1Inst <vop1<0x12>, "v_cvt_f32_ubyte1",
- VOP_F32_I32, AMDGPUcvt_f32_ubyte1
->;
-defm V_CVT_F32_UBYTE2 : VOP1Inst <vop1<0x13>, "v_cvt_f32_ubyte2",
- VOP_F32_I32, AMDGPUcvt_f32_ubyte2
->;
-defm V_CVT_F32_UBYTE3 : VOP1Inst <vop1<0x14>, "v_cvt_f32_ubyte3",
- VOP_F32_I32, AMDGPUcvt_f32_ubyte3
->;
-defm V_CVT_U32_F64 : VOP1Inst <vop1<0x15>, "v_cvt_u32_f64",
- VOP_I32_F64, fp_to_uint
->;
-defm V_CVT_F64_U32 : VOP1Inst <vop1<0x16>, "v_cvt_f64_u32",
- VOP_F64_I32, uint_to_fp
->;
-
-} // End SchedRW = [WriteQuarterRate32]
-
-defm V_FRACT_F32 : VOP1Inst <vop1<0x20, 0x1b>, "v_fract_f32",
- VOP_F32_F32, AMDGPUfract
->;
-defm V_TRUNC_F32 : VOP1Inst <vop1<0x21, 0x1c>, "v_trunc_f32",
- VOP_F32_F32, ftrunc
->;
-defm V_CEIL_F32 : VOP1Inst <vop1<0x22, 0x1d>, "v_ceil_f32",
- VOP_F32_F32, fceil
->;
-defm V_RNDNE_F32 : VOP1Inst <vop1<0x23, 0x1e>, "v_rndne_f32",
- VOP_F32_F32, frint
->;
-defm V_FLOOR_F32 : VOP1Inst <vop1<0x24, 0x1f>, "v_floor_f32",
- VOP_F32_F32, ffloor
->;
-defm V_EXP_F32 : VOP1Inst <vop1<0x25, 0x20>, "v_exp_f32",
- VOP_F32_F32, fexp2
->;
-
-let SchedRW = [WriteQuarterRate32] in {
-
-defm V_LOG_F32 : VOP1Inst <vop1<0x27, 0x21>, "v_log_f32",
- VOP_F32_F32, flog2
->;
-defm V_RCP_F32 : VOP1Inst <vop1<0x2a, 0x22>, "v_rcp_f32",
- VOP_F32_F32, AMDGPUrcp
->;
-defm V_RCP_IFLAG_F32 : VOP1Inst <vop1<0x2b, 0x23>, "v_rcp_iflag_f32",
- VOP_F32_F32
->;
-defm V_RSQ_F32 : VOP1Inst <vop1<0x2e, 0x24>, "v_rsq_f32",
- VOP_F32_F32, AMDGPUrsq
->;
-
-} // End SchedRW = [WriteQuarterRate32]
-
-let SchedRW = [WriteDouble] in {
-
-defm V_RCP_F64 : VOP1Inst <vop1<0x2f, 0x25>, "v_rcp_f64",
- VOP_F64_F64, AMDGPUrcp
->;
-defm V_RSQ_F64 : VOP1Inst <vop1<0x31, 0x26>, "v_rsq_f64",
- VOP_F64_F64, AMDGPUrsq
->;
-
-} // End SchedRW = [WriteDouble];
-
-defm V_SQRT_F32 : VOP1Inst <vop1<0x33, 0x27>, "v_sqrt_f32",
- VOP_F32_F32, fsqrt
->;
-
-let SchedRW = [WriteDouble] in {
-
-defm V_SQRT_F64 : VOP1Inst <vop1<0x34, 0x28>, "v_sqrt_f64",
- VOP_F64_F64, fsqrt
->;
-
-} // End SchedRW = [WriteDouble]
-
-let SchedRW = [WriteQuarterRate32] in {
-
-defm V_SIN_F32 : VOP1Inst <vop1<0x35, 0x29>, "v_sin_f32",
- VOP_F32_F32, AMDGPUsin
->;
-defm V_COS_F32 : VOP1Inst <vop1<0x36, 0x2a>, "v_cos_f32",
- VOP_F32_F32, AMDGPUcos
->;
-
-} // End SchedRW = [WriteQuarterRate32]
-
-defm V_NOT_B32 : VOP1Inst <vop1<0x37, 0x2b>, "v_not_b32", VOP_I32_I32>;
-defm V_BFREV_B32 : VOP1Inst <vop1<0x38, 0x2c>, "v_bfrev_b32", VOP_I32_I32>;
-defm V_FFBH_U32 : VOP1Inst <vop1<0x39, 0x2d>, "v_ffbh_u32", VOP_I32_I32>;
-defm V_FFBL_B32 : VOP1Inst <vop1<0x3a, 0x2e>, "v_ffbl_b32", VOP_I32_I32>;
-defm V_FFBH_I32 : VOP1Inst <vop1<0x3b, 0x2f>, "v_ffbh_i32", VOP_I32_I32>;
-defm V_FREXP_EXP_I32_F64 : VOP1Inst <vop1<0x3c,0x30>, "v_frexp_exp_i32_f64",
- VOP_I32_F64, int_amdgcn_frexp_exp
->;
-
-let SchedRW = [WriteDoubleAdd] in {
-defm V_FREXP_MANT_F64 : VOP1Inst <vop1<0x3d, 0x31>, "v_frexp_mant_f64",
- VOP_F64_F64, int_amdgcn_frexp_mant
->;
-
-defm V_FRACT_F64 : VOP1Inst <vop1<0x3e, 0x32>, "v_fract_f64",
- VOP_F64_F64, AMDGPUfract
->;
-} // End SchedRW = [WriteDoubleAdd]
-
-
-defm V_FREXP_EXP_I32_F32 : VOP1Inst <vop1<0x3f, 0x33>, "v_frexp_exp_i32_f32",
- VOP_I32_F32, int_amdgcn_frexp_exp
->;
-defm V_FREXP_MANT_F32 : VOP1Inst <vop1<0x40, 0x34>, "v_frexp_mant_f32",
- VOP_F32_F32, int_amdgcn_frexp_mant
->;
-let vdst = 0, src0 = 0, VOPAsmPrefer32Bit = 1 in {
-defm V_CLREXCP : VOP1Inst <vop1<0x41,0x35>, "v_clrexcp", VOP_NO_EXT<VOP_NONE>>;
-}
-
-let Uses = [M0, EXEC] in {
-defm V_MOVRELD_B32 : VOP1Inst <vop1<0x42, 0x36>, "v_movreld_b32", VOP_NO_EXT<VOP_I32_I32>>;
-defm V_MOVRELS_B32 : VOP1Inst <vop1<0x43, 0x37>, "v_movrels_b32", VOP_NO_EXT<VOP_I32_I32>>;
-defm V_MOVRELSD_B32 : VOP1Inst <vop1<0x44, 0x38>, "v_movrelsd_b32", VOP_NO_EXT<VOP_I32_I32>>;
-} // End Uses = [M0, EXEC]
-
-// These instruction only exist on SI and CI
-let SubtargetPredicate = isSICI in {
-
-let SchedRW = [WriteQuarterRate32] in {
-
-defm V_MOV_FED_B32 : VOP1InstSI <vop1<0x9>, "v_mov_fed_b32", VOP_I32_I32>;
-defm V_LOG_CLAMP_F32 : VOP1InstSI <vop1<0x26>, "v_log_clamp_f32",
- VOP_F32_F32, int_amdgcn_log_clamp>;
-defm V_RCP_CLAMP_F32 : VOP1InstSI <vop1<0x28>, "v_rcp_clamp_f32", VOP_F32_F32>;
-defm V_RCP_LEGACY_F32 : VOP1InstSI <vop1<0x29>, "v_rcp_legacy_f32", VOP_F32_F32>;
-defm V_RSQ_CLAMP_F32 : VOP1InstSI <vop1<0x2c>, "v_rsq_clamp_f32",
- VOP_F32_F32, AMDGPUrsq_clamp
->;
-defm V_RSQ_LEGACY_F32 : VOP1InstSI <vop1<0x2d>, "v_rsq_legacy_f32",
- VOP_F32_F32, AMDGPUrsq_legacy
->;
-
-} // End SchedRW = [WriteQuarterRate32]
-
-let SchedRW = [WriteDouble] in {
-
-defm V_RCP_CLAMP_F64 : VOP1InstSI <vop1<0x30>, "v_rcp_clamp_f64", VOP_F64_F64>;
-defm V_RSQ_CLAMP_F64 : VOP1InstSI <vop1<0x32>, "v_rsq_clamp_f64",
- VOP_F64_F64, AMDGPUrsq_clamp
->;
-
-} // End SchedRW = [WriteDouble]
-
-} // End SubtargetPredicate = isSICI
+defm EXP : EXP_m<0, AMDGPUexport>;
+defm EXP_DONE : EXP_m<1, AMDGPUexport_done>;
//===----------------------------------------------------------------------===//
// VINTRP Instructions
@@ -1433,11 +50,11 @@ let Uses = [M0, EXEC] in {
multiclass V_INTERP_P1_F32_m : VINTRP_m <
0x00000000,
- (outs VGPR_32:$dst),
- (ins VGPR_32:$i, i32imm:$attr_chan, i32imm:$attr),
- "v_interp_p1_f32 $dst, $i, $attr_chan, $attr, [m0]",
- [(set f32:$dst, (AMDGPUinterp_p1 i32:$i, (i32 imm:$attr_chan),
- (i32 imm:$attr)))]
+ (outs VGPR_32:$vdst),
+ (ins VGPR_32:$vsrc, Attr:$attr, AttrChan:$attrchan),
+ "v_interp_p1_f32 $vdst, $vsrc, $attr$attrchan",
+ [(set f32:$vdst, (AMDGPUinterp_p1 f32:$vsrc, (i32 imm:$attrchan),
+ (i32 imm:$attr)))]
>;
let OtherPredicates = [has32BankLDS] in {
@@ -1446,459 +63,33 @@ defm V_INTERP_P1_F32 : V_INTERP_P1_F32_m;
} // End OtherPredicates = [has32BankLDS]
-let OtherPredicates = [has16BankLDS], Constraints = "@earlyclobber $dst", isAsmParserOnly=1 in {
+let OtherPredicates = [has16BankLDS], Constraints = "@earlyclobber $vdst", isAsmParserOnly=1 in {
defm V_INTERP_P1_F32_16bank : V_INTERP_P1_F32_m;
-} // End OtherPredicates = [has32BankLDS], Constraints = "@earlyclobber $dst", isAsmParserOnly=1
+} // End OtherPredicates = [has32BankLDS], Constraints = "@earlyclobber $vdst", isAsmParserOnly=1
-let DisableEncoding = "$src0", Constraints = "$src0 = $dst" in {
+let DisableEncoding = "$src0", Constraints = "$src0 = $vdst" in {
defm V_INTERP_P2_F32 : VINTRP_m <
0x00000001,
- (outs VGPR_32:$dst),
- (ins VGPR_32:$src0, VGPR_32:$j, i32imm:$attr_chan, i32imm:$attr),
- "v_interp_p2_f32 $dst, [$src0], $j, $attr_chan, $attr, [m0]",
- [(set f32:$dst, (AMDGPUinterp_p2 f32:$src0, i32:$j, (i32 imm:$attr_chan),
- (i32 imm:$attr)))]>;
+ (outs VGPR_32:$vdst),
+ (ins VGPR_32:$src0, VGPR_32:$vsrc, Attr:$attr, AttrChan:$attrchan),
+ "v_interp_p2_f32 $vdst, $vsrc, $attr$attrchan",
+ [(set f32:$vdst, (AMDGPUinterp_p2 f32:$src0, f32:$vsrc, (i32 imm:$attrchan),
+ (i32 imm:$attr)))]>;
-} // End DisableEncoding = "$src0", Constraints = "$src0 = $dst"
+} // End DisableEncoding = "$src0", Constraints = "$src0 = $vdst"
defm V_INTERP_MOV_F32 : VINTRP_m <
0x00000002,
- (outs VGPR_32:$dst),
- (ins InterpSlot:$src0, i32imm:$attr_chan, i32imm:$attr),
- "v_interp_mov_f32 $dst, $src0, $attr_chan, $attr, [m0]",
- [(set f32:$dst, (AMDGPUinterp_mov (i32 imm:$src0), (i32 imm:$attr_chan),
- (i32 imm:$attr)))]>;
-
-} // End Uses = [M0, EXEC]
-
-//===----------------------------------------------------------------------===//
-// VOP2 Instructions
-//===----------------------------------------------------------------------===//
-
-defm V_CNDMASK_B32 : VOP2eInst <vop2<0x0, 0x0>, "v_cndmask_b32",
- VOP2e_I32_I32_I32_I1
->;
-
-let isCommutable = 1 in {
-defm V_ADD_F32 : VOP2Inst <vop2<0x3, 0x1>, "v_add_f32",
- VOP_F32_F32_F32, fadd
->;
-
-defm V_SUB_F32 : VOP2Inst <vop2<0x4, 0x2>, "v_sub_f32", VOP_F32_F32_F32, fsub>;
-defm V_SUBREV_F32 : VOP2Inst <vop2<0x5, 0x3>, "v_subrev_f32",
- VOP_F32_F32_F32, null_frag, "v_sub_f32"
->;
-} // End isCommutable = 1
-
-let isCommutable = 1 in {
-
-defm V_MUL_LEGACY_F32 : VOP2Inst <vop2<0x7, 0x4>, "v_mul_legacy_f32",
- VOP_F32_F32_F32
->;
-
-defm V_MUL_F32 : VOP2Inst <vop2<0x8, 0x5>, "v_mul_f32",
- VOP_F32_F32_F32, fmul
->;
-
-defm V_MUL_I32_I24 : VOP2Inst <vop2<0x9, 0x6>, "v_mul_i32_i24",
- VOP_I32_I32_I32, AMDGPUmul_i24
->;
-
-defm V_MUL_HI_I32_I24 : VOP2Inst <vop2<0xa,0x7>, "v_mul_hi_i32_i24",
- VOP_I32_I32_I32
->;
-
-defm V_MUL_U32_U24 : VOP2Inst <vop2<0xb, 0x8>, "v_mul_u32_u24",
- VOP_I32_I32_I32, AMDGPUmul_u24
->;
-
-defm V_MUL_HI_U32_U24 : VOP2Inst <vop2<0xc,0x9>, "v_mul_hi_u32_u24",
- VOP_I32_I32_I32
->;
-
-defm V_MIN_F32 : VOP2Inst <vop2<0xf, 0xa>, "v_min_f32", VOP_F32_F32_F32,
- fminnum>;
-defm V_MAX_F32 : VOP2Inst <vop2<0x10, 0xb>, "v_max_f32", VOP_F32_F32_F32,
- fmaxnum>;
-defm V_MIN_I32 : VOP2Inst <vop2<0x11, 0xc>, "v_min_i32", VOP_I32_I32_I32>;
-defm V_MAX_I32 : VOP2Inst <vop2<0x12, 0xd>, "v_max_i32", VOP_I32_I32_I32>;
-defm V_MIN_U32 : VOP2Inst <vop2<0x13, 0xe>, "v_min_u32", VOP_I32_I32_I32>;
-defm V_MAX_U32 : VOP2Inst <vop2<0x14, 0xf>, "v_max_u32", VOP_I32_I32_I32>;
-
-defm V_LSHRREV_B32 : VOP2Inst <
- vop2<0x16, 0x10>, "v_lshrrev_b32", VOP_I32_I32_I32, null_frag,
- "v_lshr_b32"
->;
-
-defm V_ASHRREV_I32 : VOP2Inst <
- vop2<0x18, 0x11>, "v_ashrrev_i32", VOP_I32_I32_I32, null_frag,
- "v_ashr_i32"
->;
-
-defm V_LSHLREV_B32 : VOP2Inst <
- vop2<0x1a, 0x12>, "v_lshlrev_b32", VOP_I32_I32_I32, null_frag,
- "v_lshl_b32"
->;
-
-defm V_AND_B32 : VOP2Inst <vop2<0x1b, 0x13>, "v_and_b32", VOP_I32_I32_I32>;
-defm V_OR_B32 : VOP2Inst <vop2<0x1c, 0x14>, "v_or_b32", VOP_I32_I32_I32>;
-defm V_XOR_B32 : VOP2Inst <vop2<0x1d, 0x15>, "v_xor_b32", VOP_I32_I32_I32>;
-
-let Constraints = "$vdst = $src2", DisableEncoding="$src2",
- isConvertibleToThreeAddress = 1 in {
-defm V_MAC_F32 : VOP2Inst <vop2<0x1f, 0x16>, "v_mac_f32", VOP_MAC>;
-}
-} // End isCommutable = 1
-
-defm V_MADMK_F32 : VOP2MADK <vop2<0x20, 0x17>, "v_madmk_f32", VOP_MADMK>;
-
-let isCommutable = 1 in {
-defm V_MADAK_F32 : VOP2MADK <vop2<0x21, 0x18>, "v_madak_f32", VOP_MADAK>;
-} // End isCommutable = 1
-
-let isCommutable = 1 in {
-// No patterns so that the scalar instructions are always selected.
-// The scalar versions will be replaced with vector when needed later.
-
-// V_ADD_I32, V_SUB_I32, and V_SUBREV_I32 where renamed to *_U32 in VI,
-// but the VI instructions behave the same as the SI versions.
-defm V_ADD_I32 : VOP2bInst <vop2<0x25, 0x19>, "v_add_i32",
- VOP2b_I32_I1_I32_I32
->;
-defm V_SUB_I32 : VOP2bInst <vop2<0x26, 0x1a>, "v_sub_i32", VOP2b_I32_I1_I32_I32>;
-
-defm V_SUBREV_I32 : VOP2bInst <vop2<0x27, 0x1b>, "v_subrev_i32",
- VOP2b_I32_I1_I32_I32, null_frag, "v_sub_i32"
->;
-
-defm V_ADDC_U32 : VOP2bInst <vop2<0x28, 0x1c>, "v_addc_u32",
- VOP2b_I32_I1_I32_I32_I1
->;
-defm V_SUBB_U32 : VOP2bInst <vop2<0x29, 0x1d>, "v_subb_u32",
- VOP2b_I32_I1_I32_I32_I1
->;
-defm V_SUBBREV_U32 : VOP2bInst <vop2<0x2a, 0x1e>, "v_subbrev_u32",
- VOP2b_I32_I1_I32_I32_I1, null_frag, "v_subb_u32"
->;
-
-} // End isCommutable = 1
-
-// These are special and do not read the exec mask.
-let isConvergent = 1, Uses = []<Register> in {
-
-defm V_READLANE_B32 : VOP2SI_3VI_m <
- vop3 <0x001, 0x289>,
- "v_readlane_b32",
- (outs SReg_32:$vdst),
- (ins VS_32:$src0, SCSrc_32:$src1),
- "v_readlane_b32 $vdst, $src0, $src1"
->;
-
-defm V_WRITELANE_B32 : VOP2SI_3VI_m <
- vop3 <0x002, 0x28a>,
- "v_writelane_b32",
(outs VGPR_32:$vdst),
- (ins SReg_32:$src0, SCSrc_32:$src1),
- "v_writelane_b32 $vdst, $src0, $src1"
->;
-
-} // End isConvergent = 1
-
-// These instructions only exist on SI and CI
-let SubtargetPredicate = isSICI in {
-
-let isCommutable = 1 in {
-defm V_MAC_LEGACY_F32 : VOP2InstSI <vop2<0x6>, "v_mac_legacy_f32",
- VOP_F32_F32_F32
->;
-} // End isCommutable = 1
-
-defm V_MIN_LEGACY_F32 : VOP2InstSI <vop2<0xd>, "v_min_legacy_f32",
- VOP_F32_F32_F32, AMDGPUfmin_legacy
->;
-defm V_MAX_LEGACY_F32 : VOP2InstSI <vop2<0xe>, "v_max_legacy_f32",
- VOP_F32_F32_F32, AMDGPUfmax_legacy
->;
-
-let isCommutable = 1 in {
-defm V_LSHR_B32 : VOP2InstSI <vop2<0x15>, "v_lshr_b32", VOP_I32_I32_I32>;
-defm V_ASHR_I32 : VOP2InstSI <vop2<0x17>, "v_ashr_i32", VOP_I32_I32_I32>;
-defm V_LSHL_B32 : VOP2InstSI <vop2<0x19>, "v_lshl_b32", VOP_I32_I32_I32>;
-} // End isCommutable = 1
-} // End let SubtargetPredicate = SICI
-
-defm V_BFM_B32 : VOP2_VI3_Inst <vop23<0x1e, 0x293>, "v_bfm_b32",
- VOP_I32_I32_I32
->;
-defm V_BCNT_U32_B32 : VOP2_VI3_Inst <vop23<0x22, 0x28b>, "v_bcnt_u32_b32",
- VOP_I32_I32_I32
->;
-defm V_MBCNT_LO_U32_B32 : VOP2_VI3_Inst <vop23<0x23, 0x28c>, "v_mbcnt_lo_u32_b32",
- VOP_I32_I32_I32, int_amdgcn_mbcnt_lo
->;
-defm V_MBCNT_HI_U32_B32 : VOP2_VI3_Inst <vop23<0x24, 0x28d>, "v_mbcnt_hi_u32_b32",
- VOP_I32_I32_I32, int_amdgcn_mbcnt_hi
->;
-defm V_LDEXP_F32 : VOP2_VI3_Inst <vop23<0x2b, 0x288>, "v_ldexp_f32",
- VOP_F32_F32_I32, AMDGPUldexp
->;
-
-defm V_CVT_PKACCUM_U8_F32 : VOP2_VI3_Inst <vop23<0x2c, 0x1f0>, "v_cvt_pkaccum_u8_f32",
- VOP_I32_F32_I32>; // TODO: set "Uses = dst"
-
-defm V_CVT_PKNORM_I16_F32 : VOP2_VI3_Inst <vop23<0x2d, 0x294>, "v_cvt_pknorm_i16_f32",
- VOP_I32_F32_F32
->;
-defm V_CVT_PKNORM_U16_F32 : VOP2_VI3_Inst <vop23<0x2e, 0x295>, "v_cvt_pknorm_u16_f32",
- VOP_I32_F32_F32
->;
-defm V_CVT_PKRTZ_F16_F32 : VOP2_VI3_Inst <vop23<0x2f, 0x296>, "v_cvt_pkrtz_f16_f32",
- VOP_I32_F32_F32, int_SI_packf16
->;
-defm V_CVT_PK_U16_U32 : VOP2_VI3_Inst <vop23<0x30, 0x297>, "v_cvt_pk_u16_u32",
- VOP_I32_I32_I32
->;
-defm V_CVT_PK_I16_I32 : VOP2_VI3_Inst <vop23<0x31, 0x298>, "v_cvt_pk_i16_i32",
- VOP_I32_I32_I32
->;
-
-//===----------------------------------------------------------------------===//
-// VOP3 Instructions
-//===----------------------------------------------------------------------===//
-
-let isCommutable = 1 in {
-defm V_MAD_LEGACY_F32 : VOP3Inst <vop3<0x140, 0x1c0>, "v_mad_legacy_f32",
- VOP_F32_F32_F32_F32
->;
-
-defm V_MAD_F32 : VOP3Inst <vop3<0x141, 0x1c1>, "v_mad_f32",
- VOP_F32_F32_F32_F32, fmad
->;
-
-defm V_MAD_I32_I24 : VOP3Inst <vop3<0x142, 0x1c2>, "v_mad_i32_i24",
- VOP_I32_I32_I32_I32, AMDGPUmad_i24
->;
-defm V_MAD_U32_U24 : VOP3Inst <vop3<0x143, 0x1c3>, "v_mad_u32_u24",
- VOP_I32_I32_I32_I32, AMDGPUmad_u24
->;
-} // End isCommutable = 1
-
-defm V_CUBEID_F32 : VOP3Inst <vop3<0x144, 0x1c4>, "v_cubeid_f32",
- VOP_F32_F32_F32_F32, int_amdgcn_cubeid
->;
-defm V_CUBESC_F32 : VOP3Inst <vop3<0x145, 0x1c5>, "v_cubesc_f32",
- VOP_F32_F32_F32_F32, int_amdgcn_cubesc
->;
-defm V_CUBETC_F32 : VOP3Inst <vop3<0x146, 0x1c6>, "v_cubetc_f32",
- VOP_F32_F32_F32_F32, int_amdgcn_cubetc
->;
-defm V_CUBEMA_F32 : VOP3Inst <vop3<0x147, 0x1c7>, "v_cubema_f32",
- VOP_F32_F32_F32_F32, int_amdgcn_cubema
->;
-
-defm V_BFE_U32 : VOP3Inst <vop3<0x148, 0x1c8>, "v_bfe_u32",
- VOP_I32_I32_I32_I32, AMDGPUbfe_u32
->;
-defm V_BFE_I32 : VOP3Inst <vop3<0x149, 0x1c9>, "v_bfe_i32",
- VOP_I32_I32_I32_I32, AMDGPUbfe_i32
->;
-
-defm V_BFI_B32 : VOP3Inst <vop3<0x14a, 0x1ca>, "v_bfi_b32",
- VOP_I32_I32_I32_I32, AMDGPUbfi
->;
-
-let isCommutable = 1 in {
-defm V_FMA_F32 : VOP3Inst <vop3<0x14b, 0x1cb>, "v_fma_f32",
- VOP_F32_F32_F32_F32, fma
->;
-defm V_FMA_F64 : VOP3Inst <vop3<0x14c, 0x1cc>, "v_fma_f64",
- VOP_F64_F64_F64_F64, fma
->;
-
-defm V_LERP_U8 : VOP3Inst <vop3<0x14d, 0x1cd>, "v_lerp_u8",
- VOP_I32_I32_I32_I32, int_amdgcn_lerp
->;
-} // End isCommutable = 1
-
-//def V_LERP_U8 : VOP3_U8 <0x0000014d, "v_lerp_u8", []>;
-defm V_ALIGNBIT_B32 : VOP3Inst <vop3<0x14e, 0x1ce>, "v_alignbit_b32",
- VOP_I32_I32_I32_I32
->;
-defm V_ALIGNBYTE_B32 : VOP3Inst <vop3<0x14f, 0x1cf>, "v_alignbyte_b32",
- VOP_I32_I32_I32_I32
->;
-
-defm V_MIN3_F32 : VOP3Inst <vop3<0x151, 0x1d0>, "v_min3_f32",
- VOP_F32_F32_F32_F32, AMDGPUfmin3>;
-
-defm V_MIN3_I32 : VOP3Inst <vop3<0x152, 0x1d1>, "v_min3_i32",
- VOP_I32_I32_I32_I32, AMDGPUsmin3
->;
-defm V_MIN3_U32 : VOP3Inst <vop3<0x153, 0x1d2>, "v_min3_u32",
- VOP_I32_I32_I32_I32, AMDGPUumin3
->;
-defm V_MAX3_F32 : VOP3Inst <vop3<0x154, 0x1d3>, "v_max3_f32",
- VOP_F32_F32_F32_F32, AMDGPUfmax3
->;
-defm V_MAX3_I32 : VOP3Inst <vop3<0x155, 0x1d4>, "v_max3_i32",
- VOP_I32_I32_I32_I32, AMDGPUsmax3
->;
-defm V_MAX3_U32 : VOP3Inst <vop3<0x156, 0x1d5>, "v_max3_u32",
- VOP_I32_I32_I32_I32, AMDGPUumax3
->;
-defm V_MED3_F32 : VOP3Inst <vop3<0x157, 0x1d6>, "v_med3_f32",
- VOP_F32_F32_F32_F32, AMDGPUfmed3
->;
-defm V_MED3_I32 : VOP3Inst <vop3<0x158, 0x1d7>, "v_med3_i32",
- VOP_I32_I32_I32_I32, AMDGPUsmed3
->;
-defm V_MED3_U32 : VOP3Inst <vop3<0x159, 0x1d8>, "v_med3_u32",
- VOP_I32_I32_I32_I32, AMDGPUumed3
->;
-
-//def V_SAD_U8 : VOP3_U8 <0x0000015a, "v_sad_u8", []>;
-//def V_SAD_HI_U8 : VOP3_U8 <0x0000015b, "v_sad_hi_u8", []>;
-//def V_SAD_U16 : VOP3_U16 <0x0000015c, "v_sad_u16", []>;
-defm V_SAD_U32 : VOP3Inst <vop3<0x15d, 0x1dc>, "v_sad_u32",
- VOP_I32_I32_I32_I32
->;
-//def V_CVT_PK_U8_F32 : VOP3_U8 <0x0000015e, "v_cvt_pk_u8_f32", []>;
-defm V_DIV_FIXUP_F32 : VOP3Inst <
- vop3<0x15f, 0x1de>, "v_div_fixup_f32", VOP_F32_F32_F32_F32, AMDGPUdiv_fixup
->;
-
-let SchedRW = [WriteDoubleAdd] in {
-
-defm V_DIV_FIXUP_F64 : VOP3Inst <
- vop3<0x160, 0x1df>, "v_div_fixup_f64", VOP_F64_F64_F64_F64, AMDGPUdiv_fixup
->;
-
-} // End SchedRW = [WriteDouble]
-
-let SchedRW = [WriteDoubleAdd] in {
-let isCommutable = 1 in {
-
-defm V_ADD_F64 : VOP3Inst <vop3<0x164, 0x280>, "v_add_f64",
- VOP_F64_F64_F64, fadd, 1
->;
-defm V_MUL_F64 : VOP3Inst <vop3<0x165, 0x281>, "v_mul_f64",
- VOP_F64_F64_F64, fmul, 1
->;
-
-defm V_MIN_F64 : VOP3Inst <vop3<0x166, 0x282>, "v_min_f64",
- VOP_F64_F64_F64, fminnum, 1
->;
-defm V_MAX_F64 : VOP3Inst <vop3<0x167, 0x283>, "v_max_f64",
- VOP_F64_F64_F64, fmaxnum, 1
->;
-
-} // End isCommutable = 1
-
-defm V_LDEXP_F64 : VOP3Inst <vop3<0x168, 0x284>, "v_ldexp_f64",
- VOP_F64_F64_I32, AMDGPUldexp, 1
->;
-
-} // End let SchedRW = [WriteDoubleAdd]
-
-let isCommutable = 1, SchedRW = [WriteQuarterRate32] in {
-
-defm V_MUL_LO_U32 : VOP3Inst <vop3<0x169, 0x285>, "v_mul_lo_u32",
- VOP_I32_I32_I32
->;
-defm V_MUL_HI_U32 : VOP3Inst <vop3<0x16a, 0x286>, "v_mul_hi_u32",
- VOP_I32_I32_I32, mulhu
->;
-
-let DisableVIDecoder=1 in { // removed from VI as identical to V_MUL_LO_U32
-defm V_MUL_LO_I32 : VOP3Inst <vop3<0x16b, 0x285>, "v_mul_lo_i32",
- VOP_I32_I32_I32
->;
-}
-
-defm V_MUL_HI_I32 : VOP3Inst <vop3<0x16c, 0x287>, "v_mul_hi_i32",
- VOP_I32_I32_I32, mulhs
->;
-
-} // End isCommutable = 1, SchedRW = [WriteQuarterRate32]
-
-let SchedRW = [WriteFloatFMA, WriteSALU] in {
-defm V_DIV_SCALE_F32 : VOP3bInst <vop3<0x16d, 0x1e0>, "v_div_scale_f32",
- VOP3b_F32_I1_F32_F32_F32, [], 1
->;
-}
-
-let SchedRW = [WriteDouble, WriteSALU] in {
-// Double precision division pre-scale.
-defm V_DIV_SCALE_F64 : VOP3bInst <vop3<0x16e, 0x1e1>, "v_div_scale_f64",
- VOP3b_F64_I1_F64_F64_F64, [], 1
->;
-} // End SchedRW = [WriteDouble]
-
-let isCommutable = 1, Uses = [VCC, EXEC] in {
-
-let SchedRW = [WriteFloatFMA] in {
-// v_div_fmas_f32:
-// result = src0 * src1 + src2
-// if (vcc)
-// result *= 2^32
-//
-defm V_DIV_FMAS_F32 : VOP3_VCC_Inst <vop3<0x16f, 0x1e2>, "v_div_fmas_f32",
- VOP_F32_F32_F32_F32, AMDGPUdiv_fmas
->;
-}
-
-let SchedRW = [WriteDouble] in {
-// v_div_fmas_f64:
-// result = src0 * src1 + src2
-// if (vcc)
-// result *= 2^64
-//
-defm V_DIV_FMAS_F64 : VOP3_VCC_Inst <vop3<0x170, 0x1e3>, "v_div_fmas_f64",
- VOP_F64_F64_F64_F64, AMDGPUdiv_fmas
->;
-
-} // End SchedRW = [WriteDouble]
-} // End isCommutable = 1, Uses = [VCC, EXEC]
-
-//def V_MSAD_U8 : VOP3_U8 <0x00000171, "v_msad_u8", []>;
-//def V_QSAD_U8 : VOP3_U8 <0x00000172, "v_qsad_u8", []>;
-//def V_MQSAD_U8 : VOP3_U8 <0x00000173, "v_mqsad_u8", []>;
-
-let SchedRW = [WriteDouble] in {
-defm V_TRIG_PREOP_F64 : VOP3Inst <
- vop3<0x174, 0x292>, "v_trig_preop_f64", VOP_F64_F64_I32, AMDGPUtrig_preop
->;
-
-} // End SchedRW = [WriteDouble]
-
-// These instructions only exist on SI and CI
-let SubtargetPredicate = isSICI in {
+ (ins InterpSlot:$vsrc, Attr:$attr, AttrChan:$attrchan),
+ "v_interp_mov_f32 $vdst, $vsrc, $attr$attrchan",
+ [(set f32:$vdst, (AMDGPUinterp_mov (i32 imm:$vsrc), (i32 imm:$attrchan),
+ (i32 imm:$attr)))]>;
-defm V_LSHL_B64 : VOP3Inst <vop3<0x161>, "v_lshl_b64", VOP_I64_I64_I32>;
-defm V_LSHR_B64 : VOP3Inst <vop3<0x162>, "v_lshr_b64", VOP_I64_I64_I32>;
-defm V_ASHR_I64 : VOP3Inst <vop3<0x163>, "v_ashr_i64", VOP_I64_I64_I32>;
-
-defm V_MULLIT_F32 : VOP3Inst <vop3<0x150>, "v_mullit_f32",
- VOP_F32_F32_F32_F32>;
-
-} // End SubtargetPredicate = isSICI
-
-let SubtargetPredicate = isVI, DisableSIDecoder = 1 in {
-
-defm V_LSHLREV_B64 : VOP3Inst <vop3<0, 0x28f>, "v_lshlrev_b64",
- VOP_I64_I32_I64
->;
-defm V_LSHRREV_B64 : VOP3Inst <vop3<0, 0x290>, "v_lshrrev_b64",
- VOP_I64_I32_I64
->;
-defm V_ASHRREV_I64 : VOP3Inst <vop3<0, 0x291>, "v_ashrrev_i64",
- VOP_I64_I32_I64
->;
-
-} // End SubtargetPredicate = isVI
+} // End Uses = [M0, EXEC]
//===----------------------------------------------------------------------===//
// Pseudo Instructions
@@ -1908,16 +99,16 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Uses = [EXEC] in {
// For use in patterns
def V_CNDMASK_B64_PSEUDO : VOP3Common <(outs VReg_64:$vdst),
- (ins VSrc_64:$src0, VSrc_64:$src1, SSrc_64:$src2), "", []> {
+ (ins VSrc_b64:$src0, VSrc_b64:$src1, SSrc_b64:$src2), "", []> {
let isPseudo = 1;
let isCodeGenOnly = 1;
+ let usesCustomInserter = 1;
}
// 64-bit vector move instruction. This is mainly used by the SIFoldOperands
// pass to enable folding of inline immediates.
-def V_MOV_B64_PSEUDO : PseudoInstSI <(outs VReg_64:$vdst), (ins VSrc_64:$src0)> {
- let VALU = 1;
-}
+def V_MOV_B64_PSEUDO : VPseudoInstSI <(outs VReg_64:$vdst),
+ (ins VSrc_b64:$src0)>;
} // End let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Uses = [EXEC]
let usesCustomInserter = 1, SALU = 1 in {
@@ -1925,83 +116,142 @@ def GET_GROUPSTATICSIZE : PseudoInstSI <(outs SReg_32:$sdst), (ins),
[(set SReg_32:$sdst, (int_amdgcn_groupstaticsize))]>;
} // End let usesCustomInserter = 1, SALU = 1
+def S_MOV_B64_term : PseudoInstSI<(outs SReg_64:$dst),
+ (ins SSrc_b64:$src0)> {
+ let SALU = 1;
+ let isAsCheapAsAMove = 1;
+ let isTerminator = 1;
+}
+
+def S_XOR_B64_term : PseudoInstSI<(outs SReg_64:$dst),
+ (ins SSrc_b64:$src0, SSrc_b64:$src1)> {
+ let SALU = 1;
+ let isAsCheapAsAMove = 1;
+ let isTerminator = 1;
+}
+
+def S_ANDN2_B64_term : PseudoInstSI<(outs SReg_64:$dst),
+ (ins SSrc_b64:$src0, SSrc_b64:$src1)> {
+ let SALU = 1;
+ let isAsCheapAsAMove = 1;
+ let isTerminator = 1;
+}
+
+def WAVE_BARRIER : SPseudoInstSI<(outs), (ins),
+ [(int_amdgcn_wave_barrier)]> {
+ let SchedRW = [];
+ let hasNoSchedulingInfo = 1;
+ let hasSideEffects = 1;
+ let mayLoad = 1;
+ let mayStore = 1;
+ let isBarrier = 1;
+ let isConvergent = 1;
+}
+
// SI pseudo instructions. These are used by the CFG structurizer pass
// and should be lowered to ISA instructions prior to codegen.
-let hasSideEffects = 1 in {
-
// Dummy terminator instruction to use after control flow instructions
// replaced with exec mask operations.
def SI_MASK_BRANCH : PseudoInstSI <
- (outs), (ins brtarget:$target, SReg_64:$dst)> {
- let isBranch = 1;
+ (outs), (ins brtarget:$target)> {
+ let isBranch = 0;
let isTerminator = 1;
- let isBarrier = 1;
- let SALU = 1;
+ let isBarrier = 0;
+ let Uses = [EXEC];
+ let SchedRW = [];
+ let hasNoSchedulingInfo = 1;
}
-let Uses = [EXEC], Defs = [EXEC, SCC] in {
-
-let isBranch = 1, isTerminator = 1 in {
+let isTerminator = 1 in {
-def SI_IF: PseudoInstSI <
+def SI_IF: CFPseudoInstSI <
(outs SReg_64:$dst), (ins SReg_64:$vcc, brtarget:$target),
- [(set i64:$dst, (int_amdgcn_if i1:$vcc, bb:$target))]> {
+ [(set i64:$dst, (int_amdgcn_if i1:$vcc, bb:$target))], 1, 1> {
let Constraints = "";
+ let Size = 12;
+ let mayLoad = 1;
+ let mayStore = 1;
+ let hasSideEffects = 1;
}
-def SI_ELSE : PseudoInstSI <
- (outs SReg_64:$dst), (ins SReg_64:$src, brtarget:$target),
- [(set i64:$dst, (int_amdgcn_else i64:$src, bb:$target))]> {
+def SI_ELSE : CFPseudoInstSI <
+ (outs SReg_64:$dst), (ins SReg_64:$src, brtarget:$target, i1imm:$execfix), [], 1, 1> {
let Constraints = "$src = $dst";
+ let Size = 12;
+ let mayStore = 1;
+ let mayLoad = 1;
+ let hasSideEffects = 1;
}
-def SI_LOOP : PseudoInstSI <
+def SI_LOOP : CFPseudoInstSI <
(outs), (ins SReg_64:$saved, brtarget:$target),
- [(int_amdgcn_loop i64:$saved, bb:$target)]
->;
+ [(int_amdgcn_loop i64:$saved, bb:$target)], 1, 1> {
+ let Size = 8;
+ let isBranch = 1;
+ let hasSideEffects = 1;
+ let mayLoad = 1;
+ let mayStore = 1;
+}
} // End isBranch = 1, isTerminator = 1
+def SI_END_CF : CFPseudoInstSI <
+ (outs), (ins SReg_64:$saved),
+ [(int_amdgcn_end_cf i64:$saved)], 1, 1> {
+ let Size = 4;
+ let isAsCheapAsAMove = 1;
+ let isReMaterializable = 1;
+ let mayLoad = 1;
+ let mayStore = 1;
+ let hasSideEffects = 1;
+}
-def SI_BREAK : PseudoInstSI <
+def SI_BREAK : CFPseudoInstSI <
(outs SReg_64:$dst), (ins SReg_64:$src),
- [(set i64:$dst, (int_amdgcn_break i64:$src))]
->;
+ [(set i64:$dst, (int_amdgcn_break i64:$src))], 1> {
+ let Size = 4;
+ let isAsCheapAsAMove = 1;
+ let isReMaterializable = 1;
+}
-def SI_IF_BREAK : PseudoInstSI <
+def SI_IF_BREAK : CFPseudoInstSI <
(outs SReg_64:$dst), (ins SReg_64:$vcc, SReg_64:$src),
- [(set i64:$dst, (int_amdgcn_if_break i1:$vcc, i64:$src))]
->;
+ [(set i64:$dst, (int_amdgcn_if_break i1:$vcc, i64:$src))]> {
+ let Size = 4;
+ let isAsCheapAsAMove = 1;
+ let isReMaterializable = 1;
+}
-def SI_ELSE_BREAK : PseudoInstSI <
+def SI_ELSE_BREAK : CFPseudoInstSI <
(outs SReg_64:$dst), (ins SReg_64:$src0, SReg_64:$src1),
- [(set i64:$dst, (int_amdgcn_else_break i64:$src0, i64:$src1))]
->;
-
-def SI_END_CF : PseudoInstSI <
- (outs), (ins SReg_64:$saved),
- [(int_amdgcn_end_cf i64:$saved)]
->;
-
-} // End Uses = [EXEC], Defs = [EXEC, SCC]
+ [(set i64:$dst, (int_amdgcn_else_break i64:$src0, i64:$src1))]> {
+ let Size = 4;
+ let isAsCheapAsAMove = 1;
+ let isReMaterializable = 1;
+}
let Uses = [EXEC], Defs = [EXEC,VCC] in {
def SI_KILL : PseudoInstSI <
- (outs), (ins VSrc_32:$src),
- [(int_AMDGPU_kill f32:$src)]> {
+ (outs), (ins VSrc_b32:$src),
+ [(AMDGPUkill i32:$src)]> {
let isConvergent = 1;
let usesCustomInserter = 1;
}
-def SI_KILL_TERMINATOR : PseudoInstSI <
- (outs), (ins VSrc_32:$src)> {
+def SI_KILL_TERMINATOR : SPseudoInstSI <
+ (outs), (ins VSrc_b32:$src)> {
let isTerminator = 1;
}
} // End Uses = [EXEC], Defs = [EXEC,VCC]
-} // End mayLoad = 1, mayStore = 1, hasSideEffects = 1
+// Branch on undef scc. Used to avoid intermediate copy from
+// IMPLICIT_DEF to SCC.
+def SI_BR_UNDEF : SPseudoInstSI <(outs), (ins sopp_brtarget:$simm16)> {
+ let isTerminator = 1;
+ let usesCustomInserter = 1;
+}
def SI_PS_LIVE : PseudoInstSI <
(outs SReg_64:$dst), (ins),
@@ -2013,36 +263,37 @@ def SI_PS_LIVE : PseudoInstSI <
// s_mov_b32 rather than a copy of another initialized
// register. MachineCSE skips copies, and we don't want to have to
// fold operands before it runs.
-def SI_INIT_M0 : PseudoInstSI <(outs), (ins SSrc_32:$src)> {
+def SI_INIT_M0 : SPseudoInstSI <(outs), (ins SSrc_b32:$src)> {
let Defs = [M0];
let usesCustomInserter = 1;
let isAsCheapAsAMove = 1;
- let SALU = 1;
let isReMaterializable = 1;
}
-def SI_RETURN : PseudoInstSI <
+def SI_RETURN : SPseudoInstSI <
(outs), (ins variable_ops), [(AMDGPUreturn)]> {
let isTerminator = 1;
let isBarrier = 1;
let isReturn = 1;
let hasSideEffects = 1;
- let SALU = 1;
let hasNoSchedulingInfo = 1;
let DisableWQM = 1;
}
-let Uses = [EXEC], Defs = [EXEC, VCC, M0],
+let Defs = [M0, EXEC],
UseNamedOperandTable = 1 in {
-class SI_INDIRECT_SRC<RegisterClass rc> : PseudoInstSI <
- (outs VGPR_32:$vdst, SReg_64:$sdst),
- (ins rc:$src, VS_32:$idx, i32imm:$offset)>;
+class SI_INDIRECT_SRC<RegisterClass rc> : VPseudoInstSI <
+ (outs VGPR_32:$vdst),
+ (ins rc:$src, VS_32:$idx, i32imm:$offset)> {
+ let usesCustomInserter = 1;
+}
-class SI_INDIRECT_DST<RegisterClass rc> : PseudoInstSI <
- (outs rc:$vdst, SReg_64:$sdst),
- (ins unknown:$src, VS_32:$idx, i32imm:$offset, VGPR_32:$val)> {
+class SI_INDIRECT_DST<RegisterClass rc> : VPseudoInstSI <
+ (outs rc:$vdst),
+ (ins rc:$src, VS_32:$idx, i32imm:$offset, VGPR_32:$val)> {
let Constraints = "$src = $vdst";
+ let usesCustomInserter = 1;
}
// TODO: We can support indirect SGPR access.
@@ -2058,53 +309,60 @@ def SI_INDIRECT_DST_V4 : SI_INDIRECT_DST<VReg_128>;
def SI_INDIRECT_DST_V8 : SI_INDIRECT_DST<VReg_256>;
def SI_INDIRECT_DST_V16 : SI_INDIRECT_DST<VReg_512>;
-} // End Uses = [EXEC], Defs = [EXEC,VCC,M0]
+} // End Uses = [EXEC], Defs = [M0, EXEC]
multiclass SI_SPILL_SGPR <RegisterClass sgpr_class> {
- let UseNamedOperandTable = 1, Uses = [EXEC] in {
+ let UseNamedOperandTable = 1, SGPRSpill = 1, Uses = [EXEC] in {
def _SAVE : PseudoInstSI <
(outs),
- (ins sgpr_class:$src, i32imm:$frame_idx)> {
+ (ins sgpr_class:$data, i32imm:$addr)> {
let mayStore = 1;
let mayLoad = 0;
}
def _RESTORE : PseudoInstSI <
- (outs sgpr_class:$dst),
- (ins i32imm:$frame_idx)> {
+ (outs sgpr_class:$data),
+ (ins i32imm:$addr)> {
let mayStore = 0;
let mayLoad = 1;
}
} // End UseNamedOperandTable = 1
}
-// It's unclear whether you can use M0 as the output of v_readlane_b32
-// instructions, so use SReg_32_XM0 register class for spills to prevent
-// this from happening.
-defm SI_SPILL_S32 : SI_SPILL_SGPR <SReg_32_XM0>;
+// You cannot use M0 as the output of v_readlane_b32 instructions or
+// use it in the sdata operand of SMEM instructions. We still need to
+// be able to spill the physical register m0, so allow it for
+// SI_SPILL_32_* instructions.
+defm SI_SPILL_S32 : SI_SPILL_SGPR <SReg_32>;
defm SI_SPILL_S64 : SI_SPILL_SGPR <SReg_64>;
defm SI_SPILL_S128 : SI_SPILL_SGPR <SReg_128>;
defm SI_SPILL_S256 : SI_SPILL_SGPR <SReg_256>;
defm SI_SPILL_S512 : SI_SPILL_SGPR <SReg_512>;
multiclass SI_SPILL_VGPR <RegisterClass vgpr_class> {
- let UseNamedOperandTable = 1, VGPRSpill = 1, Uses = [EXEC] in {
- def _SAVE : PseudoInstSI <
+ let UseNamedOperandTable = 1, VGPRSpill = 1,
+ SchedRW = [WriteVMEM] in {
+ def _SAVE : VPseudoInstSI <
(outs),
- (ins vgpr_class:$src, i32imm:$frame_idx, SReg_128:$scratch_rsrc,
- SReg_32:$scratch_offset, i32imm:$offset)> {
+ (ins vgpr_class:$vdata, i32imm:$vaddr, SReg_128:$srsrc,
+ SReg_32:$soffset, i32imm:$offset)> {
let mayStore = 1;
let mayLoad = 0;
+ // (2 * 4) + (8 * num_subregs) bytes maximum
+ let Size = !add(!shl(!srl(vgpr_class.Size, 5), 3), 8);
}
- def _RESTORE : PseudoInstSI <
- (outs vgpr_class:$dst),
- (ins i32imm:$frame_idx, SReg_128:$scratch_rsrc, SReg_32:$scratch_offset,
+ def _RESTORE : VPseudoInstSI <
+ (outs vgpr_class:$vdata),
+ (ins i32imm:$vaddr, SReg_128:$srsrc, SReg_32:$soffset,
i32imm:$offset)> {
let mayStore = 0;
let mayLoad = 1;
+
+ // (2 * 4) + (8 * num_subregs) bytes maximum
+ let Size = !add(!shl(!srl(vgpr_class.Size, 5), 3), 8);
}
- } // End UseNamedOperandTable = 1, VGPRSpill = 1
+ } // End UseNamedOperandTable = 1, VGPRSpill = 1, SchedRW = [WriteVMEM]
}
defm SI_SPILL_V32 : SI_SPILL_VGPR <VGPR_32>;
@@ -2114,344 +372,26 @@ defm SI_SPILL_V128 : SI_SPILL_VGPR <VReg_128>;
defm SI_SPILL_V256 : SI_SPILL_VGPR <VReg_256>;
defm SI_SPILL_V512 : SI_SPILL_VGPR <VReg_512>;
-let Defs = [SCC] in {
-
-def SI_PC_ADD_REL_OFFSET : PseudoInstSI <
+def SI_PC_ADD_REL_OFFSET : SPseudoInstSI <
(outs SReg_64:$dst),
- (ins si_ga:$ptr),
- [(set SReg_64:$dst, (i64 (SIpc_add_rel_offset (tglobaladdr:$ptr))))]> {
- let SALU = 1;
+ (ins si_ga:$ptr_lo, si_ga:$ptr_hi),
+ [(set SReg_64:$dst,
+ (i64 (SIpc_add_rel_offset (tglobaladdr:$ptr_lo), (tglobaladdr:$ptr_hi))))]> {
+ let Defs = [SCC];
}
-} // End Defs = [SCC]
-
} // End SubtargetPredicate = isGCN
let Predicates = [isGCN] in {
-def : Pat <
- (int_AMDGPU_kilp),
- (SI_KILL 0xbf800000)
->;
-
-/* int_SI_vs_load_input */
-def : Pat<
- (SIload_input v4i32:$tlst, imm:$attr_offset, i32:$buf_idx_vgpr),
- (BUFFER_LOAD_FORMAT_XYZW_IDXEN $buf_idx_vgpr, $tlst, 0, imm:$attr_offset, 0, 0, 0)
->;
-
-def : Pat <
- (int_SI_export imm:$en, imm:$vm, imm:$done, imm:$tgt, imm:$compr,
- f32:$src0, f32:$src1, f32:$src2, f32:$src3),
- (EXP imm:$en, imm:$tgt, imm:$compr, imm:$done, imm:$vm,
- $src0, $src1, $src2, $src3)
->;
-
-//===----------------------------------------------------------------------===//
-// buffer_load/store_format patterns
-//===----------------------------------------------------------------------===//
-
-multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt,
- string opcode> {
- def : Pat<
- (vt (name v4i32:$rsrc, 0,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$glc, imm:$slc)),
- (!cast<MUBUF>(opcode # _OFFSET) $rsrc, $soffset, (as_i16imm $offset),
- (as_i1imm $glc), (as_i1imm $slc), 0)
- >;
-
- def : Pat<
- (vt (name v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$glc, imm:$slc)),
- (!cast<MUBUF>(opcode # _IDXEN) $vindex, $rsrc, $soffset, (as_i16imm $offset),
- (as_i1imm $glc), (as_i1imm $slc), 0)
- >;
-
- def : Pat<
- (vt (name v4i32:$rsrc, 0,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$glc, imm:$slc)),
- (!cast<MUBUF>(opcode # _OFFEN) $voffset, $rsrc, $soffset, (as_i16imm $offset),
- (as_i1imm $glc), (as_i1imm $slc), 0)
- >;
-
- def : Pat<
- (vt (name v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$glc, imm:$slc)),
- (!cast<MUBUF>(opcode # _BOTHEN)
- (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
- $rsrc, $soffset, (as_i16imm $offset),
- (as_i1imm $glc), (as_i1imm $slc), 0)
- >;
-}
-
-defm : MUBUF_LoadIntrinsicPat<int_amdgcn_buffer_load_format, f32, "BUFFER_LOAD_FORMAT_X">;
-defm : MUBUF_LoadIntrinsicPat<int_amdgcn_buffer_load_format, v2f32, "BUFFER_LOAD_FORMAT_XY">;
-defm : MUBUF_LoadIntrinsicPat<int_amdgcn_buffer_load_format, v4f32, "BUFFER_LOAD_FORMAT_XYZW">;
-defm : MUBUF_LoadIntrinsicPat<int_amdgcn_buffer_load, f32, "BUFFER_LOAD_DWORD">;
-defm : MUBUF_LoadIntrinsicPat<int_amdgcn_buffer_load, v2f32, "BUFFER_LOAD_DWORDX2">;
-defm : MUBUF_LoadIntrinsicPat<int_amdgcn_buffer_load, v4f32, "BUFFER_LOAD_DWORDX4">;
-
-multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt,
- string opcode> {
- def : Pat<
- (name vt:$vdata, v4i32:$rsrc, 0,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$glc, imm:$slc),
- (!cast<MUBUF>(opcode # _OFFSET_exact) $vdata, $rsrc, $soffset, (as_i16imm $offset),
- (as_i1imm $glc), (as_i1imm $slc), 0)
- >;
-
- def : Pat<
- (name vt:$vdata, v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$glc, imm:$slc),
- (!cast<MUBUF>(opcode # _IDXEN_exact) $vdata, $vindex, $rsrc, $soffset,
- (as_i16imm $offset), (as_i1imm $glc),
- (as_i1imm $slc), 0)
- >;
-
- def : Pat<
- (name vt:$vdata, v4i32:$rsrc, 0,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$glc, imm:$slc),
- (!cast<MUBUF>(opcode # _OFFEN_exact) $vdata, $voffset, $rsrc, $soffset,
- (as_i16imm $offset), (as_i1imm $glc),
- (as_i1imm $slc), 0)
- >;
-
- def : Pat<
- (name vt:$vdata, v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$glc, imm:$slc),
- (!cast<MUBUF>(opcode # _BOTHEN_exact)
- $vdata,
- (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
- $rsrc, $soffset, (as_i16imm $offset),
- (as_i1imm $glc), (as_i1imm $slc), 0)
- >;
-}
-
-defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store_format, f32, "BUFFER_STORE_FORMAT_X">;
-defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store_format, v2f32, "BUFFER_STORE_FORMAT_XY">;
-defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store_format, v4f32, "BUFFER_STORE_FORMAT_XYZW">;
-defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store, f32, "BUFFER_STORE_DWORD">;
-defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store, v2f32, "BUFFER_STORE_DWORDX2">;
-defm : MUBUF_StoreIntrinsicPat<int_amdgcn_buffer_store, v4f32, "BUFFER_STORE_DWORDX4">;
-
-//===----------------------------------------------------------------------===//
-// buffer_atomic patterns
-//===----------------------------------------------------------------------===//
-multiclass BufferAtomicPatterns<SDPatternOperator name, string opcode> {
- def : Pat<
- (name i32:$vdata_in, v4i32:$rsrc, 0,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$slc),
- (!cast<MUBUF>(opcode # _RTN_OFFSET) $vdata_in, $rsrc, $soffset,
- (as_i16imm $offset), (as_i1imm $slc))
- >;
-
- def : Pat<
- (name i32:$vdata_in, v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$slc),
- (!cast<MUBUF>(opcode # _RTN_IDXEN) $vdata_in, $vindex, $rsrc, $soffset,
- (as_i16imm $offset), (as_i1imm $slc))
- >;
-
- def : Pat<
- (name i32:$vdata_in, v4i32:$rsrc, 0,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$slc),
- (!cast<MUBUF>(opcode # _RTN_OFFEN) $vdata_in, $voffset, $rsrc, $soffset,
- (as_i16imm $offset), (as_i1imm $slc))
- >;
-
- def : Pat<
- (name i32:$vdata_in, v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$slc),
- (!cast<MUBUF>(opcode # _RTN_BOTHEN)
- $vdata_in,
- (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
- $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc))
- >;
-}
-
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_swap, "BUFFER_ATOMIC_SWAP">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_add, "BUFFER_ATOMIC_ADD">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_sub, "BUFFER_ATOMIC_SUB">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_smin, "BUFFER_ATOMIC_SMIN">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_umin, "BUFFER_ATOMIC_UMIN">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_smax, "BUFFER_ATOMIC_SMAX">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_umax, "BUFFER_ATOMIC_UMAX">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_and, "BUFFER_ATOMIC_AND">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_or, "BUFFER_ATOMIC_OR">;
-defm : BufferAtomicPatterns<int_amdgcn_buffer_atomic_xor, "BUFFER_ATOMIC_XOR">;
-
def : Pat<
- (int_amdgcn_buffer_atomic_cmpswap
- i32:$data, i32:$cmp, v4i32:$rsrc, 0,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$slc),
- (EXTRACT_SUBREG
- (BUFFER_ATOMIC_CMPSWAP_RTN_OFFSET
- (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
- $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
- sub0)
+ (int_amdgcn_else i64:$src, bb:$target),
+ (SI_ELSE $src, $target, 0)
>;
-def : Pat<
- (int_amdgcn_buffer_atomic_cmpswap
- i32:$data, i32:$cmp, v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicOffset i32:$soffset, i16:$offset),
- imm:$slc),
- (EXTRACT_SUBREG
- (BUFFER_ATOMIC_CMPSWAP_RTN_IDXEN
- (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
- $vindex, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
- sub0)
->;
-
-def : Pat<
- (int_amdgcn_buffer_atomic_cmpswap
- i32:$data, i32:$cmp, v4i32:$rsrc, 0,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$slc),
- (EXTRACT_SUBREG
- (BUFFER_ATOMIC_CMPSWAP_RTN_OFFEN
- (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
- $voffset, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
- sub0)
->;
-
-def : Pat<
- (int_amdgcn_buffer_atomic_cmpswap
- i32:$data, i32:$cmp, v4i32:$rsrc, i32:$vindex,
- (MUBUFIntrinsicVOffset i32:$soffset, i16:$offset, i32:$voffset),
- imm:$slc),
- (EXTRACT_SUBREG
- (BUFFER_ATOMIC_CMPSWAP_RTN_BOTHEN
- (REG_SEQUENCE VReg_64, $data, sub0, $cmp, sub1),
- (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1),
- $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $slc)),
- sub0)
->;
-
-
-//===----------------------------------------------------------------------===//
-// S_GETREG_B32 Intrinsic Pattern.
-//===----------------------------------------------------------------------===//
def : Pat <
- (int_amdgcn_s_getreg imm:$simm16),
- (S_GETREG_B32 (as_i16imm $simm16))
->;
-
-//===----------------------------------------------------------------------===//
-// DS_SWIZZLE Intrinsic Pattern.
-//===----------------------------------------------------------------------===//
-def : Pat <
- (int_amdgcn_ds_swizzle i32:$src, imm:$offset16),
- (DS_SWIZZLE_B32 $src, (as_i16imm $offset16), (i1 0))
->;
-
-//===----------------------------------------------------------------------===//
-// SMRD Patterns
-//===----------------------------------------------------------------------===//
-
-multiclass SMRD_Pattern <string Instr, ValueType vt> {
-
- // 1. IMM offset
- def : Pat <
- (smrd_load (SMRDImm i64:$sbase, i32:$offset)),
- (vt (!cast<SMRD>(Instr#"_IMM") $sbase, $offset))
- >;
-
- // 2. SGPR offset
- def : Pat <
- (smrd_load (SMRDSgpr i64:$sbase, i32:$offset)),
- (vt (!cast<SMRD>(Instr#"_SGPR") $sbase, $offset))
- >;
-
- def : Pat <
- (smrd_load (SMRDImm32 i64:$sbase, i32:$offset)),
- (vt (!cast<SMRD>(Instr#"_IMM_ci") $sbase, $offset))
- > {
- let Predicates = [isCIOnly];
- }
-}
-
-// Global and constant loads can be selected to either MUBUF or SMRD
-// instructions, but SMRD instructions are faster so we want the instruction
-// selector to prefer those.
-let AddedComplexity = 100 in {
-
-defm : SMRD_Pattern <"S_LOAD_DWORD", i32>;
-defm : SMRD_Pattern <"S_LOAD_DWORDX2", v2i32>;
-defm : SMRD_Pattern <"S_LOAD_DWORDX4", v4i32>;
-defm : SMRD_Pattern <"S_LOAD_DWORDX8", v8i32>;
-defm : SMRD_Pattern <"S_LOAD_DWORDX16", v16i32>;
-
-// 1. Offset as an immediate
-def : Pat <
- (SIload_constant v4i32:$sbase, (SMRDBufferImm i32:$offset)),
- (S_BUFFER_LOAD_DWORD_IMM $sbase, $offset)
->;
-
-// 2. Offset loaded in an 32bit SGPR
-def : Pat <
- (SIload_constant v4i32:$sbase, (SMRDBufferSgpr i32:$offset)),
- (S_BUFFER_LOAD_DWORD_SGPR $sbase, $offset)
->;
-
-let Predicates = [isCI] in {
-
-def : Pat <
- (SIload_constant v4i32:$sbase, (SMRDBufferImm32 i32:$offset)),
- (S_BUFFER_LOAD_DWORD_IMM_ci $sbase, $offset)
->;
-
-} // End Predicates = [isCI]
-
-} // End let AddedComplexity = 10000
-
-//===----------------------------------------------------------------------===//
-// SOP1 Patterns
-//===----------------------------------------------------------------------===//
-
-def : Pat <
- (i64 (ctpop i64:$src)),
- (i64 (REG_SEQUENCE SReg_64,
- (i32 (COPY_TO_REGCLASS (S_BCNT1_I32_B64 $src), SReg_32)), sub0,
- (S_MOV_B32 0), sub1))
->;
-
-def : Pat <
- (i32 (smax i32:$x, (i32 (ineg i32:$x)))),
- (S_ABS_I32 $x)
->;
-
-//===----------------------------------------------------------------------===//
-// SOP2 Patterns
-//===----------------------------------------------------------------------===//
-
-// V_ADD_I32_e32/S_ADD_U32 produces carry in VCC/SCC. For the vector
-// case, the sgpr-copies pass will fix this to use the vector version.
-def : Pat <
- (i32 (addc i32:$src0, i32:$src1)),
- (S_ADD_U32 $src0, $src1)
->;
-
-//===----------------------------------------------------------------------===//
-// SOPP Patterns
-//===----------------------------------------------------------------------===//
-
-def : Pat <
- (int_amdgcn_s_waitcnt i32:$simm16),
- (S_WAITCNT (as_i16imm $simm16))
+ (int_AMDGPU_kilp),
+ (SI_KILL (i32 0xbf800000))
>;
//===----------------------------------------------------------------------===//
@@ -2483,308 +423,79 @@ def : Pat <
} // End Predicates = [UnsafeFPMath]
-//===----------------------------------------------------------------------===//
-// VOP2 Patterns
-//===----------------------------------------------------------------------===//
-
def : Pat <
- (i32 (add (i32 (ctpop i32:$popcnt)), i32:$val)),
- (V_BCNT_U32_B32_e64 $popcnt, $val)
+ (f32 (fpextend f16:$src)),
+ (V_CVT_F32_F16_e32 $src)
>;
def : Pat <
- (i32 (select i1:$src0, i32:$src1, i32:$src2)),
- (V_CNDMASK_B32_e64 $src2, $src1, $src0)
+ (f64 (fpextend f16:$src)),
+ (V_CVT_F64_F32_e32 (V_CVT_F32_F16_e32 $src))
>;
-// Pattern for V_MAC_F32
def : Pat <
- (fmad (VOP3NoMods0 f32:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod),
- (VOP3NoMods f32:$src1, i32:$src1_modifiers),
- (VOP3NoMods f32:$src2, i32:$src2_modifiers)),
- (V_MAC_F32_e64 $src0_modifiers, $src0, $src1_modifiers, $src1,
- $src2_modifiers, $src2, $clamp, $omod)
->;
-
-/********** ======================= **********/
-/********** Image sampling patterns **********/
-/********** ======================= **********/
-
-// Image + sampler
-class SampleRawPattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, i32:$dmask, i32:$unorm,
- i32:$r128, i32:$da, i32:$glc, i32:$slc, i32:$tfe, i32:$lwe),
- (opcode $addr, $rsrc, $sampler,
- (as_i32imm $dmask), (as_i1imm $unorm), (as_i1imm $glc), (as_i1imm $slc),
- (as_i1imm $r128), (as_i1imm $tfe), (as_i1imm $lwe), (as_i1imm $da))
->;
-
-multiclass SampleRawPatterns<SDPatternOperator name, string opcode> {
- def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V1), i32>;
- def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V2), v2i32>;
- def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V4), v4i32>;
- def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V8), v8i32>;
- def : SampleRawPattern<name, !cast<MIMG>(opcode # _V4_V16), v16i32>;
-}
-
-// Image only
-class ImagePattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, imm:$dmask, imm:$unorm,
- imm:$r128, imm:$da, imm:$glc, imm:$slc, imm:$tfe, imm:$lwe),
- (opcode $addr, $rsrc,
- (as_i32imm $dmask), (as_i1imm $unorm), (as_i1imm $glc), (as_i1imm $slc),
- (as_i1imm $r128), (as_i1imm $tfe), (as_i1imm $lwe), (as_i1imm $da))
->;
-
-multiclass ImagePatterns<SDPatternOperator name, string opcode> {
- def : ImagePattern<name, !cast<MIMG>(opcode # _V4_V1), i32>;
- def : ImagePattern<name, !cast<MIMG>(opcode # _V4_V2), v2i32>;
- def : ImagePattern<name, !cast<MIMG>(opcode # _V4_V4), v4i32>;
-}
-
-class ImageLoadPattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, imm:$dmask, imm:$r128, imm:$da, imm:$glc,
- imm:$slc),
- (opcode $addr, $rsrc,
- (as_i32imm $dmask), 1, (as_i1imm $glc), (as_i1imm $slc),
- (as_i1imm $r128), 0, 0, (as_i1imm $da))
->;
-
-multiclass ImageLoadPatterns<SDPatternOperator name, string opcode> {
- def : ImageLoadPattern<name, !cast<MIMG>(opcode # _V4_V1), i32>;
- def : ImageLoadPattern<name, !cast<MIMG>(opcode # _V4_V2), v2i32>;
- def : ImageLoadPattern<name, !cast<MIMG>(opcode # _V4_V4), v4i32>;
-}
-
-class ImageStorePattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
- (name v4f32:$data, vt:$addr, v8i32:$rsrc, i32:$dmask, imm:$r128, imm:$da,
- imm:$glc, imm:$slc),
- (opcode $data, $addr, $rsrc,
- (as_i32imm $dmask), 1, (as_i1imm $glc), (as_i1imm $slc),
- (as_i1imm $r128), 0, 0, (as_i1imm $da))
+ (f16 (fpround f32:$src)),
+ (V_CVT_F16_F32_e32 $src)
>;
-multiclass ImageStorePatterns<SDPatternOperator name, string opcode> {
- def : ImageStorePattern<name, !cast<MIMG>(opcode # _V4_V1), i32>;
- def : ImageStorePattern<name, !cast<MIMG>(opcode # _V4_V2), v2i32>;
- def : ImageStorePattern<name, !cast<MIMG>(opcode # _V4_V4), v4i32>;
-}
-
-class ImageAtomicPattern<SDPatternOperator name, MIMG opcode, ValueType vt> : Pat <
- (name i32:$vdata, vt:$addr, v8i32:$rsrc, imm:$r128, imm:$da, imm:$slc),
- (opcode $vdata, $addr, $rsrc, 1, 1, 1, (as_i1imm $slc), (as_i1imm $r128), 0, 0, (as_i1imm $da))
->;
-
-multiclass ImageAtomicPatterns<SDPatternOperator name, string opcode> {
- def : ImageAtomicPattern<name, !cast<MIMG>(opcode # _V1), i32>;
- def : ImageAtomicPattern<name, !cast<MIMG>(opcode # _V2), v2i32>;
- def : ImageAtomicPattern<name, !cast<MIMG>(opcode # _V4), v4i32>;
-}
-
-class ImageAtomicCmpSwapPattern<MIMG opcode, ValueType vt> : Pat <
- (int_amdgcn_image_atomic_cmpswap i32:$vsrc, i32:$vcmp, vt:$addr, v8i32:$rsrc,
- imm:$r128, imm:$da, imm:$slc),
- (EXTRACT_SUBREG
- (opcode (REG_SEQUENCE VReg_64, $vsrc, sub0, $vcmp, sub1),
- $addr, $rsrc, 3, 1, 1, (as_i1imm $slc), (as_i1imm $r128), 0, 0, (as_i1imm $da)),
- sub0)
->;
-
-// Basic sample
-defm : SampleRawPatterns<int_SI_image_sample, "IMAGE_SAMPLE">;
-defm : SampleRawPatterns<int_SI_image_sample_cl, "IMAGE_SAMPLE_CL">;
-defm : SampleRawPatterns<int_SI_image_sample_d, "IMAGE_SAMPLE_D">;
-defm : SampleRawPatterns<int_SI_image_sample_d_cl, "IMAGE_SAMPLE_D_CL">;
-defm : SampleRawPatterns<int_SI_image_sample_l, "IMAGE_SAMPLE_L">;
-defm : SampleRawPatterns<int_SI_image_sample_b, "IMAGE_SAMPLE_B">;
-defm : SampleRawPatterns<int_SI_image_sample_b_cl, "IMAGE_SAMPLE_B_CL">;
-defm : SampleRawPatterns<int_SI_image_sample_lz, "IMAGE_SAMPLE_LZ">;
-defm : SampleRawPatterns<int_SI_image_sample_cd, "IMAGE_SAMPLE_CD">;
-defm : SampleRawPatterns<int_SI_image_sample_cd_cl, "IMAGE_SAMPLE_CD_CL">;
-
-// Sample with comparison
-defm : SampleRawPatterns<int_SI_image_sample_c, "IMAGE_SAMPLE_C">;
-defm : SampleRawPatterns<int_SI_image_sample_c_cl, "IMAGE_SAMPLE_C_CL">;
-defm : SampleRawPatterns<int_SI_image_sample_c_d, "IMAGE_SAMPLE_C_D">;
-defm : SampleRawPatterns<int_SI_image_sample_c_d_cl, "IMAGE_SAMPLE_C_D_CL">;
-defm : SampleRawPatterns<int_SI_image_sample_c_l, "IMAGE_SAMPLE_C_L">;
-defm : SampleRawPatterns<int_SI_image_sample_c_b, "IMAGE_SAMPLE_C_B">;
-defm : SampleRawPatterns<int_SI_image_sample_c_b_cl, "IMAGE_SAMPLE_C_B_CL">;
-defm : SampleRawPatterns<int_SI_image_sample_c_lz, "IMAGE_SAMPLE_C_LZ">;
-defm : SampleRawPatterns<int_SI_image_sample_c_cd, "IMAGE_SAMPLE_C_CD">;
-defm : SampleRawPatterns<int_SI_image_sample_c_cd_cl, "IMAGE_SAMPLE_C_CD_CL">;
-
-// Sample with offsets
-defm : SampleRawPatterns<int_SI_image_sample_o, "IMAGE_SAMPLE_O">;
-defm : SampleRawPatterns<int_SI_image_sample_cl_o, "IMAGE_SAMPLE_CL_O">;
-defm : SampleRawPatterns<int_SI_image_sample_d_o, "IMAGE_SAMPLE_D_O">;
-defm : SampleRawPatterns<int_SI_image_sample_d_cl_o, "IMAGE_SAMPLE_D_CL_O">;
-defm : SampleRawPatterns<int_SI_image_sample_l_o, "IMAGE_SAMPLE_L_O">;
-defm : SampleRawPatterns<int_SI_image_sample_b_o, "IMAGE_SAMPLE_B_O">;
-defm : SampleRawPatterns<int_SI_image_sample_b_cl_o, "IMAGE_SAMPLE_B_CL_O">;
-defm : SampleRawPatterns<int_SI_image_sample_lz_o, "IMAGE_SAMPLE_LZ_O">;
-defm : SampleRawPatterns<int_SI_image_sample_cd_o, "IMAGE_SAMPLE_CD_O">;
-defm : SampleRawPatterns<int_SI_image_sample_cd_cl_o, "IMAGE_SAMPLE_CD_CL_O">;
-
-// Sample with comparison and offsets
-defm : SampleRawPatterns<int_SI_image_sample_c_o, "IMAGE_SAMPLE_C_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_cl_o, "IMAGE_SAMPLE_C_CL_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_d_o, "IMAGE_SAMPLE_C_D_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_d_cl_o, "IMAGE_SAMPLE_C_D_CL_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_l_o, "IMAGE_SAMPLE_C_L_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_b_o, "IMAGE_SAMPLE_C_B_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_b_cl_o, "IMAGE_SAMPLE_C_B_CL_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_lz_o, "IMAGE_SAMPLE_C_LZ_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_cd_o, "IMAGE_SAMPLE_C_CD_O">;
-defm : SampleRawPatterns<int_SI_image_sample_c_cd_cl_o, "IMAGE_SAMPLE_C_CD_CL_O">;
-
-// Gather opcodes
-// Only the variants which make sense are defined.
-def : SampleRawPattern<int_SI_gather4, IMAGE_GATHER4_V4_V2, v2i32>;
-def : SampleRawPattern<int_SI_gather4, IMAGE_GATHER4_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_cl, IMAGE_GATHER4_CL_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_l, IMAGE_GATHER4_L_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_b, IMAGE_GATHER4_B_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_b_cl, IMAGE_GATHER4_B_CL_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_b_cl, IMAGE_GATHER4_B_CL_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_lz, IMAGE_GATHER4_LZ_V4_V2, v2i32>;
-def : SampleRawPattern<int_SI_gather4_lz, IMAGE_GATHER4_LZ_V4_V4, v4i32>;
-
-def : SampleRawPattern<int_SI_gather4_c, IMAGE_GATHER4_C_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_c_cl, IMAGE_GATHER4_C_CL_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_c_cl, IMAGE_GATHER4_C_CL_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_l, IMAGE_GATHER4_C_L_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_c_l, IMAGE_GATHER4_C_L_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_b, IMAGE_GATHER4_C_B_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_c_b, IMAGE_GATHER4_C_B_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_b_cl, IMAGE_GATHER4_C_B_CL_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_lz, IMAGE_GATHER4_C_LZ_V4_V4, v4i32>;
-
-def : SampleRawPattern<int_SI_gather4_o, IMAGE_GATHER4_O_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_cl_o, IMAGE_GATHER4_CL_O_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_cl_o, IMAGE_GATHER4_CL_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_l_o, IMAGE_GATHER4_L_O_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_l_o, IMAGE_GATHER4_L_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_b_o, IMAGE_GATHER4_B_O_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_b_o, IMAGE_GATHER4_B_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_b_cl_o, IMAGE_GATHER4_B_CL_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_lz_o, IMAGE_GATHER4_LZ_O_V4_V4, v4i32>;
-
-def : SampleRawPattern<int_SI_gather4_c_o, IMAGE_GATHER4_C_O_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_c_o, IMAGE_GATHER4_C_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_cl_o, IMAGE_GATHER4_C_CL_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_l_o, IMAGE_GATHER4_C_L_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_b_o, IMAGE_GATHER4_C_B_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_b_cl_o, IMAGE_GATHER4_C_B_CL_O_V4_V8, v8i32>;
-def : SampleRawPattern<int_SI_gather4_c_lz_o, IMAGE_GATHER4_C_LZ_O_V4_V4, v4i32>;
-def : SampleRawPattern<int_SI_gather4_c_lz_o, IMAGE_GATHER4_C_LZ_O_V4_V8, v8i32>;
-
-def : SampleRawPattern<int_SI_getlod, IMAGE_GET_LOD_V4_V1, i32>;
-def : SampleRawPattern<int_SI_getlod, IMAGE_GET_LOD_V4_V2, v2i32>;
-def : SampleRawPattern<int_SI_getlod, IMAGE_GET_LOD_V4_V4, v4i32>;
-
-def : ImagePattern<int_SI_getresinfo, IMAGE_GET_RESINFO_V4_V1, i32>;
-defm : ImagePatterns<int_SI_image_load, "IMAGE_LOAD">;
-defm : ImagePatterns<int_SI_image_load_mip, "IMAGE_LOAD_MIP">;
-defm : ImageLoadPatterns<int_amdgcn_image_load, "IMAGE_LOAD">;
-defm : ImageLoadPatterns<int_amdgcn_image_load_mip, "IMAGE_LOAD_MIP">;
-defm : ImageStorePatterns<int_amdgcn_image_store, "IMAGE_STORE">;
-defm : ImageStorePatterns<int_amdgcn_image_store_mip, "IMAGE_STORE_MIP">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_swap, "IMAGE_ATOMIC_SWAP">;
-def : ImageAtomicCmpSwapPattern<IMAGE_ATOMIC_CMPSWAP_V1, i32>;
-def : ImageAtomicCmpSwapPattern<IMAGE_ATOMIC_CMPSWAP_V2, v2i32>;
-def : ImageAtomicCmpSwapPattern<IMAGE_ATOMIC_CMPSWAP_V4, v4i32>;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_add, "IMAGE_ATOMIC_ADD">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_sub, "IMAGE_ATOMIC_SUB">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_smin, "IMAGE_ATOMIC_SMIN">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_umin, "IMAGE_ATOMIC_UMIN">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_smax, "IMAGE_ATOMIC_SMAX">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_umax, "IMAGE_ATOMIC_UMAX">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_and, "IMAGE_ATOMIC_AND">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_or, "IMAGE_ATOMIC_OR">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_xor, "IMAGE_ATOMIC_XOR">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_inc, "IMAGE_ATOMIC_INC">;
-defm : ImageAtomicPatterns<int_amdgcn_image_atomic_dec, "IMAGE_ATOMIC_DEC">;
-
-/* SIsample for simple 1D texture lookup */
def : Pat <
- (SIsample i32:$addr, v8i32:$rsrc, v4i32:$sampler, imm),
- (IMAGE_SAMPLE_V4_V1 $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 0)
+ (f16 (fpround f64:$src)),
+ (V_CVT_F16_F32_e32 (V_CVT_F32_F64_e32 $src))
>;
-class SamplePattern<SDNode name, MIMG opcode, ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, imm),
- (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 0)
->;
-
-class SampleRectPattern<SDNode name, MIMG opcode, ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_RECT),
- (opcode $addr, $rsrc, $sampler, 0xf, 1, 0, 0, 0, 0, 0, 0)
+def : Pat <
+ (i32 (fp_to_sint f16:$src)),
+ (V_CVT_I32_F32_e32 (V_CVT_F32_F16_e32 $src))
>;
-class SampleArrayPattern<SDNode name, MIMG opcode, ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_ARRAY),
- (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 1)
+def : Pat <
+ (i32 (fp_to_uint f16:$src)),
+ (V_CVT_U32_F32_e32 (V_CVT_F32_F16_e32 $src))
>;
-class SampleShadowPattern<SDNode name, MIMG opcode,
- ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_SHADOW),
- (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 0)
+def : Pat <
+ (f16 (sint_to_fp i32:$src)),
+ (V_CVT_F16_F32_e32 (V_CVT_F32_I32_e32 $src))
>;
-class SampleShadowArrayPattern<SDNode name, MIMG opcode,
- ValueType vt> : Pat <
- (name vt:$addr, v8i32:$rsrc, v4i32:$sampler, TEX_SHADOW_ARRAY),
- (opcode $addr, $rsrc, $sampler, 0xf, 0, 0, 0, 0, 0, 0, 1)
+def : Pat <
+ (f16 (uint_to_fp i32:$src)),
+ (V_CVT_F16_F32_e32 (V_CVT_F32_U32_e32 $src))
>;
-/* SIsample* for texture lookups consuming more address parameters */
-multiclass SamplePatterns<MIMG sample, MIMG sample_c, MIMG sample_l,
- MIMG sample_c_l, MIMG sample_b, MIMG sample_c_b,
-MIMG sample_d, MIMG sample_c_d, ValueType addr_type> {
- def : SamplePattern <SIsample, sample, addr_type>;
- def : SampleRectPattern <SIsample, sample, addr_type>;
- def : SampleArrayPattern <SIsample, sample, addr_type>;
- def : SampleShadowPattern <SIsample, sample_c, addr_type>;
- def : SampleShadowArrayPattern <SIsample, sample_c, addr_type>;
+//===----------------------------------------------------------------------===//
+// VOP2 Patterns
+//===----------------------------------------------------------------------===//
- def : SamplePattern <SIsamplel, sample_l, addr_type>;
- def : SampleArrayPattern <SIsamplel, sample_l, addr_type>;
- def : SampleShadowPattern <SIsamplel, sample_c_l, addr_type>;
- def : SampleShadowArrayPattern <SIsamplel, sample_c_l, addr_type>;
+multiclass FMADPat <ValueType vt, Instruction inst> {
+ def : Pat <
+ (vt (fmad (VOP3NoMods0 vt:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod),
+ (VOP3NoMods vt:$src1, i32:$src1_modifiers),
+ (VOP3NoMods vt:$src2, i32:$src2_modifiers))),
+ (inst $src0_modifiers, $src0, $src1_modifiers, $src1,
+ $src2_modifiers, $src2, $clamp, $omod)
+ >;
+}
- def : SamplePattern <SIsampleb, sample_b, addr_type>;
- def : SampleArrayPattern <SIsampleb, sample_b, addr_type>;
- def : SampleShadowPattern <SIsampleb, sample_c_b, addr_type>;
- def : SampleShadowArrayPattern <SIsampleb, sample_c_b, addr_type>;
+defm : FMADPat <f16, V_MAC_F16_e64>;
+defm : FMADPat <f32, V_MAC_F32_e64>;
- def : SamplePattern <SIsampled, sample_d, addr_type>;
- def : SampleArrayPattern <SIsampled, sample_d, addr_type>;
- def : SampleShadowPattern <SIsampled, sample_c_d, addr_type>;
- def : SampleShadowArrayPattern <SIsampled, sample_c_d, addr_type>;
+multiclass SelectPat <ValueType vt, Instruction inst> {
+ def : Pat <
+ (vt (select i1:$src0, vt:$src1, vt:$src2)),
+ (inst $src2, $src1, $src0)
+ >;
}
-defm : SamplePatterns<IMAGE_SAMPLE_V4_V2, IMAGE_SAMPLE_C_V4_V2,
- IMAGE_SAMPLE_L_V4_V2, IMAGE_SAMPLE_C_L_V4_V2,
- IMAGE_SAMPLE_B_V4_V2, IMAGE_SAMPLE_C_B_V4_V2,
- IMAGE_SAMPLE_D_V4_V2, IMAGE_SAMPLE_C_D_V4_V2,
- v2i32>;
-defm : SamplePatterns<IMAGE_SAMPLE_V4_V4, IMAGE_SAMPLE_C_V4_V4,
- IMAGE_SAMPLE_L_V4_V4, IMAGE_SAMPLE_C_L_V4_V4,
- IMAGE_SAMPLE_B_V4_V4, IMAGE_SAMPLE_C_B_V4_V4,
- IMAGE_SAMPLE_D_V4_V4, IMAGE_SAMPLE_C_D_V4_V4,
- v4i32>;
-defm : SamplePatterns<IMAGE_SAMPLE_V4_V8, IMAGE_SAMPLE_C_V4_V8,
- IMAGE_SAMPLE_L_V4_V8, IMAGE_SAMPLE_C_L_V4_V8,
- IMAGE_SAMPLE_B_V4_V8, IMAGE_SAMPLE_C_B_V4_V8,
- IMAGE_SAMPLE_D_V4_V8, IMAGE_SAMPLE_C_D_V4_V8,
- v8i32>;
-defm : SamplePatterns<IMAGE_SAMPLE_V4_V16, IMAGE_SAMPLE_C_V4_V16,
- IMAGE_SAMPLE_L_V4_V16, IMAGE_SAMPLE_C_L_V4_V16,
- IMAGE_SAMPLE_B_V4_V16, IMAGE_SAMPLE_C_B_V4_V16,
- IMAGE_SAMPLE_D_V4_V16, IMAGE_SAMPLE_C_D_V4_V16,
- v16i32>;
+defm : SelectPat <i16, V_CNDMASK_B32_e64>;
+defm : SelectPat <i32, V_CNDMASK_B32_e64>;
+defm : SelectPat <f16, V_CNDMASK_B32_e64>;
+defm : SelectPat <f32, V_CNDMASK_B32_e64>;
+
+def : Pat <
+ (i32 (add (i32 (ctpop i32:$popcnt)), i32:$val)),
+ (V_BCNT_U32_B32_e64 $popcnt, $val)
+>;
/********** ============================================ **********/
/********** Extraction, Insertion, Building and Casting **********/
@@ -2856,6 +567,12 @@ foreach Index = 0-15 in {
// FIXME: Why do only some of these type combinations for SReg and
// VReg?
+// 16-bit bitcast
+def : BitConvert <i16, f16, VGPR_32>;
+def : BitConvert <f16, i16, VGPR_32>;
+def : BitConvert <i16, f16, SReg_32>;
+def : BitConvert <f16, i16, SReg_32>;
+
// 32-bit bitcast
def : BitConvert <i32, f32, VGPR_32>;
def : BitConvert <f32, i32, VGPR_32>;
@@ -2905,7 +622,7 @@ def : BitConvert <v16f32, v16i32, VReg_512>;
def : Pat <
(AMDGPUclamp (VOP3Mods0Clamp f32:$src0, i32:$src0_modifiers, i32:$omod),
(f32 FP_ZERO), (f32 FP_ONE)),
- (V_ADD_F32_e64 $src0_modifiers, $src0, 0, 0, 1, $omod)
+ (V_ADD_F32_e64 $src0_modifiers, $src0, 0, (i32 0), 1, $omod)
>;
/********** ================================ **********/
@@ -2916,7 +633,7 @@ def : Pat <
def : Pat <
(fneg (fabs f32:$src)),
- (S_OR_B32 $src, 0x80000000) // Set sign bit
+ (S_OR_B32 $src, (S_MOV_B32(i32 0x80000000))) // Set sign bit
>;
// FIXME: Should use S_OR_B32
@@ -2925,19 +642,19 @@ def : Pat <
(REG_SEQUENCE VReg_64,
(i32 (EXTRACT_SUBREG f64:$src, sub0)),
sub0,
- (V_OR_B32_e32 (EXTRACT_SUBREG f64:$src, sub1),
- (V_MOV_B32_e32 0x80000000)), // Set sign bit.
+ (V_OR_B32_e32 (i32 (EXTRACT_SUBREG f64:$src, sub1)),
+ (V_MOV_B32_e32 (i32 0x80000000))), // Set sign bit.
sub1)
>;
def : Pat <
(fabs f32:$src),
- (V_AND_B32_e32 $src, (V_MOV_B32_e32 0x7fffffff))
+ (V_AND_B32_e64 $src, (V_MOV_B32_e32 (i32 0x7fffffff)))
>;
def : Pat <
(fneg f32:$src),
- (V_XOR_B32_e32 $src, (V_MOV_B32_e32 0x80000000))
+ (V_XOR_B32_e32 $src, (V_MOV_B32_e32 (i32 0x80000000)))
>;
def : Pat <
@@ -2945,8 +662,8 @@ def : Pat <
(REG_SEQUENCE VReg_64,
(i32 (EXTRACT_SUBREG f64:$src, sub0)),
sub0,
- (V_AND_B32_e32 (EXTRACT_SUBREG f64:$src, sub1),
- (V_MOV_B32_e32 0x7fffffff)), // Set sign bit.
+ (V_AND_B32_e64 (i32 (EXTRACT_SUBREG f64:$src, sub1)),
+ (V_MOV_B32_e32 (i32 0x7fffffff))), // Set sign bit.
sub1)
>;
@@ -2955,33 +672,66 @@ def : Pat <
(REG_SEQUENCE VReg_64,
(i32 (EXTRACT_SUBREG f64:$src, sub0)),
sub0,
- (V_XOR_B32_e32 (EXTRACT_SUBREG f64:$src, sub1),
- (V_MOV_B32_e32 0x80000000)),
+ (V_XOR_B32_e32 (i32 (EXTRACT_SUBREG f64:$src, sub1)),
+ (i32 (V_MOV_B32_e32 (i32 0x80000000)))),
sub1)
>;
+def : Pat <
+ (fneg f16:$src),
+ (V_XOR_B32_e32 $src, (V_MOV_B32_e32 (i32 0x00008000)))
+>;
+
+def : Pat <
+ (fabs f16:$src),
+ (V_AND_B32_e64 $src, (V_MOV_B32_e32 (i32 0x00007fff)))
+>;
+
+def : Pat <
+ (fneg (fabs f16:$src)),
+ (S_OR_B32 $src, (S_MOV_B32 (i32 0x00008000))) // Set sign bit
+>;
+
/********** ================== **********/
/********** Immediate Patterns **********/
/********** ================== **********/
def : Pat <
- (SGPRImm<(i32 imm)>:$imm),
- (S_MOV_B32 imm:$imm)
+ (VGPRImm<(i32 imm)>:$imm),
+ (V_MOV_B32_e32 imm:$imm)
>;
def : Pat <
- (SGPRImm<(f32 fpimm)>:$imm),
- (S_MOV_B32 (f32 (bitcast_fpimm_to_i32 $imm)))
+ (VGPRImm<(f32 fpimm)>:$imm),
+ (V_MOV_B32_e32 (f32 (bitcast_fpimm_to_i32 $imm)))
>;
def : Pat <
(i32 imm:$imm),
- (V_MOV_B32_e32 imm:$imm)
+ (S_MOV_B32 imm:$imm)
+>;
+
+// FIXME: Workaround for ordering issue with peephole optimizer where
+// a register class copy interferes with immediate folding. Should
+// use s_mov_b32, which can be shrunk to s_movk_i32
+def : Pat <
+ (VGPRImm<(f16 fpimm)>:$imm),
+ (V_MOV_B32_e32 (f16 (bitcast_fpimm_to_i32 $imm)))
>;
def : Pat <
(f32 fpimm:$imm),
- (V_MOV_B32_e32 (f32 (bitcast_fpimm_to_i32 $imm)))
+ (S_MOV_B32 (f32 (bitcast_fpimm_to_i32 $imm)))
+>;
+
+def : Pat <
+ (f16 fpimm:$imm),
+ (S_MOV_B32 (i32 (bitcast_fpimm_to_i32 $imm)))
+>;
+
+def : Pat <
+ (i32 frameindex:$fi),
+ (V_MOV_B32_e32 (i32 (frameindex_to_targetframeindex $fi)))
>;
def : Pat <
@@ -3011,21 +761,21 @@ def : POW_Common <V_LOG_F32_e32, V_EXP_F32_e32, V_MUL_LEGACY_F32_e32>;
def : Pat <
(int_AMDGPU_cube v4f32:$src),
(REG_SEQUENCE VReg_128,
- (V_CUBETC_F32 0 /* src0_modifiers */, (EXTRACT_SUBREG $src, sub0),
- 0 /* src1_modifiers */, (EXTRACT_SUBREG $src, sub1),
- 0 /* src2_modifiers */, (EXTRACT_SUBREG $src, sub2),
+ (V_CUBETC_F32 0 /* src0_modifiers */, (f32 (EXTRACT_SUBREG $src, sub0)),
+ 0 /* src1_modifiers */, (f32 (EXTRACT_SUBREG $src, sub1)),
+ 0 /* src2_modifiers */, (f32 (EXTRACT_SUBREG $src, sub2)),
0 /* clamp */, 0 /* omod */), sub0,
- (V_CUBESC_F32 0 /* src0_modifiers */, (EXTRACT_SUBREG $src, sub0),
- 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub1),
- 0 /* src2_modifiers */,(EXTRACT_SUBREG $src, sub2),
+ (V_CUBESC_F32 0 /* src0_modifiers */, (f32 (EXTRACT_SUBREG $src, sub0)),
+ 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub1)),
+ 0 /* src2_modifiers */,(f32 (EXTRACT_SUBREG $src, sub2)),
0 /* clamp */, 0 /* omod */), sub1,
- (V_CUBEMA_F32 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub0),
- 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub1),
- 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub2),
+ (V_CUBEMA_F32 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub0)),
+ 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub1)),
+ 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub2)),
0 /* clamp */, 0 /* omod */), sub2,
- (V_CUBEID_F32 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub0),
- 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub1),
- 0 /* src1_modifiers */,(EXTRACT_SUBREG $src, sub2),
+ (V_CUBEID_F32 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub0)),
+ 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub1)),
+ 0 /* src1_modifiers */,(f32 (EXTRACT_SUBREG $src, sub2)),
0 /* clamp */, 0 /* omod */), sub3)
>;
@@ -3042,17 +792,11 @@ class Ext32Pat <SDNode ext> : Pat <
def : Ext32Pat <zext>;
def : Ext32Pat <anyext>;
-// Offset in an 32-bit VGPR
-def : Pat <
- (SIload_constant v4i32:$sbase, i32:$voff),
- (BUFFER_LOAD_DWORD_OFFEN $voff, $sbase, 0, 0, 0, 0, 0)
->;
-
// The multiplication scales from [0,1] to the unsigned integer range
def : Pat <
(AMDGPUurecip i32:$src0),
(V_CVT_U32_F32_e32
- (V_MUL_F32_e32 CONST.FP_UINT_MAX_PLUS_1,
+ (V_MUL_F32_e32 (i32 CONST.FP_UINT_MAX_PLUS_1),
(V_RCP_IFLAG_F32_e32 (V_CVT_F32_U32_e32 $src0))))
>;
@@ -3066,245 +810,8 @@ def : UMad24Pat<V_MAD_U32_U24>;
defm : BFIPatterns <V_BFI_B32, S_MOV_B32, SReg_64>;
def : ROTRPattern <V_ALIGNBIT_B32>;
-/********** ======================= **********/
-/********** Load/Store Patterns **********/
-/********** ======================= **********/
-
-class DSReadPat <DS inst, ValueType vt, PatFrag frag> : Pat <
- (vt (frag (DS1Addr1Offset i32:$ptr, i32:$offset))),
- (inst $ptr, (as_i16imm $offset), (i1 0))
->;
-
-def : DSReadPat <DS_READ_I8, i32, si_sextload_local_i8>;
-def : DSReadPat <DS_READ_U8, i32, si_az_extload_local_i8>;
-def : DSReadPat <DS_READ_I16, i32, si_sextload_local_i16>;
-def : DSReadPat <DS_READ_U16, i32, si_az_extload_local_i16>;
-def : DSReadPat <DS_READ_B32, i32, si_load_local>;
-
-let AddedComplexity = 100 in {
-
-def : DSReadPat <DS_READ_B64, v2i32, si_load_local_align8>;
-
-} // End AddedComplexity = 100
-
-def : Pat <
- (v2i32 (si_load_local (DS64Bit4ByteAligned i32:$ptr, i8:$offset0,
- i8:$offset1))),
- (DS_READ2_B32 $ptr, $offset0, $offset1, (i1 0))
->;
-
-class DSWritePat <DS inst, ValueType vt, PatFrag frag> : Pat <
- (frag vt:$value, (DS1Addr1Offset i32:$ptr, i32:$offset)),
- (inst $ptr, $value, (as_i16imm $offset), (i1 0))
->;
-
-def : DSWritePat <DS_WRITE_B8, i32, si_truncstore_local_i8>;
-def : DSWritePat <DS_WRITE_B16, i32, si_truncstore_local_i16>;
-def : DSWritePat <DS_WRITE_B32, i32, si_store_local>;
-
-let AddedComplexity = 100 in {
-
-def : DSWritePat <DS_WRITE_B64, v2i32, si_store_local_align8>;
-} // End AddedComplexity = 100
-
-def : Pat <
- (si_store_local v2i32:$value, (DS64Bit4ByteAligned i32:$ptr, i8:$offset0,
- i8:$offset1)),
- (DS_WRITE2_B32 $ptr, (EXTRACT_SUBREG $value, sub0),
- (EXTRACT_SUBREG $value, sub1), $offset0, $offset1,
- (i1 0))
->;
-
-class DSAtomicRetPat<DS inst, ValueType vt, PatFrag frag> : Pat <
- (frag (DS1Addr1Offset i32:$ptr, i32:$offset), vt:$value),
- (inst $ptr, $value, (as_i16imm $offset), (i1 0))
->;
-
-class DSAtomicCmpXChg <DS inst, ValueType vt, PatFrag frag> : Pat <
- (frag (DS1Addr1Offset i32:$ptr, i32:$offset), vt:$cmp, vt:$swap),
- (inst $ptr, $cmp, $swap, (as_i16imm $offset), (i1 0))
->;
-
-
-// 32-bit atomics.
-def : DSAtomicRetPat<DS_WRXCHG_RTN_B32, i32, si_atomic_swap_local>;
-def : DSAtomicRetPat<DS_ADD_RTN_U32, i32, si_atomic_load_add_local>;
-def : DSAtomicRetPat<DS_SUB_RTN_U32, i32, si_atomic_load_sub_local>;
-def : DSAtomicRetPat<DS_INC_RTN_U32, i32, si_atomic_inc_local>;
-def : DSAtomicRetPat<DS_DEC_RTN_U32, i32, si_atomic_dec_local>;
-def : DSAtomicRetPat<DS_AND_RTN_B32, i32, si_atomic_load_and_local>;
-def : DSAtomicRetPat<DS_OR_RTN_B32, i32, si_atomic_load_or_local>;
-def : DSAtomicRetPat<DS_XOR_RTN_B32, i32, si_atomic_load_xor_local>;
-def : DSAtomicRetPat<DS_MIN_RTN_I32, i32, si_atomic_load_min_local>;
-def : DSAtomicRetPat<DS_MAX_RTN_I32, i32, si_atomic_load_max_local>;
-def : DSAtomicRetPat<DS_MIN_RTN_U32, i32, si_atomic_load_umin_local>;
-def : DSAtomicRetPat<DS_MAX_RTN_U32, i32, si_atomic_load_umax_local>;
-def : DSAtomicCmpXChg<DS_CMPST_RTN_B32, i32, si_atomic_cmp_swap_32_local>;
-
-// 64-bit atomics.
-def : DSAtomicRetPat<DS_WRXCHG_RTN_B64, i64, si_atomic_swap_local>;
-def : DSAtomicRetPat<DS_ADD_RTN_U64, i64, si_atomic_load_add_local>;
-def : DSAtomicRetPat<DS_SUB_RTN_U64, i64, si_atomic_load_sub_local>;
-def : DSAtomicRetPat<DS_INC_RTN_U64, i64, si_atomic_inc_local>;
-def : DSAtomicRetPat<DS_DEC_RTN_U64, i64, si_atomic_dec_local>;
-def : DSAtomicRetPat<DS_AND_RTN_B64, i64, si_atomic_load_and_local>;
-def : DSAtomicRetPat<DS_OR_RTN_B64, i64, si_atomic_load_or_local>;
-def : DSAtomicRetPat<DS_XOR_RTN_B64, i64, si_atomic_load_xor_local>;
-def : DSAtomicRetPat<DS_MIN_RTN_I64, i64, si_atomic_load_min_local>;
-def : DSAtomicRetPat<DS_MAX_RTN_I64, i64, si_atomic_load_max_local>;
-def : DSAtomicRetPat<DS_MIN_RTN_U64, i64, si_atomic_load_umin_local>;
-def : DSAtomicRetPat<DS_MAX_RTN_U64, i64, si_atomic_load_umax_local>;
-
-def : DSAtomicCmpXChg<DS_CMPST_RTN_B64, i64, si_atomic_cmp_swap_64_local>;
-
-
-//===----------------------------------------------------------------------===//
-// MUBUF Patterns
-//===----------------------------------------------------------------------===//
-
-class MUBUFLoad_Pattern <MUBUF Instr_ADDR64, ValueType vt,
- PatFrag constant_ld> : Pat <
- (vt (constant_ld (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
- i16:$offset, i1:$glc, i1:$slc, i1:$tfe))),
- (Instr_ADDR64 $vaddr, $srsrc, $soffset, $offset, $glc, $slc, $tfe)
- >;
-
-multiclass MUBUFLoad_Atomic_Pattern <MUBUF Instr_ADDR64, MUBUF Instr_OFFSET,
- ValueType vt, PatFrag atomic_ld> {
- def : Pat <
- (vt (atomic_ld (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
- i16:$offset, i1:$slc))),
- (Instr_ADDR64 $vaddr, $srsrc, $soffset, $offset, 1, $slc, 0)
- >;
-
- def : Pat <
- (vt (atomic_ld (MUBUFOffsetNoGLC v4i32:$rsrc, i32:$soffset, i16:$offset))),
- (Instr_OFFSET $rsrc, $soffset, (as_i16imm $offset), 1, 0, 0)
- >;
-}
-
-let Predicates = [isSICI] in {
-def : MUBUFLoad_Pattern <BUFFER_LOAD_SBYTE_ADDR64, i32, sextloadi8_constant>;
-def : MUBUFLoad_Pattern <BUFFER_LOAD_UBYTE_ADDR64, i32, az_extloadi8_constant>;
-def : MUBUFLoad_Pattern <BUFFER_LOAD_SSHORT_ADDR64, i32, sextloadi16_constant>;
-def : MUBUFLoad_Pattern <BUFFER_LOAD_USHORT_ADDR64, i32, az_extloadi16_constant>;
-
-defm : MUBUFLoad_Atomic_Pattern <BUFFER_LOAD_DWORD_ADDR64, BUFFER_LOAD_DWORD_OFFSET, i32, mubuf_load_atomic>;
-defm : MUBUFLoad_Atomic_Pattern <BUFFER_LOAD_DWORDX2_ADDR64, BUFFER_LOAD_DWORDX2_OFFSET, i64, mubuf_load_atomic>;
-} // End Predicates = [isSICI]
-
-class MUBUFScratchLoadPat <MUBUF Instr, ValueType vt, PatFrag ld> : Pat <
- (vt (ld (MUBUFScratch v4i32:$srsrc, i32:$vaddr,
- i32:$soffset, u16imm:$offset))),
- (Instr $vaddr, $srsrc, $soffset, $offset, 0, 0, 0)
->;
-
-def : MUBUFScratchLoadPat <BUFFER_LOAD_SBYTE_OFFEN, i32, sextloadi8_private>;
-def : MUBUFScratchLoadPat <BUFFER_LOAD_UBYTE_OFFEN, i32, extloadi8_private>;
-def : MUBUFScratchLoadPat <BUFFER_LOAD_SSHORT_OFFEN, i32, sextloadi16_private>;
-def : MUBUFScratchLoadPat <BUFFER_LOAD_USHORT_OFFEN, i32, extloadi16_private>;
-def : MUBUFScratchLoadPat <BUFFER_LOAD_DWORD_OFFEN, i32, load_private>;
-def : MUBUFScratchLoadPat <BUFFER_LOAD_DWORDX2_OFFEN, v2i32, load_private>;
-def : MUBUFScratchLoadPat <BUFFER_LOAD_DWORDX4_OFFEN, v4i32, load_private>;
-
-// BUFFER_LOAD_DWORD*, addr64=0
-multiclass MUBUF_Load_Dword <ValueType vt, MUBUF offset, MUBUF offen, MUBUF idxen,
- MUBUF bothen> {
-
- def : Pat <
- (vt (int_SI_buffer_load_dword v4i32:$rsrc, (i32 imm), i32:$soffset,
- imm:$offset, 0, 0, imm:$glc, imm:$slc,
- imm:$tfe)),
- (offset $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc),
- (as_i1imm $slc), (as_i1imm $tfe))
- >;
-
- def : Pat <
- (vt (int_SI_buffer_load_dword v4i32:$rsrc, i32:$vaddr, i32:$soffset,
- imm:$offset, 1, 0, imm:$glc, imm:$slc,
- imm:$tfe)),
- (offen $vaddr, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc), (as_i1imm $slc),
- (as_i1imm $tfe))
- >;
-
- def : Pat <
- (vt (int_SI_buffer_load_dword v4i32:$rsrc, i32:$vaddr, i32:$soffset,
- imm:$offset, 0, 1, imm:$glc, imm:$slc,
- imm:$tfe)),
- (idxen $vaddr, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc),
- (as_i1imm $slc), (as_i1imm $tfe))
- >;
-
- def : Pat <
- (vt (int_SI_buffer_load_dword v4i32:$rsrc, v2i32:$vaddr, i32:$soffset,
- imm:$offset, 1, 1, imm:$glc, imm:$slc,
- imm:$tfe)),
- (bothen $vaddr, $rsrc, $soffset, (as_i16imm $offset), (as_i1imm $glc), (as_i1imm $slc),
- (as_i1imm $tfe))
- >;
-}
-
-defm : MUBUF_Load_Dword <i32, BUFFER_LOAD_DWORD_OFFSET, BUFFER_LOAD_DWORD_OFFEN,
- BUFFER_LOAD_DWORD_IDXEN, BUFFER_LOAD_DWORD_BOTHEN>;
-defm : MUBUF_Load_Dword <v2i32, BUFFER_LOAD_DWORDX2_OFFSET, BUFFER_LOAD_DWORDX2_OFFEN,
- BUFFER_LOAD_DWORDX2_IDXEN, BUFFER_LOAD_DWORDX2_BOTHEN>;
-defm : MUBUF_Load_Dword <v4i32, BUFFER_LOAD_DWORDX4_OFFSET, BUFFER_LOAD_DWORDX4_OFFEN,
- BUFFER_LOAD_DWORDX4_IDXEN, BUFFER_LOAD_DWORDX4_BOTHEN>;
-
-multiclass MUBUFStore_Atomic_Pattern <MUBUF Instr_ADDR64, MUBUF Instr_OFFSET,
- ValueType vt, PatFrag atomic_st> {
- // Store follows atomic op convention so address is forst
- def : Pat <
- (atomic_st (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset,
- i16:$offset, i1:$slc), vt:$val),
- (Instr_ADDR64 $val, $vaddr, $srsrc, $soffset, $offset, 1, $slc, 0)
- >;
-
- def : Pat <
- (atomic_st (MUBUFOffsetNoGLC v4i32:$rsrc, i32:$soffset, i16:$offset), vt:$val),
- (Instr_OFFSET $val, $rsrc, $soffset, (as_i16imm $offset), 1, 0, 0)
- >;
-}
-let Predicates = [isSICI] in {
-defm : MUBUFStore_Atomic_Pattern <BUFFER_STORE_DWORD_ADDR64, BUFFER_STORE_DWORD_OFFSET, i32, global_store_atomic>;
-defm : MUBUFStore_Atomic_Pattern <BUFFER_STORE_DWORDX2_ADDR64, BUFFER_STORE_DWORDX2_OFFSET, i64, global_store_atomic>;
-} // End Predicates = [isSICI]
-
-class MUBUFScratchStorePat <MUBUF Instr, ValueType vt, PatFrag st> : Pat <
- (st vt:$value, (MUBUFScratch v4i32:$srsrc, i32:$vaddr, i32:$soffset,
- u16imm:$offset)),
- (Instr $value, $vaddr, $srsrc, $soffset, $offset, 0, 0, 0)
->;
-
-def : MUBUFScratchStorePat <BUFFER_STORE_BYTE_OFFEN, i32, truncstorei8_private>;
-def : MUBUFScratchStorePat <BUFFER_STORE_SHORT_OFFEN, i32, truncstorei16_private>;
-def : MUBUFScratchStorePat <BUFFER_STORE_DWORD_OFFEN, i32, store_private>;
-def : MUBUFScratchStorePat <BUFFER_STORE_DWORDX2_OFFEN, v2i32, store_private>;
-def : MUBUFScratchStorePat <BUFFER_STORE_DWORDX4_OFFEN, v4i32, store_private>;
-
-//===----------------------------------------------------------------------===//
-// MTBUF Patterns
-//===----------------------------------------------------------------------===//
-
-// TBUFFER_STORE_FORMAT_*, addr64=0
-class MTBUF_StoreResource <ValueType vt, int num_channels, MTBUF opcode> : Pat<
- (SItbuffer_store v4i32:$rsrc, vt:$vdata, num_channels, i32:$vaddr,
- i32:$soffset, imm:$inst_offset, imm:$dfmt,
- imm:$nfmt, imm:$offen, imm:$idxen,
- imm:$glc, imm:$slc, imm:$tfe),
- (opcode
- $vdata, (as_i16imm $inst_offset), (as_i1imm $offen), (as_i1imm $idxen),
- (as_i1imm $glc), 0, (as_i8imm $dfmt), (as_i8imm $nfmt), $vaddr, $rsrc,
- (as_i1imm $slc), (as_i1imm $tfe), $soffset)
->;
-
-def : MTBUF_StoreResource <i32, 1, TBUFFER_STORE_FORMAT_X>;
-def : MTBUF_StoreResource <v2i32, 2, TBUFFER_STORE_FORMAT_XY>;
-def : MTBUF_StoreResource <v4i32, 3, TBUFFER_STORE_FORMAT_XYZ>;
-def : MTBUF_StoreResource <v4i32, 4, TBUFFER_STORE_FORMAT_XYZW>;
-
/********** ====================== **********/
-/********** Indirect adressing **********/
+/********** Indirect addressing **********/
/********** ====================== **********/
multiclass SI_INDIRECT_Pattern <ValueType vt, ValueType eltvt, string VecSize> {
@@ -3332,48 +839,80 @@ defm : SI_INDIRECT_Pattern <v8i32, i32, "V8">;
defm : SI_INDIRECT_Pattern <v16i32, i32, "V16">;
//===----------------------------------------------------------------------===//
+// SAD Patterns
+//===----------------------------------------------------------------------===//
+
+def : Pat <
+ (add (sub_oneuse (umax i32:$src0, i32:$src1),
+ (umin i32:$src0, i32:$src1)),
+ i32:$src2),
+ (V_SAD_U32 $src0, $src1, $src2)
+>;
+
+def : Pat <
+ (add (select_oneuse (i1 (setugt i32:$src0, i32:$src1)),
+ (sub i32:$src0, i32:$src1),
+ (sub i32:$src1, i32:$src0)),
+ i32:$src2),
+ (V_SAD_U32 $src0, $src1, $src2)
+>;
+
+//===----------------------------------------------------------------------===//
// Conversion Patterns
//===----------------------------------------------------------------------===//
def : Pat<(i32 (sext_inreg i32:$src, i1)),
- (S_BFE_I32 i32:$src, 65536)>; // 0 | 1 << 16
+ (S_BFE_I32 i32:$src, (i32 65536))>; // 0 | 1 << 16
// Handle sext_inreg in i64
def : Pat <
(i64 (sext_inreg i64:$src, i1)),
- (S_BFE_I64 i64:$src, 0x10000) // 0 | 1 << 16
+ (S_BFE_I64 i64:$src, (i32 0x10000)) // 0 | 1 << 16
+>;
+
+def : Pat <
+ (i16 (sext_inreg i16:$src, i1)),
+ (S_BFE_I32 $src, (i32 0x00010000)) // 0 | 1 << 16
+>;
+
+def : Pat <
+ (i16 (sext_inreg i16:$src, i8)),
+ (S_BFE_I32 $src, (i32 0x80000)) // 0 | 8 << 16
>;
def : Pat <
(i64 (sext_inreg i64:$src, i8)),
- (S_BFE_I64 i64:$src, 0x80000) // 0 | 8 << 16
+ (S_BFE_I64 i64:$src, (i32 0x80000)) // 0 | 8 << 16
>;
def : Pat <
(i64 (sext_inreg i64:$src, i16)),
- (S_BFE_I64 i64:$src, 0x100000) // 0 | 16 << 16
+ (S_BFE_I64 i64:$src, (i32 0x100000)) // 0 | 16 << 16
>;
def : Pat <
(i64 (sext_inreg i64:$src, i32)),
- (S_BFE_I64 i64:$src, 0x200000) // 0 | 32 << 16
+ (S_BFE_I64 i64:$src, (i32 0x200000)) // 0 | 32 << 16
>;
-class ZExt_i64_i32_Pat <SDNode ext> : Pat <
- (i64 (ext i32:$src)),
- (REG_SEQUENCE SReg_64, $src, sub0, (S_MOV_B32 0), sub1)
+def : Pat <
+ (i64 (zext i32:$src)),
+ (REG_SEQUENCE SReg_64, $src, sub0, (S_MOV_B32 (i32 0)), sub1)
+>;
+
+def : Pat <
+ (i64 (anyext i32:$src)),
+ (REG_SEQUENCE SReg_64, $src, sub0, (i32 (IMPLICIT_DEF)), sub1)
>;
class ZExt_i64_i1_Pat <SDNode ext> : Pat <
(i64 (ext i1:$src)),
(REG_SEQUENCE VReg_64,
(V_CNDMASK_B32_e64 (i32 0), (i32 1), $src), sub0,
- (S_MOV_B32 0), sub1)
+ (S_MOV_B32 (i32 0)), sub1)
>;
-def : ZExt_i64_i32_Pat<zext>;
-def : ZExt_i64_i32_Pat<anyext>;
def : ZExt_i64_i1_Pat<zext>;
def : ZExt_i64_i1_Pat<anyext>;
@@ -3382,29 +921,29 @@ def : ZExt_i64_i1_Pat<anyext>;
def : Pat <
(i64 (sext i32:$src)),
(REG_SEQUENCE SReg_64, $src, sub0,
- (i32 (COPY_TO_REGCLASS (S_ASHR_I32 $src, 31), SReg_32_XM0)), sub1)
+ (i32 (COPY_TO_REGCLASS (S_ASHR_I32 $src, (i32 31)), SReg_32_XM0)), sub1)
>;
def : Pat <
(i64 (sext i1:$src)),
(REG_SEQUENCE VReg_64,
- (V_CNDMASK_B32_e64 0, -1, $src), sub0,
- (V_CNDMASK_B32_e64 0, -1, $src), sub1)
+ (V_CNDMASK_B32_e64 (i32 0), (i32 -1), $src), sub0,
+ (V_CNDMASK_B32_e64 (i32 0), (i32 -1), $src), sub1)
>;
-class FPToI1Pat<Instruction Inst, int KOne, ValueType vt, SDPatternOperator fp_to_int> : Pat <
+class FPToI1Pat<Instruction Inst, int KOne, ValueType kone_type, ValueType vt, SDPatternOperator fp_to_int> : Pat <
(i1 (fp_to_int (vt (VOP3Mods vt:$src0, i32:$src0_modifiers)))),
- (i1 (Inst 0, KOne, $src0_modifiers, $src0, DSTCLAMP.NONE, DSTOMOD.NONE))
+ (i1 (Inst 0, (kone_type KOne), $src0_modifiers, $src0, DSTCLAMP.NONE, DSTOMOD.NONE))
>;
-def : FPToI1Pat<V_CMP_EQ_F32_e64, CONST.FP32_ONE, f32, fp_to_uint>;
-def : FPToI1Pat<V_CMP_EQ_F32_e64, CONST.FP32_NEG_ONE, f32, fp_to_sint>;
-def : FPToI1Pat<V_CMP_EQ_F64_e64, CONST.FP64_ONE, f64, fp_to_uint>;
-def : FPToI1Pat<V_CMP_EQ_F64_e64, CONST.FP64_NEG_ONE, f64, fp_to_sint>;
+def : FPToI1Pat<V_CMP_EQ_F32_e64, CONST.FP32_ONE, i32, f32, fp_to_uint>;
+def : FPToI1Pat<V_CMP_EQ_F32_e64, CONST.FP32_NEG_ONE, i32, f32, fp_to_sint>;
+def : FPToI1Pat<V_CMP_EQ_F64_e64, CONST.FP64_ONE, i64, f64, fp_to_uint>;
+def : FPToI1Pat<V_CMP_EQ_F64_e64, CONST.FP64_NEG_ONE, i64, f64, fp_to_sint>;
// If we need to perform a logical operation on i1 values, we need to
// use vector comparisons since there is only one SCC register. Vector
-// comparisions still write to a pair of SGPRs, so treat these as
+// comparisons still write to a pair of SGPRs, so treat these as
// 64-bit comparisons. When legalizing SGPR copies, instructions
// resulting in the copies from SCC to these instructions will be
// moved to the VALU.
@@ -3425,12 +964,12 @@ def : Pat <
def : Pat <
(f32 (sint_to_fp i1:$src)),
- (V_CNDMASK_B32_e64 (i32 0), CONST.FP32_NEG_ONE, $src)
+ (V_CNDMASK_B32_e64 (i32 0), (i32 CONST.FP32_NEG_ONE), $src)
>;
def : Pat <
(f32 (uint_to_fp i1:$src)),
- (V_CNDMASK_B32_e64 (i32 0), CONST.FP32_ONE, $src)
+ (V_CNDMASK_B32_e64 (i32 0), (i32 CONST.FP32_ONE), $src)
>;
def : Pat <
@@ -3454,25 +993,25 @@ def : Pat <
def : Pat <
(i1 (trunc i32:$a)),
- (V_CMP_EQ_I32_e64 (S_AND_B32 (i32 1), $a), 1)
+ (V_CMP_EQ_U32_e64 (S_AND_B32 (i32 1), $a), (i32 1))
>;
def : Pat <
- (i1 (trunc i64:$a)),
- (V_CMP_EQ_I32_e64 (S_AND_B32 (i32 1),
- (EXTRACT_SUBREG $a, sub0)), 1)
+ (i1 (trunc i16:$a)),
+ (V_CMP_EQ_U32_e64 (S_AND_B32 (i32 1), $a), (i32 1))
>;
def : Pat <
- (i32 (bswap i32:$a)),
- (V_BFI_B32 (S_MOV_B32 0x00ff00ff),
- (V_ALIGNBIT_B32 $a, $a, 24),
- (V_ALIGNBIT_B32 $a, $a, 8))
+ (i1 (trunc i64:$a)),
+ (V_CMP_EQ_U32_e64 (S_AND_B32 (i32 1),
+ (i32 (EXTRACT_SUBREG $a, sub0))), (i32 1))
>;
def : Pat <
- (f32 (select i1:$src2, f32:$src1, f32:$src0)),
- (V_CNDMASK_B32_e64 $src0, $src1, $src2)
+ (i32 (bswap i32:$a)),
+ (V_BFI_B32 (S_MOV_B32 (i32 0x00ff00ff)),
+ (V_ALIGNBIT_B32 $a, $a, (i32 24)),
+ (V_ALIGNBIT_B32 $a, $a, (i32 8)))
>;
multiclass BFMPatterns <ValueType vt, InstSI BFM, InstSI MOV> {
@@ -3483,7 +1022,7 @@ multiclass BFMPatterns <ValueType vt, InstSI BFM, InstSI MOV> {
def : Pat <
(vt (add (vt (shl 1, vt:$a)), -1)),
- (BFM $a, (MOV 0))
+ (BFM $a, (MOV (i32 0)))
>;
}
@@ -3492,16 +1031,14 @@ defm : BFMPatterns <i32, S_BFM_B32, S_MOV_B32>;
def : BFEPattern <V_BFE_U32, S_MOV_B32>;
-let Predicates = [isSICI] in {
-def : Pat <
- (i64 (readcyclecounter)),
- (S_MEMTIME)
+def : Pat<
+ (fcanonicalize f16:$src),
+ (V_MUL_F16_e64 0, (i32 CONST.FP16_ONE), 0, $src, 0, 0)
>;
-}
def : Pat<
(fcanonicalize f32:$src),
- (V_MUL_F32_e64 0, CONST.FP32_ONE, 0, $src, 0, 0)
+ (V_MUL_F32_e64 0, (i32 CONST.FP32_ONE), 0, $src, 0, 0)
>;
def : Pat<
@@ -3536,7 +1073,7 @@ def : Pat <
(V_MOV_B64_PSEUDO 0x3fefffffffffffff),
DSTCLAMP.NONE, DSTOMOD.NONE),
$x,
- (V_CMP_CLASS_F64_e64 SRCMODS.NONE, $x, 3/*NaN*/)),
+ (V_CMP_CLASS_F64_e64 SRCMODS.NONE, $x, (i32 3 /*NaN*/))),
DSTCLAMP.NONE, DSTOMOD.NONE)
>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIIntrinsics.td b/contrib/llvm/lib/Target/AMDGPU/SIIntrinsics.td
index 9d06ccf..5da3754 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIIntrinsics.td
+++ b/contrib/llvm/lib/Target/AMDGPU/SIIntrinsics.td
@@ -15,7 +15,20 @@
let TargetPrefix = "SI", isTarget = 1 in {
def int_SI_packf16 : Intrinsic <[llvm_i32_ty], [llvm_float_ty, llvm_float_ty], [IntrNoMem]>;
- def int_SI_export : Intrinsic <[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_float_ty], []>;
+
+ def int_SI_export : Intrinsic <[],
+ [llvm_i32_ty, // en
+ llvm_i32_ty, // vm (FIXME: should be i1)
+ llvm_i32_ty, // done (FIXME: should be i1)
+ llvm_i32_ty, // tgt
+ llvm_i32_ty, // compr (FIXME: should be i1)
+ llvm_float_ty, // src0
+ llvm_float_ty, // src1
+ llvm_float_ty, // src2
+ llvm_float_ty], // src3
+ []
+ >;
+
def int_SI_load_const : Intrinsic <[llvm_float_ty], [llvm_anyint_ty, llvm_i32_ty], [IntrNoMem]>;
def int_SI_vs_load_input : Intrinsic <[llvm_v4f32_ty], [llvm_anyint_ty, llvm_i16_ty, llvm_i32_ty], [IntrNoMem]> ;
@@ -186,11 +199,11 @@ let TargetPrefix = "amdgcn", isTarget = 1 in {
/* Control flow Intrinsics */
- def int_amdgcn_if : Intrinsic<[llvm_i64_ty], [llvm_i1_ty, llvm_empty_ty], []>;
- def int_amdgcn_else : Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_empty_ty], []>;
- def int_amdgcn_break : Intrinsic<[llvm_i64_ty], [llvm_i64_ty], []>;
- def int_amdgcn_if_break : Intrinsic<[llvm_i64_ty], [llvm_i1_ty, llvm_i64_ty], []>;
- def int_amdgcn_else_break : Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], []>;
- def int_amdgcn_loop : Intrinsic<[], [llvm_i64_ty, llvm_empty_ty], []>;
- def int_amdgcn_end_cf : Intrinsic<[], [llvm_i64_ty], []>;
+ def int_amdgcn_if : Intrinsic<[llvm_i64_ty], [llvm_i1_ty, llvm_empty_ty], [IntrConvergent]>;
+ def int_amdgcn_else : Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_empty_ty], [IntrConvergent]>;
+ def int_amdgcn_break : Intrinsic<[llvm_i64_ty], [llvm_i64_ty], [IntrNoMem, IntrConvergent]>;
+ def int_amdgcn_if_break : Intrinsic<[llvm_i64_ty], [llvm_i1_ty, llvm_i64_ty], [IntrNoMem, IntrConvergent]>;
+ def int_amdgcn_else_break : Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], [IntrNoMem, IntrConvergent]>;
+ def int_amdgcn_loop : Intrinsic<[], [llvm_i64_ty, llvm_empty_ty], [IntrConvergent]>;
+ def int_amdgcn_end_cf : Intrinsic<[], [llvm_i64_ty], [IntrConvergent]>;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp b/contrib/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
index 9e972a5..99fe96c 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
@@ -60,31 +60,35 @@ private:
const SIInstrInfo *TII;
const SIRegisterInfo *TRI;
MachineRegisterInfo *MRI;
- LiveIntervals *LIS;
+ AliasAnalysis *AA;
static bool offsetsCanBeCombined(unsigned Offset0,
unsigned Offset1,
unsigned EltSize);
- MachineBasicBlock::iterator findMatchingDSInst(MachineBasicBlock::iterator I,
- unsigned EltSize);
+ MachineBasicBlock::iterator findMatchingDSInst(
+ MachineBasicBlock::iterator I,
+ unsigned EltSize,
+ SmallVectorImpl<MachineInstr*> &InstsToMove);
MachineBasicBlock::iterator mergeRead2Pair(
MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired,
- unsigned EltSize);
+ unsigned EltSize,
+ ArrayRef<MachineInstr*> InstsToMove);
MachineBasicBlock::iterator mergeWrite2Pair(
MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired,
- unsigned EltSize);
+ unsigned EltSize,
+ ArrayRef<MachineInstr*> InstsToMove);
public:
static char ID;
SILoadStoreOptimizer()
: MachineFunctionPass(ID), TII(nullptr), TRI(nullptr), MRI(nullptr),
- LIS(nullptr) {}
+ AA(nullptr) {}
SILoadStoreOptimizer(const TargetMachine &TM_) : MachineFunctionPass(ID) {
initializeSILoadStoreOptimizerPass(*PassRegistry::getPassRegistry());
@@ -94,16 +98,11 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Load / Store Optimizer";
- }
+ StringRef getPassName() const override { return "SI Load / Store Optimizer"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
- AU.addPreserved<SlotIndexes>();
- AU.addPreserved<LiveIntervals>();
- AU.addPreserved<LiveVariables>();
- AU.addRequired<LiveIntervals>();
+ AU.addRequired<AAResultsWrapperPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
@@ -113,9 +112,7 @@ public:
INITIALIZE_PASS_BEGIN(SILoadStoreOptimizer, DEBUG_TYPE,
"SI Load / Store Optimizer", false, false)
-INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
-INITIALIZE_PASS_DEPENDENCY(LiveVariables)
-INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
+INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(SILoadStoreOptimizer, DEBUG_TYPE,
"SI Load / Store Optimizer", false, false)
@@ -127,6 +124,73 @@ FunctionPass *llvm::createSILoadStoreOptimizerPass(TargetMachine &TM) {
return new SILoadStoreOptimizer(TM);
}
+static void moveInstsAfter(MachineBasicBlock::iterator I,
+ ArrayRef<MachineInstr*> InstsToMove) {
+ MachineBasicBlock *MBB = I->getParent();
+ ++I;
+ for (MachineInstr *MI : InstsToMove) {
+ MI->removeFromParent();
+ MBB->insert(I, MI);
+ }
+}
+
+static void addDefsToList(const MachineInstr &MI,
+ SmallVectorImpl<const MachineOperand *> &Defs) {
+ for (const MachineOperand &Def : MI.defs()) {
+ Defs.push_back(&Def);
+ }
+}
+
+static bool memAccessesCanBeReordered(
+ MachineBasicBlock::iterator A,
+ MachineBasicBlock::iterator B,
+ const SIInstrInfo *TII,
+ llvm::AliasAnalysis * AA) {
+ return (TII->areMemAccessesTriviallyDisjoint(*A, *B, AA) ||
+ // RAW or WAR - cannot reorder
+ // WAW - cannot reorder
+ // RAR - safe to reorder
+ !(A->mayStore() || B->mayStore()));
+}
+
+// Add MI and its defs to the lists if MI reads one of the defs that are
+// already in the list. Returns true in that case.
+static bool
+addToListsIfDependent(MachineInstr &MI,
+ SmallVectorImpl<const MachineOperand *> &Defs,
+ SmallVectorImpl<MachineInstr*> &Insts) {
+ for (const MachineOperand *Def : Defs) {
+ bool ReadDef = MI.readsVirtualRegister(Def->getReg());
+ // If ReadDef is true, then there is a use of Def between I
+ // and the instruction that I will potentially be merged with. We
+ // will need to move this instruction after the merged instructions.
+ if (ReadDef) {
+ Insts.push_back(&MI);
+ addDefsToList(MI, Defs);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+canMoveInstsAcrossMemOp(MachineInstr &MemOp,
+ ArrayRef<MachineInstr*> InstsToMove,
+ const SIInstrInfo *TII,
+ AliasAnalysis *AA) {
+
+ assert(MemOp.mayLoadOrStore());
+
+ for (MachineInstr *InstToMove : InstsToMove) {
+ if (!InstToMove->mayLoadOrStore())
+ continue;
+ if (!memAccessesCanBeReordered(MemOp, *InstToMove, TII, AA))
+ return false;
+ }
+ return true;
+}
+
bool SILoadStoreOptimizer::offsetsCanBeCombined(unsigned Offset0,
unsigned Offset1,
unsigned Size) {
@@ -156,43 +220,99 @@ bool SILoadStoreOptimizer::offsetsCanBeCombined(unsigned Offset0,
MachineBasicBlock::iterator
SILoadStoreOptimizer::findMatchingDSInst(MachineBasicBlock::iterator I,
- unsigned EltSize){
+ unsigned EltSize,
+ SmallVectorImpl<MachineInstr*> &InstsToMove) {
MachineBasicBlock::iterator E = I->getParent()->end();
MachineBasicBlock::iterator MBBI = I;
++MBBI;
- if (MBBI->getOpcode() != I->getOpcode())
- return E;
-
- // Don't merge volatiles.
- if (MBBI->hasOrderedMemoryRef())
- return E;
-
- int AddrIdx = AMDGPU::getNamedOperandIdx(I->getOpcode(), AMDGPU::OpName::addr);
- const MachineOperand &AddrReg0 = I->getOperand(AddrIdx);
- const MachineOperand &AddrReg1 = MBBI->getOperand(AddrIdx);
-
- // Check same base pointer. Be careful of subregisters, which can occur with
- // vectors of pointers.
- if (AddrReg0.getReg() == AddrReg1.getReg() &&
- AddrReg0.getSubReg() == AddrReg1.getSubReg()) {
- int OffsetIdx = AMDGPU::getNamedOperandIdx(I->getOpcode(),
- AMDGPU::OpName::offset);
- unsigned Offset0 = I->getOperand(OffsetIdx).getImm() & 0xffff;
- unsigned Offset1 = MBBI->getOperand(OffsetIdx).getImm() & 0xffff;
-
- // Check both offsets fit in the reduced range.
- if (offsetsCanBeCombined(Offset0, Offset1, EltSize))
- return MBBI;
- }
+ SmallVector<const MachineOperand *, 8> DefsToMove;
+ addDefsToList(*I, DefsToMove);
+ for ( ; MBBI != E; ++MBBI) {
+
+ if (MBBI->getOpcode() != I->getOpcode()) {
+
+ // This is not a matching DS instruction, but we can keep looking as
+ // long as one of these conditions are met:
+ // 1. It is safe to move I down past MBBI.
+ // 2. It is safe to move MBBI down past the instruction that I will
+ // be merged into.
+
+ if (MBBI->hasUnmodeledSideEffects())
+ // We can't re-order this instruction with respect to other memory
+ // opeations, so we fail both conditions mentioned above.
+ return E;
+
+ if (MBBI->mayLoadOrStore() &&
+ !memAccessesCanBeReordered(*I, *MBBI, TII, AA)) {
+ // We fail condition #1, but we may still be able to satisfy condition
+ // #2. Add this instruction to the move list and then we will check
+ // if condition #2 holds once we have selected the matching instruction.
+ InstsToMove.push_back(&*MBBI);
+ addDefsToList(*MBBI, DefsToMove);
+ continue;
+ }
+
+ // When we match I with another DS instruction we will be moving I down
+ // to the location of the matched instruction any uses of I will need to
+ // be moved down as well.
+ addToListsIfDependent(*MBBI, DefsToMove, InstsToMove);
+ continue;
+ }
+
+ // Don't merge volatiles.
+ if (MBBI->hasOrderedMemoryRef())
+ return E;
+
+ // Handle a case like
+ // DS_WRITE_B32 addr, v, idx0
+ // w = DS_READ_B32 addr, idx0
+ // DS_WRITE_B32 addr, f(w), idx1
+ // where the DS_READ_B32 ends up in InstsToMove and therefore prevents
+ // merging of the two writes.
+ if (addToListsIfDependent(*MBBI, DefsToMove, InstsToMove))
+ continue;
+
+ int AddrIdx = AMDGPU::getNamedOperandIdx(I->getOpcode(), AMDGPU::OpName::addr);
+ const MachineOperand &AddrReg0 = I->getOperand(AddrIdx);
+ const MachineOperand &AddrReg1 = MBBI->getOperand(AddrIdx);
+
+ // Check same base pointer. Be careful of subregisters, which can occur with
+ // vectors of pointers.
+ if (AddrReg0.getReg() == AddrReg1.getReg() &&
+ AddrReg0.getSubReg() == AddrReg1.getSubReg()) {
+ int OffsetIdx = AMDGPU::getNamedOperandIdx(I->getOpcode(),
+ AMDGPU::OpName::offset);
+ unsigned Offset0 = I->getOperand(OffsetIdx).getImm() & 0xffff;
+ unsigned Offset1 = MBBI->getOperand(OffsetIdx).getImm() & 0xffff;
+
+ // Check both offsets fit in the reduced range.
+ // We also need to go through the list of instructions that we plan to
+ // move and make sure they are all safe to move down past the merged
+ // instruction.
+ if (offsetsCanBeCombined(Offset0, Offset1, EltSize) &&
+ canMoveInstsAcrossMemOp(*MBBI, InstsToMove, TII, AA))
+ return MBBI;
+ }
+
+ // We've found a load/store that we couldn't merge for some reason.
+ // We could potentially keep looking, but we'd need to make sure that
+ // it was safe to move I and also all the instruction in InstsToMove
+ // down past this instruction.
+ if (!memAccessesCanBeReordered(*I, *MBBI, TII, AA) || // check if we can move I across MBBI
+ !canMoveInstsAcrossMemOp(*MBBI, InstsToMove, TII, AA) // check if we can move all I's users
+ )
+ break;
+ }
return E;
}
MachineBasicBlock::iterator SILoadStoreOptimizer::mergeRead2Pair(
MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired,
- unsigned EltSize) {
+ unsigned EltSize,
+ ArrayRef<MachineInstr*> InstsToMove) {
MachineBasicBlock *MBB = I->getParent();
// Be careful, since the addresses could be subregisters themselves in weird
@@ -220,6 +340,15 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeRead2Pair(
Opc = (EltSize == 4) ? AMDGPU::DS_READ2ST64_B32 : AMDGPU::DS_READ2ST64_B64;
}
+ unsigned SubRegIdx0 = (EltSize == 4) ? AMDGPU::sub0 : AMDGPU::sub0_sub1;
+ unsigned SubRegIdx1 = (EltSize == 4) ? AMDGPU::sub1 : AMDGPU::sub2_sub3;
+
+ if (NewOffset0 > NewOffset1) {
+ // Canonicalize the merged instruction so the smaller offset comes first.
+ std::swap(NewOffset0, NewOffset1);
+ std::swap(SubRegIdx0, SubRegIdx1);
+ }
+
assert((isUInt<8>(NewOffset0) && isUInt<8>(NewOffset1)) &&
(NewOffset0 != NewOffset1) &&
"Computed offset doesn't fit");
@@ -232,62 +361,40 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeRead2Pair(
DebugLoc DL = I->getDebugLoc();
MachineInstrBuilder Read2
- = BuildMI(*MBB, I, DL, Read2Desc, DestReg)
+ = BuildMI(*MBB, Paired, DL, Read2Desc, DestReg)
.addOperand(*AddrReg) // addr
.addImm(NewOffset0) // offset0
.addImm(NewOffset1) // offset1
.addImm(0) // gds
.addMemOperand(*I->memoperands_begin())
.addMemOperand(*Paired->memoperands_begin());
-
- unsigned SubRegIdx0 = (EltSize == 4) ? AMDGPU::sub0 : AMDGPU::sub0_sub1;
- unsigned SubRegIdx1 = (EltSize == 4) ? AMDGPU::sub1 : AMDGPU::sub2_sub3;
+ (void)Read2;
const MCInstrDesc &CopyDesc = TII->get(TargetOpcode::COPY);
// Copy to the old destination registers.
- MachineInstr *Copy0 = BuildMI(*MBB, I, DL, CopyDesc)
+ BuildMI(*MBB, Paired, DL, CopyDesc)
.addOperand(*Dest0) // Copy to same destination including flags and sub reg.
.addReg(DestReg, 0, SubRegIdx0);
- MachineInstr *Copy1 = BuildMI(*MBB, I, DL, CopyDesc)
+ MachineInstr *Copy1 = BuildMI(*MBB, Paired, DL, CopyDesc)
.addOperand(*Dest1)
.addReg(DestReg, RegState::Kill, SubRegIdx1);
- LIS->InsertMachineInstrInMaps(*Read2);
-
- // repairLiveintervalsInRange() doesn't handle physical register, so we have
- // to update the M0 range manually.
- SlotIndex PairedIndex = LIS->getInstructionIndex(*Paired);
- LiveRange &M0Range = LIS->getRegUnit(*MCRegUnitIterator(AMDGPU::M0, TRI));
- LiveRange::Segment *M0Segment = M0Range.getSegmentContaining(PairedIndex);
- bool UpdateM0Range = M0Segment->end == PairedIndex.getRegSlot();
-
- // The new write to the original destination register is now the copy. Steal
- // the old SlotIndex.
- LIS->ReplaceMachineInstrInMaps(*I, *Copy0);
- LIS->ReplaceMachineInstrInMaps(*Paired, *Copy1);
+ moveInstsAfter(Copy1, InstsToMove);
+ MachineBasicBlock::iterator Next = std::next(I);
I->eraseFromParent();
Paired->eraseFromParent();
- LiveInterval &AddrRegLI = LIS->getInterval(AddrReg->getReg());
- LIS->shrinkToUses(&AddrRegLI);
-
- LIS->createAndComputeVirtRegInterval(DestReg);
-
- if (UpdateM0Range) {
- SlotIndex Read2Index = LIS->getInstructionIndex(*Read2);
- M0Segment->end = Read2Index.getRegSlot();
- }
-
DEBUG(dbgs() << "Inserted read2: " << *Read2 << '\n');
- return Read2.getInstr();
+ return Next;
}
MachineBasicBlock::iterator SILoadStoreOptimizer::mergeWrite2Pair(
MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired,
- unsigned EltSize) {
+ unsigned EltSize,
+ ArrayRef<MachineInstr*> InstsToMove) {
MachineBasicBlock *MBB = I->getParent();
// Be sure to use .addOperand(), and not .addReg() with these. We want to be
@@ -316,6 +423,12 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeWrite2Pair(
Opc = (EltSize == 4) ? AMDGPU::DS_WRITE2ST64_B32 : AMDGPU::DS_WRITE2ST64_B64;
}
+ if (NewOffset0 > NewOffset1) {
+ // Canonicalize the merged instruction so the smaller offset comes first.
+ std::swap(NewOffset0, NewOffset1);
+ std::swap(Data0, Data1);
+ }
+
assert((isUInt<8>(NewOffset0) && isUInt<8>(NewOffset1)) &&
(NewOffset0 != NewOffset1) &&
"Computed offset doesn't fit");
@@ -323,15 +436,8 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeWrite2Pair(
const MCInstrDesc &Write2Desc = TII->get(Opc);
DebugLoc DL = I->getDebugLoc();
- // repairLiveintervalsInRange() doesn't handle physical register, so we have
- // to update the M0 range manually.
- SlotIndex PairedIndex = LIS->getInstructionIndex(*Paired);
- LiveRange &M0Range = LIS->getRegUnit(*MCRegUnitIterator(AMDGPU::M0, TRI));
- LiveRange::Segment *M0Segment = M0Range.getSegmentContaining(PairedIndex);
- bool UpdateM0Range = M0Segment->end == PairedIndex.getRegSlot();
-
MachineInstrBuilder Write2
- = BuildMI(*MBB, I, DL, Write2Desc)
+ = BuildMI(*MBB, Paired, DL, Write2Desc)
.addOperand(*Addr) // addr
.addOperand(*Data0) // data0
.addOperand(*Data1) // data1
@@ -341,24 +447,14 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeWrite2Pair(
.addMemOperand(*I->memoperands_begin())
.addMemOperand(*Paired->memoperands_begin());
- // XXX - How do we express subregisters here?
- unsigned OrigRegs[] = { Data0->getReg(), Data1->getReg(), Addr->getReg() };
+ moveInstsAfter(Write2, InstsToMove);
- LIS->RemoveMachineInstrFromMaps(*I);
- LIS->RemoveMachineInstrFromMaps(*Paired);
+ MachineBasicBlock::iterator Next = std::next(I);
I->eraseFromParent();
Paired->eraseFromParent();
- // This doesn't handle physical registers like M0
- LIS->repairIntervalsInRange(MBB, Write2, Write2, OrigRegs);
-
- if (UpdateM0Range) {
- SlotIndex Write2Index = LIS->getInstructionIndex(*Write2);
- M0Segment->end = Write2Index.getRegSlot();
- }
-
DEBUG(dbgs() << "Inserted write2 inst: " << *Write2 << '\n');
- return Write2.getInstr();
+ return Next;
}
// Scan through looking for adjacent LDS operations with constant offsets from
@@ -376,13 +472,15 @@ bool SILoadStoreOptimizer::optimizeBlock(MachineBasicBlock &MBB) {
continue;
}
+ SmallVector<MachineInstr*, 8> InstsToMove;
unsigned Opc = MI.getOpcode();
if (Opc == AMDGPU::DS_READ_B32 || Opc == AMDGPU::DS_READ_B64) {
unsigned Size = (Opc == AMDGPU::DS_READ_B64) ? 8 : 4;
- MachineBasicBlock::iterator Match = findMatchingDSInst(I, Size);
+ MachineBasicBlock::iterator Match = findMatchingDSInst(I, Size,
+ InstsToMove);
if (Match != E) {
Modified = true;
- I = mergeRead2Pair(I, Match, Size);
+ I = mergeRead2Pair(I, Match, Size, InstsToMove);
} else {
++I;
}
@@ -390,10 +488,11 @@ bool SILoadStoreOptimizer::optimizeBlock(MachineBasicBlock &MBB) {
continue;
} else if (Opc == AMDGPU::DS_WRITE_B32 || Opc == AMDGPU::DS_WRITE_B64) {
unsigned Size = (Opc == AMDGPU::DS_WRITE_B64) ? 8 : 4;
- MachineBasicBlock::iterator Match = findMatchingDSInst(I, Size);
+ MachineBasicBlock::iterator Match = findMatchingDSInst(I, Size,
+ InstsToMove);
if (Match != E) {
Modified = true;
- I = mergeWrite2Pair(I, Match, Size);
+ I = mergeWrite2Pair(I, Match, Size, InstsToMove);
} else {
++I;
}
@@ -419,13 +518,10 @@ bool SILoadStoreOptimizer::runOnMachineFunction(MachineFunction &MF) {
TRI = &TII->getRegisterInfo();
MRI = &MF.getRegInfo();
-
- LIS = &getAnalysis<LiveIntervals>();
+ AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
DEBUG(dbgs() << "Running SILoadStoreOptimizer\n");
- assert(!MRI->isSSA());
-
bool Modified = false;
for (MachineBasicBlock &MBB : MF)
diff --git a/contrib/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp b/contrib/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
index ee1d5da..7ed18f2 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
@@ -58,7 +58,6 @@
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/IR/Constants.h"
using namespace llvm;
@@ -68,63 +67,50 @@ namespace {
class SILowerControlFlow : public MachineFunctionPass {
private:
- static const unsigned SkipThreshold = 12;
-
const SIRegisterInfo *TRI;
const SIInstrInfo *TII;
+ LiveIntervals *LIS;
+ MachineRegisterInfo *MRI;
- bool shouldSkip(MachineBasicBlock *From, MachineBasicBlock *To);
-
- void Skip(MachineInstr &From, MachineOperand &To);
- bool skipIfDead(MachineInstr &MI, MachineBasicBlock &NextBB);
-
- void If(MachineInstr &MI);
- void Else(MachineInstr &MI, bool ExecModified);
- void Break(MachineInstr &MI);
- void IfBreak(MachineInstr &MI);
- void ElseBreak(MachineInstr &MI);
- void Loop(MachineInstr &MI);
- void EndCf(MachineInstr &MI);
-
- void Kill(MachineInstr &MI);
- void Branch(MachineInstr &MI);
-
- MachineBasicBlock *insertSkipBlock(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I) const;
-
- std::pair<MachineBasicBlock *, MachineBasicBlock *>
- splitBlock(MachineBasicBlock &MBB, MachineBasicBlock::iterator I);
+ void emitIf(MachineInstr &MI);
+ void emitElse(MachineInstr &MI);
+ void emitBreak(MachineInstr &MI);
+ void emitIfBreak(MachineInstr &MI);
+ void emitElseBreak(MachineInstr &MI);
+ void emitLoop(MachineInstr &MI);
+ void emitEndCf(MachineInstr &MI);
- void splitLoadM0BlockLiveIns(LivePhysRegs &RemainderLiveRegs,
- const MachineRegisterInfo &MRI,
- const MachineInstr &MI,
- MachineBasicBlock &LoopBB,
- MachineBasicBlock &RemainderBB,
- unsigned SaveReg,
- const MachineOperand &IdxReg);
+ void findMaskOperands(MachineInstr &MI, unsigned OpNo,
+ SmallVectorImpl<MachineOperand> &Src) const;
- void emitLoadM0FromVGPRLoop(MachineBasicBlock &LoopBB, DebugLoc DL,
- MachineInstr *MovRel,
- const MachineOperand &IdxReg,
- int Offset);
-
- bool loadM0(MachineInstr &MI, MachineInstr *MovRel, int Offset = 0);
- std::pair<unsigned, int> computeIndirectRegAndOffset(unsigned VecReg,
- int Offset) const;
- bool indirectSrc(MachineInstr &MI);
- bool indirectDst(MachineInstr &MI);
+ void combineMasks(MachineInstr &MI);
public:
static char ID;
SILowerControlFlow() :
- MachineFunctionPass(ID), TRI(nullptr), TII(nullptr) { }
+ MachineFunctionPass(ID),
+ TRI(nullptr),
+ TII(nullptr),
+ LIS(nullptr),
+ MRI(nullptr) {}
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SI Lower control flow pseudo instructions";
}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ // Should preserve the same set that TwoAddressInstructions does.
+ AU.addPreserved<SlotIndexes>();
+ AU.addPreserved<LiveIntervals>();
+ AU.addPreservedID(LiveVariablesID);
+ AU.addPreservedID(MachineLoopInfoID);
+ AU.addPreservedID(MachineDominatorsID);
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
};
} // End anonymous namespace
@@ -132,555 +118,283 @@ public:
char SILowerControlFlow::ID = 0;
INITIALIZE_PASS(SILowerControlFlow, DEBUG_TYPE,
- "SI lower control flow", false, false)
+ "SI lower control flow", false, false)
-char &llvm::SILowerControlFlowPassID = SILowerControlFlow::ID;
+static void setImpSCCDefDead(MachineInstr &MI, bool IsDead) {
+ MachineOperand &ImpDefSCC = MI.getOperand(3);
+ assert(ImpDefSCC.getReg() == AMDGPU::SCC && ImpDefSCC.isDef());
-
-FunctionPass *llvm::createSILowerControlFlowPass() {
- return new SILowerControlFlow();
+ ImpDefSCC.setIsDead(IsDead);
}
-static bool opcodeEmitsNoInsts(unsigned Opc) {
- switch (Opc) {
- case TargetOpcode::IMPLICIT_DEF:
- case TargetOpcode::KILL:
- case TargetOpcode::BUNDLE:
- case TargetOpcode::CFI_INSTRUCTION:
- case TargetOpcode::EH_LABEL:
- case TargetOpcode::GC_LABEL:
- case TargetOpcode::DBG_VALUE:
- return true;
- default:
- return false;
- }
-}
-
-bool SILowerControlFlow::shouldSkip(MachineBasicBlock *From,
- MachineBasicBlock *To) {
- if (From->succ_empty())
- return false;
-
- unsigned NumInstr = 0;
- MachineFunction *MF = From->getParent();
-
- for (MachineFunction::iterator MBBI(From), ToI(To), End = MF->end();
- MBBI != End && MBBI != ToI; ++MBBI) {
- MachineBasicBlock &MBB = *MBBI;
-
- for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
- NumInstr < SkipThreshold && I != E; ++I) {
- if (opcodeEmitsNoInsts(I->getOpcode()))
- continue;
-
- // When a uniform loop is inside non-uniform control flow, the branch
- // leaving the loop might be an S_CBRANCH_VCCNZ, which is never taken
- // when EXEC = 0. We should skip the loop lest it becomes infinite.
- if (I->getOpcode() == AMDGPU::S_CBRANCH_VCCNZ ||
- I->getOpcode() == AMDGPU::S_CBRANCH_VCCZ)
- return true;
-
- if (I->isInlineAsm()) {
- const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
- const char *AsmStr = I->getOperand(0).getSymbolName();
-
- // inlineasm length estimate is number of bytes assuming the longest
- // instruction.
- uint64_t MaxAsmSize = TII->getInlineAsmLength(AsmStr, *MAI);
- NumInstr += MaxAsmSize / MAI->getMaxInstLength();
- } else {
- ++NumInstr;
- }
+char &llvm::SILowerControlFlowID = SILowerControlFlow::ID;
- if (NumInstr >= SkipThreshold)
- return true;
- }
- }
-
- return false;
-}
-
-void SILowerControlFlow::Skip(MachineInstr &From, MachineOperand &To) {
-
- if (!shouldSkip(*From.getParent()->succ_begin(), To.getMBB()))
- return;
-
- DebugLoc DL = From.getDebugLoc();
- BuildMI(*From.getParent(), &From, DL, TII->get(AMDGPU::S_CBRANCH_EXECZ))
- .addOperand(To);
-}
-
-bool SILowerControlFlow::skipIfDead(MachineInstr &MI, MachineBasicBlock &NextBB) {
+void SILowerControlFlow::emitIf(MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
- MachineFunction *MF = MBB.getParent();
-
- if (MF->getFunction()->getCallingConv() != CallingConv::AMDGPU_PS ||
- !shouldSkip(&MBB, &MBB.getParent()->back()))
- return false;
-
- MachineBasicBlock *SkipBB = insertSkipBlock(MBB, MI.getIterator());
- MBB.addSuccessor(SkipBB);
-
const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock::iterator I(&MI);
- // If the exec mask is non-zero, skip the next two instructions
- BuildMI(&MBB, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))
- .addMBB(&NextBB);
-
- MachineBasicBlock::iterator Insert = SkipBB->begin();
-
- // Exec mask is zero: Export to NULL target...
- BuildMI(*SkipBB, Insert, DL, TII->get(AMDGPU::EXP))
- .addImm(0)
- .addImm(0x09) // V_008DFC_SQ_EXP_NULL
- .addImm(0)
- .addImm(1)
- .addImm(1)
- .addReg(AMDGPU::VGPR0, RegState::Undef)
- .addReg(AMDGPU::VGPR0, RegState::Undef)
- .addReg(AMDGPU::VGPR0, RegState::Undef)
- .addReg(AMDGPU::VGPR0, RegState::Undef);
-
- // ... and terminate wavefront.
- BuildMI(*SkipBB, Insert, DL, TII->get(AMDGPU::S_ENDPGM));
-
- return true;
-}
-
-void SILowerControlFlow::If(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
- unsigned Reg = MI.getOperand(0).getReg();
- unsigned Vcc = MI.getOperand(1).getReg();
-
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_AND_SAVEEXEC_B64), Reg)
- .addReg(Vcc);
-
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_XOR_B64), Reg)
- .addReg(AMDGPU::EXEC)
- .addReg(Reg);
-
- Skip(MI, MI.getOperand(2));
+ MachineOperand &SaveExec = MI.getOperand(0);
+ MachineOperand &Cond = MI.getOperand(1);
+ assert(SaveExec.getSubReg() == AMDGPU::NoSubRegister &&
+ Cond.getSubReg() == AMDGPU::NoSubRegister);
- // Insert a pseudo terminator to help keep the verifier happy.
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::SI_MASK_BRANCH))
- .addOperand(MI.getOperand(2))
- .addReg(Reg);
+ unsigned SaveExecReg = SaveExec.getReg();
- MI.eraseFromParent();
-}
+ MachineOperand &ImpDefSCC = MI.getOperand(4);
+ assert(ImpDefSCC.getReg() == AMDGPU::SCC && ImpDefSCC.isDef());
-void SILowerControlFlow::Else(MachineInstr &MI, bool ExecModified) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
- unsigned Dst = MI.getOperand(0).getReg();
- unsigned Src = MI.getOperand(1).getReg();
-
- BuildMI(MBB, MBB.getFirstNonPHI(), DL,
- TII->get(AMDGPU::S_OR_SAVEEXEC_B64), Dst)
- .addReg(Src); // Saved EXEC
-
- if (ExecModified) {
- // Adjust the saved exec to account for the modifications during the flow
- // block that contains the ELSE. This can happen when WQM mode is switched
- // off.
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_AND_B64), Dst)
- .addReg(AMDGPU::EXEC)
- .addReg(Dst);
+ // Add an implicit def of exec to discourage scheduling VALU after this which
+ // will interfere with trying to form s_and_saveexec_b64 later.
+ unsigned CopyReg = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
+ MachineInstr *CopyExec =
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::COPY), CopyReg)
+ .addReg(AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC, RegState::ImplicitDefine);
+
+ unsigned Tmp = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
+
+ MachineInstr *And =
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_AND_B64), Tmp)
+ .addReg(CopyReg)
+ //.addReg(AMDGPU::EXEC)
+ .addReg(Cond.getReg());
+ setImpSCCDefDead(*And, true);
+
+ MachineInstr *Xor =
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_XOR_B64), SaveExecReg)
+ .addReg(Tmp)
+ .addReg(CopyReg);
+ setImpSCCDefDead(*Xor, ImpDefSCC.isDead());
+
+ // Use a copy that is a terminator to get correct spill code placement it with
+ // fast regalloc.
+ MachineInstr *SetExec =
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B64_term), AMDGPU::EXEC)
+ .addReg(Tmp, RegState::Kill);
+
+ // Insert a pseudo terminator to help keep the verifier happy. This will also
+ // be used later when inserting skips.
+ MachineInstr *NewBr =
+ BuildMI(MBB, I, DL, TII->get(AMDGPU::SI_MASK_BRANCH))
+ .addOperand(MI.getOperand(2));
+
+ if (!LIS) {
+ MI.eraseFromParent();
+ return;
}
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_XOR_B64), AMDGPU::EXEC)
- .addReg(AMDGPU::EXEC)
- .addReg(Dst);
+ LIS->InsertMachineInstrInMaps(*CopyExec);
- Skip(MI, MI.getOperand(2));
+ // Replace with and so we don't need to fix the live interval for condition
+ // register.
+ LIS->ReplaceMachineInstrInMaps(MI, *And);
- // Insert a pseudo terminator to help keep the verifier happy.
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::SI_MASK_BRANCH))
- .addOperand(MI.getOperand(2))
- .addReg(Dst);
+ LIS->InsertMachineInstrInMaps(*Xor);
+ LIS->InsertMachineInstrInMaps(*SetExec);
+ LIS->InsertMachineInstrInMaps(*NewBr);
+ LIS->removeRegUnit(*MCRegUnitIterator(AMDGPU::EXEC, TRI));
MI.eraseFromParent();
-}
-
-void SILowerControlFlow::Break(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
-
- unsigned Dst = MI.getOperand(0).getReg();
- unsigned Src = MI.getOperand(1).getReg();
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_OR_B64), Dst)
- .addReg(AMDGPU::EXEC)
- .addReg(Src);
-
- MI.eraseFromParent();
+ // FIXME: Is there a better way of adjusting the liveness? It shouldn't be
+ // hard to add another def here but I'm not sure how to correctly update the
+ // valno.
+ LIS->removeInterval(SaveExecReg);
+ LIS->createAndComputeVirtRegInterval(SaveExecReg);
+ LIS->createAndComputeVirtRegInterval(Tmp);
+ LIS->createAndComputeVirtRegInterval(CopyReg);
}
-void SILowerControlFlow::IfBreak(MachineInstr &MI) {
+void SILowerControlFlow::emitElse(MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
-
- unsigned Dst = MI.getOperand(0).getReg();
- unsigned Vcc = MI.getOperand(1).getReg();
- unsigned Src = MI.getOperand(2).getReg();
-
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_OR_B64), Dst)
- .addReg(Vcc)
- .addReg(Src);
-
- MI.eraseFromParent();
-}
+ const DebugLoc &DL = MI.getDebugLoc();
-void SILowerControlFlow::ElseBreak(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
+ unsigned DstReg = MI.getOperand(0).getReg();
+ assert(MI.getOperand(0).getSubReg() == AMDGPU::NoSubRegister);
- unsigned Dst = MI.getOperand(0).getReg();
- unsigned Saved = MI.getOperand(1).getReg();
- unsigned Src = MI.getOperand(2).getReg();
+ bool ExecModified = MI.getOperand(3).getImm() != 0;
+ MachineBasicBlock::iterator Start = MBB.begin();
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_OR_B64), Dst)
- .addReg(Saved)
- .addReg(Src);
+ // We are running before TwoAddressInstructions, and si_else's operands are
+ // tied. In order to correctly tie the registers, split this into a copy of
+ // the src like it does.
+ unsigned CopyReg = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
+ BuildMI(MBB, Start, DL, TII->get(AMDGPU::COPY), CopyReg)
+ .addOperand(MI.getOperand(1)); // Saved EXEC
- MI.eraseFromParent();
-}
+ // This must be inserted before phis and any spill code inserted before the
+ // else.
+ unsigned SaveReg = ExecModified ?
+ MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass) : DstReg;
+ MachineInstr *OrSaveExec =
+ BuildMI(MBB, Start, DL, TII->get(AMDGPU::S_OR_SAVEEXEC_B64), SaveReg)
+ .addReg(CopyReg);
-void SILowerControlFlow::Loop(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
- unsigned Src = MI.getOperand(0).getReg();
+ MachineBasicBlock *DestBB = MI.getOperand(2).getMBB();
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_ANDN2_B64), AMDGPU::EXEC)
- .addReg(AMDGPU::EXEC)
- .addReg(Src);
+ MachineBasicBlock::iterator ElsePt(MI);
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))
- .addOperand(MI.getOperand(1));
+ if (ExecModified) {
+ MachineInstr *And =
+ BuildMI(MBB, ElsePt, DL, TII->get(AMDGPU::S_AND_B64), DstReg)
+ .addReg(AMDGPU::EXEC)
+ .addReg(SaveReg);
- MI.eraseFromParent();
-}
+ if (LIS)
+ LIS->InsertMachineInstrInMaps(*And);
+ }
-void SILowerControlFlow::EndCf(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
- unsigned Reg = MI.getOperand(0).getReg();
+ MachineInstr *Xor =
+ BuildMI(MBB, ElsePt, DL, TII->get(AMDGPU::S_XOR_B64_term), AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC)
+ .addReg(DstReg);
- BuildMI(MBB, MBB.getFirstNonPHI(), DL,
- TII->get(AMDGPU::S_OR_B64), AMDGPU::EXEC)
- .addReg(AMDGPU::EXEC)
- .addReg(Reg);
+ MachineInstr *Branch =
+ BuildMI(MBB, ElsePt, DL, TII->get(AMDGPU::SI_MASK_BRANCH))
+ .addMBB(DestBB);
- MI.eraseFromParent();
-}
-
-void SILowerControlFlow::Branch(MachineInstr &MI) {
- MachineBasicBlock *MBB = MI.getOperand(0).getMBB();
- if (MBB == MI.getParent()->getNextNode())
+ if (!LIS) {
MI.eraseFromParent();
-
- // If these aren't equal, this is probably an infinite loop.
-}
-
-void SILowerControlFlow::Kill(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
- const MachineOperand &Op = MI.getOperand(0);
-
-#ifndef NDEBUG
- CallingConv::ID CallConv = MBB.getParent()->getFunction()->getCallingConv();
- // Kill is only allowed in pixel / geometry shaders.
- assert(CallConv == CallingConv::AMDGPU_PS ||
- CallConv == CallingConv::AMDGPU_GS);
-#endif
-
- // Clear this thread from the exec mask if the operand is negative
- if ((Op.isImm())) {
- // Constant operand: Set exec mask to 0 or do nothing
- if (Op.getImm() & 0x80000000) {
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_MOV_B64), AMDGPU::EXEC)
- .addImm(0);
- }
- } else {
- BuildMI(MBB, &MI, DL, TII->get(AMDGPU::V_CMPX_LE_F32_e32))
- .addImm(0)
- .addOperand(Op);
+ return;
}
+ LIS->RemoveMachineInstrFromMaps(MI);
MI.eraseFromParent();
-}
-// All currently live registers must remain so in the remainder block.
-void SILowerControlFlow::splitLoadM0BlockLiveIns(LivePhysRegs &RemainderLiveRegs,
- const MachineRegisterInfo &MRI,
- const MachineInstr &MI,
- MachineBasicBlock &LoopBB,
- MachineBasicBlock &RemainderBB,
- unsigned SaveReg,
- const MachineOperand &IdxReg) {
- // Add reg defined in loop body.
- RemainderLiveRegs.addReg(SaveReg);
-
- if (const MachineOperand *Val = TII->getNamedOperand(MI, AMDGPU::OpName::val)) {
- if (!Val->isUndef()) {
- RemainderLiveRegs.addReg(Val->getReg());
- LoopBB.addLiveIn(Val->getReg());
- }
- }
+ LIS->InsertMachineInstrInMaps(*OrSaveExec);
- for (unsigned Reg : RemainderLiveRegs) {
- if (MRI.isAllocatable(Reg))
- RemainderBB.addLiveIn(Reg);
- }
+ LIS->InsertMachineInstrInMaps(*Xor);
+ LIS->InsertMachineInstrInMaps(*Branch);
- const MachineOperand *Src = TII->getNamedOperand(MI, AMDGPU::OpName::src);
- if (!Src->isUndef())
- LoopBB.addLiveIn(Src->getReg());
+ // src reg is tied to dst reg.
+ LIS->removeInterval(DstReg);
+ LIS->createAndComputeVirtRegInterval(DstReg);
+ LIS->createAndComputeVirtRegInterval(CopyReg);
+ if (ExecModified)
+ LIS->createAndComputeVirtRegInterval(SaveReg);
- if (!IdxReg.isUndef())
- LoopBB.addLiveIn(IdxReg.getReg());
- LoopBB.sortUniqueLiveIns();
+ // Let this be recomputed.
+ LIS->removeRegUnit(*MCRegUnitIterator(AMDGPU::EXEC, TRI));
}
-void SILowerControlFlow::emitLoadM0FromVGPRLoop(MachineBasicBlock &LoopBB,
- DebugLoc DL,
- MachineInstr *MovRel,
- const MachineOperand &IdxReg,
- int Offset) {
- MachineBasicBlock::iterator I = LoopBB.begin();
-
- // Read the next variant into VCC (lower 32 bits) <- also loop target
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), AMDGPU::VCC_LO)
- .addReg(IdxReg.getReg(), getUndefRegState(IdxReg.isUndef()));
-
- // Move index from VCC into M0
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0)
- .addReg(AMDGPU::VCC_LO);
-
- // Compare the just read M0 value to all possible Idx values
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::V_CMP_EQ_U32_e32))
- .addReg(AMDGPU::M0)
- .addReg(IdxReg.getReg(), getUndefRegState(IdxReg.isUndef()));
-
- // Update EXEC, save the original EXEC value to VCC
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_AND_SAVEEXEC_B64), AMDGPU::VCC)
- .addReg(AMDGPU::VCC);
-
- if (Offset != 0) {
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0)
- .addReg(AMDGPU::M0)
- .addImm(Offset);
- }
-
- // Do the actual move
- LoopBB.insert(I, MovRel);
+void SILowerControlFlow::emitBreak(MachineInstr &MI) {
+ MachineBasicBlock &MBB = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ unsigned Dst = MI.getOperand(0).getReg();
- // Update EXEC, switch all done bits to 0 and all todo bits to 1
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_XOR_B64), AMDGPU::EXEC)
+ MachineInstr *Or =
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_OR_B64), Dst)
.addReg(AMDGPU::EXEC)
- .addReg(AMDGPU::VCC);
+ .addOperand(MI.getOperand(1));
- // Loop back to V_READFIRSTLANE_B32 if there are still variants to cover
- BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))
- .addMBB(&LoopBB);
+ if (LIS)
+ LIS->ReplaceMachineInstrInMaps(MI, *Or);
+ MI.eraseFromParent();
}
-MachineBasicBlock *SILowerControlFlow::insertSkipBlock(
- MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const {
- MachineFunction *MF = MBB.getParent();
-
- MachineBasicBlock *SkipBB = MF->CreateMachineBasicBlock();
- MachineFunction::iterator MBBI(MBB);
- ++MBBI;
-
- MF->insert(MBBI, SkipBB);
-
- return SkipBB;
+void SILowerControlFlow::emitIfBreak(MachineInstr &MI) {
+ MI.setDesc(TII->get(AMDGPU::S_OR_B64));
}
-std::pair<MachineBasicBlock *, MachineBasicBlock *>
-SILowerControlFlow::splitBlock(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator I) {
- MachineFunction *MF = MBB.getParent();
-
- // To insert the loop we need to split the block. Move everything after this
- // point to a new block, and insert a new empty block between the two.
- MachineBasicBlock *LoopBB = MF->CreateMachineBasicBlock();
- MachineBasicBlock *RemainderBB = MF->CreateMachineBasicBlock();
- MachineFunction::iterator MBBI(MBB);
- ++MBBI;
-
- MF->insert(MBBI, LoopBB);
- MF->insert(MBBI, RemainderBB);
-
- // Move the rest of the block into a new block.
- RemainderBB->transferSuccessors(&MBB);
- RemainderBB->splice(RemainderBB->begin(), &MBB, I, MBB.end());
-
- MBB.addSuccessor(LoopBB);
-
- return std::make_pair(LoopBB, RemainderBB);
+void SILowerControlFlow::emitElseBreak(MachineInstr &MI) {
+ MI.setDesc(TII->get(AMDGPU::S_OR_B64));
}
-// Returns true if a new block was inserted.
-bool SILowerControlFlow::loadM0(MachineInstr &MI, MachineInstr *MovRel, int Offset) {
+void SILowerControlFlow::emitLoop(MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
- DebugLoc DL = MI.getDebugLoc();
- MachineBasicBlock::iterator I(&MI);
+ const DebugLoc &DL = MI.getDebugLoc();
- const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);
+ MachineInstr *AndN2 =
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_ANDN2_B64_term), AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC)
+ .addOperand(MI.getOperand(0));
- if (AMDGPU::SReg_32RegClass.contains(Idx->getReg())) {
- if (Offset != 0) {
- BuildMI(MBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0)
- .addReg(Idx->getReg(), getUndefRegState(Idx->isUndef()))
- .addImm(Offset);
- } else {
- BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), AMDGPU::M0)
- .addReg(Idx->getReg(), getUndefRegState(Idx->isUndef()));
- }
+ MachineInstr *Branch =
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))
+ .addOperand(MI.getOperand(1));
- MBB.insert(I, MovRel);
- MI.eraseFromParent();
- return false;
+ if (LIS) {
+ LIS->ReplaceMachineInstrInMaps(MI, *AndN2);
+ LIS->InsertMachineInstrInMaps(*Branch);
}
- MachineOperand *SaveOp = TII->getNamedOperand(MI, AMDGPU::OpName::sdst);
- SaveOp->setIsDead(false);
- unsigned Save = SaveOp->getReg();
-
- // Reading from a VGPR requires looping over all workitems in the wavefront.
- assert(AMDGPU::SReg_64RegClass.contains(Save) &&
- AMDGPU::VGPR_32RegClass.contains(Idx->getReg()));
-
- // Save the EXEC mask
- BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B64), Save)
- .addReg(AMDGPU::EXEC);
-
- LivePhysRegs RemainderLiveRegs(TRI);
-
- RemainderLiveRegs.addLiveOuts(MBB);
-
- MachineBasicBlock *LoopBB;
- MachineBasicBlock *RemainderBB;
-
- std::tie(LoopBB, RemainderBB) = splitBlock(MBB, I);
-
- for (const MachineInstr &Inst : reverse(*RemainderBB))
- RemainderLiveRegs.stepBackward(Inst);
-
- MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
- LoopBB->addSuccessor(RemainderBB);
- LoopBB->addSuccessor(LoopBB);
-
- splitLoadM0BlockLiveIns(RemainderLiveRegs, MRI, MI, *LoopBB,
- *RemainderBB, Save, *Idx);
-
- emitLoadM0FromVGPRLoop(*LoopBB, DL, MovRel, *Idx, Offset);
-
- MachineBasicBlock::iterator First = RemainderBB->begin();
- BuildMI(*RemainderBB, First, DL, TII->get(AMDGPU::S_MOV_B64), AMDGPU::EXEC)
- .addReg(Save);
-
MI.eraseFromParent();
- return true;
-}
-
-/// \param @VecReg The register which holds element zero of the vector being
-/// addressed into.
-//
-/// \param[in] @Idx The index operand from the movrel instruction. This must be
-// a register, but may be NoRegister.
-///
-/// \param[in] @Offset As an input, this is the constant offset part of the
-// indirect Index. e.g. v0 = v[VecReg + Offset] As an output, this is a constant
-// value that needs to be added to the value stored in M0.
-std::pair<unsigned, int>
-SILowerControlFlow::computeIndirectRegAndOffset(unsigned VecReg, int Offset) const {
- unsigned SubReg = TRI->getSubReg(VecReg, AMDGPU::sub0);
- if (!SubReg)
- SubReg = VecReg;
-
- const TargetRegisterClass *SuperRC = TRI->getPhysRegClass(VecReg);
- const TargetRegisterClass *RC = TRI->getPhysRegClass(SubReg);
- int NumElts = SuperRC->getSize() / RC->getSize();
-
- int BaseRegIdx = TRI->getHWRegIndex(SubReg);
-
- // Skip out of bounds offsets, or else we would end up using an undefined
- // register.
- if (Offset >= NumElts)
- return std::make_pair(RC->getRegister(BaseRegIdx), Offset);
-
- int RegIdx = BaseRegIdx + Offset;
- if (RegIdx < 0) {
- Offset = RegIdx;
- RegIdx = 0;
- } else {
- Offset = 0;
- }
-
- unsigned Reg = RC->getRegister(RegIdx);
- return std::make_pair(Reg, Offset);
}
-// Return true if a new block was inserted.
-bool SILowerControlFlow::indirectSrc(MachineInstr &MI) {
+void SILowerControlFlow::emitEndCf(MachineInstr &MI) {
MachineBasicBlock &MBB = *MI.getParent();
const DebugLoc &DL = MI.getDebugLoc();
- unsigned Dst = MI.getOperand(0).getReg();
- const MachineOperand *SrcVec = TII->getNamedOperand(MI, AMDGPU::OpName::src);
- int Offset = TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm();
- unsigned Reg;
-
- std::tie(Reg, Offset) = computeIndirectRegAndOffset(SrcVec->getReg(), Offset);
+ MachineBasicBlock::iterator InsPt = MBB.begin();
+ MachineInstr *NewMI =
+ BuildMI(MBB, InsPt, DL, TII->get(AMDGPU::S_OR_B64), AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC)
+ .addOperand(MI.getOperand(0));
- const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);
- if (Idx->getReg() == AMDGPU::NoRegister) {
- // Only had a constant offset, copy the register directly.
- BuildMI(MBB, MI.getIterator(), DL, TII->get(AMDGPU::V_MOV_B32_e32), Dst)
- .addReg(Reg, getUndefRegState(SrcVec->isUndef()));
- MI.eraseFromParent();
- return false;
- }
+ if (LIS)
+ LIS->ReplaceMachineInstrInMaps(MI, *NewMI);
- MachineInstr *MovRel =
- BuildMI(*MBB.getParent(), DL, TII->get(AMDGPU::V_MOVRELS_B32_e32), Dst)
- .addReg(Reg, getUndefRegState(SrcVec->isUndef()))
- .addReg(SrcVec->getReg(), RegState::Implicit);
+ MI.eraseFromParent();
- return loadM0(MI, MovRel, Offset);
+ if (LIS)
+ LIS->handleMove(*NewMI);
}
-// Return true if a new block was inserted.
-bool SILowerControlFlow::indirectDst(MachineInstr &MI) {
- MachineBasicBlock &MBB = *MI.getParent();
- const DebugLoc &DL = MI.getDebugLoc();
-
- unsigned Dst = MI.getOperand(0).getReg();
- int Offset = TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm();
- unsigned Reg;
-
- const MachineOperand *Val = TII->getNamedOperand(MI, AMDGPU::OpName::val);
- std::tie(Reg, Offset) = computeIndirectRegAndOffset(Dst, Offset);
-
- MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);
- if (Idx->getReg() == AMDGPU::NoRegister) {
- // Only had a constant offset, copy the register directly.
- BuildMI(MBB, MI.getIterator(), DL, TII->get(AMDGPU::V_MOV_B32_e32), Reg)
- .addOperand(*Val);
- MI.eraseFromParent();
- return false;
+// Returns replace operands for a logical operation, either single result
+// for exec or two operands if source was another equivalent operation.
+void SILowerControlFlow::findMaskOperands(MachineInstr &MI, unsigned OpNo,
+ SmallVectorImpl<MachineOperand> &Src) const {
+ MachineOperand &Op = MI.getOperand(OpNo);
+ if (!Op.isReg() || !TargetRegisterInfo::isVirtualRegister(Op.getReg())) {
+ Src.push_back(Op);
+ return;
}
- MachineInstr *MovRel =
- BuildMI(*MBB.getParent(), DL, TII->get(AMDGPU::V_MOVRELD_B32_e32), Reg)
- .addReg(Val->getReg(), getUndefRegState(Val->isUndef()))
- .addReg(Dst, RegState::Implicit);
+ MachineInstr *Def = MRI->getUniqueVRegDef(Op.getReg());
+ if (!Def || Def->getParent() != MI.getParent() ||
+ !(Def->isFullCopy() || (Def->getOpcode() == MI.getOpcode())))
+ return;
- return loadM0(MI, MovRel, Offset);
+ // Make sure we do not modify exec between def and use.
+ // A copy with implcitly defined exec inserted earlier is an exclusion, it
+ // does not really modify exec.
+ for (auto I = Def->getIterator(); I != MI.getIterator(); ++I)
+ if (I->modifiesRegister(AMDGPU::EXEC, TRI) &&
+ !(I->isCopy() && I->getOperand(0).getReg() != AMDGPU::EXEC))
+ return;
+
+ for (const auto &SrcOp : Def->explicit_operands())
+ if (SrcOp.isUse() && (!SrcOp.isReg() ||
+ TargetRegisterInfo::isVirtualRegister(SrcOp.getReg()) ||
+ SrcOp.getReg() == AMDGPU::EXEC))
+ Src.push_back(SrcOp);
+}
+
+// Search and combine pairs of equivalent instructions, like
+// S_AND_B64 x, (S_AND_B64 x, y) => S_AND_B64 x, y
+// S_OR_B64 x, (S_OR_B64 x, y) => S_OR_B64 x, y
+// One of the operands is exec mask.
+void SILowerControlFlow::combineMasks(MachineInstr &MI) {
+ assert(MI.getNumExplicitOperands() == 3);
+ SmallVector<MachineOperand, 4> Ops;
+ unsigned OpToReplace = 1;
+ findMaskOperands(MI, 1, Ops);
+ if (Ops.size() == 1) OpToReplace = 2; // First operand can be exec or its copy
+ findMaskOperands(MI, 2, Ops);
+ if (Ops.size() != 3) return;
+
+ unsigned UniqueOpndIdx;
+ if (Ops[0].isIdenticalTo(Ops[1])) UniqueOpndIdx = 2;
+ else if (Ops[0].isIdenticalTo(Ops[2])) UniqueOpndIdx = 1;
+ else if (Ops[1].isIdenticalTo(Ops[2])) UniqueOpndIdx = 1;
+ else return;
+
+ unsigned Reg = MI.getOperand(OpToReplace).getReg();
+ MI.RemoveOperand(OpToReplace);
+ MI.addOperand(Ops[UniqueOpndIdx]);
+ if (MRI->use_empty(Reg))
+ MRI->getUniqueVRegDef(Reg)->eraseFromParent();
}
bool SILowerControlFlow::runOnMachineFunction(MachineFunction &MF) {
@@ -688,148 +402,66 @@ bool SILowerControlFlow::runOnMachineFunction(MachineFunction &MF) {
TII = ST.getInstrInfo();
TRI = &TII->getRegisterInfo();
- SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
-
- bool HaveKill = false;
- bool NeedFlat = false;
- unsigned Depth = 0;
+ // This doesn't actually need LiveIntervals, but we can preserve them.
+ LIS = getAnalysisIfAvailable<LiveIntervals>();
+ MRI = &MF.getRegInfo();
MachineFunction::iterator NextBB;
-
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
BI != BE; BI = NextBB) {
NextBB = std::next(BI);
MachineBasicBlock &MBB = *BI;
- MachineBasicBlock *EmptyMBBAtEnd = nullptr;
- MachineBasicBlock::iterator I, Next;
- bool ExecModified = false;
+ MachineBasicBlock::iterator I, Next, Last;
- for (I = MBB.begin(); I != MBB.end(); I = Next) {
+ for (I = MBB.begin(), Last = MBB.end(); I != MBB.end(); I = Next) {
Next = std::next(I);
-
MachineInstr &MI = *I;
- // Flat uses m0 in case it needs to access LDS.
- if (TII->isFLAT(MI))
- NeedFlat = true;
-
- if (I->modifiesRegister(AMDGPU::EXEC, TRI))
- ExecModified = true;
-
switch (MI.getOpcode()) {
- default: break;
- case AMDGPU::SI_IF:
- ++Depth;
- If(MI);
- break;
-
- case AMDGPU::SI_ELSE:
- Else(MI, ExecModified);
- break;
-
- case AMDGPU::SI_BREAK:
- Break(MI);
- break;
-
- case AMDGPU::SI_IF_BREAK:
- IfBreak(MI);
- break;
-
- case AMDGPU::SI_ELSE_BREAK:
- ElseBreak(MI);
- break;
-
- case AMDGPU::SI_LOOP:
- ++Depth;
- Loop(MI);
- break;
-
- case AMDGPU::SI_END_CF:
- if (--Depth == 0 && HaveKill) {
- HaveKill = false;
- // TODO: Insert skip if exec is 0?
- }
-
- EndCf(MI);
- break;
-
- case AMDGPU::SI_KILL_TERMINATOR:
- if (Depth == 0) {
- if (skipIfDead(MI, *NextBB)) {
- NextBB = std::next(BI);
- BE = MF.end();
- }
- } else
- HaveKill = true;
- Kill(MI);
- break;
-
- case AMDGPU::S_BRANCH:
- Branch(MI);
- break;
-
- case AMDGPU::SI_INDIRECT_SRC_V1:
- case AMDGPU::SI_INDIRECT_SRC_V2:
- case AMDGPU::SI_INDIRECT_SRC_V4:
- case AMDGPU::SI_INDIRECT_SRC_V8:
- case AMDGPU::SI_INDIRECT_SRC_V16:
- if (indirectSrc(MI)) {
- // The block was split at this point. We can safely skip the middle
- // inserted block to the following which contains the rest of this
- // block's instructions.
- NextBB = std::next(BI);
- BE = MF.end();
- Next = MBB.end();
- }
-
- break;
-
- case AMDGPU::SI_INDIRECT_DST_V1:
- case AMDGPU::SI_INDIRECT_DST_V2:
- case AMDGPU::SI_INDIRECT_DST_V4:
- case AMDGPU::SI_INDIRECT_DST_V8:
- case AMDGPU::SI_INDIRECT_DST_V16:
- if (indirectDst(MI)) {
- // The block was split at this point. We can safely skip the middle
- // inserted block to the following which contains the rest of this
- // block's instructions.
- NextBB = std::next(BI);
- BE = MF.end();
- Next = MBB.end();
- }
-
- break;
-
- case AMDGPU::SI_RETURN: {
- assert(!MF.getInfo<SIMachineFunctionInfo>()->returnsVoid());
-
- // Graphics shaders returning non-void shouldn't contain S_ENDPGM,
- // because external bytecode will be appended at the end.
- if (BI != --MF.end() || I != MBB.getFirstTerminator()) {
- // SI_RETURN is not the last instruction. Add an empty block at
- // the end and jump there.
- if (!EmptyMBBAtEnd) {
- EmptyMBBAtEnd = MF.CreateMachineBasicBlock();
- MF.insert(MF.end(), EmptyMBBAtEnd);
- }
-
- MBB.addSuccessor(EmptyMBBAtEnd);
- BuildMI(*BI, I, MI.getDebugLoc(), TII->get(AMDGPU::S_BRANCH))
- .addMBB(EmptyMBBAtEnd);
- I->eraseFromParent();
- }
- break;
- }
+ case AMDGPU::SI_IF:
+ emitIf(MI);
+ break;
+
+ case AMDGPU::SI_ELSE:
+ emitElse(MI);
+ break;
+
+ case AMDGPU::SI_BREAK:
+ emitBreak(MI);
+ break;
+
+ case AMDGPU::SI_IF_BREAK:
+ emitIfBreak(MI);
+ break;
+
+ case AMDGPU::SI_ELSE_BREAK:
+ emitElseBreak(MI);
+ break;
+
+ case AMDGPU::SI_LOOP:
+ emitLoop(MI);
+ break;
+
+ case AMDGPU::SI_END_CF:
+ emitEndCf(MI);
+ break;
+
+ case AMDGPU::S_AND_B64:
+ case AMDGPU::S_OR_B64:
+ // Cleanup bit manipulations on exec mask
+ combineMasks(MI);
+ Last = I;
+ continue;
+
+ default:
+ Last = I;
+ continue;
}
- }
- }
- if (NeedFlat && MFI->IsKernel) {
- // TODO: What to use with function calls?
- // We will need to Initialize the flat scratch register pair.
- if (NeedFlat)
- MFI->setHasFlatInstructions(true);
+ // Replay newly inserted code to combine masks
+ Next = (Last == MBB.end()) ? MBB.begin() : Last;
+ }
}
return true;
diff --git a/contrib/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp b/contrib/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp
index dc1d20d..be2e14f 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SILowerI1Copies.cpp
@@ -41,9 +41,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Lower i1 Copies";
- }
+ StringRef getPassName() const override { return "SI Lower i1 Copies"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -102,12 +100,12 @@ bool SILowerI1Copies::runOnMachineFunction(MachineFunction &MF) {
const TargetRegisterClass *DstRC = MRI.getRegClass(Dst.getReg());
const TargetRegisterClass *SrcRC = MRI.getRegClass(Src.getReg());
+ DebugLoc DL = MI.getDebugLoc();
+ MachineInstr *DefInst = MRI.getUniqueVRegDef(Src.getReg());
if (DstRC == &AMDGPU::VReg_1RegClass &&
TRI->getCommonSubClass(SrcRC, &AMDGPU::SGPR_64RegClass)) {
I1Defs.push_back(Dst.getReg());
- DebugLoc DL = MI.getDebugLoc();
- MachineInstr *DefInst = MRI.getUniqueVRegDef(Src.getReg());
if (DefInst->getOpcode() == AMDGPU::S_MOV_B64) {
if (DefInst->getOperand(1).isImm()) {
I1Defs.push_back(Dst.getReg());
@@ -131,10 +129,26 @@ bool SILowerI1Copies::runOnMachineFunction(MachineFunction &MF) {
MI.eraseFromParent();
} else if (TRI->getCommonSubClass(DstRC, &AMDGPU::SGPR_64RegClass) &&
SrcRC == &AMDGPU::VReg_1RegClass) {
- BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(AMDGPU::V_CMP_NE_I32_e64))
- .addOperand(Dst)
- .addOperand(Src)
- .addImm(0);
+ if (DefInst->getOpcode() == AMDGPU::V_CNDMASK_B32_e64 &&
+ DefInst->getOperand(1).isImm() && DefInst->getOperand(2).isImm() &&
+ DefInst->getOperand(1).getImm() == 0 &&
+ DefInst->getOperand(2).getImm() != 0 &&
+ DefInst->getOperand(3).isReg() &&
+ TargetRegisterInfo::isVirtualRegister(
+ DefInst->getOperand(3).getReg()) &&
+ TRI->getCommonSubClass(
+ MRI.getRegClass(DefInst->getOperand(3).getReg()),
+ &AMDGPU::SGPR_64RegClass)) {
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::S_AND_B64))
+ .addOperand(Dst)
+ .addReg(AMDGPU::EXEC)
+ .addOperand(DefInst->getOperand(3));
+ } else {
+ BuildMI(MBB, &MI, DL, TII->get(AMDGPU::V_CMP_NE_U32_e64))
+ .addOperand(Dst)
+ .addOperand(Src)
+ .addImm(0);
+ }
MI.eraseFromParent();
}
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 848be32..ecd46b9 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -26,9 +26,6 @@ static cl::opt<bool> EnableSpillSGPRToVGPR(
cl::ReallyHidden,
cl::init(true));
-// Pin the vtable to this file.
-void SIMachineFunctionInfo::anchor() {}
-
SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
: AMDGPUMachineFunction(MF),
TIDReg(AMDGPU::NoRegister),
@@ -51,8 +48,8 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
PrivateSegmentWaveByteOffsetSystemSGPR(AMDGPU::NoRegister),
PSInputAddr(0),
ReturnsVoid(true),
- MaximumWorkGroupSize(0),
- DebuggerReservedVGPRCount(0),
+ FlatWorkGroupSizes(0, 0),
+ WavesPerEU(0, 0),
DebuggerWorkGroupIDStackObjectIndices({{0, 0, 0}}),
DebuggerWorkItemIDStackObjectIndices({{0, 0, 0}}),
LDSWaveSpillSize(0),
@@ -62,14 +59,13 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
HasSpilledSGPRs(false),
HasSpilledVGPRs(false),
HasNonSpillStackObjects(false),
- HasFlatInstructions(false),
NumSpilledSGPRs(0),
NumSpilledVGPRs(0),
PrivateSegmentBuffer(false),
DispatchPtr(false),
QueuePtr(false),
- DispatchID(false),
KernargSegmentPtr(false),
+ DispatchID(false),
FlatScratchInit(false),
GridWorkgroupCountX(false),
GridWorkgroupCountY(false),
@@ -81,13 +77,14 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
PrivateSegmentWaveByteOffset(false),
WorkItemIDX(false),
WorkItemIDY(false),
- WorkItemIDZ(false) {
+ WorkItemIDZ(false),
+ PrivateMemoryInputPtr(false) {
const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
const Function *F = MF.getFunction();
PSInputAddr = AMDGPU::getInitialPSInputAddr(*F);
- const MachineFrameInfo *FrameInfo = MF.getFrameInfo();
+ const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
if (!AMDGPU::isShader(F->getCallingConv())) {
KernargSegmentPtr = true;
@@ -113,12 +110,12 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
WorkItemIDY = true;
bool MaySpill = ST.isVGPRSpillingEnabled(*F);
- bool HasStackObjects = FrameInfo->hasStackObjects();
+ bool HasStackObjects = FrameInfo.hasStackObjects();
if (HasStackObjects || MaySpill)
PrivateSegmentWaveByteOffset = true;
- if (ST.isAmdHsaOS()) {
+ if (ST.isAmdCodeObjectV2(MF)) {
if (HasStackObjects || MaySpill)
PrivateSegmentBuffer = true;
@@ -127,6 +124,12 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
if (F->hasFnAttribute("amdgpu-queue-ptr"))
QueuePtr = true;
+
+ if (F->hasFnAttribute("amdgpu-dispatch-id"))
+ DispatchID = true;
+ } else if (ST.isMesaGfxShader(MF)) {
+ if (HasStackObjects || MaySpill)
+ PrivateMemoryInputPtr = true;
}
// We don't need to worry about accessing spills with flat instructions.
@@ -136,13 +139,8 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
ST.isAmdHsaOS())
FlatScratchInit = true;
- if (AMDGPU::isCompute(F->getCallingConv()))
- MaximumWorkGroupSize = AMDGPU::getMaximumWorkGroupSize(*F);
- else
- MaximumWorkGroupSize = ST.getWavefrontSize();
-
- if (ST.debuggerReserveRegs())
- DebuggerReservedVGPRCount = 4;
+ FlatWorkGroupSizes = ST.getFlatWorkGroupSizes(*F);
+ WavesPerEU = ST.getWavesPerEU(*F);
}
unsigned SIMachineFunctionInfo::addPrivateSegmentBuffer(
@@ -174,6 +172,13 @@ unsigned SIMachineFunctionInfo::addKernargSegmentPtr(const SIRegisterInfo &TRI)
return KernargSegmentPtrUserSGPR;
}
+unsigned SIMachineFunctionInfo::addDispatchID(const SIRegisterInfo &TRI) {
+ DispatchIDUserSGPR = TRI.getMatchingSuperReg(
+ getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass);
+ NumUserSGPRs += 2;
+ return DispatchIDUserSGPR;
+}
+
unsigned SIMachineFunctionInfo::addFlatScratchInit(const SIRegisterInfo &TRI) {
FlatScratchInitUserSGPR = TRI.getMatchingSuperReg(
getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass);
@@ -181,6 +186,13 @@ unsigned SIMachineFunctionInfo::addFlatScratchInit(const SIRegisterInfo &TRI) {
return FlatScratchInitUserSGPR;
}
+unsigned SIMachineFunctionInfo::addPrivateMemoryPtr(const SIRegisterInfo &TRI) {
+ PrivateMemoryPtrUserSGPR = TRI.getMatchingSuperReg(
+ getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass);
+ NumUserSGPRs += 2;
+ return PrivateMemoryPtrUserSGPR;
+}
+
SIMachineFunctionInfo::SpilledReg SIMachineFunctionInfo::getSpilledReg (
MachineFunction *MF,
unsigned FrameIndex,
@@ -191,9 +203,9 @@ SIMachineFunctionInfo::SpilledReg SIMachineFunctionInfo::getSpilledReg (
const SISubtarget &ST = MF->getSubtarget<SISubtarget>();
const SIRegisterInfo *TRI = ST.getRegisterInfo();
- MachineFrameInfo *FrameInfo = MF->getFrameInfo();
+ MachineFrameInfo &FrameInfo = MF->getFrameInfo();
MachineRegisterInfo &MRI = MF->getRegInfo();
- int64_t Offset = FrameInfo->getObjectOffset(FrameIndex);
+ int64_t Offset = FrameInfo.getObjectOffset(FrameIndex);
Offset += SubIdx * 4;
unsigned LaneVGPRIdx = Offset / (64 * 4);
@@ -223,8 +235,3 @@ SIMachineFunctionInfo::SpilledReg SIMachineFunctionInfo::getSpilledReg (
Spill.VGPR = LaneVGPRs[LaneVGPRIdx];
return Spill;
}
-
-unsigned SIMachineFunctionInfo::getMaximumWorkGroupSize(
- const MachineFunction &MF) const {
- return MaximumWorkGroupSize;
-}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h
index f5bd636..6fc8d18 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h
@@ -23,12 +23,59 @@ namespace llvm {
class MachineRegisterInfo;
+class AMDGPUImagePseudoSourceValue : public PseudoSourceValue {
+public:
+ explicit AMDGPUImagePseudoSourceValue() :
+ PseudoSourceValue(PseudoSourceValue::TargetCustom) { }
+
+ bool isConstant(const MachineFrameInfo *) const override {
+ // This should probably be true for most images, but we will start by being
+ // conservative.
+ return false;
+ }
+
+ bool isAliased(const MachineFrameInfo *) const override {
+ // FIXME: If we ever change image intrinsics to accept fat pointers, then
+ // this could be true for some cases.
+ return false;
+ }
+
+ bool mayAlias(const MachineFrameInfo*) const override {
+ // FIXME: If we ever change image intrinsics to accept fat pointers, then
+ // this could be true for some cases.
+ return false;
+ }
+};
+
+class AMDGPUBufferPseudoSourceValue : public PseudoSourceValue {
+public:
+ explicit AMDGPUBufferPseudoSourceValue() :
+ PseudoSourceValue(PseudoSourceValue::TargetCustom) { }
+
+ bool isConstant(const MachineFrameInfo *) const override {
+ // This should probably be true for most images, but we will start by being
+ // conservative.
+ return false;
+ }
+
+ bool isAliased(const MachineFrameInfo *) const override {
+ // FIXME: If we ever change image intrinsics to accept fat pointers, then
+ // this could be true for some cases.
+ return false;
+ }
+
+ bool mayAlias(const MachineFrameInfo*) const override {
+ // FIXME: If we ever change image intrinsics to accept fat pointers, then
+ // this could be true for some cases.
+ return false;
+ }
+};
+
/// This class keeps track of the SPI_SP_INPUT_ADDR config register, which
/// tells the hardware which interpolation parameters to load.
class SIMachineFunctionInfo final : public AMDGPUMachineFunction {
// FIXME: This should be removed and getPreloadedValue moved here.
- friend struct SIRegisterInfo;
- void anchor() override;
+ friend class SIRegisterInfo;
unsigned TIDReg;
@@ -37,6 +84,9 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction {
unsigned ScratchRSrcReg;
unsigned ScratchWaveOffsetReg;
+ // Input registers for non-HSA ABI
+ unsigned PrivateMemoryPtrUserSGPR;
+
// Input registers setup for the HSA ABI.
// User SGPRs in allocation order.
unsigned PrivateSegmentBufferUserSGPR;
@@ -61,15 +111,22 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction {
unsigned PSInputAddr;
bool ReturnsVoid;
- unsigned MaximumWorkGroupSize;
+ // A pair of default/requested minimum/maximum flat work group sizes.
+ // Minimum - first, maximum - second.
+ std::pair<unsigned, unsigned> FlatWorkGroupSizes;
+
+ // A pair of default/requested minimum/maximum number of waves per execution
+ // unit. Minimum - first, maximum - second.
+ std::pair<unsigned, unsigned> WavesPerEU;
- // Number of reserved VGPRs for debugger usage.
- unsigned DebuggerReservedVGPRCount;
// Stack object indices for work group IDs.
std::array<int, 3> DebuggerWorkGroupIDStackObjectIndices;
// Stack object indices for work item IDs.
std::array<int, 3> DebuggerWorkItemIDStackObjectIndices;
+ AMDGPUBufferPseudoSourceValue BufferPSV;
+ AMDGPUImagePseudoSourceValue ImagePSV;
+
public:
// FIXME: Make private
unsigned LDSWaveSpillSize;
@@ -83,7 +140,6 @@ private:
bool HasSpilledSGPRs;
bool HasSpilledVGPRs;
bool HasNonSpillStackObjects;
- bool HasFlatInstructions;
unsigned NumSpilledSGPRs;
unsigned NumSpilledVGPRs;
@@ -92,8 +148,8 @@ private:
bool PrivateSegmentBuffer : 1;
bool DispatchPtr : 1;
bool QueuePtr : 1;
- bool DispatchID : 1;
bool KernargSegmentPtr : 1;
+ bool DispatchID : 1;
bool FlatScratchInit : 1;
bool GridWorkgroupCountX : 1;
bool GridWorkgroupCountY : 1;
@@ -110,6 +166,11 @@ private:
bool WorkItemIDY : 1;
bool WorkItemIDZ : 1;
+ // Private memory buffer
+ // Compute directly in sgpr[0:1]
+ // Other shaders indirect 64-bits at sgpr[0:1]
+ bool PrivateMemoryInputPtr : 1;
+
MCPhysReg getNextUserSGPR() const {
assert(NumSystemSGPRs == 0 && "System SGPRs must be added after user SGPRs");
return AMDGPU::SGPR0 + NumUserSGPRs;
@@ -143,7 +204,9 @@ public:
unsigned addDispatchPtr(const SIRegisterInfo &TRI);
unsigned addQueuePtr(const SIRegisterInfo &TRI);
unsigned addKernargSegmentPtr(const SIRegisterInfo &TRI);
+ unsigned addDispatchID(const SIRegisterInfo &TRI);
unsigned addFlatScratchInit(const SIRegisterInfo &TRI);
+ unsigned addPrivateMemoryPtr(const SIRegisterInfo &TRI);
// Add system SGPRs.
unsigned addWorkGroupIDX() {
@@ -192,14 +255,14 @@ public:
return QueuePtr;
}
- bool hasDispatchID() const {
- return DispatchID;
- }
-
bool hasKernargSegmentPtr() const {
return KernargSegmentPtr;
}
+ bool hasDispatchID() const {
+ return DispatchID;
+ }
+
bool hasFlatScratchInit() const {
return FlatScratchInit;
}
@@ -248,6 +311,10 @@ public:
return WorkItemIDZ;
}
+ bool hasPrivateMemoryInputPtr() const {
+ return PrivateMemoryInputPtr;
+ }
+
unsigned getNumUserSGPRs() const {
return NumUserSGPRs;
}
@@ -284,6 +351,10 @@ public:
return QueuePtrUserSGPR;
}
+ unsigned getPrivateMemoryPtrUserSGPR() const {
+ return PrivateMemoryPtrUserSGPR;
+ }
+
bool hasSpilledSGPRs() const {
return HasSpilledSGPRs;
}
@@ -308,14 +379,6 @@ public:
HasNonSpillStackObjects = StackObject;
}
- bool hasFlatInstructions() const {
- return HasFlatInstructions;
- }
-
- void setHasFlatInstructions(bool UseFlat = true) {
- HasFlatInstructions = UseFlat;
- }
-
unsigned getNumSpilledSGPRs() const {
return NumSpilledSGPRs;
}
@@ -352,9 +415,36 @@ public:
ReturnsVoid = Value;
}
- /// \returns Number of reserved VGPRs for debugger usage.
- unsigned getDebuggerReservedVGPRCount() const {
- return DebuggerReservedVGPRCount;
+ /// \returns A pair of default/requested minimum/maximum flat work group sizes
+ /// for this function.
+ std::pair<unsigned, unsigned> getFlatWorkGroupSizes() const {
+ return FlatWorkGroupSizes;
+ }
+
+ /// \returns Default/requested minimum flat work group size for this function.
+ unsigned getMinFlatWorkGroupSize() const {
+ return FlatWorkGroupSizes.first;
+ }
+
+ /// \returns Default/requested maximum flat work group size for this function.
+ unsigned getMaxFlatWorkGroupSize() const {
+ return FlatWorkGroupSizes.second;
+ }
+
+ /// \returns A pair of default/requested minimum/maximum number of waves per
+ /// execution unit.
+ std::pair<unsigned, unsigned> getWavesPerEU() const {
+ return WavesPerEU;
+ }
+
+ /// \returns Default/requested minimum number of waves per execution unit.
+ unsigned getMinWavesPerEU() const {
+ return WavesPerEU.first;
+ }
+
+ /// \returns Default/requested maximum number of waves per execution unit.
+ unsigned getMaxWavesPerEU() const {
+ return WavesPerEU.second;
}
/// \returns Stack object index for \p Dim's work group ID.
@@ -413,7 +503,13 @@ public:
llvm_unreachable("unexpected dimension");
}
- unsigned getMaximumWorkGroupSize(const MachineFunction &MF) const;
+ const AMDGPUBufferPseudoSourceValue *getBufferPSV() const {
+ return &BufferPSV;
+ }
+
+ const AMDGPUImagePseudoSourceValue *getImagePSV() const {
+ return &ImagePSV;
+ }
};
} // End namespace llvm
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.cpp b/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.cpp
index 7125b41..da86bbf 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.cpp
@@ -1,4 +1,4 @@
-//===-- SIMachineScheduler.cpp - SI Scheduler Interface -*- C++ -*-----===//
+//===-- SIMachineScheduler.cpp - SI Scheduler Interface -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -13,12 +13,28 @@
//===----------------------------------------------------------------------===//
#include "AMDGPU.h"
+#include "SIInstrInfo.h"
#include "SIMachineScheduler.h"
+#include "SIRegisterInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/RegisterPressure.h"
+#include "llvm/CodeGen/SlotIndexes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <algorithm>
+#include <cassert>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
using namespace llvm;
@@ -77,11 +93,11 @@ using namespace llvm;
// The block creation algorithm is divided into several steps, and several
// variants can be tried during the scheduling process.
//
-// Second the order of the instructions inside the blocks is choosen.
+// Second the order of the instructions inside the blocks is chosen.
// At that step we do take into account only register usage and hiding
// low latency instructions
//
-// Third the block order is choosen, there we try to hide high latencies
+// Third the block order is chosen, there we try to hide high latencies
// and keep register usage low.
//
// After the third step, a pass is done to improve the hiding of low
@@ -89,7 +105,7 @@ using namespace llvm;
//
// Actually when talking about 'low latency' or 'high latency' it includes
// both the latency to get the cache (or global mem) data go to the register,
-// and the bandwith limitations.
+// and the bandwidth limitations.
// Increasing the number of active wavefronts helps hide the former, but it
// doesn't solve the latter, thus why even if wavefront count is high, we have
// to try have as many instructions hiding high latencies as possible.
@@ -120,7 +136,6 @@ using namespace llvm;
// 300-600 cycles. We do not specially take that into account when scheduling
// As we expect the driver to be able to preload the constants soon.
-
// common code //
#ifndef NDEBUG
@@ -181,7 +196,6 @@ void SIScheduleBlock::addUnit(SUnit *SU) {
}
#ifndef NDEBUG
-
void SIScheduleBlock::traceCandidate(const SISchedCandidate &Cand) {
dbgs() << " SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason);
@@ -209,7 +223,7 @@ void SIScheduleBlock::tryCandidateTopDown(SISchedCandidate &Cand,
// we haven't waited for
// . Low latencies
// . All other instructions
- // Goal is to get: low latency instructions - independant instructions
+ // Goal is to get: low latency instructions - independent instructions
// - (eventually some more low latency instructions)
// - instructions that depend on the first low latency instructions.
// If in the block there is a lot of constant loads, the SGPR usage
@@ -479,8 +493,7 @@ void SIScheduleBlock::releaseSuccessors(SUnit *SU, bool InOrOutBlock) {
void SIScheduleBlock::nodeScheduled(SUnit *SU) {
// Is in TopReadySUs
assert (!SU->NumPredsLeft);
- std::vector<SUnit*>::iterator I =
- std::find(TopReadySUs.begin(), TopReadySUs.end(), SU);
+ std::vector<SUnit *>::iterator I = llvm::find(TopReadySUs, SU);
if (I == TopReadySUs.end()) {
dbgs() << "Data Structure Bug in SI Scheduler\n";
llvm_unreachable(nullptr);
@@ -589,9 +602,8 @@ void SIScheduleBlock::printDebug(bool full) {
}
}
- dbgs() << "///////////////////////\n";
+ dbgs() << "///////////////////////\n";
}
-
#endif
// SIScheduleBlockCreator //
@@ -600,8 +612,7 @@ SIScheduleBlockCreator::SIScheduleBlockCreator(SIScheduleDAGMI *DAG) :
DAG(DAG) {
}
-SIScheduleBlockCreator::~SIScheduleBlockCreator() {
-}
+SIScheduleBlockCreator::~SIScheduleBlockCreator() = default;
SIScheduleBlocks
SIScheduleBlockCreator::getBlocks(SISchedulerBlockCreatorVariant BlockVariant) {
@@ -1059,8 +1070,7 @@ void SIScheduleBlockCreator::createBlocksForVariant(SISchedulerBlockCreatorVaria
unsigned Color = CurrentColoring[SU->NodeNum];
if (RealID.find(Color) == RealID.end()) {
int ID = CurrentBlocks.size();
- BlockPtrs.push_back(
- make_unique<SIScheduleBlock>(DAG, this, ID));
+ BlockPtrs.push_back(llvm::make_unique<SIScheduleBlock>(DAG, this, ID));
CurrentBlocks.push_back(BlockPtrs.rbegin()->get());
RealID[Color] = ID;
}
@@ -1104,30 +1114,17 @@ void SIScheduleBlockCreator::createBlocksForVariant(SISchedulerBlockCreatorVaria
// Two functions taken from Codegen/MachineScheduler.cpp
-/// If this iterator is a debug value, increment until reaching the End or a
-/// non-debug instruction.
-static MachineBasicBlock::const_iterator
-nextIfDebug(MachineBasicBlock::const_iterator I,
+/// Non-const version.
+static MachineBasicBlock::iterator
+nextIfDebug(MachineBasicBlock::iterator I,
MachineBasicBlock::const_iterator End) {
- for(; I != End; ++I) {
+ for (; I != End; ++I) {
if (!I->isDebugValue())
break;
}
return I;
}
-/// Non-const version.
-static MachineBasicBlock::iterator
-nextIfDebug(MachineBasicBlock::iterator I,
- MachineBasicBlock::const_iterator End) {
- // Cast the return value to nonconst MachineInstr, then cast to an
- // instr_iterator, which does not check for null, finally return a
- // bundle_iterator.
- return MachineBasicBlock::instr_iterator(
- const_cast<MachineInstr*>(
- &*nextIfDebug(MachineBasicBlock::const_iterator(I), End)));
-}
-
void SIScheduleBlockCreator::topologicalSort() {
unsigned DAGSize = CurrentBlocks.size();
std::vector<int> WorkList;
@@ -1217,7 +1214,7 @@ void SIScheduleBlockCreator::scheduleInsideBlocks() {
DAG->getBB()->splice(CurrentTopFastSched, DAG->getBB(), MI);
// Update LiveIntervals.
- // Note: Moving all instructions and calling handleMove everytime
+ // Note: Moving all instructions and calling handleMove every time
// is the most cpu intensive operation of the scheduler.
// It would gain a lot if there was a way to recompute the
// LiveIntervals for the entire scheduling region.
@@ -1265,7 +1262,7 @@ void SIScheduleBlockCreator::fillStats() {
for (unsigned i = 0, e = DAGSize; i != e; ++i) {
int BlockIndice = TopDownIndex2Block[i];
SIScheduleBlock *Block = CurrentBlocks[BlockIndice];
- if (Block->getPreds().size() == 0)
+ if (Block->getPreds().empty())
Block->Depth = 0;
else {
unsigned Depth = 0;
@@ -1280,7 +1277,7 @@ void SIScheduleBlockCreator::fillStats() {
for (unsigned i = 0, e = DAGSize; i != e; ++i) {
int BlockIndice = BottomUpIndex2Block[i];
SIScheduleBlock *Block = CurrentBlocks[BlockIndice];
- if (Block->getSuccs().size() == 0)
+ if (Block->getSuccs().empty())
Block->Height = 0;
else {
unsigned Height = 0;
@@ -1654,20 +1651,15 @@ SIScheduler::scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant,
// SIScheduleDAGMI //
SIScheduleDAGMI::SIScheduleDAGMI(MachineSchedContext *C) :
- ScheduleDAGMILive(C, make_unique<GenericScheduler>(C)) {
+ ScheduleDAGMILive(C, llvm::make_unique<GenericScheduler>(C)) {
SITII = static_cast<const SIInstrInfo*>(TII);
SITRI = static_cast<const SIRegisterInfo*>(TRI);
- VGPRSetID = SITRI->getVGPR32PressureSet();
- SGPRSetID = SITRI->getSGPR32PressureSet();
-}
-
-SIScheduleDAGMI::~SIScheduleDAGMI() {
+ VGPRSetID = SITRI->getVGPRPressureSet();
+ SGPRSetID = SITRI->getSGPRPressureSet();
}
-ScheduleDAGInstrs *llvm::createSIMachineScheduler(MachineSchedContext *C) {
- return new SIScheduleDAGMI(C);
-}
+SIScheduleDAGMI::~SIScheduleDAGMI() = default;
// Code adapted from scheduleDAG.cpp
// Does a topological sort over the SUs.
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.h b/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.h
index 117aed4..77c0735 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIMachineScheduler.h
@@ -1,4 +1,4 @@
-//===-- SIMachineScheduler.h - SI Scheduler Interface -*- C++ -*-------===//
+//===-- SIMachineScheduler.h - SI Scheduler Interface -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -16,10 +16,16 @@
#define LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H
#include "SIInstrInfo.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/RegisterPressure.h"
-
-using namespace llvm;
+#include "llvm/CodeGen/ScheduleDAG.h"
+#include <cassert>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <set>
+#include <vector>
namespace llvm {
@@ -93,12 +99,10 @@ class SIScheduleBlock {
public:
SIScheduleBlock(SIScheduleDAGMI *DAG, SIScheduleBlockCreator *BC,
unsigned ID):
- DAG(DAG), BC(BC), SUnits(), TopReadySUs(), ScheduledSUnits(),
- TopRPTracker(TopPressure), Scheduled(false),
- HighLatencyBlock(false), ID(ID),
- Preds(), Succs(), NumHighLatencySuccessors(0) {};
+ DAG(DAG), BC(BC), TopRPTracker(TopPressure), Scheduled(false),
+ HighLatencyBlock(false), ID(ID), NumHighLatencySuccessors(0) {}
- ~SIScheduleBlock() {};
+ ~SIScheduleBlock() = default;
unsigned getID() const { return ID; }
@@ -146,7 +150,6 @@ public:
bool isScheduled() { return Scheduled; }
-
// Needs the block to be scheduled inside
// TODO: find a way to compute it.
std::vector<unsigned> &getInternalAdditionnalRegUsage() {
@@ -161,7 +164,7 @@ public:
private:
struct SISchedCandidate : SISchedulerCandidate {
// The best SUnit candidate.
- SUnit *SU;
+ SUnit *SU = nullptr;
unsigned SGPRUsage;
unsigned VGPRUsage;
@@ -169,8 +172,7 @@ private:
unsigned LowLatencyOffset;
bool HasLowLatencyNonWaitedParent;
- SISchedCandidate()
- : SU(nullptr) {}
+ SISchedCandidate() = default;
bool isValid() const { return SU; }
@@ -341,17 +343,17 @@ public:
SIScheduleBlockScheduler(SIScheduleDAGMI *DAG,
SISchedulerBlockSchedulerVariant Variant,
SIScheduleBlocks BlocksStruct);
- ~SIScheduleBlockScheduler() {};
+ ~SIScheduleBlockScheduler() = default;
- std::vector<SIScheduleBlock*> getBlocks() { return BlocksScheduled; };
+ std::vector<SIScheduleBlock*> getBlocks() { return BlocksScheduled; }
- unsigned getVGPRUsage() { return maxVregUsage; };
- unsigned getSGPRUsage() { return maxSregUsage; };
+ unsigned getVGPRUsage() { return maxVregUsage; }
+ unsigned getSGPRUsage() { return maxSregUsage; }
private:
struct SIBlockSchedCandidate : SISchedulerCandidate {
// The best Block candidate.
- SIScheduleBlock *Block;
+ SIScheduleBlock *Block = nullptr;
bool IsHighLatency;
int VGPRUsageDiff;
@@ -360,8 +362,7 @@ private:
unsigned LastPosHighLatParentScheduled;
unsigned Height;
- SIBlockSchedCandidate()
- : Block(nullptr) {}
+ SIBlockSchedCandidate() = default;
bool isValid() const { return Block; }
@@ -409,9 +410,9 @@ class SIScheduler {
SIScheduleBlockCreator BlockCreator;
public:
- SIScheduler(SIScheduleDAGMI *DAG) : DAG(DAG), BlockCreator(DAG) {};
+ SIScheduler(SIScheduleDAGMI *DAG) : DAG(DAG), BlockCreator(DAG) {}
- ~SIScheduler() {};
+ ~SIScheduler() = default;
struct SIScheduleBlockResult
scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant,
@@ -445,13 +446,13 @@ public:
}
MachineBasicBlock *getBB() { return BB; }
- MachineBasicBlock::iterator getCurrentTop() { return CurrentTop; };
- MachineBasicBlock::iterator getCurrentBottom() { return CurrentBottom; };
+ MachineBasicBlock::iterator getCurrentTop() { return CurrentTop; }
+ MachineBasicBlock::iterator getCurrentBottom() { return CurrentBottom; }
LiveIntervals *getLIS() { return LIS; }
MachineRegisterInfo *getMRI() { return &MRI; }
const TargetRegisterInfo *getTRI() { return TRI; }
- SUnit& getEntrySU() { return EntrySU; };
- SUnit& getExitSU() { return ExitSU; };
+ SUnit& getEntrySU() { return EntrySU; }
+ SUnit& getExitSU() { return ExitSU; }
void restoreSULinksLeft();
@@ -459,13 +460,14 @@ public:
_Iterator End,
unsigned &VgprUsage,
unsigned &SgprUsage);
+
std::set<unsigned> getInRegs() {
std::set<unsigned> InRegs;
for (const auto &RegMaskPair : RPTracker.getPressure().LiveInRegs) {
InRegs.insert(RegMaskPair.RegUnit);
}
return InRegs;
- };
+ }
unsigned getVGPRSetID() const { return VGPRSetID; }
unsigned getSGPRSetID() const { return SGPRSetID; }
@@ -486,6 +488,6 @@ public:
std::vector<int> BottomUpIndex2SU;
};
-} // namespace llvm
+} // end namespace llvm
-#endif /* SIMACHINESCHEDULER_H_ */
+#endif // LLVM_LIB_TARGET_AMDGPU_SIMACHINESCHEDULER_H
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIOptimizeExecMasking.cpp b/contrib/llvm/lib/Target/AMDGPU/SIOptimizeExecMasking.cpp
new file mode 100644
index 0000000..4d2f917
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/SIOptimizeExecMasking.cpp
@@ -0,0 +1,304 @@
+//===-- SIOptimizeExecMasking.cpp -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "AMDGPUSubtarget.h"
+#include "SIInstrInfo.h"
+#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "si-optimize-exec-masking"
+
+namespace {
+
+class SIOptimizeExecMasking : public MachineFunctionPass {
+public:
+ static char ID;
+
+public:
+ SIOptimizeExecMasking() : MachineFunctionPass(ID) {
+ initializeSIOptimizeExecMaskingPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override {
+ return "SI optimize exec mask operations";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+};
+
+} // End anonymous namespace.
+
+INITIALIZE_PASS_BEGIN(SIOptimizeExecMasking, DEBUG_TYPE,
+ "SI optimize exec mask operations", false, false)
+INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
+INITIALIZE_PASS_END(SIOptimizeExecMasking, DEBUG_TYPE,
+ "SI optimize exec mask operations", false, false)
+
+char SIOptimizeExecMasking::ID = 0;
+
+char &llvm::SIOptimizeExecMaskingID = SIOptimizeExecMasking::ID;
+
+/// If \p MI is a copy from exec, return the register copied to.
+static unsigned isCopyFromExec(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case AMDGPU::COPY:
+ case AMDGPU::S_MOV_B64:
+ case AMDGPU::S_MOV_B64_term: {
+ const MachineOperand &Src = MI.getOperand(1);
+ if (Src.isReg() && Src.getReg() == AMDGPU::EXEC)
+ return MI.getOperand(0).getReg();
+ }
+ }
+
+ return AMDGPU::NoRegister;
+}
+
+/// If \p MI is a copy to exec, return the register copied from.
+static unsigned isCopyToExec(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case AMDGPU::COPY:
+ case AMDGPU::S_MOV_B64: {
+ const MachineOperand &Dst = MI.getOperand(0);
+ if (Dst.isReg() && Dst.getReg() == AMDGPU::EXEC)
+ return MI.getOperand(1).getReg();
+ break;
+ }
+ case AMDGPU::S_MOV_B64_term:
+ llvm_unreachable("should have been replaced");
+ }
+
+ return AMDGPU::NoRegister;
+}
+
+static unsigned getSaveExecOp(unsigned Opc) {
+ switch (Opc) {
+ case AMDGPU::S_AND_B64:
+ return AMDGPU::S_AND_SAVEEXEC_B64;
+ case AMDGPU::S_OR_B64:
+ return AMDGPU::S_OR_SAVEEXEC_B64;
+ case AMDGPU::S_XOR_B64:
+ return AMDGPU::S_XOR_SAVEEXEC_B64;
+ case AMDGPU::S_ANDN2_B64:
+ return AMDGPU::S_ANDN2_SAVEEXEC_B64;
+ case AMDGPU::S_ORN2_B64:
+ return AMDGPU::S_ORN2_SAVEEXEC_B64;
+ case AMDGPU::S_NAND_B64:
+ return AMDGPU::S_NAND_SAVEEXEC_B64;
+ case AMDGPU::S_NOR_B64:
+ return AMDGPU::S_NOR_SAVEEXEC_B64;
+ case AMDGPU::S_XNOR_B64:
+ return AMDGPU::S_XNOR_SAVEEXEC_B64;
+ default:
+ return AMDGPU::INSTRUCTION_LIST_END;
+ }
+}
+
+// These are only terminators to get correct spill code placement during
+// register allocation, so turn them back into normal instructions. Only one of
+// these is expected per block.
+static bool removeTerminatorBit(const SIInstrInfo &TII, MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case AMDGPU::S_MOV_B64_term: {
+ MI.setDesc(TII.get(AMDGPU::COPY));
+ return true;
+ }
+ case AMDGPU::S_XOR_B64_term: {
+ // This is only a terminator to get the correct spill code placement during
+ // register allocation.
+ MI.setDesc(TII.get(AMDGPU::S_XOR_B64));
+ return true;
+ }
+ case AMDGPU::S_ANDN2_B64_term: {
+ // This is only a terminator to get the correct spill code placement during
+ // register allocation.
+ MI.setDesc(TII.get(AMDGPU::S_ANDN2_B64));
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+static MachineBasicBlock::reverse_iterator fixTerminators(
+ const SIInstrInfo &TII,
+ MachineBasicBlock &MBB) {
+ MachineBasicBlock::reverse_iterator I = MBB.rbegin(), E = MBB.rend();
+ for (; I != E; ++I) {
+ if (!I->isTerminator())
+ return I;
+
+ if (removeTerminatorBit(TII, *I))
+ return I;
+ }
+
+ return E;
+}
+
+static MachineBasicBlock::reverse_iterator findExecCopy(
+ const SIInstrInfo &TII,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::reverse_iterator I,
+ unsigned CopyToExec) {
+ const unsigned InstLimit = 25;
+
+ auto E = MBB.rend();
+ for (unsigned N = 0; N <= InstLimit && I != E; ++I, ++N) {
+ unsigned CopyFromExec = isCopyFromExec(*I);
+ if (CopyFromExec != AMDGPU::NoRegister)
+ return I;
+ }
+
+ return E;
+}
+
+// XXX - Seems LivePhysRegs doesn't work correctly since it will incorrectly
+// repor tthe register as unavailable because a super-register with a lane mask
+// as unavailable.
+static bool isLiveOut(const MachineBasicBlock &MBB, unsigned Reg) {
+ for (MachineBasicBlock *Succ : MBB.successors()) {
+ if (Succ->isLiveIn(Reg))
+ return true;
+ }
+
+ return false;
+}
+
+bool SIOptimizeExecMasking::runOnMachineFunction(MachineFunction &MF) {
+ const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
+ const SIRegisterInfo *TRI = ST.getRegisterInfo();
+ const SIInstrInfo *TII = ST.getInstrInfo();
+
+ // Optimize sequences emitted for control flow lowering. They are originally
+ // emitted as the separate operations because spill code may need to be
+ // inserted for the saved copy of exec.
+ //
+ // x = copy exec
+ // z = s_<op>_b64 x, y
+ // exec = copy z
+ // =>
+ // x = s_<op>_saveexec_b64 y
+ //
+
+ for (MachineBasicBlock &MBB : MF) {
+ MachineBasicBlock::reverse_iterator I = fixTerminators(*TII, MBB);
+ MachineBasicBlock::reverse_iterator E = MBB.rend();
+ if (I == E)
+ continue;
+
+ unsigned CopyToExec = isCopyToExec(*I);
+ if (CopyToExec == AMDGPU::NoRegister)
+ continue;
+
+ // Scan backwards to find the def.
+ auto CopyToExecInst = &*I;
+ auto CopyFromExecInst = findExecCopy(*TII, MBB, I, CopyToExec);
+ if (CopyFromExecInst == E)
+ continue;
+
+ if (isLiveOut(MBB, CopyToExec)) {
+ // The copied register is live out and has a second use in another block.
+ DEBUG(dbgs() << "Exec copy source register is live out\n");
+ continue;
+ }
+
+ unsigned CopyFromExec = CopyFromExecInst->getOperand(0).getReg();
+ MachineInstr *SaveExecInst = nullptr;
+ SmallVector<MachineInstr *, 4> OtherUseInsts;
+
+ for (MachineBasicBlock::iterator J
+ = std::next(CopyFromExecInst->getIterator()), JE = I->getIterator();
+ J != JE; ++J) {
+ if (SaveExecInst && J->readsRegister(AMDGPU::EXEC, TRI)) {
+ DEBUG(dbgs() << "exec read prevents saveexec: " << *J << '\n');
+ // Make sure this is inserted after any VALU ops that may have been
+ // scheduled in between.
+ SaveExecInst = nullptr;
+ break;
+ }
+
+ if (J->modifiesRegister(CopyToExec, TRI)) {
+ if (SaveExecInst) {
+ DEBUG(dbgs() << "Multiple instructions modify "
+ << PrintReg(CopyToExec, TRI) << '\n');
+ SaveExecInst = nullptr;
+ break;
+ }
+
+ unsigned SaveExecOp = getSaveExecOp(J->getOpcode());
+ if (SaveExecOp == AMDGPU::INSTRUCTION_LIST_END)
+ break;
+
+ if (J->readsRegister(CopyFromExec, TRI)) {
+ SaveExecInst = &*J;
+ DEBUG(dbgs() << "Found save exec op: " << *SaveExecInst << '\n');
+ continue;
+ } else {
+ DEBUG(dbgs() << "Instruction does not read exec copy: " << *J << '\n');
+ break;
+ }
+ }
+
+ if (SaveExecInst && J->readsRegister(CopyToExec, TRI)) {
+ assert(SaveExecInst != &*J);
+ OtherUseInsts.push_back(&*J);
+ }
+ }
+
+ if (!SaveExecInst)
+ continue;
+
+ DEBUG(dbgs() << "Insert save exec op: " << *SaveExecInst << '\n');
+
+ MachineOperand &Src0 = SaveExecInst->getOperand(1);
+ MachineOperand &Src1 = SaveExecInst->getOperand(2);
+
+ MachineOperand *OtherOp = nullptr;
+
+ if (Src0.isReg() && Src0.getReg() == CopyFromExec) {
+ OtherOp = &Src1;
+ } else if (Src1.isReg() && Src1.getReg() == CopyFromExec) {
+ if (!SaveExecInst->isCommutable())
+ break;
+
+ OtherOp = &Src0;
+ } else
+ llvm_unreachable("unexpected");
+
+ CopyFromExecInst->eraseFromParent();
+
+ auto InsPt = SaveExecInst->getIterator();
+ const DebugLoc &DL = SaveExecInst->getDebugLoc();
+
+ BuildMI(MBB, InsPt, DL, TII->get(getSaveExecOp(SaveExecInst->getOpcode())),
+ CopyFromExec)
+ .addReg(OtherOp->getReg());
+ SaveExecInst->eraseFromParent();
+
+ CopyToExecInst->eraseFromParent();
+
+ for (MachineInstr *OtherInst : OtherUseInsts) {
+ OtherInst->substituteRegister(CopyToExec, AMDGPU::EXEC,
+ AMDGPU::NoSubRegister, *TRI);
+ }
+ }
+
+ return true;
+
+}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index 347c33f..a1ed5e8 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -24,52 +24,11 @@
using namespace llvm;
-static unsigned getMaxWaveCountPerSIMD(const MachineFunction &MF) {
- const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
- const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
- unsigned SIMDPerCU = 4;
-
- unsigned MaxInvocationsPerWave = SIMDPerCU * ST.getWavefrontSize();
- return alignTo(MFI.getMaximumWorkGroupSize(MF), MaxInvocationsPerWave) /
- MaxInvocationsPerWave;
-}
-
-static unsigned getMaxWorkGroupSGPRCount(const MachineFunction &MF) {
- const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
- unsigned MaxWaveCountPerSIMD = getMaxWaveCountPerSIMD(MF);
-
- unsigned TotalSGPRCountPerSIMD, AddressableSGPRCount, SGPRUsageAlignment;
- unsigned ReservedSGPRCount;
-
- if (ST.getGeneration() >= SISubtarget::VOLCANIC_ISLANDS) {
- TotalSGPRCountPerSIMD = 800;
- AddressableSGPRCount = 102;
- SGPRUsageAlignment = 16;
- ReservedSGPRCount = 6; // VCC, FLAT_SCRATCH, XNACK
- } else {
- TotalSGPRCountPerSIMD = 512;
- AddressableSGPRCount = 104;
- SGPRUsageAlignment = 8;
- ReservedSGPRCount = 2; // VCC
- }
+static cl::opt<bool> EnableSpillSGPRToSMEM(
+ "amdgpu-spill-sgpr-to-smem",
+ cl::desc("Use scalar stores to spill SGPRs if supported by subtarget"),
+ cl::init(false));
- unsigned MaxSGPRCount = (TotalSGPRCountPerSIMD / MaxWaveCountPerSIMD);
- MaxSGPRCount = alignDown(MaxSGPRCount, SGPRUsageAlignment);
-
- if (ST.hasSGPRInitBug())
- MaxSGPRCount = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG;
-
- return std::min(MaxSGPRCount - ReservedSGPRCount, AddressableSGPRCount);
-}
-
-static unsigned getMaxWorkGroupVGPRCount(const MachineFunction &MF) {
- unsigned MaxWaveCountPerSIMD = getMaxWaveCountPerSIMD(MF);
- unsigned TotalVGPRCountPerSIMD = 256;
- unsigned VGPRUsageAlignment = 4;
-
- return alignDown(TotalVGPRCountPerSIMD / MaxWaveCountPerSIMD,
- VGPRUsageAlignment);
-}
static bool hasPressureSet(const int *PSets, unsigned PSetID) {
for (unsigned i = 0; PSets[i] != -1; ++i) {
@@ -95,19 +54,38 @@ SIRegisterInfo::SIRegisterInfo() : AMDGPURegisterInfo(),
VGPRPressureSets(getNumRegPressureSets()) {
unsigned NumRegPressureSets = getNumRegPressureSets();
- SGPR32SetID = NumRegPressureSets;
- VGPR32SetID = NumRegPressureSets;
- for (unsigned i = 0; i < NumRegPressureSets; ++i) {
- if (strncmp("SGPR_32", getRegPressureSetName(i), 7) == 0)
- SGPR32SetID = i;
- else if (strncmp("VGPR_32", getRegPressureSetName(i), 7) == 0)
- VGPR32SetID = i;
+ SGPRSetID = NumRegPressureSets;
+ VGPRSetID = NumRegPressureSets;
+ for (unsigned i = 0; i < NumRegPressureSets; ++i) {
classifyPressureSet(i, AMDGPU::SGPR0, SGPRPressureSets);
classifyPressureSet(i, AMDGPU::VGPR0, VGPRPressureSets);
}
- assert(SGPR32SetID < NumRegPressureSets &&
- VGPR32SetID < NumRegPressureSets);
+
+ // Determine the number of reg units for each pressure set.
+ std::vector<unsigned> PressureSetRegUnits(NumRegPressureSets, 0);
+ for (unsigned i = 0, e = getNumRegUnits(); i != e; ++i) {
+ const int *PSets = getRegUnitPressureSets(i);
+ for (unsigned j = 0; PSets[j] != -1; ++j) {
+ ++PressureSetRegUnits[PSets[j]];
+ }
+ }
+
+ unsigned VGPRMax = 0, SGPRMax = 0;
+ for (unsigned i = 0; i < NumRegPressureSets; ++i) {
+ if (isVGPRPressureSet(i) && PressureSetRegUnits[i] > VGPRMax) {
+ VGPRSetID = i;
+ VGPRMax = PressureSetRegUnits[i];
+ continue;
+ }
+ if (isSGPRPressureSet(i) && PressureSetRegUnits[i] > SGPRMax) {
+ SGPRSetID = i;
+ SGPRMax = PressureSetRegUnits[i];
+ }
+ }
+
+ assert(SGPRSetID < NumRegPressureSets &&
+ VGPRSetID < NumRegPressureSets);
}
void SIRegisterInfo::reserveRegisterTuples(BitVector &Reserved, unsigned Reg) const {
@@ -119,14 +97,14 @@ void SIRegisterInfo::reserveRegisterTuples(BitVector &Reserved, unsigned Reg) co
unsigned SIRegisterInfo::reservedPrivateSegmentBufferReg(
const MachineFunction &MF) const {
- unsigned BaseIdx = alignDown(getMaxWorkGroupSGPRCount(MF), 4) - 4;
+ unsigned BaseIdx = alignDown(getMaxNumSGPRs(MF), 4) - 4;
unsigned BaseReg(AMDGPU::SGPR_32RegClass.getRegister(BaseIdx));
return getMatchingSuperReg(BaseReg, AMDGPU::sub0, &AMDGPU::SReg_128RegClass);
}
unsigned SIRegisterInfo::reservedPrivateSegmentWaveByteOffsetReg(
const MachineFunction &MF) const {
- unsigned RegCount = getMaxWorkGroupSGPRCount(MF);
+ unsigned RegCount = getMaxNumSGPRs(MF);
unsigned Reg;
// Try to place it in a hole after PrivateSegmentbufferReg.
@@ -161,18 +139,16 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
reserveRegisterTuples(Reserved, AMDGPU::TTMP8_TTMP9);
reserveRegisterTuples(Reserved, AMDGPU::TTMP10_TTMP11);
- unsigned MaxWorkGroupSGPRCount = getMaxWorkGroupSGPRCount(MF);
- unsigned MaxWorkGroupVGPRCount = getMaxWorkGroupVGPRCount(MF);
-
- unsigned NumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs();
- unsigned NumVGPRs = AMDGPU::VGPR_32RegClass.getNumRegs();
- for (unsigned i = MaxWorkGroupSGPRCount; i < NumSGPRs; ++i) {
+ unsigned MaxNumSGPRs = getMaxNumSGPRs(MF);
+ unsigned TotalNumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs();
+ for (unsigned i = MaxNumSGPRs; i < TotalNumSGPRs; ++i) {
unsigned Reg = AMDGPU::SGPR_32RegClass.getRegister(i);
reserveRegisterTuples(Reserved, Reg);
}
-
- for (unsigned i = MaxWorkGroupVGPRCount; i < NumVGPRs; ++i) {
+ unsigned MaxNumVGPRs = getMaxNumVGPRs(MF);
+ unsigned TotalNumVGPRs = AMDGPU::VGPR_32RegClass.getNumRegs();
+ for (unsigned i = MaxNumVGPRs; i < TotalNumVGPRs; ++i) {
unsigned Reg = AMDGPU::VGPR_32RegClass.getRegister(i);
reserveRegisterTuples(Reserved, Reg);
}
@@ -194,49 +170,26 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
assert(!isSubRegister(ScratchRSrcReg, ScratchWaveOffsetReg));
}
- // Reserve registers for debugger usage if "amdgpu-debugger-reserve-trap-regs"
- // attribute was specified.
- const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
- if (ST.debuggerReserveRegs()) {
- unsigned ReservedVGPRFirst =
- MaxWorkGroupVGPRCount - MFI->getDebuggerReservedVGPRCount();
- for (unsigned i = ReservedVGPRFirst; i < MaxWorkGroupVGPRCount; ++i) {
- unsigned Reg = AMDGPU::VGPR_32RegClass.getRegister(i);
- reserveRegisterTuples(Reserved, Reg);
- }
- }
-
return Reserved;
}
-unsigned SIRegisterInfo::getRegPressureSetLimit(const MachineFunction &MF,
- unsigned Idx) const {
- const SISubtarget &STI = MF.getSubtarget<SISubtarget>();
- // FIXME: We should adjust the max number of waves based on LDS size.
- unsigned SGPRLimit = getNumSGPRsAllowed(STI, STI.getMaxWavesPerCU());
- unsigned VGPRLimit = getNumVGPRsAllowed(STI.getMaxWavesPerCU());
-
- unsigned VSLimit = SGPRLimit + VGPRLimit;
-
- if (SGPRPressureSets.test(Idx) && VGPRPressureSets.test(Idx)) {
- // FIXME: This is a hack. We should never be considering the pressure of
- // these since no virtual register should ever have this class.
- return VSLimit;
- }
-
- if (SGPRPressureSets.test(Idx))
- return SGPRLimit;
-
- return VGPRLimit;
-}
-
bool SIRegisterInfo::requiresRegisterScavenging(const MachineFunction &Fn) const {
- return Fn.getFrameInfo()->hasStackObjects();
+ return Fn.getFrameInfo().hasStackObjects();
}
bool
SIRegisterInfo::requiresFrameIndexScavenging(const MachineFunction &MF) const {
- return MF.getFrameInfo()->hasStackObjects();
+ return MF.getFrameInfo().hasStackObjects();
+}
+
+bool SIRegisterInfo::requiresFrameIndexReplacementScavenging(
+ const MachineFunction &MF) const {
+ // m0 is needed for the scalar store offset. m0 is unallocatable, so we can't
+ // create a virtual register for it during frame index elimination, so the
+ // scavenger is directly needed.
+ return MF.getFrameInfo().hasStackObjects() &&
+ MF.getSubtarget<SISubtarget>().hasScalarStores() &&
+ MF.getInfo<SIMachineFunctionInfo>()->hasSpilledSGPRs();
}
bool SIRegisterInfo::requiresVirtualBaseRegisters(
@@ -250,6 +203,14 @@ bool SIRegisterInfo::trackLivenessAfterRegAlloc(const MachineFunction &MF) const
return true;
}
+int64_t SIRegisterInfo::getMUBUFInstrOffset(const MachineInstr *MI) const {
+ assert(SIInstrInfo::isMUBUF(*MI));
+
+ int OffIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(),
+ AMDGPU::OpName::offset);
+ return MI->getOperand(OffIdx).getImm();
+}
+
int64_t SIRegisterInfo::getFrameIndexInstrOffset(const MachineInstr *MI,
int Idx) const {
if (!SIInstrInfo::isMUBUF(*MI))
@@ -259,13 +220,16 @@ int64_t SIRegisterInfo::getFrameIndexInstrOffset(const MachineInstr *MI,
AMDGPU::OpName::vaddr) &&
"Should never see frame index on non-address operand");
- int OffIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(),
- AMDGPU::OpName::offset);
- return MI->getOperand(OffIdx).getImm();
+ return getMUBUFInstrOffset(MI);
}
bool SIRegisterInfo::needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const {
- return MI->mayLoadOrStore();
+ if (!MI->mayLoadOrStore())
+ return false;
+
+ int64_t FullOffset = Offset + getMUBUFInstrOffset(MI);
+
+ return !isUInt<12>(FullOffset);
}
void SIRegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB,
@@ -290,14 +254,19 @@ void SIRegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB,
MachineRegisterInfo &MRI = MF->getRegInfo();
unsigned UnusedCarry = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
- unsigned OffsetReg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ unsigned OffsetReg = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+
+ unsigned FIReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
BuildMI(*MBB, Ins, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
.addImm(Offset);
+ BuildMI(*MBB, Ins, DL, TII->get(AMDGPU::V_MOV_B32_e32), FIReg)
+ .addFrameIndex(FrameIdx);
+
BuildMI(*MBB, Ins, DL, TII->get(AMDGPU::V_ADD_I32_e64), BaseReg)
.addReg(UnusedCarry, RegState::Define | RegState::Dead)
.addReg(OffsetReg, RegState::Kill)
- .addFrameIndex(FrameIdx);
+ .addReg(FIReg);
}
void SIRegisterInfo::resolveFrameIndex(MachineInstr &MI, unsigned BaseReg,
@@ -328,40 +297,21 @@ void SIRegisterInfo::resolveFrameIndex(MachineInstr &MI, unsigned BaseReg,
MachineOperand *OffsetOp = TII->getNamedOperand(MI, AMDGPU::OpName::offset);
int64_t NewOffset = OffsetOp->getImm() + Offset;
- if (isUInt<12>(NewOffset)) {
- // If we have a legal offset, fold it directly into the instruction.
- FIOp->ChangeToRegister(BaseReg, false);
- OffsetOp->setImm(NewOffset);
- return;
- }
-
- // The offset is not legal, so we must insert an add of the offset.
- MachineRegisterInfo &MRI = MF->getRegInfo();
- unsigned NewReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
- DebugLoc DL = MI.getDebugLoc();
-
- assert(Offset != 0 && "Non-zero offset expected");
-
- unsigned UnusedCarry = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
- unsigned OffsetReg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ assert(isUInt<12>(NewOffset) && "offset should be legal");
- // In the case the instruction already had an immediate offset, here only
- // the requested new offset is added because we are leaving the original
- // immediate in place.
- BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
- .addImm(Offset);
- BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_ADD_I32_e64), NewReg)
- .addReg(UnusedCarry, RegState::Define | RegState::Dead)
- .addReg(OffsetReg, RegState::Kill)
- .addReg(BaseReg);
-
- FIOp->ChangeToRegister(NewReg, false);
+ FIOp->ChangeToRegister(BaseReg, false);
+ OffsetOp->setImm(NewOffset);
}
bool SIRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI,
unsigned BaseReg,
int64_t Offset) const {
- return SIInstrInfo::isMUBUF(*MI) && isUInt<12>(Offset);
+ if (!SIInstrInfo::isMUBUF(*MI))
+ return false;
+
+ int64_t NewOffset = Offset + getMUBUFInstrOffset(MI);
+
+ return isUInt<12>(NewOffset);
}
const TargetRegisterClass *SIRegisterInfo::getPointerRegClass(
@@ -407,31 +357,107 @@ static unsigned getNumSubRegsForSpillOp(unsigned Op) {
}
}
-void SIRegisterInfo::buildScratchLoadStore(MachineBasicBlock::iterator MI,
- unsigned LoadStoreOp,
- const MachineOperand *SrcDst,
- unsigned ScratchRsrcReg,
- unsigned ScratchOffset,
- int64_t Offset,
- RegScavenger *RS) const {
+static int getOffsetMUBUFStore(unsigned Opc) {
+ switch (Opc) {
+ case AMDGPU::BUFFER_STORE_DWORD_OFFEN:
+ return AMDGPU::BUFFER_STORE_DWORD_OFFSET;
+ case AMDGPU::BUFFER_STORE_BYTE_OFFEN:
+ return AMDGPU::BUFFER_STORE_BYTE_OFFSET;
+ case AMDGPU::BUFFER_STORE_SHORT_OFFEN:
+ return AMDGPU::BUFFER_STORE_SHORT_OFFSET;
+ case AMDGPU::BUFFER_STORE_DWORDX2_OFFEN:
+ return AMDGPU::BUFFER_STORE_DWORDX2_OFFSET;
+ case AMDGPU::BUFFER_STORE_DWORDX4_OFFEN:
+ return AMDGPU::BUFFER_STORE_DWORDX4_OFFSET;
+ default:
+ return -1;
+ }
+}
+
+static int getOffsetMUBUFLoad(unsigned Opc) {
+ switch (Opc) {
+ case AMDGPU::BUFFER_LOAD_DWORD_OFFEN:
+ return AMDGPU::BUFFER_LOAD_DWORD_OFFSET;
+ case AMDGPU::BUFFER_LOAD_UBYTE_OFFEN:
+ return AMDGPU::BUFFER_LOAD_UBYTE_OFFSET;
+ case AMDGPU::BUFFER_LOAD_SBYTE_OFFEN:
+ return AMDGPU::BUFFER_LOAD_SBYTE_OFFSET;
+ case AMDGPU::BUFFER_LOAD_USHORT_OFFEN:
+ return AMDGPU::BUFFER_LOAD_USHORT_OFFSET;
+ case AMDGPU::BUFFER_LOAD_SSHORT_OFFEN:
+ return AMDGPU::BUFFER_LOAD_SSHORT_OFFSET;
+ case AMDGPU::BUFFER_LOAD_DWORDX2_OFFEN:
+ return AMDGPU::BUFFER_LOAD_DWORDX2_OFFSET;
+ case AMDGPU::BUFFER_LOAD_DWORDX4_OFFEN:
+ return AMDGPU::BUFFER_LOAD_DWORDX4_OFFSET;
+ default:
+ return -1;
+ }
+}
- unsigned Value = SrcDst->getReg();
- bool IsKill = SrcDst->isKill();
+// This differs from buildSpillLoadStore by only scavenging a VGPR. It does not
+// need to handle the case where an SGPR may need to be spilled while spilling.
+static bool buildMUBUFOffsetLoadStore(const SIInstrInfo *TII,
+ MachineFrameInfo &MFI,
+ MachineBasicBlock::iterator MI,
+ int Index,
+ int64_t Offset) {
+ MachineBasicBlock *MBB = MI->getParent();
+ const DebugLoc &DL = MI->getDebugLoc();
+ bool IsStore = MI->mayStore();
+
+ unsigned Opc = MI->getOpcode();
+ int LoadStoreOp = IsStore ?
+ getOffsetMUBUFStore(Opc) : getOffsetMUBUFLoad(Opc);
+ if (LoadStoreOp == -1)
+ return false;
+
+ unsigned Reg = TII->getNamedOperand(*MI, AMDGPU::OpName::vdata)->getReg();
+
+ BuildMI(*MBB, MI, DL, TII->get(LoadStoreOp))
+ .addReg(Reg, getDefRegState(!IsStore))
+ .addOperand(*TII->getNamedOperand(*MI, AMDGPU::OpName::srsrc))
+ .addOperand(*TII->getNamedOperand(*MI, AMDGPU::OpName::soffset))
+ .addImm(Offset)
+ .addImm(0) // glc
+ .addImm(0) // slc
+ .addImm(0) // tfe
+ .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ return true;
+}
+
+void SIRegisterInfo::buildSpillLoadStore(MachineBasicBlock::iterator MI,
+ unsigned LoadStoreOp,
+ int Index,
+ unsigned ValueReg,
+ bool IsKill,
+ unsigned ScratchRsrcReg,
+ unsigned ScratchOffsetReg,
+ int64_t InstOffset,
+ MachineMemOperand *MMO,
+ RegScavenger *RS) const {
MachineBasicBlock *MBB = MI->getParent();
MachineFunction *MF = MI->getParent()->getParent();
const SISubtarget &ST = MF->getSubtarget<SISubtarget>();
const SIInstrInfo *TII = ST.getInstrInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
- DebugLoc DL = MI->getDebugLoc();
- bool IsStore = MI->mayStore();
+ const MCInstrDesc &Desc = TII->get(LoadStoreOp);
+ const DebugLoc &DL = MI->getDebugLoc();
+ bool IsStore = Desc.mayStore();
bool RanOutOfSGPRs = false;
bool Scavenged = false;
- unsigned SOffset = ScratchOffset;
- unsigned OriginalImmOffset = Offset;
+ unsigned SOffset = ScratchOffsetReg;
- unsigned NumSubRegs = getNumSubRegsForSpillOp(MI->getOpcode());
+ const TargetRegisterClass *RC = getRegClassForReg(MF->getRegInfo(), ValueReg);
+ unsigned NumSubRegs = AMDGPU::getRegBitWidth(RC->getID()) / 32;
unsigned Size = NumSubRegs * 4;
+ int64_t Offset = InstOffset + MFI.getObjectOffset(Index);
+ const int64_t OriginalImmOffset = Offset;
+
+ unsigned Align = MFI.getObjectAlignment(Index);
+ const MachinePointerInfo &BasePtrInfo = MMO->getPointerInfo();
if (!isUInt<12>(Offset + Size)) {
SOffset = AMDGPU::NoRegister;
@@ -450,20 +476,23 @@ void SIRegisterInfo::buildScratchLoadStore(MachineBasicBlock::iterator MI,
// subtract the offset after the spill to return ScratchOffset to it's
// original value.
RanOutOfSGPRs = true;
- SOffset = ScratchOffset;
+ SOffset = ScratchOffsetReg;
} else {
Scavenged = true;
}
+
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), SOffset)
- .addReg(ScratchOffset)
- .addImm(Offset);
+ .addReg(ScratchOffsetReg)
+ .addImm(Offset);
+
Offset = 0;
}
- for (unsigned i = 0, e = NumSubRegs; i != e; ++i, Offset += 4) {
- unsigned SubReg = NumSubRegs > 1 ?
- getPhysRegSubReg(Value, &AMDGPU::VGPR_32RegClass, i) :
- Value;
+ const unsigned EltSize = 4;
+
+ for (unsigned i = 0, e = NumSubRegs; i != e; ++i, Offset += EltSize) {
+ unsigned SubReg = NumSubRegs == 1 ?
+ ValueReg : getSubReg(ValueReg, getSubRegFromChannel(i));
unsigned SOffsetRegState = 0;
unsigned SrcDstRegState = getDefRegState(!IsStore);
@@ -473,23 +502,324 @@ void SIRegisterInfo::buildScratchLoadStore(MachineBasicBlock::iterator MI,
SrcDstRegState |= getKillRegState(IsKill);
}
- BuildMI(*MBB, MI, DL, TII->get(LoadStoreOp))
- .addReg(SubReg, getDefRegState(!IsStore))
+ MachinePointerInfo PInfo = BasePtrInfo.getWithOffset(EltSize * i);
+ MachineMemOperand *NewMMO
+ = MF->getMachineMemOperand(PInfo, MMO->getFlags(),
+ EltSize, MinAlign(Align, EltSize * i));
+
+ auto MIB = BuildMI(*MBB, MI, DL, Desc)
+ .addReg(SubReg, getDefRegState(!IsStore) | getKillRegState(IsKill))
.addReg(ScratchRsrcReg)
.addReg(SOffset, SOffsetRegState)
.addImm(Offset)
.addImm(0) // glc
.addImm(0) // slc
.addImm(0) // tfe
- .addReg(Value, RegState::Implicit | SrcDstRegState)
- .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ .addMemOperand(NewMMO);
+
+ if (NumSubRegs > 1)
+ MIB.addReg(ValueReg, RegState::Implicit | SrcDstRegState);
}
+
if (RanOutOfSGPRs) {
// Subtract the offset we added to the ScratchOffset register.
- BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_SUB_U32), ScratchOffset)
- .addReg(ScratchOffset)
- .addImm(OriginalImmOffset);
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_SUB_U32), ScratchOffsetReg)
+ .addReg(ScratchOffsetReg)
+ .addImm(OriginalImmOffset);
+ }
+}
+
+static std::pair<unsigned, unsigned> getSpillEltSize(unsigned SuperRegSize,
+ bool Store) {
+ if (SuperRegSize % 16 == 0) {
+ return { 16, Store ? AMDGPU::S_BUFFER_STORE_DWORDX4_SGPR :
+ AMDGPU::S_BUFFER_LOAD_DWORDX4_SGPR };
+ }
+
+ if (SuperRegSize % 8 == 0) {
+ return { 8, Store ? AMDGPU::S_BUFFER_STORE_DWORDX2_SGPR :
+ AMDGPU::S_BUFFER_LOAD_DWORDX2_SGPR };
}
+
+ return { 4, Store ? AMDGPU::S_BUFFER_STORE_DWORD_SGPR :
+ AMDGPU::S_BUFFER_LOAD_DWORD_SGPR};
+}
+
+void SIRegisterInfo::spillSGPR(MachineBasicBlock::iterator MI,
+ int Index,
+ RegScavenger *RS) const {
+ MachineBasicBlock *MBB = MI->getParent();
+ MachineFunction *MF = MBB->getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ const SISubtarget &ST = MF->getSubtarget<SISubtarget>();
+ const SIInstrInfo *TII = ST.getInstrInfo();
+
+ unsigned SuperReg = MI->getOperand(0).getReg();
+ bool IsKill = MI->getOperand(0).isKill();
+ const DebugLoc &DL = MI->getDebugLoc();
+
+ SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
+ MachineFrameInfo &FrameInfo = MF->getFrameInfo();
+
+ bool SpillToSMEM = ST.hasScalarStores() && EnableSpillSGPRToSMEM;
+
+ assert(SuperReg != AMDGPU::M0 && "m0 should never spill");
+
+ unsigned OffsetReg = AMDGPU::M0;
+ unsigned M0CopyReg = AMDGPU::NoRegister;
+
+ if (SpillToSMEM) {
+ if (RS->isRegUsed(AMDGPU::M0)) {
+ M0CopyReg = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::COPY), M0CopyReg)
+ .addReg(AMDGPU::M0);
+ }
+ }
+
+ unsigned ScalarStoreOp;
+ unsigned EltSize = 4;
+ const TargetRegisterClass *RC = getPhysRegClass(SuperReg);
+ if (SpillToSMEM && isSGPRClass(RC)) {
+ // XXX - if private_element_size is larger than 4 it might be useful to be
+ // able to spill wider vmem spills.
+ std::tie(EltSize, ScalarStoreOp) = getSpillEltSize(RC->getSize(), true);
+ }
+
+ ArrayRef<int16_t> SplitParts = getRegSplitParts(RC, EltSize);
+ unsigned NumSubRegs = SplitParts.empty() ? 1 : SplitParts.size();
+
+ // SubReg carries the "Kill" flag when SubReg == SuperReg.
+ unsigned SubKillState = getKillRegState((NumSubRegs == 1) && IsKill);
+ for (unsigned i = 0, e = NumSubRegs; i < e; ++i) {
+ unsigned SubReg = NumSubRegs == 1 ?
+ SuperReg : getSubReg(SuperReg, SplitParts[i]);
+
+ if (SpillToSMEM) {
+ int64_t FrOffset = FrameInfo.getObjectOffset(Index);
+
+ // The allocated memory size is really the wavefront size * the frame
+ // index size. The widest register class is 64 bytes, so a 4-byte scratch
+ // allocation is enough to spill this in a single stack object.
+ //
+ // FIXME: Frame size/offsets are computed earlier than this, so the extra
+ // space is still unnecessarily allocated.
+
+ unsigned Align = FrameInfo.getObjectAlignment(Index);
+ MachinePointerInfo PtrInfo
+ = MachinePointerInfo::getFixedStack(*MF, Index, EltSize * i);
+ MachineMemOperand *MMO
+ = MF->getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
+ EltSize, MinAlign(Align, EltSize * i));
+
+ // SMEM instructions only support a single offset, so increment the wave
+ // offset.
+
+ int64_t Offset = (ST.getWavefrontSize() * FrOffset) + (EltSize * i);
+ if (Offset != 0) {
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), OffsetReg)
+ .addReg(MFI->getScratchWaveOffsetReg())
+ .addImm(Offset);
+ } else {
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
+ .addReg(MFI->getScratchWaveOffsetReg());
+ }
+
+ BuildMI(*MBB, MI, DL, TII->get(ScalarStoreOp))
+ .addReg(SubReg, getKillRegState(IsKill)) // sdata
+ .addReg(MFI->getScratchRSrcReg()) // sbase
+ .addReg(OffsetReg, RegState::Kill) // soff
+ .addImm(0) // glc
+ .addMemOperand(MMO);
+
+ continue;
+ }
+
+ struct SIMachineFunctionInfo::SpilledReg Spill =
+ MFI->getSpilledReg(MF, Index, i);
+ if (Spill.hasReg()) {
+ BuildMI(*MBB, MI, DL,
+ TII->getMCOpcodeFromPseudo(AMDGPU::V_WRITELANE_B32),
+ Spill.VGPR)
+ .addReg(SubReg, getKillRegState(IsKill))
+ .addImm(Spill.Lane);
+
+ // FIXME: Since this spills to another register instead of an actual
+ // frame index, we should delete the frame index when all references to
+ // it are fixed.
+ } else {
+ // Spill SGPR to a frame index.
+ // TODO: Should VI try to spill to VGPR and then spill to SMEM?
+ unsigned TmpReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ // TODO: Should VI try to spill to VGPR and then spill to SMEM?
+
+ MachineInstrBuilder Mov
+ = BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), TmpReg)
+ .addReg(SubReg, SubKillState);
+
+
+ // There could be undef components of a spilled super register.
+ // TODO: Can we detect this and skip the spill?
+ if (NumSubRegs > 1) {
+ // The last implicit use of the SuperReg carries the "Kill" flag.
+ unsigned SuperKillState = 0;
+ if (i + 1 == e)
+ SuperKillState |= getKillRegState(IsKill);
+ Mov.addReg(SuperReg, RegState::Implicit | SuperKillState);
+ }
+
+ unsigned Align = FrameInfo.getObjectAlignment(Index);
+ MachinePointerInfo PtrInfo
+ = MachinePointerInfo::getFixedStack(*MF, Index, EltSize * i);
+ MachineMemOperand *MMO
+ = MF->getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
+ EltSize, MinAlign(Align, EltSize * i));
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_SAVE))
+ .addReg(TmpReg, RegState::Kill) // src
+ .addFrameIndex(Index) // vaddr
+ .addReg(MFI->getScratchRSrcReg()) // srrsrc
+ .addReg(MFI->getScratchWaveOffsetReg()) // soffset
+ .addImm(i * 4) // offset
+ .addMemOperand(MMO);
+ }
+ }
+
+ if (M0CopyReg != AMDGPU::NoRegister) {
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::COPY), AMDGPU::M0)
+ .addReg(M0CopyReg, RegState::Kill);
+ }
+
+ MI->eraseFromParent();
+ MFI->addToSpilledSGPRs(NumSubRegs);
+}
+
+void SIRegisterInfo::restoreSGPR(MachineBasicBlock::iterator MI,
+ int Index,
+ RegScavenger *RS) const {
+ MachineFunction *MF = MI->getParent()->getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ MachineBasicBlock *MBB = MI->getParent();
+ SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
+ MachineFrameInfo &FrameInfo = MF->getFrameInfo();
+ const SISubtarget &ST = MF->getSubtarget<SISubtarget>();
+ const SIInstrInfo *TII = ST.getInstrInfo();
+ const DebugLoc &DL = MI->getDebugLoc();
+
+ unsigned SuperReg = MI->getOperand(0).getReg();
+ bool SpillToSMEM = ST.hasScalarStores() && EnableSpillSGPRToSMEM;
+
+ assert(SuperReg != AMDGPU::M0 && "m0 should never spill");
+
+ unsigned OffsetReg = AMDGPU::M0;
+ unsigned M0CopyReg = AMDGPU::NoRegister;
+
+ if (SpillToSMEM) {
+ if (RS->isRegUsed(AMDGPU::M0)) {
+ M0CopyReg = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::COPY), M0CopyReg)
+ .addReg(AMDGPU::M0);
+ }
+ }
+
+ unsigned EltSize = 4;
+ unsigned ScalarLoadOp;
+
+ const TargetRegisterClass *RC = getPhysRegClass(SuperReg);
+ if (SpillToSMEM && isSGPRClass(RC)) {
+ // XXX - if private_element_size is larger than 4 it might be useful to be
+ // able to spill wider vmem spills.
+ std::tie(EltSize, ScalarLoadOp) = getSpillEltSize(RC->getSize(), false);
+ }
+
+ ArrayRef<int16_t> SplitParts = getRegSplitParts(RC, EltSize);
+ unsigned NumSubRegs = SplitParts.empty() ? 1 : SplitParts.size();
+
+ // SubReg carries the "Kill" flag when SubReg == SuperReg.
+ int64_t FrOffset = FrameInfo.getObjectOffset(Index);
+
+ for (unsigned i = 0, e = NumSubRegs; i < e; ++i) {
+ unsigned SubReg = NumSubRegs == 1 ?
+ SuperReg : getSubReg(SuperReg, SplitParts[i]);
+
+ if (SpillToSMEM) {
+ // FIXME: Size may be > 4 but extra bytes wasted.
+ unsigned Align = FrameInfo.getObjectAlignment(Index);
+ MachinePointerInfo PtrInfo
+ = MachinePointerInfo::getFixedStack(*MF, Index, EltSize * i);
+ MachineMemOperand *MMO
+ = MF->getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
+ EltSize, MinAlign(Align, EltSize * i));
+
+ // Add i * 4 offset
+ int64_t Offset = (ST.getWavefrontSize() * FrOffset) + (EltSize * i);
+ if (Offset != 0) {
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), OffsetReg)
+ .addReg(MFI->getScratchWaveOffsetReg())
+ .addImm(Offset);
+ } else {
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
+ .addReg(MFI->getScratchWaveOffsetReg());
+ }
+
+ auto MIB =
+ BuildMI(*MBB, MI, DL, TII->get(ScalarLoadOp), SubReg)
+ .addReg(MFI->getScratchRSrcReg()) // sbase
+ .addReg(OffsetReg, RegState::Kill) // soff
+ .addImm(0) // glc
+ .addMemOperand(MMO);
+
+ if (NumSubRegs > 1)
+ MIB.addReg(SuperReg, RegState::ImplicitDefine);
+
+ continue;
+ }
+
+ SIMachineFunctionInfo::SpilledReg Spill
+ = MFI->getSpilledReg(MF, Index, i);
+
+ if (Spill.hasReg()) {
+ auto MIB =
+ BuildMI(*MBB, MI, DL, TII->getMCOpcodeFromPseudo(AMDGPU::V_READLANE_B32),
+ SubReg)
+ .addReg(Spill.VGPR)
+ .addImm(Spill.Lane);
+
+ if (NumSubRegs > 1)
+ MIB.addReg(SuperReg, RegState::ImplicitDefine);
+ } else {
+ // Restore SGPR from a stack slot.
+ // FIXME: We should use S_LOAD_DWORD here for VI.
+ unsigned TmpReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
+ unsigned Align = FrameInfo.getObjectAlignment(Index);
+
+ MachinePointerInfo PtrInfo
+ = MachinePointerInfo::getFixedStack(*MF, Index, EltSize * i);
+
+ MachineMemOperand *MMO = MF->getMachineMemOperand(PtrInfo,
+ MachineMemOperand::MOLoad, EltSize,
+ MinAlign(Align, EltSize * i));
+
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_RESTORE), TmpReg)
+ .addFrameIndex(Index) // vaddr
+ .addReg(MFI->getScratchRSrcReg()) // srsrc
+ .addReg(MFI->getScratchWaveOffsetReg()) // soffset
+ .addImm(i * 4) // offset
+ .addMemOperand(MMO);
+
+ auto MIB =
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), SubReg)
+ .addReg(TmpReg, RegState::Kill);
+
+ if (NumSubRegs > 1)
+ MIB.addReg(MI->getOperand(0).getReg(), RegState::ImplicitDefine);
+ }
+ }
+
+ if (M0CopyReg != AMDGPU::NoRegister) {
+ BuildMI(*MBB, MI, DL, TII->get(AMDGPU::COPY), AMDGPU::M0)
+ .addReg(M0CopyReg, RegState::Kill);
+ }
+
+ MI->eraseFromParent();
}
void SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
@@ -499,7 +829,7 @@ void SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
MachineRegisterInfo &MRI = MF->getRegInfo();
MachineBasicBlock *MBB = MI->getParent();
SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
- MachineFrameInfo *FrameInfo = MF->getFrameInfo();
+ MachineFrameInfo &FrameInfo = MF->getFrameInfo();
const SISubtarget &ST = MF->getSubtarget<SISubtarget>();
const SIInstrInfo *TII = ST.getInstrInfo();
DebugLoc DL = MI->getDebugLoc();
@@ -514,66 +844,7 @@ void SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
case AMDGPU::SI_SPILL_S128_SAVE:
case AMDGPU::SI_SPILL_S64_SAVE:
case AMDGPU::SI_SPILL_S32_SAVE: {
- unsigned NumSubRegs = getNumSubRegsForSpillOp(MI->getOpcode());
- unsigned TmpReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
-
- unsigned SuperReg = MI->getOperand(0).getReg();
- bool IsKill = MI->getOperand(0).isKill();
- // SubReg carries the "Kill" flag when SubReg == SuperReg.
- unsigned SubKillState = getKillRegState((NumSubRegs == 1) && IsKill);
- for (unsigned i = 0, e = NumSubRegs; i < e; ++i) {
- unsigned SubReg = getPhysRegSubReg(SuperReg,
- &AMDGPU::SGPR_32RegClass, i);
-
- struct SIMachineFunctionInfo::SpilledReg Spill =
- MFI->getSpilledReg(MF, Index, i);
-
- if (Spill.hasReg()) {
- BuildMI(*MBB, MI, DL,
- TII->getMCOpcodeFromPseudo(AMDGPU::V_WRITELANE_B32),
- Spill.VGPR)
- .addReg(SubReg, getKillRegState(IsKill))
- .addImm(Spill.Lane);
-
- // FIXME: Since this spills to another register instead of an actual
- // frame index, we should delete the frame index when all references to
- // it are fixed.
- } else {
- // Spill SGPR to a frame index.
- // FIXME we should use S_STORE_DWORD here for VI.
- MachineInstrBuilder Mov
- = BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), TmpReg)
- .addReg(SubReg, SubKillState);
-
-
- // There could be undef components of a spilled super register.
- // TODO: Can we detect this and skip the spill?
- if (NumSubRegs > 1) {
- // The last implicit use of the SuperReg carries the "Kill" flag.
- unsigned SuperKillState = 0;
- if (i + 1 == e)
- SuperKillState |= getKillRegState(IsKill);
- Mov.addReg(SuperReg, RegState::Implicit | SuperKillState);
- }
-
- unsigned Size = FrameInfo->getObjectSize(Index);
- unsigned Align = FrameInfo->getObjectAlignment(Index);
- MachinePointerInfo PtrInfo
- = MachinePointerInfo::getFixedStack(*MF, Index);
- MachineMemOperand *MMO
- = MF->getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
- Size, Align);
- BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_SAVE))
- .addReg(TmpReg, RegState::Kill) // src
- .addFrameIndex(Index) // frame_idx
- .addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
- .addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
- .addImm(i * 4) // offset
- .addMemOperand(MMO);
- }
- }
- MI->eraseFromParent();
- MFI->addToSpilledSGPRs(NumSubRegs);
+ spillSGPR(MI, Index, RS);
break;
}
@@ -583,49 +854,7 @@ void SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
case AMDGPU::SI_SPILL_S128_RESTORE:
case AMDGPU::SI_SPILL_S64_RESTORE:
case AMDGPU::SI_SPILL_S32_RESTORE: {
- unsigned NumSubRegs = getNumSubRegsForSpillOp(MI->getOpcode());
- unsigned TmpReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
-
- for (unsigned i = 0, e = NumSubRegs; i < e; ++i) {
- unsigned SubReg = getPhysRegSubReg(MI->getOperand(0).getReg(),
- &AMDGPU::SGPR_32RegClass, i);
- struct SIMachineFunctionInfo::SpilledReg Spill =
- MFI->getSpilledReg(MF, Index, i);
-
- if (Spill.hasReg()) {
- BuildMI(*MBB, MI, DL,
- TII->getMCOpcodeFromPseudo(AMDGPU::V_READLANE_B32),
- SubReg)
- .addReg(Spill.VGPR)
- .addImm(Spill.Lane)
- .addReg(MI->getOperand(0).getReg(), RegState::ImplicitDefine);
- } else {
- // Restore SGPR from a stack slot.
- // FIXME: We should use S_LOAD_DWORD here for VI.
-
- unsigned Align = FrameInfo->getObjectAlignment(Index);
- unsigned Size = FrameInfo->getObjectSize(Index);
-
- MachinePointerInfo PtrInfo
- = MachinePointerInfo::getFixedStack(*MF, Index);
-
- MachineMemOperand *MMO = MF->getMachineMemOperand(
- PtrInfo, MachineMemOperand::MOLoad, Size, Align);
-
- BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_RESTORE), TmpReg)
- .addFrameIndex(Index) // frame_idx
- .addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
- .addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
- .addImm(i * 4) // offset
- .addMemOperand(MMO);
- BuildMI(*MBB, MI, DL,
- TII->get(AMDGPU::V_READFIRSTLANE_B32), SubReg)
- .addReg(TmpReg, RegState::Kill)
- .addReg(MI->getOperand(0).getReg(), RegState::ImplicitDefine);
- }
- }
-
- MI->eraseFromParent();
+ restoreSGPR(MI, Index, RS);
break;
}
@@ -635,34 +864,62 @@ void SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
case AMDGPU::SI_SPILL_V128_SAVE:
case AMDGPU::SI_SPILL_V96_SAVE:
case AMDGPU::SI_SPILL_V64_SAVE:
- case AMDGPU::SI_SPILL_V32_SAVE:
- buildScratchLoadStore(MI, AMDGPU::BUFFER_STORE_DWORD_OFFSET,
- TII->getNamedOperand(*MI, AMDGPU::OpName::src),
- TII->getNamedOperand(*MI, AMDGPU::OpName::scratch_rsrc)->getReg(),
- TII->getNamedOperand(*MI, AMDGPU::OpName::scratch_offset)->getReg(),
- FrameInfo->getObjectOffset(Index) +
- TII->getNamedOperand(*MI, AMDGPU::OpName::offset)->getImm(), RS);
- MI->eraseFromParent();
+ case AMDGPU::SI_SPILL_V32_SAVE: {
+ const MachineOperand *VData = TII->getNamedOperand(*MI,
+ AMDGPU::OpName::vdata);
+ buildSpillLoadStore(MI, AMDGPU::BUFFER_STORE_DWORD_OFFSET,
+ Index,
+ VData->getReg(), VData->isKill(),
+ TII->getNamedOperand(*MI, AMDGPU::OpName::srsrc)->getReg(),
+ TII->getNamedOperand(*MI, AMDGPU::OpName::soffset)->getReg(),
+ TII->getNamedOperand(*MI, AMDGPU::OpName::offset)->getImm(),
+ *MI->memoperands_begin(),
+ RS);
MFI->addToSpilledVGPRs(getNumSubRegsForSpillOp(MI->getOpcode()));
+ MI->eraseFromParent();
break;
+ }
case AMDGPU::SI_SPILL_V32_RESTORE:
case AMDGPU::SI_SPILL_V64_RESTORE:
case AMDGPU::SI_SPILL_V96_RESTORE:
case AMDGPU::SI_SPILL_V128_RESTORE:
case AMDGPU::SI_SPILL_V256_RESTORE:
case AMDGPU::SI_SPILL_V512_RESTORE: {
- buildScratchLoadStore(MI, AMDGPU::BUFFER_LOAD_DWORD_OFFSET,
- TII->getNamedOperand(*MI, AMDGPU::OpName::dst),
- TII->getNamedOperand(*MI, AMDGPU::OpName::scratch_rsrc)->getReg(),
- TII->getNamedOperand(*MI, AMDGPU::OpName::scratch_offset)->getReg(),
- FrameInfo->getObjectOffset(Index) +
- TII->getNamedOperand(*MI, AMDGPU::OpName::offset)->getImm(), RS);
+ const MachineOperand *VData = TII->getNamedOperand(*MI,
+ AMDGPU::OpName::vdata);
+
+ buildSpillLoadStore(MI, AMDGPU::BUFFER_LOAD_DWORD_OFFSET,
+ Index,
+ VData->getReg(), VData->isKill(),
+ TII->getNamedOperand(*MI, AMDGPU::OpName::srsrc)->getReg(),
+ TII->getNamedOperand(*MI, AMDGPU::OpName::soffset)->getReg(),
+ TII->getNamedOperand(*MI, AMDGPU::OpName::offset)->getImm(),
+ *MI->memoperands_begin(),
+ RS);
MI->eraseFromParent();
break;
}
default: {
- int64_t Offset = FrameInfo->getObjectOffset(Index);
+ if (TII->isMUBUF(*MI)) {
+ // Disable offen so we don't need a 0 vgpr base.
+ assert(static_cast<int>(FIOperandNum) ==
+ AMDGPU::getNamedOperandIdx(MI->getOpcode(),
+ AMDGPU::OpName::vaddr));
+
+ int64_t Offset = FrameInfo.getObjectOffset(Index);
+ int64_t OldImm
+ = TII->getNamedOperand(*MI, AMDGPU::OpName::offset)->getImm();
+ int64_t NewOffset = OldImm + Offset;
+
+ if (isUInt<12>(NewOffset) &&
+ buildMUBUFOffsetLoadStore(TII, FrameInfo, MI, Index, NewOffset)) {
+ MI->eraseFromParent();
+ break;
+ }
+ }
+
+ int64_t Offset = FrameInfo.getObjectOffset(Index);
FIOp.ChangeToImmediate(Offset);
if (!TII->isImmOperandLegal(*MI, FIOperandNum, FIOp)) {
unsigned TmpReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
@@ -770,7 +1027,8 @@ const TargetRegisterClass *SIRegisterInfo::getSubRegClass(
return RC;
// We can assume that each lane corresponds to one 32-bit register.
- unsigned Count = countPopulation(getSubRegIndexLaneMask(SubIdx));
+ LaneBitmask::Type Mask = getSubRegIndexLaneMask(SubIdx).getAsInteger();
+ unsigned Count = countPopulation(Mask);
if (isSGPRClass(RC)) {
switch (Count) {
case 1:
@@ -812,7 +1070,7 @@ bool SIRegisterInfo::shouldRewriteCopySrc(
// We want to prefer the smallest register class possible, so we don't want to
// stop and rewrite on anything that looks like a subregister
// extract. Operations mostly don't care about the super register class, so we
- // only want to stop on the most basic of copies between the smae register
+ // only want to stop on the most basic of copies between the same register
// class.
//
// e.g. if we have something like
@@ -828,80 +1086,6 @@ bool SIRegisterInfo::shouldRewriteCopySrc(
return getCommonSubClass(DefRC, SrcRC) != nullptr;
}
-unsigned SIRegisterInfo::getPhysRegSubReg(unsigned Reg,
- const TargetRegisterClass *SubRC,
- unsigned Channel) const {
-
- switch (Reg) {
- case AMDGPU::VCC:
- switch(Channel) {
- case 0: return AMDGPU::VCC_LO;
- case 1: return AMDGPU::VCC_HI;
- default: llvm_unreachable("Invalid SubIdx for VCC"); break;
- }
-
- case AMDGPU::TBA:
- switch(Channel) {
- case 0: return AMDGPU::TBA_LO;
- case 1: return AMDGPU::TBA_HI;
- default: llvm_unreachable("Invalid SubIdx for TBA"); break;
- }
-
- case AMDGPU::TMA:
- switch(Channel) {
- case 0: return AMDGPU::TMA_LO;
- case 1: return AMDGPU::TMA_HI;
- default: llvm_unreachable("Invalid SubIdx for TMA"); break;
- }
-
- case AMDGPU::FLAT_SCR:
- switch (Channel) {
- case 0:
- return AMDGPU::FLAT_SCR_LO;
- case 1:
- return AMDGPU::FLAT_SCR_HI;
- default:
- llvm_unreachable("Invalid SubIdx for FLAT_SCR");
- }
- break;
-
- case AMDGPU::EXEC:
- switch (Channel) {
- case 0:
- return AMDGPU::EXEC_LO;
- case 1:
- return AMDGPU::EXEC_HI;
- default:
- llvm_unreachable("Invalid SubIdx for EXEC");
- }
- break;
- }
-
- const TargetRegisterClass *RC = getPhysRegClass(Reg);
- // 32-bit registers don't have sub-registers, so we can just return the
- // Reg. We need to have this check here, because the calculation below
- // using getHWRegIndex() will fail with special 32-bit registers like
- // VCC_LO, VCC_HI, EXEC_LO, EXEC_HI and M0.
- if (RC->getSize() == 4) {
- assert(Channel == 0);
- return Reg;
- }
-
- unsigned Index = getHWRegIndex(Reg);
- return SubRC->getRegister(Index + Channel);
-}
-
-bool SIRegisterInfo::opCanUseLiteralConstant(unsigned OpType) const {
- return OpType == AMDGPU::OPERAND_REG_IMM32;
-}
-
-bool SIRegisterInfo::opCanUseInlineConstant(unsigned OpType) const {
- if (opCanUseLiteralConstant(OpType))
- return true;
-
- return OpType == AMDGPU::OPERAND_REG_INLINE_C;
-}
-
// FIXME: Most of these are flexible with HSA and we don't need to reserve them
// as input registers if unused. Whether the dispatch ptr is necessary should be
// easy to detect from used intrinsics. Scratch setup is harder to know.
@@ -924,14 +1108,18 @@ unsigned SIRegisterInfo::getPreloadedValue(const MachineFunction &MF,
case SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET:
return MFI->PrivateSegmentWaveByteOffsetSystemSGPR;
case SIRegisterInfo::PRIVATE_SEGMENT_BUFFER:
- assert(ST.isAmdHsaOS() && "Non-HSA ABI currently uses relocations");
- assert(MFI->hasPrivateSegmentBuffer());
- return MFI->PrivateSegmentBufferUserSGPR;
+ if (ST.isAmdCodeObjectV2(MF)) {
+ assert(MFI->hasPrivateSegmentBuffer());
+ return MFI->PrivateSegmentBufferUserSGPR;
+ }
+ assert(MFI->hasPrivateMemoryInputPtr());
+ return MFI->PrivateMemoryPtrUserSGPR;
case SIRegisterInfo::KERNARG_SEGMENT_PTR:
assert(MFI->hasKernargSegmentPtr());
return MFI->KernargSegmentPtrUserSGPR;
case SIRegisterInfo::DISPATCH_ID:
- llvm_unreachable("unimplemented");
+ assert(MFI->hasDispatchID());
+ return MFI->DispatchIDUserSGPR;
case SIRegisterInfo::FLAT_SCRATCH_INIT:
assert(MFI->hasFlatScratchInit());
return MFI->FlatScratchInitUserSGPR;
@@ -968,50 +1156,323 @@ SIRegisterInfo::findUnusedRegister(const MachineRegisterInfo &MRI,
return AMDGPU::NoRegister;
}
-unsigned SIRegisterInfo::getNumVGPRsAllowed(unsigned WaveCount) const {
- switch(WaveCount) {
- case 10: return 24;
- case 9: return 28;
- case 8: return 32;
- case 7: return 36;
- case 6: return 40;
- case 5: return 48;
- case 4: return 64;
- case 3: return 84;
- case 2: return 128;
- default: return 256;
+unsigned SIRegisterInfo::getTotalNumSGPRs(const SISubtarget &ST) const {
+ if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS)
+ return 800;
+ return 512;
+}
+
+unsigned SIRegisterInfo::getNumAddressableSGPRs(const SISubtarget &ST) const {
+ if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS)
+ return 102;
+ return 104;
+}
+
+unsigned SIRegisterInfo::getNumReservedSGPRs(const SISubtarget &ST,
+ const SIMachineFunctionInfo &MFI) const {
+ if (MFI.hasFlatScratchInit()) {
+ if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS)
+ return 6; // FLAT_SCRATCH, XNACK, VCC (in that order)
+
+ if (ST.getGeneration() == AMDGPUSubtarget::SEA_ISLANDS)
+ return 4; // FLAT_SCRATCH, VCC (in that order)
}
+
+ if (ST.isXNACKEnabled())
+ return 4; // XNACK, VCC (in that order)
+
+ return 2; // VCC.
}
-unsigned SIRegisterInfo::getNumSGPRsAllowed(const SISubtarget &ST,
- unsigned WaveCount) const {
- if (ST.getGeneration() >= SISubtarget::VOLCANIC_ISLANDS) {
- switch (WaveCount) {
+unsigned SIRegisterInfo::getMinNumSGPRs(const SISubtarget &ST,
+ unsigned WavesPerEU) const {
+ if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) {
+ switch (WavesPerEU) {
+ case 0: return 0;
+ case 10: return 0;
+ case 9: return 0;
+ case 8: return 81;
+ default: return 97;
+ }
+ } else {
+ switch (WavesPerEU) {
+ case 0: return 0;
+ case 10: return 0;
+ case 9: return 49;
+ case 8: return 57;
+ case 7: return 65;
+ case 6: return 73;
+ case 5: return 81;
+ default: return 97;
+ }
+ }
+}
+
+unsigned SIRegisterInfo::getMaxNumSGPRs(const SISubtarget &ST,
+ unsigned WavesPerEU,
+ bool Addressable) const {
+ if (ST.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) {
+ switch (WavesPerEU) {
+ case 0: return 80;
case 10: return 80;
case 9: return 80;
case 8: return 96;
- default: return 102;
+ default: return Addressable ? getNumAddressableSGPRs(ST) : 112;
}
} else {
- switch(WaveCount) {
+ switch (WavesPerEU) {
+ case 0: return 48;
case 10: return 48;
case 9: return 56;
case 8: return 64;
case 7: return 72;
case 6: return 80;
case 5: return 96;
- default: return 103;
+ default: return getNumAddressableSGPRs(ST);
}
}
}
-bool SIRegisterInfo::isVGPR(const MachineRegisterInfo &MRI,
- unsigned Reg) const {
- const TargetRegisterClass *RC;
+unsigned SIRegisterInfo::getMaxNumSGPRs(const MachineFunction &MF) const {
+ const Function &F = *MF.getFunction();
+
+ const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
+ const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
+
+ // Compute maximum number of SGPRs function can use using default/requested
+ // minimum number of waves per execution unit.
+ std::pair<unsigned, unsigned> WavesPerEU = MFI.getWavesPerEU();
+ unsigned MaxNumSGPRs = getMaxNumSGPRs(ST, WavesPerEU.first, false);
+ unsigned MaxNumAddressableSGPRs = getMaxNumSGPRs(ST, WavesPerEU.first, true);
+
+ // Check if maximum number of SGPRs was explicitly requested using
+ // "amdgpu-num-sgpr" attribute.
+ if (F.hasFnAttribute("amdgpu-num-sgpr")) {
+ unsigned Requested = AMDGPU::getIntegerAttribute(
+ F, "amdgpu-num-sgpr", MaxNumSGPRs);
+
+ // Make sure requested value does not violate subtarget's specifications.
+ if (Requested && (Requested <= getNumReservedSGPRs(ST, MFI)))
+ Requested = 0;
+
+ // If more SGPRs are required to support the input user/system SGPRs,
+ // increase to accommodate them.
+ //
+ // FIXME: This really ends up using the requested number of SGPRs + number
+ // of reserved special registers in total. Theoretically you could re-use
+ // the last input registers for these special registers, but this would
+ // require a lot of complexity to deal with the weird aliasing.
+ unsigned NumInputSGPRs = MFI.getNumPreloadedSGPRs();
+ if (Requested && Requested < NumInputSGPRs)
+ Requested = NumInputSGPRs;
+
+ // Make sure requested value is compatible with values implied by
+ // default/requested minimum/maximum number of waves per execution unit.
+ if (Requested && Requested > getMaxNumSGPRs(ST, WavesPerEU.first, false))
+ Requested = 0;
+ if (WavesPerEU.second &&
+ Requested && Requested < getMinNumSGPRs(ST, WavesPerEU.second))
+ Requested = 0;
+
+ if (Requested)
+ MaxNumSGPRs = Requested;
+ }
+
+ if (ST.hasSGPRInitBug())
+ MaxNumSGPRs = SISubtarget::FIXED_SGPR_COUNT_FOR_INIT_BUG;
+
+ return std::min(MaxNumSGPRs - getNumReservedSGPRs(ST, MFI),
+ MaxNumAddressableSGPRs);
+}
+
+unsigned SIRegisterInfo::getNumDebuggerReservedVGPRs(
+ const SISubtarget &ST) const {
+ if (ST.debuggerReserveRegs())
+ return 4;
+ return 0;
+}
+
+unsigned SIRegisterInfo::getMinNumVGPRs(unsigned WavesPerEU) const {
+ switch (WavesPerEU) {
+ case 0: return 0;
+ case 10: return 0;
+ case 9: return 25;
+ case 8: return 29;
+ case 7: return 33;
+ case 6: return 37;
+ case 5: return 41;
+ case 4: return 49;
+ case 3: return 65;
+ case 2: return 85;
+ default: return 129;
+ }
+}
+
+unsigned SIRegisterInfo::getMaxNumVGPRs(unsigned WavesPerEU) const {
+ switch (WavesPerEU) {
+ case 0: return 24;
+ case 10: return 24;
+ case 9: return 28;
+ case 8: return 32;
+ case 7: return 36;
+ case 6: return 40;
+ case 5: return 48;
+ case 4: return 64;
+ case 3: return 84;
+ case 2: return 128;
+ default: return getTotalNumVGPRs();
+ }
+}
+
+unsigned SIRegisterInfo::getMaxNumVGPRs(const MachineFunction &MF) const {
+ const Function &F = *MF.getFunction();
+
+ const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
+ const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
+
+ // Compute maximum number of VGPRs function can use using default/requested
+ // minimum number of waves per execution unit.
+ std::pair<unsigned, unsigned> WavesPerEU = MFI.getWavesPerEU();
+ unsigned MaxNumVGPRs = getMaxNumVGPRs(WavesPerEU.first);
+
+ // Check if maximum number of VGPRs was explicitly requested using
+ // "amdgpu-num-vgpr" attribute.
+ if (F.hasFnAttribute("amdgpu-num-vgpr")) {
+ unsigned Requested = AMDGPU::getIntegerAttribute(
+ F, "amdgpu-num-vgpr", MaxNumVGPRs);
+
+ // Make sure requested value does not violate subtarget's specifications.
+ if (Requested && Requested <= getNumDebuggerReservedVGPRs(ST))
+ Requested = 0;
+
+ // Make sure requested value is compatible with values implied by
+ // default/requested minimum/maximum number of waves per execution unit.
+ if (Requested && Requested > getMaxNumVGPRs(WavesPerEU.first))
+ Requested = 0;
+ if (WavesPerEU.second &&
+ Requested && Requested < getMinNumVGPRs(WavesPerEU.second))
+ Requested = 0;
+
+ if (Requested)
+ MaxNumVGPRs = Requested;
+ }
+
+ return MaxNumVGPRs - getNumDebuggerReservedVGPRs(ST);
+}
+
+ArrayRef<int16_t> SIRegisterInfo::getRegSplitParts(const TargetRegisterClass *RC,
+ unsigned EltSize) const {
+ if (EltSize == 4) {
+ static const int16_t Sub0_15[] = {
+ AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2, AMDGPU::sub3,
+ AMDGPU::sub4, AMDGPU::sub5, AMDGPU::sub6, AMDGPU::sub7,
+ AMDGPU::sub8, AMDGPU::sub9, AMDGPU::sub10, AMDGPU::sub11,
+ AMDGPU::sub12, AMDGPU::sub13, AMDGPU::sub14, AMDGPU::sub15,
+ };
+
+ static const int16_t Sub0_7[] = {
+ AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2, AMDGPU::sub3,
+ AMDGPU::sub4, AMDGPU::sub5, AMDGPU::sub6, AMDGPU::sub7,
+ };
+
+ static const int16_t Sub0_3[] = {
+ AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2, AMDGPU::sub3,
+ };
+
+ static const int16_t Sub0_2[] = {
+ AMDGPU::sub0, AMDGPU::sub1, AMDGPU::sub2,
+ };
+
+ static const int16_t Sub0_1[] = {
+ AMDGPU::sub0, AMDGPU::sub1,
+ };
+
+ switch (AMDGPU::getRegBitWidth(*RC->MC)) {
+ case 32:
+ return {};
+ case 64:
+ return makeArrayRef(Sub0_1);
+ case 96:
+ return makeArrayRef(Sub0_2);
+ case 128:
+ return makeArrayRef(Sub0_3);
+ case 256:
+ return makeArrayRef(Sub0_7);
+ case 512:
+ return makeArrayRef(Sub0_15);
+ default:
+ llvm_unreachable("unhandled register size");
+ }
+ }
+
+ if (EltSize == 8) {
+ static const int16_t Sub0_15_64[] = {
+ AMDGPU::sub0_sub1, AMDGPU::sub2_sub3,
+ AMDGPU::sub4_sub5, AMDGPU::sub6_sub7,
+ AMDGPU::sub8_sub9, AMDGPU::sub10_sub11,
+ AMDGPU::sub12_sub13, AMDGPU::sub14_sub15
+ };
+
+ static const int16_t Sub0_7_64[] = {
+ AMDGPU::sub0_sub1, AMDGPU::sub2_sub3,
+ AMDGPU::sub4_sub5, AMDGPU::sub6_sub7
+ };
+
+
+ static const int16_t Sub0_3_64[] = {
+ AMDGPU::sub0_sub1, AMDGPU::sub2_sub3
+ };
+
+ switch (AMDGPU::getRegBitWidth(*RC->MC)) {
+ case 64:
+ return {};
+ case 128:
+ return makeArrayRef(Sub0_3_64);
+ case 256:
+ return makeArrayRef(Sub0_7_64);
+ case 512:
+ return makeArrayRef(Sub0_15_64);
+ default:
+ llvm_unreachable("unhandled register size");
+ }
+ }
+
+ assert(EltSize == 16 && "unhandled register spill split size");
+
+ static const int16_t Sub0_15_128[] = {
+ AMDGPU::sub0_sub1_sub2_sub3,
+ AMDGPU::sub4_sub5_sub6_sub7,
+ AMDGPU::sub8_sub9_sub10_sub11,
+ AMDGPU::sub12_sub13_sub14_sub15
+ };
+
+ static const int16_t Sub0_7_128[] = {
+ AMDGPU::sub0_sub1_sub2_sub3,
+ AMDGPU::sub4_sub5_sub6_sub7
+ };
+
+ switch (AMDGPU::getRegBitWidth(*RC->MC)) {
+ case 128:
+ return {};
+ case 256:
+ return makeArrayRef(Sub0_7_128);
+ case 512:
+ return makeArrayRef(Sub0_15_128);
+ default:
+ llvm_unreachable("unhandled register size");
+ }
+}
+
+const TargetRegisterClass*
+SIRegisterInfo::getRegClassForReg(const MachineRegisterInfo &MRI,
+ unsigned Reg) const {
if (TargetRegisterInfo::isVirtualRegister(Reg))
- RC = MRI.getRegClass(Reg);
- else
- RC = getPhysRegClass(Reg);
+ return MRI.getRegClass(Reg);
- return hasVGPRs(RC);
+ return getPhysRegClass(Reg);
+}
+
+bool SIRegisterInfo::isVGPR(const MachineRegisterInfo &MRI,
+ unsigned Reg) const {
+ return hasVGPRs(getRegClassForReg(MRI, Reg));
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
index d8b2d9f..0bcae7d 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h
@@ -16,17 +16,19 @@
#define LLVM_LIB_TARGET_AMDGPU_SIREGISTERINFO_H
#include "AMDGPURegisterInfo.h"
+#include "SIDefines.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
namespace llvm {
class SISubtarget;
class MachineRegisterInfo;
+class SIMachineFunctionInfo;
-struct SIRegisterInfo final : public AMDGPURegisterInfo {
+class SIRegisterInfo final : public AMDGPURegisterInfo {
private:
- unsigned SGPR32SetID;
- unsigned VGPR32SetID;
+ unsigned SGPRSetID;
+ unsigned VGPRSetID;
BitVector SGPRPressureSets;
BitVector VGPRPressureSets;
@@ -48,17 +50,16 @@ public:
BitVector getReservedRegs(const MachineFunction &MF) const override;
- unsigned getRegPressureSetLimit(const MachineFunction &MF,
- unsigned Idx) const override;
-
-
bool requiresRegisterScavenging(const MachineFunction &Fn) const override;
-
bool requiresFrameIndexScavenging(const MachineFunction &MF) const override;
+ bool requiresFrameIndexReplacementScavenging(
+ const MachineFunction &MF) const override;
bool requiresVirtualBaseRegisters(const MachineFunction &Fn) const override;
bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override;
+ int64_t getMUBUFInstrOffset(const MachineInstr *MI) const;
+
int64_t getFrameIndexInstrOffset(const MachineInstr *MI,
int Idx) const override;
@@ -77,6 +78,12 @@ public:
const TargetRegisterClass *getPointerRegClass(
const MachineFunction &MF, unsigned Kind = 0) const override;
+ void spillSGPR(MachineBasicBlock::iterator MI,
+ int FI, RegScavenger *RS) const;
+
+ void restoreSGPR(MachineBasicBlock::iterator MI,
+ int FI, RegScavenger *RS) const;
+
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
unsigned FIOperandNum,
RegScavenger *RS) const override;
@@ -111,13 +118,6 @@ public:
/// \returns true if this class contains VGPR registers.
bool hasVGPRs(const TargetRegisterClass *RC) const;
- /// returns true if this is a pseudoregister class combination of VGPRs and
- /// SGPRs for operand modeling. FIXME: We should set isAllocatable = 0 on
- /// them.
- static bool isPseudoRegClass(const TargetRegisterClass *RC) {
- return RC == &AMDGPU::VS_32RegClass || RC == &AMDGPU::VS_64RegClass;
- }
-
/// \returns A VGPR reg class with the same width as \p SRC
const TargetRegisterClass *getEquivalentVGPRClass(
const TargetRegisterClass *SRC) const;
@@ -137,20 +137,21 @@ public:
const TargetRegisterClass *SrcRC,
unsigned SrcSubReg) const override;
- /// \p Channel This is the register channel (e.g. a value from 0-16), not the
- /// SubReg index.
- /// \returns The sub-register of Reg that is in Channel.
- unsigned getPhysRegSubReg(unsigned Reg, const TargetRegisterClass *SubRC,
- unsigned Channel) const;
-
/// \returns True if operands defined with this operand type can accept
/// a literal constant (i.e. any 32-bit immediate).
- bool opCanUseLiteralConstant(unsigned OpType) const;
+ bool opCanUseLiteralConstant(unsigned OpType) const {
+ // TODO: 64-bit operands have extending behavior from 32-bit literal.
+ return OpType >= AMDGPU::OPERAND_REG_IMM_FIRST &&
+ OpType <= AMDGPU::OPERAND_REG_IMM_LAST;
+ }
/// \returns True if operands defined with this operand type can accept
/// an inline constant. i.e. An integer value in the range (-16, 64) or
/// -4.0f, -2.0f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 2.0f, 4.0f.
- bool opCanUseInlineConstant(unsigned OpType) const;
+ bool opCanUseInlineConstant(unsigned OpType) const {
+ return OpType >= AMDGPU::OPERAND_SRC_FIRST &&
+ OpType <= AMDGPU::OPERAND_SRC_LAST;
+ }
enum PreloadedValue {
// SGPRS:
@@ -176,29 +177,104 @@ public:
unsigned getPreloadedValue(const MachineFunction &MF,
enum PreloadedValue Value) const;
- /// \brief Give the maximum number of VGPRs that can be used by \p WaveCount
- /// concurrent waves.
- unsigned getNumVGPRsAllowed(unsigned WaveCount) const;
-
- /// \brief Give the maximum number of SGPRs that can be used by \p WaveCount
- /// concurrent waves.
- unsigned getNumSGPRsAllowed(const SISubtarget &ST, unsigned WaveCount) const;
-
unsigned findUnusedRegister(const MachineRegisterInfo &MRI,
const TargetRegisterClass *RC,
const MachineFunction &MF) const;
- unsigned getSGPR32PressureSet() const { return SGPR32SetID; };
- unsigned getVGPR32PressureSet() const { return VGPR32SetID; };
+ unsigned getSGPRPressureSet() const { return SGPRSetID; };
+ unsigned getVGPRPressureSet() const { return VGPRSetID; };
+ const TargetRegisterClass *getRegClassForReg(const MachineRegisterInfo &MRI,
+ unsigned Reg) const;
bool isVGPR(const MachineRegisterInfo &MRI, unsigned Reg) const;
+ bool isSGPRPressureSet(unsigned SetID) const {
+ return SGPRPressureSets.test(SetID) && !VGPRPressureSets.test(SetID);
+ }
+ bool isVGPRPressureSet(unsigned SetID) const {
+ return VGPRPressureSets.test(SetID) && !SGPRPressureSets.test(SetID);
+ }
+
+ /// \returns SGPR allocation granularity supported by the subtarget.
+ unsigned getSGPRAllocGranule() const {
+ return 8;
+ }
+
+ /// \returns Total number of SGPRs supported by the subtarget.
+ unsigned getTotalNumSGPRs(const SISubtarget &ST) const;
+
+ /// \returns Number of addressable SGPRs supported by the subtarget.
+ unsigned getNumAddressableSGPRs(const SISubtarget &ST) const;
+
+ /// \returns Number of reserved SGPRs supported by the subtarget.
+ unsigned getNumReservedSGPRs(const SISubtarget &ST,
+ const SIMachineFunctionInfo &MFI) const;
+
+ /// \returns Minimum number of SGPRs that meets given number of waves per
+ /// execution unit requirement for given subtarget.
+ unsigned getMinNumSGPRs(const SISubtarget &ST, unsigned WavesPerEU) const;
+
+ /// \returns Maximum number of SGPRs that meets given number of waves per
+ /// execution unit requirement for given subtarget.
+ unsigned getMaxNumSGPRs(const SISubtarget &ST, unsigned WavesPerEU,
+ bool Addressable) const;
+
+ /// \returns Maximum number of SGPRs that meets number of waves per execution
+ /// unit requirement for function \p MF, or number of SGPRs explicitly
+ /// requested using "amdgpu-num-sgpr" attribute attached to function \p MF.
+ ///
+ /// \returns Value that meets number of waves per execution unit requirement
+ /// if explicitly requested value cannot be converted to integer, violates
+ /// subtarget's specifications, or does not meet number of waves per execution
+ /// unit requirement.
+ unsigned getMaxNumSGPRs(const MachineFunction &MF) const;
+
+ /// \returns VGPR allocation granularity supported by the subtarget.
+ unsigned getVGPRAllocGranule() const {
+ return 4;
+ }
+
+ /// \returns Total number of VGPRs supported by the subtarget.
+ unsigned getTotalNumVGPRs() const {
+ return 256;
+ }
+
+ /// \returns Number of reserved VGPRs for debugger use supported by the
+ /// subtarget.
+ unsigned getNumDebuggerReservedVGPRs(const SISubtarget &ST) const;
+
+ /// \returns Minimum number of SGPRs that meets given number of waves per
+ /// execution unit requirement.
+ unsigned getMinNumVGPRs(unsigned WavesPerEU) const;
+
+ /// \returns Maximum number of VGPRs that meets given number of waves per
+ /// execution unit requirement.
+ unsigned getMaxNumVGPRs(unsigned WavesPerEU) const;
+
+ /// \returns Maximum number of VGPRs that meets number of waves per execution
+ /// unit requirement for function \p MF, or number of VGPRs explicitly
+ /// requested using "amdgpu-num-vgpr" attribute attached to function \p MF.
+ ///
+ /// \returns Value that meets number of waves per execution unit requirement
+ /// if explicitly requested value cannot be converted to integer, violates
+ /// subtarget's specifications, or does not meet number of waves per execution
+ /// unit requirement.
+ unsigned getMaxNumVGPRs(const MachineFunction &MF) const;
+
+ ArrayRef<int16_t> getRegSplitParts(const TargetRegisterClass *RC,
+ unsigned EltSize) const;
+
private:
- void buildScratchLoadStore(MachineBasicBlock::iterator MI,
- unsigned LoadStoreOp, const MachineOperand *SrcDst,
- unsigned ScratchRsrcReg, unsigned ScratchOffset,
- int64_t Offset,
- RegScavenger *RS) const;
+ void buildSpillLoadStore(MachineBasicBlock::iterator MI,
+ unsigned LoadStoreOp,
+ int Index,
+ unsigned ValueReg,
+ bool ValueIsKill,
+ unsigned ScratchRsrcReg,
+ unsigned ScratchOffsetReg,
+ int64_t InstrOffset,
+ MachineMemOperand *MMO,
+ RegScavenger *RS) const;
};
} // End namespace llvm
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index c427874..31e714b 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -120,12 +120,19 @@ def SCC_CLASS : RegisterClass<"AMDGPU", [i1], 1, (add SCC)> {
let isAllocatable = 0;
}
+def M0_CLASS : RegisterClass<"AMDGPU", [i32], 32, (add M0)> {
+ let CopyCost = 1;
+ let isAllocatable = 0;
+}
+
// TODO: Do we need to set DwarfRegAlias on register tuples?
// SGPR 32-bit registers
-def SGPR_32 : RegisterClass<"AMDGPU", [i32, f32], 32,
+def SGPR_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16], 32,
(add (sequence "SGPR%u", 0, 103))> {
- let AllocationPriority = 1;
+ // Give all SGPR classes higher priority than VGPR classes, because
+ // we want to spill SGPRs to VGPRs.
+ let AllocationPriority = 7;
}
// SGPR 64-bit registers
@@ -190,9 +197,10 @@ def TTMP_128Regs : RegisterTuples<[sub0, sub1, sub2, sub3],
(add (decimate (shl TTMP_32, 3), 4))]>;
// VGPR 32-bit registers
-def VGPR_32 : RegisterClass<"AMDGPU", [i32, f32], 32,
+def VGPR_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16], 32,
(add (sequence "VGPR%u", 0, 255))> {
let AllocationPriority = 1;
+ let Size = 32;
}
// VGPR 64-bit registers
@@ -248,43 +256,51 @@ def VGPR_512 : RegisterTuples<[sub0, sub1, sub2, sub3, sub4, sub5, sub6, sub7,
// Register classes used as source and destination
//===----------------------------------------------------------------------===//
-class RegImmMatcher<string name> : AsmOperandClass {
- let Name = name;
- let RenderMethod = "addRegOrImmOperands";
-}
-
// Subset of SReg_32 without M0 for SMRD instructions and alike.
// See comments in SIInstructions.td for more info.
-def SReg_32_XM0 : RegisterClass<"AMDGPU", [i32, f32], 32,
- (add SGPR_32, VCC_LO, VCC_HI, EXEC_LO, EXEC_HI, FLAT_SCR_LO, FLAT_SCR_HI,
+def SReg_32_XM0_XEXEC : RegisterClass<"AMDGPU", [i32, f32, i16, f16], 32,
+ (add SGPR_32, VCC_LO, VCC_HI, FLAT_SCR_LO, FLAT_SCR_HI,
TTMP_32, TMA_LO, TMA_HI, TBA_LO, TBA_HI)> {
- let AllocationPriority = 1;
+ let AllocationPriority = 7;
+}
+
+def SReg_32_XM0 : RegisterClass<"AMDGPU", [i32, f32, i16, f16], 32,
+ (add SReg_32_XM0_XEXEC, EXEC_LO, EXEC_HI)> {
+ let AllocationPriority = 7;
}
// Register class for all scalar registers (SGPRs + Special Registers)
-def SReg_32 : RegisterClass<"AMDGPU", [i32, f32], 32,
- (add SReg_32_XM0, M0)> {
- let AllocationPriority = 1;
+def SReg_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16], 32,
+ (add SReg_32_XM0, M0_CLASS, EXEC_LO, EXEC_HI)> {
+ let AllocationPriority = 7;
}
def SGPR_64 : RegisterClass<"AMDGPU", [v2i32, i64, f64], 32, (add SGPR_64Regs)> {
- let AllocationPriority = 2;
+ let CopyCost = 1;
+ let AllocationPriority = 8;
}
def TTMP_64 : RegisterClass<"AMDGPU", [v2i32, i64, f64], 32, (add TTMP_64Regs)> {
let isAllocatable = 0;
}
+def SReg_64_XEXEC : RegisterClass<"AMDGPU", [v2i32, i64, f64, i1], 32,
+ (add SGPR_64, VCC, FLAT_SCR, TTMP_64, TBA, TMA)> {
+ let CopyCost = 1;
+ let AllocationPriority = 8;
+}
+
def SReg_64 : RegisterClass<"AMDGPU", [v2i32, i64, f64, i1], 32,
- (add SGPR_64, VCC, EXEC, FLAT_SCR, TTMP_64, TBA, TMA)> {
- let AllocationPriority = 2;
+ (add SReg_64_XEXEC, EXEC)> {
+ let CopyCost = 1;
+ let AllocationPriority = 8;
}
// Requires 2 s_mov_b64 to copy
let CopyCost = 2 in {
def SGPR_128 : RegisterClass<"AMDGPU", [v4i32, v16i8, v2i64], 32, (add SGPR_128Regs)> {
- let AllocationPriority = 4;
+ let AllocationPriority = 10;
}
def TTMP_128 : RegisterClass<"AMDGPU", [v4i32, v16i8, v2i64], 32, (add TTMP_128Regs)> {
@@ -292,7 +308,7 @@ def TTMP_128 : RegisterClass<"AMDGPU", [v4i32, v16i8, v2i64], 32, (add TTMP_128R
}
def SReg_128 : RegisterClass<"AMDGPU", [v4i32, v16i8, v2i64], 32, (add SGPR_128, TTMP_128)> {
- let AllocationPriority = 4;
+ let AllocationPriority = 10;
}
} // End CopyCost = 2
@@ -300,17 +316,19 @@ def SReg_128 : RegisterClass<"AMDGPU", [v4i32, v16i8, v2i64], 32, (add SGPR_128,
def SReg_256 : RegisterClass<"AMDGPU", [v8i32, v8f32], 32, (add SGPR_256)> {
// Requires 4 s_mov_b64 to copy
let CopyCost = 4;
- let AllocationPriority = 5;
+ let AllocationPriority = 11;
}
def SReg_512 : RegisterClass<"AMDGPU", [v64i8, v16i32], 32, (add SGPR_512)> {
// Requires 8 s_mov_b64 to copy
let CopyCost = 8;
- let AllocationPriority = 6;
+ let AllocationPriority = 12;
}
// Register class for all vector registers (VGPRs + Interploation Registers)
def VReg_64 : RegisterClass<"AMDGPU", [i64, f64, v2i32, v2f32], 32, (add VGPR_64)> {
+ let Size = 64;
+
// Requires 2 v_mov_b32 to copy
let CopyCost = 2;
let AllocationPriority = 2;
@@ -325,17 +343,21 @@ def VReg_96 : RegisterClass<"AMDGPU", [untyped], 32, (add VGPR_96)> {
}
def VReg_128 : RegisterClass<"AMDGPU", [v4i32, v4f32, v2i64, v2f64], 32, (add VGPR_128)> {
+ let Size = 128;
+
// Requires 4 v_mov_b32 to copy
let CopyCost = 4;
let AllocationPriority = 4;
}
def VReg_256 : RegisterClass<"AMDGPU", [v8i32, v8f32], 32, (add VGPR_256)> {
+ let Size = 256;
let CopyCost = 8;
let AllocationPriority = 5;
}
def VReg_512 : RegisterClass<"AMDGPU", [v16i32, v16f32], 32, (add VGPR_512)> {
+ let Size = 512;
let CopyCost = 16;
let AllocationPriority = 6;
}
@@ -344,80 +366,100 @@ def VReg_1 : RegisterClass<"AMDGPU", [i1], 32, (add VGPR_32)> {
let Size = 32;
}
-class RegImmOperand <RegisterClass rc> : RegisterOperand<rc> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_IMM32";
+def VS_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16], 32,
+ (add VGPR_32, SReg_32)> {
+ let isAllocatable = 0;
}
-class RegInlineOperand <RegisterClass rc> : RegisterOperand<rc> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_INLINE_C";
+def VS_64 : RegisterClass<"AMDGPU", [i64, f64], 32, (add VReg_64, SReg_64)> {
+ let isAllocatable = 0;
}
//===----------------------------------------------------------------------===//
-// SSrc_* Operands with an SGPR or a 32-bit immediate
+// Register operands
//===----------------------------------------------------------------------===//
-def SSrc_32 : RegImmOperand<SReg_32> {
- let ParserMatchClass = RegImmMatcher<"SSrc32">;
+class RegImmMatcher<string name> : AsmOperandClass {
+ let Name = name;
+ let RenderMethod = "addRegOrImmOperands";
}
-def SSrc_64 : RegImmOperand<SReg_64> {
- let ParserMatchClass = RegImmMatcher<"SSrc64">;
+multiclass SIRegOperand <string rc, string MatchName, string opType> {
+ let OperandNamespace = "AMDGPU" in {
+ def _b16 : RegisterOperand<!cast<RegisterClass>(rc#"_32")> {
+ let OperandType = opType#"_INT16";
+ let ParserMatchClass = RegImmMatcher<MatchName#"B16">;
+ let DecoderMethod = "decodeOperand_VSrc16";
+ }
+
+ def _f16 : RegisterOperand<!cast<RegisterClass>(rc#"_32")> {
+ let OperandType = opType#"_FP16";
+ let ParserMatchClass = RegImmMatcher<MatchName#"F16">;
+ let DecoderMethod = "decodeOperand_VSrc16";
+ }
+
+ def _b32 : RegisterOperand<!cast<RegisterClass>(rc#"_32")> {
+ let OperandType = opType#"_INT32";
+ let ParserMatchClass = RegImmMatcher<MatchName#"B32">;
+ }
+
+ def _f32 : RegisterOperand<!cast<RegisterClass>(rc#"_32")> {
+ let OperandType = opType#"_FP32";
+ let ParserMatchClass = RegImmMatcher<MatchName#"F32">;
+ }
+
+ def _b64 : RegisterOperand<!cast<RegisterClass>(rc#"_64")> {
+ let OperandType = opType#"_INT64";
+ let ParserMatchClass = RegImmMatcher<MatchName#"B64">;
+ }
+
+ def _f64 : RegisterOperand<!cast<RegisterClass>(rc#"_64")> {
+ let OperandType = opType#"_FP64";
+ let ParserMatchClass = RegImmMatcher<MatchName#"F64">;
+ }
+ }
}
+// FIXME: 64-bit sources can sometimes use 32-bit constants.
+multiclass RegImmOperand <string rc, string MatchName>
+ : SIRegOperand<rc, MatchName, "OPERAND_REG_IMM">;
+
+multiclass RegInlineOperand <string rc, string MatchName>
+ : SIRegOperand<rc, MatchName, "OPERAND_REG_INLINE_C">;
+
//===----------------------------------------------------------------------===//
-// SCSrc_* Operands with an SGPR or a inline constant
+// SSrc_* Operands with an SGPR or a 32-bit immediate
//===----------------------------------------------------------------------===//
-def SCSrc_32 : RegInlineOperand<SReg_32> {
- let ParserMatchClass = RegImmMatcher<"SCSrc32">;
-}
+defm SSrc : RegImmOperand<"SReg", "SSrc">;
//===----------------------------------------------------------------------===//
-// VSrc_* Operands with an SGPR, VGPR or a 32-bit immediate
+// SCSrc_* Operands with an SGPR or a inline constant
//===----------------------------------------------------------------------===//
-def VS_32 : RegisterClass<"AMDGPU", [i32, f32], 32, (add VGPR_32, SReg_32)>;
+defm SCSrc : RegInlineOperand<"SReg", "SCSrc"> ;
-def VS_64 : RegisterClass<"AMDGPU", [i64, f64], 32, (add VReg_64, SReg_64)> {
- let CopyCost = 2;
-}
+//===----------------------------------------------------------------------===//
+// VSrc_* Operands with an SGPR, VGPR or a 32-bit immediate
+//===----------------------------------------------------------------------===//
-def VSrc_32 : RegisterOperand<VS_32> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_IMM32";
- let ParserMatchClass = RegImmMatcher<"VSrc32">;
-}
+defm VSrc : RegImmOperand<"VS", "VSrc">;
-def VSrc_64 : RegisterOperand<VS_64> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_IMM32";
- let ParserMatchClass = RegImmMatcher<"VSrc64">;
-}
+def VSrc_128 : RegisterOperand<VReg_128>;
//===----------------------------------------------------------------------===//
-// VCSrc_* Operands with an SGPR, VGPR or an inline constant
+// VSrc_* Operands with an VGPR
//===----------------------------------------------------------------------===//
-def VCSrc_32 : RegisterOperand<VS_32> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_INLINE_C";
- let ParserMatchClass = RegImmMatcher<"VCSrc32">;
-}
-
-def VCSrc_64 : RegisterOperand<VS_64> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_INLINE_C";
- let ParserMatchClass = RegImmMatcher<"VCSrc64">;
+// This is for operands with the enum(9), VSrc encoding restriction,
+// but only allows VGPRs.
+def VRegSrc_32 : RegisterOperand<VGPR_32> {
+ //let ParserMatchClass = RegImmMatcher<"VRegSrc32">;
+ let DecoderMethod = "DecodeVS_32RegisterClass";
}
//===----------------------------------------------------------------------===//
-// SCSrc_* Operands with an SGPR or an inline constant
+// VCSrc_* Operands with an SGPR, VGPR or an inline constant
//===----------------------------------------------------------------------===//
-def SCSrc_64 : RegisterOperand<SReg_64> {
- let OperandNamespace = "AMDGPU";
- let OperandType = "OPERAND_REG_INLINE_C";
- let ParserMatchClass = RegImmMatcher<"SCSrc64">;
-}
+defm VCSrc : RegInlineOperand<"VS", "VCSrc">;
diff --git a/contrib/llvm/lib/Target/AMDGPU/SISchedule.td b/contrib/llvm/lib/Target/AMDGPU/SISchedule.td
index ed19217..be27966 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SISchedule.td
+++ b/contrib/llvm/lib/Target/AMDGPU/SISchedule.td
@@ -46,7 +46,11 @@ def Write64Bit : SchedWrite;
// instructions)
class SISchedMachineModel : SchedMachineModel {
- let CompleteModel = 0;
+ let CompleteModel = 1;
+ // MicroOpBufferSize = 1 means that instructions will always be added
+ // the ready queue when they become available. This exposes them
+ // to the register pressure analysis.
+ let MicroOpBufferSize = 1;
let IssueWidth = 1;
let PostRAScheduler = 1;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp b/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp
index 6cba553..dd31dc6 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp
@@ -45,9 +45,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Shrink Instructions";
- }
+ StringRef getPassName() const override { return "SI Shrink Instructions"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -86,13 +84,19 @@ static bool canShrink(MachineInstr &MI, const SIInstrInfo *TII,
// FIXME: v_cndmask_b32 has 3 operands and is shrinkable, but we need to add
// a special case for it. It can only be shrunk if the third operand
// is vcc. We should handle this the same way we handle vopc, by addding
- // a register allocation hint pre-regalloc and then do the shrining
+ // a register allocation hint pre-regalloc and then do the shrinking
// post-regalloc.
if (Src2) {
switch (MI.getOpcode()) {
default: return false;
+ case AMDGPU::V_ADDC_U32_e64:
+ case AMDGPU::V_SUBB_U32_e64:
+ // Additional verification is needed for sdst/src2.
+ return true;
+
case AMDGPU::V_MAC_F32_e64:
+ case AMDGPU::V_MAC_F16_e64:
if (!isVGPR(Src2, TRI, MRI) ||
TII->hasModifiersSet(MI, AMDGPU::OpName::src2_modifiers))
return false;
@@ -134,23 +138,15 @@ static void foldImmediates(MachineInstr &MI, const SIInstrInfo *TII,
assert(TII->isVOP1(MI) || TII->isVOP2(MI) || TII->isVOPC(MI));
- const SIRegisterInfo &TRI = TII->getRegisterInfo();
int Src0Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
- MachineOperand &Src0 = MI.getOperand(Src0Idx);
// Only one literal constant is allowed per instruction, so if src0 is a
// literal constant then we can't do any folding.
- if (Src0.isImm() &&
- TII->isLiteralConstant(Src0, TII->getOpSize(MI, Src0Idx)))
- return;
-
- // Literal constants and SGPRs can only be used in Src0, so if Src0 is an
- // SGPR, we cannot commute the instruction, so we can't fold any literal
- // constants.
- if (Src0.isReg() && !isVGPR(&Src0, TRI, MRI))
+ if (TII->isLiteralConstant(MI, Src0Idx))
return;
// Try to fold Src0
+ MachineOperand &Src0 = MI.getOperand(Src0Idx);
if (Src0.isReg() && MRI.hasOneUse(Src0.getReg())) {
unsigned Reg = Src0.getReg();
MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
@@ -158,7 +154,8 @@ static void foldImmediates(MachineInstr &MI, const SIInstrInfo *TII,
MachineOperand &MovSrc = Def->getOperand(1);
bool ConstantFolded = false;
- if (MovSrc.isImm() && isUInt<32>(MovSrc.getImm())) {
+ if (MovSrc.isImm() && (isInt<32>(MovSrc.getImm()) ||
+ isUInt<32>(MovSrc.getImm()))) {
Src0.ChangeToImmediate(MovSrc.getImm());
ConstantFolded = true;
}
@@ -182,7 +179,7 @@ static void copyFlagsToImplicitVCC(MachineInstr &MI,
const MachineOperand &Orig) {
for (MachineOperand &Use : MI.implicit_operands()) {
- if (Use.getReg() == AMDGPU::VCC) {
+ if (Use.isUse() && Use.getReg() == AMDGPU::VCC) {
Use.setIsUndef(Orig.isUndef());
Use.setIsKill(Orig.isKill());
return;
@@ -191,7 +188,95 @@ static void copyFlagsToImplicitVCC(MachineInstr &MI,
}
static bool isKImmOperand(const SIInstrInfo *TII, const MachineOperand &Src) {
- return isInt<16>(Src.getImm()) && !TII->isInlineConstant(Src, 4);
+ return isInt<16>(Src.getImm()) &&
+ !TII->isInlineConstant(*Src.getParent(),
+ Src.getParent()->getOperandNo(&Src));
+}
+
+static bool isKUImmOperand(const SIInstrInfo *TII, const MachineOperand &Src) {
+ return isUInt<16>(Src.getImm()) &&
+ !TII->isInlineConstant(*Src.getParent(),
+ Src.getParent()->getOperandNo(&Src));
+}
+
+static bool isKImmOrKUImmOperand(const SIInstrInfo *TII,
+ const MachineOperand &Src,
+ bool &IsUnsigned) {
+ if (isInt<16>(Src.getImm())) {
+ IsUnsigned = false;
+ return !TII->isInlineConstant(Src);
+ }
+
+ if (isUInt<16>(Src.getImm())) {
+ IsUnsigned = true;
+ return !TII->isInlineConstant(Src);
+ }
+
+ return false;
+}
+
+/// \returns true if the constant in \p Src should be replaced with a bitreverse
+/// of an inline immediate.
+static bool isReverseInlineImm(const SIInstrInfo *TII,
+ const MachineOperand &Src,
+ int32_t &ReverseImm) {
+ if (!isInt<32>(Src.getImm()) || TII->isInlineConstant(Src))
+ return false;
+
+ ReverseImm = reverseBits<int32_t>(static_cast<int32_t>(Src.getImm()));
+ return ReverseImm >= -16 && ReverseImm <= 64;
+}
+
+/// Copy implicit register operands from specified instruction to this
+/// instruction that are not part of the instruction definition.
+static void copyExtraImplicitOps(MachineInstr &NewMI, MachineFunction &MF,
+ const MachineInstr &MI) {
+ for (unsigned i = MI.getDesc().getNumOperands() +
+ MI.getDesc().getNumImplicitUses() +
+ MI.getDesc().getNumImplicitDefs(), e = MI.getNumOperands();
+ i != e; ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
+ if ((MO.isReg() && MO.isImplicit()) || MO.isRegMask())
+ NewMI.addOperand(MF, MO);
+ }
+}
+
+static void shrinkScalarCompare(const SIInstrInfo *TII, MachineInstr &MI) {
+ // cmpk instructions do scc = dst <cc op> imm16, so commute the instruction to
+ // get constants on the RHS.
+ if (!MI.getOperand(0).isReg())
+ TII->commuteInstruction(MI, false, 0, 1);
+
+ const MachineOperand &Src1 = MI.getOperand(1);
+ if (!Src1.isImm())
+ return;
+
+ int SOPKOpc = AMDGPU::getSOPKOp(MI.getOpcode());
+ if (SOPKOpc == -1)
+ return;
+
+ // eq/ne is special because the imm16 can be treated as signed or unsigned,
+ // and initially selectd to the unsigned versions.
+ if (SOPKOpc == AMDGPU::S_CMPK_EQ_U32 || SOPKOpc == AMDGPU::S_CMPK_LG_U32) {
+ bool HasUImm;
+ if (isKImmOrKUImmOperand(TII, Src1, HasUImm)) {
+ if (!HasUImm) {
+ SOPKOpc = (SOPKOpc == AMDGPU::S_CMPK_EQ_U32) ?
+ AMDGPU::S_CMPK_EQ_I32 : AMDGPU::S_CMPK_LG_I32;
+ }
+
+ MI.setDesc(TII->get(SOPKOpc));
+ }
+
+ return;
+ }
+
+ const MCInstrDesc &NewDesc = TII->get(SOPKOpc);
+
+ if ((TII->sopkIsZext(SOPKOpc) && isKUImmOperand(TII, Src1)) ||
+ (!TII->sopkIsZext(SOPKOpc) && isKImmOperand(TII, Src1))) {
+ MI.setDesc(NewDesc);
+ }
}
bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
@@ -226,14 +311,11 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
MachineOperand &Src = MI.getOperand(1);
if (Src.isImm() &&
TargetRegisterInfo::isPhysicalRegister(MI.getOperand(0).getReg())) {
- int64_t Imm = Src.getImm();
- if (isInt<32>(Imm) && !TII->isInlineConstant(Src, 4)) {
- int32_t ReverseImm = reverseBits<int32_t>(static_cast<int32_t>(Imm));
- if (ReverseImm >= -16 && ReverseImm <= 64) {
- MI.setDesc(TII->get(AMDGPU::V_BFREV_B32_e32));
- Src.setImm(ReverseImm);
- continue;
- }
+ int32_t ReverseImm;
+ if (isReverseInlineImm(TII, Src, ReverseImm)) {
+ MI.setDesc(TII->get(AMDGPU::V_BFREV_B32_e32));
+ Src.setImm(ReverseImm);
+ continue;
}
}
}
@@ -272,21 +354,27 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
// satisfied.
if (MI.getOpcode() == AMDGPU::S_ADD_I32 ||
MI.getOpcode() == AMDGPU::S_MUL_I32) {
- const MachineOperand &Dest = MI.getOperand(0);
- const MachineOperand &Src0 = MI.getOperand(1);
- const MachineOperand &Src1 = MI.getOperand(2);
+ const MachineOperand *Dest = &MI.getOperand(0);
+ MachineOperand *Src0 = &MI.getOperand(1);
+ MachineOperand *Src1 = &MI.getOperand(2);
+
+ if (!Src0->isReg() && Src1->isReg()) {
+ if (TII->commuteInstruction(MI, false, 1, 2))
+ std::swap(Src0, Src1);
+ }
// FIXME: This could work better if hints worked with subregisters. If
// we have a vector add of a constant, we usually don't get the correct
// allocation due to the subregister usage.
- if (TargetRegisterInfo::isVirtualRegister(Dest.getReg()) &&
- Src0.isReg()) {
- MRI.setRegAllocationHint(Dest.getReg(), 0, Src0.getReg());
+ if (TargetRegisterInfo::isVirtualRegister(Dest->getReg()) &&
+ Src0->isReg()) {
+ MRI.setRegAllocationHint(Dest->getReg(), 0, Src0->getReg());
+ MRI.setRegAllocationHint(Src0->getReg(), 0, Dest->getReg());
continue;
}
- if (Src0.isReg() && Src0.getReg() == Dest.getReg()) {
- if (Src1.isImm() && isKImmOperand(TII, Src1)) {
+ if (Src0->isReg() && Src0->getReg() == Dest->getReg()) {
+ if (Src1->isImm() && isKImmOperand(TII, *Src1)) {
unsigned Opc = (MI.getOpcode() == AMDGPU::S_ADD_I32) ?
AMDGPU::S_ADDK_I32 : AMDGPU::S_MULK_I32;
@@ -296,12 +384,27 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
}
}
+ // Try to use s_cmpk_*
+ if (MI.isCompare() && TII->isSOPC(MI)) {
+ shrinkScalarCompare(TII, MI);
+ continue;
+ }
+
// Try to use S_MOVK_I32, which will save 4 bytes for small immediates.
if (MI.getOpcode() == AMDGPU::S_MOV_B32) {
- const MachineOperand &Src = MI.getOperand(1);
+ const MachineOperand &Dst = MI.getOperand(0);
+ MachineOperand &Src = MI.getOperand(1);
- if (Src.isImm() && isKImmOperand(TII, Src))
- MI.setDesc(TII->get(AMDGPU::S_MOVK_I32));
+ if (Src.isImm() &&
+ TargetRegisterInfo::isPhysicalRegister(Dst.getReg())) {
+ int32_t ReverseImm;
+ if (isKImmOperand(TII, Src))
+ MI.setDesc(TII->get(AMDGPU::S_MOVK_I32));
+ else if (isReverseInlineImm(TII, Src, ReverseImm)) {
+ MI.setDesc(TII->get(AMDGPU::S_BREV_B32));
+ Src.setImm(ReverseImm);
+ }
+ }
continue;
}
@@ -358,6 +461,31 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
continue;
}
+ // Check for the bool flag output for instructions like V_ADD_I32_e64.
+ const MachineOperand *SDst = TII->getNamedOperand(MI,
+ AMDGPU::OpName::sdst);
+
+ // Check the carry-in operand for v_addc_u32_e64.
+ const MachineOperand *Src2 = TII->getNamedOperand(MI,
+ AMDGPU::OpName::src2);
+
+ if (SDst) {
+ if (SDst->getReg() != AMDGPU::VCC) {
+ if (TargetRegisterInfo::isVirtualRegister(SDst->getReg()))
+ MRI.setRegAllocationHint(SDst->getReg(), 0, AMDGPU::VCC);
+ continue;
+ }
+
+ // All of the instructions with carry outs also have an SGPR input in
+ // src2.
+ if (Src2 && Src2->getReg() != AMDGPU::VCC) {
+ if (TargetRegisterInfo::isVirtualRegister(Src2->getReg()))
+ MRI.setRegAllocationHint(Src2->getReg(), 0, AMDGPU::VCC);
+
+ continue;
+ }
+ }
+
// We can shrink this instruction
DEBUG(dbgs() << "Shrinking " << MI);
@@ -383,8 +511,6 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
if (Src1)
Inst32.addOperand(*Src1);
- const MachineOperand *Src2 =
- TII->getNamedOperand(MI, AMDGPU::OpName::src2);
if (Src2) {
int Op32Src2Idx = AMDGPU::getNamedOperandIdx(Op32, AMDGPU::OpName::src2);
if (Op32Src2Idx != -1) {
@@ -398,9 +524,13 @@ bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
}
++NumInstructionsShrunk;
- MI.eraseFromParent();
+ // Copy extra operands not present in the instruction definition.
+ copyExtraImplicitOps(*Inst32, MF, MI);
+
+ MI.eraseFromParent();
foldImmediates(*Inst32, TII, MRI);
+
DEBUG(dbgs() << "e32 MI = " << *Inst32 << '\n');
diff --git a/contrib/llvm/lib/Target/AMDGPU/SITypeRewriter.cpp b/contrib/llvm/lib/Target/AMDGPU/SITypeRewriter.cpp
index facc0c7..aad6853 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SITypeRewriter.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SITypeRewriter.cpp
@@ -42,9 +42,7 @@ public:
SITypeRewriter() : FunctionPass(ID) { }
bool doInitialization(Module &M) override;
bool runOnFunction(Function &F) override;
- const char *getPassName() const override {
- return "SI Type Rewriter";
- }
+ StringRef getPassName() const override { return "SI Type Rewriter"; }
void visitLoadInst(LoadInst &I);
void visitCallInst(CallInst &I);
void visitBitCast(BitCastInst &I);
diff --git a/contrib/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp b/contrib/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
index 1534d58..a613a22 100644
--- a/contrib/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
@@ -53,10 +53,28 @@
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/LiveInterval.h"
+#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SlotIndexes.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <vector>
using namespace llvm;
@@ -69,6 +87,25 @@ enum {
StateExact = 0x2,
};
+struct PrintState {
+public:
+ int State;
+
+ explicit PrintState(int State) : State(State) {}
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const PrintState &PS) {
+ if (PS.State & StateWQM)
+ OS << "WQM";
+ if (PS.State & StateExact) {
+ if (PS.State & StateWQM)
+ OS << '|';
+ OS << "Exact";
+ }
+
+ return OS;
+}
+
struct InstrInfo {
char Needs = 0;
char OutNeeds = 0;
@@ -84,7 +121,7 @@ struct WorkItem {
MachineBasicBlock *MBB = nullptr;
MachineInstr *MI = nullptr;
- WorkItem() {}
+ WorkItem() = default;
WorkItem(MachineBasicBlock *MBB) : MBB(MBB) {}
WorkItem(MachineInstr *MI) : MI(MI) {}
};
@@ -98,16 +135,26 @@ private:
DenseMap<const MachineInstr *, InstrInfo> Instructions;
DenseMap<MachineBasicBlock *, BlockInfo> Blocks;
- SmallVector<const MachineInstr *, 2> ExecExports;
SmallVector<MachineInstr *, 1> LiveMaskQueries;
+ void printInfo();
+
void markInstruction(MachineInstr &MI, char Flag,
std::vector<WorkItem> &Worklist);
+ void markUsesWQM(const MachineInstr &MI, std::vector<WorkItem> &Worklist);
char scanInstructions(MachineFunction &MF, std::vector<WorkItem> &Worklist);
void propagateInstruction(MachineInstr &MI, std::vector<WorkItem> &Worklist);
void propagateBlock(MachineBasicBlock &MBB, std::vector<WorkItem> &Worklist);
char analyzeFunction(MachineFunction &MF);
+ bool requiresCorrectState(const MachineInstr &MI) const;
+
+ MachineBasicBlock::iterator saveSCC(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator Before);
+ MachineBasicBlock::iterator
+ prepareInsertion(MachineBasicBlock &MBB, MachineBasicBlock::iterator First,
+ MachineBasicBlock::iterator Last, bool PreferLast,
+ bool SaveSCC);
void toExact(MachineBasicBlock &MBB, MachineBasicBlock::iterator Before,
unsigned SaveWQM, unsigned LiveMaskReg);
void toWQM(MachineBasicBlock &MBB, MachineBasicBlock::iterator Before,
@@ -124,9 +171,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "SI Whole Quad Mode";
- }
+ StringRef getPassName() const override { return "SI Whole Quad Mode"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LiveIntervals>();
@@ -135,7 +180,7 @@ public:
}
};
-} // End anonymous namespace
+} // end anonymous namespace
char SIWholeQuadMode::ID = 0;
@@ -151,6 +196,24 @@ FunctionPass *llvm::createSIWholeQuadModePass() {
return new SIWholeQuadMode;
}
+void SIWholeQuadMode::printInfo() {
+ for (const auto &BII : Blocks) {
+ dbgs() << "\nBB#" << BII.first->getNumber() << ":\n"
+ << " InNeeds = " << PrintState(BII.second.InNeeds)
+ << ", Needs = " << PrintState(BII.second.Needs)
+ << ", OutNeeds = " << PrintState(BII.second.OutNeeds) << "\n\n";
+
+ for (const MachineInstr &MI : *BII.first) {
+ auto III = Instructions.find(&MI);
+ if (III == Instructions.end())
+ continue;
+
+ dbgs() << " " << MI << " Needs = " << PrintState(III->second.Needs)
+ << ", OutNeeds = " << PrintState(III->second.OutNeeds) << '\n';
+ }
+ }
+}
+
void SIWholeQuadMode::markInstruction(MachineInstr &MI, char Flag,
std::vector<WorkItem> &Worklist) {
InstrInfo &II = Instructions[&MI];
@@ -168,6 +231,45 @@ void SIWholeQuadMode::markInstruction(MachineInstr &MI, char Flag,
Worklist.push_back(&MI);
}
+/// Mark all instructions defining the uses in \p MI as WQM.
+void SIWholeQuadMode::markUsesWQM(const MachineInstr &MI,
+ std::vector<WorkItem> &Worklist) {
+ for (const MachineOperand &Use : MI.uses()) {
+ if (!Use.isReg() || !Use.isUse())
+ continue;
+
+ unsigned Reg = Use.getReg();
+
+ // Handle physical registers that we need to track; this is mostly relevant
+ // for VCC, which can appear as the (implicit) input of a uniform branch,
+ // e.g. when a loop counter is stored in a VGPR.
+ if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
+ if (Reg == AMDGPU::EXEC)
+ continue;
+
+ for (MCRegUnitIterator RegUnit(Reg, TRI); RegUnit.isValid(); ++RegUnit) {
+ LiveRange &LR = LIS->getRegUnit(*RegUnit);
+ const VNInfo *Value = LR.Query(LIS->getInstructionIndex(MI)).valueIn();
+ if (!Value)
+ continue;
+
+ // Since we're in machine SSA, we do not need to track physical
+ // registers across basic blocks.
+ if (Value->isPHIDef())
+ continue;
+
+ markInstruction(*LIS->getInstructionFromIndex(Value->def), StateWQM,
+ Worklist);
+ }
+
+ continue;
+ }
+
+ for (MachineInstr &DefMI : MRI->def_instructions(Use.getReg()))
+ markInstruction(DefMI, StateWQM, Worklist);
+ }
+}
+
// Scan instructions to determine which ones require an Exact execmask and
// which ones seed WQM requirements.
char SIWholeQuadMode::scanInstructions(MachineFunction &MF,
@@ -183,16 +285,19 @@ char SIWholeQuadMode::scanInstructions(MachineFunction &MF,
unsigned Opcode = MI.getOpcode();
char Flags = 0;
- if (TII->isWQM(Opcode) || TII->isDS(Opcode)) {
+ if (TII->isDS(Opcode)) {
Flags = StateWQM;
+ } else if (TII->isWQM(Opcode)) {
+ // Sampling instructions don't need to produce results for all pixels
+ // in a quad, they just require all inputs of a quad to have been
+ // computed for derivatives.
+ markUsesWQM(MI, Worklist);
+ GlobalFlags |= StateWQM;
+ continue;
} else if (TII->isDisableWQM(MI)) {
Flags = StateExact;
} else {
- // Handle export instructions with the exec mask valid flag set
- if (Opcode == AMDGPU::EXP) {
- if (MI.getOperand(4).getImm() != 0)
- ExecExports.push_back(&MI);
- } else if (Opcode == AMDGPU::SI_PS_LIVE) {
+ if (Opcode == AMDGPU::SI_PS_LIVE) {
LiveMaskQueries.push_back(&MI);
} else if (WQMOutputs) {
// The function is in machine SSA form, which means that physical
@@ -259,43 +364,9 @@ void SIWholeQuadMode::propagateInstruction(MachineInstr &MI,
// Propagate WQM flag to instruction inputs
assert(II.Needs != (StateWQM | StateExact));
- if (II.Needs != StateWQM)
- return;
-
- for (const MachineOperand &Use : MI.uses()) {
- if (!Use.isReg() || !Use.isUse())
- continue;
-
- unsigned Reg = Use.getReg();
-
- // Handle physical registers that we need to track; this is mostly relevant
- // for VCC, which can appear as the (implicit) input of a uniform branch,
- // e.g. when a loop counter is stored in a VGPR.
- if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
- if (Reg == AMDGPU::EXEC)
- continue;
- for (MCRegUnitIterator RegUnit(Reg, TRI); RegUnit.isValid(); ++RegUnit) {
- LiveRange &LR = LIS->getRegUnit(*RegUnit);
- const VNInfo *Value = LR.Query(LIS->getInstructionIndex(MI)).valueIn();
- if (!Value)
- continue;
-
- // Since we're in machine SSA, we do not need to track physical
- // registers across basic blocks.
- if (Value->isPHIDef())
- continue;
-
- markInstruction(*LIS->getInstructionFromIndex(Value->def), StateWQM,
- Worklist);
- }
-
- continue;
- }
-
- for (MachineInstr &DefMI : MRI->def_instructions(Use.getReg()))
- markInstruction(DefMI, StateWQM, Worklist);
- }
+ if (II.Needs == StateWQM)
+ markUsesWQM(MI, Worklist);
}
void SIWholeQuadMode::propagateBlock(MachineBasicBlock &MBB,
@@ -351,32 +422,140 @@ char SIWholeQuadMode::analyzeFunction(MachineFunction &MF) {
return GlobalFlags;
}
+/// Whether \p MI really requires the exec state computed during analysis.
+///
+/// Scalar instructions must occasionally be marked WQM for correct propagation
+/// (e.g. thread masks leading up to branches), but when it comes to actual
+/// execution, they don't care about EXEC.
+bool SIWholeQuadMode::requiresCorrectState(const MachineInstr &MI) const {
+ if (MI.isTerminator())
+ return true;
+
+ // Skip instructions that are not affected by EXEC
+ if (TII->isScalarUnit(MI))
+ return false;
+
+ // Generic instructions such as COPY will either disappear by register
+ // coalescing or be lowered to SALU or VALU instructions.
+ if (MI.isTransient()) {
+ if (MI.getNumExplicitOperands() >= 1) {
+ const MachineOperand &Op = MI.getOperand(0);
+ if (Op.isReg()) {
+ if (TRI->isSGPRReg(*MRI, Op.getReg())) {
+ // SGPR instructions are not affected by EXEC
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+MachineBasicBlock::iterator
+SIWholeQuadMode::saveSCC(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator Before) {
+ unsigned SaveReg = MRI->createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);
+
+ MachineInstr *Save =
+ BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::COPY), SaveReg)
+ .addReg(AMDGPU::SCC);
+ MachineInstr *Restore =
+ BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::COPY), AMDGPU::SCC)
+ .addReg(SaveReg);
+
+ LIS->InsertMachineInstrInMaps(*Save);
+ LIS->InsertMachineInstrInMaps(*Restore);
+ LIS->createAndComputeVirtRegInterval(SaveReg);
+
+ return Restore;
+}
+
+// Return an iterator in the (inclusive) range [First, Last] at which
+// instructions can be safely inserted, keeping in mind that some of the
+// instructions we want to add necessarily clobber SCC.
+MachineBasicBlock::iterator SIWholeQuadMode::prepareInsertion(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator First,
+ MachineBasicBlock::iterator Last, bool PreferLast, bool SaveSCC) {
+ if (!SaveSCC)
+ return PreferLast ? Last : First;
+
+ LiveRange &LR = LIS->getRegUnit(*MCRegUnitIterator(AMDGPU::SCC, TRI));
+ auto MBBE = MBB.end();
+ SlotIndex FirstIdx = First != MBBE ? LIS->getInstructionIndex(*First)
+ : LIS->getMBBEndIdx(&MBB);
+ SlotIndex LastIdx =
+ Last != MBBE ? LIS->getInstructionIndex(*Last) : LIS->getMBBEndIdx(&MBB);
+ SlotIndex Idx = PreferLast ? LastIdx : FirstIdx;
+ const LiveRange::Segment *S;
+
+ for (;;) {
+ S = LR.getSegmentContaining(Idx);
+ if (!S)
+ break;
+
+ if (PreferLast) {
+ SlotIndex Next = S->start.getBaseIndex();
+ if (Next < FirstIdx)
+ break;
+ Idx = Next;
+ } else {
+ SlotIndex Next = S->end.getNextIndex().getBaseIndex();
+ if (Next > LastIdx)
+ break;
+ Idx = Next;
+ }
+ }
+
+ MachineBasicBlock::iterator MBBI;
+
+ if (MachineInstr *MI = LIS->getInstructionFromIndex(Idx))
+ MBBI = MI;
+ else {
+ assert(Idx == LIS->getMBBEndIdx(&MBB));
+ MBBI = MBB.end();
+ }
+
+ if (S)
+ MBBI = saveSCC(MBB, MBBI);
+
+ return MBBI;
+}
+
void SIWholeQuadMode::toExact(MachineBasicBlock &MBB,
MachineBasicBlock::iterator Before,
unsigned SaveWQM, unsigned LiveMaskReg) {
+ MachineInstr *MI;
+
if (SaveWQM) {
- BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::S_AND_SAVEEXEC_B64),
- SaveWQM)
- .addReg(LiveMaskReg);
+ MI = BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::S_AND_SAVEEXEC_B64),
+ SaveWQM)
+ .addReg(LiveMaskReg);
} else {
- BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::S_AND_B64),
- AMDGPU::EXEC)
- .addReg(AMDGPU::EXEC)
- .addReg(LiveMaskReg);
+ MI = BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::S_AND_B64),
+ AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC)
+ .addReg(LiveMaskReg);
}
+
+ LIS->InsertMachineInstrInMaps(*MI);
}
void SIWholeQuadMode::toWQM(MachineBasicBlock &MBB,
MachineBasicBlock::iterator Before,
unsigned SavedWQM) {
+ MachineInstr *MI;
+
if (SavedWQM) {
- BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::COPY), AMDGPU::EXEC)
- .addReg(SavedWQM);
+ MI = BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::COPY), AMDGPU::EXEC)
+ .addReg(SavedWQM);
} else {
- BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::S_WQM_B64),
- AMDGPU::EXEC)
- .addReg(AMDGPU::EXEC);
+ MI = BuildMI(MBB, Before, DebugLoc(), TII->get(AMDGPU::S_WQM_B64),
+ AMDGPU::EXEC)
+ .addReg(AMDGPU::EXEC);
}
+
+ LIS->InsertMachineInstrInMaps(*MI);
}
void SIWholeQuadMode::processBlock(MachineBasicBlock &MBB, unsigned LiveMaskReg,
@@ -395,72 +574,82 @@ void SIWholeQuadMode::processBlock(MachineBasicBlock &MBB, unsigned LiveMaskReg,
if (!isEntry && !(BI.Needs & StateExact) && BI.OutNeeds != StateExact)
return;
+ DEBUG(dbgs() << "\nProcessing block BB#" << MBB.getNumber() << ":\n");
+
unsigned SavedWQMReg = 0;
bool WQMFromExec = isEntry;
char State = isEntry ? StateExact : StateWQM;
auto II = MBB.getFirstNonPHI(), IE = MBB.end();
- while (II != IE) {
- MachineInstr &MI = *II;
- ++II;
+ if (isEntry)
+ ++II; // Skip the instruction that saves LiveMask
- // Skip instructions that are not affected by EXEC
- if (TII->isScalarUnit(MI) && !MI.isTerminator())
- continue;
+ MachineBasicBlock::iterator First = IE;
+ for (;;) {
+ MachineBasicBlock::iterator Next = II;
+ char Needs = 0;
+ char OutNeeds = 0;
- // Generic instructions such as COPY will either disappear by register
- // coalescing or be lowered to SALU or VALU instructions.
- if (TargetInstrInfo::isGenericOpcode(MI.getOpcode())) {
- if (MI.getNumExplicitOperands() >= 1) {
- const MachineOperand &Op = MI.getOperand(0);
- if (Op.isReg()) {
- if (TRI->isSGPRReg(*MRI, Op.getReg())) {
- // SGPR instructions are not affected by EXEC
- continue;
- }
+ if (First == IE)
+ First = II;
+
+ if (II != IE) {
+ MachineInstr &MI = *II;
+
+ if (requiresCorrectState(MI)) {
+ auto III = Instructions.find(&MI);
+ if (III != Instructions.end()) {
+ Needs = III->second.Needs;
+ OutNeeds = III->second.OutNeeds;
}
}
- }
- char Needs = 0;
- char OutNeeds = 0;
- auto InstrInfoIt = Instructions.find(&MI);
- if (InstrInfoIt != Instructions.end()) {
- Needs = InstrInfoIt->second.Needs;
- OutNeeds = InstrInfoIt->second.OutNeeds;
-
- // Make sure to switch to Exact mode before the end of the block when
- // Exact and only Exact is needed further downstream.
- if (OutNeeds == StateExact && MI.isTerminator()) {
- assert(Needs == 0);
+ if (MI.isTerminator() && !Needs && OutNeeds == StateExact)
+ Needs = StateExact;
+
+ if (MI.getOpcode() == AMDGPU::SI_ELSE && BI.OutNeeds == StateExact)
+ MI.getOperand(3).setImm(1);
+
+ ++Next;
+ } else {
+ // End of basic block
+ if (BI.OutNeeds & StateWQM)
+ Needs = StateWQM;
+ else if (BI.OutNeeds == StateExact)
Needs = StateExact;
- }
}
- // State switching
- if (Needs && State != Needs) {
- if (Needs == StateExact) {
- assert(!SavedWQMReg);
+ if (Needs) {
+ if (Needs != State) {
+ MachineBasicBlock::iterator Before =
+ prepareInsertion(MBB, First, II, Needs == StateWQM,
+ Needs == StateExact || WQMFromExec);
- if (!WQMFromExec && (OutNeeds & StateWQM))
- SavedWQMReg = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
+ if (Needs == StateExact) {
+ if (!WQMFromExec && (OutNeeds & StateWQM))
+ SavedWQMReg = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
- toExact(MBB, &MI, SavedWQMReg, LiveMaskReg);
- } else {
- assert(WQMFromExec == (SavedWQMReg == 0));
- toWQM(MBB, &MI, SavedWQMReg);
- SavedWQMReg = 0;
+ toExact(MBB, Before, SavedWQMReg, LiveMaskReg);
+ } else {
+ assert(WQMFromExec == (SavedWQMReg == 0));
+
+ toWQM(MBB, Before, SavedWQMReg);
+
+ if (SavedWQMReg) {
+ LIS->createAndComputeVirtRegInterval(SavedWQMReg);
+ SavedWQMReg = 0;
+ }
+ }
+
+ State = Needs;
}
- State = Needs;
+ First = IE;
}
- }
- if ((BI.OutNeeds & StateWQM) && State != StateWQM) {
- assert(WQMFromExec == (SavedWQMReg == 0));
- toWQM(MBB, MBB.end(), SavedWQMReg);
- } else if (BI.OutNeeds == StateExact && State != StateExact) {
- toExact(MBB, MBB.end(), 0, LiveMaskReg);
+ if (II == IE)
+ break;
+ II = Next;
}
}
@@ -468,8 +657,11 @@ void SIWholeQuadMode::lowerLiveMaskQueries(unsigned LiveMaskReg) {
for (MachineInstr *MI : LiveMaskQueries) {
const DebugLoc &DL = MI->getDebugLoc();
unsigned Dest = MI->getOperand(0).getReg();
- BuildMI(*MI->getParent(), MI, DL, TII->get(AMDGPU::COPY), Dest)
- .addReg(LiveMaskReg);
+ MachineInstr *Copy =
+ BuildMI(*MI->getParent(), MI, DL, TII->get(AMDGPU::COPY), Dest)
+ .addReg(LiveMaskReg);
+
+ LIS->ReplaceMachineInstrInMaps(*MI, *Copy);
MI->eraseFromParent();
}
}
@@ -480,7 +672,6 @@ bool SIWholeQuadMode::runOnMachineFunction(MachineFunction &MF) {
Instructions.clear();
Blocks.clear();
- ExecExports.clear();
LiveMaskQueries.clear();
const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
@@ -504,8 +695,10 @@ bool SIWholeQuadMode::runOnMachineFunction(MachineFunction &MF) {
if (GlobalFlags & StateExact || !LiveMaskQueries.empty()) {
LiveMaskReg = MRI->createVirtualRegister(&AMDGPU::SReg_64RegClass);
- BuildMI(Entry, EntryMI, DebugLoc(), TII->get(AMDGPU::COPY), LiveMaskReg)
- .addReg(AMDGPU::EXEC);
+ MachineInstr *MI = BuildMI(Entry, EntryMI, DebugLoc(),
+ TII->get(AMDGPU::COPY), LiveMaskReg)
+ .addReg(AMDGPU::EXEC);
+ LIS->InsertMachineInstrInMaps(*MI);
}
if (GlobalFlags == StateWQM) {
@@ -520,11 +713,18 @@ bool SIWholeQuadMode::runOnMachineFunction(MachineFunction &MF) {
}
}
+ DEBUG(printInfo());
+
lowerLiveMaskQueries(LiveMaskReg);
// Handle the general case
for (auto BII : Blocks)
processBlock(*BII.first, LiveMaskReg, BII.first == &*MF.begin());
+ // Physical registers like SCC aren't tracked by default anyway, so just
+ // removing the ranges we computed is the simplest option for maintaining
+ // the analysis results.
+ LIS->removeRegUnit(*MCRegUnitIterator(AMDGPU::SCC, TRI));
+
return true;
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/SMInstructions.td b/contrib/llvm/lib/Target/AMDGPU/SMInstructions.td
new file mode 100644
index 0000000..0265648
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/SMInstructions.td
@@ -0,0 +1,535 @@
+//===---- SMInstructions.td - Scalar Memory Instruction Defintions --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def smrd_offset_8 : NamedOperandU32<"SMRDOffset8",
+ NamedMatchClass<"SMRDOffset8">> {
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def smrd_offset_20 : NamedOperandU32<"SMRDOffset20",
+ NamedMatchClass<"SMRDOffset20">> {
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+//===----------------------------------------------------------------------===//
+// Scalar Memory classes
+//===----------------------------------------------------------------------===//
+
+class SM_Pseudo <string opName, dag outs, dag ins, string asmOps, list<dag> pattern=[]> :
+ InstSI <outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+
+ let LGKM_CNT = 1;
+ let SMRD = 1;
+ let mayStore = 0;
+ let mayLoad = 1;
+ let hasSideEffects = 0;
+ let UseNamedOperandTable = 1;
+ let SchedRW = [WriteSMEM];
+ let SubtargetPredicate = isGCN;
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ bits<1> has_sbase = 1;
+ bits<1> has_sdst = 1;
+ bit has_glc = 0;
+ bits<1> has_offset = 1;
+ bits<1> offset_is_imm = 0;
+}
+
+class SM_Real <SM_Pseudo ps>
+ : InstSI<ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+
+ // encoding
+ bits<7> sbase;
+ bits<7> sdst;
+ bits<32> offset;
+ bits<1> imm = !if(ps.has_offset, ps.offset_is_imm, 0);
+}
+
+class SM_Load_Pseudo <string opName, dag outs, dag ins, string asmOps, list<dag> pattern=[]>
+ : SM_Pseudo<opName, outs, ins, asmOps, pattern> {
+ RegisterClass BaseClass;
+ let mayLoad = 1;
+ let mayStore = 0;
+ let has_glc = 1;
+}
+
+class SM_Store_Pseudo <string opName, dag ins, string asmOps, list<dag> pattern = []>
+ : SM_Pseudo<opName, (outs), ins, asmOps, pattern> {
+ RegisterClass BaseClass;
+ RegisterClass SrcClass;
+ let mayLoad = 0;
+ let mayStore = 1;
+ let has_glc = 1;
+ let ScalarStore = 1;
+}
+
+multiclass SM_Pseudo_Loads<string opName,
+ RegisterClass baseClass,
+ RegisterClass dstClass> {
+ def _IMM : SM_Load_Pseudo <opName,
+ (outs dstClass:$sdst),
+ (ins baseClass:$sbase, i32imm:$offset, i1imm:$glc),
+ " $sdst, $sbase, $offset$glc", []> {
+ let offset_is_imm = 1;
+ let BaseClass = baseClass;
+ let PseudoInstr = opName # "_IMM";
+ let has_glc = 1;
+ }
+
+ def _SGPR : SM_Load_Pseudo <opName,
+ (outs dstClass:$sdst),
+ (ins baseClass:$sbase, SReg_32:$soff, i1imm:$glc),
+ " $sdst, $sbase, $offset$glc", []> {
+ let BaseClass = baseClass;
+ let PseudoInstr = opName # "_SGPR";
+ let has_glc = 1;
+ }
+}
+
+multiclass SM_Pseudo_Stores<string opName,
+ RegisterClass baseClass,
+ RegisterClass srcClass> {
+ def _IMM : SM_Store_Pseudo <opName,
+ (ins srcClass:$sdata, baseClass:$sbase, i32imm:$offset, i1imm:$glc),
+ " $sdata, $sbase, $offset$glc", []> {
+ let offset_is_imm = 1;
+ let BaseClass = baseClass;
+ let SrcClass = srcClass;
+ let PseudoInstr = opName # "_IMM";
+ }
+
+ def _SGPR : SM_Store_Pseudo <opName,
+ (ins srcClass:$sdata, baseClass:$sbase, SReg_32:$soff, i1imm:$glc),
+ " $sdata, $sbase, $offset$glc", []> {
+ let BaseClass = baseClass;
+ let SrcClass = srcClass;
+ let PseudoInstr = opName # "_SGPR";
+ }
+}
+
+class SM_Time_Pseudo<string opName, SDPatternOperator node> : SM_Pseudo<
+ opName, (outs SReg_64_XEXEC:$sdst), (ins),
+ " $sdst", [(set i64:$sdst, (node))]> {
+ let hasSideEffects = 1;
+ // FIXME: mayStore = ? is a workaround for tablegen bug for different
+ // inferred mayStore flags for the instruction pattern vs. standalone
+ // Pat. Each considers the other contradictory.
+ let mayStore = ?;
+ let mayLoad = ?;
+ let has_sbase = 0;
+ let has_offset = 0;
+}
+
+class SM_Inval_Pseudo <string opName, SDPatternOperator node> : SM_Pseudo<
+ opName, (outs), (ins), "", [(node)]> {
+ let hasSideEffects = 1;
+ let mayStore = 1;
+ let has_sdst = 0;
+ let has_sbase = 0;
+ let has_offset = 0;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Scalar Memory Instructions
+//===----------------------------------------------------------------------===//
+
+// We are using the SReg_32_XM0 and not the SReg_32 register class for 32-bit
+// SMRD instructions, because the SReg_32_XM0 register class does not include M0
+// and writing to M0 from an SMRD instruction will hang the GPU.
+
+// XXX - SMEM instructions do not allow exec for data operand, but
+// does sdst for SMRD on SI/CI?
+defm S_LOAD_DWORD : SM_Pseudo_Loads <"s_load_dword", SReg_64, SReg_32_XM0_XEXEC>;
+defm S_LOAD_DWORDX2 : SM_Pseudo_Loads <"s_load_dwordx2", SReg_64, SReg_64_XEXEC>;
+defm S_LOAD_DWORDX4 : SM_Pseudo_Loads <"s_load_dwordx4", SReg_64, SReg_128>;
+defm S_LOAD_DWORDX8 : SM_Pseudo_Loads <"s_load_dwordx8", SReg_64, SReg_256>;
+defm S_LOAD_DWORDX16 : SM_Pseudo_Loads <"s_load_dwordx16", SReg_64, SReg_512>;
+
+defm S_BUFFER_LOAD_DWORD : SM_Pseudo_Loads <
+ "s_buffer_load_dword", SReg_128, SReg_32_XM0_XEXEC
+>;
+
+// FIXME: exec_lo/exec_hi appear to be allowed for SMRD loads on
+// SI/CI, bit disallowed for SMEM on VI.
+defm S_BUFFER_LOAD_DWORDX2 : SM_Pseudo_Loads <
+ "s_buffer_load_dwordx2", SReg_128, SReg_64_XEXEC
+>;
+
+defm S_BUFFER_LOAD_DWORDX4 : SM_Pseudo_Loads <
+ "s_buffer_load_dwordx4", SReg_128, SReg_128
+>;
+
+defm S_BUFFER_LOAD_DWORDX8 : SM_Pseudo_Loads <
+ "s_buffer_load_dwordx8", SReg_128, SReg_256
+>;
+
+defm S_BUFFER_LOAD_DWORDX16 : SM_Pseudo_Loads <
+ "s_buffer_load_dwordx16", SReg_128, SReg_512
+>;
+
+defm S_STORE_DWORD : SM_Pseudo_Stores <"s_store_dword", SReg_64, SReg_32_XM0_XEXEC>;
+defm S_STORE_DWORDX2 : SM_Pseudo_Stores <"s_store_dwordx2", SReg_64, SReg_64_XEXEC>;
+defm S_STORE_DWORDX4 : SM_Pseudo_Stores <"s_store_dwordx4", SReg_64, SReg_128>;
+
+defm S_BUFFER_STORE_DWORD : SM_Pseudo_Stores <
+ "s_buffer_store_dword", SReg_128, SReg_32_XM0_XEXEC
+>;
+
+defm S_BUFFER_STORE_DWORDX2 : SM_Pseudo_Stores <
+ "s_buffer_store_dwordx2", SReg_128, SReg_64_XEXEC
+>;
+
+defm S_BUFFER_STORE_DWORDX4 : SM_Pseudo_Stores <
+ "s_buffer_store_dwordx4", SReg_128, SReg_128
+>;
+
+
+def S_MEMTIME : SM_Time_Pseudo <"s_memtime", int_amdgcn_s_memtime>;
+def S_DCACHE_INV : SM_Inval_Pseudo <"s_dcache_inv", int_amdgcn_s_dcache_inv>;
+
+let SubtargetPredicate = isCIVI in {
+def S_DCACHE_INV_VOL : SM_Inval_Pseudo <"s_dcache_inv_vol", int_amdgcn_s_dcache_inv_vol>;
+} // let SubtargetPredicate = isCIVI
+
+let SubtargetPredicate = isVI in {
+def S_DCACHE_WB : SM_Inval_Pseudo <"s_dcache_wb", int_amdgcn_s_dcache_wb>;
+def S_DCACHE_WB_VOL : SM_Inval_Pseudo <"s_dcache_wb_vol", int_amdgcn_s_dcache_wb_vol>;
+def S_MEMREALTIME : SM_Time_Pseudo <"s_memrealtime", int_amdgcn_s_memrealtime>;
+} // SubtargetPredicate = isVI
+
+
+
+//===----------------------------------------------------------------------===//
+// Scalar Memory Patterns
+//===----------------------------------------------------------------------===//
+
+
+def smrd_load : PatFrag <(ops node:$ptr), (load node:$ptr), [{
+ auto Ld = cast<LoadSDNode>(N);
+ return Ld->getAlignment() >= 4 &&
+ ((Ld->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS &&
+ static_cast<const SITargetLowering *>(getTargetLowering())->isMemOpUniform(N)) ||
+ (Subtarget->getScalarizeGlobalBehavior() && Ld->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS &&
+ static_cast<const SITargetLowering *>(getTargetLowering())->isMemOpUniform(N) &&
+ static_cast<const SITargetLowering *>(getTargetLowering())->isMemOpHasNoClobberedMemOperand(N)));
+}]>;
+
+def SMRDImm : ComplexPattern<i64, 2, "SelectSMRDImm">;
+def SMRDImm32 : ComplexPattern<i64, 2, "SelectSMRDImm32">;
+def SMRDSgpr : ComplexPattern<i64, 2, "SelectSMRDSgpr">;
+def SMRDBufferImm : ComplexPattern<i32, 1, "SelectSMRDBufferImm">;
+def SMRDBufferImm32 : ComplexPattern<i32, 1, "SelectSMRDBufferImm32">;
+def SMRDBufferSgpr : ComplexPattern<i32, 1, "SelectSMRDBufferSgpr">;
+
+let Predicates = [isGCN] in {
+
+multiclass SMRD_Pattern <string Instr, ValueType vt> {
+
+ // 1. IMM offset
+ def : Pat <
+ (smrd_load (SMRDImm i64:$sbase, i32:$offset)),
+ (vt (!cast<SM_Pseudo>(Instr#"_IMM") $sbase, $offset, 0))
+ >;
+
+ // 2. SGPR offset
+ def : Pat <
+ (smrd_load (SMRDSgpr i64:$sbase, i32:$offset)),
+ (vt (!cast<SM_Pseudo>(Instr#"_SGPR") $sbase, $offset, 0))
+ >;
+}
+
+let Predicates = [isSICI] in {
+def : Pat <
+ (i64 (readcyclecounter)),
+ (S_MEMTIME)
+>;
+}
+
+// Global and constant loads can be selected to either MUBUF or SMRD
+// instructions, but SMRD instructions are faster so we want the instruction
+// selector to prefer those.
+let AddedComplexity = 100 in {
+
+defm : SMRD_Pattern <"S_LOAD_DWORD", i32>;
+defm : SMRD_Pattern <"S_LOAD_DWORDX2", v2i32>;
+defm : SMRD_Pattern <"S_LOAD_DWORDX4", v4i32>;
+defm : SMRD_Pattern <"S_LOAD_DWORDX8", v8i32>;
+defm : SMRD_Pattern <"S_LOAD_DWORDX16", v16i32>;
+
+// 1. Offset as an immediate
+def SM_LOAD_PATTERN : Pat < // name this pattern to reuse AddedComplexity on CI
+ (SIload_constant v4i32:$sbase, (SMRDBufferImm i32:$offset)),
+ (S_BUFFER_LOAD_DWORD_IMM $sbase, $offset, 0)
+>;
+
+// 2. Offset loaded in an 32bit SGPR
+def : Pat <
+ (SIload_constant v4i32:$sbase, (SMRDBufferSgpr i32:$offset)),
+ (S_BUFFER_LOAD_DWORD_SGPR $sbase, $offset, 0)
+>;
+
+} // End let AddedComplexity = 100
+
+} // let Predicates = [isGCN]
+
+let Predicates = [isVI] in {
+
+// 1. Offset as 20bit DWORD immediate
+def : Pat <
+ (SIload_constant v4i32:$sbase, IMM20bit:$offset),
+ (S_BUFFER_LOAD_DWORD_IMM $sbase, (as_i32imm $offset), 0)
+>;
+
+def : Pat <
+ (i64 (readcyclecounter)),
+ (S_MEMREALTIME)
+>;
+
+} // let Predicates = [isVI]
+
+
+//===----------------------------------------------------------------------===//
+// Targets
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SI
+//===----------------------------------------------------------------------===//
+
+class SMRD_Real_si <bits<5> op, SM_Pseudo ps>
+ : SM_Real<ps>
+ , SIMCInstr<ps.PseudoInstr, SIEncodingFamily.SI>
+ , Enc32 {
+
+ let AssemblerPredicates = [isSICI];
+ let DecoderNamespace = "SICI";
+
+ let Inst{7-0} = !if(ps.has_offset, offset{7-0}, ?);
+ let Inst{8} = imm;
+ let Inst{14-9} = !if(ps.has_sbase, sbase{6-1}, ?);
+ let Inst{21-15} = !if(ps.has_sdst, sdst{6-0}, ?);
+ let Inst{26-22} = op;
+ let Inst{31-27} = 0x18; //encoding
+}
+
+// FIXME: Assembler should reject trying to use glc on SMRD
+// instructions on SI.
+multiclass SM_Real_Loads_si<bits<5> op, string ps,
+ SM_Load_Pseudo immPs = !cast<SM_Load_Pseudo>(ps#_IMM),
+ SM_Load_Pseudo sgprPs = !cast<SM_Load_Pseudo>(ps#_SGPR)> {
+
+ def _IMM_si : SMRD_Real_si <op, immPs> {
+ let InOperandList = (ins immPs.BaseClass:$sbase, smrd_offset_8:$offset, GLC:$glc);
+ }
+
+ // FIXME: The operand name $offset is inconsistent with $soff used
+ // in the pseudo
+ def _SGPR_si : SMRD_Real_si <op, sgprPs> {
+ let InOperandList = (ins sgprPs.BaseClass:$sbase, SReg_32:$offset, GLC:$glc);
+ }
+
+}
+
+defm S_LOAD_DWORD : SM_Real_Loads_si <0x00, "S_LOAD_DWORD">;
+defm S_LOAD_DWORDX2 : SM_Real_Loads_si <0x01, "S_LOAD_DWORDX2">;
+defm S_LOAD_DWORDX4 : SM_Real_Loads_si <0x02, "S_LOAD_DWORDX4">;
+defm S_LOAD_DWORDX8 : SM_Real_Loads_si <0x03, "S_LOAD_DWORDX8">;
+defm S_LOAD_DWORDX16 : SM_Real_Loads_si <0x04, "S_LOAD_DWORDX16">;
+defm S_BUFFER_LOAD_DWORD : SM_Real_Loads_si <0x08, "S_BUFFER_LOAD_DWORD">;
+defm S_BUFFER_LOAD_DWORDX2 : SM_Real_Loads_si <0x09, "S_BUFFER_LOAD_DWORDX2">;
+defm S_BUFFER_LOAD_DWORDX4 : SM_Real_Loads_si <0x0a, "S_BUFFER_LOAD_DWORDX4">;
+defm S_BUFFER_LOAD_DWORDX8 : SM_Real_Loads_si <0x0b, "S_BUFFER_LOAD_DWORDX8">;
+defm S_BUFFER_LOAD_DWORDX16 : SM_Real_Loads_si <0x0c, "S_BUFFER_LOAD_DWORDX16">;
+
+def S_MEMTIME_si : SMRD_Real_si <0x1e, S_MEMTIME>;
+def S_DCACHE_INV_si : SMRD_Real_si <0x1f, S_DCACHE_INV>;
+
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+class SMEM_Real_vi <bits<8> op, SM_Pseudo ps>
+ : SM_Real<ps>
+ , SIMCInstr<ps.PseudoInstr, SIEncodingFamily.VI>
+ , Enc64 {
+ bit glc;
+
+ let AssemblerPredicates = [isVI];
+ let DecoderNamespace = "VI";
+
+ let Inst{5-0} = !if(ps.has_sbase, sbase{6-1}, ?);
+ let Inst{12-6} = !if(ps.has_sdst, sdst{6-0}, ?);
+
+ let Inst{16} = !if(ps.has_glc, glc, ?);
+ let Inst{17} = imm;
+ let Inst{25-18} = op;
+ let Inst{31-26} = 0x30; //encoding
+ let Inst{51-32} = !if(ps.has_offset, offset{19-0}, ?);
+}
+
+multiclass SM_Real_Loads_vi<bits<8> op, string ps,
+ SM_Load_Pseudo immPs = !cast<SM_Load_Pseudo>(ps#_IMM),
+ SM_Load_Pseudo sgprPs = !cast<SM_Load_Pseudo>(ps#_SGPR)> {
+ def _IMM_vi : SMEM_Real_vi <op, immPs> {
+ let InOperandList = (ins immPs.BaseClass:$sbase, smrd_offset_20:$offset, GLC:$glc);
+ }
+ def _SGPR_vi : SMEM_Real_vi <op, sgprPs> {
+ let InOperandList = (ins sgprPs.BaseClass:$sbase, SReg_32:$offset, GLC:$glc);
+ }
+}
+
+class SMEM_Real_Store_vi <bits<8> op, SM_Pseudo ps> : SMEM_Real_vi <op, ps> {
+ // encoding
+ bits<7> sdata;
+
+ let sdst = ?;
+ let Inst{12-6} = !if(ps.has_sdst, sdata{6-0}, ?);
+}
+
+multiclass SM_Real_Stores_vi<bits<8> op, string ps,
+ SM_Store_Pseudo immPs = !cast<SM_Store_Pseudo>(ps#_IMM),
+ SM_Store_Pseudo sgprPs = !cast<SM_Store_Pseudo>(ps#_SGPR)> {
+ // FIXME: The operand name $offset is inconsistent with $soff used
+ // in the pseudo
+ def _IMM_vi : SMEM_Real_Store_vi <op, immPs> {
+ let InOperandList = (ins immPs.SrcClass:$sdata, immPs.BaseClass:$sbase, smrd_offset_20:$offset, GLC:$glc);
+ }
+
+ def _SGPR_vi : SMEM_Real_Store_vi <op, sgprPs> {
+ let InOperandList = (ins sgprPs.SrcClass:$sdata, sgprPs.BaseClass:$sbase, SReg_32:$offset, GLC:$glc);
+ }
+}
+
+defm S_LOAD_DWORD : SM_Real_Loads_vi <0x00, "S_LOAD_DWORD">;
+defm S_LOAD_DWORDX2 : SM_Real_Loads_vi <0x01, "S_LOAD_DWORDX2">;
+defm S_LOAD_DWORDX4 : SM_Real_Loads_vi <0x02, "S_LOAD_DWORDX4">;
+defm S_LOAD_DWORDX8 : SM_Real_Loads_vi <0x03, "S_LOAD_DWORDX8">;
+defm S_LOAD_DWORDX16 : SM_Real_Loads_vi <0x04, "S_LOAD_DWORDX16">;
+defm S_BUFFER_LOAD_DWORD : SM_Real_Loads_vi <0x08, "S_BUFFER_LOAD_DWORD">;
+defm S_BUFFER_LOAD_DWORDX2 : SM_Real_Loads_vi <0x09, "S_BUFFER_LOAD_DWORDX2">;
+defm S_BUFFER_LOAD_DWORDX4 : SM_Real_Loads_vi <0x0a, "S_BUFFER_LOAD_DWORDX4">;
+defm S_BUFFER_LOAD_DWORDX8 : SM_Real_Loads_vi <0x0b, "S_BUFFER_LOAD_DWORDX8">;
+defm S_BUFFER_LOAD_DWORDX16 : SM_Real_Loads_vi <0x0c, "S_BUFFER_LOAD_DWORDX16">;
+
+defm S_STORE_DWORD : SM_Real_Stores_vi <0x10, "S_STORE_DWORD">;
+defm S_STORE_DWORDX2 : SM_Real_Stores_vi <0x11, "S_STORE_DWORDX2">;
+defm S_STORE_DWORDX4 : SM_Real_Stores_vi <0x12, "S_STORE_DWORDX4">;
+
+defm S_BUFFER_STORE_DWORD : SM_Real_Stores_vi <0x18, "S_BUFFER_STORE_DWORD">;
+defm S_BUFFER_STORE_DWORDX2 : SM_Real_Stores_vi <0x19, "S_BUFFER_STORE_DWORDX2">;
+defm S_BUFFER_STORE_DWORDX4 : SM_Real_Stores_vi <0x1a, "S_BUFFER_STORE_DWORDX4">;
+
+// These instructions use same encoding
+def S_DCACHE_INV_vi : SMEM_Real_vi <0x20, S_DCACHE_INV>;
+def S_DCACHE_WB_vi : SMEM_Real_vi <0x21, S_DCACHE_WB>;
+def S_DCACHE_INV_VOL_vi : SMEM_Real_vi <0x22, S_DCACHE_INV_VOL>;
+def S_DCACHE_WB_VOL_vi : SMEM_Real_vi <0x23, S_DCACHE_WB_VOL>;
+def S_MEMTIME_vi : SMEM_Real_vi <0x24, S_MEMTIME>;
+def S_MEMREALTIME_vi : SMEM_Real_vi <0x25, S_MEMREALTIME>;
+
+
+//===----------------------------------------------------------------------===//
+// CI
+//===----------------------------------------------------------------------===//
+
+def smrd_literal_offset : NamedOperandU32<"SMRDLiteralOffset",
+ NamedMatchClass<"SMRDLiteralOffset">> {
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+class SMRD_Real_Load_IMM_ci <bits<5> op, SM_Load_Pseudo ps> :
+ SM_Real<ps>,
+ Enc64 {
+
+ let AssemblerPredicates = [isCIOnly];
+ let DecoderNamespace = "CI";
+ let InOperandList = (ins ps.BaseClass:$sbase, smrd_literal_offset:$offset, GLC:$glc);
+
+ let LGKM_CNT = ps.LGKM_CNT;
+ let SMRD = ps.SMRD;
+ let mayLoad = ps.mayLoad;
+ let mayStore = ps.mayStore;
+ let hasSideEffects = ps.hasSideEffects;
+ let SchedRW = ps.SchedRW;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+
+ let Inst{7-0} = 0xff;
+ let Inst{8} = 0;
+ let Inst{14-9} = sbase{6-1};
+ let Inst{21-15} = sdst{6-0};
+ let Inst{26-22} = op;
+ let Inst{31-27} = 0x18; //encoding
+ let Inst{63-32} = offset{31-0};
+}
+
+def S_LOAD_DWORD_IMM_ci : SMRD_Real_Load_IMM_ci <0x00, S_LOAD_DWORD_IMM>;
+def S_LOAD_DWORDX2_IMM_ci : SMRD_Real_Load_IMM_ci <0x01, S_LOAD_DWORDX2_IMM>;
+def S_LOAD_DWORDX4_IMM_ci : SMRD_Real_Load_IMM_ci <0x02, S_LOAD_DWORDX4_IMM>;
+def S_LOAD_DWORDX8_IMM_ci : SMRD_Real_Load_IMM_ci <0x03, S_LOAD_DWORDX8_IMM>;
+def S_LOAD_DWORDX16_IMM_ci : SMRD_Real_Load_IMM_ci <0x04, S_LOAD_DWORDX16_IMM>;
+def S_BUFFER_LOAD_DWORD_IMM_ci : SMRD_Real_Load_IMM_ci <0x08, S_BUFFER_LOAD_DWORD_IMM>;
+def S_BUFFER_LOAD_DWORDX2_IMM_ci : SMRD_Real_Load_IMM_ci <0x09, S_BUFFER_LOAD_DWORDX2_IMM>;
+def S_BUFFER_LOAD_DWORDX4_IMM_ci : SMRD_Real_Load_IMM_ci <0x0a, S_BUFFER_LOAD_DWORDX4_IMM>;
+def S_BUFFER_LOAD_DWORDX8_IMM_ci : SMRD_Real_Load_IMM_ci <0x0b, S_BUFFER_LOAD_DWORDX8_IMM>;
+def S_BUFFER_LOAD_DWORDX16_IMM_ci : SMRD_Real_Load_IMM_ci <0x0c, S_BUFFER_LOAD_DWORDX16_IMM>;
+
+class SMRD_Real_ci <bits<5> op, SM_Pseudo ps>
+ : SM_Real<ps>
+ , SIMCInstr<ps.PseudoInstr, SIEncodingFamily.SI>
+ , Enc32 {
+
+ let AssemblerPredicates = [isCIOnly];
+ let DecoderNamespace = "CI";
+
+ let Inst{7-0} = !if(ps.has_offset, offset{7-0}, ?);
+ let Inst{8} = imm;
+ let Inst{14-9} = !if(ps.has_sbase, sbase{6-1}, ?);
+ let Inst{21-15} = !if(ps.has_sdst, sdst{6-0}, ?);
+ let Inst{26-22} = op;
+ let Inst{31-27} = 0x18; //encoding
+}
+
+def S_DCACHE_INV_VOL_ci : SMRD_Real_ci <0x1d, S_DCACHE_INV_VOL>;
+
+let AddedComplexity = SM_LOAD_PATTERN.AddedComplexity in {
+
+class SMRD_Pattern_ci <string Instr, ValueType vt> : Pat <
+ (smrd_load (SMRDImm32 i64:$sbase, i32:$offset)),
+ (vt (!cast<SM_Pseudo>(Instr#"_IMM_ci") $sbase, $offset, 0))> {
+ let Predicates = [isCIOnly];
+}
+
+def : SMRD_Pattern_ci <"S_LOAD_DWORD", i32>;
+def : SMRD_Pattern_ci <"S_LOAD_DWORDX2", v2i32>;
+def : SMRD_Pattern_ci <"S_LOAD_DWORDX4", v4i32>;
+def : SMRD_Pattern_ci <"S_LOAD_DWORDX8", v8i32>;
+def : SMRD_Pattern_ci <"S_LOAD_DWORDX16", v16i32>;
+
+def : Pat <
+ (SIload_constant v4i32:$sbase, (SMRDBufferImm32 i32:$offset)),
+ (S_BUFFER_LOAD_DWORD_IMM_ci $sbase, $offset, 0)> {
+ let Predicates = [isCI]; // should this be isCIOnly?
+}
+
+} // End let AddedComplexity = SM_LOAD_PATTERN.AddedComplexity
+
diff --git a/contrib/llvm/lib/Target/AMDGPU/SOPInstructions.td b/contrib/llvm/lib/Target/AMDGPU/SOPInstructions.td
new file mode 100644
index 0000000..73cd577
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/SOPInstructions.td
@@ -0,0 +1,1232 @@
+//===-- SOPInstructions.td - SOP Instruction Defintions -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def GPRIdxModeMatchClass : AsmOperandClass {
+ let Name = "GPRIdxMode";
+ let PredicateMethod = "isGPRIdxMode";
+ let RenderMethod = "addImmOperands";
+}
+
+def GPRIdxMode : Operand<i32> {
+ let PrintMethod = "printVGPRIndexMode";
+ let ParserMatchClass = GPRIdxModeMatchClass;
+ let OperandType = "OPERAND_IMMEDIATE";
+}
+
+//===----------------------------------------------------------------------===//
+// SOP1 Instructions
+//===----------------------------------------------------------------------===//
+
+class SOP1_Pseudo <string opName, dag outs, dag ins,
+ string asmOps, list<dag> pattern=[]> :
+ InstSI <outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let SubtargetPredicate = isGCN;
+
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SALU = 1;
+ let SOP1 = 1;
+ let SchedRW = [WriteSALU];
+ let Size = 4;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ bits<1> has_src0 = 1;
+ bits<1> has_sdst = 1;
+}
+
+class SOP1_Real<bits<8> op, SOP1_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList,
+ ps.Mnemonic # " " # ps.AsmOperands, []>,
+ Enc32 {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+ let Size = 4;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+
+ // encoding
+ bits<7> sdst;
+ bits<8> src0;
+
+ let Inst{7-0} = !if(ps.has_src0, src0, ?);
+ let Inst{15-8} = op;
+ let Inst{22-16} = !if(ps.has_sdst, sdst, ?);
+ let Inst{31-23} = 0x17d; //encoding;
+}
+
+class SOP1_32 <string opName, list<dag> pattern=[]> : SOP1_Pseudo <
+ opName, (outs SReg_32:$sdst), (ins SSrc_b32:$src0),
+ "$sdst, $src0", pattern
+>;
+
+// 32-bit input, no output.
+class SOP1_0_32 <string opName, list<dag> pattern = []> : SOP1_Pseudo <
+ opName, (outs), (ins SSrc_b32:$src0),
+ "$src0", pattern> {
+ let has_sdst = 0;
+}
+
+class SOP1_64 <string opName, list<dag> pattern=[]> : SOP1_Pseudo <
+ opName, (outs SReg_64:$sdst), (ins SSrc_b64:$src0),
+ "$sdst, $src0", pattern
+>;
+
+// 64-bit input, 32-bit output.
+class SOP1_32_64 <string opName, list<dag> pattern=[]> : SOP1_Pseudo <
+ opName, (outs SReg_32:$sdst), (ins SSrc_b64:$src0),
+ "$sdst, $src0", pattern
+>;
+
+// 32-bit input, 64-bit output.
+class SOP1_64_32 <string opName, list<dag> pattern=[]> : SOP1_Pseudo <
+ opName, (outs SReg_64:$sdst), (ins SSrc_b32:$src0),
+ "$sdst, $src0", pattern
+>;
+
+// no input, 64-bit output.
+class SOP1_64_0 <string opName, list<dag> pattern=[]> : SOP1_Pseudo <
+ opName, (outs SReg_64:$sdst), (ins), "$sdst", pattern> {
+ let has_src0 = 0;
+}
+
+// 64-bit input, no output
+class SOP1_1 <string opName, list<dag> pattern=[]> : SOP1_Pseudo <
+ opName, (outs), (ins SReg_64:$src0), "$src0", pattern> {
+ let has_sdst = 0;
+}
+
+
+let isMoveImm = 1 in {
+ let isReMaterializable = 1, isAsCheapAsAMove = 1 in {
+ def S_MOV_B32 : SOP1_32 <"s_mov_b32">;
+ def S_MOV_B64 : SOP1_64 <"s_mov_b64">;
+ } // End isRematerializeable = 1
+
+ let Uses = [SCC] in {
+ def S_CMOV_B32 : SOP1_32 <"s_cmov_b32">;
+ def S_CMOV_B64 : SOP1_64 <"s_cmov_b64">;
+ } // End Uses = [SCC]
+} // End isMoveImm = 1
+
+let Defs = [SCC] in {
+ def S_NOT_B32 : SOP1_32 <"s_not_b32",
+ [(set i32:$sdst, (not i32:$src0))]
+ >;
+
+ def S_NOT_B64 : SOP1_64 <"s_not_b64",
+ [(set i64:$sdst, (not i64:$src0))]
+ >;
+ def S_WQM_B32 : SOP1_32 <"s_wqm_b32">;
+ def S_WQM_B64 : SOP1_64 <"s_wqm_b64">;
+} // End Defs = [SCC]
+
+
+def S_BREV_B32 : SOP1_32 <"s_brev_b32",
+ [(set i32:$sdst, (bitreverse i32:$src0))]
+>;
+def S_BREV_B64 : SOP1_64 <"s_brev_b64">;
+
+let Defs = [SCC] in {
+def S_BCNT0_I32_B32 : SOP1_32 <"s_bcnt0_i32_b32">;
+def S_BCNT0_I32_B64 : SOP1_32_64 <"s_bcnt0_i32_b64">;
+def S_BCNT1_I32_B32 : SOP1_32 <"s_bcnt1_i32_b32",
+ [(set i32:$sdst, (ctpop i32:$src0))]
+>;
+def S_BCNT1_I32_B64 : SOP1_32_64 <"s_bcnt1_i32_b64">;
+} // End Defs = [SCC]
+
+def S_FF0_I32_B32 : SOP1_32 <"s_ff0_i32_b32">;
+def S_FF0_I32_B64 : SOP1_32_64 <"s_ff0_i32_b64">;
+def S_FF1_I32_B32 : SOP1_32 <"s_ff1_i32_b32",
+ [(set i32:$sdst, (cttz_zero_undef i32:$src0))]
+>;
+def S_FF1_I32_B64 : SOP1_32_64 <"s_ff1_i32_b64">;
+
+def S_FLBIT_I32_B32 : SOP1_32 <"s_flbit_i32_b32",
+ [(set i32:$sdst, (AMDGPUffbh_u32 i32:$src0))]
+>;
+
+def S_FLBIT_I32_B64 : SOP1_32_64 <"s_flbit_i32_b64">;
+def S_FLBIT_I32 : SOP1_32 <"s_flbit_i32",
+ [(set i32:$sdst, (AMDGPUffbh_i32 i32:$src0))]
+>;
+def S_FLBIT_I32_I64 : SOP1_32_64 <"s_flbit_i32_i64">;
+def S_SEXT_I32_I8 : SOP1_32 <"s_sext_i32_i8",
+ [(set i32:$sdst, (sext_inreg i32:$src0, i8))]
+>;
+def S_SEXT_I32_I16 : SOP1_32 <"s_sext_i32_i16",
+ [(set i32:$sdst, (sext_inreg i32:$src0, i16))]
+>;
+
+def S_BITSET0_B32 : SOP1_32 <"s_bitset0_b32">;
+def S_BITSET0_B64 : SOP1_64_32 <"s_bitset0_b64">;
+def S_BITSET1_B32 : SOP1_32 <"s_bitset1_b32">;
+def S_BITSET1_B64 : SOP1_64_32 <"s_bitset1_b64">;
+def S_GETPC_B64 : SOP1_64_0 <"s_getpc_b64">;
+
+let isTerminator = 1, isBarrier = 1,
+ isBranch = 1, isIndirectBranch = 1 in {
+def S_SETPC_B64 : SOP1_1 <"s_setpc_b64">;
+}
+def S_SWAPPC_B64 : SOP1_64 <"s_swappc_b64">;
+def S_RFE_B64 : SOP1_1 <"s_rfe_b64">;
+
+let hasSideEffects = 1, Uses = [EXEC], Defs = [EXEC, SCC] in {
+
+def S_AND_SAVEEXEC_B64 : SOP1_64 <"s_and_saveexec_b64">;
+def S_OR_SAVEEXEC_B64 : SOP1_64 <"s_or_saveexec_b64">;
+def S_XOR_SAVEEXEC_B64 : SOP1_64 <"s_xor_saveexec_b64">;
+def S_ANDN2_SAVEEXEC_B64 : SOP1_64 <"s_andn2_saveexec_b64">;
+def S_ORN2_SAVEEXEC_B64 : SOP1_64 <"s_orn2_saveexec_b64">;
+def S_NAND_SAVEEXEC_B64 : SOP1_64 <"s_nand_saveexec_b64">;
+def S_NOR_SAVEEXEC_B64 : SOP1_64 <"s_nor_saveexec_b64">;
+def S_XNOR_SAVEEXEC_B64 : SOP1_64 <"s_xnor_saveexec_b64">;
+
+} // End hasSideEffects = 1, Uses = [EXEC], Defs = [EXEC, SCC]
+
+def S_QUADMASK_B32 : SOP1_32 <"s_quadmask_b32">;
+def S_QUADMASK_B64 : SOP1_64 <"s_quadmask_b64">;
+
+let Uses = [M0] in {
+def S_MOVRELS_B32 : SOP1_32 <"s_movrels_b32">;
+def S_MOVRELS_B64 : SOP1_64 <"s_movrels_b64">;
+def S_MOVRELD_B32 : SOP1_32 <"s_movreld_b32">;
+def S_MOVRELD_B64 : SOP1_64 <"s_movreld_b64">;
+} // End Uses = [M0]
+
+def S_CBRANCH_JOIN : SOP1_1 <"s_cbranch_join">;
+def S_MOV_REGRD_B32 : SOP1_32 <"s_mov_regrd_b32">;
+let Defs = [SCC] in {
+def S_ABS_I32 : SOP1_32 <"s_abs_i32">;
+} // End Defs = [SCC]
+def S_MOV_FED_B32 : SOP1_32 <"s_mov_fed_b32">;
+
+let SubtargetPredicate = HasVGPRIndexMode in {
+def S_SET_GPR_IDX_IDX : SOP1_0_32<"s_set_gpr_idx_idx"> {
+ let Uses = [M0];
+ let Defs = [M0];
+}
+}
+
+//===----------------------------------------------------------------------===//
+// SOP2 Instructions
+//===----------------------------------------------------------------------===//
+
+class SOP2_Pseudo<string opName, dag outs, dag ins,
+ string asmOps, list<dag> pattern=[]> :
+ InstSI<outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let SubtargetPredicate = isGCN;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SALU = 1;
+ let SOP2 = 1;
+ let SchedRW = [WriteSALU];
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ bits<1> has_sdst = 1;
+
+ // Pseudo instructions have no encodings, but adding this field here allows
+ // us to do:
+ // let sdst = xxx in {
+ // for multiclasses that include both real and pseudo instructions.
+ // field bits<7> sdst = 0;
+ // let Size = 4; // Do we need size here?
+}
+
+class SOP2_Real<bits<7> op, SOP2_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList,
+ ps.Mnemonic # " " # ps.AsmOperands, []>,
+ Enc32 {
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+
+ // encoding
+ bits<7> sdst;
+ bits<8> src0;
+ bits<8> src1;
+
+ let Inst{7-0} = src0;
+ let Inst{15-8} = src1;
+ let Inst{22-16} = !if(ps.has_sdst, sdst, ?);
+ let Inst{29-23} = op;
+ let Inst{31-30} = 0x2; // encoding
+}
+
+
+class SOP2_32 <string opName, list<dag> pattern=[]> : SOP2_Pseudo <
+ opName, (outs SReg_32:$sdst), (ins SSrc_b32:$src0, SSrc_b32:$src1),
+ "$sdst, $src0, $src1", pattern
+>;
+
+class SOP2_64 <string opName, list<dag> pattern=[]> : SOP2_Pseudo <
+ opName, (outs SReg_64:$sdst), (ins SSrc_b64:$src0, SSrc_b64:$src1),
+ "$sdst, $src0, $src1", pattern
+>;
+
+class SOP2_64_32 <string opName, list<dag> pattern=[]> : SOP2_Pseudo <
+ opName, (outs SReg_64:$sdst), (ins SSrc_b64:$src0, SSrc_b32:$src1),
+ "$sdst, $src0, $src1", pattern
+>;
+
+class SOP2_64_32_32 <string opName, list<dag> pattern=[]> : SOP2_Pseudo <
+ opName, (outs SReg_64:$sdst), (ins SSrc_b32:$src0, SSrc_b32:$src1),
+ "$sdst, $src0, $src1", pattern
+>;
+
+let Defs = [SCC] in { // Carry out goes to SCC
+let isCommutable = 1 in {
+def S_ADD_U32 : SOP2_32 <"s_add_u32">;
+def S_ADD_I32 : SOP2_32 <"s_add_i32",
+ [(set i32:$sdst, (add SSrc_b32:$src0, SSrc_b32:$src1))]
+>;
+} // End isCommutable = 1
+
+def S_SUB_U32 : SOP2_32 <"s_sub_u32">;
+def S_SUB_I32 : SOP2_32 <"s_sub_i32",
+ [(set i32:$sdst, (sub SSrc_b32:$src0, SSrc_b32:$src1))]
+>;
+
+let Uses = [SCC] in { // Carry in comes from SCC
+let isCommutable = 1 in {
+def S_ADDC_U32 : SOP2_32 <"s_addc_u32",
+ [(set i32:$sdst, (adde (i32 SSrc_b32:$src0), (i32 SSrc_b32:$src1)))]>;
+} // End isCommutable = 1
+
+def S_SUBB_U32 : SOP2_32 <"s_subb_u32",
+ [(set i32:$sdst, (sube (i32 SSrc_b32:$src0), (i32 SSrc_b32:$src1)))]>;
+} // End Uses = [SCC]
+
+
+let isCommutable = 1 in {
+def S_MIN_I32 : SOP2_32 <"s_min_i32",
+ [(set i32:$sdst, (smin i32:$src0, i32:$src1))]
+>;
+def S_MIN_U32 : SOP2_32 <"s_min_u32",
+ [(set i32:$sdst, (umin i32:$src0, i32:$src1))]
+>;
+def S_MAX_I32 : SOP2_32 <"s_max_i32",
+ [(set i32:$sdst, (smax i32:$src0, i32:$src1))]
+>;
+def S_MAX_U32 : SOP2_32 <"s_max_u32",
+ [(set i32:$sdst, (umax i32:$src0, i32:$src1))]
+>;
+} // End isCommutable = 1
+} // End Defs = [SCC]
+
+
+let Uses = [SCC] in {
+ def S_CSELECT_B32 : SOP2_32 <"s_cselect_b32">;
+ def S_CSELECT_B64 : SOP2_64 <"s_cselect_b64">;
+} // End Uses = [SCC]
+
+let Defs = [SCC] in {
+let isCommutable = 1 in {
+def S_AND_B32 : SOP2_32 <"s_and_b32",
+ [(set i32:$sdst, (and i32:$src0, i32:$src1))]
+>;
+
+def S_AND_B64 : SOP2_64 <"s_and_b64",
+ [(set i64:$sdst, (and i64:$src0, i64:$src1))]
+>;
+
+def S_OR_B32 : SOP2_32 <"s_or_b32",
+ [(set i32:$sdst, (or i32:$src0, i32:$src1))]
+>;
+
+def S_OR_B64 : SOP2_64 <"s_or_b64",
+ [(set i64:$sdst, (or i64:$src0, i64:$src1))]
+>;
+
+def S_XOR_B32 : SOP2_32 <"s_xor_b32",
+ [(set i32:$sdst, (xor i32:$src0, i32:$src1))]
+>;
+
+def S_XOR_B64 : SOP2_64 <"s_xor_b64",
+ [(set i64:$sdst, (xor i64:$src0, i64:$src1))]
+>;
+} // End isCommutable = 1
+
+def S_ANDN2_B32 : SOP2_32 <"s_andn2_b32">;
+def S_ANDN2_B64 : SOP2_64 <"s_andn2_b64">;
+def S_ORN2_B32 : SOP2_32 <"s_orn2_b32">;
+def S_ORN2_B64 : SOP2_64 <"s_orn2_b64">;
+def S_NAND_B32 : SOP2_32 <"s_nand_b32">;
+def S_NAND_B64 : SOP2_64 <"s_nand_b64">;
+def S_NOR_B32 : SOP2_32 <"s_nor_b32">;
+def S_NOR_B64 : SOP2_64 <"s_nor_b64">;
+def S_XNOR_B32 : SOP2_32 <"s_xnor_b32">;
+def S_XNOR_B64 : SOP2_64 <"s_xnor_b64">;
+} // End Defs = [SCC]
+
+// Use added complexity so these patterns are preferred to the VALU patterns.
+let AddedComplexity = 1 in {
+
+let Defs = [SCC] in {
+def S_LSHL_B32 : SOP2_32 <"s_lshl_b32",
+ [(set i32:$sdst, (shl i32:$src0, i32:$src1))]
+>;
+def S_LSHL_B64 : SOP2_64_32 <"s_lshl_b64",
+ [(set i64:$sdst, (shl i64:$src0, i32:$src1))]
+>;
+def S_LSHR_B32 : SOP2_32 <"s_lshr_b32",
+ [(set i32:$sdst, (srl i32:$src0, i32:$src1))]
+>;
+def S_LSHR_B64 : SOP2_64_32 <"s_lshr_b64",
+ [(set i64:$sdst, (srl i64:$src0, i32:$src1))]
+>;
+def S_ASHR_I32 : SOP2_32 <"s_ashr_i32",
+ [(set i32:$sdst, (sra i32:$src0, i32:$src1))]
+>;
+def S_ASHR_I64 : SOP2_64_32 <"s_ashr_i64",
+ [(set i64:$sdst, (sra i64:$src0, i32:$src1))]
+>;
+} // End Defs = [SCC]
+
+def S_BFM_B32 : SOP2_32 <"s_bfm_b32",
+ [(set i32:$sdst, (AMDGPUbfm i32:$src0, i32:$src1))]>;
+def S_BFM_B64 : SOP2_64_32_32 <"s_bfm_b64">;
+def S_MUL_I32 : SOP2_32 <"s_mul_i32",
+ [(set i32:$sdst, (mul i32:$src0, i32:$src1))]> {
+ let isCommutable = 1;
+}
+
+} // End AddedComplexity = 1
+
+let Defs = [SCC] in {
+def S_BFE_U32 : SOP2_32 <"s_bfe_u32">;
+def S_BFE_I32 : SOP2_32 <"s_bfe_i32">;
+def S_BFE_U64 : SOP2_64_32 <"s_bfe_u64">;
+def S_BFE_I64 : SOP2_64_32 <"s_bfe_i64">;
+} // End Defs = [SCC]
+
+def S_CBRANCH_G_FORK : SOP2_Pseudo <
+ "s_cbranch_g_fork", (outs),
+ (ins SReg_64:$src0, SReg_64:$src1),
+ "$src0, $src1"
+> {
+ let has_sdst = 0;
+}
+
+let Defs = [SCC] in {
+def S_ABSDIFF_I32 : SOP2_32 <"s_absdiff_i32">;
+} // End Defs = [SCC]
+
+
+//===----------------------------------------------------------------------===//
+// SOPK Instructions
+//===----------------------------------------------------------------------===//
+
+class SOPK_Pseudo <string opName, dag outs, dag ins,
+ string asmOps, list<dag> pattern=[]> :
+ InstSI <outs, ins, "", pattern>,
+ SIMCInstr<opName, SIEncodingFamily.NONE> {
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let SubtargetPredicate = isGCN;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SALU = 1;
+ let SOPK = 1;
+ let SchedRW = [WriteSALU];
+ let UseNamedOperandTable = 1;
+ string Mnemonic = opName;
+ string AsmOperands = asmOps;
+
+ bits<1> has_sdst = 1;
+}
+
+class SOPK_Real<bits<5> op, SOPK_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList,
+ ps.Mnemonic # " " # ps.AsmOperands, []> {
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let DisableEncoding = ps.DisableEncoding;
+ let Constraints = ps.Constraints;
+
+ // encoding
+ bits<7> sdst;
+ bits<16> simm16;
+ bits<32> imm;
+}
+
+class SOPK_Real32<bits<5> op, SOPK_Pseudo ps> :
+ SOPK_Real <op, ps>,
+ Enc32 {
+ let Inst{15-0} = simm16;
+ let Inst{22-16} = !if(ps.has_sdst, sdst, ?);
+ let Inst{27-23} = op;
+ let Inst{31-28} = 0xb; //encoding
+}
+
+class SOPK_Real64<bits<5> op, SOPK_Pseudo ps> :
+ SOPK_Real<op, ps>,
+ Enc64 {
+ let Inst{15-0} = simm16;
+ let Inst{22-16} = !if(ps.has_sdst, sdst, ?);
+ let Inst{27-23} = op;
+ let Inst{31-28} = 0xb; //encoding
+ let Inst{63-32} = imm;
+}
+
+class SOPKInstTable <bit is_sopk, string cmpOp = ""> {
+ bit IsSOPK = is_sopk;
+ string BaseCmpOp = cmpOp;
+}
+
+class SOPK_32 <string opName, list<dag> pattern=[]> : SOPK_Pseudo <
+ opName,
+ (outs SReg_32:$sdst),
+ (ins u16imm:$simm16),
+ "$sdst, $simm16",
+ pattern>;
+
+class SOPK_SCC <string opName, string base_op = ""> : SOPK_Pseudo <
+ opName,
+ (outs),
+ (ins SReg_32:$sdst, u16imm:$simm16),
+ "$sdst, $simm16", []>,
+ SOPKInstTable<1, base_op>{
+ let Defs = [SCC];
+}
+
+class SOPK_32TIE <string opName, list<dag> pattern=[]> : SOPK_Pseudo <
+ opName,
+ (outs SReg_32:$sdst),
+ (ins SReg_32:$src0, u16imm:$simm16),
+ "$sdst, $simm16",
+ pattern
+>;
+
+let isReMaterializable = 1, isMoveImm = 1 in {
+def S_MOVK_I32 : SOPK_32 <"s_movk_i32">;
+} // End isReMaterializable = 1
+let Uses = [SCC] in {
+def S_CMOVK_I32 : SOPK_32 <"s_cmovk_i32">;
+}
+
+let isCompare = 1 in {
+
+// This instruction is disabled for now until we can figure out how to teach
+// the instruction selector to correctly use the S_CMP* vs V_CMP*
+// instructions.
+//
+// When this instruction is enabled the code generator sometimes produces this
+// invalid sequence:
+//
+// SCC = S_CMPK_EQ_I32 SGPR0, imm
+// VCC = COPY SCC
+// VGPR0 = V_CNDMASK VCC, VGPR0, VGPR1
+//
+// def S_CMPK_EQ_I32 : SOPK_SCC <"s_cmpk_eq_i32",
+// [(set i1:$dst, (setcc i32:$src0, imm:$src1, SETEQ))]
+// >;
+
+def S_CMPK_EQ_I32 : SOPK_SCC <"s_cmpk_eq_i32", "s_cmp_eq_i32">;
+def S_CMPK_LG_I32 : SOPK_SCC <"s_cmpk_lg_i32", "s_cmp_lg_i32">;
+def S_CMPK_GT_I32 : SOPK_SCC <"s_cmpk_gt_i32", "s_cmp_gt_i32">;
+def S_CMPK_GE_I32 : SOPK_SCC <"s_cmpk_ge_i32", "s_cmp_ge_i32">;
+def S_CMPK_LT_I32 : SOPK_SCC <"s_cmpk_lt_i32", "s_cmp_lt_i32">;
+def S_CMPK_LE_I32 : SOPK_SCC <"s_cmpk_le_i32", "s_cmp_le_i32">;
+
+let SOPKZext = 1 in {
+def S_CMPK_EQ_U32 : SOPK_SCC <"s_cmpk_eq_u32", "s_cmp_eq_u32">;
+def S_CMPK_LG_U32 : SOPK_SCC <"s_cmpk_lg_u32", "s_cmp_lg_u32">;
+def S_CMPK_GT_U32 : SOPK_SCC <"s_cmpk_gt_u32", "s_cmp_gt_u32">;
+def S_CMPK_GE_U32 : SOPK_SCC <"s_cmpk_ge_u32", "s_cmp_ge_u32">;
+def S_CMPK_LT_U32 : SOPK_SCC <"s_cmpk_lt_u32", "s_cmp_lt_u32">;
+def S_CMPK_LE_U32 : SOPK_SCC <"s_cmpk_le_u32", "s_cmp_le_u32">;
+} // End SOPKZext = 1
+} // End isCompare = 1
+
+let Defs = [SCC], isCommutable = 1, DisableEncoding = "$src0",
+ Constraints = "$sdst = $src0" in {
+ def S_ADDK_I32 : SOPK_32TIE <"s_addk_i32">;
+ def S_MULK_I32 : SOPK_32TIE <"s_mulk_i32">;
+}
+
+def S_CBRANCH_I_FORK : SOPK_Pseudo <
+ "s_cbranch_i_fork",
+ (outs), (ins SReg_64:$sdst, u16imm:$simm16),
+ "$sdst, $simm16"
+>;
+
+let mayLoad = 1 in {
+def S_GETREG_B32 : SOPK_Pseudo <
+ "s_getreg_b32",
+ (outs SReg_32:$sdst), (ins hwreg:$simm16),
+ "$sdst, $simm16"
+>;
+}
+
+let hasSideEffects = 1 in {
+
+def S_SETREG_B32 : SOPK_Pseudo <
+ "s_setreg_b32",
+ (outs), (ins SReg_32:$sdst, hwreg:$simm16),
+ "$simm16, $sdst",
+ [(AMDGPUsetreg i32:$sdst, (i16 timm:$simm16))]
+>;
+
+// FIXME: Not on SI?
+//def S_GETREG_REGRD_B32 : SOPK_32 <sopk<0x14, 0x13>, "s_getreg_regrd_b32">;
+
+def S_SETREG_IMM32_B32 : SOPK_Pseudo <
+ "s_setreg_imm32_b32",
+ (outs), (ins i32imm:$imm, hwreg:$simm16),
+ "$simm16, $imm"> {
+ let Size = 8; // Unlike every other SOPK instruction.
+ let has_sdst = 0;
+}
+
+} // End hasSideEffects = 1
+
+//===----------------------------------------------------------------------===//
+// SOPC Instructions
+//===----------------------------------------------------------------------===//
+
+class SOPCe <bits<7> op> : Enc32 {
+ bits<8> src0;
+ bits<8> src1;
+
+ let Inst{7-0} = src0;
+ let Inst{15-8} = src1;
+ let Inst{22-16} = op;
+ let Inst{31-23} = 0x17e;
+}
+
+class SOPC <bits<7> op, dag outs, dag ins, string asm,
+ list<dag> pattern = []> :
+ InstSI<outs, ins, asm, pattern>, SOPCe <op> {
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SALU = 1;
+ let SOPC = 1;
+ let isCodeGenOnly = 0;
+ let Defs = [SCC];
+ let SchedRW = [WriteSALU];
+ let UseNamedOperandTable = 1;
+ let SubtargetPredicate = isGCN;
+}
+
+class SOPC_Base <bits<7> op, RegisterOperand rc0, RegisterOperand rc1,
+ string opName, list<dag> pattern = []> : SOPC <
+ op, (outs), (ins rc0:$src0, rc1:$src1),
+ opName#" $src0, $src1", pattern > {
+ let Defs = [SCC];
+}
+class SOPC_Helper <bits<7> op, RegisterOperand rc, ValueType vt,
+ string opName, PatLeaf cond> : SOPC_Base <
+ op, rc, rc, opName,
+ [(set SCC, (si_setcc_uniform vt:$src0, vt:$src1, cond))] > {
+}
+
+class SOPC_CMP_32<bits<7> op, string opName,
+ PatLeaf cond = COND_NULL, string revOp = opName>
+ : SOPC_Helper<op, SSrc_b32, i32, opName, cond>,
+ Commutable_REV<revOp, !eq(revOp, opName)>,
+ SOPKInstTable<0, opName> {
+ let isCompare = 1;
+ let isCommutable = 1;
+}
+
+class SOPC_CMP_64<bits<7> op, string opName,
+ PatLeaf cond = COND_NULL, string revOp = opName>
+ : SOPC_Helper<op, SSrc_b64, i64, opName, cond>,
+ Commutable_REV<revOp, !eq(revOp, opName)> {
+ let isCompare = 1;
+ let isCommutable = 1;
+}
+
+class SOPC_32<bits<7> op, string opName, list<dag> pattern = []>
+ : SOPC_Base<op, SSrc_b32, SSrc_b32, opName, pattern>;
+
+class SOPC_64_32<bits<7> op, string opName, list<dag> pattern = []>
+ : SOPC_Base<op, SSrc_b64, SSrc_b32, opName, pattern>;
+
+def S_CMP_EQ_I32 : SOPC_CMP_32 <0x00, "s_cmp_eq_i32">;
+def S_CMP_LG_I32 : SOPC_CMP_32 <0x01, "s_cmp_lg_i32">;
+def S_CMP_GT_I32 : SOPC_CMP_32 <0x02, "s_cmp_gt_i32", COND_SGT>;
+def S_CMP_GE_I32 : SOPC_CMP_32 <0x03, "s_cmp_ge_i32", COND_SGE>;
+def S_CMP_LT_I32 : SOPC_CMP_32 <0x04, "s_cmp_lt_i32", COND_SLT, "s_cmp_gt_i32">;
+def S_CMP_LE_I32 : SOPC_CMP_32 <0x05, "s_cmp_le_i32", COND_SLE, "s_cmp_ge_i32">;
+def S_CMP_EQ_U32 : SOPC_CMP_32 <0x06, "s_cmp_eq_u32", COND_EQ>;
+def S_CMP_LG_U32 : SOPC_CMP_32 <0x07, "s_cmp_lg_u32", COND_NE>;
+def S_CMP_GT_U32 : SOPC_CMP_32 <0x08, "s_cmp_gt_u32", COND_UGT>;
+def S_CMP_GE_U32 : SOPC_CMP_32 <0x09, "s_cmp_ge_u32", COND_UGE>;
+def S_CMP_LT_U32 : SOPC_CMP_32 <0x0a, "s_cmp_lt_u32", COND_ULT, "s_cmp_gt_u32">;
+def S_CMP_LE_U32 : SOPC_CMP_32 <0x0b, "s_cmp_le_u32", COND_ULE, "s_cmp_ge_u32">;
+
+def S_BITCMP0_B32 : SOPC_32 <0x0c, "s_bitcmp0_b32">;
+def S_BITCMP1_B32 : SOPC_32 <0x0d, "s_bitcmp1_b32">;
+def S_BITCMP0_B64 : SOPC_64_32 <0x0e, "s_bitcmp0_b64">;
+def S_BITCMP1_B64 : SOPC_64_32 <0x0f, "s_bitcmp1_b64">;
+def S_SETVSKIP : SOPC_32 <0x10, "s_setvskip">;
+
+let SubtargetPredicate = isVI in {
+def S_CMP_EQ_U64 : SOPC_CMP_64 <0x12, "s_cmp_eq_u64", COND_EQ>;
+def S_CMP_LG_U64 : SOPC_CMP_64 <0x13, "s_cmp_lg_u64", COND_NE>;
+}
+
+let SubtargetPredicate = HasVGPRIndexMode in {
+def S_SET_GPR_IDX_ON : SOPC <0x11,
+ (outs),
+ (ins SSrc_b32:$src0, GPRIdxMode:$src1),
+ "s_set_gpr_idx_on $src0,$src1"> {
+ let Defs = [M0]; // No scc def
+ let Uses = [M0]; // Other bits of m0 unmodified.
+ let hasSideEffects = 1; // Sets mode.gpr_idx_en
+ let FixedSize = 1;
+}
+}
+
+//===----------------------------------------------------------------------===//
+// SOPP Instructions
+//===----------------------------------------------------------------------===//
+
+class SOPPe <bits<7> op> : Enc32 {
+ bits <16> simm16;
+
+ let Inst{15-0} = simm16;
+ let Inst{22-16} = op;
+ let Inst{31-23} = 0x17f; // encoding
+}
+
+class SOPP <bits<7> op, dag ins, string asm, list<dag> pattern = []> :
+ InstSI <(outs), ins, asm, pattern >, SOPPe <op> {
+
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SALU = 1;
+ let SOPP = 1;
+ let Size = 4;
+ let SchedRW = [WriteSALU];
+
+ let UseNamedOperandTable = 1;
+ let SubtargetPredicate = isGCN;
+}
+
+
+def S_NOP : SOPP <0x00000000, (ins i16imm:$simm16), "s_nop $simm16">;
+
+let isTerminator = 1 in {
+
+def S_ENDPGM : SOPP <0x00000001, (ins), "s_endpgm",
+ [(AMDGPUendpgm)]> {
+ let simm16 = 0;
+ let isBarrier = 1;
+ let isReturn = 1;
+}
+
+let isBranch = 1, SchedRW = [WriteBranch] in {
+def S_BRANCH : SOPP <
+ 0x00000002, (ins sopp_brtarget:$simm16), "s_branch $simm16",
+ [(br bb:$simm16)]> {
+ let isBarrier = 1;
+}
+
+let Uses = [SCC] in {
+def S_CBRANCH_SCC0 : SOPP <
+ 0x00000004, (ins sopp_brtarget:$simm16),
+ "s_cbranch_scc0 $simm16"
+>;
+def S_CBRANCH_SCC1 : SOPP <
+ 0x00000005, (ins sopp_brtarget:$simm16),
+ "s_cbranch_scc1 $simm16",
+ [(si_uniform_br_scc SCC, bb:$simm16)]
+>;
+} // End Uses = [SCC]
+
+let Uses = [VCC] in {
+def S_CBRANCH_VCCZ : SOPP <
+ 0x00000006, (ins sopp_brtarget:$simm16),
+ "s_cbranch_vccz $simm16"
+>;
+def S_CBRANCH_VCCNZ : SOPP <
+ 0x00000007, (ins sopp_brtarget:$simm16),
+ "s_cbranch_vccnz $simm16"
+>;
+} // End Uses = [VCC]
+
+let Uses = [EXEC] in {
+def S_CBRANCH_EXECZ : SOPP <
+ 0x00000008, (ins sopp_brtarget:$simm16),
+ "s_cbranch_execz $simm16"
+>;
+def S_CBRANCH_EXECNZ : SOPP <
+ 0x00000009, (ins sopp_brtarget:$simm16),
+ "s_cbranch_execnz $simm16"
+>;
+} // End Uses = [EXEC]
+
+
+} // End isBranch = 1
+} // End isTerminator = 1
+
+let hasSideEffects = 1 in {
+def S_BARRIER : SOPP <0x0000000a, (ins), "s_barrier",
+ [(int_amdgcn_s_barrier)]> {
+ let SchedRW = [WriteBarrier];
+ let simm16 = 0;
+ let mayLoad = 1;
+ let mayStore = 1;
+ let isConvergent = 1;
+}
+
+let mayLoad = 1, mayStore = 1, hasSideEffects = 1 in
+def S_WAITCNT : SOPP <0x0000000c, (ins WAIT_FLAG:$simm16), "s_waitcnt $simm16">;
+def S_SETHALT : SOPP <0x0000000d, (ins i16imm:$simm16), "s_sethalt $simm16">;
+
+// On SI the documentation says sleep for approximately 64 * low 2
+// bits, consistent with the reported maximum of 448. On VI the
+// maximum reported is 960 cycles, so 960 / 64 = 15 max, so is the
+// maximum really 15 on VI?
+def S_SLEEP : SOPP <0x0000000e, (ins i32imm:$simm16),
+ "s_sleep $simm16", [(int_amdgcn_s_sleep SIMM16bit:$simm16)]> {
+ let hasSideEffects = 1;
+ let mayLoad = 1;
+ let mayStore = 1;
+}
+
+def S_SETPRIO : SOPP <0x0000000f, (ins i16imm:$simm16), "s_setprio $simm16">;
+
+let Uses = [EXEC, M0] in {
+// FIXME: Should this be mayLoad+mayStore?
+def S_SENDMSG : SOPP <0x00000010, (ins SendMsgImm:$simm16), "s_sendmsg $simm16",
+ [(AMDGPUsendmsg (i32 imm:$simm16))]
+>;
+
+def S_SENDMSGHALT : SOPP <0x00000011, (ins SendMsgImm:$simm16), "s_sendmsghalt $simm16",
+ [(AMDGPUsendmsghalt (i32 imm:$simm16))]
+>;
+} // End Uses = [EXEC, M0]
+
+def S_TRAP : SOPP <0x00000012, (ins i16imm:$simm16), "s_trap $simm16">;
+def S_ICACHE_INV : SOPP <0x00000013, (ins), "s_icache_inv"> {
+ let simm16 = 0;
+}
+def S_INCPERFLEVEL : SOPP <0x00000014, (ins i32imm:$simm16), "s_incperflevel $simm16",
+ [(int_amdgcn_s_incperflevel SIMM16bit:$simm16)]> {
+ let hasSideEffects = 1;
+ let mayLoad = 1;
+ let mayStore = 1;
+}
+def S_DECPERFLEVEL : SOPP <0x00000015, (ins i32imm:$simm16), "s_decperflevel $simm16",
+ [(int_amdgcn_s_decperflevel SIMM16bit:$simm16)]> {
+ let hasSideEffects = 1;
+ let mayLoad = 1;
+ let mayStore = 1;
+}
+def S_TTRACEDATA : SOPP <0x00000016, (ins), "s_ttracedata"> {
+ let simm16 = 0;
+}
+
+let SubtargetPredicate = HasVGPRIndexMode in {
+def S_SET_GPR_IDX_OFF : SOPP<0x1c, (ins), "s_set_gpr_idx_off"> {
+ let simm16 = 0;
+}
+}
+} // End hasSideEffects
+
+let SubtargetPredicate = HasVGPRIndexMode in {
+def S_SET_GPR_IDX_MODE : SOPP<0x1d, (ins GPRIdxMode:$simm16),
+ "s_set_gpr_idx_mode$simm16"> {
+ let Defs = [M0];
+}
+}
+
+let Predicates = [isGCN] in {
+
+//===----------------------------------------------------------------------===//
+// S_GETREG_B32 Intrinsic Pattern.
+//===----------------------------------------------------------------------===//
+def : Pat <
+ (int_amdgcn_s_getreg imm:$simm16),
+ (S_GETREG_B32 (as_i16imm $simm16))
+>;
+
+//===----------------------------------------------------------------------===//
+// SOP1 Patterns
+//===----------------------------------------------------------------------===//
+
+def : Pat <
+ (i64 (ctpop i64:$src)),
+ (i64 (REG_SEQUENCE SReg_64,
+ (i32 (COPY_TO_REGCLASS (S_BCNT1_I32_B64 $src), SReg_32)), sub0,
+ (S_MOV_B32 (i32 0)), sub1))
+>;
+
+def : Pat <
+ (i32 (smax i32:$x, (i32 (ineg i32:$x)))),
+ (S_ABS_I32 $x)
+>;
+
+def : Pat <
+ (i16 imm:$imm),
+ (S_MOV_B32 imm:$imm)
+>;
+
+// Same as a 32-bit inreg
+def : Pat<
+ (i32 (sext i16:$src)),
+ (S_SEXT_I32_I16 $src)
+>;
+
+
+//===----------------------------------------------------------------------===//
+// SOP2 Patterns
+//===----------------------------------------------------------------------===//
+
+// V_ADD_I32_e32/S_ADD_U32 produces carry in VCC/SCC. For the vector
+// case, the sgpr-copies pass will fix this to use the vector version.
+def : Pat <
+ (i32 (addc i32:$src0, i32:$src1)),
+ (S_ADD_U32 $src0, $src1)
+>;
+
+// FIXME: We need to use COPY_TO_REGCLASS to work-around the fact that
+// REG_SEQUENCE patterns don't support instructions with multiple
+// outputs.
+def : Pat<
+ (i64 (zext i16:$src)),
+ (REG_SEQUENCE SReg_64,
+ (i32 (COPY_TO_REGCLASS (S_AND_B32 $src, (S_MOV_B32 (i32 0xffff))), SGPR_32)), sub0,
+ (S_MOV_B32 (i32 0)), sub1)
+>;
+
+def : Pat <
+ (i64 (sext i16:$src)),
+ (REG_SEQUENCE SReg_64, (i32 (S_SEXT_I32_I16 $src)), sub0,
+ (i32 (COPY_TO_REGCLASS (S_ASHR_I32 (i32 (S_SEXT_I32_I16 $src)), (S_MOV_B32 (i32 31))), SGPR_32)), sub1)
+>;
+
+def : Pat<
+ (i32 (zext i16:$src)),
+ (S_AND_B32 (S_MOV_B32 (i32 0xffff)), $src)
+>;
+
+
+
+//===----------------------------------------------------------------------===//
+// SOPP Patterns
+//===----------------------------------------------------------------------===//
+
+def : Pat <
+ (int_amdgcn_s_waitcnt i32:$simm16),
+ (S_WAITCNT (as_i16imm $simm16))
+>;
+
+} // End isGCN predicate
+
+
+//===----------------------------------------------------------------------===//
+// Real target instructions, move this to the appropriate subtarget TD file
+//===----------------------------------------------------------------------===//
+
+class Select_si<string opName> :
+ SIMCInstr<opName, SIEncodingFamily.SI> {
+ list<Predicate> AssemblerPredicates = [isSICI];
+ string DecoderNamespace = "SICI";
+}
+
+class SOP1_Real_si<bits<8> op, SOP1_Pseudo ps> :
+ SOP1_Real<op, ps>,
+ Select_si<ps.Mnemonic>;
+
+class SOP2_Real_si<bits<7> op, SOP2_Pseudo ps> :
+ SOP2_Real<op, ps>,
+ Select_si<ps.Mnemonic>;
+
+class SOPK_Real_si<bits<5> op, SOPK_Pseudo ps> :
+ SOPK_Real32<op, ps>,
+ Select_si<ps.Mnemonic>;
+
+def S_MOV_B32_si : SOP1_Real_si <0x03, S_MOV_B32>;
+def S_MOV_B64_si : SOP1_Real_si <0x04, S_MOV_B64>;
+def S_CMOV_B32_si : SOP1_Real_si <0x05, S_CMOV_B32>;
+def S_CMOV_B64_si : SOP1_Real_si <0x06, S_CMOV_B64>;
+def S_NOT_B32_si : SOP1_Real_si <0x07, S_NOT_B32>;
+def S_NOT_B64_si : SOP1_Real_si <0x08, S_NOT_B64>;
+def S_WQM_B32_si : SOP1_Real_si <0x09, S_WQM_B32>;
+def S_WQM_B64_si : SOP1_Real_si <0x0a, S_WQM_B64>;
+def S_BREV_B32_si : SOP1_Real_si <0x0b, S_BREV_B32>;
+def S_BREV_B64_si : SOP1_Real_si <0x0c, S_BREV_B64>;
+def S_BCNT0_I32_B32_si : SOP1_Real_si <0x0d, S_BCNT0_I32_B32>;
+def S_BCNT0_I32_B64_si : SOP1_Real_si <0x0e, S_BCNT0_I32_B64>;
+def S_BCNT1_I32_B32_si : SOP1_Real_si <0x0f, S_BCNT1_I32_B32>;
+def S_BCNT1_I32_B64_si : SOP1_Real_si <0x10, S_BCNT1_I32_B64>;
+def S_FF0_I32_B32_si : SOP1_Real_si <0x11, S_FF0_I32_B32>;
+def S_FF0_I32_B64_si : SOP1_Real_si <0x12, S_FF0_I32_B64>;
+def S_FF1_I32_B32_si : SOP1_Real_si <0x13, S_FF1_I32_B32>;
+def S_FF1_I32_B64_si : SOP1_Real_si <0x14, S_FF1_I32_B64>;
+def S_FLBIT_I32_B32_si : SOP1_Real_si <0x15, S_FLBIT_I32_B32>;
+def S_FLBIT_I32_B64_si : SOP1_Real_si <0x16, S_FLBIT_I32_B64>;
+def S_FLBIT_I32_si : SOP1_Real_si <0x17, S_FLBIT_I32>;
+def S_FLBIT_I32_I64_si : SOP1_Real_si <0x18, S_FLBIT_I32_I64>;
+def S_SEXT_I32_I8_si : SOP1_Real_si <0x19, S_SEXT_I32_I8>;
+def S_SEXT_I32_I16_si : SOP1_Real_si <0x1a, S_SEXT_I32_I16>;
+def S_BITSET0_B32_si : SOP1_Real_si <0x1b, S_BITSET0_B32>;
+def S_BITSET0_B64_si : SOP1_Real_si <0x1c, S_BITSET0_B64>;
+def S_BITSET1_B32_si : SOP1_Real_si <0x1d, S_BITSET1_B32>;
+def S_BITSET1_B64_si : SOP1_Real_si <0x1e, S_BITSET1_B64>;
+def S_GETPC_B64_si : SOP1_Real_si <0x1f, S_GETPC_B64>;
+def S_SETPC_B64_si : SOP1_Real_si <0x20, S_SETPC_B64>;
+def S_SWAPPC_B64_si : SOP1_Real_si <0x21, S_SWAPPC_B64>;
+def S_RFE_B64_si : SOP1_Real_si <0x22, S_RFE_B64>;
+def S_AND_SAVEEXEC_B64_si : SOP1_Real_si <0x24, S_AND_SAVEEXEC_B64>;
+def S_OR_SAVEEXEC_B64_si : SOP1_Real_si <0x25, S_OR_SAVEEXEC_B64>;
+def S_XOR_SAVEEXEC_B64_si : SOP1_Real_si <0x26, S_XOR_SAVEEXEC_B64>;
+def S_ANDN2_SAVEEXEC_B64_si: SOP1_Real_si <0x27, S_ANDN2_SAVEEXEC_B64>;
+def S_ORN2_SAVEEXEC_B64_si : SOP1_Real_si <0x28, S_ORN2_SAVEEXEC_B64>;
+def S_NAND_SAVEEXEC_B64_si : SOP1_Real_si <0x29, S_NAND_SAVEEXEC_B64>;
+def S_NOR_SAVEEXEC_B64_si : SOP1_Real_si <0x2a, S_NOR_SAVEEXEC_B64>;
+def S_XNOR_SAVEEXEC_B64_si : SOP1_Real_si <0x2b, S_XNOR_SAVEEXEC_B64>;
+def S_QUADMASK_B32_si : SOP1_Real_si <0x2c, S_QUADMASK_B32>;
+def S_QUADMASK_B64_si : SOP1_Real_si <0x2d, S_QUADMASK_B64>;
+def S_MOVRELS_B32_si : SOP1_Real_si <0x2e, S_MOVRELS_B32>;
+def S_MOVRELS_B64_si : SOP1_Real_si <0x2f, S_MOVRELS_B64>;
+def S_MOVRELD_B32_si : SOP1_Real_si <0x30, S_MOVRELD_B32>;
+def S_MOVRELD_B64_si : SOP1_Real_si <0x31, S_MOVRELD_B64>;
+def S_CBRANCH_JOIN_si : SOP1_Real_si <0x32, S_CBRANCH_JOIN>;
+def S_MOV_REGRD_B32_si : SOP1_Real_si <0x33, S_MOV_REGRD_B32>;
+def S_ABS_I32_si : SOP1_Real_si <0x34, S_ABS_I32>;
+def S_MOV_FED_B32_si : SOP1_Real_si <0x35, S_MOV_FED_B32>;
+
+def S_ADD_U32_si : SOP2_Real_si <0x00, S_ADD_U32>;
+def S_ADD_I32_si : SOP2_Real_si <0x02, S_ADD_I32>;
+def S_SUB_U32_si : SOP2_Real_si <0x01, S_SUB_U32>;
+def S_SUB_I32_si : SOP2_Real_si <0x03, S_SUB_I32>;
+def S_ADDC_U32_si : SOP2_Real_si <0x04, S_ADDC_U32>;
+def S_SUBB_U32_si : SOP2_Real_si <0x05, S_SUBB_U32>;
+def S_MIN_I32_si : SOP2_Real_si <0x06, S_MIN_I32>;
+def S_MIN_U32_si : SOP2_Real_si <0x07, S_MIN_U32>;
+def S_MAX_I32_si : SOP2_Real_si <0x08, S_MAX_I32>;
+def S_MAX_U32_si : SOP2_Real_si <0x09, S_MAX_U32>;
+def S_CSELECT_B32_si : SOP2_Real_si <0x0a, S_CSELECT_B32>;
+def S_CSELECT_B64_si : SOP2_Real_si <0x0b, S_CSELECT_B64>;
+def S_AND_B32_si : SOP2_Real_si <0x0e, S_AND_B32>;
+def S_AND_B64_si : SOP2_Real_si <0x0f, S_AND_B64>;
+def S_OR_B32_si : SOP2_Real_si <0x10, S_OR_B32>;
+def S_OR_B64_si : SOP2_Real_si <0x11, S_OR_B64>;
+def S_XOR_B32_si : SOP2_Real_si <0x12, S_XOR_B32>;
+def S_XOR_B64_si : SOP2_Real_si <0x13, S_XOR_B64>;
+def S_ANDN2_B32_si : SOP2_Real_si <0x14, S_ANDN2_B32>;
+def S_ANDN2_B64_si : SOP2_Real_si <0x15, S_ANDN2_B64>;
+def S_ORN2_B32_si : SOP2_Real_si <0x16, S_ORN2_B32>;
+def S_ORN2_B64_si : SOP2_Real_si <0x17, S_ORN2_B64>;
+def S_NAND_B32_si : SOP2_Real_si <0x18, S_NAND_B32>;
+def S_NAND_B64_si : SOP2_Real_si <0x19, S_NAND_B64>;
+def S_NOR_B32_si : SOP2_Real_si <0x1a, S_NOR_B32>;
+def S_NOR_B64_si : SOP2_Real_si <0x1b, S_NOR_B64>;
+def S_XNOR_B32_si : SOP2_Real_si <0x1c, S_XNOR_B32>;
+def S_XNOR_B64_si : SOP2_Real_si <0x1d, S_XNOR_B64>;
+def S_LSHL_B32_si : SOP2_Real_si <0x1e, S_LSHL_B32>;
+def S_LSHL_B64_si : SOP2_Real_si <0x1f, S_LSHL_B64>;
+def S_LSHR_B32_si : SOP2_Real_si <0x20, S_LSHR_B32>;
+def S_LSHR_B64_si : SOP2_Real_si <0x21, S_LSHR_B64>;
+def S_ASHR_I32_si : SOP2_Real_si <0x22, S_ASHR_I32>;
+def S_ASHR_I64_si : SOP2_Real_si <0x23, S_ASHR_I64>;
+def S_BFM_B32_si : SOP2_Real_si <0x24, S_BFM_B32>;
+def S_BFM_B64_si : SOP2_Real_si <0x25, S_BFM_B64>;
+def S_MUL_I32_si : SOP2_Real_si <0x26, S_MUL_I32>;
+def S_BFE_U32_si : SOP2_Real_si <0x27, S_BFE_U32>;
+def S_BFE_I32_si : SOP2_Real_si <0x28, S_BFE_I32>;
+def S_BFE_U64_si : SOP2_Real_si <0x29, S_BFE_U64>;
+def S_BFE_I64_si : SOP2_Real_si <0x2a, S_BFE_I64>;
+def S_CBRANCH_G_FORK_si : SOP2_Real_si <0x2b, S_CBRANCH_G_FORK>;
+def S_ABSDIFF_I32_si : SOP2_Real_si <0x2c, S_ABSDIFF_I32>;
+
+def S_MOVK_I32_si : SOPK_Real_si <0x00, S_MOVK_I32>;
+def S_CMOVK_I32_si : SOPK_Real_si <0x02, S_CMOVK_I32>;
+def S_CMPK_EQ_I32_si : SOPK_Real_si <0x03, S_CMPK_EQ_I32>;
+def S_CMPK_LG_I32_si : SOPK_Real_si <0x04, S_CMPK_LG_I32>;
+def S_CMPK_GT_I32_si : SOPK_Real_si <0x05, S_CMPK_GT_I32>;
+def S_CMPK_GE_I32_si : SOPK_Real_si <0x06, S_CMPK_GE_I32>;
+def S_CMPK_LT_I32_si : SOPK_Real_si <0x07, S_CMPK_LT_I32>;
+def S_CMPK_LE_I32_si : SOPK_Real_si <0x08, S_CMPK_LE_I32>;
+def S_CMPK_EQ_U32_si : SOPK_Real_si <0x09, S_CMPK_EQ_U32>;
+def S_CMPK_LG_U32_si : SOPK_Real_si <0x0a, S_CMPK_LG_U32>;
+def S_CMPK_GT_U32_si : SOPK_Real_si <0x0b, S_CMPK_GT_U32>;
+def S_CMPK_GE_U32_si : SOPK_Real_si <0x0c, S_CMPK_GE_U32>;
+def S_CMPK_LT_U32_si : SOPK_Real_si <0x0d, S_CMPK_LT_U32>;
+def S_CMPK_LE_U32_si : SOPK_Real_si <0x0e, S_CMPK_LE_U32>;
+def S_ADDK_I32_si : SOPK_Real_si <0x0f, S_ADDK_I32>;
+def S_MULK_I32_si : SOPK_Real_si <0x10, S_MULK_I32>;
+def S_CBRANCH_I_FORK_si : SOPK_Real_si <0x11, S_CBRANCH_I_FORK>;
+def S_GETREG_B32_si : SOPK_Real_si <0x12, S_GETREG_B32>;
+def S_SETREG_B32_si : SOPK_Real_si <0x13, S_SETREG_B32>;
+//def S_GETREG_REGRD_B32_si : SOPK_Real_si <0x14, S_GETREG_REGRD_B32>; // see pseudo for comments
+def S_SETREG_IMM32_B32_si : SOPK_Real64<0x15, S_SETREG_IMM32_B32>,
+ Select_si<S_SETREG_IMM32_B32.Mnemonic>;
+
+
+class Select_vi<string opName> :
+ SIMCInstr<opName, SIEncodingFamily.VI> {
+ list<Predicate> AssemblerPredicates = [isVI];
+ string DecoderNamespace = "VI";
+}
+
+class SOP1_Real_vi<bits<8> op, SOP1_Pseudo ps> :
+ SOP1_Real<op, ps>,
+ Select_vi<ps.Mnemonic>;
+
+
+class SOP2_Real_vi<bits<7> op, SOP2_Pseudo ps> :
+ SOP2_Real<op, ps>,
+ Select_vi<ps.Mnemonic>;
+
+class SOPK_Real_vi<bits<5> op, SOPK_Pseudo ps> :
+ SOPK_Real32<op, ps>,
+ Select_vi<ps.Mnemonic>;
+
+def S_MOV_B32_vi : SOP1_Real_vi <0x00, S_MOV_B32>;
+def S_MOV_B64_vi : SOP1_Real_vi <0x01, S_MOV_B64>;
+def S_CMOV_B32_vi : SOP1_Real_vi <0x02, S_CMOV_B32>;
+def S_CMOV_B64_vi : SOP1_Real_vi <0x03, S_CMOV_B64>;
+def S_NOT_B32_vi : SOP1_Real_vi <0x04, S_NOT_B32>;
+def S_NOT_B64_vi : SOP1_Real_vi <0x05, S_NOT_B64>;
+def S_WQM_B32_vi : SOP1_Real_vi <0x06, S_WQM_B32>;
+def S_WQM_B64_vi : SOP1_Real_vi <0x07, S_WQM_B64>;
+def S_BREV_B32_vi : SOP1_Real_vi <0x08, S_BREV_B32>;
+def S_BREV_B64_vi : SOP1_Real_vi <0x09, S_BREV_B64>;
+def S_BCNT0_I32_B32_vi : SOP1_Real_vi <0x0a, S_BCNT0_I32_B32>;
+def S_BCNT0_I32_B64_vi : SOP1_Real_vi <0x0b, S_BCNT0_I32_B64>;
+def S_BCNT1_I32_B32_vi : SOP1_Real_vi <0x0c, S_BCNT1_I32_B32>;
+def S_BCNT1_I32_B64_vi : SOP1_Real_vi <0x0d, S_BCNT1_I32_B64>;
+def S_FF0_I32_B32_vi : SOP1_Real_vi <0x0e, S_FF0_I32_B32>;
+def S_FF0_I32_B64_vi : SOP1_Real_vi <0x0f, S_FF0_I32_B64>;
+def S_FF1_I32_B32_vi : SOP1_Real_vi <0x10, S_FF1_I32_B32>;
+def S_FF1_I32_B64_vi : SOP1_Real_vi <0x11, S_FF1_I32_B64>;
+def S_FLBIT_I32_B32_vi : SOP1_Real_vi <0x12, S_FLBIT_I32_B32>;
+def S_FLBIT_I32_B64_vi : SOP1_Real_vi <0x13, S_FLBIT_I32_B64>;
+def S_FLBIT_I32_vi : SOP1_Real_vi <0x14, S_FLBIT_I32>;
+def S_FLBIT_I32_I64_vi : SOP1_Real_vi <0x15, S_FLBIT_I32_I64>;
+def S_SEXT_I32_I8_vi : SOP1_Real_vi <0x16, S_SEXT_I32_I8>;
+def S_SEXT_I32_I16_vi : SOP1_Real_vi <0x17, S_SEXT_I32_I16>;
+def S_BITSET0_B32_vi : SOP1_Real_vi <0x18, S_BITSET0_B32>;
+def S_BITSET0_B64_vi : SOP1_Real_vi <0x19, S_BITSET0_B64>;
+def S_BITSET1_B32_vi : SOP1_Real_vi <0x1a, S_BITSET1_B32>;
+def S_BITSET1_B64_vi : SOP1_Real_vi <0x1b, S_BITSET1_B64>;
+def S_GETPC_B64_vi : SOP1_Real_vi <0x1c, S_GETPC_B64>;
+def S_SETPC_B64_vi : SOP1_Real_vi <0x1d, S_SETPC_B64>;
+def S_SWAPPC_B64_vi : SOP1_Real_vi <0x1e, S_SWAPPC_B64>;
+def S_RFE_B64_vi : SOP1_Real_vi <0x1f, S_RFE_B64>;
+def S_AND_SAVEEXEC_B64_vi : SOP1_Real_vi <0x20, S_AND_SAVEEXEC_B64>;
+def S_OR_SAVEEXEC_B64_vi : SOP1_Real_vi <0x21, S_OR_SAVEEXEC_B64>;
+def S_XOR_SAVEEXEC_B64_vi : SOP1_Real_vi <0x22, S_XOR_SAVEEXEC_B64>;
+def S_ANDN2_SAVEEXEC_B64_vi: SOP1_Real_vi <0x23, S_ANDN2_SAVEEXEC_B64>;
+def S_ORN2_SAVEEXEC_B64_vi : SOP1_Real_vi <0x24, S_ORN2_SAVEEXEC_B64>;
+def S_NAND_SAVEEXEC_B64_vi : SOP1_Real_vi <0x25, S_NAND_SAVEEXEC_B64>;
+def S_NOR_SAVEEXEC_B64_vi : SOP1_Real_vi <0x26, S_NOR_SAVEEXEC_B64>;
+def S_XNOR_SAVEEXEC_B64_vi : SOP1_Real_vi <0x27, S_XNOR_SAVEEXEC_B64>;
+def S_QUADMASK_B32_vi : SOP1_Real_vi <0x28, S_QUADMASK_B32>;
+def S_QUADMASK_B64_vi : SOP1_Real_vi <0x29, S_QUADMASK_B64>;
+def S_MOVRELS_B32_vi : SOP1_Real_vi <0x2a, S_MOVRELS_B32>;
+def S_MOVRELS_B64_vi : SOP1_Real_vi <0x2b, S_MOVRELS_B64>;
+def S_MOVRELD_B32_vi : SOP1_Real_vi <0x2c, S_MOVRELD_B32>;
+def S_MOVRELD_B64_vi : SOP1_Real_vi <0x2d, S_MOVRELD_B64>;
+def S_CBRANCH_JOIN_vi : SOP1_Real_vi <0x2e, S_CBRANCH_JOIN>;
+def S_MOV_REGRD_B32_vi : SOP1_Real_vi <0x2f, S_MOV_REGRD_B32>;
+def S_ABS_I32_vi : SOP1_Real_vi <0x30, S_ABS_I32>;
+def S_MOV_FED_B32_vi : SOP1_Real_vi <0x31, S_MOV_FED_B32>;
+def S_SET_GPR_IDX_IDX_vi : SOP1_Real_vi <0x32, S_SET_GPR_IDX_IDX>;
+
+def S_ADD_U32_vi : SOP2_Real_vi <0x00, S_ADD_U32>;
+def S_ADD_I32_vi : SOP2_Real_vi <0x02, S_ADD_I32>;
+def S_SUB_U32_vi : SOP2_Real_vi <0x01, S_SUB_U32>;
+def S_SUB_I32_vi : SOP2_Real_vi <0x03, S_SUB_I32>;
+def S_ADDC_U32_vi : SOP2_Real_vi <0x04, S_ADDC_U32>;
+def S_SUBB_U32_vi : SOP2_Real_vi <0x05, S_SUBB_U32>;
+def S_MIN_I32_vi : SOP2_Real_vi <0x06, S_MIN_I32>;
+def S_MIN_U32_vi : SOP2_Real_vi <0x07, S_MIN_U32>;
+def S_MAX_I32_vi : SOP2_Real_vi <0x08, S_MAX_I32>;
+def S_MAX_U32_vi : SOP2_Real_vi <0x09, S_MAX_U32>;
+def S_CSELECT_B32_vi : SOP2_Real_vi <0x0a, S_CSELECT_B32>;
+def S_CSELECT_B64_vi : SOP2_Real_vi <0x0b, S_CSELECT_B64>;
+def S_AND_B32_vi : SOP2_Real_vi <0x0c, S_AND_B32>;
+def S_AND_B64_vi : SOP2_Real_vi <0x0d, S_AND_B64>;
+def S_OR_B32_vi : SOP2_Real_vi <0x0e, S_OR_B32>;
+def S_OR_B64_vi : SOP2_Real_vi <0x0f, S_OR_B64>;
+def S_XOR_B32_vi : SOP2_Real_vi <0x10, S_XOR_B32>;
+def S_XOR_B64_vi : SOP2_Real_vi <0x11, S_XOR_B64>;
+def S_ANDN2_B32_vi : SOP2_Real_vi <0x12, S_ANDN2_B32>;
+def S_ANDN2_B64_vi : SOP2_Real_vi <0x13, S_ANDN2_B64>;
+def S_ORN2_B32_vi : SOP2_Real_vi <0x14, S_ORN2_B32>;
+def S_ORN2_B64_vi : SOP2_Real_vi <0x15, S_ORN2_B64>;
+def S_NAND_B32_vi : SOP2_Real_vi <0x16, S_NAND_B32>;
+def S_NAND_B64_vi : SOP2_Real_vi <0x17, S_NAND_B64>;
+def S_NOR_B32_vi : SOP2_Real_vi <0x18, S_NOR_B32>;
+def S_NOR_B64_vi : SOP2_Real_vi <0x19, S_NOR_B64>;
+def S_XNOR_B32_vi : SOP2_Real_vi <0x1a, S_XNOR_B32>;
+def S_XNOR_B64_vi : SOP2_Real_vi <0x1b, S_XNOR_B64>;
+def S_LSHL_B32_vi : SOP2_Real_vi <0x1c, S_LSHL_B32>;
+def S_LSHL_B64_vi : SOP2_Real_vi <0x1d, S_LSHL_B64>;
+def S_LSHR_B32_vi : SOP2_Real_vi <0x1e, S_LSHR_B32>;
+def S_LSHR_B64_vi : SOP2_Real_vi <0x1f, S_LSHR_B64>;
+def S_ASHR_I32_vi : SOP2_Real_vi <0x20, S_ASHR_I32>;
+def S_ASHR_I64_vi : SOP2_Real_vi <0x21, S_ASHR_I64>;
+def S_BFM_B32_vi : SOP2_Real_vi <0x22, S_BFM_B32>;
+def S_BFM_B64_vi : SOP2_Real_vi <0x23, S_BFM_B64>;
+def S_MUL_I32_vi : SOP2_Real_vi <0x24, S_MUL_I32>;
+def S_BFE_U32_vi : SOP2_Real_vi <0x25, S_BFE_U32>;
+def S_BFE_I32_vi : SOP2_Real_vi <0x26, S_BFE_I32>;
+def S_BFE_U64_vi : SOP2_Real_vi <0x27, S_BFE_U64>;
+def S_BFE_I64_vi : SOP2_Real_vi <0x28, S_BFE_I64>;
+def S_CBRANCH_G_FORK_vi : SOP2_Real_vi <0x29, S_CBRANCH_G_FORK>;
+def S_ABSDIFF_I32_vi : SOP2_Real_vi <0x2a, S_ABSDIFF_I32>;
+
+def S_MOVK_I32_vi : SOPK_Real_vi <0x00, S_MOVK_I32>;
+def S_CMOVK_I32_vi : SOPK_Real_vi <0x01, S_CMOVK_I32>;
+def S_CMPK_EQ_I32_vi : SOPK_Real_vi <0x02, S_CMPK_EQ_I32>;
+def S_CMPK_LG_I32_vi : SOPK_Real_vi <0x03, S_CMPK_LG_I32>;
+def S_CMPK_GT_I32_vi : SOPK_Real_vi <0x04, S_CMPK_GT_I32>;
+def S_CMPK_GE_I32_vi : SOPK_Real_vi <0x05, S_CMPK_GE_I32>;
+def S_CMPK_LT_I32_vi : SOPK_Real_vi <0x06, S_CMPK_LT_I32>;
+def S_CMPK_LE_I32_vi : SOPK_Real_vi <0x07, S_CMPK_LE_I32>;
+def S_CMPK_EQ_U32_vi : SOPK_Real_vi <0x08, S_CMPK_EQ_U32>;
+def S_CMPK_LG_U32_vi : SOPK_Real_vi <0x09, S_CMPK_LG_U32>;
+def S_CMPK_GT_U32_vi : SOPK_Real_vi <0x0A, S_CMPK_GT_U32>;
+def S_CMPK_GE_U32_vi : SOPK_Real_vi <0x0B, S_CMPK_GE_U32>;
+def S_CMPK_LT_U32_vi : SOPK_Real_vi <0x0C, S_CMPK_LT_U32>;
+def S_CMPK_LE_U32_vi : SOPK_Real_vi <0x0D, S_CMPK_LE_U32>;
+def S_ADDK_I32_vi : SOPK_Real_vi <0x0E, S_ADDK_I32>;
+def S_MULK_I32_vi : SOPK_Real_vi <0x0F, S_MULK_I32>;
+def S_CBRANCH_I_FORK_vi : SOPK_Real_vi <0x10, S_CBRANCH_I_FORK>;
+def S_GETREG_B32_vi : SOPK_Real_vi <0x11, S_GETREG_B32>;
+def S_SETREG_B32_vi : SOPK_Real_vi <0x12, S_SETREG_B32>;
+//def S_GETREG_REGRD_B32_vi : SOPK_Real_vi <0x13, S_GETREG_REGRD_B32>; // see pseudo for comments
+def S_SETREG_IMM32_B32_vi : SOPK_Real64<0x14, S_SETREG_IMM32_B32>,
+ Select_vi<S_SETREG_IMM32_B32.Mnemonic>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/TargetInfo/AMDGPUTargetInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/TargetInfo/AMDGPUTargetInfo.cpp
index 2112135..9908fc0 100644
--- a/contrib/llvm/lib/Target/AMDGPU/TargetInfo/AMDGPUTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/TargetInfo/AMDGPUTargetInfo.cpp
@@ -18,13 +18,20 @@ using namespace llvm;
/// \brief The target which suports all AMD GPUs. This will eventually
/// be deprecated and there will be a R600 target and a GCN target.
-Target llvm::TheAMDGPUTarget;
+Target &llvm::getTheAMDGPUTarget() {
+ static Target TheAMDGPUTarget;
+ return TheAMDGPUTarget;
+}
/// \brief The target for GCN GPUs
-Target llvm::TheGCNTarget;
+Target &llvm::getTheGCNTarget() {
+ static Target TheGCNTarget;
+ return TheGCNTarget;
+}
/// \brief Extern function to initialize the targets for the AMDGPU backend
extern "C" void LLVMInitializeAMDGPUTargetInfo() {
- RegisterTarget<Triple::r600, false>
- R600(TheAMDGPUTarget, "r600", "AMD GPUs HD2XXX-HD6XXX");
- RegisterTarget<Triple::amdgcn, false> GCN(TheGCNTarget, "amdgcn", "AMD GCN GPUs");
+ RegisterTarget<Triple::r600, false> R600(getTheAMDGPUTarget(), "r600",
+ "AMD GPUs HD2XXX-HD6XXX");
+ RegisterTarget<Triple::amdgcn, false> GCN(getTheGCNTarget(), "amdgcn",
+ "AMD GCN GPUs");
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index c6f9142..5f651d4 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -8,10 +8,13 @@
//===----------------------------------------------------------------------===//
#include "AMDGPUBaseInfo.h"
#include "AMDGPU.h"
+#include "SIDefines.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/SubtargetFeature.h"
@@ -24,6 +27,55 @@
#include "AMDGPUGenRegisterInfo.inc"
#undef GET_REGINFO_ENUM
+#define GET_INSTRINFO_NAMED_OPS
+#define GET_INSTRINFO_ENUM
+#include "AMDGPUGenInstrInfo.inc"
+#undef GET_INSTRINFO_NAMED_OPS
+#undef GET_INSTRINFO_ENUM
+
+namespace {
+
+/// \returns Bit mask for given bit \p Shift and bit \p Width.
+unsigned getBitMask(unsigned Shift, unsigned Width) {
+ return ((1 << Width) - 1) << Shift;
+}
+
+/// \brief Packs \p Src into \p Dst for given bit \p Shift and bit \p Width.
+///
+/// \returns Packed \p Dst.
+unsigned packBits(unsigned Src, unsigned Dst, unsigned Shift, unsigned Width) {
+ Dst &= ~(1 << Shift) & ~getBitMask(Shift, Width);
+ Dst |= (Src << Shift) & getBitMask(Shift, Width);
+ return Dst;
+}
+
+/// \brief Unpacks bits from \p Src for given bit \p Shift and bit \p Width.
+///
+/// \returns Unpacked bits.
+unsigned unpackBits(unsigned Src, unsigned Shift, unsigned Width) {
+ return (Src & getBitMask(Shift, Width)) >> Shift;
+}
+
+/// \returns Vmcnt bit shift.
+unsigned getVmcntBitShift() { return 0; }
+
+/// \returns Vmcnt bit width.
+unsigned getVmcntBitWidth() { return 4; }
+
+/// \returns Expcnt bit shift.
+unsigned getExpcntBitShift() { return 4; }
+
+/// \returns Expcnt bit width.
+unsigned getExpcntBitWidth() { return 3; }
+
+/// \returns Lgkmcnt bit shift.
+unsigned getLgkmcntBitShift() { return 8; }
+
+/// \returns Lgkmcnt bit width.
+unsigned getLgkmcntBitWidth() { return 4; }
+
+} // anonymous namespace
+
namespace llvm {
namespace AMDGPU {
@@ -35,15 +87,27 @@ IsaVersion getIsaVersion(const FeatureBitset &Features) {
if (Features.test(FeatureISAVersion7_0_1))
return {7, 0, 1};
+ if (Features.test(FeatureISAVersion7_0_2))
+ return {7, 0, 2};
+
if (Features.test(FeatureISAVersion8_0_0))
return {8, 0, 0};
if (Features.test(FeatureISAVersion8_0_1))
return {8, 0, 1};
+ if (Features.test(FeatureISAVersion8_0_2))
+ return {8, 0, 2};
+
if (Features.test(FeatureISAVersion8_0_3))
return {8, 0, 3};
+ if (Features.test(FeatureISAVersion8_0_4))
+ return {8, 0, 4};
+
+ if (Features.test(FeatureISAVersion8_1_0))
+ return {8, 1, 0};
+
return {0, 0, 0};
}
@@ -109,6 +173,10 @@ bool isReadOnlySegment(const GlobalValue *GV) {
return GV->getType()->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS;
}
+bool shouldEmitConstantsToTextSection(const Triple &TT) {
+ return TT.getOS() != Triple::AMDHSA;
+}
+
int getIntegerAttribute(const Function &F, StringRef Name, int Default) {
Attribute A = F.getFnAttribute(Name);
int Result = Default;
@@ -124,8 +192,88 @@ int getIntegerAttribute(const Function &F, StringRef Name, int Default) {
return Result;
}
-unsigned getMaximumWorkGroupSize(const Function &F) {
- return getIntegerAttribute(F, "amdgpu-max-work-group-size", 256);
+std::pair<int, int> getIntegerPairAttribute(const Function &F,
+ StringRef Name,
+ std::pair<int, int> Default,
+ bool OnlyFirstRequired) {
+ Attribute A = F.getFnAttribute(Name);
+ if (!A.isStringAttribute())
+ return Default;
+
+ LLVMContext &Ctx = F.getContext();
+ std::pair<int, int> Ints = Default;
+ std::pair<StringRef, StringRef> Strs = A.getValueAsString().split(',');
+ if (Strs.first.trim().getAsInteger(0, Ints.first)) {
+ Ctx.emitError("can't parse first integer attribute " + Name);
+ return Default;
+ }
+ if (Strs.second.trim().getAsInteger(0, Ints.second)) {
+ if (!OnlyFirstRequired || Strs.second.trim().size()) {
+ Ctx.emitError("can't parse second integer attribute " + Name);
+ return Default;
+ }
+ }
+
+ return Ints;
+}
+
+unsigned getWaitcntBitMask(IsaVersion Version) {
+ unsigned Vmcnt = getBitMask(getVmcntBitShift(), getVmcntBitWidth());
+ unsigned Expcnt = getBitMask(getExpcntBitShift(), getExpcntBitWidth());
+ unsigned Lgkmcnt = getBitMask(getLgkmcntBitShift(), getLgkmcntBitWidth());
+ return Vmcnt | Expcnt | Lgkmcnt;
+}
+
+unsigned getVmcntBitMask(IsaVersion Version) {
+ return (1 << getVmcntBitWidth()) - 1;
+}
+
+unsigned getExpcntBitMask(IsaVersion Version) {
+ return (1 << getExpcntBitWidth()) - 1;
+}
+
+unsigned getLgkmcntBitMask(IsaVersion Version) {
+ return (1 << getLgkmcntBitWidth()) - 1;
+}
+
+unsigned decodeVmcnt(IsaVersion Version, unsigned Waitcnt) {
+ return unpackBits(Waitcnt, getVmcntBitShift(), getVmcntBitWidth());
+}
+
+unsigned decodeExpcnt(IsaVersion Version, unsigned Waitcnt) {
+ return unpackBits(Waitcnt, getExpcntBitShift(), getExpcntBitWidth());
+}
+
+unsigned decodeLgkmcnt(IsaVersion Version, unsigned Waitcnt) {
+ return unpackBits(Waitcnt, getLgkmcntBitShift(), getLgkmcntBitWidth());
+}
+
+void decodeWaitcnt(IsaVersion Version, unsigned Waitcnt,
+ unsigned &Vmcnt, unsigned &Expcnt, unsigned &Lgkmcnt) {
+ Vmcnt = decodeVmcnt(Version, Waitcnt);
+ Expcnt = decodeExpcnt(Version, Waitcnt);
+ Lgkmcnt = decodeLgkmcnt(Version, Waitcnt);
+}
+
+unsigned encodeVmcnt(IsaVersion Version, unsigned Waitcnt, unsigned Vmcnt) {
+ return packBits(Vmcnt, Waitcnt, getVmcntBitShift(), getVmcntBitWidth());
+}
+
+unsigned encodeExpcnt(IsaVersion Version, unsigned Waitcnt, unsigned Expcnt) {
+ return packBits(Expcnt, Waitcnt, getExpcntBitShift(), getExpcntBitWidth());
+}
+
+unsigned encodeLgkmcnt(IsaVersion Version, unsigned Waitcnt, unsigned Lgkmcnt) {
+ return packBits(Lgkmcnt, Waitcnt, getLgkmcntBitShift(), getLgkmcntBitWidth());
+}
+
+unsigned encodeWaitcnt(IsaVersion Version,
+ unsigned Vmcnt, unsigned Expcnt, unsigned Lgkmcnt) {
+ unsigned Waitcnt = getWaitcntBitMask(Version);
+ Waitcnt = encodeVmcnt(Version, Waitcnt, Vmcnt);
+ Waitcnt = encodeExpcnt(Version, Waitcnt, Expcnt);
+ Waitcnt = encodeLgkmcnt(Version, Waitcnt, Lgkmcnt);
+ return Waitcnt;
}
unsigned getInitialPSInputAddr(const Function &F) {
@@ -179,5 +327,135 @@ unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI) {
return Reg;
}
+bool isSISrcOperand(const MCInstrDesc &Desc, unsigned OpNo) {
+ unsigned OpType = Desc.OpInfo[OpNo].OperandType;
+ return OpType >= AMDGPU::OPERAND_SRC_FIRST &&
+ OpType <= AMDGPU::OPERAND_SRC_LAST;
+}
+
+bool isSISrcFPOperand(const MCInstrDesc &Desc, unsigned OpNo) {
+ unsigned OpType = Desc.OpInfo[OpNo].OperandType;
+ switch (OpType) {
+ case AMDGPU::OPERAND_REG_IMM_FP32:
+ case AMDGPU::OPERAND_REG_IMM_FP64:
+ case AMDGPU::OPERAND_REG_IMM_FP16:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP32:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP64:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP16:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool isSISrcInlinableOperand(const MCInstrDesc &Desc, unsigned OpNo) {
+ unsigned OpType = Desc.OpInfo[OpNo].OperandType;
+ return OpType >= AMDGPU::OPERAND_REG_INLINE_C_FIRST &&
+ OpType <= AMDGPU::OPERAND_REG_INLINE_C_LAST;
+}
+
+// Avoid using MCRegisterClass::getSize, since that function will go away
+// (move from MC* level to Target* level). Return size in bits.
+unsigned getRegBitWidth(unsigned RCID) {
+ switch (RCID) {
+ case AMDGPU::SGPR_32RegClassID:
+ case AMDGPU::VGPR_32RegClassID:
+ case AMDGPU::VS_32RegClassID:
+ case AMDGPU::SReg_32RegClassID:
+ case AMDGPU::SReg_32_XM0RegClassID:
+ return 32;
+ case AMDGPU::SGPR_64RegClassID:
+ case AMDGPU::VS_64RegClassID:
+ case AMDGPU::SReg_64RegClassID:
+ case AMDGPU::VReg_64RegClassID:
+ return 64;
+ case AMDGPU::VReg_96RegClassID:
+ return 96;
+ case AMDGPU::SGPR_128RegClassID:
+ case AMDGPU::SReg_128RegClassID:
+ case AMDGPU::VReg_128RegClassID:
+ return 128;
+ case AMDGPU::SReg_256RegClassID:
+ case AMDGPU::VReg_256RegClassID:
+ return 256;
+ case AMDGPU::SReg_512RegClassID:
+ case AMDGPU::VReg_512RegClassID:
+ return 512;
+ default:
+ llvm_unreachable("Unexpected register class");
+ }
+}
+
+unsigned getRegBitWidth(const MCRegisterClass &RC) {
+ return getRegBitWidth(RC.getID());
+}
+
+unsigned getRegOperandSize(const MCRegisterInfo *MRI, const MCInstrDesc &Desc,
+ unsigned OpNo) {
+ unsigned RCID = Desc.OpInfo[OpNo].RegClass;
+ return getRegBitWidth(MRI->getRegClass(RCID)) / 8;
+}
+
+bool isInlinableLiteral64(int64_t Literal, bool HasInv2Pi) {
+ if (Literal >= -16 && Literal <= 64)
+ return true;
+
+ uint64_t Val = static_cast<uint64_t>(Literal);
+ return (Val == DoubleToBits(0.0)) ||
+ (Val == DoubleToBits(1.0)) ||
+ (Val == DoubleToBits(-1.0)) ||
+ (Val == DoubleToBits(0.5)) ||
+ (Val == DoubleToBits(-0.5)) ||
+ (Val == DoubleToBits(2.0)) ||
+ (Val == DoubleToBits(-2.0)) ||
+ (Val == DoubleToBits(4.0)) ||
+ (Val == DoubleToBits(-4.0)) ||
+ (Val == 0x3fc45f306dc9c882 && HasInv2Pi);
+}
+
+bool isInlinableLiteral32(int32_t Literal, bool HasInv2Pi) {
+ if (Literal >= -16 && Literal <= 64)
+ return true;
+
+ // The actual type of the operand does not seem to matter as long
+ // as the bits match one of the inline immediate values. For example:
+ //
+ // -nan has the hexadecimal encoding of 0xfffffffe which is -2 in decimal,
+ // so it is a legal inline immediate.
+ //
+ // 1065353216 has the hexadecimal encoding 0x3f800000 which is 1.0f in
+ // floating-point, so it is a legal inline immediate.
+
+ uint32_t Val = static_cast<uint32_t>(Literal);
+ return (Val == FloatToBits(0.0f)) ||
+ (Val == FloatToBits(1.0f)) ||
+ (Val == FloatToBits(-1.0f)) ||
+ (Val == FloatToBits(0.5f)) ||
+ (Val == FloatToBits(-0.5f)) ||
+ (Val == FloatToBits(2.0f)) ||
+ (Val == FloatToBits(-2.0f)) ||
+ (Val == FloatToBits(4.0f)) ||
+ (Val == FloatToBits(-4.0f)) ||
+ (Val == 0x3e22f983 && HasInv2Pi);
+}
+
+bool isInlinableLiteral16(int16_t Literal, bool HasInv2Pi) {
+ assert(HasInv2Pi);
+
+ if (Literal >= -16 && Literal <= 64)
+ return true;
+
+ uint16_t Val = static_cast<uint16_t>(Literal);
+ return Val == 0x3C00 || // 1.0
+ Val == 0xBC00 || // -1.0
+ Val == 0x3800 || // 0.5
+ Val == 0xB800 || // -0.5
+ Val == 0x4000 || // 2.0
+ Val == 0xC000 || // -2.0
+ Val == 0x4400 || // 4.0
+ Val == 0xC400 || // -4.0
+ Val == 0x3118; // 1/2pi
+}
+
} // End namespace AMDGPU
} // End namespace llvm
diff --git a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index 995a904..ea5fc36 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
@@ -13,17 +13,29 @@
#include "AMDKernelCodeT.h"
#include "llvm/IR/CallingConv.h"
+#include "SIDefines.h"
+
+#define GET_INSTRINFO_OPERAND_ENUM
+#include "AMDGPUGenInstrInfo.inc"
+#undef GET_INSTRINFO_OPERAND_ENUM
+
namespace llvm {
class FeatureBitset;
class Function;
class GlobalValue;
class MCContext;
+class MCInstrDesc;
+class MCRegisterClass;
+class MCRegisterInfo;
class MCSection;
class MCSubtargetInfo;
namespace AMDGPU {
+LLVM_READONLY
+int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx);
+
struct IsaVersion {
unsigned Major;
unsigned Minor;
@@ -45,9 +57,86 @@ bool isGroupSegment(const GlobalValue *GV);
bool isGlobalSegment(const GlobalValue *GV);
bool isReadOnlySegment(const GlobalValue *GV);
+/// \returns True if constants should be emitted to .text section for given
+/// target triple \p TT, false otherwise.
+bool shouldEmitConstantsToTextSection(const Triple &TT);
+
+/// \returns Integer value requested using \p F's \p Name attribute.
+///
+/// \returns \p Default if attribute is not present.
+///
+/// \returns \p Default and emits error if requested value cannot be converted
+/// to integer.
int getIntegerAttribute(const Function &F, StringRef Name, int Default);
-unsigned getMaximumWorkGroupSize(const Function &F);
+/// \returns A pair of integer values requested using \p F's \p Name attribute
+/// in "first[,second]" format ("second" is optional unless \p OnlyFirstRequired
+/// is false).
+///
+/// \returns \p Default if attribute is not present.
+///
+/// \returns \p Default and emits error if one of the requested values cannot be
+/// converted to integer, or \p OnlyFirstRequired is false and "second" value is
+/// not present.
+std::pair<int, int> getIntegerPairAttribute(const Function &F,
+ StringRef Name,
+ std::pair<int, int> Default,
+ bool OnlyFirstRequired = false);
+
+/// \returns Waitcnt bit mask for given isa \p Version.
+unsigned getWaitcntBitMask(IsaVersion Version);
+
+/// \returns Vmcnt bit mask for given isa \p Version.
+unsigned getVmcntBitMask(IsaVersion Version);
+
+/// \returns Expcnt bit mask for given isa \p Version.
+unsigned getExpcntBitMask(IsaVersion Version);
+
+/// \returns Lgkmcnt bit mask for given isa \p Version.
+unsigned getLgkmcntBitMask(IsaVersion Version);
+
+/// \returns Decoded Vmcnt from given \p Waitcnt for given isa \p Version.
+unsigned decodeVmcnt(IsaVersion Version, unsigned Waitcnt);
+
+/// \returns Decoded Expcnt from given \p Waitcnt for given isa \p Version.
+unsigned decodeExpcnt(IsaVersion Version, unsigned Waitcnt);
+
+/// \returns Decoded Lgkmcnt from given \p Waitcnt for given isa \p Version.
+unsigned decodeLgkmcnt(IsaVersion Version, unsigned Waitcnt);
+
+/// \brief Decodes Vmcnt, Expcnt and Lgkmcnt from given \p Waitcnt for given isa
+/// \p Version, and writes decoded values into \p Vmcnt, \p Expcnt and
+/// \p Lgkmcnt respectively.
+///
+/// \details \p Vmcnt, \p Expcnt and \p Lgkmcnt are decoded as follows:
+/// \p Vmcnt = \p Waitcnt[3:0]
+/// \p Expcnt = \p Waitcnt[6:4]
+/// \p Lgkmcnt = \p Waitcnt[11:8]
+void decodeWaitcnt(IsaVersion Version, unsigned Waitcnt,
+ unsigned &Vmcnt, unsigned &Expcnt, unsigned &Lgkmcnt);
+
+/// \returns \p Waitcnt with encoded \p Vmcnt for given isa \p Version.
+unsigned encodeVmcnt(IsaVersion Version, unsigned Waitcnt, unsigned Vmcnt);
+
+/// \returns \p Waitcnt with encoded \p Expcnt for given isa \p Version.
+unsigned encodeExpcnt(IsaVersion Version, unsigned Waitcnt, unsigned Expcnt);
+
+/// \returns \p Waitcnt with encoded \p Lgkmcnt for given isa \p Version.
+unsigned encodeLgkmcnt(IsaVersion Version, unsigned Waitcnt, unsigned Lgkmcnt);
+
+/// \brief Encodes \p Vmcnt, \p Expcnt and \p Lgkmcnt into Waitcnt for given isa
+/// \p Version.
+///
+/// \details \p Vmcnt, \p Expcnt and \p Lgkmcnt are encoded as follows:
+/// Waitcnt[3:0] = \p Vmcnt
+/// Waitcnt[6:4] = \p Expcnt
+/// Waitcnt[11:8] = \p Lgkmcnt
+///
+/// \returns Waitcnt with encoded \p Vmcnt, \p Expcnt and \p Lgkmcnt for given
+/// isa \p Version.
+unsigned encodeWaitcnt(IsaVersion Version,
+ unsigned Vmcnt, unsigned Expcnt, unsigned Lgkmcnt);
+
unsigned getInitialPSInputAddr(const Function &F);
bool isShader(CallingConv::ID cc);
@@ -61,6 +150,66 @@ bool isVI(const MCSubtargetInfo &STI);
/// \p STI otherwise return \p Reg.
unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI);
+/// \brief Can this operand also contain immediate values?
+bool isSISrcOperand(const MCInstrDesc &Desc, unsigned OpNo);
+
+/// \brief Is this floating-point operand?
+bool isSISrcFPOperand(const MCInstrDesc &Desc, unsigned OpNo);
+
+/// \brief Does this opearnd support only inlinable literals?
+bool isSISrcInlinableOperand(const MCInstrDesc &Desc, unsigned OpNo);
+
+/// \brief Get the size in bits of a register from the register class \p RC.
+unsigned getRegBitWidth(unsigned RCID);
+
+/// \brief Get the size in bits of a register from the register class \p RC.
+unsigned getRegBitWidth(const MCRegisterClass &RC);
+
+/// \brief Get size of register operand
+unsigned getRegOperandSize(const MCRegisterInfo *MRI, const MCInstrDesc &Desc,
+ unsigned OpNo);
+
+LLVM_READNONE
+inline unsigned getOperandSize(const MCOperandInfo &OpInfo) {
+ switch (OpInfo.OperandType) {
+ case AMDGPU::OPERAND_REG_IMM_INT32:
+ case AMDGPU::OPERAND_REG_IMM_FP32:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT32:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP32:
+ return 4;
+
+ case AMDGPU::OPERAND_REG_IMM_INT64:
+ case AMDGPU::OPERAND_REG_IMM_FP64:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT64:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP64:
+ return 8;
+
+ case AMDGPU::OPERAND_REG_IMM_INT16:
+ case AMDGPU::OPERAND_REG_IMM_FP16:
+ case AMDGPU::OPERAND_REG_INLINE_C_INT16:
+ case AMDGPU::OPERAND_REG_INLINE_C_FP16:
+ return 2;
+
+ default:
+ llvm_unreachable("unhandled operand type");
+ }
+}
+
+LLVM_READNONE
+inline unsigned getOperandSize(const MCInstrDesc &Desc, unsigned OpNo) {
+ return getOperandSize(Desc.OpInfo[OpNo]);
+}
+
+/// \brief Is this literal inlinable
+LLVM_READNONE
+bool isInlinableLiteral64(int64_t Literal, bool HasInv2Pi);
+
+LLVM_READNONE
+bool isInlinableLiteral32(int32_t Literal, bool HasInv2Pi);
+
+LLVM_READNONE
+bool isInlinableLiteral16(int16_t Literal, bool HasInv2Pi);
+
} // end namespace AMDGPU
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTInfo.h b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTInfo.h
index 3a5ff60..c55eaab 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTInfo.h
+++ b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTInfo.h
@@ -16,10 +16,10 @@
#define QNAME(name) amd_kernel_code_t::name
#define FLD_T(name) decltype(QNAME(name)), &QNAME(name)
-#define FIELD2(sname, name) \
- RECORD(sname, printField<FLD_T(name)>, parseField<FLD_T(name)>)
+#define FIELD2(sname, aname, name) \
+ RECORD(sname, aname, printField<FLD_T(name)>, parseField<FLD_T(name)>)
-#define FIELD(name) FIELD2(name, name)
+#define FIELD(name) FIELD2(name, name, name)
#define PRINTCODEPROP(name) \
@@ -33,7 +33,7 @@
AMD_CODE_PROPERTY_##name##_WIDTH>
#define CODEPROP(name, shift) \
- RECORD(name, PRINTCODEPROP(shift), PARSECODEPROP(shift))
+ RECORD(name, name, PRINTCODEPROP(shift), PARSECODEPROP(shift))
// have to define these lambdas because of Set/GetMacro
#define PRINTCOMP(GetMacro, Shift) \
@@ -50,32 +50,70 @@
return true; \
}
-#define COMPPGM(name, GetMacro, SetMacro, Shift) \
- RECORD(name, PRINTCOMP(GetMacro, Shift), PARSECOMP(SetMacro, Shift))
+#define COMPPGM(name, aname, GetMacro, SetMacro, Shift) \
+ RECORD(name, aname, PRINTCOMP(GetMacro, Shift), PARSECOMP(SetMacro, Shift))
-#define COMPPGM1(name, AccMacro) \
- COMPPGM(compute_pgm_rsrc1_##name, \
- G_00B848_##AccMacro, S_00B848_##AccMacro, 0)
+#define COMPPGM1(name, aname, AccMacro) \
+ COMPPGM(name, aname, G_00B848_##AccMacro, S_00B848_##AccMacro, 0)
-#define COMPPGM2(name, AccMacro) \
- COMPPGM(compute_pgm_rsrc2_##name, \
- G_00B84C_##AccMacro, S_00B84C_##AccMacro, 32)
+#define COMPPGM2(name, aname, AccMacro) \
+ COMPPGM(name, aname, G_00B84C_##AccMacro, S_00B84C_##AccMacro, 32)
///////////////////////////////////////////////////////////////////////////////
// Begin of the table
// Define RECORD(name, print, parse) in your code to get field definitions
// and include this file
-FIELD2(kernel_code_version_major, amd_kernel_code_version_major),
-FIELD2(kernel_code_version_minor, amd_kernel_code_version_minor),
-FIELD2(machine_kind, amd_machine_kind),
-FIELD2(machine_version_major, amd_machine_version_major),
-FIELD2(machine_version_minor, amd_machine_version_minor),
-FIELD2(machine_version_stepping, amd_machine_version_stepping),
+FIELD2(amd_code_version_major, kernel_code_version_major, amd_kernel_code_version_major),
+FIELD2(amd_code_version_minor, kernel_code_version_minor, amd_kernel_code_version_minor),
+FIELD2(amd_machine_kind, machine_kind, amd_machine_kind),
+FIELD2(amd_machine_version_major, machine_version_major, amd_machine_version_major),
+FIELD2(amd_machine_version_minor, machine_version_minor, amd_machine_version_minor),
+FIELD2(amd_machine_version_stepping, machine_version_stepping, amd_machine_version_stepping),
+
FIELD(kernel_code_entry_byte_offset),
FIELD(kernel_code_prefetch_byte_size),
FIELD(max_scratch_backing_memory_byte_size),
-FIELD(compute_pgm_resource_registers),
+
+COMPPGM1(granulated_workitem_vgpr_count, compute_pgm_rsrc1_vgprs, VGPRS),
+COMPPGM1(granulated_wavefront_sgpr_count, compute_pgm_rsrc1_sgprs, SGPRS),
+COMPPGM1(priority, compute_pgm_rsrc1_priority, PRIORITY),
+COMPPGM1(float_mode, compute_pgm_rsrc1_float_mode, FLOAT_MODE), // TODO: split float_mode
+COMPPGM1(priv, compute_pgm_rsrc1_priv, PRIV),
+COMPPGM1(enable_dx10_clamp, compute_pgm_rsrc1_dx10_clamp, DX10_CLAMP),
+COMPPGM1(debug_mode, compute_pgm_rsrc1_debug_mode, DEBUG_MODE),
+COMPPGM1(enable_ieee_mode, compute_pgm_rsrc1_ieee_mode, IEEE_MODE),
+// TODO: bulky
+// TODO: cdbg_user
+COMPPGM2(enable_sgpr_private_segment_wave_byte_offset, compute_pgm_rsrc2_scratch_en, SCRATCH_EN),
+COMPPGM2(user_sgpr_count, compute_pgm_rsrc2_user_sgpr, USER_SGPR),
+// TODO: enable_trap_handler
+COMPPGM2(enable_sgpr_workgroup_id_x, compute_pgm_rsrc2_tgid_x_en, TGID_X_EN),
+COMPPGM2(enable_sgpr_workgroup_id_y, compute_pgm_rsrc2_tgid_y_en, TGID_Y_EN),
+COMPPGM2(enable_sgpr_workgroup_id_z, compute_pgm_rsrc2_tgid_z_en, TGID_Z_EN),
+COMPPGM2(enable_sgpr_workgroup_info, compute_pgm_rsrc2_tg_size_en, TG_SIZE_EN),
+COMPPGM2(enable_vgpr_workitem_id, compute_pgm_rsrc2_tidig_comp_cnt, TIDIG_COMP_CNT),
+COMPPGM2(enable_exception_msb, compute_pgm_rsrc2_excp_en_msb, EXCP_EN_MSB), // TODO: split enable_exception_msb
+COMPPGM2(granulated_lds_size, compute_pgm_rsrc2_lds_size, LDS_SIZE),
+COMPPGM2(enable_exception, compute_pgm_rsrc2_excp_en, EXCP_EN), // TODO: split enable_exception
+
+CODEPROP(enable_sgpr_private_segment_buffer, ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER),
+CODEPROP(enable_sgpr_dispatch_ptr, ENABLE_SGPR_DISPATCH_PTR),
+CODEPROP(enable_sgpr_queue_ptr, ENABLE_SGPR_QUEUE_PTR),
+CODEPROP(enable_sgpr_kernarg_segment_ptr, ENABLE_SGPR_KERNARG_SEGMENT_PTR),
+CODEPROP(enable_sgpr_dispatch_id, ENABLE_SGPR_DISPATCH_ID),
+CODEPROP(enable_sgpr_flat_scratch_init, ENABLE_SGPR_FLAT_SCRATCH_INIT),
+CODEPROP(enable_sgpr_private_segment_size, ENABLE_SGPR_PRIVATE_SEGMENT_SIZE),
+CODEPROP(enable_sgpr_grid_workgroup_count_x, ENABLE_SGPR_GRID_WORKGROUP_COUNT_X),
+CODEPROP(enable_sgpr_grid_workgroup_count_y, ENABLE_SGPR_GRID_WORKGROUP_COUNT_Y),
+CODEPROP(enable_sgpr_grid_workgroup_count_z, ENABLE_SGPR_GRID_WORKGROUP_COUNT_Z),
+CODEPROP(enable_ordered_append_gds, ENABLE_ORDERED_APPEND_GDS),
+CODEPROP(private_element_size, PRIVATE_ELEMENT_SIZE),
+CODEPROP(is_ptr64, IS_PTR64),
+CODEPROP(is_dynamic_callstack, IS_DYNAMIC_CALLSTACK),
+CODEPROP(is_debug_enabled, IS_DEBUG_SUPPORTED),
+CODEPROP(is_xnack_enabled, IS_XNACK_SUPPORTED),
+
FIELD(workitem_private_segment_byte_size),
FIELD(workgroup_group_segment_byte_size),
FIELD(gds_segment_byte_size),
@@ -94,59 +132,8 @@ FIELD(group_segment_alignment),
FIELD(private_segment_alignment),
FIELD(wavefront_size),
FIELD(call_convention),
-FIELD(runtime_loader_kernel_symbol),
-
-COMPPGM1(vgprs, VGPRS),
-COMPPGM1(sgprs, SGPRS),
-COMPPGM1(priority, PRIORITY),
-COMPPGM1(float_mode, FLOAT_MODE),
-COMPPGM1(priv, PRIV),
-COMPPGM1(dx10_clamp, DX10_CLAMP),
-COMPPGM1(debug_mode, DEBUG_MODE),
-COMPPGM1(ieee_mode, IEEE_MODE),
-COMPPGM2(scratch_en, SCRATCH_EN),
-COMPPGM2(user_sgpr, USER_SGPR),
-COMPPGM2(tgid_x_en, TGID_X_EN),
-COMPPGM2(tgid_y_en, TGID_Y_EN),
-COMPPGM2(tgid_z_en, TGID_Z_EN),
-COMPPGM2(tg_size_en, TG_SIZE_EN),
-COMPPGM2(tidig_comp_cnt, TIDIG_COMP_CNT),
-COMPPGM2(excp_en_msb, EXCP_EN_MSB),
-COMPPGM2(lds_size, LDS_SIZE),
-COMPPGM2(excp_en, EXCP_EN),
-
-CODEPROP(enable_sgpr_private_segment_buffer,
- ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER),
-CODEPROP(enable_sgpr_dispatch_ptr,
- ENABLE_SGPR_DISPATCH_PTR),
-CODEPROP(enable_sgpr_queue_ptr,
- ENABLE_SGPR_QUEUE_PTR),
-CODEPROP(enable_sgpr_kernarg_segment_ptr,
- ENABLE_SGPR_KERNARG_SEGMENT_PTR),
-CODEPROP(enable_sgpr_dispatch_id,
- ENABLE_SGPR_DISPATCH_ID),
-CODEPROP(enable_sgpr_flat_scratch_init,
- ENABLE_SGPR_FLAT_SCRATCH_INIT),
-CODEPROP(enable_sgpr_private_segment_size,
- ENABLE_SGPR_PRIVATE_SEGMENT_SIZE),
-CODEPROP(enable_sgpr_grid_workgroup_count_x,
- ENABLE_SGPR_GRID_WORKGROUP_COUNT_X),
-CODEPROP(enable_sgpr_grid_workgroup_count_y,
- ENABLE_SGPR_GRID_WORKGROUP_COUNT_Y),
-CODEPROP(enable_sgpr_grid_workgroup_count_z,
- ENABLE_SGPR_GRID_WORKGROUP_COUNT_Z),
-CODEPROP(enable_ordered_append_gds,
- ENABLE_ORDERED_APPEND_GDS),
-CODEPROP(private_element_size,
- PRIVATE_ELEMENT_SIZE),
-CODEPROP(is_ptr64,
- IS_PTR64),
-CODEPROP(is_dynamic_callstack,
- IS_DYNAMIC_CALLSTACK),
-CODEPROP(is_debug_enabled,
- IS_DEBUG_SUPPORTED),
-CODEPROP(is_xnack_enabled,
- IS_XNACK_SUPPORTED)
+FIELD(runtime_loader_kernel_symbol)
+// TODO: control_directive
// end of the table
///////////////////////////////////////////////////////////////////////////////
diff --git a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTUtils.cpp b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTUtils.cpp
index f64973a..0333b0a 100644
--- a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTUtils.cpp
+++ b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTUtils.cpp
@@ -24,22 +24,37 @@ using namespace llvm;
static ArrayRef<StringRef> get_amd_kernel_code_t_FldNames() {
static StringRef const Table[] = {
"", // not found placeholder
-#define RECORD(name, print, parse) #name
+#define RECORD(name, altName, print, parse) #name
#include "AMDKernelCodeTInfo.h"
#undef RECORD
};
return makeArrayRef(Table);
}
-static StringMap<int> createIndexMap(const ArrayRef<StringRef> &a) {
+static ArrayRef<StringRef> get_amd_kernel_code_t_FldAltNames() {
+ static StringRef const Table[] = {
+ "", // not found placeholder
+#define RECORD(name, altName, print, parse) #altName
+#include "AMDKernelCodeTInfo.h"
+#undef RECORD
+ };
+ return makeArrayRef(Table);
+}
+
+static StringMap<int> createIndexMap(const ArrayRef<StringRef> &names,
+ const ArrayRef<StringRef> &altNames) {
StringMap<int> map;
- for (auto Name : a)
- map.insert(std::make_pair(Name, map.size()));
+ assert(names.size() == altNames.size());
+ for (unsigned i = 0; i < names.size(); ++i) {
+ map.insert(std::make_pair(names[i], i));
+ map.insert(std::make_pair(altNames[i], i));
+ }
return map;
}
static int get_amd_kernel_code_t_FieldIndex(StringRef name) {
- static const auto map = createIndexMap(get_amd_kernel_code_t_FldNames());
+ static const auto map = createIndexMap(get_amd_kernel_code_t_FldNames(),
+ get_amd_kernel_code_t_FldAltNames());
return map.lookup(name) - 1; // returns -1 if not found
}
@@ -73,7 +88,7 @@ typedef void(*PrintFx)(StringRef,
static ArrayRef<PrintFx> getPrinterTable() {
static const PrintFx Table[] = {
-#define RECORD(name, print, parse) print
+#define RECORD(name, altName, print, parse) print
#include "AMDKernelCodeTInfo.h"
#undef RECORD
};
@@ -145,7 +160,7 @@ typedef bool(*ParseFx)(amd_kernel_code_t &,
static ArrayRef<ParseFx> getParserTable() {
static const ParseFx Table[] = {
-#define RECORD(name, print, parse) parse
+#define RECORD(name, altName, print, parse) parse
#include "AMDKernelCodeTInfo.h"
#undef RECORD
};
diff --git a/contrib/llvm/lib/Target/AMDGPU/VIInstrFormats.td b/contrib/llvm/lib/Target/AMDGPU/VIInstrFormats.td
index 912ed53..1fd1c1e 100644
--- a/contrib/llvm/lib/Target/AMDGPU/VIInstrFormats.td
+++ b/contrib/llvm/lib/Target/AMDGPU/VIInstrFormats.td
@@ -11,283 +11,6 @@
//
//===----------------------------------------------------------------------===//
-class DSe_vi <bits<8> op> : Enc64 {
- bits<8> vdst;
- bits<1> gds;
- bits<8> addr;
- bits<8> data0;
- bits<8> data1;
- bits<8> offset0;
- bits<8> offset1;
-
- let Inst{7-0} = offset0;
- let Inst{15-8} = offset1;
- let Inst{16} = gds;
- let Inst{24-17} = op;
- let Inst{31-26} = 0x36; //encoding
- let Inst{39-32} = addr;
- let Inst{47-40} = data0;
- let Inst{55-48} = data1;
- let Inst{63-56} = vdst;
-}
-
-class MUBUFe_vi <bits<7> op> : Enc64 {
- bits<12> offset;
- bits<1> offen;
- bits<1> idxen;
- bits<1> glc;
- bits<1> lds;
- bits<8> vaddr;
- bits<8> vdata;
- bits<7> srsrc;
- bits<1> slc;
- bits<1> tfe;
- bits<8> soffset;
-
- let Inst{11-0} = offset;
- let Inst{12} = offen;
- let Inst{13} = idxen;
- let Inst{14} = glc;
- let Inst{16} = lds;
- let Inst{17} = slc;
- let Inst{24-18} = op;
- let Inst{31-26} = 0x38; //encoding
- let Inst{39-32} = vaddr;
- let Inst{47-40} = vdata;
- let Inst{52-48} = srsrc{6-2};
- let Inst{55} = tfe;
- let Inst{63-56} = soffset;
-}
-
-class MTBUFe_vi <bits<4> op> : Enc64 {
- bits<12> offset;
- bits<1> offen;
- bits<1> idxen;
- bits<1> glc;
- bits<4> dfmt;
- bits<3> nfmt;
- bits<8> vaddr;
- bits<8> vdata;
- bits<7> srsrc;
- bits<1> slc;
- bits<1> tfe;
- bits<8> soffset;
-
- let Inst{11-0} = offset;
- let Inst{12} = offen;
- let Inst{13} = idxen;
- let Inst{14} = glc;
- let Inst{18-15} = op;
- let Inst{22-19} = dfmt;
- let Inst{25-23} = nfmt;
- let Inst{31-26} = 0x3a; //encoding
- let Inst{39-32} = vaddr;
- let Inst{47-40} = vdata;
- let Inst{52-48} = srsrc{6-2};
- let Inst{54} = slc;
- let Inst{55} = tfe;
- let Inst{63-56} = soffset;
-}
-
-class SMEMe_vi <bits<8> op, bit imm> : Enc64 {
- bits<7> sbase;
- bits<7> sdst;
- bits<1> glc;
-
- let Inst{5-0} = sbase{6-1};
- let Inst{12-6} = sdst;
- let Inst{16} = glc;
- let Inst{17} = imm;
- let Inst{25-18} = op;
- let Inst{31-26} = 0x30; //encoding
-}
-
-class SMEM_IMMe_vi <bits<8> op> : SMEMe_vi<op, 1> {
- bits<20> offset;
- let Inst{51-32} = offset;
-}
-
-class SMEM_SOFFe_vi <bits<8> op> : SMEMe_vi<op, 0> {
- bits<20> soff;
- let Inst{51-32} = soff;
-}
-
-class VOP3a_vi <bits<10> op> : Enc64 {
- bits<2> src0_modifiers;
- bits<9> src0;
- bits<2> src1_modifiers;
- bits<9> src1;
- bits<2> src2_modifiers;
- bits<9> src2;
- bits<1> clamp;
- bits<2> omod;
-
- let Inst{8} = src0_modifiers{1};
- let Inst{9} = src1_modifiers{1};
- let Inst{10} = src2_modifiers{1};
- let Inst{15} = clamp;
- let Inst{25-16} = op;
- let Inst{31-26} = 0x34; //encoding
- let Inst{40-32} = src0;
- let Inst{49-41} = src1;
- let Inst{58-50} = src2;
- let Inst{60-59} = omod;
- let Inst{61} = src0_modifiers{0};
- let Inst{62} = src1_modifiers{0};
- let Inst{63} = src2_modifiers{0};
-}
-
-class VOP3e_vi <bits<10> op> : VOP3a_vi <op> {
- bits<8> vdst;
-
- let Inst{7-0} = vdst;
-}
-
-// Encoding used for VOPC instructions encoded as VOP3
-// Differs from VOP3e by destination name (sdst) as VOPC doesn't have vector dst
-class VOP3ce_vi <bits<10> op> : VOP3a_vi <op> {
- bits<8> sdst;
-
- let Inst{7-0} = sdst;
-}
-
-class VOP3be_vi <bits<10> op> : Enc64 {
- bits<8> vdst;
- bits<2> src0_modifiers;
- bits<9> src0;
- bits<2> src1_modifiers;
- bits<9> src1;
- bits<2> src2_modifiers;
- bits<9> src2;
- bits<7> sdst;
- bits<2> omod;
- bits<1> clamp;
-
- let Inst{7-0} = vdst;
- let Inst{14-8} = sdst;
- let Inst{15} = clamp;
- let Inst{25-16} = op;
- let Inst{31-26} = 0x34; //encoding
- let Inst{40-32} = src0;
- let Inst{49-41} = src1;
- let Inst{58-50} = src2;
- let Inst{60-59} = omod;
- let Inst{61} = src0_modifiers{0};
- let Inst{62} = src1_modifiers{0};
- let Inst{63} = src2_modifiers{0};
-}
-
-class VOP_DPP <dag outs, dag ins, string asm, list<dag> pattern, bit HasMods = 0> :
- VOPAnyCommon <outs, ins, asm, pattern> {
- let DPP = 1;
- let Size = 8;
-
- let AsmMatchConverter = !if(!eq(HasMods,1), "cvtDPP", "");
-}
-
-class VOP_DPPe : Enc64 {
- bits<2> src0_modifiers;
- bits<8> src0;
- bits<2> src1_modifiers;
- bits<9> dpp_ctrl;
- bits<1> bound_ctrl;
- bits<4> bank_mask;
- bits<4> row_mask;
-
- let Inst{39-32} = src0;
- let Inst{48-40} = dpp_ctrl;
- let Inst{51} = bound_ctrl;
- let Inst{52} = src0_modifiers{0}; // src0_neg
- let Inst{53} = src0_modifiers{1}; // src0_abs
- let Inst{54} = src1_modifiers{0}; // src1_neg
- let Inst{55} = src1_modifiers{1}; // src1_abs
- let Inst{59-56} = bank_mask;
- let Inst{63-60} = row_mask;
-}
-
-class VOP1_DPPe <bits<8> op> : VOP_DPPe {
- bits<8> vdst;
-
- let Inst{8-0} = 0xfa; // dpp
- let Inst{16-9} = op;
- let Inst{24-17} = vdst;
- let Inst{31-25} = 0x3f; //encoding
-}
-
-class VOP2_DPPe <bits<6> op> : VOP_DPPe {
- bits<8> vdst;
- bits<8> src1;
-
- let Inst{8-0} = 0xfa; //dpp
- let Inst{16-9} = src1;
- let Inst{24-17} = vdst;
- let Inst{30-25} = op;
- let Inst{31} = 0x0; //encoding
-}
-
-class VOP_SDWA <dag outs, dag ins, string asm, list<dag> pattern, bit HasMods = 0> :
- VOPAnyCommon <outs, ins, asm, pattern> {
- let SDWA = 1;
- let Size = 8;
-}
-
-class VOP_SDWAe : Enc64 {
- bits<8> src0;
- bits<3> src0_sel;
- bits<2> src0_fmodifiers; // {abs,neg}
- bits<1> src0_imodifiers; // sext
- bits<3> src1_sel;
- bits<2> src1_fmodifiers;
- bits<1> src1_imodifiers;
- bits<3> dst_sel;
- bits<2> dst_unused;
- bits<1> clamp;
-
- let Inst{39-32} = src0;
- let Inst{42-40} = dst_sel;
- let Inst{44-43} = dst_unused;
- let Inst{45} = clamp;
- let Inst{50-48} = src0_sel;
- let Inst{53-52} = src0_fmodifiers;
- let Inst{51} = src0_imodifiers;
- let Inst{58-56} = src1_sel;
- let Inst{61-60} = src1_fmodifiers;
- let Inst{59} = src1_imodifiers;
-}
-
-class VOP1_SDWAe <bits<8> op> : VOP_SDWAe {
- bits<8> vdst;
-
- let Inst{8-0} = 0xf9; // sdwa
- let Inst{16-9} = op;
- let Inst{24-17} = vdst;
- let Inst{31-25} = 0x3f; // encoding
-}
-
-class VOP2_SDWAe <bits<6> op> : VOP_SDWAe {
- bits<8> vdst;
- bits<8> src1;
-
- let Inst{8-0} = 0xf9; // sdwa
- let Inst{16-9} = src1;
- let Inst{24-17} = vdst;
- let Inst{30-25} = op;
- let Inst{31} = 0x0; // encoding
-}
-
-class VOPC_SDWAe <bits<8> op> : VOP_SDWAe {
- bits<8> src1;
-
- let Inst{8-0} = 0xf9; // sdwa
- let Inst{16-9} = src1;
- let Inst{24-17} = op;
- let Inst{31-25} = 0x3e; // encoding
-
- // VOPC disallows dst_sel and dst_unused as they have no effect on destination
- let Inst{42-40} = 0x6;
- let Inst{44-43} = 0x2;
-}
-
class EXPe_vi : EXPe {
let Inst{31-26} = 0x31; //encoding
}
diff --git a/contrib/llvm/lib/Target/AMDGPU/VIInstructions.td b/contrib/llvm/lib/Target/AMDGPU/VIInstructions.td
index 5c490ab..b45c8fc 100644
--- a/contrib/llvm/lib/Target/AMDGPU/VIInstructions.td
+++ b/contrib/llvm/lib/Target/AMDGPU/VIInstructions.td
@@ -9,150 +9,6 @@
// Instruction definitions for VI and newer.
//===----------------------------------------------------------------------===//
-let SIAssemblerPredicate = DisableInst, SubtargetPredicate = isVI in {
-
-let DisableSIDecoder = 1 in {
-
-//===----------------------------------------------------------------------===//
-// VOP1 Instructions
-//===----------------------------------------------------------------------===//
-
-defm V_CVT_F16_U16 : VOP1Inst <vop1<0, 0x39>, "v_cvt_f16_u16", VOP_F16_I16>;
-defm V_CVT_F16_I16 : VOP1Inst <vop1<0, 0x3a>, "v_cvt_f16_i16", VOP_F16_I16>;
-defm V_CVT_U16_F16 : VOP1Inst <vop1<0, 0x3b>, "v_cvt_u16_f16", VOP_I16_F16>;
-defm V_CVT_I16_F16 : VOP1Inst <vop1<0, 0x3c>, "v_cvt_i16_f16", VOP_I16_F16>;
-defm V_RCP_F16 : VOP1Inst <vop1<0, 0x3d>, "v_rcp_f16", VOP_F16_F16>;
-defm V_SQRT_F16 : VOP1Inst <vop1<0, 0x3e>, "v_sqrt_f16", VOP_F16_F16>;
-defm V_RSQ_F16 : VOP1Inst <vop1<0, 0x3f>, "v_rsq_f16", VOP_F16_F16>;
-defm V_LOG_F16 : VOP1Inst <vop1<0, 0x40>, "v_log_f16", VOP_F16_F16>;
-defm V_EXP_F16 : VOP1Inst <vop1<0, 0x41>, "v_exp_f16", VOP_F16_F16>;
-defm V_FREXP_MANT_F16 : VOP1Inst <vop1<0, 0x42>, "v_frexp_mant_f16",
- VOP_F16_F16
->;
-defm V_FREXP_EXP_I16_F16 : VOP1Inst <vop1<0, 0x43>, "v_frexp_exp_i16_f16",
- VOP_I16_F16
->;
-defm V_FLOOR_F16 : VOP1Inst <vop1<0, 0x44>, "v_floor_f16", VOP_F16_F16>;
-defm V_CEIL_F16 : VOP1Inst <vop1<0, 0x45>, "v_ceil_f16", VOP_F16_F16>;
-defm V_TRUNC_F16 : VOP1Inst <vop1<0, 0x46>, "v_trunc_f16", VOP_F16_F16>;
-defm V_RNDNE_F16 : VOP1Inst <vop1<0, 0x47>, "v_rndne_f16", VOP_F16_F16>;
-defm V_FRACT_F16 : VOP1Inst <vop1<0, 0x48>, "v_fract_f16", VOP_F16_F16>;
-defm V_SIN_F16 : VOP1Inst <vop1<0, 0x49>, "v_sin_f16", VOP_F16_F16>;
-defm V_COS_F16 : VOP1Inst <vop1<0, 0x4a>, "v_cos_f16", VOP_F16_F16>;
-
-//===----------------------------------------------------------------------===//
-// VOP2 Instructions
-//===----------------------------------------------------------------------===//
-
-let isCommutable = 1 in {
-
-defm V_ADD_F16 : VOP2Inst <vop2<0, 0x1f>, "v_add_f16", VOP_F16_F16_F16>;
-defm V_SUB_F16 : VOP2Inst <vop2<0, 0x20>, "v_sub_f16", VOP_F16_F16_F16>;
-defm V_SUBREV_F16 : VOP2Inst <vop2<0, 0x21>, "v_subrev_f16", VOP_F16_F16_F16,
- null_frag, "v_sub_f16"
->;
-defm V_MUL_F16 : VOP2Inst <vop2<0, 0x22>, "v_mul_f16", VOP_F16_F16_F16>;
-defm V_MAC_F16 : VOP2Inst <vop2<0, 0x23>, "v_mac_f16", VOP_F16_F16_F16>;
-} // End isCommutable = 1
-defm V_MADMK_F16 : VOP2MADK <vop2<0,0x24>, "v_madmk_f16", VOP_MADMK>;
-let isCommutable = 1 in {
-defm V_MADAK_F16 : VOP2MADK <vop2<0,0x25>, "v_madak_f16", VOP_MADAK>;
-defm V_ADD_U16 : VOP2Inst <vop2<0,0x26>, "v_add_u16", VOP_I16_I16_I16>;
-defm V_SUB_U16 : VOP2Inst <vop2<0,0x27>, "v_sub_u16" , VOP_I16_I16_I16>;
-defm V_SUBREV_U16 : VOP2Inst <vop2<0,0x28>, "v_subrev_u16", VOP_I16_I16_I16>;
-defm V_MUL_LO_U16 : VOP2Inst <vop2<0,0x29>, "v_mul_lo_u16", VOP_I16_I16_I16>;
-} // End isCommutable = 1
-defm V_LSHLREV_B16 : VOP2Inst <vop2<0,0x2a>, "v_lshlrev_b16", VOP_I16_I16_I16>;
-defm V_LSHRREV_B16 : VOP2Inst <vop2<0,0x2b>, "v_lshrrev_b16", VOP_I16_I16_I16>;
-defm V_ASHRREV_B16 : VOP2Inst <vop2<0,0x2c>, "v_ashrrev_b16", VOP_I16_I16_I16>;
-let isCommutable = 1 in {
-defm V_MAX_F16 : VOP2Inst <vop2<0,0x2d>, "v_max_f16", VOP_F16_F16_F16>;
-defm V_MIN_F16 : VOP2Inst <vop2<0,0x2e>, "v_min_f16", VOP_F16_F16_F16>;
-defm V_MAX_U16 : VOP2Inst <vop2<0,0x2f>, "v_max_u16", VOP_I16_I16_I16>;
-defm V_MAX_I16 : VOP2Inst <vop2<0,0x30>, "v_max_i16", VOP_I16_I16_I16>;
-defm V_MIN_U16 : VOP2Inst <vop2<0,0x31>, "v_min_u16", VOP_I16_I16_I16>;
-defm V_MIN_I16 : VOP2Inst <vop2<0,0x32>, "v_min_i16", VOP_I16_I16_I16>;
-} // End isCommutable = 1
-defm V_LDEXP_F16 : VOP2Inst <vop2<0,0x33>, "v_ldexp_f16", VOP_F16_F16_I16>;
-
-//===----------------------------------------------------------------------===//
-// VOP3 Instructions
-//===----------------------------------------------------------------------===//
-let isCommutable = 1 in {
- defm V_MAD_F16 : VOP3Inst <vop3<0, 0x1ea>, "v_mad_f16", VOP_F16_F16_F16_F16>;
- defm V_MAD_U16 : VOP3Inst <vop3<0, 0x1eb>, "v_mad_u16", VOP_I16_I16_I16_I16>;
- defm V_MAD_I16 : VOP3Inst <vop3<0, 0x1ec>, "v_mad_i16", VOP_I16_I16_I16_I16>;
-}
-} // let DisableSIDecoder = 1
-
-// Aliases to simplify matching of floating-point instructions that
-// are VOP2 on SI and VOP3 on VI.
-
-class SI2_VI3Alias <string name, Instruction inst> : InstAlias <
- name#" $dst, $src0, $src1",
- (inst VGPR_32:$dst, 0, VCSrc_32:$src0, 0, VCSrc_32:$src1, 0, 0)
->, PredicateControl {
- let UseInstAsmMatchConverter = 0;
-}
-
-def : SI2_VI3Alias <"v_ldexp_f32", V_LDEXP_F32_e64_vi>;
-def : SI2_VI3Alias <"v_cvt_pkaccum_u8_f32", V_CVT_PKACCUM_U8_F32_e64_vi>;
-def : SI2_VI3Alias <"v_cvt_pknorm_i16_f32", V_CVT_PKNORM_I16_F32_e64_vi>;
-def : SI2_VI3Alias <"v_cvt_pknorm_u16_f32", V_CVT_PKNORM_U16_F32_e64_vi>;
-def : SI2_VI3Alias <"v_cvt_pkrtz_f16_f32", V_CVT_PKRTZ_F16_F32_e64_vi>;
-
-//===----------------------------------------------------------------------===//
-// SMEM Instructions
-//===----------------------------------------------------------------------===//
-
-def S_DCACHE_WB : SMEM_Inval <0x21,
- "s_dcache_wb", int_amdgcn_s_dcache_wb>;
-
-def S_DCACHE_WB_VOL : SMEM_Inval <0x23,
- "s_dcache_wb_vol", int_amdgcn_s_dcache_wb_vol>;
-
-def S_MEMREALTIME : SMEM_Ret<0x25,
- "s_memrealtime", int_amdgcn_s_memrealtime>;
-
-} // End SIAssemblerPredicate = DisableInst, SubtargetPredicate = isVI
-
-let Predicates = [isVI] in {
-
-// 1. Offset as 20bit DWORD immediate
-def : Pat <
- (SIload_constant v4i32:$sbase, IMM20bit:$offset),
- (S_BUFFER_LOAD_DWORD_IMM $sbase, (as_i32imm $offset))
->;
-
-//===----------------------------------------------------------------------===//
-// DPP Patterns
-//===----------------------------------------------------------------------===//
-
-def : Pat <
- (int_amdgcn_mov_dpp i32:$src, imm:$dpp_ctrl, imm:$row_mask, imm:$bank_mask,
- imm:$bound_ctrl),
- (V_MOV_B32_dpp $src, (as_i32imm $dpp_ctrl), (as_i32imm $row_mask),
- (as_i32imm $bank_mask), (as_i1imm $bound_ctrl))
->;
-
-//===----------------------------------------------------------------------===//
-// Misc Patterns
-//===----------------------------------------------------------------------===//
-
-def : Pat <
- (i64 (readcyclecounter)),
- (S_MEMREALTIME)
->;
-
-//===----------------------------------------------------------------------===//
-// DS_PERMUTE/DS_BPERMUTE Instructions.
-//===----------------------------------------------------------------------===//
-
-let Uses = [EXEC] in {
-defm DS_PERMUTE_B32 : DS_1A1D_PERMUTE <0x3e, "ds_permute_b32", VGPR_32,
- int_amdgcn_ds_permute>;
-defm DS_BPERMUTE_B32 : DS_1A1D_PERMUTE <0x3f, "ds_bpermute_b32", VGPR_32,
- int_amdgcn_ds_bpermute>;
-}
-
-} // End Predicates = [isVI]
+FIXME: Deleting this file broke buildbots that don't do full rebuilds. This
+file is no longer used by the backend, so it can be deleted once all
+the buildbots update there dependencies.
diff --git a/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td b/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td
new file mode 100644
index 0000000..8cae83c
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td
@@ -0,0 +1,615 @@
+//===-- VOP1Instructions.td - Vector Instruction Defintions ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// VOP1 Classes
+//===----------------------------------------------------------------------===//
+
+class VOP1e <bits<8> op, VOPProfile P> : Enc32 {
+ bits<8> vdst;
+ bits<9> src0;
+
+ let Inst{8-0} = !if(P.HasSrc0, src0{8-0}, 0);
+ let Inst{16-9} = op;
+ let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
+ let Inst{31-25} = 0x3f; //encoding
+}
+
+class VOP1_SDWAe <bits<8> op, VOPProfile P> : VOP_SDWAe <P> {
+ bits<8> vdst;
+
+ let Inst{8-0} = 0xf9; // sdwa
+ let Inst{16-9} = op;
+ let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
+ let Inst{31-25} = 0x3f; // encoding
+}
+
+class VOP1_Pseudo <string opName, VOPProfile P, list<dag> pattern=[]> :
+ InstSI <P.Outs32, P.Ins32, "", pattern>,
+ VOP <opName>,
+ SIMCInstr <opName#"_e32", SIEncodingFamily.NONE>,
+ MnemonicAlias<opName#"_e32", opName> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = P.Asm32;
+
+ let Size = 4;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SubtargetPredicate = isGCN;
+
+ let VOP1 = 1;
+ let VALU = 1;
+ let Uses = [EXEC];
+
+ let AsmVariantName = AMDGPUAsmVariants.Default;
+
+ VOPProfile Pfl = P;
+}
+
+class VOP1_Real <VOP1_Pseudo ps, int EncodingFamily> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
+ SIMCInstr <ps.PseudoInstr, EncodingFamily> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let AsmVariantName = ps.AsmVariantName;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+}
+
+class VOP1_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
+ VOP_SDWA_Pseudo <OpName, P, pattern> {
+ let AsmMatchConverter = "cvtSdwaVOP1";
+}
+
+class getVOP1Pat64 <SDPatternOperator node, VOPProfile P> : LetDummies {
+ list<dag> ret = !if(P.HasModifiers,
+ [(set P.DstVT:$vdst, (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0,
+ i32:$src0_modifiers, i1:$clamp, i32:$omod))))],
+ [(set P.DstVT:$vdst, (node P.Src0VT:$src0))]);
+}
+
+multiclass VOP1Inst <string opName, VOPProfile P,
+ SDPatternOperator node = null_frag> {
+ def _e32 : VOP1_Pseudo <opName, P>;
+ def _e64 : VOP3_Pseudo <opName, P, getVOP1Pat64<node, P>.ret>;
+ def _sdwa : VOP1_SDWA_Pseudo <opName, P>;
+}
+
+//===----------------------------------------------------------------------===//
+// VOP1 Instructions
+//===----------------------------------------------------------------------===//
+
+let VOPAsmPrefer32Bit = 1 in {
+defm V_NOP : VOP1Inst <"v_nop", VOP_NONE>;
+}
+
+let isMoveImm = 1, isReMaterializable = 1, isAsCheapAsAMove = 1 in {
+defm V_MOV_B32 : VOP1Inst <"v_mov_b32", VOP_I32_I32>;
+} // End isMoveImm = 1
+
+// FIXME: Specify SchedRW for READFIRSTLANE_B32
+// TODO: Make profile for this, there is VOP3 encoding also
+def V_READFIRSTLANE_B32 :
+ InstSI <(outs SReg_32:$vdst),
+ (ins VGPR_32:$src0),
+ "v_readfirstlane_b32 $vdst, $src0",
+ [(set i32:$vdst, (int_amdgcn_readfirstlane i32:$src0))]>,
+ Enc32 {
+
+ let isCodeGenOnly = 0;
+ let UseNamedOperandTable = 1;
+
+ let Size = 4;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SubtargetPredicate = isGCN;
+
+ let VOP1 = 1;
+ let VALU = 1;
+ let Uses = [EXEC];
+ let isConvergent = 1;
+
+ bits<8> vdst;
+ bits<9> src0;
+
+ let Inst{8-0} = src0;
+ let Inst{16-9} = 0x2;
+ let Inst{24-17} = vdst;
+ let Inst{31-25} = 0x3f; //encoding
+}
+
+let SchedRW = [WriteQuarterRate32] in {
+defm V_CVT_I32_F64 : VOP1Inst <"v_cvt_i32_f64", VOP_I32_F64, fp_to_sint>;
+defm V_CVT_F64_I32 : VOP1Inst <"v_cvt_f64_i32", VOP_F64_I32, sint_to_fp>;
+defm V_CVT_F32_I32 : VOP1Inst <"v_cvt_f32_i32", VOP_F32_I32, sint_to_fp>;
+defm V_CVT_F32_U32 : VOP1Inst <"v_cvt_f32_u32", VOP_F32_I32, uint_to_fp>;
+defm V_CVT_U32_F32 : VOP1Inst <"v_cvt_u32_f32", VOP_I32_F32, fp_to_uint>;
+defm V_CVT_I32_F32 : VOP1Inst <"v_cvt_i32_f32", VOP_I32_F32, fp_to_sint>;
+defm V_CVT_F16_F32 : VOP1Inst <"v_cvt_f16_f32", VOP_I32_F32, fp_to_f16>;
+defm V_CVT_F32_F16 : VOP1Inst <"v_cvt_f32_f16", VOP_F32_I32, f16_to_fp>;
+defm V_CVT_RPI_I32_F32 : VOP1Inst <"v_cvt_rpi_i32_f32", VOP_I32_F32, cvt_rpi_i32_f32>;
+defm V_CVT_FLR_I32_F32 : VOP1Inst <"v_cvt_flr_i32_f32", VOP_I32_F32, cvt_flr_i32_f32>;
+defm V_CVT_OFF_F32_I4 : VOP1Inst <"v_cvt_off_f32_i4", VOP_F32_I32>;
+defm V_CVT_F32_F64 : VOP1Inst <"v_cvt_f32_f64", VOP_F32_F64, fpround>;
+defm V_CVT_F64_F32 : VOP1Inst <"v_cvt_f64_f32", VOP_F64_F32, fpextend>;
+defm V_CVT_F32_UBYTE0 : VOP1Inst <"v_cvt_f32_ubyte0", VOP_F32_I32, AMDGPUcvt_f32_ubyte0>;
+defm V_CVT_F32_UBYTE1 : VOP1Inst <"v_cvt_f32_ubyte1", VOP_F32_I32, AMDGPUcvt_f32_ubyte1>;
+defm V_CVT_F32_UBYTE2 : VOP1Inst <"v_cvt_f32_ubyte2", VOP_F32_I32, AMDGPUcvt_f32_ubyte2>;
+defm V_CVT_F32_UBYTE3 : VOP1Inst <"v_cvt_f32_ubyte3", VOP_F32_I32, AMDGPUcvt_f32_ubyte3>;
+defm V_CVT_U32_F64 : VOP1Inst <"v_cvt_u32_f64", VOP_I32_F64, fp_to_uint>;
+defm V_CVT_F64_U32 : VOP1Inst <"v_cvt_f64_u32", VOP_F64_I32, uint_to_fp>;
+} // End SchedRW = [WriteQuarterRate32]
+
+defm V_FRACT_F32 : VOP1Inst <"v_fract_f32", VOP_F32_F32, AMDGPUfract>;
+defm V_TRUNC_F32 : VOP1Inst <"v_trunc_f32", VOP_F32_F32, ftrunc>;
+defm V_CEIL_F32 : VOP1Inst <"v_ceil_f32", VOP_F32_F32, fceil>;
+defm V_RNDNE_F32 : VOP1Inst <"v_rndne_f32", VOP_F32_F32, frint>;
+defm V_FLOOR_F32 : VOP1Inst <"v_floor_f32", VOP_F32_F32, ffloor>;
+defm V_EXP_F32 : VOP1Inst <"v_exp_f32", VOP_F32_F32, fexp2>;
+
+let SchedRW = [WriteQuarterRate32] in {
+defm V_LOG_F32 : VOP1Inst <"v_log_f32", VOP_F32_F32, flog2>;
+defm V_RCP_F32 : VOP1Inst <"v_rcp_f32", VOP_F32_F32, AMDGPUrcp>;
+defm V_RCP_IFLAG_F32 : VOP1Inst <"v_rcp_iflag_f32", VOP_F32_F32>;
+defm V_RSQ_F32 : VOP1Inst <"v_rsq_f32", VOP_F32_F32, AMDGPUrsq>;
+} // End SchedRW = [WriteQuarterRate32]
+
+let SchedRW = [WriteDouble] in {
+defm V_RCP_F64 : VOP1Inst <"v_rcp_f64", VOP_F64_F64, AMDGPUrcp>;
+defm V_RSQ_F64 : VOP1Inst <"v_rsq_f64", VOP_F64_F64, AMDGPUrsq>;
+} // End SchedRW = [WriteDouble];
+
+defm V_SQRT_F32 : VOP1Inst <"v_sqrt_f32", VOP_F32_F32, fsqrt>;
+
+let SchedRW = [WriteDouble] in {
+defm V_SQRT_F64 : VOP1Inst <"v_sqrt_f64", VOP_F64_F64, fsqrt>;
+} // End SchedRW = [WriteDouble]
+
+let SchedRW = [WriteQuarterRate32] in {
+defm V_SIN_F32 : VOP1Inst <"v_sin_f32", VOP_F32_F32, AMDGPUsin>;
+defm V_COS_F32 : VOP1Inst <"v_cos_f32", VOP_F32_F32, AMDGPUcos>;
+} // End SchedRW = [WriteQuarterRate32]
+
+defm V_NOT_B32 : VOP1Inst <"v_not_b32", VOP_I32_I32>;
+defm V_BFREV_B32 : VOP1Inst <"v_bfrev_b32", VOP_I32_I32>;
+defm V_FFBH_U32 : VOP1Inst <"v_ffbh_u32", VOP_I32_I32>;
+defm V_FFBL_B32 : VOP1Inst <"v_ffbl_b32", VOP_I32_I32>;
+defm V_FFBH_I32 : VOP1Inst <"v_ffbh_i32", VOP_I32_I32>;
+defm V_FREXP_EXP_I32_F64 : VOP1Inst <"v_frexp_exp_i32_f64", VOP_I32_F64, int_amdgcn_frexp_exp>;
+
+let SchedRW = [WriteDoubleAdd] in {
+defm V_FREXP_MANT_F64 : VOP1Inst <"v_frexp_mant_f64", VOP_F64_F64, int_amdgcn_frexp_mant>;
+defm V_FRACT_F64 : VOP1Inst <"v_fract_f64", VOP_F64_F64, AMDGPUfract>;
+} // End SchedRW = [WriteDoubleAdd]
+
+defm V_FREXP_EXP_I32_F32 : VOP1Inst <"v_frexp_exp_i32_f32", VOP_I32_F32, int_amdgcn_frexp_exp>;
+defm V_FREXP_MANT_F32 : VOP1Inst <"v_frexp_mant_f32", VOP_F32_F32, int_amdgcn_frexp_mant>;
+
+let VOPAsmPrefer32Bit = 1 in {
+defm V_CLREXCP : VOP1Inst <"v_clrexcp", VOP_NO_EXT<VOP_NONE>>;
+}
+
+// Restrict src0 to be VGPR
+def VOP_I32_VI32_NO_EXT : VOPProfile<[i32, i32, untyped, untyped]> {
+ let Src0RC32 = VRegSrc_32;
+ let Src0RC64 = VRegSrc_32;
+
+ let HasExt = 0;
+}
+
+// Special case because there are no true output operands. Hack vdst
+// to be a src operand. The custom inserter must add a tied implicit
+// def and use of the super register since there seems to be no way to
+// add an implicit def of a virtual register in tablegen.
+def VOP_MOVRELD : VOPProfile<[untyped, i32, untyped, untyped]> {
+ let Src0RC32 = VOPDstOperand<VGPR_32>;
+ let Src0RC64 = VOPDstOperand<VGPR_32>;
+
+ let Outs = (outs);
+ let Ins32 = (ins Src0RC32:$vdst, VSrc_b32:$src0);
+ let Ins64 = (ins Src0RC64:$vdst, VSrc_b32:$src0);
+ let InsDPP = (ins Src0RC32:$vdst, Src0RC32:$src0, dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
+ bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
+ let InsSDWA = (ins Src0RC32:$vdst, Src0ModSDWA:$src0_modifiers, VCSrc_b32:$src0,
+ clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
+ src0_sel:$src0_sel);
+
+ let Asm32 = getAsm32<1, 1>.ret;
+ let Asm64 = getAsm64<1, 1, 0>.ret;
+ let AsmDPP = getAsmDPP<1, 1, 0>.ret;
+ let AsmSDWA = getAsmSDWA<1, 1, 0>.ret;
+
+ let HasExt = 0;
+ let HasDst = 0;
+ let EmitDst = 1; // force vdst emission
+}
+
+let SubtargetPredicate = HasMovrel, Uses = [M0, EXEC] in {
+// v_movreld_b32 is a special case because the destination output
+ // register is really a source. It isn't actually read (but may be
+ // written), and is only to provide the base register to start
+ // indexing from. Tablegen seems to not let you define an implicit
+ // virtual register output for the super register being written into,
+ // so this must have an implicit def of the register added to it.
+defm V_MOVRELD_B32 : VOP1Inst <"v_movreld_b32", VOP_MOVRELD>;
+defm V_MOVRELS_B32 : VOP1Inst <"v_movrels_b32", VOP_I32_VI32_NO_EXT>;
+defm V_MOVRELSD_B32 : VOP1Inst <"v_movrelsd_b32", VOP_NO_EXT<VOP_I32_I32>>;
+} // End Uses = [M0, EXEC]
+
+// These instruction only exist on SI and CI
+let SubtargetPredicate = isSICI in {
+
+let SchedRW = [WriteQuarterRate32] in {
+defm V_MOV_FED_B32 : VOP1Inst <"v_mov_fed_b32", VOP_I32_I32>;
+defm V_LOG_CLAMP_F32 : VOP1Inst <"v_log_clamp_f32", VOP_F32_F32, int_amdgcn_log_clamp>;
+defm V_RCP_CLAMP_F32 : VOP1Inst <"v_rcp_clamp_f32", VOP_F32_F32>;
+defm V_RCP_LEGACY_F32 : VOP1Inst <"v_rcp_legacy_f32", VOP_F32_F32, AMDGPUrcp_legacy>;
+defm V_RSQ_CLAMP_F32 : VOP1Inst <"v_rsq_clamp_f32", VOP_F32_F32, AMDGPUrsq_clamp>;
+defm V_RSQ_LEGACY_F32 : VOP1Inst <"v_rsq_legacy_f32", VOP_F32_F32, AMDGPUrsq_legacy>;
+} // End SchedRW = [WriteQuarterRate32]
+
+let SchedRW = [WriteDouble] in {
+defm V_RCP_CLAMP_F64 : VOP1Inst <"v_rcp_clamp_f64", VOP_F64_F64>;
+defm V_RSQ_CLAMP_F64 : VOP1Inst <"v_rsq_clamp_f64", VOP_F64_F64, AMDGPUrsq_clamp>;
+} // End SchedRW = [WriteDouble]
+
+} // End SubtargetPredicate = isSICI
+
+
+let SubtargetPredicate = isCIVI in {
+
+let SchedRW = [WriteDoubleAdd] in {
+defm V_TRUNC_F64 : VOP1Inst <"v_trunc_f64", VOP_F64_F64, ftrunc>;
+defm V_CEIL_F64 : VOP1Inst <"v_ceil_f64", VOP_F64_F64, fceil>;
+defm V_FLOOR_F64 : VOP1Inst <"v_floor_f64", VOP_F64_F64, ffloor>;
+defm V_RNDNE_F64 : VOP1Inst <"v_rndne_f64", VOP_F64_F64, frint>;
+} // End SchedRW = [WriteDoubleAdd]
+
+let SchedRW = [WriteQuarterRate32] in {
+defm V_LOG_LEGACY_F32 : VOP1Inst <"v_log_legacy_f32", VOP_F32_F32>;
+defm V_EXP_LEGACY_F32 : VOP1Inst <"v_exp_legacy_f32", VOP_F32_F32>;
+} // End SchedRW = [WriteQuarterRate32]
+
+} // End SubtargetPredicate = isCIVI
+
+
+let SubtargetPredicate = isVI in {
+
+defm V_CVT_F16_U16 : VOP1Inst <"v_cvt_f16_u16", VOP_F16_I16, uint_to_fp>;
+defm V_CVT_F16_I16 : VOP1Inst <"v_cvt_f16_i16", VOP_F16_I16, sint_to_fp>;
+defm V_CVT_U16_F16 : VOP1Inst <"v_cvt_u16_f16", VOP_I16_F16, fp_to_uint>;
+defm V_CVT_I16_F16 : VOP1Inst <"v_cvt_i16_f16", VOP_I16_F16, fp_to_sint>;
+defm V_RCP_F16 : VOP1Inst <"v_rcp_f16", VOP_F16_F16, AMDGPUrcp>;
+defm V_SQRT_F16 : VOP1Inst <"v_sqrt_f16", VOP_F16_F16, fsqrt>;
+defm V_RSQ_F16 : VOP1Inst <"v_rsq_f16", VOP_F16_F16, AMDGPUrsq>;
+defm V_LOG_F16 : VOP1Inst <"v_log_f16", VOP_F16_F16, flog2>;
+defm V_EXP_F16 : VOP1Inst <"v_exp_f16", VOP_F16_F16, fexp2>;
+defm V_FREXP_MANT_F16 : VOP1Inst <"v_frexp_mant_f16", VOP_F16_F16, int_amdgcn_frexp_mant>;
+defm V_FREXP_EXP_I16_F16 : VOP1Inst <"v_frexp_exp_i16_f16", VOP_I16_F16, int_amdgcn_frexp_exp>;
+defm V_FLOOR_F16 : VOP1Inst <"v_floor_f16", VOP_F16_F16, ffloor>;
+defm V_CEIL_F16 : VOP1Inst <"v_ceil_f16", VOP_F16_F16, fceil>;
+defm V_TRUNC_F16 : VOP1Inst <"v_trunc_f16", VOP_F16_F16, ftrunc>;
+defm V_RNDNE_F16 : VOP1Inst <"v_rndne_f16", VOP_F16_F16, frint>;
+defm V_FRACT_F16 : VOP1Inst <"v_fract_f16", VOP_F16_F16, AMDGPUfract>;
+defm V_SIN_F16 : VOP1Inst <"v_sin_f16", VOP_F16_F16, AMDGPUsin>;
+defm V_COS_F16 : VOP1Inst <"v_cos_f16", VOP_F16_F16, AMDGPUcos>;
+
+}
+
+let Predicates = [isVI] in {
+
+def : Pat<
+ (f32 (f16_to_fp i16:$src)),
+ (V_CVT_F32_F16_e32 $src)
+>;
+
+def : Pat<
+ (i16 (fp_to_f16 f32:$src)),
+ (V_CVT_F16_F32_e32 $src)
+>;
+
+}
+
+//===----------------------------------------------------------------------===//
+// Target
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SI
+//===----------------------------------------------------------------------===//
+
+multiclass VOP1_Real_si <bits<9> op> {
+ let AssemblerPredicates = [isSICI], DecoderNamespace = "SICI" in {
+ def _e32_si :
+ VOP1_Real<!cast<VOP1_Pseudo>(NAME#"_e32"), SIEncodingFamily.SI>,
+ VOP1e<op{7-0}, !cast<VOP1_Pseudo>(NAME#"_e32").Pfl>;
+ def _e64_si :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
+ VOP3e_si <{1, 1, op{6-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+ }
+}
+
+defm V_NOP : VOP1_Real_si <0x0>;
+defm V_MOV_B32 : VOP1_Real_si <0x1>;
+defm V_CVT_I32_F64 : VOP1_Real_si <0x3>;
+defm V_CVT_F64_I32 : VOP1_Real_si <0x4>;
+defm V_CVT_F32_I32 : VOP1_Real_si <0x5>;
+defm V_CVT_F32_U32 : VOP1_Real_si <0x6>;
+defm V_CVT_U32_F32 : VOP1_Real_si <0x7>;
+defm V_CVT_I32_F32 : VOP1_Real_si <0x8>;
+defm V_MOV_FED_B32 : VOP1_Real_si <0x9>;
+defm V_CVT_F16_F32 : VOP1_Real_si <0xa>;
+defm V_CVT_F32_F16 : VOP1_Real_si <0xb>;
+defm V_CVT_RPI_I32_F32 : VOP1_Real_si <0xc>;
+defm V_CVT_FLR_I32_F32 : VOP1_Real_si <0xd>;
+defm V_CVT_OFF_F32_I4 : VOP1_Real_si <0xe>;
+defm V_CVT_F32_F64 : VOP1_Real_si <0xf>;
+defm V_CVT_F64_F32 : VOP1_Real_si <0x10>;
+defm V_CVT_F32_UBYTE0 : VOP1_Real_si <0x11>;
+defm V_CVT_F32_UBYTE1 : VOP1_Real_si <0x12>;
+defm V_CVT_F32_UBYTE2 : VOP1_Real_si <0x13>;
+defm V_CVT_F32_UBYTE3 : VOP1_Real_si <0x14>;
+defm V_CVT_U32_F64 : VOP1_Real_si <0x15>;
+defm V_CVT_F64_U32 : VOP1_Real_si <0x16>;
+defm V_FRACT_F32 : VOP1_Real_si <0x20>;
+defm V_TRUNC_F32 : VOP1_Real_si <0x21>;
+defm V_CEIL_F32 : VOP1_Real_si <0x22>;
+defm V_RNDNE_F32 : VOP1_Real_si <0x23>;
+defm V_FLOOR_F32 : VOP1_Real_si <0x24>;
+defm V_EXP_F32 : VOP1_Real_si <0x25>;
+defm V_LOG_CLAMP_F32 : VOP1_Real_si <0x26>;
+defm V_LOG_F32 : VOP1_Real_si <0x27>;
+defm V_RCP_CLAMP_F32 : VOP1_Real_si <0x28>;
+defm V_RCP_LEGACY_F32 : VOP1_Real_si <0x29>;
+defm V_RCP_F32 : VOP1_Real_si <0x2a>;
+defm V_RCP_IFLAG_F32 : VOP1_Real_si <0x2b>;
+defm V_RSQ_CLAMP_F32 : VOP1_Real_si <0x2c>;
+defm V_RSQ_LEGACY_F32 : VOP1_Real_si <0x2d>;
+defm V_RSQ_F32 : VOP1_Real_si <0x2e>;
+defm V_RCP_F64 : VOP1_Real_si <0x2f>;
+defm V_RCP_CLAMP_F64 : VOP1_Real_si <0x30>;
+defm V_RSQ_F64 : VOP1_Real_si <0x31>;
+defm V_RSQ_CLAMP_F64 : VOP1_Real_si <0x32>;
+defm V_SQRT_F32 : VOP1_Real_si <0x33>;
+defm V_SQRT_F64 : VOP1_Real_si <0x34>;
+defm V_SIN_F32 : VOP1_Real_si <0x35>;
+defm V_COS_F32 : VOP1_Real_si <0x36>;
+defm V_NOT_B32 : VOP1_Real_si <0x37>;
+defm V_BFREV_B32 : VOP1_Real_si <0x38>;
+defm V_FFBH_U32 : VOP1_Real_si <0x39>;
+defm V_FFBL_B32 : VOP1_Real_si <0x3a>;
+defm V_FFBH_I32 : VOP1_Real_si <0x3b>;
+defm V_FREXP_EXP_I32_F64 : VOP1_Real_si <0x3c>;
+defm V_FREXP_MANT_F64 : VOP1_Real_si <0x3d>;
+defm V_FRACT_F64 : VOP1_Real_si <0x3e>;
+defm V_FREXP_EXP_I32_F32 : VOP1_Real_si <0x3f>;
+defm V_FREXP_MANT_F32 : VOP1_Real_si <0x40>;
+defm V_CLREXCP : VOP1_Real_si <0x41>;
+defm V_MOVRELD_B32 : VOP1_Real_si <0x42>;
+defm V_MOVRELS_B32 : VOP1_Real_si <0x43>;
+defm V_MOVRELSD_B32 : VOP1_Real_si <0x44>;
+
+//===----------------------------------------------------------------------===//
+// CI
+//===----------------------------------------------------------------------===//
+
+multiclass VOP1_Real_ci <bits<9> op> {
+ let AssemblerPredicates = [isCIOnly], DecoderNamespace = "CI" in {
+ def _e32_ci :
+ VOP1_Real<!cast<VOP1_Pseudo>(NAME#"_e32"), SIEncodingFamily.SI>,
+ VOP1e<op{7-0}, !cast<VOP1_Pseudo>(NAME#"_e32").Pfl>;
+ def _e64_ci :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
+ VOP3e_si <{1, 1, op{6-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+ }
+}
+
+defm V_TRUNC_F64 : VOP1_Real_ci <0x17>;
+defm V_CEIL_F64 : VOP1_Real_ci <0x18>;
+defm V_FLOOR_F64 : VOP1_Real_ci <0x1A>;
+defm V_RNDNE_F64 : VOP1_Real_ci <0x19>;
+defm V_LOG_LEGACY_F32 : VOP1_Real_ci <0x45>;
+defm V_EXP_LEGACY_F32 : VOP1_Real_ci <0x46>;
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+class VOP1_DPP <bits<8> op, VOP1_Pseudo ps, VOPProfile P = ps.Pfl> :
+ VOP_DPP <ps.OpName, P> {
+ let Defs = ps.Defs;
+ let Uses = ps.Uses;
+ let SchedRW = ps.SchedRW;
+ let hasSideEffects = ps.hasSideEffects;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ bits<8> vdst;
+ let Inst{8-0} = 0xfa; // dpp
+ let Inst{16-9} = op;
+ let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
+ let Inst{31-25} = 0x3f; //encoding
+}
+
+multiclass VOP1_Real_vi <bits<10> op> {
+ let AssemblerPredicates = [isVI], DecoderNamespace = "VI" in {
+ def _e32_vi :
+ VOP1_Real<!cast<VOP1_Pseudo>(NAME#"_e32"), SIEncodingFamily.VI>,
+ VOP1e<op{7-0}, !cast<VOP1_Pseudo>(NAME#"_e32").Pfl>;
+ def _e64_vi :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>,
+ VOP3e_vi <!add(0x140, op), !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+ }
+
+ def _sdwa_vi :
+ VOP_SDWA_Real <!cast<VOP1_SDWA_Pseudo>(NAME#"_sdwa")>,
+ VOP1_SDWAe <op{7-0}, !cast<VOP1_SDWA_Pseudo>(NAME#"_sdwa").Pfl>;
+
+ // For now left dpp only for asm/dasm
+ // TODO: add corresponding pseudo
+ def _dpp : VOP1_DPP<op{7-0}, !cast<VOP1_Pseudo>(NAME#"_e32")>;
+}
+
+defm V_NOP : VOP1_Real_vi <0x0>;
+defm V_MOV_B32 : VOP1_Real_vi <0x1>;
+defm V_CVT_I32_F64 : VOP1_Real_vi <0x3>;
+defm V_CVT_F64_I32 : VOP1_Real_vi <0x4>;
+defm V_CVT_F32_I32 : VOP1_Real_vi <0x5>;
+defm V_CVT_F32_U32 : VOP1_Real_vi <0x6>;
+defm V_CVT_U32_F32 : VOP1_Real_vi <0x7>;
+defm V_CVT_I32_F32 : VOP1_Real_vi <0x8>;
+defm V_CVT_F16_F32 : VOP1_Real_vi <0xa>;
+defm V_CVT_F32_F16 : VOP1_Real_vi <0xb>;
+defm V_CVT_RPI_I32_F32 : VOP1_Real_vi <0xc>;
+defm V_CVT_FLR_I32_F32 : VOP1_Real_vi <0xd>;
+defm V_CVT_OFF_F32_I4 : VOP1_Real_vi <0xe>;
+defm V_CVT_F32_F64 : VOP1_Real_vi <0xf>;
+defm V_CVT_F64_F32 : VOP1_Real_vi <0x10>;
+defm V_CVT_F32_UBYTE0 : VOP1_Real_vi <0x11>;
+defm V_CVT_F32_UBYTE1 : VOP1_Real_vi <0x12>;
+defm V_CVT_F32_UBYTE2 : VOP1_Real_vi <0x13>;
+defm V_CVT_F32_UBYTE3 : VOP1_Real_vi <0x14>;
+defm V_CVT_U32_F64 : VOP1_Real_vi <0x15>;
+defm V_CVT_F64_U32 : VOP1_Real_vi <0x16>;
+defm V_FRACT_F32 : VOP1_Real_vi <0x1b>;
+defm V_TRUNC_F32 : VOP1_Real_vi <0x1c>;
+defm V_CEIL_F32 : VOP1_Real_vi <0x1d>;
+defm V_RNDNE_F32 : VOP1_Real_vi <0x1e>;
+defm V_FLOOR_F32 : VOP1_Real_vi <0x1f>;
+defm V_EXP_F32 : VOP1_Real_vi <0x20>;
+defm V_LOG_F32 : VOP1_Real_vi <0x21>;
+defm V_RCP_F32 : VOP1_Real_vi <0x22>;
+defm V_RCP_IFLAG_F32 : VOP1_Real_vi <0x23>;
+defm V_RSQ_F32 : VOP1_Real_vi <0x24>;
+defm V_RCP_F64 : VOP1_Real_vi <0x25>;
+defm V_RSQ_F64 : VOP1_Real_vi <0x26>;
+defm V_SQRT_F32 : VOP1_Real_vi <0x27>;
+defm V_SQRT_F64 : VOP1_Real_vi <0x28>;
+defm V_SIN_F32 : VOP1_Real_vi <0x29>;
+defm V_COS_F32 : VOP1_Real_vi <0x2a>;
+defm V_NOT_B32 : VOP1_Real_vi <0x2b>;
+defm V_BFREV_B32 : VOP1_Real_vi <0x2c>;
+defm V_FFBH_U32 : VOP1_Real_vi <0x2d>;
+defm V_FFBL_B32 : VOP1_Real_vi <0x2e>;
+defm V_FFBH_I32 : VOP1_Real_vi <0x2f>;
+defm V_FREXP_EXP_I32_F64 : VOP1_Real_vi <0x30>;
+defm V_FREXP_MANT_F64 : VOP1_Real_vi <0x31>;
+defm V_FRACT_F64 : VOP1_Real_vi <0x32>;
+defm V_FREXP_EXP_I32_F32 : VOP1_Real_vi <0x33>;
+defm V_FREXP_MANT_F32 : VOP1_Real_vi <0x34>;
+defm V_CLREXCP : VOP1_Real_vi <0x35>;
+defm V_MOVRELD_B32 : VOP1_Real_vi <0x36>;
+defm V_MOVRELS_B32 : VOP1_Real_vi <0x37>;
+defm V_MOVRELSD_B32 : VOP1_Real_vi <0x38>;
+defm V_TRUNC_F64 : VOP1_Real_vi <0x17>;
+defm V_CEIL_F64 : VOP1_Real_vi <0x18>;
+defm V_FLOOR_F64 : VOP1_Real_vi <0x1A>;
+defm V_RNDNE_F64 : VOP1_Real_vi <0x19>;
+defm V_LOG_LEGACY_F32 : VOP1_Real_vi <0x4c>;
+defm V_EXP_LEGACY_F32 : VOP1_Real_vi <0x4b>;
+defm V_CVT_F16_U16 : VOP1_Real_vi <0x39>;
+defm V_CVT_F16_I16 : VOP1_Real_vi <0x3a>;
+defm V_CVT_U16_F16 : VOP1_Real_vi <0x3b>;
+defm V_CVT_I16_F16 : VOP1_Real_vi <0x3c>;
+defm V_RCP_F16 : VOP1_Real_vi <0x3d>;
+defm V_SQRT_F16 : VOP1_Real_vi <0x3e>;
+defm V_RSQ_F16 : VOP1_Real_vi <0x3f>;
+defm V_LOG_F16 : VOP1_Real_vi <0x40>;
+defm V_EXP_F16 : VOP1_Real_vi <0x41>;
+defm V_FREXP_MANT_F16 : VOP1_Real_vi <0x42>;
+defm V_FREXP_EXP_I16_F16 : VOP1_Real_vi <0x43>;
+defm V_FLOOR_F16 : VOP1_Real_vi <0x44>;
+defm V_CEIL_F16 : VOP1_Real_vi <0x45>;
+defm V_TRUNC_F16 : VOP1_Real_vi <0x46>;
+defm V_RNDNE_F16 : VOP1_Real_vi <0x47>;
+defm V_FRACT_F16 : VOP1_Real_vi <0x48>;
+defm V_SIN_F16 : VOP1_Real_vi <0x49>;
+defm V_COS_F16 : VOP1_Real_vi <0x4a>;
+
+
+// Copy of v_mov_b32 with $vdst as a use operand for use with VGPR
+// indexing mode. vdst can't be treated as a def for codegen purposes,
+// and an implicit use and def of the super register should be added.
+def V_MOV_B32_indirect : VPseudoInstSI<(outs),
+ (ins getVALUDstForVT<i32>.ret:$vdst, getVOPSrc0ForVT<i32>.ret:$src0)>,
+ PseudoInstExpansion<(V_MOV_B32_e32_vi getVALUDstForVT<i32>.ret:$vdst,
+ getVOPSrc0ForVT<i32>.ret:$src0)> {
+ let VOP1 = 1;
+ let SubtargetPredicate = isVI;
+}
+
+// This is a pseudo variant of the v_movreld_b32 instruction in which the
+// vector operand appears only twice, once as def and once as use. Using this
+// pseudo avoids problems with the Two Address instructions pass.
+class V_MOVRELD_B32_pseudo<RegisterClass rc> : VPseudoInstSI <
+ (outs rc:$vdst),
+ (ins rc:$vsrc, VSrc_b32:$val, i32imm:$offset)> {
+ let VOP1 = 1;
+
+ let Constraints = "$vsrc = $vdst";
+ let Uses = [M0, EXEC];
+
+ let SubtargetPredicate = HasMovrel;
+}
+
+def V_MOVRELD_B32_V1 : V_MOVRELD_B32_pseudo<VGPR_32>;
+def V_MOVRELD_B32_V2 : V_MOVRELD_B32_pseudo<VReg_64>;
+def V_MOVRELD_B32_V4 : V_MOVRELD_B32_pseudo<VReg_128>;
+def V_MOVRELD_B32_V8 : V_MOVRELD_B32_pseudo<VReg_256>;
+def V_MOVRELD_B32_V16 : V_MOVRELD_B32_pseudo<VReg_512>;
+
+let Predicates = [isVI] in {
+
+def : Pat <
+ (i32 (int_amdgcn_mov_dpp i32:$src, imm:$dpp_ctrl, imm:$row_mask, imm:$bank_mask,
+ imm:$bound_ctrl)),
+ (V_MOV_B32_dpp $src, (as_i32imm $dpp_ctrl), (as_i32imm $row_mask),
+ (as_i32imm $bank_mask), (as_i1imm $bound_ctrl))
+>;
+
+
+def : Pat<
+ (i32 (anyext i16:$src)),
+ (COPY $src)
+>;
+
+def : Pat<
+ (i64 (anyext i16:$src)),
+ (REG_SEQUENCE VReg_64,
+ (i32 (COPY $src)), sub0,
+ (V_MOV_B32_e32 (i32 0)), sub1)
+>;
+
+def : Pat<
+ (i16 (trunc i32:$src)),
+ (COPY $src)
+>;
+
+def : Pat <
+ (i16 (trunc i64:$src)),
+ (EXTRACT_SUBREG $src, sub0)
+>;
+
+} // End Predicates = [isVI]
diff --git a/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td
new file mode 100644
index 0000000..00e5ab3
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td
@@ -0,0 +1,757 @@
+//===-- VOP2Instructions.td - Vector Instruction Defintions ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// VOP2 Classes
+//===----------------------------------------------------------------------===//
+
+class VOP2e <bits<6> op, VOPProfile P> : Enc32 {
+ bits<8> vdst;
+ bits<9> src0;
+ bits<8> src1;
+
+ let Inst{8-0} = !if(P.HasSrc0, src0, 0);
+ let Inst{16-9} = !if(P.HasSrc1, src1, 0);
+ let Inst{24-17} = !if(P.EmitDst, vdst, 0);
+ let Inst{30-25} = op;
+ let Inst{31} = 0x0; //encoding
+}
+
+class VOP2_MADKe <bits<6> op, VOPProfile P> : Enc64 {
+ bits<8> vdst;
+ bits<9> src0;
+ bits<8> src1;
+ bits<32> imm;
+
+ let Inst{8-0} = !if(P.HasSrc0, src0, 0);
+ let Inst{16-9} = !if(P.HasSrc1, src1, 0);
+ let Inst{24-17} = !if(P.EmitDst, vdst, 0);
+ let Inst{30-25} = op;
+ let Inst{31} = 0x0; // encoding
+ let Inst{63-32} = imm;
+}
+
+class VOP2_SDWAe <bits<6> op, VOPProfile P> : VOP_SDWAe <P> {
+ bits<8> vdst;
+ bits<8> src1;
+
+ let Inst{8-0} = 0xf9; // sdwa
+ let Inst{16-9} = !if(P.HasSrc1, src1{7-0}, 0);
+ let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
+ let Inst{30-25} = op;
+ let Inst{31} = 0x0; // encoding
+}
+
+class VOP2_Pseudo <string opName, VOPProfile P, list<dag> pattern=[], string suffix = "_e32"> :
+ InstSI <P.Outs32, P.Ins32, "", pattern>,
+ VOP <opName>,
+ SIMCInstr <opName#suffix, SIEncodingFamily.NONE>,
+ MnemonicAlias<opName#suffix, opName> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = P.Asm32;
+
+ let Size = 4;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SubtargetPredicate = isGCN;
+
+ let VOP2 = 1;
+ let VALU = 1;
+ let Uses = [EXEC];
+
+ let AsmVariantName = AMDGPUAsmVariants.Default;
+
+ VOPProfile Pfl = P;
+}
+
+class VOP2_Real <VOP2_Pseudo ps, int EncodingFamily> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
+ SIMCInstr <ps.PseudoInstr, EncodingFamily> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let AsmVariantName = ps.AsmVariantName;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+}
+
+class VOP2_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
+ VOP_SDWA_Pseudo <OpName, P, pattern> {
+ let AsmMatchConverter = "cvtSdwaVOP2";
+}
+
+class getVOP2Pat64 <SDPatternOperator node, VOPProfile P> : LetDummies {
+ list<dag> ret = !if(P.HasModifiers,
+ [(set P.DstVT:$vdst,
+ (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)),
+ (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))],
+ [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))]);
+}
+
+multiclass VOP2Inst <string opName,
+ VOPProfile P,
+ SDPatternOperator node = null_frag,
+ string revOp = opName> {
+
+ def _e32 : VOP2_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_e32", !eq(revOp, opName)>;
+
+ def _e64 : VOP3_Pseudo <opName, P, getVOP2Pat64<node, P>.ret>,
+ Commutable_REV<revOp#"_e64", !eq(revOp, opName)>;
+
+ def _sdwa : VOP2_SDWA_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_sdwa", !eq(revOp, opName)>;
+}
+
+// TODO: add SDWA pseudo instructions for VOP2bInst and VOP2eInst
+multiclass VOP2bInst <string opName,
+ VOPProfile P,
+ SDPatternOperator node = null_frag,
+ string revOp = opName,
+ bit useSGPRInput = !eq(P.NumSrcArgs, 3)> {
+
+ let SchedRW = [Write32Bit, WriteSALU] in {
+ let Uses = !if(useSGPRInput, [VCC, EXEC], [EXEC]), Defs = [VCC] in {
+ def _e32 : VOP2_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_e32", !eq(revOp, opName)>;
+
+ def _sdwa : VOP2_SDWA_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_sdwa", !eq(revOp, opName)>;
+ }
+ def _e64 : VOP3_Pseudo <opName, P, getVOP2Pat64<node, P>.ret>,
+ Commutable_REV<revOp#"_e64", !eq(revOp, opName)>;
+ }
+}
+
+multiclass VOP2eInst <string opName,
+ VOPProfile P,
+ SDPatternOperator node = null_frag,
+ string revOp = opName,
+ bit useSGPRInput = !eq(P.NumSrcArgs, 3)> {
+
+ let SchedRW = [Write32Bit] in {
+ let Uses = !if(useSGPRInput, [VCC, EXEC], [EXEC]) in {
+ def _e32 : VOP2_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_e32", !eq(revOp, opName)>;
+ }
+ def _e64 : VOP3_Pseudo <opName, P, getVOP2Pat64<node, P>.ret>,
+ Commutable_REV<revOp#"_e64", !eq(revOp, opName)>;
+ }
+}
+
+class VOP_MADAK <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> {
+ field Operand ImmOpType = !if(!eq(vt.Size, 32), f32kimm, f16kimm);
+ field dag Ins32 = (ins VCSrc_f32:$src0, VGPR_32:$src1, ImmOpType:$imm);
+ field string Asm32 = "$vdst, $src0, $src1, $imm";
+ field bit HasExt = 0;
+}
+
+def VOP_MADAK_F16 : VOP_MADAK <f16>;
+def VOP_MADAK_F32 : VOP_MADAK <f32>;
+
+class VOP_MADMK <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> {
+ field Operand ImmOpType = !if(!eq(vt.Size, 32), f32kimm, f16kimm);
+ field dag Ins32 = (ins VCSrc_f32:$src0, ImmOpType:$imm, VGPR_32:$src1);
+ field string Asm32 = "$vdst, $src0, $imm, $src1";
+ field bit HasExt = 0;
+}
+
+def VOP_MADMK_F16 : VOP_MADMK <f16>;
+def VOP_MADMK_F32 : VOP_MADMK <f32>;
+
+class VOP_MAC <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> {
+ let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1, VGPR_32:$src2);
+ let Ins64 = getIns64<Src0RC64, Src1RC64, RegisterOperand<VGPR_32>, 3,
+ HasModifiers, Src0Mod, Src1Mod, Src2Mod>.ret;
+ let InsDPP = (ins Src0ModDPP:$src0_modifiers, Src0DPP:$src0,
+ Src1ModDPP:$src1_modifiers, Src1DPP:$src1,
+ VGPR_32:$src2, // stub argument
+ dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
+ bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
+ let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0,
+ Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1,
+ VGPR_32:$src2, // stub argument
+ clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
+ src0_sel:$src0_sel, src1_sel:$src1_sel);
+ let Asm32 = getAsm32<1, 2, vt>.ret;
+ let AsmDPP = getAsmDPP<1, 2, HasModifiers, vt>.ret;
+ let AsmSDWA = getAsmSDWA<1, 2, HasModifiers, vt>.ret;
+ let HasSrc2 = 0;
+ let HasSrc2Mods = 0;
+ let HasExt = 1;
+}
+
+def VOP_MAC_F16 : VOP_MAC <f16> {
+ // FIXME: Move 'Asm64' definition to VOP_MAC, and use 'vt'. Currently it gives
+ // 'not a string initializer' error.
+ let Asm64 = getAsm64<1, 2, HasModifiers, f16>.ret;
+}
+
+def VOP_MAC_F32 : VOP_MAC <f32> {
+ // FIXME: Move 'Asm64' definition to VOP_MAC, and use 'vt'. Currently it gives
+ // 'not a string initializer' error.
+ let Asm64 = getAsm64<1, 2, HasModifiers, f32>.ret;
+}
+
+// Write out to vcc or arbitrary SGPR.
+def VOP2b_I32_I1_I32_I32 : VOPProfile<[i32, i32, i32, untyped]> {
+ let Asm32 = "$vdst, vcc, $src0, $src1";
+ let Asm64 = "$vdst, $sdst, $src0, $src1";
+ let AsmSDWA = "$vdst, vcc, $src0_modifiers, $src1_modifiers$clamp $dst_sel $dst_unused $src0_sel $src1_sel";
+ let AsmDPP = "$vdst, vcc, $src0, $src1 $dpp_ctrl$row_mask$bank_mask$bound_ctrl";
+ let Outs32 = (outs DstRC:$vdst);
+ let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
+}
+
+// Write out to vcc or arbitrary SGPR and read in from vcc or
+// arbitrary SGPR.
+def VOP2b_I32_I1_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> {
+ // We use VCSrc_b32 to exclude literal constants, even though the
+ // encoding normally allows them since the implicit VCC use means
+ // using one would always violate the constant bus
+ // restriction. SGPRs are still allowed because it should
+ // technically be possible to use VCC again as src0.
+ let Src0RC32 = VCSrc_b32;
+ let Asm32 = "$vdst, vcc, $src0, $src1, vcc";
+ let Asm64 = "$vdst, $sdst, $src0, $src1, $src2";
+ let AsmSDWA = "$vdst, vcc, $src0_modifiers, $src1_modifiers, vcc $clamp $dst_sel $dst_unused $src0_sel $src1_sel";
+ let AsmDPP = "$vdst, vcc, $src0, $src1, vcc $dpp_ctrl$row_mask$bank_mask$bound_ctrl";
+ let Outs32 = (outs DstRC:$vdst);
+ let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
+
+ // Suppress src2 implied by type since the 32-bit encoding uses an
+ // implicit VCC use.
+ let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1);
+
+ let InsSDWA = (ins Src0Mod:$src0_modifiers, Src0SDWA:$src0,
+ Src1Mod:$src1_modifiers, Src1SDWA:$src1,
+ clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused,
+ src0_sel:$src0_sel, src1_sel:$src1_sel);
+
+ let InsDPP = (ins Src0Mod:$src0_modifiers, Src0DPP:$src0,
+ Src1Mod:$src1_modifiers, Src1DPP:$src1,
+ dpp_ctrl:$dpp_ctrl, row_mask:$row_mask,
+ bank_mask:$bank_mask, bound_ctrl:$bound_ctrl);
+ let HasExt = 1;
+}
+
+// Read in from vcc or arbitrary SGPR
+def VOP2e_I32_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> {
+ let Src0RC32 = VCSrc_b32; // See comment in def VOP2b_I32_I1_I32_I32_I1 above.
+ let Asm32 = "$vdst, $src0, $src1, vcc";
+ let Asm64 = "$vdst, $src0, $src1, $src2";
+ let Outs32 = (outs DstRC:$vdst);
+ let Outs64 = (outs DstRC:$vdst);
+
+ // Suppress src2 implied by type since the 32-bit encoding uses an
+ // implicit VCC use.
+ let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1);
+}
+
+def VOP_READLANE : VOPProfile<[i32, i32, i32]> {
+ let Outs32 = (outs SReg_32:$vdst);
+ let Outs64 = Outs32;
+ let Ins32 = (ins VGPR_32:$src0, SCSrc_b32:$src1);
+ let Ins64 = Ins32;
+ let Asm32 = " $vdst, $src0, $src1";
+ let Asm64 = Asm32;
+}
+
+def VOP_WRITELANE : VOPProfile<[i32, i32, i32]> {
+ let Outs32 = (outs VGPR_32:$vdst);
+ let Outs64 = Outs32;
+ let Ins32 = (ins SReg_32:$src0, SCSrc_b32:$src1);
+ let Ins64 = Ins32;
+ let Asm32 = " $vdst, $src0, $src1";
+ let Asm64 = Asm32;
+}
+
+//===----------------------------------------------------------------------===//
+// VOP2 Instructions
+//===----------------------------------------------------------------------===//
+
+let SubtargetPredicate = isGCN in {
+
+defm V_CNDMASK_B32 : VOP2eInst <"v_cndmask_b32", VOP2e_I32_I32_I32_I1>;
+def V_MADMK_F32 : VOP2_Pseudo <"v_madmk_f32", VOP_MADMK_F32>;
+
+let isCommutable = 1 in {
+defm V_ADD_F32 : VOP2Inst <"v_add_f32", VOP_F32_F32_F32, fadd>;
+defm V_SUB_F32 : VOP2Inst <"v_sub_f32", VOP_F32_F32_F32, fsub>;
+defm V_SUBREV_F32 : VOP2Inst <"v_subrev_f32", VOP_F32_F32_F32, null_frag, "v_sub_f32">;
+defm V_MUL_LEGACY_F32 : VOP2Inst <"v_mul_legacy_f32", VOP_F32_F32_F32, AMDGPUfmul_legacy>;
+defm V_MUL_F32 : VOP2Inst <"v_mul_f32", VOP_F32_F32_F32, fmul>;
+defm V_MUL_I32_I24 : VOP2Inst <"v_mul_i32_i24", VOP_I32_I32_I32, AMDGPUmul_i24>;
+defm V_MUL_HI_I32_I24 : VOP2Inst <"v_mul_hi_i32_i24", VOP_I32_I32_I32, AMDGPUmulhi_i24>;
+defm V_MUL_U32_U24 : VOP2Inst <"v_mul_u32_u24", VOP_I32_I32_I32, AMDGPUmul_u24>;
+defm V_MUL_HI_U32_U24 : VOP2Inst <"v_mul_hi_u32_u24", VOP_I32_I32_I32, AMDGPUmulhi_u24>;
+defm V_MIN_F32 : VOP2Inst <"v_min_f32", VOP_F32_F32_F32, fminnum>;
+defm V_MAX_F32 : VOP2Inst <"v_max_f32", VOP_F32_F32_F32, fmaxnum>;
+defm V_MIN_I32 : VOP2Inst <"v_min_i32", VOP_I32_I32_I32>;
+defm V_MAX_I32 : VOP2Inst <"v_max_i32", VOP_I32_I32_I32>;
+defm V_MIN_U32 : VOP2Inst <"v_min_u32", VOP_I32_I32_I32>;
+defm V_MAX_U32 : VOP2Inst <"v_max_u32", VOP_I32_I32_I32>;
+defm V_LSHRREV_B32 : VOP2Inst <"v_lshrrev_b32", VOP_I32_I32_I32, null_frag, "v_lshr_b32">;
+defm V_ASHRREV_I32 : VOP2Inst <"v_ashrrev_i32", VOP_I32_I32_I32, null_frag, "v_ashr_i32">;
+defm V_LSHLREV_B32 : VOP2Inst <"v_lshlrev_b32", VOP_I32_I32_I32, null_frag, "v_lshl_b32">;
+defm V_AND_B32 : VOP2Inst <"v_and_b32", VOP_I32_I32_I32>;
+defm V_OR_B32 : VOP2Inst <"v_or_b32", VOP_I32_I32_I32>;
+defm V_XOR_B32 : VOP2Inst <"v_xor_b32", VOP_I32_I32_I32>;
+
+let Constraints = "$vdst = $src2", DisableEncoding="$src2",
+ isConvertibleToThreeAddress = 1 in {
+defm V_MAC_F32 : VOP2Inst <"v_mac_f32", VOP_MAC_F32>;
+}
+
+def V_MADAK_F32 : VOP2_Pseudo <"v_madak_f32", VOP_MADAK_F32>;
+
+// No patterns so that the scalar instructions are always selected.
+// The scalar versions will be replaced with vector when needed later.
+
+// V_ADD_I32, V_SUB_I32, and V_SUBREV_I32 where renamed to *_U32 in VI,
+// but the VI instructions behave the same as the SI versions.
+defm V_ADD_I32 : VOP2bInst <"v_add_i32", VOP2b_I32_I1_I32_I32>;
+defm V_SUB_I32 : VOP2bInst <"v_sub_i32", VOP2b_I32_I1_I32_I32>;
+defm V_SUBREV_I32 : VOP2bInst <"v_subrev_i32", VOP2b_I32_I1_I32_I32, null_frag, "v_sub_i32">;
+defm V_ADDC_U32 : VOP2bInst <"v_addc_u32", VOP2b_I32_I1_I32_I32_I1>;
+defm V_SUBB_U32 : VOP2bInst <"v_subb_u32", VOP2b_I32_I1_I32_I32_I1>;
+defm V_SUBBREV_U32 : VOP2bInst <"v_subbrev_u32", VOP2b_I32_I1_I32_I32_I1, null_frag, "v_subb_u32">;
+} // End isCommutable = 1
+
+// These are special and do not read the exec mask.
+let isConvergent = 1, Uses = []<Register> in {
+def V_READLANE_B32 : VOP2_Pseudo<"v_readlane_b32", VOP_READLANE,
+ [(set i32:$vdst, (int_amdgcn_readlane i32:$src0, i32:$src1))], "">;
+
+def V_WRITELANE_B32 : VOP2_Pseudo<"v_writelane_b32", VOP_WRITELANE, [], "">;
+} // End isConvergent = 1
+
+defm V_BFM_B32 : VOP2Inst <"v_bfm_b32", VOP_I32_I32_I32>;
+defm V_BCNT_U32_B32 : VOP2Inst <"v_bcnt_u32_b32", VOP_I32_I32_I32>;
+defm V_MBCNT_LO_U32_B32 : VOP2Inst <"v_mbcnt_lo_u32_b32", VOP_I32_I32_I32, int_amdgcn_mbcnt_lo>;
+defm V_MBCNT_HI_U32_B32 : VOP2Inst <"v_mbcnt_hi_u32_b32", VOP_I32_I32_I32, int_amdgcn_mbcnt_hi>;
+defm V_LDEXP_F32 : VOP2Inst <"v_ldexp_f32", VOP_F32_F32_I32, AMDGPUldexp>;
+defm V_CVT_PKACCUM_U8_F32 : VOP2Inst <"v_cvt_pkaccum_u8_f32", VOP_I32_F32_I32>; // TODO: set "Uses = dst"
+defm V_CVT_PKNORM_I16_F32 : VOP2Inst <"v_cvt_pknorm_i16_f32", VOP_I32_F32_F32>;
+defm V_CVT_PKNORM_U16_F32 : VOP2Inst <"v_cvt_pknorm_u16_f32", VOP_I32_F32_F32>;
+defm V_CVT_PKRTZ_F16_F32 : VOP2Inst <"v_cvt_pkrtz_f16_f32", VOP_I32_F32_F32, int_SI_packf16>;
+defm V_CVT_PK_U16_U32 : VOP2Inst <"v_cvt_pk_u16_u32", VOP_I32_I32_I32>;
+defm V_CVT_PK_I16_I32 : VOP2Inst <"v_cvt_pk_i16_i32", VOP_I32_I32_I32>;
+
+} // End SubtargetPredicate = isGCN
+
+
+// These instructions only exist on SI and CI
+let SubtargetPredicate = isSICI in {
+
+defm V_MIN_LEGACY_F32 : VOP2Inst <"v_min_legacy_f32", VOP_F32_F32_F32, AMDGPUfmin_legacy>;
+defm V_MAX_LEGACY_F32 : VOP2Inst <"v_max_legacy_f32", VOP_F32_F32_F32, AMDGPUfmax_legacy>;
+
+let isCommutable = 1 in {
+defm V_MAC_LEGACY_F32 : VOP2Inst <"v_mac_legacy_f32", VOP_F32_F32_F32>;
+defm V_LSHR_B32 : VOP2Inst <"v_lshr_b32", VOP_I32_I32_I32>;
+defm V_ASHR_I32 : VOP2Inst <"v_ashr_i32", VOP_I32_I32_I32>;
+defm V_LSHL_B32 : VOP2Inst <"v_lshl_b32", VOP_I32_I32_I32>;
+} // End isCommutable = 1
+
+} // End let SubtargetPredicate = SICI
+
+let SubtargetPredicate = isVI in {
+
+def V_MADMK_F16 : VOP2_Pseudo <"v_madmk_f16", VOP_MADMK_F16>;
+defm V_LSHLREV_B16 : VOP2Inst <"v_lshlrev_b16", VOP_I16_I16_I16>;
+defm V_LSHRREV_B16 : VOP2Inst <"v_lshrrev_b16", VOP_I16_I16_I16>;
+defm V_ASHRREV_I16 : VOP2Inst <"v_ashrrev_i16", VOP_I16_I16_I16>;
+defm V_LDEXP_F16 : VOP2Inst <"v_ldexp_f16", VOP_F16_F16_I32, AMDGPUldexp>;
+
+let isCommutable = 1 in {
+defm V_ADD_F16 : VOP2Inst <"v_add_f16", VOP_F16_F16_F16, fadd>;
+defm V_SUB_F16 : VOP2Inst <"v_sub_f16", VOP_F16_F16_F16, fsub>;
+defm V_SUBREV_F16 : VOP2Inst <"v_subrev_f16", VOP_F16_F16_F16, null_frag, "v_sub_f16">;
+defm V_MUL_F16 : VOP2Inst <"v_mul_f16", VOP_F16_F16_F16, fmul>;
+def V_MADAK_F16 : VOP2_Pseudo <"v_madak_f16", VOP_MADAK_F16>;
+defm V_ADD_U16 : VOP2Inst <"v_add_u16", VOP_I16_I16_I16>;
+defm V_SUB_U16 : VOP2Inst <"v_sub_u16" , VOP_I16_I16_I16>;
+defm V_SUBREV_U16 : VOP2Inst <"v_subrev_u16", VOP_I16_I16_I16, null_frag, "v_sub_u16">;
+defm V_MUL_LO_U16 : VOP2Inst <"v_mul_lo_u16", VOP_I16_I16_I16>;
+defm V_MAX_F16 : VOP2Inst <"v_max_f16", VOP_F16_F16_F16, fmaxnum>;
+defm V_MIN_F16 : VOP2Inst <"v_min_f16", VOP_F16_F16_F16, fminnum>;
+defm V_MAX_U16 : VOP2Inst <"v_max_u16", VOP_I16_I16_I16>;
+defm V_MAX_I16 : VOP2Inst <"v_max_i16", VOP_I16_I16_I16>;
+defm V_MIN_U16 : VOP2Inst <"v_min_u16", VOP_I16_I16_I16>;
+defm V_MIN_I16 : VOP2Inst <"v_min_i16", VOP_I16_I16_I16>;
+
+let Constraints = "$vdst = $src2", DisableEncoding="$src2",
+ isConvertibleToThreeAddress = 1 in {
+defm V_MAC_F16 : VOP2Inst <"v_mac_f16", VOP_MAC_F16>;
+}
+} // End isCommutable = 1
+
+} // End SubtargetPredicate = isVI
+
+// Note: 16-bit instructions produce a 0 result in the high 16-bits.
+multiclass Arithmetic_i16_Pats <SDPatternOperator op, Instruction inst> {
+
+def : Pat<
+ (op i16:$src0, i16:$src1),
+ (inst $src0, $src1)
+>;
+
+def : Pat<
+ (i32 (zext (op i16:$src0, i16:$src1))),
+ (inst $src0, $src1)
+>;
+
+def : Pat<
+ (i64 (zext (op i16:$src0, i16:$src1))),
+ (REG_SEQUENCE VReg_64,
+ (inst $src0, $src1), sub0,
+ (V_MOV_B32_e32 (i32 0)), sub1)
+>;
+
+}
+
+multiclass Bits_OpsRev_i16_Pats <SDPatternOperator op, Instruction inst> {
+
+def : Pat<
+ (op i16:$src0, i16:$src1),
+ (inst $src1, $src0)
+>;
+
+def : Pat<
+ (i32 (zext (op i16:$src0, i16:$src1))),
+ (inst $src1, $src0)
+>;
+
+
+def : Pat<
+ (i64 (zext (op i16:$src0, i16:$src1))),
+ (REG_SEQUENCE VReg_64,
+ (inst $src1, $src0), sub0,
+ (V_MOV_B32_e32 (i32 0)), sub1)
+>;
+}
+
+class ZExt_i16_i1_Pat <SDNode ext> : Pat <
+ (i16 (ext i1:$src)),
+ (V_CNDMASK_B32_e64 (i32 0), (i32 1), $src)
+>;
+
+let Predicates = [isVI] in {
+
+defm : Arithmetic_i16_Pats<add, V_ADD_U16_e64>;
+defm : Arithmetic_i16_Pats<mul, V_MUL_LO_U16_e64>;
+defm : Arithmetic_i16_Pats<sub, V_SUB_U16_e64>;
+defm : Arithmetic_i16_Pats<smin, V_MIN_I16_e64>;
+defm : Arithmetic_i16_Pats<smax, V_MAX_I16_e64>;
+defm : Arithmetic_i16_Pats<umin, V_MIN_U16_e64>;
+defm : Arithmetic_i16_Pats<umax, V_MAX_U16_e64>;
+
+def : Pat <
+ (and i16:$src0, i16:$src1),
+ (V_AND_B32_e64 $src0, $src1)
+>;
+
+def : Pat <
+ (or i16:$src0, i16:$src1),
+ (V_OR_B32_e64 $src0, $src1)
+>;
+
+def : Pat <
+ (xor i16:$src0, i16:$src1),
+ (V_XOR_B32_e64 $src0, $src1)
+>;
+
+defm : Bits_OpsRev_i16_Pats<shl, V_LSHLREV_B16_e64>;
+defm : Bits_OpsRev_i16_Pats<srl, V_LSHRREV_B16_e64>;
+defm : Bits_OpsRev_i16_Pats<sra, V_ASHRREV_I16_e64>;
+
+def : ZExt_i16_i1_Pat<zext>;
+def : ZExt_i16_i1_Pat<anyext>;
+
+def : Pat <
+ (i16 (sext i1:$src)),
+ (V_CNDMASK_B32_e64 (i32 0), (i32 -1), $src)
+>;
+
+} // End Predicates = [isVI]
+
+//===----------------------------------------------------------------------===//
+// SI
+//===----------------------------------------------------------------------===//
+
+let AssemblerPredicates = [isSICI], DecoderNamespace = "SICI" in {
+
+multiclass VOP2_Real_si <bits<6> op> {
+ def _si :
+ VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.SI>,
+ VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP2_Real_MADK_si <bits<6> op> {
+ def _si : VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.SI>,
+ VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP2_Real_e32_si <bits<6> op> {
+ def _e32_si :
+ VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.SI>,
+ VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>;
+}
+
+multiclass VOP2_Real_e32e64_si <bits<6> op> : VOP2_Real_e32_si<op> {
+ def _e64_si :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
+ VOP3e_si <{1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+}
+
+multiclass VOP2be_Real_e32e64_si <bits<6> op> : VOP2_Real_e32_si<op> {
+ def _e64_si :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
+ VOP3be_si <{1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+}
+
+} // End AssemblerPredicates = [isSICI], DecoderNamespace = "SICI"
+
+defm V_CNDMASK_B32 : VOP2_Real_e32e64_si <0x0>;
+defm V_ADD_F32 : VOP2_Real_e32e64_si <0x3>;
+defm V_SUB_F32 : VOP2_Real_e32e64_si <0x4>;
+defm V_SUBREV_F32 : VOP2_Real_e32e64_si <0x5>;
+defm V_MUL_LEGACY_F32 : VOP2_Real_e32e64_si <0x7>;
+defm V_MUL_F32 : VOP2_Real_e32e64_si <0x8>;
+defm V_MUL_I32_I24 : VOP2_Real_e32e64_si <0x9>;
+defm V_MUL_HI_I32_I24 : VOP2_Real_e32e64_si <0xa>;
+defm V_MUL_U32_U24 : VOP2_Real_e32e64_si <0xb>;
+defm V_MUL_HI_U32_U24 : VOP2_Real_e32e64_si <0xc>;
+defm V_MIN_F32 : VOP2_Real_e32e64_si <0xf>;
+defm V_MAX_F32 : VOP2_Real_e32e64_si <0x10>;
+defm V_MIN_I32 : VOP2_Real_e32e64_si <0x11>;
+defm V_MAX_I32 : VOP2_Real_e32e64_si <0x12>;
+defm V_MIN_U32 : VOP2_Real_e32e64_si <0x13>;
+defm V_MAX_U32 : VOP2_Real_e32e64_si <0x14>;
+defm V_LSHRREV_B32 : VOP2_Real_e32e64_si <0x16>;
+defm V_ASHRREV_I32 : VOP2_Real_e32e64_si <0x18>;
+defm V_LSHLREV_B32 : VOP2_Real_e32e64_si <0x1a>;
+defm V_AND_B32 : VOP2_Real_e32e64_si <0x1b>;
+defm V_OR_B32 : VOP2_Real_e32e64_si <0x1c>;
+defm V_XOR_B32 : VOP2_Real_e32e64_si <0x1d>;
+defm V_MAC_F32 : VOP2_Real_e32e64_si <0x1f>;
+defm V_MADMK_F32 : VOP2_Real_MADK_si <0x20>;
+defm V_MADAK_F32 : VOP2_Real_MADK_si <0x21>;
+defm V_ADD_I32 : VOP2be_Real_e32e64_si <0x25>;
+defm V_SUB_I32 : VOP2be_Real_e32e64_si <0x26>;
+defm V_SUBREV_I32 : VOP2be_Real_e32e64_si <0x27>;
+defm V_ADDC_U32 : VOP2be_Real_e32e64_si <0x28>;
+defm V_SUBB_U32 : VOP2be_Real_e32e64_si <0x29>;
+defm V_SUBBREV_U32 : VOP2be_Real_e32e64_si <0x2a>;
+
+defm V_READLANE_B32 : VOP2_Real_si <0x01>;
+defm V_WRITELANE_B32 : VOP2_Real_si <0x02>;
+
+defm V_MAC_LEGACY_F32 : VOP2_Real_e32e64_si <0x6>;
+defm V_MIN_LEGACY_F32 : VOP2_Real_e32e64_si <0xd>;
+defm V_MAX_LEGACY_F32 : VOP2_Real_e32e64_si <0xe>;
+defm V_LSHR_B32 : VOP2_Real_e32e64_si <0x15>;
+defm V_ASHR_I32 : VOP2_Real_e32e64_si <0x17>;
+defm V_LSHL_B32 : VOP2_Real_e32e64_si <0x19>;
+
+defm V_BFM_B32 : VOP2_Real_e32e64_si <0x1e>;
+defm V_BCNT_U32_B32 : VOP2_Real_e32e64_si <0x22>;
+defm V_MBCNT_LO_U32_B32 : VOP2_Real_e32e64_si <0x23>;
+defm V_MBCNT_HI_U32_B32 : VOP2_Real_e32e64_si <0x24>;
+defm V_LDEXP_F32 : VOP2_Real_e32e64_si <0x2b>;
+defm V_CVT_PKACCUM_U8_F32 : VOP2_Real_e32e64_si <0x2c>;
+defm V_CVT_PKNORM_I16_F32 : VOP2_Real_e32e64_si <0x2d>;
+defm V_CVT_PKNORM_U16_F32 : VOP2_Real_e32e64_si <0x2e>;
+defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_e32e64_si <0x2f>;
+defm V_CVT_PK_U16_U32 : VOP2_Real_e32e64_si <0x30>;
+defm V_CVT_PK_I16_I32 : VOP2_Real_e32e64_si <0x31>;
+
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+class VOP2_DPP <bits<6> op, VOP2_Pseudo ps, VOPProfile P = ps.Pfl> :
+ VOP_DPP <ps.OpName, P> {
+ let Defs = ps.Defs;
+ let Uses = ps.Uses;
+ let SchedRW = ps.SchedRW;
+ let hasSideEffects = ps.hasSideEffects;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ bits<8> vdst;
+ bits<8> src1;
+ let Inst{8-0} = 0xfa; //dpp
+ let Inst{16-9} = !if(P.HasSrc1, src1{7-0}, 0);
+ let Inst{24-17} = !if(P.EmitDst, vdst{7-0}, 0);
+ let Inst{30-25} = op;
+ let Inst{31} = 0x0; //encoding
+}
+
+let AssemblerPredicates = [isVI], DecoderNamespace = "VI" in {
+
+multiclass VOP32_Real_vi <bits<10> op> {
+ def _vi :
+ VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.VI>,
+ VOP3e_vi<op, !cast<VOP2_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP2_Real_MADK_vi <bits<6> op> {
+ def _vi : VOP2_Real<!cast<VOP2_Pseudo>(NAME), SIEncodingFamily.VI>,
+ VOP2_MADKe<op{5-0}, !cast<VOP2_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP2_Real_e32_vi <bits<6> op> {
+ def _e32_vi :
+ VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.VI>,
+ VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>;
+}
+
+multiclass VOP2_Real_e64_vi <bits<10> op> {
+ def _e64_vi :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>,
+ VOP3e_vi <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+}
+
+multiclass Base_VOP2be_Real_e32e64_vi <bits<6> op> : VOP2_Real_e32_vi<op> {
+ def _e64_vi :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>,
+ VOP3be_vi <{0, 1, 0, 0, op{5-0}}, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>;
+}
+
+multiclass Base_VOP2_Real_e32e64_vi <bits<6> op> :
+ VOP2_Real_e32_vi<op>,
+ VOP2_Real_e64_vi<{0, 1, 0, 0, op{5-0}}>;
+
+} // End AssemblerPredicates = [isVI], DecoderNamespace = "VI"
+
+multiclass VOP2_SDWA_Real <bits<6> op> {
+ def _sdwa_vi :
+ VOP_SDWA_Real <!cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa")>,
+ VOP2_SDWAe <op{5-0}, !cast<VOP2_SDWA_Pseudo>(NAME#"_sdwa").Pfl>;
+}
+
+multiclass VOP2be_Real_e32e64_vi <bits<6> op> :
+ Base_VOP2be_Real_e32e64_vi<op>, VOP2_SDWA_Real<op> {
+ // For now left dpp only for asm/dasm
+ // TODO: add corresponding pseudo
+ def _dpp : VOP2_DPP<op, !cast<VOP2_Pseudo>(NAME#"_e32")>;
+}
+
+multiclass VOP2_Real_e32e64_vi <bits<6> op> :
+ Base_VOP2_Real_e32e64_vi<op>, VOP2_SDWA_Real<op> {
+ // For now left dpp only for asm/dasm
+ // TODO: add corresponding pseudo
+ def _dpp : VOP2_DPP<op, !cast<VOP2_Pseudo>(NAME#"_e32")>;
+}
+
+defm V_CNDMASK_B32 : Base_VOP2_Real_e32e64_vi <0x0>;
+defm V_ADD_F32 : VOP2_Real_e32e64_vi <0x1>;
+defm V_SUB_F32 : VOP2_Real_e32e64_vi <0x2>;
+defm V_SUBREV_F32 : VOP2_Real_e32e64_vi <0x3>;
+defm V_MUL_LEGACY_F32 : VOP2_Real_e32e64_vi <0x4>;
+defm V_MUL_F32 : VOP2_Real_e32e64_vi <0x5>;
+defm V_MUL_I32_I24 : VOP2_Real_e32e64_vi <0x6>;
+defm V_MUL_HI_I32_I24 : VOP2_Real_e32e64_vi <0x7>;
+defm V_MUL_U32_U24 : VOP2_Real_e32e64_vi <0x8>;
+defm V_MUL_HI_U32_U24 : VOP2_Real_e32e64_vi <0x9>;
+defm V_MIN_F32 : VOP2_Real_e32e64_vi <0xa>;
+defm V_MAX_F32 : VOP2_Real_e32e64_vi <0xb>;
+defm V_MIN_I32 : VOP2_Real_e32e64_vi <0xc>;
+defm V_MAX_I32 : VOP2_Real_e32e64_vi <0xd>;
+defm V_MIN_U32 : VOP2_Real_e32e64_vi <0xe>;
+defm V_MAX_U32 : VOP2_Real_e32e64_vi <0xf>;
+defm V_LSHRREV_B32 : VOP2_Real_e32e64_vi <0x10>;
+defm V_ASHRREV_I32 : VOP2_Real_e32e64_vi <0x11>;
+defm V_LSHLREV_B32 : VOP2_Real_e32e64_vi <0x12>;
+defm V_AND_B32 : VOP2_Real_e32e64_vi <0x13>;
+defm V_OR_B32 : VOP2_Real_e32e64_vi <0x14>;
+defm V_XOR_B32 : VOP2_Real_e32e64_vi <0x15>;
+defm V_MAC_F32 : VOP2_Real_e32e64_vi <0x16>;
+defm V_MADMK_F32 : VOP2_Real_MADK_vi <0x17>;
+defm V_MADAK_F32 : VOP2_Real_MADK_vi <0x18>;
+defm V_ADD_I32 : VOP2be_Real_e32e64_vi <0x19>;
+defm V_SUB_I32 : VOP2be_Real_e32e64_vi <0x1a>;
+defm V_SUBREV_I32 : VOP2be_Real_e32e64_vi <0x1b>;
+defm V_ADDC_U32 : VOP2be_Real_e32e64_vi <0x1c>;
+defm V_SUBB_U32 : VOP2be_Real_e32e64_vi <0x1d>;
+defm V_SUBBREV_U32 : VOP2be_Real_e32e64_vi <0x1e>;
+
+defm V_READLANE_B32 : VOP32_Real_vi <0x289>;
+defm V_WRITELANE_B32 : VOP32_Real_vi <0x28a>;
+
+defm V_BFM_B32 : VOP2_Real_e64_vi <0x293>;
+defm V_BCNT_U32_B32 : VOP2_Real_e64_vi <0x28b>;
+defm V_MBCNT_LO_U32_B32 : VOP2_Real_e64_vi <0x28c>;
+defm V_MBCNT_HI_U32_B32 : VOP2_Real_e64_vi <0x28d>;
+defm V_LDEXP_F32 : VOP2_Real_e64_vi <0x288>;
+defm V_CVT_PKACCUM_U8_F32 : VOP2_Real_e64_vi <0x1f0>;
+defm V_CVT_PKNORM_I16_F32 : VOP2_Real_e64_vi <0x294>;
+defm V_CVT_PKNORM_U16_F32 : VOP2_Real_e64_vi <0x295>;
+defm V_CVT_PKRTZ_F16_F32 : VOP2_Real_e64_vi <0x296>;
+defm V_CVT_PK_U16_U32 : VOP2_Real_e64_vi <0x297>;
+defm V_CVT_PK_I16_I32 : VOP2_Real_e64_vi <0x298>;
+
+defm V_ADD_F16 : VOP2_Real_e32e64_vi <0x1f>;
+defm V_SUB_F16 : VOP2_Real_e32e64_vi <0x20>;
+defm V_SUBREV_F16 : VOP2_Real_e32e64_vi <0x21>;
+defm V_MUL_F16 : VOP2_Real_e32e64_vi <0x22>;
+defm V_MAC_F16 : VOP2_Real_e32e64_vi <0x23>;
+defm V_MADMK_F16 : VOP2_Real_MADK_vi <0x24>;
+defm V_MADAK_F16 : VOP2_Real_MADK_vi <0x25>;
+defm V_ADD_U16 : VOP2_Real_e32e64_vi <0x26>;
+defm V_SUB_U16 : VOP2_Real_e32e64_vi <0x27>;
+defm V_SUBREV_U16 : VOP2_Real_e32e64_vi <0x28>;
+defm V_MUL_LO_U16 : VOP2_Real_e32e64_vi <0x29>;
+defm V_LSHLREV_B16 : VOP2_Real_e32e64_vi <0x2a>;
+defm V_LSHRREV_B16 : VOP2_Real_e32e64_vi <0x2b>;
+defm V_ASHRREV_I16 : VOP2_Real_e32e64_vi <0x2c>;
+defm V_MAX_F16 : VOP2_Real_e32e64_vi <0x2d>;
+defm V_MIN_F16 : VOP2_Real_e32e64_vi <0x2e>;
+defm V_MAX_U16 : VOP2_Real_e32e64_vi <0x2f>;
+defm V_MAX_I16 : VOP2_Real_e32e64_vi <0x30>;
+defm V_MIN_U16 : VOP2_Real_e32e64_vi <0x31>;
+defm V_MIN_I16 : VOP2_Real_e32e64_vi <0x32>;
+defm V_LDEXP_F16 : VOP2_Real_e32e64_vi <0x33>;
+
+let SubtargetPredicate = isVI in {
+
+// Aliases to simplify matching of floating-point instructions that
+// are VOP2 on SI and VOP3 on VI.
+class SI2_VI3Alias <string name, Instruction inst> : InstAlias <
+ name#" $dst, $src0, $src1",
+ (inst VGPR_32:$dst, 0, VCSrc_f32:$src0, 0, VCSrc_f32:$src1, 0, 0)
+>, PredicateControl {
+ let UseInstAsmMatchConverter = 0;
+ let AsmVariantName = AMDGPUAsmVariants.VOP3;
+}
+
+def : SI2_VI3Alias <"v_ldexp_f32", V_LDEXP_F32_e64_vi>;
+def : SI2_VI3Alias <"v_cvt_pkaccum_u8_f32", V_CVT_PKACCUM_U8_F32_e64_vi>;
+def : SI2_VI3Alias <"v_cvt_pknorm_i16_f32", V_CVT_PKNORM_I16_F32_e64_vi>;
+def : SI2_VI3Alias <"v_cvt_pknorm_u16_f32", V_CVT_PKNORM_U16_F32_e64_vi>;
+def : SI2_VI3Alias <"v_cvt_pkrtz_f16_f32", V_CVT_PKRTZ_F16_F32_e64_vi>;
+
+} // End SubtargetPredicate = isVI
diff --git a/contrib/llvm/lib/Target/AMDGPU/VOP3Instructions.td b/contrib/llvm/lib/Target/AMDGPU/VOP3Instructions.td
new file mode 100644
index 0000000..c2a4d4b
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/VOP3Instructions.td
@@ -0,0 +1,451 @@
+//===-- VOP3Instructions.td - Vector Instruction Defintions ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// VOP3 Classes
+//===----------------------------------------------------------------------===//
+
+class getVOP3ModPat<VOPProfile P, SDPatternOperator node> {
+ list<dag> ret3 = [(set P.DstVT:$vdst,
+ (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)),
+ (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
+ (P.Src2VT (VOP3Mods P.Src2VT:$src2, i32:$src2_modifiers))))];
+
+ list<dag> ret2 = [(set P.DstVT:$vdst,
+ (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)),
+ (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers))))];
+
+ list<dag> ret1 = [(set P.DstVT:$vdst,
+ (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod))))];
+
+ list<dag> ret = !if(!eq(P.NumSrcArgs, 3), ret3,
+ !if(!eq(P.NumSrcArgs, 2), ret2,
+ ret1));
+}
+
+class getVOP3Pat<VOPProfile P, SDPatternOperator node> {
+ list<dag> ret3 = [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1, P.Src2VT:$src2))];
+ list<dag> ret2 = [(set P.DstVT:$vdst, (node P.Src0VT:$src0, P.Src1VT:$src1))];
+ list<dag> ret1 = [(set P.DstVT:$vdst, (node P.Src0VT:$src0))];
+ list<dag> ret = !if(!eq(P.NumSrcArgs, 3), ret3,
+ !if(!eq(P.NumSrcArgs, 2), ret2,
+ ret1));
+}
+
+class VOP3Inst<string OpName, VOPProfile P, SDPatternOperator node = null_frag, bit VOP3Only = 0> :
+ VOP3_Pseudo<OpName, P,
+ !if(P.HasModifiers, getVOP3ModPat<P, node>.ret, getVOP3Pat<P, node>.ret),
+ VOP3Only>;
+
+// Special case for v_div_fmas_{f32|f64}, since it seems to be the
+// only VOP instruction that implicitly reads VCC.
+let Asm64 = " $vdst, $src0_modifiers, $src1_modifiers, $src2_modifiers$clamp$omod" in {
+def VOP_F32_F32_F32_F32_VCC : VOPProfile<[f32, f32, f32, f32]> {
+ let Outs64 = (outs DstRC.RegClass:$vdst);
+}
+def VOP_F64_F64_F64_F64_VCC : VOPProfile<[f64, f64, f64, f64]> {
+ let Outs64 = (outs DstRC.RegClass:$vdst);
+}
+}
+
+class getVOP3VCC<VOPProfile P, SDPatternOperator node> {
+ list<dag> ret =
+ [(set P.DstVT:$vdst,
+ (node (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)),
+ (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
+ (P.Src2VT (VOP3Mods P.Src2VT:$src2, i32:$src2_modifiers)),
+ (i1 VCC)))];
+}
+
+class VOP3_Profile<VOPProfile P> : VOPProfile<P.ArgVT> {
+ // FIXME: Hack to stop printing _e64
+ let Outs64 = (outs DstRC.RegClass:$vdst);
+ let Asm64 = " " # P.Asm64;
+}
+
+class VOP3b_Profile<ValueType vt> : VOPProfile<[vt, vt, vt, vt]> {
+ // v_div_scale_{f32|f64} do not support input modifiers.
+ let HasModifiers = 0;
+ let Outs64 = (outs DstRC:$vdst, SReg_64:$sdst);
+ let Asm64 = " $vdst, $sdst, $src0, $src1, $src2";
+}
+
+def VOP3b_F32_I1_F32_F32_F32 : VOP3b_Profile<f32> {
+ // FIXME: Hack to stop printing _e64
+ let DstRC = RegisterOperand<VGPR_32>;
+}
+
+def VOP3b_F64_I1_F64_F64_F64 : VOP3b_Profile<f64> {
+ // FIXME: Hack to stop printing _e64
+ let DstRC = RegisterOperand<VReg_64>;
+}
+
+//===----------------------------------------------------------------------===//
+// VOP3 Instructions
+//===----------------------------------------------------------------------===//
+
+let isCommutable = 1 in {
+
+def V_MAD_LEGACY_F32 : VOP3Inst <"v_mad_legacy_f32", VOP3_Profile<VOP_F32_F32_F32_F32>>;
+def V_MAD_F32 : VOP3Inst <"v_mad_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, fmad>;
+def V_MAD_I32_I24 : VOP3Inst <"v_mad_i32_i24", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUmad_i24>;
+def V_MAD_U32_U24 : VOP3Inst <"v_mad_u32_u24", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUmad_u24>;
+def V_FMA_F32 : VOP3Inst <"v_fma_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, fma>;
+def V_FMA_F64 : VOP3Inst <"v_fma_f64", VOP3_Profile<VOP_F64_F64_F64_F64>, fma>;
+def V_LERP_U8 : VOP3Inst <"v_lerp_u8", VOP3_Profile<VOP_I32_I32_I32_I32>, int_amdgcn_lerp>;
+
+let SchedRW = [WriteDoubleAdd] in {
+def V_ADD_F64 : VOP3Inst <"v_add_f64", VOP3_Profile<VOP_F64_F64_F64>, fadd, 1>;
+def V_MUL_F64 : VOP3Inst <"v_mul_f64", VOP3_Profile<VOP_F64_F64_F64>, fmul, 1>;
+def V_MIN_F64 : VOP3Inst <"v_min_f64", VOP3_Profile<VOP_F64_F64_F64>, fminnum, 1>;
+def V_MAX_F64 : VOP3Inst <"v_max_f64", VOP3_Profile<VOP_F64_F64_F64>, fmaxnum, 1>;
+} // End SchedRW = [WriteDoubleAdd]
+
+let SchedRW = [WriteQuarterRate32] in {
+def V_MUL_LO_U32 : VOP3Inst <"v_mul_lo_u32", VOP3_Profile<VOP_I32_I32_I32>>;
+def V_MUL_HI_U32 : VOP3Inst <"v_mul_hi_u32", VOP3_Profile<VOP_I32_I32_I32>, mulhu>;
+def V_MUL_LO_I32 : VOP3Inst <"v_mul_lo_i32", VOP3_Profile<VOP_I32_I32_I32>>;
+def V_MUL_HI_I32 : VOP3Inst <"v_mul_hi_i32", VOP3_Profile<VOP_I32_I32_I32>, mulhs>;
+} // End SchedRW = [WriteQuarterRate32]
+
+let Uses = [VCC, EXEC] in {
+// v_div_fmas_f32:
+// result = src0 * src1 + src2
+// if (vcc)
+// result *= 2^32
+//
+def V_DIV_FMAS_F32 : VOP3_Pseudo <"v_div_fmas_f32", VOP_F32_F32_F32_F32_VCC,
+ getVOP3VCC<VOP_F32_F32_F32_F32_VCC, AMDGPUdiv_fmas>.ret> {
+ let SchedRW = [WriteFloatFMA];
+}
+// v_div_fmas_f64:
+// result = src0 * src1 + src2
+// if (vcc)
+// result *= 2^64
+//
+def V_DIV_FMAS_F64 : VOP3_Pseudo <"v_div_fmas_f64", VOP_F64_F64_F64_F64_VCC,
+ getVOP3VCC<VOP_F64_F64_F64_F64_VCC, AMDGPUdiv_fmas>.ret> {
+ let SchedRW = [WriteDouble];
+}
+} // End Uses = [VCC, EXEC]
+
+} // End isCommutable = 1
+
+def V_CUBEID_F32 : VOP3Inst <"v_cubeid_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, int_amdgcn_cubeid>;
+def V_CUBESC_F32 : VOP3Inst <"v_cubesc_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, int_amdgcn_cubesc>;
+def V_CUBETC_F32 : VOP3Inst <"v_cubetc_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, int_amdgcn_cubetc>;
+def V_CUBEMA_F32 : VOP3Inst <"v_cubema_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, int_amdgcn_cubema>;
+def V_BFE_U32 : VOP3Inst <"v_bfe_u32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUbfe_u32>;
+def V_BFE_I32 : VOP3Inst <"v_bfe_i32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUbfe_i32>;
+def V_BFI_B32 : VOP3Inst <"v_bfi_b32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUbfi>;
+def V_ALIGNBIT_B32 : VOP3Inst <"v_alignbit_b32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
+def V_ALIGNBYTE_B32 : VOP3Inst <"v_alignbyte_b32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
+def V_MIN3_F32 : VOP3Inst <"v_min3_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUfmin3>;
+def V_MIN3_I32 : VOP3Inst <"v_min3_i32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUsmin3>;
+def V_MIN3_U32 : VOP3Inst <"v_min3_u32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUumin3>;
+def V_MAX3_F32 : VOP3Inst <"v_max3_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUfmax3>;
+def V_MAX3_I32 : VOP3Inst <"v_max3_i32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUsmax3>;
+def V_MAX3_U32 : VOP3Inst <"v_max3_u32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUumax3>;
+def V_MED3_F32 : VOP3Inst <"v_med3_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUfmed3>;
+def V_MED3_I32 : VOP3Inst <"v_med3_i32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUsmed3>;
+def V_MED3_U32 : VOP3Inst <"v_med3_u32", VOP3_Profile<VOP_I32_I32_I32_I32>, AMDGPUumed3>;
+def V_SAD_U8 : VOP3Inst <"v_sad_u8", VOP3_Profile<VOP_I32_I32_I32_I32>, int_amdgcn_sad_u8>;
+def V_SAD_HI_U8 : VOP3Inst <"v_sad_hi_u8", VOP3_Profile<VOP_I32_I32_I32_I32>, int_amdgcn_sad_hi_u8>;
+def V_SAD_U16 : VOP3Inst <"v_sad_u16", VOP3_Profile<VOP_I32_I32_I32_I32>, int_amdgcn_sad_u16>;
+def V_SAD_U32 : VOP3Inst <"v_sad_u32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
+def V_CVT_PK_U8_F32 : VOP3Inst<"v_cvt_pk_u8_f32", VOP3_Profile<VOP_I32_F32_I32_I32>, int_amdgcn_cvt_pk_u8_f32>;
+def V_DIV_FIXUP_F32 : VOP3Inst <"v_div_fixup_f32", VOP3_Profile<VOP_F32_F32_F32_F32>, AMDGPUdiv_fixup>;
+
+let SchedRW = [WriteDoubleAdd] in {
+def V_DIV_FIXUP_F64 : VOP3Inst <"v_div_fixup_f64", VOP3_Profile<VOP_F64_F64_F64_F64>, AMDGPUdiv_fixup>;
+def V_LDEXP_F64 : VOP3Inst <"v_ldexp_f64", VOP3_Profile<VOP_F64_F64_I32>, AMDGPUldexp, 1>;
+} // End SchedRW = [WriteDoubleAdd]
+
+def V_DIV_SCALE_F32 : VOP3_Pseudo <"v_div_scale_f32", VOP3b_F32_I1_F32_F32_F32, [], 1> {
+ let SchedRW = [WriteFloatFMA, WriteSALU];
+ let hasExtraSrcRegAllocReq = 1;
+ let AsmMatchConverter = "";
+}
+
+// Double precision division pre-scale.
+def V_DIV_SCALE_F64 : VOP3_Pseudo <"v_div_scale_f64", VOP3b_F64_I1_F64_F64_F64, [], 1> {
+ let SchedRW = [WriteDouble, WriteSALU];
+ let hasExtraSrcRegAllocReq = 1;
+ let AsmMatchConverter = "";
+}
+
+def V_MSAD_U8 : VOP3Inst <"v_msad_u8", VOP3_Profile<VOP_I32_I32_I32_I32>, int_amdgcn_msad_u8>;
+def V_MQSAD_PK_U16_U8 : VOP3Inst <"v_mqsad_pk_u16_u8", VOP3_Profile<VOP_I64_I64_I32_I64>, int_amdgcn_mqsad_pk_u16_u8>;
+
+def V_TRIG_PREOP_F64 : VOP3Inst <"v_trig_preop_f64", VOP3_Profile<VOP_F64_F64_I32>, AMDGPUtrig_preop> {
+ let SchedRW = [WriteDouble];
+}
+
+// These instructions only exist on SI and CI
+let SubtargetPredicate = isSICI in {
+def V_LSHL_B64 : VOP3Inst <"v_lshl_b64", VOP3_Profile<VOP_I64_I64_I32>>;
+def V_LSHR_B64 : VOP3Inst <"v_lshr_b64", VOP3_Profile<VOP_I64_I64_I32>>;
+def V_ASHR_I64 : VOP3Inst <"v_ashr_i64", VOP3_Profile<VOP_I64_I64_I32>>;
+def V_MULLIT_F32 : VOP3Inst <"v_mullit_f32", VOP3_Profile<VOP_F32_F32_F32_F32>>;
+} // End SubtargetPredicate = isSICI
+
+let SubtargetPredicate = isVI in {
+def V_LSHLREV_B64 : VOP3Inst <"v_lshlrev_b64", VOP3_Profile<VOP_I64_I32_I64>>;
+def V_LSHRREV_B64 : VOP3Inst <"v_lshrrev_b64", VOP3_Profile<VOP_I64_I32_I64>>;
+def V_ASHRREV_I64 : VOP3Inst <"v_ashrrev_i64", VOP3_Profile<VOP_I64_I32_I64>>;
+} // End SubtargetPredicate = isVI
+
+
+let SubtargetPredicate = isCIVI in {
+
+def V_MQSAD_U16_U8 : VOP3Inst <"v_mqsad_u16_u8", VOP3_Profile<VOP_I32_I32_I32>>;
+def V_QSAD_PK_U16_U8 : VOP3Inst <"v_qsad_pk_u16_u8", VOP3_Profile<VOP_I64_I64_I32_I64>, int_amdgcn_qsad_pk_u16_u8>;
+def V_MQSAD_U32_U8 : VOP3Inst <"v_mqsad_u32_u8", VOP3_Profile<VOP_V4I32_I64_I32_V4I32>, int_amdgcn_mqsad_u32_u8>;
+
+let isCommutable = 1 in {
+def V_MAD_U64_U32 : VOP3Inst <"v_mad_u64_u32", VOP3_Profile<VOP_I64_I32_I32_I64>>;
+
+// XXX - Does this set VCC?
+def V_MAD_I64_I32 : VOP3Inst <"v_mad_i64_i32", VOP3_Profile<VOP_I64_I32_I32_I64>>;
+} // End isCommutable = 1
+
+} // End SubtargetPredicate = isCIVI
+
+
+let SubtargetPredicate = isVI in {
+
+let isCommutable = 1 in {
+
+def V_DIV_FIXUP_F16 : VOP3Inst <"v_div_fixup_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, AMDGPUdiv_fixup>;
+def V_FMA_F16 : VOP3Inst <"v_fma_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, fma>;
+def V_INTERP_P1LL_F16 : VOP3Inst <"v_interp_p1ll_f16", VOP3_Profile<VOP_F32_F32_F16>>;
+def V_INTERP_P1LV_F16 : VOP3Inst <"v_interp_p1lv_f16", VOP3_Profile<VOP_F32_F32_F16_F16>>;
+def V_INTERP_P2_F16 : VOP3Inst <"v_interp_p2_f16", VOP3_Profile<VOP_F16_F32_F16_F32>>;
+def V_MAD_F16 : VOP3Inst <"v_mad_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, fmad>;
+
+def V_MAD_U16 : VOP3Inst <"v_mad_u16", VOP3_Profile<VOP_I16_I16_I16_I16>>;
+def V_MAD_I16 : VOP3Inst <"v_mad_i16", VOP3_Profile<VOP_I16_I16_I16_I16>>;
+
+} // End isCommutable = 1
+
+} // End SubtargetPredicate = isVI
+
+let Predicates = [isVI] in {
+
+multiclass Tenary_i16_Pats <SDPatternOperator op1, SDPatternOperator op2,
+ Instruction inst, SDPatternOperator op3> {
+def : Pat<
+ (op2 (op1 i16:$src0, i16:$src1), i16:$src2),
+ (inst i16:$src0, i16:$src1, i16:$src2)
+>;
+
+def : Pat<
+ (i32 (op3 (op2 (op1 i16:$src0, i16:$src1), i16:$src2))),
+ (inst i16:$src0, i16:$src1, i16:$src2)
+>;
+
+def : Pat<
+ (i64 (op3 (op2 (op1 i16:$src0, i16:$src1), i16:$src2))),
+ (REG_SEQUENCE VReg_64,
+ (inst i16:$src0, i16:$src1, i16:$src2), sub0,
+ (V_MOV_B32_e32 (i32 0)), sub1)
+>;
+}
+
+defm: Tenary_i16_Pats<mul, add, V_MAD_U16, zext>;
+defm: Tenary_i16_Pats<mul, add, V_MAD_I16, sext>;
+
+} // End Predicates = [isVI]
+
+
+//===----------------------------------------------------------------------===//
+// Target
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SI
+//===----------------------------------------------------------------------===//
+
+let AssemblerPredicates = [isSICI], DecoderNamespace = "SICI" in {
+
+multiclass VOP3_Real_si<bits<9> op> {
+ def _si : VOP3_Real<!cast<VOP3_Pseudo>(NAME), SIEncodingFamily.SI>,
+ VOP3e_si <op, !cast<VOP3_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP3be_Real_si<bits<9> op> {
+ def _si : VOP3_Real<!cast<VOP3_Pseudo>(NAME), SIEncodingFamily.SI>,
+ VOP3be_si <op, !cast<VOP3_Pseudo>(NAME).Pfl>;
+}
+
+} // End AssemblerPredicates = [isSICI], DecoderNamespace = "SICI"
+
+defm V_MAD_LEGACY_F32 : VOP3_Real_si <0x140>;
+defm V_MAD_F32 : VOP3_Real_si <0x141>;
+defm V_MAD_I32_I24 : VOP3_Real_si <0x142>;
+defm V_MAD_U32_U24 : VOP3_Real_si <0x143>;
+defm V_CUBEID_F32 : VOP3_Real_si <0x144>;
+defm V_CUBESC_F32 : VOP3_Real_si <0x145>;
+defm V_CUBETC_F32 : VOP3_Real_si <0x146>;
+defm V_CUBEMA_F32 : VOP3_Real_si <0x147>;
+defm V_BFE_U32 : VOP3_Real_si <0x148>;
+defm V_BFE_I32 : VOP3_Real_si <0x149>;
+defm V_BFI_B32 : VOP3_Real_si <0x14a>;
+defm V_FMA_F32 : VOP3_Real_si <0x14b>;
+defm V_FMA_F64 : VOP3_Real_si <0x14c>;
+defm V_LERP_U8 : VOP3_Real_si <0x14d>;
+defm V_ALIGNBIT_B32 : VOP3_Real_si <0x14e>;
+defm V_ALIGNBYTE_B32 : VOP3_Real_si <0x14f>;
+defm V_MULLIT_F32 : VOP3_Real_si <0x150>;
+defm V_MIN3_F32 : VOP3_Real_si <0x151>;
+defm V_MIN3_I32 : VOP3_Real_si <0x152>;
+defm V_MIN3_U32 : VOP3_Real_si <0x153>;
+defm V_MAX3_F32 : VOP3_Real_si <0x154>;
+defm V_MAX3_I32 : VOP3_Real_si <0x155>;
+defm V_MAX3_U32 : VOP3_Real_si <0x156>;
+defm V_MED3_F32 : VOP3_Real_si <0x157>;
+defm V_MED3_I32 : VOP3_Real_si <0x158>;
+defm V_MED3_U32 : VOP3_Real_si <0x159>;
+defm V_SAD_U8 : VOP3_Real_si <0x15a>;
+defm V_SAD_HI_U8 : VOP3_Real_si <0x15b>;
+defm V_SAD_U16 : VOP3_Real_si <0x15c>;
+defm V_SAD_U32 : VOP3_Real_si <0x15d>;
+defm V_CVT_PK_U8_F32 : VOP3_Real_si <0x15e>;
+defm V_DIV_FIXUP_F32 : VOP3_Real_si <0x15f>;
+defm V_DIV_FIXUP_F64 : VOP3_Real_si <0x160>;
+defm V_LSHL_B64 : VOP3_Real_si <0x161>;
+defm V_LSHR_B64 : VOP3_Real_si <0x162>;
+defm V_ASHR_I64 : VOP3_Real_si <0x163>;
+defm V_ADD_F64 : VOP3_Real_si <0x164>;
+defm V_MUL_F64 : VOP3_Real_si <0x165>;
+defm V_MIN_F64 : VOP3_Real_si <0x166>;
+defm V_MAX_F64 : VOP3_Real_si <0x167>;
+defm V_LDEXP_F64 : VOP3_Real_si <0x168>;
+defm V_MUL_LO_U32 : VOP3_Real_si <0x169>;
+defm V_MUL_HI_U32 : VOP3_Real_si <0x16a>;
+defm V_MUL_LO_I32 : VOP3_Real_si <0x16b>;
+defm V_MUL_HI_I32 : VOP3_Real_si <0x16c>;
+defm V_DIV_SCALE_F32 : VOP3be_Real_si <0x16d>;
+defm V_DIV_SCALE_F64 : VOP3be_Real_si <0x16e>;
+defm V_DIV_FMAS_F32 : VOP3_Real_si <0x16f>;
+defm V_DIV_FMAS_F64 : VOP3_Real_si <0x170>;
+defm V_MSAD_U8 : VOP3_Real_si <0x171>;
+defm V_MQSAD_PK_U16_U8 : VOP3_Real_si <0x173>;
+defm V_TRIG_PREOP_F64 : VOP3_Real_si <0x174>;
+
+//===----------------------------------------------------------------------===//
+// CI
+//===----------------------------------------------------------------------===//
+
+multiclass VOP3_Real_ci<bits<9> op> {
+ def _ci : VOP3_Real<!cast<VOP3_Pseudo>(NAME), SIEncodingFamily.SI>,
+ VOP3e_si <op, !cast<VOP3_Pseudo>(NAME).Pfl> {
+ let AssemblerPredicates = [isCIOnly];
+ let DecoderNamespace = "CI";
+ }
+}
+
+defm V_MQSAD_U16_U8 : VOP3_Real_ci <0x172>;
+defm V_QSAD_PK_U16_U8 : VOP3_Real_ci <0x172>;
+defm V_MQSAD_U32_U8 : VOP3_Real_ci <0x174>;
+defm V_MAD_U64_U32 : VOP3_Real_ci <0x176>;
+defm V_MAD_I64_I32 : VOP3_Real_ci <0x177>;
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+let AssemblerPredicates = [isVI], DecoderNamespace = "VI" in {
+
+multiclass VOP3_Real_vi<bits<10> op> {
+ def _vi : VOP3_Real<!cast<VOP3_Pseudo>(NAME), SIEncodingFamily.VI>,
+ VOP3e_vi <op, !cast<VOP3_Pseudo>(NAME).Pfl>;
+}
+
+multiclass VOP3be_Real_vi<bits<10> op> {
+ def _vi : VOP3_Real<!cast<VOP3_Pseudo>(NAME), SIEncodingFamily.VI>,
+ VOP3be_vi <op, !cast<VOP3_Pseudo>(NAME).Pfl>;
+}
+
+} // End AssemblerPredicates = [isVI], DecoderNamespace = "VI"
+
+defm V_MQSAD_U16_U8 : VOP3_Real_vi <0x172>;
+defm V_MAD_U64_U32 : VOP3_Real_vi <0x176>;
+defm V_MAD_I64_I32 : VOP3_Real_vi <0x177>;
+
+defm V_MAD_LEGACY_F32 : VOP3_Real_vi <0x1c0>;
+defm V_MAD_F32 : VOP3_Real_vi <0x1c1>;
+defm V_MAD_I32_I24 : VOP3_Real_vi <0x1c2>;
+defm V_MAD_U32_U24 : VOP3_Real_vi <0x1c3>;
+defm V_CUBEID_F32 : VOP3_Real_vi <0x1c4>;
+defm V_CUBESC_F32 : VOP3_Real_vi <0x1c5>;
+defm V_CUBETC_F32 : VOP3_Real_vi <0x1c6>;
+defm V_CUBEMA_F32 : VOP3_Real_vi <0x1c7>;
+defm V_BFE_U32 : VOP3_Real_vi <0x1c8>;
+defm V_BFE_I32 : VOP3_Real_vi <0x1c9>;
+defm V_BFI_B32 : VOP3_Real_vi <0x1ca>;
+defm V_FMA_F32 : VOP3_Real_vi <0x1cb>;
+defm V_FMA_F64 : VOP3_Real_vi <0x1cc>;
+defm V_LERP_U8 : VOP3_Real_vi <0x1cd>;
+defm V_ALIGNBIT_B32 : VOP3_Real_vi <0x1ce>;
+defm V_ALIGNBYTE_B32 : VOP3_Real_vi <0x1cf>;
+defm V_MIN3_F32 : VOP3_Real_vi <0x1d0>;
+defm V_MIN3_I32 : VOP3_Real_vi <0x1d1>;
+defm V_MIN3_U32 : VOP3_Real_vi <0x1d2>;
+defm V_MAX3_F32 : VOP3_Real_vi <0x1d3>;
+defm V_MAX3_I32 : VOP3_Real_vi <0x1d4>;
+defm V_MAX3_U32 : VOP3_Real_vi <0x1d5>;
+defm V_MED3_F32 : VOP3_Real_vi <0x1d6>;
+defm V_MED3_I32 : VOP3_Real_vi <0x1d7>;
+defm V_MED3_U32 : VOP3_Real_vi <0x1d8>;
+defm V_SAD_U8 : VOP3_Real_vi <0x1d9>;
+defm V_SAD_HI_U8 : VOP3_Real_vi <0x1da>;
+defm V_SAD_U16 : VOP3_Real_vi <0x1db>;
+defm V_SAD_U32 : VOP3_Real_vi <0x1dc>;
+defm V_CVT_PK_U8_F32 : VOP3_Real_vi <0x1dd>;
+defm V_DIV_FIXUP_F32 : VOP3_Real_vi <0x1de>;
+defm V_DIV_FIXUP_F64 : VOP3_Real_vi <0x1df>;
+defm V_DIV_SCALE_F32 : VOP3be_Real_vi <0x1e0>;
+defm V_DIV_SCALE_F64 : VOP3be_Real_vi <0x1e1>;
+defm V_DIV_FMAS_F32 : VOP3_Real_vi <0x1e2>;
+defm V_DIV_FMAS_F64 : VOP3_Real_vi <0x1e3>;
+defm V_MSAD_U8 : VOP3_Real_vi <0x1e4>;
+defm V_QSAD_PK_U16_U8 : VOP3_Real_vi <0x1e5>;
+defm V_MQSAD_PK_U16_U8 : VOP3_Real_vi <0x1e6>;
+defm V_MQSAD_U32_U8 : VOP3_Real_vi <0x1e7>;
+
+defm V_MAD_F16 : VOP3_Real_vi <0x1ea>;
+defm V_MAD_U16 : VOP3_Real_vi <0x1eb>;
+defm V_MAD_I16 : VOP3_Real_vi <0x1ec>;
+
+defm V_FMA_F16 : VOP3_Real_vi <0x1ee>;
+defm V_DIV_FIXUP_F16 : VOP3_Real_vi <0x1ef>;
+
+defm V_INTERP_P1LL_F16 : VOP3_Real_vi <0x274>;
+defm V_INTERP_P1LV_F16 : VOP3_Real_vi <0x275>;
+defm V_INTERP_P2_F16 : VOP3_Real_vi <0x276>;
+defm V_ADD_F64 : VOP3_Real_vi <0x280>;
+defm V_MUL_F64 : VOP3_Real_vi <0x281>;
+defm V_MIN_F64 : VOP3_Real_vi <0x282>;
+defm V_MAX_F64 : VOP3_Real_vi <0x283>;
+defm V_LDEXP_F64 : VOP3_Real_vi <0x284>;
+defm V_MUL_LO_U32 : VOP3_Real_vi <0x285>;
+
+// removed from VI as identical to V_MUL_LO_U32
+let isAsmParserOnly = 1 in {
+defm V_MUL_LO_I32 : VOP3_Real_vi <0x285>;
+}
+
+defm V_MUL_HI_U32 : VOP3_Real_vi <0x286>;
+defm V_MUL_HI_I32 : VOP3_Real_vi <0x287>;
+
+defm V_LSHLREV_B64 : VOP3_Real_vi <0x28f>;
+defm V_LSHRREV_B64 : VOP3_Real_vi <0x290>;
+defm V_ASHRREV_I64 : VOP3_Real_vi <0x291>;
+defm V_TRIG_PREOP_F64 : VOP3_Real_vi <0x292>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td b/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td
new file mode 100644
index 0000000..16a456d
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td
@@ -0,0 +1,1144 @@
+//===-- VOPCInstructions.td - Vector Instruction Defintions ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Encodings
+//===----------------------------------------------------------------------===//
+
+class VOPCe <bits<8> op> : Enc32 {
+ bits<9> src0;
+ bits<8> src1;
+
+ let Inst{8-0} = src0;
+ let Inst{16-9} = src1;
+ let Inst{24-17} = op;
+ let Inst{31-25} = 0x3e;
+}
+
+class VOPC_SDWAe <bits<8> op, VOPProfile P> : VOP_SDWAe <P> {
+ bits<8> src1;
+
+ let Inst{8-0} = 0xf9; // sdwa
+ let Inst{16-9} = !if(P.HasSrc1, src1{7-0}, 0);
+ let Inst{24-17} = op;
+ let Inst{31-25} = 0x3e; // encoding
+
+ // VOPC disallows dst_sel and dst_unused as they have no effect on destination
+ let Inst{42-40} = SDWA.DWORD;
+ let Inst{44-43} = SDWA.UNUSED_PRESERVE;
+}
+
+//===----------------------------------------------------------------------===//
+// VOPC classes
+//===----------------------------------------------------------------------===//
+
+// VOPC instructions are a special case because for the 32-bit
+// encoding, we want to display the implicit vcc write as if it were
+// an explicit $dst.
+class VOPC_Profile<list<SchedReadWrite> sched, ValueType vt0, ValueType vt1 = vt0> :
+ VOPProfile <[i1, vt0, vt1, untyped]> {
+ let Asm32 = "vcc, $src0, $src1";
+ // The destination for 32-bit encoding is implicit.
+ let HasDst32 = 0;
+ let Outs64 = (outs VOPDstS64:$sdst);
+ list<SchedReadWrite> Schedule = sched;
+}
+
+class VOPC_Pseudo <string opName, VOPC_Profile P, list<dag> pattern=[]> :
+ InstSI<(outs), P.Ins32, "", pattern>,
+ VOP <opName>,
+ SIMCInstr<opName#"_e32", SIEncodingFamily.NONE> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = P.Asm32;
+
+ let Size = 4;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+
+ let VALU = 1;
+ let VOPC = 1;
+ let Uses = [EXEC];
+ let Defs = [VCC];
+
+ let SubtargetPredicate = isGCN;
+
+ VOPProfile Pfl = P;
+}
+
+class VOPC_Real <VOPC_Pseudo ps, int EncodingFamily> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.PseudoInstr # " " # ps.AsmOperands, []>,
+ SIMCInstr <ps.PseudoInstr, EncodingFamily> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+}
+
+class VOPC_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
+ VOP_SDWA_Pseudo <OpName, P, pattern> {
+ let AsmMatchConverter = "cvtSdwaVOPC";
+}
+
+// This class is used only with VOPC instructions. Use $sdst for out operand
+class VOPCInstAlias <VOP3_Pseudo ps, Instruction inst, VOPProfile p = ps.Pfl> :
+ InstAlias <ps.OpName#" "#p.Asm32, (inst)>, PredicateControl {
+
+ field bit isCompare;
+ field bit isCommutable;
+
+ let ResultInst =
+ !if (p.HasDst32,
+ !if (!eq(p.NumSrcArgs, 0),
+ // 1 dst, 0 src
+ (inst p.DstRC:$sdst),
+ !if (!eq(p.NumSrcArgs, 1),
+ // 1 dst, 1 src
+ (inst p.DstRC:$sdst, p.Src0RC32:$src0),
+ !if (!eq(p.NumSrcArgs, 2),
+ // 1 dst, 2 src
+ (inst p.DstRC:$sdst, p.Src0RC32:$src0, p.Src1RC32:$src1),
+ // else - unreachable
+ (inst)))),
+ // else
+ !if (!eq(p.NumSrcArgs, 2),
+ // 0 dst, 2 src
+ (inst p.Src0RC32:$src0, p.Src1RC32:$src1),
+ !if (!eq(p.NumSrcArgs, 1),
+ // 0 dst, 1 src
+ (inst p.Src0RC32:$src1),
+ // else
+ // 0 dst, 0 src
+ (inst))));
+
+ let AsmVariantName = AMDGPUAsmVariants.Default;
+ let SubtargetPredicate = AssemblerPredicate;
+}
+
+multiclass VOPC_Pseudos <string opName,
+ VOPC_Profile P,
+ PatLeaf cond = COND_NULL,
+ string revOp = opName,
+ bit DefExec = 0> {
+
+ def _e32 : VOPC_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_e32", !eq(revOp, opName)> {
+ let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
+ let SchedRW = P.Schedule;
+ let isConvergent = DefExec;
+ let isCompare = 1;
+ let isCommutable = 1;
+ }
+
+ def _e64 : VOP3_Pseudo<opName, P,
+ !if(P.HasModifiers,
+ [(set i1:$sdst,
+ (setcc (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers,
+ i1:$clamp, i32:$omod)),
+ (P.Src1VT (VOP3Mods P.Src1VT:$src1, i32:$src1_modifiers)),
+ cond))],
+ [(set i1:$sdst, (setcc P.Src0VT:$src0, P.Src1VT:$src1, cond))])>,
+ Commutable_REV<revOp#"_e64", !eq(revOp, opName)> {
+ let Defs = !if(DefExec, [EXEC], []);
+ let SchedRW = P.Schedule;
+ let isCompare = 1;
+ let isCommutable = 1;
+ }
+
+ def _sdwa : VOPC_SDWA_Pseudo <opName, P>,
+ Commutable_REV<revOp#"_sdwa", !eq(revOp, opName)> {
+ let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
+ let SchedRW = P.Schedule;
+ let isConvergent = DefExec;
+ let isCompare = 1;
+ let isCommutable = 1;
+ }
+}
+
+def VOPC_I1_F16_F16 : VOPC_Profile<[Write32Bit], f16>;
+def VOPC_I1_F32_F32 : VOPC_Profile<[Write32Bit], f32>;
+def VOPC_I1_F64_F64 : VOPC_Profile<[WriteDoubleAdd], f64>;
+def VOPC_I1_I16_I16 : VOPC_Profile<[Write32Bit], i16>;
+def VOPC_I1_I32_I32 : VOPC_Profile<[Write32Bit], i32>;
+def VOPC_I1_I64_I64 : VOPC_Profile<[Write64Bit], i64>;
+
+multiclass VOPC_F16 <string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_F16_F16, cond, revOp, 0>;
+
+multiclass VOPC_F32 <string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_F32_F32, cond, revOp, 0>;
+
+multiclass VOPC_F64 <string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_F64_F64, cond, revOp, 0>;
+
+multiclass VOPC_I16 <string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_I16_I16, cond, revOp, 0>;
+
+multiclass VOPC_I32 <string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_I32_I32, cond, revOp, 0>;
+
+multiclass VOPC_I64 <string opName, PatLeaf cond = COND_NULL, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_I64_I64, cond, revOp, 0>;
+
+multiclass VOPCX_F16 <string opName, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_F16_F16, COND_NULL, revOp, 1>;
+
+multiclass VOPCX_F32 <string opName, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_F32_F32, COND_NULL, revOp, 1>;
+
+multiclass VOPCX_F64 <string opName, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_F64_F64, COND_NULL, revOp, 1>;
+
+multiclass VOPCX_I16 <string opName, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_I16_I16, COND_NULL, revOp, 1>;
+
+multiclass VOPCX_I32 <string opName, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_I32_I32, COND_NULL, revOp, 1>;
+
+multiclass VOPCX_I64 <string opName, string revOp = opName> :
+ VOPC_Pseudos <opName, VOPC_I1_I64_I64, COND_NULL, revOp, 1>;
+
+
+//===----------------------------------------------------------------------===//
+// Compare instructions
+//===----------------------------------------------------------------------===//
+
+defm V_CMP_F_F32 : VOPC_F32 <"v_cmp_f_f32">;
+defm V_CMP_LT_F32 : VOPC_F32 <"v_cmp_lt_f32", COND_OLT, "v_cmp_gt_f32">;
+defm V_CMP_EQ_F32 : VOPC_F32 <"v_cmp_eq_f32", COND_OEQ>;
+defm V_CMP_LE_F32 : VOPC_F32 <"v_cmp_le_f32", COND_OLE, "v_cmp_ge_f32">;
+defm V_CMP_GT_F32 : VOPC_F32 <"v_cmp_gt_f32", COND_OGT>;
+defm V_CMP_LG_F32 : VOPC_F32 <"v_cmp_lg_f32", COND_ONE>;
+defm V_CMP_GE_F32 : VOPC_F32 <"v_cmp_ge_f32", COND_OGE>;
+defm V_CMP_O_F32 : VOPC_F32 <"v_cmp_o_f32", COND_O>;
+defm V_CMP_U_F32 : VOPC_F32 <"v_cmp_u_f32", COND_UO>;
+defm V_CMP_NGE_F32 : VOPC_F32 <"v_cmp_nge_f32", COND_ULT, "v_cmp_nle_f32">;
+defm V_CMP_NLG_F32 : VOPC_F32 <"v_cmp_nlg_f32", COND_UEQ>;
+defm V_CMP_NGT_F32 : VOPC_F32 <"v_cmp_ngt_f32", COND_ULE, "v_cmp_nlt_f32">;
+defm V_CMP_NLE_F32 : VOPC_F32 <"v_cmp_nle_f32", COND_UGT>;
+defm V_CMP_NEQ_F32 : VOPC_F32 <"v_cmp_neq_f32", COND_UNE>;
+defm V_CMP_NLT_F32 : VOPC_F32 <"v_cmp_nlt_f32", COND_UGE>;
+defm V_CMP_TRU_F32 : VOPC_F32 <"v_cmp_tru_f32">;
+
+defm V_CMPX_F_F32 : VOPCX_F32 <"v_cmpx_f_f32">;
+defm V_CMPX_LT_F32 : VOPCX_F32 <"v_cmpx_lt_f32", "v_cmpx_gt_f32">;
+defm V_CMPX_EQ_F32 : VOPCX_F32 <"v_cmpx_eq_f32">;
+defm V_CMPX_LE_F32 : VOPCX_F32 <"v_cmpx_le_f32", "v_cmpx_ge_f32">;
+defm V_CMPX_GT_F32 : VOPCX_F32 <"v_cmpx_gt_f32">;
+defm V_CMPX_LG_F32 : VOPCX_F32 <"v_cmpx_lg_f32">;
+defm V_CMPX_GE_F32 : VOPCX_F32 <"v_cmpx_ge_f32">;
+defm V_CMPX_O_F32 : VOPCX_F32 <"v_cmpx_o_f32">;
+defm V_CMPX_U_F32 : VOPCX_F32 <"v_cmpx_u_f32">;
+defm V_CMPX_NGE_F32 : VOPCX_F32 <"v_cmpx_nge_f32", "v_cmpx_nle_f32">;
+defm V_CMPX_NLG_F32 : VOPCX_F32 <"v_cmpx_nlg_f32">;
+defm V_CMPX_NGT_F32 : VOPCX_F32 <"v_cmpx_ngt_f32", "v_cmpx_nlt_f32">;
+defm V_CMPX_NLE_F32 : VOPCX_F32 <"v_cmpx_nle_f32">;
+defm V_CMPX_NEQ_F32 : VOPCX_F32 <"v_cmpx_neq_f32">;
+defm V_CMPX_NLT_F32 : VOPCX_F32 <"v_cmpx_nlt_f32">;
+defm V_CMPX_TRU_F32 : VOPCX_F32 <"v_cmpx_tru_f32">;
+
+defm V_CMP_F_F64 : VOPC_F64 <"v_cmp_f_f64">;
+defm V_CMP_LT_F64 : VOPC_F64 <"v_cmp_lt_f64", COND_OLT, "v_cmp_gt_f64">;
+defm V_CMP_EQ_F64 : VOPC_F64 <"v_cmp_eq_f64", COND_OEQ>;
+defm V_CMP_LE_F64 : VOPC_F64 <"v_cmp_le_f64", COND_OLE, "v_cmp_ge_f64">;
+defm V_CMP_GT_F64 : VOPC_F64 <"v_cmp_gt_f64", COND_OGT>;
+defm V_CMP_LG_F64 : VOPC_F64 <"v_cmp_lg_f64", COND_ONE>;
+defm V_CMP_GE_F64 : VOPC_F64 <"v_cmp_ge_f64", COND_OGE>;
+defm V_CMP_O_F64 : VOPC_F64 <"v_cmp_o_f64", COND_O>;
+defm V_CMP_U_F64 : VOPC_F64 <"v_cmp_u_f64", COND_UO>;
+defm V_CMP_NGE_F64 : VOPC_F64 <"v_cmp_nge_f64", COND_ULT, "v_cmp_nle_f64">;
+defm V_CMP_NLG_F64 : VOPC_F64 <"v_cmp_nlg_f64", COND_UEQ>;
+defm V_CMP_NGT_F64 : VOPC_F64 <"v_cmp_ngt_f64", COND_ULE, "v_cmp_nlt_f64">;
+defm V_CMP_NLE_F64 : VOPC_F64 <"v_cmp_nle_f64", COND_UGT>;
+defm V_CMP_NEQ_F64 : VOPC_F64 <"v_cmp_neq_f64", COND_UNE>;
+defm V_CMP_NLT_F64 : VOPC_F64 <"v_cmp_nlt_f64", COND_UGE>;
+defm V_CMP_TRU_F64 : VOPC_F64 <"v_cmp_tru_f64">;
+
+defm V_CMPX_F_F64 : VOPCX_F64 <"v_cmpx_f_f64">;
+defm V_CMPX_LT_F64 : VOPCX_F64 <"v_cmpx_lt_f64", "v_cmpx_gt_f64">;
+defm V_CMPX_EQ_F64 : VOPCX_F64 <"v_cmpx_eq_f64">;
+defm V_CMPX_LE_F64 : VOPCX_F64 <"v_cmpx_le_f64", "v_cmpx_ge_f64">;
+defm V_CMPX_GT_F64 : VOPCX_F64 <"v_cmpx_gt_f64">;
+defm V_CMPX_LG_F64 : VOPCX_F64 <"v_cmpx_lg_f64">;
+defm V_CMPX_GE_F64 : VOPCX_F64 <"v_cmpx_ge_f64">;
+defm V_CMPX_O_F64 : VOPCX_F64 <"v_cmpx_o_f64">;
+defm V_CMPX_U_F64 : VOPCX_F64 <"v_cmpx_u_f64">;
+defm V_CMPX_NGE_F64 : VOPCX_F64 <"v_cmpx_nge_f64", "v_cmpx_nle_f64">;
+defm V_CMPX_NLG_F64 : VOPCX_F64 <"v_cmpx_nlg_f64">;
+defm V_CMPX_NGT_F64 : VOPCX_F64 <"v_cmpx_ngt_f64", "v_cmpx_nlt_f64">;
+defm V_CMPX_NLE_F64 : VOPCX_F64 <"v_cmpx_nle_f64">;
+defm V_CMPX_NEQ_F64 : VOPCX_F64 <"v_cmpx_neq_f64">;
+defm V_CMPX_NLT_F64 : VOPCX_F64 <"v_cmpx_nlt_f64">;
+defm V_CMPX_TRU_F64 : VOPCX_F64 <"v_cmpx_tru_f64">;
+
+let SubtargetPredicate = isSICI in {
+
+defm V_CMPS_F_F32 : VOPC_F32 <"v_cmps_f_f32">;
+defm V_CMPS_LT_F32 : VOPC_F32 <"v_cmps_lt_f32", COND_NULL, "v_cmps_gt_f32">;
+defm V_CMPS_EQ_F32 : VOPC_F32 <"v_cmps_eq_f32">;
+defm V_CMPS_LE_F32 : VOPC_F32 <"v_cmps_le_f32", COND_NULL, "v_cmps_ge_f32">;
+defm V_CMPS_GT_F32 : VOPC_F32 <"v_cmps_gt_f32">;
+defm V_CMPS_LG_F32 : VOPC_F32 <"v_cmps_lg_f32">;
+defm V_CMPS_GE_F32 : VOPC_F32 <"v_cmps_ge_f32">;
+defm V_CMPS_O_F32 : VOPC_F32 <"v_cmps_o_f32">;
+defm V_CMPS_U_F32 : VOPC_F32 <"v_cmps_u_f32">;
+defm V_CMPS_NGE_F32 : VOPC_F32 <"v_cmps_nge_f32", COND_NULL, "v_cmps_nle_f32">;
+defm V_CMPS_NLG_F32 : VOPC_F32 <"v_cmps_nlg_f32">;
+defm V_CMPS_NGT_F32 : VOPC_F32 <"v_cmps_ngt_f32", COND_NULL, "v_cmps_nlt_f32">;
+defm V_CMPS_NLE_F32 : VOPC_F32 <"v_cmps_nle_f32">;
+defm V_CMPS_NEQ_F32 : VOPC_F32 <"v_cmps_neq_f32">;
+defm V_CMPS_NLT_F32 : VOPC_F32 <"v_cmps_nlt_f32">;
+defm V_CMPS_TRU_F32 : VOPC_F32 <"v_cmps_tru_f32">;
+
+defm V_CMPSX_F_F32 : VOPCX_F32 <"v_cmpsx_f_f32">;
+defm V_CMPSX_LT_F32 : VOPCX_F32 <"v_cmpsx_lt_f32", "v_cmpsx_gt_f32">;
+defm V_CMPSX_EQ_F32 : VOPCX_F32 <"v_cmpsx_eq_f32">;
+defm V_CMPSX_LE_F32 : VOPCX_F32 <"v_cmpsx_le_f32", "v_cmpsx_ge_f32">;
+defm V_CMPSX_GT_F32 : VOPCX_F32 <"v_cmpsx_gt_f32">;
+defm V_CMPSX_LG_F32 : VOPCX_F32 <"v_cmpsx_lg_f32">;
+defm V_CMPSX_GE_F32 : VOPCX_F32 <"v_cmpsx_ge_f32">;
+defm V_CMPSX_O_F32 : VOPCX_F32 <"v_cmpsx_o_f32">;
+defm V_CMPSX_U_F32 : VOPCX_F32 <"v_cmpsx_u_f32">;
+defm V_CMPSX_NGE_F32 : VOPCX_F32 <"v_cmpsx_nge_f32", "v_cmpsx_nle_f32">;
+defm V_CMPSX_NLG_F32 : VOPCX_F32 <"v_cmpsx_nlg_f32">;
+defm V_CMPSX_NGT_F32 : VOPCX_F32 <"v_cmpsx_ngt_f32", "v_cmpsx_nlt_f32">;
+defm V_CMPSX_NLE_F32 : VOPCX_F32 <"v_cmpsx_nle_f32">;
+defm V_CMPSX_NEQ_F32 : VOPCX_F32 <"v_cmpsx_neq_f32">;
+defm V_CMPSX_NLT_F32 : VOPCX_F32 <"v_cmpsx_nlt_f32">;
+defm V_CMPSX_TRU_F32 : VOPCX_F32 <"v_cmpsx_tru_f32">;
+
+defm V_CMPS_F_F64 : VOPC_F64 <"v_cmps_f_f64">;
+defm V_CMPS_LT_F64 : VOPC_F64 <"v_cmps_lt_f64", COND_NULL, "v_cmps_gt_f64">;
+defm V_CMPS_EQ_F64 : VOPC_F64 <"v_cmps_eq_f64">;
+defm V_CMPS_LE_F64 : VOPC_F64 <"v_cmps_le_f64", COND_NULL, "v_cmps_ge_f64">;
+defm V_CMPS_GT_F64 : VOPC_F64 <"v_cmps_gt_f64">;
+defm V_CMPS_LG_F64 : VOPC_F64 <"v_cmps_lg_f64">;
+defm V_CMPS_GE_F64 : VOPC_F64 <"v_cmps_ge_f64">;
+defm V_CMPS_O_F64 : VOPC_F64 <"v_cmps_o_f64">;
+defm V_CMPS_U_F64 : VOPC_F64 <"v_cmps_u_f64">;
+defm V_CMPS_NGE_F64 : VOPC_F64 <"v_cmps_nge_f64", COND_NULL, "v_cmps_nle_f64">;
+defm V_CMPS_NLG_F64 : VOPC_F64 <"v_cmps_nlg_f64">;
+defm V_CMPS_NGT_F64 : VOPC_F64 <"v_cmps_ngt_f64", COND_NULL, "v_cmps_nlt_f64">;
+defm V_CMPS_NLE_F64 : VOPC_F64 <"v_cmps_nle_f64">;
+defm V_CMPS_NEQ_F64 : VOPC_F64 <"v_cmps_neq_f64">;
+defm V_CMPS_NLT_F64 : VOPC_F64 <"v_cmps_nlt_f64">;
+defm V_CMPS_TRU_F64 : VOPC_F64 <"v_cmps_tru_f64">;
+
+defm V_CMPSX_F_F64 : VOPCX_F64 <"v_cmpsx_f_f64">;
+defm V_CMPSX_LT_F64 : VOPCX_F64 <"v_cmpsx_lt_f64", "v_cmpsx_gt_f64">;
+defm V_CMPSX_EQ_F64 : VOPCX_F64 <"v_cmpsx_eq_f64">;
+defm V_CMPSX_LE_F64 : VOPCX_F64 <"v_cmpsx_le_f64", "v_cmpsx_ge_f64">;
+defm V_CMPSX_GT_F64 : VOPCX_F64 <"v_cmpsx_gt_f64">;
+defm V_CMPSX_LG_F64 : VOPCX_F64 <"v_cmpsx_lg_f64">;
+defm V_CMPSX_GE_F64 : VOPCX_F64 <"v_cmpsx_ge_f64">;
+defm V_CMPSX_O_F64 : VOPCX_F64 <"v_cmpsx_o_f64">;
+defm V_CMPSX_U_F64 : VOPCX_F64 <"v_cmpsx_u_f64">;
+defm V_CMPSX_NGE_F64 : VOPCX_F64 <"v_cmpsx_nge_f64", "v_cmpsx_nle_f64">;
+defm V_CMPSX_NLG_F64 : VOPCX_F64 <"v_cmpsx_nlg_f64">;
+defm V_CMPSX_NGT_F64 : VOPCX_F64 <"v_cmpsx_ngt_f64", "v_cmpsx_nlt_f64">;
+defm V_CMPSX_NLE_F64 : VOPCX_F64 <"v_cmpsx_nle_f64">;
+defm V_CMPSX_NEQ_F64 : VOPCX_F64 <"v_cmpsx_neq_f64">;
+defm V_CMPSX_NLT_F64 : VOPCX_F64 <"v_cmpsx_nlt_f64">;
+defm V_CMPSX_TRU_F64 : VOPCX_F64 <"v_cmpsx_tru_f64">;
+
+} // End SubtargetPredicate = isSICI
+
+let SubtargetPredicate = Has16BitInsts in {
+
+defm V_CMP_F_F16 : VOPC_F16 <"v_cmp_f_f16">;
+defm V_CMP_LT_F16 : VOPC_F16 <"v_cmp_lt_f16", COND_OLT, "v_cmp_gt_f16">;
+defm V_CMP_EQ_F16 : VOPC_F16 <"v_cmp_eq_f16", COND_OEQ>;
+defm V_CMP_LE_F16 : VOPC_F16 <"v_cmp_le_f16", COND_OLE, "v_cmp_ge_f16">;
+defm V_CMP_GT_F16 : VOPC_F16 <"v_cmp_gt_f16", COND_OGT>;
+defm V_CMP_LG_F16 : VOPC_F16 <"v_cmp_lg_f16", COND_ONE>;
+defm V_CMP_GE_F16 : VOPC_F16 <"v_cmp_ge_f16", COND_OGE>;
+defm V_CMP_O_F16 : VOPC_F16 <"v_cmp_o_f16", COND_O>;
+defm V_CMP_U_F16 : VOPC_F16 <"v_cmp_u_f16", COND_UO>;
+defm V_CMP_NGE_F16 : VOPC_F16 <"v_cmp_nge_f16", COND_ULT, "v_cmp_nle_f16">;
+defm V_CMP_NLG_F16 : VOPC_F16 <"v_cmp_nlg_f16", COND_UEQ>;
+defm V_CMP_NGT_F16 : VOPC_F16 <"v_cmp_ngt_f16", COND_ULE, "v_cmp_nlt_f16">;
+defm V_CMP_NLE_F16 : VOPC_F16 <"v_cmp_nle_f16", COND_UGT>;
+defm V_CMP_NEQ_F16 : VOPC_F16 <"v_cmp_neq_f16", COND_UNE>;
+defm V_CMP_NLT_F16 : VOPC_F16 <"v_cmp_nlt_f16", COND_UGE>;
+defm V_CMP_TRU_F16 : VOPC_F16 <"v_cmp_tru_f16">;
+
+defm V_CMPX_F_F16 : VOPCX_F16 <"v_cmpx_f_f16">;
+defm V_CMPX_LT_F16 : VOPCX_F16 <"v_cmpx_lt_f16", "v_cmpx_gt_f16">;
+defm V_CMPX_EQ_F16 : VOPCX_F16 <"v_cmpx_eq_f16">;
+defm V_CMPX_LE_F16 : VOPCX_F16 <"v_cmpx_le_f16", "v_cmpx_ge_f16">;
+defm V_CMPX_GT_F16 : VOPCX_F16 <"v_cmpx_gt_f16">;
+defm V_CMPX_LG_F16 : VOPCX_F16 <"v_cmpx_lg_f16">;
+defm V_CMPX_GE_F16 : VOPCX_F16 <"v_cmpx_ge_f16">;
+defm V_CMPX_O_F16 : VOPCX_F16 <"v_cmpx_o_f16">;
+defm V_CMPX_U_F16 : VOPCX_F16 <"v_cmpx_u_f16">;
+defm V_CMPX_NGE_F16 : VOPCX_F16 <"v_cmpx_nge_f16", "v_cmpx_nle_f16">;
+defm V_CMPX_NLG_F16 : VOPCX_F16 <"v_cmpx_nlg_f16">;
+defm V_CMPX_NGT_F16 : VOPCX_F16 <"v_cmpx_ngt_f16", "v_cmpx_nlt_f16">;
+defm V_CMPX_NLE_F16 : VOPCX_F16 <"v_cmpx_nle_f16">;
+defm V_CMPX_NEQ_F16 : VOPCX_F16 <"v_cmpx_neq_f16">;
+defm V_CMPX_NLT_F16 : VOPCX_F16 <"v_cmpx_nlt_f16">;
+defm V_CMPX_TRU_F16 : VOPCX_F16 <"v_cmpx_tru_f16">;
+
+defm V_CMP_F_I16 : VOPC_I16 <"v_cmp_f_i16">;
+defm V_CMP_LT_I16 : VOPC_I16 <"v_cmp_lt_i16", COND_SLT, "v_cmp_gt_i16">;
+defm V_CMP_EQ_I16 : VOPC_I16 <"v_cmp_eq_i16">;
+defm V_CMP_LE_I16 : VOPC_I16 <"v_cmp_le_i16", COND_SLE, "v_cmp_ge_i16">;
+defm V_CMP_GT_I16 : VOPC_I16 <"v_cmp_gt_i16", COND_SGT>;
+defm V_CMP_NE_I16 : VOPC_I16 <"v_cmp_ne_i16">;
+defm V_CMP_GE_I16 : VOPC_I16 <"v_cmp_ge_i16", COND_SGE>;
+defm V_CMP_T_I16 : VOPC_I16 <"v_cmp_t_i16">;
+
+defm V_CMP_F_U16 : VOPC_I16 <"v_cmp_f_u16">;
+defm V_CMP_LT_U16 : VOPC_I16 <"v_cmp_lt_u16", COND_ULT, "v_cmp_gt_u16">;
+defm V_CMP_EQ_U16 : VOPC_I16 <"v_cmp_eq_u16", COND_EQ>;
+defm V_CMP_LE_U16 : VOPC_I16 <"v_cmp_le_u16", COND_ULE, "v_cmp_ge_u16">;
+defm V_CMP_GT_U16 : VOPC_I16 <"v_cmp_gt_u16", COND_UGT>;
+defm V_CMP_NE_U16 : VOPC_I16 <"v_cmp_ne_u16", COND_NE>;
+defm V_CMP_GE_U16 : VOPC_I16 <"v_cmp_ge_u16", COND_UGE>;
+defm V_CMP_T_U16 : VOPC_I16 <"v_cmp_t_u16">;
+
+defm V_CMPX_F_I16 : VOPCX_I16 <"v_cmpx_f_i16">;
+defm V_CMPX_LT_I16 : VOPCX_I16 <"v_cmpx_lt_i16", "v_cmpx_gt_i16">;
+defm V_CMPX_EQ_I16 : VOPCX_I16 <"v_cmpx_eq_i16">;
+defm V_CMPX_LE_I16 : VOPCX_I16 <"v_cmpx_le_i16", "v_cmpx_ge_i16">;
+defm V_CMPX_GT_I16 : VOPCX_I16 <"v_cmpx_gt_i16">;
+defm V_CMPX_NE_I16 : VOPCX_I16 <"v_cmpx_ne_i16">;
+defm V_CMPX_GE_I16 : VOPCX_I16 <"v_cmpx_ge_i16">;
+defm V_CMPX_T_I16 : VOPCX_I16 <"v_cmpx_t_i16">;
+defm V_CMPX_F_U16 : VOPCX_I16 <"v_cmpx_f_u16">;
+
+defm V_CMPX_LT_U16 : VOPCX_I16 <"v_cmpx_lt_u16", "v_cmpx_gt_u16">;
+defm V_CMPX_EQ_U16 : VOPCX_I16 <"v_cmpx_eq_u16">;
+defm V_CMPX_LE_U16 : VOPCX_I16 <"v_cmpx_le_u16", "v_cmpx_ge_u16">;
+defm V_CMPX_GT_U16 : VOPCX_I16 <"v_cmpx_gt_u16">;
+defm V_CMPX_NE_U16 : VOPCX_I16 <"v_cmpx_ne_u16">;
+defm V_CMPX_GE_U16 : VOPCX_I16 <"v_cmpx_ge_u16">;
+defm V_CMPX_T_U16 : VOPCX_I16 <"v_cmpx_t_u16">;
+
+} // End SubtargetPredicate = Has16BitInsts
+
+defm V_CMP_F_I32 : VOPC_I32 <"v_cmp_f_i32">;
+defm V_CMP_LT_I32 : VOPC_I32 <"v_cmp_lt_i32", COND_SLT, "v_cmp_gt_i32">;
+defm V_CMP_EQ_I32 : VOPC_I32 <"v_cmp_eq_i32">;
+defm V_CMP_LE_I32 : VOPC_I32 <"v_cmp_le_i32", COND_SLE, "v_cmp_ge_i32">;
+defm V_CMP_GT_I32 : VOPC_I32 <"v_cmp_gt_i32", COND_SGT>;
+defm V_CMP_NE_I32 : VOPC_I32 <"v_cmp_ne_i32">;
+defm V_CMP_GE_I32 : VOPC_I32 <"v_cmp_ge_i32", COND_SGE>;
+defm V_CMP_T_I32 : VOPC_I32 <"v_cmp_t_i32">;
+
+defm V_CMPX_F_I32 : VOPCX_I32 <"v_cmpx_f_i32">;
+defm V_CMPX_LT_I32 : VOPCX_I32 <"v_cmpx_lt_i32", "v_cmpx_gt_i32">;
+defm V_CMPX_EQ_I32 : VOPCX_I32 <"v_cmpx_eq_i32">;
+defm V_CMPX_LE_I32 : VOPCX_I32 <"v_cmpx_le_i32", "v_cmpx_ge_i32">;
+defm V_CMPX_GT_I32 : VOPCX_I32 <"v_cmpx_gt_i32">;
+defm V_CMPX_NE_I32 : VOPCX_I32 <"v_cmpx_ne_i32">;
+defm V_CMPX_GE_I32 : VOPCX_I32 <"v_cmpx_ge_i32">;
+defm V_CMPX_T_I32 : VOPCX_I32 <"v_cmpx_t_i32">;
+
+defm V_CMP_F_I64 : VOPC_I64 <"v_cmp_f_i64">;
+defm V_CMP_LT_I64 : VOPC_I64 <"v_cmp_lt_i64", COND_SLT, "v_cmp_gt_i64">;
+defm V_CMP_EQ_I64 : VOPC_I64 <"v_cmp_eq_i64">;
+defm V_CMP_LE_I64 : VOPC_I64 <"v_cmp_le_i64", COND_SLE, "v_cmp_ge_i64">;
+defm V_CMP_GT_I64 : VOPC_I64 <"v_cmp_gt_i64", COND_SGT>;
+defm V_CMP_NE_I64 : VOPC_I64 <"v_cmp_ne_i64">;
+defm V_CMP_GE_I64 : VOPC_I64 <"v_cmp_ge_i64", COND_SGE>;
+defm V_CMP_T_I64 : VOPC_I64 <"v_cmp_t_i64">;
+
+defm V_CMPX_F_I64 : VOPCX_I64 <"v_cmpx_f_i64">;
+defm V_CMPX_LT_I64 : VOPCX_I64 <"v_cmpx_lt_i64", "v_cmpx_gt_i64">;
+defm V_CMPX_EQ_I64 : VOPCX_I64 <"v_cmpx_eq_i64">;
+defm V_CMPX_LE_I64 : VOPCX_I64 <"v_cmpx_le_i64", "v_cmpx_ge_i64">;
+defm V_CMPX_GT_I64 : VOPCX_I64 <"v_cmpx_gt_i64">;
+defm V_CMPX_NE_I64 : VOPCX_I64 <"v_cmpx_ne_i64">;
+defm V_CMPX_GE_I64 : VOPCX_I64 <"v_cmpx_ge_i64">;
+defm V_CMPX_T_I64 : VOPCX_I64 <"v_cmpx_t_i64">;
+
+defm V_CMP_F_U32 : VOPC_I32 <"v_cmp_f_u32">;
+defm V_CMP_LT_U32 : VOPC_I32 <"v_cmp_lt_u32", COND_ULT, "v_cmp_gt_u32">;
+defm V_CMP_EQ_U32 : VOPC_I32 <"v_cmp_eq_u32", COND_EQ>;
+defm V_CMP_LE_U32 : VOPC_I32 <"v_cmp_le_u32", COND_ULE, "v_cmp_ge_u32">;
+defm V_CMP_GT_U32 : VOPC_I32 <"v_cmp_gt_u32", COND_UGT>;
+defm V_CMP_NE_U32 : VOPC_I32 <"v_cmp_ne_u32", COND_NE>;
+defm V_CMP_GE_U32 : VOPC_I32 <"v_cmp_ge_u32", COND_UGE>;
+defm V_CMP_T_U32 : VOPC_I32 <"v_cmp_t_u32">;
+
+defm V_CMPX_F_U32 : VOPCX_I32 <"v_cmpx_f_u32">;
+defm V_CMPX_LT_U32 : VOPCX_I32 <"v_cmpx_lt_u32", "v_cmpx_gt_u32">;
+defm V_CMPX_EQ_U32 : VOPCX_I32 <"v_cmpx_eq_u32">;
+defm V_CMPX_LE_U32 : VOPCX_I32 <"v_cmpx_le_u32", "v_cmpx_le_u32">;
+defm V_CMPX_GT_U32 : VOPCX_I32 <"v_cmpx_gt_u32">;
+defm V_CMPX_NE_U32 : VOPCX_I32 <"v_cmpx_ne_u32">;
+defm V_CMPX_GE_U32 : VOPCX_I32 <"v_cmpx_ge_u32">;
+defm V_CMPX_T_U32 : VOPCX_I32 <"v_cmpx_t_u32">;
+
+defm V_CMP_F_U64 : VOPC_I64 <"v_cmp_f_u64">;
+defm V_CMP_LT_U64 : VOPC_I64 <"v_cmp_lt_u64", COND_ULT, "v_cmp_gt_u64">;
+defm V_CMP_EQ_U64 : VOPC_I64 <"v_cmp_eq_u64", COND_EQ>;
+defm V_CMP_LE_U64 : VOPC_I64 <"v_cmp_le_u64", COND_ULE, "v_cmp_ge_u64">;
+defm V_CMP_GT_U64 : VOPC_I64 <"v_cmp_gt_u64", COND_UGT>;
+defm V_CMP_NE_U64 : VOPC_I64 <"v_cmp_ne_u64", COND_NE>;
+defm V_CMP_GE_U64 : VOPC_I64 <"v_cmp_ge_u64", COND_UGE>;
+defm V_CMP_T_U64 : VOPC_I64 <"v_cmp_t_u64">;
+
+defm V_CMPX_F_U64 : VOPCX_I64 <"v_cmpx_f_u64">;
+defm V_CMPX_LT_U64 : VOPCX_I64 <"v_cmpx_lt_u64", "v_cmpx_gt_u64">;
+defm V_CMPX_EQ_U64 : VOPCX_I64 <"v_cmpx_eq_u64">;
+defm V_CMPX_LE_U64 : VOPCX_I64 <"v_cmpx_le_u64", "v_cmpx_ge_u64">;
+defm V_CMPX_GT_U64 : VOPCX_I64 <"v_cmpx_gt_u64">;
+defm V_CMPX_NE_U64 : VOPCX_I64 <"v_cmpx_ne_u64">;
+defm V_CMPX_GE_U64 : VOPCX_I64 <"v_cmpx_ge_u64">;
+defm V_CMPX_T_U64 : VOPCX_I64 <"v_cmpx_t_u64">;
+
+//===----------------------------------------------------------------------===//
+// Class instructions
+//===----------------------------------------------------------------------===//
+
+class VOPC_Class_Profile<list<SchedReadWrite> sched, ValueType vt> :
+ VOPC_Profile<sched, vt, i32> {
+ let Ins64 = (ins Src0Mod:$src0_modifiers, Src0RC64:$src0, Src1RC64:$src1);
+ let Asm64 = "$sdst, $src0_modifiers, $src1";
+ let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0,
+ Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1,
+ clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel);
+ let AsmSDWA = " vcc, $src0_modifiers, $src1_modifiers$clamp $src0_sel $src1_sel";
+ let HasSrc1Mods = 0;
+ let HasClamp = 0;
+ let HasOMod = 0;
+}
+
+class getVOPCClassPat64 <VOPProfile P> {
+ list<dag> ret =
+ [(set i1:$sdst,
+ (AMDGPUfp_class
+ (P.Src0VT (VOP3Mods0Clamp0OMod P.Src0VT:$src0, i32:$src0_modifiers)),
+ P.Src1VT:$src1))];
+}
+
+// Special case for class instructions which only have modifiers on
+// the 1st source operand.
+multiclass VOPC_Class_Pseudos <string opName, VOPC_Profile p, bit DefExec> {
+ def _e32 : VOPC_Pseudo <opName, p> {
+ let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
+ let SchedRW = p.Schedule;
+ let isConvergent = DefExec;
+ }
+
+ def _e64 : VOP3_Pseudo<opName, p, getVOPCClassPat64<p>.ret> {
+ let Defs = !if(DefExec, [EXEC], []);
+ let SchedRW = p.Schedule;
+ }
+
+ def _sdwa : VOPC_SDWA_Pseudo <opName, p> {
+ let Defs = !if(DefExec, [VCC, EXEC], [VCC]);
+ let SchedRW = p.Schedule;
+ let isConvergent = DefExec;
+ }
+}
+
+def VOPC_I1_F16_I32 : VOPC_Class_Profile<[Write32Bit], f16>;
+def VOPC_I1_F32_I32 : VOPC_Class_Profile<[Write32Bit], f32>;
+def VOPC_I1_F64_I32 : VOPC_Class_Profile<[WriteDoubleAdd], f64>;
+
+multiclass VOPC_CLASS_F16 <string opName> :
+ VOPC_Class_Pseudos <opName, VOPC_I1_F16_I32, 0>;
+
+multiclass VOPCX_CLASS_F16 <string opName> :
+ VOPC_Class_Pseudos <opName, VOPC_I1_F32_I32, 1>;
+
+multiclass VOPC_CLASS_F32 <string opName> :
+ VOPC_Class_Pseudos <opName, VOPC_I1_F32_I32, 0>;
+
+multiclass VOPCX_CLASS_F32 <string opName> :
+ VOPC_Class_Pseudos <opName, VOPC_I1_F32_I32, 1>;
+
+multiclass VOPC_CLASS_F64 <string opName> :
+ VOPC_Class_Pseudos <opName, VOPC_I1_F64_I32, 0>;
+
+multiclass VOPCX_CLASS_F64 <string opName> :
+ VOPC_Class_Pseudos <opName, VOPC_I1_F64_I32, 1>;
+
+defm V_CMP_CLASS_F32 : VOPC_CLASS_F32 <"v_cmp_class_f32">;
+defm V_CMPX_CLASS_F32 : VOPCX_CLASS_F32 <"v_cmpx_class_f32">;
+defm V_CMP_CLASS_F64 : VOPC_CLASS_F64 <"v_cmp_class_f64">;
+defm V_CMPX_CLASS_F64 : VOPCX_CLASS_F64 <"v_cmpx_class_f64">;
+defm V_CMP_CLASS_F16 : VOPC_CLASS_F16 <"v_cmp_class_f16">;
+defm V_CMPX_CLASS_F16 : VOPCX_CLASS_F16 <"v_cmpx_class_f16">;
+
+//===----------------------------------------------------------------------===//
+// V_ICMPIntrinsic Pattern.
+//===----------------------------------------------------------------------===//
+
+let Predicates = [isGCN] in {
+
+class ICMP_Pattern <PatLeaf cond, Instruction inst, ValueType vt> : Pat <
+ (AMDGPUsetcc vt:$src0, vt:$src1, cond),
+ (inst $src0, $src1)
+>;
+
+def : ICMP_Pattern <COND_EQ, V_CMP_EQ_U32_e64, i32>;
+def : ICMP_Pattern <COND_NE, V_CMP_NE_U32_e64, i32>;
+def : ICMP_Pattern <COND_UGT, V_CMP_GT_U32_e64, i32>;
+def : ICMP_Pattern <COND_UGE, V_CMP_GE_U32_e64, i32>;
+def : ICMP_Pattern <COND_ULT, V_CMP_LT_U32_e64, i32>;
+def : ICMP_Pattern <COND_ULE, V_CMP_LE_U32_e64, i32>;
+def : ICMP_Pattern <COND_SGT, V_CMP_GT_I32_e64, i32>;
+def : ICMP_Pattern <COND_SGE, V_CMP_GE_I32_e64, i32>;
+def : ICMP_Pattern <COND_SLT, V_CMP_LT_I32_e64, i32>;
+def : ICMP_Pattern <COND_SLE, V_CMP_LE_I32_e64, i32>;
+
+def : ICMP_Pattern <COND_EQ, V_CMP_EQ_U64_e64, i64>;
+def : ICMP_Pattern <COND_NE, V_CMP_NE_U64_e64, i64>;
+def : ICMP_Pattern <COND_UGT, V_CMP_GT_U64_e64, i64>;
+def : ICMP_Pattern <COND_UGE, V_CMP_GE_U64_e64, i64>;
+def : ICMP_Pattern <COND_ULT, V_CMP_LT_U64_e64, i64>;
+def : ICMP_Pattern <COND_ULE, V_CMP_LE_U64_e64, i64>;
+def : ICMP_Pattern <COND_SGT, V_CMP_GT_I64_e64, i64>;
+def : ICMP_Pattern <COND_SGE, V_CMP_GE_I64_e64, i64>;
+def : ICMP_Pattern <COND_SLT, V_CMP_LT_I64_e64, i64>;
+def : ICMP_Pattern <COND_SLE, V_CMP_LE_I64_e64, i64>;
+
+class FCMP_Pattern <PatLeaf cond, Instruction inst, ValueType vt> : Pat <
+ (i64 (AMDGPUsetcc (vt (VOP3Mods vt:$src0, i32:$src0_modifiers)),
+ (vt (VOP3Mods vt:$src1, i32:$src1_modifiers)), cond)),
+ (inst $src0_modifiers, $src0, $src1_modifiers, $src1,
+ DSTCLAMP.NONE, DSTOMOD.NONE)
+>;
+
+def : FCMP_Pattern <COND_OEQ, V_CMP_EQ_F32_e64, f32>;
+def : FCMP_Pattern <COND_ONE, V_CMP_NEQ_F32_e64, f32>;
+def : FCMP_Pattern <COND_OGT, V_CMP_GT_F32_e64, f32>;
+def : FCMP_Pattern <COND_OGE, V_CMP_GE_F32_e64, f32>;
+def : FCMP_Pattern <COND_OLT, V_CMP_LT_F32_e64, f32>;
+def : FCMP_Pattern <COND_OLE, V_CMP_LE_F32_e64, f32>;
+
+def : FCMP_Pattern <COND_OEQ, V_CMP_EQ_F64_e64, f64>;
+def : FCMP_Pattern <COND_ONE, V_CMP_NEQ_F64_e64, f64>;
+def : FCMP_Pattern <COND_OGT, V_CMP_GT_F64_e64, f64>;
+def : FCMP_Pattern <COND_OGE, V_CMP_GE_F64_e64, f64>;
+def : FCMP_Pattern <COND_OLT, V_CMP_LT_F64_e64, f64>;
+def : FCMP_Pattern <COND_OLE, V_CMP_LE_F64_e64, f64>;
+
+def : FCMP_Pattern <COND_UEQ, V_CMP_NLG_F32_e64, f32>;
+def : FCMP_Pattern <COND_UNE, V_CMP_NEQ_F32_e64, f32>;
+def : FCMP_Pattern <COND_UGT, V_CMP_NLE_F32_e64, f32>;
+def : FCMP_Pattern <COND_UGE, V_CMP_NLT_F32_e64, f32>;
+def : FCMP_Pattern <COND_ULT, V_CMP_NGE_F32_e64, f32>;
+def : FCMP_Pattern <COND_ULE, V_CMP_NGT_F32_e64, f32>;
+
+def : FCMP_Pattern <COND_UEQ, V_CMP_NLG_F64_e64, f64>;
+def : FCMP_Pattern <COND_UNE, V_CMP_NEQ_F64_e64, f64>;
+def : FCMP_Pattern <COND_UGT, V_CMP_NLE_F64_e64, f64>;
+def : FCMP_Pattern <COND_UGE, V_CMP_NLT_F64_e64, f64>;
+def : FCMP_Pattern <COND_ULT, V_CMP_NGE_F64_e64, f64>;
+def : FCMP_Pattern <COND_ULE, V_CMP_NGT_F64_e64, f64>;
+
+} // End Predicates = [isGCN]
+
+//===----------------------------------------------------------------------===//
+// Target
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SI
+//===----------------------------------------------------------------------===//
+
+multiclass VOPC_Real_si <bits<9> op> {
+ let AssemblerPredicates = [isSICI], DecoderNamespace = "SICI" in {
+ def _e32_si :
+ VOPC_Real<!cast<VOPC_Pseudo>(NAME#"_e32"), SIEncodingFamily.SI>,
+ VOPCe<op{7-0}>;
+
+ def _e64_si :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.SI>,
+ VOP3a_si <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl> {
+ // Encoding used for VOPC instructions encoded as VOP3
+ // Differs from VOP3e by destination name (sdst) as VOPC doesn't have vector dst
+ bits<8> sdst;
+ let Inst{7-0} = sdst;
+ }
+ }
+ def : VOPCInstAlias <!cast<VOP3_Pseudo>(NAME#"_e64"),
+ !cast<Instruction>(NAME#"_e32_si")> {
+ let AssemblerPredicate = isSICI;
+ }
+}
+
+defm V_CMP_F_F32 : VOPC_Real_si <0x0>;
+defm V_CMP_LT_F32 : VOPC_Real_si <0x1>;
+defm V_CMP_EQ_F32 : VOPC_Real_si <0x2>;
+defm V_CMP_LE_F32 : VOPC_Real_si <0x3>;
+defm V_CMP_GT_F32 : VOPC_Real_si <0x4>;
+defm V_CMP_LG_F32 : VOPC_Real_si <0x5>;
+defm V_CMP_GE_F32 : VOPC_Real_si <0x6>;
+defm V_CMP_O_F32 : VOPC_Real_si <0x7>;
+defm V_CMP_U_F32 : VOPC_Real_si <0x8>;
+defm V_CMP_NGE_F32 : VOPC_Real_si <0x9>;
+defm V_CMP_NLG_F32 : VOPC_Real_si <0xa>;
+defm V_CMP_NGT_F32 : VOPC_Real_si <0xb>;
+defm V_CMP_NLE_F32 : VOPC_Real_si <0xc>;
+defm V_CMP_NEQ_F32 : VOPC_Real_si <0xd>;
+defm V_CMP_NLT_F32 : VOPC_Real_si <0xe>;
+defm V_CMP_TRU_F32 : VOPC_Real_si <0xf>;
+
+defm V_CMPX_F_F32 : VOPC_Real_si <0x10>;
+defm V_CMPX_LT_F32 : VOPC_Real_si <0x11>;
+defm V_CMPX_EQ_F32 : VOPC_Real_si <0x12>;
+defm V_CMPX_LE_F32 : VOPC_Real_si <0x13>;
+defm V_CMPX_GT_F32 : VOPC_Real_si <0x14>;
+defm V_CMPX_LG_F32 : VOPC_Real_si <0x15>;
+defm V_CMPX_GE_F32 : VOPC_Real_si <0x16>;
+defm V_CMPX_O_F32 : VOPC_Real_si <0x17>;
+defm V_CMPX_U_F32 : VOPC_Real_si <0x18>;
+defm V_CMPX_NGE_F32 : VOPC_Real_si <0x19>;
+defm V_CMPX_NLG_F32 : VOPC_Real_si <0x1a>;
+defm V_CMPX_NGT_F32 : VOPC_Real_si <0x1b>;
+defm V_CMPX_NLE_F32 : VOPC_Real_si <0x1c>;
+defm V_CMPX_NEQ_F32 : VOPC_Real_si <0x1d>;
+defm V_CMPX_NLT_F32 : VOPC_Real_si <0x1e>;
+defm V_CMPX_TRU_F32 : VOPC_Real_si <0x1f>;
+
+defm V_CMP_F_F64 : VOPC_Real_si <0x20>;
+defm V_CMP_LT_F64 : VOPC_Real_si <0x21>;
+defm V_CMP_EQ_F64 : VOPC_Real_si <0x22>;
+defm V_CMP_LE_F64 : VOPC_Real_si <0x23>;
+defm V_CMP_GT_F64 : VOPC_Real_si <0x24>;
+defm V_CMP_LG_F64 : VOPC_Real_si <0x25>;
+defm V_CMP_GE_F64 : VOPC_Real_si <0x26>;
+defm V_CMP_O_F64 : VOPC_Real_si <0x27>;
+defm V_CMP_U_F64 : VOPC_Real_si <0x28>;
+defm V_CMP_NGE_F64 : VOPC_Real_si <0x29>;
+defm V_CMP_NLG_F64 : VOPC_Real_si <0x2a>;
+defm V_CMP_NGT_F64 : VOPC_Real_si <0x2b>;
+defm V_CMP_NLE_F64 : VOPC_Real_si <0x2c>;
+defm V_CMP_NEQ_F64 : VOPC_Real_si <0x2d>;
+defm V_CMP_NLT_F64 : VOPC_Real_si <0x2e>;
+defm V_CMP_TRU_F64 : VOPC_Real_si <0x2f>;
+
+defm V_CMPX_F_F64 : VOPC_Real_si <0x30>;
+defm V_CMPX_LT_F64 : VOPC_Real_si <0x31>;
+defm V_CMPX_EQ_F64 : VOPC_Real_si <0x32>;
+defm V_CMPX_LE_F64 : VOPC_Real_si <0x33>;
+defm V_CMPX_GT_F64 : VOPC_Real_si <0x34>;
+defm V_CMPX_LG_F64 : VOPC_Real_si <0x35>;
+defm V_CMPX_GE_F64 : VOPC_Real_si <0x36>;
+defm V_CMPX_O_F64 : VOPC_Real_si <0x37>;
+defm V_CMPX_U_F64 : VOPC_Real_si <0x38>;
+defm V_CMPX_NGE_F64 : VOPC_Real_si <0x39>;
+defm V_CMPX_NLG_F64 : VOPC_Real_si <0x3a>;
+defm V_CMPX_NGT_F64 : VOPC_Real_si <0x3b>;
+defm V_CMPX_NLE_F64 : VOPC_Real_si <0x3c>;
+defm V_CMPX_NEQ_F64 : VOPC_Real_si <0x3d>;
+defm V_CMPX_NLT_F64 : VOPC_Real_si <0x3e>;
+defm V_CMPX_TRU_F64 : VOPC_Real_si <0x3f>;
+
+defm V_CMPS_F_F32 : VOPC_Real_si <0x40>;
+defm V_CMPS_LT_F32 : VOPC_Real_si <0x41>;
+defm V_CMPS_EQ_F32 : VOPC_Real_si <0x42>;
+defm V_CMPS_LE_F32 : VOPC_Real_si <0x43>;
+defm V_CMPS_GT_F32 : VOPC_Real_si <0x44>;
+defm V_CMPS_LG_F32 : VOPC_Real_si <0x45>;
+defm V_CMPS_GE_F32 : VOPC_Real_si <0x46>;
+defm V_CMPS_O_F32 : VOPC_Real_si <0x47>;
+defm V_CMPS_U_F32 : VOPC_Real_si <0x48>;
+defm V_CMPS_NGE_F32 : VOPC_Real_si <0x49>;
+defm V_CMPS_NLG_F32 : VOPC_Real_si <0x4a>;
+defm V_CMPS_NGT_F32 : VOPC_Real_si <0x4b>;
+defm V_CMPS_NLE_F32 : VOPC_Real_si <0x4c>;
+defm V_CMPS_NEQ_F32 : VOPC_Real_si <0x4d>;
+defm V_CMPS_NLT_F32 : VOPC_Real_si <0x4e>;
+defm V_CMPS_TRU_F32 : VOPC_Real_si <0x4f>;
+
+defm V_CMPSX_F_F32 : VOPC_Real_si <0x50>;
+defm V_CMPSX_LT_F32 : VOPC_Real_si <0x51>;
+defm V_CMPSX_EQ_F32 : VOPC_Real_si <0x52>;
+defm V_CMPSX_LE_F32 : VOPC_Real_si <0x53>;
+defm V_CMPSX_GT_F32 : VOPC_Real_si <0x54>;
+defm V_CMPSX_LG_F32 : VOPC_Real_si <0x55>;
+defm V_CMPSX_GE_F32 : VOPC_Real_si <0x56>;
+defm V_CMPSX_O_F32 : VOPC_Real_si <0x57>;
+defm V_CMPSX_U_F32 : VOPC_Real_si <0x58>;
+defm V_CMPSX_NGE_F32 : VOPC_Real_si <0x59>;
+defm V_CMPSX_NLG_F32 : VOPC_Real_si <0x5a>;
+defm V_CMPSX_NGT_F32 : VOPC_Real_si <0x5b>;
+defm V_CMPSX_NLE_F32 : VOPC_Real_si <0x5c>;
+defm V_CMPSX_NEQ_F32 : VOPC_Real_si <0x5d>;
+defm V_CMPSX_NLT_F32 : VOPC_Real_si <0x5e>;
+defm V_CMPSX_TRU_F32 : VOPC_Real_si <0x5f>;
+
+defm V_CMPS_F_F64 : VOPC_Real_si <0x60>;
+defm V_CMPS_LT_F64 : VOPC_Real_si <0x61>;
+defm V_CMPS_EQ_F64 : VOPC_Real_si <0x62>;
+defm V_CMPS_LE_F64 : VOPC_Real_si <0x63>;
+defm V_CMPS_GT_F64 : VOPC_Real_si <0x64>;
+defm V_CMPS_LG_F64 : VOPC_Real_si <0x65>;
+defm V_CMPS_GE_F64 : VOPC_Real_si <0x66>;
+defm V_CMPS_O_F64 : VOPC_Real_si <0x67>;
+defm V_CMPS_U_F64 : VOPC_Real_si <0x68>;
+defm V_CMPS_NGE_F64 : VOPC_Real_si <0x69>;
+defm V_CMPS_NLG_F64 : VOPC_Real_si <0x6a>;
+defm V_CMPS_NGT_F64 : VOPC_Real_si <0x6b>;
+defm V_CMPS_NLE_F64 : VOPC_Real_si <0x6c>;
+defm V_CMPS_NEQ_F64 : VOPC_Real_si <0x6d>;
+defm V_CMPS_NLT_F64 : VOPC_Real_si <0x6e>;
+defm V_CMPS_TRU_F64 : VOPC_Real_si <0x6f>;
+
+defm V_CMPSX_F_F64 : VOPC_Real_si <0x70>;
+defm V_CMPSX_LT_F64 : VOPC_Real_si <0x71>;
+defm V_CMPSX_EQ_F64 : VOPC_Real_si <0x72>;
+defm V_CMPSX_LE_F64 : VOPC_Real_si <0x73>;
+defm V_CMPSX_GT_F64 : VOPC_Real_si <0x74>;
+defm V_CMPSX_LG_F64 : VOPC_Real_si <0x75>;
+defm V_CMPSX_GE_F64 : VOPC_Real_si <0x76>;
+defm V_CMPSX_O_F64 : VOPC_Real_si <0x77>;
+defm V_CMPSX_U_F64 : VOPC_Real_si <0x78>;
+defm V_CMPSX_NGE_F64 : VOPC_Real_si <0x79>;
+defm V_CMPSX_NLG_F64 : VOPC_Real_si <0x7a>;
+defm V_CMPSX_NGT_F64 : VOPC_Real_si <0x7b>;
+defm V_CMPSX_NLE_F64 : VOPC_Real_si <0x7c>;
+defm V_CMPSX_NEQ_F64 : VOPC_Real_si <0x7d>;
+defm V_CMPSX_NLT_F64 : VOPC_Real_si <0x7e>;
+defm V_CMPSX_TRU_F64 : VOPC_Real_si <0x7f>;
+
+defm V_CMP_F_I32 : VOPC_Real_si <0x80>;
+defm V_CMP_LT_I32 : VOPC_Real_si <0x81>;
+defm V_CMP_EQ_I32 : VOPC_Real_si <0x82>;
+defm V_CMP_LE_I32 : VOPC_Real_si <0x83>;
+defm V_CMP_GT_I32 : VOPC_Real_si <0x84>;
+defm V_CMP_NE_I32 : VOPC_Real_si <0x85>;
+defm V_CMP_GE_I32 : VOPC_Real_si <0x86>;
+defm V_CMP_T_I32 : VOPC_Real_si <0x87>;
+
+defm V_CMPX_F_I32 : VOPC_Real_si <0x90>;
+defm V_CMPX_LT_I32 : VOPC_Real_si <0x91>;
+defm V_CMPX_EQ_I32 : VOPC_Real_si <0x92>;
+defm V_CMPX_LE_I32 : VOPC_Real_si <0x93>;
+defm V_CMPX_GT_I32 : VOPC_Real_si <0x94>;
+defm V_CMPX_NE_I32 : VOPC_Real_si <0x95>;
+defm V_CMPX_GE_I32 : VOPC_Real_si <0x96>;
+defm V_CMPX_T_I32 : VOPC_Real_si <0x97>;
+
+defm V_CMP_F_I64 : VOPC_Real_si <0xa0>;
+defm V_CMP_LT_I64 : VOPC_Real_si <0xa1>;
+defm V_CMP_EQ_I64 : VOPC_Real_si <0xa2>;
+defm V_CMP_LE_I64 : VOPC_Real_si <0xa3>;
+defm V_CMP_GT_I64 : VOPC_Real_si <0xa4>;
+defm V_CMP_NE_I64 : VOPC_Real_si <0xa5>;
+defm V_CMP_GE_I64 : VOPC_Real_si <0xa6>;
+defm V_CMP_T_I64 : VOPC_Real_si <0xa7>;
+
+defm V_CMPX_F_I64 : VOPC_Real_si <0xb0>;
+defm V_CMPX_LT_I64 : VOPC_Real_si <0xb1>;
+defm V_CMPX_EQ_I64 : VOPC_Real_si <0xb2>;
+defm V_CMPX_LE_I64 : VOPC_Real_si <0xb3>;
+defm V_CMPX_GT_I64 : VOPC_Real_si <0xb4>;
+defm V_CMPX_NE_I64 : VOPC_Real_si <0xb5>;
+defm V_CMPX_GE_I64 : VOPC_Real_si <0xb6>;
+defm V_CMPX_T_I64 : VOPC_Real_si <0xb7>;
+
+defm V_CMP_F_U32 : VOPC_Real_si <0xc0>;
+defm V_CMP_LT_U32 : VOPC_Real_si <0xc1>;
+defm V_CMP_EQ_U32 : VOPC_Real_si <0xc2>;
+defm V_CMP_LE_U32 : VOPC_Real_si <0xc3>;
+defm V_CMP_GT_U32 : VOPC_Real_si <0xc4>;
+defm V_CMP_NE_U32 : VOPC_Real_si <0xc5>;
+defm V_CMP_GE_U32 : VOPC_Real_si <0xc6>;
+defm V_CMP_T_U32 : VOPC_Real_si <0xc7>;
+
+defm V_CMPX_F_U32 : VOPC_Real_si <0xd0>;
+defm V_CMPX_LT_U32 : VOPC_Real_si <0xd1>;
+defm V_CMPX_EQ_U32 : VOPC_Real_si <0xd2>;
+defm V_CMPX_LE_U32 : VOPC_Real_si <0xd3>;
+defm V_CMPX_GT_U32 : VOPC_Real_si <0xd4>;
+defm V_CMPX_NE_U32 : VOPC_Real_si <0xd5>;
+defm V_CMPX_GE_U32 : VOPC_Real_si <0xd6>;
+defm V_CMPX_T_U32 : VOPC_Real_si <0xd7>;
+
+defm V_CMP_F_U64 : VOPC_Real_si <0xe0>;
+defm V_CMP_LT_U64 : VOPC_Real_si <0xe1>;
+defm V_CMP_EQ_U64 : VOPC_Real_si <0xe2>;
+defm V_CMP_LE_U64 : VOPC_Real_si <0xe3>;
+defm V_CMP_GT_U64 : VOPC_Real_si <0xe4>;
+defm V_CMP_NE_U64 : VOPC_Real_si <0xe5>;
+defm V_CMP_GE_U64 : VOPC_Real_si <0xe6>;
+defm V_CMP_T_U64 : VOPC_Real_si <0xe7>;
+
+defm V_CMPX_F_U64 : VOPC_Real_si <0xf0>;
+defm V_CMPX_LT_U64 : VOPC_Real_si <0xf1>;
+defm V_CMPX_EQ_U64 : VOPC_Real_si <0xf2>;
+defm V_CMPX_LE_U64 : VOPC_Real_si <0xf3>;
+defm V_CMPX_GT_U64 : VOPC_Real_si <0xf4>;
+defm V_CMPX_NE_U64 : VOPC_Real_si <0xf5>;
+defm V_CMPX_GE_U64 : VOPC_Real_si <0xf6>;
+defm V_CMPX_T_U64 : VOPC_Real_si <0xf7>;
+
+defm V_CMP_CLASS_F32 : VOPC_Real_si <0x88>;
+defm V_CMPX_CLASS_F32 : VOPC_Real_si <0x98>;
+defm V_CMP_CLASS_F64 : VOPC_Real_si <0xa8>;
+defm V_CMPX_CLASS_F64 : VOPC_Real_si <0xb8>;
+
+//===----------------------------------------------------------------------===//
+// VI
+//===----------------------------------------------------------------------===//
+
+multiclass VOPC_Real_vi <bits<10> op> {
+ let AssemblerPredicates = [isVI], DecoderNamespace = "VI" in {
+ def _e32_vi :
+ VOPC_Real<!cast<VOPC_Pseudo>(NAME#"_e32"), SIEncodingFamily.VI>,
+ VOPCe<op{7-0}>;
+
+ def _e64_vi :
+ VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>,
+ VOP3a_vi <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl> {
+ // Encoding used for VOPC instructions encoded as VOP3
+ // Differs from VOP3e by destination name (sdst) as VOPC doesn't have vector dst
+ bits<8> sdst;
+ let Inst{7-0} = sdst;
+ }
+ }
+
+ def _sdwa_vi :
+ VOP_SDWA_Real <!cast<VOPC_SDWA_Pseudo>(NAME#"_sdwa")>,
+ VOPC_SDWAe <op{7-0}, !cast<VOPC_SDWA_Pseudo>(NAME#"_sdwa").Pfl>;
+
+ def : VOPCInstAlias <!cast<VOP3_Pseudo>(NAME#"_e64"),
+ !cast<Instruction>(NAME#"_e32_vi")> {
+ let AssemblerPredicate = isVI;
+ }
+}
+
+defm V_CMP_CLASS_F32 : VOPC_Real_vi <0x10>;
+defm V_CMPX_CLASS_F32 : VOPC_Real_vi <0x11>;
+defm V_CMP_CLASS_F64 : VOPC_Real_vi <0x12>;
+defm V_CMPX_CLASS_F64 : VOPC_Real_vi <0x13>;
+defm V_CMP_CLASS_F16 : VOPC_Real_vi <0x14>;
+defm V_CMPX_CLASS_F16 : VOPC_Real_vi <0x15>;
+
+defm V_CMP_F_F16 : VOPC_Real_vi <0x20>;
+defm V_CMP_LT_F16 : VOPC_Real_vi <0x21>;
+defm V_CMP_EQ_F16 : VOPC_Real_vi <0x22>;
+defm V_CMP_LE_F16 : VOPC_Real_vi <0x23>;
+defm V_CMP_GT_F16 : VOPC_Real_vi <0x24>;
+defm V_CMP_LG_F16 : VOPC_Real_vi <0x25>;
+defm V_CMP_GE_F16 : VOPC_Real_vi <0x26>;
+defm V_CMP_O_F16 : VOPC_Real_vi <0x27>;
+defm V_CMP_U_F16 : VOPC_Real_vi <0x28>;
+defm V_CMP_NGE_F16 : VOPC_Real_vi <0x29>;
+defm V_CMP_NLG_F16 : VOPC_Real_vi <0x2a>;
+defm V_CMP_NGT_F16 : VOPC_Real_vi <0x2b>;
+defm V_CMP_NLE_F16 : VOPC_Real_vi <0x2c>;
+defm V_CMP_NEQ_F16 : VOPC_Real_vi <0x2d>;
+defm V_CMP_NLT_F16 : VOPC_Real_vi <0x2e>;
+defm V_CMP_TRU_F16 : VOPC_Real_vi <0x2f>;
+
+defm V_CMPX_F_F16 : VOPC_Real_vi <0x30>;
+defm V_CMPX_LT_F16 : VOPC_Real_vi <0x31>;
+defm V_CMPX_EQ_F16 : VOPC_Real_vi <0x32>;
+defm V_CMPX_LE_F16 : VOPC_Real_vi <0x33>;
+defm V_CMPX_GT_F16 : VOPC_Real_vi <0x34>;
+defm V_CMPX_LG_F16 : VOPC_Real_vi <0x35>;
+defm V_CMPX_GE_F16 : VOPC_Real_vi <0x36>;
+defm V_CMPX_O_F16 : VOPC_Real_vi <0x37>;
+defm V_CMPX_U_F16 : VOPC_Real_vi <0x38>;
+defm V_CMPX_NGE_F16 : VOPC_Real_vi <0x39>;
+defm V_CMPX_NLG_F16 : VOPC_Real_vi <0x3a>;
+defm V_CMPX_NGT_F16 : VOPC_Real_vi <0x3b>;
+defm V_CMPX_NLE_F16 : VOPC_Real_vi <0x3c>;
+defm V_CMPX_NEQ_F16 : VOPC_Real_vi <0x3d>;
+defm V_CMPX_NLT_F16 : VOPC_Real_vi <0x3e>;
+defm V_CMPX_TRU_F16 : VOPC_Real_vi <0x3f>;
+
+defm V_CMP_F_F32 : VOPC_Real_vi <0x40>;
+defm V_CMP_LT_F32 : VOPC_Real_vi <0x41>;
+defm V_CMP_EQ_F32 : VOPC_Real_vi <0x42>;
+defm V_CMP_LE_F32 : VOPC_Real_vi <0x43>;
+defm V_CMP_GT_F32 : VOPC_Real_vi <0x44>;
+defm V_CMP_LG_F32 : VOPC_Real_vi <0x45>;
+defm V_CMP_GE_F32 : VOPC_Real_vi <0x46>;
+defm V_CMP_O_F32 : VOPC_Real_vi <0x47>;
+defm V_CMP_U_F32 : VOPC_Real_vi <0x48>;
+defm V_CMP_NGE_F32 : VOPC_Real_vi <0x49>;
+defm V_CMP_NLG_F32 : VOPC_Real_vi <0x4a>;
+defm V_CMP_NGT_F32 : VOPC_Real_vi <0x4b>;
+defm V_CMP_NLE_F32 : VOPC_Real_vi <0x4c>;
+defm V_CMP_NEQ_F32 : VOPC_Real_vi <0x4d>;
+defm V_CMP_NLT_F32 : VOPC_Real_vi <0x4e>;
+defm V_CMP_TRU_F32 : VOPC_Real_vi <0x4f>;
+
+defm V_CMPX_F_F32 : VOPC_Real_vi <0x50>;
+defm V_CMPX_LT_F32 : VOPC_Real_vi <0x51>;
+defm V_CMPX_EQ_F32 : VOPC_Real_vi <0x52>;
+defm V_CMPX_LE_F32 : VOPC_Real_vi <0x53>;
+defm V_CMPX_GT_F32 : VOPC_Real_vi <0x54>;
+defm V_CMPX_LG_F32 : VOPC_Real_vi <0x55>;
+defm V_CMPX_GE_F32 : VOPC_Real_vi <0x56>;
+defm V_CMPX_O_F32 : VOPC_Real_vi <0x57>;
+defm V_CMPX_U_F32 : VOPC_Real_vi <0x58>;
+defm V_CMPX_NGE_F32 : VOPC_Real_vi <0x59>;
+defm V_CMPX_NLG_F32 : VOPC_Real_vi <0x5a>;
+defm V_CMPX_NGT_F32 : VOPC_Real_vi <0x5b>;
+defm V_CMPX_NLE_F32 : VOPC_Real_vi <0x5c>;
+defm V_CMPX_NEQ_F32 : VOPC_Real_vi <0x5d>;
+defm V_CMPX_NLT_F32 : VOPC_Real_vi <0x5e>;
+defm V_CMPX_TRU_F32 : VOPC_Real_vi <0x5f>;
+
+defm V_CMP_F_F64 : VOPC_Real_vi <0x60>;
+defm V_CMP_LT_F64 : VOPC_Real_vi <0x61>;
+defm V_CMP_EQ_F64 : VOPC_Real_vi <0x62>;
+defm V_CMP_LE_F64 : VOPC_Real_vi <0x63>;
+defm V_CMP_GT_F64 : VOPC_Real_vi <0x64>;
+defm V_CMP_LG_F64 : VOPC_Real_vi <0x65>;
+defm V_CMP_GE_F64 : VOPC_Real_vi <0x66>;
+defm V_CMP_O_F64 : VOPC_Real_vi <0x67>;
+defm V_CMP_U_F64 : VOPC_Real_vi <0x68>;
+defm V_CMP_NGE_F64 : VOPC_Real_vi <0x69>;
+defm V_CMP_NLG_F64 : VOPC_Real_vi <0x6a>;
+defm V_CMP_NGT_F64 : VOPC_Real_vi <0x6b>;
+defm V_CMP_NLE_F64 : VOPC_Real_vi <0x6c>;
+defm V_CMP_NEQ_F64 : VOPC_Real_vi <0x6d>;
+defm V_CMP_NLT_F64 : VOPC_Real_vi <0x6e>;
+defm V_CMP_TRU_F64 : VOPC_Real_vi <0x6f>;
+
+defm V_CMPX_F_F64 : VOPC_Real_vi <0x70>;
+defm V_CMPX_LT_F64 : VOPC_Real_vi <0x71>;
+defm V_CMPX_EQ_F64 : VOPC_Real_vi <0x72>;
+defm V_CMPX_LE_F64 : VOPC_Real_vi <0x73>;
+defm V_CMPX_GT_F64 : VOPC_Real_vi <0x74>;
+defm V_CMPX_LG_F64 : VOPC_Real_vi <0x75>;
+defm V_CMPX_GE_F64 : VOPC_Real_vi <0x76>;
+defm V_CMPX_O_F64 : VOPC_Real_vi <0x77>;
+defm V_CMPX_U_F64 : VOPC_Real_vi <0x78>;
+defm V_CMPX_NGE_F64 : VOPC_Real_vi <0x79>;
+defm V_CMPX_NLG_F64 : VOPC_Real_vi <0x7a>;
+defm V_CMPX_NGT_F64 : VOPC_Real_vi <0x7b>;
+defm V_CMPX_NLE_F64 : VOPC_Real_vi <0x7c>;
+defm V_CMPX_NEQ_F64 : VOPC_Real_vi <0x7d>;
+defm V_CMPX_NLT_F64 : VOPC_Real_vi <0x7e>;
+defm V_CMPX_TRU_F64 : VOPC_Real_vi <0x7f>;
+
+defm V_CMP_F_I16 : VOPC_Real_vi <0xa0>;
+defm V_CMP_LT_I16 : VOPC_Real_vi <0xa1>;
+defm V_CMP_EQ_I16 : VOPC_Real_vi <0xa2>;
+defm V_CMP_LE_I16 : VOPC_Real_vi <0xa3>;
+defm V_CMP_GT_I16 : VOPC_Real_vi <0xa4>;
+defm V_CMP_NE_I16 : VOPC_Real_vi <0xa5>;
+defm V_CMP_GE_I16 : VOPC_Real_vi <0xa6>;
+defm V_CMP_T_I16 : VOPC_Real_vi <0xa7>;
+
+defm V_CMP_F_U16 : VOPC_Real_vi <0xa8>;
+defm V_CMP_LT_U16 : VOPC_Real_vi <0xa9>;
+defm V_CMP_EQ_U16 : VOPC_Real_vi <0xaa>;
+defm V_CMP_LE_U16 : VOPC_Real_vi <0xab>;
+defm V_CMP_GT_U16 : VOPC_Real_vi <0xac>;
+defm V_CMP_NE_U16 : VOPC_Real_vi <0xad>;
+defm V_CMP_GE_U16 : VOPC_Real_vi <0xae>;
+defm V_CMP_T_U16 : VOPC_Real_vi <0xaf>;
+
+defm V_CMPX_F_I16 : VOPC_Real_vi <0xb0>;
+defm V_CMPX_LT_I16 : VOPC_Real_vi <0xb1>;
+defm V_CMPX_EQ_I16 : VOPC_Real_vi <0xb2>;
+defm V_CMPX_LE_I16 : VOPC_Real_vi <0xb3>;
+defm V_CMPX_GT_I16 : VOPC_Real_vi <0xb4>;
+defm V_CMPX_NE_I16 : VOPC_Real_vi <0xb5>;
+defm V_CMPX_GE_I16 : VOPC_Real_vi <0xb6>;
+defm V_CMPX_T_I16 : VOPC_Real_vi <0xb7>;
+
+defm V_CMPX_F_U16 : VOPC_Real_vi <0xb8>;
+defm V_CMPX_LT_U16 : VOPC_Real_vi <0xb9>;
+defm V_CMPX_EQ_U16 : VOPC_Real_vi <0xba>;
+defm V_CMPX_LE_U16 : VOPC_Real_vi <0xbb>;
+defm V_CMPX_GT_U16 : VOPC_Real_vi <0xbc>;
+defm V_CMPX_NE_U16 : VOPC_Real_vi <0xbd>;
+defm V_CMPX_GE_U16 : VOPC_Real_vi <0xbe>;
+defm V_CMPX_T_U16 : VOPC_Real_vi <0xbf>;
+
+defm V_CMP_F_I32 : VOPC_Real_vi <0xc0>;
+defm V_CMP_LT_I32 : VOPC_Real_vi <0xc1>;
+defm V_CMP_EQ_I32 : VOPC_Real_vi <0xc2>;
+defm V_CMP_LE_I32 : VOPC_Real_vi <0xc3>;
+defm V_CMP_GT_I32 : VOPC_Real_vi <0xc4>;
+defm V_CMP_NE_I32 : VOPC_Real_vi <0xc5>;
+defm V_CMP_GE_I32 : VOPC_Real_vi <0xc6>;
+defm V_CMP_T_I32 : VOPC_Real_vi <0xc7>;
+
+defm V_CMPX_F_I32 : VOPC_Real_vi <0xd0>;
+defm V_CMPX_LT_I32 : VOPC_Real_vi <0xd1>;
+defm V_CMPX_EQ_I32 : VOPC_Real_vi <0xd2>;
+defm V_CMPX_LE_I32 : VOPC_Real_vi <0xd3>;
+defm V_CMPX_GT_I32 : VOPC_Real_vi <0xd4>;
+defm V_CMPX_NE_I32 : VOPC_Real_vi <0xd5>;
+defm V_CMPX_GE_I32 : VOPC_Real_vi <0xd6>;
+defm V_CMPX_T_I32 : VOPC_Real_vi <0xd7>;
+
+defm V_CMP_F_I64 : VOPC_Real_vi <0xe0>;
+defm V_CMP_LT_I64 : VOPC_Real_vi <0xe1>;
+defm V_CMP_EQ_I64 : VOPC_Real_vi <0xe2>;
+defm V_CMP_LE_I64 : VOPC_Real_vi <0xe3>;
+defm V_CMP_GT_I64 : VOPC_Real_vi <0xe4>;
+defm V_CMP_NE_I64 : VOPC_Real_vi <0xe5>;
+defm V_CMP_GE_I64 : VOPC_Real_vi <0xe6>;
+defm V_CMP_T_I64 : VOPC_Real_vi <0xe7>;
+
+defm V_CMPX_F_I64 : VOPC_Real_vi <0xf0>;
+defm V_CMPX_LT_I64 : VOPC_Real_vi <0xf1>;
+defm V_CMPX_EQ_I64 : VOPC_Real_vi <0xf2>;
+defm V_CMPX_LE_I64 : VOPC_Real_vi <0xf3>;
+defm V_CMPX_GT_I64 : VOPC_Real_vi <0xf4>;
+defm V_CMPX_NE_I64 : VOPC_Real_vi <0xf5>;
+defm V_CMPX_GE_I64 : VOPC_Real_vi <0xf6>;
+defm V_CMPX_T_I64 : VOPC_Real_vi <0xf7>;
+
+defm V_CMP_F_U32 : VOPC_Real_vi <0xc8>;
+defm V_CMP_LT_U32 : VOPC_Real_vi <0xc9>;
+defm V_CMP_EQ_U32 : VOPC_Real_vi <0xca>;
+defm V_CMP_LE_U32 : VOPC_Real_vi <0xcb>;
+defm V_CMP_GT_U32 : VOPC_Real_vi <0xcc>;
+defm V_CMP_NE_U32 : VOPC_Real_vi <0xcd>;
+defm V_CMP_GE_U32 : VOPC_Real_vi <0xce>;
+defm V_CMP_T_U32 : VOPC_Real_vi <0xcf>;
+
+defm V_CMPX_F_U32 : VOPC_Real_vi <0xd8>;
+defm V_CMPX_LT_U32 : VOPC_Real_vi <0xd9>;
+defm V_CMPX_EQ_U32 : VOPC_Real_vi <0xda>;
+defm V_CMPX_LE_U32 : VOPC_Real_vi <0xdb>;
+defm V_CMPX_GT_U32 : VOPC_Real_vi <0xdc>;
+defm V_CMPX_NE_U32 : VOPC_Real_vi <0xdd>;
+defm V_CMPX_GE_U32 : VOPC_Real_vi <0xde>;
+defm V_CMPX_T_U32 : VOPC_Real_vi <0xdf>;
+
+defm V_CMP_F_U64 : VOPC_Real_vi <0xe8>;
+defm V_CMP_LT_U64 : VOPC_Real_vi <0xe9>;
+defm V_CMP_EQ_U64 : VOPC_Real_vi <0xea>;
+defm V_CMP_LE_U64 : VOPC_Real_vi <0xeb>;
+defm V_CMP_GT_U64 : VOPC_Real_vi <0xec>;
+defm V_CMP_NE_U64 : VOPC_Real_vi <0xed>;
+defm V_CMP_GE_U64 : VOPC_Real_vi <0xee>;
+defm V_CMP_T_U64 : VOPC_Real_vi <0xef>;
+
+defm V_CMPX_F_U64 : VOPC_Real_vi <0xf8>;
+defm V_CMPX_LT_U64 : VOPC_Real_vi <0xf9>;
+defm V_CMPX_EQ_U64 : VOPC_Real_vi <0xfa>;
+defm V_CMPX_LE_U64 : VOPC_Real_vi <0xfb>;
+defm V_CMPX_GT_U64 : VOPC_Real_vi <0xfc>;
+defm V_CMPX_NE_U64 : VOPC_Real_vi <0xfd>;
+defm V_CMPX_GE_U64 : VOPC_Real_vi <0xfe>;
+defm V_CMPX_T_U64 : VOPC_Real_vi <0xff>;
diff --git a/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td b/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td
new file mode 100644
index 0000000..5f72f97
--- /dev/null
+++ b/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td
@@ -0,0 +1,350 @@
+//===-- VOPInstructions.td - Vector Instruction Defintions ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// dummies for outer let
+class LetDummies {
+ bit isCommutable;
+ bit isConvertibleToThreeAddress;
+ bit isMoveImm;
+ bit isReMaterializable;
+ bit isAsCheapAsAMove;
+ bit VOPAsmPrefer32Bit;
+ Predicate SubtargetPredicate;
+ string Constraints;
+ string DisableEncoding;
+ list<SchedReadWrite> SchedRW;
+ list<Register> Uses;
+ list<Register> Defs;
+}
+
+class VOP <string opName> {
+ string OpName = opName;
+}
+
+class VOPAnyCommon <dag outs, dag ins, string asm, list<dag> pattern> :
+ InstSI <outs, ins, asm, pattern> {
+
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let UseNamedOperandTable = 1;
+ let VALU = 1;
+ let Uses = [EXEC];
+}
+
+class VOP3Common <dag outs, dag ins, string asm = "",
+ list<dag> pattern = [], bit HasMods = 0,
+ bit VOP3Only = 0> :
+ VOPAnyCommon <outs, ins, asm, pattern> {
+
+ // Using complex patterns gives VOP3 patterns a very high complexity rating,
+ // but standalone patterns are almost always preferred, so we need to adjust the
+ // priority lower. The goal is to use a high number to reduce complexity to
+ // zero (or less than zero).
+ let AddedComplexity = -1000;
+
+ let VOP3 = 1;
+
+ let AsmMatchConverter =
+ !if(!eq(VOP3Only,1),
+ "cvtVOP3",
+ !if(!eq(HasMods,1), "cvtVOP3_2_mod", ""));
+
+ let AsmVariantName = AMDGPUAsmVariants.VOP3;
+
+ let isCodeGenOnly = 0;
+
+ int Size = 8;
+
+ // Because SGPRs may be allowed if there are multiple operands, we
+ // need a post-isel hook to insert copies in order to avoid
+ // violating constant bus requirements.
+ let hasPostISelHook = 1;
+}
+
+class VOP3_Pseudo <string opName, VOPProfile P, list<dag> pattern=[], bit VOP3Only = 0> :
+ InstSI <P.Outs64, P.Ins64, "", pattern>,
+ VOP <opName>,
+ SIMCInstr<opName#"_e64", SIEncodingFamily.NONE>,
+ MnemonicAlias<opName#"_e64", opName> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = P.Asm64;
+
+ let Size = 8;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let SubtargetPredicate = isGCN;
+
+ // Because SGPRs may be allowed if there are multiple operands, we
+ // need a post-isel hook to insert copies in order to avoid
+ // violating constant bus requirements.
+ let hasPostISelHook = 1;
+
+ // Using complex patterns gives VOP3 patterns a very high complexity rating,
+ // but standalone patterns are almost always preferred, so we need to adjust the
+ // priority lower. The goal is to use a high number to reduce complexity to
+ // zero (or less than zero).
+ let AddedComplexity = -1000;
+
+ let VOP3 = 1;
+ let VALU = 1;
+ let Uses = [EXEC];
+
+ let AsmVariantName = AMDGPUAsmVariants.VOP3;
+ let AsmMatchConverter =
+ !if(!eq(VOP3Only,1),
+ "cvtVOP3",
+ !if(!eq(P.HasModifiers, 1), "cvtVOP3_2_mod", ""));
+
+ VOPProfile Pfl = P;
+}
+
+class VOP3_Real <VOP3_Pseudo ps, int EncodingFamily> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
+ SIMCInstr <ps.PseudoInstr, EncodingFamily> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ // copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let AsmVariantName = ps.AsmVariantName;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+}
+
+class VOP3a<VOPProfile P> : Enc64 {
+ bits<2> src0_modifiers;
+ bits<9> src0;
+ bits<2> src1_modifiers;
+ bits<9> src1;
+ bits<2> src2_modifiers;
+ bits<9> src2;
+ bits<1> clamp;
+ bits<2> omod;
+
+ let Inst{8} = !if(P.HasSrc0Mods, src0_modifiers{1}, 0);
+ let Inst{9} = !if(P.HasSrc1Mods, src1_modifiers{1}, 0);
+ let Inst{10} = !if(P.HasSrc2Mods, src2_modifiers{1}, 0);
+
+ let Inst{31-26} = 0x34; //encoding
+ let Inst{40-32} = !if(P.HasSrc0, src0, 0);
+ let Inst{49-41} = !if(P.HasSrc1, src1, 0);
+ let Inst{58-50} = !if(P.HasSrc2, src2, 0);
+ let Inst{60-59} = !if(P.HasOMod, omod, 0);
+ let Inst{61} = !if(P.HasSrc0Mods, src0_modifiers{0}, 0);
+ let Inst{62} = !if(P.HasSrc1Mods, src1_modifiers{0}, 0);
+ let Inst{63} = !if(P.HasSrc2Mods, src2_modifiers{0}, 0);
+}
+
+class VOP3a_si <bits<9> op, VOPProfile P> : VOP3a<P> {
+ let Inst{25-17} = op;
+ let Inst{11} = !if(P.HasClamp, clamp{0}, 0);
+}
+
+class VOP3a_vi <bits<10> op, VOPProfile P> : VOP3a<P> {
+ let Inst{25-16} = op;
+ let Inst{15} = !if(P.HasClamp, clamp{0}, 0);
+}
+
+class VOP3e_si <bits<9> op, VOPProfile P> : VOP3a_si <op, P> {
+ bits<8> vdst;
+ let Inst{7-0} = !if(P.EmitDst, vdst{7-0}, 0);
+}
+
+class VOP3e_vi <bits<10> op, VOPProfile P> : VOP3a_vi <op, P> {
+ bits<8> vdst;
+ let Inst{7-0} = !if(P.EmitDst, vdst{7-0}, 0);
+}
+
+class VOP3be <VOPProfile P> : Enc64 {
+ bits<8> vdst;
+ bits<2> src0_modifiers;
+ bits<9> src0;
+ bits<2> src1_modifiers;
+ bits<9> src1;
+ bits<2> src2_modifiers;
+ bits<9> src2;
+ bits<7> sdst;
+ bits<2> omod;
+
+ let Inst{7-0} = vdst;
+ let Inst{14-8} = sdst;
+ let Inst{31-26} = 0x34; //encoding
+ let Inst{40-32} = !if(P.HasSrc0, src0, 0);
+ let Inst{49-41} = !if(P.HasSrc1, src1, 0);
+ let Inst{58-50} = !if(P.HasSrc2, src2, 0);
+ let Inst{60-59} = !if(P.HasOMod, omod, 0);
+ let Inst{61} = !if(P.HasSrc0Mods, src0_modifiers{0}, 0);
+ let Inst{62} = !if(P.HasSrc1Mods, src1_modifiers{0}, 0);
+ let Inst{63} = !if(P.HasSrc2Mods, src2_modifiers{0}, 0);
+}
+
+class VOP3be_si <bits<9> op, VOPProfile P> : VOP3be<P> {
+ let Inst{25-17} = op;
+}
+
+class VOP3be_vi <bits<10> op, VOPProfile P> : VOP3be<P> {
+ bits<1> clamp;
+ let Inst{25-16} = op;
+ let Inst{15} = !if(P.HasClamp, clamp{0}, 0);
+}
+
+def SDWA {
+ // sdwa_sel
+ int BYTE_0 = 0;
+ int BYTE_1 = 1;
+ int BYTE_2 = 2;
+ int BYTE_3 = 3;
+ int WORD_0 = 4;
+ int WORD_1 = 5;
+ int DWORD = 6;
+
+ // dst_unused
+ int UNUSED_PAD = 0;
+ int UNUSED_SEXT = 1;
+ int UNUSED_PRESERVE = 2;
+}
+
+class VOP_SDWAe<VOPProfile P> : Enc64 {
+ bits<8> src0;
+ bits<3> src0_sel;
+ bits<2> src0_modifiers; // float: {abs,neg}, int {sext}
+ bits<3> src1_sel;
+ bits<2> src1_modifiers;
+ bits<3> dst_sel;
+ bits<2> dst_unused;
+ bits<1> clamp;
+
+ let Inst{39-32} = !if(P.HasSrc0, src0{7-0}, 0);
+ let Inst{42-40} = !if(P.EmitDst, dst_sel{2-0}, SDWA.DWORD);
+ let Inst{44-43} = !if(P.EmitDst, dst_unused{1-0}, SDWA.UNUSED_PRESERVE);
+ let Inst{45} = !if(P.HasSDWAClamp, clamp{0}, 0);
+ let Inst{50-48} = !if(P.HasSrc0, src0_sel{2-0}, SDWA.DWORD);
+ let Inst{53-52} = !if(P.HasSrc0FloatMods, src0_modifiers{1-0}, 0);
+ let Inst{51} = !if(P.HasSrc0IntMods, src0_modifiers{0}, 0);
+ let Inst{58-56} = !if(P.HasSrc1, src1_sel{2-0}, SDWA.DWORD);
+ let Inst{61-60} = !if(P.HasSrc1FloatMods, src1_modifiers{1-0}, 0);
+ let Inst{59} = !if(P.HasSrc1IntMods, src1_modifiers{0}, 0);
+}
+
+class VOP_SDWA_Pseudo <string opName, VOPProfile P, list<dag> pattern=[]> :
+ InstSI <P.OutsSDWA, P.InsSDWA, "", pattern>,
+ VOP <opName>,
+ SIMCInstr <opName#"_sdwa", SIEncodingFamily.NONE>,
+ MnemonicAlias <opName#"_sdwa", opName> {
+
+ let isPseudo = 1;
+ let isCodeGenOnly = 1;
+ let UseNamedOperandTable = 1;
+
+ string Mnemonic = opName;
+ string AsmOperands = P.AsmSDWA;
+
+ let Size = 8;
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+
+ let VALU = 1;
+ let SDWA = 1;
+ let Uses = [EXEC];
+
+ let SubtargetPredicate = isVI;
+ let AssemblerPredicate = !if(P.HasExt, isVI, DisableInst);
+ let AsmVariantName = !if(P.HasExt, AMDGPUAsmVariants.SDWA,
+ AMDGPUAsmVariants.Disable);
+ let DecoderNamespace = "SDWA";
+
+ VOPProfile Pfl = P;
+}
+
+class VOP_SDWA_Real <VOP_SDWA_Pseudo ps> :
+ InstSI <ps.OutOperandList, ps.InOperandList, ps.Mnemonic # ps.AsmOperands, []>,
+ SIMCInstr <ps.PseudoInstr, SIEncodingFamily.VI> {
+
+ let isPseudo = 0;
+ let isCodeGenOnly = 0;
+
+ let Defs = ps.Defs;
+ let Uses = ps.Uses;
+ let SchedRW = ps.SchedRW;
+ let hasSideEffects = ps.hasSideEffects;
+
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+
+ // Copy relevant pseudo op flags
+ let SubtargetPredicate = ps.SubtargetPredicate;
+ let AssemblerPredicate = ps.AssemblerPredicate;
+ let AsmMatchConverter = ps.AsmMatchConverter;
+ let AsmVariantName = ps.AsmVariantName;
+ let UseNamedOperandTable = ps.UseNamedOperandTable;
+ let DecoderNamespace = ps.DecoderNamespace;
+ let Constraints = ps.Constraints;
+ let DisableEncoding = ps.DisableEncoding;
+ let TSFlags = ps.TSFlags;
+}
+
+class VOP_DPPe<VOPProfile P> : Enc64 {
+ bits<2> src0_modifiers;
+ bits<8> src0;
+ bits<2> src1_modifiers;
+ bits<9> dpp_ctrl;
+ bits<1> bound_ctrl;
+ bits<4> bank_mask;
+ bits<4> row_mask;
+
+ let Inst{39-32} = !if(P.HasSrc0, src0{7-0}, 0);
+ let Inst{48-40} = dpp_ctrl;
+ let Inst{51} = bound_ctrl;
+ let Inst{52} = !if(P.HasSrc0Mods, src0_modifiers{0}, 0); // src0_neg
+ let Inst{53} = !if(P.HasSrc0Mods, src0_modifiers{1}, 0); // src0_abs
+ let Inst{54} = !if(P.HasSrc1Mods, src1_modifiers{0}, 0); // src1_neg
+ let Inst{55} = !if(P.HasSrc1Mods, src1_modifiers{1}, 0); // src1_abs
+ let Inst{59-56} = bank_mask;
+ let Inst{63-60} = row_mask;
+}
+
+class VOP_DPP <string OpName, VOPProfile P> :
+ InstSI <P.OutsDPP, P.InsDPP, OpName#P.AsmDPP, []>,
+ VOP_DPPe<P> {
+
+ let mayLoad = 0;
+ let mayStore = 0;
+ let hasSideEffects = 0;
+ let UseNamedOperandTable = 1;
+
+ let VALU = 1;
+ let DPP = 1;
+ let Size = 8;
+
+ let AsmMatchConverter = !if(!eq(P.HasModifiers,1), "cvtDPP", "");
+ let SubtargetPredicate = isVI;
+ let AssemblerPredicate = !if(P.HasExt, isVI, DisableInst);
+ let AsmVariantName = !if(P.HasExt, AMDGPUAsmVariants.DPP,
+ AMDGPUAsmVariants.Disable);
+ let DecoderNamespace = "DPP";
+}
+
+include "VOPCInstructions.td"
+include "VOP1Instructions.td"
+include "VOP2Instructions.td"
+include "VOP3Instructions.td"
diff --git a/contrib/llvm/lib/Target/ARM/A15SDOptimizer.cpp b/contrib/llvm/lib/Target/ARM/A15SDOptimizer.cpp
index 9228cc2..89859ba 100644
--- a/contrib/llvm/lib/Target/ARM/A15SDOptimizer.cpp
+++ b/contrib/llvm/lib/Target/ARM/A15SDOptimizer.cpp
@@ -52,9 +52,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &Fn) override;
- const char *getPassName() const override {
- return "ARM A15 S->D optimizer";
- }
+ StringRef getPassName() const override { return "ARM A15 S->D optimizer"; }
private:
const ARMBaseInstrInfo *TII;
diff --git a/contrib/llvm/lib/Target/ARM/ARM.h b/contrib/llvm/lib/Target/ARM/ARM.h
index 690ff86..be30482 100644
--- a/contrib/llvm/lib/Target/ARM/ARM.h
+++ b/contrib/llvm/lib/Target/ARM/ARM.h
@@ -16,6 +16,7 @@
#define LLVM_LIB_TARGET_ARM_ARM_H
#include "llvm/Support/CodeGen.h"
+#include "ARMBasicBlockInfo.h"
#include <functional>
namespace llvm {
@@ -46,6 +47,10 @@ FunctionPass *createThumb2SizeReductionPass(
void LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
ARMAsmPrinter &AP);
+void computeBlockSize(MachineFunction *MF, MachineBasicBlock *MBB,
+ BasicBlockInfo &BBI);
+std::vector<BasicBlockInfo> computeAllBlockSizes(MachineFunction *MF);
+
void initializeARMLoadStoreOptPass(PassRegistry &);
void initializeARMPreAllocLoadStoreOptPass(PassRegistry &);
diff --git a/contrib/llvm/lib/Target/ARM/ARM.td b/contrib/llvm/lib/Target/ARM/ARM.td
index ef626b6..2a090fa 100644
--- a/contrib/llvm/lib/Target/ARM/ARM.td
+++ b/contrib/llvm/lib/Target/ARM/ARM.td
@@ -99,6 +99,8 @@ def FeatureCRC : SubtargetFeature<"crc", "HasCRC", "true",
// Not to be confused with FeatureHasRetAddrStack (return address stack)
def FeatureRAS : SubtargetFeature<"ras", "HasRAS", "true",
"Enable Reliability, Availability and Serviceability extensions">;
+def FeatureFPAO : SubtargetFeature<"fpao", "HasFPAO", "true",
+ "Enable fast computation of positive address offsets">;
// Cyclone has preferred instructions for zeroing VFP registers, which can
@@ -295,7 +297,8 @@ def HasV7Ops : SubtargetFeature<"v7", "HasV7Ops", "true",
FeatureV7Clrex]>;
def HasV8Ops : SubtargetFeature<"v8", "HasV8Ops", "true",
"Support ARM v8 instructions",
- [HasV7Ops, FeatureAcquireRelease]>;
+ [HasV7Ops, FeatureAcquireRelease,
+ FeatureT2XtPk]>;
def HasV8_1aOps : SubtargetFeature<"v8.1a", "HasV8_1aOps", "true",
"Support ARM v8.1a instructions",
[HasV8Ops]>;
@@ -352,6 +355,8 @@ def ProcR5 : SubtargetFeature<"r5", "ARMProcFamily", "CortexR5",
"Cortex-R5 ARM processors", []>;
def ProcR7 : SubtargetFeature<"r7", "ARMProcFamily", "CortexR7",
"Cortex-R7 ARM processors", []>;
+def ProcR52 : SubtargetFeature<"r52", "ARMProcFamily", "CortexR52",
+ "Cortex-R52 ARM processors", []>;
def ProcM3 : SubtargetFeature<"m3", "ARMProcFamily", "CortexM3",
"Cortex-M3 ARM processors", []>;
@@ -388,7 +393,8 @@ def ARMv5tej : Architecture<"armv5tej", "ARMv5tej", [HasV5TEOps]>;
def ARMv6 : Architecture<"armv6", "ARMv6", [HasV6Ops]>;
def ARMv6t2 : Architecture<"armv6t2", "ARMv6t2", [HasV6T2Ops,
- FeatureDSP]>;
+ FeatureDSP,
+ FeatureT2XtPk]>;
def ARMv6k : Architecture<"armv6k", "ARMv6k", [HasV6KOps]>;
@@ -409,13 +415,15 @@ def ARMv7a : Architecture<"armv7-a", "ARMv7a", [HasV7Ops,
FeatureNEON,
FeatureDB,
FeatureDSP,
- FeatureAClass]>;
+ FeatureAClass,
+ FeatureT2XtPk]>;
def ARMv7r : Architecture<"armv7-r", "ARMv7r", [HasV7Ops,
FeatureDB,
FeatureDSP,
FeatureHWDiv,
- FeatureRClass]>;
+ FeatureRClass,
+ FeatureT2XtPk]>;
def ARMv7m : Architecture<"armv7-m", "ARMv7m", [HasV7Ops,
FeatureThumb2,
@@ -470,6 +478,19 @@ def ARMv82a : Architecture<"armv8.2-a", "ARMv82a", [HasV8_2aOps,
FeatureCRC,
FeatureRAS]>;
+def ARMv8r : Architecture<"armv8-r", "ARMv8r", [HasV8Ops,
+ FeatureRClass,
+ FeatureDB,
+ FeatureHWDiv,
+ FeatureHWDivARM,
+ FeatureT2XtPk,
+ FeatureDSP,
+ FeatureCRC,
+ FeatureMP,
+ FeatureVirtualization,
+ FeatureFPARMv8,
+ FeatureNEON]>;
+
def ARMv8mBaseline : Architecture<"armv8-m.base", "ARMv8mBaseline",
[HasV8MBaselineOps,
FeatureNoARM,
@@ -570,7 +591,6 @@ def : ProcessorModel<"cortex-a5", CortexA8Model, [ARMv7a, ProcA5,
FeatureSlowFPBrcc,
FeatureHasSlowFPVMLx,
FeatureVMLxForwarding,
- FeatureT2XtPk,
FeatureMP,
FeatureVFP4]>;
@@ -581,7 +601,6 @@ def : ProcessorModel<"cortex-a7", CortexA8Model, [ARMv7a, ProcA7,
FeatureHasVMLxHazards,
FeatureHasSlowFPVMLx,
FeatureVMLxForwarding,
- FeatureT2XtPk,
FeatureMP,
FeatureVFP4,
FeatureHWDiv,
@@ -595,15 +614,13 @@ def : ProcessorModel<"cortex-a8", CortexA8Model, [ARMv7a, ProcA8,
FeatureSlowFPBrcc,
FeatureHasVMLxHazards,
FeatureHasSlowFPVMLx,
- FeatureVMLxForwarding,
- FeatureT2XtPk]>;
+ FeatureVMLxForwarding]>;
def : ProcessorModel<"cortex-a9", CortexA9Model, [ARMv7a, ProcA9,
FeatureHasRetAddrStack,
FeatureTrustZone,
FeatureHasVMLxHazards,
FeatureVMLxForwarding,
- FeatureT2XtPk,
FeatureFP16,
FeatureAvoidPartialCPSR,
FeatureExpandMLx,
@@ -618,7 +635,6 @@ def : ProcessorModel<"cortex-a12", CortexA9Model, [ARMv7a, ProcA12,
FeatureHasRetAddrStack,
FeatureTrustZone,
FeatureVMLxForwarding,
- FeatureT2XtPk,
FeatureVFP4,
FeatureHWDiv,
FeatureHWDivARM,
@@ -632,7 +648,6 @@ def : ProcessorModel<"cortex-a15", CortexA9Model, [ARMv7a, ProcA15,
FeatureHasRetAddrStack,
FeatureMuxedUnits,
FeatureTrustZone,
- FeatureT2XtPk,
FeatureVFP4,
FeatureMP,
FeatureCheckVLDnAlign,
@@ -647,7 +662,6 @@ def : ProcessorModel<"cortex-a17", CortexA9Model, [ARMv7a, ProcA17,
FeatureTrustZone,
FeatureMP,
FeatureVMLxForwarding,
- FeatureT2XtPk,
FeatureVFP4,
FeatureHWDiv,
FeatureHWDivARM,
@@ -662,7 +676,6 @@ def : ProcessorModel<"krait", CortexA9Model, [ARMv7a, ProcKrait,
FeatureMuxedUnits,
FeatureCheckVLDnAlign,
FeatureVMLxForwarding,
- FeatureT2XtPk,
FeatureFP16,
FeatureAvoidPartialCPSR,
FeatureVFP4,
@@ -672,7 +685,6 @@ def : ProcessorModel<"krait", CortexA9Model, [ARMv7a, ProcKrait,
def : ProcessorModel<"swift", SwiftModel, [ARMv7a, ProcSwift,
FeatureHasRetAddrStack,
FeatureNEONForFP,
- FeatureT2XtPk,
FeatureVFP4,
FeatureMP,
FeatureHWDiv,
@@ -691,8 +703,7 @@ def : ProcessorModel<"swift", SwiftModel, [ARMv7a, ProcSwift,
// FIXME: R4 has currently the same ProcessorModel as A8.
def : ProcessorModel<"cortex-r4", CortexA8Model, [ARMv7r, ProcR4,
FeatureHasRetAddrStack,
- FeatureAvoidPartialCPSR,
- FeatureT2XtPk]>;
+ FeatureAvoidPartialCPSR]>;
// FIXME: R4F has currently the same ProcessorModel as A8.
def : ProcessorModel<"cortex-r4f", CortexA8Model, [ARMv7r, ProcR4,
@@ -701,8 +712,7 @@ def : ProcessorModel<"cortex-r4f", CortexA8Model, [ARMv7r, ProcR4,
FeatureHasSlowFPVMLx,
FeatureVFP3,
FeatureD16,
- FeatureAvoidPartialCPSR,
- FeatureT2XtPk]>;
+ FeatureAvoidPartialCPSR]>;
// FIXME: R5 has currently the same ProcessorModel as A8.
def : ProcessorModel<"cortex-r5", CortexA8Model, [ARMv7r, ProcR5,
@@ -712,8 +722,7 @@ def : ProcessorModel<"cortex-r5", CortexA8Model, [ARMv7r, ProcR5,
FeatureSlowFPBrcc,
FeatureHWDivARM,
FeatureHasSlowFPVMLx,
- FeatureAvoidPartialCPSR,
- FeatureT2XtPk]>;
+ FeatureAvoidPartialCPSR]>;
// FIXME: R7 has currently the same ProcessorModel as A8 and is modelled as R5.
def : ProcessorModel<"cortex-r7", CortexA8Model, [ARMv7r, ProcR7,
@@ -725,8 +734,7 @@ def : ProcessorModel<"cortex-r7", CortexA8Model, [ARMv7r, ProcR7,
FeatureSlowFPBrcc,
FeatureHWDivARM,
FeatureHasSlowFPVMLx,
- FeatureAvoidPartialCPSR,
- FeatureT2XtPk]>;
+ FeatureAvoidPartialCPSR]>;
def : ProcessorModel<"cortex-r8", CortexA8Model, [ARMv7r,
FeatureHasRetAddrStack,
@@ -737,8 +745,7 @@ def : ProcessorModel<"cortex-r8", CortexA8Model, [ARMv7r,
FeatureSlowFPBrcc,
FeatureHWDivARM,
FeatureHasSlowFPVMLx,
- FeatureAvoidPartialCPSR,
- FeatureT2XtPk]>;
+ FeatureAvoidPartialCPSR]>;
def : ProcNoItin<"cortex-m3", [ARMv7m, ProcM3]>;
def : ProcNoItin<"sc300", [ARMv7m, ProcM3]>;
@@ -755,42 +762,38 @@ def : ProcNoItin<"cortex-m7", [ARMv7em,
def : ProcNoItin<"cortex-a32", [ARMv8a,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
FeatureCRC]>;
def : ProcNoItin<"cortex-a35", [ARMv8a, ProcA35,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
FeatureCRC]>;
def : ProcNoItin<"cortex-a53", [ARMv8a, ProcA53,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
- FeatureCRC]>;
+ FeatureCRC,
+ FeatureFPAO]>;
def : ProcNoItin<"cortex-a57", [ARMv8a, ProcA57,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
- FeatureCRC]>;
+ FeatureCRC,
+ FeatureFPAO]>;
def : ProcNoItin<"cortex-a72", [ARMv8a, ProcA72,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
FeatureCRC]>;
def : ProcNoItin<"cortex-a73", [ARMv8a, ProcA73,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
FeatureCRC]>;
@@ -798,7 +801,6 @@ def : ProcNoItin<"cortex-a73", [ARMv8a, ProcA73,
def : ProcessorModel<"cyclone", SwiftModel, [ARMv8a, ProcSwift,
FeatureHasRetAddrStack,
FeatureNEONForFP,
- FeatureT2XtPk,
FeatureVFP4,
FeatureMP,
FeatureHWDiv,
@@ -812,10 +814,24 @@ def : ProcessorModel<"cyclone", SwiftModel, [ARMv8a, ProcSwift,
def : ProcNoItin<"exynos-m1", [ARMv8a, ProcExynosM1,
FeatureHWDiv,
FeatureHWDivARM,
- FeatureT2XtPk,
FeatureCrypto,
FeatureCRC]>;
+def : ProcNoItin<"exynos-m2", [ARMv8a, ProcExynosM1,
+ FeatureHWDiv,
+ FeatureHWDivARM,
+ FeatureCrypto,
+ FeatureCRC]>;
+
+def : ProcNoItin<"exynos-m3", [ARMv8a, ProcExynosM1,
+ FeatureHWDiv,
+ FeatureHWDivARM,
+ FeatureCrypto,
+ FeatureCRC]>;
+
+def : ProcessorModel<"cortex-r52", CortexR52Model, [ARMv8r, ProcR52,
+ FeatureFPAO]>;
+
//===----------------------------------------------------------------------===//
// Register File Description
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
index 04863a7..95db35c 100644
--- a/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -74,8 +74,9 @@ void ARMAsmPrinter::EmitFunctionEntryLabel() {
if (AFI->isThumbFunction()) {
OutStreamer->EmitAssemblerFlag(MCAF_Code16);
OutStreamer->EmitThumbFunc(CurrentFnSym);
+ } else {
+ OutStreamer->EmitAssemblerFlag(MCAF_Code32);
}
-
OutStreamer->EmitLabel(CurrentFnSym);
}
@@ -96,6 +97,13 @@ void ARMAsmPrinter::EmitXXStructor(const DataLayout &DL, const Constant *CV) {
OutStreamer->EmitValue(E, Size);
}
+void ARMAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
+ if (PromotedGlobals.count(GV))
+ // The global was promoted into a constant pool. It should not be emitted.
+ return;
+ AsmPrinter::EmitGlobalVariable(GV);
+}
+
/// runOnMachineFunction - This uses the EmitInstruction()
/// method to print assembly for each instruction.
///
@@ -108,6 +116,12 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
const Function* F = MF.getFunction();
const TargetMachine& TM = MF.getTarget();
+ // Collect all globals that had their storage promoted to a constant pool.
+ // Functions are emitted before variables, so this accumulates promoted
+ // globals from all functions in PromotedGlobals.
+ for (auto *GV : AFI->getGlobalsPromotedToConstantPool())
+ PromotedGlobals.insert(GV);
+
// Calculate this function's optimization goal.
unsigned OptimizationGoal;
if (F->hasFnAttribute(Attribute::OptimizeNone))
@@ -150,6 +164,9 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
// Emit the rest of the function body.
EmitFunctionBody();
+ // Emit the XRay table for this function.
+ emitXRayTable();
+
// If we need V4T thumb mode Register Indirect Jump pads, emit them.
// These are created per function, rather than per TU, since it's
// relatively easy to exceed the thumb branch range within a TU.
@@ -215,6 +232,8 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
break;
}
case MachineOperand::MO_ConstantPoolIndex:
+ if (Subtarget->genExecuteOnly())
+ llvm_unreachable("execute-only should not generate constant pools");
GetCPISymbol(MO.getIndex())->print(O, MAI);
break;
}
@@ -249,7 +268,7 @@ bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
<< "]";
return false;
}
- // Fallthrough
+ LLVM_FALLTHROUGH;
case 'c': // Don't print "#" before an immediate operand.
if (!MI->getOperand(OpNum).isImm())
return true;
@@ -542,11 +561,11 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
raw_string_ostream OS(Flags);
for (const auto &Function : M)
- TLOF.emitLinkerFlagsForGlobal(OS, &Function, *Mang);
+ TLOF.emitLinkerFlagsForGlobal(OS, &Function);
for (const auto &Global : M.globals())
- TLOF.emitLinkerFlagsForGlobal(OS, &Global, *Mang);
+ TLOF.emitLinkerFlagsForGlobal(OS, &Global);
for (const auto &Alias : M.aliases())
- TLOF.emitLinkerFlagsForGlobal(OS, &Alias, *Mang);
+ TLOF.emitLinkerFlagsForGlobal(OS, &Alias);
OS.flush();
@@ -588,9 +607,11 @@ static ARMBuildAttrs::CPUArch getArchForCPU(StringRef CPU,
if (CPU == "xscale")
return ARMBuildAttrs::v5TEJ;
- if (Subtarget->hasV8Ops())
+ if (Subtarget->hasV8Ops()) {
+ if (Subtarget->isRClass())
+ return ARMBuildAttrs::v8_R;
return ARMBuildAttrs::v8_A;
- else if (Subtarget->hasV8MMainlineOps())
+ } else if (Subtarget->hasV8MMainlineOps())
return ARMBuildAttrs::v8_M_Main;
else if (Subtarget->hasV7Ops()) {
if (Subtarget->isMClass() && Subtarget->hasDSP())
@@ -614,6 +635,15 @@ static ARMBuildAttrs::CPUArch getArchForCPU(StringRef CPU,
return ARMBuildAttrs::v4;
}
+// Returns true if all functions have the same function attribute value.
+// It also returns true when the module has no functions.
+static bool checkFunctionsAttributeConsistency(const Module &M, StringRef Attr,
+ StringRef Value) {
+ return !any_of(M, [&](const Function &F) {
+ return F.getFnAttribute(Attr).getValueAsString() != Value;
+ });
+}
+
void ARMAsmPrinter::emitAttributes() {
MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
@@ -725,31 +755,48 @@ void ARMAsmPrinter::emitAttributes() {
ATS.emitFPU(ARM::FK_VFPV2);
}
+ // RW data addressing.
if (isPositionIndependent()) {
- // PIC specific attributes.
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
ARMBuildAttrs::AddressRWPCRel);
+ } else if (STI.isRWPI()) {
+ // RWPI specific attributes.
+ ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
+ ARMBuildAttrs::AddressRWSBRel);
+ }
+
+ // RO data addressing.
+ if (isPositionIndependent() || STI.isROPI()) {
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RO_data,
ARMBuildAttrs::AddressROPCRel);
+ }
+
+ // GOT use.
+ if (isPositionIndependent()) {
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
ARMBuildAttrs::AddressGOT);
} else {
- // Allow direct addressing of imported data for all other relocation models.
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
ARMBuildAttrs::AddressDirect);
}
- // Signal various FP modes.
- if (!TM.Options.UnsafeFPMath) {
+ // Set FP Denormals.
+ if (checkFunctionsAttributeConsistency(*MMI->getModule(),
+ "denormal-fp-math",
+ "preserve-sign") ||
+ TM.Options.FPDenormalMode == FPDenormal::PreserveSign)
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::PreserveFPSign);
+ else if (checkFunctionsAttributeConsistency(*MMI->getModule(),
+ "denormal-fp-math",
+ "positive-zero") ||
+ TM.Options.FPDenormalMode == FPDenormal::PositiveZero)
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
+ ARMBuildAttrs::PositiveZero);
+ else if (!TM.Options.UnsafeFPMath)
ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal,
ARMBuildAttrs::IEEEDenormals);
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions, ARMBuildAttrs::Allowed);
-
- // If the user has permitted this code to choose the IEEE 754
- // rounding at run-time, emit the rounding attribute.
- if (TM.Options.HonorSignDependentRoundingFPMathOption)
- ATS.emitAttribute(ARMBuildAttrs::ABI_FP_rounding, ARMBuildAttrs::Allowed);
- } else {
+ else {
if (!STI.hasVFP2()) {
// When the target doesn't have an FPU (by design or
// intention), the assumptions made on the software support
@@ -775,6 +822,21 @@ void ARMAsmPrinter::emitAttributes() {
// absence of its emission implies zero).
}
+ // Set FP exceptions and rounding
+ if (checkFunctionsAttributeConsistency(*MMI->getModule(),
+ "no-trapping-math", "true") ||
+ TM.Options.NoTrappingFPMath)
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions,
+ ARMBuildAttrs::Not_Allowed);
+ else if (!TM.Options.UnsafeFPMath) {
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions, ARMBuildAttrs::Allowed);
+
+ // If the user has permitted this code to choose the IEEE 754
+ // rounding at run-time, emit the rounding attribute.
+ if (TM.Options.HonorSignDependentRoundingFPMathOption)
+ ATS.emitAttribute(ARMBuildAttrs::ABI_FP_rounding, ARMBuildAttrs::Allowed);
+ }
+
// TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath is the
// equivalent of GCC's -ffinite-math-only flag.
if (TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath)
@@ -858,14 +920,16 @@ void ARMAsmPrinter::emitAttributes() {
}
}
- // TODO: We currently only support either reserving the register, or treating
- // it as another callee-saved register, but not as SB or a TLS pointer; It
- // would instead be nicer to push this from the frontend as metadata, as we do
- // for the wchar and enum size tags
- if (STI.isR9Reserved())
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9Reserved);
+ // We currently do not support using R9 as the TLS pointer.
+ if (STI.isRWPI())
+ ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsSB);
+ else if (STI.isR9Reserved())
+ ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9Reserved);
else
- ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9IsGPR);
+ ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
+ ARMBuildAttrs::R9IsGPR);
if (STI.hasTrustZone() && STI.hasVirtualization())
ATS.emitAttribute(ARMBuildAttrs::Virtualization_use,
@@ -880,7 +944,7 @@ void ARMAsmPrinter::emitAttributes() {
//===----------------------------------------------------------------------===//
-static MCSymbol *getPICLabel(const char *Prefix, unsigned FunctionNumber,
+static MCSymbol *getPICLabel(StringRef Prefix, unsigned FunctionNumber,
unsigned LabelId, MCContext &Ctx) {
MCSymbol *Label = Ctx.getOrCreateSymbol(Twine(Prefix)
@@ -899,6 +963,8 @@ getModifierVariantKind(ARMCP::ARMCPModifier Modifier) {
return MCSymbolRefExpr::VK_TPOFF;
case ARMCP::GOTTPOFF:
return MCSymbolRefExpr::VK_GOTTPOFF;
+ case ARMCP::SBREL:
+ return MCSymbolRefExpr::VK_ARM_SBREL;
case ARMCP::GOT_PREL:
return MCSymbolRefExpr::VK_ARM_GOT_PREL;
case ARMCP::SECREL:
@@ -954,6 +1020,26 @@ EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV);
+ if (ACPV->isPromotedGlobal()) {
+ // This constant pool entry is actually a global whose storage has been
+ // promoted into the constant pool. This global may be referenced still
+ // by debug information, and due to the way AsmPrinter is set up, the debug
+ // info is immutable by the time we decide to promote globals to constant
+ // pools. Because of this, we need to ensure we emit a symbol for the global
+ // with private linkage (the default) so debug info can refer to it.
+ //
+ // However, if this global is promoted into several functions we must ensure
+ // we don't try and emit duplicate symbols!
+ auto *ACPC = cast<ARMConstantPoolConstant>(ACPV);
+ auto *GV = ACPC->getPromotedGlobal();
+ if (!EmittedPromotedGlobalLabels.count(GV)) {
+ MCSymbol *GVSym = getSymbol(GV);
+ OutStreamer->EmitLabel(GVSym);
+ EmittedPromotedGlobalLabels.insert(GV);
+ }
+ return EmitGlobalConstant(DL, ACPC->getPromotedGlobalInit());
+ }
+
MCSymbol *MCSym;
if (ACPV->isLSDA()) {
MCSym = getCurExceptionSym();
@@ -973,7 +1059,7 @@ EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
MCSym = MBB->getSymbol();
} else {
assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
- const char *Sym = cast<ARMConstantPoolSymbol>(ACPV)->getSymbol();
+ auto Sym = cast<ARMConstantPoolSymbol>(ACPV)->getSymbol();
MCSym = GetExternalSymbolSymbol(Sym);
}
@@ -1037,7 +1123,7 @@ void ARMAsmPrinter::EmitJumpTableAddrs(const MachineInstr *MI) {
// .word (LBB1 - LJTI_0_0)
const MCExpr *Expr = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
- if (isPositionIndependent())
+ if (isPositionIndependent() || Subtarget->isROPI())
Expr = MCBinaryExpr::createSub(Expr, MCSymbolRefExpr::create(JTISymbol,
OutContext),
OutContext);
@@ -1082,6 +1168,9 @@ void ARMAsmPrinter::EmitJumpTableTBInst(const MachineInstr *MI,
const MachineOperand &MO1 = MI->getOperand(1);
unsigned JTI = MO1.getIndex();
+ if (Subtarget->isThumb1Only())
+ EmitAlignment(2);
+
MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel(JTI);
OutStreamer->EmitLabel(JTISymbol);
@@ -1628,6 +1717,91 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
.addReg(0));
return;
}
+ case ARM::tTBB_JT:
+ case ARM::tTBH_JT: {
+
+ bool Is8Bit = MI->getOpcode() == ARM::tTBB_JT;
+ unsigned Base = MI->getOperand(0).getReg();
+ unsigned Idx = MI->getOperand(1).getReg();
+ assert(MI->getOperand(1).isKill() && "We need the index register as scratch!");
+
+ // Multiply up idx if necessary.
+ if (!Is8Bit)
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLSLri)
+ .addReg(Idx)
+ .addReg(ARM::CPSR)
+ .addReg(Idx)
+ .addImm(1)
+ // Add predicate operands.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+
+ if (Base == ARM::PC) {
+ // TBB [base, idx] =
+ // ADDS idx, idx, base
+ // LDRB idx, [idx, #4] ; or LDRH if TBH
+ // LSLS idx, #1
+ // ADDS pc, pc, idx
+
+ // When using PC as the base, it's important that there is no padding
+ // between the last ADDS and the start of the jump table. The jump table
+ // is 4-byte aligned, so we ensure we're 4 byte aligned here too.
+ //
+ // FIXME: Ideally we could vary the LDRB index based on the padding
+ // between the sequence and jump table, however that relies on MCExprs
+ // for load indexes which are currently not supported.
+ OutStreamer->EmitCodeAlignment(4);
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tADDhirr)
+ .addReg(Idx)
+ .addReg(Idx)
+ .addReg(Base)
+ // Add predicate operands.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+
+ unsigned Opc = Is8Bit ? ARM::tLDRBi : ARM::tLDRHi;
+ EmitToStreamer(*OutStreamer, MCInstBuilder(Opc)
+ .addReg(Idx)
+ .addReg(Idx)
+ .addImm(Is8Bit ? 4 : 2)
+ // Add predicate operands.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ } else {
+ // TBB [base, idx] =
+ // LDRB idx, [base, idx] ; or LDRH if TBH
+ // LSLS idx, #1
+ // ADDS pc, pc, idx
+
+ unsigned Opc = Is8Bit ? ARM::tLDRBr : ARM::tLDRHr;
+ EmitToStreamer(*OutStreamer, MCInstBuilder(Opc)
+ .addReg(Idx)
+ .addReg(Base)
+ .addReg(Idx)
+ // Add predicate operands.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ }
+
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLSLri)
+ .addReg(Idx)
+ .addReg(ARM::CPSR)
+ .addReg(Idx)
+ .addImm(1)
+ // Add predicate operands.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+
+ OutStreamer->EmitLabel(GetCPISymbol(MI->getOperand(3).getImm()));
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tADDhirr)
+ .addReg(ARM::PC)
+ .addReg(ARM::PC)
+ .addReg(Idx)
+ // Add predicate operands.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ return;
+ }
case ARM::tBR_JTr:
case ARM::BR_JTr: {
// Lower and emit the instruction itself, then the jump table following it.
@@ -1961,6 +2135,15 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
.addReg(0));
return;
}
+ case ARM::PATCHABLE_FUNCTION_ENTER:
+ LowerPATCHABLE_FUNCTION_ENTER(*MI);
+ return;
+ case ARM::PATCHABLE_FUNCTION_EXIT:
+ LowerPATCHABLE_FUNCTION_EXIT(*MI);
+ return;
+ case ARM::PATCHABLE_TAIL_CALL:
+ LowerPATCHABLE_TAIL_CALL(*MI);
+ return;
}
MCInst TmpInst;
@@ -1975,8 +2158,8 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Force static initialization.
extern "C" void LLVMInitializeARMAsmPrinter() {
- RegisterAsmPrinter<ARMAsmPrinter> X(TheARMLETarget);
- RegisterAsmPrinter<ARMAsmPrinter> Y(TheARMBETarget);
- RegisterAsmPrinter<ARMAsmPrinter> A(TheThumbLETarget);
- RegisterAsmPrinter<ARMAsmPrinter> B(TheThumbBETarget);
+ RegisterAsmPrinter<ARMAsmPrinter> X(getTheARMLETarget());
+ RegisterAsmPrinter<ARMAsmPrinter> Y(getTheARMBETarget());
+ RegisterAsmPrinter<ARMAsmPrinter> A(getTheThumbLETarget());
+ RegisterAsmPrinter<ARMAsmPrinter> B(getTheThumbBETarget());
}
diff --git a/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.h b/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.h
index 97f5ca0..93fed10 100644
--- a/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.h
+++ b/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.h
@@ -56,12 +56,22 @@ class LLVM_LIBRARY_VISIBILITY ARMAsmPrinter : public AsmPrinter {
/// -1 if uninitialized, 0 if conflicting goals
int OptimizationGoals;
+ /// List of globals that have had their storage promoted to a constant
+ /// pool. This lives between calls to runOnMachineFunction and collects
+ /// data from every MachineFunction. It is used during doFinalization
+ /// when all non-function globals are emitted.
+ SmallPtrSet<const GlobalVariable*,2> PromotedGlobals;
+ /// Set of globals in PromotedGlobals that we've emitted labels for.
+ /// We need to emit labels even for promoted globals so that DWARF
+ /// debug info can link properly.
+ SmallPtrSet<const GlobalVariable*,2> EmittedPromotedGlobalLabels;
+
public:
explicit ARMAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer);
- const char *getPassName() const override {
- return "ARM Assembly / Object Emitter";
+ StringRef getPassName() const override {
+ return "ARM Assembly Printer";
}
void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
@@ -90,11 +100,22 @@ public:
void EmitStartOfAsmFile(Module &M) override;
void EmitEndOfAsmFile(Module &M) override;
void EmitXXStructor(const DataLayout &DL, const Constant *CV) override;
-
+ void EmitGlobalVariable(const GlobalVariable *GV) override;
+
// lowerOperand - Convert a MachineOperand into the equivalent MCOperand.
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp);
+ //===------------------------------------------------------------------===//
+ // XRay implementation
+ //===------------------------------------------------------------------===//
+public:
+ // XRay-specific lowering for ARM.
+ void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
+ void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
+ void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
+
private:
+ void EmitSled(const MachineInstr &MI, SledKind Kind);
// Helpers for EmitStartOfAsmFile() and EmitEndOfAsmFile()
void emitAttributes();
diff --git a/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 693f164..70a3246 100644
--- a/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -382,7 +382,10 @@ bool ARMBaseInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
}
-unsigned ARMBaseInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned ARMBaseInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end())
return 0;
@@ -406,11 +409,13 @@ unsigned ARMBaseInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return 2;
}
-unsigned ARMBaseInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned ARMBaseInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(!BytesAdded && "code size not handled");
ARMFunctionInfo *AFI = MBB.getParent()->getInfo<ARMFunctionInfo>();
int BOpc = !AFI->isThumbFunction()
? ARM::B : (AFI->isThumb2Function() ? ARM::t2B : ARM::tB);
@@ -419,7 +424,7 @@ unsigned ARMBaseInstrInfo::InsertBranch(MachineBasicBlock &MBB,
bool isThumb = AFI->isThumbFunction() || AFI->isThumb2Function();
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"ARM branch conditions have two components!");
@@ -448,7 +453,7 @@ unsigned ARMBaseInstrInfo::InsertBranch(MachineBasicBlock &MBB,
}
bool ARMBaseInstrInfo::
-ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
ARMCC::CondCodes CC = (ARMCC::CondCodes)(int)Cond[0].getImm();
Cond[0].setImm(ARMCC::getOppositeCondition(CC));
return false;
@@ -575,6 +580,9 @@ bool ARMBaseInstrInfo::isPredicable(MachineInstr &MI) const {
if (!MI.isPredicable())
return false;
+ if (MI.isBundle())
+ return false;
+
if (!isEligibleForITBlock(&MI))
return false;
@@ -610,7 +618,7 @@ template <> bool IsCPSRDead<MachineInstr>(MachineInstr *MI) {
/// GetInstSize - Return the size of the specified MachineInstr.
///
-unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
+unsigned ARMBaseInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
const MachineBasicBlock &MBB = *MI.getParent();
const MachineFunction *MF = MBB.getParent();
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
@@ -669,7 +677,7 @@ unsigned ARMBaseInstrInfo::getInstBundleLength(const MachineInstr &MI) const {
MachineBasicBlock::const_instr_iterator E = MI.getParent()->instr_end();
while (++I != E && I->isInsideBundle()) {
assert(!I->isBundle() && "No nested bundle!");
- Size += GetInstSizeInBytes(*I);
+ Size += getInstSizeInBytes(*I);
}
return Size;
}
@@ -868,7 +876,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
MachineMemOperand *MMO = MF.getMachineMemOperand(
@@ -1051,7 +1059,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
@@ -2069,29 +2077,40 @@ bool llvm::tryFoldSPUpdateIntoPushPop(const ARMSubtarget &Subtarget,
int RegListIdx = IsT1PushPop ? 2 : 4;
// Calculate the space we'll need in terms of registers.
- unsigned FirstReg = MI->getOperand(RegListIdx).getReg();
- unsigned RD0Reg, RegsNeeded;
+ unsigned RegsNeeded;
+ const TargetRegisterClass *RegClass;
if (IsVFPPushPop) {
- RD0Reg = ARM::D0;
RegsNeeded = NumBytes / 8;
+ RegClass = &ARM::DPRRegClass;
} else {
- RD0Reg = ARM::R0;
RegsNeeded = NumBytes / 4;
+ RegClass = &ARM::GPRRegClass;
}
// We're going to have to strip all list operands off before
// re-adding them since the order matters, so save the existing ones
// for later.
SmallVector<MachineOperand, 4> RegList;
- for (int i = MI->getNumOperands() - 1; i >= RegListIdx; --i)
- RegList.push_back(MI->getOperand(i));
+
+ // We're also going to need the first register transferred by this
+ // instruction, which won't necessarily be the first register in the list.
+ unsigned FirstRegEnc = -1;
const TargetRegisterInfo *TRI = MF.getRegInfo().getTargetRegisterInfo();
+ for (int i = MI->getNumOperands() - 1; i >= RegListIdx; --i) {
+ MachineOperand &MO = MI->getOperand(i);
+ RegList.push_back(MO);
+
+ if (MO.isReg() && TRI->getEncodingValue(MO.getReg()) < FirstRegEnc)
+ FirstRegEnc = TRI->getEncodingValue(MO.getReg());
+ }
+
const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF);
// Now try to find enough space in the reglist to allocate NumBytes.
- for (unsigned CurReg = FirstReg - 1; CurReg >= RD0Reg && RegsNeeded;
- --CurReg) {
+ for (int CurRegEnc = FirstRegEnc - 1; CurRegEnc >= 0 && RegsNeeded;
+ --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
@@ -2291,6 +2310,7 @@ bool ARMBaseInstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
default: break;
case ARM::CMPri:
case ARM::t2CMPri:
+ case ARM::tCMPi8:
SrcReg = MI.getOperand(0).getReg();
SrcReg2 = 0;
CmpMask = ~0;
@@ -2477,8 +2497,21 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
if (isPredicated(*MI))
return false;
+ bool IsThumb1 = false;
switch (MI->getOpcode()) {
default: break;
+ case ARM::tLSLri:
+ case ARM::tLSRri:
+ case ARM::tLSLrr:
+ case ARM::tLSRrr:
+ case ARM::tSUBrr:
+ case ARM::tADDrr:
+ case ARM::tADDi3:
+ case ARM::tADDi8:
+ case ARM::tSUBi3:
+ case ARM::tSUBi8:
+ IsThumb1 = true;
+ LLVM_FALLTHROUGH;
case ARM::RSBrr:
case ARM::RSBri:
case ARM::RSCrr:
@@ -2511,7 +2544,11 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
case ARM::EORrr:
case ARM::EORri:
case ARM::t2EORrr:
- case ARM::t2EORri: {
+ case ARM::t2EORri:
+ case ARM::t2LSRri:
+ case ARM::t2LSRrr:
+ case ARM::t2LSLri:
+ case ARM::t2LSLrr: {
// Scan forward for the use of CPSR
// When checking against MI: if it's a conditional code that requires
// checking of the V bit or C bit, then this is not safe to do.
@@ -2618,9 +2655,12 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
return false;
}
- // Toggle the optional operand to CPSR.
- MI->getOperand(5).setReg(ARM::CPSR);
- MI->getOperand(5).setIsDef(true);
+ // Toggle the optional operand to CPSR (if it exists - in Thumb1 we always
+ // set CPSR so this is represented as an explicit output)
+ if (!IsThumb1) {
+ MI->getOperand(5).setReg(ARM::CPSR);
+ MI->getOperand(5).setIsDef(true);
+ }
assert(!isPredicated(*MI) && "Can't use flags from predicated instruction");
CmpInstr.eraseFromParent();
@@ -2632,7 +2672,7 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
return true;
}
}
-
+
return false;
}
@@ -4119,6 +4159,9 @@ bool ARMBaseInstrInfo::verifyInstruction(const MachineInstr &MI,
void ARMBaseInstrInfo::expandLoadStackGuardBase(MachineBasicBlock::iterator MI,
unsigned LoadImmOpc,
unsigned LoadOpc) const {
+ assert(!Subtarget.isROPI() && !Subtarget.isRWPI() &&
+ "ROPI/RWPI not currently supported with stack guard");
+
MachineBasicBlock &MBB = *MI->getParent();
DebugLoc DL = MI->getDebugLoc();
unsigned Reg = MI->getOperand(0).getReg();
@@ -4132,7 +4175,9 @@ void ARMBaseInstrInfo::expandLoadStackGuardBase(MachineBasicBlock::iterator MI,
if (Subtarget.isGVIndirectSymbol(GV)) {
MIB = BuildMI(MBB, MI, DL, get(LoadOpc), Reg);
MIB.addReg(Reg, RegState::Kill).addImm(0);
- auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant;
+ auto Flags = MachineMemOperand::MOLoad |
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant;
MachineMemOperand *MMO = MBB.getParent()->getMachineMemOperand(
MachinePointerInfo::getGOT(*MBB.getParent()), Flags, 4, 4);
MIB.addMemOperand(MMO);
diff --git a/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.h b/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
index 52b0ff1..b01d5c8 100644
--- a/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
+++ b/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
@@ -100,6 +100,10 @@ public:
// Return whether the target has an explicit NOP encoding.
bool hasNOP() const;
+ virtual void getNoopForElfTarget(MCInst &NopInst) const {
+ getNoopForMachoTarget(NopInst);
+ }
+
// Return the non-pre/post incrementing version of 'Opc'. Return 0
// if there is not such an opcode.
virtual unsigned getUnindexedOpcode(unsigned Opc) const =0;
@@ -124,13 +128,15 @@ public:
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
// Predication support.
bool isPredicated(const MachineInstr &MI) const override;
@@ -154,7 +160,7 @@ public:
/// GetInstSize - Returns the size of the specified MachineInstr.
///
- virtual unsigned GetInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
unsigned isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const override;
diff --git a/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index aa968ef..d995c63 100644
--- a/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -49,18 +49,13 @@ ARMBaseRegisterInfo::ARMBaseRegisterInfo()
: ARMGenRegisterInfo(ARM::LR, 0, 0, ARM::PC), BasePtr(ARM::R6) {}
static unsigned getFramePointerReg(const ARMSubtarget &STI) {
- if (STI.isTargetMachO())
- return ARM::R7;
- else if (STI.isTargetWindows())
- return ARM::R11;
- else // ARM EABI
- return STI.isThumb() ? ARM::R7 : ARM::R11;
+ return STI.useR7AsFramePointer() ? ARM::R7 : ARM::R11;
}
const MCPhysReg*
ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
const ARMSubtarget &STI = MF->getSubtarget<ARMSubtarget>();
- bool UseSplitPush = STI.splitFramePushPop();
+ bool UseSplitPush = STI.splitFramePushPop(*MF);
const MCPhysReg *RegList =
STI.isTargetDarwin()
? CSR_iOS_SaveList
@@ -136,6 +131,15 @@ ARMBaseRegisterInfo::getTLSCallPreservedMask(const MachineFunction &MF) const {
return CSR_iOS_TLSCall_RegMask;
}
+const uint32_t *
+ARMBaseRegisterInfo::getSjLjDispatchPreservedMask(const MachineFunction &MF) const {
+ const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>();
+ if (!STI.useSoftFloat() && STI.hasVFP2() && !STI.isThumb1Only())
+ return CSR_NoRegs_RegMask;
+ else
+ return CSR_FPRegs_RegMask;
+}
+
const uint32_t *
ARMBaseRegisterInfo::getThisReturnPreservedMask(const MachineFunction &MF,
@@ -163,27 +167,29 @@ getReservedRegs(const MachineFunction &MF) const {
// FIXME: avoid re-calculating this every time.
BitVector Reserved(getNumRegs());
- Reserved.set(ARM::SP);
- Reserved.set(ARM::PC);
- Reserved.set(ARM::FPSCR);
- Reserved.set(ARM::APSR_NZCV);
+ markSuperRegs(Reserved, ARM::SP);
+ markSuperRegs(Reserved, ARM::PC);
+ markSuperRegs(Reserved, ARM::FPSCR);
+ markSuperRegs(Reserved, ARM::APSR_NZCV);
if (TFI->hasFP(MF))
- Reserved.set(getFramePointerReg(STI));
+ markSuperRegs(Reserved, getFramePointerReg(STI));
if (hasBasePointer(MF))
- Reserved.set(BasePtr);
+ markSuperRegs(Reserved, BasePtr);
// Some targets reserve R9.
if (STI.isR9Reserved())
- Reserved.set(ARM::R9);
+ markSuperRegs(Reserved, ARM::R9);
// Reserve D16-D31 if the subtarget doesn't support them.
if (!STI.hasVFP3() || STI.hasD16()) {
static_assert(ARM::D31 == ARM::D16 + 15, "Register list not consecutive!");
- Reserved.set(ARM::D16, ARM::D31 + 1);
+ for (unsigned R = 0; R < 16; ++R)
+ markSuperRegs(Reserved, ARM::D16 + R);
}
const TargetRegisterClass *RC = &ARM::GPRPairRegClass;
for(TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); I!=E; ++I)
for (MCSubRegIterator SI(*I, this); SI.isValid(); ++SI)
- if (Reserved.test(*SI)) Reserved.set(*I);
+ if (Reserved.test(*SI)) markSuperRegs(Reserved, *I);
+ assert(checkAllSuperRegsMarked(Reserved));
return Reserved;
}
@@ -289,8 +295,7 @@ ARMBaseRegisterInfo::getRegAllocationHints(unsigned VirtReg,
}
// First prefer the paired physreg.
- if (PairedPhys &&
- std::find(Order.begin(), Order.end(), PairedPhys) != Order.end())
+ if (PairedPhys && is_contained(Order, PairedPhys))
Hints.push_back(PairedPhys);
// Then prefer even or odd registers.
@@ -332,7 +337,7 @@ ARMBaseRegisterInfo::updateRegAllocHint(unsigned Reg, unsigned NewReg,
}
bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
const ARMFrameLowering *TFI = getFrameLowering(MF);
@@ -347,14 +352,14 @@ bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
// It's going to be better to use the SP or Base Pointer instead. When there
// are variable sized objects, we can't reference off of the SP, so we
// reserve a Base Pointer.
- if (AFI->isThumbFunction() && MFI->hasVarSizedObjects()) {
+ if (AFI->isThumbFunction() && MFI.hasVarSizedObjects()) {
// Conservatively estimate whether the negative offset from the frame
// pointer will be sufficient to reach. If a function has a smallish
// frame, it's less likely to have lots of spills and callee saved
// space, so it's all more likely to be within range of the frame pointer.
// If it's wrong, the scavenger will still enable access to work, it just
// won't be optimal.
- if (AFI->isThumb2Function() && MFI->getLocalFrameSize() < 128)
+ if (AFI->isThumb2Function() && MFI.getLocalFrameSize() < 128)
return false;
return true;
}
@@ -389,10 +394,10 @@ bool ARMBaseRegisterInfo::canRealignStack(const MachineFunction &MF) const {
bool ARMBaseRegisterInfo::
cannotEliminateFrame(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- if (MF.getTarget().Options.DisableFramePointerElim(MF) && MFI->adjustsStack())
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (MF.getTarget().Options.DisableFramePointerElim(MF) && MFI.adjustsStack())
return true;
- return MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken()
+ return MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken()
|| needsStackRealignment(MF);
}
@@ -536,7 +541,7 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const {
// so it'll be negative.
MachineFunction &MF = *MI->getParent()->getParent();
const ARMFrameLowering *TFI = getFrameLowering(MF);
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
// Estimate an offset from the frame pointer.
@@ -551,7 +556,7 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const {
// The incoming offset is relating to the SP at the start of the function,
// but when we access the local it'll be relative to the SP after local
// allocation, so adjust our SP-relative offset by that allocation size.
- Offset += MFI->getLocalFrameSize();
+ Offset += MFI.getLocalFrameSize();
// Assume that we'll have at least some spill slots allocated.
// FIXME: This is a total SWAG number. We should run some statistics
// and pick a real one.
@@ -563,7 +568,7 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const {
// on whether there are any local variables that would trigger it.
unsigned StackAlign = TFI->getStackAlignment();
if (TFI->hasFP(MF) &&
- !((MFI->getLocalFrameMaxAlign() > StackAlign) && canRealignStack(MF))) {
+ !((MFI.getLocalFrameMaxAlign() > StackAlign) && canRealignStack(MF))) {
if (isFrameOffsetLegal(MI, getFrameRegister(MF), FPOffset))
return false;
}
@@ -572,7 +577,7 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const {
// to only disallow SP relative references in the live range of
// the VLA(s). In practice, it's unclear how much difference that
// would make, but it may be worth doing.
- if (!MFI->hasVarSizedObjects() && isFrameOffsetLegal(MI, ARM::SP, Offset))
+ if (!MFI.hasVarSizedObjects() && isFrameOffsetLegal(MI, ARM::SP, Offset))
return false;
// The offset likely isn't legal, we want to allocate a virtual base register.
@@ -730,7 +735,7 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
assert(TFI->hasReservedCallFrame(MF) &&
"Cannot use SP to access the emergency spill slot in "
"functions without a reserved call frame");
- assert(!MF.getFrameInfo()->hasVarSizedObjects() &&
+ assert(!MF.getFrameInfo().hasVarSizedObjects() &&
"Cannot use SP to access the emergency spill slot in "
"functions with variable sized frame objects");
}
diff --git a/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h b/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
index 1eee948..330e153 100644
--- a/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
+++ b/contrib/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
@@ -99,11 +99,12 @@ public:
/// Code Generation virtual methods...
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
const MCPhysReg *
- getCalleeSavedRegsViaCopy(const MachineFunction *MF) const override;
+ getCalleeSavedRegsViaCopy(const MachineFunction *MF) const;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const override;
const uint32_t *getNoPreservedMask() const override;
const uint32_t *getTLSCallPreservedMask(const MachineFunction &MF) const;
+ const uint32_t *getSjLjDispatchPreservedMask(const MachineFunction &MF) const;
/// getThisReturnPreservedMask - Returns a call preserved mask specific to the
/// case that 'returned' is on an i32 first argument if the calling convention
diff --git a/contrib/llvm/lib/Target/ARM/ARMBasicBlockInfo.h b/contrib/llvm/lib/Target/ARM/ARMBasicBlockInfo.h
new file mode 100644
index 0000000..780544f
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMBasicBlockInfo.h
@@ -0,0 +1,110 @@
+//===-- ARMBasicBlockInfo.h - Basic Block Information -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility functions and data structure for computing block size.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_ARM_ARMBASICBLOCKINFO_H
+#define LLVM_LIB_TARGET_ARM_ARMBASICBLOCKINFO_H
+
+#include "ARM.h"
+#include "ARMMachineFunctionInfo.h"
+using namespace llvm;
+
+namespace llvm {
+
+/// UnknownPadding - Return the worst case padding that could result from
+/// unknown offset bits. This does not include alignment padding caused by
+/// known offset bits.
+///
+/// @param LogAlign log2(alignment)
+/// @param KnownBits Number of known low offset bits.
+inline unsigned UnknownPadding(unsigned LogAlign, unsigned KnownBits) {
+ if (KnownBits < LogAlign)
+ return (1u << LogAlign) - (1u << KnownBits);
+ return 0;
+}
+
+/// BasicBlockInfo - Information about the offset and size of a single
+/// basic block.
+struct BasicBlockInfo {
+ /// Offset - Distance from the beginning of the function to the beginning
+ /// of this basic block.
+ ///
+ /// Offsets are computed assuming worst case padding before an aligned
+ /// block. This means that subtracting basic block offsets always gives a
+ /// conservative estimate of the real distance which may be smaller.
+ ///
+ /// Because worst case padding is used, the computed offset of an aligned
+ /// block may not actually be aligned.
+ unsigned Offset;
+
+ /// Size - Size of the basic block in bytes. If the block contains
+ /// inline assembly, this is a worst case estimate.
+ ///
+ /// The size does not include any alignment padding whether from the
+ /// beginning of the block, or from an aligned jump table at the end.
+ unsigned Size;
+
+ /// KnownBits - The number of low bits in Offset that are known to be
+ /// exact. The remaining bits of Offset are an upper bound.
+ uint8_t KnownBits;
+
+ /// Unalign - When non-zero, the block contains instructions (inline asm)
+ /// of unknown size. The real size may be smaller than Size bytes by a
+ /// multiple of 1 << Unalign.
+ uint8_t Unalign;
+
+ /// PostAlign - When non-zero, the block terminator contains a .align
+ /// directive, so the end of the block is aligned to 1 << PostAlign
+ /// bytes.
+ uint8_t PostAlign;
+
+ BasicBlockInfo() : Offset(0), Size(0), KnownBits(0), Unalign(0),
+ PostAlign(0) {}
+
+ /// Compute the number of known offset bits internally to this block.
+ /// This number should be used to predict worst case padding when
+ /// splitting the block.
+ unsigned internalKnownBits() const {
+ unsigned Bits = Unalign ? Unalign : KnownBits;
+ // If the block size isn't a multiple of the known bits, assume the
+ // worst case padding.
+ if (Size & ((1u << Bits) - 1))
+ Bits = countTrailingZeros(Size);
+ return Bits;
+ }
+
+ /// Compute the offset immediately following this block. If LogAlign is
+ /// specified, return the offset the successor block will get if it has
+ /// this alignment.
+ unsigned postOffset(unsigned LogAlign = 0) const {
+ unsigned PO = Offset + Size;
+ unsigned LA = std::max(unsigned(PostAlign), LogAlign);
+ if (!LA)
+ return PO;
+ // Add alignment padding from the terminator.
+ return PO + UnknownPadding(LA, internalKnownBits());
+ }
+
+ /// Compute the number of known low bits of postOffset. If this block
+ /// contains inline asm, the number of known bits drops to the
+ /// instruction alignment. An aligned terminator may increase the number
+ /// of know bits.
+ /// If LogAlign is given, also consider the alignment of the next block.
+ unsigned postKnownBits(unsigned LogAlign = 0) const {
+ return std::max(std::max(unsigned(PostAlign), LogAlign),
+ internalKnownBits());
+ }
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/ARM/ARMCallLowering.cpp b/contrib/llvm/lib/Target/ARM/ARMCallLowering.cpp
new file mode 100644
index 0000000..52c95b6
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMCallLowering.cpp
@@ -0,0 +1,203 @@
+//===-- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the lowering of LLVM calls to machine code calls for
+/// GlobalISel.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ARMCallLowering.h"
+
+#include "ARMBaseInstrInfo.h"
+#include "ARMISelLowering.h"
+
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "This shouldn't be built without GISel"
+#endif
+
+ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI)
+ : CallLowering(&TLI) {}
+
+static bool isSupportedType(const DataLayout DL, const ARMTargetLowering &TLI,
+ Type *T) {
+ EVT VT = TLI.getValueType(DL, T);
+ if (!VT.isSimple() || !VT.isInteger() || VT.isVector())
+ return false;
+
+ unsigned VTSize = VT.getSimpleVT().getSizeInBits();
+ return VTSize == 8 || VTSize == 16 || VTSize == 32;
+}
+
+namespace {
+struct FuncReturnHandler : public CallLowering::ValueHandler {
+ FuncReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
+ MachineInstrBuilder &MIB)
+ : ValueHandler(MIRBuilder, MRI), MIB(MIB) {}
+
+ unsigned getStackAddress(uint64_t Size, int64_t Offset,
+ MachinePointerInfo &MPO) override {
+ llvm_unreachable("Don't know how to get a stack address yet");
+ }
+
+ void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
+ CCValAssign &VA) override {
+ assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
+ assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
+
+ assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
+ assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
+
+ assert(VA.getLocInfo() != CCValAssign::SExt &&
+ VA.getLocInfo() != CCValAssign::ZExt &&
+ "ABI extensions not supported yet");
+
+ MIRBuilder.buildCopy(PhysReg, ValVReg);
+ MIB.addUse(PhysReg, RegState::Implicit);
+ }
+
+ void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
+ MachinePointerInfo &MPO, CCValAssign &VA) override {
+ llvm_unreachable("Don't know how to assign a value to an address yet");
+ }
+
+ MachineInstrBuilder &MIB;
+};
+} // End anonymous namespace.
+
+/// Lower the return value for the already existing \p Ret. This assumes that
+/// \p MIRBuilder's insertion point is correct.
+bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
+ const Value *Val, unsigned VReg,
+ MachineInstrBuilder &Ret) const {
+ if (!Val)
+ // Nothing to do here.
+ return true;
+
+ auto &MF = MIRBuilder.getMF();
+ const auto &F = *MF.getFunction();
+
+ auto DL = MF.getDataLayout();
+ auto &TLI = *getTLI<ARMTargetLowering>();
+ if (!isSupportedType(DL, TLI, Val->getType()))
+ return false;
+
+ CCAssignFn *AssignFn =
+ TLI.CCAssignFnForReturn(F.getCallingConv(), F.isVarArg());
+
+ ArgInfo RetInfo(VReg, Val->getType());
+ setArgFlags(RetInfo, AttributeSet::ReturnIndex, DL, F);
+
+ FuncReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);
+ return handleAssignments(MIRBuilder, AssignFn, RetInfo, RetHandler);
+}
+
+bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
+ const Value *Val, unsigned VReg) const {
+ assert(!Val == !VReg && "Return value without a vreg");
+
+ auto Ret = AddDefaultPred(MIRBuilder.buildInstrNoInsert(ARM::BX_RET));
+
+ if (!lowerReturnVal(MIRBuilder, Val, VReg, Ret))
+ return false;
+
+ MIRBuilder.insertInstr(Ret);
+ return true;
+}
+
+namespace {
+struct FormalArgHandler : public CallLowering::ValueHandler {
+ FormalArgHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
+ : ValueHandler(MIRBuilder, MRI) {}
+
+ unsigned getStackAddress(uint64_t Size, int64_t Offset,
+ MachinePointerInfo &MPO) override {
+ assert(Size == 4 && "Unsupported size");
+
+ auto &MFI = MIRBuilder.getMF().getFrameInfo();
+
+ int FI = MFI.CreateFixedObject(Size, Offset, true);
+ MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);
+
+ unsigned AddrReg =
+ MRI.createGenericVirtualRegister(LLT::pointer(MPO.getAddrSpace(), 32));
+ MIRBuilder.buildFrameIndex(AddrReg, FI);
+
+ return AddrReg;
+ }
+
+ void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
+ MachinePointerInfo &MPO, CCValAssign &VA) override {
+ assert(Size == 4 && "Unsupported size");
+
+ auto MMO = MIRBuilder.getMF().getMachineMemOperand(
+ MPO, MachineMemOperand::MOLoad, Size, /* Alignment */ 0);
+ MIRBuilder.buildLoad(ValVReg, Addr, *MMO);
+ }
+
+ void assignValueToReg(unsigned ValVReg, unsigned PhysReg,
+ CCValAssign &VA) override {
+ assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
+ assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
+
+ assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
+ assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
+
+ MIRBuilder.getMBB().addLiveIn(PhysReg);
+ MIRBuilder.buildCopy(ValVReg, PhysReg);
+ }
+};
+} // End anonymous namespace
+
+bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
+ const Function &F,
+ ArrayRef<unsigned> VRegs) const {
+ // Quick exit if there aren't any args
+ if (F.arg_empty())
+ return true;
+
+ if (F.isVarArg())
+ return false;
+
+ auto DL = MIRBuilder.getMF().getDataLayout();
+ auto &TLI = *getTLI<ARMTargetLowering>();
+
+ auto &Args = F.getArgumentList();
+ unsigned ArgIdx = 0;
+ for (auto &Arg : Args) {
+ ArgIdx++;
+ if (!isSupportedType(DL, TLI, Arg.getType()))
+ return false;
+
+ // FIXME: This check as well as ArgIdx are going away as soon as we support
+ // loading values < 32 bits.
+ if (ArgIdx > 4 && Arg.getType()->getIntegerBitWidth() != 32)
+ return false;
+ }
+
+ CCAssignFn *AssignFn =
+ TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
+
+ SmallVector<ArgInfo, 8> ArgInfos;
+ unsigned Idx = 0;
+ for (auto &Arg : Args) {
+ ArgInfo AInfo(VRegs[Idx], Arg.getType());
+ setArgFlags(AInfo, Idx + 1, DL, F);
+ ArgInfos.push_back(AInfo);
+ Idx++;
+ }
+
+ FormalArgHandler ArgHandler(MIRBuilder, MIRBuilder.getMF().getRegInfo());
+ return handleAssignments(MIRBuilder, AssignFn, ArgInfos, ArgHandler);
+}
diff --git a/contrib/llvm/lib/Target/ARM/ARMCallLowering.h b/contrib/llvm/lib/Target/ARM/ARMCallLowering.h
new file mode 100644
index 0000000..6a1b886
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMCallLowering.h
@@ -0,0 +1,42 @@
+//===-- llvm/lib/Target/ARM/ARMCallLowering.h - Call lowering -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file describes how to lower LLVM calls to machine code calls.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_ARM_ARMCALLLOWERING
+#define LLVM_LIB_TARGET_ARM_ARMCALLLOWERING
+
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/CodeGen/ValueTypes.h"
+
+namespace llvm {
+
+class ARMTargetLowering;
+class MachineInstrBuilder;
+
+class ARMCallLowering : public CallLowering {
+public:
+ ARMCallLowering(const ARMTargetLowering &TLI);
+
+ bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val,
+ unsigned VReg) const override;
+
+ bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
+ ArrayRef<unsigned> VRegs) const override;
+
+private:
+ bool lowerReturnVal(MachineIRBuilder &MIRBuilder, const Value *Val,
+ unsigned VReg, MachineInstrBuilder &Ret) const;
+};
+} // End of namespace llvm
+#endif
diff --git a/contrib/llvm/lib/Target/ARM/ARMCallingConv.td b/contrib/llvm/lib/Target/ARM/ARMCallingConv.td
index edb6958..7a7b7fe 100644
--- a/contrib/llvm/lib/Target/ARM/ARMCallingConv.td
+++ b/contrib/llvm/lib/Target/ARM/ARMCallingConv.td
@@ -26,8 +26,8 @@ def CC_ARM_APCS : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
- // A SwiftError is passed in R6.
- CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
+ // A SwiftError is passed in R8.
+ CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R8]>>>,
// Handle all vector types as either f64 or v2f64.
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
@@ -51,8 +51,8 @@ def RetCC_ARM_APCS : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
- // A SwiftError is returned in R6.
- CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
+ // A SwiftError is returned in R8.
+ CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R8]>>>,
// Handle all vector types as either f64 or v2f64.
CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
@@ -166,8 +166,8 @@ def CC_ARM_AAPCS : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
- // A SwiftError is passed in R6.
- CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
+ // A SwiftError is passed in R8.
+ CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R8]>>>,
CCIfType<[f64, v2f64], CCCustom<"CC_ARM_AAPCS_Custom_f64">>,
CCIfType<[f32], CCBitConvertToType<i32>>,
@@ -182,8 +182,8 @@ def RetCC_ARM_AAPCS : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
- // A SwiftError is returned in R6.
- CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
+ // A SwiftError is returned in R8.
+ CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R8]>>>,
CCIfType<[f64, v2f64], CCCustom<"RetCC_ARM_AAPCS_Custom_f64">>,
CCIfType<[f32], CCBitConvertToType<i32>>,
@@ -206,8 +206,8 @@ def CC_ARM_AAPCS_VFP : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
- // A SwiftError is passed in R6.
- CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
+ // A SwiftError is passed in R8.
+ CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R8]>>>,
// HFAs are passed in a contiguous block of registers, or on the stack
CCIfConsecutiveRegs<CCCustom<"CC_ARM_AAPCS_Custom_Aggregate">>,
@@ -227,8 +227,8 @@ def RetCC_ARM_AAPCS_VFP : CallingConv<[
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
- // A SwiftError is returned in R6.
- CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R6]>>>,
+ // A SwiftError is returned in R8.
+ CCIfSwiftError<CCIfType<[i32], CCAssignToReg<[R8]>>>,
CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>,
CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>,
@@ -242,6 +242,7 @@ def RetCC_ARM_AAPCS_VFP : CallingConv<[
//===----------------------------------------------------------------------===//
def CSR_NoRegs : CalleeSavedRegs<(add)>;
+def CSR_FPRegs : CalleeSavedRegs<(add (sequence "D%u", 0, 31))>;
def CSR_AAPCS : CalleeSavedRegs<(add LR, R11, R10, R9, R8, R7, R6, R5, R4,
(sequence "D%u", 15, 8))>;
@@ -266,8 +267,8 @@ def CSR_AAPCS_ThisReturn : CalleeSavedRegs<(add LR, R11, R10, R9, R8, R7, R6,
// Also save R7-R4 first to match the stack frame fixed spill areas.
def CSR_iOS : CalleeSavedRegs<(add LR, R7, R6, R5, R4, (sub CSR_AAPCS, R9))>;
-// R6 is used to pass swifterror, remove it from CSR.
-def CSR_iOS_SwiftError : CalleeSavedRegs<(sub CSR_iOS, R6)>;
+// R8 is used to pass swifterror, remove it from CSR.
+def CSR_iOS_SwiftError : CalleeSavedRegs<(sub CSR_iOS, R8)>;
def CSR_iOS_ThisReturn : CalleeSavedRegs<(add LR, R7, R6, R5, R4,
(sub CSR_AAPCS_ThisReturn, R9))>;
diff --git a/contrib/llvm/lib/Target/ARM/ARMComputeBlockSize.cpp b/contrib/llvm/lib/Target/ARM/ARMComputeBlockSize.cpp
new file mode 100644
index 0000000..64f187d
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMComputeBlockSize.cpp
@@ -0,0 +1,72 @@
+//===--- ARMComputeBlockSize.cpp - Compute machine block sizes ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARM.h"
+#include "ARMBasicBlockInfo.h"
+using namespace llvm;
+
+namespace llvm {
+
+// mayOptimizeThumb2Instruction - Returns true if optimizeThumb2Instructions
+// below may shrink MI.
+static bool
+mayOptimizeThumb2Instruction(const MachineInstr *MI) {
+ switch(MI->getOpcode()) {
+ // optimizeThumb2Instructions.
+ case ARM::t2LEApcrel:
+ case ARM::t2LDRpci:
+ // optimizeThumb2Branches.
+ case ARM::t2B:
+ case ARM::t2Bcc:
+ case ARM::tBcc:
+ // optimizeThumb2JumpTables.
+ case ARM::t2BR_JT:
+ return true;
+ }
+ return false;
+}
+
+void computeBlockSize(MachineFunction *MF, MachineBasicBlock *MBB,
+ BasicBlockInfo &BBI) {
+ const ARMBaseInstrInfo *TII =
+ static_cast<const ARMBaseInstrInfo *>(MF->getSubtarget().getInstrInfo());
+ bool isThumb = MF->getInfo<ARMFunctionInfo>()->isThumbFunction();
+ BBI.Size = 0;
+ BBI.Unalign = 0;
+ BBI.PostAlign = 0;
+
+ for (MachineInstr &I : *MBB) {
+ BBI.Size += TII->getInstSizeInBytes(I);
+ // For inline asm, getInstSizeInBytes returns a conservative estimate.
+ // The actual size may be smaller, but still a multiple of the instr size.
+ if (I.isInlineAsm())
+ BBI.Unalign = isThumb ? 1 : 2;
+ // Also consider instructions that may be shrunk later.
+ else if (isThumb && mayOptimizeThumb2Instruction(&I))
+ BBI.Unalign = 1;
+ }
+
+ // tBR_JTr contains a .align 2 directive.
+ if (!MBB->empty() && MBB->back().getOpcode() == ARM::tBR_JTr) {
+ BBI.PostAlign = 2;
+ MBB->getParent()->ensureAlignment(2);
+ }
+}
+
+std::vector<BasicBlockInfo> computeAllBlockSizes(MachineFunction *MF) {
+ std::vector<BasicBlockInfo> BBInfo;
+ BBInfo.resize(MF->getNumBlockIDs());
+
+ for (MachineBasicBlock &MBB : *MF)
+ computeBlockSize(MF, &MBB, BBInfo[MBB.getNumber()]);
+
+ return BBInfo;
+}
+
+} // end namespace
diff --git a/contrib/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp b/contrib/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
index 8511f67..be1a37e 100644
--- a/contrib/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ARM.h"
+#include "ARMBasicBlockInfo.h"
#include "ARMMachineFunctionInfo.h"
#include "MCTargetDesc/ARMAddressingModes.h"
#include "Thumb2InstrInfo.h"
@@ -57,18 +58,10 @@ static cl::opt<unsigned>
CPMaxIteration("arm-constant-island-max-iteration", cl::Hidden, cl::init(30),
cl::desc("The max number of iteration for converge"));
-
-/// UnknownPadding - Return the worst case padding that could result from
-/// unknown offset bits. This does not include alignment padding caused by
-/// known offset bits.
-///
-/// @param LogAlign log2(alignment)
-/// @param KnownBits Number of known low offset bits.
-static inline unsigned UnknownPadding(unsigned LogAlign, unsigned KnownBits) {
- if (KnownBits < LogAlign)
- return (1u << LogAlign) - (1u << KnownBits);
- return 0;
-}
+static cl::opt<bool> SynthesizeThumb1TBB(
+ "arm-synthesize-thumb-1-tbb", cl::Hidden, cl::init(true),
+ cl::desc("Use compressed jump tables in Thumb-1 by synthesizing an "
+ "equivalent to the TBB/TBH instructions"));
namespace {
/// ARMConstantIslands - Due to limited PC-relative displacements, ARM
@@ -83,78 +76,6 @@ namespace {
/// CPE - A constant pool entry that has been placed somewhere, which
/// tracks a list of users.
class ARMConstantIslands : public MachineFunctionPass {
- /// BasicBlockInfo - Information about the offset and size of a single
- /// basic block.
- struct BasicBlockInfo {
- /// Offset - Distance from the beginning of the function to the beginning
- /// of this basic block.
- ///
- /// Offsets are computed assuming worst case padding before an aligned
- /// block. This means that subtracting basic block offsets always gives a
- /// conservative estimate of the real distance which may be smaller.
- ///
- /// Because worst case padding is used, the computed offset of an aligned
- /// block may not actually be aligned.
- unsigned Offset;
-
- /// Size - Size of the basic block in bytes. If the block contains
- /// inline assembly, this is a worst case estimate.
- ///
- /// The size does not include any alignment padding whether from the
- /// beginning of the block, or from an aligned jump table at the end.
- unsigned Size;
-
- /// KnownBits - The number of low bits in Offset that are known to be
- /// exact. The remaining bits of Offset are an upper bound.
- uint8_t KnownBits;
-
- /// Unalign - When non-zero, the block contains instructions (inline asm)
- /// of unknown size. The real size may be smaller than Size bytes by a
- /// multiple of 1 << Unalign.
- uint8_t Unalign;
-
- /// PostAlign - When non-zero, the block terminator contains a .align
- /// directive, so the end of the block is aligned to 1 << PostAlign
- /// bytes.
- uint8_t PostAlign;
-
- BasicBlockInfo() : Offset(0), Size(0), KnownBits(0), Unalign(0),
- PostAlign(0) {}
-
- /// Compute the number of known offset bits internally to this block.
- /// This number should be used to predict worst case padding when
- /// splitting the block.
- unsigned internalKnownBits() const {
- unsigned Bits = Unalign ? Unalign : KnownBits;
- // If the block size isn't a multiple of the known bits, assume the
- // worst case padding.
- if (Size & ((1u << Bits) - 1))
- Bits = countTrailingZeros(Size);
- return Bits;
- }
-
- /// Compute the offset immediately following this block. If LogAlign is
- /// specified, return the offset the successor block will get if it has
- /// this alignment.
- unsigned postOffset(unsigned LogAlign = 0) const {
- unsigned PO = Offset + Size;
- unsigned LA = std::max(unsigned(PostAlign), LogAlign);
- if (!LA)
- return PO;
- // Add alignment padding from the terminator.
- return PO + UnknownPadding(LA, internalKnownBits());
- }
-
- /// Compute the number of known low bits of postOffset. If this block
- /// contains inline asm, the number of known bits drops to the
- /// instruction alignment. An aligned terminator may increase the number
- /// of know bits.
- /// If LogAlign is given, also consider the alignment of the next block.
- unsigned postKnownBits(unsigned LogAlign = 0) const {
- return std::max(std::max(unsigned(PostAlign), LogAlign),
- internalKnownBits());
- }
- };
std::vector<BasicBlockInfo> BBInfo;
@@ -273,6 +194,7 @@ namespace {
bool isThumb;
bool isThumb1;
bool isThumb2;
+ bool isPositionIndependentOrROPI;
public:
static char ID;
ARMConstantIslands() : MachineFunctionPass(ID) {}
@@ -281,10 +203,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "ARM constant island placement and branch shortening pass";
}
@@ -319,7 +241,6 @@ namespace {
bool fixupConditionalBr(ImmBranch &Br);
bool fixupUnconditionalBr(ImmBranch &Br);
bool undoLRSpillRestore();
- bool mayOptimizeThumb2Instruction(const MachineInstr *MI) const;
bool optimizeThumb2Instructions();
bool optimizeThumb2Branches();
bool reorderThumb2JumpTables();
@@ -330,7 +251,6 @@ namespace {
MachineBasicBlock *adjustJTTargetBlockForward(MachineBasicBlock *BB,
MachineBasicBlock *JTBB);
- void computeBlockSize(MachineBasicBlock *MBB);
unsigned getOffsetOf(MachineInstr *MI) const;
unsigned getUserOffset(CPUser&) const;
void dumpBBs();
@@ -405,6 +325,8 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
STI = &static_cast<const ARMSubtarget &>(MF->getSubtarget());
TII = STI->getInstrInfo();
+ isPositionIndependentOrROPI =
+ STI->getTargetLowering()->isPositionIndependent() || STI->isROPI();
AFI = MF->getInfo<ARMFunctionInfo>();
isThumb = AFI->isThumbFunction();
@@ -412,6 +334,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
isThumb2 = AFI->isThumb2Function();
HasFarJump = false;
+ bool GenerateTBB = isThumb2 || (isThumb1 && SynthesizeThumb1TBB);
// This pass invalidates liveness information when it splits basic blocks.
MF->getRegInfo().invalidateLiveness();
@@ -423,7 +346,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
// Try to reorder and otherwise adjust the block layout to make good use
// of the TB[BH] instructions.
bool MadeChange = false;
- if (isThumb2 && AdjustJumpTableBlocks) {
+ if (GenerateTBB && AdjustJumpTableBlocks) {
scanFunctionJumpTables();
MadeChange |= reorderThumb2JumpTables();
// Data is out of date, so clear it. It'll be re-computed later.
@@ -500,7 +423,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
MadeChange |= optimizeThumb2Branches();
// Optimize jump tables using TBB / TBH.
- if (isThumb2)
+ if (GenerateTBB && !STI->genExecuteOnly())
MadeChange |= optimizeThumb2JumpTables();
// After a while, this might be made debug-only, but it is not expensive.
@@ -626,9 +549,11 @@ void ARMConstantIslands::doInitialJumpTablePlacement(
case ARM::t2BR_JT:
JTOpcode = ARM::JUMPTABLE_INSTS;
break;
+ case ARM::tTBB_JT:
case ARM::t2TBB_JT:
JTOpcode = ARM::JUMPTABLE_TBB;
break;
+ case ARM::tTBH_JT:
case ARM::t2TBH_JT:
JTOpcode = ARM::JUMPTABLE_TBH;
break;
@@ -668,7 +593,7 @@ bool ARMConstantIslands::BBHasFallthrough(MachineBasicBlock *MBB) {
return false;
MachineBasicBlock *NextBB = &*std::next(MBBI);
- if (std::find(MBB->succ_begin(), MBB->succ_end(), NextBB) == MBB->succ_end())
+ if (!MBB->isSuccessor(NextBB))
return false;
// Try to analyze the end of the block. A potential fallthrough may already
@@ -701,8 +626,9 @@ unsigned ARMConstantIslands::getCPELogAlign(const MachineInstr *CPEMI) {
case ARM::CONSTPOOL_ENTRY:
break;
case ARM::JUMPTABLE_TBB:
- return 0;
+ return isThumb1 ? 2 : 0;
case ARM::JUMPTABLE_TBH:
+ return isThumb1 ? 2 : 1;
case ARM::JUMPTABLE_INSTS:
return 1;
case ARM::JUMPTABLE_ADDRS:
@@ -724,7 +650,8 @@ unsigned ARMConstantIslands::getCPELogAlign(const MachineInstr *CPEMI) {
void ARMConstantIslands::scanFunctionJumpTables() {
for (MachineBasicBlock &MBB : *MF) {
for (MachineInstr &I : MBB)
- if (I.isBranch() && I.getOpcode() == ARM::t2BR_JT)
+ if (I.isBranch() &&
+ (I.getOpcode() == ARM::t2BR_JT || I.getOpcode() == ARM::tBR_JTr))
T2JumpTables.push_back(&I);
}
}
@@ -734,15 +661,8 @@ void ARMConstantIslands::scanFunctionJumpTables() {
/// and finding all of the constant pool users.
void ARMConstantIslands::
initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
- BBInfo.clear();
- BBInfo.resize(MF->getNumBlockIDs());
- // First thing, compute the size of all basic blocks, and see if the function
- // has any inline assembly in it. If so, we have to be conservative about
- // alignment assumptions, as we don't know for sure the size of any
- // instructions in the inline assembly.
- for (MachineBasicBlock &MBB : *MF)
- computeBlockSize(&MBB);
+ BBInfo = computeAllBlockSizes(MF);
// The known bits of the entry block offset are determined by the function
// alignment.
@@ -772,12 +692,13 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
default:
continue; // Ignore other JT branches
case ARM::t2BR_JT:
+ case ARM::tBR_JTr:
T2JumpTables.push_back(&I);
continue; // Does not get an entry in ImmBranches
case ARM::Bcc:
isCond = true;
UOpc = ARM::B;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case ARM::B:
Bits = 24;
Scale = 4;
@@ -860,6 +781,7 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
case ARM::LDRi12:
case ARM::LDRcp:
case ARM::t2LDRpci:
+ case ARM::t2LDRHpci:
Bits = 12; // +-offset_12
NegOk = true;
break;
@@ -875,6 +797,11 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
Scale = 4; // +-(offset_8*4)
NegOk = true;
break;
+
+ case ARM::tLDRHi:
+ Bits = 5;
+ Scale = 2; // +(offset_5*2)
+ break;
}
// Remember that this is a user of a CP entry.
@@ -901,32 +828,6 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
}
}
-/// computeBlockSize - Compute the size and some alignment information for MBB.
-/// This function updates BBInfo directly.
-void ARMConstantIslands::computeBlockSize(MachineBasicBlock *MBB) {
- BasicBlockInfo &BBI = BBInfo[MBB->getNumber()];
- BBI.Size = 0;
- BBI.Unalign = 0;
- BBI.PostAlign = 0;
-
- for (MachineInstr &I : *MBB) {
- BBI.Size += TII->GetInstSizeInBytes(I);
- // For inline asm, GetInstSizeInBytes returns a conservative estimate.
- // The actual size may be smaller, but still a multiple of the instr size.
- if (I.isInlineAsm())
- BBI.Unalign = isThumb ? 1 : 2;
- // Also consider instructions that may be shrunk later.
- else if (isThumb && mayOptimizeThumb2Instruction(&I))
- BBI.Unalign = 1;
- }
-
- // tBR_JTr contains a .align 2 directive.
- if (!MBB->empty() && MBB->back().getOpcode() == ARM::tBR_JTr) {
- BBI.PostAlign = 2;
- MBB->getParent()->ensureAlignment(2);
- }
-}
-
/// getOffsetOf - Return the current offset of the specified machine instruction
/// from the start of the function. This offset changes as stuff is moved
/// around inside the function.
@@ -941,7 +842,7 @@ unsigned ARMConstantIslands::getOffsetOf(MachineInstr *MI) const {
// Sum instructions before MI in MBB.
for (MachineBasicBlock::iterator I = MBB->begin(); &*I != MI; ++I) {
assert(I != MBB->end() && "Didn't find MI in its own basic block?");
- Offset += TII->GetInstSizeInBytes(*I);
+ Offset += TII->getInstSizeInBytes(*I);
}
return Offset;
}
@@ -1034,11 +935,11 @@ MachineBasicBlock *ARMConstantIslands::splitBlockBeforeInstr(MachineInstr *MI) {
// the new jump we added. (It should be possible to do this without
// recounting everything, but it's very confusing, and this is rarely
// executed.)
- computeBlockSize(OrigBB);
+ computeBlockSize(MF, OrigBB, BBInfo[OrigBB->getNumber()]);
// Figure out how large the NewMBB is. As the second half of the original
// block, it may contain a tablejump.
- computeBlockSize(NewBB);
+ computeBlockSize(MF, NewBB, BBInfo[NewBB->getNumber()]);
// All BBOffsets following these blocks must be modified.
adjustBBOffsetsAfter(OrigBB);
@@ -1400,7 +1301,7 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
unsigned MaxDisp = getUnconditionalBrDisp(UncondBr);
ImmBranches.push_back(ImmBranch(&UserMBB->back(),
MaxDisp, false, UncondBr));
- computeBlockSize(UserMBB);
+ computeBlockSize(MF, UserMBB, BBInfo[UserMBB->getNumber()]);
adjustBBOffsetsAfter(UserMBB);
return;
}
@@ -1449,7 +1350,7 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
// iterates at least once.
BaseInsertOffset =
std::max(UserBBI.postOffset() - UPad - 8,
- UserOffset + TII->GetInstSizeInBytes(*UserMI) + 1);
+ UserOffset + TII->getInstSizeInBytes(*UserMI) + 1);
DEBUG(dbgs() << format("Move inside block: %#x\n", BaseInsertOffset));
}
unsigned EndInsertOffset = BaseInsertOffset + 4 + UPad +
@@ -1459,9 +1360,9 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
unsigned CPUIndex = CPUserIndex+1;
unsigned NumCPUsers = CPUsers.size();
MachineInstr *LastIT = nullptr;
- for (unsigned Offset = UserOffset + TII->GetInstSizeInBytes(*UserMI);
+ for (unsigned Offset = UserOffset + TII->getInstSizeInBytes(*UserMI);
Offset < BaseInsertOffset;
- Offset += TII->GetInstSizeInBytes(*MI), MI = std::next(MI)) {
+ Offset += TII->getInstSizeInBytes(*MI), MI = std::next(MI)) {
assert(MI != UserMBB->end() && "Fell off end of block");
if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == &*MI) {
CPUser &U = CPUsers[CPUIndex];
@@ -1551,7 +1452,7 @@ bool ARMConstantIslands::handleConstantPoolUser(unsigned CPUserIndex,
// it. Check for this so it will be removed from the WaterList.
// Also remove any entry from NewWaterList.
MachineBasicBlock *WaterBB = &*--NewMBB->getIterator();
- IP = std::find(WaterList.begin(), WaterList.end(), WaterBB);
+ IP = find(WaterList, WaterBB);
if (IP != WaterList.end())
NewWaterList.erase(WaterBB);
@@ -1762,7 +1663,7 @@ ARMConstantIslands::fixupConditionalBr(ImmBranch &Br) {
splitBlockBeforeInstr(MI);
// No need for the branch to the next block. We're adding an unconditional
// branch to the destination.
- int delta = TII->GetInstSizeInBytes(MBB->back());
+ int delta = TII->getInstSizeInBytes(MBB->back());
BBInfo[MBB->getNumber()].Size -= delta;
MBB->back().eraseFromParent();
// BBInfo[SplitBB].Offset is wrong temporarily, fixed below
@@ -1778,18 +1679,18 @@ ARMConstantIslands::fixupConditionalBr(ImmBranch &Br) {
BuildMI(MBB, DebugLoc(), TII->get(MI->getOpcode()))
.addMBB(NextBB).addImm(CC).addReg(CCReg);
Br.MI = &MBB->back();
- BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(MBB->back());
+ BBInfo[MBB->getNumber()].Size += TII->getInstSizeInBytes(MBB->back());
if (isThumb)
BuildMI(MBB, DebugLoc(), TII->get(Br.UncondBr)).addMBB(DestBB)
.addImm(ARMCC::AL).addReg(0);
else
BuildMI(MBB, DebugLoc(), TII->get(Br.UncondBr)).addMBB(DestBB);
- BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(MBB->back());
+ BBInfo[MBB->getNumber()].Size += TII->getInstSizeInBytes(MBB->back());
unsigned MaxDisp = getUnconditionalBrDisp(Br.UncondBr);
ImmBranches.push_back(ImmBranch(&MBB->back(), MaxDisp, false, Br.UncondBr));
// Remove the old conditional branch. It may or may not still be in MBB.
- BBInfo[MI->getParent()->getNumber()].Size -= TII->GetInstSizeInBytes(*MI);
+ BBInfo[MI->getParent()->getNumber()].Size -= TII->getInstSizeInBytes(*MI);
MI->eraseFromParent();
adjustBBOffsetsAfter(MBB);
return true;
@@ -1817,25 +1718,6 @@ bool ARMConstantIslands::undoLRSpillRestore() {
return MadeChange;
}
-// mayOptimizeThumb2Instruction - Returns true if optimizeThumb2Instructions
-// below may shrink MI.
-bool
-ARMConstantIslands::mayOptimizeThumb2Instruction(const MachineInstr *MI) const {
- switch(MI->getOpcode()) {
- // optimizeThumb2Instructions.
- case ARM::t2LEApcrel:
- case ARM::t2LDRpci:
- // optimizeThumb2Branches.
- case ARM::t2B:
- case ARM::t2Bcc:
- case ARM::tBcc:
- // optimizeThumb2JumpTables.
- case ARM::t2BR_JT:
- return true;
- }
- return false;
-}
-
bool ARMConstantIslands::optimizeThumb2Instructions() {
bool MadeChange = false;
@@ -2075,7 +1957,7 @@ bool ARMConstantIslands::preserveBaseRegister(MachineInstr *JumpMI,
if (RemovableAdd) {
RemovableAdd->eraseFromParent();
- DeadSize += 4;
+ DeadSize += isThumb2 ? 4 : 2;
} else if (BaseReg == EntryReg) {
// The add wasn't removable, but clobbered the base for the TBB. So we can't
// preserve it.
@@ -2142,25 +2024,82 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
if (!ByteOk && !HalfWordOk)
continue;
+ CPUser &User = CPUsers[JumpTableUserIndices[JTI]];
MachineBasicBlock *MBB = MI->getParent();
if (!MI->getOperand(0).isKill()) // FIXME: needed now?
continue;
- unsigned IdxReg = MI->getOperand(1).getReg();
- bool IdxRegKill = MI->getOperand(1).isKill();
- CPUser &User = CPUsers[JumpTableUserIndices[JTI]];
unsigned DeadSize = 0;
bool CanDeleteLEA = false;
bool BaseRegKill = false;
- bool PreservedBaseReg =
+
+ unsigned IdxReg = ~0U;
+ bool IdxRegKill = true;
+ if (isThumb2) {
+ IdxReg = MI->getOperand(1).getReg();
+ IdxRegKill = MI->getOperand(1).isKill();
+
+ bool PreservedBaseReg =
preserveBaseRegister(MI, User.MI, DeadSize, CanDeleteLEA, BaseRegKill);
+ if (!jumpTableFollowsTB(MI, User.CPEMI) && !PreservedBaseReg)
+ continue;
+ } else {
+ // We're in thumb-1 mode, so we must have something like:
+ // %idx = tLSLri %idx, 2
+ // %base = tLEApcrelJT
+ // %t = tLDRr %idx, %base
+ unsigned BaseReg = User.MI->getOperand(0).getReg();
+
+ if (User.MI->getIterator() == User.MI->getParent()->begin())
+ continue;
+ MachineInstr *Shift = User.MI->getPrevNode();
+ if (Shift->getOpcode() != ARM::tLSLri ||
+ Shift->getOperand(3).getImm() != 2 ||
+ !Shift->getOperand(2).isKill())
+ continue;
+ IdxReg = Shift->getOperand(2).getReg();
+ unsigned ShiftedIdxReg = Shift->getOperand(0).getReg();
- if (!jumpTableFollowsTB(MI, User.CPEMI) && !PreservedBaseReg)
- continue;
+ MachineInstr *Load = User.MI->getNextNode();
+ if (Load->getOpcode() != ARM::tLDRr)
+ continue;
+ if (Load->getOperand(1).getReg() != ShiftedIdxReg ||
+ Load->getOperand(2).getReg() != BaseReg ||
+ !Load->getOperand(1).isKill())
+ continue;
+ // If we're in PIC mode, there should be another ADD following.
+ if (isPositionIndependentOrROPI) {
+ MachineInstr *Add = Load->getNextNode();
+ if (Add->getOpcode() != ARM::tADDrr ||
+ Add->getOperand(2).getReg() != Load->getOperand(0).getReg() ||
+ Add->getOperand(3).getReg() != BaseReg ||
+ !Add->getOperand(2).isKill())
+ continue;
+ if (Add->getOperand(0).getReg() != MI->getOperand(0).getReg())
+ continue;
+
+ Add->eraseFromParent();
+ DeadSize += 2;
+ } else {
+ if (Load->getOperand(0).getReg() != MI->getOperand(0).getReg())
+ continue;
+ }
+
+
+ // Now safe to delete the load and lsl. The LEA will be removed later.
+ CanDeleteLEA = true;
+ Shift->eraseFromParent();
+ Load->eraseFromParent();
+ DeadSize += 4;
+ }
+
DEBUG(dbgs() << "Shrink JT: " << *MI);
MachineInstr *CPEMI = User.CPEMI;
unsigned Opc = ByteOk ? ARM::t2TBB_JT : ARM::t2TBH_JT;
+ if (!isThumb2)
+ Opc = ByteOk ? ARM::tTBB_JT : ARM::tTBH_JT;
+
MachineBasicBlock::iterator MI_JT = MI;
MachineInstr *NewJTMI =
BuildMI(*MBB, MI_JT, MI->getDebugLoc(), TII->get(Opc))
@@ -2180,7 +2119,7 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
if (CanDeleteLEA) {
User.MI->eraseFromParent();
- DeadSize += 4;
+ DeadSize += isThumb2 ? 4 : 2;
// The LEA was eliminated, the TBB instruction becomes the only new user
// of the jump table.
@@ -2194,16 +2133,15 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
// record the TBB or TBH use.
int CPEntryIdx = JumpTableEntryIndices[JTI];
auto &CPEs = CPEntries[CPEntryIdx];
- auto Entry = std::find_if(CPEs.begin(), CPEs.end(), [&](CPEntry &E) {
- return E.CPEMI == User.CPEMI;
- });
+ auto Entry =
+ find_if(CPEs, [&](CPEntry &E) { return E.CPEMI == User.CPEMI; });
++Entry->RefCount;
CPUsers.emplace_back(CPUser(NewJTMI, User.CPEMI, 4, false, false));
}
}
- unsigned NewSize = TII->GetInstSizeInBytes(*NewJTMI);
- unsigned OrigSize = TII->GetInstSizeInBytes(*MI);
+ unsigned NewSize = TII->getInstSizeInBytes(*NewJTMI);
+ unsigned OrigSize = TII->getInstSizeInBytes(*MI);
MI->eraseFromParent();
int Delta = OrigSize - NewSize + DeadSize;
@@ -2297,9 +2235,16 @@ adjustJTTargetBlockForward(MachineBasicBlock *BB, MachineBasicBlock *JTBB) {
// Add an unconditional branch from NewBB to BB.
// There doesn't seem to be meaningful DebugInfo available; this doesn't
// correspond directly to anything in the source.
- assert (isThumb2 && "Adjusting for TB[BH] but not in Thumb2?");
- BuildMI(NewBB, DebugLoc(), TII->get(ARM::t2B)).addMBB(BB)
- .addImm(ARMCC::AL).addReg(0);
+ if (isThumb2)
+ BuildMI(NewBB, DebugLoc(), TII->get(ARM::t2B))
+ .addMBB(BB)
+ .addImm(ARMCC::AL)
+ .addReg(0);
+ else
+ BuildMI(NewBB, DebugLoc(), TII->get(ARM::tB))
+ .addMBB(BB)
+ .addImm(ARMCC::AL)
+ .addReg(0);
// Update internal data structures to account for the newly inserted MBB.
MF->RenumberBlocks(NewBB);
diff --git a/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp b/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp
index c0db001..2d16028 100644
--- a/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp
@@ -46,7 +46,7 @@ ARMConstantPoolValue::ARMConstantPoolValue(LLVMContext &C, unsigned id,
ARMConstantPoolValue::~ARMConstantPoolValue() {}
-const char *ARMConstantPoolValue::getModifierText() const {
+StringRef ARMConstantPoolValue::getModifierText() const {
switch (Modifier) {
// FIXME: Are these case sensitive? It'd be nice to lower-case all the
// strings if that's legal.
@@ -60,6 +60,8 @@ const char *ARMConstantPoolValue::getModifierText() const {
return "gottpoff";
case ARMCP::TPOFF:
return "tpoff";
+ case ARMCP::SBREL:
+ return "SBREL";
case ARMCP::SECREL:
return "secrel32";
}
@@ -129,6 +131,12 @@ ARMConstantPoolConstant::ARMConstantPoolConstant(const Constant *C,
AddCurrentAddress),
CVal(C) {}
+ARMConstantPoolConstant::ARMConstantPoolConstant(const GlobalVariable *GV,
+ const Constant *C)
+ : ARMConstantPoolValue((Type *)C->getType(), 0, ARMCP::CPPromotedGlobal, 0,
+ ARMCP::no_modifier, false),
+ CVal(C), GVar(GV) {}
+
ARMConstantPoolConstant *
ARMConstantPoolConstant::Create(const Constant *C, unsigned ID) {
return new ARMConstantPoolConstant(C, ID, ARMCP::CPValue, 0,
@@ -136,6 +144,12 @@ ARMConstantPoolConstant::Create(const Constant *C, unsigned ID) {
}
ARMConstantPoolConstant *
+ARMConstantPoolConstant::Create(const GlobalVariable *GVar,
+ const Constant *Initializer) {
+ return new ARMConstantPoolConstant(GVar, Initializer);
+}
+
+ARMConstantPoolConstant *
ARMConstantPoolConstant::Create(const GlobalValue *GV,
ARMCP::ARMCPModifier Modifier) {
return new ARMConstantPoolConstant((Type*)Type::getInt32Ty(GV->getContext()),
@@ -191,18 +205,17 @@ void ARMConstantPoolConstant::print(raw_ostream &O) const {
// ARMConstantPoolSymbol
//===----------------------------------------------------------------------===//
-ARMConstantPoolSymbol::ARMConstantPoolSymbol(LLVMContext &C, const char *s,
- unsigned id,
- unsigned char PCAdj,
+ARMConstantPoolSymbol::ARMConstantPoolSymbol(LLVMContext &C, StringRef s,
+ unsigned id, unsigned char PCAdj,
ARMCP::ARMCPModifier Modifier,
bool AddCurrentAddress)
- : ARMConstantPoolValue(C, id, ARMCP::CPExtSymbol, PCAdj, Modifier,
- AddCurrentAddress),
- S(s) {}
+ : ARMConstantPoolValue(C, id, ARMCP::CPExtSymbol, PCAdj, Modifier,
+ AddCurrentAddress),
+ S(s) {}
-ARMConstantPoolSymbol *
-ARMConstantPoolSymbol::Create(LLVMContext &C, const char *s,
- unsigned ID, unsigned char PCAdj) {
+ARMConstantPoolSymbol *ARMConstantPoolSymbol::Create(LLVMContext &C,
+ StringRef s, unsigned ID,
+ unsigned char PCAdj) {
return new ARMConstantPoolSymbol(C, s, ID, PCAdj, ARMCP::no_modifier, false);
}
diff --git a/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.h b/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.h
index c07331d..5f61832 100644
--- a/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.h
+++ b/contrib/llvm/lib/Target/ARM/ARMConstantPoolValue.h
@@ -24,6 +24,7 @@ namespace llvm {
class BlockAddress;
class Constant;
class GlobalValue;
+class GlobalVariable;
class LLVMContext;
class MachineBasicBlock;
@@ -33,7 +34,8 @@ namespace ARMCP {
CPExtSymbol,
CPBlockAddress,
CPLSDA,
- CPMachineBasicBlock
+ CPMachineBasicBlock,
+ CPPromotedGlobal
};
enum ARMCPModifier {
@@ -43,6 +45,7 @@ namespace ARMCP {
GOTTPOFF, /// Global Offset Table, Thread Pointer Offset
TPOFF, /// Thread Pointer Offset
SECREL, /// Section Relative (Windows TLS)
+ SBREL, /// Static Base Relative (RWPI)
};
}
@@ -89,7 +92,7 @@ public:
~ARMConstantPoolValue() override;
ARMCP::ARMCPModifier getModifier() const { return Modifier; }
- const char *getModifierText() const;
+ StringRef getModifierText() const;
bool hasModifier() const { return Modifier != ARMCP::no_modifier; }
bool mustAddCurrentAddress() const { return AddCurrentAddress; }
@@ -102,7 +105,8 @@ public:
bool isBlockAddress() const { return Kind == ARMCP::CPBlockAddress; }
bool isLSDA() const { return Kind == ARMCP::CPLSDA; }
bool isMachineBasicBlock() const{ return Kind == ARMCP::CPMachineBasicBlock; }
-
+ bool isPromotedGlobal() const{ return Kind == ARMCP::CPPromotedGlobal; }
+
int getExistingMachineCPValue(MachineConstantPool *CP,
unsigned Alignment) override;
@@ -132,6 +136,7 @@ inline raw_ostream &operator<<(raw_ostream &O, const ARMConstantPoolValue &V) {
/// Functions, and BlockAddresses.
class ARMConstantPoolConstant : public ARMConstantPoolValue {
const Constant *CVal; // Constant being loaded.
+ const GlobalVariable *GVar = nullptr;
ARMConstantPoolConstant(const Constant *C,
unsigned ID,
@@ -145,11 +150,14 @@ class ARMConstantPoolConstant : public ARMConstantPoolValue {
unsigned char PCAdj,
ARMCP::ARMCPModifier Modifier,
bool AddCurrentAddress);
+ ARMConstantPoolConstant(const GlobalVariable *GV, const Constant *Init);
public:
static ARMConstantPoolConstant *Create(const Constant *C, unsigned ID);
static ARMConstantPoolConstant *Create(const GlobalValue *GV,
ARMCP::ARMCPModifier Modifier);
+ static ARMConstantPoolConstant *Create(const GlobalVariable *GV,
+ const Constant *Initializer);
static ARMConstantPoolConstant *Create(const Constant *C, unsigned ID,
ARMCP::ARMCPKind Kind,
unsigned char PCAdj);
@@ -161,6 +169,12 @@ public:
const GlobalValue *getGV() const;
const BlockAddress *getBlockAddress() const;
+ const GlobalVariable *getPromotedGlobal() const {
+ return dyn_cast_or_null<GlobalVariable>(GVar);
+ }
+ const Constant *getPromotedGlobalInit() const {
+ return CVal;
+ }
int getExistingMachineCPValue(MachineConstantPool *CP,
unsigned Alignment) override;
@@ -173,7 +187,8 @@ public:
void print(raw_ostream &O) const override;
static bool classof(const ARMConstantPoolValue *APV) {
- return APV->isGlobalValue() || APV->isBlockAddress() || APV->isLSDA();
+ return APV->isGlobalValue() || APV->isBlockAddress() || APV->isLSDA() ||
+ APV->isPromotedGlobal();
}
bool equals(const ARMConstantPoolConstant *A) const {
@@ -186,15 +201,15 @@ public:
class ARMConstantPoolSymbol : public ARMConstantPoolValue {
const std::string S; // ExtSymbol being loaded.
- ARMConstantPoolSymbol(LLVMContext &C, const char *s, unsigned id,
+ ARMConstantPoolSymbol(LLVMContext &C, StringRef s, unsigned id,
unsigned char PCAdj, ARMCP::ARMCPModifier Modifier,
bool AddCurrentAddress);
public:
- static ARMConstantPoolSymbol *Create(LLVMContext &C, const char *s,
- unsigned ID, unsigned char PCAdj);
+ static ARMConstantPoolSymbol *Create(LLVMContext &C, StringRef s, unsigned ID,
+ unsigned char PCAdj);
- const char *getSymbol() const { return S.c_str(); }
+ StringRef getSymbol() const { return S; }
int getExistingMachineCPValue(MachineConstantPool *CP,
unsigned Alignment) override;
diff --git a/contrib/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/contrib/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index a7b2996..baa4e03 100644
--- a/contrib/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -53,10 +53,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "ARM pseudo instruction expansion pass";
}
@@ -657,6 +657,9 @@ static bool IsAnAddressOperand(const MachineOperand &MO) {
return true;
case MachineOperand::MO_CFIIndex:
return false;
+ case MachineOperand::MO_IntrinsicID:
+ case MachineOperand::MO_Predicate:
+ llvm_unreachable("should not exist post-isel");
}
llvm_unreachable("unhandled machine operand type");
}
@@ -1175,8 +1178,8 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
}
// If there's dynamic realignment, adjust for it.
if (RI.needsStackRealignment(MF)) {
- MachineFrameInfo *MFI = MF.getFrameInfo();
- unsigned MaxAlign = MFI->getMaxAlignment();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned MaxAlign = MFI.getMaxAlignment();
assert (!AFI->isThumb1OnlyFunction());
// Emit bic r6, r6, MaxAlign
assert(MaxAlign <= 256 && "The BIC instruction cannot encode "
@@ -1222,16 +1225,36 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
}
case ARM::tTPsoft:
case ARM::TPsoft: {
+ const bool Thumb = Opcode == ARM::tTPsoft;
+
MachineInstrBuilder MIB;
- if (Opcode == ARM::tTPsoft)
+ if (STI->genLongCalls()) {
+ MachineFunction *MF = MBB.getParent();
+ MachineConstantPool *MCP = MF->getConstantPool();
+ unsigned PCLabelID = AFI->createPICLabelUId();
+ MachineConstantPoolValue *CPV =
+ ARMConstantPoolSymbol::Create(MF->getFunction()->getContext(),
+ "__aeabi_read_tp", PCLabelID, 0);
+ unsigned Reg = MI.getOperand(0).getReg();
MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(),
- TII->get( ARM::tBL))
- .addImm((unsigned)ARMCC::AL).addReg(0)
- .addExternalSymbol("__aeabi_read_tp", 0);
- else
+ TII->get(Thumb ? ARM::tLDRpci : ARM::LDRi12), Reg)
+ .addConstantPoolIndex(MCP->getConstantPoolIndex(CPV, 4));
+ if (!Thumb)
+ MIB.addImm(0);
+ MIB.addImm(static_cast<unsigned>(ARMCC::AL)).addReg(0);
+
MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(),
- TII->get( ARM::BL))
- .addExternalSymbol("__aeabi_read_tp", 0);
+ TII->get(Thumb ? ARM::tBLXr : ARM::BLX));
+ if (Thumb)
+ MIB.addImm(static_cast<unsigned>(ARMCC::AL)).addReg(0);
+ MIB.addReg(Reg, RegState::Kill);
+ } else {
+ MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(),
+ TII->get(Thumb ? ARM::tBL : ARM::BL));
+ if (Thumb)
+ MIB.addImm(static_cast<unsigned>(ARMCC::AL)).addReg(0);
+ MIB.addExternalSymbol("__aeabi_read_tp", 0);
+ }
MIB->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
TransferImpOps(MI, MIB, MIB);
diff --git a/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp b/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp
index 13724da..df4dcb3 100644
--- a/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMFastISel.cpp
@@ -112,11 +112,6 @@ class ARMFastISel final : public FastISel {
const TargetRegisterClass *RC,
unsigned Op0, bool Op0IsKill,
uint64_t Imm);
- unsigned fastEmitInst_rri(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC,
- unsigned Op0, bool Op0IsKill,
- unsigned Op1, bool Op1IsKill,
- uint64_t Imm);
unsigned fastEmitInst_i(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
uint64_t Imm);
@@ -351,36 +346,6 @@ unsigned ARMFastISel::fastEmitInst_ri(unsigned MachineInstOpcode,
return ResultReg;
}
-unsigned ARMFastISel::fastEmitInst_rri(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC,
- unsigned Op0, bool Op0IsKill,
- unsigned Op1, bool Op1IsKill,
- uint64_t Imm) {
- unsigned ResultReg = createResultReg(RC);
- const MCInstrDesc &II = TII.get(MachineInstOpcode);
-
- // Make sure the input operands are sufficiently constrained to be legal
- // for this instruction.
- Op0 = constrainOperandRegClass(II, Op0, 1);
- Op1 = constrainOperandRegClass(II, Op1, 2);
- if (II.getNumDefs() >= 1) {
- AddOptionalDefs(
- BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg)
- .addReg(Op0, Op0IsKill * RegState::Kill)
- .addReg(Op1, Op1IsKill * RegState::Kill)
- .addImm(Imm));
- } else {
- AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
- .addReg(Op0, Op0IsKill * RegState::Kill)
- .addReg(Op1, Op1IsKill * RegState::Kill)
- .addImm(Imm));
- AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
- TII.get(TargetOpcode::COPY), ResultReg)
- .addReg(II.ImplicitDefs[0]));
- }
- return ResultReg;
-}
-
unsigned ARMFastISel::fastEmitInst_i(unsigned MachineInstOpcode,
const TargetRegisterClass *RC,
uint64_t Imm) {
@@ -546,6 +511,10 @@ unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, MVT VT) {
// For now 32-bit only.
if (VT != MVT::i32 || GV->isThreadLocal()) return 0;
+ // ROPI/RWPI not currently supported.
+ if (Subtarget->isROPI() || Subtarget->isRWPI())
+ return 0;
+
bool IsIndirect = Subtarget->isGVIndirectSymbol(GV);
const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass
: &ARM::GPRRegClass;
@@ -764,7 +733,7 @@ bool ARMFastISel::ARMComputeAddress(const Value *Obj, Address &Addr) {
for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end();
i != e; ++i, ++GTI) {
const Value *Op = *i;
- if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
@@ -1071,7 +1040,8 @@ bool ARMFastISel::ARMEmitStore(MVT VT, unsigned SrcReg, Address &Addr,
TII.get(Opc), Res)
.addReg(SrcReg).addImm(1));
SrcReg = Res;
- } // Fallthrough here.
+ LLVM_FALLTHROUGH;
+ }
case MVT::i8:
if (isThumb2) {
if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops())
@@ -1844,7 +1814,7 @@ CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC,
// For AAPCS ABI targets, just use VFP variant of the calling convention.
return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP);
}
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CallingConv::C:
case CallingConv::CXX_FAST_TLS:
// Use target triple & subtarget features to do actual dispatch.
@@ -1863,6 +1833,7 @@ CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC,
return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP);
// Fall through to soft float variant, variadic functions don't
// use hard floating point ABI.
+ LLVM_FALLTHROUGH;
case CallingConv::ARM_AAPCS:
return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS);
case CallingConv::ARM_APCS:
@@ -2481,8 +2452,8 @@ bool ARMFastISel::SelectIntrinsicCall(const IntrinsicInst &I) {
switch (I.getIntrinsicID()) {
default: return false;
case Intrinsic::frameaddress: {
- MachineFrameInfo *MFI = FuncInfo.MF->getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = FuncInfo.MF->getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
unsigned LdrOpc = isThumb2 ? ARM::t2LDRi12 : ARM::LDRi12;
const TargetRegisterClass *RC = isThumb2 ? &ARM::tGPRRegClass
diff --git a/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index e8c9f61..c72db8a 100644
--- a/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -30,6 +30,8 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetOptions.h"
+#define DEBUG_TYPE "arm-frame-lowering"
+
using namespace llvm;
static cl::opt<bool>
@@ -57,18 +59,16 @@ bool ARMFrameLowering::noFramePointerElim(const MachineFunction &MF) const {
/// or if frame pointer elimination is disabled.
bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
- // iOS requires FP not to be clobbered for backtracing purpose.
- if (STI.isTargetIOS() || STI.isTargetWatchOS())
+ // ABI-required frame pointer.
+ if (MF.getTarget().Options.DisableFramePointerElim(MF))
return true;
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- // Always eliminate non-leaf frame pointers.
- return ((MF.getTarget().Options.DisableFramePointerElim(MF) &&
- MFI->hasCalls()) ||
- RegInfo->needsStackRealignment(MF) ||
- MFI->hasVarSizedObjects() ||
- MFI->isFrameAddressTaken());
+ // Frame pointer required for use within this function.
+ return (RegInfo->needsStackRealignment(MF) ||
+ MFI.hasVarSizedObjects() ||
+ MFI.isFrameAddressTaken());
}
/// hasReservedCallFrame - Under normal circumstances, when a frame pointer is
@@ -77,8 +77,8 @@ bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
/// add/sub sp brackets around call sites. Returns true if the call frame is
/// included as part of the stack frame.
bool ARMFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- const MachineFrameInfo *FFI = MF.getFrameInfo();
- unsigned CFSize = FFI->getMaxCallFrameSize();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned CFSize = MFI.getMaxCallFrameSize();
// It's not always a good idea to include the call frame as part of the
// stack frame. ARM (especially Thumb) has small immediate offset to
// address the stack frame. So a large call frame can cause poor codegen
@@ -86,7 +86,7 @@ bool ARMFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
if (CFSize >= ((1 << 12) - 1) / 2) // Half of imm12
return false;
- return !MF.getFrameInfo()->hasVarSizedObjects();
+ return !MFI.hasVarSizedObjects();
}
/// canSimplifyCallFramePseudos - If there is a reserved call frame, the
@@ -95,7 +95,7 @@ bool ARMFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
/// even when FP is available in Thumb2 mode.
bool
ARMFrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const {
- return hasReservedCallFrame(MF) || MF.getFrameInfo()->hasVarSizedObjects();
+ return hasReservedCallFrame(MF) || MF.getFrameInfo().hasVarSizedObjects();
}
static bool isCSRestore(MachineInstr &MI, const ARMBaseInstrInfo &TII,
@@ -169,9 +169,9 @@ static int sizeOfSPAdjustment(const MachineInstr &MI) {
static bool WindowsRequiresStackProbe(const MachineFunction &MF,
size_t StackSizeInBytes) {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const Function *F = MF.getFunction();
- unsigned StackProbeSize = (MFI->getStackProtectorIndex() > 0) ? 4080 : 4096;
+ unsigned StackProbeSize = (MFI.getStackProtectorIndex() > 0) ? 4080 : 4096;
if (F->hasFnAttribute("stack-probe-size"))
F->getFnAttribute("stack-probe-size")
.getValueAsString()
@@ -196,22 +196,21 @@ struct StackAdjustingInsts {
}
void addExtraBytes(const MachineBasicBlock::iterator I, unsigned ExtraBytes) {
- auto Info = std::find_if(Insts.begin(), Insts.end(),
- [&](InstInfo &Info) { return Info.I == I; });
+ auto Info = find_if(Insts, [&](InstInfo &Info) { return Info.I == I; });
assert(Info != Insts.end() && "invalid sp adjusting instruction");
Info->SPAdjust += ExtraBytes;
}
- void emitDefCFAOffsets(MachineModuleInfo &MMI, MachineBasicBlock &MBB,
- const DebugLoc &dl, const ARMBaseInstrInfo &TII,
- bool HasFP) {
+ void emitDefCFAOffsets(MachineBasicBlock &MBB, const DebugLoc &dl,
+ const ARMBaseInstrInfo &TII, bool HasFP) {
+ MachineFunction &MF = *MBB.getParent();
unsigned CFAOffset = 0;
for (auto &Info : Insts) {
if (HasFP && !Info.BeforeFPSet)
return;
CFAOffset -= Info.SPAdjust;
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset));
BuildMI(MBB, std::next(Info.I), dl,
TII.get(TargetOpcode::CFI_INSTRUCTION))
@@ -288,7 +287,7 @@ static void emitAligningInstructions(MachineFunction &MF, ARMFunctionInfo *AFI,
void ARMFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
MachineModuleInfo &MMI = MF.getMMI();
MCContext &Context = MMI.getContext();
@@ -301,8 +300,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
bool isARM = !AFI->isThumbFunction();
unsigned Align = STI.getFrameLowering()->getStackAlignment();
unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
- unsigned NumBytes = MFI->getStackSize();
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ unsigned NumBytes = MFI.getStackSize();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
@@ -339,7 +338,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
DefCFAOffsetCandidates.addInst(std::prev(MBBI),
NumBytes - ArgRegsSaveSize, true);
}
- DefCFAOffsetCandidates.emitDefCFAOffsets(MMI, MBB, dl, TII, HasFP);
+ DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP);
return;
}
@@ -353,11 +352,11 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R10:
case ARM::R11:
case ARM::R12:
- if (STI.splitFramePushPop()) {
+ if (STI.splitFramePushPop(MF)) {
GPRCS2Size += 4;
break;
}
- // fallthrough
+ LLVM_FALLTHROUGH;
case ARM::R0:
case ARM::R1:
case ARM::R2:
@@ -396,8 +395,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
int FramePtrOffsetInPush = 0;
if (HasFP) {
FramePtrOffsetInPush =
- MFI->getObjectOffset(FramePtrSpillFI) + ArgRegsSaveSize;
- AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) +
+ MFI.getObjectOffset(FramePtrSpillFI) + ArgRegsSaveSize;
+ AFI->setFramePtrSpillOffset(MFI.getObjectOffset(FramePtrSpillFI) +
NumBytes);
}
AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
@@ -414,7 +413,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// .cfi_offset operations will reflect that.
if (DPRGapSize) {
assert(DPRGapSize == 4 && "unexpected alignment requirements for DPRs");
- if (tryFoldSPUpdateIntoPushPop(STI, MF, &*LastPush, DPRGapSize))
+ if (LastPush != MBB.end() &&
+ tryFoldSPUpdateIntoPushPop(STI, MF, &*LastPush, DPRGapSize))
DefCFAOffsetCandidates.addExtraBytes(LastPush, DPRGapSize);
else {
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -DPRGapSize,
@@ -440,7 +440,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// leaves the stack pointer pointing to the DPRCS2 area.
//
// Adjust NumBytes to represent the stack slots below the DPRCS2 area.
- NumBytes += MFI->getObjectOffset(D8SpillFI);
+ NumBytes += MFI.getObjectOffset(D8SpillFI);
} else
NumBytes = DPRCSOffset;
@@ -526,7 +526,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
PushSize + FramePtrOffsetInPush,
MachineInstr::FrameSetup);
if (FramePtrOffsetInPush + PushSize != 0) {
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfa(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(
nullptr, MRI->getDwarfRegNum(FramePtr, true),
-(ArgRegsSaveSize - FramePtrOffsetInPush)));
BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
@@ -534,7 +534,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
.setMIFlags(MachineInstr::FrameSetup);
} else {
unsigned CFIIndex =
- MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(
+ MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FramePtr, true)));
BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -557,9 +557,9 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R10:
case ARM::R11:
case ARM::R12:
- if (STI.splitFramePushPop())
+ if (STI.splitFramePushPop(MF))
break;
- // fallthrough
+ LLVM_FALLTHROUGH;
case ARM::R0:
case ARM::R1:
case ARM::R2:
@@ -569,8 +569,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R6:
case ARM::R7:
case ARM::LR:
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
- nullptr, MRI->getDwarfRegNum(Reg, true), MFI->getObjectOffset(FI)));
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
+ nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
@@ -590,10 +590,10 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R10:
case ARM::R11:
case ARM::R12:
- if (STI.splitFramePushPop()) {
+ if (STI.splitFramePushPop(MF)) {
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
- unsigned Offset = MFI->getObjectOffset(FI);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned Offset = MFI.getObjectOffset(FI);
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -614,8 +614,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
if ((Reg >= ARM::D0 && Reg <= ARM::D31) &&
(Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs())) {
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
- unsigned Offset = MFI->getObjectOffset(FI);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned Offset = MFI.getObjectOffset(FI);
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -628,11 +628,11 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// throughout the process. If we have a frame pointer, it takes over the job
// half-way through, so only the first few .cfi_def_cfa_offset instructions
// actually get emitted.
- DefCFAOffsetCandidates.emitDefCFAOffsets(MMI, MBB, dl, TII, HasFP);
+ DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP);
if (STI.isTargetELF() && hasFP(MF))
- MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() -
- AFI->getFramePtrSpillOffset());
+ MFI.setOffsetAdjustment(MFI.getOffsetAdjustment() -
+ AFI->getFramePtrSpillOffset());
AFI->setGPRCalleeSavedArea1Size(GPRCS1Size);
AFI->setGPRCalleeSavedArea2Size(GPRCS2Size);
@@ -644,7 +644,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// If aligned NEON registers were spilled, the stack has already been
// realigned.
if (!AFI->getNumAlignedDPRCS2Regs() && RegInfo->needsStackRealignment(MF)) {
- unsigned MaxAlign = MFI->getMaxAlignment();
+ unsigned MaxAlign = MFI.getMaxAlignment();
assert(!AFI->isThumb1OnlyFunction());
if (!AFI->isThumbFunction()) {
emitAligningInstructions(MF, AFI, TII, MBB, MBBI, dl, ARM::SP, MaxAlign,
@@ -688,13 +688,13 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// If the frame has variable sized objects then the epilogue must restore
// the sp from fp. We can assume there's an FP here since hasFP already
// checks for hasVarSizedObjects.
- if (MFI->hasVarSizedObjects())
+ if (MFI.hasVarSizedObjects())
AFI->setShouldRestoreSPFromFP(true);
}
void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
const ARMBaseInstrInfo &TII =
@@ -704,7 +704,7 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
bool isARM = !AFI->isThumbFunction();
unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
- int NumBytes = (int)MFI->getStackSize();
+ int NumBytes = (int)MFI.getStackSize();
unsigned FramePtr = RegInfo->getFrameRegister(MF);
// All calls are tail calls in GHC calling conv, and functions have no
@@ -753,7 +753,7 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
// This is bad, if an interrupt is taken after the mov, sp is in an
// inconsistent state.
// Use the first callee-saved register as a scratch register.
- assert(!MFI->getPristineRegs(MF).test(ARM::R4) &&
+ assert(!MFI.getPristineRegs(MF).test(ARM::R4) &&
"No scratch register to restore SP from FP!");
emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
ARMCC::AL, 0, TII);
@@ -776,11 +776,11 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes);
// Increment past our save areas.
- if (AFI->getDPRCalleeSavedAreaSize()) {
+ if (MBBI != MBB.end() && AFI->getDPRCalleeSavedAreaSize()) {
MBBI++;
// Since vpop register list cannot have gaps, there may be multiple vpop
// instructions in the epilogue.
- while (MBBI->getOpcode() == ARM::VLDMDIA_UPD)
+ while (MBBI != MBB.end() && MBBI->getOpcode() == ARM::VLDMDIA_UPD)
MBBI++;
}
if (AFI->getDPRCalleeSavedGapSize()) {
@@ -811,13 +811,13 @@ int
ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF,
int FI, unsigned &FrameReg,
int SPAdj) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const ARMBaseRegisterInfo *RegInfo = static_cast<const ARMBaseRegisterInfo *>(
MF.getSubtarget().getRegisterInfo());
const ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize();
+ int Offset = MFI.getObjectOffset(FI) + MFI.getStackSize();
int FPOffset = Offset - AFI->getFramePtrSpillOffset();
- bool isFixed = MFI->isFixedObjectIndex(FI);
+ bool isFixed = MFI.isFixedObjectIndex(FI);
FrameReg = ARM::SP;
Offset += SPAdj;
@@ -893,16 +893,18 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
unsigned MIFlags) const {
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
DebugLoc DL;
- SmallVector<std::pair<unsigned,bool>, 4> Regs;
+ typedef std::pair<unsigned, bool> RegAndKill;
+ SmallVector<RegAndKill, 4> Regs;
unsigned i = CSI.size();
while (i != 0) {
unsigned LastReg = 0;
for (; i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
- if (!(Func)(Reg, STI.splitFramePushPop())) continue;
+ if (!(Func)(Reg, STI.splitFramePushPop(MF))) continue;
// D-registers in the aligned area DPRCS2 are NOT spilled here.
if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
@@ -927,6 +929,12 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
if (Regs.empty())
continue;
+
+ std::sort(Regs.begin(), Regs.end(), [&](const RegAndKill &LHS,
+ const RegAndKill &RHS) {
+ return TRI.getEncodingValue(LHS.first) < TRI.getEncodingValue(RHS.first);
+ });
+
if (Regs.size() > 1 || StrOpc== 0) {
MachineInstrBuilder MIB =
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP)
@@ -960,6 +968,7 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
unsigned NumAlignedDPRCS2Regs) const {
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL;
bool isTailCall = false;
@@ -983,7 +992,7 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
bool DeleteRet = false;
for (; i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
- if (!(Func)(Reg, STI.splitFramePushPop())) continue;
+ if (!(Func)(Reg, STI.splitFramePushPop(MF))) continue;
// The aligned reloads from area DPRCS2 are not inserted here.
if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
@@ -1012,6 +1021,11 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
if (Regs.empty())
continue;
+
+ std::sort(Regs.begin(), Regs.end(), [&](unsigned LHS, unsigned RHS) {
+ return TRI.getEncodingValue(LHS) < TRI.getEncodingValue(RHS);
+ });
+
if (Regs.size() > 1 || LdrOpc == 0) {
MachineInstrBuilder MIB =
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(LdmOpc), ARM::SP)
@@ -1062,7 +1076,7 @@ static void emitAlignedDPRCS2Spills(MachineBasicBlock &MBB,
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
// Mark the D-register spill slots as properly aligned. Since MFI computes
// stack slot layout backwards, this can actually mean that the d-reg stack
@@ -1104,7 +1118,7 @@ static void emitAlignedDPRCS2Spills(MachineBasicBlock &MBB,
.addReg(ARM::SP)
.addImm(8 * NumAlignedDPRCS2Regs)));
- unsigned MaxAlign = MF.getFrameInfo()->getMaxAlignment();
+ unsigned MaxAlign = MF.getFrameInfo().getMaxAlignment();
// We must set parameter MustBeSingleInstruction to true, since
// skipAlignedDPRCS2Spills expects exactly 3 instructions to perform
// stack alignment. Luckily, this can always be done since all ARM
@@ -1359,7 +1373,7 @@ static unsigned GetFunctionSizeInBytes(const MachineFunction &MF,
unsigned FnSize = 0;
for (auto &MBB : MF) {
for (auto &MI : MBB)
- FnSize += TII.GetInstSizeInBytes(MI);
+ FnSize += TII.getInstSizeInBytes(MI);
}
return FnSize;
}
@@ -1485,8 +1499,10 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
const ARMBaseInstrInfo &TII =
*static_cast<const ARMBaseInstrInfo *>(MF.getSubtarget().getInstrInfo());
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+ (void)TRI; // Silence unused warning in non-assert builds.
unsigned FramePtr = RegInfo->getFrameRegister(MF);
// Spill R4 if Thumb2 function requires stack realignment - it will be used as
@@ -1495,7 +1511,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// instruction.
// FIXME: It will be better just to find spare register here.
if (AFI->isThumb2Function() &&
- (MFI->hasVarSizedObjects() || RegInfo->needsStackRealignment(MF)))
+ (MFI.hasVarSizedObjects() || RegInfo->needsStackRealignment(MF)))
SavedRegs.set(ARM::R4);
if (AFI->isThumb1OnlyFunction()) {
@@ -1509,8 +1525,8 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// we've used all the registers and so R4 is already used, so not marking
// it here will be OK.
// FIXME: It will be better just to find spare register here.
- unsigned StackSize = MFI->estimateStackSize(MF);
- if (MFI->hasVarSizedObjects() || StackSize > 508)
+ unsigned StackSize = MFI.estimateStackSize(MF);
+ if (MFI.hasVarSizedObjects() || StackSize > 508)
SavedRegs.set(ARM::R4);
}
@@ -1547,7 +1563,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
if (Spilled) {
NumGPRSpills++;
- if (!STI.splitFramePushPop()) {
+ if (!STI.splitFramePushPop(MF)) {
if (Reg == ARM::LR)
LRSpilled = true;
CS1Spilled = true;
@@ -1558,7 +1574,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
switch (Reg) {
case ARM::LR:
LRSpilled = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case ARM::R0: case ARM::R1:
case ARM::R2: case ARM::R3:
case ARM::R4: case ARM::R5:
@@ -1569,7 +1585,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
break;
}
} else {
- if (!STI.splitFramePushPop()) {
+ if (!STI.splitFramePushPop(MF)) {
UnspilledCS1GPRs.push_back(Reg);
continue;
}
@@ -1616,7 +1632,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// and which instructions will need a scratch register for them. Is it
// worth the effort and added fragility?
unsigned EstimatedStackSize =
- MFI->estimateStackSize(MF) + 4 * (NumGPRSpills + NumFPRSpills);
+ MFI.estimateStackSize(MF) + 4 * (NumGPRSpills + NumFPRSpills);
if (hasFP(MF)) {
if (AFI->hasStackFrame())
EstimatedStackSize += 4;
@@ -1628,20 +1644,149 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
EstimatedStackSize += 16; // For possible paddings.
bool BigStack = EstimatedStackSize >= estimateRSStackSizeLimit(MF, this) ||
- MFI->hasVarSizedObjects() ||
- (MFI->adjustsStack() && !canSimplifyCallFramePseudos(MF));
+ MFI.hasVarSizedObjects() ||
+ (MFI.adjustsStack() && !canSimplifyCallFramePseudos(MF));
bool ExtraCSSpill = false;
if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) {
AFI->setHasStackFrame(true);
+ if (hasFP(MF)) {
+ SavedRegs.set(FramePtr);
+ // If the frame pointer is required by the ABI, also spill LR so that we
+ // emit a complete frame record.
+ if (MF.getTarget().Options.DisableFramePointerElim(MF) && !LRSpilled) {
+ SavedRegs.set(ARM::LR);
+ LRSpilled = true;
+ NumGPRSpills++;
+ auto LRPos = find(UnspilledCS1GPRs, ARM::LR);
+ if (LRPos != UnspilledCS1GPRs.end())
+ UnspilledCS1GPRs.erase(LRPos);
+ }
+ auto FPPos = find(UnspilledCS1GPRs, FramePtr);
+ if (FPPos != UnspilledCS1GPRs.end())
+ UnspilledCS1GPRs.erase(FPPos);
+ NumGPRSpills++;
+ if (FramePtr == ARM::R7)
+ CS1Spilled = true;
+ }
+
+ if (AFI->isThumb1OnlyFunction()) {
+ // For Thumb1-only targets, we need some low registers when we save and
+ // restore the high registers (which aren't allocatable, but could be
+ // used by inline assembly) because the push/pop instructions can not
+ // access high registers. If necessary, we might need to push more low
+ // registers to ensure that there is at least one free that can be used
+ // for the saving & restoring, and preferably we should ensure that as
+ // many as are needed are available so that fewer push/pop instructions
+ // are required.
+
+ // Low registers which are not currently pushed, but could be (r4-r7).
+ SmallVector<unsigned, 4> AvailableRegs;
+
+ // Unused argument registers (r0-r3) can be clobbered in the prologue for
+ // free.
+ int EntryRegDeficit = 0;
+ 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");
+ }
+ }
+
+ // 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");
+
+ int RegDeficit = std::max(EntryRegDeficit, ExitRegDeficit);
+ 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");
+ } else {
+ AvailableRegs.push_back(Reg);
+ DEBUG(dbgs()
+ << PrintReg(Reg, TRI)
+ << " is non-saved low register, adding to AvailableRegs\n");
+ }
+ }
+
+ // r7 can be used if it is not being used as the frame pointer.
+ if (!hasFP(MF)) {
+ if (SavedRegs.test(ARM::R7)) {
+ --RegDeficit;
+ 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");
+ }
+ }
+
+ // Each of r8-r11 needs to be copied to a low register, then pushed.
+ 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");
+ }
+ }
+
+ // LR can only be used by PUSH, not POP, and can't be used at all if the
+ // llvm.returnaddress intrinsic is used. This is only worth doing if we
+ // are more limited at function entry than exit.
+ if ((EntryRegDeficit > ExitRegDeficit) &&
+ !(MF.getRegInfo().isLiveIn(ARM::LR) &&
+ MF.getFrameInfo().isReturnAddressTaken())) {
+ if (SavedRegs.test(ARM::LR)) {
+ --RegDeficit;
+ 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");
+ }
+ }
+
+ // If there are more high registers that need pushing than low registers
+ // available, push some more low registers so that we can use fewer push
+ // 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");
+ for (; RegDeficit > 0 && !AvailableRegs.empty(); --RegDeficit) {
+ unsigned Reg = AvailableRegs.pop_back_val();
+ DEBUG(dbgs() << "Spilling " << PrintReg(Reg, TRI)
+ << " to make up reg deficit\n");
+ SavedRegs.set(Reg);
+ NumGPRSpills++;
+ CS1Spilled = true;
+ ExtraCSSpill = true;
+ UnspilledCS1GPRs.erase(find(UnspilledCS1GPRs, Reg));
+ if (Reg == ARM::LR)
+ LRSpilled = true;
+ }
+ 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.
// Spill LR as well so we can fold BX_RET to the registers restore (LDM).
if (!LRSpilled && CS1Spilled) {
SavedRegs.set(ARM::LR);
NumGPRSpills++;
SmallVectorImpl<unsigned>::iterator LRPos;
- LRPos = std::find(UnspilledCS1GPRs.begin(), UnspilledCS1GPRs.end(),
- (unsigned)ARM::LR);
+ LRPos = find(UnspilledCS1GPRs, (unsigned)ARM::LR);
if (LRPos != UnspilledCS1GPRs.end())
UnspilledCS1GPRs.erase(LRPos);
@@ -1649,18 +1794,10 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
ExtraCSSpill = true;
}
- if (hasFP(MF)) {
- SavedRegs.set(FramePtr);
- auto FPPos = std::find(UnspilledCS1GPRs.begin(), UnspilledCS1GPRs.end(),
- FramePtr);
- if (FPPos != UnspilledCS1GPRs.end())
- UnspilledCS1GPRs.erase(FPPos);
- NumGPRSpills++;
- }
-
// 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");
unsigned TargetAlign = getStackAlignment();
if (TargetAlign >= 8 && (NumGPRSpills & 1)) {
if (CS1Spilled && !UnspilledCS1GPRs.empty()) {
@@ -1672,6 +1809,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");
if (!MRI.isReserved(Reg))
ExtraCSSpill = true;
break;
@@ -1680,6 +1819,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");
if (!MRI.isReserved(Reg))
ExtraCSSpill = true;
}
@@ -1725,9 +1866,9 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// closest to SP or frame pointer.
assert(RS && "Register scavenging not provided");
const TargetRegisterClass *RC = &ARM::GPRRegClass;
- RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
- RC->getAlignment(),
- false));
+ RS->addScavengingFrameIndex(MFI.CreateStackObject(RC->getSize(),
+ RC->getAlignment(),
+ false));
}
}
}
@@ -1855,7 +1996,7 @@ void ARMFrameLowering::adjustForSegmentedStacks(
if (!ST->isTargetAndroid() && !ST->isTargetLinux())
report_fatal_error("Segmented stacks not supported on this platform.");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
MCContext &Context = MMI.getContext();
const MCRegisterInfo *MRI = Context.getRegisterInfo();
@@ -1864,7 +2005,7 @@ void ARMFrameLowering::adjustForSegmentedStacks(
ARMFunctionInfo *ARMFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL;
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
// Do not generate a prologue for functions with a stack of size zero
if (StackSize == 0)
@@ -1951,14 +2092,14 @@ void ARMFrameLowering::adjustForSegmentedStacks(
// Emit the relevant DWARF information about the change in stack pointer as
// well as where to find both r4 and r5 (the callee-save registers)
CFIIndex =
- MMI.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -8));
+ MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -8));
BuildMI(PrevStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ScratchReg1, true), -4));
BuildMI(PrevStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ScratchReg0, true), -8));
BuildMI(PrevStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -2069,10 +2210,10 @@ void ARMFrameLowering::adjustForSegmentedStacks(
// Emit the DWARF info about the change in stack as well as where to find the
// previous link register
CFIIndex =
- MMI.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -12));
+ MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -12));
BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ARM::LR, true), -12));
BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -2124,7 +2265,7 @@ void ARMFrameLowering::adjustForSegmentedStacks(
}
// Update the CFA offset now that we've popped
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0));
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0));
BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -2147,17 +2288,17 @@ void ARMFrameLowering::adjustForSegmentedStacks(
}
// Update the CFA offset now that we've popped
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0));
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0));
BuildMI(PostStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// Tell debuggers that r4 and r5 are now the same as they were in the
// previous function, that they're the "Same Value".
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createSameValue(
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createSameValue(
nullptr, MRI->getDwarfRegNum(ScratchReg0, true)));
BuildMI(PostStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createSameValue(
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createSameValue(
nullptr, MRI->getDwarfRegNum(ScratchReg1, true)));
BuildMI(PostStackMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
diff --git a/contrib/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/contrib/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 20db3d3..c3e9591 100644
--- a/contrib/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -70,9 +70,7 @@ public:
return true;
}
- const char *getPassName() const override {
- return "ARM Instruction Selection";
- }
+ StringRef getPassName() const override { return "ARM Instruction Selection"; }
void PreprocessISelDAG() override;
@@ -193,6 +191,8 @@ public:
#include "ARMGenDAGISel.inc"
private:
+ void transferMemOperands(SDNode *Src, SDNode *Dst);
+
/// Indexed (pre/post inc/dec) load matching code for ARM.
bool tryARMIndexedLoad(SDNode *N);
bool tryT1IndexedLoad(SDNode *N);
@@ -222,10 +222,11 @@ private:
const uint16_t *QOpcodes);
/// SelectVLDDup - Select NEON load-duplicate intrinsics. NumVecs
- /// should be 2, 3 or 4. The opcode array specifies the instructions used
+ /// 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 *Opcodes);
+ const uint16_t *DOpcodes,
+ const uint16_t *QOpcodes = nullptr);
/// SelectVTBL - Select NEON VTBL and VTBX intrinsics. NumVecs should be 2,
/// 3 or 4. These are custom-selected so that a REG_SEQUENCE can be
@@ -244,6 +245,7 @@ private:
bool tryInlineAsm(SDNode *N);
void SelectConcatVector(SDNode *N);
+ void SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI);
bool trySMLAWSMULW(SDNode *N);
@@ -476,7 +478,9 @@ bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
unsigned ARMDAGToDAGISel::ConstantMaterializationCost(unsigned Val) const {
if (Subtarget->isThumb()) {
if (Val <= 255) return 1; // MOV
- if (Subtarget->hasV6T2Ops() && Val <= 0xffff) return 1; // MOVW
+ if (Subtarget->hasV6T2Ops() &&
+ (Val <= 0xffff || ARM_AM::getT2SOImmValSplatVal(Val) != -1))
+ return 1; // MOVW
if (Val <= 510) return 2; // MOV + ADDi8
if (~Val <= 255) return 2; // MOV + MVN
if (ARM_AM::isThumbImmShiftedVal(Val)) return 2; // MOV + LSL
@@ -1186,6 +1190,7 @@ ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale,
} else if (N.getOpcode() == ARMISD::Wrapper &&
N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
+ N.getOperand(0).getOpcode() != ISD::TargetConstantPool &&
N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Base = N.getOperand(0);
} else {
@@ -1232,9 +1237,9 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N,
int FI = cast<FrameIndexSDNode>(N)->getIndex();
// Only multiples of 4 are allowed for the offset, so the frame object
// alignment must be at least 4.
- MachineFrameInfo *MFI = MF->getFrameInfo();
- if (MFI->getObjectAlignment(FI) < 4)
- MFI->setObjectAlignment(FI, 4);
+ MachineFrameInfo &MFI = MF->getFrameInfo();
+ if (MFI.getObjectAlignment(FI) < 4)
+ MFI.setObjectAlignment(FI, 4);
Base = CurDAG->getTargetFrameIndex(
FI, TLI->getPointerTy(CurDAG->getDataLayout()));
OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
@@ -1255,9 +1260,9 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N,
int FI = cast<FrameIndexSDNode>(Base)->getIndex();
// For LHS+RHS to result in an offset that's a multiple of 4 the object
// indexed by the LHS must be 4-byte aligned.
- MachineFrameInfo *MFI = MF->getFrameInfo();
- if (MFI->getObjectAlignment(FI) < 4)
- MFI->setObjectAlignment(FI, 4);
+ MachineFrameInfo &MFI = MF->getFrameInfo();
+ if (MFI.getObjectAlignment(FI) < 4)
+ MFI.setObjectAlignment(FI, 4);
Base = CurDAG->getTargetFrameIndex(
FI, TLI->getPointerTy(CurDAG->getDataLayout()));
}
@@ -1469,6 +1474,12 @@ static inline SDValue getAL(SelectionDAG *CurDAG, const SDLoc &dl) {
return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, dl, MVT::i32);
}
+void ARMDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) {
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = cast<MemSDNode>(N)->getMemOperand();
+ cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
+}
+
bool ARMDAGToDAGISel::tryARMIndexedLoad(SDNode *N) {
LoadSDNode *LD = cast<LoadSDNode>(N);
ISD::MemIndexedMode AM = LD->getAddressingMode();
@@ -1527,16 +1538,20 @@ bool ARMDAGToDAGISel::tryARMIndexedLoad(SDNode *N) {
SDValue Base = LD->getBasePtr();
SDValue Ops[]= { Base, AMOpc, getAL(CurDAG, SDLoc(N)),
CurDAG->getRegister(0, MVT::i32), Chain };
- ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32,
- MVT::i32, MVT::Other, Ops));
+ SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
+ MVT::Other, Ops);
+ transferMemOperands(N, New);
+ ReplaceNode(N, New);
return true;
} else {
SDValue Chain = LD->getChain();
SDValue Base = LD->getBasePtr();
SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG, SDLoc(N)),
CurDAG->getRegister(0, MVT::i32), Chain };
- ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32,
- MVT::i32, MVT::Other, Ops));
+ SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
+ MVT::Other, Ops);
+ transferMemOperands(N, New);
+ ReplaceNode(N, New);
return true;
}
}
@@ -1548,8 +1563,8 @@ bool ARMDAGToDAGISel::tryT1IndexedLoad(SDNode *N) {
LoadSDNode *LD = cast<LoadSDNode>(N);
EVT LoadedVT = LD->getMemoryVT();
ISD::MemIndexedMode AM = LD->getAddressingMode();
- if (AM == ISD::UNINDEXED || LD->getExtensionType() != ISD::NON_EXTLOAD ||
- AM != ISD::POST_INC || LoadedVT.getSimpleVT().SimpleTy != MVT::i32)
+ if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD ||
+ LoadedVT.getSimpleVT().SimpleTy != MVT::i32)
return false;
auto *COffs = dyn_cast<ConstantSDNode>(LD->getOffset());
@@ -1564,8 +1579,10 @@ bool ARMDAGToDAGISel::tryT1IndexedLoad(SDNode *N) {
SDValue Base = LD->getBasePtr();
SDValue Ops[]= { Base, getAL(CurDAG, SDLoc(N)),
CurDAG->getRegister(0, MVT::i32), Chain };
- ReplaceNode(N, CurDAG->getMachineNode(ARM::tLDR_postidx, SDLoc(N), MVT::i32, MVT::i32,
- MVT::Other, Ops));
+ SDNode *New = CurDAG->getMachineNode(ARM::tLDR_postidx, SDLoc(N), MVT::i32,
+ MVT::i32, MVT::Other, Ops);
+ transferMemOperands(N, New);
+ ReplaceNode(N, New);
return true;
}
@@ -1610,8 +1627,10 @@ bool ARMDAGToDAGISel::tryT2IndexedLoad(SDNode *N) {
SDValue Base = LD->getBasePtr();
SDValue Ops[]= { Base, Offset, getAL(CurDAG, SDLoc(N)),
CurDAG->getRegister(0, MVT::i32), Chain };
- ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
- MVT::Other, Ops));
+ SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
+ MVT::Other, Ops);
+ transferMemOperands(N, New);
+ ReplaceNode(N, New);
return true;
}
@@ -1744,6 +1763,12 @@ static bool isVLDfixed(unsigned Opc)
case ARM::VLD1q16wb_fixed : return true;
case ARM::VLD1q32wb_fixed : return true;
case ARM::VLD1q64wb_fixed : return true;
+ case ARM::VLD1DUPd8wb_fixed : return true;
+ case ARM::VLD1DUPd16wb_fixed : return true;
+ case ARM::VLD1DUPd32wb_fixed : return true;
+ case ARM::VLD1DUPq8wb_fixed : return true;
+ case ARM::VLD1DUPq16wb_fixed : return true;
+ case ARM::VLD1DUPq32wb_fixed : return true;
case ARM::VLD2d8wb_fixed : return true;
case ARM::VLD2d16wb_fixed : return true;
case ARM::VLD2d32wb_fixed : return true;
@@ -1798,6 +1823,12 @@ static unsigned getVLDSTRegisterUpdateOpcode(unsigned Opc) {
case ARM::VLD1d64Qwb_fixed: return ARM::VLD1d64Qwb_register;
case ARM::VLD1d64TPseudoWB_fixed: return ARM::VLD1d64TPseudoWB_register;
case ARM::VLD1d64QPseudoWB_fixed: return ARM::VLD1d64QPseudoWB_register;
+ case ARM::VLD1DUPd8wb_fixed : return ARM::VLD1DUPd8wb_register;
+ case ARM::VLD1DUPd16wb_fixed : return ARM::VLD1DUPd16wb_register;
+ case ARM::VLD1DUPd32wb_fixed : return ARM::VLD1DUPd32wb_register;
+ case ARM::VLD1DUPq8wb_fixed : return ARM::VLD1DUPq8wb_register;
+ case ARM::VLD1DUPq16wb_fixed : return ARM::VLD1DUPq16wb_register;
+ case ARM::VLD1DUPq32wb_fixed : return ARM::VLD1DUPq32wb_register;
case ARM::VST1d8wb_fixed: return ARM::VST1d8wb_register;
case ARM::VST1d16wb_fixed: return ARM::VST1d16wb_register;
@@ -2140,7 +2171,7 @@ void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
unsigned Alignment = 0;
if (NumVecs != 3) {
Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
- unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8;
+ unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
if (Alignment > NumBytes)
Alignment = NumBytes;
if (Alignment < 8 && Alignment < NumBytes)
@@ -2238,8 +2269,9 @@ void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
}
void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
- const uint16_t *Opcodes) {
- assert(NumVecs >=2 && NumVecs <= 4 && "VLDDup NumVecs out-of-range");
+ const uint16_t *DOpcodes,
+ const uint16_t *QOpcodes) {
+ assert(NumVecs >= 1 && NumVecs <= 4 && "VLDDup NumVecs out-of-range");
SDLoc dl(N);
SDValue MemAddr, Align;
@@ -2255,7 +2287,7 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
unsigned Alignment = 0;
if (NumVecs != 3) {
Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
- unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8;
+ unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
if (Alignment > NumBytes)
Alignment = NumBytes;
if (Alignment < 8 && Alignment < NumBytes)
@@ -2267,19 +2299,21 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
}
Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
- unsigned OpcodeIndex;
+ unsigned Opc;
switch (VT.getSimpleVT().SimpleTy) {
default: llvm_unreachable("unhandled vld-dup type");
- case MVT::v8i8: OpcodeIndex = 0; break;
- case MVT::v4i16: OpcodeIndex = 1; break;
+ 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::v2f32:
- case MVT::v2i32: OpcodeIndex = 2; break;
+ case MVT::v2i32: Opc = DOpcodes[2]; break;
+ case MVT::v4f32:
+ case MVT::v4i32: Opc = QOpcodes[2]; break;
}
SDValue Pred = getAL(CurDAG, dl);
SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
- SDValue SuperReg;
- unsigned Opc = Opcodes[OpcodeIndex];
SmallVector<SDValue, 6> Ops;
Ops.push_back(MemAddr);
Ops.push_back(Align);
@@ -2287,6 +2321,8 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
// fixed-stride update instructions don't have an explicit writeback
// operand. It's implicit in the opcode itself.
SDValue Inc = N->getOperand(2);
+ if (NumVecs <= 2 && !isa<ConstantSDNode>(Inc.getNode()))
+ Opc = getVLDSTRegisterUpdateOpcode(Opc);
if (!isa<ConstantSDNode>(Inc.getNode()))
Ops.push_back(Inc);
// FIXME: VLD3 and VLD4 haven't been updated to that form yet.
@@ -2305,14 +2341,18 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
ResTys.push_back(MVT::Other);
SDNode *VLdDup = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
cast<MachineSDNode>(VLdDup)->setMemRefs(MemOp, MemOp + 1);
- SuperReg = SDValue(VLdDup, 0);
// Extract the subregisters.
- static_assert(ARM::dsub_7 == ARM::dsub_0 + 7, "Unexpected subreg numbering");
- unsigned SubIdx = ARM::dsub_0;
- for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
- ReplaceUses(SDValue(N, Vec),
- CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg));
+ if (NumVecs == 1) {
+ ReplaceUses(SDValue(N, 0), SDValue(VLdDup, 0));
+ } 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)
+ ReplaceUses(SDValue(N, Vec),
+ CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg));
+ }
ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1));
if (isUpdating)
ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdDup, 2));
@@ -2612,6 +2652,10 @@ static bool SearchSignedMulLong(SDValue OR, unsigned *Opc, SDValue &Src0,
}
bool ARMDAGToDAGISel::trySMLAWSMULW(SDNode *N) {
+ if (!Subtarget->hasV6Ops() ||
+ (Subtarget->isThumb() && !Subtarget->hasThumb2()))
+ return false;
+
SDLoc dl(N);
SDValue Src0 = N->getOperand(0);
SDValue Src1 = N->getOperand(1);
@@ -2687,6 +2731,87 @@ void ARMDAGToDAGISel::SelectConcatVector(SDNode *N) {
ReplaceNode(N, createDRegPairNode(VT, N->getOperand(0), N->getOperand(1)));
}
+static Optional<std::pair<unsigned, unsigned>>
+getContiguousRangeOfSetBits(const APInt &A) {
+ unsigned FirstOne = A.getBitWidth() - A.countLeadingZeros() - 1;
+ unsigned LastOne = A.countTrailingZeros();
+ if (A.countPopulation() != (FirstOne - LastOne + 1))
+ return Optional<std::pair<unsigned,unsigned>>();
+ return std::make_pair(FirstOne, LastOne);
+}
+
+void ARMDAGToDAGISel::SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI) {
+ assert(N->getOpcode() == ARMISD::CMPZ);
+ SwitchEQNEToPLMI = false;
+
+ if (!Subtarget->isThumb())
+ // FIXME: Work out whether it is profitable to do this in A32 mode - LSL and
+ // LSR don't exist as standalone instructions - they need the barrel shifter.
+ return;
+
+ // select (cmpz (and X, C), #0) -> (LSLS X) or (LSRS X) or (LSRS (LSLS X))
+ SDValue And = N->getOperand(0);
+ if (!And->hasOneUse())
+ return;
+
+ SDValue Zero = N->getOperand(1);
+ if (!isa<ConstantSDNode>(Zero) || !cast<ConstantSDNode>(Zero)->isNullValue() ||
+ And->getOpcode() != ISD::AND)
+ return;
+ SDValue X = And.getOperand(0);
+ auto C = dyn_cast<ConstantSDNode>(And.getOperand(1));
+
+ if (!C || !X->hasOneUse())
+ return;
+ auto Range = getContiguousRangeOfSetBits(C->getAPIntValue());
+ if (!Range)
+ return;
+
+ // There are several ways to lower this:
+ SDNode *NewN;
+ SDLoc dl(N);
+
+ auto EmitShift = [&](unsigned Opc, SDValue Src, unsigned Imm) -> SDNode* {
+ if (Subtarget->isThumb2()) {
+ Opc = (Opc == ARM::tLSLri) ? ARM::t2LSLri : ARM::t2LSRri;
+ SDValue Ops[] = { Src, CurDAG->getTargetConstant(Imm, dl, MVT::i32),
+ getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
+ CurDAG->getRegister(0, MVT::i32) };
+ return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
+ } else {
+ SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), Src,
+ CurDAG->getTargetConstant(Imm, dl, MVT::i32),
+ getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
+ return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
+ }
+ };
+
+ if (Range->second == 0) {
+ // 1. Mask includes the LSB -> Simply shift the top N bits off
+ NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
+ ReplaceNode(And.getNode(), NewN);
+ } else if (Range->first == 31) {
+ // 2. Mask includes the MSB -> Simply shift the bottom N bits off
+ NewN = EmitShift(ARM::tLSRri, X, Range->second);
+ ReplaceNode(And.getNode(), NewN);
+ } else if (Range->first == Range->second) {
+ // 3. Only one bit is set. We can shift this into the sign bit and use a
+ // PL/MI comparison.
+ NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
+ ReplaceNode(And.getNode(), NewN);
+
+ SwitchEQNEToPLMI = true;
+ } else if (!Subtarget->hasV6T2Ops()) {
+ // 4. Do a double shift to clear bottom and top bits, but only in
+ // thumb-1 mode as in thumb-2 we can use UBFX.
+ NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
+ NewN = EmitShift(ARM::tLSRri, SDValue(NewN, 0),
+ Range->second + (31 - Range->first));
+ ReplaceNode(And.getNode(), NewN);
+ }
+
+}
+
void ARMDAGToDAGISel::Select(SDNode *N) {
SDLoc dl(N);
@@ -2761,9 +2886,9 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
if (Subtarget->isThumb1Only()) {
// Set the alignment of the frame object to 4, to avoid having to generate
// more than one ADD
- MachineFrameInfo *MFI = MF->getFrameInfo();
- if (MFI->getObjectAlignment(FI) < 4)
- MFI->setObjectAlignment(FI, 4);
+ MachineFrameInfo &MFI = MF->getFrameInfo();
+ if (MFI.getObjectAlignment(FI) < 4)
+ MFI.setObjectAlignment(FI, 4);
CurDAG->SelectNodeTo(N, ARM::tADDframe, MVT::i32, TFI,
CurDAG->getTargetConstant(0, dl, MVT::i32));
return;
@@ -2914,6 +3039,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
}
+
break;
}
case ARMISD::VMOVRRD:
@@ -2971,7 +3097,8 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
case ARMISD::UMLAL:{
// UMAAL is similar to UMLAL but it adds two 32-bit values to the
// 64-bit multiplication result.
- if (Subtarget->hasV6Ops() && N->getOperand(2).getOpcode() == ARMISD::ADDC &&
+ if (Subtarget->hasV6Ops() && Subtarget->hasDSP() &&
+ N->getOperand(2).getOpcode() == ARMISD::ADDC &&
N->getOperand(3).getOpcode() == ARMISD::ADDE) {
SDValue Addc = N->getOperand(2);
@@ -3037,6 +3164,37 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
}
+ case ARMISD::SUBE: {
+ if (!Subtarget->hasV6Ops())
+ break;
+ // Look for a pattern to match SMMLS
+ // (sube a, (smul_loHi a, b), (subc 0, (smul_LOhi(a, b))))
+ if (N->getOperand(1).getOpcode() != ISD::SMUL_LOHI ||
+ N->getOperand(2).getOpcode() != ARMISD::SUBC ||
+ !SDValue(N, 1).use_empty())
+ break;
+
+ if (Subtarget->isThumb())
+ assert(Subtarget->hasThumb2() &&
+ "This pattern should not be generated for Thumb");
+
+ SDValue SmulLoHi = N->getOperand(1);
+ SDValue Subc = N->getOperand(2);
+ auto *Zero = dyn_cast<ConstantSDNode>(Subc.getOperand(0));
+
+ if (!Zero || Zero->getZExtValue() != 0 ||
+ Subc.getOperand(1) != SmulLoHi.getValue(0) ||
+ N->getOperand(1) != SmulLoHi.getValue(1) ||
+ N->getOperand(2) != Subc.getValue(1))
+ break;
+
+ unsigned Opc = Subtarget->isThumb2() ? ARM::t2SMMLS : ARM::SMMLS;
+ SDValue Ops[] = { SmulLoHi.getOperand(0), SmulLoHi.getOperand(1),
+ N->getOperand(0), getAL(CurDAG, dl),
+ CurDAG->getRegister(0, MVT::i32) };
+ ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops));
+ return;
+ }
case ISD::LOAD: {
if (Subtarget->isThumb() && Subtarget->hasThumb2()) {
if (tryT2IndexedLoad(N))
@@ -3073,9 +3231,27 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
assert(N2.getOpcode() == ISD::Constant);
assert(N3.getOpcode() == ISD::Register);
- SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
- cast<ConstantSDNode>(N2)->getZExtValue()), dl,
- MVT::i32);
+ unsigned CC = (unsigned) cast<ConstantSDNode>(N2)->getZExtValue();
+
+ if (InFlag.getOpcode() == ARMISD::CMPZ) {
+ bool SwitchEQNEToPLMI;
+ SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI);
+ InFlag = N->getOperand(4);
+
+ if (SwitchEQNEToPLMI) {
+ switch ((ARMCC::CondCodes)CC) {
+ default: llvm_unreachable("CMPZ must be either NE or EQ!");
+ case ARMCC::NE:
+ CC = (unsigned)ARMCC::MI;
+ break;
+ case ARMCC::EQ:
+ CC = (unsigned)ARMCC::PL;
+ break;
+ }
+ }
+ }
+
+ SDValue Tmp2 = CurDAG->getTargetConstant(CC, dl, MVT::i32);
SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag };
SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other,
MVT::Glue, Ops);
@@ -3089,6 +3265,80 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
CurDAG->RemoveDeadNode(N);
return;
}
+
+ case ARMISD::CMPZ: {
+ // select (CMPZ X, #-C) -> (CMPZ (ADDS X, #C), #0)
+ // This allows us to avoid materializing the expensive negative constant.
+ // The CMPZ #0 is useless and will be peepholed away but we need to keep it
+ // for its glue output.
+ SDValue X = N->getOperand(0);
+ auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
+ if (C && C->getSExtValue() < 0 && Subtarget->isThumb()) {
+ int64_t Addend = -C->getSExtValue();
+
+ SDNode *Add = nullptr;
+ // In T2 mode, ADDS can be better than CMN if the immediate fits in a
+ // 16-bit ADDS, which means either [0,256) for tADDi8 or [0,8) for tADDi3.
+ // Outside that range we can just use a CMN which is 32-bit but has a
+ // 12-bit immediate range.
+ if (Subtarget->isThumb2() && Addend < 1<<8) {
+ SDValue Ops[] = { X, CurDAG->getTargetConstant(Addend, dl, MVT::i32),
+ getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
+ CurDAG->getRegister(0, MVT::i32) };
+ Add = CurDAG->getMachineNode(ARM::t2ADDri, dl, MVT::i32, Ops);
+ } else if (!Subtarget->isThumb2() && Addend < 1<<8) {
+ // FIXME: Add T1 tADDi8 code.
+ SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
+ CurDAG->getTargetConstant(Addend, dl, MVT::i32),
+ getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
+ Add = CurDAG->getMachineNode(ARM::tADDi8, dl, MVT::i32, Ops);
+ } else if (!Subtarget->isThumb2() && Addend < 1<<3) {
+ SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
+ CurDAG->getTargetConstant(Addend, dl, MVT::i32),
+ getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
+ Add = CurDAG->getMachineNode(ARM::tADDi3, dl, MVT::i32, Ops);
+ }
+ if (Add) {
+ SDValue Ops2[] = {SDValue(Add, 0), CurDAG->getConstant(0, dl, MVT::i32)};
+ CurDAG->MorphNodeTo(N, ARMISD::CMPZ, CurDAG->getVTList(MVT::Glue), Ops2);
+ }
+ }
+ // Other cases are autogenerated.
+ break;
+ }
+
+ case ARMISD::CMOV: {
+ SDValue InFlag = N->getOperand(4);
+
+ if (InFlag.getOpcode() == ARMISD::CMPZ) {
+ bool SwitchEQNEToPLMI;
+ SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI);
+
+ if (SwitchEQNEToPLMI) {
+ SDValue ARMcc = N->getOperand(2);
+ ARMCC::CondCodes CC =
+ (ARMCC::CondCodes)cast<ConstantSDNode>(ARMcc)->getZExtValue();
+
+ switch (CC) {
+ default: llvm_unreachable("CMPZ must be either NE or EQ!");
+ case ARMCC::NE:
+ CC = ARMCC::MI;
+ break;
+ case ARMCC::EQ:
+ CC = ARMCC::PL;
+ break;
+ }
+ SDValue NewARMcc = CurDAG->getConstant((unsigned)CC, dl, MVT::i32);
+ SDValue Ops[] = {N->getOperand(0), N->getOperand(1), NewARMcc,
+ N->getOperand(3), N->getOperand(4)};
+ CurDAG->MorphNodeTo(N, ARMISD::CMOV, N->getVTList(), Ops);
+ }
+
+ }
+ // Other cases are autogenerated.
+ break;
+ }
+
case ARMISD::VZIP: {
unsigned Opc = 0;
EVT VT = N->getValueType(0);
@@ -3174,6 +3424,15 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
+ case ARMISD::VLD1DUP: {
+ static const uint16_t DOpcodes[] = { ARM::VLD1DUPd8, ARM::VLD1DUPd16,
+ ARM::VLD1DUPd32 };
+ static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8, ARM::VLD1DUPq16,
+ ARM::VLD1DUPq32 };
+ SelectVLDDup(N, false, 1, DOpcodes, QOpcodes);
+ return;
+ }
+
case ARMISD::VLD2DUP: {
static const uint16_t Opcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
ARM::VLD2DUPd32 };
@@ -3197,6 +3456,17 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
+ case ARMISD::VLD1DUP_UPD: {
+ static const uint16_t DOpcodes[] = { ARM::VLD1DUPd8wb_fixed,
+ ARM::VLD1DUPd16wb_fixed,
+ ARM::VLD1DUPd32wb_fixed };
+ static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8wb_fixed,
+ ARM::VLD1DUPq16wb_fixed,
+ ARM::VLD1DUPq32wb_fixed };
+ SelectVLDDup(N, true, 1, DOpcodes, QOpcodes);
+ return;
+ }
+
case ARMISD::VLD2DUP_UPD: {
static const uint16_t Opcodes[] = { ARM::VLD2DUPd8wb_fixed,
ARM::VLD2DUPd16wb_fixed,
@@ -4383,7 +4653,7 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
case InlineAsm::Constraint_i:
// FIXME: It seems strange that 'i' is needed here since it's supposed to
// be an immediate and not a memory constraint.
- // Fallthrough.
+ LLVM_FALLTHROUGH;
case InlineAsm::Constraint_m:
case InlineAsm::Constraint_o:
case InlineAsm::Constraint_Q:
diff --git a/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp b/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 3cfcb1e..0f84a23 100644
--- a/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -37,6 +37,7 @@
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
@@ -59,18 +60,27 @@ using namespace llvm;
STATISTIC(NumTailCalls, "Number of tail calls");
STATISTIC(NumMovwMovt, "Number of GAs materialized with movw + movt");
STATISTIC(NumLoopByVals, "Number of loops generated for byval arguments");
+STATISTIC(NumConstpoolPromoted,
+ "Number of constants with their storage promoted into constant pools");
static cl::opt<bool>
ARMInterworking("arm-interworking", cl::Hidden,
cl::desc("Enable / disable ARM interworking (for debugging only)"),
cl::init(true));
-// Disabled for causing self-hosting failures once returned-attribute inference
-// was enabled.
-static cl::opt<bool>
-EnableThisRetForwarding("arm-this-return-forwarding", cl::Hidden,
- cl::desc("Directly forward this return"),
- cl::init(false));
+static cl::opt<bool> EnableConstpoolPromotion(
+ "arm-promote-constant", cl::Hidden,
+ cl::desc("Enable / disable promotion of unnamed_addr constants into "
+ "constant pools"),
+ cl::init(true));
+static cl::opt<unsigned> ConstpoolPromotionMaxSize(
+ "arm-promote-constant-max-size", cl::Hidden,
+ cl::desc("Maximum size of constant to promote into a constant pool"),
+ cl::init(64));
+static cl::opt<unsigned> ConstpoolPromotionMaxTotal(
+ "arm-promote-constant-max-total", cl::Hidden,
+ cl::desc("Maximum size of ALL constants to promote into a constant pool"),
+ cl::init(128));
namespace {
class ARMCCState : public CCState {
@@ -103,7 +113,7 @@ void ARMTargetLowering::addTypeForNEON(MVT VT, MVT PromotedLdStVT,
}
MVT ElemTy = VT.getVectorElementType();
- if (ElemTy != MVT::i64 && ElemTy != MVT::f64)
+ if (ElemTy != MVT::f64)
setOperationAction(ISD::SETCC, VT, Custom);
setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom);
@@ -174,6 +184,23 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
+ if (!Subtarget->isTargetDarwin() && !Subtarget->isTargetIOS() &&
+ !Subtarget->isTargetWatchOS()) {
+ const auto &E = Subtarget->getTargetTriple().getEnvironment();
+
+ bool IsHFTarget = E == Triple::EABIHF || E == Triple::GNUEABIHF ||
+ E == Triple::MuslEABIHF;
+ // Windows is a special case. Technically, we will replace all of the "GNU"
+ // calls with calls to MSVCRT if appropriate and adjust the calling
+ // convention then.
+ IsHFTarget = IsHFTarget || Subtarget->isTargetWindows();
+
+ for (int LCID = 0; LCID < RTLIB::UNKNOWN_LIBCALL; ++LCID)
+ setLibcallCallingConv(static_cast<RTLIB::Libcall>(LCID),
+ IsHFTarget ? CallingConv::ARM_AAPCS_VFP
+ : CallingConv::ARM_AAPCS);
+ }
+
if (Subtarget->isTargetMachO()) {
// Uses VFP for Thumb libfuncs if available.
if (Subtarget->isThumb() && Subtarget->hasVFP2() &&
@@ -431,15 +458,27 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
// In EABI, these functions have an __aeabi_ prefix, but in GNUEABI they have
// a __gnu_ prefix (which is the default).
if (Subtarget->isTargetAEABI()) {
- setLibcallName(RTLIB::FPROUND_F32_F16, "__aeabi_f2h");
- setLibcallName(RTLIB::FPROUND_F64_F16, "__aeabi_d2h");
- setLibcallName(RTLIB::FPEXT_F16_F32, "__aeabi_h2f");
+ static const struct {
+ const RTLIB::Libcall Op;
+ const char * const Name;
+ const CallingConv::ID CC;
+ } LibraryCalls[] = {
+ { RTLIB::FPROUND_F32_F16, "__aeabi_f2h", CallingConv::ARM_AAPCS },
+ { RTLIB::FPROUND_F64_F16, "__aeabi_d2h", CallingConv::ARM_AAPCS },
+ { RTLIB::FPEXT_F16_F32, "__aeabi_h2f", CallingConv::ARM_AAPCS },
+ };
+
+ for (const auto &LC : LibraryCalls) {
+ setLibcallName(LC.Op, LC.Name);
+ setLibcallCallingConv(LC.Op, LC.CC);
+ }
}
if (Subtarget->isThumb1Only())
addRegisterClass(MVT::i32, &ARM::tGPRRegClass);
else
addRegisterClass(MVT::i32, &ARM::GPRRegClass);
+
if (!Subtarget->useSoftFloat() && Subtarget->hasVFP2() &&
!Subtarget->isThumb1Only()) {
addRegisterClass(MVT::f32, &ARM::SPRRegClass);
@@ -565,8 +604,6 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SDIV, MVT::v8i8, Custom);
setOperationAction(ISD::UDIV, MVT::v4i16, Custom);
setOperationAction(ISD::UDIV, MVT::v8i8, Custom);
- setOperationAction(ISD::SETCC, MVT::v1i64, Expand);
- setOperationAction(ISD::SETCC, MVT::v2i64, Expand);
// Neon does not have single instruction SINT_TO_FP and UINT_TO_FP with
// a destination type that is wider than the source, and nor does
// it have a FP_TO_[SU]INT instruction with a narrower destination than
@@ -801,30 +838,58 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SREM, MVT::i32, Expand);
setOperationAction(ISD::UREM, MVT::i32, Expand);
+
// Register based DivRem for AEABI (RTABI 4.2)
if (Subtarget->isTargetAEABI() || Subtarget->isTargetAndroid() ||
- Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI()) {
+ Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI() ||
+ Subtarget->isTargetWindows()) {
setOperationAction(ISD::SREM, MVT::i64, Custom);
setOperationAction(ISD::UREM, MVT::i64, Custom);
HasStandaloneRem = false;
- setLibcallName(RTLIB::SDIVREM_I8, "__aeabi_idivmod");
- setLibcallName(RTLIB::SDIVREM_I16, "__aeabi_idivmod");
- setLibcallName(RTLIB::SDIVREM_I32, "__aeabi_idivmod");
- setLibcallName(RTLIB::SDIVREM_I64, "__aeabi_ldivmod");
- setLibcallName(RTLIB::UDIVREM_I8, "__aeabi_uidivmod");
- setLibcallName(RTLIB::UDIVREM_I16, "__aeabi_uidivmod");
- setLibcallName(RTLIB::UDIVREM_I32, "__aeabi_uidivmod");
- setLibcallName(RTLIB::UDIVREM_I64, "__aeabi_uldivmod");
-
- setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::SDIVREM_I32, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::SDIVREM_I64, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::UDIVREM_I32, CallingConv::ARM_AAPCS);
- setLibcallCallingConv(RTLIB::UDIVREM_I64, CallingConv::ARM_AAPCS);
+ if (Subtarget->isTargetWindows()) {
+ const struct {
+ const RTLIB::Libcall Op;
+ const char * const Name;
+ const CallingConv::ID CC;
+ } LibraryCalls[] = {
+ { RTLIB::SDIVREM_I8, "__rt_sdiv", CallingConv::ARM_AAPCS },
+ { RTLIB::SDIVREM_I16, "__rt_sdiv", CallingConv::ARM_AAPCS },
+ { RTLIB::SDIVREM_I32, "__rt_sdiv", CallingConv::ARM_AAPCS },
+ { RTLIB::SDIVREM_I64, "__rt_sdiv64", CallingConv::ARM_AAPCS },
+
+ { RTLIB::UDIVREM_I8, "__rt_udiv", CallingConv::ARM_AAPCS },
+ { RTLIB::UDIVREM_I16, "__rt_udiv", CallingConv::ARM_AAPCS },
+ { RTLIB::UDIVREM_I32, "__rt_udiv", CallingConv::ARM_AAPCS },
+ { RTLIB::UDIVREM_I64, "__rt_udiv64", CallingConv::ARM_AAPCS },
+ };
+
+ for (const auto &LC : LibraryCalls) {
+ setLibcallName(LC.Op, LC.Name);
+ setLibcallCallingConv(LC.Op, LC.CC);
+ }
+ } else {
+ const struct {
+ const RTLIB::Libcall Op;
+ const char * const Name;
+ const CallingConv::ID CC;
+ } LibraryCalls[] = {
+ { RTLIB::SDIVREM_I8, "__aeabi_idivmod", CallingConv::ARM_AAPCS },
+ { RTLIB::SDIVREM_I16, "__aeabi_idivmod", CallingConv::ARM_AAPCS },
+ { RTLIB::SDIVREM_I32, "__aeabi_idivmod", CallingConv::ARM_AAPCS },
+ { RTLIB::SDIVREM_I64, "__aeabi_ldivmod", CallingConv::ARM_AAPCS },
+
+ { RTLIB::UDIVREM_I8, "__aeabi_uidivmod", CallingConv::ARM_AAPCS },
+ { RTLIB::UDIVREM_I16, "__aeabi_uidivmod", CallingConv::ARM_AAPCS },
+ { RTLIB::UDIVREM_I32, "__aeabi_uidivmod", CallingConv::ARM_AAPCS },
+ { RTLIB::UDIVREM_I64, "__aeabi_uldivmod", CallingConv::ARM_AAPCS },
+ };
+
+ for (const auto &LC : LibraryCalls) {
+ setLibcallName(LC.Op, LC.Name);
+ setLibcallCallingConv(LC.Op, LC.CC);
+ }
+ }
setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
setOperationAction(ISD::UDIVREM, MVT::i32, Custom);
@@ -835,6 +900,10 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
}
+ if (Subtarget->isTargetWindows() && Subtarget->getTargetTriple().isOSMSVCRT())
+ for (auto &VT : {MVT::f32, MVT::f64})
+ setOperationAction(ISD::FPOWI, VT, Custom);
+
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
@@ -875,6 +944,10 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
} else {
// If there's anything we can use as a barrier, go through custom lowering
// for ATOMIC_FENCE.
+ // If target has DMB in thumb, Fences can be inserted.
+ if (Subtarget->hasDataBarrier())
+ InsertFencesForAtomic = true;
+
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other,
Subtarget->hasAnyDataBarrier() ? Custom : Expand);
@@ -893,8 +966,10 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand);
// Mark ATOMIC_LOAD and ATOMIC_STORE custom so we can handle the
// Unordered/Monotonic case.
- setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom);
- setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom);
+ if (!InsertFencesForAtomic) {
+ setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom);
+ setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom);
+ }
}
setOperationAction(ISD::PREFETCH, MVT::Other, Custom);
@@ -1177,7 +1252,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::PRELOAD: return "ARMISD::PRELOAD";
- case ARMISD::WIN__CHKSTK: return "ARMISD:::WIN__CHKSTK";
+ case ARMISD::WIN__CHKSTK: return "ARMISD::WIN__CHKSTK";
case ARMISD::WIN__DBZCHK: return "ARMISD::WIN__DBZCHK";
case ARMISD::VCEQ: return "ARMISD::VCEQ";
@@ -1236,6 +1311,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::VBICIMM: return "ARMISD::VBICIMM";
case ARMISD::VBSL: return "ARMISD::VBSL";
case ARMISD::MEMCPY: return "ARMISD::MEMCPY";
+ case ARMISD::VLD1DUP: return "ARMISD::VLD1DUP";
case ARMISD::VLD2DUP: return "ARMISD::VLD2DUP";
case ARMISD::VLD3DUP: return "ARMISD::VLD3DUP";
case ARMISD::VLD4DUP: return "ARMISD::VLD4DUP";
@@ -1246,6 +1322,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::VLD2LN_UPD: return "ARMISD::VLD2LN_UPD";
case ARMISD::VLD3LN_UPD: return "ARMISD::VLD3LN_UPD";
case ARMISD::VLD4LN_UPD: return "ARMISD::VLD4LN_UPD";
+ case ARMISD::VLD1DUP_UPD: return "ARMISD::VLD1DUP_UPD";
case ARMISD::VLD2DUP_UPD: return "ARMISD::VLD2DUP_UPD";
case ARMISD::VLD3DUP_UPD: return "ARMISD::VLD3DUP_UPD";
case ARMISD::VLD4DUP_UPD: return "ARMISD::VLD4DUP_UPD";
@@ -1429,6 +1506,16 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,
}
}
+CCAssignFn *ARMTargetLowering::CCAssignFnForCall(CallingConv::ID CC,
+ bool isVarArg) const {
+ return CCAssignFnForNode(CC, false, isVarArg);
+}
+
+CCAssignFn *ARMTargetLowering::CCAssignFnForReturn(CallingConv::ID CC,
+ bool isVarArg) const {
+ return CCAssignFnForNode(CC, true, isVarArg);
+}
+
/// CCAssignFnForNode - Selects the correct CCAssignFn for the given
/// CallingConvention.
CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC,
@@ -1464,9 +1551,7 @@ SDValue ARMTargetLowering::LowerCallResult(
SmallVector<CCValAssign, 16> RVLocs;
ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext(), Call);
- CCInfo.AnalyzeCallResult(Ins,
- CCAssignFnForNode(CallConv, /* Return*/ true,
- isVarArg));
+ CCInfo.AnalyzeCallResult(Ins, CCAssignFnForReturn(CallConv, isVarArg));
// Copy all of the result registers out of their specified physreg.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
@@ -1474,7 +1559,7 @@ SDValue ARMTargetLowering::LowerCallResult(
// Pass 'this' value directly from the argument to return value, to avoid
// reg unit interference
- if (i == 0 && isThisReturn && EnableThisRetForwarding) {
+ if (i == 0 && isThisReturn) {
assert(!VA.needsCustom() && VA.getLocVT() == MVT::i32 &&
"unexpected return calling convention register assignment");
InVals.push_back(ThisVal);
@@ -1627,9 +1712,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVector<CCValAssign, 16> ArgLocs;
ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext(), Call);
- CCInfo.AnalyzeCallOperands(Outs,
- CCAssignFnForNode(CallConv, /* Return*/ false,
- isVarArg));
+ CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CallConv, isVarArg));
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getNextStackOffset();
@@ -1704,7 +1787,8 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
StackPtr, MemOpChains, Flags);
}
} else if (VA.isRegLoc()) {
- if (realArgIdx == 0 && Flags.isReturned() && Outs[0].VT == MVT::i32) {
+ if (realArgIdx == 0 && Flags.isReturned() && !Flags.isSwiftSelf() &&
+ Outs[0].VT == MVT::i32) {
assert(VA.getLocVT() == MVT::i32 &&
"unexpected calling convention register assignment");
assert(!Ins.empty() && Ins[0].VT == MVT::i32 &&
@@ -1864,7 +1948,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
auto *BB = CLI.CS->getParent();
bool PreferIndirect =
Subtarget->isThumb() && MF.getFunction()->optForMinSize() &&
- std::count_if(GV->user_begin(), GV->user_end(), [&BB](const User *U) {
+ count_if(GV->users(), [&BB](const User *U) {
return isa<Instruction>(U) && cast<Instruction>(U)->getParent() == BB;
}) > 2;
@@ -1880,10 +1964,11 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
Callee = DAG.getNode(
ARMISD::WrapperPIC, dl, PtrVt,
DAG.getTargetGlobalAddress(GV, dl, PtrVt, 0, ARMII::MO_NONLAZY));
- Callee =
- DAG.getLoad(PtrVt, dl, DAG.getEntryNode(), Callee,
- MachinePointerInfo::getGOT(DAG.getMachineFunction()),
- /* Alignment = */ 0, MachineMemOperand::MOInvariant);
+ Callee = DAG.getLoad(
+ PtrVt, dl, DAG.getEntryNode(), Callee,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()),
+ /* Alignment = */ 0, MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
} else if (Subtarget->isTargetCOFF()) {
assert(Subtarget->isTargetWindows() &&
"Windows is the only supported COFF target");
@@ -1977,7 +2062,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
if (isTailCall) {
- MF.getFrameInfo()->setHasTailCall();
+ MF.getFrameInfo().setHasTailCall();
return DAG.getNode(ARMISD::TC_RETURN, dl, NodeTys, Ops);
}
@@ -2060,9 +2145,9 @@ void ARMTargetLowering::HandleByVal(CCState *State, unsigned &Size,
/// incoming argument stack.
static
bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
- MachineFrameInfo *MFI, const MachineRegisterInfo *MRI,
+ MachineFrameInfo &MFI, const MachineRegisterInfo *MRI,
const TargetInstrInfo *TII) {
- unsigned Bytes = Arg.getValueType().getSizeInBits() / 8;
+ unsigned Bytes = Arg.getValueSizeInBits() / 8;
int FI = INT_MAX;
if (Arg.getOpcode() == ISD::CopyFromReg) {
unsigned VR = cast<RegisterSDNode>(Arg.getOperand(1))->getReg();
@@ -2094,9 +2179,9 @@ bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
return false;
assert(FI != INT_MAX);
- if (!MFI->isFixedObjectIndex(FI))
+ if (!MFI.isFixedObjectIndex(FI))
return false;
- return Offset == MFI->getObjectOffset(FI) && Bytes == MFI->getObjectSize(FI);
+ return Offset == MFI.getObjectOffset(FI) && Bytes == MFI.getObjectSize(FI);
}
/// IsEligibleForTailCallOptimization - Check whether the call is eligible
@@ -2121,11 +2206,6 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
// Look for obvious safe cases to perform tail call optimization that do not
// require ABI changes. This is what gcc calls sibcall.
- // Do not sibcall optimize vararg calls unless the call site is not passing
- // any arguments.
- if (isVarArg && !Outs.empty())
- return false;
-
// Exception-handling functions need a special set of instructions to indicate
// a return to the hardware. Tail-calling another function would probably
// break this.
@@ -2155,8 +2235,8 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
// Check that the call results are passed in the same way.
LLVMContext &C = *DAG.getContext();
if (!CCState::resultsCompatible(CalleeCC, CallerCC, MF, C, Ins,
- CCAssignFnForNode(CalleeCC, true, isVarArg),
- CCAssignFnForNode(CallerCC, true, isVarArg)))
+ CCAssignFnForReturn(CalleeCC, isVarArg),
+ CCAssignFnForReturn(CallerCC, isVarArg)))
return false;
// The callee has to preserve all registers the caller needs to preserve.
const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo();
@@ -2181,12 +2261,11 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
// argument is passed on the stack.
SmallVector<CCValAssign, 16> ArgLocs;
ARMCCState CCInfo(CalleeCC, isVarArg, MF, ArgLocs, C, Call);
- CCInfo.AnalyzeCallOperands(Outs,
- CCAssignFnForNode(CalleeCC, false, isVarArg));
+ CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CalleeCC, isVarArg));
if (CCInfo.getNextStackOffset()) {
// Check if the arguments are already laid out in the right way as
// the caller's fixed stack objects.
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const MachineRegisterInfo *MRI = &MF.getRegInfo();
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
for (unsigned i = 0, realArgIdx = 0, e = ArgLocs.size();
@@ -2236,8 +2315,7 @@ ARMTargetLowering::CanLowerReturn(CallingConv::ID CallConv,
LLVMContext &Context) const {
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
- return CCInfo.CheckReturn(Outs, CCAssignFnForNode(CallConv, /*Return=*/true,
- isVarArg));
+ return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, isVarArg));
}
static SDValue LowerInterruptReturn(SmallVectorImpl<SDValue> &RetOps,
@@ -2288,8 +2366,7 @@ ARMTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
*DAG.getContext(), Call);
// Analyze outgoing return values.
- CCInfo.AnalyzeReturn(Outs, CCAssignFnForNode(CallConv, /* Return */ true,
- isVarArg));
+ CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, isVarArg));
SDValue Flag;
SmallVector<SDValue, 4> RetOps;
@@ -2537,7 +2614,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op,
EVT PtrVT = getPointerTy(DAG.getDataLayout());
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
SDValue CPAddr;
- bool IsPositionIndependent = isPositionIndependent();
+ bool IsPositionIndependent = isPositionIndependent() || Subtarget->isROPI();
if (!IsPositionIndependent) {
CPAddr = DAG.getTargetConstantPool(BA, PtrVT, 4);
} else {
@@ -2595,16 +2672,17 @@ ARMTargetLowering::LowerGlobalTLSAddressDarwin(SDValue Op,
// The first entry in the descriptor is a function pointer that we must call
// to obtain the address of the variable.
SDValue Chain = DAG.getEntryNode();
- SDValue FuncTLVGet =
- DAG.getLoad(MVT::i32, DL, Chain, DescAddr,
- MachinePointerInfo::getGOT(DAG.getMachineFunction()),
- /* Alignment = */ 4, MachineMemOperand::MONonTemporal |
- MachineMemOperand::MOInvariant);
+ SDValue FuncTLVGet = DAG.getLoad(
+ MVT::i32, DL, Chain, DescAddr,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()),
+ /* Alignment = */ 4,
+ MachineMemOperand::MONonTemporal | MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
Chain = FuncTLVGet.getValue(1);
MachineFunction &F = DAG.getMachineFunction();
- MachineFrameInfo *MFI = F.getFrameInfo();
- MFI->setAdjustsStack(true);
+ MachineFrameInfo &MFI = F.getFrameInfo();
+ MFI.setAdjustsStack(true);
// TLS calls preserve all registers except those that absolutely must be
// trashed: R0 (it takes an argument), LR (it's a call) and CPSR (let's not be
@@ -2801,12 +2879,174 @@ ARMTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const {
llvm_unreachable("bogus TLS model");
}
+/// Return true if all users of V are within function F, looking through
+/// ConstantExprs.
+static bool allUsersAreInFunction(const Value *V, const Function *F) {
+ SmallVector<const User*,4> Worklist;
+ for (auto *U : V->users())
+ Worklist.push_back(U);
+ while (!Worklist.empty()) {
+ auto *U = Worklist.pop_back_val();
+ if (isa<ConstantExpr>(U)) {
+ for (auto *UU : U->users())
+ Worklist.push_back(UU);
+ continue;
+ }
+
+ auto *I = dyn_cast<Instruction>(U);
+ if (!I || I->getParent()->getParent() != F)
+ return false;
+ }
+ return true;
+}
+
+/// Return true if all users of V are within some (any) function, looking through
+/// ConstantExprs. In other words, are there any global constant users?
+static bool allUsersAreInFunctions(const Value *V) {
+ SmallVector<const User*,4> Worklist;
+ for (auto *U : V->users())
+ Worklist.push_back(U);
+ while (!Worklist.empty()) {
+ auto *U = Worklist.pop_back_val();
+ if (isa<ConstantExpr>(U)) {
+ for (auto *UU : U->users())
+ Worklist.push_back(UU);
+ continue;
+ }
+
+ if (!isa<Instruction>(U))
+ return false;
+ }
+ return true;
+}
+
+// Return true if T is an integer, float or an array/vector of either.
+static bool isSimpleType(Type *T) {
+ if (T->isIntegerTy() || T->isFloatingPointTy())
+ return true;
+ Type *SubT = nullptr;
+ if (T->isArrayTy())
+ SubT = T->getArrayElementType();
+ else if (T->isVectorTy())
+ SubT = T->getVectorElementType();
+ else
+ return false;
+ return SubT->isIntegerTy() || SubT->isFloatingPointTy();
+}
+
+static SDValue promoteToConstantPool(const GlobalValue *GV, SelectionDAG &DAG,
+ EVT PtrVT, SDLoc dl) {
+ // If we're creating a pool entry for a constant global with unnamed address,
+ // and the global is small enough, we can emit it inline into the constant pool
+ // to save ourselves an indirection.
+ //
+ // This is a win if the constant is only used in one function (so it doesn't
+ // need to be duplicated) or duplicating the constant wouldn't increase code
+ // size (implying the constant is no larger than 4 bytes).
+ const Function *F = DAG.getMachineFunction().getFunction();
+
+ // We rely on this decision to inline being idemopotent and unrelated to the
+ // use-site. We know that if we inline a variable at one use site, we'll
+ // inline it elsewhere too (and reuse the constant pool entry). Fast-isel
+ // doesn't know about this optimization, so bail out if it's enabled else
+ // we could decide to inline here (and thus never emit the GV) but require
+ // the GV from fast-isel generated code.
+ if (!EnableConstpoolPromotion ||
+ DAG.getMachineFunction().getTarget().Options.EnableFastISel)
+ return SDValue();
+
+ auto *GVar = dyn_cast<GlobalVariable>(GV);
+ if (!GVar || !GVar->hasInitializer() ||
+ !GVar->isConstant() || !GVar->hasGlobalUnnamedAddr() ||
+ !GVar->hasLocalLinkage())
+ return SDValue();
+
+ // Ensure that we don't try and inline any type that contains pointers. If
+ // we inline a value that contains relocations, we move the relocations from
+ // .data to .text which is not ideal.
+ auto *Init = GVar->getInitializer();
+ if (!isSimpleType(Init->getType()))
+ return SDValue();
+
+ // The constant islands pass can only really deal with alignment requests
+ // <= 4 bytes and cannot pad constants itself. Therefore we cannot promote
+ // any type wanting greater alignment requirements than 4 bytes. We also
+ // can only promote constants that are multiples of 4 bytes in size or
+ // are paddable to a multiple of 4. Currently we only try and pad constants
+ // that are strings for simplicity.
+ auto *CDAInit = dyn_cast<ConstantDataArray>(Init);
+ unsigned Size = DAG.getDataLayout().getTypeAllocSize(Init->getType());
+ unsigned Align = GVar->getAlignment();
+ unsigned RequiredPadding = 4 - (Size % 4);
+ bool PaddingPossible =
+ RequiredPadding == 4 || (CDAInit && CDAInit->isString());
+ if (!PaddingPossible || Align > 4 || Size > ConstpoolPromotionMaxSize)
+ return SDValue();
+
+ unsigned PaddedSize = Size + ((RequiredPadding == 4) ? 0 : RequiredPadding);
+ MachineFunction &MF = DAG.getMachineFunction();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+
+ // We can't bloat the constant pool too much, else the ConstantIslands pass
+ // may fail to converge. If we haven't promoted this global yet (it may have
+ // multiple uses), and promoting it would increase the constant pool size (Sz
+ // > 4), ensure we have space to do so up to MaxTotal.
+ if (!AFI->getGlobalsPromotedToConstantPool().count(GVar) && Size > 4)
+ if (AFI->getPromotedConstpoolIncrease() + PaddedSize - 4 >=
+ ConstpoolPromotionMaxTotal)
+ return SDValue();
+
+ // This is only valid if all users are in a single function OR it has users
+ // in multiple functions but it no larger than a pointer. We also check if
+ // GVar has constant (non-ConstantExpr) users. If so, it essentially has its
+ // address taken.
+ if (!allUsersAreInFunction(GVar, F) &&
+ !(Size <= 4 && allUsersAreInFunctions(GVar)))
+ return SDValue();
+
+ // We're going to inline this global. Pad it out if needed.
+ if (RequiredPadding != 4) {
+ StringRef S = CDAInit->getAsString();
+
+ SmallVector<uint8_t,16> V(S.size());
+ std::copy(S.bytes_begin(), S.bytes_end(), V.begin());
+ while (RequiredPadding--)
+ V.push_back(0);
+ Init = ConstantDataArray::get(*DAG.getContext(), V);
+ }
+
+ auto CPVal = ARMConstantPoolConstant::Create(GVar, Init);
+ SDValue CPAddr =
+ DAG.getTargetConstantPool(CPVal, PtrVT, /*Align=*/4);
+ if (!AFI->getGlobalsPromotedToConstantPool().count(GVar)) {
+ AFI->markGlobalAsPromotedToConstantPool(GVar);
+ AFI->setPromotedConstpoolIncrease(AFI->getPromotedConstpoolIncrease() +
+ PaddedSize - 4);
+ }
+ ++NumConstpoolPromoted;
+ return DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr);
+}
+
+static bool isReadOnly(const GlobalValue *GV) {
+ if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
+ GV = GA->getBaseObject();
+ return (isa<GlobalVariable>(GV) && cast<GlobalVariable>(GV)->isConstant()) ||
+ isa<Function>(GV);
+}
+
SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
SelectionDAG &DAG) const {
EVT PtrVT = getPointerTy(DAG.getDataLayout());
SDLoc dl(Op);
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
const TargetMachine &TM = getTargetMachine();
+ bool IsRO = isReadOnly(GV);
+
+ // promoteToConstantPool only if not generating XO text section
+ if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV) && !Subtarget->genExecuteOnly())
+ if (SDValue V = promoteToConstantPool(GV, DAG, PtrVT, dl))
+ return V;
+
if (isPositionIndependent()) {
bool UseGOT_PREL = !TM.shouldAssumeDSOLocal(*GV->getParent(), GV);
@@ -2833,6 +3073,23 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
DAG.getLoad(PtrVT, dl, Chain, Result,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
return Result;
+ } else if (Subtarget->isROPI() && IsRO) {
+ // PC-relative.
+ SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT);
+ SDValue Result = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVT, G);
+ return Result;
+ } else if (Subtarget->isRWPI() && !IsRO) {
+ // SB-relative.
+ ARMConstantPoolValue *CPV =
+ ARMConstantPoolConstant::Create(GV, ARMCP::SBREL);
+ SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4);
+ CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr);
+ SDValue G = DAG.getLoad(
+ PtrVT, dl, DAG.getEntryNode(), CPAddr,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ SDValue SB = DAG.getCopyFromReg(DAG.getEntryNode(), dl, ARM::R9, PtrVT);
+ SDValue Result = DAG.getNode(ISD::ADD, dl, PtrVT, SB, G);
+ return Result;
}
// If we have T2 ops, we can materialize the address directly via movt/movw
@@ -2854,6 +3111,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op,
SelectionDAG &DAG) const {
+ assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
+ "ROPI/RWPI not currently supported for Darwin");
EVT PtrVT = getPointerTy(DAG.getDataLayout());
SDLoc dl(Op);
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
@@ -2880,6 +3139,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressWindows(SDValue Op,
assert(Subtarget->isTargetWindows() && "non-Windows COFF is not supported");
assert(Subtarget->useMovt(DAG.getMachineFunction()) &&
"Windows on ARM expects to use movw/movt");
+ assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
+ "ROPI/RWPI not currently supported for Windows");
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
const ARMII::TOF TargetFlags =
@@ -2931,11 +3192,6 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG,
SDLoc dl(Op);
switch (IntNo) {
default: return SDValue(); // Don't custom lower most intrinsics.
- case Intrinsic::arm_rbit: {
- assert(Op.getOperand(1).getValueType() == MVT::i32 &&
- "RBIT intrinsic must have i32 type!");
- return DAG.getNode(ISD::BITREVERSE, dl, MVT::i32, Op.getOperand(1));
- }
case Intrinsic::thread_pointer: {
EVT PtrVT = getPointerTy(DAG.getDataLayout());
return DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT);
@@ -3097,8 +3353,8 @@ SDValue ARMTargetLowering::GetF64FormalArgument(CCValAssign &VA,
SDValue ArgValue2;
if (NextVA.isMemLoc()) {
- MachineFrameInfo *MFI = MF.getFrameInfo();
- int FI = MFI->CreateFixedObject(4, NextVA.getLocMemOffset(), true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ int FI = MFI.CreateFixedObject(4, NextVA.getLocMemOffset(), true);
// Create load node to retrieve arguments from the stack.
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
@@ -3139,7 +3395,7 @@ int ARMTargetLowering::StoreByValRegs(CCState &CCInfo, SelectionDAG &DAG,
// initialize stack frame.
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
unsigned RBegin, REnd;
if (InRegsParamRecordIdx < CCInfo.getInRegsParamsCount()) {
@@ -3154,7 +3410,7 @@ int ARMTargetLowering::StoreByValRegs(CCState &CCInfo, SelectionDAG &DAG,
ArgOffset = -4 * (ARM::R4 - RBegin);
auto PtrVT = getPointerTy(DAG.getDataLayout());
- int FrameIndex = MFI->CreateFixedObject(ArgSize, ArgOffset, false);
+ int FrameIndex = MFI.CreateFixedObject(ArgSize, ArgOffset, false);
SDValue FIN = DAG.getFrameIndex(FrameIndex, PtrVT);
SmallVector<SDValue, 4> MemOps;
@@ -3200,7 +3456,7 @@ SDValue ARMTargetLowering::LowerFormalArguments(
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
@@ -3208,9 +3464,7 @@ SDValue ARMTargetLowering::LowerFormalArguments(
SmallVector<CCValAssign, 16> ArgLocs;
ARMCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext(), Prologue);
- CCInfo.AnalyzeFormalArguments(Ins,
- CCAssignFnForNode(CallConv, /* Return*/ false,
- isVarArg));
+ CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, isVarArg));
SmallVector<SDValue, 16> ArgValues;
SDValue ArgValue;
@@ -3248,7 +3502,7 @@ SDValue ARMTargetLowering::LowerFormalArguments(
CCInfo.rewindByValRegsInfo();
int lastInsIndex = -1;
- if (isVarArg && MFI->hasVAStart()) {
+ if (isVarArg && MFI.hasVAStart()) {
unsigned RegIdx = CCInfo.getFirstUnallocated(GPRArgRegs);
if (RegIdx != array_lengthof(GPRArgRegs))
ArgRegBegin = std::min(ArgRegBegin, (unsigned)GPRArgRegs[RegIdx]);
@@ -3278,7 +3532,7 @@ SDValue ARMTargetLowering::LowerFormalArguments(
VA = ArgLocs[++i]; // skip ahead to next loc
SDValue ArgValue2;
if (VA.isMemLoc()) {
- int FI = MFI->CreateFixedObject(8, VA.getLocMemOffset(), true);
+ int FI = MFI.CreateFixedObject(8, VA.getLocMemOffset(), true);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
ArgValue2 = DAG.getLoad(MVT::f64, dl, Chain, FIN,
MachinePointerInfo::getFixedStack(
@@ -3370,8 +3624,8 @@ SDValue ARMTargetLowering::LowerFormalArguments(
CCInfo.nextInRegsParam();
} else {
unsigned FIOffset = VA.getLocMemOffset();
- int FI = MFI->CreateFixedObject(VA.getLocVT().getSizeInBits()/8,
- FIOffset, true);
+ int FI = MFI.CreateFixedObject(VA.getLocVT().getSizeInBits()/8,
+ FIOffset, true);
// Create load nodes to retrieve arguments from the stack.
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
@@ -3385,7 +3639,7 @@ SDValue ARMTargetLowering::LowerFormalArguments(
}
// varargs
- if (isVarArg && MFI->hasVAStart())
+ if (isVarArg && MFI.hasVAStart())
VarArgStyleRegisters(CCInfo, DAG, dl, Chain,
CCInfo.getNextStackOffset(),
TotalArgRegsSaveSize);
@@ -4122,15 +4376,15 @@ SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
Table = DAG.getNode(ARMISD::WrapperJT, dl, MVT::i32, JTI);
Index = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, dl, PTy));
SDValue Addr = DAG.getNode(ISD::ADD, dl, PTy, Index, Table);
- if (Subtarget->isThumb2()) {
- // Thumb2 uses a two-level jump. That is, it jumps into the jump table
+ if (Subtarget->isThumb2() || (Subtarget->hasV8MBaselineOps() && Subtarget->isThumb())) {
+ // Thumb2 and ARMv8-M use a two-level jump. That is, it jumps into the jump table
// which does another jump to the destination. This also makes it easier
- // to translate it to TBB / TBH later.
+ // to translate it to TBB / TBH later (Thumb2 only).
// FIXME: This might not work if the function is extremely large.
return DAG.getNode(ARMISD::BR2_JT, dl, MVT::Other, Chain,
Addr, Op.getOperand(2), JTI);
}
- if (isPositionIndependent()) {
+ if (isPositionIndependent() || Subtarget->isROPI()) {
Addr =
DAG.getLoad((EVT)MVT::i32, dl, Chain, Addr,
MachinePointerInfo::getJumpTable(DAG.getMachineFunction()));
@@ -4320,8 +4574,8 @@ SDValue ARMTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const {
SDValue ARMTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const{
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
@@ -4346,8 +4600,8 @@ SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
const ARMBaseRegisterInfo &ARI =
*static_cast<const ARMBaseRegisterInfo*>(RegInfo);
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc dl(Op); // FIXME probably not meaningful
@@ -4520,6 +4774,7 @@ SDValue ARMTargetLowering::LowerShiftRightParts(SDValue Op,
SDValue ShOpHi = Op.getOperand(1);
SDValue ShAmt = Op.getOperand(2);
SDValue ARMcc;
+ SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32);
unsigned Opc = (Op.getOpcode() == ISD::SRA_PARTS) ? ISD::SRA : ISD::SRL;
assert(Op.getOpcode() == ISD::SRA_PARTS || Op.getOpcode() == ISD::SRL_PARTS);
@@ -4530,15 +4785,23 @@ SDValue ARMTargetLowering::LowerShiftRightParts(SDValue Op,
SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt,
DAG.getConstant(VTBits, dl, MVT::i32));
SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, RevShAmt);
- SDValue FalseVal = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2);
- SDValue TrueVal = DAG.getNode(Opc, dl, VT, ShOpHi, ExtraShAmt);
-
- SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32);
- SDValue Cmp = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32),
- ISD::SETGE, ARMcc, DAG, dl);
- SDValue Hi = DAG.getNode(Opc, dl, VT, ShOpHi, ShAmt);
- SDValue Lo = DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, TrueVal, ARMcc,
- CCR, Cmp);
+ SDValue LoSmallShift = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2);
+ SDValue LoBigShift = DAG.getNode(Opc, dl, VT, ShOpHi, ExtraShAmt);
+ SDValue CmpLo = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32),
+ ISD::SETGE, ARMcc, DAG, dl);
+ SDValue Lo = DAG.getNode(ARMISD::CMOV, dl, VT, LoSmallShift, LoBigShift,
+ ARMcc, CCR, CmpLo);
+
+
+ SDValue HiSmallShift = DAG.getNode(Opc, dl, VT, ShOpHi, ShAmt);
+ SDValue HiBigShift = Opc == ISD::SRA
+ ? DAG.getNode(Opc, dl, VT, ShOpHi,
+ DAG.getConstant(VTBits - 1, dl, VT))
+ : DAG.getConstant(0, dl, VT);
+ SDValue CmpHi = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32),
+ ISD::SETGE, ARMcc, DAG, dl);
+ SDValue Hi = DAG.getNode(ARMISD::CMOV, dl, VT, HiSmallShift, HiBigShift,
+ ARMcc, CCR, CmpHi);
SDValue Ops[2] = { Lo, Hi };
return DAG.getMergeValues(Ops, dl);
@@ -4556,23 +4819,28 @@ SDValue ARMTargetLowering::LowerShiftLeftParts(SDValue Op,
SDValue ShOpHi = Op.getOperand(1);
SDValue ShAmt = Op.getOperand(2);
SDValue ARMcc;
+ SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32);
assert(Op.getOpcode() == ISD::SHL_PARTS);
SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32,
DAG.getConstant(VTBits, dl, MVT::i32), ShAmt);
SDValue Tmp1 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, RevShAmt);
+ SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt);
+ SDValue HiSmallShift = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2);
+
SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt,
DAG.getConstant(VTBits, dl, MVT::i32));
- SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt);
- SDValue Tmp3 = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt);
+ SDValue HiBigShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt);
+ SDValue CmpHi = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32),
+ ISD::SETGE, ARMcc, DAG, dl);
+ SDValue Hi = DAG.getNode(ARMISD::CMOV, dl, VT, HiSmallShift, HiBigShift,
+ ARMcc, CCR, CmpHi);
- SDValue FalseVal = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2);
- SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32);
- SDValue Cmp = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32),
+ SDValue CmpLo = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32),
ISD::SETGE, ARMcc, DAG, dl);
- SDValue Lo = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt);
- SDValue Hi = DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, Tmp3, ARMcc,
- CCR, Cmp);
+ SDValue LoSmallShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt);
+ SDValue Lo = DAG.getNode(ARMISD::CMOV, dl, VT, LoSmallShift,
+ DAG.getConstant(0, dl, VT), ARMcc, CCR, CmpLo);
SDValue Ops[2] = { Lo, Hi };
return DAG.getMergeValues(Ops, dl);
@@ -4877,32 +5145,49 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) {
ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(CC)->get();
SDLoc dl(Op);
+ if (Op0.getValueType().getVectorElementType() == MVT::i64 &&
+ (SetCCOpcode == ISD::SETEQ || SetCCOpcode == ISD::SETNE)) {
+ // Special-case integer 64-bit equality comparisons. They aren't legal,
+ // but they can be lowered with a few vector instructions.
+ unsigned CmpElements = CmpVT.getVectorNumElements() * 2;
+ EVT SplitVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32, CmpElements);
+ SDValue CastOp0 = DAG.getNode(ISD::BITCAST, dl, SplitVT, Op0);
+ SDValue CastOp1 = DAG.getNode(ISD::BITCAST, dl, SplitVT, Op1);
+ SDValue Cmp = DAG.getNode(ISD::SETCC, dl, SplitVT, CastOp0, CastOp1,
+ DAG.getCondCode(ISD::SETEQ));
+ SDValue Reversed = DAG.getNode(ARMISD::VREV64, dl, SplitVT, Cmp);
+ SDValue Merged = DAG.getNode(ISD::AND, dl, SplitVT, Cmp, Reversed);
+ Merged = DAG.getNode(ISD::BITCAST, dl, CmpVT, Merged);
+ if (SetCCOpcode == ISD::SETNE)
+ Merged = DAG.getNOT(dl, Merged, CmpVT);
+ Merged = DAG.getSExtOrTrunc(Merged, dl, VT);
+ return Merged;
+ }
+
if (CmpVT.getVectorElementType() == MVT::i64)
- // 64-bit comparisons are not legal. We've marked SETCC as non-Custom,
- // but it's possible that our operands are 64-bit but our result is 32-bit.
- // Bail in this case.
+ // 64-bit comparisons are not legal in general.
return SDValue();
if (Op1.getValueType().isFloatingPoint()) {
switch (SetCCOpcode) {
default: llvm_unreachable("Illegal FP comparison");
case ISD::SETUNE:
- case ISD::SETNE: Invert = true; // Fallthrough
+ case ISD::SETNE: Invert = true; LLVM_FALLTHROUGH;
case ISD::SETOEQ:
case ISD::SETEQ: Opc = ARMISD::VCEQ; break;
case ISD::SETOLT:
- case ISD::SETLT: Swap = true; // Fallthrough
+ case ISD::SETLT: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETOGT:
case ISD::SETGT: Opc = ARMISD::VCGT; break;
case ISD::SETOLE:
- case ISD::SETLE: Swap = true; // Fallthrough
+ case ISD::SETLE: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETOGE:
case ISD::SETGE: Opc = ARMISD::VCGE; break;
- case ISD::SETUGE: Swap = true; // Fallthrough
+ case ISD::SETUGE: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETULE: Invert = true; Opc = ARMISD::VCGT; break;
- case ISD::SETUGT: Swap = true; // Fallthrough
+ case ISD::SETUGT: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETULT: Invert = true; Opc = ARMISD::VCGE; break;
- case ISD::SETUEQ: Invert = true; // Fallthrough
+ case ISD::SETUEQ: Invert = true; LLVM_FALLTHROUGH;
case ISD::SETONE:
// Expand this to (OLT | OGT).
TmpOp0 = Op0;
@@ -4911,7 +5196,9 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) {
Op0 = DAG.getNode(ARMISD::VCGT, dl, CmpVT, TmpOp1, TmpOp0);
Op1 = DAG.getNode(ARMISD::VCGT, dl, CmpVT, TmpOp0, TmpOp1);
break;
- case ISD::SETUO: Invert = true; // Fallthrough
+ case ISD::SETUO:
+ Invert = true;
+ LLVM_FALLTHROUGH;
case ISD::SETO:
// Expand this to (OLT | OGE).
TmpOp0 = Op0;
@@ -5168,11 +5455,28 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef,
SDValue ARMTargetLowering::LowerConstantFP(SDValue Op, SelectionDAG &DAG,
const ARMSubtarget *ST) const {
- if (!ST->hasVFP3())
- return SDValue();
-
bool IsDouble = Op.getValueType() == 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()) {
+ 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);
+ }
+ }
+
+ if (!ST->hasVFP3())
+ return SDValue();
// Use the default (constant pool) lowering for double constants when we have
// an SP-only FPU
@@ -5180,7 +5484,6 @@ SDValue ARMTargetLowering::LowerConstantFP(SDValue Op, SelectionDAG &DAG,
return SDValue();
// Try splatting with a VMOV.f32...
- const APFloat &FPVal = CFP->getValueAPF();
int ImmVal = IsDouble ? ARM_AM::getFP64Imm(FPVal) : ARM_AM::getFP32Imm(FPVal);
if (ImmVal != -1) {
@@ -5325,7 +5628,7 @@ static bool isVREVMask(ArrayRef<int> M, EVT VT, unsigned BlockSize) {
assert((BlockSize==16 || BlockSize==32 || BlockSize==64) &&
"Only possible block sizes for VREV are: 16, 32, 64");
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5376,7 +5679,7 @@ static bool isVTBLMask(ArrayRef<int> M, EVT VT) {
// want to check the low half and high half of the shuffle mask as if it were
// the other case
static bool isVTRNMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) {
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5411,7 +5714,7 @@ static bool isVTRNMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) {
/// "vector_shuffle v, v", i.e., "vector_shuffle v, undef".
/// Mask is e.g., <0, 0, 2, 2> instead of <0, 4, 2, 6>.
static bool isVTRN_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5446,7 +5749,7 @@ static bool isVTRN_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){
// Requires similar checks to that of isVTRNMask with
// respect the how results are returned.
static bool isVUZPMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) {
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5476,7 +5779,7 @@ static bool isVUZPMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) {
/// "vector_shuffle v, v", i.e., "vector_shuffle v, undef".
/// Mask is e.g., <0, 2, 0, 2> instead of <0, 2, 4, 6>,
static bool isVUZP_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5517,7 +5820,7 @@ static bool isVUZP_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){
// Requires similar checks to that of isVTRNMask with respect the how results
// are returned.
static bool isVZIPMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) {
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5550,7 +5853,7 @@ static bool isVZIPMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) {
/// "vector_shuffle v, v", i.e., "vector_shuffle v, undef".
/// Mask is e.g., <0, 0, 1, 1> instead of <0, 4, 1, 5>.
static bool isVZIP_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){
- unsigned EltSz = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSz = VT.getScalarSizeInBits();
if (EltSz == 64)
return false;
@@ -5650,6 +5953,9 @@ SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG,
unsigned SplatBitSize;
bool HasAnyUndefs;
if (BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) {
+ if (SplatUndef.isAllOnesValue())
+ return DAG.getUNDEF(VT);
+
if (SplatBitSize <= 64) {
// Check if an immediate VMOV works.
EVT VmovVT;
@@ -5732,7 +6038,7 @@ SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG,
if (isOnlyLowElement && !ISD::isNormalLoad(Value.getNode()))
return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value);
- unsigned EltSize = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSize = VT.getScalarSizeInBits();
// Use VDUP for non-constant splats. For f32 constant splats, reduce to
// i32 and try again.
@@ -5811,6 +6117,24 @@ SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG,
return shuffle;
}
+ if (VT.is128BitVector() && VT != MVT::v2f64 && VT != MVT::v4f32) {
+ // If we haven't found an efficient lowering, try splitting a 128-bit vector
+ // into two 64-bit vectors; we might discover a better way to lower it.
+ SmallVector<SDValue, 64> Ops(Op->op_begin(), Op->op_begin() + NumElts);
+ EVT ExtVT = VT.getVectorElementType();
+ EVT HVT = EVT::getVectorVT(*DAG.getContext(), ExtVT, NumElts / 2);
+ SDValue Lower =
+ DAG.getBuildVector(HVT, dl, makeArrayRef(&Ops[0], NumElts / 2));
+ if (Lower.getOpcode() == ISD::BUILD_VECTOR)
+ Lower = LowerBUILD_VECTOR(Lower, DAG, ST);
+ SDValue Upper = DAG.getBuildVector(
+ HVT, dl, makeArrayRef(&Ops[NumElts / 2], NumElts / 2));
+ if (Upper.getOpcode() == ISD::BUILD_VECTOR)
+ Upper = LowerBUILD_VECTOR(Upper, DAG, ST);
+ if (Lower && Upper)
+ return DAG.getNode(ISD::CONCAT_VECTORS, dl, VT, Lower, Upper);
+ }
+
// Vectors with 32- or 64-bit elements can be built by directly assigning
// the subregisters. Lower it to an ARMISD::BUILD_VECTOR so the operands
// will be legalized.
@@ -5896,7 +6220,7 @@ SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op,
// Add this element source to the list if it's not already there.
SDValue SourceVec = V.getOperand(0);
- auto Source = std::find(Sources.begin(), Sources.end(), SourceVec);
+ auto Source = find(Sources, SourceVec);
if (Source == Sources.end())
Source = Sources.insert(Sources.end(), ShuffleSourceInfo(SourceVec));
@@ -5920,7 +6244,7 @@ SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op,
SmallestEltTy = SrcEltTy;
}
unsigned ResMultiplier =
- VT.getVectorElementType().getSizeInBits() / SmallestEltTy.getSizeInBits();
+ VT.getScalarSizeInBits() / SmallestEltTy.getSizeInBits();
NumElts = VT.getSizeInBits() / SmallestEltTy.getSizeInBits();
EVT ShuffleVT = EVT::getVectorVT(*DAG.getContext(), SmallestEltTy, NumElts);
@@ -6006,13 +6330,13 @@ SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op,
// The stars all align, our next step is to produce the mask for the shuffle.
SmallVector<int, 8> Mask(ShuffleVT.getVectorNumElements(), -1);
- int BitsPerShuffleLane = ShuffleVT.getVectorElementType().getSizeInBits();
+ int BitsPerShuffleLane = ShuffleVT.getScalarSizeInBits();
for (unsigned i = 0; i < VT.getVectorNumElements(); ++i) {
SDValue Entry = Op.getOperand(i);
if (Entry.isUndef())
continue;
- auto Src = std::find(Sources.begin(), Sources.end(), Entry.getOperand(0));
+ auto Src = find(Sources, Entry.getOperand(0));
int EltNo = cast<ConstantSDNode>(Entry.getOperand(1))->getSExtValue();
// EXTRACT_VECTOR_ELT performs an implicit any_ext; BUILD_VECTOR an implicit
@@ -6020,7 +6344,7 @@ SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op,
// segment.
EVT OrigEltTy = Entry.getOperand(0).getValueType().getVectorElementType();
int BitsDefined = std::min(OrigEltTy.getSizeInBits(),
- VT.getVectorElementType().getSizeInBits());
+ VT.getScalarSizeInBits());
int LanesDefined = BitsDefined / BitsPerShuffleLane;
// This source is expected to fill ResMultiplier lanes of the final shuffle,
@@ -6080,7 +6404,7 @@ ARMTargetLowering::isShuffleMaskLegal(const SmallVectorImpl<int> &M,
bool ReverseVEXT, isV_UNDEF;
unsigned Imm, WhichResult;
- unsigned EltSize = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSize = VT.getScalarSizeInBits();
return (EltSize >= 32 ||
ShuffleVectorSDNode::isSplatMask(&M[0], VT) ||
isVREVMask(M, VT, 64) ||
@@ -6223,7 +6547,7 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) {
// of the same time so that they get CSEd properly.
ArrayRef<int> ShuffleMask = SVN->getMask();
- unsigned EltSize = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSize = VT.getScalarSizeInBits();
if (EltSize <= 32) {
if (SVN->isSplat()) {
int Lane = SVN->getSplatIndex();
@@ -6309,7 +6633,7 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) {
EVT SubVT = SubV1.getValueType();
// We expect these to have been canonicalized to -1.
- assert(std::all_of(ShuffleMask.begin(), ShuffleMask.end(), [&](int i) {
+ assert(all_of(ShuffleMask, [&](int i) {
return i < (int)VT.getVectorNumElements();
}) && "Unexpected shuffle index into UNDEF operand!");
@@ -6397,8 +6721,7 @@ static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) {
return SDValue();
SDValue Vec = Op.getOperand(0);
- if (Op.getValueType() == MVT::i32 &&
- Vec.getValueType().getVectorElementType().getSizeInBits() < 32) {
+ if (Op.getValueType() == MVT::i32 && Vec.getScalarValueSizeInBits() < 32) {
SDLoc dl(Op);
return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane);
}
@@ -6463,7 +6786,7 @@ static bool isExtendedBUILD_VECTOR(SDNode *N, SelectionDAG &DAG,
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
SDNode *Elt = N->getOperand(i).getNode();
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Elt)) {
- unsigned EltSize = VT.getVectorElementType().getSizeInBits();
+ unsigned EltSize = VT.getScalarSizeInBits();
unsigned HalfSize = EltSize / 2;
if (isSigned) {
if (!isIntN(HalfSize, C->getSExtValue()))
@@ -6590,7 +6913,7 @@ static SDValue SkipExtensionForVMULL(SDNode *N, SelectionDAG &DAG) {
// Construct a new BUILD_VECTOR with elements truncated to half the size.
assert(N->getOpcode() == ISD::BUILD_VECTOR && "expected BUILD_VECTOR");
EVT VT = N->getValueType(0);
- unsigned EltSize = VT.getVectorElementType().getSizeInBits() / 2;
+ unsigned EltSize = VT.getScalarSizeInBits() / 2;
unsigned NumElts = VT.getVectorNumElements();
MVT TruncVT = MVT::getIntegerVT(EltSize);
SmallVector<SDValue, 8> Ops;
@@ -6915,7 +7238,7 @@ SDValue ARMTargetLowering::LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const {
Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());
auto PtrVT = getPointerTy(DAG.getDataLayout());
- MachineFrameInfo *FrameInfo = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
// Pair of floats / doubles used to pass the result.
@@ -6929,7 +7252,7 @@ SDValue ARMTargetLowering::LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const {
// Create stack object for sret.
const uint64_t ByteSize = DL.getTypeAllocSize(RetTy);
const unsigned StackAlign = DL.getPrefTypeAlignment(RetTy);
- int FrameIdx = FrameInfo->CreateStackObject(ByteSize, StackAlign, false);
+ int FrameIdx = MFI.CreateStackObject(ByteSize, StackAlign, false);
SRet = DAG.getFrameIndex(FrameIdx, TLI.getPointerTy(DL));
ArgListEntry Entry;
@@ -7029,6 +7352,19 @@ SDValue ARMTargetLowering::LowerDIV_Windows(SDValue Op, SelectionDAG &DAG,
return LowerWindowsDIVLibCall(Op, DAG, Signed, DBZCHK);
}
+static SDValue WinDBZCheckDenominator(SelectionDAG &DAG, SDNode *N, SDValue InChain) {
+ SDLoc DL(N);
+ SDValue Op = N->getOperand(1);
+ if (N->getValueType(0) == MVT::i32)
+ return DAG.getNode(ARMISD::WIN__DBZCHK, DL, MVT::Other, InChain, Op);
+ SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, Op,
+ DAG.getConstant(0, DL, MVT::i32));
+ SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, Op,
+ DAG.getConstant(1, DL, MVT::i32));
+ return DAG.getNode(ARMISD::WIN__DBZCHK, DL, MVT::Other, InChain,
+ DAG.getNode(ISD::OR, DL, MVT::i32, Lo, Hi));
+}
+
void ARMTargetLowering::ExpandDIV_Windows(
SDValue Op, SelectionDAG &DAG, bool Signed,
SmallVectorImpl<SDValue> &Results) const {
@@ -7039,14 +7375,7 @@ void ARMTargetLowering::ExpandDIV_Windows(
"unexpected type for custom lowering DIV");
SDLoc dl(Op);
- SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op.getOperand(1),
- DAG.getConstant(0, dl, MVT::i32));
- SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op.getOperand(1),
- DAG.getConstant(1, dl, MVT::i32));
- SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i32, Lo, Hi);
-
- SDValue DBZCHK =
- DAG.getNode(ARMISD::WIN__DBZCHK, dl, MVT::Other, DAG.getEntryNode(), Or);
+ SDValue DBZCHK = WinDBZCheckDenominator(DAG, Op.getNode(), DAG.getEntryNode());
SDValue Result = LowerWindowsDIVLibCall(Op, DAG, Signed, DBZCHK);
@@ -7132,11 +7461,66 @@ static void ReplaceCMP_SWAP_64Results(SDNode *N,
Results.push_back(SDValue(CmpSwap, 2));
}
+static SDValue LowerFPOWI(SDValue Op, const ARMSubtarget &Subtarget,
+ SelectionDAG &DAG) {
+ const auto &TLI = DAG.getTargetLoweringInfo();
+
+ assert(Subtarget.getTargetTriple().isOSMSVCRT() &&
+ "Custom lowering is MSVCRT specific!");
+
+ SDLoc dl(Op);
+ SDValue Val = Op.getOperand(0);
+ MVT Ty = Val->getSimpleValueType(0);
+ SDValue Exponent = DAG.getNode(ISD::SINT_TO_FP, dl, Ty, Op.getOperand(1));
+ SDValue Callee = DAG.getExternalSymbol(Ty == MVT::f32 ? "powf" : "pow",
+ TLI.getPointerTy(DAG.getDataLayout()));
+
+ TargetLowering::ArgListTy Args;
+ TargetLowering::ArgListEntry Entry;
+
+ Entry.Node = Val;
+ Entry.Ty = Val.getValueType().getTypeForEVT(*DAG.getContext());
+ Entry.isZExt = true;
+ Args.push_back(Entry);
+
+ Entry.Node = Exponent;
+ Entry.Ty = Exponent.getValueType().getTypeForEVT(*DAG.getContext());
+ Entry.isZExt = true;
+ Args.push_back(Entry);
+
+ Type *LCRTy = Val.getValueType().getTypeForEVT(*DAG.getContext());
+
+ // In the in-chain to the call is the entry node If we are emitting a
+ // tailcall, the chain will be mutated if the node has a non-entry input
+ // chain.
+ SDValue InChain = DAG.getEntryNode();
+ SDValue TCChain = InChain;
+
+ const auto *F = DAG.getMachineFunction().getFunction();
+ bool IsTC = TLI.isInTailCallPosition(DAG, Op.getNode(), TCChain) &&
+ F->getReturnType() == LCRTy;
+ if (IsTC)
+ InChain = TCChain;
+
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(dl)
+ .setChain(InChain)
+ .setCallee(CallingConv::ARM_AAPCS_VFP, LCRTy, Callee, std::move(Args))
+ .setTailCall(IsTC);
+ std::pair<SDValue, SDValue> CI = TLI.LowerCallTo(CLI);
+
+ // Return the chain (the DAG root) if it is a tail call
+ return !CI.second.getNode() ? DAG.getRoot() : CI.first;
+}
+
SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
default: llvm_unreachable("Don't know how to custom lower this!");
case ISD::WRITE_REGISTER: return LowerWRITE_REGISTER(Op, DAG);
- case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
+ case ISD::ConstantPool:
+ if (Subtarget->genExecuteOnly())
+ llvm_unreachable("execute-only should not generate constant pools");
+ return LowerConstantPool(Op, DAG);
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
case ISD::GlobalAddress:
switch (Subtarget->getTargetTriple().getObjectFormat()) {
@@ -7191,11 +7575,11 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::FLT_ROUNDS_: return LowerFLT_ROUNDS_(Op, DAG);
case ISD::MUL: return LowerMUL(Op, DAG);
case ISD::SDIV:
- if (Subtarget->isTargetWindows())
+ if (Subtarget->isTargetWindows() && !Op.getValueType().isVector())
return LowerDIV_Windows(Op, DAG, /* Signed */ true);
return LowerSDIV(Op, DAG);
case ISD::UDIV:
- if (Subtarget->isTargetWindows())
+ if (Subtarget->isTargetWindows() && !Op.getValueType().isVector())
return LowerDIV_Windows(Op, DAG, /* Signed */ false);
return LowerUDIV(Op, DAG);
case ISD::ADDC:
@@ -7218,6 +7602,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
llvm_unreachable("Don't know how to custom lower this!");
case ISD::FP_ROUND: return LowerFP_ROUND(Op, DAG);
case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG);
+ case ISD::FPOWI: return LowerFPOWI(Op, *Subtarget, DAG);
case ARMISD::WIN__DBZCHK: return SDValue();
}
}
@@ -7278,6 +7663,8 @@ void ARMTargetLowering::SetupEntryBlockForSjLj(MachineInstr &MI,
MachineBasicBlock *MBB,
MachineBasicBlock *DispatchBB,
int FI) const {
+ assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
+ "ROPI/RWPI not currently supported with SjLj");
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
DebugLoc dl = MI.getDebugLoc();
MachineFunction *MF = MBB->getParent();
@@ -7396,8 +7783,8 @@ void ARMTargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
DebugLoc dl = MI.getDebugLoc();
MachineFunction *MF = MBB->getParent();
MachineRegisterInfo *MRI = &MF->getRegInfo();
- MachineFrameInfo *MFI = MF->getFrameInfo();
- int FI = MFI->getFunctionContextIndex();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
+ int FI = MFI.getFunctionContextIndex();
const TargetRegisterClass *TRC = Subtarget->isThumb() ? &ARM::tGPRRegClass
: &ARM::GPRnopcRegClass;
@@ -7406,7 +7793,6 @@ void ARMTargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
// associated with.
DenseMap<unsigned, SmallVector<MachineBasicBlock*, 2> > CallSiteNumToLPad;
unsigned MaxCSNum = 0;
- MachineModuleInfo &MMI = MF->getMMI();
for (MachineFunction::iterator BB = MF->begin(), E = MF->end(); BB != E;
++BB) {
if (!BB->isEHPad()) continue;
@@ -7418,9 +7804,9 @@ void ARMTargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
if (!II->isEHLabel()) continue;
MCSymbol *Sym = II->getOperand(0).getMCSymbol();
- if (!MMI.hasCallSiteLandingPad(Sym)) continue;
+ if (!MF->hasCallSiteLandingPad(Sym)) continue;
- SmallVectorImpl<unsigned> &CallSiteIdxs = MMI.getCallSiteLandingPad(Sym);
+ SmallVectorImpl<unsigned> &CallSiteIdxs = MF->getCallSiteLandingPad(Sym);
for (SmallVectorImpl<unsigned>::iterator
CSI = CallSiteIdxs.begin(), CSE = CallSiteIdxs.end();
CSI != CSE; ++CSI) {
@@ -7491,8 +7877,10 @@ void ARMTargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
const ARMBaseRegisterInfo &RI = AII->getRegisterInfo();
// Add a register mask with no preserved registers. This results in all
- // registers being marked as clobbered.
- MIB.addRegMask(RI.getNoPreservedMask());
+ // registers being marked as clobbered. This can't work if the dispatch block
+ // is in a Thumb1 function and is linked with ARM code which uses the FP
+ // registers, as there is no way to preserve the FP registers in Thumb1 mode.
+ MIB.addRegMask(RI.getSjLjDispatchPreservedMask(*MF));
bool IsPositionIndependent = isPositionIndependent();
unsigned NumLPads = LPadList.size();
@@ -7911,6 +8299,7 @@ ARMTargetLowering::EmitStructByval(MachineInstr &MI,
bool IsThumb1 = Subtarget->isThumb1Only();
bool IsThumb2 = Subtarget->isThumb2();
+ bool IsThumb = Subtarget->isThumb();
if (Align & 1) {
UnitSize = 1;
@@ -7932,7 +8321,7 @@ ARMTargetLowering::EmitStructByval(MachineInstr &MI,
// Select the correct opcode and register class for unit size load/store
bool IsNeon = UnitSize >= 8;
- TRC = (IsThumb1 || IsThumb2) ? &ARM::tGPRRegClass : &ARM::GPRRegClass;
+ TRC = IsThumb ? &ARM::tGPRRegClass : &ARM::GPRRegClass;
if (IsNeon)
VecTRC = UnitSize == 16 ? &ARM::DPairRegClass
: UnitSize == 8 ? &ARM::DPRRegClass
@@ -8014,12 +8403,12 @@ ARMTargetLowering::EmitStructByval(MachineInstr &MI,
if ((LoopSize & 0xFFFF0000) != 0)
Vtmp = MRI.createVirtualRegister(TRC);
AddDefaultPred(BuildMI(BB, dl,
- TII->get(IsThumb2 ? ARM::t2MOVi16 : ARM::MOVi16),
+ TII->get(IsThumb ? ARM::t2MOVi16 : ARM::MOVi16),
Vtmp).addImm(LoopSize & 0xFFFF));
if ((LoopSize & 0xFFFF0000) != 0)
AddDefaultPred(BuildMI(BB, dl,
- TII->get(IsThumb2 ? ARM::t2MOVTi16 : ARM::MOVTi16),
+ TII->get(IsThumb ? ARM::t2MOVTi16 : ARM::MOVTi16),
varEnd)
.addReg(Vtmp)
.addImm(LoopSize >> 16));
@@ -8034,7 +8423,7 @@ ARMTargetLowering::EmitStructByval(MachineInstr &MI,
Align = MF->getDataLayout().getTypeAllocSize(C->getType());
unsigned Idx = ConstantPool->getConstantPoolIndex(C, Align);
- if (IsThumb1)
+ if (IsThumb)
AddDefaultPred(BuildMI(*BB, MI, dl, TII->get(ARM::tLDRpci)).addReg(
varEnd, RegState::Define).addConstantPoolIndex(Idx));
else
@@ -8201,17 +8590,20 @@ ARMTargetLowering::EmitLowered__dbzchk(MachineInstr &MI,
ContBB->splice(ContBB->begin(), MBB,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
ContBB->transferSuccessorsAndUpdatePHIs(MBB);
+ MBB->addSuccessor(ContBB);
MachineBasicBlock *TrapBB = MF->CreateMachineBasicBlock();
+ BuildMI(TrapBB, DL, TII->get(ARM::t__brkdiv0));
MF->push_back(TrapBB);
- BuildMI(TrapBB, DL, TII->get(ARM::t2UDF)).addImm(249);
MBB->addSuccessor(TrapBB);
- BuildMI(*MBB, MI, DL, TII->get(ARM::tCBZ))
- .addReg(MI.getOperand(0).getReg())
- .addMBB(TrapBB);
- AddDefaultPred(BuildMI(*MBB, MI, DL, TII->get(ARM::t2B)).addMBB(ContBB));
- MBB->addSuccessor(ContBB);
+ AddDefaultPred(BuildMI(*MBB, MI, DL, TII->get(ARM::tCMPi8))
+ .addReg(MI.getOperand(0).getReg())
+ .addImm(0));
+ BuildMI(*MBB, MI, DL, TII->get(ARM::t2Bcc))
+ .addMBB(TrapBB)
+ .addImm(ARMCC::EQ)
+ .addReg(ARM::CPSR);
MI.eraseFromParent();
return ContBB;
@@ -8635,7 +9027,7 @@ static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes,
// (zext cc) can never be the all ones value.
if (AllOnes)
return false;
- // Fall through.
+ LLVM_FALLTHROUGH;
case ISD::SIGN_EXTEND: {
SDLoc dl(N);
EVT VT = N->getValueType(0);
@@ -8722,12 +9114,102 @@ SDValue combineSelectAndUseCommutative(SDNode *N, bool AllOnes,
return SDValue();
}
-// AddCombineToVPADDL- For pair-wise add on neon, use the vpaddl instruction
-// (only after legalization).
-static SDValue AddCombineToVPADDL(SDNode *N, SDValue N0, SDValue N1,
+static bool IsVUZPShuffleNode(SDNode *N) {
+ // VUZP shuffle node.
+ if (N->getOpcode() == ARMISD::VUZP)
+ return true;
+
+ // "VUZP" on i32 is an alias for VTRN.
+ if (N->getOpcode() == ARMISD::VTRN && N->getValueType(0) == MVT::v2i32)
+ return true;
+
+ return false;
+}
+
+static SDValue AddCombineToVPADD(SDNode *N, SDValue N0, SDValue N1,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
+ // Look for ADD(VUZP.0, VUZP.1).
+ if (!IsVUZPShuffleNode(N0.getNode()) || N0.getNode() != N1.getNode() ||
+ N0 == N1)
+ return SDValue();
+
+ // Make sure the ADD is a 64-bit add; there is no 128-bit VPADD.
+ if (!N->getValueType(0).is64BitVector())
+ return SDValue();
+
+ // Generate vpadd.
+ SelectionDAG &DAG = DCI.DAG;
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ SDLoc dl(N);
+ SDNode *Unzip = N0.getNode();
+ EVT VT = N->getValueType(0);
+
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(DAG.getConstant(Intrinsic::arm_neon_vpadd, dl,
+ TLI.getPointerTy(DAG.getDataLayout())));
+ Ops.push_back(Unzip->getOperand(0));
+ Ops.push_back(Unzip->getOperand(1));
+
+ return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, Ops);
+}
+
+static SDValue AddCombineVUZPToVPADDL(SDNode *N, SDValue N0, SDValue N1,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const ARMSubtarget *Subtarget) {
+ // Check for two extended operands.
+ if (!(N0.getOpcode() == ISD::SIGN_EXTEND &&
+ N1.getOpcode() == ISD::SIGN_EXTEND) &&
+ !(N0.getOpcode() == ISD::ZERO_EXTEND &&
+ N1.getOpcode() == ISD::ZERO_EXTEND))
+ return SDValue();
+
+ SDValue N00 = N0.getOperand(0);
+ SDValue N10 = N1.getOperand(0);
+
+ // Look for ADD(SEXT(VUZP.0), SEXT(VUZP.1))
+ if (!IsVUZPShuffleNode(N00.getNode()) || N00.getNode() != N10.getNode() ||
+ N00 == N10)
+ return SDValue();
+
+ // We only recognize Q register paddl here; this can't be reached until
+ // after type legalization.
+ if (!N00.getValueType().is64BitVector() ||
+ !N0.getValueType().is128BitVector())
+ return SDValue();
+
+ // Generate vpaddl.
+ SelectionDAG &DAG = DCI.DAG;
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ SDLoc dl(N);
+ EVT VT = N->getValueType(0);
+ SmallVector<SDValue, 8> Ops;
+ // Form vpaddl.sN or vpaddl.uN depending on the kind of extension.
+ unsigned Opcode;
+ if (N0.getOpcode() == ISD::SIGN_EXTEND)
+ Opcode = Intrinsic::arm_neon_vpaddls;
+ else
+ Opcode = Intrinsic::arm_neon_vpaddlu;
+ Ops.push_back(DAG.getConstant(Opcode, dl,
+ TLI.getPointerTy(DAG.getDataLayout())));
+ EVT ElemTy = N00.getValueType().getVectorElementType();
+ unsigned NumElts = VT.getVectorNumElements();
+ EVT ConcatVT = EVT::getVectorVT(*DAG.getContext(), ElemTy, NumElts * 2);
+ SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(N), ConcatVT,
+ N00.getOperand(0), N00.getOperand(1));
+ Ops.push_back(Concat);
+
+ return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, Ops);
+}
+
+// FIXME: This function shouldn't be necessary; if we lower BUILD_VECTOR in
+// an appropriate manner, we end up with ADD(VUZP(ZEXT(N))), which is
+// much easier to match.
+static SDValue
+AddCombineBUILD_VECTORToVPADDL(SDNode *N, SDValue N0, SDValue N1,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const ARMSubtarget *Subtarget) {
// Only perform optimization if after legalize, and if NEON is available. We
// also expected both operands to be BUILD_VECTORs.
if (DCI.isBeforeLegalize() || !Subtarget->hasNEON()
@@ -8783,6 +9265,10 @@ static SDValue AddCombineToVPADDL(SDNode *N, SDValue N0, SDValue N1,
return SDValue();
}
+ // Don't generate vpaddl+vmovn; we'll match it to vpadd later.
+ if (Vec.getValueType().getVectorElementType() == VT.getVectorElementType())
+ return SDValue();
+
// Create VPADDL node.
SelectionDAG &DAG = DCI.DAG;
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@@ -8962,7 +9448,8 @@ static SDValue AddCombineTo64bitUMAAL(SDNode *AddcNode,
// be combined into a UMLAL. The other pattern is AddcNode being combined
// into an UMLAL and then using another addc is handled in ISelDAGToDAG.
- if (!Subtarget->hasV6Ops())
+ if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP() ||
+ (Subtarget->isThumb() && !Subtarget->hasThumb2()))
return AddCombineTo64bitMLAL(AddcNode, DCI, Subtarget);
SDNode *PrevAddc = nullptr;
@@ -9053,9 +9540,15 @@ static SDValue PerformADDCCombine(SDNode *N,
static SDValue PerformADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget){
+ // Attempt to create vpadd for this add.
+ if (SDValue Result = AddCombineToVPADD(N, N0, N1, DCI, Subtarget))
+ return Result;
// Attempt to create vpaddl for this add.
- if (SDValue Result = AddCombineToVPADDL(N, N0, N1, DCI, Subtarget))
+ if (SDValue Result = AddCombineVUZPToVPADDL(N, N0, N1, DCI, Subtarget))
+ return Result;
+ if (SDValue Result = AddCombineBUILD_VECTORToVPADDL(N, N0, N1, DCI,
+ Subtarget))
return Result;
// fold (add (select cc, 0, c), x) -> (select cc, x, (add, x, c))
@@ -9964,6 +10457,7 @@ static SDValue CombineBaseUpdate(SDNode *N,
isLaneOp = true;
switch (N->getOpcode()) {
default: llvm_unreachable("unexpected opcode for Neon base update");
+ case ARMISD::VLD1DUP: NewOpc = ARMISD::VLD1DUP_UPD; NumVecs = 1; break;
case ARMISD::VLD2DUP: NewOpc = ARMISD::VLD2DUP_UPD; NumVecs = 2; break;
case ARMISD::VLD3DUP: NewOpc = ARMISD::VLD3DUP_UPD; NumVecs = 3; break;
case ARMISD::VLD4DUP: NewOpc = ARMISD::VLD4DUP_UPD; NumVecs = 4; break;
@@ -10078,8 +10572,8 @@ static SDValue CombineBaseUpdate(SDNode *N,
StVal = DAG.getNode(ISD::BITCAST, dl, AlignedVecTy, StVal);
}
- SDValue UpdN = DAG.getMemIntrinsicNode(NewOpc, dl, SDTys,
- Ops, AlignedVecTy,
+ EVT LoadVT = isLaneOp ? VecTy.getVectorElementType() : AlignedVecTy;
+ SDValue UpdN = DAG.getMemIntrinsicNode(NewOpc, dl, SDTys, Ops, LoadVT,
MemN->getMemOperand());
// Update the uses.
@@ -10211,19 +10705,44 @@ static SDValue PerformVDUPLANECombine(SDNode *N,
return SDValue();
// Make sure the VMOV element size is not bigger than the VDUPLANE elements.
- unsigned EltSize = Op.getValueType().getVectorElementType().getSizeInBits();
+ unsigned EltSize = Op.getScalarValueSizeInBits();
// The canonical VMOV for a zero vector uses a 32-bit element size.
unsigned Imm = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
unsigned EltBits;
if (ARM_AM::decodeNEONModImm(Imm, EltBits) == 0)
EltSize = 8;
EVT VT = N->getValueType(0);
- if (EltSize > VT.getVectorElementType().getSizeInBits())
+ if (EltSize > VT.getScalarSizeInBits())
return SDValue();
return DCI.DAG.getNode(ISD::BITCAST, SDLoc(N), VT, Op);
}
+/// PerformVDUPCombine - Target-specific dag combine xforms for ARMISD::VDUP.
+static SDValue PerformVDUPCombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI) {
+ SelectionDAG &DAG = DCI.DAG;
+ SDValue Op = N->getOperand(0);
+
+ // Match VDUP(LOAD) -> VLD1DUP.
+ // We match this pattern here rather than waiting for isel because the
+ // transform is only legal for unindexed loads.
+ LoadSDNode *LD = dyn_cast<LoadSDNode>(Op.getNode());
+ if (LD && Op.hasOneUse() && LD->isUnindexed() &&
+ LD->getMemoryVT() == N->getValueType(0).getVectorElementType()) {
+ SDValue Ops[] = { LD->getOperand(0), LD->getOperand(1),
+ DAG.getConstant(LD->getAlignment(), SDLoc(N), MVT::i32) };
+ SDVTList SDTys = DAG.getVTList(N->getValueType(0), MVT::Other);
+ SDValue VLDDup = DAG.getMemIntrinsicNode(ARMISD::VLD1DUP, SDLoc(N), SDTys,
+ Ops, LD->getMemoryVT(),
+ LD->getMemOperand());
+ DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), VLDDup.getValue(1));
+ return VLDDup;
+ }
+
+ return SDValue();
+}
+
static SDValue PerformLOADCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI) {
EVT VT = N->getValueType(0);
@@ -10255,8 +10774,8 @@ static SDValue PerformSTORECombine(SDNode *N,
EVT StVT = St->getMemoryVT();
unsigned NumElems = VT.getVectorNumElements();
assert(StVT != VT && "Cannot truncate to the same type");
- unsigned FromEltSz = VT.getVectorElementType().getSizeInBits();
- unsigned ToEltSz = StVT.getVectorElementType().getSizeInBits();
+ unsigned FromEltSz = VT.getScalarSizeInBits();
+ unsigned ToEltSz = StVT.getScalarSizeInBits();
// From, To sizes and ElemCount must be pow of two
if (!isPowerOf2_32(NumElems * FromEltSz * ToEltSz)) return SDValue();
@@ -10524,7 +11043,7 @@ static bool getVShiftImm(SDValue Op, unsigned ElementBits, int64_t &Cnt) {
/// 0 <= Value <= ElementBits for a long left shift.
static bool isVShiftLImm(SDValue Op, EVT VT, bool isLong, int64_t &Cnt) {
assert(VT.isVector() && "vector shift count is not a vector type");
- int64_t ElementBits = VT.getVectorElementType().getSizeInBits();
+ int64_t ElementBits = VT.getScalarSizeInBits();
if (! getVShiftImm(Op, ElementBits, Cnt))
return false;
return (Cnt >= 0 && (isLong ? Cnt-1 : Cnt) < ElementBits);
@@ -10539,7 +11058,7 @@ static bool isVShiftLImm(SDValue Op, EVT VT, bool isLong, int64_t &Cnt) {
static bool isVShiftRImm(SDValue Op, EVT VT, bool isNarrow, bool isIntrinsic,
int64_t &Cnt) {
assert(VT.isVector() && "vector shift count is not a vector type");
- int64_t ElementBits = VT.getVectorElementType().getSizeInBits();
+ int64_t ElementBits = VT.getScalarSizeInBits();
if (! getVShiftImm(Op, ElementBits, Cnt))
return false;
if (!isIntrinsic)
@@ -11051,6 +11570,7 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
case ISD::INSERT_VECTOR_ELT: return PerformInsertEltCombine(N, DCI);
case ISD::VECTOR_SHUFFLE: return PerformVECTOR_SHUFFLECombine(N, DCI.DAG);
case ARMISD::VDUPLANE: return PerformVDUPLANECombine(N, DCI);
+ case ARMISD::VDUP: return PerformVDUPCombine(N, DCI);
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT:
return PerformVCVTCombine(N, DCI.DAG, Subtarget);
@@ -11066,6 +11586,7 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
case ARMISD::CMOV: return PerformCMOVCombine(N, DCI.DAG);
case ARMISD::BRCOND: return PerformBRCONDCombine(N, DCI.DAG);
case ISD::LOAD: return PerformLOADCombine(N, DCI);
+ case ARMISD::VLD1DUP:
case ARMISD::VLD2DUP:
case ARMISD::VLD3DUP:
case ARMISD::VLD4DUP:
@@ -11234,6 +11755,17 @@ bool ARMTargetLowering::allowTruncateForTailCall(Type *Ty1, Type *Ty2) const {
return true;
}
+int ARMTargetLowering::getScalingFactorCost(const DataLayout &DL,
+ const AddrMode &AM, Type *Ty,
+ unsigned AS) const {
+ if (isLegalAddressingMode(DL, AM, Ty, AS)) {
+ if (Subtarget->hasFPAO())
+ return AM.Scale < 0 ? 1 : 0; // positive offsets execute faster
+ return 0;
+ }
+ return -1;
+}
+
static bool isLegalT1AddressImmediate(int64_t V, EVT VT) {
if (V < 0)
@@ -11384,7 +11916,7 @@ bool ARMTargetLowering::isLegalAddressingMode(const DataLayout &DL,
case 1:
if (Subtarget->isThumb1Only())
return false;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
default:
// ARM doesn't support any R+R*scale+imm addr modes.
if (AM.BaseOffs)
@@ -11682,7 +12214,7 @@ void ARMTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
case Intrinsic::arm_ldaex:
case Intrinsic::arm_ldrex: {
EVT VT = cast<MemIntrinsicSDNode>(Op)->getMemoryVT();
- unsigned MemBits = VT.getScalarType().getSizeInBits();
+ unsigned MemBits = VT.getScalarSizeInBits();
KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - MemBits);
return;
}
@@ -12043,7 +12575,7 @@ static RTLIB::Libcall getDivRemLibcall(
}
static TargetLowering::ArgListTy getDivRemArgList(
- const SDNode *N, LLVMContext *Context) {
+ const SDNode *N, LLVMContext *Context, const ARMSubtarget *Subtarget) {
assert((N->getOpcode() == ISD::SDIVREM || N->getOpcode() == ISD::UDIVREM ||
N->getOpcode() == ISD::SREM || N->getOpcode() == ISD::UREM) &&
"Unhandled Opcode in getDivRemArgList");
@@ -12060,12 +12592,15 @@ static TargetLowering::ArgListTy getDivRemArgList(
Entry.isZExt = !isSigned;
Args.push_back(Entry);
}
+ if (Subtarget->isTargetWindows() && Args.size() >= 2)
+ std::swap(Args[0], Args[1]);
return Args;
}
SDValue ARMTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
assert((Subtarget->isTargetAEABI() || Subtarget->isTargetAndroid() ||
- Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI()) &&
+ Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI() ||
+ Subtarget->isTargetWindows()) &&
"Register-based DivRem lowering only");
unsigned Opcode = Op->getOpcode();
assert((Opcode == ISD::SDIVREM || Opcode == ISD::UDIVREM) &&
@@ -12073,20 +12608,42 @@ SDValue ARMTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
bool isSigned = (Opcode == ISD::SDIVREM);
EVT VT = Op->getValueType(0);
Type *Ty = VT.getTypeForEVT(*DAG.getContext());
+ SDLoc dl(Op);
+
+ // If the target has hardware divide, use divide + multiply + subtract:
+ // div = a / b
+ // rem = a - b * div
+ // return {div, rem}
+ // This should be lowered into UDIV/SDIV + MLS later on.
+ if (Subtarget->hasDivide() && Op->getValueType(0).isSimple() &&
+ Op->getSimpleValueType(0) == MVT::i32) {
+ unsigned DivOpcode = isSigned ? ISD::SDIV : ISD::UDIV;
+ const SDValue Dividend = Op->getOperand(0);
+ const SDValue Divisor = Op->getOperand(1);
+ SDValue Div = DAG.getNode(DivOpcode, dl, VT, Dividend, Divisor);
+ SDValue Mul = DAG.getNode(ISD::MUL, dl, VT, Div, Divisor);
+ SDValue Rem = DAG.getNode(ISD::SUB, dl, VT, Dividend, Mul);
+
+ SDValue Values[2] = {Div, Rem};
+ return DAG.getNode(ISD::MERGE_VALUES, dl, DAG.getVTList(VT, VT), Values);
+ }
RTLIB::Libcall LC = getDivRemLibcall(Op.getNode(),
VT.getSimpleVT().SimpleTy);
SDValue InChain = DAG.getEntryNode();
TargetLowering::ArgListTy Args = getDivRemArgList(Op.getNode(),
- DAG.getContext());
+ DAG.getContext(),
+ Subtarget);
SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC),
getPointerTy(DAG.getDataLayout()));
Type *RetTy = (Type*)StructType::get(Ty, Ty, nullptr);
- SDLoc dl(Op);
+ if (Subtarget->isTargetWindows())
+ InChain = WinDBZCheckDenominator(DAG, Op.getNode(), InChain);
+
TargetLowering::CallLoweringInfo CLI(DAG);
CLI.setDebugLoc(dl).setChain(InChain)
.setCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args))
@@ -12119,11 +12676,15 @@ SDValue ARMTargetLowering::LowerREM(SDNode *N, SelectionDAG &DAG) const {
RTLIB::Libcall LC = getDivRemLibcall(N, N->getValueType(0).getSimpleVT().
SimpleTy);
SDValue InChain = DAG.getEntryNode();
- TargetLowering::ArgListTy Args = getDivRemArgList(N, DAG.getContext());
+ TargetLowering::ArgListTy Args = getDivRemArgList(N, DAG.getContext(),
+ Subtarget);
bool isSigned = N->getOpcode() == ISD::SREM;
SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC),
getPointerTy(DAG.getDataLayout()));
+ if (Subtarget->isTargetWindows())
+ InChain = WinDBZCheckDenominator(DAG, N, InChain);
+
// Lower call
CallLoweringInfo CLI(DAG);
CLI.setChain(InChain)
@@ -12342,6 +12903,14 @@ bool ARMTargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,
return true;
}
+bool ARMTargetLowering::isExtractSubvectorCheap(EVT ResVT,
+ unsigned Index) const {
+ if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT))
+ return false;
+
+ return (Index == 0 || Index == ResVT.getVectorNumElements());
+}
+
Instruction* ARMTargetLowering::makeDMB(IRBuilder<> &Builder,
ARM_MB::MemBOpt Domain) const {
Module *M = Builder.GetInsertBlock()->getParent()->getParent();
@@ -12443,7 +13012,8 @@ ARMTargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const {
TargetLowering::AtomicExpansionKind
ARMTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
unsigned Size = AI->getType()->getPrimitiveSizeInBits();
- return (Size <= (Subtarget->isMClass() ? 32U : 64U))
+ bool hasAtomicRMW = !Subtarget->isThumb() || Subtarget->hasV8MBaselineOps();
+ return (Size <= (Subtarget->isMClass() ? 32U : 64U) && hasAtomicRMW)
? AtomicExpansionKind::LLSC
: AtomicExpansionKind::None;
}
@@ -12455,7 +13025,9 @@ bool ARMTargetLowering::shouldExpandAtomicCmpXchgInIR(
// on the stack and close enough to the spill slot, this can lead to a
// situation where the monitor always gets cleared and the atomic operation
// can never succeed. So at -O0 we need a late-expanded pseudo-inst instead.
- return getTargetMachine().getOptLevel() != 0;
+ bool hasAtomicCmpXchg =
+ !Subtarget->isThumb() || Subtarget->hasV8MBaselineOps();
+ return getTargetMachine().getOptLevel() != 0 && hasAtomicCmpXchg;
}
bool ARMTargetLowering::shouldInsertFencesForAtomic(
@@ -12681,6 +13253,17 @@ static Constant *getSequentialMask(IRBuilder<> &Builder, unsigned Start,
///
/// Note that the new shufflevectors will be removed and we'll only generate one
/// vst3 instruction in CodeGen.
+///
+/// Example for a more general valid mask (Factor 3). Lower:
+/// %i.vec = shuffle <32 x i32> %v0, <32 x i32> %v1,
+/// <4, 32, 16, 5, 33, 17, 6, 34, 18, 7, 35, 19>
+/// store <12 x i32> %i.vec, <12 x i32>* %ptr
+///
+/// Into:
+/// %sub.v0 = shuffle <32 x i32> %v0, <32 x i32> v1, <4, 5, 6, 7>
+/// %sub.v1 = shuffle <32 x i32> %v0, <32 x i32> v1, <32, 33, 34, 35>
+/// %sub.v2 = shuffle <32 x i32> %v0, <32 x i32> v1, <16, 17, 18, 19>
+/// call void llvm.arm.neon.vst3(%ptr, %sub.v0, %sub.v1, %sub.v2, 4)
bool ARMTargetLowering::lowerInterleavedStore(StoreInst *SI,
ShuffleVectorInst *SVI,
unsigned Factor) const {
@@ -12691,9 +13274,9 @@ bool ARMTargetLowering::lowerInterleavedStore(StoreInst *SI,
assert(VecTy->getVectorNumElements() % Factor == 0 &&
"Invalid interleaved store");
- unsigned NumSubElts = VecTy->getVectorNumElements() / Factor;
+ unsigned LaneLen = VecTy->getVectorNumElements() / Factor;
Type *EltTy = VecTy->getVectorElementType();
- VectorType *SubVecTy = VectorType::get(EltTy, NumSubElts);
+ VectorType *SubVecTy = VectorType::get(EltTy, LaneLen);
const DataLayout &DL = SI->getModule()->getDataLayout();
unsigned SubVecSize = DL.getTypeSizeInBits(SubVecTy);
@@ -12720,7 +13303,7 @@ bool ARMTargetLowering::lowerInterleavedStore(StoreInst *SI,
Op0 = Builder.CreatePtrToInt(Op0, IntVecTy);
Op1 = Builder.CreatePtrToInt(Op1, IntVecTy);
- SubVecTy = VectorType::get(IntTy, NumSubElts);
+ SubVecTy = VectorType::get(IntTy, LaneLen);
}
static const Intrinsic::ID StoreInts[3] = {Intrinsic::arm_neon_vst2,
@@ -12736,9 +13319,28 @@ bool ARMTargetLowering::lowerInterleavedStore(StoreInst *SI,
SI->getModule(), StoreInts[Factor - 2], Tys);
// Split the shufflevector operands into sub vectors for the new vstN call.
- for (unsigned i = 0; i < Factor; i++)
- Ops.push_back(Builder.CreateShuffleVector(
- Op0, Op1, getSequentialMask(Builder, NumSubElts * i, NumSubElts)));
+ auto Mask = SVI->getShuffleMask();
+ for (unsigned i = 0; i < Factor; i++) {
+ if (Mask[i] >= 0) {
+ Ops.push_back(Builder.CreateShuffleVector(
+ Op0, Op1, getSequentialMask(Builder, Mask[i], LaneLen)));
+ } else {
+ unsigned StartMask = 0;
+ for (unsigned j = 1; j < LaneLen; j++) {
+ if (Mask[j*Factor + i] >= 0) {
+ StartMask = Mask[j*Factor + i] - j;
+ break;
+ }
+ }
+ // Note: If all elements in a chunk are undefs, StartMask=0!
+ // Note: Filling undef gaps with random elements is ok, since
+ // those elements were being written anyway (with undefs).
+ // In the case of all undefs we're defaulting to using elems from 0
+ // Note: StartMask cannot be negative, it's checked in isReInterleaveMask
+ Ops.push_back(Builder.CreateShuffleVector(
+ Op0, Op1, getSequentialMask(Builder, StartMask, LaneLen)));
+ }
+ }
Ops.push_back(Builder.getInt32(SI->getAlignment()));
Builder.CreateCall(VstNFunc, Ops);
diff --git a/contrib/llvm/lib/Target/ARM/ARMISelLowering.h b/contrib/llvm/lib/Target/ARM/ARMISelLowering.h
index 4906686..84c6eb8 100644
--- a/contrib/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/contrib/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -16,16 +16,28 @@
#define LLVM_LIB_TARGET_ARM_ARMISELLOWERING_H
#include "MCTargetDesc/ARMBaseInfo.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SelectionDAGNodes.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Target/TargetLowering.h"
-#include <vector>
+#include <utility>
namespace llvm {
- class ARMConstantPoolValue;
- class ARMSubtarget;
+
+class ARMSubtarget;
+class InstrItineraryData;
namespace ARMISD {
+
// ARM Specific DAG Nodes
enum NodeType : unsigned {
// Start the numbering where the builtin ops and target ops leave off.
@@ -190,7 +202,8 @@ namespace llvm {
MEMCPY,
// Vector load N-element structure to all lanes:
- VLD2DUP = ISD::FIRST_TARGET_MEMORY_OPCODE,
+ VLD1DUP = ISD::FIRST_TARGET_MEMORY_OPCODE,
+ VLD2DUP,
VLD3DUP,
VLD4DUP,
@@ -202,6 +215,7 @@ namespace llvm {
VLD2LN_UPD,
VLD3LN_UPD,
VLD4LN_UPD,
+ VLD1DUP_UPD,
VLD2DUP_UPD,
VLD3DUP_UPD,
VLD4DUP_UPD,
@@ -215,12 +229,15 @@ namespace llvm {
VST3LN_UPD,
VST4LN_UPD
};
- }
+
+ } // end namespace ARMISD
/// Define some predicates that are used for node matching.
namespace ARM {
+
bool isBitFieldInvertedMask(unsigned v);
- }
+
+ } // end namespace ARM
//===--------------------------------------------------------------------===//
// ARMTargetLowering - ARM Implementation of the TargetLowering interface
@@ -291,6 +308,14 @@ namespace llvm {
/// by AM is legal for this target, for a load/store of the specified type.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM,
Type *Ty, unsigned AS) const override;
+
+ /// getScalingFactorCost - Return the cost of the scaling used in
+ /// addressing mode represented by AM.
+ /// If the AM is supported, the return value must be >= 0.
+ /// If the AM is not supported, the return value must be negative.
+ int getScalingFactorCost(const DataLayout &DL, const AddrMode &AM, Type *Ty,
+ unsigned AS) const override;
+
bool isLegalT2ScaledAddressingMode(const AddrMode &AM, EVT VT) const;
/// isLegalICmpImmediate - Return true if the specified immediate is legal
@@ -421,6 +446,10 @@ namespace llvm {
bool shouldConvertConstantLoadToIntImm(const APInt &Imm,
Type *Ty) const override;
+ /// Return true if EXTRACT_SUBVECTOR is cheap for this result type
+ /// with this index.
+ bool isExtractSubvectorCheap(EVT ResVT, unsigned Index) const override;
+
/// \brief Returns true if an argument of type Ty needs to be passed in a
/// contiguous block of registers in calling convention CallConv.
bool functionArgumentNeedsConsecutiveRegisters(
@@ -482,6 +511,9 @@ namespace llvm {
return HasStandaloneRem;
}
+ CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool isVarArg) const;
+ CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC, bool isVarArg) const;
+
protected:
std::pair<const TargetRegisterClass *, uint8_t>
findRepresentativeClass(const TargetRegisterInfo *TRI,
@@ -512,6 +544,7 @@ namespace llvm {
std::pair<SDValue, SDValue> getARMXALUOOp(SDValue Op, SelectionDAG &DAG, SDValue &ARMcc) const;
typedef SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPassVector;
+
void PassF64ArgInRegs(const SDLoc &dl, SelectionDAG &DAG, SDValue Chain,
SDValue &Arg, RegsToPassVector &RegsToPass,
CCValAssign &VA, CCValAssign &NextVA,
@@ -604,6 +637,7 @@ namespace llvm {
return MF->getFunction()->getCallingConv() == CallingConv::CXX_FAST_TLS &&
MF->getFunction()->hasFnAttribute(Attribute::NoUnwind);
}
+
void initializeSplitCSR(MachineBasicBlock *Entry) const override;
void insertCopiesSplitCSR(
MachineBasicBlock *Entry,
@@ -625,9 +659,8 @@ namespace llvm {
unsigned ArgOffset, unsigned TotalArgRegsSaveSize,
bool ForceMutable = false) const;
- SDValue
- LowerCall(TargetLowering::CallLoweringInfo &CLI,
- SmallVectorImpl<SDValue> &InVals) const override;
+ SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const override;
/// HandleByVal - Target-specific cleanup for ByVal support.
void HandleByVal(CCState *, unsigned &, unsigned) const override;
@@ -693,9 +726,12 @@ namespace llvm {
};
namespace ARM {
+
FastISel *createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo);
- }
-}
-#endif // ARMISELLOWERING_H
+ } // end namespace ARM
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_ARM_ARMISELLOWERING_H
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrFormats.td b/contrib/llvm/lib/Target/ARM/ARMInstrFormats.td
index 37a83f7..488439f 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrFormats.td
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrFormats.td
@@ -398,6 +398,14 @@ class tPseudoInst<dag oops, dag iops, int sz, InstrItinClass itin,
list<Predicate> Predicates = [IsThumb];
}
+// PseudoInst that's in ARMv8-M baseline (Somewhere between Thumb and Thumb2)
+class t2basePseudoInst<dag oops, dag iops, int sz, InstrItinClass itin,
+ list<dag> pattern>
+ : PseudoInst<oops, iops, itin, pattern> {
+ let Size = sz;
+ list<Predicate> Predicates = [IsThumb,HasV8MBaseline];
+}
+
// PseudoInst that's Thumb2-mode only.
class t2PseudoInst<dag oops, dag iops, int sz, InstrItinClass itin,
list<dag> pattern>
@@ -999,6 +1007,15 @@ class VFPPat<dag pattern, dag result> : Pat<pattern, result> {
class VFPNoNEONPat<dag pattern, dag result> : Pat<pattern, result> {
list<Predicate> Predicates = [HasVFP2, DontUseNEONForFP];
}
+class Thumb2DSPPat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [IsThumb2, HasDSP];
+}
+class Thumb2DSPMulPat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [IsThumb2, UseMulOps, HasDSP];
+}
+class Thumb2ExtractPat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [IsThumb2, HasT2ExtractPack];
+}
//===----------------------------------------------------------------------===//
// Thumb Instruction Format Definitions.
//
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMInstrInfo.cpp
index 98b1b4c..27b6432 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrInfo.cpp
@@ -123,7 +123,9 @@ void ARMInstrInfo::expandLoadStackGuard(MachineBasicBlock::iterator MI) const {
MIB = BuildMI(MBB, MI, DL, get(ARM::MOV_ga_pcrel_ldr), Reg)
.addGlobalAddress(GV, 0, ARMII::MO_NONLAZY);
- auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant;
+ auto Flags = MachineMemOperand::MOLoad |
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant;
MachineMemOperand *MMO = MBB.getParent()->getMachineMemOperand(
MachinePointerInfo::getGOT(*MBB.getParent()), Flags, 4, 4);
MIB.addMemOperand(MMO);
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrInfo.td b/contrib/llvm/lib/Target/ARM/ARMInstrInfo.td
index c9735f3..c473939 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -330,6 +330,8 @@ def DontUseVMOVSR : Predicate<"!Subtarget->preferVMOVSR() &&"
def IsLE : Predicate<"MF->getDataLayout().isLittleEndian()">;
def IsBE : Predicate<"MF->getDataLayout().isBigEndian()">;
+def GenExecuteOnly : Predicate<"Subtarget->genExecuteOnly()">;
+
//===----------------------------------------------------------------------===//
// ARM Flag Definitions.
@@ -358,7 +360,23 @@ def imm16_31 : ImmLeaf<i32, [{
// sext_16_node predicate - True if the SDNode is sign-extended 16 or more bits.
def sext_16_node : PatLeaf<(i32 GPR:$a), [{
- return CurDAG->ComputeNumSignBits(SDValue(N,0)) >= 17;
+ if (CurDAG->ComputeNumSignBits(SDValue(N,0)) >= 17)
+ return true;
+
+ if (N->getOpcode() != ISD::SRA)
+ return false;
+ if (N->getOperand(0).getOpcode() != ISD::SHL)
+ return false;
+
+ auto *ShiftVal = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (!ShiftVal || ShiftVal->getZExtValue() != 16)
+ return false;
+
+ ShiftVal = dyn_cast<ConstantSDNode>(N->getOperand(0)->getOperand(1));
+ if (!ShiftVal || ShiftVal->getZExtValue() != 16)
+ return false;
+
+ return true;
}]>;
/// Split a 32-bit immediate into two 16 bit parts.
@@ -3400,6 +3418,12 @@ def SXTAB : AI_exta_rrot<0b01101010,
def SXTAH : AI_exta_rrot<0b01101011,
"sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>;
+def : ARMV6Pat<(add rGPR:$Rn, (sext_inreg (srl rGPR:$Rm, rot_imm:$rot), i8)),
+ (SXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+def : ARMV6Pat<(add rGPR:$Rn, (sext_inreg (srl rGPR:$Rm, imm8_or_16:$rot),
+ i16)),
+ (SXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+
def SXTB16 : AI_ext_rrot_np<0b01101000, "sxtb16">;
def SXTAB16 : AI_exta_rrot_np<0b01101000, "sxtab16">;
@@ -3427,6 +3451,11 @@ def UXTAB : AI_exta_rrot<0b01101110, "uxtab",
BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>;
def UXTAH : AI_exta_rrot<0b01101111, "uxtah",
BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>;
+
+def : ARMV6Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, rot_imm:$rot), 0xFF)),
+ (UXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+def : ARMV6Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, imm8_or_16:$rot), 0xFFFF)),
+ (UXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
}
// This isn't safe in general, the add is two 16-bit units, not a 32-bit add.
@@ -3471,6 +3500,7 @@ def UBFX : I<(outs GPRnopc:$Rd),
// Arithmetic Instructions.
//
+let isAdd = 1 in
defm ADD : AsI1_bin_irs<0b0100, "add",
IIC_iALUi, IIC_iALUr, IIC_iALUsr, add, 1>;
defm SUB : AsI1_bin_irs<0b0010, "sub",
@@ -3486,9 +3516,11 @@ defm SUB : AsI1_bin_irs<0b0010, "sub",
// FIXME: Eliminate ADDS/SUBS pseudo opcodes after adding tablegen
// support for an optional CPSR definition that corresponds to the DAG
// node's second value. We can then eliminate the implicit def of CPSR.
+let isAdd = 1 in
defm ADDS : AsI1_bin_s_irs<IIC_iALUi, IIC_iALUr, IIC_iALUsr, ARMaddc, 1>;
defm SUBS : AsI1_bin_s_irs<IIC_iALUi, IIC_iALUr, IIC_iALUsr, ARMsubc>;
+let isAdd = 1 in
defm ADC : AI1_adde_sube_irs<0b0101, "adc", ARMadde, 1>;
defm SBC : AI1_adde_sube_irs<0b0110, "sbc", ARMsube>;
@@ -5492,45 +5524,22 @@ def : ARMPat<(extloadi8 addrmodepc:$addr), (PICLDRB addrmodepc:$addr)>;
def : ARMPat<(extloadi16 addrmodepc:$addr), (PICLDRH addrmodepc:$addr)>;
// smul* and smla*
-def : ARMV5TEPat<(mul (sra (shl GPR:$a, (i32 16)), (i32 16)),
- (sra (shl GPR:$b, (i32 16)), (i32 16))),
- (SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, sext_16_node:$b),
(SMULBB GPR:$a, GPR:$b)>;
-def : ARMV5TEPat<(mul (sra (shl GPR:$a, (i32 16)), (i32 16)),
- (sra GPR:$b, (i32 16))),
- (SMULBT GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, (sra GPR:$b, (i32 16))),
(SMULBT GPR:$a, GPR:$b)>;
-def : ARMV5TEPat<(mul (sra GPR:$a, (i32 16)),
- (sra (shl GPR:$b, (i32 16)), (i32 16))),
- (SMULTB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra GPR:$a, (i32 16)), sext_16_node:$b),
(SMULTB GPR:$a, GPR:$b)>;
-
-def : ARMV5MOPat<(add GPR:$acc,
- (mul (sra (shl GPR:$a, (i32 16)), (i32 16)),
- (sra (shl GPR:$b, (i32 16)), (i32 16)))),
- (SMLABB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5MOPat<(add GPR:$acc,
(mul sext_16_node:$a, sext_16_node:$b)),
(SMLABB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5MOPat<(add GPR:$acc,
- (mul (sra (shl GPR:$a, (i32 16)), (i32 16)),
- (sra GPR:$b, (i32 16)))),
- (SMLABT GPR:$a, GPR:$b, GPR:$acc)>;
-def : ARMV5MOPat<(add GPR:$acc,
(mul sext_16_node:$a, (sra GPR:$b, (i32 16)))),
(SMLABT GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5MOPat<(add GPR:$acc,
- (mul (sra GPR:$a, (i32 16)),
- (sra (shl GPR:$b, (i32 16)), (i32 16)))),
- (SMLATB GPR:$a, GPR:$b, GPR:$acc)>;
-def : ARMV5MOPat<(add GPR:$acc,
(mul (sra GPR:$a, (i32 16)), sext_16_node:$b)),
(SMLATB GPR:$a, GPR:$b, GPR:$acc)>;
-
// Pre-v7 uses MCR for synchronization barriers.
def : ARMPat<(ARMMemBarrierMCR GPR:$zero), (MCR 15, 0, GPR:$zero, 7, 10, 5)>,
Requires<[IsARM, HasV6]>;
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrNEON.td b/contrib/llvm/lib/Target/ARM/ARMInstrNEON.td
index defef4e..b5fa8e9 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrNEON.td
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrNEON.td
@@ -610,14 +610,14 @@ def NEONimmAllOnesV: PatLeaf<(NEONvmovImm (i32 timm)), [{
def VLDMQIA
: PseudoVFPLdStM<(outs DPair:$dst), (ins GPR:$Rn),
IIC_fpLoad_m, "",
- [(set DPair:$dst, (v2f64 (load GPR:$Rn)))]>;
+ [(set DPair:$dst, (v2f64 (word_alignedload GPR:$Rn)))]>;
// Use VSTM to store a Q register as a D register pair.
// This is a pseudo instruction that is expanded to VSTMD after reg alloc.
def VSTMQIA
: PseudoVFPLdStM<(outs), (ins DPair:$src, GPR:$Rn),
IIC_fpStore_m, "",
- [(store (v2f64 DPair:$src), GPR:$Rn)]>;
+ [(word_alignedstore (v2f64 DPair:$src), GPR:$Rn)]>;
// Classes for VLD* pseudo-instructions with multi-register operands.
// These are expanded to real instructions after register allocation.
@@ -6849,6 +6849,16 @@ let Predicates = [IsBE] in {
def : Pat<(v2f64 (bitconvert (v4f32 QPR:$src))), (VREV64q32 QPR:$src)>;
}
+// Use VLD1/VST1 + VREV for non-word-aligned v2f64 load/store on Big Endian
+def : Pat<(v2f64 (byte_alignedload addrmode6:$addr)),
+ (VREV64q8 (VLD1q8 addrmode6:$addr))>, Requires<[IsBE]>;
+def : Pat<(byte_alignedstore (v2f64 QPR:$value), addrmode6:$addr),
+ (VST1q8 addrmode6:$addr, (VREV64q8 QPR:$value))>, Requires<[IsBE]>;
+def : Pat<(v2f64 (hword_alignedload addrmode6:$addr)),
+ (VREV64q16 (VLD1q16 addrmode6:$addr))>, Requires<[IsBE]>;
+def : Pat<(hword_alignedstore (v2f64 QPR:$value), addrmode6:$addr),
+ (VST1q16 addrmode6:$addr, (VREV64q16 QPR:$value))>, Requires<[IsBE]>;
+
// Fold extracting an element out of a v2i32 into a vfp register.
def : Pat<(f32 (bitconvert (i32 (extractelt (v2i32 DPR:$src), imm:$lane)))),
(f32 (EXTRACT_SUBREG DPR:$src, (SSubReg_f32_reg imm:$lane)))>;
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrThumb.td b/contrib/llvm/lib/Target/ARM/ARMInstrThumb.td
index 93a174f..a681f64 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrThumb.td
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrThumb.td
@@ -904,49 +904,51 @@ class T1sItGenEncodeImm<bits<5> opA, dag oops, dag iops, InstrItinClass itin,
let Inst{7-0} = imm8;
}
-// Add with carry register
-let isCommutable = 1, Uses = [CPSR] in
-def tADC : // A8.6.2
- T1sItDPEncode<0b0101, (outs tGPR:$Rdn), (ins tGPR:$Rn, tGPR:$Rm), IIC_iALUr,
- "adc", "\t$Rdn, $Rm",
- [(set tGPR:$Rdn, (adde tGPR:$Rn, tGPR:$Rm))]>, Sched<[WriteALU]>;
-
-// Add immediate
-def tADDi3 : // A8.6.4 T1
- T1sIGenEncodeImm<0b01110, (outs tGPR:$Rd), (ins tGPR:$Rm, imm0_7:$imm3),
- IIC_iALUi,
- "add", "\t$Rd, $Rm, $imm3",
- [(set tGPR:$Rd, (add tGPR:$Rm, imm0_7:$imm3))]>,
- Sched<[WriteALU]> {
- bits<3> imm3;
- let Inst{8-6} = imm3;
-}
-
-def tADDi8 : // A8.6.4 T2
- T1sItGenEncodeImm<{1,1,0,?,?}, (outs tGPR:$Rdn),
- (ins tGPR:$Rn, imm0_255:$imm8), IIC_iALUi,
- "add", "\t$Rdn, $imm8",
- [(set tGPR:$Rdn, (add tGPR:$Rn, imm8_255:$imm8))]>,
- Sched<[WriteALU]>;
+let isAdd = 1 in {
+ // Add with carry register
+ let isCommutable = 1, Uses = [CPSR] in
+ def tADC : // A8.6.2
+ T1sItDPEncode<0b0101, (outs tGPR:$Rdn), (ins tGPR:$Rn, tGPR:$Rm), IIC_iALUr,
+ "adc", "\t$Rdn, $Rm",
+ [(set tGPR:$Rdn, (adde tGPR:$Rn, tGPR:$Rm))]>, Sched<[WriteALU]>;
+
+ // Add immediate
+ def tADDi3 : // A8.6.4 T1
+ T1sIGenEncodeImm<0b01110, (outs tGPR:$Rd), (ins tGPR:$Rm, imm0_7:$imm3),
+ IIC_iALUi,
+ "add", "\t$Rd, $Rm, $imm3",
+ [(set tGPR:$Rd, (add tGPR:$Rm, imm0_7:$imm3))]>,
+ Sched<[WriteALU]> {
+ bits<3> imm3;
+ let Inst{8-6} = imm3;
+ }
-// Add register
-let isCommutable = 1 in
-def tADDrr : // A8.6.6 T1
- T1sIGenEncode<0b01100, (outs tGPR:$Rd), (ins tGPR:$Rn, tGPR:$Rm),
- IIC_iALUr,
- "add", "\t$Rd, $Rn, $Rm",
- [(set tGPR:$Rd, (add tGPR:$Rn, tGPR:$Rm))]>, Sched<[WriteALU]>;
-
-let hasSideEffects = 0 in
-def tADDhirr : T1pIt<(outs GPR:$Rdn), (ins GPR:$Rn, GPR:$Rm), IIC_iALUr,
- "add", "\t$Rdn, $Rm", []>,
- T1Special<{0,0,?,?}>, Sched<[WriteALU]> {
- // A8.6.6 T2
- bits<4> Rdn;
- bits<4> Rm;
- let Inst{7} = Rdn{3};
- let Inst{6-3} = Rm;
- let Inst{2-0} = Rdn{2-0};
+ def tADDi8 : // A8.6.4 T2
+ T1sItGenEncodeImm<{1,1,0,?,?}, (outs tGPR:$Rdn),
+ (ins tGPR:$Rn, imm0_255:$imm8), IIC_iALUi,
+ "add", "\t$Rdn, $imm8",
+ [(set tGPR:$Rdn, (add tGPR:$Rn, imm8_255:$imm8))]>,
+ Sched<[WriteALU]>;
+
+ // Add register
+ let isCommutable = 1 in
+ def tADDrr : // A8.6.6 T1
+ T1sIGenEncode<0b01100, (outs tGPR:$Rd), (ins tGPR:$Rn, tGPR:$Rm),
+ IIC_iALUr,
+ "add", "\t$Rd, $Rn, $Rm",
+ [(set tGPR:$Rd, (add tGPR:$Rn, tGPR:$Rm))]>, Sched<[WriteALU]>;
+
+ let hasSideEffects = 0 in
+ def tADDhirr : T1pIt<(outs GPR:$Rdn), (ins GPR:$Rn, GPR:$Rm), IIC_iALUr,
+ "add", "\t$Rdn, $Rm", []>,
+ T1Special<{0,0,?,?}>, Sched<[WriteALU]> {
+ // A8.6.6 T2
+ bits<4> Rdn;
+ bits<4> Rm;
+ let Inst{7} = Rdn{3};
+ let Inst{6-3} = Rm;
+ let Inst{2-0} = Rdn{2-0};
+ }
}
// AND register
@@ -1259,6 +1261,13 @@ def tUDF : TI<(outs), (ins imm0_255:$imm8), IIC_Br, "udf\t$imm8",
let Inst{7-0} = imm8;
}
+def t__brkdiv0 : TI<(outs), (ins), IIC_Br, "__brkdiv0",
+ [(int_arm_undefined 249)]>, Encoding16,
+ Requires<[IsThumb, IsWindows]> {
+ let Inst = 0xdef9;
+ let isTerminator = 1;
+}
+
// Zero-extend byte
def tUXTB : // A8.6.262
T1pIMiscEncode<{0,0,1,0,1,1,?}, (outs tGPR:$Rd), (ins tGPR:$Rm),
@@ -1306,6 +1315,18 @@ def tLEApcrelJT : tPseudoInst<(outs tGPR:$Rd),
(ins i32imm:$label, pred:$p),
2, IIC_iALUi, []>, Sched<[WriteALU]>;
+// Thumb-1 doesn't have the TBB or TBH instructions, but we can synthesize them
+// and make use of the same compressed jump table format as Thumb-2.
+let Size = 2 in {
+def tTBB_JT : tPseudoInst<(outs),
+ (ins tGPR:$base, tGPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>,
+ Sched<[WriteBr]>;
+
+def tTBH_JT : tPseudoInst<(outs),
+ (ins tGPR:$base, tGPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>,
+ Sched<[WriteBr]>;
+}
+
//===----------------------------------------------------------------------===//
// TLS Instructions
//
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td b/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td
index db8b9fb..603d664 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -536,9 +536,9 @@ class T2FourReg<dag oops, dag iops, InstrItinClass itin,
}
class T2MulLong<bits<3> opc22_20, bits<4> opc7_4,
- dag oops, dag iops, InstrItinClass itin,
- string opc, string asm, list<dag> pattern>
- : T2I<oops, iops, itin, opc, asm, pattern> {
+ string opc, list<dag> pattern>
+ : T2I<(outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64,
+ opc, "\t$RdLo, $RdHi, $Rn, $Rm", pattern> {
bits<4> RdLo;
bits<4> RdHi;
bits<4> Rn;
@@ -552,10 +552,11 @@ class T2MulLong<bits<3> opc22_20, bits<4> opc7_4,
let Inst{7-4} = opc7_4;
let Inst{3-0} = Rm;
}
-class T2MlaLong<bits<3> opc22_20, bits<4> opc7_4,
- dag oops, dag iops, InstrItinClass itin,
- string opc, string asm, list<dag> pattern>
- : T2I<oops, iops, itin, opc, asm, pattern> {
+class T2MlaLong<bits<3> opc22_20, bits<4> opc7_4, string opc>
+ : T2I<(outs rGPR:$RdLo, rGPR:$RdHi),
+ (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64,
+ opc, "\t$RdLo, $RdHi, $Rn, $Rm", []>,
+ RegConstraint<"$RLo = $RdLo, $RHi = $RdHi"> {
bits<4> RdLo;
bits<4> RdHi;
bits<4> Rn;
@@ -1983,12 +1984,19 @@ def t2SXTAB16 : T2I_exta_rrot_np<0b010, "sxtab16">;
// A simple right-shift can also be used in most cases (the exception is the
// SXTH operations with a rotate of 24: there the non-contiguous bits are
// relevant).
-def : Pat<(add rGPR:$Rn, (sext_inreg (srl rGPR:$Rm, rot_imm:$rot), i8)),
- (t2SXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>,
- Requires<[HasT2ExtractPack, IsThumb2]>;
-def : Pat<(add rGPR:$Rn, (sext_inreg (srl rGPR:$Rm, imm8_or_16:$rot), i16)),
- (t2SXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>,
- Requires<[HasT2ExtractPack, IsThumb2]>;
+def : Thumb2ExtractPat<(add rGPR:$Rn, (sext_inreg
+ (srl rGPR:$Rm, rot_imm:$rot), i8)),
+ (t2SXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+def : Thumb2ExtractPat<(add rGPR:$Rn, (sext_inreg
+ (srl rGPR:$Rm, imm8_or_16:$rot), i16)),
+ (t2SXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+def : Thumb2ExtractPat<(add rGPR:$Rn, (sext_inreg
+ (rotr rGPR:$Rm, (i32 24)), i16)),
+ (t2SXTAH rGPR:$Rn, rGPR:$Rm, (i32 3))>;
+def : Thumb2ExtractPat<(add rGPR:$Rn, (sext_inreg
+ (or (srl rGPR:$Rm, (i32 24)),
+ (shl rGPR:$Rm, (i32 8))), i16)),
+ (t2SXTAH rGPR:$Rn, rGPR:$Rm, (i32 3))>;
// Zero extenders
@@ -2017,12 +2025,12 @@ def t2UXTAH : T2I_exta_rrot<0b001, "uxtah",
BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>;
def t2UXTAB16 : T2I_exta_rrot_np<0b011, "uxtab16">;
-def : Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, rot_imm:$rot), 0xFF)),
- (t2UXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>,
- Requires<[HasT2ExtractPack, IsThumb2]>;
-def : Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, imm8_or_16:$rot), 0xFFFF)),
- (t2UXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>,
- Requires<[HasT2ExtractPack, IsThumb2]>;
+def : Thumb2ExtractPat<(add rGPR:$Rn, (and (srl rGPR:$Rm, rot_imm:$rot),
+ 0xFF)),
+ (t2UXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+def : Thumb2ExtractPat<(add rGPR:$Rn, (and (srl rGPR:$Rm, imm8_or_16:$rot),
+ 0xFFFF)),
+ (t2UXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
}
@@ -2030,6 +2038,7 @@ def : Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, imm8_or_16:$rot), 0xFFFF)),
// Arithmetic Instructions.
//
+let isAdd = 1 in
defm t2ADD : T2I_bin_ii12rs<0b000, "add", add, 1>;
defm t2SUB : T2I_bin_ii12rs<0b101, "sub", sub>;
@@ -2546,367 +2555,194 @@ def t2MUL: T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32,
let Inst{7-4} = 0b0000; // Multiply
}
-def t2MLA: T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
- "mla", "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (add (mul rGPR:$Rn, rGPR:$Rm), rGPR:$Ra))]>,
- Requires<[IsThumb2, UseMulOps]> {
+class T2FourRegMLA<bits<4> op7_4, string opc, list<dag> pattern>
+ : T2FourReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
+ opc, "\t$Rd, $Rn, $Rm, $Ra", pattern>,
+ Requires<[IsThumb2, UseMulOps]> {
let Inst{31-27} = 0b11111;
let Inst{26-23} = 0b0110;
let Inst{22-20} = 0b000;
- let Inst{7-4} = 0b0000; // Multiply
+ let Inst{7-4} = op7_4;
}
-def t2MLS: T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
- "mls", "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (sub rGPR:$Ra, (mul rGPR:$Rn, rGPR:$Rm)))]>,
- Requires<[IsThumb2, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b000;
- let Inst{7-4} = 0b0001; // Multiply and Subtract
-}
+def t2MLA : T2FourRegMLA<0b0000, "mla",
+ [(set rGPR:$Rd, (add (mul rGPR:$Rn, rGPR:$Rm),
+ rGPR:$Ra))]>;
+def t2MLS: T2FourRegMLA<0b0001, "mls",
+ [(set rGPR:$Rd, (sub rGPR:$Ra, (mul rGPR:$Rn,
+ rGPR:$Rm)))]>;
// Extra precision multiplies with low / high results
let hasSideEffects = 0 in {
let isCommutable = 1 in {
-def t2SMULL : T2MulLong<0b000, 0b0000,
- (outs rGPR:$RdLo, rGPR:$RdHi),
- (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64,
- "smull", "\t$RdLo, $RdHi, $Rn, $Rm", []>;
-
-def t2UMULL : T2MulLong<0b010, 0b0000,
- (outs rGPR:$RdLo, rGPR:$RdHi),
- (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64,
- "umull", "\t$RdLo, $RdHi, $Rn, $Rm", []>;
+def t2SMULL : T2MulLong<0b000, 0b0000, "smull", []>;
+def t2UMULL : T2MulLong<0b010, 0b0000, "umull", []>;
} // isCommutable
// Multiply + accumulate
-def t2SMLAL : T2MlaLong<0b100, 0b0000,
- (outs rGPR:$RdLo, rGPR:$RdHi),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64,
- "smlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>,
- RegConstraint<"$RLo = $RdLo, $RHi = $RdHi">;
-
-def t2UMLAL : T2MlaLong<0b110, 0b0000,
- (outs rGPR:$RdLo, rGPR:$RdHi),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64,
- "umlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>,
- RegConstraint<"$RLo = $RdLo, $RHi = $RdHi">;
-
-def t2UMAAL : T2MulLong<0b110, 0b0110,
- (outs rGPR:$RdLo, rGPR:$RdHi),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64,
- "umaal", "\t$RdLo, $RdHi, $Rn, $Rm", []>,
- RegConstraint<"$RLo = $RdLo, $RHi = $RdHi">,
- Requires<[IsThumb2, HasDSP]>;
+def t2SMLAL : T2MlaLong<0b100, 0b0000, "smlal">;
+def t2UMLAL : T2MlaLong<0b110, 0b0000, "umlal">;
+def t2UMAAL : T2MlaLong<0b110, 0b0110, "umaal">, Requires<[IsThumb2, HasDSP]>;
} // hasSideEffects
// Rounding variants of the below included for disassembly only
// Most significant word multiply
-def t2SMMUL : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32,
- "smmul", "\t$Rd, $Rn, $Rm",
- [(set rGPR:$Rd, (mulhs rGPR:$Rn, rGPR:$Rm))]>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b101;
- let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0)
-}
-
-def t2SMMULR : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32,
- "smmulr", "\t$Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]> {
+class T2SMMUL<bits<4> op7_4, string opc, list<dag> pattern>
+ : T2ThreeReg<(outs rGPR:$Rd),
+ (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32,
+ opc, "\t$Rd, $Rn, $Rm", pattern>,
+ Requires<[IsThumb2, HasDSP]> {
let Inst{31-27} = 0b11111;
let Inst{26-23} = 0b0110;
let Inst{22-20} = 0b101;
let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1)
+ let Inst{7-4} = op7_4;
}
+def t2SMMUL : T2SMMUL<0b0000, "smmul", [(set rGPR:$Rd, (mulhs rGPR:$Rn,
+ rGPR:$Rm))]>;
+def t2SMMULR : T2SMMUL<0b0001, "smmulr", []>;
-def t2SMMLA : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
- "smmla", "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (add (mulhs rGPR:$Rm, rGPR:$Rn), rGPR:$Ra))]>,
+class T2FourRegSMMLA<bits<3> op22_20, bits<4> op7_4, string opc,
+ list<dag> pattern>
+ : T2FourReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
+ opc, "\t$Rd, $Rn, $Rm, $Ra", pattern>,
Requires<[IsThumb2, HasDSP, UseMulOps]> {
let Inst{31-27} = 0b11111;
let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b101;
- let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0)
-}
-
-def t2SMMLAR: T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
- "smmlar", "\t$Rd, $Rn, $Rm, $Ra", []>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b101;
- let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1)
-}
-
-def t2SMMLS: T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
- "smmls", "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (sub rGPR:$Ra, (mulhs rGPR:$Rn, rGPR:$Rm)))]>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b110;
- let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0)
-}
-
-def t2SMMLSR:T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32,
- "smmlsr", "\t$Rd, $Rn, $Rm, $Ra", []>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b110;
- let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1)
+ let Inst{22-20} = op22_20;
+ let Inst{7-4} = op7_4;
}
-multiclass T2I_smul<string opc, SDNode opnode> {
- def BB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16,
- !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm",
- [(set rGPR:$Rd, (opnode (sext_inreg rGPR:$Rn, i16),
- (sext_inreg rGPR:$Rm, i16)))]>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b00;
- }
-
- def BT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16,
- !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm",
- [(set rGPR:$Rd, (opnode (sext_inreg rGPR:$Rn, i16),
- (sra rGPR:$Rm, (i32 16))))]>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b01;
- }
-
- def TB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16,
- !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm",
- [(set rGPR:$Rd, (opnode (sra rGPR:$Rn, (i32 16)),
- (sext_inreg rGPR:$Rm, i16)))]>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b10;
- }
+def t2SMMLA : T2FourRegSMMLA<0b101, 0b0000, "smmla",
+ [(set rGPR:$Rd, (add (mulhs rGPR:$Rm, rGPR:$Rn), rGPR:$Ra))]>;
+def t2SMMLAR: T2FourRegSMMLA<0b101, 0b0001, "smmlar", []>;
+def t2SMMLS: T2FourRegSMMLA<0b110, 0b0000, "smmls", []>;
+def t2SMMLSR: T2FourRegSMMLA<0b110, 0b0001, "smmlsr", []>;
- def TT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16,
- !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm",
- [(set rGPR:$Rd, (opnode (sra rGPR:$Rn, (i32 16)),
- (sra rGPR:$Rm, (i32 16))))]>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b11;
- }
-
- def WB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16,
- !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm",
- []>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b011;
- let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b00;
- }
-
- def WT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16,
- !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm",
- []>,
- Requires<[IsThumb2, HasDSP]> {
+class T2ThreeRegSMUL<bits<3> op22_20, bits<2> op5_4, string opc,
+ list<dag> pattern>
+ : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, opc,
+ "\t$Rd, $Rn, $Rm", pattern>,
+ Requires<[IsThumb2, HasDSP]> {
let Inst{31-27} = 0b11111;
let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b011;
+ let Inst{22-20} = op22_20;
let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b01;
- }
-}
-
-
-multiclass T2I_smla<string opc, SDNode opnode> {
- def BB : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16,
- !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (add rGPR:$Ra,
- (opnode (sext_inreg rGPR:$Rn, i16),
- (sext_inreg rGPR:$Rm, i16))))]>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b00;
- }
-
- def BT : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16,
- !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sext_inreg rGPR:$Rn, i16),
- (sra rGPR:$Rm, (i32 16)))))]>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b01;
- }
-
- def TB : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16,
- !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sra rGPR:$Rn, (i32 16)),
- (sext_inreg rGPR:$Rm, i16))))]>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
+ let Inst{5-4} = op5_4;
+}
+
+def t2SMULBB : T2ThreeRegSMUL<0b001, 0b00, "smulbb",
+ [(set rGPR:$Rd, (mul (sext_inreg rGPR:$Rn, i16),
+ (sext_inreg rGPR:$Rm, i16)))]>;
+def t2SMULBT : T2ThreeRegSMUL<0b001, 0b01, "smulbt",
+ [(set rGPR:$Rd, (mul (sext_inreg rGPR:$Rn, i16),
+ (sra rGPR:$Rm, (i32 16))))]>;
+def t2SMULTB : T2ThreeRegSMUL<0b001, 0b10, "smultb",
+ [(set rGPR:$Rd, (mul (sra rGPR:$Rn, (i32 16)),
+ (sext_inreg rGPR:$Rm, i16)))]>;
+def t2SMULTT : T2ThreeRegSMUL<0b001, 0b11, "smultt",
+ [(set rGPR:$Rd, (mul (sra rGPR:$Rn, (i32 16)),
+ (sra rGPR:$Rm, (i32 16))))]>;
+def t2SMULWB : T2ThreeRegSMUL<0b011, 0b00, "smulwb", []>;
+def t2SMULWT : T2ThreeRegSMUL<0b011, 0b01, "smulwt", []>;
+
+def : Thumb2DSPPat<(mul sext_16_node:$Rm, sext_16_node:$Rn),
+ (t2SMULBB rGPR:$Rm, rGPR:$Rn)>;
+def : Thumb2DSPPat<(mul sext_16_node:$Rn, (sra rGPR:$Rm, (i32 16))),
+ (t2SMULBT rGPR:$Rn, rGPR:$Rm)>;
+def : Thumb2DSPPat<(mul (sra rGPR:$Rn, (i32 16)), sext_16_node:$Rm),
+ (t2SMULTB rGPR:$Rn, rGPR:$Rm)>;
+
+class T2FourRegSMLA<bits<3> op22_20, bits<2> op5_4, string opc,
+ list<dag> pattern>
+ : T2FourReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMUL16,
+ opc, "\t$Rd, $Rn, $Rm, $Ra", pattern>,
+ Requires<[IsThumb2, HasDSP, UseMulOps]> {
let Inst{31-27} = 0b11111;
let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
+ let Inst{22-20} = op22_20;
let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b10;
- }
-
- def TT : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16,
- !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm, $Ra",
- [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sra rGPR:$Rn, (i32 16)),
- (sra rGPR:$Rm, (i32 16)))))]>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b001;
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b11;
- }
-
- def WB : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16,
- !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm, $Ra",
- []>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b011;
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b00;
- }
-
- def WT : T2FourReg<
- (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16,
- !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm, $Ra",
- []>,
- Requires<[IsThumb2, HasDSP, UseMulOps]> {
- let Inst{31-27} = 0b11111;
- let Inst{26-23} = 0b0110;
- let Inst{22-20} = 0b011;
- let Inst{7-6} = 0b00;
- let Inst{5-4} = 0b01;
- }
-}
-
-defm t2SMUL : T2I_smul<"smul", mul>;
-defm t2SMLA : T2I_smla<"smla", mul>;
+ let Inst{5-4} = op5_4;
+}
+
+def t2SMLABB : T2FourRegSMLA<0b001, 0b00, "smlabb",
+ [(set rGPR:$Rd, (add rGPR:$Ra,
+ (mul (sext_inreg rGPR:$Rn, i16),
+ (sext_inreg rGPR:$Rm, i16))))]>;
+def t2SMLABT : T2FourRegSMLA<0b001, 0b01, "smlabt",
+ [(set rGPR:$Rd, (add rGPR:$Ra, (mul (sext_inreg rGPR:$Rn, i16),
+ (sra rGPR:$Rm, (i32 16)))))]>;
+def t2SMLATB : T2FourRegSMLA<0b001, 0b10, "smlatb",
+ [(set rGPR:$Rd, (add rGPR:$Ra, (mul (sra rGPR:$Rn, (i32 16)),
+ (sext_inreg rGPR:$Rm, i16))))]>;
+def t2SMLATT : T2FourRegSMLA<0b001, 0b11, "smlatt",
+ [(set rGPR:$Rd, (add rGPR:$Ra, (mul (sra rGPR:$Rn, (i32 16)),
+ (sra rGPR:$Rm, (i32 16)))))]>;
+def t2SMLAWB : T2FourRegSMLA<0b011, 0b00, "smlawb", []>;
+def t2SMLAWT : T2FourRegSMLA<0b011, 0b01, "smlawt", []>;
+
+def : Thumb2DSPMulPat<(add rGPR:$Ra, (mul sext_16_node:$Rn, sext_16_node:$Rm)),
+ (t2SMLABB rGPR:$Rn, rGPR:$Rm, rGPR:$Ra)>;
+def : Thumb2DSPMulPat<(add rGPR:$Ra,
+ (mul sext_16_node:$Rn, (sra rGPR:$Rm, (i32 16)))),
+ (t2SMLABT rGPR:$Rn, rGPR:$Rm, rGPR:$Ra)>;
+def : Thumb2DSPMulPat<(add rGPR:$Ra,
+ (mul (sra rGPR:$Rn, (i32 16)), sext_16_node:$Rm)),
+ (t2SMLATB rGPR:$Rn, rGPR:$Rm, rGPR:$Ra)>;
+
+class T2SMLAL<bits<3> op22_20, bits<4> op7_4, string opc, list<dag> pattern>
+ : T2FourReg_mac<1, op22_20, op7_4,
+ (outs rGPR:$Ra, rGPR:$Rd),
+ (ins rGPR:$Rn, rGPR:$Rm),
+ IIC_iMAC64, opc, "\t$Ra, $Rd, $Rn, $Rm", []>,
+ Requires<[IsThumb2, HasDSP]>;
// Halfword multiple accumulate long: SMLAL<x><y>
-def t2SMLALBB : T2FourReg_mac<1, 0b100, 0b1000, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlalbb", "\t$Ra, $Rd, $Rn, $Rm",
- [/* For disassembly only; pattern left blank */]>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLALBT : T2FourReg_mac<1, 0b100, 0b1001, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlalbt", "\t$Ra, $Rd, $Rn, $Rm",
- [/* For disassembly only; pattern left blank */]>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLALTB : T2FourReg_mac<1, 0b100, 0b1010, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaltb", "\t$Ra, $Rd, $Rn, $Rm",
- [/* For disassembly only; pattern left blank */]>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLALTT : T2FourReg_mac<1, 0b100, 0b1011, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaltt", "\t$Ra, $Rd, $Rn, $Rm",
- [/* For disassembly only; pattern left blank */]>,
- Requires<[IsThumb2, HasDSP]>;
-
-// Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD
-def t2SMUAD: T2ThreeReg_mac<
- 0, 0b010, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm),
- IIC_iMAC32, "smuad", "\t$Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{15-12} = 0b1111;
-}
-def t2SMUADX:T2ThreeReg_mac<
- 0, 0b010, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm),
- IIC_iMAC32, "smuadx", "\t$Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]> {
+def t2SMLALBB : T2SMLAL<0b100, 0b1000, "smlalbb", []>;
+def t2SMLALBT : T2SMLAL<0b100, 0b1001, "smlalbt", []>;
+def t2SMLALTB : T2SMLAL<0b100, 0b1010, "smlaltb", []>;
+def t2SMLALTT : T2SMLAL<0b100, 0b1011, "smlaltt", []>;
+
+class T2DualHalfMul<bits<3> op22_20, bits<4> op7_4, string opc>
+ : T2ThreeReg_mac<0, op22_20, op7_4,
+ (outs rGPR:$Rd),
+ (ins rGPR:$Rn, rGPR:$Rm),
+ IIC_iMAC32, opc, "\t$Rd, $Rn, $Rm", []>,
+ Requires<[IsThumb2, HasDSP]> {
let Inst{15-12} = 0b1111;
}
-def t2SMUSD: T2ThreeReg_mac<
- 0, 0b100, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm),
- IIC_iMAC32, "smusd", "\t$Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{15-12} = 0b1111;
-}
-def t2SMUSDX:T2ThreeReg_mac<
- 0, 0b100, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm),
- IIC_iMAC32, "smusdx", "\t$Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]> {
- let Inst{15-12} = 0b1111;
-}
-def t2SMLAD : T2FourReg_mac<
- 0, 0b010, 0b0000, (outs rGPR:$Rd),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlad",
- "\t$Rd, $Rn, $Rm, $Ra", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLADX : T2FourReg_mac<
- 0, 0b010, 0b0001, (outs rGPR:$Rd),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smladx",
- "\t$Rd, $Rn, $Rm, $Ra", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLSD : T2FourReg_mac<0, 0b100, 0b0000, (outs rGPR:$Rd),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlsd",
- "\t$Rd, $Rn, $Rm, $Ra", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLSDX : T2FourReg_mac<0, 0b100, 0b0001, (outs rGPR:$Rd),
- (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlsdx",
- "\t$Rd, $Rn, $Rm, $Ra", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLALD : T2FourReg_mac<1, 0b100, 0b1100, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC64, "smlald",
- "\t$Ra, $Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLALDX : T2FourReg_mac<1, 0b100, 0b1101, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaldx",
- "\t$Ra, $Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLSLD : T2FourReg_mac<1, 0b101, 0b1100, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlsld",
- "\t$Ra, $Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]>;
-def t2SMLSLDX : T2FourReg_mac<1, 0b101, 0b1101, (outs rGPR:$Ra,rGPR:$Rd),
- (ins rGPR:$Rm,rGPR:$Rn), IIC_iMAC64, "smlsldx",
- "\t$Ra, $Rd, $Rn, $Rm", []>,
- Requires<[IsThumb2, HasDSP]>;
+
+// Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD
+def t2SMUAD: T2DualHalfMul<0b010, 0b0000, "smuad">;
+def t2SMUADX: T2DualHalfMul<0b010, 0b0001, "smuadx">;
+def t2SMUSD: T2DualHalfMul<0b100, 0b0000, "smusd">;
+def t2SMUSDX: T2DualHalfMul<0b100, 0b0001, "smusdx">;
+
+class T2DualHalfMulAdd<bits<3> op22_20, bits<4> op7_4, string opc>
+ : T2FourReg_mac<0, op22_20, op7_4,
+ (outs rGPR:$Rd),
+ (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra),
+ IIC_iMAC32, opc, "\t$Rd, $Rn, $Rm, $Ra", []>,
+ Requires<[IsThumb2, HasDSP]>;
+
+def t2SMLAD : T2DualHalfMulAdd<0b010, 0b0000, "smlad">;
+def t2SMLADX : T2DualHalfMulAdd<0b010, 0b0001, "smladx">;
+def t2SMLSD : T2DualHalfMulAdd<0b100, 0b0000, "smlsd">;
+def t2SMLSDX : T2DualHalfMulAdd<0b100, 0b0001, "smlsdx">;
+
+class T2DualHalfMulAddLong<bits<3> op22_20, bits<4> op7_4, string opc>
+ : T2FourReg_mac<1, op22_20, op7_4,
+ (outs rGPR:$Ra, rGPR:$Rd),
+ (ins rGPR:$Rn, rGPR:$Rm),
+ IIC_iMAC64, opc, "\t$Ra, $Rd, $Rn, $Rm", []>,
+ Requires<[IsThumb2, HasDSP]>;
+
+def t2SMLALD : T2DualHalfMulAddLong<0b100, 0b1100, "smlald">;
+def t2SMLALDX : T2DualHalfMulAddLong<0b100, 0b1101, "smlaldx">;
+def t2SMLSLD : T2DualHalfMulAddLong<0b101, 0b1100, "smlsld">;
+def t2SMLSLDX : T2DualHalfMulAddLong<0b101, 0b1101, "smlsldx">;
//===----------------------------------------------------------------------===//
// Division Instructions.
@@ -3545,7 +3381,9 @@ def t2B : T2I<(outs), (ins thumb_br_target:$target), IIC_Br,
}
let Size = 4, isNotDuplicable = 1, isIndirectBranch = 1 in {
-def t2BR_JT : t2PseudoInst<(outs),
+
+// available in both v8-M.Baseline and Thumb2 targets
+def t2BR_JT : t2basePseudoInst<(outs),
(ins GPR:$target, GPR:$index, i32imm:$jt),
0, IIC_Br,
[(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt)]>,
@@ -3645,6 +3483,7 @@ def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
// Branch and Exchange Jazelle -- for disassembly only
// Rm = Inst{19-16}
+let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in
def t2BXJ : T2I<(outs), (ins GPRnopc:$func), NoItinerary, "bxj", "\t$func", []>,
Sched<[WriteBr]>, Requires<[IsThumb2, IsNotMClass]> {
bits<4> func;
@@ -3753,6 +3592,7 @@ def t2DBG : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "dbg", "\t$opt",
// Secure Monitor Call is a system instruction.
// Option = Inst{19-16}
+let isCall = 1, Uses = [SP] in
def t2SMC : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "smc", "\t$opt",
[]>, Requires<[IsThumb2, HasTrustZone]> {
let Inst{31-27} = 0b11110;
@@ -3809,6 +3649,7 @@ def : t2InstAlias<"srsia${p} $mode", (t2SRSIA imm0_31:$mode, pred:$p)>;
def : t2InstAlias<"srsia${p} $mode!", (t2SRSIA_UPD imm0_31:$mode, pred:$p)>;
// Return From Exception is a system instruction.
+let isReturn = 1, isBarrier = 1, isTerminator = 1, Defs = [PC] in
class T2RFE<bits<12> op31_20, dag oops, dag iops, InstrItinClass itin,
string opc, string asm, list<dag> pattern>
: T2I<oops, iops, itin, opc, asm, pattern>,
@@ -4568,7 +4409,7 @@ def : t2InstAlias<"ldrsh${p} $Rt, $addr",
(t2LDRSHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>;
def : t2InstAlias<"ldr${p} $Rt, $addr",
- (t2LDRpci GPRnopc:$Rt, t2ldrlabel:$addr, pred:$p)>;
+ (t2LDRpci GPR:$Rt, t2ldrlabel:$addr, pred:$p)>;
def : t2InstAlias<"ldrb${p} $Rt, $addr",
(t2LDRBpci rGPR:$Rt, t2ldrlabel:$addr, pred:$p)>;
def : t2InstAlias<"ldrh${p} $Rt, $addr",
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrVFP.td b/contrib/llvm/lib/Target/ARM/ARMInstrVFP.td
index e29d265..e990486 100644
--- a/contrib/llvm/lib/Target/ARM/ARMInstrVFP.td
+++ b/contrib/llvm/lib/Target/ARM/ARMInstrVFP.td
@@ -624,7 +624,7 @@ def VCMPZH : AHuI<0b11101, 0b11, 0b0101, 0b01, 0,
def VCVTDS : ASuI<0b11101, 0b11, 0b0111, 0b11, 0,
(outs DPR:$Dd), (ins SPR:$Sm),
IIC_fpCVTDS, "vcvt", ".f64.f32\t$Dd, $Sm",
- [(set DPR:$Dd, (fextend SPR:$Sm))]> {
+ [(set DPR:$Dd, (fpextend SPR:$Sm))]> {
// Instruction operands.
bits<5> Dd;
bits<5> Sm;
@@ -641,7 +641,7 @@ def VCVTDS : ASuI<0b11101, 0b11, 0b0111, 0b11, 0,
// Special case encoding: bits 11-8 is 0b1011.
def VCVTSD : VFPAI<(outs SPR:$Sd), (ins DPR:$Dm), VFPUnaryFrm,
IIC_fpCVTSD, "vcvt", ".f32.f64\t$Sd, $Dm",
- [(set SPR:$Sd, (fround DPR:$Dm))]> {
+ [(set SPR:$Sd, (fpround DPR:$Dm))]> {
// Instruction operands.
bits<5> Sd;
bits<5> Dm;
@@ -838,7 +838,7 @@ multiclass vcvt_inst<string opc, bits<2> rm,
}
}
-defm VCVTA : vcvt_inst<"a", 0b00, frnd>;
+defm VCVTA : vcvt_inst<"a", 0b00, fround>;
defm VCVTN : vcvt_inst<"n", 0b01>;
defm VCVTP : vcvt_inst<"p", 0b10, fceil>;
defm VCVTM : vcvt_inst<"m", 0b11, ffloor>;
@@ -938,7 +938,7 @@ multiclass vrint_inst_anpm<string opc, bits<2> rm,
Requires<[HasFPARMv8,HasDPVFP]>;
}
-defm VRINTA : vrint_inst_anpm<"a", 0b00, frnd>;
+defm VRINTA : vrint_inst_anpm<"a", 0b00, fround>;
defm VRINTN : vrint_inst_anpm<"n", 0b01>;
defm VRINTP : vrint_inst_anpm<"p", 0b10, fceil>;
defm VRINTM : vrint_inst_anpm<"m", 0b11, ffloor>;
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp b/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp
new file mode 100644
index 0000000..2bdbe4f
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp
@@ -0,0 +1,109 @@
+//===- ARMInstructionSelector.cpp ----------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the InstructionSelector class for ARM.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#include "ARMInstructionSelector.h"
+#include "ARMRegisterBankInfo.h"
+#include "ARMSubtarget.h"
+#include "ARMTargetMachine.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "arm-isel"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+ARMInstructionSelector::ARMInstructionSelector(const ARMSubtarget &STI,
+ const ARMRegisterBankInfo &RBI)
+ : InstructionSelector(), TII(*STI.getInstrInfo()),
+ TRI(*STI.getRegisterInfo()), RBI(RBI) {}
+
+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;
+ assert(RegBank && "Can't get reg bank for virtual register");
+
+ const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
+ (void)DstSize;
+ unsigned SrcReg = I.getOperand(1).getReg();
+ const unsigned SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI);
+ (void)SrcSize;
+ assert((DstSize == SrcSize ||
+ // Copies are a means to setup initial types, the number of
+ // bits may not exactly match.
+ (TargetRegisterInfo::isPhysicalRegister(SrcReg) &&
+ DstSize <= SrcSize)) &&
+ "Copy with different width?!");
+
+ assert(RegBank->getID() == ARM::GPRRegBankID && "Unsupported reg bank");
+ const TargetRegisterClass *RC = &ARM::GPRRegClass;
+
+ // 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");
+ return false;
+ }
+ return true;
+}
+
+bool ARMInstructionSelector::select(MachineInstr &I) const {
+ assert(I.getParent() && "Instruction should be in a basic block!");
+ assert(I.getParent()->getParent() && "Instruction should be in a function!");
+
+ auto &MBB = *I.getParent();
+ auto &MF = *MBB.getParent();
+ auto &MRI = MF.getRegInfo();
+
+ if (!isPreISelGenericOpcode(I.getOpcode())) {
+ if (I.isCopy())
+ return selectCopy(I, TII, MRI, TRI, RBI);
+
+ return true;
+ }
+
+ MachineInstrBuilder MIB{MF, I};
+
+ using namespace TargetOpcode;
+ switch (I.getOpcode()) {
+ case G_ADD:
+ I.setDesc(TII.get(ARM::ADDrr));
+ AddDefaultCC(AddDefaultPred(MIB));
+ break;
+ case G_FRAME_INDEX:
+ // Add 0 to the given frame index and hope it will eventually be folded into
+ // the user(s).
+ I.setDesc(TII.get(ARM::ADDri));
+ AddDefaultCC(AddDefaultPred(MIB.addImm(0)));
+ break;
+ case G_LOAD:
+ I.setDesc(TII.get(ARM::LDRi12));
+ AddDefaultPred(MIB.addImm(0));
+ break;
+ default:
+ return false;
+ }
+
+ return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+}
diff --git a/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.h b/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.h
new file mode 100644
index 0000000..5072cdd
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.h
@@ -0,0 +1,39 @@
+//===- ARMInstructionSelector ------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares the targeting of the InstructionSelector class for ARM.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_ARM_ARMINSTRUCTIONSELECTOR_H
+#define LLVM_LIB_TARGET_ARM_ARMINSTRUCTIONSELECTOR_H
+
+#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+
+namespace llvm {
+class ARMBaseInstrInfo;
+class ARMBaseRegisterInfo;
+class ARMBaseTargetMachine;
+class ARMRegisterBankInfo;
+class ARMSubtarget;
+
+class ARMInstructionSelector : public InstructionSelector {
+public:
+ ARMInstructionSelector(const ARMSubtarget &STI,
+ const ARMRegisterBankInfo &RBI);
+
+ virtual bool select(MachineInstr &I) const override;
+
+private:
+ const ARMBaseInstrInfo &TII;
+ const ARMBaseRegisterInfo &TRI;
+ const ARMRegisterBankInfo &RBI;
+};
+
+} // End llvm namespace.
+#endif
diff --git a/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
new file mode 100644
index 0000000..255ea4b
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
@@ -0,0 +1,44 @@
+//===- ARMLegalizerInfo.cpp --------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the Machinelegalizer class for ARM.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#include "ARMLegalizerInfo.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Target/TargetOpcodes.h"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+ARMLegalizerInfo::ARMLegalizerInfo() {
+ using namespace TargetOpcode;
+
+ const LLT p0 = LLT::pointer(0, 32);
+
+ const LLT s8 = LLT::scalar(8);
+ const LLT s16 = LLT::scalar(16);
+ const LLT s32 = LLT::scalar(32);
+
+ setAction({G_FRAME_INDEX, p0}, Legal);
+
+ setAction({G_LOAD, s32}, Legal);
+ setAction({G_LOAD, 1, p0}, Legal);
+
+ for (auto Ty : {s8, s16, s32})
+ setAction({G_ADD, Ty}, Legal);
+
+ computeTables();
+}
diff --git a/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.h b/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.h
new file mode 100644
index 0000000..ca3eea8
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.h
@@ -0,0 +1,29 @@
+//===- ARMLegalizerInfo ------------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares the targeting of the Machinelegalizer class for ARM.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_ARM_ARMMACHINELEGALIZER_H
+#define LLVM_LIB_TARGET_ARM_ARMMACHINELEGALIZER_H
+
+#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
+
+namespace llvm {
+
+class LLVMContext;
+
+/// This class provides the information for the target register banks.
+class ARMLegalizerInfo : public LegalizerInfo {
+public:
+ ARMLegalizerInfo();
+};
+} // End llvm namespace.
+#endif
diff --git a/contrib/llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/contrib/llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp
index 62d57f3..48ab491 100644
--- a/contrib/llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp
@@ -95,12 +95,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
- return ARM_LOAD_STORE_OPT_NAME;
- }
+ StringRef getPassName() const override { return ARM_LOAD_STORE_OPT_NAME; }
private:
/// A set of load/store MachineInstrs with same base register sorted by
@@ -562,7 +560,7 @@ void ARMLoadStoreOpt::moveLiveRegsBefore(const MachineBasicBlock &MBB,
MachineBasicBlock::const_iterator Before) {
// Initialize if we never queried in this block.
if (!LiveRegsValid) {
- LiveRegs.init(TRI);
+ LiveRegs.init(*TRI);
LiveRegs.addLiveOuts(MBB);
LiveRegPos = MBB.end();
LiveRegsValid = true;
@@ -834,7 +832,7 @@ MachineInstr *ARMLoadStoreOpt::MergeOpsUpdate(const MergeCandidate &Cand) {
assert(MO.isImplicit());
unsigned DefReg = MO.getReg();
- if (std::find(ImpDefs.begin(), ImpDefs.end(), DefReg) != ImpDefs.end())
+ if (is_contained(ImpDefs, DefReg))
continue;
// We can ignore cases where the super-reg is read and written.
if (MI->readsRegister(DefReg))
@@ -1851,7 +1849,7 @@ bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
if (MBB.empty()) return false;
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
- if (MBBI != MBB.begin() &&
+ if (MBBI != MBB.begin() && MBBI != MBB.end() &&
(MBBI->getOpcode() == ARM::BX_RET ||
MBBI->getOpcode() == ARM::tBX_RET ||
MBBI->getOpcode() == ARM::MOVPCLR)) {
@@ -1953,7 +1951,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &Fn) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return ARM_PREALLOC_LOAD_STORE_OPT_NAME;
}
diff --git a/contrib/llvm/lib/Target/ARM/ARMMCInstLower.cpp b/contrib/llvm/lib/Target/ARM/ARMMCInstLower.cpp
index 7429acd..07044b9 100644
--- a/contrib/llvm/lib/Target/ARM/ARMMCInstLower.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMMCInstLower.cpp
@@ -21,6 +21,9 @@
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCStreamer.h"
using namespace llvm;
@@ -85,6 +88,8 @@ bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
break;
case MachineOperand::MO_ConstantPoolIndex:
+ if (Subtarget->genExecuteOnly())
+ llvm_unreachable("execute-only should not generate constant pools");
MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
break;
case MachineOperand::MO_BlockAddress:
@@ -93,7 +98,7 @@ bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
case MachineOperand::MO_FPImmediate: {
APFloat Val = MO.getFPImm()->getValueAPF();
bool ignored;
- Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored);
+ Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &ignored);
MCOp = MCOperand::createFPImm(Val.convertToDouble());
break;
}
@@ -150,3 +155,71 @@ void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
}
}
}
+
+void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
+{
+ if (MI.getParent()->getParent()->getInfo<ARMFunctionInfo>()
+ ->isThumbFunction())
+ {
+ MI.emitError("An attempt to perform XRay instrumentation for a"
+ " Thumb function (not supported). Detected when emitting a sled.");
+ return;
+ }
+ static const int8_t NoopsInSledCount = 6;
+ // We want to emit the following pattern:
+ //
+ // .Lxray_sled_N:
+ // ALIGN
+ // B #20
+ // ; 6 NOP instructions (24 bytes)
+ // .tmpN
+ //
+ // We need the 24 bytes (6 instructions) because at runtime, we'd be patching
+ // over the full 28 bytes (7 instructions) with the following pattern:
+ //
+ // PUSH{ r0, lr }
+ // MOVW r0, #<lower 16 bits of function ID>
+ // MOVT r0, #<higher 16 bits of function ID>
+ // MOVW ip, #<lower 16 bits of address of __xray_FunctionEntry/Exit>
+ // MOVT ip, #<higher 16 bits of address of __xray_FunctionEntry/Exit>
+ // BLX ip
+ // POP{ r0, lr }
+ //
+ OutStreamer->EmitCodeAlignment(4);
+ auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
+ OutStreamer->EmitLabel(CurSled);
+ auto Target = OutContext.createTempSymbol();
+
+ // Emit "B #20" instruction, which jumps over the next 24 bytes (because
+ // register pc is 8 bytes ahead of the jump instruction by the moment CPU
+ // is executing it).
+ // By analogy to ARMAsmPrinter::emitPseudoExpansionLowering() |case ARM::B|.
+ // It is not clear why |addReg(0)| is needed (the last operand).
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
+ .addImm(ARMCC::AL).addReg(0));
+
+ MCInst Noop;
+ Subtarget->getInstrInfo()->getNoopForElfTarget(Noop);
+ for (int8_t I = 0; I < NoopsInSledCount; I++)
+ {
+ OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
+ }
+
+ OutStreamer->EmitLabel(Target);
+ recordSled(CurSled, MI, Kind);
+}
+
+void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
+{
+ EmitSled(MI, SledKind::FUNCTION_ENTER);
+}
+
+void ARMAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI)
+{
+ EmitSled(MI, SledKind::FUNCTION_EXIT);
+}
+
+void ARMAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI)
+{
+ EmitSled(MI, SledKind::TAIL_CALL);
+}
diff --git a/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp
index b6dee9f..50d8f09 100644
--- a/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.cpp
@@ -11,14 +11,14 @@
using namespace llvm;
-void ARMFunctionInfo::anchor() { }
+void ARMFunctionInfo::anchor() {}
ARMFunctionInfo::ARMFunctionInfo(MachineFunction &MF)
: isThumb(MF.getSubtarget<ARMSubtarget>().isThumb()),
hasThumb2(MF.getSubtarget<ARMSubtarget>().hasThumb2()),
- StByValParamsPadding(0), ArgRegsSaveSize(0), HasStackFrame(false),
- RestoreSPFromFP(false), LRSpilledForFarJump(false),
+ StByValParamsPadding(0), ArgRegsSaveSize(0), ReturnRegsCount(0),
+ HasStackFrame(false), RestoreSPFromFP(false), LRSpilledForFarJump(false),
FramePtrSpillOffset(0), GPRCS1Offset(0), GPRCS2Offset(0), DPRCSOffset(0),
- GPRCS1Size(0), GPRCS2Size(0), DPRCSSize(0),
- PICLabelUId(0), VarArgsFrameIndex(0), HasITBlocks(false),
- ArgumentStackSize(0), IsSplitCSR(false) {}
+ GPRCS1Size(0), GPRCS2Size(0), DPRCSSize(0), PICLabelUId(0),
+ VarArgsFrameIndex(0), HasITBlocks(false), ArgumentStackSize(0),
+ IsSplitCSR(false), PromotedGlobalsIncrease(0) {}
diff --git a/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h b/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
index f714972..8c485e8 100644
--- a/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
+++ b/contrib/llvm/lib/Target/ARM/ARMMachineFunctionInfo.h
@@ -121,6 +121,12 @@ class ARMFunctionInfo : public MachineFunctionInfo {
/// copies.
bool IsSplitCSR;
+ /// Globals that have had their storage promoted into the constant pool.
+ SmallPtrSet<const GlobalVariable*,2> PromotedGlobals;
+
+ /// The amount the literal pool has been increasedby due to promoted globals.
+ int PromotedGlobalsIncrease;
+
public:
ARMFunctionInfo() :
isThumb(false),
@@ -131,7 +137,8 @@ public:
FramePtrSpillOffset(0), GPRCS1Offset(0), GPRCS2Offset(0), DPRCSOffset(0),
GPRCS1Size(0), GPRCS2Size(0), DPRCSAlignGapSize(0), DPRCSSize(0),
NumAlignedDPRCS2Regs(0), PICLabelUId(0),
- VarArgsFrameIndex(0), HasITBlocks(false), IsSplitCSR(false) {}
+ VarArgsFrameIndex(0), HasITBlocks(false), IsSplitCSR(false),
+ PromotedGlobalsIncrease(0) {}
explicit ARMFunctionInfo(MachineFunction &MF);
@@ -226,6 +233,22 @@ public:
}
return It;
}
+
+ /// Indicate to the backend that \c GV has had its storage changed to inside
+ /// a constant pool. This means it no longer needs to be emitted as a
+ /// global variable.
+ void markGlobalAsPromotedToConstantPool(const GlobalVariable *GV) {
+ PromotedGlobals.insert(GV);
+ }
+ SmallPtrSet<const GlobalVariable*, 2>& getGlobalsPromotedToConstantPool() {
+ return PromotedGlobals;
+ }
+ int getPromotedConstpoolIncrease() const {
+ return PromotedGlobalsIncrease;
+ }
+ void setPromotedConstpoolIncrease(int Sz) {
+ PromotedGlobalsIncrease = Sz;
+ }
};
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/ARM/ARMOptimizeBarriersPass.cpp b/contrib/llvm/lib/Target/ARM/ARMOptimizeBarriersPass.cpp
index 73dcb96..581d5fe 100644
--- a/contrib/llvm/lib/Target/ARM/ARMOptimizeBarriersPass.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMOptimizeBarriersPass.cpp
@@ -29,12 +29,10 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
- return "optimise barriers pass";
- }
+ StringRef getPassName() const override { return "optimise barriers pass"; }
};
char ARMOptimizeBarriersPass::ID = 0;
}
diff --git a/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp
new file mode 100644
index 0000000..324087d
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp
@@ -0,0 +1,150 @@
+//===- ARMRegisterBankInfo.cpp -----------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the targeting of the RegisterBankInfo class for ARM.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#include "ARMRegisterBankInfo.h"
+#include "ARMInstrInfo.h" // For the register classes
+#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
+#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "You shouldn't build this"
+#endif
+
+// FIXME: TableGen this.
+// If it grows too much and TableGen still isn't ready to do the job, extract it
+// into an ARMGenRegisterBankInfo.def (similar to AArch64).
+namespace llvm {
+namespace ARM {
+const uint32_t GPRCoverageData[] = {
+ // Classes 0-31
+ (1u << ARM::GPRRegClassID) | (1u << ARM::GPRwithAPSRRegClassID) |
+ (1u << ARM::GPRnopcRegClassID) | (1u << ARM::rGPRRegClassID) |
+ (1u << ARM::hGPRRegClassID) | (1u << ARM::tGPRRegClassID) |
+ (1u << ARM::GPRnopc_and_hGPRRegClassID) |
+ (1u << ARM::hGPR_and_rGPRRegClassID) | (1u << ARM::tcGPRRegClassID) |
+ (1u << ARM::tGPR_and_tcGPRRegClassID) | (1u << ARM::GPRspRegClassID) |
+ (1u << ARM::hGPR_and_tcGPRRegClassID),
+ // Classes 32-63
+ 0,
+ // Classes 64-96
+ 0,
+ // FIXME: Some of the entries below this point can be safely removed once
+ // this is tablegenerated. It's only needed because of the hardcoded
+ // register class limit.
+ // Classes 97-128
+ 0,
+ // Classes 129-160
+ 0,
+ // Classes 161-192
+ 0,
+ // Classes 193-224
+ 0,
+};
+
+RegisterBank GPRRegBank(ARM::GPRRegBankID, "GPRB", 32, ARM::GPRCoverageData);
+RegisterBank *RegBanks[] = {&GPRRegBank};
+
+RegisterBankInfo::PartialMapping GPRPartialMapping{0, 32, GPRRegBank};
+
+RegisterBankInfo::ValueMapping ValueMappings[] = {
+ {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}, {&GPRPartialMapping, 1}};
+} // end namespace arm
+} // end namespace llvm
+
+ARMRegisterBankInfo::ARMRegisterBankInfo(const TargetRegisterInfo &TRI)
+ : RegisterBankInfo(ARM::RegBanks, ARM::NumRegisterBanks) {
+ static bool AlreadyInit = false;
+ // We have only one set of register banks, whatever the subtarget
+ // is. Therefore, the initialization of the RegBanks table should be
+ // done only once. Indeed the table of all register banks
+ // (ARM::RegBanks) is unique in the compiler. At some point, it
+ // will get tablegen'ed and the whole constructor becomes empty.
+ if (AlreadyInit)
+ return;
+ AlreadyInit = true;
+
+ const RegisterBank &RBGPR = getRegBank(ARM::GPRRegBankID);
+ (void)RBGPR;
+ assert(&ARM::GPRRegBank == &RBGPR && "The order in RegBanks is messed up");
+
+ // Initialize the GPR bank.
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRwithAPSRRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnopcRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::rGPRRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPRRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPR_and_tcGPRRegClassID)) &&
+ "Subclass not added?");
+ assert(RBGPR.getSize() == 32 && "GPRs should hold up to 32-bit");
+}
+
+const RegisterBank &ARMRegisterBankInfo::getRegBankFromRegClass(
+ const TargetRegisterClass &RC) const {
+ using namespace ARM;
+
+ switch (RC.getID()) {
+ case GPRRegClassID:
+ case tGPR_and_tcGPRRegClassID:
+ return getRegBank(ARM::GPRRegBankID);
+ default:
+ llvm_unreachable("Unsupported register kind");
+ }
+
+ llvm_unreachable("Switch should handle all register classes");
+}
+
+RegisterBankInfo::InstructionMapping
+ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
+ auto Opc = MI.getOpcode();
+
+ // Try the default logic for non-generic instructions that are either copies
+ // or already have some operands assigned to banks.
+ if (!isPreISelGenericOpcode(Opc)) {
+ InstructionMapping Mapping = getInstrMappingImpl(MI);
+ if (Mapping.isValid())
+ return Mapping;
+ }
+
+ using namespace TargetOpcode;
+
+ unsigned NumOperands = MI.getNumOperands();
+ const ValueMapping *OperandsMapping = &ARM::ValueMappings[0];
+
+ switch (Opc) {
+ case G_ADD:
+ case G_LOAD:
+ // FIXME: We're abusing the fact that everything lives in a GPR for now; in
+ // the real world we would use different mappings.
+ OperandsMapping = &ARM::ValueMappings[0];
+ break;
+ case G_FRAME_INDEX:
+ OperandsMapping = getOperandsMapping({&ARM::ValueMappings[0], nullptr});
+ break;
+ default:
+ return InstructionMapping{};
+ }
+
+ return InstructionMapping{DefaultMappingID, /*Cost=*/1, OperandsMapping,
+ NumOperands};
+}
diff --git a/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.h b/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.h
new file mode 100644
index 0000000..773920e
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.h
@@ -0,0 +1,41 @@
+//===- ARMRegisterBankInfo ---------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares the targeting of the RegisterBankInfo class for ARM.
+/// \todo This should be generated by TableGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_ARM_ARMREGISTERBANKINFO_H
+#define LLVM_LIB_TARGET_ARM_ARMREGISTERBANKINFO_H
+
+#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
+
+namespace llvm {
+
+class TargetRegisterInfo;
+
+namespace ARM {
+enum {
+ GPRRegBankID = 0, // General purpose registers
+ NumRegisterBanks,
+};
+} // end namespace ARM
+
+/// This class provides the information for the target register banks.
+class ARMRegisterBankInfo final : public RegisterBankInfo {
+public:
+ ARMRegisterBankInfo(const TargetRegisterInfo &TRI);
+
+ const RegisterBank &
+ getRegBankFromRegClass(const TargetRegisterClass &RC) const override;
+
+ InstructionMapping getInstrMapping(const MachineInstr &MI) const override;
+};
+} // End llvm namespace.
+#endif
diff --git a/contrib/llvm/lib/Target/ARM/ARMSchedule.td b/contrib/llvm/lib/Target/ARM/ARMSchedule.td
index 47a9931..b7d2d34 100644
--- a/contrib/llvm/lib/Target/ARM/ARMSchedule.td
+++ b/contrib/llvm/lib/Target/ARM/ARMSchedule.td
@@ -364,3 +364,4 @@ include "ARMScheduleV6.td"
include "ARMScheduleA8.td"
include "ARMScheduleA9.td"
include "ARMScheduleSwift.td"
+include "ARMScheduleR52.td"
diff --git a/contrib/llvm/lib/Target/ARM/ARMScheduleR52.td b/contrib/llvm/lib/Target/ARM/ARMScheduleR52.td
new file mode 100644
index 0000000..1b40742
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARM/ARMScheduleR52.td
@@ -0,0 +1,983 @@
+//==- ARMScheduleR52.td - Cortex-R52 Scheduling Definitions -*- tablegen -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SchedRead/Write data for the ARM Cortex-R52 processor.
+//
+//===----------------------------------------------------------------------===//
+
+// ===---------------------------------------------------------------------===//
+// The Cortex-R52 is an in-order pipelined superscalar microprocessor with
+// a 8 stage pipeline. It can issue maximum two instructions in each cycle.
+// There are two ALUs, one LDST, one MUL and a non-pipelined integer DIV.
+// A number of forwarding paths enable results of computations to be input
+// to subsequent operations before they are written to registers.
+// This scheduler is a MachineScheduler. See TargetSchedule.td for details.
+
+def CortexR52Model : SchedMachineModel {
+ let MicroOpBufferSize = 0; // R52 is in-order processor
+ let IssueWidth = 2; // 2 micro-ops dispatched per cycle
+ let LoadLatency = 1; // Optimistic, assuming no misses
+ let MispredictPenalty = 8; // A branch direction mispredict, including PFU
+ let PostRAScheduler = 1; // Enable PostRA scheduler pass.
+ let CompleteModel = 0; // Covers instructions applicable to cortex-r52.
+}
+
+
+//===----------------------------------------------------------------------===//
+// Define each kind of processor resource and number available.
+
+// Modeling each pipeline as a ProcResource using the BufferSize = 0 since
+// Cortex-R52 is an in-order processor.
+
+def R52UnitALU : ProcResource<2> { let BufferSize = 0; } // Int ALU
+def R52UnitMAC : ProcResource<1> { let BufferSize = 0; } // Int MAC
+def R52UnitDiv : ProcResource<1> { let BufferSize = 0; } // Int Division
+def R52UnitLd : ProcResource<1> { let BufferSize = 0; } // Load/Store
+def R52UnitB : ProcResource<1> { let BufferSize = 0; } // Branch
+def R52UnitFPALU : ProcResource<2> { let BufferSize = 0; } // FP ALU
+def R52UnitFPMUL : ProcResource<2> { let BufferSize = 0; } // FP MUL
+def R52UnitFPDIV : ProcResource<1> { let BufferSize = 0; } // FP DIV
+
+// Cortex-R52 specific SchedReads
+def R52Read_ISS : SchedRead;
+def R52Read_EX1 : SchedRead;
+def R52Read_EX2 : SchedRead;
+def R52Read_WRI : SchedRead;
+def R52Read_F0 : SchedRead; // F0 maps to ISS stage of integer pipe
+def R52Read_F1 : SchedRead;
+def R52Read_F2 : SchedRead;
+
+
+//===----------------------------------------------------------------------===//
+// Subtarget-specific SchedWrite types which map ProcResources and set latency.
+
+let SchedModel = CortexR52Model in {
+
+// ALU - Write occurs in Late EX2 (independent of whether shift was required)
+def : WriteRes<WriteALU, [R52UnitALU]> { let Latency = 3; }
+def : WriteRes<WriteALUsi, [R52UnitALU]> { let Latency = 3; }
+def : WriteRes<WriteALUsr, [R52UnitALU]> { let Latency = 3; }
+def : WriteRes<WriteALUSsr, [R52UnitALU]> { let Latency = 3; }
+
+// Compares
+def : WriteRes<WriteCMP, [R52UnitALU]> { let Latency = 0; }
+def : WriteRes<WriteCMPsi, [R52UnitALU]> { let Latency = 0; }
+def : WriteRes<WriteCMPsr, [R52UnitALU]> { let Latency = 0; }
+
+// Div - may stall 0-9 cycles depending on input (i.e. WRI+(0-9)/2)
+def : WriteRes<WriteDiv, [R52UnitDiv]> {
+ let Latency = 8; let ResourceCycles = [8]; // not pipelined
+}
+
+// Loads
+def : WriteRes<WriteLd, [R52UnitLd]> { let Latency = 4; }
+def : WriteRes<WritePreLd, [R52UnitLd]> { let Latency = 4; }
+
+// Branches - LR written in Late EX2
+def : WriteRes<WriteBr, [R52UnitB]> { let Latency = 0; }
+def : WriteRes<WriteBrL, [R52UnitB]> { let Latency = 0; }
+def : WriteRes<WriteBrTbl, [R52UnitALU]> { let Latency = 0; }
+
+// Misc
+def : WriteRes<WriteNoop, []> { let Latency = 0; let NumMicroOps = 0; }
+def : WriteRes<WriteCvtFP, [R52UnitALU]> { let Latency = 3; }
+
+def : ReadAdvance<ReadALU, 1>; // Operand needed in EX1 stage
+def : ReadAdvance<ReadALUsr, 0>; // Shift operands needed in ISS
+
+
+//===----------------------------------------------------------------------===//
+// Subtarget-specific SchedReadWrites.
+
+// Forwarding information - based on when an operand is read
+def : ReadAdvance<R52Read_ISS, 0>;
+def : ReadAdvance<R52Read_EX1, 1>;
+def : ReadAdvance<R52Read_EX2, 2>;
+def : ReadAdvance<R52Read_F0, 0>;
+def : ReadAdvance<R52Read_F1, 1>;
+def : ReadAdvance<R52Read_F2, 2>;
+
+
+// Cortex-R52 specific SchedWrites for use with InstRW
+def R52WriteMAC : SchedWriteRes<[R52UnitMAC]> { let Latency = 4; }
+def R52WriteDIV : SchedWriteRes<[R52UnitDiv]> {
+ let Latency = 8; let ResourceCycles = [8]; // not pipelined
+}
+def R52WriteLd : SchedWriteRes<[R52UnitLd]> { let Latency = 4; }
+def R52WriteST : SchedWriteRes<[R52UnitLd]> { let Latency = 4; }
+def R52WriteAdr : SchedWriteRes<[]> { let Latency = 0; }
+def R52WriteCC : SchedWriteRes<[]> { let Latency = 0; }
+def R52WriteALU_EX1 : SchedWriteRes<[R52UnitALU]> { let Latency = 2; }
+def R52WriteALU_EX2 : SchedWriteRes<[R52UnitALU]> { let Latency = 3; }
+def R52WriteALU_WRI : SchedWriteRes<[R52UnitALU]> { let Latency = 4; }
+
+def R52WriteNoRSRC_EX2 : SchedWriteRes<[]> { let Latency = 3; }
+def R52WriteNoRSRC_WRI : SchedWriteRes<[]> { let Latency = 4; }
+
+def R52WriteFPALU_F3 : SchedWriteRes<[R52UnitFPALU]> { let Latency = 4; }
+def R52Write2FPALU_F3 : SchedWriteRes<[R52UnitFPALU, R52UnitFPALU]> {
+ let Latency = 4;
+}
+def R52WriteFPALU_F4 : SchedWriteRes<[R52UnitFPALU]> { let Latency = 5; }
+def R52Write2FPALU_F4 : SchedWriteRes<[R52UnitFPALU, R52UnitFPALU]> {
+ let Latency = 5;
+}
+def R52WriteFPALU_F5 : SchedWriteRes<[R52UnitFPALU]> { let Latency = 6; }
+def R52Write2FPALU_F5 : SchedWriteRes<[R52UnitFPALU, R52UnitFPALU]> {
+ let Latency = 6;
+}
+def R52WriteFPMUL_F5 : SchedWriteRes<[R52UnitFPMUL]> { let Latency = 6; }
+def R52Write2FPMUL_F5 : SchedWriteRes<[R52UnitFPMUL, R52UnitFPMUL]> {
+ let Latency = 6;
+}
+def R52WriteFPMAC_F5 : SchedWriteRes<[R52UnitFPMUL, R52UnitFPALU]> {
+ let Latency = 11; // as it is internally two insns (MUL then ADD)
+}
+def R52Write2FPMAC_F5 : SchedWriteRes<[R52UnitFPMUL, R52UnitFPMUL,
+ R52UnitFPALU, R52UnitFPALU]> {
+ let Latency = 11;
+}
+
+def R52WriteFPLd_F4 : SchedWriteRes<[R52UnitLd]> { let Latency = 5; }
+def R52WriteFPST_F4 : SchedWriteRes<[R52UnitLd]> { let Latency = 5; }
+
+def R52WriteFPDIV_SP : SchedWriteRes<[R52UnitFPDIV]> {
+ let Latency = 7; // FP div takes fixed #cycles
+ let ResourceCycles = [7]; // is not pipelined
+ }
+def R52WriteFPDIV_DP : SchedWriteRes<[R52UnitFPDIV]> {
+ let Latency = 17;
+ let ResourceCycles = [17];
+}
+
+
+//===----------------------------------------------------------------------===//
+// Subtarget-specific - map operands to SchedReadWrites
+
+def : InstRW<[WriteALU], (instrs COPY)>;
+
+def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_ISS],
+ (instregex "SXTB", "SXTH", "SXTB16", "UXTB", "UXTH", "UXTB16",
+ "t2SXTB", "t2SXTH", "t2SXTB16", "t2UXTB", "t2UXTH", "t2UXTB16")>;
+
+def : InstRW<[R52WriteALU_EX1, R52Read_ISS],
+ (instregex "MOVCCi32imm", "MOVi32imm", "MOV_ga_dyn", "t2MOVCCi",
+ "t2MOVi", "t2MOV_ga_dyn")>;
+def : InstRW<[R52WriteALU_EX2, R52Read_EX1],
+ (instregex "MOV_ga_pcrel", "t2MOV_ga_pcrel")>;
+def : InstRW<[R52WriteLd,R52Read_ISS],
+ (instregex "MOV_ga_pcrel_ldr", "t2MOV_ga_pcrel_ldr")>;
+
+def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_EX1], (instregex "SEL", "t2SEL")>;
+
+def : InstRW< [R52WriteALU_EX2, R52Read_ISS, R52Read_ISS],
+ (instregex "BFC", "BFI", "UBFX", "SBFX", "(t|t2)BFC", "(t|t2)BFI",
+ "(t|t2)UBFX", "(t|t2)SBFX")>;
+
+// Saturating arithmetic
+def : InstRW< [R52WriteALU_WRI, R52Read_EX1, R52Read_EX1],
+ (instregex "QADD", "QSUB", "QDADD", "QDSUB", "SSAT", "SSAT16", "USAT",
+ "QADD8", "QADD16", "QSUB8", "QSUB16", "QASX", "QSAX",
+ "UQADD8", "UQADD16","UQSUB8","UQSUB16","UQASX","UQSAX", "t2QADD",
+ "t2QSUB", "t2QDADD", "t2QDSUB", "t2SSAT", "t2SSAT16", "t2USAT",
+ "t2QADD8", "t2QADD16", "t2QSUB8", "t2QSUB16", "t2QASX", "t2QSAX",
+ "t2UQADD8", "t2UQADD16","t2UQSUB8","t2UQSUB16","t2UQASX","t2UQSAX","t2ABS")>;
+
+// Parallel arithmetic
+def : InstRW< [R52WriteALU_EX2, R52Read_EX1, R52Read_EX1],
+ (instregex "SADD8", "SADD16", "SSUB8", "SSUB16", "SASX", "SSAX",
+ "UADD8", "UADD16", "USUB8", "USUB16", "UASX", "USAX", "t2SADD8",
+ "t2SADD16", "t2SSUB8", "t2SSUB16", "t2SASX", "t2SSAX", "t2UADD8",
+ "t2UADD16", "t2USUB8", "t2USUB16", "t2UASX", "t2USAX")>;
+
+// Flag setting.
+def : InstRW< [R52WriteALU_EX2, R52Read_EX1, R52Read_EX1],
+ (instregex "SHADD8", "SHADD16", "SHSUB8", "SHSUB16", "SHASX", "SHSAX",
+ "SXTAB", "SXTAB16", "SXTAH", "UHADD8", "UHADD16", "UHSUB8", "UHSUB16",
+ "UHASX", "UHSAX", "UXTAB", "UXTAB16", "UXTAH", "t2SHADD8", "t2SHADD16",
+ "t2SHSUB8", "t2SHSUB16", "t2SHASX", "t2SHSAX", "t2SXTAB", "t2SXTAB16",
+ "t2SXTAH", "t2UHADD8", "t2UHADD16", "t2UHSUB8", "t2UHSUB16", "t2UHASX",
+ "t2UHSAX", "t2UXTAB", "t2UXTAB16", "t2UXTAH")>;
+
+// Sum of Absolute Difference
+def : InstRW< [R52WriteALU_WRI, R52Read_ISS, R52Read_ISS, R52Read_ISS],
+ (instregex "USAD8", "t2USAD8", "tUSAD8","USADA8", "t2USADA8", "tUSADA8") >;
+
+// Integer Multiply
+def : InstRW<[R52WriteMAC, R52Read_ISS, R52Read_ISS],
+ (instregex "MULS", "MUL", "SMMUL", "SMMULR", "SMULBB", "SMULBT",
+ "SMULTB", "SMULTT", "SMULWB", "SMULWT", "SMUSD", "SMUSDXi", "t2MUL",
+ "t2SMMUL", "t2SMMULR", "t2SMULBB", "t2SMULBT", "t2SMULTB", "t2SMULTT",
+ "t2SMULWB", "t2SMULWT", "t2SMUSD")>;
+
+// Multiply Accumulate
+// 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",
+ "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",
+ "SMLALTB", "SMLALTT", "SMLALD", "SMLALDX", "SMLSLD", "SMLSLDX",
+ "UMAAL", "t2SMLALS", "t2UMLALS", "t2SMLAL", "t2UMLAL", "t2MLALBB",
+ "t2SMLALBT", "t2SMLALTB", "t2SMLALTT", "t2SMLALD", "t2SMLALDX",
+ "t2SMLSLD", "t2SMLSLDX", "t2UMAAL")>;
+
+def : InstRW <[R52WriteDIV, R52Read_ISS, R52Read_ISS],
+ (instregex "SDIV", "UDIV", "t2SDIV", "t2UDIV")>;
+
+// Loads (except POST) with SHL > 2, or ror, require 2 extra cycles.
+// However, that's non-trivial to specify, so we keep it uniform
+def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_ISS],
+ (instregex "LDR(i12|rs)$", "LDRB(i12|rs)$", "t2LDR(i8|i12|s|pci)",
+ "t2LDR(H|B)(i8|i12|s|pci)", "LDREX", "t2LDREX",
+ "tLDR[BH](r|i|spi|pci|pciASM)", "tLDR(r|i|spi|pci|pciASM)",
+ "LDRH$", "PICLDR$", "PICLDR(H|B)$", "LDRcp$",
+ "PICLDRS(H|B)$", "t2LDRS(H|B)(i|r|p|s)", "LDRS(H|B)$",
+ "t2LDRpci_pic", "tLDRS(B|H)", "t2LDRDi8", "LDRD$", "LDA", "t2LDA")>;
+def : InstRW<[R52WriteLd, R52WriteAdr, R52Read_ISS, R52Read_ISS],
+ (instregex "LD(RB|R)(_|T_)(POST|PRE)_(IMM|REG)", "LDRH(_PRE|_POST)",
+ "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",
+ "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",
+ "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",
+ "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")>;
+
+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")>;
+
+def : InstRW<[R52WriteALU_EX1],
+ (instregex "ADR", "MOVSi", "MOVSsi", "MOVST?i16*", "MVNS?s?i", "t2MOVS?si")>;
+
+def : InstRW<[R52WriteALU_EX1, R52Read_ISS], (instregex "ASRi", "RORS?i")>;
+def : InstRW<[R52WriteALU_EX1, R52Read_ISS, R52Read_ISS],
+ (instregex "ASRr", "RORS?r", "LSR", "LSL")>;
+
+def : InstRW<[R52WriteCC, R52Read_EX1], (instregex "CMPri", "CMNri")>;
+def : InstRW<[R52WriteCC, R52Read_EX1, R52Read_EX1], (instregex "CMPrr", "CMNzrr")>;
+def : InstRW<[R52WriteCC, R52Read_EX1, R52Read_ISS], (instregex "CMPrsi", "CMNzrsi")>;
+def : InstRW<[R52WriteCC, R52Read_EX1, R52Read_ISS, R52Read_ISS], (instregex "CMPrsr", "CMNzrsr")>;
+
+def : InstRW<[R52WriteALU_EX2, R52Read_ISS],
+ (instregex "t2LDC", "RBIT", "REV", "REV16", "REVSH", "RRX")>;
+
+def : InstRW<[R52WriteCC, R52Read_ISS], (instregex "TST")>;
+
+def : InstRW<[R52WriteLd], (instregex "MRS", "MRSbanked")>;
+def : InstRW<[R52WriteLd, R52Read_EX1], (instregex "MSR", "MSRbanked")>;
+
+//def : InstRW<[R52WriteLd, R52Read_ISS], (instregex "^LDRB?(_PRE_IMM|_POST_IMM)", "LDRrs")>;
+//def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_ISS], (instregex "^LDRB?_PRE_REG", "LDRB?rr")>;
+//def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_ISS], (instregex "^LDRB?_POST_REG")>;
+
+//def : InstRW<[R52WriteST, R52Read_ISS], (instregex "STRi12", "PICSTR")>;
+//def : InstRW<[R52WriteST, R52WriteAdr, R52Read_ISS, R52Read_EX2], (instregex "t2STRB?_PRE_REG", "STRB?_PRE_REG")>;
+//def : InstRW<[R52WriteST, R52WriteAdr, R52Read_ISS, R52Read_EX2], (instregex "t2STRB?_POST_REG", "STRB?_POST_REG")>;
+
+
+// Integer Load, Multiple.
+foreach Lat = 3-25 in {
+ def R52WriteILDM#Lat#Cy : SchedWriteRes<[R52UnitLd]> {
+ let Latency = Lat;
+ }
+ def R52WriteILDM#Lat#CyNo : SchedWriteRes<[]> {
+ let Latency = Lat;
+ let NumMicroOps = 0;
+ }
+}
+foreach NAddr = 1-16 in {
+ def R52ILDMAddr#NAddr#Pred : SchedPredicate<"TII->getNumLDMAddresses(*MI) == "#NAddr>;
+}
+def R52WriteILDMAddrNoWB : SchedWriteRes<[R52UnitLd]> { let Latency = 0; }
+def R52WriteILDMAddrWB : SchedWriteRes<[R52UnitLd]>;
+def R52WriteILDM : SchedWriteVariant<[
+ SchedVar<R52ILDMAddr2Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy]>,
+
+ SchedVar<R52ILDMAddr3Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy]>,
+ SchedVar<R52ILDMAddr4Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy]>,
+
+ SchedVar<R52ILDMAddr5Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy]>,
+ SchedVar<R52ILDMAddr6Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy]>,
+
+ SchedVar<R52ILDMAddr7Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy]>,
+ SchedVar<R52ILDMAddr8Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy]>,
+
+ SchedVar<R52ILDMAddr9Pred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy]>,
+ SchedVar<R52ILDMAddr10Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy]>,
+
+ SchedVar<R52ILDMAddr11Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy,
+ R52WriteILDM14Cy]>,
+ SchedVar<R52ILDMAddr12Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy,
+ R52WriteILDM14Cy, R52WriteILDM15Cy]>,
+
+ SchedVar<R52ILDMAddr13Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy,
+ R52WriteILDM14Cy, R52WriteILDM15Cy,
+ R52WriteILDM16Cy]>,
+ SchedVar<R52ILDMAddr14Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy,
+ R52WriteILDM14Cy, R52WriteILDM15Cy,
+ R52WriteILDM16Cy, R52WriteILDM17Cy]>,
+
+ SchedVar<R52ILDMAddr15Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy,
+ R52WriteILDM14Cy, R52WriteILDM15Cy,
+ R52WriteILDM16Cy, R52WriteILDM17Cy,
+ R52WriteILDM18Cy]>,
+ SchedVar<R52ILDMAddr15Pred,[R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6Cy, R52WriteILDM7Cy,
+ R52WriteILDM8Cy, R52WriteILDM9Cy,
+ R52WriteILDM10Cy, R52WriteILDM11Cy,
+ R52WriteILDM12Cy, R52WriteILDM13Cy,
+ R52WriteILDM14Cy, R52WriteILDM15Cy,
+ R52WriteILDM16Cy, R52WriteILDM17Cy,
+ R52WriteILDM18Cy, R52WriteILDM19Cy]>,
+
+// Unknown number of registers, just use resources for two registers.
+ SchedVar<NoSchedPred, [R52WriteILDM4Cy, R52WriteILDM5Cy,
+ R52WriteILDM6CyNo, R52WriteILDM7CyNo,
+ R52WriteILDM8CyNo, R52WriteILDM9CyNo,
+ R52WriteILDM10CyNo, R52WriteILDM11CyNo,
+ R52WriteILDM12CyNo, R52WriteILDM13CyNo,
+ R52WriteILDM14CyNo, R52WriteILDM15CyNo,
+ R52WriteILDM16CyNo, R52WriteILDM17CyNo,
+ R52WriteILDM18Cy, R52WriteILDM19Cy]>
+]> { let Variadic=1; }
+
+// Integer Store, Multiple
+def R52WriteIStIncAddr : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 4;
+ let NumMicroOps = 2;
+}
+foreach NumAddr = 1-16 in {
+ def R52WriteISTM#NumAddr : WriteSequence<[R52WriteIStIncAddr], NumAddr>;
+}
+def R52WriteISTM : SchedWriteVariant<[
+ SchedVar<R52ILDMAddr2Pred, [R52WriteISTM2]>,
+ SchedVar<R52ILDMAddr3Pred, [R52WriteISTM3]>,
+ SchedVar<R52ILDMAddr4Pred, [R52WriteISTM4]>,
+ SchedVar<R52ILDMAddr5Pred, [R52WriteISTM5]>,
+ SchedVar<R52ILDMAddr6Pred, [R52WriteISTM6]>,
+ SchedVar<R52ILDMAddr7Pred, [R52WriteISTM7]>,
+ SchedVar<R52ILDMAddr8Pred, [R52WriteISTM8]>,
+ SchedVar<R52ILDMAddr9Pred, [R52WriteISTM9]>,
+ SchedVar<R52ILDMAddr10Pred,[R52WriteISTM10]>,
+ SchedVar<R52ILDMAddr11Pred,[R52WriteISTM11]>,
+ SchedVar<R52ILDMAddr12Pred,[R52WriteISTM12]>,
+ SchedVar<R52ILDMAddr13Pred,[R52WriteISTM13]>,
+ SchedVar<R52ILDMAddr14Pred,[R52WriteISTM14]>,
+ SchedVar<R52ILDMAddr15Pred,[R52WriteISTM15]>,
+ SchedVar<R52ILDMAddr16Pred,[R52WriteISTM16]>,
+ // Unknow number of registers, just use resources for two registers.
+ SchedVar<NoSchedPred, [R52WriteISTM2]>
+]>;
+
+def : InstRW<[R52WriteILDM, R52Read_ISS],
+ (instregex "LDM(IA|DA|DB|IB)$", "t2LDM(IA|DA|DB|IB)$",
+ "(t|sys)LDM(IA|DA|DB|IB)$")>;
+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")>;
+
+// Integer Store, Single Element
+def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_EX2],
+ (instregex "PICSTR", "STR(i12|rs)", "STRB(i12|rs)", "STRH$", "STREX", "SRS", "t2SRS",
+ "t2SRSDB", "t2STREX", "t2STREXB", "t2STREXD", "t2STREXH", "t2STR(i12|i8|s)$",
+ "RFE", "t2RFE", "t2STR[BH](i12|i8|s)$", "tSTR[BH](i|r)", "tSTR(i|r)", "tSTRspi")>;
+
+def : InstRW<[R52WriteLd, R52WriteAdr, R52Read_ISS, R52Read_EX2],
+ (instregex "STR(B_|_|BT_|T_)(PRE_IMM|PRE_REG|POST_REG|POST_IMM)",
+ "STR(i|r)_preidx", "STRB(i|r)_preidx", "STRH_preidx", "STR(H_|HT_)(PRE|POST)",
+ "STR(BT|HT|T)", "t2STR_(PRE|POST)", "t2STR[BH]_(PRE|POST)",
+ "t2STR_preidx", "t2STR[BH]_preidx", "t2ST(RB|RH|R)T")>;
+
+// Integer Store, Dual
+def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_EX2],
+ (instregex "STRD$", "t2STRDi8", "STL", "t2STRD$", "t2STL")>;
+def : InstRW<[R52WriteLd, R52WriteAdr, R52Read_ISS, R52Read_EX2],
+ (instregex "(t2|t)STRD_(POST|PRE)", "STRD_(POST|PRE)")>;
+
+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")>;
+
+// LDRLIT pseudo instructions, they expand to LDR + PICADD
+def : InstRW<[R52WriteLd],
+ (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")>;
+
+
+
+//===----------------------------------------------------------------------===//
+// VFP, Floating Point Support
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1, R52Read_F1], (instregex "VABD(fd|hd)")>;
+def : InstRW<[R52Write2FPALU_F5, R52Read_F1, R52Read_F1], (instregex "VABD(fq|hq)")>;
+
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1], (instregex "VABS(D|S|H)")>;
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1], (instregex "VABS(fd|hd)")>;
+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<[R52Write2FPALU_F5, R52Read_F1, R52Read_F1], (instregex "(VADD|VSUB)(fq|hq)")>;
+
+def : InstRW<[R52WriteFPDIV_SP, R52Read_F0, R52Read_F0], (instregex "VDIV(S|H)")>;
+def : InstRW<[R52WriteFPDIV_DP, R52Read_F0, R52Read_F0], (instregex "VDIVD")>;
+
+def : InstRW<[R52WriteFPMAC_F5, R52Read_F1, R52Read_F1, R52Read_F1],
+ (instregex "(VFMA|VFMS|VFNMA|VFNMS)(D|H|S)")>;
+
+def : InstRW<[R52WriteFPLd_F4, R52Read_ISS, R52Read_F1], (instregex "VLDR")>;
+def : InstRW<[R52WriteFPST_F4, R52Read_ISS, R52Read_F1], (instregex "VSTR")>;
+
+
+//===----------------------------------------------------------------------===//
+// Neon Support
+
+// vector multiple load stores
+foreach NumAddr = 1-16 in {
+ def R52LMAddrPred#NumAddr :
+ SchedPredicate<"MI->getNumOperands() == "#NumAddr>;
+}
+foreach Lat = 1-32 in {
+ def R52WriteLM#Lat#Cy : SchedWriteRes<[]> {
+ let Latency = Lat;
+ }
+}
+foreach Num = 1-32 in { // reserve LdSt resource, no dual-issue
+ def R52ReserveLd#Num#Cy : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 0;
+ let NumMicroOps = Num;
+ let ResourceCycles = [Num];
+ }
+}
+def R52WriteVLDM : SchedWriteVariant<[
+ // 1 D reg
+ SchedVar<R52LMAddrPred1, [R52WriteLM5Cy,
+ R52ReserveLd5Cy]>,
+ SchedVar<R52LMAddrPred2, [R52WriteLM5Cy,
+ R52ReserveLd5Cy]>,
+
+ // 2 D reg
+ SchedVar<R52LMAddrPred3, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52ReserveLd6Cy]>,
+ SchedVar<R52LMAddrPred4, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52ReserveLd6Cy]>,
+
+ // 3 D reg
+ SchedVar<R52LMAddrPred5, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy,
+ R52ReserveLd4Cy]>,
+ SchedVar<R52LMAddrPred6, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy,
+ R52ReserveLd7Cy]>,
+
+ // 4 D reg
+ SchedVar<R52LMAddrPred7, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52ReserveLd8Cy]>,
+ SchedVar<R52LMAddrPred8, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52ReserveLd8Cy]>,
+
+ // 5 D reg
+ SchedVar<R52LMAddrPred9, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy,
+ R52ReserveLd9Cy]>,
+ SchedVar<R52LMAddrPred10, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy,
+ R52ReserveLd9Cy]>,
+
+ // 6 D reg
+ SchedVar<R52LMAddrPred11, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52ReserveLd10Cy]>,
+ SchedVar<R52LMAddrPred12, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52ReserveLd10Cy]>,
+
+ // 7 D reg
+ SchedVar<R52LMAddrPred13, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52WriteLM11Cy,
+ R52ReserveLd11Cy]>,
+ SchedVar<R52LMAddrPred14, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52WriteLM11Cy,
+ R52ReserveLd11Cy]>,
+
+ // 8 D reg
+ SchedVar<R52LMAddrPred14, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52WriteLM11Cy, R52WriteLM12Cy,
+ R52ReserveLd12Cy]>,
+ SchedVar<R52LMAddrPred15, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52WriteLM11Cy, R52WriteLM12Cy,
+ R52ReserveLd12Cy]>,
+ // unknown number of reg.
+ SchedVar<NoSchedPred, [R52WriteLM5Cy, R52WriteLM6Cy,
+ R52WriteLM7Cy, R52WriteLM8Cy,
+ R52WriteLM9Cy, R52WriteLM10Cy,
+ R52WriteLM11Cy, R52WriteLM12Cy,
+ R52ReserveLd5Cy]>
+]> { let Variadic=1;}
+
+// variable stores. Cannot dual-issue
+def R52WriteSTM5 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 5;
+ let NumMicroOps = 2;
+ let ResourceCycles = [1];
+}
+def R52WriteSTM6 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 6;
+ let NumMicroOps = 4;
+ let ResourceCycles = [2];
+}
+def R52WriteSTM7 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 7;
+ let NumMicroOps = 6;
+ let ResourceCycles = [3];
+}
+def R52WriteSTM8 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 8;
+ let NumMicroOps = 8;
+ let ResourceCycles = [4];
+}
+def R52WriteSTM9 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 9;
+ let NumMicroOps = 10;
+ let ResourceCycles = [5];
+}
+def R52WriteSTM10 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 10;
+ let NumMicroOps = 12;
+ let ResourceCycles = [6];
+}
+def R52WriteSTM11 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 11;
+ let NumMicroOps = 14;
+ let ResourceCycles = [7];
+}
+def R52WriteSTM12 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 12;
+ let NumMicroOps = 16;
+ let ResourceCycles = [8];
+}
+def R52WriteSTM13 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 13;
+ let NumMicroOps = 18;
+ let ResourceCycles = [9];
+}
+def R52WriteSTM14 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 14;
+ let NumMicroOps = 20;
+ let ResourceCycles = [10];
+}
+def R52WriteSTM15 : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 15;
+ let NumMicroOps = 22;
+ let ResourceCycles = [11];
+}
+
+def R52WriteSTM : SchedWriteVariant<[
+ SchedVar<R52LMAddrPred1, [R52WriteSTM5]>,
+ SchedVar<R52LMAddrPred2, [R52WriteSTM5]>,
+ SchedVar<R52LMAddrPred3, [R52WriteSTM6]>,
+ SchedVar<R52LMAddrPred4, [R52WriteSTM6]>,
+ SchedVar<R52LMAddrPred5, [R52WriteSTM7]>,
+ SchedVar<R52LMAddrPred6, [R52WriteSTM7]>,
+ SchedVar<R52LMAddrPred7, [R52WriteSTM8]>,
+ SchedVar<R52LMAddrPred8, [R52WriteSTM8]>,
+ SchedVar<R52LMAddrPred9, [R52WriteSTM9]>,
+ SchedVar<R52LMAddrPred10, [R52WriteSTM9]>,
+ SchedVar<R52LMAddrPred11, [R52WriteSTM10]>,
+ SchedVar<R52LMAddrPred12, [R52WriteSTM10]>,
+ SchedVar<R52LMAddrPred13, [R52WriteSTM11]>,
+ SchedVar<R52LMAddrPred14, [R52WriteSTM11]>,
+ SchedVar<R52LMAddrPred15, [R52WriteSTM12]>,
+ SchedVar<R52LMAddrPred16, [R52WriteSTM12]>,
+ // unknown number of registers, just use resources for two
+ SchedVar<NoSchedPred, [R52WriteSTM6]>
+]>;
+
+// Vector Load/Stores. Can issue only in slot-0. Can dual-issue with
+// another instruction in slot-1, but only in the last issue.
+def R52WriteVLD1Mem : SchedWriteRes<[R52UnitLd]> { let Latency = 5;}
+def R52WriteVLD2Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 6;
+ let NumMicroOps = 3;
+ let ResourceCycles = [2];
+}
+def R52WriteVLD3Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 7;
+ let NumMicroOps = 5;
+ let ResourceCycles = [3];
+}
+def R52WriteVLD4Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 8;
+ let NumMicroOps = 7;
+ let ResourceCycles = [4];
+}
+def R52WriteVST1Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 5;
+ let NumMicroOps = 1;
+ let ResourceCycles = [1];
+}
+def R52WriteVST2Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 6;
+ let NumMicroOps = 3;
+ let ResourceCycles = [2];
+}
+def R52WriteVST3Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 7;
+ let NumMicroOps = 5;
+ let ResourceCycles = [3];
+}
+def R52WriteVST4Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 8;
+ let NumMicroOps = 7;
+ let ResourceCycles = [4];
+}
+def R52WriteVST5Mem : SchedWriteRes<[R52UnitLd]> {
+ let Latency = 9;
+ let NumMicroOps = 9;
+ let ResourceCycles = [5];
+}
+
+
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "VABA(u|s)(v8i8|v4i16|v2i32)")>;
+def : InstRW<[R52Write2FPALU_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "VABA(u|s)(v16i8|v8i16|v4i32)")>;
+def : InstRW<[R52Write2FPALU_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "VABAL(u|s)(v8i16|v4i32|v2i64)")>;
+
+def : InstRW<[R52WriteFPALU_F4, R52Read_F1, R52Read_F1], (instregex "VABD(u|s)(v8i8|v4i16|v2i32)")>;
+def : InstRW<[R52Write2FPALU_F4, R52Read_F1, R52Read_F1], (instregex "VABD(u|s)(v16i8|v8i16|v4i32)")>;
+def : InstRW<[R52Write2FPALU_F4, R52Read_F1, R52Read_F1], (instregex "VABDL(u|s)(v16i8|v8i16|v4i32)")>;
+
+def : InstRW<[R52Write2FPALU_F4, R52Read_F1], (instregex "VABS(v16i8|v8i16|v4i32)")>;
+
+def : InstRW<[R52WriteFPALU_F4, R52Read_F2, R52Read_F2],
+ (instregex "(VADD|VSUB)(v8i8|v4i16|v2i32|v1i64)")>;
+def : InstRW<[R52Write2FPALU_F4, R52Read_F2, R52Read_F2],
+ (instregex "(VADD|VSUB)(v16i8|v8i16|v4i32|v2i64)")>;
+def : InstRW<[R52Write2FPALU_F5, R52Read_F2, R52Read_F2],
+ (instregex "(VADDHN|VRADDHN|VSUBHN|VRSUBHN)(v8i8|v4i16|v2i32)")>;
+
+def : InstRW<[R52Write2FPALU_F4, R52Read_F1, R52Read_F1],
+ (instregex "VADDL", "VADDW", "VSUBL", "VSUBW")>;
+
+def : InstRW<[R52WriteFPALU_F3, R52Read_F2, R52Read_F2], (instregex "(VAND|VBIC|VEOR)d")>;
+def : InstRW<[R52Write2FPALU_F3, R52Read_F2, R52Read_F2], (instregex "(VAND|VBIC|VEOR)q")>;
+
+def : InstRW<[R52WriteFPALU_F3, R52Read_F2], (instregex "VBICi(v4i16|v2i32)")>;
+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],
+ (instregex "VCVT", "VSITO", "VUITO", "VTO")>;
+
+def : InstRW<[R52WriteFPALU_F3, R52Read_ISS], (instregex "VDUP(8|16|32)d")>;
+def : InstRW<[R52Write2FPALU_F3, R52Read_ISS], (instregex "VDUP(8|16|32)q")>;
+def : InstRW<[R52WriteFPALU_F3, R52Read_F1], (instregex "VDUPLN(8|16|32)d")>;
+def : InstRW<[R52Write2FPALU_F3, R52Read_F1], (instregex "VDUPLN(8|16|32)q")>;
+
+def : InstRW<[R52WriteFPALU_F3, R52Read_F1, R52Read_F1], (instregex "VEXTd(8|16|32)", "VSEL")>;
+def : InstRW<[R52Write2FPALU_F3, R52Read_F1, R52Read_F1], (instregex "VEXTq(8|16|32|64)")>;
+
+def : InstRW<[R52WriteFPMAC_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "(VFMA|VFMS)(f|h)d")>;
+def : InstRW<[R52Write2FPMAC_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "(VFMA|VFMS)(f|h)q")>;
+
+def : InstRW<[R52WriteFPALU_F4, R52Read_F2, R52Read_F2], (instregex "(VHADD|VHSUB)(u|s)(v8i8|v4i16|v2i32)")>;
+def : InstRW<[R52Write2FPALU_F4, R52Read_F2, R52Read_F2], (instregex "(VHADD|VHSUB)(u|s)(v16i8|v8i16|v4i32)")>;
+
+def : InstRW<[R52WriteVLDM], (instregex "VLDM[SD](IA|DB)$")>;
+def : InstRW<[R52WriteFPALU_F4, R52Read_F1, R52Read_F1], (instregex "VMAX", "VMIN", "VPMAX", "VPMIN")>;
+def : InstRW<[R52WriteFPALU_F3, R52Read_F1, R52Read_F1], (instregex "VMOV", "VORR", "VORN", "VREV")>;
+def : InstRW<[R52WriteNoRSRC_WRI], (instregex "VMRS")>;
+def : InstRW<[R52WriteFPMUL_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "VMUL", "VNMUL", "VMLA")>;
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1], (instregex "VNEG")>;
+def : InstRW<[R52WriteFPALU_F4, R52Read_F1, R52Read_F1], (instregex "VPADDi")>;
+def : InstRW<[R52Write2FPALU_F4, R52Read_F1, R52Read_F1], (instregex "VPADAL", "VPADDL")>;
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1], (instregex "VQABS(v8i8|v4i16|v2i32|v1i64)")>;
+def : InstRW<[R52Write2FPALU_F5, R52Read_F1], (instregex "VQABS(v16i8|v8i16|v4i32|v2i64)")>;
+def : InstRW<[R52WriteFPALU_F5, R52Read_F2, R52Read_F2],
+ (instregex "(VQADD|VQSUB)(u|s)(v8i8|v4i16|v2i32|v1i64)")>;
+def : InstRW<[R52Write2FPALU_F5, R52Read_F2, R52Read_F2],
+ (instregex "(VQADD|VQSUB)(u|s)(v16i8|v8i16|v4i32|v2i64)")>;
+def : InstRW<[R52Write2FPMAC_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "VQDMLAL", "VQDMLSL")>;
+def : InstRW<[R52WriteFPMUL_F5, R52Read_F1, R52Read_F1, R52Read_F1], (instregex "VQDMUL","VQRDMUL")>;
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1, R52Read_F1],
+ (instregex "VQMOVN", "VQNEG", "VQSHL", "VQSHRN")>;
+def : InstRW<[R52WriteFPALU_F4, R52Read_F1, R52Read_F1], (instregex "VRSHL", "VRSHR", "VRSHRN", "VTB")>;
+def : InstRW<[R52WriteFPALU_F3, R52Read_F1, R52Read_F1], (instregex "VSWP", "VTRN", "VUZP", "VZIP")>;
+
+//---
+// VLDx. Vector Loads
+//---
+// 1-element structure load
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD1d(8|16|32|64)$")>;
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD1q(8|16|32|64)$")>;
+def : InstRW<[R52WriteVLD3Mem, R52Read_ISS], (instregex "VLD1d(8|16|32|64)T$")>;
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD1d(8|16|32|64)Q$")>;
+def : InstRW<[R52WriteVLD3Mem, R52Read_ISS], (instregex "VLD1d64TPseudo$")>;
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD1d64QPseudo$")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD1(LN|DUP)d(8|16|32)$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD1LNdAsm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD1(LN|DUP)q(8|16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1d(8|16|32|64)wb")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1q(8|16|32|64)wb")>;
+def : InstRW<[R52WriteVLD3Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1d(8|16|32|64)Twb")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1d(8|16|32|64)Qwb")>;
+def : InstRW<[R52WriteVLD3Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1d64TPseudoWB")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1d64QPseudoWB")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1LNd(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1LNdWB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1DUP(d|q)(8|16|32)wb")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD1(LN|DUP)q(8|16|32)Pseudo_UPD")>;
+
+// 2-element structure load
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD2(d|b)(8|16|32)$")>;
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD2q(8|16|32)$")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2(d|b)(8|16|32)wb")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2q(8|16|32)wb")>;
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD2q(8|16|32)Pseudo$")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2q(8|16|32)PseudoWB")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2LNd(8|16|32)$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2LNdAsm_(8|16|32)$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2LNq(16|32)$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2LNqAsm_(16|32)$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2DUPd(8|16|32)$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2DUPd(8|16|32)x2$")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2LNd(8|16|32)Pseudo")>;
+def : InstRW<[R52WriteVLD1Mem, R52Read_ISS], (instregex "VLD2LNq(16|32)Pseudo")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2LNd(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2LNdWB_(fixed|register)_Asm_(8|16|32)")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2LNq(16|32)_UPD")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2LNqWB_(fixed|register)_Asm_(16|32)")>;
+
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2DUPd(8|16|32)wb")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2DUPd(8|16|32)x2wb")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2LNd(8|16|32)Pseudo_UPD")>;
+def : InstRW<[R52WriteVLD1Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD2LNq(16|32)Pseudo_UPD")>;
+
+// 3-element structure load
+def : InstRW<[R52WriteVLD3Mem, R52Read_ISS], (instregex "VLD3(d|q)(8|16|32)$")>;
+def : InstRW<[R52WriteVLD3Mem, R52Read_ISS], (instregex "VLD3(d|q)Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVLD3Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(d|q)(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVLD3Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(d|q)WB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD3Mem, R52Read_ISS], (instregex "VLD3(d|q)(8|16|32)(oddP|P)seudo")>;
+def : InstRW<[R52WriteVLD3Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(d|q)(8|16|32)(oddP|P)seudo_UPD")>;
+
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)(8|16|32)$")>;
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)(8|16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)WB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)WB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD3(LN|DUP)(d|q)(8|16|32)Pseudo_UPD")>;
+
+// 4-element structure load
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD4(d|q)(8|16|32)$")>;
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD4(d|q)Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVLD4Mem, R52Read_ISS], (instregex "VLD4(d|q)(8|16|32)(oddP|P)seudo")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD4(d|q)(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD4(d|q)WB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD4Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD4(d|q)(8|16|32)(oddP|P)seudo_UPD")>;
+
+
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD4(LN|DUP)(d|q)(8|16|32)$")>;
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD4(LN|DUP)(d|q)Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD4LN(d|q)(8|16|32)Pseudo$")>;
+def : InstRW<[R52WriteVLD2Mem, R52Read_ISS], (instregex "VLD4DUPd(8|16|32)Pseudo$")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD4(LN|DUP)(d|q)(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD4(LN|DUP)(d|q)WB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVLD2Mem, R52WriteAdr, R52Read_ISS], (instregex "VLD4(LN|DUP)(d|q)(8|16|32)Pseudo_UPD")>;
+
+//---
+// VSTx. Vector Stores
+//---
+// 1-element structure store
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST1d(8|16|32|64)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST1q(8|16|32|64)$")>;
+def : InstRW<[R52WriteVST3Mem, R52Read_ISS, R52Read_F2], (instregex "VST1d(8|16|32|64)T$")>;
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST1d(8|16|32|64)Q$")>;
+def : InstRW<[R52WriteVST3Mem, R52Read_ISS, R52Read_F2], (instregex "VST1d64TPseudo$")>;
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST1d64QPseudo$")>;
+
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST1LNd(8|16|32)$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST1LNdAsm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST1LNq(8|16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1d(8|16|32|64)wb")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1q(8|16|32|64)wb")>;
+def : InstRW<[R52WriteVST3Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1d(8|16|32|64)Twb")>;
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1d(8|16|32|64)Qwb")>;
+def : InstRW<[R52WriteVST3Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1d64TPseudoWB")>;
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1d64QPseudoWB")>;
+
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1LNd(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1LNdWB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST1LNq(8|16|32)Pseudo_UPD")>;
+
+// 2-element structure store
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST2(d|b)(8|16|32)$")>;
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST2q(8|16|32)$")>;
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST2q(8|16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST2LNd(8|16|32)$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST2LNdAsm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST2LNd(8|16|32)Pseudo$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST2LNq(16|32)$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST2LNqAsm_(16|32)$")>;
+def : InstRW<[R52WriteVST1Mem, R52Read_ISS, R52Read_F2], (instregex "VST2LNq(16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2(d|b)(8|16|32)wb")>;
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2q(8|16|32)wb")>;
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2q(8|16|32)PseudoWB")>;
+
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2LNd(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2LNdWB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2LNd(8|16|32)Pseudo_UPD")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2LNq(16|32)_UPD")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2LNqWB_(fixed|register)_Asm_(16|32)")>;
+def : InstRW<[R52WriteVST1Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST2LNq(16|32)Pseudo_UPD")>;
+
+// 3-element structure store
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST3(d|q)(8|16|32)$")>;
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST3(d|q)Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST4Mem, R52Read_ISS, R52Read_F2], (instregex "VST3d(8|16|32)(oddP|P)seudo$")>;
+
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST3LNd(8|16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST3LNdAsm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST3LNd(8|16|32)Pseudo$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST3LNq(16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST3LNqAsm_(16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST3LNq(16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3(d|q)(8|16|32)_UPD$")>;
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3(d|q)WB_(fixed|register)_Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST4Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3(d|q)(8|16|32)(oddP|P)seudo_UPD$")>;
+
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3LNd(8|16|32)_UPD$")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3LNdWB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3LNd(8|16|32)Pseudo_UPD$")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3LNq(16|32)_UPD$")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3LNqWB_(fixed|register)_Asm_(16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST3LNq(16|32)Pseudo_UPD$")>;
+
+// 4-element structure store
+def : InstRW<[R52WriteVST5Mem, R52Read_ISS, R52Read_F2], (instregex "VST4(d|q)(8|16|32)$")>;
+def : InstRW<[R52WriteVST5Mem, R52Read_ISS, R52Read_F2], (instregex "VST4(d|q)Asm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST5Mem, R52Read_ISS, R52Read_F2], (instregex "VST4d(8|16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST4LNd(8|16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST4LNdAsm_(8|16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST4LNd(8|16|32)Pseudo$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST4LNq(16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST4LNqAsm_(16|32)$")>;
+def : InstRW<[R52WriteVST2Mem, R52Read_ISS, R52Read_F2], (instregex "VST4LNq(16|32)Pseudo$")>;
+
+def : InstRW<[R52WriteVST5Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4(d|q)(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVST5Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4(d|q)WB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVST5Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4(d|q)(8|16|32)(oddP|P)seudo_UPD")>;
+
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4LNd(8|16|32)_UPD")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4LNdWB_(fixed|register)_Asm_(8|16|32)")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4LNd(8|16|32)Pseudo_UPD")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4LNq(16|32)_UPD")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4LNqWB_(fixed|register)_Asm_(16|32)")>;
+def : InstRW<[R52WriteVST2Mem, R52WriteAdr, R52Read_ISS, R52Read_F2], (instregex "VST4LNq(16|32)Pseudo_UPD")>;
+
+} // R52 SchedModel
diff --git a/contrib/llvm/lib/Target/ARM/ARMSubtarget.cpp b/contrib/llvm/lib/Target/ARM/ARMSubtarget.cpp
index 1d7eef9..e2df0bd 100644
--- a/contrib/llvm/lib/Target/ARM/ARMSubtarget.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMSubtarget.cpp
@@ -31,6 +31,7 @@
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Support/TargetParser.h"
using namespace llvm;
@@ -58,8 +59,7 @@ IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT),
clEnumValN(RestrictedIT, "arm-restrict-it",
"Disallow deprecated IT based on ARMv8"),
clEnumValN(NoRestrictedIT, "arm-no-restrict-it",
- "Allow IT blocks based on ARMv7"),
- clEnumValEnd));
+ "Allow IT blocks based on ARMv7")));
/// ForceFastISel - Use the fast-isel, even for subtargets where it is not
/// currently supported (for testing only).
@@ -76,6 +76,11 @@ ARMSubtarget &ARMSubtarget::initializeSubtargetDependencies(StringRef CPU,
return *this;
}
+/// EnableExecuteOnly - Enables the generation of execute-only code on supported
+/// targets
+static cl::opt<bool>
+EnableExecuteOnly("arm-execute-only");
+
ARMFrameLowering *ARMSubtarget::initializeFrameLowering(StringRef CPU,
StringRef FS) {
ARMSubtarget &STI = initializeSubtargetDependencies(CPU, FS);
@@ -89,8 +94,9 @@ ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU,
const std::string &FS,
const ARMBaseTargetMachine &TM, bool IsLittle)
: ARMGenSubtargetInfo(TT, CPU, FS), UseMulOps(UseFusedMulOps),
- CPUString(CPU), IsLittle(IsLittle), TargetTriple(TT), Options(TM.Options),
- TM(TM), FrameLowering(initializeFrameLowering(CPU, FS)),
+ GenExecuteOnly(EnableExecuteOnly), CPUString(CPU), IsLittle(IsLittle),
+ TargetTriple(TT), Options(TM.Options), TM(TM),
+ FrameLowering(initializeFrameLowering(CPU, FS)),
// At this point initializeSubtargetDependencies has been called so
// we can query directly.
InstrInfo(isThumb1Only()
@@ -98,7 +104,32 @@ ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU,
: !isThumb()
? (ARMBaseInstrInfo *)new ARMInstrInfo(*this)
: (ARMBaseInstrInfo *)new Thumb2InstrInfo(*this)),
- TLInfo(TM, *this) {}
+ TLInfo(TM, *this), GISel() {}
+
+const CallLowering *ARMSubtarget::getCallLowering() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getCallLowering();
+}
+
+const InstructionSelector *ARMSubtarget::getInstructionSelector() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getInstructionSelector();
+}
+
+const LegalizerInfo *ARMSubtarget::getLegalizerInfo() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getLegalizerInfo();
+}
+
+const RegisterBankInfo *ARMSubtarget::getRegBankInfo() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getRegBankInfo();
+}
+
+bool ARMSubtarget::isXRaySupported() const {
+ // We don't currently suppport Thumb, but Windows requires Thumb.
+ return hasV6Ops() && hasARMOps() && !isTargetWindows();
+}
void ARMSubtarget::initializeEnvironment() {
// MCAsmInfo isn't always present (e.g. in opt) so we can't initialize this
@@ -117,10 +148,11 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
if (isTargetDarwin()) {
StringRef ArchName = TargetTriple.getArchName();
- if (ArchName.endswith("v7s"))
+ unsigned ArchKind = llvm::ARM::parseArch(ArchName);
+ if (ArchKind == llvm::ARM::AK_ARMV7S)
// Default to the Swift CPU when targeting armv7s/thumbv7s.
CPUString = "swift";
- else if (ArchName.endswith("v7k"))
+ else if (ArchKind == llvm::ARM::AK_ARMV7K)
// Default to the Cortex-a7 CPU when targeting armv7k/thumbv7k.
// ARMv7k does not use SjLj exception handling.
CPUString = "cortex-a7";
@@ -143,6 +175,10 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
// Assert this for now to make the change obvious.
assert(hasV6T2Ops() || !hasThumb2());
+ // Execute only support requires movt support
+ if (genExecuteOnly())
+ assert(hasV8MBaselineOps() && !NoMovt && "Cannot generate execute-only code for this target");
+
// Keep a pointer to static instruction cost data for the specified CPU.
SchedModel = getSchedModelForCPU(CPUString);
@@ -199,6 +235,9 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
(Options.UnsafeFPMath || isTargetDarwin()))
UseNEONForSinglePrecisionFP = true;
+ if (isRWPI())
+ ReserveR9 = true;
+
// FIXME: Teach TableGen to deal with these instead of doing it manually here.
switch (ARMProcFamily) {
case Others:
@@ -234,6 +273,7 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
case CortexR7:
case CortexM3:
case ExynosM1:
+ case CortexR52:
break;
case Krait:
PreISelOperandLatencyAdjustment = 1;
@@ -261,6 +301,15 @@ bool ARMSubtarget::isAAPCS16_ABI() const {
return TM.TargetABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16;
}
+bool ARMSubtarget::isROPI() const {
+ return TM.getRelocationModel() == Reloc::ROPI ||
+ TM.getRelocationModel() == Reloc::ROPI_RWPI;
+}
+bool ARMSubtarget::isRWPI() const {
+ return TM.getRelocationModel() == Reloc::RWPI ||
+ TM.getRelocationModel() == Reloc::ROPI_RWPI;
+}
+
bool ARMSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return true;
@@ -268,7 +317,7 @@ bool ARMSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
// 32 bit macho has no relocation for a-b if a is undefined, even if b is in
// the section that is being relocated. This means we have to use o load even
// for GVs that are known to be local to the dso.
- if (isTargetDarwin() && TM.isPositionIndependent() &&
+ if (isTargetMachO() && TM.isPositionIndependent() &&
(GV->isDeclarationForLinker() || GV->hasCommonLinkage()))
return true;
@@ -300,9 +349,7 @@ bool ARMSubtarget::enablePostRAScheduler() const {
return (!isThumb() || hasThumb2());
}
-bool ARMSubtarget::enableAtomicExpand() const {
- return hasAnyDataBarrier() && (!isThumb() || hasV8MBaselineOps());
-}
+bool ARMSubtarget::enableAtomicExpand() const { return hasAnyDataBarrier(); }
bool ARMSubtarget::useStride4VFPs(const MachineFunction &MF) const {
// For general targets, the prologue can grow when VFPs are allocated with
@@ -316,7 +363,7 @@ bool ARMSubtarget::useMovt(const MachineFunction &MF) const {
// immediates as it is inherently position independent, and may be out of
// range otherwise.
return !NoMovt && hasV8MBaselineOps() &&
- (isTargetWindows() || !MF.getFunction()->optForMinSize());
+ (isTargetWindows() || !MF.getFunction()->optForMinSize() || genExecuteOnly());
}
bool ARMSubtarget::useFastISel() const {
diff --git a/contrib/llvm/lib/Target/ARM/ARMSubtarget.h b/contrib/llvm/lib/Target/ARM/ARMSubtarget.h
index 910de0e..8c8218d 100644
--- a/contrib/llvm/lib/Target/ARM/ARMSubtarget.h
+++ b/contrib/llvm/lib/Target/ARM/ARMSubtarget.h
@@ -25,6 +25,7 @@
#include "Thumb1InstrInfo.h"
#include "Thumb2InstrInfo.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Target/TargetSubtargetInfo.h"
@@ -43,7 +44,7 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
protected:
enum ARMProcFamilyEnum {
Others, CortexA5, CortexA7, CortexA8, CortexA9, CortexA12, CortexA15,
- CortexA17, CortexR4, CortexR4F, CortexR5, CortexR7, CortexM3,
+ CortexA17, CortexR4, CortexR4F, CortexR5, CortexR7, CortexR52, CortexM3,
CortexA32, CortexA35, CortexA53, CortexA57, CortexA72, CortexA73,
Krait, Swift, ExynosM1
};
@@ -53,7 +54,8 @@ protected:
enum ARMArchEnum {
ARMv2, ARMv2a, ARMv3, ARMv3m, ARMv4, ARMv4t, ARMv5, ARMv5t, ARMv5te,
ARMv5tej, ARMv6, ARMv6k, ARMv6kz, ARMv6t2, ARMv6m, ARMv6sm, ARMv7a, ARMv7r,
- ARMv7m, ARMv7em, ARMv8a, ARMv81a, ARMv82a, ARMv8mMainline, ARMv8mBaseline
+ ARMv7m, ARMv7em, ARMv8a, ARMv81a, ARMv82a, ARMv8mMainline, ARMv8mBaseline,
+ ARMv8r
};
public:
@@ -234,6 +236,9 @@ protected:
/// particularly effective at zeroing a VFP register.
bool HasZeroCycleZeroing = false;
+ /// HasFPAO - if true, processor does positive address offset computation faster
+ bool HasFPAO = false;
+
/// If true, if conversion may decide to leave some instructions unpredicated.
bool IsProfitableToUnpredicate = false;
@@ -296,6 +301,9 @@ protected:
/// Generate calls via indirect call instructions.
bool GenLongCalls = false;
+ /// Generate code that does not contain data access to code sections.
+ bool GenExecuteOnly = false;
+
/// Target machine allowed unsafe FP math (such as use of NEON fp)
bool UnsafeFPMath = false;
@@ -346,6 +354,9 @@ public:
ARMSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
const ARMBaseTargetMachine &TM, bool IsLittle);
+ /// This object will take onwership of \p GISelAccessor.
+ void setGISelAccessor(GISelAccessor &GISel) { this->GISel.reset(&GISel); }
+
/// getMaxInlineSizeThreshold - Returns the maximum memset / memcpy size
/// that still makes it profitable to inline the call.
unsigned getMaxInlineSizeThreshold() const {
@@ -375,6 +386,11 @@ public:
return &InstrInfo->getRegisterInfo();
}
+ const CallLowering *getCallLowering() const override;
+ const InstructionSelector *getInstructionSelector() const override;
+ const LegalizerInfo *getLegalizerInfo() const override;
+ const RegisterBankInfo *getRegBankInfo() const override;
+
private:
ARMSelectionDAGInfo TSInfo;
// Either Thumb1FrameLowering or ARMFrameLowering.
@@ -383,6 +399,11 @@ private:
std::unique_ptr<ARMBaseInstrInfo> InstrInfo;
ARMTargetLowering TLInfo;
+ /// Gather the accessor points to GlobalISel-related APIs.
+ /// This is used to avoid ifndefs spreading around while GISel is
+ /// an optional library.
+ std::unique_ptr<GISelAccessor> GISel;
+
void initializeEnvironment();
void initSubtargetFeatures(StringRef CPU, StringRef FS);
ARMFrameLowering *initializeFrameLowering(StringRef CPU, StringRef FS);
@@ -452,6 +473,7 @@ public:
bool hasTrustZone() const { return HasTrustZone; }
bool has8MSecExt() const { return Has8MSecExt; }
bool hasZeroCycleZeroing() const { return HasZeroCycleZeroing; }
+ bool hasFPAO() const { return HasFPAO; }
bool isProfitableToUnpredicate() const { return IsProfitableToUnpredicate; }
bool hasSlowVGETLNi32() const { return HasSlowVGETLNi32; }
bool hasSlowVDUP32() const { return HasSlowVDUP32; }
@@ -475,6 +497,7 @@ public:
bool useNaClTrap() const { return UseNaClTrap; }
bool useSjLjEH() const { return UseSjLjEH; }
bool genLongCalls() const { return GenLongCalls; }
+ bool genExecuteOnly() const { return GenExecuteOnly; }
bool hasFP16() const { return HasFP16; }
bool hasD16() const { return HasD16; }
@@ -540,10 +563,15 @@ public:
}
bool isTargetAndroid() const { return TargetTriple.isAndroid(); }
+ virtual bool isXRaySupported() const override;
+
bool isAPCS_ABI() const;
bool isAAPCS_ABI() const;
bool isAAPCS16_ABI() const;
+ bool isROPI() const;
+ bool isRWPI() const;
+
bool useSoftFloat() const { return UseSoftFloat; }
bool isThumb() const { return InThumbMode; }
bool isThumb1Only() const { return InThumbMode && !HasThumb2; }
@@ -557,11 +585,17 @@ public:
return isTargetMachO() ? (ReserveR9 || !HasV6Ops) : ReserveR9;
}
+ bool useR7AsFramePointer() const {
+ return isTargetDarwin() || (!isTargetWindows() && isThumb());
+ }
/// Returns true if the frame setup is split into two separate pushes (first
/// r0-r7,lr then r8-r11), principally so that the frame pointer is adjacent
- /// to lr.
- bool splitFramePushPop() const {
- return isTargetMachO();
+ /// to lr. This is always required on Thumb1-only targets, as the push and
+ /// pop instructions can't access the high registers.
+ bool splitFramePushPop(const MachineFunction &MF) const {
+ return (useR7AsFramePointer() &&
+ MF.getTarget().Options.DisableFramePointerElim(MF)) ||
+ isThumb1Only();
}
bool useStride4VFPs(const MachineFunction &MF) const;
diff --git a/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index dc730a6..70c9567 100644
--- a/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -10,11 +10,19 @@
//
//===----------------------------------------------------------------------===//
+#include "ARMTargetMachine.h"
#include "ARM.h"
+#include "ARMCallLowering.h"
#include "ARMFrameLowering.h"
-#include "ARMTargetMachine.h"
+#include "ARMInstructionSelector.h"
+#include "ARMLegalizerInfo.h"
+#include "ARMRegisterBankInfo.h"
#include "ARMTargetObjectFile.h"
#include "ARMTargetTransformInfo.h"
+#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
+#include "llvm/CodeGen/GlobalISel/Legalizer.h"
+#include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Function.h"
@@ -22,6 +30,7 @@
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/TargetParser.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
@@ -50,12 +59,13 @@ EnableGlobalMerge("arm-global-merge", cl::Hidden,
extern "C" void LLVMInitializeARMTarget() {
// Register the target.
- RegisterTargetMachine<ARMLETargetMachine> X(TheARMLETarget);
- RegisterTargetMachine<ARMBETargetMachine> Y(TheARMBETarget);
- RegisterTargetMachine<ThumbLETargetMachine> A(TheThumbLETarget);
- RegisterTargetMachine<ThumbBETargetMachine> B(TheThumbBETarget);
+ RegisterTargetMachine<ARMLETargetMachine> X(getTheARMLETarget());
+ RegisterTargetMachine<ARMBETargetMachine> Y(getTheARMBETarget());
+ RegisterTargetMachine<ThumbLETargetMachine> A(getTheThumbLETarget());
+ RegisterTargetMachine<ThumbBETargetMachine> B(getTheThumbBETarget());
PassRegistry &Registry = *PassRegistry::getPassRegistry();
+ initializeGlobalISel(Registry);
initializeARMLoadStoreOptPass(Registry);
initializeARMPreAllocLoadStoreOptPass(Registry);
}
@@ -84,11 +94,13 @@ computeTargetABI(const Triple &TT, StringRef CPU,
ARMBaseTargetMachine::ARMABI TargetABI =
ARMBaseTargetMachine::ARM_ABI_UNKNOWN;
+ unsigned ArchKind = llvm::ARM::parseCPUArch(CPU);
+ StringRef ArchName = llvm::ARM::getArchName(ArchKind);
// FIXME: This is duplicated code from the front end and should be unified.
if (TT.isOSBinFormatMachO()) {
if (TT.getEnvironment() == llvm::Triple::EABI ||
(TT.getOS() == llvm::Triple::UnknownOS && TT.isOSBinFormatMachO()) ||
- CPU.startswith("cortex-m")) {
+ llvm::ARM::parseArchProfile(ArchName) == llvm::ARM::PK_M) {
TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS;
} else if (TT.isWatchABI()) {
TargetABI = ARMBaseTargetMachine::ARM_ABI_AAPCS16;
@@ -184,6 +196,10 @@ static Reloc::Model getEffectiveRelocModel(const Triple &TT,
// Default relocation model on Darwin is PIC.
return TT.isOSBinFormatMachO() ? Reloc::PIC_ : Reloc::Static;
+ if (*RM == Reloc::ROPI || *RM == Reloc::RWPI || *RM == Reloc::ROPI_RWPI)
+ assert(TT.isOSBinFormatELF() &&
+ "ROPI/RWPI currently only supported for ELF");
+
// DynamicNoPIC is only used on darwin.
if (*RM == Reloc::DynamicNoPIC && !TT.isOSDarwin())
return Reloc::Static;
@@ -224,6 +240,29 @@ ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT,
ARMBaseTargetMachine::~ARMBaseTargetMachine() {}
+#ifdef LLVM_BUILD_GLOBAL_ISEL
+namespace {
+struct ARMGISelActualAccessor : public GISelAccessor {
+ std::unique_ptr<CallLowering> CallLoweringInfo;
+ std::unique_ptr<InstructionSelector> InstSelector;
+ std::unique_ptr<LegalizerInfo> Legalizer;
+ std::unique_ptr<RegisterBankInfo> RegBankInfo;
+ const CallLowering *getCallLowering() const override {
+ return CallLoweringInfo.get();
+ }
+ const InstructionSelector *getInstructionSelector() const override {
+ return InstSelector.get();
+ }
+ const LegalizerInfo *getLegalizerInfo() const override {
+ return Legalizer.get();
+ }
+ const RegisterBankInfo *getRegBankInfo() const override {
+ return RegBankInfo.get();
+ }
+};
+} // End anonymous namespace.
+#endif
+
const ARMSubtarget *
ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
@@ -255,6 +294,24 @@ ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const {
// function that reside in TargetOptions.
resetTargetOptions(F);
I = llvm::make_unique<ARMSubtarget>(TargetTriple, CPU, FS, *this, isLittle);
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+ GISelAccessor *GISel = new GISelAccessor();
+#else
+ ARMGISelActualAccessor *GISel = new ARMGISelActualAccessor();
+ GISel->CallLoweringInfo.reset(new ARMCallLowering(*I->getTargetLowering()));
+ GISel->Legalizer.reset(new ARMLegalizerInfo());
+
+ auto *RBI = new ARMRegisterBankInfo(*I->getRegisterInfo());
+
+ // FIXME: At this point, we can't rely on Subtarget having RBI.
+ // It's awkward to mix passing RBI and the Subtarget; should we pass
+ // TII/TRI as well?
+ GISel->InstSelector.reset(new ARMInstructionSelector(*I, *RBI));
+
+ GISel->RegBankInfo.reset(RBI);
+#endif
+ I->setGISelAccessor(*GISel);
}
return I.get();
}
@@ -346,6 +403,12 @@ public:
void addIRPasses() override;
bool addPreISel() override;
bool addInstSelector() override;
+#ifdef LLVM_BUILD_GLOBAL_ISEL
+ bool addIRTranslator() override;
+ bool addLegalizeMachineIR() override;
+ bool addRegBankSelect() override;
+ bool addGlobalInstructionSelect() override;
+#endif
void addPreRegAlloc() override;
void addPreSched2() override;
void addPreEmitPass() override;
@@ -406,6 +469,28 @@ bool ARMPassConfig::addInstSelector() {
return false;
}
+#ifdef LLVM_BUILD_GLOBAL_ISEL
+bool ARMPassConfig::addIRTranslator() {
+ addPass(new IRTranslator());
+ return false;
+}
+
+bool ARMPassConfig::addLegalizeMachineIR() {
+ addPass(new Legalizer());
+ return false;
+}
+
+bool ARMPassConfig::addRegBankSelect() {
+ addPass(new RegBankSelect());
+ return false;
+}
+
+bool ARMPassConfig::addGlobalInstructionSelect() {
+ addPass(new InstructionSelect());
+ return false;
+}
+#endif
+
void ARMPassConfig::addPreRegAlloc() {
if (getOptLevel() != CodeGenOpt::None) {
addPass(createMLxExpansionPass());
@@ -436,8 +521,8 @@ void ARMPassConfig::addPreSched2() {
return this->TM->getSubtarget<ARMSubtarget>(F).restrictIT();
}));
- addPass(createIfConverter([this](const Function &F) {
- return !this->TM->getSubtarget<ARMSubtarget>(F).isThumb1Only();
+ addPass(createIfConverter([](const MachineFunction &MF) {
+ return !MF.getSubtarget<ARMSubtarget>().isThumb1Only();
}));
}
addPass(createThumb2ITBlockPass());
@@ -447,8 +532,8 @@ void ARMPassConfig::addPreEmitPass() {
addPass(createThumb2SizeReductionPass());
// Constant island pass work on unbundled instructions.
- addPass(createUnpackMachineBundles([this](const Function &F) {
- return this->TM->getSubtarget<ARMSubtarget>(F).isThumb2();
+ addPass(createUnpackMachineBundles([](const MachineFunction &MF) {
+ return MF.getSubtarget<ARMSubtarget>().isThumb2();
}));
// Don't optimize barriers at -O0.
diff --git a/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp b/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp
index eaed5cc..625c428 100644
--- a/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp
@@ -27,8 +27,10 @@ using namespace dwarf;
void ARMElfTargetObjectFile::Initialize(MCContext &Ctx,
const TargetMachine &TM) {
- bool isAAPCS_ABI = static_cast<const ARMTargetMachine &>(TM).TargetABI ==
- ARMTargetMachine::ARMABI::ARM_ABI_AAPCS;
+ const ARMTargetMachine &ARM_TM = static_cast<const ARMTargetMachine &>(TM);
+ bool isAAPCS_ABI = ARM_TM.TargetABI == ARMTargetMachine::ARMABI::ARM_ABI_AAPCS;
+ genExecuteOnly = ARM_TM.getSubtargetImpl()->genExecuteOnly();
+
TargetLoweringObjectFileELF::Initialize(Ctx, TM);
InitializeELF(isAAPCS_ABI);
@@ -38,19 +40,28 @@ void ARMElfTargetObjectFile::Initialize(MCContext &Ctx,
AttributesSection =
getContext().getELFSection(".ARM.attributes", ELF::SHT_ARM_ATTRIBUTES, 0);
+
+ // Make code section unreadable when in execute-only mode
+ if (genExecuteOnly) {
+ unsigned Type = ELF::SHT_PROGBITS;
+ unsigned Flags = ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_ARM_PURECODE;
+ // Since we cannot modify flags for an existing section, we create a new
+ // section with the right flags, and use 0 as the unique ID for
+ // execute-only text
+ TextSection = Ctx.getELFSection(".text", Type, Flags, 0, "", 0U);
+ }
}
const MCExpr *ARMElfTargetObjectFile::getTTypeGlobalReference(
- const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
- const TargetMachine &TM, MachineModuleInfo *MMI,
- MCStreamer &Streamer) const {
+ const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM,
+ MachineModuleInfo *MMI, MCStreamer &Streamer) const {
if (TM.getMCAsmInfo()->getExceptionHandlingType() != ExceptionHandling::ARM)
return TargetLoweringObjectFileELF::getTTypeGlobalReference(
- GV, Encoding, Mang, TM, MMI, Streamer);
+ GV, Encoding, TM, MMI, Streamer);
assert(Encoding == DW_EH_PE_absptr && "Can handle absptr encoding only");
- return MCSymbolRefExpr::create(TM.getSymbol(GV, Mang),
+ return MCSymbolRefExpr::create(TM.getSymbol(GV),
MCSymbolRefExpr::VK_ARM_TARGET2, getContext());
}
@@ -59,3 +70,23 @@ getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
return MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_ARM_TLSLDO,
getContext());
}
+
+MCSection *
+ARMElfTargetObjectFile::getExplicitSectionGlobal(const GlobalObject *GO,
+ SectionKind SK, const TargetMachine &TM) const {
+ // Set execute-only access for the explicit section
+ if (genExecuteOnly && SK.isText())
+ SK = SectionKind::getExecuteOnly();
+
+ return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, SK, TM);
+}
+
+MCSection *
+ARMElfTargetObjectFile::SelectSectionForGlobal(const GlobalObject *GO,
+ SectionKind SK, const TargetMachine &TM) const {
+ // Place the global in the execute-only text section
+ if (genExecuteOnly && SK.isText())
+ SK = SectionKind::getExecuteOnly();
+
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, SK, TM);
+}
diff --git a/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.h b/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.h
index b1db201..24e755d 100644
--- a/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/ARM/ARMTargetObjectFile.h
@@ -18,6 +18,7 @@ class MCContext;
class TargetMachine;
class ARMElfTargetObjectFile : public TargetLoweringObjectFileELF {
+ mutable bool genExecuteOnly = false;
protected:
const MCSection *AttributesSection;
public:
@@ -28,14 +29,20 @@ public:
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
- const MCExpr *
- getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
- Mangler &Mang, const TargetMachine &TM,
- MachineModuleInfo *MMI,
- MCStreamer &Streamer) const override;
+ const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
+ unsigned Encoding,
+ const TargetMachine &TM,
+ MachineModuleInfo *MMI,
+ MCStreamer &Streamer) const override;
/// \brief Describe a TLS variable address within debug info.
const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
+
+ MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
+ const TargetMachine &TM) const override;
+
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
+ const TargetMachine &TM) const override;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp
index 13c5dc6..2b6b36b 100644
--- a/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp
@@ -41,7 +41,7 @@ int ARMTTIImpl::getIntImmCost(const APInt &Imm, Type *Ty) {
// Thumb1.
if (SImmVal >= 0 && SImmVal < 256)
return 1;
- if ((~ZImmVal < 256) || ARM_AM::isThumbImmShiftedVal(ZImmVal))
+ if ((~SImmVal < 256) || ARM_AM::isThumbImmShiftedVal(ZImmVal))
return 2;
// Load from constantpool.
return 3;
@@ -69,6 +69,25 @@ int ARMTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
Idx == 1)
return 0;
+ if (Opcode == Instruction::And)
+ // Conversion to BIC is free, and means we can use ~Imm instead.
+ return std::min(getIntImmCost(Imm, Ty), getIntImmCost(~Imm, Ty));
+
+ if (Opcode == Instruction::Add)
+ // Conversion to SUB is free, and means we can use -Imm instead.
+ return std::min(getIntImmCost(Imm, Ty), getIntImmCost(-Imm, Ty));
+
+ if (Opcode == Instruction::ICmp && Imm.isNegative() &&
+ Ty->getIntegerBitWidth() == 32) {
+ int64_t NegImm = -Imm.getSExtValue();
+ if (ST->isThumb2() && NegImm < 1<<12)
+ // icmp X, #-C -> cmn X, #C
+ return 0;
+ if (ST->isThumb() && NegImm < 1<<8)
+ // icmp X, #-C -> adds X, #C
+ return 0;
+ }
+
return getIntImmCost(Imm, Ty);
}
@@ -319,14 +338,17 @@ int ARMTTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) {
return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy);
}
-int ARMTTIImpl::getAddressComputationCost(Type *Ty, bool IsComplex) {
+int ARMTTIImpl::getAddressComputationCost(Type *Ty, ScalarEvolution *SE,
+ const SCEV *Ptr) {
// Address computations in vectorized code with non-consecutive addresses will
// likely result in more instructions compared to scalar code where the
// computation can more often be merged into the index mode. The resulting
// extra micro-ops can significantly decrease throughput.
unsigned NumVectorInstToHideOverhead = 10;
+ int MaxMergeDistance = 64;
- if (Ty->isVectorTy() && IsComplex)
+ if (Ty->isVectorTy() && SE &&
+ !BaseT::isConstantStridedAccessLessThan(SE, Ptr, MaxMergeDistance + 1))
return NumVectorInstToHideOverhead;
// In many cases the address computation is not merged into the instruction
@@ -411,7 +433,8 @@ int ARMTTIImpl::getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index,
int ARMTTIImpl::getArithmeticInstrCost(
unsigned Opcode, Type *Ty, TTI::OperandValueKind Op1Info,
TTI::OperandValueKind Op2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ TTI::OperandValueProperties Opd2PropInfo,
+ ArrayRef<const Value *> Args) {
int ISDOpcode = TLI->InstructionOpcodeToISD(Opcode);
std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Ty);
diff --git a/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.h b/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.h
index a0ca9e6..3c83cd9 100644
--- a/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/ARM/ARMTargetTransformInfo.h
@@ -45,13 +45,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- ARMTTIImpl(const ARMTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- ARMTTIImpl(ARMTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
bool enableInterleavedAccessVectorization() { return true; }
/// Floating-point computation using ARMv8 AArch32 Advanced
@@ -111,7 +104,8 @@ public:
int getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index);
- int getAddressComputationCost(Type *Val, bool IsComplex);
+ int getAddressComputationCost(Type *Val, ScalarEvolution *SE,
+ const SCEV *Ptr);
int getFPOpCost(Type *Ty);
@@ -120,7 +114,8 @@ public:
TTI::OperandValueKind Op1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Op2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
unsigned AddressSpace);
@@ -128,6 +123,16 @@ public:
int getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, unsigned Factor,
ArrayRef<unsigned> Indices, unsigned Alignment,
unsigned AddressSpace);
+
+ bool shouldBuildLookupTablesForConstant(Constant *C) const {
+ // In the ROPI and RWPI relocation models we can't have pointers to global
+ // variables or functions in constant data, so don't convert switches to
+ // lookup tables if any of the values would need relocation.
+ if (ST->isROPI() || ST->isRWPI())
+ return !C->needsRelocation();
+
+ return true;
+ }
/// @}
};
diff --git a/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index f5de8a3..c243a2d 100644
--- a/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -40,6 +40,7 @@
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/ARMEHABI.h"
#include "llvm/Support/COFF.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/MathExtras.h"
@@ -52,6 +53,20 @@ using namespace llvm;
namespace {
+enum class ImplicitItModeTy { Always, Never, ARMOnly, ThumbOnly };
+
+static cl::opt<ImplicitItModeTy> ImplicitItMode(
+ "arm-implicit-it", cl::init(ImplicitItModeTy::ARMOnly),
+ cl::desc("Allow conditional instructions outdside of an IT block"),
+ cl::values(clEnumValN(ImplicitItModeTy::Always, "always",
+ "Accept in both ISAs, emit implicit ITs in Thumb"),
+ clEnumValN(ImplicitItModeTy::Never, "never",
+ "Warn in ARM, reject in Thumb"),
+ clEnumValN(ImplicitItModeTy::ARMOnly, "arm",
+ "Accept in ARM, reject in Thumb"),
+ clEnumValN(ImplicitItModeTy::ThumbOnly, "thumb",
+ "Warn in ARM, emit implicit ITs in Thumb")));
+
class ARMOperand;
enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
@@ -145,6 +160,16 @@ class ARMAsmParser : public MCTargetAsmParser {
bool NextSymbolIsThumb;
+ bool useImplicitITThumb() const {
+ return ImplicitItMode == ImplicitItModeTy::Always ||
+ ImplicitItMode == ImplicitItModeTy::ThumbOnly;
+ }
+
+ bool useImplicitITARM() const {
+ return ImplicitItMode == ImplicitItModeTy::Always ||
+ ImplicitItMode == ImplicitItModeTy::ARMOnly;
+ }
+
struct {
ARMCC::CondCodes Cond; // Condition for IT block.
unsigned Mask:4; // Condition mask for instructions.
@@ -153,40 +178,174 @@ class ARMAsmParser : public MCTargetAsmParser {
// '0' inverse of condition (else).
// Count of instructions in IT block is
// 4 - trailingzeroes(mask)
-
- bool FirstCond; // Explicit flag for when we're parsing the
- // First instruction in the IT block. It's
- // implied in the mask, so needs special
- // handling.
+ // Note that this does not have the same encoding
+ // as in the IT instruction, which also depends
+ // on the low bit of the condition code.
unsigned CurPosition; // Current position in parsing of IT
- // block. In range [0,3]. Initialized
- // according to count of instructions in block.
- // ~0U if no active IT block.
+ // block. In range [0,4], with 0 being the IT
+ // instruction itself. Initialized according to
+ // count of instructions in block. ~0U if no
+ // active IT block.
+
+ bool IsExplicit; // true - The IT instruction was present in the
+ // input, we should not modify it.
+ // false - The IT instruction was added
+ // implicitly, we can extend it if that
+ // would be legal.
} ITState;
+
+ llvm::SmallVector<MCInst, 4> PendingConditionalInsts;
+
+ void flushPendingInstructions(MCStreamer &Out) override {
+ if (!inImplicitITBlock()) {
+ assert(PendingConditionalInsts.size() == 0);
+ return;
+ }
+
+ // Emit the IT instruction
+ unsigned Mask = getITMaskEncoding();
+ MCInst ITInst;
+ ITInst.setOpcode(ARM::t2IT);
+ ITInst.addOperand(MCOperand::createImm(ITState.Cond));
+ ITInst.addOperand(MCOperand::createImm(Mask));
+ Out.EmitInstruction(ITInst, getSTI());
+
+ // Emit the conditonal instructions
+ assert(PendingConditionalInsts.size() <= 4);
+ for (const MCInst &Inst : PendingConditionalInsts) {
+ Out.EmitInstruction(Inst, getSTI());
+ }
+ PendingConditionalInsts.clear();
+
+ // Clear the IT state
+ ITState.Mask = 0;
+ ITState.CurPosition = ~0U;
+ }
+
bool inITBlock() { return ITState.CurPosition != ~0U; }
+ bool inExplicitITBlock() { return inITBlock() && ITState.IsExplicit; }
+ bool inImplicitITBlock() { return inITBlock() && !ITState.IsExplicit; }
bool lastInITBlock() {
return ITState.CurPosition == 4 - countTrailingZeros(ITState.Mask);
}
void forwardITPosition() {
if (!inITBlock()) return;
// Move to the next instruction in the IT block, if there is one. If not,
- // mark the block as done.
+ // mark the block as done, except for implicit IT blocks, which we leave
+ // open until we find an instruction that can't be added to it.
unsigned TZ = countTrailingZeros(ITState.Mask);
- if (++ITState.CurPosition == 5 - TZ)
+ if (++ITState.CurPosition == 5 - TZ && ITState.IsExplicit)
ITState.CurPosition = ~0U; // Done with the IT block after this.
}
- void Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None) {
- return getParser().Note(L, Msg, Ranges);
+ // Rewind the state of the current IT block, removing the last slot from it.
+ void rewindImplicitITPosition() {
+ assert(inImplicitITBlock());
+ assert(ITState.CurPosition > 1);
+ ITState.CurPosition--;
+ unsigned TZ = countTrailingZeros(ITState.Mask);
+ unsigned NewMask = 0;
+ NewMask |= ITState.Mask & (0xC << TZ);
+ NewMask |= 0x2 << TZ;
+ ITState.Mask = NewMask;
+ }
+
+ // Rewind the state of the current IT block, removing the last slot from it.
+ // If we were at the first slot, this closes the IT block.
+ void discardImplicitITBlock() {
+ assert(inImplicitITBlock());
+ assert(ITState.CurPosition == 1);
+ ITState.CurPosition = ~0U;
+ return;
}
- bool Warning(SMLoc L, const Twine &Msg,
- ArrayRef<SMRange> Ranges = None) {
- return getParser().Warning(L, Msg, Ranges);
+
+ // Get the encoding of the IT mask, as it will appear in an IT instruction.
+ unsigned getITMaskEncoding() {
+ assert(inITBlock());
+ unsigned Mask = ITState.Mask;
+ unsigned TZ = countTrailingZeros(Mask);
+ if ((ITState.Cond & 1) == 0) {
+ assert(Mask && TZ <= 3 && "illegal IT mask value!");
+ Mask ^= (0xE << TZ) & 0xF;
+ }
+ return Mask;
}
- bool Error(SMLoc L, const Twine &Msg,
- ArrayRef<SMRange> Ranges = None) {
- return getParser().Error(L, Msg, Ranges);
+
+ // Get the condition code corresponding to the current IT block slot.
+ ARMCC::CondCodes currentITCond() {
+ unsigned MaskBit;
+ if (ITState.CurPosition == 1)
+ MaskBit = 1;
+ else
+ MaskBit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
+
+ return MaskBit ? ITState.Cond : ARMCC::getOppositeCondition(ITState.Cond);
+ }
+
+ // Invert the condition of the current IT block slot without changing any
+ // other slots in the same block.
+ void invertCurrentITCondition() {
+ if (ITState.CurPosition == 1) {
+ ITState.Cond = ARMCC::getOppositeCondition(ITState.Cond);
+ } else {
+ ITState.Mask ^= 1 << (5 - ITState.CurPosition);
+ }
+ }
+
+ // Returns true if the current IT block is full (all 4 slots used).
+ bool isITBlockFull() {
+ return inITBlock() && (ITState.Mask & 1);
+ }
+
+ // Extend the current implicit IT block to have one more slot with the given
+ // condition code.
+ void extendImplicitITBlock(ARMCC::CondCodes Cond) {
+ assert(inImplicitITBlock());
+ assert(!isITBlockFull());
+ assert(Cond == ITState.Cond ||
+ Cond == ARMCC::getOppositeCondition(ITState.Cond));
+ unsigned TZ = countTrailingZeros(ITState.Mask);
+ unsigned NewMask = 0;
+ // Keep any existing condition bits.
+ NewMask |= ITState.Mask & (0xE << TZ);
+ // Insert the new condition bit.
+ NewMask |= (Cond == ITState.Cond) << TZ;
+ // Move the trailing 1 down one bit.
+ NewMask |= 1 << (TZ - 1);
+ ITState.Mask = NewMask;
+ }
+
+ // Create a new implicit IT block with a dummy condition code.
+ void startImplicitITBlock() {
+ assert(!inITBlock());
+ ITState.Cond = ARMCC::AL;
+ ITState.Mask = 8;
+ ITState.CurPosition = 1;
+ ITState.IsExplicit = false;
+ return;
+ }
+
+ // Create a new explicit IT block with the given condition and mask. The mask
+ // should be in the parsed format, with a 1 implying 't', regardless of the
+ // low bit of the condition.
+ void startExplicitITBlock(ARMCC::CondCodes Cond, unsigned Mask) {
+ assert(!inITBlock());
+ ITState.Cond = Cond;
+ ITState.Mask = Mask;
+ ITState.CurPosition = 0;
+ ITState.IsExplicit = true;
+ return;
+ }
+
+ void Note(SMLoc L, const Twine &Msg, SMRange Range = None) {
+ return getParser().Note(L, Msg, Range);
+ }
+ bool Warning(SMLoc L, const Twine &Msg, SMRange Range = None) {
+ return getParser().Warning(L, Msg, Range);
+ }
+ bool Error(SMLoc L, const Twine &Msg, SMRange Range = None) {
+ return getParser().Error(L, Msg, Range);
}
bool validatetLDMRegList(const MCInst &Inst, const OperandVector &Operands,
@@ -355,6 +514,7 @@ class ARMAsmParser : public MCTargetAsmParser {
bool processInstruction(MCInst &Inst, const OperandVector &Ops, MCStreamer &Out);
bool shouldOmitCCOutOperand(StringRef Mnemonic, OperandVector &Operands);
bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands);
+ bool isITBlockTerminator(MCInst &Inst) const;
public:
enum ARMMatchResultTy {
@@ -363,6 +523,7 @@ public:
Match_RequiresV6,
Match_RequiresThumb2,
Match_RequiresV8,
+ Match_RequiresFlagSetting,
#define GET_OPERAND_DIAGNOSTIC_TYPES
#include "ARMGenAsmMatcher.inc"
@@ -399,6 +560,9 @@ public:
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) override;
+ unsigned MatchInstruction(OperandVector &Operands, MCInst &Inst,
+ uint64_t &ErrorInfo, bool MatchingInlineAsm,
+ bool &EmitInITBlock, MCStreamer &Out);
void onLabelParsed(MCSymbol *Symbol) override;
};
} // end anonymous namespace
@@ -3286,7 +3450,7 @@ static int MatchCoprocessorOperandName(StringRef Name, char CoprocOp) {
}
/// parseITCondCode - Try to parse a condition code for an IT instruction.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseITCondCode(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -3324,7 +3488,7 @@ ARMAsmParser::parseITCondCode(OperandVector &Operands) {
/// parseCoprocNumOperand - Try to parse an coprocessor number operand. The
/// token must be an Identifier when called, and if it is a coprocessor
/// number, the token is eaten and the operand is added to the operand list.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseCoprocNumOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -3347,7 +3511,7 @@ ARMAsmParser::parseCoprocNumOperand(OperandVector &Operands) {
/// parseCoprocRegOperand - Try to parse an coprocessor register operand. The
/// token must be an Identifier when called, and if it is a coprocessor
/// number, the token is eaten and the operand is added to the operand list.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseCoprocRegOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -3366,7 +3530,7 @@ ARMAsmParser::parseCoprocRegOperand(OperandVector &Operands) {
/// parseCoprocOptionOperand - Try to parse an coprocessor option operand.
/// coproc_option : '{' imm0_255 '}'
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseCoprocOptionOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -3447,8 +3611,8 @@ static unsigned getDRegFromQReg(unsigned QReg) {
/// Parse a register list.
bool ARMAsmParser::parseRegisterList(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
- assert(Parser.getTok().is(AsmToken::LCurly) &&
- "Token is not a Left Curly Brace");
+ if (Parser.getTok().isNot(AsmToken::LCurly))
+ return TokError("Token is not a Left Curly Brace");
SMLoc S = Parser.getTok().getLoc();
Parser.Lex(); // Eat '{' token.
SMLoc RegLoc = Parser.getTok().getLoc();
@@ -3576,7 +3740,7 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands) {
}
// Helper function to parse the lane index for vector lists.
-ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+OperandMatchResultTy ARMAsmParser::
parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index, SMLoc &EndLoc) {
MCAsmParser &Parser = getParser();
Index = 0; // Always return a defined index value.
@@ -3628,7 +3792,7 @@ parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index, SMLoc &EndLoc) {
}
// parse a vector register list
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseVectorList(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
VectorLaneTy LaneKind;
@@ -3880,7 +4044,7 @@ ARMAsmParser::parseVectorList(OperandVector &Operands) {
}
/// parseMemBarrierOptOperand - Try to parse DSB/DMB data barrier options.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -3952,7 +4116,7 @@ ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) {
}
/// parseInstSyncBarrierOptOperand - Try to parse ISB inst sync barrier options.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -4004,7 +4168,7 @@ ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) {
/// parseProcIFlagsOperand - Try to parse iflags from CPS instruction.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseProcIFlagsOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -4039,7 +4203,7 @@ ARMAsmParser::parseProcIFlagsOperand(OperandVector &Operands) {
}
/// parseMSRMaskOperand - Try to parse mask flags from MSR instruction.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -4192,7 +4356,7 @@ ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) {
/// parseBankedRegOperand - Try to parse a banked register (e.g. "lr_irq") for
/// use in the MRS/MSR instructions added to support virtualization.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseBankedRegOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -4247,7 +4411,7 @@ ARMAsmParser::parseBankedRegOperand(OperandVector &Operands) {
return MatchOperand_Success;
}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parsePKHImm(OperandVector &Operands, StringRef Op, int Low,
int High) {
MCAsmParser &Parser = getParser();
@@ -4296,7 +4460,7 @@ ARMAsmParser::parsePKHImm(OperandVector &Operands, StringRef Op, int Low,
return MatchOperand_Success;
}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseSetEndImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -4326,7 +4490,7 @@ ARMAsmParser::parseSetEndImm(OperandVector &Operands) {
/// lsl #n 'n' in [0,31]
/// asr #n 'n' in [1,32]
/// n == 32 encoded as n == 0.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseShifterImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -4397,7 +4561,7 @@ ARMAsmParser::parseShifterImm(OperandVector &Operands) {
/// parseRotImm - Parse the shifter immediate operand for SXTB/UXTB family
/// of instructions. Legal values are:
/// ror #n 'n' in {0, 8, 16, 24}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseRotImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
@@ -4444,7 +4608,7 @@ ARMAsmParser::parseRotImm(OperandVector &Operands) {
return MatchOperand_Success;
}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseModImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
MCAsmLexer &Lexer = getLexer();
@@ -4561,7 +4725,7 @@ ARMAsmParser::parseModImm(OperandVector &Operands) {
}
}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseBitfield(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
@@ -4630,7 +4794,7 @@ ARMAsmParser::parseBitfield(OperandVector &Operands) {
return MatchOperand_Success;
}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parsePostIdxReg(OperandVector &Operands) {
// Check for a post-index addressing register operand. Specifically:
// postidx_reg := '+' register {, shift}
@@ -4680,7 +4844,7 @@ ARMAsmParser::parsePostIdxReg(OperandVector &Operands) {
return MatchOperand_Success;
}
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseAM3Offset(OperandVector &Operands) {
// Check for a post-index addressing register operand. Specifically:
// am3offset := '+' register
@@ -4833,8 +4997,8 @@ void ARMAsmParser::cvtThumbBranches(MCInst &Inst,
bool ARMAsmParser::parseMemory(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S, E;
- assert(Parser.getTok().is(AsmToken::LBrac) &&
- "Token is not a Left Bracket");
+ if (Parser.getTok().isNot(AsmToken::LBrac))
+ return TokError("Token is not a Left Bracket");
S = Parser.getTok().getLoc();
Parser.Lex(); // Eat left bracket token.
@@ -5082,7 +5246,7 @@ bool ARMAsmParser::parseMemRegOffsetShift(ARM_AM::ShiftOpc &St,
}
/// parseFPImm - A floating point immediate expression operand.
-ARMAsmParser::OperandMatchResultTy
+OperandMatchResultTy
ARMAsmParser::parseFPImm(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
// Anything that can accept a floating point constant as an operand
@@ -5131,7 +5295,7 @@ ARMAsmParser::parseFPImm(OperandVector &Operands) {
const AsmToken &Tok = Parser.getTok();
SMLoc Loc = Tok.getLoc();
if (Tok.is(AsmToken::Real) && isVmovf) {
- APFloat RealVal(APFloat::IEEEsingle, Tok.getString());
+ APFloat RealVal(APFloat::IEEEsingle(), Tok.getString());
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
// If we had a '-' in front, toggle the sign bit.
IntVal ^= (uint64_t)isNegative << 31;
@@ -5259,7 +5423,7 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
return false;
}
// w/ a ':' after the '#', it's just like a plain ':'.
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
case AsmToken::Colon: {
S = Parser.getTok().getLoc();
@@ -5289,6 +5453,9 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
if (getParser().parseExpression(SubExprVal))
return true;
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+
+ // execute-only: we assume that assembly programmers know what they are
+ // doing and allow literal pool creation here
Operands.push_back(ARMOperand::CreateConstantPoolImm(SubExprVal, S, E));
return false;
}
@@ -5842,7 +6009,6 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// In Thumb1, only the branch (B) instruction can be predicated.
if (isThumbOne() && PredicationCode != ARMCC::AL && Mnemonic != "b") {
- Parser.eatToEndOfStatement();
return Error(NameLoc, "conditional execution not supported in Thumb1");
}
@@ -5856,14 +6022,12 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
if (Mnemonic == "it") {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + 2);
if (ITMask.size() > 3) {
- Parser.eatToEndOfStatement();
return Error(Loc, "too many conditions on IT instruction");
}
unsigned Mask = 8;
for (unsigned i = ITMask.size(); i != 0; --i) {
char pos = ITMask[i - 1];
if (pos != 't' && pos != 'e') {
- Parser.eatToEndOfStatement();
return Error(Loc, "illegal IT block condition mask '" + ITMask + "'");
}
Mask >>= 1;
@@ -5889,14 +6053,12 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// If we had a carry-set on an instruction that can't do that, issue an
// error.
if (!CanAcceptCarrySet && CarrySetting) {
- Parser.eatToEndOfStatement();
return Error(NameLoc, "instruction '" + Mnemonic +
"' can not set flags, but 's' suffix specified");
}
// If we had a predication code on an instruction that can't do that, issue an
// error.
if (!CanAcceptPredicationCode && PredicationCode != ARMCC::AL) {
- Parser.eatToEndOfStatement();
return Error(NameLoc, "instruction '" + Mnemonic +
"' is not predicable, but condition code specified");
}
@@ -5940,7 +6102,6 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// For for ARM mode generate an error if the .n qualifier is used.
if (ExtraToken == ".n" && !isThumb()) {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Start);
- Parser.eatToEndOfStatement();
return Error(Loc, "instruction with .n (narrow) qualifier not allowed in "
"arm mode");
}
@@ -5958,28 +6119,19 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
if (getLexer().isNot(AsmToken::EndOfStatement)) {
// Read the first operand.
if (parseOperand(Operands, Mnemonic)) {
- Parser.eatToEndOfStatement();
return true;
}
- while (getLexer().is(AsmToken::Comma)) {
- Parser.Lex(); // Eat the comma.
-
+ while (parseOptionalToken(AsmToken::Comma)) {
// Parse and remember the operand.
if (parseOperand(Operands, Mnemonic)) {
- Parser.eatToEndOfStatement();
return true;
}
}
}
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
- return Error(Loc, "unexpected token in argument list");
- }
-
- Parser.Lex(); // Consume the EndOfStatement
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
+ return true;
if (RequireVFPRegisterListCheck) {
ARMOperand &Op = static_cast<ARMOperand &>(*Operands.back());
@@ -6043,10 +6195,9 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Rt2 must be Rt + 1 and Rt must be even.
if (Rt + 1 != Rt2 || (Rt & 1)) {
- Error(Op2.getStartLoc(), isLoad
- ? "destination operands must be sequential"
- : "source operands must be sequential");
- return true;
+ return Error(Op2.getStartLoc(),
+ isLoad ? "destination operands must be sequential"
+ : "source operands must be sequential");
}
unsigned NewReg = MRI->getMatchingSuperReg(Reg1, ARM::gsub_0,
&(MRI->getRegClass(ARM::GPRPairRegClassID)));
@@ -6188,18 +6339,11 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
// NOTE: BKPT and HLT instructions have the interesting property of being
// allowed in IT blocks, but not being predicable. They just always execute.
if (inITBlock() && !instIsBreakpoint(Inst)) {
- unsigned Bit = 1;
- if (ITState.FirstCond)
- ITState.FirstCond = false;
- else
- Bit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
// 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();
- unsigned ITCond = Bit ? ITState.Cond :
- ARMCC::getOppositeCondition(ITState.Cond);
- if (Cond != ITCond) {
+ if (Cond != currentITCond()) {
// Find the condition code Operand to get its SMLoc information.
SMLoc CondLoc;
for (unsigned I = 1; I < Operands.size(); ++I)
@@ -6208,14 +6352,19 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return Error(CondLoc, "incorrect condition in IT block; got '" +
StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
"', but expected '" +
- ARMCondCodeToString(ARMCC::CondCodes(ITCond)) + "'");
+ ARMCondCodeToString(ARMCC::CondCodes(currentITCond())) + "'");
}
// Check for non-'al' condition codes outside of the IT block.
} else if (isThumbTwo() && MCID.isPredicable() &&
Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
ARMCC::AL && Inst.getOpcode() != ARM::tBcc &&
- Inst.getOpcode() != ARM::t2Bcc)
+ Inst.getOpcode() != ARM::t2Bcc) {
return Error(Loc, "predicated instructions must be in IT block");
+ } else if (!isThumb() && !useImplicitITARM() && MCID.isPredicable() &&
+ Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
+ ARMCC::AL) {
+ return Warning(Loc, "predicated instructions should be in IT block");
+ }
const unsigned Opcode = Inst.getOpcode();
switch (Opcode) {
@@ -6520,6 +6669,12 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return Error(Operands[Op]->getStartLoc(), "branch target out of range");
break;
}
+ case ARM::tCBZ:
+ case ARM::tCBNZ: {
+ if (!static_cast<ARMOperand &>(*Operands[2]).isUnsignedOffset<6, 1>())
+ return Error(Operands[2]->getStartLoc(), "branch target out of range");
+ break;
+ }
case ARM::MOVi16:
case ARM::t2MOVi16:
case ARM::t2MOVTi16:
@@ -8639,27 +8794,15 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
}
case ARM::ITasm:
case ARM::t2IT: {
- // The mask bits for all but the first condition are represented as
- // the low bit of the condition code value implies 't'. We currently
- // always have 1 implies 't', so XOR toggle the bits if the low bit
- // of the condition code is zero.
MCOperand &MO = Inst.getOperand(1);
unsigned Mask = MO.getImm();
- unsigned OrigMask = Mask;
- unsigned TZ = countTrailingZeros(Mask);
- if ((Inst.getOperand(0).getImm() & 1) == 0) {
- assert(Mask && TZ <= 3 && "illegal IT mask value!");
- Mask ^= (0xE << TZ) & 0xF;
- }
- MO.setImm(Mask);
+ ARMCC::CondCodes Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
// Set up the IT block state according to the IT instruction we just
// matched.
assert(!inITBlock() && "nested IT blocks?!");
- ITState.Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
- ITState.Mask = OrigMask; // Use the original mask, not the updated one.
- ITState.CurPosition = 0;
- ITState.FirstCond = true;
+ startExplicitITBlock(Cond, Mask);
+ MO.setImm(getITMaskEncoding());
break;
}
case ARM::t2LSLrr:
@@ -8766,7 +8909,7 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
;
// If we're parsing Thumb1, reject it completely.
if (isThumbOne() && Inst.getOperand(OpNo).getReg() != ARM::CPSR)
- return Match_MnemonicFail;
+ return Match_RequiresFlagSetting;
// If we're parsing Thumb2, which form is legal depends on whether we're
// in an IT block.
if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR &&
@@ -8807,6 +8950,132 @@ template <> inline bool IsCPSRDead<MCInst>(MCInst *Instr) {
}
}
+// Returns true if Inst is unpredictable if it is in and IT block, but is not
+// the last instruction in the block.
+bool ARMAsmParser::isITBlockTerminator(MCInst &Inst) const {
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+
+ // All branch & call instructions terminate IT blocks.
+ if (MCID.isTerminator() || MCID.isCall() || MCID.isReturn() ||
+ MCID.isBranch() || MCID.isIndirectBranch())
+ return true;
+
+ // Any arithmetic instruction which writes to the PC also terminates the IT
+ // block.
+ for (unsigned OpIdx = 0; OpIdx < MCID.getNumDefs(); ++OpIdx) {
+ MCOperand &Op = Inst.getOperand(OpIdx);
+ if (Op.isReg() && Op.getReg() == ARM::PC)
+ return true;
+ }
+
+ if (MCID.hasImplicitDefOfPhysReg(ARM::PC, MRI))
+ return true;
+
+ // Instructions with variable operand lists, which write to the variable
+ // operands. We only care about Thumb instructions here, as ARM instructions
+ // obviously can't be in an IT block.
+ switch (Inst.getOpcode()) {
+ case ARM::t2LDMIA:
+ case ARM::t2LDMIA_UPD:
+ case ARM::t2LDMDB:
+ case ARM::t2LDMDB_UPD:
+ if (listContainsReg(Inst, 3, ARM::PC))
+ return true;
+ break;
+ case ARM::tPOP:
+ if (listContainsReg(Inst, 2, ARM::PC))
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm,
+ bool &EmitInITBlock,
+ MCStreamer &Out) {
+ // If we can't use an implicit IT block here, just match as normal.
+ if (inExplicitITBlock() || !isThumbTwo() || !useImplicitITThumb())
+ return MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+
+ // Try to match the instruction in an extension of the current IT block (if
+ // there is one).
+ if (inImplicitITBlock()) {
+ extendImplicitITBlock(ITState.Cond);
+ if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+ Match_Success) {
+ // The match succeded, but we still have to check that the instruction is
+ // valid in this implicit IT block.
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+ if (MCID.isPredicable()) {
+ ARMCC::CondCodes InstCond =
+ (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+ .getImm();
+ ARMCC::CondCodes ITCond = currentITCond();
+ if (InstCond == ITCond) {
+ EmitInITBlock = true;
+ return Match_Success;
+ } else if (InstCond == ARMCC::getOppositeCondition(ITCond)) {
+ invertCurrentITCondition();
+ EmitInITBlock = true;
+ return Match_Success;
+ }
+ }
+ }
+ rewindImplicitITPosition();
+ }
+
+ // Finish the current IT block, and try to match outside any IT block.
+ flushPendingInstructions(Out);
+ unsigned PlainMatchResult =
+ MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+ if (PlainMatchResult == Match_Success) {
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+ if (MCID.isPredicable()) {
+ ARMCC::CondCodes InstCond =
+ (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+ .getImm();
+ // Some forms of the branch instruction have their own condition code
+ // fields, so can be conditionally executed without an IT block.
+ if (Inst.getOpcode() == ARM::tBcc || Inst.getOpcode() == ARM::t2Bcc) {
+ EmitInITBlock = false;
+ return Match_Success;
+ }
+ if (InstCond == ARMCC::AL) {
+ EmitInITBlock = false;
+ return Match_Success;
+ }
+ } else {
+ EmitInITBlock = false;
+ return Match_Success;
+ }
+ }
+
+ // Try to match in a new IT block. The matcher doesn't check the actual
+ // condition, so we create an IT block with a dummy condition, and fix it up
+ // once we know the actual condition.
+ startImplicitITBlock();
+ if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+ Match_Success) {
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+ if (MCID.isPredicable()) {
+ ITState.Cond =
+ (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+ .getImm();
+ EmitInITBlock = true;
+ return Match_Success;
+ }
+ }
+ discardImplicitITBlock();
+
+ // If none of these succeed, return the error we got when trying to match
+ // outside any IT blocks.
+ EmitInITBlock = false;
+ return PlainMatchResult;
+}
+
static const char *getSubtargetFeatureName(uint64_t Val);
bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
@@ -8814,9 +9083,11 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
bool MatchingInlineAsm) {
MCInst Inst;
unsigned MatchResult;
+ bool PendConditionalInstruction = false;
+
+ MatchResult = MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
+ PendConditionalInstruction, Out);
- MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
- MatchingInlineAsm);
switch (MatchResult) {
case Match_Success:
// Context sensitive operand constraints aren't handled by the matcher,
@@ -8856,7 +9127,13 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return false;
Inst.setLoc(IDLoc);
- Out.EmitInstruction(Inst, getSTI());
+ if (PendConditionalInstruction) {
+ PendingConditionalInsts.push_back(Inst);
+ if (isITBlockFull() || isITBlockTerminator(Inst))
+ flushPendingInstructions(Out);
+ } else {
+ Out.EmitInstruction(Inst, getSTI());
+ }
return false;
case Match_MissingFeature: {
assert(ErrorInfo && "Unknown missing feature!");
@@ -8898,6 +9175,8 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return Error(IDLoc, "instruction variant requires Thumb2");
case Match_RequiresV8:
return Error(IDLoc, "instruction variant requires ARMv8 or later");
+ case Match_RequiresFlagSetting:
+ return Error(IDLoc, "no flag-preserving variant of this instruction available");
case Match_ImmRange0_15: {
SMLoc ErrorLoc = ((ARMOperand &)*Operands[ErrorInfo]).getStartLoc();
if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
@@ -8958,78 +9237,79 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
if (IDVal == ".word")
- return parseLiteralValues(4, DirectiveID.getLoc());
+ parseLiteralValues(4, DirectiveID.getLoc());
else if (IDVal == ".short" || IDVal == ".hword")
- return parseLiteralValues(2, DirectiveID.getLoc());
+ parseLiteralValues(2, DirectiveID.getLoc());
else if (IDVal == ".thumb")
- return parseDirectiveThumb(DirectiveID.getLoc());
+ parseDirectiveThumb(DirectiveID.getLoc());
else if (IDVal == ".arm")
- return parseDirectiveARM(DirectiveID.getLoc());
+ parseDirectiveARM(DirectiveID.getLoc());
else if (IDVal == ".thumb_func")
- return parseDirectiveThumbFunc(DirectiveID.getLoc());
+ parseDirectiveThumbFunc(DirectiveID.getLoc());
else if (IDVal == ".code")
- return parseDirectiveCode(DirectiveID.getLoc());
+ parseDirectiveCode(DirectiveID.getLoc());
else if (IDVal == ".syntax")
- return parseDirectiveSyntax(DirectiveID.getLoc());
+ parseDirectiveSyntax(DirectiveID.getLoc());
else if (IDVal == ".unreq")
- return parseDirectiveUnreq(DirectiveID.getLoc());
+ parseDirectiveUnreq(DirectiveID.getLoc());
else if (IDVal == ".fnend")
- return parseDirectiveFnEnd(DirectiveID.getLoc());
+ parseDirectiveFnEnd(DirectiveID.getLoc());
else if (IDVal == ".cantunwind")
- return parseDirectiveCantUnwind(DirectiveID.getLoc());
+ parseDirectiveCantUnwind(DirectiveID.getLoc());
else if (IDVal == ".personality")
- return parseDirectivePersonality(DirectiveID.getLoc());
+ parseDirectivePersonality(DirectiveID.getLoc());
else if (IDVal == ".handlerdata")
- return parseDirectiveHandlerData(DirectiveID.getLoc());
+ parseDirectiveHandlerData(DirectiveID.getLoc());
else if (IDVal == ".setfp")
- return parseDirectiveSetFP(DirectiveID.getLoc());
+ parseDirectiveSetFP(DirectiveID.getLoc());
else if (IDVal == ".pad")
- return parseDirectivePad(DirectiveID.getLoc());
+ parseDirectivePad(DirectiveID.getLoc());
else if (IDVal == ".save")
- return parseDirectiveRegSave(DirectiveID.getLoc(), false);
+ parseDirectiveRegSave(DirectiveID.getLoc(), false);
else if (IDVal == ".vsave")
- return parseDirectiveRegSave(DirectiveID.getLoc(), true);
+ parseDirectiveRegSave(DirectiveID.getLoc(), true);
else if (IDVal == ".ltorg" || IDVal == ".pool")
- return parseDirectiveLtorg(DirectiveID.getLoc());
+ parseDirectiveLtorg(DirectiveID.getLoc());
else if (IDVal == ".even")
- return parseDirectiveEven(DirectiveID.getLoc());
+ parseDirectiveEven(DirectiveID.getLoc());
else if (IDVal == ".personalityindex")
- return parseDirectivePersonalityIndex(DirectiveID.getLoc());
+ parseDirectivePersonalityIndex(DirectiveID.getLoc());
else if (IDVal == ".unwind_raw")
- return parseDirectiveUnwindRaw(DirectiveID.getLoc());
+ parseDirectiveUnwindRaw(DirectiveID.getLoc());
else if (IDVal == ".movsp")
- return parseDirectiveMovSP(DirectiveID.getLoc());
+ parseDirectiveMovSP(DirectiveID.getLoc());
else if (IDVal == ".arch_extension")
- return parseDirectiveArchExtension(DirectiveID.getLoc());
+ parseDirectiveArchExtension(DirectiveID.getLoc());
else if (IDVal == ".align")
- return parseDirectiveAlign(DirectiveID.getLoc());
+ return parseDirectiveAlign(DirectiveID.getLoc()); // Use Generic on failure.
else if (IDVal == ".thumb_set")
- return parseDirectiveThumbSet(DirectiveID.getLoc());
-
- if (!IsMachO && !IsCOFF) {
+ parseDirectiveThumbSet(DirectiveID.getLoc());
+ else if (!IsMachO && !IsCOFF) {
if (IDVal == ".arch")
- return parseDirectiveArch(DirectiveID.getLoc());
+ parseDirectiveArch(DirectiveID.getLoc());
else if (IDVal == ".cpu")
- return parseDirectiveCPU(DirectiveID.getLoc());
+ parseDirectiveCPU(DirectiveID.getLoc());
else if (IDVal == ".eabi_attribute")
- return parseDirectiveEabiAttr(DirectiveID.getLoc());
+ parseDirectiveEabiAttr(DirectiveID.getLoc());
else if (IDVal == ".fpu")
- return parseDirectiveFPU(DirectiveID.getLoc());
+ parseDirectiveFPU(DirectiveID.getLoc());
else if (IDVal == ".fnstart")
- return parseDirectiveFnStart(DirectiveID.getLoc());
+ parseDirectiveFnStart(DirectiveID.getLoc());
else if (IDVal == ".inst")
- return parseDirectiveInst(DirectiveID.getLoc());
+ parseDirectiveInst(DirectiveID.getLoc());
else if (IDVal == ".inst.n")
- return parseDirectiveInst(DirectiveID.getLoc(), 'n');
+ parseDirectiveInst(DirectiveID.getLoc(), 'n');
else if (IDVal == ".inst.w")
- return parseDirectiveInst(DirectiveID.getLoc(), 'w');
+ parseDirectiveInst(DirectiveID.getLoc(), 'w');
else if (IDVal == ".object_arch")
- return parseDirectiveObjectArch(DirectiveID.getLoc());
+ parseDirectiveObjectArch(DirectiveID.getLoc());
else if (IDVal == ".tlsdescseq")
- return parseDirectiveTLSDescSeq(DirectiveID.getLoc());
- }
-
- return true;
+ parseDirectiveTLSDescSeq(DirectiveID.getLoc());
+ else
+ return true;
+ } else
+ return true;
+ return false;
}
/// parseLiteralValues
@@ -9037,47 +9317,22 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
/// ::= .short expression [, expression]*
/// ::= .word expression [, expression]*
bool ARMAsmParser::parseLiteralValues(unsigned Size, SMLoc L) {
- MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- for (;;) {
- const MCExpr *Value;
- if (getParser().parseExpression(Value)) {
- Parser.eatToEndOfStatement();
- return false;
- }
-
- getParser().getStreamer().EmitValue(Value, Size, L);
-
- if (getLexer().is(AsmToken::EndOfStatement))
- break;
-
- // FIXME: Improve diagnostic.
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(L, "unexpected token in directive");
- return false;
- }
- Parser.Lex();
- }
- }
-
- Parser.Lex();
- return false;
+ auto parseOne = [&]() -> bool {
+ const MCExpr *Value;
+ if (getParser().parseExpression(Value))
+ return true;
+ getParser().getStreamer().EmitValue(Value, Size, L);
+ return false;
+ };
+ return (parseMany(parseOne));
}
/// parseDirectiveThumb
/// ::= .thumb
bool ARMAsmParser::parseDirectiveThumb(SMLoc L) {
- MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(L, "unexpected token in directive");
- return false;
- }
- Parser.Lex();
-
- if (!hasThumb()) {
- Error(L, "target does not support Thumb mode");
- return false;
- }
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive") ||
+ check(!hasThumb(), L, "target does not support Thumb mode"))
+ return true;
if (!isThumb())
SwitchMode();
@@ -9089,26 +9344,20 @@ bool ARMAsmParser::parseDirectiveThumb(SMLoc L) {
/// parseDirectiveARM
/// ::= .arm
bool ARMAsmParser::parseDirectiveARM(SMLoc L) {
- MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(L, "unexpected token in directive");
- return false;
- }
- Parser.Lex();
-
- if (!hasARM()) {
- Error(L, "target does not support ARM mode");
- return false;
- }
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive") ||
+ check(!hasARM(), L, "target does not support ARM mode"))
+ return true;
if (isThumb())
SwitchMode();
-
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
return false;
}
void ARMAsmParser::onLabelParsed(MCSymbol *Symbol) {
+ // We need to flush the current implicit IT block on a label, because it is
+ // not legal to branch into an IT block.
+ flushPendingInstructions(getStreamer());
if (NextSymbolIsThumb) {
getParser().getStreamer().EmitThumbFunc(Symbol);
NextSymbolIsThumb = false;
@@ -9124,27 +9373,24 @@ bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) {
// Darwin asm has (optionally) function name after .thumb_func direction
// ELF doesn't
- if (IsMachO) {
- const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::EndOfStatement)) {
- if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) {
- Error(L, "unexpected token in .thumb_func directive");
- return false;
- }
- MCSymbol *Func =
- getParser().getContext().getOrCreateSymbol(Tok.getIdentifier());
+ if (IsMachO) {
+ if (Parser.getTok().is(AsmToken::Identifier) ||
+ Parser.getTok().is(AsmToken::String)) {
+ MCSymbol *Func = getParser().getContext().getOrCreateSymbol(
+ Parser.getTok().getIdentifier());
getParser().getStreamer().EmitThumbFunc(Func);
- Parser.Lex(); // Consume the identifier token.
+ Parser.Lex();
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.thumb_func' directive"))
+ return true;
return false;
}
}
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(), "unexpected token in directive");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.thumb_func' directive"))
+ return true;
NextSymbolIsThumb = true;
return false;
@@ -9161,21 +9407,13 @@ bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) {
}
StringRef Mode = Tok.getString();
- if (Mode == "unified" || Mode == "UNIFIED") {
- Parser.Lex();
- } else if (Mode == "divided" || Mode == "DIVIDED") {
- Error(L, "'.syntax divided' arm asssembly not supported");
- return false;
- } else {
- Error(L, "unrecognized syntax mode in .syntax directive");
- return false;
- }
-
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(), "unexpected token in directive");
- return false;
- }
Parser.Lex();
+ if (check(Mode == "divided" || Mode == "DIVIDED", L,
+ "'.syntax divided' arm assembly not supported") ||
+ check(Mode != "unified" && Mode != "UNIFIED", L,
+ "unrecognized syntax mode in .syntax directive") ||
+ parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
// TODO tell the MC streamer the mode
// getParser().getStreamer().Emit???();
@@ -9187,10 +9425,8 @@ bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) {
bool ARMAsmParser::parseDirectiveCode(SMLoc L) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::Integer)) {
- Error(L, "unexpected token in .code directive");
- return false;
- }
+ if (Tok.isNot(AsmToken::Integer))
+ return Error(L, "unexpected token in .code directive");
int64_t Val = Parser.getTok().getIntVal();
if (Val != 16 && Val != 32) {
Error(L, "invalid operand to .code directive");
@@ -9198,26 +9434,19 @@ bool ARMAsmParser::parseDirectiveCode(SMLoc L) {
}
Parser.Lex();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(), "unexpected token in directive");
- return false;
- }
- Parser.Lex();
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
if (Val == 16) {
- if (!hasThumb()) {
- Error(L, "target does not support Thumb mode");
- return false;
- }
+ if (!hasThumb())
+ return Error(L, "target does not support Thumb mode");
if (!isThumb())
SwitchMode();
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
} else {
- if (!hasARM()) {
- Error(L, "target does not support ARM mode");
- return false;
- }
+ if (!hasARM())
+ return Error(L, "target does not support ARM mode");
if (isThumb())
SwitchMode();
@@ -9234,25 +9463,15 @@ bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
Parser.Lex(); // Eat the '.req' token.
unsigned Reg;
SMLoc SRegLoc, ERegLoc;
- if (ParseRegister(Reg, SRegLoc, ERegLoc)) {
- Parser.eatToEndOfStatement();
- Error(SRegLoc, "register name expected");
- return false;
- }
-
- // Shouldn't be anything else.
- if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
- Parser.eatToEndOfStatement();
- Error(Parser.getTok().getLoc(), "unexpected input in .req directive.");
- return false;
- }
-
- Parser.Lex(); // Consume the EndOfStatement
+ if (check(ParseRegister(Reg, SRegLoc, ERegLoc), SRegLoc,
+ "register name expected") ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected input in .req directive."))
+ return true;
- if (RegisterReqs.insert(std::make_pair(Name, Reg)).first->second != Reg) {
- Error(SRegLoc, "redefinition of '" + Name + "' does not match original.");
- return false;
- }
+ if (RegisterReqs.insert(std::make_pair(Name, Reg)).first->second != Reg)
+ return Error(SRegLoc,
+ "redefinition of '" + Name + "' does not match original.");
return false;
}
@@ -9261,13 +9480,13 @@ bool ARMAsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
/// ::= .unreq registername
bool ARMAsmParser::parseDirectiveUnreq(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (Parser.getTok().isNot(AsmToken::Identifier)) {
- Parser.eatToEndOfStatement();
- Error(L, "unexpected input in .unreq directive.");
- return false;
- }
+ if (Parser.getTok().isNot(AsmToken::Identifier))
+ return Error(L, "unexpected input in .unreq directive.");
RegisterReqs.erase(Parser.getTok().getIdentifier().lower());
Parser.Lex(); // Eat the identifier.
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected input in '.unreq' directive"))
+ return true;
return false;
}
@@ -9300,13 +9519,10 @@ void ARMAsmParser::FixModeAfterArchChange(bool WasThumb, SMLoc Loc) {
/// ::= .arch token
bool ARMAsmParser::parseDirectiveArch(SMLoc L) {
StringRef Arch = getParser().parseStringToEndOfStatement().trim();
-
unsigned ID = ARM::parseArch(Arch);
- if (ID == ARM::AK_INVALID) {
- Error(L, "Unknown arch name");
- return false;
- }
+ if (ID == ARM::AK_INVALID)
+ return Error(L, "Unknown arch name");
bool WasThumb = isThumb();
Triple T;
@@ -9332,7 +9548,6 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
Tag = ARMBuildAttrs::AttrTypeFromString(Name);
if (Tag == -1) {
Error(TagLoc, "attribute name not recognised: " + Name);
- Parser.eatToEndOfStatement();
return false;
}
Parser.Lex();
@@ -9340,27 +9555,18 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
const MCExpr *AttrExpr;
TagLoc = Parser.getTok().getLoc();
- if (Parser.parseExpression(AttrExpr)) {
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (Parser.parseExpression(AttrExpr))
+ return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
- if (!CE) {
- Error(TagLoc, "expected numeric constant");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (check(!CE, TagLoc, "expected numeric constant"))
+ return true;
Tag = CE->getValue();
}
- if (Parser.getTok().isNot(AsmToken::Comma)) {
- Error(Parser.getTok().getLoc(), "comma expected");
- Parser.eatToEndOfStatement();
- return false;
- }
- Parser.Lex(); // skip comma
+ if (Parser.parseToken(AsmToken::Comma, "comma expected"))
+ return true;
StringRef StringValue = "";
bool IsStringValue = false;
@@ -9383,44 +9589,32 @@ bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
if (IsIntegerValue) {
const MCExpr *ValueExpr;
SMLoc ValueExprLoc = Parser.getTok().getLoc();
- if (Parser.parseExpression(ValueExpr)) {
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (Parser.parseExpression(ValueExpr))
+ return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr);
- if (!CE) {
- Error(ValueExprLoc, "expected numeric constant");
- Parser.eatToEndOfStatement();
- return false;
- }
-
+ if (!CE)
+ return Error(ValueExprLoc, "expected numeric constant");
IntegerValue = CE->getValue();
}
if (Tag == ARMBuildAttrs::compatibility) {
- if (Parser.getTok().isNot(AsmToken::Comma))
- IsStringValue = false;
- if (Parser.getTok().isNot(AsmToken::Comma)) {
- Error(Parser.getTok().getLoc(), "comma expected");
- Parser.eatToEndOfStatement();
- return false;
- } else {
- Parser.Lex();
- }
+ if (Parser.parseToken(AsmToken::Comma, "comma expected"))
+ return true;
}
if (IsStringValue) {
- if (Parser.getTok().isNot(AsmToken::String)) {
- Error(Parser.getTok().getLoc(), "bad string constant");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (Parser.getTok().isNot(AsmToken::String))
+ return Error(Parser.getTok().getLoc(), "bad string constant");
StringValue = Parser.getTok().getStringContents();
Parser.Lex();
}
+ if (Parser.parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.eabi_attribute' directive"))
+ return true;
+
if (IsIntegerValue && IsStringValue) {
assert(Tag == ARMBuildAttrs::compatibility);
getTargetStreamer().emitIntTextAttribute(Tag, IntegerValue, StringValue);
@@ -9439,10 +9633,8 @@ bool ARMAsmParser::parseDirectiveCPU(SMLoc L) {
// FIXME: This is using table-gen data, but should be moved to
// ARMTargetParser once that is table-gen'd.
- if (!getSTI().isCPUStringValid(CPU)) {
- Error(L, "Unknown CPU name");
- return false;
- }
+ if (!getSTI().isCPUStringValid(CPU))
+ return Error(L, "Unknown CPU name");
bool WasThumb = isThumb();
MCSubtargetInfo &STI = copySTI();
@@ -9459,11 +9651,9 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
StringRef FPU = getParser().parseStringToEndOfStatement().trim();
unsigned ID = ARM::parseFPU(FPU);
- std::vector<const char *> Features;
- if (!ARM::getFPUFeatures(ID, Features)) {
- Error(FPUNameLoc, "Unknown FPU name");
- return false;
- }
+ std::vector<StringRef> Features;
+ if (!ARM::getFPUFeatures(ID, Features))
+ return Error(FPUNameLoc, "Unknown FPU name");
MCSubtargetInfo &STI = copySTI();
for (auto Feature : Features)
@@ -9477,10 +9667,14 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
/// parseDirectiveFnStart
/// ::= .fnstart
bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.fnstart' directive"))
+ return true;
+
if (UC.hasFnStart()) {
Error(L, ".fnstart starts before the end of previous one");
UC.emitFnStartLocNotes();
- return false;
+ return true;
}
// Reset the unwind directives parser state
@@ -9495,11 +9689,12 @@ bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) {
/// parseDirectiveFnEnd
/// ::= .fnend
bool ARMAsmParser::parseDirectiveFnEnd(SMLoc L) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.fnend' directive"))
+ return true;
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .fnend directive");
- return false;
- }
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .fnend directive");
// Reset the unwind directives parser state
getTargetStreamer().emitFnEnd();
@@ -9511,22 +9706,24 @@ bool ARMAsmParser::parseDirectiveFnEnd(SMLoc L) {
/// parseDirectiveCantUnwind
/// ::= .cantunwind
bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) {
- UC.recordCantUnwind(L);
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cantunwind' directive"))
+ return true;
+ UC.recordCantUnwind(L);
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .cantunwind directive");
- return false;
- }
+ if (check(!UC.hasFnStart(), L, ".fnstart must precede .cantunwind directive"))
+ return true;
+
if (UC.hasHandlerData()) {
Error(L, ".cantunwind can't be used with .handlerdata directive");
UC.emitHandlerDataLocNotes();
- return false;
+ return true;
}
if (UC.hasPersonality()) {
Error(L, ".cantunwind can't be used with .personality directive");
UC.emitPersonalityLocNotes();
- return false;
+ return true;
}
getTargetStreamer().emitCantUnwind();
@@ -9539,38 +9736,36 @@ bool ARMAsmParser::parseDirectivePersonality(SMLoc L) {
MCAsmParser &Parser = getParser();
bool HasExistingPersonality = UC.hasPersonality();
+ // Parse the name of the personality routine
+ if (Parser.getTok().isNot(AsmToken::Identifier))
+ return Error(L, "unexpected input in .personality directive.");
+ StringRef Name(Parser.getTok().getIdentifier());
+ Parser.Lex();
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.personality' directive"))
+ return true;
+
UC.recordPersonality(L);
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .personality directive");
- return false;
- }
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .personality directive");
if (UC.cantUnwind()) {
Error(L, ".personality can't be used with .cantunwind directive");
UC.emitCantUnwindLocNotes();
- return false;
+ return true;
}
if (UC.hasHandlerData()) {
Error(L, ".personality must precede .handlerdata directive");
UC.emitHandlerDataLocNotes();
- return false;
+ return true;
}
if (HasExistingPersonality) {
- Parser.eatToEndOfStatement();
Error(L, "multiple personality directives");
UC.emitPersonalityLocNotes();
- return false;
- }
-
- // Parse the name of the personality routine
- if (Parser.getTok().isNot(AsmToken::Identifier)) {
- Parser.eatToEndOfStatement();
- Error(L, "unexpected input in .personality directive.");
- return false;
+ return true;
}
- StringRef Name(Parser.getTok().getIdentifier());
- Parser.Lex();
MCSymbol *PR = getParser().getContext().getOrCreateSymbol(Name);
getTargetStreamer().emitPersonality(PR);
@@ -9580,17 +9775,18 @@ bool ARMAsmParser::parseDirectivePersonality(SMLoc L) {
/// parseDirectiveHandlerData
/// ::= .handlerdata
bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) {
- UC.recordHandlerData(L);
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.handlerdata' directive"))
+ return true;
+ UC.recordHandlerData(L);
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .personality directive");
- return false;
- }
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .personality directive");
if (UC.cantUnwind()) {
Error(L, ".handlerdata can't be used with .cantunwind directive");
UC.emitCantUnwindLocNotes();
- return false;
+ return true;
}
getTargetStreamer().emitHandlerData();
@@ -9602,74 +9798,52 @@ bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) {
bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) {
MCAsmParser &Parser = getParser();
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .setfp directive");
- return false;
- }
- if (UC.hasHandlerData()) {
- Error(L, ".setfp must precede .handlerdata directive");
- return false;
- }
+ if (check(!UC.hasFnStart(), L, ".fnstart must precede .setfp directive") ||
+ check(UC.hasHandlerData(), L,
+ ".setfp must precede .handlerdata directive"))
+ return true;
// Parse fpreg
SMLoc FPRegLoc = Parser.getTok().getLoc();
int FPReg = tryParseRegister();
- if (FPReg == -1) {
- Error(FPRegLoc, "frame pointer register expected");
- return false;
- }
- // Consume comma
- if (Parser.getTok().isNot(AsmToken::Comma)) {
- Error(Parser.getTok().getLoc(), "comma expected");
- return false;
- }
- Parser.Lex(); // skip comma
+ if (check(FPReg == -1, FPRegLoc, "frame pointer register expected") ||
+ Parser.parseToken(AsmToken::Comma, "comma expected"))
+ return true;
// Parse spreg
SMLoc SPRegLoc = Parser.getTok().getLoc();
int SPReg = tryParseRegister();
- if (SPReg == -1) {
- Error(SPRegLoc, "stack pointer register expected");
- return false;
- }
-
- if (SPReg != ARM::SP && SPReg != UC.getFPReg()) {
- Error(SPRegLoc, "register should be either $sp or the latest fp register");
- return false;
- }
+ if (check(SPReg == -1, SPRegLoc, "stack pointer register expected") ||
+ check(SPReg != ARM::SP && SPReg != UC.getFPReg(), SPRegLoc,
+ "register should be either $sp or the latest fp register"))
+ return true;
// Update the frame pointer register
UC.saveFPReg(FPReg);
// Parse offset
int64_t Offset = 0;
- if (Parser.getTok().is(AsmToken::Comma)) {
- Parser.Lex(); // skip comma
-
+ if (Parser.parseOptionalToken(AsmToken::Comma)) {
if (Parser.getTok().isNot(AsmToken::Hash) &&
- Parser.getTok().isNot(AsmToken::Dollar)) {
- Error(Parser.getTok().getLoc(), "'#' expected");
- return false;
- }
+ Parser.getTok().isNot(AsmToken::Dollar))
+ return Error(Parser.getTok().getLoc(), "'#' expected");
Parser.Lex(); // skip hash token.
const MCExpr *OffsetExpr;
SMLoc ExLoc = Parser.getTok().getLoc();
SMLoc EndLoc;
- if (getParser().parseExpression(OffsetExpr, EndLoc)) {
- Error(ExLoc, "malformed setfp offset");
- return false;
- }
+ if (getParser().parseExpression(OffsetExpr, EndLoc))
+ return Error(ExLoc, "malformed setfp offset");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
- if (!CE) {
- Error(ExLoc, "setfp offset must be an immediate");
- return false;
- }
-
+ if (check(!CE, ExLoc, "setfp offset must be an immediate"))
+ return true;
Offset = CE->getValue();
}
+ if (Parser.parseToken(AsmToken::EndOfStatement))
+ return true;
+
getTargetStreamer().emitSetFP(static_cast<unsigned>(FPReg),
static_cast<unsigned>(SPReg), Offset);
return false;
@@ -9680,35 +9854,29 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) {
bool ARMAsmParser::parseDirectivePad(SMLoc L) {
MCAsmParser &Parser = getParser();
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .pad directive");
- return false;
- }
- if (UC.hasHandlerData()) {
- Error(L, ".pad must precede .handlerdata directive");
- return false;
- }
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .pad directive");
+ if (UC.hasHandlerData())
+ return Error(L, ".pad must precede .handlerdata directive");
// Parse the offset
if (Parser.getTok().isNot(AsmToken::Hash) &&
- Parser.getTok().isNot(AsmToken::Dollar)) {
- Error(Parser.getTok().getLoc(), "'#' expected");
- return false;
- }
+ Parser.getTok().isNot(AsmToken::Dollar))
+ return Error(Parser.getTok().getLoc(), "'#' expected");
Parser.Lex(); // skip hash token.
const MCExpr *OffsetExpr;
SMLoc ExLoc = Parser.getTok().getLoc();
SMLoc EndLoc;
- if (getParser().parseExpression(OffsetExpr, EndLoc)) {
- Error(ExLoc, "malformed pad offset");
- return false;
- }
+ if (getParser().parseExpression(OffsetExpr, EndLoc))
+ return Error(ExLoc, "malformed pad offset");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
- if (!CE) {
- Error(ExLoc, "pad offset must be an immediate");
- return false;
- }
+ if (!CE)
+ return Error(ExLoc, "pad offset must be an immediate");
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.pad' directive"))
+ return true;
getTargetStreamer().emitPad(CE->getValue());
return false;
@@ -9719,30 +9887,23 @@ bool ARMAsmParser::parseDirectivePad(SMLoc L) {
/// ::= .vsave { registers }
bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) {
// Check the ordering of unwind directives
- if (!UC.hasFnStart()) {
- Error(L, ".fnstart must precede .save or .vsave directives");
- return false;
- }
- if (UC.hasHandlerData()) {
- Error(L, ".save or .vsave must precede .handlerdata directive");
- return false;
- }
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .save or .vsave directives");
+ if (UC.hasHandlerData())
+ return Error(L, ".save or .vsave must precede .handlerdata directive");
// RAII object to make sure parsed operands are deleted.
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands;
// Parse the register list
- if (parseRegisterList(Operands))
- return false;
+ if (parseRegisterList(Operands) ||
+ parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
ARMOperand &Op = (ARMOperand &)*Operands[0];
- if (!IsVector && !Op.isRegList()) {
- Error(L, ".save expects GPR registers");
- return false;
- }
- if (IsVector && !Op.isDPRRegList()) {
- Error(L, ".vsave expects DPR registers");
- return false;
- }
+ if (!IsVector && !Op.isRegList())
+ return Error(L, ".save expects GPR registers");
+ if (IsVector && !Op.isDPRRegList())
+ return Error(L, ".vsave expects DPR registers");
getTargetStreamer().emitRegSave(Op.getRegList(), IsVector);
return false;
@@ -9753,8 +9914,7 @@ bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) {
/// ::= .inst.n opcode [, ...]
/// ::= .inst.w opcode [, ...]
bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) {
- MCAsmParser &Parser = getParser();
- int Width;
+ int Width = 4;
if (isThumb()) {
switch (Suffix) {
@@ -9762,96 +9922,68 @@ bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) {
Width = 2;
break;
case 'w':
- Width = 4;
break;
default:
- Parser.eatToEndOfStatement();
- Error(Loc, "cannot determine Thumb instruction size, "
- "use inst.n/inst.w instead");
- return false;
+ return Error(Loc, "cannot determine Thumb instruction size, "
+ "use inst.n/inst.w instead");
}
} else {
- if (Suffix) {
- Parser.eatToEndOfStatement();
- Error(Loc, "width suffixes are invalid in ARM mode");
- return false;
- }
- Width = 4;
- }
-
- if (getLexer().is(AsmToken::EndOfStatement)) {
- Parser.eatToEndOfStatement();
- Error(Loc, "expected expression following directive");
- return false;
+ if (Suffix)
+ return Error(Loc, "width suffixes are invalid in ARM mode");
}
- for (;;) {
+ auto parseOne = [&]() -> bool {
const MCExpr *Expr;
-
- if (getParser().parseExpression(Expr)) {
- Error(Loc, "expected expression");
- return false;
- }
-
+ if (getParser().parseExpression(Expr))
+ return true;
const MCConstantExpr *Value = dyn_cast_or_null<MCConstantExpr>(Expr);
if (!Value) {
- Error(Loc, "expected constant expression");
- return false;
+ return Error(Loc, "expected constant expression");
}
switch (Width) {
case 2:
- if (Value->getValue() > 0xffff) {
- Error(Loc, "inst.n operand is too big, use inst.w instead");
- return false;
- }
+ if (Value->getValue() > 0xffff)
+ return Error(Loc, "inst.n operand is too big, use inst.w instead");
break;
case 4:
- if (Value->getValue() > 0xffffffff) {
- Error(Loc,
- StringRef(Suffix ? "inst.w" : "inst") + " operand is too big");
- return false;
- }
+ if (Value->getValue() > 0xffffffff)
+ return Error(Loc, StringRef(Suffix ? "inst.w" : "inst") +
+ " operand is too big");
break;
default:
llvm_unreachable("only supported widths are 2 and 4");
}
getTargetStreamer().emitInst(Value->getValue(), Suffix);
+ return false;
+ };
- if (getLexer().is(AsmToken::EndOfStatement))
- break;
-
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(Loc, "unexpected token in directive");
- return false;
- }
-
- Parser.Lex();
- }
-
- Parser.Lex();
+ if (parseOptionalToken(AsmToken::EndOfStatement))
+ return Error(Loc, "expected expression following directive");
+ if (parseMany(parseOne))
+ return true;
return false;
}
/// parseDirectiveLtorg
/// ::= .ltorg | .pool
bool ARMAsmParser::parseDirectiveLtorg(SMLoc L) {
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
getTargetStreamer().emitCurrentConstantPool();
return false;
}
bool ARMAsmParser::parseDirectiveEven(SMLoc L) {
- const MCSection *Section = getStreamer().getCurrentSection().first;
+ const MCSection *Section = getStreamer().getCurrentSectionOnly();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- TokError("unexpected token in directive");
- return false;
- }
+ if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive"))
+ return true;
if (!Section) {
getStreamer().InitSections(false);
- Section = getStreamer().getCurrentSection().first;
+ Section = getStreamer().getCurrentSectionOnly();
}
assert(Section && "must have section to emit alignment");
@@ -9869,51 +10001,41 @@ bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) {
MCAsmParser &Parser = getParser();
bool HasExistingPersonality = UC.hasPersonality();
+ const MCExpr *IndexExpression;
+ SMLoc IndexLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(IndexExpression) ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.personalityindex' directive")) {
+ return true;
+ }
+
UC.recordPersonalityIndex(L);
if (!UC.hasFnStart()) {
- Parser.eatToEndOfStatement();
- Error(L, ".fnstart must precede .personalityindex directive");
- return false;
+ return Error(L, ".fnstart must precede .personalityindex directive");
}
if (UC.cantUnwind()) {
- Parser.eatToEndOfStatement();
Error(L, ".personalityindex cannot be used with .cantunwind");
UC.emitCantUnwindLocNotes();
- return false;
+ return true;
}
if (UC.hasHandlerData()) {
- Parser.eatToEndOfStatement();
Error(L, ".personalityindex must precede .handlerdata directive");
UC.emitHandlerDataLocNotes();
- return false;
+ return true;
}
if (HasExistingPersonality) {
- Parser.eatToEndOfStatement();
Error(L, "multiple personality directives");
UC.emitPersonalityLocNotes();
- return false;
- }
-
- const MCExpr *IndexExpression;
- SMLoc IndexLoc = Parser.getTok().getLoc();
- if (Parser.parseExpression(IndexExpression)) {
- Parser.eatToEndOfStatement();
- return false;
+ return true;
}
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(IndexExpression);
- if (!CE) {
- Parser.eatToEndOfStatement();
- Error(IndexLoc, "index must be a constant number");
- return false;
- }
- if (CE->getValue() < 0 ||
- CE->getValue() >= ARM::EHABI::NUM_PERSONALITY_INDEX) {
- Parser.eatToEndOfStatement();
- Error(IndexLoc, "personality routine index should be in range [0-3]");
- return false;
- }
+ if (!CE)
+ return Error(IndexLoc, "index must be a constant number");
+ if (CE->getValue() < 0 || CE->getValue() >= ARM::EHABI::NUM_PERSONALITY_INDEX)
+ return Error(IndexLoc,
+ "personality routine index should be in range [0-3]");
getTargetStreamer().emitPersonalityIndex(CE->getValue());
return false;
@@ -9923,81 +10045,51 @@ bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) {
/// ::= .unwind_raw offset, opcode [, opcode...]
bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (!UC.hasFnStart()) {
- Parser.eatToEndOfStatement();
- Error(L, ".fnstart must precede .unwind_raw directives");
- return false;
- }
-
int64_t StackOffset;
-
const MCExpr *OffsetExpr;
SMLoc OffsetLoc = getLexer().getLoc();
- if (getLexer().is(AsmToken::EndOfStatement) ||
- getParser().parseExpression(OffsetExpr)) {
- Error(OffsetLoc, "expected expression");
- Parser.eatToEndOfStatement();
- return false;
- }
+
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .unwind_raw directives");
+ if (getParser().parseExpression(OffsetExpr))
+ return Error(OffsetLoc, "expected expression");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
- if (!CE) {
- Error(OffsetLoc, "offset must be a constant");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (!CE)
+ return Error(OffsetLoc, "offset must be a constant");
StackOffset = CE->getValue();
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(getLexer().getLoc(), "expected comma");
- Parser.eatToEndOfStatement();
- return false;
- }
- Parser.Lex();
+ if (Parser.parseToken(AsmToken::Comma, "expected comma"))
+ return true;
SmallVector<uint8_t, 16> Opcodes;
- for (;;) {
- const MCExpr *OE;
+ auto parseOne = [&]() -> bool {
+ const MCExpr *OE;
SMLoc OpcodeLoc = getLexer().getLoc();
- if (getLexer().is(AsmToken::EndOfStatement) || Parser.parseExpression(OE)) {
- Error(OpcodeLoc, "expected opcode expression");
- Parser.eatToEndOfStatement();
- return false;
- }
-
+ if (check(getLexer().is(AsmToken::EndOfStatement) ||
+ Parser.parseExpression(OE),
+ OpcodeLoc, "expected opcode expression"))
+ return true;
const MCConstantExpr *OC = dyn_cast<MCConstantExpr>(OE);
- if (!OC) {
- Error(OpcodeLoc, "opcode value must be a constant");
- Parser.eatToEndOfStatement();
- return false;
- }
-
+ if (!OC)
+ return Error(OpcodeLoc, "opcode value must be a constant");
const int64_t Opcode = OC->getValue();
- if (Opcode & ~0xff) {
- Error(OpcodeLoc, "invalid opcode");
- Parser.eatToEndOfStatement();
- return false;
- }
-
+ if (Opcode & ~0xff)
+ return Error(OpcodeLoc, "invalid opcode");
Opcodes.push_back(uint8_t(Opcode));
+ return false;
+ };
- if (getLexer().is(AsmToken::EndOfStatement))
- break;
-
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(getLexer().getLoc(), "unexpected token in directive");
- Parser.eatToEndOfStatement();
- return false;
- }
-
- Parser.Lex();
- }
+ // Must have at least 1 element
+ SMLoc OpcodeLoc = getLexer().getLoc();
+ if (parseOptionalToken(AsmToken::EndOfStatement))
+ return Error(OpcodeLoc, "expected opcode expression");
+ if (parseMany(parseOne))
+ return true;
getTargetStreamer().emitUnwindRaw(StackOffset, Opcodes);
-
- Parser.Lex();
return false;
}
@@ -10006,22 +10098,17 @@ bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) {
bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::Identifier)) {
- TokError("expected variable after '.tlsdescseq' directive");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (getLexer().isNot(AsmToken::Identifier))
+ return TokError("expected variable after '.tlsdescseq' directive");
const MCSymbolRefExpr *SRE =
MCSymbolRefExpr::create(Parser.getTok().getIdentifier(),
MCSymbolRefExpr::VK_ARM_TLSDESCSEQ, getContext());
Lex();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(), "unexpected token");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.tlsdescseq' directive"))
+ return true;
getTargetStreamer().AnnotateTLSDescriptorSequence(SRE);
return false;
@@ -10031,60 +10118,40 @@ bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) {
/// ::= .movsp reg [, #offset]
bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (!UC.hasFnStart()) {
- Parser.eatToEndOfStatement();
- Error(L, ".fnstart must precede .movsp directives");
- return false;
- }
- if (UC.getFPReg() != ARM::SP) {
- Parser.eatToEndOfStatement();
- Error(L, "unexpected .movsp directive");
- return false;
- }
+ if (!UC.hasFnStart())
+ return Error(L, ".fnstart must precede .movsp directives");
+ if (UC.getFPReg() != ARM::SP)
+ return Error(L, "unexpected .movsp directive");
SMLoc SPRegLoc = Parser.getTok().getLoc();
int SPReg = tryParseRegister();
- if (SPReg == -1) {
- Parser.eatToEndOfStatement();
- Error(SPRegLoc, "register expected");
- return false;
- }
-
- if (SPReg == ARM::SP || SPReg == ARM::PC) {
- Parser.eatToEndOfStatement();
- Error(SPRegLoc, "sp and pc are not permitted in .movsp directive");
- return false;
- }
+ if (SPReg == -1)
+ return Error(SPRegLoc, "register expected");
+ if (SPReg == ARM::SP || SPReg == ARM::PC)
+ return Error(SPRegLoc, "sp and pc are not permitted in .movsp directive");
int64_t Offset = 0;
- if (Parser.getTok().is(AsmToken::Comma)) {
- Parser.Lex();
-
- if (Parser.getTok().isNot(AsmToken::Hash)) {
- Error(Parser.getTok().getLoc(), "expected #constant");
- Parser.eatToEndOfStatement();
- return false;
- }
- Parser.Lex();
+ if (Parser.parseOptionalToken(AsmToken::Comma)) {
+ if (Parser.parseToken(AsmToken::Hash, "expected #constant"))
+ return true;
const MCExpr *OffsetExpr;
SMLoc OffsetLoc = Parser.getTok().getLoc();
- if (Parser.parseExpression(OffsetExpr)) {
- Parser.eatToEndOfStatement();
- Error(OffsetLoc, "malformed offset expression");
- return false;
- }
+
+ if (Parser.parseExpression(OffsetExpr))
+ return Error(OffsetLoc, "malformed offset expression");
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
- if (!CE) {
- Parser.eatToEndOfStatement();
- Error(OffsetLoc, "offset must be an immediate constant");
- return false;
- }
+ if (!CE)
+ return Error(OffsetLoc, "offset must be an immediate constant");
Offset = CE->getValue();
}
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.movsp' directive"))
+ return true;
+
getTargetStreamer().emitMovSP(SPReg, Offset);
UC.saveFPReg(SPReg);
@@ -10095,11 +10162,8 @@ bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) {
/// ::= .object_arch name
bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::Identifier)) {
- Error(getLexer().getLoc(), "unexpected token");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (getLexer().isNot(AsmToken::Identifier))
+ return Error(getLexer().getLoc(), "unexpected token");
StringRef Arch = Parser.getTok().getString();
SMLoc ArchLoc = Parser.getTok().getLoc();
@@ -10107,19 +10171,12 @@ bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) {
unsigned ID = ARM::parseArch(Arch);
- if (ID == ARM::AK_INVALID) {
- Error(ArchLoc, "unknown architecture '" + Arch + "'");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (ID == ARM::AK_INVALID)
+ return Error(ArchLoc, "unknown architecture '" + Arch + "'");
+ if (parseToken(AsmToken::EndOfStatement))
+ return true;
getTargetStreamer().emitObjectArch(ID);
-
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(getLexer().getLoc(), "unexpected token");
- Parser.eatToEndOfStatement();
- }
-
return false;
}
@@ -10128,18 +10185,17 @@ bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) {
bool ARMAsmParser::parseDirectiveAlign(SMLoc L) {
// NOTE: if this is not the end of the statement, fall back to the target
// agnostic handling for this directive which will correctly handle this.
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return true;
-
- // '.align' is target specifically handled to mean 2**2 byte alignment.
- const MCSection *Section = getStreamer().getCurrentSection().first;
- assert(Section && "must have section to emit alignment");
- if (Section->UseCodeAlign())
- getStreamer().EmitCodeAlignment(4, 0);
- else
- getStreamer().EmitValueToAlignment(4, 0, 1, 0);
-
- return false;
+ if (parseOptionalToken(AsmToken::EndOfStatement)) {
+ // '.align' is target specifically handled to mean 2**2 byte alignment.
+ const MCSection *Section = getStreamer().getCurrentSectionOnly();
+ assert(Section && "must have section to emit alignment");
+ if (Section->UseCodeAlign())
+ getStreamer().EmitCodeAlignment(4, 0);
+ else
+ getStreamer().EmitValueToAlignment(4, 0, 1, 0);
+ return false;
+ }
+ return true;
}
/// parseDirectiveThumbSet
@@ -10148,18 +10204,10 @@ bool ARMAsmParser::parseDirectiveThumbSet(SMLoc L) {
MCAsmParser &Parser = getParser();
StringRef Name;
- if (Parser.parseIdentifier(Name)) {
- TokError("expected identifier after '.thumb_set'");
- Parser.eatToEndOfStatement();
- return false;
- }
-
- if (getLexer().isNot(AsmToken::Comma)) {
- TokError("expected comma after name '" + Name + "'");
- Parser.eatToEndOfStatement();
- return false;
- }
- Lex();
+ if (check(Parser.parseIdentifier(Name),
+ "expected identifier after '.thumb_set'") ||
+ parseToken(AsmToken::Comma, "expected comma after name '" + Name + "'"))
+ return true;
MCSymbol *Sym;
const MCExpr *Value;
@@ -10173,10 +10221,10 @@ bool ARMAsmParser::parseDirectiveThumbSet(SMLoc L) {
/// Force static initialization.
extern "C" void LLVMInitializeARMAsmParser() {
- RegisterMCAsmParser<ARMAsmParser> X(TheARMLETarget);
- RegisterMCAsmParser<ARMAsmParser> Y(TheARMBETarget);
- RegisterMCAsmParser<ARMAsmParser> A(TheThumbLETarget);
- RegisterMCAsmParser<ARMAsmParser> B(TheThumbBETarget);
+ RegisterMCAsmParser<ARMAsmParser> X(getTheARMLETarget());
+ RegisterMCAsmParser<ARMAsmParser> Y(getTheARMBETarget());
+ RegisterMCAsmParser<ARMAsmParser> A(getTheThumbLETarget());
+ RegisterMCAsmParser<ARMAsmParser> B(getTheThumbBETarget());
}
#define GET_REGISTER_MATCHER
@@ -10218,16 +10266,17 @@ static const struct {
bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::Identifier)) {
- Error(getLexer().getLoc(), "unexpected token");
- Parser.eatToEndOfStatement();
- return false;
- }
+ if (getLexer().isNot(AsmToken::Identifier))
+ return Error(getLexer().getLoc(), "expected architecture extension name");
StringRef Name = Parser.getTok().getString();
SMLoc ExtLoc = Parser.getTok().getLoc();
Lex();
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.arch_extension' directive"))
+ return true;
+
bool EnableFeature = true;
if (Name.startswith_lower("no")) {
EnableFeature = false;
@@ -10235,20 +10284,19 @@ bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) {
}
unsigned FeatureKind = ARM::parseArchExt(Name);
if (FeatureKind == ARM::AEK_INVALID)
- Error(ExtLoc, "unknown architectural extension: " + Name);
+ return Error(ExtLoc, "unknown architectural extension: " + Name);
for (const auto &Extension : Extensions) {
if (Extension.Kind != FeatureKind)
continue;
if (Extension.Features.none())
- report_fatal_error("unsupported architectural extension: " + Name);
+ return Error(ExtLoc, "unsupported architectural extension: " + Name);
- if ((getAvailableFeatures() & Extension.ArchCheck) != Extension.ArchCheck) {
- Error(ExtLoc, "architectural extension '" + Name + "' is not "
- "allowed for the current base architecture");
- return false;
- }
+ if ((getAvailableFeatures() & Extension.ArchCheck) != Extension.ArchCheck)
+ return Error(ExtLoc, "architectural extension '" + Name +
+ "' is not "
+ "allowed for the current base architecture");
MCSubtargetInfo &STI = copySTI();
FeatureBitset ToggleFeatures = EnableFeature
@@ -10261,9 +10309,7 @@ bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) {
return false;
}
- Error(ExtLoc, "unknown architectural extension: " + Name);
- Parser.eatToEndOfStatement();
- return false;
+ return Error(ExtLoc, "unknown architectural extension: " + Name);
}
// Define this matcher function after the auto-generated include so we
diff --git a/contrib/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/contrib/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index 3196a57..ac3d8c7 100644
--- a/contrib/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/contrib/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -861,13 +861,13 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
extern "C" void LLVMInitializeARMDisassembler() {
- TargetRegistry::RegisterMCDisassembler(TheARMLETarget,
+ TargetRegistry::RegisterMCDisassembler(getTheARMLETarget(),
createARMDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheARMBETarget,
+ TargetRegistry::RegisterMCDisassembler(getTheARMBETarget(),
createARMDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheThumbLETarget,
+ TargetRegistry::RegisterMCDisassembler(getTheThumbLETarget(),
createThumbDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheThumbBETarget,
+ TargetRegistry::RegisterMCDisassembler(getTheThumbBETarget(),
createThumbDisassembler);
}
@@ -1432,7 +1432,7 @@ static DecodeStatus DecodeCopMemInstruction(MCInst &Inst, unsigned Insn,
case ARM::STC_POST:
case ARM::STCL_POST:
imm |= U << 8;
- // fall through.
+ LLVM_FALLTHROUGH;
default:
// The 'option' variant doesn't encode 'U' in the immediate since
// the immediate is unsigned [0,255].
@@ -2555,6 +2555,7 @@ static DecodeStatus DecodeVLDInstruction(MCInst &Inst, unsigned Insn,
break;
}
// Fall through to handle the register offset variant.
+ LLVM_FALLTHROUGH;
case ARM::VLD1d8wb_fixed:
case ARM::VLD1d16wb_fixed:
case ARM::VLD1d32wb_fixed:
@@ -4157,7 +4158,7 @@ static DecodeStatus DecodeMSRMask(MCInst &Inst, unsigned Val,
case 0x93: // faultmask_ns
if (!(FeatureBits[ARM::HasV8MMainlineOps]))
return MCDisassembler::Fail;
- // fall through
+ LLVM_FALLTHROUGH;
case 10: // msplim
case 11: // psplim
case 0x88: // msp_ns
@@ -5310,4 +5311,3 @@ static DecodeStatus DecoderForMRRC2AndMCRR2(llvm::MCInst &Inst, unsigned Val,
return S;
}
-
diff --git a/contrib/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/contrib/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
index e81bb77..3667952 100644
--- a/contrib/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
@@ -726,6 +726,12 @@ void ARMInstPrinter::printPKHASRShiftImm(const MCInst *MI, unsigned OpNum,
void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
+ assert(std::is_sorted(MI->begin() + OpNum, MI->end(),
+ [&](const MCOperand &LHS, const MCOperand &RHS) {
+ return MRI.getEncodingValue(LHS.getReg()) <
+ MRI.getEncodingValue(RHS.getReg());
+ }));
+
O << "{";
for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) {
if (i != OpNum)
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
index 0fc7582..a58d5b3 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -375,7 +375,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case ARM::fixup_arm_movt_hi16:
if (!IsPCRel)
Value >>= 16;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case ARM::fixup_arm_movw_lo16: {
unsigned Hi4 = (Value & 0xF000) >> 12;
unsigned Lo12 = Value & 0x0FFF;
@@ -387,7 +387,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case ARM::fixup_t2_movt_hi16:
if (!IsPCRel)
Value >>= 16;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case ARM::fixup_t2_movw_lo16: {
unsigned Hi4 = (Value & 0xF000) >> 12;
unsigned i = (Value & 0x800) >> 11;
@@ -403,7 +403,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case ARM::fixup_arm_ldst_pcrel_12:
// ARM PC-relative values are offset by 8.
Value -= 4;
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case ARM::fixup_t2_ldst_pcrel_12: {
// Offset by 4, adjusted by two due to the half-word ordering of thumb.
Value -= 4;
@@ -541,7 +541,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
//
// Note that the halfwords are stored high first, low second; so we need
// to transpose the fixup value here to map properly.
- if (Ctx && Value % 4 != 0) {
+ if (Ctx && Value % 4 != 0) {
Ctx->reportError(Fixup.getLoc(), "misaligned ARM call destination");
return 0;
}
@@ -578,6 +578,13 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
// Offset by 4, and don't encode the low two bits.
return ((Value - 4) >> 2) & 0xff;
case ARM::fixup_arm_thumb_cb: {
+ // CB instructions can only branch to offsets in [4, 126] in multiples of 2
+ // so ensure that the raw value LSB is zero and it lies in [2, 130].
+ // An offset of 2 will be relaxed to a NOP.
+ if (Ctx && ((int64_t)Value < 2 || Value > 0x82 || Value & 1)) {
+ Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ return 0;
+ }
// Offset by 4 and don't encode the lower bit, which is always 0.
// FIXME: diagnose if no Thumb2
uint32_t Binary = (Value - 4) >> 1;
@@ -623,7 +630,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case ARM::fixup_arm_pcrel_10:
Value = Value - 4; // ARM fixups offset by an additional word and don't
// need to adjust for the half-word ordering.
- // Fall through.
+ LLVM_FALLTHROUGH;
case ARM::fixup_t2_pcrel_10: {
// Offset by 4, adjusted by two due to the half-word ordering of thumb.
Value = Value - 4;
@@ -650,7 +657,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case ARM::fixup_arm_pcrel_9:
Value = Value - 4; // ARM fixups offset by an additional word and don't
// need to adjust for the half-word ordering.
- // Fall through.
+ LLVM_FALLTHROUGH;
case ARM::fixup_t2_pcrel_9: {
// Offset by 4, adjusted by two due to the half-word ordering of thumb.
Value = Value - 4;
@@ -696,14 +703,16 @@ void ARMAsmBackend::processFixupValue(const MCAssembler &Asm,
bool &IsResolved) {
const MCSymbolRefExpr *A = Target.getSymA();
const MCSymbol *Sym = A ? &A->getSymbol() : nullptr;
- // Some fixups to thumb function symbols need the low bit (thumb bit)
- // twiddled.
- if ((unsigned)Fixup.getKind() != ARM::fixup_arm_ldst_pcrel_12 &&
- (unsigned)Fixup.getKind() != ARM::fixup_t2_ldst_pcrel_12 &&
- (unsigned)Fixup.getKind() != ARM::fixup_arm_adr_pcrel_12 &&
- (unsigned)Fixup.getKind() != ARM::fixup_thumb_adr_pcrel_10 &&
- (unsigned)Fixup.getKind() != ARM::fixup_t2_adr_pcrel_12 &&
- (unsigned)Fixup.getKind() != ARM::fixup_arm_thumb_cp) {
+ // MachO (the only user of "Value") tries to make .o files that look vaguely
+ // pre-linked, so for MOVW/MOVT and .word relocations they put the Thumb bit
+ // into the addend if possible. Other relocation types don't want this bit
+ // though (branches couldn't encode it if it *was* present, and no other
+ // relocations exist) and it can interfere with checking valid expressions.
+ if ((unsigned)Fixup.getKind() == FK_Data_4 ||
+ (unsigned)Fixup.getKind() == ARM::fixup_arm_movw_lo16 ||
+ (unsigned)Fixup.getKind() == ARM::fixup_arm_movt_hi16 ||
+ (unsigned)Fixup.getKind() == ARM::fixup_t2_movw_lo16 ||
+ (unsigned)Fixup.getKind() == ARM::fixup_t2_movt_hi16) {
if (Sym) {
if (Asm.isThumbFunc(Sym))
Value |= 1;
@@ -1111,6 +1120,7 @@ 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) {
switch (TheTriple.getObjectFormat()) {
default:
@@ -1131,24 +1141,28 @@ MCAsmBackend *llvm::createARMAsmBackend(const Target &T,
MCAsmBackend *llvm::createARMLEAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
- return createARMAsmBackend(T, MRI, TT, CPU, true);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
+ return createARMAsmBackend(T, MRI, TT, CPU, Options, true);
}
MCAsmBackend *llvm::createARMBEAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
- return createARMAsmBackend(T, MRI, TT, CPU, false);
+ 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) {
- return createARMAsmBackend(T, MRI, TT, CPU, true);
+ 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) {
- return createARMAsmBackend(T, MRI, TT, CPU, false);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
+ return createARMAsmBackend(T, MRI, TT, CPU, Options, false);
}
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
index 4118fe8..6f19754 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
@@ -140,6 +140,12 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
case ARM::fixup_t2_movw_lo16:
Type = ELF::R_ARM_THM_MOVW_PREL_NC;
break;
+ case ARM::fixup_arm_thumb_br:
+ Type = ELF::R_ARM_THM_JUMP11;
+ break;
+ case ARM::fixup_arm_thumb_bcc:
+ Type = ELF::R_ARM_THM_JUMP8;
+ break;
case ARM::fixup_arm_thumb_bl:
case ARM::fixup_arm_thumb_blx:
switch (Modifier) {
@@ -221,6 +227,9 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
case MCSymbolRefExpr::VK_TLSDESC:
Type = ELF::R_ARM_TLS_GOTDESC;
break;
+ case MCSymbolRefExpr::VK_TLSLDM:
+ Type = ELF::R_ARM_TLS_LDM32;
+ break;
case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ:
Type = ELF::R_ARM_TLS_DESCSEQ;
break;
@@ -239,10 +248,26 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
Type = ELF::R_ARM_JUMP24;
break;
case ARM::fixup_arm_movt_hi16:
- Type = ELF::R_ARM_MOVT_ABS;
+ switch (Modifier) {
+ default: llvm_unreachable("Unsupported Modifier");
+ case MCSymbolRefExpr::VK_None:
+ Type = ELF::R_ARM_MOVT_ABS;
+ break;
+ case MCSymbolRefExpr::VK_ARM_SBREL:
+ Type = ELF:: R_ARM_MOVT_BREL;
+ break;
+ }
break;
case ARM::fixup_arm_movw_lo16:
- Type = ELF::R_ARM_MOVW_ABS_NC;
+ switch (Modifier) {
+ default: llvm_unreachable("Unsupported Modifier");
+ case MCSymbolRefExpr::VK_None:
+ Type = ELF::R_ARM_MOVW_ABS_NC;
+ break;
+ case MCSymbolRefExpr::VK_ARM_SBREL:
+ Type = ELF:: R_ARM_MOVW_BREL_NC;
+ break;
+ }
break;
case ARM::fixup_t2_movt_hi16:
Type = ELF::R_ARM_THM_MOVT_ABS;
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index 36cb747..f6bb35d 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -591,7 +591,7 @@ private:
void FlushPendingOffset();
void FlushUnwindOpcodes(bool NoHandlerData);
- void SwitchToEHSection(const char *Prefix, unsigned Type, unsigned Flags,
+ void SwitchToEHSection(StringRef Prefix, unsigned Type, unsigned Flags,
SectionKind Kind, const MCSymbol &Fn);
void SwitchToExTabSection(const MCSymbol &FnStart);
void SwitchToExIdxSection(const MCSymbol &FnStart);
@@ -1074,7 +1074,7 @@ void ARMELFStreamer::reset() {
getAssembler().setELFHeaderEFlags(ELF::EF_ARM_EABI_VER5);
}
-inline void ARMELFStreamer::SwitchToEHSection(const char *Prefix,
+inline void ARMELFStreamer::SwitchToEHSection(StringRef Prefix,
unsigned Type,
unsigned Flags,
SectionKind Kind,
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
index 53cd29a..1e062ad 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp
@@ -90,6 +90,7 @@ ARMCOFFMCAsmInfoMicrosoft::ARMCOFFMCAsmInfoMicrosoft() {
PrivateGlobalPrefix = "$M";
PrivateLabelPrefix = "$M";
+ CommentString = ";";
}
void ARMCOFFMCAsmInfoGNU::anchor() { }
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
index 9fca13e..559a4f8 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
@@ -1493,7 +1493,7 @@ getT2SORegOpValue(const MCInst &MI, unsigned OpIdx,
case ARM_AM::lsl: SBits = 0x0; break;
case ARM_AM::lsr: SBits = 0x2; break;
case ARM_AM::asr: SBits = 0x4; break;
- case ARM_AM::rrx: // FALLTHROUGH
+ case ARM_AM::rrx: LLVM_FALLTHROUGH;
case ARM_AM::ror: SBits = 0x6; break;
}
@@ -1545,8 +1545,15 @@ getRegisterListOpValue(const MCInst &MI, unsigned Op,
else
Binary |= NumRegs * 2;
} else {
+ const MCRegisterInfo &MRI = *CTX.getRegisterInfo();
+ assert(std::is_sorted(MI.begin() + Op, MI.end(),
+ [&](const MCOperand &LHS, const MCOperand &RHS) {
+ return MRI.getEncodingValue(LHS.getReg()) <
+ MRI.getEncodingValue(RHS.getReg());
+ }));
+
for (unsigned I = Op, E = MI.getNumOperands(); I < E; ++I) {
- unsigned RegNo = CTX.getRegisterInfo()->getEncodingValue(MI.getOperand(I).getReg());
+ unsigned RegNo = MRI.getEncodingValue(MI.getOperand(I).getReg());
Binary |= 1 << RegNo;
}
}
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
index afb089a..9e4d202 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
@@ -204,7 +204,8 @@ static MCStreamer *createELFStreamer(const Triple &T, MCContext &Ctx,
MCAsmBackend &MAB, raw_pwrite_stream &OS,
MCCodeEmitter *Emitter, bool RelaxAll) {
return createARMELFStreamer(Ctx, MAB, OS, Emitter, false,
- T.getArch() == Triple::thumb);
+ (T.getArch() == Triple::thumb ||
+ T.getArch() == Triple::thumbeb));
}
static MCStreamer *createARMMachOStreamer(MCContext &Ctx, MCAsmBackend &MAB,
@@ -273,8 +274,8 @@ static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) {
// Force static initialization.
extern "C" void LLVMInitializeARMTargetMC() {
- for (Target *T : {&TheARMLETarget, &TheARMBETarget, &TheThumbLETarget,
- &TheThumbBETarget}) {
+ for (Target *T : {&getTheARMLETarget(), &getTheARMBETarget(),
+ &getTheThumbLETarget(), &getTheThumbBETarget()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createARMMCAsmInfo);
@@ -313,16 +314,18 @@ extern "C" void LLVMInitializeARMTargetMC() {
}
// Register the MC Code Emitter
- for (Target *T : {&TheARMLETarget, &TheThumbLETarget})
+ for (Target *T : {&getTheARMLETarget(), &getTheThumbLETarget()})
TargetRegistry::RegisterMCCodeEmitter(*T, createARMLEMCCodeEmitter);
- for (Target *T : {&TheARMBETarget, &TheThumbBETarget})
+ for (Target *T : {&getTheARMBETarget(), &getTheThumbBETarget()})
TargetRegistry::RegisterMCCodeEmitter(*T, createARMBEMCCodeEmitter);
// Register the asm backend.
- TargetRegistry::RegisterMCAsmBackend(TheARMLETarget, createARMLEAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(TheARMBETarget, createARMBEAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(TheThumbLETarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheARMLETarget(),
+ createARMLEAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(getTheARMBETarget(),
+ createARMBEAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(getTheThumbLETarget(),
createThumbLEAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(TheThumbBETarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheThumbBETarget(),
createThumbBEAsmBackend);
}
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
index c2bbc8e..ba83420 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
@@ -28,6 +28,7 @@ class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
class MCStreamer;
+class MCTargetOptions;
class MCRelocationInfo;
class MCTargetStreamer;
class StringRef;
@@ -36,8 +37,10 @@ class Triple;
class raw_ostream;
class raw_pwrite_stream;
-extern Target TheARMLETarget, TheThumbLETarget;
-extern Target TheARMBETarget, TheThumbBETarget;
+Target &getTheARMLETarget();
+Target &getTheThumbLETarget();
+Target &getTheARMBETarget();
+Target &getTheThumbBETarget();
namespace ARM_MC {
std::string ParseARMTriple(const Triple &TT, StringRef CPU);
@@ -66,21 +69,26 @@ MCCodeEmitter *createARMBEMCCodeEmitter(const MCInstrInfo &MCII,
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);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createARMBEAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createThumbLEAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createThumbBEAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
// Construct a PE/COFF machine code streamer which will generate a PE/COFF
// object file.
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
index cfa6ce7..b77181f 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
@@ -208,7 +208,7 @@ RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
if (Asm.isThumbFunc(A))
FixedValue &= 0xfffffffe;
MovtBit = 1;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case ARM::fixup_t2_movw_lo16:
ThumbBit = 1;
break;
diff --git a/contrib/llvm/lib/Target/ARM/MLxExpansionPass.cpp b/contrib/llvm/lib/Target/ARM/MLxExpansionPass.cpp
index 7f21240..744761b 100644
--- a/contrib/llvm/lib/Target/ARM/MLxExpansionPass.cpp
+++ b/contrib/llvm/lib/Target/ARM/MLxExpansionPass.cpp
@@ -43,7 +43,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &Fn) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "ARM MLA / MLS expansion pass";
}
@@ -334,18 +334,15 @@ bool MLxExpansion::ExpandFPMLxInstructions(MachineBasicBlock &MBB) {
unsigned Skip = 0;
MachineBasicBlock::reverse_iterator MII = MBB.rbegin(), E = MBB.rend();
while (MII != E) {
- MachineInstr *MI = &*MII;
+ MachineInstr *MI = &*MII++;
- if (MI->isPosition() || MI->isImplicitDef() || MI->isCopy()) {
- ++MII;
+ if (MI->isPosition() || MI->isImplicitDef() || MI->isCopy())
continue;
- }
const MCInstrDesc &MCID = MI->getDesc();
if (MI->isBarrier()) {
clearStack();
Skip = 0;
- ++MII;
continue;
}
@@ -365,13 +362,9 @@ bool MLxExpansion::ExpandFPMLxInstructions(MachineBasicBlock &MBB) {
pushStack(MI);
else {
ExpandFPMLxInstruction(MBB, MI, MulOpc, AddSubOpc, NegAcc, HasLane);
- E = MBB.rend(); // May have changed if MI was the 1st instruction.
Changed = true;
- continue;
}
}
-
- ++MII;
}
return Changed;
diff --git a/contrib/llvm/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp b/contrib/llvm/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
index 3f88eb8..caa69f8 100644
--- a/contrib/llvm/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/TargetInfo/ARMTargetInfo.cpp
@@ -11,17 +11,31 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheARMLETarget, llvm::TheARMBETarget;
-Target llvm::TheThumbLETarget, llvm::TheThumbBETarget;
+Target &llvm::getTheARMLETarget() {
+ static Target TheARMLETarget;
+ return TheARMLETarget;
+}
+Target &llvm::getTheARMBETarget() {
+ static Target TheARMBETarget;
+ return TheARMBETarget;
+}
+Target &llvm::getTheThumbLETarget() {
+ static Target TheThumbLETarget;
+ return TheThumbLETarget;
+}
+Target &llvm::getTheThumbBETarget() {
+ static Target TheThumbBETarget;
+ return TheThumbBETarget;
+}
extern "C" void LLVMInitializeARMTargetInfo() {
- RegisterTarget<Triple::arm, /*HasJIT=*/true>
- X(TheARMLETarget, "arm", "ARM");
- RegisterTarget<Triple::armeb, /*HasJIT=*/true>
- Y(TheARMBETarget, "armeb", "ARM (big endian)");
+ RegisterTarget<Triple::arm, /*HasJIT=*/true> X(getTheARMLETarget(), "arm",
+ "ARM");
+ RegisterTarget<Triple::armeb, /*HasJIT=*/true> Y(getTheARMBETarget(), "armeb",
+ "ARM (big endian)");
- RegisterTarget<Triple::thumb, /*HasJIT=*/true>
- A(TheThumbLETarget, "thumb", "Thumb");
- RegisterTarget<Triple::thumbeb, /*HasJIT=*/true>
- B(TheThumbBETarget, "thumbeb", "Thumb (big endian)");
+ RegisterTarget<Triple::thumb, /*HasJIT=*/true> A(getTheThumbLETarget(),
+ "thumb", "Thumb");
+ RegisterTarget<Triple::thumbeb, /*HasJIT=*/true> B(
+ getTheThumbBETarget(), "thumbeb", "Thumb (big endian)");
}
diff --git a/contrib/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp b/contrib/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
index c0732e4..9953c61 100644
--- a/contrib/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
+++ b/contrib/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
@@ -26,8 +26,8 @@ Thumb1FrameLowering::Thumb1FrameLowering(const ARMSubtarget &sti)
: ARMFrameLowering(sti) {}
bool Thumb1FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const{
- const MachineFrameInfo *FFI = MF.getFrameInfo();
- unsigned CFSize = FFI->getMaxCallFrameSize();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned CFSize = MFI.getMaxCallFrameSize();
// It's not always a good idea to include the call frame as part of the
// stack frame. ARM (especially Thumb) has small immediate offset to
// address the stack frame. So a large call frame can cause poor codegen
@@ -35,7 +35,7 @@ bool Thumb1FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const{
if (CFSize >= ((1 << 8) - 1) * 4 / 2) // Half of imm8 * 4
return false;
- return !MF.getFrameInfo()->hasVarSizedObjects();
+ return !MFI.hasVarSizedObjects();
}
static void emitSPUpdate(MachineBasicBlock &MBB,
@@ -85,7 +85,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
@@ -95,10 +95,10 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
*static_cast<const Thumb1InstrInfo *>(STI.getInstrInfo());
unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
- unsigned NumBytes = MFI->getStackSize();
+ unsigned NumBytes = MFI.getStackSize();
assert(NumBytes >= ArgRegsSaveSize &&
"ArgRegsSaveSize is included in NumBytes");
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
@@ -110,7 +110,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
// Thumb add/sub sp, imm8 instructions implicitly multiply the offset by 4.
NumBytes = (NumBytes + 3) & ~3;
- MFI->setStackSize(NumBytes);
+ MFI.setStackSize(NumBytes);
// Determine the sizes of each callee-save spill areas and record which frame
// belongs to which callee-save spill areas.
@@ -121,7 +121,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -ArgRegsSaveSize,
MachineInstr::FrameSetup);
CFAOffset -= ArgRegsSaveSize;
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -133,7 +133,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -(NumBytes - ArgRegsSaveSize),
MachineInstr::FrameSetup);
CFAOffset -= NumBytes - ArgRegsSaveSize;
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -150,11 +150,11 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R9:
case ARM::R10:
case ARM::R11:
- if (STI.splitFramePushPop()) {
+ if (STI.splitFramePushPop(MF)) {
GPRCS2Size += 4;
break;
}
- // fallthrough
+ LLVM_FALLTHROUGH;
case ARM::R4:
case ARM::R5:
case ARM::R6:
@@ -179,7 +179,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
bool HasFP = hasFP(MF);
if (HasFP)
- AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) +
+ AFI->setFramePtrSpillOffset(MFI.getObjectOffset(FramePtrSpillFI) +
NumBytes);
AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
@@ -188,7 +188,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
int FramePtrOffsetInBlock = 0;
unsigned adjustedGPRCS1Size = GPRCS1Size;
- if (tryFoldSPUpdateIntoPushPop(STI, MF, &*std::prev(MBBI), NumBytes)) {
+ if (GPRCS1Size > 0 && GPRCS2Size == 0 &&
+ tryFoldSPUpdateIntoPushPop(STI, MF, &*std::prev(MBBI), NumBytes)) {
FramePtrOffsetInBlock = NumBytes;
adjustedGPRCS1Size += NumBytes;
NumBytes = 0;
@@ -196,7 +197,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
if (adjustedGPRCS1Size) {
CFAOffset -= adjustedGPRCS1Size;
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -212,7 +213,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R10:
case ARM::R11:
case ARM::R12:
- if (STI.splitFramePushPop())
+ if (STI.splitFramePushPop(MF))
break;
// fallthough
case ARM::R0:
@@ -224,8 +225,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R6:
case ARM::R7:
case ARM::LR:
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
- nullptr, MRI->getDwarfRegNum(Reg, true), MFI->getObjectOffset(FI)));
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
+ nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
@@ -236,20 +237,20 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
// Adjust FP so it point to the stack slot that contains the previous FP.
if (HasFP) {
FramePtrOffsetInBlock +=
- MFI->getObjectOffset(FramePtrSpillFI) + GPRCS1Size + ArgRegsSaveSize;
+ MFI.getObjectOffset(FramePtrSpillFI) + GPRCS1Size + ArgRegsSaveSize;
AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDrSPi), FramePtr)
.addReg(ARM::SP).addImm(FramePtrOffsetInBlock / 4)
.setMIFlags(MachineInstr::FrameSetup));
if(FramePtrOffsetInBlock) {
CFAOffset += FramePtrOffsetInBlock;
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfa(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(
nullptr, MRI->getDwarfRegNum(FramePtr, true), CFAOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
} else {
unsigned CFIIndex =
- MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(
+ MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FramePtr, true)));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -261,13 +262,55 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
AFI->setShouldRestoreSPFromFP(true);
}
+ // Skip past the spilling of r8-r11, which could consist of multiple tPUSH
+ // and tMOVr instructions. We don't need to add any call frame information
+ // in-between these instructions, because they do not modify the high
+ // registers.
+ while (true) {
+ MachineBasicBlock::iterator OldMBBI = MBBI;
+ // Skip a run of tMOVr instructions
+ while (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tMOVr)
+ MBBI++;
+ if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tPUSH) {
+ MBBI++;
+ } else {
+ // We have reached an instruction which is not a push, so the previous
+ // run of tMOVr instructions (which may have been empty) was not part of
+ // the prologue. Reset MBBI back to the last PUSH of the prologue.
+ MBBI = OldMBBI;
+ break;
+ }
+ }
+
+ // Emit call frame information for the callee-saved high registers.
+ for (auto &I : CSI) {
+ unsigned Reg = I.getReg();
+ int FI = I.getFrameIdx();
+ switch (Reg) {
+ case ARM::R8:
+ case ARM::R9:
+ case ARM::R10:
+ case ARM::R11:
+ case ARM::R12: {
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
+ nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
+ BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex)
+ .setMIFlags(MachineInstr::FrameSetup);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
if (NumBytes) {
// Insert it after all the callee-save spills.
emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -NumBytes,
MachineInstr::FrameSetup);
if (!HasFP) {
CFAOffset -= NumBytes;
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
@@ -276,8 +319,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
}
if (STI.isTargetELF() && HasFP)
- MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() -
- AFI->getFramePtrSpillOffset());
+ MFI.setOffsetAdjustment(MFI.getOffsetAdjustment() -
+ AFI->getFramePtrSpillOffset());
AFI->setGPRCalleeSavedArea1Size(GPRCS1Size);
AFI->setGPRCalleeSavedArea2Size(GPRCS2Size);
@@ -299,7 +342,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
// If the frame has variable sized objects then the epilogue must restore
// the sp from fp. We can assume there's an FP here since hasFP already
// checks for hasVarSizedObjects.
- if (MFI->hasVarSizedObjects())
+ if (MFI.hasVarSizedObjects())
AFI->setShouldRestoreSPFromFP(true);
}
@@ -308,12 +351,12 @@ static bool isCSRestore(MachineInstr &MI, const MCPhysReg *CSRegs) {
isCalleeSavedRegister(MI.getOperand(0).getReg(), CSRegs))
return true;
else if (MI.getOpcode() == ARM::tPOP) {
- // The first two operands are predicates. The last two are
- // imp-def and imp-use of SP. Check everything in between.
- for (int i = 2, e = MI.getNumOperands() - 2; i != e; ++i)
- if (!isCalleeSavedRegister(MI.getOperand(i).getReg(), CSRegs))
- return false;
return true;
+ } else if (MI.getOpcode() == ARM::tMOVr) {
+ unsigned Dst = MI.getOperand(0).getReg();
+ unsigned Src = MI.getOperand(1).getReg();
+ return ((ARM::tGPRRegClass.contains(Src) || Src == ARM::LR) &&
+ ARM::hGPRRegClass.contains(Dst));
}
return false;
}
@@ -322,7 +365,7 @@ void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
const ThumbRegisterInfo *RegInfo =
static_cast<const ThumbRegisterInfo *>(STI.getRegisterInfo());
@@ -330,7 +373,7 @@ void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
*static_cast<const Thumb1InstrInfo *>(STI.getInstrInfo());
unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
- int NumBytes = (int)MFI->getStackSize();
+ int NumBytes = (int)MFI.getStackSize();
assert((unsigned)NumBytes >= ArgRegsSaveSize &&
"ArgRegsSaveSize is included in NumBytes");
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&MF);
@@ -361,7 +404,7 @@ void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
// frame pointer stack slot, the target is ELF and the function has FP, or
// the target uses var sized objects.
if (NumBytes) {
- assert(!MFI->getPristineRegs(MF).test(ARM::R4) &&
+ assert(!MFI.getPristineRegs(MF).test(ARM::R4) &&
"No scratch register to restore SP from FP!");
emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
TII, *RegInfo);
@@ -405,7 +448,7 @@ bool Thumb1FrameLowering::needPopSpecialFixUp(const MachineFunction &MF) const {
return true;
// LR cannot be encoded with Thumb1, i.e., it requires a special fix-up.
- for (const CalleeSavedInfo &CSI : MF.getFrameInfo()->getCalleeSavedInfo())
+ for (const CalleeSavedInfo &CSI : MF.getFrameInfo().getCalleeSavedInfo())
if (CSI.getReg() == ARM::LR)
return true;
@@ -568,6 +611,19 @@ bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB,
return true;
}
+// Return the first iteraror after CurrentReg which is present in EnabledRegs,
+// or OrderEnd if no further registers are in that set. This does not advance
+// the iterator fiorst, so returns CurrentReg if it is in EnabledRegs.
+template <unsigned SetSize>
+static const unsigned *
+findNextOrderedReg(const unsigned *CurrentReg,
+ SmallSet<unsigned, SetSize> &EnabledRegs,
+ const unsigned *OrderEnd) {
+ while (CurrentReg != OrderEnd && !EnabledRegs.count(*CurrentReg))
+ ++CurrentReg;
+ return CurrentReg;
+}
+
bool Thumb1FrameLowering::
spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
@@ -578,29 +634,114 @@ spillCalleeSavedRegisters(MachineBasicBlock &MBB,
DebugLoc DL;
const TargetInstrInfo &TII = *STI.getInstrInfo();
+ MachineFunction &MF = *MBB.getParent();
+ const ARMBaseRegisterInfo *RegInfo = static_cast<const ARMBaseRegisterInfo *>(
+ MF.getSubtarget().getRegisterInfo());
+
+ SmallSet<unsigned, 9> LoRegsToSave; // r0-r7, lr
+ SmallSet<unsigned, 4> HiRegsToSave; // r8-r11
+ SmallSet<unsigned, 9> CopyRegs; // Registers which can be used after pushing
+ // LoRegs for saving HiRegs.
- MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(ARM::tPUSH));
- AddDefaultPred(MIB);
for (unsigned i = CSI.size(); i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
- bool isKill = true;
- // Add the callee-saved register as live-in unless it's LR and
- // @llvm.returnaddress is called. If LR is returned for @llvm.returnaddress
- // then it's already added to the function and entry block live-in sets.
- if (Reg == ARM::LR) {
- MachineFunction &MF = *MBB.getParent();
- if (MF.getFrameInfo()->isReturnAddressTaken() &&
- MF.getRegInfo().isLiveIn(Reg))
- isKill = false;
+ if (ARM::tGPRRegClass.contains(Reg) || Reg == ARM::LR) {
+ LoRegsToSave.insert(Reg);
+ } else if (ARM::hGPRRegClass.contains(Reg) && Reg != ARM::LR) {
+ HiRegsToSave.insert(Reg);
+ } else {
+ llvm_unreachable("callee-saved register of unexpected class");
+ }
+
+ if ((ARM::tGPRRegClass.contains(Reg) || Reg == ARM::LR) &&
+ !MF.getRegInfo().isLiveIn(Reg) &&
+ !(hasFP(MF) && Reg == RegInfo->getFrameRegister(MF)))
+ CopyRegs.insert(Reg);
+ }
+
+ // Unused argument registers can be used for the high register saving.
+ for (unsigned ArgReg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3})
+ if (!MF.getRegInfo().isLiveIn(ArgReg))
+ CopyRegs.insert(ArgReg);
+
+ // Push the low registers and lr
+ if (!LoRegsToSave.empty()) {
+ MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(ARM::tPUSH));
+ AddDefaultPred(MIB);
+ for (unsigned Reg : {ARM::R4, ARM::R5, ARM::R6, ARM::R7, ARM::LR}) {
+ if (LoRegsToSave.count(Reg)) {
+ bool isKill = !MF.getRegInfo().isLiveIn(Reg);
+ if (isKill)
+ MBB.addLiveIn(Reg);
+
+ MIB.addReg(Reg, getKillRegState(isKill));
+ }
+ }
+ MIB.setMIFlags(MachineInstr::FrameSetup);
+ }
+
+ // Push the high registers. There are no store instructions that can access
+ // these registers directly, so we have to move them to low registers, and
+ // push them. This might take multiple pushes, as it is possible for there to
+ // be fewer low registers available than high registers which need saving.
+
+ // These are in reverse order so that in the case where we need to use
+ // multiple PUSH instructions, the order of the registers on the stack still
+ // matches the unwind info. They need to be swicthed back to ascending order
+ // before adding to the PUSH instruction.
+ static const unsigned AllCopyRegs[] = {ARM::LR, ARM::R7, ARM::R6,
+ ARM::R5, ARM::R4, ARM::R3,
+ ARM::R2, ARM::R1, ARM::R0};
+ static const unsigned AllHighRegs[] = {ARM::R11, ARM::R10, ARM::R9, ARM::R8};
+
+ const unsigned *AllCopyRegsEnd = std::end(AllCopyRegs);
+ const unsigned *AllHighRegsEnd = std::end(AllHighRegs);
+
+ // Find the first register to save.
+ const unsigned *HiRegToSave = findNextOrderedReg(
+ std::begin(AllHighRegs), HiRegsToSave, AllHighRegsEnd);
+
+ while (HiRegToSave != AllHighRegsEnd) {
+ // Find the first low register to use.
+ const unsigned *CopyReg =
+ findNextOrderedReg(std::begin(AllCopyRegs), CopyRegs, AllCopyRegsEnd);
+
+ // Create the PUSH, but don't insert it yet (the MOVs need to come first).
+ MachineInstrBuilder PushMIB = BuildMI(MF, DL, TII.get(ARM::tPUSH));
+ AddDefaultPred(PushMIB);
+
+ SmallVector<unsigned, 4> RegsToPush;
+ while (HiRegToSave != AllHighRegsEnd && CopyReg != AllCopyRegsEnd) {
+ if (HiRegsToSave.count(*HiRegToSave)) {
+ bool isKill = !MF.getRegInfo().isLiveIn(*HiRegToSave);
+ if (isKill)
+ MBB.addLiveIn(*HiRegToSave);
+
+ // Emit a MOV from the high reg to the low reg.
+ MachineInstrBuilder MIB =
+ BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr));
+ MIB.addReg(*CopyReg, RegState::Define);
+ MIB.addReg(*HiRegToSave, getKillRegState(isKill));
+ AddDefaultPred(MIB);
+
+ // Record the register that must be added to the PUSH.
+ RegsToPush.push_back(*CopyReg);
+
+ CopyReg = findNextOrderedReg(++CopyReg, CopyRegs, AllCopyRegsEnd);
+ HiRegToSave =
+ findNextOrderedReg(++HiRegToSave, HiRegsToSave, AllHighRegsEnd);
+ }
}
- if (isKill)
- MBB.addLiveIn(Reg);
+ // Add the low registers to the PUSH, in ascending order.
+ for (unsigned Reg : reverse(RegsToPush))
+ PushMIB.addReg(Reg, RegState::Kill);
- MIB.addReg(Reg, getKillRegState(isKill));
+ // Insert the PUSH instruction after the MOVs.
+ MBB.insert(MI, PushMIB);
}
- MIB.setMIFlags(MachineInstr::FrameSetup);
+
return true;
}
@@ -615,15 +756,101 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
const TargetInstrInfo &TII = *STI.getInstrInfo();
+ const ARMBaseRegisterInfo *RegInfo = static_cast<const ARMBaseRegisterInfo *>(
+ MF.getSubtarget().getRegisterInfo());
bool isVarArg = AFI->getArgRegsSaveSize() > 0;
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
+
+ SmallSet<unsigned, 9> LoRegsToRestore;
+ SmallSet<unsigned, 4> HiRegsToRestore;
+ // Low registers (r0-r7) which can be used to restore the high registers.
+ SmallSet<unsigned, 9> CopyRegs;
+
+ for (CalleeSavedInfo I : CSI) {
+ unsigned Reg = I.getReg();
+
+ if (ARM::tGPRRegClass.contains(Reg) || Reg == ARM::LR) {
+ LoRegsToRestore.insert(Reg);
+ } else if (ARM::hGPRRegClass.contains(Reg) && Reg != ARM::LR) {
+ HiRegsToRestore.insert(Reg);
+ } else {
+ llvm_unreachable("callee-saved register of unexpected class");
+ }
+
+ // If this is a low register not used as the frame pointer, we may want to
+ // use it for restoring the high registers.
+ if ((ARM::tGPRRegClass.contains(Reg)) &&
+ !(hasFP(MF) && Reg == RegInfo->getFrameRegister(MF)))
+ CopyRegs.insert(Reg);
+ }
+
+ // If this is a return block, we may be able to use some unused return value
+ // registers for restoring the high regs.
+ auto Terminator = MBB.getFirstTerminator();
+ if (Terminator != MBB.end() && Terminator->getOpcode() == ARM::tBX_RET) {
+ CopyRegs.insert(ARM::R0);
+ CopyRegs.insert(ARM::R1);
+ CopyRegs.insert(ARM::R2);
+ CopyRegs.insert(ARM::R3);
+ for (auto Op : Terminator->implicit_operands()) {
+ if (Op.isReg())
+ CopyRegs.erase(Op.getReg());
+ }
+ }
+
+ static const unsigned AllCopyRegs[] = {ARM::R0, ARM::R1, ARM::R2, ARM::R3,
+ ARM::R4, ARM::R5, ARM::R6, ARM::R7};
+ static const unsigned AllHighRegs[] = {ARM::R8, ARM::R9, ARM::R10, ARM::R11};
+
+ const unsigned *AllCopyRegsEnd = std::end(AllCopyRegs);
+ const unsigned *AllHighRegsEnd = std::end(AllHighRegs);
+
+ // Find the first register to restore.
+ auto HiRegToRestore = findNextOrderedReg(std::begin(AllHighRegs),
+ HiRegsToRestore, AllHighRegsEnd);
+
+ while (HiRegToRestore != AllHighRegsEnd) {
+ assert(!CopyRegs.empty());
+ // Find the first low register to use.
+ auto CopyReg =
+ findNextOrderedReg(std::begin(AllCopyRegs), CopyRegs, AllCopyRegsEnd);
+
+ // Create the POP instruction.
+ MachineInstrBuilder PopMIB = BuildMI(MBB, MI, DL, TII.get(ARM::tPOP));
+ AddDefaultPred(PopMIB);
+
+ while (HiRegToRestore != AllHighRegsEnd && CopyReg != AllCopyRegsEnd) {
+ // Add the low register to the POP.
+ PopMIB.addReg(*CopyReg, RegState::Define);
+
+ // Create the MOV from low to high register.
+ MachineInstrBuilder MIB =
+ BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr));
+ MIB.addReg(*HiRegToRestore, RegState::Define);
+ MIB.addReg(*CopyReg, RegState::Kill);
+ AddDefaultPred(MIB);
+
+ CopyReg = findNextOrderedReg(++CopyReg, CopyRegs, AllCopyRegsEnd);
+ HiRegToRestore =
+ findNextOrderedReg(++HiRegToRestore, HiRegsToRestore, AllHighRegsEnd);
+ }
+ }
+
+
+
+
MachineInstrBuilder MIB = BuildMI(MF, DL, TII.get(ARM::tPOP));
AddDefaultPred(MIB);
bool NeedsPop = false;
for (unsigned i = CSI.size(); i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
+
+ // High registers (excluding lr) have already been dealt with
+ if (!(ARM::tGPRRegClass.contains(Reg) || Reg == ARM::LR))
+ continue;
+
if (Reg == ARM::LR) {
if (MBB.succ_empty()) {
// Special epilogue for vararg functions. See emitEpilogue
diff --git a/contrib/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp b/contrib/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp
index 159731d..4b4fbaa 100644
--- a/contrib/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp
@@ -83,7 +83,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
@@ -109,7 +109,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
diff --git a/contrib/llvm/lib/Target/ARM/Thumb2ITBlockPass.cpp b/contrib/llvm/lib/Target/ARM/Thumb2ITBlockPass.cpp
index 0c70555..d01fc8c 100644
--- a/contrib/llvm/lib/Target/ARM/Thumb2ITBlockPass.cpp
+++ b/contrib/llvm/lib/Target/ARM/Thumb2ITBlockPass.cpp
@@ -38,10 +38,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Thumb IT blocks insertion pass";
}
diff --git a/contrib/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp b/contrib/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp
index e2e6daf..1c731d6 100644
--- a/contrib/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/Thumb2InstrInfo.cpp
@@ -130,7 +130,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
@@ -170,7 +170,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
diff --git a/contrib/llvm/lib/Target/ARM/Thumb2SizeReduction.cpp b/contrib/llvm/lib/Target/ARM/Thumb2SizeReduction.cpp
index c4fdb9b..8208e7e 100644
--- a/contrib/llvm/lib/Target/ARM/Thumb2SizeReduction.cpp
+++ b/contrib/llvm/lib/Target/ARM/Thumb2SizeReduction.cpp
@@ -148,10 +148,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Thumb2 instruction size reduction pass";
}
@@ -430,6 +430,10 @@ Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
if (!MBB.getParent()->getFunction()->optForMinSize())
return false;
+ if (!MI->hasOneMemOperand() ||
+ (*MI->memoperands_begin())->getAlignment() < 4)
+ return false;
+
// We're creating a completely different type of load/store - LDM from LDR.
// For this reason we can't reuse the logic at the end of this function; we
// have to implement the MI building here.
@@ -651,7 +655,7 @@ Thumb2SizeReduce::ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,
case ARM::t2ADDSri: {
if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
return true;
- // fallthrough
+ LLVM_FALLTHROUGH;
}
case ARM::t2ADDSrr:
return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
diff --git a/contrib/llvm/lib/Target/ARM/ThumbRegisterInfo.cpp b/contrib/llvm/lib/Target/ARM/ThumbRegisterInfo.cpp
index 6c26c88..2efd63b 100644
--- a/contrib/llvm/lib/Target/ARM/ThumbRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/ARM/ThumbRegisterInfo.cpp
@@ -126,6 +126,7 @@ static void emitThumbRegPlusImmInReg(
bool CanChangeCC, const TargetInstrInfo &TII,
const ARMBaseRegisterInfo &MRI, unsigned MIFlags = MachineInstr::NoFlags) {
MachineFunction &MF = *MBB.getParent();
+ const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
bool isHigh = !isARMLowRegister(DestReg) ||
(BaseReg != 0 && !isARMLowRegister(BaseReg));
bool isSub = false;
@@ -154,6 +155,9 @@ static void emitThumbRegPlusImmInReg(
AddDefaultT1CC(BuildMI(MBB, MBBI, dl, TII.get(ARM::tRSB), LdReg))
.addReg(LdReg, RegState::Kill)
.setMIFlags(MIFlags);
+ } else if (ST.genExecuteOnly()) {
+ BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi32imm), LdReg)
+ .addImm(NumBytes).setMIFlags(MIFlags);
} else
MRI.emitLoadConstPool(MBB, MBBI, dl, LdReg, 0, NumBytes, ARMCC::AL, 0,
MIFlags);
@@ -511,10 +515,10 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
unsigned FrameReg = ARM::SP;
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
- MF.getFrameInfo()->getStackSize() + SPAdj;
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
+ MF.getFrameInfo().getStackSize() + SPAdj;
- if (MF.getFrameInfo()->hasVarSizedObjects()) {
+ 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.
@@ -534,7 +538,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
assert(STI.getFrameLowering()->hasReservedCallFrame(MF) &&
"Cannot use SP to access the emergency spill slot in "
"functions without a reserved call frame");
- assert(!MF.getFrameInfo()->hasVarSizedObjects() &&
+ assert(!MF.getFrameInfo().hasVarSizedObjects() &&
"Cannot use SP to access the emergency spill slot in "
"functions with variable sized frame objects");
}
@@ -570,7 +574,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
unsigned TmpReg = MI.getOperand(0).getReg();
bool UseRR = false;
if (Opcode == ARM::tLDRspi) {
- if (FrameReg == ARM::SP)
+ if (FrameReg == ARM::SP || STI.genExecuteOnly())
emitThumbRegPlusImmInReg(MBB, II, dl, TmpReg, FrameReg,
Offset, false, TII, *this);
else {
@@ -594,7 +598,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
bool UseRR = false;
if (Opcode == ARM::tSTRspi) {
- if (FrameReg == ARM::SP)
+ if (FrameReg == ARM::SP || STI.genExecuteOnly())
emitThumbRegPlusImmInReg(MBB, II, dl, VReg, FrameReg,
Offset, false, TII, *this);
else {
diff --git a/contrib/llvm/lib/Target/AVR/AVR.h b/contrib/llvm/lib/Target/AVR/AVR.h
index 041c77c..8e5cc53 100644
--- a/contrib/llvm/lib/Target/AVR/AVR.h
+++ b/contrib/llvm/lib/Target/AVR/AVR.h
@@ -27,9 +27,15 @@ FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createAVRExpandPseudoPass();
FunctionPass *createAVRFrameAnalyzerPass();
+FunctionPass *createAVRInstrumentFunctionsPass();
+FunctionPass *createAVRRelaxMemPass();
FunctionPass *createAVRDynAllocaSRPass();
FunctionPass *createAVRBranchSelectionPass();
+void initializeAVRExpandPseudoPass(PassRegistry&);
+void initializeAVRInstrumentFunctionsPass(PassRegistry&);
+void initializeAVRRelaxMemPass(PassRegistry&);
+
/// Contains the AVR backend.
namespace AVR {
diff --git a/contrib/llvm/lib/Target/AVR/AVR.td b/contrib/llvm/lib/Target/AVR/AVR.td
index 27cf212..d03b983 100644
--- a/contrib/llvm/lib/Target/AVR/AVR.td
+++ b/contrib/llvm/lib/Target/AVR/AVR.td
@@ -16,493 +16,10 @@
include "llvm/Target/Target.td"
//===---------------------------------------------------------------------===//
-// AVR Subtarget Features.
+// AVR Device Definitions
//===---------------------------------------------------------------------===//
-// :TODO: Implement the skip errata, see `gcc/config/avr/avr-arch.h` for details
-// :TODO: We define all devices with SRAM to have all variants of LD/ST/LDD/STD.
-// In reality, avr1 (no SRAM) has one variant each of `LD` and `ST`.
-// avr2 (with SRAM) adds the rest of the variants.
-// :TODO: s/AVRTiny/Tiny
-
-
-// A feature set aggregates features, grouping them. We don't want to create a
-// new member in AVRSubtarget (to store a value) for each set because we do not
-// care if the set is supported, only the subfeatures inside the set. We fix
-// this by simply setting the same dummy member for all feature sets, which is
-// then ignored.
-class FeatureSet<string name, string desc, list<SubtargetFeature> i>
- : SubtargetFeature<name, "m_FeatureSetDummy", "true", desc, i>;
-
-// A family of microcontrollers, defining a set of supported features.
-class Family<string name, list<SubtargetFeature> i>
- : FeatureSet<name, !strconcat("The device is a part of the ",
- name, " family"), i>;
-
-// The device has SRAM, and supports the bare minimum of
-// SRAM-relevant instructions.
-//
-// These are:
-// LD - all 9 variants
-// ST - all 9 variants
-// LDD - two variants for Y and Z
-// STD - two variants for Y and Z
-// `LDS Rd, K`
-// `STS k, Rr`
-// `PUSH`/`POP`
-def FeatureSRAM : SubtargetFeature<"sram", "m_hasSRAM", "true",
- "The device has random access memory">;
-
-// The device supports the `JMP k` and `CALL k` instructions.
-def FeatureJMPCALL : SubtargetFeature<"jmpcall", "m_hasJMPCALL", "true",
- "The device supports the `JMP` and "
- "`CALL` instructions">;
-
-
-// The device supports the indirect branches `IJMP` and `ICALL`.
-def FeatureIJMPCALL : SubtargetFeature<"ijmpcall", "m_hasIJMPCALL",
- "true",
- "The device supports `IJMP`/`ICALL`"
- "instructions">;
-
-// The device supports the extended indirect branches `EIJMP` and `EICALL`.
-def FeatureEIJMPCALL : SubtargetFeature<"eijmpcall", "m_hasEIJMPCALL",
- "true", "The device supports the "
- "`EIJMP`/`EICALL` instructions">;
-
-// The device supports `ADDI Rd, K`, `SUBI Rd, K`.
-def FeatureADDSUBIW : SubtargetFeature<"addsubiw", "m_hasADDSUBIW",
- "true", "Enable 16-bit register-immediate "
- "addition and subtraction instructions">;
-
-// The device has an 8-bit stack pointer (SP) register.
-def FeatureSmallStack : SubtargetFeature<"smallstack", "m_hasSmallStack",
- "true", "The device has an 8-bit "
- "stack pointer">;
-
-// The device supports the 16-bit GPR pair MOVW instruction.
-def FeatureMOVW : SubtargetFeature<"movw", "m_hasMOVW", "true",
- "The device supports the 16-bit MOVW "
- "instruction">;
-
-// The device supports the `LPM` instruction, with implied destination being r0.
-def FeatureLPM : SubtargetFeature<"lpm", "m_hasLPM", "true",
- "The device supports the `LPM` instruction">;
-
-// The device supports the `LPM Rd, Z[+] instruction.
-def FeatureLPMX : SubtargetFeature<"lpmx", "m_hasLPMX", "true",
- "The device supports the `LPM Rd, Z[+]` "
- "instruction">;
-
-// The device supports the `ELPM` instruction.
-def FeatureELPM : SubtargetFeature<"elpm", "m_hasELPM", "true",
- "The device supports the ELPM instruction">;
-
-// The device supports the `ELPM Rd, Z[+]` instructions.
-def FeatureELPMX : SubtargetFeature<"elpmx", "m_hasELPMX", "true",
- "The device supports the `ELPM Rd, Z[+]` "
- "instructions">;
-
-// The device supports the `SPM` instruction.
-def FeatureSPM : SubtargetFeature<"spm", "m_hasSPM", "true",
- "The device supports the `SPM` instruction">;
-
-// The device supports the `SPM Z+` instruction.
-def FeatureSPMX : SubtargetFeature<"spmx", "m_hasSPMX", "true",
- "The device supports the `SPM Z+` "
- "instruction">;
-
-// The device supports the `DES k` instruction.
-def FeatureDES : SubtargetFeature<"des", "m_hasDES", "true",
- "The device supports the `DES k` encryption "
- "instruction">;
-
-// The device supports the Read-Write-Modify instructions
-// XCH, LAS, LAC, and LAT.
-def FeatureRMW : SubtargetFeature<"rmw", "m_supportsRMW", "true",
- "The device supports the read-write-modify "
- "instructions: XCH, LAS, LAC, LAT">;
-
-// The device supports the `[F]MUL[S][U]` family of instructions.
-def FeatureMultiplication : SubtargetFeature<"mul", "m_supportsMultiplication",
- "true", "The device supports the "
- "multiplication instructions">;
-
-// The device supports the `BREAK` instruction.
-def FeatureBREAK : SubtargetFeature<"break", "m_hasBREAK", "true",
- "The device supports the `BREAK` debugging "
- "instruction">;
-
-// The device has instruction encodings specific to the Tiny core.
-def FeatureTinyEncoding : SubtargetFeature<"tinyencoding",
- "m_hasTinyEncoding", "true",
- "The device has Tiny core specific "
- "instruction encodings">;
-
-class ELFArch<string name> : SubtargetFeature<"", "ELFArch",
- !strconcat("ELF::",name), "">;
-
-// ELF e_flags architecture values
-def ELFArchAVR1 : ELFArch<"EF_AVR_ARCH_AVR1">;
-def ELFArchAVR2 : ELFArch<"EF_AVR_ARCH_AVR2">;
-def ELFArchAVR25 : ELFArch<"EF_AVR_ARCH_AVR25">;
-def ELFArchAVR3 : ELFArch<"EF_AVR_ARCH_AVR3">;
-def ELFArchAVR31 : ELFArch<"EF_AVR_ARCH_AVR31">;
-def ELFArchAVR35 : ELFArch<"EF_AVR_ARCH_AVR35">;
-def ELFArchAVR4 : ELFArch<"EF_AVR_ARCH_AVR4">;
-def ELFArchAVR5 : ELFArch<"EF_AVR_ARCH_AVR5">;
-def ELFArchAVR51 : ELFArch<"EF_AVR_ARCH_AVR51">;
-def ELFArchAVR6 : ELFArch<"EF_AVR_ARCH_AVR6">;
-def ELFArchAVRTiny : ELFArch<"EF_AVR_ARCH_AVRTINY">;
-def ELFArchXMEGA1 : ELFArch<"EF_AVR_ARCH_XMEGA1">;
-def ELFArchXMEGA2 : ELFArch<"EF_AVR_ARCH_XMEGA2">;
-def ELFArchXMEGA3 : ELFArch<"EF_AVR_ARCH_XMEGA3">;
-def ELFArchXMEGA4 : ELFArch<"EF_AVR_ARCH_XMEGA4">;
-def ELFArchXMEGA5 : ELFArch<"EF_AVR_ARCH_XMEGA5">;
-def ELFArchXMEGA6 : ELFArch<"EF_AVR_ARCH_XMEGA6">;
-def ELFArchXMEGA7 : ELFArch<"EF_AVR_ARCH_XMEGA7">;
-
-//===---------------------------------------------------------------------===//
-// AVR Families
-//===---------------------------------------------------------------------===//
-
-// The device has at least the bare minimum that **every** single AVR
-// device should have.
-def FamilyAVR0 : Family<"avr0", []>;
-
-def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM]>;
-
-def FamilyAVR2 : Family<"avr2",
- [FamilyAVR1, FeatureIJMPCALL, FeatureADDSUBIW,
- FeatureSRAM]>;
-
-def FamilyAVR25 : Family<"avr25",
- [FamilyAVR2, FeatureMOVW, FeatureLPMX,
- FeatureSPM, FeatureBREAK]>;
-
-def FamilyAVR3 : Family<"avr3",
- [FamilyAVR2, FeatureJMPCALL]>;
-
-def FamilyAVR31 : Family<"avr31",
- [FamilyAVR3, FeatureELPM]>;
-
-def FamilyAVR35 : Family<"avr35",
- [FamilyAVR3, FeatureMOVW, FeatureLPMX,
- FeatureSPM, FeatureBREAK]>;
-
-def FamilyAVR4 : Family<"avr4",
- [FamilyAVR2, FeatureMultiplication,
- FeatureMOVW, FeatureLPMX, FeatureSPM,
- FeatureBREAK]>;
-
-def FamilyAVR5 : Family<"avr5",
- [FamilyAVR3, FeatureMultiplication,
- FeatureMOVW, FeatureLPMX, FeatureSPM,
- FeatureBREAK]>;
-
-def FamilyAVR51 : Family<"avr51",
- [FamilyAVR5, FeatureELPM, FeatureELPMX]>;
-
-def FamilyAVR6 : Family<"avr6",
- [FamilyAVR51]>;
-
-def FamilyAVRTiny : Family<"avrtiny",
- [FamilyAVR0, FeatureBREAK, FeatureSRAM,
- FeatureTinyEncoding]>;
-
-def FamilyXMEGA : Family<"xmega",
- [FamilyAVR51, FeatureEIJMPCALL, FeatureSPMX,
- FeatureDES]>;
-
-def FamilyXMEGAU : Family<"xmegau",
- [FamilyXMEGA, FeatureRMW]>;
-
-def FeatureSetSpecial : FeatureSet<"special",
- "Enable use of the entire instruction "
- "set - used for debugging",
- [FeatureSRAM, FeatureJMPCALL,
- FeatureIJMPCALL, FeatureEIJMPCALL,
- FeatureADDSUBIW, FeatureMOVW,
- FeatureLPM, FeatureLPMX, FeatureELPM,
- FeatureELPMX, FeatureSPM, FeatureSPMX,
- FeatureDES, FeatureRMW,
- FeatureMultiplication, FeatureBREAK]>;
-
-//===---------------------------------------------------------------------===//
-// AVR microcontrollers supported.
-//===---------------------------------------------------------------------===//
-
-class Device<string Name, Family Fam, ELFArch Arch,
- list<SubtargetFeature> ExtraFeatures = []>
- : Processor<Name, NoItineraries, !listconcat([Fam,Arch],ExtraFeatures)>;
-
-// Generic MCUs
-// Note that several versions of GCC has strange ELF architecture
-// settings for backwards compatibility - see `gas/config/tc-avr.c`
-// in AVR binutils. We do not replicate this.
-def : Device<"avr1", FamilyAVR1, ELFArchAVR1>;
-def : Device<"avr2", FamilyAVR2, ELFArchAVR2>;
-def : Device<"avr25", FamilyAVR25, ELFArchAVR25>;
-def : Device<"avr3", FamilyAVR3, ELFArchAVR3>;
-def : Device<"avr31", FamilyAVR31, ELFArchAVR31>;
-def : Device<"avr35", FamilyAVR35, ELFArchAVR35>;
-def : Device<"avr4", FamilyAVR4, ELFArchAVR4>;
-def : Device<"avr5", FamilyAVR5, ELFArchAVR5>;
-def : Device<"avr51", FamilyAVR51, ELFArchAVR51>;
-def : Device<"avr6", FamilyAVR6, ELFArchAVR6>;
-def : Device<"avrxmega1", FamilyXMEGA, ELFArchXMEGA1>;
-def : Device<"avrxmega2", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"avrxmega3", FamilyXMEGA, ELFArchXMEGA3>;
-def : Device<"avrxmega4", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"avrxmega5", FamilyXMEGA, ELFArchXMEGA5>;
-def : Device<"avrxmega6", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"avrxmega7", FamilyXMEGA, ELFArchXMEGA7>;
-def : Device<"avrtiny", FamilyAVRTiny, ELFArchAVRTiny>;
-
-// Specific MCUs
-def : Device<"at90s1200", FamilyAVR0, ELFArchAVR1>;
-def : Device<"attiny11", FamilyAVR1, ELFArchAVR1>;
-def : Device<"attiny12", FamilyAVR1, ELFArchAVR1>;
-def : Device<"attiny15", FamilyAVR1, ELFArchAVR1>;
-def : Device<"attiny28", FamilyAVR1, ELFArchAVR1>;
-def : Device<"at90s2313", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s2323", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s2333", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s2343", FamilyAVR2, ELFArchAVR2>;
-def : Device<"attiny22", FamilyAVR2, ELFArchAVR2>;
-def : Device<"attiny26", FamilyAVR2, ELFArchAVR2, [FeatureLPMX]>;
-def : Device<"at86rf401", FamilyAVR2, ELFArchAVR25,
- [FeatureMOVW, FeatureLPMX]>;
-def : Device<"at90s4414", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s4433", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s4434", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s8515", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90c8534", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s8535", FamilyAVR2, ELFArchAVR2>;
-def : Device<"ata5272", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny13", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny13a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny2313", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny2313a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny24", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny24a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny4313", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny44", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny44a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny84", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny84a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny25", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny45", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny85", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny261", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny261a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny461", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny461a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny861", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny861a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny87", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny43u", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny48", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny88", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny828", FamilyAVR25, ELFArchAVR25>;
-def : Device<"at43usb355", FamilyAVR3, ELFArchAVR3>;
-def : Device<"at76c711", FamilyAVR3, ELFArchAVR3>;
-def : Device<"atmega103", FamilyAVR31, ELFArchAVR31>;
-def : Device<"at43usb320", FamilyAVR31, ELFArchAVR31>;
-def : Device<"attiny167", FamilyAVR35, ELFArchAVR35>;
-def : Device<"at90usb82", FamilyAVR35, ELFArchAVR35>;
-def : Device<"at90usb162", FamilyAVR35, ELFArchAVR35>;
-def : Device<"ata5505", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega8u2", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega16u2", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega32u2", FamilyAVR35, ELFArchAVR35>;
-def : Device<"attiny1634", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega8", FamilyAVR4, ELFArchAVR4>; // FIXME: family may be wrong
-def : Device<"ata6289", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega8a", FamilyAVR4, ELFArchAVR4>;
-def : Device<"ata6285", FamilyAVR4, ELFArchAVR4>;
-def : Device<"ata6286", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48a", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48pa", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48p", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88a", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88p", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88pa", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega8515", FamilyAVR2, ELFArchAVR4,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega8535", FamilyAVR2, ELFArchAVR4,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega8hva", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm1", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm2", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm2b", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm3", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm3b", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm81", FamilyAVR4, ELFArchAVR4>;
-def : Device<"ata5790", FamilyAVR5, ELFArchAVR5>;
-def : Device<"ata5795", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega161", FamilyAVR3, ELFArchAVR5,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega162", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega163", FamilyAVR3, ELFArchAVR5,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega164a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega164p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega164pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega323", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega324a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega324p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega324pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega328", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega328p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega406", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega640", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega645", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega645a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega645p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega649", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega649a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega649p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6450", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6450a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6450p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6490", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6490a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6490p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64rfr2", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644rfr2", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hva", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hva2", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hvb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hvbrevb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32hvb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32hvbrevb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64hve", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90can32", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90can64", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90pwm161", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90pwm216", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90pwm316", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32c1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64c1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16m1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32m1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64m1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16u4", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32u4", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32u6", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90usb646", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90usb647", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90scr100", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at94k", FamilyAVR3, ELFArchAVR5,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX]>;
-def : Device<"m3000", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega128", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega128a", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1280", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1281", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1284", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1284p", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega128rfa1", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega128rfr2", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1284rfr2", FamilyAVR51, ELFArchAVR51>;
-def : Device<"at90can128", FamilyAVR51, ELFArchAVR51>;
-def : Device<"at90usb1286", FamilyAVR51, ELFArchAVR51>;
-def : Device<"at90usb1287", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega2560", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atmega2561", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atmega256rfr2", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atmega2564rfr2", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atxmega16a4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega16a4u", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega16c4", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega16d4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32a4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32a4u", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega32c4", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega32d4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32e5", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega16e5", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega8e5", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32x1", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega64a3", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"atxmega64a3u", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64a4u", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64b1", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64b3", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64c3", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64d3", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"atxmega64d4", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"atxmega64a1", FamilyXMEGA, ELFArchXMEGA5>;
-def : Device<"atxmega64a1u", FamilyXMEGAU, ELFArchXMEGA5>;
-def : Device<"atxmega128a3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega128a3u", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128b1", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128b3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega128d4", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega192a3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega192a3u", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega192c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega192d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega256a3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega256a3u", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega256a3b", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega256a3bu", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega256c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega256d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega384c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega384d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega128a1", FamilyXMEGA, ELFArchXMEGA7>;
-def : Device<"atxmega128a1u", FamilyXMEGAU, ELFArchXMEGA7>;
-def : Device<"atxmega128a4u", FamilyXMEGAU, ELFArchXMEGA7>;
-def : Device<"attiny4", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny5", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny9", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny10", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny20", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny40", FamilyAVRTiny, ELFArchAVRTiny>;
+include "AVRDevices.td"
//===---------------------------------------------------------------------===//
// Register File Description
@@ -528,36 +45,37 @@ include "AVRCallingConv.td"
// Assembly Printers
//===---------------------------------------------------------------------===//
-// def AVRAsmWriter : AsmWriter {
-// string AsmWriterClassName = "InstPrinter";
-// bit isMCAsmWriter = 1;
-// }
+def AVRAsmWriter : AsmWriter {
+ string AsmWriterClassName = "InstPrinter";
+ bit isMCAsmWriter = 1;
+}
//===---------------------------------------------------------------------===//
// Assembly Parsers
//===---------------------------------------------------------------------===//
-// def AVRAsmParser : AsmParser {
-// let ShouldEmitMatchRegisterName = 1;
-// let ShouldEmitMatchRegisterAltName = 1;
-// }
+def AVRAsmParser : AsmParser {
+ let ShouldEmitMatchRegisterName = 1;
+ let ShouldEmitMatchRegisterAltName = 1;
+}
-// def AVRAsmParserVariant : AsmParserVariant {
-// int Variant = 0;
-//
-// // Recognize hard coded registers.
-// string RegisterPrefix = "$";
-// }
+def AVRAsmParserVariant : AsmParserVariant {
+ int Variant = 0;
+
+ // Recognize hard coded registers.
+ string RegisterPrefix = "$";
+ string TokenizingCharacters = "+";
+}
//===---------------------------------------------------------------------===//
// Target Declaration
//===---------------------------------------------------------------------===//
def AVR : Target {
- let InstructionSet = AVRInstrInfo;
-// let AssemblyWriters = [AVRAsmWriter];
-//
-// let AssemblyParsers = [AVRAsmParser];
-// let AssemblyParserVariants = [AVRAsmParserVariant];
+ let InstructionSet = AVRInstrInfo;
+ let AssemblyWriters = [AVRAsmWriter];
+
+ let AssemblyParsers = [AVRAsmParser];
+ let AssemblyParserVariants = [AVRAsmParserVariant];
}
diff --git a/contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
new file mode 100644
index 0000000..4afdd3a
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
@@ -0,0 +1,184 @@
+//===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a printer that converts from our internal representation
+// of machine-dependent LLVM code to GAS-format AVR assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRMCInstLower.h"
+#include "AVRSubtarget.h"
+#include "InstPrinter/AVRInstPrinter.h"
+
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
+
+#define DEBUG_TYPE "avr-asm-printer"
+
+namespace llvm {
+
+/// An AVR assembly code printer.
+class AVRAsmPrinter : public AsmPrinter {
+public:
+ AVRAsmPrinter(TargetMachine &TM,
+ std::unique_ptr<MCStreamer> Streamer)
+ : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { }
+
+ StringRef getPassName() const override { return "AVR Assembly Printer"; }
+
+ void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O,
+ const char *Modifier = 0);
+
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+
+ void EmitInstruction(const MachineInstr *MI) override;
+
+private:
+ const MCRegisterInfo &MRI;
+};
+
+void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
+ raw_ostream &O, const char *Modifier) {
+ const MachineOperand &MO = MI->getOperand(OpNo);
+
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI);
+ break;
+ case MachineOperand::MO_Immediate:
+ O << MO.getImm();
+ break;
+ case MachineOperand::MO_GlobalAddress:
+ O << getSymbol(MO.getGlobal());
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ O << *GetExternalSymbolSymbol(MO.getSymbolName());
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ O << *MO.getMBB()->getSymbol();
+ break;
+ default:
+ llvm_unreachable("Not implemented yet!");
+ }
+}
+
+bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) {
+ // Default asm printer can only deal with some extra codes,
+ // so try it first.
+ bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O);
+
+ if (Error && ExtraCode && ExtraCode[0]) {
+ if (ExtraCode[1] != 0)
+ return true; // Unknown modifier.
+
+ if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') {
+ const MachineOperand &RegOp = MI->getOperand(OpNum);
+
+ assert(RegOp.isReg() && "Operand must be a register when you're"
+ "using 'A'..'Z' operand extracodes.");
+ unsigned Reg = RegOp.getReg();
+
+ unsigned ByteNumber = ExtraCode[0] - 'A';
+
+ unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
+ unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
+ (void)NumOpRegs;
+
+ const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
+
+ unsigned BytesPerReg = TRI.getMinimalPhysRegClass(Reg)->getSize();
+ assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported.");
+
+ unsigned RegIdx = ByteNumber / BytesPerReg;
+ assert(RegIdx < NumOpRegs && "Multibyte index out of range.");
+
+ Reg = MI->getOperand(OpNum + RegIdx).getReg();
+
+ if (BytesPerReg == 2) {
+ Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi
+ : AVR::sub_lo);
+ }
+
+ O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI);
+ return false;
+ }
+ }
+
+ printOperand(MI, OpNum, O);
+
+ return false;
+}
+
+bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+ unsigned OpNum, unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &O) {
+ if (ExtraCode && ExtraCode[0]) {
+ llvm_unreachable("This branch is not implemented yet");
+ }
+
+ const MachineOperand &MO = MI->getOperand(OpNum);
+ (void)MO;
+ assert(MO.isReg() && "Unexpected inline asm memory operand");
+
+ // TODO: We can look up the alternative name for the register if it's given.
+ if (MI->getOperand(OpNum).getReg() == AVR::R31R30) {
+ O << "Z";
+ } else {
+ assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 &&
+ "Wrong register class for memory operand.");
+ O << "Y";
+ }
+
+ // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion
+ // and the second operand is an Imm.
+ unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
+ unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
+
+ if (NumOpRegs == 2) {
+ O << '+' << MI->getOperand(OpNum + 1).getImm();
+ }
+
+ return false;
+}
+
+void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) {
+ AVRMCInstLower MCInstLowering(OutContext, *this);
+
+ MCInst I;
+ MCInstLowering.lowerInstruction(*MI, I);
+ EmitToStreamer(*OutStreamer, I);
+}
+
+} // end of namespace llvm
+
+extern "C" void LLVMInitializeAVRAsmPrinter() {
+ llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget());
+}
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRCallingConv.td b/contrib/llvm/lib/Target/AVR/AVRCallingConv.td
index d8cb3fe..68dbce0 100644
--- a/contrib/llvm/lib/Target/AVR/AVRCallingConv.td
+++ b/contrib/llvm/lib/Target/AVR/AVRCallingConv.td
@@ -23,7 +23,7 @@ def RetCC_AVR : CallingConv
]>;
// Special return value calling convention for runtime functions.
-def RetCC_AVR_RT : CallingConv
+def RetCC_AVR_BUILTIN : CallingConv
<[
CCIfType<[i8], CCAssignToReg<[R24,R25]>>,
CCIfType<[i16], CCAssignToReg<[R23R22, R25R24]>>
@@ -43,15 +43,8 @@ def ArgCC_AVR_Vararg : CallingConv
]>;
// Special argument calling convention for
-// multiplication runtime functions.
-def ArgCC_AVR_RT_MUL : CallingConv
-<[
- CCIfType<[i16], CCAssignToReg<[R27R26,R19R18]>>
-]>;
-
-// Special argument calling convention for
// division runtime functions.
-def ArgCC_AVR_RT_DIV : CallingConv
+def ArgCC_AVR_BUILTIN_DIV : CallingConv
<[
CCIfType<[i8], CCAssignToReg<[R24,R22]>>,
CCIfType<[i16], CCAssignToReg<[R25R24, R23R22]>>
diff --git a/contrib/llvm/lib/Target/AVR/AVRDevices.td b/contrib/llvm/lib/Target/AVR/AVRDevices.td
new file mode 100644
index 0000000..9224af6
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRDevices.td
@@ -0,0 +1,491 @@
+//===---------------------------------------------------------------------===//
+// AVR Device Definitions
+//===---------------------------------------------------------------------===//
+
+// :TODO: Implement the skip errata, see `gcc/config/avr/avr-arch.h` for details
+// :TODO: We define all devices with SRAM to have all variants of LD/ST/LDD/STD.
+// In reality, avr1 (no SRAM) has one variant each of `LD` and `ST`.
+// avr2 (with SRAM) adds the rest of the variants.
+// :TODO: s/AVRTiny/Tiny
+
+
+// A feature set aggregates features, grouping them. We don't want to create a
+// new member in AVRSubtarget (to store a value) for each set because we do not
+// care if the set is supported, only the subfeatures inside the set. We fix
+// this by simply setting the same dummy member for all feature sets, which is
+// then ignored.
+class FeatureSet<string name, string desc, list<SubtargetFeature> i>
+ : SubtargetFeature<name, "m_FeatureSetDummy", "true", desc, i>;
+
+// A family of microcontrollers, defining a set of supported features.
+class Family<string name, list<SubtargetFeature> i>
+ : FeatureSet<name, !strconcat("The device is a part of the ",
+ name, " family"), i>;
+
+// The device has SRAM, and supports the bare minimum of
+// SRAM-relevant instructions.
+//
+// These are:
+// LD - all 9 variants
+// ST - all 9 variants
+// LDD - two variants for Y and Z
+// STD - two variants for Y and Z
+// `LDS Rd, K`
+// `STS k, Rr`
+// `PUSH`/`POP`
+def FeatureSRAM : SubtargetFeature<"sram", "m_hasSRAM", "true",
+ "The device has random access memory">;
+
+// The device supports the `JMP k` and `CALL k` instructions.
+def FeatureJMPCALL : SubtargetFeature<"jmpcall", "m_hasJMPCALL", "true",
+ "The device supports the `JMP` and "
+ "`CALL` instructions">;
+
+
+// The device supports the indirect branches `IJMP` and `ICALL`.
+def FeatureIJMPCALL : SubtargetFeature<"ijmpcall", "m_hasIJMPCALL",
+ "true",
+ "The device supports `IJMP`/`ICALL`"
+ "instructions">;
+
+// The device supports the extended indirect branches `EIJMP` and `EICALL`.
+def FeatureEIJMPCALL : SubtargetFeature<"eijmpcall", "m_hasEIJMPCALL",
+ "true", "The device supports the "
+ "`EIJMP`/`EICALL` instructions">;
+
+// The device supports `ADDI Rd, K`, `SUBI Rd, K`.
+def FeatureADDSUBIW : SubtargetFeature<"addsubiw", "m_hasADDSUBIW",
+ "true", "Enable 16-bit register-immediate "
+ "addition and subtraction instructions">;
+
+// The device has an 8-bit stack pointer (SP) register.
+def FeatureSmallStack : SubtargetFeature<"smallstack", "m_hasSmallStack",
+ "true", "The device has an 8-bit "
+ "stack pointer">;
+
+// The device supports the 16-bit GPR pair MOVW instruction.
+def FeatureMOVW : SubtargetFeature<"movw", "m_hasMOVW", "true",
+ "The device supports the 16-bit MOVW "
+ "instruction">;
+
+// The device supports the `LPM` instruction, with implied destination being r0.
+def FeatureLPM : SubtargetFeature<"lpm", "m_hasLPM", "true",
+ "The device supports the `LPM` instruction">;
+
+// The device supports the `LPM Rd, Z[+] instruction.
+def FeatureLPMX : SubtargetFeature<"lpmx", "m_hasLPMX", "true",
+ "The device supports the `LPM Rd, Z[+]` "
+ "instruction">;
+
+// The device supports the `ELPM` instruction.
+def FeatureELPM : SubtargetFeature<"elpm", "m_hasELPM", "true",
+ "The device supports the ELPM instruction">;
+
+// The device supports the `ELPM Rd, Z[+]` instructions.
+def FeatureELPMX : SubtargetFeature<"elpmx", "m_hasELPMX", "true",
+ "The device supports the `ELPM Rd, Z[+]` "
+ "instructions">;
+
+// The device supports the `SPM` instruction.
+def FeatureSPM : SubtargetFeature<"spm", "m_hasSPM", "true",
+ "The device supports the `SPM` instruction">;
+
+// The device supports the `SPM Z+` instruction.
+def FeatureSPMX : SubtargetFeature<"spmx", "m_hasSPMX", "true",
+ "The device supports the `SPM Z+` "
+ "instruction">;
+
+// The device supports the `DES k` instruction.
+def FeatureDES : SubtargetFeature<"des", "m_hasDES", "true",
+ "The device supports the `DES k` encryption "
+ "instruction">;
+
+// The device supports the Read-Write-Modify instructions
+// XCH, LAS, LAC, and LAT.
+def FeatureRMW : SubtargetFeature<"rmw", "m_supportsRMW", "true",
+ "The device supports the read-write-modify "
+ "instructions: XCH, LAS, LAC, LAT">;
+
+// The device supports the `[F]MUL[S][U]` family of instructions.
+def FeatureMultiplication : SubtargetFeature<"mul", "m_supportsMultiplication",
+ "true", "The device supports the "
+ "multiplication instructions">;
+
+// The device supports the `BREAK` instruction.
+def FeatureBREAK : SubtargetFeature<"break", "m_hasBREAK", "true",
+ "The device supports the `BREAK` debugging "
+ "instruction">;
+
+// The device has instruction encodings specific to the Tiny core.
+def FeatureTinyEncoding : SubtargetFeature<"tinyencoding",
+ "m_hasTinyEncoding", "true",
+ "The device has Tiny core specific "
+ "instruction encodings">;
+
+class ELFArch<string name> : SubtargetFeature<"", "ELFArch",
+ !strconcat("ELF::",name), "">;
+
+// ELF e_flags architecture values
+def ELFArchAVR1 : ELFArch<"EF_AVR_ARCH_AVR1">;
+def ELFArchAVR2 : ELFArch<"EF_AVR_ARCH_AVR2">;
+def ELFArchAVR25 : ELFArch<"EF_AVR_ARCH_AVR25">;
+def ELFArchAVR3 : ELFArch<"EF_AVR_ARCH_AVR3">;
+def ELFArchAVR31 : ELFArch<"EF_AVR_ARCH_AVR31">;
+def ELFArchAVR35 : ELFArch<"EF_AVR_ARCH_AVR35">;
+def ELFArchAVR4 : ELFArch<"EF_AVR_ARCH_AVR4">;
+def ELFArchAVR5 : ELFArch<"EF_AVR_ARCH_AVR5">;
+def ELFArchAVR51 : ELFArch<"EF_AVR_ARCH_AVR51">;
+def ELFArchAVR6 : ELFArch<"EF_AVR_ARCH_AVR6">;
+def ELFArchAVRTiny : ELFArch<"EF_AVR_ARCH_AVRTINY">;
+def ELFArchXMEGA1 : ELFArch<"EF_AVR_ARCH_XMEGA1">;
+def ELFArchXMEGA2 : ELFArch<"EF_AVR_ARCH_XMEGA2">;
+def ELFArchXMEGA3 : ELFArch<"EF_AVR_ARCH_XMEGA3">;
+def ELFArchXMEGA4 : ELFArch<"EF_AVR_ARCH_XMEGA4">;
+def ELFArchXMEGA5 : ELFArch<"EF_AVR_ARCH_XMEGA5">;
+def ELFArchXMEGA6 : ELFArch<"EF_AVR_ARCH_XMEGA6">;
+def ELFArchXMEGA7 : ELFArch<"EF_AVR_ARCH_XMEGA7">;
+
+//===---------------------------------------------------------------------===//
+// AVR Families
+//===---------------------------------------------------------------------===//
+
+// The device has at least the bare minimum that **every** single AVR
+// device should have.
+def FamilyAVR0 : Family<"avr0", []>;
+
+def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM]>;
+
+def FamilyAVR2 : Family<"avr2",
+ [FamilyAVR1, FeatureIJMPCALL, FeatureADDSUBIW,
+ FeatureSRAM]>;
+
+def FamilyAVR25 : Family<"avr25",
+ [FamilyAVR2, FeatureMOVW, FeatureLPMX,
+ FeatureSPM, FeatureBREAK]>;
+
+def FamilyAVR3 : Family<"avr3",
+ [FamilyAVR2, FeatureJMPCALL]>;
+
+def FamilyAVR31 : Family<"avr31",
+ [FamilyAVR3, FeatureELPM]>;
+
+def FamilyAVR35 : Family<"avr35",
+ [FamilyAVR3, FeatureMOVW, FeatureLPMX,
+ FeatureSPM, FeatureBREAK]>;
+
+def FamilyAVR4 : Family<"avr4",
+ [FamilyAVR2, FeatureMultiplication,
+ FeatureMOVW, FeatureLPMX, FeatureSPM,
+ FeatureBREAK]>;
+
+def FamilyAVR5 : Family<"avr5",
+ [FamilyAVR3, FeatureMultiplication,
+ FeatureMOVW, FeatureLPMX, FeatureSPM,
+ FeatureBREAK]>;
+
+def FamilyAVR51 : Family<"avr51",
+ [FamilyAVR5, FeatureELPM, FeatureELPMX]>;
+
+def FamilyAVR6 : Family<"avr6",
+ [FamilyAVR51]>;
+
+def FamilyAVRTiny : Family<"avrtiny",
+ [FamilyAVR0, FeatureBREAK, FeatureSRAM,
+ FeatureTinyEncoding]>;
+
+def FamilyXMEGA : Family<"xmega",
+ [FamilyAVR51, FeatureEIJMPCALL, FeatureSPMX,
+ FeatureDES]>;
+
+def FamilyXMEGAU : Family<"xmegau",
+ [FamilyXMEGA, FeatureRMW]>;
+
+def FeatureSetSpecial : FeatureSet<"special",
+ "Enable use of the entire instruction "
+ "set - used for debugging",
+ [FeatureSRAM, FeatureJMPCALL,
+ FeatureIJMPCALL, FeatureEIJMPCALL,
+ FeatureADDSUBIW, FeatureMOVW,
+ FeatureLPM, FeatureLPMX, FeatureELPM,
+ FeatureELPMX, FeatureSPM, FeatureSPMX,
+ FeatureDES, FeatureRMW,
+ FeatureMultiplication, FeatureBREAK]>;
+
+//===---------------------------------------------------------------------===//
+// AVR microcontrollers supported.
+//===---------------------------------------------------------------------===//
+
+class Device<string Name, Family Fam, ELFArch Arch,
+ list<SubtargetFeature> ExtraFeatures = []>
+ : Processor<Name, NoItineraries, !listconcat([Fam,Arch],ExtraFeatures)>;
+
+// Generic MCUs
+// Note that several versions of GCC has strange ELF architecture
+// settings for backwards compatibility - see `gas/config/tc-avr.c`
+// in AVR binutils. We do not replicate this.
+def : Device<"avr1", FamilyAVR1, ELFArchAVR1>;
+def : Device<"avr2", FamilyAVR2, ELFArchAVR2>;
+def : Device<"avr25", FamilyAVR25, ELFArchAVR25>;
+def : Device<"avr3", FamilyAVR3, ELFArchAVR3>;
+def : Device<"avr31", FamilyAVR31, ELFArchAVR31>;
+def : Device<"avr35", FamilyAVR35, ELFArchAVR35>;
+def : Device<"avr4", FamilyAVR4, ELFArchAVR4>;
+def : Device<"avr5", FamilyAVR5, ELFArchAVR5>;
+def : Device<"avr51", FamilyAVR51, ELFArchAVR51>;
+def : Device<"avr6", FamilyAVR6, ELFArchAVR6>;
+def : Device<"avrxmega1", FamilyXMEGA, ELFArchXMEGA1>;
+def : Device<"avrxmega2", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"avrxmega3", FamilyXMEGA, ELFArchXMEGA3>;
+def : Device<"avrxmega4", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"avrxmega5", FamilyXMEGA, ELFArchXMEGA5>;
+def : Device<"avrxmega6", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"avrxmega7", FamilyXMEGA, ELFArchXMEGA7>;
+def : Device<"avrtiny", FamilyAVRTiny, ELFArchAVRTiny>;
+
+// Specific MCUs
+def : Device<"at90s1200", FamilyAVR0, ELFArchAVR1>;
+def : Device<"attiny11", FamilyAVR1, ELFArchAVR1>;
+def : Device<"attiny12", FamilyAVR1, ELFArchAVR1>;
+def : Device<"attiny15", FamilyAVR1, ELFArchAVR1>;
+def : Device<"attiny28", FamilyAVR1, ELFArchAVR1>;
+def : Device<"at90s2313", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s2323", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s2333", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s2343", FamilyAVR2, ELFArchAVR2>;
+def : Device<"attiny22", FamilyAVR2, ELFArchAVR2>;
+def : Device<"attiny26", FamilyAVR2, ELFArchAVR2, [FeatureLPMX]>;
+def : Device<"at86rf401", FamilyAVR2, ELFArchAVR25,
+ [FeatureMOVW, FeatureLPMX]>;
+def : Device<"at90s4414", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s4433", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s4434", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s8515", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90c8534", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s8535", FamilyAVR2, ELFArchAVR2>;
+def : Device<"ata5272", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny13", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny13a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny2313", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny2313a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny24", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny24a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny4313", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny44", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny44a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny84", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny84a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny25", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny45", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny85", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny261", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny261a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny461", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny461a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny861", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny861a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny87", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny43u", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny48", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny88", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny828", FamilyAVR25, ELFArchAVR25>;
+def : Device<"at43usb355", FamilyAVR3, ELFArchAVR3>;
+def : Device<"at76c711", FamilyAVR3, ELFArchAVR3>;
+def : Device<"atmega103", FamilyAVR31, ELFArchAVR31>;
+def : Device<"at43usb320", FamilyAVR31, ELFArchAVR31>;
+def : Device<"attiny167", FamilyAVR35, ELFArchAVR35>;
+def : Device<"at90usb82", FamilyAVR35, ELFArchAVR35>;
+def : Device<"at90usb162", FamilyAVR35, ELFArchAVR35>;
+def : Device<"ata5505", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega8u2", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega16u2", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega32u2", FamilyAVR35, ELFArchAVR35>;
+def : Device<"attiny1634", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega8", FamilyAVR4, ELFArchAVR4>; // FIXME: family may be wrong
+def : Device<"ata6289", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega8a", FamilyAVR4, ELFArchAVR4>;
+def : Device<"ata6285", FamilyAVR4, ELFArchAVR4>;
+def : Device<"ata6286", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48a", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48pa", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48p", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88a", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88p", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88pa", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega8515", FamilyAVR2, ELFArchAVR4,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega8535", FamilyAVR2, ELFArchAVR4,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega8hva", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm1", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm2", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm2b", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm3", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm3b", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm81", FamilyAVR4, ELFArchAVR4>;
+def : Device<"ata5790", FamilyAVR5, ELFArchAVR5>;
+def : Device<"ata5795", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega161", FamilyAVR3, ELFArchAVR5,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega162", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega163", FamilyAVR3, ELFArchAVR5,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega164a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega164p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega164pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega323", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega324a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega324p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega324pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega328", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega328p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega406", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega640", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega645", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega645a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega645p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega649", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega649a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega649p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6450", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6450a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6450p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6490", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6490a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6490p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64rfr2", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644rfr2", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hva", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hva2", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hvb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hvbrevb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32hvb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32hvbrevb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64hve", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90can32", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90can64", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90pwm161", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90pwm216", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90pwm316", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32c1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64c1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16m1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32m1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64m1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16u4", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32u4", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32u6", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90usb646", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90usb647", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90scr100", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at94k", FamilyAVR3, ELFArchAVR5,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX]>;
+def : Device<"m3000", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega128", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega128a", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1280", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1281", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1284", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1284p", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega128rfa1", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega128rfr2", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1284rfr2", FamilyAVR51, ELFArchAVR51>;
+def : Device<"at90can128", FamilyAVR51, ELFArchAVR51>;
+def : Device<"at90usb1286", FamilyAVR51, ELFArchAVR51>;
+def : Device<"at90usb1287", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega2560", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atmega2561", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atmega256rfr2", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atmega2564rfr2", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atxmega16a4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega16a4u", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega16c4", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega16d4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32a4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32a4u", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega32c4", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega32d4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32e5", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega16e5", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega8e5", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32x1", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega64a3", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"atxmega64a3u", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64a4u", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64b1", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64b3", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64c3", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64d3", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"atxmega64d4", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"atxmega64a1", FamilyXMEGA, ELFArchXMEGA5>;
+def : Device<"atxmega64a1u", FamilyXMEGAU, ELFArchXMEGA5>;
+def : Device<"atxmega128a3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega128a3u", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128b1", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128b3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega128d4", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega192a3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega192a3u", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega192c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega192d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega256a3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega256a3u", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega256a3b", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega256a3bu", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega256c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega256d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega384c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega384d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega128a1", FamilyXMEGA, ELFArchXMEGA7>;
+def : Device<"atxmega128a1u", FamilyXMEGAU, ELFArchXMEGA7>;
+def : Device<"atxmega128a4u", FamilyXMEGAU, ELFArchXMEGA7>;
+def : Device<"attiny4", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny5", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny9", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny10", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny20", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny40", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny102", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny104", FamilyAVRTiny, ELFArchAVRTiny>;
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
new file mode 100644
index 0000000..1b2f2ce
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -0,0 +1,1515 @@
+//===-- AVRExpandPseudoInsts.cpp - Expand pseudo instructions -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass that expands pseudo instructions into target
+// instructions. This pass should be run after register allocation but before
+// the post-regalloc scheduling pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRInstrInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#define AVR_EXPAND_PSEUDO_NAME "AVR pseudo instruction expansion pass"
+
+namespace {
+
+/// Expands "placeholder" instructions marked as pseudo into
+/// actual AVR instructions.
+class AVRExpandPseudo : public MachineFunctionPass {
+public:
+ static char ID;
+
+ AVRExpandPseudo() : MachineFunctionPass(ID) {
+ initializeAVRExpandPseudoPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override { return AVR_EXPAND_PSEUDO_NAME; }
+
+private:
+ typedef MachineBasicBlock Block;
+ typedef Block::iterator BlockIt;
+
+ const AVRRegisterInfo *TRI;
+ const TargetInstrInfo *TII;
+
+ /// The register to be used for temporary storage.
+ const unsigned SCRATCH_REGISTER = AVR::R0;
+ /// The IO address of the status register.
+ const unsigned SREG_ADDR = 0x3f;
+
+ bool expandMBB(Block &MBB);
+ bool expandMI(Block &MBB, BlockIt MBBI);
+ template <unsigned OP> bool expand(Block &MBB, BlockIt MBBI);
+
+ MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) {
+ return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode));
+ }
+
+ MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode,
+ unsigned DstReg) {
+ return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode), DstReg);
+ }
+
+ MachineRegisterInfo &getRegInfo(Block &MBB) { return MBB.getParent()->getRegInfo(); }
+
+ bool expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI);
+ bool expandLogic(unsigned Op, Block &MBB, BlockIt MBBI);
+ bool expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI);
+ bool isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const;
+
+ template<typename Func>
+ bool expandAtomic(Block &MBB, BlockIt MBBI, Func f);
+
+ template<typename Func>
+ bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI, Func f);
+
+ bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI);
+
+ bool expandAtomicArithmeticOp(unsigned MemOpcode,
+ unsigned ArithOpcode,
+ Block &MBB,
+ BlockIt MBBI);
+};
+
+char AVRExpandPseudo::ID = 0;
+
+bool AVRExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
+ bool Modified = false;
+
+ BlockIt MBBI = MBB.begin(), E = MBB.end();
+ while (MBBI != E) {
+ BlockIt NMBBI = std::next(MBBI);
+ Modified |= expandMI(MBB, MBBI);
+ MBBI = NMBBI;
+ }
+
+ return Modified;
+}
+
+bool AVRExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
+ bool Modified = false;
+
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ TRI = STI.getRegisterInfo();
+ TII = STI.getInstrInfo();
+
+ // We need to track liveness in order to use register scavenging.
+ MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness);
+
+ for (Block &MBB : MF) {
+ bool ContinueExpanding = true;
+ unsigned ExpandCount = 0;
+
+ // Continue expanding the block until all pseudos are expanded.
+ do {
+ assert(ExpandCount < 10 && "pseudo expand limit reached");
+
+ bool BlockModified = expandMBB(MBB);
+ Modified |= BlockModified;
+ ExpandCount++;
+
+ ContinueExpanding = BlockModified;
+ } while (ContinueExpanding);
+ }
+
+ return Modified;
+}
+
+bool AVRExpandPseudo::
+expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::
+expandLogic(unsigned Op, Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, Op)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ // SREG is always implicitly dead
+ MIBLO->getOperand(3).setIsDead();
+
+ auto MIBHI = buildMI(MBB, MBBI, Op)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::
+ isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const {
+
+ // ANDI Rd, 0xff is redundant.
+ if (Op == AVR::ANDIRdK && ImmVal == 0xff)
+ return true;
+
+ // ORI Rd, 0x0 is redundant.
+ if (Op == AVR::ORIRdK && ImmVal == 0x0)
+ return true;
+
+ return false;
+}
+
+bool AVRExpandPseudo::
+expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ unsigned Imm = MI.getOperand(2).getImm();
+ unsigned Lo8 = Imm & 0xff;
+ unsigned Hi8 = (Imm >> 8) & 0xff;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ if (!isLogicImmOpRedundant(Op, Lo8)) {
+ auto MIBLO = buildMI(MBB, MBBI, Op)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(SrcIsKill))
+ .addImm(Lo8);
+
+ // SREG is always implicitly dead
+ MIBLO->getOperand(3).setIsDead();
+ }
+
+ if (!isLogicImmOpRedundant(Op, Hi8)) {
+ auto MIBHI = buildMI(MBB, MBBI, Op)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(SrcIsKill))
+ .addImm(Hi8);
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+ }
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ADDWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::ADDRdRr, AVR::ADCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ADCWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::ADCRdRr, AVR::ADCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SUBWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::SUBRdRr, AVR::SBCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SUBIWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, AVR::SUBIRdK)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, AVR::SBCIRdK)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(SrcIsKill));
+
+ switch (MI.getOperand(2).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(2).getGlobal();
+ int64_t Offs = MI.getOperand(2).getOffset();
+ unsigned TF = MI.getOperand(2).getTargetFlags();
+ MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG | AVRII::MO_LO);
+ MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG | AVRII::MO_HI);
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(2).getImm();
+ MIBLO.addImm(Imm & 0xff);
+ MIBHI.addImm((Imm >> 8) & 0xff);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SBCWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::SBCRdRr, AVR::SBCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SBCIWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ unsigned Imm = MI.getOperand(2).getImm();
+ unsigned Lo8 = Imm & 0xff;
+ unsigned Hi8 = (Imm >> 8) & 0xff;
+ OpLo = AVR::SBCIRdK;
+ OpHi = AVR::SBCIRdK;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(SrcIsKill))
+ .addImm(Lo8);
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(4).setIsKill();
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(SrcIsKill))
+ .addImm(Hi8);
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ANDWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandLogic(AVR::ANDRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ANDIWRdK>(Block &MBB, BlockIt MBBI) {
+ return expandLogicImm(AVR::ANDIRdK, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ORWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandLogic(AVR::ORRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ORIWRdK>(Block &MBB, BlockIt MBBI) {
+ return expandLogicImm(AVR::ORIRdK, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::EORWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandLogic(AVR::EORRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::COMWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::COMRd;
+ OpHi = AVR::COMRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ // SREG is always implicitly dead
+ MIBLO->getOperand(2).setIsDead();
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::CPWRdRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::CPRdRr;
+ OpHi = AVR::CPCRdRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::CPCWRdRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::CPCRdRr;
+ OpHi = AVR::CPCRdRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(3).setIsKill();
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDIWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ OpLo = AVR::LDIRdK;
+ OpHi = AVR::LDIRdK;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ switch (MI.getOperand(1).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(1).getGlobal();
+ int64_t Offs = MI.getOperand(1).getOffset();
+ unsigned TF = MI.getOperand(1).getTargetFlags();
+
+ MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_LO);
+ MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_HI);
+ break;
+ }
+ case MachineOperand::MO_BlockAddress: {
+ const BlockAddress *BA = MI.getOperand(1).getBlockAddress();
+ unsigned TF = MI.getOperand(1).getTargetFlags();
+
+ MIBLO.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_LO));
+ MIBHI.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_HI));
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(1).getImm();
+
+ MIBLO.addImm(Imm & 0xff);
+ MIBHI.addImm((Imm >> 8) & 0xff);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDSWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ OpLo = AVR::LDSRdK;
+ OpHi = AVR::LDSRdK;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ switch (MI.getOperand(1).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(1).getGlobal();
+ int64_t Offs = MI.getOperand(1).getOffset();
+ unsigned TF = MI.getOperand(1).getTargetFlags();
+
+ MIBLO.addGlobalAddress(GV, Offs, TF);
+ MIBHI.addGlobalAddress(GV, Offs + 1, TF);
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(1).getImm();
+
+ MIBLO.addImm(Imm);
+ MIBHI.addImm(Imm + 1);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::LDRdPtr;
+ OpHi = AVR::LDDRdPtrQ;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(1);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDWRdPtrPi>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsDead = MI.getOperand(1).isKill();
+ OpLo = AVR::LDRdPtrPi;
+ OpHi = AVR::LDRdPtrPi;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define)
+ .addReg(SrcReg, RegState::Kill);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead))
+ .addReg(SrcReg, RegState::Kill);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDWRdPtrPd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsDead = MI.getOperand(1).isKill();
+ OpLo = AVR::LDRdPtrPd;
+ OpHi = AVR::LDRdPtrPd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define)
+ .addReg(SrcReg, RegState::Kill);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead))
+ .addReg(SrcReg, RegState::Kill);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned Imm = MI.getOperand(2).getImm();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::LDDRdPtrQ;
+ OpHi = AVR::LDDRdPtrQ;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(Imm <= 63 && "Offset is out of range");
+
+ MachineInstr *MIBLO, *MIBHI;
+
+ // HACK: We shouldn't have instances of this instruction
+ // where src==dest because the instruction itself is
+ // marked earlyclobber. We do however get this instruction when
+ // loading from stack slots where the earlyclobber isn't useful.
+ //
+ // In this case, just use a temporary register.
+ if (DstReg == SrcReg) {
+ RegScavenger RS;
+
+ RS.enterBasicBlock(MBB);
+ RS.forward(MBBI);
+
+ BitVector Candidates =
+ TRI->getAllocatableSet
+ (*MBB.getParent(), &AVR::GPR8RegClass);
+
+ // Exclude all the registers being used by the instruction.
+ for (MachineOperand &MO : MI.operands()) {
+ if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() &&
+ !TargetRegisterInfo::isVirtualRegister(MO.getReg()))
+ Candidates.reset(MO.getReg());
+ }
+
+ BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass);
+ Available &= Candidates;
+
+ signed TmpReg = Available.find_first();
+ assert(TmpReg != -1 && "ran out of registers");
+
+ MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(TmpReg, RegState::Define)
+ .addReg(SrcReg)
+ .addImm(Imm);
+
+ buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstLoReg).addReg(TmpReg);
+
+ MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(TmpReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(Imm + 1);
+
+ buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
+ } else {
+ MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg)
+ .addImm(Imm);
+
+ MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(Imm + 1);
+ }
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("wide LPM is unimplemented");
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LPMWRdZPi>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("wide LPMPi is unimplemented");
+}
+
+template<typename Func>
+bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) {
+ // Remove the pseudo instruction.
+ MachineInstr &MI = *MBBI;
+
+ // Store the SREG.
+ buildMI(MBB, MBBI, AVR::INRdA)
+ .addReg(SCRATCH_REGISTER, RegState::Define)
+ .addImm(SREG_ADDR);
+
+ // Disable exceptions.
+ buildMI(MBB, MBBI, AVR::BCLRs).addImm(7); // CLI
+
+ f(MI);
+
+ // Restore the status reg.
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(SREG_ADDR)
+ .addReg(SCRATCH_REGISTER);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template<typename Func>
+bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode,
+ Block &MBB,
+ BlockIt MBBI,
+ Func f) {
+ return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
+ auto Op1 = MI.getOperand(0);
+ auto Op2 = MI.getOperand(1);
+
+ MachineInstr &NewInst = *buildMI(MBB, MBBI, Opcode)
+ .addOperand(Op1).addOperand(Op2)
+ .getInstr();
+ f(NewInst);
+ });
+}
+
+bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode,
+ Block &MBB,
+ BlockIt MBBI) {
+ return expandAtomicBinaryOp(Opcode, MBB, MBBI, [](MachineInstr &MI) {});
+}
+
+bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width,
+ unsigned ArithOpcode,
+ Block &MBB,
+ BlockIt MBBI) {
+ return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
+ auto Op1 = MI.getOperand(0);
+ auto Op2 = MI.getOperand(1);
+
+ unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr : AVR::LDWRdPtr;
+ unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr;
+
+ // Create the load
+ buildMI(MBB, MBBI, LoadOpcode).addOperand(Op1).addOperand(Op2);
+
+ // Create the arithmetic op
+ buildMI(MBB, MBBI, ArithOpcode)
+ .addOperand(Op1).addOperand(Op1)
+ .addOperand(Op2);
+
+ // Create the store
+ buildMI(MBB, MBBI, StoreOpcode).addOperand(Op2).addOperand(Op1);
+ });
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoad8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoad16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::LDWRdPtr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicStore8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::STPtrRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicStore16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::STWPtrRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::ADDRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::ADDWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadSub8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::SUBRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadSub16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::SUBWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::ANDRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::ANDWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadOr8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::ORRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadOr16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::ORWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadXor8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::EORRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadXor16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::EORWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicFence>(Block &MBB, BlockIt MBBI) {
+ // On AVR, there is only one core and so atomic fences do nothing.
+ MBBI->eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STSWKRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::STSKRr;
+ OpHi = AVR::STSKRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ // Write the high byte first in case this address belongs to a special
+ // I/O address with a special temporary register.
+ auto MIBHI = buildMI(MBB, MBBI, OpHi);
+ auto MIBLO = buildMI(MBB, MBBI, OpLo);
+
+ switch (MI.getOperand(0).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(0).getGlobal();
+ int64_t Offs = MI.getOperand(0).getOffset();
+ unsigned TF = MI.getOperand(0).getTargetFlags();
+
+ MIBLO.addGlobalAddress(GV, Offs, TF);
+ MIBHI.addGlobalAddress(GV, Offs + 1, TF);
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(0).getImm();
+
+ MIBLO.addImm(Imm);
+ MIBHI.addImm(Imm + 1);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ MIBLO.addReg(SrcLoReg, getKillRegState(SrcIsKill));
+ MIBHI.addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::STPtrRr;
+ OpHi = AVR::STDPtrQRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ //:TODO: need to reverse this order like inw and stsw?
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addImm(1)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STWPtrPiRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned Imm = MI.getOperand(3).getImm();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ OpLo = AVR::STPtrPiRr;
+ OpHi = AVR::STPtrPiRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg, RegState::Define)
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STWPtrPdRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned Imm = MI.getOperand(3).getImm();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ OpLo = AVR::STPtrPdRr;
+ OpHi = AVR::STPtrPdRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, RegState::Define)
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned Imm = MI.getOperand(1).getImm();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ OpLo = AVR::STDPtrQRr;
+ OpHi = AVR::STDPtrQRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(Imm <= 63 && "Offset is out of range");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg)
+ .addImm(Imm)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addImm(Imm + 1)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned Imm = MI.getOperand(1).getImm();
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ OpLo = AVR::INRdA;
+ OpHi = AVR::INRdA;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(Imm <= 63 && "Address is out of range");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(Imm);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(Imm + 1);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned Imm = MI.getOperand(0).getImm();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::OUTARr;
+ OpHi = AVR::OUTARr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(Imm <= 63 && "Address is out of range");
+
+ // 16 bit I/O writes need the high byte first
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addImm(Imm + 1)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addImm(Imm)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::PUSHWRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned SrcReg = MI.getOperand(0).getReg();
+ bool SrcIsKill = MI.getOperand(0).isKill();
+ unsigned Flags = MI.getFlags();
+ OpLo = AVR::PUSHRr;
+ OpHi = AVR::PUSHRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::POPWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned Flags = MI.getFlags();
+ OpLo = AVR::POPRd;
+ OpHi = AVR::POPRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ buildMI(MBB, MBBI, OpHi, DstHiReg).setMIFlags(Flags); // High
+ buildMI(MBB, MBBI, OpLo, DstLoReg).setMIFlags(Flags); // Low
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::LSLRd;
+ OpHi = AVR::ROLRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::RORRd;
+ OpHi = AVR::LSRRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBLO->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("RORW unimplemented");
+ return false;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ROLWRd>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("ROLW unimplemented");
+ return false;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::RORRd;
+ OpHi = AVR::ASRRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBLO->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <> bool AVRExpandPseudo::expand<AVR::SEXT>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ // sext R17:R16, R17
+ // mov r16, r17
+ // lsl r17
+ // sbc r17, r17
+ // sext R17:R16, R13
+ // mov r16, r13
+ // mov r17, r13
+ // lsl r17
+ // sbc r17, r17
+ // sext R17:R16, R16
+ // mov r17, r16
+ // lsl r17
+ // sbc r17, r17
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ if (SrcReg != DstLoReg) {
+ auto MOV = buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg);
+
+ if (SrcReg == DstHiReg) {
+ MOV->getOperand(1).setIsKill();
+ }
+ }
+
+ if (SrcReg != DstHiReg) {
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstHiReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ }
+
+ buildMI(MBB, MBBI, AVR::LSLRd)
+ .addReg(DstHiReg, RegState::Define)
+ .addReg(DstHiReg, RegState::Kill);
+
+ auto SBC = buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ if (ImpIsDead)
+ SBC->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ SBC->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <> bool AVRExpandPseudo::expand<AVR::ZEXT>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ // zext R25:R24, R20
+ // mov R24, R20
+ // eor R25, R25
+ // zext R25:R24, R24
+ // eor R25, R25
+ // zext R25:R24, R25
+ // mov R24, R25
+ // eor R25, R25
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ if (SrcReg != DstLoReg) {
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ }
+
+ auto EOR = buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ if (ImpIsDead)
+ EOR->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SPREAD>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ unsigned Flags = MI.getFlags();
+ OpLo = AVR::INRdA;
+ OpHi = AVR::INRdA;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(0x3d)
+ .setMIFlags(Flags);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(0x3e)
+ .setMIFlags(Flags);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned SrcLoReg, SrcHiReg;
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ unsigned Flags = MI.getFlags();
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ buildMI(MBB, MBBI, AVR::INRdA)
+ .addReg(AVR::R0, RegState::Define)
+ .addImm(SREG_ADDR)
+ .setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(0x3e)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(SREG_ADDR)
+ .addReg(AVR::R0, RegState::Kill)
+ .setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(0x3d)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ int Opcode = MBBI->getOpcode();
+
+#define EXPAND(Op) \
+ case Op: \
+ return expand<Op>(MBB, MI)
+
+ switch (Opcode) {
+ EXPAND(AVR::ADDWRdRr);
+ EXPAND(AVR::ADCWRdRr);
+ EXPAND(AVR::SUBWRdRr);
+ EXPAND(AVR::SUBIWRdK);
+ EXPAND(AVR::SBCWRdRr);
+ EXPAND(AVR::SBCIWRdK);
+ EXPAND(AVR::ANDWRdRr);
+ EXPAND(AVR::ANDIWRdK);
+ EXPAND(AVR::ORWRdRr);
+ EXPAND(AVR::ORIWRdK);
+ EXPAND(AVR::EORWRdRr);
+ EXPAND(AVR::COMWRd);
+ EXPAND(AVR::CPWRdRr);
+ EXPAND(AVR::CPCWRdRr);
+ EXPAND(AVR::LDIWRdK);
+ EXPAND(AVR::LDSWRdK);
+ EXPAND(AVR::LDWRdPtr);
+ EXPAND(AVR::LDWRdPtrPi);
+ EXPAND(AVR::LDWRdPtrPd);
+ case AVR::LDDWRdYQ: //:FIXME: remove this once PR13375 gets fixed
+ EXPAND(AVR::LDDWRdPtrQ);
+ EXPAND(AVR::LPMWRdZ);
+ EXPAND(AVR::LPMWRdZPi);
+ EXPAND(AVR::AtomicLoad8);
+ EXPAND(AVR::AtomicLoad16);
+ EXPAND(AVR::AtomicStore8);
+ EXPAND(AVR::AtomicStore16);
+ EXPAND(AVR::AtomicLoadAdd8);
+ EXPAND(AVR::AtomicLoadAdd16);
+ EXPAND(AVR::AtomicLoadSub8);
+ EXPAND(AVR::AtomicLoadSub16);
+ EXPAND(AVR::AtomicLoadAnd8);
+ EXPAND(AVR::AtomicLoadAnd16);
+ EXPAND(AVR::AtomicLoadOr8);
+ EXPAND(AVR::AtomicLoadOr16);
+ EXPAND(AVR::AtomicLoadXor8);
+ EXPAND(AVR::AtomicLoadXor16);
+ EXPAND(AVR::AtomicFence);
+ EXPAND(AVR::STSWKRr);
+ EXPAND(AVR::STWPtrRr);
+ EXPAND(AVR::STWPtrPiRr);
+ EXPAND(AVR::STWPtrPdRr);
+ EXPAND(AVR::STDWPtrQRr);
+ EXPAND(AVR::INWRdA);
+ EXPAND(AVR::OUTWARr);
+ EXPAND(AVR::PUSHWRr);
+ EXPAND(AVR::POPWRd);
+ EXPAND(AVR::LSLWRd);
+ EXPAND(AVR::LSRWRd);
+ EXPAND(AVR::RORWRd);
+ EXPAND(AVR::ROLWRd);
+ EXPAND(AVR::ASRWRd);
+ EXPAND(AVR::SEXT);
+ EXPAND(AVR::ZEXT);
+ EXPAND(AVR::SPREAD);
+ EXPAND(AVR::SPWRITE);
+ }
+#undef EXPAND
+ return false;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRExpandPseudo, "avr-expand-pseudo",
+ AVR_EXPAND_PSEUDO_NAME, false, false)
+namespace llvm {
+
+FunctionPass *createAVRExpandPseudoPass() { return new AVRExpandPseudo(); }
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp
new file mode 100644
index 0000000..b8cb221
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -0,0 +1,538 @@
+//===-- AVRFrameLowering.cpp - AVR Frame Information ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the AVR implementation of TargetFrameLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRFrameLowering.h"
+
+#include "AVR.h"
+#include "AVRInstrInfo.h"
+#include "AVRMachineFunctionInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+
+#include <vector>
+
+namespace llvm {
+
+AVRFrameLowering::AVRFrameLowering()
+ : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 1, -2) {}
+
+bool AVRFrameLowering::canSimplifyCallFramePseudos(
+ const MachineFunction &MF) const {
+ // Always simplify call frame pseudo instructions, even when
+ // hasReservedCallFrame is false.
+ return true;
+}
+
+bool AVRFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
+ // Reserve call frame memory in function prologue under the following
+ // conditions:
+ // - Y pointer is reserved to be the frame pointer.
+ // - The function does not contain variable sized objects.
+
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ return hasFP(MF) && !MFI.hasVarSizedObjects();
+}
+
+void AVRFrameLowering::emitPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ MachineBasicBlock::iterator MBBI = MBB.begin();
+ CallingConv::ID CallConv = MF.getFunction()->getCallingConv();
+ DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const AVRInstrInfo &TII = *STI.getInstrInfo();
+
+ // Interrupt handlers re-enable interrupts in function entry.
+ if (CallConv == CallingConv::AVR_INTR) {
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
+ .addImm(0x07)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+
+ // Emit special prologue code to save R1, R0 and SREG in interrupt/signal
+ // handlers before saving any other registers.
+ if (CallConv == CallingConv::AVR_INTR ||
+ CallConv == CallingConv::AVR_SIGNAL) {
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHWRr))
+ .addReg(AVR::R1R0, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), AVR::R0)
+ .addImm(0x3f)
+ .setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
+ .addReg(AVR::R0, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
+ .addReg(AVR::R0, RegState::Define)
+ .addReg(AVR::R0, RegState::Kill)
+ .addReg(AVR::R0, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+
+ // Early exit if the frame pointer is not needed in this function.
+ if (!hasFP(MF)) {
+ return;
+ }
+
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
+
+ // Skip the callee-saved push instructions.
+ while (
+ (MBBI != MBB.end()) && MBBI->getFlag(MachineInstr::FrameSetup) &&
+ (MBBI->getOpcode() == AVR::PUSHRr || MBBI->getOpcode() == AVR::PUSHWRr)) {
+ ++MBBI;
+ }
+
+ // Update Y with the new base value.
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::SPREAD), AVR::R29R28)
+ .addReg(AVR::SP)
+ .setMIFlag(MachineInstr::FrameSetup);
+
+ // Mark the FramePtr as live-in in every block except the entry.
+ for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end();
+ I != E; ++I) {
+ I->addLiveIn(AVR::R29R28);
+ }
+
+ if (!FrameSize) {
+ return;
+ }
+
+ // Reserve the necessary frame memory by doing FP -= <size>.
+ unsigned Opcode = (isUInt<6>(FrameSize)) ? AVR::SBIWRdK : AVR::SUBIWRdK;
+
+ MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
+ .addReg(AVR::R29R28, RegState::Kill)
+ .addImm(FrameSize)
+ .setMIFlag(MachineInstr::FrameSetup);
+ // The SREG implicit def is dead.
+ MI->getOperand(3).setIsDead();
+
+ // Write back R29R28 to SP and temporarily disable interrupts.
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
+ .addReg(AVR::R29R28)
+ .setMIFlag(MachineInstr::FrameSetup);
+}
+
+void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ CallingConv::ID CallConv = MF.getFunction()->getCallingConv();
+ bool isHandler = (CallConv == CallingConv::AVR_INTR ||
+ CallConv == CallingConv::AVR_SIGNAL);
+
+ // Early exit if the frame pointer is not needed in this function except for
+ // signal/interrupt handlers where special code generation is required.
+ if (!hasFP(MF) && !isHandler) {
+ return;
+ }
+
+ MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+ assert(MBBI->getDesc().isReturn() &&
+ "Can only insert epilog into returning blocks");
+
+ DebugLoc DL = MBBI->getDebugLoc();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const AVRInstrInfo &TII = *STI.getInstrInfo();
+
+ // Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal
+ // handlers at the very end of the function, just before reti.
+ if (isHandler) {
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
+ .addImm(0x3f)
+ .addReg(AVR::R0, RegState::Kill);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::POPWRd), AVR::R1R0);
+ }
+
+ // Early exit if there is no need to restore the frame pointer.
+ if (!FrameSize) {
+ return;
+ }
+
+ // Skip the callee-saved pop instructions.
+ while (MBBI != MBB.begin()) {
+ MachineBasicBlock::iterator PI = std::prev(MBBI);
+ int Opc = PI->getOpcode();
+
+ if (Opc != AVR::POPRd && Opc != AVR::POPWRd && !PI->isTerminator()) {
+ break;
+ }
+
+ --MBBI;
+ }
+
+ unsigned Opcode;
+
+ // Select the optimal opcode depending on how big it is.
+ if (isUInt<6>(FrameSize)) {
+ Opcode = AVR::ADIWRdK;
+ } else {
+ Opcode = AVR::SUBIWRdK;
+ FrameSize = -FrameSize;
+ }
+
+ // Restore the frame pointer by doing FP += <size>.
+ MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
+ .addReg(AVR::R29R28, RegState::Kill)
+ .addImm(FrameSize);
+ // The SREG implicit def is dead.
+ MI->getOperand(3).setIsDead();
+
+ // Write back R29R28 to SP and temporarily disable interrupts.
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
+ .addReg(AVR::R29R28, RegState::Kill);
+}
+
+// Return true if the specified function should have a dedicated frame
+// pointer register. This is true if the function meets any of the following
+// conditions:
+// - a register has been spilled
+// - has allocas
+// - input arguments are passed using the stack
+//
+// Notice that strictly this is not a frame pointer because it contains SP after
+// frame allocation instead of having the original SP in function entry.
+bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
+ const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
+
+ return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||
+ FuncInfo->getHasStackArgs());
+}
+
+bool AVRFrameLowering::spillCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI,
+ const TargetRegisterInfo *TRI) const {
+ if (CSI.empty()) {
+ return false;
+ }
+
+ unsigned CalleeFrameSize = 0;
+ DebugLoc DL = MBB.findDebugLoc(MI);
+ MachineFunction &MF = *MBB.getParent();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+ AVRMachineFunctionInfo *AVRFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ for (unsigned i = CSI.size(); i != 0; --i) {
+ unsigned Reg = CSI[i - 1].getReg();
+ bool IsNotLiveIn = !MBB.isLiveIn(Reg);
+
+ assert(TRI->getMinimalPhysRegClass(Reg)->getSize() == 1 &&
+ "Invalid register size");
+
+ // Add the callee-saved register as live-in only if it is not already a
+ // live-in register, this usually happens with arguments that are passed
+ // through callee-saved registers.
+ if (IsNotLiveIn) {
+ MBB.addLiveIn(Reg);
+ }
+
+ // Do not kill the register when it is an input argument.
+ BuildMI(MBB, MI, DL, TII.get(AVR::PUSHRr))
+ .addReg(Reg, getKillRegState(IsNotLiveIn))
+ .setMIFlag(MachineInstr::FrameSetup);
+ ++CalleeFrameSize;
+ }
+
+ AVRFI->setCalleeSavedFrameSize(CalleeFrameSize);
+
+ return true;
+}
+
+bool AVRFrameLowering::restoreCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI,
+ const TargetRegisterInfo *TRI) const {
+ if (CSI.empty()) {
+ return false;
+ }
+
+ DebugLoc DL = MBB.findDebugLoc(MI);
+ const MachineFunction &MF = *MBB.getParent();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+
+ for (const CalleeSavedInfo &CCSI : CSI) {
+ unsigned Reg = CCSI.getReg();
+
+ assert(TRI->getMinimalPhysRegClass(Reg)->getSize() == 1 &&
+ "Invalid register size");
+
+ BuildMI(MBB, MI, DL, TII.get(AVR::POPRd), Reg);
+ }
+
+ return true;
+}
+
+/// Replace pseudo store instructions that pass arguments through the stack with
+/// real instructions. If insertPushes is true then all instructions are
+/// replaced with push instructions, otherwise regular std instructions are
+/// inserted.
+static void fixStackStores(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const TargetInstrInfo &TII, bool insertPushes) {
+ const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
+
+ // Iterate through the BB until we hit a call instruction or we reach the end.
+ for (auto I = MI, E = MBB.end(); I != E && !I->isCall();) {
+ MachineBasicBlock::iterator NextMI = std::next(I);
+ MachineInstr &MI = *I;
+ unsigned Opcode = I->getOpcode();
+
+ // Only care of pseudo store instructions where SP is the base pointer.
+ if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr) {
+ I = NextMI;
+ continue;
+ }
+
+ assert(MI.getOperand(0).getReg() == AVR::SP &&
+ "Invalid register, should be SP!");
+ if (insertPushes) {
+ // Replace this instruction with a push.
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+
+ // We can't use PUSHWRr here because when expanded the order of the new
+ // instructions are reversed from what we need. Perform the expansion now.
+ if (Opcode == AVR::STDWSPQRr) {
+ BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
+ .addReg(TRI.getSubReg(SrcReg, AVR::sub_hi),
+ getKillRegState(SrcIsKill));
+ BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
+ .addReg(TRI.getSubReg(SrcReg, AVR::sub_lo),
+ getKillRegState(SrcIsKill));
+ } else {
+ BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ }
+
+ MI.eraseFromParent();
+ I = NextMI;
+ continue;
+ }
+
+ // Replace this instruction with a regular store. Use Y as the base
+ // pointer since it is guaranteed to contain a copy of SP.
+ unsigned STOpc =
+ (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;
+
+ MI.setDesc(TII.get(STOpc));
+ MI.getOperand(0).setReg(AVR::R29R28);
+
+ I = NextMI;
+ }
+}
+
+MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
+ MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI) const {
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetFrameLowering &TFI = *STI.getFrameLowering();
+ const AVRInstrInfo &TII = *STI.getInstrInfo();
+
+ // There is nothing to insert when the call frame memory is allocated during
+ // function entry. Delete the call frame pseudo and replace all pseudo stores
+ // with real store instructions.
+ if (TFI.hasReservedCallFrame(MF)) {
+ fixStackStores(MBB, MI, TII, false);
+ return MBB.erase(MI);
+ }
+
+ DebugLoc DL = MI->getDebugLoc();
+ unsigned int Opcode = MI->getOpcode();
+ int Amount = MI->getOperand(0).getImm();
+
+ // Adjcallstackup does not need to allocate stack space for the call, instead
+ // we insert push instructions that will allocate the necessary stack.
+ // For adjcallstackdown we convert it into an 'adiw reg, <amt>' handling
+ // the read and write of SP in I/O space.
+ if (Amount != 0) {
+ assert(TFI.getStackAlignment() == 1 && "Unsupported stack alignment");
+
+ if (Opcode == TII.getCallFrameSetupOpcode()) {
+ fixStackStores(MBB, MI, TII, true);
+ } else {
+ assert(Opcode == TII.getCallFrameDestroyOpcode());
+
+ // Select the best opcode to adjust SP based on the offset size.
+ unsigned addOpcode;
+ if (isUInt<6>(Amount)) {
+ addOpcode = AVR::ADIWRdK;
+ } else {
+ addOpcode = AVR::SUBIWRdK;
+ Amount = -Amount;
+ }
+
+ // Build the instruction sequence.
+ BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
+
+ MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(addOpcode), AVR::R31R30)
+ .addReg(AVR::R31R30, RegState::Kill)
+ .addImm(Amount);
+ New->getOperand(3).setIsDead();
+
+ BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
+ .addReg(AVR::R31R30, RegState::Kill);
+ }
+ }
+
+ return MBB.erase(MI);
+}
+
+void AVRFrameLowering::determineCalleeSaves(MachineFunction &MF,
+ BitVector &SavedRegs,
+ RegScavenger *RS) const {
+ TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+
+ // Spill register Y when it is used as the frame pointer.
+ if (hasFP(MF)) {
+ SavedRegs.set(AVR::R29R28);
+ SavedRegs.set(AVR::R29);
+ SavedRegs.set(AVR::R28);
+ }
+}
+/// The frame analyzer pass.
+///
+/// Scans the function for allocas and used arguments
+/// that are passed through the stack.
+struct AVRFrameAnalyzer : public MachineFunctionPass {
+ static char ID;
+ AVRFrameAnalyzer() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) {
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
+
+ // If there are no fixed frame indexes during this stage it means there
+ // are allocas present in the function.
+ if (MFI.getNumObjects() != MFI.getNumFixedObjects()) {
+ // Check for the type of allocas present in the function. We only care
+ // about fixed size allocas so do not give false positives if only
+ // variable sized allocas are present.
+ for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
+ // Variable sized objects have size 0.
+ if (MFI.getObjectSize(i)) {
+ FuncInfo->setHasAllocas(true);
+ break;
+ }
+ }
+ }
+
+ // If there are fixed frame indexes present, scan the function to see if
+ // they are really being used.
+ if (MFI.getNumFixedObjects() == 0) {
+ return false;
+ }
+
+ // Ok fixed frame indexes present, now scan the function to see if they
+ // are really being used, otherwise we can ignore them.
+ for (const MachineBasicBlock &BB : MF) {
+ for (const MachineInstr &MI : BB) {
+ int Opcode = MI.getOpcode();
+
+ if ((Opcode != AVR::LDDRdPtrQ) && (Opcode != AVR::LDDWRdPtrQ) &&
+ (Opcode != AVR::STDPtrQRr) && (Opcode != AVR::STDWPtrQRr)) {
+ continue;
+ }
+
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isFI()) {
+ continue;
+ }
+
+ if (MFI.isFixedObjectIndex(MO.getIndex())) {
+ FuncInfo->setHasStackArgs(true);
+ return false;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ StringRef getPassName() const { return "AVR Frame Analyzer"; }
+};
+
+char AVRFrameAnalyzer::ID = 0;
+
+/// Creates instance of the frame analyzer pass.
+FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); }
+
+/// Create the Dynalloca Stack Pointer Save/Restore pass.
+/// Insert a copy of SP before allocating the dynamic stack memory and restore
+/// it in function exit to restore the original SP state. This avoids the need
+/// of reserving a register pair for a frame pointer.
+struct AVRDynAllocaSR : public MachineFunctionPass {
+ static char ID;
+ AVRDynAllocaSR() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) {
+ // Early exit when there are no variable sized objects in the function.
+ if (!MF.getFrameInfo().hasVarSizedObjects()) {
+ return false;
+ }
+
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+ MachineBasicBlock &EntryMBB = MF.front();
+ MachineBasicBlock::iterator MBBI = EntryMBB.begin();
+ DebugLoc DL = EntryMBB.findDebugLoc(MBBI);
+
+ unsigned SPCopy =
+ MF.getRegInfo().createVirtualRegister(&AVR::DREGSRegClass);
+
+ // Create a copy of SP in function entry before any dynallocas are
+ // inserted.
+ BuildMI(EntryMBB, MBBI, DL, TII.get(AVR::COPY), SPCopy).addReg(AVR::SP);
+
+ // Restore SP in all exit basic blocks.
+ for (MachineBasicBlock &MBB : MF) {
+ // If last instruction is a return instruction, add a restore copy.
+ if (!MBB.empty() && MBB.back().isReturn()) {
+ MBBI = MBB.getLastNonDebugInstr();
+ DL = MBBI->getDebugLoc();
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::COPY), AVR::SP)
+ .addReg(SPCopy, RegState::Kill);
+ }
+ }
+
+ return true;
+ }
+
+ StringRef getPassName() const {
+ return "AVR dynalloca stack pointer save/restore";
+ }
+};
+
+char AVRDynAllocaSR::ID = 0;
+
+/// createAVRDynAllocaSRPass - returns an instance of the dynalloca stack
+/// pointer save/restore pass.
+FunctionPass *createAVRDynAllocaSRPass() { return new AVRDynAllocaSR(); }
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp b/contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
new file mode 100644
index 0000000..462a7d5
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
@@ -0,0 +1,565 @@
+//===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an instruction selector for the AVR target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "avr-isel"
+
+namespace llvm {
+
+/// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
+class AVRDAGToDAGISel : public SelectionDAGISel {
+public:
+ AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOpt::Level OptLevel)
+ : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
+
+ StringRef getPassName() const override {
+ return "AVR DAG->DAG Instruction Selection";
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
+
+ bool selectIndexedLoad(SDNode *N);
+ unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT);
+
+ bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
+ std::vector<SDValue> &OutOps) override;
+
+// Include the pieces autogenerated from the target description.
+#include "AVRGenDAGISel.inc"
+
+private:
+ void Select(SDNode *N) override;
+ bool trySelect(SDNode *N);
+
+ template <unsigned NodeType> bool select(SDNode *N);
+ bool selectMultiplication(SDNode *N);
+
+ const AVRSubtarget *Subtarget;
+};
+
+bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
+ Subtarget = &MF.getSubtarget<AVRSubtarget>();
+ return SelectionDAGISel::runOnMachineFunction(MF);
+}
+
+bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
+ SDValue &Disp) {
+ SDLoc dl(Op);
+ auto DL = CurDAG->getDataLayout();
+ MVT PtrVT = getTargetLowering()->getPointerTy(DL);
+
+ // if the address is a frame index get the TargetFrameIndex.
+ if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
+ Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
+
+ return true;
+ }
+
+ // Match simple Reg + uimm6 operands.
+ if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
+ !CurDAG->isBaseWithConstantOffset(N)) {
+ return false;
+ }
+
+ if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ int RHSC = (int)RHS->getZExtValue();
+
+ // Convert negative offsets into positives ones.
+ if (N.getOpcode() == ISD::SUB) {
+ RHSC = -RHSC;
+ }
+
+ // <#Frame index + const>
+ // Allow folding offsets bigger than 63 so the frame pointer can be used
+ // directly instead of copying it around by adjusting and restoring it for
+ // each access.
+ if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
+ int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
+
+ Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
+ Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
+
+ return true;
+ }
+
+ // The value type of the memory instruction determines what is the maximum
+ // offset allowed.
+ MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT();
+
+ // We only accept offsets that fit in 6 bits (unsigned).
+ if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
+ Base = N.getOperand(0);
+ Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
+ const LoadSDNode *LD = cast<LoadSDNode>(N);
+ ISD::MemIndexedMode AM = LD->getAddressingMode();
+ MVT VT = LD->getMemoryVT().getSimpleVT();
+ auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
+
+ // We only care if this load uses a POSTINC or PREDEC mode.
+ if ((LD->getExtensionType() != ISD::NON_EXTLOAD) ||
+ (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) {
+
+ return false;
+ }
+
+ unsigned Opcode = 0;
+ bool isPre = (AM == ISD::PRE_DEC);
+ int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
+
+ switch (VT.SimpleTy) {
+ case MVT::i8: {
+ if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
+ return false;
+ }
+
+ Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
+ break;
+ }
+ case MVT::i16: {
+ if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
+ return false;
+ }
+
+ Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
+ break;
+ }
+ default:
+ return false;
+ }
+
+ SDNode *ResNode = CurDAG->getMachineNode(Opcode, SDLoc(N), VT,
+ PtrVT, MVT::Other,
+ LD->getBasePtr(), LD->getChain());
+ ReplaceUses(N, ResNode);
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD,
+ MVT VT) {
+ ISD::MemIndexedMode AM = LD->getAddressingMode();
+
+ // Progmem indexed loads only work in POSTINC mode.
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD || AM != ISD::POST_INC) {
+ return 0;
+ }
+
+ unsigned Opcode = 0;
+ int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
+
+ switch (VT.SimpleTy) {
+ case MVT::i8: {
+ if (Offs != 1) {
+ return 0;
+ }
+ Opcode = AVR::LPMRdZPi;
+ break;
+ }
+ case MVT::i16: {
+ if (Offs != 2) {
+ return 0;
+ }
+ Opcode = AVR::LPMWRdZPi;
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ return Opcode;
+}
+
+bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
+ unsigned ConstraintCode,
+ std::vector<SDValue> &OutOps) {
+ assert((ConstraintCode == InlineAsm::Constraint_m ||
+ ConstraintCode == InlineAsm::Constraint_Q) &&
+ "Unexpected asm memory constraint");
+
+ MachineRegisterInfo &RI = MF->getRegInfo();
+ const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
+ const TargetLowering &TL = *STI.getTargetLowering();
+ SDLoc dl(Op);
+ auto DL = CurDAG->getDataLayout();
+
+ const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op);
+
+ // If address operand is of PTRDISPREGS class, all is OK, then.
+ if (RegNode &&
+ RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
+ OutOps.push_back(Op);
+ return false;
+ }
+
+ if (Op->getOpcode() == ISD::FrameIndex) {
+ SDValue Base, Disp;
+
+ if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
+ OutOps.push_back(Base);
+ OutOps.push_back(Disp);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // If Op is add 'register, immediate' and
+ // register is either virtual register or register of PTRDISPREGSRegClass
+ if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) {
+ SDValue CopyFromRegOp = Op->getOperand(0);
+ SDValue ImmOp = Op->getOperand(1);
+ ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
+
+ unsigned Reg;
+ bool CanHandleRegImmOpt = true;
+
+ CanHandleRegImmOpt &= ImmNode != 0;
+ CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64;
+
+ if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
+ RegisterSDNode *RegNode =
+ cast<RegisterSDNode>(CopyFromRegOp->getOperand(1));
+ Reg = RegNode->getReg();
+ CanHandleRegImmOpt &= (TargetRegisterInfo::isVirtualRegister(Reg) ||
+ AVR::PTRDISPREGSRegClass.contains(Reg));
+ } else {
+ CanHandleRegImmOpt = false;
+ }
+
+ // If we detect proper case - correct virtual register class
+ // if needed and go to another inlineasm operand.
+ if (CanHandleRegImmOpt) {
+ SDValue Base, Disp;
+
+ if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
+ SDLoc dl(CopyFromRegOp);
+
+ unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
+
+ SDValue CopyToReg =
+ CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
+
+ SDValue NewCopyFromRegOp =
+ CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
+
+ Base = NewCopyFromRegOp;
+ } else {
+ Base = CopyFromRegOp;
+ }
+
+ if (ImmNode->getValueType(0) != MVT::i8) {
+ Disp = CurDAG->getTargetConstant(ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8);
+ } else {
+ Disp = ImmOp;
+ }
+
+ OutOps.push_back(Base);
+ OutOps.push_back(Disp);
+
+ return false;
+ }
+ }
+
+ // More generic case.
+ // Create chain that puts Op into pointer register
+ // and return that register.
+ unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
+
+ SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
+ SDValue CopyFromReg =
+ CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
+
+ OutOps.push_back(CopyFromReg);
+
+ return false;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
+ auto DL = CurDAG->getDataLayout();
+
+ // Convert the frameindex into a temp instruction that will hold the
+ // effective address of the final stack slot.
+ int FI = cast<FrameIndexSDNode>(N)->getIndex();
+ SDValue TFI =
+ CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
+
+ CurDAG->SelectNodeTo(N, AVR::FRMIDX,
+ getTargetLowering()->getPointerTy(DL), TFI,
+ CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
+ // Use the STD{W}SPQRr pseudo instruction when passing arguments through
+ // the stack on function calls for further expansion during the PEI phase.
+ const StoreSDNode *ST = cast<StoreSDNode>(N);
+ SDValue BasePtr = ST->getBasePtr();
+
+ // Early exit when the base pointer is a frame index node or a constant.
+ if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
+ BasePtr.isUndef()) {
+ return false;
+ }
+
+ const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
+ // Only stores where SP is the base pointer are valid.
+ if (!RN || (RN->getReg() != AVR::SP)) {
+ return false;
+ }
+
+ int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue();
+ SDValue Chain = ST->getChain();
+ EVT VT = ST->getValue().getValueType();
+ SDLoc DL(N);
+ SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
+ SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
+ unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
+
+ SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
+
+ // Transfer memory operands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = ST->getMemOperand();
+ cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
+ const LoadSDNode *LD = cast<LoadSDNode>(N);
+ if (!AVR::isProgramMemoryAccess(LD)) {
+ // Check if the opcode can be converted into an indexed load.
+ return selectIndexedLoad(N);
+ }
+
+ assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu");
+
+ // This is a flash memory load, move the pointer into R31R30 and emit
+ // the lpm instruction.
+ MVT VT = LD->getMemoryVT().getSimpleVT();
+ SDValue Chain = LD->getChain();
+ SDValue Ptr = LD->getBasePtr();
+ SDNode *ResNode;
+ SDLoc DL(N);
+
+ Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
+ Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
+ Chain.getValue(1));
+
+ SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16);
+
+ // Check if the opcode can be converted into an indexed load.
+ if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) {
+ // It is legal to fold the load into an indexed load.
+ ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr,
+ RegZ);
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ } else {
+ // Selecting an indexed load is not legal, fallback to a normal load.
+ switch (VT.SimpleTy) {
+ case MVT::i8:
+ ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other,
+ Ptr, RegZ);
+ break;
+ case MVT::i16:
+ ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16,
+ MVT::Other, Ptr, RegZ);
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ break;
+ default:
+ llvm_unreachable("Unsupported VT!");
+ }
+ }
+
+ // Transfer memory operands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = LD->getMemOperand();
+ cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
+ SDValue InFlag;
+ SDValue Chain = N->getOperand(0);
+ SDValue Callee = N->getOperand(1);
+ unsigned LastOpNum = N->getNumOperands() - 1;
+
+ // Direct calls are autogenerated.
+ unsigned Op = Callee.getOpcode();
+ if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
+ return false;
+ }
+
+ // Skip the incoming flag if present
+ if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
+ --LastOpNum;
+ }
+
+ SDLoc DL(N);
+ Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag);
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
+
+ // Map all operands into the new node.
+ for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
+ Ops.push_back(N->getOperand(i));
+ }
+
+ Ops.push_back(Chain);
+ Ops.push_back(Chain.getValue(1));
+
+ SDNode *ResNode =
+ CurDAG->getMachineNode(AVR::ICALL, DL, MVT::Other, MVT::Glue, Ops);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
+ SDValue Chain = N->getOperand(0);
+ SDValue JmpAddr = N->getOperand(1);
+
+ SDLoc DL(N);
+ // Move the destination address of the indirect branch into R31R30.
+ Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
+ SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
+ SDLoc DL(N);
+ MVT Type = N->getSimpleValueType(0);
+
+ assert(Type == MVT::i8 && "unexpected value type");
+
+ bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
+ unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
+
+ SDValue Lhs = N->getOperand(0);
+ SDValue Rhs = N->getOperand(1);
+ SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
+ SDValue InChain = CurDAG->getEntryNode();
+ SDValue InGlue = SDValue(Mul, 0);
+
+ // Copy the low half of the result, if it is needed.
+ if (N->hasAnyUseOfValue(0)) {
+ SDValue CopyFromLo =
+ CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
+
+ ReplaceUses(SDValue(N, 0), CopyFromLo);
+
+ InChain = CopyFromLo.getValue(1);
+ InGlue = CopyFromLo.getValue(2);
+ }
+
+ // Copy the high half of the result, if it is needed.
+ if (N->hasAnyUseOfValue(1)) {
+ SDValue CopyFromHi =
+ CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
+
+ ReplaceUses(SDValue(N, 1), CopyFromHi);
+
+ InChain = CopyFromHi.getValue(1);
+ InGlue = CopyFromHi.getValue(2);
+ }
+
+ CurDAG->RemoveDeadNode(N);
+
+ // We need to clear R1. This is currently done (dirtily)
+ // using a custom inserter.
+
+ return true;
+}
+
+void AVRDAGToDAGISel::Select(SDNode *N) {
+ // Dump information about the Node being selected
+ DEBUG(errs() << "Selecting: "; N->dump(CurDAG); errs() << "\n");
+
+ // If we have a custom node, we already have selected!
+ if (N->isMachineOpcode()) {
+ DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
+ N->setNodeId(-1);
+ return;
+ }
+
+ // See if subclasses can handle this node.
+ if (trySelect(N))
+ return;
+
+ // Select the default instruction
+ SelectCode(N);
+}
+
+bool AVRDAGToDAGISel::trySelect(SDNode *N) {
+ unsigned Opcode = N->getOpcode();
+ SDLoc DL(N);
+
+ switch (Opcode) {
+ // Nodes we fully handle.
+ case ISD::FrameIndex: return select<ISD::FrameIndex>(N);
+ case ISD::BRIND: return select<ISD::BRIND>(N);
+ case ISD::UMUL_LOHI:
+ case ISD::SMUL_LOHI: return selectMultiplication(N);
+
+ // Nodes we handle partially. Other cases are autogenerated
+ case ISD::STORE: return select<ISD::STORE>(N);
+ case ISD::LOAD: return select<ISD::LOAD>(N);
+ case AVRISD::CALL: return select<AVRISD::CALL>(N);
+ default: return false;
+ }
+}
+
+FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
+ CodeGenOpt::Level OptLevel) {
+ return new AVRDAGToDAGISel(TM, OptLevel);
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp b/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp
new file mode 100644
index 0000000..07fc3f6
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -0,0 +1,1978 @@
+//===-- AVRISelLowering.cpp - AVR DAG Lowering Implementation -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interfaces that AVR uses to lower LLVM code into a
+// selection DAG.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRISelLowering.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include "AVR.h"
+#include "AVRMachineFunctionInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+namespace llvm {
+
+AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm)
+ : TargetLowering(tm) {
+ // Set up the register classes.
+ addRegisterClass(MVT::i8, &AVR::GPR8RegClass);
+ addRegisterClass(MVT::i16, &AVR::DREGSRegClass);
+
+ // Compute derived properties from the register classes.
+ computeRegisterProperties(tm.getSubtargetImpl()->getRegisterInfo());
+
+ setBooleanContents(ZeroOrOneBooleanContent);
+ setBooleanVectorContents(ZeroOrOneBooleanContent);
+ setSchedulingPreference(Sched::RegPressure);
+ setStackPointerRegisterToSaveRestore(AVR::SP);
+
+ setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
+ setOperationAction(ISD::BlockAddress, MVT::i16, Custom);
+
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i8, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand);
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
+ setLoadExtAction(N, VT, MVT::i1, Promote);
+ setLoadExtAction(N, VT, MVT::i8, Expand);
+ }
+ }
+
+ setTruncStoreAction(MVT::i16, MVT::i8, Expand);
+
+ // sub (x, imm) gets canonicalized to add (x, -imm), so for illegal types
+ // revert into a sub since we don't have an add with immediate instruction.
+ setOperationAction(ISD::ADD, MVT::i32, Custom);
+ setOperationAction(ISD::ADD, MVT::i64, Custom);
+
+ // our shift instructions are only able to shift 1 bit at a time, so handle
+ // this in a custom way.
+ setOperationAction(ISD::SRA, MVT::i8, Custom);
+ setOperationAction(ISD::SHL, MVT::i8, Custom);
+ setOperationAction(ISD::SRL, MVT::i8, Custom);
+ setOperationAction(ISD::SRA, MVT::i16, Custom);
+ setOperationAction(ISD::SHL, MVT::i16, Custom);
+ setOperationAction(ISD::SRL, MVT::i16, Custom);
+ setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand);
+
+ setOperationAction(ISD::BR_CC, MVT::i8, Custom);
+ setOperationAction(ISD::BR_CC, MVT::i16, Custom);
+ setOperationAction(ISD::BR_CC, MVT::i32, Custom);
+ setOperationAction(ISD::BR_CC, MVT::i64, Custom);
+ setOperationAction(ISD::BRCOND, MVT::Other, Expand);
+
+ setOperationAction(ISD::SELECT_CC, MVT::i8, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i16, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
+ setOperationAction(ISD::SELECT_CC, MVT::i64, Expand);
+ setOperationAction(ISD::SETCC, MVT::i8, Custom);
+ setOperationAction(ISD::SETCC, MVT::i16, Custom);
+ setOperationAction(ISD::SETCC, MVT::i32, Custom);
+ setOperationAction(ISD::SETCC, MVT::i64, Custom);
+ setOperationAction(ISD::SELECT, MVT::i8, Expand);
+ setOperationAction(ISD::SELECT, MVT::i16, Expand);
+
+ setOperationAction(ISD::BSWAP, MVT::i16, Expand);
+
+ // Add support for postincrement and predecrement load/stores.
+ setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal);
+ setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal);
+ setIndexedLoadAction(ISD::PRE_DEC, MVT::i8, Legal);
+ setIndexedLoadAction(ISD::PRE_DEC, MVT::i16, Legal);
+ setIndexedStoreAction(ISD::POST_INC, MVT::i8, Legal);
+ setIndexedStoreAction(ISD::POST_INC, MVT::i16, Legal);
+ setIndexedStoreAction(ISD::PRE_DEC, MVT::i8, Legal);
+ setIndexedStoreAction(ISD::PRE_DEC, MVT::i16, Legal);
+
+ setOperationAction(ISD::BR_JT, MVT::Other, Expand);
+
+ setOperationAction(ISD::VASTART, MVT::Other, Custom);
+ setOperationAction(ISD::VAEND, MVT::Other, Expand);
+ setOperationAction(ISD::VAARG, MVT::Other, Expand);
+ setOperationAction(ISD::VACOPY, MVT::Other, Expand);
+
+ // Atomic operations which must be lowered to rtlib calls
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::ATOMIC_SWAP, VT, Expand);
+ setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand);
+ }
+
+ // Division/remainder
+ setOperationAction(ISD::UDIV, MVT::i8, Expand);
+ setOperationAction(ISD::UDIV, MVT::i16, Expand);
+ setOperationAction(ISD::UREM, MVT::i8, Expand);
+ setOperationAction(ISD::UREM, MVT::i16, Expand);
+ setOperationAction(ISD::SDIV, MVT::i8, Expand);
+ setOperationAction(ISD::SDIV, MVT::i16, Expand);
+ setOperationAction(ISD::SREM, MVT::i8, Expand);
+ setOperationAction(ISD::SREM, MVT::i16, Expand);
+
+ // Make division and modulus custom
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::UDIVREM, VT, Custom);
+ setOperationAction(ISD::SDIVREM, VT, Custom);
+ }
+
+ // Do not use MUL. The AVR instructions are closer to SMUL_LOHI &co.
+ setOperationAction(ISD::MUL, MVT::i8, Expand);
+ setOperationAction(ISD::MUL, MVT::i16, Expand);
+
+ // Expand 16 bit multiplications.
+ setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
+ setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::MULHS, VT, Expand);
+ setOperationAction(ISD::MULHU, VT, Expand);
+ }
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::CTPOP, VT, Expand);
+ setOperationAction(ISD::CTLZ, VT, Expand);
+ setOperationAction(ISD::CTTZ, VT, Expand);
+ }
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
+ // TODO: The generated code is pretty poor. Investigate using the
+ // same "shift and subtract with carry" trick that we do for
+ // extending 8-bit to 16-bit. This may require infrastructure
+ // improvements in how we treat 16-bit "registers" to be feasible.
+ }
+
+ // Division rtlib functions (not supported)
+ setLibcallName(RTLIB::SDIV_I8, nullptr);
+ setLibcallName(RTLIB::SDIV_I16, nullptr);
+ setLibcallName(RTLIB::SDIV_I32, nullptr);
+ setLibcallName(RTLIB::SDIV_I64, nullptr);
+ setLibcallName(RTLIB::SDIV_I128, nullptr);
+ setLibcallName(RTLIB::UDIV_I8, nullptr);
+ setLibcallName(RTLIB::UDIV_I16, nullptr);
+ setLibcallName(RTLIB::UDIV_I32, nullptr);
+ setLibcallName(RTLIB::UDIV_I64, nullptr);
+ setLibcallName(RTLIB::UDIV_I128, nullptr);
+
+ // Modulus rtlib functions (not supported)
+ setLibcallName(RTLIB::SREM_I8, nullptr);
+ setLibcallName(RTLIB::SREM_I16, nullptr);
+ setLibcallName(RTLIB::SREM_I32, nullptr);
+ setLibcallName(RTLIB::SREM_I64, nullptr);
+ setLibcallName(RTLIB::SREM_I128, nullptr);
+ setLibcallName(RTLIB::UREM_I8, nullptr);
+ setLibcallName(RTLIB::UREM_I16, nullptr);
+ setLibcallName(RTLIB::UREM_I32, nullptr);
+ setLibcallName(RTLIB::UREM_I64, nullptr);
+ setLibcallName(RTLIB::UREM_I128, nullptr);
+
+ // Division and modulus rtlib functions
+ setLibcallName(RTLIB::SDIVREM_I8, "__divmodqi4");
+ setLibcallName(RTLIB::SDIVREM_I16, "__divmodhi4");
+ setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4");
+ setLibcallName(RTLIB::SDIVREM_I64, "__divmoddi4");
+ setLibcallName(RTLIB::SDIVREM_I128, "__divmodti4");
+ setLibcallName(RTLIB::UDIVREM_I8, "__udivmodqi4");
+ setLibcallName(RTLIB::UDIVREM_I16, "__udivmodhi4");
+ setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4");
+ setLibcallName(RTLIB::UDIVREM_I64, "__udivmoddi4");
+ setLibcallName(RTLIB::UDIVREM_I128, "__udivmodti4");
+
+ // Several of the runtime library functions use a special calling conv
+ setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
+ setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
+ setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
+ setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);
+
+ // Trigonometric rtlib functions
+ setLibcallName(RTLIB::SIN_F32, "sin");
+ setLibcallName(RTLIB::COS_F32, "cos");
+
+ setMinFunctionAlignment(1);
+ setMinimumJumpTableEntries(INT_MAX);
+}
+
+const char *AVRTargetLowering::getTargetNodeName(unsigned Opcode) const {
+#define NODE(name) \
+ case AVRISD::name: \
+ return #name
+
+ switch (Opcode) {
+ default:
+ return nullptr;
+ NODE(RET_FLAG);
+ NODE(RETI_FLAG);
+ NODE(CALL);
+ NODE(WRAPPER);
+ NODE(LSL);
+ NODE(LSR);
+ NODE(ROL);
+ NODE(ROR);
+ NODE(ASR);
+ NODE(LSLLOOP);
+ NODE(LSRLOOP);
+ NODE(ASRLOOP);
+ NODE(BRCOND);
+ NODE(CMP);
+ NODE(CMPC);
+ NODE(TST);
+ NODE(SELECT_CC);
+#undef NODE
+ }
+}
+
+EVT AVRTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &,
+ EVT VT) const {
+ assert(!VT.isVector() && "No AVR SetCC type for vectors!");
+ return MVT::i8;
+}
+
+SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
+ //:TODO: this function has to be completely rewritten to produce optimal
+ // code, for now it's producing very long but correct code.
+ unsigned Opc8;
+ const SDNode *N = Op.getNode();
+ EVT VT = Op.getValueType();
+ SDLoc dl(N);
+
+ // Expand non-constant shifts to loops.
+ if (!isa<ConstantSDNode>(N->getOperand(1))) {
+ switch (Op.getOpcode()) {
+ default:
+ llvm_unreachable("Invalid shift opcode!");
+ case ISD::SHL:
+ return DAG.getNode(AVRISD::LSLLOOP, dl, VT, N->getOperand(0),
+ N->getOperand(1));
+ case ISD::SRL:
+ return DAG.getNode(AVRISD::LSRLOOP, dl, VT, N->getOperand(0),
+ N->getOperand(1));
+ case ISD::SRA:
+ return DAG.getNode(AVRISD::ASRLOOP, dl, VT, N->getOperand(0),
+ N->getOperand(1));
+ }
+ }
+
+ uint64_t ShiftAmount = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
+ SDValue Victim = N->getOperand(0);
+
+ switch (Op.getOpcode()) {
+ case ISD::SRA:
+ Opc8 = AVRISD::ASR;
+ break;
+ case ISD::ROTL:
+ Opc8 = AVRISD::ROL;
+ break;
+ case ISD::ROTR:
+ Opc8 = AVRISD::ROR;
+ break;
+ case ISD::SRL:
+ Opc8 = AVRISD::LSR;
+ break;
+ case ISD::SHL:
+ Opc8 = AVRISD::LSL;
+ break;
+ default:
+ llvm_unreachable("Invalid shift opcode");
+ }
+
+ while (ShiftAmount--) {
+ Victim = DAG.getNode(Opc8, dl, VT, Victim);
+ }
+
+ return Victim;
+}
+
+SDValue AVRTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
+ unsigned Opcode = Op->getOpcode();
+ assert((Opcode == ISD::SDIVREM || Opcode == ISD::UDIVREM) &&
+ "Invalid opcode for Div/Rem lowering");
+ bool isSigned = (Opcode == ISD::SDIVREM);
+ EVT VT = Op->getValueType(0);
+ Type *Ty = VT.getTypeForEVT(*DAG.getContext());
+
+ RTLIB::Libcall LC;
+ switch (VT.getSimpleVT().SimpleTy) {
+ default:
+ llvm_unreachable("Unexpected request for libcall!");
+ case MVT::i8:
+ LC = isSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8;
+ break;
+ case MVT::i16:
+ LC = isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16;
+ break;
+ case MVT::i32:
+ LC = isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
+ break;
+ case MVT::i64:
+ LC = isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64;
+ break;
+ }
+
+ SDValue InChain = DAG.getEntryNode();
+
+ TargetLowering::ArgListTy Args;
+ TargetLowering::ArgListEntry Entry;
+ for (SDValue const &Value : Op->op_values()) {
+ Entry.Node = Value;
+ Entry.Ty = Value.getValueType().getTypeForEVT(*DAG.getContext());
+ Entry.isSExt = isSigned;
+ Entry.isZExt = !isSigned;
+ Args.push_back(Entry);
+ }
+
+ SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC),
+ getPointerTy(DAG.getDataLayout()));
+
+ Type *RetTy = (Type *)StructType::get(Ty, Ty, nullptr);
+
+ SDLoc dl(Op);
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(dl)
+ .setChain(InChain)
+ .setCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args))
+ .setInRegister()
+ .setSExtResult(isSigned)
+ .setZExtResult(!isSigned);
+
+ std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
+ return CallInfo.first;
+}
+
+SDValue AVRTargetLowering::LowerGlobalAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+ auto DL = DAG.getDataLayout();
+
+ const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+ int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
+
+ // Create the TargetGlobalAddress node, folding in the constant offset.
+ SDValue Result =
+ DAG.getTargetGlobalAddress(GV, SDLoc(Op), getPointerTy(DL), Offset);
+ return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
+}
+
+SDValue AVRTargetLowering::LowerBlockAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+ auto DL = DAG.getDataLayout();
+ const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
+
+ SDValue Result = DAG.getTargetBlockAddress(BA, getPointerTy(DL));
+
+ return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
+}
+
+/// IntCCToAVRCC - Convert a DAG integer condition code to an AVR CC.
+static AVRCC::CondCodes intCCToAVRCC(ISD::CondCode CC) {
+ switch (CC) {
+ default:
+ llvm_unreachable("Unknown condition code!");
+ case ISD::SETEQ:
+ return AVRCC::COND_EQ;
+ case ISD::SETNE:
+ return AVRCC::COND_NE;
+ case ISD::SETGE:
+ return AVRCC::COND_GE;
+ case ISD::SETLT:
+ return AVRCC::COND_LT;
+ case ISD::SETUGE:
+ return AVRCC::COND_SH;
+ case ISD::SETULT:
+ return AVRCC::COND_LO;
+ }
+}
+
+/// Returns appropriate AVR CMP/CMPC nodes and corresponding condition code for
+/// the given operands.
+SDValue AVRTargetLowering::getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
+ SDValue &AVRcc, SelectionDAG &DAG,
+ SDLoc DL) const {
+ SDValue Cmp;
+ EVT VT = LHS.getValueType();
+ bool UseTest = false;
+
+ switch (CC) {
+ default:
+ break;
+ case ISD::SETLE: {
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETGE;
+ break;
+ }
+ case ISD::SETGT: {
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+ switch (C->getSExtValue()) {
+ case -1: {
+ // When doing lhs > -1 use a tst instruction on the top part of lhs
+ // and use brpl instead of using a chain of cp/cpc.
+ UseTest = true;
+ AVRcc = DAG.getConstant(AVRCC::COND_PL, DL, MVT::i8);
+ break;
+ }
+ case 0: {
+ // Turn lhs > 0 into 0 < lhs since 0 can be materialized with
+ // __zero_reg__ in lhs.
+ RHS = LHS;
+ LHS = DAG.getConstant(0, DL, VT);
+ CC = ISD::SETLT;
+ break;
+ }
+ default: {
+ // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows
+ // us to fold the constant into the cmp instruction.
+ RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
+ CC = ISD::SETGE;
+ break;
+ }
+ }
+ break;
+ }
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETLT;
+ break;
+ }
+ case ISD::SETLT: {
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+ switch (C->getSExtValue()) {
+ case 1: {
+ // Turn lhs < 1 into 0 >= lhs since 0 can be materialized with
+ // __zero_reg__ in lhs.
+ RHS = LHS;
+ LHS = DAG.getConstant(0, DL, VT);
+ CC = ISD::SETGE;
+ break;
+ }
+ case 0: {
+ // When doing lhs < 0 use a tst instruction on the top part of lhs
+ // and use brmi instead of using a chain of cp/cpc.
+ UseTest = true;
+ AVRcc = DAG.getConstant(AVRCC::COND_MI, DL, MVT::i8);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case ISD::SETULE: {
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETUGE;
+ break;
+ }
+ case ISD::SETUGT: {
+ // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to
+ // fold the constant into the cmp instruction.
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+ RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
+ CC = ISD::SETUGE;
+ break;
+ }
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETULT;
+ break;
+ }
+ }
+
+ // Expand 32 and 64 bit comparisons with custom CMP and CMPC nodes instead of
+ // using the default and/or/xor expansion code which is much longer.
+ if (VT == MVT::i32) {
+ SDValue LHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
+ DAG.getIntPtrConstant(1, DL));
+ SDValue RHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
+ DAG.getIntPtrConstant(1, DL));
+
+ if (UseTest) {
+ // When using tst we only care about the highest part.
+ SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHShi,
+ DAG.getIntPtrConstant(1, DL));
+ Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
+ } else {
+ Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHSlo, RHSlo);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHShi, RHShi, Cmp);
+ }
+ } else if (VT == MVT::i64) {
+ SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
+ DAG.getIntPtrConstant(1, DL));
+
+ SDValue LHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
+ DAG.getIntPtrConstant(1, DL));
+ SDValue LHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
+ DAG.getIntPtrConstant(1, DL));
+
+ SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
+ DAG.getIntPtrConstant(1, DL));
+
+ SDValue RHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
+ DAG.getIntPtrConstant(1, DL));
+ SDValue RHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
+ DAG.getIntPtrConstant(1, DL));
+
+ if (UseTest) {
+ // When using tst we only care about the highest part.
+ SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS3,
+ DAG.getIntPtrConstant(1, DL));
+ Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
+ } else {
+ Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS0, RHS0);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS1, RHS1, Cmp);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS2, RHS2, Cmp);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS3, RHS3, Cmp);
+ }
+ } else if (VT == MVT::i8 || VT == MVT::i16) {
+ if (UseTest) {
+ // When using tst we only care about the highest part.
+ Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue,
+ (VT == MVT::i8)
+ ? LHS
+ : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8,
+ LHS, DAG.getIntPtrConstant(1, DL)));
+ } else {
+ Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS, RHS);
+ }
+ } else {
+ llvm_unreachable("Invalid comparison size");
+ }
+
+ // When using a test instruction AVRcc is already set.
+ if (!UseTest) {
+ AVRcc = DAG.getConstant(intCCToAVRCC(CC), DL, MVT::i8);
+ }
+
+ return Cmp;
+}
+
+SDValue AVRTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue Chain = Op.getOperand(0);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
+ SDValue LHS = Op.getOperand(2);
+ SDValue RHS = Op.getOperand(3);
+ SDValue Dest = Op.getOperand(4);
+ SDLoc dl(Op);
+
+ SDValue TargetCC;
+ SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
+
+ return DAG.getNode(AVRISD::BRCOND, dl, MVT::Other, Chain, Dest, TargetCC,
+ Cmp);
+}
+
+SDValue AVRTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ SDValue TrueV = Op.getOperand(2);
+ SDValue FalseV = Op.getOperand(3);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
+ SDLoc dl(Op);
+
+ SDValue TargetCC;
+ SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
+
+ SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
+ SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
+
+ return DAG.getNode(AVRISD::SELECT_CC, dl, VTs, Ops);
+}
+
+SDValue AVRTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
+ SDLoc DL(Op);
+
+ SDValue TargetCC;
+ SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, DL);
+
+ SDValue TrueV = DAG.getConstant(1, DL, Op.getValueType());
+ SDValue FalseV = DAG.getConstant(0, DL, Op.getValueType());
+ SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
+ SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
+
+ return DAG.getNode(AVRISD::SELECT_CC, DL, VTs, Ops);
+}
+
+SDValue AVRTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
+ const MachineFunction &MF = DAG.getMachineFunction();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
+ auto DL = DAG.getDataLayout();
+ SDLoc dl(Op);
+
+ // Vastart just stores the address of the VarArgsFrameIndex slot into the
+ // memory location argument.
+ SDValue FI = DAG.getFrameIndex(AFI->getVarArgsFrameIndex(), getPointerTy(DL));
+
+ return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1),
+ MachinePointerInfo(SV), 0);
+}
+
+SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
+ switch (Op.getOpcode()) {
+ default:
+ llvm_unreachable("Don't know how to custom lower this!");
+ case ISD::SHL:
+ case ISD::SRA:
+ case ISD::SRL:
+ case ISD::ROTL:
+ case ISD::ROTR:
+ return LowerShifts(Op, DAG);
+ case ISD::GlobalAddress:
+ return LowerGlobalAddress(Op, DAG);
+ case ISD::BlockAddress:
+ return LowerBlockAddress(Op, DAG);
+ case ISD::BR_CC:
+ return LowerBR_CC(Op, DAG);
+ case ISD::SELECT_CC:
+ return LowerSELECT_CC(Op, DAG);
+ case ISD::SETCC:
+ return LowerSETCC(Op, DAG);
+ case ISD::VASTART:
+ return LowerVASTART(Op, DAG);
+ case ISD::SDIVREM:
+ case ISD::UDIVREM:
+ return LowerDivRem(Op, DAG);
+ }
+
+ return SDValue();
+}
+
+/// Replace a node with an illegal result type
+/// with a new node built out of custom code.
+void AVRTargetLowering::ReplaceNodeResults(SDNode *N,
+ SmallVectorImpl<SDValue> &Results,
+ SelectionDAG &DAG) const {
+ SDLoc DL(N);
+
+ switch (N->getOpcode()) {
+ case ISD::ADD: {
+ // Convert add (x, imm) into sub (x, -imm).
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
+ SDValue Sub = DAG.getNode(
+ ISD::SUB, DL, N->getValueType(0), N->getOperand(0),
+ DAG.getConstant(-C->getAPIntValue(), DL, C->getValueType(0)));
+ Results.push_back(Sub);
+ }
+ break;
+ }
+ default: {
+ SDValue Res = LowerOperation(SDValue(N, 0), DAG);
+
+ for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I)
+ Results.push_back(Res.getValue(I));
+
+ break;
+ }
+ }
+}
+
+/// Return true if the addressing mode represented
+/// by AM is legal for this target, for a load/store of the specified type.
+bool AVRTargetLowering::isLegalAddressingMode(const DataLayout &DL,
+ const AddrMode &AM, Type *Ty,
+ unsigned AS) const {
+ int64_t Offs = AM.BaseOffs;
+
+ // Allow absolute addresses.
+ if (AM.BaseGV && !AM.HasBaseReg && AM.Scale == 0 && Offs == 0) {
+ return true;
+ }
+
+ // Flash memory instructions only allow zero offsets.
+ if (isa<PointerType>(Ty) && AS == AVR::ProgramMemory) {
+ return false;
+ }
+
+ // Allow reg+<6bit> offset.
+ if (Offs < 0)
+ Offs = -Offs;
+ if (AM.BaseGV == 0 && AM.HasBaseReg && AM.Scale == 0 && isUInt<6>(Offs)) {
+ return true;
+ }
+
+ return false;
+}
+
+/// Returns true by value, base pointer and
+/// offset pointer and addressing mode by reference if the node's address
+/// can be legally represented as pre-indexed load / store address.
+bool AVRTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
+ SDValue &Offset,
+ ISD::MemIndexedMode &AM,
+ SelectionDAG &DAG) const {
+ EVT VT;
+ const SDNode *Op;
+ SDLoc DL(N);
+
+ if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ VT = LD->getMemoryVT();
+ Op = LD->getBasePtr().getNode();
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD)
+ return false;
+ if (AVR::isProgramMemoryAccess(LD)) {
+ return false;
+ }
+ } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ VT = ST->getMemoryVT();
+ Op = ST->getBasePtr().getNode();
+ if (AVR::isProgramMemoryAccess(ST)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ if (VT != MVT::i8 && VT != MVT::i16) {
+ return false;
+ }
+
+ if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
+ return false;
+ }
+
+ if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
+ int RHSC = RHS->getSExtValue();
+ if (Op->getOpcode() == ISD::SUB)
+ RHSC = -RHSC;
+
+ if ((VT == MVT::i16 && RHSC != -2) || (VT == MVT::i8 && RHSC != -1)) {
+ return false;
+ }
+
+ Base = Op->getOperand(0);
+ Offset = DAG.getConstant(RHSC, DL, MVT::i8);
+ AM = ISD::PRE_DEC;
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Returns true by value, base pointer and
+/// offset pointer and addressing mode by reference if this node can be
+/// combined with a load / store to form a post-indexed load / store.
+bool AVRTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
+ SDValue &Base,
+ SDValue &Offset,
+ ISD::MemIndexedMode &AM,
+ SelectionDAG &DAG) const {
+ EVT VT;
+ SDLoc DL(N);
+
+ if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ VT = LD->getMemoryVT();
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD)
+ return false;
+ } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ VT = ST->getMemoryVT();
+ if (AVR::isProgramMemoryAccess(ST)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ if (VT != MVT::i8 && VT != MVT::i16) {
+ return false;
+ }
+
+ if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
+ return false;
+ }
+
+ if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
+ int RHSC = RHS->getSExtValue();
+ if (Op->getOpcode() == ISD::SUB)
+ RHSC = -RHSC;
+ if ((VT == MVT::i16 && RHSC != 2) || (VT == MVT::i8 && RHSC != 1)) {
+ return false;
+ }
+
+ Base = Op->getOperand(0);
+ Offset = DAG.getConstant(RHSC, DL, MVT::i8);
+ AM = ISD::POST_INC;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool AVRTargetLowering::isOffsetFoldingLegal(
+ const GlobalAddressSDNode *GA) const {
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Formal Arguments Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+#include "AVRGenCallingConv.inc"
+
+/// For each argument in a function store the number of pieces it is composed
+/// of.
+static void parseFunctionArgs(const Function *F, const DataLayout *TD,
+ SmallVectorImpl<unsigned> &Out) {
+ for (Argument const &Arg : F->args()) {
+ unsigned Bytes = (TD->getTypeSizeInBits(Arg.getType()) + 7) / 8;
+ Out.push_back((Bytes + 1) / 2);
+ }
+}
+
+/// For external symbols there is no function prototype information so we
+/// have to rely directly on argument sizes.
+static void parseExternFuncCallArgs(const SmallVectorImpl<ISD::OutputArg> &In,
+ SmallVectorImpl<unsigned> &Out) {
+ for (unsigned i = 0, e = In.size(); i != e;) {
+ unsigned Size = 0;
+ unsigned Offset = 0;
+ while ((i != e) && (In[i].PartOffset == Offset)) {
+ Offset += In[i].VT.getStoreSize();
+ ++i;
+ ++Size;
+ }
+ Out.push_back(Size);
+ }
+}
+
+static StringRef getFunctionName(TargetLowering::CallLoweringInfo &CLI) {
+ SDValue Callee = CLI.Callee;
+
+ if (const ExternalSymbolSDNode *G = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ return G->getSymbol();
+ }
+
+ if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ return G->getGlobal()->getName();
+ }
+
+ llvm_unreachable("don't know how to get the name for this callee");
+}
+
+/// Analyze incoming and outgoing function arguments. We need custom C++ code
+/// to handle special constraints in the ABI like reversing the order of the
+/// pieces of splitted arguments. In addition, all pieces of a certain argument
+/// have to be passed either using registers or the stack but never mixing both.
+static void analyzeStandardArguments(TargetLowering::CallLoweringInfo *CLI,
+ const Function *F, const DataLayout *TD,
+ const SmallVectorImpl<ISD::OutputArg> *Outs,
+ const SmallVectorImpl<ISD::InputArg> *Ins,
+ CallingConv::ID CallConv,
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ CCState &CCInfo, bool IsCall, bool IsVarArg) {
+ static const MCPhysReg RegList8[] = {AVR::R24, AVR::R22, AVR::R20,
+ AVR::R18, AVR::R16, AVR::R14,
+ AVR::R12, AVR::R10, AVR::R8};
+ static const MCPhysReg RegList16[] = {AVR::R25R24, AVR::R23R22, AVR::R21R20,
+ AVR::R19R18, AVR::R17R16, AVR::R15R14,
+ AVR::R13R12, AVR::R11R10, AVR::R9R8};
+ if (IsVarArg) {
+ // Variadic functions do not need all the analisys below.
+ if (IsCall) {
+ CCInfo.AnalyzeCallOperands(*Outs, ArgCC_AVR_Vararg);
+ } else {
+ CCInfo.AnalyzeFormalArguments(*Ins, ArgCC_AVR_Vararg);
+ }
+ return;
+ }
+
+ // Fill in the Args array which will contain original argument sizes.
+ SmallVector<unsigned, 8> Args;
+ if (IsCall) {
+ parseExternFuncCallArgs(*Outs, Args);
+ } else {
+ assert(F != nullptr && "function should not be null");
+ parseFunctionArgs(F, TD, Args);
+ }
+
+ unsigned RegsLeft = array_lengthof(RegList8), ValNo = 0;
+ // Variadic functions always use the stack.
+ bool UsesStack = false;
+ for (unsigned i = 0, pos = 0, e = Args.size(); i != e; ++i) {
+ unsigned Size = Args[i];
+ MVT LocVT = (IsCall) ? (*Outs)[pos].VT : (*Ins)[pos].VT;
+
+ // If we have plenty of regs to pass the whole argument do it.
+ if (!UsesStack && (Size <= RegsLeft)) {
+ const MCPhysReg *RegList = (LocVT == MVT::i16) ? RegList16 : RegList8;
+
+ for (unsigned j = 0; j != Size; ++j) {
+ unsigned Reg = CCInfo.AllocateReg(
+ ArrayRef<MCPhysReg>(RegList, array_lengthof(RegList8)));
+ CCInfo.addLoc(
+ CCValAssign::getReg(ValNo++, LocVT, Reg, LocVT, CCValAssign::Full));
+ --RegsLeft;
+ }
+
+ // Reverse the order of the pieces to agree with the "big endian" format
+ // required in the calling convention ABI.
+ std::reverse(ArgLocs.begin() + pos, ArgLocs.begin() + pos + Size);
+ } else {
+ // Pass the rest of arguments using the stack.
+ UsesStack = true;
+ for (unsigned j = 0; j != Size; ++j) {
+ unsigned Offset = CCInfo.AllocateStack(
+ TD->getTypeAllocSize(EVT(LocVT).getTypeForEVT(CCInfo.getContext())),
+ TD->getABITypeAlignment(
+ EVT(LocVT).getTypeForEVT(CCInfo.getContext())));
+ CCInfo.addLoc(CCValAssign::getMem(ValNo++, LocVT, Offset, LocVT,
+ CCValAssign::Full));
+ }
+ }
+ pos += Size;
+ }
+}
+
+static void analyzeBuiltinArguments(TargetLowering::CallLoweringInfo &CLI,
+ const Function *F, const DataLayout *TD,
+ const SmallVectorImpl<ISD::OutputArg> *Outs,
+ const SmallVectorImpl<ISD::InputArg> *Ins,
+ CallingConv::ID CallConv,
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ CCState &CCInfo, bool IsCall, bool IsVarArg) {
+ StringRef FuncName = getFunctionName(CLI);
+
+ if (FuncName.startswith("__udivmod") || FuncName.startswith("__divmod")) {
+ CCInfo.AnalyzeCallOperands(*Outs, ArgCC_AVR_BUILTIN_DIV);
+ } else {
+ analyzeStandardArguments(&CLI, F, TD, Outs, Ins,
+ CallConv, ArgLocs, CCInfo,
+ IsCall, IsVarArg);
+ }
+}
+
+static void analyzeArguments(TargetLowering::CallLoweringInfo *CLI,
+ const Function *F, const DataLayout *TD,
+ const SmallVectorImpl<ISD::OutputArg> *Outs,
+ const SmallVectorImpl<ISD::InputArg> *Ins,
+ CallingConv::ID CallConv,
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ CCState &CCInfo, bool IsCall, bool IsVarArg) {
+ switch (CallConv) {
+ case CallingConv::AVR_BUILTIN: {
+ analyzeBuiltinArguments(*CLI, F, TD, Outs, Ins,
+ CallConv, ArgLocs, CCInfo,
+ IsCall, IsVarArg);
+ return;
+ }
+ default: {
+ analyzeStandardArguments(CLI, F, TD, Outs, Ins,
+ CallConv, ArgLocs, CCInfo,
+ IsCall, IsVarArg);
+ return;
+ }
+ }
+}
+
+SDValue AVRTargetLowering::LowerFormalArguments(
+ SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ auto DL = DAG.getDataLayout();
+
+ // Assign locations to all of the incoming arguments.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+
+ analyzeArguments(nullptr, MF.getFunction(), &DL, 0, &Ins, CallConv, ArgLocs, CCInfo,
+ false, isVarArg);
+
+ SDValue ArgValue;
+ for (CCValAssign &VA : ArgLocs) {
+
+ // Arguments stored on registers.
+ if (VA.isRegLoc()) {
+ EVT RegVT = VA.getLocVT();
+ const TargetRegisterClass *RC;
+ if (RegVT == MVT::i8) {
+ RC = &AVR::GPR8RegClass;
+ } else if (RegVT == MVT::i16) {
+ RC = &AVR::DREGSRegClass;
+ } else {
+ llvm_unreachable("Unknown argument type!");
+ }
+
+ unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC);
+ ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
+
+ // :NOTE: Clang should not promote any i8 into i16 but for safety the
+ // following code will handle zexts or sexts generated by other
+ // front ends. Otherwise:
+ // If this is an 8 bit value, it is really passed promoted
+ // to 16 bits. Insert an assert[sz]ext to capture this, then
+ // truncate to the right size.
+ switch (VA.getLocInfo()) {
+ default:
+ llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full:
+ break;
+ case CCValAssign::BCvt:
+ ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue);
+ break;
+ case CCValAssign::SExt:
+ ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
+ break;
+ case CCValAssign::ZExt:
+ ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
+ break;
+ }
+
+ InVals.push_back(ArgValue);
+ } else {
+ // Sanity check.
+ assert(VA.isMemLoc());
+
+ EVT LocVT = VA.getLocVT();
+
+ // Create the frame index object for this incoming parameter.
+ int FI = MFI.CreateFixedObject(LocVT.getSizeInBits() / 8,
+ VA.getLocMemOffset(), true);
+
+ // Create the SelectionDAG nodes corresponding to a load
+ // from this parameter.
+ SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DL));
+ InVals.push_back(DAG.getLoad(LocVT, dl, Chain, FIN,
+ MachinePointerInfo::getFixedStack(MF, FI),
+ 0));
+ }
+ }
+
+ // If the function takes variable number of arguments, make a frame index for
+ // the start of the first vararg value... for expansion of llvm.va_start.
+ if (isVarArg) {
+ unsigned StackSize = CCInfo.getNextStackOffset();
+ AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ AFI->setVarArgsFrameIndex(MFI.CreateFixedObject(2, StackSize, true));
+ }
+
+ return Chain;
+}
+
+//===----------------------------------------------------------------------===//
+// Call Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc &DL = CLI.DL;
+ SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
+ SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+ SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
+ SDValue Chain = CLI.Chain;
+ SDValue Callee = CLI.Callee;
+ bool &isTailCall = CLI.IsTailCall;
+ CallingConv::ID CallConv = CLI.CallConv;
+ bool isVarArg = CLI.IsVarArg;
+
+ MachineFunction &MF = DAG.getMachineFunction();
+
+ // AVR does not yet support tail call optimization.
+ isTailCall = false;
+
+ // Analyze operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+
+ // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
+ // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
+ // node so that legalize doesn't hack it.
+ const Function *F = nullptr;
+ if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ const GlobalValue *GV = G->getGlobal();
+
+ F = cast<Function>(GV);
+ Callee =
+ DAG.getTargetGlobalAddress(GV, DL, getPointerTy(DAG.getDataLayout()));
+ } else if (const ExternalSymbolSDNode *ES =
+ dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ Callee = DAG.getTargetExternalSymbol(ES->getSymbol(),
+ getPointerTy(DAG.getDataLayout()));
+ }
+
+ analyzeArguments(&CLI, F, &DAG.getDataLayout(), &Outs, 0, CallConv, ArgLocs, CCInfo,
+ true, isVarArg);
+
+ // Get a count of how many bytes are to be pushed on the stack.
+ unsigned NumBytes = CCInfo.getNextStackOffset();
+
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, DL, true),
+ DL);
+
+ SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
+
+ // First, walk the register assignments, inserting copies.
+ unsigned AI, AE;
+ bool HasStackArgs = false;
+ for (AI = 0, AE = ArgLocs.size(); AI != AE; ++AI) {
+ CCValAssign &VA = ArgLocs[AI];
+ EVT RegVT = VA.getLocVT();
+ SDValue Arg = OutVals[AI];
+
+ // Promote the value if needed. With Clang this should not happen.
+ switch (VA.getLocInfo()) {
+ default:
+ llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full:
+ break;
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, RegVT, Arg);
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, RegVT, Arg);
+ break;
+ case CCValAssign::AExt:
+ Arg = DAG.getNode(ISD::ANY_EXTEND, DL, RegVT, Arg);
+ break;
+ case CCValAssign::BCvt:
+ Arg = DAG.getNode(ISD::BITCAST, DL, RegVT, Arg);
+ break;
+ }
+
+ // Stop when we encounter a stack argument, we need to process them
+ // in reverse order in the loop below.
+ if (VA.isMemLoc()) {
+ HasStackArgs = true;
+ break;
+ }
+
+ // Arguments that can be passed on registers must be kept in the RegsToPass
+ // vector.
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ }
+
+ // Second, stack arguments have to walked in reverse order by inserting
+ // chained stores, this ensures their order is not changed by the scheduler
+ // and that the push instruction sequence generated is correct, otherwise they
+ // can be freely intermixed.
+ if (HasStackArgs) {
+ for (AE = AI, AI = ArgLocs.size(); AI != AE; --AI) {
+ unsigned Loc = AI - 1;
+ CCValAssign &VA = ArgLocs[Loc];
+ SDValue Arg = OutVals[Loc];
+
+ assert(VA.isMemLoc());
+
+ // SP points to one stack slot further so add one to adjust it.
+ SDValue PtrOff = DAG.getNode(
+ ISD::ADD, DL, getPointerTy(DAG.getDataLayout()),
+ DAG.getRegister(AVR::SP, getPointerTy(DAG.getDataLayout())),
+ DAG.getIntPtrConstant(VA.getLocMemOffset() + 1, DL));
+
+ Chain =
+ DAG.getStore(Chain, DL, Arg, PtrOff,
+ MachinePointerInfo::getStack(MF, VA.getLocMemOffset()),
+ 0);
+ }
+ }
+
+ // Build a sequence of copy-to-reg nodes chained together with token chain and
+ // flag operands which copy the outgoing args into registers. The InFlag in
+ // necessary since all emited instructions must be stuck together.
+ SDValue InFlag;
+ for (auto Reg : RegsToPass) {
+ Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, InFlag);
+ InFlag = Chain.getValue(1);
+ }
+
+ // Returns a chain & a flag for retval copy to use.
+ SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+
+ // Add argument registers to the end of the list so that they are known live
+ // into the call.
+ for (auto Reg : RegsToPass) {
+ Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
+ }
+
+ // Add a register mask operand representing the call-preserved registers.
+ const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
+ const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo();
+ const uint32_t *Mask =
+ TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
+ assert(Mask && "Missing call preserved mask for calling convention");
+ Ops.push_back(DAG.getRegisterMask(Mask));
+
+ if (InFlag.getNode()) {
+ Ops.push_back(InFlag);
+ }
+
+ Chain = DAG.getNode(AVRISD::CALL, DL, NodeTys, Ops);
+ InFlag = Chain.getValue(1);
+
+ // Create the CALLSEQ_END node.
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, DL, true),
+ DAG.getIntPtrConstant(0, DL, true), InFlag, DL);
+
+ if (!Ins.empty()) {
+ InFlag = Chain.getValue(1);
+ }
+
+ // Handle result values, copying them out of physregs into vregs that we
+ // return.
+ return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, DL, DAG,
+ InVals);
+}
+
+/// Lower the result values of a call into the
+/// appropriate copies out of appropriate physical registers.
+///
+SDValue AVRTargetLowering::LowerCallResult(
+ SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Handle runtime calling convs.
+ auto CCFunction = CCAssignFnForReturn(CallConv);
+ CCInfo.AnalyzeCallResult(Ins, CCFunction);
+
+ if (CallConv != CallingConv::AVR_BUILTIN && RVLocs.size() > 1) {
+ // Reverse splitted return values to get the "big endian" format required
+ // to agree with the calling convention ABI.
+ std::reverse(RVLocs.begin(), RVLocs.end());
+ }
+
+ // Copy all of the result registers out of their specified physreg.
+ for (CCValAssign const &RVLoc : RVLocs) {
+ Chain = DAG.getCopyFromReg(Chain, dl, RVLoc.getLocReg(), RVLoc.getValVT(),
+ InFlag)
+ .getValue(1);
+ InFlag = Chain.getValue(2);
+ InVals.push_back(Chain.getValue(0));
+ }
+
+ return Chain;
+}
+
+//===----------------------------------------------------------------------===//
+// Return Value Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+CCAssignFn *AVRTargetLowering::CCAssignFnForReturn(CallingConv::ID CC) const {
+ switch (CC) {
+ case CallingConv::AVR_BUILTIN:
+ return RetCC_AVR_BUILTIN;
+ default:
+ return RetCC_AVR;
+ }
+}
+
+bool
+AVRTargetLowering::CanLowerReturn(CallingConv::ID CallConv,
+ MachineFunction &MF, bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ LLVMContext &Context) const
+{
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
+
+ auto CCFunction = CCAssignFnForReturn(CallConv);
+ return CCInfo.CheckReturn(Outs, CCFunction);
+}
+
+SDValue
+AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ const SDLoc &dl, SelectionDAG &DAG) const {
+ // CCValAssign - represent the assignment of the return value to locations.
+ SmallVector<CCValAssign, 16> RVLocs;
+
+ // CCState - Info about the registers and stack slot.
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Analyze return values.
+ auto CCFunction = CCAssignFnForReturn(CallConv);
+ CCInfo.AnalyzeReturn(Outs, CCFunction);
+
+ // If this is the first return lowered for this function, add the regs to
+ // the liveout set for the function.
+ MachineFunction &MF = DAG.getMachineFunction();
+ unsigned e = RVLocs.size();
+
+ // Reverse splitted return values to get the "big endian" format required
+ // to agree with the calling convention ABI.
+ if (e > 1) {
+ std::reverse(RVLocs.begin(), RVLocs.end());
+ }
+
+ SDValue Flag;
+ SmallVector<SDValue, 4> RetOps(1, Chain);
+ // Copy the result values into the output registers.
+ for (unsigned i = 0; i != e; ++i) {
+ CCValAssign &VA = RVLocs[i];
+ assert(VA.isRegLoc() && "Can only return in registers!");
+
+ Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag);
+
+ // Guarantee that all emitted copies are stuck together with flags.
+ Flag = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
+ }
+
+ // Don't emit the ret/reti instruction when the naked attribute is present in
+ // the function being compiled.
+ if (MF.getFunction()->getAttributes().hasAttribute(
+ AttributeSet::FunctionIndex, Attribute::Naked)) {
+ return Chain;
+ }
+
+ unsigned RetOpc =
+ (CallConv == CallingConv::AVR_INTR || CallConv == CallingConv::AVR_SIGNAL)
+ ? AVRISD::RETI_FLAG
+ : AVRISD::RET_FLAG;
+
+ RetOps[0] = Chain; // Update chain.
+
+ if (Flag.getNode()) {
+ RetOps.push_back(Flag);
+ }
+
+ return DAG.getNode(RetOpc, dl, MVT::Other, RetOps);
+}
+
+//===----------------------------------------------------------------------===//
+// Custom Inserters
+//===----------------------------------------------------------------------===//
+
+MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+ unsigned Opc;
+ const TargetRegisterClass *RC;
+ MachineFunction *F = BB->getParent();
+ MachineRegisterInfo &RI = F->getRegInfo();
+ const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
+ const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
+ DebugLoc dl = MI.getDebugLoc();
+
+ switch (MI.getOpcode()) {
+ default:
+ llvm_unreachable("Invalid shift opcode!");
+ case AVR::Lsl8:
+ Opc = AVR::LSLRd;
+ RC = &AVR::GPR8RegClass;
+ break;
+ case AVR::Lsl16:
+ Opc = AVR::LSLWRd;
+ RC = &AVR::DREGSRegClass;
+ break;
+ case AVR::Asr8:
+ Opc = AVR::ASRRd;
+ RC = &AVR::GPR8RegClass;
+ break;
+ case AVR::Asr16:
+ Opc = AVR::ASRWRd;
+ RC = &AVR::DREGSRegClass;
+ break;
+ case AVR::Lsr8:
+ Opc = AVR::LSRRd;
+ RC = &AVR::GPR8RegClass;
+ break;
+ case AVR::Lsr16:
+ Opc = AVR::LSRWRd;
+ RC = &AVR::DREGSRegClass;
+ break;
+ }
+
+ const BasicBlock *LLVM_BB = BB->getBasicBlock();
+ MachineFunction::iterator I = BB->getParent()->begin();
+ ++I;
+
+ // Create loop block.
+ MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB);
+
+ F->insert(I, LoopBB);
+ F->insert(I, RemBB);
+
+ // Update machine-CFG edges by transferring all successors of the current
+ // block to the block containing instructions after shift.
+ RemBB->splice(RemBB->begin(), BB, std::next(MachineBasicBlock::iterator(MI)),
+ BB->end());
+ RemBB->transferSuccessorsAndUpdatePHIs(BB);
+
+ // Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB.
+ BB->addSuccessor(LoopBB);
+ BB->addSuccessor(RemBB);
+ LoopBB->addSuccessor(RemBB);
+ LoopBB->addSuccessor(LoopBB);
+
+ unsigned ShiftAmtReg = RI.createVirtualRegister(&AVR::LD8RegClass);
+ unsigned ShiftAmtReg2 = RI.createVirtualRegister(&AVR::LD8RegClass);
+ unsigned ShiftReg = RI.createVirtualRegister(RC);
+ unsigned ShiftReg2 = RI.createVirtualRegister(RC);
+ unsigned ShiftAmtSrcReg = MI.getOperand(2).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned DstReg = MI.getOperand(0).getReg();
+
+ // BB:
+ // cp 0, N
+ // breq RemBB
+ BuildMI(BB, dl, TII.get(AVR::CPRdRr)).addReg(ShiftAmtSrcReg).addReg(AVR::R0);
+ BuildMI(BB, dl, TII.get(AVR::BREQk)).addMBB(RemBB);
+
+ // LoopBB:
+ // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
+ // ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB]
+ // ShiftReg2 = shift ShiftReg
+ // ShiftAmt2 = ShiftAmt - 1;
+ BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftReg)
+ .addReg(SrcReg)
+ .addMBB(BB)
+ .addReg(ShiftReg2)
+ .addMBB(LoopBB);
+ BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftAmtReg)
+ .addReg(ShiftAmtSrcReg)
+ .addMBB(BB)
+ .addReg(ShiftAmtReg2)
+ .addMBB(LoopBB);
+ BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
+ BuildMI(LoopBB, dl, TII.get(AVR::SUBIRdK), ShiftAmtReg2)
+ .addReg(ShiftAmtReg)
+ .addImm(1);
+ BuildMI(LoopBB, dl, TII.get(AVR::BRNEk)).addMBB(LoopBB);
+
+ // RemBB:
+ // DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB]
+ BuildMI(*RemBB, RemBB->begin(), dl, TII.get(AVR::PHI), DstReg)
+ .addReg(SrcReg)
+ .addMBB(BB)
+ .addReg(ShiftReg2)
+ .addMBB(LoopBB);
+
+ MI.eraseFromParent(); // The pseudo instruction is gone now.
+ return RemBB;
+}
+
+static bool isCopyMulResult(MachineBasicBlock::iterator const &I) {
+ if (I->getOpcode() == AVR::COPY) {
+ unsigned SrcReg = I->getOperand(1).getReg();
+ return (SrcReg == AVR::R0 || SrcReg == AVR::R1);
+ }
+
+ return false;
+}
+
+// The mul instructions wreak havock on our zero_reg R1. We need to clear it
+// after the result has been evacuated. This is probably not the best way to do
+// it, but it works for now.
+MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+ const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
+ const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
+ MachineBasicBlock::iterator I(MI);
+ ++I; // in any case insert *after* the mul instruction
+ if (isCopyMulResult(I))
+ ++I;
+ if (isCopyMulResult(I))
+ ++I;
+ BuildMI(*BB, I, MI.getDebugLoc(), TII.get(AVR::EORRdRr), AVR::R1)
+ .addReg(AVR::R1)
+ .addReg(AVR::R1);
+ return BB;
+}
+
+MachineBasicBlock *
+AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ int Opc = MI.getOpcode();
+
+ // Pseudo shift instructions with a non constant shift amount are expanded
+ // into a loop.
+ switch (Opc) {
+ case AVR::Lsl8:
+ case AVR::Lsl16:
+ case AVR::Lsr8:
+ case AVR::Lsr16:
+ case AVR::Asr8:
+ case AVR::Asr16:
+ return insertShift(MI, MBB);
+ case AVR::MULRdRr:
+ case AVR::MULSRdRr:
+ return insertMul(MI, MBB);
+ }
+
+ assert((Opc == AVR::Select16 || Opc == AVR::Select8) &&
+ "Unexpected instr type to insert");
+
+ const AVRInstrInfo &TII = (const AVRInstrInfo &)*MI.getParent()
+ ->getParent()
+ ->getSubtarget()
+ .getInstrInfo();
+ DebugLoc dl = MI.getDebugLoc();
+
+ // To "insert" a SELECT instruction, we insert the diamond
+ // control-flow pattern. The incoming instruction knows the
+ // destination vreg to set, the condition code register to branch
+ // on, the true/false values to select between, and a branch opcode
+ // to use.
+
+ MachineFunction *MF = MBB->getParent();
+ const BasicBlock *LLVM_BB = MBB->getBasicBlock();
+ MachineBasicBlock *trueMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *falseMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+
+ MachineFunction::iterator I = MBB->getParent()->begin();
+ ++I;
+ MF->insert(I, trueMBB);
+ MF->insert(I, falseMBB);
+
+ // Transfer remaining instructions and all successors of the current
+ // block to the block which will contain the Phi node for the
+ // select.
+ trueMBB->splice(trueMBB->begin(), MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB->end());
+ trueMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ AVRCC::CondCodes CC = (AVRCC::CondCodes)MI.getOperand(3).getImm();
+ BuildMI(MBB, dl, TII.getBrCond(CC)).addMBB(trueMBB);
+ BuildMI(MBB, dl, TII.get(AVR::RJMPk)).addMBB(falseMBB);
+ MBB->addSuccessor(falseMBB);
+ MBB->addSuccessor(trueMBB);
+
+ // Unconditionally flow back to the true block
+ BuildMI(falseMBB, dl, TII.get(AVR::RJMPk)).addMBB(trueMBB);
+ falseMBB->addSuccessor(trueMBB);
+
+ // Set up the Phi node to determine where we came from
+ BuildMI(*trueMBB, trueMBB->begin(), dl, TII.get(AVR::PHI), MI.getOperand(0).getReg())
+ .addReg(MI.getOperand(1).getReg())
+ .addMBB(MBB)
+ .addReg(MI.getOperand(2).getReg())
+ .addMBB(falseMBB) ;
+
+ MI.eraseFromParent(); // The pseudo instruction is gone now.
+ return trueMBB;
+}
+
+//===----------------------------------------------------------------------===//
+// Inline Asm Support
+//===----------------------------------------------------------------------===//
+
+AVRTargetLowering::ConstraintType
+AVRTargetLowering::getConstraintType(StringRef Constraint) const {
+ if (Constraint.size() == 1) {
+ // See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
+ switch (Constraint[0]) {
+ case 'a': // Simple upper registers
+ case 'b': // Base pointer registers pairs
+ case 'd': // Upper register
+ case 'l': // Lower registers
+ case 'e': // Pointer register pairs
+ case 'q': // Stack pointer register
+ case 'r': // Any register
+ case 'w': // Special upper register pairs
+ return C_RegisterClass;
+ case 't': // Temporary register
+ case 'x': case 'X': // Pointer register pair X
+ case 'y': case 'Y': // Pointer register pair Y
+ case 'z': case 'Z': // Pointer register pair Z
+ return C_Register;
+ case 'Q': // A memory address based on Y or Z pointer with displacement.
+ return C_Memory;
+ case 'G': // Floating point constant
+ case 'I': // 6-bit positive integer constant
+ case 'J': // 6-bit negative integer constant
+ case 'K': // Integer constant (Range: 2)
+ case 'L': // Integer constant (Range: 0)
+ case 'M': // 8-bit integer constant
+ case 'N': // Integer constant (Range: -1)
+ case 'O': // Integer constant (Range: 8, 16, 24)
+ case 'P': // Integer constant (Range: 1)
+ case 'R': // Integer constant (Range: -6 to 5)x
+ return C_Other;
+ default:
+ break;
+ }
+ }
+
+ return TargetLowering::getConstraintType(Constraint);
+}
+
+unsigned
+AVRTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const {
+ // Not sure if this is actually the right thing to do, but we got to do
+ // *something* [agnat]
+ switch (ConstraintCode[0]) {
+ case 'Q':
+ return InlineAsm::Constraint_Q;
+ }
+ return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
+}
+
+AVRTargetLowering::ConstraintWeight
+AVRTargetLowering::getSingleConstraintMatchWeight(
+ AsmOperandInfo &info, const char *constraint) const {
+ ConstraintWeight weight = CW_Invalid;
+ Value *CallOperandVal = info.CallOperandVal;
+
+ // If we don't have a value, we can't do a match,
+ // but allow it at the lowest weight.
+ // (this behaviour has been copied from the ARM backend)
+ if (!CallOperandVal) {
+ return CW_Default;
+ }
+
+ // Look at the constraint type.
+ switch (*constraint) {
+ default:
+ weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
+ break;
+ case 'd':
+ case 'r':
+ case 'l':
+ weight = CW_Register;
+ break;
+ case 'a':
+ case 'b':
+ case 'e':
+ case 'q':
+ case 't':
+ case 'w':
+ case 'x': case 'X':
+ case 'y': case 'Y':
+ case 'z': case 'Z':
+ weight = CW_SpecificReg;
+ break;
+ case 'G':
+ if (const ConstantFP *C = dyn_cast<ConstantFP>(CallOperandVal)) {
+ if (C->isZero()) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'I':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (isUInt<6>(C->getZExtValue())) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'J':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if ((C->getSExtValue() >= -63) && (C->getSExtValue() <= 0)) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'K':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getZExtValue() == 2) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'L':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getZExtValue() == 0) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'M':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (isUInt<8>(C->getZExtValue())) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'N':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getSExtValue() == -1) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'O':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if ((C->getZExtValue() == 8) || (C->getZExtValue() == 16) ||
+ (C->getZExtValue() == 24)) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'P':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getZExtValue() == 1) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'R':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if ((C->getSExtValue() >= -6) && (C->getSExtValue() <= 5)) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'Q':
+ weight = CW_Memory;
+ break;
+ }
+
+ return weight;
+}
+
+std::pair<unsigned, const TargetRegisterClass *>
+AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ StringRef Constraint,
+ MVT VT) const {
+ auto STI = static_cast<const AVRTargetMachine &>(this->getTargetMachine())
+ .getSubtargetImpl();
+
+ // We only support i8 and i16.
+ //
+ //:FIXME: remove this assert for now since it gets sometimes executed
+ // assert((VT == MVT::i16 || VT == MVT::i8) && "Wrong operand type.");
+
+ if (Constraint.size() == 1) {
+ switch (Constraint[0]) {
+ case 'a': // Simple upper registers r16..r23.
+ return std::make_pair(0U, &AVR::LD8loRegClass);
+ case 'b': // Base pointer registers: y, z.
+ return std::make_pair(0U, &AVR::PTRDISPREGSRegClass);
+ case 'd': // Upper registers r16..r31.
+ return std::make_pair(0U, &AVR::LD8RegClass);
+ case 'l': // Lower registers r0..r15.
+ return std::make_pair(0U, &AVR::GPR8loRegClass);
+ case 'e': // Pointer register pairs: x, y, z.
+ return std::make_pair(0U, &AVR::PTRREGSRegClass);
+ case 'q': // Stack pointer register: SPH:SPL.
+ return std::make_pair(0U, &AVR::GPRSPRegClass);
+ case 'r': // Any register: r0..r31.
+ if (VT == MVT::i8)
+ return std::make_pair(0U, &AVR::GPR8RegClass);
+
+ assert(VT == MVT::i16 && "inline asm constraint too large");
+ return std::make_pair(0U, &AVR::DREGSRegClass);
+ case 't': // Temporary register: r0.
+ return std::make_pair(unsigned(AVR::R0), &AVR::GPR8RegClass);
+ case 'w': // Special upper register pairs: r24, r26, r28, r30.
+ return std::make_pair(0U, &AVR::IWREGSRegClass);
+ case 'x': // Pointer register pair X: r27:r26.
+ case 'X':
+ return std::make_pair(unsigned(AVR::R27R26), &AVR::PTRREGSRegClass);
+ case 'y': // Pointer register pair Y: r29:r28.
+ case 'Y':
+ return std::make_pair(unsigned(AVR::R29R28), &AVR::PTRREGSRegClass);
+ case 'z': // Pointer register pair Z: r31:r30.
+ case 'Z':
+ return std::make_pair(unsigned(AVR::R31R30), &AVR::PTRREGSRegClass);
+ default:
+ break;
+ }
+ }
+
+ return TargetLowering::getRegForInlineAsmConstraint(STI->getRegisterInfo(),
+ Constraint, VT);
+}
+
+void AVRTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
+ std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const {
+ SDValue Result(0, 0);
+ SDLoc DL(Op);
+ EVT Ty = Op.getValueType();
+
+ // Currently only support length 1 constraints.
+ if (Constraint.length() != 1) {
+ return;
+ }
+
+ char ConstraintLetter = Constraint[0];
+ switch (ConstraintLetter) {
+ default:
+ break;
+ // Deal with integers first:
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'R': {
+ const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
+ if (!C) {
+ return;
+ }
+
+ int64_t CVal64 = C->getSExtValue();
+ uint64_t CUVal64 = C->getZExtValue();
+ switch (ConstraintLetter) {
+ case 'I': // 0..63
+ if (!isUInt<6>(CUVal64))
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'J': // -63..0
+ if (CVal64 < -63 || CVal64 > 0)
+ return;
+ Result = DAG.getTargetConstant(CVal64, DL, Ty);
+ break;
+ case 'K': // 2
+ if (CUVal64 != 2)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'L': // 0
+ if (CUVal64 != 0)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'M': // 0..255
+ if (!isUInt<8>(CUVal64))
+ return;
+ // i8 type may be printed as a negative number,
+ // e.g. 254 would be printed as -2,
+ // so we force it to i16 at least.
+ if (Ty.getSimpleVT() == MVT::i8) {
+ Ty = MVT::i16;
+ }
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'N': // -1
+ if (CVal64 != -1)
+ return;
+ Result = DAG.getTargetConstant(CVal64, DL, Ty);
+ break;
+ case 'O': // 8, 16, 24
+ if (CUVal64 != 8 && CUVal64 != 16 && CUVal64 != 24)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'P': // 1
+ if (CUVal64 != 1)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'R': // -6..5
+ if (CVal64 < -6 || CVal64 > 5)
+ return;
+ Result = DAG.getTargetConstant(CVal64, DL, Ty);
+ break;
+ }
+
+ break;
+ }
+ case 'G':
+ const ConstantFPSDNode *FC = dyn_cast<ConstantFPSDNode>(Op);
+ if (!FC || !FC->isZero())
+ return;
+ // Soften float to i8 0
+ Result = DAG.getTargetConstant(0, DL, MVT::i8);
+ break;
+ }
+
+ if (Result.getNode()) {
+ Ops.push_back(Result);
+ return;
+ }
+
+ return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+}
+
+unsigned AVRTargetLowering::getRegisterByName(const char *RegName,
+ EVT VT,
+ SelectionDAG &DAG) const {
+ unsigned Reg;
+
+ if (VT == MVT::i8) {
+ Reg = StringSwitch<unsigned>(RegName)
+ .Case("r0", AVR::R0).Case("r1", AVR::R1).Case("r2", AVR::R2)
+ .Case("r3", AVR::R3).Case("r4", AVR::R4).Case("r5", AVR::R5)
+ .Case("r6", AVR::R6).Case("r7", AVR::R7).Case("r8", AVR::R8)
+ .Case("r9", AVR::R9).Case("r10", AVR::R10).Case("r11", AVR::R11)
+ .Case("r12", AVR::R12).Case("r13", AVR::R13).Case("r14", AVR::R14)
+ .Case("r15", AVR::R15).Case("r16", AVR::R16).Case("r17", AVR::R17)
+ .Case("r18", AVR::R18).Case("r19", AVR::R19).Case("r20", AVR::R20)
+ .Case("r21", AVR::R21).Case("r22", AVR::R22).Case("r23", AVR::R23)
+ .Case("r24", AVR::R24).Case("r25", AVR::R25).Case("r26", AVR::R26)
+ .Case("r27", AVR::R27).Case("r28", AVR::R28).Case("r29", AVR::R29)
+ .Case("r30", AVR::R30).Case("r31", AVR::R31)
+ .Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
+ .Default(0);
+ } else {
+ Reg = StringSwitch<unsigned>(RegName)
+ .Case("r0", AVR::R1R0).Case("r2", AVR::R3R2)
+ .Case("r4", AVR::R5R4).Case("r6", AVR::R7R6)
+ .Case("r8", AVR::R9R8).Case("r10", AVR::R11R10)
+ .Case("r12", AVR::R13R12).Case("r14", AVR::R15R14)
+ .Case("r16", AVR::R17R16).Case("r18", AVR::R19R18)
+ .Case("r20", AVR::R21R20).Case("r22", AVR::R23R22)
+ .Case("r24", AVR::R25R24).Case("r26", AVR::R27R26)
+ .Case("r28", AVR::R29R28).Case("r30", AVR::R31R30)
+ .Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
+ .Default(0);
+ }
+
+ if (Reg)
+ return Reg;
+
+ report_fatal_error("Invalid register name global variable");
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRISelLowering.h b/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
index 2c8c9c8..a8cdc4e 100644
--- a/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -15,6 +15,7 @@
#ifndef LLVM_AVR_ISEL_LOWERING_H
#define LLVM_AVR_ISEL_LOWERING_H
+#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/Target/TargetLowering.h"
namespace llvm {
@@ -92,6 +93,9 @@ public:
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
+ EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context,
+ EVT VT) const override;
+
MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const override;
@@ -112,6 +116,9 @@ public:
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;
+ unsigned getRegisterByName(const char* RegName, EVT VT,
+ SelectionDAG &DAG) const override;
+
private:
SDValue getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &AVRcc,
SelectionDAG &DAG, SDLoc dl) const;
@@ -125,6 +132,13 @@ private:
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
+ CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC) const;
+
+ bool CanLowerReturn(CallingConv::ID CallConv,
+ MachineFunction &MF, bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ LLVMContext &Context) const override;
+
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &dl,
@@ -143,8 +157,8 @@ private:
SmallVectorImpl<SDValue> &InVals) const;
private:
- MachineBasicBlock *insertShift(MachineInstr *MI, MachineBasicBlock *BB) const;
- MachineBasicBlock *insertMul(MachineInstr *MI, MachineBasicBlock *BB) const;
+ MachineBasicBlock *insertShift(MachineInstr &MI, MachineBasicBlock *BB) const;
+ MachineBasicBlock *insertMul(MachineInstr &MI, MachineBasicBlock *BB) const;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td b/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td
index c10023d..ce5e606 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td
@@ -20,6 +20,8 @@ class AVRInst<dag outs, dag ins, string asmstr, list<dag> pattern> : Instruction
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
+
+ field bits<32> SoftFail = 0;
}
/// A 16-bit AVR instruction.
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp
index 0327c01..88f8892 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp
@@ -27,6 +27,7 @@
#include "AVR.h"
#include "AVRMachineFunctionInfo.h"
+#include "AVRRegisterInfo.h"
#include "AVRTargetMachine.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
@@ -42,22 +43,41 @@ void AVRInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg,
unsigned SrcReg, bool KillSrc) const {
+ const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+ const AVRRegisterInfo &TRI = *STI.getRegisterInfo();
unsigned Opc;
- if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) {
- Opc = AVR::MOVRdRr;
- } else if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) {
- Opc = AVR::MOVWRdRr;
- } else if (SrcReg == AVR::SP && AVR::DREGSRegClass.contains(DestReg)) {
- Opc = AVR::SPREAD;
- } else if (DestReg == AVR::SP && AVR::DREGSRegClass.contains(SrcReg)) {
- Opc = AVR::SPWRITE;
+ // Not all AVR devices support the 16-bit `MOVW` instruction.
+ if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) {
+ if (STI.hasMOVW()) {
+ BuildMI(MBB, MI, DL, get(AVR::MOVWRdRr), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ } else {
+ unsigned DestLo, DestHi, SrcLo, SrcHi;
+
+ TRI.splitReg(DestReg, DestLo, DestHi);
+ TRI.splitReg(SrcReg, SrcLo, SrcHi);
+
+ // Copy each individual register with the `MOV` instruction.
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo)
+ .addReg(SrcLo, getKillRegState(KillSrc));
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi)
+ .addReg(SrcHi, getKillRegState(KillSrc));
+ }
} else {
- llvm_unreachable("Impossible reg-to-reg copy");
- }
+ if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) {
+ Opc = AVR::MOVRdRr;
+ } else if (SrcReg == AVR::SP && AVR::DREGSRegClass.contains(DestReg)) {
+ Opc = AVR::SPREAD;
+ } else if (DestReg == AVR::SP && AVR::DREGSRegClass.contains(SrcReg)) {
+ Opc = AVR::SPWRITE;
+ } else {
+ llvm_unreachable("Impossible reg-to-reg copy");
+ }
- BuildMI(MBB, MI, DL, get(Opc), DestReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
+ BuildMI(MBB, MI, DL, get(Opc), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ }
}
unsigned AVRInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
@@ -105,13 +125,16 @@ void AVRInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
MachineFunction &MF = *MBB.getParent();
+ AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ AFI->setHasSpills(true);
DebugLoc DL;
if (MI != MBB.end()) {
DL = MI->getDebugLoc();
}
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIndex),
@@ -145,7 +168,7 @@ void AVRInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
}
MachineFunction &MF = *MBB.getParent();
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIndex),
@@ -373,13 +396,16 @@ bool AVRInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-unsigned AVRInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned AVRInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(!BytesAdded && "code size not handled");
+
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"AVR branch conditions have one component!");
@@ -404,7 +430,10 @@ unsigned AVRInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return Count;
}
-unsigned AVRInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned AVRInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
@@ -429,7 +458,7 @@ unsigned AVRInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return Count;
}
-bool AVRInstrInfo::ReverseBranchCondition(
+bool AVRInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 1 && "Invalid AVR branch condition!");
@@ -439,8 +468,8 @@ bool AVRInstrInfo::ReverseBranchCondition(
return false;
}
-unsigned AVRInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
- unsigned Opcode = MI->getOpcode();
+unsigned AVRInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
+ unsigned Opcode = MI.getOpcode();
switch (Opcode) {
// A regular instruction
@@ -454,13 +483,16 @@ unsigned AVRInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
case TargetOpcode::DBG_VALUE:
return 0;
case TargetOpcode::INLINEASM: {
- const MachineFunction *MF = MI->getParent()->getParent();
- const AVRTargetMachine &TM = static_cast<const AVRTargetMachine&>(MF->getTarget());
- const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
- return TII.getInlineAsmLength(MI->getOperand(0).getSymbolName(),
+ const MachineFunction &MF = *MI.getParent()->getParent();
+ const AVRTargetMachine &TM = static_cast<const AVRTargetMachine&>(MF.getTarget());
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+
+ return TII.getInlineAsmLength(MI.getOperand(0).getSymbolName(),
*TM.getMCAsmInfo());
}
}
}
} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h
index fc8945d..c5105da 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h
@@ -70,7 +70,7 @@ public:
const MCInstrDesc &getBrCond(AVRCC::CondCodes CC) const;
AVRCC::CondCodes getCondFromBranchOpc(unsigned Opc) const;
AVRCC::CondCodes getOppositeCondition(AVRCC::CondCodes CC) const;
- unsigned GetInstSizeInBytes(const MachineInstr *MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
@@ -94,12 +94,14 @@ public:
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
private:
const AVRRegisterInfo RI;
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td
index e756836..bc66379 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -155,7 +155,7 @@ def memspi : Operand<iPTR>
let MIOperandInfo = (ops GPRSP, i16imm);
}
-def i8imm_com : Operand<i8>
+def imm_com8 : Operand<i8>
{
let EncoderMethod = "encodeComplement";
@@ -180,6 +180,38 @@ def call_target : Operand<iPTR>
let EncoderMethod = "encodeCallTarget";
}
+// A 16-bit address (which can lead to an R_AVR_16 relocation).
+def imm16 : Operand<i16>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_16>";
+}
+
+/// A 6-bit immediate used in the ADIW/SBIW instructions.
+def imm_arith6 : Operand<i16>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_6_adiw>";
+}
+
+/// An 8-bit immediate inside an instruction with the same format
+/// as the `LDI` instruction (the `FRdK` format).
+def imm_ldi8 : Operand<i8>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_ldi>";
+}
+
+/// A 5-bit port number used in SBIC and friends (the `FIOBIT` format).
+def imm_port5 : Operand<i8>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_port5>";
+}
+
+/// A 6-bit port number used in the `IN` instruction and friends (the
+/// `FIORdA` format.
+def imm_port6 : Operand<i8>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_port6>";
+}
+
// Addressing mode pattern reg+imm6
def addr : ComplexPattern<iPTR, 2, "SelectAddr", [], [SDNPWantRoot]>;
@@ -372,7 +404,7 @@ Defs = [SREG] in
// Adds an immediate 6-bit value K to Rd, placing the result in Rd.
def ADIWRdK : FWRdK<0b0,
(outs IWREGS:$rd),
- (ins IWREGS:$src, i16imm:$k),
+ (ins IWREGS:$src, imm_arith6:$k),
"adiw\t$rd, $k",
[(set i16:$rd, (add i16:$src, uimm6:$k)),
(implicit SREG)]>,
@@ -409,7 +441,7 @@ Defs = [SREG] in
def SUBIRdK : FRdK<0b0101,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"subi\t$rd, $k",
[(set i8:$rd, (sub i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -427,7 +459,7 @@ Defs = [SREG] in
def SBIWRdK : FWRdK<0b1,
(outs IWREGS:$rd),
- (ins IWREGS:$src, i16imm:$k),
+ (ins IWREGS:$src, imm_arith6:$k),
"sbiw\t$rd, $k",
[(set i16:$rd, (sub i16:$src, uimm6:$k)),
(implicit SREG)]>,
@@ -457,7 +489,7 @@ Defs = [SREG] in
def SBCIRdK : FRdK<0b0100,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"sbci\t$rd, $k",
[(set i8:$rd, (sube i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -626,7 +658,7 @@ Defs = [SREG] in
def ANDIRdK : FRdK<0b0111,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"andi\t$rd, $k",
[(set i8:$rd, (and i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -644,7 +676,7 @@ Defs = [SREG] in
def ORIRdK : FRdK<0b0110,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"ori\t$rd, $k",
[(set i8:$rd, (or i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -871,7 +903,7 @@ let Defs = [SREG] in
let Uses = [SREG] in
def CPIRdK : FRdK<0b0011,
(outs),
- (ins GPR8:$rd, i8imm:$k),
+ (ins GPR8:$rd, imm_ldi8:$k),
"cpi\t$rd, $k",
[(AVRcmp i8:$rd, imm:$k), (implicit SREG)]>;
}
@@ -900,13 +932,13 @@ isTerminator = 1 in
def SBICAb : FIOBIT<0b01,
(outs),
- (ins i16imm:$a, i8imm:$b),
+ (ins imm_port5:$a, i8imm:$b),
"sbic\t$a, $b",
[]>;
def SBISAb : FIOBIT<0b11,
(outs),
- (ins i16imm:$a, i8imm:$b),
+ (ins imm_port5:$a, i8imm:$b),
"sbis\t$a, $b",
[]>;
}
@@ -1065,7 +1097,7 @@ let isReMaterializable = 1 in
{
def LDIRdK : FRdK<0b1110,
(outs LD8:$rd),
- (ins i8imm:$k),
+ (ins imm_ldi8:$k),
"ldi\t$rd, $k",
[(set i8:$rd, imm:$k)]>;
@@ -1086,7 +1118,7 @@ isReMaterializable = 1 in
{
def LDSRdK : F32DM<0b0,
(outs GPR8:$rd),
- (ins i16imm:$k),
+ (ins imm16:$k),
"lds\t$rd, $k",
[(set i8:$rd, (load imm:$k))]>,
Requires<[HasSRAM]>;
@@ -1175,6 +1207,7 @@ Constraints = "$ptrreg = $base_wb,@earlyclobber $reg,@earlyclobber $base_wb" in
let canFoldAsLoad = 1,
isReMaterializable = 1 in
{
+ let Constraints = "@earlyclobber $reg" in
def LDDRdPtrQ : FSTDLDD<0,
(outs GPR8:$reg),
(ins memri:$memri),
@@ -1194,10 +1227,9 @@ isReMaterializable = 1 in
[(set i16:$dst, (load addr:$memri))]>,
Requires<[HasSRAM]>;
- //:FIXME: remove this once PR13375 gets fixed
- // Bug report: https://llvm.org/bugs/show_bug.cgi?id=13375
let mayLoad = 1,
- hasSideEffects = 0 in
+ hasSideEffects = 0,
+ Constraints = "@earlyclobber $dst" in
def LDDWRdYQ : Pseudo<(outs DREGS:$dst),
(ins memri:$memri),
"lddw\t$dst, $memri",
@@ -1205,10 +1237,42 @@ isReMaterializable = 1 in
Requires<[HasSRAM]>;
}
+class AtomicLoad<PatFrag Op, RegisterClass DRC> :
+ Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr), "atomic_op",
+ [(set DRC:$rd, (Op i16:$rr))]>;
+
+class AtomicStore<PatFrag Op, RegisterClass DRC> :
+ Pseudo<(outs), (ins PTRDISPREGS:$rd, DRC:$rr), "atomic_op",
+ [(Op i16:$rd, DRC:$rr)]>;
+
+class AtomicLoadOp<PatFrag Op, RegisterClass DRC> :
+ Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr, DRC:$operand),
+ "atomic_op",
+ [(set DRC:$rd, (Op i16:$rr, DRC:$operand))]>;
+
+def AtomicLoad8 : AtomicLoad<atomic_load_8, GPR8>;
+def AtomicLoad16 : AtomicLoad<atomic_load_16, DREGS>;
+
+def AtomicStore8 : AtomicStore<atomic_store_8, GPR8>;
+def AtomicStore16 : AtomicStore<atomic_store_16, DREGS>;
+
+def AtomicLoadAdd8 : AtomicLoadOp<atomic_load_add_8, GPR8>;
+def AtomicLoadAdd16 : AtomicLoadOp<atomic_load_add_16, DREGS>;
+def AtomicLoadSub8 : AtomicLoadOp<atomic_load_sub_8, GPR8>;
+def AtomicLoadSub16 : AtomicLoadOp<atomic_load_sub_16, DREGS>;
+def AtomicLoadAnd8 : AtomicLoadOp<atomic_load_and_8, GPR8>;
+def AtomicLoadAnd16 : AtomicLoadOp<atomic_load_and_16, DREGS>;
+def AtomicLoadOr8 : AtomicLoadOp<atomic_load_or_8, GPR8>;
+def AtomicLoadOr16 : AtomicLoadOp<atomic_load_or_16, DREGS>;
+def AtomicLoadXor8 : AtomicLoadOp<atomic_load_xor_8, GPR8>;
+def AtomicLoadXor16 : AtomicLoadOp<atomic_load_xor_16, DREGS>;
+def AtomicFence : Pseudo<(outs), (ins), "atomic_fence",
+ [(atomic_fence imm, imm)]>;
+
// Indirect store from register to data space.
def STSKRr : F32DM<0b1,
(outs),
- (ins i16imm:$k, GPR8:$rd),
+ (ins imm16:$k, GPR8:$rd),
"sts\t$k, $rd",
[(store i8:$rd, imm:$k)]>,
Requires<[HasSRAM]>;
@@ -1433,24 +1497,24 @@ let canFoldAsLoad = 1,
isReMaterializable = 1 in
{
def INRdA : FIORdA<(outs GPR8:$dst),
- (ins i16imm:$src),
+ (ins imm_port6:$src),
"in\t$dst, $src",
[(set i8:$dst, (load ioaddr8:$src))]>;
def INWRdA : Pseudo<(outs DREGS:$dst),
- (ins i16imm:$src),
+ (ins imm_port6:$src),
"inw\t$dst, $src",
[(set i16:$dst, (load ioaddr16:$src))]>;
}
// Write data to IO location operations.
def OUTARr : FIOARr<(outs),
- (ins i16imm:$dst, GPR8:$src),
+ (ins imm_port6:$dst, GPR8:$src),
"out\t$dst, $src",
[(store i8:$src, ioaddr8:$dst)]>;
def OUTWARr : Pseudo<(outs),
- (ins i16imm:$dst, DREGS:$src),
+ (ins imm_port6:$dst, DREGS:$src),
"outw\t$dst, $src",
[(store i16:$src, ioaddr16:$dst)]>;
@@ -1613,14 +1677,14 @@ def SWAPRd : FRd<0b1001,
// instead of in+ori+out which requires one more instr.
def SBIAb : FIOBIT<0b10,
(outs),
- (ins i16imm:$addr, i8imm:$bit),
+ (ins imm_port5:$addr, i8imm:$bit),
"sbi\t$addr, $bit",
[(store (or (i8 (load lowioaddr8:$addr)), iobitpos8:$bit),
lowioaddr8:$addr)]>;
def CBIAb : FIOBIT<0b00,
(outs),
- (ins i16imm:$addr, i8imm:$bit),
+ (ins imm_port5:$addr, i8imm:$bit),
"cbi\t$addr, $bit",
[(store (and (i8 (load lowioaddr8:$addr)), iobitposn8:$bit),
lowioaddr8:$addr)]>;
@@ -1648,16 +1712,18 @@ Defs = [SREG] in
// Alias for ORI Rd, K
def SBRRdK : FRdK<0b0110,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"sbr\t$rd, $k",
[(set i8:$rd, (or i8:$src, imm:$k)),
(implicit SREG)]>;
// CBR Rd, K
// Alias for `ANDI Rd, COM(K)` where COM(K) is the compliment of K.
+ // FIXME: This uses the 'complement' encoder. We need it to also use the
+ // imm_ldi8 encoder. This will cause no fixups to be created on this instruction.
def CBRRdK : FRdK<0b0111,
(outs LD8:$rd),
- (ins LD8:$src, i8imm_com:$k),
+ (ins LD8:$src, imm_com8:$k),
"cbr\t$rd, $k",
[]>;
}
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp b/contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp
new file mode 100644
index 0000000..5553dc2
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp
@@ -0,0 +1,222 @@
+//===-- AVRInstrumentFunctions.cpp - Insert instrumentation for testing ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass takes a function and inserts calls to hook functions which are
+// told the name, arguments, and results of function calls.
+//
+// The hooks can do anything with the information given. It is possible to
+// send the data through a serial connection in order to runs tests on
+// bare metal.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Module.h>
+
+using namespace llvm;
+
+#define AVR_INSTRUMENT_FUNCTIONS_NAME "AVR function instrumentation pass"
+
+namespace {
+
+// External symbols that we emit calls to.
+namespace symbols {
+
+#define SYMBOL_PREFIX "avr_instrumentation"
+
+ const StringRef PREFIX = SYMBOL_PREFIX;
+
+ // void (i16 argCount);
+ const StringRef BEGIN_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_begin_signature";
+ // void(i16 argCount);
+ const StringRef END_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_end_signature";
+
+#undef SYMBOL_PREFIX
+}
+
+class AVRInstrumentFunctions : public FunctionPass {
+public:
+ static char ID;
+
+ AVRInstrumentFunctions() : FunctionPass(ID) {
+ initializeAVRInstrumentFunctionsPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override;
+
+ StringRef getPassName() const override { return AVR_INSTRUMENT_FUNCTIONS_NAME; }
+};
+
+char AVRInstrumentFunctions::ID = 0;
+
+/// Creates a pointer to a string.
+static Value *CreateStringPtr(BasicBlock &BB, StringRef Str) {
+ LLVMContext &Ctx = BB.getContext();
+ IntegerType *I8 = Type::getInt8Ty(Ctx);
+
+ Constant *ConstantStr = ConstantDataArray::getString(Ctx, Str);
+ GlobalVariable *GlobalStr = new GlobalVariable(*BB.getParent()->getParent(),
+ ConstantStr->getType(),
+ true, /* is a constant */
+ GlobalValue::PrivateLinkage,
+ ConstantStr);
+ return GetElementPtrInst::CreateInBounds(GlobalStr,
+ {ConstantInt::get(I8, 0), ConstantInt::get(I8, 0)}, "", &BB);
+}
+
+static std::string GetTypeName(Type &Ty) {
+ if (auto *IntTy = dyn_cast<IntegerType>(&Ty)) {
+ return std::string("i") + std::to_string(IntTy->getBitWidth());
+ }
+
+ if (Ty.isFloatingPointTy()) {
+ return std::string("f") + std::to_string(Ty.getPrimitiveSizeInBits());
+ }
+
+ llvm_unreachable("unknown return type");
+}
+
+/// Builds a call to one of the signature begin/end hooks.
+static void BuildSignatureCall(StringRef SymName, BasicBlock &BB, Function &F) {
+ LLVMContext &Ctx = F.getContext();
+ IntegerType *I16 = Type::getInt16Ty(Ctx);
+
+ FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+ {Type::getInt8PtrTy(Ctx), I16}, false);
+
+ Constant *Fn = F.getParent()->getOrInsertFunction(SymName, FnType);
+ Value *FunctionName = CreateStringPtr(BB, F.getName());
+
+ Value *Args[] = {FunctionName,
+ ConstantInt::get(I16, F.getArgumentList().size())};
+ CallInst::Create(Fn, Args, "", &BB);
+}
+
+/// Builds instructions to call into an external function to
+/// notify about a function signature beginning.
+static void BuildBeginSignature(BasicBlock &BB, Function &F) {
+ return BuildSignatureCall(symbols::BEGIN_FUNCTION_SIGNATURE, BB, F);
+}
+
+/// Builds instructions to call into an external function to
+/// notify about a function signature ending.
+static void BuildEndSignature(BasicBlock &BB, Function &F) {
+ return BuildSignatureCall(symbols::END_FUNCTION_SIGNATURE, BB, F);
+}
+
+/// Get the name of the external symbol that we need to call
+/// to notify about this argument.
+static std::string GetArgumentSymbolName(Argument &Arg) {
+ return (symbols::PREFIX + "_argument_" + GetTypeName(*Arg.getType())).str();
+}
+
+/// Builds a call to one of the argument hooks.
+static void BuildArgument(BasicBlock &BB, Argument &Arg) {
+ Function &F = *Arg.getParent();
+ LLVMContext &Ctx = F.getContext();
+
+ Type *I8 = Type::getInt8Ty(Ctx);
+
+ FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+ {Type::getInt8PtrTy(Ctx), I8, Arg.getType()}, false);
+
+ Constant *Fn = F.getParent()->getOrInsertFunction(
+ GetArgumentSymbolName(Arg), FnType);
+ Value *ArgName = CreateStringPtr(BB, Arg.getName());
+
+ Value *Args[] = {ArgName, ConstantInt::get(I8, Arg.getArgNo()), &Arg};
+ CallInst::Create(Fn, Args, "", &BB);
+}
+
+/// Builds a call to all of the function signature hooks.
+static void BuildSignature(BasicBlock &BB, Function &F) {
+ BuildBeginSignature(BB, F);
+ for (Argument &Arg : F.args()) { BuildArgument(BB, Arg); }
+ BuildEndSignature(BB, F);
+}
+
+/// Builds the instrumentation entry block.
+static void BuildEntryBlock(Function &F) {
+ BasicBlock &EntryBlock = F.getEntryBlock();
+
+ // Create a new basic block at the start of the existing entry block.
+ BasicBlock *BB = BasicBlock::Create(F.getContext(),
+ "instrumentation_entry",
+ &F, &EntryBlock);
+
+ BuildSignature(*BB, F);
+
+ // Jump to the actual entry block.
+ BranchInst::Create(&EntryBlock, BB);
+}
+
+static std::string GetReturnSymbolName(Value &Val) {
+ return (symbols::PREFIX + "_result_" + GetTypeName(*Val.getType())).str();
+}
+
+static void BuildExitHook(Instruction &I) {
+ Function &F = *I.getParent()->getParent();
+ LLVMContext &Ctx = F.getContext();
+
+ if (auto *Ret = dyn_cast<ReturnInst>(&I)) {
+ Value *RetVal = Ret->getReturnValue();
+ assert(RetVal && "should only be instrumenting functions with return values");
+
+ FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+ {RetVal->getType()}, false);
+
+ Constant *Fn = F.getParent()->getOrInsertFunction(
+ GetReturnSymbolName(*RetVal), FnType);
+
+ // Call the result hook just before the return.
+ CallInst::Create(Fn, {RetVal}, "", &I);
+ }
+}
+
+/// Runs return hooks before all returns in a function.
+static void BuildExitHooks(Function &F) {
+ for (BasicBlock &BB : F) {
+ auto BBI = BB.begin(), E = BB.end();
+ while (BBI != E) {
+ auto NBBI = std::next(BBI);
+
+ BuildExitHook(*BBI);
+
+ // Modified |= expandMI(BB, MBBI);
+ BBI = NBBI;
+ }
+ }
+}
+
+static bool ShouldInstrument(Function &F) {
+ // No point reporting results if there are none.
+ return !F.getReturnType()->isVoidTy();
+}
+
+bool AVRInstrumentFunctions::runOnFunction(Function &F) {
+ if (ShouldInstrument(F)) {
+ BuildEntryBlock(F);
+ BuildExitHooks(F);
+ }
+
+ return true;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRInstrumentFunctions, "avr-instrument-functions",
+ AVR_INSTRUMENT_FUNCTIONS_NAME, false, false)
+
+namespace llvm {
+
+FunctionPass *createAVRInstrumentFunctionsPass() { return new AVRInstrumentFunctions(); }
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp
new file mode 100644
index 0000000..342fe55
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp
@@ -0,0 +1,100 @@
+//===-- AVRMCInstLower.cpp - Convert AVR MachineInstr to an MCInst --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code to lower AVR MachineInstrs to their corresponding
+// MCInst records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRMCInstLower.h"
+
+#include "AVRInstrInfo.h"
+#include "MCTargetDesc/AVRMCExpr.h"
+
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+
+MCOperand AVRMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
+ MCSymbol *Sym) const {
+ unsigned char TF = MO.getTargetFlags();
+ const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
+
+ bool IsNegated = false;
+ if (TF & AVRII::MO_NEG) { IsNegated = true; }
+
+ if (!MO.isJTI() && MO.getOffset()) {
+ Expr = MCBinaryExpr::createAdd(
+ Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
+ }
+
+ if (TF & AVRII::MO_LO) {
+ Expr = AVRMCExpr::create(AVRMCExpr::VK_AVR_LO8, Expr, IsNegated, Ctx);
+ } else if (TF & AVRII::MO_HI) {
+ Expr = AVRMCExpr::create(AVRMCExpr::VK_AVR_HI8, Expr, IsNegated, Ctx);
+ } else if (TF != 0) {
+ llvm_unreachable("Unknown target flag on symbol operand");
+ }
+
+ return MCOperand::createExpr(Expr);
+}
+
+void AVRMCInstLower::lowerInstruction(const MachineInstr &MI, MCInst &OutMI) const {
+ OutMI.setOpcode(MI.getOpcode());
+
+ for (MachineOperand const &MO : MI.operands()) {
+ MCOperand MCOp;
+
+ switch (MO.getType()) {
+ default:
+ MI.dump();
+ llvm_unreachable("unknown operand type");
+ case MachineOperand::MO_Register:
+ // Ignore all implicit register operands.
+ if (MO.isImplicit())
+ continue;
+ MCOp = MCOperand::createReg(MO.getReg());
+ break;
+ case MachineOperand::MO_Immediate:
+ MCOp = MCOperand::createImm(MO.getImm());
+ break;
+ case MachineOperand::MO_GlobalAddress:
+ MCOp = lowerSymbolOperand(MO, Printer.getSymbol(MO.getGlobal()));
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ MCOp = lowerSymbolOperand(
+ MO, Printer.GetExternalSymbolSymbol(MO.getSymbolName()));
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ MCOp = MCOperand::createExpr(
+ MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
+ break;
+ case MachineOperand::MO_RegisterMask:
+ continue;
+ case MachineOperand::MO_BlockAddress:
+ MCOp = lowerSymbolOperand(
+ MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
+ break;
+ case MachineOperand::MO_JumpTableIndex:
+ MCOp = lowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
+ break;
+ case MachineOperand::MO_ConstantPoolIndex:
+ MCOp = lowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
+ break;
+ }
+
+ OutMI.addOperand(MCOp);
+ }
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRMCInstLower.h b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.h
new file mode 100644
index 0000000..2e2d101
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.h
@@ -0,0 +1,43 @@
+//===-- AVRMCInstLower.h - Lower MachineInstr to MCInst ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_MCINST_LOWER_H
+#define LLVM_AVR_MCINST_LOWER_H
+
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+
+class AsmPrinter;
+class MachineInstr;
+class MachineOperand;
+class MCContext;
+class MCInst;
+class MCOperand;
+class MCSymbol;
+
+/// Lowers `MachineInstr` objects into `MCInst` objects.
+class AVRMCInstLower {
+public:
+ AVRMCInstLower(MCContext &Ctx, AsmPrinter &Printer)
+ : Ctx(Ctx), Printer(Printer) {}
+
+ /// Lowers a `MachineInstr` into a `MCInst`.
+ void lowerInstruction(const MachineInstr &MI, MCInst &OutMI) const;
+ MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
+
+private:
+ MCContext &Ctx;
+ AsmPrinter &Printer;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_MCINST_LOWER_H
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
index 5786f74..48798bd 100644
--- a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
@@ -129,13 +129,13 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
const MachineFunction &MF = *MBB.getParent();
const AVRTargetMachine &TM = (const AVRTargetMachine &)MF.getTarget();
const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetFrameLowering *TFI = TM.getSubtargetImpl()->getFrameLowering();
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- int Offset = MFI->getObjectOffset(FrameIndex);
+ int Offset = MFI.getObjectOffset(FrameIndex);
// Add one to the offset because SP points to an empty slot.
- Offset += MFI->getStackSize() - TFI->getOffsetOfLocalArea() + 1;
+ Offset += MFI.getStackSize() - TFI->getOffsetOfLocalArea() + 1;
// Fold incoming offset.
Offset += MI.getOperand(FIOperandNum + 1).getImm();
@@ -172,7 +172,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
Opcode = AVR::ADIWRdK;
break;
}
- // Fallthrough
+ LLVM_FALLTHROUGH;
}
default: {
// This opcode will get expanded into a pair of subi/sbci.
@@ -193,7 +193,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// If the offset is too big we have to adjust and restore the frame pointer
// to materialize a valid load/store with displacement.
//:TODO: consider using only one adiw/sbiw chain for more than one frame index
- if (Offset >= 63) {
+ if (Offset > 63) {
unsigned AddOpc = AVR::ADIWRdK, SubOpc = AVR::SBIWRdK;
int AddOffset = Offset - 63 + 1;
@@ -253,4 +253,14 @@ AVRRegisterInfo::getPointerRegClass(const MachineFunction &MF,
return &AVR::PTRDISPREGSRegClass;
}
+void AVRRegisterInfo::splitReg(unsigned Reg,
+ unsigned &LoReg,
+ unsigned &HiReg) const {
+ assert(AVR::DREGSRegClass.contains(Reg) && "can only split 16-bit registers");
+
+ LoReg = getSubReg(Reg, AVR::sub_lo);
+ HiReg = getSubReg(Reg, AVR::sub_hi);
+}
+
} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h
index 59c0849..b97e32e 100644
--- a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h
+++ b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h
@@ -42,13 +42,15 @@ public:
unsigned FIOperandNum,
RegScavenger *RS = NULL) const override;
- /// Debug information queries.
unsigned getFrameRegister(const MachineFunction &MF) const override;
- /// Returns a TargetRegisterClass used for pointer values.
const TargetRegisterClass *
getPointerRegClass(const MachineFunction &MF,
unsigned Kind = 0) const override;
+
+ /// Splits a 16-bit `DREGS` register into the lo/hi register pair.
+ /// \param Reg A 16-bit register to split.
+ void splitReg(unsigned Reg, unsigned &LoReg, unsigned &HiReg) const;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp b/contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
new file mode 100644
index 0000000..26dbcf7
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
@@ -0,0 +1,149 @@
+//===-- AVRRelaxMemOperations.cpp - Relax out of range loads/stores -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass which relaxes out of range memory operations into
+// equivalent operations which handle bigger addresses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRInstrInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#define AVR_RELAX_MEM_OPS_NAME "AVR memory operation relaxation pass"
+
+namespace {
+
+class AVRRelaxMem : public MachineFunctionPass {
+public:
+ static char ID;
+
+ AVRRelaxMem() : MachineFunctionPass(ID) {
+ initializeAVRRelaxMemPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override { return AVR_RELAX_MEM_OPS_NAME; }
+
+private:
+ typedef MachineBasicBlock Block;
+ typedef Block::iterator BlockIt;
+
+ const TargetInstrInfo *TII;
+
+ template <unsigned OP> bool relax(Block &MBB, BlockIt MBBI);
+
+ bool runOnBasicBlock(Block &MBB);
+ bool runOnInstruction(Block &MBB, BlockIt MBBI);
+
+ MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) {
+ return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode));
+ }
+};
+
+char AVRRelaxMem::ID = 0;
+
+bool AVRRelaxMem::runOnMachineFunction(MachineFunction &MF) {
+ bool Modified = false;
+
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ TII = STI.getInstrInfo();
+
+ for (Block &MBB : MF) {
+ bool BlockModified = runOnBasicBlock(MBB);
+ Modified |= BlockModified;
+ }
+
+ return Modified;
+}
+
+bool AVRRelaxMem::runOnBasicBlock(Block &MBB) {
+ bool Modified = false;
+
+ BlockIt MBBI = MBB.begin(), E = MBB.end();
+ while (MBBI != E) {
+ BlockIt NMBBI = std::next(MBBI);
+ Modified |= runOnInstruction(MBB, MBBI);
+ MBBI = NMBBI;
+ }
+
+ return Modified;
+}
+
+template <>
+bool AVRRelaxMem::relax<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+
+ MachineOperand &Ptr = MI.getOperand(0);
+ MachineOperand &Src = MI.getOperand(2);
+ int64_t Imm = MI.getOperand(1).getImm();
+
+ // We can definitely optimise this better.
+ if (Imm > 63) {
+ // Push the previous state of the pointer register.
+ // This instruction must preserve the value.
+ buildMI(MBB, MBBI, AVR::PUSHWRr)
+ .addReg(Ptr.getReg());
+
+ // Add the immediate to the pointer register.
+ buildMI(MBB, MBBI, AVR::SBCIWRdK)
+ .addReg(Ptr.getReg(), RegState::Define)
+ .addReg(Ptr.getReg())
+ .addImm(-Imm);
+
+ // Store the value in the source register to the address
+ // pointed to by the pointer register.
+ buildMI(MBB, MBBI, AVR::STWPtrRr)
+ .addReg(Ptr.getReg())
+ .addReg(Src.getReg(), getKillRegState(Src.isKill()));
+
+ // Pop the original state of the pointer register.
+ buildMI(MBB, MBBI, AVR::POPWRd)
+ .addReg(Ptr.getReg(), getKillRegState(Ptr.isKill()));
+
+ MI.removeFromParent();
+ }
+
+ return false;
+}
+
+bool AVRRelaxMem::runOnInstruction(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ int Opcode = MBBI->getOpcode();
+
+#define RELAX(Op) \
+ case Op: \
+ return relax<Op>(MBB, MI)
+
+ switch (Opcode) {
+ RELAX(AVR::STDWPtrQRr);
+ }
+#undef RELAX
+ return false;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRRelaxMem, "avr-relax-mem",
+ AVR_RELAX_MEM_OPS_NAME, false, false)
+
+namespace llvm {
+
+FunctionPass *createAVRRelaxMemPass() { return new AVRRelaxMem(); }
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp
index 508723e..fb32629 100644
--- a/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp
@@ -25,6 +25,8 @@
namespace llvm {
+static const char *AVRDataLayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8";
+
/// Processes a CPU name.
static StringRef getCPU(StringRef CPU) {
if (CPU.empty() || CPU == "generic") {
@@ -44,7 +46,7 @@ AVRTargetMachine::AVRTargetMachine(const Target &T, const Triple &TT,
Optional<Reloc::Model> RM, CodeModel::Model CM,
CodeGenOpt::Level OL)
: LLVMTargetMachine(
- T, "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-i64:8:8-f32:8:8-f64:8:8-n8", TT,
+ T, AVRDataLayout, TT,
getCPU(CPU), FS, Options, getEffectiveRelocModel(RM), CM, OL),
SubTarget(TT, getCPU(CPU), FS, *this) {
this->TLOF = make_unique<AVRTargetObjectFile>();
@@ -65,7 +67,6 @@ public:
bool addInstSelector() override;
void addPreSched2() override;
void addPreRegAlloc() override;
- void addPreEmitPass() override;
};
} // namespace
@@ -75,7 +76,12 @@ TargetPassConfig *AVRTargetMachine::createPassConfig(PassManagerBase &PM) {
extern "C" void LLVMInitializeAVRTarget() {
// Register the target.
- RegisterTargetMachine<AVRTargetMachine> X(TheAVRTarget);
+ RegisterTargetMachine<AVRTargetMachine> X(getTheAVRTarget());
+
+ auto &PR = *PassRegistry::getPassRegistry();
+ initializeAVRExpandPseudoPass(PR);
+ initializeAVRInstrumentFunctionsPass(PR);
+ initializeAVRRelaxMemPass(PR);
}
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const {
@@ -91,15 +97,22 @@ const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const {
//===----------------------------------------------------------------------===//
bool AVRPassConfig::addInstSelector() {
+ // Install an instruction selector.
+ addPass(createAVRISelDag(getAVRTargetMachine(), getOptLevel()));
+ // Create the frame analyzer pass used by the PEI pass.
+ addPass(createAVRFrameAnalyzerPass());
+
return false;
}
void AVRPassConfig::addPreRegAlloc() {
+ // Create the dynalloc SP save/restore pass to handle variable sized allocas.
+ addPass(createAVRDynAllocaSRPass());
}
-void AVRPassConfig::addPreSched2() { }
-
-void AVRPassConfig::addPreEmitPass() {
+void AVRPassConfig::addPreSched2() {
+ addPass(createAVRRelaxMemPass());
+ addPass(createAVRExpandPseudoPass());
}
} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
index 85f03e8..af14d92 100644
--- a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
@@ -26,15 +26,16 @@ void AVRTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) {
}
MCSection *
-AVRTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
+AVRTargetObjectFile::SelectSectionForGlobal(const GlobalObject *GO,
+ SectionKind Kind,
const TargetMachine &TM) const {
// Global values in flash memory are placed in the progmem.data section
// unless they already have a user assigned section.
- if (AVR::isProgramMemoryAddress(GV) && !GV->hasSection())
+ if (AVR::isProgramMemoryAddress(GO) && !GO->hasSection())
return ProgmemDataSection;
// Otherwise, we work the same way as ELF.
- return Base::SelectSectionForGlobal(GV, Kind, Mang, TM);
+ return Base::SelectSectionForGlobal(GO, Kind, TM);
}
} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h
index 5876125..ba91036 100644
--- a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h
@@ -21,8 +21,7 @@ class AVRTargetObjectFile : public TargetLoweringObjectFileELF {
public:
void Initialize(MCContext &ctx, const TargetMachine &TM) override;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
private:
diff --git a/contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp b/contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
new file mode 100644
index 0000000..5b0398c
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
@@ -0,0 +1,631 @@
+//===---- AVRAsmParser.cpp - Parse AVR assembly to MCInst instructions ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRRegisterInfo.h"
+#include "MCTargetDesc/AVRMCExpr.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TargetRegistry.h"
+
+#include <sstream>
+
+#define DEBUG_TYPE "avr-asm-parser"
+
+namespace llvm {
+
+/// Parses AVR assembly from a stream.
+class AVRAsmParser : public MCTargetAsmParser {
+ const MCSubtargetInfo &STI;
+ MCAsmParser &Parser;
+ const MCRegisterInfo *MRI;
+
+#define GET_ASSEMBLER_HEADER
+#include "AVRGenAsmMatcher.inc"
+
+ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ OperandVector &Operands, MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) override;
+
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
+
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc, OperandVector &Operands) override;
+
+ bool ParseDirective(AsmToken directiveID) override;
+
+ OperandMatchResultTy parseMemriOperand(OperandVector &Operands);
+
+ bool parseOperand(OperandVector &Operands);
+ int parseRegisterName(unsigned (*matchFn)(StringRef));
+ int parseRegisterName();
+ int parseRegister();
+ bool tryParseRegisterOperand(OperandVector &Operands);
+ bool tryParseExpression(OperandVector &Operands);
+ bool tryParseRelocExpression(OperandVector &Operands);
+ void eatComma();
+
+ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
+ unsigned Kind) override;
+
+ unsigned toDREG(unsigned Reg, unsigned From = AVR::sub_lo) {
+ MCRegisterClass const *Class = &AVRMCRegisterClasses[AVR::DREGSRegClassID];
+ return MRI->getMatchingSuperReg(Reg, From, Class);
+ }
+
+ bool emit(MCInst &Instruction, SMLoc const &Loc, MCStreamer &Out) const;
+ bool invalidOperand(SMLoc const &Loc, OperandVector const &Operands,
+ uint64_t const &ErrorInfo);
+ bool missingFeature(SMLoc const &Loc, uint64_t const &ErrorInfo);
+
+public:
+ AVRAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+ const MCInstrInfo &MII, const MCTargetOptions &Options)
+ : MCTargetAsmParser(Options, STI), STI(STI), Parser(Parser) {
+ MCAsmParserExtension::Initialize(Parser);
+ MRI = getContext().getRegisterInfo();
+
+ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+ }
+
+ MCAsmParser &getParser() const { return Parser; }
+ MCAsmLexer &getLexer() const { return Parser.getLexer(); }
+};
+
+/// An parsed AVR assembly operand.
+class AVROperand : public MCParsedAsmOperand {
+ typedef MCParsedAsmOperand Base;
+ enum KindTy { k_Immediate, k_Register, k_Token, k_Memri } Kind;
+
+public:
+ AVROperand(StringRef Tok, SMLoc const &S)
+ : Base(), Kind(k_Token), Tok(Tok), Start(S), End(S) {}
+ AVROperand(unsigned Reg, SMLoc const &S, SMLoc const &E)
+ : Base(), Kind(k_Register), RegImm({Reg, nullptr}), Start(S), End(E) {}
+ AVROperand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
+ : Base(), Kind(k_Immediate), RegImm({0, Imm}), Start(S), End(E) {}
+ AVROperand(unsigned Reg, MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
+ : Base(), Kind(k_Memri), RegImm({Reg, Imm}), Start(S), End(E) {}
+
+ struct RegisterImmediate {
+ unsigned Reg;
+ MCExpr const *Imm;
+ };
+ union {
+ StringRef Tok;
+ RegisterImmediate RegImm;
+ };
+
+ SMLoc Start, End;
+
+public:
+ void addRegOperands(MCInst &Inst, unsigned N) const {
+ assert(Kind == k_Register && "Unexpected operand kind");
+ assert(N == 1 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ }
+
+ void addExpr(MCInst &Inst, const MCExpr *Expr) const {
+ // Add as immediate when possible
+ if (!Expr)
+ Inst.addOperand(MCOperand::createImm(0));
+ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(MCOperand::createImm(CE->getValue()));
+ else
+ Inst.addOperand(MCOperand::createExpr(Expr));
+ }
+
+ void addImmOperands(MCInst &Inst, unsigned N) const {
+ assert(Kind == k_Immediate && "Unexpected operand kind");
+ assert(N == 1 && "Invalid number of operands!");
+
+ const MCExpr *Expr = getImm();
+ addExpr(Inst, Expr);
+ }
+
+ /// Adds the contained reg+imm operand to an instruction.
+ void addMemriOperands(MCInst &Inst, unsigned N) const {
+ assert(Kind == k_Memri && "Unexpected operand kind");
+ assert(N == 2 && "Invalid number of operands");
+
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ addExpr(Inst, getImm());
+ }
+
+ bool isReg() const { return Kind == k_Register; }
+ bool isImm() const { return Kind == k_Immediate; }
+ bool isToken() const { return Kind == k_Token; }
+ bool isMem() const { return Kind == k_Memri; }
+ bool isMemri() const { return Kind == k_Memri; }
+
+ StringRef getToken() const {
+ assert(Kind == k_Token && "Invalid access!");
+ return Tok;
+ }
+
+ unsigned getReg() const {
+ assert((Kind == k_Register || Kind == k_Memri) && "Invalid access!");
+
+ return RegImm.Reg;
+ }
+
+ const MCExpr *getImm() const {
+ assert((Kind == k_Immediate || Kind == k_Memri) && "Invalid access!");
+ return RegImm.Imm;
+ }
+
+ static std::unique_ptr<AVROperand> CreateToken(StringRef Str, SMLoc S) {
+ return make_unique<AVROperand>(Str, S);
+ }
+
+ static std::unique_ptr<AVROperand> CreateReg(unsigned RegNum, SMLoc S,
+ SMLoc E) {
+ return make_unique<AVROperand>(RegNum, S, E);
+ }
+
+ static std::unique_ptr<AVROperand> CreateImm(const MCExpr *Val, SMLoc S,
+ SMLoc E) {
+ return make_unique<AVROperand>(Val, S, E);
+ }
+
+ static std::unique_ptr<AVROperand>
+ CreateMemri(unsigned RegNum, const MCExpr *Val, SMLoc S, SMLoc E) {
+ return make_unique<AVROperand>(RegNum, Val, S, E);
+ }
+
+ void makeToken(StringRef Token) {
+ Kind = k_Token;
+ Tok = Token;
+ }
+
+ void makeReg(unsigned RegNo) {
+ Kind = k_Register;
+ RegImm = {RegNo, nullptr};
+ }
+
+ void makeImm(MCExpr const *Ex) {
+ Kind = k_Immediate;
+ RegImm = {0, Ex};
+ }
+
+ void makeMemri(unsigned RegNo, MCExpr const *Imm) {
+ Kind = k_Memri;
+ RegImm = {RegNo, Imm};
+ }
+
+ SMLoc getStartLoc() const { return Start; }
+ SMLoc getEndLoc() const { return End; }
+
+ virtual void print(raw_ostream &O) const {
+ switch (Kind) {
+ case k_Token:
+ O << "Token: \"" << getToken() << "\"";
+ break;
+ case k_Register:
+ O << "Register: " << getReg();
+ break;
+ case k_Immediate:
+ O << "Immediate: \"" << *getImm() << "\"";
+ break;
+ case k_Memri: {
+ // only manually print the size for non-negative values,
+ // as the sign is inserted automatically.
+ O << "Memri: \"" << getReg() << '+' << *getImm() << "\"";
+ break;
+ }
+ }
+ O << "\n";
+ }
+};
+
+// Auto-generated Match Functions
+
+/// Maps from the set of all register names to a register number.
+/// \note Generated by TableGen.
+static unsigned MatchRegisterName(StringRef Name);
+
+/// Maps from the set of all alternative registernames to a register number.
+/// \note Generated by TableGen.
+static unsigned MatchRegisterAltName(StringRef Name);
+
+bool AVRAsmParser::invalidOperand(SMLoc const &Loc,
+ OperandVector const &Operands,
+ uint64_t const &ErrorInfo) {
+ SMLoc ErrorLoc = Loc;
+ char const *Diag = 0;
+
+ if (ErrorInfo != ~0U) {
+ if (ErrorInfo >= Operands.size()) {
+ Diag = "too few operands for instruction.";
+ } else {
+ AVROperand const &Op = (AVROperand const &)*Operands[ErrorInfo];
+
+ // TODO: See if we can do a better error than just "invalid ...".
+ if (Op.getStartLoc() != SMLoc()) {
+ ErrorLoc = Op.getStartLoc();
+ }
+ }
+ }
+
+ if (!Diag) {
+ Diag = "invalid operand for instruction";
+ }
+
+ return Error(ErrorLoc, Diag);
+}
+
+bool AVRAsmParser::missingFeature(llvm::SMLoc const &Loc,
+ uint64_t const &ErrorInfo) {
+ return Error(Loc, "instruction requires a CPU feature not currently enabled");
+}
+
+bool AVRAsmParser::emit(MCInst &Inst, SMLoc const &Loc, MCStreamer &Out) const {
+ Inst.setLoc(Loc);
+ Out.EmitInstruction(Inst, STI);
+
+ return false;
+}
+
+bool AVRAsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
+ OperandVector &Operands,
+ MCStreamer &Out, uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) {
+ MCInst Inst;
+ unsigned MatchResult =
+ MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+
+ switch (MatchResult) {
+ case Match_Success: return emit(Inst, Loc, Out);
+ case Match_MissingFeature: return missingFeature(Loc, ErrorInfo);
+ case Match_InvalidOperand: return invalidOperand(Loc, Operands, ErrorInfo);
+ case Match_MnemonicFail: return Error(Loc, "invalid instruction");
+ default: return true;
+ }
+}
+
+/// Parses a register name using a given matching function.
+/// Checks for lowercase or uppercase if necessary.
+int AVRAsmParser::parseRegisterName(unsigned (*matchFn)(StringRef)) {
+ StringRef Name = Parser.getTok().getString();
+
+ int RegNum = matchFn(Name);
+
+ // GCC supports case insensitive register names. Some of the AVR registers
+ // are all lower case, some are all upper case but non are mixed. We prefer
+ // to use the original names in the register definitions. That is why we
+ // have to test both upper and lower case here.
+ if (RegNum == AVR::NoRegister) {
+ RegNum = matchFn(Name.lower());
+ }
+ if (RegNum == AVR::NoRegister) {
+ RegNum = matchFn(Name.upper());
+ }
+
+ return RegNum;
+}
+
+int AVRAsmParser::parseRegisterName() {
+ int RegNum = parseRegisterName(&MatchRegisterName);
+
+ if (RegNum == AVR::NoRegister)
+ RegNum = parseRegisterName(&MatchRegisterAltName);
+
+ return RegNum;
+}
+
+int AVRAsmParser::parseRegister() {
+ int RegNum = AVR::NoRegister;
+
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ // Check for register pair syntax
+ if (Parser.getLexer().peekTok().is(AsmToken::Colon)) {
+ Parser.Lex();
+ Parser.Lex(); // Eat high (odd) register and colon
+
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ // Convert lower (even) register to DREG
+ RegNum = toDREG(parseRegisterName());
+ }
+ } else {
+ RegNum = parseRegisterName();
+ }
+ }
+ return RegNum;
+}
+
+bool AVRAsmParser::tryParseRegisterOperand(OperandVector &Operands) {
+ int RegNo = parseRegister();
+
+ if (RegNo == AVR::NoRegister)
+ return true;
+
+ AsmToken const &T = Parser.getTok();
+ Operands.push_back(AVROperand::CreateReg(RegNo, T.getLoc(), T.getEndLoc()));
+ Parser.Lex(); // Eat register token.
+
+ return false;
+}
+
+bool AVRAsmParser::tryParseExpression(OperandVector &Operands) {
+ SMLoc S = Parser.getTok().getLoc();
+
+ if (!tryParseRelocExpression(Operands))
+ return false;
+
+ if ((Parser.getTok().getKind() == AsmToken::Plus ||
+ Parser.getTok().getKind() == AsmToken::Minus) &&
+ Parser.getLexer().peekTok().getKind() == AsmToken::Identifier) {
+ // Don't handle this case - it should be split into two
+ // separate tokens.
+ return true;
+ }
+
+ // Parse (potentially inner) expression
+ MCExpr const *Expression;
+ if (getParser().parseExpression(Expression))
+ return true;
+
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Operands.push_back(AVROperand::CreateImm(Expression, S, E));
+ return false;
+}
+
+bool AVRAsmParser::tryParseRelocExpression(OperandVector &Operands) {
+ bool isNegated = false;
+ AVRMCExpr::VariantKind ModifierKind = AVRMCExpr::VK_AVR_None;
+
+ SMLoc S = Parser.getTok().getLoc();
+
+ // Check for sign
+ AsmToken tokens[2];
+ size_t ReadCount = Parser.getLexer().peekTokens(tokens);
+
+ if (ReadCount == 2) {
+ if (tokens[0].getKind() == AsmToken::Identifier &&
+ tokens[1].getKind() == AsmToken::LParen) {
+
+ AsmToken::TokenKind CurTok = Parser.getLexer().getKind();
+ if (CurTok == AsmToken::Minus) {
+ isNegated = true;
+ } else {
+ assert(CurTok == AsmToken::Plus);
+ isNegated = false;
+ }
+
+ // Eat the sign
+ Parser.Lex();
+ }
+ }
+
+ // Check if we have a target specific modifier (lo8, hi8, &c)
+ if (Parser.getTok().getKind() != AsmToken::Identifier ||
+ Parser.getLexer().peekTok().getKind() != AsmToken::LParen) {
+ // Not a reloc expr
+ return true;
+ }
+ StringRef ModifierName = Parser.getTok().getString();
+ ModifierKind = AVRMCExpr::getKindByName(ModifierName.str().c_str());
+
+ if (ModifierKind != AVRMCExpr::VK_AVR_None) {
+ Parser.Lex();
+ Parser.Lex(); // Eat modifier name and parenthesis
+ } else {
+ return Error(Parser.getTok().getLoc(), "unknown modifier");
+ }
+
+ MCExpr const *InnerExpression;
+ if (getParser().parseExpression(InnerExpression))
+ return true;
+
+ // If we have a modifier wrap the inner expression
+ assert(Parser.getTok().getKind() == AsmToken::RParen);
+ Parser.Lex(); // Eat closing parenthesis
+
+ MCExpr const *Expression = AVRMCExpr::create(ModifierKind, InnerExpression,
+ isNegated, getContext());
+
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Operands.push_back(AVROperand::CreateImm(Expression, S, E));
+
+ return false;
+}
+
+bool AVRAsmParser::parseOperand(OperandVector &Operands) {
+ DEBUG(dbgs() << "parseOperand\n");
+
+ switch (getLexer().getKind()) {
+ default:
+ return Error(Parser.getTok().getLoc(), "unexpected token in operand");
+
+ case AsmToken::Identifier:
+ // Try to parse a register, if it fails,
+ // fall through to the next case.
+ if (!tryParseRegisterOperand(Operands)) {
+ return false;
+ }
+ case AsmToken::LParen:
+ case AsmToken::Integer:
+ case AsmToken::Dot:
+ return tryParseExpression(Operands);
+ case AsmToken::Plus:
+ case AsmToken::Minus: {
+ // If the sign preceeds a number, parse the number,
+ // otherwise treat the sign a an independent token.
+ switch (getLexer().peekTok().getKind()) {
+ case AsmToken::Integer:
+ case AsmToken::BigNum:
+ case AsmToken::Identifier:
+ case AsmToken::Real:
+ if (!tryParseExpression(Operands))
+ return false;
+ default:
+ break;
+ }
+ // Treat the token as an independent token.
+ Operands.push_back(AVROperand::CreateToken(Parser.getTok().getString(),
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the token.
+ return false;
+ }
+ }
+
+ // Could not parse operand
+ return true;
+}
+
+OperandMatchResultTy
+AVRAsmParser::parseMemriOperand(OperandVector &Operands) {
+ DEBUG(dbgs() << "parseMemriOperand()\n");
+
+ SMLoc E, S;
+ MCExpr const *Expression;
+ int RegNo;
+
+ // Parse register.
+ {
+ RegNo = parseRegister();
+
+ if (RegNo == AVR::NoRegister)
+ return MatchOperand_ParseFail;
+
+ S = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Parser.Lex(); // Eat register token.
+ }
+
+ // Parse immediate;
+ {
+ if (getParser().parseExpression(Expression))
+ return MatchOperand_ParseFail;
+
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ }
+
+ Operands.push_back(AVROperand::CreateMemri(RegNo, Expression, S, E));
+
+ return MatchOperand_Success;
+}
+
+bool AVRAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
+ SMLoc &EndLoc) {
+ StartLoc = Parser.getTok().getLoc();
+ RegNo = parseRegister();
+ EndLoc = Parser.getTok().getLoc();
+
+ return (RegNo == AVR::NoRegister);
+}
+
+void AVRAsmParser::eatComma() {
+ if (getLexer().is(AsmToken::Comma)) {
+ Parser.Lex();
+ } else {
+ // GCC allows commas to be omitted.
+ }
+}
+
+bool AVRAsmParser::ParseInstruction(ParseInstructionInfo &Info,
+ StringRef Mnemonic, SMLoc NameLoc,
+ OperandVector &Operands) {
+ Operands.push_back(AVROperand::CreateToken(Mnemonic, NameLoc));
+
+ bool first = true;
+ while (getLexer().isNot(AsmToken::EndOfStatement)) {
+ if (!first) eatComma();
+
+ first = false;
+
+ auto MatchResult = MatchOperandParserImpl(Operands, Mnemonic);
+
+ if (MatchResult == MatchOperand_Success) {
+ continue;
+ }
+
+ if (MatchResult == MatchOperand_ParseFail) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+
+ return Error(Loc, "failed to parse register and immediate pair");
+ }
+
+ if (parseOperand(Operands)) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token in argument list");
+ }
+ }
+ Parser.Lex(); // Consume the EndOfStatement
+ return false;
+}
+
+bool AVRAsmParser::ParseDirective(llvm::AsmToken DirectiveID) { return true; }
+
+extern "C" void LLVMInitializeAVRAsmParser() {
+ RegisterMCAsmParser<AVRAsmParser> X(getTheAVRTarget());
+}
+
+#define GET_REGISTER_MATCHER
+#define GET_MATCHER_IMPLEMENTATION
+#include "AVRGenAsmMatcher.inc"
+
+// Uses enums defined in AVRGenAsmMatcher.inc
+unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
+ unsigned ExpectedKind) {
+ AVROperand &Op = static_cast<AVROperand &>(AsmOp);
+ MatchClassKind Expected = static_cast<MatchClassKind>(ExpectedKind);
+
+ // If need be, GCC converts bare numbers to register names
+ // It's ugly, but GCC supports it.
+ if (Op.isImm()) {
+ if (MCConstantExpr const *Const = dyn_cast<MCConstantExpr>(Op.getImm())) {
+ int64_t RegNum = Const->getValue();
+ std::ostringstream RegName;
+ RegName << "r" << RegNum;
+ RegNum = MatchRegisterName(RegName.str().c_str());
+ if (RegNum != AVR::NoRegister) {
+ Op.makeReg(RegNum);
+ if (validateOperandClass(Op, Expected) == Match_Success) {
+ return Match_Success;
+ }
+ }
+ // Let the other quirks try their magic.
+ }
+ }
+
+ if (Op.isReg()) {
+ // If the instruction uses a register pair but we got a single, lower
+ // register we perform a "class cast".
+ if (isSubclass(Expected, MCK_DREGS)) {
+ unsigned correspondingDREG = toDREG(Op.getReg());
+
+ if (correspondingDREG != AVR::NoRegister) {
+ Op.makeReg(correspondingDREG);
+ return validateOperandClass(Op, Expected);
+ }
+ }
+ }
+ return Match_InvalidOperand;
+}
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp b/contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp
new file mode 100644
index 0000000..d2a21fb
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp
@@ -0,0 +1,156 @@
+//===- AVRDisassembler.cpp - Disassembler for AVR ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the AVR Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRRegisterInfo.h"
+#include "AVRSubtarget.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "avr-disassembler"
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+
+/// A disassembler class for AVR.
+class AVRDisassembler : public MCDisassembler {
+public:
+ AVRDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+ virtual ~AVRDisassembler() {}
+
+ DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+}
+
+static MCDisassembler *createAVRDisassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new AVRDisassembler(STI, Ctx);
+}
+
+
+extern "C" void LLVMInitializeAVRDisassembler() {
+ // Register the disassembler.
+ TargetRegistry::RegisterMCDisassembler(getTheAVRTarget(),
+ createAVRDisassembler);
+}
+
+static DecodeStatus DecodeGPR8RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeLD8RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodePTRREGSRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return MCDisassembler::Success;
+}
+
+#include "AVRGenDisassemblerTables.inc"
+
+static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint32_t &Insn) {
+ if (Bytes.size() < 2) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ Size = 2;
+ Insn = (Bytes[0] << 0) | (Bytes[1] << 8);
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint32_t &Insn) {
+
+ if (Bytes.size() < 4) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ Size = 4;
+ Insn = (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) | (Bytes[3] << 24);
+
+ return MCDisassembler::Success;
+}
+
+static const uint8_t *getDecoderTable(uint64_t Size) {
+
+ switch (Size) {
+ case 2: return DecoderTable16;
+ case 4: return DecoderTable32;
+ default: llvm_unreachable("instructions must be 16 or 32-bits");
+ }
+}
+
+DecodeStatus AVRDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint32_t Insn;
+
+ DecodeStatus Result;
+
+ // Try decode a 16-bit instruction.
+ {
+ Result = readInstruction16(Bytes, Address, Size, Insn);
+
+ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
+
+ // Try to auto-decode a 16-bit instruction.
+ Result = decodeInstruction(getDecoderTable(Size), Instr,
+ Insn, Address, this, STI);
+
+ if (Result != MCDisassembler::Fail)
+ return Result;
+ }
+
+ // Try decode a 32-bit instruction.
+ {
+ Result = readInstruction32(Bytes, Address, Size, Insn);
+
+ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
+
+ Result = decodeInstruction(getDecoderTable(Size), Instr, Insn,
+ Address, this, STI);
+
+ if (Result != MCDisassembler::Fail) {
+ return Result;
+ }
+
+ return MCDisassembler::Fail;
+ }
+}
+
+typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder);
+
diff --git a/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp
new file mode 100644
index 0000000..316b783
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp
@@ -0,0 +1,171 @@
+//===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly syntax --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an AVR MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRInstPrinter.h"
+
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+
+#include <cstring>
+
+#define DEBUG_TYPE "asm-printer"
+
+namespace llvm {
+
+// Include the auto-generated portion of the assembly writer.
+#define PRINT_ALIAS_INSTR
+#include "AVRGenAsmWriter.inc"
+
+void AVRInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
+ StringRef Annot, const MCSubtargetInfo &STI) {
+ unsigned Opcode = MI->getOpcode();
+
+ // First handle load and store instructions with postinc or predec
+ // of the form "ld reg, X+".
+ // TODO: We should be able to rewrite this using TableGen data.
+ switch (Opcode) {
+ case AVR::LDRdPtr:
+ case AVR::LDRdPtrPi:
+ case AVR::LDRdPtrPd:
+ O << "\tld\t";
+ printOperand(MI, 0, O);
+ O << ", ";
+
+ if (Opcode == AVR::LDRdPtrPd)
+ O << '-';
+
+ printOperand(MI, 1, O);
+
+ if (Opcode == AVR::LDRdPtrPi)
+ O << '+';
+ break;
+ case AVR::STPtrRr:
+ O << "\tst\t";
+ printOperand(MI, 0, O);
+ O << ", ";
+ printOperand(MI, 1, O);
+ break;
+ case AVR::STPtrPiRr:
+ case AVR::STPtrPdRr:
+ O << "\tst\t";
+
+ if (Opcode == AVR::STPtrPdRr)
+ O << '-';
+
+ printOperand(MI, 1, O);
+
+ if (Opcode == AVR::STPtrPiRr)
+ O << '+';
+
+ O << ", ";
+ printOperand(MI, 2, O);
+ break;
+ default:
+ if (!printAliasInstr(MI, O))
+ printInstruction(MI, O);
+
+ printAnnotation(O, Annot);
+ break;
+ }
+}
+
+const char *AVRInstPrinter::getPrettyRegisterName(unsigned RegNum,
+ MCRegisterInfo const &MRI) {
+ // GCC prints register pairs by just printing the lower register
+ // If the register contains a subregister, print it instead
+ if (MRI.getNumSubRegIndices() > 0) {
+ unsigned RegLoNum = MRI.getSubReg(RegNum, AVR::sub_lo);
+ RegNum = (RegLoNum != AVR::NoRegister) ? RegLoNum : RegNum;
+ }
+
+ return getRegisterName(RegNum);
+}
+
+void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).OpInfo[OpNo];
+
+ if (Op.isReg()) {
+ bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
+ (MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
+ (MOI.RegClass == AVR::ZREGSRegClassID);
+
+ if (isPtrReg) {
+ O << getRegisterName(Op.getReg(), AVR::ptr);
+ } else {
+ O << getPrettyRegisterName(Op.getReg(), MRI);
+ }
+ } else if (Op.isImm()) {
+ O << Op.getImm();
+ } else {
+ assert(Op.isExpr() && "Unknown operand kind in printOperand");
+ O << *Op.getExpr();
+ }
+}
+
+/// This is used to print an immediate value that ends up
+/// being encoded as a pc-relative value.
+void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+
+ if (Op.isImm()) {
+ int64_t Imm = Op.getImm();
+ O << '.';
+
+ // Print a position sign if needed.
+ // Negative values have their sign printed automatically.
+ if (Imm >= 0)
+ O << '+';
+
+ O << Imm;
+ } else {
+ assert(Op.isExpr() && "Unknown pcrel immediate operand");
+ O << *Op.getExpr();
+ }
+}
+
+void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ assert(MI->getOperand(OpNo).isReg() && "Expected a register for the first operand");
+
+ const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
+
+ // Print the register.
+ printOperand(MI, OpNo, O);
+
+ // Print the {+,-}offset.
+ if (OffsetOp.isImm()) {
+ int64_t Offset = OffsetOp.getImm();
+
+ if (Offset >= 0)
+ O << '+';
+
+ O << Offset;
+ } else if (OffsetOp.isExpr()) {
+ O << *OffsetOp.getExpr();
+ } else {
+ llvm_unreachable("unknown type for offset");
+ }
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h
new file mode 100644
index 0000000..c9f65b9
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h
@@ -0,0 +1,54 @@
+//===- AVRInstPrinter.h - Convert AVR MCInst to assembly syntax -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an AVR MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_INST_PRINTER_H
+#define LLVM_AVR_INST_PRINTER_H
+
+#include "llvm/MC/MCInstPrinter.h"
+
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+namespace llvm {
+
+/// Prints AVR instructions to a textual stream.
+class AVRInstPrinter : public MCInstPrinter {
+public:
+ AVRInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI)
+ : MCInstPrinter(MAI, MII, MRI) {}
+
+ static const char *getPrettyRegisterName(unsigned RegNo,
+ MCRegisterInfo const &MRI);
+
+ void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
+ const MCSubtargetInfo &STI) override;
+
+private:
+ static const char *getRegisterName(unsigned RegNo,
+ unsigned AltIdx = AVR::NoRegAltName);
+
+ void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printPCRelImm(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printMemri(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+
+ // Autogenerated by TableGen.
+ void printInstruction(const MCInst *MI, raw_ostream &O);
+ bool printAliasInstr(const MCInst *MI, raw_ostream &O);
+ void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
+ unsigned PrintMethodIdx, raw_ostream &O);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_INST_PRINTER_H
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
new file mode 100644
index 0000000..081d8b5
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
@@ -0,0 +1,473 @@
+//===-- AVRAsmBackend.cpp - AVR Asm Backend ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AVRAsmBackend class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AVRAsmBackend.h"
+#include "MCTargetDesc/AVRFixupKinds.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+// FIXME: we should be doing checks to make sure asm operands
+// are not out of bounds.
+
+namespace adjust {
+
+using namespace llvm;
+
+void signed_width(unsigned Width, uint64_t Value, std::string Description,
+ const MCFixup &Fixup, MCContext *Ctx = nullptr) {
+ if (!isIntN(Width, Value)) {
+ std::string Diagnostic = "out of range " + Description;
+
+ int64_t Min = minIntN(Width);
+ int64_t Max = maxIntN(Width);
+
+ Diagnostic += " (expected an integer in the range " + std::to_string(Min) +
+ " to " + std::to_string(Max) + ")";
+
+ if (Ctx) {
+ Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
+ } else {
+ llvm_unreachable(Diagnostic.c_str());
+ }
+ }
+}
+
+void unsigned_width(unsigned Width, uint64_t Value, std::string Description,
+ const MCFixup &Fixup, MCContext *Ctx = nullptr) {
+ if (!isUIntN(Width, Value)) {
+ std::string Diagnostic = "out of range " + Description;
+
+ int64_t Max = maxUIntN(Width);
+
+ Diagnostic += " (expected an integer in the range 0 to " +
+ std::to_string(Max) + ")";
+
+ if (Ctx) {
+ Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
+ } else {
+ llvm_unreachable(Diagnostic.c_str());
+ }
+ }
+}
+
+/// Adjusts the value of a branch target before fixup application.
+void adjustBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ // We have one extra bit of precision because the value is rightshifted by
+ // one.
+ unsigned_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
+
+ // Rightshifts the value by one.
+ AVR::fixups::adjustBranchTarget(Value);
+}
+
+/// Adjusts the value of a relative branch target before fixup application.
+void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ // We have one extra bit of precision because the value is rightshifted by
+ // one.
+ signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
+
+ Value -= 2;
+
+ // Rightshifts the value by one.
+ AVR::fixups::adjustBranchTarget(Value);
+}
+
+/// 22-bit absolute fixup.
+///
+/// Resolves to:
+/// 1001 kkkk 010k kkkk kkkk kkkk 111k kkkk
+///
+/// Offset of 0 (so the result is left shifted by 3 bits before application).
+void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ adjustBranch(Size, Fixup, Value, Ctx);
+
+ auto top = Value & (0xf00000 << 6); // the top four bits
+ auto middle = Value & (0x1ffff << 5); // the middle 13 bits
+ auto bottom = Value & 0x1f; // end bottom 5 bits
+
+ Value = (top << 6) | (middle << 3) | (bottom << 0);
+}
+
+/// 7-bit PC-relative fixup.
+///
+/// Resolves to:
+/// 0000 00kk kkkk k000
+/// Offset of 0 (so the result is left shifted by 3 bits before application).
+void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ adjustRelativeBranch(Size, Fixup, Value, Ctx);
+
+ // Because the value may be negative, we must mask out the sign bits
+ Value &= 0x7f;
+}
+
+/// 12-bit PC-relative fixup.
+/// Yes, the fixup is 12 bits even though the name says otherwise.
+///
+/// Resolves to:
+/// 0000 kkkk kkkk kkkk
+/// Offset of 0 (so the result isn't left-shifted before application).
+void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ adjustRelativeBranch(Size, Fixup, Value, Ctx);
+
+ // Because the value may be negative, we must mask out the sign bits
+ Value &= 0xfff;
+}
+
+/// 6-bit fixup for the immediate operand of the ADIW family of
+/// instructions.
+///
+/// Resolves to:
+/// 0000 0000 kk00 kkkk
+void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
+
+ Value = ((Value & 0x30) << 2) | (Value & 0x0f);
+}
+
+/// 5-bit port number fixup on the SBIC family of instructions.
+///
+/// Resolves to:
+/// 0000 0000 AAAA A000
+void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ unsigned_width(5, Value, std::string("port number"), Fixup, Ctx);
+
+ Value &= 0x1f;
+
+ Value <<= 3;
+}
+
+/// 6-bit port number fixup on the `IN` family of instructions.
+///
+/// Resolves to:
+/// 1011 0AAd dddd AAAA
+void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ unsigned_width(6, Value, std::string("port number"), Fixup, Ctx);
+
+ Value = ((Value & 0x30) << 5) | (Value & 0x0f);
+}
+
+/// Adjusts a program memory address.
+/// This is a simple right-shift.
+void pm(uint64_t &Value) {
+ Value >>= 1;
+}
+
+/// Fixups relating to the LDI instruction.
+namespace ldi {
+
+/// Adjusts a value to fix up the immediate of an `LDI Rd, K` instruction.
+///
+/// Resolves to:
+/// 0000 KKKK 0000 KKKK
+/// Offset of 0 (so the result isn't left-shifted before application).
+void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ uint64_t upper = Value & 0xf0;
+ uint64_t lower = Value & 0x0f;
+
+ Value = (upper << 4) | lower;
+}
+
+void neg(uint64_t &Value) { Value *= -1; }
+
+void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value &= 0xff;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value = (Value & 0xff00) >> 8;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value = (Value & 0xff0000) >> 16;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value = (Value & 0xff000000) >> 24;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+} // end of ldi namespace
+} // end of adjust namespace
+
+namespace llvm {
+
+// Prepare value for the target space for it
+void AVRAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx) const {
+ // The size of the fixup in bits.
+ uint64_t Size = AVRAsmBackend::getFixupKindInfo(Fixup.getKind()).TargetSize;
+
+ unsigned Kind = Fixup.getKind();
+
+ switch (Kind) {
+ default:
+ llvm_unreachable("unhandled fixup");
+ case AVR::fixup_7_pcrel:
+ adjust::fixup_7_pcrel(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_13_pcrel:
+ adjust::fixup_13_pcrel(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_call:
+ adjust::fixup_call(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_ldi:
+ adjust::ldi::fixup(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_lo8_ldi:
+ case AVR::fixup_lo8_ldi_pm:
+ if (Kind == AVR::fixup_lo8_ldi_pm) adjust::pm(Value);
+
+ adjust::ldi::lo8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hi8_ldi:
+ case AVR::fixup_hi8_ldi_pm:
+ if (Kind == AVR::fixup_hi8_ldi_pm) adjust::pm(Value);
+
+ adjust::ldi::hi8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hh8_ldi:
+ case AVR::fixup_hh8_ldi_pm:
+ if (Kind == AVR::fixup_hh8_ldi_pm) adjust::pm(Value);
+
+ adjust::ldi::hh8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_ms8_ldi:
+ adjust::ldi::ms8(Size, Fixup, Value, Ctx);
+ break;
+
+ case AVR::fixup_lo8_ldi_neg:
+ case AVR::fixup_lo8_ldi_pm_neg:
+ if (Kind == AVR::fixup_lo8_ldi_pm_neg) adjust::pm(Value);
+
+ adjust::ldi::neg(Value);
+ adjust::ldi::lo8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hi8_ldi_neg:
+ case AVR::fixup_hi8_ldi_pm_neg:
+ if (Kind == AVR::fixup_hi8_ldi_pm_neg) adjust::pm(Value);
+
+ adjust::ldi::neg(Value);
+ adjust::ldi::hi8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hh8_ldi_neg:
+ case AVR::fixup_hh8_ldi_pm_neg:
+ if (Kind == AVR::fixup_hh8_ldi_pm_neg) adjust::pm(Value);
+
+ adjust::ldi::neg(Value);
+ adjust::ldi::hh8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_ms8_ldi_neg:
+ adjust::ldi::neg(Value);
+ adjust::ldi::ms8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_16:
+ adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
+
+ Value &= 0xffff;
+ break;
+ case AVR::fixup_6_adiw:
+ adjust::fixup_6_adiw(Fixup, Value, Ctx);
+ break;
+
+ case AVR::fixup_port5:
+ adjust::fixup_port5(Fixup, Value, Ctx);
+ break;
+
+ case AVR::fixup_port6:
+ adjust::fixup_port6(Fixup, Value, Ctx);
+ break;
+
+ // Fixups which do not require adjustments.
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ break;
+
+ case FK_GPRel_4:
+ llvm_unreachable("don't know how to adjust this fixup");
+ break;
+ }
+}
+
+MCObjectWriter *AVRAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
+ return createAVRELFObjectWriter(OS,
+ MCELFObjectTargetWriter::getOSABI(OSType));
+}
+
+void AVRAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
+ unsigned DataSize, uint64_t Value,
+ bool IsPCRel) const {
+ if (Value == 0)
+ return; // Doesn't change encoding.
+
+ MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
+
+ // The number of bits in the fixup mask
+ auto NumBits = Info.TargetSize + Info.TargetOffset;
+ auto NumBytes = (NumBits / 8) + ((NumBits % 8) == 0 ? 0 : 1);
+
+ // Shift the value into position.
+ Value <<= Info.TargetOffset;
+
+ unsigned Offset = Fixup.getOffset();
+ assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
+
+ // For each byte of the fragment that the fixup touches, mask in the
+ // bits from the fixup value.
+ for (unsigned i = 0; i < NumBytes; ++i) {
+ uint8_t mask = (((Value >> (i * 8)) & 0xff));
+ Data[Offset + i] |= mask;
+ }
+}
+
+MCFixupKindInfo const &AVRAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
+ // NOTE: Many AVR fixups work on sets of non-contignous bits. We work around
+ // this by saying that the fixup is the size of the entire instruction.
+ const static MCFixupKindInfo Infos[AVR::NumTargetFixupKinds] = {
+ // This table *must* be in same the order of fixup_* kinds in
+ // AVRFixupKinds.h.
+ //
+ // name offset bits flags
+ {"fixup_32", 0, 32, 0},
+
+ {"fixup_7_pcrel", 3, 7, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_13_pcrel", 0, 12, MCFixupKindInfo::FKF_IsPCRel},
+
+ {"fixup_16", 0, 16, 0},
+ {"fixup_16_pm", 0, 16, 0},
+
+ {"fixup_ldi", 0, 8, 0},
+
+ {"fixup_lo8_ldi", 0, 8, 0},
+ {"fixup_hi8_ldi", 0, 8, 0},
+ {"fixup_hh8_ldi", 0, 8, 0},
+ {"fixup_ms8_ldi", 0, 8, 0},
+
+ {"fixup_lo8_ldi_neg", 0, 8, 0},
+ {"fixup_hi8_ldi_neg", 0, 8, 0},
+ {"fixup_hh8_ldi_neg", 0, 8, 0},
+ {"fixup_ms8_ldi_neg", 0, 8, 0},
+
+ {"fixup_lo8_ldi_pm", 0, 8, 0},
+ {"fixup_hi8_ldi_pm", 0, 8, 0},
+ {"fixup_hh8_ldi_pm", 0, 8, 0},
+
+ {"fixup_lo8_ldi_pm_neg", 0, 8, 0},
+ {"fixup_hi8_ldi_pm_neg", 0, 8, 0},
+ {"fixup_hh8_ldi_pm_neg", 0, 8, 0},
+
+ {"fixup_call", 0, 22, 0},
+
+ {"fixup_6", 0, 16, 0}, // non-contiguous
+ {"fixup_6_adiw", 0, 6, 0},
+
+ {"fixup_lo8_ldi_gs", 0, 8, 0},
+ {"fixup_hi8_ldi_gs", 0, 8, 0},
+
+ {"fixup_8", 0, 8, 0},
+ {"fixup_8_lo8", 0, 8, 0},
+ {"fixup_8_hi8", 0, 8, 0},
+ {"fixup_8_hlo8", 0, 8, 0},
+
+ {"fixup_sym_diff", 0, 32, 0},
+ {"fixup_16_ldst", 0, 16, 0},
+
+ {"fixup_lds_sts_16", 0, 16, 0},
+
+ {"fixup_port6", 0, 16, 0}, // non-contiguous
+ {"fixup_port5", 3, 5, 0},
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+
+ return Infos[Kind - FirstTargetFixupKind];
+}
+
+bool AVRAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
+ // If the count is not 2-byte aligned, we must be writing data into the text
+ // section (otherwise we have unaligned instructions, and thus have far
+ // bigger problems), so just write zeros instead.
+ assert((Count % 2) == 0 && "NOP instructions must be 2 bytes");
+
+ OW->WriteZeros(Count);
+ return true;
+}
+
+void AVRAsmBackend::processFixupValue(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup,
+ const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) {
+ switch ((unsigned) Fixup.getKind()) {
+ // Fixups which should always be recorded as relocations.
+ case AVR::fixup_7_pcrel:
+ case AVR::fixup_13_pcrel:
+ case AVR::fixup_call:
+ IsResolved = false;
+ break;
+ default:
+ // Parsed LLVM-generated temporary labels are already
+ // adjusted for instruction size, but normal labels aren't.
+ //
+ // To handle both cases, we simply un-adjust the temporary label
+ // case so it acts like all other labels.
+ if (Target.getSymA()->getSymbol().isTemporary())
+ Value += 2;
+
+ adjustFixupValue(Fixup, Value, &Asm.getContext());
+ break;
+ }
+}
+
+MCAsmBackend *createAVRAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+ const Triple &TT, StringRef CPU,
+ const llvm::MCTargetOptions &TO) {
+ return new AVRAsmBackend(TT.getOS());
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h
new file mode 100644
index 0000000..7ff4b8f
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h
@@ -0,0 +1,78 @@
+//===-- AVRAsmBackend.h - AVR Asm Backend --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// \file The AVR assembly backend implementation.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#ifndef LLVM_AVR_ASM_BACKEND_H
+#define LLVM_AVR_ASM_BACKEND_H
+
+#include "MCTargetDesc/AVRFixupKinds.h"
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmBackend.h"
+
+namespace llvm {
+
+class MCAssembler;
+class MCObjectWriter;
+class Target;
+
+struct MCFixupKindInfo;
+
+/// Utilities for manipulating generated AVR machine code.
+class AVRAsmBackend : public MCAsmBackend {
+public:
+
+ AVRAsmBackend(Triple::OSType OSType)
+ : MCAsmBackend(), OSType(OSType) {}
+
+ void adjustFixupValue(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) const;
+
+ MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
+
+ void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
+ uint64_t Value, bool IsPCRel) const override;
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
+
+ unsigned getNumFixupKinds() const override {
+ return AVR::NumTargetFixupKinds;
+ }
+
+ bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
+
+ bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override {
+ llvm_unreachable("RelaxInstruction() unimplemented");
+ return false;
+ }
+
+ void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
+ MCInst &Res) const override {}
+
+ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
+
+ void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) override;
+
+private:
+ Triple::OSType OSType;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_ASM_BACKEND_H
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
new file mode 100644
index 0000000..161f305
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
@@ -0,0 +1,127 @@
+//===-- AVRELFObjectWriter.cpp - AVR ELF Writer ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AVRFixupKinds.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+
+/// Writes AVR machine code into an ELF32 object file.
+class AVRELFObjectWriter : public MCELFObjectTargetWriter {
+public:
+ AVRELFObjectWriter(uint8_t OSABI);
+
+ virtual ~AVRELFObjectWriter() {}
+
+ unsigned getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const override;
+};
+
+AVRELFObjectWriter::AVRELFObjectWriter(uint8_t OSABI)
+ : MCELFObjectTargetWriter(false, OSABI, ELF::EM_AVR, true, false) {}
+
+unsigned AVRELFObjectWriter::getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
+ switch ((unsigned) Fixup.getKind()) {
+ case FK_Data_1:
+ case FK_Data_4:
+ llvm_unreachable("unsupported relocation type");
+ case FK_Data_2:
+ return ELF::R_AVR_16_PM;
+ case AVR::fixup_32:
+ return ELF::R_AVR_32;
+ case AVR::fixup_7_pcrel:
+ return ELF::R_AVR_7_PCREL;
+ case AVR::fixup_13_pcrel:
+ return ELF::R_AVR_13_PCREL;
+ case AVR::fixup_16:
+ return ELF::R_AVR_16;
+ case AVR::fixup_16_pm:
+ return ELF::R_AVR_16_PM;
+ case AVR::fixup_lo8_ldi:
+ return ELF::R_AVR_LO8_LDI;
+ case AVR::fixup_hi8_ldi:
+ return ELF::R_AVR_HI8_LDI;
+ case AVR::fixup_hh8_ldi:
+ return ELF::R_AVR_HH8_LDI;
+ case AVR::fixup_lo8_ldi_neg:
+ return ELF::R_AVR_LO8_LDI_NEG;
+ case AVR::fixup_hi8_ldi_neg:
+ return ELF::R_AVR_HI8_LDI_NEG;
+ case AVR::fixup_hh8_ldi_neg:
+ return ELF::R_AVR_HH8_LDI_NEG;
+ case AVR::fixup_lo8_ldi_pm:
+ return ELF::R_AVR_LO8_LDI_PM;
+ case AVR::fixup_hi8_ldi_pm:
+ return ELF::R_AVR_HI8_LDI_PM;
+ case AVR::fixup_hh8_ldi_pm:
+ return ELF::R_AVR_HH8_LDI_PM;
+ case AVR::fixup_lo8_ldi_pm_neg:
+ return ELF::R_AVR_LO8_LDI_PM_NEG;
+ case AVR::fixup_hi8_ldi_pm_neg:
+ return ELF::R_AVR_HI8_LDI_PM_NEG;
+ case AVR::fixup_hh8_ldi_pm_neg:
+ return ELF::R_AVR_HH8_LDI_PM_NEG;
+ case AVR::fixup_call:
+ return ELF::R_AVR_CALL;
+ case AVR::fixup_ldi:
+ return ELF::R_AVR_LDI;
+ case AVR::fixup_6:
+ return ELF::R_AVR_6;
+ case AVR::fixup_6_adiw:
+ return ELF::R_AVR_6_ADIW;
+ case AVR::fixup_ms8_ldi:
+ return ELF::R_AVR_MS8_LDI;
+ case AVR::fixup_ms8_ldi_neg:
+ return ELF::R_AVR_MS8_LDI_NEG;
+ case AVR::fixup_lo8_ldi_gs:
+ return ELF::R_AVR_LO8_LDI_GS;
+ case AVR::fixup_hi8_ldi_gs:
+ return ELF::R_AVR_HI8_LDI_GS;
+ case AVR::fixup_8:
+ return ELF::R_AVR_8;
+ case AVR::fixup_8_lo8:
+ return ELF::R_AVR_8_LO8;
+ case AVR::fixup_8_hi8:
+ return ELF::R_AVR_8_HI8;
+ case AVR::fixup_8_hlo8:
+ return ELF::R_AVR_8_HLO8;
+ case AVR::fixup_sym_diff:
+ return ELF::R_AVR_SYM_DIFF;
+ case AVR::fixup_16_ldst:
+ return ELF::R_AVR_16_LDST;
+ case AVR::fixup_lds_sts_16:
+ return ELF::R_AVR_LDS_STS_16;
+ case AVR::fixup_port6:
+ return ELF::R_AVR_PORT6;
+ case AVR::fixup_port5:
+ return ELF::R_AVR_PORT5;
+ default:
+ llvm_unreachable("invalid fixup kind!");
+ }
+}
+
+MCObjectWriter *createAVRELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI) {
+ MCELFObjectTargetWriter *MOTW = new AVRELFObjectWriter(OSABI);
+ return createELFObjectWriter(MOTW, OS, true);
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h
new file mode 100644
index 0000000..d3bd52d
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h
@@ -0,0 +1,149 @@
+//===-- AVRFixupKinds.h - AVR Specific Fixup Entries ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_FIXUP_KINDS_H
+#define LLVM_AVR_FIXUP_KINDS_H
+
+#include "llvm/MC/MCFixup.h"
+
+namespace llvm {
+namespace AVR {
+
+/// The set of supported fixups.
+///
+/// Although most of the current fixup types reflect a unique relocation
+/// one can have multiple fixup types for a given relocation and thus need
+/// to be uniquely named.
+///
+/// \note This table *must* be in the same order of
+/// MCFixupKindInfo Infos[AVR::NumTargetFixupKinds]
+/// in `AVRAsmBackend.cpp`.
+enum Fixups {
+ /// A 32-bit AVR fixup.
+ fixup_32 = FirstTargetFixupKind,
+
+ /// A 7-bit PC-relative fixup for the family of conditional
+ /// branches which take 7-bit targets (BRNE,BRGT,etc).
+ fixup_7_pcrel,
+ /// A 12-bit PC-relative fixup for the family of branches
+ /// which take 12-bit targets (RJMP,RCALL,etc).
+ /// \note Although the fixup is labelled as 13 bits, it
+ /// is actually only encoded in 12. The reason for
+ /// The nonmenclature is that AVR branch targets are
+ /// rightshifted by 1, because instructions are always
+ /// aligned to 2 bytes, so the 0'th bit is always 0.
+ /// This way there is 13-bits of precision.
+ fixup_13_pcrel,
+
+ /// A 16-bit address.
+ fixup_16,
+ /// A 16-bit program memory address.
+ fixup_16_pm,
+
+ /// Replaces the 8-bit immediate with another value.
+ fixup_ldi,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a 16-bit value (bits 0-7).
+ fixup_lo8_ldi,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 16-bit value (bits 8-15).
+ fixup_hi8_ldi,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 24-bit value (bits 16-23).
+ fixup_hh8_ldi,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 32-bit value (bits 24-31).
+ fixup_ms8_ldi,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a negated 16-bit value (bits 0-7).
+ fixup_lo8_ldi_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated 16-bit value (bits 8-15).
+ fixup_hi8_ldi_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated negated 24-bit value (bits 16-23).
+ fixup_hh8_ldi_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated negated 32-bit value (bits 24-31).
+ fixup_ms8_ldi_neg,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a 16-bit program memory address value (bits 0-7).
+ fixup_lo8_ldi_pm,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 16-bit program memory address value (bits
+ /// 8-15).
+ fixup_hi8_ldi_pm,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 24-bit program memory address value (bits
+ /// 16-23).
+ fixup_hh8_ldi_pm,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a negated 16-bit program memory address value
+ /// (bits 0-7).
+ fixup_lo8_ldi_pm_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated 16-bit program memory address value
+ /// (bits 8-15).
+ fixup_hi8_ldi_pm_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated 24-bit program memory address value
+ /// (bits 16-23).
+ fixup_hh8_ldi_pm_neg,
+
+ /// A 22-bit fixup for the target of a `CALL k` or `JMP k` instruction.
+ fixup_call,
+
+ fixup_6,
+ /// A symbol+addr fixup for the `LDD <x>+<n>, <r>" family of instructions.
+ fixup_6_adiw,
+
+ fixup_lo8_ldi_gs,
+ fixup_hi8_ldi_gs,
+
+ fixup_8,
+ fixup_8_lo8,
+ fixup_8_hi8,
+ fixup_8_hlo8,
+
+ /// Fixup to calculate the difference between two symbols.
+ /// Is the only stateful fixup. We do not support it yet.
+ fixup_sym_diff,
+ fixup_16_ldst,
+
+ fixup_lds_sts_16,
+
+ /// A 6-bit port address.
+ fixup_port6,
+ /// A 5-bit port address.
+ fixup_port5,
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+};
+
+namespace fixups {
+
+/// Adjusts the value of a branch target.
+/// All branch targets in AVR are rightshifted by 1 to take advantage
+/// of the fact that all instructions are aligned to addresses of size
+/// 2, so bit 0 of an address is always 0. This gives us another bit
+/// of precision.
+/// \param[in,out] The target to adjust.
+template <typename T> inline void adjustBranchTarget(T &val) { val >>= 1; }
+
+} // end of namespace fixups
+}
+} // end of namespace llvm::AVR
+
+#endif // LLVM_AVR_FIXUP_KINDS_H
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
new file mode 100644
index 0000000..e6dc886
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
@@ -0,0 +1,304 @@
+//===-- AVRMCCodeEmitter.cpp - Convert AVR Code to Machine Code -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AVRMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRMCCodeEmitter.h"
+
+#include "MCTargetDesc/AVRMCExpr.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "mccodeemitter"
+
+#define GET_INSTRMAP_INFO
+#include "AVRGenInstrInfo.inc"
+#undef GET_INSTRMAP_INFO
+
+namespace llvm {
+
+/// Performs a post-encoding step on a `LD` or `ST` instruction.
+///
+/// The encoding of the LD/ST family of instructions is inconsistent w.r.t
+/// the pointer register and the addressing mode.
+///
+/// The permutations of the format are as followed:
+/// ld Rd, X `1001 000d dddd 1100`
+/// ld Rd, X+ `1001 000d dddd 1101`
+/// ld Rd, -X `1001 000d dddd 1110`
+///
+/// ld Rd, Y `1000 000d dddd 1000`
+/// ld Rd, Y+ `1001 000d dddd 1001`
+/// ld Rd, -Y `1001 000d dddd 1010`
+///
+/// ld Rd, Z `1000 000d dddd 0000`
+/// ld Rd, Z+ `1001 000d dddd 0001`
+/// ld Rd, -Z `1001 000d dddd 0010`
+/// ^
+/// |
+/// Note this one inconsistent bit - it is 1 sometimes and 0 at other times.
+/// There is no logical pattern. Looking at a truth table, the following
+/// formula can be derived to fit the pattern:
+//
+/// ```
+/// inconsistent_bit = is_predec OR is_postinc OR is_reg_x
+/// ```
+//
+/// We manually set this bit in this post encoder method.
+unsigned
+AVRMCCodeEmitter::loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue,
+ const MCSubtargetInfo &STI) const {
+
+ assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() &&
+ "the load/store operands must be registers");
+
+ unsigned Opcode = MI.getOpcode();
+
+ // check whether either of the registers are the X pointer register.
+ bool IsRegX = MI.getOperand(0).getReg() == AVR::R27R26 ||
+ MI.getOperand(1).getReg() == AVR::R27R26;
+
+ bool IsPredec = Opcode == AVR::LDRdPtrPd || Opcode == AVR::STPtrPdRr;
+ bool IsPostinc = Opcode == AVR::LDRdPtrPi || Opcode == AVR::STPtrPiRr;
+
+ // Check if we need to set the inconsistent bit
+ if (IsRegX || IsPredec || IsPostinc) {
+ EncodedValue |= (1 << 12);
+ }
+
+ return EncodedValue;
+}
+
+template <AVR::Fixups Fixup>
+unsigned
+AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+
+ if (MO.isExpr()) {
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(),
+ MCFixupKind(Fixup), MI.getLoc()));
+ return 0;
+ }
+
+ assert(MO.isImm());
+
+ // Take the size of the current instruction away.
+ // With labels, this is implicitly done.
+ auto target = MO.getImm();
+ AVR::fixups::adjustBranchTarget(target);
+ return target;
+}
+
+unsigned AVRMCCodeEmitter::encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto MO = MI.getOperand(OpNo);
+
+ // The operand should be a pointer register.
+ assert(MO.isReg());
+
+ switch (MO.getReg()) {
+ case AVR::R27R26: return 0x03; // X: 0b11
+ case AVR::R29R28: return 0x02; // Y: 0b10
+ case AVR::R31R30: return 0x00; // Z: 0b00
+ default:
+ llvm_unreachable("invalid pointer register");
+ }
+}
+
+/// Encodes a `memri` operand.
+/// The operand is 7-bits.
+/// * The lower 6 bits is the immediate
+/// * The upper bit is the pointer register bit (Z=0,Y=1)
+unsigned AVRMCCodeEmitter::encodeMemri(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto RegOp = MI.getOperand(OpNo);
+ auto OffsetOp = MI.getOperand(OpNo + 1);
+
+ assert(RegOp.isReg() && "Expected register operand");
+
+ uint8_t RegBit = 0;
+
+ switch (RegOp.getReg()) {
+ default:
+ llvm_unreachable("Expected either Y or Z register");
+ case AVR::R31R30:
+ RegBit = 0;
+ break; // Z register
+ case AVR::R29R28:
+ RegBit = 1;
+ break; // Y register
+ }
+
+ int8_t OffsetBits;
+
+ if (OffsetOp.isImm()) {
+ OffsetBits = OffsetOp.getImm();
+ } else if (OffsetOp.isExpr()) {
+ OffsetBits = 0;
+ Fixups.push_back(MCFixup::create(0, OffsetOp.getExpr(),
+ MCFixupKind(AVR::fixup_6), MI.getLoc()));
+ } else {
+ llvm_unreachable("invalid value for offset");
+ }
+
+ return (RegBit << 6) | OffsetBits;
+}
+
+unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ // The operand should be an immediate.
+ assert(MI.getOperand(OpNo).isImm());
+
+ auto Imm = MI.getOperand(OpNo).getImm();
+ return (~0) - Imm;
+}
+
+template <AVR::Fixups Fixup>
+unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto MO = MI.getOperand(OpNo);
+
+ if (MO.isExpr()) {
+ if (isa<AVRMCExpr>(MO.getExpr())) {
+ // If the expression is already an AVRMCExpr (i.e. a lo8(symbol),
+ // we shouldn't perform any more fixups. Without this check, we would
+ // instead create a fixup to the symbol named 'lo8(symbol)' which
+ // is not correct.
+ return getExprOpValue(MO.getExpr(), Fixups, STI);
+ }
+
+ MCFixupKind FixupKind = static_cast<MCFixupKind>(Fixup);
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc()));
+
+ return 0;
+ }
+
+ assert(MO.isImm());
+ return MO.getImm();
+}
+
+unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto MO = MI.getOperand(OpNo);
+
+ if (MO.isExpr()) {
+ MCFixupKind FixupKind = static_cast<MCFixupKind>(AVR::fixup_call);
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc()));
+ return 0;
+ }
+
+ assert(MO.isImm());
+
+ auto Target = MO.getImm();
+ AVR::fixups::adjustBranchTarget(Target);
+ return Target;
+}
+
+unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+
+ MCExpr::ExprKind Kind = Expr->getKind();
+
+ if (Kind == MCExpr::Binary) {
+ Expr = static_cast<const MCBinaryExpr *>(Expr)->getLHS();
+ Kind = Expr->getKind();
+ }
+
+ if (Kind == MCExpr::Target) {
+ AVRMCExpr const *AVRExpr = cast<AVRMCExpr>(Expr);
+ int64_t Result;
+ if (AVRExpr->evaluateAsConstant(Result)) {
+ return Result;
+ }
+
+ MCFixupKind FixupKind = static_cast<MCFixupKind>(AVRExpr->getFixupKind());
+ Fixups.push_back(MCFixup::create(0, AVRExpr, FixupKind));
+ return 0;
+ }
+
+ assert(Kind == MCExpr::SymbolRef);
+ return 0;
+}
+
+unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI,
+ const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
+ if (MO.isImm()) return static_cast<unsigned>(MO.getImm());
+
+ if (MO.isFPImm())
+ return static_cast<unsigned>(APFloat(MO.getFPImm())
+ .bitcastToAPInt()
+ .getHiBits(32)
+ .getLimitedValue());
+
+ // MO must be an Expr.
+ assert(MO.isExpr());
+
+ return getExprOpValue(MO.getExpr(), Fixups, STI);
+}
+
+void AVRMCCodeEmitter::emitInstruction(uint64_t Val, unsigned Size,
+ const MCSubtargetInfo &STI,
+ raw_ostream &OS) const {
+ const uint16_t *Words = reinterpret_cast<uint16_t const *>(&Val);
+ size_t WordCount = Size / 2;
+
+ for (int64_t i = WordCount - 1; i >= 0; --i) {
+ uint16_t Word = Words[i];
+
+ OS << (uint8_t) ((Word & 0x00ff) >> 0);
+ OS << (uint8_t) ((Word & 0xff00) >> 8);
+ }
+}
+
+void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
+
+ // Get byte count of instruction
+ unsigned Size = Desc.getSize();
+
+ assert(Size > 0 && "Instruction size cannot be zero");
+
+ uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);
+ emitInstruction(BinaryOpCode, Size, STI, OS);
+}
+
+MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx) {
+ return new AVRMCCodeEmitter(MCII, Ctx);
+}
+
+#include "AVRGenMCCodeEmitter.inc"
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h
new file mode 100644
index 0000000..5fa425c
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h
@@ -0,0 +1,115 @@
+//===-- AVRMCCodeEmitter.h - Convert AVR Code to Machine Code -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AVRMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#ifndef LLVM_AVR_CODE_EMITTER_H
+#define LLVM_AVR_CODE_EMITTER_H
+
+#include "AVRFixupKinds.h"
+
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/Support/DataTypes.h"
+
+#define GET_INSTRINFO_OPERAND_TYPES_ENUM
+#include "AVRGenInstrInfo.inc"
+
+namespace llvm {
+
+class MCContext;
+class MCExpr;
+class MCFixup;
+class MCInst;
+class MCInstrInfo;
+class MCOperand;
+class MCSubtargetInfo;
+class raw_ostream;
+
+/// Writes AVR machine code to a stream.
+class AVRMCCodeEmitter : public MCCodeEmitter {
+public:
+ AVRMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
+ : MCII(MCII), Ctx(Ctx) {}
+
+private:
+ /// Finishes up encoding an LD/ST instruction.
+ /// The purpose of this function is to set an bit in the instruction
+ /// which follows no logical pattern. See the implementation for details.
+ unsigned loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue,
+ const MCSubtargetInfo &STI) const;
+
+ /// Gets the encoding for a conditional branch target.
+ template <AVR::Fixups Fixup>
+ unsigned encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Encodes the `PTRREGS` operand to a load or store instruction.
+ unsigned encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Encodes a `register+immediate` operand for `LDD`/`STD`.
+ unsigned encodeMemri(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Takes the compliment of a number (~0 - val).
+ unsigned encodeComplement(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Encodes an immediate value with a given fixup.
+ template <AVR::Fixups Fixup>
+ unsigned encodeImm(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Gets the encoding of the target for the `CALL k` instruction.
+ unsigned encodeCallTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// TableGen'ed function to get the binary encoding for an instruction.
+ uint64_t getBinaryCodeForInstr(const MCInst &MI,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Returns the binary encoding of operand.
+ ///
+ /// If the machine operand requires relocation, the relocation is recorded
+ /// and zero is returned.
+ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ void emitInstruction(uint64_t Val, unsigned Size, const MCSubtargetInfo &STI,
+ raw_ostream &OS) const;
+
+ void encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
+
+ AVRMCCodeEmitter(const AVRMCCodeEmitter &) = delete;
+ void operator=(const AVRMCCodeEmitter &) = delete;
+
+ const MCInstrInfo &MCII;
+ MCContext &Ctx;
+};
+
+} // end namespace of llvm.
+
+#endif // LLVM_AVR_CODE_EMITTER_H
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
new file mode 100644
index 0000000..400296b
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
@@ -0,0 +1,189 @@
+//===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRMCExpr.h"
+
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCAsmLayout.h"
+
+namespace llvm {
+
+namespace {
+
+const struct ModifierEntry {
+ const char * const Spelling;
+ AVRMCExpr::VariantKind VariantKind;
+} ModifierNames[] = {
+ {"lo8", AVRMCExpr::VK_AVR_LO8}, {"hi8", AVRMCExpr::VK_AVR_HI8},
+ {"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
+ {"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8},
+
+ {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8},
+ {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8},
+};
+
+} // end of anonymous namespace
+
+const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr,
+ bool Negated, MCContext &Ctx) {
+ return new (Ctx) AVRMCExpr(Kind, Expr, Negated);
+}
+
+void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
+ assert(Kind != VK_AVR_None);
+
+ if (isNegated())
+ OS << '-';
+
+ OS << getName() << '(';
+ getSubExpr()->print(OS, MAI);
+ OS << ')';
+}
+
+bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const {
+ MCValue Value;
+
+ bool isRelocatable =
+ getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr);
+
+ if (!isRelocatable)
+ return false;
+
+ if (Value.isAbsolute()) {
+ Result = evaluateAsInt64(Value.getConstant());
+ return true;
+ }
+
+ return false;
+}
+
+bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ MCValue Value;
+ bool isRelocatable = SubExpr->evaluateAsRelocatable(Value, Layout, Fixup);
+
+ if (!isRelocatable)
+ return false;
+
+ if (Value.isAbsolute()) {
+ Result = MCValue::get(evaluateAsInt64(Value.getConstant()));
+ } else {
+ if (!Layout) return false;
+
+ MCContext &Context = Layout->getAssembler().getContext();
+ const MCSymbolRefExpr *Sym = Value.getSymA();
+ MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
+ if (Modifier != MCSymbolRefExpr::VK_None)
+ return false;
+
+ Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
+ Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
+ }
+
+ return true;
+}
+
+int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
+ if (Negated)
+ Value *= -1;
+
+ switch (Kind) {
+ case AVRMCExpr::VK_AVR_LO8:
+ break;
+ case AVRMCExpr::VK_AVR_HI8:
+ Value >>= 8;
+ break;
+ case AVRMCExpr::VK_AVR_HH8:
+ Value >>= 16;
+ break;
+ case AVRMCExpr::VK_AVR_HHI8:
+ Value >>= 24;
+ break;
+ case AVRMCExpr::VK_AVR_PM_LO8:
+ Value >>= 1;
+ break;
+ case AVRMCExpr::VK_AVR_PM_HI8:
+ Value >>= 9;
+ break;
+ case AVRMCExpr::VK_AVR_PM_HH8:
+ Value >>= 17;
+ break;
+
+ case AVRMCExpr::VK_AVR_None:
+ llvm_unreachable("Uninitialized expression.");
+ }
+ return static_cast<uint64_t>(Value) & 0xff;
+}
+
+AVR::Fixups AVRMCExpr::getFixupKind() const {
+ AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind;
+
+ switch (getKind()) {
+ case VK_AVR_LO8:
+ Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi;
+ break;
+ case VK_AVR_HI8:
+ Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi;
+ break;
+ case VK_AVR_HH8:
+ Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi;
+ break;
+ case VK_AVR_HHI8:
+ Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi;
+ break;
+
+ case VK_AVR_PM_LO8:
+ Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm;
+ break;
+ case VK_AVR_PM_HI8:
+ Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm;
+ break;
+ case VK_AVR_PM_HH8:
+ Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
+ break;
+
+ case VK_AVR_None:
+ llvm_unreachable("Uninitialized expression");
+ }
+
+ return Kind;
+}
+
+void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
+ Streamer.visitUsedExpr(*getSubExpr());
+}
+
+const char *AVRMCExpr::getName() const {
+ const auto &Modifier = std::find_if(
+ std::begin(ModifierNames), std::end(ModifierNames),
+ [this](ModifierEntry const &Mod) { return Mod.VariantKind == Kind; });
+
+ if (Modifier != std::end(ModifierNames)) {
+ return Modifier->Spelling;
+ }
+ return nullptr;
+}
+
+AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) {
+ const auto &Modifier = std::find_if(
+ std::begin(ModifierNames), std::end(ModifierNames),
+ [&Name](ModifierEntry const &Mod) { return Mod.Spelling == Name; });
+
+ if (Modifier != std::end(ModifierNames)) {
+ return Modifier->VariantKind;
+ }
+ return VK_AVR_None;
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
new file mode 100644
index 0000000..be565a8
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
@@ -0,0 +1,88 @@
+//===-- AVRMCExpr.h - AVR specific MC expression classes --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_MCEXPR_H
+#define LLVM_AVR_MCEXPR_H
+
+#include "llvm/MC/MCExpr.h"
+
+#include "MCTargetDesc/AVRFixupKinds.h"
+
+namespace llvm {
+
+/// A expression in AVR machine code.
+class AVRMCExpr : public MCTargetExpr {
+public:
+ /// Specifies the type of an expression.
+ enum VariantKind {
+ VK_AVR_None,
+
+ VK_AVR_HI8, ///< Corresponds to `hi8()`.
+ VK_AVR_LO8, ///< Corresponds to `lo8()`.
+ VK_AVR_HH8, ///< Corresponds to `hlo8() and hh8()`.
+ VK_AVR_HHI8, ///< Corresponds to `hhi8()`.
+
+ VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`.
+ VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`.
+ VK_AVR_PM_HH8 ///< Corresponds to `pm_hh8()`.
+ };
+
+public:
+ /// Creates an AVR machine code expression.
+ static const AVRMCExpr *create(VariantKind Kind, const MCExpr *Expr,
+ bool isNegated, MCContext &Ctx);
+
+ /// Gets the type of the expression.
+ VariantKind getKind() const { return Kind; }
+ /// Gets the name of the expression.
+ const char *getName() const;
+ const MCExpr *getSubExpr() const { return SubExpr; }
+ /// Gets the fixup which corresponds to the expression.
+ AVR::Fixups getFixupKind() const;
+ /// Evaluates the fixup as a constant value.
+ bool evaluateAsConstant(int64_t &Result) const;
+
+ bool isNegated() const { return Negated; }
+ void setNegated(bool negated = true) { Negated = negated; }
+
+ void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
+ bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const override;
+
+ void visitUsedExpr(MCStreamer &streamer) const override;
+
+ MCFragment *findAssociatedFragment() const override {
+ return getSubExpr()->findAssociatedFragment();
+ }
+
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {}
+
+ static bool classof(const MCExpr *E) {
+ return E->getKind() == MCExpr::Target;
+ }
+
+public:
+ static VariantKind getKindByName(StringRef Name);
+
+private:
+ int64_t evaluateAsInt64(int64_t Value) const;
+
+ const VariantKind Kind;
+ const MCExpr *SubExpr;
+ bool Negated;
+
+private:
+ explicit AVRMCExpr(VariantKind Kind, const MCExpr *Expr, bool Negated)
+ : Kind(Kind), SubExpr(Expr), Negated(Negated) {}
+ ~AVRMCExpr() {}
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_MCEXPR_H
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp
new file mode 100644
index 0000000..a4fa5c0
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp
@@ -0,0 +1,121 @@
+//===-- AVRMCTargetDesc.cpp - AVR Target Descriptions ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides AVR specific target descriptions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRELFStreamer.h"
+#include "AVRMCAsmInfo.h"
+#include "AVRMCTargetDesc.h"
+#include "AVRTargetStreamer.h"
+#include "InstPrinter/AVRInstPrinter.h"
+
+#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+
+#define GET_INSTRINFO_MC_DESC
+#include "AVRGenInstrInfo.inc"
+
+#define GET_SUBTARGETINFO_MC_DESC
+#include "AVRGenSubtargetInfo.inc"
+
+#define GET_REGINFO_MC_DESC
+#include "AVRGenRegisterInfo.inc"
+
+using namespace llvm;
+
+static MCInstrInfo *createAVRMCInstrInfo() {
+ MCInstrInfo *X = new MCInstrInfo();
+ InitAVRMCInstrInfo(X);
+
+ return X;
+}
+
+static MCRegisterInfo *createAVRMCRegisterInfo(const Triple &TT) {
+ MCRegisterInfo *X = new MCRegisterInfo();
+ InitAVRMCRegisterInfo(X, 0);
+
+ return X;
+}
+
+static MCSubtargetInfo *createAVRMCSubtargetInfo(const Triple &TT,
+ StringRef CPU, StringRef FS) {
+ return createAVRMCSubtargetInfoImpl(TT, CPU, FS);
+}
+
+static MCInstPrinter *createAVRMCInstPrinter(const Triple &T,
+ unsigned SyntaxVariant,
+ const MCAsmInfo &MAI,
+ const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI) {
+ if (SyntaxVariant == 0) {
+ return new AVRInstPrinter(MAI, MII, MRI);
+ }
+
+ return nullptr;
+}
+
+static MCStreamer *createMCStreamer(const Triple &T, MCContext &Context,
+ MCAsmBackend &MAB, raw_pwrite_stream &OS,
+ MCCodeEmitter *Emitter, bool RelaxAll) {
+ return createELFStreamer(Context, MAB, OS, Emitter, RelaxAll);
+}
+
+static MCTargetStreamer *
+createAVRObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+ return new AVRELFStreamer(S, STI);
+}
+
+static MCTargetStreamer *createMCAsmTargetStreamer(MCStreamer &S,
+ formatted_raw_ostream &OS,
+ MCInstPrinter *InstPrint,
+ bool isVerboseAsm) {
+ return new AVRTargetAsmStreamer(S);
+}
+
+extern "C" void LLVMInitializeAVRTargetMC() {
+ // Register the MC asm info.
+ RegisterMCAsmInfo<AVRMCAsmInfo> X(getTheAVRTarget());
+
+ // Register the MC instruction info.
+ TargetRegistry::RegisterMCInstrInfo(getTheAVRTarget(), createAVRMCInstrInfo);
+
+ // Register the MC register info.
+ TargetRegistry::RegisterMCRegInfo(getTheAVRTarget(), createAVRMCRegisterInfo);
+
+ // Register the MC subtarget info.
+ TargetRegistry::RegisterMCSubtargetInfo(getTheAVRTarget(),
+ createAVRMCSubtargetInfo);
+
+ // Register the MCInstPrinter.
+ TargetRegistry::RegisterMCInstPrinter(getTheAVRTarget(),
+ createAVRMCInstPrinter);
+
+ // Register the MC Code Emitter
+ TargetRegistry::RegisterMCCodeEmitter(getTheAVRTarget(), createAVRMCCodeEmitter);
+
+ // Register the ELF streamer
+ TargetRegistry::RegisterELFStreamer(getTheAVRTarget(), createMCStreamer);
+
+ // Register the obj target streamer.
+ TargetRegistry::RegisterObjectTargetStreamer(getTheAVRTarget(),
+ createAVRObjectTargetStreamer);
+
+ // Register the asm target streamer.
+ TargetRegistry::RegisterAsmTargetStreamer(getTheAVRTarget(),
+ createMCAsmTargetStreamer);
+
+ // Register the asm backend (as little endian).
+ TargetRegistry::RegisterMCAsmBackend(getTheAVRTarget(), createAVRAsmBackend);
+}
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
index b72793d..41a5747 100644
--- a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
@@ -24,12 +24,13 @@ class MCContext;
class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
+class MCTargetOptions;
class StringRef;
class Target;
class Triple;
class raw_pwrite_stream;
-extern Target TheAVRTarget;
+Target &getTheAVRTarget();
/// Creates a machine code emitter for AVR.
MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
@@ -38,7 +39,8 @@ MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
/// Creates an assembly backend for AVR.
MCAsmBackend *createAVRAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const llvm::MCTargetOptions &TO);
/// Creates an ELF object writer for AVR.
MCObjectWriter *createAVRELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI);
diff --git a/contrib/llvm/lib/Target/AVR/README.md b/contrib/llvm/lib/Target/AVR/README.md
new file mode 100644
index 0000000..bd8b453
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/README.md
@@ -0,0 +1,8 @@
+# AVR backend
+
+This experimental backend is for the 8-bit Atmel [AVR](https://en.wikipedia.org/wiki/Atmel_AVR) microcontroller.
+
+## Useful links
+
+* [Unresolved bugs](https://llvm.org/bugs/buglist.cgi?product=libraries&component=Backend%3A%20AVR&resolution=---&list_id=109466)
+* [Architecture notes](https://github.com/avr-llvm/architecture)
diff --git a/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp b/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp
index c0e0d20..36cecaa 100644
--- a/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp
@@ -9,17 +9,15 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/TargetRegistry.h"
-
namespace llvm {
-Target TheAVRTarget;
+Target &getTheAVRTarget() {
+ static Target TheAVRTarget;
+ return TheAVRTarget;
+}
}
extern "C" void LLVMInitializeAVRTargetInfo() {
- llvm::RegisterTarget<llvm::Triple::avr> X(
- llvm::TheAVRTarget, "avr", "Atmel AVR Microcontroller");
+ llvm::RegisterTarget<llvm::Triple::avr> X(llvm::getTheAVRTarget(), "avr",
+ "Atmel AVR Microcontroller");
}
-// FIXME: Temporary stub - this function must be defined for linking
-// to succeed. Remove once this function is properly implemented.
-extern "C" void LLVMInitializeAVRTargetMC() {
-}
diff --git a/contrib/llvm/lib/Target/BPF/BPF.td b/contrib/llvm/lib/Target/BPF/BPF.td
index 8493b0f..11abe52 100644
--- a/contrib/llvm/lib/Target/BPF/BPF.td
+++ b/contrib/llvm/lib/Target/BPF/BPF.td
@@ -25,14 +25,20 @@ def BPFInstPrinter : AsmWriter {
bit isMCAsmWriter = 1;
}
+def BPFAsmParser : AsmParser {
+ bit HasMnemonicFirst = 0;
+}
+
def BPFAsmParserVariant : AsmParserVariant {
int Variant = 0;
string Name = "BPF";
string BreakCharacters = ".";
+ string TokenizingCharacters = "#()[]=:.<>!+*";
}
def BPF : Target {
let InstructionSet = BPFInstrInfo;
let AssemblyWriters = [BPFInstPrinter];
+ let AssemblyParsers = [BPFAsmParser];
let AssemblyParserVariants = [BPFAsmParserVariant];
}
diff --git a/contrib/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/contrib/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
index 1078b06..c520146 100644
--- a/contrib/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
@@ -38,7 +38,7 @@ public:
explicit BPFAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)) {}
- const char *getPassName() const override { return "BPF Assembly Printer"; }
+ StringRef getPassName() const override { return "BPF Assembly Printer"; }
void EmitInstruction(const MachineInstr *MI) override;
};
@@ -55,7 +55,7 @@ void BPFAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Force static initialization.
extern "C" void LLVMInitializeBPFAsmPrinter() {
- RegisterAsmPrinter<BPFAsmPrinter> X(TheBPFleTarget);
- RegisterAsmPrinter<BPFAsmPrinter> Y(TheBPFbeTarget);
- RegisterAsmPrinter<BPFAsmPrinter> Z(TheBPFTarget);
+ RegisterAsmPrinter<BPFAsmPrinter> X(getTheBPFleTarget());
+ RegisterAsmPrinter<BPFAsmPrinter> Y(getTheBPFbeTarget());
+ RegisterAsmPrinter<BPFAsmPrinter> Z(getTheBPFTarget());
}
diff --git a/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp b/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
index ac2af03..1209144 100644
--- a/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
@@ -38,7 +38,7 @@ class BPFDAGToDAGISel : public SelectionDAGISel {
public:
explicit BPFDAGToDAGISel(BPFTargetMachine &TM) : SelectionDAGISel(TM) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "BPF DAG->DAG Pattern Instruction Selection";
}
diff --git a/contrib/llvm/lib/Target/BPF/BPFInstrInfo.cpp b/contrib/llvm/lib/Target/BPF/BPFInstrInfo.cpp
index 7aea051..e38face 100644
--- a/contrib/llvm/lib/Target/BPF/BPFInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/BPF/BPFInstrInfo.cpp
@@ -13,15 +13,13 @@
#include "BPF.h"
#include "BPFInstrInfo.h"
-#include "BPFSubtarget.h"
-#include "BPFTargetMachine.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+#include <iterator>
#define GET_INSTRINFO_CTOR_DTOR
#include "BPFGenInstrInfo.inc"
@@ -109,11 +107,11 @@ bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
while (std::next(I) != MBB.end())
std::next(I)->eraseFromParent();
Cond.clear();
- FBB = 0;
+ FBB = nullptr;
// Delete the J if it's equivalent to a fall-through.
if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
- TBB = 0;
+ TBB = nullptr;
I->eraseFromParent();
I = MBB.end();
continue;
@@ -130,13 +128,16 @@ bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-unsigned BPFInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(!BytesAdded && "code size not handled");
+
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
if (Cond.empty()) {
// Unconditional branch
@@ -148,7 +149,10 @@ unsigned BPFInstrInfo::InsertBranch(MachineBasicBlock &MBB,
llvm_unreachable("Unexpected conditional branch");
}
-unsigned BPFInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
diff --git a/contrib/llvm/lib/Target/BPF/BPFInstrInfo.h b/contrib/llvm/lib/Target/BPF/BPFInstrInfo.h
index cc2e41e..c7048ab 100644
--- a/contrib/llvm/lib/Target/BPF/BPFInstrInfo.h
+++ b/contrib/llvm/lib/Target/BPF/BPFInstrInfo.h
@@ -49,10 +49,12 @@ public:
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
};
}
diff --git a/contrib/llvm/lib/Target/BPF/BPFInstrInfo.td b/contrib/llvm/lib/Target/BPF/BPFInstrInfo.td
index 6b73db8..a7910de 100644
--- a/contrib/llvm/lib/Target/BPF/BPFInstrInfo.td
+++ b/contrib/llvm/lib/Target/BPF/BPFInstrInfo.td
@@ -61,6 +61,7 @@ def FIri : ComplexPattern<i64, 2, "SelectFIAddr", [add, or], []>;
def MEMri : Operand<i64> {
let PrintMethod = "printMemOperand";
let EncoderMethod = "getMemoryOpValue";
+ let DecoderMethod = "decodeMemoryOpValue";
let MIOperandInfo = (ops GPR, i16imm);
}
@@ -81,7 +82,7 @@ def BPF_CC_GEU : PatLeaf<(imm),
// jump instructions
class JMP_RR<bits<4> Opc, string OpcodeStr, PatLeaf Cond>
: InstBPF<(outs), (ins GPR:$dst, GPR:$src, brtarget:$BrDst),
- !strconcat(OpcodeStr, "\t$dst, $src goto $BrDst"),
+ "if $dst "#OpcodeStr#" $src goto $BrDst",
[(BPFbrcc i64:$dst, i64:$src, Cond, bb:$BrDst)]> {
bits<4> op;
bits<1> BPFSrc;
@@ -102,7 +103,7 @@ class JMP_RR<bits<4> Opc, string OpcodeStr, PatLeaf Cond>
class JMP_RI<bits<4> Opc, string OpcodeStr, PatLeaf Cond>
: InstBPF<(outs), (ins GPR:$dst, i64imm:$imm, brtarget:$BrDst),
- !strconcat(OpcodeStr, "i\t$dst, $imm goto $BrDst"),
+ "if $dst "#OpcodeStr#" $imm goto $BrDst",
[(BPFbrcc i64:$dst, i64immSExt32:$imm, Cond, bb:$BrDst)]> {
bits<4> op;
bits<1> BPFSrc;
@@ -128,18 +129,18 @@ multiclass J<bits<4> Opc, string OpcodeStr, PatLeaf Cond> {
let isBranch = 1, isTerminator = 1, hasDelaySlot=0 in {
// cmp+goto instructions
-defm JEQ : J<0x1, "jeq", BPF_CC_EQ>;
-defm JUGT : J<0x2, "jgt", BPF_CC_GTU>;
-defm JUGE : J<0x3, "jge", BPF_CC_GEU>;
-defm JNE : J<0x5, "jne", BPF_CC_NE>;
-defm JSGT : J<0x6, "jsgt", BPF_CC_GT>;
-defm JSGE : J<0x7, "jsge", BPF_CC_GE>;
+defm JEQ : J<0x1, "==", BPF_CC_EQ>;
+defm JUGT : J<0x2, ">", BPF_CC_GTU>;
+defm JUGE : J<0x3, ">=", BPF_CC_GEU>;
+defm JNE : J<0x5, "!=", BPF_CC_NE>;
+defm JSGT : J<0x6, "s>", BPF_CC_GT>;
+defm JSGE : J<0x7, "s>=", BPF_CC_GE>;
}
// ALU instructions
class ALU_RI<bits<4> Opc, string OpcodeStr, SDNode OpNode>
: InstBPF<(outs GPR:$dst), (ins GPR:$src2, i64imm:$imm),
- !strconcat(OpcodeStr, "i\t$dst, $imm"),
+ "$dst "#OpcodeStr#" $imm",
[(set GPR:$dst, (OpNode GPR:$src2, i64immSExt32:$imm))]> {
bits<4> op;
bits<1> BPFSrc;
@@ -158,7 +159,7 @@ class ALU_RI<bits<4> Opc, string OpcodeStr, SDNode OpNode>
class ALU_RR<bits<4> Opc, string OpcodeStr, SDNode OpNode>
: InstBPF<(outs GPR:$dst), (ins GPR:$src2, GPR:$src),
- !strconcat(OpcodeStr, "\t$dst, $src"),
+ "$dst "#OpcodeStr#" $src",
[(set GPR:$dst, (OpNode i64:$src2, i64:$src))]> {
bits<4> op;
bits<1> BPFSrc;
@@ -182,22 +183,22 @@ multiclass ALU<bits<4> Opc, string OpcodeStr, SDNode OpNode> {
let Constraints = "$dst = $src2" in {
let isAsCheapAsAMove = 1 in {
- defm ADD : ALU<0x0, "add", add>;
- defm SUB : ALU<0x1, "sub", sub>;
- defm OR : ALU<0x4, "or", or>;
- defm AND : ALU<0x5, "and", and>;
- defm SLL : ALU<0x6, "sll", shl>;
- defm SRL : ALU<0x7, "srl", srl>;
- defm XOR : ALU<0xa, "xor", xor>;
- defm SRA : ALU<0xc, "sra", sra>;
+ defm ADD : ALU<0x0, "+=", add>;
+ defm SUB : ALU<0x1, "-=", sub>;
+ defm OR : ALU<0x4, "|=", or>;
+ defm AND : ALU<0x5, "&=", and>;
+ defm SLL : ALU<0x6, "<<=", shl>;
+ defm SRL : ALU<0x7, ">>=", srl>;
+ defm XOR : ALU<0xa, "^=", xor>;
+ defm SRA : ALU<0xc, "s>>=", sra>;
}
- defm MUL : ALU<0x2, "mul", mul>;
- defm DIV : ALU<0x3, "div", udiv>;
+ defm MUL : ALU<0x2, "*=", mul>;
+ defm DIV : ALU<0x3, "/=", udiv>;
}
class MOV_RR<string OpcodeStr>
: InstBPF<(outs GPR:$dst), (ins GPR:$src),
- !strconcat(OpcodeStr, "\t$dst, $src"),
+ "$dst "#OpcodeStr#" $src",
[]> {
bits<4> op;
bits<1> BPFSrc;
@@ -216,7 +217,7 @@ class MOV_RR<string OpcodeStr>
class MOV_RI<string OpcodeStr>
: InstBPF<(outs GPR:$dst), (ins i64imm:$imm),
- !strconcat(OpcodeStr, "\t$dst, $imm"),
+ "$dst "#OpcodeStr#" $imm",
[(set GPR:$dst, (i64 i64immSExt32:$imm))]> {
bits<4> op;
bits<1> BPFSrc;
@@ -235,7 +236,7 @@ class MOV_RI<string OpcodeStr>
class LD_IMM64<bits<4> Pseudo, string OpcodeStr>
: InstBPF<(outs GPR:$dst), (ins u64imm:$imm),
- !strconcat(OpcodeStr, "\t$dst, $imm"),
+ "$dst "#OpcodeStr#" ${imm}ll",
[(set GPR:$dst, (i64 imm:$imm))]> {
bits<3> mode;
@@ -256,9 +257,9 @@ class LD_IMM64<bits<4> Pseudo, string OpcodeStr>
}
let isReMaterializable = 1, isAsCheapAsAMove = 1 in {
-def LD_imm64 : LD_IMM64<0, "ld_64">;
-def MOV_rr : MOV_RR<"mov">;
-def MOV_ri : MOV_RI<"mov">;
+def LD_imm64 : LD_IMM64<0, "=">;
+def MOV_rr : MOV_RR<"=">;
+def MOV_ri : MOV_RI<"=">;
}
def FI_ri
@@ -267,6 +268,13 @@ def FI_ri
[(set i64:$dst, FIri:$addr)]> {
// This is a tentative instruction, and will be replaced
// with MOV_rr and ADD_ri in PEI phase
+ let Inst{63-61} = 0;
+ let Inst{60-59} = 3;
+ let Inst{51-48} = 0;
+ let Inst{55-52} = 2;
+ let Inst{47-32} = 0;
+ let Inst{31-0} = 0;
+ let BPFClass = 0;
}
@@ -296,7 +304,7 @@ def LD_pseudo
// STORE instructions
class STORE<bits<2> SizeOp, string OpcodeStr, list<dag> Pattern>
: InstBPF<(outs), (ins GPR:$src, MEMri:$addr),
- !strconcat(OpcodeStr, "\t$addr, $src"), Pattern> {
+ "*("#OpcodeStr#" *)($addr) = $src", Pattern> {
bits<3> mode;
bits<2> size;
bits<4> src;
@@ -316,15 +324,15 @@ class STORE<bits<2> SizeOp, string OpcodeStr, list<dag> Pattern>
class STOREi64<bits<2> Opc, string OpcodeStr, PatFrag OpNode>
: STORE<Opc, OpcodeStr, [(OpNode i64:$src, ADDRri:$addr)]>;
-def STW : STOREi64<0x0, "stw", truncstorei32>;
-def STH : STOREi64<0x1, "sth", truncstorei16>;
-def STB : STOREi64<0x2, "stb", truncstorei8>;
-def STD : STOREi64<0x3, "std", store>;
+def STW : STOREi64<0x0, "u32", truncstorei32>;
+def STH : STOREi64<0x1, "u16", truncstorei16>;
+def STB : STOREi64<0x2, "u8", truncstorei8>;
+def STD : STOREi64<0x3, "u64", store>;
// LOAD instructions
class LOAD<bits<2> SizeOp, string OpcodeStr, list<dag> Pattern>
: InstBPF<(outs GPR:$dst), (ins MEMri:$addr),
- !strconcat(OpcodeStr, "\t$dst, $addr"), Pattern> {
+ "$dst = *("#OpcodeStr#" *)($addr)", Pattern> {
bits<3> mode;
bits<2> size;
bits<4> dst;
@@ -344,14 +352,14 @@ class LOAD<bits<2> SizeOp, string OpcodeStr, list<dag> Pattern>
class LOADi64<bits<2> SizeOp, string OpcodeStr, PatFrag OpNode>
: LOAD<SizeOp, OpcodeStr, [(set i64:$dst, (OpNode ADDRri:$addr))]>;
-def LDW : LOADi64<0x0, "ldw", zextloadi32>;
-def LDH : LOADi64<0x1, "ldh", zextloadi16>;
-def LDB : LOADi64<0x2, "ldb", zextloadi8>;
-def LDD : LOADi64<0x3, "ldd", load>;
+def LDW : LOADi64<0x0, "u32", zextloadi32>;
+def LDH : LOADi64<0x1, "u16", zextloadi16>;
+def LDB : LOADi64<0x2, "u8", zextloadi8>;
+def LDD : LOADi64<0x3, "u64", load>;
class BRANCH<bits<4> Opc, string OpcodeStr, list<dag> Pattern>
: InstBPF<(outs), (ins brtarget:$BrDst),
- !strconcat(OpcodeStr, "\t$BrDst"), Pattern> {
+ !strconcat(OpcodeStr, " $BrDst"), Pattern> {
bits<4> op;
bits<16> BrDst;
bits<1> BPFSrc;
@@ -367,7 +375,7 @@ class BRANCH<bits<4> Opc, string OpcodeStr, list<dag> Pattern>
class CALL<string OpcodeStr>
: InstBPF<(outs), (ins calltarget:$BrDst),
- !strconcat(OpcodeStr, "\t$BrDst"), []> {
+ !strconcat(OpcodeStr, " $BrDst"), []> {
bits<4> op;
bits<32> BrDst;
bits<1> BPFSrc;
@@ -383,7 +391,7 @@ class CALL<string OpcodeStr>
// Jump always
let isBranch = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1 in {
- def JMP : BRANCH<0x0, "jmp", [(br bb:$BrDst)]>;
+ def JMP : BRANCH<0x0, "goto", [(br bb:$BrDst)]>;
}
// Jump and link
@@ -432,7 +440,7 @@ class RET<string OpcodeStr>
let isReturn = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1,
isNotDuplicable = 1 in {
- def RET : RET<"ret">;
+ def RET : RET<"exit">;
}
// ADJCALLSTACKDOWN/UP pseudo insns
@@ -472,17 +480,17 @@ def : Pat<(extloadi32 ADDRri:$src), (i64 (LDW ADDRri:$src))>;
// Atomics
class XADD<bits<2> SizeOp, string OpcodeStr, PatFrag OpNode>
: InstBPF<(outs GPR:$dst), (ins MEMri:$addr, GPR:$val),
- !strconcat(OpcodeStr, "\t$dst, $addr, $val"),
+ "lock *("#OpcodeStr#" *)($addr) += $val",
[(set GPR:$dst, (OpNode ADDRri:$addr, GPR:$val))]> {
bits<3> mode;
bits<2> size;
- bits<4> src;
+ bits<4> dst;
bits<20> addr;
let Inst{63-61} = mode;
let Inst{60-59} = size;
let Inst{51-48} = addr{19-16}; // base reg
- let Inst{55-52} = src;
+ let Inst{55-52} = dst;
let Inst{47-32} = addr{15-0}; // offset
let mode = 6; // BPF_XADD
@@ -491,8 +499,8 @@ class XADD<bits<2> SizeOp, string OpcodeStr, PatFrag OpNode>
}
let Constraints = "$dst = $val" in {
-def XADD32 : XADD<0, "xadd32", atomic_load_add_32>;
-def XADD64 : XADD<3, "xadd64", atomic_load_add_64>;
+def XADD32 : XADD<0, "u32", atomic_load_add_32>;
+def XADD64 : XADD<3, "u64", atomic_load_add_64>;
// undefined def XADD16 : XADD<1, "xadd16", atomic_load_add_16>;
// undefined def XADD8 : XADD<2, "xadd8", atomic_load_add_8>;
}
@@ -528,7 +536,7 @@ let Defs = [R0, R1, R2, R3, R4, R5], Uses = [R6], hasSideEffects = 1,
hasExtraDefRegAllocReq = 1, hasExtraSrcRegAllocReq = 1, mayLoad = 1 in {
class LOAD_ABS<bits<2> SizeOp, string OpcodeStr, Intrinsic OpNode>
: InstBPF<(outs), (ins GPR:$skb, i64imm:$imm),
- !strconcat(OpcodeStr, "\tr0, $skb.data + $imm"),
+ "r0 = *("#OpcodeStr#" *)skb[$imm]",
[(set R0, (OpNode GPR:$skb, i64immSExt32:$imm))]> {
bits<3> mode;
bits<2> size;
@@ -545,7 +553,7 @@ class LOAD_ABS<bits<2> SizeOp, string OpcodeStr, Intrinsic OpNode>
class LOAD_IND<bits<2> SizeOp, string OpcodeStr, Intrinsic OpNode>
: InstBPF<(outs), (ins GPR:$skb, GPR:$val),
- !strconcat(OpcodeStr, "\tr0, $skb.data + $val"),
+ "r0 = *("#OpcodeStr#" *)skb[$val]",
[(set R0, (OpNode GPR:$skb, GPR:$val))]> {
bits<3> mode;
bits<2> size;
@@ -561,10 +569,10 @@ class LOAD_IND<bits<2> SizeOp, string OpcodeStr, Intrinsic OpNode>
}
}
-def LD_ABS_B : LOAD_ABS<2, "ldabs_b", int_bpf_load_byte>;
-def LD_ABS_H : LOAD_ABS<1, "ldabs_h", int_bpf_load_half>;
-def LD_ABS_W : LOAD_ABS<0, "ldabs_w", int_bpf_load_word>;
+def LD_ABS_B : LOAD_ABS<2, "u8", int_bpf_load_byte>;
+def LD_ABS_H : LOAD_ABS<1, "u16", int_bpf_load_half>;
+def LD_ABS_W : LOAD_ABS<0, "u32", int_bpf_load_word>;
-def LD_IND_B : LOAD_IND<2, "ldind_b", int_bpf_load_byte>;
-def LD_IND_H : LOAD_IND<1, "ldind_h", int_bpf_load_half>;
-def LD_IND_W : LOAD_IND<0, "ldind_w", int_bpf_load_word>;
+def LD_IND_B : LOAD_IND<2, "u8", int_bpf_load_byte>;
+def LD_IND_H : LOAD_IND<1, "u16", int_bpf_load_half>;
+def LD_IND_W : LOAD_IND<0, "u32", int_bpf_load_word>;
diff --git a/contrib/llvm/lib/Target/BPF/BPFRegisterInfo.cpp b/contrib/llvm/lib/Target/BPF/BPFRegisterInfo.cpp
index 952615b..71846e3 100644
--- a/contrib/llvm/lib/Target/BPF/BPFRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/BPF/BPFRegisterInfo.cpp
@@ -62,7 +62,7 @@ void BPFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
MachineBasicBlock &MBB = *MI.getParent();
if (MI.getOpcode() == BPF::MOV_rr) {
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex);
MI.getOperand(i).ChangeToRegister(FrameReg, false);
unsigned reg = MI.getOperand(i - 1).getReg();
@@ -72,7 +72,7 @@ void BPFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
return;
}
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
MI.getOperand(i + 1).getImm();
if (!isInt<32>(Offset))
diff --git a/contrib/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/contrib/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index 5fc6f2f..8976956 100644
--- a/contrib/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -24,9 +24,9 @@ using namespace llvm;
extern "C" void LLVMInitializeBPFTarget() {
// Register the target.
- RegisterTargetMachine<BPFTargetMachine> X(TheBPFleTarget);
- RegisterTargetMachine<BPFTargetMachine> Y(TheBPFbeTarget);
- RegisterTargetMachine<BPFTargetMachine> Z(TheBPFTarget);
+ RegisterTargetMachine<BPFTargetMachine> X(getTheBPFleTarget());
+ RegisterTargetMachine<BPFTargetMachine> Y(getTheBPFbeTarget());
+ RegisterTargetMachine<BPFTargetMachine> Z(getTheBPFTarget());
}
// DataLayout: little or big endian
diff --git a/contrib/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp b/contrib/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp
new file mode 100644
index 0000000..9beefcd
--- /dev/null
+++ b/contrib/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp
@@ -0,0 +1,154 @@
+//===- BPFDisassembler.cpp - Disassembler for BPF ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the BPF Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BPF.h"
+#include "BPFSubtarget.h"
+#include "MCTargetDesc/BPFMCTargetDesc.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TargetRegistry.h"
+#include <cstdint>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "bpf-disassembler"
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+
+/// A disassembler class for BPF.
+class BPFDisassembler : public MCDisassembler {
+public:
+ BPFDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+ ~BPFDisassembler() override = default;
+
+ DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+
+} // end anonymous namespace
+
+static MCDisassembler *createBPFDisassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new BPFDisassembler(STI, Ctx);
+}
+
+
+extern "C" void LLVMInitializeBPFDisassembler() {
+ // Register the disassembler.
+ TargetRegistry::RegisterMCDisassembler(getTheBPFTarget(),
+ createBPFDisassembler);
+ TargetRegistry::RegisterMCDisassembler(getTheBPFleTarget(),
+ createBPFDisassembler);
+ TargetRegistry::RegisterMCDisassembler(getTheBPFbeTarget(),
+ createBPFDisassembler);
+}
+
+static const unsigned GPRDecoderTable[] = {
+ BPF::R0, BPF::R1, BPF::R2, BPF::R3, BPF::R4, BPF::R5,
+ BPF::R6, BPF::R7, BPF::R8, BPF::R9, BPF::R10, BPF::R11};
+
+static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t /*Address*/,
+ const void * /*Decoder*/) {
+ if (RegNo > 11)
+ return MCDisassembler::Fail;
+
+ unsigned Reg = GPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeMemoryOpValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Register = (Insn >> 16) & 0xf;
+ Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
+ unsigned Offset = (Insn & 0xffff);
+ Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));
+
+ return MCDisassembler::Success;
+}
+
+#include "BPFGenDisassemblerTables.inc"
+
+static DecodeStatus readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint64_t &Insn) {
+ uint64_t Lo, Hi;
+
+ if (Bytes.size() < 8) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ Size = 8;
+ Hi = (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 0) | (Bytes[3] << 8);
+ Lo = (Bytes[4] << 0) | (Bytes[5] << 8) | (Bytes[6] << 16) | (Bytes[7] << 24);
+ Insn = Make_64(Hi, Lo);
+
+ return MCDisassembler::Success;
+}
+
+DecodeStatus BPFDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint64_t Insn;
+ DecodeStatus Result;
+
+ Result = readInstruction64(Bytes, Address, Size, Insn);
+ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
+
+ Result = decodeInstruction(DecoderTableBPF64, Instr, Insn,
+ Address, this, STI);
+ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
+
+ switch (Instr.getOpcode()) {
+ case BPF::LD_imm64: {
+ if (Bytes.size() < 16) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+ Size = 16;
+ uint64_t Hi = (Bytes[12] << 0) | (Bytes[13] << 8) | (Bytes[14] << 16) | (Bytes[15] << 24);
+ auto& Op = Instr.getOperand(1);
+ Op.setImm(Make_64(Hi, Op.getImm()));
+ break;
+ }
+ case BPF::LD_ABS_B:
+ case BPF::LD_ABS_H:
+ case BPF::LD_ABS_W:
+ case BPF::LD_IND_B:
+ case BPF::LD_IND_H:
+ case BPF::LD_IND_W: {
+ auto Op = Instr.getOperand(0);
+ Instr.clear();
+ Instr.addOperand(MCOperand::createReg(BPF::R6));
+ Instr.addOperand(Op);
+ break;
+ }
+ }
+
+ return Result;
+}
+
+typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder);
diff --git a/contrib/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp b/contrib/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
index 552288b..ffd29f3 100644
--- a/contrib/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
@@ -67,15 +67,21 @@ void BPFInstPrinter::printMemOperand(const MCInst *MI, int OpNo, raw_ostream &O,
const char *Modifier) {
const MCOperand &RegOp = MI->getOperand(OpNo);
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
- // offset
- if (OffsetOp.isImm())
- O << formatDec(OffsetOp.getImm());
- else
- assert(0 && "Expected an immediate");
// register
assert(RegOp.isReg() && "Register operand not a register");
- O << '(' << getRegisterName(RegOp.getReg()) << ')';
+ O << getRegisterName(RegOp.getReg());
+
+ // offset
+ if (OffsetOp.isImm()) {
+ auto Imm = OffsetOp.getImm();
+ if (Imm >= 0)
+ O << " + " << formatDec(Imm);
+ else
+ O << " - " << formatDec(-Imm);
+ } else {
+ assert(0 && "Expected an immediate");
+ }
}
void BPFInstPrinter::printImm64Operand(const MCInst *MI, unsigned OpNo,
diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
index 2de40aa..afc321ea 100644
--- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
@@ -8,28 +8,24 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/BPFMCTargetDesc.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCAsmBackend.h"
-#include "llvm/MC/MCAssembler.h"
-#include "llvm/MC/MCDirectives.h"
-#include "llvm/MC/MCELFObjectWriter.h"
-#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCObjectWriter.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCSymbol.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
using namespace llvm;
namespace {
+
class BPFAsmBackend : public MCAsmBackend {
public:
bool IsLittleEndian;
BPFAsmBackend(bool IsLittleEndian)
: MCAsmBackend(), IsLittleEndian(IsLittleEndian) {}
- ~BPFAsmBackend() override {}
+ ~BPFAsmBackend() override = default;
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
uint64_t Value, bool IsPCRel) const override;
@@ -53,6 +49,8 @@ public:
bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
};
+} // end anonymous namespace
+
bool BPFAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
if ((Count % 8) != 0)
return false;
@@ -66,7 +64,6 @@ bool BPFAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
void BPFAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
unsigned DataSize, uint64_t Value,
bool IsPCRel) const {
-
if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) {
assert(Value == 0);
} else if (Fixup.getKind() == FK_Data_4 || Fixup.getKind() == FK_Data_8) {
@@ -92,16 +89,17 @@ void BPFAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
MCObjectWriter *BPFAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
return createBPFELFObjectWriter(OS, 0, IsLittleEndian);
}
-}
MCAsmBackend *llvm::createBPFAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions&) {
return new BPFAsmBackend(/*IsLittleEndian=*/true);
}
MCAsmBackend *llvm::createBPFbeAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions&) {
return new BPFAsmBackend(/*IsLittleEndian=*/false);
}
diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
index 4b92e3e..ebe9abd 100644
--- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
@@ -10,29 +10,30 @@
#include "MCTargetDesc/BPFMCTargetDesc.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixup.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
+#include <cstdint>
using namespace llvm;
namespace {
+
class BPFELFObjectWriter : public MCELFObjectTargetWriter {
public:
BPFELFObjectWriter(uint8_t OSABI);
-
- ~BPFELFObjectWriter() override;
+ ~BPFELFObjectWriter() override = default;
protected:
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
const MCFixup &Fixup, bool IsPCRel) const override;
};
-}
+
+} // end anonymous namespace
BPFELFObjectWriter::BPFELFObjectWriter(uint8_t OSABI)
: MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_BPF,
/*HasRelocationAddend*/ false) {}
-BPFELFObjectWriter::~BPFELFObjectWriter() {}
-
unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
@@ -41,13 +42,13 @@ unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
default:
llvm_unreachable("invalid fixup kind!");
case FK_SecRel_8:
- return ELF::R_X86_64_64;
+ return ELF::R_BPF_64_64;
case FK_SecRel_4:
- return ELF::R_X86_64_PC32;
+ return ELF::R_BPF_64_32;
case FK_Data_8:
- return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
+ return ELF::R_BPF_64_64;
case FK_Data_4:
- return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
+ return ELF::R_BPF_64_32;
}
}
diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
index 9a2e223..559ac29 100644
--- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
+++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
@@ -34,6 +34,15 @@ public:
HasDotTypeDotSizeDirective = false;
SupportsDebugInformation = true;
+ ExceptionsType = ExceptionHandling::DwarfCFI;
+ MinInstAlignment = 8;
+
+ // the default is 4 and it only affects dwarf elf output
+ // so if not set correctly, the dwarf data will be
+ // messed up in random places by 4 bytes. .debug_line
+ // section will be parsable, but with odd offsets and
+ // line numbers, etc.
+ PointerSize = 8;
}
};
}
diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
index c6561dd..e8c9744 100644
--- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
@@ -12,32 +12,36 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/BPFMCTargetDesc.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCSymbol.h"
-#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+
using namespace llvm;
#define DEBUG_TYPE "mccodeemitter"
namespace {
+
class BPFMCCodeEmitter : public MCCodeEmitter {
- BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;
- void operator=(const BPFMCCodeEmitter &) = delete;
+ const MCInstrInfo &MCII;
const MCRegisterInfo &MRI;
bool IsLittleEndian;
public:
- BPFMCCodeEmitter(const MCRegisterInfo &mri, bool IsLittleEndian)
- : MRI(mri), IsLittleEndian(IsLittleEndian) {}
-
- ~BPFMCCodeEmitter() {}
+ BPFMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
+ bool IsLittleEndian)
+ : MCII(mcii), MRI(mri), IsLittleEndian(IsLittleEndian) {}
+ BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;
+ void operator=(const BPFMCCodeEmitter &) = delete;
+ ~BPFMCCodeEmitter() override = default;
// getBinaryCodeForInstr - TableGen'erated function for getting the
// binary encoding for an instruction.
@@ -58,19 +62,25 @@ public:
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
+
+private:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
};
-}
+
+} // end anonymous namespace
MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx) {
- return new BPFMCCodeEmitter(MRI, true);
+ return new BPFMCCodeEmitter(MCII, MRI, true);
}
MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx) {
- return new BPFMCCodeEmitter(MRI, false);
+ return new BPFMCCodeEmitter(MCII, MRI, false);
}
unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
@@ -108,6 +118,9 @@ static uint8_t SwapBits(uint8_t Val)
void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
unsigned Opcode = MI.getOpcode();
support::endian::Writer<support::little> LE(OS);
support::endian::Writer<support::big> BE(OS);
@@ -165,4 +178,5 @@ uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,
return Encoding;
}
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "BPFGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
index 03d6b19..b584097 100644
--- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
@@ -12,14 +12,13 @@
//===----------------------------------------------------------------------===//
#include "BPF.h"
-#include "BPFMCTargetDesc.h"
-#include "BPFMCAsmInfo.h"
#include "InstPrinter/BPFInstPrinter.h"
+#include "MCTargetDesc/BPFMCTargetDesc.h"
+#include "MCTargetDesc/BPFMCAsmInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#define GET_INSTRINFO_MC_DESC
@@ -64,11 +63,12 @@ static MCInstPrinter *createBPFMCInstPrinter(const Triple &T,
const MCRegisterInfo &MRI) {
if (SyntaxVariant == 0)
return new BPFInstPrinter(MAI, MII, MRI);
- return 0;
+ return nullptr;
}
extern "C" void LLVMInitializeBPFTargetMC() {
- for (Target *T : {&TheBPFleTarget, &TheBPFbeTarget, &TheBPFTarget}) {
+ for (Target *T :
+ {&getTheBPFleTarget(), &getTheBPFbeTarget(), &getTheBPFTarget()}) {
// Register the MC asm info.
RegisterMCAsmInfo<BPFMCAsmInfo> X(*T);
@@ -90,18 +90,26 @@ extern "C" void LLVMInitializeBPFTargetMC() {
}
// Register the MC code emitter
- TargetRegistry::RegisterMCCodeEmitter(TheBPFleTarget, createBPFMCCodeEmitter);
- TargetRegistry::RegisterMCCodeEmitter(TheBPFbeTarget, createBPFbeMCCodeEmitter);
+ TargetRegistry::RegisterMCCodeEmitter(getTheBPFleTarget(),
+ createBPFMCCodeEmitter);
+ TargetRegistry::RegisterMCCodeEmitter(getTheBPFbeTarget(),
+ createBPFbeMCCodeEmitter);
// Register the ASM Backend
- TargetRegistry::RegisterMCAsmBackend(TheBPFleTarget, createBPFAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(TheBPFbeTarget, createBPFbeAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(getTheBPFleTarget(),
+ createBPFAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(getTheBPFbeTarget(),
+ createBPFbeAsmBackend);
if (sys::IsLittleEndianHost) {
- TargetRegistry::RegisterMCCodeEmitter(TheBPFTarget, createBPFMCCodeEmitter);
- TargetRegistry::RegisterMCAsmBackend(TheBPFTarget, createBPFAsmBackend);
+ TargetRegistry::RegisterMCCodeEmitter(getTheBPFTarget(),
+ createBPFMCCodeEmitter);
+ TargetRegistry::RegisterMCAsmBackend(getTheBPFTarget(),
+ createBPFAsmBackend);
} else {
- TargetRegistry::RegisterMCCodeEmitter(TheBPFTarget, createBPFbeMCCodeEmitter);
- TargetRegistry::RegisterMCAsmBackend(TheBPFTarget, createBPFbeAsmBackend);
+ TargetRegistry::RegisterMCCodeEmitter(getTheBPFTarget(),
+ createBPFbeMCCodeEmitter);
+ TargetRegistry::RegisterMCAsmBackend(getTheBPFTarget(),
+ createBPFbeAsmBackend);
}
}
diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
index e2ae652..3df673e 100644
--- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
@@ -25,15 +25,16 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
class StringRef;
class Target;
class Triple;
class raw_ostream;
class raw_pwrite_stream;
-extern Target TheBPFleTarget;
-extern Target TheBPFbeTarget;
-extern Target TheBPFTarget;
+Target &getTheBPFleTarget();
+Target &getTheBPFbeTarget();
+Target &getTheBPFTarget();
MCCodeEmitter *createBPFMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
@@ -43,9 +44,11 @@ MCCodeEmitter *createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx);
MCAsmBackend *createBPFAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createBPFbeAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createBPFELFObjectWriter(raw_pwrite_stream &OS,
uint8_t OSABI, bool IsLittleEndian);
diff --git a/contrib/llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp b/contrib/llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
index a16dbae..265180b 100644
--- a/contrib/llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
@@ -12,17 +12,25 @@
using namespace llvm;
namespace llvm {
-Target TheBPFleTarget;
-Target TheBPFbeTarget;
-Target TheBPFTarget;
+Target &getTheBPFleTarget() {
+ static Target TheBPFleTarget;
+ return TheBPFleTarget;
}
+Target &getTheBPFbeTarget() {
+ static Target TheBPFbeTarget;
+ return TheBPFbeTarget;
+}
+Target &getTheBPFTarget() {
+ static Target TheBPFTarget;
+ return TheBPFTarget;
+}
+} // namespace llvm
extern "C" void LLVMInitializeBPFTargetInfo() {
- TargetRegistry::RegisterTarget(TheBPFTarget, "bpf",
- "BPF (host endian)",
+ TargetRegistry::RegisterTarget(getTheBPFTarget(), "bpf", "BPF (host endian)",
[](Triple::ArchType) { return false; }, true);
- RegisterTarget<Triple::bpfel, /*HasJIT=*/true> X(
- TheBPFleTarget, "bpfel", "BPF (little endian)");
- RegisterTarget<Triple::bpfeb, /*HasJIT=*/true> Y(
- TheBPFbeTarget, "bpfeb", "BPF (big endian)");
+ RegisterTarget<Triple::bpfel, /*HasJIT=*/true> X(getTheBPFleTarget(), "bpfel",
+ "BPF (little endian)");
+ RegisterTarget<Triple::bpfeb, /*HasJIT=*/true> Y(getTheBPFbeTarget(), "bpfeb",
+ "BPF (big endian)");
}
diff --git a/contrib/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp b/contrib/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp
index 496efbf..becc086 100644
--- a/contrib/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp
@@ -10,39 +10,53 @@
#define DEBUG_TYPE "mcasmparser"
#include "Hexagon.h"
-#include "HexagonRegisterInfo.h"
#include "HexagonTargetStreamer.h"
-#include "MCTargetDesc/HexagonBaseInfo.h"
-#include "MCTargetDesc/HexagonMCAsmInfo.h"
#include "MCTargetDesc/HexagonMCChecker.h"
#include "MCTargetDesc/HexagonMCELFStreamer.h"
#include "MCTargetDesc/HexagonMCExpr.h"
-#include "MCTargetDesc/HexagonMCShuffler.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "MCTargetDesc/HexagonShuffler.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/TargetRegistry.h"
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
using namespace llvm;
@@ -65,8 +79,8 @@ static cl::opt<bool> ErrorNoncontigiousRegister("merror-noncontigious-register",
cl::desc("Error for register names that aren't contigious"),
cl::init(false));
-
namespace {
+
struct HexagonOperand;
class HexagonAsmParser : public MCTargetAsmParser {
@@ -93,9 +107,7 @@ class HexagonAsmParser : public MCTargetAsmParser {
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
bool ParseDirectiveFalign(unsigned Size, SMLoc L);
- virtual bool ParseRegister(unsigned &RegNo,
- SMLoc &StartLoc,
- SMLoc &EndLoc) override;
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
bool ParseDirectiveSubsection(SMLoc L);
bool ParseDirectiveValue(unsigned Size, SMLoc L);
bool ParseDirectiveComm(bool IsLocal, SMLoc L);
@@ -114,7 +126,7 @@ class HexagonAsmParser : public MCTargetAsmParser {
uint64_t &ErrorInfo, bool MatchingInlineAsm) override;
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override;
- void OutOfRange(SMLoc IDLoc, long long Val, long long Max);
+ bool OutOfRange(SMLoc IDLoc, long long Val, long long Max);
int processInstruction(MCInst &Inst, OperandVector const &Operands,
SMLoc IDLoc);
@@ -141,14 +153,14 @@ public:
MCII (MII), MCB(HexagonMCInstrInfo::createBundle()), InBrackets(false) {
setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
- MCAsmParserExtension::Initialize(_Parser);
+ MCAsmParserExtension::Initialize(_Parser);
- Assembler = nullptr;
- // FIXME: need better way to detect AsmStreamer (upstream removed getKind())
- if (!Parser.getStreamer().hasRawTextSupport()) {
- MCELFStreamer *MES = static_cast<MCELFStreamer *>(&Parser.getStreamer());
- Assembler = &MES->getAssembler();
- }
+ Assembler = nullptr;
+ // FIXME: need better way to detect AsmStreamer (upstream removed getKind())
+ if (!Parser.getStreamer().hasRawTextSupport()) {
+ MCELFStreamer *MES = static_cast<MCELFStreamer *>(&Parser.getStreamer());
+ Assembler = &MES->getAssembler();
+ }
}
bool splitIdentifier(OperandVector &Operands);
@@ -157,15 +169,17 @@ public:
bool implicitExpressionLocation(OperandVector &Operands);
bool parseExpressionOrOperand(OperandVector &Operands);
bool parseExpression(MCExpr const *& Expr);
- virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- SMLoc NameLoc, OperandVector &Operands) override
+
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc, OperandVector &Operands) override
{
llvm_unreachable("Unimplemented");
}
- virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- AsmToken ID, OperandVector &Operands) override;
- virtual bool ParseDirective(AsmToken DirectiveID) override;
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, AsmToken ID,
+ OperandVector &Operands) override;
+
+ bool ParseDirective(AsmToken DirectiveID) override;
};
/// HexagonOperand - Instances of this class represent a parsed Hexagon machine
@@ -219,12 +233,12 @@ public:
}
/// getStartLoc - Get the location of the first token of this operand.
- SMLoc getStartLoc() const { return StartLoc; }
+ SMLoc getStartLoc() const override { return StartLoc; }
/// getEndLoc - Get the location of the last token of this operand.
- SMLoc getEndLoc() const { return EndLoc; }
+ SMLoc getEndLoc() const override { return EndLoc; }
- unsigned getReg() const {
+ unsigned getReg() const override {
assert(Kind == Register && "Invalid access!");
return Reg.RegNum;
}
@@ -234,10 +248,10 @@ public:
return Imm.Val;
}
- bool isToken() const { return Kind == Token; }
- bool isImm() const { return Kind == Immediate; }
- bool isMem() const { llvm_unreachable("No isMem"); }
- bool isReg() const { return Kind == Register; }
+ bool isToken() const override { return Kind == Token; }
+ bool isImm() const override { return Kind == Immediate; }
+ bool isMem() const override { llvm_unreachable("No isMem"); }
+ bool isReg() const override { return Kind == Register; }
bool CheckImmRange(int immBits, int zeroBits, bool isSigned,
bool isRelocatable, bool Extendable) const {
@@ -259,11 +273,11 @@ public:
if (bits == 64)
return true;
if (Res >= 0)
- return ((uint64_t)Res < (uint64_t)(1ULL << bits)) ? true : false;
+ return ((uint64_t)Res < (uint64_t)(1ULL << bits));
else {
const int64_t high_bit_set = 1ULL << 63;
const uint64_t mask = (high_bit_set >> (63 - bits));
- return (((uint64_t)Res & mask) == mask) ? true : false;
+ return (((uint64_t)Res & mask) == mask);
}
}
} else if (myMCExpr->getKind() == MCExpr::SymbolRef && isRelocatable)
@@ -276,55 +290,60 @@ public:
}
bool isf32Ext() const { return false; }
- bool iss32Imm() const { return CheckImmRange(32, 0, true, true, false); }
+ bool iss32_0Imm() const { return CheckImmRange(32, 0, true, true, false); }
bool iss23_2Imm() const { return CheckImmRange(23, 2, true, true, false); }
- bool iss8Imm() const { return CheckImmRange(8, 0, true, false, false); }
- bool iss8Imm64() const { return CheckImmRange(8, 0, true, true, false); }
- bool iss7Imm() const { return CheckImmRange(7, 0, true, false, false); }
- bool iss6Imm() const { return CheckImmRange(6, 0, true, false, false); }
- bool iss4Imm() const { return CheckImmRange(4, 0, true, false, false); }
+ bool iss8_0Imm() const { return CheckImmRange(8, 0, true, false, false); }
+ bool iss8_0Imm64() const { return CheckImmRange(8, 0, true, true, false); }
+ bool iss7_0Imm() const { return CheckImmRange(7, 0, true, false, false); }
+ bool iss6_0Imm() const { return CheckImmRange(6, 0, true, false, false); }
bool iss4_0Imm() const { return CheckImmRange(4, 0, true, false, false); }
bool iss4_1Imm() const { return CheckImmRange(4, 1, true, false, false); }
bool iss4_2Imm() const { return CheckImmRange(4, 2, true, false, false); }
bool iss4_3Imm() const { return CheckImmRange(4, 3, true, false, false); }
bool iss4_6Imm() const { return CheckImmRange(4, 0, true, false, false); }
bool iss3_6Imm() const { return CheckImmRange(3, 0, true, false, false); }
- bool iss3Imm() const { return CheckImmRange(3, 0, true, false, false); }
+ bool iss3_0Imm() const { return CheckImmRange(3, 0, true, false, false); }
- bool isu64Imm() const { return CheckImmRange(64, 0, false, true, true); }
- bool isu32Imm() const { return CheckImmRange(32, 0, false, true, false); }
+ bool isu64_0Imm() const { return CheckImmRange(64, 0, false, true, true); }
+ bool isu32_0Imm() const { return CheckImmRange(32, 0, false, true, false); }
bool isu26_6Imm() const { return CheckImmRange(26, 6, false, true, false); }
- bool isu16Imm() const { return CheckImmRange(16, 0, false, true, false); }
bool isu16_0Imm() const { return CheckImmRange(16, 0, false, true, false); }
bool isu16_1Imm() const { return CheckImmRange(16, 1, false, true, false); }
bool isu16_2Imm() const { return CheckImmRange(16, 2, false, true, false); }
bool isu16_3Imm() const { return CheckImmRange(16, 3, false, true, false); }
bool isu11_3Imm() const { return CheckImmRange(11, 3, false, false, false); }
- bool isu6_0Imm() const { return CheckImmRange(6, 0, false, false, false); }
bool isu6_1Imm() const { return CheckImmRange(6, 1, false, false, false); }
bool isu6_2Imm() const { return CheckImmRange(6, 2, false, false, false); }
bool isu6_3Imm() const { return CheckImmRange(6, 3, false, false, false); }
- bool isu10Imm() const { return CheckImmRange(10, 0, false, false, false); }
- bool isu9Imm() const { return CheckImmRange(9, 0, false, false, false); }
- bool isu8Imm() const { return CheckImmRange(8, 0, false, false, false); }
- bool isu7Imm() const { return CheckImmRange(7, 0, false, false, false); }
- bool isu6Imm() const { return CheckImmRange(6, 0, false, false, false); }
- bool isu5Imm() const { return CheckImmRange(5, 0, false, false, false); }
- bool isu4Imm() const { return CheckImmRange(4, 0, false, false, false); }
- bool isu3Imm() const { return CheckImmRange(3, 0, false, false, false); }
- bool isu2Imm() const { return CheckImmRange(2, 0, false, false, false); }
- bool isu1Imm() const { return CheckImmRange(1, 0, false, false, false); }
-
- bool ism6Imm() const { return CheckImmRange(6, 0, false, false, false); }
- bool isn8Imm() const { return CheckImmRange(8, 0, false, false, false); }
-
- bool iss16Ext() const { return CheckImmRange(16 + 26, 0, true, true, true); }
- bool iss12Ext() const { return CheckImmRange(12 + 26, 0, true, true, true); }
- bool iss10Ext() const { return CheckImmRange(10 + 26, 0, true, true, true); }
- bool iss9Ext() const { return CheckImmRange(9 + 26, 0, true, true, true); }
- bool iss8Ext() const { return CheckImmRange(8 + 26, 0, true, true, true); }
- bool iss7Ext() const { return CheckImmRange(7 + 26, 0, true, true, true); }
- bool iss6Ext() const { return CheckImmRange(6 + 26, 0, true, true, true); }
+ bool isu10_0Imm() const { return CheckImmRange(10, 0, false, false, false); }
+ bool isu9_0Imm() const { return CheckImmRange(9, 0, false, false, false); }
+ bool isu8_0Imm() const { return CheckImmRange(8, 0, false, false, false); }
+ bool isu7_0Imm() const { return CheckImmRange(7, 0, false, false, false); }
+ bool isu6_0Imm() const { return CheckImmRange(6, 0, false, false, false); }
+ bool isu5_0Imm() const { return CheckImmRange(5, 0, false, false, false); }
+ bool isu4_0Imm() const { return CheckImmRange(4, 0, false, false, false); }
+ bool isu3_0Imm() const { return CheckImmRange(3, 0, false, false, false); }
+ bool isu2_0Imm() const { return CheckImmRange(2, 0, false, false, false); }
+ bool isu1_0Imm() const { return CheckImmRange(1, 0, false, false, false); }
+
+ bool ism6_0Imm() const { return CheckImmRange(6, 0, false, false, false); }
+ bool isn8_0Imm() const { return CheckImmRange(8, 0, false, false, false); }
+ bool isn1Const() const {
+ if (!isImm())
+ return false;
+ int64_t Value;
+ if (!getImm()->evaluateAsAbsolute(Value))
+ return false;
+ return Value == -1;
+ }
+
+ bool iss16_0Ext() const { return CheckImmRange(16 + 26, 0, true, true, true); }
+ bool iss12_0Ext() const { return CheckImmRange(12 + 26, 0, true, true, true); }
+ bool iss10_0Ext() const { return CheckImmRange(10 + 26, 0, true, true, true); }
+ bool iss9_0Ext() const { return CheckImmRange(9 + 26, 0, true, true, true); }
+ bool iss8_0Ext() const { return CheckImmRange(8 + 26, 0, true, true, true); }
+ bool iss7_0Ext() const { return CheckImmRange(7 + 26, 0, true, true, true); }
+ bool iss6_0Ext() const { return CheckImmRange(6 + 26, 0, true, true, true); }
bool iss11_0Ext() const {
return CheckImmRange(11 + 26, 0, true, true, true);
}
@@ -338,16 +357,15 @@ public:
return CheckImmRange(11 + 26, 3, true, true, true);
}
- bool isu6Ext() const { return CheckImmRange(6 + 26, 0, false, true, true); }
- bool isu7Ext() const { return CheckImmRange(7 + 26, 0, false, true, true); }
- bool isu8Ext() const { return CheckImmRange(8 + 26, 0, false, true, true); }
- bool isu9Ext() const { return CheckImmRange(9 + 26, 0, false, true, true); }
- bool isu10Ext() const { return CheckImmRange(10 + 26, 0, false, true, true); }
+ bool isu7_0Ext() const { return CheckImmRange(7 + 26, 0, false, true, true); }
+ bool isu8_0Ext() const { return CheckImmRange(8 + 26, 0, false, true, true); }
+ bool isu9_0Ext() const { return CheckImmRange(9 + 26, 0, false, true, true); }
+ bool isu10_0Ext() const { return CheckImmRange(10 + 26, 0, false, true, true); }
bool isu6_0Ext() const { return CheckImmRange(6 + 26, 0, false, true, true); }
bool isu6_1Ext() const { return CheckImmRange(6 + 26, 1, false, true, true); }
bool isu6_2Ext() const { return CheckImmRange(6 + 26, 2, false, true, true); }
bool isu6_3Ext() const { return CheckImmRange(6 + 26, 3, false, true, true); }
- bool isu32MustExt() const { return isImm(); }
+ bool isu32_0MustExt() const { return isImm(); }
void addRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
@@ -378,22 +396,19 @@ public:
addImmOperands(Inst, N);
}
- void adds32ImmOperands(MCInst &Inst, unsigned N) const {
+ void adds32_0ImmOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
void adds23_2ImmOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds8ImmOperands(MCInst &Inst, unsigned N) const {
- addSignedImmOperands(Inst, N);
- }
- void adds8Imm64Operands(MCInst &Inst, unsigned N) const {
+ void adds8_0ImmOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds6ImmOperands(MCInst &Inst, unsigned N) const {
+ void adds8_0Imm64Operands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds4ImmOperands(MCInst &Inst, unsigned N) const {
+ void adds6_0ImmOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
void adds4_0ImmOperands(MCInst &Inst, unsigned N) const {
@@ -408,22 +423,19 @@ public:
void adds4_3ImmOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds3ImmOperands(MCInst &Inst, unsigned N) const {
+ void adds3_0ImmOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void addu64ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu64_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu32ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu32_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
void addu26_6ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu16ImmOperands(MCInst &Inst, unsigned N) const {
- addImmOperands(Inst, N);
- }
void addu16_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
@@ -439,19 +451,16 @@ public:
void addu11_3ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu10ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu10_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu9ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu9_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu8ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu8_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu7ImmOperands(MCInst &Inst, unsigned N) const {
- addImmOperands(Inst, N);
- }
- void addu6ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu7_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
void addu6_0ImmOperands(MCInst &Inst, unsigned N) const {
@@ -466,45 +475,45 @@ public:
void addu6_3ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu5ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu5_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu4ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu4_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu3ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu3_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu2ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu2_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu1ImmOperands(MCInst &Inst, unsigned N) const {
+ void addu1_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addm6ImmOperands(MCInst &Inst, unsigned N) const {
+ void addm6_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addn8ImmOperands(MCInst &Inst, unsigned N) const {
+ void addn8_0ImmOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void adds16ExtOperands(MCInst &Inst, unsigned N) const {
+ void adds16_0ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds12ExtOperands(MCInst &Inst, unsigned N) const {
+ void adds12_0ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds10ExtOperands(MCInst &Inst, unsigned N) const {
+ void adds10_0ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds9ExtOperands(MCInst &Inst, unsigned N) const {
+ void adds9_0ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds8ExtOperands(MCInst &Inst, unsigned N) const {
+ void adds8_0ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
- void adds6ExtOperands(MCInst &Inst, unsigned N) const {
+ void adds6_0ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
void adds11_0ExtOperands(MCInst &Inst, unsigned N) const {
@@ -519,20 +528,20 @@ public:
void adds11_3ExtOperands(MCInst &Inst, unsigned N) const {
addSignedImmOperands(Inst, N);
}
-
- void addu6ExtOperands(MCInst &Inst, unsigned N) const {
+ void addn1ConstOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu7ExtOperands(MCInst &Inst, unsigned N) const {
+
+ void addu7_0ExtOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu8ExtOperands(MCInst &Inst, unsigned N) const {
+ void addu8_0ExtOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu9ExtOperands(MCInst &Inst, unsigned N) const {
+ void addu9_0ExtOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu10ExtOperands(MCInst &Inst, unsigned N) const {
+ void addu10_0ExtOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
void addu6_0ExtOperands(MCInst &Inst, unsigned N) const {
@@ -547,7 +556,7 @@ public:
void addu6_3ExtOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
- void addu32MustExtOperands(MCInst &Inst, unsigned N) const {
+ void addu32_0MustExtOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N);
}
@@ -570,7 +579,7 @@ public:
return StringRef(Tok.Data, Tok.Length);
}
- virtual void print(raw_ostream &OS) const;
+ void print(raw_ostream &OS) const override;
static std::unique_ptr<HexagonOperand> CreateToken(StringRef Str, SMLoc S) {
HexagonOperand *Op = new HexagonOperand(Token);
@@ -600,7 +609,7 @@ public:
}
};
-} // end anonymous namespace.
+} // end anonymous namespace
void HexagonOperand::print(raw_ostream &OS) const {
switch (Kind) {
@@ -630,67 +639,70 @@ bool HexagonAsmParser::finishBundle(SMLoc IDLoc, MCStreamer &Out) {
getContext(), MCB,
&Check);
- while (Check.getNextErrInfo() == true) {
+ while (Check.getNextErrInfo()) {
unsigned Reg = Check.getErrRegister();
Twine R(RI->getName(Reg));
uint64_t Err = Check.getError();
if (Err != HexagonMCErrInfo::CHECK_SUCCESS) {
if (HexagonMCErrInfo::CHECK_ERROR_BRANCHES & Err)
- Error(IDLoc,
- "unconditional branch cannot precede another branch in packet");
+ return Error(
+ IDLoc,
+ "unconditional branch cannot precede another branch in packet");
if (HexagonMCErrInfo::CHECK_ERROR_NEWP & Err ||
HexagonMCErrInfo::CHECK_ERROR_NEWV & Err)
- Error(IDLoc, "register `" + R +
- "' used with `.new' "
- "but not validly modified in the same packet");
+ return Error(IDLoc, "register `" + R +
+ "' used with `.new' "
+ "but not validly modified in the same packet");
if (HexagonMCErrInfo::CHECK_ERROR_REGISTERS & Err)
- Error(IDLoc, "register `" + R + "' modified more than once");
+ return Error(IDLoc, "register `" + R + "' modified more than once");
if (HexagonMCErrInfo::CHECK_ERROR_READONLY & Err)
- Error(IDLoc, "cannot write to read-only register `" + R + "'");
+ return Error(IDLoc, "cannot write to read-only register `" + R + "'");
if (HexagonMCErrInfo::CHECK_ERROR_LOOP & Err)
- Error(IDLoc, "loop-setup and some branch instructions "
- "cannot be in the same packet");
+ return Error(IDLoc, "loop-setup and some branch instructions "
+ "cannot be in the same packet");
if (HexagonMCErrInfo::CHECK_ERROR_ENDLOOP & Err) {
Twine N(HexagonMCInstrInfo::isInnerLoop(MCB) ? '0' : '1');
- Error(IDLoc, "packet marked with `:endloop" + N + "' " +
+ return Error(IDLoc,
+ "packet marked with `:endloop" + N + "' " +
"cannot contain instructions that modify register " +
"`" + R + "'");
}
if (HexagonMCErrInfo::CHECK_ERROR_SOLO & Err)
- Error(IDLoc,
- "instruction cannot appear in packet with other instructions");
+ return Error(
+ IDLoc,
+ "instruction cannot appear in packet with other instructions");
if (HexagonMCErrInfo::CHECK_ERROR_NOSLOTS & Err)
- Error(IDLoc, "too many slots used in packet");
+ return Error(IDLoc, "too many slots used in packet");
if (Err & HexagonMCErrInfo::CHECK_ERROR_SHUFFLE) {
uint64_t Erm = Check.getShuffleError();
if (HexagonShuffler::SHUFFLE_ERROR_INVALID == Erm)
- Error(IDLoc, "invalid instruction packet");
+ return Error(IDLoc, "invalid instruction packet");
else if (HexagonShuffler::SHUFFLE_ERROR_STORES == Erm)
- Error(IDLoc, "invalid instruction packet: too many stores");
+ return Error(IDLoc, "invalid instruction packet: too many stores");
else if (HexagonShuffler::SHUFFLE_ERROR_LOADS == Erm)
- Error(IDLoc, "invalid instruction packet: too many loads");
+ return Error(IDLoc, "invalid instruction packet: too many loads");
else if (HexagonShuffler::SHUFFLE_ERROR_BRANCHES == Erm)
- Error(IDLoc, "too many branches in packet");
+ return Error(IDLoc, "too many branches in packet");
else if (HexagonShuffler::SHUFFLE_ERROR_NOSLOTS == Erm)
- Error(IDLoc, "invalid instruction packet: out of slots");
+ return Error(IDLoc, "invalid instruction packet: out of slots");
else if (HexagonShuffler::SHUFFLE_ERROR_SLOTS == Erm)
- Error(IDLoc, "invalid instruction packet: slot error");
+ return Error(IDLoc, "invalid instruction packet: slot error");
else if (HexagonShuffler::SHUFFLE_ERROR_ERRATA2 == Erm)
- Error(IDLoc, "v60 packet violation");
+ return Error(IDLoc, "v60 packet violation");
else if (HexagonShuffler::SHUFFLE_ERROR_STORE_LOAD_CONFLICT == Erm)
- Error(IDLoc, "slot 0 instruction does not allow slot 1 store");
+ return Error(IDLoc, "slot 0 instruction does not allow slot 1 store");
else
- Error(IDLoc, "unknown error in instruction packet");
+ return Error(IDLoc, "unknown error in instruction packet");
}
}
@@ -878,7 +890,7 @@ bool HexagonAsmParser::ParseDirective(AsmToken DirectiveID) {
return true;
}
bool HexagonAsmParser::ParseDirectiveSubsection(SMLoc L) {
- const MCExpr *Subsection = 0;
+ const MCExpr *Subsection = nullptr;
int64_t Res;
assert((getLexer().isNot(AsmToken::EndOfStatement)) &&
@@ -908,13 +920,13 @@ bool HexagonAsmParser::ParseDirectiveFalign(unsigned Size, SMLoc L) {
int64_t MaxBytesToFill = 15;
- // if there is an arguement
+ // if there is an argument
if (getLexer().isNot(AsmToken::EndOfStatement)) {
const MCExpr *Value;
SMLoc ExprLoc = L;
// Make sure we have a number (false is returned if expression is a number)
- if (getParser().parseExpression(Value) == false) {
+ if (!getParser().parseExpression(Value)) {
// Make sure this is a number that is in range
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);
uint64_t IntValue = MCE->getValue();
@@ -936,8 +948,7 @@ bool HexagonAsmParser::ParseDirectiveFalign(unsigned Size, SMLoc L) {
/// ::= .word [ expression (, expression)* ]
bool HexagonAsmParser::ParseDirectiveValue(unsigned Size, SMLoc L) {
if (getLexer().isNot(AsmToken::EndOfStatement)) {
-
- for (;;) {
+ while (true) {
const MCExpr *Value;
SMLoc ExprLoc = L;
if (getParser().parseExpression(Value))
@@ -1062,15 +1073,15 @@ bool HexagonAsmParser::RegisterMatchesArch(unsigned MatchNum) const {
/// Force static initialization.
extern "C" void LLVMInitializeHexagonAsmParser() {
- RegisterMCAsmParser<HexagonAsmParser> X(TheHexagonTarget);
+ RegisterMCAsmParser<HexagonAsmParser> X(getTheHexagonTarget());
}
#define GET_MATCHER_IMPLEMENTATION
#define GET_REGISTER_MATCHER
#include "HexagonGenAsmMatcher.inc"
-namespace {
-bool previousEqual(OperandVector &Operands, size_t Index, StringRef String) {
+static bool previousEqual(OperandVector &Operands, size_t Index,
+ StringRef String) {
if (Index >= Operands.size())
return false;
MCParsedAsmOperand &Operand = *Operands[Operands.size() - Index - 1];
@@ -1078,14 +1089,14 @@ bool previousEqual(OperandVector &Operands, size_t Index, StringRef String) {
return false;
return static_cast<HexagonOperand &>(Operand).getToken().equals_lower(String);
}
-bool previousIsLoop(OperandVector &Operands, size_t Index) {
+
+static bool previousIsLoop(OperandVector &Operands, size_t Index) {
return previousEqual(Operands, Index, "loop0") ||
previousEqual(Operands, Index, "loop1") ||
previousEqual(Operands, Index, "sp1loop0") ||
previousEqual(Operands, Index, "sp2loop0") ||
previousEqual(Operands, Index, "sp3loop0");
}
-}
bool HexagonAsmParser::splitIdentifier(OperandVector &Operands) {
AsmToken const &Token = getParser().getTok();
@@ -1174,8 +1185,7 @@ bool HexagonAsmParser::isLabel(AsmToken &Token) {
StringRef Raw (String.data(), Third.getString().data() - String.data() +
Third.getString().size());
std::string Collapsed = Raw;
- Collapsed.erase(std::remove_if(Collapsed.begin(), Collapsed.end(), isspace),
- Collapsed.end());
+ Collapsed.erase(llvm::remove_if(Collapsed, isspace), Collapsed.end());
StringRef Whole = Collapsed;
std::pair<StringRef, StringRef> DotSplit = Whole.split('.');
if (!matchRegister(DotSplit.first.lower()))
@@ -1219,8 +1229,7 @@ bool HexagonAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &En
NeededWorkaround = NeededWorkaround || (Again && !(Contigious && Type));
}
std::string Collapsed = RawString;
- Collapsed.erase(std::remove_if(Collapsed.begin(), Collapsed.end(), isspace),
- Collapsed.end());
+ Collapsed.erase(llvm::remove_if(Collapsed, isspace), Collapsed.end());
StringRef FullString = Collapsed;
std::pair<StringRef, StringRef> DotSplit = FullString.split('.');
unsigned DotReg = matchRegister(DotSplit.first.lower());
@@ -1277,7 +1286,7 @@ bool HexagonAsmParser::implicitExpressionLocation(OperandVector &Operands) {
}
bool HexagonAsmParser::parseExpression(MCExpr const *& Expr) {
- llvm::SmallVector<AsmToken, 4> Tokens;
+ SmallVector<AsmToken, 4> Tokens;
MCAsmLexer &Lexer = getLexer();
bool Done = false;
static char const * Comma = ",";
@@ -1456,9 +1465,8 @@ bool HexagonAsmParser::ParseInstruction(ParseInstructionInfo &Info,
return parseInstruction(Operands);
}
-namespace {
-MCInst makeCombineInst(int opCode, MCOperand &Rdd,
- MCOperand &MO1, MCOperand &MO2) {
+static MCInst makeCombineInst(int opCode, MCOperand &Rdd,
+ MCOperand &MO1, MCOperand &MO2) {
MCInst TmpInst;
TmpInst.setOpcode(opCode);
TmpInst.addOperand(Rdd);
@@ -1467,7 +1475,6 @@ MCInst makeCombineInst(int opCode, MCOperand &Rdd,
return TmpInst;
}
-}
// Define this matcher function after the auto-generated include so we
// have the match class enum definitions.
@@ -1488,12 +1495,6 @@ unsigned HexagonAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
? Match_Success
: Match_InvalidOperand;
}
- case MCK__MINUS_1: {
- int64_t Value;
- return Op->isImm() && Op->Imm.Val->evaluateAsAbsolute(Value) && Value == -1
- ? Match_Success
- : Match_InvalidOperand;
- }
}
if (Op->Kind == HexagonOperand::Token && Kind != InvalidMatchClass) {
StringRef myStringRef = StringRef(Op->Tok.Data, Op->Tok.Length);
@@ -1510,7 +1511,8 @@ unsigned HexagonAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
return Match_InvalidOperand;
}
-void HexagonAsmParser::OutOfRange(SMLoc IDLoc, long long Val, long long Max) {
+// FIXME: Calls to OutOfRange shoudl propagate failure up to parseStatement.
+bool HexagonAsmParser::OutOfRange(SMLoc IDLoc, long long Val, long long Max) {
std::string errStr;
raw_string_ostream ES(errStr);
ES << "value " << Val << "(" << format_hex(Val, 0) << ") out of range: ";
@@ -1518,7 +1520,7 @@ void HexagonAsmParser::OutOfRange(SMLoc IDLoc, long long Val, long long Max) {
ES << "0-" << Max;
else
ES << Max << "-" << (-Max - 1);
- Error(IDLoc, ES.str().c_str());
+ return Parser.printError(IDLoc, ES.str());
}
int HexagonAsmParser::processInstruction(MCInst &Inst,
@@ -1599,11 +1601,11 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
case Hexagon::A2_tfrp: {
MCOperand &MO = Inst.getOperand(1);
unsigned int RegPairNum = RI->getEncodingValue(MO.getReg());
- std::string R1 = r + llvm::utostr(RegPairNum + 1);
+ std::string R1 = r + utostr(RegPairNum + 1);
StringRef Reg1(R1);
MO.setReg(matchRegister(Reg1));
// Add a new operand for the second register in the pair.
- std::string R2 = r + llvm::utostr(RegPairNum);
+ std::string R2 = r + utostr(RegPairNum);
StringRef Reg2(R2);
Inst.addOperand(MCOperand::createReg(matchRegister(Reg2)));
Inst.setOpcode(Hexagon::A2_combinew);
@@ -1614,11 +1616,11 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
case Hexagon::A2_tfrpf: {
MCOperand &MO = Inst.getOperand(2);
unsigned int RegPairNum = RI->getEncodingValue(MO.getReg());
- std::string R1 = r + llvm::utostr(RegPairNum + 1);
+ std::string R1 = r + utostr(RegPairNum + 1);
StringRef Reg1(R1);
MO.setReg(matchRegister(Reg1));
// Add a new operand for the second register in the pair.
- std::string R2 = r + llvm::utostr(RegPairNum);
+ std::string R2 = r + utostr(RegPairNum);
StringRef Reg2(R2);
Inst.addOperand(MCOperand::createReg(matchRegister(Reg2)));
Inst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrpt)
@@ -1630,11 +1632,11 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
case Hexagon::A2_tfrpfnew: {
MCOperand &MO = Inst.getOperand(2);
unsigned int RegPairNum = RI->getEncodingValue(MO.getReg());
- std::string R1 = r + llvm::utostr(RegPairNum + 1);
+ std::string R1 = r + utostr(RegPairNum + 1);
StringRef Reg1(R1);
MO.setReg(matchRegister(Reg1));
// Add a new operand for the second register in the pair.
- std::string R2 = r + llvm::utostr(RegPairNum);
+ std::string R2 = r + utostr(RegPairNum);
StringRef Reg2(R2);
Inst.addOperand(MCOperand::createReg(matchRegister(Reg2)));
Inst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrptnew)
@@ -1644,13 +1646,13 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
}
// Translate a "$Vdd = $Vss" to "$Vdd = vcombine($Vs, $Vt)"
- case Hexagon::HEXAGON_V6_vassignpair: {
+ case Hexagon::V6_vassignp: {
MCOperand &MO = Inst.getOperand(1);
unsigned int RegPairNum = RI->getEncodingValue(MO.getReg());
- std::string R1 = v + llvm::utostr(RegPairNum + 1);
+ std::string R1 = v + utostr(RegPairNum + 1);
MO.setReg(MatchRegisterName(R1));
// Add a new operand for the second register in the pair.
- std::string R2 = v + llvm::utostr(RegPairNum);
+ std::string R2 = v + utostr(RegPairNum);
Inst.addOperand(MCOperand::createReg(MatchRegisterName(R2)));
Inst.setOpcode(Hexagon::V6_vcombine);
break;
@@ -1658,14 +1660,9 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
// Translate a "$Rx = CONST32(#imm)" to "$Rx = memw(gp+#LABEL) "
case Hexagon::CONST32:
- case Hexagon::CONST32_Float_Real:
- case Hexagon::CONST32_Int_Real:
- case Hexagon::FCONST32_nsdata:
is32bit = true;
// Translate a "$Rx:y = CONST64(#imm)" to "$Rx:y = memd(gp+#LABEL) "
- case Hexagon::CONST64_Float_Real:
- case Hexagon::CONST64_Int_Real:
-
+ case Hexagon::CONST64:
// FIXME: need better way to detect AsmStreamer (upstream removed getKind())
if (!Parser.getStreamer().hasRawTextSupport()) {
MCELFStreamer *MES = static_cast<MCELFStreamer *>(&Parser.getStreamer());
@@ -1725,8 +1722,8 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
getStreamer().EmitIntValue(Value, byteSize);
}
} else if (MO_1.isExpr()) {
- const char *StringStart = 0;
- const char *StringEnd = 0;
+ const char *StringStart = nullptr;
+ const char *StringEnd = nullptr;
if (*Operands[4]->getStartLoc().getPointer() == '#') {
StringStart = Operands[5]->getStartLoc().getPointer();
StringEnd = Operands[6]->getStartLoc().getPointer();
@@ -1832,10 +1829,9 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
break;
}
- case Hexagon::S2_tableidxb_goodsyntax: {
+ case Hexagon::S2_tableidxb_goodsyntax:
Inst.setOpcode(Hexagon::S2_tableidxb);
break;
- }
case Hexagon::S2_tableidxh_goodsyntax: {
MCInst TmpInst;
@@ -1894,10 +1890,9 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
break;
}
- case Hexagon::M2_mpyui: {
+ case Hexagon::M2_mpyui:
Inst.setOpcode(Hexagon::M2_mpyi);
break;
- }
case Hexagon::M2_mpysmi: {
MCInst TmpInst;
MCOperand &Rd = Inst.getOperand(0);
@@ -1970,11 +1965,11 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
if (Value == 0) { // convert to $Rdd = combine ($Rs[0], $Rs[1])
MCInst TmpInst;
unsigned int RegPairNum = RI->getEncodingValue(Rss.getReg());
- std::string R1 = r + llvm::utostr(RegPairNum + 1);
+ std::string R1 = r + utostr(RegPairNum + 1);
StringRef Reg1(R1);
Rss.setReg(matchRegister(Reg1));
// Add a new operand for the second register in the pair.
- std::string R2 = r + llvm::utostr(RegPairNum);
+ std::string R2 = r + utostr(RegPairNum);
StringRef Reg2(R2);
TmpInst.setOpcode(Hexagon::A2_combinew);
TmpInst.addOperand(Rdd);
@@ -1996,14 +1991,12 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
unsigned int RegNum = RI->getEncodingValue(Rs.getReg());
if (RegNum & 1) { // Odd mapped to raw:hi, regpair is rodd:odd-1, like r3:2
Inst.setOpcode(Hexagon::A4_boundscheck_hi);
- std::string Name =
- r + llvm::utostr(RegNum) + Colon + llvm::utostr(RegNum - 1);
+ std::string Name = r + utostr(RegNum) + Colon + utostr(RegNum - 1);
StringRef RegPair = Name;
Rs.setReg(matchRegister(RegPair));
} else { // raw:lo
Inst.setOpcode(Hexagon::A4_boundscheck_lo);
- std::string Name =
- r + llvm::utostr(RegNum + 1) + Colon + llvm::utostr(RegNum);
+ std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
StringRef RegPair = Name;
Rs.setReg(matchRegister(RegPair));
}
@@ -2015,14 +2008,12 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
unsigned int RegNum = RI->getEncodingValue(Rs.getReg());
if (RegNum & 1) { // Odd mapped to raw:hi
Inst.setOpcode(Hexagon::A2_addsph);
- std::string Name =
- r + llvm::utostr(RegNum) + Colon + llvm::utostr(RegNum - 1);
+ std::string Name = r + utostr(RegNum) + Colon + utostr(RegNum - 1);
StringRef RegPair = Name;
Rs.setReg(matchRegister(RegPair));
} else { // Even mapped raw:lo
Inst.setOpcode(Hexagon::A2_addspl);
- std::string Name =
- r + llvm::utostr(RegNum + 1) + Colon + llvm::utostr(RegNum);
+ std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
StringRef RegPair = Name;
Rs.setReg(matchRegister(RegPair));
}
@@ -2034,14 +2025,12 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
unsigned int RegNum = RI->getEncodingValue(Rt.getReg());
if (RegNum & 1) { // Odd mapped to sat:raw:hi
Inst.setOpcode(Hexagon::M2_vrcmpys_s1_h);
- std::string Name =
- r + llvm::utostr(RegNum) + Colon + llvm::utostr(RegNum - 1);
+ std::string Name = r + utostr(RegNum) + Colon + utostr(RegNum - 1);
StringRef RegPair = Name;
Rt.setReg(matchRegister(RegPair));
} else { // Even mapped sat:raw:lo
Inst.setOpcode(Hexagon::M2_vrcmpys_s1_l);
- std::string Name =
- r + llvm::utostr(RegNum + 1) + Colon + llvm::utostr(RegNum);
+ std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
StringRef RegPair = Name;
Rt.setReg(matchRegister(RegPair));
}
@@ -2056,14 +2045,12 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
unsigned int RegNum = RI->getEncodingValue(Rt.getReg());
if (RegNum & 1) { // Odd mapped to sat:raw:hi
TmpInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_h);
- std::string Name =
- r + llvm::utostr(RegNum) + Colon + llvm::utostr(RegNum - 1);
+ std::string Name = r + utostr(RegNum) + Colon + utostr(RegNum - 1);
StringRef RegPair = Name;
Rt.setReg(matchRegister(RegPair));
} else { // Even mapped sat:raw:lo
TmpInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_l);
- std::string Name =
- r + llvm::utostr(RegNum + 1) + Colon + llvm::utostr(RegNum);
+ std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
StringRef RegPair = Name;
Rt.setReg(matchRegister(RegPair));
}
@@ -2081,14 +2068,12 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
unsigned int RegNum = RI->getEncodingValue(Rt.getReg());
if (RegNum & 1) { // Odd mapped to rnd:sat:raw:hi
Inst.setOpcode(Hexagon::M2_vrcmpys_s1rp_h);
- std::string Name =
- r + llvm::utostr(RegNum) + Colon + llvm::utostr(RegNum - 1);
+ std::string Name = r + utostr(RegNum) + Colon + utostr(RegNum - 1);
StringRef RegPair = Name;
Rt.setReg(matchRegister(RegPair));
} else { // Even mapped rnd:sat:raw:lo
Inst.setOpcode(Hexagon::M2_vrcmpys_s1rp_l);
- std::string Name =
- r + llvm::utostr(RegNum + 1) + Colon + llvm::utostr(RegNum);
+ std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
StringRef RegPair = Name;
Rt.setReg(matchRegister(RegPair));
}
@@ -2124,11 +2109,11 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
if (Value == 0) {
MCInst TmpInst;
unsigned int RegPairNum = RI->getEncodingValue(Rss.getReg());
- std::string R1 = r + llvm::utostr(RegPairNum + 1);
+ std::string R1 = r + utostr(RegPairNum + 1);
StringRef Reg1(R1);
Rss.setReg(matchRegister(Reg1));
// Add a new operand for the second register in the pair.
- std::string R2 = r + llvm::utostr(RegPairNum);
+ std::string R2 = r + utostr(RegPairNum);
StringRef Reg2(R2);
TmpInst.setOpcode(Hexagon::A2_combinew);
TmpInst.addOperand(Rdd);
@@ -2162,7 +2147,6 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
return Match_Success;
}
-
unsigned HexagonAsmParser::matchRegister(StringRef Name) {
if (unsigned Reg = MatchRegisterName(Name))
return Reg;
diff --git a/contrib/llvm/lib/Target/Hexagon/BitTracker.cpp b/contrib/llvm/lib/Target/Hexagon/BitTracker.cpp
index d052a83..963fb99 100644
--- a/contrib/llvm/lib/Target/Hexagon/BitTracker.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/BitTracker.cpp
@@ -53,28 +53,36 @@
//
// The code below is intended to be fully target-independent.
+#include "BitTracker.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetRegisterInfo.h"
-
-#include "BitTracker.h"
+#include <iterator>
+#include <cassert>
+#include <cstdint>
using namespace llvm;
typedef BitTracker BT;
namespace {
+
// Local trickery to pretty print a register (without the whole "%vreg"
// business).
struct printv {
printv(unsigned r) : R(r) {}
+
unsigned R;
};
+
raw_ostream &operator<< (raw_ostream &OS, const printv &PV) {
if (PV.R)
OS << 'v' << TargetRegisterInfo::virtReg2Index(PV.R);
@@ -82,9 +90,11 @@ namespace {
OS << 's';
return OS;
}
-}
+
+} // end anonymous namespace
namespace llvm {
+
raw_ostream &operator<<(raw_ostream &OS, const BT::BitValue &BV) {
switch (BV.Type) {
case BT::BitValue::Top:
@@ -167,6 +177,12 @@ namespace llvm {
return OS;
}
+
+} // end namespace llvm
+
+void BitTracker::print_cells(raw_ostream &OS) const {
+ for (CellMapType::iterator I = Map.begin(), E = Map.end(); I != E; ++I)
+ dbgs() << PrintReg(I->first, &ME.TRI) << " -> " << I->second << "\n";
}
BitTracker::BitTracker(const MachineEvaluator &E, MachineFunction &F)
@@ -176,7 +192,6 @@ BitTracker::~BitTracker() {
delete &Map;
}
-
// If we were allowed to update a cell for a part of a register, the meet
// operation would need to be parametrized by the register number and the
// exact part of the register, so that the computer BitRefs correspond to
@@ -195,7 +210,6 @@ bool BT::RegisterCell::meet(const RegisterCell &RC, unsigned SelfR) {
return Changed;
}
-
// Insert the entire cell RC into the current cell at position given by M.
BT::RegisterCell &BT::RegisterCell::insert(const BT::RegisterCell &RC,
const BitMask &M) {
@@ -218,7 +232,6 @@ BT::RegisterCell &BT::RegisterCell::insert(const BT::RegisterCell &RC,
return *this;
}
-
BT::RegisterCell BT::RegisterCell::extract(const BitMask &M) const {
uint16_t B = M.first(), E = M.last(), W = width();
assert(B < W && E < W);
@@ -237,7 +250,6 @@ BT::RegisterCell BT::RegisterCell::extract(const BitMask &M) const {
return RC;
}
-
BT::RegisterCell &BT::RegisterCell::rol(uint16_t Sh) {
// Rotate left (i.e. towards increasing bit indices).
// Swap the two parts: [0..W-Sh-1] [W-Sh..W-1]
@@ -259,7 +271,6 @@ BT::RegisterCell &BT::RegisterCell::rol(uint16_t Sh) {
return *this;
}
-
BT::RegisterCell &BT::RegisterCell::fill(uint16_t B, uint16_t E,
const BitValue &V) {
assert(B <= E);
@@ -268,7 +279,6 @@ BT::RegisterCell &BT::RegisterCell::fill(uint16_t B, uint16_t E,
return *this;
}
-
BT::RegisterCell &BT::RegisterCell::cat(const RegisterCell &RC) {
// Append the cell given as the argument to the "this" cell.
// Bit 0 of RC becomes bit W of the result, where W is this->width().
@@ -279,7 +289,6 @@ BT::RegisterCell &BT::RegisterCell::cat(const RegisterCell &RC) {
return *this;
}
-
uint16_t BT::RegisterCell::ct(bool B) const {
uint16_t W = width();
uint16_t C = 0;
@@ -289,7 +298,6 @@ uint16_t BT::RegisterCell::ct(bool B) const {
return C;
}
-
uint16_t BT::RegisterCell::cl(bool B) const {
uint16_t W = width();
uint16_t C = 0;
@@ -299,7 +307,6 @@ uint16_t BT::RegisterCell::cl(bool B) const {
return C;
}
-
bool BT::RegisterCell::operator== (const RegisterCell &RC) const {
uint16_t W = Bits.size();
if (RC.Bits.size() != W)
@@ -310,7 +317,6 @@ bool BT::RegisterCell::operator== (const RegisterCell &RC) const {
return true;
}
-
uint16_t BT::MachineEvaluator::getRegBitWidth(const RegisterRef &RR) const {
// The general problem is with finding a register class that corresponds
// to a given reference reg:sub. There can be several such classes, and
@@ -336,7 +342,6 @@ uint16_t BT::MachineEvaluator::getRegBitWidth(const RegisterRef &RR) const {
return BW;
}
-
BT::RegisterCell BT::MachineEvaluator::getCell(const RegisterRef &RR,
const CellMapType &M) const {
uint16_t BW = getRegBitWidth(RR);
@@ -364,7 +369,6 @@ BT::RegisterCell BT::MachineEvaluator::getCell(const RegisterRef &RR,
return RegisterCell::top(BW);
}
-
void BT::MachineEvaluator::putCell(const RegisterRef &RR, RegisterCell RC,
CellMapType &M) const {
// While updating the cell map can be done in a meaningful way for
@@ -382,7 +386,6 @@ void BT::MachineEvaluator::putCell(const RegisterRef &RR, RegisterCell RC,
M[RR.Reg] = RC;
}
-
// Check if the cell represents a compile-time integer value.
bool BT::MachineEvaluator::isInt(const RegisterCell &A) const {
uint16_t W = A.width();
@@ -392,7 +395,6 @@ bool BT::MachineEvaluator::isInt(const RegisterCell &A) const {
return true;
}
-
// Convert a cell to the integer value. The result must fit in uint64_t.
uint64_t BT::MachineEvaluator::toInt(const RegisterCell &A) const {
assert(isInt(A));
@@ -405,7 +407,6 @@ uint64_t BT::MachineEvaluator::toInt(const RegisterCell &A) const {
return Val;
}
-
// Evaluator helper functions. These implement some common operation on
// register cells that can be used to implement target-specific instructions
// in a target-specific evaluator.
@@ -420,7 +421,6 @@ BT::RegisterCell BT::MachineEvaluator::eIMM(int64_t V, uint16_t W) const {
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eIMM(const ConstantInt *CI) const {
const APInt &A = CI->getValue();
uint16_t BW = A.getBitWidth();
@@ -431,7 +431,6 @@ BT::RegisterCell BT::MachineEvaluator::eIMM(const ConstantInt *CI) const {
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eADD(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width();
@@ -465,7 +464,6 @@ BT::RegisterCell BT::MachineEvaluator::eADD(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eSUB(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width();
@@ -499,29 +497,26 @@ BT::RegisterCell BT::MachineEvaluator::eSUB(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eMLS(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width() + A2.width();
- uint16_t Z = A1.ct(0) + A2.ct(0);
+ uint16_t Z = A1.ct(false) + A2.ct(false);
RegisterCell Res(W);
Res.fill(0, Z, BitValue::Zero);
Res.fill(Z, W, BitValue::self());
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eMLU(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width() + A2.width();
- uint16_t Z = A1.ct(0) + A2.ct(0);
+ uint16_t Z = A1.ct(false) + A2.ct(false);
RegisterCell Res(W);
Res.fill(0, Z, BitValue::Zero);
Res.fill(Z, W, BitValue::self());
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eASL(const RegisterCell &A1,
uint16_t Sh) const {
assert(Sh <= A1.width());
@@ -531,7 +526,6 @@ BT::RegisterCell BT::MachineEvaluator::eASL(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eLSR(const RegisterCell &A1,
uint16_t Sh) const {
uint16_t W = A1.width();
@@ -542,7 +536,6 @@ BT::RegisterCell BT::MachineEvaluator::eLSR(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eASR(const RegisterCell &A1,
uint16_t Sh) const {
uint16_t W = A1.width();
@@ -554,7 +547,6 @@ BT::RegisterCell BT::MachineEvaluator::eASR(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eAND(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width();
@@ -577,7 +569,6 @@ BT::RegisterCell BT::MachineEvaluator::eAND(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eORL(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width();
@@ -600,7 +591,6 @@ BT::RegisterCell BT::MachineEvaluator::eORL(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eXOR(const RegisterCell &A1,
const RegisterCell &A2) const {
uint16_t W = A1.width();
@@ -621,7 +611,6 @@ BT::RegisterCell BT::MachineEvaluator::eXOR(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eNOT(const RegisterCell &A1) const {
uint16_t W = A1.width();
RegisterCell Res(W);
@@ -637,7 +626,6 @@ BT::RegisterCell BT::MachineEvaluator::eNOT(const RegisterCell &A1) const {
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eSET(const RegisterCell &A1,
uint16_t BitN) const {
assert(BitN < A1.width());
@@ -646,7 +634,6 @@ BT::RegisterCell BT::MachineEvaluator::eSET(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eCLR(const RegisterCell &A1,
uint16_t BitN) const {
assert(BitN < A1.width());
@@ -655,7 +642,6 @@ BT::RegisterCell BT::MachineEvaluator::eCLR(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eCLB(const RegisterCell &A1, bool B,
uint16_t W) const {
uint16_t C = A1.cl(B), AW = A1.width();
@@ -666,7 +652,6 @@ BT::RegisterCell BT::MachineEvaluator::eCLB(const RegisterCell &A1, bool B,
return RegisterCell::self(0, W);
}
-
BT::RegisterCell BT::MachineEvaluator::eCTB(const RegisterCell &A1, bool B,
uint16_t W) const {
uint16_t C = A1.ct(B), AW = A1.width();
@@ -677,7 +662,6 @@ BT::RegisterCell BT::MachineEvaluator::eCTB(const RegisterCell &A1, bool B,
return RegisterCell::self(0, W);
}
-
BT::RegisterCell BT::MachineEvaluator::eSXT(const RegisterCell &A1,
uint16_t FromN) const {
uint16_t W = A1.width();
@@ -689,7 +673,6 @@ BT::RegisterCell BT::MachineEvaluator::eSXT(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eZXT(const RegisterCell &A1,
uint16_t FromN) const {
uint16_t W = A1.width();
@@ -699,7 +682,6 @@ BT::RegisterCell BT::MachineEvaluator::eZXT(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eXTR(const RegisterCell &A1,
uint16_t B, uint16_t E) const {
uint16_t W = A1.width();
@@ -712,7 +694,6 @@ BT::RegisterCell BT::MachineEvaluator::eXTR(const RegisterCell &A1,
return Res;
}
-
BT::RegisterCell BT::MachineEvaluator::eINS(const RegisterCell &A1,
const RegisterCell &A2, uint16_t AtN) const {
uint16_t W1 = A1.width(), W2 = A2.width();
@@ -725,7 +706,6 @@ BT::RegisterCell BT::MachineEvaluator::eINS(const RegisterCell &A1,
return Res;
}
-
BT::BitMask BT::MachineEvaluator::mask(unsigned Reg, unsigned Sub) const {
assert(Sub == 0 && "Generic BitTracker::mask called for Sub != 0");
uint16_t W = getRegBitWidth(Reg);
@@ -779,7 +759,6 @@ bool BT::MachineEvaluator::evaluate(const MachineInstr &MI,
return true;
}
-
// Main W-Z implementation.
void BT::visitPHI(const MachineInstr &PI) {
@@ -971,7 +950,6 @@ void BT::visitBranchesFrom(const MachineInstr &BI) {
}
}
-
void BT::visitUsesOf(unsigned Reg) {
if (Trace)
dbgs() << "visiting uses of " << PrintReg(Reg, &ME.TRI) << "\n";
@@ -991,17 +969,14 @@ void BT::visitUsesOf(unsigned Reg) {
}
}
-
BT::RegisterCell BT::get(RegisterRef RR) const {
return ME.getCell(RR, Map);
}
-
void BT::put(RegisterRef RR, const RegisterCell &RC) {
ME.putCell(RR, RC, Map);
}
-
// Replace all references to bits from OldRR with the corresponding bits
// in NewRR.
void BT::subst(RegisterRef OldRR, RegisterRef NewRR) {
@@ -1027,7 +1002,6 @@ void BT::subst(RegisterRef OldRR, RegisterRef NewRR) {
}
}
-
// Check if the block has been "executed" during propagation. (If not, the
// block is dead, but it may still appear to be reachable.)
bool BT::reached(const MachineBasicBlock *B) const {
@@ -1041,6 +1015,18 @@ bool BT::reached(const MachineBasicBlock *B) const {
return false;
}
+// Visit an individual instruction. This could be a newly added instruction,
+// or one that has been modified by an optimization.
+void BT::visit(const MachineInstr &MI) {
+ assert(!MI.isBranch() && "Only non-branches are allowed");
+ InstrExec.insert(&MI);
+ visitNonBranch(MI);
+ // The call to visitNonBranch could propagate the changes until a branch
+ // is actually visited. This could result in adding CFG edges to the flow
+ // queue. Since the queue won't be processed, clear it.
+ while (!FlowQ.empty())
+ FlowQ.pop();
+}
void BT::reset() {
EdgeExec.clear();
@@ -1048,7 +1034,6 @@ void BT::reset() {
Map.clear();
}
-
void BT::run() {
reset();
assert(FlowQ.empty());
@@ -1118,10 +1103,6 @@ void BT::run() {
}
} // while (!FlowQ->empty())
- if (Trace) {
- dbgs() << "Cells after propagation:\n";
- for (CellMapType::iterator I = Map.begin(), E = Map.end(); I != E; ++I)
- dbgs() << PrintReg(I->first, &ME.TRI) << " -> " << I->second << "\n";
- }
+ if (Trace)
+ print_cells(dbgs() << "Cells after propagation:\n");
}
-
diff --git a/contrib/llvm/lib/Target/Hexagon/BitTracker.h b/contrib/llvm/lib/Target/Hexagon/BitTracker.h
index 5b925fe..48c5f22 100644
--- a/contrib/llvm/lib/Target/Hexagon/BitTracker.h
+++ b/contrib/llvm/lib/Target/Hexagon/BitTracker.h
@@ -1,4 +1,4 @@
-//===--- BitTracker.h -----------------------------------------------------===//
+//===--- BitTracker.h -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,24 +7,27 @@
//
//===----------------------------------------------------------------------===//
-#ifndef BITTRACKER_H
-#define BITTRACKER_H
+#ifndef LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H
+#define LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunction.h"
-
+#include "llvm/CodeGen/MachineOperand.h"
+#include <cassert>
+#include <cstdint>
#include <map>
#include <queue>
#include <set>
+#include <utility>
namespace llvm {
- class ConstantInt;
- class MachineRegisterInfo;
- class MachineBasicBlock;
- class MachineInstr;
- class MachineOperand;
- class raw_ostream;
+
+class ConstantInt;
+class MachineRegisterInfo;
+class MachineBasicBlock;
+class MachineInstr;
+class raw_ostream;
struct BitTracker {
struct BitRef;
@@ -49,6 +52,9 @@ struct BitTracker {
void put(RegisterRef RR, const RegisterCell &RC);
void subst(RegisterRef OldRR, RegisterRef NewRR);
bool reached(const MachineBasicBlock *B) const;
+ void visit(const MachineInstr &MI);
+
+ void print_cells(raw_ostream &OS) const;
private:
void visitPHI(const MachineInstr &PI);
@@ -73,19 +79,19 @@ private:
CellMapType &Map;
};
-
// Abstraction of a reference to bit at position Pos from a register Reg.
struct BitTracker::BitRef {
BitRef(unsigned R = 0, uint16_t P = 0) : Reg(R), Pos(P) {}
+
bool operator== (const BitRef &BR) const {
// If Reg is 0, disregard Pos.
return Reg == BR.Reg && (Reg == 0 || Pos == BR.Pos);
}
+
unsigned Reg;
uint16_t Pos;
};
-
// Abstraction of a register reference in MachineOperand. It contains the
// register number and the subregister index.
struct BitTracker::RegisterRef {
@@ -93,10 +99,10 @@ struct BitTracker::RegisterRef {
: Reg(R), Sub(S) {}
RegisterRef(const MachineOperand &MO)
: Reg(MO.getReg()), Sub(MO.getSubReg()) {}
+
unsigned Reg, Sub;
};
-
// Value that a single bit can take. This is outside of the context of
// any register, it is more of an abstraction of the two-element set of
// possible bit values. One extension here is the "Ref" type, which
@@ -155,6 +161,7 @@ struct BitTracker::BitValue {
bool operator!= (const BitValue &V) const {
return !operator==(V);
}
+
bool is(unsigned T) const {
assert(T == 0 || T == 1);
return T == 0 ? Type == Zero
@@ -206,6 +213,7 @@ struct BitTracker::BitValue {
bool num() const {
return Type == Zero || Type == One;
}
+
operator bool() const {
assert(Type == Zero || Type == One);
return Type == One;
@@ -214,7 +222,6 @@ struct BitTracker::BitValue {
friend raw_ostream &operator<<(raw_ostream &OS, const BitValue &BV);
};
-
// This operation must be idempotent, i.e. ref(ref(V)) == ref(V).
inline BitTracker::BitValue
BitTracker::BitValue::ref(const BitValue &V) {
@@ -225,26 +232,26 @@ BitTracker::BitValue::ref(const BitValue &V) {
return self();
}
-
inline BitTracker::BitValue
BitTracker::BitValue::self(const BitRef &Self) {
return BitValue(Self.Reg, Self.Pos);
}
-
// A sequence of bits starting from index B up to and including index E.
// If E < B, the mask represents two sections: [0..E] and [B..W) where
// W is the width of the register.
struct BitTracker::BitMask {
- BitMask() : B(0), E(0) {}
+ BitMask() = default;
BitMask(uint16_t b, uint16_t e) : B(b), E(e) {}
+
uint16_t first() const { return B; }
uint16_t last() const { return E; }
+
private:
- uint16_t B, E;
+ uint16_t B = 0;
+ uint16_t E = 0;
};
-
// Representation of a register: a list of BitValues.
struct BitTracker::RegisterCell {
RegisterCell(uint16_t Width = DefaultBitN) : Bits(Width) {}
@@ -252,6 +259,7 @@ struct BitTracker::RegisterCell {
uint16_t width() const {
return Bits.size();
}
+
const BitValue &operator[](uint16_t BitN) const {
assert(BitN < Bits.size());
return Bits[BitN];
@@ -294,12 +302,10 @@ private:
friend raw_ostream &operator<<(raw_ostream &OS, const RegisterCell &RC);
};
-
inline bool BitTracker::has(unsigned Reg) const {
return Map.find(Reg) != Map.end();
}
-
inline const BitTracker::RegisterCell&
BitTracker::lookup(unsigned Reg) const {
CellMapType::const_iterator F = Map.find(Reg);
@@ -307,7 +313,6 @@ BitTracker::lookup(unsigned Reg) const {
return F->second;
}
-
inline BitTracker::RegisterCell
BitTracker::RegisterCell::self(unsigned Reg, uint16_t Width) {
RegisterCell RC(Width);
@@ -316,7 +321,6 @@ BitTracker::RegisterCell::self(unsigned Reg, uint16_t Width) {
return RC;
}
-
inline BitTracker::RegisterCell
BitTracker::RegisterCell::top(uint16_t Width) {
RegisterCell RC(Width);
@@ -325,7 +329,6 @@ BitTracker::RegisterCell::top(uint16_t Width) {
return RC;
}
-
inline BitTracker::RegisterCell
BitTracker::RegisterCell::ref(const RegisterCell &C) {
uint16_t W = C.width();
@@ -342,12 +345,13 @@ BitTracker::RegisterCell::ref(const RegisterCell &C) {
struct BitTracker::MachineEvaluator {
MachineEvaluator(const TargetRegisterInfo &T, MachineRegisterInfo &M)
: TRI(T), MRI(M) {}
- virtual ~MachineEvaluator() {}
+ virtual ~MachineEvaluator() = default;
uint16_t getRegBitWidth(const RegisterRef &RR) const;
RegisterCell getCell(const RegisterRef &RR, const CellMapType &M) const;
void putCell(const RegisterRef &RR, RegisterCell RC, CellMapType &M) const;
+
// A result of any operation should use refs to the source cells, not
// the cells directly. This function is a convenience wrapper to quickly
// generate a ref for a cell corresponding to a register reference.
@@ -432,4 +436,4 @@ struct BitTracker::MachineEvaluator {
} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H
diff --git a/contrib/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp b/contrib/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp
index 7bc08ec..c05fbc1 100644
--- a/contrib/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp
@@ -14,22 +14,23 @@
#include "MCTargetDesc/HexagonMCChecker.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
-#include "MCTargetDesc/HexagonInstPrinter.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
using namespace llvm;
using namespace Hexagon;
@@ -37,11 +38,13 @@ using namespace Hexagon;
typedef MCDisassembler::DecodeStatus DecodeStatus;
namespace {
+
/// \brief Hexagon disassembler for all Hexagon platforms.
class HexagonDisassembler : public MCDisassembler {
public:
std::unique_ptr<MCInstrInfo const> const MCII;
std::unique_ptr<MCInst *> CurrentBundle;
+
HexagonDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
MCInstrInfo const *MCII)
: MCDisassembler(STI, Ctx), MCII(MCII), CurrentBundle(new MCInst *) {}
@@ -58,7 +61,8 @@ public:
void adjustExtendedInstructions(MCInst &MCI, MCInst const &MCB) const;
void addSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) const;
};
-}
+
+} // end anonymous namespace
// Forward declare these because the auto-generated code will reference them.
// Definitions are further down.
@@ -105,9 +109,9 @@ static unsigned getRegFromSubinstEncoding(unsigned encoded_reg);
static DecodeStatus unsignedImmDecoder(MCInst &MI, unsigned tmp,
uint64_t Address, const void *Decoder);
-static DecodeStatus s16ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
+static DecodeStatus s16_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
-static DecodeStatus s12ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
+static DecodeStatus s12_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
static DecodeStatus s11_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
@@ -117,9 +121,9 @@ static DecodeStatus s11_2ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
static DecodeStatus s11_3ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
-static DecodeStatus s10ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
+static DecodeStatus s10_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
-static DecodeStatus s8ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
+static DecodeStatus s8_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
static DecodeStatus s6_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address,
const void *Decoder);
@@ -147,7 +151,7 @@ static MCDisassembler *createHexagonDisassembler(const Target &T,
}
extern "C" void LLVMInitializeHexagonDisassembler() {
- TargetRegistry::RegisterMCDisassembler(TheHexagonTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheHexagonTarget(),
createHexagonDisassembler);
}
@@ -162,7 +166,7 @@ DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
*CurrentBundle = &MI;
MI = HexagonMCInstrInfo::createBundle();
- while (Result == Success && Complete == false) {
+ while (Result == Success && !Complete) {
if (Bytes.size() < HEXAGON_INSTR_SIZE)
return MCDisassembler::Fail;
MCInst *Inst = new (getContext()) MCInst;
@@ -179,14 +183,13 @@ DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
return MCDisassembler::Success;
}
-namespace {
-HexagonDisassembler const &disassembler(void const *Decoder) {
+static HexagonDisassembler const &disassembler(void const *Decoder) {
return *static_cast<HexagonDisassembler const *>(Decoder);
}
-MCContext &contextFromDecoder(void const *Decoder) {
+
+static MCContext &contextFromDecoder(void const *Decoder) {
return disassembler(Decoder).getContext();
}
-}
DecodeStatus HexagonDisassembler::getSingleInstruction(
MCInst &MI, MCInst &MCB, ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -329,8 +332,7 @@ DecodeStatus HexagonDisassembler::getSingleInstruction(
// follow the duplex model, so the register values in the MCInst are
// incorrect. If the instruction is a compound, loop through the
// operands and change registers appropriately.
- if (llvm::HexagonMCInstrInfo::getType(*MCII, MI) ==
- HexagonII::TypeCOMPOUND) {
+ if (HexagonMCInstrInfo::getType(*MCII, MI) == HexagonII::TypeCOMPOUND) {
for (MCInst::iterator i = MI.begin(), last = MI.end(); i < last; ++i) {
if (i->isReg()) {
unsigned reg = i->getReg() - Hexagon::R0;
@@ -341,6 +343,37 @@ DecodeStatus HexagonDisassembler::getSingleInstruction(
}
}
+ switch(MI.getOpcode()) {
+ case Hexagon::J4_cmpeqn1_f_jumpnv_nt:
+ case Hexagon::J4_cmpeqn1_f_jumpnv_t:
+ case Hexagon::J4_cmpeqn1_fp0_jump_nt:
+ case Hexagon::J4_cmpeqn1_fp0_jump_t:
+ case Hexagon::J4_cmpeqn1_fp1_jump_nt:
+ case Hexagon::J4_cmpeqn1_fp1_jump_t:
+ case Hexagon::J4_cmpeqn1_t_jumpnv_nt:
+ case Hexagon::J4_cmpeqn1_t_jumpnv_t:
+ case Hexagon::J4_cmpeqn1_tp0_jump_nt:
+ case Hexagon::J4_cmpeqn1_tp0_jump_t:
+ case Hexagon::J4_cmpeqn1_tp1_jump_nt:
+ case Hexagon::J4_cmpeqn1_tp1_jump_t:
+ case Hexagon::J4_cmpgtn1_f_jumpnv_nt:
+ case Hexagon::J4_cmpgtn1_f_jumpnv_t:
+ case Hexagon::J4_cmpgtn1_fp0_jump_nt:
+ case Hexagon::J4_cmpgtn1_fp0_jump_t:
+ case Hexagon::J4_cmpgtn1_fp1_jump_nt:
+ case Hexagon::J4_cmpgtn1_fp1_jump_t:
+ case Hexagon::J4_cmpgtn1_t_jumpnv_nt:
+ case Hexagon::J4_cmpgtn1_t_jumpnv_t:
+ case Hexagon::J4_cmpgtn1_tp0_jump_nt:
+ case Hexagon::J4_cmpgtn1_tp0_jump_t:
+ case Hexagon::J4_cmpgtn1_tp1_jump_nt:
+ case Hexagon::J4_cmpgtn1_tp1_jump_t:
+ MI.insert(MI.begin() + 1, MCOperand::createExpr(MCConstantExpr::create(-1, getContext())));
+ break;
+ default:
+ break;
+ }
+
if (HexagonMCInstrInfo::isNewValue(*MCII, MI)) {
unsigned OpIndex = HexagonMCInstrInfo::getNewValueOp(*MCII, MI);
MCOperand &MCO = MI.getOperand(OpIndex);
@@ -417,46 +450,46 @@ void HexagonDisassembler::adjustExtendedInstructions(MCInst &MCI,
// GP relative instruction in the absence of the corresponding immediate
// extender.
switch (MCI.getOpcode()) {
- case Hexagon::S2_storerbabs:
+ case Hexagon::PS_storerbabs:
opcode = Hexagon::S2_storerbgp;
break;
- case Hexagon::S2_storerhabs:
+ case Hexagon::PS_storerhabs:
opcode = Hexagon::S2_storerhgp;
break;
- case Hexagon::S2_storerfabs:
+ case Hexagon::PS_storerfabs:
opcode = Hexagon::S2_storerfgp;
break;
- case Hexagon::S2_storeriabs:
+ case Hexagon::PS_storeriabs:
opcode = Hexagon::S2_storerigp;
break;
- case Hexagon::S2_storerbnewabs:
+ case Hexagon::PS_storerbnewabs:
opcode = Hexagon::S2_storerbnewgp;
break;
- case Hexagon::S2_storerhnewabs:
+ case Hexagon::PS_storerhnewabs:
opcode = Hexagon::S2_storerhnewgp;
break;
- case Hexagon::S2_storerinewabs:
+ case Hexagon::PS_storerinewabs:
opcode = Hexagon::S2_storerinewgp;
break;
- case Hexagon::S2_storerdabs:
+ case Hexagon::PS_storerdabs:
opcode = Hexagon::S2_storerdgp;
break;
- case Hexagon::L4_loadrb_abs:
+ case Hexagon::PS_loadrbabs:
opcode = Hexagon::L2_loadrbgp;
break;
- case Hexagon::L4_loadrub_abs:
+ case Hexagon::PS_loadrubabs:
opcode = Hexagon::L2_loadrubgp;
break;
- case Hexagon::L4_loadrh_abs:
+ case Hexagon::PS_loadrhabs:
opcode = Hexagon::L2_loadrhgp;
break;
- case Hexagon::L4_loadruh_abs:
+ case Hexagon::PS_loadruhabs:
opcode = Hexagon::L2_loadruhgp;
break;
- case Hexagon::L4_loadri_abs:
+ case Hexagon::PS_loadriabs:
opcode = Hexagon::L2_loadrigp;
break;
- case Hexagon::L4_loadrd_abs:
+ case Hexagon::PS_loadrdabs:
opcode = Hexagon::L2_loadrdgp;
break;
default:
@@ -466,10 +499,6 @@ void HexagonDisassembler::adjustExtendedInstructions(MCInst &MCI,
}
}
-namespace llvm {
-extern const MCInstrDesc HexagonInsts[];
-}
-
static DecodeStatus DecodeRegisterClass(MCInst &Inst, unsigned RegNo,
ArrayRef<MCPhysReg> Table) {
if (RegNo < Table.size()) {
@@ -621,11 +650,8 @@ static DecodeStatus DecodeModRegsRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
-namespace {
-uint32_t fullValue(MCInstrInfo const &MCII,
- MCInst &MCB,
- MCInst &MI,
- int64_t Value) {
+static uint32_t fullValue(MCInstrInfo const &MCII, MCInst &MCB, MCInst &MI,
+ int64_t Value) {
MCInst const *Extender = HexagonMCInstrInfo::extenderForIndex(
MCB, HexagonMCInstrInfo::bundleSize(MCB));
if(!Extender || MI.size() != HexagonMCInstrInfo::getExtendableOp(MCII, MI))
@@ -639,8 +665,9 @@ uint32_t fullValue(MCInstrInfo const &MCII,
uint32_t Operand = Upper26 | Lower6;
return Operand;
}
+
template <size_t T>
-void signedDecoder(MCInst &MI, unsigned tmp, const void *Decoder) {
+static void signedDecoder(MCInst &MI, unsigned tmp, const void *Decoder) {
HexagonDisassembler const &Disassembler = disassembler(Decoder);
int64_t FullValue = fullValue(*Disassembler.MCII,
**Disassembler.CurrentBundle,
@@ -649,7 +676,6 @@ void signedDecoder(MCInst &MI, unsigned tmp, const void *Decoder) {
HexagonMCInstrInfo::addConstant(MI, Extended,
Disassembler.getContext());
}
-}
static DecodeStatus unsignedImmDecoder(MCInst &MI, unsigned tmp,
uint64_t /*Address*/,
@@ -663,13 +689,13 @@ static DecodeStatus unsignedImmDecoder(MCInst &MI, unsigned tmp,
return MCDisassembler::Success;
}
-static DecodeStatus s16ImmDecoder(MCInst &MI, unsigned tmp,
+static DecodeStatus s16_0ImmDecoder(MCInst &MI, unsigned tmp,
uint64_t /*Address*/, const void *Decoder) {
signedDecoder<16>(MI, tmp, Decoder);
return MCDisassembler::Success;
}
-static DecodeStatus s12ImmDecoder(MCInst &MI, unsigned tmp,
+static DecodeStatus s12_0ImmDecoder(MCInst &MI, unsigned tmp,
uint64_t /*Address*/, const void *Decoder) {
signedDecoder<12>(MI, tmp, Decoder);
return MCDisassembler::Success;
@@ -699,13 +725,13 @@ static DecodeStatus s11_3ImmDecoder(MCInst &MI, unsigned tmp,
return MCDisassembler::Success;
}
-static DecodeStatus s10ImmDecoder(MCInst &MI, unsigned tmp,
+static DecodeStatus s10_0ImmDecoder(MCInst &MI, unsigned tmp,
uint64_t /*Address*/, const void *Decoder) {
signedDecoder<10>(MI, tmp, Decoder);
return MCDisassembler::Success;
}
-static DecodeStatus s8ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/,
+static DecodeStatus s8_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/,
const void *Decoder) {
signedDecoder<8>(MI, tmp, Decoder);
return MCDisassembler::Success;
@@ -811,25 +837,24 @@ static const unsigned int StoreConditionalOpcodeData[][2] = {
// HexagonII::INST_ICLASS_LD
// HexagonII::INST_ICLASS_LD_ST_2
-static unsigned int LoadStoreOpcodeData[][2] = {{L4_loadrd_abs, 0x49c00000},
- {L4_loadri_abs, 0x49800000},
- {L4_loadruh_abs, 0x49600000},
- {L4_loadrh_abs, 0x49400000},
- {L4_loadrub_abs, 0x49200000},
- {L4_loadrb_abs, 0x49000000},
- {S2_storerdabs, 0x48c00000},
- {S2_storerinewabs, 0x48a01000},
- {S2_storerhnewabs, 0x48a00800},
- {S2_storerbnewabs, 0x48a00000},
- {S2_storeriabs, 0x48800000},
- {S2_storerfabs, 0x48600000},
- {S2_storerhabs, 0x48400000},
- {S2_storerbabs, 0x48000000}};
+static unsigned int LoadStoreOpcodeData[][2] = {{PS_loadrdabs, 0x49c00000},
+ {PS_loadriabs, 0x49800000},
+ {PS_loadruhabs, 0x49600000},
+ {PS_loadrhabs, 0x49400000},
+ {PS_loadrubabs, 0x49200000},
+ {PS_loadrbabs, 0x49000000},
+ {PS_storerdabs, 0x48c00000},
+ {PS_storerinewabs, 0x48a01000},
+ {PS_storerhnewabs, 0x48a00800},
+ {PS_storerbnewabs, 0x48a00000},
+ {PS_storeriabs, 0x48800000},
+ {PS_storerfabs, 0x48600000},
+ {PS_storerhabs, 0x48400000},
+ {PS_storerbabs, 0x48000000}};
static const size_t NumCondS = array_lengthof(StoreConditionalOpcodeData);
static const size_t NumLS = array_lengthof(LoadStoreOpcodeData);
static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
-
unsigned MachineOpcode = 0;
unsigned LLVMOpcode = 0;
@@ -868,19 +893,18 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
case Hexagon::S4_pstorerdf_abs:
case Hexagon::S4_pstorerdt_abs:
case Hexagon::S4_pstorerdfnew_abs:
- case Hexagon::S4_pstorerdtnew_abs: {
+ case Hexagon::S4_pstorerdtnew_abs:
// op: Pv
Value = insn & UINT64_C(3);
- DecodePredRegsRegisterClass(MI, Value, 0, 0);
+ DecodePredRegsRegisterClass(MI, Value, 0, nullptr);
// op: u6
Value = (insn >> 12) & UINT64_C(48);
Value |= (insn >> 3) & UINT64_C(15);
MI.addOperand(MCOperand::createImm(Value));
// op: Rtt
Value = (insn >> 8) & UINT64_C(31);
- DecodeDoubleRegsRegisterClass(MI, Value, 0, 0);
+ DecodeDoubleRegsRegisterClass(MI, Value, 0, nullptr);
break;
- }
case Hexagon::S4_pstorerbnewf_abs:
case Hexagon::S4_pstorerbnewt_abs:
@@ -893,19 +917,18 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
case Hexagon::S4_pstorerinewf_abs:
case Hexagon::S4_pstorerinewt_abs:
case Hexagon::S4_pstorerinewfnew_abs:
- case Hexagon::S4_pstorerinewtnew_abs: {
+ case Hexagon::S4_pstorerinewtnew_abs:
// op: Pv
Value = insn & UINT64_C(3);
- DecodePredRegsRegisterClass(MI, Value, 0, 0);
+ DecodePredRegsRegisterClass(MI, Value, 0, nullptr);
// op: u6
Value = (insn >> 12) & UINT64_C(48);
Value |= (insn >> 3) & UINT64_C(15);
MI.addOperand(MCOperand::createImm(Value));
// op: Nt
Value = (insn >> 8) & UINT64_C(7);
- DecodeIntRegsRegisterClass(MI, Value, 0, 0);
+ DecodeIntRegsRegisterClass(MI, Value, 0, nullptr);
break;
- }
case Hexagon::S4_pstorerbf_abs:
case Hexagon::S4_pstorerbt_abs:
@@ -918,36 +941,34 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
case Hexagon::S4_pstorerif_abs:
case Hexagon::S4_pstorerit_abs:
case Hexagon::S4_pstorerifnew_abs:
- case Hexagon::S4_pstoreritnew_abs: {
+ case Hexagon::S4_pstoreritnew_abs:
// op: Pv
Value = insn & UINT64_C(3);
- DecodePredRegsRegisterClass(MI, Value, 0, 0);
+ DecodePredRegsRegisterClass(MI, Value, 0, nullptr);
// op: u6
Value = (insn >> 12) & UINT64_C(48);
Value |= (insn >> 3) & UINT64_C(15);
MI.addOperand(MCOperand::createImm(Value));
// op: Rt
Value = (insn >> 8) & UINT64_C(31);
- DecodeIntRegsRegisterClass(MI, Value, 0, 0);
+ DecodeIntRegsRegisterClass(MI, Value, 0, nullptr);
break;
- }
case Hexagon::L4_ploadrdf_abs:
case Hexagon::L4_ploadrdt_abs:
case Hexagon::L4_ploadrdfnew_abs:
- case Hexagon::L4_ploadrdtnew_abs: {
+ case Hexagon::L4_ploadrdtnew_abs:
// op: Rdd
Value = insn & UINT64_C(31);
- DecodeDoubleRegsRegisterClass(MI, Value, 0, 0);
+ DecodeDoubleRegsRegisterClass(MI, Value, 0, nullptr);
// op: Pt
Value = ((insn >> 9) & UINT64_C(3));
- DecodePredRegsRegisterClass(MI, Value, 0, 0);
+ DecodePredRegsRegisterClass(MI, Value, 0, nullptr);
// op: u6
Value = ((insn >> 15) & UINT64_C(62));
Value |= ((insn >> 8) & UINT64_C(1));
MI.addOperand(MCOperand::createImm(Value));
break;
- }
case Hexagon::L4_ploadrbf_abs:
case Hexagon::L4_ploadrbt_abs:
@@ -971,10 +992,10 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
case Hexagon::L4_ploadritnew_abs:
// op: Rd
Value = insn & UINT64_C(31);
- DecodeIntRegsRegisterClass(MI, Value, 0, 0);
+ DecodeIntRegsRegisterClass(MI, Value, 0, nullptr);
// op: Pt
Value = (insn >> 9) & UINT64_C(3);
- DecodePredRegsRegisterClass(MI, Value, 0, 0);
+ DecodePredRegsRegisterClass(MI, Value, 0, nullptr);
// op: u6
Value = (insn >> 15) & UINT64_C(62);
Value |= (insn >> 8) & UINT64_C(1);
@@ -982,36 +1003,34 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
break;
// op: g16_2
- case (Hexagon::L4_loadri_abs):
+ case (Hexagon::PS_loadriabs):
++shift;
// op: g16_1
- case Hexagon::L4_loadrh_abs:
- case Hexagon::L4_loadruh_abs:
+ case Hexagon::PS_loadrhabs:
+ case Hexagon::PS_loadruhabs:
++shift;
// op: g16_0
- case Hexagon::L4_loadrb_abs:
- case Hexagon::L4_loadrub_abs: {
+ case Hexagon::PS_loadrbabs:
+ case Hexagon::PS_loadrubabs:
// op: Rd
Value |= insn & UINT64_C(31);
- DecodeIntRegsRegisterClass(MI, Value, 0, 0);
+ DecodeIntRegsRegisterClass(MI, Value, 0, nullptr);
Value = (insn >> 11) & UINT64_C(49152);
Value |= (insn >> 7) & UINT64_C(15872);
Value |= (insn >> 5) & UINT64_C(511);
MI.addOperand(MCOperand::createImm(Value << shift));
break;
- }
- case Hexagon::L4_loadrd_abs: {
+ case Hexagon::PS_loadrdabs:
Value = insn & UINT64_C(31);
- DecodeDoubleRegsRegisterClass(MI, Value, 0, 0);
+ DecodeDoubleRegsRegisterClass(MI, Value, 0, nullptr);
Value = (insn >> 11) & UINT64_C(49152);
Value |= (insn >> 7) & UINT64_C(15872);
Value |= (insn >> 5) & UINT64_C(511);
MI.addOperand(MCOperand::createImm(Value << 3));
break;
- }
- case Hexagon::S2_storerdabs: {
+ case Hexagon::PS_storerdabs:
// op: g16_3
Value = (insn >> 11) & UINT64_C(49152);
Value |= (insn >> 7) & UINT64_C(15872);
@@ -1020,18 +1039,17 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
MI.addOperand(MCOperand::createImm(Value << 3));
// op: Rtt
Value = (insn >> 8) & UINT64_C(31);
- DecodeDoubleRegsRegisterClass(MI, Value, 0, 0);
+ DecodeDoubleRegsRegisterClass(MI, Value, 0, nullptr);
break;
- }
// op: g16_2
- case Hexagon::S2_storerinewabs:
+ case Hexagon::PS_storerinewabs:
++shift;
// op: g16_1
- case Hexagon::S2_storerhnewabs:
+ case Hexagon::PS_storerhnewabs:
++shift;
// op: g16_0
- case Hexagon::S2_storerbnewabs: {
+ case Hexagon::PS_storerbnewabs:
Value = (insn >> 11) & UINT64_C(49152);
Value |= (insn >> 7) & UINT64_C(15872);
Value |= (insn >> 5) & UINT64_C(256);
@@ -1039,19 +1057,18 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
MI.addOperand(MCOperand::createImm(Value << shift));
// op: Nt
Value = (insn >> 8) & UINT64_C(7);
- DecodeIntRegsRegisterClass(MI, Value, 0, 0);
+ DecodeIntRegsRegisterClass(MI, Value, 0, nullptr);
break;
- }
// op: g16_2
- case Hexagon::S2_storeriabs:
+ case Hexagon::PS_storeriabs:
++shift;
// op: g16_1
- case Hexagon::S2_storerhabs:
- case Hexagon::S2_storerfabs:
+ case Hexagon::PS_storerhabs:
+ case Hexagon::PS_storerfabs:
++shift;
// op: g16_0
- case Hexagon::S2_storerbabs: {
+ case Hexagon::PS_storerbabs:
Value = (insn >> 11) & UINT64_C(49152);
Value |= (insn >> 7) & UINT64_C(15872);
Value |= (insn >> 5) & UINT64_C(256);
@@ -1059,10 +1076,9 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
MI.addOperand(MCOperand::createImm(Value << shift));
// op: Rt
Value = (insn >> 8) & UINT64_C(31);
- DecodeIntRegsRegisterClass(MI, Value, 0, 0);
+ DecodeIntRegsRegisterClass(MI, Value, 0, nullptr);
break;
}
- }
return MCDisassembler::Success;
}
return MCDisassembler::Fail;
@@ -1070,7 +1086,6 @@ static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) {
static DecodeStatus decodeImmext(MCInst &MI, uint32_t insn,
void const *Decoder) {
-
// Instruction Class for a constant a extender: bits 31:28 = 0x0000
if ((~insn & 0xf0000000) == 0xf0000000) {
unsigned Value;
@@ -1087,244 +1102,244 @@ static DecodeStatus decodeImmext(MCInst &MI, uint32_t insn,
// These values are from HexagonGenMCCodeEmitter.inc and HexagonIsetDx.td
enum subInstBinaryValues {
- V4_SA1_addi_BITS = 0x0000,
- V4_SA1_addi_MASK = 0x1800,
- V4_SA1_addrx_BITS = 0x1800,
- V4_SA1_addrx_MASK = 0x1f00,
- V4_SA1_addsp_BITS = 0x0c00,
- V4_SA1_addsp_MASK = 0x1c00,
- V4_SA1_and1_BITS = 0x1200,
- V4_SA1_and1_MASK = 0x1f00,
- V4_SA1_clrf_BITS = 0x1a70,
- V4_SA1_clrf_MASK = 0x1e70,
- V4_SA1_clrfnew_BITS = 0x1a50,
- V4_SA1_clrfnew_MASK = 0x1e70,
- V4_SA1_clrt_BITS = 0x1a60,
- V4_SA1_clrt_MASK = 0x1e70,
- V4_SA1_clrtnew_BITS = 0x1a40,
- V4_SA1_clrtnew_MASK = 0x1e70,
- V4_SA1_cmpeqi_BITS = 0x1900,
- V4_SA1_cmpeqi_MASK = 0x1f00,
- V4_SA1_combine0i_BITS = 0x1c00,
- V4_SA1_combine0i_MASK = 0x1d18,
- V4_SA1_combine1i_BITS = 0x1c08,
- V4_SA1_combine1i_MASK = 0x1d18,
- V4_SA1_combine2i_BITS = 0x1c10,
- V4_SA1_combine2i_MASK = 0x1d18,
- V4_SA1_combine3i_BITS = 0x1c18,
- V4_SA1_combine3i_MASK = 0x1d18,
- V4_SA1_combinerz_BITS = 0x1d08,
- V4_SA1_combinerz_MASK = 0x1d08,
- V4_SA1_combinezr_BITS = 0x1d00,
- V4_SA1_combinezr_MASK = 0x1d08,
- V4_SA1_dec_BITS = 0x1300,
- V4_SA1_dec_MASK = 0x1f00,
- V4_SA1_inc_BITS = 0x1100,
- V4_SA1_inc_MASK = 0x1f00,
- V4_SA1_seti_BITS = 0x0800,
- V4_SA1_seti_MASK = 0x1c00,
- V4_SA1_setin1_BITS = 0x1a00,
- V4_SA1_setin1_MASK = 0x1e40,
- V4_SA1_sxtb_BITS = 0x1500,
- V4_SA1_sxtb_MASK = 0x1f00,
- V4_SA1_sxth_BITS = 0x1400,
- V4_SA1_sxth_MASK = 0x1f00,
- V4_SA1_tfr_BITS = 0x1000,
- V4_SA1_tfr_MASK = 0x1f00,
- V4_SA1_zxtb_BITS = 0x1700,
- V4_SA1_zxtb_MASK = 0x1f00,
- V4_SA1_zxth_BITS = 0x1600,
- V4_SA1_zxth_MASK = 0x1f00,
- V4_SL1_loadri_io_BITS = 0x0000,
- V4_SL1_loadri_io_MASK = 0x1000,
- V4_SL1_loadrub_io_BITS = 0x1000,
- V4_SL1_loadrub_io_MASK = 0x1000,
- V4_SL2_deallocframe_BITS = 0x1f00,
- V4_SL2_deallocframe_MASK = 0x1fc0,
- V4_SL2_jumpr31_BITS = 0x1fc0,
- V4_SL2_jumpr31_MASK = 0x1fc4,
- V4_SL2_jumpr31_f_BITS = 0x1fc5,
- V4_SL2_jumpr31_f_MASK = 0x1fc7,
- V4_SL2_jumpr31_fnew_BITS = 0x1fc7,
- V4_SL2_jumpr31_fnew_MASK = 0x1fc7,
- V4_SL2_jumpr31_t_BITS = 0x1fc4,
- V4_SL2_jumpr31_t_MASK = 0x1fc7,
- V4_SL2_jumpr31_tnew_BITS = 0x1fc6,
- V4_SL2_jumpr31_tnew_MASK = 0x1fc7,
- V4_SL2_loadrb_io_BITS = 0x1000,
- V4_SL2_loadrb_io_MASK = 0x1800,
- V4_SL2_loadrd_sp_BITS = 0x1e00,
- V4_SL2_loadrd_sp_MASK = 0x1f00,
- V4_SL2_loadrh_io_BITS = 0x0000,
- V4_SL2_loadrh_io_MASK = 0x1800,
- V4_SL2_loadri_sp_BITS = 0x1c00,
- V4_SL2_loadri_sp_MASK = 0x1e00,
- V4_SL2_loadruh_io_BITS = 0x0800,
- V4_SL2_loadruh_io_MASK = 0x1800,
- V4_SL2_return_BITS = 0x1f40,
- V4_SL2_return_MASK = 0x1fc4,
- V4_SL2_return_f_BITS = 0x1f45,
- V4_SL2_return_f_MASK = 0x1fc7,
- V4_SL2_return_fnew_BITS = 0x1f47,
- V4_SL2_return_fnew_MASK = 0x1fc7,
- V4_SL2_return_t_BITS = 0x1f44,
- V4_SL2_return_t_MASK = 0x1fc7,
- V4_SL2_return_tnew_BITS = 0x1f46,
- V4_SL2_return_tnew_MASK = 0x1fc7,
- V4_SS1_storeb_io_BITS = 0x1000,
- V4_SS1_storeb_io_MASK = 0x1000,
- V4_SS1_storew_io_BITS = 0x0000,
- V4_SS1_storew_io_MASK = 0x1000,
- V4_SS2_allocframe_BITS = 0x1c00,
- V4_SS2_allocframe_MASK = 0x1e00,
- V4_SS2_storebi0_BITS = 0x1200,
- V4_SS2_storebi0_MASK = 0x1f00,
- V4_SS2_storebi1_BITS = 0x1300,
- V4_SS2_storebi1_MASK = 0x1f00,
- V4_SS2_stored_sp_BITS = 0x0a00,
- V4_SS2_stored_sp_MASK = 0x1e00,
- V4_SS2_storeh_io_BITS = 0x0000,
- V4_SS2_storeh_io_MASK = 0x1800,
- V4_SS2_storew_sp_BITS = 0x0800,
- V4_SS2_storew_sp_MASK = 0x1e00,
- V4_SS2_storewi0_BITS = 0x1000,
- V4_SS2_storewi0_MASK = 0x1f00,
- V4_SS2_storewi1_BITS = 0x1100,
- V4_SS2_storewi1_MASK = 0x1f00
+ SA1_addi_BITS = 0x0000,
+ SA1_addi_MASK = 0x1800,
+ SA1_addrx_BITS = 0x1800,
+ SA1_addrx_MASK = 0x1f00,
+ SA1_addsp_BITS = 0x0c00,
+ SA1_addsp_MASK = 0x1c00,
+ SA1_and1_BITS = 0x1200,
+ SA1_and1_MASK = 0x1f00,
+ SA1_clrf_BITS = 0x1a70,
+ SA1_clrf_MASK = 0x1e70,
+ SA1_clrfnew_BITS = 0x1a50,
+ SA1_clrfnew_MASK = 0x1e70,
+ SA1_clrt_BITS = 0x1a60,
+ SA1_clrt_MASK = 0x1e70,
+ SA1_clrtnew_BITS = 0x1a40,
+ SA1_clrtnew_MASK = 0x1e70,
+ SA1_cmpeqi_BITS = 0x1900,
+ SA1_cmpeqi_MASK = 0x1f00,
+ SA1_combine0i_BITS = 0x1c00,
+ SA1_combine0i_MASK = 0x1d18,
+ SA1_combine1i_BITS = 0x1c08,
+ SA1_combine1i_MASK = 0x1d18,
+ SA1_combine2i_BITS = 0x1c10,
+ SA1_combine2i_MASK = 0x1d18,
+ SA1_combine3i_BITS = 0x1c18,
+ SA1_combine3i_MASK = 0x1d18,
+ SA1_combinerz_BITS = 0x1d08,
+ SA1_combinerz_MASK = 0x1d08,
+ SA1_combinezr_BITS = 0x1d00,
+ SA1_combinezr_MASK = 0x1d08,
+ SA1_dec_BITS = 0x1300,
+ SA1_dec_MASK = 0x1f00,
+ SA1_inc_BITS = 0x1100,
+ SA1_inc_MASK = 0x1f00,
+ SA1_seti_BITS = 0x0800,
+ SA1_seti_MASK = 0x1c00,
+ SA1_setin1_BITS = 0x1a00,
+ SA1_setin1_MASK = 0x1e40,
+ SA1_sxtb_BITS = 0x1500,
+ SA1_sxtb_MASK = 0x1f00,
+ SA1_sxth_BITS = 0x1400,
+ SA1_sxth_MASK = 0x1f00,
+ SA1_tfr_BITS = 0x1000,
+ SA1_tfr_MASK = 0x1f00,
+ SA1_zxtb_BITS = 0x1700,
+ SA1_zxtb_MASK = 0x1f00,
+ SA1_zxth_BITS = 0x1600,
+ SA1_zxth_MASK = 0x1f00,
+ SL1_loadri_io_BITS = 0x0000,
+ SL1_loadri_io_MASK = 0x1000,
+ SL1_loadrub_io_BITS = 0x1000,
+ SL1_loadrub_io_MASK = 0x1000,
+ SL2_deallocframe_BITS = 0x1f00,
+ SL2_deallocframe_MASK = 0x1fc0,
+ SL2_jumpr31_BITS = 0x1fc0,
+ SL2_jumpr31_MASK = 0x1fc4,
+ SL2_jumpr31_f_BITS = 0x1fc5,
+ SL2_jumpr31_f_MASK = 0x1fc7,
+ SL2_jumpr31_fnew_BITS = 0x1fc7,
+ SL2_jumpr31_fnew_MASK = 0x1fc7,
+ SL2_jumpr31_t_BITS = 0x1fc4,
+ SL2_jumpr31_t_MASK = 0x1fc7,
+ SL2_jumpr31_tnew_BITS = 0x1fc6,
+ SL2_jumpr31_tnew_MASK = 0x1fc7,
+ SL2_loadrb_io_BITS = 0x1000,
+ SL2_loadrb_io_MASK = 0x1800,
+ SL2_loadrd_sp_BITS = 0x1e00,
+ SL2_loadrd_sp_MASK = 0x1f00,
+ SL2_loadrh_io_BITS = 0x0000,
+ SL2_loadrh_io_MASK = 0x1800,
+ SL2_loadri_sp_BITS = 0x1c00,
+ SL2_loadri_sp_MASK = 0x1e00,
+ SL2_loadruh_io_BITS = 0x0800,
+ SL2_loadruh_io_MASK = 0x1800,
+ SL2_return_BITS = 0x1f40,
+ SL2_return_MASK = 0x1fc4,
+ SL2_return_f_BITS = 0x1f45,
+ SL2_return_f_MASK = 0x1fc7,
+ SL2_return_fnew_BITS = 0x1f47,
+ SL2_return_fnew_MASK = 0x1fc7,
+ SL2_return_t_BITS = 0x1f44,
+ SL2_return_t_MASK = 0x1fc7,
+ SL2_return_tnew_BITS = 0x1f46,
+ SL2_return_tnew_MASK = 0x1fc7,
+ SS1_storeb_io_BITS = 0x1000,
+ SS1_storeb_io_MASK = 0x1000,
+ SS1_storew_io_BITS = 0x0000,
+ SS1_storew_io_MASK = 0x1000,
+ SS2_allocframe_BITS = 0x1c00,
+ SS2_allocframe_MASK = 0x1e00,
+ SS2_storebi0_BITS = 0x1200,
+ SS2_storebi0_MASK = 0x1f00,
+ SS2_storebi1_BITS = 0x1300,
+ SS2_storebi1_MASK = 0x1f00,
+ SS2_stored_sp_BITS = 0x0a00,
+ SS2_stored_sp_MASK = 0x1e00,
+ SS2_storeh_io_BITS = 0x0000,
+ SS2_storeh_io_MASK = 0x1800,
+ SS2_storew_sp_BITS = 0x0800,
+ SS2_storew_sp_MASK = 0x1e00,
+ SS2_storewi0_BITS = 0x1000,
+ SS2_storewi0_MASK = 0x1f00,
+ SS2_storewi1_BITS = 0x1100,
+ SS2_storewi1_MASK = 0x1f00
};
static unsigned GetSubinstOpcode(unsigned IClass, unsigned inst, unsigned &op,
raw_ostream &os) {
switch (IClass) {
case HexagonII::HSIG_L1:
- if ((inst & V4_SL1_loadri_io_MASK) == V4_SL1_loadri_io_BITS)
- op = Hexagon::V4_SL1_loadri_io;
- else if ((inst & V4_SL1_loadrub_io_MASK) == V4_SL1_loadrub_io_BITS)
- op = Hexagon::V4_SL1_loadrub_io;
+ if ((inst & SL1_loadri_io_MASK) == SL1_loadri_io_BITS)
+ op = Hexagon::SL1_loadri_io;
+ else if ((inst & SL1_loadrub_io_MASK) == SL1_loadrub_io_BITS)
+ op = Hexagon::SL1_loadrub_io;
else {
os << "<unknown subinstruction>";
return MCDisassembler::Fail;
}
break;
case HexagonII::HSIG_L2:
- if ((inst & V4_SL2_deallocframe_MASK) == V4_SL2_deallocframe_BITS)
- op = Hexagon::V4_SL2_deallocframe;
- else if ((inst & V4_SL2_jumpr31_MASK) == V4_SL2_jumpr31_BITS)
- op = Hexagon::V4_SL2_jumpr31;
- else if ((inst & V4_SL2_jumpr31_f_MASK) == V4_SL2_jumpr31_f_BITS)
- op = Hexagon::V4_SL2_jumpr31_f;
- else if ((inst & V4_SL2_jumpr31_fnew_MASK) == V4_SL2_jumpr31_fnew_BITS)
- op = Hexagon::V4_SL2_jumpr31_fnew;
- else if ((inst & V4_SL2_jumpr31_t_MASK) == V4_SL2_jumpr31_t_BITS)
- op = Hexagon::V4_SL2_jumpr31_t;
- else if ((inst & V4_SL2_jumpr31_tnew_MASK) == V4_SL2_jumpr31_tnew_BITS)
- op = Hexagon::V4_SL2_jumpr31_tnew;
- else if ((inst & V4_SL2_loadrb_io_MASK) == V4_SL2_loadrb_io_BITS)
- op = Hexagon::V4_SL2_loadrb_io;
- else if ((inst & V4_SL2_loadrd_sp_MASK) == V4_SL2_loadrd_sp_BITS)
- op = Hexagon::V4_SL2_loadrd_sp;
- else if ((inst & V4_SL2_loadrh_io_MASK) == V4_SL2_loadrh_io_BITS)
- op = Hexagon::V4_SL2_loadrh_io;
- else if ((inst & V4_SL2_loadri_sp_MASK) == V4_SL2_loadri_sp_BITS)
- op = Hexagon::V4_SL2_loadri_sp;
- else if ((inst & V4_SL2_loadruh_io_MASK) == V4_SL2_loadruh_io_BITS)
- op = Hexagon::V4_SL2_loadruh_io;
- else if ((inst & V4_SL2_return_MASK) == V4_SL2_return_BITS)
- op = Hexagon::V4_SL2_return;
- else if ((inst & V4_SL2_return_f_MASK) == V4_SL2_return_f_BITS)
- op = Hexagon::V4_SL2_return_f;
- else if ((inst & V4_SL2_return_fnew_MASK) == V4_SL2_return_fnew_BITS)
- op = Hexagon::V4_SL2_return_fnew;
- else if ((inst & V4_SL2_return_t_MASK) == V4_SL2_return_t_BITS)
- op = Hexagon::V4_SL2_return_t;
- else if ((inst & V4_SL2_return_tnew_MASK) == V4_SL2_return_tnew_BITS)
- op = Hexagon::V4_SL2_return_tnew;
+ if ((inst & SL2_deallocframe_MASK) == SL2_deallocframe_BITS)
+ op = Hexagon::SL2_deallocframe;
+ else if ((inst & SL2_jumpr31_MASK) == SL2_jumpr31_BITS)
+ op = Hexagon::SL2_jumpr31;
+ else if ((inst & SL2_jumpr31_f_MASK) == SL2_jumpr31_f_BITS)
+ op = Hexagon::SL2_jumpr31_f;
+ else if ((inst & SL2_jumpr31_fnew_MASK) == SL2_jumpr31_fnew_BITS)
+ op = Hexagon::SL2_jumpr31_fnew;
+ else if ((inst & SL2_jumpr31_t_MASK) == SL2_jumpr31_t_BITS)
+ op = Hexagon::SL2_jumpr31_t;
+ else if ((inst & SL2_jumpr31_tnew_MASK) == SL2_jumpr31_tnew_BITS)
+ op = Hexagon::SL2_jumpr31_tnew;
+ else if ((inst & SL2_loadrb_io_MASK) == SL2_loadrb_io_BITS)
+ op = Hexagon::SL2_loadrb_io;
+ else if ((inst & SL2_loadrd_sp_MASK) == SL2_loadrd_sp_BITS)
+ op = Hexagon::SL2_loadrd_sp;
+ else if ((inst & SL2_loadrh_io_MASK) == SL2_loadrh_io_BITS)
+ op = Hexagon::SL2_loadrh_io;
+ else if ((inst & SL2_loadri_sp_MASK) == SL2_loadri_sp_BITS)
+ op = Hexagon::SL2_loadri_sp;
+ else if ((inst & SL2_loadruh_io_MASK) == SL2_loadruh_io_BITS)
+ op = Hexagon::SL2_loadruh_io;
+ else if ((inst & SL2_return_MASK) == SL2_return_BITS)
+ op = Hexagon::SL2_return;
+ else if ((inst & SL2_return_f_MASK) == SL2_return_f_BITS)
+ op = Hexagon::SL2_return_f;
+ else if ((inst & SL2_return_fnew_MASK) == SL2_return_fnew_BITS)
+ op = Hexagon::SL2_return_fnew;
+ else if ((inst & SL2_return_t_MASK) == SL2_return_t_BITS)
+ op = Hexagon::SL2_return_t;
+ else if ((inst & SL2_return_tnew_MASK) == SL2_return_tnew_BITS)
+ op = Hexagon::SL2_return_tnew;
else {
os << "<unknown subinstruction>";
return MCDisassembler::Fail;
}
break;
case HexagonII::HSIG_A:
- if ((inst & V4_SA1_addi_MASK) == V4_SA1_addi_BITS)
- op = Hexagon::V4_SA1_addi;
- else if ((inst & V4_SA1_addrx_MASK) == V4_SA1_addrx_BITS)
- op = Hexagon::V4_SA1_addrx;
- else if ((inst & V4_SA1_addsp_MASK) == V4_SA1_addsp_BITS)
- op = Hexagon::V4_SA1_addsp;
- else if ((inst & V4_SA1_and1_MASK) == V4_SA1_and1_BITS)
- op = Hexagon::V4_SA1_and1;
- else if ((inst & V4_SA1_clrf_MASK) == V4_SA1_clrf_BITS)
- op = Hexagon::V4_SA1_clrf;
- else if ((inst & V4_SA1_clrfnew_MASK) == V4_SA1_clrfnew_BITS)
- op = Hexagon::V4_SA1_clrfnew;
- else if ((inst & V4_SA1_clrt_MASK) == V4_SA1_clrt_BITS)
- op = Hexagon::V4_SA1_clrt;
- else if ((inst & V4_SA1_clrtnew_MASK) == V4_SA1_clrtnew_BITS)
- op = Hexagon::V4_SA1_clrtnew;
- else if ((inst & V4_SA1_cmpeqi_MASK) == V4_SA1_cmpeqi_BITS)
- op = Hexagon::V4_SA1_cmpeqi;
- else if ((inst & V4_SA1_combine0i_MASK) == V4_SA1_combine0i_BITS)
- op = Hexagon::V4_SA1_combine0i;
- else if ((inst & V4_SA1_combine1i_MASK) == V4_SA1_combine1i_BITS)
- op = Hexagon::V4_SA1_combine1i;
- else if ((inst & V4_SA1_combine2i_MASK) == V4_SA1_combine2i_BITS)
- op = Hexagon::V4_SA1_combine2i;
- else if ((inst & V4_SA1_combine3i_MASK) == V4_SA1_combine3i_BITS)
- op = Hexagon::V4_SA1_combine3i;
- else if ((inst & V4_SA1_combinerz_MASK) == V4_SA1_combinerz_BITS)
- op = Hexagon::V4_SA1_combinerz;
- else if ((inst & V4_SA1_combinezr_MASK) == V4_SA1_combinezr_BITS)
- op = Hexagon::V4_SA1_combinezr;
- else if ((inst & V4_SA1_dec_MASK) == V4_SA1_dec_BITS)
- op = Hexagon::V4_SA1_dec;
- else if ((inst & V4_SA1_inc_MASK) == V4_SA1_inc_BITS)
- op = Hexagon::V4_SA1_inc;
- else if ((inst & V4_SA1_seti_MASK) == V4_SA1_seti_BITS)
- op = Hexagon::V4_SA1_seti;
- else if ((inst & V4_SA1_setin1_MASK) == V4_SA1_setin1_BITS)
- op = Hexagon::V4_SA1_setin1;
- else if ((inst & V4_SA1_sxtb_MASK) == V4_SA1_sxtb_BITS)
- op = Hexagon::V4_SA1_sxtb;
- else if ((inst & V4_SA1_sxth_MASK) == V4_SA1_sxth_BITS)
- op = Hexagon::V4_SA1_sxth;
- else if ((inst & V4_SA1_tfr_MASK) == V4_SA1_tfr_BITS)
- op = Hexagon::V4_SA1_tfr;
- else if ((inst & V4_SA1_zxtb_MASK) == V4_SA1_zxtb_BITS)
- op = Hexagon::V4_SA1_zxtb;
- else if ((inst & V4_SA1_zxth_MASK) == V4_SA1_zxth_BITS)
- op = Hexagon::V4_SA1_zxth;
+ if ((inst & SA1_addi_MASK) == SA1_addi_BITS)
+ op = Hexagon::SA1_addi;
+ else if ((inst & SA1_addrx_MASK) == SA1_addrx_BITS)
+ op = Hexagon::SA1_addrx;
+ else if ((inst & SA1_addsp_MASK) == SA1_addsp_BITS)
+ op = Hexagon::SA1_addsp;
+ else if ((inst & SA1_and1_MASK) == SA1_and1_BITS)
+ op = Hexagon::SA1_and1;
+ else if ((inst & SA1_clrf_MASK) == SA1_clrf_BITS)
+ op = Hexagon::SA1_clrf;
+ else if ((inst & SA1_clrfnew_MASK) == SA1_clrfnew_BITS)
+ op = Hexagon::SA1_clrfnew;
+ else if ((inst & SA1_clrt_MASK) == SA1_clrt_BITS)
+ op = Hexagon::SA1_clrt;
+ else if ((inst & SA1_clrtnew_MASK) == SA1_clrtnew_BITS)
+ op = Hexagon::SA1_clrtnew;
+ else if ((inst & SA1_cmpeqi_MASK) == SA1_cmpeqi_BITS)
+ op = Hexagon::SA1_cmpeqi;
+ else if ((inst & SA1_combine0i_MASK) == SA1_combine0i_BITS)
+ op = Hexagon::SA1_combine0i;
+ else if ((inst & SA1_combine1i_MASK) == SA1_combine1i_BITS)
+ op = Hexagon::SA1_combine1i;
+ else if ((inst & SA1_combine2i_MASK) == SA1_combine2i_BITS)
+ op = Hexagon::SA1_combine2i;
+ else if ((inst & SA1_combine3i_MASK) == SA1_combine3i_BITS)
+ op = Hexagon::SA1_combine3i;
+ else if ((inst & SA1_combinerz_MASK) == SA1_combinerz_BITS)
+ op = Hexagon::SA1_combinerz;
+ else if ((inst & SA1_combinezr_MASK) == SA1_combinezr_BITS)
+ op = Hexagon::SA1_combinezr;
+ else if ((inst & SA1_dec_MASK) == SA1_dec_BITS)
+ op = Hexagon::SA1_dec;
+ else if ((inst & SA1_inc_MASK) == SA1_inc_BITS)
+ op = Hexagon::SA1_inc;
+ else if ((inst & SA1_seti_MASK) == SA1_seti_BITS)
+ op = Hexagon::SA1_seti;
+ else if ((inst & SA1_setin1_MASK) == SA1_setin1_BITS)
+ op = Hexagon::SA1_setin1;
+ else if ((inst & SA1_sxtb_MASK) == SA1_sxtb_BITS)
+ op = Hexagon::SA1_sxtb;
+ else if ((inst & SA1_sxth_MASK) == SA1_sxth_BITS)
+ op = Hexagon::SA1_sxth;
+ else if ((inst & SA1_tfr_MASK) == SA1_tfr_BITS)
+ op = Hexagon::SA1_tfr;
+ else if ((inst & SA1_zxtb_MASK) == SA1_zxtb_BITS)
+ op = Hexagon::SA1_zxtb;
+ else if ((inst & SA1_zxth_MASK) == SA1_zxth_BITS)
+ op = Hexagon::SA1_zxth;
else {
os << "<unknown subinstruction>";
return MCDisassembler::Fail;
}
break;
case HexagonII::HSIG_S1:
- if ((inst & V4_SS1_storeb_io_MASK) == V4_SS1_storeb_io_BITS)
- op = Hexagon::V4_SS1_storeb_io;
- else if ((inst & V4_SS1_storew_io_MASK) == V4_SS1_storew_io_BITS)
- op = Hexagon::V4_SS1_storew_io;
+ if ((inst & SS1_storeb_io_MASK) == SS1_storeb_io_BITS)
+ op = Hexagon::SS1_storeb_io;
+ else if ((inst & SS1_storew_io_MASK) == SS1_storew_io_BITS)
+ op = Hexagon::SS1_storew_io;
else {
os << "<unknown subinstruction>";
return MCDisassembler::Fail;
}
break;
case HexagonII::HSIG_S2:
- if ((inst & V4_SS2_allocframe_MASK) == V4_SS2_allocframe_BITS)
- op = Hexagon::V4_SS2_allocframe;
- else if ((inst & V4_SS2_storebi0_MASK) == V4_SS2_storebi0_BITS)
- op = Hexagon::V4_SS2_storebi0;
- else if ((inst & V4_SS2_storebi1_MASK) == V4_SS2_storebi1_BITS)
- op = Hexagon::V4_SS2_storebi1;
- else if ((inst & V4_SS2_stored_sp_MASK) == V4_SS2_stored_sp_BITS)
- op = Hexagon::V4_SS2_stored_sp;
- else if ((inst & V4_SS2_storeh_io_MASK) == V4_SS2_storeh_io_BITS)
- op = Hexagon::V4_SS2_storeh_io;
- else if ((inst & V4_SS2_storew_sp_MASK) == V4_SS2_storew_sp_BITS)
- op = Hexagon::V4_SS2_storew_sp;
- else if ((inst & V4_SS2_storewi0_MASK) == V4_SS2_storewi0_BITS)
- op = Hexagon::V4_SS2_storewi0;
- else if ((inst & V4_SS2_storewi1_MASK) == V4_SS2_storewi1_BITS)
- op = Hexagon::V4_SS2_storewi1;
+ if ((inst & SS2_allocframe_MASK) == SS2_allocframe_BITS)
+ op = Hexagon::SS2_allocframe;
+ else if ((inst & SS2_storebi0_MASK) == SS2_storebi0_BITS)
+ op = Hexagon::SS2_storebi0;
+ else if ((inst & SS2_storebi1_MASK) == SS2_storebi1_BITS)
+ op = Hexagon::SS2_storebi1;
+ else if ((inst & SS2_stored_sp_MASK) == SS2_stored_sp_BITS)
+ op = Hexagon::SS2_stored_sp;
+ else if ((inst & SS2_storeh_io_MASK) == SS2_storeh_io_BITS)
+ op = Hexagon::SS2_storeh_io;
+ else if ((inst & SS2_storew_sp_MASK) == SS2_storew_sp_BITS)
+ op = Hexagon::SS2_storew_sp;
+ else if ((inst & SS2_storewi0_MASK) == SS2_storewi0_BITS)
+ op = Hexagon::SS2_storewi0;
+ else if ((inst & SS2_storewi1_MASK) == SS2_storewi1_BITS)
+ op = Hexagon::SS2_storewi1;
else {
os << "<unknown subinstruction>";
return MCDisassembler::Fail;
@@ -1362,25 +1377,25 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
int64_t operand;
MCOperand Op;
switch (opcode) {
- case Hexagon::V4_SL2_deallocframe:
- case Hexagon::V4_SL2_jumpr31:
- case Hexagon::V4_SL2_jumpr31_f:
- case Hexagon::V4_SL2_jumpr31_fnew:
- case Hexagon::V4_SL2_jumpr31_t:
- case Hexagon::V4_SL2_jumpr31_tnew:
- case Hexagon::V4_SL2_return:
- case Hexagon::V4_SL2_return_f:
- case Hexagon::V4_SL2_return_fnew:
- case Hexagon::V4_SL2_return_t:
- case Hexagon::V4_SL2_return_tnew:
+ case Hexagon::SL2_deallocframe:
+ case Hexagon::SL2_jumpr31:
+ case Hexagon::SL2_jumpr31_f:
+ case Hexagon::SL2_jumpr31_fnew:
+ case Hexagon::SL2_jumpr31_t:
+ case Hexagon::SL2_jumpr31_tnew:
+ case Hexagon::SL2_return:
+ case Hexagon::SL2_return_f:
+ case Hexagon::SL2_return_fnew:
+ case Hexagon::SL2_return_t:
+ case Hexagon::SL2_return_tnew:
// no operands for these instructions
break;
- case Hexagon::V4_SS2_allocframe:
+ case Hexagon::SS2_allocframe:
// u 8-4{5_3}
operand = ((inst & 0x1f0) >> 4) << 3;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SL1_loadri_io:
+ case Hexagon::SL1_loadri_io:
// Rd 3-0, Rs 7-4, u 11-8{4_2}
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1391,7 +1406,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = (inst & 0xf00) >> 6;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SL1_loadrub_io:
+ case Hexagon::SL1_loadrub_io:
// Rd 3-0, Rs 7-4, u 11-8
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1402,7 +1417,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = (inst & 0xf00) >> 8;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SL2_loadrb_io:
+ case Hexagon::SL2_loadrb_io:
// Rd 3-0, Rs 7-4, u 10-8
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1413,8 +1428,8 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = (inst & 0x700) >> 8;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SL2_loadrh_io:
- case Hexagon::V4_SL2_loadruh_io:
+ case Hexagon::SL2_loadrh_io:
+ case Hexagon::SL2_loadruh_io:
// Rd 3-0, Rs 7-4, u 10-8{3_1}
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1425,7 +1440,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = ((inst & 0x700) >> 8) << 1;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SL2_loadrd_sp:
+ case Hexagon::SL2_loadrd_sp:
// Rdd 2-0, u 7-3{5_3}
operand = getDRegFromSubinstEncoding(inst & 0x7);
Op = MCOperand::createReg(operand);
@@ -1433,7 +1448,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = ((inst & 0x0f8) >> 3) << 3;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SL2_loadri_sp:
+ case Hexagon::SL2_loadri_sp:
// Rd 3-0, u 8-4{5_2}
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1441,7 +1456,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = ((inst & 0x1f0) >> 4) << 2;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SA1_addi:
+ case Hexagon::SA1_addi:
// Rx 3-0 (x2), s7 10-4
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1450,7 +1465,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = SignExtend64<7>((inst & 0x7f0) >> 4);
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SA1_addrx:
+ case Hexagon::SA1_addrx:
// Rx 3-0 (x2), Rs 7-4
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1460,14 +1475,14 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SA1_and1:
- case Hexagon::V4_SA1_dec:
- case Hexagon::V4_SA1_inc:
- case Hexagon::V4_SA1_sxtb:
- case Hexagon::V4_SA1_sxth:
- case Hexagon::V4_SA1_tfr:
- case Hexagon::V4_SA1_zxtb:
- case Hexagon::V4_SA1_zxth:
+ case Hexagon::SA1_and1:
+ case Hexagon::SA1_dec:
+ case Hexagon::SA1_inc:
+ case Hexagon::SA1_sxtb:
+ case Hexagon::SA1_sxth:
+ case Hexagon::SA1_tfr:
+ case Hexagon::SA1_zxtb:
+ case Hexagon::SA1_zxth:
// Rd 3-0, Rs 7-4
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1476,7 +1491,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SA1_addsp:
+ case Hexagon::SA1_addsp:
// Rd 3-0, u 9-4{6_2}
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1484,7 +1499,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = ((inst & 0x3f0) >> 4) << 2;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SA1_seti:
+ case Hexagon::SA1_seti:
// Rd 3-0, u 9-4
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
@@ -1492,17 +1507,20 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = (inst & 0x3f0) >> 4;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SA1_clrf:
- case Hexagon::V4_SA1_clrfnew:
- case Hexagon::V4_SA1_clrt:
- case Hexagon::V4_SA1_clrtnew:
- case Hexagon::V4_SA1_setin1:
+ case Hexagon::SA1_clrf:
+ case Hexagon::SA1_clrfnew:
+ case Hexagon::SA1_clrt:
+ case Hexagon::SA1_clrtnew:
+ case Hexagon::SA1_setin1:
// Rd 3-0
operand = getRegFromSubinstEncoding(inst & 0xf);
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
+ if (opcode == Hexagon::SA1_setin1)
+ break;
+ MI->addOperand(MCOperand::createReg(Hexagon::P0));
break;
- case Hexagon::V4_SA1_cmpeqi:
+ case Hexagon::SA1_cmpeqi:
// Rs 7-4, u 1-0
operand = getRegFromSubinstEncoding((inst & 0xf0) >> 4);
Op = MCOperand::createReg(operand);
@@ -1510,10 +1528,10 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = inst & 0x3;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SA1_combine0i:
- case Hexagon::V4_SA1_combine1i:
- case Hexagon::V4_SA1_combine2i:
- case Hexagon::V4_SA1_combine3i:
+ case Hexagon::SA1_combine0i:
+ case Hexagon::SA1_combine1i:
+ case Hexagon::SA1_combine2i:
+ case Hexagon::SA1_combine3i:
// Rdd 2-0, u 6-5
operand = getDRegFromSubinstEncoding(inst & 0x7);
Op = MCOperand::createReg(operand);
@@ -1521,8 +1539,8 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = (inst & 0x060) >> 5;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SA1_combinerz:
- case Hexagon::V4_SA1_combinezr:
+ case Hexagon::SA1_combinerz:
+ case Hexagon::SA1_combinezr:
// Rdd 2-0, Rs 7-4
operand = getDRegFromSubinstEncoding(inst & 0x7);
Op = MCOperand::createReg(operand);
@@ -1531,7 +1549,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SS1_storeb_io:
+ case Hexagon::SS1_storeb_io:
// Rs 7-4, u 11-8, Rt 3-0
operand = getRegFromSubinstEncoding((inst & 0xf0) >> 4);
Op = MCOperand::createReg(operand);
@@ -1542,7 +1560,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SS1_storew_io:
+ case Hexagon::SS1_storew_io:
// Rs 7-4, u 11-8{4_2}, Rt 3-0
operand = getRegFromSubinstEncoding((inst & 0xf0) >> 4);
Op = MCOperand::createReg(operand);
@@ -1553,8 +1571,8 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SS2_storebi0:
- case Hexagon::V4_SS2_storebi1:
+ case Hexagon::SS2_storebi0:
+ case Hexagon::SS2_storebi1:
// Rs 7-4, u 3-0
operand = getRegFromSubinstEncoding((inst & 0xf0) >> 4);
Op = MCOperand::createReg(operand);
@@ -1562,8 +1580,8 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = inst & 0xf;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SS2_storewi0:
- case Hexagon::V4_SS2_storewi1:
+ case Hexagon::SS2_storewi0:
+ case Hexagon::SS2_storewi1:
// Rs 7-4, u 3-0{4_2}
operand = getRegFromSubinstEncoding((inst & 0xf0) >> 4);
Op = MCOperand::createReg(operand);
@@ -1571,7 +1589,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
operand = (inst & 0xf) << 2;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
break;
- case Hexagon::V4_SS2_stored_sp:
+ case Hexagon::SS2_stored_sp:
// s 8-3{6_3}, Rtt 2-0
operand = SignExtend64<9>(((inst & 0x1f8) >> 3) << 3);
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
@@ -1579,7 +1597,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SS2_storeh_io:
+ case Hexagon::SS2_storeh_io:
// Rs 7-4, u 10-8{3_1}, Rt 3-0
operand = getRegFromSubinstEncoding((inst & 0xf0) >> 4);
Op = MCOperand::createReg(operand);
@@ -1590,7 +1608,7 @@ void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode,
Op = MCOperand::createReg(operand);
MI->addOperand(Op);
break;
- case Hexagon::V4_SS2_storew_sp:
+ case Hexagon::SS2_storew_sp:
// u 8-4{5_2}, Rd 3-0
operand = ((inst & 0x1f0) >> 4) << 2;
HexagonMCInstrInfo::addConstant(*MI, operand, getContext());
diff --git a/contrib/llvm/lib/Target/Hexagon/Hexagon.td b/contrib/llvm/lib/Target/Hexagon/Hexagon.td
index aaa0f3e..0b2b463 100644
--- a/contrib/llvm/lib/Target/Hexagon/Hexagon.td
+++ b/contrib/llvm/lib/Target/Hexagon/Hexagon.td
@@ -27,11 +27,12 @@ def ArchV5: SubtargetFeature<"v5", "HexagonArchVersion", "V5", "Hexagon V5">;
def ArchV55: SubtargetFeature<"v55", "HexagonArchVersion", "V55", "Hexagon V55">;
def ArchV60: SubtargetFeature<"v60", "HexagonArchVersion", "V60", "Hexagon V60">;
-// Hexagon ISA Extensions
-def ExtensionHVX: SubtargetFeature<"hvx", "UseHVXOps",
- "true", "Hexagon HVX instructions">;
-def ExtensionHVXDbl: SubtargetFeature<"hvx-double", "UseHVXDblOps",
- "true", "Hexagon HVX Double instructions">;
+def FeatureHVX: SubtargetFeature<"hvx", "UseHVXOps", "true",
+ "Hexagon HVX instructions">;
+def FeatureHVXDbl: SubtargetFeature<"hvx-double", "UseHVXDblOps", "true",
+ "Hexagon HVX Double instructions">;
+def FeatureLongCalls: SubtargetFeature<"long-calls", "UseLongCalls", "true",
+ "Use constant-extended calls">;
//===----------------------------------------------------------------------===//
// Hexagon Instruction Predicate Definitions.
@@ -45,10 +46,10 @@ def HasV60T : Predicate<"HST->hasV60TOps()">,
def UseMEMOP : Predicate<"HST->useMemOps()">;
def IEEERndNearV5T : Predicate<"HST->modeIEEERndNear()">;
def UseHVXDbl : Predicate<"HST->useHVXDblOps()">,
- AssemblerPredicate<"ExtensionHVXDbl">;
+ AssemblerPredicate<"FeatureHVXDbl">;
def UseHVXSgl : Predicate<"HST->useHVXSglOps()">;
def UseHVX : Predicate<"HST->useHVXSglOps() ||HST->useHVXDblOps()">,
- AssemblerPredicate<"ExtensionHVX">;
+ AssemblerPredicate<"FeatureHVX">;
//===----------------------------------------------------------------------===//
// Classes used for relation maps.
@@ -249,6 +250,7 @@ include "HexagonSchedule.td"
include "HexagonRegisterInfo.td"
include "HexagonCallingConv.td"
include "HexagonInstrInfo.td"
+include "HexagonPatterns.td"
include "HexagonIntrinsics.td"
include "HexagonIntrinsicsDerived.td"
@@ -269,7 +271,7 @@ def : Proc<"hexagonv5", HexagonModelV4,
def : Proc<"hexagonv55", HexagonModelV55,
[ArchV4, ArchV5, ArchV55]>;
def : Proc<"hexagonv60", HexagonModelV60,
- [ArchV4, ArchV5, ArchV55, ArchV60, ExtensionHVX]>;
+ [ArchV4, ArchV5, ArchV55, ArchV60, FeatureHVX]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
@@ -282,7 +284,7 @@ def HexagonAsmParser : AsmParser {
def HexagonAsmParserVariant : AsmParserVariant {
int Variant = 0;
- string TokenizingCharacters = "#()=:.<>!+*";
+ string TokenizingCharacters = "#()=:.<>!+*-|^&";
}
def Hexagon : Target {
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
index cd954a1..54db5ad 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
@@ -81,7 +81,7 @@ HexagonAsmPrinter::HexagonAsmPrinter(TargetMachine &TM,
: AsmPrinter(TM, std::move(Streamer)), Subtarget(nullptr) {}
void HexagonAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
- raw_ostream &O) {
+ raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(OpNo);
switch (MO.getType()) {
@@ -141,14 +141,22 @@ bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
// Hexagon never has a prefix.
printOperand(MI, OpNo, OS);
return false;
- case 'L': // Write second word of DImode reference.
- // Verify that this operand has two consecutive registers.
- if (!MI->getOperand(OpNo).isReg() ||
- OpNo+1 == MI->getNumOperands() ||
- !MI->getOperand(OpNo+1).isReg())
+ case 'L':
+ case 'H': { // The highest-numbered register of a pair.
+ const MachineOperand &MO = MI->getOperand(OpNo);
+ const MachineFunction &MF = *MI->getParent()->getParent();
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+ if (!MO.isReg())
return true;
- ++OpNo; // Return the high-part.
- break;
+ unsigned RegNumber = MO.getReg();
+ // This should be an assert in the frontend.
+ if (Hexagon::DoubleRegsRegClass.contains(RegNumber))
+ RegNumber = TRI->getSubReg(RegNumber, ExtraCode[0] == 'L' ?
+ Hexagon::isub_lo :
+ Hexagon::isub_hi);
+ OS << HexagonInstPrinter::getRegisterName(RegNumber);
+ return false;
+ }
case 'I':
// Write 'i' if an integer constant, otherwise nothing. Used to print
// addi vs add, etc.
@@ -163,9 +171,9 @@ bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
}
bool HexagonAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
- unsigned OpNo, unsigned AsmVariant,
- const char *ExtraCode,
- raw_ostream &O) {
+ unsigned OpNo, unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &O) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
@@ -275,8 +283,7 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
}
// "$dst = CONST64(#$src1)",
- case Hexagon::CONST64_Float_Real:
- case Hexagon::CONST64_Int_Real:
+ case Hexagon::CONST64:
if (!OutStreamer->hasRawTextSupport()) {
const MCOperand &Imm = MappedInst.getOperand(1);
MCSectionSubPair Current = OutStreamer->getCurrentSection();
@@ -295,9 +302,6 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
}
break;
case Hexagon::CONST32:
- case Hexagon::CONST32_Float_Real:
- case Hexagon::CONST32_Int_Real:
- case Hexagon::FCONST32_nsdata:
if (!OutStreamer->hasRawTextSupport()) {
MCOperand &Imm = MappedInst.getOperand(1);
MCSectionSubPair Current = OutStreamer->getCurrentSection();
@@ -410,8 +414,8 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
TmpInst.setOpcode(Hexagon::A2_combinew);
TmpInst.addOperand(MappedInst.getOperand(0));
MCOperand &MO1 = MappedInst.getOperand(1);
- unsigned High = RI->getSubReg(MO1.getReg(), Hexagon::subreg_hireg);
- unsigned Low = RI->getSubReg(MO1.getReg(), Hexagon::subreg_loreg);
+ unsigned High = RI->getSubReg(MO1.getReg(), Hexagon::isub_hi);
+ unsigned Low = RI->getSubReg(MO1.getReg(), Hexagon::isub_lo);
// Add a new operand for the second register in the pair.
TmpInst.addOperand(MCOperand::createReg(High));
TmpInst.addOperand(MCOperand::createReg(Low));
@@ -458,21 +462,6 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
MappedInst = TmpInst;
return;
}
- case Hexagon::TFRI_f:
- MappedInst.setOpcode(Hexagon::A2_tfrsi);
- return;
- case Hexagon::TFRI_cPt_f:
- MappedInst.setOpcode(Hexagon::C2_cmoveit);
- return;
- case Hexagon::TFRI_cNotPt_f:
- MappedInst.setOpcode(Hexagon::C2_cmoveif);
- return;
- case Hexagon::MUX_ri_f:
- MappedInst.setOpcode(Hexagon::C2_muxri);
- return;
- case Hexagon::MUX_ir_f:
- MappedInst.setOpcode(Hexagon::C2_muxir);
- return;
// Translate a "$Rdd = #imm" to "$Rdd = combine(#[-1,0], #imm)"
case Hexagon::A2_tfrpi: {
@@ -498,8 +487,8 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
// Translate a "$Rdd = $Rss" to "$Rdd = combine($Rs, $Rt)"
case Hexagon::A2_tfrp: {
MCOperand &MO = MappedInst.getOperand(1);
- unsigned High = RI->getSubReg(MO.getReg(), Hexagon::subreg_hireg);
- unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::subreg_loreg);
+ unsigned High = RI->getSubReg(MO.getReg(), Hexagon::isub_hi);
+ unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::isub_lo);
MO.setReg(High);
// Add a new operand for the second register in the pair.
MappedInst.addOperand(MCOperand::createReg(Low));
@@ -510,8 +499,8 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
case Hexagon::A2_tfrpt:
case Hexagon::A2_tfrpf: {
MCOperand &MO = MappedInst.getOperand(2);
- unsigned High = RI->getSubReg(MO.getReg(), Hexagon::subreg_hireg);
- unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::subreg_loreg);
+ unsigned High = RI->getSubReg(MO.getReg(), Hexagon::isub_hi);
+ unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::isub_lo);
MO.setReg(High);
// Add a new operand for the second register in the pair.
MappedInst.addOperand(MCOperand::createReg(Low));
@@ -523,8 +512,8 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
case Hexagon::A2_tfrptnew:
case Hexagon::A2_tfrpfnew: {
MCOperand &MO = MappedInst.getOperand(2);
- unsigned High = RI->getSubReg(MO.getReg(), Hexagon::subreg_hireg);
- unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::subreg_loreg);
+ unsigned High = RI->getSubReg(MO.getReg(), Hexagon::isub_hi);
+ unsigned Low = RI->getSubReg(MO.getReg(), Hexagon::isub_lo);
MO.setReg(High);
// Add a new operand for the second register in the pair.
MappedInst.addOperand(MCOperand::createReg(Low));
@@ -561,8 +550,8 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
Rt.setReg(getHexagonRegisterPair(Rt.getReg(), RI));
return;
}
- case Hexagon::HEXAGON_V6_vd0_pseudo:
- case Hexagon::HEXAGON_V6_vd0_pseudo_128B: {
+ case Hexagon::V6_vd0:
+ case Hexagon::V6_vd0_128B: {
MCInst TmpInst;
assert (Inst.getOperand(0).isReg() &&
"Expected register and none was found");
@@ -611,5 +600,5 @@ void HexagonAsmPrinter::EmitInstruction(const MachineInstr *MI) {
}
extern "C" void LLVMInitializeHexagonAsmPrinter() {
- RegisterAsmPrinter<HexagonAsmPrinter> X(TheHexagonTarget);
+ RegisterAsmPrinter<HexagonAsmPrinter> X(getTheHexagonTarget());
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h b/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
index a78d97e..775da03 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonAsmPrinter.h
@@ -33,7 +33,7 @@ namespace llvm {
return AsmPrinter::runOnMachineFunction(Fn);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon Assembly Printer";
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonBitSimplify.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonBitSimplify.cpp
index c8b4a4c..fe7278f 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonBitSimplify.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonBitSimplify.cpp
@@ -11,29 +11,56 @@
#include "HexagonBitTracker.h"
#include "HexagonTargetMachine.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <utility>
+#include <vector>
using namespace llvm;
+static cl::opt<bool> PreserveTiedOps("hexbit-keep-tied", cl::Hidden,
+ cl::init(true), cl::desc("Preserve subregisters in tied operands"));
+
namespace llvm {
+
void initializeHexagonBitSimplifyPass(PassRegistry& Registry);
FunctionPass *createHexagonBitSimplify();
-}
+
+} // end namespace llvm
namespace {
+
// Set of virtual registers, based on BitVector.
struct RegisterSet : private BitVector {
- RegisterSet() : BitVector() {}
+ RegisterSet() = default;
explicit RegisterSet(unsigned s, bool t = false) : BitVector(s, t) {}
- RegisterSet(const RegisterSet &RS) : BitVector(RS) {}
+ RegisterSet(const RegisterSet &RS) = default;
using BitVector::clear;
using BitVector::count;
@@ -104,20 +131,23 @@ namespace {
if (size() <= Idx)
resize(std::max(Idx+1, 32U));
}
+
static inline unsigned v2x(unsigned v) {
return TargetRegisterInfo::virtReg2Index(v);
}
+
static inline unsigned x2v(unsigned x) {
return TargetRegisterInfo::index2VirtReg(x);
}
};
-
struct PrintRegSet {
PrintRegSet(const RegisterSet &S, const TargetRegisterInfo *RI)
: RS(S), TRI(RI) {}
+
friend raw_ostream &operator<< (raw_ostream &OS,
const PrintRegSet &P);
+
private:
const RegisterSet &RS;
const TargetRegisterInfo *TRI;
@@ -132,27 +162,28 @@ namespace {
OS << " }";
return OS;
}
-}
-
-namespace {
class Transformation;
class HexagonBitSimplify : public MachineFunctionPass {
public:
static char ID;
- HexagonBitSimplify() : MachineFunctionPass(ID), MDT(0) {
+
+ HexagonBitSimplify() : MachineFunctionPass(ID), MDT(nullptr) {
initializeHexagonBitSimplifyPass(*PassRegistry::getPassRegistry());
}
- virtual const char *getPassName() const {
+
+ StringRef getPassName() const override {
return "Hexagon bit simplification";
}
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
- virtual bool runOnMachineFunction(MachineFunction &MF);
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
static void getInstrDefs(const MachineInstr &MI, RegisterSet &Defs);
static void getInstrUses(const MachineInstr &MI, RegisterSet &Uses);
@@ -171,7 +202,8 @@ namespace {
static bool replaceSubWithSub(unsigned OldR, unsigned OldSR,
unsigned NewR, unsigned NewSR, MachineRegisterInfo &MRI);
static bool parseRegSequence(const MachineInstr &I,
- BitTracker::RegisterRef &SL, BitTracker::RegisterRef &SH);
+ BitTracker::RegisterRef &SL, BitTracker::RegisterRef &SH,
+ const MachineRegisterInfo &MRI);
static bool getUsedBitsInStore(unsigned Opc, BitVector &Bits,
uint16_t Begin);
@@ -187,23 +219,27 @@ namespace {
MachineDominatorTree *MDT;
bool visitBlock(MachineBasicBlock &B, Transformation &T, RegisterSet &AVs);
+ static bool hasTiedUse(unsigned Reg, MachineRegisterInfo &MRI,
+ unsigned NewSub = Hexagon::NoSubRegister);
};
char HexagonBitSimplify::ID = 0;
typedef HexagonBitSimplify HBS;
-
// The purpose of this class is to provide a common facility to traverse
// the function top-down or bottom-up via the dominator tree, and keep
// track of the available registers.
class Transformation {
public:
bool TopDown;
+
Transformation(bool TD) : TopDown(TD) {}
+ virtual ~Transformation() = default;
+
virtual bool processBlock(MachineBasicBlock &B, const RegisterSet &AVs) = 0;
- virtual ~Transformation() {}
};
-}
+
+} // end anonymous namespace
INITIALIZE_PASS_BEGIN(HexagonBitSimplify, "hexbit",
"Hexagon bit simplification", false, false)
@@ -211,7 +247,6 @@ INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_END(HexagonBitSimplify, "hexbit",
"Hexagon bit simplification", false, false)
-
bool HexagonBitSimplify::visitBlock(MachineBasicBlock &B, Transformation &T,
RegisterSet &AVs) {
MachineDomTreeNode *N = MDT->getNode(&B);
@@ -290,7 +325,6 @@ bool HexagonBitSimplify::isZero(const BitTracker::RegisterCell &RC,
return true;
}
-
bool HexagonBitSimplify::getConst(const BitTracker::RegisterCell &RC,
uint16_t B, uint16_t W, uint64_t &U) {
assert(B < RC.width() && B+W <= RC.width());
@@ -307,7 +341,6 @@ bool HexagonBitSimplify::getConst(const BitTracker::RegisterCell &RC,
return true;
}
-
bool HexagonBitSimplify::replaceReg(unsigned OldR, unsigned NewR,
MachineRegisterInfo &MRI) {
if (!TargetRegisterInfo::isVirtualRegister(OldR) ||
@@ -322,12 +355,13 @@ bool HexagonBitSimplify::replaceReg(unsigned OldR, unsigned NewR,
return Begin != End;
}
-
bool HexagonBitSimplify::replaceRegWithSub(unsigned OldR, unsigned NewR,
unsigned NewSR, MachineRegisterInfo &MRI) {
if (!TargetRegisterInfo::isVirtualRegister(OldR) ||
!TargetRegisterInfo::isVirtualRegister(NewR))
return false;
+ if (hasTiedUse(OldR, MRI, NewSR))
+ return false;
auto Begin = MRI.use_begin(OldR), End = MRI.use_end();
decltype(End) NextI;
for (auto I = Begin; I != End; I = NextI) {
@@ -338,12 +372,13 @@ bool HexagonBitSimplify::replaceRegWithSub(unsigned OldR, unsigned NewR,
return Begin != End;
}
-
bool HexagonBitSimplify::replaceSubWithSub(unsigned OldR, unsigned OldSR,
unsigned NewR, unsigned NewSR, MachineRegisterInfo &MRI) {
if (!TargetRegisterInfo::isVirtualRegister(OldR) ||
!TargetRegisterInfo::isVirtualRegister(NewR))
return false;
+ if (OldSR != NewSR && hasTiedUse(OldR, MRI, NewSR))
+ return false;
auto Begin = MRI.use_begin(OldR), End = MRI.use_end();
decltype(End) NextI;
for (auto I = Begin; I != End; I = NextI) {
@@ -356,47 +391,54 @@ bool HexagonBitSimplify::replaceSubWithSub(unsigned OldR, unsigned OldSR,
return Begin != End;
}
-
// For a register ref (pair Reg:Sub), set Begin to the position of the LSB
// of Sub in Reg, and set Width to the size of Sub in bits. Return true,
// if this succeeded, otherwise return false.
bool HexagonBitSimplify::getSubregMask(const BitTracker::RegisterRef &RR,
unsigned &Begin, unsigned &Width, MachineRegisterInfo &MRI) {
const TargetRegisterClass *RC = MRI.getRegClass(RR.Reg);
- if (RC == &Hexagon::IntRegsRegClass) {
- assert(RR.Sub == 0);
+ if (RR.Sub == 0) {
Begin = 0;
- Width = 32;
+ Width = RC->getSize()*8;
return true;
}
- if (RC == &Hexagon::DoubleRegsRegClass) {
- if (RR.Sub == 0) {
- Begin = 0;
- Width = 64;
- return true;
- }
- assert(RR.Sub == Hexagon::subreg_loreg || RR.Sub == Hexagon::subreg_hireg);
- Width = 32;
- Begin = (RR.Sub == Hexagon::subreg_loreg ? 0 : 32);
- return true;
+
+ Begin = 0;
+
+ switch (RC->getID()) {
+ case Hexagon::DoubleRegsRegClassID:
+ case Hexagon::VecDblRegsRegClassID:
+ case Hexagon::VecDblRegs128BRegClassID:
+ Width = RC->getSize()*8 / 2;
+ if (RR.Sub == Hexagon::isub_hi || RR.Sub == Hexagon::vsub_hi)
+ Begin = Width;
+ break;
+ default:
+ return false;
}
- return false;
+ return true;
}
// For a REG_SEQUENCE, set SL to the low subregister and SH to the high
// subregister.
bool HexagonBitSimplify::parseRegSequence(const MachineInstr &I,
- BitTracker::RegisterRef &SL, BitTracker::RegisterRef &SH) {
+ BitTracker::RegisterRef &SL, BitTracker::RegisterRef &SH,
+ const MachineRegisterInfo &MRI) {
assert(I.getOpcode() == TargetOpcode::REG_SEQUENCE);
unsigned Sub1 = I.getOperand(2).getImm(), Sub2 = I.getOperand(4).getImm();
- assert(Sub1 != Sub2);
- if (Sub1 == Hexagon::subreg_loreg && Sub2 == Hexagon::subreg_hireg) {
+ auto *DstRC = MRI.getRegClass(I.getOperand(0).getReg());
+ auto &HRI = static_cast<const HexagonRegisterInfo&>(
+ *MRI.getTargetRegisterInfo());
+ unsigned SubLo = HRI.getHexagonSubRegIndex(DstRC, Hexagon::ps_sub_lo);
+ unsigned SubHi = HRI.getHexagonSubRegIndex(DstRC, Hexagon::ps_sub_hi);
+ assert((Sub1 == SubLo && Sub2 == SubHi) || (Sub1 == SubHi && Sub2 == SubLo));
+ if (Sub1 == SubLo && Sub2 == SubHi) {
SL = I.getOperand(1);
SH = I.getOperand(3);
return true;
}
- if (Sub1 == Hexagon::subreg_hireg && Sub2 == Hexagon::subreg_loreg) {
+ if (Sub1 == SubHi && Sub2 == SubLo) {
SH = I.getOperand(1);
SL = I.getOperand(3);
return true;
@@ -404,7 +446,6 @@ bool HexagonBitSimplify::parseRegSequence(const MachineInstr &I,
return false;
}
-
// All stores (except 64-bit stores) take a 32-bit register as the source
// of the value to be stored. If the instruction stores into a location
// that is shorter than 32 bits, some bits of the source register are not
@@ -562,7 +603,6 @@ bool HexagonBitSimplify::getUsedBitsInStore(unsigned Opc, BitVector &Bits,
return false;
}
-
// For an instruction with opcode Opc, calculate the set of bits that it
// uses in a register in operand OpN. This only calculates the set of used
// bits for cases where it does not depend on any operands (as is the case
@@ -842,9 +882,8 @@ bool HexagonBitSimplify::getUsedBits(unsigned Opc, unsigned OpN,
return false;
}
-
// Calculate the register class that matches Reg:Sub. For example, if
-// vreg1 is a double register, then vreg1:subreg_hireg would match "int"
+// vreg1 is a double register, then vreg1:isub_hi would match the "int"
// register class.
const TargetRegisterClass *HexagonBitSimplify::getFinalVRegClass(
const BitTracker::RegisterRef &RR, MachineRegisterInfo &MRI) {
@@ -853,26 +892,28 @@ const TargetRegisterClass *HexagonBitSimplify::getFinalVRegClass(
auto *RC = MRI.getRegClass(RR.Reg);
if (RR.Sub == 0)
return RC;
+ auto &HRI = static_cast<const HexagonRegisterInfo&>(
+ *MRI.getTargetRegisterInfo());
- auto VerifySR = [] (unsigned Sub) -> void {
- assert(Sub == Hexagon::subreg_hireg || Sub == Hexagon::subreg_loreg);
+ auto VerifySR = [&HRI] (const TargetRegisterClass *RC, unsigned Sub) -> void {
+ assert(Sub == HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_lo) ||
+ Sub == HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_hi));
};
switch (RC->getID()) {
case Hexagon::DoubleRegsRegClassID:
- VerifySR(RR.Sub);
+ VerifySR(RC, RR.Sub);
return &Hexagon::IntRegsRegClass;
case Hexagon::VecDblRegsRegClassID:
- VerifySR(RR.Sub);
+ VerifySR(RC, RR.Sub);
return &Hexagon::VectorRegsRegClass;
case Hexagon::VecDblRegs128BRegClassID:
- VerifySR(RR.Sub);
+ VerifySR(RC, RR.Sub);
return &Hexagon::VectorRegs128BRegClass;
}
return nullptr;
}
-
// Check if RD could be replaced with RS at any possible use of RD.
// For example a predicate register cannot be replaced with a integer
// register, but a 64-bit register with a subregister can be replaced
@@ -890,11 +931,18 @@ bool HexagonBitSimplify::isTransparentCopy(const BitTracker::RegisterRef &RD,
return DRC == getFinalVRegClass(RS, MRI);
}
+bool HexagonBitSimplify::hasTiedUse(unsigned Reg, MachineRegisterInfo &MRI,
+ unsigned NewSub) {
+ if (!PreserveTiedOps)
+ return false;
+ return llvm::any_of(MRI.use_operands(Reg),
+ [NewSub] (const MachineOperand &Op) -> bool {
+ return Op.getSubReg() != NewSub && Op.isTied();
+ });
+}
-//
-// Dead code elimination
-//
namespace {
+
class DeadCodeElimination {
public:
DeadCodeElimination(MachineFunction &mf, MachineDominatorTree &mdt)
@@ -914,8 +962,8 @@ namespace {
MachineDominatorTree &MDT;
MachineRegisterInfo &MRI;
};
-}
+} // end anonymous namespace
bool DeadCodeElimination::isDead(unsigned R) const {
for (auto I = MRI.use_begin(R), E = MRI.use_end(); I != E; ++I) {
@@ -933,7 +981,6 @@ bool DeadCodeElimination::isDead(unsigned R) const {
return true;
}
-
bool DeadCodeElimination::runOnNode(MachineDomTreeNode *N) {
bool Changed = false;
typedef GraphTraits<MachineDomTreeNode*> GTN;
@@ -983,8 +1030,8 @@ bool DeadCodeElimination::runOnNode(MachineDomTreeNode *N) {
return Changed;
}
+namespace {
-//
// Eliminate redundant instructions
//
// This transformation will identify instructions where the output register
@@ -995,13 +1042,14 @@ bool DeadCodeElimination::runOnNode(MachineDomTreeNode *N) {
// registers.
// If the output matches an input, the instruction is replaced with COPY.
// The copies will be removed by another transformation.
-namespace {
class RedundantInstrElimination : public Transformation {
public:
RedundantInstrElimination(BitTracker &bt, const HexagonInstrInfo &hii,
MachineRegisterInfo &mri)
: Transformation(true), HII(hii), MRI(mri), BT(bt) {}
+
bool processBlock(MachineBasicBlock &B, const RegisterSet &AVs) override;
+
private:
bool isLossyShiftLeft(const MachineInstr &MI, unsigned OpN,
unsigned &LostB, unsigned &LostE);
@@ -1016,8 +1064,8 @@ namespace {
MachineRegisterInfo &MRI;
BitTracker &BT;
};
-}
+} // end anonymous namespace
// Check if the instruction is a lossy shift left, where the input being
// shifted is the operand OpN of MI. If true, [LostB, LostE) is the range
@@ -1025,6 +1073,7 @@ namespace {
bool RedundantInstrElimination::isLossyShiftLeft(const MachineInstr &MI,
unsigned OpN, unsigned &LostB, unsigned &LostE) {
using namespace Hexagon;
+
unsigned Opc = MI.getOpcode();
unsigned ImN, RegN, Width;
switch (Opc) {
@@ -1078,13 +1127,13 @@ bool RedundantInstrElimination::isLossyShiftLeft(const MachineInstr &MI,
return true;
}
-
// Check if the instruction is a lossy shift right, where the input being
// shifted is the operand OpN of MI. If true, [LostB, LostE) is the range
// of bit indices that are lost.
bool RedundantInstrElimination::isLossyShiftRight(const MachineInstr &MI,
unsigned OpN, unsigned &LostB, unsigned &LostE) {
using namespace Hexagon;
+
unsigned Opc = MI.getOpcode();
unsigned ImN, RegN;
switch (Opc) {
@@ -1141,7 +1190,6 @@ bool RedundantInstrElimination::isLossyShiftRight(const MachineInstr &MI,
return true;
}
-
// Calculate the bit vector that corresponds to the used bits of register Reg.
// The vector Bits has the same size, as the size of Reg in bits. If the cal-
// culation fails (i.e. the used bits are unknown), it returns false. Other-
@@ -1178,7 +1226,6 @@ bool RedundantInstrElimination::computeUsedBits(unsigned Reg, BitVector &Bits) {
return true;
}
-
// Calculate the bits used by instruction MI in a register in operand OpN.
// Return true/false if the calculation succeeds/fails. If is succeeds, set
// used bits in Bits. This function does not reset any bits in Bits, so
@@ -1188,11 +1235,11 @@ bool RedundantInstrElimination::computeUsedBits(unsigned Reg, BitVector &Bits) {
// holds the bits for the entire register. To keep track of that, the
// argument Begin indicates where in Bits is the lowest-significant bit
// of the register used in operand OpN. For example, in instruction:
-// vreg1 = S2_lsr_i_r vreg2:subreg_hireg, 10
+// vreg1 = S2_lsr_i_r vreg2:isub_hi, 10
// the operand 1 is a 32-bit register, which happens to be a subregister
// of the 64-bit register vreg2, and that subregister starts at position 32.
// In this case Begin=32, since Bits[32] would be the lowest-significant bit
-// of vreg2:subreg_hireg.
+// of vreg2:isub_hi.
bool RedundantInstrElimination::computeUsedBits(const MachineInstr &MI,
unsigned OpN, BitVector &Bits, uint16_t Begin) {
unsigned Opc = MI.getOpcode();
@@ -1219,7 +1266,6 @@ bool RedundantInstrElimination::computeUsedBits(const MachineInstr &MI,
return GotBits;
}
-
// Calculates the used bits in RD ("defined register"), and checks if these
// bits in RS ("used register") and RD are identical.
bool RedundantInstrElimination::usedBitsEqual(BitTracker::RegisterRef RD,
@@ -1246,9 +1292,10 @@ bool RedundantInstrElimination::usedBitsEqual(BitTracker::RegisterRef RD,
return true;
}
-
bool RedundantInstrElimination::processBlock(MachineBasicBlock &B,
const RegisterSet&) {
+ if (!BT.reached(&B))
+ return false;
bool Changed = false;
for (auto I = B.begin(), E = B.end(), NextI = I; I != E; ++I) {
@@ -1292,10 +1339,20 @@ bool RedundantInstrElimination::processBlock(MachineBasicBlock &B,
const DebugLoc &DL = MI->getDebugLoc();
const TargetRegisterClass *FRC = HBS::getFinalVRegClass(RD, MRI);
unsigned NewR = MRI.createVirtualRegister(FRC);
- BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
- .addReg(RS.Reg, 0, RS.Sub);
+ MachineInstr *CopyI =
+ BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
+ .addReg(RS.Reg, 0, RS.Sub);
HBS::replaceSubWithSub(RD.Reg, RD.Sub, NewR, 0, MRI);
- BT.put(BitTracker::RegisterRef(NewR), SC);
+ // This pass can create copies between registers that don't have the
+ // exact same values. Updating the tracker has to involve updating
+ // all dependent cells. Example:
+ // vreg1 = inst vreg2 ; vreg1 != vreg2, but used bits are equal
+ //
+ // vreg3 = copy vreg2 ; <- inserted
+ // ... = vreg3 ; <- replaced from vreg2
+ // Indirectly, we can create a "copy" between vreg1 and vreg2 even
+ // though their exact values do not match.
+ BT.visit(*CopyI);
Changed = true;
break;
}
@@ -1304,22 +1361,20 @@ bool RedundantInstrElimination::processBlock(MachineBasicBlock &B,
return Changed;
}
+namespace {
-//
-// Const generation
-//
// Recognize instructions that produce constant values known at compile-time.
// Replace them with register definitions that load these constants directly.
-namespace {
class ConstGeneration : public Transformation {
public:
ConstGeneration(BitTracker &bt, const HexagonInstrInfo &hii,
MachineRegisterInfo &mri)
: Transformation(true), HII(hii), MRI(mri), BT(bt) {}
+
bool processBlock(MachineBasicBlock &B, const RegisterSet &AVs) override;
+ static bool isTfrConst(const MachineInstr &MI);
+
private:
- bool isTfrConst(const MachineInstr &MI) const;
- bool isConst(unsigned R, int64_t &V) const;
unsigned genTfrConst(const TargetRegisterClass *RC, int64_t C,
MachineBasicBlock &B, MachineBasicBlock::iterator At, DebugLoc &DL);
@@ -1327,42 +1382,25 @@ namespace {
MachineRegisterInfo &MRI;
BitTracker &BT;
};
-}
-bool ConstGeneration::isConst(unsigned R, int64_t &C) const {
- if (!BT.has(R))
- return false;
- const BitTracker::RegisterCell &RC = BT.lookup(R);
- int64_t T = 0;
- for (unsigned i = RC.width(); i > 0; --i) {
- const BitTracker::BitValue &V = RC[i-1];
- T <<= 1;
- if (V.is(1))
- T |= 1;
- else if (!V.is(0))
- return false;
- }
- C = T;
- return true;
-}
+} // end anonymous namespace
-bool ConstGeneration::isTfrConst(const MachineInstr &MI) const {
+bool ConstGeneration::isTfrConst(const MachineInstr &MI) {
unsigned Opc = MI.getOpcode();
switch (Opc) {
case Hexagon::A2_combineii:
case Hexagon::A4_combineii:
case Hexagon::A2_tfrsi:
case Hexagon::A2_tfrpi:
- case Hexagon::TFR_PdTrue:
- case Hexagon::TFR_PdFalse:
- case Hexagon::CONST32_Int_Real:
- case Hexagon::CONST64_Int_Real:
+ case Hexagon::PS_true:
+ case Hexagon::PS_false:
+ case Hexagon::CONST32:
+ case Hexagon::CONST64:
return true;
}
return false;
}
-
// Generate a transfer-immediate instruction that is appropriate for the
// register class and the actual value being transferred.
unsigned ConstGeneration::genTfrConst(const TargetRegisterClass *RC, int64_t C,
@@ -1391,7 +1429,7 @@ unsigned ConstGeneration::genTfrConst(const TargetRegisterClass *RC, int64_t C,
return Reg;
}
- BuildMI(B, At, DL, HII.get(Hexagon::CONST64_Int_Real), Reg)
+ BuildMI(B, At, DL, HII.get(Hexagon::CONST64), Reg)
.addImm(C);
return Reg;
}
@@ -1399,9 +1437,9 @@ unsigned ConstGeneration::genTfrConst(const TargetRegisterClass *RC, int64_t C,
if (RC == &Hexagon::PredRegsRegClass) {
unsigned Opc;
if (C == 0)
- Opc = Hexagon::TFR_PdFalse;
+ Opc = Hexagon::PS_false;
else if ((C & 0xFF) == 0xFF)
- Opc = Hexagon::TFR_PdTrue;
+ Opc = Hexagon::PS_true;
else
return 0;
BuildMI(B, At, DL, HII.get(Opc), Reg);
@@ -1411,8 +1449,9 @@ unsigned ConstGeneration::genTfrConst(const TargetRegisterClass *RC, int64_t C,
return 0;
}
-
bool ConstGeneration::processBlock(MachineBasicBlock &B, const RegisterSet&) {
+ if (!BT.reached(&B))
+ return false;
bool Changed = false;
RegisterSet Defs;
@@ -1426,14 +1465,16 @@ bool ConstGeneration::processBlock(MachineBasicBlock &B, const RegisterSet&) {
unsigned DR = Defs.find_first();
if (!TargetRegisterInfo::isVirtualRegister(DR))
continue;
- int64_t C;
- if (isConst(DR, C)) {
+ uint64_t U;
+ const BitTracker::RegisterCell &DRC = BT.lookup(DR);
+ if (HBS::getConst(DRC, 0, DRC.width(), U)) {
+ int64_t C = U;
DebugLoc DL = I->getDebugLoc();
auto At = I->isPHI() ? B.getFirstNonPHI() : I;
unsigned ImmReg = genTfrConst(MRI.getRegClass(DR), C, B, At, DL);
if (ImmReg) {
HBS::replaceReg(DR, ImmReg, MRI);
- BT.put(ImmReg, BT.lookup(DR));
+ BT.put(ImmReg, DRC);
Changed = true;
}
}
@@ -1441,48 +1482,49 @@ bool ConstGeneration::processBlock(MachineBasicBlock &B, const RegisterSet&) {
return Changed;
}
+namespace {
-//
-// Copy generation
-//
// Identify pairs of available registers which hold identical values.
// In such cases, only one of them needs to be calculated, the other one
// will be defined as a copy of the first.
-//
-// Copy propagation
-//
-// Eliminate register copies RD = RS, by replacing the uses of RD with
-// with uses of RS.
-namespace {
class CopyGeneration : public Transformation {
public:
CopyGeneration(BitTracker &bt, const HexagonInstrInfo &hii,
- MachineRegisterInfo &mri)
- : Transformation(true), HII(hii), MRI(mri), BT(bt) {}
+ const HexagonRegisterInfo &hri, MachineRegisterInfo &mri)
+ : Transformation(true), HII(hii), HRI(hri), MRI(mri), BT(bt) {}
+
bool processBlock(MachineBasicBlock &B, const RegisterSet &AVs) override;
+
private:
bool findMatch(const BitTracker::RegisterRef &Inp,
BitTracker::RegisterRef &Out, const RegisterSet &AVs);
const HexagonInstrInfo &HII;
+ const HexagonRegisterInfo &HRI;
MachineRegisterInfo &MRI;
BitTracker &BT;
+ RegisterSet Forbidden;
};
+// Eliminate register copies RD = RS, by replacing the uses of RD with
+// with uses of RS.
class CopyPropagation : public Transformation {
public:
CopyPropagation(const HexagonRegisterInfo &hri, MachineRegisterInfo &mri)
- : Transformation(false), MRI(mri) {}
+ : Transformation(false), HRI(hri), MRI(mri) {}
+
bool processBlock(MachineBasicBlock &B, const RegisterSet &AVs) override;
- static bool isCopyReg(unsigned Opc);
+
+ static bool isCopyReg(unsigned Opc, bool NoConv);
+
private:
bool propagateRegCopy(MachineInstr &MI);
+ const HexagonRegisterInfo &HRI;
MachineRegisterInfo &MRI;
};
-}
-
+} // end anonymous namespace
/// Check if there is a register in AVs that is identical to Inp. If so,
/// set Out to the found register. The output may be a pair Reg:Sub.
@@ -1491,17 +1533,20 @@ bool CopyGeneration::findMatch(const BitTracker::RegisterRef &Inp,
if (!BT.has(Inp.Reg))
return false;
const BitTracker::RegisterCell &InpRC = BT.lookup(Inp.Reg);
+ auto *FRC = HBS::getFinalVRegClass(Inp, MRI);
unsigned B, W;
if (!HBS::getSubregMask(Inp, B, W, MRI))
return false;
for (unsigned R = AVs.find_first(); R; R = AVs.find_next(R)) {
- if (!BT.has(R) || !HBS::isTransparentCopy(R, Inp, MRI))
+ if (!BT.has(R) || Forbidden[R])
continue;
const BitTracker::RegisterCell &RC = BT.lookup(R);
unsigned RW = RC.width();
if (W == RW) {
- if (MRI.getRegClass(Inp.Reg) != MRI.getRegClass(R))
+ if (FRC != MRI.getRegClass(R))
+ continue;
+ if (!HBS::isTransparentCopy(R, Inp, MRI))
continue;
if (!HBS::isEqual(InpRC, B, RC, 0, W))
continue;
@@ -1518,20 +1563,22 @@ bool CopyGeneration::findMatch(const BitTracker::RegisterRef &Inp,
continue;
if (HBS::isEqual(InpRC, B, RC, 0, W))
- Out.Sub = Hexagon::subreg_loreg;
+ Out.Sub = Hexagon::isub_lo;
else if (HBS::isEqual(InpRC, B, RC, W, W))
- Out.Sub = Hexagon::subreg_hireg;
+ Out.Sub = Hexagon::isub_hi;
else
continue;
Out.Reg = R;
- return true;
+ if (HBS::isTransparentCopy(Out, Inp, MRI))
+ return true;
}
return false;
}
-
bool CopyGeneration::processBlock(MachineBasicBlock &B,
const RegisterSet &AVs) {
+ if (!BT.reached(&B))
+ return false;
RegisterSet AVB(AVs);
bool Changed = false;
RegisterSet Defs;
@@ -1543,44 +1590,74 @@ bool CopyGeneration::processBlock(MachineBasicBlock &B,
HBS::getInstrDefs(*I, Defs);
unsigned Opc = I->getOpcode();
- if (CopyPropagation::isCopyReg(Opc))
+ if (CopyPropagation::isCopyReg(Opc, false) ||
+ ConstGeneration::isTfrConst(*I))
continue;
+ DebugLoc DL = I->getDebugLoc();
+ auto At = I->isPHI() ? B.getFirstNonPHI() : I;
+
for (unsigned R = Defs.find_first(); R; R = Defs.find_next(R)) {
BitTracker::RegisterRef MR;
- if (!findMatch(R, MR, AVB))
+ auto *FRC = HBS::getFinalVRegClass(R, MRI);
+
+ if (findMatch(R, MR, AVB)) {
+ unsigned NewR = MRI.createVirtualRegister(FRC);
+ BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
+ .addReg(MR.Reg, 0, MR.Sub);
+ BT.put(BitTracker::RegisterRef(NewR), BT.get(MR));
+ HBS::replaceReg(R, NewR, MRI);
+ Forbidden.insert(R);
continue;
- DebugLoc DL = I->getDebugLoc();
- auto *FRC = HBS::getFinalVRegClass(MR, MRI);
- unsigned NewR = MRI.createVirtualRegister(FRC);
- auto At = I->isPHI() ? B.getFirstNonPHI() : I;
- BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
- .addReg(MR.Reg, 0, MR.Sub);
- BT.put(BitTracker::RegisterRef(NewR), BT.get(MR));
+ }
+
+ if (FRC == &Hexagon::DoubleRegsRegClass ||
+ FRC == &Hexagon::VecDblRegsRegClass ||
+ FRC == &Hexagon::VecDblRegs128BRegClass) {
+ // Try to generate REG_SEQUENCE.
+ unsigned SubLo = HRI.getHexagonSubRegIndex(FRC, Hexagon::ps_sub_lo);
+ unsigned SubHi = HRI.getHexagonSubRegIndex(FRC, Hexagon::ps_sub_hi);
+ BitTracker::RegisterRef TL = { R, SubLo };
+ BitTracker::RegisterRef TH = { R, SubHi };
+ BitTracker::RegisterRef ML, MH;
+ if (findMatch(TL, ML, AVB) && findMatch(TH, MH, AVB)) {
+ auto *FRC = HBS::getFinalVRegClass(R, MRI);
+ unsigned NewR = MRI.createVirtualRegister(FRC);
+ BuildMI(B, At, DL, HII.get(TargetOpcode::REG_SEQUENCE), NewR)
+ .addReg(ML.Reg, 0, ML.Sub)
+ .addImm(SubLo)
+ .addReg(MH.Reg, 0, MH.Sub)
+ .addImm(SubHi);
+ BT.put(BitTracker::RegisterRef(NewR), BT.get(R));
+ HBS::replaceReg(R, NewR, MRI);
+ Forbidden.insert(R);
+ }
+ }
}
}
return Changed;
}
-
-bool CopyPropagation::isCopyReg(unsigned Opc) {
+bool CopyPropagation::isCopyReg(unsigned Opc, bool NoConv) {
switch (Opc) {
case TargetOpcode::COPY:
case TargetOpcode::REG_SEQUENCE:
- case Hexagon::A2_tfr:
- case Hexagon::A2_tfrp:
- case Hexagon::A2_combinew:
case Hexagon::A4_combineir:
case Hexagon::A4_combineri:
return true;
+ case Hexagon::A2_tfr:
+ case Hexagon::A2_tfrp:
+ case Hexagon::A2_combinew:
+ case Hexagon::V6_vcombine:
+ case Hexagon::V6_vcombine_128B:
+ return NoConv;
default:
break;
}
return false;
}
-
bool CopyPropagation::propagateRegCopy(MachineInstr &MI) {
bool Changed = false;
unsigned Opc = MI.getOpcode();
@@ -1602,27 +1679,31 @@ bool CopyPropagation::propagateRegCopy(MachineInstr &MI) {
}
case TargetOpcode::REG_SEQUENCE: {
BitTracker::RegisterRef SL, SH;
- if (HBS::parseRegSequence(MI, SL, SH)) {
- Changed = HBS::replaceSubWithSub(RD.Reg, Hexagon::subreg_loreg,
- SL.Reg, SL.Sub, MRI);
- Changed |= HBS::replaceSubWithSub(RD.Reg, Hexagon::subreg_hireg,
- SH.Reg, SH.Sub, MRI);
+ if (HBS::parseRegSequence(MI, SL, SH, MRI)) {
+ const TargetRegisterClass *RC = MRI.getRegClass(RD.Reg);
+ unsigned SubLo = HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_lo);
+ unsigned SubHi = HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_hi);
+ Changed = HBS::replaceSubWithSub(RD.Reg, SubLo, SL.Reg, SL.Sub, MRI);
+ Changed |= HBS::replaceSubWithSub(RD.Reg, SubHi, SH.Reg, SH.Sub, MRI);
}
break;
}
- case Hexagon::A2_combinew: {
+ case Hexagon::A2_combinew:
+ case Hexagon::V6_vcombine:
+ case Hexagon::V6_vcombine_128B: {
+ const TargetRegisterClass *RC = MRI.getRegClass(RD.Reg);
+ unsigned SubLo = HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_lo);
+ unsigned SubHi = HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_hi);
BitTracker::RegisterRef RH = MI.getOperand(1), RL = MI.getOperand(2);
- Changed = HBS::replaceSubWithSub(RD.Reg, Hexagon::subreg_loreg,
- RL.Reg, RL.Sub, MRI);
- Changed |= HBS::replaceSubWithSub(RD.Reg, Hexagon::subreg_hireg,
- RH.Reg, RH.Sub, MRI);
+ Changed = HBS::replaceSubWithSub(RD.Reg, SubLo, RL.Reg, RL.Sub, MRI);
+ Changed |= HBS::replaceSubWithSub(RD.Reg, SubHi, RH.Reg, RH.Sub, MRI);
break;
}
case Hexagon::A4_combineir:
case Hexagon::A4_combineri: {
unsigned SrcX = (Opc == Hexagon::A4_combineir) ? 2 : 1;
- unsigned Sub = (Opc == Hexagon::A4_combineir) ? Hexagon::subreg_loreg
- : Hexagon::subreg_hireg;
+ unsigned Sub = (Opc == Hexagon::A4_combineir) ? Hexagon::isub_lo
+ : Hexagon::isub_hi;
BitTracker::RegisterRef RS = MI.getOperand(SrcX);
Changed = HBS::replaceSubWithSub(RD.Reg, Sub, RS.Reg, RS.Sub, MRI);
break;
@@ -1631,7 +1712,6 @@ bool CopyPropagation::propagateRegCopy(MachineInstr &MI) {
return Changed;
}
-
bool CopyPropagation::processBlock(MachineBasicBlock &B, const RegisterSet&) {
std::vector<MachineInstr*> Instrs;
for (auto I = B.rbegin(), E = B.rend(); I != E; ++I)
@@ -1640,7 +1720,7 @@ bool CopyPropagation::processBlock(MachineBasicBlock &B, const RegisterSet&) {
bool Changed = false;
for (auto I : Instrs) {
unsigned Opc = I->getOpcode();
- if (!CopyPropagation::isCopyReg(Opc))
+ if (!CopyPropagation::isCopyReg(Opc, true))
continue;
Changed |= propagateRegCopy(*I);
}
@@ -1648,20 +1728,20 @@ bool CopyPropagation::processBlock(MachineBasicBlock &B, const RegisterSet&) {
return Changed;
}
+namespace {
-//
-// Bit simplification
-//
// Recognize patterns that can be simplified and replace them with the
// simpler forms.
// This is by no means complete
-namespace {
class BitSimplification : public Transformation {
public:
BitSimplification(BitTracker &bt, const HexagonInstrInfo &hii,
- MachineRegisterInfo &mri)
- : Transformation(true), HII(hii), MRI(mri), BT(bt) {}
+ const HexagonRegisterInfo &hri, MachineRegisterInfo &mri,
+ MachineFunction &mf)
+ : Transformation(true), HII(hii), HRI(hri), MRI(mri), MF(mf), BT(bt) {}
+
bool processBlock(MachineBasicBlock &B, const RegisterSet &AVs) override;
+
private:
struct RegHalf : public BitTracker::RegisterRef {
bool Low; // Low/High halfword.
@@ -1669,6 +1749,7 @@ namespace {
bool matchHalf(unsigned SelfR, const BitTracker::RegisterCell &RC,
unsigned B, RegHalf &RH);
+ bool validateReg(BitTracker::RegisterRef R, unsigned Opc, unsigned OpNum);
bool matchPackhl(unsigned SelfR, const BitTracker::RegisterCell &RC,
BitTracker::RegisterRef &Rs, BitTracker::RegisterRef &Rt);
@@ -1688,11 +1769,13 @@ namespace {
const BitTracker::RegisterCell &RC);
const HexagonInstrInfo &HII;
+ const HexagonRegisterInfo &HRI;
MachineRegisterInfo &MRI;
+ MachineFunction &MF;
BitTracker &BT;
};
-}
+} // end anonymous namespace
// Check if the bits [B..B+16) in register cell RC form a valid halfword,
// i.e. [0..16), [16..32), etc. of some register. If so, return true and
@@ -1746,19 +1829,19 @@ bool BitSimplification::matchHalf(unsigned SelfR,
unsigned Sub = 0;
switch (Pos) {
case 0:
- Sub = Hexagon::subreg_loreg;
+ Sub = Hexagon::isub_lo;
Low = true;
break;
case 16:
- Sub = Hexagon::subreg_loreg;
+ Sub = Hexagon::isub_lo;
Low = false;
break;
case 32:
- Sub = Hexagon::subreg_hireg;
+ Sub = Hexagon::isub_hi;
Low = true;
break;
case 48:
- Sub = Hexagon::subreg_hireg;
+ Sub = Hexagon::isub_hi;
Low = false;
break;
default:
@@ -1775,6 +1858,12 @@ bool BitSimplification::matchHalf(unsigned SelfR,
return true;
}
+bool BitSimplification::validateReg(BitTracker::RegisterRef R, unsigned Opc,
+ unsigned OpNum) {
+ auto *OpRC = HII.getRegClass(HII.get(Opc), OpNum, &HRI, MF);
+ auto *RRC = HBS::getFinalVRegClass(R, MRI);
+ return OpRC->hasSubClassEq(RRC);
+}
// Check if RC matches the pattern of a S2_packhl. If so, return true and
// set the inputs Rs and Rt.
@@ -1799,7 +1888,6 @@ bool BitSimplification::matchPackhl(unsigned SelfR,
return true;
}
-
unsigned BitSimplification::getCombineOpcode(bool HLow, bool LLow) {
return HLow ? LLow ? Hexagon::A2_combine_ll
: Hexagon::A2_combine_lh
@@ -1807,7 +1895,6 @@ unsigned BitSimplification::getCombineOpcode(bool HLow, bool LLow) {
: Hexagon::A2_combine_hh;
}
-
// If MI stores the upper halfword of a register (potentially obtained via
// shifts or extracts), replace it with a storerf instruction. This could
// cause the "extraction" code to become dead.
@@ -1832,7 +1919,6 @@ bool BitSimplification::genStoreUpperHalf(MachineInstr *MI) {
return true;
}
-
// If MI stores a value known at compile-time, and the value is within a range
// that avoids using constant-extenders, replace it with a store-immediate.
bool BitSimplification::genStoreImmediate(MachineInstr *MI) {
@@ -1901,7 +1987,6 @@ bool BitSimplification::genStoreImmediate(MachineInstr *MI) {
return true;
}
-
// If MI is equivalent o S2_packhl, generate the S2_packhl. MI could be the
// last instruction in a sequence that results in something equivalent to
// the pack-halfwords. The intent is to cause the entire sequence to become
@@ -1914,6 +1999,9 @@ bool BitSimplification::genPackhl(MachineInstr *MI,
BitTracker::RegisterRef Rs, Rt;
if (!matchPackhl(RD.Reg, RC, Rs, Rt))
return false;
+ if (!validateReg(Rs, Hexagon::S2_packhl, 1) ||
+ !validateReg(Rt, Hexagon::S2_packhl, 2))
+ return false;
MachineBasicBlock &B = *MI->getParent();
unsigned NewR = MRI.createVirtualRegister(&Hexagon::DoubleRegsRegClass);
@@ -1928,7 +2016,6 @@ bool BitSimplification::genPackhl(MachineInstr *MI,
return true;
}
-
// If MI produces halfword of the input in the low half of the output,
// replace it with zero-extend or extractu.
bool BitSimplification::genExtractHalf(MachineInstr *MI,
@@ -1948,14 +2035,18 @@ bool BitSimplification::genExtractHalf(MachineInstr *MI,
auto At = MI->isPHI() ? B.getFirstNonPHI()
: MachineBasicBlock::iterator(MI);
if (L.Low && Opc != Hexagon::A2_zxth) {
- NewR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
- BuildMI(B, At, DL, HII.get(Hexagon::A2_zxth), NewR)
- .addReg(L.Reg, 0, L.Sub);
+ if (validateReg(L, Hexagon::A2_zxth, 1)) {
+ NewR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
+ BuildMI(B, At, DL, HII.get(Hexagon::A2_zxth), NewR)
+ .addReg(L.Reg, 0, L.Sub);
+ }
} else if (!L.Low && Opc != Hexagon::S2_lsr_i_r) {
- NewR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
- BuildMI(B, MI, DL, HII.get(Hexagon::S2_lsr_i_r), NewR)
- .addReg(L.Reg, 0, L.Sub)
- .addImm(16);
+ if (validateReg(L, Hexagon::S2_lsr_i_r, 1)) {
+ NewR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
+ BuildMI(B, MI, DL, HII.get(Hexagon::S2_lsr_i_r), NewR)
+ .addReg(L.Reg, 0, L.Sub)
+ .addImm(16);
+ }
}
if (NewR == 0)
return false;
@@ -1964,7 +2055,6 @@ bool BitSimplification::genExtractHalf(MachineInstr *MI,
return true;
}
-
// If MI is equivalent to a combine(.L/.H, .L/.H) replace with with the
// combine.
bool BitSimplification::genCombineHalf(MachineInstr *MI,
@@ -1981,6 +2071,8 @@ bool BitSimplification::genCombineHalf(MachineInstr *MI,
unsigned COpc = getCombineOpcode(H.Low, L.Low);
if (COpc == Opc)
return false;
+ if (!validateReg(H, COpc, 1) || !validateReg(L, COpc, 2))
+ return false;
MachineBasicBlock &B = *MI->getParent();
DebugLoc DL = MI->getDebugLoc();
@@ -1995,7 +2087,6 @@ bool BitSimplification::genCombineHalf(MachineInstr *MI,
return true;
}
-
// If MI resets high bits of a register and keeps the lower ones, replace it
// with zero-extend byte/half, and-immediate, or extractu, as appropriate.
bool BitSimplification::genExtractLow(MachineInstr *MI,
@@ -2039,6 +2130,8 @@ bool BitSimplification::genExtractLow(MachineInstr *MI,
continue;
if (BW < W || !HBS::isEqual(RC, 0, SC, BN, W))
continue;
+ if (!validateReg(RS, NewOpc, 1))
+ continue;
unsigned NewR = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
auto At = MI->isPHI() ? B.getFirstNonPHI()
@@ -2056,7 +2149,6 @@ bool BitSimplification::genExtractLow(MachineInstr *MI,
return false;
}
-
// Check for tstbit simplification opportunity, where the bit being checked
// can be tracked back to another register. For example:
// vreg2 = S2_lsr_i_r vreg1, 5
@@ -2086,19 +2178,19 @@ bool BitSimplification::simplifyTstbit(MachineInstr *MI,
// Need to map V.RefI.Reg to a 32-bit register, i.e. if it is
// a double register, need to use a subregister and adjust bit
// number.
- unsigned P = UINT_MAX;
+ unsigned P = std::numeric_limits<unsigned>::max();
BitTracker::RegisterRef RR(V.RefI.Reg, 0);
if (TC == &Hexagon::DoubleRegsRegClass) {
P = V.RefI.Pos;
- RR.Sub = Hexagon::subreg_loreg;
+ RR.Sub = Hexagon::isub_lo;
if (P >= 32) {
P -= 32;
- RR.Sub = Hexagon::subreg_hireg;
+ RR.Sub = Hexagon::isub_hi;
}
} else if (TC == &Hexagon::IntRegsRegClass) {
P = V.RefI.Pos;
}
- if (P != UINT_MAX) {
+ if (P != std::numeric_limits<unsigned>::max()) {
unsigned NewR = MRI.createVirtualRegister(&Hexagon::PredRegsRegClass);
BuildMI(B, At, DL, HII.get(Hexagon::S2_tstbit_i), NewR)
.addReg(RR.Reg, 0, RR.Sub)
@@ -2109,7 +2201,7 @@ bool BitSimplification::simplifyTstbit(MachineInstr *MI,
}
} else if (V.is(0) || V.is(1)) {
unsigned NewR = MRI.createVirtualRegister(&Hexagon::PredRegsRegClass);
- unsigned NewOpc = V.is(0) ? Hexagon::TFR_PdFalse : Hexagon::TFR_PdTrue;
+ unsigned NewOpc = V.is(0) ? Hexagon::PS_false : Hexagon::PS_true;
BuildMI(B, At, DL, HII.get(NewOpc), NewR);
HBS::replaceReg(RD.Reg, NewR, MRI);
return true;
@@ -2118,9 +2210,10 @@ bool BitSimplification::simplifyTstbit(MachineInstr *MI,
return false;
}
-
bool BitSimplification::processBlock(MachineBasicBlock &B,
const RegisterSet &AVs) {
+ if (!BT.reached(&B))
+ return false;
bool Changed = false;
RegisterSet AVB = AVs;
RegisterSet Defs;
@@ -2175,7 +2268,6 @@ bool BitSimplification::processBlock(MachineBasicBlock &B,
return Changed;
}
-
bool HexagonBitSimplify::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
@@ -2203,10 +2295,14 @@ bool HexagonBitSimplify::runOnMachineFunction(MachineFunction &MF) {
RegisterSet ARE; // Available registers for RIE.
RedundantInstrElimination RIE(BT, HII, MRI);
- Changed |= visitBlock(Entry, RIE, ARE);
+ bool Ried = visitBlock(Entry, RIE, ARE);
+ if (Ried) {
+ Changed = true;
+ BT.run();
+ }
RegisterSet ACG; // Available registers for CG.
- CopyGeneration CopyG(BT, HII, MRI);
+ CopyGeneration CopyG(BT, HII, HRI, MRI);
Changed |= visitBlock(Entry, CopyG, ACG);
RegisterSet ACP; // Available registers for CP.
@@ -2217,7 +2313,7 @@ bool HexagonBitSimplify::runOnMachineFunction(MachineFunction &MF) {
BT.run();
RegisterSet ABS; // Available registers for BS.
- BitSimplification BitS(BT, HII, MRI);
+ BitSimplification BitS(BT, HII, HRI, MRI, MF);
Changed |= visitBlock(Entry, BitS, ABS);
Changed = DeadCodeElimination(MF, *MDT).run() || Changed;
@@ -2231,7 +2327,6 @@ bool HexagonBitSimplify::runOnMachineFunction(MachineFunction &MF) {
return Changed;
}
-
// Recognize loops where the code at the end of the loop matches the code
// before the entry of the loop, and the matching code is such that is can
// be simplified. This pass relies on the bit simplification above and only
@@ -2295,16 +2390,20 @@ bool HexagonBitSimplify::runOnMachineFunction(MachineFunction &MF) {
// }:endloop0
namespace llvm {
+
FunctionPass *createHexagonLoopRescheduling();
void initializeHexagonLoopReschedulingPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
+
class HexagonLoopRescheduling : public MachineFunctionPass {
public:
static char ID;
+
HexagonLoopRescheduling() : MachineFunctionPass(ID),
- HII(0), HRI(0), MRI(0), BTP(0) {
+ HII(nullptr), HRI(nullptr), MRI(nullptr), BTP(nullptr) {
initializeHexagonLoopReschedulingPass(*PassRegistry::getPassRegistry());
}
@@ -2329,8 +2428,8 @@ namespace {
struct PhiInfo {
PhiInfo(MachineInstr &P, MachineBasicBlock &B);
unsigned DefR;
- BitTracker::RegisterRef LR, PR;
- MachineBasicBlock *LB, *PB;
+ BitTracker::RegisterRef LR, PR; // Loop Register, Preheader Register
+ MachineBasicBlock *LB, *PB; // Loop Block, Preheader Block
};
static unsigned getDefReg(const MachineInstr *MI);
@@ -2344,14 +2443,14 @@ namespace {
MachineBasicBlock::iterator At, unsigned OldPhiR, unsigned NewPredR);
bool processLoop(LoopCand &C);
};
-}
+
+} // end anonymous namespace
char HexagonLoopRescheduling::ID = 0;
INITIALIZE_PASS(HexagonLoopRescheduling, "hexagon-loop-resched",
"Hexagon Loop Rescheduling", false, false)
-
HexagonLoopRescheduling::PhiInfo::PhiInfo(MachineInstr &P,
MachineBasicBlock &B) {
DefR = HexagonLoopRescheduling::getDefReg(&P);
@@ -2368,7 +2467,6 @@ HexagonLoopRescheduling::PhiInfo::PhiInfo(MachineInstr &P,
}
}
-
unsigned HexagonLoopRescheduling::getDefReg(const MachineInstr *MI) {
RegisterSet Defs;
HBS::getInstrDefs(*MI, Defs);
@@ -2377,7 +2475,6 @@ unsigned HexagonLoopRescheduling::getDefReg(const MachineInstr *MI) {
return Defs.find_first();
}
-
bool HexagonLoopRescheduling::isConst(unsigned Reg) const {
if (!BTP->has(Reg))
return false;
@@ -2390,7 +2487,6 @@ bool HexagonLoopRescheduling::isConst(unsigned Reg) const {
return true;
}
-
bool HexagonLoopRescheduling::isBitShuffle(const MachineInstr *MI,
unsigned DefR) const {
unsigned Opc = MI->getOpcode();
@@ -2421,7 +2517,6 @@ bool HexagonLoopRescheduling::isBitShuffle(const MachineInstr *MI,
return false;
}
-
bool HexagonLoopRescheduling::isStoreInput(const MachineInstr *MI,
unsigned InpR) const {
for (unsigned i = 0, n = MI->getNumOperands(); i < n; ++i) {
@@ -2434,7 +2529,6 @@ bool HexagonLoopRescheduling::isStoreInput(const MachineInstr *MI,
return false;
}
-
bool HexagonLoopRescheduling::isShuffleOf(unsigned OutR, unsigned InpR) const {
if (!BTP->has(OutR) || !BTP->has(InpR))
return false;
@@ -2449,7 +2543,6 @@ bool HexagonLoopRescheduling::isShuffleOf(unsigned OutR, unsigned InpR) const {
return true;
}
-
bool HexagonLoopRescheduling::isSameShuffle(unsigned OutR1, unsigned InpR1,
unsigned OutR2, unsigned &InpR2) const {
if (!BTP->has(OutR1) || !BTP->has(InpR1) || !BTP->has(OutR2))
@@ -2481,7 +2574,6 @@ bool HexagonLoopRescheduling::isSameShuffle(unsigned OutR1, unsigned InpR1,
return true;
}
-
void HexagonLoopRescheduling::moveGroup(InstrGroup &G, MachineBasicBlock &LB,
MachineBasicBlock &PB, MachineBasicBlock::iterator At, unsigned OldPhiR,
unsigned NewPredR) {
@@ -2521,7 +2613,6 @@ void HexagonLoopRescheduling::moveGroup(InstrGroup &G, MachineBasicBlock &LB,
HBS::replaceReg(OldPhiR, RegMap[G.Out.Reg], *MRI);
}
-
bool HexagonLoopRescheduling::processLoop(LoopCand &C) {
DEBUG(dbgs() << "Processing loop in BB#" << C.LB->getNumber() << "\n");
std::vector<PhiInfo> Phis;
@@ -2595,7 +2686,7 @@ bool HexagonLoopRescheduling::processLoop(LoopCand &C) {
if (UseI->getOperand(Idx+1).getMBB() != C.LB)
BadUse = true;
} else {
- auto F = std::find(ShufIns.begin(), ShufIns.end(), UseI);
+ auto F = find(ShufIns, UseI);
if (F == ShufIns.end())
BadUse = true;
}
@@ -2661,7 +2752,7 @@ bool HexagonLoopRescheduling::processLoop(LoopCand &C) {
auto LoopInpEq = [G] (const PhiInfo &P) -> bool {
return G.Out.Reg == P.LR.Reg;
};
- if (std::find_if(Phis.begin(), Phis.end(), LoopInpEq) == Phis.end())
+ if (llvm::find_if(Phis, LoopInpEq) == Phis.end())
continue;
G.Inp.Reg = Inputs.find_first();
@@ -2686,41 +2777,46 @@ bool HexagonLoopRescheduling::processLoop(LoopCand &C) {
auto LoopInpEq = [G] (const PhiInfo &P) -> bool {
return G.Out.Reg == P.LR.Reg;
};
- auto F = std::find_if(Phis.begin(), Phis.end(), LoopInpEq);
+ auto F = llvm::find_if(Phis, LoopInpEq);
if (F == Phis.end())
continue;
- unsigned PredR = 0;
- if (!isSameShuffle(G.Out.Reg, G.Inp.Reg, F->PR.Reg, PredR)) {
- const MachineInstr *DefPredR = MRI->getVRegDef(F->PR.Reg);
- unsigned Opc = DefPredR->getOpcode();
+ unsigned PrehR = 0;
+ if (!isSameShuffle(G.Out.Reg, G.Inp.Reg, F->PR.Reg, PrehR)) {
+ const MachineInstr *DefPrehR = MRI->getVRegDef(F->PR.Reg);
+ unsigned Opc = DefPrehR->getOpcode();
if (Opc != Hexagon::A2_tfrsi && Opc != Hexagon::A2_tfrpi)
continue;
- if (!DefPredR->getOperand(1).isImm())
+ if (!DefPrehR->getOperand(1).isImm())
continue;
- if (DefPredR->getOperand(1).getImm() != 0)
+ if (DefPrehR->getOperand(1).getImm() != 0)
continue;
const TargetRegisterClass *RC = MRI->getRegClass(G.Inp.Reg);
if (RC != MRI->getRegClass(F->PR.Reg)) {
- PredR = MRI->createVirtualRegister(RC);
+ PrehR = MRI->createVirtualRegister(RC);
unsigned TfrI = (RC == &Hexagon::IntRegsRegClass) ? Hexagon::A2_tfrsi
: Hexagon::A2_tfrpi;
auto T = C.PB->getFirstTerminator();
DebugLoc DL = (T != C.PB->end()) ? T->getDebugLoc() : DebugLoc();
- BuildMI(*C.PB, T, DL, HII->get(TfrI), PredR)
+ BuildMI(*C.PB, T, DL, HII->get(TfrI), PrehR)
.addImm(0);
} else {
- PredR = F->PR.Reg;
+ PrehR = F->PR.Reg;
}
}
- assert(MRI->getRegClass(PredR) == MRI->getRegClass(G.Inp.Reg));
- moveGroup(G, *F->LB, *F->PB, F->LB->getFirstNonPHI(), F->DefR, PredR);
+ // isSameShuffle could match with PrehR being of a wider class than
+ // G.Inp.Reg, for example if G shuffles the low 32 bits of its input,
+ // it would match for the input being a 32-bit register, and PrehR
+ // being a 64-bit register (where the low 32 bits match). This could
+ // be handled, but for now skip these cases.
+ if (MRI->getRegClass(PrehR) != MRI->getRegClass(G.Inp.Reg))
+ continue;
+ moveGroup(G, *F->LB, *F->PB, F->LB->getFirstNonPHI(), F->DefR, PrehR);
Changed = true;
}
return Changed;
}
-
bool HexagonLoopRescheduling::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
@@ -2783,4 +2879,3 @@ FunctionPass *llvm::createHexagonLoopRescheduling() {
FunctionPass *llvm::createHexagonBitSimplify() {
return new HexagonBitSimplify();
}
-
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.cpp
index 78b57d2..436f88d 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.cpp
@@ -7,16 +7,30 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
#include "Hexagon.h"
+#include "HexagonBitTracker.h"
#include "HexagonInstrInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonTargetMachine.h"
-#include "HexagonBitTracker.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Argument.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <utility>
+#include <vector>
using namespace llvm;
@@ -26,7 +40,7 @@ HexagonEvaluator::HexagonEvaluator(const HexagonRegisterInfo &tri,
MachineRegisterInfo &mri,
const HexagonInstrInfo &tii,
MachineFunction &mf)
- : MachineEvaluator(tri, mri), MF(mf), MFI(*mf.getFrameInfo()), TII(tii) {
+ : MachineEvaluator(tri, mri), MF(mf), MFI(mf.getFrameInfo()), TII(tii) {
// Populate the VRX map (VR to extension-type).
// Go over all the formal parameters of the function. If a given parameter
// P is sign- or zero-extended, locate the virtual register holding that
@@ -60,13 +74,15 @@ HexagonEvaluator::HexagonEvaluator(const HexagonRegisterInfo &tri,
// Module::AnyPointerSize.
if (Width == 0 || Width > 64)
break;
+ AttributeSet Attrs = F.getAttributes();
+ if (Attrs.hasAttribute(AttrIdx, Attribute::ByVal))
+ continue;
InPhysReg = getNextPhysReg(InPhysReg, Width);
if (!InPhysReg)
break;
InVirtReg = getVirtRegFor(InPhysReg);
if (!InVirtReg)
continue;
- AttributeSet Attrs = F.getAttributes();
if (Attrs.hasAttribute(AttrIdx, Attribute::SExt))
VRX.insert(std::make_pair(InVirtReg, ExtType(ExtType::SExt, Width)));
else if (Attrs.hasAttribute(AttrIdx, Attribute::ZExt))
@@ -74,20 +90,22 @@ HexagonEvaluator::HexagonEvaluator(const HexagonRegisterInfo &tri,
}
}
-
BT::BitMask HexagonEvaluator::mask(unsigned Reg, unsigned Sub) const {
+ using namespace Hexagon;
+
if (Sub == 0)
return MachineEvaluator::mask(Reg, 0);
- using namespace Hexagon;
const TargetRegisterClass *RC = MRI.getRegClass(Reg);
unsigned ID = RC->getID();
uint16_t RW = getRegBitWidth(RegisterRef(Reg, Sub));
+ auto &HRI = static_cast<const HexagonRegisterInfo&>(TRI);
+ bool IsSubLo = (Sub == HRI.getHexagonSubRegIndex(RC, Hexagon::ps_sub_lo));
switch (ID) {
case DoubleRegsRegClassID:
case VecDblRegsRegClassID:
case VecDblRegs128BRegClassID:
- return (Sub == subreg_loreg) ? BT::BitMask(0, RW-1)
- : BT::BitMask(RW, 2*RW-1);
+ return IsSubLo ? BT::BitMask(0, RW-1)
+ : BT::BitMask(RW, 2*RW-1);
default:
break;
}
@@ -98,6 +116,7 @@ BT::BitMask HexagonEvaluator::mask(unsigned Reg, unsigned Sub) const {
}
namespace {
+
class RegisterRefs {
std::vector<BT::RegisterRef> Vector;
@@ -113,17 +132,21 @@ public:
}
size_t size() const { return Vector.size(); }
+
const BT::RegisterRef &operator[](unsigned n) const {
// The main purpose of this operator is to assert with bad argument.
assert(n < Vector.size());
return Vector[n];
}
};
-}
+
+} // end anonymous namespace
bool HexagonEvaluator::evaluate(const MachineInstr &MI,
const CellMapType &Inputs,
CellMapType &Outputs) const {
+ using namespace Hexagon;
+
unsigned NumDefs = 0;
// Sanity verification: there should not be any defs with subregisters.
@@ -138,8 +161,19 @@ bool HexagonEvaluator::evaluate(const MachineInstr &MI,
if (NumDefs == 0)
return false;
- if (MI.mayLoad())
- return evaluateLoad(MI, Inputs, Outputs);
+ unsigned Opc = MI.getOpcode();
+
+ if (MI.mayLoad()) {
+ switch (Opc) {
+ // These instructions may be marked as mayLoad, but they are generating
+ // immediate values, so skip them.
+ case CONST32:
+ case CONST64:
+ break;
+ default:
+ return evaluateLoad(MI, Inputs, Outputs);
+ }
+ }
// Check COPY instructions that copy formal parameters into virtual
// registers. Such parameters can be sign- or zero-extended at the
@@ -174,8 +208,6 @@ bool HexagonEvaluator::evaluate(const MachineInstr &MI,
}
RegisterRefs Reg(MI);
- unsigned Opc = MI.getOpcode();
- using namespace Hexagon;
#define op(i) MI.getOperand(i)
#define rc(i) RegisterCell::ref(getCell(Reg[i], Inputs))
#define im(i) MI.getOperand(i).getImm()
@@ -246,16 +278,13 @@ bool HexagonEvaluator::evaluate(const MachineInstr &MI,
case A2_tfrsi:
case A2_tfrpi:
case CONST32:
- case CONST32_Float_Real:
- case CONST32_Int_Real:
- case CONST64_Float_Real:
- case CONST64_Int_Real:
+ case CONST64:
return rr0(eIMM(im(1), W0), Outputs);
- case TFR_PdFalse:
+ case PS_false:
return rr0(RegisterCell(W0).fill(0, W0, BT::BitValue::Zero), Outputs);
- case TFR_PdTrue:
+ case PS_true:
return rr0(RegisterCell(W0).fill(0, W0, BT::BitValue::One), Outputs);
- case TFR_FI: {
+ case PS_fi: {
int FI = op(1).getIndex();
int Off = op(2).getImm();
unsigned A = MFI.getObjectAlignment(FI) + std::abs(Off);
@@ -670,6 +699,8 @@ bool HexagonEvaluator::evaluate(const MachineInstr &MI,
case A4_combineir:
case A4_combineri:
case A2_combinew:
+ case V6_vcombine:
+ case V6_vcombine_128B:
assert(W0 % 2 == 0);
return rr0(cop(2, W0/2).cat(cop(1, W0/2)), Outputs);
case A2_combine_ll:
@@ -766,10 +797,10 @@ bool HexagonEvaluator::evaluate(const MachineInstr &MI,
case S2_cl0:
case S2_cl0p:
// Always produce a 32-bit result.
- return rr0(eCLB(rc(1), 0/*bit*/, 32), Outputs);
+ return rr0(eCLB(rc(1), false/*bit*/, 32), Outputs);
case S2_cl1:
case S2_cl1p:
- return rr0(eCLB(rc(1), 1/*bit*/, 32), Outputs);
+ return rr0(eCLB(rc(1), true/*bit*/, 32), Outputs);
case S2_clb:
case S2_clbp: {
uint16_t W1 = getRegBitWidth(Reg[1]);
@@ -781,10 +812,10 @@ bool HexagonEvaluator::evaluate(const MachineInstr &MI,
}
case S2_ct0:
case S2_ct0p:
- return rr0(eCTB(rc(1), 0/*bit*/, 32), Outputs);
+ return rr0(eCTB(rc(1), false/*bit*/, 32), Outputs);
case S2_ct1:
case S2_ct1p:
- return rr0(eCTB(rc(1), 1/*bit*/, 32), Outputs);
+ return rr0(eCTB(rc(1), true/*bit*/, 32), Outputs);
case S5_popcountp:
// TODO
break;
@@ -884,17 +915,19 @@ bool HexagonEvaluator::evaluate(const MachineInstr &BI,
const CellMapType &Inputs,
BranchTargetList &Targets,
bool &FallsThru) const {
- // We need to evaluate one branch at a time. TII::AnalyzeBranch checks
+ // We need to evaluate one branch at a time. TII::analyzeBranch checks
// all the branches in a basic block at once, so we cannot use it.
unsigned Opc = BI.getOpcode();
bool SimpleBranch = false;
bool Negated = false;
switch (Opc) {
case Hexagon::J2_jumpf:
+ case Hexagon::J2_jumpfpt:
case Hexagon::J2_jumpfnew:
case Hexagon::J2_jumpfnewpt:
Negated = true;
case Hexagon::J2_jumpt:
+ case Hexagon::J2_jumptpt:
case Hexagon::J2_jumptnew:
case Hexagon::J2_jumptnewpt:
// Simple branch: if([!]Pn) jump ...
@@ -938,6 +971,8 @@ bool HexagonEvaluator::evaluate(const MachineInstr &BI,
bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
const CellMapType &Inputs,
CellMapType &Outputs) const {
+ using namespace Hexagon;
+
if (TII.isPredicated(MI))
return false;
assert(MI.mayLoad() && "A load that mayn't?");
@@ -945,7 +980,6 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
uint16_t BitNum;
bool SignEx;
- using namespace Hexagon;
switch (Opc) {
default:
@@ -986,7 +1020,7 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
case L2_loadrb_pci:
case L2_loadrb_pcr:
case L2_loadrb_pi:
- case L4_loadrb_abs:
+ case PS_loadrbabs:
case L4_loadrb_ap:
case L4_loadrb_rr:
case L4_loadrb_ur:
@@ -1000,7 +1034,7 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
case L2_loadrub_pci:
case L2_loadrub_pcr:
case L2_loadrub_pi:
- case L4_loadrub_abs:
+ case PS_loadrubabs:
case L4_loadrub_ap:
case L4_loadrub_rr:
case L4_loadrub_ur:
@@ -1014,7 +1048,7 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
case L2_loadrh_pci:
case L2_loadrh_pcr:
case L2_loadrh_pi:
- case L4_loadrh_abs:
+ case PS_loadrhabs:
case L4_loadrh_ap:
case L4_loadrh_rr:
case L4_loadrh_ur:
@@ -1029,7 +1063,7 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
case L2_loadruh_pcr:
case L2_loadruh_pi:
case L4_loadruh_rr:
- case L4_loadruh_abs:
+ case PS_loadruhabs:
case L4_loadruh_ap:
case L4_loadruh_ur:
BitNum = 16;
@@ -1043,7 +1077,7 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
case L2_loadri_pcr:
case L2_loadri_pi:
case L2_loadw_locked:
- case L4_loadri_abs:
+ case PS_loadriabs:
case L4_loadri_ap:
case L4_loadri_rr:
case L4_loadri_ur:
@@ -1059,7 +1093,7 @@ bool HexagonEvaluator::evaluateLoad(const MachineInstr &MI,
case L2_loadrd_pcr:
case L2_loadrd_pi:
case L4_loadd_locked:
- case L4_loadrd_abs:
+ case PS_loadrdabs:
case L4_loadrd_ap:
case L4_loadrd_rr:
case L4_loadrd_ur:
@@ -1126,9 +1160,9 @@ bool HexagonEvaluator::evaluateFormalCopy(const MachineInstr &MI,
return true;
}
-
unsigned HexagonEvaluator::getNextPhysReg(unsigned PReg, unsigned Width) const {
using namespace Hexagon;
+
bool Is64 = DoubleRegsRegClass.contains(PReg);
assert(PReg == 0 || Is64 || IntRegsRegClass.contains(PReg));
@@ -1165,7 +1199,6 @@ unsigned HexagonEvaluator::getNextPhysReg(unsigned PReg, unsigned Width) const {
return (Idx64+1 < Num64) ? Phys64[Idx64+1] : 0;
}
-
unsigned HexagonEvaluator::getVirtRegFor(unsigned PReg) const {
typedef MachineRegisterInfo::livein_iterator iterator;
for (iterator I = MRI.livein_begin(), E = MRI.livein_end(); I != E; ++I) {
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.h b/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.h
index 9e7b1db..2cbf65e 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonBitTracker.h
@@ -1,4 +1,4 @@
-//===--- HexagonBitTracker.h ----------------------------------------------===//
+//===--- HexagonBitTracker.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,15 +7,17 @@
//
//===----------------------------------------------------------------------===//
-#ifndef HEXAGONBITTRACKER_H
-#define HEXAGONBITTRACKER_H
+#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONBITTRACKER_H
+#define LLVM_LIB_TARGET_HEXAGON_HEXAGONBITTRACKER_H
#include "BitTracker.h"
#include "llvm/ADT/DenseMap.h"
+#include <cstdint>
namespace llvm {
- class HexagonInstrInfo;
- class HexagonRegisterInfo;
+
+class HexagonInstrInfo;
+class HexagonRegisterInfo;
struct HexagonEvaluator : public BitTracker::MachineEvaluator {
typedef BitTracker::CellMapType CellMapType;
@@ -49,10 +51,12 @@ private:
// Type of formal parameter extension.
struct ExtType {
enum { SExt, ZExt };
- char Type;
- uint16_t Width;
- ExtType() : Type(0), Width(0) {}
+
+ ExtType() = default;
ExtType(char t, uint16_t w) : Type(t), Width(w) {}
+
+ char Type = 0;
+ uint16_t Width = 0;
};
// Map VR -> extension type.
typedef DenseMap<unsigned, ExtType> RegExtMap;
@@ -61,4 +65,4 @@ private:
} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONBITTRACKER_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.cpp
index 5c44029..adc213c 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.cpp
@@ -12,17 +12,19 @@
#include "HexagonBlockRanges.h"
#include "HexagonInstrInfo.h"
#include "HexagonSubtarget.h"
-
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
-
+#include <algorithm>
+#include <cassert>
+#include <iterator>
#include <map>
using namespace llvm;
@@ -40,7 +42,6 @@ bool HexagonBlockRanges::IndexRange::overlaps(const IndexRange &A) const {
return false;
}
-
bool HexagonBlockRanges::IndexRange::contains(const IndexRange &A) const {
if (start() <= A.start()) {
// Treat "None" in the range end as equal to the range start.
@@ -52,7 +53,6 @@ bool HexagonBlockRanges::IndexRange::contains(const IndexRange &A) const {
return false;
}
-
void HexagonBlockRanges::IndexRange::merge(const IndexRange &A) {
// Allow merging adjacent ranges.
assert(end() == A.start() || overlaps(A));
@@ -70,14 +70,12 @@ void HexagonBlockRanges::IndexRange::merge(const IndexRange &A) {
Fixed = true;
}
-
void HexagonBlockRanges::RangeList::include(const RangeList &RL) {
for (auto &R : RL)
- if (std::find(begin(), end(), R) == end())
+ if (!is_contained(*this, R))
push_back(R);
}
-
// Merge all overlapping ranges in the list, so that all that remains
// is a list of disjoint ranges.
void HexagonBlockRanges::RangeList::unionize(bool MergeAdjacent) {
@@ -101,7 +99,6 @@ void HexagonBlockRanges::RangeList::unionize(bool MergeAdjacent) {
}
}
-
// Compute a range A-B and add it to the list.
void HexagonBlockRanges::RangeList::addsub(const IndexRange &A,
const IndexRange &B) {
@@ -138,7 +135,6 @@ void HexagonBlockRanges::RangeList::addsub(const IndexRange &A,
}
}
-
// Subtract a given range from each element in the list.
void HexagonBlockRanges::RangeList::subtract(const IndexRange &Range) {
// Cannot assume that the list is unionized (i.e. contains only non-
@@ -156,7 +152,6 @@ void HexagonBlockRanges::RangeList::subtract(const IndexRange &Range) {
include(T);
}
-
HexagonBlockRanges::InstrIndexMap::InstrIndexMap(MachineBasicBlock &B)
: Block(B) {
IndexType Idx = IndexType::First;
@@ -171,13 +166,11 @@ HexagonBlockRanges::InstrIndexMap::InstrIndexMap(MachineBasicBlock &B)
Last = B.empty() ? IndexType::None : unsigned(Idx)-1;
}
-
MachineInstr *HexagonBlockRanges::InstrIndexMap::getInstr(IndexType Idx) const {
auto F = Map.find(Idx);
- return (F != Map.end()) ? F->second : 0;
+ return (F != Map.end()) ? F->second : nullptr;
}
-
HexagonBlockRanges::IndexType HexagonBlockRanges::InstrIndexMap::getIndex(
MachineInstr *MI) const {
for (auto &I : Map)
@@ -186,7 +179,6 @@ HexagonBlockRanges::IndexType HexagonBlockRanges::InstrIndexMap::getIndex(
return IndexType::None;
}
-
HexagonBlockRanges::IndexType HexagonBlockRanges::InstrIndexMap::getPrevIndex(
IndexType Idx) const {
assert (Idx != IndexType::None);
@@ -199,7 +191,6 @@ HexagonBlockRanges::IndexType HexagonBlockRanges::InstrIndexMap::getPrevIndex(
return unsigned(Idx)-1;
}
-
HexagonBlockRanges::IndexType HexagonBlockRanges::InstrIndexMap::getNextIndex(
IndexType Idx) const {
assert (Idx != IndexType::None);
@@ -210,7 +201,6 @@ HexagonBlockRanges::IndexType HexagonBlockRanges::InstrIndexMap::getNextIndex(
return unsigned(Idx)+1;
}
-
void HexagonBlockRanges::InstrIndexMap::replaceInstr(MachineInstr *OldMI,
MachineInstr *NewMI) {
for (auto &I : Map) {
@@ -224,7 +214,6 @@ void HexagonBlockRanges::InstrIndexMap::replaceInstr(MachineInstr *OldMI,
}
}
-
HexagonBlockRanges::HexagonBlockRanges(MachineFunction &mf)
: MF(mf), HST(mf.getSubtarget<HexagonSubtarget>()),
TII(*HST.getInstrInfo()), TRI(*HST.getRegisterInfo()),
@@ -239,17 +228,33 @@ HexagonBlockRanges::HexagonBlockRanges(MachineFunction &mf)
}
}
-
HexagonBlockRanges::RegisterSet HexagonBlockRanges::getLiveIns(
- const MachineBasicBlock &B) {
+ const MachineBasicBlock &B, const MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI) {
RegisterSet LiveIns;
- for (auto I : B.liveins())
- if (!Reserved[I.PhysReg])
- LiveIns.insert({I.PhysReg, 0});
+ RegisterSet Tmp;
+ for (auto I : B.liveins()) {
+ if (I.LaneMask.all()) {
+ Tmp.insert({I.PhysReg,0});
+ continue;
+ }
+ for (MCSubRegIndexIterator S(I.PhysReg, &TRI); S.isValid(); ++S) {
+ LaneBitmask M = TRI.getSubRegIndexLaneMask(S.getSubRegIndex());
+ if ((M & I.LaneMask).any())
+ Tmp.insert({S.getSubReg(), 0});
+ }
+ }
+
+ for (auto R : Tmp) {
+ if (!Reserved[R.Reg])
+ LiveIns.insert(R);
+ for (auto S : expandToSubRegs(R, MRI, TRI))
+ if (!Reserved[S.Reg])
+ LiveIns.insert(S);
+ }
return LiveIns;
}
-
HexagonBlockRanges::RegisterSet HexagonBlockRanges::expandToSubRegs(
RegisterRef R, const MachineRegisterInfo &MRI,
const TargetRegisterInfo &TRI) {
@@ -279,7 +284,6 @@ HexagonBlockRanges::RegisterSet HexagonBlockRanges::expandToSubRegs(
return SRs;
}
-
void HexagonBlockRanges::computeInitialLiveRanges(InstrIndexMap &IndexMap,
RegToRangeMap &LiveMap) {
std::map<RegisterRef,IndexType> LastDef, LastUse;
@@ -287,9 +291,8 @@ void HexagonBlockRanges::computeInitialLiveRanges(InstrIndexMap &IndexMap,
MachineBasicBlock &B = IndexMap.getBlock();
MachineRegisterInfo &MRI = B.getParent()->getRegInfo();
- for (auto R : getLiveIns(B))
- for (auto S : expandToSubRegs(R, MRI, TRI))
- LiveOnEntry.insert(S);
+ for (auto R : getLiveIns(B, MRI, TRI))
+ LiveOnEntry.insert(R);
for (auto R : LiveOnEntry)
LastDef[R] = IndexType::Entry;
@@ -340,9 +343,8 @@ void HexagonBlockRanges::computeInitialLiveRanges(InstrIndexMap &IndexMap,
// Collect live-on-exit.
RegisterSet LiveOnExit;
for (auto *SB : B.successors())
- for (auto R : getLiveIns(*SB))
- for (auto S : expandToSubRegs(R, MRI, TRI))
- LiveOnExit.insert(S);
+ for (auto R : getLiveIns(*SB, MRI, TRI))
+ LiveOnExit.insert(R);
for (auto R : LiveOnExit)
LastUse[R] = IndexType::Exit;
@@ -363,18 +365,16 @@ void HexagonBlockRanges::computeInitialLiveRanges(InstrIndexMap &IndexMap,
P.second.unionize();
}
-
HexagonBlockRanges::RegToRangeMap HexagonBlockRanges::computeLiveMap(
InstrIndexMap &IndexMap) {
RegToRangeMap LiveMap;
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << ": index map\n" << IndexMap << '\n');
+ DEBUG(dbgs() << __func__ << ": index map\n" << IndexMap << '\n');
computeInitialLiveRanges(IndexMap, LiveMap);
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << ": live map\n"
+ DEBUG(dbgs() << __func__ << ": live map\n"
<< PrintRangeMap(LiveMap, TRI) << '\n');
return LiveMap;
}
-
HexagonBlockRanges::RegToRangeMap HexagonBlockRanges::computeDeadMap(
InstrIndexMap &IndexMap, RegToRangeMap &LiveMap) {
RegToRangeMap DeadMap;
@@ -432,7 +432,7 @@ HexagonBlockRanges::RegToRangeMap HexagonBlockRanges::computeDeadMap(
if (TargetRegisterInfo::isVirtualRegister(P.first.Reg))
addDeadRanges(P.first);
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << ": dead map\n"
+ DEBUG(dbgs() << __func__ << ": dead map\n"
<< PrintRangeMap(DeadMap, TRI) << '\n');
return DeadMap;
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.h b/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.h
index 9c3f938..7174803 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonBlockRanges.h
@@ -1,4 +1,4 @@
-//===--- HexagonBlockRanges.h ---------------------------------------------===//
+//===--- HexagonBlockRanges.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,23 +11,21 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/MC/MCRegisterInfo.h" // For MCPhysReg.
+#include <cassert>
#include <map>
#include <set>
#include <vector>
+#include <utility>
namespace llvm {
- class Function;
- class HexagonSubtarget;
- class MachineBasicBlock;
- class MachineFunction;
- class MachineInstr;
- class MCInstrDesc;
- class raw_ostream;
- class TargetInstrInfo;
- class TargetRegisterClass;
- class TargetRegisterInfo;
- class Type;
+
+class HexagonSubtarget;
+class MachineBasicBlock;
+class MachineFunction;
+class MachineInstr;
+class raw_ostream;
+class TargetInstrInfo;
+class TargetRegisterInfo;
struct HexagonBlockRanges {
HexagonBlockRanges(MachineFunction &MF);
@@ -50,10 +48,12 @@ struct HexagonBlockRanges {
Exit = 2,
First = 11 // 10th + 1st
};
- static bool isInstr(IndexType X) { return X.Index >= First; }
IndexType() : Index(None) {}
IndexType(unsigned Idx) : Index(Idx) {}
+
+ static bool isInstr(IndexType X) { return X.Index >= First; }
+
operator unsigned() const;
bool operator== (unsigned x) const;
bool operator== (IndexType Idx) const;
@@ -76,21 +76,23 @@ struct HexagonBlockRanges {
// register is dead.
class IndexRange : public std::pair<IndexType,IndexType> {
public:
- IndexRange() : Fixed(false), TiedEnd(false) {}
+ IndexRange() = default;
IndexRange(IndexType Start, IndexType End, bool F = false, bool T = false)
: std::pair<IndexType,IndexType>(Start, End), Fixed(F), TiedEnd(T) {}
+
IndexType start() const { return first; }
IndexType end() const { return second; }
bool operator< (const IndexRange &A) const {
return start() < A.start();
}
+
bool overlaps(const IndexRange &A) const;
bool contains(const IndexRange &A) const;
void merge(const IndexRange &A);
- bool Fixed; // Can be renamed? "Fixed" means "no".
- bool TiedEnd; // The end is not a use, but a dead def tied to a use.
+ bool Fixed = false; // Can be renamed? "Fixed" means "no".
+ bool TiedEnd = false; // The end is not a use, but a dead def tied to a use.
private:
void setStart(const IndexType &S) { first = S; }
@@ -107,6 +109,7 @@ struct HexagonBlockRanges {
void add(const IndexRange &Range) {
push_back(Range);
}
+
void include(const RangeList &RL);
void unionize(bool MergeAdjacent = false);
void subtract(const IndexRange &Range);
@@ -118,6 +121,7 @@ struct HexagonBlockRanges {
class InstrIndexMap {
public:
InstrIndexMap(MachineBasicBlock &B);
+
MachineInstr *getInstr(IndexType Idx) const;
IndexType getIndex(MachineInstr *MI) const;
MachineBasicBlock &getBlock() const { return Block; }
@@ -126,6 +130,7 @@ struct HexagonBlockRanges {
void replaceInstr(MachineInstr *OldMI, MachineInstr *NewMI);
friend raw_ostream &operator<< (raw_ostream &OS, const InstrIndexMap &Map);
+
IndexType First, Last;
private:
@@ -144,13 +149,15 @@ struct HexagonBlockRanges {
: Map(M), TRI(I) {}
friend raw_ostream &operator<< (raw_ostream &OS, const PrintRangeMap &P);
+
private:
const RegToRangeMap &Map;
const TargetRegisterInfo &TRI;
};
private:
- RegisterSet getLiveIns(const MachineBasicBlock &B);
+ RegisterSet getLiveIns(const MachineBasicBlock &B,
+ const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI);
void computeInitialLiveRanges(InstrIndexMap &IndexMap,
RegToRangeMap &LiveMap);
@@ -162,7 +169,6 @@ private:
BitVector Reserved;
};
-
inline HexagonBlockRanges::IndexType::operator unsigned() const {
assert(Index >= First);
return Index;
@@ -223,7 +229,6 @@ inline bool HexagonBlockRanges::IndexType::operator<= (IndexType Idx) const {
return operator==(Idx) || operator<(Idx);
}
-
raw_ostream &operator<< (raw_ostream &OS, HexagonBlockRanges::IndexType Idx);
raw_ostream &operator<< (raw_ostream &OS,
const HexagonBlockRanges::IndexRange &IR);
@@ -234,6 +239,6 @@ raw_ostream &operator<< (raw_ostream &OS,
raw_ostream &operator<< (raw_ostream &OS,
const HexagonBlockRanges::PrintRangeMap &P);
-} // namespace llvm
+} // end namespace llvm
-#endif
+#endif // HEXAGON_BLOCK_RANGES_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp
index f042baf..84af4b1 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp
@@ -12,15 +12,23 @@
#include "Hexagon.h"
#include "HexagonInstrInfo.h"
#include "HexagonSubtarget.h"
-#include "HexagonTargetMachine.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/PassSupport.h"
+#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
using namespace llvm;
@@ -30,21 +38,25 @@ static cl::opt<uint32_t> BranchRelaxSafetyBuffer("branch-relax-safety-buffer",
cl::init(200), cl::Hidden, cl::ZeroOrMore, cl::desc("safety buffer size"));
namespace llvm {
+
FunctionPass *createHexagonBranchRelaxation();
void initializeHexagonBranchRelaxationPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
+
struct HexagonBranchRelaxation : public MachineFunctionPass {
public:
static char ID;
+
HexagonBranchRelaxation() : MachineFunctionPass(ID) {
initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon Branch Relaxation";
}
@@ -67,6 +79,7 @@ namespace {
};
char HexagonBranchRelaxation::ID = 0;
+
} // end anonymous namespace
INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax",
@@ -76,7 +89,6 @@ FunctionPass *llvm::createHexagonBranchRelaxation() {
return new HexagonBranchRelaxation();
}
-
bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n");
@@ -89,7 +101,6 @@ bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {
return Changed;
}
-
void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,
DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) {
// offset of the current instruction from the start.
@@ -104,11 +115,10 @@ void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,
}
OffsetMap[&B] = InstOffset;
for (auto &MI : B.instrs())
- InstOffset += HII->getSize(&MI);
+ InstOffset += HII->getSize(MI);
}
}
-
/// relaxBranches - For Hexagon, if the jump target/loop label is too far from
/// the jump/loop instruction then, we need to make sure that we have constant
/// extenders set for jumps and loops.
@@ -124,7 +134,6 @@ bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) {
return reGenerateBranch(MF, BlockToInstOffset);
}
-
/// Check if a given instruction is:
/// - a jump to a distant target
/// - that exceeds its immediate range
@@ -144,7 +153,7 @@ bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
// Number of instructions times typical instruction size.
InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE;
- MachineBasicBlock *TBB = NULL, *FBB = NULL;
+ MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
SmallVector<MachineOperand, 4> Cond;
// Try to analyze this branch.
@@ -152,13 +161,13 @@ bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
// Could not analyze it. See if this is something we can recognize.
// If it is a NVJ, it should always have its target in
// a fixed location.
- if (HII->isNewValueJump(&*FirstTerm))
- TBB = FirstTerm->getOperand(HII->getCExtOpNum(&*FirstTerm)).getMBB();
+ if (HII->isNewValueJump(*FirstTerm))
+ TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB();
}
if (TBB && &MI == &*FirstTerm) {
Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB])
+ BranchRelaxSafetyBuffer;
- return !HII->isJumpWithinBranchRange(&*FirstTerm, Distance);
+ return !HII->isJumpWithinBranchRange(*FirstTerm, Distance);
}
if (FBB) {
// Look for second terminator.
@@ -171,12 +180,11 @@ bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
// Analyze the second branch in the BB.
Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB])
+ BranchRelaxSafetyBuffer;
- return !HII->isJumpWithinBranchRange(&*SecondTerm, Distance);
+ return !HII->isJumpWithinBranchRange(*SecondTerm, Distance);
}
return false;
}
-
bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,
DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
bool Changed = false;
@@ -186,16 +194,16 @@ bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,
if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset))
continue;
DEBUG(dbgs() << "Long distance jump. isExtendable("
- << HII->isExtendable(&MI) << ") isConstExtended("
- << HII->isConstExtended(&MI) << ") " << MI);
+ << HII->isExtendable(MI) << ") isConstExtended("
+ << HII->isConstExtended(MI) << ") " << MI);
// Since we have not merged HW loops relaxation into
// this code (yet), soften our approach for the moment.
- if (!HII->isExtendable(&MI) && !HII->isExtended(&MI)) {
+ if (!HII->isExtendable(MI) && !HII->isExtended(MI)) {
DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n");
} else {
// Find which operand is expandable.
- int ExtOpNum = HII->getCExtOpNum(&MI);
+ int ExtOpNum = HII->getCExtOpNum(MI);
MachineOperand &MO = MI.getOperand(ExtOpNum);
// This need to be something we understand. So far we assume all
// branches have only MBB address as expandable field.
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp
index 559bdfb..2f8fe6e 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonCFGOptimizer.cpp
@@ -45,13 +45,11 @@ public:
initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
- return "Hexagon CFG Optimizer";
- }
+ StringRef getPassName() const override { return "Hexagon CFG Optimizer"; }
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
};
@@ -59,8 +57,18 @@ public:
char HexagonCFGOptimizer::ID = 0;
static bool IsConditionalBranch(int Opc) {
- return (Opc == Hexagon::J2_jumpt) || (Opc == Hexagon::J2_jumpf)
- || (Opc == Hexagon::J2_jumptnewpt) || (Opc == Hexagon::J2_jumpfnewpt);
+ switch (Opc) {
+ case Hexagon::J2_jumpt:
+ case Hexagon::J2_jumptpt:
+ case Hexagon::J2_jumpf:
+ case Hexagon::J2_jumpfpt:
+ case Hexagon::J2_jumptnew:
+ case Hexagon::J2_jumpfnew:
+ case Hexagon::J2_jumptnewpt:
+ case Hexagon::J2_jumpfnewpt:
+ return true;
+ }
+ return false;
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonCommonGEP.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonCommonGEP.cpp
index b612b11..489da6b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonCommonGEP.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonCommonGEP.cpp
@@ -9,30 +9,43 @@
#define DEBUG_TYPE "commgep"
-#include "llvm/Pass.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/PostDominators.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
+#include "llvm/Pass.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
-
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
#include <map>
#include <set>
+#include <utility>
#include <vector>
-#include "HexagonTargetMachine.h"
-
using namespace llvm;
static cl::opt<bool> OptSpeculate("commgep-speculate", cl::init(true),
@@ -45,10 +58,13 @@ static cl::opt<bool> OptEnableConst("commgep-const", cl::init(true),
cl::Hidden, cl::ZeroOrMore);
namespace llvm {
+
void initializeHexagonCommonGEPPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
+
struct GepNode;
typedef std::set<GepNode*> NodeSet;
typedef std::map<GepNode*,Value*> NodeToValueMap;
@@ -60,7 +76,7 @@ namespace {
// Numbering map for gep nodes. Used to keep track of ordering for
// gep nodes.
struct NodeOrdering {
- NodeOrdering() : LastNum(0) {}
+ NodeOrdering() = default;
void insert(const GepNode *N) { Map.insert(std::make_pair(N, ++LastNum)); }
void clear() { Map.clear(); }
@@ -73,21 +89,21 @@ namespace {
private:
std::map<const GepNode *, unsigned> Map;
- unsigned LastNum;
+ unsigned LastNum = 0;
};
class HexagonCommonGEP : public FunctionPass {
public:
static char ID;
+
HexagonCommonGEP() : FunctionPass(ID) {
initializeHexagonCommonGEPPass(*PassRegistry::getPassRegistry());
}
- virtual bool runOnFunction(Function &F);
- virtual const char *getPassName() const {
- return "Hexagon Common GEP";
- }
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ bool runOnFunction(Function &F) override;
+ StringRef getPassName() const override { return "Hexagon Common GEP"; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DominatorTreeWrapperPass>();
AU.addPreserved<DominatorTreeWrapperPass>();
AU.addRequired<PostDominatorTreeWrapperPass>();
@@ -140,8 +156,8 @@ namespace {
PostDominatorTree *PDT;
Function *Fn;
};
-}
+} // end anonymous namespace
char HexagonCommonGEP::ID = 0;
INITIALIZE_PASS_BEGIN(HexagonCommonGEP, "hcommgep", "Hexagon Common GEP",
@@ -153,6 +169,7 @@ INITIALIZE_PASS_END(HexagonCommonGEP, "hcommgep", "Hexagon Common GEP",
false, false)
namespace {
+
struct GepNode {
enum {
None = 0,
@@ -169,18 +186,20 @@ namespace {
Value *Idx;
Type *PTy; // Type of the pointer operand.
- GepNode() : Flags(0), Parent(0), Idx(0), PTy(0) {}
+ GepNode() : Flags(0), Parent(nullptr), Idx(nullptr), PTy(nullptr) {}
GepNode(const GepNode *N) : Flags(N->Flags), Idx(N->Idx), PTy(N->PTy) {
if (Flags & Root)
BaseVal = N->BaseVal;
else
Parent = N->Parent;
}
+
friend raw_ostream &operator<< (raw_ostream &OS, const GepNode &GN);
};
-
Type *next_type(Type *Ty, Value *Idx) {
+ if (auto *PTy = dyn_cast<PointerType>(Ty))
+ return PTy->getElementType();
// Advance the type.
if (!Ty->isStructTy()) {
Type *NexTy = cast<SequentialType>(Ty)->getElementType();
@@ -194,7 +213,6 @@ namespace {
return NextTy;
}
-
raw_ostream &operator<< (raw_ostream &OS, const GepNode &GN) {
OS << "{ {";
bool Comma = false;
@@ -241,7 +259,6 @@ namespace {
return OS;
}
-
template <typename NodeContainer>
void dump_node_container(raw_ostream &OS, const NodeContainer &S) {
typedef typename NodeContainer::const_iterator const_iterator;
@@ -256,7 +273,6 @@ namespace {
return OS;
}
-
raw_ostream &operator<< (raw_ostream &OS,
const NodeToUsesMap &M) LLVM_ATTRIBUTE_UNUSED;
raw_ostream &operator<< (raw_ostream &OS, const NodeToUsesMap &M){
@@ -276,23 +292,22 @@ namespace {
return OS;
}
-
struct in_set {
in_set(const NodeSet &S) : NS(S) {}
bool operator() (GepNode *N) const {
return NS.find(N) != NS.end();
}
+
private:
const NodeSet &NS;
};
-}
+} // end anonymous namespace
inline void *operator new(size_t, SpecificBumpPtrAllocator<GepNode> &A) {
return A.Allocate();
}
-
void HexagonCommonGEP::getBlockTraversalOrder(BasicBlock *Root,
ValueVect &Order) {
// Compute block ordering for a typical DT-based traversal of the flow
@@ -307,7 +322,6 @@ void HexagonCommonGEP::getBlockTraversalOrder(BasicBlock *Root,
getBlockTraversalOrder((*I)->getBlock(), Order);
}
-
bool HexagonCommonGEP::isHandledGepForm(GetElementPtrInst *GepI) {
// No vector GEPs.
if (!GepI->getType()->isPointerTy())
@@ -318,7 +332,6 @@ bool HexagonCommonGEP::isHandledGepForm(GetElementPtrInst *GepI) {
return true;
}
-
void HexagonCommonGEP::processGepInst(GetElementPtrInst *GepI,
ValueToNodeMap &NM) {
DEBUG(dbgs() << "Visiting GEP: " << *GepI << '\n');
@@ -384,7 +397,6 @@ void HexagonCommonGEP::processGepInst(GetElementPtrInst *GepI,
NM.insert(std::make_pair(GepI, PN));
}
-
void HexagonCommonGEP::collect() {
// Establish depth-first traversal order of the dominator tree.
ValueVect BO;
@@ -408,10 +420,8 @@ void HexagonCommonGEP::collect() {
DEBUG(dbgs() << "Gep nodes after initial collection:\n" << Nodes);
}
-
-namespace {
- void invert_find_roots(const NodeVect &Nodes, NodeChildrenMap &NCM,
- NodeVect &Roots) {
+static void invert_find_roots(const NodeVect &Nodes, NodeChildrenMap &NCM,
+ NodeVect &Roots) {
typedef NodeVect::const_iterator const_iterator;
for (const_iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) {
GepNode *N = *I;
@@ -422,9 +432,10 @@ namespace {
GepNode *PN = N->Parent;
NCM[PN].push_back(N);
}
- }
+}
- void nodes_for_root(GepNode *Root, NodeChildrenMap &NCM, NodeSet &Nodes) {
+static void nodes_for_root(GepNode *Root, NodeChildrenMap &NCM,
+ NodeSet &Nodes) {
NodeVect Work;
Work.push_back(Root);
Nodes.insert(Root);
@@ -439,41 +450,43 @@ namespace {
Nodes.insert(CF->second.begin(), CF->second.end());
}
}
- }
}
-
namespace {
+
typedef std::set<NodeSet> NodeSymRel;
typedef std::pair<GepNode*,GepNode*> NodePair;
typedef std::set<NodePair> NodePairSet;
- const NodeSet *node_class(GepNode *N, NodeSymRel &Rel) {
+} // end anonymous namespace
+
+static const NodeSet *node_class(GepNode *N, NodeSymRel &Rel) {
for (NodeSymRel::iterator I = Rel.begin(), E = Rel.end(); I != E; ++I)
if (I->count(N))
return &*I;
- return 0;
- }
+ return nullptr;
+}
// Create an ordered pair of GepNode pointers. The pair will be used in
// determining equality. The only purpose of the ordering is to eliminate
// duplication due to the commutativity of equality/non-equality.
- NodePair node_pair(GepNode *N1, GepNode *N2) {
+static NodePair node_pair(GepNode *N1, GepNode *N2) {
uintptr_t P1 = uintptr_t(N1), P2 = uintptr_t(N2);
if (P1 <= P2)
return std::make_pair(N1, N2);
return std::make_pair(N2, N1);
- }
+}
- unsigned node_hash(GepNode *N) {
+static unsigned node_hash(GepNode *N) {
// Include everything except flags and parent.
FoldingSetNodeID ID;
ID.AddPointer(N->Idx);
ID.AddPointer(N->PTy);
return ID.ComputeHash();
- }
+}
- bool node_eq(GepNode *N1, GepNode *N2, NodePairSet &Eq, NodePairSet &Ne) {
+static bool node_eq(GepNode *N1, GepNode *N2, NodePairSet &Eq,
+ NodePairSet &Ne) {
// Don't cache the result for nodes with different hashes. The hash
// comparison is fast enough.
if (node_hash(N1) != node_hash(N2))
@@ -505,10 +518,8 @@ namespace {
return true;
}
return false;
- }
}
-
void HexagonCommonGEP::common() {
// The essence of this commoning is finding gep nodes that are equal.
// To do this we need to compare all pairs of nodes. To save time,
@@ -572,7 +583,6 @@ void HexagonCommonGEP::common() {
}
});
-
// Create a projection from a NodeSet to the minimal element in it.
typedef std::map<const NodeSet*,GepNode*> ProjMap;
ProjMap PM;
@@ -639,17 +649,14 @@ void HexagonCommonGEP::common() {
// Node for removal.
Erase.insert(*I);
}
- NodeVect::iterator NewE = std::remove_if(Nodes.begin(), Nodes.end(),
- in_set(Erase));
+ NodeVect::iterator NewE = remove_if(Nodes, in_set(Erase));
Nodes.resize(std::distance(Nodes.begin(), NewE));
DEBUG(dbgs() << "Gep nodes after post-commoning cleanup:\n" << Nodes);
}
-
-namespace {
- template <typename T>
- BasicBlock *nearest_common_dominator(DominatorTree *DT, T &Blocks) {
+template <typename T>
+static BasicBlock *nearest_common_dominator(DominatorTree *DT, T &Blocks) {
DEBUG({
dbgs() << "NCD of {";
for (typename T::iterator I = Blocks.begin(), E = Blocks.end();
@@ -662,23 +669,23 @@ namespace {
dbgs() << " }\n";
});
- // Allow null basic blocks in Blocks. In such cases, return 0.
+ // Allow null basic blocks in Blocks. In such cases, return nullptr.
typename T::iterator I = Blocks.begin(), E = Blocks.end();
if (I == E || !*I)
- return 0;
+ return nullptr;
BasicBlock *Dom = cast<BasicBlock>(*I);
while (++I != E) {
BasicBlock *B = cast_or_null<BasicBlock>(*I);
- Dom = B ? DT->findNearestCommonDominator(Dom, B) : 0;
+ Dom = B ? DT->findNearestCommonDominator(Dom, B) : nullptr;
if (!Dom)
- return 0;
+ return nullptr;
}
DEBUG(dbgs() << "computed:" << Dom->getName() << '\n');
return Dom;
- }
+}
- template <typename T>
- BasicBlock *nearest_common_dominatee(DominatorTree *DT, T &Blocks) {
+template <typename T>
+static BasicBlock *nearest_common_dominatee(DominatorTree *DT, T &Blocks) {
// If two blocks, A and B, dominate a block C, then A dominates B,
// or B dominates A.
typename T::iterator I = Blocks.begin(), E = Blocks.end();
@@ -695,16 +702,16 @@ namespace {
if (DT->dominates(B, DomB))
continue;
if (!DT->dominates(DomB, B))
- return 0;
+ return nullptr;
DomB = B;
}
return DomB;
- }
+}
- // Find the first use in B of any value from Values. If no such use,
- // return B->end().
- template <typename T>
- BasicBlock::iterator first_use_of_in_block(T &Values, BasicBlock *B) {
+// Find the first use in B of any value from Values. If no such use,
+// return B->end().
+template <typename T>
+static BasicBlock::iterator first_use_of_in_block(T &Values, BasicBlock *B) {
BasicBlock::iterator FirstUse = B->end(), BEnd = B->end();
typedef typename T::iterator iterator;
for (iterator I = Values.begin(), E = Values.end(); I != E; ++I) {
@@ -726,20 +733,18 @@ namespace {
FirstUse = It;
}
return FirstUse;
- }
+}
- bool is_empty(const BasicBlock *B) {
+static bool is_empty(const BasicBlock *B) {
return B->empty() || (&*B->begin() == B->getTerminator());
- }
}
-
BasicBlock *HexagonCommonGEP::recalculatePlacement(GepNode *Node,
NodeChildrenMap &NCM, NodeToValueMap &Loc) {
DEBUG(dbgs() << "Loc for node:" << Node << '\n');
// Recalculate the placement for Node, assuming that the locations of
// its children in Loc are valid.
- // Return 0 if there is no valid placement for Node (for example, it
+ // Return nullptr if there is no valid placement for Node (for example, it
// uses an index value that is not available at the location required
// to dominate all children, etc.).
@@ -782,11 +787,11 @@ BasicBlock *HexagonCommonGEP::recalculatePlacement(GepNode *Node,
BasicBlock *DomB = nearest_common_dominator(DT, Bs);
if (!DomB)
- return 0;
+ return nullptr;
// Check if the index used by Node dominates the computed dominator.
Instruction *IdxI = dyn_cast<Instruction>(Node->Idx);
if (IdxI && !DT->dominates(IdxI->getParent(), DomB))
- return 0;
+ return nullptr;
// Avoid putting nodes into empty blocks.
while (is_empty(DomB)) {
@@ -801,7 +806,6 @@ BasicBlock *HexagonCommonGEP::recalculatePlacement(GepNode *Node,
return DomB;
}
-
BasicBlock *HexagonCommonGEP::recalculatePlacementRec(GepNode *Node,
NodeChildrenMap &NCM, NodeToValueMap &Loc) {
DEBUG(dbgs() << "LocRec begin for node:" << Node << '\n');
@@ -818,7 +822,6 @@ BasicBlock *HexagonCommonGEP::recalculatePlacementRec(GepNode *Node,
return LB;
}
-
bool HexagonCommonGEP::isInvariantIn(Value *Val, Loop *L) {
if (isa<Constant>(Val) || isa<Argument>(Val))
return true;
@@ -829,7 +832,6 @@ bool HexagonCommonGEP::isInvariantIn(Value *Val, Loop *L) {
return DT->properlyDominates(DefB, HdrB);
}
-
bool HexagonCommonGEP::isInvariantIn(GepNode *Node, Loop *L) {
if (Node->Flags & GepNode::Root)
if (!isInvariantIn(Node->BaseVal, L))
@@ -837,7 +839,6 @@ bool HexagonCommonGEP::isInvariantIn(GepNode *Node, Loop *L) {
return isInvariantIn(Node->Idx, L);
}
-
bool HexagonCommonGEP::isInMainPath(BasicBlock *B, Loop *L) {
BasicBlock *HB = L->getHeader();
BasicBlock *LB = L->getLoopLatch();
@@ -849,21 +850,17 @@ bool HexagonCommonGEP::isInMainPath(BasicBlock *B, Loop *L) {
return false;
}
-
-namespace {
- BasicBlock *preheader(DominatorTree *DT, Loop *L) {
- if (BasicBlock *PH = L->getLoopPreheader())
- return PH;
- if (!OptSpeculate)
- return 0;
- DomTreeNode *DN = DT->getNode(L->getHeader());
- if (!DN)
- return 0;
- return DN->getIDom()->getBlock();
- }
+static BasicBlock *preheader(DominatorTree *DT, Loop *L) {
+ if (BasicBlock *PH = L->getLoopPreheader())
+ return PH;
+ if (!OptSpeculate)
+ return nullptr;
+ DomTreeNode *DN = DT->getNode(L->getHeader());
+ if (!DN)
+ return nullptr;
+ return DN->getIDom()->getBlock();
}
-
BasicBlock *HexagonCommonGEP::adjustForInvariance(GepNode *Node,
NodeChildrenMap &NCM, NodeToValueMap &Loc) {
// Find the "topmost" location for Node: it must be dominated by both,
@@ -913,10 +910,11 @@ BasicBlock *HexagonCommonGEP::adjustForInvariance(GepNode *Node,
return LocB;
}
-
namespace {
+
struct LocationAsBlock {
LocationAsBlock(const NodeToValueMap &L) : Map(L) {}
+
const NodeToValueMap &Map;
};
@@ -936,8 +934,8 @@ namespace {
inline bool is_constant(GepNode *N) {
return isa<ConstantInt>(N->Idx);
}
-}
+} // end anonymous namespace
void HexagonCommonGEP::separateChainForNode(GepNode *Node, Use *U,
NodeToValueMap &Loc) {
@@ -947,7 +945,7 @@ void HexagonCommonGEP::separateChainForNode(GepNode *Node, Use *U,
BasicBlock *PB = cast<Instruction>(R)->getParent();
GepNode *N = Node;
- GepNode *C = 0, *NewNode = 0;
+ GepNode *C = nullptr, *NewNode = nullptr;
while (is_constant(N) && !(N->Flags & GepNode::Root)) {
// XXX if (single-use) dont-replicate;
GepNode *NewN = new (*Mem) GepNode(N);
@@ -991,7 +989,6 @@ void HexagonCommonGEP::separateChainForNode(GepNode *Node, Use *U,
Uses[NewNode] = NewUs;
}
-
void HexagonCommonGEP::separateConstantChains(GepNode *Node,
NodeChildrenMap &NCM, NodeToValueMap &Loc) {
// First approximation: extract all chains.
@@ -1045,7 +1042,6 @@ void HexagonCommonGEP::separateConstantChains(GepNode *Node,
}
}
-
void HexagonCommonGEP::computeNodePlacement(NodeToValueMap &Loc) {
// Compute the inverse of the Node.Parent links. Also, collect the set
// of root nodes.
@@ -1080,7 +1076,6 @@ void HexagonCommonGEP::computeNodePlacement(NodeToValueMap &Loc) {
DEBUG(dbgs() << "Final node placement:\n" << LocationAsBlock(Loc));
}
-
Value *HexagonCommonGEP::fabricateGEP(NodeVect &NA, BasicBlock::iterator At,
BasicBlock *LocB) {
DEBUG(dbgs() << "Fabricating GEP in " << LocB->getName()
@@ -1089,7 +1084,7 @@ Value *HexagonCommonGEP::fabricateGEP(NodeVect &NA, BasicBlock::iterator At,
GepNode *RN = NA[0];
assert((RN->Flags & GepNode::Root) && "Creating GEP for non-root");
- Value *NewInst = 0;
+ Value *NewInst = nullptr;
Value *Input = RN->BaseVal;
Value **IdxList = new Value*[Num+1];
unsigned nax = 0;
@@ -1128,7 +1123,6 @@ Value *HexagonCommonGEP::fabricateGEP(NodeVect &NA, BasicBlock::iterator At,
return NewInst;
}
-
void HexagonCommonGEP::getAllUsersForNode(GepNode *Node, ValueVect &Values,
NodeChildrenMap &NCM) {
NodeVect Work;
@@ -1153,7 +1147,6 @@ void HexagonCommonGEP::getAllUsersForNode(GepNode *Node, ValueVect &Values,
}
}
-
void HexagonCommonGEP::materialize(NodeToValueMap &Loc) {
DEBUG(dbgs() << "Nodes before materialization:\n" << Nodes << '\n');
NodeChildrenMap NCM;
@@ -1192,7 +1185,7 @@ void HexagonCommonGEP::materialize(NodeToValueMap &Loc) {
break;
GepNode *Child = CF->second.front();
BasicBlock *ChildB = cast_or_null<BasicBlock>(Loc[Child]);
- if (ChildB != 0 && LastB != ChildB)
+ if (ChildB != nullptr && LastB != ChildB)
break;
Last = Child;
} while (true);
@@ -1236,7 +1229,6 @@ void HexagonCommonGEP::materialize(NodeToValueMap &Loc) {
}
}
-
void HexagonCommonGEP::removeDeadCode() {
ValueVect BO;
BO.push_back(&Fn->front());
@@ -1265,7 +1257,6 @@ void HexagonCommonGEP::removeDeadCode() {
}
}
-
bool HexagonCommonGEP::runOnFunction(Function &F) {
if (skipFunction(F))
return false;
@@ -1304,9 +1295,10 @@ bool HexagonCommonGEP::runOnFunction(Function &F) {
return true;
}
-
namespace llvm {
+
FunctionPass *createHexagonCommonGEP() {
return new HexagonCommonGEP();
}
-}
+
+} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonConstPropagation.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonConstPropagation.cpp
new file mode 100644
index 0000000..783b916
--- /dev/null
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonConstPropagation.cpp
@@ -0,0 +1,3149 @@
+//===--- HexagonConstPropagation.cpp --------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "hcp"
+
+#include "HexagonInstrInfo.h"
+#include "HexagonRegisterInfo.h"
+#include "HexagonSubtarget.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <map>
+#include <queue>
+#include <set>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+ // Properties of a value that are tracked by the propagation.
+ // A property that is marked as present (i.e. bit is set) dentes that the
+ // value is known (proven) to have this property. Not all combinations
+ // of bits make sense, for example Zero and NonZero are mutually exclusive,
+ // but on the other hand, Zero implies Finite. In this case, whenever
+ // the Zero property is present, Finite should also be present.
+ class ConstantProperties {
+ public:
+ enum {
+ Unknown = 0x0000,
+ Zero = 0x0001,
+ NonZero = 0x0002,
+ Finite = 0x0004,
+ Infinity = 0x0008,
+ NaN = 0x0010,
+ SignedZero = 0x0020,
+ NumericProperties = (Zero|NonZero|Finite|Infinity|NaN|SignedZero),
+ PosOrZero = 0x0100,
+ NegOrZero = 0x0200,
+ SignProperties = (PosOrZero|NegOrZero),
+ Everything = (NumericProperties|SignProperties)
+ };
+
+ // For a given constant, deduce the set of trackable properties that this
+ // constant has.
+ static uint32_t deduce(const Constant *C);
+ };
+
+ // A representation of a register as it can appear in a MachineOperand,
+ // i.e. a pair register:subregister.
+ struct Register {
+ unsigned Reg, SubReg;
+
+ explicit Register(unsigned R, unsigned SR = 0) : Reg(R), SubReg(SR) {}
+ explicit Register(const MachineOperand &MO)
+ : Reg(MO.getReg()), SubReg(MO.getSubReg()) {}
+
+ void print(const TargetRegisterInfo *TRI = nullptr) const {
+ dbgs() << PrintReg(Reg, TRI, SubReg);
+ }
+
+ bool operator== (const Register &R) const {
+ return (Reg == R.Reg) && (SubReg == R.SubReg);
+ }
+ };
+
+ // Lattice cell, based on that was described in the W-Z paper on constant
+ // propagation.
+ // Latice cell will be allowed to hold multiple constant values. While
+ // multiple values would normally indicate "bottom", we can still derive
+ // some useful information from them. For example, comparison X > 0
+ // could be folded if all the values in the cell associated with X are
+ // positive.
+ class LatticeCell {
+ private:
+ enum { Normal, Top, Bottom };
+
+ static const unsigned MaxCellSize = 4;
+
+ unsigned Kind:2;
+ unsigned Size:3;
+ unsigned IsSpecial:1;
+ unsigned :0;
+
+ public:
+ union {
+ uint32_t Properties;
+ const Constant *Value;
+ const Constant *Values[MaxCellSize];
+ };
+
+ LatticeCell() : Kind(Top), Size(0), IsSpecial(false) {
+ for (unsigned i = 0; i < MaxCellSize; ++i)
+ Values[i] = nullptr;
+ }
+
+ bool meet(const LatticeCell &L);
+ bool add(const Constant *C);
+ bool add(uint32_t Property);
+ uint32_t properties() const;
+ unsigned size() const { return Size; }
+
+ LatticeCell &operator= (const LatticeCell &L) {
+ if (this != &L) {
+ // This memcpy also copies Properties (when L.Size == 0).
+ uint32_t N = L.IsSpecial ? sizeof L.Properties
+ : L.Size*sizeof(const Constant*);
+ memcpy(Values, L.Values, N);
+ Kind = L.Kind;
+ Size = L.Size;
+ IsSpecial = L.IsSpecial;
+ }
+ return *this;
+ }
+
+ bool isSingle() const { return size() == 1; }
+ bool isProperty() const { return IsSpecial; }
+ bool isTop() const { return Kind == Top; }
+ bool isBottom() const { return Kind == Bottom; }
+
+ bool setBottom() {
+ bool Changed = (Kind != Bottom);
+ Kind = Bottom;
+ Size = 0;
+ IsSpecial = false;
+ return Changed;
+ }
+
+ void print(raw_ostream &os) const;
+
+ private:
+ void setProperty() {
+ IsSpecial = true;
+ Size = 0;
+ Kind = Normal;
+ }
+
+ bool convertToProperty();
+ };
+
+ raw_ostream &operator<< (raw_ostream &os, const LatticeCell &L) {
+ L.print(os);
+ return os;
+ }
+
+ class MachineConstEvaluator;
+
+ class MachineConstPropagator {
+ public:
+ MachineConstPropagator(MachineConstEvaluator &E) : MCE(E) {
+ Bottom.setBottom();
+ }
+
+ // Mapping: vreg -> cell
+ // The keys are registers _without_ subregisters. This won't allow
+ // definitions in the form of "vreg:subreg<def> = ...". Such definitions
+ // would be questionable from the point of view of SSA, since the "vreg"
+ // could not be initialized in its entirety (specifically, an instruction
+ // defining the "other part" of "vreg" would also count as a definition
+ // of "vreg", which would violate the SSA).
+ // If a value of a pair vreg:subreg needs to be obtained, the cell for
+ // "vreg" needs to be looked up, and then the value of subregister "subreg"
+ // needs to be evaluated.
+ class CellMap {
+ public:
+ CellMap() {
+ assert(Top.isTop());
+ Bottom.setBottom();
+ }
+
+ void clear() { Map.clear(); }
+
+ bool has(unsigned R) const {
+ // All non-virtual registers are considered "bottom".
+ if (!TargetRegisterInfo::isVirtualRegister(R))
+ return true;
+ MapType::const_iterator F = Map.find(R);
+ return F != Map.end();
+ }
+
+ const LatticeCell &get(unsigned R) const {
+ if (!TargetRegisterInfo::isVirtualRegister(R))
+ return Bottom;
+ MapType::const_iterator F = Map.find(R);
+ if (F != Map.end())
+ return F->second;
+ return Top;
+ }
+
+ // Invalidates any const references.
+ void update(unsigned R, const LatticeCell &L) {
+ Map[R] = L;
+ }
+
+ void print(raw_ostream &os, const TargetRegisterInfo &TRI) const;
+
+ private:
+ typedef std::map<unsigned,LatticeCell> MapType;
+ MapType Map;
+ // To avoid creating "top" entries, return a const reference to
+ // this cell in "get". Also, have a "Bottom" cell to return from
+ // get when a value of a physical register is requested.
+ LatticeCell Top, Bottom;
+
+ public:
+ typedef MapType::const_iterator const_iterator;
+ const_iterator begin() const { return Map.begin(); }
+ const_iterator end() const { return Map.end(); }
+ };
+
+ bool run(MachineFunction &MF);
+
+ private:
+ void visitPHI(const MachineInstr &PN);
+ void visitNonBranch(const MachineInstr &MI);
+ void visitBranchesFrom(const MachineInstr &BrI);
+ void visitUsesOf(unsigned R);
+ bool computeBlockSuccessors(const MachineBasicBlock *MB,
+ SetVector<const MachineBasicBlock*> &Targets);
+ void removeCFGEdge(MachineBasicBlock *From, MachineBasicBlock *To);
+
+ void propagate(MachineFunction &MF);
+ bool rewrite(MachineFunction &MF);
+
+ MachineRegisterInfo *MRI;
+ MachineConstEvaluator &MCE;
+
+ typedef std::pair<unsigned,unsigned> CFGEdge;
+ typedef std::set<CFGEdge> SetOfCFGEdge;
+ typedef std::set<const MachineInstr*> SetOfInstr;
+ typedef std::queue<CFGEdge> QueueOfCFGEdge;
+
+ LatticeCell Bottom;
+ CellMap Cells;
+ SetOfCFGEdge EdgeExec;
+ SetOfInstr InstrExec;
+ QueueOfCFGEdge FlowQ;
+ };
+
+ // The "evaluator/rewriter" of machine instructions. This is an abstract
+ // base class that provides the interface that the propagator will use,
+ // as well as some helper functions that are target-independent.
+ class MachineConstEvaluator {
+ public:
+ MachineConstEvaluator(MachineFunction &Fn)
+ : TRI(*Fn.getSubtarget().getRegisterInfo()),
+ MF(Fn), CX(Fn.getFunction()->getContext()) {}
+ virtual ~MachineConstEvaluator() = default;
+
+ // The required interface:
+ // - A set of three "evaluate" functions. Each returns "true" if the
+ // computation succeeded, "false" otherwise.
+ // (1) Given an instruction MI, and the map with input values "Inputs",
+ // compute the set of output values "Outputs". An example of when
+ // the computation can "fail" is if MI is not an instruction that
+ // is recognized by the evaluator.
+ // (2) Given a register R (as reg:subreg), compute the cell that
+ // corresponds to the "subreg" part of the given register.
+ // (3) Given a branch instruction BrI, compute the set of target blocks.
+ // If the branch can fall-through, add null (0) to the list of
+ // possible targets.
+ // - A function "rewrite", that given the cell map after propagation,
+ // could rewrite instruction MI in a more beneficial form. Return
+ // "true" if a change has been made, "false" otherwise.
+ typedef MachineConstPropagator::CellMap CellMap;
+ virtual bool evaluate(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs) = 0;
+ virtual bool evaluate(const Register &R, const LatticeCell &SrcC,
+ LatticeCell &Result) = 0;
+ virtual bool evaluate(const MachineInstr &BrI, const CellMap &Inputs,
+ SetVector<const MachineBasicBlock*> &Targets,
+ bool &CanFallThru) = 0;
+ virtual bool rewrite(MachineInstr &MI, const CellMap &Inputs) = 0;
+
+ const TargetRegisterInfo &TRI;
+
+ protected:
+ MachineFunction &MF;
+ LLVMContext &CX;
+
+ struct Comparison {
+ enum {
+ Unk = 0x00,
+ EQ = 0x01,
+ NE = 0x02,
+ L = 0x04, // Less-than property.
+ G = 0x08, // Greater-than property.
+ U = 0x40, // Unsigned property.
+ LTs = L,
+ LEs = L | EQ,
+ GTs = G,
+ GEs = G | EQ,
+ LTu = L | U,
+ LEu = L | EQ | U,
+ GTu = G | U,
+ GEu = G | EQ | U
+ };
+
+ static uint32_t negate(uint32_t Cmp) {
+ if (Cmp == EQ)
+ return NE;
+ if (Cmp == NE)
+ return EQ;
+ assert((Cmp & (L|G)) != (L|G));
+ return Cmp ^ (L|G);
+ }
+ };
+
+ // Helper functions.
+
+ bool getCell(const Register &R, const CellMap &Inputs, LatticeCell &RC);
+ bool constToInt(const Constant *C, APInt &Val) const;
+ bool constToFloat(const Constant *C, APFloat &Val) const;
+ const ConstantInt *intToConst(const APInt &Val) const;
+
+ // Compares.
+ bool evaluateCMPrr(uint32_t Cmp, const Register &R1, const Register &R2,
+ const CellMap &Inputs, bool &Result);
+ bool evaluateCMPri(uint32_t Cmp, const Register &R1, const APInt &A2,
+ const CellMap &Inputs, bool &Result);
+ bool evaluateCMPrp(uint32_t Cmp, const Register &R1, uint64_t Props2,
+ const CellMap &Inputs, bool &Result);
+ bool evaluateCMPii(uint32_t Cmp, const APInt &A1, const APInt &A2,
+ bool &Result);
+ bool evaluateCMPpi(uint32_t Cmp, uint32_t Props, const APInt &A2,
+ bool &Result);
+ bool evaluateCMPpp(uint32_t Cmp, uint32_t Props1, uint32_t Props2,
+ bool &Result);
+
+ bool evaluateCOPY(const Register &R1, const CellMap &Inputs,
+ LatticeCell &Result);
+
+ // Logical operations.
+ bool evaluateANDrr(const Register &R1, const Register &R2,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateANDri(const Register &R1, const APInt &A2,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateANDii(const APInt &A1, const APInt &A2, APInt &Result);
+ bool evaluateORrr(const Register &R1, const Register &R2,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateORri(const Register &R1, const APInt &A2,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateORii(const APInt &A1, const APInt &A2, APInt &Result);
+ bool evaluateXORrr(const Register &R1, const Register &R2,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateXORri(const Register &R1, const APInt &A2,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateXORii(const APInt &A1, const APInt &A2, APInt &Result);
+
+ // Extensions.
+ bool evaluateZEXTr(const Register &R1, unsigned Width, unsigned Bits,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateZEXTi(const APInt &A1, unsigned Width, unsigned Bits,
+ APInt &Result);
+ bool evaluateSEXTr(const Register &R1, unsigned Width, unsigned Bits,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateSEXTi(const APInt &A1, unsigned Width, unsigned Bits,
+ APInt &Result);
+
+ // Leading/trailing bits.
+ bool evaluateCLBr(const Register &R1, bool Zeros, bool Ones,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateCLBi(const APInt &A1, bool Zeros, bool Ones, APInt &Result);
+ bool evaluateCTBr(const Register &R1, bool Zeros, bool Ones,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateCTBi(const APInt &A1, bool Zeros, bool Ones, APInt &Result);
+
+ // Bitfield extract.
+ bool evaluateEXTRACTr(const Register &R1, unsigned Width, unsigned Bits,
+ unsigned Offset, bool Signed, const CellMap &Inputs,
+ LatticeCell &Result);
+ bool evaluateEXTRACTi(const APInt &A1, unsigned Bits, unsigned Offset,
+ bool Signed, APInt &Result);
+ // Vector operations.
+ bool evaluateSplatr(const Register &R1, unsigned Bits, unsigned Count,
+ const CellMap &Inputs, LatticeCell &Result);
+ bool evaluateSplati(const APInt &A1, unsigned Bits, unsigned Count,
+ APInt &Result);
+ };
+
+} // end anonymous namespace
+
+uint32_t ConstantProperties::deduce(const Constant *C) {
+ if (isa<ConstantInt>(C)) {
+ const ConstantInt *CI = cast<ConstantInt>(C);
+ if (CI->isZero())
+ return Zero | PosOrZero | NegOrZero | Finite;
+ uint32_t Props = (NonZero | Finite);
+ if (CI->isNegative())
+ return Props | NegOrZero;
+ return Props | PosOrZero;
+ }
+
+ if (isa<ConstantFP>(C)) {
+ const ConstantFP *CF = cast<ConstantFP>(C);
+ uint32_t Props = CF->isNegative() ? (NegOrZero|NonZero)
+ : PosOrZero;
+ if (CF->isZero())
+ return (Props & ~NumericProperties) | (Zero|Finite);
+ Props = (Props & ~NumericProperties) | NonZero;
+ if (CF->isNaN())
+ return (Props & ~NumericProperties) | NaN;
+ const APFloat &Val = CF->getValueAPF();
+ if (Val.isInfinity())
+ return (Props & ~NumericProperties) | Infinity;
+ Props |= Finite;
+ return Props;
+ }
+
+ return Unknown;
+}
+
+// Convert a cell from a set of specific values to a cell that tracks
+// properties.
+bool LatticeCell::convertToProperty() {
+ if (isProperty())
+ return false;
+ // Corner case: converting a fresh (top) cell to "special".
+ // This can happen, when adding a property to a top cell.
+ uint32_t Everything = ConstantProperties::Everything;
+ uint32_t Ps = !isTop() ? properties()
+ : Everything;
+ if (Ps != ConstantProperties::Unknown) {
+ Properties = Ps;
+ setProperty();
+ } else {
+ setBottom();
+ }
+ return true;
+}
+
+void LatticeCell::print(raw_ostream &os) const {
+ if (isProperty()) {
+ os << "{ ";
+ uint32_t Ps = properties();
+ if (Ps & ConstantProperties::Zero)
+ os << "zero ";
+ if (Ps & ConstantProperties::NonZero)
+ os << "nonzero ";
+ if (Ps & ConstantProperties::Finite)
+ os << "finite ";
+ if (Ps & ConstantProperties::Infinity)
+ os << "infinity ";
+ if (Ps & ConstantProperties::NaN)
+ os << "nan ";
+ if (Ps & ConstantProperties::PosOrZero)
+ os << "poz ";
+ if (Ps & ConstantProperties::NegOrZero)
+ os << "nez ";
+ os << '}';
+ return;
+ }
+
+ os << "{ ";
+ if (isBottom()) {
+ os << "bottom";
+ } else if (isTop()) {
+ os << "top";
+ } else {
+ for (unsigned i = 0; i < size(); ++i) {
+ const Constant *C = Values[i];
+ if (i != 0)
+ os << ", ";
+ C->print(os);
+ }
+ }
+ os << " }";
+}
+
+// "Meet" operation on two cells. This is the key of the propagation
+// algorithm.
+bool LatticeCell::meet(const LatticeCell &L) {
+ bool Changed = false;
+ if (L.isBottom())
+ Changed = setBottom();
+ if (isBottom() || L.isTop())
+ return Changed;
+ if (isTop()) {
+ *this = L;
+ // L can be neither Top nor Bottom, so *this must have changed.
+ return true;
+ }
+
+ // Top/bottom cases covered. Need to integrate L's set into ours.
+ if (L.isProperty())
+ return add(L.properties());
+ for (unsigned i = 0; i < L.size(); ++i) {
+ const Constant *LC = L.Values[i];
+ Changed |= add(LC);
+ }
+ return Changed;
+}
+
+// Add a new constant to the cell. This is actually where the cell update
+// happens. If a cell has room for more constants, the new constant is added.
+// Otherwise, the cell is converted to a "property" cell (i.e. a cell that
+// will track properties of the associated values, and not the values
+// themselves. Care is taken to handle special cases, like "bottom", etc.
+bool LatticeCell::add(const Constant *LC) {
+ assert(LC);
+ if (isBottom())
+ return false;
+
+ if (!isProperty()) {
+ // Cell is not special. Try to add the constant here first,
+ // if there is room.
+ unsigned Index = 0;
+ while (Index < Size) {
+ const Constant *C = Values[Index];
+ // If the constant is already here, no change is needed.
+ if (C == LC)
+ return false;
+ Index++;
+ }
+ if (Index < MaxCellSize) {
+ Values[Index] = LC;
+ Kind = Normal;
+ Size++;
+ return true;
+ }
+ }
+
+ bool Changed = false;
+
+ // This cell is special, or is not special, but is full. After this
+ // it will be special.
+ Changed = convertToProperty();
+ uint32_t Ps = properties();
+ uint32_t NewPs = Ps & ConstantProperties::deduce(LC);
+ if (NewPs == ConstantProperties::Unknown) {
+ setBottom();
+ return true;
+ }
+ if (Ps != NewPs) {
+ Properties = NewPs;
+ Changed = true;
+ }
+ return Changed;
+}
+
+// Add a property to the cell. This will force the cell to become a property-
+// tracking cell.
+bool LatticeCell::add(uint32_t Property) {
+ bool Changed = convertToProperty();
+ uint32_t Ps = properties();
+ if (Ps == (Ps & Property))
+ return Changed;
+ Properties = Property & Ps;
+ return true;
+}
+
+// Return the properties of the values in the cell. This is valid for any
+// cell, and does not alter the cell itself.
+uint32_t LatticeCell::properties() const {
+ if (isProperty())
+ return Properties;
+ assert(!isTop() && "Should not call this for a top cell");
+ if (isBottom())
+ return ConstantProperties::Unknown;
+
+ assert(size() > 0 && "Empty cell");
+ uint32_t Ps = ConstantProperties::deduce(Values[0]);
+ for (unsigned i = 1; i < size(); ++i) {
+ if (Ps == ConstantProperties::Unknown)
+ break;
+ Ps &= ConstantProperties::deduce(Values[i]);
+ }
+ return Ps;
+}
+
+void MachineConstPropagator::CellMap::print(raw_ostream &os,
+ const TargetRegisterInfo &TRI) const {
+ for (auto &I : Map)
+ dbgs() << " " << PrintReg(I.first, &TRI) << " -> " << I.second << '\n';
+}
+
+void MachineConstPropagator::visitPHI(const MachineInstr &PN) {
+ const MachineBasicBlock *MB = PN.getParent();
+ unsigned MBN = MB->getNumber();
+ DEBUG(dbgs() << "Visiting FI(BB#" << MBN << "): " << PN);
+
+ const MachineOperand &MD = PN.getOperand(0);
+ Register DefR(MD);
+ assert(TargetRegisterInfo::isVirtualRegister(DefR.Reg));
+
+ bool Changed = false;
+
+ // If the def has a sub-register, set the corresponding cell to "bottom".
+ if (DefR.SubReg) {
+Bottomize:
+ const LatticeCell &T = Cells.get(DefR.Reg);
+ Changed = !T.isBottom();
+ Cells.update(DefR.Reg, Bottom);
+ if (Changed)
+ visitUsesOf(DefR.Reg);
+ return;
+ }
+
+ LatticeCell DefC = Cells.get(DefR.Reg);
+
+ for (unsigned i = 1, n = PN.getNumOperands(); i < n; i += 2) {
+ const MachineBasicBlock *PB = PN.getOperand(i+1).getMBB();
+ unsigned PBN = PB->getNumber();
+ if (!EdgeExec.count(CFGEdge(PBN, MBN))) {
+ DEBUG(dbgs() << " edge BB#" << PBN << "->BB#" << MBN
+ << " not executable\n");
+ continue;
+ }
+ const MachineOperand &SO = PN.getOperand(i);
+ Register UseR(SO);
+ // If the input is not a virtual register, we don't really know what
+ // value it holds.
+ if (!TargetRegisterInfo::isVirtualRegister(UseR.Reg))
+ goto Bottomize;
+ // If there is no cell for an input register, it means top.
+ if (!Cells.has(UseR.Reg))
+ continue;
+
+ LatticeCell SrcC;
+ bool Eval = MCE.evaluate(UseR, Cells.get(UseR.Reg), SrcC);
+ DEBUG(dbgs() << " edge from BB#" << PBN << ": "
+ << PrintReg(UseR.Reg, &MCE.TRI, UseR.SubReg)
+ << SrcC << '\n');
+ Changed |= Eval ? DefC.meet(SrcC)
+ : DefC.setBottom();
+ Cells.update(DefR.Reg, DefC);
+ if (DefC.isBottom())
+ break;
+ }
+ if (Changed)
+ visitUsesOf(DefR.Reg);
+}
+
+void MachineConstPropagator::visitNonBranch(const MachineInstr &MI) {
+ DEBUG(dbgs() << "Visiting MI(BB#" << MI.getParent()->getNumber()
+ << "): " << MI);
+ CellMap Outputs;
+ bool Eval = MCE.evaluate(MI, Cells, Outputs);
+ DEBUG({
+ if (Eval) {
+ dbgs() << " outputs:";
+ for (auto &I : Outputs)
+ dbgs() << ' ' << I.second;
+ dbgs() << '\n';
+ }
+ });
+
+ // Update outputs. If the value was not computed, set all the
+ // def cells to bottom.
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isDef())
+ continue;
+ Register DefR(MO);
+ // Only track virtual registers.
+ if (!TargetRegisterInfo::isVirtualRegister(DefR.Reg))
+ continue;
+ bool Changed = false;
+ // If the evaluation failed, set cells for all output registers to bottom.
+ if (!Eval) {
+ const LatticeCell &T = Cells.get(DefR.Reg);
+ Changed = !T.isBottom();
+ Cells.update(DefR.Reg, Bottom);
+ } else {
+ // Find the corresponding cell in the computed outputs.
+ // If it's not there, go on to the next def.
+ if (!Outputs.has(DefR.Reg))
+ continue;
+ LatticeCell RC = Cells.get(DefR.Reg);
+ Changed = RC.meet(Outputs.get(DefR.Reg));
+ Cells.update(DefR.Reg, RC);
+ }
+ if (Changed)
+ visitUsesOf(DefR.Reg);
+ }
+}
+
+// \brief Starting at a given branch, visit remaining branches in the block.
+// Traverse over the subsequent branches for as long as the preceding one
+// can fall through. Add all the possible targets to the flow work queue,
+// including the potential fall-through to the layout-successor block.
+void MachineConstPropagator::visitBranchesFrom(const MachineInstr &BrI) {
+ const MachineBasicBlock &B = *BrI.getParent();
+ unsigned MBN = B.getNumber();
+ MachineBasicBlock::const_iterator It = BrI.getIterator();
+ MachineBasicBlock::const_iterator End = B.end();
+
+ SetVector<const MachineBasicBlock*> Targets;
+ bool EvalOk = true, FallsThru = true;
+ while (It != End) {
+ const MachineInstr &MI = *It;
+ InstrExec.insert(&MI);
+ DEBUG(dbgs() << "Visiting " << (EvalOk ? "BR" : "br") << "(BB#"
+ << MBN << "): " << MI);
+ // Do not evaluate subsequent branches if the evaluation of any of the
+ // previous branches failed. Keep iterating over the branches only
+ // to mark them as executable.
+ EvalOk = EvalOk && MCE.evaluate(MI, Cells, Targets, FallsThru);
+ if (!EvalOk)
+ FallsThru = true;
+ if (!FallsThru)
+ break;
+ ++It;
+ }
+
+ if (EvalOk) {
+ // Need to add all CFG successors that lead to EH landing pads.
+ // There won't be explicit branches to these blocks, but they must
+ // be processed.
+ for (const MachineBasicBlock *SB : B.successors()) {
+ if (SB->isEHPad())
+ Targets.insert(SB);
+ }
+ if (FallsThru) {
+ const MachineFunction &MF = *B.getParent();
+ MachineFunction::const_iterator BI = B.getIterator();
+ MachineFunction::const_iterator Next = std::next(BI);
+ if (Next != MF.end())
+ Targets.insert(&*Next);
+ }
+ } else {
+ // If the evaluation of the branches failed, make "Targets" to be the
+ // set of all successors of the block from the CFG.
+ // If the evaluation succeeded for all visited branches, then if the
+ // last one set "FallsThru", then add an edge to the layout successor
+ // to the targets.
+ Targets.clear();
+ DEBUG(dbgs() << " failed to evaluate a branch...adding all CFG "
+ "successors\n");
+ for (const MachineBasicBlock *SB : B.successors())
+ Targets.insert(SB);
+ }
+
+ for (const MachineBasicBlock *TB : Targets) {
+ unsigned TBN = TB->getNumber();
+ DEBUG(dbgs() << " pushing edge BB#" << MBN << " -> BB#" << TBN << "\n");
+ FlowQ.push(CFGEdge(MBN, TBN));
+ }
+}
+
+void MachineConstPropagator::visitUsesOf(unsigned Reg) {
+ DEBUG(dbgs() << "Visiting uses of " << PrintReg(Reg, &MCE.TRI)
+ << Cells.get(Reg) << '\n');
+ for (MachineInstr &MI : MRI->use_nodbg_instructions(Reg)) {
+ // Do not process non-executable instructions. They can become exceutable
+ // later (via a flow-edge in the work queue). In such case, the instruc-
+ // tion will be visited at that time.
+ if (!InstrExec.count(&MI))
+ continue;
+ if (MI.isPHI())
+ visitPHI(MI);
+ else if (!MI.isBranch())
+ visitNonBranch(MI);
+ else
+ visitBranchesFrom(MI);
+ }
+}
+
+bool MachineConstPropagator::computeBlockSuccessors(const MachineBasicBlock *MB,
+ SetVector<const MachineBasicBlock*> &Targets) {
+ MachineBasicBlock::const_iterator FirstBr = MB->end();
+ for (const MachineInstr &MI : *MB) {
+ if (MI.isDebugValue())
+ continue;
+ if (MI.isBranch()) {
+ FirstBr = MI.getIterator();
+ break;
+ }
+ }
+
+ Targets.clear();
+ MachineBasicBlock::const_iterator End = MB->end();
+
+ bool DoNext = true;
+ for (MachineBasicBlock::const_iterator I = FirstBr; I != End; ++I) {
+ const MachineInstr &MI = *I;
+ // Can there be debug instructions between branches?
+ if (MI.isDebugValue())
+ continue;
+ if (!InstrExec.count(&MI))
+ continue;
+ bool Eval = MCE.evaluate(MI, Cells, Targets, DoNext);
+ if (!Eval)
+ return false;
+ if (!DoNext)
+ break;
+ }
+ // If the last branch could fall-through, add block's layout successor.
+ if (DoNext) {
+ MachineFunction::const_iterator BI = MB->getIterator();
+ MachineFunction::const_iterator NextI = std::next(BI);
+ if (NextI != MB->getParent()->end())
+ Targets.insert(&*NextI);
+ }
+
+ // Add all the EH landing pads.
+ for (const MachineBasicBlock *SB : MB->successors())
+ if (SB->isEHPad())
+ Targets.insert(SB);
+
+ return true;
+}
+
+void MachineConstPropagator::removeCFGEdge(MachineBasicBlock *From,
+ MachineBasicBlock *To) {
+ // First, remove the CFG successor/predecessor information.
+ From->removeSuccessor(To);
+ // Remove all corresponding PHI operands in the To block.
+ for (auto I = To->begin(), E = To->getFirstNonPHI(); I != E; ++I) {
+ MachineInstr *PN = &*I;
+ // reg0 = PHI reg1, bb2, reg3, bb4, ...
+ int N = PN->getNumOperands()-2;
+ while (N > 0) {
+ if (PN->getOperand(N+1).getMBB() == From) {
+ PN->RemoveOperand(N+1);
+ PN->RemoveOperand(N);
+ }
+ N -= 2;
+ }
+ }
+}
+
+void MachineConstPropagator::propagate(MachineFunction &MF) {
+ MachineBasicBlock *Entry = GraphTraits<MachineFunction*>::getEntryNode(&MF);
+ unsigned EntryNum = Entry->getNumber();
+
+ // Start with a fake edge, just to process the entry node.
+ FlowQ.push(CFGEdge(EntryNum, EntryNum));
+
+ while (!FlowQ.empty()) {
+ CFGEdge Edge = FlowQ.front();
+ FlowQ.pop();
+
+ DEBUG(dbgs() << "Picked edge BB#" << Edge.first << "->BB#"
+ << Edge.second << '\n');
+ if (Edge.first != EntryNum)
+ if (EdgeExec.count(Edge))
+ continue;
+ EdgeExec.insert(Edge);
+ MachineBasicBlock *SB = MF.getBlockNumbered(Edge.second);
+
+ // Process the block in three stages:
+ // - visit all PHI nodes,
+ // - visit all non-branch instructions,
+ // - visit block branches.
+ MachineBasicBlock::const_iterator It = SB->begin(), End = SB->end();
+
+ // Visit PHI nodes in the successor block.
+ while (It != End && It->isPHI()) {
+ InstrExec.insert(&*It);
+ visitPHI(*It);
+ ++It;
+ }
+
+ // If the successor block just became executable, visit all instructions.
+ // To see if this is the first time we're visiting it, check the first
+ // non-debug instruction to see if it is executable.
+ while (It != End && It->isDebugValue())
+ ++It;
+ assert(It == End || !It->isPHI());
+ // If this block has been visited, go on to the next one.
+ if (It != End && InstrExec.count(&*It))
+ continue;
+ // For now, scan all non-branch instructions. Branches require different
+ // processing.
+ while (It != End && !It->isBranch()) {
+ if (!It->isDebugValue()) {
+ InstrExec.insert(&*It);
+ visitNonBranch(*It);
+ }
+ ++It;
+ }
+
+ // Time to process the end of the block. This is different from
+ // processing regular (non-branch) instructions, because there can
+ // be multiple branches in a block, and they can cause the block to
+ // terminate early.
+ if (It != End) {
+ visitBranchesFrom(*It);
+ } else {
+ // If the block didn't have a branch, add all successor edges to the
+ // work queue. (There should really be only one successor in such case.)
+ unsigned SBN = SB->getNumber();
+ for (const MachineBasicBlock *SSB : SB->successors())
+ FlowQ.push(CFGEdge(SBN, SSB->getNumber()));
+ }
+ } // while (FlowQ)
+
+ DEBUG({
+ dbgs() << "Cells after propagation:\n";
+ Cells.print(dbgs(), MCE.TRI);
+ dbgs() << "Dead CFG edges:\n";
+ for (const MachineBasicBlock &B : MF) {
+ unsigned BN = B.getNumber();
+ for (const MachineBasicBlock *SB : B.successors()) {
+ unsigned SN = SB->getNumber();
+ if (!EdgeExec.count(CFGEdge(BN, SN)))
+ dbgs() << " BB#" << BN << " -> BB#" << SN << '\n';
+ }
+ }
+ });
+}
+
+bool MachineConstPropagator::rewrite(MachineFunction &MF) {
+ bool Changed = false;
+ // Rewrite all instructions based on the collected cell information.
+ //
+ // Traverse the instructions in a post-order, so that rewriting an
+ // instruction can make changes "downstream" in terms of control-flow
+ // without affecting the rewriting process. (We should not change
+ // instructions that have not yet been visited by the rewriter.)
+ // The reason for this is that the rewriter can introduce new vregs,
+ // and replace uses of old vregs (which had corresponding cells
+ // computed during propagation) with these new vregs (which at this
+ // point would not have any cells, and would appear to be "top").
+ // If an attempt was made to evaluate an instruction with a fresh
+ // "top" vreg, it would cause an error (abend) in the evaluator.
+
+ // Collect the post-order-traversal block ordering. The subsequent
+ // traversal/rewrite will update block successors, so it's safer
+ // if the visiting order it computed ahead of time.
+ std::vector<MachineBasicBlock*> POT;
+ for (MachineBasicBlock *B : post_order(&MF))
+ if (!B->empty())
+ POT.push_back(B);
+
+ for (MachineBasicBlock *B : POT) {
+ // Walk the block backwards (which usually begin with the branches).
+ // If any branch is rewritten, we may need to update the successor
+ // information for this block. Unless the block's successors can be
+ // precisely determined (which may not be the case for indirect
+ // branches), we cannot modify any branch.
+
+ // Compute the successor information.
+ SetVector<const MachineBasicBlock*> Targets;
+ bool HaveTargets = computeBlockSuccessors(B, Targets);
+ // Rewrite the executable instructions. Skip branches if we don't
+ // have block successor information.
+ for (auto I = B->rbegin(), E = B->rend(); I != E; ++I) {
+ MachineInstr &MI = *I;
+ if (InstrExec.count(&MI)) {
+ if (MI.isBranch() && !HaveTargets)
+ continue;
+ Changed |= MCE.rewrite(MI, Cells);
+ }
+ }
+ // The rewriting could rewrite PHI nodes to non-PHI nodes, causing
+ // regular instructions to appear in between PHI nodes. Bring all
+ // the PHI nodes to the beginning of the block.
+ for (auto I = B->begin(), E = B->end(); I != E; ++I) {
+ if (I->isPHI())
+ continue;
+ // I is not PHI. Find the next PHI node P.
+ auto P = I;
+ while (++P != E)
+ if (P->isPHI())
+ break;
+ // Not found.
+ if (P == E)
+ break;
+ // Splice P right before I.
+ B->splice(I, B, P);
+ // Reset I to point at the just spliced PHI node.
+ --I;
+ }
+ // Update the block successor information: remove unnecessary successors.
+ if (HaveTargets) {
+ SmallVector<MachineBasicBlock*,2> ToRemove;
+ for (MachineBasicBlock *SB : B->successors()) {
+ if (!Targets.count(SB))
+ ToRemove.push_back(const_cast<MachineBasicBlock*>(SB));
+ Targets.remove(SB);
+ }
+ for (unsigned i = 0, n = ToRemove.size(); i < n; ++i)
+ removeCFGEdge(B, ToRemove[i]);
+ // If there are any blocks left in the computed targets, it means that
+ // we think that the block could go somewhere, but the CFG does not.
+ // This could legitimately happen in blocks that have non-returning
+ // calls---we would think that the execution can continue, but the
+ // CFG will not have a successor edge.
+ }
+ }
+ // Need to do some final post-processing.
+ // If a branch was not executable, it will not get rewritten, but should
+ // be removed (or replaced with something equivalent to a A2_nop). We can't
+ // erase instructions during rewriting, so this needs to be delayed until
+ // now.
+ for (MachineBasicBlock &B : MF) {
+ MachineBasicBlock::iterator I = B.begin(), E = B.end();
+ while (I != E) {
+ auto Next = std::next(I);
+ if (I->isBranch() && !InstrExec.count(&*I))
+ B.erase(I);
+ I = Next;
+ }
+ }
+ return Changed;
+}
+
+// This is the constant propagation algorithm as described by Wegman-Zadeck.
+// Most of the terminology comes from there.
+bool MachineConstPropagator::run(MachineFunction &MF) {
+ DEBUG(MF.print(dbgs() << "Starting MachineConstPropagator\n", 0));
+
+ MRI = &MF.getRegInfo();
+
+ Cells.clear();
+ EdgeExec.clear();
+ InstrExec.clear();
+ assert(FlowQ.empty());
+
+ propagate(MF);
+ bool Changed = rewrite(MF);
+
+ DEBUG({
+ dbgs() << "End of MachineConstPropagator (Changed=" << Changed << ")\n";
+ if (Changed)
+ MF.print(dbgs(), 0);
+ });
+ return Changed;
+}
+
+// --------------------------------------------------------------------
+// Machine const evaluator.
+
+bool MachineConstEvaluator::getCell(const Register &R, const CellMap &Inputs,
+ LatticeCell &RC) {
+ if (!TargetRegisterInfo::isVirtualRegister(R.Reg))
+ return false;
+ const LatticeCell &L = Inputs.get(R.Reg);
+ if (!R.SubReg) {
+ RC = L;
+ return !RC.isBottom();
+ }
+ bool Eval = evaluate(R, L, RC);
+ return Eval && !RC.isBottom();
+}
+
+bool MachineConstEvaluator::constToInt(const Constant *C,
+ APInt &Val) const {
+ const ConstantInt *CI = dyn_cast<ConstantInt>(C);
+ if (!CI)
+ return false;
+ Val = CI->getValue();
+ return true;
+}
+
+const ConstantInt *MachineConstEvaluator::intToConst(const APInt &Val) const {
+ return ConstantInt::get(CX, Val);
+}
+
+bool MachineConstEvaluator::evaluateCMPrr(uint32_t Cmp, const Register &R1,
+ const Register &R2, const CellMap &Inputs, bool &Result) {
+ assert(Inputs.has(R1.Reg) && Inputs.has(R2.Reg));
+ LatticeCell LS1, LS2;
+ if (!getCell(R1, Inputs, LS1) || !getCell(R2, Inputs, LS2))
+ return false;
+
+ bool IsProp1 = LS1.isProperty();
+ bool IsProp2 = LS2.isProperty();
+ if (IsProp1) {
+ uint32_t Prop1 = LS1.properties();
+ if (IsProp2)
+ return evaluateCMPpp(Cmp, Prop1, LS2.properties(), Result);
+ uint32_t NegCmp = Comparison::negate(Cmp);
+ return evaluateCMPrp(NegCmp, R2, Prop1, Inputs, Result);
+ }
+ if (IsProp2) {
+ uint32_t Prop2 = LS2.properties();
+ return evaluateCMPrp(Cmp, R1, Prop2, Inputs, Result);
+ }
+
+ APInt A;
+ bool IsTrue = true, IsFalse = true;
+ for (unsigned i = 0; i < LS2.size(); ++i) {
+ bool Res;
+ bool Computed = constToInt(LS2.Values[i], A) &&
+ evaluateCMPri(Cmp, R1, A, Inputs, Res);
+ if (!Computed)
+ return false;
+ IsTrue &= Res;
+ IsFalse &= !Res;
+ }
+ assert(!IsTrue || !IsFalse);
+ // The actual logical value of the comparison is same as IsTrue.
+ Result = IsTrue;
+ // Return true if the result was proven to be true or proven to be false.
+ return IsTrue || IsFalse;
+}
+
+bool MachineConstEvaluator::evaluateCMPri(uint32_t Cmp, const Register &R1,
+ const APInt &A2, const CellMap &Inputs, bool &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS;
+ if (!getCell(R1, Inputs, LS))
+ return false;
+ if (LS.isProperty())
+ return evaluateCMPpi(Cmp, LS.properties(), A2, Result);
+
+ APInt A;
+ bool IsTrue = true, IsFalse = true;
+ for (unsigned i = 0; i < LS.size(); ++i) {
+ bool Res;
+ bool Computed = constToInt(LS.Values[i], A) &&
+ evaluateCMPii(Cmp, A, A2, Res);
+ if (!Computed)
+ return false;
+ IsTrue &= Res;
+ IsFalse &= !Res;
+ }
+ assert(!IsTrue || !IsFalse);
+ // The actual logical value of the comparison is same as IsTrue.
+ Result = IsTrue;
+ // Return true if the result was proven to be true or proven to be false.
+ return IsTrue || IsFalse;
+}
+
+bool MachineConstEvaluator::evaluateCMPrp(uint32_t Cmp, const Register &R1,
+ uint64_t Props2, const CellMap &Inputs, bool &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS;
+ if (!getCell(R1, Inputs, LS))
+ return false;
+ if (LS.isProperty())
+ return evaluateCMPpp(Cmp, LS.properties(), Props2, Result);
+
+ APInt A;
+ uint32_t NegCmp = Comparison::negate(Cmp);
+ bool IsTrue = true, IsFalse = true;
+ for (unsigned i = 0; i < LS.size(); ++i) {
+ bool Res;
+ bool Computed = constToInt(LS.Values[i], A) &&
+ evaluateCMPpi(NegCmp, Props2, A, Res);
+ if (!Computed)
+ return false;
+ IsTrue &= Res;
+ IsFalse &= !Res;
+ }
+ assert(!IsTrue || !IsFalse);
+ Result = IsTrue;
+ return IsTrue || IsFalse;
+}
+
+bool MachineConstEvaluator::evaluateCMPii(uint32_t Cmp, const APInt &A1,
+ const APInt &A2, bool &Result) {
+ // NE is a special kind of comparison (not composed of smaller properties).
+ if (Cmp == Comparison::NE) {
+ Result = !APInt::isSameValue(A1, A2);
+ return true;
+ }
+ if (Cmp == Comparison::EQ) {
+ Result = APInt::isSameValue(A1, A2);
+ return true;
+ }
+ if (Cmp & Comparison::EQ) {
+ if (APInt::isSameValue(A1, A2))
+ return (Result = true);
+ }
+ assert((Cmp & (Comparison::L | Comparison::G)) && "Malformed comparison");
+ Result = false;
+
+ unsigned W1 = A1.getBitWidth();
+ unsigned W2 = A2.getBitWidth();
+ unsigned MaxW = (W1 >= W2) ? W1 : W2;
+ if (Cmp & Comparison::U) {
+ const APInt Zx1 = A1.zextOrSelf(MaxW);
+ const APInt Zx2 = A2.zextOrSelf(MaxW);
+ if (Cmp & Comparison::L)
+ Result = Zx1.ult(Zx2);
+ else if (Cmp & Comparison::G)
+ Result = Zx2.ult(Zx1);
+ return true;
+ }
+
+ // Signed comparison.
+ const APInt Sx1 = A1.sextOrSelf(MaxW);
+ const APInt Sx2 = A2.sextOrSelf(MaxW);
+ if (Cmp & Comparison::L)
+ Result = Sx1.slt(Sx2);
+ else if (Cmp & Comparison::G)
+ Result = Sx2.slt(Sx1);
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateCMPpi(uint32_t Cmp, uint32_t Props,
+ const APInt &A2, bool &Result) {
+ if (Props == ConstantProperties::Unknown)
+ return false;
+
+ // Should never see NaN here, but check for it for completeness.
+ if (Props & ConstantProperties::NaN)
+ return false;
+ // Infinity could theoretically be compared to a number, but the
+ // presence of infinity here would be very suspicious. If we don't
+ // know for sure that the number is finite, bail out.
+ if (!(Props & ConstantProperties::Finite))
+ return false;
+
+ // Let X be a number that has properties Props.
+
+ if (Cmp & Comparison::U) {
+ // In case of unsigned comparisons, we can only compare against 0.
+ if (A2 == 0) {
+ // Any x!=0 will be considered >0 in an unsigned comparison.
+ if (Props & ConstantProperties::Zero)
+ Result = (Cmp & Comparison::EQ);
+ else if (Props & ConstantProperties::NonZero)
+ Result = (Cmp & Comparison::G) || (Cmp == Comparison::NE);
+ else
+ return false;
+ return true;
+ }
+ // A2 is not zero. The only handled case is if X = 0.
+ if (Props & ConstantProperties::Zero) {
+ Result = (Cmp & Comparison::L) || (Cmp == Comparison::NE);
+ return true;
+ }
+ return false;
+ }
+
+ // Signed comparisons are different.
+ if (Props & ConstantProperties::Zero) {
+ if (A2 == 0)
+ Result = (Cmp & Comparison::EQ);
+ else
+ Result = (Cmp == Comparison::NE) ||
+ ((Cmp & Comparison::L) && !A2.isNegative()) ||
+ ((Cmp & Comparison::G) && A2.isNegative());
+ return true;
+ }
+ if (Props & ConstantProperties::PosOrZero) {
+ // X >= 0 and !(A2 < 0) => cannot compare
+ if (!A2.isNegative())
+ return false;
+ // X >= 0 and A2 < 0
+ Result = (Cmp & Comparison::G) || (Cmp == Comparison::NE);
+ return true;
+ }
+ if (Props & ConstantProperties::NegOrZero) {
+ // X <= 0 and Src1 < 0 => cannot compare
+ if (A2 == 0 || A2.isNegative())
+ return false;
+ // X <= 0 and A2 > 0
+ Result = (Cmp & Comparison::L) || (Cmp == Comparison::NE);
+ return true;
+ }
+
+ return false;
+}
+
+bool MachineConstEvaluator::evaluateCMPpp(uint32_t Cmp, uint32_t Props1,
+ uint32_t Props2, bool &Result) {
+ typedef ConstantProperties P;
+ if ((Props1 & P::NaN) && (Props2 & P::NaN))
+ return false;
+ if (!(Props1 & P::Finite) || !(Props2 & P::Finite))
+ return false;
+
+ bool Zero1 = (Props1 & P::Zero), Zero2 = (Props2 & P::Zero);
+ bool NonZero1 = (Props1 & P::NonZero), NonZero2 = (Props2 & P::NonZero);
+ if (Zero1 && Zero2) {
+ Result = (Cmp & Comparison::EQ);
+ return true;
+ }
+ if (Cmp == Comparison::NE) {
+ if ((Zero1 && NonZero2) || (NonZero1 && Zero2))
+ return (Result = true);
+ return false;
+ }
+
+ if (Cmp & Comparison::U) {
+ // In unsigned comparisons, we can only compare against a known zero,
+ // or a known non-zero.
+ if (Zero1 && NonZero2) {
+ Result = (Cmp & Comparison::L);
+ return true;
+ }
+ if (NonZero1 && Zero2) {
+ Result = (Cmp & Comparison::G);
+ return true;
+ }
+ return false;
+ }
+
+ // Signed comparison. The comparison is not NE.
+ bool Poz1 = (Props1 & P::PosOrZero), Poz2 = (Props2 & P::PosOrZero);
+ bool Nez1 = (Props1 & P::NegOrZero), Nez2 = (Props2 & P::NegOrZero);
+ if (Nez1 && Poz2) {
+ if (NonZero1 || NonZero2) {
+ Result = (Cmp & Comparison::L);
+ return true;
+ }
+ // Either (or both) could be zero. Can only say that X <= Y.
+ if ((Cmp & Comparison::EQ) && (Cmp & Comparison::L))
+ return (Result = true);
+ }
+ if (Poz1 && Nez2) {
+ if (NonZero1 || NonZero2) {
+ Result = (Cmp & Comparison::G);
+ return true;
+ }
+ // Either (or both) could be zero. Can only say that X >= Y.
+ if ((Cmp & Comparison::EQ) && (Cmp & Comparison::G))
+ return (Result = true);
+ }
+
+ return false;
+}
+
+bool MachineConstEvaluator::evaluateCOPY(const Register &R1,
+ const CellMap &Inputs, LatticeCell &Result) {
+ return getCell(R1, Inputs, Result);
+}
+
+bool MachineConstEvaluator::evaluateANDrr(const Register &R1,
+ const Register &R2, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg) && Inputs.has(R2.Reg));
+ const LatticeCell &L1 = Inputs.get(R2.Reg);
+ const LatticeCell &L2 = Inputs.get(R2.Reg);
+ // If both sources are bottom, exit. Otherwise try to evaluate ANDri
+ // with the non-bottom argument passed as the immediate. This is to
+ // catch cases of ANDing with 0.
+ if (L2.isBottom()) {
+ if (L1.isBottom())
+ return false;
+ return evaluateANDrr(R2, R1, Inputs, Result);
+ }
+ LatticeCell LS2;
+ if (!evaluate(R2, L2, LS2))
+ return false;
+ if (LS2.isBottom() || LS2.isProperty())
+ return false;
+
+ APInt A;
+ for (unsigned i = 0; i < LS2.size(); ++i) {
+ LatticeCell RC;
+ bool Eval = constToInt(LS2.Values[i], A) &&
+ evaluateANDri(R1, A, Inputs, RC);
+ if (!Eval)
+ return false;
+ Result.meet(RC);
+ }
+ return !Result.isBottom();
+}
+
+bool MachineConstEvaluator::evaluateANDri(const Register &R1,
+ const APInt &A2, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ if (A2 == -1)
+ return getCell(R1, Inputs, Result);
+ if (A2 == 0) {
+ LatticeCell RC;
+ RC.add(intToConst(A2));
+ // Overwrite Result.
+ Result = RC;
+ return true;
+ }
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom() || LS1.isProperty())
+ return false;
+
+ APInt A, ResA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateANDii(A, A2, ResA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(ResA);
+ Result.add(C);
+ }
+ return !Result.isBottom();
+}
+
+bool MachineConstEvaluator::evaluateANDii(const APInt &A1,
+ const APInt &A2, APInt &Result) {
+ Result = A1 & A2;
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateORrr(const Register &R1,
+ const Register &R2, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg) && Inputs.has(R2.Reg));
+ const LatticeCell &L1 = Inputs.get(R2.Reg);
+ const LatticeCell &L2 = Inputs.get(R2.Reg);
+ // If both sources are bottom, exit. Otherwise try to evaluate ORri
+ // with the non-bottom argument passed as the immediate. This is to
+ // catch cases of ORing with -1.
+ if (L2.isBottom()) {
+ if (L1.isBottom())
+ return false;
+ return evaluateORrr(R2, R1, Inputs, Result);
+ }
+ LatticeCell LS2;
+ if (!evaluate(R2, L2, LS2))
+ return false;
+ if (LS2.isBottom() || LS2.isProperty())
+ return false;
+
+ APInt A;
+ for (unsigned i = 0; i < LS2.size(); ++i) {
+ LatticeCell RC;
+ bool Eval = constToInt(LS2.Values[i], A) &&
+ evaluateORri(R1, A, Inputs, RC);
+ if (!Eval)
+ return false;
+ Result.meet(RC);
+ }
+ return !Result.isBottom();
+}
+
+bool MachineConstEvaluator::evaluateORri(const Register &R1,
+ const APInt &A2, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ if (A2 == 0)
+ return getCell(R1, Inputs, Result);
+ if (A2 == -1) {
+ LatticeCell RC;
+ RC.add(intToConst(A2));
+ // Overwrite Result.
+ Result = RC;
+ return true;
+ }
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom() || LS1.isProperty())
+ return false;
+
+ APInt A, ResA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateORii(A, A2, ResA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(ResA);
+ Result.add(C);
+ }
+ return !Result.isBottom();
+}
+
+bool MachineConstEvaluator::evaluateORii(const APInt &A1,
+ const APInt &A2, APInt &Result) {
+ Result = A1 | A2;
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateXORrr(const Register &R1,
+ const Register &R2, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg) && Inputs.has(R2.Reg));
+ LatticeCell LS1, LS2;
+ if (!getCell(R1, Inputs, LS1) || !getCell(R2, Inputs, LS2))
+ return false;
+ if (LS1.isProperty()) {
+ if (LS1.properties() & ConstantProperties::Zero)
+ return !(Result = LS2).isBottom();
+ return false;
+ }
+ if (LS2.isProperty()) {
+ if (LS2.properties() & ConstantProperties::Zero)
+ return !(Result = LS1).isBottom();
+ return false;
+ }
+
+ APInt A;
+ for (unsigned i = 0; i < LS2.size(); ++i) {
+ LatticeCell RC;
+ bool Eval = constToInt(LS2.Values[i], A) &&
+ evaluateXORri(R1, A, Inputs, RC);
+ if (!Eval)
+ return false;
+ Result.meet(RC);
+ }
+ return !Result.isBottom();
+}
+
+bool MachineConstEvaluator::evaluateXORri(const Register &R1,
+ const APInt &A2, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isProperty()) {
+ if (LS1.properties() & ConstantProperties::Zero) {
+ const Constant *C = intToConst(A2);
+ Result.add(C);
+ return !Result.isBottom();
+ }
+ return false;
+ }
+
+ APInt A, XA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateXORii(A, A2, XA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(XA);
+ Result.add(C);
+ }
+ return !Result.isBottom();
+}
+
+bool MachineConstEvaluator::evaluateXORii(const APInt &A1,
+ const APInt &A2, APInt &Result) {
+ Result = A1 ^ A2;
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateZEXTr(const Register &R1, unsigned Width,
+ unsigned Bits, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isProperty())
+ return false;
+
+ APInt A, XA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateZEXTi(A, Width, Bits, XA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(XA);
+ Result.add(C);
+ }
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateZEXTi(const APInt &A1, unsigned Width,
+ unsigned Bits, APInt &Result) {
+ unsigned BW = A1.getBitWidth();
+ (void)BW;
+ assert(Width >= Bits && BW >= Bits);
+ APInt Mask = APInt::getLowBitsSet(Width, Bits);
+ Result = A1.zextOrTrunc(Width) & Mask;
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateSEXTr(const Register &R1, unsigned Width,
+ unsigned Bits, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom() || LS1.isProperty())
+ return false;
+
+ APInt A, XA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateSEXTi(A, Width, Bits, XA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(XA);
+ Result.add(C);
+ }
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateSEXTi(const APInt &A1, unsigned Width,
+ unsigned Bits, APInt &Result) {
+ unsigned BW = A1.getBitWidth();
+ assert(Width >= Bits && BW >= Bits);
+ // Special case to make things faster for smaller source widths.
+ // Sign extension of 0 bits generates 0 as a result. This is consistent
+ // with what the HW does.
+ if (Bits == 0) {
+ Result = APInt(Width, 0);
+ return true;
+ }
+ // In C, shifts by 64 invoke undefined behavior: handle that case in APInt.
+ if (BW <= 64 && Bits != 0) {
+ int64_t V = A1.getSExtValue();
+ switch (Bits) {
+ case 8:
+ V = static_cast<int8_t>(V);
+ break;
+ case 16:
+ V = static_cast<int16_t>(V);
+ break;
+ case 32:
+ V = static_cast<int32_t>(V);
+ break;
+ default:
+ // Shift left to lose all bits except lower "Bits" bits, then shift
+ // the value back, replicating what was a sign bit after the first
+ // shift.
+ V = (V << (64-Bits)) >> (64-Bits);
+ break;
+ }
+ // V is a 64-bit sign-extended value. Convert it to APInt of desired
+ // width.
+ Result = APInt(Width, V, true);
+ return true;
+ }
+ // Slow case: the value doesn't fit in int64_t.
+ if (Bits < BW)
+ Result = A1.trunc(Bits).sext(Width);
+ else // Bits == BW
+ Result = A1.sext(Width);
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateCLBr(const Register &R1, bool Zeros,
+ bool Ones, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom() || LS1.isProperty())
+ return false;
+
+ APInt A, CA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateCLBi(A, Zeros, Ones, CA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(CA);
+ Result.add(C);
+ }
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateCLBi(const APInt &A1, bool Zeros,
+ bool Ones, APInt &Result) {
+ unsigned BW = A1.getBitWidth();
+ if (!Zeros && !Ones)
+ return false;
+ unsigned Count = 0;
+ if (Zeros && (Count == 0))
+ Count = A1.countLeadingZeros();
+ if (Ones && (Count == 0))
+ Count = A1.countLeadingOnes();
+ Result = APInt(BW, static_cast<uint64_t>(Count), false);
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateCTBr(const Register &R1, bool Zeros,
+ bool Ones, const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom() || LS1.isProperty())
+ return false;
+
+ APInt A, CA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateCTBi(A, Zeros, Ones, CA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(CA);
+ Result.add(C);
+ }
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateCTBi(const APInt &A1, bool Zeros,
+ bool Ones, APInt &Result) {
+ unsigned BW = A1.getBitWidth();
+ if (!Zeros && !Ones)
+ return false;
+ unsigned Count = 0;
+ if (Zeros && (Count == 0))
+ Count = A1.countTrailingZeros();
+ if (Ones && (Count == 0))
+ Count = A1.countTrailingOnes();
+ Result = APInt(BW, static_cast<uint64_t>(Count), false);
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateEXTRACTr(const Register &R1,
+ unsigned Width, unsigned Bits, unsigned Offset, bool Signed,
+ const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ assert(Bits+Offset <= Width);
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom())
+ return false;
+ if (LS1.isProperty()) {
+ uint32_t Ps = LS1.properties();
+ if (Ps & ConstantProperties::Zero) {
+ const Constant *C = intToConst(APInt(Width, 0, false));
+ Result.add(C);
+ return true;
+ }
+ return false;
+ }
+
+ APInt A, CA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateEXTRACTi(A, Bits, Offset, Signed, CA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(CA);
+ Result.add(C);
+ }
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateEXTRACTi(const APInt &A1, unsigned Bits,
+ unsigned Offset, bool Signed, APInt &Result) {
+ unsigned BW = A1.getBitWidth();
+ assert(Bits+Offset <= BW);
+ // Extracting 0 bits generates 0 as a result (as indicated by the HW people).
+ if (Bits == 0) {
+ Result = APInt(BW, 0);
+ return true;
+ }
+ if (BW <= 64) {
+ int64_t V = A1.getZExtValue();
+ V <<= (64-Bits-Offset);
+ if (Signed)
+ V >>= (64-Bits);
+ else
+ V = static_cast<uint64_t>(V) >> (64-Bits);
+ Result = APInt(BW, V, Signed);
+ return true;
+ }
+ if (Signed)
+ Result = A1.shl(BW-Bits-Offset).ashr(BW-Bits);
+ else
+ Result = A1.shl(BW-Bits-Offset).lshr(BW-Bits);
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateSplatr(const Register &R1,
+ unsigned Bits, unsigned Count, const CellMap &Inputs,
+ LatticeCell &Result) {
+ assert(Inputs.has(R1.Reg));
+ LatticeCell LS1;
+ if (!getCell(R1, Inputs, LS1))
+ return false;
+ if (LS1.isBottom() || LS1.isProperty())
+ return false;
+
+ APInt A, SA;
+ for (unsigned i = 0; i < LS1.size(); ++i) {
+ bool Eval = constToInt(LS1.Values[i], A) &&
+ evaluateSplati(A, Bits, Count, SA);
+ if (!Eval)
+ return false;
+ const Constant *C = intToConst(SA);
+ Result.add(C);
+ }
+ return true;
+}
+
+bool MachineConstEvaluator::evaluateSplati(const APInt &A1, unsigned Bits,
+ unsigned Count, APInt &Result) {
+ assert(Count > 0);
+ unsigned BW = A1.getBitWidth(), SW = Count*Bits;
+ APInt LoBits = (Bits < BW) ? A1.trunc(Bits) : A1.zextOrSelf(Bits);
+ if (Count > 1)
+ LoBits = LoBits.zext(SW);
+
+ APInt Res(SW, 0, false);
+ for (unsigned i = 0; i < Count; ++i) {
+ Res <<= Bits;
+ Res |= LoBits;
+ }
+ Result = Res;
+ return true;
+}
+
+// ----------------------------------------------------------------------
+// Hexagon-specific code.
+
+namespace llvm {
+
+ FunctionPass *createHexagonConstPropagationPass();
+ void initializeHexagonConstPropagationPass(PassRegistry &Registry);
+
+} // end namespace llvm
+
+namespace {
+
+ class HexagonConstEvaluator : public MachineConstEvaluator {
+ public:
+ HexagonConstEvaluator(MachineFunction &Fn);
+
+ bool evaluate(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs) override;
+ bool evaluate(const Register &R, const LatticeCell &SrcC,
+ LatticeCell &Result) override;
+ bool evaluate(const MachineInstr &BrI, const CellMap &Inputs,
+ SetVector<const MachineBasicBlock*> &Targets, bool &FallsThru)
+ override;
+ bool rewrite(MachineInstr &MI, const CellMap &Inputs) override;
+
+ private:
+ unsigned getRegBitWidth(unsigned Reg) const;
+
+ static uint32_t getCmp(unsigned Opc);
+ static APInt getCmpImm(unsigned Opc, unsigned OpX,
+ const MachineOperand &MO);
+ void replaceWithNop(MachineInstr &MI);
+
+ bool evaluateHexRSEQ32(Register RL, Register RH, const CellMap &Inputs,
+ LatticeCell &Result);
+ bool evaluateHexCompare(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs);
+ // This is suitable to be called for compare-and-jump instructions.
+ bool evaluateHexCompare2(uint32_t Cmp, const MachineOperand &Src1,
+ const MachineOperand &Src2, const CellMap &Inputs, bool &Result);
+ bool evaluateHexLogical(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs);
+ bool evaluateHexCondMove(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs);
+ bool evaluateHexExt(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs);
+ bool evaluateHexVector1(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs);
+ bool evaluateHexVector2(const MachineInstr &MI, const CellMap &Inputs,
+ CellMap &Outputs);
+
+ void replaceAllRegUsesWith(unsigned FromReg, unsigned ToReg);
+ bool rewriteHexBranch(MachineInstr &BrI, const CellMap &Inputs);
+ bool rewriteHexConstDefs(MachineInstr &MI, const CellMap &Inputs,
+ bool &AllDefs);
+ bool rewriteHexConstUses(MachineInstr &MI, const CellMap &Inputs);
+
+ MachineRegisterInfo *MRI;
+ const HexagonInstrInfo &HII;
+ const HexagonRegisterInfo &HRI;
+ };
+
+ class HexagonConstPropagation : public MachineFunctionPass {
+ public:
+ static char ID;
+
+ HexagonConstPropagation() : MachineFunctionPass(ID) {
+ PassRegistry &Registry = *PassRegistry::getPassRegistry();
+ initializeHexagonConstPropagationPass(Registry);
+ }
+
+ StringRef getPassName() const override {
+ return "Hexagon Constant Propagation";
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ const Function *F = MF.getFunction();
+ if (!F)
+ return false;
+ if (skipFunction(*F))
+ return false;
+
+ HexagonConstEvaluator HCE(MF);
+ return MachineConstPropagator(HCE).run(MF);
+ }
+ };
+
+ char HexagonConstPropagation::ID = 0;
+
+} // end anonymous namespace
+
+INITIALIZE_PASS(HexagonConstPropagation, "hcp", "Hexagon Constant Propagation",
+ false, false)
+
+HexagonConstEvaluator::HexagonConstEvaluator(MachineFunction &Fn)
+ : MachineConstEvaluator(Fn),
+ HII(*Fn.getSubtarget<HexagonSubtarget>().getInstrInfo()),
+ HRI(*Fn.getSubtarget<HexagonSubtarget>().getRegisterInfo()) {
+ MRI = &Fn.getRegInfo();
+}
+
+bool HexagonConstEvaluator::evaluate(const MachineInstr &MI,
+ const CellMap &Inputs, CellMap &Outputs) {
+ if (MI.isCall())
+ return false;
+ if (MI.getNumOperands() == 0 || !MI.getOperand(0).isReg())
+ return false;
+ const MachineOperand &MD = MI.getOperand(0);
+ if (!MD.isDef())
+ return false;
+
+ unsigned Opc = MI.getOpcode();
+ Register DefR(MD);
+ assert(!DefR.SubReg);
+ if (!TargetRegisterInfo::isVirtualRegister(DefR.Reg))
+ return false;
+
+ if (MI.isCopy()) {
+ LatticeCell RC;
+ Register SrcR(MI.getOperand(1));
+ bool Eval = evaluateCOPY(SrcR, Inputs, RC);
+ if (!Eval)
+ return false;
+ Outputs.update(DefR.Reg, RC);
+ return true;
+ }
+ if (MI.isRegSequence()) {
+ unsigned Sub1 = MI.getOperand(2).getImm();
+ unsigned Sub2 = MI.getOperand(4).getImm();
+ const TargetRegisterClass *DefRC = MRI->getRegClass(DefR.Reg);
+ unsigned SubLo = HRI.getHexagonSubRegIndex(DefRC, Hexagon::ps_sub_lo);
+ unsigned SubHi = HRI.getHexagonSubRegIndex(DefRC, Hexagon::ps_sub_hi);
+ if (Sub1 != SubLo && Sub1 != SubHi)
+ return false;
+ if (Sub2 != SubLo && Sub2 != SubHi)
+ return false;
+ assert(Sub1 != Sub2);
+ bool LoIs1 = (Sub1 == SubLo);
+ const MachineOperand &OpLo = LoIs1 ? MI.getOperand(1) : MI.getOperand(3);
+ const MachineOperand &OpHi = LoIs1 ? MI.getOperand(3) : MI.getOperand(1);
+ LatticeCell RC;
+ Register SrcRL(OpLo), SrcRH(OpHi);
+ bool Eval = evaluateHexRSEQ32(SrcRL, SrcRH, Inputs, RC);
+ if (!Eval)
+ return false;
+ Outputs.update(DefR.Reg, RC);
+ return true;
+ }
+ if (MI.isCompare()) {
+ bool Eval = evaluateHexCompare(MI, Inputs, Outputs);
+ return Eval;
+ }
+
+ switch (Opc) {
+ default:
+ return false;
+ case Hexagon::A2_tfrsi:
+ case Hexagon::A2_tfrpi:
+ case Hexagon::CONST32:
+ case Hexagon::CONST64:
+ {
+ const MachineOperand &VO = MI.getOperand(1);
+ // The operand of CONST32 can be a blockaddress, e.g.
+ // %vreg0<def> = CONST32 <blockaddress(@eat, %L)>
+ // Do this check for all instructions for safety.
+ if (!VO.isImm())
+ return false;
+ int64_t V = MI.getOperand(1).getImm();
+ unsigned W = getRegBitWidth(DefR.Reg);
+ if (W != 32 && W != 64)
+ return false;
+ IntegerType *Ty = (W == 32) ? Type::getInt32Ty(CX)
+ : Type::getInt64Ty(CX);
+ const ConstantInt *CI = ConstantInt::get(Ty, V, true);
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ RC.add(CI);
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::PS_true:
+ case Hexagon::PS_false:
+ {
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ bool NonZero = (Opc == Hexagon::PS_true);
+ uint32_t P = NonZero ? ConstantProperties::NonZero
+ : ConstantProperties::Zero;
+ RC.add(P);
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::A2_and:
+ case Hexagon::A2_andir:
+ case Hexagon::A2_andp:
+ case Hexagon::A2_or:
+ case Hexagon::A2_orir:
+ case Hexagon::A2_orp:
+ case Hexagon::A2_xor:
+ case Hexagon::A2_xorp:
+ {
+ bool Eval = evaluateHexLogical(MI, Inputs, Outputs);
+ if (!Eval)
+ return false;
+ break;
+ }
+
+ case Hexagon::A2_combineii: // combine(#s8Ext, #s8)
+ case Hexagon::A4_combineii: // combine(#s8, #u6Ext)
+ {
+ uint64_t Hi = MI.getOperand(1).getImm();
+ uint64_t Lo = MI.getOperand(2).getImm();
+ uint64_t Res = (Hi << 32) | (Lo & 0xFFFFFFFF);
+ IntegerType *Ty = Type::getInt64Ty(CX);
+ const ConstantInt *CI = ConstantInt::get(Ty, Res, false);
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ RC.add(CI);
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::S2_setbit_i:
+ {
+ int64_t B = MI.getOperand(2).getImm();
+ assert(B >=0 && B < 32);
+ APInt A(32, (1ull << B), false);
+ Register R(MI.getOperand(1));
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ bool Eval = evaluateORri(R, A, Inputs, RC);
+ if (!Eval)
+ return false;
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::C2_mux:
+ case Hexagon::C2_muxir:
+ case Hexagon::C2_muxri:
+ case Hexagon::C2_muxii:
+ {
+ bool Eval = evaluateHexCondMove(MI, Inputs, Outputs);
+ if (!Eval)
+ return false;
+ break;
+ }
+
+ case Hexagon::A2_sxtb:
+ case Hexagon::A2_sxth:
+ case Hexagon::A2_sxtw:
+ case Hexagon::A2_zxtb:
+ case Hexagon::A2_zxth:
+ {
+ bool Eval = evaluateHexExt(MI, Inputs, Outputs);
+ if (!Eval)
+ return false;
+ break;
+ }
+
+ case Hexagon::S2_ct0:
+ case Hexagon::S2_ct0p:
+ case Hexagon::S2_ct1:
+ case Hexagon::S2_ct1p:
+ {
+ using namespace Hexagon;
+
+ bool Ones = (Opc == S2_ct1) || (Opc == S2_ct1p);
+ Register R1(MI.getOperand(1));
+ assert(Inputs.has(R1.Reg));
+ LatticeCell T;
+ bool Eval = evaluateCTBr(R1, !Ones, Ones, Inputs, T);
+ if (!Eval)
+ return false;
+ // All of these instructions return a 32-bit value. The evaluate
+ // will generate the same type as the operand, so truncate the
+ // result if necessary.
+ APInt C;
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ for (unsigned i = 0; i < T.size(); ++i) {
+ const Constant *CI = T.Values[i];
+ if (constToInt(CI, C) && C.getBitWidth() > 32)
+ CI = intToConst(C.trunc(32));
+ RC.add(CI);
+ }
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::S2_cl0:
+ case Hexagon::S2_cl0p:
+ case Hexagon::S2_cl1:
+ case Hexagon::S2_cl1p:
+ case Hexagon::S2_clb:
+ case Hexagon::S2_clbp:
+ {
+ using namespace Hexagon;
+
+ bool OnlyZeros = (Opc == S2_cl0) || (Opc == S2_cl0p);
+ bool OnlyOnes = (Opc == S2_cl1) || (Opc == S2_cl1p);
+ Register R1(MI.getOperand(1));
+ assert(Inputs.has(R1.Reg));
+ LatticeCell T;
+ bool Eval = evaluateCLBr(R1, !OnlyOnes, !OnlyZeros, Inputs, T);
+ if (!Eval)
+ return false;
+ // All of these instructions return a 32-bit value. The evaluate
+ // will generate the same type as the operand, so truncate the
+ // result if necessary.
+ APInt C;
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ for (unsigned i = 0; i < T.size(); ++i) {
+ const Constant *CI = T.Values[i];
+ if (constToInt(CI, C) && C.getBitWidth() > 32)
+ CI = intToConst(C.trunc(32));
+ RC.add(CI);
+ }
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::S4_extract:
+ case Hexagon::S4_extractp:
+ case Hexagon::S2_extractu:
+ case Hexagon::S2_extractup:
+ {
+ bool Signed = (Opc == Hexagon::S4_extract) ||
+ (Opc == Hexagon::S4_extractp);
+ Register R1(MI.getOperand(1));
+ unsigned BW = getRegBitWidth(R1.Reg);
+ unsigned Bits = MI.getOperand(2).getImm();
+ unsigned Offset = MI.getOperand(3).getImm();
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ if (Offset >= BW) {
+ APInt Zero(BW, 0, false);
+ RC.add(intToConst(Zero));
+ break;
+ }
+ if (Offset+Bits > BW) {
+ // If the requested bitfield extends beyond the most significant bit,
+ // the extra bits are treated as 0s. To emulate this behavior, reduce
+ // the number of requested bits, and make the extract unsigned.
+ Bits = BW-Offset;
+ Signed = false;
+ }
+ bool Eval = evaluateEXTRACTr(R1, BW, Bits, Offset, Signed, Inputs, RC);
+ if (!Eval)
+ return false;
+ Outputs.update(DefR.Reg, RC);
+ break;
+ }
+
+ case Hexagon::S2_vsplatrb:
+ case Hexagon::S2_vsplatrh:
+ // vabsh, vabsh:sat
+ // vabsw, vabsw:sat
+ // vconj:sat
+ // vrndwh, vrndwh:sat
+ // vsathb, vsathub, vsatwuh
+ // vsxtbh, vsxthw
+ // vtrunehb, vtrunohb
+ // vzxtbh, vzxthw
+ {
+ bool Eval = evaluateHexVector1(MI, Inputs, Outputs);
+ if (!Eval)
+ return false;
+ break;
+ }
+
+ // TODO:
+ // A2_vaddh
+ // A2_vaddhs
+ // A2_vaddw
+ // A2_vaddws
+ }
+
+ return true;
+}
+
+bool HexagonConstEvaluator::evaluate(const Register &R,
+ const LatticeCell &Input, LatticeCell &Result) {
+ if (!R.SubReg) {
+ Result = Input;
+ return true;
+ }
+ const TargetRegisterClass *RC = MRI->getRegClass(R.Reg);
+ if (RC != &Hexagon::DoubleRegsRegClass)
+ return false;
+ if (R.SubReg != Hexagon::isub_lo && R.SubReg != Hexagon::isub_hi)
+ return false;
+
+ assert(!Input.isTop());
+ if (Input.isBottom())
+ return false;
+
+ typedef ConstantProperties P;
+ if (Input.isProperty()) {
+ uint32_t Ps = Input.properties();
+ if (Ps & (P::Zero|P::NaN)) {
+ uint32_t Ns = (Ps & (P::Zero|P::NaN|P::SignProperties));
+ Result.add(Ns);
+ return true;
+ }
+ if (R.SubReg == Hexagon::isub_hi) {
+ uint32_t Ns = (Ps & P::SignProperties);
+ Result.add(Ns);
+ return true;
+ }
+ return false;
+ }
+
+ // The Input cell contains some known values. Pick the word corresponding
+ // to the subregister.
+ APInt A;
+ for (unsigned i = 0; i < Input.size(); ++i) {
+ const Constant *C = Input.Values[i];
+ if (!constToInt(C, A))
+ return false;
+ if (!A.isIntN(64))
+ return false;
+ uint64_t U = A.getZExtValue();
+ if (R.SubReg == Hexagon::isub_hi)
+ U >>= 32;
+ U &= 0xFFFFFFFFULL;
+ uint32_t U32 = Lo_32(U);
+ int32_t V32;
+ memcpy(&V32, &U32, sizeof V32);
+ IntegerType *Ty = Type::getInt32Ty(CX);
+ const ConstantInt *C32 = ConstantInt::get(Ty, static_cast<int64_t>(V32));
+ Result.add(C32);
+ }
+ return true;
+}
+
+bool HexagonConstEvaluator::evaluate(const MachineInstr &BrI,
+ const CellMap &Inputs, SetVector<const MachineBasicBlock*> &Targets,
+ bool &FallsThru) {
+ // We need to evaluate one branch at a time. TII::analyzeBranch checks
+ // all the branches in a basic block at once, so we cannot use it.
+ unsigned Opc = BrI.getOpcode();
+ bool SimpleBranch = false;
+ bool Negated = false;
+ switch (Opc) {
+ case Hexagon::J2_jumpf:
+ case Hexagon::J2_jumpfnew:
+ case Hexagon::J2_jumpfnewpt:
+ Negated = true;
+ case Hexagon::J2_jumpt:
+ case Hexagon::J2_jumptnew:
+ case Hexagon::J2_jumptnewpt:
+ // Simple branch: if([!]Pn) jump ...
+ // i.e. Op0 = predicate, Op1 = branch target.
+ SimpleBranch = true;
+ break;
+ case Hexagon::J2_jump:
+ Targets.insert(BrI.getOperand(0).getMBB());
+ FallsThru = false;
+ return true;
+ default:
+Undetermined:
+ // If the branch is of unknown type, assume that all successors are
+ // executable.
+ FallsThru = !BrI.isUnconditionalBranch();
+ return false;
+ }
+
+ if (SimpleBranch) {
+ const MachineOperand &MD = BrI.getOperand(0);
+ Register PR(MD);
+ // If the condition operand has a subregister, this is not something
+ // we currently recognize.
+ if (PR.SubReg)
+ goto Undetermined;
+ assert(Inputs.has(PR.Reg));
+ const LatticeCell &PredC = Inputs.get(PR.Reg);
+ if (PredC.isBottom())
+ goto Undetermined;
+
+ uint32_t Props = PredC.properties();
+ bool CTrue = false, CFalse = false;;
+ if (Props & ConstantProperties::Zero)
+ CFalse = true;
+ else if (Props & ConstantProperties::NonZero)
+ CTrue = true;
+ // If the condition is not known to be either, bail out.
+ if (!CTrue && !CFalse)
+ goto Undetermined;
+
+ const MachineBasicBlock *BranchTarget = BrI.getOperand(1).getMBB();
+
+ FallsThru = false;
+ if ((!Negated && CTrue) || (Negated && CFalse))
+ Targets.insert(BranchTarget);
+ else if ((!Negated && CFalse) || (Negated && CTrue))
+ FallsThru = true;
+ else
+ goto Undetermined;
+ }
+
+ return true;
+}
+
+bool HexagonConstEvaluator::rewrite(MachineInstr &MI, const CellMap &Inputs) {
+ if (MI.isBranch())
+ return rewriteHexBranch(MI, Inputs);
+
+ unsigned Opc = MI.getOpcode();
+ switch (Opc) {
+ default:
+ break;
+ case Hexagon::A2_tfrsi:
+ case Hexagon::A2_tfrpi:
+ case Hexagon::CONST32:
+ case Hexagon::CONST64:
+ case Hexagon::PS_true:
+ case Hexagon::PS_false:
+ return false;
+ }
+
+ unsigned NumOp = MI.getNumOperands();
+ if (NumOp == 0)
+ return false;
+
+ bool AllDefs, Changed;
+ Changed = rewriteHexConstDefs(MI, Inputs, AllDefs);
+ // If not all defs have been rewritten (i.e. the instruction defines
+ // a register that is not compile-time constant), then try to rewrite
+ // register operands that are known to be constant with immediates.
+ if (!AllDefs)
+ Changed |= rewriteHexConstUses(MI, Inputs);
+
+ return Changed;
+}
+
+unsigned HexagonConstEvaluator::getRegBitWidth(unsigned Reg) const {
+ const TargetRegisterClass *RC = MRI->getRegClass(Reg);
+ if (Hexagon::IntRegsRegClass.hasSubClassEq(RC))
+ return 32;
+ if (Hexagon::DoubleRegsRegClass.hasSubClassEq(RC))
+ return 64;
+ if (Hexagon::PredRegsRegClass.hasSubClassEq(RC))
+ return 8;
+ llvm_unreachable("Invalid register");
+ return 0;
+}
+
+uint32_t HexagonConstEvaluator::getCmp(unsigned Opc) {
+ switch (Opc) {
+ case Hexagon::C2_cmpeq:
+ case Hexagon::C2_cmpeqp:
+ case Hexagon::A4_cmpbeq:
+ case Hexagon::A4_cmpheq:
+ case Hexagon::A4_cmpbeqi:
+ case Hexagon::A4_cmpheqi:
+ case Hexagon::C2_cmpeqi:
+ case Hexagon::J4_cmpeqn1_t_jumpnv_nt:
+ case Hexagon::J4_cmpeqn1_t_jumpnv_t:
+ case Hexagon::J4_cmpeqi_t_jumpnv_nt:
+ case Hexagon::J4_cmpeqi_t_jumpnv_t:
+ case Hexagon::J4_cmpeq_t_jumpnv_nt:
+ case Hexagon::J4_cmpeq_t_jumpnv_t:
+ return Comparison::EQ;
+
+ case Hexagon::C4_cmpneq:
+ case Hexagon::C4_cmpneqi:
+ case Hexagon::J4_cmpeqn1_f_jumpnv_nt:
+ case Hexagon::J4_cmpeqn1_f_jumpnv_t:
+ case Hexagon::J4_cmpeqi_f_jumpnv_nt:
+ case Hexagon::J4_cmpeqi_f_jumpnv_t:
+ case Hexagon::J4_cmpeq_f_jumpnv_nt:
+ case Hexagon::J4_cmpeq_f_jumpnv_t:
+ return Comparison::NE;
+
+ case Hexagon::C2_cmpgt:
+ case Hexagon::C2_cmpgtp:
+ case Hexagon::A4_cmpbgt:
+ case Hexagon::A4_cmphgt:
+ case Hexagon::A4_cmpbgti:
+ case Hexagon::A4_cmphgti:
+ case Hexagon::C2_cmpgti:
+ case Hexagon::J4_cmpgtn1_t_jumpnv_nt:
+ case Hexagon::J4_cmpgtn1_t_jumpnv_t:
+ case Hexagon::J4_cmpgti_t_jumpnv_nt:
+ case Hexagon::J4_cmpgti_t_jumpnv_t:
+ case Hexagon::J4_cmpgt_t_jumpnv_nt:
+ case Hexagon::J4_cmpgt_t_jumpnv_t:
+ return Comparison::GTs;
+
+ case Hexagon::C4_cmplte:
+ case Hexagon::C4_cmpltei:
+ case Hexagon::J4_cmpgtn1_f_jumpnv_nt:
+ case Hexagon::J4_cmpgtn1_f_jumpnv_t:
+ case Hexagon::J4_cmpgti_f_jumpnv_nt:
+ case Hexagon::J4_cmpgti_f_jumpnv_t:
+ case Hexagon::J4_cmpgt_f_jumpnv_nt:
+ case Hexagon::J4_cmpgt_f_jumpnv_t:
+ return Comparison::LEs;
+
+ case Hexagon::C2_cmpgtu:
+ case Hexagon::C2_cmpgtup:
+ case Hexagon::A4_cmpbgtu:
+ case Hexagon::A4_cmpbgtui:
+ case Hexagon::A4_cmphgtu:
+ case Hexagon::A4_cmphgtui:
+ case Hexagon::C2_cmpgtui:
+ case Hexagon::J4_cmpgtui_t_jumpnv_nt:
+ case Hexagon::J4_cmpgtui_t_jumpnv_t:
+ case Hexagon::J4_cmpgtu_t_jumpnv_nt:
+ case Hexagon::J4_cmpgtu_t_jumpnv_t:
+ return Comparison::GTu;
+
+ case Hexagon::J4_cmpltu_f_jumpnv_nt:
+ case Hexagon::J4_cmpltu_f_jumpnv_t:
+ return Comparison::GEu;
+
+ case Hexagon::J4_cmpltu_t_jumpnv_nt:
+ case Hexagon::J4_cmpltu_t_jumpnv_t:
+ return Comparison::LTu;
+
+ case Hexagon::J4_cmplt_f_jumpnv_nt:
+ case Hexagon::J4_cmplt_f_jumpnv_t:
+ return Comparison::GEs;
+
+ case Hexagon::C4_cmplteu:
+ case Hexagon::C4_cmplteui:
+ case Hexagon::J4_cmpgtui_f_jumpnv_nt:
+ case Hexagon::J4_cmpgtui_f_jumpnv_t:
+ case Hexagon::J4_cmpgtu_f_jumpnv_nt:
+ case Hexagon::J4_cmpgtu_f_jumpnv_t:
+ return Comparison::LEu;
+
+ case Hexagon::J4_cmplt_t_jumpnv_nt:
+ case Hexagon::J4_cmplt_t_jumpnv_t:
+ return Comparison::LTs;
+
+ default:
+ break;
+ }
+ return Comparison::Unk;
+}
+
+APInt HexagonConstEvaluator::getCmpImm(unsigned Opc, unsigned OpX,
+ const MachineOperand &MO) {
+ bool Signed = false;
+ switch (Opc) {
+ case Hexagon::A4_cmpbgtui: // u7
+ case Hexagon::A4_cmphgtui: // u7
+ break;
+ case Hexagon::A4_cmpheqi: // s8
+ case Hexagon::C4_cmpneqi: // s8
+ Signed = true;
+ case Hexagon::A4_cmpbeqi: // u8
+ break;
+ case Hexagon::C2_cmpgtui: // u9
+ case Hexagon::C4_cmplteui: // u9
+ break;
+ case Hexagon::C2_cmpeqi: // s10
+ case Hexagon::C2_cmpgti: // s10
+ case Hexagon::C4_cmpltei: // s10
+ Signed = true;
+ break;
+ case Hexagon::J4_cmpeqi_f_jumpnv_nt: // u5
+ case Hexagon::J4_cmpeqi_f_jumpnv_t: // u5
+ case Hexagon::J4_cmpeqi_t_jumpnv_nt: // u5
+ case Hexagon::J4_cmpeqi_t_jumpnv_t: // u5
+ case Hexagon::J4_cmpgti_f_jumpnv_nt: // u5
+ case Hexagon::J4_cmpgti_f_jumpnv_t: // u5
+ case Hexagon::J4_cmpgti_t_jumpnv_nt: // u5
+ case Hexagon::J4_cmpgti_t_jumpnv_t: // u5
+ case Hexagon::J4_cmpgtui_f_jumpnv_nt: // u5
+ case Hexagon::J4_cmpgtui_f_jumpnv_t: // u5
+ case Hexagon::J4_cmpgtui_t_jumpnv_nt: // u5
+ case Hexagon::J4_cmpgtui_t_jumpnv_t: // u5
+ break;
+ default:
+ llvm_unreachable("Unhandled instruction");
+ break;
+ }
+
+ uint64_t Val = MO.getImm();
+ return APInt(32, Val, Signed);
+}
+
+void HexagonConstEvaluator::replaceWithNop(MachineInstr &MI) {
+ MI.setDesc(HII.get(Hexagon::A2_nop));
+ while (MI.getNumOperands() > 0)
+ MI.RemoveOperand(0);
+}
+
+bool HexagonConstEvaluator::evaluateHexRSEQ32(Register RL, Register RH,
+ const CellMap &Inputs, LatticeCell &Result) {
+ assert(Inputs.has(RL.Reg) && Inputs.has(RH.Reg));
+ LatticeCell LSL, LSH;
+ if (!getCell(RL, Inputs, LSL) || !getCell(RH, Inputs, LSH))
+ return false;
+ if (LSL.isProperty() || LSH.isProperty())
+ return false;
+
+ unsigned LN = LSL.size(), HN = LSH.size();
+ SmallVector<APInt,4> LoVs(LN), HiVs(HN);
+ for (unsigned i = 0; i < LN; ++i) {
+ bool Eval = constToInt(LSL.Values[i], LoVs[i]);
+ if (!Eval)
+ return false;
+ assert(LoVs[i].getBitWidth() == 32);
+ }
+ for (unsigned i = 0; i < HN; ++i) {
+ bool Eval = constToInt(LSH.Values[i], HiVs[i]);
+ if (!Eval)
+ return false;
+ assert(HiVs[i].getBitWidth() == 32);
+ }
+
+ for (unsigned i = 0; i < HiVs.size(); ++i) {
+ APInt HV = HiVs[i].zextOrSelf(64) << 32;
+ for (unsigned j = 0; j < LoVs.size(); ++j) {
+ APInt LV = LoVs[j].zextOrSelf(64);
+ const Constant *C = intToConst(HV | LV);
+ Result.add(C);
+ if (Result.isBottom())
+ return false;
+ }
+ }
+ return !Result.isBottom();
+}
+
+bool HexagonConstEvaluator::evaluateHexCompare(const MachineInstr &MI,
+ const CellMap &Inputs, CellMap &Outputs) {
+ unsigned Opc = MI.getOpcode();
+ bool Classic = false;
+ switch (Opc) {
+ case Hexagon::C2_cmpeq:
+ case Hexagon::C2_cmpeqp:
+ case Hexagon::C2_cmpgt:
+ case Hexagon::C2_cmpgtp:
+ case Hexagon::C2_cmpgtu:
+ case Hexagon::C2_cmpgtup:
+ case Hexagon::C2_cmpeqi:
+ case Hexagon::C2_cmpgti:
+ case Hexagon::C2_cmpgtui:
+ // Classic compare: Dst0 = CMP Src1, Src2
+ Classic = true;
+ break;
+ default:
+ // Not handling other compare instructions now.
+ return false;
+ }
+
+ if (Classic) {
+ const MachineOperand &Src1 = MI.getOperand(1);
+ const MachineOperand &Src2 = MI.getOperand(2);
+
+ bool Result;
+ unsigned Opc = MI.getOpcode();
+ bool Computed = evaluateHexCompare2(Opc, Src1, Src2, Inputs, Result);
+ if (Computed) {
+ // Only create a zero/non-zero cell. At this time there isn't really
+ // much need for specific values.
+ Register DefR(MI.getOperand(0));
+ LatticeCell L = Outputs.get(DefR.Reg);
+ uint32_t P = Result ? ConstantProperties::NonZero
+ : ConstantProperties::Zero;
+ L.add(P);
+ Outputs.update(DefR.Reg, L);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool HexagonConstEvaluator::evaluateHexCompare2(unsigned Opc,
+ const MachineOperand &Src1, const MachineOperand &Src2,
+ const CellMap &Inputs, bool &Result) {
+ uint32_t Cmp = getCmp(Opc);
+ bool Reg1 = Src1.isReg(), Reg2 = Src2.isReg();
+ bool Imm1 = Src1.isImm(), Imm2 = Src2.isImm();
+ if (Reg1) {
+ Register R1(Src1);
+ if (Reg2) {
+ Register R2(Src2);
+ return evaluateCMPrr(Cmp, R1, R2, Inputs, Result);
+ } else if (Imm2) {
+ APInt A2 = getCmpImm(Opc, 2, Src2);
+ return evaluateCMPri(Cmp, R1, A2, Inputs, Result);
+ }
+ } else if (Imm1) {
+ APInt A1 = getCmpImm(Opc, 1, Src1);
+ if (Reg2) {
+ Register R2(Src2);
+ uint32_t NegCmp = Comparison::negate(Cmp);
+ return evaluateCMPri(NegCmp, R2, A1, Inputs, Result);
+ } else if (Imm2) {
+ APInt A2 = getCmpImm(Opc, 2, Src2);
+ return evaluateCMPii(Cmp, A1, A2, Result);
+ }
+ }
+ // Unknown kind of comparison.
+ return false;
+}
+
+bool HexagonConstEvaluator::evaluateHexLogical(const MachineInstr &MI,
+ const CellMap &Inputs, CellMap &Outputs) {
+ unsigned Opc = MI.getOpcode();
+ if (MI.getNumOperands() != 3)
+ return false;
+ const MachineOperand &Src1 = MI.getOperand(1);
+ const MachineOperand &Src2 = MI.getOperand(2);
+ Register R1(Src1);
+ bool Eval = false;
+ LatticeCell RC;
+ switch (Opc) {
+ default:
+ return false;
+ case Hexagon::A2_and:
+ case Hexagon::A2_andp:
+ Eval = evaluateANDrr(R1, Register(Src2), Inputs, RC);
+ break;
+ case Hexagon::A2_andir: {
+ APInt A(32, Src2.getImm(), true);
+ Eval = evaluateANDri(R1, A, Inputs, RC);
+ break;
+ }
+ case Hexagon::A2_or:
+ case Hexagon::A2_orp:
+ Eval = evaluateORrr(R1, Register(Src2), Inputs, RC);
+ break;
+ case Hexagon::A2_orir: {
+ APInt A(32, Src2.getImm(), true);
+ Eval = evaluateORri(R1, A, Inputs, RC);
+ break;
+ }
+ case Hexagon::A2_xor:
+ case Hexagon::A2_xorp:
+ Eval = evaluateXORrr(R1, Register(Src2), Inputs, RC);
+ break;
+ }
+ if (Eval) {
+ Register DefR(MI.getOperand(0));
+ Outputs.update(DefR.Reg, RC);
+ }
+ return Eval;
+}
+
+bool HexagonConstEvaluator::evaluateHexCondMove(const MachineInstr &MI,
+ const CellMap &Inputs, CellMap &Outputs) {
+ // Dst0 = Cond1 ? Src2 : Src3
+ Register CR(MI.getOperand(1));
+ assert(Inputs.has(CR.Reg));
+ LatticeCell LS;
+ if (!getCell(CR, Inputs, LS))
+ return false;
+ uint32_t Ps = LS.properties();
+ unsigned TakeOp;
+ if (Ps & ConstantProperties::Zero)
+ TakeOp = 3;
+ else if (Ps & ConstantProperties::NonZero)
+ TakeOp = 2;
+ else
+ return false;
+
+ const MachineOperand &ValOp = MI.getOperand(TakeOp);
+ Register DefR(MI.getOperand(0));
+ LatticeCell RC = Outputs.get(DefR.Reg);
+
+ if (ValOp.isImm()) {
+ int64_t V = ValOp.getImm();
+ unsigned W = getRegBitWidth(DefR.Reg);
+ APInt A(W, V, true);
+ const Constant *C = intToConst(A);
+ RC.add(C);
+ Outputs.update(DefR.Reg, RC);
+ return true;
+ }
+ if (ValOp.isReg()) {
+ Register R(ValOp);
+ const LatticeCell &LR = Inputs.get(R.Reg);
+ LatticeCell LSR;
+ if (!evaluate(R, LR, LSR))
+ return false;
+ RC.meet(LSR);
+ Outputs.update(DefR.Reg, RC);
+ return true;
+ }
+ return false;
+}
+
+bool HexagonConstEvaluator::evaluateHexExt(const MachineInstr &MI,
+ const CellMap &Inputs, CellMap &Outputs) {
+ // Dst0 = ext R1
+ Register R1(MI.getOperand(1));
+ assert(Inputs.has(R1.Reg));
+
+ unsigned Opc = MI.getOpcode();
+ unsigned Bits;
+ switch (Opc) {
+ case Hexagon::A2_sxtb:
+ case Hexagon::A2_zxtb:
+ Bits = 8;
+ break;
+ case Hexagon::A2_sxth:
+ case Hexagon::A2_zxth:
+ Bits = 16;
+ break;
+ case Hexagon::A2_sxtw:
+ Bits = 32;
+ break;
+ }
+
+ bool Signed = false;
+ switch (Opc) {
+ case Hexagon::A2_sxtb:
+ case Hexagon::A2_sxth:
+ case Hexagon::A2_sxtw:
+ Signed = true;
+ break;
+ }
+
+ Register DefR(MI.getOperand(0));
+ unsigned BW = getRegBitWidth(DefR.Reg);
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ bool Eval = Signed ? evaluateSEXTr(R1, BW, Bits, Inputs, RC)
+ : evaluateZEXTr(R1, BW, Bits, Inputs, RC);
+ if (!Eval)
+ return false;
+ Outputs.update(DefR.Reg, RC);
+ return true;
+}
+
+bool HexagonConstEvaluator::evaluateHexVector1(const MachineInstr &MI,
+ const CellMap &Inputs, CellMap &Outputs) {
+ // DefR = op R1
+ Register DefR(MI.getOperand(0));
+ Register R1(MI.getOperand(1));
+ assert(Inputs.has(R1.Reg));
+ LatticeCell RC = Outputs.get(DefR.Reg);
+ bool Eval;
+
+ unsigned Opc = MI.getOpcode();
+ switch (Opc) {
+ case Hexagon::S2_vsplatrb:
+ // Rd = 4 times Rs:0..7
+ Eval = evaluateSplatr(R1, 8, 4, Inputs, RC);
+ break;
+ case Hexagon::S2_vsplatrh:
+ // Rdd = 4 times Rs:0..15
+ Eval = evaluateSplatr(R1, 16, 4, Inputs, RC);
+ break;
+ default:
+ return false;
+ }
+
+ if (!Eval)
+ return false;
+ Outputs.update(DefR.Reg, RC);
+ return true;
+}
+
+bool HexagonConstEvaluator::rewriteHexConstDefs(MachineInstr &MI,
+ const CellMap &Inputs, bool &AllDefs) {
+ AllDefs = false;
+
+ // Some diagnostics.
+ // DEBUG({...}) gets confused with all this code as an argument.
+#ifndef NDEBUG
+ bool Debugging = DebugFlag && isCurrentDebugType(DEBUG_TYPE);
+ if (Debugging) {
+ bool Const = true, HasUse = false;
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isUse() || MO.isImplicit())
+ continue;
+ Register R(MO);
+ if (!TargetRegisterInfo::isVirtualRegister(R.Reg))
+ continue;
+ HasUse = true;
+ // PHIs can legitimately have "top" cells after propagation.
+ if (!MI.isPHI() && !Inputs.has(R.Reg)) {
+ dbgs() << "Top " << PrintReg(R.Reg, &HRI, R.SubReg)
+ << " in MI: " << MI;
+ continue;
+ }
+ const LatticeCell &L = Inputs.get(R.Reg);
+ Const &= L.isSingle();
+ if (!Const)
+ break;
+ }
+ if (HasUse && Const) {
+ if (!MI.isCopy()) {
+ dbgs() << "CONST: " << MI;
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isUse() || MO.isImplicit())
+ continue;
+ unsigned R = MO.getReg();
+ dbgs() << PrintReg(R, &TRI) << ": " << Inputs.get(R) << "\n";
+ }
+ }
+ }
+ }
+#endif
+
+ // Avoid generating TFRIs for register transfers---this will keep the
+ // coalescing opportunities.
+ if (MI.isCopy())
+ return false;
+
+ // Collect all virtual register-def operands.
+ SmallVector<unsigned,2> DefRegs;
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isDef())
+ continue;
+ unsigned R = MO.getReg();
+ if (!TargetRegisterInfo::isVirtualRegister(R))
+ continue;
+ assert(!MO.getSubReg());
+ assert(Inputs.has(R));
+ DefRegs.push_back(R);
+ }
+
+ MachineBasicBlock &B = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ unsigned ChangedNum = 0;
+#ifndef NDEBUG
+ SmallVector<const MachineInstr*,4> NewInstrs;
+#endif
+
+ // For each defined register, if it is a constant, create an instruction
+ // NewR = const
+ // and replace all uses of the defined register with NewR.
+ for (unsigned i = 0, n = DefRegs.size(); i < n; ++i) {
+ unsigned R = DefRegs[i];
+ const LatticeCell &L = Inputs.get(R);
+ if (L.isBottom())
+ continue;
+ const TargetRegisterClass *RC = MRI->getRegClass(R);
+ MachineBasicBlock::iterator At = MI.getIterator();
+
+ if (!L.isSingle()) {
+ // If this a zero/non-zero cell, we can fold a definition
+ // of a predicate register.
+ typedef ConstantProperties P;
+ uint64_t Ps = L.properties();
+ if (!(Ps & (P::Zero|P::NonZero)))
+ continue;
+ const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;
+ if (RC != PredRC)
+ continue;
+ const MCInstrDesc *NewD = (Ps & P::Zero) ?
+ &HII.get(Hexagon::PS_false) :
+ &HII.get(Hexagon::PS_true);
+ unsigned NewR = MRI->createVirtualRegister(PredRC);
+ const MachineInstrBuilder &MIB = BuildMI(B, At, DL, *NewD, NewR);
+ (void)MIB;
+#ifndef NDEBUG
+ NewInstrs.push_back(&*MIB);
+#endif
+ replaceAllRegUsesWith(R, NewR);
+ } else {
+ // This cell has a single value.
+ APInt A;
+ if (!constToInt(L.Value, A) || !A.isSignedIntN(64))
+ continue;
+ const TargetRegisterClass *NewRC;
+ const MCInstrDesc *NewD;
+
+ unsigned W = getRegBitWidth(R);
+ int64_t V = A.getSExtValue();
+ assert(W == 32 || W == 64);
+ if (W == 32)
+ NewRC = &Hexagon::IntRegsRegClass;
+ else
+ NewRC = &Hexagon::DoubleRegsRegClass;
+ unsigned NewR = MRI->createVirtualRegister(NewRC);
+ const MachineInstr *NewMI;
+
+ if (W == 32) {
+ NewD = &HII.get(Hexagon::A2_tfrsi);
+ NewMI = BuildMI(B, At, DL, *NewD, NewR)
+ .addImm(V);
+ } else {
+ if (A.isSignedIntN(8)) {
+ NewD = &HII.get(Hexagon::A2_tfrpi);
+ NewMI = BuildMI(B, At, DL, *NewD, NewR)
+ .addImm(V);
+ } else {
+ int32_t Hi = V >> 32;
+ int32_t Lo = V & 0xFFFFFFFFLL;
+ if (isInt<8>(Hi) && isInt<8>(Lo)) {
+ NewD = &HII.get(Hexagon::A2_combineii);
+ NewMI = BuildMI(B, At, DL, *NewD, NewR)
+ .addImm(Hi)
+ .addImm(Lo);
+ } else {
+ NewD = &HII.get(Hexagon::CONST64);
+ NewMI = BuildMI(B, At, DL, *NewD, NewR)
+ .addImm(V);
+ }
+ }
+ }
+ (void)NewMI;
+#ifndef NDEBUG
+ NewInstrs.push_back(NewMI);
+#endif
+ replaceAllRegUsesWith(R, NewR);
+ }
+ ChangedNum++;
+ }
+
+ DEBUG({
+ if (!NewInstrs.empty()) {
+ MachineFunction &MF = *MI.getParent()->getParent();
+ dbgs() << "In function: " << MF.getFunction()->getName() << "\n";
+ dbgs() << "Rewrite: for " << MI << " created " << *NewInstrs[0];
+ for (unsigned i = 1; i < NewInstrs.size(); ++i)
+ dbgs() << " " << *NewInstrs[i];
+ }
+ });
+
+ AllDefs = (ChangedNum == DefRegs.size());
+ return ChangedNum > 0;
+}
+
+bool HexagonConstEvaluator::rewriteHexConstUses(MachineInstr &MI,
+ const CellMap &Inputs) {
+ bool Changed = false;
+ unsigned Opc = MI.getOpcode();
+ MachineBasicBlock &B = *MI.getParent();
+ const DebugLoc &DL = MI.getDebugLoc();
+ MachineBasicBlock::iterator At = MI.getIterator();
+ MachineInstr *NewMI = nullptr;
+
+ switch (Opc) {
+ case Hexagon::M2_maci:
+ // Convert DefR += mpyi(R2, R3)
+ // to DefR += mpyi(R, #imm),
+ // or DefR -= mpyi(R, #imm).
+ {
+ Register DefR(MI.getOperand(0));
+ assert(!DefR.SubReg);
+ Register R2(MI.getOperand(2));
+ Register R3(MI.getOperand(3));
+ assert(Inputs.has(R2.Reg) && Inputs.has(R3.Reg));
+ LatticeCell LS2, LS3;
+ // It is enough to get one of the input cells, since we will only try
+ // to replace one argument---whichever happens to be a single constant.
+ bool HasC2 = getCell(R2, Inputs, LS2), HasC3 = getCell(R3, Inputs, LS3);
+ if (!HasC2 && !HasC3)
+ return false;
+ bool Zero = ((HasC2 && (LS2.properties() & ConstantProperties::Zero)) ||
+ (HasC3 && (LS3.properties() & ConstantProperties::Zero)));
+ // If one of the operands is zero, eliminate the multiplication.
+ if (Zero) {
+ // DefR == R1 (tied operands).
+ MachineOperand &Acc = MI.getOperand(1);
+ Register R1(Acc);
+ unsigned NewR = R1.Reg;
+ if (R1.SubReg) {
+ // Generate COPY. FIXME: Replace with the register:subregister.
+ const TargetRegisterClass *RC = MRI->getRegClass(DefR.Reg);
+ NewR = MRI->createVirtualRegister(RC);
+ NewMI = BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
+ .addReg(R1.Reg, getRegState(Acc), R1.SubReg);
+ }
+ replaceAllRegUsesWith(DefR.Reg, NewR);
+ MRI->clearKillFlags(NewR);
+ Changed = true;
+ break;
+ }
+
+ bool Swap = false;
+ if (!LS3.isSingle()) {
+ if (!LS2.isSingle())
+ return false;
+ Swap = true;
+ }
+ const LatticeCell &LI = Swap ? LS2 : LS3;
+ const MachineOperand &OpR2 = Swap ? MI.getOperand(3)
+ : MI.getOperand(2);
+ // LI is single here.
+ APInt A;
+ if (!constToInt(LI.Value, A) || !A.isSignedIntN(8))
+ return false;
+ int64_t V = A.getSExtValue();
+ const MCInstrDesc &D = (V >= 0) ? HII.get(Hexagon::M2_macsip)
+ : HII.get(Hexagon::M2_macsin);
+ if (V < 0)
+ V = -V;
+ const TargetRegisterClass *RC = MRI->getRegClass(DefR.Reg);
+ unsigned NewR = MRI->createVirtualRegister(RC);
+ const MachineOperand &Src1 = MI.getOperand(1);
+ NewMI = BuildMI(B, At, DL, D, NewR)
+ .addReg(Src1.getReg(), getRegState(Src1), Src1.getSubReg())
+ .addReg(OpR2.getReg(), getRegState(OpR2), OpR2.getSubReg())
+ .addImm(V);
+ replaceAllRegUsesWith(DefR.Reg, NewR);
+ Changed = true;
+ break;
+ }
+
+ case Hexagon::A2_and:
+ {
+ Register R1(MI.getOperand(1));
+ Register R2(MI.getOperand(2));
+ assert(Inputs.has(R1.Reg) && Inputs.has(R2.Reg));
+ LatticeCell LS1, LS2;
+ unsigned CopyOf = 0;
+ // Check if any of the operands is -1 (i.e. all bits set).
+ if (getCell(R1, Inputs, LS1) && LS1.isSingle()) {
+ APInt M1;
+ if (constToInt(LS1.Value, M1) && !~M1)
+ CopyOf = 2;
+ }
+ else if (getCell(R2, Inputs, LS2) && LS2.isSingle()) {
+ APInt M1;
+ if (constToInt(LS2.Value, M1) && !~M1)
+ CopyOf = 1;
+ }
+ if (!CopyOf)
+ return false;
+ MachineOperand &SO = MI.getOperand(CopyOf);
+ Register SR(SO);
+ Register DefR(MI.getOperand(0));
+ unsigned NewR = SR.Reg;
+ if (SR.SubReg) {
+ const TargetRegisterClass *RC = MRI->getRegClass(DefR.Reg);
+ NewR = MRI->createVirtualRegister(RC);
+ NewMI = BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
+ .addReg(SR.Reg, getRegState(SO), SR.SubReg);
+ }
+ replaceAllRegUsesWith(DefR.Reg, NewR);
+ MRI->clearKillFlags(NewR);
+ Changed = true;
+ }
+ break;
+
+ case Hexagon::A2_or:
+ {
+ Register R1(MI.getOperand(1));
+ Register R2(MI.getOperand(2));
+ assert(Inputs.has(R1.Reg) && Inputs.has(R2.Reg));
+ LatticeCell LS1, LS2;
+ unsigned CopyOf = 0;
+ typedef ConstantProperties P;
+ if (getCell(R1, Inputs, LS1) && (LS1.properties() & P::Zero))
+ CopyOf = 2;
+ else if (getCell(R2, Inputs, LS2) && (LS2.properties() & P::Zero))
+ CopyOf = 1;
+ if (!CopyOf)
+ return false;
+ MachineOperand &SO = MI.getOperand(CopyOf);
+ Register SR(SO);
+ Register DefR(MI.getOperand(0));
+ unsigned NewR = SR.Reg;
+ if (SR.SubReg) {
+ const TargetRegisterClass *RC = MRI->getRegClass(DefR.Reg);
+ NewR = MRI->createVirtualRegister(RC);
+ NewMI = BuildMI(B, At, DL, HII.get(TargetOpcode::COPY), NewR)
+ .addReg(SR.Reg, getRegState(SO), SR.SubReg);
+ }
+ replaceAllRegUsesWith(DefR.Reg, NewR);
+ MRI->clearKillFlags(NewR);
+ Changed = true;
+ }
+ break;
+ }
+
+ if (NewMI) {
+ // clear all the kill flags of this new instruction.
+ for (MachineOperand &MO : NewMI->operands())
+ if (MO.isReg() && MO.isUse())
+ MO.setIsKill(false);
+ }
+
+ DEBUG({
+ if (NewMI) {
+ dbgs() << "Rewrite: for " << MI;
+ if (NewMI != &MI)
+ dbgs() << " created " << *NewMI;
+ else
+ dbgs() << " modified the instruction itself and created:" << *NewMI;
+ }
+ });
+
+ return Changed;
+}
+
+void HexagonConstEvaluator::replaceAllRegUsesWith(unsigned FromReg,
+ unsigned ToReg) {
+ assert(TargetRegisterInfo::isVirtualRegister(FromReg));
+ assert(TargetRegisterInfo::isVirtualRegister(ToReg));
+ for (auto I = MRI->use_begin(FromReg), E = MRI->use_end(); I != E;) {
+ MachineOperand &O = *I;
+ ++I;
+ O.setReg(ToReg);
+ }
+}
+
+bool HexagonConstEvaluator::rewriteHexBranch(MachineInstr &BrI,
+ const CellMap &Inputs) {
+ MachineBasicBlock &B = *BrI.getParent();
+ unsigned NumOp = BrI.getNumOperands();
+ if (!NumOp)
+ return false;
+
+ bool FallsThru;
+ SetVector<const MachineBasicBlock*> Targets;
+ bool Eval = evaluate(BrI, Inputs, Targets, FallsThru);
+ unsigned NumTargets = Targets.size();
+ if (!Eval || NumTargets > 1 || (NumTargets == 1 && FallsThru))
+ return false;
+ if (BrI.getOpcode() == Hexagon::J2_jump)
+ return false;
+
+ DEBUG(dbgs() << "Rewrite(BB#" << B.getNumber() << "):" << BrI);
+ bool Rewritten = false;
+ if (NumTargets > 0) {
+ assert(!FallsThru && "This should have been checked before");
+ // MIB.addMBB needs non-const pointer.
+ MachineBasicBlock *TargetB = const_cast<MachineBasicBlock*>(Targets[0]);
+ bool Moot = B.isLayoutSuccessor(TargetB);
+ if (!Moot) {
+ // If we build a branch here, we must make sure that it won't be
+ // erased as "non-executable". We can't mark any new instructions
+ // as executable here, so we need to overwrite the BrI, which we
+ // know is executable.
+ const MCInstrDesc &JD = HII.get(Hexagon::J2_jump);
+ auto NI = BuildMI(B, BrI.getIterator(), BrI.getDebugLoc(), JD)
+ .addMBB(TargetB);
+ BrI.setDesc(JD);
+ while (BrI.getNumOperands() > 0)
+ BrI.RemoveOperand(0);
+ // This ensures that all implicit operands (e.g. %R31<imp-def>, etc)
+ // are present in the rewritten branch.
+ for (auto &Op : NI->operands())
+ BrI.addOperand(Op);
+ NI->eraseFromParent();
+ Rewritten = true;
+ }
+ }
+
+ // Do not erase instructions. A newly created instruction could get
+ // the same address as an instruction marked as executable during the
+ // propagation.
+ if (!Rewritten)
+ replaceWithNop(BrI);
+ return true;
+}
+
+FunctionPass *llvm::createHexagonConstPropagationPass() {
+ return new HexagonConstPropagation();
+}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonCopyToCombine.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonCopyToCombine.cpp
index face0f3..3608099 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonCopyToCombine.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonCopyToCombine.cpp
@@ -11,13 +11,9 @@
// to move them together. If we can move them next to each other we do so and
// replace them with a combine instruction.
//===----------------------------------------------------------------------===//
-#include "llvm/PassSupport.h"
-#include "Hexagon.h"
#include "HexagonInstrInfo.h"
-#include "HexagonMachineFunctionInfo.h"
-#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
-#include "HexagonTargetMachine.h"
+#include "llvm/PassSupport.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
@@ -64,6 +60,7 @@ namespace {
class HexagonCopyToCombine : public MachineFunctionPass {
const HexagonInstrInfo *TII;
const TargetRegisterInfo *TRI;
+ const HexagonSubtarget *ST;
bool ShouldCombineAggressively;
DenseSet<MachineInstr *> PotentiallyNewifiableTFR;
@@ -80,7 +77,7 @@ public:
MachineFunctionPass::getAnalysisUsage(AU);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon Copy-To-Combine Pass";
}
@@ -88,7 +85,7 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -163,6 +160,10 @@ static bool isCombinableInstType(MachineInstr &MI, const HexagonInstrInfo *TII,
(ShouldCombineAggressively || NotExt);
}
+ case Hexagon::V6_vassign:
+ case Hexagon::V6_vassign_128B:
+ return true;
+
default:
break;
}
@@ -186,11 +187,22 @@ static bool areCombinableOperations(const TargetRegisterInfo *TRI,
MachineInstr &LowRegInst, bool AllowC64) {
unsigned HiOpc = HighRegInst.getOpcode();
unsigned LoOpc = LowRegInst.getOpcode();
- (void)HiOpc; // Fix compiler warning
- (void)LoOpc; // Fix compiler warning
- assert((HiOpc == Hexagon::A2_tfr || HiOpc == Hexagon::A2_tfrsi) &&
- (LoOpc == Hexagon::A2_tfr || LoOpc == Hexagon::A2_tfrsi) &&
- "Assume individual instructions are of a combinable type");
+
+ auto verifyOpc = [](unsigned Opc) -> void {
+ switch (Opc) {
+ case Hexagon::A2_tfr:
+ case Hexagon::A2_tfrsi:
+ case Hexagon::V6_vassign:
+ break;
+ default:
+ llvm_unreachable("Unexpected opcode");
+ }
+ };
+ verifyOpc(HiOpc);
+ verifyOpc(LoOpc);
+
+ if (HiOpc == Hexagon::V6_vassign || LoOpc == Hexagon::V6_vassign)
+ return HiOpc == LoOpc;
if (!AllowC64) {
// There is no combine of two constant extended values.
@@ -216,9 +228,13 @@ static bool areCombinableOperations(const TargetRegisterInfo *TRI,
}
static bool isEvenReg(unsigned Reg) {
- assert(TargetRegisterInfo::isPhysicalRegister(Reg) &&
- Hexagon::IntRegsRegClass.contains(Reg));
- return (Reg - Hexagon::R0) % 2 == 0;
+ assert(TargetRegisterInfo::isPhysicalRegister(Reg));
+ if (Hexagon::IntRegsRegClass.contains(Reg))
+ return (Reg - Hexagon::R0) % 2 == 0;
+ if (Hexagon::VectorRegsRegClass.contains(Reg) ||
+ Hexagon::VectorRegs128BRegClass.contains(Reg))
+ return (Reg - Hexagon::V0) % 2 == 0;
+ llvm_unreachable("Invalid register");
}
static void removeKillInfo(MachineInstr &MI, unsigned RegNotKilled) {
@@ -385,7 +401,7 @@ HexagonCopyToCombine::findPotentialNewifiableTFRs(MachineBasicBlock &BB) {
continue;
// Mark TFRs that feed a potential new value store as such.
- if (TII->mayBeNewStore(&MI)) {
+ if (TII->mayBeNewStore(MI)) {
// Look for uses of TFR instructions.
for (unsigned OpdIdx = 0, OpdE = MI.getNumOperands(); OpdIdx != OpdE;
++OpdIdx) {
@@ -446,8 +462,9 @@ bool HexagonCopyToCombine::runOnMachineFunction(MachineFunction &MF) {
bool HasChanged = false;
// Get target info.
- TRI = MF.getSubtarget().getRegisterInfo();
- TII = MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
+ ST = &MF.getSubtarget<HexagonSubtarget>();
+ TRI = ST->getRegisterInfo();
+ TII = ST->getInstrInfo();
const Function *F = MF.getFunction();
bool OptForSize = F->hasFnAttribute(Attribute::OptimizeForSize);
@@ -504,8 +521,7 @@ MachineInstr *HexagonCopyToCombine::findPairable(MachineInstr &I1,
bool &DoInsertAtI1,
bool AllowC64) {
MachineBasicBlock::iterator I2 = std::next(MachineBasicBlock::iterator(I1));
-
- while (I2->isDebugValue())
+ while (I2 != I1.getParent()->end() && I2->isDebugValue())
++I2;
unsigned I1DestReg = I1.getOperand(0).getReg();
@@ -564,14 +580,26 @@ void HexagonCopyToCombine::combine(MachineInstr &I1, MachineInstr &I2,
unsigned I2DestReg = I2.getOperand(0).getReg();
bool IsI1Loreg = (I2DestReg - I1DestReg) == 1;
unsigned LoRegDef = IsI1Loreg ? I1DestReg : I2DestReg;
+ unsigned SubLo;
+
+ const TargetRegisterClass *SuperRC = nullptr;
+ if (Hexagon::IntRegsRegClass.contains(LoRegDef)) {
+ SuperRC = &Hexagon::DoubleRegsRegClass;
+ SubLo = Hexagon::isub_lo;
+ } else if (Hexagon::VectorRegsRegClass.contains(LoRegDef)) {
+ assert(ST->useHVXOps());
+ if (ST->useHVXSglOps())
+ SuperRC = &Hexagon::VecDblRegsRegClass;
+ else
+ SuperRC = &Hexagon::VecDblRegs128BRegClass;
+ SubLo = Hexagon::vsub_lo;
+ } else
+ llvm_unreachable("Unexpected register class");
// Get the double word register.
- unsigned DoubleRegDest =
- TRI->getMatchingSuperReg(LoRegDef, Hexagon::subreg_loreg,
- &Hexagon::DoubleRegsRegClass);
+ unsigned DoubleRegDest = TRI->getMatchingSuperReg(LoRegDef, SubLo, SuperRC);
assert(DoubleRegDest != 0 && "Expect a valid register");
-
// Setup source operands.
MachineOperand &LoOperand = IsI1Loreg ? I1.getOperand(1) : I2.getOperand(1);
MachineOperand &HiOperand = IsI1Loreg ? I2.getOperand(1) : I1.getOperand(1);
@@ -605,7 +633,7 @@ void HexagonCopyToCombine::combine(MachineInstr &I1, MachineInstr &I2,
for (auto NewMI : DbgMItoMove) {
// If iterator MI is pointing to DEBUG_VAL, make sure
// MI now points to next relevant instruction.
- if (NewMI == (MachineInstr*)MI)
+ if (NewMI == MI)
++MI;
BB->splice(InsertPt, BB, NewMI);
}
@@ -628,8 +656,7 @@ void HexagonCopyToCombine::emitConst64(MachineBasicBlock::iterator &InsertPt,
int64_t V = HiOperand.getImm();
V = (V << 32) | (0x0ffffffffLL & LoOperand.getImm());
- BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::CONST64_Int_Real),
- DoubleDestReg)
+ BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::CONST64), DoubleDestReg)
.addImm(V);
}
@@ -838,7 +865,19 @@ void HexagonCopyToCombine::emitCombineRR(MachineBasicBlock::iterator &InsertPt,
// Insert new combine instruction.
// DoubleRegDest = combine HiReg, LoReg
- BuildMI(*BB, InsertPt, DL, TII->get(Hexagon::A2_combinew), DoubleDestReg)
+ unsigned NewOpc;
+ if (Hexagon::DoubleRegsRegClass.contains(DoubleDestReg)) {
+ NewOpc = Hexagon::A2_combinew;
+ } else if (Hexagon::VecDblRegsRegClass.contains(DoubleDestReg)) {
+ assert(ST->useHVXOps());
+ if (ST->useHVXSglOps())
+ NewOpc = Hexagon::V6_vcombine;
+ else
+ NewOpc = Hexagon::V6_vcombine_128B;
+ } else
+ llvm_unreachable("Unexpected register");
+
+ BuildMI(*BB, InsertPt, DL, TII->get(NewOpc), DoubleDestReg)
.addReg(HiReg, HiRegKillFlag)
.addReg(LoReg, LoRegKillFlag);
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
index 2665acd..a5351cd 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
@@ -52,7 +52,7 @@
// %vreg41<def> = S2_tstbit_i %vreg40<kill>, 0
// spec-> %vreg11<def> = A2_addp %vreg6, %vreg10
// pred-> S2_pstorerdf_io %vreg41, %vreg32, 16, %vreg11
-// %vreg46<def> = MUX64_rr %vreg41, %vreg6, %vreg11
+// %vreg46<def> = PS_pselect %vreg41, %vreg6, %vreg11
// %vreg13<def> = A2_addp %vreg7, %vreg46
// %vreg42<def> = C2_cmpeqi %vreg9, 10
// J2_jumpf %vreg42<kill>, <BB#3>, %PC<imp-def,dead>
@@ -61,32 +61,46 @@
#define DEBUG_TYPE "hexagon-eif"
+#include "Hexagon.h"
+#include "HexagonInstrInfo.h"
+#include "HexagonSubtarget.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
-#include "HexagonTargetMachine.h"
-
-#include <functional>
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <iterator>
using namespace llvm;
namespace llvm {
+
FunctionPass *createHexagonEarlyIfConversion();
void initializeHexagonEarlyIfConversionPass(PassRegistry& Registry);
-}
+
+} // end namespace llvm
namespace {
+
cl::opt<bool> EnableHexagonBP("enable-hexagon-br-prob", cl::Hidden,
cl::init(false), cl::desc("Enable branch probability info"));
cl::opt<unsigned> SizeLimit("eif-limit", cl::init(6), cl::Hidden,
@@ -103,18 +117,22 @@ namespace {
}
struct FlowPattern {
- FlowPattern() : SplitB(0), TrueB(0), FalseB(0), JoinB(0), PredR(0) {}
+ FlowPattern() = default;
FlowPattern(MachineBasicBlock *B, unsigned PR, MachineBasicBlock *TB,
MachineBasicBlock *FB, MachineBasicBlock *JB)
: SplitB(B), TrueB(TB), FalseB(FB), JoinB(JB), PredR(PR) {}
- MachineBasicBlock *SplitB;
- MachineBasicBlock *TrueB, *FalseB, *JoinB;
- unsigned PredR;
+ MachineBasicBlock *SplitB = nullptr;
+ MachineBasicBlock *TrueB = nullptr;
+ MachineBasicBlock *FalseB = nullptr;
+ MachineBasicBlock *JoinB = nullptr;
+ unsigned PredR = 0;
};
+
struct PrintFP {
PrintFP(const FlowPattern &P, const TargetRegisterInfo &T)
: FP(P), TRI(T) {}
+
const FlowPattern &FP;
const TargetRegisterInfo &TRI;
friend raw_ostream &operator<< (raw_ostream &OS, const PrintFP &P);
@@ -133,13 +151,17 @@ namespace {
class HexagonEarlyIfConversion : public MachineFunctionPass {
public:
static char ID;
+
HexagonEarlyIfConversion() : MachineFunctionPass(ID),
- TII(0), TRI(0), MFN(0), MRI(0), MDT(0), MLI(0) {
+ HII(nullptr), TRI(nullptr), MFN(nullptr), MRI(nullptr), MDT(nullptr),
+ MLI(nullptr) {
initializeHexagonEarlyIfConversionPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
+
+ StringRef getPassName() const override {
return "Hexagon early if conversion";
}
+
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineBranchProbabilityInfo>();
AU.addRequired<MachineDominatorTree>();
@@ -147,6 +169,7 @@ namespace {
AU.addRequired<MachineLoopInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
+
bool runOnMachineFunction(MachineFunction &MF) override;
private:
@@ -185,7 +208,7 @@ namespace {
void mergeBlocks(MachineBasicBlock *PredB, MachineBasicBlock *SuccB);
void simplifyFlowGraph(const FlowPattern &FP);
- const TargetInstrInfo *TII;
+ const HexagonInstrInfo *HII;
const TargetRegisterInfo *TRI;
MachineFunction *MFN;
MachineRegisterInfo *MRI;
@@ -196,7 +219,8 @@ namespace {
};
char HexagonEarlyIfConversion::ID = 0;
-}
+
+} // end anonymous namespace
INITIALIZE_PASS(HexagonEarlyIfConversion, "hexagon-eif",
"Hexagon early if conversion", false, false)
@@ -209,7 +233,6 @@ bool HexagonEarlyIfConversion::isPreheader(const MachineBasicBlock *B) const {
return L && SB == L->getHeader();
}
-
bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B,
MachineLoop *L, FlowPattern &FP) {
DEBUG(dbgs() << "Checking flow pattern at BB#" << B->getNumber() << "\n");
@@ -217,7 +240,7 @@ bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B,
// Interested only in conditional branches, no .new, no new-value, etc.
// Check the terminators directly, it's easier than handling all responses
// from AnalyzeBranch.
- MachineBasicBlock *TB = 0, *FB = 0;
+ MachineBasicBlock *TB = nullptr, *FB = nullptr;
MachineBasicBlock::const_iterator T1I = B->getFirstTerminator();
if (T1I == B->end())
return false;
@@ -228,7 +251,7 @@ bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B,
// Get the layout successor, or 0 if B does not have one.
MachineFunction::iterator NextBI = std::next(MachineFunction::iterator(B));
- MachineBasicBlock *NextB = (NextBI != MFN->end()) ? &*NextBI : 0;
+ MachineBasicBlock *NextB = (NextBI != MFN->end()) ? &*NextBI : nullptr;
MachineBasicBlock *T1B = T1I->getOperand(1).getMBB();
MachineBasicBlock::const_iterator T2I = std::next(T1I);
@@ -273,9 +296,9 @@ bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B,
if (!TOk && !FOk)
return false;
- MachineBasicBlock *TSB = (TNS > 0) ? *TB->succ_begin() : 0;
- MachineBasicBlock *FSB = (FNS > 0) ? *FB->succ_begin() : 0;
- MachineBasicBlock *JB = 0;
+ MachineBasicBlock *TSB = (TNS > 0) ? *TB->succ_begin() : nullptr;
+ MachineBasicBlock *FSB = (FNS > 0) ? *FB->succ_begin() : nullptr;
+ MachineBasicBlock *JB = nullptr;
if (TOk) {
if (FOk) {
@@ -286,14 +309,14 @@ bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B,
// TOk && !FOk
if (TSB == FB) {
JB = FB;
- FB = 0;
+ FB = nullptr;
}
}
} else {
// !TOk && FOk (at least one must be true by now).
if (FSB == TB) {
JB = TB;
- TB = 0;
+ TB = nullptr;
}
}
// Don't try to predicate loop preheaders.
@@ -308,7 +331,6 @@ bool HexagonEarlyIfConversion::matchFlowPattern(MachineBasicBlock *B,
return true;
}
-
// KLUDGE: HexagonInstrInfo::AnalyzeBranch won't work on a block that
// contains EH_LABEL.
bool HexagonEarlyIfConversion::hasEHLabel(const MachineBasicBlock *B) const {
@@ -318,7 +340,6 @@ bool HexagonEarlyIfConversion::hasEHLabel(const MachineBasicBlock *B) const {
return false;
}
-
// KLUDGE: HexagonInstrInfo::AnalyzeBranch may be unable to recognize
// that a block can never fall-through.
bool HexagonEarlyIfConversion::hasUncondBranch(const MachineBasicBlock *B)
@@ -332,7 +353,6 @@ bool HexagonEarlyIfConversion::hasUncondBranch(const MachineBasicBlock *B)
return false;
}
-
bool HexagonEarlyIfConversion::isValidCandidate(const MachineBasicBlock *B)
const {
if (!B)
@@ -357,10 +377,10 @@ bool HexagonEarlyIfConversion::isValidCandidate(const MachineBasicBlock *B)
// update the use of it after predication). PHI uses will be updated
// to use a result of a MUX, and a MUX cannot be created for predicate
// registers.
- for (ConstMIOperands MO(MI); MO.isValid(); ++MO) {
- if (!MO->isReg() || !MO->isDef())
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isDef())
continue;
- unsigned R = MO->getReg();
+ unsigned R = MO.getReg();
if (!TargetRegisterInfo::isVirtualRegister(R))
continue;
if (MRI->getRegClass(R) != &Hexagon::PredRegsRegClass)
@@ -373,12 +393,11 @@ bool HexagonEarlyIfConversion::isValidCandidate(const MachineBasicBlock *B)
return true;
}
-
bool HexagonEarlyIfConversion::usesUndefVReg(const MachineInstr *MI) const {
- for (ConstMIOperands MO(*MI); MO.isValid(); ++MO) {
- if (!MO->isReg() || !MO->isUse())
+ for (const MachineOperand &MO : MI->operands()) {
+ if (!MO.isReg() || !MO.isUse())
continue;
- unsigned R = MO->getReg();
+ unsigned R = MO.getReg();
if (!TargetRegisterInfo::isVirtualRegister(R))
continue;
const MachineInstr *DefI = MRI->getVRegDef(R);
@@ -390,7 +409,6 @@ bool HexagonEarlyIfConversion::usesUndefVReg(const MachineInstr *MI) const {
return false;
}
-
bool HexagonEarlyIfConversion::isValid(const FlowPattern &FP) const {
if (hasEHLabel(FP.SplitB)) // KLUDGE: see function definition
return false;
@@ -424,7 +442,6 @@ bool HexagonEarlyIfConversion::isValid(const FlowPattern &FP) const {
return true;
}
-
unsigned HexagonEarlyIfConversion::computePhiCost(MachineBasicBlock *B) const {
assert(B->pred_size() <= 2);
if (B->pred_size() < 2)
@@ -443,21 +460,20 @@ unsigned HexagonEarlyIfConversion::computePhiCost(MachineBasicBlock *B) const {
}
MachineInstr *Def1 = MRI->getVRegDef(RO1.getReg());
MachineInstr *Def3 = MRI->getVRegDef(RO3.getReg());
- if (!TII->isPredicable(*Def1) || !TII->isPredicable(*Def3))
+ if (!HII->isPredicable(*Def1) || !HII->isPredicable(*Def3))
Cost++;
}
return Cost;
}
-
unsigned HexagonEarlyIfConversion::countPredicateDefs(
const MachineBasicBlock *B) const {
unsigned PredDefs = 0;
for (auto &MI : *B) {
- for (ConstMIOperands MO(MI); MO.isValid(); ++MO) {
- if (!MO->isReg() || !MO->isDef())
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || !MO.isDef())
continue;
- unsigned R = MO->getReg();
+ unsigned R = MO.getReg();
if (!TargetRegisterInfo::isVirtualRegister(R))
continue;
if (MRI->getRegClass(R) == &Hexagon::PredRegsRegClass)
@@ -467,7 +483,6 @@ unsigned HexagonEarlyIfConversion::countPredicateDefs(
return PredDefs;
}
-
bool HexagonEarlyIfConversion::isProfitable(const FlowPattern &FP) const {
if (FP.TrueB && FP.FalseB) {
@@ -547,7 +562,6 @@ bool HexagonEarlyIfConversion::isProfitable(const FlowPattern &FP) const {
return true;
}
-
bool HexagonEarlyIfConversion::visitBlock(MachineBasicBlock *B,
MachineLoop *L) {
bool Changed = false;
@@ -593,9 +607,8 @@ bool HexagonEarlyIfConversion::visitBlock(MachineBasicBlock *B,
return true;
}
-
bool HexagonEarlyIfConversion::visitLoop(MachineLoop *L) {
- MachineBasicBlock *HB = L ? L->getHeader() : 0;
+ MachineBasicBlock *HB = L ? L->getHeader() : nullptr;
DEBUG((L ? dbgs() << "Visiting loop H:" << PrintMB(HB)
: dbgs() << "Visiting function") << "\n");
bool Changed = false;
@@ -609,34 +622,29 @@ bool HexagonEarlyIfConversion::visitLoop(MachineLoop *L) {
return Changed;
}
-
bool HexagonEarlyIfConversion::isPredicableStore(const MachineInstr *MI)
const {
- // Exclude post-increment stores. Those return a value, so we cannot
- // predicate them.
+ // HexagonInstrInfo::isPredicable will consider these stores are non-
+ // -predicable if the offset would become constant-extended after
+ // predication.
unsigned Opc = MI->getOpcode();
- using namespace Hexagon;
switch (Opc) {
- // Store byte:
- case S2_storerb_io: case S4_storerb_rr:
- case S2_storerbabs: case S4_storeirb_io: case S2_storerbgp:
- // Store halfword:
- case S2_storerh_io: case S4_storerh_rr:
- case S2_storerhabs: case S4_storeirh_io: case S2_storerhgp:
- // Store upper halfword:
- case S2_storerf_io: case S4_storerf_rr:
- case S2_storerfabs: case S2_storerfgp:
- // Store word:
- case S2_storeri_io: case S4_storeri_rr:
- case S2_storeriabs: case S4_storeiri_io: case S2_storerigp:
- // Store doubleword:
- case S2_storerd_io: case S4_storerd_rr:
- case S2_storerdabs: case S2_storerdgp:
+ case Hexagon::S2_storerb_io:
+ case Hexagon::S2_storerbnew_io:
+ case Hexagon::S2_storerh_io:
+ case Hexagon::S2_storerhnew_io:
+ case Hexagon::S2_storeri_io:
+ case Hexagon::S2_storerinew_io:
+ case Hexagon::S2_storerd_io:
+ case Hexagon::S4_storeirb_io:
+ case Hexagon::S4_storeirh_io:
+ case Hexagon::S4_storeiri_io:
return true;
}
- return false;
-}
+ // TargetInstrInfo::isPredicable takes a non-const pointer.
+ return MI->mayStore() && HII->isPredicable(const_cast<MachineInstr&>(*MI));
+}
bool HexagonEarlyIfConversion::isSafeToSpeculate(const MachineInstr *MI)
const {
@@ -650,59 +658,11 @@ bool HexagonEarlyIfConversion::isSafeToSpeculate(const MachineInstr *MI)
return true;
}
-
unsigned HexagonEarlyIfConversion::getCondStoreOpcode(unsigned Opc,
bool IfTrue) const {
- // Exclude post-increment stores.
- using namespace Hexagon;
- switch (Opc) {
- case S2_storerb_io:
- return IfTrue ? S2_pstorerbt_io : S2_pstorerbf_io;
- case S4_storerb_rr:
- return IfTrue ? S4_pstorerbt_rr : S4_pstorerbf_rr;
- case S2_storerbabs:
- case S2_storerbgp:
- return IfTrue ? S4_pstorerbt_abs : S4_pstorerbf_abs;
- case S4_storeirb_io:
- return IfTrue ? S4_storeirbt_io : S4_storeirbf_io;
- case S2_storerh_io:
- return IfTrue ? S2_pstorerht_io : S2_pstorerhf_io;
- case S4_storerh_rr:
- return IfTrue ? S4_pstorerht_rr : S4_pstorerhf_rr;
- case S2_storerhabs:
- case S2_storerhgp:
- return IfTrue ? S4_pstorerht_abs : S4_pstorerhf_abs;
- case S2_storerf_io:
- return IfTrue ? S2_pstorerft_io : S2_pstorerff_io;
- case S4_storerf_rr:
- return IfTrue ? S4_pstorerft_rr : S4_pstorerff_rr;
- case S2_storerfabs:
- case S2_storerfgp:
- return IfTrue ? S4_pstorerft_abs : S4_pstorerff_abs;
- case S4_storeirh_io:
- return IfTrue ? S4_storeirht_io : S4_storeirhf_io;
- case S2_storeri_io:
- return IfTrue ? S2_pstorerit_io : S2_pstorerif_io;
- case S4_storeri_rr:
- return IfTrue ? S4_pstorerit_rr : S4_pstorerif_rr;
- case S2_storeriabs:
- case S2_storerigp:
- return IfTrue ? S4_pstorerit_abs : S4_pstorerif_abs;
- case S4_storeiri_io:
- return IfTrue ? S4_storeirit_io : S4_storeirif_io;
- case S2_storerd_io:
- return IfTrue ? S2_pstorerdt_io : S2_pstorerdf_io;
- case S4_storerd_rr:
- return IfTrue ? S4_pstorerdt_rr : S4_pstorerdf_rr;
- case S2_storerdabs:
- case S2_storerdgp:
- return IfTrue ? S4_pstorerdt_abs : S4_pstorerdf_abs;
- }
- llvm_unreachable("Unexpected opcode");
- return 0;
+ return HII->getCondOpcode(Opc, !IfTrue);
}
-
void HexagonEarlyIfConversion::predicateInstr(MachineBasicBlock *ToB,
MachineBasicBlock::iterator At, MachineInstr *MI,
unsigned PredR, bool IfTrue) {
@@ -717,10 +677,15 @@ void HexagonEarlyIfConversion::predicateInstr(MachineBasicBlock *ToB,
if (isPredicableStore(MI)) {
unsigned COpc = getCondStoreOpcode(Opc, IfTrue);
assert(COpc);
- MachineInstrBuilder MIB = BuildMI(*ToB, At, DL, TII->get(COpc))
- .addReg(PredR);
- for (MIOperands MO(*MI); MO.isValid(); ++MO)
- MIB.addOperand(*MO);
+ MachineInstrBuilder MIB = BuildMI(*ToB, At, DL, HII->get(COpc));
+ MachineInstr::mop_iterator MOI = MI->operands_begin();
+ if (HII->isPostIncrement(*MI)) {
+ MIB.addOperand(*MOI);
+ ++MOI;
+ }
+ MIB.addReg(PredR);
+ for (const MachineOperand &MO : make_range(MOI, MI->operands_end()))
+ MIB.addOperand(MO);
// Set memory references.
MachineInstr::mmo_iterator MMOBegin = MI->memoperands_begin();
@@ -733,7 +698,7 @@ void HexagonEarlyIfConversion::predicateInstr(MachineBasicBlock *ToB,
if (Opc == Hexagon::J2_jump) {
MachineBasicBlock *TB = MI->getOperand(0).getMBB();
- const MCInstrDesc &D = TII->get(IfTrue ? Hexagon::J2_jumpt
+ const MCInstrDesc &D = HII->get(IfTrue ? Hexagon::J2_jumpt
: Hexagon::J2_jumpf);
BuildMI(*ToB, At, DL, D)
.addReg(PredR)
@@ -748,7 +713,6 @@ void HexagonEarlyIfConversion::predicateInstr(MachineBasicBlock *ToB,
llvm_unreachable("Unexpected instruction");
}
-
// Predicate/speculate non-branch instructions from FromB into block ToB.
// Leave the branches alone, they will be handled later. Btw, at this point
// FromB should have at most one branch, and it should be unconditional.
@@ -769,7 +733,6 @@ void HexagonEarlyIfConversion::predicateBlockNB(MachineBasicBlock *ToB,
}
}
-
void HexagonEarlyIfConversion::updatePhiNodes(MachineBasicBlock *WhereB,
const FlowPattern &FP) {
// Visit all PHI nodes in the WhereB block and generate MUX instructions
@@ -799,10 +762,25 @@ void HexagonEarlyIfConversion::updatePhiNodes(MachineBasicBlock *WhereB,
assert(TR && FR);
using namespace Hexagon;
+
unsigned DR = PN->getOperand(0).getReg();
const TargetRegisterClass *RC = MRI->getRegClass(DR);
- const MCInstrDesc &D = RC == &IntRegsRegClass ? TII->get(C2_mux)
- : TII->get(MUX64_rr);
+ unsigned Opc = 0;
+ if (RC == &IntRegsRegClass)
+ Opc = C2_mux;
+ else if (RC == &DoubleRegsRegClass)
+ Opc = PS_pselect;
+ else if (RC == &VectorRegsRegClass)
+ Opc = PS_vselect;
+ else if (RC == &VecDblRegsRegClass)
+ Opc = PS_wselect;
+ else if (RC == &VectorRegs128BRegClass)
+ Opc = PS_vselect_128B;
+ else if (RC == &VecDblRegs128BRegClass)
+ Opc = PS_wselect_128B;
+ else
+ llvm_unreachable("unexpected register type");
+ const MCInstrDesc &D = HII->get(Opc);
MachineBasicBlock::iterator MuxAt = FP.SplitB->getFirstTerminator();
DebugLoc DL;
@@ -819,9 +797,8 @@ void HexagonEarlyIfConversion::updatePhiNodes(MachineBasicBlock *WhereB,
}
}
-
void HexagonEarlyIfConversion::convert(const FlowPattern &FP) {
- MachineBasicBlock *TSB = 0, *FSB = 0;
+ MachineBasicBlock *TSB = nullptr, *FSB = nullptr;
MachineBasicBlock::iterator OldTI = FP.SplitB->getFirstTerminator();
assert(OldTI != FP.SplitB->end());
DebugLoc DL = OldTI->getDebugLoc();
@@ -839,7 +816,7 @@ void HexagonEarlyIfConversion::convert(const FlowPattern &FP) {
// Regenerate new terminators in the split block and update the successors.
// First, remember any information that may be needed later and remove the
// existing terminators/successors from the split block.
- MachineBasicBlock *SSB = 0;
+ MachineBasicBlock *SSB = nullptr;
FP.SplitB->erase(OldTI, FP.SplitB->end());
while (FP.SplitB->succ_size() > 0) {
MachineBasicBlock *T = *FP.SplitB->succ_begin();
@@ -870,21 +847,21 @@ void HexagonEarlyIfConversion::convert(const FlowPattern &FP) {
// generated.
if (FP.JoinB) {
assert(!SSB || SSB == FP.JoinB);
- BuildMI(*FP.SplitB, FP.SplitB->end(), DL, TII->get(Hexagon::J2_jump))
+ BuildMI(*FP.SplitB, FP.SplitB->end(), DL, HII->get(Hexagon::J2_jump))
.addMBB(FP.JoinB);
FP.SplitB->addSuccessor(FP.JoinB);
} else {
bool HasBranch = false;
if (TSB) {
- BuildMI(*FP.SplitB, FP.SplitB->end(), DL, TII->get(Hexagon::J2_jumpt))
+ BuildMI(*FP.SplitB, FP.SplitB->end(), DL, HII->get(Hexagon::J2_jumpt))
.addReg(FP.PredR)
.addMBB(TSB);
FP.SplitB->addSuccessor(TSB);
HasBranch = true;
}
if (FSB) {
- const MCInstrDesc &D = HasBranch ? TII->get(Hexagon::J2_jump)
- : TII->get(Hexagon::J2_jumpf);
+ const MCInstrDesc &D = HasBranch ? HII->get(Hexagon::J2_jump)
+ : HII->get(Hexagon::J2_jumpf);
MachineInstrBuilder MIB = BuildMI(*FP.SplitB, FP.SplitB->end(), DL, D);
if (!HasBranch)
MIB.addReg(FP.PredR);
@@ -896,7 +873,7 @@ void HexagonEarlyIfConversion::convert(const FlowPattern &FP) {
// successor blocks of the TrueB and FalseB (or null of the TrueB
// or FalseB block is null). SSB is the potential successor block
// of the SplitB that is neither TrueB nor FalseB.
- BuildMI(*FP.SplitB, FP.SplitB->end(), DL, TII->get(Hexagon::J2_jump))
+ BuildMI(*FP.SplitB, FP.SplitB->end(), DL, HII->get(Hexagon::J2_jump))
.addMBB(SSB);
FP.SplitB->addSuccessor(SSB);
}
@@ -915,7 +892,6 @@ void HexagonEarlyIfConversion::convert(const FlowPattern &FP) {
}
}
-
void HexagonEarlyIfConversion::removeBlock(MachineBasicBlock *B) {
DEBUG(dbgs() << "Removing block " << PrintMB(B) << "\n");
@@ -944,7 +920,6 @@ void HexagonEarlyIfConversion::removeBlock(MachineBasicBlock *B) {
MFN->erase(B->getIterator());
}
-
void HexagonEarlyIfConversion::eliminatePhis(MachineBasicBlock *B) {
DEBUG(dbgs() << "Removing phi nodes from block " << PrintMB(B) << "\n");
MachineBasicBlock::iterator I, NextI, NonPHI = B->getFirstNonPHI();
@@ -963,7 +938,7 @@ void HexagonEarlyIfConversion::eliminatePhis(MachineBasicBlock *B) {
const DebugLoc &DL = PN->getDebugLoc();
const TargetRegisterClass *RC = MRI->getRegClass(DefR);
NewR = MRI->createVirtualRegister(RC);
- NonPHI = BuildMI(*B, NonPHI, DL, TII->get(TargetOpcode::COPY), NewR)
+ NonPHI = BuildMI(*B, NonPHI, DL, HII->get(TargetOpcode::COPY), NewR)
.addReg(UseR, 0, UseSR);
}
MRI->replaceRegWith(DefR, NewR);
@@ -971,7 +946,6 @@ void HexagonEarlyIfConversion::eliminatePhis(MachineBasicBlock *B) {
}
}
-
void HexagonEarlyIfConversion::replacePhiEdges(MachineBasicBlock *OldB,
MachineBasicBlock *NewB) {
for (auto I = OldB->succ_begin(), E = OldB->succ_end(); I != E; ++I) {
@@ -979,21 +953,20 @@ void HexagonEarlyIfConversion::replacePhiEdges(MachineBasicBlock *OldB,
MachineBasicBlock::iterator P, N = SB->getFirstNonPHI();
for (P = SB->begin(); P != N; ++P) {
MachineInstr &PN = *P;
- for (MIOperands MO(PN); MO.isValid(); ++MO)
- if (MO->isMBB() && MO->getMBB() == OldB)
- MO->setMBB(NewB);
+ for (MachineOperand &MO : PN.operands())
+ if (MO.isMBB() && MO.getMBB() == OldB)
+ MO.setMBB(NewB);
}
}
}
-
void HexagonEarlyIfConversion::mergeBlocks(MachineBasicBlock *PredB,
MachineBasicBlock *SuccB) {
DEBUG(dbgs() << "Merging blocks " << PrintMB(PredB) << " and "
<< PrintMB(SuccB) << "\n");
bool TermOk = hasUncondBranch(SuccB);
eliminatePhis(SuccB);
- TII->RemoveBranch(*PredB);
+ HII->removeBranch(*PredB);
PredB->removeSuccessor(SuccB);
PredB->splice(PredB->end(), SuccB, SuccB->begin(), SuccB->end());
MachineBasicBlock::succ_iterator I, E = SuccB->succ_end();
@@ -1006,7 +979,6 @@ void HexagonEarlyIfConversion::mergeBlocks(MachineBasicBlock *PredB,
PredB->updateTerminator();
}
-
void HexagonEarlyIfConversion::simplifyFlowGraph(const FlowPattern &FP) {
if (FP.TrueB)
removeBlock(FP.TrueB);
@@ -1030,13 +1002,12 @@ void HexagonEarlyIfConversion::simplifyFlowGraph(const FlowPattern &FP) {
mergeBlocks(FP.SplitB, SB);
}
-
bool HexagonEarlyIfConversion::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
- auto &ST = MF.getSubtarget();
- TII = ST.getInstrInfo();
+ auto &ST = MF.getSubtarget<HexagonSubtarget>();
+ HII = ST.getInstrInfo();
TRI = ST.getRegisterInfo();
MFN = &MF;
MRI = &MF.getRegInfo();
@@ -1050,7 +1021,7 @@ bool HexagonEarlyIfConversion::runOnMachineFunction(MachineFunction &MF) {
for (MachineLoopInfo::iterator I = MLI->begin(), E = MLI->end(); I != E; ++I)
Changed |= visitLoop(*I);
- Changed |= visitLoop(0);
+ Changed |= visitLoop(nullptr);
return Changed;
}
@@ -1061,4 +1032,3 @@ bool HexagonEarlyIfConversion::runOnMachineFunction(MachineFunction &MF) {
FunctionPass *llvm::createHexagonEarlyIfConversion() {
return new HexagonEarlyIfConversion();
}
-
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp
index bd5bb9c..8f070d8 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp
@@ -85,78 +85,33 @@
// implicit uses will be added later, after predication. The extra price,
// however, is that finding the locations where the implicit uses need
// to be added, and updating the live ranges will be more involved.
-//
-// An additional problem appears when subregister liveness tracking is
-// enabled. In such a scenario, the live interval for the super-register
-// will have live ranges for each subregister (i.e. subranges). This sub-
-// range contains all liveness information about the subregister, except
-// for one case: a "read-undef" flag from another subregister will not
-// be reflected: given
-// vreg1:subreg_hireg<def,read-undef> = ... ; "undefines" subreg_loreg
-// the subrange for subreg_loreg will not have any indication that it is
-// undefined at this point. Calculating subregister liveness based only
-// on the information from the subrange may create a segment which spans
-// over such a "read-undef" flag. This would create inconsistencies in
-// the liveness data, resulting in assertions or incorrect code.
-// Example:
-// vreg1:subreg_loreg<def> = ...
-// vreg1:subreg_hireg<def, read-undef> = ... ; "undefines" subreg_loreg
-// ...
-// vreg1:subreg_loreg<def> = A2_tfrt ... ; may end up with imp-use
-// ; of subreg_loreg
-// The remedy takes advantage of the fact, that at this point we have
-// an unconditional definition of the subregister. What this means is
-// that any preceding value in this subregister will be overwritten,
-// or in other words, the last use before this def is a kill. This also
-// implies that the first of the predicated transfers at this location
-// should not have any implicit uses.
-// Assume for a moment that no part of the corresponding super-register
-// is used as a source. In such case, the entire super-register can be
-// considered undefined immediately before this instruction. Because of
-// that, we can insert an IMPLICIT_DEF of the super-register at this
-// location, which will cause it to be reflected in all the associated
-// subranges. What is important here is that if an IMPLICIT_DEF of
-// subreg_loreg was used, we would lose the indication that subreg_hireg
-// is also considered undefined. This could lead to having implicit uses
-// incorrectly added.
-//
-// What is left is the two cases when the super-register is used as a
-// source.
-// * Case 1: the used part is the same as the one that is defined:
-// vreg1<def> = ...
-// ...
-// vreg1:subreg_loreg<def,read-undef> = C2_mux ..., vreg1:subreg_loreg
-// In the end, the subreg_loreg should be marked as live at the point of
-// the splitting:
-// vreg1:subreg_loreg<def,read-undef> = A2_tfrt ; should have imp-use
-// vreg1:subreg_loreg<def,read-undef> = A2_tfrf ; should have imp-use
-// Hence, an IMPLICIT_DEF of only vreg1:subreg_hireg would be sufficient.
-// * Case 2: the used part does not overlap the part being defined:
-// vreg1<def> = ...
-// ...
-// vreg1:subreg_loreg<def,read-undef> = C2_mux ..., vreg1:subreg_hireg
-// For this case, we insert an IMPLICIT_DEF of vreg1:subreg_hireg after
-// the C2_mux.
#define DEBUG_TYPE "expand-condsets"
-#include "HexagonTargetMachine.h"
+#include "HexagonInstrInfo.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/CodeGen/SlotIndexes.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-
-#include <algorithm>
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
#include <iterator>
#include <set>
#include <utility>
@@ -169,17 +124,21 @@ static cl::opt<unsigned> OptCoaLimit("expand-condsets-coa-limit",
cl::init(~0U), cl::Hidden, cl::desc("Max number of segment coalescings"));
namespace llvm {
+
void initializeHexagonExpandCondsetsPass(PassRegistry&);
FunctionPass *createHexagonExpandCondsets();
-}
+
+} // end namespace llvm
namespace {
+
class HexagonExpandCondsets : public MachineFunctionPass {
public:
static char ID;
+
HexagonExpandCondsets() :
- MachineFunctionPass(ID), HII(0), TRI(0), MRI(0),
- LIS(0), CoaLimitActive(false),
+ MachineFunctionPass(ID), HII(nullptr), TRI(nullptr), MRI(nullptr),
+ LIS(nullptr), CoaLimitActive(false),
TfrLimitActive(false), CoaCounter(0), TfrCounter(0) {
if (OptCoaLimit.getPosition())
CoaLimitActive = true, CoaLimit = OptCoaLimit;
@@ -188,9 +147,8 @@ namespace {
initializeHexagonExpandCondsetsPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
- return "Hexagon Expand Condsets";
- }
+ StringRef getPassName() const override { return "Hexagon Expand Condsets"; }
+
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LiveIntervals>();
AU.addPreserved<LiveIntervals>();
@@ -199,6 +157,7 @@ namespace {
AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
+
bool runOnMachineFunction(MachineFunction &MF) override;
private:
@@ -207,7 +166,6 @@ namespace {
MachineDominatorTree *MDT;
MachineRegisterInfo *MRI;
LiveIntervals *LIS;
- std::set<MachineInstr*> LocalImpDefs;
bool CoaLimitActive, TfrLimitActive;
unsigned CoaLimit, TfrLimit, CoaCounter, TfrCounter;
@@ -216,6 +174,7 @@ namespace {
RegisterRef(const MachineOperand &Op) : Reg(Op.getReg()),
Sub(Op.getSubReg()) {}
RegisterRef(unsigned R = 0, unsigned S = 0) : Reg(R), Sub(S) {}
+
bool operator== (RegisterRef RR) const {
return Reg == RR.Reg && Sub == RR.Sub;
}
@@ -223,6 +182,7 @@ namespace {
bool operator< (RegisterRef RR) const {
return Reg < RR.Reg || (Reg == RR.Reg && Sub < RR.Sub);
}
+
unsigned Reg, Sub;
};
@@ -236,7 +196,6 @@ namespace {
void addRefToMap(RegisterRef RR, ReferenceMap &Map, unsigned Exec);
bool isRefInMap(RegisterRef, ReferenceMap &Map, unsigned Exec);
- void removeImpDefSegments(LiveRange &Range);
void updateDeadsInRange(unsigned Reg, LaneBitmask LM, LiveRange &Range);
void updateKillFlags(unsigned Reg);
void updateDeadFlags(unsigned Reg);
@@ -251,7 +210,6 @@ namespace {
unsigned DstSR, const MachineOperand &PredOp, bool PredSense,
bool ReadUndef, bool ImpUse);
bool split(MachineInstr &MI, std::set<unsigned> &UpdRegs);
- bool splitInBlock(MachineBasicBlock &B, std::set<unsigned> &UpdRegs);
bool isPredicable(MachineInstr *MI);
MachineInstr *getReachingDefForPred(RegisterRef RD,
@@ -272,12 +230,20 @@ namespace {
bool isIntReg(RegisterRef RR, unsigned &BW);
bool isIntraBlocks(LiveInterval &LI);
bool coalesceRegisters(RegisterRef R1, RegisterRef R2);
- bool coalesceSegments(MachineFunction &MF);
+ bool coalesceSegments(const SmallVectorImpl<MachineInstr*> &Condsets,
+ std::set<unsigned> &UpdRegs);
};
-}
+
+} // end anonymous namespace
char HexagonExpandCondsets::ID = 0;
+namespace llvm {
+
+ char &HexagonExpandCondsetsID = HexagonExpandCondsets::ID;
+
+} // end namespace llvm
+
INITIALIZE_PASS_BEGIN(HexagonExpandCondsets, "expand-condsets",
"Hexagon Expand Condsets", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
@@ -288,9 +254,11 @@ INITIALIZE_PASS_END(HexagonExpandCondsets, "expand-condsets",
unsigned HexagonExpandCondsets::getMaskForSub(unsigned Sub) {
switch (Sub) {
- case Hexagon::subreg_loreg:
+ case Hexagon::isub_lo:
+ case Hexagon::vsub_lo:
return Sub_Low;
- case Hexagon::subreg_hireg:
+ case Hexagon::isub_hi:
+ case Hexagon::vsub_hi:
return Sub_High;
case Hexagon::NoSubRegister:
return Sub_None;
@@ -305,21 +273,19 @@ bool HexagonExpandCondsets::isCondset(const MachineInstr &MI) {
case Hexagon::C2_muxii:
case Hexagon::C2_muxir:
case Hexagon::C2_muxri:
- case Hexagon::MUX64_rr:
+ case Hexagon::PS_pselect:
return true;
break;
}
return false;
}
-
LaneBitmask HexagonExpandCondsets::getLaneMask(unsigned Reg, unsigned Sub) {
assert(TargetRegisterInfo::isVirtualRegister(Reg));
return Sub != 0 ? TRI->getSubRegIndexLaneMask(Sub)
: MRI->getMaxLaneMaskForVReg(Reg);
}
-
void HexagonExpandCondsets::addRefToMap(RegisterRef RR, ReferenceMap &Map,
unsigned Exec) {
unsigned Mask = getMaskForSub(RR.Sub) | Exec;
@@ -330,7 +296,6 @@ void HexagonExpandCondsets::addRefToMap(RegisterRef RR, ReferenceMap &Map,
F->second |= Mask;
}
-
bool HexagonExpandCondsets::isRefInMap(RegisterRef RR, ReferenceMap &Map,
unsigned Exec) {
ReferenceMap::iterator F = Map.find(RR.Reg);
@@ -342,7 +307,6 @@ bool HexagonExpandCondsets::isRefInMap(RegisterRef RR, ReferenceMap &Map,
return false;
}
-
void HexagonExpandCondsets::updateKillFlags(unsigned Reg) {
auto KillAt = [this,Reg] (SlotIndex K, LaneBitmask LM) -> void {
// Set the <kill> flag on a use of Reg whose lane mask is contained in LM.
@@ -392,16 +356,6 @@ void HexagonExpandCondsets::updateKillFlags(unsigned Reg) {
}
}
-
-void HexagonExpandCondsets::removeImpDefSegments(LiveRange &Range) {
- auto StartImpDef = [this] (LiveRange::Segment &S) -> bool {
- return S.start.isRegister() &&
- LocalImpDefs.count(LIS->getInstructionFromIndex(S.start));
- };
- Range.segments.erase(std::remove_if(Range.begin(), Range.end(), StartImpDef),
- Range.end());
-}
-
void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
LiveRange &Range) {
assert(TargetRegisterInfo::isVirtualRegister(Reg));
@@ -415,7 +369,7 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
if (!TargetRegisterInfo::isVirtualRegister(DR) || DR != Reg)
return false;
LaneBitmask SLM = getLaneMask(DR, DSR);
- return (SLM & LM) != 0;
+ return (SLM & LM).any();
};
// The splitting step will create pairs of predicated definitions without
@@ -425,7 +379,6 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
// We need to identify predicated defs that need implicit uses, and
// dead defs that are not really dead, and correct both problems.
- SetVector<MachineBasicBlock*> Defs;
auto Dominate = [this] (SetVector<MachineBasicBlock*> &Defs,
MachineBasicBlock *Dest) -> bool {
for (MachineBasicBlock *D : Defs)
@@ -449,20 +402,25 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
// First, try to extend live range within individual basic blocks. This
// will leave us only with dead defs that do not reach any predicated
// defs in the same block.
+ SetVector<MachineBasicBlock*> Defs;
SmallVector<SlotIndex,4> PredDefs;
for (auto &Seg : Range) {
if (!Seg.start.isRegister())
continue;
MachineInstr *DefI = LIS->getInstructionFromIndex(Seg.start);
- if (LocalImpDefs.count(DefI))
- continue;
Defs.insert(DefI->getParent());
if (HII->isPredicated(*DefI))
PredDefs.push_back(Seg.start);
}
+
+ SmallVector<SlotIndex,8> Undefs;
+ LiveInterval &LI = LIS->getInterval(Reg);
+ LI.computeSubRangeUndefs(Undefs, LM, *MRI, *LIS->getSlotIndexes());
+
for (auto &SI : PredDefs) {
MachineBasicBlock *BB = LIS->getMBBFromIndex(SI);
- if (Range.extendInBlock(LIS->getMBBStartIdx(BB), SI))
+ auto P = Range.extendInBlock(Undefs, LIS->getMBBStartIdx(BB), SI);
+ if (P.first != nullptr || P.second)
SI = SlotIndex();
}
@@ -476,10 +434,21 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
if (BB->pred_empty())
continue;
// If the defs from this range reach SI via all predecessors, it is live.
+ // It can happen that SI is reached by the defs through some paths, but
+ // not all. In the IR coming into this optimization, SI would not be
+ // considered live, since the defs would then not jointly dominate SI.
+ // That means that SI is an overwriting def, and no implicit use is
+ // needed at this point. Do not add SI to the extension points, since
+ // extendToIndices will abort if there is no joint dominance.
+ // If the abort was avoided by adding extra undefs added to Undefs,
+ // extendToIndices could actually indicate that SI is live, contrary
+ // to the original IR.
if (Dominate(Defs, BB))
ExtTo.push_back(SI);
}
- LIS->extendToIndices(Range, ExtTo);
+
+ if (!ExtTo.empty())
+ LIS->extendToIndices(Range, ExtTo, Undefs);
// Remove <dead> flags from all defs that are not dead after live range
// extension, and collect all def operands. They will be used to generate
@@ -489,8 +458,6 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
if (!Seg.start.isRegister())
continue;
MachineInstr *DefI = LIS->getInstructionFromIndex(Seg.start);
- if (LocalImpDefs.count(DefI))
- continue;
for (auto &Op : DefI->operands()) {
if (Seg.start.isDead() || !IsRegDef(Op))
continue;
@@ -499,40 +466,34 @@ void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM,
}
}
-
// Finally, add implicit uses to each predicated def that is reached
- // by other defs. Remove segments started by implicit-defs first, since
- // they do not define registers.
- removeImpDefSegments(Range);
-
+ // by other defs.
for (auto &Seg : Range) {
if (!Seg.start.isRegister() || !Range.liveAt(Seg.start.getPrevSlot()))
continue;
MachineInstr *DefI = LIS->getInstructionFromIndex(Seg.start);
if (!HII->isPredicated(*DefI))
continue;
- MachineFunction &MF = *DefI->getParent()->getParent();
// Construct the set of all necessary implicit uses, based on the def
// operands in the instruction.
std::set<RegisterRef> ImpUses;
for (auto &Op : DefI->operands())
if (Op.isReg() && Op.isDef() && DefRegs.count(Op))
ImpUses.insert(Op);
+ if (ImpUses.empty())
+ continue;
+ MachineFunction &MF = *DefI->getParent()->getParent();
for (RegisterRef R : ImpUses)
MachineInstrBuilder(MF, DefI).addReg(R.Reg, RegState::Implicit, R.Sub);
}
}
-
void HexagonExpandCondsets::updateDeadFlags(unsigned Reg) {
LiveInterval &LI = LIS->getInterval(Reg);
if (LI.hasSubRanges()) {
for (LiveInterval::SubRange &S : LI.subranges()) {
updateDeadsInRange(Reg, S.LaneMask, S);
LIS->shrinkToUses(S, Reg);
- // LI::shrinkToUses will add segments started by implicit-defs.
- // Remove them again.
- removeImpDefSegments(S);
}
LI.clear();
LIS->constructMainRangeFromSubranges(LI);
@@ -541,7 +502,6 @@ void HexagonExpandCondsets::updateDeadFlags(unsigned Reg) {
}
}
-
void HexagonExpandCondsets::recalculateLiveInterval(unsigned Reg) {
LIS->removeInterval(Reg);
LIS->createAndComputeVirtRegInterval(Reg);
@@ -552,7 +512,6 @@ void HexagonExpandCondsets::removeInstr(MachineInstr &MI) {
MI.eraseFromParent();
}
-
void HexagonExpandCondsets::updateLiveness(std::set<unsigned> &RegSet,
bool Recalc, bool UpdateKills, bool UpdateDeads) {
UpdateKills |= UpdateDeads;
@@ -571,12 +530,12 @@ void HexagonExpandCondsets::updateLiveness(std::set<unsigned> &RegSet,
}
}
-
/// Get the opcode for a conditional transfer of the value in SO (source
/// operand). The condition (true/false) is given in Cond.
unsigned HexagonExpandCondsets::getCondTfrOpcode(const MachineOperand &SO,
bool IfTrue) {
using namespace Hexagon;
+
if (SO.isReg()) {
unsigned PhysR;
RegisterRef RS = SO;
@@ -603,7 +562,6 @@ unsigned HexagonExpandCondsets::getCondTfrOpcode(const MachineOperand &SO,
llvm_unreachable("Unexpected source operand");
}
-
/// Generate a conditional transfer, copying the value SrcOp to the
/// destination register DstR:DstSR, and using the predicate register from
/// PredOp. The Cond argument specifies whether the predicate is to be
@@ -623,19 +581,29 @@ MachineInstr *HexagonExpandCondsets::genCondTfrFor(MachineOperand &SrcOp,
/// predicate.
unsigned Opc = getCondTfrOpcode(SrcOp, PredSense);
- unsigned State = RegState::Define | (ReadUndef ? RegState::Undef : 0);
- MachineInstrBuilder MIB = BuildMI(B, At, DL, HII->get(Opc))
- .addReg(DstR, State, DstSR)
- .addOperand(PredOp)
- .addOperand(SrcOp);
-
- // We don't want any kills yet.
- MIB->clearKillInfo();
+ unsigned DstState = RegState::Define | (ReadUndef ? RegState::Undef : 0);
+ unsigned PredState = getRegState(PredOp) & ~RegState::Kill;
+ MachineInstrBuilder MIB;
+
+ if (SrcOp.isReg()) {
+ unsigned SrcState = getRegState(SrcOp);
+ if (RegisterRef(SrcOp) == RegisterRef(DstR, DstSR))
+ SrcState &= ~RegState::Kill;
+ MIB = BuildMI(B, At, DL, HII->get(Opc))
+ .addReg(DstR, DstState, DstSR)
+ .addReg(PredOp.getReg(), PredState, PredOp.getSubReg())
+ .addReg(SrcOp.getReg(), SrcState, SrcOp.getSubReg());
+ } else {
+ MIB = BuildMI(B, At, DL, HII->get(Opc))
+ .addReg(DstR, DstState, DstSR)
+ .addReg(PredOp.getReg(), PredState, PredOp.getSubReg())
+ .addOperand(SrcOp);
+ }
+
DEBUG(dbgs() << "created an initial copy: " << *MIB);
return &*MIB;
}
-
/// Replace a MUX instruction MI with a pair A2_tfrt/A2_tfrf. This function
/// performs all necessary changes to complete the replacement.
bool HexagonExpandCondsets::split(MachineInstr &MI,
@@ -649,44 +617,36 @@ bool HexagonExpandCondsets::split(MachineInstr &MI,
<< MI);
MachineOperand &MD = MI.getOperand(0); // Definition
MachineOperand &MP = MI.getOperand(1); // Predicate register
- MachineOperand &MS1 = MI.getOperand(2); // Source value #1
- MachineOperand &MS2 = MI.getOperand(3); // Source value #2
assert(MD.isDef());
unsigned DR = MD.getReg(), DSR = MD.getSubReg();
bool ReadUndef = MD.isUndef();
MachineBasicBlock::iterator At = MI;
- if (ReadUndef && DSR != 0 && MRI->shouldTrackSubRegLiveness(DR)) {
- unsigned NewSR = 0;
- MachineBasicBlock::iterator DefAt = At;
- bool SameReg = (MS1.isReg() && DR == MS1.getReg()) ||
- (MS2.isReg() && DR == MS2.getReg());
- if (SameReg) {
- NewSR = (DSR == Hexagon::subreg_loreg) ? Hexagon::subreg_hireg
- : Hexagon::subreg_loreg;
- // Advance the insertion point if the subregisters differ between
- // the source and the target (with the same super-register).
- // Note: this case has never occured during tests.
- if ((MS1.isReg() && NewSR == MS1.getSubReg()) ||
- (MS2.isReg() && NewSR == MS2.getSubReg()))
- ++DefAt;
+ // If this is a mux of the same register, just replace it with COPY.
+ // Ideally, this would happen earlier, so that register coalescing would
+ // see it.
+ MachineOperand &ST = MI.getOperand(2);
+ MachineOperand &SF = MI.getOperand(3);
+ if (ST.isReg() && SF.isReg()) {
+ RegisterRef RT(ST);
+ if (RT == RegisterRef(SF)) {
+ MI.setDesc(HII->get(TargetOpcode::COPY));
+ unsigned S = getRegState(ST);
+ while (MI.getNumOperands() > 1)
+ MI.RemoveOperand(MI.getNumOperands()-1);
+ MachineFunction &MF = *MI.getParent()->getParent();
+ MachineInstrBuilder(MF, MI).addReg(RT.Reg, S, RT.Sub);
+ return true;
}
- // Use "At", since "DefAt" may be end().
- MachineBasicBlock &B = *At->getParent();
- DebugLoc DL = At->getDebugLoc();
- auto ImpD = BuildMI(B, DefAt, DL, HII->get(TargetOpcode::IMPLICIT_DEF))
- .addReg(DR, RegState::Define, NewSR);
- LIS->InsertMachineInstrInMaps(*ImpD);
- LocalImpDefs.insert(&*ImpD);
}
// First, create the two invididual conditional transfers, and add each
// of them to the live intervals information. Do that first and then remove
// the old instruction from live intervals.
MachineInstr *TfrT =
- genCondTfrFor(MI.getOperand(2), At, DR, DSR, MP, true, ReadUndef, false);
+ genCondTfrFor(ST, At, DR, DSR, MP, true, ReadUndef, false);
MachineInstr *TfrF =
- genCondTfrFor(MI.getOperand(3), At, DR, DSR, MP, false, ReadUndef, true);
+ genCondTfrFor(SF, At, DR, DSR, MP, false, ReadUndef, true);
LIS->InsertMachineInstrInMaps(*TfrT);
LIS->InsertMachineInstrInMaps(*TfrF);
@@ -699,22 +659,6 @@ bool HexagonExpandCondsets::split(MachineInstr &MI,
return true;
}
-
-/// Split all MUX instructions in the given block into pairs of conditional
-/// transfers.
-bool HexagonExpandCondsets::splitInBlock(MachineBasicBlock &B,
- std::set<unsigned> &UpdRegs) {
- bool Changed = false;
- MachineBasicBlock::iterator I, E, NextI;
- for (I = B.begin(), E = B.end(); I != E; I = NextI) {
- NextI = std::next(I);
- if (isCondset(*I))
- Changed |= split(*I, UpdRegs);
- }
- return Changed;
-}
-
-
bool HexagonExpandCondsets::isPredicable(MachineInstr *MI) {
if (HII->isPredicated(*MI) || !HII->isPredicable(*MI))
return false;
@@ -735,7 +679,6 @@ bool HexagonExpandCondsets::isPredicable(MachineInstr *MI) {
return true;
}
-
/// Find the reaching definition for a predicated use of RD. The RD is used
/// under the conditions given by PredR and Cond, and this function will ignore
/// definitions that set RD under the opposite conditions.
@@ -744,7 +687,7 @@ MachineInstr *HexagonExpandCondsets::getReachingDefForPred(RegisterRef RD,
MachineBasicBlock &B = *UseIt->getParent();
MachineBasicBlock::iterator I = UseIt, S = B.begin();
if (I == S)
- return 0;
+ return nullptr;
bool PredValid = true;
do {
@@ -775,15 +718,14 @@ MachineInstr *HexagonExpandCondsets::getReachingDefForPred(RegisterRef RD,
if (RR.Sub == RD.Sub)
return MI;
if (RR.Sub == 0 || RD.Sub == 0)
- return 0;
+ return nullptr;
// We have different subregisters, so we can continue looking.
}
} while (I != S);
- return 0;
+ return nullptr;
}
-
/// Check if the instruction MI can be safely moved over a set of instructions
/// whose side-effects (in terms of register defs and uses) are expressed in
/// the maps Defs and Uses. These maps reflect the conditional defs and uses
@@ -813,7 +755,6 @@ bool HexagonExpandCondsets::canMoveOver(MachineInstr &MI, ReferenceMap &Defs,
return true;
}
-
/// Check if the instruction accessing memory (TheI) can be moved to the
/// location ToI.
bool HexagonExpandCondsets::canMoveMemTo(MachineInstr &TheI, MachineInstr &ToI,
@@ -848,7 +789,6 @@ bool HexagonExpandCondsets::canMoveMemTo(MachineInstr &TheI, MachineInstr &ToI,
return true;
}
-
/// Generate a predicated version of MI (where the condition is given via
/// PredR and Cond) at the point indicated by Where.
void HexagonExpandCondsets::predicateAt(const MachineOperand &DefOp,
@@ -909,7 +849,6 @@ void HexagonExpandCondsets::predicateAt(const MachineOperand &DefOp,
UpdRegs.insert(Op.getReg());
}
-
/// In the range [First, Last], rename all references to the "old" register RO
/// to the "new" register RN, but only in instructions predicated on the given
/// condition.
@@ -937,7 +876,6 @@ void HexagonExpandCondsets::renameInRange(RegisterRef RO, RegisterRef RN,
}
}
-
/// For a given conditional copy, predicate the definition of the source of
/// the copy under the given condition (using the same predicate register as
/// the copy).
@@ -982,7 +920,7 @@ bool HexagonExpandCondsets::predicate(MachineInstr &TfrI, bool Cond,
// conditions when collecting def and use information.
bool PredValid = true;
for (MachineBasicBlock::iterator I = std::next(DefIt); I != TfrIt; ++I) {
- if (!I->modifiesRegister(PredR, 0))
+ if (!I->modifiesRegister(PredR, nullptr))
continue;
PredValid = false;
break;
@@ -1013,6 +951,13 @@ bool HexagonExpandCondsets::predicate(MachineInstr &TfrI, bool Cond,
return false;
ReferenceMap &Map = Op.isDef() ? Defs : Uses;
+ if (Op.isDef() && Op.isUndef()) {
+ assert(RR.Sub && "Expecting a subregister on <def,read-undef>");
+ // If this is a <def,read-undef>, then it invalidates the non-written
+ // part of the register. For the purpose of checking the validity of
+ // the move, assume that it modifies the whole register.
+ RR.Sub = 0;
+ }
addRefToMap(RR, Map, Exec);
}
}
@@ -1067,7 +1012,6 @@ bool HexagonExpandCondsets::predicate(MachineInstr &TfrI, bool Cond,
return true;
}
-
/// Predicate all cases of conditional copies in the specified block.
bool HexagonExpandCondsets::predicateInBlock(MachineBasicBlock &B,
std::set<unsigned> &UpdRegs) {
@@ -1094,7 +1038,6 @@ bool HexagonExpandCondsets::predicateInBlock(MachineBasicBlock &B,
return Changed;
}
-
bool HexagonExpandCondsets::isIntReg(RegisterRef RR, unsigned &BW) {
if (!TargetRegisterInfo::isVirtualRegister(RR.Reg))
return false;
@@ -1110,7 +1053,6 @@ bool HexagonExpandCondsets::isIntReg(RegisterRef RR, unsigned &BW) {
return false;
}
-
bool HexagonExpandCondsets::isIntraBlocks(LiveInterval &LI) {
for (LiveInterval::iterator I = LI.begin(), E = LI.end(); I != E; ++I) {
LiveRange::Segment &LR = *I;
@@ -1124,7 +1066,6 @@ bool HexagonExpandCondsets::isIntraBlocks(LiveInterval &LI) {
return true;
}
-
bool HexagonExpandCondsets::coalesceRegisters(RegisterRef R1, RegisterRef R2) {
if (CoaLimitActive) {
if (CoaCounter >= CoaLimit)
@@ -1141,6 +1082,10 @@ bool HexagonExpandCondsets::coalesceRegisters(RegisterRef R1, RegisterRef R2) {
LiveInterval &L1 = LIS->getInterval(R1.Reg);
LiveInterval &L2 = LIS->getInterval(R2.Reg);
+ if (L2.empty())
+ return false;
+ if (L1.hasSubRanges() || L2.hasSubRanges())
+ return false;
bool Overlap = L1.overlaps(L2);
DEBUG(dbgs() << "compatible registers: ("
@@ -1176,6 +1121,7 @@ bool HexagonExpandCondsets::coalesceRegisters(RegisterRef R1, RegisterRef R2) {
}
while (L2.begin() != L2.end())
L2.removeSegment(*L2.begin());
+ LIS->removeInterval(R2.Reg);
updateKillFlags(R1.Reg);
DEBUG(dbgs() << "coalesced: " << L1 << "\n");
@@ -1184,28 +1130,22 @@ bool HexagonExpandCondsets::coalesceRegisters(RegisterRef R1, RegisterRef R2) {
return true;
}
-
-/// Attempt to coalesce one of the source registers to a MUX intruction with
+/// Attempt to coalesce one of the source registers to a MUX instruction with
/// the destination register. This could lead to having only one predicated
/// instruction in the end instead of two.
-bool HexagonExpandCondsets::coalesceSegments(MachineFunction &MF) {
- SmallVector<MachineInstr*,16> Condsets;
- for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) {
- MachineBasicBlock &B = *I;
- for (MachineBasicBlock::iterator J = B.begin(), F = B.end(); J != F; ++J) {
- MachineInstr *MI = &*J;
- if (!isCondset(*MI))
- continue;
- MachineOperand &S1 = MI->getOperand(2), &S2 = MI->getOperand(3);
- if (!S1.isReg() && !S2.isReg())
- continue;
- Condsets.push_back(MI);
- }
+bool HexagonExpandCondsets::coalesceSegments(
+ const SmallVectorImpl<MachineInstr*> &Condsets,
+ std::set<unsigned> &UpdRegs) {
+ SmallVector<MachineInstr*,16> TwoRegs;
+ for (MachineInstr *MI : Condsets) {
+ MachineOperand &S1 = MI->getOperand(2), &S2 = MI->getOperand(3);
+ if (!S1.isReg() && !S2.isReg())
+ continue;
+ TwoRegs.push_back(MI);
}
bool Changed = false;
- for (unsigned i = 0, n = Condsets.size(); i < n; ++i) {
- MachineInstr *CI = Condsets[i];
+ for (MachineInstr *CI : TwoRegs) {
RegisterRef RD = CI->getOperand(0);
RegisterRef RP = CI->getOperand(1);
MachineOperand &S1 = CI->getOperand(2), &S2 = CI->getOperand(3);
@@ -1231,21 +1171,30 @@ bool HexagonExpandCondsets::coalesceSegments(MachineFunction &MF) {
if (S1.isReg()) {
RegisterRef RS = S1;
MachineInstr *RDef = getReachingDefForPred(RS, CI, RP.Reg, true);
- if (!RDef || !HII->isPredicable(*RDef))
+ if (!RDef || !HII->isPredicable(*RDef)) {
Done = coalesceRegisters(RD, RegisterRef(S1));
+ if (Done) {
+ UpdRegs.insert(RD.Reg);
+ UpdRegs.insert(S1.getReg());
+ }
+ }
}
if (!Done && S2.isReg()) {
RegisterRef RS = S2;
MachineInstr *RDef = getReachingDefForPred(RS, CI, RP.Reg, false);
- if (!RDef || !HII->isPredicable(*RDef))
+ if (!RDef || !HII->isPredicable(*RDef)) {
Done = coalesceRegisters(RD, RegisterRef(S2));
+ if (Done) {
+ UpdRegs.insert(RD.Reg);
+ UpdRegs.insert(S2.getReg());
+ }
+ }
}
Changed |= Done;
}
return Changed;
}
-
bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
@@ -1255,25 +1204,54 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
MDT = &getAnalysis<MachineDominatorTree>();
LIS = &getAnalysis<LiveIntervals>();
MRI = &MF.getRegInfo();
- LocalImpDefs.clear();
DEBUG(LIS->print(dbgs() << "Before expand-condsets\n",
MF.getFunction()->getParent()));
bool Changed = false;
- std::set<unsigned> SplitUpd, PredUpd;
+ std::set<unsigned> CoalUpd, PredUpd;
+
+ SmallVector<MachineInstr*,16> Condsets;
+ for (auto &B : MF)
+ for (auto &I : B)
+ if (isCondset(I))
+ Condsets.push_back(&I);
// Try to coalesce the target of a mux with one of its sources.
// This could eliminate a register copy in some circumstances.
- Changed |= coalesceSegments(MF);
+ Changed |= coalesceSegments(Condsets, CoalUpd);
+
+ // Update kill flags on all source operands. This is done here because
+ // at this moment (when expand-condsets runs), there are no kill flags
+ // in the IR (they have been removed by live range analysis).
+ // Updating them right before we split is the easiest, because splitting
+ // adds definitions which would interfere with updating kills afterwards.
+ std::set<unsigned> KillUpd;
+ for (MachineInstr *MI : Condsets)
+ for (MachineOperand &Op : MI->operands())
+ if (Op.isReg() && Op.isUse())
+ if (!CoalUpd.count(Op.getReg()))
+ KillUpd.insert(Op.getReg());
+ updateLiveness(KillUpd, false, true, false);
+ DEBUG(LIS->print(dbgs() << "After coalescing\n",
+ MF.getFunction()->getParent()));
// First, simply split all muxes into a pair of conditional transfers
// and update the live intervals to reflect the new arrangement. The
// goal is to update the kill flags, since predication will rely on
// them.
- for (auto &B : MF)
- Changed |= splitInBlock(B, SplitUpd);
- updateLiveness(SplitUpd, true, true, false);
+ for (MachineInstr *MI : Condsets)
+ Changed |= split(*MI, PredUpd);
+ Condsets.clear(); // The contents of Condsets are invalid here anyway.
+
+ // Do not update live ranges after splitting. Recalculation of live
+ // intervals removes kill flags, which were preserved by splitting on
+ // the source operands of condsets. These kill flags are needed by
+ // predication, and after splitting they are difficult to recalculate
+ // (because of predicated defs), so make sure they are left untouched.
+ // Predication does not use live intervals.
+ DEBUG(LIS->print(dbgs() << "After splitting\n",
+ MF.getFunction()->getParent()));
// Traverse all blocks and collapse predicable instructions feeding
// conditional transfers into predicated instructions.
@@ -1281,18 +1259,11 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
// cases that were not created in the previous step.
for (auto &B : MF)
Changed |= predicateInBlock(B, PredUpd);
+ DEBUG(LIS->print(dbgs() << "After predicating\n",
+ MF.getFunction()->getParent()));
+ PredUpd.insert(CoalUpd.begin(), CoalUpd.end());
updateLiveness(PredUpd, true, true, true);
- // Remove from SplitUpd all registers contained in PredUpd to avoid
- // unnecessary liveness recalculation.
- std::set<unsigned> Diff;
- std::set_difference(SplitUpd.begin(), SplitUpd.end(),
- PredUpd.begin(), PredUpd.end(),
- std::inserter(Diff, Diff.begin()));
- updateLiveness(Diff, false, false, true);
-
- for (auto *ImpD : LocalImpDefs)
- removeInstr(*ImpD);
DEBUG({
if (Changed)
@@ -1303,7 +1274,6 @@ bool HexagonExpandCondsets::runOnMachineFunction(MachineFunction &MF) {
return Changed;
}
-
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp
index 3de817c..dfd1f1d 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonFixupHwLoops.cpp
@@ -47,10 +47,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon Hardware Loop Fixup";
}
@@ -125,7 +125,7 @@ bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
BlockToInstOffset[&MBB] = InstOffset;
for (const MachineInstr &MI : MBB)
- InstOffset += HII->getSize(&MI);
+ InstOffset += HII->getSize(MI);
}
// Second pass - check each loop instruction to see if it needs to be
@@ -138,7 +138,7 @@ bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
MachineBasicBlock::iterator MII = MBB.begin();
MachineBasicBlock::iterator MIE = MBB.end();
while (MII != MIE) {
- InstOffset += HII->getSize(&*MII);
+ InstOffset += HII->getSize(*MII);
if (MII->isDebugValue()) {
++MII;
continue;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
index 2540214..a3f6273 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
@@ -17,25 +17,51 @@
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
+#include "MCTargetDesc/HexagonBaseInfo.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/LivePhysRegs.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachinePostDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/Type.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <map>
+#include <new>
+#include <utility>
+#include <vector>
// Hexagon stack frame layout as defined by the ABI:
//
@@ -99,27 +125,26 @@
// cated (reserved) register, it needs to be kept live throughout the function
// to be available as the base register for local object accesses.
// Normally, an address of a stack objects is obtained by a pseudo-instruction
-// TFR_FI. To access local objects with the AP register present, a different
-// pseudo-instruction needs to be used: TFR_FIA. The TFR_FIA takes one extra
-// argument compared to TFR_FI: the first input register is the AP register.
+// PS_fi. To access local objects with the AP register present, a different
+// pseudo-instruction needs to be used: PS_fia. The PS_fia takes one extra
+// argument compared to PS_fi: the first input register is the AP register.
// This keeps the register live between its definition and its uses.
-// The AP register is originally set up using pseudo-instruction ALIGNA:
-// AP = ALIGNA A
+// The AP register is originally set up using pseudo-instruction PS_aligna:
+// AP = PS_aligna A
// where
// A - required stack alignment
// The alignment value must be the maximum of all alignments required by
// any stack object.
-// The dynamic allocation uses a pseudo-instruction ALLOCA:
-// Rd = ALLOCA Rs, A
+// The dynamic allocation uses a pseudo-instruction PS_alloca:
+// Rd = PS_alloca Rs, A
// where
// Rd - address of the allocated space
// Rs - minimum size (the actual allocated can be larger to accommodate
// alignment)
// A - required alignment
-
using namespace llvm;
static cl::opt<bool> DisableDeallocRet("disable-hexagon-dealloc-ret",
@@ -145,9 +170,13 @@ static cl::opt<bool> EnableShrinkWrapping("hexagon-shrink-frame",
cl::init(true), cl::Hidden, cl::ZeroOrMore,
cl::desc("Enable stack frame shrink wrapping"));
-static cl::opt<unsigned> ShrinkLimit("shrink-frame-limit", cl::init(UINT_MAX),
- cl::Hidden, cl::ZeroOrMore, cl::desc("Max count of stack frame "
- "shrink-wraps"));
+static cl::opt<unsigned> ShrinkLimit("shrink-frame-limit",
+ cl::init(std::numeric_limits<unsigned>::max()), cl::Hidden, cl::ZeroOrMore,
+ cl::desc("Max count of stack frame shrink-wraps"));
+
+static cl::opt<bool> EnableSaveRestoreLong("enable-save-restore-long",
+ cl::Hidden, cl::desc("Enable long calls for save-restore stubs."),
+ cl::init(false), cl::ZeroOrMore);
static cl::opt<bool> UseAllocframe("use-allocframe", cl::init(true),
cl::Hidden, cl::desc("Use allocframe more conservatively"));
@@ -155,29 +184,41 @@ static cl::opt<bool> UseAllocframe("use-allocframe", cl::init(true),
static cl::opt<bool> OptimizeSpillSlots("hexagon-opt-spill", cl::Hidden,
cl::init(true), cl::desc("Optimize spill slots"));
+#ifndef NDEBUG
+static cl::opt<unsigned> SpillOptMax("spill-opt-max", cl::Hidden,
+ cl::init(std::numeric_limits<unsigned>::max()));
+static unsigned SpillOptCount = 0;
+#endif
namespace llvm {
+
void initializeHexagonCallFrameInformationPass(PassRegistry&);
FunctionPass *createHexagonCallFrameInformation();
-}
+
+} // end namespace llvm
namespace {
+
class HexagonCallFrameInformation : public MachineFunctionPass {
public:
static char ID;
+
HexagonCallFrameInformation() : MachineFunctionPass(ID) {
PassRegistry &PR = *PassRegistry::getPassRegistry();
initializeHexagonCallFrameInformationPass(PR);
}
+
bool runOnMachineFunction(MachineFunction &MF) override;
+
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
};
char HexagonCallFrameInformation::ID = 0;
-}
+
+} // end anonymous namespace
bool HexagonCallFrameInformation::runOnMachineFunction(MachineFunction &MF) {
auto &HFI = *MF.getSubtarget<HexagonSubtarget>().getFrameLowering();
@@ -197,12 +238,11 @@ FunctionPass *llvm::createHexagonCallFrameInformation() {
return new HexagonCallFrameInformation();
}
-
-namespace {
- /// Map a register pair Reg to the subregister that has the greater "number",
- /// i.e. D3 (aka R7:6) will be mapped to R7, etc.
- unsigned getMax32BitSubRegister(unsigned Reg, const TargetRegisterInfo &TRI,
- bool hireg = true) {
+/// Map a register pair Reg to the subregister that has the greater "number",
+/// i.e. D3 (aka R7:6) will be mapped to R7, etc.
+static unsigned getMax32BitSubRegister(unsigned Reg,
+ const TargetRegisterInfo &TRI,
+ bool hireg = true) {
if (Reg < Hexagon::D0 || Reg > Hexagon::D15)
return Reg;
@@ -217,11 +257,11 @@ namespace {
}
}
return RegNo;
- }
+}
- /// Returns the callee saved register with the largest id in the vector.
- unsigned getMaxCalleeSavedReg(const std::vector<CalleeSavedInfo> &CSI,
- const TargetRegisterInfo &TRI) {
+/// Returns the callee saved register with the largest id in the vector.
+static unsigned getMaxCalleeSavedReg(const std::vector<CalleeSavedInfo> &CSI,
+ const TargetRegisterInfo &TRI) {
static_assert(Hexagon::R1 > 0,
"Assume physical registers are encoded as positive integers");
if (CSI.empty())
@@ -234,20 +274,20 @@ namespace {
Max = Reg;
}
return Max;
- }
+}
- /// Checks if the basic block contains any instruction that needs a stack
- /// frame to be already in place.
- bool needsStackFrame(const MachineBasicBlock &MBB, const BitVector &CSR,
- const HexagonRegisterInfo &HRI) {
+/// Checks if the basic block contains any instruction that needs a stack
+/// frame to be already in place.
+static bool needsStackFrame(const MachineBasicBlock &MBB, const BitVector &CSR,
+ const HexagonRegisterInfo &HRI) {
for (auto &I : MBB) {
const MachineInstr *MI = &I;
if (MI->isCall())
return true;
unsigned Opc = MI->getOpcode();
switch (Opc) {
- case Hexagon::ALLOCA:
- case Hexagon::ALIGNA:
+ case Hexagon::PS_alloca:
+ case Hexagon::PS_aligna:
return true;
default:
break;
@@ -274,60 +314,62 @@ namespace {
}
}
return false;
- }
+}
/// Returns true if MBB has a machine instructions that indicates a tail call
/// in the block.
- bool hasTailCall(const MachineBasicBlock &MBB) {
+static bool hasTailCall(const MachineBasicBlock &MBB) {
MachineBasicBlock::const_iterator I = MBB.getLastNonDebugInstr();
unsigned RetOpc = I->getOpcode();
- return RetOpc == Hexagon::TCRETURNi || RetOpc == Hexagon::TCRETURNr;
- }
+ return RetOpc == Hexagon::PS_tailcall_i || RetOpc == Hexagon::PS_tailcall_r;
+}
- /// Returns true if MBB contains an instruction that returns.
- bool hasReturn(const MachineBasicBlock &MBB) {
+/// Returns true if MBB contains an instruction that returns.
+static bool hasReturn(const MachineBasicBlock &MBB) {
for (auto I = MBB.getFirstTerminator(), E = MBB.end(); I != E; ++I)
if (I->isReturn())
return true;
return false;
- }
+}
- /// Returns the "return" instruction from this block, or nullptr if there
- /// isn't any.
- MachineInstr *getReturn(MachineBasicBlock &MBB) {
+/// Returns the "return" instruction from this block, or nullptr if there
+/// isn't any.
+static MachineInstr *getReturn(MachineBasicBlock &MBB) {
for (auto &I : MBB)
if (I.isReturn())
return &I;
return nullptr;
- }
+}
- bool isRestoreCall(unsigned Opc) {
+static bool isRestoreCall(unsigned Opc) {
switch (Opc) {
case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC:
+ case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT:
+ case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC:
+ case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT:
+ case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC:
case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4:
case Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC:
return true;
}
return false;
- }
+}
- inline bool isOptNone(const MachineFunction &MF) {
+static inline bool isOptNone(const MachineFunction &MF) {
return MF.getFunction()->hasFnAttribute(Attribute::OptimizeNone) ||
MF.getTarget().getOptLevel() == CodeGenOpt::None;
- }
+}
- inline bool isOptSize(const MachineFunction &MF) {
+static inline bool isOptSize(const MachineFunction &MF) {
const Function &F = *MF.getFunction();
return F.optForSize() && !F.optForMinSize();
- }
+}
- inline bool isMinSize(const MachineFunction &MF) {
+static inline bool isMinSize(const MachineFunction &MF) {
return MF.getFunction()->optForMinSize();
- }
}
-
/// Implements shrink-wrapping of the stack frame. By default, stack frame
/// is created in the function entry block, and is cleaned up in every block
/// that returns. This function finds alternate blocks: one for the frame
@@ -342,7 +384,7 @@ void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
ShrinkCounter++;
}
- auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HRI = *HST.getRegisterInfo();
MachineDominatorTree MDT;
@@ -432,7 +474,6 @@ void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
EpilogB = PDomB;
}
-
/// Perform most of the PEI work here:
/// - saving/restoring of the callee-saved registers,
/// - stack frame creation and destruction.
@@ -440,11 +481,11 @@ void HexagonFrameLowering::findShrunkPrologEpilog(MachineFunction &MF,
/// in one place allows shrink-wrapping of the stack frame.
void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HRI = *HST.getRegisterInfo();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
MachineBasicBlock *PrologB = &MF.front(), *EpilogB = nullptr;
if (EnableShrinkWrapping)
@@ -453,6 +494,7 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
bool PrologueStubs = false;
insertCSRSpillsInBlock(*PrologB, CSI, HRI, PrologueStubs);
insertPrologueInBlock(*PrologB, PrologueStubs);
+ updateEntryPaths(MF, *PrologB);
if (EpilogB) {
insertCSRRestoresInBlock(*EpilogB, CSI, HRI);
@@ -481,50 +523,49 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
// If there is an epilog block, it may not have a return instruction.
// In such case, we need to add the callee-saved registers as live-ins
// in all blocks on all paths from the epilog to any return block.
- unsigned MaxBN = 0;
- for (auto &B : MF)
- if (B.getNumber() >= 0)
- MaxBN = std::max(MaxBN, unsigned(B.getNumber()));
+ unsigned MaxBN = MF.getNumBlockIDs();
BitVector DoneT(MaxBN+1), DoneF(MaxBN+1), Path(MaxBN+1);
- updateExitPaths(*EpilogB, EpilogB, DoneT, DoneF, Path);
+ updateExitPaths(*EpilogB, *EpilogB, DoneT, DoneF, Path);
}
}
-
void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
bool PrologueStubs) const {
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HII = *HST.getInstrInfo();
auto &HRI = *HST.getRegisterInfo();
DebugLoc dl;
- unsigned MaxAlign = std::max(MFI->getMaxAlignment(), getStackAlignment());
+ unsigned MaxAlign = std::max(MFI.getMaxAlignment(), getStackAlignment());
// Calculate the total stack frame size.
// Get the number of bytes to allocate from the FrameInfo.
- unsigned FrameSize = MFI->getStackSize();
+ unsigned FrameSize = MFI.getStackSize();
// Round up the max call frame size to the max alignment on the stack.
- unsigned MaxCFA = alignTo(MFI->getMaxCallFrameSize(), MaxAlign);
- MFI->setMaxCallFrameSize(MaxCFA);
+ unsigned MaxCFA = alignTo(MFI.getMaxCallFrameSize(), MaxAlign);
+ MFI.setMaxCallFrameSize(MaxCFA);
FrameSize = MaxCFA + alignTo(FrameSize, MaxAlign);
- MFI->setStackSize(FrameSize);
+ MFI.setStackSize(FrameSize);
bool AlignStack = (MaxAlign > getStackAlignment());
// Get the number of bytes to allocate from the FrameInfo.
- unsigned NumBytes = MFI->getStackSize();
+ unsigned NumBytes = MFI.getStackSize();
unsigned SP = HRI.getStackRegister();
- unsigned MaxCF = MFI->getMaxCallFrameSize();
+ unsigned MaxCF = MFI.getMaxCallFrameSize();
MachineBasicBlock::iterator InsertPt = MBB.begin();
- auto *FuncInfo = MF.getInfo<HexagonMachineFunctionInfo>();
- auto &AdjustRegs = FuncInfo->getAllocaAdjustInsts();
+ SmallVector<MachineInstr *, 4> AdjustRegs;
+ for (auto &MBB : MF)
+ for (auto &MI : MBB)
+ if (MI.getOpcode() == Hexagon::PS_alloca)
+ AdjustRegs.push_back(&MI);
for (auto MI : AdjustRegs) {
- assert((MI->getOpcode() == Hexagon::ALLOCA) && "Expected alloca");
+ assert((MI->getOpcode() == Hexagon::PS_alloca) && "Expected alloca");
expandAlloca(MI, HII, SP, MaxCF);
MI->eraseFromParent();
}
@@ -551,7 +592,7 @@ void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
// Subtract offset from frame pointer.
// We use a caller-saved non-parameter register for that.
unsigned CallerSavedReg = HRI.getFirstCallerSavedNonParamReg();
- BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::CONST32_Int_Real),
+ BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::CONST32),
CallerSavedReg).addImm(NumBytes);
BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::A2_sub), SP)
.addReg(SP)
@@ -572,7 +613,7 @@ void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
// registers inline (i.e. did not use a spill function), then call
// the stack checker directly.
if (EnableStackOVFSanitizer && !PrologueStubs)
- BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::CALLstk))
+ BuildMI(MBB, InsertPt, dl, HII.get(Hexagon::PS_call_stk))
.addExternalSymbol("__runtime_stack_check");
}
@@ -581,7 +622,7 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
if (!hasFP(MF))
return;
- auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HII = *HST.getInstrInfo();
auto &HRI = *HST.getRegisterInfo();
unsigned SP = HRI.getStackRegister();
@@ -608,7 +649,9 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
// Check for RESTORE_DEALLOC_RET* tail call. Don't emit an extra dealloc-
// frame instruction if we encounter it.
if (RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4 ||
- RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC) {
+ RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC ||
+ RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT ||
+ RetOpc == Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC) {
MachineBasicBlock::iterator It = RetI;
++It;
// Delete all instructions after the RESTORE (except labels).
@@ -629,16 +672,19 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator PrevIt = std::prev(InsertPt);
unsigned COpc = PrevIt->getOpcode();
if (COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4 ||
- COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC)
+ COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC ||
+ COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT ||
+ COpc == Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC ||
+ COpc == Hexagon::PS_call_nr || COpc == Hexagon::PS_callr_nr)
NeedsDeallocframe = false;
}
if (!NeedsDeallocframe)
return;
- // If the returning instruction is JMPret, replace it with dealloc_return,
+ // If the returning instruction is PS_jmpret, replace it with dealloc_return,
// otherwise just add deallocframe. The function could be returning via a
// tail call.
- if (RetOpc != Hexagon::JMPret || DisableDeallocRet) {
+ if (RetOpc != Hexagon::PS_jmpret || DisableDeallocRet) {
BuildMI(MBB, InsertPt, DL, HII.get(Hexagon::L2_deallocframe));
return;
}
@@ -649,9 +695,30 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
MBB.erase(RetI);
}
+void HexagonFrameLowering::updateEntryPaths(MachineFunction &MF,
+ MachineBasicBlock &SaveB) const {
+ SetVector<unsigned> Worklist;
+
+ MachineBasicBlock &EntryB = MF.front();
+ Worklist.insert(EntryB.getNumber());
+
+ unsigned SaveN = SaveB.getNumber();
+ auto &CSI = MF.getFrameInfo().getCalleeSavedInfo();
+
+ for (unsigned i = 0; i < Worklist.size(); ++i) {
+ unsigned BN = Worklist[i];
+ MachineBasicBlock &MBB = *MF.getBlockNumbered(BN);
+ for (auto &R : CSI)
+ if (!MBB.isLiveIn(R.getReg()))
+ MBB.addLiveIn(R.getReg());
+ if (BN != SaveN)
+ for (auto &SB : MBB.successors())
+ Worklist.insert(SB->getNumber());
+ }
+}
bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
- MachineBasicBlock *RestoreB, BitVector &DoneT, BitVector &DoneF,
+ MachineBasicBlock &RestoreB, BitVector &DoneT, BitVector &DoneF,
BitVector &Path) const {
assert(MBB.getNumber() >= 0);
unsigned BN = MBB.getNumber();
@@ -660,7 +727,7 @@ bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
if (DoneT[BN])
return true;
- auto &CSI = MBB.getParent()->getFrameInfo()->getCalleeSavedInfo();
+ auto &CSI = MBB.getParent()->getFrameInfo().getCalleeSavedInfo();
Path[BN] = true;
bool ReachedExit = false;
@@ -681,7 +748,7 @@ bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
// We don't want to add unnecessary live-ins to the restore block: since
// the callee-saved registers are being defined in it, the entry of the
// restore block cannot be on the path from the definitions to any exit.
- if (ReachedExit && &MBB != RestoreB) {
+ if (ReachedExit && &MBB != &RestoreB) {
for (auto &R : CSI)
if (!MBB.isLiveIn(R.getReg()))
MBB.addLiveIn(R.getReg());
@@ -694,42 +761,49 @@ bool HexagonFrameLowering::updateExitPaths(MachineBasicBlock &MBB,
return ReachedExit;
}
-
-namespace {
- bool IsAllocFrame(MachineBasicBlock::const_iterator It) {
- if (!It->isBundle())
- return It->getOpcode() == Hexagon::S2_allocframe;
- auto End = It->getParent()->instr_end();
- MachineBasicBlock::const_instr_iterator I = It.getInstrIterator();
- while (++I != End && I->isBundled())
- if (I->getOpcode() == Hexagon::S2_allocframe)
- return true;
- return false;
- }
-
- MachineBasicBlock::iterator FindAllocFrame(MachineBasicBlock &B) {
- for (auto &I : B)
- if (IsAllocFrame(I))
- return I;
- return B.end();
- }
+static Optional<MachineBasicBlock::iterator>
+findCFILocation(MachineBasicBlock &B) {
+ // The CFI instructions need to be inserted right after allocframe.
+ // An exception to this is a situation where allocframe is bundled
+ // with a call: then the CFI instructions need to be inserted before
+ // the packet with the allocframe+call (in case the call throws an
+ // exception).
+ auto End = B.instr_end();
+
+ for (MachineInstr &I : B) {
+ MachineBasicBlock::iterator It = I.getIterator();
+ if (!I.isBundle()) {
+ if (I.getOpcode() == Hexagon::S2_allocframe)
+ return std::next(It);
+ continue;
+ }
+ // I is a bundle.
+ bool HasCall = false, HasAllocFrame = false;
+ auto T = It.getInstrIterator();
+ while (++T != End && T->isBundled()) {
+ if (T->getOpcode() == Hexagon::S2_allocframe)
+ HasAllocFrame = true;
+ else if (T->isCall())
+ HasCall = true;
+ }
+ if (HasAllocFrame)
+ return HasCall ? It : std::next(It);
+ }
+ return None;
}
-
void HexagonFrameLowering::insertCFIInstructions(MachineFunction &MF) const {
for (auto &B : MF) {
- auto AF = FindAllocFrame(B);
- if (AF == B.end())
- continue;
- insertCFIInstructionsAt(B, ++AF);
+ auto At = findCFILocation(B);
+ if (At.hasValue())
+ insertCFIInstructionsAt(B, At.getValue());
}
}
-
void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator At) const {
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HII = *HST.getInstrInfo();
@@ -761,15 +835,15 @@ void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
// MCCFIInstruction::createOffset takes the offset without sign change.
auto DefCfa = MCCFIInstruction::createDefCfa(FrameLabel, DwFPReg, -8);
BuildMI(MBB, At, DL, CFID)
- .addCFIIndex(MMI.addFrameInst(DefCfa));
+ .addCFIIndex(MF.addFrameInst(DefCfa));
// R31 (return addr) = CFA - 4
auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4);
BuildMI(MBB, At, DL, CFID)
- .addCFIIndex(MMI.addFrameInst(OffR31));
+ .addCFIIndex(MF.addFrameInst(OffR31));
// R30 (frame ptr) = CFA - 8
auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8);
BuildMI(MBB, At, DL, CFID)
- .addCFIIndex(MMI.addFrameInst(OffR30));
+ .addCFIIndex(MF.addFrameInst(OffR30));
}
static unsigned int RegsToMove[] = {
@@ -789,7 +863,7 @@ void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool {
return C.getReg() == Reg;
};
- auto F = std::find_if(CSI.begin(), CSI.end(), IfR);
+ auto F = find_if(CSI, IfR);
if (F == CSI.end())
continue;
@@ -815,7 +889,7 @@ void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg,
Offset);
BuildMI(MBB, At, DL, CFID)
- .addCFIIndex(MMI.addFrameInst(OffReg));
+ .addCFIIndex(MF.addFrameInst(OffReg));
} else {
// Split the double regs into subregs, and generate appropriate
// cfi_offsets.
@@ -823,25 +897,24 @@ void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
// understand paired registers for cfi_offset.
// Eg .cfi_offset r1:0, -64
- unsigned HiReg = HRI.getSubReg(Reg, Hexagon::subreg_hireg);
- unsigned LoReg = HRI.getSubReg(Reg, Hexagon::subreg_loreg);
+ unsigned HiReg = HRI.getSubReg(Reg, Hexagon::isub_hi);
+ unsigned LoReg = HRI.getSubReg(Reg, Hexagon::isub_lo);
unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true);
unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true);
auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg,
Offset+4);
BuildMI(MBB, At, DL, CFID)
- .addCFIIndex(MMI.addFrameInst(OffHi));
+ .addCFIIndex(MF.addFrameInst(OffHi));
auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg,
Offset);
BuildMI(MBB, At, DL, CFID)
- .addCFIIndex(MMI.addFrameInst(OffLo));
+ .addCFIIndex(MF.addFrameInst(OffLo));
}
}
}
-
bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
- auto &MFI = *MF.getFrameInfo();
+ auto &MFI = MF.getFrameInfo();
auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
bool HasFixed = MFI.getNumFixedObjects();
@@ -877,7 +950,6 @@ bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
return false;
}
-
enum SpillKind {
SK_ToMem,
SK_FromMem,
@@ -952,13 +1024,12 @@ static const char *getSpillFunctionFor(unsigned MaxReg, SpillKind SpillType,
default:
llvm_unreachable("Unhandled maximum callee save register");
}
- return 0;
+ return nullptr;
}
-
int HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI, unsigned &FrameReg) const {
- auto &MFI = *MF.getFrameInfo();
+ auto &MFI = MF.getFrameInfo();
auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
int Offset = MFI.getObjectOffset(FI);
@@ -1039,7 +1110,6 @@ int HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF,
return RealOffset;
}
-
bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
const CSIVect &CSI, const HexagonRegisterInfo &HRI,
bool &PrologueStubs) const {
@@ -1049,7 +1119,8 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI = MBB.begin();
PrologueStubs = false;
MachineFunction &MF = *MBB.getParent();
- auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
+ auto &HII = *HST.getInstrInfo();
if (useSpillFunction(MF, CSI)) {
PrologueStubs = true;
@@ -1059,20 +1130,31 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
StkOvrFlowEnabled);
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
bool IsPIC = HTM.isPositionIndependent();
+ bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
// Call spill function.
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
unsigned SpillOpc;
- if (StkOvrFlowEnabled)
- SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
- : Hexagon::SAVE_REGISTERS_CALL_V4STK;
- else
- SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
- : Hexagon::SAVE_REGISTERS_CALL_V4;
+ if (StkOvrFlowEnabled) {
+ if (LongCalls)
+ SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT_PIC
+ : Hexagon::SAVE_REGISTERS_CALL_V4STK_EXT;
+ else
+ SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4STK_PIC
+ : Hexagon::SAVE_REGISTERS_CALL_V4STK;
+ } else {
+ if (LongCalls)
+ SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC
+ : Hexagon::SAVE_REGISTERS_CALL_V4_EXT;
+ else
+ SpillOpc = IsPIC ? Hexagon::SAVE_REGISTERS_CALL_V4_PIC
+ : Hexagon::SAVE_REGISTERS_CALL_V4;
+ }
MachineInstr *SaveRegsCall =
BuildMI(MBB, MI, DL, HII.get(SpillOpc))
.addExternalSymbol(SpillFun);
+
// Add callee-saved registers as use.
addCalleeSaveRegistersAsImpOperand(SaveRegsCall, CSI, false, true);
// Add live in registers.
@@ -1096,7 +1178,6 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
return true;
}
-
bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
const CSIVect &CSI, const HexagonRegisterInfo &HRI) const {
if (CSI.empty())
@@ -1104,7 +1185,8 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
MachineFunction &MF = *MBB.getParent();
- auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
+ auto &HII = *HST.getInstrInfo();
if (useRestoreFunction(MF, CSI)) {
bool HasTC = hasTailCall(MBB) || !hasReturn(MBB);
@@ -1113,6 +1195,7 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
const char *RestoreFn = getSpillFunctionFor(MaxR, Kind);
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
bool IsPIC = HTM.isPositionIndependent();
+ bool LongCalls = HST.useLongCalls() || EnableSaveRestoreLong;
// Call spill function.
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc()
@@ -1120,17 +1203,27 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
MachineInstr *DeallocCall = nullptr;
if (HasTC) {
- unsigned ROpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
- : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
- DeallocCall = BuildMI(MBB, MI, DL, HII.get(ROpc))
+ unsigned RetOpc;
+ if (LongCalls)
+ RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT_PIC
+ : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_EXT;
+ else
+ RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4_PIC
+ : Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
+ DeallocCall = BuildMI(MBB, MI, DL, HII.get(RetOpc))
.addExternalSymbol(RestoreFn);
} else {
// The block has a return.
MachineBasicBlock::iterator It = MBB.getFirstTerminator();
assert(It->isReturn() && std::next(It) == MBB.end());
- unsigned ROpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
- : Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
- DeallocCall = BuildMI(MBB, It, DL, HII.get(ROpc))
+ unsigned RetOpc;
+ if (LongCalls)
+ RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT_PIC
+ : Hexagon::RESTORE_DEALLOC_RET_JMP_V4_EXT;
+ else
+ RetOpc = IsPIC ? Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC
+ : Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
+ DeallocCall = BuildMI(MBB, It, DL, HII.get(RetOpc))
.addExternalSymbol(RestoreFn);
// Transfer the function live-out registers.
DeallocCall->copyImplicitOps(MF, *It);
@@ -1160,39 +1253,38 @@ MachineBasicBlock::iterator HexagonFrameLowering::eliminateCallFramePseudoInstr(
return MBB.erase(I);
}
-
void HexagonFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS) const {
// If this function has uses aligned stack and also has variable sized stack
// objects, then we need to map all spill slots to fixed positions, so that
// they can be accessed through FP. Otherwise they would have to be accessed
// via AP, which may not be available at the particular place in the program.
- MachineFrameInfo *MFI = MF.getFrameInfo();
- bool HasAlloca = MFI->hasVarSizedObjects();
- bool NeedsAlign = (MFI->getMaxAlignment() > getStackAlignment());
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ bool HasAlloca = MFI.hasVarSizedObjects();
+ bool NeedsAlign = (MFI.getMaxAlignment() > getStackAlignment());
if (!HasAlloca || !NeedsAlign)
return;
- unsigned LFS = MFI->getLocalFrameSize();
- for (int i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
- if (!MFI->isSpillSlotObjectIndex(i) || MFI->isDeadObjectIndex(i))
+ unsigned LFS = MFI.getLocalFrameSize();
+ for (int i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
+ if (!MFI.isSpillSlotObjectIndex(i) || MFI.isDeadObjectIndex(i))
continue;
- unsigned S = MFI->getObjectSize(i);
+ unsigned S = MFI.getObjectSize(i);
// Reduce the alignment to at most 8. This will require unaligned vector
// stores if they happen here.
- unsigned A = std::max(MFI->getObjectAlignment(i), 8U);
- MFI->setObjectAlignment(i, 8);
+ unsigned A = std::max(MFI.getObjectAlignment(i), 8U);
+ MFI.setObjectAlignment(i, 8);
LFS = alignTo(LFS+S, A);
- MFI->mapLocalFrameObject(i, -LFS);
+ MFI.mapLocalFrameObject(i, -LFS);
}
- MFI->setLocalFrameSize(LFS);
- unsigned A = MFI->getLocalFrameMaxAlign();
+ MFI.setLocalFrameSize(LFS);
+ unsigned A = MFI.getLocalFrameMaxAlign();
assert(A <= 8 && "Unexpected local frame alignment");
if (A == 0)
- MFI->setLocalFrameMaxAlign(8);
- MFI->setUseLocalStackAllocationBlock(true);
+ MFI.setLocalFrameMaxAlign(8);
+ MFI.setUseLocalStackAllocationBlock(true);
// Set the physical aligned-stack base address register.
unsigned AP = 0;
@@ -1224,7 +1316,6 @@ static bool needToReserveScavengingSpillSlots(MachineFunction &MF,
return true;
}
-
#ifndef NDEBUG
static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) {
dbgs() << '{';
@@ -1236,12 +1327,11 @@ static void dump_registers(BitVector &Regs, const TargetRegisterInfo &TRI) {
}
#endif
-
bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
const TargetRegisterInfo *TRI, std::vector<CalleeSavedInfo> &CSI) const {
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << " on "
+ DEBUG(dbgs() << __func__ << " on "
<< MF.getFunction()->getName() << '\n');
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
BitVector SRegs(Hexagon::NUM_TARGET_REGS);
// Generate a set of unique, callee-saved registers (SRegs), where each
@@ -1321,7 +1411,7 @@ bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
if (!SRegs[S->Reg])
continue;
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(S->Reg);
- int FI = MFI->CreateFixedSpillStackObject(RC->getSize(), S->Offset);
+ int FI = MFI.CreateFixedSpillStackObject(RC->getSize(), S->Offset);
MinOffset = std::min(MinOffset, S->Offset);
CSI.push_back(CalleeSavedInfo(S->Reg, FI));
SRegs[S->Reg] = false;
@@ -1337,7 +1427,7 @@ bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
unsigned Align = std::min(RC->getAlignment(), getStackAlignment());
assert(isPowerOf2_32(Align));
Off &= -Align;
- int FI = MFI->CreateFixedSpillStackObject(RC->getSize(), Off);
+ int FI = MFI.CreateFixedSpillStackObject(RC->getSize(), Off);
MinOffset = std::min(MinOffset, Off);
CSI.push_back(CalleeSavedInfo(R, FI));
SRegs[R] = false;
@@ -1347,7 +1437,7 @@ bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
dbgs() << "CS information: {";
for (unsigned i = 0, n = CSI.size(); i < n; ++i) {
int FI = CSI[i].getFrameIdx();
- int Off = MFI->getObjectOffset(FI);
+ int Off = MFI.getObjectOffset(FI);
dbgs() << ' ' << PrintReg(CSI[i].getReg(), TRI) << ":fi#" << FI << ":sp";
if (Off >= 0)
dbgs() << '+';
@@ -1371,7 +1461,6 @@ bool HexagonFrameLowering::assignCalleeSavedSpillSlots(MachineFunction &MF,
return true;
}
-
bool HexagonFrameLowering::expandCopy(MachineBasicBlock &B,
MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
@@ -1398,12 +1487,13 @@ bool HexagonFrameLowering::expandStoreInt(MachineBasicBlock &B,
MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
MachineInstr *MI = &*It;
+ if (!MI->getOperand(0).isFI())
+ return false;
+
DebugLoc DL = MI->getDebugLoc();
unsigned Opc = MI->getOpcode();
unsigned SrcR = MI->getOperand(2).getReg();
bool IsKill = MI->getOperand(2).isKill();
-
- assert(MI->getOperand(0).isFI() && "Expect a frame index");
int FI = MI->getOperand(0).getIndex();
// TmpR = C2_tfrpr SrcR if SrcR is a predicate register
@@ -1430,11 +1520,12 @@ bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B,
MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
MachineInstr *MI = &*It;
+ if (!MI->getOperand(1).isFI())
+ return false;
+
DebugLoc DL = MI->getDebugLoc();
unsigned Opc = MI->getOpcode();
unsigned DstR = MI->getOperand(0).getReg();
-
- assert(MI->getOperand(1).isFI() && "Expect a frame index");
int FI = MI->getOperand(1).getIndex();
// TmpR = L2_loadri_io FI, 0
@@ -1456,17 +1547,17 @@ bool HexagonFrameLowering::expandLoadInt(MachineBasicBlock &B,
return true;
}
-
bool HexagonFrameLowering::expandStoreVecPred(MachineBasicBlock &B,
MachineBasicBlock::iterator It, MachineRegisterInfo &MRI,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>();
MachineInstr *MI = &*It;
+ if (!MI->getOperand(0).isFI())
+ return false;
+
DebugLoc DL = MI->getDebugLoc();
unsigned SrcR = MI->getOperand(2).getReg();
bool IsKill = MI->getOperand(2).isKill();
-
- assert(MI->getOperand(0).isFI() && "Expect a frame index");
int FI = MI->getOperand(0).getIndex();
bool Is128B = HST.useHVXDblOps();
@@ -1503,10 +1594,11 @@ bool HexagonFrameLowering::expandLoadVecPred(MachineBasicBlock &B,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>();
MachineInstr *MI = &*It;
+ if (!MI->getOperand(1).isFI())
+ return false;
+
DebugLoc DL = MI->getDebugLoc();
unsigned DstR = MI->getOperand(0).getReg();
-
- assert(MI->getOperand(1).isFI() && "Expect a frame index");
int FI = MI->getOperand(1).getIndex();
bool Is128B = HST.useHVXDblOps();
@@ -1541,17 +1633,27 @@ bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
MachineFunction &MF = *B.getParent();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
- auto &MFI = *MF.getFrameInfo();
+ auto &MFI = MF.getFrameInfo();
auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
MachineInstr *MI = &*It;
- DebugLoc DL = MI->getDebugLoc();
+ if (!MI->getOperand(0).isFI())
+ return false;
+
+ // It is possible that the double vector being stored is only partially
+ // defined. From the point of view of the liveness tracking, it is ok to
+ // store it as a whole, but if we break it up we may end up storing a
+ // register that is entirely undefined.
+ LivePhysRegs LPR(&HRI);
+ LPR.addLiveIns(B);
+ SmallVector<std::pair<unsigned, const MachineOperand*>,2> Clobbers;
+ for (auto R = B.begin(); R != It; ++R)
+ LPR.stepForward(*R, Clobbers);
+ DebugLoc DL = MI->getDebugLoc();
unsigned SrcR = MI->getOperand(2).getReg();
- unsigned SrcLo = HRI.getSubReg(SrcR, Hexagon::subreg_loreg);
- unsigned SrcHi = HRI.getSubReg(SrcR, Hexagon::subreg_hireg);
+ unsigned SrcLo = HRI.getSubReg(SrcR, Hexagon::vsub_lo);
+ unsigned SrcHi = HRI.getSubReg(SrcR, Hexagon::vsub_hi);
bool IsKill = MI->getOperand(2).isKill();
-
- assert(MI->getOperand(0).isFI() && "Expect a frame index");
int FI = MI->getOperand(0).getIndex();
bool Is128B = HST.useHVXDblOps();
@@ -1563,28 +1665,32 @@ bool HexagonFrameLowering::expandStoreVec2(MachineBasicBlock &B,
unsigned StoreOpc;
// Store low part.
- if (NeedAlign <= HasAlign)
- StoreOpc = !Is128B ? Hexagon::V6_vS32b_ai : Hexagon::V6_vS32b_ai_128B;
- else
- StoreOpc = !Is128B ? Hexagon::V6_vS32Ub_ai : Hexagon::V6_vS32Ub_ai_128B;
+ if (LPR.contains(SrcLo)) {
+ if (NeedAlign <= HasAlign)
+ StoreOpc = !Is128B ? Hexagon::V6_vS32b_ai : Hexagon::V6_vS32b_ai_128B;
+ else
+ StoreOpc = !Is128B ? Hexagon::V6_vS32Ub_ai : Hexagon::V6_vS32Ub_ai_128B;
- BuildMI(B, It, DL, HII.get(StoreOpc))
- .addFrameIndex(FI)
- .addImm(0)
- .addReg(SrcLo, getKillRegState(IsKill))
- .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ BuildMI(B, It, DL, HII.get(StoreOpc))
+ .addFrameIndex(FI)
+ .addImm(0)
+ .addReg(SrcLo, getKillRegState(IsKill))
+ .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ }
- // Load high part.
- if (NeedAlign <= MinAlign(HasAlign, Size))
- StoreOpc = !Is128B ? Hexagon::V6_vS32b_ai : Hexagon::V6_vS32b_ai_128B;
- else
- StoreOpc = !Is128B ? Hexagon::V6_vS32Ub_ai : Hexagon::V6_vS32Ub_ai_128B;
+ // Store high part.
+ if (LPR.contains(SrcHi)) {
+ if (NeedAlign <= MinAlign(HasAlign, Size))
+ StoreOpc = !Is128B ? Hexagon::V6_vS32b_ai : Hexagon::V6_vS32b_ai_128B;
+ else
+ StoreOpc = !Is128B ? Hexagon::V6_vS32Ub_ai : Hexagon::V6_vS32Ub_ai_128B;
- BuildMI(B, It, DL, HII.get(StoreOpc))
- .addFrameIndex(FI)
- .addImm(Size)
- .addReg(SrcHi, getKillRegState(IsKill))
- .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ BuildMI(B, It, DL, HII.get(StoreOpc))
+ .addFrameIndex(FI)
+ .addImm(Size)
+ .addReg(SrcHi, getKillRegState(IsKill))
+ .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ }
B.erase(It);
return true;
@@ -1595,16 +1701,16 @@ bool HexagonFrameLowering::expandLoadVec2(MachineBasicBlock &B,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
MachineFunction &MF = *B.getParent();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
- auto &MFI = *MF.getFrameInfo();
+ auto &MFI = MF.getFrameInfo();
auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
MachineInstr *MI = &*It;
- DebugLoc DL = MI->getDebugLoc();
+ if (!MI->getOperand(1).isFI())
+ return false;
+ DebugLoc DL = MI->getDebugLoc();
unsigned DstR = MI->getOperand(0).getReg();
- unsigned DstHi = HRI.getSubReg(DstR, Hexagon::subreg_hireg);
- unsigned DstLo = HRI.getSubReg(DstR, Hexagon::subreg_loreg);
-
- assert(MI->getOperand(1).isFI() && "Expect a frame index");
+ unsigned DstHi = HRI.getSubReg(DstR, Hexagon::vsub_hi);
+ unsigned DstLo = HRI.getSubReg(DstR, Hexagon::vsub_lo);
int FI = MI->getOperand(1).getIndex();
bool Is128B = HST.useHVXDblOps();
@@ -1646,14 +1752,14 @@ bool HexagonFrameLowering::expandStoreVec(MachineBasicBlock &B,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
MachineFunction &MF = *B.getParent();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
- auto &MFI = *MF.getFrameInfo();
+ auto &MFI = MF.getFrameInfo();
MachineInstr *MI = &*It;
- DebugLoc DL = MI->getDebugLoc();
+ if (!MI->getOperand(0).isFI())
+ return false;
+ DebugLoc DL = MI->getDebugLoc();
unsigned SrcR = MI->getOperand(2).getReg();
bool IsKill = MI->getOperand(2).isKill();
-
- assert(MI->getOperand(0).isFI() && "Expect a frame index");
int FI = MI->getOperand(0).getIndex();
bool Is128B = HST.useHVXDblOps();
@@ -1684,13 +1790,13 @@ bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B,
const HexagonInstrInfo &HII, SmallVectorImpl<unsigned> &NewRegs) const {
MachineFunction &MF = *B.getParent();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
- auto &MFI = *MF.getFrameInfo();
+ auto &MFI = MF.getFrameInfo();
MachineInstr *MI = &*It;
- DebugLoc DL = MI->getDebugLoc();
+ if (!MI->getOperand(1).isFI())
+ return false;
+ DebugLoc DL = MI->getDebugLoc();
unsigned DstR = MI->getOperand(0).getReg();
-
- assert(MI->getOperand(1).isFI() && "Expect a frame index");
int FI = MI->getOperand(1).getIndex();
bool Is128B = HST.useHVXDblOps();
@@ -1715,7 +1821,6 @@ bool HexagonFrameLowering::expandLoadVec(MachineBasicBlock &B,
return true;
}
-
bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF,
SmallVectorImpl<unsigned> &NewRegs) const {
auto &HST = MF.getSubtarget<HexagonSubtarget>();
@@ -1743,30 +1848,26 @@ bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF,
case Hexagon::LDriw_mod:
Changed |= expandLoadInt(B, I, MRI, HII, NewRegs);
break;
- case Hexagon::STriq_pred_V6:
- case Hexagon::STriq_pred_V6_128B:
+ case Hexagon::PS_vstorerq_ai:
+ case Hexagon::PS_vstorerq_ai_128B:
Changed |= expandStoreVecPred(B, I, MRI, HII, NewRegs);
break;
- case Hexagon::LDriq_pred_V6:
- case Hexagon::LDriq_pred_V6_128B:
+ case Hexagon::PS_vloadrq_ai:
+ case Hexagon::PS_vloadrq_ai_128B:
Changed |= expandLoadVecPred(B, I, MRI, HII, NewRegs);
break;
- case Hexagon::LDrivv_pseudo_V6:
- case Hexagon::LDrivv_pseudo_V6_128B:
+ case Hexagon::PS_vloadrw_ai:
+ case Hexagon::PS_vloadrwu_ai:
+ case Hexagon::PS_vloadrw_ai_128B:
+ case Hexagon::PS_vloadrwu_ai_128B:
Changed |= expandLoadVec2(B, I, MRI, HII, NewRegs);
break;
- case Hexagon::STrivv_pseudo_V6:
- case Hexagon::STrivv_pseudo_V6_128B:
+ case Hexagon::PS_vstorerw_ai:
+ case Hexagon::PS_vstorerwu_ai:
+ case Hexagon::PS_vstorerw_ai_128B:
+ case Hexagon::PS_vstorerwu_ai_128B:
Changed |= expandStoreVec2(B, I, MRI, HII, NewRegs);
break;
- case Hexagon::STriv_pseudo_V6:
- case Hexagon::STriv_pseudo_V6_128B:
- Changed |= expandStoreVec(B, I, MRI, HII, NewRegs);
- break;
- case Hexagon::LDriv_pseudo_V6:
- case Hexagon::LDriv_pseudo_V6_128B:
- Changed |= expandLoadVec(B, I, MRI, HII, NewRegs);
- break;
}
}
}
@@ -1774,7 +1875,6 @@ bool HexagonFrameLowering::expandSpillMacros(MachineFunction &MF,
return Changed;
}
-
void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
@@ -1797,8 +1897,8 @@ void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
// We need to reserve a a spill slot if scavenging could potentially require
// spilling a scavenged register.
- if (!NewRegs.empty()) {
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ if (!NewRegs.empty() || mayOverflowFrameOffset(MF)) {
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
SetVector<const TargetRegisterClass*> SpillRCs;
// Reserve an int register in any case, because it could be used to hold
@@ -1823,7 +1923,6 @@ void HexagonFrameLowering::determineCalleeSaves(MachineFunction &MF,
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
}
-
unsigned HexagonFrameLowering::findPhysReg(MachineFunction &MF,
HexagonBlockRanges::IndexRange &FIR,
HexagonBlockRanges::InstrIndexMap &IndexMap,
@@ -1872,29 +1971,16 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
struct SlotInfo {
BlockRangeMap Map;
- unsigned Size;
- const TargetRegisterClass *RC;
+ unsigned Size = 0;
+ const TargetRegisterClass *RC = nullptr;
- SlotInfo() : Map(), Size(0), RC(nullptr) {}
+ SlotInfo() = default;
};
BlockIndexMap BlockIndexes;
SmallSet<int,4> BadFIs;
std::map<int,SlotInfo> FIRangeMap;
- auto getRegClass = [&MRI,&HRI] (HexagonBlockRanges::RegisterRef R)
- -> const TargetRegisterClass* {
- if (TargetRegisterInfo::isPhysicalRegister(R.Reg))
- assert(R.Sub == 0);
- if (TargetRegisterInfo::isVirtualRegister(R.Reg)) {
- auto *RCR = MRI.getRegClass(R.Reg);
- if (R.Sub == 0)
- return RCR;
- unsigned PR = *RCR->begin();
- R.Reg = HRI.getSubReg(PR, R.Sub);
- }
- return HRI.getMinimalPhysRegClass(R.Reg);
- };
// Accumulate register classes: get a common class for a pre-existing
// class HaveRC and a new class NewRC. Return nullptr if a common class
// cannot be found, otherwise return the resulting class. If HaveRC is
@@ -1942,19 +2028,13 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
// this restriction.
if (Load || Store) {
int TFI = Load ? LFI : SFI;
- unsigned AM = HII.getAddrMode(&In);
+ unsigned AM = HII.getAddrMode(In);
SlotInfo &SI = FIRangeMap[TFI];
bool Bad = (AM != HexagonII::BaseImmOffset);
if (!Bad) {
// If the addressing mode is ok, check the register class.
- const TargetRegisterClass *RC = nullptr;
- if (Load) {
- MachineOperand &DataOp = In.getOperand(0);
- RC = getRegClass({DataOp.getReg(), DataOp.getSubReg()});
- } else {
- MachineOperand &DataOp = In.getOperand(2);
- RC = getRegClass({DataOp.getReg(), DataOp.getSubReg()});
- }
+ unsigned OpNum = Load ? 0 : 2;
+ auto *RC = HII.getRegClass(In.getDesc(), OpNum, &HRI, MF);
RC = getCommonRC(SI.RC, RC);
if (RC == nullptr)
Bad = true;
@@ -1963,12 +2043,20 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
}
if (!Bad) {
// Check sizes.
- unsigned S = (1U << (HII.getMemAccessSize(&In) - 1));
+ unsigned S = (1U << (HII.getMemAccessSize(In) - 1));
if (SI.Size != 0 && SI.Size != S)
Bad = true;
else
SI.Size = S;
}
+ if (!Bad) {
+ for (auto *Mo : In.memoperands()) {
+ if (!Mo->isVolatile())
+ continue;
+ Bad = true;
+ break;
+ }
+ }
if (Bad)
BadFIs.insert(TFI);
}
@@ -2081,6 +2169,10 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
}
});
+#ifndef NDEBUG
+ bool HasOptLimit = SpillOptMax.getPosition();
+#endif
+
// eliminate loads, when all loads eliminated, eliminate all stores.
for (auto &B : MF) {
auto F = BlockIndexes.find(&B);
@@ -2101,26 +2193,33 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
if (!IndexType::isInstr(Range.start()) ||
!IndexType::isInstr(Range.end()))
continue;
- MachineInstr *SI = IM.getInstr(Range.start());
- MachineInstr *EI = IM.getInstr(Range.end());
- assert(SI->mayStore() && "Unexpected start instruction");
- assert(EI->mayLoad() && "Unexpected end instruction");
- MachineOperand &SrcOp = SI->getOperand(2);
+ MachineInstr &SI = *IM.getInstr(Range.start());
+ MachineInstr &EI = *IM.getInstr(Range.end());
+ assert(SI.mayStore() && "Unexpected start instruction");
+ assert(EI.mayLoad() && "Unexpected end instruction");
+ MachineOperand &SrcOp = SI.getOperand(2);
HexagonBlockRanges::RegisterRef SrcRR = { SrcOp.getReg(),
SrcOp.getSubReg() };
- auto *RC = getRegClass({SrcOp.getReg(), SrcOp.getSubReg()});
+ auto *RC = HII.getRegClass(SI.getDesc(), 2, &HRI, MF);
// The this-> is needed to unconfuse MSVC.
unsigned FoundR = this->findPhysReg(MF, Range, IM, DM, RC);
DEBUG(dbgs() << "Replacement reg:" << PrintReg(FoundR, &HRI) << '\n');
if (FoundR == 0)
continue;
+#ifndef NDEBUG
+ if (HasOptLimit) {
+ if (SpillOptCount >= SpillOptMax)
+ return;
+ SpillOptCount++;
+ }
+#endif
// Generate the copy-in: "FoundR = COPY SrcR" at the store location.
- MachineBasicBlock::iterator StartIt = SI, NextIt;
+ MachineBasicBlock::iterator StartIt = SI.getIterator(), NextIt;
MachineInstr *CopyIn = nullptr;
if (SrcRR.Reg != FoundR || SrcRR.Sub != 0) {
- const DebugLoc &DL = SI->getDebugLoc();
+ const DebugLoc &DL = SI.getDebugLoc();
CopyIn = BuildMI(B, StartIt, DL, HII.get(TargetOpcode::COPY), FoundR)
.addOperand(SrcOp);
}
@@ -2137,33 +2236,33 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
// We are keeping this register live.
SrcOp.setIsKill(false);
} else {
- B.erase(SI);
- IM.replaceInstr(SI, CopyIn);
+ B.erase(&SI);
+ IM.replaceInstr(&SI, CopyIn);
}
- auto EndIt = std::next(MachineBasicBlock::iterator(EI));
+ auto EndIt = std::next(EI.getIterator());
for (auto It = StartIt; It != EndIt; It = NextIt) {
- MachineInstr *MI = &*It;
+ MachineInstr &MI = *It;
NextIt = std::next(It);
int TFI;
- if (!HII.isLoadFromStackSlot(*MI, TFI) || TFI != FI)
+ if (!HII.isLoadFromStackSlot(MI, TFI) || TFI != FI)
continue;
- unsigned DstR = MI->getOperand(0).getReg();
- assert(MI->getOperand(0).getSubReg() == 0);
+ unsigned DstR = MI.getOperand(0).getReg();
+ assert(MI.getOperand(0).getSubReg() == 0);
MachineInstr *CopyOut = nullptr;
if (DstR != FoundR) {
- DebugLoc DL = MI->getDebugLoc();
+ DebugLoc DL = MI.getDebugLoc();
unsigned MemSize = (1U << (HII.getMemAccessSize(MI) - 1));
assert(HII.getAddrMode(MI) == HexagonII::BaseImmOffset);
unsigned CopyOpc = TargetOpcode::COPY;
- if (HII.isSignExtendingLoad(*MI))
+ if (HII.isSignExtendingLoad(MI))
CopyOpc = (MemSize == 1) ? Hexagon::A2_sxtb : Hexagon::A2_sxth;
- else if (HII.isZeroExtendingLoad(*MI))
+ else if (HII.isZeroExtendingLoad(MI))
CopyOpc = (MemSize == 1) ? Hexagon::A2_zxtb : Hexagon::A2_zxth;
CopyOut = BuildMI(B, It, DL, HII.get(CopyOpc), DstR)
- .addReg(FoundR, getKillRegState(MI == EI));
+ .addReg(FoundR, getKillRegState(&MI == &EI));
}
- IM.replaceInstr(MI, CopyOut);
+ IM.replaceInstr(&MI, CopyOut);
B.erase(It);
}
@@ -2176,7 +2275,6 @@ void HexagonFrameLowering::optimizeSpillSlots(MachineFunction &MF,
}
}
-
void HexagonFrameLowering::expandAlloca(MachineInstr *AI,
const HexagonInstrInfo &HII, unsigned SP, unsigned CF) const {
MachineBasicBlock &MB = *AI->getParent();
@@ -2235,28 +2333,25 @@ void HexagonFrameLowering::expandAlloca(MachineInstr *AI,
}
}
-
bool HexagonFrameLowering::needsAligna(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- if (!MFI->hasVarSizedObjects())
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (!MFI.hasVarSizedObjects())
return false;
- unsigned MaxA = MFI->getMaxAlignment();
+ unsigned MaxA = MFI.getMaxAlignment();
if (MaxA <= getStackAlignment())
return false;
return true;
}
-
const MachineInstr *HexagonFrameLowering::getAlignaInstr(
const MachineFunction &MF) const {
for (auto &B : MF)
for (auto &I : B)
- if (I.getOpcode() == Hexagon::ALIGNA)
+ if (I.getOpcode() == Hexagon::PS_aligna)
return &I;
return nullptr;
}
-
/// Adds all callee-saved registers as implicit uses or defs to the
/// instruction.
void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI,
@@ -2266,7 +2361,6 @@ void HexagonFrameLowering::addCalleeSaveRegistersAsImpOperand(MachineInstr *MI,
MI->addOperand(MachineOperand::CreateReg(R.getReg(), IsDef, true, IsKill));
}
-
/// Determine whether the callee-saved register saves and restores should
/// be generated via inline code. If this function returns "true", inline
/// code will be generated. If this function returns "false", additional
@@ -2301,7 +2395,6 @@ bool HexagonFrameLowering::shouldInlineCSR(MachineFunction &MF,
return false;
}
-
bool HexagonFrameLowering::useSpillFunction(MachineFunction &MF,
const CSIVect &CSI) const {
if (shouldInlineCSR(MF, CSI))
@@ -2315,7 +2408,6 @@ bool HexagonFrameLowering::useSpillFunction(MachineFunction &MF,
return Threshold < NumCSI;
}
-
bool HexagonFrameLowering::useRestoreFunction(MachineFunction &MF,
const CSIVect &CSI) const {
if (shouldInlineCSR(MF, CSI))
@@ -2336,3 +2428,14 @@ bool HexagonFrameLowering::useRestoreFunction(MachineFunction &MF,
: SpillFuncThreshold;
return Threshold < NumCSI;
}
+
+bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const {
+ unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF);
+ auto &HST = MF.getSubtarget<HexagonSubtarget>();
+ // A fairly simplistic guess as to whether a potential load/store to a
+ // stack location could require an extra register. It does not account
+ // for store-immediate instructions.
+ if (HST.useHVXOps())
+ return StackSize > 256;
+ return false;
+}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.h b/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.h
index 3e76214..529a61d 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.h
@@ -12,7 +12,11 @@
#include "Hexagon.h"
#include "HexagonBlockRanges.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetFrameLowering.h"
+#include <vector>
namespace llvm {
@@ -31,11 +35,13 @@ public:
override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const
override {}
+
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const override {
return true;
}
+
bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const override {
@@ -53,6 +59,7 @@ public:
bool targetHandlesStackFrameRounding() const override {
return true;
}
+
int getFrameIndexReference(const MachineFunction &MF, int FI,
unsigned &FrameReg) const override;
bool hasFP(const MachineFunction &MF) const override;
@@ -91,7 +98,8 @@ private:
const HexagonRegisterInfo &HRI, bool &PrologueStubs) const;
bool insertCSRRestoresInBlock(MachineBasicBlock &MBB, const CSIVect &CSI,
const HexagonRegisterInfo &HRI) const;
- bool updateExitPaths(MachineBasicBlock &MBB, MachineBasicBlock *RestoreB,
+ void updateEntryPaths(MachineFunction &MF, MachineBasicBlock &SaveB) const;
+ bool updateExitPaths(MachineBasicBlock &MBB, MachineBasicBlock &RestoreB,
BitVector &DoneT, BitVector &DoneF, BitVector &Path) const;
void insertCFIInstructionsAt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator At) const;
@@ -140,11 +148,12 @@ private:
void addCalleeSaveRegistersAsImpOperand(MachineInstr *MI, const CSIVect &CSI,
bool IsDef, bool IsKill) const;
- bool shouldInlineCSR(llvm::MachineFunction &MF, const CSIVect &CSI) const;
+ bool shouldInlineCSR(MachineFunction &MF, const CSIVect &CSI) const;
bool useSpillFunction(MachineFunction &MF, const CSIVect &CSI) const;
bool useRestoreFunction(MachineFunction &MF, const CSIVect &CSI) const;
+ bool mayOverflowFrameOffset(MachineFunction &MF) const;
};
-} // End llvm namespace
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONFRAMELOWERING_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonGenExtract.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonGenExtract.cpp
index f46b6d2..bb5e379 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonGenExtract.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonGenExtract.cpp
@@ -7,20 +7,25 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
-#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/PatternMatch.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
using namespace llvm;
@@ -41,28 +46,34 @@ static cl::opt<bool> NeedAnd("extract-needand", cl::init(true), cl::Hidden,
cl::desc("Require & in extract patterns"));
namespace llvm {
+
void initializeHexagonGenExtractPass(PassRegistry&);
FunctionPass *createHexagonGenExtract();
-}
+} // end namespace llvm
namespace {
+
class HexagonGenExtract : public FunctionPass {
public:
static char ID;
+
HexagonGenExtract() : FunctionPass(ID), ExtractCount(0) {
initializeHexagonGenExtractPass(*PassRegistry::getPassRegistry());
}
- virtual const char *getPassName() const override {
+
+ StringRef getPassName() const override {
return "Hexagon generate \"extract\" instructions";
}
- virtual bool runOnFunction(Function &F) override;
- virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
+
+ bool runOnFunction(Function &F) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DominatorTreeWrapperPass>();
AU.addPreserved<DominatorTreeWrapperPass>();
- AU.addPreserved<MachineFunctionAnalysis>();
FunctionPass::getAnalysisUsage(AU);
}
+
private:
bool visitBlock(BasicBlock *B);
bool convert(Instruction *In);
@@ -72,7 +83,8 @@ namespace {
};
char HexagonGenExtract::ID = 0;
-}
+
+} // end anonymous namespace
INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate "
"\"extract\" instructions", false, false)
@@ -80,11 +92,11 @@ INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate "
"\"extract\" instructions", false, false)
-
bool HexagonGenExtract::convert(Instruction *In) {
using namespace PatternMatch;
- Value *BF = 0;
- ConstantInt *CSL = 0, *CSR = 0, *CM = 0;
+
+ Value *BF = nullptr;
+ ConstantInt *CSL = nullptr, *CSR = nullptr, *CM = nullptr;
BasicBlock *BB = In->getParent();
LLVMContext &Ctx = BB->getContext();
bool LogicalSR;
@@ -126,14 +138,14 @@ bool HexagonGenExtract::convert(Instruction *In) {
m_ConstantInt(CM)));
}
if (!Match) {
- CM = 0;
+ CM = nullptr;
// (shl (lshr x, #sr), #sl)
LogicalSR = true;
Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
m_ConstantInt(CSL)));
}
if (!Match) {
- CM = 0;
+ CM = nullptr;
// (shl (ashr x, #sr), #sl)
LogicalSR = false;
Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),
@@ -207,7 +219,6 @@ bool HexagonGenExtract::convert(Instruction *In) {
return true;
}
-
bool HexagonGenExtract::visitBlock(BasicBlock *B) {
// Depth-first, bottom-up traversal.
DomTreeNode *DTN = DT->getNode(B);
@@ -240,7 +251,6 @@ bool HexagonGenExtract::visitBlock(BasicBlock *B) {
return Changed;
}
-
bool HexagonGenExtract::runOnFunction(Function &F) {
if (skipFunction(F))
return false;
@@ -256,7 +266,6 @@ bool HexagonGenExtract::runOnFunction(Function &F) {
return Changed;
}
-
FunctionPass *llvm::createHexagonGenExtract() {
return new HexagonGenExtract();
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonGenInsert.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonGenInsert.cpp
index 71d0791..5a8e392 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonGenInsert.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonGenInsert.cpp
@@ -9,29 +9,39 @@
#define DEBUG_TYPE "hexinsert"
+#include "BitTracker.h"
+#include "HexagonBitTracker.h"
+#include "HexagonInstrInfo.h"
+#include "HexagonRegisterInfo.h"
+#include "HexagonSubtarget.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/Pass.h"
-#include "llvm/PassRegistry.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Timer.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetMachine.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Target/TargetRegisterInfo.h"
-
-#include "Hexagon.h"
-#include "HexagonRegisterInfo.h"
-#include "HexagonTargetMachine.h"
-#include "HexagonBitTracker.h"
-
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <utility>
#include <vector>
using namespace llvm;
@@ -59,20 +69,18 @@ static cl::opt<bool> OptSelectHas0("insert-has0", cl::init(false), cl::Hidden,
static cl::opt<bool> OptConst("insert-const", cl::init(false), cl::Hidden,
cl::ZeroOrMore);
-namespace {
- // The preprocessor gets confused when the DEBUG macro is passed larger
- // chunks of code. Use this function to detect debugging.
- inline bool isDebug() {
+// The preprocessor gets confused when the DEBUG macro is passed larger
+// chunks of code. Use this function to detect debugging.
+inline static bool isDebug() {
#ifndef NDEBUG
- return ::llvm::DebugFlag && ::llvm::isCurrentDebugType(DEBUG_TYPE);
+ return DebugFlag && isCurrentDebugType(DEBUG_TYPE);
#else
- return false;
+ return false;
#endif
- }
}
-
namespace {
+
// Set of virtual registers, based on BitVector.
struct RegisterSet : private BitVector {
RegisterSet() = default;
@@ -146,20 +154,23 @@ namespace {
if (size() <= Idx)
resize(std::max(Idx+1, 32U));
}
+
static inline unsigned v2x(unsigned v) {
return TargetRegisterInfo::virtReg2Index(v);
}
+
static inline unsigned x2v(unsigned x) {
return TargetRegisterInfo::index2VirtReg(x);
}
};
-
struct PrintRegSet {
PrintRegSet(const RegisterSet &S, const TargetRegisterInfo *RI)
: RS(S), TRI(RI) {}
+
friend raw_ostream &operator<< (raw_ostream &OS,
const PrintRegSet &P);
+
private:
const RegisterSet &RS;
const TargetRegisterInfo *TRI;
@@ -172,14 +183,12 @@ namespace {
OS << " }";
return OS;
}
-}
-
-namespace {
// A convenience class to associate unsigned numbers (such as virtual
// registers) with unsigned numbers.
struct UnsignedMap : public DenseMap<unsigned,unsigned> {
- UnsignedMap() : BaseType() {}
+ UnsignedMap() = default;
+
private:
typedef DenseMap<unsigned,unsigned> BaseType;
};
@@ -190,22 +199,21 @@ namespace {
// by a potentially expensive comparison function, or obtained by a proce-
// dure that should not be repeated each time two registers are compared.
struct RegisterOrdering : public UnsignedMap {
- RegisterOrdering() : UnsignedMap() {}
+ RegisterOrdering() = default;
+
unsigned operator[](unsigned VR) const {
const_iterator F = find(VR);
assert(F != end());
return F->second;
}
+
// Add operator(), so that objects of this class can be used as
// comparators in std::sort et al.
bool operator() (unsigned VR1, unsigned VR2) const {
return operator[](VR1) < operator[](VR2);
}
};
-}
-
-namespace {
// Ordering of bit values. This class does not have operator[], but
// is supplies a comparison operator() for use in std:: algorithms.
// The order is as follows:
@@ -214,12 +222,14 @@ namespace {
// or ord(ref1.Reg) == ord(ref2.Reg), and ref1.Pos < ref2.Pos.
struct BitValueOrdering {
BitValueOrdering(const RegisterOrdering &RB) : BaseOrd(RB) {}
+
bool operator() (const BitTracker::BitValue &V1,
const BitTracker::BitValue &V2) const;
+
const RegisterOrdering &BaseOrd;
};
-}
+} // end anonymous namespace
bool BitValueOrdering::operator() (const BitTracker::BitValue &V1,
const BitTracker::BitValue &V2) const {
@@ -241,20 +251,21 @@ bool BitValueOrdering::operator() (const BitTracker::BitValue &V1,
return V1.RefI.Pos < V2.RefI.Pos;
}
-
namespace {
+
// Cache for the BitTracker's cell map. Map lookup has a logarithmic
// complexity, this class will memoize the lookup results to reduce
// the access time for repeated lookups of the same cell.
struct CellMapShadow {
CellMapShadow(const BitTracker &T) : BT(T) {}
+
const BitTracker::RegisterCell &lookup(unsigned VR) {
unsigned RInd = TargetRegisterInfo::virtReg2Index(VR);
// Grow the vector to at least 32 elements.
if (RInd >= CVect.size())
- CVect.resize(std::max(RInd+16, 32U), 0);
+ CVect.resize(std::max(RInd+16, 32U), nullptr);
const BitTracker::RegisterCell *CP = CVect[RInd];
- if (CP == 0)
+ if (CP == nullptr)
CP = CVect[RInd] = &BT.lookup(VR);
return *CP;
}
@@ -265,16 +276,15 @@ namespace {
typedef std::vector<const BitTracker::RegisterCell*> CellVectType;
CellVectType CVect;
};
-}
-
-namespace {
// Comparator class for lexicographic ordering of virtual registers
// according to the corresponding BitTracker::RegisterCell objects.
struct RegisterCellLexCompare {
RegisterCellLexCompare(const BitValueOrdering &BO, CellMapShadow &M)
: BitOrd(BO), CM(M) {}
+
bool operator() (unsigned VR1, unsigned VR2) const;
+
private:
const BitValueOrdering &BitOrd;
CellMapShadow &CM;
@@ -290,15 +300,17 @@ namespace {
RegisterCellBitCompareSel(unsigned R, unsigned B, unsigned N,
const BitValueOrdering &BO, CellMapShadow &M)
: SelR(R), SelB(B), BitN(N), BitOrd(BO), CM(M) {}
+
bool operator() (unsigned VR1, unsigned VR2) const;
+
private:
const unsigned SelR, SelB;
const unsigned BitN;
const BitValueOrdering &BitOrd;
CellMapShadow &CM;
};
-}
+} // end anonymous namespace
bool RegisterCellLexCompare::operator() (unsigned VR1, unsigned VR2) const {
// Ordering of registers, made up from two given orderings:
@@ -327,7 +339,6 @@ bool RegisterCellLexCompare::operator() (unsigned VR1, unsigned VR2) const {
return BitOrd.BaseOrd[VR1] < BitOrd.BaseOrd[VR2];
}
-
bool RegisterCellBitCompareSel::operator() (unsigned VR1, unsigned VR2) const {
if (VR1 == VR2)
return false;
@@ -353,18 +364,22 @@ bool RegisterCellBitCompareSel::operator() (unsigned VR1, unsigned VR2) const {
return false;
}
-
namespace {
+
class OrderedRegisterList {
typedef std::vector<unsigned> ListType;
+
public:
OrderedRegisterList(const RegisterOrdering &RO) : Ord(RO) {}
+
void insert(unsigned VR);
void remove(unsigned VR);
+
unsigned operator[](unsigned Idx) const {
assert(Idx < Seq.size());
return Seq[Idx];
}
+
unsigned size() const {
return Seq.size();
}
@@ -378,16 +393,18 @@ namespace {
// Convenience function to convert an iterator to the corresponding index.
unsigned idx(iterator It) const { return It-begin(); }
+
private:
ListType Seq;
const RegisterOrdering &Ord;
};
-
struct PrintORL {
PrintORL(const OrderedRegisterList &L, const TargetRegisterInfo *RI)
: RL(L), TRI(RI) {}
+
friend raw_ostream &operator<< (raw_ostream &OS, const PrintORL &P);
+
private:
const OrderedRegisterList &RL;
const TargetRegisterInfo *TRI;
@@ -404,8 +421,8 @@ namespace {
OS << ')';
return OS;
}
-}
+} // end anonymous namespace
void OrderedRegisterList::insert(unsigned VR) {
iterator L = std::lower_bound(Seq.begin(), Seq.end(), VR, Ord);
@@ -415,21 +432,21 @@ void OrderedRegisterList::insert(unsigned VR) {
Seq.insert(L, VR);
}
-
void OrderedRegisterList::remove(unsigned VR) {
iterator L = std::lower_bound(Seq.begin(), Seq.end(), VR, Ord);
assert(L != Seq.end());
Seq.erase(L);
}
-
namespace {
+
// A record of the insert form. The fields correspond to the operands
// of the "insert" instruction:
// ... = insert(SrcR, InsR, #Wdh, #Off)
struct IFRecord {
IFRecord(unsigned SR = 0, unsigned IR = 0, uint16_t W = 0, uint16_t O = 0)
: SrcR(SR), InsR(IR), Wdh(W), Off(O) {}
+
unsigned SrcR, InsR;
uint16_t Wdh, Off;
};
@@ -437,10 +454,12 @@ namespace {
struct PrintIFR {
PrintIFR(const IFRecord &R, const TargetRegisterInfo *RI)
: IFR(R), TRI(RI) {}
+
private:
+ friend raw_ostream &operator<< (raw_ostream &OS, const PrintIFR &P);
+
const IFRecord &IFR;
const TargetRegisterInfo *TRI;
- friend raw_ostream &operator<< (raw_ostream &OS, const PrintIFR &P);
};
raw_ostream &operator<< (raw_ostream &OS, const PrintIFR &P) {
@@ -451,31 +470,37 @@ namespace {
}
typedef std::pair<IFRecord,RegisterSet> IFRecordWithRegSet;
-}
+} // end anonymous namespace
namespace llvm {
+
void initializeHexagonGenInsertPass(PassRegistry&);
FunctionPass *createHexagonGenInsert();
-}
+} // end namespace llvm
namespace {
+
class HexagonGenInsert : public MachineFunctionPass {
public:
static char ID;
- HexagonGenInsert() : MachineFunctionPass(ID), HII(0), HRI(0) {
+
+ HexagonGenInsert() : MachineFunctionPass(ID), HII(nullptr), HRI(nullptr) {
initializeHexagonGenInsertPass(*PassRegistry::getPassRegistry());
}
- virtual const char *getPassName() const {
+
+ StringRef getPassName() const override {
return "Hexagon generate \"insert\" instructions";
}
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
- virtual bool runOnMachineFunction(MachineFunction &MF);
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
private:
typedef DenseMap<std::pair<unsigned,unsigned>,unsigned> PairMapType;
@@ -533,8 +558,8 @@ namespace {
};
char HexagonGenInsert::ID = 0;
-}
+} // end anonymous namespace
void HexagonGenInsert::dump_map() const {
typedef IFMapType::const_iterator iterator;
@@ -547,7 +572,6 @@ void HexagonGenInsert::dump_map() const {
}
}
-
void HexagonGenInsert::buildOrderingMF(RegisterOrdering &RO) const {
unsigned Index = 0;
typedef MachineFunction::const_iterator mf_iterator;
@@ -574,7 +598,6 @@ void HexagonGenInsert::buildOrderingMF(RegisterOrdering &RO) const {
// in the map.
}
-
void HexagonGenInsert::buildOrderingBT(RegisterOrdering &RB,
RegisterOrdering &RO) const {
// Create a vector of all virtual registers (collect them from the base
@@ -591,12 +614,10 @@ void HexagonGenInsert::buildOrderingBT(RegisterOrdering &RB,
RO.insert(std::make_pair(VRs[i], i));
}
-
inline bool HexagonGenInsert::isIntClass(const TargetRegisterClass *RC) const {
return RC == &Hexagon::IntRegsRegClass || RC == &Hexagon::DoubleRegsRegClass;
}
-
bool HexagonGenInsert::isConstant(unsigned VR) const {
const BitTracker::RegisterCell &RC = CMS->lookup(VR);
uint16_t W = RC.width();
@@ -609,7 +630,6 @@ bool HexagonGenInsert::isConstant(unsigned VR) const {
return true;
}
-
bool HexagonGenInsert::isSmallConstant(unsigned VR) const {
const BitTracker::RegisterCell &RC = CMS->lookup(VR);
uint16_t W = RC.width();
@@ -633,7 +653,6 @@ bool HexagonGenInsert::isSmallConstant(unsigned VR) const {
return isInt<8>(Lo_32(V)) && isInt<8>(Hi_32(V));
}
-
bool HexagonGenInsert::isValidInsertForm(unsigned DstR, unsigned SrcR,
unsigned InsR, uint16_t L, uint16_t S) const {
const TargetRegisterClass *DstRC = MRI->getRegClass(DstR);
@@ -656,7 +675,6 @@ bool HexagonGenInsert::isValidInsertForm(unsigned DstR, unsigned SrcR,
return true;
}
-
bool HexagonGenInsert::findSelfReference(unsigned VR) const {
const BitTracker::RegisterCell &RC = CMS->lookup(VR);
for (uint16_t i = 0, w = RC.width(); i < w; ++i) {
@@ -667,7 +685,6 @@ bool HexagonGenInsert::findSelfReference(unsigned VR) const {
return false;
}
-
bool HexagonGenInsert::findNonSelfReference(unsigned VR) const {
BitTracker::RegisterCell RC = CMS->lookup(VR);
for (uint16_t i = 0, w = RC.width(); i < w; ++i) {
@@ -678,7 +695,6 @@ bool HexagonGenInsert::findNonSelfReference(unsigned VR) const {
return false;
}
-
void HexagonGenInsert::getInstrDefs(const MachineInstr *MI,
RegisterSet &Defs) const {
for (unsigned i = 0, n = MI->getNumOperands(); i < n; ++i) {
@@ -692,7 +708,6 @@ void HexagonGenInsert::getInstrDefs(const MachineInstr *MI,
}
}
-
void HexagonGenInsert::getInstrUses(const MachineInstr *MI,
RegisterSet &Uses) const {
for (unsigned i = 0, n = MI->getNumOperands(); i < n; ++i) {
@@ -706,7 +721,6 @@ void HexagonGenInsert::getInstrUses(const MachineInstr *MI,
}
}
-
unsigned HexagonGenInsert::distance(const MachineBasicBlock *FromB,
const MachineBasicBlock *ToB, const UnsignedMap &RPO,
PairMapType &M) const {
@@ -740,7 +754,6 @@ unsigned HexagonGenInsert::distance(const MachineBasicBlock *FromB,
return MaxD;
}
-
unsigned HexagonGenInsert::distance(MachineBasicBlock::const_iterator FromI,
MachineBasicBlock::const_iterator ToI, const UnsignedMap &RPO,
PairMapType &M) const {
@@ -753,11 +766,10 @@ unsigned HexagonGenInsert::distance(MachineBasicBlock::const_iterator FromI,
return D1+D2+D3;
}
-
bool HexagonGenInsert::findRecordInsertForms(unsigned VR,
OrderedRegisterList &AVs) {
if (isDebug()) {
- dbgs() << LLVM_FUNCTION_NAME << ": " << PrintReg(VR, HRI)
+ dbgs() << __func__ << ": " << PrintReg(VR, HRI)
<< " AVs: " << PrintORL(AVs, HRI) << "\n";
}
if (AVs.size() == 0)
@@ -832,7 +844,6 @@ bool HexagonGenInsert::findRecordInsertForms(unsigned VR,
}
}
-
bool Recorded = false;
for (iterator I = AVs.begin(), E = AVs.end(); I != E; ++I) {
@@ -888,7 +899,6 @@ bool HexagonGenInsert::findRecordInsertForms(unsigned VR,
return Recorded;
}
-
void HexagonGenInsert::collectInBlock(MachineBasicBlock *B,
OrderedRegisterList &AVs) {
if (isDebug())
@@ -949,7 +959,6 @@ void HexagonGenInsert::collectInBlock(MachineBasicBlock *B,
AVs.remove(VR);
}
-
void HexagonGenInsert::findRemovableRegisters(unsigned VR, IFRecord IF,
RegisterSet &RMs) const {
// For a given register VR and a insert form, find the registers that are
@@ -1001,7 +1010,6 @@ void HexagonGenInsert::findRemovableRegisters(unsigned VR, IFRecord IF,
RMs.remove(VR);
}
-
void HexagonGenInsert::computeRemovableRegisters() {
for (IFMapType::iterator I = IFMap.begin(), E = IFMap.end(); I != E; ++I) {
IFListType &LL = I->second;
@@ -1010,21 +1018,19 @@ void HexagonGenInsert::computeRemovableRegisters() {
}
}
-
void HexagonGenInsert::pruneEmptyLists() {
// Remove all entries from the map, where the register has no insert forms
// associated with it.
typedef SmallVector<IFMapType::iterator,16> IterListType;
IterListType Prune;
for (IFMapType::iterator I = IFMap.begin(), E = IFMap.end(); I != E; ++I) {
- if (I->second.size() == 0)
+ if (I->second.empty())
Prune.push_back(I);
}
for (unsigned i = 0, n = Prune.size(); i < n; ++i)
IFMap.erase(Prune[i]);
}
-
void HexagonGenInsert::pruneCoveredSets(unsigned VR) {
IFMapType::iterator F = IFMap.find(VR);
assert(F != IFMap.end());
@@ -1038,7 +1044,7 @@ void HexagonGenInsert::pruneCoveredSets(unsigned VR) {
// If there exists a candidate with a non-empty set, the ones with empty
// sets will not be used and can be removed.
MachineInstr *DefVR = MRI->getVRegDef(VR);
- bool DefEx = HII->isConstExtended(DefVR);
+ bool DefEx = HII->isConstExtended(*DefVR);
bool HasNE = false;
for (unsigned i = 0, n = LL.size(); i < n; ++i) {
if (LL[i].second.empty())
@@ -1052,7 +1058,7 @@ void HexagonGenInsert::pruneCoveredSets(unsigned VR) {
auto IsEmpty = [] (const IFRecordWithRegSet &IR) -> bool {
return IR.second.empty();
};
- auto End = std::remove_if(LL.begin(), LL.end(), IsEmpty);
+ auto End = llvm::remove_if(LL, IsEmpty);
if (End != LL.end())
LL.erase(End, LL.end());
} else {
@@ -1112,7 +1118,6 @@ void HexagonGenInsert::pruneCoveredSets(unsigned VR) {
}
}
-
void HexagonGenInsert::pruneUsesTooFar(unsigned VR, const UnsignedMap &RPO,
PairMapType &M) {
IFMapType::iterator F = IFMap.find(VR);
@@ -1135,7 +1140,6 @@ void HexagonGenInsert::pruneUsesTooFar(unsigned VR, const UnsignedMap &RPO,
}
}
-
void HexagonGenInsert::pruneRegCopies(unsigned VR) {
IFMapType::iterator F = IFMap.find(VR);
assert(F != IFMap.end());
@@ -1144,12 +1148,11 @@ void HexagonGenInsert::pruneRegCopies(unsigned VR) {
auto IsCopy = [] (const IFRecordWithRegSet &IR) -> bool {
return IR.first.Wdh == 32 && (IR.first.Off == 0 || IR.first.Off == 32);
};
- auto End = std::remove_if(LL.begin(), LL.end(), IsCopy);
+ auto End = llvm::remove_if(LL, IsCopy);
if (End != LL.end())
LL.erase(End, LL.end());
}
-
void HexagonGenInsert::pruneCandidates() {
// Remove candidates that are not beneficial, regardless of the final
// selection method.
@@ -1176,8 +1179,8 @@ void HexagonGenInsert::pruneCandidates() {
pruneRegCopies(I->first);
}
-
namespace {
+
// Class for comparing IF candidates for registers that have multiple of
// them. The smaller the candidate, according to this ordering, the better.
// First, compare the number of zeros in the associated potentially remova-
@@ -1189,16 +1192,19 @@ namespace {
struct IFOrdering {
IFOrdering(const UnsignedMap &UC, const RegisterOrdering &BO)
: UseC(UC), BaseOrd(BO) {}
+
bool operator() (const IFRecordWithRegSet &A,
const IFRecordWithRegSet &B) const;
+
private:
void stats(const RegisterSet &Rs, unsigned &Size, unsigned &Zero,
unsigned &Sum) const;
+
const UnsignedMap &UseC;
const RegisterOrdering &BaseOrd;
};
-}
+} // end anonymous namespace
bool IFOrdering::operator() (const IFRecordWithRegSet &A,
const IFRecordWithRegSet &B) const {
@@ -1228,7 +1234,6 @@ bool IFOrdering::operator() (const IFRecordWithRegSet &A,
return A.first.Off < B.first.Off;
}
-
void IFOrdering::stats(const RegisterSet &Rs, unsigned &Size, unsigned &Zero,
unsigned &Sum) const {
for (unsigned R = Rs.find_first(); R; R = Rs.find_next(R)) {
@@ -1242,7 +1247,6 @@ void IFOrdering::stats(const RegisterSet &Rs, unsigned &Size, unsigned &Zero,
}
}
-
void HexagonGenInsert::selectCandidates() {
// Some registers may have multiple valid candidates. Pick the best one
// (or decide not to use any).
@@ -1280,7 +1284,6 @@ void HexagonGenInsert::selectCandidates() {
UseC[R] = (C > D) ? C-D : 0; // doz
}
-
bool SelectAll0 = OptSelectAll0, SelectHas0 = OptSelectHas0;
if (!SelectAll0 && !SelectHas0)
SelectAll0 = true;
@@ -1345,12 +1348,12 @@ void HexagonGenInsert::selectCandidates() {
AllRMs.clear();
for (IFMapType::iterator I = IFMap.begin(); I != End; ++I) {
const IFListType &LL = I->second;
- if (LL.size() > 0)
+ if (!LL.empty())
AllRMs.insert(LL[0].second);
}
for (IFMapType::iterator I = IFMap.begin(); I != End; ++I) {
IFListType &LL = I->second;
- if (LL.size() == 0)
+ if (LL.empty())
continue;
unsigned SR = LL[0].first.SrcR, IR = LL[0].first.InsR;
if (AllRMs[SR] || AllRMs[IR])
@@ -1360,7 +1363,6 @@ void HexagonGenInsert::selectCandidates() {
pruneEmptyLists();
}
-
bool HexagonGenInsert::generateInserts() {
// Create a new register for each one from IFMap, and store them in the
// map.
@@ -1387,9 +1389,9 @@ bool HexagonGenInsert::generateInserts() {
unsigned Wdh = IF.Wdh, Off = IF.Off;
unsigned InsS = 0;
if (R32 && MRI->getRegClass(IF.InsR) == &Hexagon::DoubleRegsRegClass) {
- InsS = Hexagon::subreg_loreg;
+ InsS = Hexagon::isub_lo;
if (Off >= 32) {
- InsS = Hexagon::subreg_hireg;
+ InsS = Hexagon::isub_hi;
Off -= 32;
}
}
@@ -1418,7 +1420,6 @@ bool HexagonGenInsert::generateInserts() {
return true;
}
-
bool HexagonGenInsert::removeDeadCode(MachineDomTreeNode *N) {
bool Changed = false;
typedef GraphTraits<MachineDomTreeNode*> GTN;
@@ -1444,10 +1445,10 @@ bool HexagonGenInsert::removeDeadCode(MachineDomTreeNode *N) {
bool AllDead = true;
SmallVector<unsigned,2> Regs;
- for (ConstMIOperands Op(*MI); Op.isValid(); ++Op) {
- if (!Op->isReg() || !Op->isDef())
+ for (const MachineOperand &MO : MI->operands()) {
+ if (!MO.isReg() || !MO.isDef())
continue;
- unsigned R = Op->getReg();
+ unsigned R = MO.getReg();
if (!TargetRegisterInfo::isVirtualRegister(R) ||
!MRI->use_nodbg_empty(R)) {
AllDead = false;
@@ -1467,15 +1468,12 @@ bool HexagonGenInsert::removeDeadCode(MachineDomTreeNode *N) {
return Changed;
}
-
bool HexagonGenInsert::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
bool Timing = OptTiming, TimingDetail = Timing && OptTimingDetail;
bool Changed = false;
- TimerGroup __G("hexinsert");
- NamedRegionTimer __T("hexinsert", Timing && !TimingDetail);
// Sanity check: one, but not both.
assert(!OptSelectAll0 || !OptSelectHas0);
@@ -1521,8 +1519,12 @@ bool HexagonGenInsert::runOnMachineFunction(MachineFunction &MF) {
MachineBasicBlock *RootB = MDT->getRoot();
OrderedRegisterList AvailR(CellOrd);
+ const char *const TGName = "hexinsert";
+ const char *const TGDesc = "Generate Insert Instructions";
+
{
- NamedRegionTimer _T("collection", "hexinsert", TimingDetail);
+ NamedRegionTimer _T("collection", "collection", TGName, TGDesc,
+ TimingDetail);
collectInBlock(RootB, AvailR);
// Complete the information gathered in IFMap.
computeRemovableRegisters();
@@ -1537,7 +1539,7 @@ bool HexagonGenInsert::runOnMachineFunction(MachineFunction &MF) {
return Changed;
{
- NamedRegionTimer _T("pruning", "hexinsert", TimingDetail);
+ NamedRegionTimer _T("pruning", "pruning", TGName, TGDesc, TimingDetail);
pruneCandidates();
}
@@ -1550,7 +1552,7 @@ bool HexagonGenInsert::runOnMachineFunction(MachineFunction &MF) {
return Changed;
{
- NamedRegionTimer _T("selection", "hexinsert", TimingDetail);
+ NamedRegionTimer _T("selection", "selection", TGName, TGDesc, TimingDetail);
selectCandidates();
}
@@ -1576,19 +1578,18 @@ bool HexagonGenInsert::runOnMachineFunction(MachineFunction &MF) {
return Changed;
{
- NamedRegionTimer _T("generation", "hexinsert", TimingDetail);
+ NamedRegionTimer _T("generation", "generation", TGName, TGDesc,
+ TimingDetail);
generateInserts();
}
return true;
}
-
FunctionPass *llvm::createHexagonGenInsert() {
return new HexagonGenInsert();
}
-
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp
index bb9256d..a718df9 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp
@@ -22,36 +22,60 @@
#define DEBUG_TYPE "hexmux"
-#include "llvm/CodeGen/Passes.h"
+#include "HexagonInstrInfo.h"
+#include "HexagonRegisterInfo.h"
+#include "HexagonSubtarget.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "HexagonTargetMachine.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <limits>
+#include <iterator>
+#include <utility>
using namespace llvm;
namespace llvm {
+
FunctionPass *createHexagonGenMux();
void initializeHexagonGenMuxPass(PassRegistry& Registry);
-}
+
+} // end namespace llvm
namespace {
+
class HexagonGenMux : public MachineFunctionPass {
public:
static char ID;
- HexagonGenMux() : MachineFunctionPass(ID), HII(0), HRI(0) {
+
+ HexagonGenMux() : MachineFunctionPass(ID), HII(nullptr), HRI(nullptr) {
initializeHexagonGenMuxPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
+
+ StringRef getPassName() const override {
return "Hexagon generate mux instructions";
}
+
void getAnalysisUsage(AnalysisUsage &AU) const override {
MachineFunctionPass::getAnalysisUsage(AU);
}
+
bool runOnMachineFunction(MachineFunction &MF) override;
+
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -59,26 +83,33 @@ namespace {
const HexagonRegisterInfo *HRI;
struct CondsetInfo {
- unsigned PredR;
- unsigned TrueX, FalseX;
- CondsetInfo() : PredR(0), TrueX(UINT_MAX), FalseX(UINT_MAX) {}
+ unsigned PredR = 0;
+ unsigned TrueX = std::numeric_limits<unsigned>::max();
+ unsigned FalseX = std::numeric_limits<unsigned>::max();
+
+ CondsetInfo() = default;
};
+
struct DefUseInfo {
BitVector Defs, Uses;
- DefUseInfo() : Defs(), Uses() {}
+
+ DefUseInfo() = default;
DefUseInfo(const BitVector &D, const BitVector &U) : Defs(D), Uses(U) {}
};
+
struct MuxInfo {
MachineBasicBlock::iterator At;
unsigned DefR, PredR;
MachineOperand *SrcT, *SrcF;
MachineInstr *Def1, *Def2;
+
MuxInfo(MachineBasicBlock::iterator It, unsigned DR, unsigned PR,
MachineOperand *TOp, MachineOperand *FOp, MachineInstr &D1,
MachineInstr &D2)
: At(It), DefR(DR), PredR(PR), SrcT(TOp), SrcF(FOp), Def1(&D1),
Def2(&D2) {}
};
+
typedef DenseMap<MachineInstr*,unsigned> InstrIndexMap;
typedef DenseMap<unsigned,DefUseInfo> DefUseInfoMap;
typedef SmallVector<MuxInfo,4> MuxInfoList;
@@ -86,6 +117,7 @@ namespace {
bool isRegPair(unsigned Reg) const {
return Hexagon::DoubleRegsRegClass.contains(Reg);
}
+
void getSubRegs(unsigned Reg, BitVector &SRs) const;
void expandReg(unsigned Reg, BitVector &Set) const;
void getDefsUses(const MachineInstr *MI, BitVector &Defs,
@@ -99,18 +131,17 @@ namespace {
};
char HexagonGenMux::ID = 0;
-}
+
+} // end anonymous namespace
INITIALIZE_PASS(HexagonGenMux, "hexagon-mux",
"Hexagon generate mux instructions", false, false)
-
void HexagonGenMux::getSubRegs(unsigned Reg, BitVector &SRs) const {
for (MCSubRegIterator I(Reg, HRI); I.isValid(); ++I)
SRs[*I] = true;
}
-
void HexagonGenMux::expandReg(unsigned Reg, BitVector &Set) const {
if (isRegPair(Reg))
getSubRegs(Reg, Set);
@@ -118,7 +149,6 @@ void HexagonGenMux::expandReg(unsigned Reg, BitVector &Set) const {
Set[Reg] = true;
}
-
void HexagonGenMux::getDefsUses(const MachineInstr *MI, BitVector &Defs,
BitVector &Uses) const {
// First, get the implicit defs and uses for this instruction.
@@ -132,16 +162,15 @@ void HexagonGenMux::getDefsUses(const MachineInstr *MI, BitVector &Defs,
expandReg(*R++, Uses);
// Look over all operands, and collect explicit defs and uses.
- for (ConstMIOperands Mo(*MI); Mo.isValid(); ++Mo) {
- if (!Mo->isReg() || Mo->isImplicit())
+ for (const MachineOperand &MO : MI->operands()) {
+ if (!MO.isReg() || MO.isImplicit())
continue;
- unsigned R = Mo->getReg();
- BitVector &Set = Mo->isDef() ? Defs : Uses;
+ unsigned R = MO.getReg();
+ BitVector &Set = MO.isDef() ? Defs : Uses;
expandReg(R, Set);
}
}
-
void HexagonGenMux::buildMaps(MachineBasicBlock &B, InstrIndexMap &I2X,
DefUseInfoMap &DUM) {
unsigned Index = 0;
@@ -159,7 +188,6 @@ void HexagonGenMux::buildMaps(MachineBasicBlock &B, InstrIndexMap &I2X,
}
}
-
bool HexagonGenMux::isCondTransfer(unsigned Opc) const {
switch (Opc) {
case Hexagon::A2_tfrt:
@@ -171,7 +199,6 @@ bool HexagonGenMux::isCondTransfer(unsigned Opc) const {
return false;
}
-
unsigned HexagonGenMux::getMuxOpcode(const MachineOperand &Src1,
const MachineOperand &Src2) const {
bool IsReg1 = Src1.isReg(), IsReg2 = Src2.isReg();
@@ -188,7 +215,6 @@ unsigned HexagonGenMux::getMuxOpcode(const MachineOperand &Src1,
return 0;
}
-
bool HexagonGenMux::genMuxInBlock(MachineBasicBlock &B) {
bool Changed = false;
InstrIndexMap I2X;
@@ -231,7 +257,8 @@ bool HexagonGenMux::genMuxInBlock(MachineBasicBlock &B) {
CI.TrueX = Idx;
else
CI.FalseX = Idx;
- if (CI.TrueX == UINT_MAX || CI.FalseX == UINT_MAX)
+ if (CI.TrueX == std::numeric_limits<unsigned>::max() ||
+ CI.FalseX == std::numeric_limits<unsigned>::max())
continue;
// There is now a complete definition of DR, i.e. we have the predicate
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonGenPredicate.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonGenPredicate.cpp
index dcfd3e8..f14c733 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonGenPredicate.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonGenPredicate.cpp
@@ -9,49 +9,68 @@
#define DEBUG_TYPE "gen-pred"
-#include "HexagonTargetMachine.h"
+#include "HexagonInstrInfo.h"
+#include "HexagonSubtarget.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
-
-#include <functional>
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <iterator>
+#include <map>
#include <queue>
#include <set>
+#include <utility>
using namespace llvm;
namespace llvm {
+
void initializeHexagonGenPredicatePass(PassRegistry& Registry);
FunctionPass *createHexagonGenPredicate();
-}
+
+} // end namespace llvm
namespace {
+
struct Register {
unsigned R, S;
+
Register(unsigned r = 0, unsigned s = 0) : R(r), S(s) {}
Register(const MachineOperand &MO) : R(MO.getReg()), S(MO.getSubReg()) {}
+
bool operator== (const Register &Reg) const {
return R == Reg.R && S == Reg.S;
}
+
bool operator< (const Register &Reg) const {
return R < Reg.R || (R == Reg.R && S < Reg.S);
}
};
+
struct PrintRegister {
- PrintRegister(Register R, const TargetRegisterInfo &I) : Reg(R), TRI(I) {}
friend raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR);
+
+ PrintRegister(Register R, const TargetRegisterInfo &I) : Reg(R), TRI(I) {}
+
private:
Register Reg;
const TargetRegisterInfo &TRI;
};
+
raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR)
LLVM_ATTRIBUTE_UNUSED;
raw_ostream &operator<< (raw_ostream &OS, const PrintRegister &PR) {
@@ -61,18 +80,23 @@ namespace {
class HexagonGenPredicate : public MachineFunctionPass {
public:
static char ID;
- HexagonGenPredicate() : MachineFunctionPass(ID), TII(0), TRI(0), MRI(0) {
+
+ HexagonGenPredicate() : MachineFunctionPass(ID), TII(nullptr), TRI(nullptr),
+ MRI(nullptr) {
initializeHexagonGenPredicatePass(*PassRegistry::getPassRegistry());
}
- virtual const char *getPassName() const {
+
+ StringRef getPassName() const override {
return "Hexagon generate predicate operations";
}
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
- virtual bool runOnMachineFunction(MachineFunction &MF);
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
private:
typedef SetVector<MachineInstr*> VectOfInst;
@@ -99,7 +123,8 @@ namespace {
};
char HexagonGenPredicate::ID = 0;
-}
+
+} // end anonymous namespace
INITIALIZE_PASS_BEGIN(HexagonGenPredicate, "hexagon-gen-pred",
"Hexagon generate predicate operations", false, false)
@@ -114,7 +139,6 @@ bool HexagonGenPredicate::isPredReg(unsigned R) {
return RC == &Hexagon::PredRegsRegClass;
}
-
unsigned HexagonGenPredicate::getPredForm(unsigned Opc) {
using namespace Hexagon;
@@ -159,7 +183,6 @@ unsigned HexagonGenPredicate::getPredForm(unsigned Opc) {
return 0;
}
-
bool HexagonGenPredicate::isConvertibleToPredForm(const MachineInstr *MI) {
unsigned Opc = MI->getOpcode();
if (getPredForm(Opc) != 0)
@@ -179,7 +202,6 @@ bool HexagonGenPredicate::isConvertibleToPredForm(const MachineInstr *MI) {
return false;
}
-
void HexagonGenPredicate::collectPredicateGPR(MachineFunction &MF) {
for (MachineFunction::iterator A = MF.begin(), Z = MF.end(); A != Z; ++A) {
MachineBasicBlock &B = *A;
@@ -200,9 +222,8 @@ void HexagonGenPredicate::collectPredicateGPR(MachineFunction &MF) {
}
}
-
void HexagonGenPredicate::processPredicateGPR(const Register &Reg) {
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << ": "
+ DEBUG(dbgs() << __func__ << ": "
<< PrintReg(Reg.R, TRI, Reg.S) << "\n");
typedef MachineRegisterInfo::use_iterator use_iterator;
use_iterator I = MRI->use_begin(Reg.R), E = MRI->use_end();
@@ -220,7 +241,6 @@ void HexagonGenPredicate::processPredicateGPR(const Register &Reg) {
}
}
-
Register HexagonGenPredicate::getPredRegFor(const Register &Reg) {
// Create a predicate register for a given Reg. The newly created register
// will have its value copied from Reg, so that it can be later used as
@@ -230,7 +250,7 @@ Register HexagonGenPredicate::getPredRegFor(const Register &Reg) {
if (F != G2P.end())
return F->second;
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << ": " << PrintRegister(Reg, *TRI));
+ DEBUG(dbgs() << __func__ << ": " << PrintRegister(Reg, *TRI));
MachineInstr *DefI = MRI->getVRegDef(Reg.R);
assert(DefI);
unsigned Opc = DefI->getOpcode();
@@ -261,7 +281,6 @@ Register HexagonGenPredicate::getPredRegFor(const Register &Reg) {
llvm_unreachable("Invalid argument");
}
-
bool HexagonGenPredicate::isScalarCmp(unsigned Opc) {
switch (Opc) {
case Hexagon::C2_cmpeq:
@@ -298,7 +317,6 @@ bool HexagonGenPredicate::isScalarCmp(unsigned Opc) {
return false;
}
-
bool HexagonGenPredicate::isScalarPred(Register PredReg) {
std::queue<Register> WorkQ;
WorkQ.push(PredReg);
@@ -330,9 +348,9 @@ bool HexagonGenPredicate::isScalarPred(Register PredReg) {
case Hexagon::C4_or_orn:
case Hexagon::C2_xor:
// Add operands to the queue.
- for (ConstMIOperands Mo(*DefI); Mo.isValid(); ++Mo)
- if (Mo->isReg() && Mo->isUse())
- WorkQ.push(Register(Mo->getReg()));
+ for (const MachineOperand &MO : DefI->operands())
+ if (MO.isReg() && MO.isUse())
+ WorkQ.push(Register(MO.getReg()));
break;
// All non-vector compares are ok, everything else is bad.
@@ -344,9 +362,8 @@ bool HexagonGenPredicate::isScalarPred(Register PredReg) {
return true;
}
-
bool HexagonGenPredicate::convertToPredForm(MachineInstr *MI) {
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << ": " << MI << " " << *MI);
+ DEBUG(dbgs() << __func__ << ": " << MI << " " << *MI);
unsigned Opc = MI->getOpcode();
assert(isConvertibleToPredForm(MI));
@@ -356,7 +373,7 @@ bool HexagonGenPredicate::convertToPredForm(MachineInstr *MI) {
if (!MO.isReg() || !MO.isUse())
continue;
Register Reg(MO);
- if (Reg.S && Reg.S != Hexagon::subreg_loreg)
+ if (Reg.S && Reg.S != Hexagon::isub_lo)
return false;
if (!PredGPRs.count(Reg))
return false;
@@ -430,9 +447,8 @@ bool HexagonGenPredicate::convertToPredForm(MachineInstr *MI) {
return true;
}
-
bool HexagonGenPredicate::eliminatePredCopies(MachineFunction &MF) {
- DEBUG(dbgs() << LLVM_FUNCTION_NAME << "\n");
+ DEBUG(dbgs() << __func__ << "\n");
const TargetRegisterClass *PredRC = &Hexagon::PredRegsRegClass;
bool Changed = false;
VectOfInst Erase;
@@ -474,7 +490,6 @@ bool HexagonGenPredicate::eliminatePredCopies(MachineFunction &MF) {
return Changed;
}
-
bool HexagonGenPredicate::runOnMachineFunction(MachineFunction &MF) {
if (skipFunction(*MF.getFunction()))
return false;
@@ -518,8 +533,6 @@ bool HexagonGenPredicate::runOnMachineFunction(MachineFunction &MF) {
return Changed;
}
-
FunctionPass *llvm::createHexagonGenPredicate() {
return new HexagonGenPredicate();
}
-
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonHardwareLoops.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonHardwareLoops.cpp
index cc154c4..e477dcc 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonHardwareLoops.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonHardwareLoops.cpp
@@ -25,22 +25,37 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/SmallSet.h"
-#include "Hexagon.h"
+#include "HexagonInstrInfo.h"
#include "HexagonSubtarget.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/PassSupport.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include <algorithm>
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+#include <map>
+#include <set>
+#include <utility>
#include <vector>
using namespace llvm;
@@ -60,15 +75,26 @@ static cl::opt<bool> HWCreatePreheader("hexagon-hwloop-preheader",
cl::Hidden, cl::init(true),
cl::desc("Add a preheader to a hardware loop if one doesn't exist"));
+// Turn it off by default. If a preheader block is not created here, the
+// software pipeliner may be unable to find a block suitable to serve as
+// a preheader. In that case SWP will not run.
+static cl::opt<bool> SpecPreheader("hwloop-spec-preheader", cl::init(false),
+ cl::Hidden, cl::ZeroOrMore, cl::desc("Allow speculation of preheader "
+ "instructions"));
+
STATISTIC(NumHWLoops, "Number of loops converted to hardware loops");
namespace llvm {
+
FunctionPass *createHexagonHardwareLoops();
void initializeHexagonHardwareLoopsPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
+
class CountValue;
+
struct HexagonHardwareLoops : public MachineFunctionPass {
MachineLoopInfo *MLI;
MachineRegisterInfo *MRI;
@@ -87,7 +113,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override { return "Hexagon Hardware Loops"; }
+ StringRef getPassName() const override { return "Hexagon Hardware Loops"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineDominatorTree>();
@@ -138,7 +164,6 @@ namespace {
static bool isUnsigned(Kind Cmp) {
return (Cmp & U);
}
-
};
/// \brief Find the register that contains the loop controlling
@@ -289,6 +314,7 @@ namespace {
CV_Register,
CV_Immediate
};
+
private:
CountValueType Kind;
union Values {
@@ -309,6 +335,7 @@ namespace {
Contents.ImmVal = v;
}
}
+
bool isReg() const { return Kind == CV_Register; }
bool isImm() const { return Kind == CV_Immediate; }
@@ -330,8 +357,8 @@ namespace {
if (isImm()) { OS << Contents.ImmVal; }
}
};
-} // end anonymous namespace
+} // end anonymous namespace
INITIALIZE_PASS_BEGIN(HexagonHardwareLoops, "hwloops",
"Hexagon Hardware Loops", false, false)
@@ -366,28 +393,15 @@ bool HexagonHardwareLoops::runOnMachineFunction(MachineFunction &MF) {
return Changed;
}
-/// \brief Return the latch block if it's one of the exiting blocks. Otherwise,
-/// return the exiting block. Return 'null' when multiple exiting blocks are
-/// present.
-static MachineBasicBlock* getExitingBlock(MachineLoop *L) {
- if (MachineBasicBlock *Latch = L->getLoopLatch()) {
- if (L->isLoopExiting(Latch))
- return Latch;
- else
- return L->getExitingBlock();
- }
- return nullptr;
-}
-
bool HexagonHardwareLoops::findInductionRegister(MachineLoop *L,
unsigned &Reg,
int64_t &IVBump,
MachineInstr *&IVOp
) const {
MachineBasicBlock *Header = L->getHeader();
- MachineBasicBlock *Preheader = L->getLoopPreheader();
+ MachineBasicBlock *Preheader = MLI->findLoopPreheader(L, SpecPreheader);
MachineBasicBlock *Latch = L->getLoopLatch();
- MachineBasicBlock *ExitingBlock = getExitingBlock(L);
+ MachineBasicBlock *ExitingBlock = L->findLoopControlBlock();
if (!Header || !Preheader || !Latch || !ExitingBlock)
return false;
@@ -417,10 +431,8 @@ bool HexagonHardwareLoops::findInductionRegister(MachineLoop *L,
unsigned PhiOpReg = Phi->getOperand(i).getReg();
MachineInstr *DI = MRI->getVRegDef(PhiOpReg);
- unsigned UpdOpc = DI->getOpcode();
- bool isAdd = (UpdOpc == Hexagon::A2_addi || UpdOpc == Hexagon::A2_addp);
- if (isAdd) {
+ if (DI->getDesc().isAdd()) {
// If the register operand to the add is the PHI we're looking at, this
// meets the induction pattern.
unsigned IndReg = DI->getOperand(1).getReg();
@@ -555,7 +567,7 @@ CountValue *HexagonHardwareLoops::getLoopTripCount(MachineLoop *L,
// Look for the cmp instruction to determine if we can get a useful trip
// count. The trip count can be either a register or an immediate. The
// location of the value depends upon the type (reg or imm).
- MachineBasicBlock *ExitingBlock = getExitingBlock(L);
+ MachineBasicBlock *ExitingBlock = L->findLoopControlBlock();
if (!ExitingBlock)
return nullptr;
@@ -566,7 +578,7 @@ CountValue *HexagonHardwareLoops::getLoopTripCount(MachineLoop *L,
if (!FoundIV)
return nullptr;
- MachineBasicBlock *Preheader = L->getLoopPreheader();
+ MachineBasicBlock *Preheader = MLI->findLoopPreheader(L, SpecPreheader);
MachineOperand *InitialValue = nullptr;
MachineInstr *IV_Phi = MRI->getVRegDef(IVReg);
@@ -593,7 +605,7 @@ CountValue *HexagonHardwareLoops::getLoopTripCount(MachineLoop *L,
// the fall through can go to the header.
assert (TB && "Exit block without a branch?");
if (ExitingBlock != Latch && (TB == Latch || FB == Latch)) {
- MachineBasicBlock *LTB = 0, *LFB = 0;
+ MachineBasicBlock *LTB = nullptr, *LFB = nullptr;
SmallVector<MachineOperand,2> LCond;
bool NotAnalyzed = TII->analyzeBranch(*Latch, LTB, LFB, LCond, false);
if (NotAnalyzed)
@@ -787,7 +799,7 @@ CountValue *HexagonHardwareLoops::computeCount(MachineLoop *Loop,
if (!isPowerOf2_64(std::abs(IVBump)))
return nullptr;
- MachineBasicBlock *PH = Loop->getLoopPreheader();
+ MachineBasicBlock *PH = MLI->findLoopPreheader(Loop, SpecPreheader);
assert (PH && "Should have a preheader by now");
MachineBasicBlock::iterator InsertPos = PH->getFirstTerminator();
DebugLoc DL;
@@ -951,8 +963,8 @@ bool HexagonHardwareLoops::isInvalidLoopOperation(const MachineInstr *MI,
// Call is not allowed because the callee may use a hardware loop except for
// the case when the call never returns.
- if (MI->getDesc().isCall() && MI->getOpcode() != Hexagon::CALLv3nr)
- return true;
+ if (MI->getDesc().isCall())
+ return !TII->doesNotReturn(*MI);
// Check if the instruction defines a hardware loop register.
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
@@ -1138,7 +1150,7 @@ bool HexagonHardwareLoops::convertToHardwareLoop(MachineLoop *L,
if (containsInvalidInstruction(L, IsInnerHWLoop))
return false;
- MachineBasicBlock *LastMBB = getExitingBlock(L);
+ MachineBasicBlock *LastMBB = L->findLoopControlBlock();
// Don't generate hw loop if the loop has more than one exit.
if (!LastMBB)
return false;
@@ -1153,7 +1165,7 @@ bool HexagonHardwareLoops::convertToHardwareLoop(MachineLoop *L,
// Ensure the loop has a preheader: the loop instruction will be
// placed there.
- MachineBasicBlock *Preheader = L->getLoopPreheader();
+ MachineBasicBlock *Preheader = MLI->findLoopPreheader(L, SpecPreheader);
if (!Preheader) {
Preheader = createPreheaderForLoop(L);
if (!Preheader)
@@ -1180,10 +1192,10 @@ bool HexagonHardwareLoops::convertToHardwareLoop(MachineLoop *L,
// Determine the loop start.
MachineBasicBlock *TopBlock = L->getTopBlock();
- MachineBasicBlock *ExitingBlock = getExitingBlock(L);
- MachineBasicBlock *LoopStart = 0;
+ MachineBasicBlock *ExitingBlock = L->findLoopControlBlock();
+ MachineBasicBlock *LoopStart = nullptr;
if (ExitingBlock != L->getLoopLatch()) {
- MachineBasicBlock *TB = 0, *FB = 0;
+ MachineBasicBlock *TB = nullptr, *FB = nullptr;
SmallVector<MachineOperand, 2> Cond;
if (TII->analyzeBranch(*ExitingBlock, TB, FB, Cond, false))
@@ -1254,7 +1266,7 @@ bool HexagonHardwareLoops::convertToHardwareLoop(MachineLoop *L,
if (LastI != LastMBB->end())
LastI = LastMBB->erase(LastI);
SmallVector<MachineOperand, 0> Cond;
- TII->InsertBranch(*LastMBB, BranchTarget, nullptr, Cond, LastIDL);
+ TII->insertBranch(*LastMBB, BranchTarget, nullptr, Cond, LastIDL);
}
} else {
// Conditional branch to loop start; just delete it.
@@ -1423,12 +1435,13 @@ bool HexagonHardwareLoops::loopCountMayWrapOrUnderFlow(
if (!TII->analyzeCompare(*MI, CmpReg1, CmpReg2, CmpMask, CmpValue))
continue;
- MachineBasicBlock *TBB = 0, *FBB = 0;
+ MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
SmallVector<MachineOperand, 2> Cond;
if (TII->analyzeBranch(*MI->getParent(), TBB, FBB, Cond, false))
continue;
- Comparison::Kind Cmp = getComparisonKind(MI->getOpcode(), 0, 0, 0);
+ Comparison::Kind Cmp =
+ getComparisonKind(MI->getOpcode(), nullptr, nullptr, 0);
if (Cmp == 0)
continue;
if (TII->predOpcodeHasNot(Cond) ^ (TBB != MBB))
@@ -1479,8 +1492,8 @@ bool HexagonHardwareLoops::checkForImmediate(const MachineOperand &MO,
case TargetOpcode::COPY:
case Hexagon::A2_tfrsi:
case Hexagon::A2_tfrpi:
- case Hexagon::CONST32_Int_Real:
- case Hexagon::CONST64_Int_Real: {
+ case Hexagon::CONST32:
+ case Hexagon::CONST64: {
// Call recursively to avoid an extra check whether operand(1) is
// indeed an immediate (it could be a global address, for example),
// plus we can handle COPY at the same time.
@@ -1509,9 +1522,9 @@ bool HexagonHardwareLoops::checkForImmediate(const MachineOperand &MO,
return false;
unsigned Sub2 = DI->getOperand(2).getImm();
unsigned Sub4 = DI->getOperand(4).getImm();
- if (Sub2 == Hexagon::subreg_loreg && Sub4 == Hexagon::subreg_hireg)
+ if (Sub2 == Hexagon::isub_lo && Sub4 == Hexagon::isub_hi)
TV = V1 | (V3 << 32);
- else if (Sub2 == Hexagon::subreg_hireg && Sub4 == Hexagon::subreg_loreg)
+ else if (Sub2 == Hexagon::isub_hi && Sub4 == Hexagon::isub_lo)
TV = V3 | (V1 << 32);
else
llvm_unreachable("Unexpected form of REG_SEQUENCE");
@@ -1522,13 +1535,13 @@ bool HexagonHardwareLoops::checkForImmediate(const MachineOperand &MO,
return false;
}
- // By now, we should have successfuly obtained the immediate value defining
+ // By now, we should have successfully obtained the immediate value defining
// the register referenced in MO. Handle a potential use of a subregister.
switch (MO.getSubReg()) {
- case Hexagon::subreg_loreg:
+ case Hexagon::isub_lo:
Val = TV & 0xFFFFFFFFULL;
break;
- case Hexagon::subreg_hireg:
+ case Hexagon::isub_hi:
Val = (TV >> 32) & 0xFFFFFFFFULL;
break;
default:
@@ -1569,7 +1582,7 @@ static bool isImmValidForOpcode(unsigned CmpOpc, int64_t Imm) {
bool HexagonHardwareLoops::fixupInductionVariable(MachineLoop *L) {
MachineBasicBlock *Header = L->getHeader();
MachineBasicBlock *Latch = L->getLoopLatch();
- MachineBasicBlock *ExitingBlock = getExitingBlock(L);
+ MachineBasicBlock *ExitingBlock = L->findLoopControlBlock();
if (!(Header && Latch && ExitingBlock))
return false;
@@ -1598,10 +1611,8 @@ bool HexagonHardwareLoops::fixupInductionVariable(MachineLoop *L) {
unsigned PhiReg = Phi->getOperand(i).getReg();
MachineInstr *DI = MRI->getVRegDef(PhiReg);
- unsigned UpdOpc = DI->getOpcode();
- bool isAdd = (UpdOpc == Hexagon::A2_addi || UpdOpc == Hexagon::A2_addp);
- if (isAdd) {
+ if (DI->getDesc().isAdd()) {
// If the register operand to the add/sub is the PHI we are looking
// at, this meets the induction pattern.
unsigned IndReg = DI->getOperand(1).getReg();
@@ -1626,7 +1637,7 @@ bool HexagonHardwareLoops::fixupInductionVariable(MachineLoop *L) {
return false;
if (ExitingBlock != Latch && (TB == Latch || FB == Latch)) {
- MachineBasicBlock *LTB = 0, *LFB = 0;
+ MachineBasicBlock *LTB = nullptr, *LFB = nullptr;
SmallVector<MachineOperand,2> LCond;
bool NotAnalyzed = TII->analyzeBranch(*Latch, LTB, LFB, LCond, false);
if (NotAnalyzed)
@@ -1764,7 +1775,8 @@ bool HexagonHardwareLoops::fixupInductionVariable(MachineLoop *L) {
// It is not valid to do this transformation on an unsigned comparison
// because it may underflow.
- Comparison::Kind Cmp = getComparisonKind(PredDef->getOpcode(), 0, 0, 0);
+ Comparison::Kind Cmp =
+ getComparisonKind(PredDef->getOpcode(), nullptr, nullptr, 0);
if (!Cmp || Comparison::isUnsigned(Cmp))
return false;
@@ -1807,18 +1819,17 @@ bool HexagonHardwareLoops::fixupInductionVariable(MachineLoop *L) {
return false;
}
-/// \brief Create a preheader for a given loop.
+/// createPreheaderForLoop - Create a preheader for a given loop.
MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
MachineLoop *L) {
- if (MachineBasicBlock *TmpPH = L->getLoopPreheader())
+ if (MachineBasicBlock *TmpPH = MLI->findLoopPreheader(L, SpecPreheader))
return TmpPH;
-
if (!HWCreatePreheader)
return nullptr;
MachineBasicBlock *Header = L->getHeader();
MachineBasicBlock *Latch = L->getLoopLatch();
- MachineBasicBlock *ExitingBlock = getExitingBlock(L);
+ MachineBasicBlock *ExitingBlock = L->findLoopControlBlock();
MachineFunction *MF = Header->getParent();
DebugLoc DL;
@@ -1898,7 +1909,6 @@ MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
PN->addOperand(MachineOperand::CreateReg(NewPR, false));
PN->addOperand(MachineOperand::CreateMBB(NewPH));
}
-
} else {
assert(Header->pred_size() == 2);
@@ -1934,7 +1944,7 @@ MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
(void)NotAnalyzed; // suppress compiler warning
assert (!NotAnalyzed && "Should be analyzable!");
if (TB != Header && (Tmp2.empty() || FB != Header))
- TII->InsertBranch(*PB, NewPH, nullptr, EmptyCond, DL);
+ TII->insertBranch(*PB, NewPH, nullptr, EmptyCond, DL);
PB->ReplaceUsesOfBlockWith(Header, NewPH);
}
}
@@ -1946,10 +1956,10 @@ MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
(void)LatchNotAnalyzed; // suppress compiler warning
assert (!LatchNotAnalyzed && "Should be analyzable!");
if (!TB && !FB)
- TII->InsertBranch(*Latch, Header, nullptr, EmptyCond, DL);
+ TII->insertBranch(*Latch, Header, nullptr, EmptyCond, DL);
// Finally, the branch from the preheader to the header.
- TII->InsertBranch(*NewPH, Header, nullptr, EmptyCond, DL);
+ TII->insertBranch(*NewPH, Header, nullptr, EmptyCond, DL);
NewPH->addSuccessor(Header);
MachineLoop *ParentLoop = L->getParentLoop();
@@ -1958,9 +1968,12 @@ MachineBasicBlock *HexagonHardwareLoops::createPreheaderForLoop(
// Update the dominator information with the new preheader.
if (MDT) {
- MachineDomTreeNode *HDom = MDT->getNode(Header);
- MDT->addNewBlock(NewPH, HDom->getIDom()->getBlock());
- MDT->changeImmediateDominator(Header, NewPH);
+ if (MachineDomTreeNode *HN = MDT->getNode(Header)) {
+ if (MachineDomTreeNode *DHN = HN->getIDom()) {
+ MDT->addNewBlock(NewPH, DHN->getBlock());
+ MDT->changeImmediateDominator(Header, NewPH);
+ }
+ }
}
return NewPH;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.cpp
new file mode 100644
index 0000000..036b186
--- /dev/null
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.cpp
@@ -0,0 +1,140 @@
+//===-- HexagonHazardRecognizer.cpp - Hexagon Post RA Hazard Recognizer ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the hazard recognizer for scheduling on Hexagon.
+// Use a DFA based hazard recognizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HexagonHazardRecognizer.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/ScheduleDAG.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "post-RA-sched"
+
+void HexagonHazardRecognizer::Reset() {
+ DEBUG(dbgs() << "Reset hazard recognizer\n");
+ Resources->clearResources();
+ PacketNum = 0;
+ UsesDotCur = nullptr;
+ DotCurPNum = -1;
+ RegDefs.clear();
+}
+
+ScheduleHazardRecognizer::HazardType
+HexagonHazardRecognizer::getHazardType(SUnit *SU, int stalls) {
+ MachineInstr *MI = SU->getInstr();
+ if (!MI || TII->isZeroCost(MI->getOpcode()))
+ return NoHazard;
+
+ if (!Resources->canReserveResources(*MI)) {
+ DEBUG(dbgs() << "*** Hazard in cycle " << PacketNum << ", " << *MI);
+ HazardType RetVal = Hazard;
+ if (TII->mayBeNewStore(*MI)) {
+ // Make sure the register to be stored is defined by an instruction in the
+ // packet.
+ MachineOperand &MO = MI->getOperand(MI->getNumOperands() - 1);
+ if (!MO.isReg() || RegDefs.count(MO.getReg()) == 0)
+ return Hazard;
+ // The .new store version uses different resources so check if it
+ // causes a hazard.
+ MachineFunction *MF = MI->getParent()->getParent();
+ MachineInstr *NewMI =
+ MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),
+ MI->getDebugLoc());
+ if (Resources->canReserveResources(*NewMI))
+ RetVal = NoHazard;
+ DEBUG(dbgs() << "*** Try .new version? " << (RetVal == NoHazard) << "\n");
+ MF->DeleteMachineInstr(NewMI);
+ }
+ return RetVal;
+ }
+
+ if (SU == UsesDotCur && DotCurPNum != (int)PacketNum) {
+ DEBUG(dbgs() << "*** .cur Hazard in cycle " << PacketNum << ", " << *MI);
+ return Hazard;
+ }
+
+ return NoHazard;
+}
+
+void HexagonHazardRecognizer::AdvanceCycle() {
+ DEBUG(dbgs() << "Advance cycle, clear state\n");
+ Resources->clearResources();
+ if (DotCurPNum != -1 && DotCurPNum != (int)PacketNum) {
+ UsesDotCur = nullptr;
+ DotCurPNum = -1;
+ }
+ PacketNum++;
+ RegDefs.clear();
+}
+
+/// If a packet contains a dot cur instruction, then we may prefer the
+/// instruction that can use the dot cur result. Or, if the use
+/// isn't scheduled in the same packet, then prefer other instructions
+/// in the subsequent packet.
+bool HexagonHazardRecognizer::ShouldPreferAnother(SUnit *SU) {
+ return UsesDotCur && ((SU == UsesDotCur) ^ (DotCurPNum == (int)PacketNum));
+}
+
+void HexagonHazardRecognizer::EmitInstruction(SUnit *SU) {
+ MachineInstr *MI = SU->getInstr();
+ if (!MI)
+ return;
+
+ // Keep the set of definitions for each packet, which is used to determine
+ // if a .new can be used.
+ for (const MachineOperand &MO : MI->operands())
+ if (MO.isReg() && MO.isDef() && !MO.isImplicit())
+ RegDefs.insert(MO.getReg());
+
+ if (TII->isZeroCost(MI->getOpcode()))
+ return;
+
+ if (!Resources->canReserveResources(*MI)) {
+ // It must be a .new store since other instructions must be able to be
+ // reserved at this point.
+ assert(TII->mayBeNewStore(*MI) && "Expecting .new store");
+ MachineFunction *MF = MI->getParent()->getParent();
+ MachineInstr *NewMI =
+ MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),
+ MI->getDebugLoc());
+ assert(Resources->canReserveResources(*NewMI));
+ Resources->reserveResources(*NewMI);
+ MF->DeleteMachineInstr(NewMI);
+ }
+ else
+ Resources->reserveResources(*MI);
+ DEBUG(dbgs() << " Add instruction " << *MI);
+
+ // When scheduling a dot cur instruction, check if there is an instruction
+ // that can use the dot cur in the same packet. If so, we'll attempt to
+ // schedule it before other instructions. We only do this if the use has
+ // the same height as the dot cur. Otherwise, we may miss scheduling an
+ // instruction with a greater height, which is more important.
+ if (TII->mayBeCurLoad(*MI))
+ for (auto &S : SU->Succs)
+ if (S.isAssignedRegDep() && S.getLatency() == 0 &&
+ SU->getHeight() == S.getSUnit()->getHeight()) {
+ UsesDotCur = S.getSUnit();
+ DotCurPNum = PacketNum;
+ break;
+ }
+ if (SU == UsesDotCur) {
+ UsesDotCur = nullptr;
+ DotCurPNum = -1;
+ }
+}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.h b/contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.h
new file mode 100644
index 0000000..70efcb7
--- /dev/null
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.h
@@ -0,0 +1,78 @@
+//===--- HexagonHazardRecognizer.h - Hexagon Post RA Hazard Recognizer ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file defines the hazard recognizer for scheduling on Hexagon.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONPROFITRECOGNIZER_H
+#define LLVM_LIB_TARGET_HEXAGON_HEXAGONPROFITRECOGNIZER_H
+
+#include "HexagonInstrInfo.h"
+#include "HexagonSubtarget.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/CodeGen/DFAPacketizer.h"
+#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
+
+namespace llvm {
+
+class HexagonHazardRecognizer : public ScheduleHazardRecognizer {
+ DFAPacketizer *Resources;
+ const HexagonInstrInfo *TII;
+ unsigned PacketNum;
+ // If the packet contains a potential dot cur instruction. This is
+ // used for the scheduling priority function.
+ SUnit *UsesDotCur;
+ // The packet number when a dor cur is emitted. If its use is not generated
+ // in the same packet, then try to wait another cycle before emitting.
+ int DotCurPNum;
+ // The set of registers defined by instructions in the current packet.
+ SmallSet<unsigned, 8> RegDefs;
+
+public:
+ HexagonHazardRecognizer(const InstrItineraryData *II,
+ const HexagonInstrInfo *HII,
+ const HexagonSubtarget &ST)
+ : Resources(ST.createDFAPacketizer(II)), TII(HII), PacketNum(0),
+ UsesDotCur(nullptr), DotCurPNum(-1) { }
+
+ ~HexagonHazardRecognizer() override {
+ if (Resources)
+ delete Resources;
+ }
+
+ /// This callback is invoked when a new block of instructions is about to be
+ /// scheduled. The hazard state is set to an initialized state.
+ void Reset() override;
+
+ /// Return the hazard type of emitting this node. There are three
+ /// possible results. Either:
+ /// * NoHazard: it is legal to issue this instruction on this cycle.
+ /// * Hazard: issuing this instruction would stall the machine. If some
+ /// other instruction is available, issue it first.
+ HazardType getHazardType(SUnit *SU, int stalls) override;
+
+ /// This callback is invoked when an instruction is emitted to be scheduled,
+ /// to advance the hazard state.
+ void EmitInstruction(SUnit *) override;
+
+ /// This callback may be invoked if getHazardType returns NoHazard. If, even
+ /// though there is no hazard, it would be better to schedule another
+ /// available instruction, this callback should return true.
+ bool ShouldPreferAnother(SUnit *) override;
+
+ /// This callback is invoked whenever the next top-down instruction to be
+ /// scheduled cannot issue in the current cycle, either because of latency
+ /// or resource conflicts. This should increment the internal state of the
+ /// hazard recognizer so that previously "Hazard" instructions will now not
+ /// be hazards.
+ void AdvanceCycle() override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONPROFITRECOGNIZER_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
index 22247aa..f6012d2 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
@@ -26,11 +26,22 @@ using namespace llvm;
#define DEBUG_TYPE "hexagon-isel"
static
-cl::opt<unsigned>
-MaxNumOfUsesForConstExtenders("ga-max-num-uses-for-constant-extenders",
- cl::Hidden, cl::init(2),
- cl::desc("Maximum number of uses of a global address such that we still us a"
- "constant extended instruction"));
+cl::opt<bool>
+EnableAddressRebalancing("isel-rebalance-addr", cl::Hidden, cl::init(true),
+ cl::desc("Rebalance address calculation trees to improve "
+ "instruction selection"));
+
+// Rebalance only if this allows e.g. combining a GA with an offset or
+// factoring out a shift.
+static
+cl::opt<bool>
+RebalanceOnlyForOptimizations("rebalance-only-opt", cl::Hidden, cl::init(false),
+ cl::desc("Rebalance address tree only if this allows optimizations"));
+
+static
+cl::opt<bool>
+RebalanceOnlyImbalancedTrees("rebalance-only-imbal", cl::Hidden,
+ cl::init(false), cl::desc("Rebalance address tree only if it is imbalanced"));
//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
@@ -42,14 +53,13 @@ MaxNumOfUsesForConstExtenders("ga-max-num-uses-for-constant-extenders",
///
namespace {
class HexagonDAGToDAGISel : public SelectionDAGISel {
- const HexagonTargetMachine &HTM;
const HexagonSubtarget *HST;
const HexagonInstrInfo *HII;
const HexagonRegisterInfo *HRI;
public:
explicit HexagonDAGToDAGISel(HexagonTargetMachine &tm,
CodeGenOpt::Level OptLevel)
- : SelectionDAGISel(tm, OptLevel), HTM(tm), HST(nullptr), HII(nullptr),
+ : SelectionDAGISel(tm, OptLevel), HST(nullptr), HII(nullptr),
HRI(nullptr) {}
bool runOnMachineFunction(MachineFunction &MF) override {
@@ -61,8 +71,8 @@ public:
return true;
}
- virtual void PreprocessISelDAG() override;
- virtual void EmitFunctionEntryCode() override;
+ void PreprocessISelDAG() override;
+ void EmitFunctionEntryCode() override;
void Select(SDNode *N) override;
@@ -72,7 +82,7 @@ public:
bool SelectGlobalAddress(SDValue &N, SDValue &R, bool UseGP);
bool SelectAddrFI(SDValue &N, SDValue &R);
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon DAG->DAG Pattern Instruction Selection";
}
@@ -92,7 +102,6 @@ public:
std::vector<SDValue> &OutOps) override;
bool tryLoadOfLoadIntrinsic(LoadSDNode *N);
void SelectLoad(SDNode *N);
- void SelectBaseOffsetLoad(LoadSDNode *LD, SDLoc dl);
void SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl);
void SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl);
void SelectStore(SDNode *N);
@@ -103,82 +112,27 @@ public:
void SelectIntrinsicWOChain(SDNode *N);
void SelectConstant(SDNode *N);
void SelectConstantFP(SDNode *N);
- void SelectAdd(SDNode *N);
void SelectBitcast(SDNode *N);
- void SelectBitOp(SDNode *N);
-
- // XformMskToBitPosU5Imm - Returns the bit position which
- // the single bit 32 bit mask represents.
- // Used in Clr and Set bit immediate memops.
- SDValue XformMskToBitPosU5Imm(uint32_t Imm, const SDLoc &DL) {
- int32_t bitPos;
- bitPos = Log2_32(Imm);
- assert(bitPos >= 0 && bitPos < 32 &&
- "Constant out of range for 32 BitPos Memops");
- return CurDAG->getTargetConstant(bitPos, DL, MVT::i32);
- }
-
- // XformMskToBitPosU4Imm - Returns the bit position which the single-bit
- // 16 bit mask represents. Used in Clr and Set bit immediate memops.
- SDValue XformMskToBitPosU4Imm(uint16_t Imm, const SDLoc &DL) {
- return XformMskToBitPosU5Imm(Imm, DL);
- }
-
- // XformMskToBitPosU3Imm - Returns the bit position which the single-bit
- // 8 bit mask represents. Used in Clr and Set bit immediate memops.
- SDValue XformMskToBitPosU3Imm(uint8_t Imm, const SDLoc &DL) {
- return XformMskToBitPosU5Imm(Imm, DL);
- }
-
- // Return true if there is exactly one bit set in V, i.e., if V is one of the
- // following integers: 2^0, 2^1, ..., 2^31.
- bool ImmIsSingleBit(uint32_t v) const {
- return isPowerOf2_32(v);
- }
-
- // XformM5ToU5Imm - Return a target constant with the specified value, of
- // type i32 where the negative literal is transformed into a positive literal
- // for use in -= memops.
- inline SDValue XformM5ToU5Imm(signed Imm, const SDLoc &DL) {
- assert((Imm >= -31 && Imm <= -1) && "Constant out of range for Memops");
- return CurDAG->getTargetConstant(-Imm, DL, MVT::i32);
- }
-
- // XformU7ToU7M1Imm - Return a target constant decremented by 1, in range
- // [1..128], used in cmpb.gtu instructions.
- inline SDValue XformU7ToU7M1Imm(signed Imm, const SDLoc &DL) {
- assert((Imm >= 1 && Imm <= 128) && "Constant out of range for cmpb op");
- return CurDAG->getTargetConstant(Imm - 1, DL, MVT::i8);
- }
-
- // XformS8ToS8M1Imm - Return a target constant decremented by 1.
- inline SDValue XformSToSM1Imm(signed Imm, const SDLoc &DL) {
- return CurDAG->getTargetConstant(Imm - 1, DL, MVT::i32);
- }
-
- // XformU8ToU8M1Imm - Return a target constant decremented by 1.
- inline SDValue XformUToUM1Imm(unsigned Imm, const SDLoc &DL) {
- assert((Imm >= 1) && "Cannot decrement unsigned int less than 1");
- return CurDAG->getTargetConstant(Imm - 1, DL, MVT::i32);
- }
-
- // XformSToSM2Imm - Return a target constant decremented by 2.
- inline SDValue XformSToSM2Imm(unsigned Imm, const SDLoc &DL) {
- return CurDAG->getTargetConstant(Imm - 2, DL, MVT::i32);
- }
-
- // XformSToSM3Imm - Return a target constant decremented by 3.
- inline SDValue XformSToSM3Imm(unsigned Imm, const SDLoc &DL) {
- return CurDAG->getTargetConstant(Imm - 3, DL, MVT::i32);
- }
// Include the pieces autogenerated from the target description.
#include "HexagonGenDAGISel.inc"
private:
bool isValueExtension(const SDValue &Val, unsigned FromBits, SDValue &Src);
- bool orIsAdd(const SDNode *N) const;
+ bool isOrEquivalentToAdd(const SDNode *N) const;
bool isAlignedMemNode(const MemSDNode *N) const;
+ bool isPositiveHalfWord(const SDNode *N) const;
+
+ SmallDenseMap<SDNode *,int> RootWeights;
+ SmallDenseMap<SDNode *,int> RootHeights;
+ SmallDenseMap<const Value *,int> GAUsesInFunction;
+ int getWeight(SDNode *N);
+ int getHeight(SDNode *N);
+ SDValue getMultiplierForSHL(SDNode *N);
+ SDValue factorOutPowerOf2(SDValue V, unsigned Power);
+ unsigned getUsesInFunction(const Value *V);
+ SDValue balanceSubTree(SDNode *N, bool Factorize = false);
+ void rebalanceAddressTrees();
}; // end HexagonDAGToDAGISel
} // end anonymous namespace
@@ -588,7 +542,7 @@ void HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl) {
if (ST->isTruncatingStore() && ValueVT.getSizeInBits() == 64) {
assert(StoredVT.getSizeInBits() < 64 && "Not a truncating store");
- Value = CurDAG->getTargetExtractSubreg(Hexagon::subreg_loreg,
+ Value = CurDAG->getTargetExtractSubreg(Hexagon::isub_lo,
dl, MVT::i32, Value);
}
@@ -640,7 +594,6 @@ void HexagonDAGToDAGISel::SelectStore(SDNode *N) {
void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
SDLoc dl(N);
- //
// %conv.i = sext i32 %tmp1 to i64
// %conv2.i = sext i32 %add to i64
// %mul.i = mul nsw i64 %conv2.i, %conv.i
@@ -665,7 +618,6 @@ void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
SelectCode(N);
return;
}
-
OP0 = Sext0;
} else if (MulOp0.getOpcode() == ISD::LOAD) {
LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode());
@@ -675,7 +627,6 @@ void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
SelectCode(N);
return;
}
-
SDValue Chain = LD->getChain();
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
OP0 = SDValue(CurDAG->getMachineNode(Hexagon::L2_loadri_io, dl, MVT::i32,
@@ -694,7 +645,6 @@ void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
SelectCode(N);
return;
}
-
OP1 = Sext1;
} else if (MulOp1.getOpcode() == ISD::LOAD) {
LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode());
@@ -704,7 +654,6 @@ void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
SelectCode(N);
return;
}
-
SDValue Chain = LD->getChain();
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
OP1 = SDValue(CurDAG->getMachineNode(Hexagon::L2_loadri_io, dl, MVT::i32,
@@ -717,8 +666,8 @@ void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
}
// Generate a mpy instruction.
- SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_dpmpyss_s0, dl, MVT::i64,
- OP0, OP1);
+ SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_dpmpyss_s0, dl,
+ MVT::i64, OP0, OP1);
ReplaceNode(N, Result);
return;
}
@@ -728,68 +677,56 @@ void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
void HexagonDAGToDAGISel::SelectSHL(SDNode *N) {
SDLoc dl(N);
- if (N->getValueType(0) == MVT::i32) {
- SDValue Shl_0 = N->getOperand(0);
- SDValue Shl_1 = N->getOperand(1);
- // RHS is const.
- if (Shl_1.getOpcode() == ISD::Constant) {
- if (Shl_0.getOpcode() == ISD::MUL) {
- SDValue Mul_0 = Shl_0.getOperand(0); // Val
- SDValue Mul_1 = Shl_0.getOperand(1); // Const
- // RHS of mul is const.
- if (Mul_1.getOpcode() == ISD::Constant) {
- int32_t ShlConst =
- cast<ConstantSDNode>(Shl_1.getNode())->getSExtValue();
- int32_t MulConst =
- cast<ConstantSDNode>(Mul_1.getNode())->getSExtValue();
- int32_t ValConst = MulConst << ShlConst;
- SDValue Val = CurDAG->getTargetConstant(ValConst, dl,
- MVT::i32);
- if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val.getNode()))
- if (isInt<9>(CN->getSExtValue())) {
- SDNode* Result =
- CurDAG->getMachineNode(Hexagon::M2_mpysmi, dl,
- MVT::i32, Mul_0, Val);
- ReplaceNode(N, Result);
- return;
- }
+ SDValue Shl_0 = N->getOperand(0);
+ SDValue Shl_1 = N->getOperand(1);
+
+ auto Default = [this,N] () -> void { SelectCode(N); };
+
+ if (N->getValueType(0) != MVT::i32 || Shl_1.getOpcode() != ISD::Constant)
+ return Default();
+
+ // RHS is const.
+ int32_t ShlConst = cast<ConstantSDNode>(Shl_1)->getSExtValue();
+
+ if (Shl_0.getOpcode() == ISD::MUL) {
+ SDValue Mul_0 = Shl_0.getOperand(0); // Val
+ SDValue Mul_1 = Shl_0.getOperand(1); // Const
+ // RHS of mul is const.
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Mul_1)) {
+ int32_t ValConst = C->getSExtValue() << ShlConst;
+ if (isInt<9>(ValConst)) {
+ SDValue Val = CurDAG->getTargetConstant(ValConst, dl, MVT::i32);
+ SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_mpysmi, dl,
+ MVT::i32, Mul_0, Val);
+ ReplaceNode(N, Result);
+ return;
+ }
+ }
+ return Default();
+ }
- }
- } else if (Shl_0.getOpcode() == ISD::SUB) {
- SDValue Sub_0 = Shl_0.getOperand(0); // Const 0
- SDValue Sub_1 = Shl_0.getOperand(1); // Val
- if (Sub_0.getOpcode() == ISD::Constant) {
- int32_t SubConst =
- cast<ConstantSDNode>(Sub_0.getNode())->getSExtValue();
- if (SubConst == 0) {
- if (Sub_1.getOpcode() == ISD::SHL) {
- SDValue Shl2_0 = Sub_1.getOperand(0); // Val
- SDValue Shl2_1 = Sub_1.getOperand(1); // Const
- if (Shl2_1.getOpcode() == ISD::Constant) {
- int32_t ShlConst =
- cast<ConstantSDNode>(Shl_1.getNode())->getSExtValue();
- int32_t Shl2Const =
- cast<ConstantSDNode>(Shl2_1.getNode())->getSExtValue();
- int32_t ValConst = 1 << (ShlConst+Shl2Const);
- SDValue Val = CurDAG->getTargetConstant(-ValConst, dl,
- MVT::i32);
- if (ConstantSDNode *CN =
- dyn_cast<ConstantSDNode>(Val.getNode()))
- if (isInt<9>(CN->getSExtValue())) {
- SDNode* Result =
- CurDAG->getMachineNode(Hexagon::M2_mpysmi, dl, MVT::i32,
- Shl2_0, Val);
- ReplaceNode(N, Result);
- return;
- }
- }
- }
- }
+ if (Shl_0.getOpcode() == ISD::SUB) {
+ SDValue Sub_0 = Shl_0.getOperand(0); // Const 0
+ SDValue Sub_1 = Shl_0.getOperand(1); // Val
+ if (ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(Sub_0)) {
+ if (C1->getSExtValue() != 0 || Sub_1.getOpcode() != ISD::SHL)
+ return Default();
+ SDValue Shl2_0 = Sub_1.getOperand(0); // Val
+ SDValue Shl2_1 = Sub_1.getOperand(1); // Const
+ if (ConstantSDNode *C2 = dyn_cast<ConstantSDNode>(Shl2_1)) {
+ int32_t ValConst = 1 << (ShlConst + C2->getSExtValue());
+ if (isInt<9>(-ValConst)) {
+ SDValue Val = CurDAG->getTargetConstant(-ValConst, dl, MVT::i32);
+ SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_mpysmi, dl,
+ MVT::i32, Shl2_0, Val);
+ ReplaceNode(N, Result);
+ return;
}
}
}
}
- SelectCode(N);
+
+ return Default();
}
@@ -815,20 +752,19 @@ void HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) {
SDNode *Mask = CurDAG->getMachineNode(Hexagon::C2_mask, dl, MVT::i64, Op0);
unsigned NE = OpVT.getVectorNumElements();
EVT ExVT = N->getValueType(0);
- unsigned ES = ExVT.getVectorElementType().getSizeInBits();
+ unsigned ES = ExVT.getScalarSizeInBits();
uint64_t MV = 0, Bit = 1;
for (unsigned i = 0; i < NE; ++i) {
MV |= Bit;
Bit <<= ES;
}
SDValue Ones = CurDAG->getTargetConstant(MV, dl, MVT::i64);
- SDNode *OnesReg = CurDAG->getMachineNode(Hexagon::CONST64_Int_Real, dl,
+ SDNode *OnesReg = CurDAG->getMachineNode(Hexagon::CONST64, dl,
MVT::i64, Ones);
if (ExVT.getSizeInBits() == 32) {
SDNode *And = CurDAG->getMachineNode(Hexagon::A2_andp, dl, MVT::i64,
SDValue(Mask,0), SDValue(OnesReg,0));
- SDValue SubR = CurDAG->getTargetConstant(Hexagon::subreg_loreg, dl,
- MVT::i32);
+ SDValue SubR = CurDAG->getTargetConstant(Hexagon::isub_lo, dl, MVT::i32);
ReplaceNode(N, CurDAG->getMachineNode(Hexagon::EXTRACT_SUBREG, dl, ExVT,
SDValue(And, 0), SubR));
return;
@@ -839,21 +775,18 @@ void HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) {
return;
}
- SDNode *IsIntrinsic = N->getOperand(0).getNode();
- if ((IsIntrinsic->getOpcode() == ISD::INTRINSIC_WO_CHAIN)) {
- unsigned ID =
- cast<ConstantSDNode>(IsIntrinsic->getOperand(0))->getZExtValue();
+ SDNode *Int = N->getOperand(0).getNode();
+ if ((Int->getOpcode() == ISD::INTRINSIC_WO_CHAIN)) {
+ unsigned ID = cast<ConstantSDNode>(Int->getOperand(0))->getZExtValue();
if (doesIntrinsicReturnPredicate(ID)) {
// Now we need to differentiate target data types.
if (N->getValueType(0) == MVT::i64) {
// Convert the zero_extend to Rs = Pd followed by A2_combinew(0,Rs).
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
SDNode *Result_1 = CurDAG->getMachineNode(Hexagon::C2_tfrpr, dl,
- MVT::i32,
- SDValue(IsIntrinsic, 0));
+ MVT::i32, SDValue(Int, 0));
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl,
- MVT::i32,
- TargetConst0);
+ MVT::i32, TargetConst0);
SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::A2_combinew, dl,
MVT::i64, MVT::Other,
SDValue(Result_2, 0),
@@ -864,8 +797,7 @@ void HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) {
if (N->getValueType(0) == MVT::i32) {
// Convert the zero_extend to Rs = Pd
SDNode* RsPd = CurDAG->getMachineNode(Hexagon::C2_tfrpr, dl,
- MVT::i32,
- SDValue(IsIntrinsic, 0));
+ MVT::i32, SDValue(Int, 0));
ReplaceNode(N, RsPd);
return;
}
@@ -921,19 +853,15 @@ void HexagonDAGToDAGISel::SelectIntrinsicWOChain(SDNode *N) {
void HexagonDAGToDAGISel::SelectConstantFP(SDNode *N) {
SDLoc dl(N);
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N);
- const APFloat &APF = CN->getValueAPF();
+ APInt A = CN->getValueAPF().bitcastToAPInt();
if (N->getValueType(0) == MVT::f32) {
- ReplaceNode(
- N, CurDAG->getMachineNode(Hexagon::TFRI_f, dl, MVT::f32,
- CurDAG->getTargetConstantFP(
- APF.convertToFloat(), dl, MVT::f32)));
+ SDValue V = CurDAG->getTargetConstant(A.getZExtValue(), dl, MVT::i32);
+ ReplaceNode(N, CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl, MVT::f32, V));
return;
}
- else if (N->getValueType(0) == MVT::f64) {
- ReplaceNode(
- N, CurDAG->getMachineNode(Hexagon::CONST64_Float_Real, dl, MVT::f64,
- CurDAG->getTargetConstantFP(
- APF.convertToDouble(), dl, MVT::f64)));
+ if (N->getValueType(0) == MVT::f64) {
+ SDValue V = CurDAG->getTargetConstant(A.getZExtValue(), dl, MVT::i64);
+ ReplaceNode(N, CurDAG->getMachineNode(Hexagon::CONST64, dl, MVT::f64, V));
return;
}
@@ -941,226 +869,46 @@ void HexagonDAGToDAGISel::SelectConstantFP(SDNode *N) {
}
//
-// Map predicate true (encoded as -1 in LLVM) to a XOR.
+// Map boolean values.
//
void HexagonDAGToDAGISel::SelectConstant(SDNode *N) {
- SDLoc dl(N);
if (N->getValueType(0) == MVT::i1) {
- SDNode* Result = 0;
- int32_t Val = cast<ConstantSDNode>(N)->getSExtValue();
- if (Val == -1) {
- Result = CurDAG->getMachineNode(Hexagon::TFR_PdTrue, dl, MVT::i1);
- } else if (Val == 0) {
- Result = CurDAG->getMachineNode(Hexagon::TFR_PdFalse, dl, MVT::i1);
- }
- if (Result) {
- ReplaceNode(N, Result);
- return;
- }
- }
-
- SelectCode(N);
-}
-
-
-//
-// Map add followed by a asr -> asr +=.
-//
-void HexagonDAGToDAGISel::SelectAdd(SDNode *N) {
- SDLoc dl(N);
- if (N->getValueType(0) != MVT::i32) {
- SelectCode(N);
- return;
- }
- // Identify nodes of the form: add(asr(...)).
- SDNode* Src1 = N->getOperand(0).getNode();
- if (Src1->getOpcode() != ISD::SRA || !Src1->hasOneUse()
- || Src1->getValueType(0) != MVT::i32) {
- SelectCode(N);
- return;
- }
-
- // Build Rd = Rd' + asr(Rs, Rt). The machine constraints will ensure that
- // Rd and Rd' are assigned to the same register
- SDNode* Result = CurDAG->getMachineNode(Hexagon::S2_asr_r_r_acc, dl, MVT::i32,
- N->getOperand(1),
- Src1->getOperand(0),
- Src1->getOperand(1));
- ReplaceNode(N, Result);
-}
-
-//
-// Map the following, where possible.
-// AND/FABS -> clrbit
-// OR -> setbit
-// XOR/FNEG ->toggle_bit.
-//
-void HexagonDAGToDAGISel::SelectBitOp(SDNode *N) {
- SDLoc dl(N);
- EVT ValueVT = N->getValueType(0);
-
- // We handle only 32 and 64-bit bit ops.
- if (!(ValueVT == MVT::i32 || ValueVT == MVT::i64 ||
- ValueVT == MVT::f32 || ValueVT == MVT::f64)) {
- SelectCode(N);
+ assert(!(cast<ConstantSDNode>(N)->getZExtValue() >> 1));
+ unsigned Opc = (cast<ConstantSDNode>(N)->getSExtValue() != 0)
+ ? Hexagon::PS_true
+ : Hexagon::PS_false;
+ ReplaceNode(N, CurDAG->getMachineNode(Opc, SDLoc(N), MVT::i1));
return;
}
- // We handly only fabs and fneg for V5.
- unsigned Opc = N->getOpcode();
- if ((Opc == ISD::FABS || Opc == ISD::FNEG) && !HST->hasV5TOps()) {
- SelectCode(N);
- return;
- }
-
- int64_t Val = 0;
- if (Opc != ISD::FABS && Opc != ISD::FNEG) {
- if (N->getOperand(1).getOpcode() == ISD::Constant)
- Val = cast<ConstantSDNode>((N)->getOperand(1))->getSExtValue();
- else {
- SelectCode(N);
- return;
- }
- }
-
- if (Opc == ISD::AND) {
- // Check if this is a bit-clearing AND, if not select code the usual way.
- if ((ValueVT == MVT::i32 && isPowerOf2_32(~Val)) ||
- (ValueVT == MVT::i64 && isPowerOf2_64(~Val)))
- Val = ~Val;
- else {
- SelectCode(N);
- return;
- }
- }
-
- // If OR or AND is being fed by shl, srl and, sra don't do this change,
- // because Hexagon provide |= &= on shl, srl, and sra.
- // Traverse the DAG to see if there is shl, srl and sra.
- if (Opc == ISD::OR || Opc == ISD::AND) {
- switch (N->getOperand(0)->getOpcode()) {
- default:
- break;
- case ISD::SRA:
- case ISD::SRL:
- case ISD::SHL:
- SelectCode(N);
- return;
- }
- }
-
- // Make sure it's power of 2.
- unsigned BitPos = 0;
- if (Opc != ISD::FABS && Opc != ISD::FNEG) {
- if ((ValueVT == MVT::i32 && !isPowerOf2_32(Val)) ||
- (ValueVT == MVT::i64 && !isPowerOf2_64(Val))) {
- SelectCode(N);
- return;
- }
-
- // Get the bit position.
- BitPos = countTrailingZeros(uint64_t(Val));
- } else {
- // For fabs and fneg, it's always the 31st bit.
- BitPos = 31;
- }
-
- unsigned BitOpc = 0;
- // Set the right opcode for bitwise operations.
- switch (Opc) {
- default:
- llvm_unreachable("Only bit-wise/abs/neg operations are allowed.");
- case ISD::AND:
- case ISD::FABS:
- BitOpc = Hexagon::S2_clrbit_i;
- break;
- case ISD::OR:
- BitOpc = Hexagon::S2_setbit_i;
- break;
- case ISD::XOR:
- case ISD::FNEG:
- BitOpc = Hexagon::S2_togglebit_i;
- break;
- }
-
- SDNode *Result;
- // Get the right SDVal for the opcode.
- SDValue SDVal = CurDAG->getTargetConstant(BitPos, dl, MVT::i32);
-
- if (ValueVT == MVT::i32 || ValueVT == MVT::f32) {
- Result = CurDAG->getMachineNode(BitOpc, dl, ValueVT,
- N->getOperand(0), SDVal);
- } else {
- // 64-bit gymnastic to use REG_SEQUENCE. But it's worth it.
- EVT SubValueVT;
- if (ValueVT == MVT::i64)
- SubValueVT = MVT::i32;
- else
- SubValueVT = MVT::f32;
-
- SDNode *Reg = N->getOperand(0).getNode();
- SDValue RegClass = CurDAG->getTargetConstant(Hexagon::DoubleRegsRegClassID,
- dl, MVT::i64);
-
- SDValue SubregHiIdx = CurDAG->getTargetConstant(Hexagon::subreg_hireg, dl,
- MVT::i32);
- SDValue SubregLoIdx = CurDAG->getTargetConstant(Hexagon::subreg_loreg, dl,
- MVT::i32);
-
- SDValue SubregHI = CurDAG->getTargetExtractSubreg(Hexagon::subreg_hireg, dl,
- MVT::i32, SDValue(Reg, 0));
-
- SDValue SubregLO = CurDAG->getTargetExtractSubreg(Hexagon::subreg_loreg, dl,
- MVT::i32, SDValue(Reg, 0));
-
- // Clear/set/toggle hi or lo registers depending on the bit position.
- if (SubValueVT != MVT::f32 && BitPos < 32) {
- SDNode *Result0 = CurDAG->getMachineNode(BitOpc, dl, SubValueVT,
- SubregLO, SDVal);
- const SDValue Ops[] = { RegClass, SubregHI, SubregHiIdx,
- SDValue(Result0, 0), SubregLoIdx };
- Result = CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
- dl, ValueVT, Ops);
- } else {
- if (Opc != ISD::FABS && Opc != ISD::FNEG)
- SDVal = CurDAG->getTargetConstant(BitPos-32, dl, MVT::i32);
- SDNode *Result0 = CurDAG->getMachineNode(BitOpc, dl, SubValueVT,
- SubregHI, SDVal);
- const SDValue Ops[] = { RegClass, SDValue(Result0, 0), SubregHiIdx,
- SubregLO, SubregLoIdx };
- Result = CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
- dl, ValueVT, Ops);
- }
- }
-
- ReplaceNode(N, Result);
+ SelectCode(N);
}
void HexagonDAGToDAGISel::SelectFrameIndex(SDNode *N) {
- MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
const HexagonFrameLowering *HFI = HST->getFrameLowering();
int FX = cast<FrameIndexSDNode>(N)->getIndex();
unsigned StkA = HFI->getStackAlignment();
- unsigned MaxA = MFI->getMaxAlignment();
+ unsigned MaxA = MFI.getMaxAlignment();
SDValue FI = CurDAG->getTargetFrameIndex(FX, MVT::i32);
SDLoc DL(N);
SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
- SDNode *R = 0;
+ SDNode *R = nullptr;
- // Use TFR_FI when:
+ // Use PS_fi when:
// - the object is fixed, or
// - there are no objects with higher-than-default alignment, or
// - there are no dynamically allocated objects.
- // Otherwise, use TFR_FIA.
- if (FX < 0 || MaxA <= StkA || !MFI->hasVarSizedObjects()) {
- R = CurDAG->getMachineNode(Hexagon::TFR_FI, DL, MVT::i32, FI, Zero);
+ // Otherwise, use PS_fia.
+ if (FX < 0 || MaxA <= StkA || !MFI.hasVarSizedObjects()) {
+ R = CurDAG->getMachineNode(Hexagon::PS_fi, DL, MVT::i32, FI, Zero);
} else {
auto &HMFI = *MF->getInfo<HexagonMachineFunctionInfo>();
unsigned AR = HMFI.getStackAlignBaseVReg();
SDValue CH = CurDAG->getEntryNode();
SDValue Ops[] = { CurDAG->getCopyFromReg(CH, DL, AR, MVT::i32), FI, Zero };
- R = CurDAG->getMachineNode(Hexagon::TFR_FIA, DL, MVT::i32, Ops);
+ R = CurDAG->getMachineNode(Hexagon::PS_fia, DL, MVT::i32, Ops);
}
ReplaceNode(N, R);
@@ -1202,10 +950,6 @@ void HexagonDAGToDAGISel::Select(SDNode *N) {
SelectFrameIndex(N);
return;
- case ISD::ADD:
- SelectAdd(N);
- return;
-
case ISD::BITCAST:
SelectBitcast(N);
return;
@@ -1226,14 +970,6 @@ void HexagonDAGToDAGISel::Select(SDNode *N) {
SelectMul(N);
return;
- case ISD::AND:
- case ISD::OR:
- case ISD::XOR:
- case ISD::FABS:
- case ISD::FNEG:
- SelectBitOp(N);
- return;
-
case ISD::ZERO_EXTEND:
SelectZeroExtend(N);
return;
@@ -1373,6 +1109,16 @@ void HexagonDAGToDAGISel::PreprocessISelDAG() {
SDValue NewShl = DAG.getNode(ISD::SHL, DL, VT, NewAdd, C);
ReplaceNode(T0.getNode(), NewShl.getNode());
}
+
+ if (EnableAddressRebalancing) {
+ rebalanceAddressTrees();
+
+ DEBUG(
+ dbgs() << "************* SelectionDAG after preprocessing: ***********\n";
+ CurDAG->dump();
+ dbgs() << "************* End SelectionDAG after preprocessing ********\n";
+ );
+ }
}
void HexagonDAGToDAGISel::EmitFunctionEntryCode() {
@@ -1381,11 +1127,11 @@ void HexagonDAGToDAGISel::EmitFunctionEntryCode() {
if (!HFI.needsAligna(*MF))
return;
- MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
MachineBasicBlock *EntryBB = &MF->front();
unsigned AR = FuncInfo->CreateReg(MVT::i32);
- unsigned MaxA = MFI->getMaxAlignment();
- BuildMI(EntryBB, DebugLoc(), HII->get(Hexagon::ALIGNA), AR)
+ unsigned MaxA = MFI.getMaxAlignment();
+ BuildMI(EntryBB, DebugLoc(), HII->get(Hexagon::PS_aligna), AR)
.addImm(MaxA);
MF->getInfo<HexagonMachineFunctionInfo>()->setStackAlignBaseVReg(AR);
}
@@ -1395,9 +1141,9 @@ bool HexagonDAGToDAGISel::SelectAddrFI(SDValue& N, SDValue &R) {
if (N.getOpcode() != ISD::FrameIndex)
return false;
auto &HFI = *HST->getFrameLowering();
- MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
int FX = cast<FrameIndexSDNode>(N)->getIndex();
- if (!MFI->isFixedObjectIndex(FX) && HFI.needsAligna(*MF))
+ if (!MFI.isFixedObjectIndex(FX) && HFI.needsAligna(*MF))
return false;
R = CurDAG->getTargetFrameIndex(FX, MVT::i32);
return true;
@@ -1519,15 +1265,15 @@ bool HexagonDAGToDAGISel::isValueExtension(const SDValue &Val,
}
-bool HexagonDAGToDAGISel::orIsAdd(const SDNode *N) const {
+bool HexagonDAGToDAGISel::isOrEquivalentToAdd(const SDNode *N) const {
assert(N->getOpcode() == ISD::OR);
auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
assert(C);
// Detect when "or" is used to add an offset to a stack object.
if (auto *FN = dyn_cast<FrameIndexSDNode>(N->getOperand(0))) {
- MachineFrameInfo *MFI = MF->getFrameInfo();
- unsigned A = MFI->getObjectAlignment(FN->getIndex());
+ MachineFrameInfo &MFI = MF->getFrameInfo();
+ unsigned A = MFI.getObjectAlignment(FN->getIndex());
assert(isPowerOf2_32(A));
int32_t Off = C->getSExtValue();
// If the alleged offset fits in the zero bits guaranteed by
@@ -1540,3 +1286,717 @@ bool HexagonDAGToDAGISel::orIsAdd(const SDNode *N) const {
bool HexagonDAGToDAGISel::isAlignedMemNode(const MemSDNode *N) const {
return N->getAlignment() >= N->getMemoryVT().getStoreSize();
}
+
+// Return true when the given node fits in a positive half word.
+bool HexagonDAGToDAGISel::isPositiveHalfWord(const SDNode *N) const {
+ if (const ConstantSDNode *CN = dyn_cast<const ConstantSDNode>(N)) {
+ int64_t V = CN->getSExtValue();
+ return V > 0 && isInt<16>(V);
+ }
+ if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) {
+ const VTSDNode *VN = dyn_cast<const VTSDNode>(N->getOperand(1));
+ return VN->getVT().getSizeInBits() <= 16;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Rebalancing of address calculation trees
+
+static bool isOpcodeHandled(const SDNode *N) {
+ switch (N->getOpcode()) {
+ case ISD::ADD:
+ case ISD::MUL:
+ return true;
+ case ISD::SHL:
+ // We only handle constant shifts because these can be easily flattened
+ // into multiplications by 2^Op1.
+ return isa<ConstantSDNode>(N->getOperand(1).getNode());
+ default:
+ return false;
+ }
+}
+
+/// \brief Return the weight of an SDNode
+int HexagonDAGToDAGISel::getWeight(SDNode *N) {
+ if (!isOpcodeHandled(N))
+ return 1;
+ assert(RootWeights.count(N) && "Cannot get weight of unseen root!");
+ assert(RootWeights[N] != -1 && "Cannot get weight of unvisited root!");
+ assert(RootWeights[N] != -2 && "Cannot get weight of RAWU'd root!");
+ return RootWeights[N];
+}
+
+int HexagonDAGToDAGISel::getHeight(SDNode *N) {
+ if (!isOpcodeHandled(N))
+ return 0;
+ assert(RootWeights.count(N) && RootWeights[N] >= 0 &&
+ "Cannot query height of unvisited/RAUW'd node!");
+ return RootHeights[N];
+}
+
+namespace {
+struct WeightedLeaf {
+ SDValue Value;
+ int Weight;
+ int InsertionOrder;
+
+ WeightedLeaf() : Value(SDValue()) { }
+
+ WeightedLeaf(SDValue Value, int Weight, int InsertionOrder) :
+ Value(Value), Weight(Weight), InsertionOrder(InsertionOrder) {
+ assert(Weight >= 0 && "Weight must be >= 0");
+ }
+
+ static bool Compare(const WeightedLeaf &A, const WeightedLeaf &B) {
+ assert(A.Value.getNode() && B.Value.getNode());
+ return A.Weight == B.Weight ?
+ (A.InsertionOrder > B.InsertionOrder) :
+ (A.Weight > B.Weight);
+ }
+};
+
+/// A specialized priority queue for WeigthedLeaves. It automatically folds
+/// constants and allows removal of non-top elements while maintaining the
+/// priority order.
+class LeafPrioQueue {
+ SmallVector<WeightedLeaf, 8> Q;
+ bool HaveConst;
+ WeightedLeaf ConstElt;
+ unsigned Opcode;
+
+public:
+ bool empty() {
+ return (!HaveConst && Q.empty());
+ }
+
+ size_t size() {
+ return Q.size() + HaveConst;
+ }
+
+ bool hasConst() {
+ return HaveConst;
+ }
+
+ const WeightedLeaf &top() {
+ if (HaveConst)
+ return ConstElt;
+ return Q.front();
+ }
+
+ WeightedLeaf pop() {
+ if (HaveConst) {
+ HaveConst = false;
+ return ConstElt;
+ }
+ std::pop_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
+ return Q.pop_back_val();
+ }
+
+ void push(WeightedLeaf L, bool SeparateConst=true) {
+ if (!HaveConst && SeparateConst && isa<ConstantSDNode>(L.Value)) {
+ if (Opcode == ISD::MUL &&
+ cast<ConstantSDNode>(L.Value)->getSExtValue() == 1)
+ return;
+ if (Opcode == ISD::ADD &&
+ cast<ConstantSDNode>(L.Value)->getSExtValue() == 0)
+ return;
+
+ HaveConst = true;
+ ConstElt = L;
+ } else {
+ Q.push_back(L);
+ std::push_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
+ }
+ }
+
+ /// Push L to the bottom of the queue regardless of its weight. If L is
+ /// constant, it will not be folded with other constants in the queue.
+ void pushToBottom(WeightedLeaf L) {
+ L.Weight = 1000;
+ push(L, false);
+ }
+
+ /// Search for a SHL(x, [<=MaxAmount]) subtree in the queue, return the one of
+ /// lowest weight and remove it from the queue.
+ WeightedLeaf findSHL(uint64_t MaxAmount);
+
+ WeightedLeaf findMULbyConst();
+
+ LeafPrioQueue(unsigned Opcode) :
+ HaveConst(false), Opcode(Opcode) { }
+};
+} // end anonymous namespace
+
+WeightedLeaf LeafPrioQueue::findSHL(uint64_t MaxAmount) {
+ int ResultPos;
+ WeightedLeaf Result;
+
+ for (int Pos = 0, End = Q.size(); Pos != End; ++Pos) {
+ const WeightedLeaf &L = Q[Pos];
+ const SDValue &Val = L.Value;
+ if (Val.getOpcode() != ISD::SHL ||
+ !isa<ConstantSDNode>(Val.getOperand(1)) ||
+ Val.getConstantOperandVal(1) > MaxAmount)
+ continue;
+ if (!Result.Value.getNode() || Result.Weight > L.Weight ||
+ (Result.Weight == L.Weight && Result.InsertionOrder > L.InsertionOrder))
+ {
+ Result = L;
+ ResultPos = Pos;
+ }
+ }
+
+ if (Result.Value.getNode()) {
+ Q.erase(&Q[ResultPos]);
+ std::make_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
+ }
+
+ return Result;
+}
+
+WeightedLeaf LeafPrioQueue::findMULbyConst() {
+ int ResultPos;
+ WeightedLeaf Result;
+
+ for (int Pos = 0, End = Q.size(); Pos != End; ++Pos) {
+ const WeightedLeaf &L = Q[Pos];
+ const SDValue &Val = L.Value;
+ if (Val.getOpcode() != ISD::MUL ||
+ !isa<ConstantSDNode>(Val.getOperand(1)) ||
+ Val.getConstantOperandVal(1) > 127)
+ continue;
+ if (!Result.Value.getNode() || Result.Weight > L.Weight ||
+ (Result.Weight == L.Weight && Result.InsertionOrder > L.InsertionOrder))
+ {
+ Result = L;
+ ResultPos = Pos;
+ }
+ }
+
+ if (Result.Value.getNode()) {
+ Q.erase(&Q[ResultPos]);
+ std::make_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
+ }
+
+ return Result;
+}
+
+SDValue HexagonDAGToDAGISel::getMultiplierForSHL(SDNode *N) {
+ uint64_t MulFactor = 1ull << N->getConstantOperandVal(1);
+ return CurDAG->getConstant(MulFactor, SDLoc(N),
+ N->getOperand(1).getValueType());
+}
+
+/// @returns the value x for which 2^x is a factor of Val
+static unsigned getPowerOf2Factor(SDValue Val) {
+ if (Val.getOpcode() == ISD::MUL) {
+ unsigned MaxFactor = 0;
+ for (int i = 0; i < 2; ++i) {
+ ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(i));
+ if (!C)
+ continue;
+ const APInt &CInt = C->getAPIntValue();
+ if (CInt.getBoolValue())
+ MaxFactor = CInt.countTrailingZeros();
+ }
+ return MaxFactor;
+ }
+ if (Val.getOpcode() == ISD::SHL) {
+ if (!isa<ConstantSDNode>(Val.getOperand(1).getNode()))
+ return 0;
+ return (unsigned) Val.getConstantOperandVal(1);
+ }
+
+ return 0;
+}
+
+/// @returns true if V>>Amount will eliminate V's operation on its child
+static bool willShiftRightEliminate(SDValue V, unsigned Amount) {
+ if (V.getOpcode() == ISD::MUL) {
+ SDValue Ops[] = { V.getOperand(0), V.getOperand(1) };
+ for (int i = 0; i < 2; ++i)
+ if (isa<ConstantSDNode>(Ops[i].getNode()) &&
+ V.getConstantOperandVal(i) % (1ULL << Amount) == 0) {
+ uint64_t NewConst = V.getConstantOperandVal(i) >> Amount;
+ return (NewConst == 1);
+ }
+ } else if (V.getOpcode() == ISD::SHL) {
+ return (Amount == V.getConstantOperandVal(1));
+ }
+
+ return false;
+}
+
+SDValue HexagonDAGToDAGISel::factorOutPowerOf2(SDValue V, unsigned Power) {
+ SDValue Ops[] = { V.getOperand(0), V.getOperand(1) };
+ if (V.getOpcode() == ISD::MUL) {
+ for (int i=0; i < 2; ++i) {
+ if (isa<ConstantSDNode>(Ops[i].getNode()) &&
+ V.getConstantOperandVal(i) % ((uint64_t)1 << Power) == 0) {
+ uint64_t NewConst = V.getConstantOperandVal(i) >> Power;
+ if (NewConst == 1)
+ return Ops[!i];
+ Ops[i] = CurDAG->getConstant(NewConst,
+ SDLoc(V), V.getValueType());
+ break;
+ }
+ }
+ } else if (V.getOpcode() == ISD::SHL) {
+ uint64_t ShiftAmount = V.getConstantOperandVal(1);
+ if (ShiftAmount == Power)
+ return Ops[0];
+ Ops[1] = CurDAG->getConstant(ShiftAmount - Power,
+ SDLoc(V), V.getValueType());
+ }
+
+ return CurDAG->getNode(V.getOpcode(), SDLoc(V), V.getValueType(), Ops);
+}
+
+static bool isTargetConstant(const SDValue &V) {
+ return V.getOpcode() == HexagonISD::CONST32 ||
+ V.getOpcode() == HexagonISD::CONST32_GP;
+}
+
+unsigned HexagonDAGToDAGISel::getUsesInFunction(const Value *V) {
+ if (GAUsesInFunction.count(V))
+ return GAUsesInFunction[V];
+
+ unsigned Result = 0;
+ const Function *CurF = CurDAG->getMachineFunction().getFunction();
+ for (const User *U : V->users()) {
+ if (isa<Instruction>(U) &&
+ cast<Instruction>(U)->getParent()->getParent() == CurF)
+ ++Result;
+ }
+
+ GAUsesInFunction[V] = Result;
+
+ return Result;
+}
+
+/// Note - After calling this, N may be dead. It may have been replaced by a
+/// new node, so always use the returned value in place of N.
+///
+/// @returns The SDValue taking the place of N (which could be N if it is
+/// unchanged)
+SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
+ assert(RootWeights.count(N) && "Cannot balance non-root node.");
+ assert(RootWeights[N] != -2 && "This node was RAUW'd!");
+ assert(!TopLevel || N->getOpcode() == ISD::ADD);
+
+ // Return early if this node was already visited
+ if (RootWeights[N] != -1)
+ return SDValue(N, 0);
+
+ assert(isOpcodeHandled(N));
+
+ SDValue Op0 = N->getOperand(0);
+ SDValue Op1 = N->getOperand(1);
+
+ // Return early if the operands will remain unchanged or are all roots
+ if ((!isOpcodeHandled(Op0.getNode()) || RootWeights.count(Op0.getNode())) &&
+ (!isOpcodeHandled(Op1.getNode()) || RootWeights.count(Op1.getNode()))) {
+ SDNode *Op0N = Op0.getNode();
+ int Weight;
+ if (isOpcodeHandled(Op0N) && RootWeights[Op0N] == -1) {
+ Weight = getWeight(balanceSubTree(Op0N).getNode());
+ // Weight = calculateWeight(Op0N);
+ } else
+ Weight = getWeight(Op0N);
+
+ SDNode *Op1N = N->getOperand(1).getNode(); // Op1 may have been RAUWd
+ if (isOpcodeHandled(Op1N) && RootWeights[Op1N] == -1) {
+ Weight += getWeight(balanceSubTree(Op1N).getNode());
+ // Weight += calculateWeight(Op1N);
+ } else
+ Weight += getWeight(Op1N);
+
+ RootWeights[N] = Weight;
+ RootHeights[N] = std::max(getHeight(N->getOperand(0).getNode()),
+ getHeight(N->getOperand(1).getNode())) + 1;
+
+ DEBUG(dbgs() << "--> No need to balance root (Weight=" << Weight
+ << " Height=" << RootHeights[N] << "): ");
+ DEBUG(N->dump());
+
+ return SDValue(N, 0);
+ }
+
+ DEBUG(dbgs() << "** Balancing root node: ");
+ DEBUG(N->dump());
+
+ unsigned NOpcode = N->getOpcode();
+
+ LeafPrioQueue Leaves(NOpcode);
+ SmallVector<SDValue, 4> Worklist;
+ Worklist.push_back(SDValue(N, 0));
+
+ // SHL nodes will be converted to MUL nodes
+ if (NOpcode == ISD::SHL)
+ NOpcode = ISD::MUL;
+
+ bool CanFactorize = false;
+ WeightedLeaf Mul1, Mul2;
+ unsigned MaxPowerOf2 = 0;
+ WeightedLeaf GA;
+
+ // Do not try to factor out a shift if there is already a shift at the tip of
+ // the tree.
+ bool HaveTopLevelShift = false;
+ if (TopLevel &&
+ ((isOpcodeHandled(Op0.getNode()) && Op0.getOpcode() == ISD::SHL &&
+ Op0.getConstantOperandVal(1) < 4) ||
+ (isOpcodeHandled(Op1.getNode()) && Op1.getOpcode() == ISD::SHL &&
+ Op1.getConstantOperandVal(1) < 4)))
+ HaveTopLevelShift = true;
+
+ // Flatten the subtree into an ordered list of leaves; at the same time
+ // determine whether the tree is already balanced.
+ int InsertionOrder = 0;
+ SmallDenseMap<SDValue, int> NodeHeights;
+ bool Imbalanced = false;
+ int CurrentWeight = 0;
+ while (!Worklist.empty()) {
+ SDValue Child = Worklist.pop_back_val();
+
+ if (Child.getNode() != N && RootWeights.count(Child.getNode())) {
+ // CASE 1: Child is a root note
+
+ int Weight = RootWeights[Child.getNode()];
+ if (Weight == -1) {
+ Child = balanceSubTree(Child.getNode());
+ // calculateWeight(Child.getNode());
+ Weight = getWeight(Child.getNode());
+ } else if (Weight == -2) {
+ // Whoops, this node was RAUWd by one of the balanceSubTree calls we
+ // made. Our worklist isn't up to date anymore.
+ // Restart the whole process.
+ DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
+ return balanceSubTree(N, TopLevel);
+ }
+
+ NodeHeights[Child] = 1;
+ CurrentWeight += Weight;
+
+ unsigned PowerOf2;
+ if (TopLevel && !CanFactorize && !HaveTopLevelShift &&
+ (Child.getOpcode() == ISD::MUL || Child.getOpcode() == ISD::SHL) &&
+ Child.hasOneUse() && (PowerOf2 = getPowerOf2Factor(Child))) {
+ // Try to identify two factorizable MUL/SHL children greedily. Leave
+ // them out of the priority queue for now so we can deal with them
+ // after.
+ if (!Mul1.Value.getNode()) {
+ Mul1 = WeightedLeaf(Child, Weight, InsertionOrder++);
+ MaxPowerOf2 = PowerOf2;
+ } else {
+ Mul2 = WeightedLeaf(Child, Weight, InsertionOrder++);
+ MaxPowerOf2 = std::min(MaxPowerOf2, PowerOf2);
+
+ // Our addressing modes can only shift by a maximum of 3
+ if (MaxPowerOf2 > 3)
+ MaxPowerOf2 = 3;
+
+ CanFactorize = true;
+ }
+ } else
+ Leaves.push(WeightedLeaf(Child, Weight, InsertionOrder++));
+ } else if (!isOpcodeHandled(Child.getNode())) {
+ // CASE 2: Child is an unhandled kind of node (e.g. constant)
+ int Weight = getWeight(Child.getNode());
+
+ NodeHeights[Child] = getHeight(Child.getNode());
+ CurrentWeight += Weight;
+
+ if (isTargetConstant(Child) && !GA.Value.getNode())
+ GA = WeightedLeaf(Child, Weight, InsertionOrder++);
+ else
+ Leaves.push(WeightedLeaf(Child, Weight, InsertionOrder++));
+ } else {
+ // CASE 3: Child is a subtree of same opcode
+ // Visit children first, then flatten.
+ unsigned ChildOpcode = Child.getOpcode();
+ assert(ChildOpcode == NOpcode ||
+ (NOpcode == ISD::MUL && ChildOpcode == ISD::SHL));
+
+ // Convert SHL to MUL
+ SDValue Op1;
+ if (ChildOpcode == ISD::SHL)
+ Op1 = getMultiplierForSHL(Child.getNode());
+ else
+ Op1 = Child->getOperand(1);
+
+ if (!NodeHeights.count(Op1) || !NodeHeights.count(Child->getOperand(0))) {
+ assert(!NodeHeights.count(Child) && "Parent visited before children?");
+ // Visit children first, then re-visit this node
+ Worklist.push_back(Child);
+ Worklist.push_back(Op1);
+ Worklist.push_back(Child->getOperand(0));
+ } else {
+ // Back at this node after visiting the children
+ if (std::abs(NodeHeights[Op1] - NodeHeights[Child->getOperand(0)]) > 1)
+ Imbalanced = true;
+
+ NodeHeights[Child] = std::max(NodeHeights[Op1],
+ NodeHeights[Child->getOperand(0)]) + 1;
+ }
+ }
+ }
+
+ DEBUG(dbgs() << "--> Current height=" << NodeHeights[SDValue(N, 0)]
+ << " weight=" << CurrentWeight << " imbalanced="
+ << Imbalanced << "\n");
+
+ // Transform MUL(x, C * 2^Y) + SHL(z, Y) -> SHL(ADD(MUL(x, C), z), Y)
+ // This factors out a shift in order to match memw(a<<Y+b).
+ if (CanFactorize && (willShiftRightEliminate(Mul1.Value, MaxPowerOf2) ||
+ willShiftRightEliminate(Mul2.Value, MaxPowerOf2))) {
+ DEBUG(dbgs() << "--> Found common factor for two MUL children!\n");
+ int Weight = Mul1.Weight + Mul2.Weight;
+ int Height = std::max(NodeHeights[Mul1.Value], NodeHeights[Mul2.Value]) + 1;
+ SDValue Mul1Factored = factorOutPowerOf2(Mul1.Value, MaxPowerOf2);
+ SDValue Mul2Factored = factorOutPowerOf2(Mul2.Value, MaxPowerOf2);
+ SDValue Sum = CurDAG->getNode(ISD::ADD, SDLoc(N), Mul1.Value.getValueType(),
+ Mul1Factored, Mul2Factored);
+ SDValue Const = CurDAG->getConstant(MaxPowerOf2, SDLoc(N),
+ Mul1.Value.getValueType());
+ SDValue New = CurDAG->getNode(ISD::SHL, SDLoc(N), Mul1.Value.getValueType(),
+ Sum, Const);
+ NodeHeights[New] = Height;
+ Leaves.push(WeightedLeaf(New, Weight, Mul1.InsertionOrder));
+ } else if (Mul1.Value.getNode()) {
+ // We failed to factorize two MULs, so now the Muls are left outside the
+ // queue... add them back.
+ Leaves.push(Mul1);
+ if (Mul2.Value.getNode())
+ Leaves.push(Mul2);
+ CanFactorize = false;
+ }
+
+ // Combine GA + Constant -> GA+Offset, but only if GA is not used elsewhere
+ // and the root node itself is not used more than twice. This reduces the
+ // amount of additional constant extenders introduced by this optimization.
+ bool CombinedGA = false;
+ if (NOpcode == ISD::ADD && GA.Value.getNode() && Leaves.hasConst() &&
+ GA.Value.hasOneUse() && N->use_size() < 3) {
+ GlobalAddressSDNode *GANode =
+ cast<GlobalAddressSDNode>(GA.Value.getOperand(0));
+ ConstantSDNode *Offset = cast<ConstantSDNode>(Leaves.top().Value);
+
+ if (getUsesInFunction(GANode->getGlobal()) == 1 && Offset->hasOneUse() &&
+ getTargetLowering()->isOffsetFoldingLegal(GANode)) {
+ DEBUG(dbgs() << "--> Combining GA and offset (" << Offset->getSExtValue()
+ << "): ");
+ DEBUG(GANode->dump());
+
+ SDValue NewTGA =
+ CurDAG->getTargetGlobalAddress(GANode->getGlobal(), SDLoc(GA.Value),
+ GANode->getValueType(0),
+ GANode->getOffset() + (uint64_t)Offset->getSExtValue());
+ GA.Value = CurDAG->getNode(GA.Value.getOpcode(), SDLoc(GA.Value),
+ GA.Value.getValueType(), NewTGA);
+ GA.Weight += Leaves.top().Weight;
+
+ NodeHeights[GA.Value] = getHeight(GA.Value.getNode());
+ CombinedGA = true;
+
+ Leaves.pop(); // Remove the offset constant from the queue
+ }
+ }
+
+ if ((RebalanceOnlyForOptimizations && !CanFactorize && !CombinedGA) ||
+ (RebalanceOnlyImbalancedTrees && !Imbalanced)) {
+ RootWeights[N] = CurrentWeight;
+ RootHeights[N] = NodeHeights[SDValue(N, 0)];
+
+ return SDValue(N, 0);
+ }
+
+ // Combine GA + SHL(x, C<=31) so we will match Rx=add(#u8,asl(Rx,#U5))
+ if (NOpcode == ISD::ADD && GA.Value.getNode()) {
+ WeightedLeaf SHL = Leaves.findSHL(31);
+ if (SHL.Value.getNode()) {
+ int Height = std::max(NodeHeights[GA.Value], NodeHeights[SHL.Value]) + 1;
+ GA.Value = CurDAG->getNode(ISD::ADD, SDLoc(GA.Value),
+ GA.Value.getValueType(),
+ GA.Value, SHL.Value);
+ GA.Weight = SHL.Weight; // Specifically ignore the GA weight here
+ NodeHeights[GA.Value] = Height;
+ }
+ }
+
+ if (GA.Value.getNode())
+ Leaves.push(GA);
+
+ // If this is the top level and we haven't factored out a shift, we should try
+ // to move a constant to the bottom to match addressing modes like memw(rX+C)
+ if (TopLevel && !CanFactorize && Leaves.hasConst()) {
+ DEBUG(dbgs() << "--> Pushing constant to tip of tree.");
+ Leaves.pushToBottom(Leaves.pop());
+ }
+
+ const DataLayout &DL = CurDAG->getDataLayout();
+ const TargetLowering &TLI = *getTargetLowering();
+
+ // Rebuild the tree using Huffman's algorithm
+ while (Leaves.size() > 1) {
+ WeightedLeaf L0 = Leaves.pop();
+
+ // See whether we can grab a MUL to form an add(Rx,mpyi(Ry,#u6)),
+ // otherwise just get the next leaf
+ WeightedLeaf L1 = Leaves.findMULbyConst();
+ if (!L1.Value.getNode())
+ L1 = Leaves.pop();
+
+ assert(L0.Weight <= L1.Weight && "Priority queue is broken!");
+
+ SDValue V0 = L0.Value;
+ int V0Weight = L0.Weight;
+ SDValue V1 = L1.Value;
+ int V1Weight = L1.Weight;
+
+ // Make sure that none of these nodes have been RAUW'd
+ if ((RootWeights.count(V0.getNode()) && RootWeights[V0.getNode()] == -2) ||
+ (RootWeights.count(V1.getNode()) && RootWeights[V1.getNode()] == -2)) {
+ DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
+ return balanceSubTree(N, TopLevel);
+ }
+
+ ConstantSDNode *V0C = dyn_cast<ConstantSDNode>(V0);
+ ConstantSDNode *V1C = dyn_cast<ConstantSDNode>(V1);
+ EVT VT = N->getValueType(0);
+ SDValue NewNode;
+
+ if (V0C && !V1C) {
+ std::swap(V0, V1);
+ std::swap(V0C, V1C);
+ }
+
+ // Calculate height of this node
+ assert(NodeHeights.count(V0) && NodeHeights.count(V1) &&
+ "Children must have been visited before re-combining them!");
+ int Height = std::max(NodeHeights[V0], NodeHeights[V1]) + 1;
+
+ // Rebuild this node (and restore SHL from MUL if needed)
+ if (V1C && NOpcode == ISD::MUL && V1C->getAPIntValue().isPowerOf2())
+ NewNode = CurDAG->getNode(
+ ISD::SHL, SDLoc(V0), VT, V0,
+ CurDAG->getConstant(
+ V1C->getAPIntValue().logBase2(), SDLoc(N),
+ TLI.getScalarShiftAmountTy(DL, V0.getValueType())));
+ else
+ NewNode = CurDAG->getNode(NOpcode, SDLoc(N), VT, V0, V1);
+
+ NodeHeights[NewNode] = Height;
+
+ int Weight = V0Weight + V1Weight;
+ Leaves.push(WeightedLeaf(NewNode, Weight, L0.InsertionOrder));
+
+ DEBUG(dbgs() << "--> Built new node (Weight=" << Weight << ",Height="
+ << Height << "):\n");
+ DEBUG(NewNode.dump());
+ }
+
+ assert(Leaves.size() == 1);
+ SDValue NewRoot = Leaves.top().Value;
+
+ assert(NodeHeights.count(NewRoot));
+ int Height = NodeHeights[NewRoot];
+
+ // Restore SHL if we earlier converted it to a MUL
+ if (NewRoot.getOpcode() == ISD::MUL) {
+ ConstantSDNode *V1C = dyn_cast<ConstantSDNode>(NewRoot.getOperand(1));
+ if (V1C && V1C->getAPIntValue().isPowerOf2()) {
+ EVT VT = NewRoot.getValueType();
+ SDValue V0 = NewRoot.getOperand(0);
+ NewRoot = CurDAG->getNode(
+ ISD::SHL, SDLoc(NewRoot), VT, V0,
+ CurDAG->getConstant(
+ V1C->getAPIntValue().logBase2(), SDLoc(NewRoot),
+ TLI.getScalarShiftAmountTy(DL, V0.getValueType())));
+ }
+ }
+
+ if (N != NewRoot.getNode()) {
+ DEBUG(dbgs() << "--> Root is now: ");
+ DEBUG(NewRoot.dump());
+
+ // Replace all uses of old root by new root
+ CurDAG->ReplaceAllUsesWith(N, NewRoot.getNode());
+ // Mark that we have RAUW'd N
+ RootWeights[N] = -2;
+ } else {
+ DEBUG(dbgs() << "--> Root unchanged.\n");
+ }
+
+ RootWeights[NewRoot.getNode()] = Leaves.top().Weight;
+ RootHeights[NewRoot.getNode()] = Height;
+
+ return NewRoot;
+}
+
+void HexagonDAGToDAGISel::rebalanceAddressTrees() {
+ for (auto I = CurDAG->allnodes_begin(), E = CurDAG->allnodes_end(); I != E;) {
+ SDNode *N = &*I++;
+ if (N->getOpcode() != ISD::LOAD && N->getOpcode() != ISD::STORE)
+ continue;
+
+ SDValue BasePtr = cast<MemSDNode>(N)->getBasePtr();
+ if (BasePtr.getOpcode() != ISD::ADD)
+ continue;
+
+ // We've already processed this node
+ if (RootWeights.count(BasePtr.getNode()))
+ continue;
+
+ DEBUG(dbgs() << "** Rebalancing address calculation in node: ");
+ DEBUG(N->dump());
+
+ // FindRoots
+ SmallVector<SDNode *, 4> Worklist;
+
+ Worklist.push_back(BasePtr.getOperand(0).getNode());
+ Worklist.push_back(BasePtr.getOperand(1).getNode());
+
+ while (!Worklist.empty()) {
+ SDNode *N = Worklist.pop_back_val();
+ unsigned Opcode = N->getOpcode();
+
+ if (!isOpcodeHandled(N))
+ continue;
+
+ Worklist.push_back(N->getOperand(0).getNode());
+ Worklist.push_back(N->getOperand(1).getNode());
+
+ // Not a root if it has only one use and same opcode as its parent
+ if (N->hasOneUse() && Opcode == N->use_begin()->getOpcode())
+ continue;
+
+ // This root node has already been processed
+ if (RootWeights.count(N))
+ continue;
+
+ RootWeights[N] = -1;
+ }
+
+ // Balance node itself
+ RootWeights[BasePtr.getNode()] = -1;
+ SDValue NewBasePtr = balanceSubTree(BasePtr.getNode(), /*TopLevel=*/ true);
+
+ if (N->getOpcode() == ISD::LOAD)
+ N = CurDAG->UpdateNodeOperands(N, N->getOperand(0),
+ NewBasePtr, N->getOperand(2));
+ else
+ N = CurDAG->UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1),
+ NewBasePtr, N->getOperand(3));
+
+ DEBUG(dbgs() << "--> Final node: ");
+ DEBUG(N->dump());
+ }
+
+ CurDAG->RemoveDeadNodes();
+ GAUsesInFunction.clear();
+ RootHeights.clear();
+ RootWeights.clear();
+}
+
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index cdd4c2f..e87e1e6 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -12,30 +12,52 @@
//
//===----------------------------------------------------------------------===//
+#include "Hexagon.h"
#include "HexagonISelLowering.h"
#include "HexagonMachineFunctionInfo.h"
+#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonTargetObjectFile.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineJumpTableInfo.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/RuntimeLibcalls.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalAlias.h"
-#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetCallingConv.h"
+#include "llvm/Target/TargetMachine.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <utility>
using namespace llvm;
@@ -83,23 +105,31 @@ static cl::opt<int> MaxStoresPerMemsetOptSizeCL("max-store-memset-Os",
namespace {
-class HexagonCCState : public CCState {
- unsigned NumNamedVarArgParams;
-public:
- HexagonCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
- SmallVectorImpl<CCValAssign> &locs, LLVMContext &C,
- int NumNamedVarArgParams)
- : CCState(CC, isVarArg, MF, locs, C),
- NumNamedVarArgParams(NumNamedVarArgParams) {}
+ class HexagonCCState : public CCState {
+ unsigned NumNamedVarArgParams;
- unsigned getNumNamedVarArgParams() const { return NumNamedVarArgParams; }
-};
-}
+ public:
+ HexagonCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
+ SmallVectorImpl<CCValAssign> &locs, LLVMContext &C,
+ int NumNamedVarArgParams)
+ : CCState(CC, isVarArg, MF, locs, C),
+ NumNamedVarArgParams(NumNamedVarArgParams) {}
+
+ unsigned getNumNamedVarArgParams() const { return NumNamedVarArgParams; }
+ };
+
+ enum StridedLoadKind {
+ Even = 0,
+ Odd,
+ NoPattern
+ };
+
+} // end anonymous namespace
// Implement calling convention for Hexagon.
-static bool IsHvxVectorType(MVT ty);
+static bool isHvxVectorType(MVT ty);
static bool
CC_Hexagon(unsigned ValNo, MVT ValVT,
@@ -153,13 +183,13 @@ CC_Hexagon_VarArg (unsigned ValNo, MVT ValVT,
}
// Deal with un-named arguments.
- unsigned ofst;
+ unsigned Offset;
if (ArgFlags.isByVal()) {
// If pass-by-value, the size allocated on stack is decided
// by ArgFlags.getByValSize(), not by the size of LocVT.
- ofst = State.AllocateStack(ArgFlags.getByValSize(),
- ArgFlags.getByValAlign());
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(ArgFlags.getByValSize(),
+ ArgFlags.getByValAlign());
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::i1 || LocVT == MVT::i8 || LocVT == MVT::i16) {
@@ -173,50 +203,49 @@ CC_Hexagon_VarArg (unsigned ValNo, MVT ValVT,
LocInfo = CCValAssign::AExt;
}
if (LocVT == MVT::i32 || LocVT == MVT::f32) {
- ofst = State.AllocateStack(4, 4);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(4, 4);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::i64 || LocVT == MVT::f64) {
- ofst = State.AllocateStack(8, 8);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(8, 8);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::v2i64 || LocVT == MVT::v4i32 || LocVT == MVT::v8i16 ||
LocVT == MVT::v16i8) {
- ofst = State.AllocateStack(16, 16);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(16, 16);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::v4i64 || LocVT == MVT::v8i32 || LocVT == MVT::v16i16 ||
LocVT == MVT::v32i8) {
- ofst = State.AllocateStack(32, 32);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(32, 32);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::v8i64 || LocVT == MVT::v16i32 || LocVT == MVT::v32i16 ||
LocVT == MVT::v64i8 || LocVT == MVT::v512i1) {
- ofst = State.AllocateStack(64, 64);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(64, 64);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::v16i64 || LocVT == MVT::v32i32 || LocVT == MVT::v64i16 ||
LocVT == MVT::v128i8 || LocVT == MVT::v1024i1) {
- ofst = State.AllocateStack(128, 128);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(128, 128);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::v32i64 || LocVT == MVT::v64i32 || LocVT == MVT::v128i16 ||
LocVT == MVT::v256i8) {
- ofst = State.AllocateStack(256, 256);
- State.addLoc(CCValAssign::getMem(ValNo, ValVT, ofst, LocVT, LocInfo));
+ Offset = State.AllocateStack(256, 256);
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
return false;
}
llvm_unreachable(nullptr);
}
-
static bool CC_Hexagon (unsigned ValNo, MVT ValVT, MVT LocVT,
CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) {
if (ArgFlags.isByVal()) {
@@ -260,7 +289,7 @@ static bool CC_Hexagon (unsigned ValNo, MVT ValVT, MVT LocVT,
return false;
}
- if (IsHvxVectorType(LocVT)) {
+ if (isHvxVectorType(LocVT)) {
if (!CC_HexagonVector(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
return false;
}
@@ -272,7 +301,6 @@ static bool CC_Hexagon (unsigned ValNo, MVT ValVT, MVT LocVT,
static bool CC_Hexagon32(unsigned ValNo, MVT ValVT,
MVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
-
static const MCPhysReg RegList[] = {
Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4,
Hexagon::R5
@@ -290,7 +318,6 @@ static bool CC_Hexagon32(unsigned ValNo, MVT ValVT,
static bool CC_Hexagon64(unsigned ValNo, MVT ValVT,
MVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
-
if (unsigned Reg = State.AllocateReg(Hexagon::D0)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
@@ -315,19 +342,16 @@ static bool CC_Hexagon64(unsigned ValNo, MVT ValVT,
static bool CC_HexagonVector(unsigned ValNo, MVT ValVT,
MVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
-
- static const MCPhysReg VecLstS[] = { Hexagon::V0, Hexagon::V1,
- Hexagon::V2, Hexagon::V3,
- Hexagon::V4, Hexagon::V5,
- Hexagon::V6, Hexagon::V7,
- Hexagon::V8, Hexagon::V9,
- Hexagon::V10, Hexagon::V11,
- Hexagon::V12, Hexagon::V13,
- Hexagon::V14, Hexagon::V15};
- static const MCPhysReg VecLstD[] = { Hexagon::W0, Hexagon::W1,
- Hexagon::W2, Hexagon::W3,
- Hexagon::W4, Hexagon::W5,
- Hexagon::W6, Hexagon::W7};
+ static const MCPhysReg VecLstS[] = {
+ Hexagon::V0, Hexagon::V1, Hexagon::V2, Hexagon::V3, Hexagon::V4,
+ Hexagon::V5, Hexagon::V6, Hexagon::V7, Hexagon::V8, Hexagon::V9,
+ Hexagon::V10, Hexagon::V11, Hexagon::V12, Hexagon::V13, Hexagon::V14,
+ Hexagon::V15
+ };
+ static const MCPhysReg VecLstD[] = {
+ Hexagon::W0, Hexagon::W1, Hexagon::W2, Hexagon::W3, Hexagon::W4,
+ Hexagon::W5, Hexagon::W6, Hexagon::W7
+ };
auto &MF = State.getMachineFunction();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
bool UseHVX = HST.useHVXOps();
@@ -429,16 +453,16 @@ static bool RetCC_Hexagon(unsigned ValNo, MVT ValVT,
}
if (LocVT == MVT::i32 || LocVT == MVT::f32) {
if (!RetCC_Hexagon32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
- return false;
+ return false;
}
if (LocVT == MVT::i64 || LocVT == MVT::f64) {
if (!RetCC_Hexagon64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
- return false;
+ return false;
}
if (LocVT == MVT::v16i32 || LocVT == MVT::v32i32 || LocVT == MVT::v64i32) {
if (!RetCC_HexagonVector(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
- return false;
+ return false;
}
return true; // CC didn't match.
}
@@ -452,7 +476,7 @@ static bool RetCC_Hexagon32(unsigned ValNo, MVT ValVT,
// return structs using these additional registers.
static const uint16_t RegList[] = { Hexagon::R0, Hexagon::R1,
Hexagon::R2, Hexagon::R3,
- Hexagon::R4, Hexagon::R5};
+ Hexagon::R4, Hexagon::R5 };
if (unsigned Reg = State.AllocateReg(RegList)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
@@ -525,7 +549,7 @@ void HexagonTargetLowering::promoteLdStType(MVT VT, MVT PromotedLdStVT) {
SDValue
HexagonTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG)
-const {
+ const {
return SDValue();
}
@@ -537,7 +561,6 @@ const {
static SDValue CreateCopyOfByValArgument(SDValue Src, SDValue Dst,
SDValue Chain, ISD::ArgFlagsTy Flags,
SelectionDAG &DAG, const SDLoc &dl) {
-
SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), dl, MVT::i32);
return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(),
/*isVolatile=*/false, /*AlwaysInline=*/false,
@@ -545,14 +568,26 @@ static SDValue CreateCopyOfByValArgument(SDValue Src, SDValue Dst,
MachinePointerInfo(), MachinePointerInfo());
}
-static bool IsHvxVectorType(MVT ty) {
- return (ty == MVT::v8i64 || ty == MVT::v16i32 || ty == MVT::v32i16 ||
- ty == MVT::v64i8 ||
- ty == MVT::v16i64 || ty == MVT::v32i32 || ty == MVT::v64i16 ||
- ty == MVT::v128i8 ||
- ty == MVT::v32i64 || ty == MVT::v64i32 || ty == MVT::v128i16 ||
- ty == MVT::v256i8 ||
- ty == MVT::v512i1 || ty == MVT::v1024i1);
+static bool isHvxVectorType(MVT Ty) {
+ switch (Ty.SimpleTy) {
+ case MVT::v8i64:
+ case MVT::v16i32:
+ case MVT::v32i16:
+ case MVT::v64i8:
+ case MVT::v16i64:
+ case MVT::v32i32:
+ case MVT::v64i16:
+ case MVT::v128i8:
+ case MVT::v32i64:
+ case MVT::v64i32:
+ case MVT::v128i16:
+ case MVT::v256i8:
+ case MVT::v512i1:
+ case MVT::v1024i1:
+ return true;
+ default:
+ return false;
+ }
}
// LowerReturn - Lower ISD::RET. If a struct is larger than 8 bytes and is
@@ -564,7 +599,6 @@ HexagonTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SDLoc &dl, SelectionDAG &DAG) const {
-
// CCValAssign - represent the assignment of the return value to locations.
SmallVector<CCValAssign, 16> RVLocs;
@@ -669,17 +703,17 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
SDValue Chain = CLI.Chain;
SDValue Callee = CLI.Callee;
- bool &isTailCall = CLI.IsTailCall;
+ bool &IsTailCall = CLI.IsTailCall;
CallingConv::ID CallConv = CLI.CallConv;
- bool isVarArg = CLI.IsVarArg;
- bool doesNotReturn = CLI.DoesNotReturn;
+ bool IsVarArg = CLI.IsVarArg;
+ bool DoesNotReturn = CLI.DoesNotReturn;
bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
MachineFunction &MF = DAG.getMachineFunction();
auto PtrVT = getPointerTy(MF.getDataLayout());
// Check for varargs.
- int NumNamedVarArgParams = -1;
+ unsigned NumNamedVarArgParams = -1U;
if (GlobalAddressSDNode *GAN = dyn_cast<GlobalAddressSDNode>(Callee)) {
const GlobalValue *GV = GAN->getGlobal();
Callee = DAG.getTargetGlobalAddress(GV, dl, MVT::i32);
@@ -694,32 +728,32 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
- HexagonCCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ HexagonCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext(), NumNamedVarArgParams);
- if (isVarArg)
+ if (IsVarArg)
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_VarArg);
else
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon);
auto Attr = MF.getFunction()->getFnAttribute("disable-tail-calls");
if (Attr.getValueAsString() == "true")
- isTailCall = false;
+ IsTailCall = false;
- if (isTailCall) {
+ if (IsTailCall) {
bool StructAttrFlag = MF.getFunction()->hasStructRetAttr();
- isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
- isVarArg, IsStructRet,
+ IsTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
+ IsVarArg, IsStructRet,
StructAttrFlag,
Outs, OutVals, Ins, DAG);
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
if (VA.isMemLoc()) {
- isTailCall = false;
+ IsTailCall = false;
break;
}
}
- DEBUG(dbgs() << (isTailCall ? "Eligible for Tail Call\n"
+ DEBUG(dbgs() << (IsTailCall ? "Eligible for Tail Call\n"
: "Argument must be passed on stack. "
"Not eligible for Tail Call\n"));
}
@@ -740,7 +774,7 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SDValue Arg = OutVals[i];
ISD::ArgFlagsTy Flags = Outs[i].Flags;
// Record if we need > 8 byte alignment on an argument.
- bool ArgAlign = IsHvxVectorType(VA.getValVT());
+ bool ArgAlign = isHvxVectorType(VA.getValVT());
NeedsArgAlign |= ArgAlign;
// Promote the value if needed.
@@ -792,35 +826,35 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (NeedsArgAlign && Subtarget.hasV60TOps()) {
DEBUG(dbgs() << "Function needs byte stack align due to call args\n");
- MachineFrameInfo* MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
// V6 vectors passed by value have 64 or 128 byte alignment depending
// on whether we are 64 byte vector mode or 128 byte.
bool UseHVXDbl = Subtarget.useHVXDblOps();
assert(Subtarget.useHVXOps());
const unsigned ObjAlign = UseHVXDbl ? 128 : 64;
LargestAlignSeen = std::max(LargestAlignSeen, ObjAlign);
- MFI->ensureMaxAlignment(LargestAlignSeen);
+ MFI.ensureMaxAlignment(LargestAlignSeen);
}
// Transform all store nodes into one single node because all store
// nodes are independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
- if (!isTailCall) {
+ if (!IsTailCall) {
SDValue C = DAG.getConstant(NumBytes, dl, PtrVT, true);
Chain = DAG.getCALLSEQ_START(Chain, C, dl);
}
// Build a sequence of copy-to-reg nodes chained together with token
// chain and flag operands which copy the outgoing args into registers.
- // The InFlag in necessary since all emitted instructions must be
+ // The Glue is necessary since all emitted instructions must be
// stuck together.
- SDValue InFlag;
- if (!isTailCall) {
+ SDValue Glue;
+ if (!IsTailCall) {
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
- RegsToPass[i].second, InFlag);
- InFlag = Chain.getValue(1);
+ RegsToPass[i].second, Glue);
+ Glue = Chain.getValue(1);
}
} else {
// For tail calls lower the arguments to the 'real' stack slot.
@@ -833,23 +867,26 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// on every argument instead of just those arguments it would clobber.
//
// Do not flag preceding copytoreg stuff together with the following stuff.
- InFlag = SDValue();
+ Glue = SDValue();
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
- RegsToPass[i].second, InFlag);
- InFlag = Chain.getValue(1);
+ RegsToPass[i].second, Glue);
+ Glue = Chain.getValue(1);
}
- InFlag = SDValue();
+ Glue = SDValue();
}
+ bool LongCalls = MF.getSubtarget<HexagonSubtarget>().useLongCalls();
+ unsigned Flags = LongCalls ? HexagonII::HMOTF_ConstExtended : 0;
+
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
// node so that legalize doesn't hack it.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, PtrVT);
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, PtrVT, 0, Flags);
} else if (ExternalSymbolSDNode *S =
dyn_cast<ExternalSymbolSDNode>(Callee)) {
- Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT);
+ Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, Flags);
}
// Returns a chain & a flag for retval copy to use.
@@ -865,33 +902,32 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
RegsToPass[i].second.getValueType()));
}
- if (InFlag.getNode())
- Ops.push_back(InFlag);
+ if (Glue.getNode())
+ Ops.push_back(Glue);
- if (isTailCall) {
- MF.getFrameInfo()->setHasTailCall();
+ if (IsTailCall) {
+ MF.getFrameInfo().setHasTailCall();
return DAG.getNode(HexagonISD::TC_RETURN, dl, NodeTys, Ops);
}
- int OpCode = doesNotReturn ? HexagonISD::CALLv3nr : HexagonISD::CALLv3;
+ unsigned OpCode = DoesNotReturn ? HexagonISD::CALLnr : HexagonISD::CALL;
Chain = DAG.getNode(OpCode, dl, NodeTys, Ops);
- InFlag = Chain.getValue(1);
+ Glue = Chain.getValue(1);
// Create the CALLSEQ_END node.
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, dl, true),
- DAG.getIntPtrConstant(0, dl, true), InFlag, dl);
- InFlag = Chain.getValue(1);
+ DAG.getIntPtrConstant(0, dl, true), Glue, dl);
+ Glue = Chain.getValue(1);
// Handle result values, copying them out of physregs into vregs that we
// return.
- return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl, DAG,
+ return LowerCallResult(Chain, Glue, CallConv, IsVarArg, Ins, dl, DAG,
InVals, OutVals, Callee);
}
static bool getIndexedAddressParts(SDNode *Ptr, EVT VT,
- bool isSEXTLoad, SDValue &Base,
- SDValue &Offset, bool &isInc,
- SelectionDAG &DAG) {
+ SDValue &Base, SDValue &Offset,
+ bool &IsInc, SelectionDAG &DAG) {
if (Ptr->getOpcode() != ISD::ADD)
return false;
@@ -908,11 +944,11 @@ static bool getIndexedAddressParts(SDNode *Ptr, EVT VT,
if (ValidHVXDblType || ValidHVXType ||
VT == MVT::i64 || VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) {
- isInc = (Ptr->getOpcode() == ISD::ADD);
+ IsInc = (Ptr->getOpcode() == ISD::ADD);
Base = Ptr->getOperand(0);
Offset = Ptr->getOperand(1);
// Ensure that Offset is a constant.
- return (isa<ConstantSDNode>(Offset));
+ return isa<ConstantSDNode>(Offset);
}
return false;
@@ -929,28 +965,24 @@ bool HexagonTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
{
EVT VT;
SDValue Ptr;
- bool isSEXTLoad = false;
if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
VT = LD->getMemoryVT();
- isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD;
} else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
VT = ST->getMemoryVT();
- if (ST->getValue().getValueType() == MVT::i64 && ST->isTruncatingStore()) {
+ if (ST->getValue().getValueType() == MVT::i64 && ST->isTruncatingStore())
return false;
- }
} else {
return false;
}
- bool isInc = false;
- bool isLegal = getIndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset,
- isInc, DAG);
+ bool IsInc = false;
+ bool isLegal = getIndexedAddressParts(Op, VT, Base, Offset, IsInc, DAG);
if (isLegal) {
auto &HII = *Subtarget.getInstrInfo();
int32_t OffsetVal = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
if (HII.isValidAutoIncImm(VT, OffsetVal)) {
- AM = isInc ? ISD::POST_INC : ISD::POST_DEC;
+ AM = IsInc ? ISD::POST_INC : ISD::POST_DEC;
return true;
}
}
@@ -1054,7 +1086,7 @@ HexagonTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
A = HFI.getStackAlignment();
DEBUG({
- dbgs () << LLVM_FUNCTION_NAME << " Align: " << A << " Size: ";
+ dbgs () << __func__ << " Align: " << A << " Size: ";
Size.getNode()->dump(&DAG);
dbgs() << "\n";
});
@@ -1071,9 +1103,8 @@ SDValue HexagonTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
-
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
auto &FuncInfo = *MF.getInfo<HexagonMachineFunctionInfo>();
@@ -1173,7 +1204,7 @@ SDValue HexagonTargetLowering::LowerFormalArguments(
StackLocation = HEXAGON_LRFP_SIZE + VA.getLocMemOffset();
// Create the frame index object for this incoming parameter...
- FI = MFI->CreateFixedObject(ObjSize, StackLocation, true);
+ FI = MFI.CreateFixedObject(ObjSize, StackLocation, true);
// Create the SelectionDAG nodes cordl, responding to a load
// from this parameter.
@@ -1196,10 +1227,10 @@ SDValue HexagonTargetLowering::LowerFormalArguments(
if (isVarArg) {
// This will point to the next argument passed via stack.
- int FrameIndex = MFI->CreateFixedObject(Hexagon_PointerSize,
- HEXAGON_LRFP_SIZE +
- CCInfo.getNextStackOffset(),
- true);
+ int FrameIndex = MFI.CreateFixedObject(Hexagon_PointerSize,
+ HEXAGON_LRFP_SIZE +
+ CCInfo.getNextStackOffset(),
+ true);
FuncInfo.setVarArgsFrameIndex(FrameIndex);
}
@@ -1392,7 +1423,6 @@ SDValue HexagonTargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
return DAG.getMergeValues(Ops, DL);
}
-
SDValue
HexagonTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const {
EVT ValTy = Op.getValueType();
@@ -1401,11 +1431,18 @@ HexagonTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const {
bool IsPositionIndependent = isPositionIndependent();
unsigned char TF = IsPositionIndependent ? HexagonII::MO_PCREL : 0;
+ unsigned Offset = 0;
SDValue T;
if (CPN->isMachineConstantPoolEntry())
- T = DAG.getTargetConstantPool(CPN->getMachineCPVal(), ValTy, Align, TF);
+ T = DAG.getTargetConstantPool(CPN->getMachineCPVal(), ValTy, Align, Offset,
+ TF);
else
- T = DAG.getTargetConstantPool(CPN->getConstVal(), ValTy, Align, TF);
+ T = DAG.getTargetConstantPool(CPN->getConstVal(), ValTy, Align, Offset,
+ TF);
+
+ assert(cast<ConstantPoolSDNode>(T)->getTargetFlags() == TF &&
+ "Inconsistent target flag encountered");
+
if (IsPositionIndependent)
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), ValTy, T);
return DAG.getNode(HexagonISD::CP, SDLoc(Op), ValTy, T);
@@ -1428,7 +1465,7 @@ SDValue
HexagonTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
@@ -1453,7 +1490,7 @@ HexagonTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
SDValue
HexagonTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
- MachineFrameInfo &MFI = *DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
@@ -1473,7 +1510,6 @@ HexagonTargetLowering::LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const {
return DAG.getNode(HexagonISD::BARRIER, dl, MVT::Other, Op.getOperand(0));
}
-
SDValue
HexagonTargetLowering::LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) const {
SDLoc dl(Op);
@@ -1487,7 +1523,8 @@ HexagonTargetLowering::LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) const {
if (RM == Reloc::Static) {
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, Offset);
- if (HLOF.isGlobalInSmallSection(GV, HTM))
+ const GlobalObject *GO = GV->getBaseObject();
+ if (GO && HLOF.isGlobalInSmallSection(GO, HTM))
return DAG.getNode(HexagonISD::CONST32_GP, dl, PtrVT, GA);
return DAG.getNode(HexagonISD::CONST32, dl, PtrVT, GA);
}
@@ -1536,7 +1573,7 @@ SDValue
HexagonTargetLowering::GetDynamicTLSAddr(SelectionDAG &DAG, SDValue Chain,
GlobalAddressSDNode *GA, SDValue *InFlag, EVT PtrVT, unsigned ReturnReg,
unsigned char OperandFlags) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SDLoc dl(GA);
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl,
@@ -1554,14 +1591,14 @@ HexagonTargetLowering::GetDynamicTLSAddr(SelectionDAG &DAG, SDValue Chain,
if (InFlag) {
SDValue Ops[] = { Chain, TGA,
DAG.getRegister(Hexagon::R0, PtrVT), *InFlag };
- Chain = DAG.getNode(HexagonISD::CALLv3, dl, NodeTys, Ops);
+ Chain = DAG.getNode(HexagonISD::CALL, dl, NodeTys, Ops);
} else {
SDValue Ops[] = { Chain, TGA, DAG.getRegister(Hexagon::R0, PtrVT)};
- Chain = DAG.getNode(HexagonISD::CALLv3, dl, NodeTys, Ops);
+ Chain = DAG.getNode(HexagonISD::CALL, dl, NodeTys, Ops);
}
// Inform MFI that function has calls.
- MFI->setAdjustsStack(true);
+ MFI.setAdjustsStack(true);
SDValue Flag = Chain.getValue(1);
return DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Flag);
@@ -1761,7 +1798,6 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::v32i64, &Hexagon::VecDblRegs128BRegClass);
addRegisterClass(MVT::v1024i1, &Hexagon::VecPredRegs128BRegClass);
}
-
}
//
@@ -1812,7 +1848,7 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
if (EmitJumpTables)
setMinimumJumpTableEntries(MinimumJumpTables);
else
- setMinimumJumpTableEntries(INT_MAX);
+ setMinimumJumpTableEntries(std::numeric_limits<int>::max());
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
// Hexagon has instructions for add/sub with carry. The problem with
@@ -1861,7 +1897,6 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
// operation. There is a pattern that will match i64 mul and transform it
// to a series of instructions.
setOperationAction(ISD::MUL, MVT::i64, Expand);
- setOperationAction(ISD::MULHS, MVT::i64, Expand);
for (unsigned IntExpOp :
{ ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM,
@@ -1887,7 +1922,7 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
}
// Turn FP truncstore into trunc + store.
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
- // Turn FP extload into load/fextend.
+ // Turn FP extload into load/fpextend.
for (MVT VT : MVT::fp_valuetypes())
setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand);
@@ -1937,7 +1972,7 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
ISD::FRINT, ISD::FNEARBYINT, ISD::FROUND, ISD::FFLOOR,
ISD::FMINNUM, ISD::FMAXNUM, ISD::FSINCOS,
// Misc:
- ISD::SELECT, ISD::ConstantPool,
+ ISD::BR_CC, ISD::SELECT_CC, ISD::ConstantPool,
// Vector:
ISD::BUILD_VECTOR, ISD::SCALAR_TO_VECTOR,
ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT,
@@ -1949,12 +1984,22 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
for (unsigned VectExpOp : VectExpOps)
setOperationAction(VectExpOp, VT, Expand);
- // Expand all extended loads and truncating stores:
+ // Expand all extending loads and truncating stores:
for (MVT TargetVT : MVT::vector_valuetypes()) {
+ if (TargetVT == VT)
+ continue;
setLoadExtAction(ISD::EXTLOAD, TargetVT, VT, Expand);
+ setLoadExtAction(ISD::ZEXTLOAD, TargetVT, VT, Expand);
+ setLoadExtAction(ISD::SEXTLOAD, TargetVT, VT, Expand);
setTruncStoreAction(VT, TargetVT, Expand);
}
+ // Normalize all inputs to SELECT to be vectors of i32.
+ if (VT.getVectorElementType() != MVT::i32) {
+ MVT VT32 = MVT::getVectorVT(MVT::i32, VT.getSizeInBits()/32);
+ setOperationAction(ISD::SELECT, VT, Promote);
+ AddPromotedToType(ISD::SELECT, VT, VT32);
+ }
setOperationAction(ISD::SRA, VT, Custom);
setOperationAction(ISD::SHL, VT, Custom);
setOperationAction(ISD::SRL, VT, Custom);
@@ -1983,17 +2028,33 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::VSELECT, MVT::v2i16, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4i16, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v8i8, Custom);
+
if (UseHVX) {
if (UseHVXSgl) {
setOperationAction(ISD::CONCAT_VECTORS, MVT::v128i8, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v64i16, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v32i32, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v16i64, Custom);
+ // We try to generate the vpack{e/o} instructions. If we fail
+ // we fall back upon ExpandOp.
+ setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v64i8, Custom);
+ setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v32i16, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v64i8, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v32i16, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v16i32, Custom);
} else if (UseHVXDbl) {
setOperationAction(ISD::CONCAT_VECTORS, MVT::v256i8, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v128i16, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v64i32, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v32i64, Custom);
+ // We try to generate the vpack{e/o} instructions. If we fail
+ // we fall back upon ExpandOp.
+ setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v128i8, Custom);
+ setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v64i16, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v4i32, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v128i8, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v64i16, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v32i32, Custom);
} else {
llvm_unreachable("Unrecognized HVX mode");
}
@@ -2006,6 +2067,9 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FSUB, MVT::f64, Expand);
setOperationAction(ISD::FMUL, MVT::f64, Expand);
+ setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
+ setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
+
setOperationAction(ISD::FP_TO_UINT, MVT::i1, Promote);
setOperationAction(ISD::FP_TO_UINT, MVT::i8, Promote);
setOperationAction(ISD::FP_TO_UINT, MVT::i16, Promote);
@@ -2018,7 +2082,6 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SINT_TO_FP, MVT::i1, Promote);
setOperationAction(ISD::SINT_TO_FP, MVT::i8, Promote);
setOperationAction(ISD::SINT_TO_FP, MVT::i16, Promote);
-
} else { // V4
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand);
setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand);
@@ -2052,13 +2115,20 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
// Handling of indexed loads/stores: default is "expand".
//
- for (MVT LSXTy : {MVT::i8, MVT::i16, MVT::i32, MVT::i64}) {
- setIndexedLoadAction(ISD::POST_INC, LSXTy, Legal);
- setIndexedStoreAction(ISD::POST_INC, LSXTy, Legal);
+ for (MVT VT : {MVT::i8, MVT::i16, MVT::i32, MVT::i64}) {
+ setIndexedLoadAction(ISD::POST_INC, VT, Legal);
+ setIndexedStoreAction(ISD::POST_INC, VT, Legal);
}
- if (UseHVXDbl) {
- for (MVT VT : {MVT::v128i8, MVT::v64i16, MVT::v32i32, MVT::v16i64}) {
+ if (UseHVXSgl) {
+ for (MVT VT : {MVT::v64i8, MVT::v32i16, MVT::v16i32, MVT::v8i64,
+ MVT::v128i8, MVT::v64i16, MVT::v32i32, MVT::v16i64}) {
+ setIndexedLoadAction(ISD::POST_INC, VT, Legal);
+ setIndexedStoreAction(ISD::POST_INC, VT, Legal);
+ }
+ } else if (UseHVXDbl) {
+ for (MVT VT : {MVT::v128i8, MVT::v64i16, MVT::v32i32, MVT::v16i64,
+ MVT::v256i8, MVT::v128i16, MVT::v64i32, MVT::v32i64}) {
setIndexedLoadAction(ISD::POST_INC, VT, Legal);
setIndexedStoreAction(ISD::POST_INC, VT, Legal);
}
@@ -2177,17 +2247,15 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
setLibcallName(RTLIB::SRA_I128, nullptr);
}
-
const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch ((HexagonISD::NodeType)Opcode) {
case HexagonISD::ALLOCA: return "HexagonISD::ALLOCA";
- case HexagonISD::ARGEXTEND: return "HexagonISD::ARGEXTEND";
case HexagonISD::AT_GOT: return "HexagonISD::AT_GOT";
case HexagonISD::AT_PCREL: return "HexagonISD::AT_PCREL";
case HexagonISD::BARRIER: return "HexagonISD::BARRIER";
+ case HexagonISD::CALL: return "HexagonISD::CALL";
+ case HexagonISD::CALLnr: return "HexagonISD::CALLnr";
case HexagonISD::CALLR: return "HexagonISD::CALLR";
- case HexagonISD::CALLv3nr: return "HexagonISD::CALLv3nr";
- case HexagonISD::CALLv3: return "HexagonISD::CALLv3";
case HexagonISD::COMBINE: return "HexagonISD::COMBINE";
case HexagonISD::CONST32_GP: return "HexagonISD::CONST32_GP";
case HexagonISD::CONST32: return "HexagonISD::CONST32";
@@ -2196,7 +2264,6 @@ const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
case HexagonISD::EH_RETURN: return "HexagonISD::EH_RETURN";
case HexagonISD::EXTRACTU: return "HexagonISD::EXTRACTU";
case HexagonISD::EXTRACTURP: return "HexagonISD::EXTRACTURP";
- case HexagonISD::FCONST32: return "HexagonISD::FCONST32";
case HexagonISD::INSERT: return "HexagonISD::INSERT";
case HexagonISD::INSERTRP: return "HexagonISD::INSERTRP";
case HexagonISD::JT: return "HexagonISD::JT";
@@ -2218,6 +2285,7 @@ const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
case HexagonISD::VCMPWGT: return "HexagonISD::VCMPWGT";
case HexagonISD::VCMPWGTU: return "HexagonISD::VCMPWGTU";
case HexagonISD::VCOMBINE: return "HexagonISD::VCOMBINE";
+ case HexagonISD::VPACK: return "HexagonISD::VPACK";
case HexagonISD::VSHLH: return "HexagonISD::VSHLH";
case HexagonISD::VSHLW: return "HexagonISD::VSHLW";
case HexagonISD::VSPLATB: return "HexagonISD::VSPLTB";
@@ -2247,12 +2315,13 @@ bool HexagonTargetLowering::isTruncateFree(EVT VT1, EVT VT2) const {
return (VT1.getSimpleVT() == MVT::i64) && (VT2.getSimpleVT() == MVT::i32);
}
-// shouldExpandBuildVectorWithShuffles
-// Should we expand the build vector with shuffles?
-bool
-HexagonTargetLowering::shouldExpandBuildVectorWithShuffles(EVT VT,
- unsigned DefinedValues) const {
+bool HexagonTargetLowering::isFMAFasterThanFMulAndFAdd(EVT VT) const {
+ return isOperationLegalOrCustom(ISD::FMA, VT);
+}
+// Should we expand the build vector with shuffles?
+bool HexagonTargetLowering::shouldExpandBuildVectorWithShuffles(EVT VT,
+ unsigned DefinedValues) const {
// Hexagon vector shuffle operates on element sizes of bytes or halfwords
EVT EltVT = VT.getVectorElementType();
int EltBits = EltVT.getSizeInBits();
@@ -2262,14 +2331,48 @@ HexagonTargetLowering::shouldExpandBuildVectorWithShuffles(EVT VT,
return TargetLowering::shouldExpandBuildVectorWithShuffles(VT, DefinedValues);
}
-// LowerVECTOR_SHUFFLE - Lower a vector shuffle (V1, V2, V3). V1 and
-// V2 are the two vectors to select data from, V3 is the permutation.
-static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) {
+static StridedLoadKind isStridedLoad(const ArrayRef<int> &Mask) {
+ int even_start = -2;
+ int odd_start = -1;
+ size_t mask_len = Mask.size();
+ for (auto idx : Mask) {
+ if ((idx - even_start) == 2)
+ even_start = idx;
+ else
+ break;
+ }
+ if (even_start == (int)(mask_len * 2) - 2)
+ return StridedLoadKind::Even;
+ for (auto idx : Mask) {
+ if ((idx - odd_start) == 2)
+ odd_start = idx;
+ else
+ break;
+ }
+ if (odd_start == (int)(mask_len * 2) - 1)
+ return StridedLoadKind::Odd;
+
+ return StridedLoadKind::NoPattern;
+}
+
+bool HexagonTargetLowering::isShuffleMaskLegal(const SmallVectorImpl<int> &Mask,
+ EVT VT) const {
+ if (Subtarget.useHVXOps())
+ return isStridedLoad(Mask) != StridedLoadKind::NoPattern;
+ return true;
+}
+
+// Lower a vector shuffle (V1, V2, V3). V1 and V2 are the two vectors
+// to select data from, V3 is the permutation.
+SDValue
+HexagonTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG)
+ const {
const ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op);
SDValue V1 = Op.getOperand(0);
SDValue V2 = Op.getOperand(1);
SDLoc dl(Op);
EVT VT = Op.getValueType();
+ bool UseHVX = Subtarget.useHVXOps();
if (V2.isUndef())
V2 = V1;
@@ -2288,17 +2391,42 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) {
if (Lane == 0 && V1.getOpcode() == ISD::BUILD_VECTOR &&
!isa<ConstantSDNode>(V1.getOperand(0))) {
bool IsScalarToVector = true;
- for (unsigned i = 1, e = V1.getNumOperands(); i != e; ++i)
+ for (unsigned i = 1, e = V1.getNumOperands(); i != e; ++i) {
if (!V1.getOperand(i).isUndef()) {
IsScalarToVector = false;
break;
}
+ }
if (IsScalarToVector)
return createSplat(DAG, dl, VT, V1.getOperand(0));
}
return createSplat(DAG, dl, VT, DAG.getConstant(Lane, dl, MVT::i32));
}
+ if (UseHVX) {
+ ArrayRef<int> Mask = SVN->getMask();
+ size_t MaskLen = Mask.size();
+ int ElemSizeInBits = VT.getScalarSizeInBits();
+ if ((Subtarget.useHVXSglOps() && (ElemSizeInBits * MaskLen) == 64 * 8) ||
+ (Subtarget.useHVXDblOps() && (ElemSizeInBits * MaskLen) == 128 * 8)) {
+ // Return 1 for odd and 2 of even
+ StridedLoadKind Pattern = isStridedLoad(Mask);
+
+ if (Pattern == StridedLoadKind::NoPattern)
+ return SDValue();
+
+ SDValue Vec0 = Op.getOperand(0);
+ SDValue Vec1 = Op.getOperand(1);
+ SDValue StridePattern = DAG.getConstant(Pattern, dl, MVT::i32);
+ SDValue Ops[] = { Vec1, Vec0, StridePattern };
+ return DAG.getNode(HexagonISD::VPACK, dl, VT, Ops);
+ }
+ // We used to assert in the "else" part here, but that is bad for Halide
+ // Halide creates intermediate double registers by interleaving two
+ // concatenated vector registers. The interleaving requires vector_shuffle
+ // nodes and we shouldn't barf on a double register result of a
+ // vector_shuffle because it is most likely an intermediate result.
+ }
// FIXME: We need to support more general vector shuffles. See
// below the comment from the ARM backend that deals in the general
// case with the vector shuffles. For now, let expand handle these.
@@ -2321,11 +2449,12 @@ static bool isCommonSplatElement(BuildVectorSDNode *BVN) {
return true;
}
-// LowerVECTOR_SHIFT - Lower a vector shift. Try to convert
+// Lower a vector shift. Try to convert
// <VT> = SHL/SRA/SRL <VT> by <VT> to Hexagon specific
// <VT> = SHL/SRA/SRL <VT> by <IT/i32>.
-static SDValue LowerVECTOR_SHIFT(SDValue Op, SelectionDAG &DAG) {
- BuildVectorSDNode *BVN = 0;
+SDValue
+HexagonTargetLowering::LowerVECTOR_SHIFT(SDValue Op, SelectionDAG &DAG) const {
+ BuildVectorSDNode *BVN = nullptr;
SDValue V1 = Op.getOperand(0);
SDValue V2 = Op.getOperand(1);
SDValue V3;
@@ -2442,7 +2571,7 @@ HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
SDValue pack = DAG.getNode(HexagonISD::PACKHL, dl, MVT::v4i16,
BVN->getOperand(1), BVN->getOperand(0));
- return DAG.getTargetExtractSubreg(Hexagon::subreg_loreg, dl, MVT::v2i16,
+ return DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::v2i16,
pack);
}
}
@@ -2474,6 +2603,9 @@ HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
Res = (Res << EltSize) | Val;
}
+ if (Size > 64)
+ return SDValue();
+
if (Size == 64)
ConstVal = DAG.getConstant(Res, dl, MVT::i64);
else
@@ -2497,7 +2629,7 @@ HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
continue;
if (VT.getSizeInBits() == 64 &&
- Operand.getValueType().getSizeInBits() == 32) {
+ Operand.getValueSizeInBits() == 32) {
SDValue C = DAG.getConstant(0, dl, MVT::i32);
Operand = DAG.getNode(HexagonISD::COMBINE, dl, VT, C, Operand);
}
@@ -2562,7 +2694,7 @@ HexagonTargetLowering::LowerCONCAT_VECTORS(SDValue Op,
unsigned N = NElts-i-1;
SDValue OpN = Op.getOperand(N);
- if (VT.getSizeInBits() == 64 && OpN.getValueType().getSizeInBits() == 32) {
+ if (VT.getSizeInBits() == 64 && OpN.getValueSizeInBits() == 32) {
SDValue C = DAG.getConstant(0, dl, MVT::i32);
OpN = DAG.getNode(HexagonISD::COMBINE, dl, VT, C, OpN);
}
@@ -2571,16 +2703,66 @@ HexagonTargetLowering::LowerCONCAT_VECTORS(SDValue Op,
SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i64, S, Offset);
if (VT.getSizeInBits() == 32)
V = DAG.getNode(HexagonISD::INSERTRP, dl, MVT::i32, {V, OpN, Or});
- else
+ else if (VT.getSizeInBits() == 64)
V = DAG.getNode(HexagonISD::INSERTRP, dl, MVT::i64, {V, OpN, Or});
+ else
+ return SDValue();
}
return DAG.getNode(ISD::BITCAST, dl, VT, V);
}
SDValue
+HexagonTargetLowering::LowerEXTRACT_SUBVECTOR_HVX(SDValue Op,
+ SelectionDAG &DAG) const {
+ EVT VT = Op.getOperand(0).getValueType();
+ SDLoc dl(Op);
+ bool UseHVX = Subtarget.useHVXOps();
+ bool UseHVXSgl = Subtarget.useHVXSglOps();
+ // Just in case...
+
+ if (!VT.isVector() || !UseHVX)
+ return SDValue();
+
+ EVT ResVT = Op.getValueType();
+ unsigned ResSize = ResVT.getSizeInBits();
+ unsigned VectorSizeInBits = UseHVXSgl ? (64 * 8) : (128 * 8);
+ unsigned OpSize = VT.getSizeInBits();
+
+ // We deal only with cases where the result is the vector size
+ // and the vector operand is a double register.
+ if (!(ResVT.isByteSized() && ResSize == VectorSizeInBits) ||
+ !(VT.isByteSized() && OpSize == 2 * VectorSizeInBits))
+ return SDValue();
+
+ ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Op.getOperand(1));
+ if (!Cst)
+ return SDValue();
+ unsigned Val = Cst->getZExtValue();
+
+ // These two will get lowered to an appropriate EXTRACT_SUBREG in ISel.
+ if (Val == 0) {
+ SDValue Vec = Op.getOperand(0);
+ return DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, ResVT, Vec);
+ }
+
+ if (ResVT.getVectorNumElements() == Val) {
+ SDValue Vec = Op.getOperand(0);
+ return DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, ResVT, Vec);
+ }
+
+ return SDValue();
+}
+
+SDValue
HexagonTargetLowering::LowerEXTRACT_VECTOR(SDValue Op,
SelectionDAG &DAG) const {
+ // If we are dealing with EXTRACT_SUBVECTOR on a HVX type, we may
+ // be able to simplify it to an EXTRACT_SUBREG.
+ if (Op.getOpcode() == ISD::EXTRACT_SUBVECTOR && Subtarget.useHVXOps() &&
+ isHvxVectorType(Op.getValueType().getSimpleVT()))
+ return LowerEXTRACT_SUBVECTOR_HVX(Op, DAG);
+
EVT VT = Op.getValueType();
int VTN = VT.isVector() ? VT.getVectorNumElements() : 1;
SDLoc dl(Op);
@@ -2607,27 +2789,28 @@ HexagonTargetLowering::LowerEXTRACT_VECTOR(SDValue Op,
if (W == 32) {
// Translate this node into EXTRACT_SUBREG.
- unsigned Subreg = (X == 0) ? Hexagon::subreg_loreg : 0;
+ unsigned Subreg = (X == 0) ? Hexagon::isub_lo : 0;
if (X == 0)
- Subreg = Hexagon::subreg_loreg;
+ Subreg = Hexagon::isub_lo;
else if (SVT == MVT::v2i32 && X == 1)
- Subreg = Hexagon::subreg_hireg;
+ Subreg = Hexagon::isub_hi;
else if (SVT == MVT::v4i16 && X == 2)
- Subreg = Hexagon::subreg_hireg;
+ Subreg = Hexagon::isub_hi;
else if (SVT == MVT::v8i8 && X == 4)
- Subreg = Hexagon::subreg_hireg;
+ Subreg = Hexagon::isub_hi;
else
llvm_unreachable("Bad offset");
N = DAG.getTargetExtractSubreg(Subreg, dl, MVT::i32, Vec);
- } else if (VecVT.getSizeInBits() == 32) {
+ } else if (SVT.getSizeInBits() == 32) {
N = DAG.getNode(HexagonISD::EXTRACTU, dl, MVT::i32, Ops);
- } else {
+ } else if (SVT.getSizeInBits() == 64) {
N = DAG.getNode(HexagonISD::EXTRACTU, dl, MVT::i64, Ops);
if (VT.getSizeInBits() == 32)
- N = DAG.getTargetExtractSubreg(Hexagon::subreg_loreg, dl, MVT::i32, N);
- }
+ N = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, N);
+ } else
+ return SDValue();
return DAG.getNode(ISD::BITCAST, dl, VT, N);
}
@@ -2647,7 +2830,7 @@ HexagonTargetLowering::LowerEXTRACT_VECTOR(SDValue Op,
} else {
N = DAG.getNode(HexagonISD::EXTRACTURP, dl, MVT::i64, Ops);
if (VT.getSizeInBits() == 32)
- N = DAG.getTargetExtractSubreg(Hexagon::subreg_loreg, dl, MVT::i32, N);
+ N = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, N);
}
return DAG.getNode(ISD::BITCAST, dl, VT, N);
}
@@ -2674,8 +2857,10 @@ HexagonTargetLowering::LowerINSERT_VECTOR(SDValue Op,
SDValue N;
if (VT.getSizeInBits() == 32)
N = DAG.getNode(HexagonISD::INSERT, dl, MVT::i32, Ops);
- else
+ else if (VT.getSizeInBits() == 64)
N = DAG.getNode(HexagonISD::INSERT, dl, MVT::i64, Ops);
+ else
+ return SDValue();
return DAG.getNode(ISD::BITCAST, dl, VT, N);
}
@@ -2687,8 +2872,7 @@ HexagonTargetLowering::LowerINSERT_VECTOR(SDValue Op,
DAG.getConstant(32, dl, MVT::i64));
SDValue Combined = DAG.getNode(ISD::OR, dl, MVT::i64, Shifted, Offset);
- if (VT.getSizeInBits() == 64 &&
- Val.getValueType().getSizeInBits() == 32) {
+ if (VT.getSizeInBits() == 64 && Val.getValueSizeInBits() == 32) {
SDValue C = DAG.getConstant(0, dl, MVT::i32);
Val = DAG.getNode(HexagonISD::COMBINE, dl, VT, C, Val);
}
@@ -2698,8 +2882,10 @@ HexagonTargetLowering::LowerINSERT_VECTOR(SDValue Op,
SDValue N;
if (VT.getSizeInBits() == 32)
N = DAG.getNode(HexagonISD::INSERTRP, dl, MVT::i32, Ops);
- else
+ else if (VT.getSizeInBits() == 64)
N = DAG.getNode(HexagonISD::INSERTRP, dl, MVT::i64, Ops);
+ else
+ return SDValue();
return DAG.getNode(ISD::BITCAST, dl, VT, N);
}
@@ -2800,20 +2986,6 @@ HexagonTargetLowering::getPICJumpTableRelocBase(SDValue Table,
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Table), VT, T);
}
-MachineBasicBlock *HexagonTargetLowering::EmitInstrWithCustomInserter(
- MachineInstr &MI, MachineBasicBlock *BB) const {
- switch (MI.getOpcode()) {
- case Hexagon::ALLOCA: {
- MachineFunction *MF = BB->getParent();
- auto *FuncInfo = MF->getInfo<HexagonMachineFunctionInfo>();
- FuncInfo->addAllocaAdjustInst(&MI);
- return BB;
- }
- default:
- llvm_unreachable("Unexpected instr type to insert");
- } // switch
-}
-
//===----------------------------------------------------------------------===//
// Inline Assembly Support
//===----------------------------------------------------------------------===//
@@ -2832,7 +3004,7 @@ HexagonTargetLowering::getConstraintType(StringRef Constraint) const {
return TargetLowering::getConstraintType(Constraint);
}
-std::pair<unsigned, const TargetRegisterClass *>
+std::pair<unsigned, const TargetRegisterClass*>
HexagonTargetLowering::getRegForInlineAsmConstraint(
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
bool UseHVX = Subtarget.useHVXOps(), UseHVXDbl = Subtarget.useHVXDblOps();
@@ -2840,53 +3012,53 @@ HexagonTargetLowering::getRegForInlineAsmConstraint(
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'r': // R0-R31
- switch (VT.SimpleTy) {
- default:
- llvm_unreachable("getRegForInlineAsmConstraint Unhandled data type");
- case MVT::i32:
- case MVT::i16:
- case MVT::i8:
- case MVT::f32:
- return std::make_pair(0U, &Hexagon::IntRegsRegClass);
- case MVT::i64:
- case MVT::f64:
- return std::make_pair(0U, &Hexagon::DoubleRegsRegClass);
+ switch (VT.SimpleTy) {
+ default:
+ llvm_unreachable("getRegForInlineAsmConstraint Unhandled data type");
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ case MVT::i32:
+ case MVT::f32:
+ return std::make_pair(0U, &Hexagon::IntRegsRegClass);
+ case MVT::i64:
+ case MVT::f64:
+ return std::make_pair(0U, &Hexagon::DoubleRegsRegClass);
}
case 'q': // q0-q3
- switch (VT.SimpleTy) {
- default:
- llvm_unreachable("getRegForInlineAsmConstraint Unhandled data type");
- case MVT::v1024i1:
- case MVT::v512i1:
- case MVT::v32i16:
- case MVT::v16i32:
- case MVT::v64i8:
- case MVT::v8i64:
- return std::make_pair(0U, &Hexagon::VecPredRegsRegClass);
- }
+ switch (VT.SimpleTy) {
+ default:
+ llvm_unreachable("getRegForInlineAsmConstraint Unhandled data type");
+ case MVT::v1024i1:
+ case MVT::v512i1:
+ case MVT::v32i16:
+ case MVT::v16i32:
+ case MVT::v64i8:
+ case MVT::v8i64:
+ return std::make_pair(0U, &Hexagon::VecPredRegsRegClass);
+ }
case 'v': // V0-V31
- switch (VT.SimpleTy) {
- default:
- llvm_unreachable("getRegForInlineAsmConstraint Unhandled data type");
- case MVT::v16i32:
- case MVT::v32i16:
- case MVT::v64i8:
- case MVT::v8i64:
- return std::make_pair(0U, &Hexagon::VectorRegsRegClass);
- case MVT::v32i32:
- case MVT::v64i16:
- case MVT::v16i64:
- case MVT::v128i8:
- if (Subtarget.hasV60TOps() && UseHVX && UseHVXDbl)
- return std::make_pair(0U, &Hexagon::VectorRegs128BRegClass);
- else
- return std::make_pair(0U, &Hexagon::VecDblRegsRegClass);
- case MVT::v256i8:
- case MVT::v128i16:
- case MVT::v64i32:
- case MVT::v32i64:
- return std::make_pair(0U, &Hexagon::VecDblRegs128BRegClass);
- }
+ switch (VT.SimpleTy) {
+ default:
+ llvm_unreachable("getRegForInlineAsmConstraint Unhandled data type");
+ case MVT::v16i32:
+ case MVT::v32i16:
+ case MVT::v64i8:
+ case MVT::v8i64:
+ return std::make_pair(0U, &Hexagon::VectorRegsRegClass);
+ case MVT::v32i32:
+ case MVT::v64i16:
+ case MVT::v16i64:
+ case MVT::v128i8:
+ if (Subtarget.hasV60TOps() && UseHVX && UseHVXDbl)
+ return std::make_pair(0U, &Hexagon::VectorRegs128BRegClass);
+ return std::make_pair(0U, &Hexagon::VecDblRegsRegClass);
+ case MVT::v256i8:
+ case MVT::v128i16:
+ case MVT::v64i32:
+ case MVT::v32i64:
+ return std::make_pair(0U, &Hexagon::VecDblRegs128BRegClass);
+ }
default:
llvm_unreachable("Unknown asm register class");
@@ -2908,16 +3080,30 @@ bool HexagonTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
bool HexagonTargetLowering::isLegalAddressingMode(const DataLayout &DL,
const AddrMode &AM, Type *Ty,
unsigned AS) const {
- // Allows a signed-extended 11-bit immediate field.
- if (AM.BaseOffs <= -(1LL << 13) || AM.BaseOffs >= (1LL << 13)-1)
- return false;
+ if (Ty->isSized()) {
+ // When LSR detects uses of the same base address to access different
+ // types (e.g. unions), it will assume a conservative type for these
+ // uses:
+ // LSR Use: Kind=Address of void in addrspace(4294967295), ...
+ // The type Ty passed here would then be "void". Skip the alignment
+ // checks, but do not return false right away, since that confuses
+ // LSR into crashing.
+ unsigned A = DL.getABITypeAlignment(Ty);
+ // The base offset must be a multiple of the alignment.
+ if ((AM.BaseOffs % A) != 0)
+ return false;
+ // The shifted offset must fit in 11 bits.
+ if (!isInt<11>(AM.BaseOffs >> Log2_32(A)))
+ return false;
+ }
// No global is ever allowed as a base.
if (AM.BaseGV)
return false;
int Scale = AM.Scale;
- if (Scale < 0) Scale = -Scale;
+ if (Scale < 0)
+ Scale = -Scale;
switch (Scale) {
case 0: // No scale reg, "r+i", "r", or just "i".
break;
@@ -2934,7 +3120,6 @@ bool HexagonTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA)
return HTM.getRelocationModel() == Reloc::Static;
}
-
/// isLegalICmpImmediate - Return true if the specified immediate is legal
/// icmp immediate, that is the target has icmp instructions which can compare
/// a register against the immediate without having to materialize the
@@ -2966,14 +3151,20 @@ bool HexagonTargetLowering::IsEligibleForTailCallOptimization(
// ***************************************************************************
// If this is a tail call via a function pointer, then don't do it!
- if (!(isa<GlobalAddressSDNode>(Callee)) &&
- !(isa<ExternalSymbolSDNode>(Callee))) {
+ if (!isa<GlobalAddressSDNode>(Callee) &&
+ !isa<ExternalSymbolSDNode>(Callee)) {
return false;
}
- // Do not optimize if the calling conventions do not match.
- if (!CCMatch)
- return false;
+ // Do not optimize if the calling conventions do not match and the conventions
+ // used are not C or Fast.
+ if (!CCMatch) {
+ bool R = (CallerCC == CallingConv::C || CallerCC == CallingConv::Fast);
+ bool E = (CalleeCC == CallingConv::C || CalleeCC == CallingConv::Fast);
+ // If R & E, then ok.
+ if (!R || !E)
+ return false;
+ }
// Do not tail call optimize vararg calls.
if (isVarArg)
@@ -2991,18 +3182,33 @@ bool HexagonTargetLowering::IsEligibleForTailCallOptimization(
return true;
}
-// Return true when the given node fits in a positive half word.
-bool llvm::isPositiveHalfWord(SDNode *N) {
- ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N);
- if (CN && CN->getSExtValue() > 0 && isInt<16>(CN->getSExtValue()))
- return true;
+/// Returns the target specific optimal type for load and store operations as
+/// a result of memset, memcpy, and memmove lowering.
+///
+/// If DstAlign is zero that means it's safe to destination alignment can
+/// satisfy any constraint. Similarly if SrcAlign is zero it means there isn't
+/// a need to check it against alignment requirement, probably because the
+/// source does not need to be loaded. If 'IsMemset' is true, that means it's
+/// expanding a memset. If 'ZeroMemset' is true, that means it's a memset of
+/// zero. 'MemcpyStrSrc' indicates whether the memcpy source is constant so it
+/// does not need to be loaded. It returns EVT::Other if the type should be
+/// determined using generic target-independent logic.
+EVT HexagonTargetLowering::getOptimalMemOpType(uint64_t Size,
+ unsigned DstAlign, unsigned SrcAlign, bool IsMemset, bool ZeroMemset,
+ bool MemcpyStrSrc, MachineFunction &MF) const {
+
+ auto Aligned = [](unsigned GivenA, unsigned MinA) -> bool {
+ return (GivenA % MinA) == 0;
+ };
- switch (N->getOpcode()) {
- default:
- return false;
- case ISD::SIGN_EXTEND_INREG:
- return true;
- }
+ if (Size >= 8 && Aligned(DstAlign, 8) && (IsMemset || Aligned(SrcAlign, 8)))
+ return MVT::i64;
+ if (Size >= 4 && Aligned(DstAlign, 4) && (IsMemset || Aligned(SrcAlign, 4)))
+ return MVT::i32;
+ if (Size >= 2 && Aligned(DstAlign, 2) && (IsMemset || Aligned(SrcAlign, 2)))
+ return MVT::i16;
+
+ return MVT::Other;
}
bool HexagonTargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
@@ -3030,7 +3236,6 @@ bool HexagonTargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
return false;
}
-
std::pair<const TargetRegisterClass*, uint8_t>
HexagonTargetLowering::findRepresentativeClass(const TargetRegisterInfo *TRI,
MVT VT) const {
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index 71f6734..a8ed29e 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -16,30 +16,33 @@
#define LLVM_LIB_TARGET_HEXAGON_HEXAGONISELLOWERING_H
#include "Hexagon.h"
-#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/ISDOpcodes.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/CodeGen/SelectionDAGNodes.h"
+#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/InlineAsm.h"
#include "llvm/Target/TargetLowering.h"
+#include <cstdint>
+#include <utility>
namespace llvm {
-// Return true when the given node fits in a positive half word.
-bool isPositiveHalfWord(SDNode *N);
+namespace HexagonISD {
- namespace HexagonISD {
enum NodeType : unsigned {
OP_BEGIN = ISD::BUILTIN_OP_END,
CONST32 = OP_BEGIN,
CONST32_GP, // For marking data present in GP.
- FCONST32,
ALLOCA,
- ARGEXTEND,
AT_GOT, // Index in GOT.
AT_PCREL, // Offset relative to PC.
- CALLv3, // A V3+ call instruction.
- CALLv3nr, // A V3+ call instruction that doesn't return.
+ CALL, // Function call.
+ CALLnr, // Function call that does not return.
CALLR,
RET_FLAG, // Return with a flag operand.
@@ -79,24 +82,26 @@ bool isPositiveHalfWord(SDNode *N);
EXTRACTU,
EXTRACTURP,
VCOMBINE,
+ VPACK,
TC_RETURN,
EH_RETURN,
DCFETCH,
OP_END
};
- }
+
+} // end namespace HexagonISD
class HexagonSubtarget;
class HexagonTargetLowering : public TargetLowering {
int VarArgsFrameOffset; // Frame offset to start of varargs area.
+ const HexagonTargetMachine &HTM;
+ const HexagonSubtarget &Subtarget;
bool CanReturnSmallStruct(const Function* CalleeFn, unsigned& RetSize)
const;
void promoteLdStType(MVT VT, MVT PromotedLdStVT);
- const HexagonTargetMachine &HTM;
- const HexagonSubtarget &Subtarget;
public:
explicit HexagonTargetLowering(const TargetMachine &TM,
@@ -116,15 +121,27 @@ bool isPositiveHalfWord(SDNode *N);
bool allowTruncateForTailCall(Type *Ty1, Type *Ty2) const override;
+ /// Return true if an FMA operation is faster than a pair of mul and add
+ /// instructions. fmuladd intrinsics will be expanded to FMAs when this
+ /// method returns true (and FMAs are legal), otherwise fmuladd is
+ /// expanded to mul + add.
+ bool isFMAFasterThanFMulAndFAdd(EVT) const override;
+
// Should we expand the build vector with shuffles?
bool shouldExpandBuildVectorWithShuffles(EVT VT,
unsigned DefinedValues) const override;
+ bool isShuffleMaskLegal(const SmallVectorImpl<int> &Mask, EVT VT)
+ const override;
+
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
const char *getTargetNodeName(unsigned Opcode) const override;
SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEXTRACT_VECTOR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerEXTRACT_SUBVECTOR_HVX(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINSERT_VECTOR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerVECTOR_SHIFT(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const;
@@ -174,9 +191,6 @@ bool isPositiveHalfWord(SDNode *N);
const SDLoc &dl, SelectionDAG &DAG) const override;
bool mayBeEmittedAsTailCall(CallInst *CI) const override;
- MachineBasicBlock *
- EmitInstrWithCustomInserter(MachineInstr &MI,
- MachineBasicBlock *BB) const override;
/// If a physical register, this returns the register that receives the
/// exception address on entry to an EH pad.
@@ -195,6 +209,7 @@ bool isPositiveHalfWord(SDNode *N);
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
+
EVT getSetCCResultType(const DataLayout &, LLVMContext &C,
EVT VT) const override {
if (!VT.isVector())
@@ -243,6 +258,10 @@ bool isPositiveHalfWord(SDNode *N);
/// the immediate into a register.
bool isLegalICmpImmediate(int64_t Imm) const override;
+ EVT getOptimalMemOpType(uint64_t Size, unsigned DstAlign,
+ unsigned SrcAlign, bool IsMemset, bool ZeroMemset, bool MemcpyStrSrc,
+ MachineFunction &MF) const override;
+
bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AddrSpace,
unsigned Align, bool *Fast) const override;
@@ -269,6 +288,7 @@ bool isPositiveHalfWord(SDNode *N);
findRepresentativeClass(const TargetRegisterInfo *TRI, MVT VT)
const override;
};
+
} // end namespace llvm
-#endif // Hexagon_ISELLOWERING_H
+#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONISELLOWERING_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrAlias.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrAlias.td
index 9cbeae7..7283d94 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrAlias.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrAlias.td
@@ -63,34 +63,34 @@ def : InstAlias<"memw($Rs) = $Rt.new",
(S2_storerinew_io IntRegs:$Rs, 0, IntRegs:$Rt), 0>;
def : InstAlias<"memb($Rs) = #$S8",
- (S4_storeirb_io IntRegs:$Rs, 0, s8Ext:$S8), 0>;
+ (S4_storeirb_io IntRegs:$Rs, 0, s8_0Ext:$S8), 0>;
def : InstAlias<"memh($Rs) = #$S8",
- (S4_storeirh_io IntRegs:$Rs, 0, s8Ext:$S8), 0>;
+ (S4_storeirh_io IntRegs:$Rs, 0, s8_0Ext:$S8), 0>;
def : InstAlias<"memw($Rs) = #$S8",
- (S4_storeiri_io IntRegs:$Rs, 0, s8Ext:$S8), 0>;
+ (S4_storeiri_io IntRegs:$Rs, 0, s8_0Ext:$S8), 0>;
def : InstAlias<"memd($Rs) = $Rtt",
(S2_storerd_io IntRegs:$Rs, 0, DoubleRegs:$Rtt), 0>;
def : InstAlias<"memb($Rs) = setbit(#$U5)",
- (L4_ior_memopb_io IntRegs:$Rs, 0, u5Imm:$U5), 0>;
+ (L4_ior_memopb_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>;
def : InstAlias<"memh($Rs) = setbit(#$U5)",
- (L4_ior_memoph_io IntRegs:$Rs, 0, u5Imm:$U5), 0>;
+ (L4_ior_memoph_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>;
def : InstAlias<"memw($Rs) = setbit(#$U5)",
- (L4_ior_memopw_io IntRegs:$Rs, 0, u5Imm:$U5), 0>;
+ (L4_ior_memopw_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>;
def : InstAlias<"memb($Rs) = clrbit(#$U5)",
- (L4_iand_memopb_io IntRegs:$Rs, 0, u5Imm:$U5), 0>;
+ (L4_iand_memopb_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>;
def : InstAlias<"memh($Rs) = clrbit(#$U5)",
- (L4_iand_memoph_io IntRegs:$Rs, 0, u5Imm:$U5), 0>;
+ (L4_iand_memoph_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>;
def : InstAlias<"memw($Rs) = clrbit(#$U5)",
- (L4_iand_memopw_io IntRegs:$Rs, 0, u5Imm:$U5), 0>;
+ (L4_iand_memopw_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>;
// Alias of: $Rd = memXX($Rs+#XX) to $Rd = memXX($Rs)
def : InstAlias<"$Rd = memb($Rs)",
@@ -241,40 +241,40 @@ def : InstAlias<"if (!$Pt.new) memw($Rs) = $Rt.new",
(S4_pstorerinewfnew_io PredRegs:$Pt, IntRegs:$Rs, 0, IntRegs:$Rt), 0>;
def : InstAlias<"if ($Pt) memb($Rs) = #$S6",
- (S4_storeirbt_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirbt_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if ($Pt) memh($Rs) = #$S6",
- (S4_storeirht_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirht_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if ($Pt) memw($Rs) = #$S6",
- (S4_storeirit_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirit_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if ($Pt.new) memb($Rs) = #$S6",
- (S4_storeirbtnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirbtnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if ($Pt.new) memh($Rs) = #$S6",
- (S4_storeirhtnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirhtnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if ($Pt.new) memw($Rs) = #$S6",
- (S4_storeiritnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeiritnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if (!$Pt) memb($Rs) = #$S6",
- (S4_storeirbf_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirbf_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if (!$Pt) memh($Rs) = #$S6",
- (S4_storeirhf_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirhf_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if (!$Pt) memw($Rs) = #$S6",
- (S4_storeirif_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirif_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if (!$Pt.new) memb($Rs) = #$S6",
- (S4_storeirbfnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirbfnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if (!$Pt.new) memh($Rs) = #$S6",
- (S4_storeirhfnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirhfnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
def : InstAlias<"if (!$Pt.new) memw($Rs) = #$S6",
- (S4_storeirifnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6Ext:$S6), 0>;
+ (S4_storeirifnew_io PredRegs:$Pt, IntRegs:$Rs, 0, s6_0Ext:$S6), 0>;
// Alias of: memXX($Rs + $u6_X) |= $Rt, also &=, +=, -=
// to: memXX($Rs) |= $Rt
@@ -295,11 +295,11 @@ def : InstAlias<"memb($Rs) -= $Rt",
Requires<[UseMEMOP]>;
def : InstAlias<"memb($Rs) += #$U5",
- (L4_iadd_memopb_io IntRegs:$Rs, 0, u5Imm:$U5), 0>,
+ (L4_iadd_memopb_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>,
Requires<[UseMEMOP]>;
def : InstAlias<"memb($Rs) -= #$U5",
- (L4_isub_memopb_io IntRegs:$Rs, 0, u5Imm:$U5), 0>,
+ (L4_isub_memopb_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>,
Requires<[UseMEMOP]>;
def : InstAlias<"memh($Rs) &= $Rt",
@@ -319,11 +319,11 @@ def : InstAlias<"memh($Rs) -= $Rt",
Requires<[UseMEMOP]>;
def : InstAlias<"memh($Rs) += #$U5",
- (L4_iadd_memoph_io IntRegs:$Rs, 0, u5Imm:$U5), 0>,
+ (L4_iadd_memoph_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>,
Requires<[UseMEMOP]>;
def : InstAlias<"memh($Rs) -= #$U5",
- (L4_isub_memoph_io IntRegs:$Rs, 0, u5Imm:$U5), 0>,
+ (L4_isub_memoph_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>,
Requires<[UseMEMOP]>;
def : InstAlias<"memw($Rs) &= $Rt",
@@ -343,11 +343,11 @@ def : InstAlias<"memw($Rs) -= $Rt",
Requires<[UseMEMOP]>;
def : InstAlias<"memw($Rs) += #$U5",
- (L4_iadd_memopw_io IntRegs:$Rs, 0, u5Imm:$U5), 0>,
+ (L4_iadd_memopw_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>,
Requires<[UseMEMOP]>;
def : InstAlias<"memw($Rs) -= #$U5",
- (L4_isub_memopw_io IntRegs:$Rs, 0, u5Imm:$U5), 0>,
+ (L4_isub_memopw_io IntRegs:$Rs, 0, u5_0Imm:$U5), 0>,
Requires<[UseMEMOP]>;
//
@@ -492,12 +492,10 @@ def : InstAlias<"if ($src1) jumpr $src2",
def : InstAlias<"if (!$src1) jumpr $src2",
(J2_jumprf PredRegs:$src1, IntRegs:$src2), 0>;
-// V6_vassignp: Vector assign mapping.
-let hasNewValue = 1, opNewValue = 0, isAsmParserOnly = 1 in
-def HEXAGON_V6_vassignpair: CVI_VA_DV_Resource <
- (outs VecDblRegs:$Vdd),
- (ins VecDblRegs:$Vss),
- "$Vdd = $Vss">;
+// maps Vdd = Vss to Vdd = V6_vassignp(Vss)
+def : InstAlias<"$Vdd = $Vss",
+ (V6_vassignp VecDblRegs:$Vdd, VecDblRegs:$Vss)>,
+ Requires<[HasV60T]>;
// maps Vd = #0 to Vd = vxor(Vd, Vd)
def : InstAlias<"$Vd = #0",
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormats.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormats.td
index 0bfb044..fa3cccb 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormats.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormats.td
@@ -54,7 +54,7 @@ class MemAccessSize<bits<4> value> {
bits<4> Value = value;
}
-def NoMemAccess : MemAccessSize<0>;// Not a memory acces instruction.
+def NoMemAccess : MemAccessSize<0>;// Not a memory access instruction.
def ByteAccess : MemAccessSize<1>;// Byte access instruction (memb).
def HalfWordAccess : MemAccessSize<2>;// Half word access instruction (memh).
def WordAccess : MemAccessSize<3>;// Word access instruction (memw).
@@ -179,6 +179,9 @@ class InstHexagon<dag outs, dag ins, string asmstr, list<dag> pattern,
bits<1> isAccumulator = 0;
let TSFlags{54} = isAccumulator;
+ bit cofMax1 = 0;
+ let TSFlags{60} = cofMax1;
+
// Fields used for relation models.
bit isNonTemporal = 0;
string isNT = ""; // set to "true" for non-temporal vector stores.
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV4.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV4.td
index e17f71f..493d047 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV4.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV4.td
@@ -17,7 +17,7 @@
// *** Must match BaseInfo.h ***
//----------------------------------------------------------------------------//
-def TypeMEMOP : IType<9>;
+def TypeV4LDST : IType<9>;
def TypeNV : IType<10>;
def TypeDUPLEX : IType<11>;
def TypeCOMPOUND : IType<12>;
@@ -132,7 +132,7 @@ class NCJInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
let mayLoad = 1, mayStore = 1 in
class MEMInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
string cstr = "", InstrItinClass itin = V4LDST_tc_st_SLOT0>
- : InstHexagon<outs, ins, asmstr, pattern, cstr, itin, TypeMEMOP>,
+ : InstHexagon<outs, ins, asmstr, pattern, cstr, itin, TypeV4LDST>,
OpcodeHexagon;
class MEMInst_V4<dag outs, dag ins, string asmstr, list<dag> pattern = [],
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV60.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV60.td
index f3d43de..b9f4373 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV60.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrFormatsV60.td
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
//----------------------------------------------------------------------------//
-// Hexagon Intruction Flags +
+// Hexagon Instruction Flags +
//
// *** Must match BaseInfo.h ***
//----------------------------------------------------------------------------//
@@ -34,7 +34,7 @@ def TypeCVI_VM_NEW_ST : IType<26>;
def TypeCVI_VM_STU : IType<27>;
def TypeCVI_HIST : IType<28>;
//----------------------------------------------------------------------------//
-// Intruction Classes Definitions +
+// Instruction Classes Definitions +
//----------------------------------------------------------------------------//
let validSubTargets = HasV60SubT in
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
index fe9f97d..0a7dc6b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
@@ -11,24 +11,45 @@
//
//===----------------------------------------------------------------------===//
-#include "HexagonInstrInfo.h"
#include "Hexagon.h"
+#include "HexagonHazardRecognizer.h"
+#include "HexagonInstrInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DFAPacketizer.h"
+#include "llvm/CodeGen/LivePhysRegs.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineInstrBundle.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/PseudoSourceValue.h"
+#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/BranchProbability.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
+#include <cassert>
#include <cctype>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
using namespace llvm;
@@ -39,8 +60,6 @@ using namespace llvm;
#include "HexagonGenInstrInfo.inc"
#include "HexagonGenDFAPacketizer.inc"
-using namespace llvm;
-
cl::opt<bool> ScheduleInlineAsm("hexagon-sched-inline-asm", cl::Hidden,
cl::init(false), cl::desc("Do not consider inline-asm a scheduling/"
"packetization boundary."));
@@ -67,6 +86,10 @@ static cl::opt<bool> EnableACCForwarding(
static cl::opt<bool> BranchRelaxAsmLarge("branch-relax-asm-large",
cl::init(true), cl::Hidden, cl::ZeroOrMore, cl::desc("branch relax asm"));
+static cl::opt<bool> UseDFAHazardRec("dfa-hazard-rec",
+ cl::init(true), cl::Hidden, cl::ZeroOrMore,
+ cl::desc("Use the DFA based hazard recognizer."));
+
///
/// Constants for Hexagon instructions.
///
@@ -104,19 +127,16 @@ HexagonInstrInfo::HexagonInstrInfo(HexagonSubtarget &ST)
: HexagonGenInstrInfo(Hexagon::ADJCALLSTACKDOWN, Hexagon::ADJCALLSTACKUP),
RI() {}
-
static bool isIntRegForSubInst(unsigned Reg) {
return (Reg >= Hexagon::R0 && Reg <= Hexagon::R7) ||
(Reg >= Hexagon::R16 && Reg <= Hexagon::R23);
}
-
static bool isDblRegForSubInst(unsigned Reg, const HexagonRegisterInfo &HRI) {
- return isIntRegForSubInst(HRI.getSubReg(Reg, Hexagon::subreg_loreg)) &&
- isIntRegForSubInst(HRI.getSubReg(Reg, Hexagon::subreg_hireg));
+ return isIntRegForSubInst(HRI.getSubReg(Reg, Hexagon::isub_lo)) &&
+ isIntRegForSubInst(HRI.getSubReg(Reg, Hexagon::isub_hi));
}
-
/// Calculate number of instructions excluding the debug instructions.
static unsigned nonDbgMICount(MachineBasicBlock::const_instr_iterator MIB,
MachineBasicBlock::const_instr_iterator MIE) {
@@ -128,7 +148,6 @@ static unsigned nonDbgMICount(MachineBasicBlock::const_instr_iterator MIB,
return Count;
}
-
/// Find the hardware loop instruction used to set-up the specified loop.
/// On Hexagon, we have two instructions used to set-up the hardware loop
/// (LOOP0, LOOP1) with corresponding endloop (ENDLOOP0, ENDLOOP1) instructions
@@ -160,27 +179,26 @@ static MachineInstr *findLoopInstr(MachineBasicBlock *BB, int EndLoopOp,
return &*I;
// We've reached a different loop, which means the loop0 has been removed.
if (Opc == EndLoopOp)
- return 0;
+ return nullptr;
}
// Check the predecessors for the LOOP instruction.
MachineInstr *loop = findLoopInstr(*PB, EndLoopOp, Visited);
if (loop)
return loop;
}
- return 0;
+ return nullptr;
}
-
/// Gather register def/uses from MI.
/// This treats possible (predicated) defs as actually happening ones
/// (conservatively).
-static inline void parseOperands(const MachineInstr *MI,
+static inline void parseOperands(const MachineInstr &MI,
SmallVector<unsigned, 4> &Defs, SmallVector<unsigned, 8> &Uses) {
Defs.clear();
Uses.clear();
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
+ for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg())
continue;
@@ -197,7 +215,6 @@ static inline void parseOperands(const MachineInstr *MI,
}
}
-
// Position dependent, so check twice for swap.
static bool isDuplexPairMatch(unsigned Ga, unsigned Gb) {
switch (Ga) {
@@ -224,8 +241,6 @@ static bool isDuplexPairMatch(unsigned Ga, unsigned Gb) {
return false;
}
-
-
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
@@ -236,10 +251,6 @@ unsigned HexagonInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
switch (MI.getOpcode()) {
default:
break;
- case Hexagon::L2_loadrb_io:
- case Hexagon::L2_loadrub_io:
- case Hexagon::L2_loadrh_io:
- case Hexagon::L2_loadruh_io:
case Hexagon::L2_loadri_io:
case Hexagon::L2_loadrd_io:
case Hexagon::V6_vL32b_ai:
@@ -248,14 +259,10 @@ unsigned HexagonInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
case Hexagon::V6_vL32Ub_ai_128B:
case Hexagon::LDriw_pred:
case Hexagon::LDriw_mod:
- case Hexagon::LDriq_pred_V6:
- case Hexagon::LDriq_pred_vec_V6:
- case Hexagon::LDriv_pseudo_V6:
- case Hexagon::LDrivv_pseudo_V6:
- case Hexagon::LDriq_pred_V6_128B:
- case Hexagon::LDriq_pred_vec_V6_128B:
- case Hexagon::LDriv_pseudo_V6_128B:
- case Hexagon::LDrivv_pseudo_V6_128B: {
+ case Hexagon::PS_vloadrq_ai:
+ case Hexagon::PS_vloadrw_ai:
+ case Hexagon::PS_vloadrq_ai_128B:
+ case Hexagon::PS_vloadrw_ai_128B: {
const MachineOperand OpFI = MI.getOperand(1);
if (!OpFI.isFI())
return 0;
@@ -266,14 +273,6 @@ unsigned HexagonInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
return MI.getOperand(0).getReg();
}
- case Hexagon::L2_ploadrbt_io:
- case Hexagon::L2_ploadrbf_io:
- case Hexagon::L2_ploadrubt_io:
- case Hexagon::L2_ploadrubf_io:
- case Hexagon::L2_ploadrht_io:
- case Hexagon::L2_ploadrhf_io:
- case Hexagon::L2_ploadruht_io:
- case Hexagon::L2_ploadruhf_io:
case Hexagon::L2_ploadrit_io:
case Hexagon::L2_ploadrif_io:
case Hexagon::L2_ploadrdt_io:
@@ -292,7 +291,6 @@ unsigned HexagonInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
return 0;
}
-
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
@@ -313,14 +311,10 @@ unsigned HexagonInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
case Hexagon::V6_vS32Ub_ai_128B:
case Hexagon::STriw_pred:
case Hexagon::STriw_mod:
- case Hexagon::STriq_pred_V6:
- case Hexagon::STriq_pred_vec_V6:
- case Hexagon::STriv_pseudo_V6:
- case Hexagon::STrivv_pseudo_V6:
- case Hexagon::STriq_pred_V6_128B:
- case Hexagon::STriq_pred_vec_V6_128B:
- case Hexagon::STriv_pseudo_V6_128B:
- case Hexagon::STrivv_pseudo_V6_128B: {
+ case Hexagon::PS_vstorerq_ai:
+ case Hexagon::PS_vstorerw_ai:
+ case Hexagon::PS_vstorerq_ai_128B:
+ case Hexagon::PS_vstorerw_ai_128B: {
const MachineOperand &OpFI = MI.getOperand(0);
if (!OpFI.isFI())
return 0;
@@ -353,7 +347,6 @@ unsigned HexagonInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
return 0;
}
-
/// This function can analyze one/two way branching only and should (mostly) be
/// called by target independent side.
/// First entry is always the opcode of the branching instruction, except when
@@ -417,7 +410,7 @@ bool HexagonInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
// Delete the J2_jump if it's equivalent to a fall-through.
if (AllowModify && JumpToBlock &&
MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
- DEBUG(dbgs()<< "\nErasing the jump to successor block\n";);
+ DEBUG(dbgs() << "\nErasing the jump to successor block\n";);
I->eraseFromParent();
I = MBB.instr_end();
if (I == MBB.instr_begin())
@@ -431,7 +424,7 @@ bool HexagonInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineInstr *LastInst = &*I;
MachineInstr *SecondLastInst = nullptr;
// Find one more terminator if present.
- for (;;) {
+ while (true) {
if (&*I != LastInst && !I->isBundle() && isUnpredicatedTerminator(*I)) {
if (!SecondLastInst)
SecondLastInst = &*I;
@@ -455,7 +448,7 @@ bool HexagonInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
bool LastOpcodeHasJMP_c = PredOpcodeHasJMP_c(LastOpcode);
- bool LastOpcodeHasNVJump = isNewValueJump(LastInst);
+ bool LastOpcodeHasNVJump = isNewValueJump(*LastInst);
if (LastOpcodeHasJMP_c && !LastInst->getOperand(1).isMBB())
return true;
@@ -493,7 +486,7 @@ bool HexagonInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
}
bool SecLastOpcodeHasJMP_c = PredOpcodeHasJMP_c(SecLastOpcode);
- bool SecLastOpcodeHasNVJump = isNewValueJump(SecondLastInst);
+ bool SecLastOpcodeHasNVJump = isNewValueJump(*SecondLastInst);
if (SecLastOpcodeHasJMP_c && (LastOpcode == Hexagon::J2_jump)) {
if (!SecondLastInst->getOperand(1).isMBB())
return true;
@@ -540,8 +533,10 @@ bool HexagonInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}
+unsigned HexagonInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
-unsigned HexagonInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
DEBUG(dbgs() << "\nRemoving branches out of BB#" << MBB.getNumber());
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
@@ -561,17 +556,19 @@ unsigned HexagonInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return Count;
}
-unsigned HexagonInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned HexagonInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
unsigned BOpc = Hexagon::J2_jump;
unsigned BccOpc = Hexagon::J2_jumpt;
assert(validateBranchCond(Cond) && "Invalid branching condition");
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
+ assert(!BytesAdded && "code size not handled");
- // Check if ReverseBranchCondition has asked to reverse this branch
+ // Check if reverseBranchCondition has asked to reverse this branch
// If we want to reverse the branch an odd number of times, we want
// J2_jumpf.
if (!Cond.empty() && Cond[0].isImm())
@@ -587,13 +584,11 @@ unsigned HexagonInstrInfo::InsertBranch(MachineBasicBlock &MBB,
SmallVector<MachineOperand, 4> Cond;
auto Term = MBB.getFirstTerminator();
if (Term != MBB.end() && isPredicated(*Term) &&
- !analyzeBranch(MBB, NewTBB, NewFBB, Cond, false)) {
- MachineBasicBlock *NextBB = &*++MBB.getIterator();
- if (NewTBB == NextBB) {
- ReverseBranchCondition(Cond);
- RemoveBranch(MBB);
- return InsertBranch(MBB, TBB, nullptr, Cond, DL);
- }
+ !analyzeBranch(MBB, NewTBB, NewFBB, Cond, false) &&
+ MachineFunction::iterator(NewTBB) == ++MBB.getIterator()) {
+ reverseBranchCondition(Cond);
+ removeBranch(MBB);
+ return insertBranch(MBB, TBB, nullptr, Cond, DL);
}
BuildMI(&MBB, DL, get(BOpc)).addMBB(TBB);
} else if (isEndLoopN(Cond[0].getImm())) {
@@ -657,6 +652,85 @@ unsigned HexagonInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return 2;
}
+/// Analyze the loop code to find the loop induction variable and compare used
+/// to compute the number of iterations. Currently, we analyze loop that are
+/// controlled using hardware loops. In this case, the induction variable
+/// instruction is null. For all other cases, this function returns true, which
+/// means we're unable to analyze it.
+bool HexagonInstrInfo::analyzeLoop(MachineLoop &L,
+ MachineInstr *&IndVarInst,
+ MachineInstr *&CmpInst) const {
+
+ MachineBasicBlock *LoopEnd = L.getBottomBlock();
+ MachineBasicBlock::iterator I = LoopEnd->getFirstTerminator();
+ // We really "analyze" only hardware loops right now.
+ if (I != LoopEnd->end() && isEndLoopN(I->getOpcode())) {
+ IndVarInst = nullptr;
+ CmpInst = &*I;
+ return false;
+ }
+ return true;
+}
+
+/// Generate code to reduce the loop iteration by one and check if the loop is
+/// finished. Return the value/register of the new loop count. this function
+/// assumes the nth iteration is peeled first.
+unsigned HexagonInstrInfo::reduceLoopCount(MachineBasicBlock &MBB,
+ MachineInstr *IndVar, MachineInstr &Cmp,
+ SmallVectorImpl<MachineOperand> &Cond,
+ SmallVectorImpl<MachineInstr *> &PrevInsts,
+ unsigned Iter, unsigned MaxIter) const {
+ // We expect a hardware loop currently. This means that IndVar is set
+ // to null, and the compare is the ENDLOOP instruction.
+ assert((!IndVar) && isEndLoopN(Cmp.getOpcode())
+ && "Expecting a hardware loop");
+ MachineFunction *MF = MBB.getParent();
+ DebugLoc DL = Cmp.getDebugLoc();
+ SmallPtrSet<MachineBasicBlock *, 8> VisitedBBs;
+ MachineInstr *Loop = findLoopInstr(&MBB, Cmp.getOpcode(), VisitedBBs);
+ if (!Loop)
+ return 0;
+ // If the loop trip count is a compile-time value, then just change the
+ // value.
+ if (Loop->getOpcode() == Hexagon::J2_loop0i ||
+ Loop->getOpcode() == Hexagon::J2_loop1i) {
+ int64_t Offset = Loop->getOperand(1).getImm();
+ if (Offset <= 1)
+ Loop->eraseFromParent();
+ else
+ Loop->getOperand(1).setImm(Offset - 1);
+ return Offset - 1;
+ }
+ // The loop trip count is a run-time value. We generate code to subtract
+ // one from the trip count, and update the loop instruction.
+ assert(Loop->getOpcode() == Hexagon::J2_loop0r && "Unexpected instruction");
+ unsigned LoopCount = Loop->getOperand(1).getReg();
+ // Check if we're done with the loop.
+ unsigned LoopEnd = createVR(MF, MVT::i1);
+ MachineInstr *NewCmp = BuildMI(&MBB, DL, get(Hexagon::C2_cmpgtui), LoopEnd).
+ addReg(LoopCount).addImm(1);
+ unsigned NewLoopCount = createVR(MF, MVT::i32);
+ MachineInstr *NewAdd = BuildMI(&MBB, DL, get(Hexagon::A2_addi), NewLoopCount).
+ addReg(LoopCount).addImm(-1);
+ // Update the previously generated instructions with the new loop counter.
+ for (SmallVectorImpl<MachineInstr *>::iterator I = PrevInsts.begin(),
+ E = PrevInsts.end(); I != E; ++I)
+ (*I)->substituteRegister(LoopCount, NewLoopCount, 0, getRegisterInfo());
+ PrevInsts.clear();
+ PrevInsts.push_back(NewCmp);
+ PrevInsts.push_back(NewAdd);
+ // Insert the new loop instruction if this is the last time the loop is
+ // decremented.
+ if (Iter == MaxIter)
+ BuildMI(&MBB, DL, get(Hexagon::J2_loop0r)).
+ addMBB(Loop->getOperand(0).getMBB()).addReg(NewLoopCount);
+ // Delete the old loop instruction.
+ if (Iter == 0)
+ Loop->eraseFromParent();
+ Cond.push_back(MachineOperand::CreateImm(Hexagon::J2_jumpf));
+ Cond.push_back(NewCmp->getOperand(0));
+ return NewLoopCount;
+}
bool HexagonInstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB,
unsigned NumCycles, unsigned ExtraPredCycles,
@@ -664,7 +738,6 @@ bool HexagonInstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB,
return nonDbgBBSize(&MBB) <= 3;
}
-
bool HexagonInstrInfo::isProfitableToIfCvt(MachineBasicBlock &TMBB,
unsigned NumTCycles, unsigned ExtraTCycles, MachineBasicBlock &FMBB,
unsigned NumFCycles, unsigned ExtraFCycles, BranchProbability Probability)
@@ -672,7 +745,6 @@ bool HexagonInstrInfo::isProfitableToIfCvt(MachineBasicBlock &TMBB,
return nonDbgBBSize(&TMBB) <= 3 && nonDbgBBSize(&FMBB) <= 3;
}
-
bool HexagonInstrInfo::isProfitableToDupForIfCvt(MachineBasicBlock &MBB,
unsigned NumInstrs, BranchProbability Probability) const {
return NumInstrs <= 4;
@@ -743,9 +815,11 @@ void HexagonInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
return;
}
if (Hexagon::VecDblRegsRegClass.contains(SrcReg, DestReg)) {
+ unsigned LoSrc = HRI.getSubReg(SrcReg, Hexagon::vsub_lo);
+ unsigned HiSrc = HRI.getSubReg(SrcReg, Hexagon::vsub_hi);
BuildMI(MBB, I, DL, get(Hexagon::V6_vcombine), DestReg)
- .addReg(HRI.getSubReg(SrcReg, Hexagon::subreg_hireg), KillFlag)
- .addReg(HRI.getSubReg(SrcReg, Hexagon::subreg_loreg), KillFlag);
+ .addReg(HiSrc, KillFlag)
+ .addReg(LoSrc, KillFlag);
return;
}
if (Hexagon::VecPredRegsRegClass.contains(SrcReg, DestReg)) {
@@ -765,12 +839,14 @@ void HexagonInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
return;
}
if (Hexagon::VecPredRegs128BRegClass.contains(SrcReg, DestReg)) {
- unsigned DstHi = HRI.getSubReg(DestReg, Hexagon::subreg_hireg);
- BuildMI(MBB, I, DL, get(Hexagon::V6_pred_and), DstHi)
- .addReg(HRI.getSubReg(SrcReg, Hexagon::subreg_hireg), KillFlag);
- unsigned DstLo = HRI.getSubReg(DestReg, Hexagon::subreg_loreg);
- BuildMI(MBB, I, DL, get(Hexagon::V6_pred_and), DstLo)
- .addReg(HRI.getSubReg(SrcReg, Hexagon::subreg_loreg), KillFlag);
+ unsigned HiDst = HRI.getSubReg(DestReg, Hexagon::vsub_hi);
+ unsigned LoDst = HRI.getSubReg(DestReg, Hexagon::vsub_lo);
+ unsigned HiSrc = HRI.getSubReg(SrcReg, Hexagon::vsub_hi);
+ unsigned LoSrc = HRI.getSubReg(SrcReg, Hexagon::vsub_lo);
+ BuildMI(MBB, I, DL, get(Hexagon::V6_pred_and), HiDst)
+ .addReg(HiSrc, KillFlag);
+ BuildMI(MBB, I, DL, get(Hexagon::V6_pred_and), LoDst)
+ .addReg(LoSrc, KillFlag);
return;
}
@@ -783,13 +859,12 @@ void HexagonInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
llvm_unreachable("Unimplemented");
}
-
void HexagonInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, unsigned SrcReg, bool isKill, int FI,
const TargetRegisterClass *RC, const TargetRegisterInfo *TRI) const {
DebugLoc DL = MBB.findDebugLoc(I);
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
unsigned KillFlag = getKillRegState(isKill);
@@ -814,31 +889,35 @@ void HexagonInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else if (Hexagon::VecPredRegs128BRegClass.hasSubClassEq(RC)) {
- BuildMI(MBB, I, DL, get(Hexagon::STriq_pred_V6_128B))
+ BuildMI(MBB, I, DL, get(Hexagon::PS_vstorerq_ai_128B))
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else if (Hexagon::VecPredRegsRegClass.hasSubClassEq(RC)) {
- BuildMI(MBB, I, DL, get(Hexagon::STriq_pred_V6))
+ BuildMI(MBB, I, DL, get(Hexagon::PS_vstorerq_ai))
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else if (Hexagon::VectorRegs128BRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating 128B vector spill");
- BuildMI(MBB, I, DL, get(Hexagon::STriv_pseudo_V6_128B))
+ unsigned Opc = Align < 128 ? Hexagon::V6_vS32Ub_ai_128B
+ : Hexagon::V6_vS32b_ai_128B;
+ BuildMI(MBB, I, DL, get(Opc))
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else if (Hexagon::VectorRegsRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating vector spill");
- BuildMI(MBB, I, DL, get(Hexagon::STriv_pseudo_V6))
+ unsigned Opc = Align < 64 ? Hexagon::V6_vS32Ub_ai
+ : Hexagon::V6_vS32b_ai;
+ BuildMI(MBB, I, DL, get(Opc))
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else if (Hexagon::VecDblRegsRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating double vector spill");
- BuildMI(MBB, I, DL, get(Hexagon::STrivv_pseudo_V6))
+ unsigned Opc = Align < 64 ? Hexagon::PS_vstorerwu_ai
+ : Hexagon::PS_vstorerw_ai;
+ BuildMI(MBB, I, DL, get(Opc))
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else if (Hexagon::VecDblRegs128BRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating 128B double vector spill");
- BuildMI(MBB, I, DL, get(Hexagon::STrivv_pseudo_V6_128B))
+ unsigned Opc = Align < 128 ? Hexagon::PS_vstorerwu_ai_128B
+ : Hexagon::PS_vstorerw_ai_128B;
+ BuildMI(MBB, I, DL, get(Opc))
.addFrameIndex(FI).addImm(0)
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
} else {
@@ -852,7 +931,7 @@ void HexagonInstrInfo::loadRegFromStackSlot(
const TargetRegisterInfo *TRI) const {
DebugLoc DL = MBB.findDebugLoc(I);
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
MachineMemOperand *MMO = MF.getMachineMemOperand(
@@ -872,32 +951,43 @@ void HexagonInstrInfo::loadRegFromStackSlot(
BuildMI(MBB, I, DL, get(Hexagon::LDriw_mod), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else if (Hexagon::VecPredRegs128BRegClass.hasSubClassEq(RC)) {
- BuildMI(MBB, I, DL, get(Hexagon::LDriq_pred_V6_128B), DestReg)
+ BuildMI(MBB, I, DL, get(Hexagon::PS_vloadrq_ai_128B), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else if (Hexagon::VecPredRegsRegClass.hasSubClassEq(RC)) {
- BuildMI(MBB, I, DL, get(Hexagon::LDriq_pred_V6), DestReg)
+ BuildMI(MBB, I, DL, get(Hexagon::PS_vloadrq_ai), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else if (Hexagon::VecDblRegs128BRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating 128B double vector restore");
- BuildMI(MBB, I, DL, get(Hexagon::LDrivv_pseudo_V6_128B), DestReg)
+ unsigned Opc = Align < 128 ? Hexagon::PS_vloadrwu_ai_128B
+ : Hexagon::PS_vloadrw_ai_128B;
+ BuildMI(MBB, I, DL, get(Opc), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else if (Hexagon::VectorRegs128BRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating 128B vector restore");
- BuildMI(MBB, I, DL, get(Hexagon::LDriv_pseudo_V6_128B), DestReg)
+ unsigned Opc = Align < 128 ? Hexagon::V6_vL32Ub_ai_128B
+ : Hexagon::V6_vL32b_ai_128B;
+ BuildMI(MBB, I, DL, get(Opc), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else if (Hexagon::VectorRegsRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating vector restore");
- BuildMI(MBB, I, DL, get(Hexagon::LDriv_pseudo_V6), DestReg)
+ unsigned Opc = Align < 64 ? Hexagon::V6_vL32Ub_ai
+ : Hexagon::V6_vL32b_ai;
+ BuildMI(MBB, I, DL, get(Opc), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else if (Hexagon::VecDblRegsRegClass.hasSubClassEq(RC)) {
- DEBUG(dbgs() << "++Generating double vector restore");
- BuildMI(MBB, I, DL, get(Hexagon::LDrivv_pseudo_V6), DestReg)
+ unsigned Opc = Align < 64 ? Hexagon::PS_vloadrwu_ai
+ : Hexagon::PS_vloadrw_ai;
+ BuildMI(MBB, I, DL, get(Opc), DestReg)
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
} else {
llvm_unreachable("Can't store this register to stack slot");
}
}
+static void getLiveRegsAt(LivePhysRegs &Regs, const MachineInstr &MI) {
+ const MachineBasicBlock &B = *MI.getParent();
+ Regs.addLiveOuts(B);
+ auto E = ++MachineBasicBlock::const_iterator(MI.getIterator()).getReverse();
+ for (auto I = B.rbegin(); I != E; ++I)
+ Regs.stepBackward(*I);
+}
/// expandPostRAPseudo - This function is called for all pseudo instructions
/// that remain after register allocation. Many pseudo instructions are
@@ -912,7 +1002,6 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
DebugLoc DL = MI.getDebugLoc();
unsigned Opc = MI.getOpcode();
const unsigned VecOffset = 1;
- bool Is128B = false;
switch (Opc) {
case TargetOpcode::COPY: {
@@ -926,58 +1015,71 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MBB.erase(MBBI);
return true;
}
- case Hexagon::ALIGNA:
+ case Hexagon::PS_aligna:
BuildMI(MBB, MI, DL, get(Hexagon::A2_andir), MI.getOperand(0).getReg())
.addReg(HRI.getFrameRegister())
.addImm(-MI.getOperand(1).getImm());
MBB.erase(MI);
return true;
- case Hexagon::HEXAGON_V6_vassignp_128B:
- case Hexagon::HEXAGON_V6_vassignp: {
+ case Hexagon::V6_vassignp_128B:
+ case Hexagon::V6_vassignp: {
unsigned SrcReg = MI.getOperand(1).getReg();
unsigned DstReg = MI.getOperand(0).getReg();
- if (SrcReg != DstReg)
- copyPhysReg(MBB, MI, DL, DstReg, SrcReg, MI.getOperand(1).isKill());
+ unsigned Kill = getKillRegState(MI.getOperand(1).isKill());
+ BuildMI(MBB, MI, DL, get(Hexagon::V6_vcombine), DstReg)
+ .addReg(HRI.getSubReg(SrcReg, Hexagon::vsub_hi), Kill)
+ .addReg(HRI.getSubReg(SrcReg, Hexagon::vsub_lo), Kill);
MBB.erase(MI);
return true;
}
- case Hexagon::HEXAGON_V6_lo_128B:
- case Hexagon::HEXAGON_V6_lo: {
+ case Hexagon::V6_lo_128B:
+ case Hexagon::V6_lo: {
unsigned SrcReg = MI.getOperand(1).getReg();
unsigned DstReg = MI.getOperand(0).getReg();
- unsigned SrcSubLo = HRI.getSubReg(SrcReg, Hexagon::subreg_loreg);
+ unsigned SrcSubLo = HRI.getSubReg(SrcReg, Hexagon::vsub_lo);
copyPhysReg(MBB, MI, DL, DstReg, SrcSubLo, MI.getOperand(1).isKill());
MBB.erase(MI);
MRI.clearKillFlags(SrcSubLo);
return true;
}
- case Hexagon::HEXAGON_V6_hi_128B:
- case Hexagon::HEXAGON_V6_hi: {
+ case Hexagon::V6_hi_128B:
+ case Hexagon::V6_hi: {
unsigned SrcReg = MI.getOperand(1).getReg();
unsigned DstReg = MI.getOperand(0).getReg();
- unsigned SrcSubHi = HRI.getSubReg(SrcReg, Hexagon::subreg_hireg);
+ unsigned SrcSubHi = HRI.getSubReg(SrcReg, Hexagon::vsub_hi);
copyPhysReg(MBB, MI, DL, DstReg, SrcSubHi, MI.getOperand(1).isKill());
MBB.erase(MI);
MRI.clearKillFlags(SrcSubHi);
return true;
}
- case Hexagon::STrivv_indexed_128B:
- Is128B = true;
- case Hexagon::STrivv_indexed: {
+ case Hexagon::PS_vstorerw_ai:
+ case Hexagon::PS_vstorerwu_ai:
+ case Hexagon::PS_vstorerw_ai_128B:
+ case Hexagon::PS_vstorerwu_ai_128B: {
+ bool Is128B = (Opc == Hexagon::PS_vstorerw_ai_128B ||
+ Opc == Hexagon::PS_vstorerwu_ai_128B);
+ bool Aligned = (Opc == Hexagon::PS_vstorerw_ai ||
+ Opc == Hexagon::PS_vstorerw_ai_128B);
unsigned SrcReg = MI.getOperand(2).getReg();
- unsigned SrcSubHi = HRI.getSubReg(SrcReg, Hexagon::subreg_hireg);
- unsigned SrcSubLo = HRI.getSubReg(SrcReg, Hexagon::subreg_loreg);
- unsigned NewOpcd = Is128B ? Hexagon::V6_vS32b_ai_128B
- : Hexagon::V6_vS32b_ai;
+ unsigned SrcSubHi = HRI.getSubReg(SrcReg, Hexagon::vsub_hi);
+ unsigned SrcSubLo = HRI.getSubReg(SrcReg, Hexagon::vsub_lo);
+ unsigned NewOpc;
+ if (Aligned)
+ NewOpc = Is128B ? Hexagon::V6_vS32b_ai_128B
+ : Hexagon::V6_vS32b_ai;
+ else
+ NewOpc = Is128B ? Hexagon::V6_vS32Ub_ai_128B
+ : Hexagon::V6_vS32Ub_ai;
+
unsigned Offset = Is128B ? VecOffset << 7 : VecOffset << 6;
MachineInstr *MI1New =
- BuildMI(MBB, MI, DL, get(NewOpcd))
+ BuildMI(MBB, MI, DL, get(NewOpc))
.addOperand(MI.getOperand(0))
.addImm(MI.getOperand(1).getImm())
.addReg(SrcSubLo)
.setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
MI1New->getOperand(0).setIsKill(false);
- BuildMI(MBB, MI, DL, get(NewOpcd))
+ BuildMI(MBB, MI, DL, get(NewOpc))
.addOperand(MI.getOperand(0))
// The Vectors are indexed in multiples of vector size.
.addImm(MI.getOperand(1).getImm() + Offset)
@@ -986,23 +1088,32 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MBB.erase(MI);
return true;
}
- case Hexagon::LDrivv_pseudo_V6_128B:
- case Hexagon::LDrivv_indexed_128B:
- Is128B = true;
- case Hexagon::LDrivv_pseudo_V6:
- case Hexagon::LDrivv_indexed: {
- unsigned NewOpcd = Is128B ? Hexagon::V6_vL32b_ai_128B
- : Hexagon::V6_vL32b_ai;
+ case Hexagon::PS_vloadrw_ai:
+ case Hexagon::PS_vloadrwu_ai:
+ case Hexagon::PS_vloadrw_ai_128B:
+ case Hexagon::PS_vloadrwu_ai_128B: {
+ bool Is128B = (Opc == Hexagon::PS_vloadrw_ai_128B ||
+ Opc == Hexagon::PS_vloadrwu_ai_128B);
+ bool Aligned = (Opc == Hexagon::PS_vloadrw_ai ||
+ Opc == Hexagon::PS_vloadrw_ai_128B);
+ unsigned NewOpc;
+ if (Aligned)
+ NewOpc = Is128B ? Hexagon::V6_vL32b_ai_128B
+ : Hexagon::V6_vL32b_ai;
+ else
+ NewOpc = Is128B ? Hexagon::V6_vL32Ub_ai_128B
+ : Hexagon::V6_vL32Ub_ai;
+
unsigned DstReg = MI.getOperand(0).getReg();
unsigned Offset = Is128B ? VecOffset << 7 : VecOffset << 6;
MachineInstr *MI1New =
- BuildMI(MBB, MI, DL, get(NewOpcd),
- HRI.getSubReg(DstReg, Hexagon::subreg_loreg))
+ BuildMI(MBB, MI, DL, get(NewOpc),
+ HRI.getSubReg(DstReg, Hexagon::vsub_lo))
.addOperand(MI.getOperand(1))
.addImm(MI.getOperand(2).getImm());
MI1New->getOperand(1).setIsKill(false);
- BuildMI(MBB, MI, DL, get(NewOpcd),
- HRI.getSubReg(DstReg, Hexagon::subreg_hireg))
+ BuildMI(MBB, MI, DL, get(NewOpc),
+ HRI.getSubReg(DstReg, Hexagon::vsub_hi))
.addOperand(MI.getOperand(1))
// The Vectors are indexed in multiples of vector size.
.addImm(MI.getOperand(2).getImm() + Offset)
@@ -1010,35 +1121,7 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MBB.erase(MI);
return true;
}
- case Hexagon::LDriv_pseudo_V6_128B:
- Is128B = true;
- case Hexagon::LDriv_pseudo_V6: {
- unsigned DstReg = MI.getOperand(0).getReg();
- unsigned NewOpc = Is128B ? Hexagon::V6_vL32b_ai_128B
- : Hexagon::V6_vL32b_ai;
- int32_t Off = MI.getOperand(2).getImm();
- BuildMI(MBB, MI, DL, get(NewOpc), DstReg)
- .addOperand(MI.getOperand(1))
- .addImm(Off)
- .setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
- MBB.erase(MI);
- return true;
- }
- case Hexagon::STriv_pseudo_V6_128B:
- Is128B = true;
- case Hexagon::STriv_pseudo_V6: {
- unsigned NewOpc = Is128B ? Hexagon::V6_vS32b_ai_128B
- : Hexagon::V6_vS32b_ai;
- int32_t Off = MI.getOperand(1).getImm();
- BuildMI(MBB, MI, DL, get(NewOpc))
- .addOperand(MI.getOperand(0))
- .addImm(Off)
- .addOperand(MI.getOperand(2))
- .setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
- MBB.erase(MI);
- return true;
- }
- case Hexagon::TFR_PdTrue: {
+ case Hexagon::PS_true: {
unsigned Reg = MI.getOperand(0).getReg();
BuildMI(MBB, MI, DL, get(Hexagon::C2_orn), Reg)
.addReg(Reg, RegState::Undef)
@@ -1046,7 +1129,7 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MBB.erase(MI);
return true;
}
- case Hexagon::TFR_PdFalse: {
+ case Hexagon::PS_false: {
unsigned Reg = MI.getOperand(0).getReg();
BuildMI(MBB, MI, DL, get(Hexagon::C2_andn), Reg)
.addReg(Reg, RegState::Undef)
@@ -1054,21 +1137,21 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MBB.erase(MI);
return true;
}
- case Hexagon::VMULW: {
+ case Hexagon::PS_vmulw: {
// Expand a 64-bit vector multiply into 2 32-bit scalar multiplies.
unsigned DstReg = MI.getOperand(0).getReg();
unsigned Src1Reg = MI.getOperand(1).getReg();
unsigned Src2Reg = MI.getOperand(2).getReg();
- unsigned Src1SubHi = HRI.getSubReg(Src1Reg, Hexagon::subreg_hireg);
- unsigned Src1SubLo = HRI.getSubReg(Src1Reg, Hexagon::subreg_loreg);
- unsigned Src2SubHi = HRI.getSubReg(Src2Reg, Hexagon::subreg_hireg);
- unsigned Src2SubLo = HRI.getSubReg(Src2Reg, Hexagon::subreg_loreg);
+ unsigned Src1SubHi = HRI.getSubReg(Src1Reg, Hexagon::isub_hi);
+ unsigned Src1SubLo = HRI.getSubReg(Src1Reg, Hexagon::isub_lo);
+ unsigned Src2SubHi = HRI.getSubReg(Src2Reg, Hexagon::isub_hi);
+ unsigned Src2SubLo = HRI.getSubReg(Src2Reg, Hexagon::isub_lo);
BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::M2_mpyi),
- HRI.getSubReg(DstReg, Hexagon::subreg_hireg))
+ HRI.getSubReg(DstReg, Hexagon::isub_hi))
.addReg(Src1SubHi)
.addReg(Src2SubHi);
BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::M2_mpyi),
- HRI.getSubReg(DstReg, Hexagon::subreg_loreg))
+ HRI.getSubReg(DstReg, Hexagon::isub_lo))
.addReg(Src1SubLo)
.addReg(Src2SubLo);
MBB.erase(MI);
@@ -1078,25 +1161,25 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MRI.clearKillFlags(Src2SubLo);
return true;
}
- case Hexagon::VMULW_ACC: {
+ case Hexagon::PS_vmulw_acc: {
// Expand 64-bit vector multiply with addition into 2 scalar multiplies.
unsigned DstReg = MI.getOperand(0).getReg();
unsigned Src1Reg = MI.getOperand(1).getReg();
unsigned Src2Reg = MI.getOperand(2).getReg();
unsigned Src3Reg = MI.getOperand(3).getReg();
- unsigned Src1SubHi = HRI.getSubReg(Src1Reg, Hexagon::subreg_hireg);
- unsigned Src1SubLo = HRI.getSubReg(Src1Reg, Hexagon::subreg_loreg);
- unsigned Src2SubHi = HRI.getSubReg(Src2Reg, Hexagon::subreg_hireg);
- unsigned Src2SubLo = HRI.getSubReg(Src2Reg, Hexagon::subreg_loreg);
- unsigned Src3SubHi = HRI.getSubReg(Src3Reg, Hexagon::subreg_hireg);
- unsigned Src3SubLo = HRI.getSubReg(Src3Reg, Hexagon::subreg_loreg);
+ unsigned Src1SubHi = HRI.getSubReg(Src1Reg, Hexagon::isub_hi);
+ unsigned Src1SubLo = HRI.getSubReg(Src1Reg, Hexagon::isub_lo);
+ unsigned Src2SubHi = HRI.getSubReg(Src2Reg, Hexagon::isub_hi);
+ unsigned Src2SubLo = HRI.getSubReg(Src2Reg, Hexagon::isub_lo);
+ unsigned Src3SubHi = HRI.getSubReg(Src3Reg, Hexagon::isub_hi);
+ unsigned Src3SubLo = HRI.getSubReg(Src3Reg, Hexagon::isub_lo);
BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::M2_maci),
- HRI.getSubReg(DstReg, Hexagon::subreg_hireg))
+ HRI.getSubReg(DstReg, Hexagon::isub_hi))
.addReg(Src1SubHi)
.addReg(Src2SubHi)
.addReg(Src3SubHi);
BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::M2_maci),
- HRI.getSubReg(DstReg, Hexagon::subreg_loreg))
+ HRI.getSubReg(DstReg, Hexagon::isub_lo))
.addReg(Src1SubLo)
.addReg(Src2SubLo)
.addReg(Src3SubLo);
@@ -1109,49 +1192,7 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MRI.clearKillFlags(Src3SubLo);
return true;
}
- case Hexagon::Insert4: {
- unsigned DstReg = MI.getOperand(0).getReg();
- unsigned Src1Reg = MI.getOperand(1).getReg();
- unsigned Src2Reg = MI.getOperand(2).getReg();
- unsigned Src3Reg = MI.getOperand(3).getReg();
- unsigned Src4Reg = MI.getOperand(4).getReg();
- unsigned Src1RegIsKill = getKillRegState(MI.getOperand(1).isKill());
- unsigned Src2RegIsKill = getKillRegState(MI.getOperand(2).isKill());
- unsigned Src3RegIsKill = getKillRegState(MI.getOperand(3).isKill());
- unsigned Src4RegIsKill = getKillRegState(MI.getOperand(4).isKill());
- unsigned DstSubHi = HRI.getSubReg(DstReg, Hexagon::subreg_hireg);
- unsigned DstSubLo = HRI.getSubReg(DstReg, Hexagon::subreg_loreg);
- BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::S2_insert),
- HRI.getSubReg(DstReg, Hexagon::subreg_loreg))
- .addReg(DstSubLo)
- .addReg(Src1Reg, Src1RegIsKill)
- .addImm(16)
- .addImm(0);
- BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::S2_insert),
- HRI.getSubReg(DstReg, Hexagon::subreg_loreg))
- .addReg(DstSubLo)
- .addReg(Src2Reg, Src2RegIsKill)
- .addImm(16)
- .addImm(16);
- BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::S2_insert),
- HRI.getSubReg(DstReg, Hexagon::subreg_hireg))
- .addReg(DstSubHi)
- .addReg(Src3Reg, Src3RegIsKill)
- .addImm(16)
- .addImm(0);
- BuildMI(MBB, MI, MI.getDebugLoc(), get(Hexagon::S2_insert),
- HRI.getSubReg(DstReg, Hexagon::subreg_hireg))
- .addReg(DstSubHi)
- .addReg(Src4Reg, Src4RegIsKill)
- .addImm(16)
- .addImm(16);
- MBB.erase(MI);
- MRI.clearKillFlags(DstReg);
- MRI.clearKillFlags(DstSubHi);
- MRI.clearKillFlags(DstSubLo);
- return true;
- }
- case Hexagon::MUX64_rr: {
+ case Hexagon::PS_pselect: {
const MachineOperand &Op0 = MI.getOperand(0);
const MachineOperand &Op1 = MI.getOperand(1);
const MachineOperand &Op2 = MI.getOperand(2);
@@ -1175,73 +1216,104 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MBB.erase(MI);
return true;
}
- case Hexagon::VSelectPseudo_V6: {
+ case Hexagon::PS_vselect:
+ case Hexagon::PS_vselect_128B: {
const MachineOperand &Op0 = MI.getOperand(0);
const MachineOperand &Op1 = MI.getOperand(1);
const MachineOperand &Op2 = MI.getOperand(2);
const MachineOperand &Op3 = MI.getOperand(3);
- BuildMI(MBB, MI, DL, get(Hexagon::V6_vcmov))
- .addOperand(Op0)
- .addOperand(Op1)
- .addOperand(Op2);
- BuildMI(MBB, MI, DL, get(Hexagon::V6_vncmov))
- .addOperand(Op0)
- .addOperand(Op1)
- .addOperand(Op3);
+ LivePhysRegs LiveAtMI(&HRI);
+ getLiveRegsAt(LiveAtMI, MI);
+ bool IsDestLive = !LiveAtMI.available(MRI, Op0.getReg());
+ if (Op0.getReg() != Op2.getReg()) {
+ auto T = BuildMI(MBB, MI, DL, get(Hexagon::V6_vcmov))
+ .addOperand(Op0)
+ .addOperand(Op1)
+ .addOperand(Op2);
+ if (IsDestLive)
+ T.addReg(Op0.getReg(), RegState::Implicit);
+ IsDestLive = true;
+ }
+ if (Op0.getReg() != Op3.getReg()) {
+ auto T = BuildMI(MBB, MI, DL, get(Hexagon::V6_vncmov))
+ .addOperand(Op0)
+ .addOperand(Op1)
+ .addOperand(Op3);
+ if (IsDestLive)
+ T.addReg(Op0.getReg(), RegState::Implicit);
+ }
MBB.erase(MI);
return true;
}
- case Hexagon::VSelectDblPseudo_V6: {
+ case Hexagon::PS_wselect:
+ case Hexagon::PS_wselect_128B: {
MachineOperand &Op0 = MI.getOperand(0);
MachineOperand &Op1 = MI.getOperand(1);
MachineOperand &Op2 = MI.getOperand(2);
MachineOperand &Op3 = MI.getOperand(3);
- unsigned SrcLo = HRI.getSubReg(Op2.getReg(), Hexagon::subreg_loreg);
- unsigned SrcHi = HRI.getSubReg(Op2.getReg(), Hexagon::subreg_hireg);
- BuildMI(MBB, MI, DL, get(Hexagon::V6_vccombine))
- .addOperand(Op0)
- .addOperand(Op1)
- .addReg(SrcHi)
- .addReg(SrcLo);
- SrcLo = HRI.getSubReg(Op3.getReg(), Hexagon::subreg_loreg);
- SrcHi = HRI.getSubReg(Op3.getReg(), Hexagon::subreg_hireg);
- BuildMI(MBB, MI, DL, get(Hexagon::V6_vnccombine))
- .addOperand(Op0)
- .addOperand(Op1)
- .addReg(SrcHi)
- .addReg(SrcLo);
+ LivePhysRegs LiveAtMI(&HRI);
+ getLiveRegsAt(LiveAtMI, MI);
+ bool IsDestLive = !LiveAtMI.available(MRI, Op0.getReg());
+
+ if (Op0.getReg() != Op2.getReg()) {
+ unsigned SrcLo = HRI.getSubReg(Op2.getReg(), Hexagon::vsub_lo);
+ unsigned SrcHi = HRI.getSubReg(Op2.getReg(), Hexagon::vsub_hi);
+ auto T = BuildMI(MBB, MI, DL, get(Hexagon::V6_vccombine))
+ .addOperand(Op0)
+ .addOperand(Op1)
+ .addReg(SrcHi)
+ .addReg(SrcLo);
+ if (IsDestLive)
+ T.addReg(Op0.getReg(), RegState::Implicit);
+ IsDestLive = true;
+ }
+ if (Op0.getReg() != Op3.getReg()) {
+ unsigned SrcLo = HRI.getSubReg(Op3.getReg(), Hexagon::vsub_lo);
+ unsigned SrcHi = HRI.getSubReg(Op3.getReg(), Hexagon::vsub_hi);
+ auto T = BuildMI(MBB, MI, DL, get(Hexagon::V6_vnccombine))
+ .addOperand(Op0)
+ .addOperand(Op1)
+ .addReg(SrcHi)
+ .addReg(SrcLo);
+ if (IsDestLive)
+ T.addReg(Op0.getReg(), RegState::Implicit);
+ }
MBB.erase(MI);
return true;
}
- case Hexagon::TCRETURNi:
+ case Hexagon::PS_tailcall_i:
MI.setDesc(get(Hexagon::J2_jump));
return true;
- case Hexagon::TCRETURNr:
+ case Hexagon::PS_tailcall_r:
+ case Hexagon::PS_jmpret:
MI.setDesc(get(Hexagon::J2_jumpr));
return true;
- case Hexagon::TFRI_f:
- case Hexagon::TFRI_cPt_f:
- case Hexagon::TFRI_cNotPt_f: {
- unsigned Opx = (Opc == Hexagon::TFRI_f) ? 1 : 2;
- APFloat FVal = MI.getOperand(Opx).getFPImm()->getValueAPF();
- APInt IVal = FVal.bitcastToAPInt();
- MI.RemoveOperand(Opx);
- unsigned NewOpc = (Opc == Hexagon::TFRI_f) ? Hexagon::A2_tfrsi :
- (Opc == Hexagon::TFRI_cPt_f) ? Hexagon::C2_cmoveit :
- Hexagon::C2_cmoveif;
- MI.setDesc(get(NewOpc));
- MI.addOperand(MachineOperand::CreateImm(IVal.getZExtValue()));
+ case Hexagon::PS_jmprett:
+ MI.setDesc(get(Hexagon::J2_jumprt));
+ return true;
+ case Hexagon::PS_jmpretf:
+ MI.setDesc(get(Hexagon::J2_jumprf));
+ return true;
+ case Hexagon::PS_jmprettnewpt:
+ MI.setDesc(get(Hexagon::J2_jumprtnewpt));
+ return true;
+ case Hexagon::PS_jmpretfnewpt:
+ MI.setDesc(get(Hexagon::J2_jumprfnewpt));
+ return true;
+ case Hexagon::PS_jmprettnew:
+ MI.setDesc(get(Hexagon::J2_jumprtnew));
+ return true;
+ case Hexagon::PS_jmpretfnew:
+ MI.setDesc(get(Hexagon::J2_jumprfnew));
return true;
- }
}
return false;
}
-
// We indicate that we want to reverse the branch by
// inserting the reversed branching opcode.
-bool HexagonInstrInfo::ReverseBranchCondition(
+bool HexagonInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
if (Cond.empty())
return true;
@@ -1256,13 +1328,15 @@ bool HexagonInstrInfo::ReverseBranchCondition(
return false;
}
-
void HexagonInstrInfo::insertNoop(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const {
DebugLoc DL;
BuildMI(MBB, MI, DL, get(Hexagon::A2_nop));
}
+bool HexagonInstrInfo::isPostIncrement(const MachineInstr &MI) const {
+ return getAddrMode(MI) == HexagonII::PostInc;
+}
// Returns true if an instruction is predicated irrespective of the predicate
// sense. For example, all of the following will return true.
@@ -1277,7 +1351,6 @@ bool HexagonInstrInfo::isPredicated(const MachineInstr &MI) const {
return (F >> HexagonII::PredicatedPos) & HexagonII::PredicatedMask;
}
-
bool HexagonInstrInfo::PredicateInstruction(
MachineInstr &MI, ArrayRef<MachineOperand> Cond) const {
if (Cond.empty() || isNewValueJump(Cond[0].getImm()) ||
@@ -1329,14 +1402,12 @@ bool HexagonInstrInfo::PredicateInstruction(
return true;
}
-
bool HexagonInstrInfo::SubsumesPredicate(ArrayRef<MachineOperand> Pred1,
ArrayRef<MachineOperand> Pred2) const {
// TODO: Fix this
return false;
}
-
bool HexagonInstrInfo::DefinesPredicate(
MachineInstr &MI, std::vector<MachineOperand> &Pred) const {
auto &HRI = getRegisterInfo();
@@ -1353,7 +1424,6 @@ bool HexagonInstrInfo::DefinesPredicate(
return false;
}
-
bool HexagonInstrInfo::isPredicable(MachineInstr &MI) const {
return MI.getDesc().isPredicable();
}
@@ -1372,6 +1442,9 @@ bool HexagonInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
// Throwing call is a boundary.
if (MI.isCall()) {
+ // Don't mess around with no return calls.
+ if (doesNotReturn(MI))
+ return true;
// If any of the block's successors is a landing pad, this could be a
// throwing call.
for (auto I : MBB->successors())
@@ -1379,10 +1452,6 @@ bool HexagonInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
return true;
}
- // Don't mess around with no return calls.
- if (MI.getOpcode() == Hexagon::CALLv3nr)
- return true;
-
// Terminators and labels can't be scheduled around.
if (MI.getDesc().isTerminator() || MI.isPosition())
return true;
@@ -1393,7 +1462,6 @@ bool HexagonInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
return false;
}
-
/// Measure the specified inline asm to determine an approximation of its
/// length.
/// Comments (which run till the next SeparatorString or newline) do not
@@ -1418,8 +1486,8 @@ unsigned HexagonInstrInfo::getInlineAsmLength(const char *Str,
Length += MAI.getMaxInstLength();
atInsnStart = false;
}
- if (atInsnStart && strncmp(Str, MAI.getCommentString(),
- strlen(MAI.getCommentString())) == 0)
+ if (atInsnStart && strncmp(Str, MAI.getCommentString().data(),
+ MAI.getCommentString().size()) == 0)
atInsnStart = false;
}
@@ -1429,14 +1497,16 @@ unsigned HexagonInstrInfo::getInlineAsmLength(const char *Str,
return Length;
}
-
ScheduleHazardRecognizer*
HexagonInstrInfo::CreateTargetPostRAHazardRecognizer(
const InstrItineraryData *II, const ScheduleDAG *DAG) const {
+ if (UseDFAHazardRec) {
+ auto &HST = DAG->MF.getSubtarget<HexagonSubtarget>();
+ return new HexagonHazardRecognizer(II, this, HST);
+ }
return TargetInstrInfo::CreateTargetPostRAHazardRecognizer(II, DAG);
}
-
/// \brief For a comparison instruction, return the source registers in
/// \p SrcReg and \p SrcReg2 if having two register operands, and the value it
/// compares against in CmpValue. Return true if the comparison instruction
@@ -1529,17 +1599,15 @@ bool HexagonInstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
unsigned HexagonInstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
const MachineInstr &MI,
unsigned *PredCost) const {
- return getInstrTimingClassLatency(ItinData, &MI);
+ return getInstrTimingClassLatency(ItinData, MI);
}
-
DFAPacketizer *HexagonInstrInfo::CreateTargetScheduleState(
const TargetSubtargetInfo &STI) const {
const InstrItineraryData *II = STI.getInstrItineraryData();
return static_cast<const HexagonSubtarget&>(STI).createDFAPacketizer(II);
}
-
// Inspired by this pair:
// %R13<def> = L2_loadri_io %R29, 136; mem:LD4[FixedStack0]
// S2_storeri_io %R29, 132, %R1<kill>; flags: mem:ST4[FixedStack1]
@@ -1555,16 +1623,16 @@ bool HexagonInstrInfo::areMemAccessesTriviallyDisjoint(
// Instructions that are pure loads, not loads and stores like memops are not
// dependent.
- if (MIa.mayLoad() && !isMemOp(&MIa) && MIb.mayLoad() && !isMemOp(&MIb))
+ if (MIa.mayLoad() && !isMemOp(MIa) && MIb.mayLoad() && !isMemOp(MIb))
return true;
// Get base, offset, and access size in MIa.
- unsigned BaseRegA = getBaseAndOffset(&MIa, OffsetA, SizeA);
+ unsigned BaseRegA = getBaseAndOffset(MIa, OffsetA, SizeA);
if (!BaseRegA || !SizeA)
return false;
// Get base, offset, and access size in MIb.
- unsigned BaseRegB = getBaseAndOffset(&MIb, OffsetB, SizeB);
+ unsigned BaseRegB = getBaseAndOffset(MIb, OffsetB, SizeB);
if (!BaseRegB || !SizeB)
return false;
@@ -1584,8 +1652,22 @@ bool HexagonInstrInfo::areMemAccessesTriviallyDisjoint(
return false;
}
+/// If the instruction is an increment of a constant value, return the amount.
+bool HexagonInstrInfo::getIncrementValue(const MachineInstr &MI,
+ int &Value) const {
+ if (isPostIncrement(MI)) {
+ unsigned AccessSize;
+ return getBaseAndOffset(MI, Value, AccessSize);
+ }
+ if (MI.getOpcode() == Hexagon::A2_addi) {
+ Value = MI.getOperand(2).getImm();
+ return true;
+ }
+
+ return false;
+}
-unsigned HexagonInstrInfo::createVR(MachineFunction* MF, MVT VT) const {
+unsigned HexagonInstrInfo::createVR(MachineFunction *MF, MVT VT) const {
MachineRegisterInfo &MRI = MF->getRegInfo();
const TargetRegisterClass *TRC;
if (VT == MVT::i1) {
@@ -1602,58 +1684,52 @@ unsigned HexagonInstrInfo::createVR(MachineFunction* MF, MVT VT) const {
return NewReg;
}
-
-bool HexagonInstrInfo::isAbsoluteSet(const MachineInstr* MI) const {
+bool HexagonInstrInfo::isAbsoluteSet(const MachineInstr &MI) const {
return (getAddrMode(MI) == HexagonII::AbsoluteSet);
}
-
-bool HexagonInstrInfo::isAccumulator(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::isAccumulator(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return((F >> HexagonII::AccumulatorPos) & HexagonII::AccumulatorMask);
}
-
-bool HexagonInstrInfo::isComplex(const MachineInstr *MI) const {
- const MachineFunction *MF = MI->getParent()->getParent();
+bool HexagonInstrInfo::isComplex(const MachineInstr &MI) const {
+ const MachineFunction *MF = MI.getParent()->getParent();
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
const HexagonInstrInfo *QII = (const HexagonInstrInfo *) TII;
if (!(isTC1(MI))
&& !(QII->isTC2Early(MI))
- && !(MI->getDesc().mayLoad())
- && !(MI->getDesc().mayStore())
- && (MI->getDesc().getOpcode() != Hexagon::S2_allocframe)
- && (MI->getDesc().getOpcode() != Hexagon::L2_deallocframe)
+ && !(MI.getDesc().mayLoad())
+ && !(MI.getDesc().mayStore())
+ && (MI.getDesc().getOpcode() != Hexagon::S2_allocframe)
+ && (MI.getDesc().getOpcode() != Hexagon::L2_deallocframe)
&& !(QII->isMemOp(MI))
- && !(MI->isBranch())
- && !(MI->isReturn())
- && !MI->isCall())
+ && !(MI.isBranch())
+ && !(MI.isReturn())
+ && !MI.isCall())
return true;
return false;
}
-
// Return true if the instruction is a compund branch instruction.
-bool HexagonInstrInfo::isCompoundBranchInstr(const MachineInstr *MI) const {
- return (getType(MI) == HexagonII::TypeCOMPOUND && MI->isBranch());
+bool HexagonInstrInfo::isCompoundBranchInstr(const MachineInstr &MI) const {
+ return (getType(MI) == HexagonII::TypeCOMPOUND && MI.isBranch());
}
-
-bool HexagonInstrInfo::isCondInst(const MachineInstr *MI) const {
- return (MI->isBranch() && isPredicated(*MI)) ||
+bool HexagonInstrInfo::isCondInst(const MachineInstr &MI) const {
+ return (MI.isBranch() && isPredicated(MI)) ||
isConditionalTransfer(MI) ||
isConditionalALU32(MI) ||
isConditionalLoad(MI) ||
// Predicated stores which don't have a .new on any operands.
- (MI->mayStore() && isPredicated(*MI) && !isNewValueStore(MI) &&
- !isPredicatedNew(*MI));
+ (MI.mayStore() && isPredicated(MI) && !isNewValueStore(MI) &&
+ !isPredicatedNew(MI));
}
-
-bool HexagonInstrInfo::isConditionalALU32(const MachineInstr* MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isConditionalALU32(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::A2_paddf:
case Hexagon::A2_paddfnew:
case Hexagon::A2_paddif:
@@ -1709,25 +1785,23 @@ bool HexagonInstrInfo::isConditionalALU32(const MachineInstr* MI) const {
return false;
}
-
// FIXME - Function name and it's functionality don't match.
// It should be renamed to hasPredNewOpcode()
-bool HexagonInstrInfo::isConditionalLoad(const MachineInstr* MI) const {
- if (!MI->getDesc().mayLoad() || !isPredicated(*MI))
+bool HexagonInstrInfo::isConditionalLoad(const MachineInstr &MI) const {
+ if (!MI.getDesc().mayLoad() || !isPredicated(MI))
return false;
- int PNewOpcode = Hexagon::getPredNewOpcode(MI->getOpcode());
+ int PNewOpcode = Hexagon::getPredNewOpcode(MI.getOpcode());
// Instruction with valid predicated-new opcode can be promoted to .new.
return PNewOpcode >= 0;
}
-
// Returns true if an instruction is a conditional store.
//
// Note: It doesn't include conditional new-value stores as they can't be
// converted to .new predicate.
-bool HexagonInstrInfo::isConditionalStore(const MachineInstr* MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isConditionalStore(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
default: return false;
case Hexagon::S4_storeirbt_io:
case Hexagon::S4_storeirbf_io:
@@ -1779,9 +1853,8 @@ bool HexagonInstrInfo::isConditionalStore(const MachineInstr* MI) const {
}
}
-
-bool HexagonInstrInfo::isConditionalTransfer(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isConditionalTransfer(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::A2_tfrt:
case Hexagon::A2_tfrf:
case Hexagon::C2_cmoveit:
@@ -1800,11 +1873,10 @@ bool HexagonInstrInfo::isConditionalTransfer(const MachineInstr *MI) const {
return false;
}
-
// TODO: In order to have isExtendable for fpimm/f32Ext, we need to handle
// isFPImm and later getFPImm as well.
-bool HexagonInstrInfo::isConstExtended(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::isConstExtended(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
unsigned isExtended = (F >> HexagonII::ExtendedPos) & HexagonII::ExtendedMask;
if (isExtended) // Instruction must be extended.
return true;
@@ -1814,11 +1886,11 @@ bool HexagonInstrInfo::isConstExtended(const MachineInstr *MI) const {
if (!isExtendable)
return false;
- if (MI->isCall())
+ if (MI.isCall())
return false;
short ExtOpNum = getCExtOpNum(MI);
- const MachineOperand &MO = MI->getOperand(ExtOpNum);
+ const MachineOperand &MO = MI.getOperand(ExtOpNum);
// Use MO operand flags to determine if MO
// has the HMOTF_ConstExtended flag set.
if (MO.getTargetFlags() && HexagonII::HMOTF_ConstExtended)
@@ -1835,7 +1907,7 @@ bool HexagonInstrInfo::isConstExtended(const MachineInstr *MI) const {
// object we are going to end up with here for now.
// In the future we probably should add isSymbol(), etc.
if (MO.isGlobal() || MO.isSymbol() || MO.isBlockAddress() ||
- MO.isJTI() || MO.isCPI())
+ MO.isJTI() || MO.isCPI() || MO.isFPImm())
return true;
// If the extendable operand is not 'Immediate' type, the instruction should
@@ -1849,9 +1921,8 @@ bool HexagonInstrInfo::isConstExtended(const MachineInstr *MI) const {
return (ImmValue < MinValue || ImmValue > MaxValue);
}
-
-bool HexagonInstrInfo::isDeallocRet(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isDeallocRet(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::L4_return :
case Hexagon::L4_return_t :
case Hexagon::L4_return_f :
@@ -1864,12 +1935,10 @@ bool HexagonInstrInfo::isDeallocRet(const MachineInstr *MI) const {
return false;
}
-
// Return true when ConsMI uses a register defined by ProdMI.
-bool HexagonInstrInfo::isDependent(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) const {
- const MCInstrDesc &ProdMCID = ProdMI->getDesc();
- if (!ProdMCID.getNumDefs())
+bool HexagonInstrInfo::isDependent(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) const {
+ if (!ProdMI.getDesc().getNumDefs())
return false;
auto &HRI = getRegisterInfo();
@@ -1902,10 +1971,9 @@ bool HexagonInstrInfo::isDependent(const MachineInstr *ProdMI,
return false;
}
-
// Returns true if the instruction is alread a .cur.
-bool HexagonInstrInfo::isDotCurInst(const MachineInstr* MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isDotCurInst(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::V6_vL32b_cur_pi:
case Hexagon::V6_vL32b_cur_ai:
case Hexagon::V6_vL32b_cur_pi_128B:
@@ -1915,47 +1983,39 @@ bool HexagonInstrInfo::isDotCurInst(const MachineInstr* MI) const {
return false;
}
-
// Returns true, if any one of the operands is a dot new
// insn, whether it is predicated dot new or register dot new.
-bool HexagonInstrInfo::isDotNewInst(const MachineInstr* MI) const {
- if (isNewValueInst(MI) || (isPredicated(*MI) && isPredicatedNew(*MI)))
+bool HexagonInstrInfo::isDotNewInst(const MachineInstr &MI) const {
+ if (isNewValueInst(MI) || (isPredicated(MI) && isPredicatedNew(MI)))
return true;
return false;
}
-
/// Symmetrical. See if these two instructions are fit for duplex pair.
-bool HexagonInstrInfo::isDuplexPair(const MachineInstr *MIa,
- const MachineInstr *MIb) const {
+bool HexagonInstrInfo::isDuplexPair(const MachineInstr &MIa,
+ const MachineInstr &MIb) const {
HexagonII::SubInstructionGroup MIaG = getDuplexCandidateGroup(MIa);
HexagonII::SubInstructionGroup MIbG = getDuplexCandidateGroup(MIb);
return (isDuplexPairMatch(MIaG, MIbG) || isDuplexPairMatch(MIbG, MIaG));
}
-
-bool HexagonInstrInfo::isEarlySourceInstr(const MachineInstr *MI) const {
- if (!MI)
- return false;
-
- if (MI->mayLoad() || MI->mayStore() || MI->isCompare())
+bool HexagonInstrInfo::isEarlySourceInstr(const MachineInstr &MI) const {
+ if (MI.mayLoad() || MI.mayStore() || MI.isCompare())
return true;
// Multiply
- unsigned SchedClass = MI->getDesc().getSchedClass();
+ unsigned SchedClass = MI.getDesc().getSchedClass();
if (SchedClass == Hexagon::Sched::M_tc_3or4x_SLOT23)
return true;
return false;
}
-
bool HexagonInstrInfo::isEndLoopN(unsigned Opcode) const {
return (Opcode == Hexagon::ENDLOOP0 ||
Opcode == Hexagon::ENDLOOP1);
}
-
bool HexagonInstrInfo::isExpr(unsigned OpType) const {
switch(OpType) {
case MachineOperand::MO_MachineBasicBlock:
@@ -1970,18 +2030,18 @@ bool HexagonInstrInfo::isExpr(unsigned OpType) const {
}
}
-
-bool HexagonInstrInfo::isExtendable(const MachineInstr *MI) const {
- const MCInstrDesc &MID = MI->getDesc();
+bool HexagonInstrInfo::isExtendable(const MachineInstr &MI) const {
+ const MCInstrDesc &MID = MI.getDesc();
const uint64_t F = MID.TSFlags;
if ((F >> HexagonII::ExtendablePos) & HexagonII::ExtendableMask)
return true;
// TODO: This is largely obsolete now. Will need to be removed
// in consecutive patches.
- switch(MI->getOpcode()) {
- // TFR_FI Remains a special case.
- case Hexagon::TFR_FI:
+ switch (MI.getOpcode()) {
+ // PS_fi and PS_fia remain special cases.
+ case Hexagon::PS_fi:
+ case Hexagon::PS_fia:
return true;
default:
return false;
@@ -1989,57 +2049,53 @@ bool HexagonInstrInfo::isExtendable(const MachineInstr *MI) const {
return false;
}
-
// This returns true in two cases:
// - The OP code itself indicates that this is an extended instruction.
// - One of MOs has been marked with HMOTF_ConstExtended flag.
-bool HexagonInstrInfo::isExtended(const MachineInstr *MI) const {
+bool HexagonInstrInfo::isExtended(const MachineInstr &MI) const {
// First check if this is permanently extended op code.
- const uint64_t F = MI->getDesc().TSFlags;
+ const uint64_t F = MI.getDesc().TSFlags;
if ((F >> HexagonII::ExtendedPos) & HexagonII::ExtendedMask)
return true;
// Use MO operand flags to determine if one of MI's operands
// has HMOTF_ConstExtended flag set.
- for (MachineInstr::const_mop_iterator I = MI->operands_begin(),
- E = MI->operands_end(); I != E; ++I) {
+ for (MachineInstr::const_mop_iterator I = MI.operands_begin(),
+ E = MI.operands_end(); I != E; ++I) {
if (I->getTargetFlags() && HexagonII::HMOTF_ConstExtended)
return true;
}
return false;
}
-
-bool HexagonInstrInfo::isFloat(const MachineInstr *MI) const {
- unsigned Opcode = MI->getOpcode();
+bool HexagonInstrInfo::isFloat(const MachineInstr &MI) const {
+ unsigned Opcode = MI.getOpcode();
const uint64_t F = get(Opcode).TSFlags;
return (F >> HexagonII::FPPos) & HexagonII::FPMask;
}
-
// No V60 HVX VMEM with A_INDIRECT.
-bool HexagonInstrInfo::isHVXMemWithAIndirect(const MachineInstr *I,
- const MachineInstr *J) const {
+bool HexagonInstrInfo::isHVXMemWithAIndirect(const MachineInstr &I,
+ const MachineInstr &J) const {
if (!isV60VectorInstruction(I))
return false;
- if (!I->mayLoad() && !I->mayStore())
+ if (!I.mayLoad() && !I.mayStore())
return false;
- return J->isIndirectBranch() || isIndirectCall(J) || isIndirectL4Return(J);
+ return J.isIndirectBranch() || isIndirectCall(J) || isIndirectL4Return(J);
}
-
-bool HexagonInstrInfo::isIndirectCall(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isIndirectCall(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::J2_callr :
case Hexagon::J2_callrf :
case Hexagon::J2_callrt :
+ case Hexagon::PS_call_nr :
return true;
}
return false;
}
-
-bool HexagonInstrInfo::isIndirectL4Return(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isIndirectL4Return(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::L4_return :
case Hexagon::L4_return_t :
case Hexagon::L4_return_f :
@@ -2052,9 +2108,8 @@ bool HexagonInstrInfo::isIndirectL4Return(const MachineInstr *MI) const {
return false;
}
-
-bool HexagonInstrInfo::isJumpR(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isJumpR(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::J2_jumpr :
case Hexagon::J2_jumprt :
case Hexagon::J2_jumprf :
@@ -2067,25 +2122,24 @@ bool HexagonInstrInfo::isJumpR(const MachineInstr *MI) const {
return false;
}
-
-// Return true if a given MI can accomodate given offset.
+// Return true if a given MI can accommodate given offset.
// Use abs estimate as oppose to the exact number.
// TODO: This will need to be changed to use MC level
// definition of instruction extendable field size.
-bool HexagonInstrInfo::isJumpWithinBranchRange(const MachineInstr *MI,
+bool HexagonInstrInfo::isJumpWithinBranchRange(const MachineInstr &MI,
unsigned offset) const {
// This selection of jump instructions matches to that what
// AnalyzeBranch can parse, plus NVJ.
if (isNewValueJump(MI)) // r9:2
return isInt<11>(offset);
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
// Still missing Jump to address condition on register value.
default:
return false;
case Hexagon::J2_jump: // bits<24> dst; // r22:2
case Hexagon::J2_call:
- case Hexagon::CALLv3nr:
+ case Hexagon::PS_call_nr:
return isInt<24>(offset);
case Hexagon::J2_jumpt: //bits<17> dst; // r15:2
case Hexagon::J2_jumpf:
@@ -2112,19 +2166,15 @@ bool HexagonInstrInfo::isJumpWithinBranchRange(const MachineInstr *MI,
}
}
-
-bool HexagonInstrInfo::isLateInstrFeedsEarlyInstr(const MachineInstr *LRMI,
- const MachineInstr *ESMI) const {
- if (!LRMI || !ESMI)
- return false;
-
+bool HexagonInstrInfo::isLateInstrFeedsEarlyInstr(const MachineInstr &LRMI,
+ const MachineInstr &ESMI) const {
bool isLate = isLateResultInstr(LRMI);
bool isEarly = isEarlySourceInstr(ESMI);
DEBUG(dbgs() << "V60" << (isLate ? "-LR " : " -- "));
- DEBUG(LRMI->dump());
+ DEBUG(LRMI.dump());
DEBUG(dbgs() << "V60" << (isEarly ? "-ES " : " -- "));
- DEBUG(ESMI->dump());
+ DEBUG(ESMI.dump());
if (isLate && isEarly) {
DEBUG(dbgs() << "++Is Late Result feeding Early Source\n");
@@ -2134,12 +2184,8 @@ bool HexagonInstrInfo::isLateInstrFeedsEarlyInstr(const MachineInstr *LRMI,
return false;
}
-
-bool HexagonInstrInfo::isLateResultInstr(const MachineInstr *MI) const {
- if (!MI)
- return false;
-
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isLateResultInstr(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case TargetOpcode::EXTRACT_SUBREG:
case TargetOpcode::INSERT_SUBREG:
case TargetOpcode::SUBREG_TO_REG:
@@ -2153,7 +2199,7 @@ bool HexagonInstrInfo::isLateResultInstr(const MachineInstr *MI) const {
break;
}
- unsigned SchedClass = MI->getDesc().getSchedClass();
+ unsigned SchedClass = MI.getDesc().getSchedClass();
switch (SchedClass) {
case Hexagon::Sched::ALU32_2op_tc_1_SLOT0123:
@@ -2174,19 +2220,14 @@ bool HexagonInstrInfo::isLateResultInstr(const MachineInstr *MI) const {
return true;
}
-
-bool HexagonInstrInfo::isLateSourceInstr(const MachineInstr *MI) const {
- if (!MI)
- return false;
-
+bool HexagonInstrInfo::isLateSourceInstr(const MachineInstr &MI) const {
// Instructions with iclass A_CVI_VX and attribute A_CVI_LATE uses a multiply
// resource, but all operands can be received late like an ALU instruction.
- return MI->getDesc().getSchedClass() == Hexagon::Sched::CVI_VX_LATE;
+ return MI.getDesc().getSchedClass() == Hexagon::Sched::CVI_VX_LATE;
}
-
-bool HexagonInstrInfo::isLoopN(const MachineInstr *MI) const {
- unsigned Opcode = MI->getOpcode();
+bool HexagonInstrInfo::isLoopN(const MachineInstr &MI) const {
+ unsigned Opcode = MI.getOpcode();
return Opcode == Hexagon::J2_loop0i ||
Opcode == Hexagon::J2_loop0r ||
Opcode == Hexagon::J2_loop0iext ||
@@ -2197,9 +2238,8 @@ bool HexagonInstrInfo::isLoopN(const MachineInstr *MI) const {
Opcode == Hexagon::J2_loop1rext;
}
-
-bool HexagonInstrInfo::isMemOp(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isMemOp(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
default: return false;
case Hexagon::L4_iadd_memopw_io :
case Hexagon::L4_isub_memopw_io :
@@ -2230,81 +2270,64 @@ bool HexagonInstrInfo::isMemOp(const MachineInstr *MI) const {
return false;
}
-
-bool HexagonInstrInfo::isNewValue(const MachineInstr* MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::isNewValue(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::NewValuePos) & HexagonII::NewValueMask;
}
-
bool HexagonInstrInfo::isNewValue(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
return (F >> HexagonII::NewValuePos) & HexagonII::NewValueMask;
}
-
-bool HexagonInstrInfo::isNewValueInst(const MachineInstr *MI) const {
+bool HexagonInstrInfo::isNewValueInst(const MachineInstr &MI) const {
return isNewValueJump(MI) || isNewValueStore(MI);
}
-
-bool HexagonInstrInfo::isNewValueJump(const MachineInstr *MI) const {
- return isNewValue(MI) && MI->isBranch();
+bool HexagonInstrInfo::isNewValueJump(const MachineInstr &MI) const {
+ return isNewValue(MI) && MI.isBranch();
}
-
bool HexagonInstrInfo::isNewValueJump(unsigned Opcode) const {
return isNewValue(Opcode) && get(Opcode).isBranch() && isPredicated(Opcode);
}
-
-bool HexagonInstrInfo::isNewValueStore(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::isNewValueStore(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::NVStorePos) & HexagonII::NVStoreMask;
}
-
bool HexagonInstrInfo::isNewValueStore(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
return (F >> HexagonII::NVStorePos) & HexagonII::NVStoreMask;
}
-
// Returns true if a particular operand is extendable for an instruction.
-bool HexagonInstrInfo::isOperandExtended(const MachineInstr *MI,
+bool HexagonInstrInfo::isOperandExtended(const MachineInstr &MI,
unsigned OperandNum) const {
- const uint64_t F = MI->getDesc().TSFlags;
+ const uint64_t F = MI.getDesc().TSFlags;
return ((F >> HexagonII::ExtendableOpPos) & HexagonII::ExtendableOpMask)
== OperandNum;
}
-
-bool HexagonInstrInfo::isPostIncrement(const MachineInstr* MI) const {
- return getAddrMode(MI) == HexagonII::PostInc;
-}
-
-
bool HexagonInstrInfo::isPredicatedNew(const MachineInstr &MI) const {
const uint64_t F = MI.getDesc().TSFlags;
assert(isPredicated(MI));
return (F >> HexagonII::PredicatedNewPos) & HexagonII::PredicatedNewMask;
}
-
bool HexagonInstrInfo::isPredicatedNew(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
assert(isPredicated(Opcode));
return (F >> HexagonII::PredicatedNewPos) & HexagonII::PredicatedNewMask;
}
-
bool HexagonInstrInfo::isPredicatedTrue(const MachineInstr &MI) const {
const uint64_t F = MI.getDesc().TSFlags;
return !((F >> HexagonII::PredicatedFalsePos) &
HexagonII::PredicatedFalseMask);
}
-
bool HexagonInstrInfo::isPredicatedTrue(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
// Make sure that the instruction is predicated.
@@ -2313,19 +2336,16 @@ bool HexagonInstrInfo::isPredicatedTrue(unsigned Opcode) const {
HexagonII::PredicatedFalseMask);
}
-
bool HexagonInstrInfo::isPredicated(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
return (F >> HexagonII::PredicatedPos) & HexagonII::PredicatedMask;
}
-
bool HexagonInstrInfo::isPredicateLate(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
return ~(F >> HexagonII::PredicateLatePos) & HexagonII::PredicateLateMask;
}
-
bool HexagonInstrInfo::isPredictedTaken(unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
assert(get(Opcode).isBranch() &&
@@ -2333,12 +2353,11 @@ bool HexagonInstrInfo::isPredictedTaken(unsigned Opcode) const {
return (F >> HexagonII::TakenPos) & HexagonII::TakenMask;
}
-
-bool HexagonInstrInfo::isSaveCalleeSavedRegsCall(const MachineInstr *MI) const {
- return MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4 ||
- MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT ||
- MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_PIC ||
- MI->getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC;
+bool HexagonInstrInfo::isSaveCalleeSavedRegsCall(const MachineInstr &MI) const {
+ return MI.getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4 ||
+ MI.getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT ||
+ MI.getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_PIC ||
+ MI.getOpcode() == Hexagon::SAVE_REGISTERS_CALL_V4_EXT_PIC;
}
bool HexagonInstrInfo::isSignExtendingLoad(const MachineInstr &MI) const {
@@ -2419,15 +2438,13 @@ bool HexagonInstrInfo::isSignExtendingLoad(const MachineInstr &MI) const {
}
}
-
-bool HexagonInstrInfo::isSolo(const MachineInstr* MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::isSolo(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::SoloPos) & HexagonII::SoloMask;
}
-
-bool HexagonInstrInfo::isSpillPredRegOp(const MachineInstr *MI) const {
- switch (MI->getOpcode()) {
+bool HexagonInstrInfo::isSpillPredRegOp(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
case Hexagon::STriw_pred :
case Hexagon::LDriw_pred :
return true;
@@ -2436,21 +2453,19 @@ bool HexagonInstrInfo::isSpillPredRegOp(const MachineInstr *MI) const {
}
}
-
-bool HexagonInstrInfo::isTailCall(const MachineInstr *MI) const {
- if (!MI->isBranch())
+bool HexagonInstrInfo::isTailCall(const MachineInstr &MI) const {
+ if (!MI.isBranch())
return false;
- for (auto &Op : MI->operands())
+ for (auto &Op : MI.operands())
if (Op.isGlobal() || Op.isSymbol())
return true;
return false;
}
-
// Returns true when SU has a timing class TC1.
-bool HexagonInstrInfo::isTC1(const MachineInstr *MI) const {
- unsigned SchedClass = MI->getDesc().getSchedClass();
+bool HexagonInstrInfo::isTC1(const MachineInstr &MI) const {
+ unsigned SchedClass = MI.getDesc().getSchedClass();
switch (SchedClass) {
case Hexagon::Sched::ALU32_2op_tc_1_SLOT0123:
case Hexagon::Sched::ALU32_3op_tc_1_SLOT0123:
@@ -2467,9 +2482,8 @@ bool HexagonInstrInfo::isTC1(const MachineInstr *MI) const {
}
}
-
-bool HexagonInstrInfo::isTC2(const MachineInstr *MI) const {
- unsigned SchedClass = MI->getDesc().getSchedClass();
+bool HexagonInstrInfo::isTC2(const MachineInstr &MI) const {
+ unsigned SchedClass = MI.getDesc().getSchedClass();
switch (SchedClass) {
case Hexagon::Sched::ALU32_3op_tc_2_SLOT0123:
case Hexagon::Sched::ALU64_tc_2_SLOT23:
@@ -2484,9 +2498,8 @@ bool HexagonInstrInfo::isTC2(const MachineInstr *MI) const {
}
}
-
-bool HexagonInstrInfo::isTC2Early(const MachineInstr *MI) const {
- unsigned SchedClass = MI->getDesc().getSchedClass();
+bool HexagonInstrInfo::isTC2Early(const MachineInstr &MI) const {
+ unsigned SchedClass = MI.getDesc().getSchedClass();
switch (SchedClass) {
case Hexagon::Sched::ALU32_2op_tc_2early_SLOT0123:
case Hexagon::Sched::ALU32_3op_tc_2early_SLOT0123:
@@ -2505,47 +2518,35 @@ bool HexagonInstrInfo::isTC2Early(const MachineInstr *MI) const {
}
}
-
-bool HexagonInstrInfo::isTC4x(const MachineInstr *MI) const {
- if (!MI)
- return false;
-
- unsigned SchedClass = MI->getDesc().getSchedClass();
+bool HexagonInstrInfo::isTC4x(const MachineInstr &MI) const {
+ unsigned SchedClass = MI.getDesc().getSchedClass();
return SchedClass == Hexagon::Sched::M_tc_3or4x_SLOT23;
}
-
// Schedule this ASAP.
-bool HexagonInstrInfo::isToBeScheduledASAP(const MachineInstr *MI1,
- const MachineInstr *MI2) const {
- if (!MI1 || !MI2)
- return false;
+bool HexagonInstrInfo::isToBeScheduledASAP(const MachineInstr &MI1,
+ const MachineInstr &MI2) const {
if (mayBeCurLoad(MI1)) {
// if (result of SU is used in Next) return true;
- unsigned DstReg = MI1->getOperand(0).getReg();
- int N = MI2->getNumOperands();
+ unsigned DstReg = MI1.getOperand(0).getReg();
+ int N = MI2.getNumOperands();
for (int I = 0; I < N; I++)
- if (MI2->getOperand(I).isReg() && DstReg == MI2->getOperand(I).getReg())
+ if (MI2.getOperand(I).isReg() && DstReg == MI2.getOperand(I).getReg())
return true;
}
if (mayBeNewStore(MI2))
- if (MI2->getOpcode() == Hexagon::V6_vS32b_pi)
- if (MI1->getOperand(0).isReg() && MI2->getOperand(3).isReg() &&
- MI1->getOperand(0).getReg() == MI2->getOperand(3).getReg())
+ if (MI2.getOpcode() == Hexagon::V6_vS32b_pi)
+ if (MI1.getOperand(0).isReg() && MI2.getOperand(3).isReg() &&
+ MI1.getOperand(0).getReg() == MI2.getOperand(3).getReg())
return true;
return false;
}
-
-bool HexagonInstrInfo::isV60VectorInstruction(const MachineInstr *MI) const {
- if (!MI)
- return false;
-
+bool HexagonInstrInfo::isV60VectorInstruction(const MachineInstr &MI) const {
const uint64_t V = getType(MI);
return HexagonII::TypeCVI_FIRST <= V && V <= HexagonII::TypeCVI_LAST;
}
-
// Check if the Offset is a valid auto-inc imm by Load/Store Type.
//
bool HexagonInstrInfo::isValidAutoIncImm(const EVT VT, const int Offset) const {
@@ -2584,7 +2585,6 @@ bool HexagonInstrInfo::isValidAutoIncImm(const EVT VT, const int Offset) const {
llvm_unreachable("Not an auto-inc opc!");
}
-
bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset,
bool Extend) const {
// This function is to check whether the "Offset" is in the correct range of
@@ -2597,16 +2597,10 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset,
// misaligns with respect to load size.
switch (Opcode) {
- case Hexagon::STriq_pred_V6:
- case Hexagon::STriq_pred_vec_V6:
- case Hexagon::STriv_pseudo_V6:
- case Hexagon::STrivv_pseudo_V6:
- case Hexagon::LDriq_pred_V6:
- case Hexagon::LDriq_pred_vec_V6:
- case Hexagon::LDriv_pseudo_V6:
- case Hexagon::LDrivv_pseudo_V6:
- case Hexagon::LDrivv_indexed:
- case Hexagon::STrivv_indexed:
+ case Hexagon::PS_vstorerq_ai:
+ case Hexagon::PS_vstorerw_ai:
+ case Hexagon::PS_vloadrq_ai:
+ case Hexagon::PS_vloadrw_ai:
case Hexagon::V6_vL32b_ai:
case Hexagon::V6_vS32b_ai:
case Hexagon::V6_vL32Ub_ai:
@@ -2614,16 +2608,10 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset,
return (Offset >= Hexagon_MEMV_OFFSET_MIN) &&
(Offset <= Hexagon_MEMV_OFFSET_MAX);
- case Hexagon::STriq_pred_V6_128B:
- case Hexagon::STriq_pred_vec_V6_128B:
- case Hexagon::STriv_pseudo_V6_128B:
- case Hexagon::STrivv_pseudo_V6_128B:
- case Hexagon::LDriq_pred_V6_128B:
- case Hexagon::LDriq_pred_vec_V6_128B:
- case Hexagon::LDriv_pseudo_V6_128B:
- case Hexagon::LDrivv_pseudo_V6_128B:
- case Hexagon::LDrivv_indexed_128B:
- case Hexagon::STrivv_indexed_128B:
+ case Hexagon::PS_vstorerq_ai_128B:
+ case Hexagon::PS_vstorerw_ai_128B:
+ case Hexagon::PS_vloadrq_ai_128B:
+ case Hexagon::PS_vloadrw_ai_128B:
case Hexagon::V6_vL32b_ai_128B:
case Hexagon::V6_vS32b_ai_128B:
case Hexagon::V6_vL32Ub_ai_128B:
@@ -2713,8 +2701,8 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset,
case Hexagon::LDriw_mod:
return true;
- case Hexagon::TFR_FI:
- case Hexagon::TFR_FIA:
+ case Hexagon::PS_fi:
+ case Hexagon::PS_fia:
case Hexagon::INLINEASM:
return true;
@@ -2751,25 +2739,20 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset,
"Please define it in the above switch statement!");
}
-
-bool HexagonInstrInfo::isVecAcc(const MachineInstr *MI) const {
- return MI && isV60VectorInstruction(MI) && isAccumulator(MI);
+bool HexagonInstrInfo::isVecAcc(const MachineInstr &MI) const {
+ return isV60VectorInstruction(MI) && isAccumulator(MI);
}
-
-bool HexagonInstrInfo::isVecALU(const MachineInstr *MI) const {
- if (!MI)
- return false;
- const uint64_t F = get(MI->getOpcode()).TSFlags;
+bool HexagonInstrInfo::isVecALU(const MachineInstr &MI) const {
+ const uint64_t F = get(MI.getOpcode()).TSFlags;
const uint64_t V = ((F >> HexagonII::TypePos) & HexagonII::TypeMask);
return
V == HexagonII::TypeCVI_VA ||
V == HexagonII::TypeCVI_VA_DV;
}
-
-bool HexagonInstrInfo::isVecUsableNextPacket(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) const {
+bool HexagonInstrInfo::isVecUsableNextPacket(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) const {
if (EnableACCForwarding && isVecAcc(ProdMI) && isVecAcc(ConsMI))
return true;
@@ -2860,31 +2843,40 @@ bool HexagonInstrInfo::isZeroExtendingLoad(const MachineInstr &MI) const {
}
}
-
// Add latency to instruction.
-bool HexagonInstrInfo::addLatencyToSchedule(const MachineInstr *MI1,
- const MachineInstr *MI2) const {
+bool HexagonInstrInfo::addLatencyToSchedule(const MachineInstr &MI1,
+ const MachineInstr &MI2) const {
if (isV60VectorInstruction(MI1) && isV60VectorInstruction(MI2))
if (!isVecUsableNextPacket(MI1, MI2))
return true;
return false;
}
+/// \brief Get the base register and byte offset of a load/store instr.
+bool HexagonInstrInfo::getMemOpBaseRegImmOfs(MachineInstr &LdSt,
+ unsigned &BaseReg, int64_t &Offset, const TargetRegisterInfo *TRI)
+ const {
+ unsigned AccessSize = 0;
+ int OffsetVal = 0;
+ BaseReg = getBaseAndOffset(LdSt, OffsetVal, AccessSize);
+ Offset = OffsetVal;
+ return BaseReg != 0;
+}
/// \brief Can these instructions execute at the same time in a bundle.
-bool HexagonInstrInfo::canExecuteInBundle(const MachineInstr *First,
- const MachineInstr *Second) const {
+bool HexagonInstrInfo::canExecuteInBundle(const MachineInstr &First,
+ const MachineInstr &Second) const {
if (DisableNVSchedule)
return false;
if (mayBeNewStore(Second)) {
// Make sure the definition of the first instruction is the value being
// stored.
const MachineOperand &Stored =
- Second->getOperand(Second->getNumOperands() - 1);
+ Second.getOperand(Second.getNumOperands() - 1);
if (!Stored.isReg())
return false;
- for (unsigned i = 0, e = First->getNumOperands(); i < e; ++i) {
- const MachineOperand &Op = First->getOperand(i);
+ for (unsigned i = 0, e = First.getNumOperands(); i < e; ++i) {
+ const MachineOperand &Op = First.getOperand(i);
if (Op.isReg() && Op.isDef() && Op.getReg() == Stored.getReg())
return true;
}
@@ -2892,6 +2884,10 @@ bool HexagonInstrInfo::canExecuteInBundle(const MachineInstr *First,
return false;
}
+bool HexagonInstrInfo::doesNotReturn(const MachineInstr &CallMI) const {
+ unsigned Opc = CallMI.getOpcode();
+ return Opc == Hexagon::PS_call_nr || Opc == Hexagon::PS_callr_nr;
+}
bool HexagonInstrInfo::hasEHLabel(const MachineBasicBlock *B) const {
for (auto &I : *B)
@@ -2900,33 +2896,32 @@ bool HexagonInstrInfo::hasEHLabel(const MachineBasicBlock *B) const {
return false;
}
-
// Returns true if an instruction can be converted into a non-extended
// equivalent instruction.
-bool HexagonInstrInfo::hasNonExtEquivalent(const MachineInstr *MI) const {
+bool HexagonInstrInfo::hasNonExtEquivalent(const MachineInstr &MI) const {
short NonExtOpcode;
// Check if the instruction has a register form that uses register in place
// of the extended operand, if so return that as the non-extended form.
- if (Hexagon::getRegForm(MI->getOpcode()) >= 0)
+ if (Hexagon::getRegForm(MI.getOpcode()) >= 0)
return true;
- if (MI->getDesc().mayLoad() || MI->getDesc().mayStore()) {
+ if (MI.getDesc().mayLoad() || MI.getDesc().mayStore()) {
// Check addressing mode and retrieve non-ext equivalent instruction.
switch (getAddrMode(MI)) {
case HexagonII::Absolute :
// Load/store with absolute addressing mode can be converted into
// base+offset mode.
- NonExtOpcode = Hexagon::getBaseWithImmOffset(MI->getOpcode());
+ NonExtOpcode = Hexagon::getBaseWithImmOffset(MI.getOpcode());
break;
case HexagonII::BaseImmOffset :
// Load/store with base+offset addressing mode can be converted into
// base+register offset addressing mode. However left shift operand should
// be set to 0.
- NonExtOpcode = Hexagon::getBaseWithRegOffset(MI->getOpcode());
+ NonExtOpcode = Hexagon::getBaseWithRegOffset(MI.getOpcode());
break;
case HexagonII::BaseLongOffset:
- NonExtOpcode = Hexagon::getRegShlForm(MI->getOpcode());
+ NonExtOpcode = Hexagon::getRegShlForm(MI.getOpcode());
break;
default:
return false;
@@ -2938,13 +2933,11 @@ bool HexagonInstrInfo::hasNonExtEquivalent(const MachineInstr *MI) const {
return false;
}
-
-bool HexagonInstrInfo::hasPseudoInstrPair(const MachineInstr *MI) const {
- return Hexagon::getRealHWInstr(MI->getOpcode(),
+bool HexagonInstrInfo::hasPseudoInstrPair(const MachineInstr &MI) const {
+ return Hexagon::getRealHWInstr(MI.getOpcode(),
Hexagon::InstrType_Pseudo) >= 0;
}
-
bool HexagonInstrInfo::hasUncondBranch(const MachineBasicBlock *B)
const {
MachineBasicBlock::const_iterator I = B->getFirstTerminator(), E = B->end();
@@ -2956,25 +2949,22 @@ bool HexagonInstrInfo::hasUncondBranch(const MachineBasicBlock *B)
return false;
}
-
// Returns true, if a LD insn can be promoted to a cur load.
-bool HexagonInstrInfo::mayBeCurLoad(const MachineInstr *MI) const {
- auto &HST = MI->getParent()->getParent()->getSubtarget<HexagonSubtarget>();
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::mayBeCurLoad(const MachineInstr &MI) const {
+ auto &HST = MI.getParent()->getParent()->getSubtarget<HexagonSubtarget>();
+ const uint64_t F = MI.getDesc().TSFlags;
return ((F >> HexagonII::mayCVLoadPos) & HexagonII::mayCVLoadMask) &&
HST.hasV60TOps();
}
-
// Returns true, if a ST insn can be promoted to a new-value store.
-bool HexagonInstrInfo::mayBeNewStore(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+bool HexagonInstrInfo::mayBeNewStore(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::mayNVStorePos) & HexagonII::mayNVStoreMask;
}
-
-bool HexagonInstrInfo::producesStall(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) const {
+bool HexagonInstrInfo::producesStall(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) const {
// There is no stall when ProdMI is not a V60 vector.
if (!isV60VectorInstruction(ProdMI))
return false;
@@ -2991,8 +2981,7 @@ bool HexagonInstrInfo::producesStall(const MachineInstr *ProdMI,
return true;
}
-
-bool HexagonInstrInfo::producesStall(const MachineInstr *MI,
+bool HexagonInstrInfo::producesStall(const MachineInstr &MI,
MachineBasicBlock::const_instr_iterator BII) const {
// There is no stall when I is not a V60 vector.
if (!isV60VectorInstruction(MI))
@@ -3001,8 +2990,8 @@ bool HexagonInstrInfo::producesStall(const MachineInstr *MI,
MachineBasicBlock::const_instr_iterator MII = BII;
MachineBasicBlock::const_instr_iterator MIE = MII->getParent()->instr_end();
- if (!(*MII).isBundle()) {
- const MachineInstr *J = &*MII;
+ if (!MII->isBundle()) {
+ const MachineInstr &J = *MII;
if (!isV60VectorInstruction(J))
return false;
else if (isVecUsableNextPacket(J, MI))
@@ -3011,18 +3000,17 @@ bool HexagonInstrInfo::producesStall(const MachineInstr *MI,
}
for (++MII; MII != MIE && MII->isInsideBundle(); ++MII) {
- const MachineInstr *J = &*MII;
+ const MachineInstr &J = *MII;
if (producesStall(J, MI))
return true;
}
return false;
}
-
-bool HexagonInstrInfo::predCanBeUsedAsDotNew(const MachineInstr *MI,
+bool HexagonInstrInfo::predCanBeUsedAsDotNew(const MachineInstr &MI,
unsigned PredReg) const {
- for (unsigned opNum = 0; opNum < MI->getNumOperands(); opNum++) {
- const MachineOperand &MO = MI->getOperand(opNum);
+ for (unsigned opNum = 0; opNum < MI.getNumOperands(); opNum++) {
+ const MachineOperand &MO = MI.getOperand(opNum);
if (MO.isReg() && MO.isDef() && MO.isImplicit() && (MO.getReg() == PredReg))
return false; // Predicate register must be explicitly defined.
}
@@ -3030,10 +3018,9 @@ bool HexagonInstrInfo::predCanBeUsedAsDotNew(const MachineInstr *MI,
// Hexagon Programmer's Reference says that decbin, memw_locked, and
// memd_locked cannot be used as .new as well,
// but we don't seem to have these instructions defined.
- return MI->getOpcode() != Hexagon::A4_tlbmatch;
+ return MI.getOpcode() != Hexagon::A4_tlbmatch;
}
-
bool HexagonInstrInfo::PredOpcodeHasJMP_c(unsigned Opcode) const {
return (Opcode == Hexagon::J2_jumpt) ||
(Opcode == Hexagon::J2_jumpf) ||
@@ -3043,28 +3030,24 @@ bool HexagonInstrInfo::PredOpcodeHasJMP_c(unsigned Opcode) const {
(Opcode == Hexagon::J2_jumpfnewpt);
}
-
bool HexagonInstrInfo::predOpcodeHasNot(ArrayRef<MachineOperand> Cond) const {
if (Cond.empty() || !isPredicated(Cond[0].getImm()))
return false;
return !isPredicatedTrue(Cond[0].getImm());
}
-
-short HexagonInstrInfo::getAbsoluteForm(const MachineInstr *MI) const {
- return Hexagon::getAbsoluteForm(MI->getOpcode());
+short HexagonInstrInfo::getAbsoluteForm(const MachineInstr &MI) const {
+ return Hexagon::getAbsoluteForm(MI.getOpcode());
}
-
-unsigned HexagonInstrInfo::getAddrMode(const MachineInstr* MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+unsigned HexagonInstrInfo::getAddrMode(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::AddrModePos) & HexagonII::AddrModeMask;
}
-
// Returns the base register in a memory access (load/store). The offset is
// returned in Offset and the access size is returned in AccessSize.
-unsigned HexagonInstrInfo::getBaseAndOffset(const MachineInstr *MI,
+unsigned HexagonInstrInfo::getBaseAndOffset(const MachineInstr &MI,
int &Offset, unsigned &AccessSize) const {
// Return if it is not a base+offset type instruction or a MemOp.
if (getAddrMode(MI) != HexagonII::BaseImmOffset &&
@@ -3092,30 +3075,29 @@ unsigned HexagonInstrInfo::getBaseAndOffset(const MachineInstr *MI,
if (isPostIncrement(MI))
Offset = 0;
else {
- Offset = MI->getOperand(offsetPos).getImm();
+ Offset = MI.getOperand(offsetPos).getImm();
}
- return MI->getOperand(basePos).getReg();
+ return MI.getOperand(basePos).getReg();
}
-
/// Return the position of the base and offset operands for this instruction.
-bool HexagonInstrInfo::getBaseAndOffsetPosition(const MachineInstr *MI,
+bool HexagonInstrInfo::getBaseAndOffsetPosition(const MachineInstr &MI,
unsigned &BasePos, unsigned &OffsetPos) const {
// Deal with memops first.
if (isMemOp(MI)) {
BasePos = 0;
OffsetPos = 1;
- } else if (MI->mayStore()) {
+ } else if (MI.mayStore()) {
BasePos = 0;
OffsetPos = 1;
- } else if (MI->mayLoad()) {
+ } else if (MI.mayLoad()) {
BasePos = 1;
OffsetPos = 2;
} else
return false;
- if (isPredicated(*MI)) {
+ if (isPredicated(MI)) {
BasePos++;
OffsetPos++;
}
@@ -3124,14 +3106,13 @@ bool HexagonInstrInfo::getBaseAndOffsetPosition(const MachineInstr *MI,
OffsetPos++;
}
- if (!MI->getOperand(BasePos).isReg() || !MI->getOperand(OffsetPos).isImm())
+ if (!MI.getOperand(BasePos).isReg() || !MI.getOperand(OffsetPos).isImm())
return false;
return true;
}
-
-// Inserts branching instructions in reverse order of their occurence.
+// Inserts branching instructions in reverse order of their occurrence.
// e.g. jump_t t1 (i1)
// jump t2 (i2)
// Jumpers = {i2, i1}
@@ -3192,37 +3173,33 @@ SmallVector<MachineInstr*, 2> HexagonInstrInfo::getBranchingInstrs(
return Jumpers;
}
-
short HexagonInstrInfo::getBaseWithLongOffset(short Opcode) const {
if (Opcode < 0)
return -1;
return Hexagon::getBaseWithLongOffset(Opcode);
}
-
-short HexagonInstrInfo::getBaseWithLongOffset(const MachineInstr *MI) const {
- return Hexagon::getBaseWithLongOffset(MI->getOpcode());
+short HexagonInstrInfo::getBaseWithLongOffset(const MachineInstr &MI) const {
+ return Hexagon::getBaseWithLongOffset(MI.getOpcode());
}
-
-short HexagonInstrInfo::getBaseWithRegOffset(const MachineInstr *MI) const {
- return Hexagon::getBaseWithRegOffset(MI->getOpcode());
+short HexagonInstrInfo::getBaseWithRegOffset(const MachineInstr &MI) const {
+ return Hexagon::getBaseWithRegOffset(MI.getOpcode());
}
-
// Returns Operand Index for the constant extended instruction.
-unsigned HexagonInstrInfo::getCExtOpNum(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+unsigned HexagonInstrInfo::getCExtOpNum(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::ExtendableOpPos) & HexagonII::ExtendableOpMask;
}
// See if instruction could potentially be a duplex candidate.
// If so, return its group. Zero otherwise.
HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
- const MachineInstr *MI) const {
+ const MachineInstr &MI) const {
unsigned DstReg, SrcReg, Src1Reg, Src2Reg;
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
default:
return HexagonII::HCG_None;
//
@@ -3234,9 +3211,9 @@ HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
case Hexagon::C2_cmpeq:
case Hexagon::C2_cmpgt:
case Hexagon::C2_cmpgtu:
- DstReg = MI->getOperand(0).getReg();
- Src1Reg = MI->getOperand(1).getReg();
- Src2Reg = MI->getOperand(2).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ Src1Reg = MI.getOperand(1).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
if (Hexagon::PredRegsRegClass.contains(DstReg) &&
(Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
isIntRegForSubInst(Src1Reg) && isIntRegForSubInst(Src2Reg))
@@ -3246,19 +3223,19 @@ HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
case Hexagon::C2_cmpgti:
case Hexagon::C2_cmpgtui:
// P0 = cmp.eq(Rs,#u2)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (Hexagon::PredRegsRegClass.contains(DstReg) &&
(Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
- isIntRegForSubInst(SrcReg) && MI->getOperand(2).isImm() &&
- ((isUInt<5>(MI->getOperand(2).getImm())) ||
- (MI->getOperand(2).getImm() == -1)))
+ isIntRegForSubInst(SrcReg) && MI.getOperand(2).isImm() &&
+ ((isUInt<5>(MI.getOperand(2).getImm())) ||
+ (MI.getOperand(2).getImm() == -1)))
return HexagonII::HCG_A;
break;
case Hexagon::A2_tfr:
// Rd = Rs
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg))
return HexagonII::HCG_A;
break;
@@ -3266,17 +3243,17 @@ HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
// Rd = #u6
// Do not test for #u6 size since the const is getting extended
// regardless and compound could be formed.
- DstReg = MI->getOperand(0).getReg();
+ DstReg = MI.getOperand(0).getReg();
if (isIntRegForSubInst(DstReg))
return HexagonII::HCG_A;
break;
case Hexagon::S2_tstbit_i:
- DstReg = MI->getOperand(0).getReg();
- Src1Reg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ Src1Reg = MI.getOperand(1).getReg();
if (Hexagon::PredRegsRegClass.contains(DstReg) &&
(Hexagon::P0 == DstReg || Hexagon::P1 == DstReg) &&
- MI->getOperand(2).isImm() &&
- isIntRegForSubInst(Src1Reg) && (MI->getOperand(2).getImm() == 0))
+ MI.getOperand(2).isImm() &&
+ isIntRegForSubInst(Src1Reg) && (MI.getOperand(2).getImm() == 0))
return HexagonII::HCG_A;
break;
// The fact that .new form is used pretty much guarantees
@@ -3287,7 +3264,7 @@ HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
case Hexagon::J2_jumpfnew:
case Hexagon::J2_jumptnewpt:
case Hexagon::J2_jumpfnewpt:
- Src1Reg = MI->getOperand(0).getReg();
+ Src1Reg = MI.getOperand(0).getReg();
if (Hexagon::PredRegsRegClass.contains(Src1Reg) &&
(Hexagon::P0 == Src1Reg || Hexagon::P1 == Src1Reg))
return HexagonII::HCG_B;
@@ -3298,6 +3275,7 @@ HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
// Do not test for jump range here.
case Hexagon::J2_jump:
case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
+ case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC:
return HexagonII::HCG_C;
break;
}
@@ -3305,17 +3283,16 @@ HexagonII::CompoundGroup HexagonInstrInfo::getCompoundCandidateGroup(
return HexagonII::HCG_None;
}
-
// Returns -1 when there is no opcode found.
-unsigned HexagonInstrInfo::getCompoundOpcode(const MachineInstr *GA,
- const MachineInstr *GB) const {
+unsigned HexagonInstrInfo::getCompoundOpcode(const MachineInstr &GA,
+ const MachineInstr &GB) const {
assert(getCompoundCandidateGroup(GA) == HexagonII::HCG_A);
assert(getCompoundCandidateGroup(GB) == HexagonII::HCG_B);
- if ((GA->getOpcode() != Hexagon::C2_cmpeqi) ||
- (GB->getOpcode() != Hexagon::J2_jumptnew))
+ if ((GA.getOpcode() != Hexagon::C2_cmpeqi) ||
+ (GB.getOpcode() != Hexagon::J2_jumptnew))
return -1;
- unsigned DestReg = GA->getOperand(0).getReg();
- if (!GB->readsRegister(DestReg))
+ unsigned DestReg = GA.getOperand(0).getReg();
+ if (!GB.readsRegister(DestReg))
return -1;
if (DestReg == Hexagon::P0)
return Hexagon::J4_cmpeqi_tp0_jump_nt;
@@ -3324,7 +3301,6 @@ unsigned HexagonInstrInfo::getCompoundOpcode(const MachineInstr *GA,
return -1;
}
-
int HexagonInstrInfo::getCondOpcode(int Opc, bool invertPredicate) const {
enum Hexagon::PredSense inPredSense;
inPredSense = invertPredicate ? Hexagon::PredSense_false :
@@ -3333,21 +3309,12 @@ int HexagonInstrInfo::getCondOpcode(int Opc, bool invertPredicate) const {
if (CondOpcode >= 0) // Valid Conditional opcode/instruction
return CondOpcode;
- // This switch case will be removed once all the instructions have been
- // modified to use relation maps.
- switch(Opc) {
- case Hexagon::TFRI_f:
- return !invertPredicate ? Hexagon::TFRI_cPt_f :
- Hexagon::TFRI_cNotPt_f;
- }
-
llvm_unreachable("Unexpected predicable instruction");
}
-
// Return the cur value instruction for a given store.
-int HexagonInstrInfo::getDotCurOp(const MachineInstr* MI) const {
- switch (MI->getOpcode()) {
+int HexagonInstrInfo::getDotCurOp(const MachineInstr &MI) const {
+ switch (MI.getOpcode()) {
default: llvm_unreachable("Unknown .cur type");
case Hexagon::V6_vL32b_pi:
return Hexagon::V6_vL32b_cur_pi;
@@ -3362,8 +3329,6 @@ int HexagonInstrInfo::getDotCurOp(const MachineInstr* MI) const {
return 0;
}
-
-
// The diagram below shows the steps involved in the conversion of a predicated
// store instruction to its .new predicated new-value form.
//
@@ -3443,14 +3408,13 @@ int HexagonInstrInfo::getDotCurOp(const MachineInstr* MI) const {
// promoted. Therefore, in case of dependence check failure (due to R5) during
// next iteration, it should be converted back to its most basic form.
-
// Return the new value instruction for a given store.
-int HexagonInstrInfo::getDotNewOp(const MachineInstr* MI) const {
- int NVOpcode = Hexagon::getNewValueOpcode(MI->getOpcode());
+int HexagonInstrInfo::getDotNewOp(const MachineInstr &MI) const {
+ int NVOpcode = Hexagon::getNewValueOpcode(MI.getOpcode());
if (NVOpcode >= 0) // Valid new-value store instruction.
return NVOpcode;
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
default: llvm_unreachable("Unknown .new type");
case Hexagon::S4_storerb_ur:
return Hexagon::S4_storerbnew_ur;
@@ -3486,23 +3450,22 @@ int HexagonInstrInfo::getDotNewOp(const MachineInstr* MI) const {
return 0;
}
-
// Returns the opcode to use when converting MI, which is a conditional jump,
// into a conditional instruction which uses the .new value of the predicate.
// We also use branch probabilities to add a hint to the jump.
-int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr *MI,
+int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr &MI,
const MachineBranchProbabilityInfo *MBPI) const {
// We assume that block can have at most two successors.
bool taken = false;
- const MachineBasicBlock *Src = MI->getParent();
- const MachineOperand *BrTarget = &MI->getOperand(1);
- const MachineBasicBlock *Dst = BrTarget->getMBB();
+ const MachineBasicBlock *Src = MI.getParent();
+ const MachineOperand &BrTarget = MI.getOperand(1);
+ const MachineBasicBlock *Dst = BrTarget.getMBB();
const BranchProbability Prediction = MBPI->getEdgeProbability(Src, Dst);
if (Prediction >= BranchProbability(1,2))
taken = true;
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
case Hexagon::J2_jumpt:
return taken ? Hexagon::J2_jumptnewpt : Hexagon::J2_jumptnew;
case Hexagon::J2_jumpf:
@@ -3513,15 +3476,14 @@ int HexagonInstrInfo::getDotNewPredJumpOp(const MachineInstr *MI,
}
}
-
// Return .new predicate version for an instruction.
-int HexagonInstrInfo::getDotNewPredOp(const MachineInstr *MI,
+int HexagonInstrInfo::getDotNewPredOp(const MachineInstr &MI,
const MachineBranchProbabilityInfo *MBPI) const {
- int NewOpcode = Hexagon::getPredNewOpcode(MI->getOpcode());
+ int NewOpcode = Hexagon::getPredNewOpcode(MI.getOpcode());
if (NewOpcode >= 0) // Valid predicate new instruction
return NewOpcode;
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
// Condtional Jumps
case Hexagon::J2_jumpt:
case Hexagon::J2_jumpf:
@@ -3533,7 +3495,6 @@ int HexagonInstrInfo::getDotNewPredOp(const MachineInstr *MI,
return 0;
}
-
int HexagonInstrInfo::getDotOldOp(const int opc) const {
int NewOp = opc;
if (isPredicated(NewOp) && isPredicatedNew(NewOp)) { // Get predicate old form
@@ -3549,15 +3510,14 @@ int HexagonInstrInfo::getDotOldOp(const int opc) const {
return NewOp;
}
-
// See if instruction could potentially be a duplex candidate.
// If so, return its group. Zero otherwise.
HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
- const MachineInstr *MI) const {
+ const MachineInstr &MI) const {
unsigned DstReg, SrcReg, Src1Reg, Src2Reg;
auto &HRI = getRegisterInfo();
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
default:
return HexagonII::HSIG_None;
//
@@ -3566,29 +3526,29 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
// Rd = memw(Rs+#u4:2)
// Rd = memub(Rs+#u4:0)
case Hexagon::L2_loadri_io:
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
// Special case this one from Group L2.
// Rd = memw(r29+#u5:2)
if (isIntRegForSubInst(DstReg)) {
if (Hexagon::IntRegsRegClass.contains(SrcReg) &&
HRI.getStackRegister() == SrcReg &&
- MI->getOperand(2).isImm() &&
- isShiftedUInt<5,2>(MI->getOperand(2).getImm()))
+ MI.getOperand(2).isImm() &&
+ isShiftedUInt<5,2>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_L2;
// Rd = memw(Rs+#u4:2)
if (isIntRegForSubInst(SrcReg) &&
- (MI->getOperand(2).isImm() &&
- isShiftedUInt<4,2>(MI->getOperand(2).getImm())))
+ (MI.getOperand(2).isImm() &&
+ isShiftedUInt<4,2>(MI.getOperand(2).getImm())))
return HexagonII::HSIG_L1;
}
break;
case Hexagon::L2_loadrub_io:
// Rd = memub(Rs+#u4:0)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg) &&
- MI->getOperand(2).isImm() && isUInt<4>(MI->getOperand(2).getImm()))
+ MI.getOperand(2).isImm() && isUInt<4>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_L1;
break;
//
@@ -3604,61 +3564,62 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
case Hexagon::L2_loadrh_io:
case Hexagon::L2_loadruh_io:
// Rd = memh/memuh(Rs+#u3:1)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg) &&
- MI->getOperand(2).isImm() &&
- isShiftedUInt<3,1>(MI->getOperand(2).getImm()))
+ MI.getOperand(2).isImm() &&
+ isShiftedUInt<3,1>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_L2;
break;
case Hexagon::L2_loadrb_io:
// Rd = memb(Rs+#u3:0)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg) &&
- MI->getOperand(2).isImm() &&
- isUInt<3>(MI->getOperand(2).getImm()))
+ MI.getOperand(2).isImm() &&
+ isUInt<3>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_L2;
break;
case Hexagon::L2_loadrd_io:
// Rdd = memd(r29+#u5:3)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isDblRegForSubInst(DstReg, HRI) &&
Hexagon::IntRegsRegClass.contains(SrcReg) &&
HRI.getStackRegister() == SrcReg &&
- MI->getOperand(2).isImm() &&
- isShiftedUInt<5,3>(MI->getOperand(2).getImm()))
+ MI.getOperand(2).isImm() &&
+ isShiftedUInt<5,3>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_L2;
break;
// dealloc_return is not documented in Hexagon Manual, but marked
// with A_SUBINSN attribute in iset_v4classic.py.
case Hexagon::RESTORE_DEALLOC_RET_JMP_V4:
+ case Hexagon::RESTORE_DEALLOC_RET_JMP_V4_PIC:
case Hexagon::L4_return:
case Hexagon::L2_deallocframe:
return HexagonII::HSIG_L2;
case Hexagon::EH_RETURN_JMPR:
- case Hexagon::JMPret :
+ case Hexagon::PS_jmpret:
// jumpr r31
// Actual form JMPR %PC<imp-def>, %R31<imp-use>, %R0<imp-use,internal>.
- DstReg = MI->getOperand(0).getReg();
+ DstReg = MI.getOperand(0).getReg();
if (Hexagon::IntRegsRegClass.contains(DstReg) && (Hexagon::R31 == DstReg))
return HexagonII::HSIG_L2;
break;
- case Hexagon::JMPrett:
- case Hexagon::JMPretf:
- case Hexagon::JMPrettnewpt:
- case Hexagon::JMPretfnewpt :
- case Hexagon::JMPrettnew :
- case Hexagon::JMPretfnew :
- DstReg = MI->getOperand(1).getReg();
- SrcReg = MI->getOperand(0).getReg();
+ case Hexagon::PS_jmprett:
+ case Hexagon::PS_jmpretf:
+ case Hexagon::PS_jmprettnewpt:
+ case Hexagon::PS_jmpretfnewpt:
+ case Hexagon::PS_jmprettnew:
+ case Hexagon::PS_jmpretfnew:
+ DstReg = MI.getOperand(1).getReg();
+ SrcReg = MI.getOperand(0).getReg();
// [if ([!]p0[.new])] jumpr r31
if ((Hexagon::PredRegsRegClass.contains(SrcReg) &&
(Hexagon::P0 == SrcReg)) &&
(Hexagon::IntRegsRegClass.contains(DstReg) && (Hexagon::R31 == DstReg)))
return HexagonII::HSIG_L2;
- break;
+ break;
case Hexagon::L4_return_t :
case Hexagon::L4_return_f :
case Hexagon::L4_return_tnew_pnt :
@@ -3666,7 +3627,7 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
case Hexagon::L4_return_tnew_pt :
case Hexagon::L4_return_fnew_pt :
// [if ([!]p0[.new])] dealloc_return
- SrcReg = MI->getOperand(0).getReg();
+ SrcReg = MI.getOperand(0).getReg();
if (Hexagon::PredRegsRegClass.contains(SrcReg) && (Hexagon::P0 == SrcReg))
return HexagonII::HSIG_L2;
break;
@@ -3678,25 +3639,25 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
case Hexagon::S2_storeri_io:
// Special case this one from Group S2.
// memw(r29+#u5:2) = Rt
- Src1Reg = MI->getOperand(0).getReg();
- Src2Reg = MI->getOperand(2).getReg();
+ Src1Reg = MI.getOperand(0).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
if (Hexagon::IntRegsRegClass.contains(Src1Reg) &&
isIntRegForSubInst(Src2Reg) &&
- HRI.getStackRegister() == Src1Reg && MI->getOperand(1).isImm() &&
- isShiftedUInt<5,2>(MI->getOperand(1).getImm()))
+ HRI.getStackRegister() == Src1Reg && MI.getOperand(1).isImm() &&
+ isShiftedUInt<5,2>(MI.getOperand(1).getImm()))
return HexagonII::HSIG_S2;
// memw(Rs+#u4:2) = Rt
if (isIntRegForSubInst(Src1Reg) && isIntRegForSubInst(Src2Reg) &&
- MI->getOperand(1).isImm() &&
- isShiftedUInt<4,2>(MI->getOperand(1).getImm()))
+ MI.getOperand(1).isImm() &&
+ isShiftedUInt<4,2>(MI.getOperand(1).getImm()))
return HexagonII::HSIG_S1;
break;
case Hexagon::S2_storerb_io:
// memb(Rs+#u4:0) = Rt
- Src1Reg = MI->getOperand(0).getReg();
- Src2Reg = MI->getOperand(2).getReg();
+ Src1Reg = MI.getOperand(0).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
if (isIntRegForSubInst(Src1Reg) && isIntRegForSubInst(Src2Reg) &&
- MI->getOperand(1).isImm() && isUInt<4>(MI->getOperand(1).getImm()))
+ MI.getOperand(1).isImm() && isUInt<4>(MI.getOperand(1).getImm()))
return HexagonII::HSIG_S1;
break;
//
@@ -3710,42 +3671,42 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
// allocframe(#u5:3)
case Hexagon::S2_storerh_io:
// memh(Rs+#u3:1) = Rt
- Src1Reg = MI->getOperand(0).getReg();
- Src2Reg = MI->getOperand(2).getReg();
+ Src1Reg = MI.getOperand(0).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
if (isIntRegForSubInst(Src1Reg) && isIntRegForSubInst(Src2Reg) &&
- MI->getOperand(1).isImm() &&
- isShiftedUInt<3,1>(MI->getOperand(1).getImm()))
+ MI.getOperand(1).isImm() &&
+ isShiftedUInt<3,1>(MI.getOperand(1).getImm()))
return HexagonII::HSIG_S1;
break;
case Hexagon::S2_storerd_io:
// memd(r29+#s6:3) = Rtt
- Src1Reg = MI->getOperand(0).getReg();
- Src2Reg = MI->getOperand(2).getReg();
+ Src1Reg = MI.getOperand(0).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
if (isDblRegForSubInst(Src2Reg, HRI) &&
Hexagon::IntRegsRegClass.contains(Src1Reg) &&
- HRI.getStackRegister() == Src1Reg && MI->getOperand(1).isImm() &&
- isShiftedInt<6,3>(MI->getOperand(1).getImm()))
+ HRI.getStackRegister() == Src1Reg && MI.getOperand(1).isImm() &&
+ isShiftedInt<6,3>(MI.getOperand(1).getImm()))
return HexagonII::HSIG_S2;
break;
case Hexagon::S4_storeiri_io:
// memw(Rs+#u4:2) = #U1
- Src1Reg = MI->getOperand(0).getReg();
- if (isIntRegForSubInst(Src1Reg) && MI->getOperand(1).isImm() &&
- isShiftedUInt<4,2>(MI->getOperand(1).getImm()) &&
- MI->getOperand(2).isImm() && isUInt<1>(MI->getOperand(2).getImm()))
+ Src1Reg = MI.getOperand(0).getReg();
+ if (isIntRegForSubInst(Src1Reg) && MI.getOperand(1).isImm() &&
+ isShiftedUInt<4,2>(MI.getOperand(1).getImm()) &&
+ MI.getOperand(2).isImm() && isUInt<1>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_S2;
break;
case Hexagon::S4_storeirb_io:
// memb(Rs+#u4) = #U1
- Src1Reg = MI->getOperand(0).getReg();
+ Src1Reg = MI.getOperand(0).getReg();
if (isIntRegForSubInst(Src1Reg) &&
- MI->getOperand(1).isImm() && isUInt<4>(MI->getOperand(1).getImm()) &&
- MI->getOperand(2).isImm() && isUInt<1>(MI->getOperand(2).getImm()))
+ MI.getOperand(1).isImm() && isUInt<4>(MI.getOperand(1).getImm()) &&
+ MI.getOperand(2).isImm() && isUInt<1>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_S2;
break;
case Hexagon::S2_allocframe:
- if (MI->getOperand(0).isImm() &&
- isShiftedUInt<5,3>(MI->getOperand(0).getImm()))
+ if (MI.getOperand(0).isImm() &&
+ isShiftedUInt<5,3>(MI.getOperand(0).getImm()))
return HexagonII::HSIG_S1;
break;
//
@@ -3767,31 +3728,31 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
// Rd = sxth/sxtb/zxtb/zxth(Rs)
// Rd = and(Rs,#1)
case Hexagon::A2_addi:
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg)) {
// Rd = add(r29,#u6:2)
if (Hexagon::IntRegsRegClass.contains(SrcReg) &&
- HRI.getStackRegister() == SrcReg && MI->getOperand(2).isImm() &&
- isShiftedUInt<6,2>(MI->getOperand(2).getImm()))
+ HRI.getStackRegister() == SrcReg && MI.getOperand(2).isImm() &&
+ isShiftedUInt<6,2>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_A;
// Rx = add(Rx,#s7)
- if ((DstReg == SrcReg) && MI->getOperand(2).isImm() &&
- isInt<7>(MI->getOperand(2).getImm()))
+ if ((DstReg == SrcReg) && MI.getOperand(2).isImm() &&
+ isInt<7>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_A;
// Rd = add(Rs,#1)
// Rd = add(Rs,#-1)
- if (isIntRegForSubInst(SrcReg) && MI->getOperand(2).isImm() &&
- ((MI->getOperand(2).getImm() == 1) ||
- (MI->getOperand(2).getImm() == -1)))
+ if (isIntRegForSubInst(SrcReg) && MI.getOperand(2).isImm() &&
+ ((MI.getOperand(2).getImm() == 1) ||
+ (MI.getOperand(2).getImm() == -1)))
return HexagonII::HSIG_A;
}
break;
case Hexagon::A2_add:
// Rx = add(Rx,Rs)
- DstReg = MI->getOperand(0).getReg();
- Src1Reg = MI->getOperand(1).getReg();
- Src2Reg = MI->getOperand(2).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ Src1Reg = MI.getOperand(1).getReg();
+ Src2Reg = MI.getOperand(2).getReg();
if (isIntRegForSubInst(DstReg) && (DstReg == Src1Reg) &&
isIntRegForSubInst(Src2Reg))
return HexagonII::HSIG_A;
@@ -3800,18 +3761,18 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
// Same as zxtb.
// Rd16=and(Rs16,#255)
// Rd16=and(Rs16,#1)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg) &&
- MI->getOperand(2).isImm() &&
- ((MI->getOperand(2).getImm() == 1) ||
- (MI->getOperand(2).getImm() == 255)))
+ MI.getOperand(2).isImm() &&
+ ((MI.getOperand(2).getImm() == 1) ||
+ (MI.getOperand(2).getImm() == 255)))
return HexagonII::HSIG_A;
break;
case Hexagon::A2_tfr:
// Rd = Rs
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg))
return HexagonII::HSIG_A;
break;
@@ -3820,7 +3781,7 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
// Do not test for #u6 size since the const is getting extended
// regardless and compound could be formed.
// Rd = #-1
- DstReg = MI->getOperand(0).getReg();
+ DstReg = MI.getOperand(0).getReg();
if (isIntRegForSubInst(DstReg))
return HexagonII::HSIG_A;
break;
@@ -3831,51 +3792,51 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
// if ([!]P0[.new]) Rd = #0
// Actual form:
// %R16<def> = C2_cmovenewit %P0<internal>, 0, %R16<imp-use,undef>;
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) &&
Hexagon::PredRegsRegClass.contains(SrcReg) && Hexagon::P0 == SrcReg &&
- MI->getOperand(2).isImm() && MI->getOperand(2).getImm() == 0)
+ MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0)
return HexagonII::HSIG_A;
break;
case Hexagon::C2_cmpeqi:
// P0 = cmp.eq(Rs,#u2)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (Hexagon::PredRegsRegClass.contains(DstReg) &&
Hexagon::P0 == DstReg && isIntRegForSubInst(SrcReg) &&
- MI->getOperand(2).isImm() && isUInt<2>(MI->getOperand(2).getImm()))
+ MI.getOperand(2).isImm() && isUInt<2>(MI.getOperand(2).getImm()))
return HexagonII::HSIG_A;
break;
case Hexagon::A2_combineii:
case Hexagon::A4_combineii:
// Rdd = combine(#u2,#U2)
- DstReg = MI->getOperand(0).getReg();
+ DstReg = MI.getOperand(0).getReg();
if (isDblRegForSubInst(DstReg, HRI) &&
- ((MI->getOperand(1).isImm() && isUInt<2>(MI->getOperand(1).getImm())) ||
- (MI->getOperand(1).isGlobal() &&
- isUInt<2>(MI->getOperand(1).getOffset()))) &&
- ((MI->getOperand(2).isImm() && isUInt<2>(MI->getOperand(2).getImm())) ||
- (MI->getOperand(2).isGlobal() &&
- isUInt<2>(MI->getOperand(2).getOffset()))))
+ ((MI.getOperand(1).isImm() && isUInt<2>(MI.getOperand(1).getImm())) ||
+ (MI.getOperand(1).isGlobal() &&
+ isUInt<2>(MI.getOperand(1).getOffset()))) &&
+ ((MI.getOperand(2).isImm() && isUInt<2>(MI.getOperand(2).getImm())) ||
+ (MI.getOperand(2).isGlobal() &&
+ isUInt<2>(MI.getOperand(2).getOffset()))))
return HexagonII::HSIG_A;
break;
case Hexagon::A4_combineri:
// Rdd = combine(Rs,#0)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isDblRegForSubInst(DstReg, HRI) && isIntRegForSubInst(SrcReg) &&
- ((MI->getOperand(2).isImm() && MI->getOperand(2).getImm() == 0) ||
- (MI->getOperand(2).isGlobal() && MI->getOperand(2).getOffset() == 0)))
+ ((MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) ||
+ (MI.getOperand(2).isGlobal() && MI.getOperand(2).getOffset() == 0)))
return HexagonII::HSIG_A;
break;
case Hexagon::A4_combineir:
// Rdd = combine(#0,Rs)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(2).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(2).getReg();
if (isDblRegForSubInst(DstReg, HRI) && isIntRegForSubInst(SrcReg) &&
- ((MI->getOperand(1).isImm() && MI->getOperand(1).getImm() == 0) ||
- (MI->getOperand(1).isGlobal() && MI->getOperand(1).getOffset() == 0)))
+ ((MI.getOperand(1).isImm() && MI.getOperand(1).getImm() == 0) ||
+ (MI.getOperand(1).isGlobal() && MI.getOperand(1).getOffset() == 0)))
return HexagonII::HSIG_A;
break;
case Hexagon::A2_sxtb:
@@ -3883,8 +3844,8 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
case Hexagon::A2_zxtb:
case Hexagon::A2_zxth:
// Rd = sxth/sxtb/zxtb/zxth(Rs)
- DstReg = MI->getOperand(0).getReg();
- SrcReg = MI->getOperand(1).getReg();
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
if (isIntRegForSubInst(DstReg) && isIntRegForSubInst(SrcReg))
return HexagonII::HSIG_A;
break;
@@ -3893,47 +3854,43 @@ HexagonII::SubInstructionGroup HexagonInstrInfo::getDuplexCandidateGroup(
return HexagonII::HSIG_None;
}
-
-short HexagonInstrInfo::getEquivalentHWInstr(const MachineInstr *MI) const {
- return Hexagon::getRealHWInstr(MI->getOpcode(), Hexagon::InstrType_Real);
+short HexagonInstrInfo::getEquivalentHWInstr(const MachineInstr &MI) const {
+ return Hexagon::getRealHWInstr(MI.getOpcode(), Hexagon::InstrType_Real);
}
-
// Return first non-debug instruction in the basic block.
MachineInstr *HexagonInstrInfo::getFirstNonDbgInst(MachineBasicBlock *BB)
const {
for (auto MII = BB->instr_begin(), End = BB->instr_end(); MII != End; MII++) {
- MachineInstr *MI = &*MII;
- if (MI->isDebugValue())
+ MachineInstr &MI = *MII;
+ if (MI.isDebugValue())
continue;
- return MI;
+ return &MI;
}
return nullptr;
}
-
unsigned HexagonInstrInfo::getInstrTimingClassLatency(
- const InstrItineraryData *ItinData, const MachineInstr *MI) const {
+ const InstrItineraryData *ItinData, const MachineInstr &MI) const {
// Default to one cycle for no itinerary. However, an "empty" itinerary may
// still have a MinLatency property, which getStageLatency checks.
if (!ItinData)
- return getInstrLatency(ItinData, *MI);
+ return getInstrLatency(ItinData, MI);
// Get the latency embedded in the itinerary. If we're not using timing class
// latencies or if we using BSB scheduling, then restrict the maximum latency
// to 1 (that is, either 0 or 1).
- if (MI->isTransient())
+ if (MI.isTransient())
return 0;
- unsigned Latency = ItinData->getStageLatency(MI->getDesc().getSchedClass());
+ unsigned Latency = ItinData->getStageLatency(MI.getDesc().getSchedClass());
if (!EnableTimingClassLatency ||
- MI->getParent()->getParent()->getSubtarget<HexagonSubtarget>().
+ MI.getParent()->getParent()->getSubtarget<HexagonSubtarget>().
useBSBScheduling())
if (Latency > 1)
Latency = 1;
return Latency;
}
-
// inverts the predication logic.
// p -> NotP
// NotP -> P
@@ -3946,7 +3903,6 @@ bool HexagonInstrInfo::getInvertedPredSense(
return true;
}
-
unsigned HexagonInstrInfo::getInvertedPredicatedOpcode(const int Opc) const {
int InvPredOpcode;
InvPredOpcode = isPredicatedTrue(Opc) ? Hexagon::getFalsePredOpcode(Opc)
@@ -3957,10 +3913,9 @@ unsigned HexagonInstrInfo::getInvertedPredicatedOpcode(const int Opc) const {
llvm_unreachable("Unexpected predicated instruction");
}
-
// Returns the max value that doesn't need to be extended.
-int HexagonInstrInfo::getMaxValue(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+int HexagonInstrInfo::getMaxValue(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
unsigned isSigned = (F >> HexagonII::ExtentSignedPos)
& HexagonII::ExtentSignedMask;
unsigned bits = (F >> HexagonII::ExtentBitsPos)
@@ -3972,16 +3927,14 @@ int HexagonInstrInfo::getMaxValue(const MachineInstr *MI) const {
return ~(-1U << bits);
}
-
-unsigned HexagonInstrInfo::getMemAccessSize(const MachineInstr* MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+unsigned HexagonInstrInfo::getMemAccessSize(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::MemAccessSizePos) & HexagonII::MemAccesSizeMask;
}
-
// Returns the min value that doesn't need to be extended.
-int HexagonInstrInfo::getMinValue(const MachineInstr *MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+int HexagonInstrInfo::getMinValue(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
unsigned isSigned = (F >> HexagonII::ExtentSignedPos)
& HexagonII::ExtentSignedMask;
unsigned bits = (F >> HexagonII::ExtentBitsPos)
@@ -3993,24 +3946,23 @@ int HexagonInstrInfo::getMinValue(const MachineInstr *MI) const {
return 0;
}
-
// Returns opcode of the non-extended equivalent instruction.
-short HexagonInstrInfo::getNonExtOpcode(const MachineInstr *MI) const {
+short HexagonInstrInfo::getNonExtOpcode(const MachineInstr &MI) const {
// Check if the instruction has a register form that uses register in place
// of the extended operand, if so return that as the non-extended form.
- short NonExtOpcode = Hexagon::getRegForm(MI->getOpcode());
+ short NonExtOpcode = Hexagon::getRegForm(MI.getOpcode());
if (NonExtOpcode >= 0)
return NonExtOpcode;
- if (MI->getDesc().mayLoad() || MI->getDesc().mayStore()) {
+ if (MI.getDesc().mayLoad() || MI.getDesc().mayStore()) {
// Check addressing mode and retrieve non-ext equivalent instruction.
switch (getAddrMode(MI)) {
case HexagonII::Absolute :
- return Hexagon::getBaseWithImmOffset(MI->getOpcode());
+ return Hexagon::getBaseWithImmOffset(MI.getOpcode());
case HexagonII::BaseImmOffset :
- return Hexagon::getBaseWithRegOffset(MI->getOpcode());
+ return Hexagon::getBaseWithRegOffset(MI.getOpcode());
case HexagonII::BaseLongOffset:
- return Hexagon::getRegShlForm(MI->getOpcode());
+ return Hexagon::getRegShlForm(MI.getOpcode());
default:
return -1;
@@ -4019,15 +3971,14 @@ short HexagonInstrInfo::getNonExtOpcode(const MachineInstr *MI) const {
return -1;
}
-
bool HexagonInstrInfo::getPredReg(ArrayRef<MachineOperand> Cond,
unsigned &PredReg, unsigned &PredRegPos, unsigned &PredRegFlags) const {
if (Cond.empty())
return false;
assert(Cond.size() == 2);
if (isNewValueJump(Cond[0].getImm()) || Cond[1].isMBB()) {
- DEBUG(dbgs() << "No predregs for new-value jumps/endloop");
- return false;
+ DEBUG(dbgs() << "No predregs for new-value jumps/endloop");
+ return false;
}
PredReg = Cond[1].getReg();
PredRegPos = 1;
@@ -4040,26 +3991,23 @@ bool HexagonInstrInfo::getPredReg(ArrayRef<MachineOperand> Cond,
return true;
}
-
-short HexagonInstrInfo::getPseudoInstrPair(const MachineInstr *MI) const {
- return Hexagon::getRealHWInstr(MI->getOpcode(), Hexagon::InstrType_Pseudo);
+short HexagonInstrInfo::getPseudoInstrPair(const MachineInstr &MI) const {
+ return Hexagon::getRealHWInstr(MI.getOpcode(), Hexagon::InstrType_Pseudo);
}
-
-short HexagonInstrInfo::getRegForm(const MachineInstr *MI) const {
- return Hexagon::getRegForm(MI->getOpcode());
+short HexagonInstrInfo::getRegForm(const MachineInstr &MI) const {
+ return Hexagon::getRegForm(MI.getOpcode());
}
-
// Return the number of bytes required to encode the instruction.
// Hexagon instructions are fixed length, 4 bytes, unless they
// use a constant extender, which requires another 4 bytes.
// For debug instructions and prolog labels, return 0.
-unsigned HexagonInstrInfo::getSize(const MachineInstr *MI) const {
- if (MI->isDebugValue() || MI->isPosition())
+unsigned HexagonInstrInfo::getSize(const MachineInstr &MI) const {
+ if (MI.isDebugValue() || MI.isPosition())
return 0;
- unsigned Size = MI->getDesc().getSize();
+ unsigned Size = MI.getDesc().getSize();
if (!Size)
// Assume the default insn size in case it cannot be determined
// for whatever reason.
@@ -4069,71 +4017,65 @@ unsigned HexagonInstrInfo::getSize(const MachineInstr *MI) const {
Size += HEXAGON_INSTR_SIZE;
// Try and compute number of instructions in asm.
- if (BranchRelaxAsmLarge && MI->getOpcode() == Hexagon::INLINEASM) {
- const MachineBasicBlock &MBB = *MI->getParent();
+ if (BranchRelaxAsmLarge && MI.getOpcode() == Hexagon::INLINEASM) {
+ const MachineBasicBlock &MBB = *MI.getParent();
const MachineFunction *MF = MBB.getParent();
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
// Count the number of register definitions to find the asm string.
unsigned NumDefs = 0;
- for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef();
+ for (; MI.getOperand(NumDefs).isReg() && MI.getOperand(NumDefs).isDef();
++NumDefs)
- assert(NumDefs != MI->getNumOperands()-2 && "No asm string?");
+ assert(NumDefs != MI.getNumOperands()-2 && "No asm string?");
- assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?");
+ assert(MI.getOperand(NumDefs).isSymbol() && "No asm string?");
// Disassemble the AsmStr and approximate number of instructions.
- const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
+ const char *AsmStr = MI.getOperand(NumDefs).getSymbolName();
Size = getInlineAsmLength(AsmStr, *MAI);
}
return Size;
}
-
-uint64_t HexagonInstrInfo::getType(const MachineInstr* MI) const {
- const uint64_t F = MI->getDesc().TSFlags;
+uint64_t HexagonInstrInfo::getType(const MachineInstr &MI) const {
+ const uint64_t F = MI.getDesc().TSFlags;
return (F >> HexagonII::TypePos) & HexagonII::TypeMask;
}
-
-unsigned HexagonInstrInfo::getUnits(const MachineInstr* MI) const {
- const TargetSubtargetInfo &ST = MI->getParent()->getParent()->getSubtarget();
+unsigned HexagonInstrInfo::getUnits(const MachineInstr &MI) const {
+ const TargetSubtargetInfo &ST = MI.getParent()->getParent()->getSubtarget();
const InstrItineraryData &II = *ST.getInstrItineraryData();
- const InstrStage &IS = *II.beginStage(MI->getDesc().getSchedClass());
+ const InstrStage &IS = *II.beginStage(MI.getDesc().getSchedClass());
return IS.getUnits();
}
-
unsigned HexagonInstrInfo::getValidSubTargets(const unsigned Opcode) const {
const uint64_t F = get(Opcode).TSFlags;
return (F >> HexagonII::validSubTargetPos) & HexagonII::validSubTargetMask;
}
-
// Calculate size of the basic block without debug instructions.
unsigned HexagonInstrInfo::nonDbgBBSize(const MachineBasicBlock *BB) const {
return nonDbgMICount(BB->instr_begin(), BB->instr_end());
}
-
unsigned HexagonInstrInfo::nonDbgBundleSize(
MachineBasicBlock::const_iterator BundleHead) const {
assert(BundleHead->isBundle() && "Not a bundle header");
auto MII = BundleHead.getInstrIterator();
// Skip the bundle header.
- return nonDbgMICount(++MII, getBundleEnd(*BundleHead));
+ return nonDbgMICount(++MII, getBundleEnd(BundleHead.getInstrIterator()));
}
-
/// immediateExtend - Changes the instruction in place to one using an immediate
/// extender.
-void HexagonInstrInfo::immediateExtend(MachineInstr *MI) const {
+void HexagonInstrInfo::immediateExtend(MachineInstr &MI) const {
assert((isExtendable(MI)||isConstExtended(MI)) &&
"Instruction must be extendable");
// Find which operand is extendable.
short ExtOpNum = getCExtOpNum(MI);
- MachineOperand &MO = MI->getOperand(ExtOpNum);
+ MachineOperand &MO = MI.getOperand(ExtOpNum);
// This needs to be something we understand.
assert((MO.isMBB() || MO.isImm()) &&
"Branch with unknown extendable field type");
@@ -4141,40 +4083,37 @@ void HexagonInstrInfo::immediateExtend(MachineInstr *MI) const {
MO.addTargetFlag(HexagonII::HMOTF_ConstExtended);
}
-
bool HexagonInstrInfo::invertAndChangeJumpTarget(
- MachineInstr* MI, MachineBasicBlock* NewTarget) const {
+ MachineInstr &MI, MachineBasicBlock *NewTarget) const {
DEBUG(dbgs() << "\n[invertAndChangeJumpTarget] to BB#"
- << NewTarget->getNumber(); MI->dump(););
- assert(MI->isBranch());
- unsigned NewOpcode = getInvertedPredicatedOpcode(MI->getOpcode());
- int TargetPos = MI->getNumOperands() - 1;
+ << NewTarget->getNumber(); MI.dump(););
+ assert(MI.isBranch());
+ unsigned NewOpcode = getInvertedPredicatedOpcode(MI.getOpcode());
+ int TargetPos = MI.getNumOperands() - 1;
// In general branch target is the last operand,
// but some implicit defs added at the end might change it.
- while ((TargetPos > -1) && !MI->getOperand(TargetPos).isMBB())
+ while ((TargetPos > -1) && !MI.getOperand(TargetPos).isMBB())
--TargetPos;
- assert((TargetPos >= 0) && MI->getOperand(TargetPos).isMBB());
- MI->getOperand(TargetPos).setMBB(NewTarget);
- if (EnableBranchPrediction && isPredicatedNew(*MI)) {
+ assert((TargetPos >= 0) && MI.getOperand(TargetPos).isMBB());
+ MI.getOperand(TargetPos).setMBB(NewTarget);
+ if (EnableBranchPrediction && isPredicatedNew(MI)) {
NewOpcode = reversePrediction(NewOpcode);
}
- MI->setDesc(get(NewOpcode));
+ MI.setDesc(get(NewOpcode));
return true;
}
-
void HexagonInstrInfo::genAllInsnTimingClasses(MachineFunction &MF) const {
/* +++ The code below is used to generate complete set of Hexagon Insn +++ */
MachineFunction::iterator A = MF.begin();
MachineBasicBlock &B = *A;
MachineBasicBlock::iterator I = B.begin();
- MachineInstr *MI = &*I;
- DebugLoc DL = MI->getDebugLoc();
+ DebugLoc DL = I->getDebugLoc();
MachineInstr *NewMI;
for (unsigned insn = TargetOpcode::GENERIC_OP_END+1;
insn < Hexagon::INSTRUCTION_LIST_END; ++insn) {
- NewMI = BuildMI(B, MI, DL, get(insn));
+ NewMI = BuildMI(B, I, DL, get(insn));
DEBUG(dbgs() << "\n" << getName(NewMI->getOpcode()) <<
" Class: " << NewMI->getDesc().getSchedClass());
NewMI->eraseFromParent();
@@ -4182,17 +4121,15 @@ void HexagonInstrInfo::genAllInsnTimingClasses(MachineFunction &MF) const {
/* --- The code above is used to generate complete set of Hexagon Insn --- */
}
-
// inverts the predication logic.
// p -> NotP
// NotP -> P
-bool HexagonInstrInfo::reversePredSense(MachineInstr* MI) const {
- DEBUG(dbgs() << "\nTrying to reverse pred. sense of:"; MI->dump());
- MI->setDesc(get(getInvertedPredicatedOpcode(MI->getOpcode())));
+bool HexagonInstrInfo::reversePredSense(MachineInstr &MI) const {
+ DEBUG(dbgs() << "\nTrying to reverse pred. sense of:"; MI.dump());
+ MI.setDesc(get(getInvertedPredicatedOpcode(MI.getOpcode())));
return true;
}
-
// Reverse the branch prediction.
unsigned HexagonInstrInfo::reversePrediction(unsigned Opcode) const {
int PredRevOpcode = -1;
@@ -4204,14 +4141,12 @@ unsigned HexagonInstrInfo::reversePrediction(unsigned Opcode) const {
return PredRevOpcode;
}
-
// TODO: Add more rigorous validation.
bool HexagonInstrInfo::validateBranchCond(const ArrayRef<MachineOperand> &Cond)
const {
return Cond.empty() || (Cond[0].isImm() && (Cond.size() != 1));
}
-
-short HexagonInstrInfo::xformRegToImmOffset(const MachineInstr *MI) const {
- return Hexagon::xformRegToImmOffset(MI->getOpcode());
+short HexagonInstrInfo::xformRegToImmOffset(const MachineInstr &MI) const {
+ return Hexagon::xformRegToImmOffset(MI.getOpcode());
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.h b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
index 66b6883..2358d4b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.h
@@ -16,9 +16,14 @@
#include "HexagonRegisterInfo.h"
#include "MCTargetDesc/HexagonBaseInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
-#include "llvm/Target/TargetFrameLowering.h"
+#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Target/TargetInstrInfo.h"
+#include <cstdint>
+#include <vector>
#define GET_INSTRINFO_HEADER
#include "HexagonGenInstrInfo.inc"
@@ -29,9 +34,10 @@ struct EVT;
class HexagonSubtarget;
class HexagonInstrInfo : public HexagonGenInstrInfo {
- virtual void anchor();
const HexagonRegisterInfo RI;
+ virtual void anchor();
+
public:
explicit HexagonInstrInfo(HexagonSubtarget &ST);
@@ -73,7 +79,7 @@ public:
/// condition. These operands can be passed to other TargetInstrInfo
/// methods to create new branches.
///
- /// Note that RemoveBranch and InsertBranch must be implemented to support
+ /// Note that removeBranch and insertBranch must be implemented to support
/// cases where this method returns success.
///
/// If AllowModify is true, then this routine is allowed to modify the basic
@@ -87,7 +93,8 @@ public:
/// Remove the branching code at the end of the specific MBB.
/// This is only invoked in cases where AnalyzeBranch returns success. It
/// returns the number of instructions that were removed.
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
/// Insert branch code into the end of the specified MachineBasicBlock.
/// The operands to this method are the same as those
@@ -99,9 +106,26 @@ public:
/// cases where AnalyzeBranch doesn't apply because there was no original
/// branch to analyze. At least this much must be implemented, else tail
/// merging needs to be disabled.
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
+
+ /// Analyze the loop code, return true if it cannot be understood. Upon
+ /// success, this function returns false and returns information about the
+ /// induction variable and compare instruction used at the end.
+ bool analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst,
+ MachineInstr *&CmpInst) const override;
+
+ /// Generate code to reduce the loop iteration by one and check if the loop is
+ /// finished. Return the value/register of the the new loop count. We need
+ /// this function when peeling off one or more iterations of a loop. This
+ /// function assumes the nth iteration is peeled first.
+ unsigned reduceLoopCount(MachineBasicBlock &MBB,
+ MachineInstr *IndVar, MachineInstr &Cmp,
+ SmallVectorImpl<MachineOperand> &Cond,
+ SmallVectorImpl<MachineInstr *> &PrevInsts,
+ unsigned Iter, unsigned MaxIter) const override;
/// Return true if it's profitable to predicate
/// instructions with accumulated instruction latency of "NumCycles"
@@ -172,9 +196,14 @@ public:
/// anything was changed.
bool expandPostRAPseudo(MachineInstr &MI) const override;
+ /// \brief Get the base register and byte offset of a load/store instr.
+ bool getMemOpBaseRegImmOfs(MachineInstr &LdSt, unsigned &BaseReg,
+ int64_t &Offset,
+ const TargetRegisterInfo *TRI) const override;
+
/// Reverses the branch condition of the specified condition list,
/// returning false on success and true if it cannot be reversed.
- bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond)
+ bool reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond)
const override;
/// Insert a noop into the instruction stream at the specified point.
@@ -184,6 +213,9 @@ public:
/// Returns true if the instruction is already predicated.
bool isPredicated(const MachineInstr &MI) const override;
+ /// Return true for post-incremented instructions.
+ bool isPostIncrement(const MachineInstr &MI) const override;
+
/// Convert the instruction into a predicated instruction.
/// It returns true if the operation was successful.
bool PredicateInstruction(MachineInstr &MI,
@@ -234,7 +266,7 @@ public:
/// PredCost.
unsigned getInstrLatency(const InstrItineraryData *ItinData,
const MachineInstr &MI,
- unsigned *PredCost = 0) const override;
+ unsigned *PredCost = nullptr) const override;
/// Create machine specific model for scheduling.
DFAPacketizer *
@@ -248,6 +280,16 @@ public:
areMemAccessesTriviallyDisjoint(MachineInstr &MIa, MachineInstr &MIb,
AliasAnalysis *AA = nullptr) const override;
+ /// For instructions with a base and offset, return the position of the
+ /// base register and offset operands.
+ bool getBaseAndOffsetPosition(const MachineInstr &MI, unsigned &BasePos,
+ unsigned &OffsetPos) const override;
+
+ /// If the instruction is an increment of a constant value, return the amount.
+ bool getIncrementValue(const MachineInstr &MI, int &Value) const override;
+
+ bool isTailCall(const MachineInstr &MI) const override;
+
/// HexagonInstrInfo specifics.
///
@@ -255,49 +297,48 @@ public:
unsigned createVR(MachineFunction* MF, MVT VT) const;
- bool isAbsoluteSet(const MachineInstr* MI) const;
- bool isAccumulator(const MachineInstr *MI) const;
- bool isComplex(const MachineInstr *MI) const;
- bool isCompoundBranchInstr(const MachineInstr *MI) const;
- bool isCondInst(const MachineInstr *MI) const;
- bool isConditionalALU32 (const MachineInstr* MI) const;
- bool isConditionalLoad(const MachineInstr* MI) const;
- bool isConditionalStore(const MachineInstr* MI) const;
- bool isConditionalTransfer(const MachineInstr* MI) const;
- bool isConstExtended(const MachineInstr *MI) const;
- bool isDeallocRet(const MachineInstr *MI) const;
- bool isDependent(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) const;
- bool isDotCurInst(const MachineInstr* MI) const;
- bool isDotNewInst(const MachineInstr* MI) const;
- bool isDuplexPair(const MachineInstr *MIa, const MachineInstr *MIb) const;
- bool isEarlySourceInstr(const MachineInstr *MI) const;
+ bool isAbsoluteSet(const MachineInstr &MI) const;
+ bool isAccumulator(const MachineInstr &MI) const;
+ bool isComplex(const MachineInstr &MI) const;
+ bool isCompoundBranchInstr(const MachineInstr &MI) const;
+ bool isCondInst(const MachineInstr &MI) const;
+ bool isConditionalALU32 (const MachineInstr &MI) const;
+ bool isConditionalLoad(const MachineInstr &MI) const;
+ bool isConditionalStore(const MachineInstr &MI) const;
+ bool isConditionalTransfer(const MachineInstr &MI) const;
+ bool isConstExtended(const MachineInstr &MI) const;
+ bool isDeallocRet(const MachineInstr &MI) const;
+ bool isDependent(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) const;
+ bool isDotCurInst(const MachineInstr &MI) const;
+ bool isDotNewInst(const MachineInstr &MI) const;
+ bool isDuplexPair(const MachineInstr &MIa, const MachineInstr &MIb) const;
+ bool isEarlySourceInstr(const MachineInstr &MI) const;
bool isEndLoopN(unsigned Opcode) const;
bool isExpr(unsigned OpType) const;
- bool isExtendable(const MachineInstr* MI) const;
- bool isExtended(const MachineInstr* MI) const;
- bool isFloat(const MachineInstr *MI) const;
- bool isHVXMemWithAIndirect(const MachineInstr *I,
- const MachineInstr *J) const;
- bool isIndirectCall(const MachineInstr *MI) const;
- bool isIndirectL4Return(const MachineInstr *MI) const;
- bool isJumpR(const MachineInstr *MI) const;
- bool isJumpWithinBranchRange(const MachineInstr *MI, unsigned offset) const;
- bool isLateInstrFeedsEarlyInstr(const MachineInstr *LRMI,
- const MachineInstr *ESMI) const;
- bool isLateResultInstr(const MachineInstr *MI) const;
- bool isLateSourceInstr(const MachineInstr *MI) const;
- bool isLoopN(const MachineInstr *MI) const;
- bool isMemOp(const MachineInstr *MI) const;
- bool isNewValue(const MachineInstr* MI) const;
+ bool isExtendable(const MachineInstr &MI) const;
+ bool isExtended(const MachineInstr &MI) const;
+ bool isFloat(const MachineInstr &MI) const;
+ bool isHVXMemWithAIndirect(const MachineInstr &I,
+ const MachineInstr &J) const;
+ bool isIndirectCall(const MachineInstr &MI) const;
+ bool isIndirectL4Return(const MachineInstr &MI) const;
+ bool isJumpR(const MachineInstr &MI) const;
+ bool isJumpWithinBranchRange(const MachineInstr &MI, unsigned offset) const;
+ bool isLateInstrFeedsEarlyInstr(const MachineInstr &LRMI,
+ const MachineInstr &ESMI) const;
+ bool isLateResultInstr(const MachineInstr &MI) const;
+ bool isLateSourceInstr(const MachineInstr &MI) const;
+ bool isLoopN(const MachineInstr &MI) const;
+ bool isMemOp(const MachineInstr &MI) const;
+ bool isNewValue(const MachineInstr &MI) const;
bool isNewValue(unsigned Opcode) const;
- bool isNewValueInst(const MachineInstr* MI) const;
- bool isNewValueJump(const MachineInstr* MI) const;
+ bool isNewValueInst(const MachineInstr &MI) const;
+ bool isNewValueJump(const MachineInstr &MI) const;
bool isNewValueJump(unsigned Opcode) const;
- bool isNewValueStore(const MachineInstr* MI) const;
+ bool isNewValueStore(const MachineInstr &MI) const;
bool isNewValueStore(unsigned Opcode) const;
- bool isOperandExtended(const MachineInstr *MI, unsigned OperandNum) const;
- bool isPostIncrement(const MachineInstr* MI) const;
+ bool isOperandExtended(const MachineInstr &MI, unsigned OperandNum) const;
bool isPredicatedNew(const MachineInstr &MI) const;
bool isPredicatedNew(unsigned Opcode) const;
bool isPredicatedTrue(const MachineInstr &MI) const;
@@ -305,106 +346,101 @@ public:
bool isPredicated(unsigned Opcode) const;
bool isPredicateLate(unsigned Opcode) const;
bool isPredictedTaken(unsigned Opcode) const;
- bool isSaveCalleeSavedRegsCall(const MachineInstr *MI) const;
+ bool isSaveCalleeSavedRegsCall(const MachineInstr &MI) const;
bool isSignExtendingLoad(const MachineInstr &MI) const;
- bool isSolo(const MachineInstr* MI) const;
- bool isSpillPredRegOp(const MachineInstr *MI) const;
- bool isTailCall(const MachineInstr *MI) const;
- bool isTC1(const MachineInstr *MI) const;
- bool isTC2(const MachineInstr *MI) const;
- bool isTC2Early(const MachineInstr *MI) const;
- bool isTC4x(const MachineInstr *MI) const;
- bool isToBeScheduledASAP(const MachineInstr *MI1,
- const MachineInstr *MI2) const;
- bool isV60VectorInstruction(const MachineInstr *MI) const;
+ bool isSolo(const MachineInstr &MI) const;
+ bool isSpillPredRegOp(const MachineInstr &MI) const;
+ bool isTC1(const MachineInstr &MI) const;
+ bool isTC2(const MachineInstr &MI) const;
+ bool isTC2Early(const MachineInstr &MI) const;
+ bool isTC4x(const MachineInstr &MI) const;
+ bool isToBeScheduledASAP(const MachineInstr &MI1,
+ const MachineInstr &MI2) const;
+ bool isV60VectorInstruction(const MachineInstr &MI) const;
bool isValidAutoIncImm(const EVT VT, const int Offset) const;
bool isValidOffset(unsigned Opcode, int Offset, bool Extend = true) const;
- bool isVecAcc(const MachineInstr *MI) const;
- bool isVecALU(const MachineInstr *MI) const;
- bool isVecUsableNextPacket(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) const;
+ bool isVecAcc(const MachineInstr &MI) const;
+ bool isVecALU(const MachineInstr &MI) const;
+ bool isVecUsableNextPacket(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) const;
bool isZeroExtendingLoad(const MachineInstr &MI) const;
- bool addLatencyToSchedule(const MachineInstr *MI1,
- const MachineInstr *MI2) const;
- bool canExecuteInBundle(const MachineInstr *First,
- const MachineInstr *Second) const;
+ bool addLatencyToSchedule(const MachineInstr &MI1,
+ const MachineInstr &MI2) const;
+ bool canExecuteInBundle(const MachineInstr &First,
+ const MachineInstr &Second) const;
+ bool doesNotReturn(const MachineInstr &CallMI) const;
bool hasEHLabel(const MachineBasicBlock *B) const;
- bool hasNonExtEquivalent(const MachineInstr *MI) const;
- bool hasPseudoInstrPair(const MachineInstr *MI) const;
+ bool hasNonExtEquivalent(const MachineInstr &MI) const;
+ bool hasPseudoInstrPair(const MachineInstr &MI) const;
bool hasUncondBranch(const MachineBasicBlock *B) const;
- bool mayBeCurLoad(const MachineInstr* MI) const;
- bool mayBeNewStore(const MachineInstr* MI) const;
- bool producesStall(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) const;
- bool producesStall(const MachineInstr *MI,
+ bool mayBeCurLoad(const MachineInstr &MI) const;
+ bool mayBeNewStore(const MachineInstr &MI) const;
+ bool producesStall(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) const;
+ bool producesStall(const MachineInstr &MI,
MachineBasicBlock::const_instr_iterator MII) const;
- bool predCanBeUsedAsDotNew(const MachineInstr *MI, unsigned PredReg) const;
+ bool predCanBeUsedAsDotNew(const MachineInstr &MI, unsigned PredReg) const;
bool PredOpcodeHasJMP_c(unsigned Opcode) const;
bool predOpcodeHasNot(ArrayRef<MachineOperand> Cond) const;
-
- short getAbsoluteForm(const MachineInstr *MI) const;
- unsigned getAddrMode(const MachineInstr* MI) const;
- unsigned getBaseAndOffset(const MachineInstr *MI, int &Offset,
+ short getAbsoluteForm(const MachineInstr &MI) const;
+ unsigned getAddrMode(const MachineInstr &MI) const;
+ unsigned getBaseAndOffset(const MachineInstr &MI, int &Offset,
unsigned &AccessSize) const;
- bool getBaseAndOffsetPosition(const MachineInstr *MI, unsigned &BasePos,
- unsigned &OffsetPos) const;
short getBaseWithLongOffset(short Opcode) const;
- short getBaseWithLongOffset(const MachineInstr *MI) const;
- short getBaseWithRegOffset(const MachineInstr *MI) const;
+ short getBaseWithLongOffset(const MachineInstr &MI) const;
+ short getBaseWithRegOffset(const MachineInstr &MI) const;
SmallVector<MachineInstr*,2> getBranchingInstrs(MachineBasicBlock& MBB) const;
- unsigned getCExtOpNum(const MachineInstr *MI) const;
+ unsigned getCExtOpNum(const MachineInstr &MI) const;
HexagonII::CompoundGroup
- getCompoundCandidateGroup(const MachineInstr *MI) const;
- unsigned getCompoundOpcode(const MachineInstr *GA,
- const MachineInstr *GB) const;
+ getCompoundCandidateGroup(const MachineInstr &MI) const;
+ unsigned getCompoundOpcode(const MachineInstr &GA,
+ const MachineInstr &GB) const;
int getCondOpcode(int Opc, bool sense) const;
- int getDotCurOp(const MachineInstr* MI) const;
- int getDotNewOp(const MachineInstr* MI) const;
- int getDotNewPredJumpOp(const MachineInstr *MI,
+ int getDotCurOp(const MachineInstr &MI) const;
+ int getDotNewOp(const MachineInstr &MI) const;
+ int getDotNewPredJumpOp(const MachineInstr &MI,
const MachineBranchProbabilityInfo *MBPI) const;
- int getDotNewPredOp(const MachineInstr *MI,
+ int getDotNewPredOp(const MachineInstr &MI,
const MachineBranchProbabilityInfo *MBPI) const;
int getDotOldOp(const int opc) const;
- HexagonII::SubInstructionGroup getDuplexCandidateGroup(const MachineInstr *MI)
+ HexagonII::SubInstructionGroup getDuplexCandidateGroup(const MachineInstr &MI)
const;
- short getEquivalentHWInstr(const MachineInstr *MI) const;
+ short getEquivalentHWInstr(const MachineInstr &MI) const;
MachineInstr *getFirstNonDbgInst(MachineBasicBlock *BB) const;
unsigned getInstrTimingClassLatency(const InstrItineraryData *ItinData,
- const MachineInstr *MI) const;
+ const MachineInstr &MI) const;
bool getInvertedPredSense(SmallVectorImpl<MachineOperand> &Cond) const;
unsigned getInvertedPredicatedOpcode(const int Opc) const;
- int getMaxValue(const MachineInstr *MI) const;
- unsigned getMemAccessSize(const MachineInstr* MI) const;
- int getMinValue(const MachineInstr *MI) const;
- short getNonExtOpcode(const MachineInstr *MI) const;
+ int getMaxValue(const MachineInstr &MI) const;
+ unsigned getMemAccessSize(const MachineInstr &MI) const;
+ int getMinValue(const MachineInstr &MI) const;
+ short getNonExtOpcode(const MachineInstr &MI) const;
bool getPredReg(ArrayRef<MachineOperand> Cond, unsigned &PredReg,
unsigned &PredRegPos, unsigned &PredRegFlags) const;
- short getPseudoInstrPair(const MachineInstr *MI) const;
- short getRegForm(const MachineInstr *MI) const;
- unsigned getSize(const MachineInstr *MI) const;
- uint64_t getType(const MachineInstr* MI) const;
- unsigned getUnits(const MachineInstr* MI) const;
+ short getPseudoInstrPair(const MachineInstr &MI) const;
+ short getRegForm(const MachineInstr &MI) const;
+ unsigned getSize(const MachineInstr &MI) const;
+ uint64_t getType(const MachineInstr &MI) const;
+ unsigned getUnits(const MachineInstr &MI) const;
unsigned getValidSubTargets(const unsigned Opcode) const;
-
/// getInstrTimingClassLatency - Compute the instruction latency of a given
/// instruction using Timing Class information, if available.
unsigned nonDbgBBSize(const MachineBasicBlock *BB) const;
unsigned nonDbgBundleSize(MachineBasicBlock::const_iterator BundleHead) const;
-
- void immediateExtend(MachineInstr *MI) const;
- bool invertAndChangeJumpTarget(MachineInstr* MI,
+ void immediateExtend(MachineInstr &MI) const;
+ bool invertAndChangeJumpTarget(MachineInstr &MI,
MachineBasicBlock* NewTarget) const;
void genAllInsnTimingClasses(MachineFunction &MF) const;
- bool reversePredSense(MachineInstr* MI) const;
+ bool reversePredSense(MachineInstr &MI) const;
unsigned reversePrediction(unsigned Opcode) const;
bool validateBranchCond(const ArrayRef<MachineOperand> &Cond) const;
- short xformRegToImmOffset(const MachineInstr *MI) const;
+ short xformRegToImmOffset(const MachineInstr &MI) const;
};
-}
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONINSTRINFO_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.td
index 74dc5ac..c5719ad 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.td
@@ -14,54 +14,6 @@
include "HexagonInstrFormats.td"
include "HexagonOperands.td"
include "HexagonInstrEnc.td"
-// Pattern fragment that combines the value type and the register class
-// into a single parameter.
-// The pat frags in the definitions below need to have a named register,
-// otherwise i32 will be assumed regardless of the register class. The
-// name of the register does not matter.
-def I1 : PatLeaf<(i1 PredRegs:$R)>;
-def I32 : PatLeaf<(i32 IntRegs:$R)>;
-def I64 : PatLeaf<(i64 DoubleRegs:$R)>;
-def F32 : PatLeaf<(f32 IntRegs:$R)>;
-def F64 : PatLeaf<(f64 DoubleRegs:$R)>;
-
-// Pattern fragments to extract the low and high subregisters from a
-// 64-bit value.
-def LoReg: OutPatFrag<(ops node:$Rs),
- (EXTRACT_SUBREG (i64 $Rs), subreg_loreg)>;
-def HiReg: OutPatFrag<(ops node:$Rs),
- (EXTRACT_SUBREG (i64 $Rs), subreg_hireg)>;
-
-def orisadd: PatFrag<(ops node:$Addr, node:$off),
- (or node:$Addr, node:$off), [{ return orIsAdd(N); }]>;
-
-// SDNode for converting immediate C to C-1.
-def DEC_CONST_SIGNED : SDNodeXForm<imm, [{
- // Return the byte immediate const-1 as an SDNode.
- int32_t imm = N->getSExtValue();
- return XformSToSM1Imm(imm, SDLoc(N));
-}]>;
-
-// SDNode for converting immediate C to C-2.
-def DEC2_CONST_SIGNED : SDNodeXForm<imm, [{
- // Return the byte immediate const-2 as an SDNode.
- int32_t imm = N->getSExtValue();
- return XformSToSM2Imm(imm, SDLoc(N));
-}]>;
-
-// SDNode for converting immediate C to C-3.
-def DEC3_CONST_SIGNED : SDNodeXForm<imm, [{
- // Return the byte immediate const-3 as an SDNode.
- int32_t imm = N->getSExtValue();
- return XformSToSM3Imm(imm, SDLoc(N));
-}]>;
-
-// SDNode for converting immediate C to C-1.
-def DEC_CONST_UNSIGNED : SDNodeXForm<imm, [{
- // Return the byte immediate const-1 as an SDNode.
- uint32_t imm = N->getZExtValue();
- return XformUToUM1Imm(imm, SDLoc(N));
-}]>;
//===----------------------------------------------------------------------===//
// Compare
@@ -92,32 +44,15 @@ class T_CMP <string mnemonic, bits<2> MajOp, bit isNot, Operand ImmOp>
let Inst{1-0} = dst;
}
-def C2_cmpeqi : T_CMP <"cmp.eq", 0b00, 0, s10Ext>;
-def C2_cmpgti : T_CMP <"cmp.gt", 0b01, 0, s10Ext>;
-def C2_cmpgtui : T_CMP <"cmp.gtu", 0b10, 0, u9Ext>;
-
-class T_CMP_pat <InstHexagon MI, PatFrag OpNode, PatLeaf ImmPred>
- : Pat<(i1 (OpNode (i32 IntRegs:$src1), ImmPred:$src2)),
- (MI IntRegs:$src1, ImmPred:$src2)>;
-
-def : T_CMP_pat <C2_cmpeqi, seteq, s10ImmPred>;
-def : T_CMP_pat <C2_cmpgti, setgt, s10ImmPred>;
-def : T_CMP_pat <C2_cmpgtui, setugt, u9ImmPred>;
+def C2_cmpeqi : T_CMP <"cmp.eq", 0b00, 0, s10_0Ext>;
+def C2_cmpgti : T_CMP <"cmp.gt", 0b01, 0, s10_0Ext>;
+def C2_cmpgtui : T_CMP <"cmp.gtu", 0b10, 0, u9_0Ext>;
//===----------------------------------------------------------------------===//
// ALU32/ALU +
//===----------------------------------------------------------------------===//
// Add.
-def SDT_Int32Leaf : SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>;
-def SDT_Int32Unary : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
-
-def SDTHexagonI64I32I32 : SDTypeProfile<1, 2,
- [SDTCisVT<0, i64>, SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>;
-
-def HexagonCOMBINE : SDNode<"HexagonISD::COMBINE", SDTHexagonI64I32I32>;
-def HexagonPACKHL : SDNode<"HexagonISD::PACKHL", SDTHexagonI64I32I32>;
-
let hasSideEffects = 0, hasNewValue = 1, InputType = "reg" in
class T_ALU32_3op<string mnemonic, bits<3> MajOp, bits<3> MinOp, bit OpsRev,
bit IsComm>
@@ -227,17 +162,6 @@ defm or : T_ALU32_3op_A2<"or", 0b001, 0b001, 0, 1>;
defm sub : T_ALU32_3op_A2<"sub", 0b011, 0b001, 1, 0>;
defm xor : T_ALU32_3op_A2<"xor", 0b001, 0b011, 0, 1>;
-// Pats for instruction selection.
-class BinOp32_pat<SDNode Op, InstHexagon MI, ValueType ResT>
- : Pat<(ResT (Op (i32 IntRegs:$Rs), (i32 IntRegs:$Rt))),
- (ResT (MI IntRegs:$Rs, IntRegs:$Rt))>;
-
-def: BinOp32_pat<add, A2_add, i32>;
-def: BinOp32_pat<and, A2_and, i32>;
-def: BinOp32_pat<or, A2_or, i32>;
-def: BinOp32_pat<sub, A2_sub, i32>;
-def: BinOp32_pat<xor, A2_xor, i32>;
-
// A few special cases producing register pairs:
let OutOperandList = (outs DoubleRegs:$Rd), hasNewValue = 0 in {
def S2_packhl : T_ALU32_3op <"packhl", 0b101, 0b100, 0, 0>;
@@ -252,9 +176,6 @@ let OutOperandList = (outs DoubleRegs:$Rd), hasNewValue = 0 in {
def C2_ccombinewnewf : T_ALU32_3op_pred<"combine", 0b101, 0b000, 0, 1, 1>;
}
-def: BinOp32_pat<HexagonCOMBINE, A2_combinew, i64>;
-def: BinOp32_pat<HexagonPACKHL, S2_packhl, i64>;
-
let hasSideEffects = 0, hasNewValue = 1, isCompare = 1, InputType = "reg" in
class T_ALU32_3op_cmp<string mnemonic, bits<2> MinOp, bit IsNeg, bit IsComm>
: ALU32_rr<(outs PredRegs:$Pd), (ins IntRegs:$Rs, IntRegs:$Rt),
@@ -282,23 +203,6 @@ let Itinerary = ALU32_3op_tc_2early_SLOT0123 in {
def C2_cmpgtu : T_ALU32_3op_cmp< "cmp.gtu", 0b11, 0, 0>;
}
-// Patfrag to convert the usual comparison patfrags (e.g. setlt) to ones
-// that reverse the order of the operands.
-class RevCmp<PatFrag F> : PatFrag<(ops node:$rhs, node:$lhs), F.Fragment>;
-
-// Pats for compares. They use PatFrags as operands, not SDNodes,
-// since seteq/setgt/etc. are defined as ParFrags.
-class T_cmp32_rr_pat<InstHexagon MI, PatFrag Op, ValueType VT>
- : Pat<(VT (Op (i32 IntRegs:$Rs), (i32 IntRegs:$Rt))),
- (VT (MI IntRegs:$Rs, IntRegs:$Rt))>;
-
-def: T_cmp32_rr_pat<C2_cmpeq, seteq, i1>;
-def: T_cmp32_rr_pat<C2_cmpgt, setgt, i1>;
-def: T_cmp32_rr_pat<C2_cmpgtu, setugt, i1>;
-
-def: T_cmp32_rr_pat<C2_cmpgt, RevCmp<setlt>, i1>;
-def: T_cmp32_rr_pat<C2_cmpgtu, RevCmp<setult>, i1>;
-
let CextOpcode = "MUX", InputType = "reg", hasNewValue = 1 in
def C2_mux: ALU32_rr<(outs IntRegs:$Rd),
(ins PredRegs:$Pu, IntRegs:$Rs, IntRegs:$Rt),
@@ -320,9 +224,6 @@ def C2_mux: ALU32_rr<(outs IntRegs:$Rd),
let Inst{4-0} = Rd;
}
-def: Pat<(i32 (select (i1 PredRegs:$Pu), (i32 IntRegs:$Rs), (i32 IntRegs:$Rt))),
- (C2_mux PredRegs:$Pu, IntRegs:$Rs, IntRegs:$Rt)>;
-
// Combines the two immediates into a double register.
// Increase complexity to make it greater than any complexity of a combine
// that involves a register.
@@ -330,10 +231,9 @@ def: Pat<(i32 (select (i1 PredRegs:$Pu), (i32 IntRegs:$Rs), (i32 IntRegs:$Rt))),
let isReMaterializable = 1, isMoveImm = 1, isAsCheapAsAMove = 1,
isExtentSigned = 1, isExtendable = 1, opExtentBits = 8, opExtendable = 1,
AddedComplexity = 75 in
-def A2_combineii: ALU32Inst <(outs DoubleRegs:$Rdd), (ins s8Ext:$s8, s8Imm:$S8),
+def A2_combineii: ALU32Inst <(outs DoubleRegs:$Rdd), (ins s8_0Ext:$s8, s8_0Imm:$S8),
"$Rdd = combine(#$s8, #$S8)",
- [(set (i64 DoubleRegs:$Rdd),
- (i64 (HexagonCOMBINE(i32 s32ImmPred:$s8), (i32 s8ImmPred:$S8))))]> {
+ []> {
bits<5> Rdd;
bits<8> s8;
bits<8> S8;
@@ -352,7 +252,7 @@ def A2_combineii: ALU32Inst <(outs DoubleRegs:$Rdd), (ins s8Ext:$s8, s8Imm:$S8),
let hasNewValue = 1, hasSideEffects = 0 in
class T_Addri_Pred <bit PredNot, bit PredNew>
: ALU32_ri <(outs IntRegs:$Rd),
- (ins PredRegs:$Pu, IntRegs:$Rs, s8Ext:$s8),
+ (ins PredRegs:$Pu, IntRegs:$Rs, s8_0Ext:$s8),
!if(PredNot, "if (!$Pu", "if ($Pu")#!if(PredNew,".new) $Rd = ",
") $Rd = ")#"add($Rs, #$s8)"> {
bits<5> Rd;
@@ -406,8 +306,8 @@ multiclass Addri_Pred<string mnemonic, bit PredNot> {
let isExtendable = 1, isExtentSigned = 1, InputType = "imm" in
multiclass Addri_base<string mnemonic, SDNode OpNode> {
let CextOpcode = mnemonic, BaseOpcode = mnemonic#_ri in {
- let opExtendable = 2, opExtentBits = 16, isPredicable = 1 in
- def A2_#NAME : T_Addri<s16Ext>;
+ let opExtendable = 2, opExtentBits = 16, isPredicable = 1, isAdd = 1 in
+ def A2_#NAME : T_Addri<s16_0Ext>;
let opExtendable = 3, opExtentBits = 8, isPredicated = 1 in {
defm A2_p#NAME#t : Addri_Pred<mnemonic, 0>;
@@ -418,9 +318,6 @@ multiclass Addri_base<string mnemonic, SDNode OpNode> {
defm addi : Addri_base<"add", add>, ImmRegRel, PredNewRel;
-def: Pat<(i32 (add I32:$Rs, s32ImmPred:$s16)),
- (i32 (A2_addi I32:$Rs, imm:$s16))>;
-
let hasNewValue = 1, hasSideEffects = 0, isPseudo = 1 in
def A2_iconst
: ALU32_ri <(outs IntRegs:$Rd),
@@ -436,9 +333,9 @@ let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 10,
InputType = "imm", hasNewValue = 1 in
class T_ALU32ri_logical <string mnemonic, SDNode OpNode, bits<2> MinOp>
: ALU32_ri <(outs IntRegs:$Rd),
- (ins IntRegs:$Rs, s10Ext:$s10),
+ (ins IntRegs:$Rs, s10_0Ext:$s10),
"$Rd = "#mnemonic#"($Rs, #$s10)" ,
- [(set (i32 IntRegs:$Rd), (OpNode (i32 IntRegs:$Rs), s32ImmPred:$s10))]> {
+ []> {
bits<5> Rd;
bits<5> Rs;
bits<10> s10;
@@ -461,7 +358,7 @@ def A2_andir : T_ALU32ri_logical<"and", and, 0b00>, ImmRegRel;
// Rd32=sub(#s10,Rs32)
let isExtendable = 1, CextOpcode = "sub", opExtendable = 1, isExtentSigned = 1,
opExtentBits = 10, InputType = "imm", hasNewValue = 1, hasSideEffects = 0 in
-def A2_subri: ALU32_ri <(outs IntRegs:$Rd), (ins s10Ext:$s10, IntRegs:$Rs),
+def A2_subri: ALU32_ri <(outs IntRegs:$Rd), (ins s10_0Ext:$s10, IntRegs:$Rs),
"$Rd = sub(#$s10, $Rs)", []>, ImmRegRel {
bits<5> Rd;
bits<10> s10;
@@ -483,16 +380,9 @@ def A2_nop: ALU32Inst <(outs), (ins), "nop" > {
let Inst{27-24} = 0b1111;
}
-def: Pat<(sub s32ImmPred:$s10, IntRegs:$Rs),
- (A2_subri imm:$s10, IntRegs:$Rs)>;
-
-// Rd = not(Rs) gets mapped to Rd=sub(#-1, Rs).
-def: Pat<(not (i32 IntRegs:$src1)),
- (A2_subri -1, IntRegs:$src1)>;
-
let hasSideEffects = 0, hasNewValue = 1 in
class T_tfr16<bit isHi>
- : ALU32Inst <(outs IntRegs:$Rx), (ins IntRegs:$src1, u16Imm:$u16),
+ : ALU32Inst <(outs IntRegs:$Rx), (ins IntRegs:$src1, u16_0Imm:$u16),
"$Rx"#!if(isHi, ".h", ".l")#" = #$u16",
[], "$src1 = $Rx" > {
bits<5> Rx;
@@ -601,7 +491,7 @@ let InputType = "imm", isExtendable = 1, isExtentSigned = 1, opExtentBits = 12,
isMoveImm = 1, opExtendable = 2, BaseOpcode = "TFRI", CextOpcode = "TFR",
hasSideEffects = 0, isPredicated = 1, hasNewValue = 1 in
class T_TFRI_Pred<bit PredNot, bit PredNew>
- : ALU32_ri<(outs IntRegs:$Rd), (ins PredRegs:$Pu, s12Ext:$s12),
+ : ALU32_ri<(outs IntRegs:$Rd), (ins PredRegs:$Pu, s12_0Ext:$s12),
"if ("#!if(PredNot,"!","")#"$Pu"#!if(PredNew,".new","")#") $Rd = #$s12",
[], "", ALU32_2op_tc_1_SLOT0123>, ImmRegRel, PredNewRel {
let isPredicatedFalse = PredNot;
@@ -630,8 +520,8 @@ let InputType = "imm", isExtendable = 1, isExtentSigned = 1,
CextOpcode = "TFR", BaseOpcode = "TFRI", hasNewValue = 1, opNewValue = 0,
isAsCheapAsAMove = 1 , opExtendable = 1, opExtentBits = 16, isMoveImm = 1,
isPredicated = 0, isPredicable = 1, isReMaterializable = 1 in
-def A2_tfrsi : ALU32Inst<(outs IntRegs:$Rd), (ins s16Ext:$s16), "$Rd = #$s16",
- [(set (i32 IntRegs:$Rd), s32ImmPred:$s16)], "", ALU32_2op_tc_1_SLOT0123>,
+def A2_tfrsi : ALU32Inst<(outs IntRegs:$Rd), (ins s16_0Ext:$s16), "$Rd = #$s16",
+ [], "", ALU32_2op_tc_1_SLOT0123>,
ImmRegRel, PredRel {
bits<5> Rd;
bits<16> s16;
@@ -649,17 +539,17 @@ defm A2_tfrp : TFR64_base<"TFR64">, PredNewRel;
// Assembler mapped
let isReMaterializable = 1, isMoveImm = 1, isAsCheapAsAMove = 1,
isAsmParserOnly = 1 in
-def A2_tfrpi : ALU64_rr<(outs DoubleRegs:$dst), (ins s8Imm64:$src1),
+def A2_tfrpi : ALU64_rr<(outs DoubleRegs:$dst), (ins s8_0Imm64:$src1),
"$dst = #$src1",
- [(set (i64 DoubleRegs:$dst), s8Imm64Pred:$src1)]>;
+ []>;
// TODO: see if this instruction can be deleted..
let isExtendable = 1, opExtendable = 1, opExtentBits = 6,
isAsmParserOnly = 1 in {
-def TFRI64_V4 : ALU64_rr<(outs DoubleRegs:$dst), (ins u64Imm:$src1),
+def TFRI64_V4 : ALU64_rr<(outs DoubleRegs:$dst), (ins u64_0Imm:$src1),
"$dst = #$src1">;
def TFRI64_V2_ext : ALU64_rr<(outs DoubleRegs:$dst),
- (ins s8Ext:$src1, s8Imm:$src2),
+ (ins s8_0Ext:$src1, s8_0Imm:$src2),
"$dst = combine(##$src1, #$src2)">;
}
@@ -692,27 +582,20 @@ class T_MUX1 <bit MajOp, dag ins, string AsmStr>
}
let opExtendable = 2 in
-def C2_muxri : T_MUX1<0b1, (ins PredRegs:$Pu, s8Ext:$s8, IntRegs:$Rs),
+def C2_muxri : T_MUX1<0b1, (ins PredRegs:$Pu, s8_0Ext:$s8, IntRegs:$Rs),
"$Rd = mux($Pu, #$s8, $Rs)">;
let opExtendable = 3 in
-def C2_muxir : T_MUX1<0b0, (ins PredRegs:$Pu, IntRegs:$Rs, s8Ext:$s8),
+def C2_muxir : T_MUX1<0b0, (ins PredRegs:$Pu, IntRegs:$Rs, s8_0Ext:$s8),
"$Rd = mux($Pu, $Rs, #$s8)">;
-def : Pat<(i32 (select I1:$Pu, s32ImmPred:$s8, I32:$Rs)),
- (C2_muxri I1:$Pu, s32ImmPred:$s8, I32:$Rs)>;
-
-def : Pat<(i32 (select I1:$Pu, I32:$Rs, s32ImmPred:$s8)),
- (C2_muxir I1:$Pu, I32:$Rs, s32ImmPred:$s8)>;
-
// C2_muxii: Scalar mux immediates.
let isExtentSigned = 1, hasNewValue = 1, isExtendable = 1,
opExtentBits = 8, opExtendable = 2 in
def C2_muxii: ALU32Inst <(outs IntRegs:$Rd),
- (ins PredRegs:$Pu, s8Ext:$s8, s8Imm:$S8),
+ (ins PredRegs:$Pu, s8_0Ext:$s8, s8_0Imm:$S8),
"$Rd = mux($Pu, #$s8, #$S8)" ,
- [(set (i32 IntRegs:$Rd),
- (i32 (select I1:$Pu, s32ImmPred:$s8, s8ImmPred:$S8)))] > {
+ []> {
bits<5> Rd;
bits<2> Pu;
bits<8> s8;
@@ -729,9 +612,9 @@ def C2_muxii: ALU32Inst <(outs IntRegs:$Rd),
}
let isCodeGenOnly = 1, isPseudo = 1 in
-def MUX64_rr : ALU64_rr<(outs DoubleRegs:$Rd),
- (ins PredRegs:$Pu, DoubleRegs:$Rs, DoubleRegs:$Rt),
- ".error \"should not emit\" ", []>;
+def PS_pselect : ALU64_rr<(outs DoubleRegs:$Rd),
+ (ins PredRegs:$Pu, DoubleRegs:$Rs, DoubleRegs:$Rt),
+ ".error \"should not emit\" ", []>;
//===----------------------------------------------------------------------===//
@@ -809,7 +692,7 @@ defm sxth : ALU32_2op_base<"sxth", 0b111>, PredNewRel;
defm zxth : ALU32_2op_base<"zxth", 0b110>, PredNewRel;
// Rd=zxtb(Rs): assembler mapped to Rd=and(Rs,#255).
-// Compiler would want to generate 'zxtb' instead of 'and' becuase 'zxtb' has
+// Compiler would want to generate 'zxtb' instead of 'and' because 'zxtb' has
// predicated forms while 'and' doesn't. Since integrated assembler can't
// handle 'mapped' instructions, we need to encode 'zxtb' same as 'and' where
// immediate operand is set to '255'.
@@ -845,11 +728,6 @@ multiclass ZXTB_base <string mnemonic, bits<3> minOp> {
defm zxtb : ZXTB_base<"zxtb",0b100>, PredNewRel;
-def: Pat<(shl I32:$src1, (i32 16)), (A2_aslh I32:$src1)>;
-def: Pat<(sra I32:$src1, (i32 16)), (A2_asrh I32:$src1)>;
-def: Pat<(sext_inreg I32:$src1, i8), (A2_sxtb I32:$src1)>;
-def: Pat<(sext_inreg I32:$src1, i16), (A2_sxth I32:$src1)>;
-
//===----------------------------------------------------------------------===//
// Template class for vector add and avg
//===----------------------------------------------------------------------===//
@@ -980,10 +858,6 @@ class T_vcmp <string Str, bits<4> minOp>
let Inst{12-8} = Rtt;
}
-class T_vcmp_pat<InstHexagon MI, PatFrag Op, ValueType T>
- : Pat<(i1 (Op (T DoubleRegs:$Rss), (T DoubleRegs:$Rtt))),
- (i1 (MI DoubleRegs:$Rss, DoubleRegs:$Rtt))>;
-
// Vector compare bytes
def A2_vcmpbeq : T_vcmp <"vcmpb.eq", 0b0110>;
def A2_vcmpbgtu : T_vcmp <"vcmpb.gtu", 0b0111>;
@@ -998,15 +872,6 @@ def A2_vcmpweq : T_vcmp <"vcmpw.eq", 0b0000>;
def A2_vcmpwgt : T_vcmp <"vcmpw.gt", 0b0001>;
def A2_vcmpwgtu : T_vcmp <"vcmpw.gtu", 0b0010>;
-def: T_vcmp_pat<A2_vcmpbeq, seteq, v8i8>;
-def: T_vcmp_pat<A2_vcmpbgtu, setugt, v8i8>;
-def: T_vcmp_pat<A2_vcmpheq, seteq, v4i16>;
-def: T_vcmp_pat<A2_vcmphgt, setgt, v4i16>;
-def: T_vcmp_pat<A2_vcmphgtu, setugt, v4i16>;
-def: T_vcmp_pat<A2_vcmpweq, seteq, v2i32>;
-def: T_vcmp_pat<A2_vcmpwgt, setgt, v2i32>;
-def: T_vcmp_pat<A2_vcmpwgtu, setugt, v2i32>;
-
//===----------------------------------------------------------------------===//
// ALU32/PERM -
//===----------------------------------------------------------------------===//
@@ -1019,10 +884,10 @@ def: T_vcmp_pat<A2_vcmpwgtu, setugt, v2i32>;
// transform it to cmp.gt subtracting 1 from the immediate.
let isPseudo = 1 in {
def C2_cmpgei: ALU32Inst <
- (outs PredRegs:$Pd), (ins IntRegs:$Rs, s8Ext:$s8),
+ (outs PredRegs:$Pd), (ins IntRegs:$Rs, s8_0Ext:$s8),
"$Pd = cmp.ge($Rs, #$s8)">;
def C2_cmpgeui: ALU32Inst <
- (outs PredRegs:$Pd), (ins IntRegs:$Rs, u8Ext:$s8),
+ (outs PredRegs:$Pd), (ins IntRegs:$Rs, u8_0Ext:$s8),
"$Pd = cmp.geu($Rs, #$s8)">;
}
@@ -1112,23 +977,6 @@ let Itinerary = ALU64_tc_2_SLOT23, Defs = [USR_OVF] in {
def A2_addh_h16_sat_hh : T_XTYPE_ADD_SUB <0b11, 1, 1, 0>;
}
-// Add halfword.
-def: Pat<(sext_inreg (add I32:$src1, I32:$src2), i16),
- (A2_addh_l16_ll I32:$src1, I32:$src2)>;
-
-def: Pat<(sra (add (shl I32:$src1, (i32 16)), I32:$src2), (i32 16)),
- (A2_addh_l16_hl I32:$src1, I32:$src2)>;
-
-def: Pat<(shl (add I32:$src1, I32:$src2), (i32 16)),
- (A2_addh_h16_ll I32:$src1, I32:$src2)>;
-
-// Subtract halfword.
-def: Pat<(sext_inreg (sub I32:$src1, I32:$src2), i16),
- (A2_subh_l16_ll I32:$src1, I32:$src2)>;
-
-def: Pat<(shl (sub I32:$src1, I32:$src2), (i32 16)),
- (A2_subh_h16_ll I32:$src1, I32:$src2)>;
-
let hasSideEffects = 0, hasNewValue = 1 in
def S2_parityp: ALU64Inst<(outs IntRegs:$Rd),
(ins DoubleRegs:$Rs, DoubleRegs:$Rt),
@@ -1168,52 +1016,6 @@ def A2_minu : T_XTYPE_MIN_MAX < 0, 1 >;
def A2_max : T_XTYPE_MIN_MAX < 1, 0 >;
def A2_maxu : T_XTYPE_MIN_MAX < 1, 1 >;
-// Here, depending on the operand being selected, we'll either generate a
-// min or max instruction.
-// Ex:
-// (a>b)?a:b --> max(a,b) => Here check performed is '>' and the value selected
-// is the larger of two. So, the corresponding HexagonInst is passed in 'Inst'.
-// (a>b)?b:a --> min(a,b) => Here check performed is '>' but the smaller value
-// is selected and the corresponding HexagonInst is passed in 'SwapInst'.
-
-multiclass T_MinMax_pats <PatFrag Op, RegisterClass RC, ValueType VT,
- InstHexagon Inst, InstHexagon SwapInst> {
- def: Pat<(select (i1 (Op (VT RC:$src1), (VT RC:$src2))),
- (VT RC:$src1), (VT RC:$src2)),
- (Inst RC:$src1, RC:$src2)>;
- def: Pat<(select (i1 (Op (VT RC:$src1), (VT RC:$src2))),
- (VT RC:$src2), (VT RC:$src1)),
- (SwapInst RC:$src1, RC:$src2)>;
-}
-
-
-multiclass MinMax_pats <PatFrag Op, InstHexagon Inst, InstHexagon SwapInst> {
- defm: T_MinMax_pats<Op, IntRegs, i32, Inst, SwapInst>;
-
- def: Pat<(sext_inreg (i32 (select (i1 (Op (i32 PositiveHalfWord:$src1),
- (i32 PositiveHalfWord:$src2))),
- (i32 PositiveHalfWord:$src1),
- (i32 PositiveHalfWord:$src2))), i16),
- (Inst IntRegs:$src1, IntRegs:$src2)>;
-
- def: Pat<(sext_inreg (i32 (select (i1 (Op (i32 PositiveHalfWord:$src1),
- (i32 PositiveHalfWord:$src2))),
- (i32 PositiveHalfWord:$src2),
- (i32 PositiveHalfWord:$src1))), i16),
- (SwapInst IntRegs:$src1, IntRegs:$src2)>;
-}
-
-let AddedComplexity = 200 in {
- defm: MinMax_pats<setge, A2_max, A2_min>;
- defm: MinMax_pats<setgt, A2_max, A2_min>;
- defm: MinMax_pats<setle, A2_min, A2_max>;
- defm: MinMax_pats<setlt, A2_min, A2_max>;
- defm: MinMax_pats<setuge, A2_maxu, A2_minu>;
- defm: MinMax_pats<setugt, A2_maxu, A2_minu>;
- defm: MinMax_pats<setule, A2_minu, A2_maxu>;
- defm: MinMax_pats<setult, A2_minu, A2_maxu>;
-}
-
class T_cmp64_rr<string mnemonic, bits<3> MinOp, bit IsComm>
: ALU64_rr<(outs PredRegs:$Pd), (ins DoubleRegs:$Rs, DoubleRegs:$Rt),
"$Pd = "#mnemonic#"($Rs, $Rt)", [], "", ALU64_tc_2early_SLOT23> {
@@ -1237,16 +1039,6 @@ def C2_cmpeqp : T_cmp64_rr<"cmp.eq", 0b000, 1>;
def C2_cmpgtp : T_cmp64_rr<"cmp.gt", 0b010, 0>;
def C2_cmpgtup : T_cmp64_rr<"cmp.gtu", 0b100, 0>;
-class T_cmp64_rr_pat<InstHexagon MI, PatFrag CmpOp>
- : Pat<(i1 (CmpOp (i64 DoubleRegs:$Rs), (i64 DoubleRegs:$Rt))),
- (i1 (MI DoubleRegs:$Rs, DoubleRegs:$Rt))>;
-
-def: T_cmp64_rr_pat<C2_cmpeqp, seteq>;
-def: T_cmp64_rr_pat<C2_cmpgtp, setgt>;
-def: T_cmp64_rr_pat<C2_cmpgtup, setugt>;
-def: T_cmp64_rr_pat<C2_cmpgtp, RevCmp<setlt>>;
-def: T_cmp64_rr_pat<C2_cmpgtup, RevCmp<setult>>;
-
def C2_vmux : ALU64_rr<(outs DoubleRegs:$Rd),
(ins PredRegs:$Pu, DoubleRegs:$Rs, DoubleRegs:$Rt),
"$Rd = vmux($Pu, $Rs, $Rt)", [], "", ALU64_tc_1_SLOT23> {
@@ -1292,12 +1084,10 @@ class T_ALU64_arith<string mnemonic, bits<3> MajOp, bits<3> MinOp, bit IsSat,
: T_ALU64_rr<mnemonic, !if(IsSat,":sat",""), 0b0011, MajOp, MinOp, OpsRev,
IsComm, "">;
+let isAdd = 1 in
def A2_addp : T_ALU64_arith<"add", 0b000, 0b111, 0, 0, 1>;
def A2_subp : T_ALU64_arith<"sub", 0b001, 0b111, 0, 1, 0>;
-def: Pat<(i64 (add I64:$Rs, I64:$Rt)), (A2_addp I64:$Rs, I64:$Rt)>;
-def: Pat<(i64 (sub I64:$Rs, I64:$Rt)), (A2_subp I64:$Rs, I64:$Rt)>;
-
class T_ALU64_logical<string mnemonic, bits<3> MinOp, bit OpsRev, bit IsComm,
bit IsNeg>
: T_ALU64_rr<mnemonic, "", 0b0011, 0b111, MinOp, OpsRev, IsComm,
@@ -1307,10 +1097,6 @@ def A2_andp : T_ALU64_logical<"and", 0b000, 0, 1, 0>;
def A2_orp : T_ALU64_logical<"or", 0b010, 0, 1, 0>;
def A2_xorp : T_ALU64_logical<"xor", 0b100, 0, 1, 0>;
-def: Pat<(i64 (and I64:$Rs, I64:$Rt)), (A2_andp I64:$Rs, I64:$Rt)>;
-def: Pat<(i64 (or I64:$Rs, I64:$Rt)), (A2_orp I64:$Rs, I64:$Rt)>;
-def: Pat<(i64 (xor I64:$Rs, I64:$Rt)), (A2_xorp I64:$Rs, I64:$Rt)>;
-
//===----------------------------------------------------------------------===//
// ALU64/ALU -
//===----------------------------------------------------------------------===//
@@ -1361,9 +1147,6 @@ def C2_any8 : T_LOGICAL_1OP<"any8", 0b00>;
def C2_all8 : T_LOGICAL_1OP<"all8", 0b01>;
def C2_not : T_LOGICAL_1OP<"not", 0b10>;
-def: Pat<(i1 (not (i1 PredRegs:$Ps))),
- (C2_not PredRegs:$Ps)>;
-
let hasSideEffects = 0 in
class T_LOGICAL_2OP<string MnOp, bits<3> OpBits, bit IsNeg, bit Rev>
: CRInst<(outs PredRegs:$Pd), (ins PredRegs:$Ps, PredRegs:$Pt),
@@ -1389,12 +1172,6 @@ def C2_xor : T_LOGICAL_2OP<"xor", 0b010, 0, 0>;
def C2_andn : T_LOGICAL_2OP<"and", 0b011, 1, 1>;
def C2_orn : T_LOGICAL_2OP<"or", 0b111, 1, 1>;
-def: Pat<(i1 (and I1:$Ps, I1:$Pt)), (C2_and I1:$Ps, I1:$Pt)>;
-def: Pat<(i1 (or I1:$Ps, I1:$Pt)), (C2_or I1:$Ps, I1:$Pt)>;
-def: Pat<(i1 (xor I1:$Ps, I1:$Pt)), (C2_xor I1:$Ps, I1:$Pt)>;
-def: Pat<(i1 (and I1:$Ps, (not I1:$Pt))), (C2_andn I1:$Ps, I1:$Pt)>;
-def: Pat<(i1 (or I1:$Ps, (not I1:$Pt))), (C2_orn I1:$Ps, I1:$Pt)>;
-
let hasSideEffects = 0, hasNewValue = 1 in
def C2_vitpack : SInst<(outs IntRegs:$Rd), (ins PredRegs:$Ps, PredRegs:$Pt),
"$Rd = vitpack($Ps, $Pt)", [], "", S_2op_tc_1_SLOT23> {
@@ -1431,10 +1208,6 @@ def C2_mask : SInst<(outs DoubleRegs:$Rd), (ins PredRegs:$Pt),
// JR +
//===----------------------------------------------------------------------===//
-def retflag : SDNode<"HexagonISD::RET_FLAG", SDTNone,
- [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
-def eh_return: SDNode<"HexagonISD::EH_RETURN", SDTNone, [SDNPHasChain]>;
-
class CondStr<string CReg, bit True, bit New> {
string S = "if (" # !if(True,"","!") # CReg # !if(New,".new","") # ") ";
}
@@ -1587,8 +1360,8 @@ let isTerminator = 1, hasSideEffects = 0 in {
defm J2_jumpr : JMPR_base<"JMPr">, PredNewRel;
- let isReturn = 1, isCodeGenOnly = 1 in
- defm JMPret : JMPR_base<"JMPret">, PredNewRel;
+ let isReturn = 1, isPseudo = 1, isCodeGenOnly = 1 in
+ defm PS_jmpret : JMPR_base<"JMPret">, PredNewRel;
}
let validSubTargets = HasV60SubT in
@@ -1610,23 +1383,11 @@ multiclass JMPRpt_base<string BaseOp> {
defm J2_jumpr : JMPRpt_base<"JMPr">;
defm J2_jump : JMPpt_base<"JMP">;
-def: Pat<(br bb:$dst),
- (J2_jump brtarget:$dst)>;
-def: Pat<(retflag),
- (JMPret (i32 R31))>;
-def: Pat<(brcond (i1 PredRegs:$src1), bb:$offset),
- (J2_jumpt PredRegs:$src1, bb:$offset)>;
-
// A return through builtin_eh_return.
let isReturn = 1, isTerminator = 1, isBarrier = 1, hasSideEffects = 0,
isCodeGenOnly = 1, Defs = [PC], Uses = [R28], isPredicable = 0 in
def EH_RETURN_JMPR : T_JMPr;
-def: Pat<(eh_return),
- (EH_RETURN_JMPR (i32 R31))>;
-def: Pat<(brind (i32 IntRegs:$dst)),
- (J2_jumpr IntRegs:$dst)>;
-
//===----------------------------------------------------------------------===//
// JR -
//===----------------------------------------------------------------------===//
@@ -1784,45 +1545,6 @@ def L2_loadalignh_io: T_loadalign_io <"memh_fifo", 0b0010, s11_1Ext>;
let accessSize = ByteAccess, opExtentBits = 11 in
def L2_loadalignb_io: T_loadalign_io <"memb_fifo", 0b0100, s11_0Ext>;
-// Patterns to select load-indexed (i.e. load from base+offset).
-multiclass Loadx_pat<PatFrag Load, ValueType VT, PatLeaf ImmPred,
- InstHexagon MI> {
- def: Pat<(VT (Load AddrFI:$fi)), (VT (MI AddrFI:$fi, 0))>;
- def: Pat<(VT (Load (add (i32 AddrFI:$fi), ImmPred:$Off))),
- (VT (MI AddrFI:$fi, imm:$Off))>;
- def: Pat<(VT (Load (orisadd (i32 AddrFI:$fi), ImmPred:$Off))),
- (VT (MI AddrFI:$fi, imm:$Off))>;
- def: Pat<(VT (Load (add (i32 IntRegs:$Rs), ImmPred:$Off))),
- (VT (MI IntRegs:$Rs, imm:$Off))>;
- def: Pat<(VT (Load (i32 IntRegs:$Rs))), (VT (MI IntRegs:$Rs, 0))>;
-}
-
-let AddedComplexity = 20 in {
- defm: Loadx_pat<load, i32, s30_2ImmPred, L2_loadri_io>;
- defm: Loadx_pat<load, i64, s29_3ImmPred, L2_loadrd_io>;
- defm: Loadx_pat<atomic_load_8 , i32, s32_0ImmPred, L2_loadrub_io>;
- defm: Loadx_pat<atomic_load_16, i32, s31_1ImmPred, L2_loadruh_io>;
- defm: Loadx_pat<atomic_load_32, i32, s30_2ImmPred, L2_loadri_io>;
- defm: Loadx_pat<atomic_load_64, i64, s29_3ImmPred, L2_loadrd_io>;
-
- defm: Loadx_pat<extloadi1, i32, s32_0ImmPred, L2_loadrub_io>;
- defm: Loadx_pat<extloadi8, i32, s32_0ImmPred, L2_loadrub_io>;
- defm: Loadx_pat<extloadi16, i32, s31_1ImmPred, L2_loadruh_io>;
- defm: Loadx_pat<sextloadi8, i32, s32_0ImmPred, L2_loadrb_io>;
- defm: Loadx_pat<sextloadi16, i32, s31_1ImmPred, L2_loadrh_io>;
- defm: Loadx_pat<zextloadi1, i32, s32_0ImmPred, L2_loadrub_io>;
- defm: Loadx_pat<zextloadi8, i32, s32_0ImmPred, L2_loadrub_io>;
- defm: Loadx_pat<zextloadi16, i32, s31_1ImmPred, L2_loadruh_io>;
- // No sextloadi1.
-}
-
-// Sign-extending loads of i1 need to replicate the lowest bit throughout
-// the 32-bit value. Since the loaded value can only be 0 or 1, 0-v should
-// do the trick.
-let AddedComplexity = 20 in
-def: Pat<(i32 (sextloadi1 (i32 IntRegs:$Rs))),
- (A2_subri 0, (L2_loadrub_io IntRegs:$Rs, 0))>;
-
//===----------------------------------------------------------------------===//
// Post increment load
//===----------------------------------------------------------------------===//
@@ -2696,10 +2418,6 @@ def M2_mpy_up_s1_sat : T_MType_rr1 <"mpy", 0b111, 0b000, 1>;
def M2_hmmpyh_s1 : T_MType_rr2 <"mpy", 0b101, 0b000, 1, 0, ".h">;
def M2_hmmpyl_s1 : T_MType_rr2 <"mpy", 0b101, 0b001, 1, 0, ".l">;
-def: Pat<(i32 (mul I32:$src1, I32:$src2)), (M2_mpyi I32:$src1, I32:$src2)>;
-def: Pat<(i32 (mulhs I32:$src1, I32:$src2)), (M2_mpy_up I32:$src1, I32:$src2)>;
-def: Pat<(i32 (mulhu I32:$src1, I32:$src2)), (M2_mpyu_up I32:$src1, I32:$src2)>;
-
let hasNewValue = 1, opNewValue = 0 in
class T_MType_mpy_ri <bit isNeg, Operand ImmOp, list<dag> pattern>
: MInst < (outs IntRegs:$Rd), (ins IntRegs:$Rs, ImmOp:$u8),
@@ -2720,12 +2438,9 @@ class T_MType_mpy_ri <bit isNeg, Operand ImmOp, list<dag> pattern>
}
let isExtendable = 1, opExtentBits = 8, opExtendable = 2 in
-def M2_mpysip : T_MType_mpy_ri <0, u8Ext,
- [(set (i32 IntRegs:$Rd), (mul IntRegs:$Rs, u32ImmPred:$u8))]>;
+def M2_mpysip : T_MType_mpy_ri <0, u8_0Ext, []>;
-def M2_mpysin : T_MType_mpy_ri <1, u8Imm,
- [(set (i32 IntRegs:$Rd), (ineg (mul IntRegs:$Rs,
- u8ImmPred:$u8)))]>;
+def M2_mpysin : T_MType_mpy_ri <1, u8_0Imm, []>;
// Assember mapped to M2_mpyi
let isAsmParserOnly = 1 in
@@ -2740,10 +2455,8 @@ def M2_mpyui : MInst<(outs IntRegs:$dst),
let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 9,
CextOpcode = "mpyi", InputType = "imm", hasNewValue = 1,
isAsmParserOnly = 1 in
-def M2_mpysmi : MInst<(outs IntRegs:$dst), (ins IntRegs:$src1, s9Ext:$src2),
- "$dst = mpyi($src1, #$src2)",
- [(set (i32 IntRegs:$dst), (mul (i32 IntRegs:$src1),
- s32ImmPred:$src2))]>, ImmRegRel;
+def M2_mpysmi : MInst<(outs IntRegs:$dst), (ins IntRegs:$src1, s9_0Ext:$src2),
+ "$dst = mpyi($src1, #$src2)", []>, ImmRegRel;
let hasNewValue = 1, isExtendable = 1, opExtentBits = 8, opExtendable = 3,
InputType = "imm" in
@@ -2792,58 +2505,31 @@ class T_MType_acc_rr <string mnemonic, bits<3> MajOp, bits<3> MinOp,
}
let CextOpcode = "MPYI_acc", Itinerary = M_tc_3x_SLOT23 in {
- def M2_macsip : T_MType_acc_ri <"+= mpyi", 0b010, u8Ext,
- [(set (i32 IntRegs:$dst),
- (add (mul IntRegs:$src2, u32ImmPred:$src3),
- IntRegs:$src1))]>, ImmRegRel;
-
- def M2_maci : T_MType_acc_rr <"+= mpyi", 0b000, 0b000, 0,
- [(set (i32 IntRegs:$dst),
- (add (mul IntRegs:$src2, IntRegs:$src3),
- IntRegs:$src1))]>, ImmRegRel;
+ def M2_macsip : T_MType_acc_ri <"+= mpyi", 0b010, u8_0Ext, []>, ImmRegRel;
+
+ def M2_maci : T_MType_acc_rr <"+= mpyi", 0b000, 0b000, 0, []>, ImmRegRel;
}
let CextOpcode = "ADD_acc" in {
let isExtentSigned = 1 in
- def M2_accii : T_MType_acc_ri <"+= add", 0b100, s8Ext,
- [(set (i32 IntRegs:$dst),
- (add (add (i32 IntRegs:$src2), s32ImmPred:$src3),
- (i32 IntRegs:$src1)))]>, ImmRegRel;
-
- def M2_acci : T_MType_acc_rr <"+= add", 0b000, 0b001, 0,
- [(set (i32 IntRegs:$dst),
- (add (add (i32 IntRegs:$src2), (i32 IntRegs:$src3)),
- (i32 IntRegs:$src1)))]>, ImmRegRel;
+ def M2_accii : T_MType_acc_ri <"+= add", 0b100, s8_0Ext, []>, ImmRegRel;
+
+ def M2_acci : T_MType_acc_rr <"+= add", 0b000, 0b001, 0, []>, ImmRegRel;
}
let CextOpcode = "SUB_acc" in {
let isExtentSigned = 1 in
- def M2_naccii : T_MType_acc_ri <"-= add", 0b101, s8Ext>, ImmRegRel;
+ def M2_naccii : T_MType_acc_ri <"-= add", 0b101, s8_0Ext>, ImmRegRel;
def M2_nacci : T_MType_acc_rr <"-= add", 0b100, 0b001, 0>, ImmRegRel;
}
let Itinerary = M_tc_3x_SLOT23 in
-def M2_macsin : T_MType_acc_ri <"-= mpyi", 0b011, u8Ext>;
+def M2_macsin : T_MType_acc_ri <"-= mpyi", 0b011, u8_0Ext>;
def M2_xor_xacc : T_MType_acc_rr < "^= xor", 0b100, 0b011, 0>;
def M2_subacc : T_MType_acc_rr <"+= sub", 0b000, 0b011, 1>;
-class T_MType_acc_pat1 <InstHexagon MI, SDNode firstOp, SDNode secOp,
- PatLeaf ImmPred>
- : Pat <(secOp IntRegs:$src1, (firstOp IntRegs:$src2, ImmPred:$src3)),
- (MI IntRegs:$src1, IntRegs:$src2, ImmPred:$src3)>;
-
-class T_MType_acc_pat2 <InstHexagon MI, SDNode firstOp, SDNode secOp>
- : Pat <(i32 (secOp IntRegs:$src1, (firstOp IntRegs:$src2, IntRegs:$src3))),
- (MI IntRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
-def : T_MType_acc_pat2 <M2_xor_xacc, xor, xor>;
-def : T_MType_acc_pat1 <M2_macsin, mul, sub, u32ImmPred>;
-
-def : T_MType_acc_pat1 <M2_naccii, add, sub, s32ImmPred>;
-def : T_MType_acc_pat2 <M2_nacci, add, sub>;
-
//===----------------------------------------------------------------------===//
// Template Class -- XType Vector Instructions
//===----------------------------------------------------------------------===//
@@ -3189,51 +2875,6 @@ def M2_vmac2 : T_XTYPE_mpy64_acc < "vmpyh", "+", 0b001, 0b001, 0, 0, 0>;
def M2_vmac2s_s1 : T_XTYPE_mpy64_acc < "vmpyh", "+", 0b100, 0b101, 1, 1, 0>;
def M2_vmac2s_s0 : T_XTYPE_mpy64_acc < "vmpyh", "+", 0b000, 0b101, 1, 0, 0>;
-def: Pat<(i64 (mul (i64 (anyext (i32 IntRegs:$src1))),
- (i64 (anyext (i32 IntRegs:$src2))))),
- (M2_dpmpyuu_s0 IntRegs:$src1, IntRegs:$src2)>;
-
-def: Pat<(i64 (mul (i64 (sext (i32 IntRegs:$src1))),
- (i64 (sext (i32 IntRegs:$src2))))),
- (M2_dpmpyss_s0 IntRegs:$src1, IntRegs:$src2)>;
-
-def: Pat<(i64 (mul (is_sext_i32:$src1),
- (is_sext_i32:$src2))),
- (M2_dpmpyss_s0 (LoReg DoubleRegs:$src1), (LoReg DoubleRegs:$src2))>;
-
-// Multiply and accumulate, use full result.
-// Rxx[+-]=mpy(Rs,Rt)
-
-def: Pat<(i64 (add (i64 DoubleRegs:$src1),
- (mul (i64 (sext (i32 IntRegs:$src2))),
- (i64 (sext (i32 IntRegs:$src3)))))),
- (M2_dpmpyss_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
-def: Pat<(i64 (sub (i64 DoubleRegs:$src1),
- (mul (i64 (sext (i32 IntRegs:$src2))),
- (i64 (sext (i32 IntRegs:$src3)))))),
- (M2_dpmpyss_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
-def: Pat<(i64 (add (i64 DoubleRegs:$src1),
- (mul (i64 (anyext (i32 IntRegs:$src2))),
- (i64 (anyext (i32 IntRegs:$src3)))))),
- (M2_dpmpyuu_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
-def: Pat<(i64 (add (i64 DoubleRegs:$src1),
- (mul (i64 (zext (i32 IntRegs:$src2))),
- (i64 (zext (i32 IntRegs:$src3)))))),
- (M2_dpmpyuu_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
-def: Pat<(i64 (sub (i64 DoubleRegs:$src1),
- (mul (i64 (anyext (i32 IntRegs:$src2))),
- (i64 (anyext (i32 IntRegs:$src3)))))),
- (M2_dpmpyuu_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
-def: Pat<(i64 (sub (i64 DoubleRegs:$src1),
- (mul (i64 (zext (i32 IntRegs:$src2))),
- (i64 (zext (i32 IntRegs:$src3)))))),
- (M2_dpmpyuu_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
-
//===----------------------------------------------------------------------===//
// MTYPE/MPYH -
//===----------------------------------------------------------------------===//
@@ -3375,16 +3016,6 @@ defm storerd: ST_PostInc <"memd", "STrid", DoubleRegs, s4_3Imm, 0b1110>;
let accessSize = HalfWordAccess, isNVStorable = 0 in
defm storerf: ST_PostInc <"memh", "STrih_H", IntRegs, s4_1Imm, 0b1011, 1>;
-class Storepi_pat<PatFrag Store, PatFrag Value, PatFrag Offset,
- InstHexagon MI>
- : Pat<(Store Value:$src1, I32:$src2, Offset:$offset),
- (MI I32:$src2, imm:$offset, Value:$src1)>;
-
-def: Storepi_pat<post_truncsti8, I32, s4_0ImmPred, S2_storerb_pi>;
-def: Storepi_pat<post_truncsti16, I32, s4_1ImmPred, S2_storerh_pi>;
-def: Storepi_pat<post_store, I32, s4_2ImmPred, S2_storeri_pi>;
-def: Storepi_pat<post_store, I64, s4_3ImmPred, S2_storerd_pi>;
-
//===----------------------------------------------------------------------===//
// Template class for post increment stores with register offset.
//===----------------------------------------------------------------------===//
@@ -3535,116 +3166,6 @@ let addrMode = BaseImmOffset, InputType = "imm" in {
u6_1Ext, 0b011, 1>;
}
-// Patterns for generating stores, where the address takes different forms:
-// - frameindex,
-// - frameindex + offset,
-// - base + offset,
-// - simple (base address without offset).
-// These would usually be used together (via Storex_pat defined below), but
-// in some cases one may want to apply different properties (such as
-// AddedComplexity) to the individual patterns.
-class Storex_fi_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
- : Pat<(Store Value:$Rs, AddrFI:$fi), (MI AddrFI:$fi, 0, Value:$Rs)>;
-multiclass Storex_fi_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
- InstHexagon MI> {
- def: Pat<(Store Value:$Rs, (add (i32 AddrFI:$fi), ImmPred:$Off)),
- (MI AddrFI:$fi, imm:$Off, Value:$Rs)>;
- def: Pat<(Store Value:$Rs, (orisadd (i32 AddrFI:$fi), ImmPred:$Off)),
- (MI AddrFI:$fi, imm:$Off, Value:$Rs)>;
-}
-multiclass Storex_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
- InstHexagon MI> {
- def: Pat<(Store Value:$Rt, (add (i32 IntRegs:$Rs), ImmPred:$Off)),
- (MI IntRegs:$Rs, imm:$Off, Value:$Rt)>;
- def: Pat<(Store Value:$Rt, (orisadd (i32 IntRegs:$Rs), ImmPred:$Off)),
- (MI IntRegs:$Rs, imm:$Off, Value:$Rt)>;
-}
-class Storex_simple_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
- : Pat<(Store Value:$Rt, (i32 IntRegs:$Rs)),
- (MI IntRegs:$Rs, 0, Value:$Rt)>;
-
-// Patterns for generating stores, where the address takes different forms,
-// and where the value being stored is transformed through the value modifier
-// ValueMod. The address forms are same as above.
-class Storexm_fi_pat<PatFrag Store, PatFrag Value, PatFrag ValueMod,
- InstHexagon MI>
- : Pat<(Store Value:$Rs, AddrFI:$fi),
- (MI AddrFI:$fi, 0, (ValueMod Value:$Rs))>;
-multiclass Storexm_fi_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
- PatFrag ValueMod, InstHexagon MI> {
- def: Pat<(Store Value:$Rs, (add (i32 AddrFI:$fi), ImmPred:$Off)),
- (MI AddrFI:$fi, imm:$Off, (ValueMod Value:$Rs))>;
- def: Pat<(Store Value:$Rs, (orisadd (i32 AddrFI:$fi), ImmPred:$Off)),
- (MI AddrFI:$fi, imm:$Off, (ValueMod Value:$Rs))>;
-}
-multiclass Storexm_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
- PatFrag ValueMod, InstHexagon MI> {
- def: Pat<(Store Value:$Rt, (add (i32 IntRegs:$Rs), ImmPred:$Off)),
- (MI IntRegs:$Rs, imm:$Off, (ValueMod Value:$Rt))>;
- def: Pat<(Store Value:$Rt, (orisadd (i32 IntRegs:$Rs), ImmPred:$Off)),
- (MI IntRegs:$Rs, imm:$Off, (ValueMod Value:$Rt))>;
-}
-class Storexm_simple_pat<PatFrag Store, PatFrag Value, PatFrag ValueMod,
- InstHexagon MI>
- : Pat<(Store Value:$Rt, (i32 IntRegs:$Rs)),
- (MI IntRegs:$Rs, 0, (ValueMod Value:$Rt))>;
-
-multiclass Storex_pat<PatFrag Store, PatFrag Value, PatLeaf ImmPred,
- InstHexagon MI> {
- def: Storex_fi_pat <Store, Value, MI>;
- defm: Storex_fi_add_pat <Store, Value, ImmPred, MI>;
- defm: Storex_add_pat <Store, Value, ImmPred, MI>;
-}
-
-multiclass Storexm_pat<PatFrag Store, PatFrag Value, PatLeaf ImmPred,
- PatFrag ValueMod, InstHexagon MI> {
- def: Storexm_fi_pat <Store, Value, ValueMod, MI>;
- defm: Storexm_fi_add_pat <Store, Value, ImmPred, ValueMod, MI>;
- defm: Storexm_add_pat <Store, Value, ImmPred, ValueMod, MI>;
-}
-
-// Regular stores in the DAG have two operands: value and address.
-// Atomic stores also have two, but they are reversed: address, value.
-// To use atomic stores with the patterns, they need to have their operands
-// swapped. This relies on the knowledge that the F.Fragment uses names
-// "ptr" and "val".
-class SwapSt<PatFrag F>
- : PatFrag<(ops node:$val, node:$ptr), F.Fragment, F.PredicateCode,
- F.OperandTransform>;
-
-let AddedComplexity = 20 in {
- defm: Storex_pat<truncstorei8, I32, s32_0ImmPred, S2_storerb_io>;
- defm: Storex_pat<truncstorei16, I32, s31_1ImmPred, S2_storerh_io>;
- defm: Storex_pat<store, I32, s30_2ImmPred, S2_storeri_io>;
- defm: Storex_pat<store, I64, s29_3ImmPred, S2_storerd_io>;
-
- defm: Storex_pat<SwapSt<atomic_store_8>, I32, s32_0ImmPred, S2_storerb_io>;
- defm: Storex_pat<SwapSt<atomic_store_16>, I32, s31_1ImmPred, S2_storerh_io>;
- defm: Storex_pat<SwapSt<atomic_store_32>, I32, s30_2ImmPred, S2_storeri_io>;
- defm: Storex_pat<SwapSt<atomic_store_64>, I64, s29_3ImmPred, S2_storerd_io>;
-}
-
-// Simple patterns should be tried with the least priority.
-def: Storex_simple_pat<truncstorei8, I32, S2_storerb_io>;
-def: Storex_simple_pat<truncstorei16, I32, S2_storerh_io>;
-def: Storex_simple_pat<store, I32, S2_storeri_io>;
-def: Storex_simple_pat<store, I64, S2_storerd_io>;
-
-def: Storex_simple_pat<SwapSt<atomic_store_8>, I32, S2_storerb_io>;
-def: Storex_simple_pat<SwapSt<atomic_store_16>, I32, S2_storerh_io>;
-def: Storex_simple_pat<SwapSt<atomic_store_32>, I32, S2_storeri_io>;
-def: Storex_simple_pat<SwapSt<atomic_store_64>, I64, S2_storerd_io>;
-
-let AddedComplexity = 20 in {
- defm: Storexm_pat<truncstorei8, I64, s32_0ImmPred, LoReg, S2_storerb_io>;
- defm: Storexm_pat<truncstorei16, I64, s31_1ImmPred, LoReg, S2_storerh_io>;
- defm: Storexm_pat<truncstorei32, I64, s30_2ImmPred, LoReg, S2_storeri_io>;
-}
-
-def: Storexm_simple_pat<truncstorei8, I64, LoReg, S2_storerb_io>;
-def: Storexm_simple_pat<truncstorei16, I64, LoReg, S2_storerh_io>;
-def: Storexm_simple_pat<truncstorei32, I64, LoReg, S2_storeri_io>;
-
// Store predicate.
let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13,
isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in
@@ -3951,8 +3472,6 @@ let isReMaterializable = 1, isAsCheapAsAMove = 1 in {
// Sign extend word to doubleword
def A2_sxtw : T_S2op_1_di <"sxtw", 0b01, 0b000>;
-def: Pat <(i64 (sext I32:$src)), (A2_sxtw I32:$src)>;
-
// Vector saturate and pack
let Defs = [USR_OVF] in {
def S2_svsathb : T_S2op_1_ii <"vsathb", 0b10, 0b000>;
@@ -4001,22 +3520,11 @@ let Itinerary = S_2op_tc_2_SLOT23 in {
def A2_negsat : T_S2op_1_ii <"neg", 0b10, 0b110, 1>;
}
-def: Pat<(i32 (select (i1 (setlt (i32 IntRegs:$src), 0)),
- (i32 (sub 0, (i32 IntRegs:$src))),
- (i32 IntRegs:$src))),
- (A2_abs IntRegs:$src)>;
-
-let AddedComplexity = 50 in
-def: Pat<(i32 (xor (add (sra (i32 IntRegs:$src), (i32 31)),
- (i32 IntRegs:$src)),
- (sra (i32 IntRegs:$src), (i32 31)))),
- (A2_abs IntRegs:$src)>;
-
class T_S2op_2 <string mnemonic, bits<4> RegTyBits, RegisterClass RCOut,
RegisterClass RCIn, bits<3> MajOp, bits<3> MinOp,
bit isSat, bit isRnd, list<dag> pattern = []>
: SInst <(outs RCOut:$dst),
- (ins RCIn:$src, u5Imm:$u5),
+ (ins RCIn:$src, u5_0Imm:$u5),
"$dst = "#mnemonic#"($src, #$u5)"#!if(isSat, ":sat", "")
#!if(isRnd, ":rnd", ""),
pattern, "", S_2op_tc_2_SLOT23> {
@@ -4049,9 +3557,7 @@ class T_S2op_2_ii <string mnemonic, bits<3> MajOp, bits<3> MinOp,
isSat, isRnd, pattern>;
class T_S2op_shift <string mnemonic, bits<3> MajOp, bits<3> MinOp, SDNode OpNd>
- : T_S2op_2_ii <mnemonic, MajOp, MinOp, 0, 0,
- [(set (i32 IntRegs:$dst), (OpNd (i32 IntRegs:$src),
- (u5ImmPred:$u5)))]>;
+ : T_S2op_2_ii <mnemonic, MajOp, MinOp, 0, 0, []>;
// Vector arithmetic shift right by immediate with truncate and pack
def S2_asr_i_svw_trun : T_S2op_2_id <"vasrw", 0b110, 0b010>;
@@ -4072,7 +3578,7 @@ def S2_asr_i_r_rnd : T_S2op_2_ii <"asr", 0b010, 0b000, 0, 1>;
let isAsmParserOnly = 1 in
def S2_asr_i_r_rnd_goodsyntax
- : SInst <(outs IntRegs:$dst), (ins IntRegs:$src, u5Imm:$u5),
+ : SInst <(outs IntRegs:$dst), (ins IntRegs:$src, u5_0Imm:$u5),
"$dst = asrrnd($src, #$u5)",
[], "", S_2op_tc_1_SLOT23>;
@@ -4080,11 +3586,6 @@ let isAsmParserOnly = 1 in
def A2_not: ALU32_rr<(outs IntRegs:$dst),(ins IntRegs:$src),
"$dst = not($src)">;
-def: Pat<(i32 (sra (i32 (add (i32 (sra I32:$src1, u5ImmPred:$src2)),
- (i32 1))),
- (i32 1))),
- (S2_asr_i_r_rnd IntRegs:$src1, u5ImmPred:$src2)>;
-
class T_S2op_3<string opc, bits<2>MajOp, bits<3>minOp, bits<1> sat = 0>
: SInst<(outs DoubleRegs:$Rdd), (ins DoubleRegs:$Rss),
"$Rdd = "#opc#"($Rss)"#!if(!eq(sat, 1),":sat","")> {
@@ -4124,9 +3625,6 @@ def A2_vabshsat : T_S2op_3 <"vabsh", 0b01, 0b101, 1>;
def A2_vabsw : T_S2op_3 <"vabsw", 0b01, 0b110>;
def A2_vabswsat : T_S2op_3 <"vabsw", 0b01, 0b111, 1>;
-def : Pat<(not (i64 DoubleRegs:$src1)),
- (A2_notp DoubleRegs:$src1)>;
-
//===----------------------------------------------------------------------===//
// STYPE/BIT +
//===----------------------------------------------------------------------===//
@@ -4166,27 +3664,13 @@ def S2_clb : T_COUNT_LEADING_32<"clb", 0b000, 0b100>;
def S2_clbp : T_COUNT_LEADING_64<"clb", 0b010, 0b000>;
def S2_clbnorm : T_COUNT_LEADING_32<"normamt", 0b000, 0b111>;
-// Count leading zeros.
-def: Pat<(i32 (ctlz I32:$Rs)), (S2_cl0 I32:$Rs)>;
-def: Pat<(i32 (trunc (ctlz I64:$Rss))), (S2_cl0p I64:$Rss)>;
-
-// Count trailing zeros: 32-bit.
-def: Pat<(i32 (cttz I32:$Rs)), (S2_ct0 I32:$Rs)>;
-
-// Count leading ones.
-def: Pat<(i32 (ctlz (not I32:$Rs))), (S2_cl1 I32:$Rs)>;
-def: Pat<(i32 (trunc (ctlz (not I64:$Rss)))), (S2_cl1p I64:$Rss)>;
-
-// Count trailing ones: 32-bit.
-def: Pat<(i32 (cttz (not I32:$Rs))), (S2_ct1 I32:$Rs)>;
-
// The 64-bit counts leading/trailing are defined in HexagonInstrInfoV4.td.
// Bit set/clear/toggle
let hasSideEffects = 0, hasNewValue = 1 in
class T_SCT_BIT_IMM<string MnOp, bits<3> MinOp>
- : SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, u5Imm:$u5),
+ : SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, u5_0Imm:$u5),
"$Rd = "#MnOp#"($Rs, #$u5)", [], "", S_2op_tc_1_SLOT23> {
bits<5> Rd;
bits<5> Rs;
@@ -4222,24 +3706,11 @@ def S2_clrbit_r : T_SCT_BIT_REG<"clrbit", 0b01>;
def S2_setbit_r : T_SCT_BIT_REG<"setbit", 0b00>;
def S2_togglebit_r : T_SCT_BIT_REG<"togglebit", 0b10>;
-def: Pat<(i32 (and (i32 IntRegs:$Rs), (not (shl 1, u5ImmPred:$u5)))),
- (S2_clrbit_i IntRegs:$Rs, u5ImmPred:$u5)>;
-def: Pat<(i32 (or (i32 IntRegs:$Rs), (shl 1, u5ImmPred:$u5))),
- (S2_setbit_i IntRegs:$Rs, u5ImmPred:$u5)>;
-def: Pat<(i32 (xor (i32 IntRegs:$Rs), (shl 1, u5ImmPred:$u5))),
- (S2_togglebit_i IntRegs:$Rs, u5ImmPred:$u5)>;
-def: Pat<(i32 (and (i32 IntRegs:$Rs), (not (shl 1, (i32 IntRegs:$Rt))))),
- (S2_clrbit_r IntRegs:$Rs, IntRegs:$Rt)>;
-def: Pat<(i32 (or (i32 IntRegs:$Rs), (shl 1, (i32 IntRegs:$Rt)))),
- (S2_setbit_r IntRegs:$Rs, IntRegs:$Rt)>;
-def: Pat<(i32 (xor (i32 IntRegs:$Rs), (shl 1, (i32 IntRegs:$Rt)))),
- (S2_togglebit_r IntRegs:$Rs, IntRegs:$Rt)>;
-
// Bit test
let hasSideEffects = 0 in
class T_TEST_BIT_IMM<string MnOp, bits<3> MajOp>
- : SInst<(outs PredRegs:$Pd), (ins IntRegs:$Rs, u5Imm:$u5),
+ : SInst<(outs PredRegs:$Pd), (ins IntRegs:$Rs, u5_0Imm:$u5),
"$Pd = "#MnOp#"($Rs, #$u5)",
[], "", S_2op_tc_2early_SLOT23> {
bits<2> Pd;
@@ -4273,20 +3744,9 @@ class T_TEST_BIT_REG<string MnOp, bit IsNeg>
def S2_tstbit_i : T_TEST_BIT_IMM<"tstbit", 0b000>;
def S2_tstbit_r : T_TEST_BIT_REG<"tstbit", 0>;
-let AddedComplexity = 20 in { // Complexity greater than cmp reg-imm.
- def: Pat<(i1 (setne (and (shl 1, u5ImmPred:$u5), (i32 IntRegs:$Rs)), 0)),
- (S2_tstbit_i IntRegs:$Rs, u5ImmPred:$u5)>;
- def: Pat<(i1 (setne (and (shl 1, (i32 IntRegs:$Rt)), (i32 IntRegs:$Rs)), 0)),
- (S2_tstbit_r IntRegs:$Rs, IntRegs:$Rt)>;
- def: Pat<(i1 (trunc (i32 IntRegs:$Rs))),
- (S2_tstbit_i IntRegs:$Rs, 0)>;
- def: Pat<(i1 (trunc (i64 DoubleRegs:$Rs))),
- (S2_tstbit_i (LoReg DoubleRegs:$Rs), 0)>;
-}
-
let hasSideEffects = 0 in
class T_TEST_BITS_IMM<string MnOp, bits<2> MajOp, bit IsNeg>
- : SInst<(outs PredRegs:$Pd), (ins IntRegs:$Rs, u6Imm:$u6),
+ : SInst<(outs PredRegs:$Pd), (ins IntRegs:$Rs, u6_0Imm:$u6),
"$Pd = "#MnOp#"($Rs, #$u6)",
[], "", S_2op_tc_2early_SLOT23> {
bits<2> Pd;
@@ -4322,17 +3782,6 @@ def C2_bitsclri : T_TEST_BITS_IMM<"bitsclr", 0b10, 0>;
def C2_bitsclr : T_TEST_BITS_REG<"bitsclr", 0b10, 0>;
def C2_bitsset : T_TEST_BITS_REG<"bitsset", 0b01, 0>;
-let AddedComplexity = 20 in { // Complexity greater than compare reg-imm.
- def: Pat<(i1 (seteq (and (i32 IntRegs:$Rs), u6ImmPred:$u6), 0)),
- (C2_bitsclri IntRegs:$Rs, u6ImmPred:$u6)>;
- def: Pat<(i1 (seteq (and (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)), 0)),
- (C2_bitsclr IntRegs:$Rs, IntRegs:$Rt)>;
-}
-
-let AddedComplexity = 10 in // Complexity greater than compare reg-reg.
-def: Pat<(i1 (seteq (and (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)), IntRegs:$Rt)),
- (C2_bitsset IntRegs:$Rs, IntRegs:$Rt)>;
-
//===----------------------------------------------------------------------===//
// STYPE/BIT -
//===----------------------------------------------------------------------===//
@@ -4348,14 +3797,6 @@ def: Pat<(i1 (seteq (and (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)), IntRegs:$Rt)),
// XTYPE/PERM +
//===----------------------------------------------------------------------===//
-def: Pat<(or (or (shl (or (shl (i32 (extloadi8 (add (i32 IntRegs:$b), 3))),
- (i32 8)),
- (i32 (zextloadi8 (add (i32 IntRegs:$b), 2)))),
- (i32 16)),
- (shl (i32 (zextloadi8 (add (i32 IntRegs:$b), 1))), (i32 8))),
- (zextloadi8 (i32 IntRegs:$b))),
- (A2_swiz (L2_loadri_io IntRegs:$b, 0))>;
-
//===----------------------------------------------------------------------===//
// XTYPE/PERM -
//===----------------------------------------------------------------------===//
@@ -4395,24 +3836,6 @@ let hasSideEffects = 0, isCodeGenOnly = 1 in
def C2_pxfer_map: SInst<(outs PredRegs:$dst), (ins PredRegs:$src),
"$dst = $src">;
-
-// Patterns for loads of i1:
-def: Pat<(i1 (load AddrFI:$fi)),
- (C2_tfrrp (L2_loadrub_io AddrFI:$fi, 0))>;
-def: Pat<(i1 (load (add (i32 IntRegs:$Rs), s32ImmPred:$Off))),
- (C2_tfrrp (L2_loadrub_io IntRegs:$Rs, imm:$Off))>;
-def: Pat<(i1 (load (i32 IntRegs:$Rs))),
- (C2_tfrrp (L2_loadrub_io IntRegs:$Rs, 0))>;
-
-def I1toI32: OutPatFrag<(ops node:$Rs),
- (C2_muxii (i1 $Rs), 1, 0)>;
-
-def I32toI1: OutPatFrag<(ops node:$Rs),
- (i1 (C2_tfrrp (i32 $Rs)))>;
-
-defm: Storexm_pat<store, I1, s32ImmPred, I1toI32, S2_storerb_io>;
-def: Storexm_simple_pat<store, I1, I1toI32, S2_storerb_io>;
-
//===----------------------------------------------------------------------===//
// STYPE/PRED -
//===----------------------------------------------------------------------===//
@@ -4436,9 +3859,7 @@ class S_2OpInstImm<string Mnemonic, bits<3>MajOp, bits<3>MinOp,
}
class S_2OpInstImmI6<string Mnemonic, SDNode OpNode, bits<3>MinOp>
- : S_2OpInstImm<Mnemonic, 0b000, MinOp, u6Imm,
- [(set (i64 DoubleRegs:$dst), (OpNode (i64 DoubleRegs:$src1),
- u6ImmPred:$src2))]> {
+ : S_2OpInstImm<Mnemonic, 0b000, MinOp, u6_0Imm, []> {
bits<6> src2;
let Inst{13-8} = src2;
}
@@ -4451,10 +3872,8 @@ def S2_lsr_i_p : S_2OpInstImmI6<"lsr", srl, 0b001>;
// Shift left by small amount and add.
let AddedComplexity = 100, hasNewValue = 1, hasSideEffects = 0 in
def S2_addasl_rrri: SInst <(outs IntRegs:$Rd),
- (ins IntRegs:$Rt, IntRegs:$Rs, u3Imm:$u3),
- "$Rd = addasl($Rt, $Rs, #$u3)" ,
- [(set (i32 IntRegs:$Rd), (add (i32 IntRegs:$Rt),
- (shl (i32 IntRegs:$Rs), u3ImmPred:$u3)))],
+ (ins IntRegs:$Rt, IntRegs:$Rs, u3_0Imm:$u3),
+ "$Rd = addasl($Rt, $Rs, #$u3)" , [],
"", S_3op_tc_2_SLOT23> {
bits<5> Rd;
bits<5> Rt;
@@ -4496,12 +3915,8 @@ def S2_addasl_rrri: SInst <(outs IntRegs:$Rd),
//===----------------------------------------------------------------------===//
// SYSTEM/USER +
//===----------------------------------------------------------------------===//
-def HexagonBARRIER: SDNode<"HexagonISD::BARRIER", SDTNone, [SDNPHasChain]>;
-
let hasSideEffects = 1, isSoloAX = 1 in
-def Y2_barrier : SYSInst<(outs), (ins),
- "barrier",
- [(HexagonBARRIER)],"",ST_tc_st_SLOT0> {
+def Y2_barrier : SYSInst<(outs), (ins), "barrier", [],"",ST_tc_st_SLOT0> {
let Inst{31-28} = 0b1010;
let Inst{27-21} = 0b1000000;
}
@@ -4517,15 +3932,12 @@ def Y2_barrier : SYSInst<(outs), (ins),
//
let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1,
isPseudo = 1, isCodeGenOnly = 1, hasSideEffects = 0 in {
- def TFR_FI : ALU32_ri<(outs IntRegs:$Rd),
- (ins IntRegs:$fi, s32Imm:$off), "">;
- def TFR_FIA : ALU32_ri<(outs IntRegs:$Rd),
- (ins IntRegs:$Rs, IntRegs:$fi, s32Imm:$off), "">;
+ def PS_fi : ALU32_ri<(outs IntRegs:$Rd),
+ (ins IntRegs:$fi, s32_0Imm:$off), "">;
+ def PS_fia : ALU32_ri<(outs IntRegs:$Rd),
+ (ins IntRegs:$Rs, IntRegs:$fi, s32_0Imm:$off), "">;
}
-def: Pat<(i32 (orisadd (i32 AddrFI:$Rs), s32ImmPred:$off)),
- (i32 (TFR_FI (i32 AddrFI:$Rs), s32ImmPred:$off))>;
-
//===----------------------------------------------------------------------===//
// CRUSER - Type.
//===----------------------------------------------------------------------===//
@@ -4533,7 +3945,7 @@ def: Pat<(i32 (orisadd (i32 AddrFI:$Rs), s32ImmPred:$off)),
let isExtendable = 1, isExtentSigned = 1, opExtentBits = 9, opExtentAlign = 2,
opExtendable = 0, hasSideEffects = 0 in
class LOOP_iBase<string mnemonic, Operand brOp, bit mustExtend = 0>
- : CRInst<(outs), (ins brOp:$offset, u10Imm:$src2),
+ : CRInst<(outs), (ins brOp:$offset, u10_0Imm:$src2),
#mnemonic#"($offset, #$src2)",
[], "" , CR_tc_3x_SLOT3> {
bits<9> offset;
@@ -4605,7 +4017,7 @@ let Defs = [LC0, SA0, P3, USR], hasSideEffects = 0,
isExtentSigned = 1, isExtendable = 1, opExtentBits = 9, opExtentAlign = 2,
opExtendable = 0, isPredicateLate = 1 in
class SPLOOP_iBase<string SP, bits<2> op>
- : CRInst <(outs), (ins brtarget:$r7_2, u10Imm:$U10),
+ : CRInst <(outs), (ins brtarget:$r7_2, u10_0Imm:$U10),
"p3 = sp"#SP#"loop0($r7_2, #$U10)" > {
bits<9> r7_2;
bits<10> U10;
@@ -4733,20 +4145,12 @@ def Y4_trace: CRInst <(outs), (ins IntRegs:$Rs),
let Inst{20-16} = Rs;
}
-// Support for generating global address.
-// Taken from X86InstrInfo.td.
-def SDTHexagonCONST32 : SDTypeProfile<1, 1, [SDTCisVT<0, i32>,
- SDTCisVT<1, i32>,
- SDTCisPtrTy<0>]>;
-def HexagonCONST32 : SDNode<"HexagonISD::CONST32", SDTHexagonCONST32>;
-def HexagonCONST32_GP : SDNode<"HexagonISD::CONST32_GP", SDTHexagonCONST32>;
-
// HI/LO Instructions
let isReMaterializable = 1, isMoveImm = 1, hasSideEffects = 0,
hasNewValue = 1, opNewValue = 0 in
class REG_IMMED<string RegHalf, bit Rs, bits<3> MajOp, bit MinOp>
: ALU32_ri<(outs IntRegs:$dst),
- (ins u16Imm:$imm_value),
+ (ins u16_0Imm:$imm_value),
"$dst"#RegHalf#" = $imm_value", []> {
bits<5> dst;
bits<32> imm_value;
@@ -4765,100 +4169,28 @@ let isAsmParserOnly = 1 in {
def HI : REG_IMMED<".h", 0b0, 0b010, 0b1>;
}
-let isMoveImm = 1, isCodeGenOnly = 1 in
-def LO_PIC : ALU32_ri<(outs IntRegs:$dst), (ins bblabel:$label),
- "$dst.l = #LO($label@GOTREL)",
- []>;
-
-let isMoveImm = 1, isCodeGenOnly = 1 in
-def HI_PIC : ALU32_ri<(outs IntRegs:$dst), (ins bblabel:$label),
- "$dst.h = #HI($label@GOTREL)",
- []>;
-
-let isReMaterializable = 1, isMoveImm = 1,
- isCodeGenOnly = 1, hasSideEffects = 0 in
-def HI_GOT : ALU32_ri<(outs IntRegs:$dst), (ins globaladdress:$global),
- "$dst.h = #HI($global@GOT)",
- []>;
-
-let isReMaterializable = 1, isMoveImm = 1,
- isCodeGenOnly = 1, hasSideEffects = 0 in
-def LO_GOT : ALU32_ri<(outs IntRegs:$dst), (ins globaladdress:$global),
- "$dst.l = #LO($global@GOT)",
- []>;
-
-let isReMaterializable = 1, isMoveImm = 1,
- isCodeGenOnly = 1, hasSideEffects = 0 in
-def HI_GOTREL : ALU32_ri<(outs IntRegs:$dst), (ins globaladdress:$global),
- "$dst.h = #HI($global@GOTREL)",
- []>;
-
-let isReMaterializable = 1, isMoveImm = 1,
- isCodeGenOnly = 1, hasSideEffects = 0 in
-def LO_GOTREL : ALU32_ri<(outs IntRegs:$dst), (ins globaladdress:$global),
- "$dst.l = #LO($global@GOTREL)",
- []>;
-
-// This pattern is incorrect. When we add small data, we should change
-// this pattern to use memw(#foo).
-// This is for sdata.
-let isMoveImm = 1, isAsmParserOnly = 1 in
-def CONST32 : CONSTLDInst<(outs IntRegs:$dst), (ins globaladdress:$global),
- "$dst = CONST32(#$global)",
- [(set (i32 IntRegs:$dst),
- (load (HexagonCONST32 tglobaltlsaddr:$global)))]>;
-
-let isReMaterializable = 1, isMoveImm = 1, isAsmParserOnly = 1 in
-def CONST32_Int_Real : CONSTLDInst<(outs IntRegs:$dst), (ins i32imm:$global),
- "$dst = CONST32(#$global)",
- [(set (i32 IntRegs:$dst), imm:$global) ]>;
-
-// Map TLS addressses to a CONST32 instruction
-def: Pat<(HexagonCONST32 tglobaltlsaddr:$addr), (A2_tfrsi s16Ext:$addr)>;
-def: Pat<(HexagonCONST32 bbl:$label), (A2_tfrsi s16Ext:$label)>;
-
-let isReMaterializable = 1, isMoveImm = 1, isAsmParserOnly = 1 in
-def CONST64_Int_Real : CONSTLDInst<(outs DoubleRegs:$dst), (ins i64imm:$global),
- "$dst = CONST64(#$global)",
- [(set (i64 DoubleRegs:$dst), imm:$global)]>;
+let isReMaterializable = 1, isMoveImm = 1, isAsmParserOnly = 1 in {
+ def CONST32 : CONSTLDInst<(outs IntRegs:$Rd), (ins i32imm:$v),
+ "$Rd = CONST32(#$v)", []>;
+ def CONST64 : CONSTLDInst<(outs DoubleRegs:$Rd), (ins i64imm:$v),
+ "$Rd = CONST64(#$v)", []>;
+}
let hasSideEffects = 0, isReMaterializable = 1, isPseudo = 1,
isCodeGenOnly = 1 in
-def TFR_PdTrue : SInst<(outs PredRegs:$dst), (ins), "",
- [(set (i1 PredRegs:$dst), 1)]>;
+def PS_true : SInst<(outs PredRegs:$dst), (ins), "", []>;
let hasSideEffects = 0, isReMaterializable = 1, isPseudo = 1,
isCodeGenOnly = 1 in
-def TFR_PdFalse : SInst<(outs PredRegs:$dst), (ins), "",
- [(set (i1 PredRegs:$dst), 0)]>;
-
-// Pseudo instructions.
-def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
-def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
- SDTCisVT<1, i32> ]>;
-
-def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_SPCallSeqStart,
- [SDNPHasChain, SDNPOutGlue]>;
-def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SPCallSeqEnd,
- [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
-
-def SDT_SPCall : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
-
-// For tailcalls a HexagonTCRet SDNode has 3 SDNode Properties - a chain,
-// Optional Flag and Variable Arguments.
-// Its 1 Operand has pointer type.
-def HexagonTCRet : SDNode<"HexagonISD::TC_RETURN", SDT_SPCall,
- [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+def PS_false : SInst<(outs PredRegs:$dst), (ins), "", []>;
let Defs = [R29, R30], Uses = [R31, R30, R29], isPseudo = 1 in
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt),
- ".error \"should not emit\" ",
- [(callseq_start timm:$amt)]>;
+ ".error \"should not emit\" ", []>;
let Defs = [R29, R30, R31], Uses = [R29], isPseudo = 1 in
def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
- ".error \"should not emit\" ",
- [(callseq_end timm:$amt1, timm:$amt2)]>;
+ ".error \"should not emit\" ", []>;
// Call subroutine indirectly.
let Defs = VolatileV3.Regs in
@@ -4867,260 +4199,21 @@ def J2_callr : JUMPR_MISC_CALLR<0, 1>;
// Indirect tail-call.
let isPseudo = 1, isCall = 1, isReturn = 1, isBarrier = 1, isPredicable = 0,
isTerminator = 1, isCodeGenOnly = 1 in
-def TCRETURNr : T_JMPr;
+def PS_tailcall_r : T_JMPr;
// Direct tail-calls.
let isPseudo = 1, isCall = 1, isReturn = 1, isBarrier = 1, isPredicable = 0,
isTerminator = 1, isCodeGenOnly = 1 in
-def TCRETURNi : JInst<(outs), (ins calltarget:$dst), "", []>;
-
-//Tail calls.
-def: Pat<(HexagonTCRet tglobaladdr:$dst),
- (TCRETURNi tglobaladdr:$dst)>;
-def: Pat<(HexagonTCRet texternalsym:$dst),
- (TCRETURNi texternalsym:$dst)>;
-def: Pat<(HexagonTCRet (i32 IntRegs:$dst)),
- (TCRETURNr IntRegs:$dst)>;
-
-// Map from r0 = and(r1, 65535) to r0 = zxth(r1)
-def: Pat<(and (i32 IntRegs:$src1), 65535),
- (A2_zxth IntRegs:$src1)>;
-
-// Map from r0 = and(r1, 255) to r0 = zxtb(r1).
-def: Pat<(and (i32 IntRegs:$src1), 255),
- (A2_zxtb IntRegs:$src1)>;
-
-// Map Add(p1, true) to p1 = not(p1).
-// Add(p1, false) should never be produced,
-// if it does, it got to be mapped to NOOP.
-def: Pat<(add (i1 PredRegs:$src1), -1),
- (C2_not PredRegs:$src1)>;
-
-// Map from p0 = pnot(p0); r0 = mux(p0, #i, #j) => r0 = mux(p0, #j, #i).
-def: Pat<(select (not (i1 PredRegs:$src1)), s8ImmPred:$src2, s32ImmPred:$src3),
- (C2_muxii PredRegs:$src1, s32ImmPred:$src3, s8ImmPred:$src2)>;
-
-// Map from p0 = pnot(p0); r0 = select(p0, #i, r1)
-// => r0 = C2_muxir(p0, r1, #i)
-def: Pat<(select (not (i1 PredRegs:$src1)), s32ImmPred:$src2,
- (i32 IntRegs:$src3)),
- (C2_muxir PredRegs:$src1, IntRegs:$src3, s32ImmPred:$src2)>;
-
-// Map from p0 = pnot(p0); r0 = mux(p0, r1, #i)
-// => r0 = C2_muxri (p0, #i, r1)
-def: Pat<(select (not (i1 PredRegs:$src1)), IntRegs:$src2, s32ImmPred:$src3),
- (C2_muxri PredRegs:$src1, s32ImmPred:$src3, IntRegs:$src2)>;
-
-// Map from p0 = pnot(p0); if (p0) jump => if (!p0) jump.
-def: Pat<(brcond (not (i1 PredRegs:$src1)), bb:$offset),
- (J2_jumpf PredRegs:$src1, bb:$offset)>;
-
-// Map from Rdd = sign_extend_inreg(Rss, i32) -> Rdd = A2_sxtw(Rss.lo).
-def: Pat<(i64 (sext_inreg (i64 DoubleRegs:$src1), i32)),
- (A2_sxtw (LoReg DoubleRegs:$src1))>;
-
-// Map from Rdd = sign_extend_inreg(Rss, i16) -> Rdd = A2_sxtw(A2_sxth(Rss.lo)).
-def: Pat<(i64 (sext_inreg (i64 DoubleRegs:$src1), i16)),
- (A2_sxtw (A2_sxth (LoReg DoubleRegs:$src1)))>;
-
-// Map from Rdd = sign_extend_inreg(Rss, i8) -> Rdd = A2_sxtw(A2_sxtb(Rss.lo)).
-def: Pat<(i64 (sext_inreg (i64 DoubleRegs:$src1), i8)),
- (A2_sxtw (A2_sxtb (LoReg DoubleRegs:$src1)))>;
-
-// We want to prevent emitting pnot's as much as possible.
-// Map brcond with an unsupported setcc to a J2_jumpf.
-def : Pat <(brcond (i1 (setne (i32 IntRegs:$src1), (i32 IntRegs:$src2))),
- bb:$offset),
- (J2_jumpf (C2_cmpeq (i32 IntRegs:$src1), (i32 IntRegs:$src2)),
- bb:$offset)>;
-
-def : Pat <(brcond (i1 (setne (i32 IntRegs:$src1), s10ImmPred:$src2)),
- bb:$offset),
- (J2_jumpf (C2_cmpeqi (i32 IntRegs:$src1), s10ImmPred:$src2), bb:$offset)>;
-
-def: Pat<(brcond (i1 (setne (i1 PredRegs:$src1), (i1 -1))), bb:$offset),
- (J2_jumpf PredRegs:$src1, bb:$offset)>;
-
-def: Pat<(brcond (i1 (setne (i1 PredRegs:$src1), (i1 0))), bb:$offset),
- (J2_jumpt PredRegs:$src1, bb:$offset)>;
-
-// cmp.lt(Rs, Imm) -> !cmp.ge(Rs, Imm) -> !cmp.gt(Rs, Imm-1)
-def: Pat<(brcond (i1 (setlt (i32 IntRegs:$src1), s8ImmPred:$src2)), bb:$offset),
- (J2_jumpf (C2_cmpgti IntRegs:$src1, (DEC_CONST_SIGNED s8ImmPred:$src2)),
- bb:$offset)>;
-
-// Map from a 64-bit select to an emulated 64-bit mux.
-// Hexagon does not support 64-bit MUXes; so emulate with combines.
-def: Pat<(select (i1 PredRegs:$src1), (i64 DoubleRegs:$src2),
- (i64 DoubleRegs:$src3)),
- (A2_combinew (C2_mux PredRegs:$src1, (HiReg DoubleRegs:$src2),
- (HiReg DoubleRegs:$src3)),
- (C2_mux PredRegs:$src1, (LoReg DoubleRegs:$src2),
- (LoReg DoubleRegs:$src3)))>;
-
-// Map from a 1-bit select to logical ops.
-// From LegalizeDAG.cpp: (B1 ? B2 : B3) <=> (B1 & B2)|(!B1&B3).
-def: Pat<(select (i1 PredRegs:$src1), (i1 PredRegs:$src2), (i1 PredRegs:$src3)),
- (C2_or (C2_and PredRegs:$src1, PredRegs:$src2),
- (C2_and (C2_not PredRegs:$src1), PredRegs:$src3))>;
-
-// Map for truncating from 64 immediates to 32 bit immediates.
-def: Pat<(i32 (trunc (i64 DoubleRegs:$src))),
- (LoReg DoubleRegs:$src)>;
-
-// Map for truncating from i64 immediates to i1 bit immediates.
-def: Pat<(i1 (trunc (i64 DoubleRegs:$src))),
- (C2_tfrrp (LoReg DoubleRegs:$src))>;
-
-// rs <= rt -> !(rs > rt).
-let AddedComplexity = 30 in
-def: Pat<(i1 (setle (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C2_not (C2_cmpgti IntRegs:$src1, s32ImmPred:$src2))>;
-
-// rs <= rt -> !(rs > rt).
-def : Pat<(i1 (setle (i32 IntRegs:$src1), (i32 IntRegs:$src2))),
- (i1 (C2_not (C2_cmpgt (i32 IntRegs:$src1), (i32 IntRegs:$src2))))>;
-
-// Rss <= Rtt -> !(Rss > Rtt).
-def: Pat<(i1 (setle (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2))),
- (C2_not (C2_cmpgtp DoubleRegs:$src1, DoubleRegs:$src2))>;
-
-// Map cmpne -> cmpeq.
-// Hexagon_TODO: We should improve on this.
-// rs != rt -> !(rs == rt).
-let AddedComplexity = 30 in
-def: Pat<(i1 (setne (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C2_not (C2_cmpeqi IntRegs:$src1, s32ImmPred:$src2))>;
-
-// Convert setne back to xor for hexagon since we compute w/ pred registers.
-def: Pat<(i1 (setne (i1 PredRegs:$src1), (i1 PredRegs:$src2))),
- (C2_xor PredRegs:$src1, PredRegs:$src2)>;
-
-// Map cmpne(Rss) -> !cmpew(Rss).
-// rs != rt -> !(rs == rt).
-def: Pat<(i1 (setne (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2))),
- (C2_not (C2_cmpeqp DoubleRegs:$src1, DoubleRegs:$src2))>;
-
-// Map cmpge(Rs, Rt) -> !(cmpgt(Rs, Rt).
-// rs >= rt -> !(rt > rs).
-def : Pat <(i1 (setge (i32 IntRegs:$src1), (i32 IntRegs:$src2))),
- (i1 (C2_not (i1 (C2_cmpgt (i32 IntRegs:$src2), (i32 IntRegs:$src1)))))>;
-
-// cmpge(Rs, Imm) -> cmpgt(Rs, Imm-1)
-let AddedComplexity = 30 in
-def: Pat<(i1 (setge (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C2_cmpgti IntRegs:$src1, (DEC_CONST_SIGNED s32ImmPred:$src2))>;
-
-// Map cmpge(Rss, Rtt) -> !cmpgt(Rtt, Rss).
-// rss >= rtt -> !(rtt > rss).
-def: Pat<(i1 (setge (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2))),
- (C2_not (C2_cmpgtp DoubleRegs:$src2, DoubleRegs:$src1))>;
-
-// Map cmplt(Rs, Imm) -> !cmpge(Rs, Imm).
-// !cmpge(Rs, Imm) -> !cmpgt(Rs, Imm-1).
-// rs < rt -> !(rs >= rt).
-let AddedComplexity = 30 in
-def: Pat<(i1 (setlt (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C2_not (C2_cmpgti IntRegs:$src1,
- (DEC_CONST_SIGNED s32ImmPred:$src2)))>;
-
-// Generate cmpgeu(Rs, #0) -> cmpeq(Rs, Rs)
-def: Pat<(i1 (setuge (i32 IntRegs:$src1), 0)),
- (C2_cmpeq IntRegs:$src1, IntRegs:$src1)>;
-
-// Generate cmpgeu(Rs, #u8) -> cmpgtu(Rs, #u8 -1)
-def: Pat<(i1 (setuge (i32 IntRegs:$src1), u32ImmPred:$src2)),
- (C2_cmpgtui IntRegs:$src1, (DEC_CONST_UNSIGNED u32ImmPred:$src2))>;
-
-// Generate cmpgtu(Rs, #u9)
-def: Pat<(i1 (setugt (i32 IntRegs:$src1), u32ImmPred:$src2)),
- (C2_cmpgtui IntRegs:$src1, u32ImmPred:$src2)>;
-
-// Map from Rs >= Rt -> !(Rt > Rs).
-// rs >= rt -> !(rt > rs).
-def: Pat<(i1 (setuge (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2))),
- (C2_not (C2_cmpgtup DoubleRegs:$src2, DoubleRegs:$src1))>;
-
-// Map from cmpleu(Rss, Rtt) -> !cmpgtu(Rss, Rtt-1).
-// Map from (Rs <= Rt) -> !(Rs > Rt).
-def: Pat<(i1 (setule (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2))),
- (C2_not (C2_cmpgtup DoubleRegs:$src1, DoubleRegs:$src2))>;
-
-// Sign extends.
-// i1 -> i32
-def: Pat<(i32 (sext (i1 PredRegs:$src1))),
- (C2_muxii PredRegs:$src1, -1, 0)>;
-
-// i1 -> i64
-def: Pat<(i64 (sext (i1 PredRegs:$src1))),
- (A2_combinew (A2_tfrsi -1), (C2_muxii PredRegs:$src1, -1, 0))>;
-
-// Zero extends.
-// i1 -> i32
-def: Pat<(i32 (zext (i1 PredRegs:$src1))),
- (C2_muxii PredRegs:$src1, 1, 0)>;
-
-// Map from Rs = Pd to Pd = mux(Pd, #1, #0)
-def: Pat<(i32 (anyext (i1 PredRegs:$src1))),
- (C2_muxii PredRegs:$src1, 1, 0)>;
-
-// Map from Rss = Pd to Rdd = sxtw (mux(Pd, #1, #0))
-def: Pat<(i64 (anyext (i1 PredRegs:$src1))),
- (A2_sxtw (C2_muxii PredRegs:$src1, 1, 0))>;
-
-// Multiply 64-bit unsigned and use upper result.
-def : Pat <(mulhu (i64 DoubleRegs:$src1), (i64 DoubleRegs:$src2)),
- (A2_addp
- (M2_dpmpyuu_acc_s0
- (S2_lsr_i_p
- (A2_addp
- (M2_dpmpyuu_acc_s0
- (S2_lsr_i_p (M2_dpmpyuu_s0 (LoReg $src1), (LoReg $src2)), 32),
- (HiReg $src1),
- (LoReg $src2)),
- (A2_combinew (A2_tfrsi 0),
- (LoReg (M2_dpmpyuu_s0 (LoReg $src1), (HiReg $src2))))),
- 32),
- (HiReg $src1),
- (HiReg $src2)),
- (S2_lsr_i_p (M2_dpmpyuu_s0 (LoReg $src1), (HiReg $src2)), 32)
-)>;
-
-// Hexagon specific ISD nodes.
-def SDTHexagonALLOCA : SDTypeProfile<1, 2,
- [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
-def HexagonALLOCA : SDNode<"HexagonISD::ALLOCA", SDTHexagonALLOCA,
- [SDNPHasChain]>;
+def PS_tailcall_i : JInst<(outs), (ins calltarget:$dst), "", []>;
// The reason for the custom inserter is to record all ALLOCA instructions
// in MachineFunctionInfo.
-let Defs = [R29], isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 1,
- usesCustomInserter = 1 in
-def ALLOCA: ALU32Inst<(outs IntRegs:$Rd),
- (ins IntRegs:$Rs, u32Imm:$A), "",
- [(set (i32 IntRegs:$Rd),
- (HexagonALLOCA (i32 IntRegs:$Rs), (i32 imm:$A)))]>;
+let Defs = [R29], isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 1 in
+def PS_alloca: ALU32Inst<(outs IntRegs:$Rd),
+ (ins IntRegs:$Rs, u32_0Imm:$A), "", []>;
let isCodeGenOnly = 1, isPseudo = 1, Uses = [R30], hasSideEffects = 0 in
-def ALIGNA : ALU32Inst<(outs IntRegs:$Rd), (ins u32Imm:$A), "", []>;
-
-def SDTHexagonARGEXTEND : SDTypeProfile<1, 1, [SDTCisVT<0, i32>]>;
-def Hexagon_ARGEXTEND : SDNode<"HexagonISD::ARGEXTEND", SDTHexagonARGEXTEND>;
-let isCodeGenOnly = 1 in
-def ARGEXTEND : ALU32_rr <(outs IntRegs:$dst), (ins IntRegs:$src1),
- "$dst = $src1",
- [(set (i32 IntRegs:$dst),
- (Hexagon_ARGEXTEND (i32 IntRegs:$src1)))]>;
-
-let AddedComplexity = 100 in
-def: Pat<(i32 (sext_inreg (Hexagon_ARGEXTEND (i32 IntRegs:$src1)), i16)),
- (i32 IntRegs:$src1)>;
-
-def HexagonJT: SDNode<"HexagonISD::JT", SDTIntUnaryOp>;
-def HexagonCP: SDNode<"HexagonISD::CP", SDTIntUnaryOp>;
-
-def: Pat<(HexagonJT tjumptable:$dst), (A2_tfrsi s16Ext:$dst)>;
-def: Pat<(HexagonCP tconstpool:$dst), (A2_tfrsi s16Ext:$dst)>;
+def PS_aligna : ALU32Inst<(outs IntRegs:$Rd), (ins u32_0Imm:$A), "", []>;
// XTYPE/SHIFT
//
@@ -5137,11 +4230,8 @@ let hasNewValue = 1, opNewValue = 0 in
class T_shift_imm_acc_r <string opc1, string opc2, SDNode OpNode1,
SDNode OpNode2, bits<3> majOp, bits<2> minOp>
: SInst_acc<(outs IntRegs:$Rx),
- (ins IntRegs:$src1, IntRegs:$Rs, u5Imm:$u5),
- "$Rx "#opc2#opc1#"($Rs, #$u5)",
- [(set (i32 IntRegs:$Rx),
- (OpNode2 (i32 IntRegs:$src1),
- (OpNode1 (i32 IntRegs:$Rs), u5ImmPred:$u5)))],
+ (ins IntRegs:$src1, IntRegs:$Rs, u5_0Imm:$u5),
+ "$Rx "#opc2#opc1#"($Rs, #$u5)", [],
"$src1 = $Rx", S_2op_tc_2_SLOT23> {
bits<5> Rx;
bits<5> Rs;
@@ -5168,10 +4258,7 @@ class T_shift_reg_acc_r <string opc1, string opc2, SDNode OpNode1,
SDNode OpNode2, bits<2> majOp, bits<2> minOp>
: SInst_acc<(outs IntRegs:$Rx),
(ins IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt),
- "$Rx "#opc2#opc1#"($Rs, $Rt)",
- [(set (i32 IntRegs:$Rx),
- (OpNode2 (i32 IntRegs:$src1),
- (OpNode1 (i32 IntRegs:$Rs), (i32 IntRegs:$Rt))))],
+ "$Rx "#opc2#opc1#"($Rs, $Rt)", [],
"$src1 = $Rx", S_3op_tc_2_SLOT23 > {
bits<5> Rx;
bits<5> Rs;
@@ -5194,11 +4281,8 @@ class T_shift_reg_acc_r <string opc1, string opc2, SDNode OpNode1,
class T_shift_imm_acc_p <string opc1, string opc2, SDNode OpNode1,
SDNode OpNode2, bits<3> majOp, bits<2> minOp>
: SInst_acc<(outs DoubleRegs:$Rxx),
- (ins DoubleRegs:$src1, DoubleRegs:$Rss, u6Imm:$u6),
- "$Rxx "#opc2#opc1#"($Rss, #$u6)",
- [(set (i64 DoubleRegs:$Rxx),
- (OpNode2 (i64 DoubleRegs:$src1),
- (OpNode1 (i64 DoubleRegs:$Rss), u6ImmPred:$u6)))],
+ (ins DoubleRegs:$src1, DoubleRegs:$Rss, u6_0Imm:$u6),
+ "$Rxx "#opc2#opc1#"($Rss, #$u6)", [],
"$src1 = $Rxx", S_2op_tc_2_SLOT23> {
bits<5> Rxx;
bits<5> Rss;
@@ -5225,10 +4309,7 @@ class T_shift_reg_acc_p <string opc1, string opc2, SDNode OpNode1,
SDNode OpNode2, bits<3> majOp, bits<2> minOp>
: SInst_acc<(outs DoubleRegs:$Rxx),
(ins DoubleRegs:$src1, DoubleRegs:$Rss, IntRegs:$Rt),
- "$Rxx "#opc2#opc1#"($Rss, $Rt)",
- [(set (i64 DoubleRegs:$Rxx),
- (OpNode2 (i64 DoubleRegs:$src1),
- (OpNode1 (i64 DoubleRegs:$Rss), (i32 IntRegs:$Rt))))],
+ "$Rxx "#opc2#opc1#"($Rss, $Rt)", [],
"$src1 = $Rxx", S_3op_tc_2_SLOT23> {
bits<5> Rxx;
bits<5> Rss;
@@ -5400,9 +4481,7 @@ class T_S3op_3 <string mnemonic, RegisterClass RC, bits<2> MajOp,
let hasNewValue = 1 in
class T_S3op_shift32 <string mnemonic, SDNode OpNode, bits<2> MinOp>
- : T_S3op_3 <mnemonic, IntRegs, 0b01, MinOp, 0,
- [(set (i32 IntRegs:$dst), (OpNode (i32 IntRegs:$src1),
- (i32 IntRegs:$src2)))]>;
+ : T_S3op_3 <mnemonic, IntRegs, 0b01, MinOp, 0, []>;
let hasNewValue = 1, Itinerary = S_3op_tc_2_SLOT23 in
class T_S3op_shift32_Sat <string mnemonic, bits<2> MinOp>
@@ -5410,9 +4489,7 @@ class T_S3op_shift32_Sat <string mnemonic, bits<2> MinOp>
class T_S3op_shift64 <string mnemonic, SDNode OpNode, bits<2> MinOp>
- : T_S3op_3 <mnemonic, DoubleRegs, 0b10, MinOp, 0,
- [(set (i64 DoubleRegs:$dst), (OpNode (i64 DoubleRegs:$src1),
- (i32 IntRegs:$src2)))]>;
+ : T_S3op_3 <mnemonic, DoubleRegs, 0b10, MinOp, 0, []>;
class T_S3op_shiftVect <string mnemonic, bits<2> MajOp, bits<2> MinOp>
@@ -5473,7 +4550,7 @@ def S2_vcrotate : T_S3op_shiftVect < "vcrotate", 0b11, 0b00>;
let hasSideEffects = 0 in
class T_S3op_7 <string mnemonic, bit MajOp >
: SInst <(outs DoubleRegs:$Rdd),
- (ins DoubleRegs:$Rss, DoubleRegs:$Rtt, u3Imm:$u3),
+ (ins DoubleRegs:$Rss, DoubleRegs:$Rtt, u3_0Imm:$u3),
"$Rdd = "#mnemonic#"($Rss, $Rtt, #$u3)" ,
[], "", S_3op_tc_1_SLOT23 > {
bits<5> Rdd;
@@ -5530,8 +4607,8 @@ class T_S2op_insert <bits<4> RegTyBits, RegisterClass RC, Operand ImmOp>
bit bit13;
string ImmOpStr = !cast<string>(ImmOp);
- let bit23 = !if (!eq(ImmOpStr, "u6Imm"), src3{5}, 0);
- let bit13 = !if (!eq(ImmOpStr, "u6Imm"), src2{5}, 0);
+ let bit23 = !if (!eq(ImmOpStr, "u6_0Imm"), src3{5}, 0);
+ let bit13 = !if (!eq(ImmOpStr, "u6_0Imm"), src2{5}, 0);
let IClass = 0b1000;
@@ -5549,42 +4626,13 @@ class T_S2op_insert <bits<4> RegTyBits, RegisterClass RC, Operand ImmOp>
// Rx=insert(Rs,#u5,#U5)
let hasNewValue = 1 in {
def S2_insert_rp : T_S3op_insert <"insert", IntRegs>;
- def S2_insert : T_S2op_insert <0b1111, IntRegs, u5Imm>;
+ def S2_insert : T_S2op_insert <0b1111, IntRegs, u5_0Imm>;
}
// Rxx=insert(Rss,Rtt)
// Rxx=insert(Rss,#u6,#U6)
def S2_insertp_rp : T_S3op_insert<"insert", DoubleRegs>;
-def S2_insertp : T_S2op_insert <0b0011, DoubleRegs, u6Imm>;
-
-
-def SDTHexagonINSERT:
- SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
- SDTCisInt<0>, SDTCisVT<3, i32>, SDTCisVT<4, i32>]>;
-def SDTHexagonINSERTRP:
- SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
- SDTCisInt<0>, SDTCisVT<3, i64>]>;
-
-def HexagonINSERT : SDNode<"HexagonISD::INSERT", SDTHexagonINSERT>;
-def HexagonINSERTRP : SDNode<"HexagonISD::INSERTRP", SDTHexagonINSERTRP>;
-
-def: Pat<(HexagonINSERT I32:$Rs, I32:$Rt, u5ImmPred:$u1, u5ImmPred:$u2),
- (S2_insert I32:$Rs, I32:$Rt, u5ImmPred:$u1, u5ImmPred:$u2)>;
-def: Pat<(HexagonINSERT I64:$Rs, I64:$Rt, u6ImmPred:$u1, u6ImmPred:$u2),
- (S2_insertp I64:$Rs, I64:$Rt, u6ImmPred:$u1, u6ImmPred:$u2)>;
-def: Pat<(HexagonINSERTRP I32:$Rs, I32:$Rt, I64:$Ru),
- (S2_insert_rp I32:$Rs, I32:$Rt, I64:$Ru)>;
-def: Pat<(HexagonINSERTRP I64:$Rs, I64:$Rt, I64:$Ru),
- (S2_insertp_rp I64:$Rs, I64:$Rt, I64:$Ru)>;
-
-let AddedComplexity = 100 in
-def: Pat<(or (or (shl (HexagonINSERT (i32 (zextloadi8 (add I32:$b, 2))),
- (i32 (extloadi8 (add I32:$b, 3))),
- 24, 8),
- (i32 16)),
- (shl (i32 (zextloadi8 (add I32:$b, 1))), (i32 8))),
- (zextloadi8 I32:$b)),
- (A2_swiz (L2_loadri_io I32:$b, 0))>;
+def S2_insertp : T_S2op_insert <0b0011, DoubleRegs, u6_0Imm>;
//===----------------------------------------------------------------------===//
@@ -5622,10 +4670,10 @@ class T_S2op_extract <string mnemonic, bits<4> RegTyBits,
bit bit13;
string ImmOpStr = !cast<string>(ImmOp);
- let bit23 = !if (!eq(ImmOpStr, "u6Imm"), src3{5},
+ let bit23 = !if (!eq(ImmOpStr, "u6_0Imm"), src3{5},
!if (!eq(mnemonic, "extractu"), 0, 1));
- let bit13 = !if (!eq(ImmOpStr, "u6Imm"), src2{5}, 0);
+ let bit13 = !if (!eq(ImmOpStr, "u6_0Imm"), src2{5}, 0);
let IClass = 0b1000;
@@ -5644,38 +4692,15 @@ class T_S2op_extract <string mnemonic, bits<4> RegTyBits,
// Rdd=extractu(Rss,Rtt)
// Rdd=extractu(Rss,#u6,#U6)
def S2_extractup_rp : T_S3op_64 < "extractu", 0b00, 0b000, 0>;
-def S2_extractup : T_S2op_extract <"extractu", 0b0001, DoubleRegs, u6Imm>;
+def S2_extractup : T_S2op_extract <"extractu", 0b0001, DoubleRegs, u6_0Imm>;
// Rd=extractu(Rs,Rtt)
// Rd=extractu(Rs,#u5,#U5)
let hasNewValue = 1 in {
def S2_extractu_rp : T_S3op_extract<"extractu", 0b00>;
- def S2_extractu : T_S2op_extract <"extractu", 0b1101, IntRegs, u5Imm>;
+ def S2_extractu : T_S2op_extract <"extractu", 0b1101, IntRegs, u5_0Imm>;
}
-def SDTHexagonEXTRACTU:
- SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisInt<1>,
- SDTCisVT<2, i32>, SDTCisVT<3, i32>]>;
-def SDTHexagonEXTRACTURP:
- SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisInt<1>,
- SDTCisVT<2, i64>]>;
-
-def HexagonEXTRACTU : SDNode<"HexagonISD::EXTRACTU", SDTHexagonEXTRACTU>;
-def HexagonEXTRACTURP : SDNode<"HexagonISD::EXTRACTURP", SDTHexagonEXTRACTURP>;
-
-def: Pat<(HexagonEXTRACTU I32:$src1, u5ImmPred:$src2, u5ImmPred:$src3),
- (S2_extractu I32:$src1, u5ImmPred:$src2, u5ImmPred:$src3)>;
-def: Pat<(HexagonEXTRACTU I64:$src1, u6ImmPred:$src2, u6ImmPred:$src3),
- (S2_extractup I64:$src1, u6ImmPred:$src2, u6ImmPred:$src3)>;
-def: Pat<(HexagonEXTRACTURP I32:$src1, I64:$src2),
- (S2_extractu_rp I32:$src1, I64:$src2)>;
-def: Pat<(HexagonEXTRACTURP I64:$src1, I64:$src2),
- (S2_extractup_rp I64:$src1, I64:$src2)>;
-
-// Change the sign of the immediate for Rd=-mpyi(Rs,#u8)
-def: Pat<(mul (i32 IntRegs:$src1), (ineg n8ImmPred:$src2)),
- (M2_mpysin IntRegs:$src1, u8ImmPred:$src2)>;
-
//===----------------------------------------------------------------------===//
// :raw for of tableindx[bdhw] insns
//===----------------------------------------------------------------------===//
@@ -5683,7 +4708,7 @@ def: Pat<(mul (i32 IntRegs:$src1), (ineg n8ImmPred:$src2)),
let hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
class tableidxRaw<string OpStr, bits<2>MinOp>
: SInst <(outs IntRegs:$Rx),
- (ins IntRegs:$_dst_, IntRegs:$Rs, u4Imm:$u4, s6Imm:$S6),
+ (ins IntRegs:$_dst_, IntRegs:$Rs, u4_0Imm:$u4, s6_0Imm:$S6),
"$Rx = "#OpStr#"($Rs, #$u4, #$S6):raw",
[], "$Rx = $_dst_" > {
bits<5> Rx;
@@ -5714,7 +4739,7 @@ def S2_tableidxd : tableidxRaw<"tableidxd", 0b11>;
let isPseudo = 1 in
class tableidx_goodsyntax <string mnemonic>
: SInst <(outs IntRegs:$Rx),
- (ins IntRegs:$_dst_, IntRegs:$Rs, u4Imm:$u4, u5Imm:$u5),
+ (ins IntRegs:$_dst_, IntRegs:$Rs, u4_0Imm:$u4, u5_0Imm:$u5),
"$Rx = "#mnemonic#"($Rs, #$u4, #$u5)",
[], "$Rx = $_dst_" >;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV3.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV3.td
index 9024a43..225f944 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV3.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV3.td
@@ -11,12 +11,6 @@
//
//===----------------------------------------------------------------------===//
-def callv3 : SDNode<"HexagonISD::CALLv3", SDT_SPCall,
- [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>;
-
-def callv3nr : SDNode<"HexagonISD::CALLv3nr", SDT_SPCall,
- [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>;
-
//===----------------------------------------------------------------------===//
// J +
//===----------------------------------------------------------------------===//
@@ -66,11 +60,13 @@ multiclass T_Calls<bit CSR, string ExtStr> {
defm J2_call: T_Calls<1, "">, PredRel;
-let isCodeGenOnly = 1, isCall = 1, hasSideEffects = 1, Defs = VolatileV3.Regs in
-def CALLv3nr : T_Call<1, "">, PredRel;
+let isCodeGenOnly = 1, isCall = 1, hasSideEffects = 1,
+ Defs = VolatileV3.Regs in
+def PS_call_nr : T_Call<1, "">, PredRel;
-let isCodeGenOnly = 1, isCall = 1, hasSideEffects = 1, Defs = [PC, R31, R6, R7, P0] in
-def CALLstk : T_Call<0, "">, PredRel;
+let isCodeGenOnly = 1, isCall = 1, hasSideEffects = 1,
+ Defs = [PC, R31, R6, R7, P0] in
+def PS_call_stk : T_Call<0, "">, PredRel;
//===----------------------------------------------------------------------===//
// J -
@@ -83,7 +79,7 @@ def CALLstk : T_Call<0, "">, PredRel;
// Call subroutine from register.
let isCodeGenOnly = 1, Defs = VolatileV3.Regs in {
- def CALLRv3nr : JUMPR_MISC_CALLR<0, 1>; // Call, no return.
+ def PS_callr_nr : JUMPR_MISC_CALLR<0, 1>; // Call, no return.
}
//===----------------------------------------------------------------------===//
@@ -105,9 +101,7 @@ def A2_addsph : T_ALU64_addsp_hl<":raw:hi", 0b111>;
let hasSideEffects = 0, isAsmParserOnly = 1 in
def A2_addsp : ALU64_rr<(outs DoubleRegs:$Rd),
- (ins IntRegs:$Rs, DoubleRegs:$Rt), "$Rd = add($Rs, $Rt)",
- [(set (i64 DoubleRegs:$Rd), (i64 (add (i64 (sext (i32 IntRegs:$Rs))),
- (i64 DoubleRegs:$Rt))))],
+ (ins IntRegs:$Rs, DoubleRegs:$Rt), "$Rd = add($Rs, $Rt)", [],
"", ALU64_tc_1_SLOT23>;
@@ -137,60 +131,10 @@ def A2_minup : T_XTYPE_MIN_MAX_P<0, 1>;
def A2_maxp : T_XTYPE_MIN_MAX_P<1, 0>;
def A2_maxup : T_XTYPE_MIN_MAX_P<1, 1>;
-multiclass MinMax_pats_p<PatFrag Op, InstHexagon Inst, InstHexagon SwapInst> {
- defm: T_MinMax_pats<Op, DoubleRegs, i64, Inst, SwapInst>;
-}
-
-let AddedComplexity = 200 in {
- defm: MinMax_pats_p<setge, A2_maxp, A2_minp>;
- defm: MinMax_pats_p<setgt, A2_maxp, A2_minp>;
- defm: MinMax_pats_p<setle, A2_minp, A2_maxp>;
- defm: MinMax_pats_p<setlt, A2_minp, A2_maxp>;
- defm: MinMax_pats_p<setuge, A2_maxup, A2_minup>;
- defm: MinMax_pats_p<setugt, A2_maxup, A2_minup>;
- defm: MinMax_pats_p<setule, A2_minup, A2_maxup>;
- defm: MinMax_pats_p<setult, A2_minup, A2_maxup>;
-}
-
//===----------------------------------------------------------------------===//
// ALU64/ALU -
//===----------------------------------------------------------------------===//
-
-
-
-//def : Pat <(brcond (i1 (seteq (i32 IntRegs:$src1), 0)), bb:$offset),
-// (JMP_RegEzt (i32 IntRegs:$src1), bb:$offset)>;
-
-//def : Pat <(brcond (i1 (setne (i32 IntRegs:$src1), 0)), bb:$offset),
-// (JMP_RegNzt (i32 IntRegs:$src1), bb:$offset)>;
-
-//def : Pat <(brcond (i1 (setle (i32 IntRegs:$src1), 0)), bb:$offset),
-// (JMP_RegLezt (i32 IntRegs:$src1), bb:$offset)>;
-
-//def : Pat <(brcond (i1 (setge (i32 IntRegs:$src1), 0)), bb:$offset),
-// (JMP_RegGezt (i32 IntRegs:$src1), bb:$offset)>;
-
-//def : Pat <(brcond (i1 (setgt (i32 IntRegs:$src1), -1)), bb:$offset),
-// (JMP_RegGezt (i32 IntRegs:$src1), bb:$offset)>;
-
-// Map call instruction
-def : Pat<(callv3 (i32 IntRegs:$dst)),
- (J2_callr (i32 IntRegs:$dst))>;
-def : Pat<(callv3 tglobaladdr:$dst),
- (J2_call tglobaladdr:$dst)>;
-def : Pat<(callv3 texternalsym:$dst),
- (J2_call texternalsym:$dst)>;
-def : Pat<(callv3 tglobaltlsaddr:$dst),
- (J2_call tglobaltlsaddr:$dst)>;
-
-def : Pat<(callv3nr (i32 IntRegs:$dst)),
- (CALLRv3nr (i32 IntRegs:$dst))>;
-def : Pat<(callv3nr tglobaladdr:$dst),
- (CALLv3nr tglobaladdr:$dst)>;
-def : Pat<(callv3nr texternalsym:$dst),
- (CALLv3nr texternalsym:$dst)>;
-
//===----------------------------------------------------------------------===//
// :raw form of vrcmpys:hi/lo insns
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV4.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV4.td
index 398d2d3..18943a0 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV4.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV4.td
@@ -30,9 +30,6 @@ def DuplexIClassD: InstDuplex < 0xD >;
def DuplexIClassE: InstDuplex < 0xE >;
def DuplexIClassF: InstDuplex < 0xF >;
-def addrga: PatLeaf<(i32 AddrGA:$Addr)>;
-def addrgp: PatLeaf<(i32 AddrGP:$Addr)>;
-
let hasSideEffects = 0 in
class T_Immext<Operand ImmType>
: EXTENDERInst<(outs), (ins ImmType:$imm),
@@ -53,14 +50,6 @@ let isCodeGenOnly = 1 in {
def A4_ext_g : T_Immext<globaladdress>;
}
-def BITPOS32 : SDNodeXForm<imm, [{
- // Return the bit position we will set [0-31].
- // As an SDNode.
- int32_t imm = N->getSExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-
// Hexagon V4 Architecture spec defines 8 instruction classes:
// LD ST ALU32 XTYPE J JR MEMOP NV CR SYSTEM(system is not implemented in the
// compiler)
@@ -145,22 +134,6 @@ def C4_cmpneq : T_ALU32_3op_cmp<"!cmp.eq", 0b00, 1, 1>;
def C4_cmplte : T_ALU32_3op_cmp<"!cmp.gt", 0b10, 1, 0>;
def C4_cmplteu : T_ALU32_3op_cmp<"!cmp.gtu", 0b11, 1, 0>;
-// Pats for instruction selection.
-
-// A class to embed the usual comparison patfrags within a zext to i32.
-// The seteq/setne frags use "lhs" and "rhs" as operands, so use the same
-// names, or else the frag's "body" won't match the operands.
-class CmpInReg<PatFrag Op>
- : PatFrag<(ops node:$lhs, node:$rhs),(i32 (zext (i1 Op.Fragment)))>;
-
-def: T_cmp32_rr_pat<A4_rcmpeq, CmpInReg<seteq>, i32>;
-def: T_cmp32_rr_pat<A4_rcmpneq, CmpInReg<setne>, i32>;
-
-def: T_cmp32_rr_pat<C4_cmpneq, setne, i1>;
-def: T_cmp32_rr_pat<C4_cmplteu, setule, i1>;
-
-def: T_cmp32_rr_pat<C4_cmplteu, RevCmp<setuge>, i1>;
-
class T_CMP_rrbh<string mnemonic, bits<3> MinOp, bit IsComm>
: SInst<(outs PredRegs:$Pd), (ins IntRegs:$Rs, IntRegs:$Rt),
"$Pd = "#mnemonic#"($Rs, $Rt)", [], "", S_3op_tc_2early_SLOT23>,
@@ -190,21 +163,6 @@ def A4_cmpheq : T_CMP_rrbh<"cmph.eq", 0b011, 1>;
def A4_cmphgt : T_CMP_rrbh<"cmph.gt", 0b100, 0>;
def A4_cmphgtu : T_CMP_rrbh<"cmph.gtu", 0b101, 0>;
-let AddedComplexity = 100 in {
- def: Pat<(i1 (seteq (and (xor (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)),
- 255), 0)),
- (A4_cmpbeq IntRegs:$Rs, IntRegs:$Rt)>;
- def: Pat<(i1 (setne (and (xor (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)),
- 255), 0)),
- (C2_not (A4_cmpbeq IntRegs:$Rs, IntRegs:$Rt))>;
- def: Pat<(i1 (seteq (and (xor (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)),
- 65535), 0)),
- (A4_cmpheq IntRegs:$Rs, IntRegs:$Rt)>;
- def: Pat<(i1 (setne (and (xor (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)),
- 65535), 0)),
- (C2_not (A4_cmpheq IntRegs:$Rs, IntRegs:$Rt))>;
-}
-
class T_CMP_ribh<string mnemonic, bits<2> MajOp, bit IsHalf, bit IsComm,
Operand ImmType, bit IsImmExt, bit IsImmSigned, int ImmBits>
: ALU64Inst<(outs PredRegs:$Pd), (ins IntRegs:$Rs, ImmType:$Imm),
@@ -234,15 +192,15 @@ class T_CMP_ribh<string mnemonic, bits<2> MajOp, bit IsHalf, bit IsComm,
let Inst{1-0} = Pd;
}
-def A4_cmpbeqi : T_CMP_ribh<"cmpb.eq", 0b00, 0, 1, u8Imm, 0, 0, 8>;
-def A4_cmpbgti : T_CMP_ribh<"cmpb.gt", 0b01, 0, 0, s8Imm, 0, 1, 8>;
-def A4_cmpbgtui : T_CMP_ribh<"cmpb.gtu", 0b10, 0, 0, u7Ext, 1, 0, 7>;
-def A4_cmpheqi : T_CMP_ribh<"cmph.eq", 0b00, 1, 1, s8Ext, 1, 1, 8>;
-def A4_cmphgti : T_CMP_ribh<"cmph.gt", 0b01, 1, 0, s8Ext, 1, 1, 8>;
-def A4_cmphgtui : T_CMP_ribh<"cmph.gtu", 0b10, 1, 0, u7Ext, 1, 0, 7>;
+def A4_cmpbeqi : T_CMP_ribh<"cmpb.eq", 0b00, 0, 1, u8_0Imm, 0, 0, 8>;
+def A4_cmpbgti : T_CMP_ribh<"cmpb.gt", 0b01, 0, 0, s8_0Imm, 0, 1, 8>;
+def A4_cmpbgtui : T_CMP_ribh<"cmpb.gtu", 0b10, 0, 0, u7_0Ext, 1, 0, 7>;
+def A4_cmpheqi : T_CMP_ribh<"cmph.eq", 0b00, 1, 1, s8_0Ext, 1, 1, 8>;
+def A4_cmphgti : T_CMP_ribh<"cmph.gt", 0b01, 1, 0, s8_0Ext, 1, 1, 8>;
+def A4_cmphgtui : T_CMP_ribh<"cmph.gtu", 0b10, 1, 0, u7_0Ext, 1, 0, 7>;
class T_RCMP_EQ_ri<string mnemonic, bit IsNeg>
- : ALU32_ri<(outs IntRegs:$Rd), (ins IntRegs:$Rs, s8Ext:$s8),
+ : ALU32_ri<(outs IntRegs:$Rd), (ins IntRegs:$Rs, s8_0Ext:$s8),
"$Rd = "#mnemonic#"($Rs, #$s8)", [], "", ALU32_2op_tc_1_SLOT0123>,
ImmRegRel {
let InputType = "imm";
@@ -270,16 +228,6 @@ class T_RCMP_EQ_ri<string mnemonic, bit IsNeg>
def A4_rcmpeqi : T_RCMP_EQ_ri<"cmp.eq", 0>;
def A4_rcmpneqi : T_RCMP_EQ_ri<"!cmp.eq", 1>;
-def: Pat<(i32 (zext (i1 (seteq (i32 IntRegs:$Rs), s32ImmPred:$s8)))),
- (A4_rcmpeqi IntRegs:$Rs, s32ImmPred:$s8)>;
-def: Pat<(i32 (zext (i1 (setne (i32 IntRegs:$Rs), s32ImmPred:$s8)))),
- (A4_rcmpneqi IntRegs:$Rs, s32ImmPred:$s8)>;
-
-// Preserve the S2_tstbit_r generation
-def: Pat<(i32 (zext (i1 (setne (i32 (and (i32 (shl 1, (i32 IntRegs:$src2))),
- (i32 IntRegs:$src1))), 0)))),
- (C2_muxii (S2_tstbit_r IntRegs:$src1, IntRegs:$src2), 1, 0)>;
-
//===----------------------------------------------------------------------===//
// ALU32 -
//===----------------------------------------------------------------------===//
@@ -308,26 +256,16 @@ class T_Combine1 <bits<2> MajOp, dag ins, string AsmStr>
}
let opExtendable = 2 in
-def A4_combineri : T_Combine1<0b00, (ins IntRegs:$Rs, s8Ext:$s8),
+def A4_combineri : T_Combine1<0b00, (ins IntRegs:$Rs, s8_0Ext:$s8),
"$Rdd = combine($Rs, #$s8)">;
let opExtendable = 1 in
-def A4_combineir : T_Combine1<0b01, (ins s8Ext:$s8, IntRegs:$Rs),
+def A4_combineir : T_Combine1<0b01, (ins s8_0Ext:$s8, IntRegs:$Rs),
"$Rdd = combine(#$s8, $Rs)">;
-// The complexity of the combines involving immediates should be greater
-// than the complexity of the combine with two registers.
-let AddedComplexity = 50 in {
-def: Pat<(HexagonCOMBINE IntRegs:$r, s32ImmPred:$i),
- (A4_combineri IntRegs:$r, s32ImmPred:$i)>;
-
-def: Pat<(HexagonCOMBINE s32ImmPred:$i, IntRegs:$r),
- (A4_combineir s32ImmPred:$i, IntRegs:$r)>;
-}
-
// A4_combineii: Set two small immediates.
let hasSideEffects = 0, isExtendable = 1, opExtentBits = 6, opExtendable = 2 in
-def A4_combineii: ALU32Inst<(outs DoubleRegs:$Rdd), (ins s8Imm:$s8, u6Ext:$U6),
+def A4_combineii: ALU32Inst<(outs DoubleRegs:$Rdd), (ins s8_0Imm:$s8, u6_0Ext:$U6),
"$Rdd = combine(#$s8, #$U6)"> {
bits<5> Rdd;
bits<8> s8;
@@ -341,12 +279,6 @@ def A4_combineii: ALU32Inst<(outs DoubleRegs:$Rdd), (ins s8Imm:$s8, u6Ext:$U6),
let Inst{4-0} = Rdd;
}
-// The complexity of the combine with two immediates should be greater than
-// the complexity of a combine involving a register.
-let AddedComplexity = 75 in
-def: Pat<(HexagonCOMBINE s8ImmPred:$s8, u32ImmPred:$u6),
- (A4_combineii imm:$s8, imm:$u6)>;
-
//===----------------------------------------------------------------------===//
// ALU32/PERM -
//===----------------------------------------------------------------------===//
@@ -355,39 +287,6 @@ def: Pat<(HexagonCOMBINE s8ImmPred:$s8, u32ImmPred:$u6),
// LD +
//===----------------------------------------------------------------------===//
-def Zext64: OutPatFrag<(ops node:$Rs),
- (i64 (A4_combineir 0, (i32 $Rs)))>;
-def Sext64: OutPatFrag<(ops node:$Rs),
- (i64 (A2_sxtw (i32 $Rs)))>;
-
-// Patterns to generate indexed loads with different forms of the address:
-// - frameindex,
-// - base + offset,
-// - base (without offset).
-multiclass Loadxm_pat<PatFrag Load, ValueType VT, PatFrag ValueMod,
- PatLeaf ImmPred, InstHexagon MI> {
- def: Pat<(VT (Load AddrFI:$fi)),
- (VT (ValueMod (MI AddrFI:$fi, 0)))>;
- def: Pat<(VT (Load (add AddrFI:$fi, ImmPred:$Off))),
- (VT (ValueMod (MI AddrFI:$fi, imm:$Off)))>;
- def: Pat<(VT (Load (add IntRegs:$Rs, ImmPred:$Off))),
- (VT (ValueMod (MI IntRegs:$Rs, imm:$Off)))>;
- def: Pat<(VT (Load (i32 IntRegs:$Rs))),
- (VT (ValueMod (MI IntRegs:$Rs, 0)))>;
-}
-
-defm: Loadxm_pat<extloadi1, i64, Zext64, s32_0ImmPred, L2_loadrub_io>;
-defm: Loadxm_pat<extloadi8, i64, Zext64, s32_0ImmPred, L2_loadrub_io>;
-defm: Loadxm_pat<extloadi16, i64, Zext64, s31_1ImmPred, L2_loadruh_io>;
-defm: Loadxm_pat<zextloadi1, i64, Zext64, s32_0ImmPred, L2_loadrub_io>;
-defm: Loadxm_pat<zextloadi8, i64, Zext64, s32_0ImmPred, L2_loadrub_io>;
-defm: Loadxm_pat<zextloadi16, i64, Zext64, s31_1ImmPred, L2_loadruh_io>;
-defm: Loadxm_pat<sextloadi8, i64, Sext64, s32_0ImmPred, L2_loadrb_io>;
-defm: Loadxm_pat<sextloadi16, i64, Sext64, s31_1ImmPred, L2_loadrh_io>;
-
-// Map Rdd = anyext(Rs) -> Rdd = combine(#0, Rs).
-def: Pat<(i64 (anyext (i32 IntRegs:$src1))), (Zext64 IntRegs:$src1)>;
-
//===----------------------------------------------------------------------===//
// Template class for load instructions with Absolute set addressing mode.
//===----------------------------------------------------------------------===//
@@ -395,7 +294,7 @@ let isExtended = 1, opExtendable = 2, opExtentBits = 6, addrMode = AbsoluteSet,
hasSideEffects = 0 in
class T_LD_abs_set<string mnemonic, RegisterClass RC, bits<4>MajOp>:
LDInst<(outs RC:$dst1, IntRegs:$dst2),
- (ins u6Ext:$addr),
+ (ins u6_0Ext:$addr),
"$dst1 = "#mnemonic#"($dst2 = #$addr)",
[]> {
bits<7> name;
@@ -447,7 +346,7 @@ let InputType = "imm", addrMode = BaseLongOffset, isExtended = 1,
opExtentBits = 6, opExtendable = 3 in
class T_LoadAbsReg <string mnemonic, string CextOp, RegisterClass RC,
bits<4> MajOp>
- : LDInst <(outs RC:$dst), (ins IntRegs:$src1, u2Imm:$src2, u6Ext:$src3),
+ : LDInst <(outs RC:$dst), (ins IntRegs:$src1, u2_0Imm:$src2, u6_0Ext:$src3),
"$dst = "#mnemonic#"($src1<<#$src2 + #$src3)",
[] >, ImmRegShl {
bits<5> dst;
@@ -495,48 +394,12 @@ let accessSize = DoubleWordAccess in
def L4_loadrd_ur : T_LoadAbsReg<"memd", "LDrid", DoubleRegs, 0b1110>;
-multiclass T_LoadAbsReg_Pat <PatFrag ldOp, InstHexagon MI, ValueType VT = i32> {
- def : Pat <(VT (ldOp (add (shl IntRegs:$src1, u2ImmPred:$src2),
- (HexagonCONST32 tglobaladdr:$src3)))),
- (MI IntRegs:$src1, u2ImmPred:$src2, tglobaladdr:$src3)>;
- def : Pat <(VT (ldOp (add IntRegs:$src1,
- (HexagonCONST32 tglobaladdr:$src2)))),
- (MI IntRegs:$src1, 0, tglobaladdr:$src2)>;
-
- def : Pat <(VT (ldOp (add (shl IntRegs:$src1, u2ImmPred:$src2),
- (HexagonCONST32 tconstpool:$src3)))),
- (MI IntRegs:$src1, u2ImmPred:$src2, tconstpool:$src3)>;
- def : Pat <(VT (ldOp (add IntRegs:$src1,
- (HexagonCONST32 tconstpool:$src2)))),
- (MI IntRegs:$src1, 0, tconstpool:$src2)>;
-
- def : Pat <(VT (ldOp (add (shl IntRegs:$src1, u2ImmPred:$src2),
- (HexagonCONST32 tjumptable:$src3)))),
- (MI IntRegs:$src1, u2ImmPred:$src2, tjumptable:$src3)>;
- def : Pat <(VT (ldOp (add IntRegs:$src1,
- (HexagonCONST32 tjumptable:$src2)))),
- (MI IntRegs:$src1, 0, tjumptable:$src2)>;
-}
-
-let AddedComplexity = 60 in {
-defm : T_LoadAbsReg_Pat <sextloadi8, L4_loadrb_ur>;
-defm : T_LoadAbsReg_Pat <zextloadi8, L4_loadrub_ur>;
-defm : T_LoadAbsReg_Pat <extloadi8, L4_loadrub_ur>;
-
-defm : T_LoadAbsReg_Pat <sextloadi16, L4_loadrh_ur>;
-defm : T_LoadAbsReg_Pat <zextloadi16, L4_loadruh_ur>;
-defm : T_LoadAbsReg_Pat <extloadi16, L4_loadruh_ur>;
-
-defm : T_LoadAbsReg_Pat <load, L4_loadri_ur>;
-defm : T_LoadAbsReg_Pat <load, L4_loadrd_ur, i64>;
-}
-
//===----------------------------------------------------------------------===//
// Template classes for the non-predicated load instructions with
// base + register offset addressing mode
//===----------------------------------------------------------------------===//
class T_load_rr <string mnemonic, RegisterClass RC, bits<3> MajOp>:
- LDInst<(outs RC:$dst), (ins IntRegs:$src1, IntRegs:$src2, u2Imm:$u2),
+ LDInst<(outs RC:$dst), (ins IntRegs:$src1, IntRegs:$src2, u2_0Imm:$u2),
"$dst = "#mnemonic#"($src1 + $src2<<#$u2)",
[], "", V4LDST_tc_ld_SLOT01>, ImmRegShl, AddrModeRel {
bits<5> dst;
@@ -563,7 +426,7 @@ let isPredicated = 1 in
class T_pload_rr <string mnemonic, RegisterClass RC, bits<3> MajOp,
bit isNot, bit isPredNew>:
LDInst <(outs RC:$dst),
- (ins PredRegs:$src1, IntRegs:$src2, IntRegs:$src3, u2Imm:$u2),
+ (ins PredRegs:$src1, IntRegs:$src2, IntRegs:$src3, u2_0Imm:$u2),
!if(isNot, "if (!$src1", "if ($src1")#!if(isPredNew, ".new) ",
") ")#"$dst = "#mnemonic#"($src2+$src3<<#$u2)",
[], "", V4LDST_tc_ld_SLOT01>, AddrModeRel {
@@ -628,50 +491,6 @@ defm loadri : ld_idxd_shl<"memw", "LDriw", IntRegs, 0b100>;
let accessSize = DoubleWordAccess in
defm loadrd : ld_idxd_shl<"memd", "LDrid", DoubleRegs, 0b110>;
-// 'def pats' for load instructions with base + register offset and non-zero
-// immediate value. Immediate value is used to left-shift the second
-// register operand.
-class Loadxs_pat<PatFrag Load, ValueType VT, InstHexagon MI>
- : Pat<(VT (Load (add (i32 IntRegs:$Rs),
- (i32 (shl (i32 IntRegs:$Rt), u2ImmPred:$u2))))),
- (VT (MI IntRegs:$Rs, IntRegs:$Rt, imm:$u2))>;
-
-let AddedComplexity = 40 in {
- def: Loadxs_pat<extloadi8, i32, L4_loadrub_rr>;
- def: Loadxs_pat<zextloadi8, i32, L4_loadrub_rr>;
- def: Loadxs_pat<sextloadi8, i32, L4_loadrb_rr>;
- def: Loadxs_pat<extloadi16, i32, L4_loadruh_rr>;
- def: Loadxs_pat<zextloadi16, i32, L4_loadruh_rr>;
- def: Loadxs_pat<sextloadi16, i32, L4_loadrh_rr>;
- def: Loadxs_pat<load, i32, L4_loadri_rr>;
- def: Loadxs_pat<load, i64, L4_loadrd_rr>;
-}
-
-// 'def pats' for load instruction base + register offset and
-// zero immediate value.
-class Loadxs_simple_pat<PatFrag Load, ValueType VT, InstHexagon MI>
- : Pat<(VT (Load (add (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)))),
- (VT (MI IntRegs:$Rs, IntRegs:$Rt, 0))>;
-
-let AddedComplexity = 20 in {
- def: Loadxs_simple_pat<extloadi8, i32, L4_loadrub_rr>;
- def: Loadxs_simple_pat<zextloadi8, i32, L4_loadrub_rr>;
- def: Loadxs_simple_pat<sextloadi8, i32, L4_loadrb_rr>;
- def: Loadxs_simple_pat<extloadi16, i32, L4_loadruh_rr>;
- def: Loadxs_simple_pat<zextloadi16, i32, L4_loadruh_rr>;
- def: Loadxs_simple_pat<sextloadi16, i32, L4_loadrh_rr>;
- def: Loadxs_simple_pat<load, i32, L4_loadri_rr>;
- def: Loadxs_simple_pat<load, i64, L4_loadrd_rr>;
-}
-
-// zext i1->i64
-def: Pat<(i64 (zext (i1 PredRegs:$src1))),
- (Zext64 (C2_muxii PredRegs:$src1, 1, 0))>;
-
-// zext i32->i64
-def: Pat<(i64 (zext (i32 IntRegs:$src1))),
- (Zext64 IntRegs:$src1)>;
-
//===----------------------------------------------------------------------===//
// LD -
//===----------------------------------------------------------------------===//
@@ -688,7 +507,7 @@ let isExtended = 1, opExtendable = 1, opExtentBits = 6,
class T_ST_absset <string mnemonic, string BaseOp, RegisterClass RC,
bits<3> MajOp, MemAccessSize AccessSz, bit isHalf = 0>
: STInst<(outs IntRegs:$dst),
- (ins u6Ext:$addr, RC:$src),
+ (ins u6_0Ext:$addr, RC:$src),
mnemonic#"($dst = #$addr) = $src"#!if(isHalf, ".h","")>, NewValueRel {
bits<5> dst;
bits<6> addr;
@@ -727,7 +546,7 @@ isExtended = 1, opExtentBits= 6 in
class T_ST_absset_nv <string mnemonic, string BaseOp, bits<2> MajOp,
MemAccessSize AccessSz >
: NVInst <(outs IntRegs:$dst),
- (ins u6Ext:$addr, IntRegs:$src),
+ (ins u6_0Ext:$addr, IntRegs:$src),
mnemonic#"($dst = #$addr) = $src.new">, NewValueRel {
bits<5> dst;
bits<6> addr;
@@ -757,7 +576,7 @@ let isExtended = 1, opExtendable = 2, opExtentBits = 6, InputType = "imm",
class T_StoreAbsReg <string mnemonic, string CextOp, RegisterClass RC,
bits<3> MajOp, MemAccessSize AccessSz, bit isHalf = 0>
: STInst<(outs),
- (ins IntRegs:$src1, u2Imm:$src2, u6Ext:$src3, RC:$src4),
+ (ins IntRegs:$src1, u2_0Imm:$src2, u6_0Ext:$src3, RC:$src4),
mnemonic#"($src1<<#$src2 + #$src3) = $src4"#!if(isHalf, ".h",""),
[]>, ImmRegShl, NewValueRel {
@@ -794,35 +613,12 @@ def S4_storeri_ur : T_StoreAbsReg <"memw", "STriw", IntRegs, 0b100, WordAccess>;
def S4_storerd_ur : T_StoreAbsReg <"memd", "STrid", DoubleRegs, 0b110,
DoubleWordAccess>;
-let AddedComplexity = 40 in
-multiclass T_StoreAbsReg_Pats <InstHexagon MI, RegisterClass RC, ValueType VT,
- PatFrag stOp> {
- def : Pat<(stOp (VT RC:$src4),
- (add (shl (i32 IntRegs:$src1), u2ImmPred:$src2),
- u32ImmPred:$src3)),
- (MI IntRegs:$src1, u2ImmPred:$src2, u32ImmPred:$src3, RC:$src4)>;
-
- def : Pat<(stOp (VT RC:$src4),
- (add (shl IntRegs:$src1, u2ImmPred:$src2),
- (HexagonCONST32 tglobaladdr:$src3))),
- (MI IntRegs:$src1, u2ImmPred:$src2, tglobaladdr:$src3, RC:$src4)>;
-
- def : Pat<(stOp (VT RC:$src4),
- (add IntRegs:$src1, (HexagonCONST32 tglobaladdr:$src3))),
- (MI IntRegs:$src1, 0, tglobaladdr:$src3, RC:$src4)>;
-}
-
-defm : T_StoreAbsReg_Pats <S4_storerd_ur, DoubleRegs, i64, store>;
-defm : T_StoreAbsReg_Pats <S4_storeri_ur, IntRegs, i32, store>;
-defm : T_StoreAbsReg_Pats <S4_storerb_ur, IntRegs, i32, truncstorei8>;
-defm : T_StoreAbsReg_Pats <S4_storerh_ur, IntRegs, i32, truncstorei16>;
-
let mayStore = 1, isNVStore = 1, isExtended = 1, addrMode = BaseLongOffset,
opExtentBits = 6, isNewValue = 1, opNewValue = 3, opExtendable = 2 in
class T_StoreAbsRegNV <string mnemonic, string CextOp, bits<2> MajOp,
MemAccessSize AccessSz>
: NVInst <(outs ),
- (ins IntRegs:$src1, u2Imm:$src2, u6Ext:$src3, IntRegs:$src4),
+ (ins IntRegs:$src1, u2_0Imm:$src2, u6_0Ext:$src3, IntRegs:$src4),
mnemonic#"($src1<<#$src2 + #$src3) = $src4.new">, NewValueRel {
bits<5> src1;
bits<2> src2;
@@ -854,7 +650,7 @@ def S4_storerinew_ur : T_StoreAbsRegNV <"memw", "STriw", 0b10, WordAccess>;
//===----------------------------------------------------------------------===//
let isPredicable = 1 in
class T_store_rr <string mnemonic, RegisterClass RC, bits<3> MajOp, bit isH>
- : STInst < (outs ), (ins IntRegs:$Rs, IntRegs:$Ru, u2Imm:$u2, RC:$Rt),
+ : STInst < (outs ), (ins IntRegs:$Rs, IntRegs:$Ru, u2_0Imm:$u2, RC:$Rt),
mnemonic#"($Rs + $Ru<<#$u2) = $Rt"#!if(isH, ".h",""),
[],"",V4LDST_tc_st_SLOT01>, ImmRegShl, AddrModeRel {
@@ -885,7 +681,7 @@ let isPredicated = 1 in
class T_pstore_rr <string mnemonic, RegisterClass RC, bits<3> MajOp,
bit isNot, bit isPredNew, bit isH>
: STInst <(outs),
- (ins PredRegs:$Pv, IntRegs:$Rs, IntRegs:$Ru, u2Imm:$u2, RC:$Rt),
+ (ins PredRegs:$Pv, IntRegs:$Rs, IntRegs:$Ru, u2_0Imm:$u2, RC:$Rt),
!if(isNot, "if (!$Pv", "if ($Pv")#!if(isPredNew, ".new) ",
") ")#mnemonic#"($Rs+$Ru<<#$u2) = $Rt"#!if(isH, ".h",""),
@@ -921,7 +717,7 @@ class T_pstore_rr <string mnemonic, RegisterClass RC, bits<3> MajOp,
//===----------------------------------------------------------------------===//
let isPredicable = 1, isNewValue = 1, opNewValue = 3 in
class T_store_new_rr <string mnemonic, bits<2> MajOp> :
- NVInst < (outs ), (ins IntRegs:$Rs, IntRegs:$Ru, u2Imm:$u2, IntRegs:$Nt),
+ NVInst < (outs ), (ins IntRegs:$Rs, IntRegs:$Ru, u2_0Imm:$u2, IntRegs:$Nt),
mnemonic#"($Rs + $Ru<<#$u2) = $Nt.new",
[],"",V4LDST_tc_st_SLOT0>, ImmRegShl, AddrModeRel {
@@ -948,7 +744,7 @@ class T_store_new_rr <string mnemonic, bits<2> MajOp> :
let isPredicated = 1, isNewValue = 1, opNewValue = 4 in
class T_pstore_new_rr <string mnemonic, bits<2> MajOp, bit isNot, bit isPredNew>
: NVInst<(outs),
- (ins PredRegs:$Pv, IntRegs:$Rs, IntRegs:$Ru, u2Imm:$u2, IntRegs:$Nt),
+ (ins PredRegs:$Pv, IntRegs:$Rs, IntRegs:$Ru, u2_0Imm:$u2, IntRegs:$Nt),
!if(isNot, "if (!$Pv", "if ($Pv")#!if(isPredNew, ".new) ",
") ")#mnemonic#"($Rs+$Ru<<#$u2) = $Nt.new",
[], "", V4LDST_tc_st_SLOT0>, AddrModeRel {
@@ -1035,48 +831,13 @@ let addrMode = BaseRegOffset, InputType = "reg", hasSideEffects = 0 in {
defm storerf: ST_Idxd_shl<"memh", "STrif", IntRegs, 0b011, 1>;
}
-class Storexs_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
- : Pat<(Store Value:$Ru, (add (i32 IntRegs:$Rs),
- (i32 (shl (i32 IntRegs:$Rt), u2ImmPred:$u2)))),
- (MI IntRegs:$Rs, IntRegs:$Rt, imm:$u2, Value:$Ru)>;
-
-let AddedComplexity = 40 in {
- def: Storexs_pat<truncstorei8, I32, S4_storerb_rr>;
- def: Storexs_pat<truncstorei16, I32, S4_storerh_rr>;
- def: Storexs_pat<store, I32, S4_storeri_rr>;
- def: Storexs_pat<store, I64, S4_storerd_rr>;
-}
-
-class Store_rr_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
- : Pat<(Store Value:$Ru, (add I32:$Rs, I32:$Rt)),
- (MI IntRegs:$Rs, IntRegs:$Rt, 0, Value:$Ru)>;
-
-let AddedComplexity = 20 in {
- def: Store_rr_pat<truncstorei8, I32, S4_storerb_rr>;
- def: Store_rr_pat<truncstorei16, I32, S4_storerh_rr>;
- def: Store_rr_pat<store, I32, S4_storeri_rr>;
- def: Store_rr_pat<store, I64, S4_storerd_rr>;
-}
-
-
-// memd(Rx++#s4:3)=Rtt
-// memd(Rx++#s4:3:circ(Mu))=Rtt
-// memd(Rx++I:circ(Mu))=Rtt
-// memd(Rx++Mu)=Rtt
-// memd(Rx++Mu:brev)=Rtt
-// memd(gp+#u16:3)=Rtt
-
-// Store doubleword conditionally.
-// if ([!]Pv[.new]) memd(#u6)=Rtt
-// TODO: needs to be implemented.
-
//===----------------------------------------------------------------------===//
// Template class
//===----------------------------------------------------------------------===//
let isPredicable = 1, isExtendable = 1, isExtentSigned = 1, opExtentBits = 8,
opExtendable = 2 in
class T_StoreImm <string mnemonic, Operand OffsetOp, bits<2> MajOp >
- : STInst <(outs ), (ins IntRegs:$Rs, OffsetOp:$offset, s8Ext:$S8),
+ : STInst <(outs ), (ins IntRegs:$Rs, OffsetOp:$offset, s8_0Ext:$S8),
mnemonic#"($Rs+#$offset)=#$S8",
[], "", V4LDST_tc_st_SLOT01>,
ImmRegRel, PredNewRel {
@@ -1105,7 +866,7 @@ let isPredicated = 1, isExtendable = 1, isExtentSigned = 1, opExtentBits = 6,
class T_StoreImm_pred <string mnemonic, Operand OffsetOp, bits<2> MajOp,
bit isPredNot, bit isPredNew >
: STInst <(outs ),
- (ins PredRegs:$Pv, IntRegs:$Rs, OffsetOp:$offset, s6Ext:$S6),
+ (ins PredRegs:$Pv, IntRegs:$Rs, OffsetOp:$offset, s6_0Ext:$S6),
!if(isPredNot, "if (!$Pv", "if ($Pv")#!if(isPredNew, ".new) ",
") ")#mnemonic#"($Rs+#$offset)=#$S6",
[], "", V4LDST_tc_st_SLOT01>,
@@ -1173,126 +934,6 @@ let hasSideEffects = 0, addrMode = BaseImmOffset,
defm S4_storeiri : ST_Imm<"memw", "STriw", u6_2Imm, 0b10>;
}
-def IMM_BYTE : SDNodeXForm<imm, [{
- // -1 etc is represented as 255 etc
- // assigning to a byte restores our desired signed value.
- int8_t imm = N->getSExtValue();
- return CurDAG->getTargetConstant(imm, SDLoc(N), MVT::i32);
-}]>;
-
-def IMM_HALF : SDNodeXForm<imm, [{
- // -1 etc is represented as 65535 etc
- // assigning to a short restores our desired signed value.
- int16_t imm = N->getSExtValue();
- return CurDAG->getTargetConstant(imm, SDLoc(N), MVT::i32);
-}]>;
-
-def IMM_WORD : SDNodeXForm<imm, [{
- // -1 etc can be represented as 4294967295 etc
- // Currently, it's not doing this. But some optimization
- // might convert -1 to a large +ve number.
- // assigning to a word restores our desired signed value.
- int32_t imm = N->getSExtValue();
- return CurDAG->getTargetConstant(imm, SDLoc(N), MVT::i32);
-}]>;
-
-def ToImmByte : OutPatFrag<(ops node:$R), (IMM_BYTE $R)>;
-def ToImmHalf : OutPatFrag<(ops node:$R), (IMM_HALF $R)>;
-def ToImmWord : OutPatFrag<(ops node:$R), (IMM_WORD $R)>;
-
-// Emit store-immediate, but only when the stored value will not be constant-
-// extended. The reason for that is that there is no pass that can optimize
-// constant extenders in store-immediate instructions. In some cases we can
-// end up will a number of such stores, all of which store the same extended
-// value (e.g. after unrolling a loop that initializes floating point array).
-
-// Predicates to determine if the 16-bit immediate is expressible as a sign-
-// extended 8-bit immediate. Store-immediate-halfword will ignore any bits
-// beyond 0..15, so we don't care what is in there.
-
-def i16in8ImmPred: PatLeaf<(i32 imm), [{
- int64_t v = (int16_t)N->getSExtValue();
- return v == (int64_t)(int8_t)v;
-}]>;
-
-// Predicates to determine if the 32-bit immediate is expressible as a sign-
-// extended 8-bit immediate.
-def i32in8ImmPred: PatLeaf<(i32 imm), [{
- int64_t v = (int32_t)N->getSExtValue();
- return v == (int64_t)(int8_t)v;
-}]>;
-
-
-let AddedComplexity = 40 in {
- // Even though the offset is not extendable in the store-immediate, we
- // can still generate the fi# in the base address. If the final offset
- // is not valid for the instruction, we will replace it with a scratch
- // register.
-// def: Storexm_fi_pat <truncstorei8, s32ImmPred, ToImmByte, S4_storeirb_io>;
-// def: Storexm_fi_pat <truncstorei16, i16in8ImmPred, ToImmHalf,
-// S4_storeirh_io>;
-// def: Storexm_fi_pat <store, i32in8ImmPred, ToImmWord, S4_storeiri_io>;
-
-// defm: Storexm_fi_add_pat <truncstorei8, s32ImmPred, u6_0ImmPred, ToImmByte,
-// S4_storeirb_io>;
-// defm: Storexm_fi_add_pat <truncstorei16, i16in8ImmPred, u6_1ImmPred,
-// ToImmHalf, S4_storeirh_io>;
-// defm: Storexm_fi_add_pat <store, i32in8ImmPred, u6_2ImmPred, ToImmWord,
-// S4_storeiri_io>;
-
- defm: Storexm_add_pat<truncstorei8, s32ImmPred, u6_0ImmPred, ToImmByte,
- S4_storeirb_io>;
- defm: Storexm_add_pat<truncstorei16, i16in8ImmPred, u6_1ImmPred, ToImmHalf,
- S4_storeirh_io>;
- defm: Storexm_add_pat<store, i32in8ImmPred, u6_2ImmPred, ToImmWord,
- S4_storeiri_io>;
-}
-
-def: Storexm_simple_pat<truncstorei8, s32ImmPred, ToImmByte, S4_storeirb_io>;
-def: Storexm_simple_pat<truncstorei16, s32ImmPred, ToImmHalf, S4_storeirh_io>;
-def: Storexm_simple_pat<store, s32ImmPred, ToImmWord, S4_storeiri_io>;
-
-// memb(Rx++#s4:0:circ(Mu))=Rt
-// memb(Rx++I:circ(Mu))=Rt
-// memb(Rx++Mu)=Rt
-// memb(Rx++Mu:brev)=Rt
-// memb(gp+#u16:0)=Rt
-
-// Store halfword.
-// TODO: needs to be implemented
-// memh(Re=#U6)=Rt.H
-// memh(Rs+#s11:1)=Rt.H
-// memh(Rs+Ru<<#u2)=Rt.H
-// TODO: needs to be implemented.
-
-// memh(Ru<<#u2+#U6)=Rt.H
-// memh(Rx++#s4:1:circ(Mu))=Rt.H
-// memh(Rx++#s4:1:circ(Mu))=Rt
-// memh(Rx++I:circ(Mu))=Rt.H
-// memh(Rx++I:circ(Mu))=Rt
-// memh(Rx++Mu)=Rt.H
-// memh(Rx++Mu)=Rt
-// memh(Rx++Mu:brev)=Rt.H
-// memh(Rx++Mu:brev)=Rt
-// memh(gp+#u16:1)=Rt
-// if ([!]Pv[.new]) memh(#u6)=Rt.H
-// if ([!]Pv[.new]) memh(#u6)=Rt
-
-// if ([!]Pv[.new]) memh(Rs+#u6:1)=Rt.H
-// TODO: needs to be implemented.
-
-// if ([!]Pv[.new]) memh(Rx++#s4:1)=Rt.H
-// TODO: Needs to be implemented.
-
-// Store word.
-// memw(Re=#U6)=Rt
-// TODO: Needs to be implemented.
-// memw(Rx++#s4:2)=Rt
-// memw(Rx++#s4:2:circ(Mu))=Rt
-// memw(Rx++I:circ(Mu))=Rt
-// memw(Rx++Mu)=Rt
-// memw(Rx++Mu:brev)=Rt
-
//===----------------------------------------------------------------------===
// ST -
//===----------------------------------------------------------------------===
@@ -1685,7 +1326,7 @@ let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 11,
class NVJri_template<string mnemonic, bits<3> majOp, bit isNegCond,
bit isTak>
: NVInst_V4<(outs),
- (ins IntRegs:$src1, u5Imm:$src2, brtarget:$offset),
+ (ins IntRegs:$src1, u5_0Imm:$src2, brtarget:$offset),
"if ("#!if(isNegCond, "!","")#mnemonic#"($src1.new, #$src2)) jump:"
#!if(isTak, "t","nt")#" $offset", []> {
@@ -1738,19 +1379,22 @@ let isPredicated = 1, isBranch = 1, isNewValue = 1, isTerminator = 1,
// with a register and an hardcoded 0/-1 immediate value.
//===----------------------------------------------------------------------===//
-let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 11,
+let isExtendable = 1, isExtentSigned = 1, opExtentBits = 11,
opExtentAlign = 2 in
class NVJ_ConstImm_template<string mnemonic, bits<3> majOp, string ImmVal,
bit isNegCond, bit isTak>
: NVInst_V4<(outs),
- (ins IntRegs:$src1, brtarget:$offset),
+ !if(!eq(ImmVal, "{-1}"),
+ (ins IntRegs:$src1, n1Const:$n1, brtarget:$offset),
+ (ins IntRegs:$src1, brtarget:$offset)),
"if ("#!if(isNegCond, "!","")#mnemonic
- #"($src1.new, #" # ImmVal # ")) jump:"
+ #"($src1.new, #" # !if(!eq(ImmVal, "{-1}"), "$n1", ImmVal) # ")) jump:"
#!if(isTak, "t","nt")#" $offset", []> {
let isTaken = isTak;
let isPredicatedFalse = isNegCond;
let isTaken = isTak;
+ let opExtendable = !if(!eq(ImmVal, "{-1}"), 2, 1);
bits<3> src1;
bits<11> offset;
@@ -1787,8 +1431,8 @@ multiclass NVJ_ConstImm_base<string mnemonic, string BaseOp, bits<3> majOp,
let isPredicated = 1, isBranch = 1, isNewValue = 1, isTerminator=1,
Defs = [PC], hasSideEffects = 0 in {
defm J4_tstbit0 : NVJ_ConstImm_base<"tstbit", "TSTBIT", 0b011, "0">, PredRel;
- defm J4_cmpeqn1 : NVJ_ConstImm_base<"cmp.eq", "CMPEQ", 0b100, "-1">, PredRel;
- defm J4_cmpgtn1 : NVJ_ConstImm_base<"cmp.gt", "CMPGT", 0b101, "-1">, PredRel;
+ defm J4_cmpeqn1 : NVJ_ConstImm_base<"cmp.eq", "CMPEQ", 0b100, "{-1}">, PredRel;
+ defm J4_cmpgtn1 : NVJ_ConstImm_base<"cmp.gt", "CMPGT", 0b101, "{-1}">, PredRel;
}
// J4_hintjumpr: Hint indirect conditional jump.
@@ -1814,7 +1458,7 @@ def J4_hintjumpr: JRInst <
// PC-relative add
let hasNewValue = 1, isExtendable = 1, opExtendable = 1,
isExtentSigned = 0, opExtentBits = 6, hasSideEffects = 0, Uses = [PC] in
-def C4_addipc : CRInst <(outs IntRegs:$Rd), (ins u6Ext:$u6),
+def C4_addipc : CRInst <(outs IntRegs:$Rd), (ins u6_0Ext:$u6),
"$Rd = add(pc, #$u6)", [], "", CR_tc_2_SLOT3 > {
bits<5> Rd;
bits<6> u6;
@@ -1860,48 +1504,6 @@ def C4_and_orn : T_LOGICAL_3OP<"and", "or", 0b01, 1>;
def C4_or_andn : T_LOGICAL_3OP<"or", "and", 0b10, 1>;
def C4_or_orn : T_LOGICAL_3OP<"or", "or", 0b11, 1>;
-// op(Ps, op(Pt, Pu))
-class LogLog_pat<SDNode Op1, SDNode Op2, InstHexagon MI>
- : Pat<(i1 (Op1 I1:$Ps, (Op2 I1:$Pt, I1:$Pu))),
- (MI I1:$Ps, I1:$Pt, I1:$Pu)>;
-
-// op(Ps, op(Pt, ~Pu))
-class LogLogNot_pat<SDNode Op1, SDNode Op2, InstHexagon MI>
- : Pat<(i1 (Op1 I1:$Ps, (Op2 I1:$Pt, (not I1:$Pu)))),
- (MI I1:$Ps, I1:$Pt, I1:$Pu)>;
-
-def: LogLog_pat<and, and, C4_and_and>;
-def: LogLog_pat<and, or, C4_and_or>;
-def: LogLog_pat<or, and, C4_or_and>;
-def: LogLog_pat<or, or, C4_or_or>;
-
-def: LogLogNot_pat<and, and, C4_and_andn>;
-def: LogLogNot_pat<and, or, C4_and_orn>;
-def: LogLogNot_pat<or, and, C4_or_andn>;
-def: LogLogNot_pat<or, or, C4_or_orn>;
-
-//===----------------------------------------------------------------------===//
-// PIC: Support for PIC compilations. The patterns and SD nodes defined
-// below are needed to support code generation for PIC
-//===----------------------------------------------------------------------===//
-
-def SDT_HexagonAtGot
- : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, SDTCisVT<2, i32>]>;
-def SDT_HexagonAtPcrel
- : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
-
-// AT_GOT address-of-GOT, address-of-global, offset-in-global
-def HexagonAtGot : SDNode<"HexagonISD::AT_GOT", SDT_HexagonAtGot>;
-// AT_PCREL address-of-global
-def HexagonAtPcrel : SDNode<"HexagonISD::AT_PCREL", SDT_HexagonAtPcrel>;
-
-def: Pat<(HexagonAtGot I32:$got, I32:$addr, (i32 0)),
- (L2_loadri_io I32:$got, imm:$addr)>;
-def: Pat<(HexagonAtGot I32:$got, I32:$addr, s30_2ImmPred:$off),
- (A2_addi (L2_loadri_io I32:$got, imm:$addr), imm:$off)>;
-def: Pat<(HexagonAtPcrel I32:$addr),
- (C4_addipc imm:$addr)>;
-
//===----------------------------------------------------------------------===//
// CR -
//===----------------------------------------------------------------------===//
@@ -1914,11 +1516,6 @@ def: Pat<(HexagonAtPcrel I32:$addr),
def A4_andnp : T_ALU64_logical<"and", 0b001, 1, 0, 1>;
def A4_ornp : T_ALU64_logical<"or", 0b011, 1, 0, 1>;
-def: Pat<(i64 (and (i64 DoubleRegs:$Rs), (i64 (not (i64 DoubleRegs:$Rt))))),
- (A4_andnp DoubleRegs:$Rs, DoubleRegs:$Rt)>;
-def: Pat<(i64 (or (i64 DoubleRegs:$Rs), (i64 (not (i64 DoubleRegs:$Rt))))),
- (A4_ornp DoubleRegs:$Rs, DoubleRegs:$Rt)>;
-
let hasNewValue = 1, hasSideEffects = 0 in
def S4_parity: ALU64Inst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, IntRegs:$Rt),
"$Rd = parity($Rs, $Rt)", [], "", ALU64_tc_2_SLOT23> {
@@ -1938,10 +1535,8 @@ def S4_parity: ALU64Inst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, IntRegs:$Rt),
let isExtentSigned = 1, hasNewValue = 1, isExtendable = 1, opExtentBits = 6,
opExtendable = 3 in
def S4_addaddi : ALU64Inst <(outs IntRegs:$Rd),
- (ins IntRegs:$Rs, IntRegs:$Ru, s6Ext:$s6),
- "$Rd = add($Rs, add($Ru, #$s6))" ,
- [(set (i32 IntRegs:$Rd), (add (i32 IntRegs:$Rs),
- (add (i32 IntRegs:$Ru), s32ImmPred:$s6)))],
+ (ins IntRegs:$Rs, IntRegs:$Ru, s6_0Ext:$s6),
+ "$Rd = add($Rs, add($Ru, #$s6))" , [],
"", ALU64_tc_2_SLOT23> {
bits<5> Rd;
bits<5> Rs;
@@ -1962,7 +1557,7 @@ def S4_addaddi : ALU64Inst <(outs IntRegs:$Rd),
let isExtentSigned = 1, hasSideEffects = 0, hasNewValue = 1, isExtendable = 1,
opExtentBits = 6, opExtendable = 2 in
def S4_subaddi: ALU64Inst <(outs IntRegs:$Rd),
- (ins IntRegs:$Rs, s6Ext:$s6, IntRegs:$Ru),
+ (ins IntRegs:$Rs, s6_0Ext:$s6, IntRegs:$Ru),
"$Rd = add($Rs, sub(#$s6, $Ru))",
[], "", ALU64_tc_2_SLOT23> {
bits<5> Rd;
@@ -1981,40 +1576,12 @@ def S4_subaddi: ALU64Inst <(outs IntRegs:$Rd),
let Inst{4-0} = Ru;
}
-// Rd=add(Rs,sub(#s6,Ru))
-def: Pat<(add (i32 IntRegs:$src1), (sub s32ImmPred:$src2,
- (i32 IntRegs:$src3))),
- (S4_subaddi IntRegs:$src1, s32ImmPred:$src2, IntRegs:$src3)>;
-
-// Rd=sub(add(Rs,#s6),Ru)
-def: Pat<(sub (add (i32 IntRegs:$src1), s32ImmPred:$src2),
- (i32 IntRegs:$src3)),
- (S4_subaddi IntRegs:$src1, s32ImmPred:$src2, IntRegs:$src3)>;
-
-// Rd=add(sub(Rs,Ru),#s6)
-def: Pat<(add (sub (i32 IntRegs:$src1), (i32 IntRegs:$src3)),
- (s32ImmPred:$src2)),
- (S4_subaddi IntRegs:$src1, s32ImmPred:$src2, IntRegs:$src3)>;
-
-
-// Add or subtract doublewords with carry.
-//TODO:
-// Rdd=add(Rss,Rtt,Px):carry
-//TODO:
-// Rdd=sub(Rss,Rtt,Px):carry
-
-// Extract bitfield
-// Rdd=extract(Rss,#u6,#U6)
-// Rdd=extract(Rss,Rtt)
-// Rd=extract(Rs,Rtt)
-// Rd=extract(Rs,#u5,#U5)
-
def S4_extractp_rp : T_S3op_64 < "extract", 0b11, 0b100, 0>;
-def S4_extractp : T_S2op_extract <"extract", 0b1010, DoubleRegs, u6Imm>;
+def S4_extractp : T_S2op_extract <"extract", 0b1010, DoubleRegs, u6_0Imm>;
let hasNewValue = 1 in {
def S4_extract_rp : T_S3op_extract<"extract", 0b01>;
- def S4_extract : T_S2op_extract <"extract", 0b1101, IntRegs, u5Imm>;
+ def S4_extract : T_S2op_extract <"extract", 0b1101, IntRegs, u5_0Imm>;
}
// Complex add/sub halfwords/words
@@ -2041,10 +1608,7 @@ let hasSideEffects = 0 in
def M4_xor_xacc
: SInst <(outs DoubleRegs:$Rxx),
(ins DoubleRegs:$dst2, DoubleRegs:$Rss, DoubleRegs:$Rtt),
- "$Rxx ^= xor($Rss, $Rtt)",
- [(set (i64 DoubleRegs:$Rxx),
- (xor (i64 DoubleRegs:$dst2), (xor (i64 DoubleRegs:$Rss),
- (i64 DoubleRegs:$Rtt))))],
+ "$Rxx ^= xor($Rss, $Rtt)", [],
"$dst2 = $Rxx", S_3op_tc_1_SLOT23> {
bits<5> Rxx;
bits<5> Rss;
@@ -2064,7 +1628,7 @@ def M4_xor_xacc
let hasSideEffects = 0 in
def S4_vrcrotate
: SInst <(outs DoubleRegs:$Rdd),
- (ins DoubleRegs:$Rss, IntRegs:$Rt, u2Imm:$u2),
+ (ins DoubleRegs:$Rss, IntRegs:$Rt, u2_0Imm:$u2),
"$Rdd = vrcrotate($Rss, $Rt, #$u2)",
[], "", S_3op_tc_3x_SLOT23> {
bits<5> Rdd;
@@ -2088,7 +1652,7 @@ def S4_vrcrotate
let hasSideEffects = 0 in
def S4_vrcrotate_acc
: SInst <(outs DoubleRegs:$Rxx),
- (ins DoubleRegs:$dst2, DoubleRegs:$Rss, IntRegs:$Rt, u2Imm:$u2),
+ (ins DoubleRegs:$dst2, DoubleRegs:$Rss, IntRegs:$Rt, u2_0Imm:$u2),
"$Rxx += vrcrotate($Rss, $Rt, #$u2)", [],
"$dst2 = $Rxx", S_3op_tc_3x_SLOT23> {
bits<5> Rxx;
@@ -2144,10 +1708,8 @@ let isExtentSigned = 1, hasNewValue = 1, isExtendable = 1, opExtentBits = 10,
opExtendable = 3 in
def S4_or_andix:
ALU64Inst<(outs IntRegs:$Rx),
- (ins IntRegs:$Ru, IntRegs:$_src_, s10Ext:$s10),
- "$Rx = or($Ru, and($_src_, #$s10))" ,
- [(set (i32 IntRegs:$Rx),
- (or (i32 IntRegs:$Ru), (and (i32 IntRegs:$_src_), s32ImmPred:$s10)))] ,
+ (ins IntRegs:$Ru, IntRegs:$_src_, s10_0Ext:$s10),
+ "$Rx = or($Ru, and($_src_, #$s10))" , [] ,
"$_src_ = $Rx", ALU64_tc_2_SLOT23> {
bits<5> Rx;
bits<5> Ru;
@@ -2266,33 +1828,13 @@ def M4_xor_andn : T_MType_acc_rr < "^= and", 0b001, 0b010, 0, [], 1>;
def M4_or_andn : T_MType_acc_rr < "|= and", 0b001, 0b000, 0, [], 1>;
def M4_and_andn : T_MType_acc_rr < "&= and", 0b001, 0b001, 0, [], 1>;
-def: T_MType_acc_pat2 <M4_or_xor, xor, or>;
-def: T_MType_acc_pat2 <M4_and_xor, xor, and>;
-def: T_MType_acc_pat2 <M4_or_and, and, or>;
-def: T_MType_acc_pat2 <M4_and_and, and, and>;
-def: T_MType_acc_pat2 <M4_xor_and, and, xor>;
-def: T_MType_acc_pat2 <M4_or_or, or, or>;
-def: T_MType_acc_pat2 <M4_and_or, or, and>;
-def: T_MType_acc_pat2 <M4_xor_or, or, xor>;
-
-class T_MType_acc_pat3 <InstHexagon MI, SDNode firstOp, SDNode secOp>
- : Pat <(i32 (secOp IntRegs:$src1, (firstOp IntRegs:$src2,
- (not IntRegs:$src3)))),
- (i32 (MI IntRegs:$src1, IntRegs:$src2, IntRegs:$src3))>;
-
-def: T_MType_acc_pat3 <M4_or_andn, and, or>;
-def: T_MType_acc_pat3 <M4_and_andn, and, and>;
-def: T_MType_acc_pat3 <M4_xor_andn, and, xor>;
-
// Compound or-or and or-and
let isExtentSigned = 1, InputType = "imm", hasNewValue = 1, isExtendable = 1,
opExtentBits = 10, opExtendable = 3 in
class T_CompOR <string mnemonic, bits<2> MajOp, SDNode OpNode>
: MInst_acc <(outs IntRegs:$Rx),
- (ins IntRegs:$src1, IntRegs:$Rs, s10Ext:$s10),
- "$Rx |= "#mnemonic#"($Rs, #$s10)",
- [(set (i32 IntRegs:$Rx), (or (i32 IntRegs:$src1),
- (OpNode (i32 IntRegs:$Rs), s32ImmPred:$s10)))],
+ (ins IntRegs:$src1, IntRegs:$Rs, s10_0Ext:$s10),
+ "$Rx |= "#mnemonic#"($Rs, #$s10)", [],
"$src1 = $Rx", ALU64_tc_2_SLOT23>, ImmRegRel {
bits<5> Rx;
bits<5> Rs;
@@ -2363,21 +1905,8 @@ def S2_ct0p : T_COUNT_LEADING_64<"ct0", 0b111, 0b010>;
def S2_ct1p : T_COUNT_LEADING_64<"ct1", 0b111, 0b100>;
def S4_clbpnorm : T_COUNT_LEADING_64<"normamt", 0b011, 0b000>;
-// Count trailing zeros: 64-bit.
-def: Pat<(i32 (trunc (cttz I64:$Rss))), (S2_ct0p I64:$Rss)>;
-
-// Count trailing ones: 64-bit.
-def: Pat<(i32 (trunc (cttz (not I64:$Rss)))), (S2_ct1p I64:$Rss)>;
-
-// Define leading/trailing patterns that require zero-extensions to 64 bits.
-def: Pat<(i64 (ctlz I64:$Rss)), (Zext64 (S2_cl0p I64:$Rss))>;
-def: Pat<(i64 (cttz I64:$Rss)), (Zext64 (S2_ct0p I64:$Rss))>;
-def: Pat<(i64 (ctlz (not I64:$Rss))), (Zext64 (S2_cl1p I64:$Rss))>;
-def: Pat<(i64 (cttz (not I64:$Rss))), (Zext64 (S2_ct1p I64:$Rss))>;
-
-
let hasSideEffects = 0, hasNewValue = 1 in
-def S4_clbaddi : SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, s6Imm:$s6),
+def S4_clbaddi : SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, s6_0Imm:$s6),
"$Rd = add(clb($Rs), #$s6)", [], "", S_2op_tc_2_SLOT23> {
bits<5> Rs;
bits<5> Rd;
@@ -2392,7 +1921,7 @@ def S4_clbaddi : SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs, s6Imm:$s6),
}
let hasSideEffects = 0, hasNewValue = 1 in
-def S4_clbpaddi : SInst<(outs IntRegs:$Rd), (ins DoubleRegs:$Rs, s6Imm:$s6),
+def S4_clbpaddi : SInst<(outs IntRegs:$Rd), (ins DoubleRegs:$Rs, s6_0Imm:$s6),
"$Rd = add(clb($Rs), #$s6)", [], "", S_2op_tc_2_SLOT23> {
bits<5> Rs;
bits<5> Rd;
@@ -2411,41 +1940,10 @@ def S4_clbpaddi : SInst<(outs IntRegs:$Rd), (ins DoubleRegs:$Rs, s6Imm:$s6),
def S4_ntstbit_i : T_TEST_BIT_IMM<"!tstbit", 0b001>;
def S4_ntstbit_r : T_TEST_BIT_REG<"!tstbit", 1>;
-let AddedComplexity = 20 in { // Complexity greater than cmp reg-imm.
- def: Pat<(i1 (seteq (and (shl 1, u5ImmPred:$u5), (i32 IntRegs:$Rs)), 0)),
- (S4_ntstbit_i (i32 IntRegs:$Rs), u5ImmPred:$u5)>;
- def: Pat<(i1 (seteq (and (shl 1, (i32 IntRegs:$Rt)), (i32 IntRegs:$Rs)), 0)),
- (S4_ntstbit_r (i32 IntRegs:$Rs), (i32 IntRegs:$Rt))>;
-}
-
-// Add extra complexity to prefer these instructions over bitsset/bitsclr.
-// The reason is that tstbit/ntstbit can be folded into a compound instruction:
-// if ([!]tstbit(...)) jump ...
-let AddedComplexity = 100 in
-def: Pat<(i1 (setne (and (i32 IntRegs:$Rs), (i32 Set5ImmPred:$u5)), (i32 0))),
- (S2_tstbit_i (i32 IntRegs:$Rs), (BITPOS32 Set5ImmPred:$u5))>;
-
-let AddedComplexity = 100 in
-def: Pat<(i1 (seteq (and (i32 IntRegs:$Rs), (i32 Set5ImmPred:$u5)), (i32 0))),
- (S4_ntstbit_i (i32 IntRegs:$Rs), (BITPOS32 Set5ImmPred:$u5))>;
-
def C4_nbitsset : T_TEST_BITS_REG<"!bitsset", 0b01, 1>;
def C4_nbitsclr : T_TEST_BITS_REG<"!bitsclr", 0b10, 1>;
def C4_nbitsclri : T_TEST_BITS_IMM<"!bitsclr", 0b10, 1>;
-// Do not increase complexity of these patterns. In the DAG, "cmp i8" may be
-// represented as a compare against "value & 0xFF", which is an exact match
-// for cmpb (same for cmph). The patterns below do not contain any additional
-// complexity that would make them preferable, and if they were actually used
-// instead of cmpb/cmph, they would result in a compare against register that
-// is loaded with the byte/half mask (i.e. 0xFF or 0xFFFF).
-def: Pat<(i1 (setne (and I32:$Rs, u6ImmPred:$u6), 0)),
- (C4_nbitsclri I32:$Rs, u6ImmPred:$u6)>;
-def: Pat<(i1 (setne (and I32:$Rs, I32:$Rt), 0)),
- (C4_nbitsclr I32:$Rs, I32:$Rt)>;
-def: Pat<(i1 (setne (and I32:$Rs, I32:$Rt), I32:$Rt)),
- (C4_nbitsset I32:$Rs, I32:$Rt)>;
-
//===----------------------------------------------------------------------===//
// XTYPE/BIT -
//===----------------------------------------------------------------------===//
@@ -2458,11 +1956,8 @@ def: Pat<(i1 (setne (and I32:$Rs, I32:$Rt), I32:$Rt)),
let hasNewValue = 1, isExtendable = 1, opExtentBits = 6, opExtendable = 1 in
def M4_mpyri_addi : MInst<(outs IntRegs:$Rd),
- (ins u6Ext:$u6, IntRegs:$Rs, u6Imm:$U6),
- "$Rd = add(#$u6, mpyi($Rs, #$U6))" ,
- [(set (i32 IntRegs:$Rd),
- (add (mul (i32 IntRegs:$Rs), u6ImmPred:$U6),
- u32ImmPred:$u6))] ,"",ALU64_tc_3x_SLOT23> {
+ (ins u6_0Ext:$u6, IntRegs:$Rs, u6_0Imm:$U6),
+ "$Rd = add(#$u6, mpyi($Rs, #$U6))" , [],"",ALU64_tc_3x_SLOT23> {
bits<5> Rd;
bits<6> u6;
bits<5> Rs;
@@ -2484,11 +1979,8 @@ def M4_mpyri_addi : MInst<(outs IntRegs:$Rd),
let CextOpcode = "ADD_MPY", InputType = "imm", hasNewValue = 1,
isExtendable = 1, opExtentBits = 6, opExtendable = 1 in
def M4_mpyrr_addi : MInst <(outs IntRegs:$Rd),
- (ins u6Ext:$u6, IntRegs:$Rs, IntRegs:$Rt),
- "$Rd = add(#$u6, mpyi($Rs, $Rt))" ,
- [(set (i32 IntRegs:$Rd),
- (add (mul (i32 IntRegs:$Rs), (i32 IntRegs:$Rt)), u32ImmPred:$u6))],
- "", ALU64_tc_3x_SLOT23>, ImmRegRel {
+ (ins u6_0Ext:$u6, IntRegs:$Rs, IntRegs:$Rt),
+ "$Rd = add(#$u6, mpyi($Rs, $Rt))" , [], "", ALU64_tc_3x_SLOT23>, ImmRegRel {
bits<5> Rd;
bits<6> u6;
bits<5> Rs;
@@ -2509,9 +2001,7 @@ let hasNewValue = 1 in
class T_AddMpy <bit MajOp, PatLeaf ImmPred, dag ins>
: ALU64Inst <(outs IntRegs:$dst), ins,
"$dst = add($src1, mpyi("#!if(MajOp,"$src3, #$src2))",
- "#$src2, $src3))"),
- [(set (i32 IntRegs:$dst),
- (add (i32 IntRegs:$src1), (mul (i32 IntRegs:$src3), ImmPred:$src2)))],
+ "#$src2, $src3))"), [],
"", ALU64_tc_3x_SLOT23> {
bits<5> dst;
bits<5> src1;
@@ -2537,16 +2027,14 @@ def M4_mpyri_addr_u2 : T_AddMpy<0b0, u6_2ImmPred,
let isExtendable = 1, opExtentBits = 6, opExtendable = 3,
CextOpcode = "ADD_MPY", InputType = "imm" in
-def M4_mpyri_addr : T_AddMpy<0b1, u32ImmPred,
- (ins IntRegs:$src1, IntRegs:$src3, u6Ext:$src2)>, ImmRegRel;
+def M4_mpyri_addr : T_AddMpy<0b1, u32_0ImmPred,
+ (ins IntRegs:$src1, IntRegs:$src3, u6_0Ext:$src2)>, ImmRegRel;
// Rx=add(Ru,mpyi(Rx,Rs))
let CextOpcode = "ADD_MPY", InputType = "reg", hasNewValue = 1 in
def M4_mpyrr_addr: MInst_acc <(outs IntRegs:$Rx),
(ins IntRegs:$Ru, IntRegs:$_src_, IntRegs:$Rs),
- "$Rx = add($Ru, mpyi($_src_, $Rs))",
- [(set (i32 IntRegs:$Rx), (add (i32 IntRegs:$Ru),
- (mul (i32 IntRegs:$_src_), (i32 IntRegs:$Rs))))],
+ "$Rx = add($Ru, mpyi($_src_, $Rs))", [],
"$_src_ = $Rx", M_tc_3x_SLOT23>, ImmRegRel {
bits<5> Rx;
bits<5> Ru;
@@ -2637,24 +2125,23 @@ class T_vcmpImm <string Str, bits<2> cmpOp, bits<2> minOp, Operand ImmOprnd>
// Vector compare bytes
def A4_vcmpbgt : T_vcmp <"vcmpb.gt", 0b1010>;
-def: T_vcmp_pat<A4_vcmpbgt, setgt, v8i8>;
let AsmString = "$Pd = any8(vcmpb.eq($Rss, $Rtt))" in
def A4_vcmpbeq_any : T_vcmp <"any8(vcmpb.gt", 0b1000>;
-def A4_vcmpbeqi : T_vcmpImm <"vcmpb.eq", 0b00, 0b00, u8Imm>;
-def A4_vcmpbgti : T_vcmpImm <"vcmpb.gt", 0b01, 0b00, s8Imm>;
-def A4_vcmpbgtui : T_vcmpImm <"vcmpb.gtu", 0b10, 0b00, u7Imm>;
+def A4_vcmpbeqi : T_vcmpImm <"vcmpb.eq", 0b00, 0b00, u8_0Imm>;
+def A4_vcmpbgti : T_vcmpImm <"vcmpb.gt", 0b01, 0b00, s8_0Imm>;
+def A4_vcmpbgtui : T_vcmpImm <"vcmpb.gtu", 0b10, 0b00, u7_0Imm>;
// Vector compare halfwords
-def A4_vcmpheqi : T_vcmpImm <"vcmph.eq", 0b00, 0b01, s8Imm>;
-def A4_vcmphgti : T_vcmpImm <"vcmph.gt", 0b01, 0b01, s8Imm>;
-def A4_vcmphgtui : T_vcmpImm <"vcmph.gtu", 0b10, 0b01, u7Imm>;
+def A4_vcmpheqi : T_vcmpImm <"vcmph.eq", 0b00, 0b01, s8_0Imm>;
+def A4_vcmphgti : T_vcmpImm <"vcmph.gt", 0b01, 0b01, s8_0Imm>;
+def A4_vcmphgtui : T_vcmpImm <"vcmph.gtu", 0b10, 0b01, u7_0Imm>;
// Vector compare words
-def A4_vcmpweqi : T_vcmpImm <"vcmpw.eq", 0b00, 0b10, s8Imm>;
-def A4_vcmpwgti : T_vcmpImm <"vcmpw.gt", 0b01, 0b10, s8Imm>;
-def A4_vcmpwgtui : T_vcmpImm <"vcmpw.gtu", 0b10, 0b10, u7Imm>;
+def A4_vcmpweqi : T_vcmpImm <"vcmpw.eq", 0b00, 0b10, s8_0Imm>;
+def A4_vcmpwgti : T_vcmpImm <"vcmpw.gt", 0b01, 0b10, s8_0Imm>;
+def A4_vcmpwgtui : T_vcmpImm <"vcmpw.gtu", 0b10, 0b10, u7_0Imm>;
//===----------------------------------------------------------------------===//
// XTYPE/SHIFT +
@@ -2666,13 +2153,11 @@ def A4_vcmpwgtui : T_vcmpImm <"vcmpw.gtu", 0b10, 0b10, u7Imm>;
// Rx=or(#u8,asl(Rx,#U5)) Rx=or(#u8,lsr(Rx,#U5))
let isExtendable = 1, opExtendable = 1, isExtentSigned = 0, opExtentBits = 8,
hasNewValue = 1, opNewValue = 0 in
-class T_S4_ShiftOperate<string MnOp, string MnSh, SDNode Op, SDNode Sh,
- bit asl_lsr, bits<2> MajOp, InstrItinClass Itin>
- : MInst_acc<(outs IntRegs:$Rd), (ins u8Ext:$u8, IntRegs:$Rx, u5Imm:$U5),
+class T_S4_ShiftOperate<string MnOp, string MnSh, bit asl_lsr,
+ bits<2> MajOp, InstrItinClass Itin>
+ : MInst_acc<(outs IntRegs:$Rd), (ins u8_0Ext:$u8, IntRegs:$Rx, u5_0Imm:$U5),
"$Rd = "#MnOp#"(#$u8, "#MnSh#"($Rx, #$U5))",
- [(set (i32 IntRegs:$Rd),
- (Op (Sh I32:$Rx, u5ImmPred:$U5), u32ImmPred:$u8))],
- "$Rd = $Rx", Itin> {
+ [], "$Rd = $Rx", Itin> {
bits<5> Rd;
bits<8> u8;
@@ -2691,32 +2176,15 @@ class T_S4_ShiftOperate<string MnOp, string MnSh, SDNode Op, SDNode Sh,
let Inst{2-1} = MajOp;
}
-multiclass T_ShiftOperate<string mnemonic, SDNode Op, bits<2> MajOp,
- InstrItinClass Itin> {
- def _asl_ri : T_S4_ShiftOperate<mnemonic, "asl", Op, shl, 0, MajOp, Itin>;
- def _lsr_ri : T_S4_ShiftOperate<mnemonic, "lsr", Op, srl, 1, MajOp, Itin>;
-}
-
-let AddedComplexity = 200 in {
- defm S4_addi : T_ShiftOperate<"add", add, 0b10, ALU64_tc_2_SLOT23>;
- defm S4_andi : T_ShiftOperate<"and", and, 0b00, ALU64_tc_2_SLOT23>;
+multiclass T_ShiftOperate<string mnemonic, bits<2> MajOp, InstrItinClass Itin> {
+ def _asl_ri : T_S4_ShiftOperate<mnemonic, "asl", 0, MajOp, Itin>;
+ def _lsr_ri : T_S4_ShiftOperate<mnemonic, "lsr", 1, MajOp, Itin>;
}
-let AddedComplexity = 30 in
-defm S4_ori : T_ShiftOperate<"or", or, 0b01, ALU64_tc_1_SLOT23>;
-
-defm S4_subi : T_ShiftOperate<"sub", sub, 0b11, ALU64_tc_1_SLOT23>;
-
-let AddedComplexity = 200 in {
- def: Pat<(add addrga:$addr, (shl I32:$src2, u5ImmPred:$src3)),
- (S4_addi_asl_ri addrga:$addr, IntRegs:$src2, u5ImmPred:$src3)>;
- def: Pat<(add addrga:$addr, (srl I32:$src2, u5ImmPred:$src3)),
- (S4_addi_lsr_ri addrga:$addr, IntRegs:$src2, u5ImmPred:$src3)>;
- def: Pat<(sub addrga:$addr, (shl I32:$src2, u5ImmPred:$src3)),
- (S4_subi_asl_ri addrga:$addr, IntRegs:$src2, u5ImmPred:$src3)>;
- def: Pat<(sub addrga:$addr, (srl I32:$src2, u5ImmPred:$src3)),
- (S4_subi_lsr_ri addrga:$addr, IntRegs:$src2, u5ImmPred:$src3)>;
-}
+defm S4_addi : T_ShiftOperate<"add", 0b10, ALU64_tc_2_SLOT23>;
+defm S4_andi : T_ShiftOperate<"and", 0b00, ALU64_tc_2_SLOT23>;
+defm S4_ori : T_ShiftOperate<"or", 0b01, ALU64_tc_1_SLOT23>;
+defm S4_subi : T_ShiftOperate<"sub", 0b11, ALU64_tc_1_SLOT23>;
// Vector conditional negate
// Rdd=vcnegh(Rss,Rt)
@@ -2806,11 +2274,8 @@ def A4_vrminuw : T_S3op_6 < "vrminuw", 0b110, 1>;
// Shift an immediate left by register amount.
let hasNewValue = 1, hasSideEffects = 0 in
-def S4_lsli: SInst <(outs IntRegs:$Rd), (ins s6Imm:$s6, IntRegs:$Rt),
- "$Rd = lsl(#$s6, $Rt)" ,
- [(set (i32 IntRegs:$Rd), (shl s6ImmPred:$s6,
- (i32 IntRegs:$Rt)))],
- "", S_3op_tc_1_SLOT23> {
+def S4_lsli: SInst <(outs IntRegs:$Rd), (ins s6_0Imm:$s6, IntRegs:$Rt),
+ "$Rd = lsl(#$s6, $Rt)" , [], "", S_3op_tc_1_SLOT23> {
bits<5> Rd;
bits<6> s6;
bits<5> Rt;
@@ -2833,71 +2298,6 @@ def S4_lsli: SInst <(outs IntRegs:$Rd), (ins s6Imm:$s6, IntRegs:$Rt),
// MEMOP
//===----------------------------------------------------------------------===//
-def m5Imm8Pred : PatLeaf<(i32 imm), [{
- int8_t v = (int8_t)N->getSExtValue();
- return v > -32 && v <= -1;
-}]>;
-
-def m5Imm16Pred : PatLeaf<(i32 imm), [{
- int16_t v = (int16_t)N->getSExtValue();
- return v > -32 && v <= -1;
-}]>;
-
-def Clr5Imm8Pred : PatLeaf<(i32 imm), [{
- uint32_t v = (uint8_t)~N->getZExtValue();
- return ImmIsSingleBit(v);
-}]>;
-
-def Clr5Imm16Pred : PatLeaf<(i32 imm), [{
- uint32_t v = (uint16_t)~N->getZExtValue();
- return ImmIsSingleBit(v);
-}]>;
-
-def Set5Imm8 : SDNodeXForm<imm, [{
- uint32_t imm = (uint8_t)N->getZExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-def Set5Imm16 : SDNodeXForm<imm, [{
- uint32_t imm = (uint16_t)N->getZExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-def Set5Imm32 : SDNodeXForm<imm, [{
- uint32_t imm = (uint32_t)N->getZExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-def Clr5Imm8 : SDNodeXForm<imm, [{
- uint32_t imm = (uint8_t)~N->getZExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-def Clr5Imm16 : SDNodeXForm<imm, [{
- uint32_t imm = (uint16_t)~N->getZExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-def Clr5Imm32 : SDNodeXForm<imm, [{
- int32_t imm = (int32_t)~N->getZExtValue();
- return XformMskToBitPosU5Imm(imm, SDLoc(N));
-}]>;
-
-def NegImm8 : SDNodeXForm<imm, [{
- int8_t V = N->getSExtValue();
- return CurDAG->getTargetConstant(-V, SDLoc(N), MVT::i32);
-}]>;
-
-def NegImm16 : SDNodeXForm<imm, [{
- int16_t V = N->getSExtValue();
- return CurDAG->getTargetConstant(-V, SDLoc(N), MVT::i32);
-}]>;
-
-def NegImm32 : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(-N->getSExtValue(), SDLoc(N), MVT::i32);
-}]>;
-
-def IdImm : SDNodeXForm<imm, [{ return SDValue(N, 0); }]>;
//===----------------------------------------------------------------------===//
// Template class for MemOp instructions with the register value.
@@ -2936,7 +2336,7 @@ class MemOp_rr_base <string opc, bits<2> opcBits, Operand ImmOp,
class MemOp_ri_base <string opc, bits<2> opcBits, Operand ImmOp,
string memOp, bits<2> memOpBits> :
MEMInst_V4 <(outs),
- (ins IntRegs:$base, ImmOp:$offset, u5Imm:$delta),
+ (ins IntRegs:$base, ImmOp:$offset, u5_0Imm:$delta),
opc#"($base+#$offset)"#memOp#"#$delta"
#!if(memOpBits{1},")", ""), // clrbit, setbit - include ')'
[]>,
@@ -2996,235 +2396,6 @@ let isExtendable = 1, opExtendable = 1, isExtentSigned = 0 in {
}
-multiclass Memopxr_simple_pat<PatFrag Load, PatFrag Store, SDNode Oper,
- InstHexagon MI> {
- // Addr: i32
- def: Pat<(Store (Oper (Load I32:$Rs), I32:$A), I32:$Rs),
- (MI I32:$Rs, 0, I32:$A)>;
- // Addr: fi
- def: Pat<(Store (Oper (Load AddrFI:$Rs), I32:$A), AddrFI:$Rs),
- (MI AddrFI:$Rs, 0, I32:$A)>;
-}
-
-multiclass Memopxr_add_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
- SDNode Oper, InstHexagon MI> {
- // Addr: i32
- def: Pat<(Store (Oper (Load (add I32:$Rs, ImmPred:$Off)), I32:$A),
- (add I32:$Rs, ImmPred:$Off)),
- (MI I32:$Rs, imm:$Off, I32:$A)>;
- def: Pat<(Store (Oper (Load (orisadd I32:$Rs, ImmPred:$Off)), I32:$A),
- (orisadd I32:$Rs, ImmPred:$Off)),
- (MI I32:$Rs, imm:$Off, I32:$A)>;
- // Addr: fi
- def: Pat<(Store (Oper (Load (add AddrFI:$Rs, ImmPred:$Off)), I32:$A),
- (add AddrFI:$Rs, ImmPred:$Off)),
- (MI AddrFI:$Rs, imm:$Off, I32:$A)>;
- def: Pat<(Store (Oper (Load (orisadd AddrFI:$Rs, ImmPred:$Off)), I32:$A),
- (orisadd AddrFI:$Rs, ImmPred:$Off)),
- (MI AddrFI:$Rs, imm:$Off, I32:$A)>;
-}
-
-multiclass Memopxr_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
- SDNode Oper, InstHexagon MI> {
- defm: Memopxr_simple_pat <Load, Store, Oper, MI>;
- defm: Memopxr_add_pat <Load, Store, ImmPred, Oper, MI>;
-}
-
-let AddedComplexity = 180 in {
- // add reg
- defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, add,
- /*anyext*/ L4_add_memopb_io>;
- defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, add,
- /*sext*/ L4_add_memopb_io>;
- defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, add,
- /*zext*/ L4_add_memopb_io>;
- defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, add,
- /*anyext*/ L4_add_memoph_io>;
- defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, add,
- /*sext*/ L4_add_memoph_io>;
- defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, add,
- /*zext*/ L4_add_memoph_io>;
- defm: Memopxr_pat<load, store, u6_2ImmPred, add, L4_add_memopw_io>;
-
- // sub reg
- defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, sub,
- /*anyext*/ L4_sub_memopb_io>;
- defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, sub,
- /*sext*/ L4_sub_memopb_io>;
- defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, sub,
- /*zext*/ L4_sub_memopb_io>;
- defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, sub,
- /*anyext*/ L4_sub_memoph_io>;
- defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, sub,
- /*sext*/ L4_sub_memoph_io>;
- defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, sub,
- /*zext*/ L4_sub_memoph_io>;
- defm: Memopxr_pat<load, store, u6_2ImmPred, sub, L4_sub_memopw_io>;
-
- // and reg
- defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, and,
- /*anyext*/ L4_and_memopb_io>;
- defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, and,
- /*sext*/ L4_and_memopb_io>;
- defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, and,
- /*zext*/ L4_and_memopb_io>;
- defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, and,
- /*anyext*/ L4_and_memoph_io>;
- defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, and,
- /*sext*/ L4_and_memoph_io>;
- defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, and,
- /*zext*/ L4_and_memoph_io>;
- defm: Memopxr_pat<load, store, u6_2ImmPred, and, L4_and_memopw_io>;
-
- // or reg
- defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, or,
- /*anyext*/ L4_or_memopb_io>;
- defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, or,
- /*sext*/ L4_or_memopb_io>;
- defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, or,
- /*zext*/ L4_or_memopb_io>;
- defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, or,
- /*anyext*/ L4_or_memoph_io>;
- defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, or,
- /*sext*/ L4_or_memoph_io>;
- defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, or,
- /*zext*/ L4_or_memoph_io>;
- defm: Memopxr_pat<load, store, u6_2ImmPred, or, L4_or_memopw_io>;
-}
-
-
-multiclass Memopxi_simple_pat<PatFrag Load, PatFrag Store, SDNode Oper,
- PatFrag Arg, SDNodeXForm ArgMod,
- InstHexagon MI> {
- // Addr: i32
- def: Pat<(Store (Oper (Load I32:$Rs), Arg:$A), I32:$Rs),
- (MI I32:$Rs, 0, (ArgMod Arg:$A))>;
- // Addr: fi
- def: Pat<(Store (Oper (Load AddrFI:$Rs), Arg:$A), AddrFI:$Rs),
- (MI AddrFI:$Rs, 0, (ArgMod Arg:$A))>;
-}
-
-multiclass Memopxi_add_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
- SDNode Oper, PatFrag Arg, SDNodeXForm ArgMod,
- InstHexagon MI> {
- // Addr: i32
- def: Pat<(Store (Oper (Load (add I32:$Rs, ImmPred:$Off)), Arg:$A),
- (add I32:$Rs, ImmPred:$Off)),
- (MI I32:$Rs, imm:$Off, (ArgMod Arg:$A))>;
- def: Pat<(Store (Oper (Load (orisadd I32:$Rs, ImmPred:$Off)), Arg:$A),
- (orisadd I32:$Rs, ImmPred:$Off)),
- (MI I32:$Rs, imm:$Off, (ArgMod Arg:$A))>;
- // Addr: fi
- def: Pat<(Store (Oper (Load (add AddrFI:$Rs, ImmPred:$Off)), Arg:$A),
- (add AddrFI:$Rs, ImmPred:$Off)),
- (MI AddrFI:$Rs, imm:$Off, (ArgMod Arg:$A))>;
- def: Pat<(Store (Oper (Load (orisadd AddrFI:$Rs, ImmPred:$Off)), Arg:$A),
- (orisadd AddrFI:$Rs, ImmPred:$Off)),
- (MI AddrFI:$Rs, imm:$Off, (ArgMod Arg:$A))>;
-}
-
-multiclass Memopxi_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
- SDNode Oper, PatFrag Arg, SDNodeXForm ArgMod,
- InstHexagon MI> {
- defm: Memopxi_simple_pat <Load, Store, Oper, Arg, ArgMod, MI>;
- defm: Memopxi_add_pat <Load, Store, ImmPred, Oper, Arg, ArgMod, MI>;
-}
-
-
-let AddedComplexity = 200 in {
- // add imm
- defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, add, u5ImmPred,
- /*anyext*/ IdImm, L4_iadd_memopb_io>;
- defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, add, u5ImmPred,
- /*sext*/ IdImm, L4_iadd_memopb_io>;
- defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, add, u5ImmPred,
- /*zext*/ IdImm, L4_iadd_memopb_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, u5ImmPred,
- /*anyext*/ IdImm, L4_iadd_memoph_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, u5ImmPred,
- /*sext*/ IdImm, L4_iadd_memoph_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, u5ImmPred,
- /*zext*/ IdImm, L4_iadd_memoph_io>;
- defm: Memopxi_pat<load, store, u6_2ImmPred, add, u5ImmPred, IdImm,
- L4_iadd_memopw_io>;
- defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, sub, m5Imm8Pred,
- /*anyext*/ NegImm8, L4_iadd_memopb_io>;
- defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, sub, m5Imm8Pred,
- /*sext*/ NegImm8, L4_iadd_memopb_io>;
- defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, sub, m5Imm8Pred,
- /*zext*/ NegImm8, L4_iadd_memopb_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, sub, m5Imm16Pred,
- /*anyext*/ NegImm16, L4_iadd_memoph_io>;
- defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, sub, m5Imm16Pred,
- /*sext*/ NegImm16, L4_iadd_memoph_io>;
- defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, sub, m5Imm16Pred,
- /*zext*/ NegImm16, L4_iadd_memoph_io>;
- defm: Memopxi_pat<load, store, u6_2ImmPred, sub, m5ImmPred, NegImm32,
- L4_iadd_memopw_io>;
-
- // sub imm
- defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, sub, u5ImmPred,
- /*anyext*/ IdImm, L4_isub_memopb_io>;
- defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, sub, u5ImmPred,
- /*sext*/ IdImm, L4_isub_memopb_io>;
- defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, sub, u5ImmPred,
- /*zext*/ IdImm, L4_isub_memopb_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, sub, u5ImmPred,
- /*anyext*/ IdImm, L4_isub_memoph_io>;
- defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, sub, u5ImmPred,
- /*sext*/ IdImm, L4_isub_memoph_io>;
- defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, sub, u5ImmPred,
- /*zext*/ IdImm, L4_isub_memoph_io>;
- defm: Memopxi_pat<load, store, u6_2ImmPred, sub, u5ImmPred, IdImm,
- L4_isub_memopw_io>;
- defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, add, m5Imm8Pred,
- /*anyext*/ NegImm8, L4_isub_memopb_io>;
- defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, add, m5Imm8Pred,
- /*sext*/ NegImm8, L4_isub_memopb_io>;
- defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, add, m5Imm8Pred,
- /*zext*/ NegImm8, L4_isub_memopb_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, m5Imm16Pred,
- /*anyext*/ NegImm16, L4_isub_memoph_io>;
- defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, add, m5Imm16Pred,
- /*sext*/ NegImm16, L4_isub_memoph_io>;
- defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, add, m5Imm16Pred,
- /*zext*/ NegImm16, L4_isub_memoph_io>;
- defm: Memopxi_pat<load, store, u6_2ImmPred, add, m5ImmPred, NegImm32,
- L4_isub_memopw_io>;
-
- // clrbit imm
- defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, and, Clr5Imm8Pred,
- /*anyext*/ Clr5Imm8, L4_iand_memopb_io>;
- defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, and, Clr5Imm8Pred,
- /*sext*/ Clr5Imm8, L4_iand_memopb_io>;
- defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, and, Clr5Imm8Pred,
- /*zext*/ Clr5Imm8, L4_iand_memopb_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, and, Clr5Imm16Pred,
- /*anyext*/ Clr5Imm16, L4_iand_memoph_io>;
- defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, and, Clr5Imm16Pred,
- /*sext*/ Clr5Imm16, L4_iand_memoph_io>;
- defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, and, Clr5Imm16Pred,
- /*zext*/ Clr5Imm16, L4_iand_memoph_io>;
- defm: Memopxi_pat<load, store, u6_2ImmPred, and, Clr5ImmPred, Clr5Imm32,
- L4_iand_memopw_io>;
-
- // setbit imm
- defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, or, Set5ImmPred,
- /*anyext*/ Set5Imm8, L4_ior_memopb_io>;
- defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, or, Set5ImmPred,
- /*sext*/ Set5Imm8, L4_ior_memopb_io>;
- defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, or, Set5ImmPred,
- /*zext*/ Set5Imm8, L4_ior_memopb_io>;
- defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, or, Set5ImmPred,
- /*anyext*/ Set5Imm16, L4_ior_memoph_io>;
- defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, or, Set5ImmPred,
- /*sext*/ Set5Imm16, L4_ior_memoph_io>;
- defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, or, Set5ImmPred,
- /*zext*/ Set5Imm16, L4_ior_memoph_io>;
- defm: Memopxi_pat<load, store, u6_2ImmPred, or, Set5ImmPred, Set5Imm32,
- L4_ior_memopw_io>;
-}
-
//===----------------------------------------------------------------------===//
// XTYPE/PRED +
//===----------------------------------------------------------------------===//
@@ -3241,57 +2412,9 @@ let AddedComplexity = 200 in {
// Pd=cmpb.eq(Rs,#u8)
// p=!cmp.eq(r1,#s10)
-def C4_cmpneqi : T_CMP <"cmp.eq", 0b00, 1, s10Ext>;
-def C4_cmpltei : T_CMP <"cmp.gt", 0b01, 1, s10Ext>;
-def C4_cmplteui : T_CMP <"cmp.gtu", 0b10, 1, u9Ext>;
-
-def : T_CMP_pat <C4_cmpneqi, setne, s32ImmPred>;
-def : T_CMP_pat <C4_cmpltei, setle, s32ImmPred>;
-def : T_CMP_pat <C4_cmplteui, setule, u9ImmPred>;
-
-// rs <= rt -> !(rs > rt).
-/*
-def: Pat<(i1 (setle (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C2_not (C2_cmpgti IntRegs:$src1, s32ImmPred:$src2))>;
-// (C4_cmpltei IntRegs:$src1, s32ImmPred:$src2)>;
-*/
-// Map cmplt(Rs, Imm) -> !cmpgt(Rs, Imm-1).
-def: Pat<(i1 (setlt (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C4_cmpltei IntRegs:$src1, (DEC_CONST_SIGNED s32ImmPred:$src2))>;
-
-// rs != rt -> !(rs == rt).
-def: Pat<(i1 (setne (i32 IntRegs:$src1), s32ImmPred:$src2)),
- (C4_cmpneqi IntRegs:$src1, s32ImmPred:$src2)>;
-
-// SDNode for converting immediate C to C-1.
-def DEC_CONST_BYTE : SDNodeXForm<imm, [{
- // Return the byte immediate const-1 as an SDNode.
- int32_t imm = N->getSExtValue();
- return XformU7ToU7M1Imm(imm, SDLoc(N));
-}]>;
-
-// For the sequence
-// zext( setult ( and(Rs, 255), u8))
-// Use the isdigit transformation below
-
-// Generate code of the form 'C2_muxii(cmpbgtui(Rdd, C-1),0,1)'
-// for C code of the form r = ((c>='0') & (c<='9')) ? 1 : 0;.
-// The isdigit transformation relies on two 'clever' aspects:
-// 1) The data type is unsigned which allows us to eliminate a zero test after
-// biasing the expression by 48. We are depending on the representation of
-// the unsigned types, and semantics.
-// 2) The front end has converted <= 9 into < 10 on entry to LLVM
-//
-// For the C code:
-// retval = ((c>='0') & (c<='9')) ? 1 : 0;
-// The code is transformed upstream of llvm into
-// retval = (c-48) < 10 ? 1 : 0;
-let AddedComplexity = 139 in
-def: Pat<(i32 (zext (i1 (setult (i32 (and (i32 IntRegs:$src1), 255)),
- u7StrictPosImmPred:$src2)))),
- (C2_muxii (A4_cmpbgtui IntRegs:$src1,
- (DEC_CONST_BYTE u7StrictPosImmPred:$src2)),
- 0, 1)>;
+def C4_cmpneqi : T_CMP <"cmp.eq", 0b00, 1, s10_0Ext>;
+def C4_cmpltei : T_CMP <"cmp.gt", 0b01, 1, s10_0Ext>;
+def C4_cmplteui : T_CMP <"cmp.gtu", 0b10, 1, u9_0Ext>;
//===----------------------------------------------------------------------===//
// XTYPE/PRED -
@@ -3450,7 +2573,7 @@ class T_StoreAbsGP <string mnemonic, RegisterClass RC, Operand ImmOp,
let hasSideEffects = 0, isPredicated = 1, opExtentBits = 6, opExtendable = 1 in
class T_StoreAbs_Pred <string mnemonic, RegisterClass RC, bits<2> MajOp,
bit isHalf, bit isNot, bit isNew>
- : STInst<(outs), (ins PredRegs:$src1, u32MustExt:$absaddr, RC: $src2),
+ : STInst<(outs), (ins PredRegs:$src1, u32_0MustExt:$absaddr, RC: $src2),
!if(isNot, "if (!$src1", "if ($src1")#!if(isNew, ".new) ",
") ")#mnemonic#"(#$absaddr) = $src2"#!if(isHalf, ".h",""),
[], "", ST_tc_st_SLOT01>, AddrModeRel {
@@ -3482,7 +2605,7 @@ class T_StoreAbs_Pred <string mnemonic, RegisterClass RC, bits<2> MajOp,
//===----------------------------------------------------------------------===//
class T_StoreAbs <string mnemonic, RegisterClass RC, Operand ImmOp,
bits<2> MajOp, bit isHalf>
- : T_StoreAbsGP <mnemonic, RC, u32MustExt, MajOp, 1, isHalf>,
+ : T_StoreAbsGP <mnemonic, RC, u32_0MustExt, MajOp, 1, isHalf>,
AddrModeRel {
string ImmOpStr = !cast<string>(ImmOp);
let opExtentBits = !if (!eq(ImmOpStr, "u16_3Imm"), 19,
@@ -3504,7 +2627,7 @@ multiclass ST_Abs<string mnemonic, string CextOp, RegisterClass RC,
Operand ImmOp, bits<2> MajOp, bit isHalf = 0> {
let CextOpcode = CextOp, BaseOpcode = CextOp#_abs in {
let opExtendable = 0, isPredicable = 1 in
- def S2_#NAME#abs : T_StoreAbs <mnemonic, RC, ImmOp, MajOp, isHalf>;
+ def PS_#NAME#abs : T_StoreAbs <mnemonic, RC, ImmOp, MajOp, isHalf>;
// Predicated
def S4_p#NAME#t_abs : T_StoreAbs_Pred<mnemonic, RC, MajOp, isHalf, 0, 0>;
@@ -3554,7 +2677,7 @@ class T_StoreAbsGP_NV <string mnemonic, Operand ImmOp, bits<2>MajOp>
let hasSideEffects = 0, isPredicated = 1, mayStore = 1, isNVStore = 1,
isNewValue = 1, opNewValue = 2, opExtentBits = 6, opExtendable = 1 in
class T_StoreAbs_NV_Pred <string mnemonic, bits<2> MajOp, bit isNot, bit isNew>
- : NVInst_V4<(outs), (ins PredRegs:$src1, u32MustExt:$absaddr, IntRegs:$src2),
+ : NVInst_V4<(outs), (ins PredRegs:$src1, u32_0MustExt:$absaddr, IntRegs:$src2),
!if(isNot, "if (!$src1", "if ($src1")#!if(isNew, ".new) ",
") ")#mnemonic#"(#$absaddr) = $src2.new",
[], "", ST_tc_st_SLOT0>, AddrModeRel {
@@ -3584,7 +2707,7 @@ class T_StoreAbs_NV_Pred <string mnemonic, bits<2> MajOp, bit isNot, bit isNew>
// absolute addressing.
//===----------------------------------------------------------------------===//
class T_StoreAbs_NV <string mnemonic, Operand ImmOp, bits<2> MajOp>
- : T_StoreAbsGP_NV <mnemonic, u32MustExt, MajOp>, AddrModeRel {
+ : T_StoreAbsGP_NV <mnemonic, u32_0MustExt, MajOp>, AddrModeRel {
string ImmOpStr = !cast<string>(ImmOp);
let opExtentBits = !if (!eq(ImmOpStr, "u16_3Imm"), 19,
@@ -3606,7 +2729,7 @@ multiclass ST_Abs_NV <string mnemonic, string CextOp, Operand ImmOp,
bits<2> MajOp> {
let CextOpcode = CextOp, BaseOpcode = CextOp#_abs in {
let opExtendable = 0, isPredicable = 1 in
- def S2_#NAME#newabs : T_StoreAbs_NV <mnemonic, ImmOp, MajOp>;
+ def PS_#NAME#newabs : T_StoreAbs_NV <mnemonic, ImmOp, MajOp>;
// Predicated
def S4_p#NAME#newt_abs : T_StoreAbs_NV_Pred <mnemonic, MajOp, 0, 0>;
@@ -3687,50 +2810,6 @@ let isNVStorable = 0, accessSize = HalfWordAccess in
def S2_storerfgp : T_StoreGP <"memh", "STrif", IntRegs,
u16_1Imm, 0b01, 1>, PredNewRel;
-class Loada_pat<PatFrag Load, ValueType VT, PatFrag Addr, InstHexagon MI>
- : Pat<(VT (Load Addr:$addr)), (MI Addr:$addr)>;
-
-class Loadam_pat<PatFrag Load, ValueType VT, PatFrag Addr, PatFrag ValueMod,
- InstHexagon MI>
- : Pat<(VT (Load Addr:$addr)), (ValueMod (MI Addr:$addr))>;
-
-class Storea_pat<PatFrag Store, PatFrag Value, PatFrag Addr, InstHexagon MI>
- : Pat<(Store Value:$val, Addr:$addr), (MI Addr:$addr, Value:$val)>;
-
-class Stoream_pat<PatFrag Store, PatFrag Value, PatFrag Addr, PatFrag ValueMod,
- InstHexagon MI>
- : Pat<(Store Value:$val, Addr:$addr),
- (MI Addr:$addr, (ValueMod Value:$val))>;
-
-let AddedComplexity = 30 in {
- def: Storea_pat<truncstorei8, I32, addrga, S2_storerbabs>;
- def: Storea_pat<truncstorei16, I32, addrga, S2_storerhabs>;
- def: Storea_pat<store, I32, addrga, S2_storeriabs>;
- def: Storea_pat<store, I64, addrga, S2_storerdabs>;
-
- def: Stoream_pat<truncstorei8, I64, addrga, LoReg, S2_storerbabs>;
- def: Stoream_pat<truncstorei16, I64, addrga, LoReg, S2_storerhabs>;
- def: Stoream_pat<truncstorei32, I64, addrga, LoReg, S2_storeriabs>;
-}
-
-def: Storea_pat<SwapSt<atomic_store_8>, I32, addrgp, S2_storerbgp>;
-def: Storea_pat<SwapSt<atomic_store_16>, I32, addrgp, S2_storerhgp>;
-def: Storea_pat<SwapSt<atomic_store_32>, I32, addrgp, S2_storerigp>;
-def: Storea_pat<SwapSt<atomic_store_64>, I64, addrgp, S2_storerdgp>;
-
-let AddedComplexity = 100 in {
- def: Storea_pat<truncstorei8, I32, addrgp, S2_storerbgp>;
- def: Storea_pat<truncstorei16, I32, addrgp, S2_storerhgp>;
- def: Storea_pat<store, I32, addrgp, S2_storerigp>;
- def: Storea_pat<store, I64, addrgp, S2_storerdgp>;
-
- // Map from "i1 = constant<-1>; memw(CONST32(#foo)) = i1"
- // to "r0 = 1; memw(#foo) = r0"
- let AddedComplexity = 100 in
- def: Pat<(store (i1 -1), (HexagonCONST32_GP tglobaladdr:$global)),
- (S2_storerbgp tglobaladdr:$global, (A2_tfrsi 1))>;
-}
-
//===----------------------------------------------------------------------===//
// Template class for non predicated load instructions with
// absolute addressing mode.
@@ -3764,7 +2843,7 @@ class T_LoadAbsGP <string mnemonic, RegisterClass RC, Operand ImmOp,
class T_LoadAbs <string mnemonic, RegisterClass RC, Operand ImmOp,
bits<3> MajOp>
- : T_LoadAbsGP <mnemonic, RC, u32MustExt, MajOp>, AddrModeRel {
+ : T_LoadAbsGP <mnemonic, RC, u32_0MustExt, MajOp>, AddrModeRel {
string ImmOpStr = !cast<string>(ImmOp);
let opExtentBits = !if (!eq(ImmOpStr, "u16_3Imm"), 19,
@@ -3786,7 +2865,7 @@ let isPredicated = 1, hasSideEffects = 0, hasNewValue = 1, opExtentBits = 6,
opExtendable = 2 in
class T_LoadAbs_Pred <string mnemonic, RegisterClass RC, bits<3> MajOp,
bit isPredNot, bit isPredNew>
- : LDInst <(outs RC:$dst), (ins PredRegs:$src1, u32MustExt:$absaddr),
+ : LDInst <(outs RC:$dst), (ins PredRegs:$src1, u32_0MustExt:$absaddr),
!if(isPredNot, "if (!$src1", "if ($src1")#!if(isPredNew, ".new) ",
") ")#"$dst = "#mnemonic#"(#$absaddr)">, AddrModeRel {
bits<5> dst;
@@ -3826,7 +2905,7 @@ multiclass LD_Abs<string mnemonic, string CextOp, RegisterClass RC,
Operand ImmOp, bits<3> MajOp> {
let CextOpcode = CextOp, BaseOpcode = CextOp#_abs in {
let opExtendable = 1, isPredicable = 1 in
- def L4_#NAME#_abs: T_LoadAbs <mnemonic, RC, ImmOp, MajOp>;
+ def PS_#NAME#abs: T_LoadAbs <mnemonic, RC, ImmOp, MajOp>;
// Predicated
defm L4_p#NAME#t : LD_Abs_Pred<mnemonic, RC, MajOp, 0>;
@@ -3850,26 +2929,6 @@ defm loadri : LD_Abs<"memw", "LDriw", IntRegs, u16_2Imm, 0b100>;
let accessSize = DoubleWordAccess in
defm loadrd : LD_Abs<"memd", "LDrid", DoubleRegs, u16_3Imm, 0b110>;
-class LoadAbs_pats <PatFrag ldOp, InstHexagon MI, ValueType VT = i32>
- : Pat <(VT (ldOp (HexagonCONST32 tglobaladdr:$absaddr))),
- (VT (MI tglobaladdr:$absaddr))>;
-
-let AddedComplexity = 30 in {
- def: LoadAbs_pats <load, L4_loadri_abs>;
- def: LoadAbs_pats <zextloadi1, L4_loadrub_abs>;
- def: LoadAbs_pats <sextloadi8, L4_loadrb_abs>;
- def: LoadAbs_pats <extloadi8, L4_loadrub_abs>;
- def: LoadAbs_pats <zextloadi8, L4_loadrub_abs>;
- def: LoadAbs_pats <sextloadi16, L4_loadrh_abs>;
- def: LoadAbs_pats <extloadi16, L4_loadruh_abs>;
- def: LoadAbs_pats <zextloadi16, L4_loadruh_abs>;
- def: LoadAbs_pats <load, L4_loadrd_abs, i64>;
-}
-
-let AddedComplexity = 30 in
-def: Pat<(i64 (zextloadi1 (HexagonCONST32 tglobaladdr:$absaddr))),
- (Zext64 (L4_loadrub_abs tglobaladdr:$absaddr))>;
-
//===----------------------------------------------------------------------===//
// multiclass for load instructions with GP-relative addressing mode.
// Rx=mem[bhwd](##global)
@@ -3900,149 +2959,6 @@ def L2_loadrigp : T_LoadGP<"memw", "LDriw", IntRegs, u16_2Imm, 0b100>;
let accessSize = DoubleWordAccess in
def L2_loadrdgp : T_LoadGP<"memd", "LDrid", DoubleRegs, u16_3Imm, 0b110>;
-def: Loada_pat<atomic_load_8, i32, addrgp, L2_loadrubgp>;
-def: Loada_pat<atomic_load_16, i32, addrgp, L2_loadruhgp>;
-def: Loada_pat<atomic_load_32, i32, addrgp, L2_loadrigp>;
-def: Loada_pat<atomic_load_64, i64, addrgp, L2_loadrdgp>;
-
-// Map from Pd = load(globaladdress) -> Rd = memb(globaladdress), Pd = Rd
-def: Loadam_pat<load, i1, addrga, I32toI1, L4_loadrub_abs>;
-def: Loadam_pat<load, i1, addrgp, I32toI1, L2_loadrubgp>;
-
-def: Stoream_pat<store, I1, addrga, I1toI32, S2_storerbabs>;
-def: Stoream_pat<store, I1, addrgp, I1toI32, S2_storerbgp>;
-
-// Map from load(globaladdress) -> mem[u][bhwd](#foo)
-class LoadGP_pats <PatFrag ldOp, InstHexagon MI, ValueType VT = i32>
- : Pat <(VT (ldOp (HexagonCONST32_GP tglobaladdr:$global))),
- (VT (MI tglobaladdr:$global))>;
-
-let AddedComplexity = 100 in {
- def: LoadGP_pats <extloadi8, L2_loadrubgp>;
- def: LoadGP_pats <sextloadi8, L2_loadrbgp>;
- def: LoadGP_pats <zextloadi8, L2_loadrubgp>;
- def: LoadGP_pats <extloadi16, L2_loadruhgp>;
- def: LoadGP_pats <sextloadi16, L2_loadrhgp>;
- def: LoadGP_pats <zextloadi16, L2_loadruhgp>;
- def: LoadGP_pats <load, L2_loadrigp>;
- def: LoadGP_pats <load, L2_loadrdgp, i64>;
-}
-
-// When the Interprocedural Global Variable optimizer realizes that a certain
-// global variable takes only two constant values, it shrinks the global to
-// a boolean. Catch those loads here in the following 3 patterns.
-let AddedComplexity = 100 in {
- def: LoadGP_pats <extloadi1, L2_loadrubgp>;
- def: LoadGP_pats <zextloadi1, L2_loadrubgp>;
-}
-
-// Transfer global address into a register
-def: Pat<(HexagonCONST32 tglobaladdr:$Rs), (A2_tfrsi s16Ext:$Rs)>;
-def: Pat<(HexagonCONST32_GP tblockaddress:$Rs), (A2_tfrsi s16Ext:$Rs)>;
-def: Pat<(HexagonCONST32_GP tglobaladdr:$Rs), (A2_tfrsi s16Ext:$Rs)>;
-
-let AddedComplexity = 30 in {
- def: Storea_pat<truncstorei8, I32, u32ImmPred, S2_storerbabs>;
- def: Storea_pat<truncstorei16, I32, u32ImmPred, S2_storerhabs>;
- def: Storea_pat<store, I32, u32ImmPred, S2_storeriabs>;
-}
-
-let AddedComplexity = 30 in {
- def: Loada_pat<load, i32, u32ImmPred, L4_loadri_abs>;
- def: Loada_pat<sextloadi8, i32, u32ImmPred, L4_loadrb_abs>;
- def: Loada_pat<zextloadi8, i32, u32ImmPred, L4_loadrub_abs>;
- def: Loada_pat<sextloadi16, i32, u32ImmPred, L4_loadrh_abs>;
- def: Loada_pat<zextloadi16, i32, u32ImmPred, L4_loadruh_abs>;
-}
-
-// Indexed store word - global address.
-// memw(Rs+#u6:2)=#S8
-let AddedComplexity = 100 in
-defm: Storex_add_pat<store, addrga, u6_2ImmPred, S4_storeiri_io>;
-
-// Load from a global address that has only one use in the current basic block.
-let AddedComplexity = 100 in {
- def: Loada_pat<extloadi8, i32, addrga, L4_loadrub_abs>;
- def: Loada_pat<sextloadi8, i32, addrga, L4_loadrb_abs>;
- def: Loada_pat<zextloadi8, i32, addrga, L4_loadrub_abs>;
-
- def: Loada_pat<extloadi16, i32, addrga, L4_loadruh_abs>;
- def: Loada_pat<sextloadi16, i32, addrga, L4_loadrh_abs>;
- def: Loada_pat<zextloadi16, i32, addrga, L4_loadruh_abs>;
-
- def: Loada_pat<load, i32, addrga, L4_loadri_abs>;
- def: Loada_pat<load, i64, addrga, L4_loadrd_abs>;
-}
-
-// Store to a global address that has only one use in the current basic block.
-let AddedComplexity = 100 in {
- def: Storea_pat<truncstorei8, I32, addrga, S2_storerbabs>;
- def: Storea_pat<truncstorei16, I32, addrga, S2_storerhabs>;
- def: Storea_pat<store, I32, addrga, S2_storeriabs>;
- def: Storea_pat<store, I64, addrga, S2_storerdabs>;
-
- def: Stoream_pat<truncstorei32, I64, addrga, LoReg, S2_storeriabs>;
-}
-
-// i8/i16/i32 -> i64 loads
-// We need a complexity of 120 here to override preceding handling of
-// zextload.
-let AddedComplexity = 120 in {
- def: Loadam_pat<extloadi8, i64, addrga, Zext64, L4_loadrub_abs>;
- def: Loadam_pat<sextloadi8, i64, addrga, Sext64, L4_loadrb_abs>;
- def: Loadam_pat<zextloadi8, i64, addrga, Zext64, L4_loadrub_abs>;
-
- def: Loadam_pat<extloadi16, i64, addrga, Zext64, L4_loadruh_abs>;
- def: Loadam_pat<sextloadi16, i64, addrga, Sext64, L4_loadrh_abs>;
- def: Loadam_pat<zextloadi16, i64, addrga, Zext64, L4_loadruh_abs>;
-
- def: Loadam_pat<extloadi32, i64, addrga, Zext64, L4_loadri_abs>;
- def: Loadam_pat<sextloadi32, i64, addrga, Sext64, L4_loadri_abs>;
- def: Loadam_pat<zextloadi32, i64, addrga, Zext64, L4_loadri_abs>;
-}
-
-let AddedComplexity = 100 in {
- def: Loada_pat<extloadi8, i32, addrgp, L4_loadrub_abs>;
- def: Loada_pat<sextloadi8, i32, addrgp, L4_loadrb_abs>;
- def: Loada_pat<zextloadi8, i32, addrgp, L4_loadrub_abs>;
-
- def: Loada_pat<extloadi16, i32, addrgp, L4_loadruh_abs>;
- def: Loada_pat<sextloadi16, i32, addrgp, L4_loadrh_abs>;
- def: Loada_pat<zextloadi16, i32, addrgp, L4_loadruh_abs>;
-
- def: Loada_pat<load, i32, addrgp, L4_loadri_abs>;
- def: Loada_pat<load, i64, addrgp, L4_loadrd_abs>;
-}
-
-let AddedComplexity = 100 in {
- def: Storea_pat<truncstorei8, I32, addrgp, S2_storerbabs>;
- def: Storea_pat<truncstorei16, I32, addrgp, S2_storerhabs>;
- def: Storea_pat<store, I32, addrgp, S2_storeriabs>;
- def: Storea_pat<store, I64, addrgp, S2_storerdabs>;
-}
-
-def: Loada_pat<atomic_load_8, i32, addrgp, L4_loadrub_abs>;
-def: Loada_pat<atomic_load_16, i32, addrgp, L4_loadruh_abs>;
-def: Loada_pat<atomic_load_32, i32, addrgp, L4_loadri_abs>;
-def: Loada_pat<atomic_load_64, i64, addrgp, L4_loadrd_abs>;
-
-def: Storea_pat<SwapSt<atomic_store_8>, I32, addrgp, S2_storerbabs>;
-def: Storea_pat<SwapSt<atomic_store_16>, I32, addrgp, S2_storerhabs>;
-def: Storea_pat<SwapSt<atomic_store_32>, I32, addrgp, S2_storeriabs>;
-def: Storea_pat<SwapSt<atomic_store_64>, I64, addrgp, S2_storerdabs>;
-
-let Constraints = "@earlyclobber $dst" in
-def Insert4 : PseudoM<(outs DoubleRegs:$dst), (ins IntRegs:$a, IntRegs:$b,
- IntRegs:$c, IntRegs:$d),
- ".error \"Should never try to emit Insert4\"",
- [(set (i64 DoubleRegs:$dst),
- (or (or (or (shl (i64 (zext (i32 (and (i32 IntRegs:$b), (i32 65535))))),
- (i32 16)),
- (i64 (zext (i32 (and (i32 IntRegs:$a), (i32 65535)))))),
- (shl (i64 (anyext (i32 (and (i32 IntRegs:$c), (i32 65535))))),
- (i32 32))),
- (shl (i64 (anyext (i32 IntRegs:$d))), (i32 48))))]>;
-
//===----------------------------------------------------------------------===//
// :raw for of boundscheck:hi:lo insns
//===----------------------------------------------------------------------===//
@@ -4111,20 +3027,12 @@ def A4_tlbmatch : ALU64Inst<(outs PredRegs:$Pd),
let Inst{1-0} = Pd;
}
-// We need custom lowering of ISD::PREFETCH into HexagonISD::DCFETCH
-// because the SDNode ISD::PREFETCH has properties MayLoad and MayStore.
-// We don't really want either one here.
-def SDTHexagonDCFETCH : SDTypeProfile<0, 2, [SDTCisPtrTy<0>,SDTCisInt<1>]>;
-def HexagonDCFETCH : SDNode<"HexagonISD::DCFETCH", SDTHexagonDCFETCH,
- [SDNPHasChain]>;
-
// Use LD0Inst for dcfetch, but set "mayLoad" to 0 because this doesn't
// really do a load.
let hasSideEffects = 1, mayLoad = 0 in
def Y2_dcfetchbo : LD0Inst<(outs), (ins IntRegs:$Rs, u11_3Imm:$u11_3),
"dcfetch($Rs + #$u11_3)",
- [(HexagonDCFETCH IntRegs:$Rs, u11_3ImmPred:$u11_3)],
- "", LD_tc_ld_SLOT0> {
+ [], "", LD_tc_ld_SLOT0> {
bits<5> Rs;
bits<14> u11_3;
@@ -4136,9 +3044,6 @@ def Y2_dcfetchbo : LD0Inst<(outs), (ins IntRegs:$Rs, u11_3Imm:$u11_3),
}
-def: Pat<(HexagonDCFETCH (i32 (add IntRegs:$Rs, u11_3ImmPred:$u11_3)), (i32 0)),
- (Y2_dcfetchbo IntRegs:$Rs, u11_3ImmPred:$u11_3)>;
-
//===----------------------------------------------------------------------===//
// Compound instructions
//===----------------------------------------------------------------------===//
@@ -4248,7 +3153,7 @@ let isBranch = 1, hasSideEffects = 0, isExtentSigned = 1,
isPredicated = 1, isPredicatedNew = 1, isExtendable = 1, opExtentBits = 11,
opExtentAlign = 2, opExtendable = 2, isTerminator = 1 in
class CJInst_RU5<string px, string op, bit np, string tnt>
- : InstHexagon<(outs), (ins IntRegs:$Rs, u5Imm:$U5, brtarget:$r9_2),
+ : InstHexagon<(outs), (ins IntRegs:$Rs, u5_0Imm:$U5, brtarget:$r9_2),
""#px#" = cmp."#op#"($Rs, #$U5); if ("
#!if(np, "!","")#""#px#".new) jump:"#tnt#" $r9_2",
[], "", COMPOUND_CJ_ARCHDEPSLOT, TypeCOMPOUND>, OpcodeHexagon {
@@ -4300,11 +3205,11 @@ defm gtu : T_pnp_CJInst_RU5<"gtu">;
let isBranch = 1, hasSideEffects = 0, isExtentSigned = 1,
isPredicated = 1, isPredicatedFalse = 1, isPredicatedNew = 1,
- isExtendable = 1, opExtentBits = 11, opExtentAlign = 2, opExtendable = 1,
+ isExtendable = 1, opExtentBits = 11, opExtentAlign = 2, opExtendable = 2,
isTerminator = 1 in
class CJInst_Rn1<string px, string op, bit np, string tnt>
- : InstHexagon<(outs), (ins IntRegs:$Rs, brtarget:$r9_2),
- ""#px#" = cmp."#op#"($Rs,#-1); if ("
+ : InstHexagon<(outs), (ins IntRegs:$Rs, n1Const:$n1, brtarget:$r9_2),
+ ""#px#" = cmp."#op#"($Rs,#$n1); if ("
#!if(np, "!","")#""#px#".new) jump:"#tnt#" $r9_2",
[], "", COMPOUND_CJ_ARCHDEPSLOT, TypeCOMPOUND>, OpcodeHexagon {
bits<4> Rs;
@@ -4357,7 +3262,7 @@ let Defs = [PC], isBranch = 1, hasSideEffects = 0, hasNewValue = 1,
opExtentAlign = 2, opExtendable = 2 in
def J4_jumpseti: CJInst_JMPSET <
(outs IntRegs:$Rd),
- (ins u6Imm:$U6, brtarget:$r9_2),
+ (ins u6_0Imm:$U6, brtarget:$r9_2),
"$Rd = #$U6 ; jump $r9_2"> {
bits<4> Rd;
bits<6> U6;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV5.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV5.td
index 823961f..cd19b69 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV5.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV5.td
@@ -43,10 +43,7 @@ let Predicates = [HasV5T] in {
def A5_vaddhubs: T_S3op_1 <"vaddhub", IntRegs, 0b01, 0b001, 0, 1>;
}
-def S2_asr_i_p_rnd : S_2OpInstImm<"asr", 0b110, 0b111, u6Imm,
- [(set I64:$dst,
- (sra (i64 (add (i64 (sra I64:$src1, u6ImmPred:$src2)), 1)),
- (i32 1)))], 1>,
+def S2_asr_i_p_rnd : S_2OpInstImm<"asr", 0b110, 0b111, u6_0Imm, [], 1>,
Requires<[HasV5T]> {
bits<6> src2;
let Inst{13-8} = src2;
@@ -54,7 +51,7 @@ def S2_asr_i_p_rnd : S_2OpInstImm<"asr", 0b110, 0b111, u6Imm,
let isAsmParserOnly = 1 in
def S2_asr_i_p_rnd_goodsyntax
- : MInst<(outs DoubleRegs:$dst), (ins DoubleRegs:$src1, u6Imm:$src2),
+ : MInst<(outs DoubleRegs:$dst), (ins DoubleRegs:$src1, u6_0Imm:$src2),
"$dst = asrrnd($src1, #$src2)">;
def C4_fastcorner9 : T_LOGICAL_2OP<"fastcorner9", 0b000, 0, 0>,
@@ -67,66 +64,9 @@ def C4_fastcorner9_not : T_LOGICAL_2OP<"!fastcorner9", 0b000, 0, 0>,
let Inst{20,13,7,4} = 0b1111;
}
-def SDTHexagonFCONST32 : SDTypeProfile<1, 1, [SDTCisVT<0, f32>,
- SDTCisPtrTy<1>]>;
-def HexagonFCONST32 : SDNode<"HexagonISD::FCONST32", SDTHexagonFCONST32>;
-
-let isReMaterializable = 1, isMoveImm = 1, isAsmParserOnly = 1 in
-def FCONST32_nsdata : LDInst<(outs IntRegs:$dst), (ins globaladdress:$global),
- "$dst = CONST32(#$global)",
- [(set F32:$dst,
- (HexagonFCONST32 tglobaladdr:$global))]>,
- Requires<[HasV5T]>;
-
-let isReMaterializable = 1, isMoveImm = 1, isAsmParserOnly = 1 in
-def CONST64_Float_Real : LDInst<(outs DoubleRegs:$dst), (ins f64imm:$src1),
- "$dst = CONST64(#$src1)",
- [(set F64:$dst, fpimm:$src1)]>,
- Requires<[HasV5T]>;
-
-let isReMaterializable = 1, isMoveImm = 1, isAsmParserOnly = 1 in
-def CONST32_Float_Real : LDInst<(outs IntRegs:$dst), (ins f32imm:$src1),
- "$dst = CONST32(#$src1)",
- [(set F32:$dst, fpimm:$src1)]>,
- Requires<[HasV5T]>;
-
-// Transfer immediate float.
-// Only works with single precision fp value.
-// For double precision, use CONST64_float_real, as 64bit transfer
-// can only hold 40-bit values - 32 from const ext + 8 bit immediate.
-// Make sure that complexity is more than the CONST32 pattern in
-// HexagonInstrInfo.td patterns.
-let isExtended = 1, opExtendable = 1, isMoveImm = 1, isReMaterializable = 1,
- isPredicable = 1, AddedComplexity = 30, validSubTargets = HasV5SubT,
- isCodeGenOnly = 1, isPseudo = 1 in
-def TFRI_f : ALU32_ri<(outs IntRegs:$dst), (ins f32Ext:$src1),
- "$dst = #$src1",
- [(set F32:$dst, fpimm:$src1)]>,
- Requires<[HasV5T]>;
-
-let isExtended = 1, opExtendable = 2, isPredicated = 1, hasSideEffects = 0,
- validSubTargets = HasV5SubT, isCodeGenOnly = 1, isPseudo = 1 in
-def TFRI_cPt_f : ALU32_ri<(outs IntRegs:$dst),
- (ins PredRegs:$src1, f32Ext:$src2),
- "if ($src1) $dst = #$src2", []>,
- Requires<[HasV5T]>;
-
-let isExtended = 1, opExtendable = 2, isPredicated = 1, isPredicatedFalse = 1,
- hasSideEffects = 0, validSubTargets = HasV5SubT, isPseudo = 1 in
-def TFRI_cNotPt_f : ALU32_ri<(outs IntRegs:$dst),
- (ins PredRegs:$src1, f32Ext:$src2),
- "if (!$src1) $dst = #$src2", []>,
- Requires<[HasV5T]>;
-
-def SDTHexagonI32I64: SDTypeProfile<1, 1, [SDTCisVT<0, i32>,
- SDTCisVT<1, i64>]>;
-
-def HexagonPOPCOUNT: SDNode<"HexagonISD::POPCOUNT", SDTHexagonI32I64>;
-
let hasNewValue = 1, validSubTargets = HasV5SubT in
def S5_popcountp : ALU64_rr<(outs IntRegs:$Rd), (ins DoubleRegs:$Rss),
- "$Rd = popcount($Rss)",
- [(set I32:$Rd, (HexagonPOPCOUNT I64:$Rss))], "", S_2op_tc_2_SLOT23>,
+ "$Rd = popcount($Rss)", [], "", S_2op_tc_2_SLOT23>,
Requires<[HasV5T]> {
bits<5> Rd;
bits<5> Rss;
@@ -139,14 +79,6 @@ def S5_popcountp : ALU64_rr<(outs IntRegs:$Rd), (ins DoubleRegs:$Rss),
let Inst{20-16} = Rss;
}
-defm: Loadx_pat<load, f32, s30_2ImmPred, L2_loadri_io>;
-defm: Loadx_pat<load, f64, s29_3ImmPred, L2_loadrd_io>;
-
-defm: Storex_pat<store, F32, s30_2ImmPred, S2_storeri_io>;
-defm: Storex_pat<store, F64, s29_3ImmPred, S2_storerd_io>;
-def: Storex_simple_pat<store, F32, S2_storeri_io>;
-def: Storex_simple_pat<store, F64, S2_storerd_io>;
-
let isFP = 1, hasNewValue = 1, opNewValue = 0 in
class T_MInstFloat <string mnemonic, bits<3> MajOp, bits<3> MinOp>
: MInst<(outs IntRegs:$Rd),
@@ -176,44 +108,19 @@ let isCommutable = 1 in {
def F2_sfsub : T_MInstFloat < "sfsub", 0b000, 0b001>;
-def: Pat<(f32 (fadd F32:$src1, F32:$src2)),
- (F2_sfadd F32:$src1, F32:$src2)>;
-
-def: Pat<(f32 (fsub F32:$src1, F32:$src2)),
- (F2_sfsub F32:$src1, F32:$src2)>;
-
-def: Pat<(f32 (fmul F32:$src1, F32:$src2)),
- (F2_sfmpy F32:$src1, F32:$src2)>;
-
let Itinerary = M_tc_3x_SLOT23 in {
def F2_sfmax : T_MInstFloat < "sfmax", 0b100, 0b000>;
def F2_sfmin : T_MInstFloat < "sfmin", 0b100, 0b001>;
}
-let AddedComplexity = 100, Predicates = [HasV5T] in {
- def: Pat<(f32 (select (i1 (setolt F32:$src1, F32:$src2)),
- F32:$src1, F32:$src2)),
- (F2_sfmin F32:$src1, F32:$src2)>;
-
- def: Pat<(f32 (select (i1 (setogt F32:$src1, F32:$src2)),
- F32:$src2, F32:$src1)),
- (F2_sfmin F32:$src1, F32:$src2)>;
-
- def: Pat<(f32 (select (i1 (setogt F32:$src1, F32:$src2)),
- F32:$src1, F32:$src2)),
- (F2_sfmax F32:$src1, F32:$src2)>;
-
- def: Pat<(f32 (select (i1 (setolt F32:$src1, F32:$src2)),
- F32:$src2, F32:$src1)),
- (F2_sfmax F32:$src1, F32:$src2)>;
-}
-
+let Itinerary = M_tc_3or4x_SLOT23 in {
def F2_sffixupn : T_MInstFloat < "sffixupn", 0b110, 0b000>;
def F2_sffixupd : T_MInstFloat < "sffixupd", 0b110, 0b001>;
+}
// F2_sfrecipa: Reciprocal approximation for division.
-let isPredicateLate = 1, isFP = 1,
-hasSideEffects = 0, hasNewValue = 1 in
+let Uses = [USR], isPredicateLate = 1, isFP = 1,
+ hasSideEffects = 0, hasNewValue = 1, Itinerary = M_tc_3or4x_SLOT23 in
def F2_sfrecipa: MInst <
(outs IntRegs:$Rd, PredRegs:$Pe),
(ins IntRegs:$Rs, IntRegs:$Rt),
@@ -235,7 +142,7 @@ def F2_sfrecipa: MInst <
}
// F2_dfcmpeq: Floating point compare for equal.
-let isCompare = 1, isFP = 1 in
+let Uses = [USR], isCompare = 1, isFP = 1 in
class T_fcmp <string mnemonic, RegisterClass RC, bits<3> MinOp,
list<dag> pattern = [] >
: ALU64Inst <(outs PredRegs:$dst), (ins RC:$src1, RC:$src2),
@@ -256,15 +163,13 @@ class T_fcmp <string mnemonic, RegisterClass RC, bits<3> MinOp,
}
class T_fcmp64 <string mnemonic, PatFrag OpNode, bits<3> MinOp>
- : T_fcmp <mnemonic, DoubleRegs, MinOp,
- [(set I1:$dst, (OpNode F64:$src1, F64:$src2))]> {
+ : T_fcmp <mnemonic, DoubleRegs, MinOp, []> {
let IClass = 0b1101;
let Inst{27-21} = 0b0010111;
}
class T_fcmp32 <string mnemonic, PatFrag OpNode, bits<3> MinOp>
- : T_fcmp <mnemonic, IntRegs, MinOp,
- [(set I1:$dst, (OpNode F32:$src1, F32:$src2))]> {
+ : T_fcmp <mnemonic, IntRegs, MinOp, []> {
let IClass = 0b1100;
let Inst{27-21} = 0b0111111;
}
@@ -279,259 +184,12 @@ def F2_sfcmpuo : T_fcmp32<"sfcmp.uo", setuo, 0b001>;
def F2_sfcmpeq : T_fcmp32<"sfcmp.eq", setoeq, 0b011>;
def F2_sfcmpgt : T_fcmp32<"sfcmp.gt", setogt, 0b100>;
-//===----------------------------------------------------------------------===//
-// Multiclass to define 'Def Pats' for ordered gt, ge, eq operations.
-//===----------------------------------------------------------------------===//
-
-let Predicates = [HasV5T] in
-multiclass T_fcmp_pats<PatFrag cmpOp, InstHexagon IntMI, InstHexagon DoubleMI> {
- // IntRegs
- def: Pat<(i1 (cmpOp F32:$src1, F32:$src2)),
- (IntMI F32:$src1, F32:$src2)>;
- // DoubleRegs
- def: Pat<(i1 (cmpOp F64:$src1, F64:$src2)),
- (DoubleMI F64:$src1, F64:$src2)>;
-}
-
-defm : T_fcmp_pats <seteq, F2_sfcmpeq, F2_dfcmpeq>;
-defm : T_fcmp_pats <setgt, F2_sfcmpgt, F2_dfcmpgt>;
-defm : T_fcmp_pats <setge, F2_sfcmpge, F2_dfcmpge>;
-
-//===----------------------------------------------------------------------===//
-// Multiclass to define 'Def Pats' for unordered gt, ge, eq operations.
-//===----------------------------------------------------------------------===//
-let Predicates = [HasV5T] in
-multiclass unord_Pats <PatFrag cmpOp, InstHexagon IntMI, InstHexagon DoubleMI> {
- // IntRegs
- def: Pat<(i1 (cmpOp F32:$src1, F32:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
- (IntMI F32:$src1, F32:$src2))>;
-
- // DoubleRegs
- def: Pat<(i1 (cmpOp F64:$src1, F64:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
- (DoubleMI F64:$src1, F64:$src2))>;
-}
-
-defm : unord_Pats <setuge, F2_sfcmpge, F2_dfcmpge>;
-defm : unord_Pats <setugt, F2_sfcmpgt, F2_dfcmpgt>;
-defm : unord_Pats <setueq, F2_sfcmpeq, F2_dfcmpeq>;
-
-//===----------------------------------------------------------------------===//
-// Multiclass to define 'Def Pats' for the following dags:
-// seteq(setoeq(op1, op2), 0) -> not(setoeq(op1, op2))
-// seteq(setoeq(op1, op2), 1) -> setoeq(op1, op2)
-// setne(setoeq(op1, op2), 0) -> setoeq(op1, op2)
-// setne(setoeq(op1, op2), 1) -> not(setoeq(op1, op2))
-//===----------------------------------------------------------------------===//
-let Predicates = [HasV5T] in
-multiclass eq_ordgePats <PatFrag cmpOp, InstHexagon IntMI,
- InstHexagon DoubleMI> {
- // IntRegs
- def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
- (C2_not (IntMI F32:$src1, F32:$src2))>;
- def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
- (IntMI F32:$src1, F32:$src2)>;
- def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
- (IntMI F32:$src1, F32:$src2)>;
- def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
- (C2_not (IntMI F32:$src1, F32:$src2))>;
-
- // DoubleRegs
- def : Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
- (C2_not (DoubleMI F64:$src1, F64:$src2))>;
- def : Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 1)),
- (DoubleMI F64:$src1, F64:$src2)>;
- def : Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
- (DoubleMI F64:$src1, F64:$src2)>;
- def : Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 1)),
- (C2_not (DoubleMI F64:$src1, F64:$src2))>;
-}
-
-defm : eq_ordgePats<setoeq, F2_sfcmpeq, F2_dfcmpeq>;
-defm : eq_ordgePats<setoge, F2_sfcmpge, F2_dfcmpge>;
-defm : eq_ordgePats<setogt, F2_sfcmpgt, F2_dfcmpgt>;
-
-//===----------------------------------------------------------------------===//
-// Multiclass to define 'Def Pats' for the following dags:
-// seteq(setolt(op1, op2), 0) -> not(setogt(op2, op1))
-// seteq(setolt(op1, op2), 1) -> setogt(op2, op1)
-// setne(setolt(op1, op2), 0) -> setogt(op2, op1)
-// setne(setolt(op1, op2), 1) -> not(setogt(op2, op1))
-//===----------------------------------------------------------------------===//
-let Predicates = [HasV5T] in
-multiclass eq_ordltPats <PatFrag cmpOp, InstHexagon IntMI,
- InstHexagon DoubleMI> {
- // IntRegs
- def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
- (C2_not (IntMI F32:$src2, F32:$src1))>;
- def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
- (IntMI F32:$src2, F32:$src1)>;
- def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
- (IntMI F32:$src2, F32:$src1)>;
- def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
- (C2_not (IntMI F32:$src2, F32:$src1))>;
-
- // DoubleRegs
- def: Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
- (C2_not (DoubleMI F64:$src2, F64:$src1))>;
- def: Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 1)),
- (DoubleMI F64:$src2, F64:$src1)>;
- def: Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
- (DoubleMI F64:$src2, F64:$src1)>;
- def: Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
- (C2_not (DoubleMI F64:$src2, F64:$src1))>;
-}
-
-defm : eq_ordltPats<setole, F2_sfcmpge, F2_dfcmpge>;
-defm : eq_ordltPats<setolt, F2_sfcmpgt, F2_dfcmpgt>;
-
-
-// o. seto inverse of setuo. http://llvm.org/docs/LangRef.html#i_fcmp
-let Predicates = [HasV5T] in {
- def: Pat<(i1 (seto F32:$src1, F32:$src2)),
- (C2_not (F2_sfcmpuo F32:$src2, F32:$src1))>;
- def: Pat<(i1 (seto F32:$src1, fpimm:$src2)),
- (C2_not (F2_sfcmpuo (TFRI_f fpimm:$src2), F32:$src1))>;
- def: Pat<(i1 (seto F64:$src1, F64:$src2)),
- (C2_not (F2_dfcmpuo F64:$src2, F64:$src1))>;
- def: Pat<(i1 (seto F64:$src1, fpimm:$src2)),
- (C2_not (F2_dfcmpuo (CONST64_Float_Real fpimm:$src2), F64:$src1))>;
-}
-
-// Ordered lt.
-let Predicates = [HasV5T] in {
- def: Pat<(i1 (setolt F32:$src1, F32:$src2)),
- (F2_sfcmpgt F32:$src2, F32:$src1)>;
- def: Pat<(i1 (setolt F32:$src1, fpimm:$src2)),
- (F2_sfcmpgt (f32 (TFRI_f fpimm:$src2)), F32:$src1)>;
- def: Pat<(i1 (setolt F64:$src1, F64:$src2)),
- (F2_dfcmpgt F64:$src2, F64:$src1)>;
- def: Pat<(i1 (setolt F64:$src1, fpimm:$src2)),
- (F2_dfcmpgt (CONST64_Float_Real fpimm:$src2), F64:$src1)>;
-}
-
-// Unordered lt.
-let Predicates = [HasV5T] in {
- def: Pat<(i1 (setult F32:$src1, F32:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
- (F2_sfcmpgt F32:$src2, F32:$src1))>;
- def: Pat<(i1 (setult F32:$src1, fpimm:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, (TFRI_f fpimm:$src2)),
- (F2_sfcmpgt (TFRI_f fpimm:$src2), F32:$src1))>;
- def: Pat<(i1 (setult F64:$src1, F64:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
- (F2_dfcmpgt F64:$src2, F64:$src1))>;
- def: Pat<(i1 (setult F64:$src1, fpimm:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, (CONST64_Float_Real fpimm:$src2)),
- (F2_dfcmpgt (CONST64_Float_Real fpimm:$src2), F64:$src1))>;
-}
-
-// Ordered le.
-let Predicates = [HasV5T] in {
- // rs <= rt -> rt >= rs.
- def: Pat<(i1 (setole F32:$src1, F32:$src2)),
- (F2_sfcmpge F32:$src2, F32:$src1)>;
- def: Pat<(i1 (setole F32:$src1, fpimm:$src2)),
- (F2_sfcmpge (TFRI_f fpimm:$src2), F32:$src1)>;
-
- // Rss <= Rtt -> Rtt >= Rss.
- def: Pat<(i1 (setole F64:$src1, F64:$src2)),
- (F2_dfcmpge F64:$src2, F64:$src1)>;
- def: Pat<(i1 (setole F64:$src1, fpimm:$src2)),
- (F2_dfcmpge (CONST64_Float_Real fpimm:$src2), F64:$src1)>;
-}
-
-// Unordered le.
-let Predicates = [HasV5T] in {
-// rs <= rt -> rt >= rs.
- def: Pat<(i1 (setule F32:$src1, F32:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
- (F2_sfcmpge F32:$src2, F32:$src1))>;
- def: Pat<(i1 (setule F32:$src1, fpimm:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, (TFRI_f fpimm:$src2)),
- (F2_sfcmpge (TFRI_f fpimm:$src2), F32:$src1))>;
- def: Pat<(i1 (setule F64:$src1, F64:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
- (F2_dfcmpge F64:$src2, F64:$src1))>;
- def: Pat<(i1 (setule F64:$src1, fpimm:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, (CONST64_Float_Real fpimm:$src2)),
- (F2_dfcmpge (CONST64_Float_Real fpimm:$src2), F64:$src1))>;
-}
-
-// Ordered ne.
-let Predicates = [HasV5T] in {
- def: Pat<(i1 (setone F32:$src1, F32:$src2)),
- (C2_not (F2_sfcmpeq F32:$src1, F32:$src2))>;
- def: Pat<(i1 (setone F64:$src1, F64:$src2)),
- (C2_not (F2_dfcmpeq F64:$src1, F64:$src2))>;
- def: Pat<(i1 (setone F32:$src1, fpimm:$src2)),
- (C2_not (F2_sfcmpeq F32:$src1, (TFRI_f fpimm:$src2)))>;
- def: Pat<(i1 (setone F64:$src1, fpimm:$src2)),
- (C2_not (F2_dfcmpeq F64:$src1, (CONST64_Float_Real fpimm:$src2)))>;
-}
-
-// Unordered ne.
-let Predicates = [HasV5T] in {
- def: Pat<(i1 (setune F32:$src1, F32:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
- (C2_not (F2_sfcmpeq F32:$src1, F32:$src2)))>;
- def: Pat<(i1 (setune F64:$src1, F64:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
- (C2_not (F2_dfcmpeq F64:$src1, F64:$src2)))>;
- def: Pat<(i1 (setune F32:$src1, fpimm:$src2)),
- (C2_or (F2_sfcmpuo F32:$src1, (TFRI_f fpimm:$src2)),
- (C2_not (F2_sfcmpeq F32:$src1, (TFRI_f fpimm:$src2))))>;
- def: Pat<(i1 (setune F64:$src1, fpimm:$src2)),
- (C2_or (F2_dfcmpuo F64:$src1, (CONST64_Float_Real fpimm:$src2)),
- (C2_not (F2_dfcmpeq F64:$src1,
- (CONST64_Float_Real fpimm:$src2))))>;
-}
-
-// Besides set[o|u][comparions], we also need set[comparisons].
-let Predicates = [HasV5T] in {
- // lt.
- def: Pat<(i1 (setlt F32:$src1, F32:$src2)),
- (F2_sfcmpgt F32:$src2, F32:$src1)>;
- def: Pat<(i1 (setlt F32:$src1, fpimm:$src2)),
- (F2_sfcmpgt (TFRI_f fpimm:$src2), F32:$src1)>;
- def: Pat<(i1 (setlt F64:$src1, F64:$src2)),
- (F2_dfcmpgt F64:$src2, F64:$src1)>;
- def: Pat<(i1 (setlt F64:$src1, fpimm:$src2)),
- (F2_dfcmpgt (CONST64_Float_Real fpimm:$src2), F64:$src1)>;
-
- // le.
- // rs <= rt -> rt >= rs.
- def: Pat<(i1 (setle F32:$src1, F32:$src2)),
- (F2_sfcmpge F32:$src2, F32:$src1)>;
- def: Pat<(i1 (setle F32:$src1, fpimm:$src2)),
- (F2_sfcmpge (TFRI_f fpimm:$src2), F32:$src1)>;
-
- // Rss <= Rtt -> Rtt >= Rss.
- def: Pat<(i1 (setle F64:$src1, F64:$src2)),
- (F2_dfcmpge F64:$src2, F64:$src1)>;
- def: Pat<(i1 (setle F64:$src1, fpimm:$src2)),
- (F2_dfcmpge (CONST64_Float_Real fpimm:$src2), F64:$src1)>;
-
- // ne.
- def: Pat<(i1 (setne F32:$src1, F32:$src2)),
- (C2_not (F2_sfcmpeq F32:$src1, F32:$src2))>;
- def: Pat<(i1 (setne F64:$src1, F64:$src2)),
- (C2_not (F2_dfcmpeq F64:$src1, F64:$src2))>;
- def: Pat<(i1 (setne F32:$src1, fpimm:$src2)),
- (C2_not (F2_sfcmpeq F32:$src1, (TFRI_f fpimm:$src2)))>;
- def: Pat<(i1 (setne F64:$src1, fpimm:$src2)),
- (C2_not (F2_dfcmpeq F64:$src1, (CONST64_Float_Real fpimm:$src2)))>;
-}
-
// F2 convert template classes:
-let isFP = 1 in
+let Uses = [USR], isFP = 1 in
class F2_RDD_RSS_CONVERT<string mnemonic, bits<3> MinOp,
- SDNode Op, PatLeaf RCOut, PatLeaf RCIn,
string chop ="">
: SInst <(outs DoubleRegs:$Rdd), (ins DoubleRegs:$Rss),
- "$Rdd = "#mnemonic#"($Rss)"#chop,
- [(set RCOut:$Rdd, (Op RCIn:$Rss))], "",
+ "$Rdd = "#mnemonic#"($Rss)"#chop, [], "",
S_2op_tc_3or4x_SLOT23> {
bits<5> Rdd;
bits<5> Rss;
@@ -544,13 +202,11 @@ class F2_RDD_RSS_CONVERT<string mnemonic, bits<3> MinOp,
let Inst{4-0} = Rdd;
}
-let isFP = 1 in
+let Uses = [USR], isFP = 1 in
class F2_RDD_RS_CONVERT<string mnemonic, bits<3> MinOp,
- SDNode Op, PatLeaf RCOut, PatLeaf RCIn,
string chop ="">
: SInst <(outs DoubleRegs:$Rdd), (ins IntRegs:$Rs),
- "$Rdd = "#mnemonic#"($Rs)"#chop,
- [(set RCOut:$Rdd, (Op RCIn:$Rs))], "",
+ "$Rdd = "#mnemonic#"($Rs)"#chop, [], "",
S_2op_tc_3or4x_SLOT23> {
bits<5> Rdd;
bits<5> Rs;
@@ -563,13 +219,11 @@ class F2_RDD_RS_CONVERT<string mnemonic, bits<3> MinOp,
let Inst{4-0} = Rdd;
}
-let isFP = 1, hasNewValue = 1 in
+let Uses = [USR], isFP = 1, hasNewValue = 1 in
class F2_RD_RSS_CONVERT<string mnemonic, bits<3> MinOp,
- SDNode Op, PatLeaf RCOut, PatLeaf RCIn,
string chop ="">
: SInst <(outs IntRegs:$Rd), (ins DoubleRegs:$Rss),
- "$Rd = "#mnemonic#"($Rss)"#chop,
- [(set RCOut:$Rd, (Op RCIn:$Rss))], "",
+ "$Rd = "#mnemonic#"($Rss)"#chop, [], "",
S_2op_tc_3or4x_SLOT23> {
bits<5> Rd;
bits<5> Rss;
@@ -583,13 +237,11 @@ class F2_RD_RSS_CONVERT<string mnemonic, bits<3> MinOp,
let Inst{4-0} = Rd;
}
-let isFP = 1, hasNewValue = 1 in
+let Uses = [USR], isFP = 1, hasNewValue = 1 in
class F2_RD_RS_CONVERT<string mnemonic, bits<3> MajOp, bits<3> MinOp,
- SDNode Op, PatLeaf RCOut, PatLeaf RCIn,
string chop ="">
: SInst <(outs IntRegs:$Rd), (ins IntRegs:$Rs),
- "$Rd = "#mnemonic#"($Rs)"#chop,
- [(set RCOut:$Rd, (Op RCIn:$Rs))], "",
+ "$Rd = "#mnemonic#"($Rs)"#chop, [], "",
S_2op_tc_3or4x_SLOT23> {
bits<5> Rd;
bits<5> Rs;
@@ -604,70 +256,45 @@ class F2_RD_RS_CONVERT<string mnemonic, bits<3> MajOp, bits<3> MinOp,
}
// Convert single precision to double precision and vice-versa.
-def F2_conv_sf2df : F2_RDD_RS_CONVERT <"convert_sf2df", 0b000,
- fextend, F64, F32>;
-
-def F2_conv_df2sf : F2_RD_RSS_CONVERT <"convert_df2sf", 0b000,
- fround, F32, F64>;
+def F2_conv_sf2df : F2_RDD_RS_CONVERT <"convert_sf2df", 0b000>;
+def F2_conv_df2sf : F2_RD_RSS_CONVERT <"convert_df2sf", 0b000>;
// Convert Integer to Floating Point.
-def F2_conv_d2sf : F2_RD_RSS_CONVERT <"convert_d2sf", 0b010,
- sint_to_fp, F32, I64>;
-def F2_conv_ud2sf : F2_RD_RSS_CONVERT <"convert_ud2sf", 0b001,
- uint_to_fp, F32, I64>;
-def F2_conv_uw2sf : F2_RD_RS_CONVERT <"convert_uw2sf", 0b001, 0b000,
- uint_to_fp, F32, I32>;
-def F2_conv_w2sf : F2_RD_RS_CONVERT <"convert_w2sf", 0b010, 0b000,
- sint_to_fp, F32, I32>;
-def F2_conv_d2df : F2_RDD_RSS_CONVERT <"convert_d2df", 0b011,
- sint_to_fp, F64, I64>;
-def F2_conv_ud2df : F2_RDD_RSS_CONVERT <"convert_ud2df", 0b010,
- uint_to_fp, F64, I64>;
-def F2_conv_uw2df : F2_RDD_RS_CONVERT <"convert_uw2df", 0b001,
- uint_to_fp, F64, I32>;
-def F2_conv_w2df : F2_RDD_RS_CONVERT <"convert_w2df", 0b010,
- sint_to_fp, F64, I32>;
-
-// Convert Floating Point to Integer - default.
-def F2_conv_df2uw_chop : F2_RD_RSS_CONVERT <"convert_df2uw", 0b101,
- fp_to_uint, I32, F64, ":chop">;
-def F2_conv_df2w_chop : F2_RD_RSS_CONVERT <"convert_df2w", 0b111,
- fp_to_sint, I32, F64, ":chop">;
+def F2_conv_d2sf : F2_RD_RSS_CONVERT <"convert_d2sf", 0b010>;
+def F2_conv_ud2sf : F2_RD_RSS_CONVERT <"convert_ud2sf", 0b001>;
+def F2_conv_uw2sf : F2_RD_RS_CONVERT <"convert_uw2sf", 0b001, 0b000>;
+def F2_conv_w2sf : F2_RD_RS_CONVERT <"convert_w2sf", 0b010, 0b000>;
+def F2_conv_d2df : F2_RDD_RSS_CONVERT <"convert_d2df", 0b011>;
+def F2_conv_ud2df : F2_RDD_RSS_CONVERT <"convert_ud2df", 0b010>;
+def F2_conv_uw2df : F2_RDD_RS_CONVERT <"convert_uw2df", 0b001>;
+def F2_conv_w2df : F2_RDD_RS_CONVERT <"convert_w2df", 0b010>;
+
+// Convert Floating Point to Integer.
+def F2_conv_df2uw_chop : F2_RD_RSS_CONVERT <"convert_df2uw", 0b101, ":chop">;
+def F2_conv_df2w_chop : F2_RD_RSS_CONVERT <"convert_df2w", 0b111, ":chop">;
def F2_conv_sf2uw_chop : F2_RD_RS_CONVERT <"convert_sf2uw", 0b011, 0b001,
- fp_to_uint, I32, F32, ":chop">;
+ ":chop">;
def F2_conv_sf2w_chop : F2_RD_RS_CONVERT <"convert_sf2w", 0b100, 0b001,
- fp_to_sint, I32, F32, ":chop">;
-def F2_conv_df2d_chop : F2_RDD_RSS_CONVERT <"convert_df2d", 0b110,
- fp_to_sint, I64, F64, ":chop">;
-def F2_conv_df2ud_chop : F2_RDD_RSS_CONVERT <"convert_df2ud", 0b111,
- fp_to_uint, I64, F64, ":chop">;
-def F2_conv_sf2d_chop : F2_RDD_RS_CONVERT <"convert_sf2d", 0b110,
- fp_to_sint, I64, F32, ":chop">;
-def F2_conv_sf2ud_chop : F2_RDD_RS_CONVERT <"convert_sf2ud", 0b101,
- fp_to_uint, I64, F32, ":chop">;
+ ":chop">;
+def F2_conv_df2d_chop : F2_RDD_RSS_CONVERT <"convert_df2d", 0b110, ":chop">;
+def F2_conv_df2ud_chop : F2_RDD_RSS_CONVERT <"convert_df2ud", 0b111, ":chop">;
+def F2_conv_sf2d_chop : F2_RDD_RS_CONVERT <"convert_sf2d", 0b110, ":chop">;
+def F2_conv_sf2ud_chop : F2_RDD_RS_CONVERT <"convert_sf2ud", 0b101, ":chop">;
// Convert Floating Point to Integer: non-chopped.
-let AddedComplexity = 20, Predicates = [HasV5T, IEEERndNearV5T] in {
- def F2_conv_df2d : F2_RDD_RSS_CONVERT <"convert_df2d", 0b000,
- fp_to_sint, I64, F64>;
- def F2_conv_df2ud : F2_RDD_RSS_CONVERT <"convert_df2ud", 0b001,
- fp_to_uint, I64, F64>;
- def F2_conv_sf2ud : F2_RDD_RS_CONVERT <"convert_sf2ud", 0b011,
- fp_to_uint, I64, F32>;
- def F2_conv_sf2d : F2_RDD_RS_CONVERT <"convert_sf2d", 0b100,
- fp_to_sint, I64, F32>;
- def F2_conv_df2uw : F2_RD_RSS_CONVERT <"convert_df2uw", 0b011,
- fp_to_uint, I32, F64>;
- def F2_conv_df2w : F2_RD_RSS_CONVERT <"convert_df2w", 0b100,
- fp_to_sint, I32, F64>;
- def F2_conv_sf2uw : F2_RD_RS_CONVERT <"convert_sf2uw", 0b011, 0b000,
- fp_to_uint, I32, F32>;
- def F2_conv_sf2w : F2_RD_RS_CONVERT <"convert_sf2w", 0b100, 0b000,
- fp_to_sint, I32, F32>;
+let AddedComplexity = 20, Predicates = [HasV5T] in {
+ def F2_conv_df2d : F2_RDD_RSS_CONVERT <"convert_df2d", 0b000>;
+ def F2_conv_df2ud : F2_RDD_RSS_CONVERT <"convert_df2ud", 0b001>;
+ def F2_conv_sf2ud : F2_RDD_RS_CONVERT <"convert_sf2ud", 0b011>;
+ def F2_conv_sf2d : F2_RDD_RS_CONVERT <"convert_sf2d", 0b100>;
+ def F2_conv_df2uw : F2_RD_RSS_CONVERT <"convert_df2uw", 0b011>;
+ def F2_conv_df2w : F2_RD_RSS_CONVERT <"convert_df2w", 0b100>;
+ def F2_conv_sf2uw : F2_RD_RS_CONVERT <"convert_sf2uw", 0b011, 0b000>;
+ def F2_conv_sf2w : F2_RD_RS_CONVERT <"convert_sf2w", 0b100, 0b000>;
}
// Fix up radicand.
-let isFP = 1, hasNewValue = 1 in
+let Uses = [USR], isFP = 1, hasNewValue = 1 in
def F2_sffixupr: SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs),
"$Rd = sffixupr($Rs)",
[], "" , S_2op_tc_3or4x_SLOT23>, Requires<[HasV5T]> {
@@ -682,21 +309,13 @@ def F2_sffixupr: SInst<(outs IntRegs:$Rd), (ins IntRegs:$Rs),
let Inst{4-0} = Rd;
}
-// Bitcast is different than [fp|sint|uint]_to_[sint|uint|fp].
-let Predicates = [HasV5T] in {
- def: Pat <(i32 (bitconvert F32:$src)), (I32:$src)>;
- def: Pat <(f32 (bitconvert I32:$src)), (F32:$src)>;
- def: Pat <(i64 (bitconvert F64:$src)), (I64:$src)>;
- def: Pat <(f64 (bitconvert I64:$src)), (F64:$src)>;
-}
-
// F2_sffma: Floating-point fused multiply add.
-let isFP = 1, hasNewValue = 1 in
+let Uses = [USR], isFP = 1, hasNewValue = 1 in
class T_sfmpy_acc <bit isSub, bit isLib>
: MInst<(outs IntRegs:$Rx),
(ins IntRegs:$dst2, IntRegs:$Rs, IntRegs:$Rt),
"$Rx "#!if(isSub, "-=","+=")#" sfmpy($Rs, $Rt)"#!if(isLib, ":lib",""),
- [], "$dst2 = $Rx" , M_tc_3_SLOT23 > ,
+ [], "$dst2 = $Rx" , M_tc_3or4x_SLOT23 > ,
Requires<[HasV5T]> {
bits<5> Rx;
bits<5> Rs;
@@ -719,16 +338,13 @@ def F2_sffms: T_sfmpy_acc <1, 0>;
def F2_sffma_lib: T_sfmpy_acc <0, 1>;
def F2_sffms_lib: T_sfmpy_acc <1, 1>;
-def : Pat <(f32 (fma F32:$src2, F32:$src3, F32:$src1)),
- (F2_sffma F32:$src1, F32:$src2, F32:$src3)>;
-
// Floating-point fused multiply add w/ additional scaling (2**pu).
-let isFP = 1, hasNewValue = 1 in
+let Uses = [USR], isFP = 1, hasNewValue = 1 in
def F2_sffma_sc: MInst <
(outs IntRegs:$Rx),
(ins IntRegs:$dst2, IntRegs:$Rs, IntRegs:$Rt, PredRegs:$Pu),
"$Rx += sfmpy($Rs, $Rt, $Pu):scale" ,
- [], "$dst2 = $Rx" , M_tc_3_SLOT23 > ,
+ [], "$dst2 = $Rx" , M_tc_3or4x_SLOT23 > ,
Requires<[HasV5T]> {
bits<5> Rx;
bits<5> Rs;
@@ -746,54 +362,6 @@ def F2_sffma_sc: MInst <
let Inst{4-0} = Rx;
}
-let isExtended = 1, isExtentSigned = 1, opExtentBits = 8, opExtendable = 3,
- isPseudo = 1, InputType = "imm" in
-def MUX_ir_f : ALU32_rr<(outs IntRegs:$dst),
- (ins PredRegs:$src1, IntRegs:$src2, f32Ext:$src3),
- "$dst = mux($src1, $src2, #$src3)",
- [(set F32:$dst, (f32 (select I1:$src1, F32:$src2, fpimm:$src3)))]>,
- Requires<[HasV5T]>;
-
-let isExtended = 1, isExtentSigned = 1, opExtentBits = 8, opExtendable = 2,
- isPseudo = 1, InputType = "imm" in
-def MUX_ri_f : ALU32_rr<(outs IntRegs:$dst),
- (ins PredRegs:$src1, f32Ext:$src2, IntRegs:$src3),
- "$dst = mux($src1, #$src2, $src3)",
- [(set F32:$dst, (f32 (select I1:$src1, fpimm:$src2, F32:$src3)))]>,
- Requires<[HasV5T]>;
-
-def: Pat<(select I1:$src1, F32:$src2, F32:$src3),
- (C2_mux I1:$src1, F32:$src2, F32:$src3)>,
- Requires<[HasV5T]>;
-
-def: Pat<(select (i1 (setult F32:$src1, F32:$src2)), F32:$src3, F32:$src4),
- (C2_mux (F2_sfcmpgt F32:$src2, F32:$src1), F32:$src4, F32:$src3)>,
- Requires<[HasV5T]>;
-
-def: Pat<(select I1:$src1, F64:$src2, F64:$src3),
- (C2_vmux I1:$src1, F64:$src2, F64:$src3)>,
- Requires<[HasV5T]>;
-
-def: Pat<(select (i1 (setult F64:$src1, F64:$src2)), F64:$src3, F64:$src4),
- (C2_vmux (F2_dfcmpgt F64:$src2, F64:$src1), F64:$src3, F64:$src4)>,
- Requires<[HasV5T]>;
-
-// Map from p0 = pnot(p0); r0 = select(p0, #i, r1)
-// => r0 = MUX_ir_f(p0, #i, r1)
-def: Pat<(select (not I1:$src1), fpimm:$src2, F32:$src3),
- (MUX_ir_f I1:$src1, F32:$src3, fpimm:$src2)>,
- Requires<[HasV5T]>;
-
-// Map from p0 = pnot(p0); r0 = mux(p0, r1, #i)
-// => r0 = MUX_ri_f(p0, r1, #i)
-def: Pat<(select (not I1:$src1), F32:$src2, fpimm:$src3),
- (MUX_ri_f I1:$src1, fpimm:$src3, F32:$src2)>,
- Requires<[HasV5T]>;
-
-def: Pat<(i32 (fp_to_sint F64:$src1)),
- (LoReg (F2_conv_df2d_chop F64:$src1))>,
- Requires<[HasV5T]>;
-
//===----------------------------------------------------------------------===//
// :natural forms of vasrh and vasrhub insns
//===----------------------------------------------------------------------===//
@@ -802,7 +370,7 @@ def: Pat<(i32 (fp_to_sint F64:$src1)),
let Defs = [USR_OVF], hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
class T_ASRHUB<bit isSat>
: SInst <(outs IntRegs:$Rd),
- (ins DoubleRegs:$Rss, u4Imm:$u4),
+ (ins DoubleRegs:$Rss, u4_0Imm:$u4),
"$Rd = vasrhub($Rss, #$u4):"#!if(isSat, "sat", "raw"),
[], "", S_2op_tc_2_SLOT23>,
Requires<[HasV5T]> {
@@ -826,13 +394,13 @@ def S5_asrhub_sat : T_ASRHUB <1>;
let isAsmParserOnly = 1 in
def S5_asrhub_rnd_sat_goodsyntax
- : SInst <(outs IntRegs:$Rd), (ins DoubleRegs:$Rss, u4Imm:$u4),
+ : SInst <(outs IntRegs:$Rd), (ins DoubleRegs:$Rss, u4_0Imm:$u4),
"$Rd = vasrhub($Rss, #$u4):rnd:sat">, Requires<[HasV5T]>;
// S5_vasrhrnd: Vector arithmetic shift right by immediate with round.
let hasSideEffects = 0 in
def S5_vasrhrnd : SInst <(outs DoubleRegs:$Rdd),
- (ins DoubleRegs:$Rss, u4Imm:$u4),
+ (ins DoubleRegs:$Rss, u4_0Imm:$u4),
"$Rdd = vasrh($Rss, #$u4):raw">,
Requires<[HasV5T]> {
bits<5> Rdd;
@@ -851,7 +419,7 @@ def S5_vasrhrnd : SInst <(outs DoubleRegs:$Rdd),
let isAsmParserOnly = 1 in
def S5_vasrhrnd_goodsyntax
- : SInst <(outs DoubleRegs:$Rdd), (ins DoubleRegs:$Rss, u4Imm:$u4),
+ : SInst <(outs DoubleRegs:$Rdd), (ins DoubleRegs:$Rss, u4_0Imm:$u4),
"$Rdd = vasrh($Rss,#$u4):rnd">, Requires<[HasV5T]>;
// Floating point reciprocal square root approximation
@@ -883,11 +451,11 @@ let Defs = [USR_OVF], Itinerary = S_3op_tc_3x_SLOT23 in {
}
// Classify floating-point value
-let isFP = 1 in
- def F2_sfclass : T_TEST_BIT_IMM<"sfclass", 0b111>;
+let Uses = [USR], isFP = 1 in
+def F2_sfclass : T_TEST_BIT_IMM<"sfclass", 0b111>, Requires<[HasV5T]>;
-let isFP = 1 in
-def F2_dfclass: ALU64Inst<(outs PredRegs:$Pd), (ins DoubleRegs:$Rss, u5Imm:$u5),
+let Uses = [USR], isFP = 1 in
+def F2_dfclass: ALU64Inst<(outs PredRegs:$Pd), (ins DoubleRegs:$Rss, u5_0Imm:$u5),
"$Pd = dfclass($Rss, #$u5)",
[], "" , ALU64_tc_2early_SLOT23 > , Requires<[HasV5T]> {
bits<2> Pd;
@@ -905,9 +473,9 @@ def F2_dfclass: ALU64Inst<(outs PredRegs:$Pd), (ins DoubleRegs:$Rss, u5Imm:$u5),
// Instructions to create floating point constant
class T_fimm <string mnemonic, RegisterClass RC, bits<4> RegType, bit isNeg>
- : ALU64Inst<(outs RC:$dst), (ins u10Imm:$src),
+ : ALU64Inst<(outs RC:$dst), (ins u10_0Imm:$src),
"$dst = "#mnemonic#"(#$src)"#!if(isNeg, ":neg", ":pos"),
- [], "", ALU64_tc_3x_SLOT23>, Requires<[HasV5T]> {
+ [], "", ALU64_tc_2_SLOT23>, Requires<[HasV5T]> {
bits<5> dst;
bits<10> src;
@@ -921,17 +489,9 @@ class T_fimm <string mnemonic, RegisterClass RC, bits<4> RegType, bit isNeg>
}
let hasNewValue = 1, opNewValue = 0 in {
-def F2_sfimm_p : T_fimm <"sfmake", IntRegs, 0b0110, 0>;
-def F2_sfimm_n : T_fimm <"sfmake", IntRegs, 0b0110, 1>;
+ def F2_sfimm_p : T_fimm <"sfmake", IntRegs, 0b0110, 0>;
+ def F2_sfimm_n : T_fimm <"sfmake", IntRegs, 0b0110, 1>;
}
def F2_dfimm_p : T_fimm <"dfmake", DoubleRegs, 0b1001, 0>;
def F2_dfimm_n : T_fimm <"dfmake", DoubleRegs, 0b1001, 1>;
-
-def : Pat <(fabs (f32 IntRegs:$src1)),
- (S2_clrbit_i (f32 IntRegs:$src1), 31)>,
- Requires<[HasV5T]>;
-
-def : Pat <(fneg (f32 IntRegs:$src1)),
- (S2_togglebit_i (f32 IntRegs:$src1), 31)>,
- Requires<[HasV5T]>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV60.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV60.td
index c3f09b6..c50141b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV60.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoV60.td
@@ -10,33 +10,6 @@
// This file describes the Hexagon V60 instructions in TableGen format.
//
//===----------------------------------------------------------------------===//
-def alignedload : PatFrag<(ops node:$addr), (load $addr), [{
- return isAlignedMemNode(dyn_cast<MemSDNode>(N));
-}]>;
-
-def unalignedload : PatFrag<(ops node:$addr), (load $addr), [{
- return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
-}]>;
-
-def alignedstore : PatFrag<(ops node:$val, node:$addr), (store $val, $addr), [{
- return isAlignedMemNode(dyn_cast<MemSDNode>(N));
-}]>;
-
-def unalignedstore : PatFrag<(ops node:$val, node:$addr), (store $val, $addr), [{
- return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
-}]>;
-
-
-// Vector store
-let mayStore = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
-{
- class VSTInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
- string cstr = "", InstrItinClass itin = CVI_VM_ST,
- IType type = TypeCVI_VM_ST>
- : InstHexagon<outs, ins, asmstr, pattern, cstr, itin, type>, OpcodeHexagon;
-
-}
-
// Vector load
let Predicates = [HasV60T, UseHVX] in
let mayLoad = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
@@ -45,6 +18,7 @@ let mayLoad = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
IType type = TypeCVI_VM_LD>
: InstHexagon<outs, ins, asmstr, pattern, cstr, itin, type>;
+// Vector store
let Predicates = [HasV60T, UseHVX] in
let mayStore = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
class V6_STInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
@@ -219,6 +193,8 @@ let isNVStorable = 1 in {
def V6_vS32b_npred_ai_128B : T_vstore_pred_ai_128B <"vmem", "vS32b_ai", 1>,
V6_vS32b_npred_ai_128B_enc;
}
+
+
let isNVStorable = 1, isNonTemporal = 1 in {
def V6_vS32b_nt_pred_ai : T_vstore_pred_ai_64B <"vmem", "vS32b_ai", 0, 1>,
V6_vS32b_nt_pred_ai_enc;
@@ -774,256 +750,60 @@ def V6_vS32b_nt_new_npred_ppu : T_vstore_new_pred_ppu<1, 1>,
V6_vS32b_nt_new_npred_ppu_enc;
}
-let isPseudo = 1, validSubTargets = HasV60SubT in
-class STrivv_template<string mnemonic, Operand ImmOp, RegisterClass RC>:
- VSTInst<(outs), (ins IntRegs:$addr, ImmOp:$off, RC:$src),
- #mnemonic#"($addr+#$off) = $src", []>;
-
-def STrivv_indexed: STrivv_template<"vvmem", s4_6Imm, VecDblRegs>,
- Requires<[HasV60T, UseHVXSgl]>;
-def STrivv_indexed_128B: STrivv_template<"vvmem", s4_7Imm, VecDblRegs128B>,
- Requires<[HasV60T, UseHVXDbl]>;
-
-multiclass STrivv_pats <ValueType VTSgl, ValueType VTDbl> {
- def : Pat<(store (VTSgl VecDblRegs:$src1), IntRegs:$addr),
- (STrivv_indexed IntRegs:$addr, #0, (VTSgl VecDblRegs:$src1))>,
- Requires<[UseHVXSgl]>;
-
- def : Pat<(store (VTDbl VecDblRegs128B:$src1), IntRegs:$addr),
- (STrivv_indexed_128B IntRegs:$addr, #0,
- (VTDbl VecDblRegs128B:$src1))>,
- Requires<[UseHVXDbl]>;
-}
-
-defm : STrivv_pats <v128i8, v256i8>;
-defm : STrivv_pats <v64i16, v128i16>;
-defm : STrivv_pats <v32i32, v64i32>;
-defm : STrivv_pats <v16i64, v32i64>;
-
-
-multiclass vS32b_ai_pats <ValueType VTSgl, ValueType VTDbl> {
- // Aligned stores
- def : Pat<(alignedstore (VTSgl VectorRegs:$src1), IntRegs:$addr),
- (V6_vS32b_ai IntRegs:$addr, #0, (VTSgl VectorRegs:$src1))>,
- Requires<[UseHVXSgl]>;
- def : Pat<(unalignedstore (VTSgl VectorRegs:$src1), IntRegs:$addr),
- (V6_vS32Ub_ai IntRegs:$addr, #0, (VTSgl VectorRegs:$src1))>,
- Requires<[UseHVXSgl]>;
-
- // 128B Aligned stores
- def : Pat<(alignedstore (VTDbl VectorRegs128B:$src1), IntRegs:$addr),
- (V6_vS32b_ai_128B IntRegs:$addr, #0, (VTDbl VectorRegs128B:$src1))>,
- Requires<[UseHVXDbl]>;
- def : Pat<(unalignedstore (VTDbl VectorRegs128B:$src1), IntRegs:$addr),
- (V6_vS32Ub_ai_128B IntRegs:$addr, #0, (VTDbl VectorRegs128B:$src1))>,
- Requires<[UseHVXDbl]>;
-
- // Fold Add R+IFF into vector store.
- let AddedComplexity = 10 in {
- def : Pat<(alignedstore (VTSgl VectorRegs:$src1),
- (add IntRegs:$src2, s4_6ImmPred:$offset)),
- (V6_vS32b_ai IntRegs:$src2, s4_6ImmPred:$offset,
- (VTSgl VectorRegs:$src1))>,
- Requires<[UseHVXSgl]>;
- def : Pat<(unalignedstore (VTSgl VectorRegs:$src1),
- (add IntRegs:$src2, s4_6ImmPred:$offset)),
- (V6_vS32Ub_ai IntRegs:$src2, s4_6ImmPred:$offset,
- (VTSgl VectorRegs:$src1))>,
- Requires<[UseHVXSgl]>;
-
- // Fold Add R+IFF into vector store 128B.
- def : Pat<(alignedstore (VTDbl VectorRegs128B:$src1),
- (add IntRegs:$src2, s4_7ImmPred:$offset)),
- (V6_vS32b_ai_128B IntRegs:$src2, s4_7ImmPred:$offset,
- (VTDbl VectorRegs128B:$src1))>,
- Requires<[UseHVXDbl]>;
- def : Pat<(unalignedstore (VTDbl VectorRegs128B:$src1),
- (add IntRegs:$src2, s4_7ImmPred:$offset)),
- (V6_vS32Ub_ai_128B IntRegs:$src2, s4_7ImmPred:$offset,
- (VTDbl VectorRegs128B:$src1))>,
- Requires<[UseHVXDbl]>;
- }
-}
-
-defm : vS32b_ai_pats <v64i8, v128i8>;
-defm : vS32b_ai_pats <v32i16, v64i16>;
-defm : vS32b_ai_pats <v16i32, v32i32>;
-defm : vS32b_ai_pats <v8i64, v16i64>;
-
-let isPseudo = 1, validSubTargets = HasV60SubT in
-class LDrivv_template<string mnemonic, Operand ImmOp, RegisterClass RC>
- : V6_LDInst <(outs RC:$dst), (ins IntRegs:$addr, ImmOp:$off),
- "$dst="#mnemonic#"($addr+#$off)",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-
-def LDrivv_indexed: LDrivv_template<"vvmem", s4_6Imm, VecDblRegs>;
-def LDrivv_indexed_128B: LDrivv_template<"vvmem", s4_7Imm, VecDblRegs128B>;
-
-multiclass LDrivv_pats <ValueType VTSgl, ValueType VTDbl> {
- def : Pat < (VTSgl (load IntRegs:$addr)),
- (LDrivv_indexed IntRegs:$addr, #0) >,
- Requires<[UseHVXSgl]>;
-
- def : Pat < (VTDbl (load IntRegs:$addr)),
- (LDrivv_indexed_128B IntRegs:$addr, #0) >,
- Requires<[UseHVXDbl]>;
-}
-
-defm : LDrivv_pats <v128i8, v256i8>;
-defm : LDrivv_pats <v64i16, v128i16>;
-defm : LDrivv_pats <v32i32, v64i32>;
-defm : LDrivv_pats <v16i64, v32i64>;
-
-multiclass vL32b_ai_pats <ValueType VTSgl, ValueType VTDbl> {
- // Aligned loads
- def : Pat < (VTSgl (alignedload IntRegs:$addr)),
- (V6_vL32b_ai IntRegs:$addr, #0) >,
- Requires<[UseHVXSgl]>;
- def : Pat < (VTSgl (unalignedload IntRegs:$addr)),
- (V6_vL32Ub_ai IntRegs:$addr, #0) >,
- Requires<[UseHVXSgl]>;
-
- // 128B Load
- def : Pat < (VTDbl (alignedload IntRegs:$addr)),
- (V6_vL32b_ai_128B IntRegs:$addr, #0) >,
- Requires<[UseHVXDbl]>;
- def : Pat < (VTDbl (unalignedload IntRegs:$addr)),
- (V6_vL32Ub_ai_128B IntRegs:$addr, #0) >,
- Requires<[UseHVXDbl]>;
-
- // Fold Add R+IFF into vector load.
- let AddedComplexity = 10 in {
- def : Pat<(VTDbl (alignedload (add IntRegs:$src2, s4_7ImmPred:$offset))),
- (V6_vL32b_ai_128B IntRegs:$src2, s4_7ImmPred:$offset)>,
- Requires<[UseHVXDbl]>;
- def : Pat<(VTDbl (unalignedload (add IntRegs:$src2, s4_7ImmPred:$offset))),
- (V6_vL32Ub_ai_128B IntRegs:$src2, s4_7ImmPred:$offset)>,
- Requires<[UseHVXDbl]>;
-
- def : Pat<(VTSgl (alignedload (add IntRegs:$src2, s4_6ImmPred:$offset))),
- (V6_vL32b_ai IntRegs:$src2, s4_6ImmPred:$offset)>,
- Requires<[UseHVXSgl]>;
- def : Pat<(VTSgl (unalignedload (add IntRegs:$src2, s4_6ImmPred:$offset))),
- (V6_vL32Ub_ai IntRegs:$src2, s4_6ImmPred:$offset)>,
- Requires<[UseHVXSgl]>;
- }
-}
-
-defm : vL32b_ai_pats <v64i8, v128i8>;
-defm : vL32b_ai_pats <v32i16, v64i16>;
-defm : vL32b_ai_pats <v16i32, v32i32>;
-defm : vL32b_ai_pats <v8i64, v16i64>;
-// Store vector predicate pseudo.
-let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13,
- isCodeGenOnly = 1, isPseudo = 1, mayStore = 1, hasSideEffects = 0 in {
-def STriq_pred_V6 : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VecPredRegs:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-
-def STriq_pred_vec_V6 : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VectorRegs:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-
-def STriq_pred_V6_128B : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VecPredRegs128B:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
-
-def STriq_pred_vec_V6_128B : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VectorRegs128B:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
-}
+// Vector load/store pseudos
-// Load vector predicate pseudo.
-let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 13,
- opExtentAlign = 2, isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in {
-def LDriq_pred_V6 : LDInst<(outs VecPredRegs:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def LDriq_pred_vec_V6 : LDInst<(outs VectorRegs:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def LDriq_pred_V6_128B : LDInst<(outs VecPredRegs128B:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
-def LDriq_pred_vec_V6_128B : LDInst<(outs VectorRegs128B:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
-}
-
-// Store vector pseudo.
-let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13,
- isCodeGenOnly = 1, isPseudo = 1, mayStore = 1, hasSideEffects = 0 in {
-def STriv_pseudo_V6 : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VectorRegs:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def STriv_pseudo_V6_128B : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VectorRegs128B:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
-}
+let isPseudo = 1, isCodeGenOnly = 1, validSubTargets = HasV60SubT in
+class STrivv_template<RegisterClass RC>
+ : V6_STInst<(outs), (ins IntRegs:$addr, s32_0Imm:$off, RC:$src), "", []>;
+
+def PS_vstorerw_ai: STrivv_template<VecDblRegs>,
+ Requires<[HasV60T,UseHVXSgl]>;
+def PS_vstorerwu_ai: STrivv_template<VecDblRegs>,
+ Requires<[HasV60T,UseHVXSgl]>;
+def PS_vstorerw_ai_128B: STrivv_template<VecDblRegs128B>,
+ Requires<[HasV60T,UseHVXDbl]>;
+def PS_vstorerwu_ai_128B: STrivv_template<VecDblRegs128B>,
+ Requires<[HasV60T,UseHVXDbl]>;
+
+
+let isPseudo = 1, isCodeGenOnly = 1, validSubTargets = HasV60SubT in
+class LDrivv_template<RegisterClass RC>
+ : V6_LDInst<(outs RC:$dst), (ins IntRegs:$addr, s32_0Imm:$off), "", []>;
+def PS_vloadrw_ai: LDrivv_template<VecDblRegs>,
+ Requires<[HasV60T,UseHVXSgl]>;
+def PS_vloadrwu_ai: LDrivv_template<VecDblRegs>,
+ Requires<[HasV60T,UseHVXSgl]>;
+def PS_vloadrw_ai_128B: LDrivv_template<VecDblRegs128B>,
+ Requires<[HasV60T,UseHVXDbl]>;
+def PS_vloadrwu_ai_128B: LDrivv_template<VecDblRegs128B>,
+ Requires<[HasV60T,UseHVXDbl]>;
+
+// Store vector predicate pseudo.
let isExtendable = 1, opExtendable = 1, isExtentSigned = 1, opExtentBits = 13,
isCodeGenOnly = 1, isPseudo = 1, mayStore = 1, hasSideEffects = 0 in {
-def STrivv_pseudo_V6 : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VecDblRegs:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def STrivv_pseudo_V6_128B : STInst<(outs),
- (ins IntRegs:$base, s32Imm:$offset, VecDblRegs128B:$src1),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
-}
-
-// Load vector pseudo.
-let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 13,
- opExtentAlign = 2, isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in {
-def LDriv_pseudo_V6 : LDInst<(outs VectorRegs:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def LDriv_pseudo_V6_128B : LDInst<(outs VectorRegs128B:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
+ def PS_vstorerq_ai : STInst<(outs),
+ (ins IntRegs:$base, s32_0Imm:$offset, VecPredRegs:$src1),
+ ".error \"should not emit\"", []>,
+ Requires<[HasV60T,UseHVXSgl]>;
+ def PS_vstorerq_ai_128B : STInst<(outs),
+ (ins IntRegs:$base, s32_0Imm:$offset, VecPredRegs128B:$src1),
+ ".error \"should not emit\"", []>,
+ Requires<[HasV60T,UseHVXDbl]>;
}
+// Load vector predicate pseudo.
let isExtendable = 1, opExtendable = 2, isExtentSigned = 1, opExtentBits = 13,
opExtentAlign = 2, isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in {
-def LDrivv_pseudo_V6 : LDInst<(outs VecDblRegs:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def LDrivv_pseudo_V6_128B : LDInst<(outs VecDblRegs128B:$dst),
- (ins IntRegs:$base, s32Imm:$offset),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXDbl]>;
+ def PS_vloadrq_ai : LDInst<(outs VecPredRegs:$dst),
+ (ins IntRegs:$base, s32_0Imm:$offset),
+ ".error \"should not emit\"", []>,
+ Requires<[HasV60T,UseHVXSgl]>;
+ def PS_vloadrq_ai_128B : LDInst<(outs VecPredRegs128B:$dst),
+ (ins IntRegs:$base, s32_0Imm:$offset),
+ ".error \"should not emit\"", []>,
+ Requires<[HasV60T,UseHVXDbl]>;
}
class VSELInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
@@ -1032,26 +812,19 @@ class VSELInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
: InstHexagon<outs, ins, asmstr, pattern, cstr, itin, type>;
let isCodeGenOnly = 1, isPseudo = 1, hasSideEffects = 0 in {
-def VSelectPseudo_V6 : VSELInst<(outs VectorRegs:$dst),
- (ins PredRegs:$src1, VectorRegs:$src2, VectorRegs:$src3),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-def VSelectDblPseudo_V6 : VSELInst<(outs VecDblRegs:$dst),
- (ins PredRegs:$src1, VecDblRegs:$src2, VecDblRegs:$src3),
- ".error \"should not emit\" ",
- []>,
- Requires<[HasV60T,UseHVXSgl]>;
-}
-
-def : Pat <(v16i32 (selectcc (i32 IntRegs:$lhs), (i32 IntRegs:$rhs),
- (v16i32 VectorRegs:$tval),
- (v16i32 VectorRegs:$fval), SETEQ)),
- (v16i32 (VSelectPseudo_V6 (i32 (C2_cmpeq (i32 IntRegs:$lhs),
- (i32 IntRegs:$rhs))),
- (v16i32 VectorRegs:$tval),
- (v16i32 VectorRegs:$fval)))>;
-
+ def PS_vselect: VSELInst<(outs VectorRegs:$dst),
+ (ins PredRegs:$src1, VectorRegs:$src2, VectorRegs:$src3), "", []>,
+ Requires<[HasV60T,UseHVXSgl]>;
+ def PS_vselect_128B: VSELInst<(outs VectorRegs128B:$dst),
+ (ins PredRegs:$src1, VectorRegs128B:$src2, VectorRegs128B:$src3),
+ "", []>, Requires<[HasV60T,UseHVXDbl]>;
+ def PS_wselect: VSELInst<(outs VecDblRegs:$dst),
+ (ins PredRegs:$src1, VecDblRegs:$src2, VecDblRegs:$src3), "", []>,
+ Requires<[HasV60T,UseHVXSgl]>;
+ def PS_wselect_128B: VSELInst<(outs VecDblRegs128B:$dst),
+ (ins PredRegs:$src1, VecDblRegs128B:$src2, VecDblRegs128B:$src3),
+ "", []>, Requires<[HasV60T,UseHVXDbl]>;
+}
let hasNewValue = 1 in
class T_vmpy <string asmString, RegisterClass RCout, RegisterClass RCin>
@@ -1581,20 +1354,6 @@ let isRegSequence = 1, Itinerary = CVI_VA_DV, Type = TypeCVI_VA_DV in
defm V6_vcombine :
T_HVX_alu_WV <"$dst = vcombine($src1,$src2)">, V6_vcombine_enc;
-def SDTHexagonVCOMBINE: SDTypeProfile<1, 2, [SDTCisSameAs<1, 2>,
- SDTCisSubVecOfVec<1, 0>]>;
-
-def HexagonVCOMBINE: SDNode<"HexagonISD::VCOMBINE", SDTHexagonVCOMBINE>;
-
-def: Pat<(v32i32 (HexagonVCOMBINE (v16i32 VectorRegs:$Vs),
- (v16i32 VectorRegs:$Vt))),
- (V6_vcombine VectorRegs:$Vs, VectorRegs:$Vt)>,
- Requires<[UseHVXSgl]>;
-def: Pat<(v64i32 (HexagonVCOMBINE (v32i32 VecDblRegs:$Vs),
- (v32i32 VecDblRegs:$Vt))),
- (V6_vcombine_128B VecDblRegs:$Vs, VecDblRegs:$Vt)>,
- Requires<[UseHVXDbl]>;
-
let Itinerary = CVI_VINLANESAT, Type = TypeCVI_VINLANESAT in {
defm V6_vsathub :
T_HVX_alu_VV <"$dst.ub = vsat($src1.h,$src2.h)">, V6_vsathub_enc;
@@ -1782,7 +1541,7 @@ let isAccumulator = 1, hasNewValue = 1, Itinerary = CVI_VX_DV_LONG,
Type = TypeCVI_VX_DV in
class T_HVX_vmpyacc2 <string asmString, RegisterClass RC>
: CVI_VA_Resource1 <(outs RC:$dst),
- (ins RC:$_src_, RC:$src1, IntRegs:$src2, u1Imm:$src3),
+ (ins RC:$_src_, RC:$src1, IntRegs:$src2, u1_0Imm:$src3),
asmString, [], "$dst = $_src_" > ;
@@ -1806,7 +1565,7 @@ defm V6_vrmpyubi_acc :
let Itinerary = CVI_VX_DV_LONG, Type = TypeCVI_VX_DV, hasNewValue = 1 in
class T_HVX_vmpy2 <string asmString, RegisterClass RC>
- : CVI_VA_Resource1<(outs RC:$dst), (ins RC:$src1, IntRegs:$src2, u1Imm:$src3),
+ : CVI_VA_Resource1<(outs RC:$dst), (ins RC:$src1, IntRegs:$src2, u1_0Imm:$src3),
asmString>;
@@ -1958,7 +1717,7 @@ defm V6_vunpackoh : T_HVX_unpack <"$dst.w |= vunpacko($src1.h)">, V6_vunpackoh_e
let Itinerary = CVI_VP_LONG, Type = TypeCVI_VP, hasNewValue = 1,
hasSideEffects = 0 in
class T_HVX_valign <string asmString, RegisterClass RC>
- : CVI_VA_Resource1<(outs RC:$dst), (ins RC:$src1, RC:$src2, u3Imm:$src3),
+ : CVI_VA_Resource1<(outs RC:$dst), (ins RC:$src1, RC:$src2, u3_0Imm:$src3),
asmString>;
multiclass T_HVX_valign <string asmString> {
@@ -2095,9 +1854,9 @@ class T_HVX_rol <string asmString, RegisterClass RC, Operand ImmOp >
: SInst2 <(outs RC:$dst), (ins RC:$src1, ImmOp:$src2), asmString>;
class T_HVX_rol_R <string asmString>
- : T_HVX_rol <asmString, IntRegs, u5Imm>;
+ : T_HVX_rol <asmString, IntRegs, u5_0Imm>;
class T_HVX_rol_P <string asmString>
- : T_HVX_rol <asmString, DoubleRegs, u6Imm>;
+ : T_HVX_rol <asmString, DoubleRegs, u6_0Imm>;
def S6_rol_i_p : T_HVX_rol_P <"$dst = rol($src1,#$src2)">, S6_rol_i_p_enc;
let hasNewValue = 1, opNewValue = 0 in
@@ -2109,10 +1868,10 @@ class T_HVX_rol_acc <string asmString, RegisterClass RC, Operand ImmOp>
asmString, [], "$dst = $_src_" >;
class T_HVX_rol_acc_P <string asmString>
- : T_HVX_rol_acc <asmString, DoubleRegs, u6Imm>;
+ : T_HVX_rol_acc <asmString, DoubleRegs, u6_0Imm>;
class T_HVX_rol_acc_R <string asmString>
- : T_HVX_rol_acc <asmString, IntRegs, u5Imm>;
+ : T_HVX_rol_acc <asmString, IntRegs, u5_0Imm>;
def S6_rol_i_p_nac :
T_HVX_rol_acc_P <"$dst -= rol($src1,#$src2)">, S6_rol_i_p_nac_enc;
@@ -2285,3 +2044,25 @@ def V6_vhistq
def V6_vhist
: CVI_HIST_Resource1 <(outs), (ins),
"vhist" >, V6_vhist_enc;
+
+
+let isPseudo = 1, isCodeGenOnly = 1, hasSideEffects = 0 in {
+ def V6_vd0: CVI_VA_Resource<(outs VectorRegs:$dst), (ins), "$dst = #0", []>;
+ def V6_vd0_128B: CVI_VA_Resource<(outs VectorRegs128B:$dst), (ins),
+ "$dst = #0", []>;
+
+ def V6_vassignp: CVI_VA_Resource<(outs VecDblRegs:$dst),
+ (ins VecDblRegs:$src), "", []>;
+ def V6_vassignp_128B : CVI_VA_Resource<(outs VecDblRegs128B:$dst),
+ (ins VecDblRegs128B:$src), "", []>;
+
+ def V6_lo: CVI_VA_Resource<(outs VectorRegs:$dst), (ins VecDblRegs:$src1),
+ "", []>;
+ def V6_lo_128B: CVI_VA_Resource<(outs VectorRegs128B:$dst),
+ (ins VecDblRegs128B:$src1), "", []>;
+
+ def V6_hi: CVI_VA_Resource<(outs VectorRegs:$dst), (ins VecDblRegs:$src1),
+ "", []>;
+ def V6_hi_128B: CVI_VA_Resource<(outs VectorRegs128B:$dst),
+ (ins VecDblRegs128B:$src1), "", []>;
+}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoVector.td b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoVector.td
index 0277d5e..e3520bd 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoVector.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfoVector.td
@@ -11,37 +11,6 @@
//
//===----------------------------------------------------------------------===//
-def V2I1: PatLeaf<(v2i1 PredRegs:$R)>;
-def V4I1: PatLeaf<(v4i1 PredRegs:$R)>;
-def V8I1: PatLeaf<(v8i1 PredRegs:$R)>;
-def V4I8: PatLeaf<(v4i8 IntRegs:$R)>;
-def V2I16: PatLeaf<(v2i16 IntRegs:$R)>;
-def V8I8: PatLeaf<(v8i8 DoubleRegs:$R)>;
-def V4I16: PatLeaf<(v4i16 DoubleRegs:$R)>;
-def V2I32: PatLeaf<(v2i32 DoubleRegs:$R)>;
-
-
-multiclass bitconvert_32<ValueType a, ValueType b> {
- def : Pat <(b (bitconvert (a IntRegs:$src))),
- (b IntRegs:$src)>;
- def : Pat <(a (bitconvert (b IntRegs:$src))),
- (a IntRegs:$src)>;
-}
-
-multiclass bitconvert_64<ValueType a, ValueType b> {
- def : Pat <(b (bitconvert (a DoubleRegs:$src))),
- (b DoubleRegs:$src)>;
- def : Pat <(a (bitconvert (b DoubleRegs:$src))),
- (a DoubleRegs:$src)>;
-}
-
-// Bit convert vector types to integers.
-defm : bitconvert_32<v4i8, i32>;
-defm : bitconvert_32<v2i16, i32>;
-defm : bitconvert_64<v8i8, i64>;
-defm : bitconvert_64<v4i16, i64>;
-defm : bitconvert_64<v2i32, i64>;
-
// Vector shift support. Vector shifting in Hexagon is rather different
// from internal representation of LLVM.
// LLVM assumes all shifts (in vector case) will have the form
@@ -51,27 +20,17 @@ defm : bitconvert_64<v2i32, i64>;
// As a result, special care is needed to guarantee correctness and
// performance.
class vshift_v4i16<SDNode Op, string Str, bits<3>MajOp, bits<3>MinOp>
- : S_2OpInstImm<Str, MajOp, MinOp, u4Imm,
- [(set (v4i16 DoubleRegs:$dst),
- (Op (v4i16 DoubleRegs:$src1), u4ImmPred:$src2))]> {
+ : S_2OpInstImm<Str, MajOp, MinOp, u4_0Imm, []> {
bits<4> src2;
let Inst{11-8} = src2;
}
class vshift_v2i32<SDNode Op, string Str, bits<3>MajOp, bits<3>MinOp>
- : S_2OpInstImm<Str, MajOp, MinOp, u5Imm,
- [(set (v2i32 DoubleRegs:$dst),
- (Op (v2i32 DoubleRegs:$src1), u5ImmPred:$src2))]> {
+ : S_2OpInstImm<Str, MajOp, MinOp, u5_0Imm, []> {
bits<5> src2;
let Inst{12-8} = src2;
}
-def : Pat<(v2i16 (add (v2i16 IntRegs:$src1), (v2i16 IntRegs:$src2))),
- (A2_svaddh IntRegs:$src1, IntRegs:$src2)>;
-
-def : Pat<(v2i16 (sub (v2i16 IntRegs:$src1), (v2i16 IntRegs:$src2))),
- (A2_svsubh IntRegs:$src1, IntRegs:$src2)>;
-
def S2_asr_i_vw : vshift_v2i32<sra, "vasrw", 0b010, 0b000>;
def S2_lsr_i_vw : vshift_v2i32<srl, "vlsrw", 0b010, 0b001>;
def S2_asl_i_vw : vshift_v2i32<shl, "vaslw", 0b010, 0b010>;
@@ -80,87 +39,6 @@ def S2_asr_i_vh : vshift_v4i16<sra, "vasrh", 0b100, 0b000>;
def S2_lsr_i_vh : vshift_v4i16<srl, "vlsrh", 0b100, 0b001>;
def S2_asl_i_vh : vshift_v4i16<shl, "vaslh", 0b100, 0b010>;
-
-def HexagonVSPLATB: SDNode<"HexagonISD::VSPLATB", SDTUnaryOp>;
-def HexagonVSPLATH: SDNode<"HexagonISD::VSPLATH", SDTUnaryOp>;
-
-// Replicate the low 8-bits from 32-bits input register into each of the
-// four bytes of 32-bits destination register.
-def: Pat<(v4i8 (HexagonVSPLATB I32:$Rs)), (S2_vsplatrb I32:$Rs)>;
-
-// Replicate the low 16-bits from 32-bits input register into each of the
-// four halfwords of 64-bits destination register.
-def: Pat<(v4i16 (HexagonVSPLATH I32:$Rs)), (S2_vsplatrh I32:$Rs)>;
-
-
-class VArith_pat <InstHexagon MI, SDNode Op, PatFrag Type>
- : Pat <(Op Type:$Rss, Type:$Rtt),
- (MI Type:$Rss, Type:$Rtt)>;
-
-def: VArith_pat <A2_vaddub, add, V8I8>;
-def: VArith_pat <A2_vaddh, add, V4I16>;
-def: VArith_pat <A2_vaddw, add, V2I32>;
-def: VArith_pat <A2_vsubub, sub, V8I8>;
-def: VArith_pat <A2_vsubh, sub, V4I16>;
-def: VArith_pat <A2_vsubw, sub, V2I32>;
-
-def: VArith_pat <A2_and, and, V2I16>;
-def: VArith_pat <A2_xor, xor, V2I16>;
-def: VArith_pat <A2_or, or, V2I16>;
-
-def: VArith_pat <A2_andp, and, V8I8>;
-def: VArith_pat <A2_andp, and, V4I16>;
-def: VArith_pat <A2_andp, and, V2I32>;
-def: VArith_pat <A2_orp, or, V8I8>;
-def: VArith_pat <A2_orp, or, V4I16>;
-def: VArith_pat <A2_orp, or, V2I32>;
-def: VArith_pat <A2_xorp, xor, V8I8>;
-def: VArith_pat <A2_xorp, xor, V4I16>;
-def: VArith_pat <A2_xorp, xor, V2I32>;
-
-def: Pat<(v2i32 (sra V2I32:$b, (i64 (HexagonCOMBINE (i32 u5ImmPred:$c),
- (i32 u5ImmPred:$c))))),
- (S2_asr_i_vw V2I32:$b, imm:$c)>;
-def: Pat<(v2i32 (srl V2I32:$b, (i64 (HexagonCOMBINE (i32 u5ImmPred:$c),
- (i32 u5ImmPred:$c))))),
- (S2_lsr_i_vw V2I32:$b, imm:$c)>;
-def: Pat<(v2i32 (shl V2I32:$b, (i64 (HexagonCOMBINE (i32 u5ImmPred:$c),
- (i32 u5ImmPred:$c))))),
- (S2_asl_i_vw V2I32:$b, imm:$c)>;
-
-def: Pat<(v4i16 (sra V4I16:$b, (v4i16 (HexagonVSPLATH (i32 (u4ImmPred:$c)))))),
- (S2_asr_i_vh V4I16:$b, imm:$c)>;
-def: Pat<(v4i16 (srl V4I16:$b, (v4i16 (HexagonVSPLATH (i32 (u4ImmPred:$c)))))),
- (S2_lsr_i_vh V4I16:$b, imm:$c)>;
-def: Pat<(v4i16 (shl V4I16:$b, (v4i16 (HexagonVSPLATH (i32 (u4ImmPred:$c)))))),
- (S2_asl_i_vh V4I16:$b, imm:$c)>;
-
-
-def SDTHexagon_v2i32_v2i32_i32 : SDTypeProfile<1, 2,
- [SDTCisSameAs<0, 1>, SDTCisVT<0, v2i32>, SDTCisInt<2>]>;
-def SDTHexagon_v4i16_v4i16_i32 : SDTypeProfile<1, 2,
- [SDTCisSameAs<0, 1>, SDTCisVT<0, v4i16>, SDTCisInt<2>]>;
-
-def HexagonVSRAW: SDNode<"HexagonISD::VSRAW", SDTHexagon_v2i32_v2i32_i32>;
-def HexagonVSRAH: SDNode<"HexagonISD::VSRAH", SDTHexagon_v4i16_v4i16_i32>;
-def HexagonVSRLW: SDNode<"HexagonISD::VSRLW", SDTHexagon_v2i32_v2i32_i32>;
-def HexagonVSRLH: SDNode<"HexagonISD::VSRLH", SDTHexagon_v4i16_v4i16_i32>;
-def HexagonVSHLW: SDNode<"HexagonISD::VSHLW", SDTHexagon_v2i32_v2i32_i32>;
-def HexagonVSHLH: SDNode<"HexagonISD::VSHLH", SDTHexagon_v4i16_v4i16_i32>;
-
-def: Pat<(v2i32 (HexagonVSRAW V2I32:$Rs, u5ImmPred:$u5)),
- (S2_asr_i_vw V2I32:$Rs, imm:$u5)>;
-def: Pat<(v4i16 (HexagonVSRAH V4I16:$Rs, u4ImmPred:$u4)),
- (S2_asr_i_vh V4I16:$Rs, imm:$u4)>;
-def: Pat<(v2i32 (HexagonVSRLW V2I32:$Rs, u5ImmPred:$u5)),
- (S2_lsr_i_vw V2I32:$Rs, imm:$u5)>;
-def: Pat<(v4i16 (HexagonVSRLH V4I16:$Rs, u4ImmPred:$u4)),
- (S2_lsr_i_vh V4I16:$Rs, imm:$u4)>;
-def: Pat<(v2i32 (HexagonVSHLW V2I32:$Rs, u5ImmPred:$u5)),
- (S2_asl_i_vw V2I32:$Rs, imm:$u5)>;
-def: Pat<(v4i16 (HexagonVSHLH V4I16:$Rs, u4ImmPred:$u4)),
- (S2_asl_i_vh V4I16:$Rs, imm:$u4)>;
-
// Vector shift words by register
def S2_asr_r_vw : T_S3op_shiftVect < "vasrw", 0b00, 0b00>;
def S2_lsr_r_vw : T_S3op_shiftVect < "vlsrw", 0b00, 0b01>;
@@ -173,305 +51,19 @@ def S2_lsr_r_vh : T_S3op_shiftVect < "vlsrh", 0b01, 0b01>;
def S2_asl_r_vh : T_S3op_shiftVect < "vaslh", 0b01, 0b10>;
def S2_lsl_r_vh : T_S3op_shiftVect < "vlslh", 0b01, 0b11>;
-class vshift_rr_pat<InstHexagon MI, SDNode Op, PatFrag Value>
- : Pat <(Op Value:$Rs, I32:$Rt),
- (MI Value:$Rs, I32:$Rt)>;
-
-def: vshift_rr_pat <S2_asr_r_vw, HexagonVSRAW, V2I32>;
-def: vshift_rr_pat <S2_asr_r_vh, HexagonVSRAH, V4I16>;
-def: vshift_rr_pat <S2_lsr_r_vw, HexagonVSRLW, V2I32>;
-def: vshift_rr_pat <S2_lsr_r_vh, HexagonVSRLH, V4I16>;
-def: vshift_rr_pat <S2_asl_r_vw, HexagonVSHLW, V2I32>;
-def: vshift_rr_pat <S2_asl_r_vh, HexagonVSHLH, V4I16>;
-
-
-def SDTHexagonVecCompare_v8i8 : SDTypeProfile<1, 2,
- [SDTCisSameAs<1, 2>, SDTCisVT<0, i1>, SDTCisVT<1, v8i8>]>;
-def SDTHexagonVecCompare_v4i16 : SDTypeProfile<1, 2,
- [SDTCisSameAs<1, 2>, SDTCisVT<0, i1>, SDTCisVT<1, v4i16>]>;
-def SDTHexagonVecCompare_v2i32 : SDTypeProfile<1, 2,
- [SDTCisSameAs<1, 2>, SDTCisVT<0, i1>, SDTCisVT<1, v2i32>]>;
-
-def HexagonVCMPBEQ: SDNode<"HexagonISD::VCMPBEQ", SDTHexagonVecCompare_v8i8>;
-def HexagonVCMPBGT: SDNode<"HexagonISD::VCMPBGT", SDTHexagonVecCompare_v8i8>;
-def HexagonVCMPBGTU: SDNode<"HexagonISD::VCMPBGTU", SDTHexagonVecCompare_v8i8>;
-def HexagonVCMPHEQ: SDNode<"HexagonISD::VCMPHEQ", SDTHexagonVecCompare_v4i16>;
-def HexagonVCMPHGT: SDNode<"HexagonISD::VCMPHGT", SDTHexagonVecCompare_v4i16>;
-def HexagonVCMPHGTU: SDNode<"HexagonISD::VCMPHGTU", SDTHexagonVecCompare_v4i16>;
-def HexagonVCMPWEQ: SDNode<"HexagonISD::VCMPWEQ", SDTHexagonVecCompare_v2i32>;
-def HexagonVCMPWGT: SDNode<"HexagonISD::VCMPWGT", SDTHexagonVecCompare_v2i32>;
-def HexagonVCMPWGTU: SDNode<"HexagonISD::VCMPWGTU", SDTHexagonVecCompare_v2i32>;
-
-
-class vcmp_i1_pat<InstHexagon MI, SDNode Op, PatFrag Value>
- : Pat <(i1 (Op Value:$Rs, Value:$Rt)),
- (MI Value:$Rs, Value:$Rt)>;
-
-def: vcmp_i1_pat<A2_vcmpbeq, HexagonVCMPBEQ, V8I8>;
-def: vcmp_i1_pat<A4_vcmpbgt, HexagonVCMPBGT, V8I8>;
-def: vcmp_i1_pat<A2_vcmpbgtu, HexagonVCMPBGTU, V8I8>;
-
-def: vcmp_i1_pat<A2_vcmpheq, HexagonVCMPHEQ, V4I16>;
-def: vcmp_i1_pat<A2_vcmphgt, HexagonVCMPHGT, V4I16>;
-def: vcmp_i1_pat<A2_vcmphgtu, HexagonVCMPHGTU, V4I16>;
-
-def: vcmp_i1_pat<A2_vcmpweq, HexagonVCMPWEQ, V2I32>;
-def: vcmp_i1_pat<A2_vcmpwgt, HexagonVCMPWGT, V2I32>;
-def: vcmp_i1_pat<A2_vcmpwgtu, HexagonVCMPWGTU, V2I32>;
-
-
-class vcmp_vi1_pat<InstHexagon MI, PatFrag Op, PatFrag InVal, ValueType OutTy>
- : Pat <(OutTy (Op InVal:$Rs, InVal:$Rt)),
- (MI InVal:$Rs, InVal:$Rt)>;
-
-def: vcmp_vi1_pat<A2_vcmpweq, seteq, V2I32, v2i1>;
-def: vcmp_vi1_pat<A2_vcmpwgt, setgt, V2I32, v2i1>;
-def: vcmp_vi1_pat<A2_vcmpwgtu, setugt, V2I32, v2i1>;
-
-def: vcmp_vi1_pat<A2_vcmpheq, seteq, V4I16, v4i1>;
-def: vcmp_vi1_pat<A2_vcmphgt, setgt, V4I16, v4i1>;
-def: vcmp_vi1_pat<A2_vcmphgtu, setugt, V4I16, v4i1>;
-
// Hexagon doesn't have a vector multiply with C semantics.
// Instead, generate a pseudo instruction that gets expaneded into two
// scalar MPYI instructions.
// This is expanded by ExpandPostRAPseudos.
let isPseudo = 1 in
-def VMULW : PseudoM<(outs DoubleRegs:$Rd),
- (ins DoubleRegs:$Rs, DoubleRegs:$Rt),
- ".error \"Should never try to emit VMULW\"",
- [(set V2I32:$Rd, (mul V2I32:$Rs, V2I32:$Rt))]>;
+def PS_vmulw : PseudoM<(outs DoubleRegs:$Rd),
+ (ins DoubleRegs:$Rs, DoubleRegs:$Rt), "", []>;
let isPseudo = 1 in
-def VMULW_ACC : PseudoM<(outs DoubleRegs:$Rd),
- (ins DoubleRegs:$Rx, DoubleRegs:$Rs, DoubleRegs:$Rt),
- ".error \"Should never try to emit VMULW_ACC\"",
- [(set V2I32:$Rd, (add V2I32:$Rx, (mul V2I32:$Rs, V2I32:$Rt)))],
+def PS_vmulw_acc : PseudoM<(outs DoubleRegs:$Rd),
+ (ins DoubleRegs:$Rx, DoubleRegs:$Rs, DoubleRegs:$Rt), "", [],
"$Rd = $Rx">;
-// Adds two v4i8: Hexagon does not have an insn for this one, so we
-// use the double add v8i8, and use only the low part of the result.
-def: Pat<(v4i8 (add (v4i8 IntRegs:$Rs), (v4i8 IntRegs:$Rt))),
- (LoReg (A2_vaddub (Zext64 $Rs), (Zext64 $Rt)))>;
-
-// Subtract two v4i8: Hexagon does not have an insn for this one, so we
-// use the double sub v8i8, and use only the low part of the result.
-def: Pat<(v4i8 (sub (v4i8 IntRegs:$Rs), (v4i8 IntRegs:$Rt))),
- (LoReg (A2_vsubub (Zext64 $Rs), (Zext64 $Rt)))>;
-
-//
-// No 32 bit vector mux.
-//
-def: Pat<(v4i8 (select I1:$Pu, V4I8:$Rs, V4I8:$Rt)),
- (LoReg (C2_vmux I1:$Pu, (Zext64 $Rs), (Zext64 $Rt)))>;
-def: Pat<(v2i16 (select I1:$Pu, V2I16:$Rs, V2I16:$Rt)),
- (LoReg (C2_vmux I1:$Pu, (Zext64 $Rs), (Zext64 $Rt)))>;
-
-//
-// 64-bit vector mux.
-//
-def: Pat<(v8i8 (vselect V8I1:$Pu, V8I8:$Rs, V8I8:$Rt)),
- (C2_vmux V8I1:$Pu, V8I8:$Rs, V8I8:$Rt)>;
-def: Pat<(v4i16 (vselect V4I1:$Pu, V4I16:$Rs, V4I16:$Rt)),
- (C2_vmux V4I1:$Pu, V4I16:$Rs, V4I16:$Rt)>;
-def: Pat<(v2i32 (vselect V2I1:$Pu, V2I32:$Rs, V2I32:$Rt)),
- (C2_vmux V2I1:$Pu, V2I32:$Rs, V2I32:$Rt)>;
-
-//
-// No 32 bit vector compare.
-//
-def: Pat<(i1 (seteq V4I8:$Rs, V4I8:$Rt)),
- (A2_vcmpbeq (Zext64 $Rs), (Zext64 $Rt))>;
-def: Pat<(i1 (setgt V4I8:$Rs, V4I8:$Rt)),
- (A4_vcmpbgt (Zext64 $Rs), (Zext64 $Rt))>;
-def: Pat<(i1 (setugt V4I8:$Rs, V4I8:$Rt)),
- (A2_vcmpbgtu (Zext64 $Rs), (Zext64 $Rt))>;
-
-def: Pat<(i1 (seteq V2I16:$Rs, V2I16:$Rt)),
- (A2_vcmpheq (Zext64 $Rs), (Zext64 $Rt))>;
-def: Pat<(i1 (setgt V2I16:$Rs, V2I16:$Rt)),
- (A2_vcmphgt (Zext64 $Rs), (Zext64 $Rt))>;
-def: Pat<(i1 (setugt V2I16:$Rs, V2I16:$Rt)),
- (A2_vcmphgtu (Zext64 $Rs), (Zext64 $Rt))>;
-
-
-class InvertCmp_pat<InstHexagon InvMI, PatFrag CmpOp, PatFrag Value,
- ValueType CmpTy>
- : Pat<(CmpTy (CmpOp Value:$Rs, Value:$Rt)),
- (InvMI Value:$Rt, Value:$Rs)>;
-
-// Map from a compare operation to the corresponding instruction with the
-// order of operands reversed, e.g. x > y --> cmp.lt(y,x).
-def: InvertCmp_pat<A4_vcmpbgt, setlt, V8I8, i1>;
-def: InvertCmp_pat<A4_vcmpbgt, setlt, V8I8, v8i1>;
-def: InvertCmp_pat<A2_vcmphgt, setlt, V4I16, i1>;
-def: InvertCmp_pat<A2_vcmphgt, setlt, V4I16, v4i1>;
-def: InvertCmp_pat<A2_vcmpwgt, setlt, V2I32, i1>;
-def: InvertCmp_pat<A2_vcmpwgt, setlt, V2I32, v2i1>;
-
-def: InvertCmp_pat<A2_vcmpbgtu, setult, V8I8, i1>;
-def: InvertCmp_pat<A2_vcmpbgtu, setult, V8I8, v8i1>;
-def: InvertCmp_pat<A2_vcmphgtu, setult, V4I16, i1>;
-def: InvertCmp_pat<A2_vcmphgtu, setult, V4I16, v4i1>;
-def: InvertCmp_pat<A2_vcmpwgtu, setult, V2I32, i1>;
-def: InvertCmp_pat<A2_vcmpwgtu, setult, V2I32, v2i1>;
-
-// Map from vcmpne(Rss) -> !vcmpew(Rss).
-// rs != rt -> !(rs == rt).
-def: Pat<(v2i1 (setne V2I32:$Rs, V2I32:$Rt)),
- (C2_not (v2i1 (A2_vcmpbeq V2I32:$Rs, V2I32:$Rt)))>;
-
-
-// Truncate: from vector B copy all 'E'ven 'B'yte elements:
-// A[0] = B[0]; A[1] = B[2]; A[2] = B[4]; A[3] = B[6];
-def: Pat<(v4i8 (trunc V4I16:$Rs)),
- (S2_vtrunehb V4I16:$Rs)>;
-
-// Truncate: from vector B copy all 'O'dd 'B'yte elements:
-// A[0] = B[1]; A[1] = B[3]; A[2] = B[5]; A[3] = B[7];
-// S2_vtrunohb
-
-// Truncate: from vectors B and C copy all 'E'ven 'H'alf-word elements:
-// A[0] = B[0]; A[1] = B[2]; A[2] = C[0]; A[3] = C[2];
-// S2_vtruneh
-
-def: Pat<(v2i16 (trunc V2I32:$Rs)),
- (LoReg (S2_packhl (HiReg $Rs), (LoReg $Rs)))>;
-
-
-def HexagonVSXTBH : SDNode<"HexagonISD::VSXTBH", SDTUnaryOp>;
-def HexagonVSXTBW : SDNode<"HexagonISD::VSXTBW", SDTUnaryOp>;
-
-def: Pat<(i64 (HexagonVSXTBH I32:$Rs)), (S2_vsxtbh I32:$Rs)>;
-def: Pat<(i64 (HexagonVSXTBW I32:$Rs)), (S2_vsxthw I32:$Rs)>;
-
-def: Pat<(v4i16 (zext V4I8:$Rs)), (S2_vzxtbh V4I8:$Rs)>;
-def: Pat<(v2i32 (zext V2I16:$Rs)), (S2_vzxthw V2I16:$Rs)>;
-def: Pat<(v4i16 (anyext V4I8:$Rs)), (S2_vzxtbh V4I8:$Rs)>;
-def: Pat<(v2i32 (anyext V2I16:$Rs)), (S2_vzxthw V2I16:$Rs)>;
-def: Pat<(v4i16 (sext V4I8:$Rs)), (S2_vsxtbh V4I8:$Rs)>;
-def: Pat<(v2i32 (sext V2I16:$Rs)), (S2_vsxthw V2I16:$Rs)>;
-
-// Sign extends a v2i8 into a v2i32.
-def: Pat<(v2i32 (sext_inreg V2I32:$Rs, v2i8)),
- (A2_combinew (A2_sxtb (HiReg $Rs)), (A2_sxtb (LoReg $Rs)))>;
-
-// Sign extends a v2i16 into a v2i32.
-def: Pat<(v2i32 (sext_inreg V2I32:$Rs, v2i16)),
- (A2_combinew (A2_sxth (HiReg $Rs)), (A2_sxth (LoReg $Rs)))>;
-
-
-// Multiplies two v2i16 and returns a v2i32. We are using here the
-// saturating multiply, as hexagon does not provide a non saturating
-// vector multiply, and saturation does not impact the result that is
-// in double precision of the operands.
-
-// Multiplies two v2i16 vectors: as Hexagon does not have a multiply
-// with the C semantics for this one, this pattern uses the half word
-// multiply vmpyh that takes two v2i16 and returns a v2i32. This is
-// then truncated to fit this back into a v2i16 and to simulate the
-// wrap around semantics for unsigned in C.
-def vmpyh: OutPatFrag<(ops node:$Rs, node:$Rt),
- (M2_vmpy2s_s0 (i32 $Rs), (i32 $Rt))>;
-
-def: Pat<(v2i16 (mul V2I16:$Rs, V2I16:$Rt)),
- (LoReg (S2_vtrunewh (v2i32 (A2_combineii 0, 0)),
- (v2i32 (vmpyh V2I16:$Rs, V2I16:$Rt))))>;
-
-// Multiplies two v4i16 vectors.
-def: Pat<(v4i16 (mul V4I16:$Rs, V4I16:$Rt)),
- (S2_vtrunewh (vmpyh (HiReg $Rs), (HiReg $Rt)),
- (vmpyh (LoReg $Rs), (LoReg $Rt)))>;
-
-def VMPYB_no_V5: OutPatFrag<(ops node:$Rs, node:$Rt),
- (S2_vtrunewh (vmpyh (HiReg (S2_vsxtbh $Rs)), (HiReg (S2_vsxtbh $Rt))),
- (vmpyh (LoReg (S2_vsxtbh $Rs)), (LoReg (S2_vsxtbh $Rt))))>;
-
-// Multiplies two v4i8 vectors.
-def: Pat<(v4i8 (mul V4I8:$Rs, V4I8:$Rt)),
- (S2_vtrunehb (M5_vmpybsu V4I8:$Rs, V4I8:$Rt))>,
- Requires<[HasV5T]>;
-
-def: Pat<(v4i8 (mul V4I8:$Rs, V4I8:$Rt)),
- (S2_vtrunehb (VMPYB_no_V5 V4I8:$Rs, V4I8:$Rt))>;
-
-// Multiplies two v8i8 vectors.
-def: Pat<(v8i8 (mul V8I8:$Rs, V8I8:$Rt)),
- (A2_combinew (S2_vtrunehb (M5_vmpybsu (HiReg $Rs), (HiReg $Rt))),
- (S2_vtrunehb (M5_vmpybsu (LoReg $Rs), (LoReg $Rt))))>,
- Requires<[HasV5T]>;
-
-def: Pat<(v8i8 (mul V8I8:$Rs, V8I8:$Rt)),
- (A2_combinew (S2_vtrunehb (VMPYB_no_V5 (HiReg $Rs), (HiReg $Rt))),
- (S2_vtrunehb (VMPYB_no_V5 (LoReg $Rs), (LoReg $Rt))))>;
-
-
-class shuffler<SDNode Op, string Str>
- : SInst<(outs DoubleRegs:$a), (ins DoubleRegs:$b, DoubleRegs:$c),
- "$a = " # Str # "($b, $c)",
- [(set (i64 DoubleRegs:$a),
- (i64 (Op (i64 DoubleRegs:$b), (i64 DoubleRegs:$c))))],
- "", S_3op_tc_1_SLOT23>;
-
-def SDTHexagonBinOp64 : SDTypeProfile<1, 2,
- [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i64>]>;
-
-def HexagonSHUFFEB: SDNode<"HexagonISD::SHUFFEB", SDTHexagonBinOp64>;
-def HexagonSHUFFEH: SDNode<"HexagonISD::SHUFFEH", SDTHexagonBinOp64>;
-def HexagonSHUFFOB: SDNode<"HexagonISD::SHUFFOB", SDTHexagonBinOp64>;
-def HexagonSHUFFOH: SDNode<"HexagonISD::SHUFFOH", SDTHexagonBinOp64>;
-
-class ShufflePat<InstHexagon MI, SDNode Op>
- : Pat<(i64 (Op DoubleRegs:$src1, DoubleRegs:$src2)),
- (i64 (MI DoubleRegs:$src1, DoubleRegs:$src2))>;
-
-// Shuffles even bytes for i=0..3: A[2*i].b = C[2*i].b; A[2*i+1].b = B[2*i].b
-def: ShufflePat<S2_shuffeb, HexagonSHUFFEB>;
-
-// Shuffles odd bytes for i=0..3: A[2*i].b = C[2*i+1].b; A[2*i+1].b = B[2*i+1].b
-def: ShufflePat<S2_shuffob, HexagonSHUFFOB>;
-
-// Shuffles even half for i=0,1: A[2*i].h = C[2*i].h; A[2*i+1].h = B[2*i].h
-def: ShufflePat<S2_shuffeh, HexagonSHUFFEH>;
-
-// Shuffles odd half for i=0,1: A[2*i].h = C[2*i+1].h; A[2*i+1].h = B[2*i+1].h
-def: ShufflePat<S2_shuffoh, HexagonSHUFFOH>;
-
-
-// Truncated store from v4i16 to v4i8.
-def truncstorev4i8: PatFrag<(ops node:$val, node:$ptr),
- (truncstore node:$val, node:$ptr),
- [{ return cast<StoreSDNode>(N)->getMemoryVT() == MVT::v4i8; }]>;
-
-// Truncated store from v2i32 to v2i16.
-def truncstorev2i16: PatFrag<(ops node:$val, node:$ptr),
- (truncstore node:$val, node:$ptr),
- [{ return cast<StoreSDNode>(N)->getMemoryVT() == MVT::v2i16; }]>;
-
-def: Pat<(truncstorev2i16 V2I32:$Rs, I32:$Rt),
- (S2_storeri_io I32:$Rt, 0, (LoReg (S2_packhl (HiReg $Rs),
- (LoReg $Rs))))>;
-
-def: Pat<(truncstorev4i8 V4I16:$Rs, I32:$Rt),
- (S2_storeri_io I32:$Rt, 0, (S2_vtrunehb V4I16:$Rs))>;
-
-
-// Zero and sign extended load from v2i8 into v2i16.
-def zextloadv2i8: PatFrag<(ops node:$ptr), (zextload node:$ptr),
- [{ return cast<LoadSDNode>(N)->getMemoryVT() == MVT::v2i8; }]>;
-
-def sextloadv2i8: PatFrag<(ops node:$ptr), (sextload node:$ptr),
- [{ return cast<LoadSDNode>(N)->getMemoryVT() == MVT::v2i8; }]>;
-
-def: Pat<(v2i16 (zextloadv2i8 I32:$Rs)),
- (LoReg (v4i16 (S2_vzxtbh (L2_loadruh_io I32:$Rs, 0))))>;
-
-def: Pat<(v2i16 (sextloadv2i8 I32:$Rs)),
- (LoReg (v4i16 (S2_vsxtbh (L2_loadrh_io I32:$Rs, 0))))>;
-def: Pat<(v2i32 (zextloadv2i8 I32:$Rs)),
- (S2_vzxthw (LoReg (v4i16 (S2_vzxtbh (L2_loadruh_io I32:$Rs, 0)))))>;
-def: Pat<(v2i32 (sextloadv2i8 I32:$Rs)),
- (S2_vsxthw (LoReg (v4i16 (S2_vsxtbh (L2_loadrh_io I32:$Rs, 0)))))>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsics.td b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsics.td
index a319dd4..d4f303b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsics.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsics.td
@@ -774,13 +774,13 @@ def: T_RR_pat<A2_combine_hl, int_hexagon_A2_combine_hl>;
def: T_RR_pat<A2_combine_lh, int_hexagon_A2_combine_lh>;
def: T_RR_pat<A2_combine_ll, int_hexagon_A2_combine_ll>;
-def: T_II_pat<A2_combineii, int_hexagon_A2_combineii, s32ImmPred, s8ImmPred>;
+def: T_II_pat<A2_combineii, int_hexagon_A2_combineii, s32_0ImmPred, s8_0ImmPred>;
// Mux
def : T_QRR_pat<C2_mux, int_hexagon_C2_mux>;
-def : T_QRI_pat<C2_muxir, int_hexagon_C2_muxir, s32ImmPred>;
-def : T_QIR_pat<C2_muxri, int_hexagon_C2_muxri, s32ImmPred>;
-def : T_QII_pat<C2_muxii, int_hexagon_C2_muxii, s32ImmPred, s8ImmPred>;
+def : T_QRI_pat<C2_muxir, int_hexagon_C2_muxir, s32_0ImmPred>;
+def : T_QIR_pat<C2_muxri, int_hexagon_C2_muxri, s32_0ImmPred>;
+def : T_QII_pat<C2_muxii, int_hexagon_C2_muxii, s32_0ImmPred, s8_0ImmPred>;
// Shift halfword
def : T_R_pat<A2_aslh, int_hexagon_A2_aslh>;
@@ -801,17 +801,15 @@ def : T_Q_RR_pat<C2_cmpeq, int_hexagon_C2_cmpeq>;
def : T_Q_RR_pat<C2_cmpgt, int_hexagon_C2_cmpgt>;
def : T_Q_RR_pat<C2_cmpgtu, int_hexagon_C2_cmpgtu>;
-def : T_Q_RI_pat<C2_cmpeqi, int_hexagon_C2_cmpeqi, s32ImmPred>;
-def : T_Q_RI_pat<C2_cmpgti, int_hexagon_C2_cmpgti, s32ImmPred>;
-def : T_Q_RI_pat<C2_cmpgtui, int_hexagon_C2_cmpgtui, u32ImmPred>;
+def : T_Q_RI_pat<C2_cmpeqi, int_hexagon_C2_cmpeqi, s32_0ImmPred>;
+def : T_Q_RI_pat<C2_cmpgti, int_hexagon_C2_cmpgti, s32_0ImmPred>;
+def : T_Q_RI_pat<C2_cmpgtui, int_hexagon_C2_cmpgtui, u32_0ImmPred>;
-def : Pat <(int_hexagon_C2_cmpgei I32:$src1, s32ImmPred:$src2),
- (C2_tfrpr (C2_cmpgti I32:$src1,
- (DEC_CONST_SIGNED s32ImmPred:$src2)))>;
+def : Pat <(int_hexagon_C2_cmpgei I32:$src1, s32_0ImmPred:$src2),
+ (C2_tfrpr (C2_cmpgti I32:$src1, (SDEC1 s32_0ImmPred:$src2)))>;
-def : Pat <(int_hexagon_C2_cmpgeui I32:$src1, u32ImmPred:$src2),
- (C2_tfrpr (C2_cmpgtui I32:$src1,
- (DEC_CONST_UNSIGNED u32ImmPred:$src2)))>;
+def : Pat <(int_hexagon_C2_cmpgeui I32:$src1, u32_0ImmPred:$src2),
+ (C2_tfrpr (C2_cmpgtui I32:$src1, (UDEC1 u32_0ImmPred:$src2)))>;
def : Pat <(int_hexagon_C2_cmpgeui I32:$src, 0),
(C2_tfrpr (C2_cmpeq I32:$src, I32:$src))>;
@@ -1104,14 +1102,14 @@ def : Pat<(i64 (int_hexagon_S2_insertp_rp I64:$src1, I64:$src2, I64:$src3)),
(i64 (S2_insertp_rp I64:$src1, I64:$src2, I64:$src3))>;
def : Pat<(int_hexagon_S2_insert I32:$src1, I32:$src2,
- u5ImmPred:$src3, u5ImmPred:$src4),
+ u5_0ImmPred:$src3, u5_0ImmPred:$src4),
(S2_insert I32:$src1, I32:$src2,
- u5ImmPred:$src3, u5ImmPred:$src4)>;
+ u5_0ImmPred:$src3, u5_0ImmPred:$src4)>;
def : Pat<(i64 (int_hexagon_S2_insertp I64:$src1, I64:$src2,
- u6ImmPred:$src3, u6ImmPred:$src4)),
+ u6_0ImmPred:$src3, u6_0ImmPred:$src4)),
(i64 (S2_insertp I64:$src1, I64:$src2,
- u6ImmPred:$src3, u6ImmPred:$src4))>;
+ u6_0ImmPred:$src3, u6_0ImmPred:$src4))>;
// Innterleave/deinterleave
def : T_P_pat <S2_interleave, int_hexagon_S2_interleave>;
@@ -1239,10 +1237,19 @@ def : T_RI_pat <S2_asl_i_r_sat, int_hexagon_S2_asl_i_r_sat>;
//===----------------------------------------------------------------------===//
class S2op_tableidx_pat <Intrinsic IntID, InstHexagon OutputInst,
SDNodeXForm XformImm>
- : Pat <(IntID I32:$src1, I32:$src2, u4ImmPred:$src3, u5ImmPred:$src4),
- (OutputInst I32:$src1, I32:$src2, u4ImmPred:$src3,
- (XformImm u5ImmPred:$src4))>;
+ : Pat <(IntID I32:$src1, I32:$src2, u4_0ImmPred:$src3, u5_0ImmPred:$src4),
+ (OutputInst I32:$src1, I32:$src2, u4_0ImmPred:$src3,
+ (XformImm u5_0ImmPred:$src4))>;
+def SDEC2 : SDNodeXForm<imm, [{
+ int32_t V = N->getSExtValue();
+ return CurDAG->getTargetConstant(V-2, SDLoc(N), MVT::i32);
+}]>;
+
+def SDEC3 : SDNodeXForm<imm, [{
+ int32_t V = N->getSExtValue();
+ return CurDAG->getTargetConstant(V-3, SDLoc(N), MVT::i32);
+}]>;
// Table Index : Extract and insert bits.
// Map to the real hardware instructions after subtracting appropriate
@@ -1250,16 +1257,16 @@ class S2op_tableidx_pat <Intrinsic IntID, InstHexagon OutputInst,
// needed for int_hexagon_S2_tableidxb_goodsyntax.
def : Pat <(int_hexagon_S2_tableidxb_goodsyntax I32:$src1, I32:$src2,
- u4ImmPred:$src3, u5ImmPred:$src4),
+ u4_0ImmPred:$src3, u5_0ImmPred:$src4),
(S2_tableidxb I32:$src1, I32:$src2,
- u4ImmPred:$src3, u5ImmPred:$src4)>;
+ u4_0ImmPred:$src3, u5_0ImmPred:$src4)>;
def : S2op_tableidx_pat <int_hexagon_S2_tableidxh_goodsyntax, S2_tableidxh,
- DEC_CONST_SIGNED>;
+ SDEC1>;
def : S2op_tableidx_pat <int_hexagon_S2_tableidxw_goodsyntax, S2_tableidxw,
- DEC2_CONST_SIGNED>;
+ SDEC2>;
def : S2op_tableidx_pat <int_hexagon_S2_tableidxd_goodsyntax, S2_tableidxd,
- DEC3_CONST_SIGNED>;
+ SDEC3>;
//*******************************************************************
// STYPE/VH
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td
index 4c28b28..400c173 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td
@@ -20,21 +20,21 @@ def : Pat <(mul DoubleRegs:$src1, DoubleRegs:$src2),
(EXTRACT_SUBREG
(i64
(M2_dpmpyuu_s0 (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1),
- subreg_loreg)),
+ isub_lo)),
(i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2),
- subreg_loreg)))),
- subreg_hireg)),
- (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), subreg_loreg)),
- (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), subreg_hireg))),
- (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), subreg_loreg)),
- (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), subreg_hireg))),
+ isub_lo)))),
+ isub_hi)),
+ (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), isub_lo)),
+ (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), isub_hi))),
+ (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), isub_lo)),
+ (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), isub_hi))),
(i32
(EXTRACT_SUBREG
(i64
(M2_dpmpyuu_s0
- (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), subreg_loreg)),
+ (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), isub_lo)),
(i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2),
- subreg_loreg)))), subreg_loreg))))>;
+ isub_lo)))), isub_lo))))>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV4.td b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV4.td
index 578973d..2affe53 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV4.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV4.td
@@ -167,15 +167,15 @@ def : T_PPR_pat <A4_vrminuw, int_hexagon_A4_vrminuw>;
// Rotate and reduce bytes
def : Pat <(int_hexagon_S4_vrcrotate DoubleRegs:$src1, IntRegs:$src2,
- u2ImmPred:$src3),
- (S4_vrcrotate DoubleRegs:$src1, IntRegs:$src2, u2ImmPred:$src3)>;
+ u2_0ImmPred:$src3),
+ (S4_vrcrotate DoubleRegs:$src1, IntRegs:$src2, u2_0ImmPred:$src3)>;
// Rotate and reduce bytes with accumulation
// Rxx+=vrcrotate(Rss,Rt,#u2)
def : Pat <(int_hexagon_S4_vrcrotate_acc DoubleRegs:$src1, DoubleRegs:$src2,
- IntRegs:$src3, u2ImmPred:$src4),
+ IntRegs:$src3, u2_0ImmPred:$src4),
(S4_vrcrotate_acc DoubleRegs:$src1, DoubleRegs:$src2,
- IntRegs:$src3, u2ImmPred:$src4)>;
+ IntRegs:$src3, u2_0ImmPred:$src4)>;
// Vector conditional negate
def : T_PPR_pat<S2_vrcnegh, int_hexagon_S2_vrcnegh>;
@@ -223,17 +223,17 @@ def: T_RR_pat<A4_orn, int_hexagon_A4_orn>;
//*******************************************************************
// Combine Words Into Doublewords.
-def: T_RI_pat<A4_combineri, int_hexagon_A4_combineri, s32ImmPred>;
-def: T_IR_pat<A4_combineir, int_hexagon_A4_combineir, s32ImmPred>;
+def: T_RI_pat<A4_combineri, int_hexagon_A4_combineri, s32_0ImmPred>;
+def: T_IR_pat<A4_combineir, int_hexagon_A4_combineir, s32_0ImmPred>;
//*******************************************************************
// ALU32/PRED
//*******************************************************************
// Compare
-def : T_Q_RI_pat<C4_cmpneqi, int_hexagon_C4_cmpneqi, s32ImmPred>;
-def : T_Q_RI_pat<C4_cmpltei, int_hexagon_C4_cmpltei, s32ImmPred>;
-def : T_Q_RI_pat<C4_cmplteui, int_hexagon_C4_cmplteui, u32ImmPred>;
+def : T_Q_RI_pat<C4_cmpneqi, int_hexagon_C4_cmpneqi, s32_0ImmPred>;
+def : T_Q_RI_pat<C4_cmpltei, int_hexagon_C4_cmpltei, s32_0ImmPred>;
+def : T_Q_RI_pat<C4_cmplteui, int_hexagon_C4_cmplteui, u32_0ImmPred>;
// Compare To General Register.
def: T_Q_RR_pat<C4_cmpneq, int_hexagon_C4_cmpneq>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV60.td b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV60.td
index 82bc91b..a45e1c9 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV60.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonIntrinsicsV60.td
@@ -12,72 +12,21 @@
//===----------------------------------------------------------------------===//
-let isCodeGenOnly = 1 in {
-def HEXAGON_V6_vd0_pseudo : CVI_VA_Resource<(outs VectorRegs:$dst),
- (ins ),
- "$dst=#0",
- [(set VectorRegs:$dst, (int_hexagon_V6_vd0 ))]>;
-
-def HEXAGON_V6_vd0_pseudo_128B : CVI_VA_Resource<(outs VectorRegs128B:$dst),
- (ins ),
- "$dst=#0",
- [(set VectorRegs128B:$dst, (int_hexagon_V6_vd0_128B ))]>;
-}
-
-let isPseudo = 1 in
-def HEXAGON_V6_vassignp : CVI_VA_Resource<(outs VecDblRegs:$dst),
- (ins VecDblRegs:$src1),
- "$dst=vassignp_W($src1)",
- [(set VecDblRegs:$dst, (int_hexagon_V6_vassignp VecDblRegs:$src1))]>;
-
-let isPseudo = 1 in
-def HEXAGON_V6_vassignp_128B : CVI_VA_Resource<(outs VecDblRegs128B:$dst),
- (ins VecDblRegs128B:$src1),
- "$dst=vassignp_W_128B($src1)",
- [(set VecDblRegs128B:$dst, (int_hexagon_V6_vassignp_128B
- VecDblRegs128B:$src1))]>;
-
-let isPseudo = 1 in
-def HEXAGON_V6_lo : CVI_VA_Resource<(outs VectorRegs:$dst),
- (ins VecDblRegs:$src1),
- "$dst=lo_W($src1)",
- [(set VectorRegs:$dst, (int_hexagon_V6_lo VecDblRegs:$src1))]>;
-
-let isPseudo = 1 in
-def HEXAGON_V6_hi : CVI_VA_Resource<(outs VectorRegs:$dst),
- (ins VecDblRegs:$src1),
- "$dst=hi_W($src1)",
- [(set VectorRegs:$dst, (int_hexagon_V6_hi VecDblRegs:$src1))]>;
-
-let isPseudo = 1 in
-def HEXAGON_V6_lo_128B : CVI_VA_Resource<(outs VectorRegs128B:$dst),
- (ins VecDblRegs128B:$src1),
- "$dst=lo_W($src1)",
- [(set VectorRegs128B:$dst, (int_hexagon_V6_lo_128B VecDblRegs128B:$src1))]>;
-
-let isPseudo = 1 in
-def HEXAGON_V6_hi_128B : CVI_VA_Resource<(outs VectorRegs128B:$dst),
- (ins VecDblRegs128B:$src1),
- "$dst=hi_W($src1)",
- [(set VectorRegs128B:$dst, (int_hexagon_V6_hi_128B VecDblRegs128B:$src1))]>;
-
let AddedComplexity = 100 in {
def : Pat < (v16i32 (int_hexagon_V6_lo (v32i32 VecDblRegs:$src1))),
- (v16i32 (EXTRACT_SUBREG (v32i32 VecDblRegs:$src1), subreg_loreg)) >,
+ (v16i32 (EXTRACT_SUBREG (v32i32 VecDblRegs:$src1), vsub_lo)) >,
Requires<[UseHVXSgl]>;
def : Pat < (v16i32 (int_hexagon_V6_hi (v32i32 VecDblRegs:$src1))),
- (v16i32 (EXTRACT_SUBREG (v32i32 VecDblRegs:$src1), subreg_hireg)) >,
+ (v16i32 (EXTRACT_SUBREG (v32i32 VecDblRegs:$src1), vsub_hi)) >,
Requires<[UseHVXSgl]>;
def : Pat < (v32i32 (int_hexagon_V6_lo_128B (v64i32 VecDblRegs128B:$src1))),
- (v32i32 (EXTRACT_SUBREG (v64i32 VecDblRegs128B:$src1),
- subreg_loreg)) >,
+ (v32i32 (EXTRACT_SUBREG (v64i32 VecDblRegs128B:$src1), vsub_lo)) >,
Requires<[UseHVXDbl]>;
def : Pat < (v32i32 (int_hexagon_V6_hi_128B (v64i32 VecDblRegs128B:$src1))),
- (v32i32 (EXTRACT_SUBREG (v64i32 VecDblRegs128B:$src1),
- subreg_hireg)) >,
+ (v32i32 (EXTRACT_SUBREG (v64i32 VecDblRegs128B:$src1), vsub_hi)) >,
Requires<[UseHVXDbl]>;
}
@@ -204,6 +153,16 @@ multiclass T_V_pat <InstHexagon MI, Intrinsic IntID> {
Requires<[UseHVXDbl]>;
}
+multiclass T_W_pat <InstHexagon MI, Intrinsic IntID> {
+ def: Pat<(IntID VecDblRegs:$src1),
+ (MI VecDblRegs:$src1)>,
+ Requires<[UseHVXSgl]>;
+
+ def: Pat<(!cast<Intrinsic>(IntID#"_128B") VecDblRegs128B:$src1),
+ (!cast<InstHexagon>(MI#"_128B") VecDblRegs128B:$src1)>,
+ Requires<[UseHVXDbl]>;
+}
+
multiclass T_Q_pat <InstHexagon MI, Intrinsic IntID> {
def: Pat<(IntID VecPredRegs:$src1),
(MI VecPredRegs:$src1)>,
@@ -495,7 +454,7 @@ multiclass T_WVVR_pat <InstHexagon MI, Intrinsic IntID> {
Requires<[UseHVXDbl]>;
}
-defm : T_WR_pat<V6_vtmpyb, int_hexagon_V6_vtmpyb>;
+defm : T_WR_pat <V6_vtmpyb, int_hexagon_V6_vtmpyb>;
defm : T_WR_pat <V6_vtmpybus, int_hexagon_V6_vtmpybus>;
defm : T_VR_pat <V6_vdmpyhb, int_hexagon_V6_vdmpyhb>;
defm : T_VR_pat <V6_vrmpyub, int_hexagon_V6_vrmpyub>;
@@ -751,6 +710,10 @@ defm : T_V_pat <V6_vcl0h, int_hexagon_V6_vcl0h>;
defm : T_V_pat <V6_vnormamtw, int_hexagon_V6_vnormamtw>;
defm : T_V_pat <V6_vnormamth, int_hexagon_V6_vnormamth>;
+defm : T_W_pat <V6_lo, int_hexagon_V6_lo>;
+defm : T_W_pat <V6_hi, int_hexagon_V6_hi>;
+defm : T_W_pat <V6_vassignp, int_hexagon_V6_vassignp>;
+
defm : T_WRI_pat <V6_vrmpybusi, int_hexagon_V6_vrmpybusi>;
defm : T_WRI_pat <V6_vrsadubi, int_hexagon_V6_vrsadubi>;
defm : T_WRI_pat <V6_vrmpyubi, int_hexagon_V6_vrmpyubi>;
@@ -831,8 +794,10 @@ def : T_PPQ_pat <S2_cabacencbin, int_hexagon_S2_cabacencbin>;
def: Pat<(v64i16 (trunc v64i32:$Vdd)),
(v64i16 (V6_vpackwh_sat_128B
- (v32i32 (HEXAGON_V6_hi_128B VecDblRegs128B:$Vdd)),
- (v32i32 (HEXAGON_V6_lo_128B VecDblRegs128B:$Vdd))))>,
+ (v32i32 (V6_hi_128B VecDblRegs128B:$Vdd)),
+ (v32i32 (V6_lo_128B VecDblRegs128B:$Vdd))))>,
Requires<[UseHVXDbl]>;
+def: Pat<(int_hexagon_V6_vd0), (V6_vd0)>;
+def: Pat<(int_hexagon_V6_vd0_128B), (V6_vd0_128B)>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonIsetDx.td b/contrib/llvm/lib/Target/Hexagon/HexagonIsetDx.td
index 0ca95e9..ebedf2c 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonIsetDx.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonIsetDx.td
@@ -13,9 +13,9 @@
// SA1_combine1i: Combines.
let isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_combine1i: SUBInst <
+def SA1_combine1i: SUBInst <
(outs DoubleRegs:$Rdd),
- (ins u2Imm:$u2),
+ (ins u2_0Imm:$u2),
"$Rdd = combine(#1, #$u2)"> {
bits<3> Rdd;
bits<2> u2;
@@ -30,7 +30,7 @@ def V4_SA1_combine1i: SUBInst <
// SL2_jumpr31_f: Indirect conditional jump if false.
// SL2_jumpr31_f -> SL2_jumpr31_fnew
let Defs = [PC], Uses = [P0, R31], isCodeGenOnly = 1, isPredicated = 1, isPredicatedFalse = 1, isBranch = 1, isIndirectBranch = 1, hasSideEffects = 0 in
-def V4_SL2_jumpr31_f: SUBInst <
+def SL2_jumpr31_f: SUBInst <
(outs ),
(ins ),
"if (!p0) jumpr r31"> {
@@ -40,7 +40,7 @@ def V4_SL2_jumpr31_f: SUBInst <
// SL2_deallocframe: Deallocate stack frame.
let Defs = [R31, R29, R30], Uses = [R30], isCodeGenOnly = 1, mayLoad = 1, accessSize = DoubleWordAccess in
-def V4_SL2_deallocframe: SUBInst <
+def SL2_deallocframe: SUBInst <
(outs ),
(ins ),
"deallocframe"> {
@@ -51,7 +51,7 @@ def V4_SL2_deallocframe: SUBInst <
// SL2_return_f: Deallocate stack frame and return.
// SL2_return_f -> SL2_return_fnew
let Defs = [PC, R31, R29, R30], Uses = [R30, P0], isCodeGenOnly = 1, isPredicated = 1, isPredicatedFalse = 1, mayLoad = 1, accessSize = DoubleWordAccess, isBranch = 1, isIndirectBranch = 1 in
-def V4_SL2_return_f: SUBInst <
+def SL2_return_f: SUBInst <
(outs ),
(ins ),
"if (!p0) dealloc_return"> {
@@ -61,9 +61,9 @@ def V4_SL2_return_f: SUBInst <
// SA1_combine3i: Combines.
let isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_combine3i: SUBInst <
+def SA1_combine3i: SUBInst <
(outs DoubleRegs:$Rdd),
- (ins u2Imm:$u2),
+ (ins u2_0Imm:$u2),
"$Rdd = combine(#3, #$u2)"> {
bits<3> Rdd;
bits<2> u2;
@@ -77,7 +77,7 @@ def V4_SA1_combine3i: SUBInst <
// SS2_storebi0: Store byte.
let isCodeGenOnly = 1, mayStore = 1, accessSize = ByteAccess in
-def V4_SS2_storebi0: SUBInst <
+def SS2_storebi0: SUBInst <
(outs ),
(ins IntRegs:$Rs, u4_0Imm:$u4_0),
"memb($Rs + #$u4_0)=#0"> {
@@ -91,10 +91,10 @@ def V4_SS2_storebi0: SUBInst <
// SA1_clrtnew: Clear if true.
let Uses = [P0], isCodeGenOnly = 1, isPredicated = 1, isPredicatedNew = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_clrtnew: SUBInst <
+def SA1_clrtnew: SUBInst <
(outs IntRegs:$Rd),
- (ins ),
- "if (p0.new) $Rd = #0"> {
+ (ins PredRegs:$Pu),
+ "if ($Pu.new) $Rd = #0"> {
bits<4> Rd;
let Inst{12-9} = 0b1101;
@@ -104,7 +104,7 @@ def V4_SA1_clrtnew: SUBInst <
// SL2_loadruh_io: Load half.
let isCodeGenOnly = 1, mayLoad = 1, accessSize = HalfWordAccess, hasNewValue = 1, opNewValue = 0 in
-def V4_SL2_loadruh_io: SUBInst <
+def SL2_loadruh_io: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs, u3_1Imm:$u3_1),
"$Rd = memuh($Rs + #$u3_1)"> {
@@ -120,7 +120,7 @@ def V4_SL2_loadruh_io: SUBInst <
// SL2_jumpr31_tnew: Indirect conditional jump if true.
let Defs = [PC], Uses = [P0, R31], isCodeGenOnly = 1, isPredicated = 1, isPredicatedNew = 1, isBranch = 1, isIndirectBranch = 1, hasSideEffects = 0 in
-def V4_SL2_jumpr31_tnew: SUBInst <
+def SL2_jumpr31_tnew: SUBInst <
(outs ),
(ins ),
"if (p0.new) jumpr:nt r31"> {
@@ -130,9 +130,9 @@ def V4_SL2_jumpr31_tnew: SUBInst <
// SA1_addi: Add.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0, isExtendable = 1, isExtentSigned = 1, opExtentBits = 7, opExtendable = 2 in
-def V4_SA1_addi: SUBInst <
+def SA1_addi: SUBInst <
(outs IntRegs:$Rx),
- (ins IntRegs:$_src_, s7Ext:$s7),
+ (ins IntRegs:$_src_, s7_0Ext:$s7),
"$Rx = add($_src_, #$s7)" ,
[] ,
"$_src_ = $Rx"> {
@@ -146,7 +146,7 @@ def V4_SA1_addi: SUBInst <
// SL1_loadrub_io: Load byte.
let isCodeGenOnly = 1, mayLoad = 1, accessSize = ByteAccess, hasNewValue = 1, opNewValue = 0 in
-def V4_SL1_loadrub_io: SUBInst <
+def SL1_loadrub_io: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs, u4_0Imm:$u4_0),
"$Rd = memub($Rs + #$u4_0)"> {
@@ -162,7 +162,7 @@ def V4_SL1_loadrub_io: SUBInst <
// SL1_loadri_io: Load word.
let isCodeGenOnly = 1, mayLoad = 1, accessSize = WordAccess, hasNewValue = 1, opNewValue = 0 in
-def V4_SL1_loadri_io: SUBInst <
+def SL1_loadri_io: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs, u4_2Imm:$u4_2),
"$Rd = memw($Rs + #$u4_2)"> {
@@ -178,9 +178,9 @@ def V4_SL1_loadri_io: SUBInst <
// SA1_cmpeqi: Compareimmed.
let Defs = [P0], isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_cmpeqi: SUBInst <
+def SA1_cmpeqi: SUBInst <
(outs ),
- (ins IntRegs:$Rs, u2Imm:$u2),
+ (ins IntRegs:$Rs, u2_0Imm:$u2),
"p0 = cmp.eq($Rs, #$u2)"> {
bits<4> Rs;
bits<2> u2;
@@ -192,7 +192,7 @@ def V4_SA1_cmpeqi: SUBInst <
// SA1_combinerz: Combines.
let isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_combinerz: SUBInst <
+def SA1_combinerz: SUBInst <
(outs DoubleRegs:$Rdd),
(ins IntRegs:$Rs),
"$Rdd = combine($Rs, #0)"> {
@@ -209,7 +209,7 @@ def V4_SA1_combinerz: SUBInst <
// SL2_return_t: Deallocate stack frame and return.
// SL2_return_t -> SL2_return_tnew
let Defs = [PC, R31, R29, R30], Uses = [R30, P0], isCodeGenOnly = 1, isPredicated = 1, mayLoad = 1, accessSize = DoubleWordAccess, isBranch = 1, isIndirectBranch = 1 in
-def V4_SL2_return_t: SUBInst <
+def SL2_return_t: SUBInst <
(outs ),
(ins ),
"if (p0) dealloc_return"> {
@@ -219,7 +219,7 @@ def V4_SL2_return_t: SUBInst <
// SS2_allocframe: Allocate stack frame.
let Defs = [R29, R30], Uses = [R30, R31, R29], isCodeGenOnly = 1, mayStore = 1, accessSize = DoubleWordAccess in
-def V4_SS2_allocframe: SUBInst <
+def SS2_allocframe: SUBInst <
(outs ),
(ins u5_3Imm:$u5_3),
"allocframe(#$u5_3)"> {
@@ -231,7 +231,7 @@ def V4_SS2_allocframe: SUBInst <
// SS2_storeh_io: Store half.
let isCodeGenOnly = 1, mayStore = 1, accessSize = HalfWordAccess in
-def V4_SS2_storeh_io: SUBInst <
+def SS2_storeh_io: SUBInst <
(outs ),
(ins IntRegs:$Rs, u3_1Imm:$u3_1, IntRegs:$Rt),
"memh($Rs + #$u3_1) = $Rt"> {
@@ -247,7 +247,7 @@ def V4_SS2_storeh_io: SUBInst <
// SS2_storewi0: Store word.
let isCodeGenOnly = 1, mayStore = 1, accessSize = WordAccess in
-def V4_SS2_storewi0: SUBInst <
+def SS2_storewi0: SUBInst <
(outs ),
(ins IntRegs:$Rs, u4_2Imm:$u4_2),
"memw($Rs + #$u4_2)=#0"> {
@@ -261,7 +261,7 @@ def V4_SS2_storewi0: SUBInst <
// SS2_storewi1: Store word.
let isCodeGenOnly = 1, mayStore = 1, accessSize = WordAccess in
-def V4_SS2_storewi1: SUBInst <
+def SS2_storewi1: SUBInst <
(outs ),
(ins IntRegs:$Rs, u4_2Imm:$u4_2),
"memw($Rs + #$u4_2)=#1"> {
@@ -275,7 +275,7 @@ def V4_SS2_storewi1: SUBInst <
// SL2_jumpr31: Indirect conditional jump if true.
let Defs = [PC], Uses = [R31], isCodeGenOnly = 1, isBranch = 1, isIndirectBranch = 1, hasSideEffects = 0 in
-def V4_SL2_jumpr31: SUBInst <
+def SL2_jumpr31: SUBInst <
(outs ),
(ins ),
"jumpr r31"> {
@@ -285,7 +285,7 @@ def V4_SL2_jumpr31: SUBInst <
// SA1_combinezr: Combines.
let isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_combinezr: SUBInst <
+def SA1_combinezr: SUBInst <
(outs DoubleRegs:$Rdd),
(ins IntRegs:$Rs),
"$Rdd = combine(#0, $Rs)"> {
@@ -301,7 +301,7 @@ def V4_SA1_combinezr: SUBInst <
// SL2_loadrh_io: Load half.
let isCodeGenOnly = 1, mayLoad = 1, accessSize = HalfWordAccess, hasNewValue = 1, opNewValue = 0 in
-def V4_SL2_loadrh_io: SUBInst <
+def SL2_loadrh_io: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs, u3_1Imm:$u3_1),
"$Rd = memh($Rs + #$u3_1)"> {
@@ -317,7 +317,7 @@ def V4_SL2_loadrh_io: SUBInst <
// SA1_addrx: Add.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_addrx: SUBInst <
+def SA1_addrx: SUBInst <
(outs IntRegs:$Rx),
(ins IntRegs:$_src_, IntRegs:$Rs),
"$Rx = add($_src_, $Rs)" ,
@@ -333,10 +333,10 @@ def V4_SA1_addrx: SUBInst <
// SA1_setin1: Set to -1.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_setin1: SUBInst <
+def SA1_setin1: SUBInst <
(outs IntRegs:$Rd),
(ins ),
- "$Rd = #-1"> {
+ "$Rd = #{-1}"> {
bits<4> Rd;
let Inst{12-9} = 0b1101;
@@ -346,7 +346,7 @@ def V4_SA1_setin1: SUBInst <
// SA1_sxth: Sxth.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_sxth: SUBInst <
+def SA1_sxth: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = sxth($Rs)"> {
@@ -360,9 +360,9 @@ def V4_SA1_sxth: SUBInst <
// SA1_combine0i: Combines.
let isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_combine0i: SUBInst <
+def SA1_combine0i: SUBInst <
(outs DoubleRegs:$Rdd),
- (ins u2Imm:$u2),
+ (ins u2_0Imm:$u2),
"$Rdd = combine(#0, #$u2)"> {
bits<3> Rdd;
bits<2> u2;
@@ -376,9 +376,9 @@ def V4_SA1_combine0i: SUBInst <
// SA1_combine2i: Combines.
let isCodeGenOnly = 1, hasSideEffects = 0 in
-def V4_SA1_combine2i: SUBInst <
+def SA1_combine2i: SUBInst <
(outs DoubleRegs:$Rdd),
- (ins u2Imm:$u2),
+ (ins u2_0Imm:$u2),
"$Rdd = combine(#2, #$u2)"> {
bits<3> Rdd;
bits<2> u2;
@@ -392,7 +392,7 @@ def V4_SA1_combine2i: SUBInst <
// SA1_sxtb: Sxtb.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_sxtb: SUBInst <
+def SA1_sxtb: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = sxtb($Rs)"> {
@@ -407,10 +407,10 @@ def V4_SA1_sxtb: SUBInst <
// SA1_clrf: Clear if false.
// SA1_clrf -> SA1_clrfnew
let Uses = [P0], isCodeGenOnly = 1, isPredicated = 1, isPredicatedFalse = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_clrf: SUBInst <
+def SA1_clrf: SUBInst <
(outs IntRegs:$Rd),
- (ins ),
- "if (!p0) $Rd = #0"> {
+ (ins PredRegs:$Pu),
+ "if (!$Pu) $Rd = #0"> {
bits<4> Rd;
let Inst{12-9} = 0b1101;
@@ -420,7 +420,7 @@ def V4_SA1_clrf: SUBInst <
// SL2_loadrb_io: Load byte.
let isCodeGenOnly = 1, mayLoad = 1, accessSize = ByteAccess, hasNewValue = 1, opNewValue = 0 in
-def V4_SL2_loadrb_io: SUBInst <
+def SL2_loadrb_io: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs, u3_0Imm:$u3_0),
"$Rd = memb($Rs + #$u3_0)"> {
@@ -436,7 +436,7 @@ def V4_SL2_loadrb_io: SUBInst <
// SA1_tfr: Tfr.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_tfr: SUBInst <
+def SA1_tfr: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = $Rs"> {
@@ -450,7 +450,7 @@ def V4_SA1_tfr: SUBInst <
// SL2_loadrd_sp: Load dword.
let Uses = [R29], isCodeGenOnly = 1, mayLoad = 1, accessSize = DoubleWordAccess in
-def V4_SL2_loadrd_sp: SUBInst <
+def SL2_loadrd_sp: SUBInst <
(outs DoubleRegs:$Rdd),
(ins u5_3Imm:$u5_3),
"$Rdd = memd(r29 + #$u5_3)"> {
@@ -464,7 +464,7 @@ def V4_SL2_loadrd_sp: SUBInst <
// SA1_and1: And #1.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_and1: SUBInst <
+def SA1_and1: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = and($Rs, #1)"> {
@@ -478,7 +478,7 @@ def V4_SA1_and1: SUBInst <
// SS2_storebi1: Store byte.
let isCodeGenOnly = 1, mayStore = 1, accessSize = ByteAccess in
-def V4_SS2_storebi1: SUBInst <
+def SS2_storebi1: SUBInst <
(outs ),
(ins IntRegs:$Rs, u4_0Imm:$u4_0),
"memb($Rs + #$u4_0)=#1"> {
@@ -492,7 +492,7 @@ def V4_SS2_storebi1: SUBInst <
// SA1_inc: Inc.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_inc: SUBInst <
+def SA1_inc: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = add($Rs, #1)"> {
@@ -506,7 +506,7 @@ def V4_SA1_inc: SUBInst <
// SS2_stored_sp: Store dword.
let Uses = [R29], isCodeGenOnly = 1, mayStore = 1, accessSize = DoubleWordAccess in
-def V4_SS2_stored_sp: SUBInst <
+def SS2_stored_sp: SUBInst <
(outs ),
(ins s6_3Imm:$s6_3, DoubleRegs:$Rtt),
"memd(r29 + #$s6_3) = $Rtt"> {
@@ -520,7 +520,7 @@ def V4_SS2_stored_sp: SUBInst <
// SS2_storew_sp: Store word.
let Uses = [R29], isCodeGenOnly = 1, mayStore = 1, accessSize = WordAccess in
-def V4_SS2_storew_sp: SUBInst <
+def SS2_storew_sp: SUBInst <
(outs ),
(ins u5_2Imm:$u5_2, IntRegs:$Rt),
"memw(r29 + #$u5_2) = $Rt"> {
@@ -534,7 +534,7 @@ def V4_SS2_storew_sp: SUBInst <
// SL2_jumpr31_fnew: Indirect conditional jump if false.
let Defs = [PC], Uses = [P0, R31], isCodeGenOnly = 1, isPredicated = 1, isPredicatedFalse = 1, isPredicatedNew = 1, isBranch = 1, isIndirectBranch = 1, hasSideEffects = 0 in
-def V4_SL2_jumpr31_fnew: SUBInst <
+def SL2_jumpr31_fnew: SUBInst <
(outs ),
(ins ),
"if (!p0.new) jumpr:nt r31"> {
@@ -545,10 +545,10 @@ def V4_SL2_jumpr31_fnew: SUBInst <
// SA1_clrt: Clear if true.
// SA1_clrt -> SA1_clrtnew
let Uses = [P0], isCodeGenOnly = 1, isPredicated = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_clrt: SUBInst <
+def SA1_clrt: SUBInst <
(outs IntRegs:$Rd),
- (ins ),
- "if (p0) $Rd = #0"> {
+ (ins PredRegs:$Pu),
+ "if ($Pu) $Rd = #0"> {
bits<4> Rd;
let Inst{12-9} = 0b1101;
@@ -558,7 +558,7 @@ def V4_SA1_clrt: SUBInst <
// SL2_return: Deallocate stack frame and return.
let Defs = [PC, R31, R29, R30], Uses = [R30], isCodeGenOnly = 1, mayLoad = 1, accessSize = DoubleWordAccess, isBranch = 1, isIndirectBranch = 1 in
-def V4_SL2_return: SUBInst <
+def SL2_return: SUBInst <
(outs ),
(ins ),
"dealloc_return"> {
@@ -568,10 +568,10 @@ def V4_SL2_return: SUBInst <
// SA1_dec: Dec.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_dec: SUBInst <
+def SA1_dec: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
- "$Rd = add($Rs,#-1)"> {
+ "$Rd = add($Rs,#{-1})"> {
bits<4> Rd;
bits<4> Rs;
@@ -582,9 +582,9 @@ def V4_SA1_dec: SUBInst <
// SA1_seti: Set immed.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0, isExtendable = 1, isExtentSigned = 0, opExtentBits = 6, opExtendable = 1 in
-def V4_SA1_seti: SUBInst <
+def SA1_seti: SUBInst <
(outs IntRegs:$Rd),
- (ins u6Ext:$u6),
+ (ins u6_0Ext:$u6),
"$Rd = #$u6"> {
bits<4> Rd;
bits<6> u6;
@@ -597,7 +597,7 @@ def V4_SA1_seti: SUBInst <
// SL2_jumpr31_t: Indirect conditional jump if true.
// SL2_jumpr31_t -> SL2_jumpr31_tnew
let Defs = [PC], Uses = [P0, R31], isCodeGenOnly = 1, isPredicated = 1, isBranch = 1, isIndirectBranch = 1, hasSideEffects = 0 in
-def V4_SL2_jumpr31_t: SUBInst <
+def SL2_jumpr31_t: SUBInst <
(outs ),
(ins ),
"if (p0) jumpr r31"> {
@@ -607,10 +607,10 @@ def V4_SL2_jumpr31_t: SUBInst <
// SA1_clrfnew: Clear if false.
let Uses = [P0], isCodeGenOnly = 1, isPredicated = 1, isPredicatedFalse = 1, isPredicatedNew = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_clrfnew: SUBInst <
+def SA1_clrfnew: SUBInst <
(outs IntRegs:$Rd),
- (ins ),
- "if (!p0.new) $Rd = #0"> {
+ (ins PredRegs:$Pu),
+ "if (!$Pu.new) $Rd = #0"> {
bits<4> Rd;
let Inst{12-9} = 0b1101;
@@ -620,7 +620,7 @@ def V4_SA1_clrfnew: SUBInst <
// SS1_storew_io: Store word.
let isCodeGenOnly = 1, mayStore = 1, accessSize = WordAccess in
-def V4_SS1_storew_io: SUBInst <
+def SS1_storew_io: SUBInst <
(outs ),
(ins IntRegs:$Rs, u4_2Imm:$u4_2, IntRegs:$Rt),
"memw($Rs + #$u4_2) = $Rt"> {
@@ -636,7 +636,7 @@ def V4_SS1_storew_io: SUBInst <
// SA1_zxtb: Zxtb.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_zxtb: SUBInst <
+def SA1_zxtb: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = and($Rs, #255)"> {
@@ -650,7 +650,7 @@ def V4_SA1_zxtb: SUBInst <
// SA1_addsp: Add.
let Uses = [R29], isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_addsp: SUBInst <
+def SA1_addsp: SUBInst <
(outs IntRegs:$Rd),
(ins u6_2Imm:$u6_2),
"$Rd = add(r29, #$u6_2)"> {
@@ -664,7 +664,7 @@ def V4_SA1_addsp: SUBInst <
// SL2_loadri_sp: Load word.
let Uses = [R29], isCodeGenOnly = 1, mayLoad = 1, accessSize = WordAccess, hasNewValue = 1, opNewValue = 0 in
-def V4_SL2_loadri_sp: SUBInst <
+def SL2_loadri_sp: SUBInst <
(outs IntRegs:$Rd),
(ins u5_2Imm:$u5_2),
"$Rd = memw(r29 + #$u5_2)"> {
@@ -678,7 +678,7 @@ def V4_SL2_loadri_sp: SUBInst <
// SS1_storeb_io: Store byte.
let isCodeGenOnly = 1, mayStore = 1, accessSize = ByteAccess in
-def V4_SS1_storeb_io: SUBInst <
+def SS1_storeb_io: SUBInst <
(outs ),
(ins IntRegs:$Rs, u4_0Imm:$u4_0, IntRegs:$Rt),
"memb($Rs + #$u4_0) = $Rt"> {
@@ -694,7 +694,7 @@ def V4_SS1_storeb_io: SUBInst <
// SL2_return_tnew: Deallocate stack frame and return.
let Defs = [PC, R31, R29, R30], Uses = [R30, P0], isCodeGenOnly = 1, isPredicated = 1, isPredicatedNew = 1, mayLoad = 1, accessSize = DoubleWordAccess, isBranch = 1, isIndirectBranch = 1 in
-def V4_SL2_return_tnew: SUBInst <
+def SL2_return_tnew: SUBInst <
(outs ),
(ins ),
"if (p0.new) dealloc_return:nt"> {
@@ -704,7 +704,7 @@ def V4_SL2_return_tnew: SUBInst <
// SL2_return_fnew: Deallocate stack frame and return.
let Defs = [PC, R31, R29, R30], Uses = [R30, P0], isCodeGenOnly = 1, isPredicated = 1, isPredicatedFalse = 1, isPredicatedNew = 1, mayLoad = 1, accessSize = DoubleWordAccess, isBranch = 1, isIndirectBranch = 1 in
-def V4_SL2_return_fnew: SUBInst <
+def SL2_return_fnew: SUBInst <
(outs ),
(ins ),
"if (!p0.new) dealloc_return:nt"> {
@@ -714,7 +714,7 @@ def V4_SL2_return_fnew: SUBInst <
// SA1_zxth: Zxth.
let isCodeGenOnly = 1, hasSideEffects = 0, hasNewValue = 1, opNewValue = 0 in
-def V4_SA1_zxth: SUBInst <
+def SA1_zxth: SUBInst <
(outs IntRegs:$Rd),
(ins IntRegs:$Rs),
"$Rd = zxth($Rs)"> {
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonMachineFunctionInfo.h b/contrib/llvm/lib/Target/Hexagon/HexagonMachineFunctionInfo.h
index 26c5b63..d83bcbc 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonMachineFunctionInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonMachineFunctionInfo.h
@@ -15,45 +15,35 @@
namespace llvm {
- namespace Hexagon {
+namespace Hexagon {
+
const unsigned int StartPacket = 0x1;
const unsigned int EndPacket = 0x2;
- }
+} // end namespace Hexagon
/// Hexagon target-specific information for each MachineFunction.
class HexagonMachineFunctionInfo : public MachineFunctionInfo {
// SRetReturnReg - Some subtargets require that sret lowering includes
// returning the value of the returned struct in a register. This field
// holds the virtual register into which the sret argument is passed.
- unsigned SRetReturnReg;
- unsigned StackAlignBaseVReg; // Aligned-stack base register (virtual)
- unsigned StackAlignBasePhysReg; // (physical)
- std::vector<MachineInstr*> AllocaAdjustInsts;
+ unsigned SRetReturnReg = 0;
+ unsigned StackAlignBaseVReg = 0; // Aligned-stack base register (virtual)
+ unsigned StackAlignBasePhysReg = 0; // (physical)
int VarArgsFrameIndex;
- bool HasClobberLR;
- bool HasEHReturn;
+ bool HasClobberLR = false;
+ bool HasEHReturn = false;
std::map<const MachineInstr*, unsigned> PacketInfo;
virtual void anchor();
public:
- HexagonMachineFunctionInfo() : SRetReturnReg(0), StackAlignBaseVReg(0),
- StackAlignBasePhysReg(0), HasClobberLR(0), HasEHReturn(false) {}
+ HexagonMachineFunctionInfo() = default;
- HexagonMachineFunctionInfo(MachineFunction &MF) : SRetReturnReg(0),
- StackAlignBaseVReg(0), StackAlignBasePhysReg(0), HasClobberLR(0),
- HasEHReturn(false) {}
+ HexagonMachineFunctionInfo(MachineFunction &MF) {}
unsigned getSRetReturnReg() const { return SRetReturnReg; }
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
- void addAllocaAdjustInst(MachineInstr* MI) {
- AllocaAdjustInsts.push_back(MI);
- }
- const std::vector<MachineInstr*>& getAllocaAdjustInsts() {
- return AllocaAdjustInsts;
- }
-
void setVarArgsFrameIndex(int v) { VarArgsFrameIndex = v; }
int getVarArgsFrameIndex() { return VarArgsFrameIndex; }
@@ -83,6 +73,7 @@ public:
void setStackAlignBasePhysReg(unsigned R) { StackAlignBasePhysReg = R; }
unsigned getStackAlignBasePhysReg() const { return StackAlignBasePhysReg; }
};
-} // End llvm namespace
-#endif
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONMACHINEFUNCTIONINFO_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp
index 6dcac0d..9ff9d93 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp
@@ -51,6 +51,7 @@ using namespace llvm;
#define DEBUG_TYPE "misched"
+namespace {
class HexagonCallMutation : public ScheduleDAGMutation {
public:
void apply(ScheduleDAGInstrs *DAG) override;
@@ -58,6 +59,7 @@ private:
bool shouldTFRICallBind(const HexagonInstrInfo &HII,
const SUnit &Inst1, const SUnit &Inst2) const;
};
+} // end anonymous namespace
// Check if a call and subsequent A2_tfrpi instructions should maintain
// scheduling affinity. We are looking for the TFRI to be consumed in
@@ -72,7 +74,7 @@ bool HexagonCallMutation::shouldTFRICallBind(const HexagonInstrInfo &HII,
return false;
// TypeXTYPE are 64 bit operations.
- if (HII.getType(Inst2.getInstr()) == HexagonII::TypeXTYPE)
+ if (HII.getType(*Inst2.getInstr()) == HexagonII::TypeXTYPE)
return true;
return false;
}
@@ -168,7 +170,7 @@ bool VLIWResourceModel::isResourceAvailable(SUnit *SU) {
continue;
// Enable .cur formation.
- if (QII.mayBeCurLoad(Packet[i]->getInstr()))
+ if (QII.mayBeCurLoad(*Packet[i]->getInstr()))
continue;
for (SUnit::const_succ_iterator I = Packet[i]->Succs.begin(),
@@ -616,7 +618,7 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
if (!SU || SU->isScheduled)
return ResCount;
- MachineInstr *Instr = SU->getInstr();
+ MachineInstr &Instr = *SU->getInstr();
DEBUG(if (verbose) dbgs() << ((Q.getID() == TopQID) ? "(top|" : "(bot|"));
// Forced priority is high.
@@ -705,7 +707,7 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
// available for it.
auto &QST = DAG->MF.getSubtarget<HexagonSubtarget>();
auto &QII = *QST.getInstrInfo();
- if (SU->isInstr() && QII.mayBeCurLoad(SU->getInstr())) {
+ if (SU->isInstr() && QII.mayBeCurLoad(*SU->getInstr())) {
if (Q.getID() == TopQID && Top.ResourceModel->isResourceAvailable(SU)) {
ResCount += PriorityTwo;
DEBUG(if (verbose) dbgs() << "C|");
@@ -744,11 +746,11 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
// Check for stalls in the previous packet.
if (Q.getID() == TopQID) {
for (auto J : Top.ResourceModel->OldPacket)
- if (QII.producesStall(J->getInstr(), Instr))
+ if (QII.producesStall(*J->getInstr(), Instr))
ResCount -= PriorityOne;
} else {
for (auto J : Bot.ResourceModel->OldPacket)
- if (QII.producesStall(Instr, J->getInstr()))
+ if (QII.producesStall(Instr, *J->getInstr()))
ResCount -= PriorityOne;
}
}
@@ -841,8 +843,8 @@ pickNodeFromQueue(ReadyQueue &Q, const RegPressureTracker &RPTracker,
const MachineInstr *CandI = Candidate.SU->getInstr();
const InstrItineraryData *InstrItins = QST.getInstrItineraryData();
- unsigned InstrLatency = QII.getInstrTimingClassLatency(InstrItins, MI);
- unsigned CandLatency = QII.getInstrTimingClassLatency(InstrItins, CandI);
+ unsigned InstrLatency = QII.getInstrTimingClassLatency(InstrItins, *MI);
+ unsigned CandLatency = QII.getInstrTimingClassLatency(InstrItins, *CandI);
DEBUG(dbgs() << "TC Tie Breaker Cand: "
<< CandLatency << " Instr:" << InstrLatency << "\n"
<< *MI << *CandI << "\n");
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.h b/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.h
index 51c84a4..dc10028 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonMachineScheduler.h
@@ -94,9 +94,7 @@ public:
void savePacket();
unsigned getTotalPackets() const { return TotalPackets; }
- bool isInPacket(SUnit *SU) const {
- return std::find(Packet.begin(), Packet.end(), SU) != Packet.end();
- }
+ bool isInPacket(SUnit *SU) const { return is_contained(Packet, SU); }
};
/// Extend the standard ScheduleDAGMI to provide more context and override the
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
index 3ffb9cf..72d8011 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
@@ -29,7 +29,6 @@
#include "HexagonTargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LiveVariables.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
@@ -79,14 +78,12 @@ namespace {
MachineFunctionPass::getAnalysisUsage(AU);
}
- const char *getPassName() const override {
- return "Hexagon NewValueJump";
- }
+ StringRef getPassName() const override { return "Hexagon NewValueJump"; }
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -180,7 +177,7 @@ static bool commonChecksToProhibitNewValueJump(bool afterRA,
return false;
// if call in path, bail out.
- if (MII->getOpcode() == Hexagon::J2_call)
+ if (MII->isCall())
return false;
// if NVJ is running prior to RA, do the following checks.
@@ -189,9 +186,9 @@ static bool commonChecksToProhibitNewValueJump(bool afterRA,
// to new value jump. If they are in the path, bail out.
// KILL sets kill flag on the opcode. It also sets up a
// single register, out of pair.
- // %D0<def> = Hexagon_S2_lsr_r_p %D0<kill>, %R2<kill>
+ // %D0<def> = S2_lsr_r_p %D0<kill>, %R2<kill>
// %R0<def> = KILL %R0, %D0<imp-use,kill>
- // %P0<def> = CMPEQri %R0<kill>, 0
+ // %P0<def> = C2_cmpeqi %R0<kill>, 0
// PHI can be anything after RA.
// COPY can remateriaze things in between feeder, compare and nvj.
if (MII->getOpcode() == TargetOpcode::KILL ||
@@ -203,7 +200,7 @@ static bool commonChecksToProhibitNewValueJump(bool afterRA,
// of registers by individual passes in the backend. At this time,
// we don't know the scope of usage and definitions of these
// instructions.
- if (MII->getOpcode() == Hexagon::LDriw_pred ||
+ if (MII->getOpcode() == Hexagon::LDriw_pred ||
MII->getOpcode() == Hexagon::STriw_pred)
return false;
}
@@ -226,10 +223,23 @@ static bool canCompareBeNewValueJump(const HexagonInstrInfo *QII,
// range specified by the arch.
if (!secondReg) {
int64_t v = MI.getOperand(2).getImm();
+ bool Valid = false;
- if (!(isUInt<5>(v) || ((MI.getOpcode() == Hexagon::C2_cmpeqi ||
- MI.getOpcode() == Hexagon::C2_cmpgti) &&
- (v == -1))))
+ switch (MI.getOpcode()) {
+ case Hexagon::C2_cmpeqi:
+ case Hexagon::C2_cmpgti:
+ Valid = (isUInt<5>(v) || v == -1);
+ break;
+ case Hexagon::C2_cmpgtui:
+ Valid = isUInt<5>(v);
+ break;
+ case Hexagon::S2_tstbit_i:
+ case Hexagon::S4_ntstbit_i:
+ Valid = (v == 0);
+ break;
+ }
+
+ if (!Valid)
return false;
}
@@ -239,6 +249,11 @@ static bool canCompareBeNewValueJump(const HexagonInstrInfo *QII,
if (secondReg) {
cmpOp2 = MI.getOperand(2).getReg();
+ // If the same register appears as both operands, we cannot generate a new
+ // value compare. Only one operand may use the .new suffix.
+ if (cmpReg1 == cmpOp2)
+ return false;
+
// Make sure that that second register is not from COPY
// At machine code level, we don't need this, but if we decide
// to move new value jump prior to RA, we would be needing this.
@@ -255,6 +270,8 @@ static bool canCompareBeNewValueJump(const HexagonInstrInfo *QII,
++II ;
for (MachineBasicBlock::iterator localII = II; localII != end;
++localII) {
+ if (localII->isDebugValue())
+ continue;
// Check 1.
// If "common" checks fail, bail out.
@@ -449,7 +466,9 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Instr: "; MI.dump(); dbgs() << "\n");
if (!foundJump && (MI.getOpcode() == Hexagon::J2_jumpt ||
+ MI.getOpcode() == Hexagon::J2_jumptpt ||
MI.getOpcode() == Hexagon::J2_jumpf ||
+ MI.getOpcode() == Hexagon::J2_jumpfpt ||
MI.getOpcode() == Hexagon::J2_jumptnewpt ||
MI.getOpcode() == Hexagon::J2_jumptnew ||
MI.getOpcode() == Hexagon::J2_jumpfnewpt ||
@@ -472,7 +491,7 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) {
//if(LVs.isLiveOut(predReg, *MBB)) break;
// Get all the successors of this block - which will always
- // be 2. Check if the predicate register is live in in those
+ // be 2. Check if the predicate register is live-in in those
// successor. If yes, we can not delete the predicate -
// I am doing this only because LLVM does not provide LiveOut
// at the BB level.
@@ -580,8 +599,9 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) {
if (isSecondOpReg) {
// In case of CMPLT, or CMPLTU, or EQ with the second register
// to newify, swap the operands.
- if (cmpInstr->getOpcode() == Hexagon::C2_cmpeq &&
- feederReg == (unsigned) cmpOp2) {
+ unsigned COp = cmpInstr->getOpcode();
+ if ((COp == Hexagon::C2_cmpeq || COp == Hexagon::C4_cmpneq) &&
+ (feederReg == (unsigned) cmpOp2)) {
unsigned tmp = cmpReg1;
bool tmpIsKill = MO1IsKill;
cmpReg1 = cmpOp2;
@@ -647,16 +667,6 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) {
.addReg(cmpOp2, getKillRegState(MO2IsKill))
.addMBB(jmpTarget);
- else if ((cmpInstr->getOpcode() == Hexagon::C2_cmpeqi ||
- cmpInstr->getOpcode() == Hexagon::C2_cmpgti) &&
- cmpOp2 == -1 )
- // Corresponding new-value compare jump instructions don't have the
- // operand for -1 immediate value.
- NewMI = BuildMI(*MBB, jmpPos, dl,
- QII->get(opc))
- .addReg(cmpReg1, getKillRegState(MO1IsKill))
- .addMBB(jmpTarget);
-
else
NewMI = BuildMI(*MBB, jmpPos, dl,
QII->get(opc))
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonOperands.td b/contrib/llvm/lib/Target/Hexagon/HexagonOperands.td
index 11092d2..9833105 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonOperands.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonOperands.td
@@ -7,58 +7,53 @@
//
//===----------------------------------------------------------------------===//
-def s32ImmOperand : AsmOperandClass { let Name = "s32Imm"; }
+def s32_0ImmOperand : AsmOperandClass { let Name = "s32_0Imm"; }
def s23_2ImmOperand : AsmOperandClass { let Name = "s23_2Imm"; }
-def s8ImmOperand : AsmOperandClass { let Name = "s8Imm"; }
-def s8Imm64Operand : AsmOperandClass { let Name = "s8Imm64"; }
-def s6ImmOperand : AsmOperandClass { let Name = "s6Imm"; }
-def s4ImmOperand : AsmOperandClass { let Name = "s4Imm"; }
+def s8_0ImmOperand : AsmOperandClass { let Name = "s8_0Imm"; }
+def s8_0Imm64Operand : AsmOperandClass { let Name = "s8_0Imm64"; }
+def s6_0ImmOperand : AsmOperandClass { let Name = "s6_0Imm"; }
def s4_0ImmOperand : AsmOperandClass { let Name = "s4_0Imm"; }
def s4_1ImmOperand : AsmOperandClass { let Name = "s4_1Imm"; }
def s4_2ImmOperand : AsmOperandClass { let Name = "s4_2Imm"; }
def s4_3ImmOperand : AsmOperandClass { let Name = "s4_3Imm"; }
def s4_6ImmOperand : AsmOperandClass { let Name = "s4_6Imm"; }
def s3_6ImmOperand : AsmOperandClass { let Name = "s3_6Imm"; }
-def u64ImmOperand : AsmOperandClass { let Name = "u64Imm"; }
-def u32ImmOperand : AsmOperandClass { let Name = "u32Imm"; }
+def u64_0ImmOperand : AsmOperandClass { let Name = "u64_0Imm"; }
+def u32_0ImmOperand : AsmOperandClass { let Name = "u32_0Imm"; }
def u26_6ImmOperand : AsmOperandClass { let Name = "u26_6Imm"; }
-def u16ImmOperand : AsmOperandClass { let Name = "u16Imm"; }
def u16_0ImmOperand : AsmOperandClass { let Name = "u16_0Imm"; }
def u16_1ImmOperand : AsmOperandClass { let Name = "u16_1Imm"; }
def u16_2ImmOperand : AsmOperandClass { let Name = "u16_2Imm"; }
def u16_3ImmOperand : AsmOperandClass { let Name = "u16_3Imm"; }
def u11_3ImmOperand : AsmOperandClass { let Name = "u11_3Imm"; }
-def u10ImmOperand : AsmOperandClass { let Name = "u10Imm"; }
-def u9ImmOperand : AsmOperandClass { let Name = "u9Imm"; }
-def u8ImmOperand : AsmOperandClass { let Name = "u8Imm"; }
-def u7ImmOperand : AsmOperandClass { let Name = "u7Imm"; }
-def u6ImmOperand : AsmOperandClass { let Name = "u6Imm"; }
+def u10_0ImmOperand : AsmOperandClass { let Name = "u10_0Imm"; }
+def u9_0ImmOperand : AsmOperandClass { let Name = "u9_0Imm"; }
+def u8_0ImmOperand : AsmOperandClass { let Name = "u8_0Imm"; }
+def u7_0ImmOperand : AsmOperandClass { let Name = "u7_0Imm"; }
def u6_0ImmOperand : AsmOperandClass { let Name = "u6_0Imm"; }
def u6_1ImmOperand : AsmOperandClass { let Name = "u6_1Imm"; }
def u6_2ImmOperand : AsmOperandClass { let Name = "u6_2Imm"; }
def u6_3ImmOperand : AsmOperandClass { let Name = "u6_3Imm"; }
-def u5ImmOperand : AsmOperandClass { let Name = "u5Imm"; }
-def u4ImmOperand : AsmOperandClass { let Name = "u4Imm"; }
-def u3ImmOperand : AsmOperandClass { let Name = "u3Imm"; }
-def u2ImmOperand : AsmOperandClass { let Name = "u2Imm"; }
-def u1ImmOperand : AsmOperandClass { let Name = "u1Imm"; }
-def n8ImmOperand : AsmOperandClass { let Name = "n8Imm"; }
+def u5_0ImmOperand : AsmOperandClass { let Name = "u5_0Imm"; }
+def u4_0ImmOperand : AsmOperandClass { let Name = "u4_0Imm"; }
+def u3_0ImmOperand : AsmOperandClass { let Name = "u3_0Imm"; }
+def u2_0ImmOperand : AsmOperandClass { let Name = "u2_0Imm"; }
+def u1_0ImmOperand : AsmOperandClass { let Name = "u1_0Imm"; }
+def n8_0ImmOperand : AsmOperandClass { let Name = "n8_0Imm"; }
// Immediate operands.
let OperandType = "OPERAND_IMMEDIATE",
DecoderMethod = "unsignedImmDecoder" in {
- def s32Imm : Operand<i32> { let ParserMatchClass = s32ImmOperand;
- let DecoderMethod = "s32ImmDecoder"; }
+ def s32_0Imm : Operand<i32> { let ParserMatchClass = s32_0ImmOperand;
+ let DecoderMethod = "s32_0ImmDecoder"; }
def s23_2Imm : Operand<i32> { let ParserMatchClass = s23_2ImmOperand; }
- def s8Imm : Operand<i32> { let ParserMatchClass = s8ImmOperand;
- let DecoderMethod = "s8ImmDecoder"; }
- def s8Imm64 : Operand<i64> { let ParserMatchClass = s8Imm64Operand;
- let DecoderMethod = "s8ImmDecoder"; }
- def s6Imm : Operand<i32> { let ParserMatchClass = s6ImmOperand;
+ def s8_0Imm : Operand<i32> { let ParserMatchClass = s8_0ImmOperand;
+ let DecoderMethod = "s8_0ImmDecoder"; }
+ def s8_0Imm64 : Operand<i64> { let ParserMatchClass = s8_0Imm64Operand;
+ let DecoderMethod = "s8_0ImmDecoder"; }
+ def s6_0Imm : Operand<i32> { let ParserMatchClass = s6_0ImmOperand;
let DecoderMethod = "s6_0ImmDecoder"; }
def s6_3Imm : Operand<i32>;
- def s4Imm : Operand<i32> { let ParserMatchClass = s4ImmOperand;
- let DecoderMethod = "s4_0ImmDecoder"; }
def s4_0Imm : Operand<i32> { let ParserMatchClass = s4_0ImmOperand;
let DecoderMethod = "s4_0ImmDecoder"; }
def s4_1Imm : Operand<i32> { let ParserMatchClass = s4_1ImmOperand;
@@ -67,42 +62,37 @@ let OperandType = "OPERAND_IMMEDIATE",
let DecoderMethod = "s4_2ImmDecoder"; }
def s4_3Imm : Operand<i32> { let ParserMatchClass = s4_3ImmOperand;
let DecoderMethod = "s4_3ImmDecoder"; }
- def u64Imm : Operand<i64> { let ParserMatchClass = u64ImmOperand; }
- def u32Imm : Operand<i32> { let ParserMatchClass = u32ImmOperand; }
+ def u64_0Imm : Operand<i64> { let ParserMatchClass = u64_0ImmOperand; }
+ def u32_0Imm : Operand<i32> { let ParserMatchClass = u32_0ImmOperand; }
def u26_6Imm : Operand<i32> { let ParserMatchClass = u26_6ImmOperand; }
- def u16Imm : Operand<i32> { let ParserMatchClass = u16ImmOperand; }
def u16_0Imm : Operand<i32> { let ParserMatchClass = u16_0ImmOperand; }
def u16_1Imm : Operand<i32> { let ParserMatchClass = u16_1ImmOperand; }
def u16_2Imm : Operand<i32> { let ParserMatchClass = u16_2ImmOperand; }
def u16_3Imm : Operand<i32> { let ParserMatchClass = u16_3ImmOperand; }
def u11_3Imm : Operand<i32> { let ParserMatchClass = u11_3ImmOperand; }
- def u10Imm : Operand<i32> { let ParserMatchClass = u10ImmOperand; }
- def u9Imm : Operand<i32> { let ParserMatchClass = u9ImmOperand; }
- def u8Imm : Operand<i32> { let ParserMatchClass = u8ImmOperand; }
- def u7Imm : Operand<i32> { let ParserMatchClass = u7ImmOperand; }
- def u6Imm : Operand<i32> { let ParserMatchClass = u6ImmOperand; }
+ def u10_0Imm : Operand<i32> { let ParserMatchClass = u10_0ImmOperand; }
+ def u9_0Imm : Operand<i32> { let ParserMatchClass = u9_0ImmOperand; }
+ def u8_0Imm : Operand<i32> { let ParserMatchClass = u8_0ImmOperand; }
+ def u7_0Imm : Operand<i32> { let ParserMatchClass = u7_0ImmOperand; }
def u6_0Imm : Operand<i32> { let ParserMatchClass = u6_0ImmOperand; }
def u6_1Imm : Operand<i32> { let ParserMatchClass = u6_1ImmOperand; }
def u6_2Imm : Operand<i32> { let ParserMatchClass = u6_2ImmOperand; }
def u6_3Imm : Operand<i32> { let ParserMatchClass = u6_3ImmOperand; }
- def u5Imm : Operand<i32> { let ParserMatchClass = u5ImmOperand; }
- def u5_0Imm : Operand<i32>;
+ def u5_0Imm : Operand<i32> { let ParserMatchClass = u5_0ImmOperand; }
def u5_1Imm : Operand<i32>;
def u5_2Imm : Operand<i32>;
def u5_3Imm : Operand<i32>;
- def u4Imm : Operand<i32> { let ParserMatchClass = u4ImmOperand; }
- def u4_0Imm : Operand<i32>;
+ def u4_0Imm : Operand<i32> { let ParserMatchClass = u4_0ImmOperand; }
def u4_1Imm : Operand<i32>;
def u4_2Imm : Operand<i32>;
def u4_3Imm : Operand<i32>;
- def u3Imm : Operand<i32> { let ParserMatchClass = u3ImmOperand; }
- def u3_0Imm : Operand<i32>;
+ def u3_0Imm : Operand<i32> { let ParserMatchClass = u3_0ImmOperand; }
def u3_1Imm : Operand<i32>;
def u3_2Imm : Operand<i32>;
def u3_3Imm : Operand<i32>;
- def u2Imm : Operand<i32> { let ParserMatchClass = u2ImmOperand; }
- def u1Imm : Operand<i32> { let ParserMatchClass = u1ImmOperand; }
- def n8Imm : Operand<i32> { let ParserMatchClass = n8ImmOperand; }
+ def u2_0Imm : Operand<i32> { let ParserMatchClass = u2_0ImmOperand; }
+ def u1_0Imm : Operand<i32> { let ParserMatchClass = u1_0ImmOperand; }
+ def n8_0Imm : Operand<i32> { let ParserMatchClass = n8_0ImmOperand; }
}
let OperandType = "OPERAND_IMMEDIATE" in {
@@ -117,15 +107,12 @@ let OperandType = "OPERAND_IMMEDIATE" in {
def s3_7Imm : Operand<i32> { let PrintMethod = "prints3_7ImmOperand";
let DecoderMethod = "s3_6ImmDecoder";}
}
+def n1ConstOperand : AsmOperandClass { let Name = "n1Const"; }
+def n1Const : Operand<i32> { let ParserMatchClass = n1ConstOperand; }
//
// Immediate predicates
//
-def s32ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isInt<32>(v);
-}]>;
-
def s32_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isInt<32>(v);
@@ -146,47 +133,22 @@ def s29_3ImmPred : PatLeaf<(i32 imm), [{
return isShiftedInt<29,3>(v);
}]>;
-def s16ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isInt<16>(v);
-}]>;
-
-def s11_0ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isInt<11>(v);
-}]>;
-
-def s11_1ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedInt<11,1>(v);
-}]>;
-
-def s11_2ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedInt<11,2>(v);
-}]>;
-
-def s11_3ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedInt<11,3>(v);
-}]>;
-
-def s10ImmPred : PatLeaf<(i32 imm), [{
+def s10_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isInt<10>(v);
}]>;
-def s8ImmPred : PatLeaf<(i32 imm), [{
+def s8_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isInt<8>(v);
}]>;
-def s8Imm64Pred : PatLeaf<(i64 imm), [{
+def s8_0Imm64Pred : PatLeaf<(i64 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isInt<8>(v);
}]>;
-def s6ImmPred : PatLeaf<(i32 imm), [{
+def s6_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isInt<6>(v);
}]>;
@@ -211,92 +173,31 @@ def s4_3ImmPred : PatLeaf<(i32 imm), [{
return isShiftedInt<4,3>(v);
}]>;
-def u64ImmPred : PatLeaf<(i64 imm), [{
- // Adding "N ||" to suppress gcc unused warning.
- return (N || true);
-}]>;
-
-def u32ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isUInt<32>(v);
-}]>;
-
def u32_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<32>(v);
}]>;
-def u31_1ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<31,1>(v);
-}]>;
-
-def u30_2ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<30,2>(v);
-}]>;
-
-def u29_3ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<29,3>(v);
-}]>;
-
-def u26_6ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<26,6>(v);
-}]>;
-
def u16_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<16>(v);
}]>;
-def u16_1ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<16,1>(v);
-}]>;
-
-def u16_2ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<16,2>(v);
-}]>;
-
def u11_3ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isShiftedUInt<11,3>(v);
}]>;
-def u10ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isUInt<10>(v);
-}]>;
-
-def u9ImmPred : PatLeaf<(i32 imm), [{
+def u9_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<9>(v);
}]>;
-def u8ImmPred : PatLeaf<(i32 imm), [{
+def u8_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<8>(v);
}]>;
-def u7StrictPosImmPred : ImmLeaf<i32, [{
- // u7StrictPosImmPred predicate - True if the immediate fits in an 7-bit
- // unsigned field and is strictly greater than 0.
- return isUInt<7>(Imm) && Imm > 0;
-}]>;
-
-def u7ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isUInt<7>(v);
-}]>;
-
-def u6ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isUInt<6>(v);
-}]>;
-
def u6_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<6>(v);
@@ -312,182 +213,87 @@ def u6_2ImmPred : PatLeaf<(i32 imm), [{
return isShiftedUInt<6,2>(v);
}]>;
-def u6_3ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isShiftedUInt<6,3>(v);
-}]>;
-
-def u5ImmPred : PatLeaf<(i32 imm), [{
+def u5_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<5>(v);
}]>;
-def u4ImmPred : PatLeaf<(i32 imm), [{
+def u4_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<4>(v);
}]>;
-def u3ImmPred : PatLeaf<(i32 imm), [{
+def u3_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<3>(v);
}]>;
-def u2ImmPred : PatLeaf<(i32 imm), [{
+def u2_0ImmPred : PatLeaf<(i32 imm), [{
int64_t v = (int64_t)N->getSExtValue();
return isUInt<2>(v);
}]>;
-def u1ImmPred : PatLeaf<(i1 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isUInt<1>(v);
-}]>;
-
-def u1ImmPred32 : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- return isUInt<1>(v);
-}]>;
-
-def m5ImmPred : PatLeaf<(i32 imm), [{
- // m5ImmPred predicate - True if the number is in range -1 .. -31
- // and will fit in a 5 bit field when made positive, for use in memops.
- int64_t v = (int64_t)N->getSExtValue();
- return (-31 <= v && v <= -1);
-}]>;
-
-//InN means negative integers in [-(2^N - 1), 0]
-def n8ImmPred : PatLeaf<(i32 imm), [{
- // n8ImmPred predicate - True if the immediate fits in a 8-bit signed
- // field.
- int64_t v = (int64_t)N->getSExtValue();
- return (-255 <= v && v <= 0);
-}]>;
-
-def nOneImmPred : PatLeaf<(i32 imm), [{
- // nOneImmPred predicate - True if the immediate is -1.
- int64_t v = (int64_t)N->getSExtValue();
- return (-1 == v);
-}]>;
-
-def Set5ImmPred : PatLeaf<(i32 imm), [{
- // Set5ImmPred predicate - True if the number is in the series of values.
- // [ 2^0, 2^1, ... 2^31 ]
- // For use in setbit immediate.
- uint32_t v = (int32_t)N->getSExtValue();
- // Constrain to 32 bits, and then check for single bit.
- return ImmIsSingleBit(v);
-}]>;
-
-def Clr5ImmPred : PatLeaf<(i32 imm), [{
- // Clr5ImmPred predicate - True if the number is in the series of
- // bit negated values.
- // [ 2^0, 2^1, ... 2^31 ]
- // For use in clrbit immediate.
- // Note: we are bit NOTing the value.
- uint32_t v = ~ (int32_t)N->getSExtValue();
- // Constrain to 32 bits, and then check for single bit.
- return ImmIsSingleBit(v);
-}]>;
-
// Extendable immediate operands.
def f32ExtOperand : AsmOperandClass { let Name = "f32Ext"; }
-def s16ExtOperand : AsmOperandClass { let Name = "s16Ext"; }
-def s12ExtOperand : AsmOperandClass { let Name = "s12Ext"; }
-def s10ExtOperand : AsmOperandClass { let Name = "s10Ext"; }
-def s9ExtOperand : AsmOperandClass { let Name = "s9Ext"; }
-def s8ExtOperand : AsmOperandClass { let Name = "s8Ext"; }
-def s7ExtOperand : AsmOperandClass { let Name = "s7Ext"; }
-def s6ExtOperand : AsmOperandClass { let Name = "s6Ext"; }
+def s16_0ExtOperand : AsmOperandClass { let Name = "s16_0Ext"; }
+def s12_0ExtOperand : AsmOperandClass { let Name = "s12_0Ext"; }
+def s10_0ExtOperand : AsmOperandClass { let Name = "s10_0Ext"; }
+def s9_0ExtOperand : AsmOperandClass { let Name = "s9_0Ext"; }
+def s8_0ExtOperand : AsmOperandClass { let Name = "s8_0Ext"; }
+def s7_0ExtOperand : AsmOperandClass { let Name = "s7_0Ext"; }
+def s6_0ExtOperand : AsmOperandClass { let Name = "s6_0Ext"; }
def s11_0ExtOperand : AsmOperandClass { let Name = "s11_0Ext"; }
def s11_1ExtOperand : AsmOperandClass { let Name = "s11_1Ext"; }
def s11_2ExtOperand : AsmOperandClass { let Name = "s11_2Ext"; }
def s11_3ExtOperand : AsmOperandClass { let Name = "s11_3Ext"; }
-def u6ExtOperand : AsmOperandClass { let Name = "u6Ext"; }
-def u7ExtOperand : AsmOperandClass { let Name = "u7Ext"; }
-def u8ExtOperand : AsmOperandClass { let Name = "u8Ext"; }
-def u9ExtOperand : AsmOperandClass { let Name = "u9Ext"; }
-def u10ExtOperand : AsmOperandClass { let Name = "u10Ext"; }
def u6_0ExtOperand : AsmOperandClass { let Name = "u6_0Ext"; }
+def u7_0ExtOperand : AsmOperandClass { let Name = "u7_0Ext"; }
+def u8_0ExtOperand : AsmOperandClass { let Name = "u8_0Ext"; }
+def u9_0ExtOperand : AsmOperandClass { let Name = "u9_0Ext"; }
+def u10_0ExtOperand : AsmOperandClass { let Name = "u10_0Ext"; }
def u6_1ExtOperand : AsmOperandClass { let Name = "u6_1Ext"; }
def u6_2ExtOperand : AsmOperandClass { let Name = "u6_2Ext"; }
def u6_3ExtOperand : AsmOperandClass { let Name = "u6_3Ext"; }
-def u32MustExtOperand : AsmOperandClass { let Name = "u32MustExt"; }
+def u32_0MustExtOperand : AsmOperandClass { let Name = "u32_0MustExt"; }
let OperandType = "OPERAND_IMMEDIATE", PrintMethod = "printExtOperand",
DecoderMethod = "unsignedImmDecoder" in {
def f32Ext : Operand<f32> { let ParserMatchClass = f32ExtOperand; }
- def s16Ext : Operand<i32> { let ParserMatchClass = s16ExtOperand;
- let DecoderMethod = "s16ImmDecoder"; }
- def s12Ext : Operand<i32> { let ParserMatchClass = s12ExtOperand;
- let DecoderMethod = "s12ImmDecoder"; }
+ def s16_0Ext : Operand<i32> { let ParserMatchClass = s16_0ExtOperand;
+ let DecoderMethod = "s16_0ImmDecoder"; }
+ def s12_0Ext : Operand<i32> { let ParserMatchClass = s12_0ExtOperand;
+ let DecoderMethod = "s12_0ImmDecoder"; }
def s11_0Ext : Operand<i32> { let ParserMatchClass = s11_0ExtOperand;
- let DecoderMethod = "s11_0ImmDecoder"; }
+ let DecoderMethod = "s11_0ImmDecoder"; }
def s11_1Ext : Operand<i32> { let ParserMatchClass = s11_1ExtOperand;
- let DecoderMethod = "s11_1ImmDecoder"; }
+ let DecoderMethod = "s11_1ImmDecoder"; }
def s11_2Ext : Operand<i32> { let ParserMatchClass = s11_2ExtOperand;
- let DecoderMethod = "s11_2ImmDecoder"; }
+ let DecoderMethod = "s11_2ImmDecoder"; }
def s11_3Ext : Operand<i32> { let ParserMatchClass = s11_3ExtOperand;
- let DecoderMethod = "s11_3ImmDecoder"; }
- def s10Ext : Operand<i32> { let ParserMatchClass = s10ExtOperand;
- let DecoderMethod = "s10ImmDecoder"; }
- def s9Ext : Operand<i32> { let ParserMatchClass = s9ExtOperand;
- let DecoderMethod = "s90ImmDecoder"; }
- def s8Ext : Operand<i32> { let ParserMatchClass = s8ExtOperand;
- let DecoderMethod = "s8ImmDecoder"; }
- def s7Ext : Operand<i32> { let ParserMatchClass = s7ExtOperand; }
- def s6Ext : Operand<i32> { let ParserMatchClass = s6ExtOperand;
- let DecoderMethod = "s6_0ImmDecoder"; }
- def u6Ext : Operand<i32> { let ParserMatchClass = u6ExtOperand; }
- def u7Ext : Operand<i32> { let ParserMatchClass = u7ExtOperand; }
- def u8Ext : Operand<i32> { let ParserMatchClass = u8ExtOperand; }
- def u9Ext : Operand<i32> { let ParserMatchClass = u9ExtOperand; }
- def u10Ext : Operand<i32> { let ParserMatchClass = u10ExtOperand; }
+ let DecoderMethod = "s11_3ImmDecoder"; }
+ def s10_0Ext : Operand<i32> { let ParserMatchClass = s10_0ExtOperand;
+ let DecoderMethod = "s10_0ImmDecoder"; }
+ def s9_0Ext : Operand<i32> { let ParserMatchClass = s9_0ExtOperand;
+ let DecoderMethod = "s9_0ImmDecoder"; }
+ def s8_0Ext : Operand<i32> { let ParserMatchClass = s8_0ExtOperand;
+ let DecoderMethod = "s8_0ImmDecoder"; }
+ def s7_0Ext : Operand<i32> { let ParserMatchClass = s7_0ExtOperand; }
+ def s6_0Ext : Operand<i32> { let ParserMatchClass = s6_0ExtOperand;
+ let DecoderMethod = "s6_0ImmDecoder"; }
+ def u7_0Ext : Operand<i32> { let ParserMatchClass = u7_0ExtOperand; }
+ def u8_0Ext : Operand<i32> { let ParserMatchClass = u8_0ExtOperand; }
+ def u9_0Ext : Operand<i32> { let ParserMatchClass = u9_0ExtOperand; }
+ def u10_0Ext : Operand<i32> { let ParserMatchClass = u10_0ExtOperand; }
def u6_0Ext : Operand<i32> { let ParserMatchClass = u6_0ExtOperand; }
def u6_1Ext : Operand<i32> { let ParserMatchClass = u6_1ExtOperand; }
def u6_2Ext : Operand<i32> { let ParserMatchClass = u6_2ExtOperand; }
def u6_3Ext : Operand<i32> { let ParserMatchClass = u6_3ExtOperand; }
- def u32MustExt : Operand<i32> { let ParserMatchClass = u32MustExtOperand; }
+ def u32_0MustExt : Operand<i32> { let ParserMatchClass = u32_0MustExtOperand; }
}
-def s4_7ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- if (HST->hasV60TOps())
- // Return true if the immediate can fit in a 10-bit sign extended field and
- // is 128-byte aligned.
- return isShiftedInt<4,7>(v);
- return false;
-}]>;
-
-def s3_7ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- if (HST->hasV60TOps())
- // Return true if the immediate can fit in a 9-bit sign extended field and
- // is 128-byte aligned.
- return isShiftedInt<3,7>(v);
- return false;
-}]>;
-
-def s4_6ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- if (HST->hasV60TOps())
- // Return true if the immediate can fit in a 10-bit sign extended field and
- // is 64-byte aligned.
- return isShiftedInt<4,6>(v);
- return false;
-}]>;
-
-def s3_6ImmPred : PatLeaf<(i32 imm), [{
- int64_t v = (int64_t)N->getSExtValue();
- if (HST->hasV60TOps())
- // Return true if the immediate can fit in a 9-bit sign extended field and
- // is 64-byte aligned.
- return isShiftedInt<3,6>(v);
- return false;
-}]>;
-
-
// This complex pattern exists only to create a machine instruction operand
// of type "frame index". There doesn't seem to be a way to do that directly
// in the patterns.
@@ -524,12 +330,3 @@ def calltarget : Operand<i32> {
def bblabel : Operand<i32>;
def bbl : SDNode<"ISD::BasicBlock", SDTPtrLeaf, [], "BasicBlockSDNode">;
-
-// Return true if for a 32 to 64-bit sign-extended load.
-def is_sext_i32 : PatLeaf<(i64 DoubleRegs:$src1), [{
- LoadSDNode *LD = dyn_cast<LoadSDNode>(N);
- if (!LD)
- return false;
- return LD->getExtensionType() == ISD::SEXTLOAD &&
- LD->getMemoryVT().getScalarType() == MVT::i32;
-}]>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp
index 4dff0db..89db467 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp
@@ -12,24 +12,30 @@
#define DEBUG_TYPE "opt-addr-mode"
-#include "HexagonTargetMachine.h"
+#include "HexagonInstrInfo.h"
+#include "HexagonSubtarget.h"
+#include "MCTargetDesc/HexagonBaseInfo.h"
#include "RDFGraph.h"
#include "RDFLiveness.h"
-
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominanceFrontier.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <cstdint>
+#include <map>
static cl::opt<int> CodeGrowthLimit("hexagon-amode-growth-limit",
cl::Hidden, cl::init(0), cl::desc("Code growth limit for address mode "
@@ -39,28 +45,36 @@ using namespace llvm;
using namespace rdf;
namespace llvm {
+
FunctionPass *createHexagonOptAddrMode();
void initializeHexagonOptAddrModePass(PassRegistry &);
-}
+
+} // end namespace llvm
namespace {
+
class HexagonOptAddrMode : public MachineFunctionPass {
public:
static char ID;
+
HexagonOptAddrMode()
- : MachineFunctionPass(ID), HII(0), MDT(0), DFG(0), LV(0) {
+ : MachineFunctionPass(ID), HII(nullptr), MDT(nullptr), DFG(nullptr),
+ LV(nullptr) {
PassRegistry &R = *PassRegistry::getPassRegistry();
initializeHexagonOptAddrModePass(R);
}
- const char *getPassName() const override {
+
+ StringRef getPassName() const override {
return "Optimize addressing mode of load/store";
}
+
void getAnalysisUsage(AnalysisUsage &AU) const override {
MachineFunctionPass::getAnalysisUsage(AU);
AU.addRequired<MachineDominatorTree>();
AU.addRequired<MachineDominanceFrontier>();
AU.setPreservesAll();
}
+
bool runOnMachineFunction(MachineFunction &MF) override;
private:
@@ -79,12 +93,12 @@ private:
NodeAddr<UseNode *> UseN, unsigned UseMOnum);
bool analyzeUses(unsigned DefR, const NodeList &UNodeList,
InstrEvalMap &InstrEvalResult, short &SizeInc);
- bool hasRepForm(MachineInstr *MI, unsigned TfrDefR);
- bool canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, MachineInstr *MI,
+ bool hasRepForm(MachineInstr &MI, unsigned TfrDefR);
+ bool canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, MachineInstr &MI,
const NodeList &UNodeList);
void getAllRealUses(NodeAddr<StmtNode *> SN, NodeList &UNodeList);
bool allValidCandidates(NodeAddr<StmtNode *> SA, NodeList &UNodeList);
- short getBaseWithLongOffset(const MachineInstr *MI) const;
+ short getBaseWithLongOffset(const MachineInstr &MI) const;
void updateMap(NodeAddr<InstrNode *> IA);
bool constructDefMap(MachineBasicBlock *B);
bool changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
@@ -93,7 +107,8 @@ private:
bool changeAddAsl(NodeAddr<UseNode *> AddAslUN, MachineInstr *AddAslMI,
const MachineOperand &ImmOp, unsigned ImmOpNum);
};
-}
+
+} // end anonymous namespace
char HexagonOptAddrMode::ID = 0;
@@ -104,14 +119,14 @@ INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
INITIALIZE_PASS_END(HexagonOptAddrMode, "opt-amode", "Optimize addressing mode",
false, false)
-bool HexagonOptAddrMode::hasRepForm(MachineInstr *MI, unsigned TfrDefR) {
- const MCInstrDesc &MID = MI->getDesc();
+bool HexagonOptAddrMode::hasRepForm(MachineInstr &MI, unsigned TfrDefR) {
+ const MCInstrDesc &MID = MI.getDesc();
- if ((!MID.mayStore() && !MID.mayLoad()) || HII->isPredicated(*MI))
+ if ((!MID.mayStore() && !MID.mayLoad()) || HII->isPredicated(MI))
return false;
if (MID.mayStore()) {
- MachineOperand StOp = MI->getOperand(MI->getNumOperands() - 1);
+ MachineOperand StOp = MI.getOperand(MI.getNumOperands() - 1);
if (StOp.isReg() && StOp.getReg() == TfrDefR)
return false;
}
@@ -137,18 +152,18 @@ bool HexagonOptAddrMode::hasRepForm(MachineInstr *MI, unsigned TfrDefR) {
// Above three instructions can be replaced with Rd = memw(Rt<<#2 + ##foo+28)
bool HexagonOptAddrMode::canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN,
- MachineInstr *MI,
+ MachineInstr &MI,
const NodeList &UNodeList) {
// check offset size in addasl. if 'offset > 3' return false
- const MachineOperand &OffsetOp = MI->getOperand(3);
+ const MachineOperand &OffsetOp = MI.getOperand(3);
if (!OffsetOp.isImm() || OffsetOp.getImm() > 3)
return false;
- unsigned OffsetReg = MI->getOperand(2).getReg();
+ unsigned OffsetReg = MI.getOperand(2).getReg();
RegisterRef OffsetRR;
NodeId OffsetRegRD = 0;
for (NodeAddr<UseNode *> UA : AddAslSN.Addr->members_if(DFG->IsUse, *DFG)) {
- RegisterRef RR = UA.Addr->getRegRef();
+ RegisterRef RR = UA.Addr->getRegRef(*DFG);
if (OffsetReg == RR.Reg) {
OffsetRR = RR;
OffsetRegRD = UA.Addr->getReachingDef();
@@ -162,25 +177,25 @@ bool HexagonOptAddrMode::canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN,
RDefMap[OffsetRR][IA.Id] != OffsetRegRD)
return false;
- MachineInstr *UseMI = NodeAddr<StmtNode *>(IA).Addr->getCode();
+ MachineInstr &UseMI = *NodeAddr<StmtNode *>(IA).Addr->getCode();
NodeAddr<DefNode *> OffsetRegDN = DFG->addr<DefNode *>(OffsetRegRD);
// Reaching Def to an offset register can't be a phi.
if ((OffsetRegDN.Addr->getFlags() & NodeAttrs::PhiRef) &&
- MI->getParent() != UseMI->getParent())
+ MI.getParent() != UseMI.getParent())
return false;
- const MCInstrDesc &UseMID = UseMI->getDesc();
+ const MCInstrDesc &UseMID = UseMI.getDesc();
if ((!UseMID.mayLoad() && !UseMID.mayStore()) ||
HII->getAddrMode(UseMI) != HexagonII::BaseImmOffset ||
getBaseWithLongOffset(UseMI) < 0)
return false;
// Addasl output can't be a store value.
- if (UseMID.mayStore() && UseMI->getOperand(2).isReg() &&
- UseMI->getOperand(2).getReg() == MI->getOperand(0).getReg())
+ if (UseMID.mayStore() && UseMI.getOperand(2).isReg() &&
+ UseMI.getOperand(2).getReg() == MI.getOperand(0).getReg())
return false;
- for (auto &Mo : UseMI->operands())
+ for (auto &Mo : UseMI.operands())
if (Mo.isFI())
return false;
}
@@ -191,7 +206,7 @@ bool HexagonOptAddrMode::allValidCandidates(NodeAddr<StmtNode *> SA,
NodeList &UNodeList) {
for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
NodeAddr<UseNode *> UN = *I;
- RegisterRef UR = UN.Addr->getRegRef();
+ RegisterRef UR = UN.Addr->getRegRef(*DFG);
NodeSet Visited, Defs;
const auto &ReachingDefs = LV->getAllReachingDefsRec(UR, UN, Visited, Defs);
if (ReachingDefs.size() > 1) {
@@ -215,7 +230,8 @@ void HexagonOptAddrMode::getAllRealUses(NodeAddr<StmtNode *> SA,
for (NodeAddr<DefNode *> DA : SA.Addr->members_if(DFG->IsDef, *DFG)) {
DEBUG(dbgs() << "\t\t[DefNode]: " << Print<NodeAddr<DefNode *>>(DA, *DFG)
<< "\n");
- RegisterRef DR = DA.Addr->getRegRef();
+ RegisterRef DR = DFG->normalizeRef(DA.Addr->getRegRef(*DFG));
+
auto UseSet = LV->getAllReachedUses(DR, DA);
for (auto UI : UseSet) {
@@ -232,13 +248,13 @@ void HexagonOptAddrMode::getAllRealUses(NodeAddr<StmtNode *> SA,
const Liveness::RefMap &phiUse = LV->getRealUses(id);
DEBUG(dbgs() << "\t\t\t\tphi real Uses"
<< Print<Liveness::RefMap>(phiUse, *DFG) << "\n");
- if (phiUse.size() > 0) {
+ if (!phiUse.empty()) {
for (auto I : phiUse) {
- if (DR != I.first)
+ if (DR.Reg != I.first)
continue;
auto phiUseSet = I.second;
for (auto phiUI : phiUseSet) {
- NodeAddr<UseNode *> phiUA = DFG->addr<UseNode *>(phiUI);
+ NodeAddr<UseNode *> phiUA = DFG->addr<UseNode *>(phiUI.first);
UNodeList.push_back(phiUA);
}
}
@@ -261,8 +277,8 @@ bool HexagonOptAddrMode::analyzeUses(unsigned tfrDefR,
bool CanBeReplaced = false;
NodeAddr<UseNode *> UN = *I;
NodeAddr<StmtNode *> SN = UN.Addr->getOwner(*DFG);
- MachineInstr *MI = SN.Addr->getCode();
- const MCInstrDesc &MID = MI->getDesc();
+ MachineInstr &MI = *SN.Addr->getCode();
+ const MCInstrDesc &MID = MI.getDesc();
if ((MID.mayLoad() || MID.mayStore())) {
if (!hasRepForm(MI, tfrDefR)) {
KeepTfr = true;
@@ -270,10 +286,10 @@ bool HexagonOptAddrMode::analyzeUses(unsigned tfrDefR,
}
SizeInc++;
CanBeReplaced = true;
- } else if (MI->getOpcode() == Hexagon::S2_addasl_rrri) {
+ } else if (MI.getOpcode() == Hexagon::S2_addasl_rrri) {
NodeList AddaslUseList;
- DEBUG(dbgs() << "\nGetting ReachedUses for === " << *MI << "\n");
+ DEBUG(dbgs() << "\nGetting ReachedUses for === " << MI << "\n");
getAllRealUses(SN, AddaslUseList);
// Process phi nodes.
if (allValidCandidates(SN, AddaslUseList) &&
@@ -290,7 +306,7 @@ bool HexagonOptAddrMode::analyzeUses(unsigned tfrDefR,
// M4_mpyrr_addr -> M4_mpyrr_addi
KeepTfr = true;
- InstrEvalResult[MI] = CanBeReplaced;
+ InstrEvalResult[&MI] = CanBeReplaced;
HasRepInstr |= CanBeReplaced;
}
@@ -313,8 +329,8 @@ bool HexagonOptAddrMode::changeLoad(MachineInstr *OldMI, MachineOperand ImmOp,
MachineInstrBuilder MIB;
if (ImmOpNum == 1) {
- if (HII->getAddrMode(OldMI) == HexagonII::BaseRegOffset) {
- short NewOpCode = HII->getBaseWithLongOffset(OldMI);
+ if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset) {
+ short NewOpCode = HII->getBaseWithLongOffset(*OldMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
MIB.addOperand(OldMI->getOperand(0));
@@ -323,8 +339,8 @@ bool HexagonOptAddrMode::changeLoad(MachineInstr *OldMI, MachineOperand ImmOp,
MIB.addOperand(ImmOp);
OpStart = 4;
Changed = true;
- } else if (HII->getAddrMode(OldMI) == HexagonII::BaseImmOffset) {
- short NewOpCode = HII->getAbsoluteForm(OldMI);
+ } else if (HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset) {
+ short NewOpCode = HII->getAbsoluteForm(*OldMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode))
.addOperand(OldMI->getOperand(0));
@@ -340,7 +356,7 @@ bool HexagonOptAddrMode::changeLoad(MachineInstr *OldMI, MachineOperand ImmOp,
DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n");
DEBUG(dbgs() << "[TO]: " << MIB << "\n");
} else if (ImmOpNum == 2 && OldMI->getOperand(3).getImm() == 0) {
- short NewOpCode = HII->xformRegToImmOffset(OldMI);
+ short NewOpCode = HII->xformRegToImmOffset(*OldMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
MIB.addOperand(OldMI->getOperand(0));
@@ -370,8 +386,8 @@ bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
++InsertPt;
MachineInstrBuilder MIB;
if (ImmOpNum == 0) {
- if (HII->getAddrMode(OldMI) == HexagonII::BaseRegOffset) {
- short NewOpCode = HII->getBaseWithLongOffset(OldMI);
+ if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset) {
+ short NewOpCode = HII->getBaseWithLongOffset(*OldMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
MIB.addOperand(OldMI->getOperand(1));
@@ -379,8 +395,8 @@ bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
MIB.addOperand(ImmOp);
MIB.addOperand(OldMI->getOperand(3));
OpStart = 4;
- } else if (HII->getAddrMode(OldMI) == HexagonII::BaseImmOffset) {
- short NewOpCode = HII->getAbsoluteForm(OldMI);
+ } else if (HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset) {
+ short NewOpCode = HII->getAbsoluteForm(*OldMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
const GlobalValue *GV = ImmOp.getGlobal();
@@ -393,7 +409,7 @@ bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n");
DEBUG(dbgs() << "[TO]: " << MIB << "\n");
} else if (ImmOpNum == 1 && OldMI->getOperand(2).getImm() == 0) {
- short NewOpCode = HII->xformRegToImmOffset(OldMI);
+ short NewOpCode = HII->xformRegToImmOffset(*OldMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
MIB.addOperand(OldMI->getOperand(0));
@@ -411,7 +427,7 @@ bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
return Changed;
}
-short HexagonOptAddrMode::getBaseWithLongOffset(const MachineInstr *MI) const {
+short HexagonOptAddrMode::getBaseWithLongOffset(const MachineInstr &MI) const {
if (HII->getAddrMode(MI) == HexagonII::BaseImmOffset) {
short TempOpCode = HII->getBaseWithRegOffset(MI);
return HII->getBaseWithLongOffset(TempOpCode);
@@ -442,11 +458,11 @@ bool HexagonOptAddrMode::changeAddAsl(NodeAddr<UseNode *> AddAslUN,
DEBUG(dbgs() << "[MI <BB#" << UseMI->getParent()->getNumber()
<< ">]: " << *UseMI << "\n");
const MCInstrDesc &UseMID = UseMI->getDesc();
- assert(HII->getAddrMode(UseMI) == HexagonII::BaseImmOffset);
+ assert(HII->getAddrMode(*UseMI) == HexagonII::BaseImmOffset);
auto UsePos = MachineBasicBlock::iterator(UseMI);
MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator();
- short NewOpCode = getBaseWithLongOffset(UseMI);
+ short NewOpCode = getBaseWithLongOffset(*UseMI);
assert(NewOpCode >= 0 && "Invalid New opcode\n");
unsigned OpStart;
@@ -575,7 +591,7 @@ bool HexagonOptAddrMode::processBlock(NodeAddr<BlockNode *> BA) {
void HexagonOptAddrMode::updateMap(NodeAddr<InstrNode *> IA) {
RegisterSet RRs;
for (NodeAddr<RefNode *> RA : IA.Addr->members(*DFG))
- RRs.insert(RA.Addr->getRegRef());
+ RRs.insert(RA.Addr->getRegRef(*DFG));
bool Common = false;
for (auto &R : RDefMap) {
if (!RRs.count(R.first))
@@ -587,7 +603,7 @@ void HexagonOptAddrMode::updateMap(NodeAddr<InstrNode *> IA) {
return;
for (auto &R : RDefMap) {
- auto F = DefM.find(R.first);
+ auto F = DefM.find(R.first.Reg);
if (F == DefM.end() || F->second.empty())
continue;
R.second[IA.Id] = F->second.top()->Id;
@@ -622,8 +638,7 @@ bool HexagonOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
const auto &TRI = *MF.getSubtarget().getRegisterInfo();
const TargetOperandInfo TOI(*HII);
- RegisterAliasInfo RAI(TRI);
- DataFlowGraph G(MF, *HII, TRI, *MDT, MDF, RAI, TOI);
+ DataFlowGraph G(MF, *HII, TRI, *MDT, MDF, TOI);
G.build();
DFG = &G;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonOptimizeSZextends.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonOptimizeSZextends.cpp
index 7937a79..101de3d 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonOptimizeSZextends.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonOptimizeSZextends.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
@@ -38,13 +37,9 @@ namespace {
}
bool runOnFunction(Function &F) override;
- const char *getPassName() const override {
- return "Remove sign extends";
- }
+ StringRef getPassName() const override { return "Remove sign extends"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<MachineFunctionAnalysis>();
- AU.addPreserved<MachineFunctionAnalysis>();
AU.addPreserved<StackProtector>();
FunctionPass::getAnalysisUsage(AU);
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonPatterns.td b/contrib/llvm/lib/Target/Hexagon/HexagonPatterns.td
new file mode 100644
index 0000000..ad81287
--- /dev/null
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonPatterns.td
@@ -0,0 +1,3347 @@
+// Pattern fragment that combines the value type and the register class
+// into a single parameter.
+// The pat frags in the definitions below need to have a named register,
+// otherwise i32 will be assumed regardless of the register class. The
+// name of the register does not matter.
+def I1 : PatLeaf<(i1 PredRegs:$R)>;
+def I32 : PatLeaf<(i32 IntRegs:$R)>;
+def I64 : PatLeaf<(i64 DoubleRegs:$R)>;
+def F32 : PatLeaf<(f32 IntRegs:$R)>;
+def F64 : PatLeaf<(f64 DoubleRegs:$R)>;
+
+// Pattern fragments to extract the low and high subregisters from a
+// 64-bit value.
+def LoReg: OutPatFrag<(ops node:$Rs), (EXTRACT_SUBREG (i64 $Rs), isub_lo)>;
+def HiReg: OutPatFrag<(ops node:$Rs), (EXTRACT_SUBREG (i64 $Rs), isub_hi)>;
+
+def IsOrAdd: PatFrag<(ops node:$Addr, node:$off),
+ (or node:$Addr, node:$off), [{ return isOrEquivalentToAdd(N); }]>;
+
+def IsPow2_32 : PatLeaf<(i32 imm), [{
+ uint32_t V = N->getZExtValue();
+ return isPowerOf2_32(V);
+}]>;
+
+def IsPow2_64 : PatLeaf<(i64 imm), [{
+ uint64_t V = N->getZExtValue();
+ return isPowerOf2_64(V);
+}]>;
+
+def IsNPow2_32 : PatLeaf<(i32 imm), [{
+ uint32_t NV = ~N->getZExtValue();
+ return isPowerOf2_32(NV);
+}]>;
+
+def IsPow2_64L : PatLeaf<(i64 imm), [{
+ uint64_t V = N->getZExtValue();
+ return isPowerOf2_64(V) && Log2_64(V) < 32;
+}]>;
+
+def IsPow2_64H : PatLeaf<(i64 imm), [{
+ uint64_t V = N->getZExtValue();
+ return isPowerOf2_64(V) && Log2_64(V) >= 32;
+}]>;
+
+def IsNPow2_64L : PatLeaf<(i64 imm), [{
+ uint64_t NV = ~N->getZExtValue();
+ return isPowerOf2_64(NV) && Log2_64(NV) < 32;
+}]>;
+
+def IsNPow2_64H : PatLeaf<(i64 imm), [{
+ uint64_t NV = ~N->getZExtValue();
+ return isPowerOf2_64(NV) && Log2_64(NV) >= 32;
+}]>;
+
+def SDEC1 : SDNodeXForm<imm, [{
+ int32_t V = N->getSExtValue();
+ return CurDAG->getTargetConstant(V-1, SDLoc(N), MVT::i32);
+}]>;
+
+def UDEC1 : SDNodeXForm<imm, [{
+ uint32_t V = N->getZExtValue();
+ assert(V >= 1);
+ return CurDAG->getTargetConstant(V-1, SDLoc(N), MVT::i32);
+}]>;
+
+def UDEC32 : SDNodeXForm<imm, [{
+ uint32_t V = N->getZExtValue();
+ assert(V >= 32);
+ return CurDAG->getTargetConstant(V-32, SDLoc(N), MVT::i32);
+}]>;
+
+def Log2_32 : SDNodeXForm<imm, [{
+ uint32_t V = N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_32(V), SDLoc(N), MVT::i32);
+}]>;
+
+def Log2_64 : SDNodeXForm<imm, [{
+ uint64_t V = N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_64(V), SDLoc(N), MVT::i32);
+}]>;
+
+def LogN2_32 : SDNodeXForm<imm, [{
+ uint32_t NV = ~N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_32(NV), SDLoc(N), MVT::i32);
+}]>;
+
+def LogN2_64 : SDNodeXForm<imm, [{
+ uint64_t NV = ~N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_64(NV), SDLoc(N), MVT::i32);
+}]>;
+
+
+class T_CMP_pat <InstHexagon MI, PatFrag OpNode, PatLeaf ImmPred>
+ : Pat<(i1 (OpNode I32:$src1, ImmPred:$src2)),
+ (MI IntRegs:$src1, ImmPred:$src2)>;
+
+def : T_CMP_pat <C2_cmpeqi, seteq, s10_0ImmPred>;
+def : T_CMP_pat <C2_cmpgti, setgt, s10_0ImmPred>;
+def : T_CMP_pat <C2_cmpgtui, setugt, u9_0ImmPred>;
+
+def SDTHexagonI64I32I32 : SDTypeProfile<1, 2,
+ [SDTCisVT<0, i64>, SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>;
+
+def HexagonCOMBINE : SDNode<"HexagonISD::COMBINE", SDTHexagonI64I32I32>;
+def HexagonPACKHL : SDNode<"HexagonISD::PACKHL", SDTHexagonI64I32I32>;
+
+// Pats for instruction selection.
+class BinOp32_pat<SDNode Op, InstHexagon MI, ValueType ResT>
+ : Pat<(ResT (Op I32:$Rs, I32:$Rt)),
+ (ResT (MI IntRegs:$Rs, IntRegs:$Rt))>;
+
+def: BinOp32_pat<add, A2_add, i32>;
+def: BinOp32_pat<and, A2_and, i32>;
+def: BinOp32_pat<or, A2_or, i32>;
+def: BinOp32_pat<sub, A2_sub, i32>;
+def: BinOp32_pat<xor, A2_xor, i32>;
+
+def: BinOp32_pat<HexagonCOMBINE, A2_combinew, i64>;
+def: BinOp32_pat<HexagonPACKHL, S2_packhl, i64>;
+
+// Patfrag to convert the usual comparison patfrags (e.g. setlt) to ones
+// that reverse the order of the operands.
+class RevCmp<PatFrag F> : PatFrag<(ops node:$rhs, node:$lhs), F.Fragment>;
+
+// Pats for compares. They use PatFrags as operands, not SDNodes,
+// since seteq/setgt/etc. are defined as ParFrags.
+class T_cmp32_rr_pat<InstHexagon MI, PatFrag Op, ValueType VT>
+ : Pat<(VT (Op I32:$Rs, I32:$Rt)),
+ (MI IntRegs:$Rs, IntRegs:$Rt)>;
+
+def: T_cmp32_rr_pat<C2_cmpeq, seteq, i1>;
+def: T_cmp32_rr_pat<C2_cmpgt, setgt, i1>;
+def: T_cmp32_rr_pat<C2_cmpgtu, setugt, i1>;
+
+def: T_cmp32_rr_pat<C2_cmpgt, RevCmp<setlt>, i1>;
+def: T_cmp32_rr_pat<C2_cmpgtu, RevCmp<setult>, i1>;
+
+def: Pat<(select I1:$Pu, I32:$Rs, I32:$Rt),
+ (C2_mux PredRegs:$Pu, IntRegs:$Rs, IntRegs:$Rt)>;
+
+def: Pat<(add I32:$Rs, s32_0ImmPred:$s16),
+ (A2_addi I32:$Rs, imm:$s16)>;
+
+def: Pat<(or I32:$Rs, s32_0ImmPred:$s10),
+ (A2_orir IntRegs:$Rs, imm:$s10)>;
+def: Pat<(and I32:$Rs, s32_0ImmPred:$s10),
+ (A2_andir IntRegs:$Rs, imm:$s10)>;
+
+def: Pat<(sub s32_0ImmPred:$s10, IntRegs:$Rs),
+ (A2_subri imm:$s10, IntRegs:$Rs)>;
+
+// Rd = not(Rs) gets mapped to Rd=sub(#-1, Rs).
+def: Pat<(not I32:$src1),
+ (A2_subri -1, IntRegs:$src1)>;
+
+def: Pat<(s32_0ImmPred:$s16), (A2_tfrsi imm:$s16)>;
+def: Pat<(s8_0Imm64Pred:$s8), (A2_tfrpi imm:$s8)>;
+
+def : Pat<(select I1:$Pu, s32_0ImmPred:$s8, I32:$Rs),
+ (C2_muxri I1:$Pu, imm:$s8, I32:$Rs)>;
+
+def : Pat<(select I1:$Pu, I32:$Rs, s32_0ImmPred:$s8),
+ (C2_muxir I1:$Pu, I32:$Rs, imm:$s8)>;
+
+def : Pat<(select I1:$Pu, s32_0ImmPred:$s8, s8_0ImmPred:$S8),
+ (C2_muxii I1:$Pu, imm:$s8, imm:$S8)>;
+
+def: Pat<(shl I32:$src1, (i32 16)), (A2_aslh I32:$src1)>;
+def: Pat<(sra I32:$src1, (i32 16)), (A2_asrh I32:$src1)>;
+def: Pat<(sext_inreg I32:$src1, i8), (A2_sxtb I32:$src1)>;
+def: Pat<(sext_inreg I32:$src1, i16), (A2_sxth I32:$src1)>;
+
+class T_vcmp_pat<InstHexagon MI, PatFrag Op, ValueType T>
+ : Pat<(i1 (Op (T DoubleRegs:$Rss), (T DoubleRegs:$Rtt))),
+ (i1 (MI DoubleRegs:$Rss, DoubleRegs:$Rtt))>;
+
+def: T_vcmp_pat<A2_vcmpbeq, seteq, v8i8>;
+def: T_vcmp_pat<A2_vcmpbgtu, setugt, v8i8>;
+def: T_vcmp_pat<A2_vcmpheq, seteq, v4i16>;
+def: T_vcmp_pat<A2_vcmphgt, setgt, v4i16>;
+def: T_vcmp_pat<A2_vcmphgtu, setugt, v4i16>;
+def: T_vcmp_pat<A2_vcmpweq, seteq, v2i32>;
+def: T_vcmp_pat<A2_vcmpwgt, setgt, v2i32>;
+def: T_vcmp_pat<A2_vcmpwgtu, setugt, v2i32>;
+
+// Add halfword.
+def: Pat<(sext_inreg (add I32:$src1, I32:$src2), i16),
+ (A2_addh_l16_ll I32:$src1, I32:$src2)>;
+
+def: Pat<(sra (add (shl I32:$src1, (i32 16)), I32:$src2), (i32 16)),
+ (A2_addh_l16_hl I32:$src1, I32:$src2)>;
+
+def: Pat<(shl (add I32:$src1, I32:$src2), (i32 16)),
+ (A2_addh_h16_ll I32:$src1, I32:$src2)>;
+
+// Subtract halfword.
+def: Pat<(sext_inreg (sub I32:$src1, I32:$src2), i16),
+ (A2_subh_l16_ll I32:$src1, I32:$src2)>;
+
+def: Pat<(shl (sub I32:$src1, I32:$src2), (i32 16)),
+ (A2_subh_h16_ll I32:$src1, I32:$src2)>;
+
+// Here, depending on the operand being selected, we'll either generate a
+// min or max instruction.
+// Ex:
+// (a>b)?a:b --> max(a,b) => Here check performed is '>' and the value selected
+// is the larger of two. So, the corresponding HexagonInst is passed in 'Inst'.
+// (a>b)?b:a --> min(a,b) => Here check performed is '>' but the smaller value
+// is selected and the corresponding HexagonInst is passed in 'SwapInst'.
+
+multiclass T_MinMax_pats <PatFrag Op, PatLeaf Val,
+ InstHexagon Inst, InstHexagon SwapInst> {
+ def: Pat<(select (i1 (Op Val:$src1, Val:$src2)), Val:$src1, Val:$src2),
+ (Inst Val:$src1, Val:$src2)>;
+ def: Pat<(select (i1 (Op Val:$src1, Val:$src2)), Val:$src2, Val:$src1),
+ (SwapInst Val:$src1, Val:$src2)>;
+}
+
+def IsPosHalf : PatLeaf<(i32 IntRegs:$a), [{
+ return isPositiveHalfWord(N);
+}]>;
+
+multiclass MinMax_pats <PatFrag Op, InstHexagon Inst, InstHexagon SwapInst> {
+ defm: T_MinMax_pats<Op, I32, Inst, SwapInst>;
+
+ def: Pat<(sext_inreg (select (i1 (Op IsPosHalf:$src1, IsPosHalf:$src2)),
+ IsPosHalf:$src1, IsPosHalf:$src2),
+ i16),
+ (Inst IntRegs:$src1, IntRegs:$src2)>;
+
+ def: Pat<(sext_inreg (select (i1 (Op IsPosHalf:$src1, IsPosHalf:$src2)),
+ IsPosHalf:$src2, IsPosHalf:$src1),
+ i16),
+ (SwapInst IntRegs:$src1, IntRegs:$src2)>;
+}
+
+let AddedComplexity = 200 in {
+ defm: MinMax_pats<setge, A2_max, A2_min>;
+ defm: MinMax_pats<setgt, A2_max, A2_min>;
+ defm: MinMax_pats<setle, A2_min, A2_max>;
+ defm: MinMax_pats<setlt, A2_min, A2_max>;
+ defm: MinMax_pats<setuge, A2_maxu, A2_minu>;
+ defm: MinMax_pats<setugt, A2_maxu, A2_minu>;
+ defm: MinMax_pats<setule, A2_minu, A2_maxu>;
+ defm: MinMax_pats<setult, A2_minu, A2_maxu>;
+}
+
+class T_cmp64_rr_pat<InstHexagon MI, PatFrag CmpOp>
+ : Pat<(i1 (CmpOp I64:$Rs, I64:$Rt)),
+ (i1 (MI DoubleRegs:$Rs, DoubleRegs:$Rt))>;
+
+def: T_cmp64_rr_pat<C2_cmpeqp, seteq>;
+def: T_cmp64_rr_pat<C2_cmpgtp, setgt>;
+def: T_cmp64_rr_pat<C2_cmpgtup, setugt>;
+def: T_cmp64_rr_pat<C2_cmpgtp, RevCmp<setlt>>;
+def: T_cmp64_rr_pat<C2_cmpgtup, RevCmp<setult>>;
+
+def: Pat<(i64 (add I64:$Rs, I64:$Rt)), (A2_addp I64:$Rs, I64:$Rt)>;
+def: Pat<(i64 (sub I64:$Rs, I64:$Rt)), (A2_subp I64:$Rs, I64:$Rt)>;
+
+def: Pat<(i64 (and I64:$Rs, I64:$Rt)), (A2_andp I64:$Rs, I64:$Rt)>;
+def: Pat<(i64 (or I64:$Rs, I64:$Rt)), (A2_orp I64:$Rs, I64:$Rt)>;
+def: Pat<(i64 (xor I64:$Rs, I64:$Rt)), (A2_xorp I64:$Rs, I64:$Rt)>;
+
+def: Pat<(i1 (not I1:$Ps)), (C2_not PredRegs:$Ps)>;
+
+def: Pat<(i1 (and I1:$Ps, I1:$Pt)), (C2_and I1:$Ps, I1:$Pt)>;
+def: Pat<(i1 (or I1:$Ps, I1:$Pt)), (C2_or I1:$Ps, I1:$Pt)>;
+def: Pat<(i1 (xor I1:$Ps, I1:$Pt)), (C2_xor I1:$Ps, I1:$Pt)>;
+def: Pat<(i1 (and I1:$Ps, (not I1:$Pt))), (C2_andn I1:$Ps, I1:$Pt)>;
+def: Pat<(i1 (or I1:$Ps, (not I1:$Pt))), (C2_orn I1:$Ps, I1:$Pt)>;
+
+def retflag : SDNode<"HexagonISD::RET_FLAG", SDTNone,
+ [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+def eh_return: SDNode<"HexagonISD::EH_RETURN", SDTNone, [SDNPHasChain]>;
+
+def: Pat<(br bb:$dst), (J2_jump brtarget:$dst)>;
+def: Pat<(brcond I1:$src1, bb:$block), (J2_jumpt PredRegs:$src1, bb:$block)>;
+def: Pat<(brind I32:$dst), (J2_jumpr IntRegs:$dst)>;
+
+def: Pat<(retflag), (PS_jmpret (i32 R31))>;
+def: Pat<(eh_return), (EH_RETURN_JMPR (i32 R31))>;
+
+// Patterns to select load-indexed (i.e. load from base+offset).
+multiclass Loadx_pat<PatFrag Load, ValueType VT, PatLeaf ImmPred,
+ InstHexagon MI> {
+ def: Pat<(VT (Load AddrFI:$fi)), (VT (MI AddrFI:$fi, 0))>;
+ def: Pat<(VT (Load (add (i32 AddrFI:$fi), ImmPred:$Off))),
+ (VT (MI AddrFI:$fi, imm:$Off))>;
+ def: Pat<(VT (Load (IsOrAdd (i32 AddrFI:$fi), ImmPred:$Off))),
+ (VT (MI AddrFI:$fi, imm:$Off))>;
+ def: Pat<(VT (Load (add I32:$Rs, ImmPred:$Off))),
+ (VT (MI IntRegs:$Rs, imm:$Off))>;
+ def: Pat<(VT (Load I32:$Rs)), (VT (MI IntRegs:$Rs, 0))>;
+}
+
+let AddedComplexity = 20 in {
+ defm: Loadx_pat<load, i32, s30_2ImmPred, L2_loadri_io>;
+ defm: Loadx_pat<load, i64, s29_3ImmPred, L2_loadrd_io>;
+ defm: Loadx_pat<atomic_load_8 , i32, s32_0ImmPred, L2_loadrub_io>;
+ defm: Loadx_pat<atomic_load_16, i32, s31_1ImmPred, L2_loadruh_io>;
+ defm: Loadx_pat<atomic_load_32, i32, s30_2ImmPred, L2_loadri_io>;
+ defm: Loadx_pat<atomic_load_64, i64, s29_3ImmPred, L2_loadrd_io>;
+
+ defm: Loadx_pat<extloadi1, i32, s32_0ImmPred, L2_loadrub_io>;
+ defm: Loadx_pat<extloadi8, i32, s32_0ImmPred, L2_loadrub_io>;
+ defm: Loadx_pat<extloadi16, i32, s31_1ImmPred, L2_loadruh_io>;
+ defm: Loadx_pat<sextloadi8, i32, s32_0ImmPred, L2_loadrb_io>;
+ defm: Loadx_pat<sextloadi16, i32, s31_1ImmPred, L2_loadrh_io>;
+ defm: Loadx_pat<zextloadi1, i32, s32_0ImmPred, L2_loadrub_io>;
+ defm: Loadx_pat<zextloadi8, i32, s32_0ImmPred, L2_loadrub_io>;
+ defm: Loadx_pat<zextloadi16, i32, s31_1ImmPred, L2_loadruh_io>;
+ // No sextloadi1.
+}
+
+// Sign-extending loads of i1 need to replicate the lowest bit throughout
+// the 32-bit value. Since the loaded value can only be 0 or 1, 0-v should
+// do the trick.
+let AddedComplexity = 20 in
+def: Pat<(i32 (sextloadi1 I32:$Rs)),
+ (A2_subri 0, (L2_loadrub_io IntRegs:$Rs, 0))>;
+
+def: Pat<(i32 (mul I32:$src1, I32:$src2)), (M2_mpyi I32:$src1, I32:$src2)>;
+def: Pat<(i32 (mulhs I32:$src1, I32:$src2)), (M2_mpy_up I32:$src1, I32:$src2)>;
+def: Pat<(i32 (mulhu I32:$src1, I32:$src2)), (M2_mpyu_up I32:$src1, I32:$src2)>;
+
+def: Pat<(mul IntRegs:$Rs, u32_0ImmPred:$u8),
+ (M2_mpysip IntRegs:$Rs, imm:$u8)>;
+def: Pat<(ineg (mul IntRegs:$Rs, u8_0ImmPred:$u8)),
+ (M2_mpysin IntRegs:$Rs, imm:$u8)>;
+def: Pat<(mul IntRegs:$src1, s32_0ImmPred:$src2),
+ (M2_mpysmi IntRegs:$src1, imm:$src2)>;
+def: Pat<(add (mul IntRegs:$src2, u32_0ImmPred:$src3), IntRegs:$src1),
+ (M2_macsip IntRegs:$src1, IntRegs:$src2, imm:$src3)>;
+def: Pat<(add (mul I32:$src2, I32:$src3), I32:$src1),
+ (M2_maci IntRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+def: Pat<(add (add IntRegs:$src2, u32_0ImmPred:$src3), IntRegs:$src1),
+ (M2_accii IntRegs:$src1, IntRegs:$src2, imm:$src3)>;
+def: Pat<(add (add I32:$src2, I32:$src3), I32:$src1),
+ (M2_acci IntRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+class T_MType_acc_pat1 <InstHexagon MI, SDNode firstOp, SDNode secOp,
+ PatLeaf ImmPred>
+ : Pat <(secOp IntRegs:$src1, (firstOp IntRegs:$src2, ImmPred:$src3)),
+ (MI IntRegs:$src1, IntRegs:$src2, ImmPred:$src3)>;
+
+class T_MType_acc_pat2 <InstHexagon MI, SDNode firstOp, SDNode secOp>
+ : Pat <(i32 (secOp IntRegs:$src1, (firstOp IntRegs:$src2, IntRegs:$src3))),
+ (MI IntRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def : T_MType_acc_pat2 <M2_xor_xacc, xor, xor>;
+def : T_MType_acc_pat1 <M2_macsin, mul, sub, u32_0ImmPred>;
+
+def : T_MType_acc_pat1 <M2_naccii, add, sub, s32_0ImmPred>;
+def : T_MType_acc_pat2 <M2_nacci, add, sub>;
+
+def: T_MType_acc_pat2 <M4_or_xor, xor, or>;
+def: T_MType_acc_pat2 <M4_and_xor, xor, and>;
+def: T_MType_acc_pat2 <M4_or_and, and, or>;
+def: T_MType_acc_pat2 <M4_and_and, and, and>;
+def: T_MType_acc_pat2 <M4_xor_and, and, xor>;
+def: T_MType_acc_pat2 <M4_or_or, or, or>;
+def: T_MType_acc_pat2 <M4_and_or, or, and>;
+def: T_MType_acc_pat2 <M4_xor_or, or, xor>;
+
+class T_MType_acc_pat3 <InstHexagon MI, SDNode firstOp, SDNode secOp>
+ : Pat <(secOp I32:$src1, (firstOp I32:$src2, (not I32:$src3))),
+ (MI IntRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def: T_MType_acc_pat3 <M4_or_andn, and, or>;
+def: T_MType_acc_pat3 <M4_and_andn, and, and>;
+def: T_MType_acc_pat3 <M4_xor_andn, and, xor>;
+
+def Aext64: PatFrag<(ops node:$Rs), (i64 (anyext node:$Rs))>;
+def Sext64: PatFrag<(ops node:$Rs), (i64 (sext node:$Rs))>;
+def Zext64: PatFrag<(ops node:$Rs), (i64 (zext node:$Rs))>;
+
+// Return true if for a 32 to 64-bit sign-extended load.
+def Sext64Ld : PatLeaf<(i64 DoubleRegs:$src1), [{
+ LoadSDNode *LD = dyn_cast<LoadSDNode>(N);
+ if (!LD)
+ return false;
+ return LD->getExtensionType() == ISD::SEXTLOAD &&
+ LD->getMemoryVT().getScalarType() == MVT::i32;
+}]>;
+
+def: Pat<(mul (Aext64 I32:$src1), (Aext64 I32:$src2)),
+ (M2_dpmpyuu_s0 IntRegs:$src1, IntRegs:$src2)>;
+
+def: Pat<(mul (Sext64 I32:$src1), (Sext64 I32:$src2)),
+ (M2_dpmpyss_s0 IntRegs:$src1, IntRegs:$src2)>;
+
+def: Pat<(mul Sext64Ld:$src1, Sext64Ld:$src2),
+ (M2_dpmpyss_s0 (LoReg DoubleRegs:$src1), (LoReg DoubleRegs:$src2))>;
+
+// Multiply and accumulate, use full result.
+// Rxx[+-]=mpy(Rs,Rt)
+
+def: Pat<(add I64:$src1, (mul (Sext64 I32:$src2), (Sext64 I32:$src3))),
+ (M2_dpmpyss_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def: Pat<(sub I64:$src1, (mul (Sext64 I32:$src2), (Sext64 I32:$src3))),
+ (M2_dpmpyss_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def: Pat<(add I64:$src1, (mul (Aext64 I32:$src2), (Aext64 I32:$src3))),
+ (M2_dpmpyuu_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def: Pat<(add I64:$src1, (mul (Zext64 I32:$src2), (Zext64 I32:$src3))),
+ (M2_dpmpyuu_acc_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def: Pat<(sub I64:$src1, (mul (Aext64 I32:$src2), (Aext64 I32:$src3))),
+ (M2_dpmpyuu_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+def: Pat<(sub I64:$src1, (mul (Zext64 I32:$src2), (Zext64 I32:$src3))),
+ (M2_dpmpyuu_nac_s0 DoubleRegs:$src1, IntRegs:$src2, IntRegs:$src3)>;
+
+class Storepi_pat<PatFrag Store, PatFrag Value, PatFrag Offset,
+ InstHexagon MI>
+ : Pat<(Store Value:$src1, I32:$src2, Offset:$offset),
+ (MI I32:$src2, imm:$offset, Value:$src1)>;
+
+def: Storepi_pat<post_truncsti8, I32, s4_0ImmPred, S2_storerb_pi>;
+def: Storepi_pat<post_truncsti16, I32, s4_1ImmPred, S2_storerh_pi>;
+def: Storepi_pat<post_store, I32, s4_2ImmPred, S2_storeri_pi>;
+def: Storepi_pat<post_store, I64, s4_3ImmPred, S2_storerd_pi>;
+
+// Patterns for generating stores, where the address takes different forms:
+// - frameindex,
+// - frameindex + offset,
+// - base + offset,
+// - simple (base address without offset).
+// These would usually be used together (via Storex_pat defined below), but
+// in some cases one may want to apply different properties (such as
+// AddedComplexity) to the individual patterns.
+class Storex_fi_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
+ : Pat<(Store Value:$Rs, AddrFI:$fi), (MI AddrFI:$fi, 0, Value:$Rs)>;
+multiclass Storex_fi_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
+ InstHexagon MI> {
+ def: Pat<(Store Value:$Rs, (add (i32 AddrFI:$fi), ImmPred:$Off)),
+ (MI AddrFI:$fi, imm:$Off, Value:$Rs)>;
+ def: Pat<(Store Value:$Rs, (IsOrAdd (i32 AddrFI:$fi), ImmPred:$Off)),
+ (MI AddrFI:$fi, imm:$Off, Value:$Rs)>;
+}
+multiclass Storex_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
+ InstHexagon MI> {
+ def: Pat<(Store Value:$Rt, (add I32:$Rs, ImmPred:$Off)),
+ (MI IntRegs:$Rs, imm:$Off, Value:$Rt)>;
+ def: Pat<(Store Value:$Rt, (IsOrAdd I32:$Rs, ImmPred:$Off)),
+ (MI IntRegs:$Rs, imm:$Off, Value:$Rt)>;
+}
+class Storex_simple_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
+ : Pat<(Store Value:$Rt, I32:$Rs),
+ (MI IntRegs:$Rs, 0, Value:$Rt)>;
+
+// Patterns for generating stores, where the address takes different forms,
+// and where the value being stored is transformed through the value modifier
+// ValueMod. The address forms are same as above.
+class Storexm_fi_pat<PatFrag Store, PatFrag Value, PatFrag ValueMod,
+ InstHexagon MI>
+ : Pat<(Store Value:$Rs, AddrFI:$fi),
+ (MI AddrFI:$fi, 0, (ValueMod Value:$Rs))>;
+multiclass Storexm_fi_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
+ PatFrag ValueMod, InstHexagon MI> {
+ def: Pat<(Store Value:$Rs, (add (i32 AddrFI:$fi), ImmPred:$Off)),
+ (MI AddrFI:$fi, imm:$Off, (ValueMod Value:$Rs))>;
+ def: Pat<(Store Value:$Rs, (IsOrAdd (i32 AddrFI:$fi), ImmPred:$Off)),
+ (MI AddrFI:$fi, imm:$Off, (ValueMod Value:$Rs))>;
+}
+multiclass Storexm_add_pat<PatFrag Store, PatFrag Value, PatFrag ImmPred,
+ PatFrag ValueMod, InstHexagon MI> {
+ def: Pat<(Store Value:$Rt, (add I32:$Rs, ImmPred:$Off)),
+ (MI IntRegs:$Rs, imm:$Off, (ValueMod Value:$Rt))>;
+ def: Pat<(Store Value:$Rt, (IsOrAdd I32:$Rs, ImmPred:$Off)),
+ (MI IntRegs:$Rs, imm:$Off, (ValueMod Value:$Rt))>;
+}
+class Storexm_simple_pat<PatFrag Store, PatFrag Value, PatFrag ValueMod,
+ InstHexagon MI>
+ : Pat<(Store Value:$Rt, I32:$Rs),
+ (MI IntRegs:$Rs, 0, (ValueMod Value:$Rt))>;
+
+multiclass Storex_pat<PatFrag Store, PatFrag Value, PatLeaf ImmPred,
+ InstHexagon MI> {
+ def: Storex_fi_pat <Store, Value, MI>;
+ defm: Storex_fi_add_pat <Store, Value, ImmPred, MI>;
+ defm: Storex_add_pat <Store, Value, ImmPred, MI>;
+}
+
+multiclass Storexm_pat<PatFrag Store, PatFrag Value, PatLeaf ImmPred,
+ PatFrag ValueMod, InstHexagon MI> {
+ def: Storexm_fi_pat <Store, Value, ValueMod, MI>;
+ defm: Storexm_fi_add_pat <Store, Value, ImmPred, ValueMod, MI>;
+ defm: Storexm_add_pat <Store, Value, ImmPred, ValueMod, MI>;
+}
+
+// Regular stores in the DAG have two operands: value and address.
+// Atomic stores also have two, but they are reversed: address, value.
+// To use atomic stores with the patterns, they need to have their operands
+// swapped. This relies on the knowledge that the F.Fragment uses names
+// "ptr" and "val".
+class SwapSt<PatFrag F>
+ : PatFrag<(ops node:$val, node:$ptr), F.Fragment, F.PredicateCode,
+ F.OperandTransform>;
+
+let AddedComplexity = 20 in {
+ defm: Storex_pat<truncstorei8, I32, s32_0ImmPred, S2_storerb_io>;
+ defm: Storex_pat<truncstorei16, I32, s31_1ImmPred, S2_storerh_io>;
+ defm: Storex_pat<store, I32, s30_2ImmPred, S2_storeri_io>;
+ defm: Storex_pat<store, I64, s29_3ImmPred, S2_storerd_io>;
+
+ defm: Storex_pat<SwapSt<atomic_store_8>, I32, s32_0ImmPred, S2_storerb_io>;
+ defm: Storex_pat<SwapSt<atomic_store_16>, I32, s31_1ImmPred, S2_storerh_io>;
+ defm: Storex_pat<SwapSt<atomic_store_32>, I32, s30_2ImmPred, S2_storeri_io>;
+ defm: Storex_pat<SwapSt<atomic_store_64>, I64, s29_3ImmPred, S2_storerd_io>;
+}
+
+// Simple patterns should be tried with the least priority.
+def: Storex_simple_pat<truncstorei8, I32, S2_storerb_io>;
+def: Storex_simple_pat<truncstorei16, I32, S2_storerh_io>;
+def: Storex_simple_pat<store, I32, S2_storeri_io>;
+def: Storex_simple_pat<store, I64, S2_storerd_io>;
+
+def: Storex_simple_pat<SwapSt<atomic_store_8>, I32, S2_storerb_io>;
+def: Storex_simple_pat<SwapSt<atomic_store_16>, I32, S2_storerh_io>;
+def: Storex_simple_pat<SwapSt<atomic_store_32>, I32, S2_storeri_io>;
+def: Storex_simple_pat<SwapSt<atomic_store_64>, I64, S2_storerd_io>;
+
+let AddedComplexity = 20 in {
+ defm: Storexm_pat<truncstorei8, I64, s32_0ImmPred, LoReg, S2_storerb_io>;
+ defm: Storexm_pat<truncstorei16, I64, s31_1ImmPred, LoReg, S2_storerh_io>;
+ defm: Storexm_pat<truncstorei32, I64, s30_2ImmPred, LoReg, S2_storeri_io>;
+}
+
+def: Storexm_simple_pat<truncstorei8, I64, LoReg, S2_storerb_io>;
+def: Storexm_simple_pat<truncstorei16, I64, LoReg, S2_storerh_io>;
+def: Storexm_simple_pat<truncstorei32, I64, LoReg, S2_storeri_io>;
+
+def: Pat <(Sext64 I32:$src), (A2_sxtw I32:$src)>;
+
+def: Pat<(select (i1 (setlt I32:$src, 0)), (sub 0, I32:$src), I32:$src),
+ (A2_abs IntRegs:$src)>;
+
+let AddedComplexity = 50 in
+def: Pat<(xor (add (sra I32:$src, (i32 31)),
+ I32:$src),
+ (sra I32:$src, (i32 31))),
+ (A2_abs IntRegs:$src)>;
+
+def: Pat<(sra I32:$src, u5_0ImmPred:$u5),
+ (S2_asr_i_r IntRegs:$src, imm:$u5)>;
+def: Pat<(srl I32:$src, u5_0ImmPred:$u5),
+ (S2_lsr_i_r IntRegs:$src, imm:$u5)>;
+def: Pat<(shl I32:$src, u5_0ImmPred:$u5),
+ (S2_asl_i_r IntRegs:$src, imm:$u5)>;
+
+def: Pat<(sra (add (sra I32:$src1, u5_0ImmPred:$src2), 1), (i32 1)),
+ (S2_asr_i_r_rnd IntRegs:$src1, u5_0ImmPred:$src2)>;
+
+def : Pat<(not I64:$src1),
+ (A2_notp DoubleRegs:$src1)>;
+
+// Count leading zeros.
+def: Pat<(ctlz I32:$Rs), (S2_cl0 I32:$Rs)>;
+def: Pat<(i32 (trunc (ctlz I64:$Rss))), (S2_cl0p I64:$Rss)>;
+
+// Count trailing zeros: 32-bit.
+def: Pat<(cttz I32:$Rs), (S2_ct0 I32:$Rs)>;
+
+// Count leading ones.
+def: Pat<(ctlz (not I32:$Rs)), (S2_cl1 I32:$Rs)>;
+def: Pat<(i32 (trunc (ctlz (not I64:$Rss)))), (S2_cl1p I64:$Rss)>;
+
+// Count trailing ones: 32-bit.
+def: Pat<(cttz (not I32:$Rs)), (S2_ct1 I32:$Rs)>;
+
+let AddedComplexity = 20 in { // Complexity greater than and/or/xor
+ def: Pat<(and I32:$Rs, IsNPow2_32:$V),
+ (S2_clrbit_i IntRegs:$Rs, (LogN2_32 $V))>;
+ def: Pat<(or I32:$Rs, IsPow2_32:$V),
+ (S2_setbit_i IntRegs:$Rs, (Log2_32 $V))>;
+ def: Pat<(xor I32:$Rs, IsPow2_32:$V),
+ (S2_togglebit_i IntRegs:$Rs, (Log2_32 $V))>;
+
+ def: Pat<(and I32:$Rs, (not (shl 1, I32:$Rt))),
+ (S2_clrbit_r IntRegs:$Rs, IntRegs:$Rt)>;
+ def: Pat<(or I32:$Rs, (shl 1, I32:$Rt)),
+ (S2_setbit_r IntRegs:$Rs, IntRegs:$Rt)>;
+ def: Pat<(xor I32:$Rs, (shl 1, I32:$Rt)),
+ (S2_togglebit_r IntRegs:$Rs, IntRegs:$Rt)>;
+}
+
+// Clr/set/toggle bit for 64-bit values with immediate bit index.
+let AddedComplexity = 20 in { // Complexity greater than and/or/xor
+ def: Pat<(and I64:$Rss, IsNPow2_64L:$V),
+ (REG_SEQUENCE DoubleRegs,
+ (i32 (HiReg $Rss)), isub_hi,
+ (S2_clrbit_i (LoReg $Rss), (LogN2_64 $V)), isub_lo)>;
+ def: Pat<(and I64:$Rss, IsNPow2_64H:$V),
+ (REG_SEQUENCE DoubleRegs,
+ (S2_clrbit_i (HiReg $Rss), (UDEC32 (i32 (LogN2_64 $V)))),
+ isub_hi,
+ (i32 (LoReg $Rss)), isub_lo)>;
+
+ def: Pat<(or I64:$Rss, IsPow2_64L:$V),
+ (REG_SEQUENCE DoubleRegs,
+ (i32 (HiReg $Rss)), isub_hi,
+ (S2_setbit_i (LoReg $Rss), (Log2_64 $V)), isub_lo)>;
+ def: Pat<(or I64:$Rss, IsPow2_64H:$V),
+ (REG_SEQUENCE DoubleRegs,
+ (S2_setbit_i (HiReg $Rss), (UDEC32 (i32 (Log2_64 $V)))),
+ isub_hi,
+ (i32 (LoReg $Rss)), isub_lo)>;
+
+ def: Pat<(xor I64:$Rss, IsPow2_64L:$V),
+ (REG_SEQUENCE DoubleRegs,
+ (i32 (HiReg $Rss)), isub_hi,
+ (S2_togglebit_i (LoReg $Rss), (Log2_64 $V)), isub_lo)>;
+ def: Pat<(xor I64:$Rss, IsPow2_64H:$V),
+ (REG_SEQUENCE DoubleRegs,
+ (S2_togglebit_i (HiReg $Rss), (UDEC32 (i32 (Log2_64 $V)))),
+ isub_hi,
+ (i32 (LoReg $Rss)), isub_lo)>;
+}
+
+let AddedComplexity = 20 in { // Complexity greater than cmp reg-imm.
+ def: Pat<(i1 (setne (and (shl 1, u5_0ImmPred:$u5), I32:$Rs), 0)),
+ (S2_tstbit_i IntRegs:$Rs, u5_0ImmPred:$u5)>;
+ def: Pat<(i1 (setne (and (shl 1, I32:$Rt), I32:$Rs), 0)),
+ (S2_tstbit_r IntRegs:$Rs, IntRegs:$Rt)>;
+ def: Pat<(i1 (trunc I32:$Rs)),
+ (S2_tstbit_i IntRegs:$Rs, 0)>;
+ def: Pat<(i1 (trunc I64:$Rs)),
+ (S2_tstbit_i (LoReg DoubleRegs:$Rs), 0)>;
+}
+
+let AddedComplexity = 20 in { // Complexity greater than compare reg-imm.
+ def: Pat<(i1 (seteq (and I32:$Rs, u6_0ImmPred:$u6), 0)),
+ (C2_bitsclri IntRegs:$Rs, u6_0ImmPred:$u6)>;
+ def: Pat<(i1 (seteq (and I32:$Rs, I32:$Rt), 0)),
+ (C2_bitsclr IntRegs:$Rs, IntRegs:$Rt)>;
+}
+
+let AddedComplexity = 10 in // Complexity greater than compare reg-reg.
+def: Pat<(i1 (seteq (and I32:$Rs, I32:$Rt), IntRegs:$Rt)),
+ (C2_bitsset IntRegs:$Rs, IntRegs:$Rt)>;
+
+def: Pat<(or (or (shl (or (shl (i32 (extloadi8 (add I32:$b, 3))),
+ (i32 8)),
+ (i32 (zextloadi8 (add I32:$b, 2)))),
+ (i32 16)),
+ (shl (i32 (zextloadi8 (add I32:$b, 1))), (i32 8))),
+ (zextloadi8 I32:$b)),
+ (A2_swiz (L2_loadri_io IntRegs:$b, 0))>;
+
+// Patterns for loads of i1:
+def: Pat<(i1 (load AddrFI:$fi)),
+ (C2_tfrrp (L2_loadrub_io AddrFI:$fi, 0))>;
+def: Pat<(i1 (load (add I32:$Rs, s32_0ImmPred:$Off))),
+ (C2_tfrrp (L2_loadrub_io IntRegs:$Rs, imm:$Off))>;
+def: Pat<(i1 (load I32:$Rs)),
+ (C2_tfrrp (L2_loadrub_io IntRegs:$Rs, 0))>;
+
+def I1toI32: OutPatFrag<(ops node:$Rs),
+ (C2_muxii (i1 $Rs), 1, 0)>;
+
+def I32toI1: OutPatFrag<(ops node:$Rs),
+ (i1 (C2_tfrrp (i32 $Rs)))>;
+
+defm: Storexm_pat<store, I1, s32_0ImmPred, I1toI32, S2_storerb_io>;
+def: Storexm_simple_pat<store, I1, I1toI32, S2_storerb_io>;
+
+def: Pat<(sra I64:$src, u6_0ImmPred:$u6),
+ (S2_asr_i_p DoubleRegs:$src, imm:$u6)>;
+def: Pat<(srl I64:$src, u6_0ImmPred:$u6),
+ (S2_lsr_i_p DoubleRegs:$src, imm:$u6)>;
+def: Pat<(shl I64:$src, u6_0ImmPred:$u6),
+ (S2_asl_i_p DoubleRegs:$src, imm:$u6)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$Rt, (shl I32:$Rs, u3_0ImmPred:$u3)),
+ (S2_addasl_rrri IntRegs:$Rt, IntRegs:$Rs, imm:$u3)>;
+
+def HexagonBARRIER: SDNode<"HexagonISD::BARRIER", SDTNone, [SDNPHasChain]>;
+def: Pat<(HexagonBARRIER), (Y2_barrier)>;
+
+def: Pat<(IsOrAdd (i32 AddrFI:$Rs), s32_0ImmPred:$off),
+ (PS_fi (i32 AddrFI:$Rs), s32_0ImmPred:$off)>;
+
+
+// Support for generating global address.
+// Taken from X86InstrInfo.td.
+def SDTHexagonCONST32 : SDTypeProfile<1, 1, [SDTCisVT<0, i32>,
+ SDTCisVT<1, i32>,
+ SDTCisPtrTy<0>]>;
+def HexagonCONST32 : SDNode<"HexagonISD::CONST32", SDTHexagonCONST32>;
+def HexagonCONST32_GP : SDNode<"HexagonISD::CONST32_GP", SDTHexagonCONST32>;
+
+// Map TLS addressses to A2_tfrsi.
+def: Pat<(HexagonCONST32 tglobaltlsaddr:$addr), (A2_tfrsi s16_0Ext:$addr)>;
+def: Pat<(HexagonCONST32 bbl:$label), (A2_tfrsi s16_0Ext:$label)>;
+
+def: Pat<(i64 imm:$v), (CONST64 imm:$v)>;
+def: Pat<(i1 0), (PS_false)>;
+def: Pat<(i1 1), (PS_true)>;
+
+// Pseudo instructions.
+def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
+def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
+ SDTCisVT<1, i32> ]>;
+
+def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_SPCallSeqStart,
+ [SDNPHasChain, SDNPOutGlue]>;
+def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SPCallSeqEnd,
+ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
+
+def SDT_SPCall : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
+
+// For tailcalls a HexagonTCRet SDNode has 3 SDNode Properties - a chain,
+// Optional Flag and Variable Arguments.
+// Its 1 Operand has pointer type.
+def HexagonTCRet : SDNode<"HexagonISD::TC_RETURN", SDT_SPCall,
+ [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+
+
+def: Pat<(callseq_start timm:$amt),
+ (ADJCALLSTACKDOWN imm:$amt)>;
+def: Pat<(callseq_end timm:$amt1, timm:$amt2),
+ (ADJCALLSTACKUP imm:$amt1, imm:$amt2)>;
+
+//Tail calls.
+def: Pat<(HexagonTCRet tglobaladdr:$dst),
+ (PS_tailcall_i tglobaladdr:$dst)>;
+def: Pat<(HexagonTCRet texternalsym:$dst),
+ (PS_tailcall_i texternalsym:$dst)>;
+def: Pat<(HexagonTCRet I32:$dst),
+ (PS_tailcall_r I32:$dst)>;
+
+// Map from r0 = and(r1, 65535) to r0 = zxth(r1)
+def: Pat<(and I32:$src1, 65535),
+ (A2_zxth IntRegs:$src1)>;
+
+// Map from r0 = and(r1, 255) to r0 = zxtb(r1).
+def: Pat<(and I32:$src1, 255),
+ (A2_zxtb IntRegs:$src1)>;
+
+// Map Add(p1, true) to p1 = not(p1).
+// Add(p1, false) should never be produced,
+// if it does, it got to be mapped to NOOP.
+def: Pat<(add I1:$src1, -1),
+ (C2_not PredRegs:$src1)>;
+
+// Map from p0 = pnot(p0); r0 = mux(p0, #i, #j) => r0 = mux(p0, #j, #i).
+def: Pat<(select (not I1:$src1), s8_0ImmPred:$src2, s32_0ImmPred:$src3),
+ (C2_muxii PredRegs:$src1, s32_0ImmPred:$src3, s8_0ImmPred:$src2)>;
+
+// Map from p0 = pnot(p0); r0 = select(p0, #i, r1)
+// => r0 = C2_muxir(p0, r1, #i)
+def: Pat<(select (not I1:$src1), s32_0ImmPred:$src2,
+ I32:$src3),
+ (C2_muxir PredRegs:$src1, IntRegs:$src3, s32_0ImmPred:$src2)>;
+
+// Map from p0 = pnot(p0); r0 = mux(p0, r1, #i)
+// => r0 = C2_muxri (p0, #i, r1)
+def: Pat<(select (not I1:$src1), IntRegs:$src2, s32_0ImmPred:$src3),
+ (C2_muxri PredRegs:$src1, s32_0ImmPred:$src3, IntRegs:$src2)>;
+
+// Map from p0 = pnot(p0); if (p0) jump => if (!p0) jump.
+def: Pat<(brcond (not I1:$src1), bb:$offset),
+ (J2_jumpf PredRegs:$src1, bb:$offset)>;
+
+// Map from Rdd = sign_extend_inreg(Rss, i32) -> Rdd = A2_sxtw(Rss.lo).
+def: Pat<(i64 (sext_inreg I64:$src1, i32)),
+ (A2_sxtw (LoReg DoubleRegs:$src1))>;
+
+// Map from Rdd = sign_extend_inreg(Rss, i16) -> Rdd = A2_sxtw(A2_sxth(Rss.lo)).
+def: Pat<(i64 (sext_inreg I64:$src1, i16)),
+ (A2_sxtw (A2_sxth (LoReg DoubleRegs:$src1)))>;
+
+// Map from Rdd = sign_extend_inreg(Rss, i8) -> Rdd = A2_sxtw(A2_sxtb(Rss.lo)).
+def: Pat<(i64 (sext_inreg I64:$src1, i8)),
+ (A2_sxtw (A2_sxtb (LoReg DoubleRegs:$src1)))>;
+
+// We want to prevent emitting pnot's as much as possible.
+// Map brcond with an unsupported setcc to a J2_jumpf.
+def : Pat <(brcond (i1 (setne I32:$src1, I32:$src2)),
+ bb:$offset),
+ (J2_jumpf (C2_cmpeq I32:$src1, I32:$src2),
+ bb:$offset)>;
+
+def : Pat <(brcond (i1 (setne I32:$src1, s10_0ImmPred:$src2)),
+ bb:$offset),
+ (J2_jumpf (C2_cmpeqi I32:$src1, s10_0ImmPred:$src2), bb:$offset)>;
+
+def: Pat<(brcond (i1 (setne I1:$src1, (i1 -1))), bb:$offset),
+ (J2_jumpf PredRegs:$src1, bb:$offset)>;
+
+def: Pat<(brcond (i1 (setne I1:$src1, (i1 0))), bb:$offset),
+ (J2_jumpt PredRegs:$src1, bb:$offset)>;
+
+// cmp.lt(Rs, Imm) -> !cmp.ge(Rs, Imm) -> !cmp.gt(Rs, Imm-1)
+def: Pat<(brcond (i1 (setlt I32:$src1, s8_0ImmPred:$src2)), bb:$offset),
+ (J2_jumpf (C2_cmpgti IntRegs:$src1, (SDEC1 s8_0ImmPred:$src2)),
+ bb:$offset)>;
+
+// Map from a 64-bit select to an emulated 64-bit mux.
+// Hexagon does not support 64-bit MUXes; so emulate with combines.
+def: Pat<(select I1:$src1, I64:$src2,
+ I64:$src3),
+ (A2_combinew (C2_mux PredRegs:$src1, (HiReg DoubleRegs:$src2),
+ (HiReg DoubleRegs:$src3)),
+ (C2_mux PredRegs:$src1, (LoReg DoubleRegs:$src2),
+ (LoReg DoubleRegs:$src3)))>;
+
+// Map from a 1-bit select to logical ops.
+// From LegalizeDAG.cpp: (B1 ? B2 : B3) <=> (B1 & B2)|(!B1&B3).
+def: Pat<(select I1:$src1, I1:$src2, I1:$src3),
+ (C2_or (C2_and PredRegs:$src1, PredRegs:$src2),
+ (C2_and (C2_not PredRegs:$src1), PredRegs:$src3))>;
+
+// Map for truncating from 64 immediates to 32 bit immediates.
+def: Pat<(i32 (trunc I64:$src)),
+ (LoReg DoubleRegs:$src)>;
+
+// Map for truncating from i64 immediates to i1 bit immediates.
+def: Pat<(i1 (trunc I64:$src)),
+ (C2_tfrrp (LoReg DoubleRegs:$src))>;
+
+// rs <= rt -> !(rs > rt).
+let AddedComplexity = 30 in
+def: Pat<(i1 (setle I32:$src1, s32_0ImmPred:$src2)),
+ (C2_not (C2_cmpgti IntRegs:$src1, s32_0ImmPred:$src2))>;
+
+// rs <= rt -> !(rs > rt).
+def : Pat<(i1 (setle I32:$src1, I32:$src2)),
+ (i1 (C2_not (C2_cmpgt I32:$src1, I32:$src2)))>;
+
+// Rss <= Rtt -> !(Rss > Rtt).
+def: Pat<(i1 (setle I64:$src1, I64:$src2)),
+ (C2_not (C2_cmpgtp DoubleRegs:$src1, DoubleRegs:$src2))>;
+
+// Map cmpne -> cmpeq.
+// Hexagon_TODO: We should improve on this.
+// rs != rt -> !(rs == rt).
+let AddedComplexity = 30 in
+def: Pat<(i1 (setne I32:$src1, s32_0ImmPred:$src2)),
+ (C2_not (C2_cmpeqi IntRegs:$src1, s32_0ImmPred:$src2))>;
+
+// Convert setne back to xor for hexagon since we compute w/ pred registers.
+def: Pat<(i1 (setne I1:$src1, I1:$src2)),
+ (C2_xor PredRegs:$src1, PredRegs:$src2)>;
+
+// Map cmpne(Rss) -> !cmpew(Rss).
+// rs != rt -> !(rs == rt).
+def: Pat<(i1 (setne I64:$src1, I64:$src2)),
+ (C2_not (C2_cmpeqp DoubleRegs:$src1, DoubleRegs:$src2))>;
+
+// Map cmpge(Rs, Rt) -> !cmpgt(Rs, Rt).
+// rs >= rt -> !(rt > rs).
+def : Pat <(i1 (setge I32:$src1, I32:$src2)),
+ (i1 (C2_not (i1 (C2_cmpgt I32:$src2, I32:$src1))))>;
+
+// cmpge(Rs, Imm) -> cmpgt(Rs, Imm-1)
+let AddedComplexity = 30 in
+def: Pat<(i1 (setge I32:$src1, s32_0ImmPred:$src2)),
+ (C2_cmpgti IntRegs:$src1, (SDEC1 s32_0ImmPred:$src2))>;
+
+// Map cmpge(Rss, Rtt) -> !cmpgt(Rtt, Rss).
+// rss >= rtt -> !(rtt > rss).
+def: Pat<(i1 (setge I64:$src1, I64:$src2)),
+ (C2_not (C2_cmpgtp DoubleRegs:$src2, DoubleRegs:$src1))>;
+
+// Map cmplt(Rs, Imm) -> !cmpge(Rs, Imm).
+// !cmpge(Rs, Imm) -> !cmpgt(Rs, Imm-1).
+// rs < rt -> !(rs >= rt).
+let AddedComplexity = 30 in
+def: Pat<(i1 (setlt I32:$src1, s32_0ImmPred:$src2)),
+ (C2_not (C2_cmpgti IntRegs:$src1, (SDEC1 s32_0ImmPred:$src2)))>;
+
+// Generate cmpgeu(Rs, #0) -> cmpeq(Rs, Rs)
+def: Pat<(i1 (setuge I32:$src1, 0)),
+ (C2_cmpeq IntRegs:$src1, IntRegs:$src1)>;
+
+// Generate cmpgeu(Rs, #u8) -> cmpgtu(Rs, #u8 -1)
+def: Pat<(i1 (setuge I32:$src1, u32_0ImmPred:$src2)),
+ (C2_cmpgtui IntRegs:$src1, (UDEC1 u32_0ImmPred:$src2))>;
+
+// Generate cmpgtu(Rs, #u9)
+def: Pat<(i1 (setugt I32:$src1, u32_0ImmPred:$src2)),
+ (C2_cmpgtui IntRegs:$src1, u32_0ImmPred:$src2)>;
+
+// Map from Rs >= Rt -> !(Rt > Rs).
+// rs >= rt -> !(rt > rs).
+def: Pat<(i1 (setuge I64:$src1, I64:$src2)),
+ (C2_not (C2_cmpgtup DoubleRegs:$src2, DoubleRegs:$src1))>;
+
+// Map from cmpleu(Rss, Rtt) -> !cmpgtu(Rss, Rtt-1).
+// Map from (Rs <= Rt) -> !(Rs > Rt).
+def: Pat<(i1 (setule I64:$src1, I64:$src2)),
+ (C2_not (C2_cmpgtup DoubleRegs:$src1, DoubleRegs:$src2))>;
+
+// Sign extends.
+// i1 -> i32
+def: Pat<(i32 (sext I1:$src1)),
+ (C2_muxii PredRegs:$src1, -1, 0)>;
+
+// i1 -> i64
+def: Pat<(i64 (sext I1:$src1)),
+ (A2_combinew (A2_tfrsi -1), (C2_muxii PredRegs:$src1, -1, 0))>;
+
+// Zero extends.
+// i1 -> i32
+def: Pat<(i32 (zext I1:$src1)),
+ (C2_muxii PredRegs:$src1, 1, 0)>;
+
+// Map from Rs = Pd to Pd = mux(Pd, #1, #0)
+def: Pat<(i32 (anyext I1:$src1)),
+ (C2_muxii PredRegs:$src1, 1, 0)>;
+
+// Map from Rss = Pd to Rdd = sxtw (mux(Pd, #1, #0))
+def: Pat<(i64 (anyext I1:$src1)),
+ (A2_sxtw (C2_muxii PredRegs:$src1, 1, 0))>;
+
+// Clear the sign bit in a 64-bit register.
+def ClearSign : OutPatFrag<(ops node:$Rss),
+ (A2_combinew (S2_clrbit_i (HiReg $Rss), 31), (LoReg $Rss))>;
+
+def MulHU : OutPatFrag<(ops node:$Rss, node:$Rtt),
+ (A2_addp
+ (M2_dpmpyuu_acc_s0
+ (S2_lsr_i_p
+ (A2_addp
+ (M2_dpmpyuu_acc_s0
+ (S2_lsr_i_p (M2_dpmpyuu_s0 (LoReg $Rss), (LoReg $Rtt)), 32),
+ (HiReg $Rss),
+ (LoReg $Rtt)),
+ (A2_combinew (A2_tfrsi 0),
+ (LoReg (M2_dpmpyuu_s0 (LoReg $Rss), (HiReg $Rtt))))),
+ 32),
+ (HiReg $Rss),
+ (HiReg $Rtt)),
+ (S2_lsr_i_p (M2_dpmpyuu_s0 (LoReg $Rss), (HiReg $Rtt)), 32))>;
+
+// Multiply 64-bit unsigned and use upper result.
+def : Pat <(mulhu I64:$Rss, I64:$Rtt), (MulHU $Rss, $Rtt)>;
+
+// Multiply 64-bit signed and use upper result.
+//
+// For two signed 64-bit integers A and B, let A' and B' denote A and B
+// with the sign bit cleared. Then A = -2^63*s(A) + A', where s(A) is the
+// sign bit of A (and identically for B). With this notation, the signed
+// product A*B can be written as:
+// AB = (-2^63 s(A) + A') * (-2^63 s(B) + B')
+// = 2^126 s(A)s(B) - 2^63 [s(A)B'+s(B)A'] + A'B'
+// = 2^126 s(A)s(B) + 2^63 [s(A)B'+s(B)A'] + A'B' - 2*2^63 [s(A)B'+s(B)A']
+// = (unsigned product AB) - 2^64 [s(A)B'+s(B)A']
+
+def : Pat <(mulhs I64:$Rss, I64:$Rtt),
+ (A2_subp
+ (MulHU $Rss, $Rtt),
+ (A2_addp
+ (A2_andp (S2_asr_i_p $Rss, 63), (ClearSign $Rtt)),
+ (A2_andp (S2_asr_i_p $Rtt, 63), (ClearSign $Rss))))>;
+
+// Hexagon specific ISD nodes.
+def SDTHexagonALLOCA : SDTypeProfile<1, 2,
+ [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+def HexagonALLOCA : SDNode<"HexagonISD::ALLOCA", SDTHexagonALLOCA,
+ [SDNPHasChain]>;
+
+
+def: Pat<(HexagonALLOCA I32:$Rs, (i32 imm:$A)),
+ (PS_alloca IntRegs:$Rs, imm:$A)>;
+
+def HexagonJT: SDNode<"HexagonISD::JT", SDTIntUnaryOp>;
+def HexagonCP: SDNode<"HexagonISD::CP", SDTIntUnaryOp>;
+
+def: Pat<(HexagonJT tjumptable:$dst), (A2_tfrsi imm:$dst)>;
+def: Pat<(HexagonCP tconstpool:$dst), (A2_tfrsi imm:$dst)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (sra I32:$Rs, u5_0ImmPred:$u5)), (S2_asr_i_r_acc IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(sub I32:$src1, (sra I32:$Rs, u5_0ImmPred:$u5)), (S2_asr_i_r_nac IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(and I32:$src1, (sra I32:$Rs, u5_0ImmPred:$u5)), (S2_asr_i_r_and IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(or I32:$src1, (sra I32:$Rs, u5_0ImmPred:$u5)), (S2_asr_i_r_or IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (sra I64:$Rs, u6_0ImmPred:$u5)), (S2_asr_i_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(sub I64:$src1, (sra I64:$Rs, u6_0ImmPred:$u5)), (S2_asr_i_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(and I64:$src1, (sra I64:$Rs, u6_0ImmPred:$u5)), (S2_asr_i_p_and DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(or I64:$src1, (sra I64:$Rs, u6_0ImmPred:$u5)), (S2_asr_i_p_or DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (srl I32:$Rs, u5_0ImmPred:$u5)), (S2_lsr_i_r_acc IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(sub I32:$src1, (srl I32:$Rs, u5_0ImmPred:$u5)), (S2_lsr_i_r_nac IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(and I32:$src1, (srl I32:$Rs, u5_0ImmPred:$u5)), (S2_lsr_i_r_and IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(or I32:$src1, (srl I32:$Rs, u5_0ImmPred:$u5)), (S2_lsr_i_r_or IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+let AddedComplexity = 100 in
+def: Pat<(xor I32:$src1, (srl I32:$Rs, u5_0ImmPred:$u5)), (S2_lsr_i_r_xacc IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (srl I64:$Rs, u6_0ImmPred:$u5)), (S2_lsr_i_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(sub I64:$src1, (srl I64:$Rs, u6_0ImmPred:$u5)), (S2_lsr_i_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(and I64:$src1, (srl I64:$Rs, u6_0ImmPred:$u5)), (S2_lsr_i_p_and DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(or I64:$src1, (srl I64:$Rs, u6_0ImmPred:$u5)), (S2_lsr_i_p_or DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+let AddedComplexity = 100 in
+def: Pat<(xor I64:$src1, (srl I64:$Rs, u6_0ImmPred:$u5)), (S2_lsr_i_p_xacc DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (shl I32:$Rs, u5_0ImmPred:$u5)), (S2_asl_i_r_acc IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(sub I32:$src1, (shl I32:$Rs, u5_0ImmPred:$u5)), (S2_asl_i_r_nac IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(and I32:$src1, (shl I32:$Rs, u5_0ImmPred:$u5)), (S2_asl_i_r_and IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+def: Pat<(or I32:$src1, (shl I32:$Rs, u5_0ImmPred:$u5)), (S2_asl_i_r_or IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+let AddedComplexity = 100 in
+def: Pat<(xor I32:$src1, (shl I32:$Rs, u5_0ImmPred:$u5)), (S2_asl_i_r_xacc IntRegs:$src1, IntRegs:$Rs, u5_0ImmPred:$u5)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (shl I64:$Rs, u6_0ImmPred:$u5)), (S2_asl_i_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(sub I64:$src1, (shl I64:$Rs, u6_0ImmPred:$u5)), (S2_asl_i_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(and I64:$src1, (shl I64:$Rs, u6_0ImmPred:$u5)), (S2_asl_i_p_and DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+def: Pat<(or I64:$src1, (shl I64:$Rs, u6_0ImmPred:$u5)), (S2_asl_i_p_or DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+let AddedComplexity = 100 in
+def: Pat<(xor I64:$src1, (shl I64:$Rs, u6_0ImmPred:$u5)), (S2_asl_i_p_xacc DoubleRegs:$src1, DoubleRegs:$Rs, u6_0ImmPred:$u5)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_asl_r_r_acc IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_asl_r_r_nac IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_asl_r_r_and IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_asl_r_r_or IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_asl_r_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_asl_r_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_asl_r_p_and DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_asl_r_p_or DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(xor I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_asl_r_p_xor DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (sra I32:$Rs, I32:$Rt)), (S2_asr_r_r_acc IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I32:$src1, (sra I32:$Rs, I32:$Rt)), (S2_asr_r_r_nac IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I32:$src1, (sra I32:$Rs, I32:$Rt)), (S2_asr_r_r_and IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I32:$src1, (sra I32:$Rs, I32:$Rt)), (S2_asr_r_r_or IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (sra I64:$Rs, I32:$Rt)), (S2_asr_r_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I64:$src1, (sra I64:$Rs, I32:$Rt)), (S2_asr_r_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I64:$src1, (sra I64:$Rs, I32:$Rt)), (S2_asr_r_p_and DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I64:$src1, (sra I64:$Rs, I32:$Rt)), (S2_asr_r_p_or DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(xor I64:$src1, (sra I64:$Rs, I32:$Rt)), (S2_asr_r_p_xor DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (srl I32:$Rs, I32:$Rt)), (S2_lsr_r_r_acc IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I32:$src1, (srl I32:$Rs, I32:$Rt)), (S2_lsr_r_r_nac IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I32:$src1, (srl I32:$Rs, I32:$Rt)), (S2_lsr_r_r_and IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I32:$src1, (srl I32:$Rs, I32:$Rt)), (S2_lsr_r_r_or IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (srl I64:$Rs, I32:$Rt)), (S2_lsr_r_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I64:$src1, (srl I64:$Rs, I32:$Rt)), (S2_lsr_r_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I64:$src1, (srl I64:$Rs, I32:$Rt)), (S2_lsr_r_p_and DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I64:$src1, (srl I64:$Rs, I32:$Rt)), (S2_lsr_r_p_or DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(xor I64:$src1, (srl I64:$Rs, I32:$Rt)), (S2_lsr_r_p_xor DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+
+let AddedComplexity = 100 in
+def: Pat<(add I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_lsl_r_r_acc IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_lsl_r_r_nac IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_lsl_r_r_and IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I32:$src1, (shl I32:$Rs, I32:$Rt)), (S2_lsl_r_r_or IntRegs:$src1, IntRegs:$Rs, IntRegs:$Rt)>;
+let AddedComplexity = 100 in
+def: Pat<(add I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_lsl_r_p_acc DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(sub I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_lsl_r_p_nac DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(and I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_lsl_r_p_and DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(or I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_lsl_r_p_or DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+def: Pat<(xor I64:$src1, (shl I64:$Rs, I32:$Rt)), (S2_lsl_r_p_xor DoubleRegs:$src1, DoubleRegs:$Rs, IntRegs:$Rt)>;
+
+def: Pat<(sra I64:$src1, I32:$src2), (S2_asr_r_p DoubleRegs:$src1, IntRegs:$src2)>;
+def: Pat<(srl I64:$src1, I32:$src2), (S2_lsr_r_p DoubleRegs:$src1, IntRegs:$src2)>;
+def: Pat<(shl I64:$src1, I32:$src2), (S2_asl_r_p DoubleRegs:$src1, IntRegs:$src2)>;
+def: Pat<(shl I64:$src1, I32:$src2), (S2_lsl_r_p DoubleRegs:$src1, IntRegs:$src2)>;
+
+def: Pat<(sra I32:$src1, I32:$src2), (S2_asr_r_r IntRegs:$src1, IntRegs:$src2)>;
+def: Pat<(srl I32:$src1, I32:$src2), (S2_lsr_r_r IntRegs:$src1, IntRegs:$src2)>;
+def: Pat<(shl I32:$src1, I32:$src2), (S2_asl_r_r IntRegs:$src1, IntRegs:$src2)>;
+def: Pat<(shl I32:$src1, I32:$src2), (S2_lsl_r_r IntRegs:$src1, IntRegs:$src2)>;
+
+def SDTHexagonINSERT:
+ SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
+ SDTCisInt<0>, SDTCisVT<3, i32>, SDTCisVT<4, i32>]>;
+def SDTHexagonINSERTRP:
+ SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
+ SDTCisInt<0>, SDTCisVT<3, i64>]>;
+
+def HexagonINSERT : SDNode<"HexagonISD::INSERT", SDTHexagonINSERT>;
+def HexagonINSERTRP : SDNode<"HexagonISD::INSERTRP", SDTHexagonINSERTRP>;
+
+def: Pat<(HexagonINSERT I32:$Rs, I32:$Rt, u5_0ImmPred:$u1, u5_0ImmPred:$u2),
+ (S2_insert I32:$Rs, I32:$Rt, u5_0ImmPred:$u1, u5_0ImmPred:$u2)>;
+def: Pat<(HexagonINSERT I64:$Rs, I64:$Rt, u6_0ImmPred:$u1, u6_0ImmPred:$u2),
+ (S2_insertp I64:$Rs, I64:$Rt, u6_0ImmPred:$u1, u6_0ImmPred:$u2)>;
+def: Pat<(HexagonINSERTRP I32:$Rs, I32:$Rt, I64:$Ru),
+ (S2_insert_rp I32:$Rs, I32:$Rt, I64:$Ru)>;
+def: Pat<(HexagonINSERTRP I64:$Rs, I64:$Rt, I64:$Ru),
+ (S2_insertp_rp I64:$Rs, I64:$Rt, I64:$Ru)>;
+
+let AddedComplexity = 100 in
+def: Pat<(or (or (shl (HexagonINSERT (i32 (zextloadi8 (add I32:$b, 2))),
+ (i32 (extloadi8 (add I32:$b, 3))),
+ 24, 8),
+ (i32 16)),
+ (shl (i32 (zextloadi8 (add I32:$b, 1))), (i32 8))),
+ (zextloadi8 I32:$b)),
+ (A2_swiz (L2_loadri_io I32:$b, 0))>;
+
+def SDTHexagonEXTRACTU:
+ SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisInt<1>,
+ SDTCisVT<2, i32>, SDTCisVT<3, i32>]>;
+def SDTHexagonEXTRACTURP:
+ SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisInt<1>,
+ SDTCisVT<2, i64>]>;
+
+def HexagonEXTRACTU : SDNode<"HexagonISD::EXTRACTU", SDTHexagonEXTRACTU>;
+def HexagonEXTRACTURP : SDNode<"HexagonISD::EXTRACTURP", SDTHexagonEXTRACTURP>;
+
+def: Pat<(HexagonEXTRACTU I32:$src1, u5_0ImmPred:$src2, u5_0ImmPred:$src3),
+ (S2_extractu I32:$src1, u5_0ImmPred:$src2, u5_0ImmPred:$src3)>;
+def: Pat<(HexagonEXTRACTU I64:$src1, u6_0ImmPred:$src2, u6_0ImmPred:$src3),
+ (S2_extractup I64:$src1, u6_0ImmPred:$src2, u6_0ImmPred:$src3)>;
+def: Pat<(HexagonEXTRACTURP I32:$src1, I64:$src2),
+ (S2_extractu_rp I32:$src1, I64:$src2)>;
+def: Pat<(HexagonEXTRACTURP I64:$src1, I64:$src2),
+ (S2_extractup_rp I64:$src1, I64:$src2)>;
+
+def n8_0ImmPred: PatLeaf<(i32 imm), [{
+ int64_t V = N->getSExtValue();
+ return -255 <= V && V <= 0;
+}]>;
+
+// Change the sign of the immediate for Rd=-mpyi(Rs,#u8)
+def: Pat<(mul I32:$src1, (ineg n8_0ImmPred:$src2)),
+ (M2_mpysin IntRegs:$src1, u8_0ImmPred:$src2)>;
+
+multiclass MinMax_pats_p<PatFrag Op, InstHexagon Inst, InstHexagon SwapInst> {
+ defm: T_MinMax_pats<Op, I64, Inst, SwapInst>;
+}
+
+def: Pat<(add (Sext64 I32:$Rs), I64:$Rt),
+ (A2_addsp IntRegs:$Rs, DoubleRegs:$Rt)>;
+
+let AddedComplexity = 200 in {
+ defm: MinMax_pats_p<setge, A2_maxp, A2_minp>;
+ defm: MinMax_pats_p<setgt, A2_maxp, A2_minp>;
+ defm: MinMax_pats_p<setle, A2_minp, A2_maxp>;
+ defm: MinMax_pats_p<setlt, A2_minp, A2_maxp>;
+ defm: MinMax_pats_p<setuge, A2_maxup, A2_minup>;
+ defm: MinMax_pats_p<setugt, A2_maxup, A2_minup>;
+ defm: MinMax_pats_p<setule, A2_minup, A2_maxup>;
+ defm: MinMax_pats_p<setult, A2_minup, A2_maxup>;
+}
+
+def callv3 : SDNode<"HexagonISD::CALL", SDT_SPCall,
+ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>;
+
+def callv3nr : SDNode<"HexagonISD::CALLnr", SDT_SPCall,
+ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>;
+
+
+// Map call instruction
+def : Pat<(callv3 I32:$dst),
+ (J2_callr I32:$dst)>;
+def : Pat<(callv3 tglobaladdr:$dst),
+ (J2_call tglobaladdr:$dst)>;
+def : Pat<(callv3 texternalsym:$dst),
+ (J2_call texternalsym:$dst)>;
+def : Pat<(callv3 tglobaltlsaddr:$dst),
+ (J2_call tglobaltlsaddr:$dst)>;
+
+def : Pat<(callv3nr I32:$dst),
+ (PS_callr_nr I32:$dst)>;
+def : Pat<(callv3nr tglobaladdr:$dst),
+ (PS_call_nr tglobaladdr:$dst)>;
+def : Pat<(callv3nr texternalsym:$dst),
+ (PS_call_nr texternalsym:$dst)>;
+
+
+def addrga: PatLeaf<(i32 AddrGA:$Addr)>;
+def addrgp: PatLeaf<(i32 AddrGP:$Addr)>;
+
+
+// Pats for instruction selection.
+
+// A class to embed the usual comparison patfrags within a zext to i32.
+// The seteq/setne frags use "lhs" and "rhs" as operands, so use the same
+// names, or else the frag's "body" won't match the operands.
+class CmpInReg<PatFrag Op>
+ : PatFrag<(ops node:$lhs, node:$rhs),(i32 (zext (i1 Op.Fragment)))>;
+
+def: T_cmp32_rr_pat<A4_rcmpeq, CmpInReg<seteq>, i32>;
+def: T_cmp32_rr_pat<A4_rcmpneq, CmpInReg<setne>, i32>;
+
+def: T_cmp32_rr_pat<C4_cmpneq, setne, i1>;
+def: T_cmp32_rr_pat<C4_cmplte, setle, i1>;
+def: T_cmp32_rr_pat<C4_cmplteu, setule, i1>;
+
+def: T_cmp32_rr_pat<C4_cmplte, RevCmp<setge>, i1>;
+def: T_cmp32_rr_pat<C4_cmplteu, RevCmp<setuge>, i1>;
+
+let AddedComplexity = 100 in {
+ def: Pat<(i1 (seteq (and (xor I32:$Rs, I32:$Rt),
+ 255), 0)),
+ (A4_cmpbeq IntRegs:$Rs, IntRegs:$Rt)>;
+ def: Pat<(i1 (setne (and (xor I32:$Rs, I32:$Rt),
+ 255), 0)),
+ (C2_not (A4_cmpbeq IntRegs:$Rs, IntRegs:$Rt))>;
+ def: Pat<(i1 (seteq (and (xor I32:$Rs, I32:$Rt),
+ 65535), 0)),
+ (A4_cmpheq IntRegs:$Rs, IntRegs:$Rt)>;
+ def: Pat<(i1 (setne (and (xor I32:$Rs, I32:$Rt),
+ 65535), 0)),
+ (C2_not (A4_cmpheq IntRegs:$Rs, IntRegs:$Rt))>;
+}
+
+def: Pat<(i32 (zext (i1 (seteq I32:$Rs, s32_0ImmPred:$s8)))),
+ (A4_rcmpeqi IntRegs:$Rs, s32_0ImmPred:$s8)>;
+def: Pat<(i32 (zext (i1 (setne I32:$Rs, s32_0ImmPred:$s8)))),
+ (A4_rcmpneqi IntRegs:$Rs, s32_0ImmPred:$s8)>;
+
+// Preserve the S2_tstbit_r generation
+def: Pat<(i32 (zext (i1 (setne (i32 (and (i32 (shl 1, I32:$src2)),
+ I32:$src1)), 0)))),
+ (C2_muxii (S2_tstbit_r IntRegs:$src1, IntRegs:$src2), 1, 0)>;
+
+// The complexity of the combines involving immediates should be greater
+// than the complexity of the combine with two registers.
+let AddedComplexity = 50 in {
+def: Pat<(HexagonCOMBINE IntRegs:$r, s32_0ImmPred:$i),
+ (A4_combineri IntRegs:$r, s32_0ImmPred:$i)>;
+
+def: Pat<(HexagonCOMBINE s32_0ImmPred:$i, IntRegs:$r),
+ (A4_combineir s32_0ImmPred:$i, IntRegs:$r)>;
+}
+
+// The complexity of the combine with two immediates should be greater than
+// the complexity of a combine involving a register.
+let AddedComplexity = 75 in {
+def: Pat<(HexagonCOMBINE s8_0ImmPred:$s8, u32_0ImmPred:$u6),
+ (A4_combineii imm:$s8, imm:$u6)>;
+def: Pat<(HexagonCOMBINE s32_0ImmPred:$s8, s8_0ImmPred:$S8),
+ (A2_combineii imm:$s8, imm:$S8)>;
+}
+
+
+def ToZext64: OutPatFrag<(ops node:$Rs),
+ (i64 (A4_combineir 0, (i32 $Rs)))>;
+def ToSext64: OutPatFrag<(ops node:$Rs),
+ (i64 (A2_sxtw (i32 $Rs)))>;
+
+// Patterns to generate indexed loads with different forms of the address:
+// - frameindex,
+// - base + offset,
+// - base (without offset).
+multiclass Loadxm_pat<PatFrag Load, ValueType VT, PatFrag ValueMod,
+ PatLeaf ImmPred, InstHexagon MI> {
+ def: Pat<(VT (Load AddrFI:$fi)),
+ (VT (ValueMod (MI AddrFI:$fi, 0)))>;
+ def: Pat<(VT (Load (add AddrFI:$fi, ImmPred:$Off))),
+ (VT (ValueMod (MI AddrFI:$fi, imm:$Off)))>;
+ def: Pat<(VT (Load (add IntRegs:$Rs, ImmPred:$Off))),
+ (VT (ValueMod (MI IntRegs:$Rs, imm:$Off)))>;
+ def: Pat<(VT (Load I32:$Rs)),
+ (VT (ValueMod (MI IntRegs:$Rs, 0)))>;
+}
+
+defm: Loadxm_pat<extloadi1, i64, ToZext64, s32_0ImmPred, L2_loadrub_io>;
+defm: Loadxm_pat<extloadi8, i64, ToZext64, s32_0ImmPred, L2_loadrub_io>;
+defm: Loadxm_pat<extloadi16, i64, ToZext64, s31_1ImmPred, L2_loadruh_io>;
+defm: Loadxm_pat<zextloadi1, i64, ToZext64, s32_0ImmPred, L2_loadrub_io>;
+defm: Loadxm_pat<zextloadi8, i64, ToZext64, s32_0ImmPred, L2_loadrub_io>;
+defm: Loadxm_pat<zextloadi16, i64, ToZext64, s31_1ImmPred, L2_loadruh_io>;
+defm: Loadxm_pat<sextloadi8, i64, ToSext64, s32_0ImmPred, L2_loadrb_io>;
+defm: Loadxm_pat<sextloadi16, i64, ToSext64, s31_1ImmPred, L2_loadrh_io>;
+
+// Map Rdd = anyext(Rs) -> Rdd = combine(#0, Rs).
+def: Pat<(Aext64 I32:$src1), (ToZext64 IntRegs:$src1)>;
+
+multiclass T_LoadAbsReg_Pat <PatFrag ldOp, InstHexagon MI, ValueType VT = i32> {
+ def : Pat <(VT (ldOp (add (shl IntRegs:$src1, u2_0ImmPred:$src2),
+ (HexagonCONST32 tglobaladdr:$src3)))),
+ (MI IntRegs:$src1, u2_0ImmPred:$src2, tglobaladdr:$src3)>;
+ def : Pat <(VT (ldOp (add IntRegs:$src1,
+ (HexagonCONST32 tglobaladdr:$src2)))),
+ (MI IntRegs:$src1, 0, tglobaladdr:$src2)>;
+
+ def : Pat <(VT (ldOp (add (shl IntRegs:$src1, u2_0ImmPred:$src2),
+ (HexagonCONST32 tconstpool:$src3)))),
+ (MI IntRegs:$src1, u2_0ImmPred:$src2, tconstpool:$src3)>;
+ def : Pat <(VT (ldOp (add IntRegs:$src1,
+ (HexagonCONST32 tconstpool:$src2)))),
+ (MI IntRegs:$src1, 0, tconstpool:$src2)>;
+
+ def : Pat <(VT (ldOp (add (shl IntRegs:$src1, u2_0ImmPred:$src2),
+ (HexagonCONST32 tjumptable:$src3)))),
+ (MI IntRegs:$src1, u2_0ImmPred:$src2, tjumptable:$src3)>;
+ def : Pat <(VT (ldOp (add IntRegs:$src1,
+ (HexagonCONST32 tjumptable:$src2)))),
+ (MI IntRegs:$src1, 0, tjumptable:$src2)>;
+}
+
+let AddedComplexity = 60 in {
+defm : T_LoadAbsReg_Pat <sextloadi8, L4_loadrb_ur>;
+defm : T_LoadAbsReg_Pat <zextloadi8, L4_loadrub_ur>;
+defm : T_LoadAbsReg_Pat <extloadi8, L4_loadrub_ur>;
+
+defm : T_LoadAbsReg_Pat <sextloadi16, L4_loadrh_ur>;
+defm : T_LoadAbsReg_Pat <zextloadi16, L4_loadruh_ur>;
+defm : T_LoadAbsReg_Pat <extloadi16, L4_loadruh_ur>;
+
+defm : T_LoadAbsReg_Pat <load, L4_loadri_ur>;
+defm : T_LoadAbsReg_Pat <load, L4_loadrd_ur, i64>;
+}
+
+// 'def pats' for load instructions with base + register offset and non-zero
+// immediate value. Immediate value is used to left-shift the second
+// register operand.
+class Loadxs_pat<PatFrag Load, ValueType VT, InstHexagon MI>
+ : Pat<(VT (Load (add I32:$Rs,
+ (i32 (shl I32:$Rt, u2_0ImmPred:$u2))))),
+ (VT (MI IntRegs:$Rs, IntRegs:$Rt, imm:$u2))>;
+
+let AddedComplexity = 40 in {
+ def: Loadxs_pat<extloadi8, i32, L4_loadrub_rr>;
+ def: Loadxs_pat<zextloadi8, i32, L4_loadrub_rr>;
+ def: Loadxs_pat<sextloadi8, i32, L4_loadrb_rr>;
+ def: Loadxs_pat<extloadi16, i32, L4_loadruh_rr>;
+ def: Loadxs_pat<zextloadi16, i32, L4_loadruh_rr>;
+ def: Loadxs_pat<sextloadi16, i32, L4_loadrh_rr>;
+ def: Loadxs_pat<load, i32, L4_loadri_rr>;
+ def: Loadxs_pat<load, i64, L4_loadrd_rr>;
+}
+
+// 'def pats' for load instruction base + register offset and
+// zero immediate value.
+class Loadxs_simple_pat<PatFrag Load, ValueType VT, InstHexagon MI>
+ : Pat<(VT (Load (add I32:$Rs, I32:$Rt))),
+ (VT (MI IntRegs:$Rs, IntRegs:$Rt, 0))>;
+
+let AddedComplexity = 20 in {
+ def: Loadxs_simple_pat<extloadi8, i32, L4_loadrub_rr>;
+ def: Loadxs_simple_pat<zextloadi8, i32, L4_loadrub_rr>;
+ def: Loadxs_simple_pat<sextloadi8, i32, L4_loadrb_rr>;
+ def: Loadxs_simple_pat<extloadi16, i32, L4_loadruh_rr>;
+ def: Loadxs_simple_pat<zextloadi16, i32, L4_loadruh_rr>;
+ def: Loadxs_simple_pat<sextloadi16, i32, L4_loadrh_rr>;
+ def: Loadxs_simple_pat<load, i32, L4_loadri_rr>;
+ def: Loadxs_simple_pat<load, i64, L4_loadrd_rr>;
+}
+
+// zext i1->i64
+def: Pat<(i64 (zext I1:$src1)),
+ (ToZext64 (C2_muxii PredRegs:$src1, 1, 0))>;
+
+// zext i32->i64
+def: Pat<(Zext64 I32:$src1),
+ (ToZext64 IntRegs:$src1)>;
+
+let AddedComplexity = 40 in
+multiclass T_StoreAbsReg_Pats <InstHexagon MI, RegisterClass RC, ValueType VT,
+ PatFrag stOp> {
+ def : Pat<(stOp (VT RC:$src4),
+ (add (shl I32:$src1, u2_0ImmPred:$src2),
+ u32_0ImmPred:$src3)),
+ (MI IntRegs:$src1, u2_0ImmPred:$src2, u32_0ImmPred:$src3, RC:$src4)>;
+
+ def : Pat<(stOp (VT RC:$src4),
+ (add (shl IntRegs:$src1, u2_0ImmPred:$src2),
+ (HexagonCONST32 tglobaladdr:$src3))),
+ (MI IntRegs:$src1, u2_0ImmPred:$src2, tglobaladdr:$src3, RC:$src4)>;
+
+ def : Pat<(stOp (VT RC:$src4),
+ (add IntRegs:$src1, (HexagonCONST32 tglobaladdr:$src3))),
+ (MI IntRegs:$src1, 0, tglobaladdr:$src3, RC:$src4)>;
+}
+
+defm : T_StoreAbsReg_Pats <S4_storerd_ur, DoubleRegs, i64, store>;
+defm : T_StoreAbsReg_Pats <S4_storeri_ur, IntRegs, i32, store>;
+defm : T_StoreAbsReg_Pats <S4_storerb_ur, IntRegs, i32, truncstorei8>;
+defm : T_StoreAbsReg_Pats <S4_storerh_ur, IntRegs, i32, truncstorei16>;
+
+class Storexs_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
+ : Pat<(Store Value:$Ru, (add I32:$Rs,
+ (i32 (shl I32:$Rt, u2_0ImmPred:$u2)))),
+ (MI IntRegs:$Rs, IntRegs:$Rt, imm:$u2, Value:$Ru)>;
+
+let AddedComplexity = 40 in {
+ def: Storexs_pat<truncstorei8, I32, S4_storerb_rr>;
+ def: Storexs_pat<truncstorei16, I32, S4_storerh_rr>;
+ def: Storexs_pat<store, I32, S4_storeri_rr>;
+ def: Storexs_pat<store, I64, S4_storerd_rr>;
+}
+
+def s30_2ProperPred : PatLeaf<(i32 imm), [{
+ int64_t v = (int64_t)N->getSExtValue();
+ return isShiftedInt<30,2>(v) && !isShiftedInt<29,3>(v);
+}]>;
+def RoundTo8 : SDNodeXForm<imm, [{
+ int32_t Imm = N->getSExtValue();
+ return CurDAG->getTargetConstant(Imm & -8, SDLoc(N), MVT::i32);
+}]>;
+
+let AddedComplexity = 40 in
+def: Pat<(store I64:$Ru, (add I32:$Rs, s30_2ProperPred:$Off)),
+ (S2_storerd_io (A2_addi I32:$Rs, 4), (RoundTo8 $Off), I64:$Ru)>;
+
+class Store_rr_pat<PatFrag Store, PatFrag Value, InstHexagon MI>
+ : Pat<(Store Value:$Ru, (add I32:$Rs, I32:$Rt)),
+ (MI IntRegs:$Rs, IntRegs:$Rt, 0, Value:$Ru)>;
+
+let AddedComplexity = 20 in {
+ def: Store_rr_pat<truncstorei8, I32, S4_storerb_rr>;
+ def: Store_rr_pat<truncstorei16, I32, S4_storerh_rr>;
+ def: Store_rr_pat<store, I32, S4_storeri_rr>;
+ def: Store_rr_pat<store, I64, S4_storerd_rr>;
+}
+
+
+def IMM_BYTE : SDNodeXForm<imm, [{
+ // -1 etc is represented as 255 etc
+ // assigning to a byte restores our desired signed value.
+ int8_t imm = N->getSExtValue();
+ return CurDAG->getTargetConstant(imm, SDLoc(N), MVT::i32);
+}]>;
+
+def IMM_HALF : SDNodeXForm<imm, [{
+ // -1 etc is represented as 65535 etc
+ // assigning to a short restores our desired signed value.
+ int16_t imm = N->getSExtValue();
+ return CurDAG->getTargetConstant(imm, SDLoc(N), MVT::i32);
+}]>;
+
+def IMM_WORD : SDNodeXForm<imm, [{
+ // -1 etc can be represented as 4294967295 etc
+ // Currently, it's not doing this. But some optimization
+ // might convert -1 to a large +ve number.
+ // assigning to a word restores our desired signed value.
+ int32_t imm = N->getSExtValue();
+ return CurDAG->getTargetConstant(imm, SDLoc(N), MVT::i32);
+}]>;
+
+def ToImmByte : OutPatFrag<(ops node:$R), (IMM_BYTE $R)>;
+def ToImmHalf : OutPatFrag<(ops node:$R), (IMM_HALF $R)>;
+def ToImmWord : OutPatFrag<(ops node:$R), (IMM_WORD $R)>;
+
+// Emit store-immediate, but only when the stored value will not be constant-
+// extended. The reason for that is that there is no pass that can optimize
+// constant extenders in store-immediate instructions. In some cases we can
+// end up will a number of such stores, all of which store the same extended
+// value (e.g. after unrolling a loop that initializes floating point array).
+
+// Predicates to determine if the 16-bit immediate is expressible as a sign-
+// extended 8-bit immediate. Store-immediate-halfword will ignore any bits
+// beyond 0..15, so we don't care what is in there.
+
+def i16in8ImmPred: PatLeaf<(i32 imm), [{
+ int64_t v = (int16_t)N->getSExtValue();
+ return v == (int64_t)(int8_t)v;
+}]>;
+
+// Predicates to determine if the 32-bit immediate is expressible as a sign-
+// extended 8-bit immediate.
+def i32in8ImmPred: PatLeaf<(i32 imm), [{
+ int64_t v = (int32_t)N->getSExtValue();
+ return v == (int64_t)(int8_t)v;
+}]>;
+
+
+let AddedComplexity = 40 in {
+ // Even though the offset is not extendable in the store-immediate, we
+ // can still generate the fi# in the base address. If the final offset
+ // is not valid for the instruction, we will replace it with a scratch
+ // register.
+// def: Storexm_fi_pat <truncstorei8, s32_0ImmPred, ToImmByte, S4_storeirb_io>;
+// def: Storexm_fi_pat <truncstorei16, i16in8ImmPred, ToImmHalf,
+// S4_storeirh_io>;
+// def: Storexm_fi_pat <store, i32in8ImmPred, ToImmWord, S4_storeiri_io>;
+
+// defm: Storexm_fi_add_pat <truncstorei8, s32_0ImmPred, u6_0ImmPred, ToImmByte,
+// S4_storeirb_io>;
+// defm: Storexm_fi_add_pat <truncstorei16, i16in8ImmPred, u6_1ImmPred,
+// ToImmHalf, S4_storeirh_io>;
+// defm: Storexm_fi_add_pat <store, i32in8ImmPred, u6_2ImmPred, ToImmWord,
+// S4_storeiri_io>;
+
+ defm: Storexm_add_pat<truncstorei8, s32_0ImmPred, u6_0ImmPred, ToImmByte,
+ S4_storeirb_io>;
+ defm: Storexm_add_pat<truncstorei16, i16in8ImmPred, u6_1ImmPred, ToImmHalf,
+ S4_storeirh_io>;
+ defm: Storexm_add_pat<store, i32in8ImmPred, u6_2ImmPred, ToImmWord,
+ S4_storeiri_io>;
+}
+
+def: Storexm_simple_pat<truncstorei8, s32_0ImmPred, ToImmByte, S4_storeirb_io>;
+def: Storexm_simple_pat<truncstorei16, s32_0ImmPred, ToImmHalf, S4_storeirh_io>;
+def: Storexm_simple_pat<store, s32_0ImmPred, ToImmWord, S4_storeiri_io>;
+
+// op(Ps, op(Pt, Pu))
+class LogLog_pat<SDNode Op1, SDNode Op2, InstHexagon MI>
+ : Pat<(i1 (Op1 I1:$Ps, (Op2 I1:$Pt, I1:$Pu))),
+ (MI I1:$Ps, I1:$Pt, I1:$Pu)>;
+
+// op(Ps, op(Pt, ~Pu))
+class LogLogNot_pat<SDNode Op1, SDNode Op2, InstHexagon MI>
+ : Pat<(i1 (Op1 I1:$Ps, (Op2 I1:$Pt, (not I1:$Pu)))),
+ (MI I1:$Ps, I1:$Pt, I1:$Pu)>;
+
+def: LogLog_pat<and, and, C4_and_and>;
+def: LogLog_pat<and, or, C4_and_or>;
+def: LogLog_pat<or, and, C4_or_and>;
+def: LogLog_pat<or, or, C4_or_or>;
+
+def: LogLogNot_pat<and, and, C4_and_andn>;
+def: LogLogNot_pat<and, or, C4_and_orn>;
+def: LogLogNot_pat<or, and, C4_or_andn>;
+def: LogLogNot_pat<or, or, C4_or_orn>;
+
+//===----------------------------------------------------------------------===//
+// PIC: Support for PIC compilations. The patterns and SD nodes defined
+// below are needed to support code generation for PIC
+//===----------------------------------------------------------------------===//
+
+def SDT_HexagonAtGot
+ : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, SDTCisVT<2, i32>]>;
+def SDT_HexagonAtPcrel
+ : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+
+// AT_GOT address-of-GOT, address-of-global, offset-in-global
+def HexagonAtGot : SDNode<"HexagonISD::AT_GOT", SDT_HexagonAtGot>;
+// AT_PCREL address-of-global
+def HexagonAtPcrel : SDNode<"HexagonISD::AT_PCREL", SDT_HexagonAtPcrel>;
+
+def: Pat<(HexagonAtGot I32:$got, I32:$addr, (i32 0)),
+ (L2_loadri_io I32:$got, imm:$addr)>;
+def: Pat<(HexagonAtGot I32:$got, I32:$addr, s30_2ImmPred:$off),
+ (A2_addi (L2_loadri_io I32:$got, imm:$addr), imm:$off)>;
+def: Pat<(HexagonAtPcrel I32:$addr),
+ (C4_addipc imm:$addr)>;
+
+def: Pat<(i64 (and I64:$Rs, (i64 (not I64:$Rt)))),
+ (A4_andnp DoubleRegs:$Rs, DoubleRegs:$Rt)>;
+def: Pat<(i64 (or I64:$Rs, (i64 (not I64:$Rt)))),
+ (A4_ornp DoubleRegs:$Rs, DoubleRegs:$Rt)>;
+
+def: Pat<(add I32:$Rs, (add I32:$Ru, s32_0ImmPred:$s6)),
+ (S4_addaddi IntRegs:$Rs, IntRegs:$Ru, imm:$s6)>;
+
+// Rd=add(Rs,sub(#s6,Ru))
+def: Pat<(add I32:$src1, (sub s32_0ImmPred:$src2,
+ I32:$src3)),
+ (S4_subaddi IntRegs:$src1, s32_0ImmPred:$src2, IntRegs:$src3)>;
+
+// Rd=sub(add(Rs,#s6),Ru)
+def: Pat<(sub (add I32:$src1, s32_0ImmPred:$src2),
+ I32:$src3),
+ (S4_subaddi IntRegs:$src1, s32_0ImmPred:$src2, IntRegs:$src3)>;
+
+// Rd=add(sub(Rs,Ru),#s6)
+def: Pat<(add (sub I32:$src1, I32:$src3),
+ (s32_0ImmPred:$src2)),
+ (S4_subaddi IntRegs:$src1, s32_0ImmPred:$src2, IntRegs:$src3)>;
+
+def: Pat<(xor I64:$dst2,
+ (xor I64:$Rss, I64:$Rtt)),
+ (M4_xor_xacc DoubleRegs:$dst2, DoubleRegs:$Rss, DoubleRegs:$Rtt)>;
+def: Pat<(or I32:$Ru, (and (i32 IntRegs:$_src_), s32_0ImmPred:$s10)),
+ (S4_or_andix IntRegs:$Ru, IntRegs:$_src_, imm:$s10)>;
+
+def: Pat<(or I32:$src1, (and I32:$Rs, s32_0ImmPred:$s10)),
+ (S4_or_andi IntRegs:$src1, IntRegs:$Rs, imm:$s10)>;
+
+def: Pat<(or I32:$src1, (or I32:$Rs, s32_0ImmPred:$s10)),
+ (S4_or_ori IntRegs:$src1, IntRegs:$Rs, imm:$s10)>;
+
+
+
+// Count trailing zeros: 64-bit.
+def: Pat<(i32 (trunc (cttz I64:$Rss))), (S2_ct0p I64:$Rss)>;
+
+// Count trailing ones: 64-bit.
+def: Pat<(i32 (trunc (cttz (not I64:$Rss)))), (S2_ct1p I64:$Rss)>;
+
+// Define leading/trailing patterns that require zero-extensions to 64 bits.
+def: Pat<(i64 (ctlz I64:$Rss)), (ToZext64 (S2_cl0p I64:$Rss))>;
+def: Pat<(i64 (cttz I64:$Rss)), (ToZext64 (S2_ct0p I64:$Rss))>;
+def: Pat<(i64 (ctlz (not I64:$Rss))), (ToZext64 (S2_cl1p I64:$Rss))>;
+def: Pat<(i64 (cttz (not I64:$Rss))), (ToZext64 (S2_ct1p I64:$Rss))>;
+
+
+let AddedComplexity = 20 in { // Complexity greater than cmp reg-imm.
+ def: Pat<(i1 (seteq (and (shl 1, u5_0ImmPred:$u5), I32:$Rs), 0)),
+ (S4_ntstbit_i I32:$Rs, u5_0ImmPred:$u5)>;
+ def: Pat<(i1 (seteq (and (shl 1, I32:$Rt), I32:$Rs), 0)),
+ (S4_ntstbit_r I32:$Rs, I32:$Rt)>;
+}
+
+// Add extra complexity to prefer these instructions over bitsset/bitsclr.
+// The reason is that tstbit/ntstbit can be folded into a compound instruction:
+// if ([!]tstbit(...)) jump ...
+let AddedComplexity = 100 in
+def: Pat<(i1 (setne (and I32:$Rs, (i32 IsPow2_32:$u5)), (i32 0))),
+ (S2_tstbit_i I32:$Rs, (Log2_32 imm:$u5))>;
+
+let AddedComplexity = 100 in
+def: Pat<(i1 (seteq (and I32:$Rs, (i32 IsPow2_32:$u5)), (i32 0))),
+ (S4_ntstbit_i I32:$Rs, (Log2_32 imm:$u5))>;
+
+// Do not increase complexity of these patterns. In the DAG, "cmp i8" may be
+// represented as a compare against "value & 0xFF", which is an exact match
+// for cmpb (same for cmph). The patterns below do not contain any additional
+// complexity that would make them preferable, and if they were actually used
+// instead of cmpb/cmph, they would result in a compare against register that
+// is loaded with the byte/half mask (i.e. 0xFF or 0xFFFF).
+def: Pat<(i1 (setne (and I32:$Rs, u6_0ImmPred:$u6), 0)),
+ (C4_nbitsclri I32:$Rs, u6_0ImmPred:$u6)>;
+def: Pat<(i1 (setne (and I32:$Rs, I32:$Rt), 0)),
+ (C4_nbitsclr I32:$Rs, I32:$Rt)>;
+def: Pat<(i1 (setne (and I32:$Rs, I32:$Rt), I32:$Rt)),
+ (C4_nbitsset I32:$Rs, I32:$Rt)>;
+
+
+def: Pat<(add (mul I32:$Rs, u6_0ImmPred:$U6), u32_0ImmPred:$u6),
+ (M4_mpyri_addi imm:$u6, IntRegs:$Rs, imm:$U6)>;
+def: Pat<(add (mul I32:$Rs, I32:$Rt), u32_0ImmPred:$u6),
+ (M4_mpyrr_addi imm:$u6, IntRegs:$Rs, IntRegs:$Rt)>;
+
+def: Pat<(add I32:$src1, (mul I32:$src3, u6_2ImmPred:$src2)),
+ (M4_mpyri_addr_u2 IntRegs:$src1, imm:$src2, IntRegs:$src3)>;
+def: Pat<(add I32:$src1, (mul I32:$src3, u32_0ImmPred:$src2)),
+ (M4_mpyri_addr IntRegs:$src1, IntRegs:$src3, imm:$src2)>;
+
+def: Pat<(add I32:$Ru, (mul (i32 IntRegs:$_src_), I32:$Rs)),
+ (M4_mpyrr_addr IntRegs:$Ru, IntRegs:$_src_, IntRegs:$Rs)>;
+
+def: T_vcmp_pat<A4_vcmpbgt, setgt, v8i8>;
+
+class T_Shift_CommOp_pat<InstHexagon MI, SDNode Op, SDNode ShOp>
+ : Pat<(Op (ShOp IntRegs:$Rx, u5_0ImmPred:$U5), u32_0ImmPred:$u8),
+ (MI u32_0ImmPred:$u8, IntRegs:$Rx, u5_0ImmPred:$U5)>;
+
+let AddedComplexity = 200 in {
+ def : T_Shift_CommOp_pat <S4_addi_asl_ri, add, shl>;
+ def : T_Shift_CommOp_pat <S4_addi_lsr_ri, add, srl>;
+ def : T_Shift_CommOp_pat <S4_andi_asl_ri, and, shl>;
+ def : T_Shift_CommOp_pat <S4_andi_lsr_ri, and, srl>;
+}
+
+let AddedComplexity = 30 in {
+ def : T_Shift_CommOp_pat <S4_ori_asl_ri, or, shl>;
+ def : T_Shift_CommOp_pat <S4_ori_lsr_ri, or, srl>;
+}
+
+class T_Shift_Op_pat<InstHexagon MI, SDNode Op, SDNode ShOp>
+ : Pat<(Op u32_0ImmPred:$u8, (ShOp IntRegs:$Rx, u5_0ImmPred:$U5)),
+ (MI u32_0ImmPred:$u8, IntRegs:$Rx, u5_0ImmPred:$U5)>;
+
+def : T_Shift_Op_pat <S4_subi_asl_ri, sub, shl>;
+def : T_Shift_Op_pat <S4_subi_lsr_ri, sub, srl>;
+
+let AddedComplexity = 200 in {
+ def: Pat<(add addrga:$addr, (shl I32:$src2, u5_0ImmPred:$src3)),
+ (S4_addi_asl_ri addrga:$addr, IntRegs:$src2, u5_0ImmPred:$src3)>;
+ def: Pat<(add addrga:$addr, (srl I32:$src2, u5_0ImmPred:$src3)),
+ (S4_addi_lsr_ri addrga:$addr, IntRegs:$src2, u5_0ImmPred:$src3)>;
+ def: Pat<(sub addrga:$addr, (shl I32:$src2, u5_0ImmPred:$src3)),
+ (S4_subi_asl_ri addrga:$addr, IntRegs:$src2, u5_0ImmPred:$src3)>;
+ def: Pat<(sub addrga:$addr, (srl I32:$src2, u5_0ImmPred:$src3)),
+ (S4_subi_lsr_ri addrga:$addr, IntRegs:$src2, u5_0ImmPred:$src3)>;
+}
+
+def: Pat<(shl s6_0ImmPred:$s6, I32:$Rt),
+ (S4_lsli imm:$s6, IntRegs:$Rt)>;
+
+
+//===----------------------------------------------------------------------===//
+// MEMOP
+//===----------------------------------------------------------------------===//
+
+def m5_0Imm8Pred : PatLeaf<(i32 imm), [{
+ int8_t V = N->getSExtValue();
+ return -32 < V && V <= -1;
+}]>;
+
+def m5_0Imm16Pred : PatLeaf<(i32 imm), [{
+ int16_t V = N->getSExtValue();
+ return -32 < V && V <= -1;
+}]>;
+
+def m5_0ImmPred : PatLeaf<(i32 imm), [{
+ int64_t V = N->getSExtValue();
+ return -31 <= V && V <= -1;
+}]>;
+
+def IsNPow2_8 : PatLeaf<(i32 imm), [{
+ uint8_t NV = ~N->getZExtValue();
+ return isPowerOf2_32(NV);
+}]>;
+
+def IsNPow2_16 : PatLeaf<(i32 imm), [{
+ uint16_t NV = ~N->getZExtValue();
+ return isPowerOf2_32(NV);
+}]>;
+
+def Log2_8 : SDNodeXForm<imm, [{
+ uint8_t V = N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_32(V), SDLoc(N), MVT::i32);
+}]>;
+
+def Log2_16 : SDNodeXForm<imm, [{
+ uint16_t V = N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_32(V), SDLoc(N), MVT::i32);
+}]>;
+
+def LogN2_8 : SDNodeXForm<imm, [{
+ uint8_t NV = ~N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_32(NV), SDLoc(N), MVT::i32);
+}]>;
+
+def LogN2_16 : SDNodeXForm<imm, [{
+ uint16_t NV = ~N->getZExtValue();
+ return CurDAG->getTargetConstant(Log2_32(NV), SDLoc(N), MVT::i32);
+}]>;
+
+def NegImm8 : SDNodeXForm<imm, [{
+ int8_t NV = -N->getSExtValue();
+ return CurDAG->getTargetConstant(NV, SDLoc(N), MVT::i32);
+}]>;
+
+def NegImm16 : SDNodeXForm<imm, [{
+ int16_t NV = -N->getSExtValue();
+ return CurDAG->getTargetConstant(NV, SDLoc(N), MVT::i32);
+}]>;
+
+def NegImm32 : SDNodeXForm<imm, [{
+ int32_t NV = -N->getSExtValue();
+ return CurDAG->getTargetConstant(NV, SDLoc(N), MVT::i32);
+}]>;
+
+def IdImm : SDNodeXForm<imm, [{ return SDValue(N, 0); }]>;
+
+multiclass Memopxr_simple_pat<PatFrag Load, PatFrag Store, SDNode Oper,
+ InstHexagon MI> {
+ // Addr: i32
+ def: Pat<(Store (Oper (Load I32:$Rs), I32:$A), I32:$Rs),
+ (MI I32:$Rs, 0, I32:$A)>;
+ // Addr: fi
+ def: Pat<(Store (Oper (Load AddrFI:$Rs), I32:$A), AddrFI:$Rs),
+ (MI AddrFI:$Rs, 0, I32:$A)>;
+}
+
+multiclass Memopxr_add_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
+ SDNode Oper, InstHexagon MI> {
+ // Addr: i32
+ def: Pat<(Store (Oper (Load (add I32:$Rs, ImmPred:$Off)), I32:$A),
+ (add I32:$Rs, ImmPred:$Off)),
+ (MI I32:$Rs, imm:$Off, I32:$A)>;
+ def: Pat<(Store (Oper (Load (IsOrAdd I32:$Rs, ImmPred:$Off)), I32:$A),
+ (IsOrAdd I32:$Rs, ImmPred:$Off)),
+ (MI I32:$Rs, imm:$Off, I32:$A)>;
+ // Addr: fi
+ def: Pat<(Store (Oper (Load (add AddrFI:$Rs, ImmPred:$Off)), I32:$A),
+ (add AddrFI:$Rs, ImmPred:$Off)),
+ (MI AddrFI:$Rs, imm:$Off, I32:$A)>;
+ def: Pat<(Store (Oper (Load (IsOrAdd AddrFI:$Rs, ImmPred:$Off)), I32:$A),
+ (IsOrAdd AddrFI:$Rs, ImmPred:$Off)),
+ (MI AddrFI:$Rs, imm:$Off, I32:$A)>;
+}
+
+multiclass Memopxr_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
+ SDNode Oper, InstHexagon MI> {
+ defm: Memopxr_simple_pat <Load, Store, Oper, MI>;
+ defm: Memopxr_add_pat <Load, Store, ImmPred, Oper, MI>;
+}
+
+let AddedComplexity = 180 in {
+ // add reg
+ defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, add,
+ /*anyext*/ L4_add_memopb_io>;
+ defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, add,
+ /*sext*/ L4_add_memopb_io>;
+ defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, add,
+ /*zext*/ L4_add_memopb_io>;
+ defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, add,
+ /*anyext*/ L4_add_memoph_io>;
+ defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, add,
+ /*sext*/ L4_add_memoph_io>;
+ defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, add,
+ /*zext*/ L4_add_memoph_io>;
+ defm: Memopxr_pat<load, store, u6_2ImmPred, add, L4_add_memopw_io>;
+
+ // sub reg
+ defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, sub,
+ /*anyext*/ L4_sub_memopb_io>;
+ defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, sub,
+ /*sext*/ L4_sub_memopb_io>;
+ defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, sub,
+ /*zext*/ L4_sub_memopb_io>;
+ defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, sub,
+ /*anyext*/ L4_sub_memoph_io>;
+ defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, sub,
+ /*sext*/ L4_sub_memoph_io>;
+ defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, sub,
+ /*zext*/ L4_sub_memoph_io>;
+ defm: Memopxr_pat<load, store, u6_2ImmPred, sub, L4_sub_memopw_io>;
+
+ // and reg
+ defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, and,
+ /*anyext*/ L4_and_memopb_io>;
+ defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, and,
+ /*sext*/ L4_and_memopb_io>;
+ defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, and,
+ /*zext*/ L4_and_memopb_io>;
+ defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, and,
+ /*anyext*/ L4_and_memoph_io>;
+ defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, and,
+ /*sext*/ L4_and_memoph_io>;
+ defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, and,
+ /*zext*/ L4_and_memoph_io>;
+ defm: Memopxr_pat<load, store, u6_2ImmPred, and, L4_and_memopw_io>;
+
+ // or reg
+ defm: Memopxr_pat<extloadi8, truncstorei8, u6_0ImmPred, or,
+ /*anyext*/ L4_or_memopb_io>;
+ defm: Memopxr_pat<sextloadi8, truncstorei8, u6_0ImmPred, or,
+ /*sext*/ L4_or_memopb_io>;
+ defm: Memopxr_pat<zextloadi8, truncstorei8, u6_0ImmPred, or,
+ /*zext*/ L4_or_memopb_io>;
+ defm: Memopxr_pat<extloadi16, truncstorei16, u6_1ImmPred, or,
+ /*anyext*/ L4_or_memoph_io>;
+ defm: Memopxr_pat<sextloadi16, truncstorei16, u6_1ImmPred, or,
+ /*sext*/ L4_or_memoph_io>;
+ defm: Memopxr_pat<zextloadi16, truncstorei16, u6_1ImmPred, or,
+ /*zext*/ L4_or_memoph_io>;
+ defm: Memopxr_pat<load, store, u6_2ImmPred, or, L4_or_memopw_io>;
+}
+
+
+multiclass Memopxi_simple_pat<PatFrag Load, PatFrag Store, SDNode Oper,
+ PatFrag Arg, SDNodeXForm ArgMod,
+ InstHexagon MI> {
+ // Addr: i32
+ def: Pat<(Store (Oper (Load I32:$Rs), Arg:$A), I32:$Rs),
+ (MI I32:$Rs, 0, (ArgMod Arg:$A))>;
+ // Addr: fi
+ def: Pat<(Store (Oper (Load AddrFI:$Rs), Arg:$A), AddrFI:$Rs),
+ (MI AddrFI:$Rs, 0, (ArgMod Arg:$A))>;
+}
+
+multiclass Memopxi_add_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
+ SDNode Oper, PatFrag Arg, SDNodeXForm ArgMod,
+ InstHexagon MI> {
+ // Addr: i32
+ def: Pat<(Store (Oper (Load (add I32:$Rs, ImmPred:$Off)), Arg:$A),
+ (add I32:$Rs, ImmPred:$Off)),
+ (MI I32:$Rs, imm:$Off, (ArgMod Arg:$A))>;
+ def: Pat<(Store (Oper (Load (IsOrAdd I32:$Rs, ImmPred:$Off)), Arg:$A),
+ (IsOrAdd I32:$Rs, ImmPred:$Off)),
+ (MI I32:$Rs, imm:$Off, (ArgMod Arg:$A))>;
+ // Addr: fi
+ def: Pat<(Store (Oper (Load (add AddrFI:$Rs, ImmPred:$Off)), Arg:$A),
+ (add AddrFI:$Rs, ImmPred:$Off)),
+ (MI AddrFI:$Rs, imm:$Off, (ArgMod Arg:$A))>;
+ def: Pat<(Store (Oper (Load (IsOrAdd AddrFI:$Rs, ImmPred:$Off)), Arg:$A),
+ (IsOrAdd AddrFI:$Rs, ImmPred:$Off)),
+ (MI AddrFI:$Rs, imm:$Off, (ArgMod Arg:$A))>;
+}
+
+multiclass Memopxi_pat<PatFrag Load, PatFrag Store, PatFrag ImmPred,
+ SDNode Oper, PatFrag Arg, SDNodeXForm ArgMod,
+ InstHexagon MI> {
+ defm: Memopxi_simple_pat <Load, Store, Oper, Arg, ArgMod, MI>;
+ defm: Memopxi_add_pat <Load, Store, ImmPred, Oper, Arg, ArgMod, MI>;
+}
+
+
+let AddedComplexity = 200 in {
+ // add imm
+ defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, add, u5_0ImmPred,
+ /*anyext*/ IdImm, L4_iadd_memopb_io>;
+ defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, add, u5_0ImmPred,
+ /*sext*/ IdImm, L4_iadd_memopb_io>;
+ defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, add, u5_0ImmPred,
+ /*zext*/ IdImm, L4_iadd_memopb_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, u5_0ImmPred,
+ /*anyext*/ IdImm, L4_iadd_memoph_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, u5_0ImmPred,
+ /*sext*/ IdImm, L4_iadd_memoph_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, u5_0ImmPred,
+ /*zext*/ IdImm, L4_iadd_memoph_io>;
+ defm: Memopxi_pat<load, store, u6_2ImmPred, add, u5_0ImmPred, IdImm,
+ L4_iadd_memopw_io>;
+ defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, sub, m5_0Imm8Pred,
+ /*anyext*/ NegImm8, L4_iadd_memopb_io>;
+ defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, sub, m5_0Imm8Pred,
+ /*sext*/ NegImm8, L4_iadd_memopb_io>;
+ defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, sub, m5_0Imm8Pred,
+ /*zext*/ NegImm8, L4_iadd_memopb_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, sub, m5_0Imm16Pred,
+ /*anyext*/ NegImm16, L4_iadd_memoph_io>;
+ defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, sub, m5_0Imm16Pred,
+ /*sext*/ NegImm16, L4_iadd_memoph_io>;
+ defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, sub, m5_0Imm16Pred,
+ /*zext*/ NegImm16, L4_iadd_memoph_io>;
+ defm: Memopxi_pat<load, store, u6_2ImmPred, sub, m5_0ImmPred, NegImm32,
+ L4_iadd_memopw_io>;
+
+ // sub imm
+ defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, sub, u5_0ImmPred,
+ /*anyext*/ IdImm, L4_isub_memopb_io>;
+ defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, sub, u5_0ImmPred,
+ /*sext*/ IdImm, L4_isub_memopb_io>;
+ defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, sub, u5_0ImmPred,
+ /*zext*/ IdImm, L4_isub_memopb_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, sub, u5_0ImmPred,
+ /*anyext*/ IdImm, L4_isub_memoph_io>;
+ defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, sub, u5_0ImmPred,
+ /*sext*/ IdImm, L4_isub_memoph_io>;
+ defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, sub, u5_0ImmPred,
+ /*zext*/ IdImm, L4_isub_memoph_io>;
+ defm: Memopxi_pat<load, store, u6_2ImmPred, sub, u5_0ImmPred, IdImm,
+ L4_isub_memopw_io>;
+ defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, add, m5_0Imm8Pred,
+ /*anyext*/ NegImm8, L4_isub_memopb_io>;
+ defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, add, m5_0Imm8Pred,
+ /*sext*/ NegImm8, L4_isub_memopb_io>;
+ defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, add, m5_0Imm8Pred,
+ /*zext*/ NegImm8, L4_isub_memopb_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, add, m5_0Imm16Pred,
+ /*anyext*/ NegImm16, L4_isub_memoph_io>;
+ defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, add, m5_0Imm16Pred,
+ /*sext*/ NegImm16, L4_isub_memoph_io>;
+ defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, add, m5_0Imm16Pred,
+ /*zext*/ NegImm16, L4_isub_memoph_io>;
+ defm: Memopxi_pat<load, store, u6_2ImmPred, add, m5_0ImmPred, NegImm32,
+ L4_isub_memopw_io>;
+
+ // clrbit imm
+ defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, and, IsNPow2_8,
+ /*anyext*/ LogN2_8, L4_iand_memopb_io>;
+ defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, and, IsNPow2_8,
+ /*sext*/ LogN2_8, L4_iand_memopb_io>;
+ defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, and, IsNPow2_8,
+ /*zext*/ LogN2_8, L4_iand_memopb_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, and, IsNPow2_16,
+ /*anyext*/ LogN2_16, L4_iand_memoph_io>;
+ defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, and, IsNPow2_16,
+ /*sext*/ LogN2_16, L4_iand_memoph_io>;
+ defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, and, IsNPow2_16,
+ /*zext*/ LogN2_16, L4_iand_memoph_io>;
+ defm: Memopxi_pat<load, store, u6_2ImmPred, and, IsNPow2_32,
+ LogN2_32, L4_iand_memopw_io>;
+
+ // setbit imm
+ defm: Memopxi_pat<extloadi8, truncstorei8, u6_0ImmPred, or, IsPow2_32,
+ /*anyext*/ Log2_8, L4_ior_memopb_io>;
+ defm: Memopxi_pat<sextloadi8, truncstorei8, u6_0ImmPred, or, IsPow2_32,
+ /*sext*/ Log2_8, L4_ior_memopb_io>;
+ defm: Memopxi_pat<zextloadi8, truncstorei8, u6_0ImmPred, or, IsPow2_32,
+ /*zext*/ Log2_8, L4_ior_memopb_io>;
+ defm: Memopxi_pat<extloadi16, truncstorei16, u6_1ImmPred, or, IsPow2_32,
+ /*anyext*/ Log2_16, L4_ior_memoph_io>;
+ defm: Memopxi_pat<sextloadi16, truncstorei16, u6_1ImmPred, or, IsPow2_32,
+ /*sext*/ Log2_16, L4_ior_memoph_io>;
+ defm: Memopxi_pat<zextloadi16, truncstorei16, u6_1ImmPred, or, IsPow2_32,
+ /*zext*/ Log2_16, L4_ior_memoph_io>;
+ defm: Memopxi_pat<load, store, u6_2ImmPred, or, IsPow2_32,
+ Log2_32, L4_ior_memopw_io>;
+}
+
+def : T_CMP_pat <C4_cmpneqi, setne, s32_0ImmPred>;
+def : T_CMP_pat <C4_cmpltei, setle, s32_0ImmPred>;
+def : T_CMP_pat <C4_cmplteui, setule, u9_0ImmPred>;
+
+// Map cmplt(Rs, Imm) -> !cmpgt(Rs, Imm-1).
+def: Pat<(i1 (setlt I32:$src1, s32_0ImmPred:$src2)),
+ (C4_cmpltei IntRegs:$src1, (SDEC1 s32_0ImmPred:$src2))>;
+
+// rs != rt -> !(rs == rt).
+def: Pat<(i1 (setne I32:$src1, s32_0ImmPred:$src2)),
+ (C4_cmpneqi IntRegs:$src1, s32_0ImmPred:$src2)>;
+
+// For the sequence
+// zext( setult ( and(Rs, 255), u8))
+// Use the isdigit transformation below
+
+
+def u7_0PosImmPred : ImmLeaf<i32, [{
+ // True if the immediate fits in an 7-bit unsigned field and
+ // is strictly greater than 0.
+ return Imm > 0 && isUInt<7>(Imm);
+}]>;
+
+
+// Generate code of the form 'C2_muxii(cmpbgtui(Rdd, C-1),0,1)'
+// for C code of the form r = ((c>='0') & (c<='9')) ? 1 : 0;.
+// The isdigit transformation relies on two 'clever' aspects:
+// 1) The data type is unsigned which allows us to eliminate a zero test after
+// biasing the expression by 48. We are depending on the representation of
+// the unsigned types, and semantics.
+// 2) The front end has converted <= 9 into < 10 on entry to LLVM
+//
+// For the C code:
+// retval = ((c>='0') & (c<='9')) ? 1 : 0;
+// The code is transformed upstream of llvm into
+// retval = (c-48) < 10 ? 1 : 0;
+
+let AddedComplexity = 139 in
+def: Pat<(i32 (zext (i1 (setult (and I32:$src1, 255), u7_0PosImmPred:$src2)))),
+ (C2_muxii (A4_cmpbgtui IntRegs:$src1, (UDEC1 imm:$src2)), 0, 1)>;
+
+class Loada_pat<PatFrag Load, ValueType VT, PatFrag Addr, InstHexagon MI>
+ : Pat<(VT (Load Addr:$addr)), (MI Addr:$addr)>;
+
+class Loadam_pat<PatFrag Load, ValueType VT, PatFrag Addr, PatFrag ValueMod,
+ InstHexagon MI>
+ : Pat<(VT (Load Addr:$addr)), (ValueMod (MI Addr:$addr))>;
+
+class Storea_pat<PatFrag Store, PatFrag Value, PatFrag Addr, InstHexagon MI>
+ : Pat<(Store Value:$val, Addr:$addr), (MI Addr:$addr, Value:$val)>;
+
+class Stoream_pat<PatFrag Store, PatFrag Value, PatFrag Addr, PatFrag ValueMod,
+ InstHexagon MI>
+ : Pat<(Store Value:$val, Addr:$addr),
+ (MI Addr:$addr, (ValueMod Value:$val))>;
+
+let AddedComplexity = 30 in {
+ def: Storea_pat<truncstorei8, I32, addrga, PS_storerbabs>;
+ def: Storea_pat<truncstorei16, I32, addrga, PS_storerhabs>;
+ def: Storea_pat<store, I32, addrga, PS_storeriabs>;
+ def: Storea_pat<store, I64, addrga, PS_storerdabs>;
+
+ def: Stoream_pat<truncstorei8, I64, addrga, LoReg, PS_storerbabs>;
+ def: Stoream_pat<truncstorei16, I64, addrga, LoReg, PS_storerhabs>;
+ def: Stoream_pat<truncstorei32, I64, addrga, LoReg, PS_storeriabs>;
+}
+
+def: Storea_pat<SwapSt<atomic_store_8>, I32, addrgp, S2_storerbgp>;
+def: Storea_pat<SwapSt<atomic_store_16>, I32, addrgp, S2_storerhgp>;
+def: Storea_pat<SwapSt<atomic_store_32>, I32, addrgp, S2_storerigp>;
+def: Storea_pat<SwapSt<atomic_store_64>, I64, addrgp, S2_storerdgp>;
+
+let AddedComplexity = 100 in {
+ def: Storea_pat<truncstorei8, I32, addrgp, S2_storerbgp>;
+ def: Storea_pat<truncstorei16, I32, addrgp, S2_storerhgp>;
+ def: Storea_pat<store, I32, addrgp, S2_storerigp>;
+ def: Storea_pat<store, I64, addrgp, S2_storerdgp>;
+
+ // Map from "i1 = constant<-1>; memw(CONST32(#foo)) = i1"
+ // to "r0 = 1; memw(#foo) = r0"
+ let AddedComplexity = 100 in
+ def: Pat<(store (i1 -1), (HexagonCONST32_GP tglobaladdr:$global)),
+ (S2_storerbgp tglobaladdr:$global, (A2_tfrsi 1))>;
+}
+
+class LoadAbs_pats <PatFrag ldOp, InstHexagon MI, ValueType VT = i32>
+ : Pat <(VT (ldOp (HexagonCONST32 tglobaladdr:$absaddr))),
+ (VT (MI tglobaladdr:$absaddr))>;
+
+let AddedComplexity = 30 in {
+ def: LoadAbs_pats <load, PS_loadriabs>;
+ def: LoadAbs_pats <zextloadi1, PS_loadrubabs>;
+ def: LoadAbs_pats <sextloadi8, PS_loadrbabs>;
+ def: LoadAbs_pats <extloadi8, PS_loadrubabs>;
+ def: LoadAbs_pats <zextloadi8, PS_loadrubabs>;
+ def: LoadAbs_pats <sextloadi16, PS_loadrhabs>;
+ def: LoadAbs_pats <extloadi16, PS_loadruhabs>;
+ def: LoadAbs_pats <zextloadi16, PS_loadruhabs>;
+ def: LoadAbs_pats <load, PS_loadrdabs, i64>;
+}
+
+let AddedComplexity = 30 in
+def: Pat<(i64 (zextloadi1 (HexagonCONST32 tglobaladdr:$absaddr))),
+ (ToZext64 (PS_loadrubabs tglobaladdr:$absaddr))>;
+
+def: Loada_pat<atomic_load_8, i32, addrgp, L2_loadrubgp>;
+def: Loada_pat<atomic_load_16, i32, addrgp, L2_loadruhgp>;
+def: Loada_pat<atomic_load_32, i32, addrgp, L2_loadrigp>;
+def: Loada_pat<atomic_load_64, i64, addrgp, L2_loadrdgp>;
+
+def: Loadam_pat<load, i1, addrga, I32toI1, PS_loadrubabs>;
+def: Loadam_pat<load, i1, addrgp, I32toI1, L2_loadrubgp>;
+
+def: Stoream_pat<store, I1, addrga, I1toI32, PS_storerbabs>;
+def: Stoream_pat<store, I1, addrgp, I1toI32, S2_storerbgp>;
+
+// Map from load(globaladdress) -> mem[u][bhwd](#foo)
+class LoadGP_pats <PatFrag ldOp, InstHexagon MI, ValueType VT = i32>
+ : Pat <(VT (ldOp (HexagonCONST32_GP tglobaladdr:$global))),
+ (VT (MI tglobaladdr:$global))>;
+
+let AddedComplexity = 100 in {
+ def: LoadGP_pats <extloadi8, L2_loadrubgp>;
+ def: LoadGP_pats <sextloadi8, L2_loadrbgp>;
+ def: LoadGP_pats <zextloadi8, L2_loadrubgp>;
+ def: LoadGP_pats <extloadi16, L2_loadruhgp>;
+ def: LoadGP_pats <sextloadi16, L2_loadrhgp>;
+ def: LoadGP_pats <zextloadi16, L2_loadruhgp>;
+ def: LoadGP_pats <load, L2_loadrigp>;
+ def: LoadGP_pats <load, L2_loadrdgp, i64>;
+}
+
+// When the Interprocedural Global Variable optimizer realizes that a certain
+// global variable takes only two constant values, it shrinks the global to
+// a boolean. Catch those loads here in the following 3 patterns.
+let AddedComplexity = 100 in {
+ def: LoadGP_pats <extloadi1, L2_loadrubgp>;
+ def: LoadGP_pats <zextloadi1, L2_loadrubgp>;
+}
+
+// Transfer global address into a register
+def: Pat<(HexagonCONST32 tglobaladdr:$Rs), (A2_tfrsi imm:$Rs)>;
+def: Pat<(HexagonCONST32_GP tblockaddress:$Rs), (A2_tfrsi imm:$Rs)>;
+def: Pat<(HexagonCONST32_GP tglobaladdr:$Rs), (A2_tfrsi imm:$Rs)>;
+
+let AddedComplexity = 30 in {
+ def: Storea_pat<truncstorei8, I32, u32_0ImmPred, PS_storerbabs>;
+ def: Storea_pat<truncstorei16, I32, u32_0ImmPred, PS_storerhabs>;
+ def: Storea_pat<store, I32, u32_0ImmPred, PS_storeriabs>;
+}
+
+let AddedComplexity = 30 in {
+ def: Loada_pat<load, i32, u32_0ImmPred, PS_loadriabs>;
+ def: Loada_pat<sextloadi8, i32, u32_0ImmPred, PS_loadrbabs>;
+ def: Loada_pat<zextloadi8, i32, u32_0ImmPred, PS_loadrubabs>;
+ def: Loada_pat<sextloadi16, i32, u32_0ImmPred, PS_loadrhabs>;
+ def: Loada_pat<zextloadi16, i32, u32_0ImmPred, PS_loadruhabs>;
+}
+
+// Indexed store word - global address.
+// memw(Rs+#u6:2)=#S8
+let AddedComplexity = 100 in
+defm: Storex_add_pat<store, addrga, u6_2ImmPred, S4_storeiri_io>;
+
+// Load from a global address that has only one use in the current basic block.
+let AddedComplexity = 100 in {
+ def: Loada_pat<extloadi8, i32, addrga, PS_loadrubabs>;
+ def: Loada_pat<sextloadi8, i32, addrga, PS_loadrbabs>;
+ def: Loada_pat<zextloadi8, i32, addrga, PS_loadrubabs>;
+
+ def: Loada_pat<extloadi16, i32, addrga, PS_loadruhabs>;
+ def: Loada_pat<sextloadi16, i32, addrga, PS_loadrhabs>;
+ def: Loada_pat<zextloadi16, i32, addrga, PS_loadruhabs>;
+
+ def: Loada_pat<load, i32, addrga, PS_loadriabs>;
+ def: Loada_pat<load, i64, addrga, PS_loadrdabs>;
+}
+
+// Store to a global address that has only one use in the current basic block.
+let AddedComplexity = 100 in {
+ def: Storea_pat<truncstorei8, I32, addrga, PS_storerbabs>;
+ def: Storea_pat<truncstorei16, I32, addrga, PS_storerhabs>;
+ def: Storea_pat<store, I32, addrga, PS_storeriabs>;
+ def: Storea_pat<store, I64, addrga, PS_storerdabs>;
+
+ def: Stoream_pat<truncstorei32, I64, addrga, LoReg, PS_storeriabs>;
+}
+
+// i8/i16/i32 -> i64 loads
+// We need a complexity of 120 here to override preceding handling of
+// zextload.
+let AddedComplexity = 120 in {
+ def: Loadam_pat<extloadi8, i64, addrga, ToZext64, PS_loadrubabs>;
+ def: Loadam_pat<sextloadi8, i64, addrga, ToSext64, PS_loadrbabs>;
+ def: Loadam_pat<zextloadi8, i64, addrga, ToZext64, PS_loadrubabs>;
+
+ def: Loadam_pat<extloadi16, i64, addrga, ToZext64, PS_loadruhabs>;
+ def: Loadam_pat<sextloadi16, i64, addrga, ToSext64, PS_loadrhabs>;
+ def: Loadam_pat<zextloadi16, i64, addrga, ToZext64, PS_loadruhabs>;
+
+ def: Loadam_pat<extloadi32, i64, addrga, ToZext64, PS_loadriabs>;
+ def: Loadam_pat<sextloadi32, i64, addrga, ToSext64, PS_loadriabs>;
+ def: Loadam_pat<zextloadi32, i64, addrga, ToZext64, PS_loadriabs>;
+}
+
+let AddedComplexity = 100 in {
+ def: Loada_pat<extloadi8, i32, addrgp, PS_loadrubabs>;
+ def: Loada_pat<sextloadi8, i32, addrgp, PS_loadrbabs>;
+ def: Loada_pat<zextloadi8, i32, addrgp, PS_loadrubabs>;
+
+ def: Loada_pat<extloadi16, i32, addrgp, PS_loadruhabs>;
+ def: Loada_pat<sextloadi16, i32, addrgp, PS_loadrhabs>;
+ def: Loada_pat<zextloadi16, i32, addrgp, PS_loadruhabs>;
+
+ def: Loada_pat<load, i32, addrgp, PS_loadriabs>;
+ def: Loada_pat<load, i64, addrgp, PS_loadrdabs>;
+}
+
+let AddedComplexity = 100 in {
+ def: Storea_pat<truncstorei8, I32, addrgp, PS_storerbabs>;
+ def: Storea_pat<truncstorei16, I32, addrgp, PS_storerhabs>;
+ def: Storea_pat<store, I32, addrgp, PS_storeriabs>;
+ def: Storea_pat<store, I64, addrgp, PS_storerdabs>;
+}
+
+def: Loada_pat<atomic_load_8, i32, addrgp, PS_loadrubabs>;
+def: Loada_pat<atomic_load_16, i32, addrgp, PS_loadruhabs>;
+def: Loada_pat<atomic_load_32, i32, addrgp, PS_loadriabs>;
+def: Loada_pat<atomic_load_64, i64, addrgp, PS_loadrdabs>;
+
+def: Storea_pat<SwapSt<atomic_store_8>, I32, addrgp, PS_storerbabs>;
+def: Storea_pat<SwapSt<atomic_store_16>, I32, addrgp, PS_storerhabs>;
+def: Storea_pat<SwapSt<atomic_store_32>, I32, addrgp, PS_storeriabs>;
+def: Storea_pat<SwapSt<atomic_store_64>, I64, addrgp, PS_storerdabs>;
+
+def: Pat<(or (or (or (shl (i64 (zext (and I32:$b, (i32 65535)))), (i32 16)),
+ (i64 (zext (i32 (and I32:$a, (i32 65535)))))),
+ (shl (i64 (anyext (and I32:$c, (i32 65535)))), (i32 32))),
+ (shl (Aext64 I32:$d), (i32 48))),
+ (A2_combinew (A2_combine_ll I32:$d, I32:$c),
+ (A2_combine_ll I32:$b, I32:$a))>;
+
+// We need custom lowering of ISD::PREFETCH into HexagonISD::DCFETCH
+// because the SDNode ISD::PREFETCH has properties MayLoad and MayStore.
+// We don't really want either one here.
+def SDTHexagonDCFETCH : SDTypeProfile<0, 2, [SDTCisPtrTy<0>,SDTCisInt<1>]>;
+def HexagonDCFETCH : SDNode<"HexagonISD::DCFETCH", SDTHexagonDCFETCH,
+ [SDNPHasChain]>;
+
+def: Pat<(HexagonDCFETCH IntRegs:$Rs, u11_3ImmPred:$u11_3),
+ (Y2_dcfetchbo IntRegs:$Rs, imm:$u11_3)>;
+def: Pat<(HexagonDCFETCH (i32 (add IntRegs:$Rs, u11_3ImmPred:$u11_3)), (i32 0)),
+ (Y2_dcfetchbo IntRegs:$Rs, imm:$u11_3)>;
+
+def f32ImmPred : PatLeaf<(f32 fpimm:$F)>;
+def f64ImmPred : PatLeaf<(f64 fpimm:$F)>;
+
+def ftoi : SDNodeXForm<fpimm, [{
+ APInt I = N->getValueAPF().bitcastToAPInt();
+ return CurDAG->getTargetConstant(I.getZExtValue(), SDLoc(N),
+ MVT::getIntegerVT(I.getBitWidth()));
+}]>;
+
+
+def: Pat<(sra (i64 (add (sra I64:$src1, u6_0ImmPred:$src2), 1)), (i32 1)),
+ (S2_asr_i_p_rnd I64:$src1, imm:$src2)>;
+
+def SDTHexagonI32I64: SDTypeProfile<1, 1, [SDTCisVT<0, i32>,
+ SDTCisVT<1, i64>]>;
+def HexagonPOPCOUNT: SDNode<"HexagonISD::POPCOUNT", SDTHexagonI32I64>;
+
+def: Pat<(HexagonPOPCOUNT I64:$Rss), (S5_popcountp I64:$Rss)>;
+
+let AddedComplexity = 20 in {
+ defm: Loadx_pat<load, f32, s30_2ImmPred, L2_loadri_io>;
+ defm: Loadx_pat<load, f64, s29_3ImmPred, L2_loadrd_io>;
+}
+
+let AddedComplexity = 60 in {
+ defm : T_LoadAbsReg_Pat <load, L4_loadri_ur, f32>;
+ defm : T_LoadAbsReg_Pat <load, L4_loadrd_ur, f64>;
+}
+
+let AddedComplexity = 40 in {
+ def: Loadxs_pat<load, f32, L4_loadri_rr>;
+ def: Loadxs_pat<load, f64, L4_loadrd_rr>;
+}
+
+let AddedComplexity = 20 in {
+ def: Loadxs_simple_pat<load, f32, L4_loadri_rr>;
+ def: Loadxs_simple_pat<load, f64, L4_loadrd_rr>;
+}
+
+let AddedComplexity = 80 in {
+ def: Loada_pat<load, f32, u32_0ImmPred, PS_loadriabs>;
+ def: Loada_pat<load, f32, addrga, PS_loadriabs>;
+ def: Loada_pat<load, f64, addrga, PS_loadrdabs>;
+}
+
+let AddedComplexity = 100 in {
+ def: LoadGP_pats <load, L2_loadrigp, f32>;
+ def: LoadGP_pats <load, L2_loadrdgp, f64>;
+}
+
+let AddedComplexity = 20 in {
+ defm: Storex_pat<store, F32, s30_2ImmPred, S2_storeri_io>;
+ defm: Storex_pat<store, F64, s29_3ImmPred, S2_storerd_io>;
+}
+
+// Simple patterns should be tried with the least priority.
+def: Storex_simple_pat<store, F32, S2_storeri_io>;
+def: Storex_simple_pat<store, F64, S2_storerd_io>;
+
+let AddedComplexity = 60 in {
+ defm : T_StoreAbsReg_Pats <S4_storeri_ur, IntRegs, f32, store>;
+ defm : T_StoreAbsReg_Pats <S4_storerd_ur, DoubleRegs, f64, store>;
+}
+
+let AddedComplexity = 40 in {
+ def: Storexs_pat<store, F32, S4_storeri_rr>;
+ def: Storexs_pat<store, F64, S4_storerd_rr>;
+}
+
+let AddedComplexity = 20 in {
+ def: Store_rr_pat<store, F32, S4_storeri_rr>;
+ def: Store_rr_pat<store, F64, S4_storerd_rr>;
+}
+
+let AddedComplexity = 80 in {
+ def: Storea_pat<store, F32, addrga, PS_storeriabs>;
+ def: Storea_pat<store, F64, addrga, PS_storerdabs>;
+}
+
+let AddedComplexity = 100 in {
+ def: Storea_pat<store, F32, addrgp, S2_storerigp>;
+ def: Storea_pat<store, F64, addrgp, S2_storerdgp>;
+}
+
+defm: Storex_pat<store, F32, s30_2ImmPred, S2_storeri_io>;
+defm: Storex_pat<store, F64, s29_3ImmPred, S2_storerd_io>;
+def: Storex_simple_pat<store, F32, S2_storeri_io>;
+def: Storex_simple_pat<store, F64, S2_storerd_io>;
+
+def: Pat<(fadd F32:$src1, F32:$src2),
+ (F2_sfadd F32:$src1, F32:$src2)>;
+
+def: Pat<(fsub F32:$src1, F32:$src2),
+ (F2_sfsub F32:$src1, F32:$src2)>;
+
+def: Pat<(fmul F32:$src1, F32:$src2),
+ (F2_sfmpy F32:$src1, F32:$src2)>;
+
+let Predicates = [HasV5T] in {
+ def: Pat<(f32 (fminnum F32:$Rs, F32:$Rt)), (F2_sfmin F32:$Rs, F32:$Rt)>;
+ def: Pat<(f32 (fmaxnum F32:$Rs, F32:$Rt)), (F2_sfmax F32:$Rs, F32:$Rt)>;
+}
+
+let AddedComplexity = 100, Predicates = [HasV5T] in {
+ class SfSel12<PatFrag Cmp, InstHexagon MI>
+ : Pat<(select (i1 (Cmp F32:$Rs, F32:$Rt)), F32:$Rs, F32:$Rt),
+ (MI F32:$Rs, F32:$Rt)>;
+ class SfSel21<PatFrag Cmp, InstHexagon MI>
+ : Pat<(select (i1 (Cmp F32:$Rs, F32:$Rt)), F32:$Rt, F32:$Rs),
+ (MI F32:$Rs, F32:$Rt)>;
+
+ def: SfSel12<setolt, F2_sfmin>;
+ def: SfSel12<setole, F2_sfmin>;
+ def: SfSel12<setogt, F2_sfmax>;
+ def: SfSel12<setoge, F2_sfmax>;
+ def: SfSel21<setolt, F2_sfmax>;
+ def: SfSel21<setole, F2_sfmax>;
+ def: SfSel21<setogt, F2_sfmin>;
+ def: SfSel21<setoge, F2_sfmin>;
+}
+
+class T_fcmp32_pat<PatFrag OpNode, InstHexagon MI>
+ : Pat<(i1 (OpNode F32:$src1, F32:$src2)),
+ (MI F32:$src1, F32:$src2)>;
+class T_fcmp64_pat<PatFrag OpNode, InstHexagon MI>
+ : Pat<(i1 (OpNode F64:$src1, F64:$src2)),
+ (MI F64:$src1, F64:$src2)>;
+
+def: T_fcmp32_pat<setoge, F2_sfcmpge>;
+def: T_fcmp32_pat<setuo, F2_sfcmpuo>;
+def: T_fcmp32_pat<setoeq, F2_sfcmpeq>;
+def: T_fcmp32_pat<setogt, F2_sfcmpgt>;
+
+def: T_fcmp64_pat<setoge, F2_dfcmpge>;
+def: T_fcmp64_pat<setuo, F2_dfcmpuo>;
+def: T_fcmp64_pat<setoeq, F2_dfcmpeq>;
+def: T_fcmp64_pat<setogt, F2_dfcmpgt>;
+
+let Predicates = [HasV5T] in
+multiclass T_fcmp_pats<PatFrag cmpOp, InstHexagon IntMI, InstHexagon DoubleMI> {
+ // IntRegs
+ def: Pat<(i1 (cmpOp F32:$src1, F32:$src2)),
+ (IntMI F32:$src1, F32:$src2)>;
+ // DoubleRegs
+ def: Pat<(i1 (cmpOp F64:$src1, F64:$src2)),
+ (DoubleMI F64:$src1, F64:$src2)>;
+}
+
+defm : T_fcmp_pats <seteq, F2_sfcmpeq, F2_dfcmpeq>;
+defm : T_fcmp_pats <setgt, F2_sfcmpgt, F2_dfcmpgt>;
+defm : T_fcmp_pats <setge, F2_sfcmpge, F2_dfcmpge>;
+
+//===----------------------------------------------------------------------===//
+// Multiclass to define 'Def Pats' for unordered gt, ge, eq operations.
+//===----------------------------------------------------------------------===//
+let Predicates = [HasV5T] in
+multiclass unord_Pats <PatFrag cmpOp, InstHexagon IntMI, InstHexagon DoubleMI> {
+ // IntRegs
+ def: Pat<(i1 (cmpOp F32:$src1, F32:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
+ (IntMI F32:$src1, F32:$src2))>;
+
+ // DoubleRegs
+ def: Pat<(i1 (cmpOp F64:$src1, F64:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
+ (DoubleMI F64:$src1, F64:$src2))>;
+}
+
+defm : unord_Pats <setuge, F2_sfcmpge, F2_dfcmpge>;
+defm : unord_Pats <setugt, F2_sfcmpgt, F2_dfcmpgt>;
+defm : unord_Pats <setueq, F2_sfcmpeq, F2_dfcmpeq>;
+
+//===----------------------------------------------------------------------===//
+// Multiclass to define 'Def Pats' for the following dags:
+// seteq(setoeq(op1, op2), 0) -> not(setoeq(op1, op2))
+// seteq(setoeq(op1, op2), 1) -> setoeq(op1, op2)
+// setne(setoeq(op1, op2), 0) -> setoeq(op1, op2)
+// setne(setoeq(op1, op2), 1) -> not(setoeq(op1, op2))
+//===----------------------------------------------------------------------===//
+let Predicates = [HasV5T] in
+multiclass eq_ordgePats <PatFrag cmpOp, InstHexagon IntMI,
+ InstHexagon DoubleMI> {
+ // IntRegs
+ def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
+ (C2_not (IntMI F32:$src1, F32:$src2))>;
+ def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
+ (IntMI F32:$src1, F32:$src2)>;
+ def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
+ (IntMI F32:$src1, F32:$src2)>;
+ def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
+ (C2_not (IntMI F32:$src1, F32:$src2))>;
+
+ // DoubleRegs
+ def : Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
+ (C2_not (DoubleMI F64:$src1, F64:$src2))>;
+ def : Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 1)),
+ (DoubleMI F64:$src1, F64:$src2)>;
+ def : Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
+ (DoubleMI F64:$src1, F64:$src2)>;
+ def : Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 1)),
+ (C2_not (DoubleMI F64:$src1, F64:$src2))>;
+}
+
+defm : eq_ordgePats<setoeq, F2_sfcmpeq, F2_dfcmpeq>;
+defm : eq_ordgePats<setoge, F2_sfcmpge, F2_dfcmpge>;
+defm : eq_ordgePats<setogt, F2_sfcmpgt, F2_dfcmpgt>;
+
+//===----------------------------------------------------------------------===//
+// Multiclass to define 'Def Pats' for the following dags:
+// seteq(setolt(op1, op2), 0) -> not(setogt(op2, op1))
+// seteq(setolt(op1, op2), 1) -> setogt(op2, op1)
+// setne(setolt(op1, op2), 0) -> setogt(op2, op1)
+// setne(setolt(op1, op2), 1) -> not(setogt(op2, op1))
+//===----------------------------------------------------------------------===//
+let Predicates = [HasV5T] in
+multiclass eq_ordltPats <PatFrag cmpOp, InstHexagon IntMI,
+ InstHexagon DoubleMI> {
+ // IntRegs
+ def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
+ (C2_not (IntMI F32:$src2, F32:$src1))>;
+ def: Pat<(i1 (seteq (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
+ (IntMI F32:$src2, F32:$src1)>;
+ def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 0)),
+ (IntMI F32:$src2, F32:$src1)>;
+ def: Pat<(i1 (setne (i1 (cmpOp F32:$src1, F32:$src2)), 1)),
+ (C2_not (IntMI F32:$src2, F32:$src1))>;
+
+ // DoubleRegs
+ def: Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
+ (C2_not (DoubleMI F64:$src2, F64:$src1))>;
+ def: Pat<(i1 (seteq (i1 (cmpOp F64:$src1, F64:$src2)), 1)),
+ (DoubleMI F64:$src2, F64:$src1)>;
+ def: Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
+ (DoubleMI F64:$src2, F64:$src1)>;
+ def: Pat<(i1 (setne (i1 (cmpOp F64:$src1, F64:$src2)), 0)),
+ (C2_not (DoubleMI F64:$src2, F64:$src1))>;
+}
+
+defm : eq_ordltPats<setole, F2_sfcmpge, F2_dfcmpge>;
+defm : eq_ordltPats<setolt, F2_sfcmpgt, F2_dfcmpgt>;
+
+
+// o. seto inverse of setuo. http://llvm.org/docs/LangRef.html#i_fcmp
+let Predicates = [HasV5T] in {
+ def: Pat<(i1 (seto F32:$src1, F32:$src2)),
+ (C2_not (F2_sfcmpuo F32:$src2, F32:$src1))>;
+ def: Pat<(i1 (seto F32:$src1, f32ImmPred:$src2)),
+ (C2_not (F2_sfcmpuo (f32 (A2_tfrsi (ftoi $src2))), F32:$src1))>;
+ def: Pat<(i1 (seto F64:$src1, F64:$src2)),
+ (C2_not (F2_dfcmpuo F64:$src2, F64:$src1))>;
+ def: Pat<(i1 (seto F64:$src1, f64ImmPred:$src2)),
+ (C2_not (F2_dfcmpuo (CONST64 (ftoi $src2)), F64:$src1))>;
+}
+
+// Ordered lt.
+let Predicates = [HasV5T] in {
+ def: Pat<(i1 (setolt F32:$src1, F32:$src2)),
+ (F2_sfcmpgt F32:$src2, F32:$src1)>;
+ def: Pat<(i1 (setolt F32:$src1, f32ImmPred:$src2)),
+ (F2_sfcmpgt (f32 (A2_tfrsi (ftoi $src2))), F32:$src1)>;
+ def: Pat<(i1 (setolt F64:$src1, F64:$src2)),
+ (F2_dfcmpgt F64:$src2, F64:$src1)>;
+ def: Pat<(i1 (setolt F64:$src1, f64ImmPred:$src2)),
+ (F2_dfcmpgt (CONST64 (ftoi $src2)), F64:$src1)>;
+}
+
+// Unordered lt.
+let Predicates = [HasV5T] in {
+ def: Pat<(i1 (setult F32:$src1, F32:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
+ (F2_sfcmpgt F32:$src2, F32:$src1))>;
+ def: Pat<(i1 (setult F32:$src1, f32ImmPred:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, (f32 (A2_tfrsi (ftoi $src2)))),
+ (F2_sfcmpgt (f32 (A2_tfrsi (ftoi $src2))), F32:$src1))>;
+ def: Pat<(i1 (setult F64:$src1, F64:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
+ (F2_dfcmpgt F64:$src2, F64:$src1))>;
+ def: Pat<(i1 (setult F64:$src1, f64ImmPred:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, (CONST64 (ftoi $src2))),
+ (F2_dfcmpgt (CONST64 (ftoi $src2)), F64:$src1))>;
+}
+
+// Ordered le.
+let Predicates = [HasV5T] in {
+ // rs <= rt -> rt >= rs.
+ def: Pat<(i1 (setole F32:$src1, F32:$src2)),
+ (F2_sfcmpge F32:$src2, F32:$src1)>;
+ def: Pat<(i1 (setole F32:$src1, f32ImmPred:$src2)),
+ (F2_sfcmpge (f32 (A2_tfrsi (ftoi $src2))), F32:$src1)>;
+
+ // Rss <= Rtt -> Rtt >= Rss.
+ def: Pat<(i1 (setole F64:$src1, F64:$src2)),
+ (F2_dfcmpge F64:$src2, F64:$src1)>;
+ def: Pat<(i1 (setole F64:$src1, f64ImmPred:$src2)),
+ (F2_dfcmpge (CONST64 (ftoi $src2)), F64:$src1)>;
+}
+
+// Unordered le.
+let Predicates = [HasV5T] in {
+// rs <= rt -> rt >= rs.
+ def: Pat<(i1 (setule F32:$src1, F32:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
+ (F2_sfcmpge F32:$src2, F32:$src1))>;
+ def: Pat<(i1 (setule F32:$src1, f32ImmPred:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, (f32 (A2_tfrsi (ftoi $src2)))),
+ (F2_sfcmpge (f32 (A2_tfrsi (ftoi $src2))), F32:$src1))>;
+ def: Pat<(i1 (setule F64:$src1, F64:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
+ (F2_dfcmpge F64:$src2, F64:$src1))>;
+ def: Pat<(i1 (setule F64:$src1, f64ImmPred:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, (CONST64 (ftoi $src2))),
+ (F2_dfcmpge (CONST64 (ftoi $src2)), F64:$src1))>;
+}
+
+// Ordered ne.
+let Predicates = [HasV5T] in {
+ def: Pat<(i1 (setone F32:$src1, F32:$src2)),
+ (C2_not (F2_sfcmpeq F32:$src1, F32:$src2))>;
+ def: Pat<(i1 (setone F64:$src1, F64:$src2)),
+ (C2_not (F2_dfcmpeq F64:$src1, F64:$src2))>;
+ def: Pat<(i1 (setone F32:$src1, f32ImmPred:$src2)),
+ (C2_not (F2_sfcmpeq F32:$src1, (f32 (A2_tfrsi (ftoi $src2)))))>;
+ def: Pat<(i1 (setone F64:$src1, f64ImmPred:$src2)),
+ (C2_not (F2_dfcmpeq F64:$src1, (CONST64 (ftoi $src2))))>;
+}
+
+// Unordered ne.
+let Predicates = [HasV5T] in {
+ def: Pat<(i1 (setune F32:$src1, F32:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, F32:$src2),
+ (C2_not (F2_sfcmpeq F32:$src1, F32:$src2)))>;
+ def: Pat<(i1 (setune F64:$src1, F64:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, F64:$src2),
+ (C2_not (F2_dfcmpeq F64:$src1, F64:$src2)))>;
+ def: Pat<(i1 (setune F32:$src1, f32ImmPred:$src2)),
+ (C2_or (F2_sfcmpuo F32:$src1, (f32 (A2_tfrsi (ftoi $src2)))),
+ (C2_not (F2_sfcmpeq F32:$src1,
+ (f32 (A2_tfrsi (ftoi $src2))))))>;
+ def: Pat<(i1 (setune F64:$src1, f64ImmPred:$src2)),
+ (C2_or (F2_dfcmpuo F64:$src1, (CONST64 (ftoi $src2))),
+ (C2_not (F2_dfcmpeq F64:$src1,
+ (CONST64 (ftoi $src2)))))>;
+}
+
+// Besides set[o|u][comparions], we also need set[comparisons].
+let Predicates = [HasV5T] in {
+ // lt.
+ def: Pat<(i1 (setlt F32:$src1, F32:$src2)),
+ (F2_sfcmpgt F32:$src2, F32:$src1)>;
+ def: Pat<(i1 (setlt F32:$src1, f32ImmPred:$src2)),
+ (F2_sfcmpgt (f32 (A2_tfrsi (ftoi $src2))), F32:$src1)>;
+ def: Pat<(i1 (setlt F64:$src1, F64:$src2)),
+ (F2_dfcmpgt F64:$src2, F64:$src1)>;
+ def: Pat<(i1 (setlt F64:$src1, f64ImmPred:$src2)),
+ (F2_dfcmpgt (CONST64 (ftoi $src2)), F64:$src1)>;
+
+ // le.
+ // rs <= rt -> rt >= rs.
+ def: Pat<(i1 (setle F32:$src1, F32:$src2)),
+ (F2_sfcmpge F32:$src2, F32:$src1)>;
+ def: Pat<(i1 (setle F32:$src1, f32ImmPred:$src2)),
+ (F2_sfcmpge (f32 (A2_tfrsi (ftoi $src2))), F32:$src1)>;
+
+ // Rss <= Rtt -> Rtt >= Rss.
+ def: Pat<(i1 (setle F64:$src1, F64:$src2)),
+ (F2_dfcmpge F64:$src2, F64:$src1)>;
+ def: Pat<(i1 (setle F64:$src1, f64ImmPred:$src2)),
+ (F2_dfcmpge (CONST64 (ftoi $src2)), F64:$src1)>;
+
+ // ne.
+ def: Pat<(i1 (setne F32:$src1, F32:$src2)),
+ (C2_not (F2_sfcmpeq F32:$src1, F32:$src2))>;
+ def: Pat<(i1 (setne F64:$src1, F64:$src2)),
+ (C2_not (F2_dfcmpeq F64:$src1, F64:$src2))>;
+ def: Pat<(i1 (setne F32:$src1, f32ImmPred:$src2)),
+ (C2_not (F2_sfcmpeq F32:$src1, (f32 (A2_tfrsi (ftoi $src2)))))>;
+ def: Pat<(i1 (setne F64:$src1, f64ImmPred:$src2)),
+ (C2_not (F2_dfcmpeq F64:$src1, (CONST64 (ftoi $src2))))>;
+}
+
+
+def: Pat<(f64 (fpextend F32:$Rs)), (F2_conv_sf2df F32:$Rs)>;
+def: Pat<(f32 (fpround F64:$Rs)), (F2_conv_df2sf F64:$Rs)>;
+
+def: Pat<(f32 (sint_to_fp I32:$Rs)), (F2_conv_w2sf I32:$Rs)>;
+def: Pat<(f32 (sint_to_fp I64:$Rs)), (F2_conv_d2sf I64:$Rs)>;
+def: Pat<(f64 (sint_to_fp I32:$Rs)), (F2_conv_w2df I32:$Rs)>;
+def: Pat<(f64 (sint_to_fp I64:$Rs)), (F2_conv_d2df I64:$Rs)>;
+
+def: Pat<(f32 (uint_to_fp I32:$Rs)), (F2_conv_uw2sf I32:$Rs)>;
+def: Pat<(f32 (uint_to_fp I64:$Rs)), (F2_conv_ud2sf I64:$Rs)>;
+def: Pat<(f64 (uint_to_fp I32:$Rs)), (F2_conv_uw2df I32:$Rs)>;
+def: Pat<(f64 (uint_to_fp I64:$Rs)), (F2_conv_ud2df I64:$Rs)>;
+
+def: Pat<(i32 (fp_to_sint F32:$Rs)), (F2_conv_sf2w_chop F32:$Rs)>;
+def: Pat<(i32 (fp_to_sint F64:$Rs)), (F2_conv_df2w_chop F64:$Rs)>;
+def: Pat<(i64 (fp_to_sint F32:$Rs)), (F2_conv_sf2d_chop F32:$Rs)>;
+def: Pat<(i64 (fp_to_sint F64:$Rs)), (F2_conv_df2d_chop F64:$Rs)>;
+
+def: Pat<(i32 (fp_to_uint F32:$Rs)), (F2_conv_sf2uw_chop F32:$Rs)>;
+def: Pat<(i32 (fp_to_uint F64:$Rs)), (F2_conv_df2uw_chop F64:$Rs)>;
+def: Pat<(i64 (fp_to_uint F32:$Rs)), (F2_conv_sf2ud_chop F32:$Rs)>;
+def: Pat<(i64 (fp_to_uint F64:$Rs)), (F2_conv_df2ud_chop F64:$Rs)>;
+
+// Bitcast is different than [fp|sint|uint]_to_[sint|uint|fp].
+let Predicates = [HasV5T] in {
+ def: Pat <(i32 (bitconvert F32:$src)), (I32:$src)>;
+ def: Pat <(f32 (bitconvert I32:$src)), (F32:$src)>;
+ def: Pat <(i64 (bitconvert F64:$src)), (I64:$src)>;
+ def: Pat <(f64 (bitconvert I64:$src)), (F64:$src)>;
+}
+
+def : Pat <(fma F32:$src2, F32:$src3, F32:$src1),
+ (F2_sffma F32:$src1, F32:$src2, F32:$src3)>;
+
+def : Pat <(fma (fneg F32:$src2), F32:$src3, F32:$src1),
+ (F2_sffms F32:$src1, F32:$src2, F32:$src3)>;
+
+def : Pat <(fma F32:$src2, (fneg F32:$src3), F32:$src1),
+ (F2_sffms F32:$src1, F32:$src2, F32:$src3)>;
+
+def: Pat<(select I1:$Pu, F32:$Rs, f32ImmPred:$imm),
+ (C2_muxir I1:$Pu, F32:$Rs, (ftoi $imm))>,
+ Requires<[HasV5T]>;
+
+def: Pat<(select I1:$Pu, f32ImmPred:$imm, F32:$Rt),
+ (C2_muxri I1:$Pu, (ftoi $imm), F32:$Rt)>,
+ Requires<[HasV5T]>;
+
+def: Pat<(select I1:$src1, F32:$src2, F32:$src3),
+ (C2_mux I1:$src1, F32:$src2, F32:$src3)>,
+ Requires<[HasV5T]>;
+
+def: Pat<(select (i1 (setult F32:$src1, F32:$src2)), F32:$src3, F32:$src4),
+ (C2_mux (F2_sfcmpgt F32:$src2, F32:$src1), F32:$src4, F32:$src3)>,
+ Requires<[HasV5T]>;
+
+def: Pat<(select I1:$src1, F64:$src2, F64:$src3),
+ (C2_vmux I1:$src1, F64:$src2, F64:$src3)>,
+ Requires<[HasV5T]>;
+
+def: Pat<(select (i1 (setult F64:$src1, F64:$src2)), F64:$src3, F64:$src4),
+ (C2_vmux (F2_dfcmpgt F64:$src2, F64:$src1), F64:$src3, F64:$src4)>,
+ Requires<[HasV5T]>;
+
+// Map from p0 = pnot(p0); r0 = select(p0, #i, r1)
+// => r0 = mux(p0, #i, r1)
+def: Pat<(select (not I1:$src1), f32ImmPred:$src2, F32:$src3),
+ (C2_muxir I1:$src1, F32:$src3, (ftoi $src2))>,
+ Requires<[HasV5T]>;
+
+// Map from p0 = pnot(p0); r0 = mux(p0, r1, #i)
+// => r0 = mux(p0, r1, #i)
+def: Pat<(select (not I1:$src1), F32:$src2, f32ImmPred:$src3),
+ (C2_muxri I1:$src1, (ftoi $src3), F32:$src2)>,
+ Requires<[HasV5T]>;
+
+def: Pat<(i32 (fp_to_sint F64:$src1)),
+ (LoReg (F2_conv_df2d_chop F64:$src1))>,
+ Requires<[HasV5T]>;
+
+def : Pat <(fabs F32:$src1),
+ (S2_clrbit_i F32:$src1, 31)>,
+ Requires<[HasV5T]>;
+
+def : Pat <(fneg F32:$src1),
+ (S2_togglebit_i F32:$src1, 31)>,
+ Requires<[HasV5T]>;
+
+def: Pat<(fabs F64:$Rs),
+ (REG_SEQUENCE DoubleRegs,
+ (S2_clrbit_i (HiReg $Rs), 31), isub_hi,
+ (i32 (LoReg $Rs)), isub_lo)>;
+
+def: Pat<(fneg F64:$Rs),
+ (REG_SEQUENCE DoubleRegs,
+ (S2_togglebit_i (HiReg $Rs), 31), isub_hi,
+ (i32 (LoReg $Rs)), isub_lo)>;
+
+def alignedload : PatFrag<(ops node:$addr), (load $addr), [{
+ return isAlignedMemNode(dyn_cast<MemSDNode>(N));
+}]>;
+
+def unalignedload : PatFrag<(ops node:$addr), (load $addr), [{
+ return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
+}]>;
+
+def alignedstore : PatFrag<(ops node:$val, node:$addr), (store $val, $addr), [{
+ return isAlignedMemNode(dyn_cast<MemSDNode>(N));
+}]>;
+
+def unalignedstore : PatFrag<(ops node:$val, node:$addr), (store $val, $addr), [{
+ return !isAlignedMemNode(dyn_cast<MemSDNode>(N));
+}]>;
+
+
+def s4_6ImmPred: PatLeaf<(i32 imm), [{
+ int64_t V = N->getSExtValue();
+ return isShiftedInt<4,6>(V);
+}]>;
+
+def s4_7ImmPred: PatLeaf<(i32 imm), [{
+ int64_t V = N->getSExtValue();
+ return isShiftedInt<4,7>(V);
+}]>;
+
+
+multiclass vS32b_ai_pats <ValueType VTSgl, ValueType VTDbl> {
+ // Aligned stores
+ def : Pat<(alignedstore (VTSgl VectorRegs:$src1), IntRegs:$addr),
+ (V6_vS32b_ai IntRegs:$addr, 0, (VTSgl VectorRegs:$src1))>,
+ Requires<[UseHVXSgl]>;
+ def : Pat<(unalignedstore (VTSgl VectorRegs:$src1), IntRegs:$addr),
+ (V6_vS32Ub_ai IntRegs:$addr, 0, (VTSgl VectorRegs:$src1))>,
+ Requires<[UseHVXSgl]>;
+
+ // 128B Aligned stores
+ def : Pat<(alignedstore (VTDbl VectorRegs128B:$src1), IntRegs:$addr),
+ (V6_vS32b_ai_128B IntRegs:$addr, 0, (VTDbl VectorRegs128B:$src1))>,
+ Requires<[UseHVXDbl]>;
+ def : Pat<(unalignedstore (VTDbl VectorRegs128B:$src1), IntRegs:$addr),
+ (V6_vS32Ub_ai_128B IntRegs:$addr, 0, (VTDbl VectorRegs128B:$src1))>,
+ Requires<[UseHVXDbl]>;
+
+ // Fold Add R+OFF into vector store.
+ let AddedComplexity = 10 in {
+ def : Pat<(alignedstore (VTSgl VectorRegs:$src1),
+ (add IntRegs:$src2, s4_6ImmPred:$offset)),
+ (V6_vS32b_ai IntRegs:$src2, s4_6ImmPred:$offset,
+ (VTSgl VectorRegs:$src1))>,
+ Requires<[UseHVXSgl]>;
+ def : Pat<(unalignedstore (VTSgl VectorRegs:$src1),
+ (add IntRegs:$src2, s4_6ImmPred:$offset)),
+ (V6_vS32Ub_ai IntRegs:$src2, s4_6ImmPred:$offset,
+ (VTSgl VectorRegs:$src1))>,
+ Requires<[UseHVXSgl]>;
+
+ // Fold Add R+OFF into vector store 128B.
+ def : Pat<(alignedstore (VTDbl VectorRegs128B:$src1),
+ (add IntRegs:$src2, s4_7ImmPred:$offset)),
+ (V6_vS32b_ai_128B IntRegs:$src2, s4_7ImmPred:$offset,
+ (VTDbl VectorRegs128B:$src1))>,
+ Requires<[UseHVXDbl]>;
+ def : Pat<(unalignedstore (VTDbl VectorRegs128B:$src1),
+ (add IntRegs:$src2, s4_7ImmPred:$offset)),
+ (V6_vS32Ub_ai_128B IntRegs:$src2, s4_7ImmPred:$offset,
+ (VTDbl VectorRegs128B:$src1))>,
+ Requires<[UseHVXDbl]>;
+ }
+}
+
+defm : vS32b_ai_pats <v64i8, v128i8>;
+defm : vS32b_ai_pats <v32i16, v64i16>;
+defm : vS32b_ai_pats <v16i32, v32i32>;
+defm : vS32b_ai_pats <v8i64, v16i64>;
+
+
+multiclass vL32b_ai_pats <ValueType VTSgl, ValueType VTDbl> {
+ // Aligned loads
+ def : Pat < (VTSgl (alignedload IntRegs:$addr)),
+ (V6_vL32b_ai IntRegs:$addr, 0) >,
+ Requires<[UseHVXSgl]>;
+ def : Pat < (VTSgl (unalignedload IntRegs:$addr)),
+ (V6_vL32Ub_ai IntRegs:$addr, 0) >,
+ Requires<[UseHVXSgl]>;
+
+ // 128B Load
+ def : Pat < (VTDbl (alignedload IntRegs:$addr)),
+ (V6_vL32b_ai_128B IntRegs:$addr, 0) >,
+ Requires<[UseHVXDbl]>;
+ def : Pat < (VTDbl (unalignedload IntRegs:$addr)),
+ (V6_vL32Ub_ai_128B IntRegs:$addr, 0) >,
+ Requires<[UseHVXDbl]>;
+
+ // Fold Add R+OFF into vector load.
+ let AddedComplexity = 10 in {
+ def : Pat<(VTDbl (alignedload (add IntRegs:$src2, s4_7ImmPred:$offset))),
+ (V6_vL32b_ai_128B IntRegs:$src2, s4_7ImmPred:$offset)>,
+ Requires<[UseHVXDbl]>;
+ def : Pat<(VTDbl (unalignedload (add IntRegs:$src2, s4_7ImmPred:$offset))),
+ (V6_vL32Ub_ai_128B IntRegs:$src2, s4_7ImmPred:$offset)>,
+ Requires<[UseHVXDbl]>;
+
+ def : Pat<(VTSgl (alignedload (add IntRegs:$src2, s4_6ImmPred:$offset))),
+ (V6_vL32b_ai IntRegs:$src2, s4_6ImmPred:$offset)>,
+ Requires<[UseHVXSgl]>;
+ def : Pat<(VTSgl (unalignedload (add IntRegs:$src2, s4_6ImmPred:$offset))),
+ (V6_vL32Ub_ai IntRegs:$src2, s4_6ImmPred:$offset)>,
+ Requires<[UseHVXSgl]>;
+ }
+}
+
+defm : vL32b_ai_pats <v64i8, v128i8>;
+defm : vL32b_ai_pats <v32i16, v64i16>;
+defm : vL32b_ai_pats <v16i32, v32i32>;
+defm : vL32b_ai_pats <v8i64, v16i64>;
+
+multiclass STrivv_pats <ValueType VTSgl, ValueType VTDbl> {
+ def : Pat<(alignedstore (VTSgl VecDblRegs:$src1), IntRegs:$addr),
+ (PS_vstorerw_ai IntRegs:$addr, 0, (VTSgl VecDblRegs:$src1))>,
+ Requires<[UseHVXSgl]>;
+ def : Pat<(unalignedstore (VTSgl VecDblRegs:$src1), IntRegs:$addr),
+ (PS_vstorerwu_ai IntRegs:$addr, 0, (VTSgl VecDblRegs:$src1))>,
+ Requires<[UseHVXSgl]>;
+
+ def : Pat<(alignedstore (VTDbl VecDblRegs128B:$src1), IntRegs:$addr),
+ (PS_vstorerw_ai_128B IntRegs:$addr, 0,
+ (VTDbl VecDblRegs128B:$src1))>,
+ Requires<[UseHVXDbl]>;
+ def : Pat<(unalignedstore (VTDbl VecDblRegs128B:$src1), IntRegs:$addr),
+ (PS_vstorerwu_ai_128B IntRegs:$addr, 0,
+ (VTDbl VecDblRegs128B:$src1))>,
+ Requires<[UseHVXDbl]>;
+}
+
+defm : STrivv_pats <v128i8, v256i8>;
+defm : STrivv_pats <v64i16, v128i16>;
+defm : STrivv_pats <v32i32, v64i32>;
+defm : STrivv_pats <v16i64, v32i64>;
+
+multiclass LDrivv_pats <ValueType VTSgl, ValueType VTDbl> {
+ def : Pat<(VTSgl (alignedload I32:$addr)),
+ (PS_vloadrw_ai I32:$addr, 0)>,
+ Requires<[UseHVXSgl]>;
+ def : Pat<(VTSgl (unalignedload I32:$addr)),
+ (PS_vloadrwu_ai I32:$addr, 0)>,
+ Requires<[UseHVXSgl]>;
+
+ def : Pat<(VTDbl (alignedload I32:$addr)),
+ (PS_vloadrw_ai_128B I32:$addr, 0)>,
+ Requires<[UseHVXDbl]>;
+ def : Pat<(VTDbl (unalignedload I32:$addr)),
+ (PS_vloadrwu_ai_128B I32:$addr, 0)>,
+ Requires<[UseHVXDbl]>;
+}
+
+defm : LDrivv_pats <v128i8, v256i8>;
+defm : LDrivv_pats <v64i16, v128i16>;
+defm : LDrivv_pats <v32i32, v64i32>;
+defm : LDrivv_pats <v16i64, v32i64>;
+
+let Predicates = [HasV60T,UseHVXSgl] in {
+ def: Pat<(select I1:$Pu, (v16i32 VectorRegs:$Vs), VectorRegs:$Vt),
+ (PS_vselect I1:$Pu, VectorRegs:$Vs, VectorRegs:$Vt)>;
+ def: Pat<(select I1:$Pu, (v32i32 VecDblRegs:$Vs), VecDblRegs:$Vt),
+ (PS_wselect I1:$Pu, VecDblRegs:$Vs, VecDblRegs:$Vt)>;
+}
+let Predicates = [HasV60T,UseHVXDbl] in {
+ def: Pat<(select I1:$Pu, (v32i32 VectorRegs128B:$Vs), VectorRegs128B:$Vt),
+ (PS_vselect_128B I1:$Pu, VectorRegs128B:$Vs, VectorRegs128B:$Vt)>;
+ def: Pat<(select I1:$Pu, (v64i32 VecDblRegs128B:$Vs), VecDblRegs128B:$Vt),
+ (PS_wselect_128B I1:$Pu, VecDblRegs128B:$Vs, VecDblRegs128B:$Vt)>;
+}
+
+
+def SDTHexagonVCOMBINE: SDTypeProfile<1, 2, [SDTCisSameAs<1, 2>,
+ SDTCisSubVecOfVec<1, 0>]>;
+
+def HexagonVCOMBINE: SDNode<"HexagonISD::VCOMBINE", SDTHexagonVCOMBINE>;
+
+def: Pat<(v32i32 (HexagonVCOMBINE (v16i32 VectorRegs:$Vs),
+ (v16i32 VectorRegs:$Vt))),
+ (V6_vcombine VectorRegs:$Vs, VectorRegs:$Vt)>,
+ Requires<[UseHVXSgl]>;
+def: Pat<(v64i32 (HexagonVCOMBINE (v32i32 VecDblRegs:$Vs),
+ (v32i32 VecDblRegs:$Vt))),
+ (V6_vcombine_128B VecDblRegs:$Vs, VecDblRegs:$Vt)>,
+ Requires<[UseHVXDbl]>;
+
+def SDTHexagonVPACK: SDTypeProfile<1, 3, [SDTCisSameAs<1, 2>,
+ SDTCisInt<3>]>;
+
+def HexagonVPACK: SDNode<"HexagonISD::VPACK", SDTHexagonVPACK>;
+
+// 0 as the last argument denotes vpacke. 1 denotes vpacko
+def: Pat<(v64i8 (HexagonVPACK (v64i8 VectorRegs:$Vs),
+ (v64i8 VectorRegs:$Vt), (i32 0))),
+ (V6_vpackeb VectorRegs:$Vs, VectorRegs:$Vt)>,
+ Requires<[UseHVXSgl]>;
+def: Pat<(v64i8 (HexagonVPACK (v64i8 VectorRegs:$Vs),
+ (v64i8 VectorRegs:$Vt), (i32 1))),
+ (V6_vpackob VectorRegs:$Vs, VectorRegs:$Vt)>,
+ Requires<[UseHVXSgl]>;
+def: Pat<(v32i16 (HexagonVPACK (v32i16 VectorRegs:$Vs),
+ (v32i16 VectorRegs:$Vt), (i32 0))),
+ (V6_vpackeh VectorRegs:$Vs, VectorRegs:$Vt)>,
+ Requires<[UseHVXSgl]>;
+def: Pat<(v32i16 (HexagonVPACK (v32i16 VectorRegs:$Vs),
+ (v32i16 VectorRegs:$Vt), (i32 1))),
+ (V6_vpackoh VectorRegs:$Vs, VectorRegs:$Vt)>,
+ Requires<[UseHVXSgl]>;
+
+def: Pat<(v128i8 (HexagonVPACK (v128i8 VecDblRegs:$Vs),
+ (v128i8 VecDblRegs:$Vt), (i32 0))),
+ (V6_vpackeb_128B VecDblRegs:$Vs, VecDblRegs:$Vt)>,
+ Requires<[UseHVXDbl]>;
+def: Pat<(v128i8 (HexagonVPACK (v128i8 VecDblRegs:$Vs),
+ (v128i8 VecDblRegs:$Vt), (i32 1))),
+ (V6_vpackob_128B VecDblRegs:$Vs, VecDblRegs:$Vt)>,
+ Requires<[UseHVXDbl]>;
+def: Pat<(v64i16 (HexagonVPACK (v64i16 VecDblRegs:$Vs),
+ (v64i16 VecDblRegs:$Vt), (i32 0))),
+ (V6_vpackeh_128B VecDblRegs:$Vs, VecDblRegs:$Vt)>,
+ Requires<[UseHVXDbl]>;
+def: Pat<(v64i16 (HexagonVPACK (v64i16 VecDblRegs:$Vs),
+ (v64i16 VecDblRegs:$Vt), (i32 1))),
+ (V6_vpackoh_128B VecDblRegs:$Vs, VecDblRegs:$Vt)>,
+ Requires<[UseHVXDbl]>;
+
+def V2I1: PatLeaf<(v2i1 PredRegs:$R)>;
+def V4I1: PatLeaf<(v4i1 PredRegs:$R)>;
+def V8I1: PatLeaf<(v8i1 PredRegs:$R)>;
+def V4I8: PatLeaf<(v4i8 IntRegs:$R)>;
+def V2I16: PatLeaf<(v2i16 IntRegs:$R)>;
+def V8I8: PatLeaf<(v8i8 DoubleRegs:$R)>;
+def V4I16: PatLeaf<(v4i16 DoubleRegs:$R)>;
+def V2I32: PatLeaf<(v2i32 DoubleRegs:$R)>;
+
+
+multiclass bitconvert_32<ValueType a, ValueType b> {
+ def : Pat <(b (bitconvert (a IntRegs:$src))),
+ (b IntRegs:$src)>;
+ def : Pat <(a (bitconvert (b IntRegs:$src))),
+ (a IntRegs:$src)>;
+}
+
+multiclass bitconvert_64<ValueType a, ValueType b> {
+ def : Pat <(b (bitconvert (a DoubleRegs:$src))),
+ (b DoubleRegs:$src)>;
+ def : Pat <(a (bitconvert (b DoubleRegs:$src))),
+ (a DoubleRegs:$src)>;
+}
+
+// Bit convert vector types to integers.
+defm : bitconvert_32<v4i8, i32>;
+defm : bitconvert_32<v2i16, i32>;
+defm : bitconvert_64<v8i8, i64>;
+defm : bitconvert_64<v4i16, i64>;
+defm : bitconvert_64<v2i32, i64>;
+
+def: Pat<(sra (v4i16 DoubleRegs:$src1), u4_0ImmPred:$src2),
+ (S2_asr_i_vh DoubleRegs:$src1, imm:$src2)>;
+def: Pat<(srl (v4i16 DoubleRegs:$src1), u4_0ImmPred:$src2),
+ (S2_lsr_i_vh DoubleRegs:$src1, imm:$src2)>;
+def: Pat<(shl (v4i16 DoubleRegs:$src1), u4_0ImmPred:$src2),
+ (S2_asl_i_vh DoubleRegs:$src1, imm:$src2)>;
+
+def: Pat<(sra (v2i32 DoubleRegs:$src1), u5_0ImmPred:$src2),
+ (S2_asr_i_vw DoubleRegs:$src1, imm:$src2)>;
+def: Pat<(srl (v2i32 DoubleRegs:$src1), u5_0ImmPred:$src2),
+ (S2_lsr_i_vw DoubleRegs:$src1, imm:$src2)>;
+def: Pat<(shl (v2i32 DoubleRegs:$src1), u5_0ImmPred:$src2),
+ (S2_asl_i_vw DoubleRegs:$src1, imm:$src2)>;
+
+def : Pat<(v2i16 (add (v2i16 IntRegs:$src1), (v2i16 IntRegs:$src2))),
+ (A2_svaddh IntRegs:$src1, IntRegs:$src2)>;
+
+def : Pat<(v2i16 (sub (v2i16 IntRegs:$src1), (v2i16 IntRegs:$src2))),
+ (A2_svsubh IntRegs:$src1, IntRegs:$src2)>;
+
+def HexagonVSPLATB: SDNode<"HexagonISD::VSPLATB", SDTUnaryOp>;
+def HexagonVSPLATH: SDNode<"HexagonISD::VSPLATH", SDTUnaryOp>;
+
+// Replicate the low 8-bits from 32-bits input register into each of the
+// four bytes of 32-bits destination register.
+def: Pat<(v4i8 (HexagonVSPLATB I32:$Rs)), (S2_vsplatrb I32:$Rs)>;
+
+// Replicate the low 16-bits from 32-bits input register into each of the
+// four halfwords of 64-bits destination register.
+def: Pat<(v4i16 (HexagonVSPLATH I32:$Rs)), (S2_vsplatrh I32:$Rs)>;
+
+
+class VArith_pat <InstHexagon MI, SDNode Op, PatFrag Type>
+ : Pat <(Op Type:$Rss, Type:$Rtt),
+ (MI Type:$Rss, Type:$Rtt)>;
+
+def: VArith_pat <A2_vaddub, add, V8I8>;
+def: VArith_pat <A2_vaddh, add, V4I16>;
+def: VArith_pat <A2_vaddw, add, V2I32>;
+def: VArith_pat <A2_vsubub, sub, V8I8>;
+def: VArith_pat <A2_vsubh, sub, V4I16>;
+def: VArith_pat <A2_vsubw, sub, V2I32>;
+
+def: VArith_pat <A2_and, and, V2I16>;
+def: VArith_pat <A2_xor, xor, V2I16>;
+def: VArith_pat <A2_or, or, V2I16>;
+
+def: VArith_pat <A2_andp, and, V8I8>;
+def: VArith_pat <A2_andp, and, V4I16>;
+def: VArith_pat <A2_andp, and, V2I32>;
+def: VArith_pat <A2_orp, or, V8I8>;
+def: VArith_pat <A2_orp, or, V4I16>;
+def: VArith_pat <A2_orp, or, V2I32>;
+def: VArith_pat <A2_xorp, xor, V8I8>;
+def: VArith_pat <A2_xorp, xor, V4I16>;
+def: VArith_pat <A2_xorp, xor, V2I32>;
+
+def: Pat<(v2i32 (sra V2I32:$b, (i64 (HexagonCOMBINE (i32 u5_0ImmPred:$c),
+ (i32 u5_0ImmPred:$c))))),
+ (S2_asr_i_vw V2I32:$b, imm:$c)>;
+def: Pat<(v2i32 (srl V2I32:$b, (i64 (HexagonCOMBINE (i32 u5_0ImmPred:$c),
+ (i32 u5_0ImmPred:$c))))),
+ (S2_lsr_i_vw V2I32:$b, imm:$c)>;
+def: Pat<(v2i32 (shl V2I32:$b, (i64 (HexagonCOMBINE (i32 u5_0ImmPred:$c),
+ (i32 u5_0ImmPred:$c))))),
+ (S2_asl_i_vw V2I32:$b, imm:$c)>;
+
+def: Pat<(v4i16 (sra V4I16:$b, (v4i16 (HexagonVSPLATH (i32 (u4_0ImmPred:$c)))))),
+ (S2_asr_i_vh V4I16:$b, imm:$c)>;
+def: Pat<(v4i16 (srl V4I16:$b, (v4i16 (HexagonVSPLATH (i32 (u4_0ImmPred:$c)))))),
+ (S2_lsr_i_vh V4I16:$b, imm:$c)>;
+def: Pat<(v4i16 (shl V4I16:$b, (v4i16 (HexagonVSPLATH (i32 (u4_0ImmPred:$c)))))),
+ (S2_asl_i_vh V4I16:$b, imm:$c)>;
+
+
+def SDTHexagon_v2i32_v2i32_i32 : SDTypeProfile<1, 2,
+ [SDTCisSameAs<0, 1>, SDTCisVT<0, v2i32>, SDTCisInt<2>]>;
+def SDTHexagon_v4i16_v4i16_i32 : SDTypeProfile<1, 2,
+ [SDTCisSameAs<0, 1>, SDTCisVT<0, v4i16>, SDTCisInt<2>]>;
+
+def HexagonVSRAW: SDNode<"HexagonISD::VSRAW", SDTHexagon_v2i32_v2i32_i32>;
+def HexagonVSRAH: SDNode<"HexagonISD::VSRAH", SDTHexagon_v4i16_v4i16_i32>;
+def HexagonVSRLW: SDNode<"HexagonISD::VSRLW", SDTHexagon_v2i32_v2i32_i32>;
+def HexagonVSRLH: SDNode<"HexagonISD::VSRLH", SDTHexagon_v4i16_v4i16_i32>;
+def HexagonVSHLW: SDNode<"HexagonISD::VSHLW", SDTHexagon_v2i32_v2i32_i32>;
+def HexagonVSHLH: SDNode<"HexagonISD::VSHLH", SDTHexagon_v4i16_v4i16_i32>;
+
+def: Pat<(v2i32 (HexagonVSRAW V2I32:$Rs, u5_0ImmPred:$u5)),
+ (S2_asr_i_vw V2I32:$Rs, imm:$u5)>;
+def: Pat<(v4i16 (HexagonVSRAH V4I16:$Rs, u4_0ImmPred:$u4)),
+ (S2_asr_i_vh V4I16:$Rs, imm:$u4)>;
+def: Pat<(v2i32 (HexagonVSRLW V2I32:$Rs, u5_0ImmPred:$u5)),
+ (S2_lsr_i_vw V2I32:$Rs, imm:$u5)>;
+def: Pat<(v4i16 (HexagonVSRLH V4I16:$Rs, u4_0ImmPred:$u4)),
+ (S2_lsr_i_vh V4I16:$Rs, imm:$u4)>;
+def: Pat<(v2i32 (HexagonVSHLW V2I32:$Rs, u5_0ImmPred:$u5)),
+ (S2_asl_i_vw V2I32:$Rs, imm:$u5)>;
+def: Pat<(v4i16 (HexagonVSHLH V4I16:$Rs, u4_0ImmPred:$u4)),
+ (S2_asl_i_vh V4I16:$Rs, imm:$u4)>;
+
+class vshift_rr_pat<InstHexagon MI, SDNode Op, PatFrag Value>
+ : Pat <(Op Value:$Rs, I32:$Rt),
+ (MI Value:$Rs, I32:$Rt)>;
+
+def: vshift_rr_pat <S2_asr_r_vw, HexagonVSRAW, V2I32>;
+def: vshift_rr_pat <S2_asr_r_vh, HexagonVSRAH, V4I16>;
+def: vshift_rr_pat <S2_lsr_r_vw, HexagonVSRLW, V2I32>;
+def: vshift_rr_pat <S2_lsr_r_vh, HexagonVSRLH, V4I16>;
+def: vshift_rr_pat <S2_asl_r_vw, HexagonVSHLW, V2I32>;
+def: vshift_rr_pat <S2_asl_r_vh, HexagonVSHLH, V4I16>;
+
+
+def SDTHexagonVecCompare_v8i8 : SDTypeProfile<1, 2,
+ [SDTCisSameAs<1, 2>, SDTCisVT<0, i1>, SDTCisVT<1, v8i8>]>;
+def SDTHexagonVecCompare_v4i16 : SDTypeProfile<1, 2,
+ [SDTCisSameAs<1, 2>, SDTCisVT<0, i1>, SDTCisVT<1, v4i16>]>;
+def SDTHexagonVecCompare_v2i32 : SDTypeProfile<1, 2,
+ [SDTCisSameAs<1, 2>, SDTCisVT<0, i1>, SDTCisVT<1, v2i32>]>;
+
+def HexagonVCMPBEQ: SDNode<"HexagonISD::VCMPBEQ", SDTHexagonVecCompare_v8i8>;
+def HexagonVCMPBGT: SDNode<"HexagonISD::VCMPBGT", SDTHexagonVecCompare_v8i8>;
+def HexagonVCMPBGTU: SDNode<"HexagonISD::VCMPBGTU", SDTHexagonVecCompare_v8i8>;
+def HexagonVCMPHEQ: SDNode<"HexagonISD::VCMPHEQ", SDTHexagonVecCompare_v4i16>;
+def HexagonVCMPHGT: SDNode<"HexagonISD::VCMPHGT", SDTHexagonVecCompare_v4i16>;
+def HexagonVCMPHGTU: SDNode<"HexagonISD::VCMPHGTU", SDTHexagonVecCompare_v4i16>;
+def HexagonVCMPWEQ: SDNode<"HexagonISD::VCMPWEQ", SDTHexagonVecCompare_v2i32>;
+def HexagonVCMPWGT: SDNode<"HexagonISD::VCMPWGT", SDTHexagonVecCompare_v2i32>;
+def HexagonVCMPWGTU: SDNode<"HexagonISD::VCMPWGTU", SDTHexagonVecCompare_v2i32>;
+
+
+class vcmp_i1_pat<InstHexagon MI, SDNode Op, PatFrag Value>
+ : Pat <(i1 (Op Value:$Rs, Value:$Rt)),
+ (MI Value:$Rs, Value:$Rt)>;
+
+def: vcmp_i1_pat<A2_vcmpbeq, HexagonVCMPBEQ, V8I8>;
+def: vcmp_i1_pat<A4_vcmpbgt, HexagonVCMPBGT, V8I8>;
+def: vcmp_i1_pat<A2_vcmpbgtu, HexagonVCMPBGTU, V8I8>;
+
+def: vcmp_i1_pat<A2_vcmpheq, HexagonVCMPHEQ, V4I16>;
+def: vcmp_i1_pat<A2_vcmphgt, HexagonVCMPHGT, V4I16>;
+def: vcmp_i1_pat<A2_vcmphgtu, HexagonVCMPHGTU, V4I16>;
+
+def: vcmp_i1_pat<A2_vcmpweq, HexagonVCMPWEQ, V2I32>;
+def: vcmp_i1_pat<A2_vcmpwgt, HexagonVCMPWGT, V2I32>;
+def: vcmp_i1_pat<A2_vcmpwgtu, HexagonVCMPWGTU, V2I32>;
+
+
+class vcmp_vi1_pat<InstHexagon MI, PatFrag Op, PatFrag InVal, ValueType OutTy>
+ : Pat <(OutTy (Op InVal:$Rs, InVal:$Rt)),
+ (MI InVal:$Rs, InVal:$Rt)>;
+
+def: vcmp_vi1_pat<A2_vcmpweq, seteq, V2I32, v2i1>;
+def: vcmp_vi1_pat<A2_vcmpwgt, setgt, V2I32, v2i1>;
+def: vcmp_vi1_pat<A2_vcmpwgtu, setugt, V2I32, v2i1>;
+
+def: vcmp_vi1_pat<A2_vcmpheq, seteq, V4I16, v4i1>;
+def: vcmp_vi1_pat<A2_vcmphgt, setgt, V4I16, v4i1>;
+def: vcmp_vi1_pat<A2_vcmphgtu, setugt, V4I16, v4i1>;
+
+def: Pat<(mul V2I32:$Rs, V2I32:$Rt),
+ (PS_vmulw DoubleRegs:$Rs, DoubleRegs:$Rt)>;
+def: Pat<(add V2I32:$Rx, (mul V2I32:$Rs, V2I32:$Rt)),
+ (PS_vmulw_acc DoubleRegs:$Rx, DoubleRegs:$Rs, DoubleRegs:$Rt)>;
+
+
+// Adds two v4i8: Hexagon does not have an insn for this one, so we
+// use the double add v8i8, and use only the low part of the result.
+def: Pat<(v4i8 (add (v4i8 IntRegs:$Rs), (v4i8 IntRegs:$Rt))),
+ (LoReg (A2_vaddub (ToZext64 $Rs), (ToZext64 $Rt)))>;
+
+// Subtract two v4i8: Hexagon does not have an insn for this one, so we
+// use the double sub v8i8, and use only the low part of the result.
+def: Pat<(v4i8 (sub (v4i8 IntRegs:$Rs), (v4i8 IntRegs:$Rt))),
+ (LoReg (A2_vsubub (ToZext64 $Rs), (ToZext64 $Rt)))>;
+
+//
+// No 32 bit vector mux.
+//
+def: Pat<(v4i8 (select I1:$Pu, V4I8:$Rs, V4I8:$Rt)),
+ (LoReg (C2_vmux I1:$Pu, (ToZext64 $Rs), (ToZext64 $Rt)))>;
+def: Pat<(v2i16 (select I1:$Pu, V2I16:$Rs, V2I16:$Rt)),
+ (LoReg (C2_vmux I1:$Pu, (ToZext64 $Rs), (ToZext64 $Rt)))>;
+
+//
+// 64-bit vector mux.
+//
+def: Pat<(v8i8 (vselect V8I1:$Pu, V8I8:$Rs, V8I8:$Rt)),
+ (C2_vmux V8I1:$Pu, V8I8:$Rs, V8I8:$Rt)>;
+def: Pat<(v4i16 (vselect V4I1:$Pu, V4I16:$Rs, V4I16:$Rt)),
+ (C2_vmux V4I1:$Pu, V4I16:$Rs, V4I16:$Rt)>;
+def: Pat<(v2i32 (vselect V2I1:$Pu, V2I32:$Rs, V2I32:$Rt)),
+ (C2_vmux V2I1:$Pu, V2I32:$Rs, V2I32:$Rt)>;
+
+//
+// No 32 bit vector compare.
+//
+def: Pat<(i1 (seteq V4I8:$Rs, V4I8:$Rt)),
+ (A2_vcmpbeq (ToZext64 $Rs), (ToZext64 $Rt))>;
+def: Pat<(i1 (setgt V4I8:$Rs, V4I8:$Rt)),
+ (A4_vcmpbgt (ToZext64 $Rs), (ToZext64 $Rt))>;
+def: Pat<(i1 (setugt V4I8:$Rs, V4I8:$Rt)),
+ (A2_vcmpbgtu (ToZext64 $Rs), (ToZext64 $Rt))>;
+
+def: Pat<(i1 (seteq V2I16:$Rs, V2I16:$Rt)),
+ (A2_vcmpheq (ToZext64 $Rs), (ToZext64 $Rt))>;
+def: Pat<(i1 (setgt V2I16:$Rs, V2I16:$Rt)),
+ (A2_vcmphgt (ToZext64 $Rs), (ToZext64 $Rt))>;
+def: Pat<(i1 (setugt V2I16:$Rs, V2I16:$Rt)),
+ (A2_vcmphgtu (ToZext64 $Rs), (ToZext64 $Rt))>;
+
+
+class InvertCmp_pat<InstHexagon InvMI, PatFrag CmpOp, PatFrag Value,
+ ValueType CmpTy>
+ : Pat<(CmpTy (CmpOp Value:$Rs, Value:$Rt)),
+ (InvMI Value:$Rt, Value:$Rs)>;
+
+// Map from a compare operation to the corresponding instruction with the
+// order of operands reversed, e.g. x > y --> cmp.lt(y,x).
+def: InvertCmp_pat<A4_vcmpbgt, setlt, V8I8, i1>;
+def: InvertCmp_pat<A4_vcmpbgt, setlt, V8I8, v8i1>;
+def: InvertCmp_pat<A2_vcmphgt, setlt, V4I16, i1>;
+def: InvertCmp_pat<A2_vcmphgt, setlt, V4I16, v4i1>;
+def: InvertCmp_pat<A2_vcmpwgt, setlt, V2I32, i1>;
+def: InvertCmp_pat<A2_vcmpwgt, setlt, V2I32, v2i1>;
+
+def: InvertCmp_pat<A2_vcmpbgtu, setult, V8I8, i1>;
+def: InvertCmp_pat<A2_vcmpbgtu, setult, V8I8, v8i1>;
+def: InvertCmp_pat<A2_vcmphgtu, setult, V4I16, i1>;
+def: InvertCmp_pat<A2_vcmphgtu, setult, V4I16, v4i1>;
+def: InvertCmp_pat<A2_vcmpwgtu, setult, V2I32, i1>;
+def: InvertCmp_pat<A2_vcmpwgtu, setult, V2I32, v2i1>;
+
+// Map from vcmpne(Rss) -> !vcmpew(Rss).
+// rs != rt -> !(rs == rt).
+def: Pat<(v2i1 (setne V2I32:$Rs, V2I32:$Rt)),
+ (C2_not (v2i1 (A2_vcmpbeq V2I32:$Rs, V2I32:$Rt)))>;
+
+
+// Truncate: from vector B copy all 'E'ven 'B'yte elements:
+// A[0] = B[0]; A[1] = B[2]; A[2] = B[4]; A[3] = B[6];
+def: Pat<(v4i8 (trunc V4I16:$Rs)),
+ (S2_vtrunehb V4I16:$Rs)>;
+
+// Truncate: from vector B copy all 'O'dd 'B'yte elements:
+// A[0] = B[1]; A[1] = B[3]; A[2] = B[5]; A[3] = B[7];
+// S2_vtrunohb
+
+// Truncate: from vectors B and C copy all 'E'ven 'H'alf-word elements:
+// A[0] = B[0]; A[1] = B[2]; A[2] = C[0]; A[3] = C[2];
+// S2_vtruneh
+
+def: Pat<(v2i16 (trunc V2I32:$Rs)),
+ (LoReg (S2_packhl (HiReg $Rs), (LoReg $Rs)))>;
+
+
+def HexagonVSXTBH : SDNode<"HexagonISD::VSXTBH", SDTUnaryOp>;
+def HexagonVSXTBW : SDNode<"HexagonISD::VSXTBW", SDTUnaryOp>;
+
+def: Pat<(i64 (HexagonVSXTBH I32:$Rs)), (S2_vsxtbh I32:$Rs)>;
+def: Pat<(i64 (HexagonVSXTBW I32:$Rs)), (S2_vsxthw I32:$Rs)>;
+
+def: Pat<(v4i16 (zext V4I8:$Rs)), (S2_vzxtbh V4I8:$Rs)>;
+def: Pat<(v2i32 (zext V2I16:$Rs)), (S2_vzxthw V2I16:$Rs)>;
+def: Pat<(v4i16 (anyext V4I8:$Rs)), (S2_vzxtbh V4I8:$Rs)>;
+def: Pat<(v2i32 (anyext V2I16:$Rs)), (S2_vzxthw V2I16:$Rs)>;
+def: Pat<(v4i16 (sext V4I8:$Rs)), (S2_vsxtbh V4I8:$Rs)>;
+def: Pat<(v2i32 (sext V2I16:$Rs)), (S2_vsxthw V2I16:$Rs)>;
+
+// Sign extends a v2i8 into a v2i32.
+def: Pat<(v2i32 (sext_inreg V2I32:$Rs, v2i8)),
+ (A2_combinew (A2_sxtb (HiReg $Rs)), (A2_sxtb (LoReg $Rs)))>;
+
+// Sign extends a v2i16 into a v2i32.
+def: Pat<(v2i32 (sext_inreg V2I32:$Rs, v2i16)),
+ (A2_combinew (A2_sxth (HiReg $Rs)), (A2_sxth (LoReg $Rs)))>;
+
+
+// Multiplies two v2i16 and returns a v2i32. We are using here the
+// saturating multiply, as hexagon does not provide a non saturating
+// vector multiply, and saturation does not impact the result that is
+// in double precision of the operands.
+
+// Multiplies two v2i16 vectors: as Hexagon does not have a multiply
+// with the C semantics for this one, this pattern uses the half word
+// multiply vmpyh that takes two v2i16 and returns a v2i32. This is
+// then truncated to fit this back into a v2i16 and to simulate the
+// wrap around semantics for unsigned in C.
+def vmpyh: OutPatFrag<(ops node:$Rs, node:$Rt),
+ (M2_vmpy2s_s0 (i32 $Rs), (i32 $Rt))>;
+
+def: Pat<(v2i16 (mul V2I16:$Rs, V2I16:$Rt)),
+ (LoReg (S2_vtrunewh (v2i32 (A2_combineii 0, 0)),
+ (v2i32 (vmpyh V2I16:$Rs, V2I16:$Rt))))>;
+
+// Multiplies two v4i16 vectors.
+def: Pat<(v4i16 (mul V4I16:$Rs, V4I16:$Rt)),
+ (S2_vtrunewh (vmpyh (HiReg $Rs), (HiReg $Rt)),
+ (vmpyh (LoReg $Rs), (LoReg $Rt)))>;
+
+def VMPYB_no_V5: OutPatFrag<(ops node:$Rs, node:$Rt),
+ (S2_vtrunewh (vmpyh (HiReg (S2_vsxtbh $Rs)), (HiReg (S2_vsxtbh $Rt))),
+ (vmpyh (LoReg (S2_vsxtbh $Rs)), (LoReg (S2_vsxtbh $Rt))))>;
+
+// Multiplies two v4i8 vectors.
+def: Pat<(v4i8 (mul V4I8:$Rs, V4I8:$Rt)),
+ (S2_vtrunehb (M5_vmpybsu V4I8:$Rs, V4I8:$Rt))>,
+ Requires<[HasV5T]>;
+
+def: Pat<(v4i8 (mul V4I8:$Rs, V4I8:$Rt)),
+ (S2_vtrunehb (VMPYB_no_V5 V4I8:$Rs, V4I8:$Rt))>;
+
+// Multiplies two v8i8 vectors.
+def: Pat<(v8i8 (mul V8I8:$Rs, V8I8:$Rt)),
+ (A2_combinew (S2_vtrunehb (M5_vmpybsu (HiReg $Rs), (HiReg $Rt))),
+ (S2_vtrunehb (M5_vmpybsu (LoReg $Rs), (LoReg $Rt))))>,
+ Requires<[HasV5T]>;
+
+def: Pat<(v8i8 (mul V8I8:$Rs, V8I8:$Rt)),
+ (A2_combinew (S2_vtrunehb (VMPYB_no_V5 (HiReg $Rs), (HiReg $Rt))),
+ (S2_vtrunehb (VMPYB_no_V5 (LoReg $Rs), (LoReg $Rt))))>;
+
+def SDTHexagonBinOp64 : SDTypeProfile<1, 2,
+ [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVT<0, i64>]>;
+
+def HexagonSHUFFEB: SDNode<"HexagonISD::SHUFFEB", SDTHexagonBinOp64>;
+def HexagonSHUFFEH: SDNode<"HexagonISD::SHUFFEH", SDTHexagonBinOp64>;
+def HexagonSHUFFOB: SDNode<"HexagonISD::SHUFFOB", SDTHexagonBinOp64>;
+def HexagonSHUFFOH: SDNode<"HexagonISD::SHUFFOH", SDTHexagonBinOp64>;
+
+class ShufflePat<InstHexagon MI, SDNode Op>
+ : Pat<(i64 (Op DoubleRegs:$src1, DoubleRegs:$src2)),
+ (i64 (MI DoubleRegs:$src1, DoubleRegs:$src2))>;
+
+// Shuffles even bytes for i=0..3: A[2*i].b = C[2*i].b; A[2*i+1].b = B[2*i].b
+def: ShufflePat<S2_shuffeb, HexagonSHUFFEB>;
+
+// Shuffles odd bytes for i=0..3: A[2*i].b = C[2*i+1].b; A[2*i+1].b = B[2*i+1].b
+def: ShufflePat<S2_shuffob, HexagonSHUFFOB>;
+
+// Shuffles even half for i=0,1: A[2*i].h = C[2*i].h; A[2*i+1].h = B[2*i].h
+def: ShufflePat<S2_shuffeh, HexagonSHUFFEH>;
+
+// Shuffles odd half for i=0,1: A[2*i].h = C[2*i+1].h; A[2*i+1].h = B[2*i+1].h
+def: ShufflePat<S2_shuffoh, HexagonSHUFFOH>;
+
+
+// Truncated store from v4i16 to v4i8.
+def truncstorev4i8: PatFrag<(ops node:$val, node:$ptr),
+ (truncstore node:$val, node:$ptr),
+ [{ return cast<StoreSDNode>(N)->getMemoryVT() == MVT::v4i8; }]>;
+
+// Truncated store from v2i32 to v2i16.
+def truncstorev2i16: PatFrag<(ops node:$val, node:$ptr),
+ (truncstore node:$val, node:$ptr),
+ [{ return cast<StoreSDNode>(N)->getMemoryVT() == MVT::v2i16; }]>;
+
+def: Pat<(truncstorev2i16 V2I32:$Rs, I32:$Rt),
+ (S2_storeri_io I32:$Rt, 0, (LoReg (S2_packhl (HiReg $Rs),
+ (LoReg $Rs))))>;
+
+def: Pat<(truncstorev4i8 V4I16:$Rs, I32:$Rt),
+ (S2_storeri_io I32:$Rt, 0, (S2_vtrunehb V4I16:$Rs))>;
+
+
+// Zero and sign extended load from v2i8 into v2i16.
+def zextloadv2i8: PatFrag<(ops node:$ptr), (zextload node:$ptr),
+ [{ return cast<LoadSDNode>(N)->getMemoryVT() == MVT::v2i8; }]>;
+
+def sextloadv2i8: PatFrag<(ops node:$ptr), (sextload node:$ptr),
+ [{ return cast<LoadSDNode>(N)->getMemoryVT() == MVT::v2i8; }]>;
+
+def: Pat<(v2i16 (zextloadv2i8 I32:$Rs)),
+ (LoReg (v4i16 (S2_vzxtbh (L2_loadruh_io I32:$Rs, 0))))>;
+
+def: Pat<(v2i16 (sextloadv2i8 I32:$Rs)),
+ (LoReg (v4i16 (S2_vsxtbh (L2_loadrh_io I32:$Rs, 0))))>;
+
+def: Pat<(v2i32 (zextloadv2i8 I32:$Rs)),
+ (S2_vzxthw (LoReg (v4i16 (S2_vzxtbh (L2_loadruh_io I32:$Rs, 0)))))>;
+
+def: Pat<(v2i32 (sextloadv2i8 I32:$Rs)),
+ (S2_vsxthw (LoReg (v4i16 (S2_vsxtbh (L2_loadrh_io I32:$Rs, 0)))))>;
+
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp
index b064dec..ee32093 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp
@@ -10,7 +10,7 @@
// Transform the following pattern
// %vreg170<def> = SXTW %vreg166
// ...
-// %vreg176<def> = COPY %vreg170:subreg_loreg
+// %vreg176<def> = COPY %vreg170:isub_lo
//
// Into
// %vreg176<def> = COPY vreg166
@@ -93,7 +93,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon optimize redundant zero and size extends";
}
@@ -167,9 +167,9 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) {
// Look for this sequence below
// %vregDoubleReg1 = LSRd_ri %vregDoubleReg0, 32
- // %vregIntReg = COPY %vregDoubleReg1:subreg_loreg.
+ // %vregIntReg = COPY %vregDoubleReg1:isub_lo.
// and convert into
- // %vregIntReg = COPY %vregDoubleReg0:subreg_hireg.
+ // %vregIntReg = COPY %vregDoubleReg0:isub_hi.
if (MI.getOpcode() == Hexagon::S2_lsr_i_p) {
assert(MI.getNumOperands() == 3);
MachineOperand &Dst = MI.getOperand(0);
@@ -180,7 +180,7 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) {
unsigned DstReg = Dst.getReg();
unsigned SrcReg = Src1.getReg();
PeepholeDoubleRegsMap[DstReg] =
- std::make_pair(*&SrcReg, Hexagon::subreg_hireg);
+ std::make_pair(*&SrcReg, Hexagon::isub_hi);
}
// Look for P=NOT(P).
@@ -201,14 +201,14 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) {
}
// Look for copy:
- // %vreg176<def> = COPY %vreg170:subreg_loreg
+ // %vreg176<def> = COPY %vreg170:isub_lo
if (!DisableOptSZExt && MI.isCopy()) {
assert(MI.getNumOperands() == 2);
MachineOperand &Dst = MI.getOperand(0);
MachineOperand &Src = MI.getOperand(1);
// Make sure we are copying the lower 32 bits.
- if (Src.getSubReg() != Hexagon::subreg_loreg)
+ if (Src.getSubReg() != Hexagon::isub_lo)
continue;
unsigned DstReg = Dst.getReg();
@@ -250,6 +250,7 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) {
if (unsigned PeepholeSrc = PeepholeMap.lookup(Reg0)) {
// Change the 1st operand and, flip the opcode.
MI.getOperand(0).setReg(PeepholeSrc);
+ MRI->clearKillFlags(PeepholeSrc);
int NewOp = QII->getInvertedPredicatedOpcode(MI.getOpcode());
MI.setDesc(QII->get(NewOp));
Done = true;
@@ -280,6 +281,7 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) {
unsigned PSrc = MI.getOperand(PR).getReg();
if (unsigned POrig = PeepholeMap.lookup(PSrc)) {
MI.getOperand(PR).setReg(POrig);
+ MRI->clearKillFlags(POrig);
MI.setDesc(QII->get(NewOp));
// Swap operands S1 and S2.
MachineOperand Op1 = MI.getOperand(S1);
@@ -304,6 +306,7 @@ void HexagonPeephole::ChangeOpInto(MachineOperand &Dst, MachineOperand &Src) {
if (Src.isReg()) {
Dst.setReg(Src.getReg());
Dst.setSubReg(Src.getSubReg());
+ MRI->clearKillFlags(Src.getReg());
} else if (Src.isImm()) {
Dst.ChangeToImmediate(Src.getImm());
} else {
@@ -316,7 +319,7 @@ void HexagonPeephole::ChangeOpInto(MachineOperand &Dst, MachineOperand &Src) {
Dst.setImm(Src.getImm());
} else if (Src.isReg()) {
Dst.ChangeToRegister(Src.getReg(), Src.isDef(), Src.isImplicit(),
- Src.isKill(), Src.isDead(), Src.isUndef(),
+ false, Src.isDead(), Src.isUndef(),
Src.isDebug());
Dst.setSubReg(Src.getSubReg());
} else {
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonRDF.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonRDF.cpp
deleted file mode 100644
index 06719cd..0000000
--- a/contrib/llvm/lib/Target/Hexagon/HexagonRDF.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-//===--- HexagonRDF.cpp ---------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "HexagonRDF.h"
-#include "HexagonInstrInfo.h"
-#include "HexagonRegisterInfo.h"
-
-#include "llvm/CodeGen/MachineInstr.h"
-
-using namespace llvm;
-using namespace rdf;
-
-bool HexagonRegisterAliasInfo::covers(RegisterRef RA, RegisterRef RB) const {
- if (RA == RB)
- return true;
-
- if (TargetRegisterInfo::isVirtualRegister(RA.Reg) &&
- TargetRegisterInfo::isVirtualRegister(RB.Reg)) {
- // Hexagon-specific cases.
- if (RA.Reg == RB.Reg) {
- if (RA.Sub == 0)
- return true;
- if (RB.Sub == 0)
- return false;
- }
- }
-
- return RegisterAliasInfo::covers(RA, RB);
-}
-
-bool HexagonRegisterAliasInfo::covers(const RegisterSet &RRs, RegisterRef RR)
- const {
- if (RRs.count(RR))
- return true;
-
- if (!TargetRegisterInfo::isPhysicalRegister(RR.Reg)) {
- assert(TargetRegisterInfo::isVirtualRegister(RR.Reg));
- // Check if both covering subregisters are present.
- bool HasLo = RRs.count({RR.Reg, Hexagon::subreg_loreg});
- bool HasHi = RRs.count({RR.Reg, Hexagon::subreg_hireg});
- if (HasLo && HasHi)
- return true;
- }
-
- if (RR.Sub == 0) {
- // Check if both covering subregisters are present.
- unsigned Lo = TRI.getSubReg(RR.Reg, Hexagon::subreg_loreg);
- unsigned Hi = TRI.getSubReg(RR.Reg, Hexagon::subreg_hireg);
- if (RRs.count({Lo, 0}) && RRs.count({Hi, 0}))
- return true;
- }
-
- return RegisterAliasInfo::covers(RRs, RR);
-}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonRDF.h b/contrib/llvm/lib/Target/Hexagon/HexagonRDF.h
deleted file mode 100644
index 9a63150..0000000
--- a/contrib/llvm/lib/Target/Hexagon/HexagonRDF.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//===--- HexagonRDF.h -----------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef HEXAGON_RDF_H
-#define HEXAGON_RDF_H
-#include "RDFGraph.h"
-
-namespace llvm {
- class TargetRegisterInfo;
-
-namespace rdf {
- struct HexagonRegisterAliasInfo : public RegisterAliasInfo {
- HexagonRegisterAliasInfo(const TargetRegisterInfo &TRI)
- : RegisterAliasInfo(TRI) {}
- bool covers(RegisterRef RA, RegisterRef RR) const override;
- bool covers(const RegisterSet &RRs, RegisterRef RR) const override;
- };
-} // namespace rdf
-} // namespace llvm
-
-#endif
-
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonRDFOpt.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonRDFOpt.cpp
index 642a878..30640e1 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonRDFOpt.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonRDFOpt.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "HexagonInstrInfo.h"
-#include "HexagonRDF.h"
#include "HexagonSubtarget.h"
#include "RDFCopy.h"
#include "RDFDeadCode.h"
@@ -50,14 +49,14 @@ namespace {
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Hexagon RDF optimizations";
}
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
static char ID;
@@ -99,6 +98,7 @@ bool HexagonCP::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) {
EM.insert(std::make_pair(DstR, SrcR));
};
+ DataFlowGraph &DFG = getDFG();
unsigned Opc = MI->getOpcode();
switch (Opc) {
case Hexagon::A2_combinew: {
@@ -106,23 +106,23 @@ bool HexagonCP::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) {
const MachineOperand &HiOp = MI->getOperand(1);
const MachineOperand &LoOp = MI->getOperand(2);
assert(DstOp.getSubReg() == 0 && "Unexpected subregister");
- mapRegs({ DstOp.getReg(), Hexagon::subreg_hireg },
- { HiOp.getReg(), HiOp.getSubReg() });
- mapRegs({ DstOp.getReg(), Hexagon::subreg_loreg },
- { LoOp.getReg(), LoOp.getSubReg() });
+ mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_hi),
+ DFG.makeRegRef(HiOp.getReg(), HiOp.getSubReg()));
+ mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_lo),
+ DFG.makeRegRef(LoOp.getReg(), LoOp.getSubReg()));
return true;
}
case Hexagon::A2_addi: {
const MachineOperand &A = MI->getOperand(2);
if (!A.isImm() || A.getImm() != 0)
return false;
+ LLVM_FALLTHROUGH;
}
- // Fall through.
case Hexagon::A2_tfr: {
const MachineOperand &DstOp = MI->getOperand(0);
const MachineOperand &SrcOp = MI->getOperand(1);
- mapRegs({ DstOp.getReg(), DstOp.getSubReg() },
- { SrcOp.getReg(), SrcOp.getSubReg() });
+ mapRegs(DFG.makeRegRef(DstOp.getReg(), DstOp.getSubReg()),
+ DFG.makeRegRef(SrcOp.getReg(), SrcOp.getSubReg()));
return true;
}
}
@@ -182,7 +182,8 @@ void HexagonDCE::removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum) {
llvm_unreachable("Invalid operand");
};
DenseMap<NodeId,unsigned> OpMap;
- NodeList Refs = IA.Addr->members(getDFG());
+ DataFlowGraph &DFG = getDFG();
+ NodeList Refs = IA.Addr->members(DFG);
for (NodeAddr<RefNode*> RA : Refs)
OpMap.insert(std::make_pair(RA.Id, getOpNum(RA.Addr->getOp())));
@@ -191,9 +192,9 @@ void HexagonDCE::removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum) {
for (NodeAddr<RefNode*> RA : Refs) {
unsigned N = OpMap[RA.Id];
if (N < OpNum)
- RA.Addr->setRegRef(&MI->getOperand(N));
+ RA.Addr->setRegRef(&MI->getOperand(N), DFG);
else if (N > OpNum)
- RA.Addr->setRegRef(&MI->getOperand(N-1));
+ RA.Addr->setRegRef(&MI->getOperand(N-1), DFG);
}
}
@@ -202,11 +203,11 @@ bool HexagonDCE::rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove) {
if (!getDFG().IsCode<NodeAttrs::Stmt>(IA))
return false;
DataFlowGraph &DFG = getDFG();
- MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
+ MachineInstr &MI = *NodeAddr<StmtNode*>(IA).Addr->getCode();
auto &HII = static_cast<const HexagonInstrInfo&>(DFG.getTII());
if (HII.getAddrMode(MI) != HexagonII::PostInc)
return false;
- unsigned Opc = MI->getOpcode();
+ unsigned Opc = MI.getOpcode();
unsigned OpNum, NewOpc;
switch (Opc) {
case Hexagon::L2_loadri_pi:
@@ -240,12 +241,12 @@ bool HexagonDCE::rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove) {
return getDeadNodes().count(DA.Id);
};
NodeList Defs;
- MachineOperand &Op = MI->getOperand(OpNum);
+ MachineOperand &Op = MI.getOperand(OpNum);
for (NodeAddr<DefNode*> DA : IA.Addr->members_if(DFG.IsDef, DFG)) {
if (&DA.Addr->getOp() != &Op)
continue;
Defs = DFG.getRelatedRefs(IA, DA);
- if (!std::all_of(Defs.begin(), Defs.end(), IsDead))
+ if (!all_of(Defs, IsDead))
return false;
break;
}
@@ -255,12 +256,12 @@ bool HexagonDCE::rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove) {
Remove.insert(D.Id);
if (trace())
- dbgs() << "Rewriting: " << *MI;
- MI->setDesc(HII.get(NewOpc));
- MI->getOperand(OpNum+2).setImm(0);
+ dbgs() << "Rewriting: " << MI;
+ MI.setDesc(HII.get(NewOpc));
+ MI.getOperand(OpNum+2).setImm(0);
removeOperand(IA, OpNum);
if (trace())
- dbgs() << " to: " << *MI;
+ dbgs() << " to: " << MI;
return true;
}
@@ -286,9 +287,8 @@ bool HexagonRDFOpt::runOnMachineFunction(MachineFunction &MF) {
if (RDFDump)
MF.print(dbgs() << "Before " << getPassName() << "\n", nullptr);
- HexagonRegisterAliasInfo HAI(HRI);
TargetOperandInfo TOI(HII);
- DataFlowGraph G(MF, HII, HRI, *MDT, MDF, HAI, TOI);
+ DataFlowGraph G(MF, HII, HRI, *MDT, MDF, TOI);
// Dead phi nodes are necessary for copy propagation: we can add a use
// of a register in a block where it would need a phi node, but which
// was dead (and removed) during the graph build time.
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
index 23ebfd4..d3f230d 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
@@ -151,6 +151,7 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF)
Reserved.set(Hexagon::CS0);
Reserved.set(Hexagon::CS1);
Reserved.set(Hexagon::CS);
+ Reserved.set(Hexagon::USR);
return Reserved;
}
@@ -180,12 +181,12 @@ void HexagonRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
unsigned Opc = MI.getOpcode();
switch (Opc) {
- case Hexagon::TFR_FIA:
+ case Hexagon::PS_fia:
MI.setDesc(HII.get(Hexagon::A2_addi));
MI.getOperand(FIOp).ChangeToImmediate(RealOffset);
MI.RemoveOperand(FIOp+1);
return;
- case Hexagon::TFR_FI:
+ case Hexagon::PS_fi:
// Set up the instruction for updating below.
MI.setDesc(HII.get(Hexagon::A2_addi));
break;
@@ -234,6 +235,28 @@ unsigned HexagonRegisterInfo::getStackRegister() const {
}
+unsigned HexagonRegisterInfo::getHexagonSubRegIndex(
+ const TargetRegisterClass *RC, unsigned GenIdx) const {
+ assert(GenIdx == Hexagon::ps_sub_lo || GenIdx == Hexagon::ps_sub_hi);
+
+ static const unsigned ISub[] = { Hexagon::isub_lo, Hexagon::isub_hi };
+ static const unsigned VSub[] = { Hexagon::vsub_lo, Hexagon::vsub_hi };
+
+ switch (RC->getID()) {
+ case Hexagon::CtrRegs64RegClassID:
+ case Hexagon::DoubleRegsRegClassID:
+ return ISub[GenIdx];
+ case Hexagon::VecDblRegsRegClassID:
+ case Hexagon::VecDblRegs128BRegClassID:
+ return VSub[GenIdx];
+ }
+
+ if (const TargetRegisterClass *SuperRC = *RC->getSuperClasses())
+ return getHexagonSubRegIndex(SuperRC, GenIdx);
+
+ llvm_unreachable("Invalid register class");
+}
+
bool HexagonRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF)
const {
return MF.getSubtarget<HexagonSubtarget>().getFrameLowering()->hasFP(MF);
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.h b/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.h
index fc70679..1fb295b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.h
@@ -22,6 +22,12 @@
#include "HexagonGenRegisterInfo.inc"
namespace llvm {
+
+namespace Hexagon {
+ // Generic (pseudo) subreg indices for use with getHexagonSubRegIndex.
+ enum { ps_sub_lo = 0, ps_sub_hi = 1 };
+}
+
class HexagonRegisterInfo : public HexagonGenRegisterInfo {
public:
HexagonRegisterInfo();
@@ -61,6 +67,9 @@ public:
unsigned getFrameRegister() const;
unsigned getStackRegister() const;
+ unsigned getHexagonSubRegIndex(const TargetRegisterClass *RC,
+ unsigned GenIdx) const;
+
const MCPhysReg *getCallerSavedRegs(const MachineFunction *MF,
const TargetRegisterClass *RC) const;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.td b/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.td
index 4d0d411..a75f351 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonRegisterInfo.td
@@ -81,8 +81,10 @@ let Namespace = "Hexagon" in {
let Num = !cast<bits<5>>(num);
}
- def subreg_loreg : SubRegIndex<32>;
- def subreg_hireg : SubRegIndex<32, 32>;
+ def isub_lo : SubRegIndex<32>;
+ def isub_hi : SubRegIndex<32, 32>;
+ def vsub_lo : SubRegIndex<512>;
+ def vsub_hi : SubRegIndex<512, 512>;
def subreg_overflow : SubRegIndex<1, 0>;
// Integer registers.
@@ -95,7 +97,7 @@ let Namespace = "Hexagon" in {
def R31 : Ri<31, "r31", ["lr"]>, DwarfRegNum<[31]>;
// Aliases of the R* registers used to hold 64-bit int values (doubles).
- let SubRegIndices = [subreg_loreg, subreg_hireg], CoveredBySubRegs = 1 in {
+ let SubRegIndices = [isub_lo, isub_hi], CoveredBySubRegs = 1 in {
def D0 : Rd< 0, "r1:0", [R0, R1]>, DwarfRegNum<[32]>;
def D1 : Rd< 2, "r3:2", [R2, R3]>, DwarfRegNum<[34]>;
def D2 : Rd< 4, "r5:4", [R4, R5]>, DwarfRegNum<[36]>;
@@ -150,12 +152,12 @@ let Namespace = "Hexagon" in {
// Define C8 separately and make it aliased with USR.
// The problem is that USR has subregisters (e.g. overflow). If USR was
// specified as a subregister of C9_8, it would imply that subreg_overflow
- // and subreg_loreg can be composed, which leads to all kinds of issues
+ // and isub_lo can be composed, which leads to all kinds of issues
// with lane masks.
def C8 : Rc<8, "c8", [], [USR]>, DwarfRegNum<[75]>;
def PC : Rc<9, "pc">, DwarfRegNum<[76]>;
def UGP : Rc<10, "ugp", ["c10"]>, DwarfRegNum<[77]>;
- def GP : Rc<11, "gp">, DwarfRegNum<[78]>;
+ def GP : Rc<11, "gp", ["c11"]>, DwarfRegNum<[78]>;
def CS0 : Rc<12, "cs0", ["c12"]>, DwarfRegNum<[79]>;
def CS1 : Rc<13, "cs1", ["c13"]>, DwarfRegNum<[80]>;
def UPCL : Rc<14, "upcyclelo", ["c14"]>, DwarfRegNum<[81]>;
@@ -163,9 +165,10 @@ let Namespace = "Hexagon" in {
}
// Control registers pairs.
- let SubRegIndices = [subreg_loreg, subreg_hireg], CoveredBySubRegs = 1 in {
+ let SubRegIndices = [isub_lo, isub_hi], CoveredBySubRegs = 1 in {
def C1_0 : Rcc<0, "c1:0", [SA0, LC0], ["lc0:sa0"]>, DwarfRegNum<[67]>;
def C3_2 : Rcc<2, "c3:2", [SA1, LC1], ["lc1:sa1"]>, DwarfRegNum<[69]>;
+ def C5_4 : Rcc<4, "c5:4", [P3_0, C5]>, DwarfRegNum<[71]>;
def C7_6 : Rcc<6, "c7:6", [C6, C7], ["m1:0"]>, DwarfRegNum<[72]>;
// Use C8 instead of USR as a subregister of C9_8.
def C9_8 : Rcc<8, "c9:8", [C8, PC]>, DwarfRegNum<[74]>;
@@ -179,7 +182,7 @@ let Namespace = "Hexagon" in {
}
// Aliases of the V* registers used to hold double vec values.
- let SubRegIndices = [subreg_loreg, subreg_hireg], CoveredBySubRegs = 1 in {
+ let SubRegIndices = [vsub_lo, vsub_hi], CoveredBySubRegs = 1 in {
def W0 : Rd< 0, "v1:0", [V0, V1]>, DwarfRegNum<[99]>;
def W1 : Rd< 2, "v3:2", [V2, V3]>, DwarfRegNum<[101]>;
def W2 : Rd< 4, "v5:4", [V4, V5]>, DwarfRegNum<[103]>;
@@ -256,10 +259,13 @@ def ModRegs : RegisterClass<"Hexagon", [i32], 32, (add M0, M1)>;
let Size = 32, isAllocatable = 0 in
def CtrRegs : RegisterClass<"Hexagon", [i32], 32,
- (add LC0, SA0, LC1, SA1,
- P3_0,
- M0, M1, C6, C7, CS0, CS1, UPCL, UPCH,
- USR, USR_OVF, UGP, GP, PC)>;
+ (add LC0, SA0, LC1, SA1,
+ P3_0, C5,
+ M0, M1, C6, C7, C8, CS0, CS1, UPCL, UPCH,
+ USR, UGP, GP, PC)>;
+
+let isAllocatable = 0 in
+def UsrBits : RegisterClass<"Hexagon", [i1], 0, (add USR_OVF)>;
let Size = 64, isAllocatable = 0 in
def CtrRegs64 : RegisterClass<"Hexagon", [i64], 64,
@@ -278,8 +284,3 @@ def VolatileV3 {
W12, W13, W14, W15,
Q0, Q1, Q2, Q3];
}
-
-def PositiveHalfWord : PatLeaf<(i32 IntRegs:$a),
-[{
- return isPositiveHalfWord(N);
-}]>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSelectCCInfo.td b/contrib/llvm/lib/Target/Hexagon/HexagonSelectCCInfo.td
deleted file mode 100644
index d8feb89..0000000
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSelectCCInfo.td
+++ /dev/null
@@ -1,121 +0,0 @@
-//===-- HexagoSelectCCInfo.td - Selectcc mappings ----------*- tablegen -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-
-//
-// selectcc mappings.
-//
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETEQ)),
- (i32 (MUX_rr (i1 (CMPEQrr IntRegs:$lhs, IntRegs:$rhs)),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETNE)),
- (i32 (MUX_rr (i1 (NOT_p (CMPEQrr IntRegs:$lhs, IntRegs:$rhs))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETGT)),
- (i32 (MUX_rr (i1 (CMPGTrr IntRegs:$lhs, IntRegs:$rhs)),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETUGT)),
- (i32 (MUX_rr (i1 (CMPGTUrr IntRegs:$lhs, IntRegs:$rhs)),
- IntRegs:$tval, IntRegs:$fval))>;
-
-
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETULT)),
- (i32 (MUX_rr (i1 (NOT_p (CMPGTUrr IntRegs:$lhs,
- (ADD_ri IntRegs:$rhs, -1)))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETLT)),
- (i32 (MUX_rr (i1 (NOT_p (CMPGTrr IntRegs:$lhs,
- (ADD_ri IntRegs:$rhs, -1)))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETLE)),
- (i32 (MUX_rr (i1 (NOT_p (CMPGTrr IntRegs:$lhs, IntRegs:$rhs))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETULE)),
- (i32 (MUX_rr (i1 (NOT_p (CMPGTUrr IntRegs:$lhs, IntRegs:$rhs))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-
-//
-// selectcc mappings for greater-equal-to Rs => greater-than Rs-1.
-//
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETGE)),
- (i32 (MUX_rr (i1 (CMPGTrr IntRegs:$lhs, (ADD_ri IntRegs:$rhs, -1))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETUGE)),
- (i32 (MUX_rr (i1 (CMPGTUrr IntRegs:$lhs, (ADD_ri IntRegs:$rhs, -1))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-
-
-//
-// selectcc mappings for predicate comparisons.
-//
-// Convert Rd = selectcc(p0, p1, true_val, false_val, SETEQ) into:
-// pt = not(p1 xor p2)
-// Rd = mux(pt, true_val, false_val)
-// and similarly for SETNE
-//
-def : Pat <(i32 (selectcc PredRegs:$lhs, PredRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETNE)),
- (i32 (MUX_rr (i1 (XOR_pp PredRegs:$lhs, PredRegs:$rhs)), IntRegs:$tval,
- IntRegs:$fval))>;
-
-def : Pat <(i32 (selectcc PredRegs:$lhs, PredRegs:$rhs, IntRegs:$tval,
- IntRegs:$fval, SETEQ)),
- (i32 (MUX_rr (i1 (NOT_p (XOR_pp PredRegs:$lhs, PredRegs:$rhs))),
- IntRegs:$tval, IntRegs:$fval))>;
-
-
-//
-// selectcc mappings for 64-bit operands are messy. Hexagon does not have a
-// MUX64 o, use this:
-// selectcc(Rss, Rdd, tval, fval, cond) ->
-// combine(mux(cmp_cond(Rss, Rdd), tval.hi, fval.hi),
-// mux(cmp_cond(Rss, Rdd), tval.lo, fval.lo))
-
-// setgt-64.
-def : Pat<(i64 (selectcc DoubleRegs:$lhs, DoubleRegs:$rhs, DoubleRegs:$tval,
- DoubleRegs:$fval, SETGT)),
- (COMBINE_rr (MUX_rr (CMPGT64rr DoubleRegs:$lhs, DoubleRegs:$rhs),
- (EXTRACT_SUBREG DoubleRegs:$tval, subreg_hireg),
- (EXTRACT_SUBREG DoubleRegs:$fval, subreg_hireg)),
- (MUX_rr (CMPGT64rr DoubleRegs:$lhs, DoubleRegs:$rhs),
- (EXTRACT_SUBREG DoubleRegs:$tval, subreg_loreg),
- (EXTRACT_SUBREG DoubleRegs:$fval, subreg_loreg)))>;
-
-
-// setlt-64 -> setgt-64.
-def : Pat<(i64 (selectcc DoubleRegs:$lhs, DoubleRegs:$rhs, DoubleRegs:$tval,
- DoubleRegs:$fval, SETLT)),
- (COMBINE_rr (MUX_rr (CMPGT64rr DoubleRegs:$lhs,
- (ADD64_rr DoubleRegs:$rhs, (TFRI64 -1))),
- (EXTRACT_SUBREG DoubleRegs:$tval, subreg_hireg),
- (EXTRACT_SUBREG DoubleRegs:$fval, subreg_hireg)),
- (MUX_rr (CMPGT64rr DoubleRegs:$lhs,
- (ADD64_rr DoubleRegs:$rhs, (TFRI64 -1))),
- (EXTRACT_SUBREG DoubleRegs:$tval, subreg_loreg),
- (EXTRACT_SUBREG DoubleRegs:$fval, subreg_loreg)))>;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.cpp
index 00dfed7..1073053 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.cpp
@@ -44,14 +44,17 @@ SDValue HexagonSelectionDAGInfo::EmitTargetCodeForMemcpy(
const char *SpecialMemcpyName =
"__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes";
+ const MachineFunction &MF = DAG.getMachineFunction();
+ bool LongCalls = MF.getSubtarget<HexagonSubtarget>().useLongCalls();
+ unsigned Flags = LongCalls ? HexagonII::HMOTF_ConstExtended : 0;
TargetLowering::CallLoweringInfo CLI(DAG);
CLI.setDebugLoc(dl)
.setChain(Chain)
.setCallee(TLI.getLibcallCallingConv(RTLIB::MEMCPY),
Type::getVoidTy(*DAG.getContext()),
- DAG.getTargetExternalSymbol(
- SpecialMemcpyName, TLI.getPointerTy(DAG.getDataLayout())),
+ DAG.getTargetExternalSymbol(SpecialMemcpyName,
+ TLI.getPointerTy(DAG.getDataLayout()), Flags),
std::move(Args))
.setDiscardResult();
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.h b/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.h
index 6f2a42c..a83a8ef 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSelectionDAGInfo.h
@@ -20,6 +20,8 @@ namespace llvm {
class HexagonSelectionDAGInfo : public SelectionDAGTargetInfo {
public:
+ explicit HexagonSelectionDAGInfo() = default;
+
SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, const SDLoc &dl,
SDValue Chain, SDValue Dst, SDValue Src,
SDValue Size, unsigned Align, bool isVolatile,
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSplitConst32AndConst64.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonSplitConst32AndConst64.cpp
index 5a94cce..6848434 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSplitConst32AndConst64.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSplitConst32AndConst64.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// When the compiler is invoked with no small data, for instance, with the -G0
-// command line option, then all CONST32_* opcodes should be broken down into
+// command line option, then all CONST* opcodes should be broken down into
// appropriate LO and HI instructions. This splitting is done by this pass.
// The only reason this is not done in the DAG lowering itself is that there
// is no simple way of getting the register allocator to allot the same hard
@@ -17,24 +17,13 @@
//
//===----------------------------------------------------------------------===//
-#include "HexagonMachineFunctionInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonTargetObjectFile.h"
-#include "llvm/CodeGen/LatencyPriorityQueue.h"
-#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineLoopInfo.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/CodeGen/ScheduleDAGInstrs.h"
-#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
-#include "llvm/CodeGen/SchedulerRegistry.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
@@ -47,28 +36,30 @@ namespace llvm {
}
namespace {
-
-class HexagonSplitConst32AndConst64 : public MachineFunctionPass {
- public:
+ class HexagonSplitConst32AndConst64 : public MachineFunctionPass {
+ public:
static char ID;
- HexagonSplitConst32AndConst64() : MachineFunctionPass(ID) {}
-
- const char *getPassName() const override {
+ HexagonSplitConst32AndConst64() : MachineFunctionPass(ID) {
+ PassRegistry &R = *PassRegistry::getPassRegistry();
+ initializeHexagonSplitConst32AndConst64Pass(R);
+ }
+ StringRef getPassName() const override {
return "Hexagon Split Const32s and Const64s";
}
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
-};
-
+ };
+}
char HexagonSplitConst32AndConst64::ID = 0;
+INITIALIZE_PASS(HexagonSplitConst32AndConst64, "split-const-for-sdata",
+ "Hexagon Split Const32s and Const64s", false, false)
bool HexagonSplitConst32AndConst64::runOnMachineFunction(MachineFunction &Fn) {
-
const HexagonTargetObjectFile &TLOF =
*static_cast<const HexagonTargetObjectFile *>(
Fn.getTarget().getObjFileLowering());
@@ -79,93 +70,46 @@ bool HexagonSplitConst32AndConst64::runOnMachineFunction(MachineFunction &Fn) {
const TargetRegisterInfo *TRI = Fn.getSubtarget().getRegisterInfo();
// Loop over all of the basic blocks
- for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
- MBBb != MBBe; ++MBBb) {
- MachineBasicBlock *MBB = &*MBBb;
- // Traverse the basic block
- MachineBasicBlock::iterator MII = MBB->begin();
- MachineBasicBlock::iterator MIE = MBB->end ();
- while (MII != MIE) {
- MachineInstr &MI = *MII;
- int Opc = MI.getOpcode();
- if (Opc == Hexagon::CONST32_Int_Real &&
- MI.getOperand(1).isBlockAddress()) {
- int DestReg = MI.getOperand(0).getReg();
- MachineOperand &Symbol = MI.getOperand(1);
-
- BuildMI(*MBB, MII, MI.getDebugLoc(), TII->get(Hexagon::LO), DestReg)
- .addOperand(Symbol);
- BuildMI(*MBB, MII, MI.getDebugLoc(), TII->get(Hexagon::HI), DestReg)
- .addOperand(Symbol);
- // MBB->erase returns the iterator to the next instruction, which is the
- // one we want to process next
- MII = MBB->erase(&MI);
- continue;
- }
-
- else if (Opc == Hexagon::CONST32_Int_Real ||
- Opc == Hexagon::CONST32_Float_Real) {
- int DestReg = MI.getOperand(0).getReg();
-
- // We have to convert an FP immediate into its corresponding integer
- // representation
- int64_t ImmValue;
- if (Opc == Hexagon::CONST32_Float_Real) {
- APFloat Val = MI.getOperand(1).getFPImm()->getValueAPF();
- ImmValue = *Val.bitcastToAPInt().getRawData();
- }
- else
- ImmValue = MI.getOperand(1).getImm();
-
- BuildMI(*MBB, MII, MI.getDebugLoc(), TII->get(Hexagon::A2_tfrsi),
- DestReg)
+ for (MachineBasicBlock &B : Fn) {
+ for (auto I = B.begin(), E = B.end(); I != E; ) {
+ MachineInstr &MI = *I;
+ ++I;
+ unsigned Opc = MI.getOpcode();
+
+ if (Opc == Hexagon::CONST32) {
+ unsigned DestReg = MI.getOperand(0).getReg();
+ uint64_t ImmValue = MI.getOperand(1).getImm();
+ const DebugLoc &DL = MI.getDebugLoc();
+ BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), DestReg)
.addImm(ImmValue);
- MII = MBB->erase(&MI);
- continue;
- }
- else if (Opc == Hexagon::CONST64_Int_Real ||
- Opc == Hexagon::CONST64_Float_Real) {
- int DestReg = MI.getOperand(0).getReg();
-
- // We have to convert an FP immediate into its corresponding integer
- // representation
- int64_t ImmValue;
- if (Opc == Hexagon::CONST64_Float_Real) {
- APFloat Val = MI.getOperand(1).getFPImm()->getValueAPF();
- ImmValue = *Val.bitcastToAPInt().getRawData();
- }
- else
- ImmValue = MI.getOperand(1).getImm();
-
- unsigned DestLo = TRI->getSubReg(DestReg, Hexagon::subreg_loreg);
- unsigned DestHi = TRI->getSubReg(DestReg, Hexagon::subreg_hireg);
+ B.erase(&MI);
+ } else if (Opc == Hexagon::CONST64) {
+ unsigned DestReg = MI.getOperand(0).getReg();
+ int64_t ImmValue = MI.getOperand(1).getImm();
+ const DebugLoc &DL = MI.getDebugLoc();
+ unsigned DestLo = TRI->getSubReg(DestReg, Hexagon::isub_lo);
+ unsigned DestHi = TRI->getSubReg(DestReg, Hexagon::isub_hi);
int32_t LowWord = (ImmValue & 0xFFFFFFFF);
int32_t HighWord = (ImmValue >> 32) & 0xFFFFFFFF;
- BuildMI(*MBB, MII, MI.getDebugLoc(), TII->get(Hexagon::A2_tfrsi),
- DestLo)
+ BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), DestLo)
.addImm(LowWord);
- BuildMI(*MBB, MII, MI.getDebugLoc(), TII->get(Hexagon::A2_tfrsi),
- DestHi)
+ BuildMI(B, MI, DL, TII->get(Hexagon::A2_tfrsi), DestHi)
.addImm(HighWord);
- MII = MBB->erase(&MI);
- continue;
+ B.erase(&MI);
}
- ++MII;
}
}
return true;
}
-}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
-FunctionPass *
-llvm::createHexagonSplitConst32AndConst64() {
+FunctionPass *llvm::createHexagonSplitConst32AndConst64() {
return new HexagonSplitConst32AndConst64();
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSplitDouble.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonSplitDouble.cpp
index 25b2aff..2c93721 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSplitDouble.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSplitDouble.cpp
@@ -9,32 +9,50 @@
#define DEBUG_TYPE "hsdr"
+#include "HexagonInstrInfo.h"
#include "HexagonRegisterInfo.h"
-#include "HexagonTargetMachine.h"
-
+#include "HexagonSubtarget.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetRegisterInfo.h"
-
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <limits>
#include <map>
#include <set>
+#include <utility>
#include <vector>
using namespace llvm;
namespace llvm {
+
FunctionPass *createHexagonSplitDoubleRegs();
void initializeHexagonSplitDoubleRegsPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
+
static cl::opt<int> MaxHSDR("max-hsdr", cl::Hidden, cl::init(-1),
cl::desc("Maximum number of split partitions"));
static cl::opt<bool> MemRefsFixed("hsdr-no-mem", cl::Hidden, cl::init(true),
@@ -43,18 +61,22 @@ namespace {
class HexagonSplitDoubleRegs : public MachineFunctionPass {
public:
static char ID;
+
HexagonSplitDoubleRegs() : MachineFunctionPass(ID), TRI(nullptr),
TII(nullptr) {
initializeHexagonSplitDoubleRegsPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
+
+ StringRef getPassName() const override {
return "Hexagon Split Double Registers";
}
+
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineLoopInfo>();
AU.addPreserved<MachineLoopInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
+
bool runOnMachineFunction(MachineFunction &MF) override;
private:
@@ -98,16 +120,17 @@ namespace {
static void dump_partition(raw_ostream&, const USet&,
const TargetRegisterInfo&);
};
+
char HexagonSplitDoubleRegs::ID;
int HexagonSplitDoubleRegs::Counter = 0;
const TargetRegisterClass *const HexagonSplitDoubleRegs::DoubleRC
= &Hexagon::DoubleRegsRegClass;
-}
+
+} // end anonymous namespace
INITIALIZE_PASS(HexagonSplitDoubleRegs, "hexagon-split-double",
"Hexagon Split Double Registers", false, false)
-
void HexagonSplitDoubleRegs::dump_partition(raw_ostream &os,
const USet &Part, const TargetRegisterInfo &TRI) {
dbgs() << '{';
@@ -116,7 +139,6 @@ void HexagonSplitDoubleRegs::dump_partition(raw_ostream &os,
dbgs() << " }";
}
-
bool HexagonSplitDoubleRegs::isInduction(unsigned Reg, LoopRegMap &IRM) const {
for (auto I : IRM) {
const USet &Rs = I.second;
@@ -126,7 +148,6 @@ bool HexagonSplitDoubleRegs::isInduction(unsigned Reg, LoopRegMap &IRM) const {
return false;
}
-
bool HexagonSplitDoubleRegs::isVolatileInstr(const MachineInstr *MI) const {
for (auto &I : MI->memoperands())
if (I->isVolatile())
@@ -134,7 +155,6 @@ bool HexagonSplitDoubleRegs::isVolatileInstr(const MachineInstr *MI) const {
return false;
}
-
bool HexagonSplitDoubleRegs::isFixedInstr(const MachineInstr *MI) const {
if (MI->mayLoad() || MI->mayStore())
if (MemRefsFixed || isVolatileInstr(MI))
@@ -170,7 +190,7 @@ bool HexagonSplitDoubleRegs::isFixedInstr(const MachineInstr *MI) const {
case Hexagon::A4_combineii:
case Hexagon::A4_combineri:
case Hexagon::A2_combinew:
- case Hexagon::CONST64_Int_Real:
+ case Hexagon::CONST64:
case Hexagon::A2_sxtw:
@@ -194,7 +214,6 @@ bool HexagonSplitDoubleRegs::isFixedInstr(const MachineInstr *MI) const {
return false;
}
-
void HexagonSplitDoubleRegs::partitionRegisters(UUSetMap &P2Rs) {
typedef std::map<unsigned,unsigned> UUMap;
typedef std::vector<unsigned> UVect;
@@ -283,7 +302,6 @@ void HexagonSplitDoubleRegs::partitionRegisters(UUSetMap &P2Rs) {
P2Rs[I.second].insert(I.first);
}
-
static inline int32_t profitImm(unsigned Lo, unsigned Hi) {
int32_t P = 0;
bool LoZ1 = false, HiZ1 = false;
@@ -296,7 +314,6 @@ static inline int32_t profitImm(unsigned Lo, unsigned Hi) {
return P;
}
-
int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const {
unsigned ImmX = 0;
unsigned Opc = MI->getOpcode();
@@ -319,7 +336,7 @@ int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const {
return 2;
case Hexagon::A2_tfrpi:
- case Hexagon::CONST64_Int_Real: {
+ case Hexagon::CONST64: {
uint64_t D = MI->getOperand(1).getImm();
unsigned Lo = D & 0xFFFFFFFFULL;
unsigned Hi = D >> 32;
@@ -337,6 +354,7 @@ int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const {
if (V == 0 || V == -1)
return 10;
// Fall through into A2_combinew.
+ LLVM_FALLTHROUGH;
}
case Hexagon::A2_combinew:
return 2;
@@ -371,7 +389,6 @@ int32_t HexagonSplitDoubleRegs::profit(const MachineInstr *MI) const {
return 0;
}
-
bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM)
const {
unsigned FixedNum = 0, SplitNum = 0, LoopPhiNum = 0;
@@ -380,7 +397,7 @@ bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM)
for (unsigned DR : Part) {
MachineInstr *DefI = MRI->getVRegDef(DR);
int32_t P = profit(DefI);
- if (P == INT_MIN)
+ if (P == std::numeric_limits<int>::min())
return false;
TotalP += P;
// Reduce the profitability of splitting induction registers.
@@ -413,7 +430,7 @@ bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM)
// Splittable instruction.
SplitNum++;
int32_t P = profit(UseI);
- if (P == INT_MIN)
+ if (P == std::numeric_limits<int>::min())
return false;
TotalP += P;
}
@@ -426,7 +443,6 @@ bool HexagonSplitDoubleRegs::isProfitable(const USet &Part, LoopRegMap &IRM)
return TotalP > 0;
}
-
void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L,
USet &Rs) {
const MachineBasicBlock *HB = L->getHeader();
@@ -436,11 +452,11 @@ void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L,
// Examine the latch branch. Expect it to be a conditional branch to
// the header (either "br-cond header" or "br-cond exit; br header").
- MachineBasicBlock *TB = 0, *FB = 0;
+ MachineBasicBlock *TB = nullptr, *FB = nullptr;
MachineBasicBlock *TmpLB = const_cast<MachineBasicBlock*>(LB);
SmallVector<MachineOperand,2> Cond;
bool BadLB = TII->analyzeBranch(*TmpLB, TB, FB, Cond, false);
- // Only analyzable conditional branches. HII::AnalyzeBranch will put
+ // Only analyzable conditional branches. HII::analyzeBranch will put
// the branch opcode as the first element of Cond, and the predicate
// operand as the second.
if (BadLB || Cond.size() != 2)
@@ -451,7 +467,7 @@ void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L,
// Must go to the header.
if (TB != HB && FB != HB)
return;
- assert(Cond[1].isReg() && "Unexpected Cond vector from AnalyzeBranch");
+ assert(Cond[1].isReg() && "Unexpected Cond vector from analyzeBranch");
// Expect a predicate register.
unsigned PR = Cond[1].getReg();
assert(MRI->getRegClass(PR) == &Hexagon::PredRegsRegClass);
@@ -510,7 +526,7 @@ void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L,
}
return true;
};
- UVect::iterator End = std::remove_if(DP.begin(), DP.end(), NoIndOp);
+ UVect::iterator End = llvm::remove_if(DP, NoIndOp);
Rs.insert(DP.begin(), End);
Rs.insert(CmpR1);
Rs.insert(CmpR2);
@@ -522,7 +538,6 @@ void HexagonSplitDoubleRegs::collectIndRegsForLoop(const MachineLoop *L,
});
}
-
void HexagonSplitDoubleRegs::collectIndRegs(LoopRegMap &IRM) {
typedef std::vector<MachineLoop*> LoopVector;
LoopVector WorkQ;
@@ -544,7 +559,6 @@ void HexagonSplitDoubleRegs::collectIndRegs(LoopRegMap &IRM) {
}
}
-
void HexagonSplitDoubleRegs::createHalfInstr(unsigned Opc, MachineInstr *MI,
const UUPairMap &PairMap, unsigned SubR) {
MachineBasicBlock &B = *MI->getParent();
@@ -568,7 +582,7 @@ void HexagonSplitDoubleRegs::createHalfInstr(unsigned Opc, MachineInstr *MI,
SR = SubR;
} else {
const UUPair &P = F->second;
- R = (SubR == Hexagon::subreg_loreg) ? P.first : P.second;
+ R = (SubR == Hexagon::isub_lo) ? P.first : P.second;
SR = 0;
}
}
@@ -579,7 +593,6 @@ void HexagonSplitDoubleRegs::createHalfInstr(unsigned Opc, MachineInstr *MI,
}
}
-
void HexagonSplitDoubleRegs::splitMemRef(MachineInstr *MI,
const UUPairMap &PairMap) {
bool Load = MI->mayLoad();
@@ -652,7 +665,6 @@ void HexagonSplitDoubleRegs::splitMemRef(MachineInstr *MI,
}
}
-
void HexagonSplitDoubleRegs::splitImmediate(MachineInstr *MI,
const UUPairMap &PairMap) {
MachineOperand &Op0 = MI->getOperand(0);
@@ -680,7 +692,6 @@ void HexagonSplitDoubleRegs::splitImmediate(MachineInstr *MI,
.addImm(int32_t(V >> 32));
}
-
void HexagonSplitDoubleRegs::splitCombine(MachineInstr *MI,
const UUPairMap &PairMap) {
MachineOperand &Op0 = MI->getOperand(0);
@@ -713,7 +724,6 @@ void HexagonSplitDoubleRegs::splitCombine(MachineInstr *MI,
llvm_unreachable("Unexpected operand");
}
-
void HexagonSplitDoubleRegs::splitExt(MachineInstr *MI,
const UUPairMap &PairMap) {
MachineOperand &Op0 = MI->getOperand(0);
@@ -734,9 +744,10 @@ void HexagonSplitDoubleRegs::splitExt(MachineInstr *MI,
.addImm(31);
}
-
void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI,
const UUPairMap &PairMap) {
+ using namespace Hexagon;
+
MachineOperand &Op0 = MI->getOperand(0);
MachineOperand &Op1 = MI->getOperand(1);
MachineOperand &Op2 = MI->getOperand(2);
@@ -750,7 +761,6 @@ void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI,
const UUPair &P = F->second;
unsigned LoR = P.first;
unsigned HiR = P.second;
- using namespace Hexagon;
unsigned Opc = MI->getOpcode();
bool Right = (Opc == S2_lsr_i_p || Opc == S2_asr_i_p);
@@ -762,8 +772,8 @@ void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI,
unsigned RS = getRegState(Op1);
unsigned ShiftOpc = Left ? S2_asl_i_r
: (Signed ? S2_asr_i_r : S2_lsr_i_r);
- unsigned LoSR = subreg_loreg;
- unsigned HiSR = subreg_hireg;
+ unsigned LoSR = isub_lo;
+ unsigned HiSR = isub_hi;
if (S == 0) {
// No shift, subregister copy.
@@ -858,9 +868,10 @@ void HexagonSplitDoubleRegs::splitShift(MachineInstr *MI,
}
}
-
void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI,
const UUPairMap &PairMap) {
+ using namespace Hexagon;
+
MachineOperand &Op0 = MI->getOperand(0);
MachineOperand &Op1 = MI->getOperand(1);
MachineOperand &Op2 = MI->getOperand(2);
@@ -875,7 +886,6 @@ void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI,
const UUPair &P = F->second;
unsigned LoR = P.first;
unsigned HiR = P.second;
- using namespace Hexagon;
MachineBasicBlock &B = *MI->getParent();
DebugLoc DL = MI->getDebugLoc();
@@ -883,8 +893,8 @@ void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI,
unsigned RS2 = getRegState(Op2);
const TargetRegisterClass *IntRC = &IntRegsRegClass;
- unsigned LoSR = subreg_loreg;
- unsigned HiSR = subreg_hireg;
+ unsigned LoSR = isub_lo;
+ unsigned HiSR = isub_hi;
// Op0 = S2_asl_i_p_or Op1, Op2, Op3
// means: Op0 = or (Op1, asl(Op2, Op3))
@@ -951,38 +961,38 @@ void HexagonSplitDoubleRegs::splitAslOr(MachineInstr *MI,
}
}
-
bool HexagonSplitDoubleRegs::splitInstr(MachineInstr *MI,
const UUPairMap &PairMap) {
+ using namespace Hexagon;
+
DEBUG(dbgs() << "Splitting: " << *MI);
bool Split = false;
unsigned Opc = MI->getOpcode();
- using namespace Hexagon;
switch (Opc) {
case TargetOpcode::PHI:
case TargetOpcode::COPY: {
unsigned DstR = MI->getOperand(0).getReg();
if (MRI->getRegClass(DstR) == DoubleRC) {
- createHalfInstr(Opc, MI, PairMap, subreg_loreg);
- createHalfInstr(Opc, MI, PairMap, subreg_hireg);
+ createHalfInstr(Opc, MI, PairMap, isub_lo);
+ createHalfInstr(Opc, MI, PairMap, isub_hi);
Split = true;
}
break;
}
case A2_andp:
- createHalfInstr(A2_and, MI, PairMap, subreg_loreg);
- createHalfInstr(A2_and, MI, PairMap, subreg_hireg);
+ createHalfInstr(A2_and, MI, PairMap, isub_lo);
+ createHalfInstr(A2_and, MI, PairMap, isub_hi);
Split = true;
break;
case A2_orp:
- createHalfInstr(A2_or, MI, PairMap, subreg_loreg);
- createHalfInstr(A2_or, MI, PairMap, subreg_hireg);
+ createHalfInstr(A2_or, MI, PairMap, isub_lo);
+ createHalfInstr(A2_or, MI, PairMap, isub_hi);
Split = true;
break;
case A2_xorp:
- createHalfInstr(A2_xor, MI, PairMap, subreg_loreg);
- createHalfInstr(A2_xor, MI, PairMap, subreg_hireg);
+ createHalfInstr(A2_xor, MI, PairMap, isub_lo);
+ createHalfInstr(A2_xor, MI, PairMap, isub_hi);
Split = true;
break;
@@ -995,7 +1005,7 @@ bool HexagonSplitDoubleRegs::splitInstr(MachineInstr *MI,
break;
case A2_tfrpi:
- case CONST64_Int_Real:
+ case CONST64:
splitImmediate(MI, PairMap);
Split = true;
break;
@@ -1034,7 +1044,6 @@ bool HexagonSplitDoubleRegs::splitInstr(MachineInstr *MI,
return Split;
}
-
void HexagonSplitDoubleRegs::replaceSubregUses(MachineInstr *MI,
const UUPairMap &PairMap) {
for (auto &Op : MI->operands()) {
@@ -1046,10 +1055,10 @@ void HexagonSplitDoubleRegs::replaceSubregUses(MachineInstr *MI,
continue;
const UUPair &P = F->second;
switch (Op.getSubReg()) {
- case Hexagon::subreg_loreg:
+ case Hexagon::isub_lo:
Op.setReg(P.first);
break;
- case Hexagon::subreg_hireg:
+ case Hexagon::isub_hi:
Op.setReg(P.second);
break;
}
@@ -1057,7 +1066,6 @@ void HexagonSplitDoubleRegs::replaceSubregUses(MachineInstr *MI,
}
}
-
void HexagonSplitDoubleRegs::collapseRegPairs(MachineInstr *MI,
const UUPairMap &PairMap) {
MachineBasicBlock &B = *MI->getParent();
@@ -1078,14 +1086,13 @@ void HexagonSplitDoubleRegs::collapseRegPairs(MachineInstr *MI,
unsigned NewDR = MRI->createVirtualRegister(DoubleRC);
BuildMI(B, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), NewDR)
.addReg(Pr.first)
- .addImm(Hexagon::subreg_loreg)
+ .addImm(Hexagon::isub_lo)
.addReg(Pr.second)
- .addImm(Hexagon::subreg_hireg);
+ .addImm(Hexagon::isub_hi);
Op.setReg(NewDR);
}
}
-
bool HexagonSplitDoubleRegs::splitPartition(const USet &Part) {
const TargetRegisterClass *IntRC = &Hexagon::IntRegsRegClass;
typedef std::set<MachineInstr*> MISet;
@@ -1146,7 +1153,6 @@ bool HexagonSplitDoubleRegs::splitPartition(const USet &Part) {
return Changed;
}
-
bool HexagonSplitDoubleRegs::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Splitting double registers in function: "
<< MF.getName() << '\n');
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonStoreWidening.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonStoreWidening.cpp
index 54bc3cf..af1bf48 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonStoreWidening.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonStoreWidening.cpp
@@ -23,33 +23,45 @@
#define DEBUG_TYPE "hexagon-widen-stores"
-#include "HexagonTargetMachine.h"
-
-#include "llvm/PassSupport.h"
+#include "HexagonInstrInfo.h"
+#include "HexagonRegisterInfo.h"
+#include "HexagonSubtarget.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/AliasAnalysis.h"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/Analysis/MemoryLocation.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegisterInfo.h"
-#include "llvm/Target/TargetInstrInfo.h"
-
#include <algorithm>
-
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <vector>
using namespace llvm;
namespace llvm {
+
FunctionPass *createHexagonStoreWidening();
void initializeHexagonStoreWideningPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
+
struct HexagonStoreWidening : public MachineFunctionPass {
const HexagonInstrInfo *TII;
const HexagonRegisterInfo *TRI;
@@ -59,15 +71,14 @@ namespace {
public:
static char ID;
+
HexagonStoreWidening() : MachineFunctionPass(ID) {
initializeHexagonStoreWideningPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "Hexagon Store Widening";
- }
+ StringRef getPassName() const override { return "Hexagon Store Widening"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<AAResultsWrapperPass>();
@@ -98,19 +109,18 @@ namespace {
bool storesAreAdjacent(const MachineInstr *S1, const MachineInstr *S2);
};
-} // namespace
-
+char HexagonStoreWidening::ID = 0;
-namespace {
+} // end anonymous namespace
// Some local helper functions...
-unsigned getBaseAddressRegister(const MachineInstr *MI) {
+static unsigned getBaseAddressRegister(const MachineInstr *MI) {
const MachineOperand &MO = MI->getOperand(0);
assert(MO.isReg() && "Expecting register operand");
return MO.getReg();
}
-int64_t getStoreOffset(const MachineInstr *MI) {
+static int64_t getStoreOffset(const MachineInstr *MI) {
unsigned OpC = MI->getOpcode();
assert(HexagonStoreWidening::handledStoreType(MI) && "Unhandled opcode");
@@ -128,23 +138,17 @@ int64_t getStoreOffset(const MachineInstr *MI) {
return 0;
}
-const MachineMemOperand &getStoreTarget(const MachineInstr *MI) {
+static const MachineMemOperand &getStoreTarget(const MachineInstr *MI) {
assert(!MI->memoperands_empty() && "Expecting memory operands");
return **MI->memoperands_begin();
}
-} // namespace
-
-
-char HexagonStoreWidening::ID = 0;
-
INITIALIZE_PASS_BEGIN(HexagonStoreWidening, "hexagon-widen-stores",
"Hexason Store Widening", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(HexagonStoreWidening, "hexagon-widen-stores",
"Hexagon Store Widening", false, false)
-
// Filtering function: any stores whose opcodes are not "approved" of by
// this function will not be subjected to widening.
inline bool HexagonStoreWidening::handledStoreType(const MachineInstr *MI) {
@@ -162,7 +166,6 @@ inline bool HexagonStoreWidening::handledStoreType(const MachineInstr *MI) {
}
}
-
// Check if the machine memory operand MMO is aliased with any of the
// stores in the store group Stores.
bool HexagonStoreWidening::instrAliased(InstrGroup &Stores,
@@ -185,7 +188,6 @@ bool HexagonStoreWidening::instrAliased(InstrGroup &Stores,
return false;
}
-
// Check if the machine instruction MI accesses any storage aliased with
// any store in the group Stores.
bool HexagonStoreWidening::instrAliased(InstrGroup &Stores,
@@ -196,7 +198,6 @@ bool HexagonStoreWidening::instrAliased(InstrGroup &Stores,
return false;
}
-
// Inspect a machine basic block, and generate store groups out of stores
// encountered in the block.
//
@@ -233,7 +234,6 @@ void HexagonStoreWidening::createStoreGroups(MachineBasicBlock &MBB,
}
}
-
// Create a single store group. The stores need to be independent between
// themselves, and also there cannot be other instructions between them
// that could read or modify storage being stored into.
@@ -263,7 +263,7 @@ void HexagonStoreWidening::createStoreGroup(MachineInstr *BaseStore,
unsigned BR = getBaseAddressRegister(MI);
if (BR == BaseReg) {
Group.push_back(MI);
- *I = 0;
+ *I = nullptr;
continue;
}
}
@@ -280,7 +280,6 @@ void HexagonStoreWidening::createStoreGroup(MachineInstr *BaseStore,
} // for
}
-
// Check if store instructions S1 and S2 are adjacent. More precisely,
// S2 has to access memory immediately following that accessed by S1.
bool HexagonStoreWidening::storesAreAdjacent(const MachineInstr *S1,
@@ -298,7 +297,6 @@ bool HexagonStoreWidening::storesAreAdjacent(const MachineInstr *S1,
: int(Off1+S1MO.getSize()) == Off2;
}
-
/// Given a sequence of adjacent stores, and a maximum size of a single wide
/// store, pick a group of stores that can be replaced by a single store
/// of size not exceeding MaxSize. The selected sequence will be recorded
@@ -390,7 +388,6 @@ bool HexagonStoreWidening::selectStores(InstrGroup::iterator Begin,
return true;
}
-
/// Given an "old group" OG of stores, create a "new group" NG of instructions
/// to replace them. Ideally, NG would only have a single instruction in it,
/// but that may only be possible for store-immediate.
@@ -419,7 +416,6 @@ bool HexagonStoreWidening::createWideStores(InstrGroup &OG, InstrGroup &NG,
Shift += NBits;
}
-
MachineInstr *FirstSt = OG.front();
DebugLoc DL = OG.back()->getDebugLoc();
const MachineMemOperand &OldM = getStoreTarget(FirstSt);
@@ -471,7 +467,6 @@ bool HexagonStoreWidening::createWideStores(InstrGroup &OG, InstrGroup &NG,
return true;
}
-
// Replace instructions from the old group OG with instructions from the
// new group NG. Conceptually, remove all instructions in OG, and then
// insert all instructions in NG, starting at where the first instruction
@@ -536,7 +531,6 @@ bool HexagonStoreWidening::replaceStores(InstrGroup &OG, InstrGroup &NG) {
return true;
}
-
// Break up the group into smaller groups, each of which can be replaced by
// a single wide store. Widen each such smaller group and replace the old
// instructions with the widened ones.
@@ -566,7 +560,6 @@ bool HexagonStoreWidening::processStoreGroup(InstrGroup &Group) {
return Changed;
}
-
// Process a single basic block: create the store groups, and replace them
// with the widened stores, if possible. Processing of each basic block
// is independent from processing of any other basic block. This transfor-
@@ -592,7 +585,6 @@ bool HexagonStoreWidening::processBasicBlock(MachineBasicBlock &MBB) {
return Changed;
}
-
bool HexagonStoreWidening::runOnMachineFunction(MachineFunction &MFn) {
if (skipFunction(*MFn.getFunction()))
return false;
@@ -612,8 +604,6 @@ bool HexagonStoreWidening::runOnMachineFunction(MachineFunction &MFn) {
return Changed;
}
-
FunctionPass *llvm::createHexagonStoreWidening() {
return new HexagonStoreWidening();
}
-
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
index fb315a7..8c23a24 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
@@ -66,9 +66,13 @@ static cl::opt<bool> DisableHexagonMISched("disable-hexagon-misched",
cl::desc("Disable Hexagon MI Scheduling"));
static cl::opt<bool> EnableSubregLiveness("hexagon-subreg-liveness",
- cl::Hidden, cl::ZeroOrMore, cl::init(false),
+ cl::Hidden, cl::ZeroOrMore, cl::init(true),
cl::desc("Enable subregister liveness tracking for Hexagon"));
+static cl::opt<bool> OverrideLongCalls("hexagon-long-calls",
+ cl::Hidden, cl::ZeroOrMore, cl::init(false),
+ cl::desc("If present, forces/disables the use of long calls"));
+
void HexagonSubtarget::initializeEnvironment() {
UseMemOps = false;
ModeIEEERndNear = false;
@@ -77,7 +81,7 @@ void HexagonSubtarget::initializeEnvironment() {
HexagonSubtarget &
HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
- CPUString = HEXAGON_MC::selectHexagonCPU(getTargetTriple(), CPU);
+ CPUString = Hexagon_MC::selectHexagonCPU(getTargetTriple(), CPU);
static std::map<StringRef, HexagonArchEnum> CpuTable {
{ "hexagonv4", V4 },
@@ -94,12 +98,15 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
UseHVXOps = false;
UseHVXDblOps = false;
+ UseLongCalls = false;
ParseSubtargetFeatures(CPUString, FS);
if (EnableHexagonHVX.getPosition())
UseHVXOps = EnableHexagonHVX;
if (EnableHexagonHVXDouble.getPosition())
UseHVXDblOps = EnableHexagonHVXDouble;
+ if (OverrideLongCalls.getPosition())
+ UseLongCalls = OverrideLongCalls;
return *this;
}
@@ -148,19 +155,19 @@ void HexagonSubtarget::HexagonDAGMutation::apply(ScheduleDAGInstrs *DAG) {
// Update the latency of chain edges between v60 vector load or store
// instructions to be 1. These instructions cannot be scheduled in the
// same packet.
- MachineInstr *MI1 = SU.getInstr();
+ MachineInstr &MI1 = *SU.getInstr();
auto *QII = static_cast<const HexagonInstrInfo*>(DAG->TII);
- bool IsStoreMI1 = MI1->mayStore();
- bool IsLoadMI1 = MI1->mayLoad();
+ bool IsStoreMI1 = MI1.mayStore();
+ bool IsLoadMI1 = MI1.mayLoad();
if (!QII->isV60VectorInstruction(MI1) || !(IsStoreMI1 || IsLoadMI1))
continue;
for (auto &SI : SU.Succs) {
if (SI.getKind() != SDep::Order || SI.getLatency() != 0)
continue;
- MachineInstr *MI2 = SI.getSUnit()->getInstr();
+ MachineInstr &MI2 = *SI.getSUnit()->getInstr();
if (!QII->isV60VectorInstruction(MI2))
continue;
- if ((IsStoreMI1 && MI2->mayStore()) || (IsLoadMI1 && MI2->mayLoad())) {
+ if ((IsStoreMI1 && MI2.mayStore()) || (IsLoadMI1 && MI2.mayLoad())) {
SI.setLatency(1);
SU.setHeightDirty();
// Change the dependence in the opposite direction too.
@@ -181,6 +188,11 @@ void HexagonSubtarget::getPostRAMutations(
Mutations.push_back(make_unique<HexagonSubtarget::HexagonDAGMutation>());
}
+void HexagonSubtarget::getSMSMutations(
+ std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const {
+ Mutations.push_back(make_unique<HexagonSubtarget::HexagonDAGMutation>());
+}
+
// Pin the vtable to this file.
void HexagonSubtarget::anchor() {}
@@ -196,8 +208,8 @@ bool HexagonSubtarget::enableSubRegLiveness() const {
}
// This helper function is responsible for increasing the latency only.
-void HexagonSubtarget::updateLatency(MachineInstr *SrcInst,
- MachineInstr *DstInst, SDep &Dep) const {
+void HexagonSubtarget::updateLatency(MachineInstr &SrcInst,
+ MachineInstr &DstInst, SDep &Dep) const {
if (!hasV60TOps())
return;
@@ -231,19 +243,19 @@ static SUnit *getZeroLatency(SUnit *N, SmallVector<SDep, 4> &Deps) {
/// Change the latency between the two SUnits.
void HexagonSubtarget::changeLatency(SUnit *Src, SmallVector<SDep, 4> &Deps,
SUnit *Dst, unsigned Lat) const {
- MachineInstr *SrcI = Src->getInstr();
+ MachineInstr &SrcI = *Src->getInstr();
for (auto &I : Deps) {
if (I.getSUnit() != Dst)
continue;
I.setLatency(Lat);
SUnit *UpdateDst = I.getSUnit();
- updateLatency(SrcI, UpdateDst->getInstr(), I);
+ updateLatency(SrcI, *UpdateDst->getInstr(), I);
// Update the latency of opposite edge too.
for (auto &PI : UpdateDst->Preds) {
if (PI.getSUnit() != Src || !PI.isAssignedRegDep())
continue;
PI.setLatency(Lat);
- updateLatency(SrcI, UpdateDst->getInstr(), PI);
+ updateLatency(SrcI, *UpdateDst->getInstr(), PI);
}
}
}
@@ -254,10 +266,14 @@ void HexagonSubtarget::changeLatency(SUnit *Src, SmallVector<SDep, 4> &Deps,
// ther others, if needed.
bool HexagonSubtarget::isBestZeroLatency(SUnit *Src, SUnit *Dst,
const HexagonInstrInfo *TII) const {
- MachineInstr *SrcInst = Src->getInstr();
- MachineInstr *DstInst = Dst->getInstr();
+ MachineInstr &SrcInst = *Src->getInstr();
+ MachineInstr &DstInst = *Dst->getInstr();
+
+ // Ignore Boundary SU nodes as these have null instructions.
+ if (Dst->isBoundaryNode())
+ return false;
- if (SrcInst->isPHI() || DstInst->isPHI())
+ if (SrcInst.isPHI() || DstInst.isPHI())
return false;
// Check if the Dst instruction is the best candidate first.
@@ -294,9 +310,9 @@ bool HexagonSubtarget::isBestZeroLatency(SUnit *Src, SUnit *Dst,
// Update the latency of a Phi when the Phi bridges two instructions that
// require a multi-cycle latency.
-void HexagonSubtarget::changePhiLatency(MachineInstr *SrcInst, SUnit *Dst,
+void HexagonSubtarget::changePhiLatency(MachineInstr &SrcInst, SUnit *Dst,
SDep &Dep) const {
- if (!SrcInst->isPHI() || Dst->NumPreds == 0 || Dep.getLatency() != 0)
+ if (!SrcInst.isPHI() || Dst->NumPreds == 0 || Dep.getLatency() != 0)
return;
for (const SDep &PI : Dst->Preds) {
@@ -319,7 +335,7 @@ void HexagonSubtarget::adjustSchedDependency(SUnit *Src, SUnit *Dst,
const HexagonInstrInfo *QII = static_cast<const HexagonInstrInfo *>(getInstrInfo());
// Instructions with .new operands have zero latency.
- if (QII->canExecuteInBundle(SrcInst, DstInst) &&
+ if (QII->canExecuteInBundle(*SrcInst, *DstInst) &&
isBestZeroLatency(Src, Dst, QII)) {
Dep.setLatency(0);
return;
@@ -329,17 +345,17 @@ void HexagonSubtarget::adjustSchedDependency(SUnit *Src, SUnit *Dst,
return;
// Don't adjust the latency of post-increment part of the instruction.
- if (QII->isPostIncrement(SrcInst) && Dep.isAssignedRegDep()) {
+ if (QII->isPostIncrement(*SrcInst) && Dep.isAssignedRegDep()) {
if (SrcInst->mayStore())
return;
if (Dep.getReg() != SrcInst->getOperand(0).getReg())
return;
- } else if (QII->isPostIncrement(DstInst) && Dep.getKind() == SDep::Anti) {
+ } else if (QII->isPostIncrement(*DstInst) && Dep.getKind() == SDep::Anti) {
if (DstInst->mayStore())
return;
if (Dep.getReg() != DstInst->getOperand(0).getReg())
return;
- } else if (QII->isPostIncrement(DstInst) && DstInst->mayStore() &&
+ } else if (QII->isPostIncrement(*DstInst) && DstInst->mayStore() &&
Dep.isAssignedRegDep()) {
MachineOperand &Op = DstInst->getOperand(DstInst->getNumOperands() - 1);
if (Op.isReg() && Dep.getReg() != Op.getReg())
@@ -348,7 +364,7 @@ void HexagonSubtarget::adjustSchedDependency(SUnit *Src, SUnit *Dst,
// Check if we need to change any the latency values when Phis are added.
if (useBSBScheduling() && SrcInst->isPHI()) {
- changePhiLatency(SrcInst, Dst, Dep);
+ changePhiLatency(*SrcInst, Dst, Dep);
return;
}
@@ -358,12 +374,20 @@ void HexagonSubtarget::adjustSchedDependency(SUnit *Src, SUnit *Dst,
DstInst = Dst->Succs[0].getSUnit()->getInstr();
// Try to schedule uses near definitions to generate .cur.
- if (EnableDotCurSched && QII->isToBeScheduledASAP(SrcInst, DstInst) &&
+ if (EnableDotCurSched && QII->isToBeScheduledASAP(*SrcInst, *DstInst) &&
isBestZeroLatency(Src, Dst, QII)) {
Dep.setLatency(0);
return;
}
- updateLatency(SrcInst, DstInst, Dep);
+ updateLatency(*SrcInst, *DstInst, Dep);
+}
+
+unsigned HexagonSubtarget::getL1CacheLineSize() const {
+ return 32;
+}
+
+unsigned HexagonSubtarget::getL1PrefetchDistance() const {
+ return 32;
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h
index 9b40c13..f2b9cda 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h
@@ -34,6 +34,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo {
virtual void anchor();
bool UseMemOps, UseHVXOps, UseHVXDblOps;
+ bool UseLongCalls;
bool ModeIEEERndNear;
public:
@@ -101,6 +102,7 @@ public:
bool useHVXOps() const { return UseHVXOps; }
bool useHVXDblOps() const { return UseHVXOps && UseHVXDblOps; }
bool useHVXSglOps() const { return UseHVXOps && !UseHVXDblOps; }
+ bool useLongCalls() const { return UseLongCalls; }
bool useBSBScheduling() const { return UseBSBScheduling; }
bool enableMachineScheduler() const override;
@@ -128,19 +130,26 @@ public:
std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations)
const override;
+ void getSMSMutations(
+ std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations)
+ const override;
+
/// \brief Perform target specific adjustments to the latency of a schedule
/// dependency.
void adjustSchedDependency(SUnit *def, SUnit *use, SDep& dep) const override;
+ unsigned getL1CacheLineSize() const;
+ unsigned getL1PrefetchDistance() const;
+
private:
// Helper function responsible for increasing the latency only.
- void updateLatency(MachineInstr *SrcInst, MachineInstr *DstInst, SDep &Dep)
+ void updateLatency(MachineInstr &SrcInst, MachineInstr &DstInst, SDep &Dep)
const;
void changeLatency(SUnit *Src, SmallVector<SDep, 4> &Deps, SUnit *Dst,
unsigned Lat) const;
bool isBestZeroLatency(SUnit *Src, SUnit *Dst, const HexagonInstrInfo *TII)
const;
- void changePhiLatency(MachineInstr *SrcInst, SUnit *Dst, SDep &Dep) const;
+ void changePhiLatency(MachineInstr &SrcInst, SUnit *Dst, SDep &Dep) const;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSystemInst.td b/contrib/llvm/lib/Target/Hexagon/HexagonSystemInst.td
index 771498a..629a987 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonSystemInst.td
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonSystemInst.td
@@ -118,7 +118,7 @@ def Y2_isync: JRInst <(outs), (ins),
let hasSideEffects = 0, isSolo = 1 in
class J2_MISC_TRAP_PAUSE<string mnemonic, bits<2> MajOp>
: JRInst
- <(outs), (ins u8Imm:$u8),
+ <(outs), (ins u8_0Imm:$u8),
#mnemonic#"(#$u8)"> {
bits<8> u8;
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
index f964a66..132d12a 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -27,7 +27,6 @@
using namespace llvm;
-
static cl::opt<bool> EnableRDFOpt("rdf-opt", cl::Hidden, cl::ZeroOrMore,
cl::init(true), cl::desc("Enable RDF-based optimizations"));
@@ -42,6 +41,9 @@ static cl::opt<bool> DisableHexagonCFGOpt("disable-hexagon-cfgopt",
cl::Hidden, cl::ZeroOrMore, cl::init(false),
cl::desc("Disable Hexagon CFG Optimization"));
+static cl::opt<bool> DisableHCP("disable-hcp", cl::init(false), cl::Hidden,
+ cl::ZeroOrMore, cl::desc("Disable Hexagon constant propagation"));
+
static cl::opt<bool> DisableStoreWidening("disable-store-widen",
cl::Hidden, cl::init(false), cl::desc("Disable store widening"));
@@ -68,6 +70,10 @@ static cl::opt<bool> EnableGenPred("hexagon-gen-pred", cl::init(true),
cl::Hidden, cl::desc("Enable conversion of arithmetic operations to "
"predicate instructions"));
+static cl::opt<bool> EnableLoopPrefetch("hexagon-loop-prefetch",
+ cl::init(false), cl::Hidden, cl::ZeroOrMore,
+ cl::desc("Enable loop data prefetch on Hexagon"));
+
static cl::opt<bool> DisableHSDR("disable-hsdr", cl::init(false), cl::Hidden,
cl::desc("Disable splitting double registers"));
@@ -80,6 +86,10 @@ static cl::opt<bool> EnableLoopResched("hexagon-loop-resched", cl::init(true),
static cl::opt<bool> HexagonNoOpt("hexagon-noopt", cl::init(false),
cl::Hidden, cl::desc("Disable backend optimizations"));
+static cl::opt<bool> EnableVectorPrint("enable-hexagon-vector-print",
+ cl::Hidden, cl::ZeroOrMore, cl::init(false),
+ cl::desc("Enable Hexagon Vector print instr pass"));
+
/// HexagonTargetMachineModule - Note that this is used on hosts that
/// cannot link in a library unless there are references into the
/// library. In particular, it seems that it is not possible to get
@@ -90,7 +100,7 @@ int HexagonTargetMachineModule = 0;
extern "C" void LLVMInitializeHexagonTarget() {
// Register the target.
- RegisterTargetMachine<HexagonTargetMachine> X(TheHexagonTarget);
+ RegisterTargetMachine<HexagonTargetMachine> X(getTheHexagonTarget());
}
static ScheduleDAGInstrs *createVLIWMachineSched(MachineSchedContext *C) {
@@ -102,14 +112,17 @@ SchedCustomRegistry("hexagon", "Run Hexagon's custom scheduler",
createVLIWMachineSched);
namespace llvm {
+ extern char &HexagonExpandCondsetsID;
+ void initializeHexagonExpandCondsetsPass(PassRegistry&);
+
FunctionPass *createHexagonBitSimplify();
FunctionPass *createHexagonBranchRelaxation();
FunctionPass *createHexagonCallFrameInformation();
FunctionPass *createHexagonCFGOptimizer();
FunctionPass *createHexagonCommonGEP();
+ FunctionPass *createHexagonConstPropagationPass();
FunctionPass *createHexagonCopyToCombine();
FunctionPass *createHexagonEarlyIfConversion();
- FunctionPass *createHexagonExpandCondsets();
FunctionPass *createHexagonFixupHwLoops();
FunctionPass *createHexagonGenExtract();
FunctionPass *createHexagonGenInsert();
@@ -128,6 +141,7 @@ namespace llvm {
FunctionPass *createHexagonSplitConst32AndConst64();
FunctionPass *createHexagonSplitDoubleRegs();
FunctionPass *createHexagonStoreWidening();
+ FunctionPass *createHexagonVectorPrint();
} // end namespace llvm;
static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
@@ -152,6 +166,7 @@ HexagonTargetMachine::HexagonTargetMachine(const Target &T, const Triple &TT,
TT, CPU, FS, Options, getEffectiveRelocModel(RM), CM,
(HexagonNoOpt ? CodeGenOpt::None : OL)),
TLOF(make_unique<HexagonTargetObjectFile>()) {
+ initializeHexagonExpandCondsetsPass(*PassRegistry::getPassRegistry());
initAsmInfo();
}
@@ -225,6 +240,8 @@ void HexagonPassConfig::addIRPasses() {
addPass(createAtomicExpandPass(TM));
if (!NoOpt) {
+ if (EnableLoopPrefetch)
+ addPass(createLoopDataPrefetchPass());
if (EnableCommGEP)
addPass(createHexagonCommonGEP());
// Replace certain combinations of shifts and ands with extracts.
@@ -257,6 +274,11 @@ bool HexagonPassConfig::addInstSelector() {
addPass(createHexagonBitSimplify(), false);
addPass(createHexagonPeephole());
printAndVerify("After hexagon peephole pass");
+ // Constant propagation.
+ if (!DisableHCP) {
+ addPass(createHexagonConstPropagationPass(), false);
+ addPass(&UnreachableMachineBlockElimID, false);
+ }
if (EnableGenInsert)
addPass(createHexagonGenInsert(), false);
if (EnableEarlyIf)
@@ -268,15 +290,15 @@ bool HexagonPassConfig::addInstSelector() {
void HexagonPassConfig::addPreRegAlloc() {
if (getOptLevel() != CodeGenOpt::None) {
- if (EnableExpandCondsets) {
- Pass *Exp = createHexagonExpandCondsets();
- insertPass(&RegisterCoalescerID, IdentifyingPassPtr(Exp));
- }
+ if (EnableExpandCondsets)
+ insertPass(&RegisterCoalescerID, &HexagonExpandCondsetsID);
if (!DisableStoreWidening)
addPass(createHexagonStoreWidening(), false);
if (!DisableHardwareLoops)
addPass(createHexagonHardwareLoops(), false);
}
+ if (TM->getOptLevel() >= CodeGenOpt::Default)
+ addPass(&MachinePipelinerID);
}
void HexagonPassConfig::addPostRegAlloc() {
@@ -315,6 +337,8 @@ void HexagonPassConfig::addPreEmitPass() {
addPass(createHexagonPacketizer(), false);
}
+ if (EnableVectorPrint)
+ addPass(createHexagonVectorPrint(), false);
// Add CFI instructions if necessary.
addPass(createHexagonCallFrameInformation(), false);
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
index 82b437e..c9c4f95 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
@@ -10,17 +10,27 @@
// This file contains the declarations of the HexagonTargetAsmInfo properties.
//
//===----------------------------------------------------------------------===//
+
#define DEBUG_TYPE "hexagon-sdata"
-#include "HexagonTargetMachine.h"
#include "HexagonTargetObjectFile.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalObject.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Type.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
using namespace llvm;
@@ -44,13 +54,21 @@ static cl::opt<bool> TraceGVPlacement("trace-gv-placement",
// (e.g. -debug and -debug-only=globallayout)
#define TRACE_TO(s, X) s << X
#ifdef NDEBUG
-#define TRACE(X) do { if (TraceGVPlacement) { TRACE_TO(errs(), X); } } while (0)
+#define TRACE(X) \
+ do { \
+ if (TraceGVPlacement) { \
+ TRACE_TO(errs(), X); \
+ } \
+ } while (false)
#else
-#define TRACE(X) \
- do { \
- if (TraceGVPlacement) { TRACE_TO(errs(), X); } \
- else { DEBUG( TRACE_TO(dbgs(), X) ); } \
- } while (0)
+#define TRACE(X) \
+ do { \
+ if (TraceGVPlacement) { \
+ TRACE_TO(errs(), X); \
+ } else { \
+ DEBUG(TRACE_TO(dbgs(), X)); \
+ } \
+ } while (false)
#endif
// Returns true if the section name is such that the symbol will be put
@@ -69,7 +87,6 @@ static bool isSmallDataSection(StringRef Sec) {
Sec.find(".scommon.") != StringRef::npos;
}
-
static const char *getSectionSuffixForSize(unsigned Size) {
switch (Size) {
default:
@@ -100,25 +117,23 @@ void HexagonTargetObjectFile::Initialize(MCContext &Ctx,
ELF::SHF_HEX_GPREL);
}
-
MCSection *HexagonTargetObjectFile::SelectSectionForGlobal(
- const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
- TRACE("[SelectSectionForGlobal] GV(" << GV->getName() << ") ");
- TRACE("input section(" << GV->getSection() << ") ");
-
- TRACE((GV->hasPrivateLinkage() ? "private_linkage " : "")
- << (GV->hasLocalLinkage() ? "local_linkage " : "")
- << (GV->hasInternalLinkage() ? "internal " : "")
- << (GV->hasExternalLinkage() ? "external " : "")
- << (GV->hasCommonLinkage() ? "common_linkage " : "")
- << (GV->hasCommonLinkage() ? "common " : "" )
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ TRACE("[SelectSectionForGlobal] GO(" << GO->getName() << ") ");
+ TRACE("input section(" << GO->getSection() << ") ");
+
+ TRACE((GO->hasPrivateLinkage() ? "private_linkage " : "")
+ << (GO->hasLocalLinkage() ? "local_linkage " : "")
+ << (GO->hasInternalLinkage() ? "internal " : "")
+ << (GO->hasExternalLinkage() ? "external " : "")
+ << (GO->hasCommonLinkage() ? "common_linkage " : "")
+ << (GO->hasCommonLinkage() ? "common " : "" )
<< (Kind.isCommon() ? "kind_common " : "" )
<< (Kind.isBSS() ? "kind_bss " : "" )
<< (Kind.isBSSLocal() ? "kind_bss_local " : "" ));
- if (isGlobalInSmallSection(GV, TM))
- return selectSmallSectionForGlobal(GV, Kind, Mang, TM);
+ if (isGlobalInSmallSection(GO, TM))
+ return selectSmallSectionForGlobal(GO, Kind, TM);
if (Kind.isCommon()) {
// This is purely for LTO+Linker Script because commons don't really have a
@@ -130,54 +145,49 @@ MCSection *HexagonTargetObjectFile::SelectSectionForGlobal(
TRACE("default_ELF_section\n");
// Otherwise, we work the same as ELF.
- return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind,
- Mang, TM);
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
}
-
MCSection *HexagonTargetObjectFile::getExplicitSectionGlobal(
- const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
- TRACE("[getExplicitSectionGlobal] GV(" << GV->getName() << ") from("
- << GV->getSection() << ") ");
- TRACE((GV->hasPrivateLinkage() ? "private_linkage " : "")
- << (GV->hasLocalLinkage() ? "local_linkage " : "")
- << (GV->hasInternalLinkage() ? "internal " : "")
- << (GV->hasExternalLinkage() ? "external " : "")
- << (GV->hasCommonLinkage() ? "common_linkage " : "")
- << (GV->hasCommonLinkage() ? "common " : "" )
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ TRACE("[getExplicitSectionGlobal] GO(" << GO->getName() << ") from("
+ << GO->getSection() << ") ");
+ TRACE((GO->hasPrivateLinkage() ? "private_linkage " : "")
+ << (GO->hasLocalLinkage() ? "local_linkage " : "")
+ << (GO->hasInternalLinkage() ? "internal " : "")
+ << (GO->hasExternalLinkage() ? "external " : "")
+ << (GO->hasCommonLinkage() ? "common_linkage " : "")
+ << (GO->hasCommonLinkage() ? "common " : "" )
<< (Kind.isCommon() ? "kind_common " : "" )
<< (Kind.isBSS() ? "kind_bss " : "" )
<< (Kind.isBSSLocal() ? "kind_bss_local " : "" ));
- if (GV->hasSection()) {
- StringRef Section = GV->getSection();
+ if (GO->hasSection()) {
+ StringRef Section = GO->getSection();
if (Section.find(".access.text.group") != StringRef::npos)
- return getContext().getELFSection(GV->getSection(), ELF::SHT_PROGBITS,
+ return getContext().getELFSection(GO->getSection(), ELF::SHT_PROGBITS,
ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
if (Section.find(".access.data.group") != StringRef::npos)
- return getContext().getELFSection(GV->getSection(), ELF::SHT_PROGBITS,
+ return getContext().getELFSection(GO->getSection(), ELF::SHT_PROGBITS,
ELF::SHF_WRITE | ELF::SHF_ALLOC);
}
- if (isGlobalInSmallSection(GV, TM))
- return selectSmallSectionForGlobal(GV, Kind, Mang, TM);
+ if (isGlobalInSmallSection(GO, TM))
+ return selectSmallSectionForGlobal(GO, Kind, TM);
// Otherwise, we work the same as ELF.
TRACE("default_ELF_section\n");
- return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GV, Kind,
- Mang, TM);
+ return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM);
}
-
/// Return true if this global value should be placed into small data/bss
/// section.
-bool HexagonTargetObjectFile::isGlobalInSmallSection(const GlobalValue *GV,
+bool HexagonTargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO,
const TargetMachine &TM) const {
// Only global variables, not functions.
DEBUG(dbgs() << "Checking if value is in small-data, -G"
- << SmallDataThreshold << ": \"" << GV->getName() << "\": ");
- const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
+ << SmallDataThreshold << ": \"" << GO->getName() << "\": ");
+ const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO);
if (!GVar) {
DEBUG(dbgs() << "no, not a global variable\n");
return false;
@@ -238,17 +248,14 @@ bool HexagonTargetObjectFile::isGlobalInSmallSection(const GlobalValue *GV,
return true;
}
-
bool HexagonTargetObjectFile::isSmallDataEnabled() const {
return SmallDataThreshold > 0;
}
-
unsigned HexagonTargetObjectFile::getSmallDataSize() const {
return SmallDataThreshold;
}
-
/// Descends any type down to "elementary" components,
/// discovering the smallest addressable one.
/// If zero is returned, declaration will not be modified.
@@ -302,12 +309,10 @@ unsigned HexagonTargetObjectFile::getSmallestAddressableSize(const Type *Ty,
return 0;
}
-
MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal(
- const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
- const Type *GTy = GV->getType()->getElementType();
- unsigned Size = getSmallestAddressableSize(GTy, GV, TM);
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ const Type *GTy = GO->getType()->getElementType();
+ unsigned Size = getSmallestAddressableSize(GTy, GO, TM);
// If we have -ffunction-section or -fdata-section then we should emit the
// global value to a unique section specifically for it... even for sdata.
@@ -333,7 +338,7 @@ MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal(
if (EmitUniquedSection) {
Name.append(".");
- Name.append(GV->getName());
+ Name.append(GO->getName());
}
TRACE(" unique sbss(" << Name << ")\n");
return getContext().getELFSection(Name.str(), ELF::SHT_NOBITS,
@@ -360,7 +365,7 @@ MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal(
// case the Kind could be wrong for it.
if (Kind.isMergeableConst()) {
TRACE(" const_object_as_data ");
- const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
+ const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GO);
if (GVar->hasSection() && isSmallDataSection(GVar->getSection()))
Kind = SectionKind::getData();
}
@@ -377,7 +382,7 @@ MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal(
if (EmitUniquedSection) {
Name.append(".");
- Name.append(GV->getName());
+ Name.append(GO->getName());
}
TRACE(" unique sdata(" << Name << ")\n");
return getContext().getELFSection(Name.str(), ELF::SHT_PROGBITS,
@@ -386,6 +391,5 @@ MCSection *HexagonTargetObjectFile::selectSmallSectionForGlobal(
TRACE("default ELF section\n");
// Otherwise, we work the same as ELF.
- return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind,
- Mang, TM);
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.h b/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.h
index cbc00da..58dff2b 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.h
@@ -19,14 +19,15 @@ namespace llvm {
public:
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang, const TargetMachine &TM) const override;
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
+ const TargetMachine &TM) const override;
- MCSection *getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang, const TargetMachine &TM) const override;
+ MCSection *getExplicitSectionGlobal(const GlobalObject *GO,
+ SectionKind Kind,
+ const TargetMachine &TM) const override;
- bool isGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM)
- const;
+ bool isGlobalInSmallSection(const GlobalObject *GO,
+ const TargetMachine &TM) const;
bool isSmallDataEnabled() const;
@@ -39,8 +40,9 @@ namespace llvm {
unsigned getSmallestAddressableSize(const Type *Ty, const GlobalValue *GV,
const TargetMachine &TM) const;
- MCSection *selectSmallSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const;
+ MCSection *selectSmallSectionForGlobal(const GlobalObject *GO,
+ SectionKind Kind,
+ const TargetMachine &TM) const;
};
} // namespace llvm
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.cpp
index a05443e..d578bfa 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "HexagonTargetTransformInfo.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
@@ -36,3 +37,35 @@ void HexagonTTIImpl::getUnrollingPreferences(Loop *L,
unsigned HexagonTTIImpl::getNumberOfRegisters(bool vector) const {
return vector ? 0 : 32;
}
+
+unsigned HexagonTTIImpl::getPrefetchDistance() const {
+ return getST()->getL1PrefetchDistance();
+}
+
+unsigned HexagonTTIImpl::getCacheLineSize() const {
+ return getST()->getL1CacheLineSize();
+}
+
+int HexagonTTIImpl::getUserCost(const User *U) {
+ auto isCastFoldedIntoLoad = [] (const CastInst *CI) -> bool {
+ if (!CI->isIntegerCast())
+ return false;
+ const LoadInst *LI = dyn_cast<const LoadInst>(CI->getOperand(0));
+ // Technically, this code could allow multiple uses of the load, and
+ // check if all the uses are the same extension operation, but this
+ // should be sufficient for most cases.
+ if (!LI || !LI->hasOneUse())
+ return false;
+
+ // Only extensions from an integer type shorter than 32-bit to i32
+ // can be folded into the load.
+ unsigned SBW = CI->getSrcTy()->getIntegerBitWidth();
+ unsigned DBW = CI->getDestTy()->getIntegerBitWidth();
+ return DBW == 32 && (SBW < DBW);
+ };
+
+ if (const CastInst *CI = dyn_cast<const CastInst>(U))
+ if (isCastFoldedIntoLoad(CI))
+ return TargetTransformInfo::TCC_Free;
+ return BaseT::getUserCost(U);
+}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.h b/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.h
index 71ae17a..8414bfc 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetTransformInfo.h
@@ -40,13 +40,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- HexagonTTIImpl(const HexagonTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- HexagonTTIImpl(HexagonTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
/// \name Scalar TTI Implementations
/// @{
@@ -55,6 +48,10 @@ public:
// The Hexagon target can unroll loops with run-time trip counts.
void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP);
+ // L1 cache prefetch.
+ unsigned getPrefetchDistance() const;
+ unsigned getCacheLineSize() const;
+
/// @}
/// \name Vector TTI Implementations
@@ -63,6 +60,8 @@ public:
unsigned getNumberOfRegisters(bool vector) const;
/// @}
+
+ int getUserCost(const User *U);
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
index d326b94..7b1247d 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
@@ -22,7 +22,6 @@
#include "HexagonVLIWPacketizer.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/MachineDominators.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
@@ -75,13 +74,11 @@ namespace {
AU.addPreserved<MachineLoopInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
- const char *getPassName() const override {
- return "Hexagon Packetizer";
- }
+ StringRef getPassName() const override { return "Hexagon Packetizer"; }
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -101,7 +98,6 @@ INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(HexagonPacketizer, "packets", "Hexagon Packetizer",
false, false)
-
HexagonPacketizerList::HexagonPacketizerList(MachineFunction &MF,
MachineLoopInfo &MLI, AliasAnalysis *AA,
const MachineBranchProbabilityInfo *MBPI)
@@ -127,7 +123,7 @@ static bool hasWriteToReadDep(const MachineInstr &FirstI,
}
-static MachineBasicBlock::iterator moveInstrOut(MachineInstr *MI,
+static MachineBasicBlock::iterator moveInstrOut(MachineInstr &MI,
MachineBasicBlock::iterator BundleIt, bool Before) {
MachineBasicBlock::instr_iterator InsertPt;
if (Before)
@@ -135,20 +131,20 @@ static MachineBasicBlock::iterator moveInstrOut(MachineInstr *MI,
else
InsertPt = std::next(BundleIt).getInstrIterator();
- MachineBasicBlock &B = *MI->getParent();
+ MachineBasicBlock &B = *MI.getParent();
// The instruction should at least be bundled with the preceding instruction
// (there will always be one, i.e. BUNDLE, if nothing else).
- assert(MI->isBundledWithPred());
- if (MI->isBundledWithSucc()) {
- MI->clearFlag(MachineInstr::BundledSucc);
- MI->clearFlag(MachineInstr::BundledPred);
+ assert(MI.isBundledWithPred());
+ if (MI.isBundledWithSucc()) {
+ MI.clearFlag(MachineInstr::BundledSucc);
+ MI.clearFlag(MachineInstr::BundledPred);
} else {
// If it's not bundled with the successor (i.e. it is the last one
// in the bundle), then we can simply unbundle it from the predecessor,
// which will take care of updating the predecessor's flag.
- MI->unbundleFromPred();
+ MI.unbundleFromPred();
}
- B.splice(InsertPt, &B, MI);
+ B.splice(InsertPt, &B, MI.getIterator());
// Get the size of the bundle without asserting.
MachineBasicBlock::const_instr_iterator I = BundleIt.getInstrIterator();
@@ -164,9 +160,9 @@ static MachineBasicBlock::iterator moveInstrOut(MachineInstr *MI,
// Otherwise, extract the single instruction out and delete the bundle.
MachineBasicBlock::iterator NextIt = std::next(BundleIt);
- MachineInstr *SingleI = BundleIt->getNextNode();
- SingleI->unbundleFromPred();
- assert(!SingleI->isBundledWithSucc());
+ MachineInstr &SingleI = *BundleIt->getNextNode();
+ SingleI.unbundleFromPred();
+ assert(!SingleI.isBundledWithSucc());
BundleIt->eraseFromParent();
return NextIt;
}
@@ -267,7 +263,7 @@ bool HexagonPacketizerList::tryAllocateResourcesForConstExt(bool Reserve) {
}
-bool HexagonPacketizerList::isCallDependent(const MachineInstr* MI,
+bool HexagonPacketizerList::isCallDependent(const MachineInstr &MI,
SDep::Kind DepType, unsigned DepReg) {
// Check for LR dependence.
if (DepReg == HRI->getRARegister())
@@ -284,11 +280,18 @@ bool HexagonPacketizerList::isCallDependent(const MachineInstr* MI,
// Assumes that the first operand of the CALLr is the function address.
if (HII->isIndirectCall(MI) && (DepType == SDep::Data)) {
- MachineOperand MO = MI->getOperand(0);
+ const MachineOperand MO = MI.getOperand(0);
if (MO.isReg() && MO.isUse() && (MO.getReg() == DepReg))
return true;
}
+ if (HII->isJumpR(MI)) {
+ const MachineOperand &MO = HII->isPredicated(MI) ? MI.getOperand(1)
+ : MI.getOperand(0);
+ assert(MO.isReg() && MO.isUse());
+ if (MO.getReg() == DepReg)
+ return true;
+ }
return false;
}
@@ -297,54 +300,60 @@ static bool isRegDependence(const SDep::Kind DepType) {
DepType == SDep::Output;
}
-static bool isDirectJump(const MachineInstr* MI) {
- return MI->getOpcode() == Hexagon::J2_jump;
+static bool isDirectJump(const MachineInstr &MI) {
+ return MI.getOpcode() == Hexagon::J2_jump;
}
-static bool isSchedBarrier(const MachineInstr* MI) {
- switch (MI->getOpcode()) {
+static bool isSchedBarrier(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
case Hexagon::Y2_barrier:
return true;
}
return false;
}
-static bool isControlFlow(const MachineInstr* MI) {
- return (MI->getDesc().isTerminator() || MI->getDesc().isCall());
+static bool isControlFlow(const MachineInstr &MI) {
+ return MI.getDesc().isTerminator() || MI.getDesc().isCall();
}
/// Returns true if the instruction modifies a callee-saved register.
-static bool doesModifyCalleeSavedReg(const MachineInstr *MI,
+static bool doesModifyCalleeSavedReg(const MachineInstr &MI,
const TargetRegisterInfo *TRI) {
- const MachineFunction &MF = *MI->getParent()->getParent();
+ const MachineFunction &MF = *MI.getParent()->getParent();
for (auto *CSR = TRI->getCalleeSavedRegs(&MF); CSR && *CSR; ++CSR)
- if (MI->modifiesRegister(*CSR, TRI))
+ if (MI.modifiesRegister(*CSR, TRI))
return true;
return false;
}
-// TODO: MI->isIndirectBranch() and IsRegisterJump(MI)
// Returns true if an instruction can be promoted to .new predicate or
// new-value store.
-bool HexagonPacketizerList::isNewifiable(const MachineInstr* MI) {
- return HII->isCondInst(MI) || MI->isReturn() || HII->mayBeNewStore(MI);
+bool HexagonPacketizerList::isNewifiable(const MachineInstr &MI,
+ const TargetRegisterClass *NewRC) {
+ // Vector stores can be predicated, and can be new-value stores, but
+ // they cannot be predicated on a .new predicate value.
+ if (NewRC == &Hexagon::PredRegsRegClass)
+ if (HII->isV60VectorInstruction(MI) && MI.mayStore())
+ return false;
+ return HII->isCondInst(MI) || HII->isJumpR(MI) || MI.isReturn() ||
+ HII->mayBeNewStore(MI);
}
// Promote an instructiont to its .cur form.
// At this time, we have already made a call to canPromoteToDotCur and made
// sure that it can *indeed* be promoted.
-bool HexagonPacketizerList::promoteToDotCur(MachineInstr* MI,
+bool HexagonPacketizerList::promoteToDotCur(MachineInstr &MI,
SDep::Kind DepType, MachineBasicBlock::iterator &MII,
const TargetRegisterClass* RC) {
assert(DepType == SDep::Data);
int CurOpcode = HII->getDotCurOp(MI);
- MI->setDesc(HII->get(CurOpcode));
+ MI.setDesc(HII->get(CurOpcode));
return true;
}
void HexagonPacketizerList::cleanUpDotCur() {
- MachineInstr *MI = NULL;
+ MachineInstr *MI = nullptr;
for (auto BI : CurrentPacketMIs) {
DEBUG(dbgs() << "Cleanup packet has "; BI->dump(););
if (BI->getOpcode() == Hexagon::V6_vL32b_cur_ai) {
@@ -365,12 +374,12 @@ void HexagonPacketizerList::cleanUpDotCur() {
}
// Check to see if an instruction can be dot cur.
-bool HexagonPacketizerList::canPromoteToDotCur(const MachineInstr *MI,
+bool HexagonPacketizerList::canPromoteToDotCur(const MachineInstr &MI,
const SUnit *PacketSU, unsigned DepReg, MachineBasicBlock::iterator &MII,
const TargetRegisterClass *RC) {
if (!HII->isV60VectorInstruction(MI))
return false;
- if (!HII->isV60VectorInstruction(&*MII))
+ if (!HII->isV60VectorInstruction(*MII))
return false;
// Already a dot new instruction.
@@ -386,14 +395,14 @@ bool HexagonPacketizerList::canPromoteToDotCur(const MachineInstr *MI,
// Make sure candidate instruction uses cur.
DEBUG(dbgs() << "Can we DOT Cur Vector MI\n";
- MI->dump();
+ MI.dump();
dbgs() << "in packet\n";);
MachineInstr &MJ = *MII;
DEBUG({
dbgs() << "Checking CUR against ";
MJ.dump();
});
- unsigned DestReg = MI->getOperand(0).getReg();
+ unsigned DestReg = MI.getOperand(0).getReg();
bool FoundMatch = false;
for (auto &MO : MJ.operands())
if (MO.isReg() && MO.getReg() == DestReg)
@@ -409,7 +418,7 @@ bool HexagonPacketizerList::canPromoteToDotCur(const MachineInstr *MI,
return false;
}
- DEBUG(dbgs() << "Can Dot CUR MI\n"; MI->dump(););
+ DEBUG(dbgs() << "Can Dot CUR MI\n"; MI.dump(););
// We can convert the opcode into a .cur.
return true;
}
@@ -417,7 +426,7 @@ bool HexagonPacketizerList::canPromoteToDotCur(const MachineInstr *MI,
// Promote an instruction to its .new form. At this time, we have already
// made a call to canPromoteToDotNew and made sure that it can *indeed* be
// promoted.
-bool HexagonPacketizerList::promoteToDotNew(MachineInstr* MI,
+bool HexagonPacketizerList::promoteToDotNew(MachineInstr &MI,
SDep::Kind DepType, MachineBasicBlock::iterator &MII,
const TargetRegisterClass* RC) {
assert (DepType == SDep::Data);
@@ -426,16 +435,53 @@ bool HexagonPacketizerList::promoteToDotNew(MachineInstr* MI,
NewOpcode = HII->getDotNewPredOp(MI, MBPI);
else
NewOpcode = HII->getDotNewOp(MI);
- MI->setDesc(HII->get(NewOpcode));
+ MI.setDesc(HII->get(NewOpcode));
return true;
}
-bool HexagonPacketizerList::demoteToDotOld(MachineInstr* MI) {
- int NewOpcode = HII->getDotOldOp(MI->getOpcode());
- MI->setDesc(HII->get(NewOpcode));
+bool HexagonPacketizerList::demoteToDotOld(MachineInstr &MI) {
+ int NewOpcode = HII->getDotOldOp(MI.getOpcode());
+ MI.setDesc(HII->get(NewOpcode));
return true;
}
+bool HexagonPacketizerList::useCallersSP(MachineInstr &MI) {
+ unsigned Opc = MI.getOpcode();
+ switch (Opc) {
+ case Hexagon::S2_storerd_io:
+ case Hexagon::S2_storeri_io:
+ case Hexagon::S2_storerh_io:
+ case Hexagon::S2_storerb_io:
+ break;
+ default:
+ llvm_unreachable("Unexpected instruction");
+ }
+ unsigned FrameSize = MF.getFrameInfo().getStackSize();
+ MachineOperand &Off = MI.getOperand(1);
+ int64_t NewOff = Off.getImm() - (FrameSize + HEXAGON_LRFP_SIZE);
+ if (HII->isValidOffset(Opc, NewOff)) {
+ Off.setImm(NewOff);
+ return true;
+ }
+ return false;
+}
+
+void HexagonPacketizerList::useCalleesSP(MachineInstr &MI) {
+ unsigned Opc = MI.getOpcode();
+ switch (Opc) {
+ case Hexagon::S2_storerd_io:
+ case Hexagon::S2_storeri_io:
+ case Hexagon::S2_storerh_io:
+ case Hexagon::S2_storerb_io:
+ break;
+ default:
+ llvm_unreachable("Unexpected instruction");
+ }
+ unsigned FrameSize = MF.getFrameInfo().getStackSize();
+ MachineOperand &Off = MI.getOperand(1);
+ Off.setImm(Off.getImm() + FrameSize + HEXAGON_LRFP_SIZE);
+}
+
enum PredicateKind {
PK_False,
PK_True,
@@ -453,7 +499,7 @@ static PredicateKind getPredicateSense(const MachineInstr &MI,
return PK_False;
}
-static const MachineOperand &getPostIncrementOperand(const MachineInstr *MI,
+static const MachineOperand &getPostIncrementOperand(const MachineInstr &MI,
const HexagonInstrInfo *HII) {
assert(HII->isPostIncrement(MI) && "Not a post increment operation.");
#ifndef NDEBUG
@@ -461,22 +507,22 @@ static const MachineOperand &getPostIncrementOperand(const MachineInstr *MI,
// list. Caution: Densemap initializes with the minimum of 64 buckets,
// whereas there are at most 5 operands in the post increment.
DenseSet<unsigned> DefRegsSet;
- for (auto &MO : MI->operands())
+ for (auto &MO : MI.operands())
if (MO.isReg() && MO.isDef())
DefRegsSet.insert(MO.getReg());
- for (auto &MO : MI->operands())
+ for (auto &MO : MI.operands())
if (MO.isReg() && MO.isUse() && DefRegsSet.count(MO.getReg()))
return MO;
#else
- if (MI->mayLoad()) {
- const MachineOperand &Op1 = MI->getOperand(1);
+ if (MI.mayLoad()) {
+ const MachineOperand &Op1 = MI.getOperand(1);
// The 2nd operand is always the post increment operand in load.
assert(Op1.isReg() && "Post increment operand has be to a register.");
return Op1;
}
- if (MI->getDesc().mayStore()) {
- const MachineOperand &Op0 = MI->getOperand(0);
+ if (MI.getDesc().mayStore()) {
+ const MachineOperand &Op0 = MI.getOperand(0);
// The 1st operand is always the post increment operand in store.
assert(Op0.isReg() && "Post increment operand has be to a register.");
return Op0;
@@ -487,13 +533,13 @@ static const MachineOperand &getPostIncrementOperand(const MachineInstr *MI,
}
// Get the value being stored.
-static const MachineOperand& getStoreValueOperand(const MachineInstr *MI) {
+static const MachineOperand& getStoreValueOperand(const MachineInstr &MI) {
// value being stored is always the last operand.
- return MI->getOperand(MI->getNumOperands()-1);
+ return MI.getOperand(MI.getNumOperands()-1);
}
-static bool isLoadAbsSet(const MachineInstr *MI) {
- unsigned Opc = MI->getOpcode();
+static bool isLoadAbsSet(const MachineInstr &MI) {
+ unsigned Opc = MI.getOpcode();
switch (Opc) {
case Hexagon::L4_loadrd_ap:
case Hexagon::L4_loadrb_ap:
@@ -506,9 +552,9 @@ static bool isLoadAbsSet(const MachineInstr *MI) {
return false;
}
-static const MachineOperand &getAbsSetOperand(const MachineInstr *MI) {
+static const MachineOperand &getAbsSetOperand(const MachineInstr &MI) {
assert(isLoadAbsSet(MI));
- return MI->getOperand(1);
+ return MI.getOperand(1);
}
@@ -529,8 +575,8 @@ static const MachineOperand &getAbsSetOperand(const MachineInstr *MI) {
// if there is a new value store in the packet. Corollary: if there is
// already a store in a packet, there can not be a new value store.
// Arch Spec: 3.4.4.2
-bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
- const MachineInstr *PacketMI, unsigned DepReg) {
+bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr &MI,
+ const MachineInstr &PacketMI, unsigned DepReg) {
// Make sure we are looking at the store, that can be promoted.
if (!HII->mayBeNewStore(MI))
return false;
@@ -540,7 +586,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
if (Val.isReg() && Val.getReg() != DepReg)
return false;
- const MCInstrDesc& MCID = PacketMI->getDesc();
+ const MCInstrDesc& MCID = PacketMI.getDesc();
// First operand is always the result.
const TargetRegisterClass *PacketRC = HII->getRegClass(MCID, 0, HRI, MF);
@@ -563,7 +609,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
return false;
}
- if (HII->isPostIncrement(PacketMI) && PacketMI->mayLoad() &&
+ if (HII->isPostIncrement(PacketMI) && PacketMI.mayLoad() &&
getPostIncrementOperand(PacketMI, HII).getReg() == DepReg) {
// If source is post_inc, or absolute-set addressing, it can not feed
// into new value store
@@ -578,8 +624,8 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
// If the source that feeds the store is predicated, new value store must
// also be predicated.
- if (HII->isPredicated(*PacketMI)) {
- if (!HII->isPredicated(*MI))
+ if (HII->isPredicated(PacketMI)) {
+ if (!HII->isPredicated(MI))
return false;
// Check to make sure that they both will have their predicates
@@ -589,7 +635,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
const TargetRegisterClass* predRegClass = nullptr;
// Get predicate register used in the source instruction.
- for (auto &MO : PacketMI->operands()) {
+ for (auto &MO : PacketMI.operands()) {
if (!MO.isReg())
continue;
predRegNumSrc = MO.getReg();
@@ -601,7 +647,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
"predicate register not found in a predicated PacketMI instruction");
// Get predicate register used in new-value store instruction.
- for (auto &MO : MI->operands()) {
+ for (auto &MO : MI.operands()) {
if (!MO.isReg())
continue;
predRegNumDst = MO.getReg();
@@ -622,7 +668,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
// sense, i.e, either both should be negated or both should be non-negated.
if (predRegNumDst != predRegNumSrc ||
HII->isDotNewInst(PacketMI) != HII->isDotNewInst(MI) ||
- getPredicateSense(*MI, HII) != getPredicateSense(*PacketMI, HII))
+ getPredicateSense(MI, HII) != getPredicateSense(PacketMI, HII))
return false;
}
@@ -638,19 +684,19 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
for (auto I : CurrentPacketMIs) {
SUnit *TempSU = MIToSUnit.find(I)->second;
- MachineInstr* TempMI = TempSU->getInstr();
+ MachineInstr &TempMI = *TempSU->getInstr();
// Following condition is true for all the instructions until PacketMI is
// reached (StartCheck is set to 0 before the for loop).
// StartCheck flag is 1 for all the instructions after PacketMI.
- if (TempMI != PacketMI && !StartCheck) // Start processing only after
- continue; // encountering PacketMI.
+ if (&TempMI != &PacketMI && !StartCheck) // Start processing only after
+ continue; // encountering PacketMI.
StartCheck = 1;
- if (TempMI == PacketMI) // We don't want to check PacketMI for dependence.
+ if (&TempMI == &PacketMI) // We don't want to check PacketMI for dependence.
continue;
- for (auto &MO : MI->operands())
+ for (auto &MO : MI.operands())
if (MO.isReg() && TempSU->getInstr()->modifiesRegister(MO.getReg(), HRI))
return false;
}
@@ -662,8 +708,8 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
// Eg. r0 = add(r0, #3)
// memw(r1+r0<<#2) = r0
if (!HII->isPostIncrement(MI)) {
- for (unsigned opNum = 0; opNum < MI->getNumOperands()-1; opNum++) {
- const MachineOperand &MO = MI->getOperand(opNum);
+ for (unsigned opNum = 0; opNum < MI.getNumOperands()-1; opNum++) {
+ const MachineOperand &MO = MI.getOperand(opNum);
if (MO.isReg() && MO.getReg() == DepReg)
return false;
}
@@ -673,7 +719,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
// do not newify the store. Eg.
// %R9<def> = ZXTH %R12, %D6<imp-use>, %R12<imp-def>
// S2_storerh_io %R8, 2, %R12<kill>; mem:ST2[%scevgep343]
- for (auto &MO : PacketMI->operands()) {
+ for (auto &MO : PacketMI.operands()) {
if (!MO.isReg() || !MO.isDef() || !MO.isImplicit())
continue;
unsigned R = MO.getReg();
@@ -686,7 +732,7 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
// just-in-case. For example, we cannot newify R2 in the following case:
// %R3<def> = A2_tfrsi 0;
// S2_storeri_io %R0<kill>, 0, %R2<kill>, %D1<imp-use,kill>;
- for (auto &MO : MI->operands()) {
+ for (auto &MO : MI.operands()) {
if (MO.isReg() && MO.isUse() && MO.isImplicit() && MO.getReg() == DepReg)
return false;
}
@@ -696,14 +742,14 @@ bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr *MI,
}
// Can this MI to promoted to either new value store or new value jump.
-bool HexagonPacketizerList::canPromoteToNewValue(const MachineInstr *MI,
+bool HexagonPacketizerList::canPromoteToNewValue(const MachineInstr &MI,
const SUnit *PacketSU, unsigned DepReg,
MachineBasicBlock::iterator &MII) {
if (!HII->mayBeNewStore(MI))
return false;
// Check to see the store can be new value'ed.
- MachineInstr *PacketMI = PacketSU->getInstr();
+ MachineInstr &PacketMI = *PacketSU->getInstr();
if (canPromoteToNewValueStore(MI, PacketMI, DepReg))
return true;
@@ -712,8 +758,8 @@ bool HexagonPacketizerList::canPromoteToNewValue(const MachineInstr *MI,
return false;
}
-static bool isImplicitDependency(const MachineInstr *I, unsigned DepReg) {
- for (auto &MO : I->operands())
+static bool isImplicitDependency(const MachineInstr &I, unsigned DepReg) {
+ for (auto &MO : I.operands())
if (MO.isReg() && MO.isDef() && (MO.getReg() == DepReg) && MO.isImplicit())
return true;
return false;
@@ -724,25 +770,25 @@ static bool isImplicitDependency(const MachineInstr *I, unsigned DepReg) {
// 1. dot new on predicate - V2/V3/V4
// 2. dot new on stores NV/ST - V4
// 3. dot new on jump NV/J - V4 -- This is generated in a pass.
-bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr *MI,
+bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr &MI,
const SUnit *PacketSU, unsigned DepReg, MachineBasicBlock::iterator &MII,
const TargetRegisterClass* RC) {
// Already a dot new instruction.
if (HII->isDotNewInst(MI) && !HII->mayBeNewStore(MI))
return false;
- if (!isNewifiable(MI))
+ if (!isNewifiable(MI, RC))
return false;
- const MachineInstr *PI = PacketSU->getInstr();
+ const MachineInstr &PI = *PacketSU->getInstr();
// The "new value" cannot come from inline asm.
- if (PI->isInlineAsm())
+ if (PI.isInlineAsm())
return false;
// IMPLICIT_DEFs won't materialize as real instructions, so .new makes no
// sense.
- if (PI->isImplicitDef())
+ if (PI.isImplicitDef())
return false;
// If dependency is trough an implicitly defined register, we should not
@@ -750,16 +796,14 @@ bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr *MI,
if (isImplicitDependency(PI, DepReg))
return false;
- const MCInstrDesc& MCID = PI->getDesc();
+ const MCInstrDesc& MCID = PI.getDesc();
const TargetRegisterClass *VecRC = HII->getRegClass(MCID, 0, HRI, MF);
if (DisableVecDblNVStores && VecRC == &Hexagon::VecDblRegsRegClass)
return false;
// predicate .new
- // bug 5670: until that is fixed
- // TODO: MI->isIndirectBranch() and IsRegisterJump(MI)
if (RC == &Hexagon::PredRegsRegClass)
- if (HII->isCondInst(MI) || MI->isReturn())
+ if (HII->isCondInst(MI) || HII->isJumpR(MI) || MI.isReturn())
return HII->predCanBeUsedAsDotNew(PI, DepReg);
if (RC != &Hexagon::PredRegsRegClass && !HII->mayBeNewStore(MI))
@@ -795,9 +839,9 @@ bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr *MI,
// The P3 from a) and d) will be complements after
// a)'s P3 is converted to .new form
// Anti-dep between c) and b) is irrelevant for this case
-bool HexagonPacketizerList::restrictingDepExistInPacket(MachineInstr* MI,
+bool HexagonPacketizerList::restrictingDepExistInPacket(MachineInstr &MI,
unsigned DepReg) {
- SUnit *PacketSUDep = MIToSUnit.find(MI)->second;
+ SUnit *PacketSUDep = MIToSUnit.find(&MI)->second;
for (auto I : CurrentPacketMIs) {
// We only care for dependencies to predicated instructions
@@ -889,7 +933,7 @@ bool HexagonPacketizerList::arePredicatesComplements(MachineInstr &MI1,
// above example. Now I need to see if there is an anti dependency
// from c) to any other instruction in the same packet on the pred
// reg of interest.
- if (restrictingDepExistInPacket(I, Dep.getReg()))
+ if (restrictingDepExistInPacket(*I, Dep.getReg()))
return false;
}
}
@@ -906,7 +950,7 @@ bool HexagonPacketizerList::arePredicatesComplements(MachineInstr &MI1,
Hexagon::PredRegsRegClass.contains(PReg1) &&
Hexagon::PredRegsRegClass.contains(PReg2) &&
getPredicateSense(MI1, HII) != getPredicateSense(MI2, HII) &&
- HII->isDotNewInst(&MI1) == HII->isDotNewInst(&MI2);
+ HII->isDotNewInst(MI1) == HII->isDotNewInst(MI2);
}
// Initialize packetizer flags.
@@ -957,10 +1001,10 @@ bool HexagonPacketizerList::isSoloInstruction(const MachineInstr &MI) {
// From Hexagon V4 Programmer's Reference Manual 3.4.4 Grouping constraints:
// trap, pause, barrier, icinva, isync, and syncht are solo instructions.
// They must not be grouped with other instructions in a packet.
- if (isSchedBarrier(&MI))
+ if (isSchedBarrier(MI))
return true;
- if (HII->isSolo(&MI))
+ if (HII->isSolo(MI))
return true;
if (MI.getOpcode() == Hexagon::A2_nop)
@@ -977,9 +1021,9 @@ bool HexagonPacketizerList::isSoloInstruction(const MachineInstr &MI) {
// cannotCoexistAsymm(MI, MJ) || cannotCoexistAsymm(MJ, MI)
// Doing the test only one way saves the amount of code in this function,
// since every test would need to be repeated with the MI and MJ reversed.
-static bool cannotCoexistAsymm(const MachineInstr *MI, const MachineInstr *MJ,
+static bool cannotCoexistAsymm(const MachineInstr &MI, const MachineInstr &MJ,
const HexagonInstrInfo &HII) {
- const MachineFunction *MF = MI->getParent()->getParent();
+ const MachineFunction *MF = MI.getParent()->getParent();
if (MF->getSubtarget<HexagonSubtarget>().hasV60TOpsOnly() &&
HII.isHVXMemWithAIndirect(MI, MJ))
return true;
@@ -988,9 +1032,27 @@ static bool cannotCoexistAsymm(const MachineInstr *MI, const MachineInstr *MJ,
// able to remove the asm out after packetizing (i.e. if the asm must be
// moved past the bundle). Similarly, two asms cannot be together to avoid
// complications when determining their relative order outside of a bundle.
- if (MI->isInlineAsm())
- return MJ->isInlineAsm() || MJ->isBranch() || MJ->isBarrier() ||
- MJ->isCall() || MJ->isTerminator();
+ if (MI.isInlineAsm())
+ return MJ.isInlineAsm() || MJ.isBranch() || MJ.isBarrier() ||
+ MJ.isCall() || MJ.isTerminator();
+
+ switch (MI.getOpcode()) {
+ case (Hexagon::S2_storew_locked):
+ case (Hexagon::S4_stored_locked):
+ case (Hexagon::L2_loadw_locked):
+ case (Hexagon::L4_loadd_locked):
+ case (Hexagon::Y4_l2fetch): {
+ // These instructions can only be grouped with ALU32 or non-floating-point
+ // XTYPE instructions. Since there is no convenient way of identifying fp
+ // XTYPE instructions, only allow grouping with ALU32 for now.
+ unsigned TJ = HII.getType(MJ);
+ if (TJ != HexagonII::TypeALU32)
+ return true;
+ break;
+ }
+ default:
+ break;
+ }
// "False" really means that the quick check failed to determine if
// I and J cannot coexist.
@@ -999,8 +1061,8 @@ static bool cannotCoexistAsymm(const MachineInstr *MI, const MachineInstr *MJ,
// Full, symmetric check.
-bool HexagonPacketizerList::cannotCoexist(const MachineInstr *MI,
- const MachineInstr *MJ) {
+bool HexagonPacketizerList::cannotCoexist(const MachineInstr &MI,
+ const MachineInstr &MJ) {
return cannotCoexistAsymm(MI, MJ, *HII) || cannotCoexistAsymm(MJ, MI, *HII);
}
@@ -1010,10 +1072,10 @@ void HexagonPacketizerList::unpacketizeSoloInstrs(MachineFunction &MF) {
MachineBasicBlock::instr_iterator NextI;
for (auto I = B.instr_begin(), E = B.instr_end(); I != E; I = NextI) {
NextI = std::next(I);
- MachineInstr *MI = &*I;
- if (MI->isBundle())
+ MachineInstr &MI = *I;
+ if (MI.isBundle())
BundleIt = I;
- if (!MI->isInsideBundle())
+ if (!MI.isInsideBundle())
continue;
// Decide on where to insert the instruction that we are pulling out.
@@ -1023,9 +1085,9 @@ void HexagonPacketizerList::unpacketizeSoloInstrs(MachineFunction &MF) {
// other instructions in the bundle read, then we need to place it
// after the bundle (to preserve the bundle semantics).
bool InsertBeforeBundle;
- if (MI->isInlineAsm())
- InsertBeforeBundle = !hasWriteToReadDep(*MI, *BundleIt, HRI);
- else if (MI->isDebugValue())
+ if (MI.isInlineAsm())
+ InsertBeforeBundle = !hasWriteToReadDep(MI, *BundleIt, HRI);
+ else if (MI.isDebugValue())
InsertBeforeBundle = true;
else
continue;
@@ -1036,8 +1098,8 @@ void HexagonPacketizerList::unpacketizeSoloInstrs(MachineFunction &MF) {
}
// Check if a given instruction is of class "system".
-static bool isSystemInstr(const MachineInstr *MI) {
- unsigned Opc = MI->getOpcode();
+static bool isSystemInstr(const MachineInstr &MI) {
+ unsigned Opc = MI.getOpcode();
switch (Opc) {
case Hexagon::Y2_barrier:
case Hexagon::Y2_dcfetchbo:
@@ -1046,24 +1108,24 @@ static bool isSystemInstr(const MachineInstr *MI) {
return false;
}
-bool HexagonPacketizerList::hasDeadDependence(const MachineInstr *I,
- const MachineInstr *J) {
+bool HexagonPacketizerList::hasDeadDependence(const MachineInstr &I,
+ const MachineInstr &J) {
// The dependence graph may not include edges between dead definitions,
// so without extra checks, we could end up packetizing two instruction
// defining the same (dead) register.
- if (I->isCall() || J->isCall())
+ if (I.isCall() || J.isCall())
return false;
- if (HII->isPredicated(*I) || HII->isPredicated(*J))
+ if (HII->isPredicated(I) || HII->isPredicated(J))
return false;
BitVector DeadDefs(Hexagon::NUM_TARGET_REGS);
- for (auto &MO : I->operands()) {
+ for (auto &MO : I.operands()) {
if (!MO.isReg() || !MO.isDef() || !MO.isDead())
continue;
DeadDefs[MO.getReg()] = true;
}
- for (auto &MO : J->operands()) {
+ for (auto &MO : J.operands()) {
if (!MO.isReg() || !MO.isDef() || !MO.isDead())
continue;
unsigned R = MO.getReg();
@@ -1073,8 +1135,8 @@ bool HexagonPacketizerList::hasDeadDependence(const MachineInstr *I,
return false;
}
-bool HexagonPacketizerList::hasControlDependence(const MachineInstr *I,
- const MachineInstr *J) {
+bool HexagonPacketizerList::hasControlDependence(const MachineInstr &I,
+ const MachineInstr &J) {
// A save callee-save register function call can only be in a packet
// with instructions that don't write to the callee-save registers.
if ((HII->isSaveCalleeSavedRegsCall(I) &&
@@ -1090,10 +1152,10 @@ bool HexagonPacketizerList::hasControlDependence(const MachineInstr *I,
// \ref-manual (7.3.4) A loop setup packet in loopN or spNloop0 cannot
// contain a speculative indirect jump,
// a new-value compare jump or a dealloc_return.
- auto isBadForLoopN = [this] (const MachineInstr *MI) -> bool {
- if (MI->isCall() || HII->isDeallocRet(MI) || HII->isNewValueJump(MI))
+ auto isBadForLoopN = [this] (const MachineInstr &MI) -> bool {
+ if (MI.isCall() || HII->isDeallocRet(MI) || HII->isNewValueJump(MI))
return true;
- if (HII->isPredicated(*MI) && HII->isPredicatedNew(*MI) && HII->isJumpR(MI))
+ if (HII->isPredicated(MI) && HII->isPredicatedNew(MI) && HII->isJumpR(MI))
return true;
return false;
};
@@ -1106,13 +1168,13 @@ bool HexagonPacketizerList::hasControlDependence(const MachineInstr *I,
// dealloc_return cannot appear in the same packet as a conditional or
// unconditional jump.
return HII->isDeallocRet(I) &&
- (J->isBranch() || J->isCall() || J->isBarrier());
+ (J.isBranch() || J.isCall() || J.isBarrier());
}
-bool HexagonPacketizerList::hasV4SpecificDependence(const MachineInstr *I,
- const MachineInstr *J) {
+bool HexagonPacketizerList::hasV4SpecificDependence(const MachineInstr &I,
+ const MachineInstr &J) {
bool SysI = isSystemInstr(I), SysJ = isSystemInstr(J);
- bool StoreI = I->mayStore(), StoreJ = J->mayStore();
+ bool StoreI = I.mayStore(), StoreJ = J.mayStore();
if ((SysI && StoreJ) || (SysJ && StoreI))
return true;
@@ -1135,19 +1197,18 @@ bool HexagonPacketizerList::hasV4SpecificDependence(const MachineInstr *I,
// SUJ is the current instruction inside the current packet against which that
// SUI will be packetized.
bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
- MachineInstr *I = SUI->getInstr();
- MachineInstr *J = SUJ->getInstr();
- assert(I && J && "Unable to packetize null instruction!");
+ assert(SUI->getInstr() && SUJ->getInstr());
+ MachineInstr &I = *SUI->getInstr();
+ MachineInstr &J = *SUJ->getInstr();
// Clear IgnoreDepMIs when Packet starts.
if (CurrentPacketMIs.size() == 1)
IgnoreDepMIs.clear();
- MachineBasicBlock::iterator II = I;
- const unsigned FrameSize = MF.getFrameInfo()->getStackSize();
+ MachineBasicBlock::iterator II = I.getIterator();
// Solo instructions cannot go in the packet.
- assert(!isSoloInstruction(*I) && "Unexpected solo instr!");
+ assert(!isSoloInstruction(I) && "Unexpected solo instr!");
if (cannotCoexist(I, J))
return false;
@@ -1164,23 +1225,23 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
return false;
// If an instruction feeds new value jump, glue it.
- MachineBasicBlock::iterator NextMII = I;
+ MachineBasicBlock::iterator NextMII = I.getIterator();
++NextMII;
- if (NextMII != I->getParent()->end() && HII->isNewValueJump(&*NextMII)) {
+ if (NextMII != I.getParent()->end() && HII->isNewValueJump(*NextMII)) {
MachineInstr &NextMI = *NextMII;
bool secondRegMatch = false;
const MachineOperand &NOp0 = NextMI.getOperand(0);
const MachineOperand &NOp1 = NextMI.getOperand(1);
- if (NOp1.isReg() && I->getOperand(0).getReg() == NOp1.getReg())
+ if (NOp1.isReg() && I.getOperand(0).getReg() == NOp1.getReg())
secondRegMatch = true;
- for (auto I : CurrentPacketMIs) {
- SUnit *PacketSU = MIToSUnit.find(I)->second;
- MachineInstr *PI = PacketSU->getInstr();
+ for (auto T : CurrentPacketMIs) {
+ SUnit *PacketSU = MIToSUnit.find(T)->second;
+ MachineInstr &PI = *PacketSU->getInstr();
// NVJ can not be part of the dual jump - Arch Spec: section 7.8.
- if (PI->isCall()) {
+ if (PI.isCall()) {
Dependence = true;
break;
}
@@ -1192,14 +1253,14 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// 3. If the second operand of the nvj is newified, (which means
// first operand is also a reg), first reg is not defined in
// the same packet.
- if (PI->getOpcode() == Hexagon::S2_allocframe || PI->mayStore() ||
+ if (PI.getOpcode() == Hexagon::S2_allocframe || PI.mayStore() ||
HII->isLoopN(PI)) {
Dependence = true;
break;
}
// Check #2/#3.
const MachineOperand &OpR = secondRegMatch ? NOp0 : NOp1;
- if (OpR.isReg() && PI->modifiesRegister(OpR.getReg(), HRI)) {
+ if (OpR.isReg() && PI.modifiesRegister(OpR.getReg(), HRI)) {
Dependence = true;
break;
}
@@ -1237,12 +1298,6 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// dealloc return unless we have dependencies on the explicit uses
// of the registers used by jumpr (like r31) or dealloc return
// (like r29 or r30).
- //
- // TODO: Currently, jumpr is handling only return of r31. So, the
- // following logic (specificaly isCallDependent) is working fine.
- // We need to enable jumpr for register other than r31 and then,
- // we need to rework the last part, where it handles indirect call
- // of that (isCallDependent) function. Bug 6216 is opened for this.
unsigned DepReg = 0;
const TargetRegisterClass *RC = nullptr;
if (DepType == SDep::Data) {
@@ -1250,7 +1305,7 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
RC = HRI->getMinimalPhysRegClass(DepReg);
}
- if (I->isCall() || I->isReturn() || HII->isTailCall(I)) {
+ if (I.isCall() || HII->isJumpR(I) || I.isReturn() || HII->isTailCall(I)) {
if (!isRegDependence(DepType))
continue;
if (!isCallDependent(I, DepType, SUJ->Succs[i].getReg()))
@@ -1283,8 +1338,8 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// For predicated instructions, if the predicates are complements then
// there can be no dependence.
- if (HII->isPredicated(*I) && HII->isPredicated(*J) &&
- arePredicatesComplements(*I, *J)) {
+ if (HII->isPredicated(I) && HII->isPredicated(J) &&
+ arePredicatesComplements(I, J)) {
// Not always safe to do this translation.
// DAG Builder attempts to reduce dependence edges using transitive
// nature of dependencies. Here is an example:
@@ -1297,24 +1352,24 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// However, there is no dependence edge between (1)->(3). This results
// in all 3 instructions going in the same packet. We ignore dependce
// only once to avoid this situation.
- auto Itr = std::find(IgnoreDepMIs.begin(), IgnoreDepMIs.end(), J);
+ auto Itr = find(IgnoreDepMIs, &J);
if (Itr != IgnoreDepMIs.end()) {
Dependence = true;
return false;
}
- IgnoreDepMIs.push_back(I);
+ IgnoreDepMIs.push_back(&I);
continue;
}
// Ignore Order dependences between unconditional direct branches
// and non-control-flow instructions.
- if (isDirectJump(I) && !J->isBranch() && !J->isCall() &&
+ if (isDirectJump(I) && !J.isBranch() && !J.isCall() &&
DepType == SDep::Order)
continue;
// Ignore all dependences for jumps except for true and output
// dependences.
- if (I->isConditionalBranch() && DepType != SDep::Data &&
+ if (I.isConditionalBranch() && DepType != SDep::Data &&
DepType != SDep::Output)
continue;
@@ -1336,7 +1391,7 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
unsigned DepReg = SUJ->Succs[i].getReg();
// Check if I and J really defines DepReg.
- if (!I->definesRegister(DepReg) && !J->definesRegister(DepReg))
+ if (!I.definesRegister(DepReg) && !J.definesRegister(DepReg))
continue;
FoundSequentialDependence = true;
break;
@@ -1350,15 +1405,15 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// 4. Load followed by any memory operation is allowed.
if (DepType == SDep::Order) {
if (!PacketizeVolatiles) {
- bool OrdRefs = I->hasOrderedMemoryRef() || J->hasOrderedMemoryRef();
+ bool OrdRefs = I.hasOrderedMemoryRef() || J.hasOrderedMemoryRef();
if (OrdRefs) {
FoundSequentialDependence = true;
break;
}
}
// J is first, I is second.
- bool LoadJ = J->mayLoad(), StoreJ = J->mayStore();
- bool LoadI = I->mayLoad(), StoreI = I->mayStore();
+ bool LoadJ = J.mayLoad(), StoreJ = J.mayStore();
+ bool LoadI = I.mayLoad(), StoreI = I.mayStore();
if (StoreJ) {
// Two stores are only allowed on V4+. Load following store is never
// allowed.
@@ -1383,25 +1438,21 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// between ALLOCFRAME and subsequent store, allow it to be packetized
// in a same packet. This implies that the store is using the caller's
// SP. Hence, offset needs to be updated accordingly.
- if (DepType == SDep::Data && J->getOpcode() == Hexagon::S2_allocframe) {
- unsigned Opc = I->getOpcode();
+ if (DepType == SDep::Data && J.getOpcode() == Hexagon::S2_allocframe) {
+ unsigned Opc = I.getOpcode();
switch (Opc) {
case Hexagon::S2_storerd_io:
case Hexagon::S2_storeri_io:
case Hexagon::S2_storerh_io:
case Hexagon::S2_storerb_io:
- if (I->getOperand(0).getReg() == HRI->getStackRegister()) {
- int64_t Imm = I->getOperand(1).getImm();
- int64_t NewOff = Imm - (FrameSize + HEXAGON_LRFP_SIZE);
- if (HII->isValidOffset(Opc, NewOff)) {
- GlueAllocframeStore = true;
- // Since this store is to be glued with allocframe in the same
- // packet, it will use SP of the previous stack frame, i.e.
- // caller's SP. Therefore, we need to recalculate offset
- // according to this change.
- I->getOperand(1).setImm(NewOff);
+ if (I.getOperand(0).getReg() == HRI->getStackRegister()) {
+ // Since this store is to be glued with allocframe in the same
+ // packet, it will use SP of the previous stack frame, i.e.
+ // caller's SP. Therefore, we need to recalculate offset
+ // according to this change.
+ GlueAllocframeStore = useCallersSP(I);
+ if (GlueAllocframeStore)
continue;
- }
}
default:
break;
@@ -1414,12 +1465,12 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
// R0 = ... ; SUI
// Those cannot be packetized together, since the call will observe
// the effect of the assignment to R0.
- if (DepType == SDep::Anti && J->isCall()) {
+ if (DepType == SDep::Anti && J.isCall()) {
// Check if I defines any volatile register. We should also check
// registers that the call may read, but these happen to be a
// subset of the volatile register set.
- for (const MCPhysReg *P = J->getDesc().ImplicitDefs; P && *P; ++P) {
- if (!I->modifiesRegister(*P, HRI))
+ for (const MCPhysReg *P = J.getDesc().ImplicitDefs; P && *P; ++P) {
+ if (!I.modifiesRegister(*P, HRI))
continue;
FoundSequentialDependence = true;
break;
@@ -1447,9 +1498,9 @@ bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
}
bool HexagonPacketizerList::isLegalToPruneDependencies(SUnit *SUI, SUnit *SUJ) {
- MachineInstr *I = SUI->getInstr();
- MachineInstr *J = SUJ->getInstr();
- assert(I && J && "Unable to packetize null instruction!");
+ assert(SUI->getInstr() && SUJ->getInstr());
+ MachineInstr &I = *SUI->getInstr();
+ MachineInstr &J = *SUJ->getInstr();
if (cannotCoexist(I, J))
return false;
@@ -1467,16 +1518,15 @@ bool HexagonPacketizerList::isLegalToPruneDependencies(SUnit *SUI, SUnit *SUJ) {
// instruction. If so, restore its offset to its original value, i.e. use
// current SP instead of caller's SP.
if (GlueAllocframeStore) {
- unsigned FrameSize = MF.getFrameInfo()->getStackSize();
- MachineOperand &MOff = I->getOperand(1);
- MOff.setImm(MOff.getImm() + FrameSize + HEXAGON_LRFP_SIZE);
+ useCalleesSP(I);
+ GlueAllocframeStore = false;
}
return false;
}
MachineBasicBlock::iterator
HexagonPacketizerList::addToPacket(MachineInstr &MI) {
- MachineBasicBlock::iterator MII = MI;
+ MachineBasicBlock::iterator MII = MI.getIterator();
MachineBasicBlock *MBB = MI.getParent();
if (MI.isImplicitDef()) {
unsigned R = MI.getOperand(0).getReg();
@@ -1488,7 +1538,7 @@ HexagonPacketizerList::addToPacket(MachineInstr &MI) {
}
assert(ResourceTracker->canReserveResources(MI));
- bool ExtMI = HII->isExtended(&MI) || HII->isConstExtended(&MI);
+ bool ExtMI = HII->isExtended(MI) || HII->isConstExtended(MI);
bool Good = true;
if (GlueToNewValueJump) {
@@ -1501,7 +1551,7 @@ HexagonPacketizerList::addToPacket(MachineInstr &MI) {
if (ExtMI)
Good = tryAllocateResourcesForConstExt(true);
- bool ExtNvjMI = HII->isExtended(&NvjMI) || HII->isConstExtended(&NvjMI);
+ bool ExtNvjMI = HII->isExtended(NvjMI) || HII->isConstExtended(NvjMI);
if (Good) {
if (ResourceTracker->canReserveResources(NvjMI))
ResourceTracker->reserveResources(NvjMI);
@@ -1535,7 +1585,11 @@ HexagonPacketizerList::addToPacket(MachineInstr &MI) {
if (ExtMI && !tryAllocateResourcesForConstExt(true)) {
endPacket(MBB, MI);
if (PromotedToDotNew)
- demoteToDotOld(&MI);
+ demoteToDotOld(MI);
+ if (GlueAllocframeStore) {
+ useCalleesSP(MI);
+ GlueAllocframeStore = false;
+ }
ResourceTracker->reserveResources(MI);
reserveResourcesForConstExt();
}
@@ -1551,18 +1605,18 @@ void HexagonPacketizerList::endPacket(MachineBasicBlock *MBB,
}
bool HexagonPacketizerList::shouldAddToPacket(const MachineInstr &MI) {
- return !producesStall(&MI);
+ return !producesStall(MI);
}
// Return true when ConsMI uses a register defined by ProdMI.
-static bool isDependent(const MachineInstr *ProdMI,
- const MachineInstr *ConsMI) {
- if (!ProdMI->getOperand(0).isReg())
+static bool isDependent(const MachineInstr &ProdMI,
+ const MachineInstr &ConsMI) {
+ if (!ProdMI.getOperand(0).isReg())
return false;
- unsigned DstReg = ProdMI->getOperand(0).getReg();
+ unsigned DstReg = ProdMI.getOperand(0).getReg();
- for (auto &Op : ConsMI->operands())
+ for (auto &Op : ConsMI.operands())
if (Op.isReg() && Op.isUse() && Op.getReg() == DstReg)
// The MIs depend on each other.
return true;
@@ -1571,7 +1625,7 @@ static bool isDependent(const MachineInstr *ProdMI,
}
// V60 forward scheduling.
-bool HexagonPacketizerList::producesStall(const MachineInstr *I) {
+bool HexagonPacketizerList::producesStall(const MachineInstr &I) {
// Check whether the previous packet is in a different loop. If this is the
// case, there is little point in trying to avoid a stall because that would
// favor the rare case (loop entry) over the common case (loop iteration).
@@ -1581,7 +1635,7 @@ bool HexagonPacketizerList::producesStall(const MachineInstr *I) {
// backedge.
if (!OldPacketMIs.empty()) {
auto *OldBB = OldPacketMIs.front()->getParent();
- auto *ThisBB = I->getParent();
+ auto *ThisBB = I.getParent();
if (MLI->getLoopFor(OldBB) != MLI->getLoopFor(ThisBB))
return false;
}
@@ -1589,9 +1643,9 @@ bool HexagonPacketizerList::producesStall(const MachineInstr *I) {
// Check for stall between two vector instructions.
if (HII->isV60VectorInstruction(I)) {
for (auto J : OldPacketMIs) {
- if (!HII->isV60VectorInstruction(J))
+ if (!HII->isV60VectorInstruction(*J))
continue;
- if (isDependent(J, I) && !HII->isVecUsableNextPacket(J, I))
+ if (isDependent(*J, I) && !HII->isVecUsableNextPacket(*J, I))
return true;
}
return false;
@@ -1601,17 +1655,17 @@ bool HexagonPacketizerList::producesStall(const MachineInstr *I) {
// there is no definition of a use in the current packet, because it
// may be a candidate for .new.
for (auto J : CurrentPacketMIs)
- if (!HII->isV60VectorInstruction(J) && isDependent(J, I))
+ if (!HII->isV60VectorInstruction(*J) && isDependent(*J, I))
return false;
// Check for stall between I and instructions in the previous packet.
if (MF.getSubtarget<HexagonSubtarget>().useBSBScheduling()) {
for (auto J : OldPacketMIs) {
- if (HII->isV60VectorInstruction(J))
+ if (HII->isV60VectorInstruction(*J))
continue;
- if (!HII->isLateInstrFeedsEarlyInstr(J, I))
+ if (!HII->isLateInstrFeedsEarlyInstr(*J, I))
continue;
- if (isDependent(J, I) && !HII->canExecuteInBundle(J, I))
+ if (isDependent(*J, I) && !HII->canExecuteInBundle(*J, I))
return true;
}
}
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.h b/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.h
index 3f8ed5a..b28b926 100644
--- a/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.h
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.h
@@ -73,42 +73,44 @@ public:
void unpacketizeSoloInstrs(MachineFunction &MF);
protected:
- bool isCallDependent(const MachineInstr* MI, SDep::Kind DepType,
+ bool isCallDependent(const MachineInstr &MI, SDep::Kind DepType,
unsigned DepReg);
- bool promoteToDotCur(MachineInstr* MI, SDep::Kind DepType,
+ bool promoteToDotCur(MachineInstr &MI, SDep::Kind DepType,
MachineBasicBlock::iterator &MII,
- const TargetRegisterClass* RC);
- bool canPromoteToDotCur(const MachineInstr* MI, const SUnit* PacketSU,
+ const TargetRegisterClass *RC);
+ bool canPromoteToDotCur(const MachineInstr &MI, const SUnit *PacketSU,
unsigned DepReg, MachineBasicBlock::iterator &MII,
- const TargetRegisterClass* RC);
+ const TargetRegisterClass *RC);
void cleanUpDotCur();
- bool promoteToDotNew(MachineInstr* MI, SDep::Kind DepType,
+ bool promoteToDotNew(MachineInstr &MI, SDep::Kind DepType,
MachineBasicBlock::iterator &MII,
- const TargetRegisterClass* RC);
- bool canPromoteToDotNew(const MachineInstr* MI, const SUnit* PacketSU,
+ const TargetRegisterClass *RC);
+ bool canPromoteToDotNew(const MachineInstr &MI, const SUnit *PacketSU,
unsigned DepReg, MachineBasicBlock::iterator &MII,
- const TargetRegisterClass* RC);
- bool canPromoteToNewValue(const MachineInstr* MI, const SUnit* PacketSU,
+ const TargetRegisterClass *RC);
+ bool canPromoteToNewValue(const MachineInstr &MI, const SUnit *PacketSU,
unsigned DepReg, MachineBasicBlock::iterator &MII);
- bool canPromoteToNewValueStore(const MachineInstr* MI,
- const MachineInstr* PacketMI, unsigned DepReg);
- bool demoteToDotOld(MachineInstr* MI);
+ bool canPromoteToNewValueStore(const MachineInstr &MI,
+ const MachineInstr &PacketMI, unsigned DepReg);
+ bool demoteToDotOld(MachineInstr &MI);
+ bool useCallersSP(MachineInstr &MI);
+ void useCalleesSP(MachineInstr &MI);
bool arePredicatesComplements(MachineInstr &MI1, MachineInstr &MI2);
- bool restrictingDepExistInPacket(MachineInstr*, unsigned);
- bool isNewifiable(const MachineInstr *MI);
- bool isCurifiable(MachineInstr* MI);
- bool cannotCoexist(const MachineInstr *MI, const MachineInstr *MJ);
+ bool restrictingDepExistInPacket(MachineInstr&, unsigned);
+ bool isNewifiable(const MachineInstr &MI, const TargetRegisterClass *NewRC);
+ bool isCurifiable(MachineInstr &MI);
+ bool cannotCoexist(const MachineInstr &MI, const MachineInstr &MJ);
inline bool isPromotedToDotNew() const {
return PromotedToDotNew;
}
bool tryAllocateResourcesForConstExt(bool Reserve);
bool canReserveResourcesForConstExt();
void reserveResourcesForConstExt();
- bool hasDeadDependence(const MachineInstr *I, const MachineInstr *J);
- bool hasControlDependence(const MachineInstr *I, const MachineInstr *J);
- bool hasV4SpecificDependence(const MachineInstr *I, const MachineInstr *J);
- bool producesStall(const MachineInstr *MI);
+ bool hasDeadDependence(const MachineInstr &I, const MachineInstr &J);
+ bool hasControlDependence(const MachineInstr &I, const MachineInstr &J);
+ bool hasV4SpecificDependence(const MachineInstr &I, const MachineInstr &J);
+ bool producesStall(const MachineInstr &MI);
};
} // namespace llvm
#endif // HEXAGONVLIWPACKETIZER_H
diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonVectorPrint.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonVectorPrint.cpp
new file mode 100644
index 0000000..085d464
--- /dev/null
+++ b/contrib/llvm/lib/Target/Hexagon/HexagonVectorPrint.cpp
@@ -0,0 +1,209 @@
+//===-- HexagonVectorPrint.cpp - Generate vector printing instructions -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass adds the capability to generate pseudo vector/predicate register
+// printing instructions. These pseudo instructions should be used with the
+// simulator, NEVER on hardware.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "hexagon-vector-print"
+
+#include "HexagonInstrInfo.h"
+#include "HexagonSubtarget.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+static cl::opt<bool> TraceHexVectorStoresOnly("trace-hex-vector-stores-only",
+ cl::Hidden, cl::ZeroOrMore, cl::init(false),
+ cl::desc("Enables tracing of vector stores"));
+
+namespace llvm {
+
+ FunctionPass *createHexagonVectorPrint();
+ void initializeHexagonVectorPrintPass(PassRegistry&);
+
+} // end namespace llvm
+
+namespace {
+
+class HexagonVectorPrint : public MachineFunctionPass {
+ const HexagonSubtarget *QST;
+ const HexagonInstrInfo *QII;
+ const HexagonRegisterInfo *QRI;
+
+public:
+ static char ID;
+
+ HexagonVectorPrint()
+ : MachineFunctionPass(ID), QST(nullptr), QII(nullptr), QRI(nullptr) {
+ initializeHexagonVectorPrintPass(*PassRegistry::getPassRegistry());
+ }
+
+ StringRef getPassName() const override { return "Hexagon VectorPrint pass"; }
+
+ bool runOnMachineFunction(MachineFunction &Fn) override;
+};
+
+char HexagonVectorPrint::ID = 0;
+
+} // end anonymous namespace
+
+static bool isVecReg(unsigned Reg) {
+ return (Reg >= Hexagon::V0 && Reg <= Hexagon::V31)
+ || (Reg >= Hexagon::W0 && Reg <= Hexagon::W15)
+ || (Reg >= Hexagon::Q0 && Reg <= Hexagon::Q3);
+}
+
+static std::string getStringReg(unsigned R) {
+ if (R >= Hexagon::V0 && R <= Hexagon::V31) {
+ static const char* S[] = { "20", "21", "22", "23", "24", "25", "26", "27",
+ "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
+ "30", "31", "32", "33", "34", "35", "36", "37",
+ "38", "39", "3a", "3b", "3c", "3d", "3e", "3f"};
+ return S[R-Hexagon::V0];
+ }
+ if (R >= Hexagon::Q0 && R <= Hexagon::Q3) {
+ static const char* S[] = { "00", "01", "02", "03"};
+ return S[R-Hexagon::Q0];
+
+ }
+ llvm_unreachable("valid vreg");
+}
+
+static void addAsmInstr(MachineBasicBlock *MBB, unsigned Reg,
+ MachineBasicBlock::instr_iterator I,
+ const DebugLoc &DL, const HexagonInstrInfo *QII,
+ MachineFunction &Fn) {
+
+ std::string VDescStr = ".long 0x1dffe0" + getStringReg(Reg);
+ const char *cstr = Fn.createExternalSymbolName(VDescStr);
+ unsigned ExtraInfo = InlineAsm::Extra_HasSideEffects;
+ BuildMI(*MBB, I, DL, QII->get(TargetOpcode::INLINEASM))
+ .addExternalSymbol(cstr)
+ .addImm(ExtraInfo);
+}
+
+static bool getInstrVecReg(const MachineInstr &MI, unsigned &Reg) {
+ if (MI.getNumOperands() < 1) return false;
+ // Vec load or compute.
+ if (MI.getOperand(0).isReg() && MI.getOperand(0).isDef()) {
+ Reg = MI.getOperand(0).getReg();
+ if (isVecReg(Reg))
+ return !TraceHexVectorStoresOnly;
+ }
+ // Vec store.
+ if (MI.mayStore() && MI.getNumOperands() >= 3 && MI.getOperand(2).isReg()) {
+ Reg = MI.getOperand(2).getReg();
+ if (isVecReg(Reg))
+ return true;
+ }
+ // Vec store post increment.
+ if (MI.mayStore() && MI.getNumOperands() >= 4 && MI.getOperand(3).isReg()) {
+ Reg = MI.getOperand(3).getReg();
+ if (isVecReg(Reg))
+ return true;
+ }
+ return false;
+}
+
+bool HexagonVectorPrint::runOnMachineFunction(MachineFunction &Fn) {
+ bool Changed = false;
+ QST = &Fn.getSubtarget<HexagonSubtarget>();
+ QRI = QST->getRegisterInfo();
+ QII = QST->getInstrInfo();
+ std::vector<MachineInstr *> VecPrintList;
+ for (auto &MBB : Fn)
+ for (auto &MI : MBB) {
+ if (MI.isBundle()) {
+ MachineBasicBlock::instr_iterator MII = MI.getIterator();
+ for (++MII; MII != MBB.instr_end() && MII->isInsideBundle(); ++MII) {
+ if (MII->getNumOperands() < 1)
+ continue;
+ unsigned Reg = 0;
+ if (getInstrVecReg(*MII, Reg)) {
+ VecPrintList.push_back((&*MII));
+ DEBUG(dbgs() << "Found vector reg inside bundle \n"; MII->dump());
+ }
+ }
+ } else {
+ unsigned Reg = 0;
+ if (getInstrVecReg(MI, Reg)) {
+ VecPrintList.push_back(&MI);
+ DEBUG(dbgs() << "Found vector reg \n"; MI.dump());
+ }
+ }
+ }
+
+ Changed = !VecPrintList.empty();
+ if (!Changed)
+ return Changed;
+
+ for (auto *I : VecPrintList) {
+ DebugLoc DL = I->getDebugLoc();
+ MachineBasicBlock *MBB = I->getParent();
+ DEBUG(dbgs() << "Evaluating V MI\n"; I->dump());
+ unsigned Reg = 0;
+ if (!getInstrVecReg(*I, Reg))
+ llvm_unreachable("Need a vector reg");
+ MachineBasicBlock::instr_iterator MII = I->getIterator();
+ if (I->isInsideBundle()) {
+ DEBUG(dbgs() << "add to end of bundle\n"; I->dump());
+ while (MBB->instr_end() != MII && MII->isInsideBundle())
+ MII++;
+ } else {
+ DEBUG(dbgs() << "add after instruction\n"; I->dump());
+ MII++;
+ }
+ if (MBB->instr_end() == MII)
+ continue;
+
+ if (Reg >= Hexagon::V0 && Reg <= Hexagon::V31) {
+ DEBUG(dbgs() << "adding dump for V" << Reg-Hexagon::V0 << '\n');
+ addAsmInstr(MBB, Reg, MII, DL, QII, Fn);
+ } else if (Reg >= Hexagon::W0 && Reg <= Hexagon::W15) {
+ DEBUG(dbgs() << "adding dump for W" << Reg-Hexagon::W0 << '\n');
+ addAsmInstr(MBB, Hexagon::V0 + (Reg - Hexagon::W0) * 2 + 1,
+ MII, DL, QII, Fn);
+ addAsmInstr(MBB, Hexagon::V0 + (Reg - Hexagon::W0) * 2,
+ MII, DL, QII, Fn);
+ } else if (Reg >= Hexagon::Q0 && Reg <= Hexagon::Q3) {
+ DEBUG(dbgs() << "adding dump for Q" << Reg-Hexagon::Q0 << '\n');
+ addAsmInstr(MBB, Reg, MII, DL, QII, Fn);
+ } else
+ llvm_unreachable("Bad Vector reg");
+ }
+ return Changed;
+}
+
+//===----------------------------------------------------------------------===//
+// Public Constructor Functions
+//===----------------------------------------------------------------------===//
+INITIALIZE_PASS(HexagonVectorPrint, "hexagon-vector-print",
+ "Hexagon VectorPrint pass", false, false)
+
+FunctionPass *llvm::createHexagonVectorPrint() {
+ return new HexagonVectorPrint();
+}
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
index 2898b05..c140bd1 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
@@ -569,8 +569,8 @@ public:
if (!Resolved) {
switch ((unsigned)Fixup.getKind()) {
case fixup_Hexagon_B22_PCREL:
- // GetFixupCount assumes B22 won't relax
- // Fallthrough
+ // GetFixupCount assumes B22 won't relax
+ LLVM_FALLTHROUGH;
default:
return false;
break;
@@ -745,7 +745,8 @@ public:
namespace llvm {
MCAsmBackend *createHexagonAsmBackend(Target const &T,
MCRegisterInfo const & /*MRI*/,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
return new HexagonAsmBackend(T, OSABI, CPU);
}
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h
index c63f044..4292f6b 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h
@@ -41,7 +41,7 @@ namespace HexagonII {
TypeST = 6,
TypeSYSTEM = 7,
TypeXTYPE = 8,
- TypeMEMOP = 9,
+ TypeV4LDST = 9,
TypeNV = 10,
TypeDUPLEX = 11,
TypeCOMPOUND = 12,
@@ -92,7 +92,7 @@ namespace HexagonII {
// MemAccessSize is represented as 1+log2(N) where N is size in bits.
enum class MemAccessSize {
- NoMemAccess = 0, // Not a memory acces instruction.
+ NoMemAccess = 0, // Not a memory access instruction.
ByteAccess = 1, // Byte access instruction (memb).
HalfWordAccess = 2, // Half word access instruction (memh).
WordAccess = 3, // Word access instruction (memw).
@@ -201,9 +201,12 @@ namespace HexagonII {
AccumulatorPos = 54,
AccumulatorMask = 0x1,
- // Complex XU, prevent xu competition by prefering slot3
+ // Complex XU, prevent xu competition by preferring slot3
PrefersSlot3Pos = 55,
PrefersSlot3Mask = 0x1,
+
+ CofMax1Pos = 60,
+ CofMax1Mask = 0x1
};
// *** The code above must match HexagonInstrFormat*.td *** //
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp
index 9e2c280..c619c36 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCAsmInfo.cpp
@@ -22,7 +22,6 @@ HexagonMCAsmInfo::HexagonMCAsmInfo(const Triple &TT) {
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";
Data64bitsDirective = nullptr; // .xword is only supported by V9.
- ZeroDirective = "\t.skip\t";
CommentString = "//";
LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment;
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp
index 39b828d..2645a17 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.cpp
@@ -78,6 +78,9 @@ void HexagonMCCodeEmitter::encodeInstruction(MCInst const &MI, raw_ostream &OS,
size_t Last = HexagonMCInstrInfo::bundleSize(HMB) - 1;
for (auto &I : HexagonMCInstrInfo::bundleInstructions(HMB)) {
MCInst &HMI = const_cast<MCInst &>(*I.getInst());
+ verifyInstructionPredicates(HMI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
EncodeSingleInstruction(HMI, OS, Fixups, STI,
parseBits(Instruction, Last, HMB, HMI),
Instruction);
@@ -817,4 +820,5 @@ MCCodeEmitter *llvm::createHexagonMCCodeEmitter(MCInstrInfo const &MII,
return new HexagonMCCodeEmitter(MII, MCT);
}
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "HexagonGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
index 2a154da..8e0667d 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCodeEmitter.h
@@ -63,6 +63,11 @@ public:
unsigned getMachineOpValue(MCInst const &MI, MCOperand const &MO,
SmallVectorImpl<MCFixup> &Fixups,
MCSubtargetInfo const &STI) const;
+
+private:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
}; // class HexagonMCCodeEmitter
} // namespace llvm
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp
index d194bea..9a09a17 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCCompound.cpp
@@ -1,5 +1,4 @@
-
-//=== HexagonMCCompound.cpp - Hexagon Compound checker -------===//
+//=== HexagonMCCompound.cpp - Hexagon Compound checker -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,18 +10,17 @@
// This file is looks at a packet and tries to form compound insns
//
//===----------------------------------------------------------------------===//
+
#include "Hexagon.h"
#include "MCTargetDesc/HexagonBaseInfo.h"
-#include "MCTargetDesc/HexagonMCShuffler.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/MC/MCAssembler.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCSectionELF.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
using namespace llvm;
using namespace Hexagon;
@@ -79,8 +77,7 @@ static const unsigned cmpgtn1BitOpcode[8] = {
};
// enum HexagonII::CompoundGroup
-namespace {
-unsigned getCompoundCandidateGroup(MCInst const &MI, bool IsExtended) {
+static unsigned getCompoundCandidateGroup(MCInst const &MI, bool IsExtended) {
unsigned DstReg, SrcReg, Src1Reg, Src2Reg;
switch (MI.getOpcode()) {
@@ -173,11 +170,9 @@ unsigned getCompoundCandidateGroup(MCInst const &MI, bool IsExtended) {
return HexagonII::HCG_None;
}
-}
/// getCompoundOp - Return the index from 0-7 into the above opcode lists.
-namespace {
-unsigned getCompoundOp(MCInst const &HMCI) {
+static unsigned getCompoundOp(MCInst const &HMCI) {
const MCOperand &Predicate = HMCI.getOperand(0);
unsigned PredReg = Predicate.getReg();
@@ -198,11 +193,10 @@ unsigned getCompoundOp(MCInst const &HMCI) {
return (PredReg == Hexagon::P0) ? tp0_jump_t : tp1_jump_t;
}
}
-}
-namespace {
-MCInst *getCompoundInsn(MCContext &Context, MCInst const &L, MCInst const &R) {
- MCInst *CompoundInsn = 0;
+static MCInst *getCompoundInsn(MCContext &Context, MCInst const &L,
+ MCInst const &R) {
+ MCInst *CompoundInsn = nullptr;
unsigned compoundOpcode;
MCOperand Rs, Rt;
int64_t Value;
@@ -290,8 +284,7 @@ MCInst *getCompoundInsn(MCContext &Context, MCInst const &L, MCInst const &R) {
CompoundInsn = new (Context) MCInst;
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
- if (Value != -1)
- CompoundInsn->addOperand(L.getOperand(2));
+ CompoundInsn->addOperand(L.getOperand(2));
CompoundInsn->addOperand(R.getOperand(1));
break;
@@ -309,8 +302,7 @@ MCInst *getCompoundInsn(MCContext &Context, MCInst const &L, MCInst const &R) {
CompoundInsn = new (Context) MCInst;
CompoundInsn->setOpcode(compoundOpcode);
CompoundInsn->addOperand(Rs);
- if (Value != -1)
- CompoundInsn->addOperand(L.getOperand(2));
+ CompoundInsn->addOperand(L.getOperand(2));
CompoundInsn->addOperand(R.getOperand(1));
break;
@@ -338,12 +330,10 @@ MCInst *getCompoundInsn(MCContext &Context, MCInst const &L, MCInst const &R) {
return CompoundInsn;
}
-}
/// Non-Symmetrical. See if these two instructions are fit for compound pair.
-namespace {
-bool isOrderedCompoundPair(MCInst const &MIa, bool IsExtendedA,
- MCInst const &MIb, bool IsExtendedB) {
+static bool isOrderedCompoundPair(MCInst const &MIa, bool IsExtendedA,
+ MCInst const &MIb, bool IsExtendedB) {
unsigned MIaG = getCompoundCandidateGroup(MIa, IsExtendedA);
unsigned MIbG = getCompoundCandidateGroup(MIb, IsExtendedB);
// We have two candidates - check that this is the same register
@@ -355,10 +345,9 @@ bool isOrderedCompoundPair(MCInst const &MIa, bool IsExtendedA,
return ((MIaG == HexagonII::HCG_A && MIbG == HexagonII::HCG_B) &&
(MIa.getOperand(0).getReg() == MIb.getOperand(0).getReg()));
}
-}
-namespace {
-bool lookForCompound(MCInstrInfo const &MCII, MCContext &Context, MCInst &MCI) {
+static bool lookForCompound(MCInstrInfo const &MCII, MCContext &Context,
+ MCInst &MCI) {
assert(HexagonMCInstrInfo::isBundle(MCI));
bool JExtended = false;
for (MCInst::iterator J =
@@ -369,8 +358,7 @@ bool lookForCompound(MCInstrInfo const &MCII, MCContext &Context, MCInst &MCI) {
JExtended = true;
continue;
}
- if (llvm::HexagonMCInstrInfo::getType(MCII, *JumpInst) ==
- HexagonII::TypeJ) {
+ if (HexagonMCInstrInfo::getType(MCII, *JumpInst) == HexagonII::TypeJ) {
// Try to pair with another insn (B)undled with jump.
bool BExtended = false;
for (MCInst::iterator B =
@@ -403,7 +391,6 @@ bool lookForCompound(MCInstrInfo const &MCII, MCContext &Context, MCInst &MCI) {
}
return false;
}
-}
/// tryCompound - Given a bundle check for compound insns when one
/// is found update the contents fo the bundle with the compound insn.
@@ -422,6 +409,4 @@ void HexagonMCInstrInfo::tryCompound(MCInstrInfo const &MCII,
// a compound is found.
while (lookForCompound(MCII, Context, MCI))
;
-
- return;
}
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp
index 8833621..413f052 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp
@@ -27,58 +27,58 @@ using namespace Hexagon;
// pair table of subInstructions with opcodes
static const std::pair<unsigned, unsigned> opcodeData[] = {
- std::make_pair((unsigned)V4_SA1_addi, 0),
- std::make_pair((unsigned)V4_SA1_addrx, 6144),
- std::make_pair((unsigned)V4_SA1_addsp, 3072),
- std::make_pair((unsigned)V4_SA1_and1, 4608),
- std::make_pair((unsigned)V4_SA1_clrf, 6768),
- std::make_pair((unsigned)V4_SA1_clrfnew, 6736),
- std::make_pair((unsigned)V4_SA1_clrt, 6752),
- std::make_pair((unsigned)V4_SA1_clrtnew, 6720),
- std::make_pair((unsigned)V4_SA1_cmpeqi, 6400),
- std::make_pair((unsigned)V4_SA1_combine0i, 7168),
- std::make_pair((unsigned)V4_SA1_combine1i, 7176),
- std::make_pair((unsigned)V4_SA1_combine2i, 7184),
- std::make_pair((unsigned)V4_SA1_combine3i, 7192),
- std::make_pair((unsigned)V4_SA1_combinerz, 7432),
- std::make_pair((unsigned)V4_SA1_combinezr, 7424),
- std::make_pair((unsigned)V4_SA1_dec, 4864),
- std::make_pair((unsigned)V4_SA1_inc, 4352),
- std::make_pair((unsigned)V4_SA1_seti, 2048),
- std::make_pair((unsigned)V4_SA1_setin1, 6656),
- std::make_pair((unsigned)V4_SA1_sxtb, 5376),
- std::make_pair((unsigned)V4_SA1_sxth, 5120),
- std::make_pair((unsigned)V4_SA1_tfr, 4096),
- std::make_pair((unsigned)V4_SA1_zxtb, 5888),
- std::make_pair((unsigned)V4_SA1_zxth, 5632),
- std::make_pair((unsigned)V4_SL1_loadri_io, 0),
- std::make_pair((unsigned)V4_SL1_loadrub_io, 4096),
- std::make_pair((unsigned)V4_SL2_deallocframe, 7936),
- std::make_pair((unsigned)V4_SL2_jumpr31, 8128),
- std::make_pair((unsigned)V4_SL2_jumpr31_f, 8133),
- std::make_pair((unsigned)V4_SL2_jumpr31_fnew, 8135),
- std::make_pair((unsigned)V4_SL2_jumpr31_t, 8132),
- std::make_pair((unsigned)V4_SL2_jumpr31_tnew, 8134),
- std::make_pair((unsigned)V4_SL2_loadrb_io, 4096),
- std::make_pair((unsigned)V4_SL2_loadrd_sp, 7680),
- std::make_pair((unsigned)V4_SL2_loadrh_io, 0),
- std::make_pair((unsigned)V4_SL2_loadri_sp, 7168),
- std::make_pair((unsigned)V4_SL2_loadruh_io, 2048),
- std::make_pair((unsigned)V4_SL2_return, 8000),
- std::make_pair((unsigned)V4_SL2_return_f, 8005),
- std::make_pair((unsigned)V4_SL2_return_fnew, 8007),
- std::make_pair((unsigned)V4_SL2_return_t, 8004),
- std::make_pair((unsigned)V4_SL2_return_tnew, 8006),
- std::make_pair((unsigned)V4_SS1_storeb_io, 4096),
- std::make_pair((unsigned)V4_SS1_storew_io, 0),
- std::make_pair((unsigned)V4_SS2_allocframe, 7168),
- std::make_pair((unsigned)V4_SS2_storebi0, 4608),
- std::make_pair((unsigned)V4_SS2_storebi1, 4864),
- std::make_pair((unsigned)V4_SS2_stored_sp, 2560),
- std::make_pair((unsigned)V4_SS2_storeh_io, 0),
- std::make_pair((unsigned)V4_SS2_storew_sp, 2048),
- std::make_pair((unsigned)V4_SS2_storewi0, 4096),
- std::make_pair((unsigned)V4_SS2_storewi1, 4352)};
+ std::make_pair((unsigned)SA1_addi, 0),
+ std::make_pair((unsigned)SA1_addrx, 6144),
+ std::make_pair((unsigned)SA1_addsp, 3072),
+ std::make_pair((unsigned)SA1_and1, 4608),
+ std::make_pair((unsigned)SA1_clrf, 6768),
+ std::make_pair((unsigned)SA1_clrfnew, 6736),
+ std::make_pair((unsigned)SA1_clrt, 6752),
+ std::make_pair((unsigned)SA1_clrtnew, 6720),
+ std::make_pair((unsigned)SA1_cmpeqi, 6400),
+ std::make_pair((unsigned)SA1_combine0i, 7168),
+ std::make_pair((unsigned)SA1_combine1i, 7176),
+ std::make_pair((unsigned)SA1_combine2i, 7184),
+ std::make_pair((unsigned)SA1_combine3i, 7192),
+ std::make_pair((unsigned)SA1_combinerz, 7432),
+ std::make_pair((unsigned)SA1_combinezr, 7424),
+ std::make_pair((unsigned)SA1_dec, 4864),
+ std::make_pair((unsigned)SA1_inc, 4352),
+ std::make_pair((unsigned)SA1_seti, 2048),
+ std::make_pair((unsigned)SA1_setin1, 6656),
+ std::make_pair((unsigned)SA1_sxtb, 5376),
+ std::make_pair((unsigned)SA1_sxth, 5120),
+ std::make_pair((unsigned)SA1_tfr, 4096),
+ std::make_pair((unsigned)SA1_zxtb, 5888),
+ std::make_pair((unsigned)SA1_zxth, 5632),
+ std::make_pair((unsigned)SL1_loadri_io, 0),
+ std::make_pair((unsigned)SL1_loadrub_io, 4096),
+ std::make_pair((unsigned)SL2_deallocframe, 7936),
+ std::make_pair((unsigned)SL2_jumpr31, 8128),
+ std::make_pair((unsigned)SL2_jumpr31_f, 8133),
+ std::make_pair((unsigned)SL2_jumpr31_fnew, 8135),
+ std::make_pair((unsigned)SL2_jumpr31_t, 8132),
+ std::make_pair((unsigned)SL2_jumpr31_tnew, 8134),
+ std::make_pair((unsigned)SL2_loadrb_io, 4096),
+ std::make_pair((unsigned)SL2_loadrd_sp, 7680),
+ std::make_pair((unsigned)SL2_loadrh_io, 0),
+ std::make_pair((unsigned)SL2_loadri_sp, 7168),
+ std::make_pair((unsigned)SL2_loadruh_io, 2048),
+ std::make_pair((unsigned)SL2_return, 8000),
+ std::make_pair((unsigned)SL2_return_f, 8005),
+ std::make_pair((unsigned)SL2_return_fnew, 8007),
+ std::make_pair((unsigned)SL2_return_t, 8004),
+ std::make_pair((unsigned)SL2_return_tnew, 8006),
+ std::make_pair((unsigned)SS1_storeb_io, 4096),
+ std::make_pair((unsigned)SS1_storew_io, 0),
+ std::make_pair((unsigned)SS2_allocframe, 7168),
+ std::make_pair((unsigned)SS2_storebi0, 4608),
+ std::make_pair((unsigned)SS2_storebi1, 4864),
+ std::make_pair((unsigned)SS2_stored_sp, 2560),
+ std::make_pair((unsigned)SS2_storeh_io, 0),
+ std::make_pair((unsigned)SS2_storew_sp, 2048),
+ std::make_pair((unsigned)SS2_storewi0, 4096),
+ std::make_pair((unsigned)SS2_storewi1, 4352)};
bool HexagonMCInstrInfo::isDuplexPairMatch(unsigned Ga, unsigned Gb) {
switch (Ga) {
@@ -262,25 +262,19 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) {
case Hexagon::EH_RETURN_JMPR:
case Hexagon::J2_jumpr:
- case Hexagon::JMPret:
// jumpr r31
// Actual form JMPR %PC<imp-def>, %R31<imp-use>, %R0<imp-use,internal>.
DstReg = MCI.getOperand(0).getReg();
- if (Hexagon::R31 == DstReg) {
+ if (Hexagon::R31 == DstReg)
return HexagonII::HSIG_L2;
- }
break;
case Hexagon::J2_jumprt:
case Hexagon::J2_jumprf:
case Hexagon::J2_jumprtnew:
case Hexagon::J2_jumprfnew:
- case Hexagon::JMPrett:
- case Hexagon::JMPretf:
- case Hexagon::JMPrettnew:
- case Hexagon::JMPretfnew:
- case Hexagon::JMPrettnewpt:
- case Hexagon::JMPretfnewpt:
+ case Hexagon::J2_jumprtnewpt:
+ case Hexagon::J2_jumprfnewpt:
DstReg = MCI.getOperand(1).getReg();
SrcReg = MCI.getOperand(0).getReg();
// [if ([!]p0[.new])] jumpr r31
@@ -679,6 +673,7 @@ inline static void addOps(MCInst &subInstPtr, MCInst const &Inst,
case Hexagon::D9:
case Hexagon::D10:
case Hexagon::D11:
+ case Hexagon::P0:
subInstPtr.addOperand(Inst.getOperand(opNum));
break;
}
@@ -699,54 +694,54 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) {
Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value);
assert(Absolute);(void)Absolute;
if (Value == 1) {
- Result.setOpcode(Hexagon::V4_SA1_inc);
+ Result.setOpcode(Hexagon::SA1_inc);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break;
} // 1,2 SUBInst $Rd = add($Rs, #1)
else if (Value == -1) {
- Result.setOpcode(Hexagon::V4_SA1_dec);
+ Result.setOpcode(Hexagon::SA1_dec);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break;
} // 1,2 SUBInst $Rd = add($Rs,#-1)
else if (Inst.getOperand(1).getReg() == Hexagon::R29) {
- Result.setOpcode(Hexagon::V4_SA1_addsp);
+ Result.setOpcode(Hexagon::SA1_addsp);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break;
} // 1,3 SUBInst $Rd = add(r29, #$u6_2)
else {
- Result.setOpcode(Hexagon::V4_SA1_addi);
+ Result.setOpcode(Hexagon::SA1_addi);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break;
} // 1,2,3 SUBInst $Rx = add($Rx, #$s7)
case Hexagon::A2_add:
- Result.setOpcode(Hexagon::V4_SA1_addrx);
+ Result.setOpcode(Hexagon::SA1_addrx);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1,2,3 SUBInst $Rx = add($_src_, $Rs)
case Hexagon::S2_allocframe:
- Result.setOpcode(Hexagon::V4_SS2_allocframe);
+ Result.setOpcode(Hexagon::SS2_allocframe);
addOps(Result, Inst, 0);
break; // 1 SUBInst allocframe(#$u5_3)
case Hexagon::A2_andir:
if (minConstant(Inst, 2) == 255) {
- Result.setOpcode(Hexagon::V4_SA1_zxtb);
+ Result.setOpcode(Hexagon::SA1_zxtb);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 $Rd = and($Rs, #255)
} else {
- Result.setOpcode(Hexagon::V4_SA1_and1);
+ Result.setOpcode(Hexagon::SA1_and1);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rd = and($Rs, #1)
}
case Hexagon::C2_cmpeqi:
- Result.setOpcode(Hexagon::V4_SA1_cmpeqi);
+ Result.setOpcode(Hexagon::SA1_cmpeqi);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 2,3 SUBInst p0 = cmp.eq($Rs, #$u2)
@@ -755,120 +750,115 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) {
Absolute = Inst.getOperand(1).getExpr()->evaluateAsAbsolute(Value);
assert(Absolute);(void)Absolute;
if (Value == 1) {
- Result.setOpcode(Hexagon::V4_SA1_combine1i);
+ Result.setOpcode(Hexagon::SA1_combine1i);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 1,3 SUBInst $Rdd = combine(#1, #$u2)
}
if (Value == 3) {
- Result.setOpcode(Hexagon::V4_SA1_combine3i);
+ Result.setOpcode(Hexagon::SA1_combine3i);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 1,3 SUBInst $Rdd = combine(#3, #$u2)
}
if (Value == 0) {
- Result.setOpcode(Hexagon::V4_SA1_combine0i);
+ Result.setOpcode(Hexagon::SA1_combine0i);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 1,3 SUBInst $Rdd = combine(#0, #$u2)
}
if (Value == 2) {
- Result.setOpcode(Hexagon::V4_SA1_combine2i);
+ Result.setOpcode(Hexagon::SA1_combine2i);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 1,3 SUBInst $Rdd = combine(#2, #$u2)
}
case Hexagon::A4_combineir:
- Result.setOpcode(Hexagon::V4_SA1_combinezr);
+ Result.setOpcode(Hexagon::SA1_combinezr);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 1,3 SUBInst $Rdd = combine(#0, $Rs)
case Hexagon::A4_combineri:
- Result.setOpcode(Hexagon::V4_SA1_combinerz);
+ Result.setOpcode(Hexagon::SA1_combinerz);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rdd = combine($Rs, #0)
case Hexagon::L4_return_tnew_pnt:
case Hexagon::L4_return_tnew_pt:
- Result.setOpcode(Hexagon::V4_SL2_return_tnew);
+ Result.setOpcode(Hexagon::SL2_return_tnew);
break; // none SUBInst if (p0.new) dealloc_return:nt
case Hexagon::L4_return_fnew_pnt:
case Hexagon::L4_return_fnew_pt:
- Result.setOpcode(Hexagon::V4_SL2_return_fnew);
+ Result.setOpcode(Hexagon::SL2_return_fnew);
break; // none SUBInst if (!p0.new) dealloc_return:nt
case Hexagon::L4_return_f:
- Result.setOpcode(Hexagon::V4_SL2_return_f);
+ Result.setOpcode(Hexagon::SL2_return_f);
break; // none SUBInst if (!p0) dealloc_return
case Hexagon::L4_return_t:
- Result.setOpcode(Hexagon::V4_SL2_return_t);
+ Result.setOpcode(Hexagon::SL2_return_t);
break; // none SUBInst if (p0) dealloc_return
case Hexagon::L4_return:
- Result.setOpcode(Hexagon::V4_SL2_return);
+ Result.setOpcode(Hexagon::SL2_return);
break; // none SUBInst dealloc_return
case Hexagon::L2_deallocframe:
- Result.setOpcode(Hexagon::V4_SL2_deallocframe);
+ Result.setOpcode(Hexagon::SL2_deallocframe);
break; // none SUBInst deallocframe
case Hexagon::EH_RETURN_JMPR:
case Hexagon::J2_jumpr:
- case Hexagon::JMPret:
- Result.setOpcode(Hexagon::V4_SL2_jumpr31);
+ Result.setOpcode(Hexagon::SL2_jumpr31);
break; // none SUBInst jumpr r31
case Hexagon::J2_jumprf:
- case Hexagon::JMPretf:
- Result.setOpcode(Hexagon::V4_SL2_jumpr31_f);
+ Result.setOpcode(Hexagon::SL2_jumpr31_f);
break; // none SUBInst if (!p0) jumpr r31
case Hexagon::J2_jumprfnew:
- case Hexagon::JMPretfnewpt:
- case Hexagon::JMPretfnew:
- Result.setOpcode(Hexagon::V4_SL2_jumpr31_fnew);
+ case Hexagon::J2_jumprfnewpt:
+ Result.setOpcode(Hexagon::SL2_jumpr31_fnew);
break; // none SUBInst if (!p0.new) jumpr:nt r31
case Hexagon::J2_jumprt:
- case Hexagon::JMPrett:
- Result.setOpcode(Hexagon::V4_SL2_jumpr31_t);
+ Result.setOpcode(Hexagon::SL2_jumpr31_t);
break; // none SUBInst if (p0) jumpr r31
case Hexagon::J2_jumprtnew:
- case Hexagon::JMPrettnewpt:
- case Hexagon::JMPrettnew:
- Result.setOpcode(Hexagon::V4_SL2_jumpr31_tnew);
+ case Hexagon::J2_jumprtnewpt:
+ Result.setOpcode(Hexagon::SL2_jumpr31_tnew);
break; // none SUBInst if (p0.new) jumpr:nt r31
case Hexagon::L2_loadrb_io:
- Result.setOpcode(Hexagon::V4_SL2_loadrb_io);
+ Result.setOpcode(Hexagon::SL2_loadrb_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1,2,3 SUBInst $Rd = memb($Rs + #$u3_0)
case Hexagon::L2_loadrd_io:
- Result.setOpcode(Hexagon::V4_SL2_loadrd_sp);
+ Result.setOpcode(Hexagon::SL2_loadrd_sp);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 1,3 SUBInst $Rdd = memd(r29 + #$u5_3)
case Hexagon::L2_loadrh_io:
- Result.setOpcode(Hexagon::V4_SL2_loadrh_io);
+ Result.setOpcode(Hexagon::SL2_loadrh_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1,2,3 SUBInst $Rd = memh($Rs + #$u3_1)
case Hexagon::L2_loadrub_io:
- Result.setOpcode(Hexagon::V4_SL1_loadrub_io);
+ Result.setOpcode(Hexagon::SL1_loadrub_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1,2,3 SUBInst $Rd = memub($Rs + #$u4_0)
case Hexagon::L2_loadruh_io:
- Result.setOpcode(Hexagon::V4_SL2_loadruh_io);
+ Result.setOpcode(Hexagon::SL2_loadruh_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1,2,3 SUBInst $Rd = memuh($Rs + #$u3_1)
case Hexagon::L2_loadri_io:
if (Inst.getOperand(1).getReg() == Hexagon::R29) {
- Result.setOpcode(Hexagon::V4_SL2_loadri_sp);
+ Result.setOpcode(Hexagon::SL2_loadri_sp);
addOps(Result, Inst, 0);
addOps(Result, Inst, 2);
break; // 2 1,3 SUBInst $Rd = memw(r29 + #$u5_2)
} else {
- Result.setOpcode(Hexagon::V4_SL1_loadri_io);
+ Result.setOpcode(Hexagon::SL1_loadri_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
@@ -878,29 +868,29 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) {
Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value);
assert(Absolute);(void)Absolute;
if (Value == 0) {
- Result.setOpcode(Hexagon::V4_SS2_storebi0);
+ Result.setOpcode(Hexagon::SS2_storebi0);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst memb($Rs + #$u4_0)=#0
} else if (Value == 1) {
- Result.setOpcode(Hexagon::V4_SS2_storebi1);
+ Result.setOpcode(Hexagon::SS2_storebi1);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 2 1,2 SUBInst memb($Rs + #$u4_0)=#1
}
case Hexagon::S2_storerb_io:
- Result.setOpcode(Hexagon::V4_SS1_storeb_io);
+ Result.setOpcode(Hexagon::SS1_storeb_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1,2,3 SUBInst memb($Rs + #$u4_0) = $Rt
case Hexagon::S2_storerd_io:
- Result.setOpcode(Hexagon::V4_SS2_stored_sp);
+ Result.setOpcode(Hexagon::SS2_stored_sp);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 2,3 SUBInst memd(r29 + #$s6_3) = $Rtt
case Hexagon::S2_storerh_io:
- Result.setOpcode(Hexagon::V4_SS2_storeh_io);
+ Result.setOpcode(Hexagon::SS2_storeh_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
@@ -909,84 +899,88 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) {
Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value);
assert(Absolute);(void)Absolute;
if (Value == 0) {
- Result.setOpcode(Hexagon::V4_SS2_storewi0);
+ Result.setOpcode(Hexagon::SS2_storewi0);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 3 1,2 SUBInst memw($Rs + #$u4_2)=#0
} else if (Value == 1) {
- Result.setOpcode(Hexagon::V4_SS2_storewi1);
+ Result.setOpcode(Hexagon::SS2_storewi1);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 3 1,2 SUBInst memw($Rs + #$u4_2)=#1
} else if (Inst.getOperand(0).getReg() == Hexagon::R29) {
- Result.setOpcode(Hexagon::V4_SS2_storew_sp);
+ Result.setOpcode(Hexagon::SS2_storew_sp);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2);
break; // 1 2,3 SUBInst memw(r29 + #$u5_2) = $Rt
}
case Hexagon::S2_storeri_io:
if (Inst.getOperand(0).getReg() == Hexagon::R29) {
- Result.setOpcode(Hexagon::V4_SS2_storew_sp);
+ Result.setOpcode(Hexagon::SS2_storew_sp);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2); // 1,2,3 SUBInst memw(sp + #$u5_2) = $Rt
} else {
- Result.setOpcode(Hexagon::V4_SS1_storew_io);
+ Result.setOpcode(Hexagon::SS1_storew_io);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
addOps(Result, Inst, 2); // 1,2,3 SUBInst memw($Rs + #$u4_2) = $Rt
}
break;
case Hexagon::A2_sxtb:
- Result.setOpcode(Hexagon::V4_SA1_sxtb);
+ Result.setOpcode(Hexagon::SA1_sxtb);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rd = sxtb($Rs)
case Hexagon::A2_sxth:
- Result.setOpcode(Hexagon::V4_SA1_sxth);
+ Result.setOpcode(Hexagon::SA1_sxth);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rd = sxth($Rs)
case Hexagon::A2_tfr:
- Result.setOpcode(Hexagon::V4_SA1_tfr);
+ Result.setOpcode(Hexagon::SA1_tfr);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rd = $Rs
case Hexagon::C2_cmovenewif:
- Result.setOpcode(Hexagon::V4_SA1_clrfnew);
+ Result.setOpcode(Hexagon::SA1_clrfnew);
addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
break; // 2 SUBInst if (!p0.new) $Rd = #0
case Hexagon::C2_cmovenewit:
- Result.setOpcode(Hexagon::V4_SA1_clrtnew);
+ Result.setOpcode(Hexagon::SA1_clrtnew);
addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
break; // 2 SUBInst if (p0.new) $Rd = #0
case Hexagon::C2_cmoveif:
- Result.setOpcode(Hexagon::V4_SA1_clrf);
+ Result.setOpcode(Hexagon::SA1_clrf);
addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
break; // 2 SUBInst if (!p0) $Rd = #0
case Hexagon::C2_cmoveit:
- Result.setOpcode(Hexagon::V4_SA1_clrt);
+ Result.setOpcode(Hexagon::SA1_clrt);
addOps(Result, Inst, 0);
+ addOps(Result, Inst, 1);
break; // 2 SUBInst if (p0) $Rd = #0
case Hexagon::A2_tfrsi:
Absolute = Inst.getOperand(1).getExpr()->evaluateAsAbsolute(Value);
if (Absolute && Value == -1) {
- Result.setOpcode(Hexagon::V4_SA1_setin1);
+ Result.setOpcode(Hexagon::SA1_setin1);
addOps(Result, Inst, 0);
break; // 2 1 SUBInst $Rd = #-1
} else {
- Result.setOpcode(Hexagon::V4_SA1_seti);
+ Result.setOpcode(Hexagon::SA1_seti);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rd = #$u6
}
case Hexagon::A2_zxtb:
- Result.setOpcode(Hexagon::V4_SA1_zxtb);
+ Result.setOpcode(Hexagon::SA1_zxtb);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 $Rd = and($Rs, #255)
case Hexagon::A2_zxth:
- Result.setOpcode(Hexagon::V4_SA1_zxth);
+ Result.setOpcode(Hexagon::SA1_zxth);
addOps(Result, Inst, 0);
addOps(Result, Inst, 1);
break; // 1,2 SUBInst $Rd = zxth($Rs)
@@ -1022,7 +1016,7 @@ HexagonMCInstrInfo::getDuplexPossibilties(MCInstrInfo const &MCII,
k = j + distance;
(j < numInstrInPacket) && (k < numInstrInPacket); ++j, ++k) {
- // Check if reversable.
+ // Check if reversible.
bool bisReversable = true;
if (isStoreInst(MCB.getOperand(j).getInst()->getOpcode()) &&
isStoreInst(MCB.getOperand(k).getInst()->getOpcode())) {
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
index 67dcb8f..226470c 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
@@ -13,20 +13,27 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "hexagonmcelfstreamer"
-#include "Hexagon.h"
-#include "HexagonMCELFStreamer.h"
-#include "MCTargetDesc/HexagonBaseInfo.h"
+#include "MCTargetDesc/HexagonMCELFStreamer.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonMCShuffler.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstdint>
using namespace llvm;
@@ -148,8 +155,10 @@ void HexagonMCELFStreamer::HexagonMCEmitLocalCommonSymbol(
}
namespace llvm {
+
MCStreamer *createHexagonELFStreamer(MCContext &Context, MCAsmBackend &MAB,
raw_pwrite_stream &OS, MCCodeEmitter *CE) {
return new HexagonMCELFStreamer(Context, MAB, OS, CE);
}
-}
+
+} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h
index d77c0cd..0ac1a68 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.h
@@ -7,14 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#ifndef HEXAGONMCELFSTREAMER_H
-#define HEXAGONMCELFSTREAMER_H
+#ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCELFSTREAMER_H
+#define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCELFSTREAMER_H
-#include "MCTargetDesc/HexagonMCCodeEmitter.h"
-#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "llvm/MC/MCELFStreamer.h"
-#include "HexagonTargetStreamer.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include <cstdint>
+#include <memory>
namespace llvm {
@@ -27,8 +27,7 @@ public:
: MCELFStreamer(Context, TAB, OS, Emitter),
MCII(createHexagonMCInstrInfo()) {}
- virtual void EmitInstruction(const MCInst &Inst,
- const MCSubtargetInfo &STI) override;
+ void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
void EmitSymbol(const MCInst &Inst);
void HexagonMCEmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment,
@@ -40,6 +39,6 @@ public:
MCStreamer *createHexagonELFStreamer(MCContext &Context, MCAsmBackend &MAB,
raw_pwrite_stream &OS, MCCodeEmitter *CE);
-} // namespace llvm
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCELFSTREAMER_H
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp
index 941cbd6..e627f02 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp
@@ -306,7 +306,7 @@ int HexagonMCInstrInfo::getMinValue(MCInstrInfo const &MCII,
return 0;
}
-char const *HexagonMCInstrInfo::getName(MCInstrInfo const &MCII,
+StringRef HexagonMCInstrInfo::getName(MCInstrInfo const &MCII,
MCInst const &MCI) {
return MCII.getName(MCI.getOpcode());
}
@@ -431,6 +431,11 @@ bool HexagonMCInstrInfo::isCanon(MCInstrInfo const &MCII, MCInst const &MCI) {
HexagonMCInstrInfo::getType(MCII, MCI) != HexagonII::TypeENDLOOP);
}
+bool HexagonMCInstrInfo::isCofMax1(MCInstrInfo const &MCII, MCInst const &MCI) {
+ const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
+ return ((F >> HexagonII::CofMax1Pos) & HexagonII::CofMax1Mask);
+}
+
bool HexagonMCInstrInfo::isCompound(MCInstrInfo const &MCII,
MCInst const &MCI) {
return (getType(MCII, MCI) == HexagonII::TypeCOMPOUND);
@@ -602,58 +607,58 @@ bool HexagonMCInstrInfo::isSubInstruction(MCInst const &MCI) {
switch (MCI.getOpcode()) {
default:
return false;
- case Hexagon::V4_SA1_addi:
- case Hexagon::V4_SA1_addrx:
- case Hexagon::V4_SA1_addsp:
- case Hexagon::V4_SA1_and1:
- case Hexagon::V4_SA1_clrf:
- case Hexagon::V4_SA1_clrfnew:
- case Hexagon::V4_SA1_clrt:
- case Hexagon::V4_SA1_clrtnew:
- case Hexagon::V4_SA1_cmpeqi:
- case Hexagon::V4_SA1_combine0i:
- case Hexagon::V4_SA1_combine1i:
- case Hexagon::V4_SA1_combine2i:
- case Hexagon::V4_SA1_combine3i:
- case Hexagon::V4_SA1_combinerz:
- case Hexagon::V4_SA1_combinezr:
- case Hexagon::V4_SA1_dec:
- case Hexagon::V4_SA1_inc:
- case Hexagon::V4_SA1_seti:
- case Hexagon::V4_SA1_setin1:
- case Hexagon::V4_SA1_sxtb:
- case Hexagon::V4_SA1_sxth:
- case Hexagon::V4_SA1_tfr:
- case Hexagon::V4_SA1_zxtb:
- case Hexagon::V4_SA1_zxth:
- case Hexagon::V4_SL1_loadri_io:
- case Hexagon::V4_SL1_loadrub_io:
- case Hexagon::V4_SL2_deallocframe:
- case Hexagon::V4_SL2_jumpr31:
- case Hexagon::V4_SL2_jumpr31_f:
- case Hexagon::V4_SL2_jumpr31_fnew:
- case Hexagon::V4_SL2_jumpr31_t:
- case Hexagon::V4_SL2_jumpr31_tnew:
- case Hexagon::V4_SL2_loadrb_io:
- case Hexagon::V4_SL2_loadrd_sp:
- case Hexagon::V4_SL2_loadrh_io:
- case Hexagon::V4_SL2_loadri_sp:
- case Hexagon::V4_SL2_loadruh_io:
- case Hexagon::V4_SL2_return:
- case Hexagon::V4_SL2_return_f:
- case Hexagon::V4_SL2_return_fnew:
- case Hexagon::V4_SL2_return_t:
- case Hexagon::V4_SL2_return_tnew:
- case Hexagon::V4_SS1_storeb_io:
- case Hexagon::V4_SS1_storew_io:
- case Hexagon::V4_SS2_allocframe:
- case Hexagon::V4_SS2_storebi0:
- case Hexagon::V4_SS2_storebi1:
- case Hexagon::V4_SS2_stored_sp:
- case Hexagon::V4_SS2_storeh_io:
- case Hexagon::V4_SS2_storew_sp:
- case Hexagon::V4_SS2_storewi0:
- case Hexagon::V4_SS2_storewi1:
+ case Hexagon::SA1_addi:
+ case Hexagon::SA1_addrx:
+ case Hexagon::SA1_addsp:
+ case Hexagon::SA1_and1:
+ case Hexagon::SA1_clrf:
+ case Hexagon::SA1_clrfnew:
+ case Hexagon::SA1_clrt:
+ case Hexagon::SA1_clrtnew:
+ case Hexagon::SA1_cmpeqi:
+ case Hexagon::SA1_combine0i:
+ case Hexagon::SA1_combine1i:
+ case Hexagon::SA1_combine2i:
+ case Hexagon::SA1_combine3i:
+ case Hexagon::SA1_combinerz:
+ case Hexagon::SA1_combinezr:
+ case Hexagon::SA1_dec:
+ case Hexagon::SA1_inc:
+ case Hexagon::SA1_seti:
+ case Hexagon::SA1_setin1:
+ case Hexagon::SA1_sxtb:
+ case Hexagon::SA1_sxth:
+ case Hexagon::SA1_tfr:
+ case Hexagon::SA1_zxtb:
+ case Hexagon::SA1_zxth:
+ case Hexagon::SL1_loadri_io:
+ case Hexagon::SL1_loadrub_io:
+ case Hexagon::SL2_deallocframe:
+ case Hexagon::SL2_jumpr31:
+ case Hexagon::SL2_jumpr31_f:
+ case Hexagon::SL2_jumpr31_fnew:
+ case Hexagon::SL2_jumpr31_t:
+ case Hexagon::SL2_jumpr31_tnew:
+ case Hexagon::SL2_loadrb_io:
+ case Hexagon::SL2_loadrd_sp:
+ case Hexagon::SL2_loadrh_io:
+ case Hexagon::SL2_loadri_sp:
+ case Hexagon::SL2_loadruh_io:
+ case Hexagon::SL2_return:
+ case Hexagon::SL2_return_f:
+ case Hexagon::SL2_return_fnew:
+ case Hexagon::SL2_return_t:
+ case Hexagon::SL2_return_tnew:
+ case Hexagon::SS1_storeb_io:
+ case Hexagon::SS1_storew_io:
+ case Hexagon::SS2_allocframe:
+ case Hexagon::SS2_storebi0:
+ case Hexagon::SS2_storebi1:
+ case Hexagon::SS2_stored_sp:
+ case Hexagon::SS2_storeh_io:
+ case Hexagon::SS2_storew_sp:
+ case Hexagon::SS2_storewi0:
+ case Hexagon::SS2_storewi1:
return true;
}
}
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h
index 58a8f68..d701c3a 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h
@@ -133,7 +133,7 @@ int getMaxValue(MCInstrInfo const &MCII, MCInst const &MCI);
int getMinValue(MCInstrInfo const &MCII, MCInst const &MCI);
// Return instruction name
-char const *getName(MCInstrInfo const &MCII, MCInst const &MCI);
+StringRef getName(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the operand index for the new value.
unsigned short getNewValueOp(MCInstrInfo const &MCII, MCInst const &MCI);
@@ -170,6 +170,7 @@ bool isBundle(MCInst const &MCI);
// Return whether the insn is an actual insn.
bool isCanon(MCInstrInfo const &MCII, MCInst const &MCI);
+bool isCofMax1(MCInstrInfo const &MCII, MCInst const &MCI);
bool isCompound(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the duplex iclass given the two duplex classes
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
index 35a1a23..694cf58 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
@@ -11,22 +11,29 @@
//
//===----------------------------------------------------------------------===//
-#include "HexagonMCTargetDesc.h"
#include "Hexagon.h"
-#include "HexagonMCAsmInfo.h"
-#include "HexagonMCELFStreamer.h"
+#include "HexagonTargetStreamer.h"
#include "MCTargetDesc/HexagonInstPrinter.h"
+#include "MCTargetDesc/HexagonMCAsmInfo.h"
+#include "MCTargetDesc/HexagonMCELFStreamer.h"
+#include "MCTargetDesc/HexagonMCInstrInfo.h"
+#include "MCTargetDesc/HexagonMCTargetDesc.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MachineLocation.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
+#include <cassert>
+#include <cstdint>
+#include <new>
+#include <string>
using namespace llvm;
@@ -59,7 +66,6 @@ static cl::opt<bool> HexagonV55ArchVariant("mv55", cl::Hidden, cl::init(false),
static cl::opt<bool> HexagonV60ArchVariant("mv60", cl::Hidden, cl::init(false),
cl::desc("Build for Hexagon V60"));
-
static StringRef DefaultArch = "hexagonv60";
static StringRef HexagonGetArchVariant() {
@@ -74,7 +80,7 @@ static StringRef HexagonGetArchVariant() {
return "";
}
-StringRef HEXAGON_MC::selectHexagonCPU(const Triple &TT, StringRef CPU) {
+StringRef Hexagon_MC::selectHexagonCPU(const Triple &TT, StringRef CPU) {
StringRef ArchV = HexagonGetArchVariant();
if (!ArchV.empty() && !CPU.empty()) {
if (ArchV != CPU)
@@ -103,17 +109,19 @@ static MCRegisterInfo *createHexagonMCRegisterInfo(const Triple &TT) {
static MCSubtargetInfo *
createHexagonMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
- CPU = HEXAGON_MC::selectHexagonCPU(TT, CPU);
+ CPU = Hexagon_MC::selectHexagonCPU(TT, CPU);
return createHexagonMCSubtargetInfoImpl(TT, CPU, FS);
}
namespace {
+
class HexagonTargetAsmStreamer : public HexagonTargetStreamer {
public:
HexagonTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &, bool,
MCInstPrinter &)
: HexagonTargetStreamer(S) {}
+
void prettyPrintAsm(MCInstPrinter &InstPrinter, raw_ostream &OS,
const MCInst &Inst, const MCSubtargetInfo &STI) override {
assert(HexagonMCInstrInfo::isBundle(Inst));
@@ -145,14 +153,9 @@ public:
OS << "\t}" << PacketBundle.second;
}
};
-}
-namespace {
class HexagonTargetELFStreamer : public HexagonTargetStreamer {
public:
- MCELFStreamer &getStreamer() {
- return static_cast<MCELFStreamer &>(Streamer);
- }
HexagonTargetELFStreamer(MCStreamer &S, MCSubtargetInfo const &STI)
: HexagonTargetStreamer(S) {
auto Bits = STI.getFeatureBits();
@@ -167,6 +170,11 @@ public:
Flags = ELF::EF_HEXAGON_MACH_V4;
getStreamer().getAssembler().setELFHeaderEFlags(Flags);
}
+
+ MCELFStreamer &getStreamer() {
+ return static_cast<MCELFStreamer &>(Streamer);
+ }
+
void EmitCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment,
unsigned AccessSize) override {
@@ -175,6 +183,7 @@ public:
HexagonELFStreamer.HexagonMCEmitCommonSymbol(Symbol, Size, ByteAlignment,
AccessSize);
}
+
void EmitLocalCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment,
unsigned AccessSize) override {
@@ -184,7 +193,8 @@ public:
Symbol, Size, ByteAlignment, AccessSize);
}
};
-}
+
+} // end anonymous namespace
static MCAsmInfo *createHexagonMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT) {
@@ -230,39 +240,39 @@ createHexagonObjectTargetStreamer(MCStreamer &S, MCSubtargetInfo const &STI) {
// Force static initialization.
extern "C" void LLVMInitializeHexagonTargetMC() {
// Register the MC asm info.
- RegisterMCAsmInfoFn X(TheHexagonTarget, createHexagonMCAsmInfo);
+ RegisterMCAsmInfoFn X(getTheHexagonTarget(), createHexagonMCAsmInfo);
// Register the MC instruction info.
- TargetRegistry::RegisterMCInstrInfo(TheHexagonTarget,
+ TargetRegistry::RegisterMCInstrInfo(getTheHexagonTarget(),
createHexagonMCInstrInfo);
// Register the MC register info.
- TargetRegistry::RegisterMCRegInfo(TheHexagonTarget,
+ TargetRegistry::RegisterMCRegInfo(getTheHexagonTarget(),
createHexagonMCRegisterInfo);
// Register the MC subtarget info.
- TargetRegistry::RegisterMCSubtargetInfo(TheHexagonTarget,
+ TargetRegistry::RegisterMCSubtargetInfo(getTheHexagonTarget(),
createHexagonMCSubtargetInfo);
// Register the MC Code Emitter
- TargetRegistry::RegisterMCCodeEmitter(TheHexagonTarget,
+ TargetRegistry::RegisterMCCodeEmitter(getTheHexagonTarget(),
createHexagonMCCodeEmitter);
// Register the asm backend
- TargetRegistry::RegisterMCAsmBackend(TheHexagonTarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheHexagonTarget(),
createHexagonAsmBackend);
// Register the obj streamer
- TargetRegistry::RegisterELFStreamer(TheHexagonTarget, createMCStreamer);
+ TargetRegistry::RegisterELFStreamer(getTheHexagonTarget(), createMCStreamer);
// Register the asm streamer
- TargetRegistry::RegisterAsmTargetStreamer(TheHexagonTarget,
+ TargetRegistry::RegisterAsmTargetStreamer(getTheHexagonTarget(),
createMCAsmTargetStreamer);
// Register the MC Inst Printer
- TargetRegistry::RegisterMCInstPrinter(TheHexagonTarget,
+ TargetRegistry::RegisterMCInstPrinter(getTheHexagonTarget(),
createHexagonMCInstPrinter);
TargetRegistry::RegisterObjectTargetStreamer(
- TheHexagonTarget, createHexagonObjectTargetStreamer);
+ getTheHexagonTarget(), createHexagonObjectTargetStreamer);
}
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h
index a005a01..6e677e9 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h
@@ -14,11 +14,11 @@
#ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCTARGETDESC_H
#define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCTARGETDESC_H
-#include <cstdint>
-
#include "llvm/Support/CommandLine.h"
+#include <cstdint>
namespace llvm {
+
struct InstrItinerary;
struct InstrStage;
class MCAsmBackend;
@@ -28,13 +28,14 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
class Target;
class Triple;
class StringRef;
class raw_ostream;
class raw_pwrite_stream;
-extern Target TheHexagonTarget;
+Target &getTheHexagonTarget();
extern cl::opt<bool> HexagonDisableCompound;
extern cl::opt<bool> HexagonDisableDuplex;
extern const InstrStage HexagonStages[];
@@ -47,16 +48,19 @@ MCCodeEmitter *createHexagonMCCodeEmitter(const MCInstrInfo &MCII,
MCAsmBackend *createHexagonAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createHexagonELFObjectWriter(raw_pwrite_stream &OS,
uint8_t OSABI, StringRef CPU);
-namespace HEXAGON_MC {
+namespace Hexagon_MC {
+
StringRef selectHexagonCPU(const Triple &TT, StringRef CPU);
-}
-} // End llvm namespace
+} // end namespace Hexagon_MC
+
+} // end namespace llvm
// Define symbolic names for Hexagon registers. This defines a mapping from
// register name to register number.
@@ -72,4 +76,4 @@ namespace HEXAGON_MC {
#define GET_SUBTARGETINFO_ENUM
#include "HexagonGenSubtargetInfo.inc"
-#endif
+#endif // LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCTARGETDESC_H
diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
index 4e1cce3..88f37d6 100644
--- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
@@ -171,7 +171,7 @@ bool HexagonShuffler::check() {
unsigned slotJump = slotFirstJump;
unsigned slotLoadStore = slotFirstLoadStore;
// Number of branches, solo branches, indirect branches.
- unsigned jumps = 0, jump1 = 0, jumpr = 0;
+ unsigned jumps = 0, jump1 = 0;
// Number of memory operations, loads, solo loads, stores, solo stores, single
// stores.
unsigned memory = 0, loads = 0, load0 = 0, stores = 0, store0 = 0, store1 = 0;
@@ -207,6 +207,8 @@ bool HexagonShuffler::check() {
++pSlot3Cnt;
slot3ISJ = ISJ;
}
+ if (HexagonMCInstrInfo::isCofMax1(MCII, *ID))
+ ++jump1;
switch (HexagonMCInstrInfo::getType(MCII, *ID)) {
case HexagonII::TypeXTYPE:
@@ -214,8 +216,6 @@ bool HexagonShuffler::check() {
++xtypeFloat;
break;
case HexagonII::TypeJR:
- ++jumpr;
- // Fall-through.
case HexagonII::TypeJ:
++jumps;
break;
@@ -244,7 +244,7 @@ bool HexagonShuffler::check() {
if (ISJ->Core.getUnits() == slotSingleStore)
++store0;
break;
- case HexagonII::TypeMEMOP:
+ case HexagonII::TypeV4LDST:
++loads;
++stores;
++store1;
@@ -304,7 +304,7 @@ bool HexagonShuffler::check() {
if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch() ||
HexagonMCInstrInfo::getDesc(MCII, *ID).isCall())
if (jumps > 1) {
- if (jumpr || slotJump < slotLastJump) {
+ if (slotJump < slotLastJump) {
// Error if indirect branch with another branch or
// no more slots available for branches.
Error = SHUFFLE_ERROR_BRANCHES;
diff --git a/contrib/llvm/lib/Target/Hexagon/RDFCopy.cpp b/contrib/llvm/lib/Target/Hexagon/RDFCopy.cpp
index 61a83da..3928716 100644
--- a/contrib/llvm/lib/Target/Hexagon/RDFCopy.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/RDFCopy.cpp
@@ -32,43 +32,19 @@ bool CopyPropagation::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) {
case TargetOpcode::COPY: {
const MachineOperand &Dst = MI->getOperand(0);
const MachineOperand &Src = MI->getOperand(1);
- RegisterRef DstR = { Dst.getReg(), Dst.getSubReg() };
- RegisterRef SrcR = { Src.getReg(), Src.getSubReg() };
- if (TargetRegisterInfo::isVirtualRegister(DstR.Reg)) {
- if (!TargetRegisterInfo::isVirtualRegister(SrcR.Reg))
- return false;
- MachineRegisterInfo &MRI = DFG.getMF().getRegInfo();
- if (MRI.getRegClass(DstR.Reg) != MRI.getRegClass(SrcR.Reg))
- return false;
- } else if (TargetRegisterInfo::isPhysicalRegister(DstR.Reg)) {
- if (!TargetRegisterInfo::isPhysicalRegister(SrcR.Reg))
- return false;
- const TargetRegisterInfo &TRI = DFG.getTRI();
- if (TRI.getMinimalPhysRegClass(DstR.Reg) !=
- TRI.getMinimalPhysRegClass(SrcR.Reg))
- return false;
- } else {
- // Copy between some unknown objects.
+ RegisterRef DstR = DFG.makeRegRef(Dst.getReg(), Dst.getSubReg());
+ RegisterRef SrcR = DFG.makeRegRef(Src.getReg(), Src.getSubReg());
+ assert(TargetRegisterInfo::isPhysicalRegister(DstR.Reg));
+ assert(TargetRegisterInfo::isPhysicalRegister(SrcR.Reg));
+ const TargetRegisterInfo &TRI = DFG.getTRI();
+ if (TRI.getMinimalPhysRegClass(DstR.Reg) !=
+ TRI.getMinimalPhysRegClass(SrcR.Reg))
return false;
- }
EM.insert(std::make_pair(DstR, SrcR));
return true;
}
- case TargetOpcode::REG_SEQUENCE: {
- const MachineOperand &Dst = MI->getOperand(0);
- RegisterRef DefR = { Dst.getReg(), Dst.getSubReg() };
- SmallVector<TargetInstrInfo::RegSubRegPairAndIdx,2> Inputs;
- const TargetInstrInfo &TII = DFG.getTII();
- if (!TII.getRegSequenceInputs(*MI, 0, Inputs))
- return false;
- for (auto I : Inputs) {
- unsigned S = DFG.getTRI().composeSubRegIndices(DefR.Sub, I.SubIdx);
- RegisterRef DR = { DefR.Reg, S };
- RegisterRef SR = { I.Reg, I.SubReg };
- EM.insert(std::make_pair(DR, SR));
- }
- return true;
- }
+ case TargetOpcode::REG_SEQUENCE:
+ llvm_unreachable("Unexpected REG_SEQUENCE");
}
return false;
}
@@ -79,7 +55,7 @@ void CopyPropagation::recordCopy(NodeAddr<StmtNode*> SA, EqualityMap &EM) {
Copies.push_back(SA.Id);
for (auto I : EM) {
- auto FS = DefM.find(I.second);
+ auto FS = DefM.find(I.second.Reg);
if (FS == DefM.end() || FS->second.empty())
continue; // Undefined source
RDefMap[I.second][SA.Id] = FS->second.top()->Id;
@@ -92,7 +68,7 @@ void CopyPropagation::recordCopy(NodeAddr<StmtNode*> SA, EqualityMap &EM) {
void CopyPropagation::updateMap(NodeAddr<InstrNode*> IA) {
RegisterSet RRs;
for (NodeAddr<RefNode*> RA : IA.Addr->members(DFG))
- RRs.insert(RA.Addr->getRegRef());
+ RRs.insert(RA.Addr->getRegRef(DFG));
bool Common = false;
for (auto &R : RDefMap) {
if (!RRs.count(R.first))
@@ -106,7 +82,7 @@ void CopyPropagation::updateMap(NodeAddr<InstrNode*> IA) {
for (auto &R : RDefMap) {
if (!RRs.count(R.first))
continue;
- auto F = DefM.find(R.first);
+ auto F = DefM.find(R.first.Reg);
if (F == DefM.end() || F->second.empty())
continue;
R.second[IA.Id] = F->second.top()->Id;
@@ -168,6 +144,18 @@ bool CopyPropagation::run() {
bool HasLimit = CpLimit.getNumOccurrences() > 0;
#endif
+ auto MinPhysReg = [this] (RegisterRef RR) -> unsigned {
+ const TargetRegisterInfo &TRI = DFG.getTRI();
+ const TargetRegisterClass &RC = *TRI.getMinimalPhysRegClass(RR.Reg);
+ if ((RC.LaneMask & RR.Mask) == RC.LaneMask)
+ return RR.Reg;
+ for (MCSubRegIndexIterator S(RR.Reg, &TRI); S.isValid(); ++S)
+ if (RR.Mask == TRI.getSubRegIndexLaneMask(S.getSubRegIndex()))
+ return S.getSubReg();
+ llvm_unreachable("Should have found a register");
+ return 0;
+ };
+
for (auto C : Copies) {
#ifndef NDEBUG
if (HasLimit && CpCount >= CpLimit)
@@ -180,7 +168,7 @@ bool CopyPropagation::run() {
EqualityMap &EM = FS->second;
for (NodeAddr<DefNode*> DA : SA.Addr->members_if(DFG.IsDef, DFG)) {
- RegisterRef DR = DA.Addr->getRegRef();
+ RegisterRef DR = DA.Addr->getRegRef(DFG);
auto FR = EM.find(DR);
if (FR == EM.end())
continue;
@@ -197,7 +185,7 @@ bool CopyPropagation::run() {
uint16_t F = UA.Addr->getFlags();
if ((F & NodeAttrs::PhiRef) || (F & NodeAttrs::Fixed))
continue;
- if (UA.Addr->getRegRef() != DR)
+ if (UA.Addr->getRegRef(DFG) != DR)
continue;
NodeAddr<InstrNode*> IA = UA.Addr->getOwner(DFG);
@@ -214,8 +202,9 @@ bool CopyPropagation::run() {
<< *NodeAddr<StmtNode*>(IA).Addr->getCode();
}
- Op.setReg(SR.Reg);
- Op.setSubReg(SR.Sub);
+ unsigned NewReg = MinPhysReg(SR);
+ Op.setReg(NewReg);
+ Op.setSubReg(0);
DFG.unlinkUse(UA, false);
if (RDefSR_SA != 0) {
UA.Addr->linkToDef(UA.Id, DFG.addr<DefNode*>(RDefSR_SA));
diff --git a/contrib/llvm/lib/Target/Hexagon/RDFCopy.h b/contrib/llvm/lib/Target/Hexagon/RDFCopy.h
index e8a576c..5ece11b 100644
--- a/contrib/llvm/lib/Target/Hexagon/RDFCopy.h
+++ b/contrib/llvm/lib/Target/Hexagon/RDFCopy.h
@@ -1,4 +1,4 @@
-//===--- RDFCopy.h --------------------------------------------------------===//
+//===--- RDFCopy.h ----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,27 +7,31 @@
//
//===----------------------------------------------------------------------===//
-#ifndef RDF_COPY_H
-#define RDF_COPY_H
+#ifndef LLVM_LIB_TARGET_HEXAGON_RDFCOPY_H
+#define LLVM_LIB_TARGET_HEXAGON_RDFCOPY_H
#include "RDFGraph.h"
#include <map>
#include <vector>
namespace llvm {
+
class MachineBasicBlock;
class MachineDominatorTree;
class MachineInstr;
namespace rdf {
+
struct CopyPropagation {
CopyPropagation(DataFlowGraph &dfg) : MDT(dfg.getDT()), DFG(dfg),
Trace(false) {}
- virtual ~CopyPropagation() {}
+
+ virtual ~CopyPropagation() = default;
bool run();
void trace(bool On) { Trace = On; }
bool trace() const { return Trace; }
+ DataFlowGraph &getDFG() { return DFG; }
typedef std::map<RegisterRef, RegisterRef> EqualityMap;
virtual bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM);
@@ -48,7 +52,9 @@ namespace rdf {
void updateMap(NodeAddr<InstrNode*> IA);
bool scanBlock(MachineBasicBlock *B);
};
-} // namespace rdf
-} // namespace llvm
-#endif
+} // end namespace rdf
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_HEXAGON_RDFCOPY_H
diff --git a/contrib/llvm/lib/Target/Hexagon/RDFGraph.cpp b/contrib/llvm/lib/Target/Hexagon/RDFGraph.cpp
index 273d6b7..fa272ea 100644
--- a/contrib/llvm/lib/Target/Hexagon/RDFGraph.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/RDFGraph.cpp
@@ -10,15 +10,31 @@
// Target-independent, SSA-based data flow graph for register data flow (RDF).
//
#include "RDFGraph.h"
-
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominanceFrontier.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/MC/LaneBitmask.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <utility>
+#include <vector>
using namespace llvm;
using namespace rdf;
@@ -28,6 +44,12 @@ using namespace rdf;
namespace llvm {
namespace rdf {
+raw_ostream &operator<< (raw_ostream &OS, const PrintLaneMaskOpt &P) {
+ if (!P.Mask.all())
+ OS << ':' << PrintLaneMask(P.Mask);
+ return OS;
+}
+
template<>
raw_ostream &operator<< (raw_ostream &OS, const Print<RegisterRef> &P) {
auto &TRI = P.G.getTRI();
@@ -35,13 +57,7 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<RegisterRef> &P) {
OS << TRI.getName(P.Obj.Reg);
else
OS << '#' << P.Obj.Reg;
- if (P.Obj.Sub > 0) {
- OS << ':';
- if (P.Obj.Sub < TRI.getNumSubRegIndices())
- OS << TRI.getSubRegIndexName(P.Obj.Sub);
- else
- OS << '#' << P.Obj.Sub;
- }
+ OS << PrintLaneMaskOpt(P.Obj.Mask);
return OS;
}
@@ -62,6 +78,10 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<NodeId> &P) {
}
break;
case NodeAttrs::Ref:
+ if (Flags & NodeAttrs::Undef)
+ OS << '/';
+ if (Flags & NodeAttrs::Dead)
+ OS << '\\';
if (Flags & NodeAttrs::Preserving)
OS << '+';
if (Flags & NodeAttrs::Clobbering)
@@ -83,14 +103,12 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<NodeId> &P) {
return OS;
}
-namespace {
- void printRefHeader(raw_ostream &OS, const NodeAddr<RefNode*> RA,
- const DataFlowGraph &G) {
- OS << Print<NodeId>(RA.Id, G) << '<'
- << Print<RegisterRef>(RA.Addr->getRegRef(), G) << '>';
- if (RA.Addr->getFlags() & NodeAttrs::Fixed)
- OS << '!';
- }
+static void printRefHeader(raw_ostream &OS, const NodeAddr<RefNode*> RA,
+ const DataFlowGraph &G) {
+ OS << Print<NodeId>(RA.Id, G) << '<'
+ << Print<RegisterRef>(RA.Addr->getRegRef(G), G) << '>';
+ if (RA.Addr->getFlags() & NodeAttrs::Fixed)
+ OS << '!';
}
template<>
@@ -178,9 +196,11 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<NodeSet> &P) {
}
namespace {
+
template <typename T>
struct PrintListV {
PrintListV(const NodeList &L, const DataFlowGraph &G) : List(L), G(G) {}
+
typedef T Type;
const NodeList &List;
const DataFlowGraph &G;
@@ -196,7 +216,8 @@ namespace {
}
return OS;
}
-}
+
+} // end anonymous namespace
template<>
raw_ostream &operator<< (raw_ostream &OS, const Print<NodeAddr<PhiNode*>> &P) {
@@ -208,9 +229,27 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<NodeAddr<PhiNode*>> &P) {
template<>
raw_ostream &operator<< (raw_ostream &OS,
const Print<NodeAddr<StmtNode*>> &P) {
- unsigned Opc = P.Obj.Addr->getCode()->getOpcode();
- OS << Print<NodeId>(P.Obj.Id, P.G) << ": " << P.G.getTII().getName(Opc)
- << " [" << PrintListV<RefNode*>(P.Obj.Addr->members(P.G), P.G) << ']';
+ const MachineInstr &MI = *P.Obj.Addr->getCode();
+ unsigned Opc = MI.getOpcode();
+ OS << Print<NodeId>(P.Obj.Id, P.G) << ": " << P.G.getTII().getName(Opc);
+ // Print the target for calls and branches (for readability).
+ if (MI.isCall() || MI.isBranch()) {
+ MachineInstr::const_mop_iterator T =
+ llvm::find_if(MI.operands(),
+ [] (const MachineOperand &Op) -> bool {
+ return Op.isMBB() || Op.isGlobal() || Op.isSymbol();
+ });
+ if (T != MI.operands_end()) {
+ OS << ' ';
+ if (T->isMBB())
+ OS << "BB#" << T->getMBB()->getNumber();
+ else if (T->isGlobal())
+ OS << T->getGlobal()->getName();
+ else if (T->isSymbol())
+ OS << T->getSymbolName();
+ }
+ }
+ OS << " [" << PrintListV<RefNode*>(P.Obj.Addr->members(P.G), P.G) << ']';
return OS;
}
@@ -234,29 +273,29 @@ raw_ostream &operator<< (raw_ostream &OS,
template<>
raw_ostream &operator<< (raw_ostream &OS,
const Print<NodeAddr<BlockNode*>> &P) {
- auto *BB = P.Obj.Addr->getCode();
+ MachineBasicBlock *BB = P.Obj.Addr->getCode();
unsigned NP = BB->pred_size();
std::vector<int> Ns;
auto PrintBBs = [&OS,&P] (std::vector<int> Ns) -> void {
unsigned N = Ns.size();
- for (auto I : Ns) {
+ for (int I : Ns) {
OS << "BB#" << I;
if (--N)
OS << ", ";
}
};
- OS << Print<NodeId>(P.Obj.Id, P.G) << ": === BB#" << BB->getNumber()
- << " === preds(" << NP << "): ";
- for (auto I : BB->predecessors())
- Ns.push_back(I->getNumber());
+ OS << Print<NodeId>(P.Obj.Id, P.G) << ": --- BB#" << BB->getNumber()
+ << " --- preds(" << NP << "): ";
+ for (MachineBasicBlock *B : BB->predecessors())
+ Ns.push_back(B->getNumber());
PrintBBs(Ns);
unsigned NS = BB->succ_size();
OS << " succs(" << NS << "): ";
Ns.clear();
- for (auto I : BB->successors())
- Ns.push_back(I->getNumber());
+ for (MachineBasicBlock *B : BB->successors())
+ Ns.push_back(B->getNumber());
PrintBBs(Ns);
OS << '\n';
@@ -286,11 +325,17 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<RegisterSet> &P) {
}
template<>
+raw_ostream &operator<< (raw_ostream &OS, const Print<RegisterAggr> &P) {
+ P.Obj.print(OS);
+ return OS;
+}
+
+template<>
raw_ostream &operator<< (raw_ostream &OS,
const Print<DataFlowGraph::DefStack> &P) {
for (auto I = P.Obj.top(), E = P.Obj.bottom(); I != E; ) {
OS << Print<NodeId>(I->Id, P.G)
- << '<' << Print<RegisterRef>(I->Addr->getRegRef(), P.G) << '>';
+ << '<' << Print<RegisterRef>(I->Addr->getRegRef(P.G), P.G) << '>';
I.down();
if (I != E)
OS << ' ';
@@ -298,8 +343,8 @@ raw_ostream &operator<< (raw_ostream &OS,
return OS;
}
-} // namespace rdf
-} // namespace llvm
+} // end namespace rdf
+} // end namespace llvm
// Node allocation functions.
//
@@ -361,7 +406,6 @@ void NodeAllocator::clear() {
ActiveEnd = nullptr;
}
-
// Insert node NA after "this" in the circular chain.
void NodeBase::append(NodeAddr<NodeBase*> NA) {
NodeId Nx = Next;
@@ -372,31 +416,31 @@ void NodeBase::append(NodeAddr<NodeBase*> NA) {
}
}
-
// Fundamental node manipulator functions.
// Obtain the register reference from a reference node.
-RegisterRef RefNode::getRegRef() const {
+RegisterRef RefNode::getRegRef(const DataFlowGraph &G) const {
assert(NodeAttrs::type(Attrs) == NodeAttrs::Ref);
if (NodeAttrs::flags(Attrs) & NodeAttrs::PhiRef)
- return Ref.RR;
+ return G.unpack(Ref.PR);
assert(Ref.Op != nullptr);
- return { Ref.Op->getReg(), Ref.Op->getSubReg() };
+ return G.makeRegRef(Ref.Op->getReg(), Ref.Op->getSubReg());
}
// Set the register reference in the reference node directly (for references
// in phi nodes).
-void RefNode::setRegRef(RegisterRef RR) {
+void RefNode::setRegRef(RegisterRef RR, DataFlowGraph &G) {
assert(NodeAttrs::type(Attrs) == NodeAttrs::Ref);
assert(NodeAttrs::flags(Attrs) & NodeAttrs::PhiRef);
- Ref.RR = RR;
+ Ref.PR = G.pack(RR);
}
// Set the register reference in the reference node based on a machine
// operand (for references in statement nodes).
-void RefNode::setRegRef(MachineOperand *Op) {
+void RefNode::setRegRef(MachineOperand *Op, DataFlowGraph &G) {
assert(NodeAttrs::type(Attrs) == NodeAttrs::Ref);
assert(!(NodeAttrs::flags(Attrs) & NodeAttrs::PhiRef));
+ (void)G;
Ref.Op = Op;
}
@@ -442,7 +486,7 @@ NodeAddr<NodeBase*> CodeNode::getLastMember(const DataFlowGraph &G) const {
// Add node NA at the end of the member list of the given code node.
void CodeNode::addMember(NodeAddr<NodeBase*> NA, const DataFlowGraph &G) {
- auto ML = getLastMember(G);
+ NodeAddr<NodeBase*> ML = getLastMember(G);
if (ML.Id != 0) {
ML.Addr->append(NA);
} else {
@@ -463,7 +507,7 @@ void CodeNode::addMemberAfter(NodeAddr<NodeBase*> MA, NodeAddr<NodeBase*> NA,
// Remove member node NA from the given code node.
void CodeNode::removeMember(NodeAddr<NodeBase*> NA, const DataFlowGraph &G) {
- auto MA = getFirstMember(G);
+ NodeAddr<NodeBase*> MA = getFirstMember(G);
assert(MA.Id != 0);
// Special handling if the member to remove is the first member.
@@ -514,7 +558,7 @@ NodeAddr<NodeBase*> InstrNode::getOwner(const DataFlowGraph &G) {
// Add the phi node PA to the given block node.
void BlockNode::addPhi(NodeAddr<PhiNode*> PA, const DataFlowGraph &G) {
- auto M = getFirstMember(G);
+ NodeAddr<NodeBase*> M = getFirstMember(G);
if (M.Id == 0) {
addMember(PA, G);
return;
@@ -560,115 +604,6 @@ NodeAddr<BlockNode*> FuncNode::getEntryBlock(const DataFlowGraph &G) {
return findBlock(EntryB, G);
}
-
-// Register aliasing information.
-//
-// In theory, the lane information could be used to determine register
-// covering (and aliasing), but depending on the sub-register structure,
-// the lane mask information may be missing. The covering information
-// must be available for this framework to work, so relying solely on
-// the lane data is not sufficient.
-
-// Determine whether RA covers RB.
-bool RegisterAliasInfo::covers(RegisterRef RA, RegisterRef RB) const {
- if (RA == RB)
- return true;
- if (TargetRegisterInfo::isVirtualRegister(RA.Reg)) {
- assert(TargetRegisterInfo::isVirtualRegister(RB.Reg));
- if (RA.Reg != RB.Reg)
- return false;
- if (RA.Sub == 0)
- return true;
- return TRI.composeSubRegIndices(RA.Sub, RB.Sub) == RA.Sub;
- }
-
- assert(TargetRegisterInfo::isPhysicalRegister(RA.Reg) &&
- TargetRegisterInfo::isPhysicalRegister(RB.Reg));
- unsigned A = RA.Sub != 0 ? TRI.getSubReg(RA.Reg, RA.Sub) : RA.Reg;
- unsigned B = RB.Sub != 0 ? TRI.getSubReg(RB.Reg, RB.Sub) : RB.Reg;
- return TRI.isSubRegister(A, B);
-}
-
-// Determine whether RR is covered by the set of references RRs.
-bool RegisterAliasInfo::covers(const RegisterSet &RRs, RegisterRef RR) const {
- if (RRs.count(RR))
- return true;
-
- // For virtual registers, we cannot accurately determine covering based
- // on subregisters. If RR itself is not present in RRs, but it has a sub-
- // register reference, check for the super-register alone. Otherwise,
- // assume non-covering.
- if (TargetRegisterInfo::isVirtualRegister(RR.Reg)) {
- if (RR.Sub != 0)
- return RRs.count({RR.Reg, 0});
- return false;
- }
-
- // If any super-register of RR is present, then RR is covered.
- unsigned Reg = RR.Sub == 0 ? RR.Reg : TRI.getSubReg(RR.Reg, RR.Sub);
- for (MCSuperRegIterator SR(Reg, &TRI); SR.isValid(); ++SR)
- if (RRs.count({*SR, 0}))
- return true;
-
- return false;
-}
-
-// Get the list of references aliased to RR.
-std::vector<RegisterRef> RegisterAliasInfo::getAliasSet(RegisterRef RR) const {
- // Do not include RR in the alias set. For virtual registers return an
- // empty set.
- std::vector<RegisterRef> AS;
- if (TargetRegisterInfo::isVirtualRegister(RR.Reg))
- return AS;
- assert(TargetRegisterInfo::isPhysicalRegister(RR.Reg));
- unsigned R = RR.Reg;
- if (RR.Sub)
- R = TRI.getSubReg(RR.Reg, RR.Sub);
-
- for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI)
- AS.push_back(RegisterRef({*AI, 0}));
- return AS;
-}
-
-// Check whether RA and RB are aliased.
-bool RegisterAliasInfo::alias(RegisterRef RA, RegisterRef RB) const {
- bool VirtA = TargetRegisterInfo::isVirtualRegister(RA.Reg);
- bool VirtB = TargetRegisterInfo::isVirtualRegister(RB.Reg);
- bool PhysA = TargetRegisterInfo::isPhysicalRegister(RA.Reg);
- bool PhysB = TargetRegisterInfo::isPhysicalRegister(RB.Reg);
-
- if (VirtA != VirtB)
- return false;
-
- if (VirtA) {
- if (RA.Reg != RB.Reg)
- return false;
- // RA and RB refer to the same register. If any of them refer to the
- // whole register, they must be aliased.
- if (RA.Sub == 0 || RB.Sub == 0)
- return true;
- unsigned SA = TRI.getSubRegIdxSize(RA.Sub);
- unsigned OA = TRI.getSubRegIdxOffset(RA.Sub);
- unsigned SB = TRI.getSubRegIdxSize(RB.Sub);
- unsigned OB = TRI.getSubRegIdxOffset(RB.Sub);
- if (OA <= OB && OA+SA > OB)
- return true;
- if (OB <= OA && OB+SB > OA)
- return true;
- return false;
- }
-
- assert(PhysA && PhysB);
- (void)PhysA, (void)PhysB;
- unsigned A = RA.Sub ? TRI.getSubReg(RA.Reg, RA.Sub) : RA.Reg;
- unsigned B = RB.Sub ? TRI.getSubReg(RB.Reg, RB.Sub) : RB.Reg;
- for (MCRegAliasIterator I(A, &TRI, true); I.isValid(); ++I)
- if (B == *I)
- return true;
- return false;
-}
-
-
// Target operand information.
//
@@ -695,7 +630,7 @@ bool TargetOperandInfo::isFixedReg(const MachineInstr &In, unsigned OpNum)
return true;
// Check for a tail call.
if (In.isBranch())
- for (auto &O : In.operands())
+ for (const MachineOperand &O : In.operands())
if (O.isGlobal() || O.isSymbol())
return true;
@@ -708,7 +643,7 @@ bool TargetOperandInfo::isFixedReg(const MachineInstr &In, unsigned OpNum)
// uses or defs, and those lists do not allow sub-registers.
if (Op.getSubReg() != 0)
return false;
- unsigned Reg = Op.getReg();
+ RegisterId Reg = Op.getReg();
const MCPhysReg *ImpR = Op.isDef() ? D.getImplicitDefs()
: D.getImplicitUses();
if (!ImpR)
@@ -719,6 +654,108 @@ bool TargetOperandInfo::isFixedReg(const MachineInstr &In, unsigned OpNum)
return false;
}
+RegisterRef RegisterAggr::normalize(RegisterRef RR) const {
+ RegisterId SuperReg = RR.Reg;
+ while (true) {
+ MCSuperRegIterator SR(SuperReg, &TRI, false);
+ if (!SR.isValid())
+ break;
+ SuperReg = *SR;
+ }
+
+ const TargetRegisterClass &RC = *TRI.getMinimalPhysRegClass(RR.Reg);
+ LaneBitmask Common = RR.Mask & RC.LaneMask;
+ uint32_t Sub = TRI.getSubRegIndex(SuperReg, RR.Reg);
+ LaneBitmask SuperMask = TRI.composeSubRegIndexLaneMask(Sub, Common);
+ return RegisterRef(SuperReg, SuperMask);
+}
+
+bool RegisterAggr::hasAliasOf(RegisterRef RR) const {
+ RegisterRef NR = normalize(RR);
+ auto F = Masks.find(NR.Reg);
+ if (F != Masks.end()) {
+ if ((F->second & NR.Mask).any())
+ return true;
+ }
+ if (CheckUnits) {
+ for (MCRegUnitIterator U(RR.Reg, &TRI); U.isValid(); ++U)
+ if (ExpAliasUnits.test(*U))
+ return true;
+ }
+ return false;
+}
+
+bool RegisterAggr::hasCoverOf(RegisterRef RR) const {
+ // Always have a cover for empty lane mask.
+ RegisterRef NR = normalize(RR);
+ if (NR.Mask.none())
+ return true;
+ auto F = Masks.find(NR.Reg);
+ if (F == Masks.end())
+ return false;
+ return (NR.Mask & F->second) == NR.Mask;
+}
+
+RegisterAggr &RegisterAggr::insert(RegisterRef RR) {
+ RegisterRef NR = normalize(RR);
+ auto F = Masks.find(NR.Reg);
+ if (F == Masks.end())
+ Masks.insert({NR.Reg, NR.Mask});
+ else
+ F->second |= NR.Mask;
+
+ // Visit all register units to see if there are any that were created
+ // by explicit aliases. Add those that were to the bit vector.
+ for (MCRegUnitIterator U(RR.Reg, &TRI); U.isValid(); ++U) {
+ MCRegUnitRootIterator R(*U, &TRI);
+ ++R;
+ if (!R.isValid())
+ continue;
+ ExpAliasUnits.set(*U);
+ CheckUnits = true;
+ }
+ return *this;
+}
+
+RegisterAggr &RegisterAggr::insert(const RegisterAggr &RG) {
+ for (std::pair<RegisterId,LaneBitmask> P : RG.Masks)
+ insert(RegisterRef(P.first, P.second));
+ return *this;
+}
+
+RegisterAggr &RegisterAggr::clear(RegisterRef RR) {
+ RegisterRef NR = normalize(RR);
+ auto F = Masks.find(NR.Reg);
+ if (F == Masks.end())
+ return *this;
+ LaneBitmask NewM = F->second & ~NR.Mask;
+ if (NewM.none())
+ Masks.erase(F);
+ else
+ F->second = NewM;
+ return *this;
+}
+
+RegisterAggr &RegisterAggr::clear(const RegisterAggr &RG) {
+ for (std::pair<RegisterId,LaneBitmask> P : RG.Masks)
+ clear(RegisterRef(P.first, P.second));
+ return *this;
+}
+
+RegisterRef RegisterAggr::clearIn(RegisterRef RR) const {
+ RegisterAggr T(TRI);
+ T.insert(RR).clear(*this);
+ if (T.empty())
+ return RegisterRef();
+ return RegisterRef(T.begin()->first, T.begin()->second);
+}
+
+void RegisterAggr::print(raw_ostream &OS) const {
+ OS << '{';
+ for (auto I : Masks)
+ OS << ' ' << PrintReg(I.first, &TRI) << PrintLaneMaskOpt(I.second);
+ OS << " }";
+}
//
// The data flow graph construction.
@@ -726,13 +763,10 @@ bool TargetOperandInfo::isFixedReg(const MachineInstr &In, unsigned OpNum)
DataFlowGraph::DataFlowGraph(MachineFunction &mf, const TargetInstrInfo &tii,
const TargetRegisterInfo &tri, const MachineDominatorTree &mdt,
- const MachineDominanceFrontier &mdf, const RegisterAliasInfo &rai,
- const TargetOperandInfo &toi)
- : TimeG("rdf"), MF(mf), TII(tii), TRI(tri), MDT(mdt), MDF(mdf), RAI(rai),
- TOI(toi) {
+ const MachineDominanceFrontier &mdf, const TargetOperandInfo &toi)
+ : MF(mf), TII(tii), TRI(tri), MDT(mdt), MDF(mdf), TOI(toi) {
}
-
// The implementation of the definition stack.
// Each register reference has its own definition stack. In particular,
// for a register references "Reg" and "Reg:subreg" will each have their
@@ -821,6 +855,32 @@ unsigned DataFlowGraph::DefStack::nextDown(unsigned P) const {
return P;
}
+// Register information.
+
+// Get the list of references aliased to RR. Lane masks are ignored.
+RegisterSet DataFlowGraph::getAliasSet(RegisterId Reg) const {
+ // Do not include RR in the alias set.
+ RegisterSet AS;
+ assert(TargetRegisterInfo::isPhysicalRegister(Reg));
+
+ for (MCRegAliasIterator AI(Reg, &TRI, false); AI.isValid(); ++AI)
+ AS.insert(RegisterRef(*AI));
+ return AS;
+}
+
+RegisterSet DataFlowGraph::getLandingPadLiveIns() const {
+ RegisterSet LR;
+ const Function &F = *MF.getFunction();
+ const Constant *PF = F.hasPersonalityFn() ? F.getPersonalityFn()
+ : nullptr;
+ const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
+ if (RegisterId R = TLI.getExceptionPointerRegister(PF))
+ LR.insert(RegisterRef(R));
+ if (RegisterId R = TLI.getExceptionSelectorRegister(PF))
+ LR.insert(RegisterRef(R));
+ return LR;
+}
+
// Node management functions.
// Get the pointer to the node with the id N.
@@ -864,13 +924,12 @@ NodeAddr<NodeBase*> DataFlowGraph::cloneNode(const NodeAddr<NodeBase*> B) {
return NA;
}
-
// Allocation routines for specific node types/kinds.
NodeAddr<UseNode*> DataFlowGraph::newUse(NodeAddr<InstrNode*> Owner,
MachineOperand &Op, uint16_t Flags) {
NodeAddr<UseNode*> UA = newNode(NodeAttrs::Ref | NodeAttrs::Use | Flags);
- UA.Addr->setRegRef(&Op);
+ UA.Addr->setRegRef(&Op, *this);
return UA;
}
@@ -878,7 +937,7 @@ NodeAddr<PhiUseNode*> DataFlowGraph::newPhiUse(NodeAddr<PhiNode*> Owner,
RegisterRef RR, NodeAddr<BlockNode*> PredB, uint16_t Flags) {
NodeAddr<PhiUseNode*> PUA = newNode(NodeAttrs::Ref | NodeAttrs::Use | Flags);
assert(Flags & NodeAttrs::PhiRef);
- PUA.Addr->setRegRef(RR);
+ PUA.Addr->setRegRef(RR, *this);
PUA.Addr->setPredecessor(PredB.Id);
return PUA;
}
@@ -886,7 +945,7 @@ NodeAddr<PhiUseNode*> DataFlowGraph::newPhiUse(NodeAddr<PhiNode*> Owner,
NodeAddr<DefNode*> DataFlowGraph::newDef(NodeAddr<InstrNode*> Owner,
MachineOperand &Op, uint16_t Flags) {
NodeAddr<DefNode*> DA = newNode(NodeAttrs::Ref | NodeAttrs::Def | Flags);
- DA.Addr->setRegRef(&Op);
+ DA.Addr->setRegRef(&Op, *this);
return DA;
}
@@ -894,7 +953,7 @@ NodeAddr<DefNode*> DataFlowGraph::newDef(NodeAddr<InstrNode*> Owner,
RegisterRef RR, uint16_t Flags) {
NodeAddr<DefNode*> DA = newNode(NodeAttrs::Ref | NodeAttrs::Def | Flags);
assert(Flags & NodeAttrs::PhiRef);
- DA.Addr->setRegRef(RR);
+ DA.Addr->setRegRef(RR, *this);
return DA;
}
@@ -934,17 +993,20 @@ void DataFlowGraph::build(unsigned Options) {
if (MF.empty())
return;
- for (auto &B : MF) {
- auto BA = newBlock(Func, &B);
- for (auto &I : B) {
+ for (MachineBasicBlock &B : MF) {
+ NodeAddr<BlockNode*> BA = newBlock(Func, &B);
+ BlockNodes.insert(std::make_pair(&B, BA));
+ for (MachineInstr &I : B) {
if (I.isDebugValue())
continue;
buildStmt(BA, I);
}
}
- // Collect information about block references.
NodeAddr<BlockNode*> EA = Func.Addr->getEntryBlock(*this);
+ NodeList Blocks = Func.Addr->members(*this);
+
+ // Collect information about block references.
BlockRefsMap RefM;
buildBlockRefs(EA, RefM);
@@ -952,16 +1014,48 @@ void DataFlowGraph::build(unsigned Options) {
MachineRegisterInfo &MRI = MF.getRegInfo();
for (auto I = MRI.livein_begin(), E = MRI.livein_end(); I != E; ++I) {
NodeAddr<PhiNode*> PA = newPhi(EA);
- RegisterRef RR = { I->first, 0 };
+ RegisterRef RR = RegisterRef(I->first);
uint16_t PhiFlags = NodeAttrs::PhiRef | NodeAttrs::Preserving;
NodeAddr<DefNode*> DA = newDef(PA, RR, PhiFlags);
PA.Addr->addMember(DA, *this);
}
+ // Add phis for landing pads.
+ // Landing pads, unlike usual backs blocks, are not entered through
+ // branches in the program, or fall-throughs from other blocks. They
+ // are entered from the exception handling runtime and target's ABI
+ // may define certain registers as defined on entry to such a block.
+ RegisterSet EHRegs = getLandingPadLiveIns();
+ if (!EHRegs.empty()) {
+ for (NodeAddr<BlockNode*> BA : Blocks) {
+ const MachineBasicBlock &B = *BA.Addr->getCode();
+ if (!B.isEHPad())
+ continue;
+
+ // Prepare a list of NodeIds of the block's predecessors.
+ NodeList Preds;
+ for (MachineBasicBlock *PB : B.predecessors())
+ Preds.push_back(findBlock(PB));
+
+ // Build phi nodes for each live-in.
+ for (RegisterRef RR : EHRegs) {
+ NodeAddr<PhiNode*> PA = newPhi(BA);
+ uint16_t PhiFlags = NodeAttrs::PhiRef | NodeAttrs::Preserving;
+ // Add def:
+ NodeAddr<DefNode*> DA = newDef(PA, RR, PhiFlags);
+ PA.Addr->addMember(DA, *this);
+ // Add uses (no reaching defs for phi uses):
+ for (NodeAddr<BlockNode*> PBA : Preds) {
+ NodeAddr<PhiUseNode*> PUA = newPhiUse(PA, RR, PBA);
+ PA.Addr->addMember(PUA, *this);
+ }
+ }
+ }
+ }
+
// Build a map "PhiM" which will contain, for each block, the set
// of references that will require phi definitions in that block.
BlockRefsMap PhiM;
- auto Blocks = Func.Addr->members(*this);
for (NodeAddr<BlockNode*> BA : Blocks)
recordDefsForDF(PhiM, RefM, BA);
for (NodeAddr<BlockNode*> BA : Blocks)
@@ -976,6 +1070,47 @@ void DataFlowGraph::build(unsigned Options) {
removeUnusedPhis();
}
+RegisterRef DataFlowGraph::makeRegRef(unsigned Reg, unsigned Sub) const {
+ assert(TargetRegisterInfo::isPhysicalRegister(Reg));
+ if (Sub != 0)
+ Reg = TRI.getSubReg(Reg, Sub);
+ return RegisterRef(Reg);
+}
+
+RegisterRef DataFlowGraph::normalizeRef(RegisterRef RR) const {
+ // FIXME copied from RegisterAggr
+ RegisterId SuperReg = RR.Reg;
+ while (true) {
+ MCSuperRegIterator SR(SuperReg, &TRI, false);
+ if (!SR.isValid())
+ break;
+ SuperReg = *SR;
+ }
+
+ uint32_t Sub = TRI.getSubRegIndex(SuperReg, RR.Reg);
+ const TargetRegisterClass &RC = *TRI.getMinimalPhysRegClass(RR.Reg);
+ LaneBitmask SuperMask = RR.Mask &
+ TRI.composeSubRegIndexLaneMask(Sub, RC.LaneMask);
+ return RegisterRef(SuperReg, SuperMask);
+}
+
+RegisterRef DataFlowGraph::restrictRef(RegisterRef AR, RegisterRef BR) const {
+ if (AR.Reg == BR.Reg) {
+ LaneBitmask M = AR.Mask & BR.Mask;
+ return M.any() ? RegisterRef(AR.Reg, M) : RegisterRef();
+ }
+#ifndef NDEBUG
+ RegisterRef NAR = normalizeRef(AR);
+ RegisterRef NBR = normalizeRef(BR);
+ assert(NAR.Reg != NBR.Reg);
+#endif
+ // This isn't strictly correct, because the overlap may happen in the
+ // part masked out.
+ if (TRI.regsOverlap(AR.Reg, BR.Reg))
+ return AR;
+ return RegisterRef();
+}
+
// For each stack in the map DefM, push the delimiter for block B on it.
void DataFlowGraph::markBlock(NodeId B, DefStackMap &DefM) {
// Push block delimiters.
@@ -1024,28 +1159,31 @@ void DataFlowGraph::pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DefM) {
for (NodeAddr<DefNode*> DA : Defs) {
if (Visited.count(DA.Id))
continue;
+
NodeList Rel = getRelatedRefs(IA, DA);
NodeAddr<DefNode*> PDA = Rel.front();
- // Push the definition on the stack for the register and all aliases.
- RegisterRef RR = PDA.Addr->getRegRef();
+ RegisterRef RR = PDA.Addr->getRegRef(*this);
#ifndef NDEBUG
// Assert if the register is defined in two or more unrelated defs.
// This could happen if there are two or more def operands defining it.
if (!Defined.insert(RR).second) {
- auto *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
+ MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
dbgs() << "Multiple definitions of register: "
<< Print<RegisterRef>(RR, *this) << " in\n " << *MI
<< "in BB#" << MI->getParent()->getNumber() << '\n';
llvm_unreachable(nullptr);
}
#endif
- DefM[RR].push(DA);
- for (auto A : RAI.getAliasSet(RR)) {
+ // Push the definition on the stack for the register and all aliases.
+ // The def stack traversal in linkNodeUp will check the exact aliasing.
+ DefM[RR.Reg].push(DA);
+ for (RegisterRef A : getAliasSet(RR.Reg /*FIXME? use RegisterRef*/)) {
+ // Check that we don't push the same def twice.
assert(A != RR);
- DefM[A].push(DA);
+ DefM[A.Reg].push(DA);
}
// Mark all the related defs as visited.
- for (auto T : Rel)
+ for (NodeAddr<NodeBase*> T : Rel)
Visited.insert(T.Id);
}
}
@@ -1065,14 +1203,66 @@ NodeList DataFlowGraph::getRelatedRefs(NodeAddr<InstrNode*> IA,
return Refs;
}
+// Return true if RA and RB overlap, false otherwise.
+bool DataFlowGraph::alias(RegisterRef RA, RegisterRef RB) const {
+ assert(TargetRegisterInfo::isPhysicalRegister(RA.Reg));
+ assert(TargetRegisterInfo::isPhysicalRegister(RB.Reg));
+
+ MCRegUnitMaskIterator UMA(RA.Reg, &TRI);
+ MCRegUnitMaskIterator UMB(RB.Reg, &TRI);
+ // Reg units are returned in the numerical order.
+ while (UMA.isValid() && UMB.isValid()) {
+ std::pair<uint32_t,LaneBitmask> PA = *UMA;
+ std::pair<uint32_t,LaneBitmask> PB = *UMB;
+ if (PA.first == PB.first) {
+ // Lane mask of 0 (given by the iterator) should be treated as "full".
+ // This can happen when the register has only one unit, or when the
+ // unit corresponds to explicit aliasing. In such cases, the lane mask
+ // from RegisterRef should be ignored.
+ if (PA.second.none() || PB.second.none())
+ return true;
+
+ // At this point the common unit corresponds to a subregister. The lane
+ // masks correspond to the lane mask of that unit within the original
+ // register, for example assuming register quadruple q0 = r3:0, and
+ // a register pair d1 = r3:2, the lane mask of r2 in q0 may be 0b0100,
+ // while the lane mask of r2 in d1 may be 0b0001.
+ LaneBitmask LA = PA.second & RA.Mask;
+ LaneBitmask LB = PB.second & RB.Mask;
+ if (LA.any() && LB.any()) {
+ unsigned Root = *MCRegUnitRootIterator(PA.first, &TRI);
+ // If register units were guaranteed to only have 1 bit in any lane
+ // mask, the code below would not be necessary. This is because LA
+ // and LB would have at most 1 bit set each, and that bit would be
+ // guaranteed to correspond to the given register unit.
+ uint32_t SubA = TRI.getSubRegIndex(RA.Reg, Root);
+ uint32_t SubB = TRI.getSubRegIndex(RB.Reg, Root);
+ const TargetRegisterClass &RC = *TRI.getMinimalPhysRegClass(Root);
+ LaneBitmask MaskA = TRI.reverseComposeSubRegIndexLaneMask(SubA, LA);
+ LaneBitmask MaskB = TRI.reverseComposeSubRegIndexLaneMask(SubB, LB);
+ if ((MaskA & MaskB & RC.LaneMask).any())
+ return true;
+ }
+
+ ++UMA;
+ ++UMB;
+ continue;
+ }
+ if (PA.first < PB.first)
+ ++UMA;
+ else if (PB.first < PA.first)
+ ++UMB;
+ }
+ return false;
+}
// Clear all information in the graph.
void DataFlowGraph::reset() {
Memory.clear();
+ BlockNodes.clear();
Func = NodeAddr<FuncNode*>();
}
-
// Return the next reference node in the instruction node IA that is related
// to RA. Conceptually, two reference nodes are related if they refer to the
// same instance of a register access, but differ in flags or other minor
@@ -1083,10 +1273,10 @@ NodeAddr<RefNode*> DataFlowGraph::getNextRelated(NodeAddr<InstrNode*> IA,
NodeAddr<RefNode*> RA) const {
assert(IA.Id != 0 && RA.Id != 0);
- auto Related = [RA](NodeAddr<RefNode*> TA) -> bool {
+ auto Related = [this,RA](NodeAddr<RefNode*> TA) -> bool {
if (TA.Addr->getKind() != RA.Addr->getKind())
return false;
- if (TA.Addr->getRegRef() != RA.Addr->getRegRef())
+ if (TA.Addr->getRegRef(*this) != RA.Addr->getRegRef(*this))
return false;
return true;
};
@@ -1105,7 +1295,7 @@ NodeAddr<RefNode*> DataFlowGraph::getNextRelated(NodeAddr<InstrNode*> IA,
return TUA.Addr->getPredecessor() == RUA.Addr->getPredecessor();
};
- RegisterRef RR = RA.Addr->getRegRef();
+ RegisterRef RR = RA.Addr->getRegRef(*this);
if (IA.Addr->getKind() == NodeAttrs::Stmt)
return RA.Addr->getNextRef(RR, RelatedStmt, true, *this);
return RA.Addr->getNextRef(RR, RelatedPhi, true, *this);
@@ -1174,31 +1364,45 @@ NodeAddr<RefNode*> DataFlowGraph::getNextShadow(NodeAddr<InstrNode*> IA,
// Create a new statement node in the block node BA that corresponds to
// the machine instruction MI.
void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
- auto SA = newStmt(BA, &In);
+ NodeAddr<StmtNode*> SA = newStmt(BA, &In);
auto isCall = [] (const MachineInstr &In) -> bool {
if (In.isCall())
return true;
// Is tail call?
if (In.isBranch())
- for (auto &Op : In.operands())
+ for (const MachineOperand &Op : In.operands())
if (Op.isGlobal() || Op.isSymbol())
return true;
return false;
};
+ auto isDefUndef = [this] (const MachineInstr &In, RegisterRef DR) -> bool {
+ // This instruction defines DR. Check if there is a use operand that
+ // would make DR live on entry to the instruction.
+ for (const MachineOperand &UseOp : In.operands()) {
+ if (!UseOp.isReg() || !UseOp.isUse() || UseOp.isUndef())
+ continue;
+ RegisterRef UR = makeRegRef(UseOp.getReg(), UseOp.getSubReg());
+ if (alias(DR, UR))
+ return false;
+ }
+ return true;
+ };
+
// Collect a set of registers that this instruction implicitly uses
// or defines. Implicit operands from an instruction will be ignored
// unless they are listed here.
RegisterSet ImpUses, ImpDefs;
if (const uint16_t *ImpD = In.getDesc().getImplicitDefs())
while (uint16_t R = *ImpD++)
- ImpDefs.insert({R, 0});
+ ImpDefs.insert(RegisterRef(R));
if (const uint16_t *ImpU = In.getDesc().getImplicitUses())
while (uint16_t R = *ImpU++)
- ImpUses.insert({R, 0});
+ ImpUses.insert(RegisterRef(R));
- bool NeedsImplicit = isCall(In) || In.isInlineAsm() || In.isReturn();
+ bool IsCall = isCall(In);
+ bool NeedsImplicit = IsCall || In.isInlineAsm() || In.isReturn();
bool IsPredicated = TII.isPredicated(In);
unsigned NumOps = In.getNumOperands();
@@ -1212,14 +1416,20 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
MachineOperand &Op = In.getOperand(OpN);
if (!Op.isReg() || !Op.isDef() || Op.isImplicit())
continue;
- RegisterRef RR = { Op.getReg(), Op.getSubReg() };
+ RegisterRef RR = makeRegRef(Op.getReg(), Op.getSubReg());
uint16_t Flags = NodeAttrs::None;
- if (TOI.isPreserving(In, OpN))
+ if (TOI.isPreserving(In, OpN)) {
Flags |= NodeAttrs::Preserving;
+ // If the def is preserving, check if it is also undefined.
+ if (isDefUndef(In, RR))
+ Flags |= NodeAttrs::Undef;
+ }
if (TOI.isClobbering(In, OpN))
Flags |= NodeAttrs::Clobbering;
if (TOI.isFixedReg(In, OpN))
Flags |= NodeAttrs::Fixed;
+ if (IsCall && Op.isDead())
+ Flags |= NodeAttrs::Dead;
NodeAddr<DefNode*> DA = newDef(SA, Op, Flags);
SA.Addr->addMember(DA, *this);
DoneDefs.insert(RR);
@@ -1231,18 +1441,24 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
MachineOperand &Op = In.getOperand(OpN);
if (!Op.isReg() || !Op.isDef() || !Op.isImplicit())
continue;
- RegisterRef RR = { Op.getReg(), Op.getSubReg() };
+ RegisterRef RR = makeRegRef(Op.getReg(), Op.getSubReg());
if (!NeedsImplicit && !ImpDefs.count(RR))
continue;
if (DoneDefs.count(RR))
continue;
uint16_t Flags = NodeAttrs::None;
- if (TOI.isPreserving(In, OpN))
+ if (TOI.isPreserving(In, OpN)) {
Flags |= NodeAttrs::Preserving;
+ // If the def is preserving, check if it is also undefined.
+ if (isDefUndef(In, RR))
+ Flags |= NodeAttrs::Undef;
+ }
if (TOI.isClobbering(In, OpN))
Flags |= NodeAttrs::Clobbering;
if (TOI.isFixedReg(In, OpN))
Flags |= NodeAttrs::Fixed;
+ if (IsCall && Op.isDead())
+ Flags |= NodeAttrs::Dead;
NodeAddr<DefNode*> DA = newDef(SA, Op, Flags);
SA.Addr->addMember(DA, *this);
DoneDefs.insert(RR);
@@ -1252,7 +1468,7 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
MachineOperand &Op = In.getOperand(OpN);
if (!Op.isReg() || !Op.isUse())
continue;
- RegisterRef RR = { Op.getReg(), Op.getSubReg() };
+ RegisterRef RR = makeRegRef(Op.getReg(), Op.getSubReg());
// Add implicit uses on return and call instructions, and on predicated
// instructions regardless of whether or not they appear in the instruction
// descriptor's list.
@@ -1261,6 +1477,8 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
if (Implicit && !TakeImplicit && !ImpUses.count(RR))
continue;
uint16_t Flags = NodeAttrs::None;
+ if (Op.isUndef())
+ Flags |= NodeAttrs::Undef;
if (TOI.isFixedReg(In, OpN))
Flags |= NodeAttrs::Fixed;
NodeAddr<UseNode*> UA = newUse(SA, Op, Flags);
@@ -1272,20 +1490,20 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
// that block, and from all blocks dominated by it.
void DataFlowGraph::buildBlockRefs(NodeAddr<BlockNode*> BA,
BlockRefsMap &RefM) {
- auto &Refs = RefM[BA.Id];
+ RegisterSet &Refs = RefM[BA.Id];
MachineDomTreeNode *N = MDT.getNode(BA.Addr->getCode());
assert(N);
for (auto I : *N) {
MachineBasicBlock *SB = I->getBlock();
- auto SBA = Func.Addr->findBlock(SB, *this);
+ NodeAddr<BlockNode*> SBA = findBlock(SB);
buildBlockRefs(SBA, RefM);
- const auto &SRs = RefM[SBA.Id];
- Refs.insert(SRs.begin(), SRs.end());
+ const RegisterSet &RefsS = RefM[SBA.Id];
+ Refs.insert(RefsS.begin(), RefsS.end());
}
for (NodeAddr<InstrNode*> IA : BA.Addr->members(*this))
for (NodeAddr<RefNode*> RA : IA.Addr->members(*this))
- Refs.insert(RA.Addr->getRegRef());
+ Refs.insert(RA.Addr->getRegRef(*this));
}
// Scan all defs in the block node BA and record in PhiM the locations of
@@ -1307,17 +1525,11 @@ void DataFlowGraph::recordDefsForDF(BlockRefsMap &PhiM, BlockRefsMap &RefM,
// This is done to make sure that each defined reference gets only one
// phi node, even if it is defined multiple times.
RegisterSet Defs;
- for (auto I : BA.Addr->members(*this)) {
- assert(I.Addr->getType() == NodeAttrs::Code);
- assert(I.Addr->getKind() == NodeAttrs::Phi ||
- I.Addr->getKind() == NodeAttrs::Stmt);
- NodeAddr<InstrNode*> IA = I;
+ for (NodeAddr<InstrNode*> IA : BA.Addr->members(*this))
for (NodeAddr<RefNode*> RA : IA.Addr->members_if(IsDef, *this))
- Defs.insert(RA.Addr->getRegRef());
- }
+ Defs.insert(RA.Addr->getRegRef(*this));
- // Finally, add the set of defs to each block in the iterated dominance
- // frontier.
+ // Calculate the iterated dominance frontier of BB.
const MachineDominanceFrontier::DomSetType &DF = DFLoc->second;
SetVector<MachineBasicBlock*> IDF(DF.begin(), DF.end());
for (unsigned i = 0; i < IDF.size(); ++i) {
@@ -1329,13 +1541,15 @@ void DataFlowGraph::recordDefsForDF(BlockRefsMap &PhiM, BlockRefsMap &RefM,
// Get the register references that are reachable from this block.
RegisterSet &Refs = RefM[BA.Id];
for (auto DB : IDF) {
- auto DBA = Func.Addr->findBlock(DB, *this);
- const auto &Rs = RefM[DBA.Id];
- Refs.insert(Rs.begin(), Rs.end());
+ NodeAddr<BlockNode*> DBA = findBlock(DB);
+ const RegisterSet &RefsD = RefM[DBA.Id];
+ Refs.insert(RefsD.begin(), RefsD.end());
}
+ // Finally, add the set of defs to each block in the iterated dominance
+ // frontier.
for (auto DB : IDF) {
- auto DBA = Func.Addr->findBlock(DB, *this);
+ NodeAddr<BlockNode*> DBA = findBlock(DB);
PhiM[DBA.Id].insert(Defs.begin(), Defs.end());
}
}
@@ -1355,19 +1569,19 @@ void DataFlowGraph::buildPhis(BlockRefsMap &PhiM, BlockRefsMap &RefM,
// are not covered by another ref (i.e. maximal with respect to covering).
auto MaxCoverIn = [this] (RegisterRef RR, RegisterSet &RRs) -> RegisterRef {
- for (auto I : RRs)
- if (I != RR && RAI.covers(I, RR))
+ for (RegisterRef I : RRs)
+ if (I != RR && RegisterAggr::isCoverOf(I, RR, TRI))
RR = I;
return RR;
};
RegisterSet MaxDF;
- for (auto I : HasDF->second)
+ for (RegisterRef I : HasDF->second)
MaxDF.insert(MaxCoverIn(I, HasDF->second));
std::vector<RegisterRef> MaxRefs;
- auto &RefB = RefM[BA.Id];
- for (auto I : MaxDF)
+ RegisterSet &RefB = RefM[BA.Id];
+ for (RegisterRef I : MaxDF)
MaxRefs.push_back(MaxCoverIn(I, RefB));
// Now, for each R in MaxRefs, get the alias closure of R. If the closure
@@ -1382,19 +1596,17 @@ void DataFlowGraph::buildPhis(BlockRefsMap &PhiM, BlockRefsMap &RefM,
auto Aliased = [this,&MaxRefs](RegisterRef RR,
std::vector<unsigned> &Closure) -> bool {
- for (auto I : Closure)
- if (RAI.alias(RR, MaxRefs[I]))
+ for (unsigned I : Closure)
+ if (alias(RR, MaxRefs[I]))
return true;
return false;
};
// Prepare a list of NodeIds of the block's predecessors.
- std::vector<NodeId> PredList;
+ NodeList Preds;
const MachineBasicBlock *MBB = BA.Addr->getCode();
- for (auto PB : MBB->predecessors()) {
- auto B = Func.Addr->findBlock(PB, *this);
- PredList.push_back(B.Id);
- }
+ for (MachineBasicBlock *PB : MBB->predecessors())
+ Preds.push_back(findBlock(PB));
while (!MaxRefs.empty()) {
// Put the first element in the closure, and then add all subsequent
@@ -1418,8 +1630,7 @@ void DataFlowGraph::buildPhis(BlockRefsMap &PhiM, BlockRefsMap &RefM,
PA.Addr->addMember(DA, *this);
}
// Add phi uses.
- for (auto P : PredList) {
- auto PBA = addr<BlockNode*>(P);
+ for (NodeAddr<BlockNode*> PBA : Preds) {
for (unsigned X = 0; X != CS; ++X) {
RegisterRef RR = MaxRefs[ClosureIdx[X]];
NodeAddr<PhiUseNode*> PUA = newPhiUse(PA, RR, PBA);
@@ -1449,7 +1660,7 @@ void DataFlowGraph::removeUnusedPhis() {
}
static auto HasUsedDef = [](NodeList &Ms) -> bool {
- for (auto M : Ms) {
+ for (NodeAddr<NodeBase*> M : Ms) {
if (M.Addr->getKind() != NodeAttrs::Def)
continue;
NodeAddr<DefNode*> DA = M;
@@ -1493,25 +1704,25 @@ void DataFlowGraph::linkRefUp(NodeAddr<InstrNode*> IA, NodeAddr<T> TA,
DefStack &DS) {
if (DS.empty())
return;
- RegisterRef RR = TA.Addr->getRegRef();
+ RegisterRef RR = TA.Addr->getRegRef(*this);
NodeAddr<T> TAP;
// References from the def stack that have been examined so far.
- RegisterSet Defs;
+ RegisterAggr Defs(TRI);
for (auto I = DS.top(), E = DS.bottom(); I != E; I.down()) {
- RegisterRef QR = I->Addr->getRegRef();
- auto AliasQR = [QR,this] (RegisterRef RR) -> bool {
- return RAI.alias(QR, RR);
- };
- bool PrecUp = RAI.covers(QR, RR);
+ RegisterRef QR = I->Addr->getRegRef(*this);
+
// Skip all defs that are aliased to any of the defs that we have already
- // seen. If we encounter a covering def, stop the stack traversal early.
- if (std::any_of(Defs.begin(), Defs.end(), AliasQR)) {
- if (PrecUp)
+ // seen. If this completes a cover of RR, stop the stack traversal.
+ bool Alias = Defs.hasAliasOf(QR);
+ bool Cover = Defs.insert(QR).hasCoverOf(RR);
+ if (Alias) {
+ if (Cover)
break;
continue;
}
+
// The reaching def.
NodeAddr<DefNode*> RDA = *I;
@@ -1527,27 +1738,29 @@ void DataFlowGraph::linkRefUp(NodeAddr<InstrNode*> IA, NodeAddr<T> TA,
// Create the link.
TAP.Addr->linkToDef(TAP.Id, RDA);
- if (PrecUp)
+ if (Cover)
break;
- Defs.insert(QR);
}
}
// Create data-flow links for all reference nodes in the statement node SA.
void DataFlowGraph::linkStmtRefs(DefStackMap &DefM, NodeAddr<StmtNode*> SA) {
+#ifndef NDEBUG
RegisterSet Defs;
+#endif
// Link all nodes (upwards in the data-flow) with their reaching defs.
for (NodeAddr<RefNode*> RA : SA.Addr->members(*this)) {
uint16_t Kind = RA.Addr->getKind();
assert(Kind == NodeAttrs::Def || Kind == NodeAttrs::Use);
- RegisterRef RR = RA.Addr->getRegRef();
- // Do not process multiple defs of the same reference.
- if (Kind == NodeAttrs::Def && Defs.count(RR))
- continue;
+ RegisterRef RR = RA.Addr->getRegRef(*this);
+#ifndef NDEBUG
+ // Do not expect multiple defs of the same reference.
+ assert(Kind != NodeAttrs::Def || !Defs.count(RR));
Defs.insert(RR);
+#endif
- auto F = DefM.find(RR);
+ auto F = DefM.find(RR.Reg);
if (F == DefM.end())
continue;
DefStack &DS = F->second;
@@ -1584,7 +1797,7 @@ void DataFlowGraph::linkBlockRefs(DefStackMap &DefM, NodeAddr<BlockNode*> BA) {
MachineDomTreeNode *N = MDT.getNode(BA.Addr->getCode());
for (auto I : *N) {
MachineBasicBlock *SB = I->getBlock();
- auto SBA = Func.Addr->findBlock(SB, *this);
+ NodeAddr<BlockNode*> SBA = findBlock(SB);
linkBlockRefs(DefM, SBA);
}
@@ -1596,15 +1809,27 @@ void DataFlowGraph::linkBlockRefs(DefStackMap &DefM, NodeAddr<BlockNode*> BA) {
NodeAddr<PhiUseNode*> PUA = NA;
return PUA.Addr->getPredecessor() == BA.Id;
};
+
+ RegisterSet EHLiveIns = getLandingPadLiveIns();
MachineBasicBlock *MBB = BA.Addr->getCode();
- for (auto SB : MBB->successors()) {
- auto SBA = Func.Addr->findBlock(SB, *this);
+
+ for (MachineBasicBlock *SB : MBB->successors()) {
+ bool IsEHPad = SB->isEHPad();
+ NodeAddr<BlockNode*> SBA = findBlock(SB);
for (NodeAddr<InstrNode*> IA : SBA.Addr->members_if(IsPhi, *this)) {
+ // Do not link phi uses for landing pad live-ins.
+ if (IsEHPad) {
+ // Find what register this phi is for.
+ NodeAddr<RefNode*> RA = IA.Addr->getFirstMember(*this);
+ assert(RA.Id != 0);
+ if (EHLiveIns.count(RA.Addr->getRegRef(*this)))
+ continue;
+ }
// Go over each phi use associated with MBB, and link it.
for (auto U : IA.Addr->members_if(IsUseForBA, *this)) {
NodeAddr<PhiUseNode*> PUA = U;
- RegisterRef RR = PUA.Addr->getRegRef();
- linkRefUp<UseNode*>(IA, PUA, DefM[RR]);
+ RegisterRef RR = PUA.Addr->getRegRef(*this);
+ linkRefUp<UseNode*>(IA, PUA, DefM[RR.Reg]);
}
}
}
diff --git a/contrib/llvm/lib/Target/Hexagon/RDFGraph.h b/contrib/llvm/lib/Target/Hexagon/RDFGraph.h
index 49b0537..49d78a8 100644
--- a/contrib/llvm/lib/Target/Hexagon/RDFGraph.h
+++ b/contrib/llvm/lib/Target/Hexagon/RDFGraph.h
@@ -1,4 +1,4 @@
-//===--- RDFGraph.h -------------------------------------------------------===//
+//===--- RDFGraph.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -175,7 +175,29 @@
// - Clobbering: applied only to defs, indicates that the value generated
// by this def is unspecified. A typical example would be volatile registers
// after function calls.
-//
+// - Fixed: the register in this def/use cannot be replaced with any other
+// register. A typical case would be a parameter register to a call, or
+// the register with the return value from a function.
+// - Undef: the register in this reference the register is assumed to have
+// no pre-existing value, even if it appears to be reached by some def.
+// This is typically used to prevent keeping registers artificially live
+// in cases when they are defined via predicated instructions. For example:
+// r0 = add-if-true cond, r10, r11 (1)
+// r0 = add-if-false cond, r12, r13, r0<imp-use> (2)
+// ... = r0 (3)
+// Before (1), r0 is not intended to be live, and the use of r0 in (3) is
+// not meant to be reached by any def preceding (1). However, since the
+// defs in (1) and (2) are both preserving, these properties alone would
+// imply that the use in (3) may indeed be reached by some prior def.
+// Adding Undef flag to the def in (1) prevents that. The Undef flag
+// may be applied to both defs and uses.
+// - Dead: applies only to defs. The value coming out of a "dead" def is
+// assumed to be unused, even if the def appears to be reaching other defs
+// or uses. The motivation for this flag comes from dead defs on function
+// calls: there is no way to determine if such a def is dead without
+// analyzing the target's ABI. Hence the graph should contain this info,
+// as it is unavailable otherwise. On the other hand, a def without any
+// uses on a typical instruction is not the intended target for this flag.
//
// *** Shadow references
//
@@ -199,20 +221,34 @@
// The statement s5 has two use nodes for t0: u7" and u9". The quotation
// mark " indicates that the node is a shadow.
//
-#ifndef RDF_GRAPH_H
-#define RDF_GRAPH_H
+#ifndef LLVM_LIB_TARGET_HEXAGON_RDFGRAPH_H
+#define LLVM_LIB_TARGET_HEXAGON_RDFGRAPH_H
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/LaneBitmask.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Timer.h"
-
+#include "llvm/Target/TargetRegisterInfo.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
#include <functional>
#include <map>
#include <set>
+#include <unordered_map>
+#include <utility>
#include <vector>
+// RDF uses uint32_t to refer to registers. This is to ensure that the type
+// size remains specific. In other places, registers are often stored using
+// unsigned.
+static_assert(sizeof(uint32_t) == sizeof(unsigned), "Those should be equal");
+
namespace llvm {
+
class MachineBasicBlock;
class MachineFunction;
class MachineInstr;
@@ -220,10 +256,13 @@ namespace llvm {
class MachineDominanceFrontier;
class MachineDominatorTree;
class TargetInstrInfo;
- class TargetRegisterInfo;
namespace rdf {
+
typedef uint32_t NodeId;
+ typedef uint32_t RegisterId;
+
+ struct DataFlowGraph;
struct NodeAttrs {
enum : uint16_t {
@@ -243,13 +282,15 @@ namespace rdf {
Block = 0x0005 << 2, // 101
Func = 0x0006 << 2, // 110
- // Flags: 5 bits for now
- FlagMask = 0x001F << 5,
- Shadow = 0x0001 << 5, // 00001, Has extra reaching defs.
- Clobbering = 0x0002 << 5, // 00010, Produces unspecified values.
- PhiRef = 0x0004 << 5, // 00100, Member of PhiNode.
- Preserving = 0x0008 << 5, // 01000, Def can keep original bits.
- Fixed = 0x0010 << 5, // 10000, Fixed register.
+ // Flags: 7 bits for now
+ FlagMask = 0x007F << 5,
+ Shadow = 0x0001 << 5, // 0000001, Has extra reaching defs.
+ Clobbering = 0x0002 << 5, // 0000010, Produces unspecified values.
+ PhiRef = 0x0004 << 5, // 0000100, Member of PhiNode.
+ Preserving = 0x0008 << 5, // 0001000, Def can keep original bits.
+ Fixed = 0x0010 << 5, // 0010000, Fixed register.
+ Undef = 0x0020 << 5, // 0100000, Has no pre-existing value.
+ Dead = 0x0040 << 5, // 1000000, Does not define a value.
};
static uint16_t type(uint16_t T) { return T & TypeMask; }
@@ -259,9 +300,11 @@ namespace rdf {
static uint16_t set_type(uint16_t A, uint16_t T) {
return (A & ~TypeMask) | T;
}
+
static uint16_t set_kind(uint16_t A, uint16_t K) {
return (A & ~KindMask) | K;
}
+
static uint16_t set_flags(uint16_t A, uint16_t F) {
return (A & ~FlagMask) | F;
}
@@ -292,10 +335,13 @@ namespace rdf {
};
template <typename T> struct NodeAddr {
- NodeAddr() : Addr(nullptr), Id(0) {}
+ NodeAddr() : Addr(nullptr) {}
NodeAddr(T A, NodeId I) : Addr(A), Id(I) {}
- NodeAddr(const NodeAddr&) = default;
- NodeAddr &operator= (const NodeAddr&) = default;
+
+ // Type cast (casting constructor). The reason for having this class
+ // instead of std::pair.
+ template <typename S> NodeAddr(const NodeAddr<S> &NA)
+ : Addr(static_cast<T>(NA.Addr)), Id(NA.Id) {}
bool operator== (const NodeAddr<T> &NA) const {
assert((Addr == NA.Addr) == (Id == NA.Id));
@@ -304,13 +350,9 @@ namespace rdf {
bool operator!= (const NodeAddr<T> &NA) const {
return !operator==(NA);
}
- // Type cast (casting constructor). The reason for having this class
- // instead of std::pair.
- template <typename S> NodeAddr(const NodeAddr<S> &NA)
- : Addr(static_cast<T>(NA.Addr)), Id(NA.Id) {}
T Addr;
- NodeId Id;
+ NodeId Id = 0;
};
struct NodeBase;
@@ -334,17 +376,20 @@ namespace rdf {
struct NodeAllocator {
// Amount of storage for a single node.
enum { NodeMemSize = 32 };
+
NodeAllocator(uint32_t NPB = 4096)
: NodesPerBlock(NPB), BitsPerIndex(Log2_32(NPB)),
- IndexMask((1 << BitsPerIndex)-1), ActiveEnd(nullptr) {
+ IndexMask((1 << BitsPerIndex)-1) {
assert(isPowerOf2_32(NPB));
}
+
NodeBase *ptr(NodeId N) const {
uint32_t N1 = N-1;
uint32_t BlockN = N1 >> BitsPerIndex;
uint32_t Offset = (N1 & IndexMask) * NodeMemSize;
return reinterpret_cast<NodeBase*>(Blocks[BlockN]+Offset);
}
+
NodeId id(const NodeBase *P) const;
NodeAddr<NodeBase*> New();
void clear();
@@ -352,6 +397,7 @@ namespace rdf {
private:
void startNewBlock();
bool needNewBlock();
+
uint32_t makeId(uint32_t Block, uint32_t Index) const {
// Add 1 to the id, to avoid the id of 0, which is treated as "null".
return ((Block << BitsPerIndex) | Index) + 1;
@@ -360,46 +406,37 @@ namespace rdf {
const uint32_t NodesPerBlock;
const uint32_t BitsPerIndex;
const uint32_t IndexMask;
- char *ActiveEnd;
+ char *ActiveEnd = nullptr;
std::vector<char*> Blocks;
typedef BumpPtrAllocatorImpl<MallocAllocator, 65536> AllocatorTy;
AllocatorTy MemPool;
};
struct RegisterRef {
- unsigned Reg, Sub;
+ RegisterId Reg;
+ LaneBitmask Mask;
- // No non-trivial constructors, since this will be a member of a union.
- RegisterRef() = default;
- RegisterRef(const RegisterRef &RR) = default;
- RegisterRef &operator= (const RegisterRef &RR) = default;
+ RegisterRef() : RegisterRef(0) {}
+ explicit RegisterRef(RegisterId R, LaneBitmask M = LaneBitmask::getAll())
+ : Reg(R), Mask(R != 0 ? M : LaneBitmask::getNone()) {}
+
+ operator bool() const { return Reg != 0 && Mask.any(); }
bool operator== (const RegisterRef &RR) const {
- return Reg == RR.Reg && Sub == RR.Sub;
+ return Reg == RR.Reg && Mask == RR.Mask;
}
bool operator!= (const RegisterRef &RR) const {
return !operator==(RR);
}
bool operator< (const RegisterRef &RR) const {
- return Reg < RR.Reg || (Reg == RR.Reg && Sub < RR.Sub);
+ return Reg < RR.Reg || (Reg == RR.Reg && Mask < RR.Mask);
}
};
typedef std::set<RegisterRef> RegisterSet;
- struct RegisterAliasInfo {
- RegisterAliasInfo(const TargetRegisterInfo &tri) : TRI(tri) {}
- virtual ~RegisterAliasInfo() {}
-
- virtual std::vector<RegisterRef> getAliasSet(RegisterRef RR) const;
- virtual bool alias(RegisterRef RA, RegisterRef RB) const;
- virtual bool covers(RegisterRef RA, RegisterRef RB) const;
- virtual bool covers(const RegisterSet &RRs, RegisterRef RR) const;
-
- const TargetRegisterInfo &TRI;
- };
-
struct TargetOperandInfo {
TargetOperandInfo(const TargetInstrInfo &tii) : TII(tii) {}
- virtual ~TargetOperandInfo() {}
+ virtual ~TargetOperandInfo() = default;
+
virtual bool isPreserving(const MachineInstr &In, unsigned OpNum) const;
virtual bool isClobbering(const MachineInstr &In, unsigned OpNum) const;
virtual bool isFixedReg(const MachineInstr &In, unsigned OpNum) const;
@@ -407,13 +444,115 @@ namespace rdf {
const TargetInstrInfo &TII;
};
+ // Packed register reference. Only used for storage.
+ struct PackedRegisterRef {
+ RegisterId Reg;
+ uint32_t MaskId;
+ };
- struct DataFlowGraph;
+ // Template class for a map translating uint32_t into arbitrary types.
+ // The map will act like an indexed set: upon insertion of a new object,
+ // it will automatically assign a new index to it. Index of 0 is treated
+ // as invalid and is never allocated.
+ template <typename T, unsigned N = 32>
+ struct IndexedSet {
+ IndexedSet() : Map() { Map.reserve(N); }
+
+ T get(uint32_t Idx) const {
+ // Index Idx corresponds to Map[Idx-1].
+ assert(Idx != 0 && !Map.empty() && Idx-1 < Map.size());
+ return Map[Idx-1];
+ }
+
+ uint32_t insert(T Val) {
+ // Linear search.
+ auto F = llvm::find(Map, Val);
+ if (F != Map.end())
+ return F - Map.begin() + 1;
+ Map.push_back(Val);
+ return Map.size(); // Return actual_index + 1.
+ }
+
+ uint32_t find(T Val) const {
+ auto F = llvm::find(Map, Val);
+ assert(F != Map.end());
+ return F - Map.begin();
+ }
+
+ private:
+ std::vector<T> Map;
+ };
+
+ struct LaneMaskIndex : private IndexedSet<LaneBitmask> {
+ LaneMaskIndex() = default;
+
+ LaneBitmask getLaneMaskForIndex(uint32_t K) const {
+ return K == 0 ? LaneBitmask::getAll() : get(K);
+ }
+ uint32_t getIndexForLaneMask(LaneBitmask LM) {
+ assert(LM.any());
+ return LM.all() ? 0 : insert(LM);
+ }
+ uint32_t getIndexForLaneMask(LaneBitmask LM) const {
+ assert(LM.any());
+ return LM.all() ? 0 : find(LM);
+ }
+
+ PackedRegisterRef pack(RegisterRef RR) {
+ return { RR.Reg, getIndexForLaneMask(RR.Mask) };
+ }
+ PackedRegisterRef pack(RegisterRef RR) const {
+ return { RR.Reg, getIndexForLaneMask(RR.Mask) };
+ }
+
+ RegisterRef unpack(PackedRegisterRef PR) const {
+ return RegisterRef(PR.Reg, getLaneMaskForIndex(PR.MaskId));
+ }
+ };
+
+ struct RegisterAggr {
+ RegisterAggr(const TargetRegisterInfo &tri)
+ : ExpAliasUnits(tri.getNumRegUnits()), CheckUnits(false), TRI(tri) {}
+ RegisterAggr(const RegisterAggr &RG) = default;
+
+ bool empty() const { return Masks.empty(); }
+ bool hasAliasOf(RegisterRef RR) const;
+ bool hasCoverOf(RegisterRef RR) const;
+ static bool isCoverOf(RegisterRef RA, RegisterRef RB,
+ const TargetRegisterInfo &TRI) {
+ return RegisterAggr(TRI).insert(RA).hasCoverOf(RB);
+ }
+
+ RegisterAggr &insert(RegisterRef RR);
+ RegisterAggr &insert(const RegisterAggr &RG);
+ RegisterAggr &clear(RegisterRef RR);
+ RegisterAggr &clear(const RegisterAggr &RG);
+
+ RegisterRef clearIn(RegisterRef RR) const;
+
+ void print(raw_ostream &OS) const;
+
+ private:
+ typedef std::unordered_map<RegisterId, LaneBitmask> MapType;
+
+ public:
+ typedef MapType::const_iterator iterator;
+ iterator begin() const { return Masks.begin(); }
+ iterator end() const { return Masks.end(); }
+ RegisterRef normalize(RegisterRef RR) const;
+
+ private:
+ MapType Masks;
+ BitVector ExpAliasUnits; // Register units for explicit aliases.
+ bool CheckUnits;
+ const TargetRegisterInfo &TRI;
+ };
struct NodeBase {
public:
// Make sure this is a POD.
NodeBase() = default;
+
uint16_t getType() const { return NodeAttrs::type(Attrs); }
uint16_t getKind() const { return NodeAttrs::kind(Attrs); }
uint16_t getFlags() const { return NodeAttrs::flags(Attrs); }
@@ -454,7 +593,7 @@ namespace rdf {
};
union {
MachineOperand *Op; // Non-phi refs point to a machine operand.
- RegisterRef RR; // Phi refs store register info directly.
+ PackedRegisterRef PR; // Phi refs store register info directly.
};
};
@@ -475,29 +614,36 @@ namespace rdf {
struct RefNode : public NodeBase {
RefNode() = default;
- RegisterRef getRegRef() const;
+
+ RegisterRef getRegRef(const DataFlowGraph &G) const;
+
MachineOperand &getOp() {
assert(!(getFlags() & NodeAttrs::PhiRef));
return *Ref.Op;
}
- void setRegRef(RegisterRef RR);
- void setRegRef(MachineOperand *Op);
+
+ void setRegRef(RegisterRef RR, DataFlowGraph &G);
+ void setRegRef(MachineOperand *Op, DataFlowGraph &G);
+
NodeId getReachingDef() const {
return Ref.RD;
}
void setReachingDef(NodeId RD) {
Ref.RD = RD;
}
+
NodeId getSibling() const {
return Ref.Sib;
}
void setSibling(NodeId Sib) {
Ref.Sib = Sib;
}
+
bool isUse() const {
assert(getType() == NodeAttrs::Ref);
return getKind() == NodeAttrs::Use;
}
+
bool isDef() const {
assert(getType() == NodeAttrs::Ref);
return getKind() == NodeAttrs::Def;
@@ -581,6 +727,7 @@ namespace rdf {
MachineBasicBlock *getCode() const {
return CodeNode::getCode<MachineBasicBlock*>();
}
+
void addPhi(NodeAddr<PhiNode*> PA, const DataFlowGraph &G);
};
@@ -588,6 +735,7 @@ namespace rdf {
MachineFunction *getCode() const {
return CodeNode::getCode<MachineFunction*>();
}
+
NodeAddr<BlockNode*> findBlock(const MachineBasicBlock *BB,
const DataFlowGraph &G) const;
NodeAddr<BlockNode*> getEntryBlock(const DataFlowGraph &G);
@@ -596,50 +744,39 @@ namespace rdf {
struct DataFlowGraph {
DataFlowGraph(MachineFunction &mf, const TargetInstrInfo &tii,
const TargetRegisterInfo &tri, const MachineDominatorTree &mdt,
- const MachineDominanceFrontier &mdf, const RegisterAliasInfo &rai,
- const TargetOperandInfo &toi);
+ const MachineDominanceFrontier &mdf, const TargetOperandInfo &toi);
NodeBase *ptr(NodeId N) const;
template <typename T> T ptr(NodeId N) const {
return static_cast<T>(ptr(N));
}
+
NodeId id(const NodeBase *P) const;
template <typename T> NodeAddr<T> addr(NodeId N) const {
return { ptr<T>(N), N };
}
- NodeAddr<FuncNode*> getFunc() const {
- return Func;
- }
- MachineFunction &getMF() const {
- return MF;
- }
- const TargetInstrInfo &getTII() const {
- return TII;
- }
- const TargetRegisterInfo &getTRI() const {
- return TRI;
- }
- const MachineDominatorTree &getDT() const {
- return MDT;
- }
- const MachineDominanceFrontier &getDF() const {
- return MDF;
- }
- const RegisterAliasInfo &getRAI() const {
- return RAI;
- }
+ NodeAddr<FuncNode*> getFunc() const { return Func; }
+ MachineFunction &getMF() const { return MF; }
+ const TargetInstrInfo &getTII() const { return TII; }
+ const TargetRegisterInfo &getTRI() const { return TRI; }
+ const MachineDominatorTree &getDT() const { return MDT; }
+ const MachineDominanceFrontier &getDF() const { return MDF; }
struct DefStack {
DefStack() = default;
+
bool empty() const { return Stack.empty() || top() == bottom(); }
+
private:
typedef NodeAddr<DefNode*> value_type;
struct Iterator {
typedef DefStack::value_type value_type;
+
Iterator &up() { Pos = DS.nextUp(Pos); return *this; }
Iterator &down() { Pos = DS.nextDown(Pos); return *this; }
+
value_type operator*() const {
assert(Pos >= 1);
return DS.Stack[Pos-1];
@@ -650,14 +787,17 @@ namespace rdf {
}
bool operator==(const Iterator &It) const { return Pos == It.Pos; }
bool operator!=(const Iterator &It) const { return Pos != It.Pos; }
+
private:
Iterator(const DefStack &S, bool Top);
+
// Pos-1 is the index in the StorageType object that corresponds to
// the top of the DefStack.
const DefStack &DS;
unsigned Pos;
friend struct DefStack;
};
+
public:
typedef Iterator iterator;
iterator top() const { return Iterator(*this, true); }
@@ -668,24 +808,37 @@ namespace rdf {
void pop();
void start_block(NodeId N);
void clear_block(NodeId N);
+
private:
friend struct Iterator;
typedef std::vector<value_type> StorageType;
+
bool isDelimiter(const StorageType::value_type &P, NodeId N = 0) const {
return (P.Addr == nullptr) && (N == 0 || P.Id == N);
}
+
unsigned nextUp(unsigned P) const;
unsigned nextDown(unsigned P) const;
+
StorageType Stack;
};
- typedef std::map<RegisterRef,DefStack> DefStackMap;
+ // Make this std::unordered_map for speed of accessing elements.
+ // Map: Register (physical or virtual) -> DefStack
+ typedef std::unordered_map<RegisterId,DefStack> DefStackMap;
void build(unsigned Options = BuildOptions::None);
void pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DM);
void markBlock(NodeId B, DefStackMap &DefM);
void releaseBlock(NodeId B, DefStackMap &DefM);
+ PackedRegisterRef pack(RegisterRef RR) { return LMI.pack(RR); }
+ PackedRegisterRef pack(RegisterRef RR) const { return LMI.pack(RR); }
+ RegisterRef unpack(PackedRegisterRef PR) const { return LMI.unpack(PR); }
+ RegisterRef makeRegRef(unsigned Reg, unsigned Sub) const;
+ RegisterRef normalizeRef(RegisterRef RR) const;
+ RegisterRef restrictRef(RegisterRef AR, RegisterRef BR) const;
+
NodeAddr<RefNode*> getNextRelated(NodeAddr<InstrNode*> IA,
NodeAddr<RefNode*> RA) const;
NodeAddr<RefNode*> getNextImp(NodeAddr<InstrNode*> IA,
@@ -705,6 +858,7 @@ namespace rdf {
if (RemoveFromOwner)
removeFromOwner(UA);
}
+
void unlinkDef(NodeAddr<DefNode*> DA, bool RemoveFromOwner) {
unlinkDefDF(DA);
if (RemoveFromOwner)
@@ -717,27 +871,42 @@ namespace rdf {
return BA.Addr->getType() == NodeAttrs::Ref &&
BA.Addr->getKind() == Kind;
}
+
template <uint16_t Kind>
static bool IsCode(const NodeAddr<NodeBase*> BA) {
return BA.Addr->getType() == NodeAttrs::Code &&
BA.Addr->getKind() == Kind;
}
+
static bool IsDef(const NodeAddr<NodeBase*> BA) {
return BA.Addr->getType() == NodeAttrs::Ref &&
BA.Addr->getKind() == NodeAttrs::Def;
}
+
static bool IsUse(const NodeAddr<NodeBase*> BA) {
return BA.Addr->getType() == NodeAttrs::Ref &&
BA.Addr->getKind() == NodeAttrs::Use;
}
+
static bool IsPhi(const NodeAddr<NodeBase*> BA) {
return BA.Addr->getType() == NodeAttrs::Code &&
BA.Addr->getKind() == NodeAttrs::Phi;
}
+ static bool IsPreservingDef(const NodeAddr<DefNode*> DA) {
+ uint16_t Flags = DA.Addr->getFlags();
+ return (Flags & NodeAttrs::Preserving) && !(Flags & NodeAttrs::Undef);
+ }
+
+ // Register aliasing.
+ bool alias(RegisterRef RA, RegisterRef RB) const;
+
private:
void reset();
+ RegisterSet getAliasSet(RegisterId Reg) const;
+ RegisterSet getLandingPadLiveIns() const;
+
NodeAddr<NodeBase*> newNode(uint16_t Attrs);
NodeAddr<NodeBase*> cloneNode(const NodeAddr<NodeBase*> B);
NodeAddr<UseNode*> newUse(NodeAddr<InstrNode*> Owner,
@@ -778,21 +947,28 @@ namespace rdf {
void unlinkUseDF(NodeAddr<UseNode*> UA);
void unlinkDefDF(NodeAddr<DefNode*> DA);
+
void removeFromOwner(NodeAddr<RefNode*> RA) {
NodeAddr<InstrNode*> IA = RA.Addr->getOwner(*this);
IA.Addr->removeMember(RA, *this);
}
- TimerGroup TimeG;
+ NodeAddr<BlockNode*> findBlock(MachineBasicBlock *BB) {
+ return BlockNodes[BB];
+ }
+
NodeAddr<FuncNode*> Func;
NodeAllocator Memory;
+ // Local map: MachineBasicBlock -> NodeAddr<BlockNode*>
+ std::map<MachineBasicBlock*,NodeAddr<BlockNode*>> BlockNodes;
+ // Lane mask map.
+ LaneMaskIndex LMI;
MachineFunction &MF;
const TargetInstrInfo &TII;
const TargetRegisterInfo &TRI;
const MachineDominatorTree &MDT;
const MachineDominanceFrontier &MDF;
- const RegisterAliasInfo &RAI;
const TargetOperandInfo &TOI;
}; // struct DataFlowGraph
@@ -806,7 +982,7 @@ namespace rdf {
while (NA.Addr != this) {
if (NA.Addr->getType() == NodeAttrs::Ref) {
NodeAddr<RefNode*> RA = NA;
- if (RA.Addr->getRegRef() == RR && P(NA))
+ if (RA.Addr->getRegRef(G) == RR && P(NA))
return NA;
if (NextOnly)
break;
@@ -837,6 +1013,12 @@ namespace rdf {
return MM;
}
+ // Optionally print the lane mask, if it is not ~0.
+ struct PrintLaneMaskOpt {
+ PrintLaneMaskOpt(LaneBitmask M) : Mask(M) {}
+ LaneBitmask Mask;
+ };
+ raw_ostream &operator<< (raw_ostream &OS, const PrintLaneMaskOpt &P);
template <typename T> struct Print;
template <typename T>
@@ -854,7 +1036,9 @@ namespace rdf {
PrintNode(const NodeAddr<T> &x, const DataFlowGraph &g)
: Print<NodeAddr<T>>(x, g) {}
};
-} // namespace rdf
-} // namespace llvm
-#endif // RDF_GRAPH_H
+} // end namespace rdf
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_HEXAGON_RDFGRAPH_H
diff --git a/contrib/llvm/lib/Target/Hexagon/RDFLiveness.cpp b/contrib/llvm/lib/Target/Hexagon/RDFLiveness.cpp
index 641f014..e74c4bf 100644
--- a/contrib/llvm/lib/Target/Hexagon/RDFLiveness.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/RDFLiveness.cpp
@@ -41,10 +41,10 @@ namespace rdf {
template<>
raw_ostream &operator<< (raw_ostream &OS, const Print<Liveness::RefMap> &P) {
OS << '{';
- for (auto I : P.Obj) {
- OS << ' ' << Print<RegisterRef>(I.first, P.G) << '{';
+ for (auto &I : P.Obj) {
+ OS << ' ' << PrintReg(I.first, &P.G.getTRI()) << '{';
for (auto J = I.second.begin(), E = I.second.end(); J != E; ) {
- OS << Print<NodeId>(*J, P.G);
+ OS << Print<NodeId>(J->first, P.G) << PrintLaneMaskOpt(J->second);
if (++J != E)
OS << ',';
}
@@ -85,10 +85,19 @@ namespace rdf {
// the data-flow.
NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
- NodeAddr<RefNode*> RefA, bool FullChain, const RegisterSet &DefRRs) {
+ NodeAddr<RefNode*> RefA, bool FullChain, const RegisterAggr &DefRRs) {
+ NodeList RDefs; // Return value.
SetVector<NodeId> DefQ;
SetVector<NodeId> Owners;
+ // Dead defs will be treated as if they were live, since they are actually
+ // on the data-flow path. They cannot be ignored because even though they
+ // do not generate meaningful values, they still modify registers.
+
+ // If the reference is undefined, there is nothing to do.
+ if (RefA.Addr->getFlags() & NodeAttrs::Undef)
+ return RDefs;
+
// The initial queue should not have reaching defs for shadows. The
// whole point of a shadow is that it will have a reaching def that
// is not aliased to the reaching defs of the related shadows.
@@ -108,26 +117,24 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
if (TA.Addr->getFlags() & NodeAttrs::PhiRef)
continue;
// Stop at the covering/overwriting def of the initial register reference.
- RegisterRef RR = TA.Addr->getRegRef();
- if (RAI.covers(RR, RefRR)) {
- uint16_t Flags = TA.Addr->getFlags();
- if (!(Flags & NodeAttrs::Preserving))
+ RegisterRef RR = TA.Addr->getRegRef(DFG);
+ if (!DFG.IsPreservingDef(TA))
+ if (RegisterAggr::isCoverOf(RR, RefRR, TRI))
continue;
- }
// Get the next level of reaching defs. This will include multiple
// reaching defs for shadows.
for (auto S : DFG.getRelatedRefs(TA.Addr->getOwner(DFG), TA))
- if (auto RD = NodeAddr<RefNode*>(S).Addr->getReachingDef())
+ if (NodeId RD = NodeAddr<RefNode*>(S).Addr->getReachingDef())
DefQ.insert(RD);
}
// Remove all non-phi defs that are not aliased to RefRR, and collect
// the owners of the remaining defs.
SetVector<NodeId> Defs;
- for (auto N : DefQ) {
+ for (NodeId N : DefQ) {
auto TA = DFG.addr<DefNode*>(N);
bool IsPhi = TA.Addr->getFlags() & NodeAttrs::PhiRef;
- if (!IsPhi && !RAI.alias(RefRR, TA.Addr->getRegRef()))
+ if (!IsPhi && !DFG.alias(RefRR, TA.Addr->getRegRef(DFG)))
continue;
Defs.insert(TA.Id);
Owners.insert(TA.Addr->getOwner(DFG).Id);
@@ -156,8 +163,8 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
if (StmtA) {
if (!StmtB) // OB is a phi and phis dominate statements.
return true;
- auto CA = NodeAddr<StmtNode*>(OA).Addr->getCode();
- auto CB = NodeAddr<StmtNode*>(OB).Addr->getCode();
+ MachineInstr *CA = NodeAddr<StmtNode*>(OA).Addr->getCode();
+ MachineInstr *CB = NodeAddr<StmtNode*>(OB).Addr->getCode();
// The order must be linear, so tie-break such equalities.
if (CA == CB)
return A < B;
@@ -189,21 +196,20 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
// covered if we added A first, and A would be covered
// if we added B first.
- NodeList RDefs;
- RegisterSet RRs = DefRRs;
+ RegisterAggr RRs(DefRRs);
auto DefInSet = [&Defs] (NodeAddr<RefNode*> TA) -> bool {
return TA.Addr->getKind() == NodeAttrs::Def &&
Defs.count(TA.Id);
};
- for (auto T : Tmp) {
- if (!FullChain && RAI.covers(RRs, RefRR))
+ for (NodeId T : Tmp) {
+ if (!FullChain && RRs.hasCoverOf(RefRR))
break;
auto TA = DFG.addr<InstrNode*>(T);
bool IsPhi = DFG.IsCode<NodeAttrs::Phi>(TA);
NodeList Ds;
for (NodeAddr<DefNode*> DA : TA.Addr->members_if(DefInSet, DFG)) {
- auto QR = DA.Addr->getRegRef();
+ RegisterRef QR = DA.Addr->getRegRef(DFG);
// Add phi defs even if they are covered by subsequent defs. This is
// for cases where the reached use is not covered by any of the defs
// encountered so far: the phi def is needed to expose the liveness
@@ -212,7 +218,7 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
// phi d1<R3>(,d2,), ... Phi def d1 is covered by d2.
// d2<R3>(d1,,u3), ...
// ..., u3<D1>(d2) This use needs to be live on entry.
- if (FullChain || IsPhi || !RAI.covers(RRs, QR))
+ if (FullChain || IsPhi || !RRs.hasCoverOf(QR))
Ds.push_back(DA);
}
RDefs.insert(RDefs.end(), Ds.begin(), Ds.end());
@@ -221,19 +227,17 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
// defs to actually define a register.
uint16_t Flags = DA.Addr->getFlags();
if (!FullChain || !(Flags & NodeAttrs::PhiRef))
- if (!(Flags & NodeAttrs::Preserving))
- RRs.insert(DA.Addr->getRegRef());
+ if (!(Flags & NodeAttrs::Preserving)) // Don't care about Undef here.
+ RRs.insert(DA.Addr->getRegRef(DFG));
}
}
- return RDefs;
-}
-
-
-static const RegisterSet NoRegs;
+ auto DeadP = [](const NodeAddr<DefNode*> DA) -> bool {
+ return DA.Addr->getFlags() & NodeAttrs::Dead;
+ };
+ RDefs.resize(std::distance(RDefs.begin(), remove_if(RDefs, DeadP)));
-NodeList Liveness::getAllReachingDefs(NodeAddr<RefNode*> RefA) {
- return getAllReachingDefs(RefA.Addr->getRegRef(), RefA, false, NoRegs);
+ return RDefs;
}
@@ -241,20 +245,20 @@ NodeSet Liveness::getAllReachingDefsRec(RegisterRef RefRR,
NodeAddr<RefNode*> RefA, NodeSet &Visited, const NodeSet &Defs) {
// Collect all defined registers. Do not consider phis to be defining
// anything, only collect "real" definitions.
- RegisterSet DefRRs;
- for (const auto D : Defs) {
+ RegisterAggr DefRRs(TRI);
+ for (NodeId D : Defs) {
const auto DA = DFG.addr<const DefNode*>(D);
if (!(DA.Addr->getFlags() & NodeAttrs::PhiRef))
- DefRRs.insert(DA.Addr->getRegRef());
+ DefRRs.insert(DA.Addr->getRegRef(DFG));
}
- auto RDs = getAllReachingDefs(RefRR, RefA, true, DefRRs);
+ NodeList RDs = getAllReachingDefs(RefRR, RefA, true, DefRRs);
if (RDs.empty())
return Defs;
// Make a copy of the preexisting definitions and add the newly found ones.
NodeSet TmpDefs = Defs;
- for (auto R : RDs)
+ for (NodeAddr<NodeBase*> R : RDs)
TmpDefs.insert(R.Id);
NodeSet Result = Defs;
@@ -279,39 +283,43 @@ NodeSet Liveness::getAllReachingDefsRec(RegisterRef RefRR,
NodeSet Liveness::getAllReachedUses(RegisterRef RefRR,
- NodeAddr<DefNode*> DefA, const RegisterSet &DefRRs) {
+ NodeAddr<DefNode*> DefA, const RegisterAggr &DefRRs) {
NodeSet Uses;
// If the original register is already covered by all the intervening
// defs, no more uses can be reached.
- if (RAI.covers(DefRRs, RefRR))
+ if (DefRRs.hasCoverOf(RefRR))
return Uses;
// Add all directly reached uses.
- NodeId U = DefA.Addr->getReachedUse();
+ // If the def is dead, it does not provide a value for any use.
+ bool IsDead = DefA.Addr->getFlags() & NodeAttrs::Dead;
+ NodeId U = !IsDead ? DefA.Addr->getReachedUse() : 0;
while (U != 0) {
auto UA = DFG.addr<UseNode*>(U);
- auto UR = UA.Addr->getRegRef();
- if (RAI.alias(RefRR, UR) && !RAI.covers(DefRRs, UR))
- Uses.insert(U);
+ if (!(UA.Addr->getFlags() & NodeAttrs::Undef)) {
+ RegisterRef UR = UA.Addr->getRegRef(DFG);
+ if (DFG.alias(RefRR, UR) && !DefRRs.hasCoverOf(UR))
+ Uses.insert(U);
+ }
U = UA.Addr->getSibling();
}
- // Traverse all reached defs.
+ // Traverse all reached defs. This time dead defs cannot be ignored.
for (NodeId D = DefA.Addr->getReachedDef(), NextD; D != 0; D = NextD) {
auto DA = DFG.addr<DefNode*>(D);
NextD = DA.Addr->getSibling();
- auto DR = DA.Addr->getRegRef();
+ RegisterRef DR = DA.Addr->getRegRef(DFG);
// If this def is already covered, it cannot reach anything new.
// Similarly, skip it if it is not aliased to the interesting register.
- if (RAI.covers(DefRRs, DR) || !RAI.alias(RefRR, DR))
+ if (DefRRs.hasCoverOf(DR) || !DFG.alias(RefRR, DR))
continue;
NodeSet T;
- if (DA.Addr->getFlags() & NodeAttrs::Preserving) {
+ if (DFG.IsPreservingDef(DA)) {
// If it is a preserving def, do not update the set of intervening defs.
T = getAllReachedUses(RefRR, DA, DefRRs);
} else {
- RegisterSet NewDefRRs = DefRRs;
+ RegisterAggr NewDefRRs = DefRRs;
NewDefRRs.insert(DR);
T = getAllReachedUses(RefRR, DA, NewDefRRs);
}
@@ -326,42 +334,57 @@ void Liveness::computePhiInfo() {
NodeList Phis;
NodeAddr<FuncNode*> FA = DFG.getFunc();
- auto Blocks = FA.Addr->members(DFG);
+ NodeList Blocks = FA.Addr->members(DFG);
for (NodeAddr<BlockNode*> BA : Blocks) {
auto Ps = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG);
Phis.insert(Phis.end(), Ps.begin(), Ps.end());
}
// phi use -> (map: reaching phi -> set of registers defined in between)
- std::map<NodeId,std::map<NodeId,RegisterSet>> PhiUp;
+ std::map<NodeId,std::map<NodeId,RegisterAggr>> PhiUp;
std::vector<NodeId> PhiUQ; // Work list of phis for upward propagation.
// Go over all phis.
for (NodeAddr<PhiNode*> PhiA : Phis) {
// Go over all defs and collect the reached uses that are non-phi uses
// (i.e. the "real uses").
- auto &RealUses = RealUseMap[PhiA.Id];
- auto PhiRefs = PhiA.Addr->members(DFG);
+ RefMap &RealUses = RealUseMap[PhiA.Id];
+ NodeList PhiRefs = PhiA.Addr->members(DFG);
// Have a work queue of defs whose reached uses need to be found.
// For each def, add to the queue all reached (non-phi) defs.
SetVector<NodeId> DefQ;
NodeSet PhiDefs;
- for (auto R : PhiRefs) {
+ for (NodeAddr<RefNode*> R : PhiRefs) {
if (!DFG.IsRef<NodeAttrs::Def>(R))
continue;
DefQ.insert(R.Id);
PhiDefs.insert(R.Id);
}
+
+ // Collect the super-set of all possible reached uses. This set will
+ // contain all uses reached from this phi, either directly from the
+ // phi defs, or (recursively) via non-phi defs reached by the phi defs.
+ // This set of uses will later be trimmed to only contain these uses that
+ // are actually reached by the phi defs.
for (unsigned i = 0; i < DefQ.size(); ++i) {
NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]);
- NodeId UN = DA.Addr->getReachedUse();
+ // Visit all reached uses. Phi defs should not really have the "dead"
+ // flag set, but check it anyway for consistency.
+ bool IsDead = DA.Addr->getFlags() & NodeAttrs::Dead;
+ NodeId UN = !IsDead ? DA.Addr->getReachedUse() : 0;
while (UN != 0) {
NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
- if (!(A.Addr->getFlags() & NodeAttrs::PhiRef))
- RealUses[getRestrictedRegRef(A)].insert(A.Id);
+ uint16_t F = A.Addr->getFlags();
+ if ((F & (NodeAttrs::Undef | NodeAttrs::PhiRef)) == 0) {
+ RegisterRef R = DFG.normalizeRef(getRestrictedRegRef(A));
+ RealUses[R.Reg].insert({A.Id,R.Mask});
+ }
UN = A.Addr->getSibling();
}
+ // Visit all reached defs, and add them to the queue. These defs may
+ // override some of the uses collected here, but that will be handled
+ // later.
NodeId DN = DA.Addr->getReachedDef();
while (DN != 0) {
NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN);
@@ -388,7 +411,7 @@ void Liveness::computePhiInfo() {
// = R1:0 u6 Not reached by d1 (covered collectively
// by d3 and d5), but following reached
// defs and uses from d1 will lead here.
- auto HasDef = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool {
+ auto InPhiDefs = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool {
return PhiDefs.count(DA.Id);
};
for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) {
@@ -396,11 +419,14 @@ void Liveness::computePhiInfo() {
// uses of it. For each such use, check if it is reached by this phi,
// i.e. check if the set of its reaching uses intersects the set of
// this phi's defs.
- auto &Uses = UI->second;
+ NodeRefSet &Uses = UI->second;
for (auto I = Uses.begin(), E = Uses.end(); I != E; ) {
- auto UA = DFG.addr<UseNode*>(*I);
- NodeList RDs = getAllReachingDefs(UI->first, UA);
- if (std::any_of(RDs.begin(), RDs.end(), HasDef))
+ auto UA = DFG.addr<UseNode*>(I->first);
+ // Undef flag is checked above.
+ assert((UA.Addr->getFlags() & NodeAttrs::Undef) == 0);
+ RegisterRef R(UI->first, I->second);
+ NodeList RDs = getAllReachingDefs(R, UA);
+ if (any_of(RDs, InPhiDefs))
++I;
else
I = Uses.erase(I);
@@ -418,31 +444,50 @@ void Liveness::computePhiInfo() {
// Go over all phi uses and check if the reaching def is another phi.
// Collect the phis that are among the reaching defs of these uses.
- // While traversing the list of reaching defs for each phi use, collect
- // the set of registers defined between this phi (Phi) and the owner phi
+ // While traversing the list of reaching defs for each phi use, accumulate
+ // the set of registers defined between this phi (PhiA) and the owner phi
// of the reaching def.
+ NodeSet SeenUses;
+
for (auto I : PhiRefs) {
- if (!DFG.IsRef<NodeAttrs::Use>(I))
+ if (!DFG.IsRef<NodeAttrs::Use>(I) || SeenUses.count(I.Id))
continue;
NodeAddr<UseNode*> UA = I;
- auto &UpMap = PhiUp[UA.Id];
- RegisterSet DefRRs;
- for (NodeAddr<DefNode*> DA : getAllReachingDefs(UA)) {
- if (DA.Addr->getFlags() & NodeAttrs::PhiRef)
- UpMap[DA.Addr->getOwner(DFG).Id] = DefRRs;
- else
- DefRRs.insert(DA.Addr->getRegRef());
+
+ // Given a phi use UA, traverse all related phi uses (including UA).
+ // The related phi uses may reach different phi nodes or may reach the
+ // same phi node. If multiple uses reach the same phi P, the intervening
+ // defs must be accumulated for all such uses. To group all such uses
+ // into one set, map their node ids to the first use id that reaches P.
+ std::map<NodeId,NodeId> FirstUse; // Phi reached up -> first phi use.
+
+ for (NodeAddr<UseNode*> VA : DFG.getRelatedRefs(PhiA, UA)) {
+ SeenUses.insert(VA.Id);
+ RegisterAggr DefRRs(TRI);
+ for (NodeAddr<DefNode*> DA : getAllReachingDefs(VA)) {
+ if (DA.Addr->getFlags() & NodeAttrs::PhiRef) {
+ NodeId RP = DA.Addr->getOwner(DFG).Id;
+ NodeId FU = FirstUse.insert({RP,VA.Id}).first->second;
+ std::map<NodeId,RegisterAggr> &M = PhiUp[FU];
+ auto F = M.find(RP);
+ if (F == M.end())
+ M.insert(std::make_pair(RP, DefRRs));
+ else
+ F->second.insert(DefRRs);
+ }
+ DefRRs.insert(DA.Addr->getRegRef(DFG));
+ }
}
}
}
if (Trace) {
- dbgs() << "Phi-up-to-phi map:\n";
+ dbgs() << "Phi-up-to-phi map with intervening defs:\n";
for (auto I : PhiUp) {
dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {";
for (auto R : I.second)
dbgs() << ' ' << Print<NodeId>(R.first, DFG)
- << Print<RegisterSet>(R.second, DFG);
+ << Print<RegisterAggr>(R.second, DFG);
dbgs() << " }\n";
}
}
@@ -467,40 +512,50 @@ void Liveness::computePhiInfo() {
//
// When propagating uses up the phi chains, get the all reaching defs
// for a given phi use, and traverse the list until the propagated ref
- // is covered, or until or until reaching the final phi. Only assume
- // that the reference reaches the phi in the latter case.
+ // is covered, or until reaching the final phi. Only assume that the
+ // reference reaches the phi in the latter case.
for (unsigned i = 0; i < PhiUQ.size(); ++i) {
auto PA = DFG.addr<PhiNode*>(PhiUQ[i]);
- auto &RealUses = RealUseMap[PA.Id];
- for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
- NodeAddr<UseNode*> UA = U;
- auto &UpPhis = PhiUp[UA.Id];
- for (auto UP : UpPhis) {
+ NodeList PUs = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG);
+ RefMap &RUM = RealUseMap[PA.Id];
+
+ for (NodeAddr<UseNode*> UA : PUs) {
+ std::map<NodeId,RegisterAggr> &PUM = PhiUp[UA.Id];
+ RegisterRef UR = DFG.normalizeRef(getRestrictedRegRef(UA));
+ for (const std::pair<NodeId,RegisterAggr> &P : PUM) {
bool Changed = false;
- auto &MidDefs = UP.second;
- // Collect the set UpReached of uses that are reached by the current
- // phi PA, and are not covered by any intervening def between PA and
- // the upward phi UP.
- RegisterSet UpReached;
- for (auto T : RealUses) {
- if (!isRestricted(PA, UA, T.first))
- continue;
- if (!RAI.covers(MidDefs, T.first))
- UpReached.insert(T.first);
- }
- if (UpReached.empty())
+ const RegisterAggr &MidDefs = P.second;
+
+ // Collect the set PropUp of uses that are reached by the current
+ // phi PA, and are not covered by any intervening def between the
+ // currently visited use UA and the the upward phi P.
+
+ if (MidDefs.hasCoverOf(UR))
continue;
- // Update the set PRUs of real uses reached by the upward phi UP with
- // the actual set of uses (UpReached) that the UP phi reaches.
- auto &PRUs = RealUseMap[UP.first];
- for (auto R : UpReached) {
- unsigned Z = PRUs[R].size();
- PRUs[R].insert(RealUses[R].begin(), RealUses[R].end());
- Changed |= (PRUs[R].size() != Z);
+
+ // General algorithm:
+ // for each (R,U) : U is use node of R, U is reached by PA
+ // if MidDefs does not cover (R,U)
+ // then add (R-MidDefs,U) to RealUseMap[P]
+ //
+ for (const std::pair<RegisterId,NodeRefSet> &T : RUM) {
+ RegisterRef R = DFG.restrictRef(RegisterRef(T.first), UR);
+ if (!R)
+ continue;
+ for (std::pair<NodeId,LaneBitmask> V : T.second) {
+ RegisterRef S = DFG.restrictRef(RegisterRef(R.Reg, V.second), R);
+ if (!S)
+ continue;
+ if (RegisterRef SS = MidDefs.clearIn(S)) {
+ NodeRefSet &RS = RealUseMap[P.first][SS.Reg];
+ Changed |= RS.insert({V.first,SS.Mask}).second;
+ }
+ }
}
+
if (Changed)
- PhiUQ.push_back(UP.first);
+ PhiUQ.push_back(P.first);
}
}
}
@@ -512,7 +567,7 @@ void Liveness::computePhiInfo() {
NodeAddr<PhiNode*> PA = DFG.addr<PhiNode*>(I.first);
NodeList Ds = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Def>, DFG);
if (!Ds.empty()) {
- RegisterRef RR = NodeAddr<DefNode*>(Ds[0]).Addr->getRegRef();
+ RegisterRef RR = NodeAddr<DefNode*>(Ds[0]).Addr->getRegRef(DFG);
dbgs() << '<' << Print<RegisterRef>(RR, DFG) << '>';
} else {
dbgs() << "<noreg>";
@@ -540,7 +595,7 @@ void Liveness::computeLiveIns() {
// Compute IDF first, then the inverse.
decltype(IIDF) IDF;
- for (auto &B : MF) {
+ for (MachineBasicBlock &B : MF) {
auto F1 = MDF.find(&B);
if (F1 == MDF.end())
continue;
@@ -562,20 +617,20 @@ void Liveness::computeLiveIns() {
computePhiInfo();
NodeAddr<FuncNode*> FA = DFG.getFunc();
- auto Blocks = FA.Addr->members(DFG);
+ NodeList Blocks = FA.Addr->members(DFG);
// Build the phi live-on-entry map.
for (NodeAddr<BlockNode*> BA : Blocks) {
MachineBasicBlock *MB = BA.Addr->getCode();
- auto &LON = PhiLON[MB];
+ RefMap &LON = PhiLON[MB];
for (auto P : BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG))
- for (auto S : RealUseMap[P.Id])
+ for (const RefMap::value_type &S : RealUseMap[P.Id])
LON[S.first].insert(S.second.begin(), S.second.end());
}
if (Trace) {
dbgs() << "Phi live-on-entry map:\n";
- for (auto I : PhiLON)
+ for (auto &I : PhiLON)
dbgs() << "block #" << I.first->getNumber() << " -> "
<< Print<RefMap>(I.second, DFG) << '\n';
}
@@ -584,33 +639,35 @@ void Liveness::computeLiveIns() {
// "real" uses. Propagate this set backwards into the block predecessors
// through the reaching defs of the corresponding phi uses.
for (NodeAddr<BlockNode*> BA : Blocks) {
- auto Phis = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG);
+ NodeList Phis = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG);
for (NodeAddr<PhiNode*> PA : Phis) {
- auto &RUs = RealUseMap[PA.Id];
+ RefMap &RUs = RealUseMap[PA.Id];
if (RUs.empty())
continue;
for (auto U : PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG)) {
- NodeAddr<PhiUseNode*> UA = U;
- if (UA.Addr->getReachingDef() == 0)
+ NodeAddr<PhiUseNode*> PUA = U;
+ if (PUA.Addr->getReachingDef() == 0)
continue;
// Mark all reached "real" uses of P as live on exit in the
// predecessor.
// Remap all the RUs so that they have a correct reaching def.
- auto PrA = DFG.addr<BlockNode*>(UA.Addr->getPredecessor());
- auto &LOX = PhiLOX[PrA.Addr->getCode()];
- for (auto R : RUs) {
- RegisterRef RR = R.first;
- if (!isRestricted(PA, UA, RR))
- RR = getRestrictedRegRef(UA);
- // The restricted ref may be different from the ref that was
- // accessed in the "real use". This means that this phi use
- // is not the one that carries this reference, so skip it.
- if (!RAI.alias(R.first, RR))
+ auto PrA = DFG.addr<BlockNode*>(PUA.Addr->getPredecessor());
+ RefMap &LOX = PhiLOX[PrA.Addr->getCode()];
+
+ RegisterRef UR = DFG.normalizeRef(getRestrictedRegRef(PUA));
+ for (const std::pair<RegisterId,NodeRefSet> &T : RUs) {
+ // Check if T.first aliases UR?
+ LaneBitmask M;
+ for (std::pair<NodeId,LaneBitmask> P : T.second)
+ M |= P.second;
+
+ RegisterRef S = DFG.restrictRef(RegisterRef(T.first, M), UR);
+ if (!S)
continue;
- for (auto D : getAllReachingDefs(RR, UA))
- LOX[RR].insert(D.Id);
+ for (NodeAddr<DefNode*> D : getAllReachingDefs(S, PUA))
+ LOX[S.Reg].insert({D.Id, S.Mask});
}
} // for U : phi uses
} // for P : Phis
@@ -618,7 +675,7 @@ void Liveness::computeLiveIns() {
if (Trace) {
dbgs() << "Phi live-on-exit map:\n";
- for (auto I : PhiLOX)
+ for (auto &I : PhiLOX)
dbgs() << "block #" << I.first->getNumber() << " -> "
<< Print<RefMap>(I.second, DFG) << '\n';
}
@@ -629,19 +686,41 @@ void Liveness::computeLiveIns() {
// Add function live-ins to the live-in set of the function entry block.
auto &EntryIn = LiveMap[&MF.front()];
for (auto I = MRI.livein_begin(), E = MRI.livein_end(); I != E; ++I)
- EntryIn.insert({I->first,0});
+ EntryIn.insert(RegisterRef(I->first));
if (Trace) {
// Dump the liveness map
- for (auto &B : MF) {
- BitVector LV(TRI.getNumRegs());
+ for (MachineBasicBlock &B : MF) {
+ std::vector<RegisterRef> LV;
for (auto I = B.livein_begin(), E = B.livein_end(); I != E; ++I)
- LV.set(I->PhysReg);
+ LV.push_back(RegisterRef(I->PhysReg, I->LaneMask));
+ std::sort(LV.begin(), LV.end());
dbgs() << "BB#" << B.getNumber() << "\t rec = {";
- for (int x = LV.find_first(); x >= 0; x = LV.find_next(x))
- dbgs() << ' ' << Print<RegisterRef>({unsigned(x),0}, DFG);
+ for (auto I : LV)
+ dbgs() << ' ' << Print<RegisterRef>(I, DFG);
dbgs() << " }\n";
- dbgs() << "\tcomp = " << Print<RegisterSet>(LiveMap[&B], DFG) << '\n';
+ //dbgs() << "\tcomp = " << Print<RegisterAggr>(LiveMap[&B], DFG) << '\n';
+
+ LV.clear();
+ for (std::pair<RegisterId,LaneBitmask> P : LiveMap[&B]) {
+ MCSubRegIndexIterator S(P.first, &TRI);
+ if (!S.isValid()) {
+ LV.push_back(RegisterRef(P.first));
+ continue;
+ }
+ do {
+ LaneBitmask M = TRI.getSubRegIndexLaneMask(S.getSubRegIndex());
+ if ((M & P.second).any())
+ LV.push_back(RegisterRef(S.getSubReg()));
+ ++S;
+ } while (S.isValid());
+ }
+ std::sort(LV.begin(), LV.end());
+ dbgs() << "\tcomp = {";
+ for (auto I : LV)
+ dbgs() << ' ' << Print<RegisterRef>(I, DFG);
+ dbgs() << " }\n";
+
}
}
}
@@ -658,8 +737,7 @@ void Liveness::resetLiveIns() {
// Add the newly computed live-ins.
auto &LiveIns = LiveMap[&B];
for (auto I : LiveIns) {
- assert(I.Sub == 0);
- B.addLiveIn(I.Reg);
+ B.addLiveIn({MCPhysReg(I.first), I.second});
}
}
}
@@ -672,9 +750,20 @@ void Liveness::resetKills() {
void Liveness::resetKills(MachineBasicBlock *B) {
- auto CopyLiveIns = [] (MachineBasicBlock *B, BitVector &LV) -> void {
- for (auto I = B->livein_begin(), E = B->livein_end(); I != E; ++I)
- LV.set(I->PhysReg);
+ auto CopyLiveIns = [this] (MachineBasicBlock *B, BitVector &LV) -> void {
+ for (auto I : B->liveins()) {
+ MCSubRegIndexIterator S(I.PhysReg, &TRI);
+ if (!S.isValid()) {
+ LV.set(I.PhysReg);
+ continue;
+ }
+ do {
+ LaneBitmask M = TRI.getSubRegIndexLaneMask(S.getSubRegIndex());
+ if ((M & I.LaneMask).any())
+ LV.set(S.getSubReg());
+ ++S;
+ } while (S.isValid());
+ }
};
BitVector LiveIn(TRI.getNumRegs()), Live(TRI.getNumRegs());
@@ -724,26 +813,6 @@ void Liveness::resetKills(MachineBasicBlock *B) {
}
-// For shadows, determine if RR is aliased to a reaching def of any other
-// shadow associated with RA. If it is not, then RR is "restricted" to RA,
-// and so it can be considered a value specific to RA. This is important
-// for accurately determining values associated with phi uses.
-// For non-shadows, this function returns "true".
-bool Liveness::isRestricted(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
- RegisterRef RR) const {
- NodeId Start = RA.Id;
- for (NodeAddr<RefNode*> TA = DFG.getNextShadow(IA, RA);
- TA.Id != 0 && TA.Id != Start; TA = DFG.getNextShadow(IA, TA)) {
- NodeId RD = TA.Addr->getReachingDef();
- if (RD == 0)
- continue;
- if (RAI.alias(RR, DFG.addr<DefNode*>(RD).Addr->getRegRef()))
- return false;
- }
- return true;
-}
-
-
RegisterRef Liveness::getRestrictedRegRef(NodeAddr<RefNode*> RA) const {
assert(DFG.IsRef<NodeAttrs::Use>(RA));
if (RA.Addr->getFlags() & NodeAttrs::Shadow) {
@@ -751,14 +820,7 @@ RegisterRef Liveness::getRestrictedRegRef(NodeAddr<RefNode*> RA) const {
assert(RD);
RA = DFG.addr<DefNode*>(RD);
}
- return RA.Addr->getRegRef();
-}
-
-
-unsigned Liveness::getPhysReg(RegisterRef RR) const {
- if (!TargetRegisterInfo::isPhysicalRegister(RR.Reg))
- return 0;
- return RR.Sub ? TRI.getSubReg(RR.Reg, RR.Sub) : RR.Reg;
+ return RA.Addr->getRegRef(DFG);
}
@@ -808,77 +870,99 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
}
if (Trace) {
- dbgs() << LLVM_FUNCTION_NAME << " in BB#" << B->getNumber()
- << " after recursion into";
+ dbgs() << "\n-- BB#" << B->getNumber() << ": " << __func__
+ << " after recursion into: {";
for (auto I : *N)
dbgs() << ' ' << I->getBlock()->getNumber();
- dbgs() << "\n LiveIn: " << Print<RefMap>(LiveIn, DFG);
- dbgs() << "\n Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n';
+ dbgs() << " }\n";
+ dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n';
+ dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n';
}
- // Add phi uses that are live on exit from this block.
+ // Add reaching defs of phi uses that are live on exit from this block.
RefMap &PUs = PhiLOX[B];
- for (auto S : PUs)
+ for (auto &S : PUs)
LiveIn[S.first].insert(S.second.begin(), S.second.end());
if (Trace) {
dbgs() << "after LOX\n";
dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n';
- dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n';
+ dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n';
}
- // Stop tracking all uses defined in this block: erase those records
- // where the reaching def is located in B and which cover all reached
- // uses.
- auto Copy = LiveIn;
+ // The LiveIn map at this point has all defs that are live-on-exit from B,
+ // as if they were live-on-entry to B. First, we need to filter out all
+ // defs that are present in this block. Then we will add reaching defs of
+ // all upward-exposed uses.
+
+ // To filter out the defs, first make a copy of LiveIn, and then re-populate
+ // LiveIn with the defs that should remain.
+ RefMap LiveInCopy = LiveIn;
LiveIn.clear();
- for (auto I : Copy) {
- auto &Defs = LiveIn[I.first];
- NodeSet Rest;
- for (auto R : I.second) {
- auto DA = DFG.addr<DefNode*>(R);
- RegisterRef DDR = DA.Addr->getRegRef();
+ for (const std::pair<RegisterId,NodeRefSet> &LE : LiveInCopy) {
+ RegisterRef LRef(LE.first);
+ NodeRefSet &NewDefs = LiveIn[LRef.Reg]; // To be filled.
+ const NodeRefSet &OldDefs = LE.second;
+ for (NodeRef OR : OldDefs) {
+ // R is a def node that was live-on-exit
+ auto DA = DFG.addr<DefNode*>(OR.first);
NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG);
NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG);
- // Defs from a different block need to be preserved. Defs from this
- // block will need to be processed further, except for phi defs, the
- // liveness of which is handled through the PhiLON/PhiLOX maps.
- if (B != BA.Addr->getCode())
- Defs.insert(R);
- else {
- bool IsPreserving = DA.Addr->getFlags() & NodeAttrs::Preserving;
- if (IA.Addr->getKind() != NodeAttrs::Phi && !IsPreserving) {
- bool Covering = RAI.covers(DDR, I.first);
- NodeId U = DA.Addr->getReachedUse();
- while (U && Covering) {
- auto DUA = DFG.addr<UseNode*>(U);
- RegisterRef Q = DUA.Addr->getRegRef();
- Covering = RAI.covers(DA.Addr->getRegRef(), Q);
- U = DUA.Addr->getSibling();
- }
- if (!Covering)
- Rest.insert(R);
- }
+ if (B != BA.Addr->getCode()) {
+ // Defs from a different block need to be preserved. Defs from this
+ // block will need to be processed further, except for phi defs, the
+ // liveness of which is handled through the PhiLON/PhiLOX maps.
+ NewDefs.insert(OR);
+ continue;
+ }
+
+ // Defs from this block need to stop the liveness from being
+ // propagated upwards. This only applies to non-preserving defs,
+ // and to the parts of the register actually covered by those defs.
+ // (Note that phi defs should always be preserving.)
+ RegisterAggr RRs(TRI);
+ LRef.Mask = OR.second;
+
+ if (!DFG.IsPreservingDef(DA)) {
+ assert(!(IA.Addr->getFlags() & NodeAttrs::Phi));
+ // DA is a non-phi def that is live-on-exit from this block, and
+ // that is also located in this block. LRef is a register ref
+ // whose use this def reaches. If DA covers LRef, then no part
+ // of LRef is exposed upwards.A
+ if (RRs.insert(DA.Addr->getRegRef(DFG)).hasCoverOf(LRef))
+ continue;
}
- }
- // Non-covering defs from B.
- for (auto R : Rest) {
- auto DA = DFG.addr<DefNode*>(R);
- RegisterRef DRR = DA.Addr->getRegRef();
- RegisterSet RRs;
+ // DA itself was not sufficient to cover LRef. In general, it is
+ // the last in a chain of aliased defs before the exit from this block.
+ // There could be other defs in this block that are a part of that
+ // chain. Check that now: accumulate the registers from these defs,
+ // and if they all together cover LRef, it is not live-on-entry.
for (NodeAddr<DefNode*> TA : getAllReachingDefs(DA)) {
- NodeAddr<InstrNode*> IA = TA.Addr->getOwner(DFG);
- NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG);
- // Preserving defs do not count towards covering.
+ // DefNode -> InstrNode -> BlockNode.
+ NodeAddr<InstrNode*> ITA = TA.Addr->getOwner(DFG);
+ NodeAddr<BlockNode*> BTA = ITA.Addr->getOwner(DFG);
+ // Reaching defs are ordered in the upward direction.
+ if (BTA.Addr->getCode() != B) {
+ // We have reached past the beginning of B, and the accumulated
+ // registers are not covering LRef. The first def from the
+ // upward chain will be live.
+ // Subtract all accumulated defs (RRs) from LRef.
+ RegisterAggr L(TRI);
+ L.insert(LRef).clear(RRs);
+ assert(!L.empty());
+ NewDefs.insert({TA.Id,L.begin()->second});
+ break;
+ }
+
+ // TA is in B. Only add this def to the accumulated cover if it is
+ // not preserving.
if (!(TA.Addr->getFlags() & NodeAttrs::Preserving))
- RRs.insert(TA.Addr->getRegRef());
- if (BA.Addr->getCode() == B)
- continue;
- if (RAI.covers(RRs, DRR))
+ RRs.insert(TA.Addr->getRegRef(DFG));
+ // If this is enough to cover LRef, then stop.
+ if (RRs.hasCoverOf(LRef))
break;
- Defs.insert(TA.Id);
}
}
}
@@ -888,7 +972,7 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
if (Trace) {
dbgs() << "after defs in block\n";
dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n';
- dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n';
+ dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n';
}
// Scan the block for upward-exposed uses and add them to the tracking set.
@@ -897,38 +981,44 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
if (IA.Addr->getKind() != NodeAttrs::Stmt)
continue;
for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) {
- RegisterRef RR = UA.Addr->getRegRef();
- for (auto D : getAllReachingDefs(UA))
+ if (UA.Addr->getFlags() & NodeAttrs::Undef)
+ continue;
+ RegisterRef RR = DFG.normalizeRef(UA.Addr->getRegRef(DFG));
+ for (NodeAddr<DefNode*> D : getAllReachingDefs(UA))
if (getBlockWithRef(D.Id) != B)
- LiveIn[RR].insert(D.Id);
+ LiveIn[RR.Reg].insert({D.Id,RR.Mask});
}
}
if (Trace) {
dbgs() << "after uses in block\n";
dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n';
- dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n';
+ dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n';
}
// Phi uses should not be propagated up the dominator tree, since they
// are not dominated by their corresponding reaching defs.
- auto &Local = LiveMap[B];
- auto &LON = PhiLON[B];
- for (auto R : LON)
- Local.insert(R.first);
+ RegisterAggr &Local = LiveMap[B];
+ RefMap &LON = PhiLON[B];
+ for (auto &R : LON) {
+ LaneBitmask M;
+ for (auto P : R.second)
+ M |= P.second;
+ Local.insert(RegisterRef(R.first,M));
+ }
if (Trace) {
dbgs() << "after phi uses in block\n";
dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n';
- dbgs() << " Local: " << Print<RegisterSet>(Local, DFG) << '\n';
+ dbgs() << " Local: " << Print<RegisterAggr>(Local, DFG) << '\n';
}
for (auto C : IIDF[B]) {
- auto &LiveC = LiveMap[C];
- for (auto S : LiveIn)
+ RegisterAggr &LiveC = LiveMap[C];
+ for (const std::pair<RegisterId,NodeRefSet> &S : LiveIn)
for (auto R : S.second)
- if (MDT.properlyDominates(getBlockWithRef(R), C))
- LiveC.insert(S.first);
+ if (MDT.properlyDominates(getBlockWithRef(R.first), C))
+ LiveC.insert(RegisterRef(S.first, R.second));
}
}
diff --git a/contrib/llvm/lib/Target/Hexagon/RDFLiveness.h b/contrib/llvm/lib/Target/Hexagon/RDFLiveness.h
index 2b49c74..c88396f 100644
--- a/contrib/llvm/lib/Target/Hexagon/RDFLiveness.h
+++ b/contrib/llvm/lib/Target/Hexagon/RDFLiveness.h
@@ -30,20 +30,44 @@ namespace llvm {
namespace rdf {
struct Liveness {
public:
- typedef std::map<MachineBasicBlock*,RegisterSet> LiveMapType;
- typedef std::map<RegisterRef,NodeSet> RefMap;
+ // This is really a std::map, except that it provides a non-trivial
+ // default constructor to the element accessed via [].
+ struct LiveMapType {
+ LiveMapType(const TargetRegisterInfo &tri) : Empty(tri) {}
+
+ RegisterAggr &operator[] (MachineBasicBlock *B) {
+ return Map.emplace(B, Empty).first->second;
+ }
+ private:
+ RegisterAggr Empty;
+ std::map<MachineBasicBlock*,RegisterAggr> Map;
+ };
+
+ typedef std::pair<NodeId,LaneBitmask> NodeRef;
+ typedef std::set<NodeRef> NodeRefSet;
+ // RegisterId in RefMap must be normalized.
+ typedef std::map<RegisterId,NodeRefSet> RefMap;
Liveness(MachineRegisterInfo &mri, const DataFlowGraph &g)
: DFG(g), TRI(g.getTRI()), MDT(g.getDT()), MDF(g.getDF()),
- RAI(g.getRAI()), MRI(mri), Empty(), Trace(false) {}
+ MRI(mri), LiveMap(g.getTRI()), Empty(), NoRegs(g.getTRI()),
+ Trace(false) {}
NodeList getAllReachingDefs(RegisterRef RefRR, NodeAddr<RefNode*> RefA,
- bool FullChain = false, const RegisterSet &DefRRs = RegisterSet());
- NodeList getAllReachingDefs(NodeAddr<RefNode*> RefA);
+ bool FullChain, const RegisterAggr &DefRRs);
+ NodeList getAllReachingDefs(NodeAddr<RefNode*> RefA) {
+ return getAllReachingDefs(RefA.Addr->getRegRef(DFG), RefA, false, NoRegs);
+ }
+ NodeList getAllReachingDefs(RegisterRef RefRR, NodeAddr<RefNode*> RefA) {
+ return getAllReachingDefs(RefRR, RefA, false, NoRegs);
+ }
NodeSet getAllReachingDefsRec(RegisterRef RefRR, NodeAddr<RefNode*> RefA,
NodeSet &Visited, const NodeSet &Defs);
NodeSet getAllReachedUses(RegisterRef RefRR, NodeAddr<DefNode*> DefA,
- const RegisterSet &DefRRs = RegisterSet());
+ const RegisterAggr &DefRRs);
+ NodeSet getAllReachedUses(RegisterRef RefRR, NodeAddr<DefNode*> DefA) {
+ return getAllReachedUses(RefRR, DefA, NoRegs);
+ }
LiveMapType &getLiveMap() { return LiveMap; }
const LiveMapType &getLiveMap() const { return LiveMap; }
@@ -65,10 +89,10 @@ namespace rdf {
const TargetRegisterInfo &TRI;
const MachineDominatorTree &MDT;
const MachineDominanceFrontier &MDF;
- const RegisterAliasInfo &RAI;
MachineRegisterInfo &MRI;
LiveMapType LiveMap;
const RefMap Empty;
+ const RegisterAggr NoRegs;
bool Trace;
// Cache of mapping from node ids (for RefNodes) to the containing
@@ -79,7 +103,8 @@ namespace rdf {
// Phi information:
//
- // map: NodeId -> (map: RegisterRef -> NodeSet)
+ // RealUseMap
+ // map: NodeId -> (map: RegisterId -> NodeRefSet)
// phi id -> (map: register -> set of reached non-phi uses)
std::map<NodeId, RefMap> RealUseMap;
@@ -96,10 +121,9 @@ namespace rdf {
// the dominator tree), create a map: block -> set of uses live on exit.
std::map<MachineBasicBlock*,RefMap> PhiLOX;
- bool isRestricted(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
+ bool isRestrictedToRef(NodeAddr<InstrNode*> IA, NodeAddr<RefNode*> RA,
RegisterRef RR) const;
RegisterRef getRestrictedRegRef(NodeAddr<RefNode*> RA) const;
- unsigned getPhysReg(RegisterRef RR) const;
MachineBasicBlock *getBlockWithRef(NodeId RN) const;
void traverse(MachineBasicBlock *B, RefMap &LiveIn);
void emptify(RefMap &M);
diff --git a/contrib/llvm/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp b/contrib/llvm/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
index 40f6c8d..0554646 100644
--- a/contrib/llvm/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/Hexagon/TargetInfo/HexagonTargetInfo.cpp
@@ -12,8 +12,12 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheHexagonTarget;
+Target &llvm::getTheHexagonTarget() {
+ static Target TheHexagonTarget;
+ return TheHexagonTarget;
+}
extern "C" void LLVMInitializeHexagonTargetInfo() {
- RegisterTarget<Triple::hexagon, /*HasJIT=*/false> X(TheHexagonTarget, "hexagon", "Hexagon");
+ RegisterTarget<Triple::hexagon, /*HasJIT=*/false> X(getTheHexagonTarget(),
+ "hexagon", "Hexagon");
}
diff --git a/contrib/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp b/contrib/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
index cbb96d8..57ead97 100644
--- a/contrib/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
+++ b/contrib/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
@@ -8,23 +8,41 @@
//===----------------------------------------------------------------------===//
#include "Lanai.h"
+#include "LanaiAluCode.h"
+#include "LanaiCondCode.h"
#include "MCTargetDesc/LanaiMCExpr.h"
-#include "MCTargetDesc/LanaiMCTargetDesc.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
namespace llvm {
+
+// Auto-generated by TableGen
+static unsigned MatchRegisterName(StringRef Name);
+
namespace {
+
struct LanaiOperand;
class LanaiAsmParser : public MCTargetAsmParser {
@@ -80,9 +98,6 @@ private:
const MCSubtargetInfo &SubtargetInfo;
};
-// Auto-generated by TableGen
-static unsigned MatchRegisterName(llvm::StringRef Name);
-
// LanaiOperand - Instances of this class represented a parsed machine
// instruction
struct LanaiOperand : public MCParsedAsmOperand {
@@ -627,6 +642,8 @@ public:
}
};
+} // end anonymous namespace
+
bool LanaiAsmParser::ParseDirective(AsmToken /*DirectiveId*/) { return true; }
bool LanaiAsmParser::MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,
@@ -680,11 +697,11 @@ std::unique_ptr<LanaiOperand> LanaiAsmParser::parseRegister() {
if (Lexer.getKind() == AsmToken::Identifier) {
RegNum = MatchRegisterName(Lexer.getTok().getIdentifier());
if (RegNum == 0)
- return 0;
+ return nullptr;
Parser.Lex(); // Eat identifier token
return LanaiOperand::createReg(RegNum, Start, End);
}
- return 0;
+ return nullptr;
}
bool LanaiAsmParser::ParseRegister(unsigned &RegNum, SMLoc &StartLoc,
@@ -701,15 +718,15 @@ bool LanaiAsmParser::ParseRegister(unsigned &RegNum, SMLoc &StartLoc,
std::unique_ptr<LanaiOperand> LanaiAsmParser::parseIdentifier() {
SMLoc Start = Parser.getTok().getLoc();
SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- const MCExpr *Res, *RHS = 0;
+ const MCExpr *Res, *RHS = nullptr;
LanaiMCExpr::VariantKind Kind = LanaiMCExpr::VK_Lanai_None;
if (Lexer.getKind() != AsmToken::Identifier)
- return 0;
+ return nullptr;
StringRef Identifier;
if (Parser.parseIdentifier(Identifier))
- return 0;
+ return nullptr;
// Check if identifier has a modifier
if (Identifier.equals_lower("hi"))
@@ -722,24 +739,24 @@ std::unique_ptr<LanaiOperand> LanaiAsmParser::parseIdentifier() {
if (Kind != LanaiMCExpr::VK_Lanai_None) {
if (Lexer.getKind() != AsmToken::LParen) {
Error(Lexer.getLoc(), "Expected '('");
- return 0;
+ return nullptr;
}
Lexer.Lex(); // lex '('
// Parse identifier
if (Parser.parseIdentifier(Identifier))
- return 0;
+ return nullptr;
}
// If addition parse the RHS.
if (Lexer.getKind() == AsmToken::Plus && Parser.parseExpression(RHS))
- return 0;
+ return nullptr;
// For variants parse the final ')'
if (Kind != LanaiMCExpr::VK_Lanai_None) {
if (Lexer.getKind() != AsmToken::RParen) {
Error(Lexer.getLoc(), "Expected ')'");
- return 0;
+ return nullptr;
}
Lexer.Lex(); // lex ')'
}
@@ -771,7 +788,7 @@ std::unique_ptr<LanaiOperand> LanaiAsmParser::parseImmediate() {
if (!Parser.parseExpression(ExprVal))
return LanaiOperand::createImm(ExprVal, Start, End);
default:
- return 0;
+ return nullptr;
}
}
@@ -844,7 +861,7 @@ bool shouldBeSls(const LanaiOperand &Op) {
}
// Matches memory operand. Returns true if error encountered.
-LanaiAsmParser::OperandMatchResultTy
+OperandMatchResultTy
LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) {
// Try to match a memory operand.
// The memory operands are of the form:
@@ -978,7 +995,7 @@ LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) {
// Looks at a token type and creates the relevant operand from this
// information, adding to operands.
// If operand was parsed, returns false, else true.
-LanaiAsmParser::OperandMatchResultTy
+OperandMatchResultTy
LanaiAsmParser::parseOperand(OperandVector *Operands, StringRef Mnemonic) {
// Check if the current operand has a custom associated parser, if so, try to
// custom parse the operand, or fallback to the general approach.
@@ -1204,10 +1221,9 @@ bool LanaiAsmParser::ParseInstruction(ParseInstructionInfo & /*Info*/,
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#include "LanaiGenAsmMatcher.inc"
-} // namespace
extern "C" void LLVMInitializeLanaiAsmParser() {
- RegisterMCAsmParser<LanaiAsmParser> x(TheLanaiTarget);
+ RegisterMCAsmParser<LanaiAsmParser> x(getTheLanaiTarget());
}
-} // namespace llvm
+} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp b/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
index 744441b..609b650 100644
--- a/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
+++ b/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
@@ -19,7 +19,6 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
@@ -27,7 +26,7 @@ using namespace llvm;
typedef MCDisassembler::DecodeStatus DecodeStatus;
namespace llvm {
-extern Target TheLanaiTarget;
+Target &getTheLanaiTarget();
}
static MCDisassembler *createLanaiDisassembler(const Target & /*T*/,
@@ -38,7 +37,7 @@ static MCDisassembler *createLanaiDisassembler(const Target & /*T*/,
extern "C" void LLVMInitializeLanaiDisassembler() {
// Register the disassembler
- TargetRegistry::RegisterMCDisassembler(TheLanaiTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheLanaiTarget(),
createLanaiDisassembler);
}
@@ -47,8 +46,9 @@ LanaiDisassembler::LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
// Forward declare because the autogenerated code will reference this.
// Definition is further down.
-DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
- uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder);
static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);
diff --git a/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.h b/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.h
index a317cd8..e0c19e8 100644
--- a/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.h
+++ b/contrib/llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.h
@@ -20,14 +20,11 @@
namespace llvm {
-class MCInst;
-class raw_ostream;
-
class LanaiDisassembler : public MCDisassembler {
public:
LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx);
- ~LanaiDisassembler() override {}
+ ~LanaiDisassembler() override = default;
// getInstruction - See MCDisassembler.
MCDisassembler::DecodeStatus
@@ -36,6 +33,6 @@ public:
raw_ostream &CStream) const override;
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H
diff --git a/contrib/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h b/contrib/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
index 1c9d186..59904fb 100644
--- a/contrib/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
+++ b/contrib/llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
@@ -14,10 +14,10 @@
#ifndef LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
#define LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
+#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInstPrinter.h"
namespace llvm {
-class MCOperand;
class LanaiInstPrinter : public MCInstPrinter {
public:
@@ -28,14 +28,14 @@ public:
void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
const MCSubtargetInfo &STI) override;
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
- const char *Modifier = 0);
+ const char *Modifier = nullptr);
void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O,
- const char *Modifier = 0);
+ const char *Modifier = nullptr);
void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O,
- const char *Modifier = 0);
+ const char *Modifier = nullptr);
void printMemSplsOperand(const MCInst *MI, int OpNo, raw_ostream &O,
- const char *Modifier = 0);
+ const char *Modifier = nullptr);
void printCCOperand(const MCInst *MI, int OpNo, raw_ostream &O);
void printAluOperand(const MCInst *MI, int OpNo, raw_ostream &O);
void printHi16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
@@ -60,6 +60,7 @@ private:
bool printMemoryStoreIncrement(const MCInst *MI, raw_ostream &Ostream,
StringRef Opcode, int AddOffset);
};
-} // namespace llvm
+
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
diff --git a/contrib/llvm/lib/Target/Lanai/Lanai.h b/contrib/llvm/lib/Target/Lanai/Lanai.h
index 47bd498..c1fdf79 100644
--- a/contrib/llvm/lib/Target/Lanai/Lanai.h
+++ b/contrib/llvm/lib/Target/Lanai/Lanai.h
@@ -45,7 +45,7 @@ FunctionPass *createLanaiMemAluCombinerPass();
// operations.
FunctionPass *createLanaiSetflagAluCombinerPass();
-extern Target TheLanaiTarget;
+Target &getTheLanaiTarget();
} // namespace llvm
#endif // LLVM_LIB_TARGET_LANAI_LANAI_H
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiAluCode.h b/contrib/llvm/lib/Target/Lanai/LanaiAluCode.h
index b6ceede..d514569 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiAluCode.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiAluCode.h
@@ -43,8 +43,8 @@ enum AluCode {
// Bits indicating post- and pre-operators should be tested and set using Is*
// and Make* utility functions
-constexpr int Lanai_PRE_OP = 0x40;
-constexpr int Lanai_POST_OP = 0x80;
+const int Lanai_PRE_OP = 0x40;
+const int Lanai_POST_OP = 0x80;
inline static unsigned encodeLanaiAluCode(unsigned AluOp) {
unsigned const OP_ENCODING_MASK = 0x07;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp b/contrib/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp
index 9d39cef..607b2a9 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp
@@ -45,7 +45,7 @@ public:
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)) {}
- const char *getPassName() const override { return "Lanai Assembly Printer"; }
+ StringRef getPassName() const override { return "Lanai Assembly Printer"; }
void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
@@ -151,7 +151,7 @@ void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {
assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) &&
"Unsupported call function");
- LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this);
+ LanaiMCInstLower MCInstLowering(OutContext, *this);
MCSubtargetInfo STI = getSubtargetInfo();
// Insert save rca instruction immediately before the call.
// TODO: We should generate a pc-relative mov instruction here instead
@@ -188,7 +188,7 @@ void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {
}
void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) {
- LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this);
+ LanaiMCInstLower MCInstLowering(OutContext, *this);
MCSubtargetInfo STI = getSubtargetInfo();
MCInst TmpInst;
MCInstLowering.Lower(MI, TmpInst);
@@ -239,5 +239,5 @@ bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough(
// Force static initialization.
extern "C" void LLVMInitializeLanaiAsmPrinter() {
- RegisterAsmPrinter<LanaiAsmPrinter> X(TheLanaiTarget);
+ RegisterAsmPrinter<LanaiAsmPrinter> X(getTheLanaiTarget());
}
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp b/contrib/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
index 7b10654..802232b 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
@@ -42,7 +42,7 @@ struct Filler : public MachineFunctionPass {
static char ID;
explicit Filler() : MachineFunctionPass(ID) {}
- const char *getPassName() const override { return "Lanai Delay Slot Filler"; }
+ StringRef getPassName() const override { return "Lanai Delay Slot Filler"; }
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
@@ -60,7 +60,7 @@ struct Filler : public MachineFunctionPass {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
void insertDefsUses(MachineBasicBlock::instr_iterator MI,
@@ -105,7 +105,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
// RET is generated as part of epilogue generation and hence we know
// what the two instructions preceding it are and that it is safe to
// insert RET above them.
- MachineBasicBlock::reverse_instr_iterator RI(I);
+ MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse();
assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
RI->getOperand(0).getReg() == Lanai::FP &&
RI->getOperand(1).isReg() &&
@@ -117,8 +117,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
RI->getOperand(0).getReg() == Lanai::SP &&
RI->getOperand(1).isReg() &&
RI->getOperand(1).getReg() == Lanai::FP);
- ++RI;
- MachineBasicBlock::instr_iterator FI(RI.base());
+ MachineBasicBlock::instr_iterator FI = RI.getReverse();
MBB.splice(std::next(I), &MBB, FI, I);
FilledSlots += 2;
} else {
@@ -154,14 +153,14 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB,
bool SawLoad = false;
bool SawStore = false;
- for (MachineBasicBlock::reverse_instr_iterator I(Slot); I != MBB.instr_rend();
- ++I) {
+ for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse();
+ I != MBB.instr_rend(); ++I) {
// skip debug value
if (I->isDebugValue())
continue;
// Convert to forward iterator.
- MachineBasicBlock::instr_iterator FI(std::next(I).base());
+ MachineBasicBlock::instr_iterator FI = I.getReverse();
if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
FI == LastFiller || I->isPseudo())
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiFrameLowering.cpp b/contrib/llvm/lib/Target/Lanai/LanaiFrameLowering.cpp
index cb048d5..0723668 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiFrameLowering.cpp
@@ -26,36 +26,36 @@ using namespace llvm;
// Determines the size of the frame and maximum call frame size.
void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const LanaiRegisterInfo *LRI = STI.getRegisterInfo();
// Get the number of bytes to allocate from the FrameInfo.
- unsigned FrameSize = MFI->getStackSize();
+ unsigned FrameSize = MFI.getStackSize();
// Get the alignment.
- unsigned StackAlign = LRI->needsStackRealignment(MF) ? MFI->getMaxAlignment()
+ unsigned StackAlign = LRI->needsStackRealignment(MF) ? MFI.getMaxAlignment()
: getStackAlignment();
// Get the maximum call frame size of all the calls.
- unsigned MaxCallFrameSize = MFI->getMaxCallFrameSize();
+ unsigned MaxCallFrameSize = MFI.getMaxCallFrameSize();
// If we have dynamic alloca then MaxCallFrameSize needs to be aligned so
// that allocations will be aligned.
- if (MFI->hasVarSizedObjects())
+ if (MFI.hasVarSizedObjects())
MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign);
// Update maximum call frame size.
- MFI->setMaxCallFrameSize(MaxCallFrameSize);
+ MFI.setMaxCallFrameSize(MaxCallFrameSize);
// Include call frame size in total.
- if (!(hasReservedCallFrame(MF) && MFI->adjustsStack()))
+ if (!(hasReservedCallFrame(MF) && MFI.adjustsStack()))
FrameSize += MaxCallFrameSize;
// Make sure the frame is aligned.
FrameSize = alignTo(FrameSize, StackAlign);
// Update frame info.
- MFI->setStackSize(FrameSize);
+ MFI.setStackSize(FrameSize);
}
// Iterates through each basic block in a machine function and replaces
@@ -64,7 +64,7 @@ void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const {
void LanaiFrameLowering::replaceAdjDynAllocPseudo(MachineFunction &MF) const {
const LanaiInstrInfo &LII =
*static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
- unsigned MaxCallFrameSize = MF.getFrameInfo()->getMaxCallFrameSize();
+ unsigned MaxCallFrameSize = MF.getFrameInfo().getMaxCallFrameSize();
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E;
++MBB) {
@@ -93,7 +93,7 @@ void LanaiFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const LanaiInstrInfo &LII =
*static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
MachineBasicBlock::iterator MBBI = MBB.begin();
@@ -107,7 +107,7 @@ void LanaiFrameLowering::emitPrologue(MachineFunction &MF,
// FIXME: This appears to be overallocating. Needs investigation.
// Get the number of bytes to allocate from the FrameInfo.
- unsigned StackSize = MFI->getStackSize();
+ unsigned StackSize = MFI.getStackSize();
// Push old FP
// st %fp,-4[*%sp]
@@ -135,7 +135,7 @@ void LanaiFrameLowering::emitPrologue(MachineFunction &MF,
}
// Replace ADJDYNANALLOC
- if (MFI->hasVarSizedObjects())
+ if (MFI.hasVarSizedObjects())
replaceAdjDynAllocPseudo(MF);
}
@@ -200,21 +200,21 @@ void LanaiFrameLowering::determineCalleeSaves(MachineFunction &MF,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const LanaiRegisterInfo *LRI =
static_cast<const LanaiRegisterInfo *>(STI.getRegisterInfo());
int Offset = -4;
// Reserve 4 bytes for the saved RCA
- MFI->CreateFixedObject(4, Offset, true);
+ MFI.CreateFixedObject(4, Offset, true);
Offset -= 4;
// Reserve 4 bytes for the saved FP
- MFI->CreateFixedObject(4, Offset, true);
+ MFI.CreateFixedObject(4, Offset, true);
Offset -= 4;
if (LRI->hasBasePointer(MF)) {
- MFI->CreateFixedObject(4, Offset, true);
+ MFI.CreateFixedObject(4, Offset, true);
SavedRegs.reset(LRI->getBaseRegister());
}
}
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Lanai/LanaiISelDAGToDAG.cpp
index 29bc6e8..ed0c99a 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiISelDAGToDAG.cpp
@@ -56,7 +56,7 @@ public:
}
// Pass Name
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Lanai DAG->DAG Pattern Instruction Selection";
}
@@ -282,9 +282,29 @@ void LanaiDAGToDAGISel::Select(SDNode *Node) {
return;
}
- // Instruction Selection not handled by the auto-generated
- // tablegen selection should be handled here.
+ // Instruction Selection not handled by the auto-generated tablegen selection
+ // should be handled here.
+ EVT VT = Node->getValueType(0);
switch (Opcode) {
+ case ISD::Constant:
+ if (VT == MVT::i32) {
+ ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node);
+ // Materialize zero constants as copies from R0. This allows the coalescer
+ // to propagate these into other instructions.
+ if (ConstNode->isNullValue()) {
+ SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
+ SDLoc(Node), Lanai::R0, MVT::i32);
+ return ReplaceNode(Node, New.getNode());
+ }
+ // Materialize all ones constants as copies from R1. This allows the
+ // coalescer to propagate these into other instructions.
+ if (ConstNode->isAllOnesValue()) {
+ SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
+ SDLoc(Node), Lanai::R1, MVT::i32);
+ return ReplaceNode(Node, New.getNode());
+ }
+ }
+ break;
case ISD::FrameIndex:
selectFrameIndex(Node);
return;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.cpp b/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.cpp
index 66416b3..d156294 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.cpp
@@ -11,31 +11,46 @@
//
//===----------------------------------------------------------------------===//
-#include "LanaiISelLowering.h"
-
#include "Lanai.h"
+#include "LanaiCondCode.h"
+#include "LanaiISelLowering.h"
#include "LanaiMachineFunctionInfo.h"
#include "LanaiSubtarget.h"
-#include "LanaiTargetMachine.h"
#include "LanaiTargetObjectFile.h"
+#include "MCTargetDesc/LanaiBaseInfo.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/SelectionDAGISel.h"
-#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/CodeGen/RuntimeLibcalls.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalAlias.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetCallingConv.h"
+#include "llvm/Target/TargetMachine.h"
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <utility>
#define DEBUG_TYPE "lanai-lower"
@@ -104,7 +119,7 @@ LanaiTargetLowering::LanaiTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::ROTR, MVT::i32, Expand);
setOperationAction(ISD::ROTL, MVT::i32, Expand);
- setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom);
setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
@@ -179,6 +194,8 @@ SDValue LanaiTargetLowering::LowerOperation(SDValue Op,
return LowerSETCC(Op, DAG);
case ISD::SETCCE:
return LowerSETCCE(Op, DAG);
+ case ISD::SHL_PARTS:
+ return LowerSHL_PARTS(Op, DAG);
case ISD::SRL_PARTS:
return LowerSRL_PARTS(Op, DAG);
case ISD::VASTART:
@@ -193,6 +210,7 @@ SDValue LanaiTargetLowering::LowerOperation(SDValue Op,
llvm_unreachable("unimplemented operand");
}
}
+
//===----------------------------------------------------------------------===//
// Lanai Inline Assembly Support
//===----------------------------------------------------------------------===//
@@ -242,7 +260,7 @@ LanaiTargetLowering::getSingleConstraintMatchWeight(
Value *CallOperandVal = Info.CallOperandVal;
// If we don't have a value, we can't do a match,
// but allow it at the lowest weight.
- if (CallOperandVal == NULL)
+ if (CallOperandVal == nullptr)
return CW_Default;
// Look at the constraint type.
switch (*Constraint) {
@@ -268,7 +286,7 @@ LanaiTargetLowering::getSingleConstraintMatchWeight(
void LanaiTargetLowering::LowerAsmOperandForConstraint(
SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
SelectionDAG &DAG) const {
- SDValue Result(0, 0);
+ SDValue Result(nullptr, 0);
// Only support length 1 constraints for now.
if (Constraint.length() > 1)
@@ -423,7 +441,7 @@ SDValue LanaiTargetLowering::LowerCCCArguments(
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>();
@@ -480,7 +498,7 @@ SDValue LanaiTargetLowering::LowerCCCArguments(
<< EVT(VA.getLocVT()).getEVTString() << "\n";
}
// Create the frame index object for this incoming parameter...
- int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
+ int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
// Create the SelectionDAG nodes corresponding to a load
// from this parameter
@@ -507,7 +525,7 @@ SDValue LanaiTargetLowering::LowerCCCArguments(
if (IsVarArg) {
// Record the frame index of the first variable argument
// which is a value necessary to VASTART.
- int FI = MFI->CreateFixedObject(4, CCInfo.getNextStackOffset(), true);
+ int FI = MFI.CreateFixedObject(4, CCInfo.getNextStackOffset(), true);
LanaiMFI->setVarArgsFrameIndex(FI);
}
@@ -588,7 +606,7 @@ SDValue LanaiTargetLowering::LowerCCCCallTo(
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee);
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
NumFixedArgs = 0;
if (IsVarArg && G) {
@@ -619,7 +637,7 @@ SDValue LanaiTargetLowering::LowerCCCCallTo(
unsigned Size = Flags.getByValSize();
unsigned Align = Flags.getByValAlign();
- int FI = MFI->CreateStackObject(Size, Align, false);
+ int FI = MFI.CreateStackObject(Size, Align, false);
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
SDValue SizeNode = DAG.getConstant(Size, DL, MVT::i32);
@@ -674,7 +692,7 @@ SDValue LanaiTargetLowering::LowerCCCCallTo(
} else {
assert(VA.isMemLoc());
- if (StackPtr.getNode() == 0)
+ if (StackPtr.getNode() == nullptr)
StackPtr = DAG.getCopyFromReg(Chain, DL, Lanai::SP,
getPointerTy(DAG.getDataLayout()));
@@ -1052,8 +1070,8 @@ SDValue LanaiTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SDValue LanaiTargetLowering::LowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc DL(Op);
@@ -1074,8 +1092,8 @@ SDValue LanaiTargetLowering::LowerRETURNADDR(SDValue Op,
SDValue LanaiTargetLowering::LowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc DL(Op);
@@ -1118,7 +1136,7 @@ const char *LanaiTargetLowering::getTargetNodeName(unsigned Opcode) const {
case LanaiISD::SMALL:
return "LanaiISD::SMALL";
default:
- return NULL;
+ return nullptr;
}
}
@@ -1167,8 +1185,8 @@ SDValue LanaiTargetLowering::LowerGlobalAddress(SDValue Op,
// If the code model is small or global variable will be placed in the small
// section, then assume address will fit in 21-bits.
- if (getTargetMachine().getCodeModel() == CodeModel::Small ||
- TLOF->isGlobalInSmallSection(GV, getTargetMachine())) {
+ const GlobalObject *GO = GV->getBaseObject();
+ if (TLOF->isGlobalInSmallSection(GO, getTargetMachine())) {
SDValue Small = DAG.getTargetGlobalAddress(
GV, DL, getPointerTy(DAG.getDataLayout()), Offset, LanaiII::MO_NO_FLAG);
return DAG.getNode(ISD::OR, DL, MVT::i32,
@@ -1232,6 +1250,55 @@ SDValue LanaiTargetLowering::LowerJumpTable(SDValue Op,
}
}
+SDValue LanaiTargetLowering::LowerSHL_PARTS(SDValue Op,
+ SelectionDAG &DAG) const {
+ EVT VT = Op.getValueType();
+ unsigned VTBits = VT.getSizeInBits();
+ SDLoc dl(Op);
+ assert(Op.getNumOperands() == 3 && "Unexpected SHL!");
+ SDValue ShOpLo = Op.getOperand(0);
+ SDValue ShOpHi = Op.getOperand(1);
+ SDValue ShAmt = Op.getOperand(2);
+
+ // Performs the following for (ShOpLo + (ShOpHi << 32)) << ShAmt:
+ // LoBitsForHi = (ShAmt == 0) ? 0 : (ShOpLo >> (32-ShAmt))
+ // HiBitsForHi = ShOpHi << ShAmt
+ // Hi = (ShAmt >= 32) ? (ShOpLo << (ShAmt-32)) : (LoBitsForHi | HiBitsForHi)
+ // Lo = (ShAmt >= 32) ? 0 : (ShOpLo << ShAmt)
+ // return (Hi << 32) | Lo;
+
+ SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32,
+ DAG.getConstant(VTBits, dl, MVT::i32), ShAmt);
+ SDValue LoBitsForHi = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, RevShAmt);
+
+ // If ShAmt == 0, we just calculated "(SRL ShOpLo, 32)" which is "undef". We
+ // wanted 0, so CSEL it directly.
+ SDValue Zero = DAG.getConstant(0, dl, MVT::i32);
+ SDValue SetCC = DAG.getSetCC(dl, MVT::i32, ShAmt, Zero, ISD::SETEQ);
+ LoBitsForHi = DAG.getSelect(dl, MVT::i32, SetCC, Zero, LoBitsForHi);
+
+ SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt,
+ DAG.getConstant(VTBits, dl, MVT::i32));
+ SDValue HiBitsForHi = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt);
+ SDValue HiForNormalShift =
+ DAG.getNode(ISD::OR, dl, VT, LoBitsForHi, HiBitsForHi);
+
+ SDValue HiForBigShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt);
+
+ SetCC = DAG.getSetCC(dl, MVT::i32, ExtraShAmt, Zero, ISD::SETGE);
+ SDValue Hi =
+ DAG.getSelect(dl, MVT::i32, SetCC, HiForBigShift, HiForNormalShift);
+
+ // Lanai shifts of larger than register sizes are wrapped rather than
+ // clamped, so we can't just emit "lo << b" if b is too big.
+ SDValue LoForNormalShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt);
+ SDValue Lo = DAG.getSelect(
+ dl, MVT::i32, SetCC, DAG.getConstant(0, dl, MVT::i32), LoForNormalShift);
+
+ SDValue Ops[2] = {Lo, Hi};
+ return DAG.getMergeValues(Ops, dl);
+}
+
SDValue LanaiTargetLowering::LowerSRL_PARTS(SDValue Op,
SelectionDAG &DAG) const {
MVT VT = Op.getSimpleValueType();
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.h b/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.h
index 16ce8ed..c2fba4f 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiISelLowering.h
@@ -88,6 +88,7 @@ public:
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSETCCE(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerSHL_PARTS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSRL_PARTS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp b/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp
index 673d23d..fcd5da8 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.cpp
@@ -558,7 +558,7 @@ LanaiInstrInfo::optimizeSelect(MachineInstr &MI,
// - FalseBlock is set to the destination if condition evaluates to false (it
// is the nullptr if the branch is unconditional);
// - condition is populated with machine operands needed to generate the branch
-// to insert in InsertBranch;
+// to insert in insertBranch;
// Returns: false if branch could successfully be analyzed.
bool LanaiInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TrueBlock,
@@ -641,10 +641,10 @@ bool LanaiInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-// ReverseBranchCondition - Reverses the branch condition of the specified
+// reverseBranchCondition - Reverses the branch condition of the specified
// condition list, returning false on success and true if it cannot be
// reversed.
-bool LanaiInstrInfo::ReverseBranchCondition(
+bool LanaiInstrInfo::reverseBranchCondition(
SmallVectorImpl<llvm::MachineOperand> &Condition) const {
assert((Condition.size() == 1) &&
"Lanai branch conditions should have one component.");
@@ -658,13 +658,15 @@ bool LanaiInstrInfo::ReverseBranchCondition(
// Insert the branch with condition specified in condition and given targets
// (TrueBlock and FalseBlock). This function returns the number of machine
// instructions inserted.
-unsigned LanaiInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned LanaiInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TrueBlock,
MachineBasicBlock *FalseBlock,
ArrayRef<MachineOperand> Condition,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TrueBlock && "InsertBranch must not be told to insert a fallthrough");
+ assert(TrueBlock && "insertBranch must not be told to insert a fallthrough");
+ assert(!BytesAdded && "code size not handled");
// If condition is empty then an unconditional branch is being inserted.
if (Condition.empty()) {
@@ -688,7 +690,10 @@ unsigned LanaiInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return 2;
}
-unsigned LanaiInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned LanaiInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator Instruction = MBB.end();
unsigned Count = 0;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.h b/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.h
index 51f6c6e..4387fe1 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.h
@@ -86,7 +86,8 @@ public:
SmallVectorImpl<MachineOperand> &Condition,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
// For a comparison instruction, return the source registers in SrcReg and
// SrcReg2 if having two register operands, and the value it compares against
@@ -129,13 +130,14 @@ public:
SmallPtrSetImpl<MachineInstr *> &SeenMIs,
bool PreferFalse) const override;
- bool ReverseBranchCondition(
+ bool reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Condition) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TrueBlock,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TrueBlock,
MachineBasicBlock *FalseBlock,
ArrayRef<MachineOperand> Condition,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
};
static inline bool isSPLSOpcode(unsigned Opcode) {
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.td b/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.td
index cd1abc1..285fca1 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.td
+++ b/contrib/llvm/lib/Target/Lanai/LanaiInstrInfo.td
@@ -115,9 +115,6 @@ def imm10 : Operand<i32>, PatLeaf<(imm), [{
let ParserMatchClass = Imm10AsmOperand;
}
-def immZExt21 : PatLeaf<(imm),
- [{return isUInt<21>(N->getZExtValue()); }], LO21>;
-
def LoImm16AsmOperand : AsmOperandClass { let Name = "LoImm16"; }
def i32lo16z : Operand<i32>, PatLeaf<(i32 imm), [{
// i32lo16 predicate - true if the 32-bit immediate has only rightmost 16
@@ -834,11 +831,6 @@ def TRAILZ : InstSpecial<0b011, (outs GPR:$Rd), (ins GPR:$Rs1),
// Non-Instruction Patterns
//===----------------------------------------------------------------------===//
-// i32 0 and R0 can be used interchangeably.
-def : Pat<(i32 0), (i32 R0)>;
-// i32 -1 and R1 can be used interchangeably.
-def : Pat<(i32 -1), (i32 R1)>;
-
// unsigned 16-bit immediate
def : Pat<(i32 i32lo16z:$imm), (OR_I_LO (i32 R0), imm:$imm)>;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.cpp b/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.cpp
index 6c809b4..39c6335 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.cpp
@@ -21,7 +21,6 @@
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/IR/Constants.h"
-#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.h b/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.h
index 41c0766..6d7818d 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiMCInstLower.h
@@ -31,8 +31,7 @@ class LLVM_LIBRARY_VISIBILITY LanaiMCInstLower {
AsmPrinter &Printer;
public:
- LanaiMCInstLower(MCContext &CTX, Mangler & /*Mang*/, AsmPrinter &AP)
- : Ctx(CTX), Printer(AP) {}
+ LanaiMCInstLower(MCContext &CTX, AsmPrinter &AP) : Ctx(CTX), Printer(AP) {}
void Lower(const MachineInstr *MI, MCInst &OutMI) const;
MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiMemAluCombiner.cpp b/contrib/llvm/lib/Target/Lanai/LanaiMemAluCombiner.cpp
index c5a4614..7259c02 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiMemAluCombiner.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiMemAluCombiner.cpp
@@ -61,7 +61,7 @@ public:
initializeLanaiMemAluCombinerPass(*PassRegistry::getPassRegistry());
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Lanai load / store optimization pass";
}
@@ -69,7 +69,7 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -339,6 +339,9 @@ MbbIterator LanaiMemAluCombiner::findClosestSuitableAluInstr(
while (First != Last) {
Decrement ? --First : ++First;
+ if (First == Last)
+ break;
+
// Skip over debug instructions
if (First->isDebugValue())
continue;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp b/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp
index a4c6122..12a2571 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.cpp
@@ -146,13 +146,13 @@ void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
MI.getOperand(FIOperandNum + 1).getImm();
// Addressable stack objects are addressed using neg. offsets from fp
// or pos. offsets from sp/basepointer
if (!HasFP || (needsStackRealignment(MF) && FrameIndex >= 0))
- Offset += MF.getFrameInfo()->getStackSize();
+ Offset += MF.getFrameInfo().getStackSize();
unsigned FrameReg = getFrameRegister(MF);
if (FrameIndex >= 0) {
@@ -246,10 +246,10 @@ void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
}
bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// When we need stack realignment and there are dynamic allocas, we can't
// reference off of the stack pointer, so we reserve a base pointer.
- if (needsStackRealignment(MF) && MFI->hasVarSizedObjects())
+ if (needsStackRealignment(MF) && MFI.hasVarSizedObjects())
return true;
return false;
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.h b/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.h
index 8b84bbc..c6e4590 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiRegisterInfo.h
@@ -21,9 +21,6 @@
namespace llvm {
-class TargetInstrInfo;
-class Type;
-
struct LanaiRegisterInfo : public LanaiGenRegisterInfo {
LanaiRegisterInfo();
@@ -32,7 +29,7 @@ struct LanaiRegisterInfo : public LanaiGenRegisterInfo {
// Code Generation virtual methods.
const uint16_t *
- getCalleeSavedRegs(const MachineFunction *MF = 0) const override;
+ getCalleeSavedRegs(const MachineFunction *MF = nullptr) const override;
BitVector getReservedRegs(const MachineFunction &MF) const override;
@@ -42,7 +39,7 @@ struct LanaiRegisterInfo : public LanaiGenRegisterInfo {
void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj,
unsigned FIOperandNum,
- RegScavenger *RS = NULL) const override;
+ RegScavenger *RS = nullptr) const override;
bool canRealignStack(const MachineFunction &MF) const override;
@@ -58,6 +55,6 @@ struct LanaiRegisterInfo : public LanaiGenRegisterInfo {
int getDwarfRegNum(unsigned RegNum, bool IsEH) const;
};
-} // namespace llvm
+} // end namespace llvm
#endif // LLVM_LIB_TARGET_LANAI_LANAIREGISTERINFO_H
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp b/contrib/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp
index b1f4b49..2a9bc25 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiTargetMachine.cpp
@@ -32,7 +32,8 @@ void initializeLanaiMemAluCombinerPass(PassRegistry &);
extern "C" void LLVMInitializeLanaiTarget() {
// Register the target.
- RegisterTargetMachine<LanaiTargetMachine> registered_target(TheLanaiTarget);
+ RegisterTargetMachine<LanaiTargetMachine> registered_target(
+ getTheLanaiTarget());
}
static std::string computeDataLayout() {
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp b/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp
index 4048c85..7475dbd 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.cpp
@@ -49,22 +49,25 @@ static bool isInSmallSection(uint64_t Size) {
// Return true if this global address should be placed into small data/bss
// section.
bool LanaiTargetObjectFile::isGlobalInSmallSection(
- const GlobalValue *GV, const TargetMachine &TM) const {
+ const GlobalObject *GO, const TargetMachine &TM) const {
+ if (GO == nullptr)
+ return false;
+
// We first check the case where global is a declaration, because finding
// section kind using getKindForGlobal() is only allowed for global
// definitions.
- if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
- return isGlobalInSmallSectionImpl(GV, TM);
+ if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage())
+ return isGlobalInSmallSectionImpl(GO, TM);
- return isGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM));
+ return isGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM));
}
// Return true if this global address should be placed into small data/bss
// section.
-bool LanaiTargetObjectFile::isGlobalInSmallSection(const GlobalValue *GV,
+bool LanaiTargetObjectFile::isGlobalInSmallSection(const GlobalObject *GO,
const TargetMachine &TM,
SectionKind Kind) const {
- return (isGlobalInSmallSectionImpl(GV, TM) &&
+ return (isGlobalInSmallSectionImpl(GO, TM) &&
(Kind.isData() || Kind.isBSS() || Kind.isCommon()));
}
@@ -72,37 +75,43 @@ bool LanaiTargetObjectFile::isGlobalInSmallSection(const GlobalValue *GV,
// section. This method does all the work, except for checking the section
// kind.
bool LanaiTargetObjectFile::isGlobalInSmallSectionImpl(
- const GlobalValue *GV, const TargetMachine & /*TM*/) const {
+ const GlobalObject *GO, const TargetMachine &TM) const {
// Only global variables, not functions.
- const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV);
+ const auto *GVA = dyn_cast<GlobalVariable>(GO);
if (!GVA)
return false;
- if (GV->hasLocalLinkage())
+ // Global values placed in sections starting with .ldata do not fit in
+ // 21-bits, so always use large memory access for them. FIXME: This is a
+ // workaround for a tool limitation.
+ if (GVA->getSection().startswith(".ldata"))
+ return false;
+
+ if (TM.getCodeModel() == CodeModel::Small)
+ return true;
+
+ if (GVA->hasLocalLinkage())
return false;
- if (((GV->hasExternalLinkage() && GV->isDeclaration()) ||
- GV->hasCommonLinkage()))
+ if (((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||
+ GVA->hasCommonLinkage()))
return false;
- Type *Ty = GV->getType()->getElementType();
+ Type *Ty = GVA->getValueType();
return isInSmallSection(
- GV->getParent()->getDataLayout().getTypeAllocSize(Ty));
+ GVA->getParent()->getDataLayout().getTypeAllocSize(Ty));
}
-MCSection *
-LanaiTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
+MCSection *LanaiTargetObjectFile::SelectSectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
// Handle Small Section classification here.
- if (Kind.isBSS() && isGlobalInSmallSection(GV, TM, Kind))
+ if (Kind.isBSS() && isGlobalInSmallSection(GO, TM, Kind))
return SmallBSSSection;
- if (Kind.isData() && isGlobalInSmallSection(GV, TM, Kind))
+ if (Kind.isData() && isGlobalInSmallSection(GO, TM, Kind))
return SmallDataSection;
// Otherwise, we work the same as ELF.
- return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,
- TM);
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
}
/// Return true if this constant should be placed into small data section.
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h b/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h
index eb51954..99ec195 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiTargetObjectFile.h
@@ -18,20 +18,20 @@ class LanaiTargetObjectFile : public TargetLoweringObjectFileELF {
MCSection *SmallDataSection;
MCSection *SmallBSSSection;
+ bool isGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM,
+ SectionKind Kind) const;
+ bool isGlobalInSmallSectionImpl(const GlobalObject *GO,
+ const TargetMachine &TM) const;
+
public:
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
/// Return true if this global address should be placed into small data/bss
/// section.
- bool isGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
- SectionKind Kind) const;
- bool isGlobalInSmallSection(const GlobalValue *GV,
+ bool isGlobalInSmallSection(const GlobalObject *GO,
const TargetMachine &TM) const;
- bool isGlobalInSmallSectionImpl(const GlobalValue *GV,
- const TargetMachine &TM) const;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
/// Return true if this constant should be placed into small data section.
diff --git a/contrib/llvm/lib/Target/Lanai/LanaiTargetTransformInfo.h b/contrib/llvm/lib/Target/Lanai/LanaiTargetTransformInfo.h
index 6300d25..d95c16f 100644
--- a/contrib/llvm/lib/Target/Lanai/LanaiTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/Lanai/LanaiTargetTransformInfo.h
@@ -41,11 +41,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- LanaiTTIImpl(const LanaiTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- LanaiTTIImpl(LanaiTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(Arg.ST), TLI(Arg.TLI) {}
-
bool shouldBuildLookupTables() const { return false; }
TargetTransformInfo::PopcntSupportKind getPopcntSupport(unsigned TyWidth) {
@@ -59,7 +54,8 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None) {
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>()) {
int ISD = TLI->InstructionOpcodeToISD(Opcode);
switch (ISD) {
diff --git a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp
index a3d8699..a04fe81 100644
--- a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp
@@ -163,10 +163,10 @@ LanaiAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
MCAsmBackend *llvm::createLanaiAsmBackend(const Target &T,
const MCRegisterInfo & /*MRI*/,
- const Triple &TheTriple,
- StringRef /*CPU*/) {
- if (!TheTriple.isOSBinFormatELF())
+ const Triple &TT, StringRef /*CPU*/,
+ const MCTargetOptions & /*Options*/) {
+ if (!TT.isOSBinFormatELF())
llvm_unreachable("OS not supported");
- return new LanaiAsmBackend(T, TheTriple.getOS());
+ return new LanaiAsmBackend(T, TT.getOS());
}
diff --git a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
index e30d5e9..e02bba5 100644
--- a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
@@ -9,20 +9,19 @@
#include "MCTargetDesc/LanaiBaseInfo.h"
#include "MCTargetDesc/LanaiFixupKinds.h"
-#include "MCTargetDesc/LanaiMCTargetDesc.h"
#include "llvm/MC/MCELFObjectWriter.h"
-#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
+
class LanaiELFObjectWriter : public MCELFObjectTargetWriter {
public:
explicit LanaiELFObjectWriter(uint8_t OSABI);
- ~LanaiELFObjectWriter() override;
+ ~LanaiELFObjectWriter() override = default;
protected:
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
@@ -30,14 +29,13 @@ protected:
bool needsRelocateWithSymbol(const MCSymbol &SD,
unsigned Type) const override;
};
-} // namespace
+
+} // end anonymous namespace
LanaiELFObjectWriter::LanaiELFObjectWriter(uint8_t OSABI)
: MCELFObjectTargetWriter(/*Is64Bit_=*/false, OSABI, ELF::EM_LANAI,
/*HasRelocationAddend=*/true) {}
-LanaiELFObjectWriter::~LanaiELFObjectWriter() {}
-
unsigned LanaiELFObjectWriter::getRelocType(MCContext & /*Ctx*/,
const MCValue & /*Target*/,
const MCFixup &Fixup,
diff --git a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp
index f14adc2..f5b5335 100644
--- a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp
@@ -12,37 +12,38 @@
//===----------------------------------------------------------------------===//
#include "Lanai.h"
+#include "LanaiAluCode.h"
#include "MCTargetDesc/LanaiBaseInfo.h"
#include "MCTargetDesc/LanaiFixupKinds.h"
#include "MCTargetDesc/LanaiMCExpr.h"
-#include "MCTargetDesc/LanaiMCTargetDesc.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
#define DEBUG_TYPE "mccodeemitter"
STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
namespace llvm {
+
namespace {
-class LanaiMCCodeEmitter : public MCCodeEmitter {
- LanaiMCCodeEmitter(const LanaiMCCodeEmitter &); // DO NOT IMPLEMENT
- void operator=(const LanaiMCCodeEmitter &); // DO NOT IMPLEMENT
- const MCInstrInfo &InstrInfo;
- MCContext &Context;
+class LanaiMCCodeEmitter : public MCCodeEmitter {
public:
- LanaiMCCodeEmitter(const MCInstrInfo &MCII, MCContext &C)
- : InstrInfo(MCII), Context(C) {}
-
- ~LanaiMCCodeEmitter() override {}
+ LanaiMCCodeEmitter(const MCInstrInfo &MCII, MCContext &C) {}
+ LanaiMCCodeEmitter(const LanaiMCCodeEmitter &) = delete;
+ void operator=(const LanaiMCCodeEmitter &) = delete;
+ ~LanaiMCCodeEmitter() override = default;
// The functions below are called by TableGen generated functions for getting
// the binary encoding of instructions/opereands.
@@ -75,10 +76,6 @@ public:
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &SubtargetInfo) const;
- unsigned getCallTargetOpValue(const MCInst &Inst, unsigned OpNo,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &SubtargetInfo) const;
-
void encodeInstruction(const MCInst &Inst, raw_ostream &Ostream,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &SubtargetInfo) const override;
@@ -90,6 +87,8 @@ public:
const MCSubtargetInfo &STI) const;
};
+} // end anonymous namespace
+
Lanai::Fixups FixupKind(const MCExpr *Expr) {
if (isa<MCSymbolRefExpr>(Expr))
return Lanai::FIXUP_LANAI_21;
@@ -288,19 +287,6 @@ LanaiMCCodeEmitter::getSplsOpValue(const MCInst &Inst, unsigned OpNo,
return Encoding;
}
-unsigned LanaiMCCodeEmitter::getCallTargetOpValue(
- const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &SubtargetInfo) const {
- const MCOperand &MCOp = Inst.getOperand(OpNo);
- if (MCOp.isReg() || MCOp.isImm())
- return getMachineOpValue(Inst, MCOp, Fixups, SubtargetInfo);
-
- Fixups.push_back(MCFixup::create(
- 0, MCOp.getExpr(), static_cast<MCFixupKind>(Lanai::FIXUP_LANAI_25)));
-
- return 0;
-}
-
unsigned LanaiMCCodeEmitter::getBranchTargetOpValue(
const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &SubtargetInfo) const {
@@ -315,8 +301,8 @@ unsigned LanaiMCCodeEmitter::getBranchTargetOpValue(
}
#include "LanaiGenMCCodeEmitter.inc"
-} // namespace
-} // namespace llvm
+
+} // end namespace llvm
llvm::MCCodeEmitter *
llvm::createLanaiMCCodeEmitter(const MCInstrInfo &InstrInfo,
diff --git a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp
index 04bedfb7..a47ff9f 100644
--- a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp
@@ -11,16 +11,21 @@
//
//===----------------------------------------------------------------------===//
+#include "LanaiMCAsmInfo.h"
#include "LanaiMCTargetDesc.h"
-
#include "InstPrinter/LanaiInstPrinter.h"
-#include "LanaiMCAsmInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
+#include <cstdint>
+#include <string>
#define GET_INSTRINFO_MC_DESC
#include "LanaiGenInstrInfo.inc"
@@ -70,14 +75,16 @@ static MCInstPrinter *createLanaiMCInstPrinter(const Triple & /*T*/,
const MCRegisterInfo &MRI) {
if (SyntaxVariant == 0)
return new LanaiInstPrinter(MAI, MII, MRI);
- return 0;
+ return nullptr;
}
-MCRelocationInfo *createLanaiElfRelocation(const Triple &TheTriple,
- MCContext &Ctx) {
+static MCRelocationInfo *createLanaiElfRelocation(const Triple &TheTriple,
+ MCContext &Ctx) {
return createMCRelocationInfo(TheTriple, Ctx);
}
+namespace {
+
class LanaiMCInstrAnalysis : public MCInstrAnalysis {
public:
explicit LanaiMCInstrAnalysis(const MCInstrInfo *Info)
@@ -107,43 +114,48 @@ public:
}
};
+} // end anonymous namespace
+
static MCInstrAnalysis *createLanaiInstrAnalysis(const MCInstrInfo *Info) {
return new LanaiMCInstrAnalysis(Info);
}
extern "C" void LLVMInitializeLanaiTargetMC() {
// Register the MC asm info.
- RegisterMCAsmInfo<LanaiMCAsmInfo> X(TheLanaiTarget);
+ RegisterMCAsmInfo<LanaiMCAsmInfo> X(getTheLanaiTarget());
// Register the MC instruction info.
- TargetRegistry::RegisterMCInstrInfo(TheLanaiTarget, createLanaiMCInstrInfo);
+ TargetRegistry::RegisterMCInstrInfo(getTheLanaiTarget(),
+ createLanaiMCInstrInfo);
// Register the MC register info.
- TargetRegistry::RegisterMCRegInfo(TheLanaiTarget, createLanaiMCRegisterInfo);
+ TargetRegistry::RegisterMCRegInfo(getTheLanaiTarget(),
+ createLanaiMCRegisterInfo);
// Register the MC subtarget info.
- TargetRegistry::RegisterMCSubtargetInfo(TheLanaiTarget,
+ TargetRegistry::RegisterMCSubtargetInfo(getTheLanaiTarget(),
createLanaiMCSubtargetInfo);
// Register the MC code emitter
- TargetRegistry::RegisterMCCodeEmitter(TheLanaiTarget,
- llvm::createLanaiMCCodeEmitter);
+ TargetRegistry::RegisterMCCodeEmitter(getTheLanaiTarget(),
+ createLanaiMCCodeEmitter);
// Register the ASM Backend
- TargetRegistry::RegisterMCAsmBackend(TheLanaiTarget, createLanaiAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(getTheLanaiTarget(),
+ createLanaiAsmBackend);
// Register the MCInstPrinter.
- TargetRegistry::RegisterMCInstPrinter(TheLanaiTarget,
+ TargetRegistry::RegisterMCInstPrinter(getTheLanaiTarget(),
createLanaiMCInstPrinter);
// Register the ELF streamer.
- TargetRegistry::RegisterELFStreamer(TheLanaiTarget, createMCStreamer);
+ TargetRegistry::RegisterELFStreamer(getTheLanaiTarget(), createMCStreamer);
// Register the MC relocation info.
- TargetRegistry::RegisterMCRelocationInfo(TheLanaiTarget,
+ TargetRegistry::RegisterMCRelocationInfo(getTheLanaiTarget(),
createLanaiElfRelocation);
// Register the MC instruction analyzer.
- TargetRegistry::RegisterMCInstrAnalysis(TheLanaiTarget,
+ TargetRegistry::RegisterMCInstrAnalysis(getTheLanaiTarget(),
createLanaiInstrAnalysis);
}
diff --git a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h
index e117ed7..8adaf4c 100644
--- a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h
@@ -15,6 +15,7 @@
#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCTARGETDESC_H
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Support/DataTypes.h"
namespace llvm {
@@ -31,14 +32,15 @@ class Triple;
class StringRef;
class raw_pwrite_stream;
-extern Target TheLanaiTarget;
+Target &getTheLanaiTarget();
MCCodeEmitter *createLanaiMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx);
MCAsmBackend *createLanaiAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TheTriple, StringRef CPU);
+ const Triple &TheTriple, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createLanaiELFObjectWriter(raw_pwrite_stream &OS,
uint8_t OSABI);
diff --git a/contrib/llvm/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp b/contrib/llvm/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp
index bd615d6..e377db1 100644
--- a/contrib/llvm/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp
@@ -13,8 +13,13 @@
using namespace llvm;
-Target llvm::TheLanaiTarget;
+namespace llvm {
+Target &getTheLanaiTarget() {
+ static Target TheLanaiTarget;
+ return TheLanaiTarget;
+}
+} // namespace llvm
extern "C" void LLVMInitializeLanaiTargetInfo() {
- RegisterTarget<Triple::lanai> X(TheLanaiTarget, "lanai", "Lanai");
+ RegisterTarget<Triple::lanai> X(getTheLanaiTarget(), "lanai", "Lanai");
}
diff --git a/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.cpp b/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.cpp
index b3631ca..8c71550 100644
--- a/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.cpp
@@ -59,20 +59,21 @@ static MCInstPrinter *createMSP430MCInstPrinter(const Triple &T,
extern "C" void LLVMInitializeMSP430TargetMC() {
// Register the MC asm info.
- RegisterMCAsmInfo<MSP430MCAsmInfo> X(TheMSP430Target);
+ RegisterMCAsmInfo<MSP430MCAsmInfo> X(getTheMSP430Target());
// Register the MC instruction info.
- TargetRegistry::RegisterMCInstrInfo(TheMSP430Target, createMSP430MCInstrInfo);
+ TargetRegistry::RegisterMCInstrInfo(getTheMSP430Target(),
+ createMSP430MCInstrInfo);
// Register the MC register info.
- TargetRegistry::RegisterMCRegInfo(TheMSP430Target,
+ TargetRegistry::RegisterMCRegInfo(getTheMSP430Target(),
createMSP430MCRegisterInfo);
// Register the MC subtarget info.
- TargetRegistry::RegisterMCSubtargetInfo(TheMSP430Target,
+ TargetRegistry::RegisterMCSubtargetInfo(getTheMSP430Target(),
createMSP430MCSubtargetInfo);
// Register the MCInstPrinter.
- TargetRegistry::RegisterMCInstPrinter(TheMSP430Target,
+ TargetRegistry::RegisterMCInstPrinter(getTheMSP430Target(),
createMSP430MCInstPrinter);
}
diff --git a/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.h b/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.h
index 241f1d6..b901c5f 100644
--- a/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.h
+++ b/contrib/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCTargetDesc.h
@@ -19,7 +19,7 @@
namespace llvm {
class Target;
-extern Target TheMSP430Target;
+Target &getTheMSP430Target();
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430AsmPrinter.cpp b/contrib/llvm/lib/Target/MSP430/MSP430AsmPrinter.cpp
index 4342c10a..abf062f 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430AsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430AsmPrinter.cpp
@@ -42,9 +42,7 @@ namespace {
MSP430AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)) {}
- const char *getPassName() const override {
- return "MSP430 Assembly Printer";
- }
+ StringRef getPassName() const override { return "MSP430 Assembly Printer"; }
void printOperand(const MachineInstr *MI, int OpNum,
raw_ostream &O, const char* Modifier = nullptr);
@@ -157,5 +155,5 @@ void MSP430AsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Force static initialization.
extern "C" void LLVMInitializeMSP430AsmPrinter() {
- RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target);
+ RegisterAsmPrinter<MSP430AsmPrinter> X(getTheMSP430Target());
}
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp b/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp
index 511e5bc..5fd6b63 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp
@@ -27,63 +27,84 @@ using namespace llvm;
#define DEBUG_TYPE "msp430-branch-select"
+static cl::opt<bool>
+ BranchSelectEnabled("msp430-branch-select", cl::Hidden, cl::init(true),
+ cl::desc("Expand out of range branches"));
+
+STATISTIC(NumSplit, "Number of machine basic blocks split");
STATISTIC(NumExpanded, "Number of branches expanded to long format");
namespace {
- struct MSP430BSel : public MachineFunctionPass {
- static char ID;
- MSP430BSel() : MachineFunctionPass(ID) {}
+class MSP430BSel : public MachineFunctionPass {
- /// BlockSizes - The sizes of the basic blocks in the function.
- std::vector<unsigned> BlockSizes;
+ typedef SmallVector<int, 16> OffsetVector;
- bool runOnMachineFunction(MachineFunction &Fn) override;
+ MachineFunction *MF;
+ const MSP430InstrInfo *TII;
- MachineFunctionProperties getRequiredProperties() const override {
- return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
- }
+ unsigned measureFunction(OffsetVector &BlockOffsets,
+ MachineBasicBlock *FromBB = nullptr);
+ bool expandBranches(OffsetVector &BlockOffsets);
- const char *getPassName() const override {
- return "MSP430 Branch Selector";
- }
- };
- char MSP430BSel::ID = 0;
+public:
+ static char ID;
+ MSP430BSel() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ MachineFunctionProperties getRequiredProperties() const override {
+ return MachineFunctionProperties().set(
+ MachineFunctionProperties::Property::NoVRegs);
+ }
+
+ StringRef getPassName() const override { return "MSP430 Branch Selector"; }
+};
+char MSP430BSel::ID = 0;
}
-/// createMSP430BranchSelectionPass - returns an instance of the Branch
-/// Selection Pass
-///
-FunctionPass *llvm::createMSP430BranchSelectionPass() {
- return new MSP430BSel();
+static bool isInRage(int DistanceInBytes) {
+ // According to CC430 Family User's Guide, Section 4.5.1.3, branch
+ // instructions have the signed 10-bit word offset field, so first we need to
+ // convert the distance from bytes to words, then check if it fits in 10-bit
+ // signed integer.
+ const int WordSize = 2;
+
+ assert((DistanceInBytes % WordSize == 0) &&
+ "Branch offset should be word aligned!");
+
+ int Words = DistanceInBytes / WordSize;
+ return isInt<10>(Words);
}
-bool MSP430BSel::runOnMachineFunction(MachineFunction &Fn) {
- const MSP430InstrInfo *TII =
- static_cast<const MSP430InstrInfo *>(Fn.getSubtarget().getInstrInfo());
+/// Measure each basic block, fill the BlockOffsets, and return the size of
+/// the function, starting with BB
+unsigned MSP430BSel::measureFunction(OffsetVector &BlockOffsets,
+ MachineBasicBlock *FromBB) {
// Give the blocks of the function a dense, in-order, numbering.
- Fn.RenumberBlocks();
- BlockSizes.resize(Fn.getNumBlockIDs());
-
- // Measure each MBB and compute a size for the entire function.
- unsigned FuncSize = 0;
- for (MachineBasicBlock &MBB : Fn) {
- unsigned BlockSize = 0;
- for (MachineInstr &MI : MBB)
- BlockSize += TII->GetInstSizeInBytes(MI);
-
- BlockSizes[MBB.getNumber()] = BlockSize;
- FuncSize += BlockSize;
+ MF->RenumberBlocks(FromBB);
+
+ MachineFunction::iterator Begin;
+ if (FromBB == nullptr) {
+ Begin = MF->begin();
+ } else {
+ Begin = FromBB->getIterator();
}
- // If the entire function is smaller than the displacement of a branch field,
- // we know we don't need to shrink any branches in this function. This is a
- // common case.
- if (FuncSize < (1 << 9)) {
- BlockSizes.clear();
- return false;
+ BlockOffsets.resize(MF->getNumBlockIDs());
+
+ unsigned TotalSize = BlockOffsets[Begin->getNumber()];
+ for (auto &MBB : make_range(Begin, MF->end())) {
+ BlockOffsets[MBB.getNumber()] = TotalSize;
+ for (MachineInstr &MI : MBB) {
+ TotalSize += TII->getInstSizeInBytes(MI);
+ }
}
+ return TotalSize;
+}
+/// Do expand branches and split the basic blocks if necessary.
+/// Returns true if made any change.
+bool MSP430BSel::expandBranches(OffsetVector &BlockOffsets) {
// For each conditional branch, if the offset to its destination is larger
// than the offset field allows, transform it into a long branch sequence
// like this:
@@ -93,91 +114,144 @@ bool MSP430BSel::runOnMachineFunction(MachineFunction &Fn) {
// b!CC $PC+6
// b MBB
//
- bool MadeChange = true;
- bool EverMadeChange = false;
- while (MadeChange) {
- // Iteratively expand branches until we reach a fixed point.
- MadeChange = false;
-
- for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
- ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- unsigned MBBStartOffset = 0;
- for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
- I != E; ++I) {
- if ((I->getOpcode() != MSP430::JCC || I->getOperand(0).isImm()) &&
- I->getOpcode() != MSP430::JMP) {
- MBBStartOffset += TII->GetInstSizeInBytes(*I);
- continue;
- }
+ bool MadeChange = false;
+ for (auto MBB = MF->begin(), E = MF->end(); MBB != E; ++MBB) {
+ unsigned MBBStartOffset = 0;
+ for (auto MI = MBB->begin(), EE = MBB->end(); MI != EE; ++MI) {
+ MBBStartOffset += TII->getInstSizeInBytes(*MI);
- // Determine the offset from the current branch to the destination
- // block.
- MachineBasicBlock *Dest = I->getOperand(0).getMBB();
-
- int BranchSize;
- if (Dest->getNumber() <= MBB.getNumber()) {
- // If this is a backwards branch, the delta is the offset from the
- // start of this block to this branch, plus the sizes of all blocks
- // from this block to the dest.
- BranchSize = MBBStartOffset;
-
- for (unsigned i = Dest->getNumber(), e = MBB.getNumber(); i != e; ++i)
- BranchSize += BlockSizes[i];
- } else {
- // Otherwise, add the size of the blocks between this block and the
- // dest to the number of bytes left in this block.
- BranchSize = -MBBStartOffset;
-
- for (unsigned i = MBB.getNumber(), e = Dest->getNumber(); i != e; ++i)
- BranchSize += BlockSizes[i];
- }
+ // If this instruction is not a short branch then skip it.
+ if (MI->getOpcode() != MSP430::JCC && MI->getOpcode() != MSP430::JMP) {
+ continue;
+ }
- // If this branch is in range, ignore it.
- if (isInt<10>(BranchSize)) {
- MBBStartOffset += 2;
- continue;
- }
+ MachineBasicBlock *DestBB = MI->getOperand(0).getMBB();
+ // Determine the distance from the current branch to the destination
+ // block. MBBStartOffset already includes the size of the current branch
+ // instruction.
+ int BlockDistance =
+ BlockOffsets[DestBB->getNumber()] - BlockOffsets[MBB->getNumber()];
+ int BranchDistance = BlockDistance - MBBStartOffset;
+
+ // If this branch is in range, ignore it.
+ if (isInRage(BranchDistance)) {
+ continue;
+ }
+
+ DEBUG(dbgs() << " Found a branch that needs expanding, BB#"
+ << DestBB->getNumber() << ", Distance " << BranchDistance
+ << "\n");
+
+ // If JCC is not the last instruction we need to split the MBB.
+ if (MI->getOpcode() == MSP430::JCC && std::next(MI) != EE) {
+
+ DEBUG(dbgs() << " Found a basic block that needs to be split, BB#"
+ << MBB->getNumber() << "\n");
+
+ // Create a new basic block.
+ MachineBasicBlock *NewBB =
+ MF->CreateMachineBasicBlock(MBB->getBasicBlock());
+ MF->insert(std::next(MBB), NewBB);
- // Otherwise, we have to expand it to a long branch.
- unsigned NewSize;
- MachineInstr &OldBranch = *I;
- DebugLoc dl = OldBranch.getDebugLoc();
-
- if (I->getOpcode() == MSP430::JMP) {
- NewSize = 4;
- } else {
- // The BCC operands are:
- // 0. MSP430 branch predicate
- // 1. Target MBB
- SmallVector<MachineOperand, 1> Cond;
- Cond.push_back(I->getOperand(1));
-
- // Jump over the uncond branch inst (i.e. $+6) on opposite condition.
- TII->ReverseBranchCondition(Cond);
- BuildMI(MBB, I, dl, TII->get(MSP430::JCC))
- .addImm(4).addOperand(Cond[0]);
-
- NewSize = 6;
+ // Splice the instructions following MI over to the NewBB.
+ NewBB->splice(NewBB->end(), &*MBB, std::next(MI), MBB->end());
+
+ // Update the successor lists.
+ for (MachineBasicBlock *Succ : MBB->successors()) {
+ if (Succ == DestBB) {
+ continue;
+ }
+ MBB->replaceSuccessor(Succ, NewBB);
+ NewBB->addSuccessor(Succ);
}
- // Uncond branch to the real destination.
- I = BuildMI(MBB, I, dl, TII->get(MSP430::Bi)).addMBB(Dest);
- // Remove the old branch from the function.
- OldBranch.eraseFromParent();
+ // We introduced a new MBB so all following blocks should be numbered
+ // and measured again.
+ measureFunction(BlockOffsets, &*MBB);
- // Remember that this instruction is NewSize bytes, increase the size of the
- // block by NewSize-2, remember to iterate.
- BlockSizes[MBB.getNumber()] += NewSize-2;
- MBBStartOffset += NewSize;
+ ++NumSplit;
- ++NumExpanded;
- MadeChange = true;
+ // It may be not necessary to start all over at this point, but it's
+ // safer do this anyway.
+ return true;
}
+
+ MachineInstr &OldBranch = *MI;
+ DebugLoc dl = OldBranch.getDebugLoc();
+ int InstrSizeDiff = -TII->getInstSizeInBytes(OldBranch);
+
+ if (MI->getOpcode() == MSP430::JCC) {
+ MachineBasicBlock *NextMBB = &*std::next(MBB);
+ assert(MBB->isSuccessor(NextMBB) &&
+ "This block must have a layout successor!");
+
+ // The BCC operands are:
+ // 0. Target MBB
+ // 1. MSP430 branch predicate
+ SmallVector<MachineOperand, 1> Cond;
+ Cond.push_back(MI->getOperand(1));
+
+ // Jump over the long branch on the opposite condition
+ TII->reverseBranchCondition(Cond);
+ MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::JCC))
+ .addMBB(NextMBB)
+ .addOperand(Cond[0]);
+ InstrSizeDiff += TII->getInstSizeInBytes(*MI);
+ ++MI;
+ }
+
+ // Unconditional branch to the real destination.
+ MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::Bi)).addMBB(DestBB);
+ InstrSizeDiff += TII->getInstSizeInBytes(*MI);
+
+ // Remove the old branch from the function.
+ OldBranch.eraseFromParent();
+
+ // The size of a new instruction is different from the old one, so we need
+ // to correct all block offsets.
+ for (int i = MBB->getNumber() + 1, e = BlockOffsets.size(); i < e; ++i) {
+ BlockOffsets[i] += InstrSizeDiff;
+ }
+ MBBStartOffset += InstrSizeDiff;
+
+ ++NumExpanded;
+ MadeChange = true;
}
- EverMadeChange |= MadeChange;
}
+ return MadeChange;
+}
+
+bool MSP430BSel::runOnMachineFunction(MachineFunction &mf) {
+ MF = &mf;
+ TII = static_cast<const MSP430InstrInfo *>(MF->getSubtarget().getInstrInfo());
+
+ // If the pass is disabled, just bail early.
+ if (!BranchSelectEnabled)
+ return false;
+
+ DEBUG(dbgs() << "\n********** " << getPassName() << " **********\n");
+
+ // BlockOffsets - Contains the distance from the beginning of the function to
+ // the beginning of each basic block.
+ OffsetVector BlockOffsets;
+
+ unsigned FunctionSize = measureFunction(BlockOffsets);
+ // If the entire function is smaller than the displacement of a branch field,
+ // we know we don't need to expand any branches in this
+ // function. This is a common case.
+ if (isInRage(FunctionSize)) {
+ return false;
+ }
+
+ // Iteratively expand branches until we reach a fixed point.
+ bool MadeChange = false;
+ while (expandBranches(BlockOffsets))
+ MadeChange = true;
+
+ return MadeChange;
+}
- BlockSizes.clear();
- return true;
+/// Returns an instance of the Branch Selection Pass
+FunctionPass *llvm::createMSP430BranchSelectionPass() {
+ return new MSP430BSel();
}
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp b/contrib/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
index 29555f9..f1cb0b6 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
@@ -27,21 +27,21 @@
using namespace llvm;
bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
- MF.getFrameInfo()->hasVarSizedObjects() ||
- MFI->isFrameAddressTaken());
+ MF.getFrameInfo().hasVarSizedObjects() ||
+ MFI.isFrameAddressTaken());
}
bool MSP430FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- return !MF.getFrameInfo()->hasVarSizedObjects();
+ return !MF.getFrameInfo().hasVarSizedObjects();
}
void MSP430FrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>();
const MSP430InstrInfo &TII =
*static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo());
@@ -50,7 +50,7 @@ void MSP430FrameLowering::emitPrologue(MachineFunction &MF,
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
// Get the number of bytes to allocate from the FrameInfo.
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
uint64_t NumBytes = 0;
if (hasFP(MF)) {
@@ -61,7 +61,7 @@ void MSP430FrameLowering::emitPrologue(MachineFunction &MF,
// Get the offset of the stack slot for the EBP register... which is
// guaranteed to be the last slot by processFunctionBeforeFrameFinalized.
// Update the frame offset adjustment.
- MFI->setOffsetAdjustment(-NumBytes);
+ MFI.setOffsetAdjustment(-NumBytes);
// Save FP into the appropriate stack slot...
BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r))
@@ -106,7 +106,7 @@ void MSP430FrameLowering::emitPrologue(MachineFunction &MF,
void MSP430FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>();
const MSP430InstrInfo &TII =
*static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo());
@@ -123,7 +123,7 @@ void MSP430FrameLowering::emitEpilogue(MachineFunction &MF,
}
// Get the number of bytes to allocate from the FrameInfo
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
unsigned CSSize = MSP430FI->getCalleeSavedFrameSize();
uint64_t NumBytes = 0;
@@ -150,10 +150,10 @@ void MSP430FrameLowering::emitEpilogue(MachineFunction &MF,
// If there is an ADD16ri or SUB16ri of SP immediately before this
// instruction, merge the two instructions.
- //if (NumBytes || MFI->hasVarSizedObjects())
+ //if (NumBytes || MFI.hasVarSizedObjects())
// mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes);
- if (MFI->hasVarSizedObjects()) {
+ if (MFI.hasVarSizedObjects()) {
BuildMI(MBB, MBBI, DL,
TII.get(MSP430::MOV16rr), MSP430::SP).addReg(MSP430::FP);
if (CSSize) {
@@ -293,9 +293,9 @@ MSP430FrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *) const {
// Create a frame entry for the FP register that must be saved.
if (hasFP(MF)) {
- int FrameIdx = MF.getFrameInfo()->CreateFixedObject(2, -4, true);
+ int FrameIdx = MF.getFrameInfo().CreateFixedObject(2, -4, true);
(void)FrameIdx;
- assert(FrameIdx == MF.getFrameInfo()->getObjectIndexBegin() &&
+ assert(FrameIdx == MF.getFrameInfo().getObjectIndexBegin() &&
"Slot for FP register must be last in order to be found!");
}
}
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp
index 69c609d..6e481b6 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp
@@ -95,7 +95,7 @@ namespace {
MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOpt::Level OptLevel)
: SelectionDAGISel(TM, OptLevel) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "MSP430 DAG->DAG Pattern Instruction Selection";
}
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
index cb2c620..73346b9 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
@@ -54,8 +54,7 @@ HWMultMode("msp430-hwmult-mode", cl::Hidden,
clEnumValN(HWMultIntr, "interrupts",
"Assume hardware multiplier can be used inside interrupts"),
clEnumValN(HWMultNoIntr, "use",
- "Assume hardware multiplier cannot be used inside interrupts"),
- clEnumValEnd));
+ "Assume hardware multiplier cannot be used inside interrupts")));
MSP430TargetLowering::MSP430TargetLowering(const TargetMachine &TM,
const MSP430Subtarget &STI)
@@ -413,7 +412,7 @@ SDValue MSP430TargetLowering::LowerCCCArguments(
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
MSP430MachineFunctionInfo *FuncInfo = MF.getInfo<MSP430MachineFunctionInfo>();
@@ -426,7 +425,7 @@ SDValue MSP430TargetLowering::LowerCCCArguments(
// Create frame index for the start of the first vararg value
if (isVarArg) {
unsigned Offset = CCInfo.getNextStackOffset();
- FuncInfo->setVarArgsFrameIndex(MFI->CreateFixedObject(1, Offset, true));
+ FuncInfo->setVarArgsFrameIndex(MFI.CreateFixedObject(1, Offset, true));
}
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
@@ -471,8 +470,8 @@ SDValue MSP430TargetLowering::LowerCCCArguments(
ISD::ArgFlagsTy Flags = Ins[i].Flags;
if (Flags.isByVal()) {
- int FI = MFI->CreateFixedObject(Flags.getByValSize(),
- VA.getLocMemOffset(), true);
+ int FI = MFI.CreateFixedObject(Flags.getByValSize(),
+ VA.getLocMemOffset(), true);
InVal = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
} else {
// Load the argument to a virtual register
@@ -483,7 +482,7 @@ SDValue MSP430TargetLowering::LowerCCCArguments(
<< "\n";
}
// Create the frame index object for this incoming parameter...
- int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
+ int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
// Create the SelectionDAG nodes corresponding to a load
//from this parameter
@@ -807,7 +806,8 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
std::swap(LHS, RHS);
break;
case ISD::SETULE:
- std::swap(LHS, RHS); // FALLTHROUGH
+ std::swap(LHS, RHS);
+ LLVM_FALLTHROUGH;
case ISD::SETUGE:
// Turn lhs u>= rhs with lhs constant into rhs u< lhs+1, this allows us to
// fold constant into instruction.
@@ -820,7 +820,8 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
TCC = MSP430CC::COND_HS; // aka COND_C
break;
case ISD::SETUGT:
- std::swap(LHS, RHS); // FALLTHROUGH
+ std::swap(LHS, RHS);
+ LLVM_FALLTHROUGH;
case ISD::SETULT:
// Turn lhs u< rhs with lhs constant into rhs u>= lhs+1, this allows us to
// fold constant into instruction.
@@ -833,7 +834,8 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
TCC = MSP430CC::COND_LO; // aka COND_NC
break;
case ISD::SETLE:
- std::swap(LHS, RHS); // FALLTHROUGH
+ std::swap(LHS, RHS);
+ LLVM_FALLTHROUGH;
case ISD::SETGE:
// Turn lhs >= rhs with lhs constant into rhs < lhs+1, this allows us to
// fold constant into instruction.
@@ -846,7 +848,8 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
TCC = MSP430CC::COND_GE;
break;
case ISD::SETGT:
- std::swap(LHS, RHS); // FALLTHROUGH
+ std::swap(LHS, RHS);
+ LLVM_FALLTHROUGH;
case ISD::SETLT:
// Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to
// fold constant into instruction.
@@ -997,7 +1000,7 @@ MSP430TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const {
if (ReturnAddrIndex == 0) {
// Set up a frame object for the return address.
uint64_t SlotSize = MF.getDataLayout().getPointerSize();
- ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(SlotSize, -SlotSize,
+ ReturnAddrIndex = MF.getFrameInfo().CreateFixedObject(SlotSize, -SlotSize,
true);
FuncInfo->setRAIndex(ReturnAddrIndex);
}
@@ -1007,8 +1010,8 @@ MSP430TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const {
SDValue MSP430TargetLowering::LowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
@@ -1034,8 +1037,8 @@ SDValue MSP430TargetLowering::LowerRETURNADDR(SDValue Op,
SDValue MSP430TargetLowering::LowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc dl(Op); // FIXME probably not meaningful
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp
index c834da3..6135ce0 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp
@@ -42,7 +42,7 @@ void MSP430InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
DebugLoc DL;
if (MI != MBB.end()) DL = MI->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIdx),
@@ -69,7 +69,7 @@ void MSP430InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
DebugLoc DL;
if (MI != MBB.end()) DL = MI->getDebugLoc();
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIdx),
@@ -104,7 +104,10 @@ void MSP430InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
.addReg(SrcReg, getKillRegState(KillSrc));
}
-unsigned MSP430InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned MSP430InstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
@@ -127,7 +130,7 @@ unsigned MSP430InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
}
bool MSP430InstrInfo::
-ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 1 && "Invalid Xbranch condition!");
MSP430CC::CondCodes CC = static_cast<MSP430CC::CondCodes>(Cond[0].getImm());
@@ -260,15 +263,17 @@ bool MSP430InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-unsigned MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned MSP430InstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"MSP430 branch conditions have one component!");
+ assert(!BytesAdded && "code size not handled");
if (Cond.empty()) {
// Unconditional branch?
@@ -293,7 +298,7 @@ unsigned MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB,
/// GetInstSize - Return the number of bytes of code the specified
/// instruction may be. This returns the maximum number of bytes.
///
-unsigned MSP430InstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
+unsigned MSP430InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
const MCInstrDesc &Desc = MI.getDesc();
switch (Desc.TSFlags & MSP430II::SizeMask) {
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h
index 46d4738..e3259bd 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h
+++ b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h
@@ -68,21 +68,23 @@ public:
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
- unsigned GetInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
// Branch folding goodness
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
bool isUnpredicatedTerminator(const MachineInstr &MI) const override;
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
};
}
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp
index 2fb82e5..81cd9d1 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp
@@ -114,13 +114,13 @@ MSP430RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
unsigned BasePtr = (TFI->hasFP(MF) ? MSP430::FP : MSP430::SP);
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex);
// Skip the saved PC
Offset += 2;
if (!TFI->hasFP(MF))
- Offset += MF.getFrameInfo()->getStackSize();
+ Offset += MF.getFrameInfo().getStackSize();
else
Offset += 2; // Skip the saved FP
diff --git a/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp
index b2e698c..bebe5fa 100644
--- a/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp
+++ b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp
@@ -23,7 +23,7 @@ using namespace llvm;
extern "C" void LLVMInitializeMSP430Target() {
// Register the target.
- RegisterTargetMachine<MSP430TargetMachine> X(TheMSP430Target);
+ RegisterTargetMachine<MSP430TargetMachine> X(getTheMSP430Target());
}
static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
diff --git a/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp b/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp
index 0d71d04..62f52a1 100644
--- a/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp
+++ b/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp
@@ -12,9 +12,12 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheMSP430Target;
+Target &llvm::getTheMSP430Target() {
+ static Target TheMSP430Target;
+ return TheMSP430Target;
+}
-extern "C" void LLVMInitializeMSP430TargetInfo() {
- RegisterTarget<Triple::msp430>
- X(TheMSP430Target, "msp430", "MSP430 [experimental]");
+extern "C" void LLVMInitializeMSP430TargetInfo() {
+ RegisterTarget<Triple::msp430> X(getTheMSP430Target(), "msp430",
+ "MSP430 [experimental]");
}
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index b51d020..d054578 100644
--- a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -13,6 +13,7 @@
#include "MipsRegisterInfo.h"
#include "MipsTargetObjectFile.h"
#include "MipsTargetStreamer.h"
+#include "MCTargetDesc/MipsBaseInfo.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCContext.h"
@@ -129,6 +130,9 @@ class MipsAsmParser : public MCTargetAsmParser {
#define GET_ASSEMBLER_HEADER
#include "MipsGenAsmMatcher.inc"
+ unsigned
+ checkEarlyTargetMatchPredicate(MCInst &Inst,
+ const OperandVector &Operands) override;
unsigned checkTargetMatchPredicate(MCInst &Inst) override;
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
@@ -230,7 +234,10 @@ class MipsAsmParser : public MCTargetAsmParser {
bool expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
- bool expandUlw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ bool expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI);
+
+ bool expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
bool expandRotation(MCInst &Inst, SMLoc IDLoc,
@@ -245,13 +252,19 @@ class MipsAsmParser : public MCTargetAsmParser {
bool expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
+ bool expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI, bool IsLoad);
+
+ bool expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI);
+
+ bool expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI);
+
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
bool parseMemOffset(const MCExpr *&Res, bool isParenExpr);
- bool parseRelocOperand(const MCExpr *&Res);
-
- const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr);
bool isEvaluated(const MCExpr *Expr);
bool parseSetMips0Directive();
@@ -292,6 +305,10 @@ class MipsAsmParser : public MCTargetAsmParser {
bool parseDataDirective(unsigned Size, SMLoc L);
bool parseDirectiveGpWord();
bool parseDirectiveGpDWord();
+ bool parseDirectiveDtpRelWord();
+ bool parseDirectiveDtpRelDWord();
+ bool parseDirectiveTpRelWord();
+ bool parseDirectiveTpRelDWord();
bool parseDirectiveModule();
bool parseDirectiveModuleFP();
bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI,
@@ -395,6 +412,9 @@ public:
Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY,
Match_RequiresDifferentOperands,
Match_RequiresNoZeroRegister,
+ Match_RequiresSameSrcAndDst,
+ Match_NoFCCRegisterForCurrentISA,
+ Match_NonZeroOperandForSync,
#define GET_OPERAND_DIAGNOSTIC_TYPES
#include "MipsGenAsmMatcher.inc"
#undef GET_OPERAND_DIAGNOSTIC_TYPES
@@ -548,6 +568,64 @@ public:
void warnIfNoMacro(SMLoc Loc);
bool isLittle() const { return IsLittleEndian; }
+
+ const MCExpr *createTargetUnaryExpr(const MCExpr *E,
+ AsmToken::TokenKind OperatorToken,
+ MCContext &Ctx) override {
+ switch(OperatorToken) {
+ default:
+ llvm_unreachable("Unknown token");
+ return nullptr;
+ case AsmToken::PercentCall16:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, E, Ctx);
+ case AsmToken::PercentCall_Hi:
+ return MipsMCExpr::create(MipsMCExpr::MEK_CALL_HI16, E, Ctx);
+ case AsmToken::PercentCall_Lo:
+ return MipsMCExpr::create(MipsMCExpr::MEK_CALL_LO16, E, Ctx);
+ case AsmToken::PercentDtprel_Hi:
+ return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_HI, E, Ctx);
+ case AsmToken::PercentDtprel_Lo:
+ return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_LO, E, Ctx);
+ case AsmToken::PercentGot:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT, E, Ctx);
+ case AsmToken::PercentGot_Disp:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, E, Ctx);
+ case AsmToken::PercentGot_Hi:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT_HI16, E, Ctx);
+ case AsmToken::PercentGot_Lo:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT_LO16, E, Ctx);
+ case AsmToken::PercentGot_Ofst:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT_OFST, E, Ctx);
+ case AsmToken::PercentGot_Page:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOT_PAGE, E, Ctx);
+ case AsmToken::PercentGottprel:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GOTTPREL, E, Ctx);
+ case AsmToken::PercentGp_Rel:
+ return MipsMCExpr::create(MipsMCExpr::MEK_GPREL, E, Ctx);
+ case AsmToken::PercentHi:
+ return MipsMCExpr::create(MipsMCExpr::MEK_HI, E, Ctx);
+ case AsmToken::PercentHigher:
+ return MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, E, Ctx);
+ case AsmToken::PercentHighest:
+ return MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, E, Ctx);
+ case AsmToken::PercentLo:
+ return MipsMCExpr::create(MipsMCExpr::MEK_LO, E, Ctx);
+ case AsmToken::PercentNeg:
+ return MipsMCExpr::create(MipsMCExpr::MEK_NEG, E, Ctx);
+ case AsmToken::PercentPcrel_Hi:
+ return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_HI16, E, Ctx);
+ case AsmToken::PercentPcrel_Lo:
+ return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_LO16, E, Ctx);
+ case AsmToken::PercentTlsgd:
+ return MipsMCExpr::create(MipsMCExpr::MEK_TLSGD, E, Ctx);
+ case AsmToken::PercentTlsldm:
+ return MipsMCExpr::create(MipsMCExpr::MEK_TLSLDM, E, Ctx);
+ case AsmToken::PercentTprel_Hi:
+ return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_HI, E, Ctx);
+ case AsmToken::PercentTprel_Lo:
+ return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_LO, E, Ctx);
+ }
+ }
};
}
@@ -605,6 +683,7 @@ private:
struct RegIdxOp {
unsigned Index; /// Index into the register class
RegKind Kind; /// Bitfield of the kinds it could possibly be
+ struct Token Tok; /// The input token this operand originated from.
const MCRegisterInfo *RegInfo;
};
@@ -632,7 +711,8 @@ private:
SMLoc StartLoc, EndLoc;
/// Internal constructor for register kinds
- static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, RegKind RegKind,
+ static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, StringRef Str,
+ RegKind RegKind,
const MCRegisterInfo *RegInfo,
SMLoc S, SMLoc E,
MipsAsmParser &Parser) {
@@ -640,6 +720,8 @@ private:
Op->RegIdx.Index = Index;
Op->RegIdx.RegInfo = RegInfo;
Op->RegIdx.Kind = RegKind;
+ Op->RegIdx.Tok.Data = Str.data();
+ Op->RegIdx.Tok.Length = Str.size();
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
@@ -856,9 +938,11 @@ public:
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createReg(getFGR32Reg()));
// FIXME: We ought to do this for -integrated-as without -via-file-asm too.
+ // FIXME: This should propagate failure up to parseStatement.
if (!AsmParser.useOddSPReg() && RegIdx.Index & 1)
- AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU "
- "registers");
+ AsmParser.getParser().printError(
+ StartLoc, "-mno-odd-spreg prohibits the use of odd FPU "
+ "registers");
}
void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const {
@@ -925,7 +1009,7 @@ public:
void addConstantUImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
uint64_t Imm = getConstantImm() - Offset;
- Imm &= (1 << Bits) - 1;
+ Imm &= (1ULL << Bits) - 1;
Imm += Offset;
Imm += AdjustOffset;
Inst.addOperand(MCOperand::createImm(Imm));
@@ -1023,7 +1107,8 @@ public:
bool isRegIdx() const { return Kind == k_RegisterIndex; }
bool isImm() const override { return Kind == k_Immediate; }
bool isConstantImm() const {
- return isImm() && isa<MCConstantExpr>(getImm());
+ int64_t Res;
+ return isImm() && getImm()->evaluateAsAbsolute(Res);
}
bool isConstantImmz() const {
return isConstantImm() && getConstantImm() == 0;
@@ -1099,8 +1184,14 @@ public:
}
template <unsigned Bits, unsigned ShiftLeftAmount>
bool isScaledSImm() const {
- return isConstantImm() &&
- isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm());
+ if (isConstantImm() && isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm()))
+ return true;
+ // Operand can also be a symbol or symbol plus offset in case of relocations.
+ if (Kind != k_Immediate)
+ return false;
+ MCValue Res;
+ bool Success = getImm()->evaluateAsRelocatable(Res, nullptr, nullptr);
+ return Success && isShiftedInt<Bits, ShiftLeftAmount>(Res.getConstant());
}
bool isRegList16() const {
if (!isRegList())
@@ -1188,7 +1279,9 @@ public:
int64_t getConstantImm() const {
const MCExpr *Val = getImm();
- return static_cast<const MCConstantExpr *>(Val)->getValue();
+ int64_t Value = 0;
+ (void)Val->evaluateAsAbsolute(Value);
+ return Value;
}
MipsOperand *getMemBase() const {
@@ -1228,66 +1321,66 @@ public:
/// Create a numeric register (e.g. $1). The exact register remains
/// unresolved until an instruction successfully matches
static std::unique_ptr<MipsOperand>
- createNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S,
- SMLoc E, MipsAsmParser &Parser) {
+ createNumericReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n");
- return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser);
+ return CreateReg(Index, Str, RegKind_Numeric, RegInfo, S, E, Parser);
}
/// Create a register that is definitely a GPR.
/// This is typically only used for named registers such as $gp.
static std::unique_ptr<MipsOperand>
- createGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E,
- MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser);
+ createGPRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+ return CreateReg(Index, Str, RegKind_GPR, RegInfo, S, E, Parser);
}
/// Create a register that is definitely a FGR.
/// This is typically only used for named registers such as $f0.
static std::unique_ptr<MipsOperand>
- createFGRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E,
- MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser);
+ createFGRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+ return CreateReg(Index, Str, RegKind_FGR, RegInfo, S, E, Parser);
}
/// Create a register that is definitely a HWReg.
/// This is typically only used for named registers such as $hwr_cpunum.
static std::unique_ptr<MipsOperand>
- createHWRegsReg(unsigned Index, const MCRegisterInfo *RegInfo,
+ createHWRegsReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
SMLoc S, SMLoc E, MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_HWRegs, RegInfo, S, E, Parser);
+ return CreateReg(Index, Str, RegKind_HWRegs, RegInfo, S, E, Parser);
}
/// Create a register that is definitely an FCC.
/// This is typically only used for named registers such as $fcc0.
static std::unique_ptr<MipsOperand>
- createFCCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E,
- MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser);
+ createFCCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+ return CreateReg(Index, Str, RegKind_FCC, RegInfo, S, E, Parser);
}
/// Create a register that is definitely an ACC.
/// This is typically only used for named registers such as $ac0.
static std::unique_ptr<MipsOperand>
- createACCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E,
- MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser);
+ createACCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+ return CreateReg(Index, Str, RegKind_ACC, RegInfo, S, E, Parser);
}
/// Create a register that is definitely an MSA128.
/// This is typically only used for named registers such as $w0.
static std::unique_ptr<MipsOperand>
- createMSA128Reg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S,
- SMLoc E, MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser);
+ createMSA128Reg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+ return CreateReg(Index, Str, RegKind_MSA128, RegInfo, S, E, Parser);
}
/// Create a register that is definitely an MSACtrl.
/// This is typically only used for named registers such as $msaaccess.
static std::unique_ptr<MipsOperand>
- createMSACtrlReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S,
- SMLoc E, MipsAsmParser &Parser) {
- return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser);
+ createMSACtrlReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,
+ SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+ return CreateReg(Index, Str, RegKind_MSACtrl, RegInfo, S, E, Parser);
}
static std::unique_ptr<MipsOperand>
@@ -1369,8 +1462,6 @@ public:
bool isFCCAsmReg() const {
if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC))
return false;
- if (!AsmParser.hasEightFccRegisters())
- return RegIdx.Index == 0;
return RegIdx.Index <= 7;
}
bool isACCAsmReg() const {
@@ -1428,10 +1519,11 @@ public:
OS << ">";
break;
case k_RegisterIndex:
- OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ">";
+ OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ", "
+ << StringRef(RegIdx.Tok.Data, RegIdx.Tok.Length) << ">";
break;
case k_Token:
- OS << Tok.Data;
+ OS << getToken();
break;
case k_RegList:
OS << "RegList< ";
@@ -1444,6 +1536,22 @@ public:
break;
}
}
+
+ bool isValidForTie(const MipsOperand &Other) const {
+ if (Kind != Other.Kind)
+ return false;
+
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unexpected kind");
+ return false;
+ case k_RegisterIndex: {
+ StringRef Token(RegIdx.Tok.Data, RegIdx.Tok.Length);
+ StringRef OtherToken(Other.RegIdx.Tok.Data, Other.RegIdx.Tok.Length);
+ return Token == OtherToken;
+ }
+ }
+ }
}; // class MipsOperand
} // namespace
@@ -1526,7 +1634,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case Mips::BBIT1:
case Mips::BBIT132:
assert(hasCnMips() && "instruction only valid for octeon cpus");
- // Fall through
+ LLVM_FALLTHROUGH;
case Mips::BEQ:
case Mips::BNE:
@@ -1572,6 +1680,45 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
1LL << (inMicroMipsMode() ? 1 : 2)))
return Error(IDLoc, "branch to misaligned address");
break;
+ case Mips::BGEC: case Mips::BGEC_MMR6:
+ case Mips::BLTC: case Mips::BLTC_MMR6:
+ case Mips::BGEUC: case Mips::BGEUC_MMR6:
+ case Mips::BLTUC: case Mips::BLTUC_MMR6:
+ case Mips::BEQC: case Mips::BEQC_MMR6:
+ case Mips::BNEC: case Mips::BNEC_MMR6:
+ assert(MCID.getNumOperands() == 3 && "unexpected number of operands");
+ Offset = Inst.getOperand(2);
+ if (!Offset.isImm())
+ break; // We'll deal with this situation later on when applying fixups.
+ if (!isIntN(18, Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (OffsetToAlignment(Offset.getImm(), 1LL << 2))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
+ case Mips::BLEZC: case Mips::BLEZC_MMR6:
+ case Mips::BGEZC: case Mips::BGEZC_MMR6:
+ case Mips::BGTZC: case Mips::BGTZC_MMR6:
+ case Mips::BLTZC: case Mips::BLTZC_MMR6:
+ assert(MCID.getNumOperands() == 2 && "unexpected number of operands");
+ Offset = Inst.getOperand(1);
+ if (!Offset.isImm())
+ break; // We'll deal with this situation later on when applying fixups.
+ if (!isIntN(18, Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (OffsetToAlignment(Offset.getImm(), 1LL << 2))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
+ case Mips::BEQZC: case Mips::BEQZC_MMR6:
+ case Mips::BNEZC: case Mips::BNEZC_MMR6:
+ assert(MCID.getNumOperands() == 2 && "unexpected number of operands");
+ Offset = Inst.getOperand(1);
+ if (!Offset.isImm())
+ break; // We'll deal with this situation later on when applying fixups.
+ if (!isIntN(23, Offset.getImm()))
+ return Error(IDLoc, "branch target out of range");
+ if (OffsetToAlignment(Offset.getImm(), 1LL << 2))
+ return Error(IDLoc, "branch to misaligned address");
+ break;
case Mips::BEQZ16_MM:
case Mips::BEQZC16_MMR6:
case Mips::BNEZ16_MM:
@@ -1638,6 +1785,17 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
}
}
+ // For PIC code convert unconditional jump to unconditional branch.
+ if ((Inst.getOpcode() == Mips::J || Inst.getOpcode() == Mips::J_MM) &&
+ inPicMode()) {
+ MCInst BInst;
+ BInst.setOpcode(inMicroMipsMode() ? Mips::BEQ_MM : Mips::BEQ);
+ BInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BInst.addOperand(MCOperand::createReg(Mips::ZERO));
+ BInst.addOperand(Inst.getOperand(0));
+ Inst = BInst;
+ }
+
// This expansion is not in a function called by tryExpandInstruction()
// because the pseudo-instruction doesn't have a distinct opcode.
if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) &&
@@ -1658,7 +1816,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
// FIXME: Add support for label+offset operands (currently causes an error).
// FIXME: Add support for forward-declared local symbols.
// FIXME: Add expansion for when the LargeGOT option is enabled.
- if (JalSym->isInSection() || JalSym->isTemporary()) {
+ if (JalSym->isInSection() || JalSym->isTemporary() ||
+ (JalSym->isELF() && cast<MCSymbolELF>(JalSym)->getBinding() == ELF::STB_LOCAL)) {
if (isABI_O32()) {
// If it's a local symbol and the O32 ABI is being used, we expand to:
// lw $25, 0($gp)
@@ -1716,7 +1875,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
ExpandedJalSym = true;
}
- if (MCID.mayLoad() || MCID.mayStore()) {
+ bool IsPCRelativeLoad = (MCID.TSFlags & MipsII::IsPCRelativeLoad) != 0;
+ if ((MCID.mayLoad() || MCID.mayStore()) && !IsPCRelativeLoad) {
// Check the offset of memory operand, if it is a symbol
// reference or immediate we may have to expand instructions.
for (unsigned i = 0; i < MCID.getNumOperands(); i++) {
@@ -1729,7 +1889,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (MemOffset < -32768 || MemOffset > 32767) {
// Offset can't exceed 16bit value.
expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), true);
- return false;
+ return getParser().hasPendingError();
}
} else if (Op.isExpr()) {
const MCExpr *Expr = Op.getExpr();
@@ -1739,11 +1899,11 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (SR->getKind() == MCSymbolRefExpr::VK_None) {
// Expand symbol.
expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false);
- return false;
+ return getParser().hasPendingError();
}
} else if (!isEvaluated(Expr)) {
expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false);
- return false;
+ return getParser().hasPendingError();
}
}
}
@@ -2034,8 +2194,11 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return expandUlh(Inst, true, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::Ulhu:
return expandUlh(Inst, false, IDLoc, Out, STI) ? MER_Fail : MER_Success;
+ case Mips::Ush:
+ return expandUsh(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::Ulw:
- return expandUlw(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
+ case Mips::Usw:
+ return expandUxw(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::NORImm:
return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::ADDi:
@@ -2077,6 +2240,16 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return expandDRotationImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::ABSMacro:
return expandAbs(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
+ case Mips::LDMacro:
+ case Mips::SDMacro:
+ return expandLoadStoreDMacro(Inst, IDLoc, Out, STI,
+ Inst.getOpcode() == Mips::LDMacro)
+ ? MER_Fail
+ : MER_Success;
+ case Mips::SEQMacro:
+ return expandSeq(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
+ case Mips::SEQIMacro:
+ return expandSeqI(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
}
}
@@ -2335,6 +2508,7 @@ bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg,
Error(IDLoc, "la used to load 64-bit address");
// Continue as if we had 'dla' instead.
Is32BitAddress = false;
+ return true;
}
// dla requires 64-bit addresses.
@@ -2561,9 +2735,9 @@ bool MipsAsmParser::expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc,
Inst.setOpcode(hasMips32r6() ? Mips::BC16_MMR6 : Mips::B16_MM);
} else {
if (!isInt<17>(Offset.getImm()))
- Error(IDLoc, "branch target out of range");
+ return Error(IDLoc, "branch target out of range");
if (OffsetToAlignment(Offset.getImm(), 1LL << 1))
- Error(IDLoc, "branch to misaligned address");
+ return Error(IDLoc, "branch to misaligned address");
Inst.clear();
Inst.setOpcode(Mips::BEQ_MM);
Inst.addOperand(MCOperand::createReg(Mips::ZERO));
@@ -3168,146 +3342,158 @@ bool MipsAsmParser::expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU,
bool MipsAsmParser::expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc,
MCStreamer &Out, const MCSubtargetInfo *STI) {
- MipsTargetStreamer &TOut = getTargetStreamer();
-
if (hasMips32r6() || hasMips64r6()) {
- Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
- return false;
+ return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
}
- warnIfNoMacro(IDLoc);
-
const MCOperand &DstRegOp = Inst.getOperand(0);
assert(DstRegOp.isReg() && "expected register operand kind");
-
const MCOperand &SrcRegOp = Inst.getOperand(1);
assert(SrcRegOp.isReg() && "expected register operand kind");
-
const MCOperand &OffsetImmOp = Inst.getOperand(2);
assert(OffsetImmOp.isImm() && "expected immediate operand kind");
+ MipsTargetStreamer &TOut = getTargetStreamer();
unsigned DstReg = DstRegOp.getReg();
unsigned SrcReg = SrcRegOp.getReg();
int64_t OffsetValue = OffsetImmOp.getImm();
// NOTE: We always need AT for ULHU, as it is always used as the source
// register for one of the LBu's.
+ warnIfNoMacro(IDLoc);
unsigned ATReg = getATReg(IDLoc);
if (!ATReg)
return true;
- // When the value of offset+1 does not fit in 16 bits, we have to load the
- // offset in AT, (D)ADDu the original source register (if there was one), and
- // then use AT as the source register for the 2 generated LBu's.
- bool LoadedOffsetInAT = false;
- if (!isInt<16>(OffsetValue + 1) || !isInt<16>(OffsetValue)) {
- LoadedOffsetInAT = true;
-
- if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(),
- true, IDLoc, Out, STI))
+ bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue));
+ if (IsLargeOffset) {
+ if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true,
+ IDLoc, Out, STI))
return true;
-
- // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate()
- // because it will make our output more similar to GAS'. For example,
- // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9",
- // instead of just an "ori $1, $9, 32768".
- // NOTE: If there is no source register specified in the ULHU, the parser
- // will interpret it as $0.
- if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64)
- TOut.emitAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), STI);
}
- unsigned FirstLbuDstReg = LoadedOffsetInAT ? DstReg : ATReg;
- unsigned SecondLbuDstReg = LoadedOffsetInAT ? ATReg : DstReg;
- unsigned LbuSrcReg = LoadedOffsetInAT ? ATReg : SrcReg;
+ int64_t FirstOffset = IsLargeOffset ? 0 : OffsetValue;
+ int64_t SecondOffset = IsLargeOffset ? 1 : (OffsetValue + 1);
+ if (isLittle())
+ std::swap(FirstOffset, SecondOffset);
- int64_t FirstLbuOffset = 0, SecondLbuOffset = 0;
- if (isLittle()) {
- FirstLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1);
- SecondLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue;
- } else {
- FirstLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue;
- SecondLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1);
- }
+ unsigned FirstLbuDstReg = IsLargeOffset ? DstReg : ATReg;
+ unsigned SecondLbuDstReg = IsLargeOffset ? ATReg : DstReg;
- unsigned SllReg = LoadedOffsetInAT ? DstReg : ATReg;
+ unsigned LbuSrcReg = IsLargeOffset ? ATReg : SrcReg;
+ unsigned SllReg = IsLargeOffset ? DstReg : ATReg;
TOut.emitRRI(Signed ? Mips::LB : Mips::LBu, FirstLbuDstReg, LbuSrcReg,
- FirstLbuOffset, IDLoc, STI);
-
- TOut.emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondLbuOffset, IDLoc,
- STI);
-
+ FirstOffset, IDLoc, STI);
+ TOut.emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondOffset, IDLoc, STI);
TOut.emitRRI(Mips::SLL, SllReg, SllReg, 8, IDLoc, STI);
-
TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI);
return false;
}
-bool MipsAsmParser::expandUlw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+bool MipsAsmParser::expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI) {
+ if (hasMips32r6() || hasMips64r6()) {
+ return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
+ }
+
+ const MCOperand &DstRegOp = Inst.getOperand(0);
+ assert(DstRegOp.isReg() && "expected register operand kind");
+ const MCOperand &SrcRegOp = Inst.getOperand(1);
+ assert(SrcRegOp.isReg() && "expected register operand kind");
+ const MCOperand &OffsetImmOp = Inst.getOperand(2);
+ assert(OffsetImmOp.isImm() && "expected immediate operand kind");
+
MipsTargetStreamer &TOut = getTargetStreamer();
+ unsigned DstReg = DstRegOp.getReg();
+ unsigned SrcReg = SrcRegOp.getReg();
+ int64_t OffsetValue = OffsetImmOp.getImm();
+ warnIfNoMacro(IDLoc);
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+
+ bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue));
+ if (IsLargeOffset) {
+ if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true,
+ IDLoc, Out, STI))
+ return true;
+ }
+
+ int64_t FirstOffset = IsLargeOffset ? 1 : (OffsetValue + 1);
+ int64_t SecondOffset = IsLargeOffset ? 0 : OffsetValue;
+ if (isLittle())
+ std::swap(FirstOffset, SecondOffset);
+
+ if (IsLargeOffset) {
+ TOut.emitRRI(Mips::SB, DstReg, ATReg, FirstOffset, IDLoc, STI);
+ TOut.emitRRI(Mips::SRL, DstReg, DstReg, 8, IDLoc, STI);
+ TOut.emitRRI(Mips::SB, DstReg, ATReg, SecondOffset, IDLoc, STI);
+ TOut.emitRRI(Mips::LBu, ATReg, ATReg, 0, IDLoc, STI);
+ TOut.emitRRI(Mips::SLL, DstReg, DstReg, 8, IDLoc, STI);
+ TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI);
+ } else {
+ TOut.emitRRI(Mips::SB, DstReg, SrcReg, FirstOffset, IDLoc, STI);
+ TOut.emitRRI(Mips::SRL, ATReg, DstReg, 8, IDLoc, STI);
+ TOut.emitRRI(Mips::SB, ATReg, SrcReg, SecondOffset, IDLoc, STI);
+ }
+
+ return false;
+}
+
+bool MipsAsmParser::expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI) {
if (hasMips32r6() || hasMips64r6()) {
- Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
- return false;
+ return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6");
}
const MCOperand &DstRegOp = Inst.getOperand(0);
assert(DstRegOp.isReg() && "expected register operand kind");
-
const MCOperand &SrcRegOp = Inst.getOperand(1);
assert(SrcRegOp.isReg() && "expected register operand kind");
-
const MCOperand &OffsetImmOp = Inst.getOperand(2);
assert(OffsetImmOp.isImm() && "expected immediate operand kind");
+ MipsTargetStreamer &TOut = getTargetStreamer();
+ unsigned DstReg = DstRegOp.getReg();
unsigned SrcReg = SrcRegOp.getReg();
int64_t OffsetValue = OffsetImmOp.getImm();
- unsigned ATReg = 0;
-
- // When the value of offset+3 does not fit in 16 bits, we have to load the
- // offset in AT, (D)ADDu the original source register (if there was one), and
- // then use AT as the source register for the generated LWL and LWR.
- bool LoadedOffsetInAT = false;
- if (!isInt<16>(OffsetValue + 3) || !isInt<16>(OffsetValue)) {
- ATReg = getATReg(IDLoc);
- if (!ATReg)
- return true;
- LoadedOffsetInAT = true;
+ // Compute left/right load/store offsets.
+ bool IsLargeOffset = !(isInt<16>(OffsetValue + 3) && isInt<16>(OffsetValue));
+ int64_t LxlOffset = IsLargeOffset ? 0 : OffsetValue;
+ int64_t LxrOffset = IsLargeOffset ? 3 : (OffsetValue + 3);
+ if (isLittle())
+ std::swap(LxlOffset, LxrOffset);
+
+ bool IsLoadInst = (Inst.getOpcode() == Mips::Ulw);
+ bool DoMove = IsLoadInst && (SrcReg == DstReg) && !IsLargeOffset;
+ unsigned TmpReg = SrcReg;
+ if (IsLargeOffset || DoMove) {
warnIfNoMacro(IDLoc);
-
- if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(),
- true, IDLoc, Out, STI))
+ TmpReg = getATReg(IDLoc);
+ if (!TmpReg)
return true;
+ }
- // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate()
- // because it will make our output more similar to GAS'. For example,
- // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9",
- // instead of just an "ori $1, $9, 32768".
- // NOTE: If there is no source register specified in the ULW, the parser
- // will interpret it as $0.
- if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64)
- TOut.emitAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), STI);
- }
-
- unsigned FinalSrcReg = LoadedOffsetInAT ? ATReg : SrcReg;
- int64_t LeftLoadOffset = 0, RightLoadOffset = 0;
- if (isLittle()) {
- LeftLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3);
- RightLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue;
- } else {
- LeftLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue;
- RightLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3);
+ if (IsLargeOffset) {
+ if (loadImmediate(OffsetValue, TmpReg, SrcReg, !ABI.ArePtrs64bit(), true,
+ IDLoc, Out, STI))
+ return true;
}
- TOut.emitRRI(Mips::LWL, DstRegOp.getReg(), FinalSrcReg, LeftLoadOffset, IDLoc,
- STI);
+ if (DoMove)
+ std::swap(DstReg, TmpReg);
- TOut.emitRRI(Mips::LWR, DstRegOp.getReg(), FinalSrcReg, RightLoadOffset,
- IDLoc, STI);
+ unsigned XWL = IsLoadInst ? Mips::LWL : Mips::SWL;
+ unsigned XWR = IsLoadInst ? Mips::LWR : Mips::SWR;
+ TOut.emitRRI(XWL, DstReg, TmpReg, LxlOffset, IDLoc, STI);
+ TOut.emitRRI(XWR, DstReg, TmpReg, LxrOffset, IDLoc, STI);
+
+ if (DoMove)
+ TOut.emitRRR(Mips::OR, TmpReg, DstReg, Mips::ZERO, IDLoc, STI);
return false;
}
@@ -3685,8 +3871,198 @@ bool MipsAsmParser::expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return false;
}
+static unsigned nextReg(unsigned Reg) {
+ switch (Reg) {
+ case Mips::ZERO: return Mips::AT;
+ case Mips::AT: return Mips::V0;
+ case Mips::V0: return Mips::V1;
+ case Mips::V1: return Mips::A0;
+ case Mips::A0: return Mips::A1;
+ case Mips::A1: return Mips::A2;
+ case Mips::A2: return Mips::A3;
+ case Mips::A3: return Mips::T0;
+ case Mips::T0: return Mips::T1;
+ case Mips::T1: return Mips::T2;
+ case Mips::T2: return Mips::T3;
+ case Mips::T3: return Mips::T4;
+ case Mips::T4: return Mips::T5;
+ case Mips::T5: return Mips::T6;
+ case Mips::T6: return Mips::T7;
+ case Mips::T7: return Mips::S0;
+ case Mips::S0: return Mips::S1;
+ case Mips::S1: return Mips::S2;
+ case Mips::S2: return Mips::S3;
+ case Mips::S3: return Mips::S4;
+ case Mips::S4: return Mips::S5;
+ case Mips::S5: return Mips::S6;
+ case Mips::S6: return Mips::S7;
+ case Mips::S7: return Mips::T8;
+ case Mips::T8: return Mips::T9;
+ case Mips::T9: return Mips::K0;
+ case Mips::K0: return Mips::K1;
+ case Mips::K1: return Mips::GP;
+ case Mips::GP: return Mips::SP;
+ case Mips::SP: return Mips::FP;
+ case Mips::FP: return Mips::RA;
+ case Mips::RA: return Mips::ZERO;
+ default: return 0;
+ }
+
+}
+
+// Expand 'ld $<reg> offset($reg2)' to 'lw $<reg>, offset($reg2);
+// lw $<reg+1>>, offset+4($reg2)'
+// or expand 'sd $<reg> offset($reg2)' to 'sw $<reg>, offset($reg2);
+// sw $<reg+1>>, offset+4($reg2)'
+// for O32.
+bool MipsAsmParser::expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc,
+ MCStreamer &Out,
+ const MCSubtargetInfo *STI,
+ bool IsLoad) {
+ if (!isABI_O32())
+ return true;
+
+ warnIfNoMacro(IDLoc);
+
+ MipsTargetStreamer &TOut = getTargetStreamer();
+ unsigned Opcode = IsLoad ? Mips::LW : Mips::SW;
+ unsigned FirstReg = Inst.getOperand(0).getReg();
+ unsigned SecondReg = nextReg(FirstReg);
+ unsigned BaseReg = Inst.getOperand(1).getReg();
+ if (!SecondReg)
+ return true;
+
+ warnIfRegIndexIsAT(FirstReg, IDLoc);
+
+ assert(Inst.getOperand(2).isImm() &&
+ "Offset for load macro is not immediate!");
+
+ MCOperand &FirstOffset = Inst.getOperand(2);
+ signed NextOffset = FirstOffset.getImm() + 4;
+ MCOperand SecondOffset = MCOperand::createImm(NextOffset);
+
+ if (!isInt<16>(FirstOffset.getImm()) || !isInt<16>(NextOffset))
+ return true;
+
+ // For loads, clobber the base register with the second load instead of the
+ // first if the BaseReg == FirstReg.
+ if (FirstReg != BaseReg || !IsLoad) {
+ TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI);
+ TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI);
+ } else {
+ TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI);
+ TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI);
+ }
+
+ return false;
+}
+
+bool MipsAsmParser::expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI) {
+
+ warnIfNoMacro(IDLoc);
+ MipsTargetStreamer &TOut = getTargetStreamer();
+
+ if (Inst.getOperand(1).getReg() != Mips::ZERO &&
+ Inst.getOperand(2).getReg() != Mips::ZERO) {
+ TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(),
+ Inst.getOperand(1).getReg(), Inst.getOperand(2).getReg(),
+ IDLoc, STI);
+ TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(),
+ Inst.getOperand(0).getReg(), 1, IDLoc, STI);
+ return false;
+ }
+
+ unsigned Reg = 0;
+ if (Inst.getOperand(1).getReg() == Mips::ZERO) {
+ Reg = Inst.getOperand(2).getReg();
+ } else {
+ Reg = Inst.getOperand(1).getReg();
+ }
+ TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Reg, 1, IDLoc, STI);
+ return false;
+}
+
+bool MipsAsmParser::expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
+ const MCSubtargetInfo *STI) {
+
+ warnIfNoMacro(IDLoc);
+ MipsTargetStreamer &TOut = getTargetStreamer();
+
+ unsigned Opc;
+ int64_t Imm = Inst.getOperand(2).getImm();
+ unsigned Reg = Inst.getOperand(1).getReg();
+
+ if (Imm == 0) {
+ TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(),
+ Inst.getOperand(1).getReg(), 1, IDLoc, STI);
+ return false;
+ } else {
+
+ if (Reg == Mips::ZERO) {
+ Warning(IDLoc, "comparison is always false");
+ TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu,
+ Inst.getOperand(0).getReg(), Reg, Reg, IDLoc, STI);
+ return false;
+ }
+
+ if (Imm > -0x8000 && Imm < 0) {
+ Imm = -Imm;
+ Opc = isGP64bit() ? Mips::DADDiu : Mips::ADDiu;
+ } else {
+ Opc = Mips::XORi;
+ }
+ }
+ if (!isUInt<16>(Imm)) {
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+
+ if (loadImmediate(Imm, ATReg, Mips::NoRegister, true, isGP64bit(), IDLoc,
+ Out, STI))
+ return true;
+
+ TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(),
+ Inst.getOperand(1).getReg(), ATReg, IDLoc, STI);
+ TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(),
+ Inst.getOperand(0).getReg(), 1, IDLoc, STI);
+ return false;
+ }
+
+ TOut.emitRRI(Opc, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(),
+ Imm, IDLoc, STI);
+ TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(),
+ Inst.getOperand(0).getReg(), 1, IDLoc, STI);
+ return false;
+}
+
+unsigned
+MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst,
+ const OperandVector &Operands) {
+ switch (Inst.getOpcode()) {
+ default:
+ return Match_Success;
+ case Mips::DATI:
+ case Mips::DAHI:
+ case Mips::DATI_MM64R6:
+ case Mips::DAHI_MM64R6:
+ if (static_cast<MipsOperand &>(*Operands[1])
+ .isValidForTie(static_cast<MipsOperand &>(*Operands[2])))
+ return Match_Success;
+ return Match_RequiresSameSrcAndDst;
+ }
+}
+
unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
switch (Inst.getOpcode()) {
+ // As described by the MIPSR6 spec, daui must not use the zero operand for
+ // its source operand.
+ case Mips::DAUI:
+ case Mips::DAUI_MM64R6:
+ if (Inst.getOperand(1).getReg() == Mips::ZERO ||
+ Inst.getOperand(1).getReg() == Mips::ZERO_64)
+ return Match_RequiresNoZeroRegister;
+ return Match_Success;
// As described by the Mips32r2 spec, the registers Rd and Rs for
// jalr.hb must be different.
// It also applies for registers Rt and Rs of microMIPSr6 jalrc.hb instruction
@@ -3702,6 +4078,10 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
if (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg())
return Match_RequiresDifferentSrcAndDst;
return Match_Success;
+ case Mips::SYNC:
+ if (Inst.getOperand(0).getImm() != 0 && !hasMips32())
+ return Match_NonZeroOperandForSync;
+ return Match_Success;
// As described the MIPSR6 spec, the compact branches that compare registers
// must:
// a) Not use the zero register.
@@ -3714,31 +4094,52 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
// The compact branches that branch iff the signed addition of two registers
// would overflow must have rs >= rt. That can be handled like beqc/bnec with
// operand swapping. They do not have restriction of using the zero register.
- case Mips::BLEZC:
- case Mips::BGEZC:
- case Mips::BGTZC:
- case Mips::BLTZC:
- case Mips::BEQZC:
- case Mips::BNEZC:
- if (Inst.getOperand(0).getReg() == Mips::ZERO)
+ case Mips::BLEZC: case Mips::BLEZC_MMR6:
+ case Mips::BGEZC: case Mips::BGEZC_MMR6:
+ case Mips::BGTZC: case Mips::BGTZC_MMR6:
+ case Mips::BLTZC: case Mips::BLTZC_MMR6:
+ case Mips::BEQZC: case Mips::BEQZC_MMR6:
+ case Mips::BNEZC: case Mips::BNEZC_MMR6:
+ case Mips::BLEZC64:
+ case Mips::BGEZC64:
+ case Mips::BGTZC64:
+ case Mips::BLTZC64:
+ case Mips::BEQZC64:
+ case Mips::BNEZC64:
+ if (Inst.getOperand(0).getReg() == Mips::ZERO ||
+ Inst.getOperand(0).getReg() == Mips::ZERO_64)
return Match_RequiresNoZeroRegister;
return Match_Success;
- case Mips::BGEC:
- case Mips::BLTC:
- case Mips::BGEUC:
- case Mips::BLTUC:
- case Mips::BEQC:
- case Mips::BNEC:
- if (Inst.getOperand(0).getReg() == Mips::ZERO)
+ case Mips::BGEC: case Mips::BGEC_MMR6:
+ case Mips::BLTC: case Mips::BLTC_MMR6:
+ case Mips::BGEUC: case Mips::BGEUC_MMR6:
+ case Mips::BLTUC: case Mips::BLTUC_MMR6:
+ case Mips::BEQC: case Mips::BEQC_MMR6:
+ case Mips::BNEC: case Mips::BNEC_MMR6:
+ case Mips::BGEC64:
+ case Mips::BLTC64:
+ case Mips::BGEUC64:
+ case Mips::BLTUC64:
+ case Mips::BEQC64:
+ case Mips::BNEC64:
+ if (Inst.getOperand(0).getReg() == Mips::ZERO ||
+ Inst.getOperand(0).getReg() == Mips::ZERO_64)
return Match_RequiresNoZeroRegister;
- if (Inst.getOperand(1).getReg() == Mips::ZERO)
+ if (Inst.getOperand(1).getReg() == Mips::ZERO ||
+ Inst.getOperand(1).getReg() == Mips::ZERO_64)
return Match_RequiresNoZeroRegister;
if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())
return Match_RequiresDifferentOperands;
return Match_Success;
- default:
- return Match_Success;
}
+
+ uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags;
+ if ((TSFlags & MipsII::HasFCCRegOperand) &&
+ (Inst.getOperand(0).getReg() != Mips::FCC0) && !hasEightFccRegisters())
+ return Match_NoFCCRegisterForCurrentISA;
+
+ return Match_Success;
+
}
static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands,
@@ -3784,6 +4185,8 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return Error(ErrorLoc, "invalid operand for instruction");
}
+ case Match_NonZeroOperandForSync:
+ return Error(IDLoc, "s-type must be zero or unspecified for pre-MIPS32 ISAs");
case Match_MnemonicFail:
return Error(IDLoc, "invalid instruction");
case Match_RequiresDifferentSrcAndDst:
@@ -3792,6 +4195,11 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return Error(IDLoc, "registers must be different");
case Match_RequiresNoZeroRegister:
return Error(IDLoc, "invalid operand ($zero) for instruction");
+ case Match_RequiresSameSrcAndDst:
+ return Error(IDLoc, "source and destination must match");
+ case Match_NoFCCRegisterForCurrentISA:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "non-zero fcc register doesn't exist in current ISA level");
case Match_Immz:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'");
case Match_UImm1_0:
@@ -3876,6 +4284,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_SImm16_Relaxed:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 16-bit signed immediate");
+ case Match_SImm19_Lsl2:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected both 19-bit signed immediate and multiple of 4");
case Match_UImm20_0:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 20-bit unsigned immediate");
@@ -3886,6 +4297,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_SImm32_Relaxed:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected 32-bit signed immediate");
+ case Match_UImm32_Coerced:
+ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+ "expected 32-bit immediate");
case Match_MemSImm9:
return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
"expected memory with 9-bit signed offset");
@@ -4131,9 +4545,6 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
DEBUG(dbgs() << ".. Generic Parser\n");
switch (getLexer().getKind()) {
- default:
- Error(Parser.getTok().getLoc(), "unexpected token in operand");
- return true;
case AsmToken::Dollar: {
// Parse the register.
SMLoc S = Parser.getTok().getLoc();
@@ -4160,72 +4571,23 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this));
return false;
}
- // Else drop to expression parsing.
- case AsmToken::LParen:
- case AsmToken::Minus:
- case AsmToken::Plus:
- case AsmToken::Integer:
- case AsmToken::Tilde:
- case AsmToken::String: {
- DEBUG(dbgs() << ".. generic integer\n");
- OperandMatchResultTy ResTy = parseImm(Operands);
- return ResTy != MatchOperand_Success;
- }
- case AsmToken::Percent: {
- // It is a symbol reference or constant expression.
- const MCExpr *IdVal;
+ default: {
+ DEBUG(dbgs() << ".. generic integer expression\n");
+
+ const MCExpr *Expr;
SMLoc S = Parser.getTok().getLoc(); // Start location of the operand.
- if (parseRelocOperand(IdVal))
+ if (getParser().parseExpression(Expr))
return true;
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this));
+ Operands.push_back(MipsOperand::CreateImm(Expr, S, E, *this));
return false;
- } // case AsmToken::Percent
+ }
} // switch(getLexer().getKind())
return true;
}
-const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr,
- StringRef RelocStr) {
- if (RelocStr == "hi(%neg(%gp_rel")
- return MipsMCExpr::createGpOff(MipsMCExpr::MEK_HI, Expr, getContext());
- else if (RelocStr == "lo(%neg(%gp_rel")
- return MipsMCExpr::createGpOff(MipsMCExpr::MEK_LO, Expr, getContext());
-
- MipsMCExpr::MipsExprKind Kind =
- StringSwitch<MipsMCExpr::MipsExprKind>(RelocStr)
- .Case("call16", MipsMCExpr::MEK_GOT_CALL)
- .Case("call_hi", MipsMCExpr::MEK_CALL_HI16)
- .Case("call_lo", MipsMCExpr::MEK_CALL_LO16)
- .Case("dtprel_hi", MipsMCExpr::MEK_DTPREL_HI)
- .Case("dtprel_lo", MipsMCExpr::MEK_DTPREL_LO)
- .Case("got", MipsMCExpr::MEK_GOT)
- .Case("got_disp", MipsMCExpr::MEK_GOT_DISP)
- .Case("got_hi", MipsMCExpr::MEK_GOT_HI16)
- .Case("got_lo", MipsMCExpr::MEK_GOT_LO16)
- .Case("got_ofst", MipsMCExpr::MEK_GOT_OFST)
- .Case("got_page", MipsMCExpr::MEK_GOT_PAGE)
- .Case("gottprel", MipsMCExpr::MEK_GOTTPREL)
- .Case("gp_rel", MipsMCExpr::MEK_GPREL)
- .Case("hi", MipsMCExpr::MEK_HI)
- .Case("higher", MipsMCExpr::MEK_HIGHER)
- .Case("highest", MipsMCExpr::MEK_HIGHEST)
- .Case("lo", MipsMCExpr::MEK_LO)
- .Case("neg", MipsMCExpr::MEK_NEG)
- .Case("pcrel_hi", MipsMCExpr::MEK_PCREL_HI16)
- .Case("pcrel_lo", MipsMCExpr::MEK_PCREL_LO16)
- .Case("tlsgd", MipsMCExpr::MEK_TLSGD)
- .Case("tlsldm", MipsMCExpr::MEK_TLSLDM)
- .Case("tprel_hi", MipsMCExpr::MEK_TPREL_HI)
- .Case("tprel_lo", MipsMCExpr::MEK_TPREL_LO)
- .Default(MipsMCExpr::MEK_None);
-
- assert(Kind != MipsMCExpr::MEK_None);
- return MipsMCExpr::create(Kind, Expr, getContext());
-}
-
bool MipsAsmParser::isEvaluated(const MCExpr *Expr) {
switch (Expr->getKind()) {
@@ -4247,49 +4609,6 @@ bool MipsAsmParser::isEvaluated(const MCExpr *Expr) {
return false;
}
-bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) {
- MCAsmParser &Parser = getParser();
- Parser.Lex(); // Eat the % token.
- const AsmToken &Tok = Parser.getTok(); // Get next token, operation.
- if (Tok.isNot(AsmToken::Identifier))
- return true;
-
- std::string Str = Tok.getIdentifier();
-
- Parser.Lex(); // Eat the identifier.
- // Now make an expression from the rest of the operand.
- const MCExpr *IdVal;
- SMLoc EndLoc;
-
- if (getLexer().getKind() == AsmToken::LParen) {
- while (1) {
- Parser.Lex(); // Eat the '(' token.
- if (getLexer().getKind() == AsmToken::Percent) {
- Parser.Lex(); // Eat the % token.
- const AsmToken &nextTok = Parser.getTok();
- if (nextTok.isNot(AsmToken::Identifier))
- return true;
- Str += "(%";
- Str += nextTok.getIdentifier();
- Parser.Lex(); // Eat the identifier.
- if (getLexer().getKind() != AsmToken::LParen)
- return true;
- } else
- break;
- }
- if (getParser().parseParenExpression(IdVal, EndLoc))
- return true;
-
- while (getLexer().getKind() == AsmToken::RParen)
- Parser.Lex(); // Eat the ')' token.
-
- } else
- return true; // Parenthesis must follow the relocation operand.
-
- Res = evaluateRelocExpr(IdVal, Str);
- return false;
-}
-
bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
SMLoc &EndLoc) {
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands;
@@ -4317,45 +4636,21 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
}
bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) {
- MCAsmParser &Parser = getParser();
SMLoc S;
- bool Result = true;
- unsigned NumOfLParen = 0;
-
- while (getLexer().getKind() == AsmToken::LParen) {
- Parser.Lex();
- ++NumOfLParen;
- }
- switch (getLexer().getKind()) {
- default:
- return true;
- case AsmToken::Identifier:
- case AsmToken::LParen:
- case AsmToken::Integer:
- case AsmToken::Minus:
- case AsmToken::Plus:
- if (isParenExpr)
- Result = getParser().parseParenExprOfDepth(NumOfLParen, Res, S);
- else
- Result = (getParser().parseExpression(Res));
- while (getLexer().getKind() == AsmToken::RParen)
- Parser.Lex();
- break;
- case AsmToken::Percent:
- Result = parseRelocOperand(Res);
- }
- return Result;
+ if (isParenExpr)
+ return getParser().parseParenExprOfDepth(0, Res, S);
+ return getParser().parseExpression(Res);
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseMemOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
DEBUG(dbgs() << "parseMemOperand\n");
const MCExpr *IdVal = nullptr;
SMLoc S;
bool isParenExpr = false;
- MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch;
+ OperandMatchResultTy Res = MatchOperand_NoMatch;
// First operand is the offset.
S = Parser.getTok().getLoc();
@@ -4383,14 +4678,66 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) {
// Zero register assumed, add a memory operand with ZERO as its base.
// "Base" will be managed by k_Memory.
- auto Base = MipsOperand::createGPRReg(0, getContext().getRegisterInfo(),
- S, E, *this);
+ auto Base = MipsOperand::createGPRReg(
+ 0, "0", getContext().getRegisterInfo(), S, E, *this);
Operands.push_back(
MipsOperand::CreateMem(std::move(Base), IdVal, S, E, *this));
return MatchOperand_Success;
}
- Error(Parser.getTok().getLoc(), "'(' expected");
- return MatchOperand_ParseFail;
+ MCBinaryExpr::Opcode Opcode;
+ // GAS and LLVM treat comparison operators different. GAS will generate -1
+ // or 0, while LLVM will generate 0 or 1. Since a comparsion operator is
+ // highly unlikely to be found in a memory offset expression, we don't
+ // handle them.
+ switch (Tok.getKind()) {
+ case AsmToken::Plus:
+ Opcode = MCBinaryExpr::Add;
+ Parser.Lex();
+ break;
+ case AsmToken::Minus:
+ Opcode = MCBinaryExpr::Sub;
+ Parser.Lex();
+ break;
+ case AsmToken::Star:
+ Opcode = MCBinaryExpr::Mul;
+ Parser.Lex();
+ break;
+ case AsmToken::Pipe:
+ Opcode = MCBinaryExpr::Or;
+ Parser.Lex();
+ break;
+ case AsmToken::Amp:
+ Opcode = MCBinaryExpr::And;
+ Parser.Lex();
+ break;
+ case AsmToken::LessLess:
+ Opcode = MCBinaryExpr::Shl;
+ Parser.Lex();
+ break;
+ case AsmToken::GreaterGreater:
+ Opcode = MCBinaryExpr::LShr;
+ Parser.Lex();
+ break;
+ case AsmToken::Caret:
+ Opcode = MCBinaryExpr::Xor;
+ Parser.Lex();
+ break;
+ case AsmToken::Slash:
+ Opcode = MCBinaryExpr::Div;
+ Parser.Lex();
+ break;
+ case AsmToken::Percent:
+ Opcode = MCBinaryExpr::Mod;
+ Parser.Lex();
+ break;
+ default:
+ Error(Parser.getTok().getLoc(), "'(' or expression expected");
+ return MatchOperand_ParseFail;
+ }
+ const MCExpr * NextExpr;
+ if (getParser().parseExpression(NextExpr))
+ return MatchOperand_ParseFail;
+ IdVal = MCBinaryExpr::create(Opcode, IdVal, NextExpr, getContext());
}
Parser.Lex(); // Eat the '(' token.
@@ -4460,63 +4807,70 @@ bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) {
return false;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands,
StringRef Identifier,
SMLoc S) {
int Index = matchCPURegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createGPRReg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
Index = matchHWRegsRegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createHWRegsReg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
Index = matchFPURegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createFGRReg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
Index = matchFCCRegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createFCCReg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
Index = matchACRegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createACCReg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
Index = matchMSA128RegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createMSA128Reg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
Index = matchMSA128CtrlRegisterName(Identifier);
if (Index != -1) {
Operands.push_back(MipsOperand::createMSACtrlReg(
- Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this));
+ Index, Identifier, getContext().getRegisterInfo(), S,
+ getLexer().getLoc(), *this));
return MatchOperand_Success;
}
return MatchOperand_NoMatch;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) {
MCAsmParser &Parser = getParser();
auto Token = Parser.getLexer().peekTok(false);
@@ -4530,8 +4884,8 @@ MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) {
} else if (Token.is(AsmToken::Integer)) {
DEBUG(dbgs() << ".. integer\n");
Operands.push_back(MipsOperand::createNumericReg(
- Token.getIntVal(), getContext().getRegisterInfo(), S, Token.getLoc(),
- *this));
+ Token.getIntVal(), Token.getString(), getContext().getRegisterInfo(), S,
+ Token.getLoc(), *this));
return MatchOperand_Success;
}
@@ -4540,7 +4894,7 @@ MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) {
return MatchOperand_NoMatch;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseAnyRegister(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
DEBUG(dbgs() << "parseAnyRegister\n");
@@ -4568,48 +4922,19 @@ MipsAsmParser::parseAnyRegister(OperandVector &Operands) {
return ResTy;
}
-MipsAsmParser::OperandMatchResultTy
-MipsAsmParser::parseImm(OperandVector &Operands) {
- MCAsmParser &Parser = getParser();
- switch (getLexer().getKind()) {
- default:
- return MatchOperand_NoMatch;
- case AsmToken::LParen:
- case AsmToken::Minus:
- case AsmToken::Plus:
- case AsmToken::Integer:
- case AsmToken::Tilde:
- case AsmToken::String:
- break;
- }
-
- const MCExpr *IdVal;
- SMLoc S = Parser.getTok().getLoc();
- if (getParser().parseExpression(IdVal))
- return MatchOperand_ParseFail;
-
- SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this));
- return MatchOperand_Success;
-}
-
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseJumpTarget(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
DEBUG(dbgs() << "parseJumpTarget\n");
SMLoc S = getLexer().getLoc();
- // Integers and expressions are acceptable
- OperandMatchResultTy ResTy = parseImm(Operands);
- if (ResTy != MatchOperand_NoMatch)
- return ResTy;
-
// Registers are a valid target and have priority over symbols.
- ResTy = parseAnyRegister(Operands);
+ OperandMatchResultTy ResTy = parseAnyRegister(Operands);
if (ResTy != MatchOperand_NoMatch)
return ResTy;
+ // Integers and expressions are acceptable
const MCExpr *Expr = nullptr;
if (Parser.parseExpression(Expr)) {
// We have no way of knowing if a symbol was consumed so we must ParseFail
@@ -4620,7 +4945,7 @@ MipsAsmParser::parseJumpTarget(OperandVector &Operands) {
return MatchOperand_Success;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseInvNum(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const MCExpr *IdVal;
@@ -4639,7 +4964,7 @@ MipsAsmParser::parseInvNum(OperandVector &Operands) {
return MatchOperand_Success;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseRegisterList(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SmallVector<unsigned, 10> Regs;
@@ -4725,7 +5050,7 @@ MipsAsmParser::parseRegisterList(OperandVector &Operands) {
return MatchOperand_Success;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseRegisterPair(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
@@ -4741,7 +5066,7 @@ MipsAsmParser::parseRegisterPair(OperandVector &Operands) {
return MatchOperand_Success;
}
-MipsAsmParser::OperandMatchResultTy
+OperandMatchResultTy
MipsAsmParser::parseMovePRegPair(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands;
@@ -4793,12 +5118,10 @@ bool MipsAsmParser::parseParenSuffix(StringRef Name, OperandVector &Operands) {
Parser.Lex();
if (parseOperand(Operands, Name)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
if (Parser.getTok().isNot(AsmToken::RParen)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token, expected ')'");
}
Operands.push_back(
@@ -4823,12 +5146,10 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name,
Parser.Lex();
if (parseOperand(Operands, Name)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
if (Parser.getTok().isNot(AsmToken::RBrac)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token, expected ']'");
}
Operands.push_back(
@@ -4848,7 +5169,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Check if we have valid mnemonic
if (!mnemonicIsValid(Name, 0)) {
- Parser.eatToEndOfStatement();
return Error(NameLoc, "unknown instruction");
}
// First operand in MCInst is instruction mnemonic.
@@ -4859,7 +5179,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Read the first operand.
if (parseOperand(Operands, Name)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
if (getLexer().is(AsmToken::LBrac) && parseBracketSuffix(Name, Operands))
@@ -4871,7 +5190,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// Parse and remember the operand.
if (parseOperand(Operands, Name)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
// Parse bracket and parenthesis suffixes before we iterate
@@ -4885,7 +5203,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
if (getLexer().isNot(AsmToken::EndOfStatement)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
Parser.Lex(); // Consume the EndOfStatement.
@@ -4895,9 +5212,7 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// FIXME: Given that these have the same name, these should both be
// consistent on affecting the Parser.
bool MipsAsmParser::reportParseError(Twine ErrorMsg) {
- MCAsmParser &Parser = getParser();
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, ErrorMsg);
}
@@ -5398,7 +5713,6 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) {
MCAsmParser &Parser = getParser();
if (getLexer().isNot(AsmToken::Comma)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, ErrorStr);
}
@@ -5507,7 +5821,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() {
MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]);
if (!FuncRegOpnd.isGPRAsmReg()) {
reportParseError(FuncRegOpnd.getStartLoc(), "invalid register");
- Parser.eatToEndOfStatement();
return false;
}
@@ -5526,7 +5839,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() {
if (Parser.parseExpression(OffsetExpr) ||
!OffsetExpr->evaluateAsAbsolute(OffsetVal)) {
reportParseError(ExprLoc, "expected save register or stack offset");
- Parser.eatToEndOfStatement();
return false;
}
@@ -5536,7 +5848,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() {
MipsOperand &SaveOpnd = static_cast<MipsOperand &>(*TmpReg[0]);
if (!SaveOpnd.isGPRAsmReg()) {
reportParseError(SaveOpnd.getStartLoc(), "invalid register");
- Parser.eatToEndOfStatement();
return false;
}
Save = SaveOpnd.getGPR32Reg();
@@ -5740,7 +6051,79 @@ bool MipsAsmParser::parseDirectiveGpDWord() {
getParser().getStreamer().EmitGPRel64Value(Value);
if (getLexer().isNot(AsmToken::EndOfStatement))
- return Error(getLexer().getLoc(),
+ return Error(getLexer().getLoc(),
+ "unexpected token, expected end of statement");
+ Parser.Lex(); // Eat EndOfStatement token.
+ return false;
+}
+
+/// parseDirectiveDtpRelWord
+/// ::= .dtprelword tls_sym
+bool MipsAsmParser::parseDirectiveDtpRelWord() {
+ MCAsmParser &Parser = getParser();
+ const MCExpr *Value;
+ // EmitDTPRel32Value requires an expression, so we are using base class
+ // method to evaluate the expression.
+ if (getParser().parseExpression(Value))
+ return true;
+ getParser().getStreamer().EmitDTPRel32Value(Value);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return Error(getLexer().getLoc(),
+ "unexpected token, expected end of statement");
+ Parser.Lex(); // Eat EndOfStatement token.
+ return false;
+}
+
+/// parseDirectiveDtpRelDWord
+/// ::= .dtpreldword tls_sym
+bool MipsAsmParser::parseDirectiveDtpRelDWord() {
+ MCAsmParser &Parser = getParser();
+ const MCExpr *Value;
+ // EmitDTPRel64Value requires an expression, so we are using base class
+ // method to evaluate the expression.
+ if (getParser().parseExpression(Value))
+ return true;
+ getParser().getStreamer().EmitDTPRel64Value(Value);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return Error(getLexer().getLoc(),
+ "unexpected token, expected end of statement");
+ Parser.Lex(); // Eat EndOfStatement token.
+ return false;
+}
+
+/// parseDirectiveTpRelWord
+/// ::= .tprelword tls_sym
+bool MipsAsmParser::parseDirectiveTpRelWord() {
+ MCAsmParser &Parser = getParser();
+ const MCExpr *Value;
+ // EmitTPRel32Value requires an expression, so we are using base class
+ // method to evaluate the expression.
+ if (getParser().parseExpression(Value))
+ return true;
+ getParser().getStreamer().EmitTPRel32Value(Value);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return Error(getLexer().getLoc(),
+ "unexpected token, expected end of statement");
+ Parser.Lex(); // Eat EndOfStatement token.
+ return false;
+}
+
+/// parseDirectiveTpRelDWord
+/// ::= .tpreldword tls_sym
+bool MipsAsmParser::parseDirectiveTpRelDWord() {
+ MCAsmParser &Parser = getParser();
+ const MCExpr *Value;
+ // EmitTPRel64Value requires an expression, so we are using base class
+ // method to evaluate the expression.
+ if (getParser().parseExpression(Value))
+ return true;
+ getParser().getStreamer().EmitTPRel64Value(Value);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return Error(getLexer().getLoc(),
"unexpected token, expected end of statement");
Parser.Lex(); // Eat EndOfStatement token.
return false;
@@ -5752,9 +6135,8 @@ bool MipsAsmParser::parseDirectiveOption() {
AsmToken Tok = Parser.getTok();
// At the moment only identifiers are supported.
if (Tok.isNot(AsmToken::Identifier)) {
- Error(Parser.getTok().getLoc(), "unexpected token, expected identifier");
- Parser.eatToEndOfStatement();
- return false;
+ return Error(Parser.getTok().getLoc(),
+ "unexpected token, expected identifier");
}
StringRef Option = Tok.getIdentifier();
@@ -5766,9 +6148,8 @@ bool MipsAsmParser::parseDirectiveOption() {
getTargetStreamer().emitDirectiveOptionPic0();
Parser.Lex();
if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(),
- "unexpected token, expected end of statement");
- Parser.eatToEndOfStatement();
+ return Error(Parser.getTok().getLoc(),
+ "unexpected token, expected end of statement");
}
return false;
}
@@ -5780,9 +6161,8 @@ bool MipsAsmParser::parseDirectiveOption() {
getTargetStreamer().emitDirectiveOptionPic2();
Parser.Lex();
if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
- Error(Parser.getTok().getLoc(),
- "unexpected token, expected end of statement");
- Parser.eatToEndOfStatement();
+ return Error(Parser.getTok().getLoc(),
+ "unexpected token, expected end of statement");
}
return false;
}
@@ -5873,8 +6253,7 @@ bool MipsAsmParser::parseDirectiveModule() {
return false; // parseDirectiveModule has finished successfully.
} else if (Option == "nooddspreg") {
if (!isABI_O32()) {
- Error(L, "'.module nooddspreg' requires the O32 ABI");
- return false;
+ return Error(L, "'.module nooddspreg' requires the O32 ABI");
}
setModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg");
@@ -6295,6 +6674,26 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
return false;
}
+ if (IDVal == ".dtprelword") {
+ parseDirectiveDtpRelWord();
+ return false;
+ }
+
+ if (IDVal == ".dtpreldword") {
+ parseDirectiveDtpRelDWord();
+ return false;
+ }
+
+ if (IDVal == ".tprelword") {
+ parseDirectiveTpRelWord();
+ return false;
+ }
+
+ if (IDVal == ".tpreldword") {
+ parseDirectiveTpRelDWord();
+ return false;
+ }
+
if (IDVal == ".word") {
parseDataDirective(4, DirectiveID.getLoc());
return false;
@@ -6315,8 +6714,6 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {
if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
Error(Parser.getTok().getLoc(),
"unexpected token, expected end of statement");
- // Clear line
- Parser.eatToEndOfStatement();
}
return false;
}
@@ -6367,10 +6764,10 @@ bool MipsAsmParser::parseInternalDirectiveReallowModule() {
}
extern "C" void LLVMInitializeMipsAsmParser() {
- RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget);
- RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget);
- RegisterMCAsmParser<MipsAsmParser> A(TheMips64Target);
- RegisterMCAsmParser<MipsAsmParser> B(TheMips64elTarget);
+ RegisterMCAsmParser<MipsAsmParser> X(getTheMipsTarget());
+ RegisterMCAsmParser<MipsAsmParser> Y(getTheMipselTarget());
+ RegisterMCAsmParser<MipsAsmParser> A(getTheMips64Target());
+ RegisterMCAsmParser<MipsAsmParser> B(getTheMips64elTarget());
}
#define GET_REGISTER_MATCHER
diff --git a/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
index aebb4ef..f80efb1 100644
--- a/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
+++ b/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
@@ -439,6 +439,22 @@ static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address,
const void *Decoder);
template <typename InsnType>
+static DecodeStatus DecodeDAHIDATIMMR6(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder);
+
+template <typename InsnType>
+static DecodeStatus DecodeDAHIDATI(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder);
+
+template <typename InsnType>
+static DecodeStatus DecodeDAHIDATIMMR6(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder);
+
+template <typename InsnType>
+static DecodeStatus DecodeDAHIDATI(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder);
+
+template <typename InsnType>
static DecodeStatus
DecodeAddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address,
const void *Decoder);
@@ -460,6 +476,16 @@ DecodePOP37GroupBranchMMR6(MCInst &MI, InsnType insn, uint64_t Address,
template <typename InsnType>
static DecodeStatus
+DecodePOP65GroupBranchMMR6(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder);
+
+template <typename InsnType>
+static DecodeStatus
+DecodePOP75GroupBranchMMR6(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder);
+
+template <typename InsnType>
+static DecodeStatus
DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address,
const void *Decoder);
@@ -501,8 +527,10 @@ static DecodeStatus DecodeMovePRegPair(MCInst &Inst, unsigned Insn,
const void *Decoder);
namespace llvm {
-extern Target TheMipselTarget, TheMipsTarget, TheMips64Target,
- TheMips64elTarget;
+Target &getTheMipselTarget();
+Target &getTheMipsTarget();
+Target &getTheMips64Target();
+Target &getTheMips64elTarget();
}
static MCDisassembler *createMipsDisassembler(
@@ -521,13 +549,13 @@ static MCDisassembler *createMipselDisassembler(
extern "C" void LLVMInitializeMipsDisassembler() {
// Register the disassembler.
- TargetRegistry::RegisterMCDisassembler(TheMipsTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheMipsTarget(),
createMipsDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheMipselTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheMipselTarget(),
createMipselDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheMips64Target,
+ TargetRegistry::RegisterMCDisassembler(getTheMips64Target(),
createMipsDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheMips64elTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheMips64elTarget(),
createMipselDisassembler);
}
@@ -586,6 +614,34 @@ static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address,
}
template <typename InsnType>
+static DecodeStatus DecodeDAHIDATIMMR6(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder) {
+ InsnType Rs = fieldFromInstruction(insn, 16, 5);
+ InsnType Imm = fieldFromInstruction(insn, 0, 16);
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID,
+ Rs)));
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID,
+ Rs)));
+ MI.addOperand(MCOperand::createImm(Imm));
+
+ return MCDisassembler::Success;
+}
+
+template <typename InsnType>
+static DecodeStatus DecodeDAHIDATI(MCInst &MI, InsnType insn, uint64_t Address,
+ const void *Decoder) {
+ InsnType Rs = fieldFromInstruction(insn, 21, 5);
+ InsnType Imm = fieldFromInstruction(insn, 0, 16);
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID,
+ Rs)));
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID,
+ Rs)));
+ MI.addOperand(MCOperand::createImm(Imm));
+
+ return MCDisassembler::Success;
+}
+
+template <typename InsnType>
static DecodeStatus DecodeAddiGroupBranch(MCInst &MI, InsnType insn,
uint64_t Address,
const void *Decoder) {
@@ -630,7 +686,7 @@ static DecodeStatus DecodePOP35GroupBranchMMR6(MCInst &MI, InsnType insn,
const void *Decoder) {
InsnType Rt = fieldFromInstruction(insn, 21, 5);
InsnType Rs = fieldFromInstruction(insn, 16, 5);
- InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2;
+ int64_t Imm = 0;
if (Rs >= Rt) {
MI.setOpcode(Mips::BOVC_MMR6);
@@ -638,16 +694,19 @@ static DecodeStatus DecodePOP35GroupBranchMMR6(MCInst &MI, InsnType insn,
Rt)));
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rs)));
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
} else if (Rs != 0 && Rs < Rt) {
MI.setOpcode(Mips::BEQC_MMR6);
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rs)));
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rt)));
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4 + 4;
} else {
MI.setOpcode(Mips::BEQZALC_MMR6);
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rt)));
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
}
MI.addOperand(MCOperand::createImm(Imm));
@@ -700,7 +759,7 @@ static DecodeStatus DecodePOP37GroupBranchMMR6(MCInst &MI, InsnType insn,
const void *Decoder) {
InsnType Rt = fieldFromInstruction(insn, 21, 5);
InsnType Rs = fieldFromInstruction(insn, 16, 5);
- InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2;
+ int64_t Imm = 0;
if (Rs >= Rt) {
MI.setOpcode(Mips::BNVC_MMR6);
@@ -708,16 +767,19 @@ static DecodeStatus DecodePOP37GroupBranchMMR6(MCInst &MI, InsnType insn,
Rt)));
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rs)));
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
} else if (Rs != 0 && Rs < Rt) {
MI.setOpcode(Mips::BNEC_MMR6);
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rs)));
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rt)));
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4 + 4;
} else {
MI.setOpcode(Mips::BNEZALC_MMR6);
MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
Rt)));
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
}
MI.addOperand(MCOperand::createImm(Imm));
@@ -726,6 +788,84 @@ static DecodeStatus DecodePOP37GroupBranchMMR6(MCInst &MI, InsnType insn,
}
template <typename InsnType>
+static DecodeStatus DecodePOP65GroupBranchMMR6(MCInst &MI, InsnType insn,
+ uint64_t Address,
+ const void *Decoder) {
+ // We have:
+ // 0b110101 ttttt sssss iiiiiiiiiiiiiiii
+ // Invalid if rt == 0
+ // BGTZC_MMR6 if rs == 0 && rt != 0
+ // BLTZC_MMR6 if rs == rt && rt != 0
+ // BLTC_MMR6 if rs != rt && rs != 0 && rt != 0
+
+ InsnType Rt = fieldFromInstruction(insn, 21, 5);
+ InsnType Rs = fieldFromInstruction(insn, 16, 5);
+ int64_t Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4 + 4;
+ bool HasRs = false;
+
+ if (Rt == 0)
+ return MCDisassembler::Fail;
+ else if (Rs == 0)
+ MI.setOpcode(Mips::BGTZC_MMR6);
+ else if (Rs == Rt)
+ MI.setOpcode(Mips::BLTZC_MMR6);
+ else {
+ MI.setOpcode(Mips::BLTC_MMR6);
+ HasRs = true;
+ }
+
+ if (HasRs)
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
+ Rs)));
+
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
+ Rt)));
+
+ MI.addOperand(MCOperand::createImm(Imm));
+
+ return MCDisassembler::Success;
+}
+
+template <typename InsnType>
+static DecodeStatus DecodePOP75GroupBranchMMR6(MCInst &MI, InsnType insn,
+ uint64_t Address,
+ const void *Decoder) {
+ // We have:
+ // 0b111101 ttttt sssss iiiiiiiiiiiiiiii
+ // Invalid if rt == 0
+ // BLEZC_MMR6 if rs == 0 && rt != 0
+ // BGEZC_MMR6 if rs == rt && rt != 0
+ // BGEC_MMR6 if rs != rt && rs != 0 && rt != 0
+
+ InsnType Rt = fieldFromInstruction(insn, 21, 5);
+ InsnType Rs = fieldFromInstruction(insn, 16, 5);
+ int64_t Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4 + 4;
+ bool HasRs = false;
+
+ if (Rt == 0)
+ return MCDisassembler::Fail;
+ else if (Rs == 0)
+ MI.setOpcode(Mips::BLEZC_MMR6);
+ else if (Rs == Rt)
+ MI.setOpcode(Mips::BGEZC_MMR6);
+ else {
+ HasRs = true;
+ MI.setOpcode(Mips::BGEC_MMR6);
+ }
+
+ if (HasRs)
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
+ Rs)));
+
+ MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID,
+ Rt)));
+
+ MI.addOperand(MCOperand::createImm(Imm));
+
+ return MCDisassembler::Success;
+}
+
+template <typename InsnType>
static DecodeStatus DecodeBlezlGroupBranch(MCInst &MI, InsnType insn,
uint64_t Address,
const void *Decoder) {
@@ -904,7 +1044,7 @@ static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn,
}
/// Read two bytes from the ArrayRef and return 16 bit halfword sorted
-/// according to the given endianess.
+/// according to the given endianness.
static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn,
bool IsBigEndian) {
@@ -924,7 +1064,7 @@ static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
}
/// Read four bytes from the ArrayRef and return 32 bit word sorted
-/// according to the given endianess
+/// according to the given endianness.
static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn,
bool IsBigEndian, bool IsMicroMips) {
@@ -1662,7 +1802,7 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst,
break;
case Mips::SC_MM:
Inst.addOperand(MCOperand::createReg(Reg));
- // fallthrough
+ LLVM_FALLTHROUGH;
default:
Inst.addOperand(MCOperand::createReg(Reg));
if (Inst.getOpcode() == Mips::LWP_MM || Inst.getOpcode() == Mips::SWP_MM ||
@@ -2008,7 +2148,7 @@ static DecodeStatus DecodeBranchTarget21MM(MCInst &Inst,
unsigned Offset,
uint64_t Address,
const void *Decoder) {
- int32_t BranchOffset = SignExtend32<21>(Offset) << 1;
+ int32_t BranchOffset = SignExtend32<21>(Offset) * 4 + 4;
Inst.addOperand(MCOperand::createImm(BranchOffset));
return MCDisassembler::Success;
@@ -2046,7 +2186,7 @@ static DecodeStatus DecodeBranchTargetMM(MCInst &Inst,
unsigned Offset,
uint64_t Address,
const void *Decoder) {
- int32_t BranchOffset = SignExtend32<16>(Offset) * 2;
+ int32_t BranchOffset = SignExtend32<16>(Offset) * 2 + 4;
Inst.addOperand(MCOperand::createImm(BranchOffset));
return MCDisassembler::Success;
}
@@ -2285,7 +2425,7 @@ static DecodeStatus DecodeBgtzGroupBranchMMR6(MCInst &MI, InsnType insn,
InsnType Rt = fieldFromInstruction(insn, 21, 5);
InsnType Rs = fieldFromInstruction(insn, 16, 5);
- InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2;
+ InsnType Imm = 0;
bool HasRs = false;
bool HasRt = false;
@@ -2294,15 +2434,18 @@ static DecodeStatus DecodeBgtzGroupBranchMMR6(MCInst &MI, InsnType insn,
else if (Rs == 0) {
MI.setOpcode(Mips::BGTZALC_MMR6);
HasRt = true;
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
}
else if (Rs == Rt) {
MI.setOpcode(Mips::BLTZALC_MMR6);
HasRs = true;
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
}
else {
MI.setOpcode(Mips::BLTUC_MMR6);
HasRs = true;
HasRt = true;
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4 + 4;
}
if (HasRs)
@@ -2324,25 +2467,30 @@ static DecodeStatus DecodeBlezGroupBranchMMR6(MCInst &MI, InsnType insn,
const void *Decoder) {
// We have:
// 0b000110 ttttt sssss iiiiiiiiiiiiiiii
- // Invalid if rs == 0
+ // Invalid if rt == 0
// BLEZALC_MMR6 if rs == 0 && rt != 0
// BGEZALC_MMR6 if rs == rt && rt != 0
// BGEUC_MMR6 if rs != rt && rs != 0 && rt != 0
InsnType Rt = fieldFromInstruction(insn, 21, 5);
InsnType Rs = fieldFromInstruction(insn, 16, 5);
- InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2;
+ InsnType Imm = 0;
bool HasRs = false;
if (Rt == 0)
return MCDisassembler::Fail;
- else if (Rs == 0)
+ else if (Rs == 0) {
MI.setOpcode(Mips::BLEZALC_MMR6);
- else if (Rs == Rt)
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
+ }
+ else if (Rs == Rt) {
MI.setOpcode(Mips::BGEZALC_MMR6);
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 2 + 4;
+ }
else {
HasRs = true;
MI.setOpcode(Mips::BGEUC_MMR6);
+ Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4 + 4;
}
if (HasRs)
diff --git a/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
index 0fd593f..49c42fd 100644
--- a/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
@@ -236,6 +236,7 @@ bool MipsInstPrinter::printAlias(const MCInst &MI, raw_ostream &OS) {
// beq $r0, $zero, $L2 => beqz $r0, $L2
return isReg<Mips::ZERO_64>(MI, 1) && printAlias("beqz", MI, 0, 2, OS);
case Mips::BNE:
+ case Mips::BNE_MM:
// bne $r0, $zero, $L2 => bnez $r0, $L2
return isReg<Mips::ZERO>(MI, 1) && printAlias("bnez", MI, 0, 2, OS);
case Mips::BNE64:
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index 3cf632e..498ea6f 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -51,12 +51,11 @@ MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef CPU,
const MCTargetOptions &Options) {
if (Options.getABIName().startswith("o32"))
return MipsABIInfo::O32();
- else if (Options.getABIName().startswith("n32"))
+ if (Options.getABIName().startswith("n32"))
return MipsABIInfo::N32();
- else if (Options.getABIName().startswith("n64"))
+ if (Options.getABIName().startswith("n64"))
return MipsABIInfo::N64();
- else if (!Options.getABIName().empty())
- llvm_unreachable("Unknown ABI option for MIPS");
+ assert(Options.getABIName().empty() && "Unknown ABI option for MIPS");
if (TT.getArch() == Triple::mips64 || TT.getArch() == Triple::mips64el)
return MipsABIInfo::N64();
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index 8292d6b..38b11f7 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -59,9 +59,15 @@ static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case Mips::fixup_MIPS_PCLO16:
Value &= 0xffff;
break;
+ case FK_DTPRel_4:
+ case FK_DTPRel_8:
+ case FK_TPRel_4:
+ case FK_TPRel_8:
case FK_GPRel_4:
case FK_Data_4:
case FK_Data_8:
+ case Mips::fixup_Mips_SUB:
+ case Mips::fixup_MICROMIPS_SUB:
break;
case Mips::fixup_Mips_PC16:
// The displacement is then divided by 4 to give us an 18 bit
@@ -361,7 +367,9 @@ getFixupKindInfo(MCFixupKind Kind) const {
{ "fixup_MICROMIPS_TLS_DTPREL_HI16", 0, 16, 0 },
{ "fixup_MICROMIPS_TLS_DTPREL_LO16", 0, 16, 0 },
{ "fixup_MICROMIPS_TLS_TPREL_HI16", 0, 16, 0 },
- { "fixup_MICROMIPS_TLS_TPREL_LO16", 0, 16, 0 }
+ { "fixup_MICROMIPS_TLS_TPREL_LO16", 0, 16, 0 },
+ { "fixup_Mips_SUB", 0, 64, 0 },
+ { "fixup_MICROMIPS_SUB", 0, 64, 0 }
};
const static MCFixupKindInfo BigEndianInfos[Mips::NumTargetFixupKinds] = {
@@ -430,7 +438,9 @@ getFixupKindInfo(MCFixupKind Kind) const {
{ "fixup_MICROMIPS_TLS_DTPREL_HI16", 16, 16, 0 },
{ "fixup_MICROMIPS_TLS_DTPREL_LO16", 16, 16, 0 },
{ "fixup_MICROMIPS_TLS_TPREL_HI16", 16, 16, 0 },
- { "fixup_MICROMIPS_TLS_TPREL_LO16", 16, 16, 0 }
+ { "fixup_MICROMIPS_TLS_TPREL_LO16", 16, 16, 0 },
+ { "fixup_Mips_SUB", 0, 64, 0 },
+ { "fixup_MICROMIPS_SUB", 0, 64, 0 }
};
if (Kind < FirstTargetFixupKind)
@@ -482,27 +492,31 @@ void MipsAsmBackend::processFixupValue(const MCAssembler &Asm,
// MCAsmBackend
MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ true,
/*Is64Bit*/ false);
}
MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ false,
/*Is64Bit*/ false);
}
MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ true, /*Is64Bit*/ true);
}
MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
return new MipsAsmBackend(T, TT.getOS(), /*IsLittle*/ false,
/*Is64Bit*/ true);
}
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index 2bcff88..a90db23 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -120,7 +120,12 @@ namespace MipsII {
/// IsCTI - Instruction is a Control Transfer Instruction.
IsCTI = 1 << 4,
/// HasForbiddenSlot - Instruction has a forbidden slot.
- HasForbiddenSlot = 1 << 5
+ HasForbiddenSlot = 1 << 5,
+ /// IsPCRelativeLoad - A Load instruction with implicit source register
+ /// ($pc) with explicit offset and destination register
+ IsPCRelativeLoad = 1 << 6,
+ /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
+ HasFCCRegOperand = 1 << 7
};
}
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
index 20c5f36..b2efd72 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -270,6 +270,14 @@ unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
case Mips::fixup_Mips_64:
case FK_Data_8:
return ELF::R_MIPS_64;
+ case FK_DTPRel_4:
+ return ELF::R_MIPS_TLS_DTPREL32;
+ case FK_DTPRel_8:
+ return ELF::R_MIPS_TLS_DTPREL64;
+ case FK_TPRel_4:
+ return ELF::R_MIPS_TLS_TPREL32;
+ case FK_TPRel_8:
+ return ELF::R_MIPS_TLS_TPREL64;
case FK_GPRel_4:
if (isN64()) {
unsigned Type = (unsigned)ELF::R_MIPS_NONE;
@@ -329,6 +337,8 @@ unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
return ELF::R_MIPS_HIGHER;
case Mips::fixup_Mips_HIGHEST:
return ELF::R_MIPS_HIGHEST;
+ case Mips::fixup_Mips_SUB:
+ return ELF::R_MIPS_SUB;
case Mips::fixup_Mips_GOT_HI16:
return ELF::R_MIPS_GOT_HI16;
case Mips::fixup_Mips_GOT_LO16:
@@ -365,6 +375,8 @@ unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
return ELF::R_MICROMIPS_TLS_TPREL_HI16;
case Mips::fixup_MICROMIPS_TLS_TPREL_LO16:
return ELF::R_MICROMIPS_TLS_TPREL_LO16;
+ case Mips::fixup_MICROMIPS_SUB:
+ return ELF::R_MICROMIPS_SUB;
}
llvm_unreachable("invalid fixup kind!");
@@ -407,6 +419,13 @@ unsigned MipsELFObjectWriter::getRelocType(MCContext &Ctx,
/// always match using the expressions from the source.
void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
std::vector<ELFRelocationEntry> &Relocs) {
+
+ // We do not need to sort the relocation table for RELA relocations which
+ // N32/N64 uses as the relocation addend contains the value we require,
+ // rather than it being split across a pair of relocations.
+ if (hasRelocationAddend())
+ return;
+
if (Relocs.size() < 2)
return;
@@ -527,7 +546,7 @@ bool MipsELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
case ELF::R_MIPS_GPREL32:
if (cast<MCSymbolELF>(Sym).getOther() & ELF::STO_MIPS_MICROMIPS)
return true;
- // fallthrough
+ LLVM_FALLTHROUGH;
case ELF::R_MIPS_26:
case ELF::R_MIPS_64:
case ELF::R_MIPS_GPREL16:
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
index b4d8e94..1492962 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
@@ -209,6 +209,10 @@ namespace Mips {
// resulting in - R_MICROMIPS_TLS_TPREL_LO16
fixup_MICROMIPS_TLS_TPREL_LO16,
+ // resulting in - R_MIPS_SUB/R_MICROMIPS_SUB
+ fixup_Mips_SUB,
+ fixup_MICROMIPS_SUB,
+
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
index 1ce8f07..a44a35f 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
@@ -45,13 +45,22 @@ MipsMCAsmInfo::MipsMCAsmInfo(const Triple &TheTriple) {
ZeroDirective = "\t.space\t";
GPRel32Directive = "\t.gpword\t";
GPRel64Directive = "\t.gpdword\t";
+ DTPRel32Directive = "\t.dtprelword\t";
+ DTPRel64Directive = "\t.dtpreldword\t";
+ TPRel32Directive = "\t.tprelword\t";
+ TPRel64Directive = "\t.tpreldword\t";
UseAssignmentForEHBegin = true;
SupportsDebugInformation = true;
ExceptionsType = ExceptionHandling::DwarfCFI;
DwarfRegNumForCFI = true;
+ HasMipsExpressions = true;
// Enable IAS by default for O32.
if (TheTriple.getArch() == Triple::mips ||
TheTriple.getArch() == Triple::mipsel)
UseIntegratedAssembler = true;
+
+ // Enable IAS by default for Debian mips64/mips64el.
+ if (TheTriple.getEnvironment() == Triple::GNUABI64)
+ UseIntegratedAssembler = true;
}
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index 401c7d4..0614316 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -129,7 +129,8 @@ void MipsMCCodeEmitter::LowerCompactBranch(MCInst& Inst) const {
unsigned Reg0 = Ctx.getRegisterInfo()->getEncodingValue(RegOp0);
unsigned Reg1 = Ctx.getRegisterInfo()->getEncodingValue(RegOp1);
- if (Inst.getOpcode() == Mips::BNEC || Inst.getOpcode() == Mips::BEQC) {
+ if (Inst.getOpcode() == Mips::BNEC || Inst.getOpcode() == Mips::BEQC ||
+ Inst.getOpcode() == Mips::BNEC64 || Inst.getOpcode() == Mips::BEQC64) {
assert(Reg0 != Reg1 && "Instruction has bad operands ($rs == $rt)!");
if (Reg0 < Reg1)
return;
@@ -141,7 +142,7 @@ void MipsMCCodeEmitter::LowerCompactBranch(MCInst& Inst) const {
if (Reg1 >= Reg0)
return;
} else
- llvm_unreachable("Cannot rewrite unknown branch!");
+ llvm_unreachable("Cannot rewrite unknown branch!");
Inst.getOperand(0).setReg(RegOp1);
Inst.getOperand(1).setReg(RegOp0);
@@ -210,6 +211,8 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
// Compact branches, enforce encoding restrictions.
case Mips::BEQC:
case Mips::BNEC:
+ case Mips::BEQC64:
+ case Mips::BNEC64:
case Mips::BOVC:
case Mips::BOVC_MMR6:
case Mips::BNVC:
@@ -332,6 +335,30 @@ getBranchTargetOpValueMMR6(const MCInst &MI, unsigned OpNo,
return 0;
}
+/// getBranchTargetOpValueLsl2MMR6 - Return binary encoding of the branch
+/// target operand. If the machine operand requires relocation,
+/// record the relocation and return zero.
+unsigned MipsMCCodeEmitter::
+getBranchTargetOpValueLsl2MMR6(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+
+ const MCOperand &MO = MI.getOperand(OpNo);
+
+ // If the destination is an immediate, divide by 4.
+ if (MO.isImm())
+ return MO.getImm() >> 2;
+
+ assert(MO.isExpr() &&
+ "getBranchTargetOpValueLsl2MMR6 expects only expressions or immediates");
+
+ const MCExpr *FixupExpression = MCBinaryExpr::createAdd(
+ MO.getExpr(), MCConstantExpr::create(-4, Ctx), Ctx);
+ Fixups.push_back(MCFixup::create(0, FixupExpression,
+ MCFixupKind(Mips::fixup_Mips_PC16)));
+ return 0;
+}
+
/// getBranchTarget7OpValueMM - Return binary encoding of the microMIPS branch
/// target operand. If the machine operand requires relocation,
/// record the relocation and return zero.
@@ -432,8 +459,8 @@ getBranchTarget21OpValueMM(const MCInst &MI, unsigned OpNo,
const MCOperand &MO = MI.getOperand(OpNo);
- // If the destination is an immediate, divide by 2.
- if (MO.isImm()) return MO.getImm() >> 1;
+ // If the destination is an immediate, divide by 4.
+ if (MO.isImm()) return MO.getImm() >> 2;
assert(MO.isExpr() &&
"getBranchTarget21OpValueMM expects only expressions or immediates");
@@ -634,7 +661,6 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
Mips::Fixups FixupKind = Mips::Fixups(0);
switch (MipsExpr->getKind()) {
- case MipsMCExpr::MEK_NEG:
case MipsMCExpr::MEK_None:
case MipsMCExpr::MEK_Special:
llvm_unreachable("Unhandled fixup kind!");
@@ -732,6 +758,10 @@ getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_TPREL_LO16
: Mips::fixup_Mips_TPREL_LO;
break;
+ case MipsMCExpr::MEK_NEG:
+ FixupKind =
+ isMicroMips(STI) ? Mips::fixup_MICROMIPS_SUB : Mips::fixup_Mips_SUB;
+ break;
}
Fixups.push_back(MCFixup::create(0, MipsExpr, MCFixupKind(FixupKind)));
return 0;
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
index 0f4dfe1..2d041dc 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
@@ -116,6 +116,13 @@ public:
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ // getBranchTargetOpValueLsl2MMR6 - Return binary encoding of the branch
+ // target operand. If the machine operand requires relocation,
+ // record the relocation and return zero.
+ unsigned getBranchTargetOpValueLsl2MMR6(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
// getBranchTarget7OpValue - Return binary encoding of the microMIPS branch
// target operand. If the machine operand requires relocation,
// record the relocation and return zero.
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
index a055739..56fe185 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
@@ -149,8 +149,8 @@ static MCInstrAnalysis *createMipsMCInstrAnalysis(const MCInstrInfo *Info) {
}
extern "C" void LLVMInitializeMipsTargetMC() {
- for (Target *T : {&TheMipsTarget, &TheMipselTarget, &TheMips64Target,
- &TheMips64elTarget}) {
+ for (Target *T : {&getTheMipsTarget(), &getTheMipselTarget(),
+ &getTheMips64Target(), &getTheMips64elTarget()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createMipsMCAsmInfo);
@@ -183,20 +183,19 @@ extern "C" void LLVMInitializeMipsTargetMC() {
}
// Register the MC Code Emitter
- for (Target *T : {&TheMipsTarget, &TheMips64Target})
+ for (Target *T : {&getTheMipsTarget(), &getTheMips64Target()})
TargetRegistry::RegisterMCCodeEmitter(*T, createMipsMCCodeEmitterEB);
- for (Target *T : {&TheMipselTarget, &TheMips64elTarget})
+ for (Target *T : {&getTheMipselTarget(), &getTheMips64elTarget()})
TargetRegistry::RegisterMCCodeEmitter(*T, createMipsMCCodeEmitterEL);
// Register the asm backend.
- TargetRegistry::RegisterMCAsmBackend(TheMipsTarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheMipsTarget(),
createMipsAsmBackendEB32);
- TargetRegistry::RegisterMCAsmBackend(TheMipselTarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheMipselTarget(),
createMipsAsmBackendEL32);
- TargetRegistry::RegisterMCAsmBackend(TheMips64Target,
+ TargetRegistry::RegisterMCAsmBackend(getTheMips64Target(),
createMipsAsmBackendEB64);
- TargetRegistry::RegisterMCAsmBackend(TheMips64elTarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheMips64elTarget(),
createMipsAsmBackendEL64);
-
}
diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
index 4069d7d..b28681f 100644
--- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
@@ -24,16 +24,17 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
class StringRef;
class Target;
class Triple;
class raw_ostream;
class raw_pwrite_stream;
-extern Target TheMipsTarget;
-extern Target TheMipselTarget;
-extern Target TheMips64Target;
-extern Target TheMips64elTarget;
+Target &getTheMipsTarget();
+Target &getTheMipselTarget();
+Target &getTheMips64Target();
+Target &getTheMips64elTarget();
MCCodeEmitter *createMipsMCCodeEmitterEB(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
@@ -44,16 +45,20 @@ MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII,
MCAsmBackend *createMipsAsmBackendEB32(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createMipsAsmBackendEL32(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createMipsAsmBackendEB64(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createMipsAsmBackendEL64(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createMipsELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI,
bool IsLittleEndian, bool Is64Bit);
diff --git a/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
index 2b636cf..fd04f80 100644
--- a/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/MicroMips32r6InstrInfo.td
@@ -32,6 +32,15 @@ def brtargetr6 : Operand<OtherVT> {
let ParserMatchClass = MipsJumpTargetAsmOperand;
}
+def brtarget_lsl2_mm : Operand<OtherVT> {
+ let EncoderMethod = "getBranchTargetOpValueLsl2MMR6";
+ let OperandType = "OPERAND_PCREL";
+ // Instructions that use this operand have their decoder method
+ // set with DecodeDisambiguates
+ let DecoderMethod = "";
+ let ParserMatchClass = MipsJumpTargetAsmOperand;
+}
+
//===----------------------------------------------------------------------===//
//
// Instruction Encodings
@@ -56,16 +65,28 @@ class BITSWAP_MMR6_ENC : POOL32A_BITSWAP_FM_MMR6<0b101100>;
class BRK_MMR6_ENC : BREAK_MMR6_ENC<"break">;
class BEQZC_MMR6_ENC : CMP_BRANCH_OFF21_FM_MMR6<"beqzc", 0b100000>;
class BNEZC_MMR6_ENC : CMP_BRANCH_OFF21_FM_MMR6<"bnezc", 0b101000>;
-class BGEC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bgec", 0b111001>;
+class BGEC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bgec", 0b111101>,
+ DecodeDisambiguates<"POP75GroupBranchMMR6">;
class BGEUC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bgeuc", 0b110000>,
DecodeDisambiguates<"BlezGroupBranchMMR6">;
-class BLTC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bltc", 0b110001>;
+class BLTC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bltc", 0b110101>,
+ DecodeDisambiguates<"POP65GroupBranchMMR6">;
class BLTUC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bltuc", 0b111000>,
DecodeDisambiguates<"BgtzGroupBranchMMR6">;
class BEQC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"beqc", 0b011101>;
class BNEC_MMR6_ENC : CMP_BRANCH_2R_OFF16_FM_MMR6<"bnec", 0b011111>;
-class BEQZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"beqzalc", 0b011101>;
-class BNEZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bnezalc", 0b011111>;
+class BLTZC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bltzc", 0b110101>,
+ DecodeDisambiguates<"POP65GroupBranchMMR6">;
+class BLEZC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"blezc", 0b111101>,
+ DecodeDisambiguates<"POP75GroupBranchMMR6">;
+class BGEZC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bgezc", 0b111101>,
+ DecodeDisambiguates<"POP75GroupBranchMMR6">;
+class BGTZC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bgtzc", 0b110101>,
+ DecodeDisambiguates<"POP65GroupBranchMMR6">;
+class BEQZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"beqzalc", 0b011101>,
+ DecodeDisambiguates<"POP35GroupBranchMMR6">;
+class BNEZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bnezalc", 0b011111>,
+ DecodeDisambiguates<"POP37GroupBranchMMR6">;
class BGTZALC_MMR6_ENC : CMP_BRANCH_1R_RT_OFF16_FM_MMR6<"bgtzalc", 0b111000>,
MMDecodeDisambiguatedBy<"BgtzGroupBranchMMR6">;
class BLTZALC_MMR6_ENC : CMP_BRANCH_1R_BOTH_OFF16_FM_MMR6<"bltzalc", 0b111000>,
@@ -165,8 +186,6 @@ class TRUNC_W_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.w.s", 0, 0b10101100>;
class TRUNC_W_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"trunc.w.d", 1, 0b10101100>;
class SQRT_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"sqrt.s", 0, 0b00101000>;
class SQRT_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"sqrt.d", 1, 0b00101000>;
-class RSQRT_S_MMR6_ENC : POOL32F_MATH_FM_MMR6<"rsqrt.s", 0, 0b00001000>;
-class RSQRT_D_MMR6_ENC : POOL32F_MATH_FM_MMR6<"rsqrt.d", 1, 0b00001000>;
class SB_MMR6_ENC : SB32_SH32_STORE_FM_MMR6<0b000110>;
class SBE_MMR6_ENC : POOL32C_STORE_EVA_FM_MMR6<0b100>;
class SCE_MMR6_ENC : POOL32C_STORE_EVA_FM_MMR6<0b110>;
@@ -177,8 +196,6 @@ class LWE_MMR6_ENC : LOAD_WORD_EVA_FM_MMR6<0b111>;
class LW_MMR6_ENC : LOAD_WORD_FM_MMR6;
class LUI_MMR6_ENC : LOAD_UPPER_IMM_FM_MMR6;
class JALRC_HB_MMR6_ENC : POOL32A_JALRC_FM_MMR6<"jalrc.hb", 0b0001111100>;
-class RECIP_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"recip.s", 0, 0b01001000>;
-class RECIP_D_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"recip.d", 1, 0b01001000>;
class RINT_S_MMR6_ENC : POOL32F_RINT_FM_MMR6<"rint.s", 0>;
class RINT_D_MMR6_ENC : POOL32F_RINT_FM_MMR6<"rint.d", 1>;
class ROUND_L_S_MMR6_ENC : POOL32F_RECIP_ROUND_FM_MMR6<"round.l.s", 0,
@@ -230,6 +247,49 @@ class SDC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"sdc2", 0b1010>;
class LWC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"lwc2", 0b0000>;
class SWC2_MMR6_ENC : POOL32B_LDWC2_SDWC2_FM_MMR6<"swc2", 0b1000>;
+/// Floating Point Instructions
+class FADD_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.s", 0, 0b00110000>;
+class FADD_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.d", 1, 0b00110000>;
+class FSUB_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.s", 0, 0b01110000>;
+class FSUB_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.d", 1, 0b01110000>;
+class FMUL_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.s", 0, 0b10110000>;
+class FMUL_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.d", 1, 0b10110000>;
+class FDIV_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.s", 0, 0b11110000>;
+class FDIV_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.d", 1, 0b11110000>;
+class MADDF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.s", 0, 0b110111000>;
+class MADDF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.d", 1, 0b110111000>;
+class MSUBF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.s", 0, 0b111111000>;
+class MSUBF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.d", 1, 0b111111000>;
+class FMOV_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.s", 0, 0b0000001>;
+class FMOV_D_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.d", 1, 0b0000001>;
+class FNEG_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.s", 0, 0b0101101>;
+class FNEG_D_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.d", 1, 0b0101101>;
+class MAX_S_MMR6_ENC : POOL32F_MINMAX_FM<"max.s", 0, 0b000001011>;
+class MAX_D_MMR6_ENC : POOL32F_MINMAX_FM<"max.d", 1, 0b000001011>;
+class MAXA_S_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.s", 0, 0b000101011>;
+class MAXA_D_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.d", 1, 0b000101011>;
+class MIN_S_MMR6_ENC : POOL32F_MINMAX_FM<"min.s", 0, 0b000000011>;
+class MIN_D_MMR6_ENC : POOL32F_MINMAX_FM<"min.d", 1, 0b000000011>;
+class MINA_S_MMR6_ENC : POOL32F_MINMAX_FM<"mina.s", 0, 0b000100011>;
+class MINA_D_MMR6_ENC : POOL32F_MINMAX_FM<"mina.d", 1, 0b000100011>;
+
+class CVT_L_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.s", 0, 0b00000100>;
+class CVT_L_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.d", 1, 0b00000100>;
+class CVT_W_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.s", 0, 0b00100100>;
+class CVT_W_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.d", 1, 0b00100100>;
+class CVT_D_S_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.s", 0, 0b1001101>;
+class CVT_D_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.w", 1, 0b1001101>;
+class CVT_D_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.l", 2, 0b1001101>;
+class CVT_S_D_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.d", 0, 0b1101101>;
+class CVT_S_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.w", 1, 0b1101101>;
+class CVT_S_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.l", 2, 0b1101101>;
+
+//===----------------------------------------------------------------------===//
+//
+// Instruction Descriptions
+//
+//===----------------------------------------------------------------------===//
+
class CMP_CBR_RT_Z_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd,
RegisterOperand GPROpnd>
: BRANCH_DESC_BASE {
@@ -237,6 +297,7 @@ class CMP_CBR_RT_Z_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd,
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$rt, $offset");
list<Register> Defs = [AT];
+ InstrItinClass Itinerary = II_BCCZC;
}
class BEQZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"beqzalc", brtarget_mm,
@@ -269,91 +330,59 @@ class BNEZALC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bnezalc", brtarget_mm,
list<Register> Defs = [RA];
}
+class BLTZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bltzc", brtarget_lsl2_mm,
+ GPR32Opnd>;
+class BLEZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"blezc", brtarget_lsl2_mm,
+ GPR32Opnd>;
+class BGEZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgezc", brtarget_lsl2_mm,
+ GPR32Opnd>;
+class BGTZC_MMR6_DESC : CMP_CBR_RT_Z_MMR6_DESC_BASE<"bgtzc", brtarget_lsl2_mm,
+ GPR32Opnd>;
+
class CMP_CBR_2R_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd,
RegisterOperand GPROpnd> : BRANCH_DESC_BASE {
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, opnd:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $offset");
list<Register> Defs = [AT];
+ InstrItinClass Itinerary = II_BCCC;
}
-class BGEC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bgec", brtarget_mm,
+class BGEC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bgec", brtarget_lsl2_mm,
GPR32Opnd>;
-class BGEUC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bgeuc", brtarget_mm,
+class BGEUC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bgeuc", brtarget_lsl2_mm,
GPR32Opnd>;
-class BLTC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bltc", brtarget_mm,
+class BLTC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bltc", brtarget_lsl2_mm,
GPR32Opnd>;
-class BLTUC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bltuc", brtarget_mm,
+class BLTUC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bltuc", brtarget_lsl2_mm,
GPR32Opnd>;
-class BEQC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"beqc", brtarget_mm,
+class BEQC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"beqc", brtarget_lsl2_mm,
GPR32Opnd>;
-class BNEC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bnec", brtarget_mm,
+class BNEC_MMR6_DESC : CMP_CBR_2R_MMR6_DESC_BASE<"bnec", brtarget_lsl2_mm,
GPR32Opnd>;
-/// Floating Point Instructions
-class FADD_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.s", 0, 0b00110000>;
-class FADD_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"add.d", 1, 0b00110000>;
-class FSUB_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.s", 0, 0b01110000>;
-class FSUB_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"sub.d", 1, 0b01110000>;
-class FMUL_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.s", 0, 0b10110000>;
-class FMUL_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"mul.d", 1, 0b10110000>;
-class FDIV_S_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.s", 0, 0b11110000>;
-class FDIV_D_MMR6_ENC : POOL32F_ARITH_FM_MMR6<"div.d", 1, 0b11110000>;
-class MADDF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.s", 0, 0b110111000>;
-class MADDF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"maddf.d", 1, 0b110111000>;
-class MSUBF_S_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.s", 0, 0b111111000>;
-class MSUBF_D_MMR6_ENC : POOL32F_ARITHF_FM_MMR6<"msubf.d", 1, 0b111111000>;
-class FMOV_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.s", 0, 0b0000001>;
-class FMOV_D_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"mov.d", 1, 0b0000001>;
-class FNEG_S_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.s", 0, 0b0101101>;
-class FNEG_D_MMR6_ENC : POOL32F_MOV_NEG_FM_MMR6<"neg.d", 1, 0b0101101>;
-class MAX_S_MMR6_ENC : POOL32F_MINMAX_FM<"max.s", 0, 0b000001011>;
-class MAX_D_MMR6_ENC : POOL32F_MINMAX_FM<"max.d", 1, 0b000001011>;
-class MAXA_S_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.s", 0, 0b000101011>;
-class MAXA_D_MMR6_ENC : POOL32F_MINMAX_FM<"maxa.d", 1, 0b000101011>;
-class MIN_S_MMR6_ENC : POOL32F_MINMAX_FM<"min.s", 0, 0b000000011>;
-class MIN_D_MMR6_ENC : POOL32F_MINMAX_FM<"min.d", 1, 0b000000011>;
-class MINA_S_MMR6_ENC : POOL32F_MINMAX_FM<"mina.s", 0, 0b000100011>;
-class MINA_D_MMR6_ENC : POOL32F_MINMAX_FM<"mina.d", 1, 0b000100011>;
-
-class CVT_L_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.s", 0, 0b00000100>;
-class CVT_L_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.l.d", 1, 0b00000100>;
-class CVT_W_S_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.s", 0, 0b00100100>;
-class CVT_W_D_MMR6_ENC : POOL32F_CVT_LW_FM<"cvt.w.d", 1, 0b00100100>;
-class CVT_D_S_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.s", 0, 0b1001101>;
-class CVT_D_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.w", 1, 0b1001101>;
-class CVT_D_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.d.l", 2, 0b1001101>;
-class CVT_S_D_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.d", 0, 0b1101101>;
-class CVT_S_W_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.w", 1, 0b1101101>;
-class CVT_S_L_MMR6_ENC : POOL32F_CVT_DS_FM<"cvt.s.l", 2, 0b1101101>;
-
-//===----------------------------------------------------------------------===//
-//
-// Instruction Descriptions
-//
-//===----------------------------------------------------------------------===//
-
-class ADD_MMR6_DESC : ArithLogicR<"add", GPR32Opnd>;
+class ADD_MMR6_DESC : ArithLogicR<"add", GPR32Opnd, 1, II_ADD>;
class ADDIU_MMR6_DESC : ArithLogicI<"addiu", simm16, GPR32Opnd, II_ADDIU, immSExt16, add>;
-class ADDU_MMR6_DESC : ArithLogicR<"addu", GPR32Opnd>;
+class ADDU_MMR6_DESC : ArithLogicR<"addu", GPR32Opnd, 1, II_ADDU>;
class MUL_MMR6_DESC : ArithLogicR<"mul", GPR32Opnd, 1, II_MUL, mul>;
class MUH_MMR6_DESC : ArithLogicR<"muh", GPR32Opnd, 1, II_MUH, mulhs>;
class MULU_MMR6_DESC : ArithLogicR<"mulu", GPR32Opnd, 1, II_MULU>;
class MUHU_MMR6_DESC : ArithLogicR<"muhu", GPR32Opnd, 1, II_MUHU, mulhu>;
-class BC_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd>
+class BC_MMR6_DESC_BASE<string instr_asm, DAGOperand opnd, InstrItinClass Itin>
: BRANCH_DESC_BASE, MMR6Arch<instr_asm> {
dag InOperandList = (ins opnd:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$offset");
bit isBarrier = 1;
+ InstrItinClass Itinerary = Itin;
}
-class BALC_MMR6_DESC : BC_MMR6_DESC_BASE<"balc", brtarget26_mm> {
+class BALC_MMR6_DESC : BC_MMR6_DESC_BASE<"balc", brtarget26_mm, II_BALC> {
bit isCall = 1;
list<Register> Defs = [RA];
}
-class BC_MMR6_DESC : BC_MMR6_DESC_BASE<"bc", brtarget26_mm>;
+class BC_MMR6_DESC : BC_MMR6_DESC_BASE<"bc", brtarget26_mm, II_BC>;
class BC16_MMR6_DESC : MicroMipsInst16<(outs), (ins brtarget10_mm:$offset),
!strconcat("bc16", "\t$offset"), [],
@@ -377,8 +406,8 @@ class BEQZC_BNEZC_MM16R6_DESC_BASE<string instr_asm>
class BEQZC16_MMR6_DESC : BEQZC_BNEZC_MM16R6_DESC_BASE<"beqzc16">;
class BNEZC16_MMR6_DESC : BEQZC_BNEZC_MM16R6_DESC_BASE<"bnezc16">;
-class SUB_MMR6_DESC : ArithLogicR<"sub", GPR32Opnd>;
-class SUBU_MMR6_DESC : ArithLogicR<"subu", GPR32Opnd>;
+class SUB_MMR6_DESC : ArithLogicR<"sub", GPR32Opnd, 0, II_SUB>;
+class SUBU_MMR6_DESC : ArithLogicR<"subu", GPR32Opnd, 0,II_SUBU>;
class BITSWAP_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
: MMR6Arch<instr_asm> {
@@ -386,6 +415,7 @@ class BITSWAP_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
dag InOperandList = (ins GPROpnd:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rt");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = II_BITSWAP;
}
class BITSWAP_MMR6_DESC : BITSWAP_MMR6_DESC_BASE<"bitswap", GPR32Opnd>;
@@ -393,63 +423,74 @@ class BITSWAP_MMR6_DESC : BITSWAP_MMR6_DESC_BASE<"bitswap", GPR32Opnd>;
class BRK_MMR6_DESC : BRK_FT<"break">;
class CACHE_HINT_MMR6_DESC<string instr_asm, Operand MemOpnd,
- RegisterOperand GPROpnd> : MMR6Arch<instr_asm> {
+ RegisterOperand GPROpnd, InstrItinClass Itin>
+ : MMR6Arch<instr_asm> {
dag OutOperandList = (outs);
dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint);
string AsmString = !strconcat(instr_asm, "\t$hint, $addr");
list<dag> Pattern = [];
string DecoderMethod = "DecodeCacheOpMM";
+ InstrItinClass Itinerary = Itin;
}
-class CACHE_MMR6_DESC : CACHE_HINT_MMR6_DESC<"cache", mem_mm_12, GPR32Opnd>;
-class PREF_MMR6_DESC : CACHE_HINT_MMR6_DESC<"pref", mem_mm_12, GPR32Opnd>;
+class CACHE_MMR6_DESC : CACHE_HINT_MMR6_DESC<"cache", mem_mm_12, GPR32Opnd,
+ II_CACHE>;
+class PREF_MMR6_DESC : CACHE_HINT_MMR6_DESC<"pref", mem_mm_12, GPR32Opnd,
+ II_PREF>;
class PREFE_CACHEE_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd,
- RegisterOperand GPROpnd> :
- CACHE_HINT_MMR6_DESC<instr_asm, MemOpnd,
- GPROpnd> {
+ RegisterOperand GPROpnd, InstrItinClass Itin>
+ : CACHE_HINT_MMR6_DESC<instr_asm, MemOpnd, GPROpnd, Itin> {
string DecoderMethod = "DecodePrefeOpMM";
}
-class PREFE_MMR6_DESC : PREFE_CACHEE_MMR6_DESC_BASE<"prefe", mem_mm_9, GPR32Opnd>;
-class CACHEE_MMR6_DESC : PREFE_CACHEE_MMR6_DESC_BASE<"cachee", mem_mm_9, GPR32Opnd>;
+class PREFE_MMR6_DESC : PREFE_CACHEE_MMR6_DESC_BASE<"prefe", mem_mm_9,
+ GPR32Opnd, II_PREFE>;
+class CACHEE_MMR6_DESC : PREFE_CACHEE_MMR6_DESC_BASE<"cachee", mem_mm_9,
+ GPR32Opnd, II_CACHEE>;
class LB_LBU_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd,
- RegisterOperand GPROpnd> : MMR6Arch<instr_asm> {
+ RegisterOperand GPROpnd, InstrItinClass Itin>
+ : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins MemOpnd:$addr);
string AsmString = !strconcat(instr_asm, "\t$rt, $addr");
string DecoderMethod = "DecodeLoadByte15";
bit mayLoad = 1;
+ InstrItinClass Itinerary = Itin;
}
-class LB_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lb", mem_mm_16, GPR32Opnd>;
-class LBU_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lbu", mem_mm_16, GPR32Opnd>;
+class LB_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lb", mem_mm_16, GPR32Opnd, II_LB>;
+class LBU_MMR6_DESC : LB_LBU_MMR6_DESC_BASE<"lbu", mem_mm_16, GPR32Opnd,
+ II_LBU>;
class LBE_LBUE_MMR6_DESC_BASE<string instr_asm, Operand MemOpnd,
- RegisterOperand GPROpnd>
- : LB_LBU_MMR6_DESC_BASE<instr_asm, MemOpnd, GPROpnd> {
+ RegisterOperand GPROpnd, InstrItinClass Itin>
+ : LB_LBU_MMR6_DESC_BASE<instr_asm, MemOpnd, GPROpnd, Itin> {
let DecoderMethod = "DecodeLoadByte9";
}
-class LBE_MMR6_DESC : LBE_LBUE_MMR6_DESC_BASE<"lbe", mem_mm_9, GPR32Opnd>;
-class LBUE_MMR6_DESC : LBE_LBUE_MMR6_DESC_BASE<"lbue", mem_mm_9, GPR32Opnd>;
+class LBE_MMR6_DESC : LBE_LBUE_MMR6_DESC_BASE<"lbe", mem_mm_9, GPR32Opnd,
+ II_LBE>;
+class LBUE_MMR6_DESC : LBE_LBUE_MMR6_DESC_BASE<"lbue", mem_mm_9, GPR32Opnd,
+ II_LBUE>;
-class CLO_CLZ_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
- : MMR6Arch<instr_asm> {
+class CLO_CLZ_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins GPROpnd:$rs);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs");
+ InstrItinClass Itinerary = Itin;
}
-class CLO_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clo", GPR32Opnd>;
-class CLZ_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clz", GPR32Opnd>;
+class CLO_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clo", GPR32Opnd, II_CLO>;
+class CLZ_MMR6_DESC : CLO_CLZ_MMR6_DESC_BASE<"clz", GPR32Opnd, II_CLZ>;
-class EHB_MMR6_DESC : Barrier<"ehb">;
-class EI_MMR6_DESC : DEI_FT<"ei", GPR32Opnd>;
-class DI_MMR6_DESC : DEI_FT<"di", GPR32Opnd>;
+class EHB_MMR6_DESC : Barrier<"ehb", II_EHB>;
+class EI_MMR6_DESC : DEI_FT<"ei", GPR32Opnd, II_EI>;
+class DI_MMR6_DESC : DEI_FT<"di", GPR32Opnd, II_DI>;
-class ERET_MMR6_DESC : ER_FT<"eret">;
-class DERET_MMR6_DESC : ER_FT<"deret">;
-class ERETNC_MMR6_DESC : ER_FT<"eretnc">;
+class ERET_MMR6_DESC : ER_FT<"eret", II_ERET>;
+class DERET_MMR6_DESC : ER_FT<"deret", II_DERET>;
+class ERETNC_MMR6_DESC : ER_FT<"eretnc", II_ERETNC>;
class JALRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO>
: MicroMipsInst16<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"),
@@ -462,23 +503,25 @@ class JALRC16_MMR6_DESC_BASE<string opstr, RegisterOperand RO>
class JALRC16_MMR6_DESC : JALRC16_MMR6_DESC_BASE<"jalr", GPR32Opnd>;
class JMP_MMR6_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd,
- RegisterOperand GPROpnd>
+ RegisterOperand GPROpnd,
+ InstrItinClass Itin>
: MMR6Arch<opstr> {
dag InOperandList = (ins GPROpnd:$rt, opnd:$offset);
string AsmString = !strconcat(opstr, "\t$rt, $offset");
list<dag> Pattern = [];
bit isTerminator = 1;
bit hasDelaySlot = 0;
+ InstrItinClass Itinerary = Itin;
}
class JIALC_MMR6_DESC : JMP_MMR6_IDX_COMPACT_DESC_BASE<"jialc", calloffset16,
- GPR32Opnd> {
+ GPR32Opnd, II_JIALC> {
bit isCall = 1;
list<Register> Defs = [RA];
}
class JIC_MMR6_DESC : JMP_MMR6_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16,
- GPR32Opnd> {
+ GPR32Opnd, II_JIC> {
bit isBarrier = 1;
list<Register> Defs = [AT];
}
@@ -505,65 +548,76 @@ class JRCADDIUSP_MMR6_DESC
}
class ALIGN_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
- Operand ImmOpnd> : MMR6Arch<instr_asm> {
+ Operand ImmOpnd, InstrItinClass Itin>
+ : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class ALIGN_MMR6_DESC : ALIGN_MMR6_DESC_BASE<"align", GPR32Opnd, uimm2>;
+class ALIGN_MMR6_DESC : ALIGN_MMR6_DESC_BASE<"align", GPR32Opnd, uimm2,
+ II_ALIGN>;
-class AUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
- : MMR6Arch<instr_asm> {
+class AUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
- dag InOperandList = (ins GPROpnd:$rs, simm16:$imm);
+ dag InOperandList = (ins GPROpnd:$rs, uimm16:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class AUI_MMR6_DESC : AUI_MMR6_DESC_BASE<"aui", GPR32Opnd>;
+class AUI_MMR6_DESC : AUI_MMR6_DESC_BASE<"aui", GPR32Opnd, II_AUI>;
class SEB_MMR6_DESC : SignExtInReg<"seb", i8, GPR32Opnd, II_SEB>;
class SEH_MMR6_DESC : SignExtInReg<"seh", i16, GPR32Opnd, II_SEH>;
-class ALUIPC_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
- : MMR6Arch<instr_asm> {
+class ALUIPC_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins simm16:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $imm");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class ALUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"aluipc", GPR32Opnd>;
-class AUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"auipc", GPR32Opnd>;
+class ALUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"aluipc", GPR32Opnd, II_ALUIPC>;
+class AUIPC_MMR6_DESC : ALUIPC_MMR6_DESC_BASE<"auipc", GPR32Opnd, II_AUIPC>;
class LSA_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
- Operand ImmOpnd> : MMR6Arch<instr_asm> {
+ Operand ImmOpnd, InstrItinClass Itin>
+ : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$imm2);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $rd, $imm2");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class LSA_MMR6_DESC : LSA_MMR6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1>;
+class LSA_MMR6_DESC : LSA_MMR6_DESC_BASE<"lsa", GPR32Opnd, uimm2_plus1, II_LSA>;
class PCREL_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
- Operand ImmOpnd> : MMR6Arch<instr_asm> {
+ Operand ImmOpnd, InstrItinClass Itin>
+ : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins ImmOpnd:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $imm");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class ADDIUPC_MMR6_DESC : PCREL_MMR6_DESC_BASE<"addiupc", GPR32Opnd, simm19_lsl2>;
-class LWPC_MMR6_DESC: PCREL_MMR6_DESC_BASE<"lwpc", GPR32Opnd, simm19_lsl2>;
+class ADDIUPC_MMR6_DESC : PCREL_MMR6_DESC_BASE<"addiupc", GPR32Opnd,
+ simm19_lsl2, II_ADDIUPC>;
+class LWPC_MMR6_DESC: PCREL_MMR6_DESC_BASE<"lwpc", GPR32Opnd, simm19_lsl2,
+ II_LWPC>;
class LWP_MMR6_DESC : MMR6Arch<"lwp"> {
dag OutOperandList = (outs regpair:$rd);
dag InOperandList = (ins mem_simm12:$addr);
string AsmString = !strconcat("lwp", "\t$rd, $addr");
list<dag> Pattern = [];
- InstrItinClass Itin = NoItinerary;
+ InstrItinClass Itinerary = II_LWP;
ComplexPattern Addr = addr;
Format f = FrmI;
string BaseOpcode = "lwp";
@@ -576,7 +630,7 @@ class SWP_MMR6_DESC : MMR6Arch<"swp"> {
dag InOperandList = (ins regpair:$rd, mem_simm12:$addr);
string AsmString = !strconcat("swp", "\t$rd, $addr");
list<dag> Pattern = [];
- InstrItinClass Itin = NoItinerary;
+ InstrItinClass Itinerary = II_SWP;
ComplexPattern Addr = addr;
Format f = FrmI;
string BaseOpcode = "swp";
@@ -584,17 +638,20 @@ class SWP_MMR6_DESC : MMR6Arch<"swp"> {
bit mayStore = 1;
}
-class SELEQNE_Z_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
- : MMR6Arch<instr_asm> {
+class SELEQNE_Z_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class SELEQZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"seleqz", GPR32Opnd>;
-class SELNEZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"selnez", GPR32Opnd>;
-class PAUSE_MMR6_DESC : Barrier<"pause">;
+class SELEQZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"seleqz", GPR32Opnd,
+ II_SELCCZ>;
+class SELNEZ_MMR6_DESC : SELEQNE_Z_MMR6_DESC_BASE<"selnez", GPR32Opnd,
+ II_SELCCZ>;
+class PAUSE_MMR6_DESC : Barrier<"pause", II_PAUSE>;
class RDHWR_MMR6_DESC : MMR6Arch<"rdhwr">, MipsR6Inst {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins HWRegsOpnd:$rs, uimm3:$sel);
@@ -605,10 +662,14 @@ class RDHWR_MMR6_DESC : MMR6Arch<"rdhwr">, MipsR6Inst {
}
class WAIT_MMR6_DESC : WaitMM<"wait">;
-class SSNOP_MMR6_DESC : Barrier<"ssnop">;
+// FIXME: ssnop should not be defined for R6. Per MD000582 microMIPS32 6.03:
+// Assemblers targeting specifically Release 6 should reject the SSNOP
+// instruction with an error.
+class SSNOP_MMR6_DESC : Barrier<"ssnop", II_SSNOP>;
class SLL_MMR6_DESC : shift_rotate_imm<"sll", uimm5, GPR32Opnd, II_SLL>;
class DIVMOD_MMR6_DESC_BASE<string opstr, RegisterOperand GPROpnd,
+ InstrItinClass Itin,
SDPatternOperator OpNode=null_frag>
: MipsR6Inst {
dag OutOperandList = (outs GPROpnd:$rd);
@@ -619,15 +680,16 @@ class DIVMOD_MMR6_DESC_BASE<string opstr, RegisterOperand GPROpnd,
Format f = FrmR;
let isCommutable = 0;
let isReMaterializable = 1;
+ InstrItinClass Itinerary = Itin;
// This instruction doesn't trap division by zero itself. We must insert
// teq instructions as well.
bit usesCustomInserter = 1;
}
-class DIV_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"div", GPR32Opnd, sdiv>;
-class DIVU_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"divu", GPR32Opnd, udiv>;
-class MOD_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"mod", GPR32Opnd, srem>;
-class MODU_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"modu", GPR32Opnd, urem>;
+class DIV_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"div", GPR32Opnd, II_DIV, sdiv>;
+class DIVU_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"divu", GPR32Opnd, II_DIVU, udiv>;
+class MOD_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"mod", GPR32Opnd, II_MOD, srem>;
+class MODU_MMR6_DESC : DIVMOD_MMR6_DESC_BASE<"modu", GPR32Opnd, II_MODU, urem>;
class AND_MMR6_DESC : ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>;
class ANDI_MMR6_DESC : ArithLogicI<"andi", uimm16, GPR32Opnd, II_ANDI>;
class NOR_MMR6_DESC : LogicNOR<"nor", GPR32Opnd>;
@@ -641,19 +703,21 @@ class XORI_MMR6_DESC : ArithLogicI<"xori", uimm16, GPR32Opnd, II_XORI,
immZExt16, xor>;
class SWE_MMR6_DESC_BASE<string opstr, DAGOperand RO, DAGOperand MO,
- SDPatternOperator OpNode = null_frag,
InstrItinClass Itin = NoItinerary,
+ SDPatternOperator OpNode = null_frag,
ComplexPattern Addr = addr> :
InstSE<(outs), (ins RO:$rt, MO:$addr), !strconcat(opstr, "\t$rt, $addr"),
[(OpNode RO:$rt, Addr:$addr)], Itin, FrmI, opstr> {
let DecoderMethod = "DecodeMem";
let mayStore = 1;
}
-class SW_MMR6_DESC : Store<"sw", GPR32Opnd>;
-class SWE_MMR6_DESC : SWE_MMR6_DESC_BASE<"swe", GPR32Opnd, mem_simm9>;
+class SW_MMR6_DESC : Store<"sw", GPR32Opnd> {
+ InstrItinClass Itinerary = II_SW;
+}
+class SWE_MMR6_DESC : SWE_MMR6_DESC_BASE<"swe", GPR32Opnd, mem_simm9, II_SWE>;
-class WRPGPR_WSBH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO>
- : MMR6Arch<instr_asm> {
+class WRPGPR_WSBH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO,
+ InstrItinClass Itin> : MMR6Arch<instr_asm> {
dag InOperandList = (ins RO:$rs);
dag OutOperandList = (outs RO:$rt);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs");
@@ -661,18 +725,21 @@ class WRPGPR_WSBH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO>
Format f = FrmR;
string BaseOpcode = instr_asm;
bit hasSideEffects = 0;
+ InstrItinClass Itinerary = Itin;
}
-class WRPGPR_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wrpgpr", GPR32Opnd>;
-class WSBH_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wsbh", GPR32Opnd>;
+class WRPGPR_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wrpgpr", GPR32Opnd,
+ II_WRPGPR>;
+class WSBH_MMR6_DESC : WRPGPR_WSBH_MMR6_DESC_BASE<"wsbh", GPR32Opnd, II_WSBH>;
class MTC0_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
- RegisterOperand SrcRC> {
+ RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rt, uimm3:$sel);
dag OutOperandList = (outs DstRC:$rs);
string AsmString = !strconcat(opstr, "\t$rt, $rs, $sel");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
+ InstrItinClass Itinerary = Itin;
}
class MTC1_MMR6_DESC_BASE<
string opstr, RegisterOperand DstRC, RegisterOperand SrcRC,
@@ -701,34 +768,42 @@ class MTC1_64_MMR6_DESC_BASE<
let Constraints = "$fs = $fs_in";
}
class MTC2_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
- RegisterOperand SrcRC> {
+ RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rt);
dag OutOperandList = (outs DstRC:$impl);
string AsmString = !strconcat(opstr, "\t$rt, $impl");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
+ InstrItinClass Itinerary = Itin;
}
-class MTC0_MMR6_DESC : MTC0_MMR6_DESC_BASE<"mtc0", COP0Opnd, GPR32Opnd>;
+class MTC0_MMR6_DESC : MTC0_MMR6_DESC_BASE<"mtc0", COP0Opnd, GPR32Opnd,
+ II_MTC0>;
class MTC1_MMR6_DESC : MTC1_MMR6_DESC_BASE<"mtc1", FGR32Opnd, GPR32Opnd,
II_MTC1, bitconvert>, HARDFLOAT;
-class MTC2_MMR6_DESC : MTC2_MMR6_DESC_BASE<"mtc2", COP2Opnd, GPR32Opnd>;
-class MTHC0_MMR6_DESC : MTC0_MMR6_DESC_BASE<"mthc0", COP0Opnd, GPR32Opnd>;
-class MTHC1_D32_MMR6_DESC : MTC1_64_MMR6_DESC_BASE<"mthc1", AFGR64Opnd, GPR32Opnd>,
+class MTC2_MMR6_DESC : MTC2_MMR6_DESC_BASE<"mtc2", COP2Opnd, GPR32Opnd,
+ II_MTC2>;
+class MTHC0_MMR6_DESC : MTC0_MMR6_DESC_BASE<"mthc0", COP0Opnd, GPR32Opnd,
+ II_MTHC0>;
+class MTHC1_D32_MMR6_DESC : MTC1_64_MMR6_DESC_BASE<"mthc1", AFGR64Opnd,
+ GPR32Opnd, II_MTC1>,
HARDFLOAT, FGR_32;
-class MTHC1_D64_MMR6_DESC : MTC1_64_MMR6_DESC_BASE<"mthc1", FGR64Opnd, GPR32Opnd>,
+class MTHC1_D64_MMR6_DESC : MTC1_64_MMR6_DESC_BASE<"mthc1", FGR64Opnd,
+ GPR32Opnd, II_MTC1>,
HARDFLOAT, FGR_64;
-class MTHC2_MMR6_DESC : MTC2_MMR6_DESC_BASE<"mthc2", COP2Opnd, GPR32Opnd>;
+class MTHC2_MMR6_DESC : MTC2_MMR6_DESC_BASE<"mthc2", COP2Opnd, GPR32Opnd,
+ II_MTC2>;
class MFC0_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
- RegisterOperand SrcRC> {
+ RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$rs, uimm3:$sel);
dag OutOperandList = (outs DstRC:$rt);
string AsmString = !strconcat(opstr, "\t$rt, $rs, $sel");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
+ InstrItinClass Itinerary = Itin;
}
class MFC1_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
RegisterOperand SrcRC,
@@ -743,24 +818,29 @@ class MFC1_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
string BaseOpcode = opstr;
}
class MFC2_MMR6_DESC_BASE<string opstr, RegisterOperand DstRC,
- RegisterOperand SrcRC> {
+ RegisterOperand SrcRC, InstrItinClass Itin> {
dag InOperandList = (ins SrcRC:$impl);
dag OutOperandList = (outs DstRC:$rt);
string AsmString = !strconcat(opstr, "\t$rt, $impl");
list<dag> Pattern = [];
Format f = FrmFR;
string BaseOpcode = opstr;
+ InstrItinClass Itinerary = Itin;
}
-class MFC0_MMR6_DESC : MFC0_MMR6_DESC_BASE<"mfc0", GPR32Opnd, COP0Opnd>;
+class MFC0_MMR6_DESC : MFC0_MMR6_DESC_BASE<"mfc0", GPR32Opnd, COP0Opnd,
+ II_MFC0>;
class MFC1_MMR6_DESC : MFC1_MMR6_DESC_BASE<"mfc1", GPR32Opnd, FGR32Opnd,
II_MFC1, bitconvert>, HARDFLOAT;
-class MFC2_MMR6_DESC : MFC2_MMR6_DESC_BASE<"mfc2", GPR32Opnd, COP2Opnd>;
-class MFHC0_MMR6_DESC : MFC0_MMR6_DESC_BASE<"mfhc0", GPR32Opnd, COP0Opnd>;
+class MFC2_MMR6_DESC : MFC2_MMR6_DESC_BASE<"mfc2", GPR32Opnd, COP2Opnd,
+ II_MFC2>;
+class MFHC0_MMR6_DESC : MFC0_MMR6_DESC_BASE<"mfhc0", GPR32Opnd, COP0Opnd,
+ II_MFHC0>;
class MFHC1_D32_MMR6_DESC : MFC1_MMR6_DESC_BASE<"mfhc1", GPR32Opnd, AFGR64Opnd,
II_MFHC1>, HARDFLOAT, FGR_32;
class MFHC1_D64_MMR6_DESC : MFC1_MMR6_DESC_BASE<"mfhc1", GPR32Opnd, FGR64Opnd,
II_MFHC1>, HARDFLOAT, FGR_64;
-class MFHC2_MMR6_DESC : MFC2_MMR6_DESC_BASE<"mfhc2", GPR32Opnd, COP2Opnd>;
+class MFHC2_MMR6_DESC : MFC2_MMR6_DESC_BASE<"mfhc2", GPR32Opnd, COP2Opnd,
+ II_MFC2>;
class LDC1_D64_MMR6_DESC : MipsR6Inst, HARDFLOAT, FGR_64 {
dag InOperandList = (ins mem_mm_16:$addr);
@@ -786,33 +866,33 @@ class SDC1_D64_MMR6_DESC : MipsR6Inst, HARDFLOAT, FGR_64 {
let DecoderMethod = "DecodeFMemMMR2";
}
-class LDC2_LWC2_MMR6_DESC_BASE<string opstr> {
+class LDC2_LWC2_MMR6_DESC_BASE<string opstr, InstrItinClass itin> {
dag OutOperandList = (outs COP2Opnd:$rt);
dag InOperandList = (ins mem_mm_11:$addr);
string AsmString = !strconcat(opstr, "\t$rt, $addr");
list<dag> Pattern = [(set COP2Opnd:$rt, (load addrimm11:$addr))];
Format f = FrmFI;
- InstrItinClass Itinerary = NoItinerary;
+ InstrItinClass Itinerary = itin;
string BaseOpcode = opstr;
bit mayLoad = 1;
string DecoderMethod = "DecodeFMemCop2MMR6";
}
-class LDC2_MMR6_DESC : LDC2_LWC2_MMR6_DESC_BASE<"ldc2">;
-class LWC2_MMR6_DESC : LDC2_LWC2_MMR6_DESC_BASE<"lwc2">;
+class LDC2_MMR6_DESC : LDC2_LWC2_MMR6_DESC_BASE<"ldc2", II_LDC2>;
+class LWC2_MMR6_DESC : LDC2_LWC2_MMR6_DESC_BASE<"lwc2", II_LWC2>;
-class SDC2_SWC2_MMR6_DESC_BASE<string opstr> {
+class SDC2_SWC2_MMR6_DESC_BASE<string opstr, InstrItinClass itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins COP2Opnd:$rt, mem_mm_11:$addr);
string AsmString = !strconcat(opstr, "\t$rt, $addr");
list<dag> Pattern = [(store COP2Opnd:$rt, addrimm11:$addr)];
Format f = FrmFI;
- InstrItinClass Itinerary = NoItinerary;
+ InstrItinClass Itinerary = itin;
string BaseOpcode = opstr;
bit mayStore = 1;
string DecoderMethod = "DecodeFMemCop2MMR6";
}
-class SDC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"sdc2">;
-class SWC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"swc2">;
+class SDC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"sdc2", II_SDC2>;
+class SWC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"swc2", II_SWC2>;
/// Floating Point Instructions
class FARITH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RC,
@@ -841,10 +921,14 @@ class FDIV_S_MMR6_DESC
: FARITH_MMR6_DESC_BASE<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>;
class FDIV_D_MMR6_DESC
: FARITH_MMR6_DESC_BASE<"div.d", AFGR64Opnd, II_DIV_D, 0, fdiv>;
-class MADDF_S_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.s", FGR32Opnd>, HARDFLOAT;
-class MADDF_D_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd>, HARDFLOAT;
-class MSUBF_S_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd>, HARDFLOAT;
-class MSUBF_D_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd>, HARDFLOAT;
+class MADDF_S_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.s", FGR32Opnd,
+ II_MADDF_S>, HARDFLOAT;
+class MADDF_D_MMR6_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd,
+ II_MADDF_D>, HARDFLOAT;
+class MSUBF_S_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd,
+ II_MSUBF_S>, HARDFLOAT;
+class MSUBF_D_MMR6_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd,
+ II_MSUBF_D>, HARDFLOAT;
class FMOV_FNEG_MMR6_DESC_BASE<string instr_asm, RegisterOperand DstRC,
RegisterOperand SrcRC, InstrItinClass Itin,
@@ -866,15 +950,23 @@ class FNEG_S_MMR6_DESC
class FNEG_D_MMR6_DESC
: FMOV_FNEG_MMR6_DESC_BASE<"neg.d", AFGR64Opnd, AFGR64Opnd, II_NEG, fneg>;
-class MAX_S_MMR6_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd>, HARDFLOAT;
-class MAX_D_MMR6_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd>, HARDFLOAT;
-class MIN_S_MMR6_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd>, HARDFLOAT;
-class MIN_D_MMR6_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd>, HARDFLOAT;
-
-class MAXA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd>, HARDFLOAT;
-class MAXA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd>, HARDFLOAT;
-class MINA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd>, HARDFLOAT;
-class MINA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd>, HARDFLOAT;
+class MAX_S_MMR6_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd, II_MAX_S>,
+ HARDFLOAT;
+class MAX_D_MMR6_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd, II_MAX_D>,
+ HARDFLOAT;
+class MIN_S_MMR6_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd, II_MIN_S>,
+ HARDFLOAT;
+class MIN_D_MMR6_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd, II_MIN_D>,
+ HARDFLOAT;
+
+class MAXA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd, II_MAXA_S>,
+ HARDFLOAT;
+class MAXA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd, II_MAXA_D>,
+ HARDFLOAT;
+class MINA_S_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd, II_MINA_S>,
+ HARDFLOAT;
+class MINA_D_MMR6_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd, II_MINA_D>,
+ HARDFLOAT;
class CVT_MMR6_DESC_BASE<
string instr_asm, RegisterOperand DstRC, RegisterOperand SrcRC,
@@ -910,70 +1002,70 @@ class CVT_S_L_MMR6_DESC : CVT_MMR6_DESC_BASE<"cvt.s.l", FGR64Opnd, FGR32Opnd,
II_CVT>, FGR_64;
multiclass CMP_CC_MMR6<bits<6> format, string Typestr,
- RegisterOperand FGROpnd> {
+ RegisterOperand FGROpnd, InstrItinClass Itin> {
def CMP_AF_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.af.", Typestr), format, FIELD_CMP_COND_AF>,
- CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_UN_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.un.", Typestr), format, FIELD_CMP_COND_UN>,
- CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, setuo>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, Itin, setuo>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_EQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.eq.", Typestr), format, FIELD_CMP_COND_EQ>,
- CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, setoeq>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, Itin, setoeq>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_UEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ueq.", Typestr), format, FIELD_CMP_COND_UEQ>,
- CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, setueq>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, Itin, setueq>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_LT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.lt.", Typestr), format, FIELD_CMP_COND_LT>,
- CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, setolt>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, Itin, setolt>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_ULT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ult.", Typestr), format, FIELD_CMP_COND_ULT>,
- CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, setult>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, Itin, setult>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_LE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.le.", Typestr), format, FIELD_CMP_COND_LE>,
- CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, setole>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, Itin, setole>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_ULE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.ule.", Typestr), format, FIELD_CMP_COND_ULE>,
- CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, setule>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, Itin, setule>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SAF_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.saf.", Typestr), format, FIELD_CMP_COND_SAF>,
- CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SUN_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sun.", Typestr), format, FIELD_CMP_COND_SUN>,
- CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.seq.", Typestr), format, FIELD_CMP_COND_SEQ>,
- CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SUEQ_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sueq.", Typestr), format, FIELD_CMP_COND_SUEQ>,
- CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SLT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.slt.", Typestr), format, FIELD_CMP_COND_SLT>,
- CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SULT_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sult.", Typestr), format, FIELD_CMP_COND_SULT>,
- CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SLE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sle.", Typestr), format, FIELD_CMP_COND_SLE>,
- CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
def CMP_SULE_#NAME : R6MMR6Rel, POOL32F_CMP_FM<
!strconcat("cmp.sule.", Typestr), format, FIELD_CMP_COND_SULE>,
- CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>, HARDFLOAT,
+ CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd, Itin>, HARDFLOAT,
ISA_MICROMIPS32R6;
}
@@ -1022,14 +1114,6 @@ class SQRT_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"sqrt.s", FGR32Opnd, FGR32Opnd,
II_SQRT_S, fsqrt>;
class SQRT_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"sqrt.d", AFGR64Opnd, AFGR64Opnd,
II_SQRT_D, fsqrt>;
-class RSQRT_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"rsqrt.s", FGR32Opnd,
- FGR32Opnd, II_TRUNC>;
-class RSQRT_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"rsqrt.d", FGR32Opnd,
- AFGR64Opnd, II_TRUNC>;
-class RECIP_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"recip.s", FGR32Opnd,
- FGR32Opnd, II_ROUND>;
-class RECIP_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"recip.d", FGR32Opnd, FGR32Opnd,
- II_ROUND>;
class ROUND_L_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.l.s", FGR64Opnd,
FGR32Opnd, II_ROUND>;
class ROUND_L_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.l.d", FGR64Opnd,
@@ -1039,49 +1123,63 @@ class ROUND_W_S_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.s", FGR32Opnd,
class ROUND_W_D_MMR6_DESC : ABSS_FT_MMR6_DESC_BASE<"round.w.d", FGR64Opnd,
FGR64Opnd, II_ROUND>;
-class SEL_S_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>;
-class SEL_D_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd> {
+class SEL_S_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd, II_SEL_S>;
+class SEL_D_MMR6_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd, II_SEL_D> {
// We must insert a SUBREG_TO_REG around $fd_in
bit usesCustomInserter = 1;
}
-class SELEQZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd>;
-class SELEQZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd>;
-class SELNEZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd>;
-class SELNEZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd>;
-class RINT_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd>;
-class RINT_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd>;
-class CLASS_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd>;
-class CLASS_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd>;
-
-class STORE_MMR6_DESC_BASE<string opstr, DAGOperand RO>
+class SELEQZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd,
+ II_SELCCZ_S>;
+class SELEQZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd,
+ II_SELCCZ_D>;
+class SELNEZ_S_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd,
+ II_SELCCZ_S>;
+class SELNEZ_D_MMR6_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd,
+ II_SELCCZ_D>;
+class RINT_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd,
+ II_RINT_S>;
+class RINT_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd,
+ II_RINT_S>;
+class CLASS_S_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd,
+ II_CLASS_S>;
+class CLASS_D_MMR6_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd,
+ II_CLASS_S>;
+
+class STORE_MMR6_DESC_BASE<string opstr, DAGOperand RO,
+ InstrItinClass Itin>
: Store<opstr, RO>, MMR6Arch<opstr> {
let DecoderMethod = "DecodeMemMMImm16";
+ InstrItinClass Itinerary = Itin;
}
-class SB_MMR6_DESC : STORE_MMR6_DESC_BASE<"sb", GPR32Opnd>;
+class SB_MMR6_DESC : STORE_MMR6_DESC_BASE<"sb", GPR32Opnd, II_SB>;
-class STORE_EVA_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO>
+class STORE_EVA_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO,
+ InstrItinClass Itin>
: MMR6Arch<instr_asm>, MipsR6Inst {
dag OutOperandList = (outs);
dag InOperandList = (ins RO:$rt, mem_simm9:$addr);
string AsmString = !strconcat(instr_asm, "\t$rt, $addr");
string DecoderMethod = "DecodeStoreEvaOpMM";
bit mayStore = 1;
+ InstrItinClass Itinerary = Itin;
}
-class SBE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"sbe", GPR32Opnd>;
-class SCE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"sce", GPR32Opnd>;
-class SH_MMR6_DESC : STORE_MMR6_DESC_BASE<"sh", GPR32Opnd>;
-class SHE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"she", GPR32Opnd>;
-class LOAD_WORD_EVA_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO> :
- MMR6Arch<instr_asm>, MipsR6Inst {
+class SBE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"sbe", GPR32Opnd, II_SBE>;
+class SCE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"sce", GPR32Opnd, II_SCE>;
+class SH_MMR6_DESC : STORE_MMR6_DESC_BASE<"sh", GPR32Opnd, II_SH>;
+class SHE_MMR6_DESC : STORE_EVA_MMR6_DESC_BASE<"she", GPR32Opnd, II_SHE>;
+class LOAD_WORD_EVA_MMR6_DESC_BASE<string instr_asm, RegisterOperand RO,
+ InstrItinClass Itin>
+ : MMR6Arch<instr_asm>, MipsR6Inst {
dag OutOperandList = (outs RO:$rt);
dag InOperandList = (ins mem_simm9:$addr);
string AsmString = !strconcat(instr_asm, "\t$rt, $addr");
string DecoderMethod = "DecodeMemMMImm9";
bit mayLoad = 1;
+ InstrItinClass Itinerary = Itin;
}
-class LLE_MMR6_DESC : LOAD_WORD_EVA_MMR6_DESC_BASE<"lle", GPR32Opnd>;
-class LWE_MMR6_DESC : LOAD_WORD_EVA_MMR6_DESC_BASE<"lwe", GPR32Opnd>;
+class LLE_MMR6_DESC : LOAD_WORD_EVA_MMR6_DESC_BASE<"lle", GPR32Opnd, II_LLE>;
+class LWE_MMR6_DESC : LOAD_WORD_EVA_MMR6_DESC_BASE<"lwe", GPR32Opnd, II_LWE>;
class ADDU16_MMR6_DESC : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>,
MMR6Arch<"addu16"> {
int AddedComplexity = 1;
@@ -1103,13 +1201,13 @@ class SLL16_MMR6_DESC : ShiftIMM16<"sll16", uimm3_shift, GPRMM16Opnd, II_SLL>,
MMR6Arch<"sll16">;
class SRL16_MMR6_DESC : ShiftIMM16<"srl16", uimm3_shift, GPRMM16Opnd, II_SRL>,
MMR6Arch<"srl16">;
-class BREAK16_MMR6_DESC : BrkSdbbp16MM<"break16">, MMR6Arch<"break16">,
+class BREAK16_MMR6_DESC : BrkSdbbp16MM<"break16", II_BREAK>, MMR6Arch<"break16">,
MicroMipsR6Inst16;
class LI16_MMR6_DESC : LoadImmMM16<"li16", li16_imm, GPRMM16Opnd>,
MMR6Arch<"li16">, MicroMipsR6Inst16, IsAsCheapAsAMove;
class MOVE16_MMR6_DESC : MoveMM16<"move16", GPR32Opnd>, MMR6Arch<"move16">,
MicroMipsR6Inst16;
-class SDBBP16_MMR6_DESC : BrkSdbbp16MM<"sdbbp16">, MMR6Arch<"sdbbp16">,
+class SDBBP16_MMR6_DESC : BrkSdbbp16MM<"sdbbp16", II_SDBBP>, MMR6Arch<"sdbbp16">,
MicroMipsR6Inst16;
class SUBU16_MMR6_DESC : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>,
MMR6Arch<"subu16">, MicroMipsR6Inst16 {
@@ -1147,7 +1245,7 @@ class SYNC_MMR6_DESC : MMR6Arch<"sync">, MipsR6Inst {
dag InOperandList = (ins uimm5:$stype);
string AsmString = !strconcat("sync", "\t$stype");
list<dag> Pattern = [(MipsSync immZExt5:$stype)];
- InstrItinClass Itinerary = NoItinerary;
+ InstrItinClass Itinerary = II_SYNC;
bit HasSideEffects = 1;
}
@@ -1159,6 +1257,7 @@ class RDPGPR_MMR6_DESC : MMR6Arch<"rdpgpr">, MipsR6Inst {
dag OutOperandList = (outs GPR32Opnd:$rt);
dag InOperandList = (ins GPR32Opnd:$rd);
string AsmString = !strconcat("rdpgpr", "\t$rt, $rd");
+ InstrItinClass Itinerary = II_RDPGPR;
}
class SDBBP_MMR6_DESC : MipsR6Inst {
@@ -1166,27 +1265,26 @@ class SDBBP_MMR6_DESC : MipsR6Inst {
dag InOperandList = (ins uimm20:$code_);
string AsmString = !strconcat("sdbbp", "\t$code_");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = II_SDBBP;
}
class LWM16_MMR6_DESC
: MicroMipsInst16<(outs reglist16:$rt), (ins mem_mm_4sp:$addr),
!strconcat("lwm16", "\t$rt, $addr"), [],
- NoItinerary, FrmI>,
+ II_LWM, FrmI>,
MMR6Arch<"lwm16">, MicroMipsR6Inst16 {
let DecoderMethod = "DecodeMemMMReglistImm4Lsl2";
let mayLoad = 1;
- InstrItinClass Itin = NoItinerary;
ComplexPattern Addr = addr;
}
class SWM16_MMR6_DESC
: MicroMipsInst16<(outs), (ins reglist16:$rt, mem_mm_4sp:$addr),
!strconcat("swm16", "\t$rt, $addr"), [],
- NoItinerary, FrmI>,
+ II_SWM, FrmI>,
MMR6Arch<"swm16">, MicroMipsR6Inst16 {
let DecoderMethod = "DecodeMemMMReglistImm4Lsl2";
let mayStore = 1;
- InstrItinClass Itin = NoItinerary;
ComplexPattern Addr = addr;
}
@@ -1219,31 +1317,34 @@ class JALRC_HB_MMR6_DESC {
dag InOperandList = (ins GPR32Opnd:$rs);
string AsmString = !strconcat("jalrc.hb", "\t$rt, $rs");
list<dag> Pattern = [];
- InstrItinClass Itinerary = NoItinerary;
+ InstrItinClass Itinerary = II_JALR_HB;
Format Form = FrmJ;
bit isIndirectBranch = 1;
bit hasDelaySlot = 0;
}
-class TLBINV_MMR6_DESC_BASE<string opstr> {
+class TLBINV_MMR6_DESC_BASE<string opstr, InstrItinClass Itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins);
string AsmString = opstr;
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class TLBINV_MMR6_DESC : TLBINV_MMR6_DESC_BASE<"tlbinv">;
-class TLBINVF_MMR6_DESC : TLBINV_MMR6_DESC_BASE<"tlbinvf">;
+class TLBINV_MMR6_DESC : TLBINV_MMR6_DESC_BASE<"tlbinv", II_TLBINV>;
+class TLBINVF_MMR6_DESC : TLBINV_MMR6_DESC_BASE<"tlbinvf", II_TLBINVF>;
-class DVPEVP_MMR6_DESC_BASE<string opstr> {
- dag OutOperandList = (outs);
- dag InOperandList = (ins GPR32Opnd:$rs);
+class DVPEVP_MMR6_DESC_BASE<string opstr, InstrItinClass Itin> {
+ dag OutOperandList = (outs GPR32Opnd:$rs);
+ dag InOperandList = (ins);
string AsmString = !strconcat(opstr, "\t$rs");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
+ bit hasUnModeledSideEffects = 1;
}
-class DVP_MMR6_DESC : DVPEVP_MMR6_DESC_BASE<"dvp">;
-class EVP_MMR6_DESC : DVPEVP_MMR6_DESC_BASE<"evp">;
+class DVP_MMR6_DESC : DVPEVP_MMR6_DESC_BASE<"dvp", II_DVP>;
+class EVP_MMR6_DESC : DVPEVP_MMR6_DESC_BASE<"evp", II_EVP>;
class BEQZC_MMR6_DESC
: CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21_mm, GPR32Opnd>,
@@ -1262,15 +1363,17 @@ class BRANCH_COP1_MMR6_DESC_BASE<string opstr> :
class BC1EQZC_MMR6_DESC : BRANCH_COP1_MMR6_DESC_BASE<"bc1eqzc">;
class BC1NEZC_MMR6_DESC : BRANCH_COP1_MMR6_DESC_BASE<"bc1nezc">;
-class BRANCH_COP2_MMR6_DESC_BASE<string opstr> : BRANCH_DESC_BASE {
+class BRANCH_COP2_MMR6_DESC_BASE<string opstr, InstrItinClass Itin>
+ : BRANCH_DESC_BASE {
dag InOperandList = (ins COP2Opnd:$rt, brtarget_mm:$offset);
dag OutOperandList = (outs);
string AsmString = !strconcat(opstr, "\t$rt, $offset");
list<Register> Defs = [AT];
+ InstrItinClass Itinerary = Itin;
}
-class BC2EQZC_MMR6_DESC : BRANCH_COP2_MMR6_DESC_BASE<"bc2eqzc">;
-class BC2NEZC_MMR6_DESC : BRANCH_COP2_MMR6_DESC_BASE<"bc2nezc">;
+class BC2EQZC_MMR6_DESC : BRANCH_COP2_MMR6_DESC_BASE<"bc2eqzc", II_BC2CCZ>;
+class BC2NEZC_MMR6_DESC : BRANCH_COP2_MMR6_DESC_BASE<"bc2nezc", II_BC2CCZ>;
class EXT_MMR6_DESC {
dag OutOperandList = (outs GPR32Opnd:$rt);
@@ -1314,6 +1417,7 @@ class BOVC_BNVC_MMR6_DESC_BASE<string instr_asm, Operand opnd,
dag OutOperandList = (outs);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $offset");
list<Register> Defs = [AT];
+ InstrItinClass Itinerary = II_BCCC;
}
class BOVC_MMR6_DESC : BOVC_BNVC_MMR6_DESC_BASE<"bovc", brtargetr6, GPR32Opnd>;
@@ -1517,8 +1621,8 @@ def CVT_S_W_MMR6 : StdMMR6Rel, CVT_S_W_MMR6_ENC, CVT_S_W_MMR6_DESC,
ISA_MICROMIPS32R6;
def CVT_S_L_MMR6 : StdMMR6Rel, CVT_S_L_MMR6_ENC, CVT_S_L_MMR6_DESC,
ISA_MICROMIPS32R6;
-defm S_MMR6 : CMP_CC_MMR6<0b000101, "s", FGR32Opnd>;
-defm D_MMR6 : CMP_CC_MMR6<0b010101, "d", FGR64Opnd>;
+defm S_MMR6 : CMP_CC_MMR6<0b000101, "s", FGR32Opnd, II_CMP_CC_S>;
+defm D_MMR6 : CMP_CC_MMR6<0b010101, "d", FGR64Opnd, II_CMP_CC_D>;
def ABS_S_MMR6 : StdMMR6Rel, ABS_S_MMR6_ENC, ABS_S_MMR6_DESC, ISA_MICROMIPS32R6;
def ABS_D_MMR6 : StdMMR6Rel, ABS_D_MMR6_ENC, ABS_D_MMR6_DESC, ISA_MICROMIPS32R6;
def FLOOR_L_S_MMR6 : StdMMR6Rel, FLOOR_L_S_MMR6_ENC, FLOOR_L_S_MMR6_DESC,
@@ -1549,10 +1653,6 @@ def SQRT_S_MMR6 : StdMMR6Rel, SQRT_S_MMR6_ENC, SQRT_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def SQRT_D_MMR6 : StdMMR6Rel, SQRT_D_MMR6_ENC, SQRT_D_MMR6_DESC,
ISA_MICROMIPS32R6;
-def RSQRT_S_MMR6 : StdMMR6Rel, RSQRT_S_MMR6_ENC, RSQRT_S_MMR6_DESC,
- ISA_MICROMIPS32R6;
-def RSQRT_D_MMR6 : StdMMR6Rel, RSQRT_D_MMR6_ENC, RSQRT_D_MMR6_DESC,
- ISA_MICROMIPS32R6;
def SB_MMR6 : StdMMR6Rel, SB_MMR6_DESC, SB_MMR6_ENC, ISA_MICROMIPS32R6;
def SBE_MMR6 : StdMMR6Rel, SBE_MMR6_DESC, SBE_MMR6_ENC, ISA_MICROMIPS32R6;
def SCE_MMR6 : StdMMR6Rel, SCE_MMR6_DESC, SCE_MMR6_ENC, ISA_MICROMIPS32R6;
@@ -1593,9 +1693,6 @@ def JALRC_HB_MMR6 : R6MMR6Rel, JALRC_HB_MMR6_ENC, JALRC_HB_MMR6_DESC,
def EXT_MMR6 : StdMMR6Rel, EXT_MMR6_ENC, EXT_MMR6_DESC, ISA_MICROMIPS32R6;
def INS_MMR6 : StdMMR6Rel, INS_MMR6_ENC, INS_MMR6_DESC, ISA_MICROMIPS32R6;
def JALRC_MMR6 : R6MMR6Rel, JALRC_MMR6_ENC, JALRC_MMR6_DESC, ISA_MICROMIPS32R6;
-def RECIP_S_MMR6 : StdMMR6Rel, RECIP_S_MMR6_ENC, RECIP_S_MMR6_DESC,
- ISA_MICROMIPS32R6;
-def RECIP_D_MMR6 : StdMMR6Rel, RECIP_D_MMR6_ENC, RECIP_D_MMR6_DESC, ISA_MICROMIPS32R6;
def RINT_S_MMR6 : StdMMR6Rel, RINT_S_MMR6_ENC, RINT_S_MMR6_DESC,
ISA_MICROMIPS32R6;
def RINT_D_MMR6 : StdMMR6Rel, RINT_D_MMR6_ENC, RINT_D_MMR6_DESC, ISA_MICROMIPS32R6;
@@ -1661,6 +1758,10 @@ def BEQC_MMR6 : R6MMR6Rel, BEQC_MMR6_ENC, BEQC_MMR6_DESC, ISA_MICROMIPS32R6,
DecodeDisambiguates<"POP35GroupBranchMMR6">;
def BNEC_MMR6 : R6MMR6Rel, BNEC_MMR6_ENC, BNEC_MMR6_DESC, ISA_MICROMIPS32R6,
DecodeDisambiguates<"POP37GroupBranchMMR6">;
+def BLTZC_MMR6 : R6MMR6Rel, BLTZC_MMR6_ENC, BLTZC_MMR6_DESC, ISA_MICROMIPS32R6;
+def BLEZC_MMR6 : R6MMR6Rel, BLEZC_MMR6_ENC, BLEZC_MMR6_DESC, ISA_MICROMIPS32R6;
+def BGEZC_MMR6 : R6MMR6Rel, BGEZC_MMR6_ENC, BGEZC_MMR6_DESC, ISA_MICROMIPS32R6;
+def BGTZC_MMR6 : R6MMR6Rel, BGTZC_MMR6_ENC, BGTZC_MMR6_DESC, ISA_MICROMIPS32R6;
def BGEZALC_MMR6 : R6MMR6Rel, BGEZALC_MMR6_ENC, BGEZALC_MMR6_DESC,
ISA_MICROMIPS32R6;
def BGTZALC_MMR6 : R6MMR6Rel, BGTZALC_MMR6_ENC, BGTZALC_MMR6_DESC,
@@ -1727,6 +1828,10 @@ def : MipsInstAlias<"xor $rs, $imm",
def : MipsInstAlias<"not $rt, $rs",
(NOR_MMR6 GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>,
ISA_MICROMIPS32R6;
+def : MipsInstAlias<"seh $rd", (SEH_MMR6 GPR32Opnd:$rd, GPR32Opnd:$rd), 0>,
+ ISA_MICROMIPS32R6;
+def : MipsInstAlias<"seb $rd", (SEB_MMR6 GPR32Opnd:$rd, GPR32Opnd:$rd), 0>,
+ ISA_MICROMIPS32R6;
//===----------------------------------------------------------------------===//
//
@@ -1772,3 +1877,5 @@ let AddedComplexity = 41 in {
def : LoadRegImmPat<LDC1_D64_MMR6, f64, load>, FGR_64, ISA_MICROMIPS32R6;
def : StoreRegImmPat<SDC1_D64_MMR6, f64>, FGR_64, ISA_MICROMIPS32R6;
}
+
+def TAILCALL_MMR6 : TailCall<BC_MMR6, brtarget26_mm>, ISA_MICROMIPS32R6;
diff --git a/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td
index 4add305..26062bf 100644
--- a/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td
+++ b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td
@@ -219,3 +219,49 @@ class POOL32S_3R_FM_MMR6<string instr_asm, bits<9> funct>
let Inst{10-9} = 0b00;
let Inst{8-0} = funct;
}
+
+class POOL32S_DBITSWAP_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm>,
+ MipsR6Inst {
+ bits<5> rt;
+ bits<5> rd;
+
+ bits<32> Inst;
+
+ let Inst{31-26} = 0b010110;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rd;
+ let Inst{15-12} = 0b0000;
+ let Inst{11-6} = 0b101100;
+ let Inst{5-0} = 0b111100;
+}
+
+class POOL32S_3RSA_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm>,
+ MipsR6Inst {
+ bits<5> rt;
+ bits<5> rs;
+ bits<5> rd;
+ bits<2> sa;
+
+ bits<32> Inst;
+
+ let Inst{31-26} = 0b010110;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-11} = rd;
+ let Inst{10-9} = sa;
+ let Inst{8-6} = 0b100;
+ let Inst{5-0} = 0b000100;
+}
+
+class PCREL_1ROFFSET19_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm>,
+ MipsR6Inst {
+ bits<5> rt;
+ bits<19> offset;
+
+ bits<32> Inst;
+
+ let Inst{31-26} = 0b011110;
+ let Inst{25-21} = rt;
+ let Inst{20-19} = 0b10;
+ let Inst{18-0} = offset;
+}
diff --git a/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td
index 87c41de..05aad51 100644
--- a/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td
@@ -67,6 +67,9 @@ class SD_MM64R6_ENC : LD_SD_32_2R_OFFSET16_FM_MMR6<"sd", 0b110110>;
class DSRL_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsrl", 0b001000000>;
class DSRL32_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsrl32", 0b001001000>;
class DSRLV_MM64R6_ENC : POOL32S_3R_FM_MMR6<"dsrlv", 0b001010000>;
+class DBITSWAP_MM64R6_ENC : POOL32S_DBITSWAP_FM_MMR6<"dbitswap">;
+class DLSA_MM64R6_ENC : POOL32S_3RSA_FM_MMR6<"dlsa">;
+class LWUPC_MM64R6_ENC : PCREL_1ROFFSET19_FM_MMR6<"lwupc">;
//===----------------------------------------------------------------------===//
//
@@ -74,24 +77,28 @@ class DSRLV_MM64R6_ENC : POOL32S_3R_FM_MMR6<"dsrlv", 0b001010000>;
//
//===----------------------------------------------------------------------===//
-class DAUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
+class DAUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin>
: MMR6Arch<instr_asm>, MipsR6Inst {
dag OutOperandList = (outs GPROpnd:$rt);
- dag InOperandList = (ins GPROpnd:$rs, simm16:$imm);
+ dag InOperandList = (ins GPROpnd:$rs, uimm16:$imm);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
}
-class DAUI_MMR6_DESC : DAUI_MMR6_DESC_BASE<"daui", GPR64Opnd>;
+class DAUI_MMR6_DESC : DAUI_MMR6_DESC_BASE<"daui", GPR64Opnd, II_DAUI>;
-class DAHI_DATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
+class DAHI_DATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin>
: MMR6Arch<instr_asm>, MipsR6Inst {
dag OutOperandList = (outs GPROpnd:$rs);
- dag InOperandList = (ins GPROpnd:$rt, simm16:$imm);
- string AsmString = !strconcat(instr_asm, "\t$rt, $imm");
+ dag InOperandList = (ins GPROpnd:$rt, uimm16:$imm);
+ string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm");
string Constraints = "$rs = $rt";
+ InstrItinClass Itinerary = Itin;
}
-class DAHI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dahi", GPR64Opnd>;
-class DATI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dati", GPR64Opnd>;
+class DAHI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dahi", GPR64Opnd, II_DAHI>;
+class DATI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dati", GPR64Opnd, II_DATI>;
class EXTBITS_DESC_BASE<string instr_asm, RegisterOperand RO, Operand PosOpnd,
Operand SizeOpnd, SDPatternOperator Op = null_frag>
@@ -115,26 +122,33 @@ class DEXTU_MMR6_DESC : EXTBITS_DESC_BASE<"dextu", GPR64Opnd, uimm5_plus32,
uimm5_plus1, MipsExt>;
class DALIGN_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
- Operand ImmOpnd> : MMR6Arch<instr_asm>, MipsR6Inst {
+ Operand ImmOpnd, InstrItinClass itin>
+ : MMR6Arch<instr_asm>, MipsR6Inst {
dag OutOperandList = (outs GPROpnd:$rd);
dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp);
string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = itin;
}
-class DALIGN_MMR6_DESC : DALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3>;
+class DALIGN_MMR6_DESC : DALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3,
+ II_DALIGN>;
-class DDIV_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"ddiv", GPR64Opnd, sdiv>;
-class DMOD_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"dmod", GPR64Opnd, srem>;
-class DDIVU_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"ddivu", GPR64Opnd, udiv>;
-class DMODU_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"dmodu", GPR64Opnd, urem>;
+class DDIV_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"ddiv", GPR64Opnd, II_DDIV,
+ sdiv>;
+class DMOD_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"dmod", GPR64Opnd, II_DMOD,
+ srem>;
+class DDIVU_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"ddivu", GPR64Opnd, II_DDIVU,
+ udiv>;
+class DMODU_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"dmodu", GPR64Opnd, II_DMODU,
+ urem>;
class DCLO_MM64R6_DESC {
dag OutOperandList = (outs GPR64Opnd:$rt);
dag InOperandList = (ins GPR64Opnd:$rs);
string AsmString = !strconcat("dclo", "\t$rt, $rs");
list<dag> Pattern = [(set GPR64Opnd:$rt, (ctlz (not GPR64Opnd:$rs)))];
- InstrItinClass Itinerary = II_CLO;
+ InstrItinClass Itinerary = II_DCLO;
Format Form = FrmR;
string BaseOpcode = "dclo";
}
@@ -144,7 +158,7 @@ class DCLZ_MM64R6_DESC {
dag InOperandList = (ins GPR64Opnd:$rs);
string AsmString = !strconcat("dclz", "\t$rt, $rs");
list<dag> Pattern = [(set GPR64Opnd:$rt, (ctlz GPR64Opnd:$rs))];
- InstrItinClass Itinerary = II_CLZ;
+ InstrItinClass Itinerary = II_DCLZ;
Format Form = FrmR;
string BaseOpcode = "dclz";
}
@@ -154,16 +168,18 @@ class DINSU_MM64R6_DESC : InsBase<"dinsu", GPR64Opnd, uimm5_plus32,
class DINSM_MM64R6_DESC : InsBase<"dinsm", GPR64Opnd, uimm5, uimm_range_2_64>;
class DINS_MM64R6_DESC : InsBase<"dins", GPR64Opnd, uimm5, uimm5_inssize_plus1,
MipsIns>;
-class DMTC0_MM64R6_DESC : MTC0_MMR6_DESC_BASE<"dmtc0", COP0Opnd, GPR64Opnd>;
+class DMTC0_MM64R6_DESC : MTC0_MMR6_DESC_BASE<"dmtc0", COP0Opnd, GPR64Opnd,
+ II_DMTC0>;
class DMTC1_MM64R6_DESC : MTC1_MMR6_DESC_BASE<"dmtc1", FGR64Opnd, GPR64Opnd,
II_DMTC1, bitconvert>;
-class DMTC2_MM64R6_DESC : MTC2_MMR6_DESC_BASE<"dmtc2", COP2Opnd, GPR64Opnd>;
-
-class DMFC0_MM64R6_DESC : MFC0_MMR6_DESC_BASE<"dmfc0", GPR64Opnd, COP0Opnd>;
+class DMTC2_MM64R6_DESC : MTC2_MMR6_DESC_BASE<"dmtc2", COP2Opnd, GPR64Opnd,
+ II_DMTC2>;
+class DMFC0_MM64R6_DESC : MFC0_MMR6_DESC_BASE<"dmfc0", GPR64Opnd, COP0Opnd,
+ II_DMFC0>;
class DMFC1_MM64R6_DESC : MFC1_MMR6_DESC_BASE<"dmfc1", GPR64Opnd, FGR64Opnd,
II_DMFC1, bitconvert>;
-class DMFC2_MM64R6_DESC : MFC2_MMR6_DESC_BASE<"dmfc2", GPR64Opnd, COP2Opnd>;
-
+class DMFC2_MM64R6_DESC : MFC2_MMR6_DESC_BASE<"dmfc2", GPR64Opnd, COP2Opnd,
+ II_DMFC2>;
class DADD_MM64R6_DESC : ArithLogicR<"dadd", GPR64Opnd, 1, II_DADD>;
class DADDIU_MM64R6_DESC : ArithLogicI<"daddiu", simm16_64, GPR64Opnd,
II_DADDIU, immSExt16, add>,
@@ -188,7 +204,8 @@ class DSUB_DESC_BASE<string instr_asm, RegisterOperand RO,
class DSUB_MM64R6_DESC : DSUB_DESC_BASE<"dsub", GPR64Opnd, II_DSUB>;
class DSUBU_MM64R6_DESC : DSUB_DESC_BASE<"dsubu", GPR64Opnd, II_DSUBU, sub>;
-class LDPC_MM64R6_DESC : PCREL_MMR6_DESC_BASE<"ldpc", GPR64Opnd, simm18_lsl3>;
+class LDPC_MM64R6_DESC : PCREL_MMR6_DESC_BASE<"ldpc", GPR64Opnd, simm18_lsl3,
+ II_LDPC>;
class MUL_MM64R6_DESC_BASE<string opstr, RegisterOperand GPROpnd,
InstrItinClass Itin = NoItinerary,
@@ -207,19 +224,20 @@ class DMULU_MM64R6_DESC : MUL_MM64R6_DESC_BASE<"dmulu", GPR64Opnd, II_DMULU>;
class DMUHU_MM64R6_DESC : MUL_MM64R6_DESC_BASE<"dmuhu", GPR64Opnd, II_DMUHU,
mulhu>;
-class DSBH_DSHD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> {
+class DSBH_DSHD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+ InstrItinClass Itin> {
dag OutOperandList = (outs GPROpnd:$rt);
dag InOperandList = (ins GPROpnd:$rs);
string AsmString = !strconcat(instr_asm, "\t$rt, $rs");
bit hasSideEffects = 0;
list<dag> Pattern = [];
- InstrItinClass Itinerary = NoItinerary;
+ InstrItinClass Itinerary = Itin;
Format Form = FrmR;
string BaseOpcode = instr_asm;
}
-class DSBH_MM64R6_DESC : DSBH_DSHD_DESC_BASE<"dsbh", GPR64Opnd>;
-class DSHD_MM64R6_DESC : DSBH_DSHD_DESC_BASE<"dshd", GPR64Opnd>;
+class DSBH_MM64R6_DESC : DSBH_DSHD_DESC_BASE<"dsbh", GPR64Opnd, II_DSBH>;
+class DSHD_MM64R6_DESC : DSBH_DSHD_DESC_BASE<"dshd", GPR64Opnd, II_DSHD>;
class SHIFT_ROTATE_IMM_MM64R6<string instr_asm, Operand ImmOpnd,
InstrItinClass itin,
@@ -308,6 +326,32 @@ class SD_MM64R6_DESC {
string DecoderMethod = "DecodeMemMMImm16";
}
+class DBITSWAP_MM64R6_DESC {
+ dag OutOperandList = (outs GPR64Opnd:$rd);
+ dag InOperandList = (ins GPR64Opnd:$rt);
+ string AsmString = !strconcat("dbitswap", "\t$rd, $rt");
+ list<dag> Pattern = [];
+ InstrItinClass Itinerary = II_DBITSWAP;
+}
+
+class DLSA_MM64R6_DESC {
+ dag OutOperandList = (outs GPR64Opnd:$rd);
+ dag InOperandList = (ins GPR64Opnd:$rt, GPR64Opnd:$rs, uimm2_plus1:$sa);
+ string AsmString = "dlsa\t$rt, $rs, $rd, $sa";
+ list<dag> Pattern = [];
+ InstrItinClass Itinerary = II_DLSA;
+}
+
+class LWUPC_MM64R6_DESC {
+ dag OutOperandList = (outs GPR64Opnd:$rt);
+ dag InOperandList = (ins simm19_lsl2:$offset);
+ string AsmString = "lwupc\t$rt, $offset";
+ list<dag> Pattern = [];
+ InstrItinClass Itinerary = II_LWUPC;
+ bit mayLoad = 1;
+ bit IsPCRelativeLoad = 1;
+}
+
//===----------------------------------------------------------------------===//
//
// Instruction Definitions
@@ -316,8 +360,10 @@ class SD_MM64R6_DESC {
let DecoderNamespace = "MicroMipsR6" in {
def DAUI_MM64R6 : StdMMR6Rel, DAUI_MMR6_DESC, DAUI_MMR6_ENC, ISA_MICROMIPS64R6;
- def DAHI_MM64R6 : StdMMR6Rel, DAHI_MMR6_DESC, DAHI_MMR6_ENC, ISA_MICROMIPS64R6;
- def DATI_MM64R6 : StdMMR6Rel, DATI_MMR6_DESC, DATI_MMR6_ENC, ISA_MICROMIPS64R6;
+ let DecoderMethod = "DecodeDAHIDATIMMR6" in {
+ def DAHI_MM64R6 : StdMMR6Rel, DAHI_MMR6_DESC, DAHI_MMR6_ENC, ISA_MICROMIPS64R6;
+ def DATI_MM64R6 : StdMMR6Rel, DATI_MMR6_DESC, DATI_MMR6_ENC, ISA_MICROMIPS64R6;
+ }
def DEXT_MM64R6 : StdMMR6Rel, DEXT_MMR6_DESC, DEXT_MMR6_ENC,
ISA_MICROMIPS64R6;
def DEXTM_MM64R6 : StdMMR6Rel, DEXTM_MMR6_DESC, DEXTM_MMR6_ENC,
@@ -412,8 +458,17 @@ let DecoderNamespace = "MicroMipsR6" in {
ISA_MICROMIPS64R6;
def DSRLV_MM64R6 : StdMMR6Rel, DSRLV_MM64R6_ENC, DSRLV_MM64R6_DESC,
ISA_MICROMIPS64R6;
+ def DBITSWAP_MM64R6 : R6MMR6Rel, DBITSWAP_MM64R6_ENC, DBITSWAP_MM64R6_DESC,
+ ISA_MICROMIPS64R6;
+ def DLSA_MM64R6 : R6MMR6Rel, DLSA_MM64R6_ENC, DLSA_MM64R6_DESC,
+ ISA_MICROMIPS64R6;
+ def LWUPC_MM64R6 : R6MMR6Rel, LWUPC_MM64R6_ENC, LWUPC_MM64R6_DESC,
+ ISA_MICROMIPS64R6;
}
+let AdditionalPredicates = [InMicroMips] in
+defm : MaterializeImms<i64, ZERO_64, DADDIU_MM64R6, LUi64, ORi64>;
+
//===----------------------------------------------------------------------===//
//
// Arbitrary patterns that map to one or more instructions
@@ -503,11 +558,11 @@ def : MipsInstAlias<"dneg $rt, $rs",
(DSUB_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>,
ISA_MICROMIPS64R6;
def : MipsInstAlias<"dneg $rt",
- (DSUB_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 0>,
+ (DSUB_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 1>,
ISA_MICROMIPS64R6;
def : MipsInstAlias<"dnegu $rt, $rs",
(DSUBU_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>,
ISA_MICROMIPS64R6;
def : MipsInstAlias<"dnegu $rt",
- (DSUBU_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 0>,
+ (DSUBU_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 1>,
ISA_MICROMIPS64R6;
diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td
index 7b0e00b..5600f71 100644
--- a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td
+++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFPU.td
@@ -27,9 +27,20 @@ def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>,
SWXC1_FM_MM<0x188>, INSN_MIPS5_32R2_NOT_32R6_64R6;
def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>,
- CEQS_FM_MM<0>;
+ CEQS_FM_MM<0> {
+ // FIXME: This is a required to work around the fact that these instructions
+ // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
+ // fcc register set is used directly.
+ bits<3> fcc = 0;
+}
+
def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>,
- CEQS_FM_MM<1>;
+ CEQS_FM_MM<1> {
+ // FIXME: This is a required to work around the fact that these instructions
+ // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
+ // fcc register set is used directly.
+ bits<3> fcc = 0;
+}
def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, II_BC1F, MIPS_BRANCH_F>,
BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6;
@@ -99,11 +110,6 @@ def MOVT_D32_MM : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D,
MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 1>;
def MOVF_D32_MM : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D,
MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 1>;
-
-def CFC1_MM : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>,
- MFC1_FM_MM<0x40>;
-def CTC1_MM : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>,
- MFC1_FM_MM<0x60>;
def MFC1_MM : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd,
II_MFC1, bitconvert>, MFC1_FM_MM<0x80>;
def MTC1_MM : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd,
@@ -141,6 +147,22 @@ let AdditionalPredicates = [InMicroMips] in {
MFC1_FM_MM<0xe0>, ISA_MIPS32R2, FGR_32;
def MFHC1_MM : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, AFGR64Opnd, II_MFHC1>,
MFC1_FM_MM<0xc0>, ISA_MIPS32R2, FGR_32;
+ let DecoderNamespace = "MicroMips" in {
+ def CFC1_MM : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>,
+ MFC1_FM_MM<0x40>;
+ def CTC1_MM : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>,
+ MFC1_FM_MM<0x60>;
+ def RECIP_S_MM : MMRel, ABSS_FT<"recip.s", FGR32Opnd, FGR32Opnd,
+ II_RECIP_S>,
+ ROUND_W_FM_MM<0b0, 0b01001000>;
+ def RECIP_D_MM : MMRel, ABSS_FT<"recip.d", AFGR64Opnd, AFGR64Opnd,
+ II_RECIP_D>, ROUND_W_FM_MM<0b1, 0b01001000>;
+ def RSQRT_S_MM : MMRel, ABSS_FT<"rsqrt.s", FGR32Opnd, FGR32Opnd,
+ II_RECIP_S>,
+ ROUND_W_FM_MM<0b0, 0b00001000>;
+ def RSQRT_D_MM : MMRel, ABSS_FT<"rsqrt.d", AFGR64Opnd, AFGR64Opnd,
+ II_RECIP_D>, ROUND_W_FM_MM<0b1, 0b00001000>;
+ }
let DecoderNamespace = "MicroMips", DecoderMethod = "DecodeFMemMMR2" in {
def LDC1_MM : MMRel, LW_FT<"ldc1", AFGR64Opnd, mem_mm_16, II_LDC1, load>,
LW_FM_MM<0x2f>, FGR_32 {
@@ -153,6 +175,98 @@ let AdditionalPredicates = [InMicroMips] in {
def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, mem_mm_16, II_SWC1, store>,
LW_FM_MM<0x26>;
}
+
+ multiclass C_COND_MM<string TypeStr, RegisterOperand RC, bits<2> fmt,
+ InstrItinClass itin> {
+ def C_F_#NAME#_MM : MMRel, C_COND_FT<"f", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 0> {
+ let BaseOpcode = "c.f."#NAME;
+ let isCommutable = 1;
+ }
+ def C_UN_#NAME#_MM : MMRel, C_COND_FT<"un", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 1> {
+ let BaseOpcode = "c.un."#NAME;
+ let isCommutable = 1;
+ }
+ def C_EQ_#NAME#_MM : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 2> {
+ let BaseOpcode = "c.eq."#NAME;
+ let isCommutable = 1;
+ }
+ def C_UEQ_#NAME#_MM : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 3> {
+ let BaseOpcode = "c.ueq."#NAME;
+ let isCommutable = 1;
+ }
+ def C_OLT_#NAME#_MM : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 4> {
+ let BaseOpcode = "c.olt."#NAME;
+ }
+ def C_ULT_#NAME#_MM : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 5> {
+ let BaseOpcode = "c.ult."#NAME;
+ }
+ def C_OLE_#NAME#_MM : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 6> {
+ let BaseOpcode = "c.ole."#NAME;
+ }
+ def C_ULE_#NAME#_MM : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 7> {
+ let BaseOpcode = "c.ule."#NAME;
+ }
+ def C_SF_#NAME#_MM : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 8> {
+ let BaseOpcode = "c.sf."#NAME;
+ let isCommutable = 1;
+ }
+ def C_NGLE_#NAME#_MM : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 9> {
+ let BaseOpcode = "c.ngle."#NAME;
+ }
+ def C_SEQ_#NAME#_MM : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 10> {
+ let BaseOpcode = "c.seq."#NAME;
+ let isCommutable = 1;
+ }
+ def C_NGL_#NAME#_MM : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 11> {
+ let BaseOpcode = "c.ngl."#NAME;
+ }
+ def C_LT_#NAME#_MM : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 12> {
+ let BaseOpcode = "c.lt."#NAME;
+ }
+ def C_NGE_#NAME#_MM : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 13> {
+ let BaseOpcode = "c.nge."#NAME;
+ }
+ def C_LE_#NAME#_MM : MMRel, C_COND_FT<"le", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 14> {
+ let BaseOpcode = "c.le."#NAME;
+ }
+ def C_NGT_#NAME#_MM : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>,
+ C_COND_FM_MM<fmt, 15> {
+ let BaseOpcode = "c.ngt."#NAME;
+ }
+ }
+
+ defm S : C_COND_MM<"s", FGR32Opnd, 0b00, II_C_CC_S>,
+ ISA_MIPS1_NOT_32R6_64R6;
+ defm D32 : C_COND_MM<"d", AFGR64Opnd, 0b01, II_C_CC_D>,
+ ISA_MIPS1_NOT_32R6_64R6, FGR_32;
+ let DecoderNamespace = "Mips64" in
+ defm D64 : C_COND_MM<"d", FGR64Opnd, 0b01, II_C_CC_D>,
+ ISA_MIPS1_NOT_32R6_64R6, FGR_64;
+
+ defm S_MM : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT,
+ ISA_MIPS1_NOT_32R6_64R6;
+ defm D32_MM : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT,
+ ISA_MIPS1_NOT_32R6_64R6, FGR_32;
+ defm D64_MM : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT,
+ ISA_MIPS1_NOT_32R6_64R6, FGR_64;
+
+ defm : BC1_ALIASES<BC1T_MM, "bc1t", BC1F_MM, "bc1f">,
+ ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT;
}
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td
index 79ef648..7749768 100644
--- a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td
+++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td
@@ -599,6 +599,17 @@ class SYNC_FM_MM : MMArch {
let Inst{5-0} = 0x3c;
}
+class SYNCI_FM_MM : MMArch {
+ bits<5> rs;
+ bits<16> offset;
+ bits<32> Inst;
+
+ let Inst{31-26} = 0b010000;
+ let Inst{25-21} = 0b10000;
+ let Inst{20-16} = rs;
+ let Inst{15-0} = offset;
+}
+
class BRK_FM_MM : MMArch {
bits<10> code_1;
bits<10> code_2;
@@ -755,6 +766,7 @@ class SWXC1_FM_MM<bits<9> funct> : MMArch {
class CEQS_FM_MM<bits<2> fmt> : MMArch {
bits<5> fs;
bits<5> ft;
+ bits<3> fcc;
bits<4> cond;
bits<32> Inst;
@@ -762,13 +774,17 @@ class CEQS_FM_MM<bits<2> fmt> : MMArch {
let Inst{31-26} = 0x15;
let Inst{25-21} = ft;
let Inst{20-16} = fs;
- let Inst{15-13} = 0x0; // cc
+ let Inst{15-13} = fcc;
let Inst{12} = 0;
let Inst{11-10} = fmt;
let Inst{9-6} = cond;
let Inst{5-0} = 0x3c;
}
+class C_COND_FM_MM<bits <2> fmt, bits<4> c> : CEQS_FM_MM<fmt> {
+ let cond = c;
+}
+
class BC1F_FM_MM<bits<5> tf> : MMArch {
bits<16> offset;
@@ -1023,3 +1039,16 @@ class ADDIUPC_FM_MM {
let Inst{25-23} = rs;
let Inst{22-0} = imm;
}
+
+class POOL32A_CFTC2_FM_MM<bits<10> funct> : MMArch {
+ bits<5> rt;
+ bits<5> impl;
+
+ bits<32> Inst;
+
+ let Inst{31-26} = 0b000000;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = impl;
+ let Inst{15-6} = funct;
+ let Inst{5-0} = 0b111100;
+}
diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
index f27370f..c0de9e7 100644
--- a/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td
@@ -194,20 +194,20 @@ class CompactBranchMM<string opstr, DAGOperand opnd, PatFrag cond_op,
let canFoldAsLoad = 1 in
class LoadLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
- Operand MemOpnd> :
+ Operand MemOpnd, InstrItinClass Itin> :
InstSE<(outs RO:$rt), (ins MemOpnd:$addr, RO:$src),
!strconcat(opstr, "\t$rt, $addr"),
[(set RO:$rt, (OpNode addrimm12:$addr, RO:$src))],
- NoItinerary, FrmI> {
+ Itin, FrmI> {
let DecoderMethod = "DecodeMemMMImm12";
string Constraints = "$src = $rt";
}
class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
- Operand MemOpnd>:
+ Operand MemOpnd, InstrItinClass Itin>:
InstSE<(outs), (ins RO:$rt, MemOpnd:$addr),
!strconcat(opstr, "\t$rt, $addr"),
- [(OpNode RO:$rt, addrimm12:$addr)], NoItinerary, FrmI> {
+ [(OpNode RO:$rt, addrimm12:$addr)], Itin, FrmI> {
let DecoderMethod = "DecodeMemMMImm12";
}
@@ -248,39 +248,37 @@ def regpair : Operand<i32> {
let MIOperandInfo = (ops ptr_rc, ptr_rc);
}
-class StorePairMM<string opstr, InstrItinClass Itin = NoItinerary,
- ComplexPattern Addr = addr> :
- InstSE<(outs), (ins regpair:$rt, mem_simm12:$addr),
- !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> {
+class StorePairMM<string opstr, ComplexPattern Addr = addr>
+ : InstSE<(outs), (ins regpair:$rt, mem_simm12:$addr),
+ !strconcat(opstr, "\t$rt, $addr"), [], II_SWP, FrmI, opstr> {
let DecoderMethod = "DecodeMemMMImm12";
let mayStore = 1;
}
-class LoadPairMM<string opstr, InstrItinClass Itin = NoItinerary,
- ComplexPattern Addr = addr> :
- InstSE<(outs regpair:$rt), (ins mem_simm12:$addr),
- !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> {
+class LoadPairMM<string opstr, ComplexPattern Addr = addr>
+ : InstSE<(outs regpair:$rt), (ins mem_simm12:$addr),
+ !strconcat(opstr, "\t$rt, $addr"), [], II_LWP, FrmI, opstr> {
let DecoderMethod = "DecodeMemMMImm12";
let mayLoad = 1;
}
class LLBaseMM<string opstr, RegisterOperand RO> :
InstSE<(outs RO:$rt), (ins mem_mm_12:$addr),
- !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> {
+ !strconcat(opstr, "\t$rt, $addr"), [], II_LL, FrmI> {
let DecoderMethod = "DecodeMemMMImm12";
let mayLoad = 1;
}
class LLEBaseMM<string opstr, RegisterOperand RO> :
InstSE<(outs RO:$rt), (ins mem_simm9:$addr),
- !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> {
+ !strconcat(opstr, "\t$rt, $addr"), [], II_LLE, FrmI> {
let DecoderMethod = "DecodeMemMMImm9";
let mayLoad = 1;
}
class SCBaseMM<string opstr, RegisterOperand RO> :
InstSE<(outs RO:$dst), (ins RO:$rt, mem_mm_12:$addr),
- !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> {
+ !strconcat(opstr, "\t$rt, $addr"), [], II_SC, FrmI> {
let DecoderMethod = "DecodeMemMMImm12";
let mayStore = 1;
let Constraints = "$rt = $dst";
@@ -288,7 +286,7 @@ class SCBaseMM<string opstr, RegisterOperand RO> :
class SCEBaseMM<string opstr, RegisterOperand RO> :
InstSE<(outs RO:$dst), (ins RO:$rt, mem_simm9:$addr),
- !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> {
+ !strconcat(opstr, "\t$rt, $addr"), [], II_SCE, FrmI> {
let DecoderMethod = "DecodeMemMMImm9";
let mayStore = 1;
let Constraints = "$rt = $dst";
@@ -331,7 +329,7 @@ class LogicRMM16<string opstr, RegisterOperand RO,
class NotMM16<string opstr, RegisterOperand RO> :
MicroMipsInst16<(outs RO:$rt), (ins RO:$rs),
!strconcat(opstr, "\t$rt, $rs"),
- [(set RO:$rt, (not RO:$rs))], NoItinerary, FrmR>;
+ [(set RO:$rt, (not RO:$rs))], II_NOT, FrmR>;
class ShiftIMM16<string opstr, Operand ImmOpnd, RegisterOperand RO,
InstrItinClass Itin = NoItinerary> :
@@ -385,23 +383,23 @@ class LoadGPMM16<string opstr, DAGOperand RO, InstrItinClass Itin,
class AddImmUR2<string opstr, RegisterOperand RO> :
MicroMipsInst16<(outs RO:$rd), (ins RO:$rs, simm3_lsa2:$imm),
!strconcat(opstr, "\t$rd, $rs, $imm"),
- [], NoItinerary, FrmR> {
+ [], II_ADDIU, FrmR> {
let isCommutable = 1;
}
class AddImmUS5<string opstr, RegisterOperand RO> :
MicroMipsInst16<(outs RO:$dst), (ins RO:$rd, simm4:$imm),
- !strconcat(opstr, "\t$rd, $imm"), [], NoItinerary, FrmR> {
+ !strconcat(opstr, "\t$rd, $imm"), [], II_ADDIU, FrmR> {
let Constraints = "$rd = $dst";
}
class AddImmUR1SP<string opstr, RegisterOperand RO> :
MicroMipsInst16<(outs RO:$rd), (ins uimm6_lsl2:$imm),
- !strconcat(opstr, "\t$rd, $imm"), [], NoItinerary, FrmR>;
+ !strconcat(opstr, "\t$rd, $imm"), [], II_ADDIU, FrmR>;
class AddImmUSP<string opstr> :
MicroMipsInst16<(outs), (ins simm9_addiusp:$imm),
- !strconcat(opstr, "\t$imm"), [], NoItinerary, FrmI>;
+ !strconcat(opstr, "\t$imm"), [], II_ADDIU, FrmI>;
class MoveFromHILOMM<string opstr, RegisterOperand RO, Register UseReg> :
MicroMipsInst16<(outs RO:$rd), (ins), !strconcat(opstr, "\t$rd"),
@@ -410,17 +408,15 @@ class MoveFromHILOMM<string opstr, RegisterOperand RO, Register UseReg> :
let hasSideEffects = 0;
}
-class MoveMM16<string opstr, RegisterOperand RO, bit isComm = 0,
- InstrItinClass Itin = NoItinerary> :
- MicroMipsInst16<(outs RO:$rd), (ins RO:$rs),
- !strconcat(opstr, "\t$rd, $rs"), [], Itin, FrmR> {
- let isCommutable = isComm;
+class MoveMM16<string opstr, RegisterOperand RO>
+ : MicroMipsInst16<(outs RO:$rd), (ins RO:$rs),
+ !strconcat(opstr, "\t$rd, $rs"), [], II_MOVE, FrmR> {
let isReMaterializable = 1;
}
class LoadImmMM16<string opstr, Operand Od, RegisterOperand RO> :
MicroMipsInst16<(outs RO:$rd), (ins Od:$imm),
- !strconcat(opstr, "\t$rd, $imm"), [], NoItinerary, FrmI> {
+ !strconcat(opstr, "\t$rd, $imm"), [], II_LI, FrmI> {
let isReMaterializable = 1;
}
@@ -472,10 +468,10 @@ class JumpRegCMM16<string opstr, RegisterOperand RO> :
}
// Break16 and Sdbbp16
-class BrkSdbbp16MM<string opstr> :
+class BrkSdbbp16MM<string opstr, InstrItinClass Itin> :
MicroMipsInst16<(outs), (ins uimm4:$code_),
!strconcat(opstr, "\t$code_"),
- [], NoItinerary, FrmOther>;
+ [], Itin, FrmOther>;
class CBranchZeroMM<string opstr, DAGOperand opnd, RegisterOperand RO> :
MicroMipsInst16<(outs), (ins RO:$rs, opnd:$offset),
@@ -505,18 +501,17 @@ let isCall = 1, hasDelaySlot = 1, Defs = [RA] in {
}
class LoadWordIndexedScaledMM<string opstr, RegisterOperand RO,
- InstrItinClass Itin = NoItinerary,
SDPatternOperator OpNode = null_frag> :
InstSE<(outs RO:$rd), (ins PtrRC:$base, PtrRC:$index),
- !strconcat(opstr, "\t$rd, ${index}(${base})"), [], Itin, FrmFI>;
+ !strconcat(opstr, "\t$rd, ${index}(${base})"), [], II_LWXS, FrmFI>;
class PrefetchIndexed<string opstr> :
InstSE<(outs), (ins PtrRC:$base, PtrRC:$index, uimm5:$hint),
- !strconcat(opstr, "\t$hint, ${index}(${base})"), [], NoItinerary, FrmOther>;
+ !strconcat(opstr, "\t$hint, ${index}(${base})"), [], II_PREF, FrmOther>;
class AddImmUPC<string opstr, RegisterOperand RO> :
InstSE<(outs RO:$rs), (ins simm23_lsl2:$imm),
- !strconcat(opstr, "\t$rs, $imm"), [], NoItinerary, FrmR>;
+ !strconcat(opstr, "\t$rs, $imm"), [], II_ADDIU, FrmR>;
/// A list of registers used by load/store multiple instructions.
def RegListAsmOperand : AsmOperandClass {
@@ -650,40 +645,50 @@ def BEQZ16_MM : CBranchZeroMM<"beqz16", brtarget7_mm, GPRMM16Opnd>,
def BNEZ16_MM : CBranchZeroMM<"bnez16", brtarget7_mm, GPRMM16Opnd>,
BEQNEZ_FM_MM16<0x2b>;
def B16_MM : UncondBranchMM16<"b16">, B16_FM;
-def BREAK16_MM : BrkSdbbp16MM<"break16">, BRKSDBBP16_FM_MM<0x28>,
+def BREAK16_MM : BrkSdbbp16MM<"break16", II_BREAK>, BRKSDBBP16_FM_MM<0x28>,
ISA_MICROMIPS_NOT_32R6_64R6;
-def SDBBP16_MM : BrkSdbbp16MM<"sdbbp16">, BRKSDBBP16_FM_MM<0x2C>,
+def SDBBP16_MM : BrkSdbbp16MM<"sdbbp16", II_SDBBP>, BRKSDBBP16_FM_MM<0x2C>,
ISA_MICROMIPS_NOT_32R6_64R6;
let DecoderNamespace = "MicroMips" in {
/// Load and Store Instructions - multiple
- def SWM16_MM : StoreMultMM16<"swm16">, LWM_FM_MM16<0x5>,
+ def SWM16_MM : StoreMultMM16<"swm16", II_SWM>, LWM_FM_MM16<0x5>,
ISA_MICROMIPS32_NOT_MIPS32R6;
- def LWM16_MM : LoadMultMM16<"lwm16">, LWM_FM_MM16<0x4>,
+ def LWM16_MM : LoadMultMM16<"lwm16", II_LWM>, LWM_FM_MM16<0x4>,
ISA_MICROMIPS32_NOT_MIPS32R6;
+ let AdditionalPredicates = [InMicroMips] in {
+ def CFC2_MM : InstSE<(outs GPR32Opnd:$rt), (ins COP2Opnd:$impl),
+ "cfc2\t$rt, $impl", [], II_CFC2, FrmFR, "cfc2">,
+ POOL32A_CFTC2_FM_MM<0b1100110100>;
+ def CTC2_MM : InstSE<(outs COP2Opnd:$impl), (ins GPR32Opnd:$rt),
+ "ctc2\t$rt, $impl", [], II_CTC2, FrmFR, "ctc2">,
+ POOL32A_CFTC2_FM_MM<0b1101110100>;
+ }
}
class WaitMM<string opstr> :
InstSE<(outs), (ins uimm10:$code_), !strconcat(opstr, "\t$code_"), [],
- NoItinerary, FrmOther, opstr>;
+ II_WAIT, FrmOther, opstr>;
-let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
+let DecoderNamespace = "MicroMips", Predicates = [InMicroMips, NotMips32r6,
+ NotMips64r6] in {
/// Compact Branch Instructions
def BEQZC_MM : CompactBranchMM<"beqzc", brtarget_mm, seteq, GPR32Opnd>,
COMPACT_BRANCH_FM_MM<0x7>;
def BNEZC_MM : CompactBranchMM<"bnezc", brtarget_mm, setne, GPR32Opnd>,
COMPACT_BRANCH_FM_MM<0x5>;
-
+}
+let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
/// Arithmetic Instructions (ALU Immediate)
- def ADDiu_MM : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd>,
+ def ADDiu_MM : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd, II_ADDIU>,
ADDI_FM_MM<0xc>;
- def ADDi_MM : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>,
+ def ADDi_MM : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd, II_ADDI>,
ADDI_FM_MM<0x4>;
def SLTi_MM : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>,
SLTI_FM_MM<0x24>;
def SLTiu_MM : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>,
SLTI_FM_MM<0x2c>;
- def ANDi_MM : MMRel, ArithLogicI<"andi", uimm16, GPR32Opnd>,
+ def ANDi_MM : MMRel, ArithLogicI<"andi", uimm16, GPR32Opnd, II_ANDI>,
ADDI_FM_MM<0x34>;
def ORi_MM : MMRel, ArithLogicI<"ori", uimm16, GPR32Opnd, II_ORI, immZExt16,
or>, ADDI_FM_MM<0x14>;
@@ -699,9 +704,12 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
ADD_FM_MM<0, 0x150>;
def SUBu_MM : MMRel, ArithLogicR<"subu", GPR32Opnd, 0, II_SUBU, sub>,
ADD_FM_MM<0, 0x1d0>;
- def MUL_MM : MMRel, ArithLogicR<"mul", GPR32Opnd>, ADD_FM_MM<0, 0x210>;
- def ADD_MM : MMRel, ArithLogicR<"add", GPR32Opnd>, ADD_FM_MM<0, 0x110>;
- def SUB_MM : MMRel, ArithLogicR<"sub", GPR32Opnd>, ADD_FM_MM<0, 0x190>;
+ def MUL_MM : MMRel, ArithLogicR<"mul", GPR32Opnd, 1, II_MUL>,
+ ADD_FM_MM<0, 0x210>;
+ def ADD_MM : MMRel, ArithLogicR<"add", GPR32Opnd, 1, II_ADD>,
+ ADD_FM_MM<0, 0x110>;
+ def SUB_MM : MMRel, ArithLogicR<"sub", GPR32Opnd, 0, II_SUB>,
+ ADD_FM_MM<0, 0x190>;
def SLT_MM : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM_MM<0, 0x350>;
def SLTu_MM : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>,
ADD_FM_MM<0, 0x390>;
@@ -750,60 +758,69 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
/// Load and Store Instructions - aligned
let DecoderMethod = "DecodeMemMMImm16" in {
- def LB_MM : LoadMemory<"lb", GPR32Opnd, mem_mm_16>, MMRel, LW_FM_MM<0x7>;
- def LBu_MM : LoadMemory<"lbu", GPR32Opnd, mem_mm_16>, MMRel, LW_FM_MM<0x5>;
+ def LB_MM : LoadMemory<"lb", GPR32Opnd, mem_mm_16, null_frag, II_LB>,
+ MMRel, LW_FM_MM<0x7>;
+ def LBu_MM : LoadMemory<"lbu", GPR32Opnd, mem_mm_16, null_frag, II_LBU>,
+ MMRel, LW_FM_MM<0x5>;
def LH_MM : LoadMemory<"lh", GPR32Opnd, mem_simm16, sextloadi16, II_LH,
addrDefault>, MMRel, LW_FM_MM<0xf>;
def LHu_MM : LoadMemory<"lhu", GPR32Opnd, mem_simm16, zextloadi16, II_LHU>,
MMRel, LW_FM_MM<0xd>;
- def LW_MM : Load<"lw", GPR32Opnd>, MMRel, LW_FM_MM<0x3f>;
- def SB_MM : Store<"sb", GPR32Opnd>, MMRel, LW_FM_MM<0x6>;
- def SH_MM : Store<"sh", GPR32Opnd>, MMRel, LW_FM_MM<0xe>;
- def SW_MM : Store<"sw", GPR32Opnd>, MMRel, LW_FM_MM<0x3e>;
+ def LW_MM : Load<"lw", GPR32Opnd, null_frag, II_LW>, MMRel, LW_FM_MM<0x3f>;
+ def SB_MM : Store<"sb", GPR32Opnd, null_frag, II_SB>, MMRel,
+ LW_FM_MM<0x6>;
+ def SH_MM : Store<"sh", GPR32Opnd, null_frag, II_SH>, MMRel,
+ LW_FM_MM<0xe>;
+ def SW_MM : Store<"sw", GPR32Opnd, null_frag, II_SW>, MMRel,
+ LW_FM_MM<0x3e>;
}
let DecoderMethod = "DecodeMemMMImm9" in {
- def LBE_MM : Load<"lbe", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x4>;
- def LBuE_MM : Load<"lbue", GPR32Opnd>, POOL32C_LHUE_FM_MM<0x18, 0x6, 0x0>;
- def LHE_MM : LoadMemory<"lhe", GPR32Opnd, mem_simm9>,
+ def LBE_MM : Load<"lbe", GPR32Opnd, null_frag, II_LBE>,
+ POOL32C_LHUE_FM_MM<0x18, 0x6, 0x4>;
+ def LBuE_MM : Load<"lbue", GPR32Opnd, null_frag, II_LBUE>,
+ POOL32C_LHUE_FM_MM<0x18, 0x6, 0x0>;
+ def LHE_MM : LoadMemory<"lhe", GPR32Opnd, mem_simm9, null_frag, II_LHE>,
POOL32C_LHUE_FM_MM<0x18, 0x6, 0x5>;
- def LHuE_MM : LoadMemory<"lhue", GPR32Opnd, mem_simm9>,
+ def LHuE_MM : LoadMemory<"lhue", GPR32Opnd, mem_simm9, null_frag, II_LHUE>,
POOL32C_LHUE_FM_MM<0x18, 0x6, 0x1>;
- def LWE_MM : LoadMemory<"lwe", GPR32Opnd, mem_simm9>,
+ def LWE_MM : LoadMemory<"lwe", GPR32Opnd, mem_simm9, null_frag, II_LWE>,
POOL32C_LHUE_FM_MM<0x18, 0x6, 0x7>;
- def SBE_MM : StoreMemory<"sbe", GPR32Opnd, mem_simm9>,
+ def SBE_MM : StoreMemory<"sbe", GPR32Opnd, mem_simm9, null_frag, II_SBE>,
POOL32C_LHUE_FM_MM<0x18, 0xa, 0x4>;
- def SHE_MM : StoreMemory<"she", GPR32Opnd, mem_simm9>,
+ def SHE_MM : StoreMemory<"she", GPR32Opnd, mem_simm9, null_frag, II_SHE>,
POOL32C_LHUE_FM_MM<0x18, 0xa, 0x5>;
- def SWE_MM : StoreMemory<"swe", GPR32Opnd, mem_simm9>,
+ def SWE_MM : StoreMemory<"swe", GPR32Opnd, mem_simm9, null_frag, II_SWE>,
POOL32C_LHUE_FM_MM<0x18, 0xa, 0x7>;
}
def LWXS_MM : LoadWordIndexedScaledMM<"lwxs", GPR32Opnd>, LWXS_FM_MM<0x118>;
/// Load and Store Instructions - unaligned
- def LWL_MM : LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12>,
+ def LWL_MM : LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12, II_LWL>,
LWL_FM_MM<0x0>;
- def LWR_MM : LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12>,
+ def LWR_MM : LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12, II_LWR>,
LWL_FM_MM<0x1>;
- def SWL_MM : StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12>,
+ def SWL_MM : StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12, II_SWL>,
LWL_FM_MM<0x8>;
- def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>,
+ def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12, II_SWR>,
LWL_FM_MM<0x9>;
let DecoderMethod = "DecodeMemMMImm9" in {
- def LWLE_MM : LoadLeftRightMM<"lwle", MipsLWL, GPR32Opnd, mem_mm_9>,
- POOL32C_STEVA_LDEVA_FM_MM<0x6, 0x2>;
- def LWRE_MM : LoadLeftRightMM<"lwre", MipsLWR, GPR32Opnd, mem_mm_9>,
- POOL32C_STEVA_LDEVA_FM_MM<0x6, 0x3>;
- def SWLE_MM : StoreLeftRightMM<"swle", MipsSWL, GPR32Opnd, mem_mm_9>,
+ def LWLE_MM : LoadLeftRightMM<"lwle", MipsLWL, GPR32Opnd, mem_mm_9,
+ II_LWLE>, POOL32C_STEVA_LDEVA_FM_MM<0x6, 0x2>;
+ def LWRE_MM : LoadLeftRightMM<"lwre", MipsLWR, GPR32Opnd, mem_mm_9,
+ II_LWRE>, POOL32C_STEVA_LDEVA_FM_MM<0x6, 0x3>;
+ def SWLE_MM : StoreLeftRightMM<"swle", MipsSWL, GPR32Opnd, mem_mm_9,
+ II_SWLE>,
POOL32C_STEVA_LDEVA_FM_MM<0xa, 0x0>;
- def SWRE_MM : StoreLeftRightMM<"swre", MipsSWR, GPR32Opnd, mem_mm_9>,
+ def SWRE_MM : StoreLeftRightMM<"swre", MipsSWR, GPR32Opnd, mem_mm_9,
+ II_SWRE>,
POOL32C_STEVA_LDEVA_FM_MM<0xa, 0x1>, ISA_MIPS1_NOT_32R6_64R6;
}
/// Load and Store Instructions - multiple
- def SWM32_MM : StoreMultMM<"swm32">, LWM_FM_MM<0xd>;
- def LWM32_MM : LoadMultMM<"lwm32">, LWM_FM_MM<0x5>;
+ def SWM32_MM : StoreMultMM<"swm32", II_SWM>, LWM_FM_MM<0xd>;
+ def LWM32_MM : LoadMultMM<"lwm32", II_LWM>, LWM_FM_MM<0x5>;
/// Load and Store Pair Instructions
def SWP_MM : StorePairMM<"swp">, LWM_FM_MM<0x9>;
@@ -849,9 +866,9 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
def MSUBU_MM : MMRel, MArithR<"msubu", II_MSUBU>, MULT_FM_MM<0x3ec>;
/// Count Leading
- def CLZ_MM : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM_MM<0x16c>,
+ def CLZ_MM : MMRel, CountLeading0<"clz", GPR32Opnd, II_CLZ>, CLO_FM_MM<0x16c>,
ISA_MIPS32;
- def CLO_MM : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM_MM<0x12c>,
+ def CLO_MM : MMRel, CountLeading1<"clo", GPR32Opnd, II_CLO>, CLO_FM_MM<0x12c>,
ISA_MIPS32;
/// Sign Ext In Register Instructions.
@@ -910,30 +927,35 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
/// Control Instructions
def SYNC_MM : MMRel, SYNC_FT<"sync">, SYNC_FM_MM;
+ def SYNCI_MM : MMRel, SYNCI_FT<"synci">, SYNCI_FM_MM;
def BREAK_MM : MMRel, BRK_FT<"break">, BRK_FM_MM;
- def SYSCALL_MM : MMRel, SYS_FT<"syscall", uimm10>, SYS_FM_MM;
+ def SYSCALL_MM : MMRel, SYS_FT<"syscall", uimm10, II_SYSCALL>, SYS_FM_MM;
def WAIT_MM : WaitMM<"wait">, WAIT_FM_MM;
- def ERET_MM : MMRel, ER_FT<"eret">, ER_FM_MM<0x3cd>;
- def DERET_MM : MMRel, ER_FT<"deret">, ER_FM_MM<0x38d>;
- def EI_MM : MMRel, DEI_FT<"ei", GPR32Opnd>, EI_FM_MM<0x15d>,
+ def ERET_MM : MMRel, ER_FT<"eret", II_ERET>, ER_FM_MM<0x3cd>;
+ def DERET_MM : MMRel, ER_FT<"deret", II_DERET>, ER_FM_MM<0x38d>;
+ def EI_MM : MMRel, DEI_FT<"ei", GPR32Opnd, II_EI>, EI_FM_MM<0x15d>,
ISA_MIPS32R2;
- def DI_MM : MMRel, DEI_FT<"di", GPR32Opnd>, EI_FM_MM<0x11d>,
+ def DI_MM : MMRel, DEI_FT<"di", GPR32Opnd, II_DI>, EI_FM_MM<0x11d>,
ISA_MIPS32R2;
/// Trap Instructions
- def TEQ_MM : MMRel, TEQ_FT<"teq", GPR32Opnd, uimm4>, TEQ_FM_MM<0x0>;
- def TGE_MM : MMRel, TEQ_FT<"tge", GPR32Opnd, uimm4>, TEQ_FM_MM<0x08>;
- def TGEU_MM : MMRel, TEQ_FT<"tgeu", GPR32Opnd, uimm4>, TEQ_FM_MM<0x10>;
- def TLT_MM : MMRel, TEQ_FT<"tlt", GPR32Opnd, uimm4>, TEQ_FM_MM<0x20>;
- def TLTU_MM : MMRel, TEQ_FT<"tltu", GPR32Opnd, uimm4>, TEQ_FM_MM<0x28>;
- def TNE_MM : MMRel, TEQ_FT<"tne", GPR32Opnd, uimm4>, TEQ_FM_MM<0x30>;
-
- def TEQI_MM : MMRel, TEQI_FT<"teqi", GPR32Opnd>, TEQI_FM_MM<0x0e>;
- def TGEI_MM : MMRel, TEQI_FT<"tgei", GPR32Opnd>, TEQI_FM_MM<0x09>;
- def TGEIU_MM : MMRel, TEQI_FT<"tgeiu", GPR32Opnd>, TEQI_FM_MM<0x0b>;
- def TLTI_MM : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM_MM<0x08>;
- def TLTIU_MM : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM_MM<0x0a>;
- def TNEI_MM : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM_MM<0x0c>;
+ def TEQ_MM : MMRel, TEQ_FT<"teq", GPR32Opnd, uimm4, II_TEQ>, TEQ_FM_MM<0x0>;
+ def TGE_MM : MMRel, TEQ_FT<"tge", GPR32Opnd, uimm4, II_TGE>, TEQ_FM_MM<0x08>;
+ def TGEU_MM : MMRel, TEQ_FT<"tgeu", GPR32Opnd, uimm4, II_TGEU>,
+ TEQ_FM_MM<0x10>;
+ def TLT_MM : MMRel, TEQ_FT<"tlt", GPR32Opnd, uimm4, II_TLT>, TEQ_FM_MM<0x20>;
+ def TLTU_MM : MMRel, TEQ_FT<"tltu", GPR32Opnd, uimm4, II_TLTU>,
+ TEQ_FM_MM<0x28>;
+ def TNE_MM : MMRel, TEQ_FT<"tne", GPR32Opnd, uimm4, II_TNE>, TEQ_FM_MM<0x30>;
+
+ def TEQI_MM : MMRel, TEQI_FT<"teqi", GPR32Opnd, II_TEQI>, TEQI_FM_MM<0x0e>;
+ def TGEI_MM : MMRel, TEQI_FT<"tgei", GPR32Opnd, II_TGEI>, TEQI_FM_MM<0x09>;
+ def TGEIU_MM : MMRel, TEQI_FT<"tgeiu", GPR32Opnd, II_TGEIU>,
+ TEQI_FM_MM<0x0b>;
+ def TLTI_MM : MMRel, TEQI_FT<"tlti", GPR32Opnd, II_TLTI>, TEQI_FM_MM<0x08>;
+ def TLTIU_MM : MMRel, TEQI_FT<"tltiu", GPR32Opnd, II_TTLTIU>,
+ TEQI_FM_MM<0x0a>;
+ def TNEI_MM : MMRel, TEQI_FT<"tnei", GPR32Opnd, II_TNEI>, TEQI_FM_MM<0x0c>;
/// Load-linked, Store-conditional
def LL_MM : LLBaseMM<"ll", GPR32Opnd>, LL_FM_MM<0x3>;
@@ -943,32 +965,34 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
def SCE_MM : SCEBaseMM<"sce", GPR32Opnd>, LLE_FM_MM<0xA>;
let DecoderMethod = "DecodeCacheOpMM" in {
- def CACHE_MM : MMRel, CacheOp<"cache", mem_mm_12>,
+ def CACHE_MM : MMRel, CacheOp<"cache", mem_mm_12, II_CACHE>,
CACHE_PREF_FM_MM<0x08, 0x6>;
- def PREF_MM : MMRel, CacheOp<"pref", mem_mm_12>,
+ def PREF_MM : MMRel, CacheOp<"pref", mem_mm_12, II_PREF>,
CACHE_PREF_FM_MM<0x18, 0x2>;
}
let DecoderMethod = "DecodePrefeOpMM" in {
- def PREFE_MM : MMRel, CacheOp<"prefe", mem_mm_9>,
+ def PREFE_MM : MMRel, CacheOp<"prefe", mem_mm_9, II_PREFE>,
CACHE_PREFE_FM_MM<0x18, 0x2>;
- def CACHEE_MM : MMRel, CacheOp<"cachee", mem_mm_9>,
+ def CACHEE_MM : MMRel, CacheOp<"cachee", mem_mm_9, II_CACHEE>,
CACHE_PREFE_FM_MM<0x18, 0x3>;
}
- def SSNOP_MM : MMRel, Barrier<"ssnop">, BARRIER_FM_MM<0x1>;
- def EHB_MM : MMRel, Barrier<"ehb">, BARRIER_FM_MM<0x3>;
- def PAUSE_MM : MMRel, Barrier<"pause">, BARRIER_FM_MM<0x5>;
+ def SSNOP_MM : MMRel, Barrier<"ssnop", II_SSNOP>, BARRIER_FM_MM<0x1>;
+ def EHB_MM : MMRel, Barrier<"ehb", II_EHB>, BARRIER_FM_MM<0x3>;
+ def PAUSE_MM : MMRel, Barrier<"pause", II_PAUSE>, BARRIER_FM_MM<0x5>;
- def TLBP_MM : MMRel, TLB<"tlbp">, COP0_TLB_FM_MM<0x0d>;
- def TLBR_MM : MMRel, TLB<"tlbr">, COP0_TLB_FM_MM<0x4d>;
- def TLBWI_MM : MMRel, TLB<"tlbwi">, COP0_TLB_FM_MM<0x8d>;
- def TLBWR_MM : MMRel, TLB<"tlbwr">, COP0_TLB_FM_MM<0xcd>;
+ def TLBP_MM : MMRel, TLB<"tlbp", II_TLBP>, COP0_TLB_FM_MM<0x0d>;
+ def TLBR_MM : MMRel, TLB<"tlbr", II_TLBR>, COP0_TLB_FM_MM<0x4d>;
+ def TLBWI_MM : MMRel, TLB<"tlbwi", II_TLBWI>, COP0_TLB_FM_MM<0x8d>;
+ def TLBWR_MM : MMRel, TLB<"tlbwr", II_TLBWR>, COP0_TLB_FM_MM<0xcd>;
- def SDBBP_MM : MMRel, SYS_FT<"sdbbp", uimm10>, SDBBP_FM_MM;
+ def SDBBP_MM : MMRel, SYS_FT<"sdbbp", uimm10, II_SDBBP>, SDBBP_FM_MM;
def PREFX_MM : PrefetchIndexed<"prefx">, POOL32F_PREFX_FM_MM<0x15, 0x1A0>;
}
+def TAILCALL_MM : TailCall<J_MM, jmptarget_mm>, ISA_MIPS1_NOT_32R6_64R6;
+
let DecoderNamespace = "MicroMips" in {
def RDHWR_MM : MMRel, R6MMR6Rel, ReadHardware<GPR32Opnd, HWRegsOpnd>,
RDHWR_FM_MM, ISA_MICROMIPS32_NOT_MIPS32R6;
@@ -981,6 +1005,12 @@ let DecoderNamespace = "MicroMips" in {
// MicroMips arbitrary patterns that map to one or more instructions
//===----------------------------------------------------------------------===//
+def : MipsPat<(i32 immLi16:$imm),
+ (LI16_MM immLi16:$imm)>;
+
+let AdditionalPredicates = [InMicroMips] in
+defm : MaterializeImms<i32, ZERO, ADDiu_MM, LUi_MM, ORi_MM>;
+
let Predicates = [InMicroMips] in {
def : MipsPat<(i32 immLi16:$imm),
(LI16_MM immLi16:$imm)>;
@@ -1036,6 +1066,11 @@ let Predicates = [InMicroMips] in {
(LW_MM addr:$addr)>;
def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs),
(SUBu_MM GPR32:$lhs, GPR32:$rhs)>;
+
+ def : MipsPat<(MipsTailCall (iPTR tglobaladdr:$dst)),
+ (TAILCALL_MM tglobaladdr:$dst)>, ISA_MIPS1_NOT_32R6_64R6;
+ def : MipsPat<(MipsTailCall (iPTR texternalsym:$dst)),
+ (TAILCALL_MM texternalsym:$dst)>, ISA_MIPS1_NOT_32R6_64R6;
}
let AddedComplexity = 40 in {
@@ -1047,6 +1082,15 @@ def : MipsPat<(atomic_load_16 addr:$a),
def : MipsPat<(i32 (extloadi16 addr:$src)),
(LHu_MM addr:$src)>;
+defm : BrcondPats<GPR32, BEQ_MM, BEQ_MM, BNE_MM, SLT_MM, SLTu_MM, SLTi_MM,
+ SLTiu_MM, ZERO>;
+
+defm : SeteqPats<GPR32, SLTiu_MM, XOR_MM, SLTu_MM, ZERO>;
+defm : SetlePats<GPR32, XORi_MM, SLT_MM, SLTu_MM>;
+defm : SetgtPats<GPR32, SLT_MM, SLTu_MM>;
+defm : SetgePats<GPR32, XORi_MM, SLT_MM, SLTu_MM>;
+defm : SetgeImmPats<GPR32, XORi_MM, SLTi_MM, SLTiu_MM>;
+
//===----------------------------------------------------------------------===//
// MicroMips instruction aliases
//===----------------------------------------------------------------------===//
@@ -1080,6 +1124,24 @@ let Predicates = [InMicroMips] in {
(TLTU_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>;
def : MipsInstAlias<"tne $rs, $rt",
(TNE_MM GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>;
+ def : MipsInstAlias<
+ "sgt $rd, $rs, $rt",
+ (SLT_MM GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
+ "sgt $rs, $rt",
+ (SLT_MM GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
+ "sgtu $rd, $rs, $rt",
+ (SLTu_MM GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
+ "sgtu $rs, $rt",
+ (SLTu_MM GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<"slt $rs, $rt, $imm",
+ (SLTi_MM GPR32Opnd:$rs, GPR32Opnd:$rt,
+ simm32_relaxed:$imm), 0>;
+ def : MipsInstAlias<"sltu $rs, $rt, $imm",
+ (SLTiu_MM GPR32Opnd:$rs, GPR32Opnd:$rt,
+ simm32_relaxed:$imm), 0>;
def : MipsInstAlias<"sll $rd, $rt, $rs",
(SLLV_MM GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
def : MipsInstAlias<"sra $rd, $rt, $rs",
@@ -1115,4 +1177,14 @@ let Predicates = [InMicroMips] in {
(XORi_MM GPR32Opnd:$rs, GPR32Opnd:$rs, uimm16:$imm), 0>;
def : MipsInstAlias<"not $rt, $rs",
(NOR_MM GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>;
+ def : MipsInstAlias<"not $rt",
+ (NOR_MM GPR32Opnd:$rt, GPR32Opnd:$rt, ZERO), 0>;
+ def : MipsInstAlias<"bnez $rs,$offset",
+ (BNE_MM GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>;
+ def : MipsInstAlias<"beqz $rs,$offset",
+ (BEQ_MM GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>;
+ def : MipsInstAlias<"seh $rd", (SEH_MM GPR32Opnd:$rd, GPR32Opnd:$rd), 0>,
+ ISA_MIPS32R2_NOT_32R6_64R6;
+ def : MipsInstAlias<"seb $rd", (SEB_MM GPR32Opnd:$rd, GPR32Opnd:$rd), 0>,
+ ISA_MIPS32R2_NOT_32R6_64R6;
}
diff --git a/contrib/llvm/lib/Target/Mips/Mips.td b/contrib/llvm/lib/Target/Mips/Mips.td
index ea3fa0a..670272d 100644
--- a/contrib/llvm/lib/Target/Mips/Mips.td
+++ b/contrib/llvm/lib/Target/Mips/Mips.td
@@ -57,6 +57,10 @@ include "MipsSchedule.td"
include "MipsInstrInfo.td"
include "MipsCallingConv.td"
+// Avoid forward declaration issues.
+include "MipsScheduleP5600.td"
+include "MipsScheduleGeneric.td"
+
def MipsInstrInfo : InstrInfo;
//===----------------------------------------------------------------------===//
@@ -188,7 +192,7 @@ def ImplP5600 : SubtargetFeature<"p5600", "ProcImpl",
"The P5600 Processor", [FeatureMips32r5]>;
class Proc<string Name, list<SubtargetFeature> Features>
- : Processor<Name, MipsGenericItineraries, Features>;
+ : ProcessorModel<Name, MipsGenericModel, Features>;
def : Proc<"mips1", [FeatureMips1]>;
def : Proc<"mips2", [FeatureMips2]>;
diff --git a/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp
index e937ffa..e7ceca9 100644
--- a/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp
+++ b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp
@@ -34,7 +34,7 @@ Mips16FrameLowering::Mips16FrameLowering(const MipsSubtarget &STI)
void Mips16FrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const Mips16InstrInfo &TII =
*static_cast<const Mips16InstrInfo *>(STI.getInstrInfo());
MachineBasicBlock::iterator MBBI = MBB.begin();
@@ -43,10 +43,10 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF,
// to determine the end of the prologue.
DebugLoc dl;
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
// No need to allocate space on the stack.
- if (StackSize == 0 && !MFI->adjustsStack()) return;
+ if (StackSize == 0 && !MFI.adjustsStack()) return;
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
@@ -56,22 +56,22 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF,
TII.makeFrame(Mips::SP, StackSize, MBB, MBBI);
// emit ".cfi_def_cfa_offset StackSize"
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
if (CSI.size()) {
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(),
E = CSI.end(); I != E; ++I) {
- int64_t Offset = MFI->getObjectOffset(I->getFrameIdx());
+ int64_t Offset = MFI.getObjectOffset(I->getFrameIdx());
unsigned Reg = I->getReg();
unsigned DReg = MRI->getDwarfRegNum(Reg, true);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DReg, Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -86,11 +86,11 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF,
void Mips16FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const Mips16InstrInfo &TII =
*static_cast<const Mips16InstrInfo *>(STI.getInstrInfo());
DebugLoc dl = MBBI->getDebugLoc();
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
if (!StackSize)
return;
@@ -120,12 +120,12 @@ spillCalleeSavedRegisters(MachineBasicBlock &MBB,
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
// Add the callee-saved register as live-in. Do not add if the register is
// RA and return address is taken, because it has already been added in
- // method MipsTargetLowering::LowerRETURNADDR.
+ // method MipsTargetLowering::lowerRETURNADDR.
// It's killed at the spill, unless the register is RA and return address
// is taken.
unsigned Reg = CSI[i].getReg();
bool IsRAAndRetAddrIsTaken = (Reg == Mips::RA)
- && MF->getFrameInfo()->isReturnAddressTaken();
+ && MF->getFrameInfo().isReturnAddressTaken();
if (!IsRAAndRetAddrIsTaken)
EntryBlock->addLiveIn(Reg);
}
@@ -149,10 +149,10 @@ bool Mips16FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
bool
Mips16FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Reserve call frame if the size of the maximum call frame fits into 15-bit
// immediate field and there are no variable sized objects on the stack.
- return isInt<15>(MFI->getMaxCallFrameSize()) && !MFI->hasVarSizedObjects();
+ return isInt<15>(MFI.getMaxCallFrameSize()) && !MFI.hasVarSizedObjects();
}
void Mips16FrameLowering::determineCalleeSaves(MachineFunction &MF,
diff --git a/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp
index d2d1c65..191006d 100644
--- a/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp
+++ b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp
@@ -30,9 +30,7 @@ namespace {
Mips16HardFloat(MipsTargetMachine &TM_) : ModulePass(ID), TM(TM_) {}
- const char *getPassName() const override {
- return "MIPS16 Hard Float Pass";
- }
+ StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
bool runOnModule(Module &M) override;
diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
index 0405291..ce193b1 100644
--- a/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
@@ -80,9 +80,10 @@ void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) {
V1 = RegInfo.createVirtualRegister(RC);
V2 = RegInfo.createVirtualRegister(RC);
- BuildMI(MBB, I, DL, TII.get(Mips::GotPrologue16), V0)
- .addReg(V1, RegState::Define)
- .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI)
+
+ BuildMI(MBB, I, DL, TII.get(Mips::LiRxImmX16), V0)
+ .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);
+ BuildMI(MBB, I, DL, TII.get(Mips::AddiuRxPcImmX16), V1)
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);
BuildMI(MBB, I, DL, TII.get(Mips::SllX16), V2).addReg(V0).addImm(16);
diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp
index daa1355..35ef317 100644
--- a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp
@@ -172,7 +172,7 @@ static void addSaveRestoreRegs(MachineInstrBuilder &MIB,
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
// Add the callee-saved register as live-in. Do not add if the register is
// RA and return address is taken, because it has already been added in
- // method MipsTargetLowering::LowerRETURNADDR.
+ // method MipsTargetLowering::lowerRETURNADDR.
// It's killed at the spill, unless the register is RA and return address
// is taken.
unsigned Reg = CSI[e-i-1].getReg();
@@ -196,13 +196,13 @@ void Mips16InstrInfo::makeFrame(unsigned SP, int64_t FrameSize,
MachineBasicBlock::iterator I) const {
DebugLoc DL;
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const BitVector Reserved = RI.getReservedRegs(MF);
bool SaveS2 = Reserved[Mips::S2];
MachineInstrBuilder MIB;
unsigned Opc = ((FrameSize <= 128) && !SaveS2)? Mips::Save16:Mips::SaveX16;
MIB = BuildMI(MBB, I, DL, get(Opc));
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
addSaveRestoreRegs(MIB, CSI);
if (SaveS2)
MIB.addReg(Mips::S2);
@@ -226,7 +226,7 @@ void Mips16InstrInfo::restoreFrame(unsigned SP, int64_t FrameSize,
MachineBasicBlock::iterator I) const {
DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
MachineFunction *MF = MBB.getParent();
- MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
const BitVector Reserved = RI.getReservedRegs(*MF);
bool SaveS2 = Reserved[Mips::S2];
MachineInstrBuilder MIB;
@@ -245,7 +245,7 @@ void Mips16InstrInfo::restoreFrame(unsigned SP, int64_t FrameSize,
adjustStackPtrBig(SP, Remainder, MBB, I, Mips::A0, Mips::A1);
}
MIB = BuildMI(MBB, I, DL, get(Opc));
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
addSaveRestoreRegs(MIB, CSI, RegState::Define);
if (SaveS2)
MIB.addReg(Mips::S2, RegState::Define);
@@ -510,8 +510,8 @@ unsigned Mips16InstrInfo::getInlineAsmLength(const char *Str,
Length += MAI.getMaxInstLength();
atInsnStart = false;
}
- if (atInsnStart && strncmp(Str, MAI.getCommentString(),
- strlen(MAI.getCommentString())) == 0)
+ if (atInsnStart && strncmp(Str, MAI.getCommentString().data(),
+ MAI.getCommentString().size()) == 0)
atInsnStart = false;
}
diff --git a/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp
index b034c26..44771cb 100644
--- a/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp
@@ -79,9 +79,9 @@ void Mips16RegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
int64_t SPOffset) const {
MachineInstr &MI = *II;
MachineFunction &MF = *MI.getParent()->getParent();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
int MinCSFI = 0;
int MaxCSFI = -1;
diff --git a/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td b/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td
index a20c683..516caa3 100644
--- a/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td
+++ b/contrib/llvm/lib/Target/Mips/Mips32r6InstrFormats.td
@@ -45,6 +45,7 @@ class MipsR6Inst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther>,
class OPGROUP<bits<6> Val> {
bits<6> Value = Val;
}
+def OPGROUP_COP0 : OPGROUP<0b010000>;
def OPGROUP_COP1 : OPGROUP<0b010001>;
def OPGROUP_COP2 : OPGROUP<0b010010>;
def OPGROUP_ADDI : OPGROUP<0b001000>;
@@ -201,6 +202,21 @@ class BAL_FM : MipsR6Inst {
let Inst{15-0} = offset;
}
+class COP0_EVP_DVP_FM<bits<1> sc> : MipsR6Inst {
+ bits<5> rt;
+
+ bits<32> Inst;
+
+ let Inst{31-26} = OPGROUP_COP0.Value;
+ let Inst{25-21} = 0b01011;
+ let Inst{20-16} = rt;
+ let Inst{15-11} = 0b00000;
+ let Inst{10-6} = 0b00000;
+ let Inst{5} = sc;
+ let Inst{4-3} = 0b00;
+ let Inst{2-0} = 0b100;
+}
+
class COP1_2R_FM<bits<6> funct, FIELD_FMT Format> : MipsR6Inst {
bits<5> fs;
bits<5> fd;
diff --git a/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
index f552f8d..1b4d73b 100644
--- a/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
@@ -98,6 +98,9 @@ class BC1NEZ_ENC : COP1_BCCZ_FM<OPCODE5_BC1NEZ>;
class BC2EQZ_ENC : COP2_BCCZ_FM<OPCODE5_BC2EQZ>;
class BC2NEZ_ENC : COP2_BCCZ_FM<OPCODE5_BC2NEZ>;
+class DVP_ENC : COP0_EVP_DVP_FM<0b1>;
+class EVP_ENC : COP0_EVP_DVP_FM<0b0>;
+
class JIALC_ENC : JMP_IDX_COMPACT_FM<0b111110>;
class JIC_ENC : JMP_IDX_COMPACT_FM<0b110110>;
class JR_HB_R6_ENC : JR_HB_R6_FM<OPCODE6_JALR>;
@@ -177,90 +180,98 @@ class SDBBP_R6_ENC : SPECIAL_SDBBP_FM;
class CMP_CONDN_DESC_BASE<string CondStr, string Typestr,
RegisterOperand FGROpnd,
+ InstrItinClass Itin,
SDPatternOperator Op = null_frag> {
dag OutOperandList = (outs FGRCCOpnd:$fd);
dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft");
list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))];
bit isCTI = 1;
+ InstrItinClass Itinerary = Itin;
}
multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr,
- RegisterOperand FGROpnd>{
+ RegisterOperand FGROpnd, InstrItinClass Itin>{
let AdditionalPredicates = [NotInMicroMips] in {
def CMP_F_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_AF>,
- CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"af", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.af.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_UN_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_UN>,
- CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, setuo>,
+ CMP_CONDN_DESC_BASE<"un", Typestr, FGROpnd, Itin, setuo>,
MipsR6Arch<!strconcat("cmp.un.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_EQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_EQ>,
- CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, setoeq>,
+ CMP_CONDN_DESC_BASE<"eq", Typestr, FGROpnd, Itin,
+ setoeq>,
MipsR6Arch<!strconcat("cmp.eq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_UEQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_UEQ>,
- CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, setueq>,
+ CMP_CONDN_DESC_BASE<"ueq", Typestr, FGROpnd, Itin,
+ setueq>,
MipsR6Arch<!strconcat("cmp.ueq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_LT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LT>,
- CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, setolt>,
+ CMP_CONDN_DESC_BASE<"lt", Typestr, FGROpnd, Itin,
+ setolt>,
MipsR6Arch<!strconcat("cmp.lt.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_ULT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_ULT>,
- CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, setult>,
+ CMP_CONDN_DESC_BASE<"ult", Typestr, FGROpnd, Itin,
+ setult>,
MipsR6Arch<!strconcat("cmp.ult.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_LE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format, FIELD_CMP_COND_LE>,
- CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, setole>,
+ CMP_CONDN_DESC_BASE<"le", Typestr, FGROpnd, Itin,
+ setole>,
MipsR6Arch<!strconcat("cmp.le.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_ULE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_ULE>,
- CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, setule>,
+ CMP_CONDN_DESC_BASE<"ule", Typestr, FGROpnd, Itin,
+ setule>,
MipsR6Arch<!strconcat("cmp.ule.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SAF_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SAF>,
- CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"saf", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.saf.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SUN_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SUN>,
- CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"sun", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.sun.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SEQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SEQ>,
- CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"seq", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.seq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SUEQ_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SUEQ>,
- CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"sueq", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.sueq.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SLT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SLT>,
- CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"slt", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.slt.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SULT_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SULT>,
- CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"sult", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.sult.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SLE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SLE>,
- CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"sle", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.sle.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
def CMP_SULE_#NAME : R6MMR6Rel, COP1_CMP_CONDN_FM<Format,
FIELD_CMP_COND_SULE>,
- CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd>,
+ CMP_CONDN_DESC_BASE<"sule", Typestr, FGROpnd, Itin>,
MipsR6Arch<!strconcat("cmp.sule.", Typestr)>,
ISA_MIPS32R6, HARDFLOAT;
}
@@ -316,7 +327,7 @@ class AUI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
InstrItinClass itin = NoItinerary>
: MipsR6Arch<instr_asm> {
dag OutOperandList = (outs GPROpnd:$rs);
- dag InOperandList = (ins GPROpnd:$rt, simm16:$imm);
+ dag InOperandList = (ins GPROpnd:$rt, uimm16:$imm);
string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $imm");
list<dag> Pattern = [];
InstrItinClass Itinerary = itin;
@@ -426,6 +437,7 @@ class COP2_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE {
string AsmString = instr_asm;
bit hasDelaySlot = 1;
bit isCTI = 1;
+ InstrItinClass Itinerary = II_BC2CCZ;
}
class BC2EQZ_DESC : COP2_BCCZ_DESC_BASE<"bc2eqz $ct, $offset">;
@@ -468,6 +480,7 @@ class JR_HB_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> {
bit isTerminator=1;
bit isBarrier=1;
bit isCTI = 1;
+ InstrItinClass Itinerary = II_JR_HB;
}
class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
@@ -496,6 +509,19 @@ class DIVMOD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
bit usesCustomInserter = 1;
}
+class DVPEVP_DESC_BASE<string instr_asm, InstrItinClass Itin>
+ : MipsR6Arch<instr_asm> {
+ dag OutOperandList = (outs GPR32Opnd:$rt);
+ dag InOperandList = (ins);
+ string AsmString = !strconcat(instr_asm, "\t$rt");
+ list<dag> Pattern = [];
+ InstrItinClass Itinerary = Itin;
+ bit hasUnModeledSideEffects = 1;
+}
+
+class DVP_DESC : DVPEVP_DESC_BASE<"dvp", II_DVP>;
+class EVP_DESC : DVPEVP_DESC_BASE<"evp", II_EVP>;
+
class DIV_DESC : DIVMOD_DESC_BASE<"div", GPR32Opnd, II_DIV, sdiv>;
class DIVU_DESC : DIVMOD_DESC_BASE<"divu", GPR32Opnd, II_DIVU, udiv>;
class MOD_DESC : DIVMOD_DESC_BASE<"mod", GPR32Opnd, II_MOD, srem>;
@@ -540,7 +566,8 @@ class MUHU_DESC : MUL_R6_DESC_BASE<"muhu", GPR32Opnd, II_MUHU, mulhu>;
class MUL_R6_DESC : MUL_R6_DESC_BASE<"mul", GPR32Opnd, II_MUL, mul>;
class MULU_DESC : MUL_R6_DESC_BASE<"mulu", GPR32Opnd, II_MULU>;
-class COP1_SEL_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> {
+class COP1_SEL_DESC_BASE<string instr_asm, RegisterOperand FGROpnd,
+ InstrItinClass itin> {
dag OutOperandList = (outs FGROpnd:$fd);
dag InOperandList = (ins FGRCCOpnd:$fd_in, FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft");
@@ -548,13 +575,16 @@ class COP1_SEL_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> {
FGROpnd:$ft,
FGROpnd:$fs))];
string Constraints = "$fd_in = $fd";
+ InstrItinClass Itinerary = itin;
}
-class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd>, MipsR6Arch<"sel.d"> {
+class SEL_D_DESC : COP1_SEL_DESC_BASE<"sel.d", FGR64Opnd, II_SEL_D>,
+ MipsR6Arch<"sel.d"> {
// We must insert a SUBREG_TO_REG around $fd_in
bit usesCustomInserter = 1;
}
-class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd>, MipsR6Arch<"sel.s">;
+class SEL_S_DESC : COP1_SEL_DESC_BASE<"sel.s", FGR32Opnd, II_SEL_S>,
+ MipsR6Arch<"sel.s">;
class SELEQNE_Z_DESC_BASE<string instr_asm, RegisterOperand GPROpnd>
: MipsR6Arch<instr_asm> {
@@ -583,86 +613,98 @@ class MADDF_D_DESC : COP1_4R_DESC_BASE<"maddf.d", FGR64Opnd, II_MADDF_D>;
class MSUBF_S_DESC : COP1_4R_DESC_BASE<"msubf.s", FGR32Opnd, II_MSUBF_S>;
class MSUBF_D_DESC : COP1_4R_DESC_BASE<"msubf.d", FGR64Opnd, II_MSUBF_D>;
-class MAX_MIN_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> {
+class MAX_MIN_DESC_BASE<string instr_asm, RegisterOperand FGROpnd,
+ InstrItinClass itin> {
dag OutOperandList = (outs FGROpnd:$fd);
dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = itin;
}
-class MAX_S_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd>;
-class MAX_D_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd>;
-class MIN_S_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd>;
-class MIN_D_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd>;
+class MAX_S_DESC : MAX_MIN_DESC_BASE<"max.s", FGR32Opnd, II_MAX_S>;
+class MAX_D_DESC : MAX_MIN_DESC_BASE<"max.d", FGR64Opnd, II_MAX_D>;
+class MIN_S_DESC : MAX_MIN_DESC_BASE<"min.s", FGR32Opnd, II_MIN_S>;
+class MIN_D_DESC : MAX_MIN_DESC_BASE<"min.d", FGR64Opnd, II_MIN_D>;
-class MAXA_S_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd>;
-class MAXA_D_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd>;
-class MINA_S_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd>;
-class MINA_D_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd>;
+class MAXA_S_DESC : MAX_MIN_DESC_BASE<"maxa.s", FGR32Opnd, II_MAX_S>;
+class MAXA_D_DESC : MAX_MIN_DESC_BASE<"maxa.d", FGR64Opnd, II_MAX_D>;
+class MINA_S_DESC : MAX_MIN_DESC_BASE<"mina.s", FGR32Opnd, II_MIN_D>;
+class MINA_D_DESC : MAX_MIN_DESC_BASE<"mina.d", FGR64Opnd, II_MIN_S>;
-class SELEQNEZ_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> {
+class SELEQNEZ_DESC_BASE<string instr_asm, RegisterOperand FGROpnd,
+ InstrItinClass itin> {
dag OutOperandList = (outs FGROpnd:$fd);
dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft);
string AsmString = !strconcat(instr_asm, "\t$fd, $fs, $ft");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = itin;
}
-class SELEQZ_S_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd>,
+class SELEQZ_S_DESC : SELEQNEZ_DESC_BASE<"seleqz.s", FGR32Opnd, II_SELCCZ_S>,
MipsR6Arch<"seleqz.s">;
-class SELEQZ_D_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd>,
+class SELEQZ_D_DESC : SELEQNEZ_DESC_BASE<"seleqz.d", FGR64Opnd, II_SELCCZ_D>,
MipsR6Arch<"seleqz.d">;
-class SELNEZ_S_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd>,
+class SELNEZ_S_DESC : SELEQNEZ_DESC_BASE<"selnez.s", FGR32Opnd, II_SELCCZ_S>,
MipsR6Arch<"selnez.s">;
-class SELNEZ_D_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd>,
+class SELNEZ_D_DESC : SELEQNEZ_DESC_BASE<"selnez.d", FGR64Opnd, II_SELCCZ_D>,
MipsR6Arch<"selnez.d">;
-class CLASS_RINT_DESC_BASE<string instr_asm, RegisterOperand FGROpnd> {
+class CLASS_RINT_DESC_BASE<string instr_asm, RegisterOperand FGROpnd,
+ InstrItinClass itin> {
dag OutOperandList = (outs FGROpnd:$fd);
dag InOperandList = (ins FGROpnd:$fs);
string AsmString = !strconcat(instr_asm, "\t$fd, $fs");
list<dag> Pattern = [];
+ InstrItinClass Itinerary = itin;
}
-class RINT_S_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd>;
-class RINT_D_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd>;
-class CLASS_S_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd>;
-class CLASS_D_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd>;
+class RINT_S_DESC : CLASS_RINT_DESC_BASE<"rint.s", FGR32Opnd, II_RINT_S>;
+class RINT_D_DESC : CLASS_RINT_DESC_BASE<"rint.d", FGR64Opnd, II_RINT_D>;
+class CLASS_S_DESC : CLASS_RINT_DESC_BASE<"class.s", FGR32Opnd, II_CLASS_S>;
+class CLASS_D_DESC : CLASS_RINT_DESC_BASE<"class.d", FGR64Opnd, II_CLASS_D>;
class CACHE_HINT_DESC<string instr_asm, Operand MemOpnd,
- RegisterOperand GPROpnd> : MipsR6Arch<instr_asm> {
+ RegisterOperand GPROpnd, InstrItinClass itin>
+ : MipsR6Arch<instr_asm> {
dag OutOperandList = (outs);
dag InOperandList = (ins MemOpnd:$addr, uimm5:$hint);
string AsmString = !strconcat(instr_asm, "\t$hint, $addr");
list<dag> Pattern = [];
string DecoderMethod = "DecodeCacheeOp_CacheOpR6";
+ InstrItinClass Itinerary = itin;
}
-class CACHE_DESC : CACHE_HINT_DESC<"cache", mem_simm9, GPR32Opnd>;
-class PREF_DESC : CACHE_HINT_DESC<"pref", mem_simm9, GPR32Opnd>;
+class CACHE_DESC : CACHE_HINT_DESC<"cache", mem_simm9, GPR32Opnd, II_CACHE>;
+class PREF_DESC : CACHE_HINT_DESC<"pref", mem_simm9, GPR32Opnd, II_PREF>;
-class COP2LD_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> {
+class COP2LD_DESC_BASE<string instr_asm, RegisterOperand COPOpnd,
+ InstrItinClass itin> {
dag OutOperandList = (outs COPOpnd:$rt);
dag InOperandList = (ins mem_simm11:$addr);
string AsmString = !strconcat(instr_asm, "\t$rt, $addr");
list<dag> Pattern = [];
bit mayLoad = 1;
string DecoderMethod = "DecodeFMemCop2R6";
+ InstrItinClass Itinerary = itin;
}
-class LDC2_R6_DESC : COP2LD_DESC_BASE<"ldc2", COP2Opnd>;
-class LWC2_R6_DESC : COP2LD_DESC_BASE<"lwc2", COP2Opnd>;
+class LDC2_R6_DESC : COP2LD_DESC_BASE<"ldc2", COP2Opnd, II_LDC2>;
+class LWC2_R6_DESC : COP2LD_DESC_BASE<"lwc2", COP2Opnd, II_LWC2>;
-class COP2ST_DESC_BASE<string instr_asm, RegisterOperand COPOpnd> {
+class COP2ST_DESC_BASE<string instr_asm, RegisterOperand COPOpnd,
+ InstrItinClass itin> {
dag OutOperandList = (outs);
dag InOperandList = (ins COPOpnd:$rt, mem_simm11:$addr);
string AsmString = !strconcat(instr_asm, "\t$rt, $addr");
list<dag> Pattern = [];
bit mayStore = 1;
string DecoderMethod = "DecodeFMemCop2R6";
+ InstrItinClass Itinerary = itin;
}
-class SDC2_R6_DESC : COP2ST_DESC_BASE<"sdc2", COP2Opnd>;
-class SWC2_R6_DESC : COP2ST_DESC_BASE<"swc2", COP2Opnd>;
+class SDC2_R6_DESC : COP2ST_DESC_BASE<"sdc2", COP2Opnd, II_SDC2>;
+class SWC2_R6_DESC : COP2ST_DESC_BASE<"swc2", COP2Opnd, II_SWC2>;
class LSA_R6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
Operand ImmOpnd, InstrItinClass itin>
@@ -732,6 +774,7 @@ class SDBBP_R6_DESC {
string AsmString = "sdbbp\t$code_";
list<dag> Pattern = [];
bit isCTI = 1;
+ InstrItinClass Itinerary = II_SDBBP;
}
//===----------------------------------------------------------------------===//
@@ -754,26 +797,28 @@ let AdditionalPredicates = [NotInMicroMips] in {
def BC2NEZ : BC2NEZ_ENC, BC2NEZ_DESC, ISA_MIPS32R6;
}
def BC : R6MMR6Rel, BC_ENC, BC_DESC, ISA_MIPS32R6;
-def BEQC : R6MMR6Rel, BEQC_ENC, BEQC_DESC, ISA_MIPS32R6;
-def BEQZALC : R6MMR6Rel, BEQZALC_ENC, BEQZALC_DESC, ISA_MIPS32R6;
-def BEQZC : R6MMR6Rel, BEQZC_ENC, BEQZC_DESC, ISA_MIPS32R6;
-def BGEC : R6MMR6Rel, BGEC_ENC, BGEC_DESC, ISA_MIPS32R6;
-def BGEUC : R6MMR6Rel, BGEUC_ENC, BGEUC_DESC, ISA_MIPS32R6;
-def BGEZALC : R6MMR6Rel, BGEZALC_ENC, BGEZALC_DESC, ISA_MIPS32R6;
-def BGEZC : BGEZC_ENC, BGEZC_DESC, ISA_MIPS32R6;
-def BGTZALC : R6MMR6Rel, BGTZALC_ENC, BGTZALC_DESC, ISA_MIPS32R6;
-def BGTZC : BGTZC_ENC, BGTZC_DESC, ISA_MIPS32R6;
+let AdditionalPredicates = [NotInMicroMips] in {
+ def BEQC : R6MMR6Rel, BEQC_ENC, BEQC_DESC, ISA_MIPS32R6;
+ def BEQZALC : R6MMR6Rel, BEQZALC_ENC, BEQZALC_DESC, ISA_MIPS32R6;
+ def BEQZC : R6MMR6Rel, BEQZC_ENC, BEQZC_DESC, ISA_MIPS32R6;
+ def BGEC : R6MMR6Rel, BGEC_ENC, BGEC_DESC, ISA_MIPS32R6;
+ def BGEUC : R6MMR6Rel, BGEUC_ENC, BGEUC_DESC, ISA_MIPS32R6;
+ def BGEZALC : R6MMR6Rel, BGEZALC_ENC, BGEZALC_DESC, ISA_MIPS32R6;
+ def BGEZC : R6MMR6Rel, BGEZC_ENC, BGEZC_DESC, ISA_MIPS32R6;
+ def BGTZALC : R6MMR6Rel, BGTZALC_ENC, BGTZALC_DESC, ISA_MIPS32R6;
+ def BGTZC : R6MMR6Rel, BGTZC_ENC, BGTZC_DESC, ISA_MIPS32R6;
+}
def BITSWAP : R6MMR6Rel, BITSWAP_ENC, BITSWAP_DESC, ISA_MIPS32R6;
-def BLEZALC : R6MMR6Rel, BLEZALC_ENC, BLEZALC_DESC, ISA_MIPS32R6;
-def BLEZC : BLEZC_ENC, BLEZC_DESC, ISA_MIPS32R6;
-def BLTC : R6MMR6Rel, BLTC_ENC, BLTC_DESC, ISA_MIPS32R6;
-def BLTUC : R6MMR6Rel, BLTUC_ENC, BLTUC_DESC, ISA_MIPS32R6;
-def BLTZALC : R6MMR6Rel, BLTZALC_ENC, BLTZALC_DESC, ISA_MIPS32R6;
-def BLTZC : BLTZC_ENC, BLTZC_DESC, ISA_MIPS32R6;
-def BNEC : R6MMR6Rel, BNEC_ENC, BNEC_DESC, ISA_MIPS32R6;
-def BNEZALC : R6MMR6Rel, BNEZALC_ENC, BNEZALC_DESC, ISA_MIPS32R6;
-def BNEZC : R6MMR6Rel, BNEZC_ENC, BNEZC_DESC, ISA_MIPS32R6;
let AdditionalPredicates = [NotInMicroMips] in {
+ def BLEZALC : R6MMR6Rel, BLEZALC_ENC, BLEZALC_DESC, ISA_MIPS32R6;
+ def BLEZC : R6MMR6Rel, BLEZC_ENC, BLEZC_DESC, ISA_MIPS32R6;
+ def BLTC : R6MMR6Rel, BLTC_ENC, BLTC_DESC, ISA_MIPS32R6;
+ def BLTUC : R6MMR6Rel, BLTUC_ENC, BLTUC_DESC, ISA_MIPS32R6;
+ def BLTZALC : R6MMR6Rel, BLTZALC_ENC, BLTZALC_DESC, ISA_MIPS32R6;
+ def BLTZC : R6MMR6Rel, BLTZC_ENC, BLTZC_DESC, ISA_MIPS32R6;
+ def BNEC : R6MMR6Rel, BNEC_ENC, BNEC_DESC, ISA_MIPS32R6;
+ def BNEZALC : R6MMR6Rel, BNEZALC_ENC, BNEZALC_DESC, ISA_MIPS32R6;
+ def BNEZC : R6MMR6Rel, BNEZC_ENC, BNEZC_DESC, ISA_MIPS32R6;
def BNVC : R6MMR6Rel, BNVC_ENC, BNVC_DESC, ISA_MIPS32R6;
def BOVC : R6MMR6Rel, BOVC_ENC, BOVC_DESC, ISA_MIPS32R6;
}
@@ -784,12 +829,16 @@ let AdditionalPredicates = [NotInMicroMips] in {
}
def CLO_R6 : R6MMR6Rel, CLO_R6_ENC, CLO_R6_DESC, ISA_MIPS32R6;
def CLZ_R6 : R6MMR6Rel, CLZ_R6_ENC, CLZ_R6_DESC, ISA_MIPS32R6;
-defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd>;
-defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd>;
+defm S : CMP_CC_M<FIELD_CMP_FORMAT_S, "s", FGR32Opnd, II_CMP_CC_S>;
+defm D : CMP_CC_M<FIELD_CMP_FORMAT_D, "d", FGR64Opnd, II_CMP_CC_D>;
let AdditionalPredicates = [NotInMicroMips] in {
def DIV : R6MMR6Rel, DIV_ENC, DIV_DESC, ISA_MIPS32R6;
def DIVU : R6MMR6Rel, DIVU_ENC, DIVU_DESC, ISA_MIPS32R6;
}
+
+def DVP : R6MMR6Rel, DVP_ENC, DVP_DESC, ISA_MIPS32R6;
+def EVP : R6MMR6Rel, EVP_ENC, EVP_DESC, ISA_MIPS32R6;
+
def JIALC : R6MMR6Rel, JIALC_ENC, JIALC_DESC, ISA_MIPS32R6;
def JIC : R6MMR6Rel, JIC_ENC, JIC_DESC, ISA_MIPS32R6;
def JR_HB_R6 : JR_HB_R6_ENC, JR_HB_R6_DESC, ISA_MIPS32R6;
@@ -802,8 +851,8 @@ let AdditionalPredicates = [NotInMicroMips] in {
def LWC2_R6 : LWC2_R6_ENC, LWC2_R6_DESC, ISA_MIPS32R6;
}
def LWPC : R6MMR6Rel, LWPC_ENC, LWPC_DESC, ISA_MIPS32R6;
-def LWUPC : LWUPC_ENC, LWUPC_DESC, ISA_MIPS32R6;
let AdditionalPredicates = [NotInMicroMips] in {
+ def LWUPC : R6MMR6Rel, LWUPC_ENC, LWUPC_DESC, ISA_MIPS32R6;
def MADDF_S : MADDF_S_ENC, MADDF_S_DESC, ISA_MIPS32R6, HARDFLOAT;
def MADDF_D : MADDF_D_ENC, MADDF_D_DESC, ISA_MIPS32R6, HARDFLOAT;
def MAXA_D : MAXA_D_ENC, MAXA_D_DESC, ISA_MIPS32R6, HARDFLOAT;
@@ -855,6 +904,9 @@ let AdditionalPredicates = [NotInMicroMips] in {
//
//===----------------------------------------------------------------------===//
+def : MipsInstAlias<"dvp", (DVP ZERO), 0>, ISA_MIPS32R6;
+def : MipsInstAlias<"evp", (EVP ZERO), 0>, ISA_MIPS32R6;
+
let AdditionalPredicates = [NotInMicroMips] in {
def : MipsInstAlias<"sdbbp", (SDBBP_R6 0)>, ISA_MIPS32R6;
def : MipsInstAlias<"jr $rs", (JALR ZERO, GPR32Opnd:$rs), 1>, ISA_MIPS32R6, GPR_32;
diff --git a/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td
index 88cfec5..521e22f 100644
--- a/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td
@@ -15,11 +15,6 @@
// Mips Operand, Complex Patterns and Transformations Definitions.
//===----------------------------------------------------------------------===//
-// Transformation Function - get Imm - 32.
-def Subtract32 : SDNodeXForm<imm, [{
- return getImm(N, (unsigned)N->getZExtValue() - 32);
-}]>;
-
// shamt must fit in 6 bits.
def immZExt6 : ImmLeaf<i32, [{return Imm == (Imm & 0x3f);}]>;
@@ -228,22 +223,24 @@ def LL64 : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, PTR_64,
ISA_MIPS2_NOT_32R6_64R6;
def SC64 : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, PTR_64,
ISA_MIPS2_NOT_32R6_64R6;
+def JR64 : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>, PTR_64;
}
+def JALR64 : JumpLinkReg<"jalr", GPR64Opnd>, JALR_FM;
+
/// Jump and Branch Instructions
let isCodeGenOnly = 1 in {
- def JR64 : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>;
def BEQ64 : CBranch<"beq", brtarget, seteq, GPR64Opnd>, BEQ_FM<4>;
def BNE64 : CBranch<"bne", brtarget, setne, GPR64Opnd>, BEQ_FM<5>;
def BGEZ64 : CBranchZero<"bgez", brtarget, setge, GPR64Opnd>, BGEZ_FM<1, 1>;
def BGTZ64 : CBranchZero<"bgtz", brtarget, setgt, GPR64Opnd>, BGEZ_FM<7, 0>;
def BLEZ64 : CBranchZero<"blez", brtarget, setle, GPR64Opnd>, BGEZ_FM<6, 0>;
def BLTZ64 : CBranchZero<"bltz", brtarget, setlt, GPR64Opnd>, BGEZ_FM<1, 0>;
- def JALR64 : JumpLinkReg<"jalr", GPR64Opnd>, JALR_FM;
def JALR64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR, RA, GPR32Opnd>;
- def TAILCALL64_R : TailCallReg<GPR64Opnd, JR, GPR32Opnd>;
}
+def TAILCALLREG64 : TailCallReg<GPR64Opnd>;
+
def PseudoReturn64 : PseudoReturnBase<GPR64Opnd>;
def PseudoIndirectBranch64 : PseudoIndirectBranchBase<GPR64Opnd>;
@@ -293,14 +290,16 @@ def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd, II_SEH>, SEB_FM<0x18, 0x20>,
/// Count Leading
let AdditionalPredicates = [NotInMicroMips] in {
- def DCLZ : StdMMR6Rel, CountLeading0<"dclz", GPR64Opnd>, CLO_FM<0x24>,
- ISA_MIPS64_NOT_64R6;
- def DCLO : StdMMR6Rel, CountLeading1<"dclo", GPR64Opnd>, CLO_FM<0x25>,
- ISA_MIPS64_NOT_64R6;
+ def DCLZ : StdMMR6Rel, CountLeading0<"dclz", GPR64Opnd, II_DCLZ>,
+ CLO_FM<0x24>, ISA_MIPS64_NOT_64R6;
+ def DCLO : StdMMR6Rel, CountLeading1<"dclo", GPR64Opnd, II_DCLO>,
+ CLO_FM<0x25>, ISA_MIPS64_NOT_64R6;
/// Double Word Swap Bytes/HalfWords
- def DSBH : SubwordSwap<"dsbh", GPR64Opnd>, SEB_FM<2, 0x24>, ISA_MIPS64R2;
- def DSHD : SubwordSwap<"dshd", GPR64Opnd>, SEB_FM<5, 0x24>, ISA_MIPS64R2;
+ def DSBH : SubwordSwap<"dsbh", GPR64Opnd, II_DSBH>, SEB_FM<2, 0x24>,
+ ISA_MIPS64R2;
+ def DSHD : SubwordSwap<"dshd", GPR64Opnd, II_DSHD>, SEB_FM<5, 0x24>,
+ ISA_MIPS64R2;
}
def LEA_ADDiu64 : EffectiveAddress<"daddiu", GPR64Opnd>, LW_FM<0x19>;
@@ -357,11 +356,12 @@ class Count1s<string opstr, RegisterOperand RO>:
let TwoOperandAliasConstraint = "$rd = $rs";
}
-class ExtsCins<string opstr, SDPatternOperator Op = null_frag>:
+class ExtsCins<string opstr, InstrItinClass itin,
+ SDPatternOperator Op = null_frag>:
InstSE<(outs GPR64Opnd:$rt), (ins GPR64Opnd:$rs, uimm5:$pos, uimm5:$lenm1),
!strconcat(opstr, " $rt, $rs, $pos, $lenm1"),
[(set GPR64Opnd:$rt, (Op GPR64Opnd:$rs, imm:$pos, imm:$lenm1))],
- NoItinerary, FrmR, opstr> {
+ itin, FrmR, opstr> {
let TwoOperandAliasConstraint = "$rt = $rs";
}
@@ -395,9 +395,9 @@ class CBranchBitNum<string opstr, DAGOperand opnd, PatFrag cond_op,
let Defs = [AT];
}
-class MFC2OP<string asmstr, RegisterOperand RO> :
+class MFC2OP<string asmstr, RegisterOperand RO, InstrItinClass itin> :
InstSE<(outs RO:$rt, uimm16:$imm16), (ins),
- !strconcat(asmstr, "\t$rt, $imm16"), [], NoItinerary, FrmFR>;
+ !strconcat(asmstr, "\t$rt, $imm16"), [], itin, FrmFR>;
// Unsigned Byte Add
def BADDu : ArithLogicR<"baddu", GPR64Opnd, 1, II_BADDU>,
@@ -425,12 +425,12 @@ def DMUL : ArithLogicR<"dmul", GPR64Opnd, 1, II_DMUL, mul>,
}
// Extract a signed bit field /+32
-def EXTS : ExtsCins<"exts">, EXTS_FM<0x3a>, ASE_CNMIPS;
-def EXTS32: ExtsCins<"exts32">, EXTS_FM<0x3b>, ASE_CNMIPS;
+def EXTS : ExtsCins<"exts", II_EXT>, EXTS_FM<0x3a>, ASE_CNMIPS;
+def EXTS32: ExtsCins<"exts32", II_EXT>, EXTS_FM<0x3b>, ASE_CNMIPS;
// Clear and insert a bit field /+32
-def CINS : ExtsCins<"cins">, EXTS_FM<0x32>, ASE_CNMIPS;
-def CINS32: ExtsCins<"cins32">, EXTS_FM<0x33>, ASE_CNMIPS;
+def CINS : ExtsCins<"cins", II_INS>, EXTS_FM<0x32>, ASE_CNMIPS;
+def CINS32: ExtsCins<"cins32", II_INS>, EXTS_FM<0x33>, ASE_CNMIPS;
// Move to multiplier/product register
def MTM0 : MoveToLOHI<"mtm0", GPR64Opnd, [MPL0, P0, P1, P2]>, MTMR_FM<0x08>,
@@ -472,8 +472,10 @@ def VMULU : ArithLogicR<"vmulu", GPR64Opnd, 0, II_DMUL>, ADD_FM<0x1c, 0x0f>,
}
// Move between CPU and coprocessor registers
-def DMFC2_OCTEON : MFC2OP<"dmfc2", GPR64Opnd>, MFC2OP_FM<0x12, 1>, ASE_CNMIPS;
-def DMTC2_OCTEON : MFC2OP<"dmtc2", GPR64Opnd>, MFC2OP_FM<0x12, 5>, ASE_CNMIPS;
+def DMFC2_OCTEON : MFC2OP<"dmfc2", GPR64Opnd, II_DMFC2>, MFC2OP_FM<0x12, 1>,
+ ASE_CNMIPS;
+def DMTC2_OCTEON : MFC2OP<"dmtc2", GPR64Opnd, II_DMTC2>, MFC2OP_FM<0x12, 5>,
+ ASE_CNMIPS;
}
}
@@ -494,6 +496,16 @@ def DMTC2 : MTC3OP<"dmtc2", COP2Opnd, GPR64Opnd, II_DMTC2>, MFC3OP_FM<0x12, 5>,
// Arbitrary patterns that map to one or more instructions
//===----------------------------------------------------------------------===//
+// Materialize i64 constants.
+defm : MaterializeImms<i64, ZERO_64, DADDiu, LUi64, ORi64>;
+
+def : MipsPat<(i64 immZExt32Low16Zero:$imm),
+ (DSLL (ORi64 ZERO_64, (HI16 imm:$imm)), 16)>;
+
+def : MipsPat<(i64 immZExt32:$imm),
+ (ORi64 (DSLL (ORi64 ZERO_64, (HI16 imm:$imm)), 16),
+ (LO16 imm:$imm))>;
+
// extended loads
def : MipsPat<(i64 (extloadi1 addr:$src)), (LB64 addr:$src)>;
def : MipsPat<(i64 (extloadi8 addr:$src)), (LB64 addr:$src)>;
@@ -537,21 +549,21 @@ let AdditionalPredicates = [NotInMicroMips] in {
def : WrapperPat<tglobaltlsaddr, DADDiu, GPR64>;
}
-defm : BrcondPats<GPR64, BEQ64, BNE64, SLT64, SLTu64, SLTi64, SLTiu64,
+defm : BrcondPats<GPR64, BEQ64, BEQ, BNE64, SLT64, SLTu64, SLTi64, SLTiu64,
ZERO_64>;
-
def : MipsPat<(brcond (i32 (setlt i64:$lhs, 1)), bb:$dst),
(BLEZ64 i64:$lhs, bb:$dst)>;
def : MipsPat<(brcond (i32 (setgt i64:$lhs, -1)), bb:$dst),
(BGEZ64 i64:$lhs, bb:$dst)>;
// setcc patterns
-defm : SeteqPats<GPR64, SLTiu64, XOR64, SLTu64, ZERO_64>;
-defm : SetlePats<GPR64, SLT64, SLTu64>;
-defm : SetgtPats<GPR64, SLT64, SLTu64>;
-defm : SetgePats<GPR64, SLT64, SLTu64>;
-defm : SetgeImmPats<GPR64, SLTi64, SLTiu64>;
-
+let AdditionalPredicates = [NotInMicroMips] in {
+ defm : SeteqPats<GPR64, SLTiu64, XOR64, SLTu64, ZERO_64>;
+ defm : SetlePats<GPR64, XORi, SLT64, SLTu64>;
+ defm : SetgtPats<GPR64, SLT64, SLTu64>;
+ defm : SetgePats<GPR64, XORi, SLT64, SLTu64>;
+ defm : SetgeImmPats<GPR64, XORi, SLTi64, SLTiu64>;
+}
// truncate
def : MipsPat<(trunc (assertsext GPR64:$src)),
(EXTRACT_SUBREG GPR64:$src, sub_32)>;
@@ -658,11 +670,14 @@ let AdditionalPredicates = [NotInMicroMips] in {
(DSUB GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>,
ISA_MIPS3;
def : MipsInstAlias<"dneg $rt",
- (DSUB GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 0>,
+ (DSUB GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 1>,
ISA_MIPS3;
def : MipsInstAlias<"dnegu $rt, $rs",
(DSUBu GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>,
ISA_MIPS3;
+ def : MipsInstAlias<"dnegu $rt",
+ (DSUBu GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 1>,
+ ISA_MIPS3;
}
def : MipsInstAlias<"dsubi $rs, $rt, $imm",
(DADDi GPR64Opnd:$rs, GPR64Opnd:$rt,
diff --git a/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td
index 64effbe..dabf4e0 100644
--- a/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/Mips64r6InstrInfo.td
@@ -48,8 +48,8 @@ class SCD_R6_ENC : SPECIAL3_LL_SC_FM<OPCODE6_SCD>;
class AHI_ATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, InstrItinClass itin> {
dag OutOperandList = (outs GPROpnd:$rs);
- dag InOperandList = (ins GPROpnd:$rt, simm16_relaxed:$imm);
- string AsmString = !strconcat(instr_asm, "\t$rt, $imm");
+ dag InOperandList = (ins GPROpnd:$rt, uimm16_altrelaxed:$imm);
+ string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $imm");
string Constraints = "$rs = $rt";
InstrItinClass Itinerary = itin;
}
@@ -76,13 +76,27 @@ class SCD_R6_DESC : SC_R6_DESC_BASE<"scd", GPR64Opnd, II_SCD>;
class SELEQZ64_DESC : SELEQNE_Z_DESC_BASE<"seleqz", GPR64Opnd>;
class SELNEZ64_DESC : SELEQNE_Z_DESC_BASE<"selnez", GPR64Opnd>;
+class BGEC64_DESC : CMP_BC_DESC_BASE<"bgec", brtarget, GPR64Opnd>;
+class BGEUC64_DESC : CMP_BC_DESC_BASE<"bgeuc", brtarget, GPR64Opnd>;
+class BEQC64_DESC : CMP_BC_DESC_BASE<"beqc", brtarget, GPR64Opnd>;
+class BNEC64_DESC : CMP_BC_DESC_BASE<"bnec", brtarget, GPR64Opnd>;
+class BLTC64_DESC : CMP_BC_DESC_BASE<"bltc", brtarget, GPR64Opnd>;
+class BLTUC64_DESC : CMP_BC_DESC_BASE<"bltuc", brtarget, GPR64Opnd>;
+class BLTZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"bltzc", brtarget, GPR64Opnd>;
+class BGEZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgezc", brtarget, GPR64Opnd>;
+class BLEZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"blezc", brtarget, GPR64Opnd>;
+class BGTZC64_DESC : CMP_CBR_RT_Z_DESC_BASE<"bgtzc", brtarget, GPR64Opnd>;
+class BEQZC64_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"beqzc", brtarget21, GPR64Opnd>;
+class BNEZC64_DESC : CMP_CBR_EQNE_Z_DESC_BASE<"bnezc", brtarget21, GPR64Opnd>;
+
class JIALC64_DESC : JMP_IDX_COMPACT_DESC_BASE<"jialc", calloffset16,
- GPR64Opnd> {
+ GPR64Opnd, II_JIALC> {
bit isCall = 1;
list<Register> Defs = [RA];
}
-class JIC64_DESC : JMP_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, GPR64Opnd> {
+class JIC64_DESC : JMP_IDX_COMPACT_DESC_BASE<"jic", jmpoffset16, GPR64Opnd,
+ II_JIC> {
bit isBarrier = 1;
bit isTerminator = 1;
list<Register> Defs = [AT];
@@ -97,22 +111,20 @@ class SC64_R6_DESC : SC_R6_DESC_BASE<"sc", GPR32Opnd, II_SC>;
//===----------------------------------------------------------------------===//
let AdditionalPredicates = [NotInMicroMips] in {
- def DATI : DATI_ENC, DATI_DESC, ISA_MIPS64R6;
- def DAHI : DAHI_ENC, DAHI_DESC, ISA_MIPS64R6;
+ let DecoderMethod = "DecodeDAHIDATI" in {
+ def DATI : DATI_ENC, DATI_DESC, ISA_MIPS64R6;
+ def DAHI : DAHI_ENC, DAHI_DESC, ISA_MIPS64R6;
+ }
def DAUI : DAUI_ENC, DAUI_DESC, ISA_MIPS64R6;
def DALIGN : DALIGN_ENC, DALIGN_DESC, ISA_MIPS64R6;
-}
-def DBITSWAP : DBITSWAP_ENC, DBITSWAP_DESC, ISA_MIPS64R6;
-let AdditionalPredicates = [NotInMicroMips] in {
+ def DBITSWAP : R6MMR6Rel, DBITSWAP_ENC, DBITSWAP_DESC, ISA_MIPS64R6;
def DCLO_R6 : R6MMR6Rel, DCLO_R6_ENC, DCLO_R6_DESC, ISA_MIPS64R6;
def DCLZ_R6 : R6MMR6Rel, DCLZ_R6_ENC, DCLZ_R6_DESC, ISA_MIPS64R6;
def DDIV : DDIV_ENC, DDIV_DESC, ISA_MIPS64R6;
def DDIVU : DDIVU_ENC, DDIVU_DESC, ISA_MIPS64R6;
def DMOD : DMOD_ENC, DMOD_DESC, ISA_MIPS64R6;
def DMODU : DMODU_ENC, DMODU_DESC, ISA_MIPS64R6;
-}
-def DLSA_R6 : DLSA_R6_ENC, DLSA_R6_DESC, ISA_MIPS64R6;
-let AdditionalPredicates = [NotInMicroMips] in {
+ def DLSA_R6 : R6MMR6Rel, DLSA_R6_ENC, DLSA_R6_DESC, ISA_MIPS64R6;
def DMUH: DMUH_ENC, DMUH_DESC, ISA_MIPS64R6;
def DMUHU: DMUHU_ENC, DMUHU_DESC, ISA_MIPS64R6;
def DMUL_R6: DMUL_R6_ENC, DMUL_R6_DESC, ISA_MIPS64R6;
@@ -130,10 +142,28 @@ let AdditionalPredicates = [NotInMicroMips],
def LL64_R6 : LL_R6_ENC, LL64_R6_DESC, PTR_64, ISA_MIPS64R6;
def SC64_R6 : SC_R6_ENC, SC64_R6_DESC, PTR_64, ISA_MIPS64R6;
}
-let isCodeGenOnly = 1 in {
-def JIALC64 : JIALC_ENC, JIALC64_DESC, ISA_MIPS64R6;
-def JIC64 : JIC_ENC, JIC64_DESC, ISA_MIPS64R6;
+
+let DecoderNamespace = "Mips32r6_64r6_GP64" in {
+// Jump and Branch Instructions
+def JIALC64 : JIALC_ENC, JIALC64_DESC, ISA_MIPS64R6, GPR_64;
+def JIC64 : JIC_ENC, JIC64_DESC, ISA_MIPS64R6, GPR_64;
+
+def BEQC64 : BEQC_ENC, BEQC64_DESC, ISA_MIPS64R6, GPR_64;
+def BEQZC64 : BEQZC_ENC, BEQZC64_DESC, ISA_MIPS64R6, GPR_64;
+def BGEC64 : BGEC_ENC, BGEC64_DESC, ISA_MIPS64R6, GPR_64;
+def BGEUC64 : BGEUC_ENC, BGEUC64_DESC, ISA_MIPS64R6, GPR_64;
+def BGTZC64 : BGTZC_ENC, BGTZC64_DESC, ISA_MIPS64R6, GPR_64;
+def BLEZC64 : BLEZC_ENC, BLEZC64_DESC, ISA_MIPS64R6, GPR_64;
+def BLTC64 : BLTC_ENC, BLTC64_DESC, ISA_MIPS64R6, GPR_64;
+def BLTUC64 : BLTUC_ENC, BLTUC64_DESC, ISA_MIPS64R6, GPR_64;
+def BNEC64 : BNEC_ENC, BNEC64_DESC, ISA_MIPS64R6, GPR_64;
+def BNEZC64 : BNEZC_ENC, BNEZC64_DESC, ISA_MIPS64R6, GPR_64;
}
+let DecoderNamespace = "Mips32r6_64r6_BranchZero" in {
+def BLTZC64 : BLTZC_ENC, BLTZC64_DESC, ISA_MIPS64R6, GPR_64;
+def BGEZC64 : BGEZC_ENC, BGEZC64_DESC, ISA_MIPS64R6, GPR_64;
+}
+
//===----------------------------------------------------------------------===//
//
// Instruction Aliases
diff --git a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index 3686c2f..04d6529 100644
--- a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -60,10 +60,6 @@ MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {
bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
Subtarget = &MF.getSubtarget<MipsSubtarget>();
- // Initialize TargetLoweringObjectFile.
- const_cast<TargetLoweringObjectFile &>(getObjFileLowering())
- .Initialize(OutContext, TM);
-
MipsFI = MF.getInfo<MipsFunctionInfo>();
if (Subtarget->inMips16Mode())
for (std::map<
@@ -98,6 +94,7 @@ bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
const MachineInstr *MI) {
bool HasLinkReg = false;
+ bool InMicroMipsMode = Subtarget->inMicroMipsMode();
MCInst TmpInst0;
if (Subtarget->hasMips64r6()) {
@@ -106,8 +103,12 @@ void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
HasLinkReg = true;
} else if (Subtarget->hasMips32r6()) {
// MIPS32r6 should use (JALR ZERO, $rs)
- TmpInst0.setOpcode(Mips::JALR);
- HasLinkReg = true;
+ if (InMicroMipsMode)
+ TmpInst0.setOpcode(Mips::JRC16_MMR6);
+ else {
+ TmpInst0.setOpcode(Mips::JALR);
+ HasLinkReg = true;
+ }
} else if (Subtarget->inMicroMipsMode())
// microMIPS should use (JR_MM $rs)
TmpInst0.setOpcode(Mips::JR_MM);
@@ -185,7 +186,9 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
if (I->getOpcode() == Mips::PseudoReturn ||
I->getOpcode() == Mips::PseudoReturn64 ||
I->getOpcode() == Mips::PseudoIndirectBranch ||
- I->getOpcode() == Mips::PseudoIndirectBranch64) {
+ I->getOpcode() == Mips::PseudoIndirectBranch64 ||
+ I->getOpcode() == Mips::TAILCALLREG ||
+ I->getOpcode() == Mips::TAILCALLREG64) {
emitPseudoIndirectBranch(*OutStreamer, &*I);
continue;
}
@@ -250,9 +253,9 @@ void MipsAsmPrinter::printSavedRegsBitmask() {
int CPUTopSavedRegOff, FPUTopSavedRegOff;
// Set the CPU and FPU Bitmasks
- const MachineFrameInfo *MFI = MF->getFrameInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// size of stack area to which FP callee-saved regs are saved.
unsigned CPURegSize = Mips::GPR32RegClass.getSize();
unsigned FGR32RegSize = Mips::FGR32RegClass.getSize();
@@ -302,7 +305,7 @@ void MipsAsmPrinter::emitFrameDirective() {
unsigned stackReg = RI.getFrameRegister(*MF);
unsigned returnReg = RI.getRARegister();
- unsigned stackSize = MF->getFrameInfo()->getStackSize();
+ unsigned stackSize = MF->getFrameInfo().getStackSize();
getTargetStreamer().emitFrame(stackReg, stackSize, returnReg);
}
@@ -497,7 +500,7 @@ bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
unsigned RegOp = OpNum;
if (!Subtarget->isGP64bit()){
- // Endianess reverses which register holds the high or low value
+ // Endianness reverses which register holds the high or low value
// between M and L.
switch(ExtraCode[0]) {
case 'M':
@@ -1034,6 +1037,22 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
// TODO: implement
}
+// Emit .dtprelword or .dtpreldword directive
+// and value for debug thread local expression.
+void MipsAsmPrinter::EmitDebugValue(const MCExpr *Value,
+ unsigned Size) const {
+ switch (Size) {
+ case 4:
+ OutStreamer->EmitDTPRel32Value(Value);
+ break;
+ case 8:
+ OutStreamer->EmitDTPRel64Value(Value);
+ break;
+ default:
+ llvm_unreachable("Unexpected size of expression value.");
+ }
+}
+
// Align all targets of indirect branches on bundle size. Used only if target
// is NaCl.
void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
@@ -1063,8 +1082,8 @@ bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {
// Force static initialization.
extern "C" void LLVMInitializeMipsAsmPrinter() {
- RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget);
- RegisterAsmPrinter<MipsAsmPrinter> Y(TheMipselTarget);
- RegisterAsmPrinter<MipsAsmPrinter> A(TheMips64Target);
- RegisterAsmPrinter<MipsAsmPrinter> B(TheMips64elTarget);
+ RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget());
+ RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());
+ RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());
+ RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h
index f30141f..c5cf524 100644
--- a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h
+++ b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h
@@ -103,9 +103,7 @@ public:
: AsmPrinter(TM, std::move(Streamer)), MCP(nullptr),
InConstantPool(false), MCInstLowering(*this) {}
- const char *getPassName() const override {
- return "Mips Assembly Printer";
- }
+ StringRef getPassName() const override { return "Mips Assembly Printer"; }
bool runOnMachineFunction(MachineFunction &MF) override;
@@ -142,6 +140,7 @@ public:
void EmitStartOfAsmFile(Module &M) override;
void EmitEndOfAsmFile(Module &M) override;
void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
+ void EmitDebugValue(const MCExpr *Value, unsigned Size) const override;
};
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp b/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp
index 1ea48e0..08b8ed3 100644
--- a/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp
@@ -356,15 +356,13 @@ namespace {
: MachineFunctionPass(ID), STI(nullptr), MF(nullptr), MCP(nullptr),
PrescannedForConstants(false) {}
- const char *getPassName() const override {
- return "Mips Constant Islands";
- }
+ StringRef getPassName() const override { return "Mips Constant Islands"; }
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
void doInitialPlacement(std::vector<MachineInstr*> &CPEMIs);
@@ -801,7 +799,7 @@ void MipsConstantIslands::computeBlockSize(MachineBasicBlock *MBB) {
BBI.Size = 0;
for (const MachineInstr &MI : *MBB)
- BBI.Size += TII->GetInstSizeInBytes(MI);
+ BBI.Size += TII->getInstSizeInBytes(MI);
}
/// getOffsetOf - Return the current offset of the specified machine instruction
@@ -818,7 +816,7 @@ unsigned MipsConstantIslands::getOffsetOf(MachineInstr *MI) const {
// Sum instructions before MI in MBB.
for (MachineBasicBlock::iterator I = MBB->begin(); &*I != MI; ++I) {
assert(I != MBB->end() && "Didn't find MI in its own basic block?");
- Offset += TII->GetInstSizeInBytes(*I);
+ Offset += TII->getInstSizeInBytes(*I);
}
return Offset;
}
@@ -1297,12 +1295,11 @@ void MipsConstantIslands::createNewWater(unsigned CPUserIndex,
unsigned CPUIndex = CPUserIndex+1;
unsigned NumCPUsers = CPUsers.size();
//MachineInstr *LastIT = 0;
- for (unsigned Offset = UserOffset + TII->GetInstSizeInBytes(*UserMI);
+ for (unsigned Offset = UserOffset + TII->getInstSizeInBytes(*UserMI);
Offset < BaseInsertOffset;
- Offset += TII->GetInstSizeInBytes(*MI), MI = std::next(MI)) {
+ Offset += TII->getInstSizeInBytes(*MI), MI = std::next(MI)) {
assert(MI != UserMBB->end() && "Fell off end of block");
- if (CPUIndex < NumCPUsers &&
- CPUsers[CPUIndex].MI == static_cast<MachineInstr *>(MI)) {
+ if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == MI) {
CPUser &U = CPUsers[CPUIndex];
if (!isOffsetInRange(Offset, EndInsertOffset, U)) {
// Shift intertion point by one unit of alignment so it is within reach.
@@ -1374,7 +1371,7 @@ bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) {
// it. Check for this so it will be removed from the WaterList.
// Also remove any entry from NewWaterList.
MachineBasicBlock *WaterBB = &*--NewMBB->getIterator();
- IP = std::find(WaterList.begin(), WaterList.end(), WaterBB);
+ IP = find(WaterList, WaterBB);
if (IP != WaterList.end())
NewWaterList.erase(WaterBB);
@@ -1622,7 +1619,7 @@ MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) {
splitBlockBeforeInstr(*MI);
// No need for the branch to the next block. We're adding an unconditional
// branch to the destination.
- int delta = TII->GetInstSizeInBytes(MBB->back());
+ int delta = TII->getInstSizeInBytes(MBB->back());
BBInfo[MBB->getNumber()].Size -= delta;
MBB->back().eraseFromParent();
// BBInfo[SplitBB].Offset is wrong temporarily, fixed below
@@ -1644,14 +1641,14 @@ MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) {
.addMBB(NextBB);
}
Br.MI = &MBB->back();
- BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(MBB->back());
+ BBInfo[MBB->getNumber()].Size += TII->getInstSizeInBytes(MBB->back());
BuildMI(MBB, DebugLoc(), TII->get(Br.UncondBr)).addMBB(DestBB);
- BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(MBB->back());
+ BBInfo[MBB->getNumber()].Size += TII->getInstSizeInBytes(MBB->back());
unsigned MaxDisp = getUnconditionalBrDisp(Br.UncondBr);
ImmBranches.push_back(ImmBranch(&MBB->back(), MaxDisp, false, Br.UncondBr));
// Remove the old conditional branch. It may or may not still be in MBB.
- BBInfo[MI->getParent()->getNumber()].Size -= TII->GetInstSizeInBytes(*MI);
+ BBInfo[MI->getParent()->getNumber()].Size -= TII->getInstSizeInBytes(*MI);
MI->eraseFromParent();
adjustBBOffsetsAfter(MBB);
return true;
diff --git a/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
index b5ba770..c821084 100644
--- a/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
@@ -79,8 +79,7 @@ static cl::opt<CompactBranchPolicy> MipsCompactBranchPolicy(
cl::values(
clEnumValN(CB_Never, "never", "Do not use compact branches if possible."),
clEnumValN(CB_Optimal, "optimal", "Use compact branches where appropiate (default)."),
- clEnumValN(CB_Always, "always", "Always use compact branches if possible."),
- clEnumValEnd
+ clEnumValN(CB_Always, "always", "Always use compact branches if possible.")
)
);
@@ -192,9 +191,7 @@ namespace {
Filler(TargetMachine &tm)
: MachineFunctionPass(ID), TM(tm) { }
- const char *getPassName() const override {
- return "Mips Delay Slot Filler";
- }
+ StringRef getPassName() const override { return "Mips Delay Slot Filler"; }
bool runOnMachineFunction(MachineFunction &F) override {
bool Changed = false;
@@ -213,7 +210,7 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -242,7 +239,7 @@ namespace {
/// This function searches in the backward direction for an instruction that
/// can be moved to the delay slot. Returns true on success.
- bool searchBackward(MachineBasicBlock &MBB, Iter Slot) const;
+ bool searchBackward(MachineBasicBlock &MBB, MachineInstr &Slot) const;
/// This function searches MBB in the forward direction for an instruction
/// that can be moved to the delay slot. Returns true on success.
@@ -543,6 +540,9 @@ Iter Filler::replaceWithCompactBranch(MachineBasicBlock &MBB, Iter Branch,
// For given opcode returns opcode of corresponding instruction with short
// delay slot.
+// For the pseudo TAILCALL*_MM instrunctions return the short delay slot
+// form. Unfortunately, TAILCALL<->b16 is denied as b16 has a limited range
+// that is too short to make use of for tail calls.
static int getEquivalentCallShort(int Opcode) {
switch (Opcode) {
case Mips::BGEZAL:
@@ -555,6 +555,10 @@ static int getEquivalentCallShort(int Opcode) {
return Mips::JALRS_MM;
case Mips::JALR16_MM:
return Mips::JALRS16_MM;
+ case Mips::TAILCALL_MM:
+ llvm_unreachable("Attempting to shorten the TAILCALL_MM pseudo!");
+ case Mips::TAILCALLREG:
+ return Mips::JR16_MM;
default:
llvm_unreachable("Unexpected call instruction for microMIPS.");
}
@@ -587,7 +591,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
if (MipsCompactBranchPolicy.getValue() != CB_Always ||
!TII->getEquivalentCompactForm(I)) {
- if (searchBackward(MBB, I)) {
+ if (searchBackward(MBB, *I)) {
Filled = true;
} else if (I->isTerminator()) {
if (searchSuccBBs(MBB, I)) {
@@ -602,10 +606,16 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
// Get instruction with delay slot.
MachineBasicBlock::instr_iterator DSI = I.getInstrIterator();
- if (InMicroMipsMode && TII->GetInstSizeInBytes(*std::next(DSI)) == 2 &&
+ if (InMicroMipsMode && TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
DSI->isCall()) {
// If instruction in delay slot is 16b change opcode to
// corresponding instruction with short delay slot.
+
+ // TODO: Implement an instruction mapping table of 16bit opcodes to
+ // 32bit opcodes so that an instruction can be expanded. This would
+ // save 16 bits as a TAILCALL_MM pseudo requires a fullsized nop.
+ // TODO: Permit b16 when branching backwards to the the same function
+ // if it is in range.
DSI->setDesc(TII->get(getEquivalentCallShort(DSI->getOpcode())));
}
continue;
@@ -646,8 +656,6 @@ template<typename IterTy>
bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
RegDefsUses &RegDU, InspectMemInstr& IM, Iter Slot,
IterTy &Filler) const {
- bool IsReverseIter = std::is_convertible<IterTy, ReverseIter>::value;
-
for (IterTy I = Begin; I != End;) {
IterTy CurrI = I;
++I;
@@ -664,12 +672,6 @@ bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
if (CurrI->isKill()) {
CurrI->eraseFromParent();
-
- // This special case is needed for reverse iterators, because when we
- // erase an instruction, the iterators are updated to point to the next
- // instruction.
- if (IsReverseIter && I != End)
- I = CurrI;
continue;
}
@@ -692,9 +694,14 @@ bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
bool InMicroMipsMode = STI.inMicroMipsMode();
const MipsInstrInfo *TII = STI.getInstrInfo();
unsigned Opcode = (*Slot).getOpcode();
- if (InMicroMipsMode && TII->GetInstSizeInBytes(*CurrI) == 2 &&
+ // This is complicated by the tail call optimization. For non-PIC code
+ // there is only a 32bit sized unconditional branch which can be assumed
+ // to be able to reach the target. b16 only has a range of +/- 1 KB.
+ // It's entirely possible that the target function is reachable with b16
+ // but we don't have enough information to make that decision.
+ if (InMicroMipsMode && TII->getInstSizeInBytes(*CurrI) == 2 &&
(Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
- Opcode == Mips::PseudoReturn))
+ Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
continue;
Filler = CurrI;
@@ -704,23 +711,24 @@ bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
return false;
}
-bool Filler::searchBackward(MachineBasicBlock &MBB, Iter Slot) const {
+bool Filler::searchBackward(MachineBasicBlock &MBB, MachineInstr &Slot) const {
if (DisableBackwardSearch)
return false;
auto *Fn = MBB.getParent();
RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
- MemDefsUses MemDU(Fn->getDataLayout(), Fn->getFrameInfo());
+ MemDefsUses MemDU(Fn->getDataLayout(), &Fn->getFrameInfo());
ReverseIter Filler;
- RegDU.init(*Slot);
+ RegDU.init(Slot);
- if (!searchRange(MBB, ReverseIter(Slot), MBB.rend(), RegDU, MemDU, Slot,
+ MachineBasicBlock::iterator SlotI = Slot;
+ if (!searchRange(MBB, ++SlotI.getReverse(), MBB.rend(), RegDU, MemDU, Slot,
Filler))
return false;
- MBB.splice(std::next(Slot), &MBB, std::next(Filler).base());
- MIBundleBuilder(MBB, Slot, std::next(Slot, 2));
+ MBB.splice(std::next(SlotI), &MBB, Filler.getReverse());
+ MIBundleBuilder(MBB, SlotI, std::next(SlotI, 2));
++UsefulSlots;
return true;
}
@@ -776,8 +784,8 @@ bool Filler::searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const {
if (HasMultipleSuccs) {
IM.reset(new LoadFromStackOrConst());
} else {
- const MachineFrameInfo *MFI = Fn->getFrameInfo();
- IM.reset(new MemDefsUses(Fn->getDataLayout(), MFI));
+ const MachineFrameInfo &MFI = Fn->getFrameInfo();
+ IM.reset(new MemDefsUses(Fn->getDataLayout(), &MFI));
}
if (!searchRange(MBB, SuccBB->begin(), SuccBB->end(), RegDU, *IM, Slot,
diff --git a/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td
index 11e191a..8c30248 100644
--- a/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td
+++ b/contrib/llvm/lib/Target/Mips/MipsEVAInstrFormats.td
@@ -50,7 +50,7 @@ def OPCODE6_TLBINVF : OPCODE6<0b000100>;
def OPCODE6_CACHEE : OPCODE6<0b011011>;
def OPCODE6_PREFE : OPCODE6<0b100011>;
-def OPGROUP_COP0 : OPGROUP<0b010000>;
+def OPGROUP_COP0_TLB : OPGROUP<0b010000>;
//===----------------------------------------------------------------------===//
//
@@ -77,7 +77,7 @@ class SPECIAL3_EVA_LOAD_STORE_FM<OPCODE6 Operation> : MipsEVAInst {
class TLB_FM<OPCODE6 Operation> : MipsEVAInst {
bits<32> Inst;
- let Inst{31-26} = OPGROUP_COP0.Value;
+ let Inst{31-26} = OPGROUP_COP0_TLB.Value;
let Inst{25} = 1; // CO
let Inst{24-6} = 0;
let Inst{5-0} = Operation.Value;
diff --git a/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp b/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp
index 19c201d..a44192f 100644
--- a/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsFastISel.cpp
@@ -31,6 +31,9 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "mips-fastisel"
using namespace llvm;
@@ -95,10 +98,10 @@ class MipsFastISel final : public FastISel {
// Convenience variables to avoid some queries.
LLVMContext *Context;
+ bool fastLowerArguments() override;
bool fastLowerCall(CallLoweringInfo &CLI) override;
bool fastLowerIntrinsicCall(const IntrinsicInst *II) override;
- bool TargetSupported;
bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle
// floating point but not reject doing fast-isel in other
// situations
@@ -195,6 +198,9 @@ private:
bool processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl<MVT> &ArgVTs,
unsigned &NumBytes);
bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes);
+ const MipsABIInfo &getABI() const {
+ return static_cast<const MipsTargetMachine &>(TM).getABI();
+ }
public:
// Backend specific FastISel code.
@@ -205,12 +211,7 @@ public:
TII(*Subtarget->getInstrInfo()), TLI(*Subtarget->getTargetLowering()) {
MFI = funcInfo.MF->getInfo<MipsFunctionInfo>();
Context = &funcInfo.Fn->getContext();
- bool ISASupported = !Subtarget->hasMips32r6() &&
- !Subtarget->inMicroMipsMode() && Subtarget->hasMips32();
- TargetSupported =
- ISASupported && TM.isPositionIndependent() &&
- (static_cast<const MipsTargetMachine &>(TM).getABI().IsO32());
- UnsupportedFPMode = Subtarget->isFP64bit();
+ UnsupportedFPMode = Subtarget->isFP64bit() || Subtarget->useSoftFloat();
}
unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
@@ -285,9 +286,6 @@ unsigned MipsFastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT,
}
unsigned MipsFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
- if (!TargetSupported)
- return 0;
-
assert(TLI.getValueType(DL, AI->getType(), true) == MVT::i32 &&
"Alloca should always return a pointer.");
@@ -398,9 +396,6 @@ unsigned MipsFastISel::materializeExternalCallSym(MCSymbol *Sym) {
// Materialize a constant into a register, and return the register
// number (or zero if we failed to handle it).
unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) {
- if (!TargetSupported)
- return 0;
-
EVT CEVT = TLI.getValueType(DL, C->getType(), true);
// Only handle simple types.
@@ -443,14 +438,14 @@ bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) {
}
case Instruction::GetElementPtr: {
Address SavedAddr = Addr;
- uint64_t TmpOffset = Addr.getOffset();
+ int64_t TmpOffset = Addr.getOffset();
// Iterate through the GEP folding the constants into offsets where
// we can.
gep_type_iterator GTI = gep_type_begin(U);
for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); i != e;
++i, ++GTI) {
const Value *Op = *i;
- if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
@@ -703,8 +698,8 @@ bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) {
unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass);
emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0);
emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1);
- emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg(
- Mips::FCC0, RegState::ImplicitDefine);
+ emitInst(Opc).addReg(Mips::FCC0, RegState::Define).addReg(LeftReg)
+ .addReg(RightReg);
emitInst(CondMovOpc, ResultReg)
.addReg(RegWithOne)
.addReg(Mips::FCC0)
@@ -761,8 +756,8 @@ bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
if (Addr.isFIBase()) {
unsigned FI = Addr.getFI();
unsigned Align = 4;
- unsigned Offset = Addr.getOffset();
- MachineFrameInfo &MFI = *MF->getFrameInfo();
+ int64_t Offset = Addr.getOffset();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), Align);
@@ -812,8 +807,8 @@ bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr,
if (Addr.isFIBase()) {
unsigned FI = Addr.getFI();
unsigned Align = 4;
- unsigned Offset = Addr.getOffset();
- MachineFrameInfo &MFI = *MF->getFrameInfo();
+ int64_t Offset = Addr.getOffset();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,
MFI.getObjectSize(FI), Align);
@@ -970,9 +965,13 @@ bool MipsFastISel::selectFPExt(const Instruction *I) {
bool MipsFastISel::selectSelect(const Instruction *I) {
assert(isa<SelectInst>(I) && "Expected a select instruction.");
+ DEBUG(dbgs() << "selectSelect\n");
+
MVT VT;
- if (!isTypeSupported(I->getType(), VT))
+ if (!isTypeSupported(I->getType(), VT) || UnsupportedFPMode) {
+ DEBUG(dbgs() << ".. .. gave up (!isTypeSupported || UnsupportedFPMode)\n");
return false;
+ }
unsigned CondMovOpc;
const TargetRegisterClass *RC;
@@ -1249,10 +1248,191 @@ bool MipsFastISel::finishCall(CallLoweringInfo &CLI, MVT RetVT,
return true;
}
-bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {
- if (!TargetSupported)
+bool MipsFastISel::fastLowerArguments() {
+ DEBUG(dbgs() << "fastLowerArguments\n");
+
+ if (!FuncInfo.CanLowerReturn) {
+ DEBUG(dbgs() << ".. gave up (!CanLowerReturn)\n");
return false;
+ }
+
+ const Function *F = FuncInfo.Fn;
+ if (F->isVarArg()) {
+ DEBUG(dbgs() << ".. gave up (varargs)\n");
+ return false;
+ }
+
+ CallingConv::ID CC = F->getCallingConv();
+ if (CC != CallingConv::C) {
+ DEBUG(dbgs() << ".. gave up (calling convention is not C)\n");
+ return false;
+ }
+
+ const ArrayRef<MCPhysReg> GPR32ArgRegs = {Mips::A0, Mips::A1, Mips::A2,
+ Mips::A3};
+ const ArrayRef<MCPhysReg> FGR32ArgRegs = {Mips::F12, Mips::F14};
+ const ArrayRef<MCPhysReg> AFGR64ArgRegs = {Mips::D6, Mips::D7};
+ ArrayRef<MCPhysReg>::iterator NextGPR32 = GPR32ArgRegs.begin();
+ ArrayRef<MCPhysReg>::iterator NextFGR32 = FGR32ArgRegs.begin();
+ ArrayRef<MCPhysReg>::iterator NextAFGR64 = AFGR64ArgRegs.begin();
+
+ struct AllocatedReg {
+ const TargetRegisterClass *RC;
+ unsigned Reg;
+ AllocatedReg(const TargetRegisterClass *RC, unsigned Reg)
+ : RC(RC), Reg(Reg) {}
+ };
+
+ // Only handle simple cases. i.e. All arguments are directly mapped to
+ // registers of the appropriate type.
+ SmallVector<AllocatedReg, 4> Allocation;
+ unsigned Idx = 1;
+ for (const auto &FormalArg : F->args()) {
+ if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
+ F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
+ F->getAttributes().hasAttribute(Idx, Attribute::ByVal)) {
+ DEBUG(dbgs() << ".. gave up (inreg, structret, byval)\n");
+ return false;
+ }
+
+ Type *ArgTy = FormalArg.getType();
+ if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy()) {
+ DEBUG(dbgs() << ".. gave up (struct, array, or vector)\n");
+ return false;
+ }
+
+ EVT ArgVT = TLI.getValueType(DL, ArgTy);
+ DEBUG(dbgs() << ".. " << (Idx - 1) << ": " << ArgVT.getEVTString() << "\n");
+ if (!ArgVT.isSimple()) {
+ DEBUG(dbgs() << ".. .. gave up (not a simple type)\n");
+ return false;
+ }
+
+ switch (ArgVT.getSimpleVT().SimpleTy) {
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ if (!F->getAttributes().hasAttribute(Idx, Attribute::SExt) &&
+ !F->getAttributes().hasAttribute(Idx, Attribute::ZExt)) {
+ // It must be any extend, this shouldn't happen for clang-generated IR
+ // so just fall back on SelectionDAG.
+ DEBUG(dbgs() << ".. .. gave up (i8/i16 arg is not extended)\n");
+ return false;
+ }
+
+ if (NextGPR32 == GPR32ArgRegs.end()) {
+ DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n");
+ return false;
+ }
+
+ DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n");
+ Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++);
+
+ // Allocating any GPR32 prohibits further use of floating point arguments.
+ NextFGR32 = FGR32ArgRegs.end();
+ NextAFGR64 = AFGR64ArgRegs.end();
+ break;
+
+ case MVT::i32:
+ if (F->getAttributes().hasAttribute(Idx, Attribute::ZExt)) {
+ // The O32 ABI does not permit a zero-extended i32.
+ DEBUG(dbgs() << ".. .. gave up (i32 arg is zero extended)\n");
+ return false;
+ }
+ if (NextGPR32 == GPR32ArgRegs.end()) {
+ DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n");
+ return false;
+ }
+
+ DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n");
+ Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++);
+
+ // Allocating any GPR32 prohibits further use of floating point arguments.
+ NextFGR32 = FGR32ArgRegs.end();
+ NextAFGR64 = AFGR64ArgRegs.end();
+ break;
+
+ case MVT::f32:
+ if (UnsupportedFPMode) {
+ DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode)\n");
+ return false;
+ }
+ if (NextFGR32 == FGR32ArgRegs.end()) {
+ DEBUG(dbgs() << ".. .. gave up (ran out of FGR32 arguments)\n");
+ return false;
+ }
+ DEBUG(dbgs() << ".. .. FGR32(" << *NextFGR32 << ")\n");
+ Allocation.emplace_back(&Mips::FGR32RegClass, *NextFGR32++);
+ // Allocating an FGR32 also allocates the super-register AFGR64, and
+ // ABI rules require us to skip the corresponding GPR32.
+ if (NextGPR32 != GPR32ArgRegs.end())
+ NextGPR32++;
+ if (NextAFGR64 != AFGR64ArgRegs.end())
+ NextAFGR64++;
+ break;
+
+ case MVT::f64:
+ if (UnsupportedFPMode) {
+ DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode)\n");
+ return false;
+ }
+ if (NextAFGR64 == AFGR64ArgRegs.end()) {
+ DEBUG(dbgs() << ".. .. gave up (ran out of AFGR64 arguments)\n");
+ return false;
+ }
+ DEBUG(dbgs() << ".. .. AFGR64(" << *NextAFGR64 << ")\n");
+ Allocation.emplace_back(&Mips::AFGR64RegClass, *NextAFGR64++);
+ // Allocating an FGR32 also allocates the super-register AFGR64, and
+ // ABI rules require us to skip the corresponding GPR32 pair.
+ if (NextGPR32 != GPR32ArgRegs.end())
+ NextGPR32++;
+ if (NextGPR32 != GPR32ArgRegs.end())
+ NextGPR32++;
+ if (NextFGR32 != FGR32ArgRegs.end())
+ NextFGR32++;
+ break;
+
+ default:
+ DEBUG(dbgs() << ".. .. gave up (unknown type)\n");
+ return false;
+ }
+
+ ++Idx;
+ }
+
+ Idx = 0;
+ for (const auto &FormalArg : F->args()) {
+ unsigned SrcReg = Allocation[Idx].Reg;
+ unsigned DstReg = FuncInfo.MF->addLiveIn(SrcReg, Allocation[Idx].RC);
+ // FIXME: Unfortunately it's necessary to emit a copy from the livein copy.
+ // Without this, EmitLiveInCopies may eliminate the livein if its only
+ // use is a bitcast (which isn't turned into an instruction).
+ unsigned ResultReg = createResultReg(Allocation[Idx].RC);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), ResultReg)
+ .addReg(DstReg, getKillRegState(true));
+ updateValueMap(&FormalArg, ResultReg);
+ ++Idx;
+ }
+
+ // Calculate the size of the incoming arguments area.
+ // We currently reject all the cases where this would be non-zero.
+ unsigned IncomingArgSizeInBytes = 0;
+
+ // Account for the reserved argument area on ABI's that have one (O32).
+ // It seems strange to do this on the caller side but it's necessary in
+ // SelectionDAG's implementation.
+ IncomingArgSizeInBytes = std::min(getABI().GetCalleeAllocdArgSizeInBytes(CC),
+ IncomingArgSizeInBytes);
+
+ MF->getInfo<MipsFunctionInfo>()->setFormalArgInfo(IncomingArgSizeInBytes,
+ false);
+
+ return true;
+}
+
+bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {
CallingConv::ID CC = CLI.CallConv;
bool IsTailCall = CLI.IsTailCall;
bool IsVarArg = CLI.IsVarArg;
@@ -1337,9 +1517,6 @@ bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {
}
bool MipsFastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
- if (!TargetSupported)
- return false;
-
switch (II->getIntrinsicID()) {
default:
return false;
@@ -1435,6 +1612,8 @@ bool MipsFastISel::selectRet(const Instruction *I) {
const Function &F = *I->getParent()->getParent();
const ReturnInst *Ret = cast<ReturnInst>(I);
+ DEBUG(dbgs() << "selectRet\n");
+
if (!FuncInfo.CanLowerReturn)
return false;
@@ -1495,6 +1674,12 @@ bool MipsFastISel::selectRet(const Instruction *I) {
if (RVVT == MVT::f128)
return false;
+ // Do not handle FGR64 returns for now.
+ if (RVVT == MVT::f64 && UnsupportedFPMode) {
+ DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode\n");
+ return false;
+ }
+
MVT DestVT = VA.getValVT();
// Special handling for extended integers.
if (RVVT != DestVT) {
@@ -1778,8 +1963,6 @@ bool MipsFastISel::selectShift(const Instruction *I) {
}
bool MipsFastISel::fastSelectInstruction(const Instruction *I) {
- if (!TargetSupported)
- return false;
switch (I->getOpcode()) {
default:
break;
diff --git a/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp
index fe6f332..b2cf039 100644
--- a/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp
@@ -92,30 +92,30 @@ const MipsFrameLowering *MipsFrameLowering::create(const MipsSubtarget &ST) {
// if it needs dynamic stack realignment, if frame pointer elimination is
// disabled, or if the frame address is taken.
bool MipsFrameLowering::hasFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *TRI = STI.getRegisterInfo();
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
- MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() ||
+ MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() ||
TRI->needsStackRealignment(MF);
}
bool MipsFrameLowering::hasBP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *TRI = STI.getRegisterInfo();
- return MFI->hasVarSizedObjects() && TRI->needsStackRealignment(MF);
+ return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF);
}
uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
int64_t Offset = 0;
// Iterate over fixed sized objects.
- for (int I = MFI->getObjectIndexBegin(); I != 0; ++I)
- Offset = std::max(Offset, -MFI->getObjectOffset(I));
+ for (int I = MFI.getObjectIndexBegin(); I != 0; ++I)
+ Offset = std::max(Offset, -MFI.getObjectOffset(I));
// Conservatively assume all callee-saved registers will be saved.
for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) {
@@ -123,19 +123,19 @@ uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const {
Offset = alignTo(Offset + Size, Size);
}
- unsigned MaxAlign = MFI->getMaxAlignment();
+ unsigned MaxAlign = MFI.getMaxAlignment();
// Check that MaxAlign is not zero if there is a stack object that is not a
// callee-saved spill.
- assert(!MFI->getObjectIndexEnd() || MaxAlign);
+ assert(!MFI.getObjectIndexEnd() || MaxAlign);
// Iterate over other objects.
- for (unsigned I = 0, E = MFI->getObjectIndexEnd(); I != E; ++I)
- Offset = alignTo(Offset + MFI->getObjectSize(I), MaxAlign);
+ for (unsigned I = 0, E = MFI.getObjectIndexEnd(); I != E; ++I)
+ Offset = alignTo(Offset + MFI.getObjectSize(I), MaxAlign);
// Call frame.
- if (MFI->adjustsStack() && hasReservedCallFrame(MF))
- Offset = alignTo(Offset + MFI->getMaxCallFrameSize(),
+ if (MFI.adjustsStack() && hasReservedCallFrame(MF))
+ Offset = alignTo(Offset + MFI.getMaxCallFrameSize(),
std::max(MaxAlign, getStackAlignment()));
return alignTo(Offset, getStackAlignment());
diff --git a/contrib/llvm/lib/Target/Mips/MipsHazardSchedule.cpp b/contrib/llvm/lib/Target/Mips/MipsHazardSchedule.cpp
index 10022ba..31b8612 100644
--- a/contrib/llvm/lib/Target/Mips/MipsHazardSchedule.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsHazardSchedule.cpp
@@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
/// \file
-/// This pass is used to workaround certain pipeline hazards. For now, this covers
-/// compact branch hazards. In future this pass can be extended to other pipeline
-/// hazards, such as various MIPS1 hazards, processor errata that require
-/// instruction reorganization, etc.
+/// This pass is used to workaround certain pipeline hazards. For now, this
+/// covers compact branch hazards. In future this pass can be extended to other
+/// pipeline hazards, such as various MIPS1 hazards, processor errata that
+/// require instruction reorganization, etc.
///
/// This pass has to run after the delay slot filler as that pass can introduce
/// pipeline hazards, hence the existing hazard recognizer is not suitable.
@@ -18,8 +18,8 @@
/// Hazards handled: forbidden slots for MIPSR6.
///
/// A forbidden slot hazard occurs when a compact branch instruction is executed
-/// and the adjacent instruction in memory is a control transfer instruction such
-/// as a branch or jump, ERET, ERETNC, DERET, WAIT and PAUSE.
+/// and the adjacent instruction in memory is a control transfer instruction
+/// such as a branch or jump, ERET, ERETNC, DERET, WAIT and PAUSE.
///
/// For example:
///
@@ -70,13 +70,13 @@ class MipsHazardSchedule : public MachineFunctionPass {
public:
MipsHazardSchedule() : MachineFunctionPass(ID) {}
- const char *getPassName() const override { return "Mips Hazard Schedule"; }
+ StringRef getPassName() const override { return "Mips Hazard Schedule"; }
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -91,20 +91,43 @@ FunctionPass *llvm::createMipsHazardSchedule() {
return new MipsHazardSchedule();
}
-// Find the next real instruction from the current position.
-static Iter getNextMachineInstr(Iter Position) {
+// Find the next real instruction from the current position in current basic
+// block.
+static Iter getNextMachineInstrInBB(Iter Position) {
Iter I = Position, E = Position->getParent()->end();
- I = std::find_if_not(I, E, [](const Iter &Insn) { return Insn->isTransient(); });
- assert(I != E);
+ I = std::find_if_not(I, E,
+ [](const Iter &Insn) { return Insn->isTransient(); });
+
return I;
}
+// Find the next real instruction from the current position, looking through
+// basic block boundaries.
+static Iter getNextMachineInstr(Iter Position, MachineBasicBlock *Parent) {
+ if (Position == Parent->end()) {
+ MachineBasicBlock *Succ = Parent->getNextNode();
+ if (Succ != nullptr && Parent->isSuccessor(Succ)) {
+ Position = Succ->begin();
+ Parent = Succ;
+ } else {
+ llvm_unreachable(
+ "Should have identified the end of the function earlier!");
+ }
+ }
+
+ Iter Instr = getNextMachineInstrInBB(Position);
+ if (Instr == Parent->end()) {
+ return getNextMachineInstr(Instr, Parent);
+ }
+ return Instr;
+}
+
bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
const MipsSubtarget *STI =
&static_cast<const MipsSubtarget &>(MF.getSubtarget());
- // Forbidden slot hazards are only defined for MIPSR6.
+ // Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
if (!STI->hasMips32r6() || STI->inMicroMipsMode())
return false;
@@ -118,27 +141,17 @@ bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
if (!TII->HasForbiddenSlot(*I))
continue;
- bool InsertNop = false;
- // Next instruction in the basic block.
- if (std::next(I) != FI->end() &&
- !TII->SafeInForbiddenSlot(*getNextMachineInstr(std::next(I)))) {
- InsertNop = true;
- } else {
- // Next instruction in the physical successor basic block.
- for (auto *Succ : FI->successors()) {
- if (FI->isLayoutSuccessor(Succ) &&
- getNextMachineInstr(Succ->begin()) != Succ->end() &&
- !TII->SafeInForbiddenSlot(*getNextMachineInstr(Succ->begin()))) {
- InsertNop = true;
- break;
- }
- }
+ Iter Inst;
+ bool LastInstInFunction =
+ std::next(I) == FI->end() && std::next(FI) == MF.end();
+ if (!LastInstInFunction) {
+ Inst = getNextMachineInstr(std::next(I), &*FI);
}
- if (InsertNop) {
+ if (LastInstInFunction || !TII->SafeInForbiddenSlot(*Inst)) {
Changed = true;
- MIBundleBuilder(&*I).append(
- BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
+ MIBundleBuilder(&*I)
+ .append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
NumInsertedNops++;
}
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
index 83763a6..0e1173f 100644
--- a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -108,8 +108,26 @@ bool MipsDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base,
return false;
}
-bool MipsDAGToDAGISel::selectIntAddrMSA(SDValue Addr, SDValue &Base,
- SDValue &Offset) const {
+bool MipsDAGToDAGISel::selectIntAddrSImm10(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+ llvm_unreachable("Unimplemented function.");
+ return false;
+}
+
+bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl1(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+ llvm_unreachable("Unimplemented function.");
+ return false;
+}
+
+bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl2(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+ llvm_unreachable("Unimplemented function.");
+ return false;
+}
+
+bool MipsDAGToDAGISel::selectIntAddrSImm10Lsl3(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
llvm_unreachable("Unimplemented function.");
return false;
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h
index 289832a..20bdd4a 100644
--- a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h
+++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h
@@ -35,7 +35,7 @@ public:
: SelectionDAGISel(TM, OL), Subtarget(nullptr) {}
// Pass Name
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "MIPS DAG->DAG Pattern Instruction Selection";
}
@@ -78,8 +78,17 @@ private:
SDValue &Offset) const;
/// Match addr+simm10 and addr
- virtual bool selectIntAddrMSA(SDValue Addr, SDValue &Base,
- SDValue &Offset) const;
+ virtual bool selectIntAddrSImm10(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const;
+
+ virtual bool selectIntAddrSImm10Lsl1(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const;
+
+ virtual bool selectIntAddrSImm10Lsl2(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const;
+
+ virtual bool selectIntAddrSImm10Lsl3(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const;
virtual bool selectAddr16(SDValue Addr, SDValue &Base, SDValue &Offset);
virtual bool selectAddr16SP(SDValue Addr, SDValue &Base, SDValue &Offset);
diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp
index d63a62a..9c511bd 100644
--- a/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -268,7 +268,7 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32);
// Mips Custom Operations
- setOperationAction(ISD::BR_JT, MVT::Other, Custom);
+ setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::BlockAddress, MVT::i32, Custom);
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
@@ -426,6 +426,13 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
setTargetDAGCombine(ISD::ADD);
setTargetDAGCombine(ISD::AssertZext);
+ if (ABI.IsO32()) {
+ // These libcalls are not available in 32-bit.
+ setLibcallName(RTLIB::SHL_I128, nullptr);
+ setLibcallName(RTLIB::SRL_I128, nullptr);
+ setLibcallName(RTLIB::SRA_I128, nullptr);
+ }
+
setMinFunctionAlignment(Subtarget.isGP64bit() ? 3 : 2);
// The arguments on the stack are defined in terms of 4-byte slots on O32
@@ -451,9 +458,19 @@ const MipsTargetLowering *MipsTargetLowering::create(const MipsTargetMachine &TM
FastISel *
MipsTargetLowering::createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo) const {
- if (!funcInfo.MF->getTarget().Options.EnableFastISel)
- return TargetLowering::createFastISel(funcInfo, libInfo);
- return Mips::createFastISel(funcInfo, libInfo);
+ const MipsTargetMachine &TM =
+ static_cast<const MipsTargetMachine &>(funcInfo.MF->getTarget());
+
+ // We support only the standard encoding [MIPS32,MIPS32R5] ISAs.
+ bool UseFastISel = TM.Options.EnableFastISel && Subtarget.hasMips32() &&
+ !Subtarget.hasMips32r6() && !Subtarget.inMips16Mode() &&
+ !Subtarget.inMicroMipsMode();
+
+ // Disable if we don't generate PIC or the ABI isn't O32.
+ if (!TM.isPositionIndependent() || !TM.getABI().IsO32())
+ UseFastISel = false;
+
+ return UseFastISel ? Mips::createFastISel(funcInfo, libInfo) : nullptr;
}
EVT MipsTargetLowering::getSetCCResultType(const DataLayout &, LLVMContext &,
@@ -893,7 +910,6 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
{
switch (Op.getOpcode())
{
- case ISD::BR_JT: return lowerBR_JT(Op, DAG);
case ISD::BRCOND: return lowerBRCOND(Op, DAG);
case ISD::ConstantPool: return lowerConstantPool(Op, DAG);
case ISD::GlobalAddress: return lowerGlobalAddress(Op, DAG);
@@ -1659,40 +1675,6 @@ MachineBasicBlock *MipsTargetLowering::emitSEL_D(MachineInstr &MI,
return BB;
}
-//===----------------------------------------------------------------------===//
-// Misc Lower Operation implementation
-//===----------------------------------------------------------------------===//
-SDValue MipsTargetLowering::lowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
- SDValue Chain = Op.getOperand(0);
- SDValue Table = Op.getOperand(1);
- SDValue Index = Op.getOperand(2);
- SDLoc DL(Op);
- auto &TD = DAG.getDataLayout();
- EVT PTy = getPointerTy(TD);
- unsigned EntrySize =
- DAG.getMachineFunction().getJumpTableInfo()->getEntrySize(TD);
-
- Index = DAG.getNode(ISD::MUL, DL, PTy, Index,
- DAG.getConstant(EntrySize, DL, PTy));
- SDValue Addr = DAG.getNode(ISD::ADD, DL, PTy, Index, Table);
-
- EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8);
- Addr = DAG.getExtLoad(
- ISD::SEXTLOAD, DL, PTy, Chain, Addr,
- MachinePointerInfo::getJumpTable(DAG.getMachineFunction()), MemVT);
- Chain = Addr.getValue(1);
-
- if (isPositionIndependent() || ABI.IsN64()) {
- // For PIC, the sequence is:
- // BRIND(load(Jumptable + index) + RelocBase)
- // RelocBase can be JumpTable, GOT or some sort of global base.
- Addr = DAG.getNode(ISD::ADD, DL, PTy, Addr,
- getPICJumpTableRelocBase(Table, DAG));
- }
-
- return DAG.getNode(ISD::BRIND, DL, MVT::Other, Chain, Addr);
-}
-
SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
// The first operand is the chain, the second is the condition, the third is
// the block to branch to if the condition is true.
@@ -1755,7 +1737,8 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op,
const MipsTargetObjectFile *TLOF =
static_cast<const MipsTargetObjectFile *>(
getTargetMachine().getObjFileLowering());
- if (TLOF->IsGlobalInSmallSection(GV, getTargetMachine()))
+ const GlobalObject *GO = GV->getBaseObject();
+ if (GO && TLOF->IsGlobalInSmallSection(GO, getTargetMachine()))
// %gp_rel relocation
return getAddrGPRel(N, SDLoc(N), Ty, DAG);
@@ -2099,8 +2082,8 @@ lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
assert((cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0) &&
"Frame address can only be determined for current frame.");
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc DL(Op);
SDValue FrameAddr = DAG.getCopyFromReg(
@@ -2118,10 +2101,10 @@ SDValue MipsTargetLowering::lowerRETURNADDR(SDValue Op,
"Return address can be determined only for current frame.");
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MVT VT = Op.getSimpleValueType();
unsigned RA = ABI.IsN64() ? Mips::RA_64 : Mips::RA;
- MFI->setReturnAddressIsTaken(true);
+ MFI.setReturnAddressIsTaken(true);
// Return RA, which contains the return address. Mark it an implicit live-in.
unsigned Reg = MF.addLiveIn(RA, getRegClassFor(VT));
@@ -2398,9 +2381,9 @@ SDValue MipsTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
// Return a fixed StackObject with offset 0 which points to the old stack
// pointer.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
EVT ValTy = Op->getValueType(0);
- int FI = MFI->CreateFixedObject(Op.getValueSizeInBits() / 8, 0, false);
+ int FI = MFI.CreateFixedObject(Op.getValueSizeInBits() / 8, 0, false);
return DAG.getFrameIndex(FI, ValTy);
}
@@ -2563,8 +2546,8 @@ SDValue MipsTargetLowering::passArgOnStack(SDValue StackPtr, unsigned Offset,
return DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo());
}
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- int FI = MFI->CreateFixedObject(Arg.getValueSizeInBits() / 8, Offset, false);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ int FI = MFI.CreateFixedObject(Arg.getValueSizeInBits() / 8, Offset, false);
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
return DAG.getStore(Chain, DL, Arg, FIN, MachinePointerInfo(),
/* Alignment = */ 0, MachineMemOperand::MOVolatile);
@@ -2647,7 +2630,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
bool IsVarArg = CLI.IsVarArg;
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetFrameLowering *TFL = Subtarget.getFrameLowering();
MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>();
bool IsPIC = isPositionIndependent();
@@ -2667,11 +2650,20 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Get a count of how many bytes are to be pushed on the stack.
unsigned NextStackOffset = CCInfo.getNextStackOffset();
- // Check if it's really possible to do a tail call.
- if (IsTailCall)
+ // Check if it's really possible to do a tail call. Restrict it to functions
+ // that are part of this compilation unit.
+ bool InternalLinkage = false;
+ if (IsTailCall) {
IsTailCall = isEligibleForTailCallOptimization(
CCInfo, NextStackOffset, *MF.getInfo<MipsFunctionInfo>());
-
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ InternalLinkage = G->getGlobal()->hasInternalLinkage();
+ IsTailCall &= (InternalLinkage || G->getGlobal()->hasLocalLinkage() ||
+ G->getGlobal()->hasPrivateLinkage() ||
+ G->getGlobal()->hasHiddenVisibility() ||
+ G->getGlobal()->hasProtectedVisibility());
+ }
+ }
if (!IsTailCall && CLI.CS && CLI.CS->isMustTailCall())
report_fatal_error("failed to perform tail call elimination on a call "
"site marked musttail");
@@ -2754,19 +2746,19 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
break;
case CCValAssign::SExtUpper:
UseUpperBits = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, LocVT, Arg);
break;
case CCValAssign::ZExtUpper:
UseUpperBits = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, LocVT, Arg);
break;
case CCValAssign::AExtUpper:
UseUpperBits = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, LocVT, Arg);
break;
@@ -2806,9 +2798,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// node so that legalize doesn't hack it.
bool IsPICCall = (ABI.IsN64() || IsPIC); // true if calls are translated to
// jalr $25
- bool GlobalOrExternal = false, InternalLinkage = false, IsCallReloc = false;
SDValue CalleeLo;
EVT Ty = Callee.getValueType();
+ bool GlobalOrExternal = false, IsCallReloc = false;
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
if (IsPICCall) {
@@ -2859,8 +2851,10 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, InternalLinkage,
IsCallReloc, CLI, Callee, Chain);
- if (IsTailCall)
+ if (IsTailCall) {
+ MF.getFrameInfo().setHasTailCall();
return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, Ops);
+ }
Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, Ops);
SDValue InFlag = Chain.getValue(1);
@@ -3006,7 +3000,7 @@ SDValue MipsTargetLowering::LowerFormalArguments(
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
MipsFI->setVarArgsFrameIndex(0);
@@ -3105,8 +3099,8 @@ SDValue MipsTargetLowering::LowerFormalArguments(
assert(VA.isMemLoc());
// The stack pointer offset is relative to the caller stack frame.
- int FI = MFI->CreateFixedObject(LocVT.getSizeInBits() / 8,
- VA.getLocMemOffset(), true);
+ int FI = MFI.CreateFixedObject(LocVT.getSizeInBits() / 8,
+ VA.getLocMemOffset(), true);
// Create load nodes to retrieve arguments from the stack
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
@@ -3224,19 +3218,19 @@ MipsTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
break;
case CCValAssign::AExtUpper:
UseUpperBits = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CCValAssign::AExt:
Val = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Val);
break;
case CCValAssign::ZExtUpper:
UseUpperBits = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CCValAssign::ZExt:
Val = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Val);
break;
case CCValAssign::SExtUpper:
UseUpperBits = true;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CCValAssign::SExt:
Val = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Val);
break;
@@ -3706,7 +3700,7 @@ void MipsTargetLowering::copyByValRegs(
unsigned FirstReg, unsigned LastReg, const CCValAssign &VA,
MipsCCState &State) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned GPRSizeInBytes = Subtarget.getGPRSizeInBytes();
unsigned NumRegs = LastReg - FirstReg;
unsigned RegAreaSize = NumRegs * GPRSizeInBytes;
@@ -3723,7 +3717,7 @@ void MipsTargetLowering::copyByValRegs(
// Create frame object.
EVT PtrTy = getPointerTy(DAG.getDataLayout());
- int FI = MFI->CreateFixedObject(FrameObjSize, FrameObjOffset, true);
+ int FI = MFI.CreateFixedObject(FrameObjSize, FrameObjOffset, true);
SDValue FIN = DAG.getFrameIndex(FI, PtrTy);
InVals.push_back(FIN);
@@ -3751,7 +3745,7 @@ void MipsTargetLowering::passByValArg(
SDValue Chain, const SDLoc &DL,
std::deque<std::pair<unsigned, SDValue>> &RegsToPass,
SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr,
- MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, unsigned FirstReg,
+ MachineFrameInfo &MFI, SelectionDAG &DAG, SDValue Arg, unsigned FirstReg,
unsigned LastReg, const ISD::ArgFlagsTy &Flags, bool isLittle,
const CCValAssign &VA) const {
unsigned ByValSizeInBytes = Flags.getByValSize();
@@ -3853,7 +3847,7 @@ void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains,
MVT RegTy = MVT::getIntegerVT(RegSizeInBytes * 8);
const TargetRegisterClass *RC = getRegClassFor(RegTy);
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
// Offset of the first variable argument from stack pointer.
@@ -3869,7 +3863,7 @@ void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains,
// Record the frame index of the first variable argument
// which is a value necessary to VASTART.
- int FI = MFI->CreateFixedObject(RegSizeInBytes, VaArgOffset, true);
+ int FI = MFI.CreateFixedObject(RegSizeInBytes, VaArgOffset, true);
MipsFI->setVarArgsFrameIndex(FI);
// Copy the integer registers that have not been used for argument passing
@@ -3880,7 +3874,7 @@ void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains,
++I, VaArgOffset += RegSizeInBytes) {
unsigned Reg = addLiveIn(MF, ArgRegs[I], RC);
SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy);
- FI = MFI->CreateFixedObject(RegSizeInBytes, VaArgOffset, true);
+ FI = MFI.CreateFixedObject(RegSizeInBytes, VaArgOffset, true);
SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
SDValue Store =
DAG.getStore(Chain, DL, ArgValue, PtrOff, MachinePointerInfo());
diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h
index 2ded118..cddf090 100644
--- a/contrib/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -296,6 +296,10 @@ namespace llvm {
return SrcAS < 256 && DestAS < 256;
}
+ bool isJumpTableRelative() const override {
+ return getTargetMachine().isPositionIndependent() || ABI.IsN64();
+ }
+
protected:
SDValue getGlobalReg(SelectionDAG &DAG, EVT Ty) const;
@@ -426,7 +430,6 @@ namespace llvm {
TargetLowering::CallLoweringInfo &CLI) const;
// Lower Operand specifics
- SDValue lowerBR_JT(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerBRCOND(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
@@ -471,7 +474,7 @@ namespace llvm {
void passByValArg(SDValue Chain, const SDLoc &DL,
std::deque<std::pair<unsigned, SDValue>> &RegsToPass,
SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr,
- MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg,
+ MachineFrameInfo &MFI, SelectionDAG &DAG, SDValue Arg,
unsigned FirstReg, unsigned LastReg,
const ISD::ArgFlagsTy &Flags, bool isLittle,
const CCValAssign &VA) const;
diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td
index 87b02bd..df42d56 100644
--- a/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td
+++ b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td
@@ -219,6 +219,7 @@ class BC1F_FT<string opstr, DAGOperand opnd, InstrItinClass Itin,
let isTerminator = 1;
let hasDelaySlot = DelaySlot;
let Defs = [AT];
+ let hasFCCRegOperand = 1;
}
class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin,
@@ -229,41 +230,106 @@ class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin,
!strconcat("c.$cond.", typestr)>, HARDFLOAT {
let Defs = [FCC0];
let isCodeGenOnly = 1;
+ let hasFCCRegOperand = 1;
}
+
+// Note: MIPS-IV introduced $fcc1-$fcc7 and renamed FCSR31[23] $fcc0. Rather
+// duplicating the instruction definition for MIPS1 - MIPS3, we expand
+// c.cond.ft if necessary, and reject it after constructing the
+// instruction if the ISA doesn't support it.
class C_COND_FT<string CondStr, string Typestr, RegisterOperand RC,
InstrItinClass itin> :
- InstSE<(outs), (ins RC:$fs, RC:$ft),
- !strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], itin,
- FrmFR>, HARDFLOAT;
+ InstSE<(outs FCCRegsOpnd:$fcc), (ins RC:$fs, RC:$ft),
+ !strconcat("c.", CondStr, ".", Typestr, "\t$fcc, $fs, $ft"), [], itin,
+ FrmFR>, HARDFLOAT {
+ let isCompare = 1;
+ let hasFCCRegOperand = 1;
+}
+
multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt,
InstrItinClass itin> {
- def C_F_#NAME : C_COND_FT<"f", TypeStr, RC, itin>, C_COND_FM<fmt, 0>;
- def C_UN_#NAME : C_COND_FT<"un", TypeStr, RC, itin>, C_COND_FM<fmt, 1>;
- def C_EQ_#NAME : C_COND_FT<"eq", TypeStr, RC, itin>, C_COND_FM<fmt, 2>;
- def C_UEQ_#NAME : C_COND_FT<"ueq", TypeStr, RC, itin>, C_COND_FM<fmt, 3>;
- def C_OLT_#NAME : C_COND_FT<"olt", TypeStr, RC, itin>, C_COND_FM<fmt, 4>;
- def C_ULT_#NAME : C_COND_FT<"ult", TypeStr, RC, itin>, C_COND_FM<fmt, 5>;
- def C_OLE_#NAME : C_COND_FT<"ole", TypeStr, RC, itin>, C_COND_FM<fmt, 6>;
- def C_ULE_#NAME : C_COND_FT<"ule", TypeStr, RC, itin>, C_COND_FM<fmt, 7>;
- def C_SF_#NAME : C_COND_FT<"sf", TypeStr, RC, itin>, C_COND_FM<fmt, 8>;
- def C_NGLE_#NAME : C_COND_FT<"ngle", TypeStr, RC, itin>, C_COND_FM<fmt, 9>;
- def C_SEQ_#NAME : C_COND_FT<"seq", TypeStr, RC, itin>, C_COND_FM<fmt, 10>;
- def C_NGL_#NAME : C_COND_FT<"ngl", TypeStr, RC, itin>, C_COND_FM<fmt, 11>;
- def C_LT_#NAME : C_COND_FT<"lt", TypeStr, RC, itin>, C_COND_FM<fmt, 12>;
- def C_NGE_#NAME : C_COND_FT<"nge", TypeStr, RC, itin>, C_COND_FM<fmt, 13>;
- def C_LE_#NAME : C_COND_FT<"le", TypeStr, RC, itin>, C_COND_FM<fmt, 14>;
- def C_NGT_#NAME : C_COND_FT<"ngt", TypeStr, RC, itin>, C_COND_FM<fmt, 15>;
+ def C_F_#NAME : MMRel, C_COND_FT<"f", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 0> {
+ let BaseOpcode = "c.f."#NAME;
+ let isCommutable = 1;
+ }
+ def C_UN_#NAME : MMRel, C_COND_FT<"un", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 1> {
+ let BaseOpcode = "c.un."#NAME;
+ let isCommutable = 1;
+ }
+ def C_EQ_#NAME : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 2> {
+ let BaseOpcode = "c.eq."#NAME;
+ let isCommutable = 1;
+ }
+ def C_UEQ_#NAME : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 3> {
+ let BaseOpcode = "c.ueq."#NAME;
+ let isCommutable = 1;
+ }
+ def C_OLT_#NAME : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 4> {
+ let BaseOpcode = "c.olt."#NAME;
+ }
+ def C_ULT_#NAME : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 5> {
+ let BaseOpcode = "c.ult."#NAME;
+ }
+ def C_OLE_#NAME : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 6> {
+ let BaseOpcode = "c.ole."#NAME;
+ }
+ def C_ULE_#NAME : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 7> {
+ let BaseOpcode = "c.ule."#NAME;
+ }
+ def C_SF_#NAME : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 8> {
+ let BaseOpcode = "c.sf."#NAME;
+ let isCommutable = 1;
+ }
+ def C_NGLE_#NAME : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 9> {
+ let BaseOpcode = "c.ngle."#NAME;
+ }
+ def C_SEQ_#NAME : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 10> {
+ let BaseOpcode = "c.seq."#NAME;
+ let isCommutable = 1;
+ }
+ def C_NGL_#NAME : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 11> {
+ let BaseOpcode = "c.ngl."#NAME;
+ }
+ def C_LT_#NAME : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 12> {
+ let BaseOpcode = "c.lt."#NAME;
+ }
+ def C_NGE_#NAME : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 13> {
+ let BaseOpcode = "c.nge."#NAME;
+ }
+ def C_LE_#NAME : MMRel, C_COND_FT<"le", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 14> {
+ let BaseOpcode = "c.le."#NAME;
+ }
+ def C_NGT_#NAME : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>,
+ C_COND_FM<fmt, 15> {
+ let BaseOpcode = "c.ngt."#NAME;
+ }
}
+let AdditionalPredicates = [NotInMicroMips] in {
defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>, ISA_MIPS1_NOT_32R6_64R6;
defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
FGR_32;
let DecoderNamespace = "Mips64" in
defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6,
FGR_64;
-
+}
//===----------------------------------------------------------------------===//
// Floating Point Instructions
//===----------------------------------------------------------------------===//
@@ -284,6 +350,16 @@ defm CEIL_W : ROUND_M<"ceil.w.d", II_CEIL>, ABSS_FM<0xe, 17>, ISA_MIPS2;
defm FLOOR_W : ROUND_M<"floor.w.d", II_FLOOR>, ABSS_FM<0xf, 17>, ISA_MIPS2;
defm CVT_W : ROUND_M<"cvt.w.d", II_CVT>, ABSS_FM<0x24, 17>;
+let AdditionalPredicates = [NotInMicroMips] in {
+ def RECIP_S : MMRel, ABSS_FT<"recip.s", FGR32Opnd, FGR32Opnd, II_RECIP_S>,
+ ABSS_FM<0b010101, 0x10>, INSN_MIPS4_32R2;
+ def RECIP_D : MMRel, ABSS_FT<"recip.d", FGR64Opnd, FGR64Opnd, II_RECIP_D>,
+ ABSS_FM<0b010101, 0x11>, INSN_MIPS4_32R2;
+ def RSQRT_S : MMRel, ABSS_FT<"rsqrt.s", FGR32Opnd, FGR32Opnd, II_RSQRT_S>,
+ ABSS_FM<0b010110, 0x10>, INSN_MIPS4_32R2;
+ def RSQRT_D : MMRel, ABSS_FT<"rsqrt.d", FGR64Opnd, FGR64Opnd, II_RSQRT_D>,
+ ABSS_FM<0b010110, 0x11>, INSN_MIPS4_32R2;
+}
let DecoderNamespace = "Mips64" in {
let AdditionalPredicates = [NotInMicroMips] in {
def ROUND_L_S : ABSS_FT<"round.l.s", FGR64Opnd, FGR32Opnd, II_ROUND>,
@@ -361,8 +437,10 @@ defm FSQRT : ABSS_M<"sqrt.d", II_SQRT_D, fsqrt>, ABSS_FM<0x4, 17>, ISA_MIPS2;
// regardless of register aliasing.
/// Move Control Registers From/To CPU Registers
-def CFC1 : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM<2>;
-def CTC1 : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM<6>;
+let AdditionalPredicates = [NotInMicroMips] in {
+ def CFC1 : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM<2>;
+ def CTC1 : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM<6>;
+}
def MFC1 : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, II_MFC1,
bitconvert>, MFC1_FM<0>;
def MTC1 : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1,
@@ -537,13 +615,29 @@ def BC1TL : MMRel, BC1F_FT<"bc1tl", brtarget, II_BC1TL, MIPS_BRANCH_T, 0>,
/// Floating Point Compare
let AdditionalPredicates = [NotInMicroMips] in {
def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>,
- ISA_MIPS1_NOT_32R6_64R6;
+ ISA_MIPS1_NOT_32R6_64R6 {
+
+ // FIXME: This is a required to work around the fact that these instructions
+ // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
+ // fcc register set is used directly.
+ bits<3> fcc = 0;
+ }
def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>,
- ISA_MIPS1_NOT_32R6_64R6, FGR_32;
+ ISA_MIPS1_NOT_32R6_64R6, FGR_32 {
+ // FIXME: This is a required to work around the fact that these instructions
+ // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
+ // fcc register set is used directly.
+ bits<3> fcc = 0;
+ }
}
let DecoderNamespace = "Mips64" in
def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>,
- ISA_MIPS1_NOT_32R6_64R6, FGR_64;
+ ISA_MIPS1_NOT_32R6_64R6, FGR_64 {
+ // FIXME: This is a required to work around the fact that thiese instructions
+ // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the
+ // fcc register set is used directly.
+ bits<3> fcc = 0;
+}
//===----------------------------------------------------------------------===//
// Floating Point Pseudo-Instructions
@@ -590,15 +684,99 @@ def PseudoTRUNC_W_D : MipsAsmPseudoInst<(outs FGR32Opnd:$fd),
//===----------------------------------------------------------------------===//
// InstAliases.
//===----------------------------------------------------------------------===//
-def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>,
- ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT;
-def : MipsInstAlias<"bc1tl $offset", (BC1TL FCC0, brtarget:$offset)>,
- ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT;
-def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>,
- ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT;
-def : MipsInstAlias<"bc1fl $offset", (BC1FL FCC0, brtarget:$offset)>,
- ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT;
+def : MipsInstAlias
+ <"s.s $fd, $addr", (SWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>,
+ ISA_MIPS2, HARDFLOAT;
+def : MipsInstAlias
+ <"s.d $fd, $addr", (SDC1 AFGR64Opnd:$fd, mem_simm16:$addr), 0>,
+ FGR_32, ISA_MIPS2, HARDFLOAT;
+def : MipsInstAlias
+ <"s.d $fd, $addr", (SDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>,
+ FGR_64, ISA_MIPS2, HARDFLOAT;
+
+def : MipsInstAlias
+ <"l.s $fd, $addr", (LWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>,
+ ISA_MIPS2, HARDFLOAT;
+def : MipsInstAlias
+ <"l.d $fd, $addr", (LDC1 AFGR64Opnd:$fd, mem_simm16:$addr), 0>,
+ FGR_32, ISA_MIPS2, HARDFLOAT;
+def : MipsInstAlias
+ <"l.d $fd, $addr", (LDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>,
+ FGR_64, ISA_MIPS2, HARDFLOAT;
+
+multiclass C_COND_ALIASES<string TypeStr, RegisterOperand RC> {
+ def : MipsInstAlias<!strconcat("c.f.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_F_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.un.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_UN_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.eq.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_EQ_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ueq.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_UEQ_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.olt.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_OLT_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ult.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_ULT_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ole.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_OLE_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ule.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_ULE_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.sf.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_SF_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ngle.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_NGLE_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.seq.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_SEQ_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ngl.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_NGL_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.lt.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_LT_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.nge.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_NGE_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.le.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_LE_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+ def : MipsInstAlias<!strconcat("c.ngt.", TypeStr, " $fs, $ft"),
+ (!cast<Instruction>("C_NGT_"#NAME) FCC0,
+ RC:$fs, RC:$ft), 1>;
+}
+
+multiclass BC1_ALIASES<Instruction BCTrue, string BCTrueString,
+ Instruction BCFalse, string BCFalseString> {
+ def : MipsInstAlias<!strconcat(BCTrueString, " $offset"),
+ (BCTrue FCC0, brtarget:$offset), 1>;
+
+ def : MipsInstAlias<!strconcat(BCFalseString, " $offset"),
+ (BCFalse FCC0, brtarget:$offset), 1>;
+}
+let AdditionalPredicates = [NotInMicroMips] in {
+ defm S : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT,
+ ISA_MIPS1_NOT_32R6_64R6;
+ defm D32 : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT,
+ ISA_MIPS1_NOT_32R6_64R6, FGR_32;
+ defm D64 : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT,
+ ISA_MIPS1_NOT_32R6_64R6, FGR_64;
+
+ defm : BC1_ALIASES<BC1T, "bc1t", BC1F, "bc1f">, ISA_MIPS1_NOT_32R6_64R6,
+ HARDFLOAT;
+ defm : BC1_ALIASES<BC1TL, "bc1tl", BC1FL, "bc1fl">, ISA_MIPS2_NOT_32R6_64R6,
+ HARDFLOAT;
+}
//===----------------------------------------------------------------------===//
// Floating Point Patterns
//===----------------------------------------------------------------------===//
@@ -614,9 +792,9 @@ def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)),
(PseudoCVT_D32_W GPR32Opnd:$src)>, FGR_32;
def : MipsPat<(MipsTruncIntFP AFGR64Opnd:$src),
(TRUNC_W_D32 AFGR64Opnd:$src)>, FGR_32;
-def : MipsPat<(f32 (fround AFGR64Opnd:$src)),
+def : MipsPat<(f32 (fpround AFGR64Opnd:$src)),
(CVT_S_D32 AFGR64Opnd:$src)>, FGR_32;
-def : MipsPat<(f64 (fextend FGR32Opnd:$src)),
+def : MipsPat<(f64 (fpextend FGR32Opnd:$src)),
(CVT_D32_S FGR32Opnd:$src)>, FGR_32;
def : MipsPat<(f64 fpimm0), (DMTC1 ZERO_64)>, FGR_64;
@@ -636,9 +814,9 @@ def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src),
def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src),
(TRUNC_L_D64 FGR64Opnd:$src)>, FGR_64;
-def : MipsPat<(f32 (fround FGR64Opnd:$src)),
+def : MipsPat<(f32 (fpround FGR64Opnd:$src)),
(CVT_S_D64 FGR64Opnd:$src)>, FGR_64;
-def : MipsPat<(f64 (fextend FGR32Opnd:$src)),
+def : MipsPat<(f64 (fpextend FGR32Opnd:$src)),
(CVT_D64_S FGR32Opnd:$src)>, FGR_64;
// Patterns for loads/stores with a reg+imm operand.
diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td
index 0bbb49b..817d9b4 100644
--- a/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td
+++ b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td
@@ -98,11 +98,18 @@ class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern,
bit isCTI = 0; // Any form of Control Transfer Instruction.
// Required for MIPSR6
bit hasForbiddenSlot = 0; // Instruction has a forbidden slot.
+ bit IsPCRelativeLoad = 0; // Load instruction with implicit source register
+ // ($pc) and with explicit offset and destination
+ // register
+ bit hasFCCRegOperand = 0; // Instruction uses $fcc<X> register and is
+ // present in MIPS-I to MIPS-III.
- // TSFlags layout should be kept in sync with MipsInstrInfo.h.
+ // TSFlags layout should be kept in sync with MCTargetDesc/MipsBaseInfo.h.
let TSFlags{3-0} = FormBits;
let TSFlags{4} = isCTI;
let TSFlags{5} = hasForbiddenSlot;
+ let TSFlags{6} = IsPCRelativeLoad;
+ let TSFlags{7} = hasFCCRegOperand;
let DecoderNamespace = "Mips";
@@ -825,6 +832,7 @@ class BC1F_FM<bit nd, bit tf> : StdArch {
class CEQS_FM<bits<5> fmt> : StdArch {
bits<5> fs;
bits<5> ft;
+ bits<3> fcc;
bits<4> cond;
bits<32> Inst;
@@ -833,7 +841,7 @@ class CEQS_FM<bits<5> fmt> : StdArch {
let Inst{25-21} = fmt;
let Inst{20-16} = ft;
let Inst{15-11} = fs;
- let Inst{10-8} = 0; // cc
+ let Inst{10-8} = fcc;
let Inst{7-4} = 0x3;
let Inst{3-0} = cond;
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp
index 800d834..19af191 100644
--- a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp
@@ -58,7 +58,7 @@ MachineMemOperand *
MipsInstrInfo::GetMemOperand(MachineBasicBlock &MBB, int FI,
MachineMemOperand::Flags Flags) const {
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FI);
return MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI),
@@ -113,13 +113,15 @@ void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MIB.addMBB(TBB);
}
-unsigned MipsInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned MipsInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
+ assert(!BytesAdded && "code size not handled");
// # of condition operands:
// Unconditional branches: 0
@@ -145,16 +147,21 @@ unsigned MipsInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return 1;
}
-unsigned MipsInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned MipsInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::reverse_iterator I = MBB.rbegin(), REnd = MBB.rend();
- MachineBasicBlock::reverse_iterator FirstBr;
unsigned removed;
// Skip all the debug instructions.
while (I != REnd && I->isDebugValue())
++I;
- FirstBr = I;
+ if (I == REnd)
+ return 0;
+
+ MachineBasicBlock::iterator FirstBr = ++I.getReverse();
// Up to 2 branches are removed.
// Note that indirect branches are not removed.
@@ -162,14 +169,14 @@ unsigned MipsInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
if (!getAnalyzableBrOpc(I->getOpcode()))
break;
- MBB.erase(I.base(), FirstBr.base());
+ MBB.erase((--I).getReverse(), FirstBr);
return removed;
}
-/// ReverseBranchCondition - Return the inverse opcode of the
+/// reverseBranchCondition - Return the inverse opcode of the
/// specified Branch instruction.
-bool MipsInstrInfo::ReverseBranchCondition(
+bool MipsInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert( (Cond.size() && Cond.size() <= 3) &&
"Invalid Mips branch condition!");
@@ -269,7 +276,9 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(
if (Subtarget.inMicroMipsMode()) {
switch (Opcode) {
case Mips::BNE:
+ case Mips::BNE_MM:
case Mips::BEQ:
+ case Mips::BEQ_MM:
// microMIPS has NE,EQ branches that do not have delay slots provided one
// of the operands is zero.
if (I->getOperand(1).getReg() == Subtarget.getABI().GetZeroReg())
@@ -280,6 +289,7 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(
case Mips::JR:
case Mips::PseudoReturn:
case Mips::PseudoIndirectBranch:
+ case Mips::TAILCALLREG:
canUseShortMicroMipsCTI = true;
break;
}
@@ -302,12 +312,14 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(
case Mips::BAL:
return Mips::BALC;
case Mips::BEQ:
+ case Mips::BEQ_MM:
if (canUseShortMicroMipsCTI)
return Mips::BEQZC_MM;
else if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
return 0;
return Mips::BEQC;
case Mips::BNE:
+ case Mips::BNE_MM:
if (canUseShortMicroMipsCTI)
return Mips::BNEZC_MM;
else if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
@@ -337,11 +349,28 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(
return Mips::BLTUC;
case Mips::BLTZ:
return Mips::BLTZC;
+ case Mips::BEQ64:
+ if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BEQC64;
+ case Mips::BNE64:
+ if (I->getOperand(0).getReg() == I->getOperand(1).getReg())
+ return 0;
+ return Mips::BNEC64;
+ case Mips::BGTZ64:
+ return Mips::BGTZC64;
+ case Mips::BGEZ64:
+ return Mips::BGEZC64;
+ case Mips::BLTZ64:
+ return Mips::BLTZC64;
+ case Mips::BLEZ64:
+ return Mips::BLEZC64;
// For MIPSR6, the instruction 'jic' can be used for these cases. Some
// tools will accept 'jrc reg' as an alias for 'jic 0, $reg'.
case Mips::JR:
case Mips::PseudoReturn:
case Mips::PseudoIndirectBranch:
+ case Mips::TAILCALLREG:
if (canUseShortMicroMipsCTI)
return Mips::JRC16_MM;
return Mips::JIC;
@@ -350,6 +379,7 @@ unsigned MipsInstrInfo::getEquivalentCompactForm(
case Mips::JR64:
case Mips::PseudoReturn64:
case Mips::PseudoIndirectBranch64:
+ case Mips::TAILCALLREG64:
return Mips::JIC64;
case Mips::JALR64Pseudo:
return Mips::JIALC64;
@@ -378,7 +408,7 @@ bool MipsInstrInfo::HasForbiddenSlot(const MachineInstr &MI) const {
}
/// Return the number of bytes of code the specified instruction may be.
-unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
+unsigned MipsInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
switch (MI.getOpcode()) {
default:
return MI.getDesc().getSize();
@@ -399,17 +429,22 @@ MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
MachineBasicBlock::iterator I) const {
MachineInstrBuilder MIB;
- // Certain branches have two forms: e.g beq $1, $zero, dst vs beqz $1, dest
+ // Certain branches have two forms: e.g beq $1, $zero, dest vs beqz $1, dest
// Pick the zero form of the branch for readable assembly and for greater
// branch distance in non-microMIPS mode.
+ // Additional MIPSR6 does not permit the use of register $zero for compact
+ // branches.
// FIXME: Certain atomic sequences on mips64 generate 32bit references to
// Mips::ZERO, which is incorrect. This test should be updated to use
// Subtarget.getABI().GetZeroReg() when those atomic sequences and others
// are fixed.
- bool BranchWithZeroOperand =
- (I->isBranch() && !I->isPseudo() && I->getOperand(1).isReg() &&
- (I->getOperand(1).getReg() == Mips::ZERO ||
- I->getOperand(1).getReg() == Mips::ZERO_64));
+ int ZeroOperandPosition = -1;
+ bool BranchWithZeroOperand = false;
+ if (I->isBranch() && !I->isPseudo()) {
+ auto TRI = I->getParent()->getParent()->getSubtarget().getRegisterInfo();
+ ZeroOperandPosition = I->findRegisterUseOperandIdx(Mips::ZERO, false, TRI);
+ BranchWithZeroOperand = ZeroOperandPosition != -1;
+ }
if (BranchWithZeroOperand) {
switch (NewOpc) {
@@ -425,6 +460,12 @@ MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
case Mips::BLTC:
NewOpc = Mips::BLTZC;
break;
+ case Mips::BEQC64:
+ NewOpc = Mips::BEQZC64;
+ break;
+ case Mips::BNEC64:
+ NewOpc = Mips::BNEZC64;
+ break;
}
}
@@ -446,17 +487,11 @@ MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
MIB.addImm(0);
- } else if (BranchWithZeroOperand) {
- // For MIPSR6 and microMIPS branches with an explicit zero operand, copy
- // everything after the zero.
- MIB.addOperand(I->getOperand(0));
-
- for (unsigned J = 2, E = I->getDesc().getNumOperands(); J < E; ++J) {
- MIB.addOperand(I->getOperand(J));
- }
} else {
- // All other cases copy all other operands.
for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J) {
+ if (BranchWithZeroOperand && (unsigned)ZeroOperandPosition == J)
+ continue;
+
MIB.addOperand(I->getOperand(J));
}
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h
index 2e55012..347b918 100644
--- a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h
+++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h
@@ -55,14 +55,16 @@ public:
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
BranchType analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
@@ -92,7 +94,7 @@ public:
virtual unsigned getOppositeBranchOpc(unsigned Opc) const = 0;
/// Return the number of bytes of code the specified instruction may be.
- unsigned GetInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td
index 296f6e9..5bc4833 100644
--- a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -157,6 +157,8 @@ def HasMips3_32r2 : Predicate<"Subtarget->hasMips3_32r2()">,
AssemblerPredicate<"FeatureMips3_32r2">;
def HasMips3 : Predicate<"Subtarget->hasMips3()">,
AssemblerPredicate<"FeatureMips3">;
+def NotMips3 : Predicate<"!Subtarget->hasMips3()">,
+ AssemblerPredicate<"!FeatureMips3">;
def HasMips4_32 : Predicate<"Subtarget->hasMips4_32()">,
AssemblerPredicate<"FeatureMips4_32">;
def NotMips4_32 : Predicate<"!Subtarget->hasMips4_32()">,
@@ -201,6 +203,8 @@ def InMips16Mode : Predicate<"Subtarget->inMips16Mode()">,
AssemblerPredicate<"FeatureMips16">;
def HasCnMips : Predicate<"Subtarget->hasCnMips()">,
AssemblerPredicate<"FeatureCnMips">;
+def NotCnMips : Predicate<"!Subtarget->hasCnMips()">,
+ AssemblerPredicate<"!FeatureCnMips">;
def RelocNotPIC : Predicate<"!TM.isPositionIndependent()">;
def RelocPIC : Predicate<"TM.isPositionIndependent()">;
def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">;
@@ -242,6 +246,9 @@ class PTR_64 { list<Predicate> PTRPredicates = [IsPTR64bit]; }
// subtractive predicate will hopefully keep us under the 32 predicate
// limit long enough to develop an alternative way to handle P1||P2
// predicates.
+class ISA_MIPS1_NOT_MIPS3 {
+ list<Predicate> InsnPredicates = [NotMips3];
+}
class ISA_MIPS1_NOT_4_32 {
list<Predicate> InsnPredicates = [NotMips4_32];
}
@@ -300,6 +307,9 @@ class INSN_MIPS3_32_NOT_32R6_64R6 {
// The portions of MIPS-III that were also added to MIPS32
class INSN_MIPS3_32R2 { list<Predicate> InsnPredicates = [HasMips3_32r2]; }
+// The portions of MIPS-IV that were also added to MIPS32.
+class INSN_MIPS4_32 { list <Predicate> InsnPredicates = [HasMips4_32]; }
+
// The portions of MIPS-IV that were also added to MIPS32 but were removed in
// MIPS32r6 and MIPS64r6.
class INSN_MIPS4_32_NOT_32R6_64R6 {
@@ -312,6 +322,11 @@ class INSN_MIPS4_32R2_NOT_32R6_64R6 {
list<Predicate> InsnPredicates = [HasMips4_32r2, NotMips32r6, NotMips64r6];
}
+// The portions of MIPS-IV that were also added to MIPS32r2.
+class INSN_MIPS4_32R2 {
+ list<Predicate> InsnPredicates = [HasMips4_32r2];
+}
+
// The portions of MIPS-V that were also added to MIPS32r2 but were removed in
// MIPS32r6 and MIPS64r6.
class INSN_MIPS5_32R2_NOT_32R6_64R6 {
@@ -322,6 +337,10 @@ class ASE_CNMIPS {
list<Predicate> InsnPredicates = [HasCnMips];
}
+class NOT_ASE_CNMIPS {
+ list<Predicate> InsnPredicates = [NotCnMips];
+}
+
class ASE_MIPS64_CNMIPS {
list<Predicate> InsnPredicates = [HasMips64, HasCnMips];
}
@@ -413,6 +432,15 @@ class ConstantSImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = [],
let DiagnosticType = "SImm" # Bits # "_" # Offset;
}
+class SimmLslAsmOperandClass<int Bits, list<AsmOperandClass> Supers = [],
+ int Shift = 0> : AsmOperandClass {
+ let Name = "Simm" # Bits # "_Lsl" # Shift;
+ let RenderMethod = "addImmOperands";
+ let PredicateMethod = "isScaledSImm<" # Bits # ", " # Shift # ">";
+ let SuperClasses = Supers;
+ let DiagnosticType = "SImm" # Bits # "_Lsl" # Shift;
+}
+
class ConstantUImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = [],
int Offset = 0> : AsmOperandClass {
let Name = "ConstantUImm" # Bits # "_" # Offset;
@@ -450,6 +478,16 @@ class UImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = []>
let DiagnosticType = "UImm" # Bits;
}
+// Generic case - only to support certain assembly pseudo instructions.
+class UImmAnyAsmOperandClass<int Bits, list<AsmOperandClass> Supers = []>
+ : AsmOperandClass {
+ let Name = "ImmAny";
+ let RenderMethod = "addConstantUImmOperands<32>";
+ let PredicateMethod = "isSImm<" # Bits # ">";
+ let SuperClasses = Supers;
+ let DiagnosticType = "ImmAny";
+}
+
// AsmOperandClasses require a strict ordering which is difficult to manage
// as a hierarchy. Instead, we use a linear ordering and impose an order that
// is in some places arbitrary.
@@ -473,8 +511,13 @@ class UImmAsmOperandClass<int Bits, list<AsmOperandClass> Supers = []>
// uimm5 < uimm5_64, and uimm5 < vsplat_uimm5
// This is entirely arbitrary. We need an ordering and what we pick is
// unimportant since only one is possible for a given mnemonic.
+
+def UImm32CoercedAsmOperandClass : UImmAnyAsmOperandClass<33, []> {
+ let Name = "UImm32_Coerced";
+ let DiagnosticType = "UImm32_Coerced";
+}
def SImm32RelaxedAsmOperandClass
- : SImmAsmOperandClass<32, []> {
+ : SImmAsmOperandClass<32, [UImm32CoercedAsmOperandClass]> {
let Name = "SImm32_Relaxed";
let PredicateMethod = "isAnyImm<32>";
let DiagnosticType = "SImm32_Relaxed";
@@ -485,12 +528,29 @@ def ConstantUImm26AsmOperandClass
: ConstantUImmAsmOperandClass<26, [SImm32AsmOperandClass]>;
def ConstantUImm20AsmOperandClass
: ConstantUImmAsmOperandClass<20, [ConstantUImm26AsmOperandClass]>;
+def ConstantSImm19Lsl2AsmOperandClass : AsmOperandClass {
+ let Name = "SImm19Lsl2";
+ let RenderMethod = "addImmOperands";
+ let PredicateMethod = "isScaledSImm<19, 2>";
+ let SuperClasses = [ConstantUImm20AsmOperandClass];
+ let DiagnosticType = "SImm19_Lsl2";
+}
def UImm16RelaxedAsmOperandClass
: UImmAsmOperandClass<16, [ConstantUImm20AsmOperandClass]> {
let Name = "UImm16_Relaxed";
let PredicateMethod = "isAnyImm<16>";
let DiagnosticType = "UImm16_Relaxed";
}
+// Similar to the relaxed classes which take an SImm and render it as
+// an UImm, this takes a UImm and renders it as an SImm.
+def UImm16AltRelaxedAsmOperandClass
+ : SImmAsmOperandClass<16, [UImm16RelaxedAsmOperandClass]> {
+ let Name = "UImm16_AltRelaxed";
+ let PredicateMethod = "isUImm<16>";
+ let DiagnosticType = "UImm16_AltRelaxed";
+}
+// FIXME: One of these should probably have UImm16AsmOperandClass as the
+// superclass instead of UImm16RelaxedasmOPerandClass.
def UImm16AsmOperandClass
: UImmAsmOperandClass<16, [UImm16RelaxedAsmOperandClass]>;
def SImm16RelaxedAsmOperandClass
@@ -611,6 +671,9 @@ def ConstantImmzAsmOperandClass : AsmOperandClass {
let DiagnosticType = "Immz";
}
+def Simm19Lsl2AsmOperand
+ : SimmLslAsmOperandClass<19, [], 2>;
+
def MipsJumpTargetAsmOperand : AsmOperandClass {
let Name = "JumpTarget";
let ParserMethod = "parseJumpTarget";
@@ -645,7 +708,7 @@ def imm64: Operand<i64>;
def simm19_lsl2 : Operand<i32> {
let EncoderMethod = "getSimm19Lsl2Encoding";
let DecoderMethod = "DecodeSimm19Lsl2";
- let ParserMatchClass = MipsJumpTargetAsmOperand;
+ let ParserMatchClass = Simm19Lsl2AsmOperand;
}
def simm18_lsl3 : Operand<i32> {
@@ -766,6 +829,11 @@ def uimm16_64_relaxed : Operand<i64> {
!cast<AsmOperandClass>("UImm16RelaxedAsmOperandClass");
}
+def uimm16_altrelaxed : Operand<i32> {
+ let PrintMethod = "printUImm<16>";
+ let ParserMatchClass =
+ !cast<AsmOperandClass>("UImm16AltRelaxedAsmOperandClass");
+}
// Like uimm5 but reports a less confusing error for 32-63 when
// an instruction alias permits that.
def uimm5_report_uimm6 : Operand<i32> {
@@ -845,6 +913,10 @@ def simm16_64 : Operand<i64> {
let ParserMatchClass = !cast<AsmOperandClass>("SImm16AsmOperandClass");
}
+// like simm32 but coerces simm32 to uimm32.
+def uimm32_coerced : Operand<i32> {
+ let ParserMatchClass = !cast<AsmOperandClass>("UImm32CoercedAsmOperandClass");
+}
// Like simm32 but coerces uimm32 to simm32.
def simm32_relaxed : Operand<i32> {
let DecoderMethod = "DecodeSImmWithOffsetAndScale<32>";
@@ -1033,10 +1105,6 @@ def immSExt8 : PatLeaf<(imm), [{ return isInt<8>(N->getSExtValue()); }]>;
// e.g. addi, andi
def immSExt16 : PatLeaf<(imm), [{ return isInt<16>(N->getSExtValue()); }]>;
-// Node immediate fits as 15-bit sign extended on target immediate.
-// e.g. addi, andi
-def immSExt15 : PatLeaf<(imm), [{ return isInt<15>(N->getSExtValue()); }]>;
-
// Node immediate fits as 7-bit zero extended on target immediate.
def immZExt7 : PatLeaf<(imm), [{ return isUInt<7>(N->getZExtValue()); }]>;
@@ -1052,11 +1120,23 @@ def immZExt16 : PatLeaf<(imm), [{
}], LO16>;
// Immediate can be loaded with LUi (32-bit int with lower 16-bit cleared).
-def immLow16Zero : PatLeaf<(imm), [{
+def immSExt32Low16Zero : PatLeaf<(imm), [{
int64_t Val = N->getSExtValue();
return isInt<32>(Val) && !(Val & 0xffff);
}]>;
+// Zero-extended 32-bit unsigned int with lower 16-bit cleared.
+def immZExt32Low16Zero : PatLeaf<(imm), [{
+ uint64_t Val = N->getZExtValue();
+ return isUInt<32>(Val) && !(Val & 0xffff);
+}]>;
+
+// Note immediate fits as a 32 bit signed extended on target immediate.
+def immSExt32 : PatLeaf<(imm), [{ return isInt<32>(N->getSExtValue()); }]>;
+
+// Note immediate fits as a 32 bit zero extended on target immediate.
+def immZExt32 : PatLeaf<(imm), [{ return isUInt<32>(N->getZExtValue()); }]>;
+
// shamt field must fit in 5 bits.
def immZExt5 : ImmLeaf<i32, [{return Imm == (Imm & 0x1f);}]>;
@@ -1086,7 +1166,13 @@ def addrRegImm :
def addrDefault :
ComplexPattern<iPTR, 2, "selectAddrDefault", [frameindex]>;
-def addrimm10 : ComplexPattern<iPTR, 2, "selectIntAddrMSA", [frameindex]>;
+def addrimm10 : ComplexPattern<iPTR, 2, "selectIntAddrSImm10", [frameindex]>;
+def addrimm10lsl1 : ComplexPattern<iPTR, 2, "selectIntAddrSImm10Lsl1",
+ [frameindex]>;
+def addrimm10lsl2 : ComplexPattern<iPTR, 2, "selectIntAddrSImm10Lsl2",
+ [frameindex]>;
+def addrimm10lsl3 : ComplexPattern<iPTR, 2, "selectIntAddrSImm10Lsl3",
+ [frameindex]>;
//===----------------------------------------------------------------------===//
// Instructions specific format
@@ -1352,14 +1438,12 @@ let isCall=1, hasDelaySlot=1, isCTI=1, Defs = [RA] in {
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in {
- class TailCall<Instruction JumpInst> :
+ class TailCall<Instruction JumpInst, DAGOperand Opnd> :
PseudoSE<(outs), (ins calltarget:$target), [], II_J>,
- PseudoInstExpansion<(JumpInst jmptarget:$target)>;
+ PseudoInstExpansion<(JumpInst Opnd:$target)>;
- class TailCallReg<RegisterOperand RO, Instruction JRInst,
- RegisterOperand ResRO = RO> :
- PseudoSE<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>,
- PseudoInstExpansion<(JRInst ResRO:$rs)>;
+ class TailCallReg<RegisterOperand RO> :
+ MipsPseudo<(outs), (ins RO:$rs), [(MipsTailCall RO:$rs)], II_JR>;
}
class BAL_BR_Pseudo<Instruction RealInst> :
@@ -1686,33 +1770,35 @@ let AdditionalPredicates = [NotInMicroMips] in {
}
def ADDi : MMRel, ArithLogicI<"addi", simm16_relaxed, GPR32Opnd, II_ADDI>, ADDI_FM<0x8>,
ISA_MIPS1_NOT_32R6_64R6;
-def SLTi : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>,
- SLTI_FM<0xa>;
-def SLTiu : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>,
- SLTI_FM<0xb>;
+let AdditionalPredicates = [NotInMicroMips] in {
+ def SLTi : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>,
+ SLTI_FM<0xa>;
+ def SLTiu : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>,
+ SLTI_FM<0xb>;
+}
def LUi : MMRel, LoadUpper<"lui", GPR32Opnd, uimm16_relaxed>, LUI_FM;
let AdditionalPredicates = [NotInMicroMips] in {
-/// Arithmetic Instructions (3-Operand, R-Type)
-def ADDu : MMRel, StdMMR6Rel, ArithLogicR<"addu", GPR32Opnd, 1, II_ADDU, add>,
- ADD_FM<0, 0x21>;
-def SUBu : MMRel, StdMMR6Rel, ArithLogicR<"subu", GPR32Opnd, 0, II_SUBU, sub>,
- ADD_FM<0, 0x23>;
+ /// Arithmetic Instructions (3-Operand, R-Type)
+ def ADDu : MMRel, StdMMR6Rel, ArithLogicR<"addu", GPR32Opnd, 1, II_ADDU, add>,
+ ADD_FM<0, 0x21>;
+ def SUBu : MMRel, StdMMR6Rel, ArithLogicR<"subu", GPR32Opnd, 0, II_SUBU, sub>,
+ ADD_FM<0, 0x23>;
}
let Defs = [HI0, LO0] in
def MUL : MMRel, ArithLogicR<"mul", GPR32Opnd, 1, II_MUL, mul>,
ADD_FM<0x1c, 2>, ISA_MIPS32_NOT_32R6_64R6;
def ADD : MMRel, StdMMR6Rel, ArithLogicR<"add", GPR32Opnd, 1, II_ADD>, ADD_FM<0, 0x20>;
def SUB : MMRel, StdMMR6Rel, ArithLogicR<"sub", GPR32Opnd, 0, II_SUB>, ADD_FM<0, 0x22>;
-def SLT : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM<0, 0x2a>;
-def SLTu : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>, ADD_FM<0, 0x2b>;
let AdditionalPredicates = [NotInMicroMips] in {
-def AND : MMRel, StdMMR6Rel, ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>,
- ADD_FM<0, 0x24>;
-def OR : MMRel, StdMMR6Rel, ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>,
- ADD_FM<0, 0x25>;
-def XOR : MMRel, StdMMR6Rel, ArithLogicR<"xor", GPR32Opnd, 1, II_XOR, xor>,
- ADD_FM<0, 0x26>;
-def NOR : MMRel, StdMMR6Rel, LogicNOR<"nor", GPR32Opnd>, ADD_FM<0, 0x27>;
+ def SLT : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM<0, 0x2a>;
+ def SLTu : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>, ADD_FM<0, 0x2b>;
+ def AND : MMRel, StdMMR6Rel, ArithLogicR<"and", GPR32Opnd, 1, II_AND, and>,
+ ADD_FM<0, 0x24>;
+ def OR : MMRel, StdMMR6Rel, ArithLogicR<"or", GPR32Opnd, 1, II_OR, or>,
+ ADD_FM<0, 0x25>;
+ def XOR : MMRel, StdMMR6Rel, ArithLogicR<"xor", GPR32Opnd, 1, II_XOR, xor>,
+ ADD_FM<0, 0x26>;
+ def NOR : MMRel, StdMMR6Rel, LogicNOR<"nor", GPR32Opnd>, ADD_FM<0, 0x27>;
}
/// Shift Instructions
@@ -1794,11 +1880,10 @@ let DecoderNamespace = "COP3_" in {
def SDC3 : SW_FT3<"sdc3", COP3Opnd, II_SDC3, store>, LW_FM<0x3f>,
ISA_MIPS2;
}
-}
-def SYNC : MMRel, StdMMR6Rel, SYNC_FT<"sync">, SYNC_FM,
- ISA_MIPS32;
-def SYNCI : MMRel, StdMMR6Rel, SYNCI_FT<"synci">, SYNCI_FM, ISA_MIPS32R2;
+ def SYNC : MMRel, StdMMR6Rel, SYNC_FT<"sync">, SYNC_FM, ISA_MIPS2;
+ def SYNCI : MMRel, StdMMR6Rel, SYNCI_FT<"synci">, SYNCI_FM, ISA_MIPS32R2;
+}
let AdditionalPredicates = [NotInMicroMips] in {
def TEQ : MMRel, TEQ_FT<"teq", GPR32Opnd, uimm10, II_TEQ>, TEQ_FM<0x34>, ISA_MIPS2;
@@ -1898,8 +1983,12 @@ def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>,
def BLTZALL : MMRel, BGEZAL_FT<"bltzall", brtarget, GPR32Opnd, 0>,
BGEZAL_FM<0x12>, ISA_MIPS2_NOT_32R6_64R6;
def BAL_BR : BAL_BR_Pseudo<BGEZAL>;
-def TAILCALL : TailCall<J>;
-def TAILCALL_R : TailCallReg<GPR32Opnd, JR>;
+
+let Predicates = [NotInMicroMips] in {
+ def TAILCALL : TailCall<J, jmptarget>;
+}
+
+def TAILCALLREG : TailCallReg<GPR32Opnd>;
// Indirect branches are matched as PseudoIndirectBranch/PseudoIndirectBranch64
// then are expanded to JR, JR64, JALR, or JALR64 depending on the ISA.
@@ -2177,6 +2266,21 @@ def : MipsInstAlias<"dror $rd, $imm",
def ABSMacro : MipsAsmPseudoInst<(outs GPR32Opnd:$rd), (ins GPR32Opnd:$rs),
"abs\t$rd, $rs">;
+def SEQMacro : MipsAsmPseudoInst<(outs GPR32Opnd:$rd),
+ (ins GPR32Opnd:$rs, GPR32Opnd:$rt),
+ "seq $rd, $rs, $rt">, NOT_ASE_CNMIPS;
+
+def : MipsInstAlias<"seq $rd, $rs",
+ (SEQMacro GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rs), 0>,
+ NOT_ASE_CNMIPS;
+
+def SEQIMacro : MipsAsmPseudoInst<(outs GPR32Opnd:$rd),
+ (ins GPR32Opnd:$rs, simm32_relaxed:$imm),
+ "seq $rd, $rs, $imm">, NOT_ASE_CNMIPS;
+
+def : MipsInstAlias<"seq $rd, $imm",
+ (SEQIMacro GPR32Opnd:$rd, GPR32Opnd:$rd, simm32:$imm), 0>,
+ NOT_ASE_CNMIPS;
//===----------------------------------------------------------------------===//
// Instruction aliases
//===----------------------------------------------------------------------===//
@@ -2219,17 +2323,31 @@ def : MipsInstAlias<"jalr $rs", (JALR RA, GPR32Opnd:$rs), 0>;
def : MipsInstAlias<"jalr.hb $rs", (JALR_HB RA, GPR32Opnd:$rs), 1>, ISA_MIPS32;
def : MipsInstAlias<"neg $rt, $rs",
(SUB GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>;
-def : MipsInstAlias<"negu $rt",
- (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 0>;
+def : MipsInstAlias<"neg $rt",
+ (SUB GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 1>;
def : MipsInstAlias<"negu $rt, $rs",
(SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>;
-def : MipsInstAlias<
+def : MipsInstAlias<"negu $rt",
+ (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rt), 1>;
+let AdditionalPredicates = [NotInMicroMips] in {
+ def : MipsInstAlias<
+ "sgt $rd, $rs, $rt",
+ (SLT GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
+ "sgt $rs, $rt",
+ (SLT GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
+ "sgtu $rd, $rs, $rt",
+ (SLTu GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
+ "sgtu $$rs, $rt",
+ (SLTu GPR32Opnd:$rs, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<
"slt $rs, $rt, $imm",
(SLTi GPR32Opnd:$rs, GPR32Opnd:$rt, simm32_relaxed:$imm), 0>;
-def : MipsInstAlias<
+ def : MipsInstAlias<
"sltu $rt, $rs, $imm",
(SLTiu GPR32Opnd:$rt, GPR32Opnd:$rs, simm32_relaxed:$imm), 0>;
-let AdditionalPredicates = [NotInMicroMips] in {
def : MipsInstAlias<
"and $rs, $rt, $imm",
(ANDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm32_relaxed:$imm), 0>;
@@ -2251,6 +2369,9 @@ let AdditionalPredicates = [NotInMicroMips] in {
def : MipsInstAlias<
"not $rt, $rs",
(NOR GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>;
+ def : MipsInstAlias<
+ "not $rt",
+ (NOR GPR32Opnd:$rt, GPR32Opnd:$rt, ZERO), 0>;
def : MipsInstAlias<"nop", (SLL ZERO, ZERO, 0), 1>;
}
def : MipsInstAlias<"mfc0 $rt, $rd", (MFC0 GPR32Opnd:$rt, COP0Opnd:$rd, 0), 0>;
@@ -2310,6 +2431,16 @@ let AdditionalPredicates = [NotInMicroMips] in {
(SRAV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
def : MipsInstAlias<"srl $rd, $rt, $rs",
(SRLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
+ def : MipsInstAlias<"sll $rd, $rt",
+ (SLLV GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rt), 0>;
+ def : MipsInstAlias<"sra $rd, $rt",
+ (SRAV GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rt), 0>;
+ def : MipsInstAlias<"srl $rd, $rt",
+ (SRLV GPR32Opnd:$rd, GPR32Opnd:$rd, GPR32Opnd:$rt), 0>;
+ def : MipsInstAlias<"seh $rd", (SEH GPR32Opnd:$rd, GPR32Opnd:$rd), 0>,
+ ISA_MIPS32R2;
+ def : MipsInstAlias<"seb $rd", (SEB GPR32Opnd:$rd, GPR32Opnd:$rd), 0>,
+ ISA_MIPS32R2;
}
def : MipsInstAlias<"sdbbp", (SDBBP 0)>, ISA_MIPS32_NOT_32R6_64R6;
def : MipsInstAlias<"sync",
@@ -2318,11 +2449,12 @@ def : MipsInstAlias<"sync",
// Assembler Pseudo Instructions
//===----------------------------------------------------------------------===//
-// We use i32imm on li/la to defer range checking to the assembler.
+// We use uimm32_coerced to accept a 33 bit signed number that is rendered into
+// a 32 bit number.
class LoadImmediate32<string instr_asm, Operand Od, RegisterOperand RO> :
MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32),
!strconcat(instr_asm, "\t$rt, $imm32")> ;
-def LoadImm32 : LoadImmediate32<"li", i32imm, GPR32Opnd>;
+def LoadImm32 : LoadImmediate32<"li", uimm32_coerced, GPR32Opnd>;
class LoadAddressFromReg32<string instr_asm, Operand MemOpnd,
RegisterOperand RO> :
@@ -2441,6 +2573,18 @@ def Ulhu : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr),
def Ulw : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr),
"ulw\t$rt, $addr">; //, ISA_MIPS1_NOT_32R6_64R6;
+def Ush : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr),
+ "ush\t$rt, $addr">; //, ISA_MIPS1_NOT_32R6_64R6;
+
+def Usw : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins mem:$addr),
+ "usw\t$rt, $addr">; //, ISA_MIPS1_NOT_32R6_64R6;
+
+def LDMacro : MipsAsmPseudoInst<(outs GPR32Opnd:$rt),
+ (ins mem_simm16:$addr), "ld $rt, $addr">,
+ ISA_MIPS1_NOT_MIPS3;
+def SDMacro : MipsAsmPseudoInst<(outs GPR32Opnd:$rt),
+ (ins mem_simm16:$addr), "sd $rt, $addr">,
+ ISA_MIPS1_NOT_MIPS3;
//===----------------------------------------------------------------------===//
// Arbitrary patterns that map to one or more instructions
//===----------------------------------------------------------------------===//
@@ -2452,19 +2596,24 @@ class LoadRegImmPat<Instruction LoadInst, ValueType ValTy, PatFrag Node> :
class StoreRegImmPat<Instruction StoreInst, ValueType ValTy> :
MipsPat<(store ValTy:$v, addrRegImm:$a), (StoreInst ValTy:$v, addrRegImm:$a)>;
+// Materialize constants.
+multiclass MaterializeImms<ValueType VT, Register ZEROReg,
+ Instruction ADDiuOp, Instruction LUiOp,
+ Instruction ORiOp> {
+
// Small immediates
-let AdditionalPredicates = [NotInMicroMips] in {
-def : MipsPat<(i32 immSExt16:$in),
- (ADDiu ZERO, imm:$in)>;
-def : MipsPat<(i32 immZExt16:$in),
- (ORi ZERO, imm:$in)>;
-}
-def : MipsPat<(i32 immLow16Zero:$in),
- (LUi (HI16 imm:$in))>;
+def : MipsPat<(VT immSExt16:$imm), (ADDiuOp ZEROReg, imm:$imm)>;
+def : MipsPat<(VT immZExt16:$imm), (ORiOp ZEROReg, imm:$imm)>;
+
+// Bits 32-16 set, sign/zero extended.
+def : MipsPat<(VT immSExt32Low16Zero:$imm), (LUiOp (HI16 imm:$imm))>;
// Arbitrary immediates
-def : MipsPat<(i32 imm:$imm),
- (ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>;
+def : MipsPat<(VT immSExt32:$imm), (ORiOp (LUiOp (HI16 imm:$imm)), (LO16 imm:$imm))>;
+}
+
+let AdditionalPredicates = [NotInMicroMips] in
+ defm : MaterializeImms<i32, ZERO, ADDiu, LUi, ORi>;
// Carry MipsPatterns
let AdditionalPredicates = [NotInMicroMips] in {
@@ -2558,38 +2707,39 @@ let AdditionalPredicates = [NotInMicroMips] in {
def : MipsPat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>;
// brcond patterns
-multiclass BrcondPats<RegisterClass RC, Instruction BEQOp, Instruction BNEOp,
- Instruction SLTOp, Instruction SLTuOp, Instruction SLTiOp,
- Instruction SLTiuOp, Register ZEROReg> {
+multiclass BrcondPats<RegisterClass RC, Instruction BEQOp, Instruction BEQOp1,
+ Instruction BNEOp, Instruction SLTOp, Instruction SLTuOp,
+ Instruction SLTiOp, Instruction SLTiuOp,
+ Register ZEROReg> {
def : MipsPat<(brcond (i32 (setne RC:$lhs, 0)), bb:$dst),
(BNEOp RC:$lhs, ZEROReg, bb:$dst)>;
def : MipsPat<(brcond (i32 (seteq RC:$lhs, 0)), bb:$dst),
(BEQOp RC:$lhs, ZEROReg, bb:$dst)>;
def : MipsPat<(brcond (i32 (setge RC:$lhs, RC:$rhs)), bb:$dst),
- (BEQ (SLTOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setuge RC:$lhs, RC:$rhs)), bb:$dst),
- (BEQ (SLTuOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTuOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setge RC:$lhs, immSExt16:$rhs)), bb:$dst),
- (BEQ (SLTiOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTiOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setuge RC:$lhs, immSExt16:$rhs)), bb:$dst),
- (BEQ (SLTiuOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTiuOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setgt RC:$lhs, immSExt16Plus1:$rhs)), bb:$dst),
- (BEQ (SLTiOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTiOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setugt RC:$lhs, immSExt16Plus1:$rhs)), bb:$dst),
- (BEQ (SLTiuOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTiuOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setle RC:$lhs, RC:$rhs)), bb:$dst),
- (BEQ (SLTOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>;
def : MipsPat<(brcond (i32 (setule RC:$lhs, RC:$rhs)), bb:$dst),
- (BEQ (SLTuOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>;
+ (BEQOp1 (SLTuOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>;
def : MipsPat<(brcond RC:$cond, bb:$dst),
(BNEOp RC:$cond, ZEROReg, bb:$dst)>;
}
-
-defm : BrcondPats<GPR32, BEQ, BNE, SLT, SLTu, SLTi, SLTiu, ZERO>;
-
+let AdditionalPredicates = [NotInMicroMips] in {
+ defm : BrcondPats<GPR32, BEQ, BEQ, BNE, SLT, SLTu, SLTi, SLTiu, ZERO>;
+}
def : MipsPat<(brcond (i32 (setlt i32:$lhs, 1)), bb:$dst),
(BLEZ i32:$lhs, bb:$dst)>;
def : MipsPat<(brcond (i32 (setgt i32:$lhs, -1)), bb:$dst),
@@ -2608,11 +2758,12 @@ multiclass SeteqPats<RegisterClass RC, Instruction SLTiuOp, Instruction XOROp,
(SLTuOp ZEROReg, (XOROp RC:$lhs, RC:$rhs))>;
}
-multiclass SetlePats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> {
+multiclass SetlePats<RegisterClass RC, Instruction XORiOp, Instruction SLTOp,
+ Instruction SLTuOp> {
def : MipsPat<(setle RC:$lhs, RC:$rhs),
- (XORi (SLTOp RC:$rhs, RC:$lhs), 1)>;
+ (XORiOp (SLTOp RC:$rhs, RC:$lhs), 1)>;
def : MipsPat<(setule RC:$lhs, RC:$rhs),
- (XORi (SLTuOp RC:$rhs, RC:$lhs), 1)>;
+ (XORiOp (SLTuOp RC:$rhs, RC:$lhs), 1)>;
}
multiclass SetgtPats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> {
@@ -2622,26 +2773,29 @@ multiclass SetgtPats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> {
(SLTuOp RC:$rhs, RC:$lhs)>;
}
-multiclass SetgePats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> {
+multiclass SetgePats<RegisterClass RC, Instruction XORiOp, Instruction SLTOp,
+ Instruction SLTuOp> {
def : MipsPat<(setge RC:$lhs, RC:$rhs),
- (XORi (SLTOp RC:$lhs, RC:$rhs), 1)>;
+ (XORiOp (SLTOp RC:$lhs, RC:$rhs), 1)>;
def : MipsPat<(setuge RC:$lhs, RC:$rhs),
- (XORi (SLTuOp RC:$lhs, RC:$rhs), 1)>;
+ (XORiOp (SLTuOp RC:$lhs, RC:$rhs), 1)>;
}
-multiclass SetgeImmPats<RegisterClass RC, Instruction SLTiOp,
- Instruction SLTiuOp> {
+multiclass SetgeImmPats<RegisterClass RC, Instruction XORiOp,
+ Instruction SLTiOp, Instruction SLTiuOp> {
def : MipsPat<(setge RC:$lhs, immSExt16:$rhs),
- (XORi (SLTiOp RC:$lhs, immSExt16:$rhs), 1)>;
+ (XORiOp (SLTiOp RC:$lhs, immSExt16:$rhs), 1)>;
def : MipsPat<(setuge RC:$lhs, immSExt16:$rhs),
- (XORi (SLTiuOp RC:$lhs, immSExt16:$rhs), 1)>;
+ (XORiOp (SLTiuOp RC:$lhs, immSExt16:$rhs), 1)>;
}
-defm : SeteqPats<GPR32, SLTiu, XOR, SLTu, ZERO>;
-defm : SetlePats<GPR32, SLT, SLTu>;
-defm : SetgtPats<GPR32, SLT, SLTu>;
-defm : SetgePats<GPR32, SLT, SLTu>;
-defm : SetgeImmPats<GPR32, SLTi, SLTiu>;
+let AdditionalPredicates = [NotInMicroMips] in {
+ defm : SeteqPats<GPR32, SLTiu, XOR, SLTu, ZERO>;
+ defm : SetlePats<GPR32, XORi, SLT, SLTu>;
+ defm : SetgtPats<GPR32, SLT, SLTu>;
+ defm : SetgePats<GPR32, XORi, SLT, SLTu>;
+ defm : SetgeImmPats<GPR32, XORi, SLTi, SLTiu>;
+}
// bswap pattern
def : MipsPat<(bswap GPR32:$rt), (ROTR (WSBH GPR32:$rt), 16)>;
diff --git a/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp
index e721312..1087d0e 100644
--- a/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp
@@ -66,15 +66,13 @@ namespace {
: MachineFunctionPass(ID), TM(tm), IsPIC(TM.isPositionIndependent()),
ABI(static_cast<const MipsTargetMachine &>(TM).getABI()) {}
- const char *getPassName() const override {
- return "Mips Long Branch";
- }
+ StringRef getPassName() const override { return "Mips Long Branch"; }
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -157,7 +155,7 @@ void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) {
MBB->addSuccessor(Tgt);
MF->insert(std::next(MachineFunction::iterator(MBB)), NewMBB);
- NewMBB->splice(NewMBB->end(), MBB, (++LastBr).base(), MBB->end());
+ NewMBB->splice(NewMBB->end(), MBB, LastBr.getReverse(), MBB->end());
}
// Fill MBBInfos.
@@ -179,7 +177,7 @@ void MipsLongBranch::initMBBInfo() {
// Compute size of MBB.
for (MachineBasicBlock::instr_iterator MI = MBB->instr_begin();
MI != MBB->instr_end(); ++MI)
- MBBInfos[I].Size += TII->GetInstSizeInBytes(*MI);
+ MBBInfos[I].Size += TII->getInstSizeInBytes(*MI);
// Search for MBB's branch instruction.
ReverseIter End = MBB->rend();
@@ -187,7 +185,7 @@ void MipsLongBranch::initMBBInfo() {
if ((Br != End) && !Br->isIndirectBranch() &&
(Br->isConditionalBranch() || (Br->isUnconditionalBranch() && IsPIC)))
- MBBInfos[I].Br = &*(++Br).base();
+ MBBInfos[I].Br = &*Br;
}
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td
index deb4345..8b04fcb 100644
--- a/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td
+++ b/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td
@@ -389,10 +389,6 @@ def mulsub : PatFrag<(ops node:$wd, node:$ws, node:$wt),
def mul_fexp2 : PatFrag<(ops node:$ws, node:$wt),
(fmul node:$ws, (fexp2 node:$wt))>;
-// Immediates
-def immSExt5 : ImmLeaf<i32, [{return isInt<5>(Imm);}]>;
-def immSExt10: ImmLeaf<i32, [{return isInt<10>(Imm);}]>;
-
// Instruction encoding.
class ADD_A_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010000>;
class ADD_A_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010000>;
@@ -2308,9 +2304,12 @@ class LD_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
}
class LD_B_DESC : LD_DESC_BASE<"ld.b", load, v16i8, MSA128BOpnd, mem_simm10>;
-class LD_H_DESC : LD_DESC_BASE<"ld.h", load, v8i16, MSA128HOpnd, mem_simm10_lsl1>;
-class LD_W_DESC : LD_DESC_BASE<"ld.w", load, v4i32, MSA128WOpnd, mem_simm10_lsl2>;
-class LD_D_DESC : LD_DESC_BASE<"ld.d", load, v2i64, MSA128DOpnd, mem_simm10_lsl3>;
+class LD_H_DESC : LD_DESC_BASE<"ld.h", load, v8i16, MSA128HOpnd,
+ mem_simm10_lsl1, addrimm10lsl1>;
+class LD_W_DESC : LD_DESC_BASE<"ld.w", load, v4i32, MSA128WOpnd,
+ mem_simm10_lsl2, addrimm10lsl2>;
+class LD_D_DESC : LD_DESC_BASE<"ld.d", load, v2i64, MSA128DOpnd,
+ mem_simm10_lsl3, addrimm10lsl3>;
class LDI_B_DESC : MSA_I10_LDI_DESC_BASE<"ldi.b", MSA128BOpnd>;
class LDI_H_DESC : MSA_I10_LDI_DESC_BASE<"ldi.h", MSA128HOpnd>;
@@ -2641,9 +2640,12 @@ class ST_DESC_BASE<string instr_asm, SDPatternOperator OpNode,
}
class ST_B_DESC : ST_DESC_BASE<"st.b", store, v16i8, MSA128BOpnd, mem_simm10>;
-class ST_H_DESC : ST_DESC_BASE<"st.h", store, v8i16, MSA128HOpnd, mem_simm10_lsl1>;
-class ST_W_DESC : ST_DESC_BASE<"st.w", store, v4i32, MSA128WOpnd, mem_simm10_lsl2>;
-class ST_D_DESC : ST_DESC_BASE<"st.d", store, v2i64, MSA128DOpnd, mem_simm10_lsl3>;
+class ST_H_DESC : ST_DESC_BASE<"st.h", store, v8i16, MSA128HOpnd,
+ mem_simm10_lsl1, addrimm10lsl1>;
+class ST_W_DESC : ST_DESC_BASE<"st.w", store, v4i32, MSA128WOpnd,
+ mem_simm10_lsl2, addrimm10lsl2>;
+class ST_D_DESC : ST_DESC_BASE<"st.d", store, v2i64, MSA128DOpnd,
+ mem_simm10_lsl3, addrimm10lsl3>;
class SUBS_S_B_DESC : MSA_3R_DESC_BASE<"subs_s.b", int_mips_subs_s_b,
MSA128BOpnd>;
@@ -3523,16 +3525,16 @@ class MSAPat<dag pattern, dag result, list<Predicate> pred = [HasMSA]> :
def : MSAPat<(extractelt (v4i32 MSA128W:$ws), immZExt4:$idx),
(COPY_S_W MSA128W:$ws, immZExt4:$idx)>;
-def : MSAPat<(v8f16 (load addrimm10:$addr)), (LD_H addrimm10:$addr)>;
-def : MSAPat<(v4f32 (load addrimm10:$addr)), (LD_W addrimm10:$addr)>;
-def : MSAPat<(v2f64 (load addrimm10:$addr)), (LD_D addrimm10:$addr)>;
+def : MSAPat<(v8f16 (load addrimm10lsl1:$addr)), (LD_H addrimm10lsl1:$addr)>;
+def : MSAPat<(v4f32 (load addrimm10lsl2:$addr)), (LD_W addrimm10lsl2:$addr)>;
+def : MSAPat<(v2f64 (load addrimm10lsl3:$addr)), (LD_D addrimm10lsl3:$addr)>;
-def ST_FH : MSAPat<(store (v8f16 MSA128H:$ws), addrimm10:$addr),
- (ST_H MSA128H:$ws, addrimm10:$addr)>;
-def ST_FW : MSAPat<(store (v4f32 MSA128W:$ws), addrimm10:$addr),
- (ST_W MSA128W:$ws, addrimm10:$addr)>;
-def ST_FD : MSAPat<(store (v2f64 MSA128D:$ws), addrimm10:$addr),
- (ST_D MSA128D:$ws, addrimm10:$addr)>;
+def ST_FH : MSAPat<(store (v8f16 MSA128H:$ws), addrimm10lsl1:$addr),
+ (ST_H MSA128H:$ws, addrimm10lsl1:$addr)>;
+def ST_FW : MSAPat<(store (v4f32 MSA128W:$ws), addrimm10lsl2:$addr),
+ (ST_W MSA128W:$ws, addrimm10lsl2:$addr)>;
+def ST_FD : MSAPat<(store (v2f64 MSA128D:$ws), addrimm10lsl3:$addr),
+ (ST_D MSA128D:$ws, addrimm10lsl3:$addr)>;
class MSA_FABS_PSEUDO_DESC_BASE<RegisterOperand ROWD,
RegisterOperand ROWS = ROWD,
@@ -3729,6 +3731,56 @@ def SZ_D_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v2i64,
def SZ_V_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAnyZero, v16i8,
MSA128B, NoItinerary>;
+// Pseudoes used to implement transparent fp16 support.
+
+let Predicates = [HasMSA] in {
+ def ST_F16 : MipsPseudo<(outs), (ins MSA128F16:$ws, mem_simm10:$addr),
+ [(store (f16 MSA128F16:$ws), (addrimm10:$addr))]> {
+ let usesCustomInserter = 1;
+ }
+
+ def LD_F16 : MipsPseudo<(outs MSA128F16:$ws), (ins mem_simm10:$addr),
+ [(set MSA128F16:$ws, (f16 (load addrimm10:$addr)))]> {
+ let usesCustomInserter = 1;
+ }
+
+ def MSA_FP_EXTEND_W_PSEUDO : MipsPseudo<(outs FGR32Opnd:$fd),
+ (ins MSA128F16:$ws),
+ [(set FGR32Opnd:$fd,
+ (f32 (fpextend MSA128F16:$ws)))]> {
+ let usesCustomInserter = 1;
+ }
+
+ def MSA_FP_ROUND_W_PSEUDO : MipsPseudo<(outs MSA128F16:$wd),
+ (ins FGR32Opnd:$fs),
+ [(set MSA128F16:$wd,
+ (f16 (fpround FGR32Opnd:$fs)))]> {
+ let usesCustomInserter = 1;
+ }
+
+ def MSA_FP_EXTEND_D_PSEUDO : MipsPseudo<(outs FGR64Opnd:$fd),
+ (ins MSA128F16:$ws),
+ [(set FGR64Opnd:$fd,
+ (f64 (fpextend MSA128F16:$ws)))]> {
+ let usesCustomInserter = 1;
+ }
+
+ def MSA_FP_ROUND_D_PSEUDO : MipsPseudo<(outs MSA128F16:$wd),
+ (ins FGR64Opnd:$fs),
+ [(set MSA128F16:$wd,
+ (f16 (fpround FGR64Opnd:$fs)))]> {
+ let usesCustomInserter = 1;
+ }
+
+ def : MipsPat<(MipsTruncIntFP MSA128F16:$ws),
+ (TRUNC_W_D64 (MSA_FP_EXTEND_D_PSEUDO MSA128F16:$ws))>;
+
+ def : MipsPat<(MipsFPCmp MSA128F16:$ws, MSA128F16:$wt, imm:$cond),
+ (FCMP_S32 (MSA_FP_EXTEND_W_PSEUDO MSA128F16:$ws),
+ (MSA_FP_EXTEND_W_PSEUDO MSA128F16:$wt), imm:$cond)>,
+ ISA_MIPS1_NOT_32R6_64R6;
+}
+
// Vector extraction with fixed index.
//
// Extracting 32-bit values on MSA32 should always use COPY_S_W rather than
diff --git a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp
index f81e64e..d0609b1 100644
--- a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp
@@ -60,7 +60,7 @@ void MipsFunctionInfo::createEhDataRegsFI() {
? &Mips::GPR64RegClass
: &Mips::GPR32RegClass;
- EhDataRegFI[I] = MF.getFrameInfo()->CreateStackObject(RC->getSize(),
+ EhDataRegFI[I] = MF.getFrameInfo().CreateStackObject(RC->getSize(),
RC->getAlignment(), false);
}
}
@@ -68,12 +68,12 @@ void MipsFunctionInfo::createEhDataRegsFI() {
void MipsFunctionInfo::createISRRegFI() {
// ISRs require spill slots for Status & ErrorPC Coprocessor 0 registers.
// The current implementation only supports Mips32r2+ not Mips64rX. Status
- // is always 32 bits, ErrorPC is 32 or 64 bits dependant on architecture,
+ // is always 32 bits, ErrorPC is 32 or 64 bits dependent on architecture,
// however Mips32r2+ is the supported architecture.
const TargetRegisterClass *RC = &Mips::GPR32RegClass;
for (int I = 0; I < 2; ++I)
- ISRDataRegFI[I] = MF.getFrameInfo()->CreateStackObject(
+ ISRDataRegFI[I] = MF.getFrameInfo().CreateStackObject(
RC->getSize(), RC->getAlignment(), false);
}
@@ -95,7 +95,7 @@ MachinePointerInfo MipsFunctionInfo::callPtrInfo(const GlobalValue *GV) {
int MipsFunctionInfo::getMoveF64ViaSpillFI(const TargetRegisterClass *RC) {
if (MoveF64ViaSpillFI == -1) {
- MoveF64ViaSpillFI = MF.getFrameInfo()->CreateStackObject(
+ MoveF64ViaSpillFI = MF.getFrameInfo().CreateStackObject(
RC->getSize(), RC->getAlignment(), false);
}
return MoveF64ViaSpillFI;
diff --git a/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp
index b18a673..cf85eb3 100644
--- a/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp
@@ -26,7 +26,7 @@ namespace {
: MachineFunctionPass(ID), TM(TM_) {}
// Pass Name
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "MIPS DAG->DAG Pattern Instruction Selection";
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp b/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp
index 7c940ee..f33857f 100644
--- a/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsOptimizePICCall.cpp
@@ -61,7 +61,7 @@ class OptimizePICCall : public MachineFunctionPass {
public:
OptimizePICCall(TargetMachine &tm) : MachineFunctionPass(ID) {}
- const char *getPassName() const override { return "Mips OptimizePICCall"; }
+ StringRef getPassName() const override { return "Mips OptimizePICCall"; }
bool runOnMachineFunction(MachineFunction &F) override;
diff --git a/contrib/llvm/lib/Target/Mips/MipsOs16.cpp b/contrib/llvm/lib/Target/Mips/MipsOs16.cpp
index 8136907..51ac562 100644
--- a/contrib/llvm/lib/Target/Mips/MipsOs16.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsOs16.cpp
@@ -35,9 +35,7 @@ namespace {
MipsOs16() : ModulePass(ID) {}
- const char *getPassName() const override {
- return "MIPS Os16 Optimization";
- }
+ StringRef getPassName() const override { return "MIPS Os16 Optimization"; }
bool runOnModule(Module &M) override;
};
diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 860cf9c..65be350 100644
--- a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -206,7 +206,7 @@ getReservedRegs(const MachineFunction &MF) const {
// allocate variable-sized objects at runtime. This should test the
// same conditions as MipsFrameLowering::hasBP().
if (needsStackRealignment(MF) &&
- MF.getFrameInfo()->hasVarSizedObjects()) {
+ MF.getFrameInfo().hasVarSizedObjects()) {
Reserved.set(Mips::S7);
Reserved.set(Mips::S7_64);
}
@@ -281,8 +281,8 @@ eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj,
errs() << "<--------->\n" << MI);
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- uint64_t stackSize = MF.getFrameInfo()->getStackSize();
- int64_t spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
+ uint64_t stackSize = MF.getFrameInfo().getStackSize();
+ int64_t spOffset = MF.getFrameInfo().getObjectOffset(FrameIndex);
DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n"
<< "spOffset : " << spOffset << "\n"
diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td
index cfce7c8..8c82239 100644
--- a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td
+++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td
@@ -400,6 +400,8 @@ def FCC : RegisterClass<"Mips", [i32], 32, (sequence "FCC%u", 0, 7)>,
// This class allows us to represent this in codegen patterns.
def FGRCC : RegisterClass<"Mips", [i32], 32, (sequence "F%u", 0, 31)>;
+def MSA128F16 : RegisterClass<"Mips", [f16], 128, (sequence "W%u", 0, 31)>;
+
def MSA128B: RegisterClass<"Mips", [v16i8], 128,
(sequence "W%u", 0, 31)>;
def MSA128H: RegisterClass<"Mips", [v8i16, v8f16], 128,
@@ -646,6 +648,10 @@ def COP3Opnd : RegisterOperand<COP3> {
let ParserMatchClass = COP3AsmOperand;
}
+def MSA128F16Opnd : RegisterOperand<MSA128F16> {
+ let ParserMatchClass = MSA128AsmOperand;
+}
+
def MSA128BOpnd : RegisterOperand<MSA128B> {
let ParserMatchClass = MSA128AsmOperand;
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
index a7ddd77..4996d07 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
@@ -374,7 +374,7 @@ MipsSEFrameLowering::MipsSEFrameLowering(const MipsSubtarget &STI)
void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
const MipsSEInstrInfo &TII =
@@ -396,10 +396,10 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
&Mips::GPR64RegClass : &Mips::GPR32RegClass;
// First, compute final stack size.
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
// No need to allocate space on the stack.
- if (StackSize == 0 && !MFI->adjustsStack()) return;
+ if (StackSize == 0 && !MFI.adjustsStack()) return;
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
@@ -409,7 +409,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);
// emit ".cfi_def_cfa_offset StackSize"
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -417,7 +417,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
if (MF.getFunction()->hasFnAttribute("interrupt"))
emitInterruptPrologueStub(MF, MBB);
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
if (CSI.size()) {
// Find the instruction past the last instruction that saves a callee-saved
@@ -429,7 +429,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
// directives.
for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(),
E = CSI.end(); I != E; ++I) {
- int64_t Offset = MFI->getObjectOffset(I->getFrameIdx());
+ int64_t Offset = MFI.getObjectOffset(I->getFrameIdx());
unsigned Reg = I->getReg();
// If Reg is a double precision register, emit two cfa_offsets,
@@ -443,12 +443,12 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
if (!STI.isLittle())
std::swap(Reg0, Reg1);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg0, Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg1, Offset + 4));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -459,18 +459,18 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
if (!STI.isLittle())
std::swap(Reg0, Reg1);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg0, Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg1, Offset + 4));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
} else {
// Reg is either in GPR32 or FGR32.
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -489,9 +489,9 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
// Emit .cfi_offset directives for eh data registers.
for (int I = 0; I < 4; ++I) {
- int64_t Offset = MFI->getObjectOffset(MipsFI->getEhDataRegFI(I));
+ int64_t Offset = MFI.getObjectOffset(MipsFI->getEhDataRegFI(I));
unsigned Reg = MRI->getDwarfRegNum(ABI.GetEhDataReg(I), true);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -505,7 +505,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
.setMIFlag(MachineInstr::FrameSetup);
// emit ".cfi_def_cfa_register $fp"
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FP, true)));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -514,9 +514,9 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
// addiu $Reg, $zero, -MaxAlignment
// andi $sp, $sp, $Reg
unsigned VR = MF.getRegInfo().createVirtualRegister(RC);
- assert(isInt<16>(MFI->getMaxAlignment()) &&
+ assert(isInt<16>(MFI.getMaxAlignment()) &&
"Function's alignment size requirement is not supported.");
- int MaxAlign = -(int)MFI->getMaxAlignment();
+ int MaxAlign = -(int)MFI.getMaxAlignment();
BuildMI(MBB, MBBI, dl, TII.get(ADDiu), VR).addReg(ZERO) .addImm(MaxAlign);
BuildMI(MBB, MBBI, dl, TII.get(AND), SP).addReg(SP).addReg(VR);
@@ -664,7 +664,7 @@ void MipsSEFrameLowering::emitInterruptPrologueStub(
void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
const MipsSEInstrInfo &TII =
@@ -684,7 +684,7 @@ void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
// Find the first instruction that restores a callee-saved register.
MachineBasicBlock::iterator I = MBBI;
- for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i)
+ for (unsigned i = 0; i < MFI.getCalleeSavedInfo().size(); ++i)
--I;
// Insert instruction "move $sp, $fp" at this location.
@@ -697,7 +697,7 @@ void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
// Find first instruction that restores a callee-saved register.
MachineBasicBlock::iterator I = MBBI;
- for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i)
+ for (unsigned i = 0; i < MFI.getCalleeSavedInfo().size(); ++i)
--I;
// Insert instructions that restore eh data registers.
@@ -711,7 +711,7 @@ void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
emitInterruptEpilogueStub(MF, MBB);
// Get the number of bytes from FrameInfo
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
if (!StackSize)
return;
@@ -754,16 +754,16 @@ void MipsSEFrameLowering::emitInterruptEpilogueStub(
int MipsSEFrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI,
unsigned &FrameReg) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MipsABIInfo ABI = STI.getABI();
- if (MFI->isFixedObjectIndex(FI))
+ if (MFI.isFixedObjectIndex(FI))
FrameReg = hasFP(MF) ? ABI.GetFramePtr() : ABI.GetStackPtr();
else
FrameReg = hasBP(MF) ? ABI.GetBasePtr() : ABI.GetStackPtr();
- return MFI->getObjectOffset(FI) + MFI->getStackSize() -
- getOffsetOfLocalArea() + MFI->getOffsetAdjustment();
+ return MFI.getObjectOffset(FI) + MFI.getStackSize() -
+ getOffsetOfLocalArea() + MFI.getOffsetAdjustment();
}
bool MipsSEFrameLowering::
@@ -778,12 +778,12 @@ spillCalleeSavedRegisters(MachineBasicBlock &MBB,
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
// Add the callee-saved register as live-in. Do not add if the register is
// RA and return address is taken, because it has already been added in
- // method MipsTargetLowering::LowerRETURNADDR.
+ // method MipsTargetLowering::lowerRETURNADDR.
// It's killed at the spill, unless the register is RA and return address
// is taken.
unsigned Reg = CSI[i].getReg();
bool IsRAAndRetAddrIsTaken = (Reg == Mips::RA || Reg == Mips::RA_64)
- && MF->getFrameInfo()->isReturnAddressTaken();
+ && MF->getFrameInfo().isReturnAddressTaken();
if (!IsRAAndRetAddrIsTaken)
EntryBlock->addLiveIn(Reg);
@@ -819,14 +819,14 @@ spillCalleeSavedRegisters(MachineBasicBlock &MBB,
bool
MipsSEFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Reserve call frame if the size of the maximum call frame fits into 16-bit
// immediate field and there are no variable sized objects on the stack.
// Make sure the second register scavenger spill slot can be accessed with one
// instruction.
- return isInt<16>(MFI->getMaxCallFrameSize() + getStackAlignment()) &&
- !MFI->hasVarSizedObjects();
+ return isInt<16>(MFI.getMaxCallFrameSize() + getStackAlignment()) &&
+ !MFI.hasVarSizedObjects();
}
/// Mark \p Reg and all registers aliasing it in the bitset.
@@ -868,7 +868,7 @@ void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF,
// mips64, it should be 64-bit, otherwise it should be 32-bt.
const TargetRegisterClass *RC = STI.hasMips64() ?
&Mips::GPR64RegClass : &Mips::GPR32RegClass;
- int FI = MF.getFrameInfo()->CreateStackObject(RC->getSize(),
+ int FI = MF.getFrameInfo().CreateStackObject(RC->getSize(),
RC->getAlignment(), false);
RS->addScavengingFrameIndex(FI);
}
@@ -882,7 +882,7 @@ void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF,
const TargetRegisterClass *RC =
ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
- int FI = MF.getFrameInfo()->CreateStackObject(RC->getSize(),
+ int FI = MF.getFrameInfo().CreateStackObject(RC->getSize(),
RC->getAlignment(), false);
RS->addScavengingFrameIndex(FI);
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
index d9528da..92d3c00 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
@@ -28,6 +28,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
+#include "llvm/IR/Dominators.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -43,6 +44,11 @@ bool MipsSEDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
return MipsDAGToDAGISel::runOnMachineFunction(MF);
}
+void MipsSEDAGToDAGISel::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<DominatorTreeWrapperPass>();
+ SelectionDAGISel::getAnalysisUsage(AU);
+}
+
void MipsSEDAGToDAGISel::addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI,
MachineFunction &MF) {
MachineInstrBuilder MIB(MF, &MI);
@@ -293,20 +299,25 @@ bool MipsSEDAGToDAGISel::selectAddrFrameIndex(SDValue Addr, SDValue &Base,
}
/// Match frameindex+offset and frameindex|offset
-bool MipsSEDAGToDAGISel::selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base,
- SDValue &Offset,
- unsigned OffsetBits) const {
+bool MipsSEDAGToDAGISel::selectAddrFrameIndexOffset(
+ SDValue Addr, SDValue &Base, SDValue &Offset, unsigned OffsetBits,
+ unsigned ShiftAmount = 0) const {
if (CurDAG->isBaseWithConstantOffset(Addr)) {
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
- if (isIntN(OffsetBits, CN->getSExtValue())) {
+ if (isIntN(OffsetBits + ShiftAmount, CN->getSExtValue())) {
EVT ValTy = Addr.getValueType();
// If the first operand is a FI, get the TargetFI Node
- if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>
- (Addr.getOperand(0)))
+ if (FrameIndexSDNode *FIN =
+ dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
- else
+ else {
Base = Addr.getOperand(0);
+ // If base is a FI, additional offset calculation is done in
+ // eliminateFrameIndex, otherwise we need to check the alignment
+ if (OffsetToAlignment(CN->getZExtValue(), 1ull << ShiftAmount) != 0)
+ return false;
+ }
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
ValTy);
@@ -392,17 +403,6 @@ bool MipsSEDAGToDAGISel::selectAddrRegImm9(SDValue Addr, SDValue &Base,
return false;
}
-bool MipsSEDAGToDAGISel::selectAddrRegImm10(SDValue Addr, SDValue &Base,
- SDValue &Offset) const {
- if (selectAddrFrameIndex(Addr, Base, Offset))
- return true;
-
- if (selectAddrFrameIndexOffset(Addr, Base, Offset, 10))
- return true;
-
- return false;
-}
-
/// Used on microMIPS LWC2, LDC2, SWC2 and SDC2 instructions (11-bit offset)
bool MipsSEDAGToDAGISel::selectAddrRegImm11(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
@@ -478,15 +478,49 @@ bool MipsSEDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base,
return selectAddrDefault(Addr, Base, Offset);
}
-bool MipsSEDAGToDAGISel::selectIntAddrMSA(SDValue Addr, SDValue &Base,
- SDValue &Offset) const {
- if (selectAddrRegImm10(Addr, Base, Offset))
+bool MipsSEDAGToDAGISel::selectIntAddrSImm10(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+
+ if (selectAddrFrameIndex(Addr, Base, Offset))
return true;
- if (selectAddrDefault(Addr, Base, Offset))
+ if (selectAddrFrameIndexOffset(Addr, Base, Offset, 10))
return true;
- return false;
+ return selectAddrDefault(Addr, Base, Offset);
+}
+
+bool MipsSEDAGToDAGISel::selectIntAddrSImm10Lsl1(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+ if (selectAddrFrameIndex(Addr, Base, Offset))
+ return true;
+
+ if (selectAddrFrameIndexOffset(Addr, Base, Offset, 10, 1))
+ return true;
+
+ return selectAddrDefault(Addr, Base, Offset);
+}
+
+bool MipsSEDAGToDAGISel::selectIntAddrSImm10Lsl2(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+ if (selectAddrFrameIndex(Addr, Base, Offset))
+ return true;
+
+ if (selectAddrFrameIndexOffset(Addr, Base, Offset, 10, 2))
+ return true;
+
+ return selectAddrDefault(Addr, Base, Offset);
+}
+
+bool MipsSEDAGToDAGISel::selectIntAddrSImm10Lsl3(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const {
+ if (selectAddrFrameIndex(Addr, Base, Offset))
+ return true;
+
+ if (selectAddrFrameIndexOffset(Addr, Base, Offset, 10, 3))
+ return true;
+
+ return selectAddrDefault(Addr, Base, Offset);
}
// Select constant vector splats.
@@ -771,13 +805,13 @@ bool MipsSEDAGToDAGISel::trySelect(SDNode *Node) {
case ISD::Constant: {
const ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node);
+ int64_t Imm = CN->getSExtValue();
unsigned Size = CN->getValueSizeInBits(0);
- if (Size == 32)
+ if (isInt<32>(Imm))
break;
MipsAnalyzeImmediate AnalyzeImm;
- int64_t Imm = CN->getSExtValue();
const MipsAnalyzeImmediate::InstSeq &Seq =
AnalyzeImm.Analyze(Imm, Size, false);
diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h
index 0f08b72..f89a350 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h
+++ b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h
@@ -28,6 +28,8 @@ private:
bool runOnMachineFunction(MachineFunction &MF) override;
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+
void addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI,
MachineFunction &MF);
@@ -44,7 +46,8 @@ private:
bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset) const;
bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, SDValue &Offset,
- unsigned OffsetBits) const;
+ unsigned OffsetBits,
+ unsigned ShiftAmount) const;
bool selectAddrRegImm(SDValue Addr, SDValue &Base,
SDValue &Offset) const override;
@@ -58,9 +61,6 @@ private:
bool selectAddrRegImm9(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
- bool selectAddrRegImm10(SDValue Addr, SDValue &Base,
- SDValue &Offset) const;
-
bool selectAddrRegImm11(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
@@ -82,8 +82,17 @@ private:
bool selectIntAddrLSL2MM(SDValue Addr, SDValue &Base,
SDValue &Offset) const override;
- bool selectIntAddrMSA(SDValue Addr, SDValue &Base,
- SDValue &Offset) const override;
+ bool selectIntAddrSImm10(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const override;
+
+ bool selectIntAddrSImm10Lsl1(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const override;
+
+ bool selectIntAddrSImm10Lsl2(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const override;
+
+ bool selectIntAddrSImm10Lsl3(SDValue Addr, SDValue &Base,
+ SDValue &Offset) const override;
/// \brief Select constant vector splats.
bool selectVSplat(SDNode *N, APInt &Imm,
diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
index 80c000d..f28e8b3 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -14,11 +14,13 @@
#include "MipsMachineFunction.h"
#include "MipsRegisterInfo.h"
#include "MipsTargetMachine.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
@@ -27,8 +29,8 @@ using namespace llvm;
#define DEBUG_TYPE "mips-isel"
static cl::opt<bool>
-EnableMipsTailCalls("enable-mips-tail-calls", cl::Hidden,
- cl::desc("MIPS: Enable tail calls."), cl::init(false));
+UseMipsTailCalls("mips-tail-calls", cl::Hidden,
+ cl::desc("MIPS: permit tail calls."), cl::init(false));
static cl::opt<bool> NoDPLoadStore("mno-ldc1-sdc1", cl::init(false),
cl::desc("Expand double precision loads and "
@@ -92,6 +94,44 @@ MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM,
addMSAFloatType(MVT::v4f32, &Mips::MSA128WRegClass);
addMSAFloatType(MVT::v2f64, &Mips::MSA128DRegClass);
+ // f16 is a storage-only type, always promote it to f32.
+ addRegisterClass(MVT::f16, &Mips::MSA128HRegClass);
+ setOperationAction(ISD::SETCC, MVT::f16, Promote);
+ setOperationAction(ISD::BR_CC, MVT::f16, Promote);
+ setOperationAction(ISD::SELECT_CC, MVT::f16, Promote);
+ setOperationAction(ISD::SELECT, MVT::f16, Promote);
+ setOperationAction(ISD::FADD, MVT::f16, Promote);
+ setOperationAction(ISD::FSUB, MVT::f16, Promote);
+ setOperationAction(ISD::FMUL, MVT::f16, Promote);
+ setOperationAction(ISD::FDIV, MVT::f16, Promote);
+ setOperationAction(ISD::FREM, MVT::f16, Promote);
+ setOperationAction(ISD::FMA, MVT::f16, Promote);
+ setOperationAction(ISD::FNEG, MVT::f16, Promote);
+ setOperationAction(ISD::FABS, MVT::f16, Promote);
+ setOperationAction(ISD::FCEIL, MVT::f16, Promote);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f16, Promote);
+ setOperationAction(ISD::FCOS, MVT::f16, Promote);
+ setOperationAction(ISD::FP_EXTEND, MVT::f16, Promote);
+ setOperationAction(ISD::FFLOOR, MVT::f16, Promote);
+ setOperationAction(ISD::FNEARBYINT, MVT::f16, Promote);
+ setOperationAction(ISD::FPOW, MVT::f16, Promote);
+ setOperationAction(ISD::FPOWI, MVT::f16, Promote);
+ setOperationAction(ISD::FRINT, MVT::f16, Promote);
+ setOperationAction(ISD::FSIN, MVT::f16, Promote);
+ setOperationAction(ISD::FSINCOS, MVT::f16, Promote);
+ setOperationAction(ISD::FSQRT, MVT::f16, Promote);
+ setOperationAction(ISD::FEXP, MVT::f16, Promote);
+ setOperationAction(ISD::FEXP2, MVT::f16, Promote);
+ setOperationAction(ISD::FLOG, MVT::f16, Promote);
+ setOperationAction(ISD::FLOG2, MVT::f16, Promote);
+ setOperationAction(ISD::FLOG10, MVT::f16, Promote);
+ setOperationAction(ISD::FROUND, MVT::f16, Promote);
+ setOperationAction(ISD::FTRUNC, MVT::f16, Promote);
+ setOperationAction(ISD::FMINNUM, MVT::f16, Promote);
+ setOperationAction(ISD::FMAXNUM, MVT::f16, Promote);
+ setOperationAction(ISD::FMINNAN, MVT::f16, Promote);
+ setOperationAction(ISD::FMAXNAN, MVT::f16, Promote);
+
setTargetDAGCombine(ISD::AND);
setTargetDAGCombine(ISD::OR);
setTargetDAGCombine(ISD::SRA);
@@ -852,7 +892,7 @@ static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty,
APInt SplatValue, SplatUndef;
unsigned SplatBitSize;
bool HasAnyUndefs;
- unsigned EltSize = Ty.getVectorElementType().getSizeInBits();
+ unsigned EltSize = Ty.getScalarSizeInBits();
BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N->getOperand(1));
if (!Subtarget.hasDSP())
@@ -1172,13 +1212,25 @@ MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
return emitFEXP2_W_1(MI, BB);
case Mips::FEXP2_D_1_PSEUDO:
return emitFEXP2_D_1(MI, BB);
+ case Mips::ST_F16:
+ return emitST_F16_PSEUDO(MI, BB);
+ case Mips::LD_F16:
+ return emitLD_F16_PSEUDO(MI, BB);
+ case Mips::MSA_FP_EXTEND_W_PSEUDO:
+ return emitFPEXTEND_PSEUDO(MI, BB, false);
+ case Mips::MSA_FP_ROUND_W_PSEUDO:
+ return emitFPROUND_PSEUDO(MI, BB, false);
+ case Mips::MSA_FP_EXTEND_D_PSEUDO:
+ return emitFPEXTEND_PSEUDO(MI, BB, true);
+ case Mips::MSA_FP_ROUND_D_PSEUDO:
+ return emitFPROUND_PSEUDO(MI, BB, true);
}
}
bool MipsSETargetLowering::isEligibleForTailCallOptimization(
const CCState &CCInfo, unsigned NextStackOffset,
const MipsFunctionInfo &FI) const {
- if (!EnableMipsTailCalls)
+ if (!UseMipsTailCalls)
return false;
// Exception has to be cleared with eret.
@@ -1406,9 +1458,12 @@ static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) {
return Result;
}
-static SDValue lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG) {
- return DAG.getConstant(Op->getConstantOperandVal(ImmOp), SDLoc(Op),
- Op->getValueType(0));
+static SDValue lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG,
+ bool IsSigned = false) {
+ return DAG.getConstant(
+ APInt(Op->getValueType(0).getScalarType().getSizeInBits(),
+ Op->getConstantOperandVal(ImmOp), IsSigned),
+ SDLoc(Op), Op->getValueType(0));
}
static SDValue getBuildVectorSplat(EVT VecTy, SDValue SplatValue,
@@ -1504,7 +1559,7 @@ static SDValue lowerMSABitClear(SDValue Op, SelectionDAG &DAG) {
static SDValue lowerMSABitClearImm(SDValue Op, SelectionDAG &DAG) {
SDLoc DL(Op);
EVT ResTy = Op->getValueType(0);
- APInt BitImm = APInt(ResTy.getVectorElementType().getSizeInBits(), 1)
+ APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1)
<< cast<ConstantSDNode>(Op->getOperand(2))->getAPIntValue();
SDValue BitMask = DAG.getConstant(~BitImm, DL, ResTy);
@@ -1514,8 +1569,8 @@ static SDValue lowerMSABitClearImm(SDValue Op, SelectionDAG &DAG) {
SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
-
- switch (cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue()) {
+ unsigned Intrinsic = cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue();
+ switch (Intrinsic) {
default:
return SDValue();
case Intrinsic::mips_shilo:
@@ -1585,6 +1640,8 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
// binsli_x(IfClear, IfSet, nbits) -> (vselect LBitsMask, IfSet, IfClear)
EVT VecTy = Op->getValueType(0);
EVT EltTy = VecTy.getVectorElementType();
+ if (Op->getConstantOperandVal(3) >= EltTy.getSizeInBits())
+ report_fatal_error("Immediate out of range");
APInt Mask = APInt::getHighBitsSet(EltTy.getSizeInBits(),
Op->getConstantOperandVal(3));
return DAG.getNode(ISD::VSELECT, DL, VecTy,
@@ -1598,6 +1655,8 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
// binsri_x(IfClear, IfSet, nbits) -> (vselect RBitsMask, IfSet, IfClear)
EVT VecTy = Op->getValueType(0);
EVT EltTy = VecTy.getVectorElementType();
+ if (Op->getConstantOperandVal(3) >= EltTy.getSizeInBits())
+ report_fatal_error("Immediate out of range");
APInt Mask = APInt::getLowBitsSet(EltTy.getSizeInBits(),
Op->getConstantOperandVal(3));
return DAG.getNode(ISD::VSELECT, DL, VecTy,
@@ -1691,7 +1750,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_ceqi_w:
case Intrinsic::mips_ceqi_d:
return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
- lowerMSASplatImm(Op, 2, DAG), ISD::SETEQ);
+ lowerMSASplatImm(Op, 2, DAG, true), ISD::SETEQ);
case Intrinsic::mips_cle_s_b:
case Intrinsic::mips_cle_s_h:
case Intrinsic::mips_cle_s_w:
@@ -1703,7 +1762,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_clei_s_w:
case Intrinsic::mips_clei_s_d:
return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
- lowerMSASplatImm(Op, 2, DAG), ISD::SETLE);
+ lowerMSASplatImm(Op, 2, DAG, true), ISD::SETLE);
case Intrinsic::mips_cle_u_b:
case Intrinsic::mips_cle_u_h:
case Intrinsic::mips_cle_u_w:
@@ -1727,7 +1786,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_clti_s_w:
case Intrinsic::mips_clti_s_d:
return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
- lowerMSASplatImm(Op, 2, DAG), ISD::SETLT);
+ lowerMSASplatImm(Op, 2, DAG, true), ISD::SETLT);
case Intrinsic::mips_clt_u_b:
case Intrinsic::mips_clt_u_h:
case Intrinsic::mips_clt_u_w:
@@ -1940,15 +1999,28 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_insve_b:
case Intrinsic::mips_insve_h:
case Intrinsic::mips_insve_w:
- case Intrinsic::mips_insve_d:
+ case Intrinsic::mips_insve_d: {
+ // Report an error for out of range values.
+ int64_t Max;
+ switch (Intrinsic) {
+ case Intrinsic::mips_insve_b: Max = 15; break;
+ case Intrinsic::mips_insve_h: Max = 7; break;
+ case Intrinsic::mips_insve_w: Max = 3; break;
+ case Intrinsic::mips_insve_d: Max = 1; break;
+ default: llvm_unreachable("Unmatched intrinsic");
+ }
+ int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
+ if (Value < 0 || Value > Max)
+ report_fatal_error("Immediate out of range");
return DAG.getNode(MipsISD::INSVE, DL, Op->getValueType(0),
Op->getOperand(1), Op->getOperand(2), Op->getOperand(3),
DAG.getConstant(0, DL, MVT::i32));
+ }
case Intrinsic::mips_ldi_b:
case Intrinsic::mips_ldi_h:
case Intrinsic::mips_ldi_w:
case Intrinsic::mips_ldi_d:
- return lowerMSASplatImm(Op, 1, DAG);
+ return lowerMSASplatImm(Op, 1, DAG, true);
case Intrinsic::mips_lsa:
case Intrinsic::mips_dlsa: {
EVT ResTy = Op->getValueType(0);
@@ -1982,7 +2054,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_maxi_s_w:
case Intrinsic::mips_maxi_s_d:
return DAG.getNode(MipsISD::VSMAX, DL, Op->getValueType(0),
- Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
+ Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG, true));
case Intrinsic::mips_maxi_u_b:
case Intrinsic::mips_maxi_u_h:
case Intrinsic::mips_maxi_u_w:
@@ -2006,7 +2078,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_mini_s_w:
case Intrinsic::mips_mini_s_d:
return DAG.getNode(MipsISD::VSMIN, DL, Op->getValueType(0),
- Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
+ Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG, true));
case Intrinsic::mips_mini_u_b:
case Intrinsic::mips_mini_u_h:
case Intrinsic::mips_mini_u_w:
@@ -2079,11 +2151,59 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_pcnt_w:
case Intrinsic::mips_pcnt_d:
return DAG.getNode(ISD::CTPOP, DL, Op->getValueType(0), Op->getOperand(1));
+ case Intrinsic::mips_sat_s_b:
+ case Intrinsic::mips_sat_s_h:
+ case Intrinsic::mips_sat_s_w:
+ case Intrinsic::mips_sat_s_d:
+ case Intrinsic::mips_sat_u_b:
+ case Intrinsic::mips_sat_u_h:
+ case Intrinsic::mips_sat_u_w:
+ case Intrinsic::mips_sat_u_d: {
+ // Report an error for out of range values.
+ int64_t Max;
+ switch (Intrinsic) {
+ case Intrinsic::mips_sat_s_b:
+ case Intrinsic::mips_sat_u_b: Max = 7; break;
+ case Intrinsic::mips_sat_s_h:
+ case Intrinsic::mips_sat_u_h: Max = 15; break;
+ case Intrinsic::mips_sat_s_w:
+ case Intrinsic::mips_sat_u_w: Max = 31; break;
+ case Intrinsic::mips_sat_s_d:
+ case Intrinsic::mips_sat_u_d: Max = 63; break;
+ default: llvm_unreachable("Unmatched intrinsic");
+ }
+ int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
+ if (Value < 0 || Value > Max)
+ report_fatal_error("Immediate out of range");
+ return SDValue();
+ }
case Intrinsic::mips_shf_b:
case Intrinsic::mips_shf_h:
- case Intrinsic::mips_shf_w:
+ case Intrinsic::mips_shf_w: {
+ int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
+ if (Value < 0 || Value > 255)
+ report_fatal_error("Immediate out of range");
return DAG.getNode(MipsISD::SHF, DL, Op->getValueType(0),
Op->getOperand(2), Op->getOperand(1));
+ }
+ case Intrinsic::mips_sldi_b:
+ case Intrinsic::mips_sldi_h:
+ case Intrinsic::mips_sldi_w:
+ case Intrinsic::mips_sldi_d: {
+ // Report an error for out of range values.
+ int64_t Max;
+ switch (Intrinsic) {
+ case Intrinsic::mips_sldi_b: Max = 15; break;
+ case Intrinsic::mips_sldi_h: Max = 7; break;
+ case Intrinsic::mips_sldi_w: Max = 3; break;
+ case Intrinsic::mips_sldi_d: Max = 1; break;
+ default: llvm_unreachable("Unmatched intrinsic");
+ }
+ int64_t Value = cast<ConstantSDNode>(Op->getOperand(3))->getSExtValue();
+ if (Value < 0 || Value > Max)
+ report_fatal_error("Immediate out of range");
+ return SDValue();
+ }
case Intrinsic::mips_sll_b:
case Intrinsic::mips_sll_h:
case Intrinsic::mips_sll_w:
@@ -2126,6 +2246,24 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_srai_d:
return DAG.getNode(ISD::SRA, DL, Op->getValueType(0),
Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
+ case Intrinsic::mips_srari_b:
+ case Intrinsic::mips_srari_h:
+ case Intrinsic::mips_srari_w:
+ case Intrinsic::mips_srari_d: {
+ // Report an error for out of range values.
+ int64_t Max;
+ switch (Intrinsic) {
+ case Intrinsic::mips_srari_b: Max = 7; break;
+ case Intrinsic::mips_srari_h: Max = 15; break;
+ case Intrinsic::mips_srari_w: Max = 31; break;
+ case Intrinsic::mips_srari_d: Max = 63; break;
+ default: llvm_unreachable("Unmatched intrinsic");
+ }
+ int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
+ if (Value < 0 || Value > Max)
+ report_fatal_error("Immediate out of range");
+ return SDValue();
+ }
case Intrinsic::mips_srl_b:
case Intrinsic::mips_srl_h:
case Intrinsic::mips_srl_w:
@@ -2138,6 +2276,24 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
case Intrinsic::mips_srli_d:
return DAG.getNode(ISD::SRL, DL, Op->getValueType(0),
Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
+ case Intrinsic::mips_srlri_b:
+ case Intrinsic::mips_srlri_h:
+ case Intrinsic::mips_srlri_w:
+ case Intrinsic::mips_srlri_d: {
+ // Report an error for out of range values.
+ int64_t Max;
+ switch (Intrinsic) {
+ case Intrinsic::mips_srlri_b: Max = 7; break;
+ case Intrinsic::mips_srlri_h: Max = 15; break;
+ case Intrinsic::mips_srlri_w: Max = 31; break;
+ case Intrinsic::mips_srlri_d: Max = 63; break;
+ default: llvm_unreachable("Unmatched intrinsic");
+ }
+ int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
+ if (Value < 0 || Value > Max)
+ report_fatal_error("Immediate out of range");
+ return SDValue();
+ }
case Intrinsic::mips_subv_b:
case Intrinsic::mips_subv_h:
case Intrinsic::mips_subv_w:
@@ -2169,7 +2325,8 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
}
}
-static SDValue lowerMSALoadIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) {
+static SDValue lowerMSALoadIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr,
+ const MipsSubtarget &Subtarget) {
SDLoc DL(Op);
SDValue ChainIn = Op->getOperand(0);
SDValue Address = Op->getOperand(2);
@@ -2177,6 +2334,12 @@ static SDValue lowerMSALoadIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) {
EVT ResTy = Op->getValueType(0);
EVT PtrTy = Address->getValueType(0);
+ // For N64 addresses have the underlying type MVT::i64. This intrinsic
+ // however takes an i32 signed constant offset. The actual type of the
+ // intrinsic is a scaled signed i10.
+ if (Subtarget.isABI_N64())
+ Offset = DAG.getNode(ISD::SIGN_EXTEND, DL, PtrTy, Offset);
+
Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset);
return DAG.getLoad(ResTy, DL, ChainIn, Address, MachinePointerInfo(),
/* Alignment = */ 16);
@@ -2232,11 +2395,12 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
case Intrinsic::mips_ld_h:
case Intrinsic::mips_ld_w:
case Intrinsic::mips_ld_d:
- return lowerMSALoadIntr(Op, DAG, Intr);
+ return lowerMSALoadIntr(Op, DAG, Intr, Subtarget);
}
}
-static SDValue lowerMSAStoreIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) {
+static SDValue lowerMSAStoreIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr,
+ const MipsSubtarget &Subtarget) {
SDLoc DL(Op);
SDValue ChainIn = Op->getOperand(0);
SDValue Value = Op->getOperand(2);
@@ -2244,6 +2408,12 @@ static SDValue lowerMSAStoreIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) {
SDValue Offset = Op->getOperand(4);
EVT PtrTy = Address->getValueType(0);
+ // For N64 addresses have the underlying type MVT::i64. This intrinsic
+ // however takes an i32 signed constant offset. The actual type of the
+ // intrinsic is a scaled signed i10.
+ if (Subtarget.isABI_N64())
+ Offset = DAG.getNode(ISD::SIGN_EXTEND, DL, PtrTy, Offset);
+
Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset);
return DAG.getStore(ChainIn, DL, Value, Address, MachinePointerInfo(),
@@ -2260,7 +2430,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_VOID(SDValue Op,
case Intrinsic::mips_st_h:
case Intrinsic::mips_st_w:
case Intrinsic::mips_st_d:
- return lowerMSAStoreIntr(Op, DAG, Intr);
+ return lowerMSAStoreIntr(Op, DAG, Intr, Subtarget);
}
}
@@ -3327,8 +3497,12 @@ MipsSETargetLowering::emitFILL_FW(MachineInstr &MI,
DebugLoc DL = MI.getDebugLoc();
unsigned Wd = MI.getOperand(0).getReg();
unsigned Fs = MI.getOperand(1).getReg();
- unsigned Wt1 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
- unsigned Wt2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
+ unsigned Wt1 = RegInfo.createVirtualRegister(
+ Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass
+ : &Mips::MSA128WEvensRegClass);
+ unsigned Wt2 = RegInfo.createVirtualRegister(
+ Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass
+ : &Mips::MSA128WEvensRegClass);
BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1);
BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2)
@@ -3372,6 +3546,304 @@ MipsSETargetLowering::emitFILL_FD(MachineInstr &MI,
return BB;
}
+// Emit the ST_F16_PSEDUO instruction to store a f16 value from an MSA
+// register.
+//
+// STF16 MSA128F16:$wd, mem_simm10:$addr
+// =>
+// copy_u.h $rtemp,$wd[0]
+// sh $rtemp, $addr
+//
+// Safety: We can't use st.h & co as they would over write the memory after
+// the destination. It would require half floats be allocated 16 bytes(!) of
+// space.
+MachineBasicBlock *
+MipsSETargetLowering::emitST_F16_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ unsigned Ws = MI.getOperand(0).getReg();
+ unsigned Rt = MI.getOperand(1).getReg();
+ const MachineMemOperand &MMO = **MI.memoperands_begin();
+ unsigned Imm = MMO.getOffset();
+
+ // Caution: A load via the GOT can expand to a GPR32 operand, a load via
+ // spill and reload can expand as a GPR64 operand. Examine the
+ // operand in detail and default to ABI.
+ const TargetRegisterClass *RC =
+ MI.getOperand(1).isReg() ? RegInfo.getRegClass(MI.getOperand(1).getReg())
+ : (Subtarget.isABI_O32() ? &Mips::GPR32RegClass
+ : &Mips::GPR64RegClass);
+ const bool UsingMips32 = RC == &Mips::GPR32RegClass;
+ unsigned Rs = RegInfo.createVirtualRegister(RC);
+
+ BuildMI(*BB, MI, DL, TII->get(Mips::COPY_U_H), Rs).addReg(Ws).addImm(0);
+ BuildMI(*BB, MI, DL, TII->get(UsingMips32 ? Mips::SH : Mips::SH64))
+ .addReg(Rs)
+ .addReg(Rt)
+ .addImm(Imm)
+ .addMemOperand(BB->getParent()->getMachineMemOperand(
+ &MMO, MMO.getOffset(), MMO.getSize()));
+
+ MI.eraseFromParent();
+ return BB;
+}
+
+// Emit the LD_F16_PSEDUO instruction to load a f16 value into an MSA register.
+//
+// LD_F16 MSA128F16:$wd, mem_simm10:$addr
+// =>
+// lh $rtemp, $addr
+// fill.h $wd, $rtemp
+//
+// Safety: We can't use ld.h & co as they over-read from the source.
+// Additionally, if the address is not modulo 16, 2 cases can occur:
+// a) Segmentation fault as the load instruction reads from a memory page
+// memory it's not supposed to.
+// b) The load crosses an implementation specific boundary, requiring OS
+// intervention.
+//
+MachineBasicBlock *
+MipsSETargetLowering::emitLD_F16_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ unsigned Wd = MI.getOperand(0).getReg();
+
+ // Caution: A load via the GOT can expand to a GPR32 operand, a load via
+ // spill and reload can expand as a GPR64 operand. Examine the
+ // operand in detail and default to ABI.
+ const TargetRegisterClass *RC =
+ MI.getOperand(1).isReg() ? RegInfo.getRegClass(MI.getOperand(1).getReg())
+ : (Subtarget.isABI_O32() ? &Mips::GPR32RegClass
+ : &Mips::GPR64RegClass);
+
+ const bool UsingMips32 = RC == &Mips::GPR32RegClass;
+ unsigned Rt = RegInfo.createVirtualRegister(RC);
+
+ MachineInstrBuilder MIB =
+ BuildMI(*BB, MI, DL, TII->get(UsingMips32 ? Mips::LH : Mips::LH64), Rt);
+ for (unsigned i = 1; i < MI.getNumOperands(); i++)
+ MIB.addOperand(MI.getOperand(i));
+
+ BuildMI(*BB, MI, DL, TII->get(Mips::FILL_H), Wd).addReg(Rt);
+
+ MI.eraseFromParent();
+ return BB;
+}
+
+// Emit the FPROUND_PSEUDO instruction.
+//
+// Round an FGR64Opnd, FGR32Opnd to an f16.
+//
+// Safety: Cycle the operand through the GPRs so the result always ends up
+// the correct MSA register.
+//
+// FIXME: This copying is strictly unnecessary. If we could tie FGR32Opnd:$Fs
+// / FGR64Opnd:$Fs and MSA128F16:$Wd to the same physical register
+// (which they can be, as the MSA registers are defined to alias the
+// FPU's 64 bit and 32 bit registers) the result can be accessed using
+// the correct register class. That requires operands be tie-able across
+// register classes which have a sub/super register class relationship.
+//
+// For FPG32Opnd:
+//
+// FPROUND MSA128F16:$wd, FGR32Opnd:$fs
+// =>
+// mfc1 $rtemp, $fs
+// fill.w $rtemp, $wtemp
+// fexdo.w $wd, $wtemp, $wtemp
+//
+// For FPG64Opnd on mips32r2+:
+//
+// FPROUND MSA128F16:$wd, FGR64Opnd:$fs
+// =>
+// mfc1 $rtemp, $fs
+// fill.w $rtemp, $wtemp
+// mfhc1 $rtemp2, $fs
+// insert.w $wtemp[1], $rtemp2
+// insert.w $wtemp[3], $rtemp2
+// fexdo.w $wtemp2, $wtemp, $wtemp
+// fexdo.h $wd, $temp2, $temp2
+//
+// For FGR64Opnd on mips64r2+:
+//
+// FPROUND MSA128F16:$wd, FGR64Opnd:$fs
+// =>
+// dmfc1 $rtemp, $fs
+// fill.d $rtemp, $wtemp
+// fexdo.w $wtemp2, $wtemp, $wtemp
+// fexdo.h $wd, $wtemp2, $wtemp2
+//
+// Safety note: As $wtemp is UNDEF, we may provoke a spurious exception if the
+// undef bits are "just right" and the exception enable bits are
+// set. By using fill.w to replicate $fs into all elements over
+// insert.w for one element, we avoid that potiential case. If
+// fexdo.[hw] causes an exception in, the exception is valid and it
+// occurs for all elements.
+//
+MachineBasicBlock *
+MipsSETargetLowering::emitFPROUND_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB,
+ bool IsFGR64) const {
+
+ // Strictly speaking, we need MIPS32R5 to support MSA. We'll be generous
+ // here. It's technically doable to support MIPS32 here, but the ISA forbids
+ // it.
+ assert(Subtarget.hasMSA() && Subtarget.hasMips32r2());
+
+ bool IsFGR64onMips64 = Subtarget.hasMips64() && IsFGR64;
+
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ unsigned Wd = MI.getOperand(0).getReg();
+ unsigned Fs = MI.getOperand(1).getReg();
+
+ MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
+ unsigned Wtemp = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
+ const TargetRegisterClass *GPRRC =
+ IsFGR64onMips64 ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
+ unsigned MFC1Opc = IsFGR64onMips64 ? Mips::DMFC1 : Mips::MFC1;
+ unsigned FILLOpc = IsFGR64onMips64 ? Mips::FILL_D : Mips::FILL_W;
+
+ // Perform the register class copy as mentioned above.
+ unsigned Rtemp = RegInfo.createVirtualRegister(GPRRC);
+ BuildMI(*BB, MI, DL, TII->get(MFC1Opc), Rtemp).addReg(Fs);
+ BuildMI(*BB, MI, DL, TII->get(FILLOpc), Wtemp).addReg(Rtemp);
+ unsigned WPHI = Wtemp;
+
+ if (!Subtarget.hasMips64() && IsFGR64) {
+ unsigned Rtemp2 = RegInfo.createVirtualRegister(GPRRC);
+ BuildMI(*BB, MI, DL, TII->get(Mips::MFHC1_D64), Rtemp2).addReg(Fs);
+ unsigned Wtemp2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
+ unsigned Wtemp3 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
+ BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_W), Wtemp2)
+ .addReg(Wtemp)
+ .addReg(Rtemp2)
+ .addImm(1);
+ BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_W), Wtemp3)
+ .addReg(Wtemp2)
+ .addReg(Rtemp2)
+ .addImm(3);
+ WPHI = Wtemp3;
+ }
+
+ if (IsFGR64) {
+ unsigned Wtemp2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
+ BuildMI(*BB, MI, DL, TII->get(Mips::FEXDO_W), Wtemp2)
+ .addReg(WPHI)
+ .addReg(WPHI);
+ WPHI = Wtemp2;
+ }
+
+ BuildMI(*BB, MI, DL, TII->get(Mips::FEXDO_H), Wd).addReg(WPHI).addReg(WPHI);
+
+ MI.eraseFromParent();
+ return BB;
+}
+
+// Emit the FPEXTEND_PSEUDO instruction.
+//
+// Expand an f16 to either a FGR32Opnd or FGR64Opnd.
+//
+// Safety: Cycle the result through the GPRs so the result always ends up
+// the correct floating point register.
+//
+// FIXME: This copying is strictly unnecessary. If we could tie FGR32Opnd:$Fd
+// / FGR64Opnd:$Fd and MSA128F16:$Ws to the same physical register
+// (which they can be, as the MSA registers are defined to alias the
+// FPU's 64 bit and 32 bit registers) the result can be accessed using
+// the correct register class. That requires operands be tie-able across
+// register classes which have a sub/super register class relationship. I
+// haven't checked.
+//
+// For FGR32Opnd:
+//
+// FPEXTEND FGR32Opnd:$fd, MSA128F16:$ws
+// =>
+// fexupr.w $wtemp, $ws
+// copy_s.w $rtemp, $ws[0]
+// mtc1 $rtemp, $fd
+//
+// For FGR64Opnd on Mips64:
+//
+// FPEXTEND FGR64Opnd:$fd, MSA128F16:$ws
+// =>
+// fexupr.w $wtemp, $ws
+// fexupr.d $wtemp2, $wtemp
+// copy_s.d $rtemp, $wtemp2s[0]
+// dmtc1 $rtemp, $fd
+//
+// For FGR64Opnd on Mips32:
+//
+// FPEXTEND FGR64Opnd:$fd, MSA128F16:$ws
+// =>
+// fexupr.w $wtemp, $ws
+// fexupr.d $wtemp2, $wtemp
+// copy_s.w $rtemp, $wtemp2[0]
+// mtc1 $rtemp, $ftemp
+// copy_s.w $rtemp2, $wtemp2[1]
+// $fd = mthc1 $rtemp2, $ftemp
+//
+MachineBasicBlock *
+MipsSETargetLowering::emitFPEXTEND_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB,
+ bool IsFGR64) const {
+
+ // Strictly speaking, we need MIPS32R5 to support MSA. We'll be generous
+ // here. It's technically doable to support MIPS32 here, but the ISA forbids
+ // it.
+ assert(Subtarget.hasMSA() && Subtarget.hasMips32r2());
+
+ bool IsFGR64onMips64 = Subtarget.hasMips64() && IsFGR64;
+ bool IsFGR64onMips32 = !Subtarget.hasMips64() && IsFGR64;
+
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+ unsigned Fd = MI.getOperand(0).getReg();
+ unsigned Ws = MI.getOperand(1).getReg();
+
+ MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
+ const TargetRegisterClass *GPRRC =
+ IsFGR64onMips64 ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
+ unsigned MTC1Opc = IsFGR64onMips64 ? Mips::DMTC1 : Mips::MTC1;
+ unsigned COPYOpc = IsFGR64onMips64 ? Mips::COPY_S_D : Mips::COPY_S_W;
+
+ unsigned Wtemp = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
+ unsigned WPHI = Wtemp;
+
+ BuildMI(*BB, MI, DL, TII->get(Mips::FEXUPR_W), Wtemp).addReg(Ws);
+ if (IsFGR64) {
+ WPHI = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass);
+ BuildMI(*BB, MI, DL, TII->get(Mips::FEXUPR_D), WPHI).addReg(Wtemp);
+ }
+
+ // Perform the safety regclass copy mentioned above.
+ unsigned Rtemp = RegInfo.createVirtualRegister(GPRRC);
+ unsigned FPRPHI = IsFGR64onMips32
+ ? RegInfo.createVirtualRegister(&Mips::FGR64RegClass)
+ : Fd;
+ BuildMI(*BB, MI, DL, TII->get(COPYOpc), Rtemp).addReg(WPHI).addImm(0);
+ BuildMI(*BB, MI, DL, TII->get(MTC1Opc), FPRPHI).addReg(Rtemp);
+
+ if (IsFGR64onMips32) {
+ unsigned Rtemp2 = RegInfo.createVirtualRegister(GPRRC);
+ BuildMI(*BB, MI, DL, TII->get(Mips::COPY_S_W), Rtemp2)
+ .addReg(WPHI)
+ .addImm(1);
+ BuildMI(*BB, MI, DL, TII->get(Mips::MTHC1_D64), Fd)
+ .addReg(FPRPHI)
+ .addReg(Rtemp2);
+ }
+
+ MI.eraseFromParent();
+ return BB;
+}
+
// Emit the FEXP2_W_1 pseudo instructions.
//
// fexp2_w_1_pseudo $wd, $wt
diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h
index 5415466..0abb9b3 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h
+++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h
@@ -111,6 +111,20 @@ namespace llvm {
/// \brief Emit the FEXP2_D_1 pseudo instructions.
MachineBasicBlock *emitFEXP2_D_1(MachineInstr &MI,
MachineBasicBlock *BB) const;
+ /// \brief Emit the FILL_FW pseudo instruction
+ MachineBasicBlock *emitLD_F16_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB) const;
+ /// \brief Emit the FILL_FD pseudo instruction
+ MachineBasicBlock *emitST_F16_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB) const;
+ /// \brief Emit the FEXP2_W_1 pseudo instructions.
+ MachineBasicBlock *emitFPEXTEND_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BB,
+ bool IsFGR64) const;
+ /// \brief Emit the FEXP2_D_1 pseudo instructions.
+ MachineBasicBlock *emitFPROUND_PSEUDO(MachineInstr &MI,
+ MachineBasicBlock *BBi,
+ bool IsFGR64) const;
};
}
diff --git a/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
index 29107b2..ea703d0 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
@@ -408,7 +408,9 @@ unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const {
switch (Opc) {
default: llvm_unreachable("Illegal opcode!");
case Mips::BEQ: return Mips::BNE;
+ case Mips::BEQ_MM: return Mips::BNE_MM;
case Mips::BNE: return Mips::BEQ;
+ case Mips::BNE_MM: return Mips::BEQ_MM;
case Mips::BGTZ: return Mips::BLEZ;
case Mips::BGEZ: return Mips::BLTZ;
case Mips::BLTZ: return Mips::BGEZ;
@@ -431,6 +433,18 @@ unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const {
case Mips::BGEZC: return Mips::BLTZC;
case Mips::BLTZC: return Mips::BGEZC;
case Mips::BLEZC: return Mips::BGTZC;
+ case Mips::BEQZC64: return Mips::BNEZC64;
+ case Mips::BNEZC64: return Mips::BEQZC64;
+ case Mips::BEQC64: return Mips::BNEC64;
+ case Mips::BNEC64: return Mips::BEQC64;
+ case Mips::BGEC64: return Mips::BLTC64;
+ case Mips::BGEUC64: return Mips::BLTUC64;
+ case Mips::BLTC64: return Mips::BGEC64;
+ case Mips::BLTUC64: return Mips::BGEUC64;
+ case Mips::BGTZC64: return Mips::BLEZC64;
+ case Mips::BGEZC64: return Mips::BLTZC64;
+ case Mips::BLTZC64: return Mips::BGEZC64;
+ case Mips::BLEZC64: return Mips::BGTZC64;
}
}
@@ -506,17 +520,22 @@ unsigned MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
}
unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
- return (Opc == Mips::BEQ || Opc == Mips::BNE || Opc == Mips::BGTZ ||
- Opc == Mips::BGEZ || Opc == Mips::BLTZ || Opc == Mips::BLEZ ||
- Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 ||
- Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 ||
- Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B ||
- Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM ||
- Opc == Mips::BEQC || Opc == Mips::BNEC || Opc == Mips::BLTC ||
- Opc == Mips::BGEC || Opc == Mips::BLTUC || Opc == Mips::BGEUC ||
- Opc == Mips::BGTZC || Opc == Mips::BLEZC || Opc == Mips::BGEZC ||
- Opc == Mips::BLTZC || Opc == Mips::BEQZC || Opc == Mips::BNEZC ||
- Opc == Mips::BC) ? Opc : 0;
+ return (Opc == Mips::BEQ || Opc == Mips::BEQ_MM || Opc == Mips::BNE ||
+ Opc == Mips::BNE_MM || Opc == Mips::BGTZ || Opc == Mips::BGEZ ||
+ Opc == Mips::BLTZ || Opc == Mips::BLEZ || Opc == Mips::BEQ64 ||
+ Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || Opc == Mips::BGEZ64 ||
+ Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || Opc == Mips::BC1T ||
+ Opc == Mips::BC1F || Opc == Mips::B || Opc == Mips::J ||
+ Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM || Opc == Mips::BEQC ||
+ Opc == Mips::BNEC || Opc == Mips::BLTC || Opc == Mips::BGEC ||
+ Opc == Mips::BLTUC || Opc == Mips::BGEUC || Opc == Mips::BGTZC ||
+ Opc == Mips::BLEZC || Opc == Mips::BGEZC || Opc == Mips::BLTZC ||
+ Opc == Mips::BEQZC || Opc == Mips::BNEZC || Opc == Mips::BEQZC64 ||
+ Opc == Mips::BNEZC64 || Opc == Mips::BEQC64 || Opc == Mips::BNEC64 ||
+ Opc == Mips::BGEC64 || Opc == Mips::BGEUC64 || Opc == Mips::BLTC64 ||
+ Opc == Mips::BLTUC64 || Opc == Mips::BGTZC64 ||
+ Opc == Mips::BGEZC64 || Opc == Mips::BLTZC64 ||
+ Opc == Mips::BLEZC64 || Opc == Mips::BC) ? Opc : 0;
}
void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB,
diff --git a/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp
index e3431cd..86bd241 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp
@@ -149,7 +149,7 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
int64_t SPOffset) const {
MachineInstr &MI = *II;
MachineFunction &MF = *MI.getParent()->getParent();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
MipsABIInfo ABI =
@@ -157,7 +157,7 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
const MipsRegisterInfo *RegInfo =
static_cast<const MipsRegisterInfo *>(MF.getSubtarget().getRegisterInfo());
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
int MinCSFI = 0;
int MaxCSFI = -1;
@@ -182,9 +182,9 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
IsISRRegFI)
FrameReg = ABI.GetStackPtr();
else if (RegInfo->needsStackRealignment(MF)) {
- if (MFI->hasVarSizedObjects() && !MFI->isFixedObjectIndex(FrameIndex))
+ if (MFI.hasVarSizedObjects() && !MFI.isFixedObjectIndex(FrameIndex))
FrameReg = ABI.GetBasePtr();
- else if (MFI->isFixedObjectIndex(FrameIndex))
+ else if (MFI.isFixedObjectIndex(FrameIndex))
FrameReg = getFrameRegister(MF);
else
FrameReg = ABI.GetStackPtr();
diff --git a/contrib/llvm/lib/Target/Mips/MipsSchedule.td b/contrib/llvm/lib/Target/Mips/MipsSchedule.td
index 738b6c4..c0de59b 100644
--- a/contrib/llvm/lib/Target/Mips/MipsSchedule.td
+++ b/contrib/llvm/lib/Target/Mips/MipsSchedule.td
@@ -44,6 +44,7 @@ def II_BC1FL : InstrItinClass;
def II_BC1T : InstrItinClass;
def II_BC1TL : InstrItinClass;
def II_BC1CCZ : InstrItinClass;
+def II_BC2CCZ : InstrItinClass;
def II_BCC : InstrItinClass; // beq and bne
def II_BCCZ : InstrItinClass; // b[gl][et]z
def II_BCCC : InstrItinClass; // b<cc>c
@@ -53,12 +54,18 @@ def II_BCCZC : InstrItinClass; // beqzc, bnezc
def II_BITSWAP : InstrItinClass;
def II_CEIL : InstrItinClass;
def II_CFC1 : InstrItinClass;
+def II_CFC2 : InstrItinClass;
def II_CLO : InstrItinClass;
def II_CLZ : InstrItinClass;
def II_CTC1 : InstrItinClass;
+def II_CTC2 : InstrItinClass;
def II_CVT : InstrItinClass;
def II_C_CC_D : InstrItinClass; // Any c.<cc>.d instruction
def II_C_CC_S : InstrItinClass; // Any c.<cc>.s instruction
+def II_CMP_CC_D : InstrItinClass; // Any cmp.<cc>.d instruction
+def II_CMP_CC_S : InstrItinClass; // Any cmp.<cc>.s instruction
+def II_CLASS_D : InstrItinClass;
+def II_CLASS_S : InstrItinClass;
def II_DADDIU : InstrItinClass;
def II_DADDU : InstrItinClass;
def II_DADDI : InstrItinClass;
@@ -172,6 +179,7 @@ def II_LHE : InstrItinClass;
def II_LHU : InstrItinClass;
def II_LHUE : InstrItinClass;
def II_LL : InstrItinClass;
+def II_LI : InstrItinClass;
def II_LLD : InstrItinClass;
def II_LUI : InstrItinClass;
def II_LUXC1 : InstrItinClass;
@@ -180,14 +188,17 @@ def II_LWE : InstrItinClass;
def II_LWC1 : InstrItinClass;
def II_LWC2 : InstrItinClass;
def II_LWC3 : InstrItinClass;
+def II_LWM : InstrItinClass;
def II_LWL : InstrItinClass;
def II_LWLE : InstrItinClass;
def II_LWPC : InstrItinClass;
+def II_LWP : InstrItinClass;
def II_LWR : InstrItinClass;
def II_LWRE : InstrItinClass;
def II_LWU : InstrItinClass;
def II_LWUPC : InstrItinClass;
def II_LWXC1 : InstrItinClass;
+def II_LWXS : InstrItinClass;
def II_LSA : InstrItinClass;
def II_DLSA : InstrItinClass;
def II_MADD : InstrItinClass;
@@ -196,13 +207,23 @@ def II_MADD_D : InstrItinClass;
def II_MADD_S : InstrItinClass;
def II_MADDF_D : InstrItinClass;
def II_MADDF_S : InstrItinClass;
+def II_MAX_D : InstrItinClass;
+def II_MAX_S : InstrItinClass;
+def II_MAXA_D : InstrItinClass;
+def II_MAXA_S : InstrItinClass;
+def II_MIN_D : InstrItinClass;
+def II_MIN_S : InstrItinClass;
+def II_MINA_D : InstrItinClass;
+def II_MINA_S : InstrItinClass;
def II_MFC0 : InstrItinClass;
+def II_MFHC0 : InstrItinClass;
def II_MFC1 : InstrItinClass;
def II_MFHC1 : InstrItinClass;
def II_MFC2 : InstrItinClass;
def II_MFHI_MFLO : InstrItinClass; // mfhi and mflo
def II_MOD : InstrItinClass;
def II_MODU : InstrItinClass;
+def II_MOVE : InstrItinClass;
def II_MOVF : InstrItinClass;
def II_MOVF_D : InstrItinClass;
def II_MOVF_S : InstrItinClass;
@@ -224,6 +245,7 @@ def II_MSUB_S : InstrItinClass;
def II_MSUBF_D : InstrItinClass;
def II_MSUBF_S : InstrItinClass;
def II_MTC0 : InstrItinClass;
+def II_MTHC0 : InstrItinClass;
def II_MTC1 : InstrItinClass;
def II_MTHC1 : InstrItinClass;
def II_MTC2 : InstrItinClass;
@@ -242,14 +264,21 @@ def II_NMADD_S : InstrItinClass;
def II_NMSUB_D : InstrItinClass;
def II_NMSUB_S : InstrItinClass;
def II_NOR : InstrItinClass;
+def II_NOT : InstrItinClass;
def II_OR : InstrItinClass;
def II_ORI : InstrItinClass;
def II_POP : InstrItinClass;
def II_RDHWR : InstrItinClass;
def II_RESTORE : InstrItinClass;
+def II_RECIP_S : InstrItinClass;
+def II_RECIP_D : InstrItinClass;
+def II_RINT_S : InstrItinClass;
+def II_RINT_D : InstrItinClass;
def II_ROTR : InstrItinClass;
def II_ROTRV : InstrItinClass;
def II_ROUND : InstrItinClass;
+def II_RSQRT_S : InstrItinClass;
+def II_RSQRT_D : InstrItinClass;
def II_SAVE : InstrItinClass;
def II_SC : InstrItinClass;
def II_SCD : InstrItinClass;
@@ -265,6 +294,8 @@ def II_SDXC1 : InstrItinClass;
def II_SEB : InstrItinClass;
def II_SEH : InstrItinClass;
def II_SELCCZ : InstrItinClass;
+def II_SELCCZ_D : InstrItinClass;
+def II_SELCCZ_S : InstrItinClass;
def II_SEQ_SNE : InstrItinClass; // seq and sne
def II_SEQI_SNEI : InstrItinClass; // seqi and snei
def II_SH : InstrItinClass;
@@ -275,6 +306,8 @@ def II_SLTI_SLTIU : InstrItinClass; // slti and sltiu
def II_SLT_SLTU : InstrItinClass; // slt and sltu
def II_SQRT_D : InstrItinClass;
def II_SQRT_S : InstrItinClass;
+def II_SEL_D : InstrItinClass;
+def II_SEL_S : InstrItinClass;
def II_SRA : InstrItinClass;
def II_SRAV : InstrItinClass;
def II_SRL : InstrItinClass;
@@ -291,6 +324,8 @@ def II_SWC2 : InstrItinClass;
def II_SWC3 : InstrItinClass;
def II_SWL : InstrItinClass;
def II_SWLE : InstrItinClass;
+def II_SWM : InstrItinClass;
+def II_SWP : InstrItinClass;
def II_SWR : InstrItinClass;
def II_SWRE : InstrItinClass;
def II_SWXC1 : InstrItinClass;
@@ -306,6 +341,10 @@ def II_LLE : InstrItinClass;
def II_SCE : InstrItinClass;
def II_TLBINV : InstrItinClass;
def II_TLBINVF : InstrItinClass;
+def II_WRPGPR : InstrItinClass;
+def II_RDPGPR : InstrItinClass;
+def II_DVP : InstrItinClass;
+def II_EVP : InstrItinClass;
//===----------------------------------------------------------------------===//
// Mips Generic instruction itineraries.
@@ -368,6 +407,7 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_EXT , [InstrStage<1, [ALU]>]>,
InstrItinData<II_INS , [InstrStage<1, [ALU]>]>,
InstrItinData<II_LUI , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_MOVE , [InstrStage<1, [ALU]>]>,
InstrItinData<II_MOVF , [InstrStage<1, [ALU]>]>,
InstrItinData<II_MOVN , [InstrStage<1, [ALU]>]>,
InstrItinData<II_MOVN_S , [InstrStage<1, [ALU]>]>,
@@ -375,6 +415,7 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_MOVT , [InstrStage<1, [ALU]>]>,
InstrItinData<II_MOVZ , [InstrStage<1, [ALU]>]>,
InstrItinData<II_NOR , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_NOT , [InstrStage<1, [ALU]>]>,
InstrItinData<II_OR , [InstrStage<1, [ALU]>]>,
InstrItinData<II_POP , [InstrStage<1, [ALU]>]>,
InstrItinData<II_RDHWR , [InstrStage<1, [ALU]>]>,
@@ -392,6 +433,8 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_LHU , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LHUE , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LW , [InstrStage<3, [ALU]>]>,
+ InstrItinData<II_LWM , [InstrStage<3, [ALU]>]>,
+ InstrItinData<II_LWP , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LWPC , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LWL , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LWLE , [InstrStage<3, [ALU]>]>,
@@ -402,6 +445,7 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_LDL , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LDR , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LDPC , [InstrStage<3, [ALU]>]>,
+ InstrItinData<II_LI , [InstrStage<1, [ALU]>]>,
InstrItinData<II_LL , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LLD , [InstrStage<3, [ALU]>]>,
InstrItinData<II_RESTORE , [InstrStage<3, [ALU]>]>,
@@ -409,15 +453,18 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_SH , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SHE , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SW , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_SWM , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SWL , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SWR , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_SWP , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SDL , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SDR , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SD , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SC , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SCD , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SAVE , [InstrStage<1, [ALU]>]>,
- InstrItinData<II_SELCCZ , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_SELCCZ_S , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_SELCCZ_D , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SEQ_SNE , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SEQI_SNEI , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SLTI_SLTIU , [InstrStage<1, [ALU]>]>,
@@ -431,12 +478,15 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_BC1T , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BC1TL , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BC1CCZ , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_BC2CCZ , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BCC , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BCCC , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BCCZ , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BCCZAL , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BCCZALS , [InstrStage<1, [ALU]>]>,
InstrItinData<II_BCCZC , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_CLASS_D , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_CLASS_S , [InstrStage<1, [ALU]>]>,
InstrItinData<II_IndirectBranchPseudo, [InstrStage<1, [ALU]>]>,
InstrItinData<II_J , [InstrStage<1, [ALU]>]>,
InstrItinData<II_JAL , [InstrStage<1, [ALU]>]>,
@@ -493,6 +543,14 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_MADD , [InstrStage<17, [IMULDIV]>]>,
InstrItinData<II_MADDU , [InstrStage<17, [IMULDIV]>]>,
InstrItinData<II_MFHI_MFLO , [InstrStage<1, [IMULDIV]>]>,
+ InstrItinData<II_MAX_D , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MAX_S , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MAXA_D , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MAXA_S , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MIN_S , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MIN_D , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MINA_S , [InstrStage<4, [ALU]>]>,
+ InstrItinData<II_MINA_D , [InstrStage<4, [ALU]>]>,
InstrItinData<II_MOD , [InstrStage<38, [IMULDIV]>]>,
InstrItinData<II_MODU , [InstrStage<38, [IMULDIV]>]>,
InstrItinData<II_MSUB , [InstrStage<17, [IMULDIV]>]>,
@@ -521,6 +579,8 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_MOV_S , [InstrStage<2, [ALU]>]>,
InstrItinData<II_CFC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_CTC1 , [InstrStage<2, [ALU]>]>,
+ InstrItinData<II_CFC2 , [InstrStage<2, [ALU]>]>,
+ InstrItinData<II_CTC2 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MOVF_D , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MOVF_S , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MOVT_D , [InstrStage<2, [ALU]>]>,
@@ -529,6 +589,8 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_MOVZ_S , [InstrStage<2, [ALU]>]>,
InstrItinData<II_C_CC_S , [InstrStage<3, [ALU]>]>,
InstrItinData<II_C_CC_D , [InstrStage<3, [ALU]>]>,
+ InstrItinData<II_CMP_CC_S , [InstrStage<3, [ALU]>]>,
+ InstrItinData<II_CMP_CC_D , [InstrStage<3, [ALU]>]>,
InstrItinData<II_ADD_D , [InstrStage<4, [ALU]>]>,
InstrItinData<II_ADD_S , [InstrStage<4, [ALU]>]>,
InstrItinData<II_SUB_D , [InstrStage<4, [ALU]>]>,
@@ -549,8 +611,16 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_NMSUB_D , [InstrStage<8, [ALU]>]>,
InstrItinData<II_DIV_S , [InstrStage<23, [ALU]>]>,
InstrItinData<II_DIV_D , [InstrStage<36, [ALU]>]>,
+ InstrItinData<II_RECIP_D , [InstrStage<25, [ALU]>]>,
+ InstrItinData<II_RECIP_S , [InstrStage<13, [ALU]>]>,
+ InstrItinData<II_RSQRT_D , [InstrStage<29, [ALU]>]>,
+ InstrItinData<II_RSQRT_S , [InstrStage<14, [ALU]>]>,
+ InstrItinData<II_RINT_D , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_RINT_S , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SQRT_S , [InstrStage<54, [ALU]>]>,
InstrItinData<II_SQRT_D , [InstrStage<12, [ALU]>]>,
+ InstrItinData<II_SEL_D , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_SEL_S , [InstrStage<1, [ALU]>]>,
InstrItinData<II_WSBH , [InstrStage<1, [ALU]>]>,
InstrItinData<II_LSA , [InstrStage<1, [ALU]>]>,
InstrItinData<II_DLSA , [InstrStage<1, [ALU]>]>,
@@ -563,6 +633,7 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_LDXC1 , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LWXC1 , [InstrStage<3, [ALU]>]>,
InstrItinData<II_LUXC1 , [InstrStage<3, [ALU]>]>,
+ InstrItinData<II_LWXS , [InstrStage<3, [ALU]>]>,
InstrItinData<II_SDC1 , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SDC2 , [InstrStage<1, [ALU]>]>,
InstrItinData<II_SDC3 , [InstrStage<1, [ALU]>]>,
@@ -579,9 +650,11 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_DMTC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_DMTC2 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFC0 , [InstrStage<2, [ALU]>]>,
+ InstrItinData<II_MFHC0 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFC2 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTC0 , [InstrStage<2, [ALU]>]>,
+ InstrItinData<II_MTHC0 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTC2 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFHC1 , [InstrStage<2, [ALU]>]>,
@@ -593,7 +666,9 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_TLBINV , [InstrStage<1, [ALU]>]>,
InstrItinData<II_TLBINVF , [InstrStage<1, [ALU]>]>,
InstrItinData<II_LLE , [InstrStage<3, [ALU]>]>,
- InstrItinData<II_SCE , [InstrStage<1, [ALU]>]>
+ InstrItinData<II_SCE , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_WRPGPR , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_RDPGPR , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_DVP , [InstrStage<1, [ALU]>]>,
+ InstrItinData<II_EVP , [InstrStage<1, [ALU]>]>
]>;
-
-include "MipsScheduleP5600.td"
diff --git a/contrib/llvm/lib/Target/Mips/MipsScheduleGeneric.td b/contrib/llvm/lib/Target/Mips/MipsScheduleGeneric.td
new file mode 100644
index 0000000..15a0401
--- /dev/null
+++ b/contrib/llvm/lib/Target/Mips/MipsScheduleGeneric.td
@@ -0,0 +1,1048 @@
+//=- MipsScheduleGeneric.td - Generic Scheduling Definitions -*- tablegen -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the interAptiv processor in a manner of speaking. It
+// describes a hypothetical version of the in-order MIPS32R2 interAptiv with all
+// branches of the MIPS ISAs, ASEs and ISA variants. The itinerary lists are
+// broken down into per ISA lists, so that this file can be used to rapidly
+// develop new schedule models.
+//
+//===----------------------------------------------------------------------===//
+def MipsGenericModel : SchedMachineModel {
+ int IssueWidth = 1;
+ int MicroOpBufferSize = 0;
+
+ // These figures assume an L1 hit.
+ int LoadLatency = 2;
+ int MispredictPenalty = 4;
+
+ int HighLatency = 37;
+ list<Predicate> UnsupportedFeatures = [];
+
+ let CompleteModel = 1;
+ let PostRAScheduler = 1;
+}
+
+let SchedModel = MipsGenericModel in {
+
+// ALU Pipeline
+// ============
+
+def GenericALU : ProcResource<1> { let BufferSize = 1; }
+def GenericIssueALU : ProcResource<1> { let Super = GenericALU; }
+
+def GenericWriteALU : SchedWriteRes<[GenericIssueALU]>;
+
+// and, lui, nor, or, slti, sltiu, sub, subu, xor
+// add, addi, addiu, addu, andi, ori, rotr, se[bh], sllv?, sr[al]v?, slt, sltu,
+// xori
+def : ItinRW<[GenericWriteALU], [II_ADD, II_ADDU, II_ADDI, II_ADDIU, II_ANDI,
+ II_AND, II_ANDI, II_CLO, II_CLZ, II_EXT,
+ II_INS, II_LUI, II_MULT, II_MULTU, II_NOR,
+ II_ORI, II_OR, II_ROTR, II_ROTRV, II_SEB,
+ II_SEH, II_SLTI_SLTIU, II_SLT_SLTU, II_SLL,
+ II_SRA, II_SRL, II_SLLV, II_SRAV, II_SRLV,
+ II_SSNOP, II_SUB, II_SUBU, II_WSBH, II_XOR,
+ II_XORI]>;
+
+def : InstRW<[GenericWriteALU], (instrs COPY)>;
+
+def GenericMDU : ProcResource<1> { let BufferSize = 1; }
+def GenericIssueMDU : ProcResource<1> { let Super = GenericALU; }
+def GenericIssueDIV : ProcResource<1> { let Super = GenericMDU; }
+def GenericWriteHILO : SchedWriteRes<[GenericIssueMDU]>;
+def GenericWriteALULong : SchedWriteRes<[GenericIssueALU]> { let Latency = 5; }
+def GenericWriteMove : SchedWriteRes<[GenericIssueALU]> { let Latency = 2; }
+
+def : ItinRW<[GenericWriteHILO], [II_MADD, II_MADDU, II_MSUB, II_MSUBU]>;
+
+def GenericWriteMDUtoGPR : SchedWriteRes<[GenericIssueMDU]> {
+ let Latency = 5;
+}
+
+def : ItinRW<[GenericWriteMDUtoGPR], [II_MUL]>;
+
+def GenericWriteDIV : SchedWriteRes<[GenericIssueDIV]> {
+ // Estimated worst case
+ let Latency = 33;
+ let ResourceCycles = [1, 33];
+}
+def GenericWriteDIVU : SchedWriteRes<[GenericIssueDIV]> {
+ // Estimated worst case
+ let Latency = 31;
+ let ResourceCycles = [1, 31];
+}
+
+def : ItinRW<[GenericWriteDIV], [II_DIV]>;
+
+def : ItinRW<[GenericWriteDIVU], [II_DIVU]>;
+
+// MIPS64
+// ======
+
+def : ItinRW<[GenericWriteALU], [II_DADDIU, II_DADDU, II_DADDI, II_DADD,
+ II_DCLO, II_DCLZ, II_DROTR, II_DROTR32,
+ II_DROTRV, II_DSBH, II_DSHD, II_DSLL,
+ II_DSLL32, II_DSLLV, II_DSRA, II_DSRA32,
+ II_DSRAV, II_DSRL, II_DSRL32, II_DSRLV,
+ II_DSUBU, II_DSUB]>;
+
+def : ItinRW<[GenericWriteDIV], [II_DDIV]>;
+
+def : ItinRW<[GenericWriteDIVU], [II_DDIVU]>;
+
+def : ItinRW<[GenericWriteMDUtoGPR], [II_DMUL]>;
+
+def : ItinRW<[GenericWriteHILO], [II_DMULU, II_DMULT, II_DMULTU]>;
+
+// MIPS16e
+// =======
+
+def : ItinRW<[GenericWriteALU], [IIM16Alu, IIPseudo]>;
+
+// microMIPS
+// =========
+
+def : ItinRW<[GenericWriteALU], [II_MOVE, II_LI, II_NOT]>;
+
+// MIPSR6
+// ======
+
+def GenericWriteMul : SchedWriteRes<[GenericIssueMDU]> { let Latency = 4; }
+def : ItinRW<[GenericWriteMul], [II_MUH, II_MUHU, II_MULU]>;
+
+def : ItinRW<[GenericWriteDIV], [II_MOD, II_MODU]>;
+
+def : ItinRW<[GenericWriteALU], [II_ADDIUPC, II_ALIGN, II_ALUIPC, II_AUI,
+ II_AUIPC, II_BITSWAP, II_LSA, II_SELCCZ]>;
+
+// MIPS64R6
+// ========
+
+def : ItinRW<[GenericWriteALU], [II_DALIGN, II_DAHI, II_DATI, II_DAUI,
+ II_DBITSWAP, II_DLSA]>;
+
+def : ItinRW<[GenericWriteMDUtoGPR], [II_DMUH, II_DMUHU]>;
+def : ItinRW<[GenericWriteDIV], [II_DMOD, II_DMODU]>;
+
+// clo, clz, di, mfhi, mflo
+def : ItinRW<[GenericWriteALULong], [II_MFHI_MFLO]>;
+def : ItinRW<[GenericWriteALU], [II_MOVN, II_MOVZ]>;
+def : ItinRW<[GenericWriteMove], [II_MTHI_MTLO, II_RDHWR]>;
+
+
+// CTISTD Pipeline
+// ---------------
+
+def GenericIssueCTISTD : ProcResource<1> { let Super = GenericALU; }
+
+def GenericLDST : ProcResource<1> { let BufferSize = 1; }
+def GenericIssueLDST : ProcResource<1> { let Super = GenericLDST; }
+
+def GenericWriteJump : SchedWriteRes<[GenericIssueCTISTD]>;
+def GenericWriteJumpAndLink : SchedWriteRes<[GenericIssueCTISTD]> {
+ let Latency = 2;
+}
+
+// b, beq, beql, bg[et]z, bl[et]z, bne, bnel, j, syscall, jal, bltzal, jalx,
+// jalr, jr.hb, jr, jalr.hb, jarlc, jialc
+def : ItinRW<[GenericWriteJump], [II_B, II_BCC, II_BCCZ, II_BCCZAL, II_J,
+ II_JR, II_JR_HB, II_ERET, II_ERETNC,
+ II_DERET]>;
+
+def : ItinRW<[GenericWriteJumpAndLink], [II_JAL, II_JALR, II_JALR_HB,
+ II_BC2CCZ]>;
+
+def : ItinRW<[GenericWriteJump], [II_JRC, II_JRADDIUSP]>;
+
+def : ItinRW<[GenericWriteJumpAndLink], [II_BCCZALS, II_JALS, II_JALRS]>;
+
+// MIPSR6
+// ======
+
+def : ItinRW<[GenericWriteJumpAndLink], [II_BALC, II_JALRC, II_JIALC]>;
+
+def : ItinRW<[GenericWriteJump], [II_JIC, II_BC, II_BCCC, II_BCCZC]>;
+
+
+def GenericWriteTrap : SchedWriteRes<[GenericIssueCTISTD]>;
+
+def : ItinRW<[GenericWriteTrap], [II_BREAK, II_SYSCALL, II_TEQ, II_TEQI,
+ II_TGE, II_TGEI, II_TGEIU, II_TGEU, II_TNE,
+ II_TNEI, II_TLT, II_TLTI, II_TLTU, II_TTLTIU,
+ II_TRAP, II_SDBBP]>;
+
+// COP0 Pipeline
+// =============
+
+def GenericCOP0 : ProcResource<1> { let BufferSize = 1; }
+
+def GenericIssueCOP0 : ProcResource<1> { let Super = GenericCOP0; }
+def GenericWriteCOP0TLB : SchedWriteRes<[GenericIssueCOP0]> { let Latency = 4; }
+def GenericWriteCOP0 : SchedWriteRes<[GenericIssueCOP0]> { let Latency = 3; }
+def GenericReadCOP0 : SchedWriteRes<[GenericIssueCOP0]> { let Latency = 2; }
+def GnereicReadWritePGPR : SchedWriteRes<[GenericIssueCOP0]>;
+
+def : ItinRW<[GenericWriteCOP0TLB], [II_TLBP, II_TLBR, II_TLBWI, II_TLBWR]>;
+def : ItinRW<[GenericWriteCOP0TLB], [II_TLBINV, II_TLBINVF]>;
+
+def : ItinRW<[GenericReadCOP0], [II_MFC0]>;
+def : ItinRW<[GenericWriteCOP0], [II_MTC0]>;
+
+def : ItinRW<[GenericWriteCOP0], [II_EVP, II_DVP]>;
+
+// MIPSR5
+// ======
+def : ItinRW<[GenericReadCOP0], [II_MFHC0]>;
+def : ItinRW<[GenericWriteCOP0], [II_MTHC0]>;
+
+// MIPS64
+// ======
+
+def : ItinRW<[GenericReadCOP0], [II_DMFC0]>;
+def : ItinRW<[GenericWriteCOP0], [II_DMTC0]>;
+
+def : ItinRW<[GenericWriteCOP0], [II_RDPGPR, II_WRPGPR]>;
+
+def : ItinRW<[GenericWriteCOP0], [II_DI, II_EI]>;
+
+def : ItinRW<[GenericWriteCOP0], [II_EHB, II_PAUSE, II_WAIT]>;
+
+def GenericCOP2 : ProcResource<1> { let BufferSize = 1; }
+def GenericWriteCOPOther : SchedWriteRes<[GenericCOP2]>;
+
+def : ItinRW<[GenericWriteCOPOther], [II_MFC2, II_MTC2, II_DMFC2, II_DMTC2]>;
+
+// LDST Pipeline
+// -------------
+
+def GenericWriteLoad : SchedWriteRes<[GenericIssueLDST]> {
+ let Latency = 2;
+}
+
+def GenericWritePref : SchedWriteRes<[GenericIssueLDST]>;
+def GenericWriteSync : SchedWriteRes<[GenericIssueLDST]>;
+def GenericWriteCache : SchedWriteRes<[GenericIssueLDST]> { let Latency = 5; }
+
+def GenericWriteStore : SchedWriteRes<[GenericIssueLDST]>;
+def GenericWriteStoreSC : SchedWriteRes<[GenericIssueLDST]> { let Latency = 2; }
+
+def GenericWriteGPRFromBypass : SchedWriteRes<[GenericIssueLDST]> {
+ let Latency = 2;
+}
+
+def GenericWriteStoreFromOtherUnits : SchedWriteRes<[GenericIssueLDST]>;
+def GenericWriteLoadToOtherUnits : SchedWriteRes<[GenericIssueLDST]> {
+ let Latency = 0;
+}
+
+// l[bhw], l[bh]u, ll
+def : ItinRW<[GenericWriteLoad], [II_LB, II_LBU, II_LH, II_LHU, II_LW, II_LL,
+ II_LWC2, II_LWC3, II_LDC2, II_LDC3]>;
+
+// lw[lr]
+def : ItinRW<[GenericWriteLoad], [II_LWL, II_LWR]>;
+
+// MIPS64 loads
+def : ItinRW<[GenericWriteLoad], [II_LD, II_LLD, II_LWU]>;
+
+// ld[lr]
+def : ItinRW<[GenericWriteLoad], [II_LDL, II_LDR]>;
+
+// MIPS32 EVA
+def : ItinRW<[GenericWriteLoad], [II_LBE, II_LBUE, II_LHE, II_LHUE, II_LWE,
+ II_LLE]>;
+
+def : ItinRW<[GenericWriteLoad], [II_LWLE, II_LWRE]>;
+
+// MIPS32R6 and MIPS16e
+// ====================
+
+def : ItinRW<[GenericWriteLoad], [II_LWPC]>;
+
+// MIPS64R6
+// ====================
+
+def : ItinRW<[GenericWriteLoad], [II_LWUPC, II_LDPC]>;
+
+
+// s[bhw], sc, s[dw]c[23]
+def : ItinRW<[GenericWriteStore], [II_SB, II_SH, II_SW, II_SWC2, II_SWC3,
+ II_SDC2, II_SDC3]>;
+
+def : ItinRW<[GenericWriteStoreSC], [II_SC]>;
+
+// PreMIPSR6 sw[lr]
+def : ItinRW<[GenericWriteStore], [II_SWL, II_SWR]>;
+
+// EVA ASE stores
+def : ItinRW<[GenericWriteStore], [II_SBE, II_SHE, II_SWE, II_SCE]>;
+
+def : ItinRW<[GenericWriteStore], [II_SWLE, II_SWRE]>;
+
+// MIPS64
+// ======
+
+def : ItinRW<[GenericWriteStore], [II_SD, II_SCD]>;
+
+// PreMIPSR6 stores
+// ================
+
+def : ItinRW<[GenericWriteStore], [II_SDL, II_SDR]>;
+
+// MIPS16e
+// =======
+
+def : ItinRW<[GenericWriteLoad], [II_RESTORE]>;
+
+def : ItinRW<[GenericWriteStore], [II_SAVE]>;
+
+// microMIPS
+// =========
+
+def : ItinRW<[GenericWriteLoad], [II_LWM, II_LWP, II_LWXS]>;
+
+def : ItinRW<[GenericWriteStore], [II_SWM, II_SWP]>;
+
+// pref
+def : ItinRW<[GenericWritePref], [II_PREF]>;
+
+def : ItinRW<[GenericWritePref], [II_PREFE]>;
+
+// cache
+def : ItinRW<[GenericWriteCache], [II_CACHE]>;
+
+def : ItinRW<[GenericWriteCache], [II_CACHEE]>;
+
+// sync
+def : ItinRW<[GenericWriteSync], [II_SYNC]>;
+
+def : ItinRW<[GenericWriteSync], [II_SYNCI]>;
+
+// FPU Pipelines
+// =============
+
+def GenericFPQ : ProcResource<1> { let BufferSize = 1; }
+def GenericIssueFPUS : ProcResource<1> { let Super = GenericFPQ; }
+def GenericIssueFPUL : ProcResource<1> { let Super = GenericFPQ; }
+def GenericIssueFPULoad : ProcResource<1> { let Super = GenericFPQ; }
+def GenericIssueFPUStore : ProcResource<1> { let Super = GenericFPQ; }
+def GenericIssueFPUMove : ProcResource<1> { let Super = GenericFPQ; }
+def GenericFPUDivSqrt : ProcResource<1> { let Super = GenericFPQ; }
+
+// The floating point compare of the 24k series including interAptiv has a
+// listed latency of 1-2. Using the higher latency here.
+
+def GenericWriteFPUCmp : SchedWriteRes<[GenericIssueFPUS]> { let Latency = 2; }
+def GenericWriteFPUS : SchedWriteRes<[GenericIssueFPUS]> { let Latency = 4; }
+def GenericWriteFPUL : SchedWriteRes<[GenericIssueFPUL]> { let Latency = 5; }
+def GenericWriteFPUStore : SchedWriteRes<[GenericIssueFPUStore]> { let
+ Latency = 1;
+}
+def GenericWriteFPULoad : SchedWriteRes<[GenericIssueFPULoad]> {
+ let Latency = 2;
+}
+def GenericWriteFPUMoveFP : SchedWriteRes<[GenericIssueFPUMove]> {
+ let Latency = 4;
+}
+def GenericWriteFPUMoveGPRFPU : SchedWriteRes<[GenericIssueFPUMove]> {
+ let Latency = 2;
+}
+def GenericWriteFPUDivS : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 17;
+ let ResourceCycles = [ 14 ];
+}
+def GenericWriteFPUDivD : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 32;
+ let ResourceCycles = [ 29 ];
+}
+def GenericWriteFPURcpS : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 13;
+ let ResourceCycles = [ 10 ];
+}
+def GenericWriteFPURcpD : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 25;
+ let ResourceCycles = [ 21 ];
+}
+def GenericWriteFPURsqrtS : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 17;
+ let ResourceCycles = [ 14 ];
+}
+def GenericWriteFPURsqrtD : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 32;
+ let ResourceCycles = [ 29 ];
+}
+def GenericWriteFPUSqrtS : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 17;
+ let ResourceCycles = [ 14 ];
+}
+def GenericWriteFPUSqrtD : SchedWriteRes<[GenericFPUDivSqrt]> {
+ let Latency = 29;
+ let ResourceCycles = [ 29 ];
+}
+
+// Floating point compare and branch
+// ---------------------------------
+//
+// c.<cc>.[ds], bc1[tf], bc1[tf]l
+def : ItinRW<[GenericWriteFPUCmp], [II_C_CC_D, II_C_CC_S, II_BC1F, II_BC1T,
+ II_BC1FL, II_BC1TL]>;
+
+def : ItinRW<[GenericWriteFPUCmp], [II_CMP_CC_D, II_CMP_CC_S]>;
+
+// Short Pipe
+// ----------
+//
+// abs.[ds], abs.ps, add.[ds], neg.[ds], neg.ps, madd.s, msub.s, nmadd,s
+// nmsub.s, sub.[ds], mul.s
+
+def : ItinRW<[GenericWriteFPUS], [II_ABS, II_ADD_D, II_ADD_S, II_MADD_S,
+ II_MSUB_S, II_MUL_S, II_NEG, II_NMADD_S,
+ II_NMSUB_S, II_SUB_S, II_SUB_D]>;
+// mov[tf].[ds]
+
+def : ItinRW<[GenericWriteFPUS], [II_MOVF_S, II_MOVF_D, II_MOVT_S, II_MOVT_D]>;
+
+// MIPSR6
+// ------
+//
+// sel(eq|ne).[ds], max.[ds], maxa.[ds], min.[ds], mina.[ds], class.[ds]
+def : ItinRW<[GenericWriteFPUS], [II_SELCCZ_S, II_SELCCZ_D, II_MAX_S,
+ II_MAX_D, II_MAXA_S, II_MAXA_D, II_MIN_S,
+ II_MIN_D, II_MINA_S, II_MINA_D, II_CLASS_S,
+ II_CLASS_D]>;
+
+// Long Pipe
+// ----------
+//
+// nmadd.d, nmsub.d, mul.[ds], mul.ps, ceil.[wl].[sd], cvt.d.[sw], cvt.s.[dw],
+// cvt.w.[sd], cvt.[sw].ps, trunc.w.[ds], trunc.w.ps, floor.[ds],
+// round.[lw].[ds], floor.[lw].ds
+
+// madd.d, msub.dm mul.d, mul.ps, nmadd.d, nmsub.d, ceil.[wl].[sd], cvt.d.[sw],
+// cvt.s.[dw], cvt.w.[sd], cvt.[sw].ps, round.[lw].[ds], floor.[lw].ds,
+// trunc.w.[ds], trunc.w.ps,
+def : ItinRW<[GenericWriteFPUL], [II_MADD_D, II_MSUB_D, II_MUL_D, II_NMADD_D,
+ II_NMSUB_D, II_CEIL, II_CVT,
+ II_FLOOR, II_ROUND, II_TRUNC]>;
+
+// div.[ds], div.ps
+def : ItinRW<[GenericWriteFPUDivS], [II_DIV_S]>;
+def : ItinRW<[GenericWriteFPUDivD], [II_DIV_D]>;
+
+// sqrt.[ds], sqrt.ps
+def : ItinRW<[GenericWriteFPUSqrtS], [II_SQRT_S]>;
+def : ItinRW<[GenericWriteFPUSqrtD], [II_SQRT_D]>;
+
+// rsqrt.[ds], recip.[ds]
+def : ItinRW<[GenericWriteFPURcpS], [II_RECIP_S, II_RSQRT_S]>;
+def : ItinRW<[GenericWriteFPURcpD], [II_RECIP_D, II_RSQRT_D]>;
+
+// MIPSR6
+// ======
+//
+// rint.[ds]
+def : ItinRW<[GenericWriteFPUL], [II_RINT_S, II_RINT_D]>;
+
+// Load Pipe
+// ---------
+
+// ctc1, mtc1, mthc1, cfc1, mfc1, mfhc1
+def : ItinRW<[GenericWriteFPUMoveGPRFPU], [II_CFC1, II_CTC1, II_MFC1, II_MFHC1,
+ II_MTC1, II_MTHC1]>;
+
+// swc1, swxc1
+def : ItinRW<[GenericWriteFPUStore], [II_SDC1, II_SDXC1, II_SUXC1, II_SWC1,
+ II_SWXC1]>;
+
+// movn.[ds], movz.[ds]
+def : ItinRW<[GenericWriteFPUMoveFP], [II_MOV_D, II_MOV_S, II_MOVF, II_MOVT,
+ II_MOVN_D, II_MOVN_S, II_MOVZ_D,
+ II_MOVZ_S]>;
+
+// l[dw]x?c1
+def : ItinRW<[GenericWriteFPULoad], [II_LDC1, II_LDXC1, II_LUXC1, II_LWC1,
+ II_LWXC1]>;
+
+// MIPS64
+// ======
+
+def : ItinRW<[GenericWriteFPUMoveGPRFPU], [II_DMFC1, II_DMTC1]>;
+
+// MIPSR6
+// ======
+
+def : ItinRW<[GenericWriteFPUS], [II_MADDF_S, II_MSUBF_S]>;
+
+def : ItinRW<[GenericWriteFPUS], [II_MADDF_D, II_MSUBF_D]>;
+
+def : ItinRW<[GenericWriteFPUCmp], [II_BC1CCZ, II_SEL_D, II_SEL_S]>;
+
+// Cavium Networks MIPS (cnMIPS) - Octeon, HasCnMips
+// =================================================
+
+def : ItinRW<[GenericWriteALU], [II_SEQ_SNE, II_SEQI_SNEI, II_POP, II_BADDU,
+ II_BBIT]>;
+
+// MIPS DSP ASE, HasDSP
+// ====================
+
+def GenericDSP : ProcResource<1> { let BufferSize = 1; }
+def GenericDSPShort : SchedWriteRes<[GenericDSP]> { let Latency = 2; }
+def GenericDSPLong : SchedWriteRes<[GenericDSP]> { let Latency = 6; }
+def GenericDSPBypass : SchedWriteRes<[GenericDSP]> { let Latency = 1; }
+def GenericDSPMTHILO : SchedWriteRes<[GenericDSP]> { let Latency = 5; }
+def GenericDSPLoad : SchedWriteRes<[GenericDSP]> { let Latency = 4; }
+def GenericDSPMTHLIP : SchedWriteRes<[GenericDSP]> { let Latency = 5; }
+
+def : InstRW<[GenericDSPLong], (instregex "^EXTRV_RS_W$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTRV_R_W$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTRV_S_H$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTRV_W$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTR_RS_W$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTR_R_W$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTR_S_H$")>;
+def : InstRW<[GenericDSPLong], (instregex "^EXTR_W$")>;
+def : InstRW<[GenericDSPLong], (instregex "^INSV$")>;
+
+def : InstRW<[GenericDSPMTHLIP], (instregex "^MTHLIP$")>;
+def : InstRW<[GenericDSPMTHILO], (instregex "^MTHI_DSP$")>;
+def : InstRW<[GenericDSPMTHILO], (instregex "^MTLO_DSP$")>;
+
+def : InstRW<[GenericDSPShort], (instregex "^ABSQ_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ABSQ_S_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQ_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQ_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQ_S_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDSC$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_S_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDWC$")>;
+def : InstRW<[GenericDSPShort], (instregex "^BITREV$")>;
+def : InstRW<[GenericDSPShort], (instregex "^BPOSGE32$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGU_EQ_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGU_LE_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGU_LT_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPU_EQ_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPU_LE_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPU_LT_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMP_EQ_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMP_LE_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMP_LT_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQ_SA_L_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQ_S_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAU_H_QBL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAU_H_QBR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQ_SA_L_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQ_S_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSU_H_QBL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSU_H_QBR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTPDPV$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTPDP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTPV$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^LBUX$")>;
+def : InstRW<[GenericDSPShort], (instregex "^LHX$")>;
+def : InstRW<[GenericDSPShort], (instregex "^LWX$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MADDU_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MADD_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_SA_W_PHL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_SA_W_PHR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_S_W_PHL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_S_W_PHR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MFHI_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MFLO_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MODSUB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MSUBU_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MSUB_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEQ_S_W_PHL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEQ_S_W_PHR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEU_S_PH_QBL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEU_S_PH_QBR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_RS_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULSAQ_S_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULTU_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULT_DSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PACKRL_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PICK_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PICK_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBLA$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBRA$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQ_W_PHL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQ_W_PHR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBLA$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBL$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBRA$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBR$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQU_S_QB_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQ_PH_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQ_QB_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQ_RS_PH_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^RADDU_W_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^RDDSP$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPLV_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPLV_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPL_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPL_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHILOV$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHILO$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_S_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_S_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_R_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_R_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_R_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_R_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRLV_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRL_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQ_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQ_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQ_S_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_S_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^WRDSP$")>;
+
+// MIPS DSP R2 - hasDSP, HasDSPR2, InMicroMips
+// ===========================================
+
+def : InstRW<[GenericDSPShort], (instregex "^ABSQ_S_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_R_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_R_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDUH_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDUH_R_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^APPEND$")>;
+def : InstRW<[GenericDSPShort], (instregex "^BALIGN$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGDU_EQ_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGDU_LE_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGDU_LT_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPA_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQX_SA_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQX_S_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAX_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPS_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQX_S_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQX_SA_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSX_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MUL_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MUL_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_RS_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_S_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULSA_W_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECR_QB_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECR_SRA_PH_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECR_SRA_R_PH_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PREPEND$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_R_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_R_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRL_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRLV_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_R_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_R_W$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_S_PH$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBUH_QB$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBUH_R_QB$")>;
+
+// microMIPS DSP R1 - HasDSP, InMicroMips
+// ======================================
+
+def : InstRW<[GenericDSPShort], (instregex "^ABSQ_S_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ABSQ_S_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQ_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQ_S_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQ_S_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDSC_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_S_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDWC_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^BITREV_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^BPOSGE32_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGU_EQ_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGU_LE_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGU_LT_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPU_EQ_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPU_LE_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPU_LT_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMP_EQ_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMP_LE_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMP_LT_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQ_SA_L_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQ_S_W_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAU_H_QBL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAU_H_QBR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQ_SA_L_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQ_S_W_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSU_H_QBL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSU_H_QBR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTPDPV_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTPDP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTPV_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTRV_RS_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTRV_R_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTRV_S_H_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTRV_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTR_RS_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTR_R_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTR_S_H_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^EXTR_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^INSV_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^LBUX_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^LHX_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^LWX_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MADDU_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MADD_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_SA_W_PHL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_SA_W_PHR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_S_W_PHL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MAQ_S_W_PHR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MFHI_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MFLO_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MODSUB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MOVEP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MOVN_I_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MOVZ_I_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MSUBU_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MSUB_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MTHI_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MTHLIP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MTLO_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEQ_S_W_PHL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEQ_S_W_PHR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEU_S_PH_QBL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULEU_S_PH_QBR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_RS_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULSAQ_S_W_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULTU_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULT_DSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PACKRL_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PICK_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PICK_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBLA_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBRA_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQU_PH_QBR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQ_W_PHL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEQ_W_PHR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBLA_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBL_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBRA_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECEU_PH_QBR_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQU_S_QB_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQ_PH_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQ_QB_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECRQ_RS_PH_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^RADDU_W_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^RDDSP_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPLV_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPLV_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPL_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^REPL_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHILOV_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHILO_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_S_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLLV_S_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_S_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHLL_S_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_R_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_R_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_R_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_R_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRLV_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRL_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQ_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQ_S_PH_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQ_S_W_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_S_QB_MM$")>;
+def : InstRW<[GenericDSPShort], (instregex "^WRDSP_MM$")>;
+
+
+// microMIPS DSP R2 - hasDSP, HasDSPR2, InMicroMips
+// ================================================
+
+def : InstRW<[GenericDSPShort], (instregex "^ABSQ_S_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_R_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_R_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDQH_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDUH_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDUH_R_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^ADDU_S_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^APPEND_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^BALIGN_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGDU_EQ_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGDU_LE_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^CMPGDU_LT_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPA_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQX_SA_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAQX_S_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPAX_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPS_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQX_S_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSQX_SA_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^DPSX_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MUL_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MUL_S_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_RS_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_S_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULQ_S_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^MULSA_W_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECR_QB_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECR_SRA_PH_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PRECR_SRA_R_PH_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^PREPEND_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRA_R_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRAV_R_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRL_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SHRLV_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_R_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBQH_R_W_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBU_S_PH_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBUH_QB_MMR2$")>;
+def : InstRW<[GenericDSPShort], (instregex "^SUBUH_R_QB_MMR2$")>;
+
+// microMIPS DSP R3 - hasDSP, hasDSPR2, hasDSPR3, InMicroMips
+// ==========================================================
+
+def : InstRW<[GenericDSPShort], (instregex "^BPOSGE32C_MMR3$")>;
+
+// MIPS MSA ASE - hasMSA
+// =====================
+
+def GenericWriteMSAShortLogic : SchedWriteRes<[GenericIssueFPUS]>;
+def GenericWriteMSAShortInt : SchedWriteRes<[GenericIssueFPUS]> {
+let Latency = 2;
+}
+def GenericWriteMoveOtherUnitsToFPU : SchedWriteRes<[GenericIssueFPUS]>;
+def GenericWriteMSAOther3 : SchedWriteRes<[GenericIssueFPUS]> {
+let Latency = 3;
+}
+def GenericWriteMSALongInt : SchedWriteRes<[GenericIssueFPUS]> {
+let Latency = 5;
+}
+def GenericWriteFPUDivI : SchedWriteRes<[GenericFPQ]> {
+ let Latency = 33;
+ let ResourceCycles = [ 33 ];
+}
+
+// FPUS is also used in moves from floating point and MSA registers to general
+// purpose registers.
+def GenericWriteMoveFPUSToOtherUnits : SchedWriteRes<[GenericIssueFPUS]> {
+ let Latency = 0;
+}
+
+// FPUL is also used in moves from floating point and MSA registers to general
+// purpose registers.
+def GenericWriteMoveFPULToOtherUnits : SchedWriteRes<[GenericIssueFPUL]>;
+
+
+// adds_a.[bhwd], adds_[asu].[bhwd], addvi?.[bhwd], asub_[us].[bhwd],
+// aver?_[us].[bhwd]
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^ADD_A_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^ADDS_[ASU]_[BHWD]$")>;
+
+// TODO: ADDVI_[BHW] might be 1 cycle latency rather than 2. Need to confirm it.
+// add.[bhwd], addvi.[bhwd], asub_[us].[bhwd], ave.[bhwd], aver.[bhwd]
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^ADDVI?_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^ASUB_[US].[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^AVER?_[US].[BHWD]$")>;
+
+// and.v, andi.b, move.v, ldi.[bhwd], xor.v, nor.v, xori.b, nori.b
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^MOVE_V$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^LDI_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)_V$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)I_B$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)I_B$")>;
+
+// vshf.[bhwd], binsl.[bhwd], binsr.[bhwd], insert.[bhwd], sld?.[bhwd],
+// bset.[bhwd], bclr.[bhwd], bneg.[bhwd], bsel_v, bseli_b
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^VSHF_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(BINSL|BINSLI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(BINSR|BINSRI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^INSERT_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(SLD|SLDI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(BSET|BSETI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(BCLR|BCLRI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(BNEG|BNEGI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(BSEL_V|BSELI_B)$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^BMN*Z.*$")>;
+
+// pcnt.[bhwd], sat_s.[bhwd], sat_u.bhwd]
+def : InstRW<[GenericWriteMSAOther3], (instregex "^PCNT_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAOther3], (instregex "^SAT_(S|U)_[BHWD]$")>;
+
+// bnz.[bhwdv], cfcmsa, ctcmsa
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(BNZ|BZ)_[BHWDV]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^C(F|T)CMSA$")>;
+
+// shf.[bhw], fill[bhwd], splat?.[bhwd]
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^SHF_[BHW]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^FILL_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^(SPLAT|SPLATI)_[BHWD]$")>;
+
+// pcnt.[bhwd], sat_s.[bhwd], sat_u.bhwd]
+def : InstRW<[GenericWriteMSAOther3], (instregex "^PCNT_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAOther3], (instregex "^SAT_(S|U)_[BHWD]$")>;
+
+// fexp2_w, fexp2_d
+def : InstRW<[GenericWriteFPUS], (instregex "^FEXP2_(W|D)$")>;
+
+// compare, converts, round to int, floating point truncate.
+def : InstRW<[GenericWriteFPUS], (instregex "^(CLT|CLTI)_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^(CLE|CLEI)_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^(CEQ|CEQI)_[BHWD]$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_UN_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_UEQ_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_EQ_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_LT_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_ULT_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_LE_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^CMP_ULE_(S|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FS(AF|EQ|LT|LE|NE|OR)_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FSUEQ_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FSULE_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FSULT_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FSUNE_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FSUN_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCAF_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCEQ_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCLE_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCLT_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCNE_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCOR_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCUEQ_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCULE_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCULT_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCUNE_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FCUN_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FABS_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FFINT_(U|S)_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FFQL_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FFQR_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FTINT_(U|S)_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FRINT_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FTQ_(H|W)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FTRUNC_(U|S)_(W|D)$")>;
+
+// fexdo.[hw], fexupl.[wd], fexupr.[wd]
+def : InstRW<[GenericWriteFPUS], (instregex "^FEXDO_(H|W)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FEXUPL_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FEXUPR_(W|D)$")>;
+
+// fclass.[wd], fmax.[wd], fmax_a.[wd], fmin.[wd], fmin_a.[wd], flog2.[wd]
+def : InstRW<[GenericWriteFPUS], (instregex "^FCLASS_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FMAX_A_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FMAX_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FMIN_A_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FMIN_(W|D)$")>;
+def : InstRW<[GenericWriteFPUS], (instregex "^FLOG2_(W|D)$")>;
+
+// interleave right/left, interleave even/odd, insert
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(ILVR|ILVL)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(ILVEV|ILVOD)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^INSVE_[BHWD]$")>;
+
+// subs_?.[bhwd], subsus_?.[bhwd], subsuu_?.[bhwd], subvi.[bhwd], subv.[bhwd],
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^SUBS_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^SUBSUS_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^SUBSUU_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^SUBVI_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortInt], (instregex "^SUBV_[BHWD]$")>;
+
+// mod_[su].[bhwd], div_[su].[bhwd]
+def : InstRW<[GenericWriteFPUDivI], (instregex "^MOD_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteFPUDivI], (instregex "^DIV_(S|U)_[BHWD]$")>;
+
+// hadd_[su].[bhwd], hsub_[su].[bhwd], max_[sua].[bhwd], min_[sua].[bhwd],
+// maxi_[su].[bhwd], mini_[su].[bhwd], sra?.[bhwd], srar?.[bhwd], srlr.[bhwd],
+// sll?.[bhwd], pckev.[bhwd], pckod.[bhwd], nloc.[bhwd], nlzc.[bhwd],
+// insve.[bhwd]
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^HADD_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^HSUB_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(MAX|MIN)_S_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(MAX|MIN)_U_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(MAX|MIN)_A_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic],
+ (instregex "^(MAXI|MINI)_(S|U)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(SRA|SRAI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(SRL|SRLI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(SRAR|SRARI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(SRLR|SRLRI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(SLL|SLLI)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(PCKEV|PCKOD)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^(NLOC|NLZC)_[BHWD]$")>;
+def : InstRW<[GenericWriteMSAShortLogic], (instregex "^INSVE_[BHWD]$")>;
+
+// dpadd_?.[bhwd], dpsub_?.[bhwd], dotp_?.[bhwd], msubv.[bhwd], maddv.[bhwd]
+// mulv.[bhwd].
+def : InstRW<[GenericWriteMSALongInt], (instregex "^DPADD_(S|U)_[HWD]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^DPSUB_(S|U)_[HWD]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^DOTP_(S|U)_[HWD]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MSUBV_[BHWD]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MADDV_[BHWD]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MULV_[BHWD]$")>;
+
+// madd?.q.[hw], msub?.q.[hw], mul?.q.[hw]
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MADDR_Q_[HW]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MADD_Q_[HW]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MSUBR_Q_[HW]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MSUB_Q_[HW]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MULR_Q_[HW]$")>;
+def : InstRW<[GenericWriteMSALongInt], (instregex "^MUL_Q_[HW]$")>;
+
+// fadd.[dw], fmadd.[dw], fmul.[dw], frcp.[dw], frsqrt.[dw], fsqrt.[dw]
+// fsub.[dw], fdiv.[dw]
+def : InstRW<[GenericWriteFPUL], (instregex "^FADD_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FMADD_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FMSUB_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FMUL_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FRCP_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FRSQRT_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FSQRT_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FSUB_[DW]$")>;
+def : InstRW<[GenericWriteFPUL], (instregex "^FDIV_[DW]$")>;
+
+// copy.[su]_[bhwd]
+def : InstRW<[GenericWriteFPUMoveGPRFPU], (instregex "^COPY_U_[BHW]$")>;
+def : InstRW<[GenericWriteFPUMoveGPRFPU], (instregex "^COPY_S_[BHWD]$")>;
+
+def : InstRW<[GenericWriteFPUStore], (instregex "^ST_[BHWD]$")>;
+def : InstRW<[GenericWriteFPULoad], (instregex "^LD_[BHWD]$")>;
+}
diff --git a/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td b/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td
index cee4287..882a241 100644
--- a/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td
+++ b/contrib/llvm/lib/Target/Mips/MipsScheduleP5600.td
@@ -13,7 +13,14 @@ def MipsP5600Model : SchedMachineModel {
int LoadLatency = 4;
int MispredictPenalty = 8; // TODO: Estimated
- let CompleteModel = 0;
+ let CompleteModel = 1;
+
+ list<Predicate> UnsupportedFeatures = [HasMips32r6, HasMips64r6,
+ HasMips64, HasMips64r2, HasCnMips,
+ InMicroMips, InMips16Mode,
+ HasMicroMips32r6, HasMicroMips64r6,
+ HasDSP, HasDSPR2];
+
}
let SchedModel = MipsP5600Model in {
@@ -31,7 +38,8 @@ def P5600WriteALU : SchedWriteRes<[P5600IssueALU]>;
// and, lui, nor, or, slti, sltiu, sub, subu, xor
def : ItinRW<[P5600WriteALU],
- [II_AND, II_LUI, II_NOR, II_OR, II_SLTI_SLTIU, II_SUBU, II_XOR]>;
+ [II_AND, II_LUI, II_NOR, II_OR, II_SLTI_SLTIU, II_SUB, II_SUBU,
+ II_XOR]>;
// AGQ Pipelines
// =============
@@ -53,11 +61,22 @@ def P5600WriteJumpAndLink : SchedWriteRes<[P5600IssueCTISTD, P5600CTISTD]> {
let Latency = 2;
}
-// b, beq, beql, bg[et]z, bl[et]z, bne, bnel, j, syscall, jal, bltzal, jalx,
+// b, beq, beql, bg[et]z, bl[et]z, bne, bnel, j, syscall, jal, bltzal,
// jalr, jr.hb, jr
-def : ItinRW<[P5600WriteJump], [II_B, II_BCC, II_BCCZ, II_BCCZAL, II_J, II_JR]>;
-def : ItinRW<[P5600WriteJumpAndLink], [II_JAL, II_JALR]>;
+def : ItinRW<[P5600WriteJump], [II_B, II_BCC, II_BCCZ, II_BCCZAL, II_J, II_JR,
+ II_JR_HB, II_DERET, II_ERET, II_ERETNC,
+ II_SYSCALL, II_BREAK, II_SDBBP, II_SSNOP,
+ II_TEQ, II_TEQI, II_TGE, II_TGEI, II_TGEIU,
+ II_TGEU, II_TLT, II_TLTI, II_TLTU, II_TNE,
+ II_TNEI, II_TRAP, II_TTLTIU, II_WAIT,
+ II_PAUSE]>;
+
+def : ItinRW<[P5600WriteJumpAndLink], [II_JAL, II_JALR, II_JALR_HB]>;
+def P5600COP0 : SchedWriteRes<[P5600IssueCTISTD, P5600CTISTD]>;
+
+def : ItinRW<[P5600COP0], [II_TLBINV, II_TLBINVF, II_TLBP, II_TLBR, II_TLBWI,
+ II_TLBWR, II_MFC0, II_MTC0]>;
// LDST Pipeline
// -------------
@@ -69,7 +88,7 @@ def P5600WriteLoadShifted : SchedWriteRes<[P5600IssueLDST, P5600CTISTD]> {
let Latency = 4;
}
-def P5600WritePref : SchedWriteRes<[P5600IssueLDST]>;
+def P5600WriteCache : SchedWriteRes<[P5600IssueLDST]>;
def P5600WriteStore : SchedWriteRes<[P5600IssueLDST, P5600CTISTD]> {
// FIXME: This is a bit pessimistic. P5600CTISTD is only used during cycle 2
@@ -87,21 +106,21 @@ def P5600WriteLoadToOtherUnits : SchedWriteRes<[P5600IssueLDST]> {
}
// l[bhw], l[bh]u, ll
-def : ItinRW<[P5600WriteLoad], [II_LB, II_LBU, II_LH, II_LHU, II_LW, II_LWU]>;
+def : ItinRW<[P5600WriteLoad], [II_LB, II_LBE, II_LBU, II_LBUE, II_LH, II_LHE,
+ II_LHU, II_LHUE, II_LW, II_LWE, II_LL, II_LLE,
+ II_LWPC]>;
// lw[lr]
-def : ItinRW<[P5600WriteLoadShifted], [II_LWL, II_LWR]>;
+def : ItinRW<[P5600WriteLoadShifted], [II_LWL, II_LWLE, II_LWR, II_LWRE]>;
// s[bhw], sw[lr]
-def : ItinRW<[P5600WriteStore], [II_SB, II_SH, II_SW, II_SWL, II_SWR]>;
-
-// pref
-// (this instruction does not exist in the backend yet)
-def : ItinRW<[P5600WritePref], []>;
+def : ItinRW<[P5600WriteStore], [II_SB, II_SBE, II_SH, II_SHE, II_SW, II_SWE,
+ II_SWL, II_SWLE, II_SWR, II_SWRE, II_SC,
+ II_SCE]>;
-// sc
-// (this instruction does not exist in the backend yet)
-def : ItinRW<[P5600WriteStore], []>;
+// pref, cache, sync, synci
+def : ItinRW<[P5600WriteCache], [II_PREF, II_PREFE, II_CACHE, II_CACHEE,
+ II_SYNC, II_SYNCI]>;
// LDST is also used in moves from general purpose registers to floating point
// and MSA.
@@ -134,11 +153,11 @@ def P5600WriteAL2MAdd: SchedWriteRes<[P5600IssueAL2, P5600CTISTD]> {
let Latency = 5;
}
-// clo, clz, di, mfhi, mflo
-def : ItinRW<[P5600WriteAL2], [II_CLO, II_CLZ, II_MFHI_MFLO]>;
+// clo, clz, di, ei, mfhi, mflo
+def : ItinRW<[P5600WriteAL2], [II_CLO, II_CLZ, II_DI, II_EI, II_MFHI_MFLO]>;
// ehb, rdhwr, rdpgpr, wrpgpr, wsbh
-def : ItinRW<[P5600WriteAL2ShadowMov], [II_RDHWR]>;
+def : ItinRW<[P5600WriteAL2ShadowMov], [II_EHB, II_RDHWR, II_WSBH]>;
// mov[nz]
def : ItinRW<[P5600WriteAL2CondMov], [II_MOVN, II_MOVZ]>;
@@ -156,8 +175,7 @@ def : ItinRW<[P5600WriteAL2MAdd],
[II_MADD, II_MADDU, II_MSUB, II_MSUBU, II_MTHI_MTLO]>;
// ext, ins
-def : ItinRW<[P5600WriteAL2BitExt],
- [II_EXT, II_INS]>;
+def : ItinRW<[P5600WriteAL2BitExt], [II_EXT, II_INS]>;
// Either ALU or AL2 Pipelines
// ---------------------------
@@ -176,9 +194,10 @@ def P5600WriteEitherALU : SchedWriteVariant<
// add, addi, addiu, addu, andi, ori, rotr, se[bh], sllv?, sr[al]v?, slt, sltu,
// xori
def : ItinRW<[P5600WriteEitherALU],
- [II_ADDI, II_ADDIU, II_ANDI, II_ORI, II_ROTR, II_SEB, II_SEH,
+ [II_ADD, II_ADDI, II_ADDIU, II_ANDI, II_ORI, II_ROTR, II_SEB, II_SEH,
II_SLT_SLTU, II_SLL, II_SRA, II_SRL, II_XORI, II_ADDU, II_SLLV,
- II_SRAV, II_SRLV]>;
+ II_SRAV, II_SRLV, II_LSA]>;
+def : InstRW<[], (instrs COPY)>;
// FPU Pipelines
// =============
@@ -193,6 +212,11 @@ def P5600FPUDivSqrt : ProcResource<2>;
def P5600WriteFPUS : SchedWriteRes<[P5600IssueFPUS]>;
def P5600WriteFPUL : SchedWriteRes<[P5600IssueFPUL]> { let Latency = 4; }
def P5600WriteFPUL_MADDSUB : SchedWriteRes<[P5600IssueFPUL]> { let Latency = 6; }
+def P5600WriteFPUDivI : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> {
+ // Best/Common/Worst case = 7 / 23 / 27
+ let Latency = 23; // Using common case
+ let ResourceCycles = [ 1, 23 ];
+}
def P5600WriteFPUDivS : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> {
// Best/Common/Worst case = 7 / 23 / 27
let Latency = 23; // Using common case
@@ -236,6 +260,29 @@ def P5600WriteFPUSqrtD : SchedWriteRes<[P5600IssueFPUL, P5600FPUDivSqrt]> {
def P5600WriteMSAShortLogic : SchedWriteRes<[P5600IssueFPUS]>;
def P5600WriteMSAShortInt : SchedWriteRes<[P5600IssueFPUS]> { let Latency = 2; }
def P5600WriteMoveOtherUnitsToFPU : SchedWriteRes<[P5600IssueFPUS]>;
+def P5600WriteMSAOther3 : SchedWriteRes<[P5600IssueFPUS]> { let Latency = 3; }
+def P5600WriteMSALongInt : SchedWriteRes<[P5600IssueFPUS]> { let Latency = 5; }
+
+// vshf.[bhwd], binsl.[bhwd], binsr.[bhwd], insert.[bhwd], sld?.[bhwd],
+// bset.[bhwd], bclr.[bhwd], bneg.[bhwd], bsel_v, bseli_b
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^VSHF_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BINSL|BINSLI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BINSR|BINSRI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^INSERT_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(SLD|SLDI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BSET|BSETI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BCLR|BCLRI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BNEG|BNEGI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BSEL_V|BSELI_B)$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^BMN*Z.*$")>;
+
+// pcnt.[bhwd], sat_s.[bhwd], sat_u.bhwd]
+def : InstRW<[P5600WriteMSAOther3], (instregex "^PCNT_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAOther3], (instregex "^SAT_(S|U)_[BHWD]$")>;
+
+// bnz.[bhwdv], cfcmsa, ctcmsa
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(BNZ|BZ)_[BHWDV]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^C(F|T)CMSA$")>;
// FPUS is also used in moves from floating point and MSA registers to general
// purpose registers.
@@ -257,13 +304,16 @@ def : ItinRW<[P5600WriteFPUS], [II_ABS, II_MOVF_D, II_MOVF_S, II_MOVT_D,
II_MOVT_S, II_MOV_D, II_MOV_S, II_NEG]>;
// adds_a.[bhwd], adds_[asu].[bhwd], addvi?.[bhwd], asub_[us].[bhwd],
-// aver?_[us].[bhwd]
+// aver?_[us].[bhwd], shf.[bhw], fill[bhwd], splat?.[bhwd]
def : InstRW<[P5600WriteMSAShortInt], (instregex "^ADD_A_[BHWD]$")>;
def : InstRW<[P5600WriteMSAShortInt], (instregex "^ADDS_[ASU]_[BHWD]$")>;
// TODO: ADDVI_[BHW] might be 1 cycle latency rather than 2. Need to confirm it.
def : InstRW<[P5600WriteMSAShortInt], (instregex "^ADDVI?_[BHWD]$")>;
def : InstRW<[P5600WriteMSAShortInt], (instregex "^ASUB_[US].[BHWD]$")>;
def : InstRW<[P5600WriteMSAShortInt], (instregex "^AVER?_[US].[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^SHF_[BHW]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^FILL_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(SPLAT|SPLATI)_[BHWD]$")>;
// and.v, andi.b, move.v, ldi.[bhwd]
def : InstRW<[P5600WriteMSAShortLogic], (instregex "^MOVE_V$")>;
@@ -271,6 +321,111 @@ def : InstRW<[P5600WriteMSAShortLogic], (instregex "^LDI_[BHWD]$")>;
def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)_V$")>;
def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(AND|OR|[XN]OR)I_B$")>;
+// vshf.[bhwd], binsl.[bhwd], binsr.[bhwd], insert.[bhwd], sld?.[bhwd],
+// bset.[bhwd], bclr.[bhwd], bneg.[bhwd], bsel_v, bseli_b
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^VSHF_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BINSL|BINSLI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BINSR|BINSRI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^INSERT_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(SLD|SLDI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BSET|BSETI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BCLR|BCLRI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BNEG|BNEGI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^(BSEL_V|BSELI_B)$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^BMN*Z.*$")>;
+
+// pcnt.[bhwd], sat_s.[bhwd], sat_u.bhwd]
+def : InstRW<[P5600WriteMSAOther3], (instregex "^PCNT_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAOther3], (instregex "^SAT_(S|U)_[BHWD]$")>;
+
+// fexp2_w, fexp2_d
+def : InstRW<[P5600WriteFPUS], (instregex "^FEXP2_(W|D)$")>;
+
+// compare, converts, round to int, floating point truncate.
+def : InstRW<[P5600WriteFPUS], (instregex "^(CLT|CLTI)_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^(CLE|CLEI)_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^(CEQ|CEQI)_[BHWD]$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_UN_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_UEQ_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_EQ_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_LT_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_ULT_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_LE_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^CMP_ULE_(S|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FS(AF|EQ|LT|LE|NE|OR)_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FSUEQ_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FSULE_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FSULT_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FSUNE_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FSUN_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCAF_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCEQ_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCLE_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCLT_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCNE_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCOR_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCUEQ_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCULE_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCULT_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCUNE_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FCUN_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FABS_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FFINT_(U|S)_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FFQL_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FFQR_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FTINT_(U|S)_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FRINT_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FTQ_(H|W)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FTRUNC_(U|S)_(W|D)$")>;
+
+// fexdo.[hw], fexupl.[wd], fexupr.[wd]
+def : InstRW<[P5600WriteFPUS], (instregex "^FEXDO_(H|W)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FEXUPL_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FEXUPR_(W|D)$")>;
+
+// fclass.[wd], fmax.[wd], fmax_a.[wd], fmin.[wd], fmin_a.[wd], flog2.[wd]
+def : InstRW<[P5600WriteFPUS], (instregex "^FCLASS_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FMAX_A_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FMAX_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FMIN_A_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FMIN_(W|D)$")>;
+def : InstRW<[P5600WriteFPUS], (instregex "^FLOG2_(W|D)$")>;
+
+// interleave right/left, interleave even/odd, insert
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(ILVR|ILVL)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(ILVEV|ILVOD)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^INSVE_[BHWD]$")>;
+
+// subs_?.[bhwd], subsus_?.[bhwd], subsuu_?.[bhwd], subvi.[bhwd], subv.[bhwd],
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^SUBS_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^SUBSUS_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^SUBSUU_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^SUBVI_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortInt], (instregex "^SUBV_[BHWD]$")>;
+
+// mod_[su].[bhwd], div_[su].[bhwd]
+def : InstRW<[P5600WriteFPUDivI], (instregex "^MOD_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteFPUDivI], (instregex "^DIV_(S|U)_[BHWD]$")>;
+
+// hadd_[su].[bhwd], hsub_[su].[bhwd], max_[sua].[bhwd], min_[sua].[bhwd],
+// maxi_[su].[bhwd], mini_[su].[bhwd], sra?.[bhwd], srar?.[bhwd], srlr.[bhwd],
+// sll?.[bhwd], pckev.[bhwd], pckod.[bhwd], nloc.[bhwd], nlzc.[bhwd],
+// insve.[bhwd]
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^HADD_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^HSUB_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(MAX|MIN)_S_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(MAX|MIN)_U_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(MAX|MIN)_A_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(MAXI|MINI)_(S|U)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(SRA|SRAI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(SRL|SRLI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(SRAR|SRARI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(SRLR|SRLRI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(SLL|SLLI)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(PCKEV|PCKOD)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^(NLOC|NLZC)_[BHWD]$")>;
+def : InstRW<[P5600WriteMSAShortLogic], (instregex "^INSVE_[BHWD]$")>;
+
// Long Pipe
// ----------
//
@@ -289,6 +444,41 @@ def : ItinRW<[P5600WriteFPUDivD], [II_DIV_D]>;
def : ItinRW<[P5600WriteFPUSqrtS], [II_SQRT_S]>;
def : ItinRW<[P5600WriteFPUSqrtD], [II_SQRT_D]>;
+// frcp.[wd], frsqrt.[wd]
+def : InstRW<[P5600WriteFPURsqrtD], (instregex "^FRCP_(W|D)$")>;
+def : InstRW<[P5600WriteFPURsqrtD], (instregex "^FRSQRT_(W|D)$")>;
+
+def : ItinRW<[P5600WriteFPURsqrtD], [II_RECIP_D, II_RSQRT_D]>;
+def : ItinRW<[P5600WriteFPURsqrtS], [II_RECIP_S, II_RSQRT_S]>;
+
+// fmadd.[wd], fmsubb.[wd], fdiv.[wd], fsqrt.[wd], fmul.[wd], fadd.[wd],
+// fsub.[wd]
+def : InstRW<[P5600WriteFPUL_MADDSUB], (instregex "^FMADD_(W|D)$")>;
+def : InstRW<[P5600WriteFPUL_MADDSUB], (instregex "^FMSUB_(W|D)$")>;
+def : InstRW<[P5600WriteFPUDivS], (instregex "^FDIV_W$")>;
+def : InstRW<[P5600WriteFPUDivD], (instregex "^FDIV_D$")>;
+def : InstRW<[P5600WriteFPUSqrtS], (instregex "^FSQRT_W$")>;
+def : InstRW<[P5600WriteFPUSqrtD], (instregex "^FSQRT_D$")>;
+def : InstRW<[P5600WriteFPUL], (instregex "^FMUL_(W|D)$")>;
+def : InstRW<[P5600WriteFPUL], (instregex "^FADD_(W|D)$")>;
+def : InstRW<[P5600WriteFPUL], (instregex "^FSUB_(W|D)$")>;
+
+// dpadd_?.[bhwd], dpsub_?.[bhwd], dotp_?.[bhwd], msubv.[bhwd], maddv.[bhwd]
+// mulv.[bhwd].
+def : InstRW<[P5600WriteMSALongInt], (instregex "^DPADD_(S|U)_[HWD]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^DPSUB_(S|U)_[HWD]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^DOTP_(S|U)_[HWD]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MSUBV_[BHWD]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MADDV_[BHWD]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MULV_[BHWD]$")>;
+
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MADDR_Q_[HW]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MADD_Q_[HW]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MSUBR_Q_[HW]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MSUB_Q_[HW]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MULR_Q_[HW]$")>;
+def : InstRW<[P5600WriteMSALongInt], (instregex "^MUL_Q_[HW]$")>;
+
// madd.[ds], msub.[ds], nmadd.[ds], nmsub.[ds],
// Operand 0 is read on cycle 5. All other operands are read on operand 0.
def : ItinRW<[SchedReadAdvance<5>, P5600WriteFPUL_MADDSUB],
@@ -348,19 +538,24 @@ def P5600WriteLoadFPU : WriteSequence<[P5600WriteLoadToOtherUnits,
// ctc1, mtc1, mthc1
def : ItinRW<[P5600WriteMoveGPRToFPU], [II_CTC1, II_MTC1, II_MTHC1]>;
+// copy.[su]_[bhwd]
+def : InstRW<[P5600WriteMoveFPUToGPR], (instregex "^COPY_U_[BHW]$")>;
+def : InstRW<[P5600WriteMoveFPUToGPR], (instregex "^COPY_S_[BHWD]$")>;
+
// bc1[ft], cfc1, mfc1, mfhc1, movf, movt
def : ItinRW<[P5600WriteMoveFPUToGPR],
- [II_BC1F, II_BC1T, II_CFC1, II_MFC1, II_MFHC1, II_MOVF, II_MOVT]>;
+ [II_BC1F, II_BC1FL, II_BC1T, II_BC1TL, II_CFC1, II_MFC1, II_MFHC1, II_MOVF, II_MOVT]>;
// swc1, swxc1, st.[bhwd]
-def : ItinRW<[P5600WriteStoreFPUS], [II_SWC1, II_SWXC1]>;
+def : ItinRW<[P5600WriteStoreFPUS], [II_SDC1, II_SDXC1, II_SUXC1, II_SWC1,
+ II_SWXC1]>;
def : InstRW<[P5600WriteStoreFPUS], (instregex "^ST_[BHWD]$")>;
// movn.[ds], movz.[ds]
def : ItinRW<[P5600WriteStoreFPUL], [II_MOVN_D, II_MOVN_S, II_MOVZ_D, II_MOVZ_S]>;
// l[dw]x?c1, ld.[bhwd]
-def : ItinRW<[P5600WriteLoadFPU], [II_LDC1, II_LDXC1, II_LWC1, II_LWXC1]>;
+def : ItinRW<[P5600WriteLoadFPU], [II_LDC1, II_LDXC1, II_LWC1, II_LWXC1, II_LUXC1]>;
def : InstRW<[P5600WriteLoadFPU], (instregex "LD_[BHWD]")>;
// Unsupported Instructions
@@ -370,11 +565,10 @@ def : InstRW<[P5600WriteLoadFPU], (instregex "LD_[BHWD]")>;
// II_DADDIU, II_DADDU, II_DMFC1, II_DMTC1, II_DMULT, II_DMULTU, II_DROTR,
// II_DROTR32, II_DROTRV, II_DDIV, II_DSLL, II_DSLL32, II_DSLLV, II_DSRA,
// II_DSRA32, II_DSRAV, II_DSRL, II_DSRL32, II_DSRLV, II_DSUBU, II_DDIVU,
-// II_JALRC, II_LD, II_LD[LR], II_LUXC1, II_RESTORE, II_SAVE, II_SD, II_SDC1,
-// II_SDL, II_SDR, II_SDXC1
+// II_JALRC, II_LD, II_LD[LR], II_RESTORE, II_SAVE, II_SD, II_SDC1, II_SD[LR]
//
// The following instructions are never valid on P5600.
-// addq.ph, rdhwr, repl.ph, repl.qb, subq.ph, subu_s.qb
+// addq.ph, repl.ph, repl.qb, subq.ph, subu_s.qb
//
// Guesswork
// =========
diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 80641ed..bb48188 100644
--- a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -39,10 +39,10 @@ using namespace llvm;
extern "C" void LLVMInitializeMipsTarget() {
// Register the target.
- RegisterTargetMachine<MipsebTargetMachine> X(TheMipsTarget);
- RegisterTargetMachine<MipselTargetMachine> Y(TheMipselTarget);
- RegisterTargetMachine<MipsebTargetMachine> A(TheMips64Target);
- RegisterTargetMachine<MipselTargetMachine> B(TheMips64elTarget);
+ RegisterTargetMachine<MipsebTargetMachine> X(getTheMipsTarget());
+ RegisterTargetMachine<MipselTargetMachine> Y(getTheMipselTarget());
+ RegisterTargetMachine<MipsebTargetMachine> A(getTheMips64Target());
+ RegisterTargetMachine<MipselTargetMachine> B(getTheMips64elTarget());
}
static std::string computeDataLayout(const Triple &TT, StringRef CPU,
@@ -208,7 +208,6 @@ public:
void addIRPasses() override;
bool addInstSelector() override;
- void addMachineSSAOptimization() override;
void addPreEmitPass() override;
void addPreRegAlloc() override;
@@ -237,14 +236,8 @@ bool MipsPassConfig::addInstSelector() {
return false;
}
-void MipsPassConfig::addMachineSSAOptimization() {
- addPass(createMipsOptimizePICCallPass(getMipsTargetMachine()));
- TargetPassConfig::addMachineSSAOptimization();
-}
-
void MipsPassConfig::addPreRegAlloc() {
- if (getOptLevel() == CodeGenOpt::None)
- addPass(createMipsOptimizePICCallPass(getMipsTargetMachine()));
+ addPass(createMipsOptimizePICCallPass(getMipsTargetMachine()));
}
TargetIRAnalysis MipsTargetMachine::getTargetIRAnalysis() {
diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp
index 3bd4567..c5d6a05 100644
--- a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp
@@ -61,23 +61,23 @@ static bool IsInSmallSection(uint64_t Size) {
/// Return true if this global address should be placed into small data/bss
/// section.
-bool MipsTargetObjectFile::
-IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const {
+bool MipsTargetObjectFile::IsGlobalInSmallSection(
+ const GlobalObject *GO, const TargetMachine &TM) const {
// We first check the case where global is a declaration, because finding
// section kind using getKindForGlobal() is only allowed for global
// definitions.
- if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
- return IsGlobalInSmallSectionImpl(GV, TM);
+ if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage())
+ return IsGlobalInSmallSectionImpl(GO, TM);
- return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM));
+ return IsGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM));
}
/// Return true if this global address should be placed into small data/bss
/// section.
bool MipsTargetObjectFile::
-IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
+IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM,
SectionKind Kind) const {
- return (IsGlobalInSmallSectionImpl(GV, TM) &&
+ return (IsGlobalInSmallSectionImpl(GO, TM) &&
(Kind.isData() || Kind.isBSS() || Kind.isCommon()));
}
@@ -85,7 +85,7 @@ IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
/// section. This method does all the work, except for checking the section
/// kind.
bool MipsTargetObjectFile::
-IsGlobalInSmallSectionImpl(const GlobalValue *GV,
+IsGlobalInSmallSectionImpl(const GlobalObject *GO,
const TargetMachine &TM) const {
const MipsSubtarget &Subtarget =
*static_cast<const MipsTargetMachine &>(TM).getSubtargetImpl();
@@ -95,39 +95,37 @@ IsGlobalInSmallSectionImpl(const GlobalValue *GV,
return false;
// Only global variables, not functions.
- const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV);
+ const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GO);
if (!GVA)
return false;
// Enforce -mlocal-sdata.
- if (!LocalSData && GV->hasLocalLinkage())
+ if (!LocalSData && GVA->hasLocalLinkage())
return false;
// Enforce -mextern-sdata.
- if (!ExternSData && ((GV->hasExternalLinkage() && GV->isDeclaration()) ||
- GV->hasCommonLinkage()))
+ if (!ExternSData && ((GVA->hasExternalLinkage() && GVA->isDeclaration()) ||
+ GVA->hasCommonLinkage()))
return false;
- Type *Ty = GV->getValueType();
+ Type *Ty = GVA->getValueType();
return IsInSmallSection(
- GV->getParent()->getDataLayout().getTypeAllocSize(Ty));
+ GVA->getParent()->getDataLayout().getTypeAllocSize(Ty));
}
-MCSection *
-MipsTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
+MCSection *MipsTargetObjectFile::SelectSectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
// TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*"
// sections?
// Handle Small Section classification here.
- if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind))
+ if (Kind.isBSS() && IsGlobalInSmallSection(GO, TM, Kind))
return SmallBSSSection;
- if (Kind.isData() && IsGlobalInSmallSection(GV, TM, Kind))
+ if (Kind.isData() && IsGlobalInSmallSection(GO, TM, Kind))
return SmallDataSection;
// Otherwise, we work the same as ELF.
- return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM);
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
}
/// Return true if this constant should be placed into small data section.
@@ -150,3 +148,11 @@ MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL,
// Otherwise, we work the same as ELF.
return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align);
}
+
+const MCExpr *
+MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
+ const MCExpr *Expr =
+ MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
+ return MCBinaryExpr::createAdd(
+ Expr, MCConstantExpr::create(0x8000, getContext()), getContext());
+}
diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h
index 9840769..a37ec15 100644
--- a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h
@@ -18,21 +18,21 @@ class MipsTargetMachine;
MCSection *SmallDataSection;
MCSection *SmallBSSSection;
const MipsTargetMachine *TM;
+
+ bool IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM,
+ SectionKind Kind) const;
+ bool IsGlobalInSmallSectionImpl(const GlobalObject *GO,
+ const TargetMachine &TM) const;
public:
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
/// Return true if this global address should be placed into small data/bss
/// section.
- bool IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
- SectionKind Kind) const;
- bool IsGlobalInSmallSection(const GlobalValue *GV,
+ bool IsGlobalInSmallSection(const GlobalObject *GO,
const TargetMachine &TM) const;
- bool IsGlobalInSmallSectionImpl(const GlobalValue *GV,
- const TargetMachine &TM) const;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
/// Return true if this constant should be placed into small data section.
@@ -42,6 +42,8 @@ class MipsTargetMachine;
MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
const Constant *C,
unsigned &Align) const override;
+ /// Describe a TLS variable address within debug info.
+ const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
index 6a65943..4c1edfa 100644
--- a/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
@@ -12,20 +12,37 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheMipsTarget, llvm::TheMipselTarget;
-Target llvm::TheMips64Target, llvm::TheMips64elTarget;
+Target &llvm::getTheMipsTarget() {
+ static Target TheMipsTarget;
+ return TheMipsTarget;
+}
+Target &llvm::getTheMipselTarget() {
+ static Target TheMipselTarget;
+ return TheMipselTarget;
+}
+Target &llvm::getTheMips64Target() {
+ static Target TheMips64Target;
+ return TheMips64Target;
+}
+Target &llvm::getTheMips64elTarget() {
+ static Target TheMips64elTarget;
+ return TheMips64elTarget;
+}
extern "C" void LLVMInitializeMipsTargetInfo() {
RegisterTarget<Triple::mips,
- /*HasJIT=*/true> X(TheMipsTarget, "mips", "Mips");
+ /*HasJIT=*/true>
+ X(getTheMipsTarget(), "mips", "Mips");
RegisterTarget<Triple::mipsel,
- /*HasJIT=*/true> Y(TheMipselTarget, "mipsel", "Mipsel");
+ /*HasJIT=*/true>
+ Y(getTheMipselTarget(), "mipsel", "Mipsel");
RegisterTarget<Triple::mips64,
- /*HasJIT=*/true> A(TheMips64Target, "mips64", "Mips64 [experimental]");
+ /*HasJIT=*/true>
+ A(getTheMips64Target(), "mips64", "Mips64 [experimental]");
RegisterTarget<Triple::mips64el,
- /*HasJIT=*/true> B(TheMips64elTarget,
- "mips64el", "Mips64el [experimental]");
+ /*HasJIT=*/true>
+ B(getTheMips64elTarget(), "mips64el", "Mips64el [experimental]");
}
diff --git a/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXBaseInfo.h b/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXBaseInfo.h
index a72ae2e..1cb9200 100644
--- a/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXBaseInfo.h
+++ b/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXBaseInfo.h
@@ -30,60 +30,6 @@ enum AddressSpace {
ADDRESS_SPACE_PARAM = 101
};
-enum PropertyAnnotation {
- PROPERTY_MAXNTID_X = 0,
- PROPERTY_MAXNTID_Y,
- PROPERTY_MAXNTID_Z,
- PROPERTY_REQNTID_X,
- PROPERTY_REQNTID_Y,
- PROPERTY_REQNTID_Z,
- PROPERTY_MINNCTAPERSM,
- PROPERTY_ISTEXTURE,
- PROPERTY_ISSURFACE,
- PROPERTY_ISSAMPLER,
- PROPERTY_ISREADONLY_IMAGE_PARAM,
- PROPERTY_ISWRITEONLY_IMAGE_PARAM,
- PROPERTY_ISREADWRITE_IMAGE_PARAM,
- PROPERTY_ISKERNEL_FUNCTION,
- PROPERTY_ALIGN,
- PROPERTY_MANAGED,
-
- // last property
- PROPERTY_LAST
-};
-
-const unsigned AnnotationNameLen = 9; // length of each annotation name
-const char PropertyAnnotationNames[PROPERTY_LAST + 1][AnnotationNameLen + 1] = {
- "maxntidx", // PROPERTY_MAXNTID_X
- "maxntidy", // PROPERTY_MAXNTID_Y
- "maxntidz", // PROPERTY_MAXNTID_Z
- "reqntidx", // PROPERTY_REQNTID_X
- "reqntidy", // PROPERTY_REQNTID_Y
- "reqntidz", // PROPERTY_REQNTID_Z
- "minctasm", // PROPERTY_MINNCTAPERSM
- "texture", // PROPERTY_ISTEXTURE
- "surface", // PROPERTY_ISSURFACE
- "sampler", // PROPERTY_ISSAMPLER
- "rdoimage", // PROPERTY_ISREADONLY_IMAGE_PARAM
- "wroimage", // PROPERTY_ISWRITEONLY_IMAGE_PARAM
- "rdwrimage", // PROPERTY_ISREADWRITE_IMAGE_PARAM
- "kernel", // PROPERTY_ISKERNEL_FUNCTION
- "align", // PROPERTY_ALIGN
- "managed", // PROPERTY_MANAGED
-
- // last property
- "proplast", // PROPERTY_LAST
-};
-
-// name of named metadata used for global annotations
-#if defined(__GNUC__)
-// As this is declared to be static but some of the .cpp files that
-// include NVVM.h do not use this array, gcc gives a warning when
-// compiling those .cpp files, hence __attribute__((unused)).
-__attribute__((unused))
-#endif
- static const char *NamedMDForAnnotations = "nvvm.annotations";
-
namespace NVPTXII {
enum {
// These must be kept in sync with TSFlags in NVPTXInstrFormats.td
@@ -94,7 +40,7 @@ enum {
IsSurfTexQueryFlag = 0x800,
IsTexModeUnifiedFlag = 0x1000
};
-}
-}
+} // namespace NVPTXII
+} // namespace llvm
#endif
diff --git a/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.cpp b/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.cpp
index e356a96..12f9927 100644
--- a/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.cpp
@@ -60,7 +60,7 @@ static MCInstPrinter *createNVPTXMCInstPrinter(const Triple &T,
// Force static initialization.
extern "C" void LLVMInitializeNVPTXTargetMC() {
- for (Target *T : {&TheNVPTXTarget32, &TheNVPTXTarget64}) {
+ for (Target *T : {&getTheNVPTXTarget32(), &getTheNVPTXTarget64()}) {
// Register the MC asm info.
RegisterMCAsmInfo<NVPTXMCAsmInfo> X(*T);
diff --git a/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.h b/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.h
index bfd5123..0c9ad97 100644
--- a/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXMCTargetDesc.h
@@ -19,8 +19,8 @@
namespace llvm {
class Target;
-extern Target TheNVPTXTarget32;
-extern Target TheNVPTXTarget64;
+Target &getTheNVPTXTarget32();
+Target &getTheNVPTXTarget64();
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/NVPTX/ManagedStringPool.h b/contrib/llvm/lib/Target/NVPTX/ManagedStringPool.h
index a2d670f..7fc0156 100644
--- a/contrib/llvm/lib/Target/NVPTX/ManagedStringPool.h
+++ b/contrib/llvm/lib/Target/NVPTX/ManagedStringPool.h
@@ -27,7 +27,8 @@ class ManagedStringPool {
SmallVector<std::string *, 8> Pool;
public:
- ManagedStringPool() {}
+ ManagedStringPool() = default;
+
~ManagedStringPool() {
SmallVectorImpl<std::string *>::iterator Current = Pool.begin();
while (Current != Pool.end()) {
@@ -43,6 +44,6 @@ public:
}
};
-}
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_NVPTX_MANAGEDSTRINGPOOL_H
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTX.h b/contrib/llvm/lib/Target/NVPTX/NVPTX.h
index e91385a..c455a43 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTX.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTX.h
@@ -45,7 +45,6 @@ FunctionPass *createNVPTXISelDag(NVPTXTargetMachine &TM,
llvm::CodeGenOpt::Level OptLevel);
ModulePass *createNVPTXAssignValidGlobalNamesPass();
ModulePass *createGenericToNVVMPass();
-FunctionPass *createNVPTXFavorNonGenericAddrSpacesPass();
FunctionPass *createNVPTXInferAddressSpacesPass();
FunctionPass *createNVVMIntrRangePass(unsigned int SmVersion);
FunctionPass *createNVVMReflectPass();
@@ -53,12 +52,12 @@ FunctionPass *createNVVMReflectPass(const StringMap<int> &Mapping);
MachineFunctionPass *createNVPTXPrologEpilogPass();
MachineFunctionPass *createNVPTXReplaceImageHandlesPass();
FunctionPass *createNVPTXImageOptimizerPass();
-FunctionPass *createNVPTXLowerKernelArgsPass(const NVPTXTargetMachine *TM);
+FunctionPass *createNVPTXLowerArgsPass(const NVPTXTargetMachine *TM);
BasicBlockPass *createNVPTXLowerAllocaPass();
MachineFunctionPass *createNVPTXPeephole();
-extern Target TheNVPTXTarget32;
-extern Target TheNVPTXTarget64;
+Target &getTheNVPTXTarget32();
+Target &getTheNVPTXTarget64();
namespace NVPTX {
enum DrvInterface {
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTX.td b/contrib/llvm/lib/Target/NVPTX/NVPTX.td
index 032991a..c77ddbc 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTX.td
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTX.td
@@ -51,6 +51,9 @@ def SM61 : SubtargetFeature<"sm_61", "SmVersion", "61",
def SM62 : SubtargetFeature<"sm_62", "SmVersion", "62",
"Target SM 6.2">;
+def SATOM : SubtargetFeature<"satom", "HasAtomScope", "true",
+ "Atomic operations with scope">;
+
// PTX Versions
def PTX32 : SubtargetFeature<"ptx32", "PTXVersion", "32",
"Use PTX version 3.2">;
@@ -81,9 +84,9 @@ def : Proc<"sm_37", [SM37, PTX41]>;
def : Proc<"sm_50", [SM50, PTX40]>;
def : Proc<"sm_52", [SM52, PTX41]>;
def : Proc<"sm_53", [SM53, PTX42]>;
-def : Proc<"sm_60", [SM60, PTX50]>;
-def : Proc<"sm_61", [SM61, PTX50]>;
-def : Proc<"sm_62", [SM62, PTX50]>;
+def : Proc<"sm_60", [SM60, PTX50, SATOM]>;
+def : Proc<"sm_61", [SM61, PTX50, SATOM]>;
+def : Proc<"sm_62", [SM62, PTX50, SATOM]>;
def NVPTXInstrInfo : InstrInfo {
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXAllocaHoisting.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXAllocaHoisting.cpp
index 4f3ccf4..bed5229 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXAllocaHoisting.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXAllocaHoisting.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "NVPTXAllocaHoisting.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
@@ -28,11 +27,10 @@ public:
NVPTXAllocaHoisting() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addPreserved<MachineFunctionAnalysis>();
AU.addPreserved<StackProtector>();
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "NVPTX specific alloca hoisting";
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
index 660016b..3c2594c 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp
@@ -12,43 +12,83 @@
//
//===----------------------------------------------------------------------===//
-#include "NVPTXAsmPrinter.h"
#include "InstPrinter/NVPTXInstPrinter.h"
+#include "MCTargetDesc/NVPTXBaseInfo.h"
#include "MCTargetDesc/NVPTXMCAsmInfo.h"
#include "NVPTX.h"
-#include "NVPTXInstrInfo.h"
+#include "NVPTXAsmPrinter.h"
#include "NVPTXMCExpr.h"
#include "NVPTXMachineFunctionInfo.h"
#include "NVPTXRegisterInfo.h"
+#include "NVPTXSubtarget.h"
#include "NVPTXTargetMachine.h"
#include "NVPTXUtilities.h"
#include "cl_common_defines.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/CodeGen/Analysis.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/User.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TimeValue.h"
+#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Transforms/Utils/UnrollLoop.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <new>
#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
using namespace llvm;
#define DEPOTNAME "__local_depot"
@@ -63,11 +103,11 @@ InterleaveSrc("nvptx-emit-src", cl::ZeroOrMore, cl::Hidden,
cl::desc("NVPTX Specific: Emit source line in ptx file"),
cl::init(false));
-namespace {
/// DiscoverDependentGlobals - Return a set of GlobalVariables on which \p V
/// depends.
-void DiscoverDependentGlobals(const Value *V,
- DenseSet<const GlobalVariable *> &Globals) {
+static void
+DiscoverDependentGlobals(const Value *V,
+ DenseSet<const GlobalVariable *> &Globals) {
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
Globals.insert(GV);
else {
@@ -81,11 +121,12 @@ void DiscoverDependentGlobals(const Value *V,
/// VisitGlobalVariableForEmission - Add \p GV to the list of GlobalVariable
/// instances to be emitted, but only after any dependents have been added
-/// first.
-void VisitGlobalVariableForEmission(
- const GlobalVariable *GV, SmallVectorImpl<const GlobalVariable *> &Order,
- DenseSet<const GlobalVariable *> &Visited,
- DenseSet<const GlobalVariable *> &Visiting) {
+/// first.s
+static void
+VisitGlobalVariableForEmission(const GlobalVariable *GV,
+ SmallVectorImpl<const GlobalVariable *> &Order,
+ DenseSet<const GlobalVariable *> &Visited,
+ DenseSet<const GlobalVariable *> &Visiting) {
// Have we already visited this one?
if (Visited.count(GV))
return;
@@ -109,7 +150,6 @@ void VisitGlobalVariableForEmission(
Visited.insert(GV);
Visiting.erase(GV);
}
-}
void NVPTXAsmPrinter::emitLineNumberAsDotLoc(const MachineInstr &MI) {
if (!EmitLineNumbers)
@@ -225,8 +265,7 @@ void NVPTXAsmPrinter::lowerImageHandleSymbol(unsigned Index, MCOperand &MCOp) {
const char *Sym = MFI->getImageHandleSymbol(Index);
std::string *SymNamePtr =
nvTM.getManagedStrPool()->getManagedString(Sym);
- MCOp = GetSymbolRef(OutContext.getOrCreateSymbol(
- StringRef(SymNamePtr->c_str())));
+ MCOp = GetSymbolRef(OutContext.getOrCreateSymbol(StringRef(*SymNamePtr)));
}
void NVPTXAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
@@ -368,13 +407,13 @@ void NVPTXAsmPrinter::printReturnValStr(const Function *F, raw_ostream &O) {
} else if (isa<PointerType>(Ty)) {
O << ".param .b" << TLI->getPointerTy(DL).getSizeInBits()
<< " func_retval0";
- } else if ((Ty->getTypeID() == Type::StructTyID) || isa<VectorType>(Ty)) {
+ } else if (Ty->isAggregateType() || Ty->isVectorTy()) {
unsigned totalsz = DL.getTypeAllocSize(Ty);
- unsigned retAlignment = 0;
- if (!llvm::getAlign(*F, 0, retAlignment))
- retAlignment = DL.getABITypeAlignment(Ty);
- O << ".param .align " << retAlignment << " .b8 func_retval0[" << totalsz
- << "]";
+ unsigned retAlignment = 0;
+ if (!getAlign(*F, 0, retAlignment))
+ retAlignment = DL.getABITypeAlignment(Ty);
+ O << ".param .align " << retAlignment << " .b8 func_retval0[" << totalsz
+ << "]";
} else
llvm_unreachable("Unknown return type");
} else {
@@ -403,7 +442,6 @@ void NVPTXAsmPrinter::printReturnValStr(const Function *F, raw_ostream &O) {
}
}
O << ") ";
- return;
}
void NVPTXAsmPrinter::printReturnValStr(const MachineFunction &MF,
@@ -461,7 +499,7 @@ void NVPTXAsmPrinter::EmitFunctionEntryLabel() {
MRI = &MF->getRegInfo();
F = MF->getFunction();
emitLinkageDirective(F, O);
- if (llvm::isKernelFunction(*F))
+ if (isKernelFunction(*F))
O << ".entry ";
else {
O << ".func ";
@@ -472,7 +510,7 @@ void NVPTXAsmPrinter::EmitFunctionEntryLabel() {
emitFunctionParamList(*MF, O);
- if (llvm::isKernelFunction(*F))
+ if (isKernelFunction(*F))
emitKernelFunctionDirectives(*F, O);
OutStreamer->EmitRawText(O.str());
@@ -515,15 +553,15 @@ void NVPTXAsmPrinter::emitKernelFunctionDirectives(const Function &F,
// If none of reqntid* is specified, don't output reqntid directive.
unsigned reqntidx, reqntidy, reqntidz;
bool specified = false;
- if (!llvm::getReqNTIDx(F, reqntidx))
+ if (!getReqNTIDx(F, reqntidx))
reqntidx = 1;
else
specified = true;
- if (!llvm::getReqNTIDy(F, reqntidy))
+ if (!getReqNTIDy(F, reqntidy))
reqntidy = 1;
else
specified = true;
- if (!llvm::getReqNTIDz(F, reqntidz))
+ if (!getReqNTIDz(F, reqntidz))
reqntidz = 1;
else
specified = true;
@@ -537,15 +575,15 @@ void NVPTXAsmPrinter::emitKernelFunctionDirectives(const Function &F,
// If none of maxntid* is specified, don't output maxntid directive.
unsigned maxntidx, maxntidy, maxntidz;
specified = false;
- if (!llvm::getMaxNTIDx(F, maxntidx))
+ if (!getMaxNTIDx(F, maxntidx))
maxntidx = 1;
else
specified = true;
- if (!llvm::getMaxNTIDy(F, maxntidy))
+ if (!getMaxNTIDy(F, maxntidy))
maxntidy = 1;
else
specified = true;
- if (!llvm::getMaxNTIDz(F, maxntidz))
+ if (!getMaxNTIDz(F, maxntidz))
maxntidz = 1;
else
specified = true;
@@ -555,8 +593,12 @@ void NVPTXAsmPrinter::emitKernelFunctionDirectives(const Function &F,
<< "\n";
unsigned mincta;
- if (llvm::getMinCTASm(F, mincta))
+ if (getMinCTASm(F, mincta))
O << ".minnctapersm " << mincta << "\n";
+
+ unsigned maxnreg;
+ if (getMaxNReg(F, maxnreg))
+ O << ".maxnreg " << maxnreg << "\n";
}
std::string
@@ -615,12 +657,9 @@ void NVPTXAsmPrinter::printVecModifiedImmediate(
llvm_unreachable("Unknown Modifier on immediate operand");
}
-
-
void NVPTXAsmPrinter::emitDeclaration(const Function *F, raw_ostream &O) {
-
emitLinkageDirective(F, O);
- if (llvm::isKernelFunction(*F))
+ if (isKernelFunction(*F))
O << ".entry ";
else
O << ".func ";
@@ -682,7 +721,7 @@ static bool canDemoteGlobalVar(const GlobalVariable *gv, Function const *&f) {
if (!gv->hasInternalLinkage())
return false;
PointerType *Pty = gv->getType();
- if (Pty->getAddressSpace() != llvm::ADDRESS_SPACE_SHARED)
+ if (Pty->getAddressSpace() != ADDRESS_SPACE_SHARED)
return false;
const Function *oneFunc = nullptr;
@@ -697,7 +736,7 @@ static bool canDemoteGlobalVar(const GlobalVariable *gv, Function const *&f) {
}
static bool useFuncSeen(const Constant *C,
- llvm::DenseMap<const Function *, bool> &seenMap) {
+ DenseMap<const Function *, bool> &seenMap) {
for (const User *U : C->users()) {
if (const Constant *cu = dyn_cast<Constant>(U)) {
if (useFuncSeen(cu, seenMap))
@@ -717,7 +756,7 @@ static bool useFuncSeen(const Constant *C,
}
void NVPTXAsmPrinter::emitDeclarations(const Module &M, raw_ostream &O) {
- llvm::DenseMap<const Function *, bool> seenMap;
+ DenseMap<const Function *, bool> seenMap;
for (Module::const_iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) {
const Function *F = &*FI;
@@ -844,12 +883,12 @@ bool NVPTXAsmPrinter::doInitialization(Module &M) {
// We need to call the parent's one explicitly.
//bool Result = AsmPrinter::doInitialization(M);
- // Initialize TargetLoweringObjectFile.
+ // Initialize TargetLoweringObjectFile since we didn't do in
+ // AsmPrinter::doInitialization either right above or where it's commented out
+ // below.
const_cast<TargetLoweringObjectFile &>(getObjFileLowering())
.Initialize(OutContext, TM);
- Mang = new Mangler();
-
// Emit header before any dwarf directives are emitted below.
emitHeader(M, OS1, STI);
OutStreamer->EmitRawText(OS1.str());
@@ -1038,7 +1077,6 @@ void NVPTXAsmPrinter::emitLinkageDirective(const GlobalValue *V,
void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
raw_ostream &O,
bool processDemoted) {
-
// Skip meta data
if (GVar->hasSection()) {
if (GVar->getSection() == "llvm.metadata")
@@ -1067,13 +1105,13 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
O << ".weak ";
}
- if (llvm::isTexture(*GVar)) {
- O << ".global .texref " << llvm::getTextureName(*GVar) << ";\n";
+ if (isTexture(*GVar)) {
+ O << ".global .texref " << getTextureName(*GVar) << ";\n";
return;
}
- if (llvm::isSurface(*GVar)) {
- O << ".global .surfref " << llvm::getSurfaceName(*GVar) << ";\n";
+ if (isSurface(*GVar)) {
+ O << ".global .surfref " << getSurfaceName(*GVar) << ";\n";
return;
}
@@ -1086,8 +1124,8 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
return;
}
- if (llvm::isSampler(*GVar)) {
- O << ".global .samplerref " << llvm::getSamplerName(*GVar);
+ if (isSampler(*GVar)) {
+ O << ".global .samplerref " << getSamplerName(*GVar);
const Constant *Initializer = nullptr;
if (GVar->hasInitializer())
@@ -1148,12 +1186,11 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
}
if (GVar->hasPrivateLinkage()) {
-
- if (!strncmp(GVar->getName().data(), "unrollpragma", 12))
+ if (strncmp(GVar->getName().data(), "unrollpragma", 12) == 0)
return;
// FIXME - need better way (e.g. Metadata) to avoid generating this global
- if (!strncmp(GVar->getName().data(), "filename", 8))
+ if (strncmp(GVar->getName().data(), "filename", 8) == 0)
return;
if (GVar->use_empty())
return;
@@ -1197,8 +1234,8 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
// Ptx allows variable initilization only for constant and global state
// spaces.
if (GVar->hasInitializer()) {
- if ((PTy->getAddressSpace() == llvm::ADDRESS_SPACE_GLOBAL) ||
- (PTy->getAddressSpace() == llvm::ADDRESS_SPACE_CONST)) {
+ if ((PTy->getAddressSpace() == ADDRESS_SPACE_GLOBAL) ||
+ (PTy->getAddressSpace() == ADDRESS_SPACE_CONST)) {
const Constant *Initializer = GVar->getInitializer();
// 'undef' is treated as there is no value specified.
if (!Initializer->isNullValue() && !isa<UndefValue>(Initializer)) {
@@ -1231,8 +1268,8 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
ElementSize = DL.getTypeStoreSize(ETy);
// Ptx allows variable initilization only for constant and
// global state spaces.
- if (((PTy->getAddressSpace() == llvm::ADDRESS_SPACE_GLOBAL) ||
- (PTy->getAddressSpace() == llvm::ADDRESS_SPACE_CONST)) &&
+ if (((PTy->getAddressSpace() == ADDRESS_SPACE_GLOBAL) ||
+ (PTy->getAddressSpace() == ADDRESS_SPACE_CONST)) &&
GVar->hasInitializer()) {
const Constant *Initializer = GVar->getInitializer();
if (!isa<UndefValue>(Initializer) && !Initializer->isNullValue()) {
@@ -1283,7 +1320,6 @@ void NVPTXAsmPrinter::printModuleLevelGV(const GlobalVariable *GVar,
default:
llvm_unreachable("type not supported yet");
}
-
}
O << ";\n";
}
@@ -1303,16 +1339,16 @@ void NVPTXAsmPrinter::emitDemotedVars(const Function *f, raw_ostream &O) {
void NVPTXAsmPrinter::emitPTXAddressSpace(unsigned int AddressSpace,
raw_ostream &O) const {
switch (AddressSpace) {
- case llvm::ADDRESS_SPACE_LOCAL:
+ case ADDRESS_SPACE_LOCAL:
O << "local";
break;
- case llvm::ADDRESS_SPACE_GLOBAL:
+ case ADDRESS_SPACE_GLOBAL:
O << "global";
break;
- case llvm::ADDRESS_SPACE_CONST:
+ case ADDRESS_SPACE_CONST:
O << "const";
break;
- case llvm::ADDRESS_SPACE_SHARED:
+ case ADDRESS_SPACE_SHARED:
O << "shared";
break;
default:
@@ -1361,7 +1397,6 @@ NVPTXAsmPrinter::getPTXFundamentalTypeStr(Type *Ty, bool useB4PTR) const {
void NVPTXAsmPrinter::emitPTXGlobalVariable(const GlobalVariable *GVar,
raw_ostream &O) {
-
const DataLayout &DL = getDataLayout();
// GlobalVariables are always constant pointers themselves.
@@ -1404,7 +1439,6 @@ void NVPTXAsmPrinter::emitPTXGlobalVariable(const GlobalVariable *GVar,
default:
llvm_unreachable("type not supported yet");
}
- return;
}
static unsigned int getOpenCLAlignment(const DataLayout &DL, Type *Ty) {
@@ -1448,7 +1482,7 @@ void NVPTXAsmPrinter::emitFunctionParamList(const Function *F, raw_ostream &O) {
Function::const_arg_iterator I, E;
unsigned paramIndex = 0;
bool first = true;
- bool isKernelFunc = llvm::isKernelFunction(*F);
+ bool isKernelFunc = isKernelFunction(*F);
bool isABI = (nvptxSubtarget->getSmVersion() >= 20);
MVT thePointerTy = TLI->getPointerTy(DL);
@@ -1531,13 +1565,13 @@ void NVPTXAsmPrinter::emitFunctionParamList(const Function *F, raw_ostream &O) {
default:
O << ".ptr ";
break;
- case llvm::ADDRESS_SPACE_CONST:
+ case ADDRESS_SPACE_CONST:
O << ".ptr .const ";
break;
- case llvm::ADDRESS_SPACE_SHARED:
+ case ADDRESS_SPACE_SHARED:
O << ".ptr .shared ";
break;
- case llvm::ADDRESS_SPACE_GLOBAL:
+ case ADDRESS_SPACE_GLOBAL:
O << ".ptr .global ";
break;
}
@@ -1589,7 +1623,19 @@ void NVPTXAsmPrinter::emitFunctionParamList(const Function *F, raw_ostream &O) {
unsigned align = PAL.getParamAlignment(paramIndex + 1);
if (align == 0)
align = DL.getABITypeAlignment(ETy);
-
+ // Work around a bug in ptxas. When PTX code takes address of
+ // byval parameter with alignment < 4, ptxas generates code to
+ // spill argument into memory. Alas on sm_50+ ptxas generates
+ // SASS code that fails with misaligned access. To work around
+ // the problem, make sure that we align byval parameters by at
+ // least 4. Matching change must be made in LowerCall() where we
+ // prepare parameters for the call.
+ //
+ // TODO: this will need to be undone when we get to support multi-TU
+ // device-side compilation as it breaks ABI compatibility with nvcc.
+ // Hopefully ptxas bug is fixed by then.
+ if (!isKernelFunc && align < 4)
+ align = 4;
unsigned sz = DL.getTypeAllocSize(ETy);
O << "\t.param .align " << align << " .b8 ";
printParamName(I, paramIndex, O);
@@ -1648,10 +1694,10 @@ void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters(
//unsigned numRegClasses = TRI->getNumRegClasses();
// Emit the Fake Stack Object
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- int NumBytes = (int) MFI->getStackSize();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ int NumBytes = (int) MFI.getStackSize();
if (NumBytes) {
- O << "\t.local .align " << MFI->getMaxAlignment() << " .b8 \t" << DEPOTNAME
+ O << "\t.local .align " << MFI.getMaxAlignment() << " .b8 \t" << DEPOTNAME
<< getFunctionNumber() << "[" << NumBytes << "];\n";
if (static_cast<const NVPTXTargetMachine &>(MF.getTarget()).is64Bit()) {
O << "\t.reg .b64 \t%SP;\n";
@@ -1713,11 +1759,11 @@ void NVPTXAsmPrinter::printFPConstant(const ConstantFP *Fp, raw_ostream &O) {
if (Fp->getType()->getTypeID() == Type::FloatTyID) {
numHex = 8;
lead = "0f";
- APF.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &ignored);
+ APF.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &ignored);
} else if (Fp->getType()->getTypeID() == Type::DoubleTyID) {
numHex = 16;
lead = "0d";
- APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &ignored);
+ APF.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &ignored);
} else
llvm_unreachable("unsupported fp type");
@@ -1806,7 +1852,6 @@ static void ConvertDoubleToBytes(unsigned char *p, double val) {
void NVPTXAsmPrinter::bufferLEByte(const Constant *CPV, int Bytes,
AggBuffer *aggBuffer) {
-
const DataLayout &DL = getDataLayout();
if (isa<UndefValue>(CPV) || CPV->isNullValue()) {
@@ -1836,9 +1881,9 @@ void NVPTXAsmPrinter::bufferLEByte(const Constant *CPV, int Bytes,
ConvertIntToBytes<>(ptr, int32);
aggBuffer->addBytes(ptr, 4, Bytes);
break;
- } else if (const ConstantExpr *Cexpr = dyn_cast<ConstantExpr>(CPV)) {
- if (const ConstantInt *constInt = dyn_cast<ConstantInt>(
- ConstantFoldConstantExpression(Cexpr, DL))) {
+ } else if (const auto *Cexpr = dyn_cast<ConstantExpr>(CPV)) {
+ if (const auto *constInt = dyn_cast_or_null<ConstantInt>(
+ ConstantFoldConstant(Cexpr, DL))) {
int int32 = (int)(constInt->getZExtValue());
ConvertIntToBytes<>(ptr, int32);
aggBuffer->addBytes(ptr, 4, Bytes);
@@ -1859,8 +1904,8 @@ void NVPTXAsmPrinter::bufferLEByte(const Constant *CPV, int Bytes,
aggBuffer->addBytes(ptr, 8, Bytes);
break;
} else if (const ConstantExpr *Cexpr = dyn_cast<ConstantExpr>(CPV)) {
- if (const ConstantInt *constInt = dyn_cast<ConstantInt>(
- ConstantFoldConstantExpression(Cexpr, DL))) {
+ if (const auto *constInt = dyn_cast_or_null<ConstantInt>(
+ ConstantFoldConstant(Cexpr, DL))) {
long long int64 = (long long)(constInt->getZExtValue());
ConvertIntToBytes<>(ptr, int64);
aggBuffer->addBytes(ptr, 8, Bytes);
@@ -1971,7 +2016,6 @@ void NVPTXAsmPrinter::bufferAggregateConstant(const Constant *CPV,
// buildTypeNameMap - Run through symbol table looking for type names.
//
-
bool NVPTXAsmPrinter::ignoreLoc(const MachineInstr &MI) {
switch (MI.getOpcode()) {
default:
@@ -2062,8 +2106,8 @@ NVPTXAsmPrinter::lowerConstantForGV(const Constant *CV, bool ProcessingGeneric)
// If the code isn't optimized, there may be outstanding folding
// opportunities. Attempt to fold the expression using DataLayout as a
// last resort before giving up.
- if (Constant *C = ConstantFoldConstantExpression(CE, getDataLayout()))
- if (C != CE)
+ if (Constant *C = ConstantFoldConstant(CE, getDataLayout()))
+ if (C && C != CE)
return lowerConstantForGV(C, ProcessingGeneric);
// Otherwise report the problem to the user.
@@ -2086,7 +2130,7 @@ NVPTXAsmPrinter::lowerConstantForGV(const Constant *CV, bool ProcessingGeneric)
raw_string_ostream OS(S);
OS << "Unsupported expression in static initializer: ";
CE->printAsOperand(OS, /*PrintType=*/ false,
- !MF ? 0 : MF->getFunction()->getParent());
+ !MF ? nullptr : MF->getFunction()->getParent());
report_fatal_error(OS.str());
}
@@ -2112,7 +2156,7 @@ NVPTXAsmPrinter::lowerConstantForGV(const Constant *CV, bool ProcessingGeneric)
// expression properly. This is important for differences between
// blockaddress labels. Since the two labels are in the same function, it
// is reasonable to treat their delta as a 32-bit value.
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
case Instruction::BitCast:
return lowerConstantForGV(CE->getOperand(0), ProcessingGeneric);
@@ -2316,7 +2360,7 @@ void NVPTXAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
raw_ostream &O, const char *Modifier) {
printOperand(MI, opNum, O);
- if (Modifier && !strcmp(Modifier, "add")) {
+ if (Modifier && strcmp(Modifier, "add") == 0) {
O << ", ";
printOperand(MI, opNum + 1, O);
} else {
@@ -2368,6 +2412,6 @@ std::string LineReader::readLine(unsigned lineNum) {
// Force static initialization.
extern "C" void LLVMInitializeNVPTXAsmPrinter() {
- RegisterAsmPrinter<NVPTXAsmPrinter> X(TheNVPTXTarget32);
- RegisterAsmPrinter<NVPTXAsmPrinter> Y(TheNVPTXTarget64);
+ RegisterAsmPrinter<NVPTXAsmPrinter> X(getTheNVPTXTarget32());
+ RegisterAsmPrinter<NVPTXAsmPrinter> Y(getTheNVPTXTarget64());
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h b/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h
index 85660fb..8ec3476 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.h
@@ -1,4 +1,4 @@
-//===-- NVPTXAsmPrinter.h - NVPTX LLVM assembly writer --------------------===//
+//===-- NVPTXAsmPrinter.h - NVPTX LLVM assembly writer ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -18,17 +18,34 @@
#include "NVPTX.h"
#include "NVPTXSubtarget.h"
#include "NVPTXTargetMachine.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
-#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Value.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
-#include "llvm/Support/FormattedStream.h"
+#include "llvm/PassAnalysisSupport.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
+#include <algorithm>
+#include <cassert>
#include <fstream>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
// The ptx syntax and format is very different from that usually seem in a .s
// file,
@@ -40,7 +57,8 @@
// (subclass of MCStreamer).
namespace llvm {
- class MCOperand;
+
+class MCOperand;
class LineReader {
private:
@@ -49,14 +67,17 @@ private:
char buff[512];
std::string theFileName;
SmallVector<unsigned, 32> lineOffset;
+
public:
LineReader(std::string filename) {
theCurLine = 0;
fstr.open(filename.c_str());
theFileName = filename;
}
- std::string fileName() { return theFileName; }
+
~LineReader() { fstr.close(); }
+
+ std::string fileName() { return theFileName; }
std::string readLine(unsigned line);
};
@@ -107,6 +128,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter {
numSymbols = 0;
EmitGeneric = AP.EmitGeneric;
}
+
unsigned addBytes(unsigned char *Ptr, int Num, int Bytes) {
assert((curpos + Num) <= size);
assert((curpos + Bytes) <= size);
@@ -120,6 +142,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter {
}
return curpos;
}
+
unsigned addZeros(int Num) {
assert((curpos + Num) <= size);
for (int i = 0; i < Num; ++i) {
@@ -128,12 +151,14 @@ class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter {
}
return curpos;
}
+
void addSymbol(const Value *GVar, const Value *GVarBeforeStripping) {
symbolPosInBuffer.push_back(curpos);
Symbols.push_back(GVar);
SymbolsBeforeStripping.push_back(GVarBeforeStripping);
numSymbols++;
}
+
void print() {
if (numSymbols == 0) {
// print out in bytes
@@ -195,7 +220,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter {
void emitSrcInText(StringRef filename, unsigned line);
private:
- const char *getPassName() const override { return "NVPTX Assembly Printer"; }
+ StringRef getPassName() const override { return "NVPTX Assembly Printer"; }
const Function *F;
std::string CurrentFnName;
@@ -267,7 +292,7 @@ private:
std::map<Type *, std::string> TypeNameMap;
// List of variables demoted to a function scope.
- std::map<const Function *, std::vector<const GlobalVariable *> > localDecls;
+ std::map<const Function *, std::vector<const GlobalVariable *>> localDecls;
// To record filename to ID mapping
std::map<std::string, unsigned> filenameMap;
@@ -292,7 +317,8 @@ private:
bool isLoopHeaderOfNoUnroll(const MachineBasicBlock &MBB) const;
- LineReader *reader;
+ LineReader *reader = nullptr;
+
LineReader *getReader(const std::string &);
// Used to control the need to emit .generic() in the initializer of
@@ -312,20 +338,17 @@ public:
NVPTXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)),
EmitGeneric(static_cast<NVPTXTargetMachine &>(TM).getDrvInterface() ==
- NVPTX::CUDA) {
- CurrentBankselLabelInBasicBlock = "";
- reader = nullptr;
- }
+ NVPTX::CUDA) {}
- ~NVPTXAsmPrinter() {
- if (!reader)
- delete reader;
+ ~NVPTXAsmPrinter() override {
+ delete reader;
}
bool runOnMachineFunction(MachineFunction &F) override {
nvptxSubtarget = &F.getSubtarget<NVPTXSubtarget>();
return AsmPrinter::runOnMachineFunction(F);
}
+
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineLoopInfo>();
AsmPrinter::getAnalysisUsage(AU);
@@ -338,6 +361,7 @@ public:
DebugLoc prevDebugLoc;
void emitLineNumberAsDotLoc(const MachineInstr &);
};
-} // end of namespace
-#endif
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp
deleted file mode 100644
index 7c5a541..0000000
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXFavorNonGenericAddrSpaces.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-//===-- NVPTXFavorNonGenericAddrSpace.cpp - ---------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// FIXME: This pass is deprecated in favor of NVPTXInferAddressSpaces, which
-// uses a new algorithm that handles pointer induction variables.
-//
-// When a load/store accesses the generic address space, checks whether the
-// address is casted from a non-generic address space. If so, remove this
-// addrspacecast because accessing non-generic address spaces is typically
-// faster. Besides removing addrspacecasts directly used by loads/stores, this
-// optimization also recursively traces into a GEP's pointer operand and a
-// bitcast's source to find more eliminable addrspacecasts.
-//
-// For instance, the code below loads a float from an array allocated in
-// addrspace(3).
-//
-// %0 = addrspacecast [10 x float] addrspace(3)* @a to [10 x float]*
-// %1 = gep [10 x float]* %0, i64 0, i64 %i
-// %2 = bitcast float* %1 to i32*
-// %3 = load i32* %2 ; emits ld.u32
-//
-// First, function hoistAddrSpaceCastFrom reorders the addrspacecast, the GEP,
-// and the bitcast to expose more optimization opportunities to function
-// optimizeMemoryInst. The intermediate code looks like:
-//
-// %0 = gep [10 x float] addrspace(3)* @a, i64 0, i64 %i
-// %1 = bitcast float addrspace(3)* %0 to i32 addrspace(3)*
-// %2 = addrspacecast i32 addrspace(3)* %1 to i32*
-// %3 = load i32* %2 ; still emits ld.u32, but will be optimized shortly
-//
-// Then, function optimizeMemoryInstruction detects a load from addrspacecast'ed
-// generic pointers, and folds the load and the addrspacecast into a load from
-// the original address space. The final code looks like:
-//
-// %0 = gep [10 x float] addrspace(3)* @a, i64 0, i64 %i
-// %1 = bitcast float addrspace(3)* %0 to i32 addrspace(3)*
-// %3 = load i32 addrspace(3)* %1 ; emits ld.shared.f32
-//
-// This pass may remove an addrspacecast in a different BB. Therefore, we
-// implement it as a FunctionPass.
-//
-// TODO:
-// The current implementation doesn't handle PHINodes. Eliminating
-// addrspacecasts used by PHINodes is trickier because PHINodes can introduce
-// loops in data flow. For example,
-//
-// %generic.input = addrspacecast float addrspace(3)* %input to float*
-// loop:
-// %y = phi [ %generic.input, %y2 ]
-// %y2 = getelementptr %y, 1
-// %v = load %y2
-// br ..., label %loop, ...
-//
-// Marking %y2 shared depends on marking %y shared, but %y also data-flow
-// depends on %y2. We probably need an iterative fix-point algorithm on handle
-// this case.
-//
-//===----------------------------------------------------------------------===//
-
-#include "NVPTX.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/Support/CommandLine.h"
-
-using namespace llvm;
-
-// An option to disable this optimization. Enable it by default.
-static cl::opt<bool> DisableFavorNonGeneric(
- "disable-nvptx-favor-non-generic",
- cl::init(false),
- cl::desc("Do not convert generic address space usage "
- "to non-generic address space usage"),
- cl::Hidden);
-
-namespace {
-/// \brief NVPTXFavorNonGenericAddrSpaces
-class NVPTXFavorNonGenericAddrSpaces : public FunctionPass {
-public:
- static char ID;
- NVPTXFavorNonGenericAddrSpaces() : FunctionPass(ID) {}
- bool runOnFunction(Function &F) override;
-
-private:
- /// Optimizes load/store instructions. Idx is the index of the pointer operand
- /// (0 for load, and 1 for store). Returns true if it changes anything.
- bool optimizeMemoryInstruction(Instruction *I, unsigned Idx);
- /// Recursively traces into a GEP's pointer operand or a bitcast's source to
- /// find an eliminable addrspacecast, and hoists that addrspacecast to the
- /// outermost level. For example, this function transforms
- /// bitcast(gep(gep(addrspacecast(X))))
- /// to
- /// addrspacecast(bitcast(gep(gep(X)))).
- ///
- /// This reordering exposes to optimizeMemoryInstruction more
- /// optimization opportunities on loads and stores.
- ///
- /// If this function successfully hoists an eliminable addrspacecast or V is
- /// already such an addrspacecast, it returns the transformed value (which is
- /// guaranteed to be an addrspacecast); otherwise, it returns nullptr.
- Value *hoistAddrSpaceCastFrom(Value *V, int Depth = 0);
- /// Helper function for GEPs.
- Value *hoistAddrSpaceCastFromGEP(GEPOperator *GEP, int Depth);
- /// Helper function for bitcasts.
- Value *hoistAddrSpaceCastFromBitCast(BitCastOperator *BC, int Depth);
-};
-}
-
-char NVPTXFavorNonGenericAddrSpaces::ID = 0;
-
-namespace llvm {
-void initializeNVPTXFavorNonGenericAddrSpacesPass(PassRegistry &);
-}
-INITIALIZE_PASS(NVPTXFavorNonGenericAddrSpaces, "nvptx-favor-non-generic",
- "Remove unnecessary non-generic-to-generic addrspacecasts",
- false, false)
-
-// Decides whether V is an addrspacecast and shortcutting V in load/store is
-// valid and beneficial.
-static bool isEliminableAddrSpaceCast(Value *V) {
- // Returns false if V is not even an addrspacecast.
- Operator *Cast = dyn_cast<Operator>(V);
- if (Cast == nullptr || Cast->getOpcode() != Instruction::AddrSpaceCast)
- return false;
-
- Value *Src = Cast->getOperand(0);
- PointerType *SrcTy = cast<PointerType>(Src->getType());
- PointerType *DestTy = cast<PointerType>(Cast->getType());
- // TODO: For now, we only handle the case where the addrspacecast only changes
- // the address space but not the type. If the type also changes, we could
- // still get rid of the addrspacecast by adding an extra bitcast, but we
- // rarely see such scenarios.
- if (SrcTy->getElementType() != DestTy->getElementType())
- return false;
-
- // Checks whether the addrspacecast is from a non-generic address space to the
- // generic address space.
- return (SrcTy->getAddressSpace() != AddressSpace::ADDRESS_SPACE_GENERIC &&
- DestTy->getAddressSpace() == AddressSpace::ADDRESS_SPACE_GENERIC);
-}
-
-Value *NVPTXFavorNonGenericAddrSpaces::hoistAddrSpaceCastFromGEP(
- GEPOperator *GEP, int Depth) {
- Value *NewOperand =
- hoistAddrSpaceCastFrom(GEP->getPointerOperand(), Depth + 1);
- if (NewOperand == nullptr)
- return nullptr;
-
- // hoistAddrSpaceCastFrom returns an eliminable addrspacecast or nullptr.
- assert(isEliminableAddrSpaceCast(NewOperand));
- Operator *Cast = cast<Operator>(NewOperand);
-
- SmallVector<Value *, 8> Indices(GEP->idx_begin(), GEP->idx_end());
- Value *NewASC;
- if (Instruction *GEPI = dyn_cast<Instruction>(GEP)) {
- // GEP = gep (addrspacecast X), indices
- // =>
- // NewGEP = gep X, indices
- // NewASC = addrspacecast NewGEP
- GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
- GEP->getSourceElementType(), Cast->getOperand(0), Indices,
- "", GEPI);
- NewGEP->setIsInBounds(GEP->isInBounds());
- NewGEP->takeName(GEP);
- NewASC = new AddrSpaceCastInst(NewGEP, GEP->getType(), "", GEPI);
- // Without RAUWing GEP, the compiler would visit GEP again and emit
- // redundant instructions. This is exercised in test @rauw in
- // access-non-generic.ll.
- GEP->replaceAllUsesWith(NewASC);
- } else {
- // GEP is a constant expression.
- Constant *NewGEP = ConstantExpr::getGetElementPtr(
- GEP->getSourceElementType(), cast<Constant>(Cast->getOperand(0)),
- Indices, GEP->isInBounds());
- NewASC = ConstantExpr::getAddrSpaceCast(NewGEP, GEP->getType());
- }
- return NewASC;
-}
-
-Value *NVPTXFavorNonGenericAddrSpaces::hoistAddrSpaceCastFromBitCast(
- BitCastOperator *BC, int Depth) {
- Value *NewOperand = hoistAddrSpaceCastFrom(BC->getOperand(0), Depth + 1);
- if (NewOperand == nullptr)
- return nullptr;
-
- // hoistAddrSpaceCastFrom returns an eliminable addrspacecast or nullptr.
- assert(isEliminableAddrSpaceCast(NewOperand));
- Operator *Cast = cast<Operator>(NewOperand);
-
- // Cast = addrspacecast Src
- // BC = bitcast Cast
- // =>
- // Cast' = bitcast Src
- // BC' = addrspacecast Cast'
- Value *Src = Cast->getOperand(0);
- Type *TypeOfNewCast =
- PointerType::get(BC->getType()->getPointerElementType(),
- Src->getType()->getPointerAddressSpace());
- Value *NewBC;
- if (BitCastInst *BCI = dyn_cast<BitCastInst>(BC)) {
- Value *NewCast = new BitCastInst(Src, TypeOfNewCast, "", BCI);
- NewBC = new AddrSpaceCastInst(NewCast, BC->getType(), "", BCI);
- NewBC->takeName(BC);
- // Without RAUWing BC, the compiler would visit BC again and emit
- // redundant instructions. This is exercised in test @rauw in
- // access-non-generic.ll.
- BC->replaceAllUsesWith(NewBC);
- } else {
- // BC is a constant expression.
- Constant *NewCast =
- ConstantExpr::getBitCast(cast<Constant>(Src), TypeOfNewCast);
- NewBC = ConstantExpr::getAddrSpaceCast(NewCast, BC->getType());
- }
- return NewBC;
-}
-
-Value *NVPTXFavorNonGenericAddrSpaces::hoistAddrSpaceCastFrom(Value *V,
- int Depth) {
- // Returns V if V is already an eliminable addrspacecast.
- if (isEliminableAddrSpaceCast(V))
- return V;
-
- // Limit the depth to prevent this recursive function from running too long.
- const int MaxDepth = 20;
- if (Depth >= MaxDepth)
- return nullptr;
-
- // If V is a GEP or bitcast, hoist the addrspacecast if any from its pointer
- // operand. This enables optimizeMemoryInstruction to shortcut addrspacecasts
- // that are not directly used by the load/store.
- if (GEPOperator *GEP = dyn_cast<GEPOperator>(V))
- return hoistAddrSpaceCastFromGEP(GEP, Depth);
-
- if (BitCastOperator *BC = dyn_cast<BitCastOperator>(V))
- return hoistAddrSpaceCastFromBitCast(BC, Depth);
-
- return nullptr;
-}
-
-bool NVPTXFavorNonGenericAddrSpaces::optimizeMemoryInstruction(Instruction *MI,
- unsigned Idx) {
- Value *NewOperand = hoistAddrSpaceCastFrom(MI->getOperand(Idx));
- if (NewOperand == nullptr)
- return false;
-
- // load/store (addrspacecast X) => load/store X if shortcutting the
- // addrspacecast is valid and can improve performance.
- //
- // e.g.,
- // %1 = addrspacecast float addrspace(3)* %0 to float*
- // %2 = load float* %1
- // ->
- // %2 = load float addrspace(3)* %0
- //
- // Note: the addrspacecast can also be a constant expression.
- assert(isEliminableAddrSpaceCast(NewOperand));
- Operator *ASC = dyn_cast<Operator>(NewOperand);
- MI->setOperand(Idx, ASC->getOperand(0));
- return true;
-}
-
-bool NVPTXFavorNonGenericAddrSpaces::runOnFunction(Function &F) {
- if (DisableFavorNonGeneric || skipFunction(F))
- return false;
-
- bool Changed = false;
- for (BasicBlock &B : F) {
- for (Instruction &I : B) {
- if (isa<LoadInst>(I)) {
- // V = load P
- Changed |= optimizeMemoryInstruction(&I, 0);
- } else if (isa<StoreInst>(I)) {
- // store V, P
- Changed |= optimizeMemoryInstruction(&I, 1);
- }
- }
- }
- return Changed;
-}
-
-FunctionPass *llvm::createNVPTXFavorNonGenericAddrSpacesPass() {
- return new NVPTXFavorNonGenericAddrSpaces();
-}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
index bbcb497..6ced2f6 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
@@ -32,7 +32,7 @@ bool NVPTXFrameLowering::hasFP(const MachineFunction &MF) const { return true; }
void NVPTXFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- if (MF.getFrameInfo()->hasStackObjects()) {
+ if (MF.getFrameInfo().hasStackObjects()) {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
MachineInstr *MI = &MBB.front();
MachineRegisterInfo &MR = MF.getRegInfo();
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
index 66a9640..3907762 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXGenericToNVVM.cpp
@@ -15,7 +15,6 @@
#include "NVPTX.h"
#include "MCTargetDesc/NVPTXBaseInfo.h"
#include "NVPTXUtilities.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
@@ -55,7 +54,6 @@ private:
IRBuilder<> &Builder);
Value *remapConstantExpr(Module *M, Function *F, ConstantExpr *C,
IRBuilder<> &Builder);
- void remapNamedMDNode(ValueToValueMapTy &VM, NamedMDNode *N);
typedef ValueMap<GlobalVariable *, GlobalVariable *> GVMapTy;
typedef ValueMap<Constant *, Value *> ConstantToValueMapTy;
@@ -130,12 +128,6 @@ bool GenericToNVVM::runOnModule(Module &M) {
for (auto I = GVMap.begin(), E = GVMap.end(); I != E; ++I)
VM[I->first] = I->second;
- // Walk through the metadata section and update the debug information
- // associated with the global variables in the default address space.
- for (NamedMDNode &I : M.named_metadata()) {
- remapNamedMDNode(VM, &I);
- }
-
// Walk through the global variable initializers, and replace any use of
// original global variables in GVMap with a use of the corresponding copies
// in GVMap. The copies need to be bitcast to the original global variable
@@ -360,32 +352,3 @@ Value *GenericToNVVM::remapConstantExpr(Module *M, Function *F, ConstantExpr *C,
llvm_unreachable("GenericToNVVM encountered an unsupported ConstantExpr");
}
}
-
-void GenericToNVVM::remapNamedMDNode(ValueToValueMapTy &VM, NamedMDNode *N) {
-
- bool OperandChanged = false;
- SmallVector<MDNode *, 16> NewOperands;
- unsigned NumOperands = N->getNumOperands();
-
- // Check if any operand is or contains a global variable in GVMap, and thus
- // converted to another value.
- for (unsigned i = 0; i < NumOperands; ++i) {
- MDNode *Operand = N->getOperand(i);
- MDNode *NewOperand = MapMetadata(Operand, VM);
- OperandChanged |= Operand != NewOperand;
- NewOperands.push_back(NewOperand);
- }
-
- // If none of the operands has been modified, return immediately.
- if (!OperandChanged) {
- return;
- }
-
- // Replace the old operands with the new operands.
- N->dropAllReferences();
- for (SmallVectorImpl<MDNode *>::iterator I = NewOperands.begin(),
- E = NewOperands.end();
- I != E; ++I) {
- N->addOperand(*I);
- }
-}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
index 61c6758..43c478f 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
@@ -558,21 +558,30 @@ static unsigned int getCodeAddrSpace(MemSDNode *N) {
static bool canLowerToLDG(MemSDNode *N, const NVPTXSubtarget &Subtarget,
unsigned CodeAddrSpace, MachineFunction *F) {
- // To use non-coherent caching, the load has to be from global
- // memory and we have to prove that the memory area is not written
- // to anywhere for the duration of the kernel call, not even after
- // the load.
+ // We use ldg (i.e. ld.global.nc) for invariant loads from the global address
+ // space.
//
- // To ensure that there are no writes to the memory, we require the
- // underlying pointer to be a noalias (__restrict) kernel parameter
- // that is never used for a write. We can only do this for kernel
- // functions since from within a device function, we cannot know if
- // there were or will be writes to the memory from the caller - or we
- // could, but then we would have to do inter-procedural analysis.
- if (!Subtarget.hasLDG() || CodeAddrSpace != NVPTX::PTXLdStInstCode::GLOBAL ||
- !isKernelFunction(*F->getFunction())) {
+ // We have two ways of identifying invariant loads: Loads may be explicitly
+ // marked as invariant, or we may infer them to be invariant.
+ //
+ // We currently infer invariance only for kernel function pointer params that
+ // are noalias (i.e. __restrict) and never written to.
+ //
+ // TODO: Perform a more powerful invariance analysis (ideally IPO, and ideally
+ // not during the SelectionDAG phase).
+ //
+ // TODO: Infer invariance only at -O2. We still want to use ldg at -O0 for
+ // explicitly invariant loads because these are how clang tells us to use ldg
+ // when the user uses a builtin.
+ if (!Subtarget.hasLDG() || CodeAddrSpace != NVPTX::PTXLdStInstCode::GLOBAL)
+ return false;
+
+ if (N->isInvariant())
+ return true;
+
+ // Load wasn't explicitly invariant. Attempt to infer invariance.
+ if (!isKernelFunction(*F->getFunction()))
return false;
- }
// We use GetUnderlyingObjects() here instead of
// GetUnderlyingObject() mainly because the former looks through phi
@@ -4902,7 +4911,7 @@ bool NVPTXDAGToDAGISel::tryBFE(SDNode *N) {
uint64_t StartVal = StartConst->getZExtValue();
// How many "good" bits do we have left? "good" is defined here as bits
// that exist in the original value, not shifted in.
- uint64_t GoodBits = Start.getValueType().getSizeInBits() - StartVal;
+ uint64_t GoodBits = Start.getValueSizeInBits() - StartVal;
if (NumBits > GoodBits) {
// Do not handle the case where bits have been shifted in. In theory
// we could handle this, but the cost is likely higher than just
@@ -5010,15 +5019,14 @@ bool NVPTXDAGToDAGISel::tryBFE(SDNode *N) {
// If the outer shift is more than the type size, we have no bitfield to
// extract (since we also check that the inner shift is <= the outer shift
// then this also implies that the inner shift is < the type size)
- if (OuterShiftAmt >= Val.getValueType().getSizeInBits()) {
+ if (OuterShiftAmt >= Val.getValueSizeInBits()) {
return false;
}
- Start =
- CurDAG->getTargetConstant(OuterShiftAmt - InnerShiftAmt, DL, MVT::i32);
- Len =
- CurDAG->getTargetConstant(Val.getValueType().getSizeInBits() -
- OuterShiftAmt, DL, MVT::i32);
+ Start = CurDAG->getTargetConstant(OuterShiftAmt - InnerShiftAmt, DL,
+ MVT::i32);
+ Len = CurDAG->getTargetConstant(Val.getValueSizeInBits() - OuterShiftAmt,
+ DL, MVT::i32);
if (N->getOpcode() == ISD::SRA) {
// If we have a arithmetic right shift, we need to use the signed bfe
@@ -5076,11 +5084,12 @@ bool NVPTXDAGToDAGISel::SelectDirectAddr(SDValue N, SDValue &Address) {
Address = N.getOperand(0);
return true;
}
- if (N.getOpcode() == ISD::INTRINSIC_WO_CHAIN) {
- unsigned IID = cast<ConstantSDNode>(N.getOperand(0))->getZExtValue();
- if (IID == Intrinsic::nvvm_ptr_gen_to_param)
- if (N.getOperand(1).getOpcode() == NVPTXISD::MoveParam)
- return (SelectDirectAddr(N.getOperand(1).getOperand(0), Address));
+ // addrspacecast(MoveParam(arg_symbol) to addrspace(PARAM)) -> arg_symbol
+ if (AddrSpaceCastSDNode *CastN = dyn_cast<AddrSpaceCastSDNode>(N)) {
+ if (CastN->getSrcAddressSpace() == ADDRESS_SPACE_GENERIC &&
+ CastN->getDestAddressSpace() == ADDRESS_SPACE_PARAM &&
+ CastN->getOperand(0).getOpcode() == NVPTXISD::MoveParam)
+ return SelectDirectAddr(CastN->getOperand(0).getOperand(0), Address);
}
return false;
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.h b/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.h
index d53c92f..0591035 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.h
@@ -40,7 +40,7 @@ public:
CodeGenOpt::Level OptLevel);
// Pass Name
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "NVPTX DAG->DAG Pattern Instruction Selection";
}
bool runOnMachineFunction(MachineFunction &MF) override;
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
index f28c89c..7a760fd 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
@@ -1,3 +1,4 @@
+//===-- NVPTXISelLowering.cpp - NVPTX DAG Lowering Implementation ---------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,31 +12,55 @@
//
//===----------------------------------------------------------------------===//
-#include "NVPTXISelLowering.h"
+#include "MCTargetDesc/NVPTXBaseInfo.h"
#include "NVPTX.h"
+#include "NVPTXISelLowering.h"
+#include "NVPTXSection.h"
+#include "NVPTXSubtarget.h"
#include "NVPTXTargetMachine.h"
#include "NVPTXTargetObjectFile.h"
#include "NVPTXUtilities.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/Analysis.h"
-#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SelectionDAGNodes.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/Argument.h"
+#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
-#include "llvm/MC/MCSectionELF.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetCallingConv.h"
+#include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
#undef DEBUG_TYPE
#define DEBUG_TYPE "nvptx-lower"
@@ -109,7 +134,6 @@ static void ComputePTXValueVTs(const TargetLowering &TLI, const DataLayout &DL,
NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
const NVPTXSubtarget &STI)
: TargetLowering(TM), nvTM(&TM), STI(STI) {
-
// always lower memset, memcpy, and memmove intrinsics to load/store
// instructions, rather
// then generating calls to memset, mempcy or memmove.
@@ -206,7 +230,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
// intrinsics.
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
- // Turn FP extload into load/fextend
+ // Turn FP extload into load/fpextend
setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
@@ -278,6 +302,30 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
setTargetDAGCombine(ISD::MUL);
setTargetDAGCombine(ISD::SHL);
setTargetDAGCombine(ISD::SELECT);
+ setTargetDAGCombine(ISD::SREM);
+ setTargetDAGCombine(ISD::UREM);
+
+ // Library functions. These default to Expand, but we have instructions
+ // for them.
+ setOperationAction(ISD::FCEIL, MVT::f32, Legal);
+ setOperationAction(ISD::FCEIL, MVT::f64, Legal);
+ setOperationAction(ISD::FFLOOR, MVT::f32, Legal);
+ setOperationAction(ISD::FFLOOR, MVT::f64, Legal);
+ setOperationAction(ISD::FNEARBYINT, MVT::f32, Legal);
+ setOperationAction(ISD::FNEARBYINT, MVT::f64, Legal);
+ setOperationAction(ISD::FRINT, MVT::f32, Legal);
+ setOperationAction(ISD::FRINT, MVT::f64, Legal);
+ setOperationAction(ISD::FROUND, MVT::f32, Legal);
+ setOperationAction(ISD::FROUND, MVT::f64, Legal);
+ setOperationAction(ISD::FTRUNC, MVT::f32, Legal);
+ setOperationAction(ISD::FTRUNC, MVT::f64, Legal);
+ setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
+ setOperationAction(ISD::FMINNUM, MVT::f64, Legal);
+ setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
+ setOperationAction(ISD::FMAXNUM, MVT::f64, Legal);
+
+ // No FEXP2, FLOG2. The PTX ex2 and log2 functions are always approximate.
+ // No FPOW or FREM in PTX.
// Now deduce the information based on the above mentioned
// actions
@@ -957,7 +1005,7 @@ std::string NVPTXTargetLowering::getPrototype(
unsigned align = 0;
const CallInst *CallI = cast<CallInst>(CS->getInstruction());
// +1 because index 0 is reserved for return type alignment
- if (!llvm::getAlign(*CallI, i + 1, align))
+ if (!getAlign(*CallI, i + 1, align))
align = DL.getABITypeAlignment(Ty);
unsigned sz = DL.getTypeAllocSize(Ty);
O << ".param .align " << align << " .b8 ";
@@ -1002,11 +1050,15 @@ std::string NVPTXTargetLowering::getPrototype(
return O.str();
}
-unsigned
-NVPTXTargetLowering::getArgumentAlignment(SDValue Callee,
- const ImmutableCallSite *CS,
- Type *Ty,
- unsigned Idx) const {
+unsigned NVPTXTargetLowering::getArgumentAlignment(SDValue Callee,
+ const ImmutableCallSite *CS,
+ Type *Ty, unsigned Idx,
+ const DataLayout &DL) const {
+ if (!CS) {
+ // CallSite is zero, fallback to ABI type alignment
+ return DL.getABITypeAlignment(Ty);
+ }
+
unsigned Align = 0;
const Value *DirectCallee = CS->getCalledFunction();
@@ -1019,12 +1071,12 @@ NVPTXTargetLowering::getArgumentAlignment(SDValue Callee,
// With bitcast'd call targets, the instruction will be the call
if (isa<CallInst>(CalleeI)) {
// Check if we have call alignment metadata
- if (llvm::getAlign(*cast<CallInst>(CalleeI), Idx, Align))
+ if (getAlign(*cast<CallInst>(CalleeI), Idx, Align))
return Align;
const Value *CalleeV = cast<CallInst>(CalleeI)->getCalledValue();
// Ignore any bitcast instructions
- while(isa<ConstantExpr>(CalleeV)) {
+ while (isa<ConstantExpr>(CalleeV)) {
const ConstantExpr *CE = cast<ConstantExpr>(CalleeV);
if (!CE->isCast())
break;
@@ -1042,12 +1094,11 @@ NVPTXTargetLowering::getArgumentAlignment(SDValue Callee,
// Check for function alignment information if we found that the
// ultimate target is a Function
if (DirectCallee)
- if (llvm::getAlign(*cast<Function>(DirectCallee), Idx, Align))
+ if (getAlign(*cast<Function>(DirectCallee), Idx, Align))
return Align;
// Call is indirect or alignment information is not available, fall back to
// the ABI type alignment
- auto &DL = CS->getCaller()->getParent()->getDataLayout();
return DL.getABITypeAlignment(Ty);
}
@@ -1104,7 +1155,8 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
ComputePTXValueVTs(*this, DAG.getDataLayout(), Ty, vtparts, &Offsets,
0);
- unsigned align = getArgumentAlignment(Callee, CS, Ty, paramCount + 1);
+ unsigned align =
+ getArgumentAlignment(Callee, CS, Ty, paramCount + 1, DL);
// declare .param .align <align> .b8 .param<n>[<size>];
unsigned sz = DL.getTypeAllocSize(Ty);
SDVTList DeclareParamVTs = DAG.getVTList(MVT::Other, MVT::Glue);
@@ -1144,7 +1196,8 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
}
if (Ty->isVectorTy()) {
EVT ObjectVT = getValueType(DL, Ty);
- unsigned align = getArgumentAlignment(Callee, CS, Ty, paramCount + 1);
+ unsigned align =
+ getArgumentAlignment(Callee, CS, Ty, paramCount + 1, DL);
// declare .param .align <align> .b8 .param<n>[<size>];
unsigned sz = DL.getTypeAllocSize(Ty);
SDVTList DeclareParamVTs = DAG.getVTList(MVT::Other, MVT::Glue);
@@ -1337,11 +1390,15 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// The ByValAlign in the Outs[OIdx].Flags is alway set at this point,
// so we don't need to worry about natural alignment or not.
// See TargetLowering::LowerCallTo().
- SDValue DeclareParamOps[] = {
- Chain, DAG.getConstant(Outs[OIdx].Flags.getByValAlign(), dl, MVT::i32),
- DAG.getConstant(paramCount, dl, MVT::i32),
- DAG.getConstant(sz, dl, MVT::i32), InFlag
- };
+
+ // Enforce minumum alignment of 4 to work around ptxas miscompile
+ // for sm_50+. See corresponding alignment adjustment in
+ // emitFunctionParamList() for details.
+ if (ArgAlign < 4)
+ ArgAlign = 4;
+ SDValue DeclareParamOps[] = {Chain, DAG.getConstant(ArgAlign, dl, MVT::i32),
+ DAG.getConstant(paramCount, dl, MVT::i32),
+ DAG.getConstant(sz, dl, MVT::i32), InFlag};
Chain = DAG.getNode(NVPTXISD::DeclareParam, dl, DeclareParamVTs,
DeclareParamOps);
InFlag = Chain.getValue(1);
@@ -1400,7 +1457,7 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
DeclareRetOps);
InFlag = Chain.getValue(1);
} else {
- retAlignment = getArgumentAlignment(Callee, CS, retTy, 0);
+ retAlignment = getArgumentAlignment(Callee, CS, retTy, 0, DL);
SDVTList DeclareRetVTs = DAG.getVTList(MVT::Other, MVT::Glue);
SDValue DeclareRetOps[] = { Chain,
DAG.getConstant(retAlignment, dl, MVT::i32),
@@ -1607,9 +1664,10 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
} else {
SmallVector<EVT, 16> VTs;
SmallVector<uint64_t, 16> Offsets;
- ComputePTXValueVTs(*this, DAG.getDataLayout(), retTy, VTs, &Offsets, 0);
+ auto &DL = DAG.getDataLayout();
+ ComputePTXValueVTs(*this, DL, retTy, VTs, &Offsets, 0);
assert(VTs.size() == Ins.size() && "Bad value decomposition");
- unsigned RetAlign = getArgumentAlignment(Callee, CS, retTy, 0);
+ unsigned RetAlign = getArgumentAlignment(Callee, CS, retTy, 0, DL);
for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
unsigned sz = VTs[i].getSizeInBits();
unsigned AlignI = GreatestCommonDivisor64(RetAlign, Offsets[i]);
@@ -1713,7 +1771,6 @@ SDValue NVPTXTargetLowering::LowerShiftRightParts(SDValue Op,
unsigned Opc = (Op.getOpcode() == ISD::SRA_PARTS) ? ISD::SRA : ISD::SRL;
if (VTBits == 32 && STI.getSmVersion() >= 35) {
-
// For 32bit and sm35, we can use the funnel shift 'shf' instruction.
// {dHi, dLo} = {aHi, aLo} >> Amt
// dHi = aHi >> Amt
@@ -1727,7 +1784,6 @@ SDValue NVPTXTargetLowering::LowerShiftRightParts(SDValue Op,
return DAG.getMergeValues(Ops, dl);
}
else {
-
// {dHi, dLo} = {aHi, aLo} >> Amt
// - if (Amt>=size) then
// dLo = aHi >> (Amt-size)
@@ -1775,7 +1831,6 @@ SDValue NVPTXTargetLowering::LowerShiftLeftParts(SDValue Op,
SDValue ShAmt = Op.getOperand(2);
if (VTBits == 32 && STI.getSmVersion() >= 35) {
-
// For 32bit and sm35, we can use the funnel shift 'shf' instruction.
// {dHi, dLo} = {aHi, aLo} << Amt
// dHi = shf.l.clamp aLo, aHi, Amt
@@ -1789,7 +1844,6 @@ SDValue NVPTXTargetLowering::LowerShiftLeftParts(SDValue Op,
return DAG.getMergeValues(Ops, dl);
}
else {
-
// {dHi, dLo} = {aHi, aLo} << Amt
// - if (Amt>=size) then
// dLo = aLo << Amt (all 0)
@@ -1968,11 +2022,10 @@ NVPTXTargetLowering::LowerSTOREVector(SDValue Op, SelectionDAG &DAG) const {
case 2:
Opcode = NVPTXISD::StoreV2;
break;
- case 4: {
+ case 4:
Opcode = NVPTXISD::StoreV4;
break;
}
- }
SmallVector<SDValue, 8> Ops;
@@ -2073,7 +2126,6 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
SDValue Root = DAG.getRoot();
std::vector<SDValue> OutChains;
- bool isKernel = llvm::isKernelFunction(*F);
bool isABI = (STI.getSmVersion() >= 20);
assert(isABI && "Non-ABI compilation is not supported");
if (!isABI)
@@ -2107,7 +2159,8 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
theArgs[i],
(theArgs[i]->getParent() ? theArgs[i]->getParent()->getParent()
: nullptr))) {
- assert(isKernel && "Only kernels can have image/sampler params");
+ assert(isKernelFunction(*F) &&
+ "Only kernels can have image/sampler params");
InVals.push_back(DAG.getConstant(i + 1, dl, MVT::i32));
continue;
}
@@ -2159,7 +2212,7 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
0);
assert(vtparts.size() > 0 && "empty aggregate type not expected");
bool aggregateIsPacked = false;
- if (StructType *STy = llvm::dyn_cast<StructType>(Ty))
+ if (StructType *STy = dyn_cast<StructType>(Ty))
aggregateIsPacked = STy->isPacked();
SDValue Arg = getParamSymbol(DAG, idx, PtrVT);
@@ -2168,7 +2221,7 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
EVT partVT = vtparts[parti];
Value *srcValue = Constant::getNullValue(
PointerType::get(partVT.getTypeForEVT(F->getContext()),
- llvm::ADDRESS_SPACE_PARAM));
+ ADDRESS_SPACE_PARAM));
SDValue srcAddr =
DAG.getNode(ISD::ADD, dl, PtrVT, Arg,
DAG.getConstant(offsets[parti], dl, PtrVT));
@@ -2208,11 +2261,12 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
if (NumElts == 1) {
// We only have one element, so just directly load it
Value *SrcValue = Constant::getNullValue(PointerType::get(
- EltVT.getTypeForEVT(F->getContext()), llvm::ADDRESS_SPACE_PARAM));
+ EltVT.getTypeForEVT(F->getContext()), ADDRESS_SPACE_PARAM));
SDValue P = DAG.getLoad(
EltVT, dl, Root, Arg, MachinePointerInfo(SrcValue),
DL.getABITypeAlignment(EltVT.getTypeForEVT(F->getContext())),
- MachineMemOperand::MOInvariant);
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
if (P.getNode())
P.getNode()->setIROrder(idx + 1);
@@ -2225,11 +2279,12 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
// f32,f32 = load ...
EVT VecVT = EVT::getVectorVT(F->getContext(), EltVT, 2);
Value *SrcValue = Constant::getNullValue(PointerType::get(
- VecVT.getTypeForEVT(F->getContext()), llvm::ADDRESS_SPACE_PARAM));
+ VecVT.getTypeForEVT(F->getContext()), ADDRESS_SPACE_PARAM));
SDValue P = DAG.getLoad(
VecVT, dl, Root, Arg, MachinePointerInfo(SrcValue),
DL.getABITypeAlignment(VecVT.getTypeForEVT(F->getContext())),
- MachineMemOperand::MOInvariant);
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
if (P.getNode())
P.getNode()->setIROrder(idx + 1);
@@ -2265,13 +2320,14 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
for (unsigned i = 0; i < NumElts; i += VecSize) {
Value *SrcValue = Constant::getNullValue(
PointerType::get(VecVT.getTypeForEVT(F->getContext()),
- llvm::ADDRESS_SPACE_PARAM));
+ ADDRESS_SPACE_PARAM));
SDValue SrcAddr = DAG.getNode(ISD::ADD, dl, PtrVT, Arg,
DAG.getConstant(Ofst, dl, PtrVT));
SDValue P = DAG.getLoad(
VecVT, dl, Root, SrcAddr, MachinePointerInfo(SrcValue),
DL.getABITypeAlignment(VecVT.getTypeForEVT(F->getContext())),
- MachineMemOperand::MOInvariant);
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant);
if (P.getNode())
P.getNode()->setIROrder(idx + 1);
@@ -2298,7 +2354,7 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
// If ABI, load from the param symbol
SDValue Arg = getParamSymbol(DAG, idx, PtrVT);
Value *srcValue = Constant::getNullValue(PointerType::get(
- ObjectVT.getTypeForEVT(F->getContext()), llvm::ADDRESS_SPACE_PARAM));
+ ObjectVT.getTypeForEVT(F->getContext()), ADDRESS_SPACE_PARAM));
SDValue p;
if (ObjectVT.getSizeInBits() < Ins[InsIdx].VT.getSizeInBits()) {
ISD::LoadExtType ExtOp = Ins[InsIdx].Flags.isSExt() ?
@@ -2332,14 +2388,7 @@ SDValue NVPTXTargetLowering::LowerFormalArguments(
SDValue p = DAG.getNode(NVPTXISD::MoveParam, dl, ObjectVT, Arg);
if (p.getNode())
p.getNode()->setIROrder(idx + 1);
- if (isKernel)
- InVals.push_back(p);
- else {
- SDValue p2 = DAG.getNode(
- ISD::INTRINSIC_WO_CHAIN, dl, ObjectVT,
- DAG.getConstant(Intrinsic::nvvm_ptr_local_to_gen, dl, MVT::i32), p);
- InVals.push_back(p2);
- }
+ InVals.push_back(p);
}
// Clang will check explicit VarArg and issue error if any. However, Clang
@@ -2394,7 +2443,6 @@ NVPTXTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
Chain = DAG.getMemIntrinsicNode(NVPTXISD::StoreRetval, dl,
DAG.getVTList(MVT::Other), Ops,
EltVT, MachinePointerInfo());
-
} else if (NumElts == 2) {
// V2 store
SDValue StoreVal0 = OutVals[0];
@@ -2422,7 +2470,7 @@ NVPTXTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
// 11 elem => 3 st.v4
unsigned VecSize = 4;
- if (OutVals[0].getValueType().getSizeInBits() == 64)
+ if (OutVals[0].getValueSizeInBits() == 64)
VecSize = 2;
unsigned Offset = 0;
@@ -2510,7 +2558,7 @@ NVPTXTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
TmpVal = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, TmpVal);
TheStoreType = MVT::i32;
}
- else if (TmpVal.getValueType().getSizeInBits() < 16)
+ else if (TmpVal.getValueSizeInBits() < 16)
TmpVal = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i16, TmpVal);
SDValue Ops[] = {
@@ -2528,7 +2576,6 @@ NVPTXTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
return DAG.getNode(NVPTXISD::RET_FLAG, dl, MVT::Other, Chain);
}
-
void NVPTXTargetLowering::LowerAsmOperandForConstraint(
SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
SelectionDAG &DAG) const {
@@ -3246,27 +3293,42 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
return false;
case Intrinsic::nvvm_atomic_load_add_f32:
- Info.opc = ISD::INTRINSIC_W_CHAIN;
- Info.memVT = MVT::f32;
- Info.ptrVal = I.getArgOperand(0);
- Info.offset = 0;
- Info.vol = 0;
- Info.readMem = true;
- Info.writeMem = true;
- Info.align = 0;
- return true;
-
case Intrinsic::nvvm_atomic_load_inc_32:
case Intrinsic::nvvm_atomic_load_dec_32:
+
+ case Intrinsic::nvvm_atomic_add_gen_f_cta:
+ case Intrinsic::nvvm_atomic_add_gen_f_sys:
+ case Intrinsic::nvvm_atomic_add_gen_i_cta:
+ case Intrinsic::nvvm_atomic_add_gen_i_sys:
+ case Intrinsic::nvvm_atomic_and_gen_i_cta:
+ case Intrinsic::nvvm_atomic_and_gen_i_sys:
+ case Intrinsic::nvvm_atomic_cas_gen_i_cta:
+ case Intrinsic::nvvm_atomic_cas_gen_i_sys:
+ case Intrinsic::nvvm_atomic_dec_gen_i_cta:
+ case Intrinsic::nvvm_atomic_dec_gen_i_sys:
+ case Intrinsic::nvvm_atomic_inc_gen_i_cta:
+ case Intrinsic::nvvm_atomic_inc_gen_i_sys:
+ case Intrinsic::nvvm_atomic_max_gen_i_cta:
+ case Intrinsic::nvvm_atomic_max_gen_i_sys:
+ case Intrinsic::nvvm_atomic_min_gen_i_cta:
+ case Intrinsic::nvvm_atomic_min_gen_i_sys:
+ case Intrinsic::nvvm_atomic_or_gen_i_cta:
+ case Intrinsic::nvvm_atomic_or_gen_i_sys:
+ case Intrinsic::nvvm_atomic_exch_gen_i_cta:
+ case Intrinsic::nvvm_atomic_exch_gen_i_sys:
+ case Intrinsic::nvvm_atomic_xor_gen_i_cta:
+ case Intrinsic::nvvm_atomic_xor_gen_i_sys: {
+ auto &DL = I.getModule()->getDataLayout();
Info.opc = ISD::INTRINSIC_W_CHAIN;
- Info.memVT = MVT::i32;
+ Info.memVT = getValueType(DL, I.getType());
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = true;
Info.align = 0;
return true;
+ }
case Intrinsic::nvvm_ldu_global_i:
case Intrinsic::nvvm_ldu_global_f:
@@ -3281,7 +3343,7 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
Info.memVT = getValueType(DL, I.getType());
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = cast<ConstantInt>(I.getArgOperand(1))->getZExtValue();
@@ -3302,7 +3364,7 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
Info.memVT = getValueType(DL, I.getType());
Info.ptrVal = I.getArgOperand(0);
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = cast<ConstantInt>(I.getArgOperand(1))->getZExtValue();
@@ -3365,17 +3427,17 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
case Intrinsic::nvvm_tld4_unified_r_2d_v4f32_f32:
case Intrinsic::nvvm_tld4_unified_g_2d_v4f32_f32:
case Intrinsic::nvvm_tld4_unified_b_2d_v4f32_f32:
- case Intrinsic::nvvm_tld4_unified_a_2d_v4f32_f32: {
+ case Intrinsic::nvvm_tld4_unified_a_2d_v4f32_f32:
Info.opc = getOpcForTextureInstr(Intrinsic);
Info.memVT = MVT::v4f32;
Info.ptrVal = nullptr;
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = 16;
return true;
- }
+
case Intrinsic::nvvm_tex_1d_v4s32_s32:
case Intrinsic::nvvm_tex_1d_v4s32_f32:
case Intrinsic::nvvm_tex_1d_level_v4s32_f32:
@@ -3487,17 +3549,17 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
case Intrinsic::nvvm_tld4_unified_r_2d_v4u32_f32:
case Intrinsic::nvvm_tld4_unified_g_2d_v4u32_f32:
case Intrinsic::nvvm_tld4_unified_b_2d_v4u32_f32:
- case Intrinsic::nvvm_tld4_unified_a_2d_v4u32_f32: {
+ case Intrinsic::nvvm_tld4_unified_a_2d_v4u32_f32:
Info.opc = getOpcForTextureInstr(Intrinsic);
Info.memVT = MVT::v4i32;
Info.ptrVal = nullptr;
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = 16;
return true;
- }
+
case Intrinsic::nvvm_suld_1d_i8_clamp:
case Intrinsic::nvvm_suld_1d_v2i8_clamp:
case Intrinsic::nvvm_suld_1d_v4i8_clamp:
@@ -3542,17 +3604,17 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
case Intrinsic::nvvm_suld_2d_array_v4i8_zero:
case Intrinsic::nvvm_suld_3d_i8_zero:
case Intrinsic::nvvm_suld_3d_v2i8_zero:
- case Intrinsic::nvvm_suld_3d_v4i8_zero: {
+ case Intrinsic::nvvm_suld_3d_v4i8_zero:
Info.opc = getOpcForSurfaceInstr(Intrinsic);
Info.memVT = MVT::i8;
Info.ptrVal = nullptr;
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = 16;
return true;
- }
+
case Intrinsic::nvvm_suld_1d_i16_clamp:
case Intrinsic::nvvm_suld_1d_v2i16_clamp:
case Intrinsic::nvvm_suld_1d_v4i16_clamp:
@@ -3597,17 +3659,17 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
case Intrinsic::nvvm_suld_2d_array_v4i16_zero:
case Intrinsic::nvvm_suld_3d_i16_zero:
case Intrinsic::nvvm_suld_3d_v2i16_zero:
- case Intrinsic::nvvm_suld_3d_v4i16_zero: {
+ case Intrinsic::nvvm_suld_3d_v4i16_zero:
Info.opc = getOpcForSurfaceInstr(Intrinsic);
Info.memVT = MVT::i16;
Info.ptrVal = nullptr;
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = 16;
return true;
- }
+
case Intrinsic::nvvm_suld_1d_i32_clamp:
case Intrinsic::nvvm_suld_1d_v2i32_clamp:
case Intrinsic::nvvm_suld_1d_v4i32_clamp:
@@ -3652,17 +3714,17 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
case Intrinsic::nvvm_suld_2d_array_v4i32_zero:
case Intrinsic::nvvm_suld_3d_i32_zero:
case Intrinsic::nvvm_suld_3d_v2i32_zero:
- case Intrinsic::nvvm_suld_3d_v4i32_zero: {
+ case Intrinsic::nvvm_suld_3d_v4i32_zero:
Info.opc = getOpcForSurfaceInstr(Intrinsic);
Info.memVT = MVT::i32;
Info.ptrVal = nullptr;
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = 16;
return true;
- }
+
case Intrinsic::nvvm_suld_1d_i64_clamp:
case Intrinsic::nvvm_suld_1d_v2i64_clamp:
case Intrinsic::nvvm_suld_1d_array_i64_clamp:
@@ -3692,18 +3754,17 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
case Intrinsic::nvvm_suld_2d_array_i64_zero:
case Intrinsic::nvvm_suld_2d_array_v2i64_zero:
case Intrinsic::nvvm_suld_3d_i64_zero:
- case Intrinsic::nvvm_suld_3d_v2i64_zero: {
+ case Intrinsic::nvvm_suld_3d_v2i64_zero:
Info.opc = getOpcForSurfaceInstr(Intrinsic);
Info.memVT = MVT::i64;
Info.ptrVal = nullptr;
Info.offset = 0;
- Info.vol = 0;
+ Info.vol = false;
Info.readMem = true;
Info.writeMem = false;
Info.align = 16;
return true;
}
- }
return false;
}
@@ -3715,7 +3776,6 @@ bool NVPTXTargetLowering::getTgtMemIntrinsic(
bool NVPTXTargetLowering::isLegalAddressingMode(const DataLayout &DL,
const AddrMode &AM, Type *Ty,
unsigned AS) const {
-
// AddrMode - This represents an addressing mode of:
// BaseGV + BaseOffs + BaseReg + Scale*ScaleReg
//
@@ -4014,7 +4074,7 @@ static SDValue PerformANDCombine(SDNode *N,
}
bool AddTo = false;
- if (AExt.getNode() != 0) {
+ if (AExt.getNode() != nullptr) {
// Re-insert the ext as a zext.
Val = DCI.DAG.getNode(ISD::ZERO_EXTEND, SDLoc(N),
AExt.getValueType(), Val);
@@ -4089,6 +4149,37 @@ static SDValue PerformSELECTCombine(SDNode *N,
DCI.DAG.getConstant(IntrinsicId, DL, VT), LHS, RHS);
}
+static SDValue PerformREMCombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
+ CodeGenOpt::Level OptLevel) {
+ assert(N->getOpcode() == ISD::SREM || N->getOpcode() == ISD::UREM);
+
+ // Don't do anything at less than -O2.
+ if (OptLevel < CodeGenOpt::Default)
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+ bool IsSigned = N->getOpcode() == ISD::SREM;
+ unsigned DivOpc = IsSigned ? ISD::SDIV : ISD::UDIV;
+
+ const SDValue &Num = N->getOperand(0);
+ const SDValue &Den = N->getOperand(1);
+
+ for (const SDNode *U : Num->uses()) {
+ if (U->getOpcode() == DivOpc && U->getOperand(0) == Num &&
+ U->getOperand(1) == Den) {
+ // Num % Den -> Num - (Num / Den) * Den
+ return DAG.getNode(ISD::SUB, DL, VT, Num,
+ DAG.getNode(ISD::MUL, DL, VT,
+ DAG.getNode(DivOpc, DL, VT, Num, Den),
+ Den));
+ }
+ }
+ return SDValue();
+}
+
enum OperandSignedness {
Signed = 0,
Unsigned,
@@ -4128,7 +4219,6 @@ static bool IsMulWideOperandDemotable(SDValue Op,
static bool AreMulWideOperandsDemotable(SDValue LHS, SDValue RHS,
unsigned OptSize,
bool &IsSigned) {
-
OperandSignedness LHSSign;
// The LHS operand must be a demotable op
@@ -4270,6 +4360,9 @@ SDValue NVPTXTargetLowering::PerformDAGCombine(SDNode *N,
return PerformANDCombine(N, DCI);
case ISD::SELECT:
return PerformSELECTCombine(N, DCI);
+ case ISD::UREM:
+ case ISD::SREM:
+ return PerformREMCombine(N, DCI, OptLevel);
}
return SDValue();
}
@@ -4554,9 +4647,7 @@ NVPTXTargetObjectFile::~NVPTXTargetObjectFile() {
delete static_cast<NVPTXSection *>(DwarfMacinfoSection);
}
-MCSection *
-NVPTXTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
+MCSection *NVPTXTargetObjectFile::SelectSectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
return getDataSection();
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.h b/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.h
index 1c32232..e433aed 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXISelLowering.h
@@ -539,7 +539,8 @@ private:
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
unsigned getArgumentAlignment(SDValue Callee, const ImmutableCallSite *CS,
- Type *Ty, unsigned Idx) const;
+ Type *Ty, unsigned Idx,
+ const DataLayout &DL) const;
};
} // namespace llvm
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp
index e451d27..f4940c9 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXInferAddressSpaces.cpp
@@ -87,9 +87,6 @@
// Finally, it fixes the undef in %y' so that
// %y' = phi float addrspace(3)* [ %input, %y2' ]
//
-// TODO: This pass is experimental and not enabled by default. Users can turn it
-// on by setting the -nvptx-use-infer-addrspace flag of llc. We plan to replace
-// NVPTXNonFavorGenericAddrSpaces with this pass shortly.
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "nvptx-infer-addrspace"
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.cpp
index 0c7c6cb..7f89742 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.cpp
@@ -110,19 +110,6 @@ bool NVPTXInstrInfo::isStoreInstr(const MachineInstr &MI,
return isStore;
}
-bool NVPTXInstrInfo::CanTailMerge(const MachineInstr *MI) const {
- unsigned addrspace = 0;
- if (MI->getOpcode() == NVPTX::INT_BARRIER0)
- return false;
- if (isLoadInstr(*MI, addrspace))
- if (addrspace == NVPTX::PTXLdStInstCode::SHARED)
- return false;
- if (isStoreInstr(*MI, addrspace))
- if (addrspace == NVPTX::PTXLdStInstCode::SHARED)
- return false;
- return true;
-}
-
/// AnalyzeBranch - Analyze the branching code at the end of MBB, returning
/// true if it cannot be understood (e.g. it's a switch dispatch or isn't
/// implemented for a target). Upon success, this returns false and returns
@@ -143,7 +130,7 @@ bool NVPTXInstrInfo::CanTailMerge(const MachineInstr *MI) const {
/// operands can be passed to other TargetInstrInfo methods to create new
/// branches.
///
-/// Note that RemoveBranch and InsertBranch must be implemented to support
+/// Note that removeBranch and insertBranch must be implemented to support
/// cases where this method returns success.
///
bool NVPTXInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
@@ -205,7 +192,9 @@ bool NVPTXInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}
-unsigned NVPTXInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned NVPTXInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
MachineBasicBlock::iterator I = MBB.end();
if (I == MBB.begin())
return 0;
@@ -229,13 +218,16 @@ unsigned NVPTXInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return 2;
}
-unsigned NVPTXInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned NVPTXInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(!BytesAdded && "code size not handled");
+
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"NVPTX branch conditions have two components!");
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.h b/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.h
index 050bf12..d284282 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.h
@@ -57,16 +57,17 @@ public:
bool isLoadInstr(const MachineInstr &MI, unsigned &AddrSpace) const;
bool isStoreInstr(const MachineInstr &MI, unsigned &AddrSpace) const;
- virtual bool CanTailMerge(const MachineInstr *MI) const;
// Branch analysis.
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
unsigned getLdStCodeAddrSpace(const MachineInstr &MI) const {
return MI.getOperand(2).getImm();
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
index c158cc6..0fbb044 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
@@ -71,10 +71,6 @@ def CmpLT : PatLeaf<(i32 2)>;
def CmpLE : PatLeaf<(i32 3)>;
def CmpGT : PatLeaf<(i32 4)>;
def CmpGE : PatLeaf<(i32 5)>;
-def CmpLO : PatLeaf<(i32 6)>;
-def CmpLS : PatLeaf<(i32 7)>;
-def CmpHI : PatLeaf<(i32 8)>;
-def CmpHS : PatLeaf<(i32 9)>;
def CmpEQU : PatLeaf<(i32 10)>;
def CmpNEU : PatLeaf<(i32 11)>;
def CmpLTU : PatLeaf<(i32 12)>;
@@ -90,10 +86,6 @@ def CmpLT_FTZ : PatLeaf<(i32 0x102)>;
def CmpLE_FTZ : PatLeaf<(i32 0x103)>;
def CmpGT_FTZ : PatLeaf<(i32 0x104)>;
def CmpGE_FTZ : PatLeaf<(i32 0x105)>;
-def CmpLO_FTZ : PatLeaf<(i32 0x106)>;
-def CmpLS_FTZ : PatLeaf<(i32 0x107)>;
-def CmpHI_FTZ : PatLeaf<(i32 0x108)>;
-def CmpHS_FTZ : PatLeaf<(i32 0x109)>;
def CmpEQU_FTZ : PatLeaf<(i32 0x10A)>;
def CmpNEU_FTZ : PatLeaf<(i32 0x10B)>;
def CmpLTU_FTZ : PatLeaf<(i32 0x10C)>;
@@ -107,13 +99,6 @@ def CmpMode : Operand<i32> {
let PrintMethod = "printCmpMode";
}
-def F32ConstZero : Operand<f32>, PatLeaf<(f32 fpimm)>, SDNodeXForm<fpimm, [{
- return CurDAG->getTargetConstantFP(0.0, MVT::f32);
- }]>;
-def F32ConstOne : Operand<f32>, PatLeaf<(f32 fpimm)>, SDNodeXForm<fpimm, [{
- return CurDAG->getTargetConstantFP(1.0, MVT::f32);
- }]>;
-
//===----------------------------------------------------------------------===//
// NVPTX Instruction Predicate Definitions
//===----------------------------------------------------------------------===//
@@ -131,6 +116,10 @@ def hasAtomRedGen64 : Predicate<"Subtarget->hasAtomRedGen64()">;
def useAtomRedG64forGen64 :
Predicate<"!Subtarget->hasAtomRedGen64() && Subtarget->hasAtomRedG64()">;
def hasAtomAddF32 : Predicate<"Subtarget->hasAtomAddF32()">;
+def hasAtomAddF64 : Predicate<"Subtarget->hasAtomAddF64()">;
+def hasAtomScope : Predicate<"Subtarget->hasAtomScope()">;
+def hasAtomBitwise64 : Predicate<"Subtarget->hasAtomBitwise64()">;
+def hasAtomMinMax64 : Predicate<"Subtarget->hasAtomMinMax64()">;
def hasVote : Predicate<"Subtarget->hasVote()">;
def hasDouble : Predicate<"Subtarget->hasDouble()">;
def reqPTX20 : Predicate<"Subtarget->reqPTX20()">;
@@ -155,7 +144,7 @@ def do_SQRTF32_RN : Predicate<"usePrecSqrtF32()">;
def hasHWROT32 : Predicate<"Subtarget->hasHWROT32()">;
def noHWROT32 : Predicate<"!Subtarget->hasHWROT32()">;
-def true : Predicate<"1">;
+def true : Predicate<"true">;
def hasPTX31 : Predicate<"Subtarget->getPTXVersion() >= 31">;
@@ -207,15 +196,63 @@ multiclass ADD_SUB_INT_32<string OpcStr, SDNode OpNode> {
}
// Template for instructions which take three fp64 or fp32 args. The
-// instructions are named "<OpcStr>.f<Width>" (e.g. "add.f64").
+// instructions are named "<OpcStr>.f<Width>" (e.g. "min.f64").
//
// Also defines ftz (flush subnormal inputs and results to sign-preserving
// zero) variants for fp32 functions.
+//
+// This multiclass should be used for nodes that cannot be folded into FMAs.
+// For nodes that can be folded into FMAs (i.e. adds and muls), use
+// F3_fma_component.
multiclass F3<string OpcStr, SDNode OpNode> {
def f64rr :
NVPTXInst<(outs Float64Regs:$dst),
(ins Float64Regs:$a, Float64Regs:$b),
!strconcat(OpcStr, ".f64 \t$dst, $a, $b;"),
+ [(set Float64Regs:$dst, (OpNode Float64Regs:$a, Float64Regs:$b))]>;
+ def f64ri :
+ NVPTXInst<(outs Float64Regs:$dst),
+ (ins Float64Regs:$a, f64imm:$b),
+ !strconcat(OpcStr, ".f64 \t$dst, $a, $b;"),
+ [(set Float64Regs:$dst, (OpNode Float64Regs:$a, fpimm:$b))]>;
+ def f32rr_ftz :
+ NVPTXInst<(outs Float32Regs:$dst),
+ (ins Float32Regs:$a, Float32Regs:$b),
+ !strconcat(OpcStr, ".ftz.f32 \t$dst, $a, $b;"),
+ [(set Float32Regs:$dst, (OpNode Float32Regs:$a, Float32Regs:$b))]>,
+ Requires<[doF32FTZ]>;
+ def f32ri_ftz :
+ NVPTXInst<(outs Float32Regs:$dst),
+ (ins Float32Regs:$a, f32imm:$b),
+ !strconcat(OpcStr, ".ftz.f32 \t$dst, $a, $b;"),
+ [(set Float32Regs:$dst, (OpNode Float32Regs:$a, fpimm:$b))]>,
+ Requires<[doF32FTZ]>;
+ def f32rr :
+ NVPTXInst<(outs Float32Regs:$dst),
+ (ins Float32Regs:$a, Float32Regs:$b),
+ !strconcat(OpcStr, ".f32 \t$dst, $a, $b;"),
+ [(set Float32Regs:$dst, (OpNode Float32Regs:$a, Float32Regs:$b))]>;
+ def f32ri :
+ NVPTXInst<(outs Float32Regs:$dst),
+ (ins Float32Regs:$a, f32imm:$b),
+ !strconcat(OpcStr, ".f32 \t$dst, $a, $b;"),
+ [(set Float32Regs:$dst, (OpNode Float32Regs:$a, fpimm:$b))]>;
+}
+
+// Template for instructions which take three fp64 or fp32 args. The
+// instructions are named "<OpcStr>.f<Width>" (e.g. "add.f64").
+//
+// Also defines ftz (flush subnormal inputs and results to sign-preserving
+// zero) variants for fp32 functions.
+//
+// This multiclass should be used for nodes that can be folded to make fma ops.
+// In this case, we use the ".rn" variant when FMA is disabled, as this behaves
+// just like the non ".rn" op, but prevents ptxas from creating FMAs.
+multiclass F3_fma_component<string OpcStr, SDNode OpNode> {
+ def f64rr :
+ NVPTXInst<(outs Float64Regs:$dst),
+ (ins Float64Regs:$a, Float64Regs:$b),
+ !strconcat(OpcStr, ".f64 \t$dst, $a, $b;"),
[(set Float64Regs:$dst, (OpNode Float64Regs:$a, Float64Regs:$b))]>,
Requires<[allowFMA]>;
def f64ri :
@@ -248,41 +285,39 @@ multiclass F3<string OpcStr, SDNode OpNode> {
!strconcat(OpcStr, ".f32 \t$dst, $a, $b;"),
[(set Float32Regs:$dst, (OpNode Float32Regs:$a, fpimm:$b))]>,
Requires<[allowFMA]>;
-}
-// Same as F3, but defines ".rn" variants (round to nearest even).
-multiclass F3_rn<string OpcStr, SDNode OpNode> {
- def f64rr :
+ // These have strange names so we don't perturb existing mir tests.
+ def _rnf64rr :
NVPTXInst<(outs Float64Regs:$dst),
(ins Float64Regs:$a, Float64Regs:$b),
!strconcat(OpcStr, ".rn.f64 \t$dst, $a, $b;"),
[(set Float64Regs:$dst, (OpNode Float64Regs:$a, Float64Regs:$b))]>,
Requires<[noFMA]>;
- def f64ri :
+ def _rnf64ri :
NVPTXInst<(outs Float64Regs:$dst),
(ins Float64Regs:$a, f64imm:$b),
!strconcat(OpcStr, ".rn.f64 \t$dst, $a, $b;"),
[(set Float64Regs:$dst, (OpNode Float64Regs:$a, fpimm:$b))]>,
Requires<[noFMA]>;
- def f32rr_ftz :
+ def _rnf32rr_ftz :
NVPTXInst<(outs Float32Regs:$dst),
(ins Float32Regs:$a, Float32Regs:$b),
!strconcat(OpcStr, ".rn.ftz.f32 \t$dst, $a, $b;"),
[(set Float32Regs:$dst, (OpNode Float32Regs:$a, Float32Regs:$b))]>,
Requires<[noFMA, doF32FTZ]>;
- def f32ri_ftz :
+ def _rnf32ri_ftz :
NVPTXInst<(outs Float32Regs:$dst),
(ins Float32Regs:$a, f32imm:$b),
!strconcat(OpcStr, ".rn.ftz.f32 \t$dst, $a, $b;"),
[(set Float32Regs:$dst, (OpNode Float32Regs:$a, fpimm:$b))]>,
Requires<[noFMA, doF32FTZ]>;
- def f32rr :
+ def _rnf32rr :
NVPTXInst<(outs Float32Regs:$dst),
(ins Float32Regs:$a, Float32Regs:$b),
!strconcat(OpcStr, ".rn.f32 \t$dst, $a, $b;"),
[(set Float32Regs:$dst, (OpNode Float32Regs:$a, Float32Regs:$b))]>,
Requires<[noFMA]>;
- def f32ri :
+ def _rnf32ri :
NVPTXInst<(outs Float32Regs:$dst),
(ins Float32Regs:$a, f32imm:$b),
!strconcat(OpcStr, ".rn.f32 \t$dst, $a, $b;"),
@@ -704,22 +739,21 @@ def INEG64 :
// Constant 1.0f
def FloatConst1 : PatLeaf<(fpimm), [{
- return &N->getValueAPF().getSemantics() == &llvm::APFloat::IEEEsingle &&
+ return &N->getValueAPF().getSemantics() == &llvm::APFloat::IEEEsingle() &&
N->getValueAPF().convertToFloat() == 1.0f;
}]>;
// Constant 1.0 (double)
def DoubleConst1 : PatLeaf<(fpimm), [{
- return &N->getValueAPF().getSemantics() == &llvm::APFloat::IEEEdouble &&
+ return &N->getValueAPF().getSemantics() == &llvm::APFloat::IEEEdouble() &&
N->getValueAPF().convertToDouble() == 1.0;
}]>;
-defm FADD : F3<"add", fadd>;
-defm FSUB : F3<"sub", fsub>;
-defm FMUL : F3<"mul", fmul>;
+defm FADD : F3_fma_component<"add", fadd>;
+defm FSUB : F3_fma_component<"sub", fsub>;
+defm FMUL : F3_fma_component<"mul", fmul>;
-defm FADD_rn : F3_rn<"add", fadd>;
-defm FSUB_rn : F3_rn<"sub", fsub>;
-defm FMUL_rn : F3_rn<"mul", fmul>;
+defm FMIN : F3<"min", fminnum>;
+defm FMAX : F3<"max", fmaxnum>;
defm FABS : F2<"abs", fabs>;
defm FNEG : F2<"neg", fneg>;
@@ -2613,21 +2647,70 @@ def : Pat<(ctpop Int64Regs:$a), (CVT_u64_u32 (POPCr64 Int64Regs:$a), CvtNONE)>;
def : Pat<(ctpop Int16Regs:$a),
(CVT_u16_u32 (POPCr32 (CVT_u32_u16 Int16Regs:$a, CvtNONE)), CvtNONE)>;
-// fround f64 -> f32
-def : Pat<(f32 (fround Float64Regs:$a)),
+// fpround f64 -> f32
+def : Pat<(f32 (fpround Float64Regs:$a)),
(CVT_f32_f64 Float64Regs:$a, CvtRN_FTZ)>, Requires<[doF32FTZ]>;
-def : Pat<(f32 (fround Float64Regs:$a)),
+def : Pat<(f32 (fpround Float64Regs:$a)),
(CVT_f32_f64 Float64Regs:$a, CvtRN)>;
-// fextend f32 -> f64
-def : Pat<(f64 (fextend Float32Regs:$a)),
+// fpextend f32 -> f64
+def : Pat<(f64 (fpextend Float32Regs:$a)),
(CVT_f64_f32 Float32Regs:$a, CvtNONE_FTZ)>, Requires<[doF32FTZ]>;
-def : Pat<(f64 (fextend Float32Regs:$a)),
+def : Pat<(f64 (fpextend Float32Regs:$a)),
(CVT_f64_f32 Float32Regs:$a, CvtNONE)>;
def retflag : SDNode<"NVPTXISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInGlue]>;
+// fceil, ffloor, fround, ftrunc.
+
+def : Pat<(fceil Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRPI_FTZ)>, Requires<[doF32FTZ]>;
+def : Pat<(fceil Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRPI)>, Requires<[doNoF32FTZ]>;
+def : Pat<(fceil Float64Regs:$a),
+ (CVT_f64_f64 Float64Regs:$a, CvtRPI)>;
+
+def : Pat<(ffloor Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRMI_FTZ)>, Requires<[doF32FTZ]>;
+def : Pat<(ffloor Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRMI)>, Requires<[doNoF32FTZ]>;
+def : Pat<(ffloor Float64Regs:$a),
+ (CVT_f64_f64 Float64Regs:$a, CvtRMI)>;
+
+def : Pat<(fround Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRNI_FTZ)>, Requires<[doF32FTZ]>;
+def : Pat<(f32 (fround Float32Regs:$a)),
+ (CVT_f32_f32 Float32Regs:$a, CvtRNI)>, Requires<[doNoF32FTZ]>;
+def : Pat<(f64 (fround Float64Regs:$a)),
+ (CVT_f64_f64 Float64Regs:$a, CvtRNI)>;
+
+def : Pat<(ftrunc Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRZI_FTZ)>, Requires<[doF32FTZ]>;
+def : Pat<(ftrunc Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRZI)>, Requires<[doNoF32FTZ]>;
+def : Pat<(ftrunc Float64Regs:$a),
+ (CVT_f64_f64 Float64Regs:$a, CvtRZI)>;
+
+// nearbyint and rint are implemented as rounding to nearest even. This isn't
+// strictly correct, because it causes us to ignore the rounding mode. But it
+// matches what CUDA's "libm" does.
+
+def : Pat<(fnearbyint Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRNI_FTZ)>, Requires<[doF32FTZ]>;
+def : Pat<(fnearbyint Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRNI)>, Requires<[doNoF32FTZ]>;
+def : Pat<(fnearbyint Float64Regs:$a),
+ (CVT_f64_f64 Float64Regs:$a, CvtRNI)>;
+
+def : Pat<(frint Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRNI_FTZ)>, Requires<[doF32FTZ]>;
+def : Pat<(frint Float32Regs:$a),
+ (CVT_f32_f32 Float32Regs:$a, CvtRNI)>, Requires<[doNoF32FTZ]>;
+def : Pat<(frint Float64Regs:$a),
+ (CVT_f64_f64 Float64Regs:$a, CvtRNI)>;
+
+
//-----------------------------------
// Control-flow
//-----------------------------------
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/contrib/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
index ed16afa..b0408f1 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
@@ -1377,8 +1377,204 @@ defm INT_PTX_ATOM_CAS_GEN_64 : F_ATOMIC_3<Int64Regs, "", ".b64", ".cas",
defm INT_PTX_ATOM_CAS_GEN_64_USE_G : F_ATOMIC_3<Int64Regs, ".global", ".b64",
".cas", atomic_cmp_swap_64_gen, i64imm, useAtomRedG64forGen64>;
+// Support for scoped atomic operations. Matches
+// int_nvvm_atomic_{op}_{space}_{type}_{scope}
+// and converts it into the appropriate instruction.
+// NOTE: not all possible combinations are implemented
+// 'space' is limited to generic as it's the only one needed to support CUDA.
+// 'scope' = 'gpu' is default and is handled by regular atomic instructions.
+class ATOM23_impl<string AsmStr, NVPTXRegClass regclass, list<Predicate> Preds,
+ dag ins, dag Operands>
+ : NVPTXInst<(outs regclass:$result), ins,
+ AsmStr,
+ [(set regclass:$result, Operands)]>,
+ Requires<Preds>;
+
+// Define instruction variants for all addressing modes.
+multiclass ATOM2P_impl<string AsmStr, Intrinsic Intr,
+ NVPTXRegClass regclass, Operand ImmType,
+ SDNode Imm, ValueType ImmTy,
+ list<Predicate> Preds> {
+ let AddedComplexity = 1 in {
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int32Regs:$src, regclass:$b),
+ (Intr Int32Regs:$src, regclass:$b)>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int64Regs:$src, regclass:$b),
+ (Intr Int64Regs:$src, regclass:$b)>;
+ }
+ // tablegen can't infer argument types from Intrinsic (though it can
+ // from Instruction) so we have to enforce specific type on
+ // immediates via explicit cast to ImmTy.
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int32Regs:$src, ImmType:$b),
+ (Intr Int32Regs:$src, (ImmTy Imm:$b))>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int64Regs:$src, ImmType:$b),
+ (Intr Int64Regs:$src, (ImmTy Imm:$b))>;
+}
+
+multiclass ATOM3P_impl<string AsmStr, Intrinsic Intr,
+ NVPTXRegClass regclass, Operand ImmType,
+ SDNode Imm, ValueType ImmTy,
+ list<Predicate> Preds> {
+ // Variants for register/immediate permutations of $b and $c
+ let AddedComplexity = 2 in {
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int32Regs:$src, regclass:$b, regclass:$c),
+ (Intr Int32Regs:$src, regclass:$b, regclass:$c)>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int64Regs:$src, regclass:$b, regclass:$c),
+ (Intr Int64Regs:$src, regclass:$b, regclass:$c)>;
+ }
+ let AddedComplexity = 1 in {
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int32Regs:$src, ImmType:$b, regclass:$c),
+ (Intr Int32Regs:$src, (ImmTy Imm:$b), regclass:$c)>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int64Regs:$src, ImmType:$b, regclass:$c),
+ (Intr Int64Regs:$src, (ImmTy Imm:$b), regclass:$c)>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int32Regs:$src, regclass:$b, ImmType:$c),
+ (Intr Int32Regs:$src, regclass:$b, (ImmTy Imm:$c))>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int64Regs:$src, regclass:$b, ImmType:$c),
+ (Intr Int64Regs:$src, regclass:$b, (ImmTy Imm:$c))>;
+ }
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int32Regs:$src, ImmType:$b, ImmType:$c),
+ (Intr Int32Regs:$src, (ImmTy Imm:$b), (ImmTy Imm:$c))>;
+ def : ATOM23_impl<AsmStr, regclass, Preds,
+ (ins Int64Regs:$src, ImmType:$b, ImmType:$c),
+ (Intr Int64Regs:$src, (ImmTy Imm:$b), (ImmTy Imm:$c))>;
+}
+
+// Constructs instrinsic name and instruction asm strings.
+multiclass ATOM2N_impl<string OpStr, string IntTypeStr, string TypeStr,
+ string ScopeStr, string SpaceStr,
+ NVPTXRegClass regclass, Operand ImmType, SDNode Imm,
+ ValueType ImmTy, list<Predicate> Preds> {
+ defm : ATOM2P_impl<"atom" # !if(!eq(SpaceStr, "gen"), "", "." # SpaceStr)
+ # !if(!eq(ScopeStr, "gpu"), "", "." # ScopeStr)
+ # "." # OpStr # "." # TypeStr
+ # " \t$result, [$src], $b;",
+ !cast<Intrinsic>(
+ "int_nvvm_atomic_" # OpStr
+ # "_" # SpaceStr # "_" # IntTypeStr
+ # !if(!eq(ScopeStr,""), "", "_" # ScopeStr)),
+ regclass, ImmType, Imm, ImmTy, Preds>;
+}
+multiclass ATOM3N_impl<string OpStr, string IntTypeStr, string TypeStr,
+ string ScopeStr, string SpaceStr,
+ NVPTXRegClass regclass, Operand ImmType, SDNode Imm,
+ ValueType ImmTy, list<Predicate> Preds> {
+ defm : ATOM3P_impl<"atom" # !if(!eq(SpaceStr, "gen"), "", "." # SpaceStr)
+ # !if(!eq(ScopeStr, "gpu"), "", "." # ScopeStr)
+ # "." # OpStr # "." # TypeStr
+ # " \t$result, [$src], $b, $c;",
+ !cast<Intrinsic>(
+ "int_nvvm_atomic_" # OpStr
+ # "_" # SpaceStr # "_" # IntTypeStr
+ # !if(!eq(ScopeStr,""), "", "_" # ScopeStr)),
+ regclass, ImmType, Imm, ImmTy, Preds>;
+}
+
+// Constructs variants for different address spaces.
+// For now we only need variants for generic space pointers.
+multiclass ATOM2A_impl<string OpStr, string IntTypeStr, string TypeStr,
+ string ScopeStr, NVPTXRegClass regclass, Operand ImmType,
+ SDNode Imm, ValueType ImmTy, list<Predicate> Preds> {
+ defm _gen_ : ATOM2N_impl<OpStr, IntTypeStr, TypeStr, ScopeStr, "gen",
+ regclass, ImmType, Imm, ImmTy, Preds>;
+}
+multiclass ATOM3A_impl<string OpStr, string IntTypeStr, string TypeStr,
+ string ScopeStr, NVPTXRegClass regclass, Operand ImmType,
+ SDNode Imm, ValueType ImmTy, list<Predicate> Preds> {
+ defm _gen_ : ATOM3N_impl<OpStr, IntTypeStr, TypeStr, ScopeStr, "gen",
+ regclass, ImmType, Imm, ImmTy, Preds>;
+}
+
+// Constructs variants for different scopes of atomic op.
+multiclass ATOM2S_impl<string OpStr, string IntTypeStr, string TypeStr,
+ NVPTXRegClass regclass, Operand ImmType, SDNode Imm,
+ ValueType ImmTy, list<Predicate> Preds> {
+ // .gpu scope is default and is currently covered by existing
+ // atomics w/o explicitly specified scope.
+ defm _cta : ATOM2A_impl<OpStr, IntTypeStr, TypeStr, "cta",
+ regclass, ImmType, Imm, ImmTy,
+ !listconcat(Preds,[hasAtomScope])>;
+ defm _sys : ATOM2A_impl<OpStr, IntTypeStr, TypeStr, "sys",
+ regclass, ImmType, Imm, ImmTy,
+ !listconcat(Preds,[hasAtomScope])>;
+}
+multiclass ATOM3S_impl<string OpStr, string IntTypeStr, string TypeStr,
+ NVPTXRegClass regclass, Operand ImmType, SDNode Imm, ValueType ImmTy,
+ list<Predicate> Preds> {
+ // No need to define ".gpu"-scoped atomics. They do the same thing
+ // as the regular, non-scoped atomics defined elsewhere.
+ defm _cta : ATOM3A_impl<OpStr, IntTypeStr, TypeStr, "cta",
+ regclass, ImmType, Imm, ImmTy,
+ !listconcat(Preds,[hasAtomScope])>;
+ defm _sys : ATOM3A_impl<OpStr, IntTypeStr, TypeStr, "sys",
+ regclass, ImmType, Imm, ImmTy,
+ !listconcat(Preds,[hasAtomScope])>;
+}
+// atom.add
+multiclass ATOM2_add_impl<string OpStr> {
+ defm _s32 : ATOM2S_impl<OpStr, "i", "s32", Int32Regs, i32imm, imm, i32, []>;
+ defm _u32 : ATOM2S_impl<OpStr, "i", "u32", Int32Regs, i32imm, imm, i32, []>;
+ defm _u64 : ATOM2S_impl<OpStr, "i", "u64", Int64Regs, i64imm, imm, i64, []>;
+ defm _f32 : ATOM2S_impl<OpStr, "f", "f32", Float32Regs, f32imm, fpimm, f32,
+ [hasAtomAddF32]>;
+ defm _f64 : ATOM2S_impl<OpStr, "f", "f64", Float64Regs, f64imm, fpimm, f64,
+ [hasAtomAddF64]>;
+}
+
+// atom.{and,or,xor}
+multiclass ATOM2_bitwise_impl<string OpStr> {
+ defm _b32 : ATOM2S_impl<OpStr, "i", "b32", Int32Regs, i32imm, imm, i32, []>;
+ defm _b64 : ATOM2S_impl<OpStr, "i", "b64", Int64Regs, i64imm, imm, i64,
+ [hasAtomBitwise64]>;
+}
+
+// atom.exch
+multiclass ATOM2_exch_impl<string OpStr> {
+ defm _b32 : ATOM2S_impl<OpStr, "i", "b32", Int32Regs, i32imm, imm, i32, []>;
+ defm _b64 : ATOM2S_impl<OpStr, "i", "b64", Int64Regs, i64imm, imm, i64, []>;
+}
+
+// atom.{min,max}
+multiclass ATOM2_minmax_impl<string OpStr> {
+ defm _s32 : ATOM2S_impl<OpStr, "i", "s32", Int32Regs, i32imm, imm, i32, []>;
+ defm _u32 : ATOM2S_impl<OpStr, "i", "u32", Int32Regs, i32imm, imm, i32, []>;
+ defm _s64 : ATOM2S_impl<OpStr, "i", "s64", Int64Regs, i64imm, imm, i64,
+ [hasAtomMinMax64]>;
+ defm _u64 : ATOM2S_impl<OpStr, "i", "u64", Int64Regs, i64imm, imm, i64,
+ [hasAtomMinMax64]>;
+}
+
+// atom.{inc,dec}
+multiclass ATOM2_incdec_impl<string OpStr> {
+ defm _u32 : ATOM2S_impl<OpStr, "i", "u32", Int32Regs, i32imm, imm, i32, []>;
+}
+
+// atom.cas
+multiclass ATOM3_cas_impl<string OpStr> {
+ defm _b32 : ATOM3S_impl<OpStr, "i", "b32", Int32Regs, i32imm, imm, i32, []>;
+ defm _b64 : ATOM3S_impl<OpStr, "i", "b64", Int64Regs, i64imm, imm, i64, []>;
+}
+defm INT_PTX_SATOM_ADD : ATOM2_add_impl<"add">;
+defm INT_PTX_SATOM_AND : ATOM2_bitwise_impl<"and">;
+defm INT_PTX_SATOM_CAS : ATOM3_cas_impl<"cas">;
+defm INT_PTX_SATOM_DEC : ATOM2_incdec_impl<"dec">;
+defm INT_PTX_SATOM_EXCH: ATOM2_exch_impl<"exch">;
+defm INT_PTX_SATOM_INC : ATOM2_incdec_impl<"inc">;
+defm INT_PTX_SATOM_MAX : ATOM2_minmax_impl<"max">;
+defm INT_PTX_SATOM_MIN : ATOM2_minmax_impl<"min">;
+defm INT_PTX_SATOM_OR : ATOM2_bitwise_impl<"or">;
+defm INT_PTX_SATOM_XOR : ATOM2_bitwise_impl<"xor">;
//-----------------------------------
// Support for ldu on sm_20 or later
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAggrCopies.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAggrCopies.cpp
index f770c2a..b925b63 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAggrCopies.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAggrCopies.cpp
@@ -14,7 +14,6 @@
//===----------------------------------------------------------------------===//
#include "NVPTXLowerAggrCopies.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -41,7 +40,6 @@ struct NVPTXLowerAggrCopies : public FunctionPass {
NVPTXLowerAggrCopies() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addPreserved<MachineFunctionAnalysis>();
AU.addPreserved<StackProtector>();
}
@@ -49,7 +47,7 @@ struct NVPTXLowerAggrCopies : public FunctionPass {
static const unsigned MaxAggrCopySize = 128;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Lower aggregate copies/intrinsics into loops";
}
};
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAlloca.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAlloca.cpp
index fa1a3ef..e94c191 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAlloca.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXLowerAlloca.cpp
@@ -20,8 +20,8 @@
// %Generic = addrspacecast i32 addrspace(5)* %A to i32*
// store i32 0, i32 addrspace(5)* %Generic ; emits st.local.u32
//
-// And we will rely on NVPTXFavorNonGenericAddrSpace to combine the last
-// two instructions.
+// And we will rely on NVPTXInferAddressSpaces to combine the last two
+// instructions.
//
//===----------------------------------------------------------------------===//
@@ -47,7 +47,7 @@ class NVPTXLowerAlloca : public BasicBlockPass {
public:
static char ID; // Pass identification, replacement for typeid
NVPTXLowerAlloca() : BasicBlockPass(ID) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "convert address space of alloca'ed memory to local";
}
};
@@ -83,7 +83,7 @@ bool NVPTXLowerAlloca::runOnBasicBlock(BasicBlock &BB) {
UI != UE; ) {
// Check Load, Store, GEP, and BitCast Uses on alloca and make them
// use the converted generic address, in order to expose non-generic
- // addrspacecast to NVPTXFavorNonGenericAddrSpace. For other types
+ // addrspacecast to NVPTXInferAddressSpaces. For other types
// of instructions this is unnecessary and may introduce redundant
// address cast.
const auto &AllocaUse = *UI++;
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXLowerKernelArgs.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXLowerArgs.cpp
index d162a28..3f0c7be 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXLowerKernelArgs.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXLowerArgs.cpp
@@ -1,4 +1,4 @@
-//===-- NVPTXLowerKernelArgs.cpp - Lower kernel arguments -----------------===//
+//===-- NVPTXLowerArgs.cpp - Lower arguments ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,20 +7,28 @@
//
//===----------------------------------------------------------------------===//
//
-// Pointer arguments to kernel functions need to be lowered specially.
//
-// 1. Copy byval struct args to local memory. This is a preparation for handling
-// cases like
+// Arguments to kernel and device functions are passed via param space,
+// which imposes certain restrictions:
+// http://docs.nvidia.com/cuda/parallel-thread-execution/#state-spaces
//
-// kernel void foo(struct A arg, ...)
-// {
-// struct A *p = &arg;
-// ...
-// ... = p->filed1 ... (this is no generic address for .param)
-// p->filed2 = ... (this is no write access to .param)
-// }
+// Kernel parameters are read-only and accessible only via ld.param
+// instruction, directly or via a pointer. Pointers to kernel
+// arguments can't be converted to generic address space.
+//
+// Device function parameters are directly accessible via
+// ld.param/st.param, but taking the address of one returns a pointer
+// to a copy created in local space which *can't* be used with
+// ld.param/st.param.
//
-// 2. Convert non-byval pointer arguments of CUDA kernels to pointers in the
+// Copying a byval struct into local memory in IR allows us to enforce
+// the param space restrictions, gives the rest of IR a pointer w/o
+// param space restrictions, and gives us an opportunity to eliminate
+// the copy.
+//
+// Pointer arguments to kernel functions need more work to be lowered:
+//
+// 1. Convert non-byval pointer arguments of CUDA kernels to pointers in the
// global address space. This allows later optimizations to emit
// ld.global.*/st.global.* for accessing these pointer arguments. For
// example,
@@ -39,7 +47,7 @@
// ...
// }
//
-// Later, NVPTXFavorNonGenericAddrSpaces will optimize it to
+// Later, NVPTXInferAddressSpaces will optimize it to
//
// define void @foo(float* %input) {
// %input2 = addrspacecast float* %input to float addrspace(1)*
@@ -47,7 +55,7 @@
// ...
// }
//
-// 3. Convert pointers in a byval kernel parameter to pointers in the global
+// 2. Convert pointers in a byval kernel parameter to pointers in the global
// address space. As #2, it allows NVPTX to emit more ld/st.global. E.g.,
//
// struct S {
@@ -77,8 +85,8 @@
// ; use %b_generic
// }
//
-// TODO: merge this pass with NVPTXFavorNonGenericAddrSpace so that other passes
-// don't cancel the addrspacecast pair this pass emits.
+// TODO: merge this pass with NVPTXInferAddressSpaces so that other passes don't
+// cancel the addrspacecast pair this pass emits.
//===----------------------------------------------------------------------===//
#include "NVPTX.h"
@@ -94,26 +102,29 @@
using namespace llvm;
namespace llvm {
-void initializeNVPTXLowerKernelArgsPass(PassRegistry &);
+void initializeNVPTXLowerArgsPass(PassRegistry &);
}
namespace {
-class NVPTXLowerKernelArgs : public FunctionPass {
+class NVPTXLowerArgs : public FunctionPass {
bool runOnFunction(Function &F) override;
+ bool runOnKernelFunction(Function &F);
+ bool runOnDeviceFunction(Function &F);
+
// handle byval parameters
void handleByValParam(Argument *Arg);
// Knowing Ptr must point to the global address space, this function
// addrspacecasts Ptr to global and then back to generic. This allows
- // NVPTXFavorNonGenericAddrSpace to fold the global-to-generic cast into
+ // NVPTXInferAddressSpaces to fold the global-to-generic cast into
// loads/stores that appear later.
void markPointerAsGlobal(Value *Ptr);
public:
static char ID; // Pass identification, replacement for typeid
- NVPTXLowerKernelArgs(const NVPTXTargetMachine *TM = nullptr)
+ NVPTXLowerArgs(const NVPTXTargetMachine *TM = nullptr)
: FunctionPass(ID), TM(TM) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Lower pointer arguments of CUDA kernels";
}
@@ -122,10 +133,10 @@ private:
};
} // namespace
-char NVPTXLowerKernelArgs::ID = 1;
+char NVPTXLowerArgs::ID = 1;
-INITIALIZE_PASS(NVPTXLowerKernelArgs, "nvptx-lower-kernel-args",
- "Lower kernel arguments (NVPTX)", false, false)
+INITIALIZE_PASS(NVPTXLowerArgs, "nvptx-lower-args",
+ "Lower arguments (NVPTX)", false, false)
// =============================================================================
// If the function had a byval struct ptr arg, say foo(%struct.x* byval %d),
@@ -140,7 +151,7 @@ INITIALIZE_PASS(NVPTXLowerKernelArgs, "nvptx-lower-kernel-args",
// struct from param space to local space.
// Then replace all occurrences of %d by %temp.
// =============================================================================
-void NVPTXLowerKernelArgs::handleByValParam(Argument *Arg) {
+void NVPTXLowerArgs::handleByValParam(Argument *Arg) {
Function *Func = Arg->getParent();
Instruction *FirstInst = &(Func->getEntryBlock().front());
PointerType *PType = dyn_cast<PointerType>(Arg->getType());
@@ -162,7 +173,7 @@ void NVPTXLowerKernelArgs::handleByValParam(Argument *Arg) {
new StoreInst(LI, AllocA, FirstInst);
}
-void NVPTXLowerKernelArgs::markPointerAsGlobal(Value *Ptr) {
+void NVPTXLowerArgs::markPointerAsGlobal(Value *Ptr) {
if (Ptr->getType()->getPointerAddressSpace() == ADDRESS_SPACE_GLOBAL)
return;
@@ -192,11 +203,7 @@ void NVPTXLowerKernelArgs::markPointerAsGlobal(Value *Ptr) {
// =============================================================================
// Main function for this pass.
// =============================================================================
-bool NVPTXLowerKernelArgs::runOnFunction(Function &F) {
- // Skip non-kernels. See the comments at the top of this file.
- if (!isKernelFunction(F))
- return false;
-
+bool NVPTXLowerArgs::runOnKernelFunction(Function &F) {
if (TM && TM->getDrvInterface() == NVPTX::CUDA) {
// Mark pointers in byval structs as global.
for (auto &B : F) {
@@ -228,7 +235,19 @@ bool NVPTXLowerKernelArgs::runOnFunction(Function &F) {
return true;
}
+// Device functions only need to copy byval args into local memory.
+bool NVPTXLowerArgs::runOnDeviceFunction(Function &F) {
+ for (Argument &Arg : F.args())
+ if (Arg.getType()->isPointerTy() && Arg.hasByValAttr())
+ handleByValParam(&Arg);
+ return true;
+}
+
+bool NVPTXLowerArgs::runOnFunction(Function &F) {
+ return isKernelFunction(F) ? runOnKernelFunction(F) : runOnDeviceFunction(F);
+}
+
FunctionPass *
-llvm::createNVPTXLowerKernelArgsPass(const NVPTXTargetMachine *TM) {
- return new NVPTXLowerKernelArgs(TM);
+llvm::createNVPTXLowerArgsPass(const NVPTXTargetMachine *TM) {
+ return new NVPTXLowerArgs(TM);
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXMCExpr.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXMCExpr.cpp
index 84d5239..eab5ee8 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXMCExpr.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXMCExpr.cpp
@@ -30,12 +30,12 @@ void NVPTXFloatMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
case VK_NVPTX_SINGLE_PREC_FLOAT:
OS << "0f";
NumHex = 8;
- APF.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &Ignored);
+ APF.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &Ignored);
break;
case VK_NVPTX_DOUBLE_PREC_FLOAT:
OS << "0d";
NumHex = 16;
- APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &Ignored);
+ APF.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &Ignored);
break;
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXPeephole.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXPeephole.cpp
index 7d0cd55..49e6397 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXPeephole.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXPeephole.cpp
@@ -57,7 +57,7 @@ struct NVPTXPeephole : public MachineFunctionPass {
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "NVPTX optimize redundant cvta.to.local instruction";
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp
index 029e009..88288ab 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp
@@ -80,14 +80,14 @@ bool NVPTXPrologEpilogPass::runOnMachineFunction(MachineFunction &MF) {
/// AdjustStackOffset - Helper function used to adjust the stack frame offset.
static inline void
-AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx,
+AdjustStackOffset(MachineFrameInfo &MFI, int FrameIdx,
bool StackGrowsDown, int64_t &Offset,
unsigned &MaxAlign) {
// If the stack grows down, add the object size to find the lowest address.
if (StackGrowsDown)
- Offset += MFI->getObjectSize(FrameIdx);
+ Offset += MFI.getObjectSize(FrameIdx);
- unsigned Align = MFI->getObjectAlignment(FrameIdx);
+ unsigned Align = MFI.getObjectAlignment(FrameIdx);
// If the alignment of this object is greater than that of the stack, then
// increase the stack alignment to match.
@@ -98,11 +98,11 @@ AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx,
if (StackGrowsDown) {
DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << -Offset << "]\n");
- MFI->setObjectOffset(FrameIdx, -Offset); // Set the computed offset
+ MFI.setObjectOffset(FrameIdx, -Offset); // Set the computed offset
} else {
DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << Offset << "]\n");
- MFI->setObjectOffset(FrameIdx, Offset);
- Offset += MFI->getObjectSize(FrameIdx);
+ MFI.setObjectOffset(FrameIdx, Offset);
+ Offset += MFI.getObjectSize(FrameIdx);
}
}
@@ -115,7 +115,7 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
// Loop over all of the stack objects, assigning sequential addresses...
- MachineFrameInfo *MFI = Fn.getFrameInfo();
+ MachineFrameInfo &MFI = Fn.getFrameInfo();
// Start at the beginning of the local area.
// The Offset is the distance from the stack top in the direction
@@ -132,24 +132,24 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
// We currently don't support filling in holes in between fixed sized
// objects, so we adjust 'Offset' to point to the end of last fixed sized
// preallocated object.
- for (int i = MFI->getObjectIndexBegin(); i != 0; ++i) {
+ for (int i = MFI.getObjectIndexBegin(); i != 0; ++i) {
int64_t FixedOff;
if (StackGrowsDown) {
// The maximum distance from the stack pointer is at lower address of
// the object -- which is given by offset. For down growing stack
// the offset is negative, so we negate the offset to get the distance.
- FixedOff = -MFI->getObjectOffset(i);
+ FixedOff = -MFI.getObjectOffset(i);
} else {
// The maximum distance from the start pointer is at the upper
// address of the object.
- FixedOff = MFI->getObjectOffset(i) + MFI->getObjectSize(i);
+ FixedOff = MFI.getObjectOffset(i) + MFI.getObjectSize(i);
}
if (FixedOff > Offset) Offset = FixedOff;
}
// NOTE: We do not have a call stack
- unsigned MaxAlign = MFI->getMaxAlignment();
+ unsigned MaxAlign = MFI.getMaxAlignment();
// No scavenger
@@ -157,8 +157,8 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
// check for whether the frame is large enough to want to use virtual
// frame index registers. Functions which don't want/need this optimization
// will continue to use the existing code path.
- if (MFI->getUseLocalStackAllocationBlock()) {
- unsigned Align = MFI->getLocalFrameMaxAlign();
+ if (MFI.getUseLocalStackAllocationBlock()) {
+ unsigned Align = MFI.getLocalFrameMaxAlign();
// Adjust to alignment boundary.
Offset = (Offset + Align - 1) / Align * Align;
@@ -166,15 +166,15 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
DEBUG(dbgs() << "Local frame base offset: " << Offset << "\n");
// Resolve offsets for objects in the local block.
- for (unsigned i = 0, e = MFI->getLocalFrameObjectCount(); i != e; ++i) {
- std::pair<int, int64_t> Entry = MFI->getLocalFrameObjectMap(i);
+ for (unsigned i = 0, e = MFI.getLocalFrameObjectCount(); i != e; ++i) {
+ std::pair<int, int64_t> Entry = MFI.getLocalFrameObjectMap(i);
int64_t FIOffset = (StackGrowsDown ? -Offset : Offset) + Entry.second;
DEBUG(dbgs() << "alloc FI(" << Entry.first << ") at SP[" <<
FIOffset << "]\n");
- MFI->setObjectOffset(Entry.first, FIOffset);
+ MFI.setObjectOffset(Entry.first, FIOffset);
}
// Allocate the local block
- Offset += MFI->getLocalFrameSize();
+ Offset += MFI.getLocalFrameSize();
MaxAlign = std::max(Align, MaxAlign);
}
@@ -183,11 +183,11 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
// Then assign frame offsets to stack objects that are not used to spill
// callee saved registers.
- for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
- if (MFI->isObjectPreAllocated(i) &&
- MFI->getUseLocalStackAllocationBlock())
+ for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
+ if (MFI.isObjectPreAllocated(i) &&
+ MFI.getUseLocalStackAllocationBlock())
continue;
- if (MFI->isDeadObjectIndex(i))
+ if (MFI.isDeadObjectIndex(i))
continue;
AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
@@ -199,8 +199,8 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
// If we have reserved argument space for call sites in the function
// immediately on entry to the current function, count it as part of the
// overall stack size.
- if (MFI->adjustsStack() && TFI.hasReservedCallFrame(Fn))
- Offset += MFI->getMaxCallFrameSize();
+ if (MFI.adjustsStack() && TFI.hasReservedCallFrame(Fn))
+ Offset += MFI.getMaxCallFrameSize();
// Round up the size to a multiple of the alignment. If the function has
// any calls or alloca's, align to the target's StackAlignment value to
@@ -208,8 +208,8 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
// otherwise, for leaf functions, align to the TransientStackAlignment
// value.
unsigned StackAlign;
- if (MFI->adjustsStack() || MFI->hasVarSizedObjects() ||
- (RegInfo->needsStackRealignment(Fn) && MFI->getObjectIndexEnd() != 0))
+ if (MFI.adjustsStack() || MFI.hasVarSizedObjects() ||
+ (RegInfo->needsStackRealignment(Fn) && MFI.getObjectIndexEnd() != 0))
StackAlign = TFI.getStackAlignment();
else
StackAlign = TFI.getTransientStackAlignment();
@@ -223,5 +223,5 @@ NVPTXPrologEpilogPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
// Update frame info to pretend that this is part of the stack...
int64_t StackSize = Offset - LocalAreaOffset;
- MFI->setStackSize(StackSize);
+ MFI.setStackSize(StackSize);
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp
index 6e97f9e..6cbf060 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXRegisterInfo.cpp
@@ -33,11 +33,29 @@ std::string getNVPTXRegClassName(TargetRegisterClass const *RC) {
if (RC == &NVPTX::Float64RegsRegClass) {
return ".f64";
} else if (RC == &NVPTX::Int64RegsRegClass) {
- return ".s64";
+ // We use untyped (.b) integer registers here as NVCC does.
+ // Correctness of generated code does not depend on register type,
+ // but using .s/.u registers runs into ptxas bug that prevents
+ // assembly of otherwise valid PTX into SASS. Despite PTX ISA
+ // specifying only argument size for fp16 instructions, ptxas does
+ // not allow using .s16 or .u16 arguments for .fp16
+ // instructions. At the same time it allows using .s32/.u32
+ // arguments for .fp16v2 instructions:
+ //
+ // .reg .b16 rb16
+ // .reg .s16 rs16
+ // add.f16 rb16,rb16,rb16; // OK
+ // add.f16 rs16,rs16,rs16; // Arguments mismatch for instruction 'add'
+ // but:
+ // .reg .b32 rb32
+ // .reg .s32 rs32
+ // add.f16v2 rb32,rb32,rb32; // OK
+ // add.f16v2 rs32,rs32,rs32; // OK
+ return ".b64";
} else if (RC == &NVPTX::Int32RegsRegClass) {
- return ".s32";
+ return ".b32";
} else if (RC == &NVPTX::Int16RegsRegClass) {
- return ".s16";
+ return ".b16";
} else if (RC == &NVPTX::Int1RegsRegClass) {
return ".pred";
} else if (RC == &NVPTX::SpecialRegsRegClass) {
@@ -97,7 +115,7 @@ void NVPTXRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
MachineFunction &MF = *MI.getParent()->getParent();
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
MI.getOperand(FIOperandNum + 1).getImm();
// Using I0 as the frame pointer
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp
index 5a83371..2022cac 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXReplaceImageHandles.cpp
@@ -36,7 +36,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "NVPTX Replace Image Handles";
}
private:
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXSection.h b/contrib/llvm/lib/Target/NVPTX/NVPTXSection.h
index cad4f56..b0472de 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXSection.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXSection.h
@@ -1,4 +1,4 @@
-//===- NVPTXSection.h - NVPTX-specific section representation -*- C++ -*-===//
+//===- NVPTXSection.h - NVPTX-specific section representation ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,18 +14,20 @@
#ifndef LLVM_LIB_TARGET_NVPTX_NVPTXSECTION_H
#define LLVM_LIB_TARGET_NVPTX_NVPTXSECTION_H
-#include "llvm/IR/GlobalVariable.h"
#include "llvm/MC/MCSection.h"
+#include "llvm/MC/SectionKind.h"
namespace llvm {
+
/// Represents a section in PTX PTX does not have sections. We create this class
/// in order to use the ASMPrint interface.
///
class NVPTXSection final : public MCSection {
virtual void anchor();
+
public:
NVPTXSection(SectionVariant V, SectionKind K) : MCSection(V, K, nullptr) {}
- ~NVPTXSection() {}
+ ~NVPTXSection() = default;
/// Override this as NVPTX has its own way of printing switching
/// to a section.
@@ -40,4 +42,4 @@ public:
} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_NVPTX_NVPTXSECTION_H
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp
index bd2509a..6e1f427 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp
@@ -29,8 +29,6 @@ void NVPTXSubtarget::anchor() {}
NVPTXSubtarget &NVPTXSubtarget::initializeSubtargetDependencies(StringRef CPU,
StringRef FS) {
// Provide the default CPU if we don't have one.
- if (CPU.empty() && FS.size())
- llvm_unreachable("we are not using FeatureStr");
TargetName = CPU.empty() ? "sm_20" : CPU;
ParseSubtargetFeatures(TargetName, FS);
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.h b/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.h
index 4167039..da020a9 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXSubtarget.h
@@ -48,6 +48,10 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo {
// FrameLowering class because TargetFrameLowering is abstract.
NVPTXFrameLowering FrameLowering;
+protected:
+ // Processor supports scoped atomic operations.
+ bool HasAtomScope;
+
public:
/// This constructor initializes the data members to match that
/// of the specified module.
@@ -77,6 +81,10 @@ public:
bool hasAtomRedGen32() const { return SmVersion >= 20; }
bool hasAtomRedGen64() const { return SmVersion >= 20; }
bool hasAtomAddF32() const { return SmVersion >= 20; }
+ bool hasAtomAddF64() const { return SmVersion >= 60; }
+ bool hasAtomScope() const { return HasAtomScope; }
+ bool hasAtomBitwise64() const { return SmVersion >= 32; }
+ bool hasAtomMinMax64() const { return SmVersion >= 32; }
bool hasVote() const { return SmVersion >= 12; }
bool hasDouble() const { return SmVersion >= 13; }
bool reqPTX20() const { return SmVersion >= 20; }
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
index b9f5919..eb357e0 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
@@ -11,66 +11,56 @@
//
//===----------------------------------------------------------------------===//
-#include "NVPTXTargetMachine.h"
-#include "MCTargetDesc/NVPTXMCAsmInfo.h"
#include "NVPTX.h"
#include "NVPTXAllocaHoisting.h"
#include "NVPTXLowerAggrCopies.h"
+#include "NVPTXTargetMachine.h"
#include "NVPTXTargetObjectFile.h"
#include "NVPTXTargetTransformInfo.h"
-#include "llvm/Analysis/Passes.h"
-#include "llvm/CodeGen/AsmPrinter.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetLowering.h"
-#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Target/TargetRegisterInfo.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
+#include "llvm/Transforms/Vectorize.h"
+#include <cassert>
+#include <string>
using namespace llvm;
-static cl::opt<bool> UseInferAddressSpaces(
- "nvptx-use-infer-addrspace", cl::init(false), cl::Hidden,
- cl::desc("Optimize address spaces using NVPTXInferAddressSpaces instead of "
- "NVPTXFavorNonGenericAddrSpaces"));
+// LSV is still relatively new; this switch lets us turn it off in case we
+// encounter (or suspect) a bug.
+static cl::opt<bool>
+ DisableLoadStoreVectorizer("disable-nvptx-load-store-vectorizer",
+ cl::desc("Disable load/store vectorizer"),
+ cl::init(false), cl::Hidden);
namespace llvm {
+
void initializeNVVMIntrRangePass(PassRegistry&);
void initializeNVVMReflectPass(PassRegistry&);
void initializeGenericToNVVMPass(PassRegistry&);
void initializeNVPTXAllocaHoistingPass(PassRegistry &);
void initializeNVPTXAssignValidGlobalNamesPass(PassRegistry&);
-void initializeNVPTXFavorNonGenericAddrSpacesPass(PassRegistry &);
void initializeNVPTXInferAddressSpacesPass(PassRegistry &);
void initializeNVPTXLowerAggrCopiesPass(PassRegistry &);
-void initializeNVPTXLowerKernelArgsPass(PassRegistry &);
+void initializeNVPTXLowerArgsPass(PassRegistry &);
void initializeNVPTXLowerAllocaPass(PassRegistry &);
-}
+
+} // end namespace llvm
extern "C" void LLVMInitializeNVPTXTarget() {
// Register the target.
- RegisterTargetMachine<NVPTXTargetMachine32> X(TheNVPTXTarget32);
- RegisterTargetMachine<NVPTXTargetMachine64> Y(TheNVPTXTarget64);
+ RegisterTargetMachine<NVPTXTargetMachine32> X(getTheNVPTXTarget32());
+ RegisterTargetMachine<NVPTXTargetMachine64> Y(getTheNVPTXTarget64());
// FIXME: This pass is really intended to be invoked during IR optimization,
// but it's very NVPTX-specific.
@@ -80,9 +70,8 @@ extern "C" void LLVMInitializeNVPTXTarget() {
initializeGenericToNVVMPass(PR);
initializeNVPTXAllocaHoistingPass(PR);
initializeNVPTXAssignValidGlobalNamesPass(PR);
- initializeNVPTXFavorNonGenericAddrSpacesPass(PR);
initializeNVPTXInferAddressSpacesPass(PR);
- initializeNVPTXLowerKernelArgsPass(PR);
+ initializeNVPTXLowerArgsPass(PR);
initializeNVPTXLowerAllocaPass(PR);
initializeNVPTXLowerAggrCopiesPass(PR);
}
@@ -109,7 +98,7 @@ NVPTXTargetMachine::NVPTXTargetMachine(const Target &T, const Triple &TT,
: LLVMTargetMachine(T, computeDataLayout(is64bit), TT, CPU, FS, Options,
Reloc::PIC_, CM, OL),
is64bit(is64bit),
- TLOF(make_unique<NVPTXTargetObjectFile>()),
+ TLOF(llvm::make_unique<NVPTXTargetObjectFile>()),
Subtarget(TT, CPU, FS, *this) {
if (TT.getOS() == Triple::NVCL)
drvInterface = NVPTX::NVCL;
@@ -118,7 +107,7 @@ NVPTXTargetMachine::NVPTXTargetMachine(const Target &T, const Triple &TT,
initAsmInfo();
}
-NVPTXTargetMachine::~NVPTXTargetMachine() {}
+NVPTXTargetMachine::~NVPTXTargetMachine() = default;
void NVPTXTargetMachine32::anchor() {}
@@ -141,6 +130,7 @@ NVPTXTargetMachine64::NVPTXTargetMachine64(const Target &T, const Triple &TT,
: NVPTXTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {}
namespace {
+
class NVPTXPassConfig : public TargetPassConfig {
public:
NVPTXPassConfig(NVPTXTargetMachine *TM, PassManagerBase &PM)
@@ -170,6 +160,7 @@ private:
// Add passes that perform straight-line scalar optimizations.
void addStraightLineScalarOptimizationPasses();
};
+
} // end anonymous namespace
TargetPassConfig *NVPTXTargetMachine::createPassConfig(PassManagerBase &PM) {
@@ -195,19 +186,11 @@ void NVPTXPassConfig::addEarlyCSEOrGVNPass() {
}
void NVPTXPassConfig::addAddressSpaceInferencePasses() {
- // NVPTXLowerKernelArgs emits alloca for byval parameters which can often
+ // NVPTXLowerArgs emits alloca for byval parameters which can often
// be eliminated by SROA.
addPass(createSROAPass());
addPass(createNVPTXLowerAllocaPass());
- if (UseInferAddressSpaces) {
- addPass(createNVPTXInferAddressSpacesPass());
- } else {
- addPass(createNVPTXFavorNonGenericAddrSpacesPass());
- // FavorNonGenericAddrSpaces shortcuts unnecessary addrspacecasts, and leave
- // them unused. We could remove dead code in an ad-hoc manner, but that
- // requires manual work and might be error-prone.
- addPass(createDeadCodeEliminationPass());
- }
+ addPass(createNVPTXInferAddressSpacesPass());
}
void NVPTXPassConfig::addStraightLineScalarOptimizationPasses() {
@@ -253,11 +236,13 @@ void NVPTXPassConfig::addIRPasses() {
addPass(createNVPTXAssignValidGlobalNamesPass());
addPass(createGenericToNVVMPass());
- // NVPTXLowerKernelArgs is required for correctness and should be run right
+ // NVPTXLowerArgs is required for correctness and should be run right
// before the address space inference passes.
- addPass(createNVPTXLowerKernelArgsPass(&getNVPTXTargetMachine()));
+ addPass(createNVPTXLowerArgsPass(&getNVPTXTargetMachine()));
if (getOptLevel() != CodeGenOpt::None) {
addAddressSpaceInferencePasses();
+ if (!DisableLoadStoreVectorizer)
+ addPass(createLoadStoreVectorizerPass());
addStraightLineScalarOptimizationPasses();
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h
index 045fbb7..69c59d0 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetObjectFile.h
@@ -11,14 +11,13 @@
#define LLVM_LIB_TARGET_NVPTX_NVPTXTARGETOBJECTFILE_H
#include "NVPTXSection.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/SectionKind.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
namespace llvm {
-class GlobalVariable;
-class Module;
class NVPTXTargetObjectFile : public TargetLoweringObjectFile {
-
public:
NVPTXTargetObjectFile() {
TextSection = nullptr;
@@ -43,7 +42,7 @@ public:
DwarfMacinfoSection = nullptr;
}
- virtual ~NVPTXTargetObjectFile();
+ ~NVPTXTargetObjectFile() override;
void Initialize(MCContext &ctx, const TargetMachine &TM) override {
TargetLoweringObjectFile::Initialize(ctx, TM);
@@ -52,7 +51,6 @@ public:
BSSSection = new NVPTXSection(MCSection::SV_ELF, SectionKind::getBSS());
ReadOnlySection =
new NVPTXSection(MCSection::SV_ELF, SectionKind::getReadOnly());
-
StaticCtorSection =
new NVPTXSection(MCSection::SV_ELF, SectionKind::getMetadata());
StaticDtorSection =
@@ -91,17 +89,15 @@ public:
return ReadOnlySection;
}
- MCSection *getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override {
return DataSection;
}
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
};
} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_NVPTX_NVPTXTARGETOBJECTFILE_H
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
index 580d345..dd77070 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
@@ -42,6 +42,29 @@ static bool isNVVMAtomic(const IntrinsicInst *II) {
case Intrinsic::nvvm_atomic_load_add_f32:
case Intrinsic::nvvm_atomic_load_inc_32:
case Intrinsic::nvvm_atomic_load_dec_32:
+
+ case Intrinsic::nvvm_atomic_add_gen_f_cta:
+ case Intrinsic::nvvm_atomic_add_gen_f_sys:
+ case Intrinsic::nvvm_atomic_add_gen_i_cta:
+ case Intrinsic::nvvm_atomic_add_gen_i_sys:
+ case Intrinsic::nvvm_atomic_and_gen_i_cta:
+ case Intrinsic::nvvm_atomic_and_gen_i_sys:
+ case Intrinsic::nvvm_atomic_cas_gen_i_cta:
+ case Intrinsic::nvvm_atomic_cas_gen_i_sys:
+ case Intrinsic::nvvm_atomic_dec_gen_i_cta:
+ case Intrinsic::nvvm_atomic_dec_gen_i_sys:
+ case Intrinsic::nvvm_atomic_inc_gen_i_cta:
+ case Intrinsic::nvvm_atomic_inc_gen_i_sys:
+ case Intrinsic::nvvm_atomic_max_gen_i_cta:
+ case Intrinsic::nvvm_atomic_max_gen_i_sys:
+ case Intrinsic::nvvm_atomic_min_gen_i_cta:
+ case Intrinsic::nvvm_atomic_min_gen_i_sys:
+ case Intrinsic::nvvm_atomic_or_gen_i_cta:
+ case Intrinsic::nvvm_atomic_or_gen_i_sys:
+ case Intrinsic::nvvm_atomic_exch_gen_i_cta:
+ case Intrinsic::nvvm_atomic_exch_gen_i_sys:
+ case Intrinsic::nvvm_atomic_xor_gen_i_cta:
+ case Intrinsic::nvvm_atomic_xor_gen_i_sys:
return true;
}
}
@@ -92,7 +115,7 @@ bool NVPTXTTIImpl::isSourceOfDivergence(const Value *V) {
int NVPTXTTIImpl::getArithmeticInstrCost(
unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info,
TTI::OperandValueKind Opd2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ TTI::OperandValueProperties Opd2PropInfo, ArrayRef<const Value *> Args) {
// Legalize the type.
std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Ty);
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
index 08ffdf1..b6c271a 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
@@ -41,13 +41,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl()),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- NVPTXTTIImpl(const NVPTXTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- NVPTXTTIImpl(NVPTXTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
bool hasBranchDivergence() { return true; }
bool isSourceOfDivergence(const Value *V);
@@ -61,7 +54,8 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP);
};
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp b/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp
index 835e4b4..e464f47 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.cpp
@@ -26,16 +26,18 @@
#include <string>
#include <vector>
-using namespace llvm;
+namespace llvm {
+namespace {
typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t;
typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t;
typedef std::map<const Module *, global_val_annot_t> per_module_annot_t;
+} // anonymous namespace
-ManagedStatic<per_module_annot_t> annotationCache;
+static ManagedStatic<per_module_annot_t> annotationCache;
static sys::Mutex Lock;
-void llvm::clearAnnotationCache(const llvm::Module *Mod) {
+void clearAnnotationCache(const Module *Mod) {
MutexGuard Guard(Lock);
annotationCache->erase(Mod);
}
@@ -68,7 +70,7 @@ static void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) {
static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) {
MutexGuard Guard(Lock);
- NamedMDNode *NMD = m->getNamedMetadata(llvm::NamedMDForAnnotations);
+ NamedMDNode *NMD = m->getNamedMetadata("nvvm.annotations");
if (!NMD)
return;
key_val_pair_t tmp;
@@ -99,8 +101,8 @@ static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) {
}
}
-bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
- unsigned &retval) {
+bool findOneNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
+ unsigned &retval) {
MutexGuard Guard(Lock);
const Module *m = gv->getParent();
if ((*annotationCache).find(m) == (*annotationCache).end())
@@ -113,8 +115,8 @@ bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
return true;
}
-bool llvm::findAllNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
- std::vector<unsigned> &retval) {
+bool findAllNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
+ std::vector<unsigned> &retval) {
MutexGuard Guard(Lock);
const Module *m = gv->getParent();
if ((*annotationCache).find(m) == (*annotationCache).end())
@@ -127,12 +129,10 @@ bool llvm::findAllNVVMAnnotation(const GlobalValue *gv, const std::string &prop,
return true;
}
-bool llvm::isTexture(const llvm::Value &val) {
+bool isTexture(const Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
- if (llvm::findOneNVVMAnnotation(
- gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISTEXTURE],
- annot)) {
+ if (findOneNVVMAnnotation(gv, "texture", annot)) {
assert((annot == 1) && "Unexpected annotation on a texture symbol");
return true;
}
@@ -140,12 +140,10 @@ bool llvm::isTexture(const llvm::Value &val) {
return false;
}
-bool llvm::isSurface(const llvm::Value &val) {
+bool isSurface(const Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
- if (llvm::findOneNVVMAnnotation(
- gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSURFACE],
- annot)) {
+ if (findOneNVVMAnnotation(gv, "surface", annot)) {
assert((annot == 1) && "Unexpected annotation on a surface symbol");
return true;
}
@@ -153,12 +151,12 @@ bool llvm::isSurface(const llvm::Value &val) {
return false;
}
-bool llvm::isSampler(const llvm::Value &val) {
+bool isSampler(const Value &val) {
+ const char *AnnotationName = "sampler";
+
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
- if (llvm::findOneNVVMAnnotation(
- gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
- annot)) {
+ if (findOneNVVMAnnotation(gv, AnnotationName, annot)) {
assert((annot == 1) && "Unexpected annotation on a sampler symbol");
return true;
}
@@ -166,72 +164,58 @@ bool llvm::isSampler(const llvm::Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
- if (llvm::findAllNVVMAnnotation(
- func, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
- annot)) {
- if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
+ if (findAllNVVMAnnotation(func, AnnotationName, annot)) {
+ if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
-bool llvm::isImageReadOnly(const llvm::Value &val) {
+bool isImageReadOnly(const Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
- if (llvm::findAllNVVMAnnotation(func,
- llvm::PropertyAnnotationNames[
- llvm::PROPERTY_ISREADONLY_IMAGE_PARAM],
- annot)) {
- if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
+ if (findAllNVVMAnnotation(func, "rdoimage", annot)) {
+ if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
-bool llvm::isImageWriteOnly(const llvm::Value &val) {
+bool isImageWriteOnly(const Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
- if (llvm::findAllNVVMAnnotation(func,
- llvm::PropertyAnnotationNames[
- llvm::PROPERTY_ISWRITEONLY_IMAGE_PARAM],
- annot)) {
- if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
+ if (findAllNVVMAnnotation(func, "wroimage", annot)) {
+ if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
-bool llvm::isImageReadWrite(const llvm::Value &val) {
+bool isImageReadWrite(const Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
- if (llvm::findAllNVVMAnnotation(func,
- llvm::PropertyAnnotationNames[
- llvm::PROPERTY_ISREADWRITE_IMAGE_PARAM],
- annot)) {
- if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
+ if (findAllNVVMAnnotation(func, "rdwrimage", annot)) {
+ if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
-bool llvm::isImage(const llvm::Value &val) {
- return llvm::isImageReadOnly(val) || llvm::isImageWriteOnly(val) ||
- llvm::isImageReadWrite(val);
+bool isImage(const Value &val) {
+ return isImageReadOnly(val) || isImageWriteOnly(val) || isImageReadWrite(val);
}
-bool llvm::isManaged(const llvm::Value &val) {
+bool isManaged(const Value &val) {
if(const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
- if(llvm::findOneNVVMAnnotation(gv,
- llvm::PropertyAnnotationNames[llvm::PROPERTY_MANAGED],
- annot)) {
+ if (findOneNVVMAnnotation(gv, "managed", annot)) {
assert((annot == 1) && "Unexpected annotation on a managed symbol");
return true;
}
@@ -239,71 +223,66 @@ bool llvm::isManaged(const llvm::Value &val) {
return false;
}
-std::string llvm::getTextureName(const llvm::Value &val) {
+std::string getTextureName(const Value &val) {
assert(val.hasName() && "Found texture variable with no name");
return val.getName();
}
-std::string llvm::getSurfaceName(const llvm::Value &val) {
+std::string getSurfaceName(const Value &val) {
assert(val.hasName() && "Found surface variable with no name");
return val.getName();
}
-std::string llvm::getSamplerName(const llvm::Value &val) {
+std::string getSamplerName(const Value &val) {
assert(val.hasName() && "Found sampler variable with no name");
return val.getName();
}
-bool llvm::getMaxNTIDx(const Function &F, unsigned &x) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_X], x));
+bool getMaxNTIDx(const Function &F, unsigned &x) {
+ return findOneNVVMAnnotation(&F, "maxntidx", x);
+}
+
+bool getMaxNTIDy(const Function &F, unsigned &y) {
+ return findOneNVVMAnnotation(&F, "maxntidy", y);
}
-bool llvm::getMaxNTIDy(const Function &F, unsigned &y) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Y], y));
+bool getMaxNTIDz(const Function &F, unsigned &z) {
+ return findOneNVVMAnnotation(&F, "maxntidz", z);
}
-bool llvm::getMaxNTIDz(const Function &F, unsigned &z) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Z], z));
+bool getReqNTIDx(const Function &F, unsigned &x) {
+ return findOneNVVMAnnotation(&F, "reqntidx", x);
}
-bool llvm::getReqNTIDx(const Function &F, unsigned &x) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_X], x));
+bool getReqNTIDy(const Function &F, unsigned &y) {
+ return findOneNVVMAnnotation(&F, "reqntidy", y);
}
-bool llvm::getReqNTIDy(const Function &F, unsigned &y) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Y], y));
+bool getReqNTIDz(const Function &F, unsigned &z) {
+ return findOneNVVMAnnotation(&F, "reqntidz", z);
}
-bool llvm::getReqNTIDz(const Function &F, unsigned &z) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Z], z));
+bool getMinCTASm(const Function &F, unsigned &x) {
+ return findOneNVVMAnnotation(&F, "minctasm", x);
}
-bool llvm::getMinCTASm(const Function &F, unsigned &x) {
- return (llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MINNCTAPERSM], x));
+bool getMaxNReg(const Function &F, unsigned &x) {
+ return findOneNVVMAnnotation(&F, "maxnreg", x);
}
-bool llvm::isKernelFunction(const Function &F) {
+bool isKernelFunction(const Function &F) {
unsigned x = 0;
- bool retval = llvm::findOneNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISKERNEL_FUNCTION], x);
+ bool retval = findOneNVVMAnnotation(&F, "kernel", x);
if (!retval) {
// There is no NVVM metadata, check the calling convention
- return F.getCallingConv() == llvm::CallingConv::PTX_Kernel;
+ return F.getCallingConv() == CallingConv::PTX_Kernel;
}
return (x == 1);
}
-bool llvm::getAlign(const Function &F, unsigned index, unsigned &align) {
+bool getAlign(const Function &F, unsigned index, unsigned &align) {
std::vector<unsigned> Vs;
- bool retval = llvm::findAllNVVMAnnotation(
- &F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ALIGN], Vs);
+ bool retval = findAllNVVMAnnotation(&F, "align", Vs);
if (!retval)
return false;
for (int i = 0, e = Vs.size(); i < e; i++) {
@@ -316,7 +295,7 @@ bool llvm::getAlign(const Function &F, unsigned index, unsigned &align) {
return false;
}
-bool llvm::getAlign(const CallInst &I, unsigned index, unsigned &align) {
+bool getAlign(const CallInst &I, unsigned index, unsigned &align) {
if (MDNode *alignNode = I.getMetadata("callalign")) {
for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) {
if (const ConstantInt *CI =
@@ -335,108 +314,4 @@ bool llvm::getAlign(const CallInst &I, unsigned index, unsigned &align) {
return false;
}
-// The following are some useful utilities for debugging
-
-BasicBlock *llvm::getParentBlock(Value *v) {
- if (BasicBlock *B = dyn_cast<BasicBlock>(v))
- return B;
-
- if (Instruction *I = dyn_cast<Instruction>(v))
- return I->getParent();
-
- return nullptr;
-}
-
-Function *llvm::getParentFunction(Value *v) {
- if (Function *F = dyn_cast<Function>(v))
- return F;
-
- if (Instruction *I = dyn_cast<Instruction>(v))
- return I->getParent()->getParent();
-
- if (BasicBlock *B = dyn_cast<BasicBlock>(v))
- return B->getParent();
-
- return nullptr;
-}
-
-// Dump a block by name
-void llvm::dumpBlock(Value *v, char *blockName) {
- Function *F = getParentFunction(v);
- if (!F)
- return;
-
- for (Function::iterator it = F->begin(), ie = F->end(); it != ie; ++it) {
- BasicBlock *B = &*it;
- if (strcmp(B->getName().data(), blockName) == 0) {
- B->dump();
- return;
- }
- }
-}
-
-// Find an instruction by name
-Instruction *llvm::getInst(Value *base, char *instName) {
- Function *F = getParentFunction(base);
- if (!F)
- return nullptr;
-
- for (inst_iterator it = inst_begin(F), ie = inst_end(F); it != ie; ++it) {
- Instruction *I = &*it;
- if (strcmp(I->getName().data(), instName) == 0) {
- return I;
- }
- }
-
- return nullptr;
-}
-
-// Dump an instruction by name
-void llvm::dumpInst(Value *base, char *instName) {
- Instruction *I = getInst(base, instName);
- if (I)
- I->dump();
-}
-
-// Dump an instruction and all dependent instructions
-void llvm::dumpInstRec(Value *v, std::set<Instruction *> *visited) {
- if (Instruction *I = dyn_cast<Instruction>(v)) {
-
- if (visited->find(I) != visited->end())
- return;
-
- visited->insert(I);
-
- for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
- dumpInstRec(I->getOperand(i), visited);
-
- I->dump();
- }
-}
-
-// Dump an instruction and all dependent instructions
-void llvm::dumpInstRec(Value *v) {
- std::set<Instruction *> visited;
-
- //BasicBlock *B = getParentBlock(v);
-
- dumpInstRec(v, &visited);
-}
-
-// Dump the parent for Instruction, block or function
-void llvm::dumpParent(Value *v) {
- if (Instruction *I = dyn_cast<Instruction>(v)) {
- I->getParent()->dump();
- return;
- }
-
- if (BasicBlock *B = dyn_cast<BasicBlock>(v)) {
- B->getParent()->dump();
- return;
- }
-
- if (Function *F = dyn_cast<Function>(v)) {
- F->getParent()->dump();
- return;
- }
-}
+} // namespace llvm
diff --git a/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.h b/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.h
index ec5bfc1..a0cc4e7 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.h
+++ b/contrib/llvm/lib/Target/NVPTX/NVPTXUtilities.h
@@ -25,51 +25,40 @@
namespace llvm {
-#define NVCL_IMAGE2D_READONLY_FUNCNAME "__is_image2D_readonly"
-#define NVCL_IMAGE3D_READONLY_FUNCNAME "__is_image3D_readonly"
+void clearAnnotationCache(const Module *);
-void clearAnnotationCache(const llvm::Module *);
-
-bool findOneNVVMAnnotation(const llvm::GlobalValue *, const std::string &,
+bool findOneNVVMAnnotation(const GlobalValue *, const std::string &,
unsigned &);
-bool findAllNVVMAnnotation(const llvm::GlobalValue *, const std::string &,
+bool findAllNVVMAnnotation(const GlobalValue *, const std::string &,
std::vector<unsigned> &);
-bool isTexture(const llvm::Value &);
-bool isSurface(const llvm::Value &);
-bool isSampler(const llvm::Value &);
-bool isImage(const llvm::Value &);
-bool isImageReadOnly(const llvm::Value &);
-bool isImageWriteOnly(const llvm::Value &);
-bool isImageReadWrite(const llvm::Value &);
-bool isManaged(const llvm::Value &);
-
-std::string getTextureName(const llvm::Value &);
-std::string getSurfaceName(const llvm::Value &);
-std::string getSamplerName(const llvm::Value &);
+bool isTexture(const Value &);
+bool isSurface(const Value &);
+bool isSampler(const Value &);
+bool isImage(const Value &);
+bool isImageReadOnly(const Value &);
+bool isImageWriteOnly(const Value &);
+bool isImageReadWrite(const Value &);
+bool isManaged(const Value &);
-bool getMaxNTIDx(const llvm::Function &, unsigned &);
-bool getMaxNTIDy(const llvm::Function &, unsigned &);
-bool getMaxNTIDz(const llvm::Function &, unsigned &);
+std::string getTextureName(const Value &);
+std::string getSurfaceName(const Value &);
+std::string getSamplerName(const Value &);
-bool getReqNTIDx(const llvm::Function &, unsigned &);
-bool getReqNTIDy(const llvm::Function &, unsigned &);
-bool getReqNTIDz(const llvm::Function &, unsigned &);
+bool getMaxNTIDx(const Function &, unsigned &);
+bool getMaxNTIDy(const Function &, unsigned &);
+bool getMaxNTIDz(const Function &, unsigned &);
-bool getMinCTASm(const llvm::Function &, unsigned &);
-bool isKernelFunction(const llvm::Function &);
+bool getReqNTIDx(const Function &, unsigned &);
+bool getReqNTIDy(const Function &, unsigned &);
+bool getReqNTIDz(const Function &, unsigned &);
-bool getAlign(const llvm::Function &, unsigned index, unsigned &);
-bool getAlign(const llvm::CallInst &, unsigned index, unsigned &);
+bool getMinCTASm(const Function &, unsigned &);
+bool getMaxNReg(const Function &, unsigned &);
+bool isKernelFunction(const Function &);
-BasicBlock *getParentBlock(Value *v);
-Function *getParentFunction(Value *v);
-void dumpBlock(Value *v, char *blockName);
-Instruction *getInst(Value *base, char *instName);
-void dumpInst(Value *base, char *instName);
-void dumpInstRec(Value *v, std::set<Instruction *> *visited);
-void dumpInstRec(Value *v);
-void dumpParent(Value *v);
+bool getAlign(const Function &, unsigned index, unsigned &);
+bool getAlign(const CallInst &, unsigned index, unsigned &);
}
diff --git a/contrib/llvm/lib/Target/NVPTX/NVVMIntrRange.cpp b/contrib/llvm/lib/Target/NVPTX/NVVMIntrRange.cpp
index b9c02c4..9c71a2e 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVVMIntrRange.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVVMIntrRange.cpp
@@ -65,6 +65,10 @@ INITIALIZE_PASS(NVVMIntrRange, "nvvm-intr-range",
// Adds the passed-in [Low,High) range information as metadata to the
// passed-in call instruction.
static bool addRangeMetadata(uint64_t Low, uint64_t High, CallInst *C) {
+ // This call already has range metadata, nothing to do.
+ if (C->getMetadata(LLVMContext::MD_range))
+ return false;
+
LLVMContext &Context = C->getParent()->getContext();
IntegerType *Int32Ty = Type::getInt32Ty(Context);
Metadata *LowAndHigh[] = {
diff --git a/contrib/llvm/lib/Target/NVPTX/NVVMReflect.cpp b/contrib/llvm/lib/Target/NVPTX/NVVMReflect.cpp
index e0c35e7..c639c4d 100644
--- a/contrib/llvm/lib/Target/NVPTX/NVVMReflect.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/NVVMReflect.cpp
@@ -65,7 +65,6 @@ public:
bool runOnFunction(Function &) override;
private:
- bool handleFunction(Function *ReflectFunction);
void setVarMap();
};
}
diff --git a/contrib/llvm/lib/Target/NVPTX/TargetInfo/NVPTXTargetInfo.cpp b/contrib/llvm/lib/Target/NVPTX/TargetInfo/NVPTXTargetInfo.cpp
index cc7d4dc..d44876a 100644
--- a/contrib/llvm/lib/Target/NVPTX/TargetInfo/NVPTXTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/NVPTX/TargetInfo/NVPTXTargetInfo.cpp
@@ -12,12 +12,18 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheNVPTXTarget32;
-Target llvm::TheNVPTXTarget64;
+Target &llvm::getTheNVPTXTarget32() {
+ static Target TheNVPTXTarget32;
+ return TheNVPTXTarget32;
+}
+Target &llvm::getTheNVPTXTarget64() {
+ static Target TheNVPTXTarget64;
+ return TheNVPTXTarget64;
+}
extern "C" void LLVMInitializeNVPTXTargetInfo() {
- RegisterTarget<Triple::nvptx> X(TheNVPTXTarget32, "nvptx",
+ RegisterTarget<Triple::nvptx> X(getTheNVPTXTarget32(), "nvptx",
"NVIDIA PTX 32-bit");
- RegisterTarget<Triple::nvptx64> Y(TheNVPTXTarget64, "nvptx64",
+ RegisterTarget<Triple::nvptx64> Y(getTheNVPTXTarget64(), "nvptx64",
"NVIDIA PTX 64-bit");
}
diff --git a/contrib/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/contrib/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 4181775..52432a5 100644
--- a/contrib/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -83,6 +83,16 @@ static const MCPhysReg FRegs[32] = {
PPC::F24, PPC::F25, PPC::F26, PPC::F27,
PPC::F28, PPC::F29, PPC::F30, PPC::F31
};
+static const MCPhysReg VFRegs[32] = {
+ PPC::VF0, PPC::VF1, PPC::VF2, PPC::VF3,
+ PPC::VF4, PPC::VF5, PPC::VF6, PPC::VF7,
+ PPC::VF8, PPC::VF9, PPC::VF10, PPC::VF11,
+ PPC::VF12, PPC::VF13, PPC::VF14, PPC::VF15,
+ PPC::VF16, PPC::VF17, PPC::VF18, PPC::VF19,
+ PPC::VF20, PPC::VF21, PPC::VF22, PPC::VF23,
+ PPC::VF24, PPC::VF25, PPC::VF26, PPC::VF27,
+ PPC::VF28, PPC::VF29, PPC::VF30, PPC::VF31
+};
static const MCPhysReg VRegs[32] = {
PPC::V0, PPC::V1, PPC::V2, PPC::V3,
PPC::V4, PPC::V5, PPC::V6, PPC::V7,
@@ -103,14 +113,14 @@ static const MCPhysReg VSRegs[64] = {
PPC::VSL24, PPC::VSL25, PPC::VSL26, PPC::VSL27,
PPC::VSL28, PPC::VSL29, PPC::VSL30, PPC::VSL31,
- PPC::VSH0, PPC::VSH1, PPC::VSH2, PPC::VSH3,
- PPC::VSH4, PPC::VSH5, PPC::VSH6, PPC::VSH7,
- PPC::VSH8, PPC::VSH9, PPC::VSH10, PPC::VSH11,
- PPC::VSH12, PPC::VSH13, PPC::VSH14, PPC::VSH15,
- PPC::VSH16, PPC::VSH17, PPC::VSH18, PPC::VSH19,
- PPC::VSH20, PPC::VSH21, PPC::VSH22, PPC::VSH23,
- PPC::VSH24, PPC::VSH25, PPC::VSH26, PPC::VSH27,
- PPC::VSH28, PPC::VSH29, PPC::VSH30, PPC::VSH31
+ PPC::V0, PPC::V1, PPC::V2, PPC::V3,
+ PPC::V4, PPC::V5, PPC::V6, PPC::V7,
+ PPC::V8, PPC::V9, PPC::V10, PPC::V11,
+ PPC::V12, PPC::V13, PPC::V14, PPC::V15,
+ PPC::V16, PPC::V17, PPC::V18, PPC::V19,
+ PPC::V20, PPC::V21, PPC::V22, PPC::V23,
+ PPC::V24, PPC::V25, PPC::V26, PPC::V27,
+ PPC::V28, PPC::V29, PPC::V30, PPC::V31
};
static const MCPhysReg VSFRegs[64] = {
PPC::F0, PPC::F1, PPC::F2, PPC::F3,
@@ -246,13 +256,11 @@ class PPCAsmParser : public MCTargetAsmParser {
bool IsDarwin;
void Warning(SMLoc L, const Twine &Msg) { getParser().Warning(L, Msg); }
- bool Error(SMLoc L, const Twine &Msg) { return getParser().Error(L, Msg); }
bool isPPC64() const { return IsPPC64; }
bool isDarwin() const { return IsDarwin; }
- bool MatchRegisterName(const AsmToken &Tok,
- unsigned &RegNo, int64_t &IntVal);
+ bool MatchRegisterName(unsigned &RegNo, int64_t &IntVal);
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
@@ -264,8 +272,8 @@ class PPCAsmParser : public MCTargetAsmParser {
bool ParseOperand(OperandVector &Operands);
- bool ParseDirectiveWord(unsigned Size, SMLoc L);
- bool ParseDirectiveTC(unsigned Size, SMLoc L);
+ bool ParseDirectiveWord(unsigned Size, AsmToken ID);
+ bool ParseDirectiveTC(unsigned Size, AsmToken ID);
bool ParseDirectiveMachine(SMLoc L);
bool ParseDarwinDirectiveMachine(SMLoc L);
bool ParseDirectiveAbiVersion(SMLoc L);
@@ -545,6 +553,7 @@ public:
&& isUInt<5>(getImm())); }
bool isCRBitMask() const { return Kind == Immediate && isUInt<8>(getImm()) &&
isPowerOf2_32(getImm()); }
+ bool isATBitsAsHint() const { return false; }
bool isMem() const override { return false; }
bool isReg() const override { return false; }
@@ -596,6 +605,11 @@ public:
Inst.addOperand(MCOperand::createReg(FRegs[getReg()]));
}
+ void addRegVFRCOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(VFRegs[getReg()]));
+ }
+
void addRegVRRCOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createReg(VRegs[getReg()]));
@@ -874,6 +888,23 @@ void PPCAsmParser::ProcessInstruction(MCInst &Inst,
Inst = TmpInst;
break;
}
+ case PPC::DCBFx:
+ case PPC::DCBFL:
+ case PPC::DCBFLP: {
+ int L = 0;
+ if (Opcode == PPC::DCBFL)
+ L = 1;
+ else if (Opcode == PPC::DCBFLP)
+ L = 3;
+
+ MCInst TmpInst;
+ TmpInst.setOpcode(PPC::DCBF);
+ TmpInst.addOperand(MCOperand::createImm(L));
+ TmpInst.addOperand(Inst.getOperand(0));
+ TmpInst.addOperand(Inst.getOperand(1));
+ Inst = TmpInst;
+ break;
+ }
case PPC::LAx: {
MCInst TmpInst;
TmpInst.setOpcode(PPC::LA);
@@ -1263,68 +1294,54 @@ bool PPCAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
llvm_unreachable("Implement any new match types added!");
}
-bool PPCAsmParser::
-MatchRegisterName(const AsmToken &Tok, unsigned &RegNo, int64_t &IntVal) {
- if (Tok.is(AsmToken::Identifier)) {
- StringRef Name = Tok.getString();
-
+bool PPCAsmParser::MatchRegisterName(unsigned &RegNo, int64_t &IntVal) {
+ if (getParser().getTok().is(AsmToken::Identifier)) {
+ StringRef Name = getParser().getTok().getString();
if (Name.equals_lower("lr")) {
RegNo = isPPC64()? PPC::LR8 : PPC::LR;
IntVal = 8;
- return false;
} else if (Name.equals_lower("ctr")) {
RegNo = isPPC64()? PPC::CTR8 : PPC::CTR;
IntVal = 9;
- return false;
} else if (Name.equals_lower("vrsave")) {
RegNo = PPC::VRSAVE;
IntVal = 256;
- return false;
} else if (Name.startswith_lower("r") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = isPPC64()? XRegs[IntVal] : RRegs[IntVal];
- return false;
} else if (Name.startswith_lower("f") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = FRegs[IntVal];
- return false;
} else if (Name.startswith_lower("vs") &&
!Name.substr(2).getAsInteger(10, IntVal) && IntVal < 64) {
RegNo = VSRegs[IntVal];
- return false;
} else if (Name.startswith_lower("v") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = VRegs[IntVal];
- return false;
} else if (Name.startswith_lower("q") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = QFRegs[IntVal];
- return false;
} else if (Name.startswith_lower("cr") &&
!Name.substr(2).getAsInteger(10, IntVal) && IntVal < 8) {
RegNo = CRRegs[IntVal];
- return false;
- }
+ } else
+ return true;
+ getParser().Lex();
+ return false;
}
-
return true;
}
bool PPCAsmParser::
ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
+ const AsmToken &Tok = getParser().getTok();
StartLoc = Tok.getLoc();
EndLoc = Tok.getEndLoc();
RegNo = 0;
int64_t IntVal;
-
- if (!MatchRegisterName(Tok, RegNo, IntVal)) {
- Parser.Lex(); // Eat identifier token.
- return false;
- }
-
- return Error(StartLoc, "invalid register name");
+ if (MatchRegisterName(RegNo, IntVal))
+ return TokError("invalid register name");
+ return false;
}
/// Extract \code @l/@ha \endcode modifier from expression. Recursively scan
@@ -1550,14 +1567,21 @@ bool PPCAsmParser::ParseOperand(OperandVector &Operands) {
Parser.Lex(); // Eat the '%'.
unsigned RegNo;
int64_t IntVal;
- if (!MatchRegisterName(Parser.getTok(), RegNo, IntVal)) {
- Parser.Lex(); // Eat the identifier token.
- Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64()));
- return false;
- }
- return Error(S, "invalid register name");
+ if (MatchRegisterName(RegNo, IntVal))
+ return Error(S, "invalid register name");
+
+ Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64()));
+ return false;
case AsmToken::Identifier:
+ case AsmToken::LParen:
+ case AsmToken::Plus:
+ case AsmToken::Minus:
+ case AsmToken::Integer:
+ case AsmToken::Dot:
+ case AsmToken::Dollar:
+ case AsmToken::Exclaim:
+ case AsmToken::Tilde:
// Note that non-register-name identifiers from the compiler will begin
// with '_', 'L'/'l' or '"'. Of course, handwritten asm could include
// identifiers like r31foo - so we fall through in the event that parsing
@@ -1565,25 +1589,17 @@ bool PPCAsmParser::ParseOperand(OperandVector &Operands) {
if (isDarwin()) {
unsigned RegNo;
int64_t IntVal;
- if (!MatchRegisterName(Parser.getTok(), RegNo, IntVal)) {
- Parser.Lex(); // Eat the identifier token.
+ if (!MatchRegisterName(RegNo, IntVal)) {
Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64()));
return false;
}
}
- // Fall-through to process non-register-name identifiers as expression.
- // All other expressions
- case AsmToken::LParen:
- case AsmToken::Plus:
- case AsmToken::Minus:
- case AsmToken::Integer:
- case AsmToken::Dot:
- case AsmToken::Dollar:
- case AsmToken::Exclaim:
- case AsmToken::Tilde:
+ // All other expressions
+
if (!ParseExpression(EVal))
break;
- /* fall through */
+ // Fall-through
+ LLVM_FALLTHROUGH;
default:
return Error(S, "unknown operand");
}
@@ -1621,40 +1637,33 @@ bool PPCAsmParser::ParseOperand(OperandVector &Operands) {
case AsmToken::Percent:
Parser.Lex(); // Eat the '%'.
unsigned RegNo;
- if (MatchRegisterName(Parser.getTok(), RegNo, IntVal))
+ if (MatchRegisterName(RegNo, IntVal))
return Error(S, "invalid register name");
- Parser.Lex(); // Eat the identifier token.
break;
case AsmToken::Integer:
- if (!isDarwin()) {
- if (getParser().parseAbsoluteExpression(IntVal) ||
- IntVal < 0 || IntVal > 31)
- return Error(S, "invalid register number");
- } else {
+ if (isDarwin())
return Error(S, "unexpected integer value");
- }
+ else if (getParser().parseAbsoluteExpression(IntVal) || IntVal < 0 ||
+ IntVal > 31)
+ return Error(S, "invalid register number");
break;
-
case AsmToken::Identifier:
if (isDarwin()) {
unsigned RegNo;
- if (!MatchRegisterName(Parser.getTok(), RegNo, IntVal)) {
- Parser.Lex(); // Eat the identifier token.
+ if (!MatchRegisterName(RegNo, IntVal)) {
break;
}
}
- // Fall-through..
+ LLVM_FALLTHROUGH;
default:
return Error(S, "invalid memory operand");
}
- if (getLexer().isNot(AsmToken::RParen))
- return Error(Parser.getTok().getLoc(), "missing ')'");
E = Parser.getTok().getLoc();
- Parser.Lex(); // Eat the ')'.
-
+ if (parseToken(AsmToken::RParen, "missing ')'"))
+ return true;
Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64()));
}
@@ -1668,14 +1677,12 @@ bool PPCAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
// If the next character is a '+' or '-', we need to add it to the
// instruction name, to match what TableGen is doing.
std::string NewOpcode;
- if (getLexer().is(AsmToken::Plus)) {
- getLexer().Lex();
+ if (parseOptionalToken(AsmToken::Plus)) {
NewOpcode = Name;
NewOpcode += '+';
Name = NewOpcode;
}
- if (getLexer().is(AsmToken::Minus)) {
- getLexer().Lex();
+ if (parseOptionalToken(AsmToken::Minus)) {
NewOpcode = Name;
NewOpcode += '-';
Name = NewOpcode;
@@ -1700,20 +1707,15 @@ bool PPCAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
// If there are no more operands then finish
- if (getLexer().is(AsmToken::EndOfStatement))
+ if (parseOptionalToken(AsmToken::EndOfStatement))
return false;
// Parse the first operand
if (ParseOperand(Operands))
return true;
- while (getLexer().isNot(AsmToken::EndOfStatement) &&
- getLexer().is(AsmToken::Comma)) {
- // Consume the comma token
- Lex();
-
- // Parse the next operand
- if (ParseOperand(Operands))
+ while (!parseOptionalToken(AsmToken::EndOfStatement)) {
+ if (parseToken(AsmToken::Comma) || ParseOperand(Operands))
return true;
}
@@ -1738,108 +1740,94 @@ bool PPCAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
/// ParseDirective parses the PPC specific directives
bool PPCAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
- if (!isDarwin()) {
- if (IDVal == ".word")
- return ParseDirectiveWord(2, DirectiveID.getLoc());
- if (IDVal == ".llong")
- return ParseDirectiveWord(8, DirectiveID.getLoc());
- if (IDVal == ".tc")
- return ParseDirectiveTC(isPPC64()? 8 : 4, DirectiveID.getLoc());
+ if (isDarwin()) {
if (IDVal == ".machine")
- return ParseDirectiveMachine(DirectiveID.getLoc());
- if (IDVal == ".abiversion")
- return ParseDirectiveAbiVersion(DirectiveID.getLoc());
- if (IDVal == ".localentry")
- return ParseDirectiveLocalEntry(DirectiveID.getLoc());
- } else {
- if (IDVal == ".machine")
- return ParseDarwinDirectiveMachine(DirectiveID.getLoc());
- }
- return true;
+ ParseDarwinDirectiveMachine(DirectiveID.getLoc());
+ else
+ return true;
+ } else if (IDVal == ".word")
+ ParseDirectiveWord(2, DirectiveID);
+ else if (IDVal == ".llong")
+ ParseDirectiveWord(8, DirectiveID);
+ else if (IDVal == ".tc")
+ ParseDirectiveTC(isPPC64() ? 8 : 4, DirectiveID);
+ else if (IDVal == ".machine")
+ ParseDirectiveMachine(DirectiveID.getLoc());
+ else if (IDVal == ".abiversion")
+ ParseDirectiveAbiVersion(DirectiveID.getLoc());
+ else if (IDVal == ".localentry")
+ ParseDirectiveLocalEntry(DirectiveID.getLoc());
+ else
+ return true;
+ return false;
}
/// ParseDirectiveWord
/// ::= .word [ expression (, expression)* ]
-bool PPCAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
- MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- for (;;) {
- const MCExpr *Value;
- SMLoc ExprLoc = getLexer().getLoc();
- if (getParser().parseExpression(Value))
- return false;
-
- if (const auto *MCE = dyn_cast<MCConstantExpr>(Value)) {
- assert(Size <= 8 && "Invalid size");
- uint64_t IntValue = MCE->getValue();
- if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
- return Error(ExprLoc, "literal value out of range for directive");
- getStreamer().EmitIntValue(IntValue, Size);
- } else {
- getStreamer().EmitValue(Value, Size, ExprLoc);
- }
-
- if (getLexer().is(AsmToken::EndOfStatement))
- break;
-
- if (getLexer().isNot(AsmToken::Comma))
- return Error(L, "unexpected token in directive");
- Parser.Lex();
- }
- }
+bool PPCAsmParser::ParseDirectiveWord(unsigned Size, AsmToken ID) {
+ auto parseOp = [&]() -> bool {
+ const MCExpr *Value;
+ SMLoc ExprLoc = getParser().getTok().getLoc();
+ if (getParser().parseExpression(Value))
+ return true;
+ if (const auto *MCE = dyn_cast<MCConstantExpr>(Value)) {
+ assert(Size <= 8 && "Invalid size");
+ uint64_t IntValue = MCE->getValue();
+ if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
+ return Error(ExprLoc, "literal value out of range for '" +
+ ID.getIdentifier() + "' directive");
+ getStreamer().EmitIntValue(IntValue, Size);
+ } else
+ getStreamer().EmitValue(Value, Size, ExprLoc);
+ return false;
+ };
- Parser.Lex();
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '" + ID.getIdentifier() + "' directive");
return false;
}
/// ParseDirectiveTC
/// ::= .tc [ symbol (, expression)* ]
-bool PPCAsmParser::ParseDirectiveTC(unsigned Size, SMLoc L) {
+bool PPCAsmParser::ParseDirectiveTC(unsigned Size, AsmToken ID) {
MCAsmParser &Parser = getParser();
// Skip TC symbol, which is only used with XCOFF.
while (getLexer().isNot(AsmToken::EndOfStatement)
&& getLexer().isNot(AsmToken::Comma))
Parser.Lex();
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(L, "unexpected token in directive");
- return false;
- }
- Parser.Lex();
+ if (parseToken(AsmToken::Comma))
+ return addErrorSuffix(" in '.tc' directive");
// Align to word size.
getParser().getStreamer().EmitValueToAlignment(Size);
// Emit expressions.
- return ParseDirectiveWord(Size, L);
+ return ParseDirectiveWord(Size, ID);
}
/// ParseDirectiveMachine (ELF platforms)
/// ::= .machine [ cpu | "push" | "pop" ]
bool PPCAsmParser::ParseDirectiveMachine(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::Identifier) &&
- getLexer().isNot(AsmToken::String)) {
- Error(L, "unexpected token in directive");
- return false;
- }
+ if (Parser.getTok().isNot(AsmToken::Identifier) &&
+ Parser.getTok().isNot(AsmToken::String))
+ return Error(L, "unexpected token in '.machine' directive");
StringRef CPU = Parser.getTok().getIdentifier();
- Parser.Lex();
// FIXME: Right now, the parser always allows any available
// instruction, so the .machine directive is not useful.
// Implement ".machine any" (by doing nothing) for the benefit
// of existing assembler code. Likewise, we can then implement
// ".machine push" and ".machine pop" as no-op.
- if (CPU != "any" && CPU != "push" && CPU != "pop") {
- Error(L, "unrecognized machine type");
- return false;
- }
+ if (CPU != "any" && CPU != "push" && CPU != "pop")
+ return TokError("unrecognized machine type");
+
+ Parser.Lex();
+
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.machine' directive");
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(L, "unexpected token in directive");
- return false;
- }
PPCTargetStreamer &TStreamer =
*static_cast<PPCTargetStreamer *>(
getParser().getStreamer().getTargetStreamer());
@@ -1852,11 +1840,9 @@ bool PPCAsmParser::ParseDirectiveMachine(SMLoc L) {
/// ::= .machine cpu-identifier
bool PPCAsmParser::ParseDarwinDirectiveMachine(SMLoc L) {
MCAsmParser &Parser = getParser();
- if (getLexer().isNot(AsmToken::Identifier) &&
- getLexer().isNot(AsmToken::String)) {
- Error(L, "unexpected token in directive");
- return false;
- }
+ if (Parser.getTok().isNot(AsmToken::Identifier) &&
+ Parser.getTok().isNot(AsmToken::String))
+ return Error(L, "unexpected token in directive");
StringRef CPU = Parser.getTok().getIdentifier();
Parser.Lex();
@@ -1864,25 +1850,14 @@ bool PPCAsmParser::ParseDarwinDirectiveMachine(SMLoc L) {
// FIXME: this is only the 'default' set of cpu variants.
// However we don't act on this information at present, this is simply
// allowing parsing to proceed with minimal sanity checking.
- if (CPU != "ppc7400" && CPU != "ppc" && CPU != "ppc64") {
- Error(L, "unrecognized cpu type");
- return false;
- }
-
- if (isPPC64() && (CPU == "ppc7400" || CPU == "ppc")) {
- Error(L, "wrong cpu type specified for 64bit");
- return false;
- }
- if (!isPPC64() && CPU == "ppc64") {
- Error(L, "wrong cpu type specified for 32bit");
- return false;
- }
-
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(L, "unexpected token in directive");
- return false;
- }
-
+ if (check(CPU != "ppc7400" && CPU != "ppc" && CPU != "ppc64", L,
+ "unrecognized cpu type") ||
+ check(isPPC64() && (CPU == "ppc7400" || CPU == "ppc"), L,
+ "wrong cpu type specified for 64bit") ||
+ check(!isPPC64() && CPU == "ppc64", L,
+ "wrong cpu type specified for 32bit") ||
+ parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.machine' directive");
return false;
}
@@ -1890,14 +1865,10 @@ bool PPCAsmParser::ParseDarwinDirectiveMachine(SMLoc L) {
/// ::= .abiversion constant-expression
bool PPCAsmParser::ParseDirectiveAbiVersion(SMLoc L) {
int64_t AbiVersion;
- if (getParser().parseAbsoluteExpression(AbiVersion)){
- Error(L, "expected constant expression");
- return false;
- }
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(L, "unexpected token in directive");
- return false;
- }
+ if (check(getParser().parseAbsoluteExpression(AbiVersion), L,
+ "expected constant expression") ||
+ parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.abiversion' directive");
PPCTargetStreamer &TStreamer =
*static_cast<PPCTargetStreamer *>(
@@ -1911,28 +1882,16 @@ bool PPCAsmParser::ParseDirectiveAbiVersion(SMLoc L) {
/// ::= .localentry symbol, expression
bool PPCAsmParser::ParseDirectiveLocalEntry(SMLoc L) {
StringRef Name;
- if (getParser().parseIdentifier(Name)) {
- Error(L, "expected identifier in directive");
- return false;
- }
- MCSymbolELF *Sym = cast<MCSymbolELF>(getContext().getOrCreateSymbol(Name));
-
- if (getLexer().isNot(AsmToken::Comma)) {
- Error(L, "unexpected token in directive");
- return false;
- }
- Lex();
+ if (getParser().parseIdentifier(Name))
+ return Error(L, "expected identifier in '.localentry' directive");
+ MCSymbolELF *Sym = cast<MCSymbolELF>(getContext().getOrCreateSymbol(Name));
const MCExpr *Expr;
- if (getParser().parseExpression(Expr)) {
- Error(L, "expected expression");
- return false;
- }
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- Error(L, "unexpected token in directive");
- return false;
- }
+ if (parseToken(AsmToken::Comma) ||
+ check(getParser().parseExpression(Expr), L, "expected expression") ||
+ parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.localentry' directive");
PPCTargetStreamer &TStreamer =
*static_cast<PPCTargetStreamer *>(
@@ -1946,9 +1905,9 @@ bool PPCAsmParser::ParseDirectiveLocalEntry(SMLoc L) {
/// Force static initialization.
extern "C" void LLVMInitializePowerPCAsmParser() {
- RegisterMCAsmParser<PPCAsmParser> A(ThePPC32Target);
- RegisterMCAsmParser<PPCAsmParser> B(ThePPC64Target);
- RegisterMCAsmParser<PPCAsmParser> C(ThePPC64LETarget);
+ RegisterMCAsmParser<PPCAsmParser> A(getThePPC32Target());
+ RegisterMCAsmParser<PPCAsmParser> B(getThePPC64Target());
+ RegisterMCAsmParser<PPCAsmParser> C(getThePPC64LETarget());
}
#define GET_REGISTER_MATCHER
diff --git a/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp b/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
index 6ea4fb1..12ffbfd 100644
--- a/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
@@ -51,11 +51,11 @@ static MCDisassembler *createPPCLEDisassembler(const Target &T,
extern "C" void LLVMInitializePowerPCDisassembler() {
// Register the disassembler for each target.
- TargetRegistry::RegisterMCDisassembler(ThePPC32Target,
+ TargetRegistry::RegisterMCDisassembler(getThePPC32Target(),
createPPCDisassembler);
- TargetRegistry::RegisterMCDisassembler(ThePPC64Target,
+ TargetRegistry::RegisterMCDisassembler(getThePPC64Target(),
createPPCDisassembler);
- TargetRegistry::RegisterMCDisassembler(ThePPC64LETarget,
+ TargetRegistry::RegisterMCDisassembler(getThePPC64LETarget(),
createPPCLEDisassembler);
}
@@ -89,6 +89,17 @@ static const unsigned FRegs[] = {
PPC::F28, PPC::F29, PPC::F30, PPC::F31
};
+static const unsigned VFRegs[] = {
+ PPC::VF0, PPC::VF1, PPC::VF2, PPC::VF3,
+ PPC::VF4, PPC::VF5, PPC::VF6, PPC::VF7,
+ PPC::VF8, PPC::VF9, PPC::VF10, PPC::VF11,
+ PPC::VF12, PPC::VF13, PPC::VF14, PPC::VF15,
+ PPC::VF16, PPC::VF17, PPC::VF18, PPC::VF19,
+ PPC::VF20, PPC::VF21, PPC::VF22, PPC::VF23,
+ PPC::VF24, PPC::VF25, PPC::VF26, PPC::VF27,
+ PPC::VF28, PPC::VF29, PPC::VF30, PPC::VF31
+};
+
static const unsigned VRegs[] = {
PPC::V0, PPC::V1, PPC::V2, PPC::V3,
PPC::V4, PPC::V5, PPC::V6, PPC::V7,
@@ -110,14 +121,14 @@ static const unsigned VSRegs[] = {
PPC::VSL24, PPC::VSL25, PPC::VSL26, PPC::VSL27,
PPC::VSL28, PPC::VSL29, PPC::VSL30, PPC::VSL31,
- PPC::VSH0, PPC::VSH1, PPC::VSH2, PPC::VSH3,
- PPC::VSH4, PPC::VSH5, PPC::VSH6, PPC::VSH7,
- PPC::VSH8, PPC::VSH9, PPC::VSH10, PPC::VSH11,
- PPC::VSH12, PPC::VSH13, PPC::VSH14, PPC::VSH15,
- PPC::VSH16, PPC::VSH17, PPC::VSH18, PPC::VSH19,
- PPC::VSH20, PPC::VSH21, PPC::VSH22, PPC::VSH23,
- PPC::VSH24, PPC::VSH25, PPC::VSH26, PPC::VSH27,
- PPC::VSH28, PPC::VSH29, PPC::VSH30, PPC::VSH31
+ PPC::V0, PPC::V1, PPC::V2, PPC::V3,
+ PPC::V4, PPC::V5, PPC::V6, PPC::V7,
+ PPC::V8, PPC::V9, PPC::V10, PPC::V11,
+ PPC::V12, PPC::V13, PPC::V14, PPC::V15,
+ PPC::V16, PPC::V17, PPC::V18, PPC::V19,
+ PPC::V20, PPC::V21, PPC::V22, PPC::V23,
+ PPC::V24, PPC::V25, PPC::V26, PPC::V27,
+ PPC::V28, PPC::V29, PPC::V30, PPC::V31
};
static const unsigned VSFRegs[] = {
@@ -242,6 +253,12 @@ static DecodeStatus DecodeF8RCRegisterClass(MCInst &Inst, uint64_t RegNo,
return decodeRegisterClass(Inst, RegNo, FRegs);
}
+static DecodeStatus DecodeVFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ return decodeRegisterClass(Inst, RegNo, VFRegs);
+}
+
static DecodeStatus DecodeVRRCRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const void *Decoder) {
diff --git a/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp b/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp
index d9d9b4f1..609d959 100644
--- a/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "PPCInstPrinter.h"
+#include "PPCInstrInfo.h"
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "llvm/MC/MCExpr.h"
@@ -33,6 +34,11 @@ static cl::opt<bool>
FullRegNames("ppc-asm-full-reg-names", cl::Hidden, cl::init(false),
cl::desc("Use full register names when printing assembly"));
+// Useful for testing purposes. Prints vs{31-63} as v{0-31} respectively.
+static cl::opt<bool>
+ShowVSRNumsAsVR("ppc-vsr-nums-as-vr", cl::Hidden, cl::init(false),
+ cl::desc("Prints full register names with vs{31-63} as v{0-31}"));
+
#define PRINT_ALIAS_INSTR
#include "PPCGenAsmWriter.inc"
@@ -135,6 +141,25 @@ void PPCInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
printAnnotation(O, Annot);
return;
}
+
+ if (MI->getOpcode() == PPC::DCBF) {
+ unsigned char L = MI->getOperand(0).getImm();
+ if (!L || L == 1 || L == 3) {
+ O << "\tdcbf";
+ if (L == 1 || L == 3)
+ O << "l";
+ if (L == 3)
+ O << "p";
+ O << " ";
+
+ printOperand(MI, 1, O);
+ O << ", ";
+ printOperand(MI, 2, O);
+
+ printAnnotation(O, Annot);
+ return;
+ }
+ }
if (!printAliasInstr(MI, O))
printInstruction(MI, O);
@@ -239,6 +264,15 @@ void PPCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
printOperand(MI, OpNo+1, O);
}
+void PPCInstPrinter::printATBitsAsHint(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ unsigned Code = MI->getOperand(OpNo).getImm();
+ if (Code == 2)
+ O << "-";
+ else if (Code == 3)
+ O << "+";
+}
+
void PPCInstPrinter::printU1ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
@@ -295,10 +329,12 @@ void PPCInstPrinter::printU7ImmOperand(const MCInst *MI, unsigned OpNo,
O << (unsigned int)Value;
}
+// Operands of BUILD_VECTOR are signed and we use this to print operands
+// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and
+// print as unsigned.
void PPCInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
- unsigned int Value = MI->getOperand(OpNo).getImm();
- assert(Value <= 255 && "Invalid u8imm argument!");
+ unsigned char Value = MI->getOperand(OpNo).getImm();
O << (unsigned int)Value;
}
@@ -412,7 +448,7 @@ void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
/// stripRegisterPrefix - This method strips the character prefix from a
/// register name so that only the number is left. Used by for linux asm.
static const char *stripRegisterPrefix(const char *RegName) {
- if (FullRegNames)
+ if (FullRegNames || ShowVSRNumsAsVR)
return RegName;
switch (RegName[0]) {
@@ -433,7 +469,24 @@ void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg()) {
- const char *RegName = getRegisterName(Op.getReg());
+ unsigned Reg = Op.getReg();
+
+ // There are VSX instructions that use VSX register numbering (vs0 - vs63)
+ // as well as those that use VMX register numbering (v0 - v31 which
+ // correspond to vs32 - vs63). If we have an instruction that uses VSX
+ // numbering, we need to convert the VMX registers to VSX registers.
+ // Namely, we print 32-63 when the instruction operates on one of the
+ // VMX registers.
+ // (Please synchronize with PPCAsmPrinter::printOperand)
+ if ((MII.get(MI->getOpcode()).TSFlags & PPCII::UseVSXReg) &&
+ !ShowVSRNumsAsVR) {
+ if (PPCInstrInfo::isVRRegister(Reg))
+ Reg = PPC::VSX32 + (Reg - PPC::V0);
+ else if (PPCInstrInfo::isVFRegister(Reg))
+ Reg = PPC::VSX32 + (Reg - PPC::VF0);
+ }
+
+ const char *RegName = getRegisterName(Reg);
// The linux and AIX assembler does not take register prefixes.
if (!isDarwinSyntax())
RegName = stripRegisterPrefix(RegName);
diff --git a/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h b/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h
index d0ffeff..9c79ffb 100644
--- a/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h
+++ b/contrib/llvm/lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h
@@ -45,6 +45,7 @@ public:
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printPredicateOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O, const char *Modifier = nullptr);
+ void printATBitsAsHint(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU1ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printU2ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
diff --git a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
index 9100ecb..5847b3a 100644
--- a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
@@ -230,7 +230,8 @@ namespace {
MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
if (TT.isOSDarwin())
return new DarwinPPCAsmBackend(T);
diff --git a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
index e7b2d83..017d21a 100644
--- a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "PPCInstrInfo.h"
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "MCTargetDesc/PPCFixupKinds.h"
#include "llvm/ADT/Statistic.h"
@@ -105,6 +106,9 @@ public:
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
unsigned Opcode = MI.getOpcode();
const MCInstrDesc &Desc = MCII.get(Opcode);
@@ -138,7 +142,11 @@ public:
++MCNumEmitted; // Keep track of the # of mi's emitted.
}
-
+
+private:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
};
} // end anonymous namespace
@@ -350,7 +358,6 @@ get_crbitm_encoding(const MCInst &MI, unsigned OpNo,
return 0x80 >> CTX.getRegisterInfo()->getEncodingValue(MO.getReg());
}
-
unsigned PPCMCCodeEmitter::
getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
@@ -361,7 +368,14 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO,
assert((MI.getOpcode() != PPC::MTOCRF && MI.getOpcode() != PPC::MTOCRF8 &&
MI.getOpcode() != PPC::MFOCRF && MI.getOpcode() != PPC::MFOCRF8) ||
MO.getReg() < PPC::CR0 || MO.getReg() > PPC::CR7);
- return CTX.getRegisterInfo()->getEncodingValue(MO.getReg());
+ unsigned Reg = MO.getReg();
+ unsigned Encode = CTX.getRegisterInfo()->getEncodingValue(Reg);
+
+ if ((MCII.get(MI.getOpcode()).TSFlags & PPCII::UseVSXReg))
+ if (PPCInstrInfo::isVRRegister(Reg))
+ Encode += 32;
+
+ return Encode;
}
assert(MO.isImm() &&
@@ -370,4 +384,6 @@ getMachineOpValue(const MCInst &MI, const MCOperand &MO,
}
+
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "PPCGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
index c907444..bbd10e5 100644
--- a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
@@ -228,7 +228,8 @@ static MCInstPrinter *createPPCMCInstPrinter(const Triple &T,
}
extern "C" void LLVMInitializePowerPCTargetMC() {
- for (Target *T : {&ThePPC32Target, &ThePPC64Target, &ThePPC64LETarget}) {
+ for (Target *T :
+ {&getThePPC32Target(), &getThePPC64Target(), &getThePPC64LETarget()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn C(*T, createPPCMCAsmInfo);
diff --git a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
index 77fe458..0989e0c 100644
--- a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
@@ -28,22 +28,24 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
class Target;
class Triple;
class StringRef;
class raw_pwrite_stream;
class raw_ostream;
-extern Target ThePPC32Target;
-extern Target ThePPC64Target;
-extern Target ThePPC64LETarget;
+Target &getThePPC32Target();
+Target &getThePPC64Target();
+Target &getThePPC64LETarget();
MCCodeEmitter *createPPCMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx);
MCAsmBackend *createPPCAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
/// Construct an PPC ELF object writer.
MCObjectWriter *createPPCELFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit,
diff --git a/contrib/llvm/lib/Target/PowerPC/P9InstrResources.td b/contrib/llvm/lib/Target/PowerPC/P9InstrResources.td
new file mode 100644
index 0000000..aea022f
--- /dev/null
+++ b/contrib/llvm/lib/Target/PowerPC/P9InstrResources.td
@@ -0,0 +1,808 @@
+//===- P9InstrResources.td - P9 Instruction Resource Defs -*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines resources required by some of P9 instruction. This is part
+// P9 processor model used for instruction scheduling. Not every instruction
+// is listed here. Instructions in this file belong to itinerary classes that
+// have instructions with different resource requirements.
+//
+//===----------------------------------------------------------------------===//
+
+
+def : InstRW<[P9_ALUE_2C, P9_ALUO_2C, IP_EXECE_1C, IP_EXECO_1C,
+ DISP_1C, DISP_1C],
+ (instrs
+ VADDCUW,
+ VADDUBM,
+ VADDUDM,
+ VADDUHM,
+ VADDUWM,
+ VAND,
+ VANDC,
+ VCMPEQUB,
+ VCMPEQUBo,
+ VCMPEQUD,
+ VCMPEQUDo,
+ VCMPEQUH,
+ VCMPEQUHo,
+ VCMPEQUW,
+ VCMPEQUWo,
+ VCMPGTSB,
+ VCMPGTSBo,
+ VCMPGTSD,
+ VCMPGTSDo,
+ VCMPGTSH,
+ VCMPGTSHo,
+ VCMPGTSW,
+ VCMPGTSWo,
+ VCMPGTUB,
+ VCMPGTUBo,
+ VCMPGTUD,
+ VCMPGTUDo,
+ VCMPGTUH,
+ VCMPGTUHo,
+ VCMPGTUW,
+ VCMPGTUWo,
+ VCMPNEB,
+ VCMPNEBo,
+ VCMPNEH,
+ VCMPNEHo,
+ VCMPNEW,
+ VCMPNEWo,
+ VCMPNEZB,
+ VCMPNEZBo,
+ VCMPNEZH,
+ VCMPNEZHo,
+ VCMPNEZW,
+ VCMPNEZWo,
+ VEQV,
+ VEXTSB2D,
+ VEXTSB2W,
+ VEXTSH2D,
+ VEXTSH2W,
+ VEXTSW2D,
+ VMRGEW,
+ VMRGOW,
+ VNAND,
+ VNEGD,
+ VNEGW,
+ VNOR,
+ VOR,
+ VORC,
+ VPOPCNTB,
+ VPOPCNTH,
+ VPOPCNTW,
+ VSEL,
+ VSUBCUW,
+ VSUBUBM,
+ VSUBUDM,
+ VSUBUHM,
+ VSUBUWM,
+ VXOR,
+ V_SET0B,
+ V_SET0H,
+ V_SET0,
+ XVABSDP,
+ XVABSSP,
+ XVCPSGNDP,
+ XVCPSGNSP,
+ XVIEXPDP,
+ XVNABSDP,
+ XVNABSSP,
+ XVNEGDP,
+ XVNEGSP,
+ XVXEXPDP,
+ XXLAND,
+ XXLANDC,
+ XXLEQV,
+ XXLNAND,
+ XXLNOR,
+ XXLOR,
+ XXLORf,
+ XXLORC,
+ XXLXOR,
+ XXSEL
+)>;
+
+def : InstRW<[P9_ALU_2C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSABSQP,
+ XSCPSGNQP,
+ XSIEXPQP,
+ XSNABSQP,
+ XSNEGQP,
+ XSXEXPQP,
+ XSABSDP,
+ XSCPSGNDP,
+ XSIEXPDP,
+ XSNABSDP,
+ XSNEGDP,
+ XSXEXPDP
+)>;
+
+def : InstRW<[P9_ALUE_3C, P9_ALUO_3C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+
+ VMINSB,
+ VMINSD,
+ VMINSH,
+ VMINSW,
+ VMINUB,
+ VMINUD,
+ VMINUH,
+ VMINUW,
+ VPOPCNTD,
+ VPRTYBD,
+ VPRTYBW,
+ VRLB,
+ VRLD,
+ VRLDMI,
+ VRLDNM,
+ VRLH,
+ VRLW,
+ VRLWMI,
+ VRLWNM,
+ VSHASIGMAD,
+ VSHASIGMAW,
+ VSLB,
+ VSLD,
+ VSLH,
+ VSLW,
+ VSRAB,
+ VSRAD,
+ VSRAH,
+ VSRAW,
+ VSRB,
+ VSRD,
+ VSRH,
+ VSRW,
+ VSUBSBS,
+ VSUBSHS,
+ VSUBSWS,
+ VSUBUBS,
+ VSUBUHS,
+ VSUBUWS,
+ XSCMPEQDP,
+ XSCMPEXPDP,
+ XSCMPGEDP,
+ XSCMPGTDP,
+ XSCMPODP,
+ XSCMPUDP,
+ XSCVSPDPN,
+ XSMAXCDP,
+ XSMAXDP,
+ XSMAXJDP,
+ XSMINCDP,
+ XSMINDP,
+ XSMINJDP,
+ XSTDIVDP,
+ XSTSQRTDP,
+ XSTSTDCDP,
+ XSTSTDCSP,
+ XSXSIGDP,
+ XVCMPEQDP,
+ XVCMPEQDPo,
+ XVCMPEQSP,
+ XVCMPEQSPo,
+ XVCMPGEDP,
+ XVCMPGEDPo,
+ XVCMPGESP,
+ XVCMPGESPo,
+ XVCMPGTDP,
+ XVCMPGTDPo,
+ XVCMPGTSP,
+ XVCMPGTSPo,
+ XVIEXPSP,
+ XVMAXDP,
+ XVMAXSP,
+ XVMINDP,
+ XVMINSP,
+ XVTDIVDP,
+ XVTDIVSP,
+ XVTSQRTDP,
+ XVTSQRTSP,
+ XVTSTDCDP,
+ XVTSTDCSP,
+ XVXEXPSP,
+ XVXSIGDP,
+ XVXSIGSP
+)>;
+
+def : InstRW<[P9_ALUE_4C, P9_ALUO_4C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ VABSDUB,
+ VABSDUH,
+ VABSDUW,
+ VADDSBS,
+ VADDSHS,
+ VADDSWS,
+ VADDUBS,
+ VADDUHS,
+ VADDUWS,
+ VAVGSB,
+ VAVGSH,
+ VAVGSW,
+ VAVGUB,
+ VAVGUH,
+ VAVGUW,
+ VBPERMD,
+ VCLZB,
+ VCLZD,
+ VCLZH,
+ VCLZW,
+ VCMPBFP,
+ VCMPBFPo,
+ VCMPGTFP,
+ VCMPGTFPo,
+ VCTZB,
+ VCTZD,
+ VCTZH,
+ VCTZW,
+ VMAXFP,
+ VMAXSB,
+ VMAXSD,
+ VMAXSH,
+ VMAXSW,
+ VMAXUB,
+ VMAXUD,
+ VMAXUH,
+ VMAXUW,
+ VMINFP,
+ VCMPEQFP,
+ VCMPEQFPo,
+ VCMPGEFP,
+ VCMPGEFPo
+)>;
+
+def : InstRW<[P9_DPE_7C, P9_DPO_7C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ VADDFP,
+ VCTSXS,
+ VCTSXS_0,
+ VCTUXS,
+ VCTUXS_0,
+ VEXPTEFP,
+ VLOGEFP,
+ VMADDFP,
+ VMHADDSHS,
+ VNMSUBFP,
+ VREFP,
+ VRFIM,
+ VRFIN,
+ VRFIP,
+ VRFIZ,
+ VRSQRTEFP,
+ VSUBFP,
+ XVADDDP,
+ XVADDSP,
+ XVCVDPSP,
+ XVCVDPSXDS,
+ XVCVDPSXWS,
+ XVCVDPUXDS,
+ XVCVDPUXWS,
+ XVCVHPSP,
+ XVCVSPDP,
+ XVCVSPHP,
+ XVCVSPSXDS,
+ XVCVSPSXWS,
+ XVCVSPUXDS,
+ XVCVSPUXWS,
+ XVCVSXDDP,
+ XVCVSXDSP,
+ XVCVSXWDP,
+ XVCVSXWSP,
+ XVCVUXDDP,
+ XVCVUXDSP,
+ XVCVUXWDP,
+ XVCVUXWSP,
+ XVMADDADP,
+ XVMADDASP,
+ XVMADDMDP,
+ XVMADDMSP,
+ XVMSUBADP,
+ XVMSUBASP,
+ XVMSUBMDP,
+ XVMSUBMSP,
+ XVMULDP,
+ XVMULSP,
+ XVNMADDADP,
+ XVNMADDASP,
+ XVNMADDMDP,
+ XVNMADDMSP,
+ XVNMSUBADP,
+ XVNMSUBASP,
+ XVNMSUBMDP,
+ XVNMSUBMSP,
+ XVRDPI,
+ XVRDPIC,
+ XVRDPIM,
+ XVRDPIP,
+ XVRDPIZ,
+ XVREDP,
+ XVRESP,
+ XVRSPI,
+ XVRSPIC,
+ XVRSPIM,
+ XVRSPIP,
+ XVRSPIZ,
+ XVRSQRTEDP,
+ XVRSQRTESP,
+ XVSUBDP,
+ XVSUBSP,
+ VCFSX,
+ VCFSX_0,
+ VCFUX,
+ VCFUX_0,
+ VMHRADDSHS,
+ VMLADDUHM,
+ VMSUMMBM,
+ VMSUMSHM,
+ VMSUMSHS,
+ VMSUMUBM,
+ VMSUMUHM,
+ VMSUMUHS,
+ VMULESB,
+ VMULESH,
+ VMULESW,
+ VMULEUB,
+ VMULEUH,
+ VMULEUW,
+ VMULOSB,
+ VMULOSH,
+ VMULOSW,
+ VMULOUB,
+ VMULOUH,
+ VMULOUW,
+ VMULUWM,
+ VSUM2SWS,
+ VSUM4SBS,
+ VSUM4SHS,
+ VSUM4UBS,
+ VSUMSWS
+)>;
+
+def : InstRW<[P9_DP_7C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSMADDADP,
+ XSMADDASP,
+ XSMADDMDP,
+ XSMADDMSP,
+ XSMSUBADP,
+ XSMSUBASP,
+ XSMSUBMDP,
+ XSMSUBMSP,
+ XSMULDP,
+ XSMULSP,
+ XSNMADDADP,
+ XSNMADDASP,
+ XSNMADDMDP,
+ XSNMADDMSP,
+ XSNMSUBADP,
+ XSNMSUBASP,
+ XSNMSUBMDP,
+ XSNMSUBMSP
+)>;
+
+
+def : InstRW<[P9_DP_7C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSADDDP,
+ XSADDSP,
+ XSCVDPHP,
+ XSCVDPSP,
+ XSCVDPSXDS,
+ XSCVDPSXWS,
+ XSCVDPUXDS,
+ XSCVDPUXWS,
+ XSCVHPDP,
+ XSCVSPDP,
+ XSCVSXDDP,
+ XSCVSXDSP,
+ XSCVUXDDP,
+ XSCVUXDSP,
+ XSRDPI,
+ XSRDPIC,
+ XSRDPIM,
+ XSRDPIP,
+ XSRDPIZ,
+ XSREDP,
+ XSRESP,
+ //XSRSP,
+ XSRSQRTEDP,
+ XSRSQRTESP,
+ XSSUBDP,
+ XSSUBSP,
+ XSCVDPSPN
+)>;
+
+def : InstRW<[P9_PM_3C, IP_EXECO_1C, IP_EXECE_1C, DISP_1C, DISP_1C],
+ (instrs
+ VBPERMQ,
+ VCLZLSBB,
+ VCTZLSBB,
+ VEXTRACTD,
+ VEXTRACTUB,
+ VEXTRACTUH,
+ VEXTRACTUW,
+ VEXTUBLX,
+ VEXTUBRX,
+ VEXTUHLX,
+ VEXTUHRX,
+ VEXTUWLX,
+ VEXTUWRX,
+ VGBBD,
+ VINSERTB,
+ VINSERTD,
+ VINSERTH,
+ VINSERTW,
+ VMRGHB,
+ VMRGHH,
+ VMRGHW,
+ VMRGLB,
+ VMRGLH,
+ VMRGLW,
+ VPERM,
+ VPERMR,
+ VPERMXOR,
+ VPKPX,
+ VPKSDSS,
+ VPKSDUS,
+ VPKSHSS,
+ VPKSHUS,
+ VPKSWSS,
+ VPKSWUS,
+ VPKUDUM,
+ VPKUDUS,
+ VPKUHUM,
+ VPKUHUS,
+ VPKUWUM,
+ VPKUWUS,
+ VPRTYBQ,
+ VSL,
+ VSLDOI,
+ VSLO,
+ VSLV,
+ VSPLTB,
+ VSPLTH,
+ VSPLTISB,
+ VSPLTISH,
+ VSPLTISW,
+ VSPLTW,
+ VSR,
+ VSRO,
+ VSRV,
+ VUPKHPX,
+ VUPKHSB,
+ VUPKHSH,
+ VUPKHSW,
+ VUPKLPX,
+ VUPKLSB,
+ VUPKLSH,
+ VUPKLSW,
+ XXBRD,
+ XXBRH,
+ XXBRQ,
+ XXBRW,
+ XXEXTRACTUW,
+ XXINSERTW,
+ XXMRGHW,
+ XXMRGLW,
+ XXPERM,
+ XXPERMR,
+ XXSLDWI,
+ XXSPLTIB,
+ XXSPLTW,
+ VADDCUQ,
+ VADDECUQ,
+ VADDEUQM,
+ VADDUQM,
+ VMUL10CUQ,
+ VMUL10ECUQ,
+ VMUL10EUQ,
+ VMUL10UQ,
+ VSUBCUQ,
+ VSUBECUQ,
+ VSUBEUQM,
+ VSUBUQM,
+ XSCMPEXPQP,
+ XSCMPOQP,
+ XSCMPUQP,
+ XSTSTDCQP,
+ XSXSIGQP
+)>;
+
+def : InstRW<[P9_DFU_12C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSADDQP,
+ XSADDQPO,
+ XSCVDPQP,
+ XSCVQPDP,
+ XSCVQPDPO,
+ XSCVQPSDZ,
+ XSCVQPSWZ,
+ XSCVQPUDZ,
+ XSCVQPUWZ,
+ XSCVSDQP,
+ XSCVUDQP,
+ XSRQPI,
+ XSRQPXP,
+ XSSUBQP,
+ XSSUBQPO
+)>;
+
+def : InstRW<[P9_DFU_24C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSMADDQP,
+ XSMADDQPO,
+ XSMSUBQP,
+ XSMSUBQPO,
+ XSMULQP,
+ XSMULQPO,
+ XSNMADDQP,
+ XSNMADDQPO,
+ XSNMSUBQP,
+ XSNMSUBQPO
+)>;
+
+def : InstRW<[P9_DFU_58C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSDIVQP,
+ XSDIVQPO
+)>;
+
+def : InstRW<[P9_DFU_76C, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ XSSQRTQP,
+ XSSQRTQPO
+)>;
+
+// Load Operation in IIC_LdStLFD
+
+def : InstRW<[P9_LS_5C, IP_AGEN_1C, DISP_1C, DISP_1C],
+ (instrs
+ LXSDX,
+ LXVD2X,
+ LXSIWZX,
+ LXV,
+ LXSD
+)>;
+
+def : InstRW<[P9_LS_5C, IP_AGEN_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ LFIWZX,
+ LFDX,
+ LFD
+)>;
+
+def : InstRW<[P9_LoadAndALUOp_7C, IP_AGEN_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ LXSSPX,
+ LXSIWAX,
+ LXSSP
+)>;
+
+def : InstRW<[P9_LoadAndALUOp_7C, IP_AGEN_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ LFIWAX,
+ LFSX,
+ LFS
+)>;
+
+def : InstRW<[P9_LoadAndPMOp_8C, IP_AGEN_1C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ (instrs
+ LXVDSX,
+ LXVW4X
+)>;
+
+// Store Operations in IIC_LdStSTFD.
+
+def : InstRW<[P9_LS_1C, IP_EXEC_1C, IP_AGEN_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ STFS,
+ STFD,
+ STFIWX,
+ STFSX,
+ STFDX,
+ STXSDX,
+ STXSSPX,
+ STXSIWX
+)>;
+
+def : InstRW<[P9_LS_1C, IP_EXEC_1C, IP_EXEC_1C, IP_AGEN_1C, DISP_1C, DISP_1C],
+ (instrs
+ STXVD2X,
+ STXVW4X
+)>;
+
+
+// Divide Operations in IIC_IntDivW, IIC_IntDivD.
+
+def : InstRW<[P9_DIV_16C_8, IP_EXECE_1C, DISP_1C, DISP_1C],
+ (instrs
+ DIVW,
+ DIVWU
+)>;
+
+def : InstRW<[P9_DIV_24C_8, IP_EXECE_1C, DISP_1C, DISP_1C],
+ (instrs
+ DIVWE,
+ DIVD,
+ DIVWEU,
+ DIVDU
+)>;
+
+def : InstRW<[P9_DIV_40C_8, IP_EXECE_1C, DISP_1C, DISP_1C],
+ (instrs
+ DIVDE,
+ DIVDEU
+)>;
+
+def : InstRW<[P9_IntDivAndALUOp_26C_8, IP_EXECE_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ DIVWEo,
+ DIVWEUo
+)>;
+
+def : InstRW<[P9_IntDivAndALUOp_42C_8, IP_EXECE_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ DIVDEo,
+ DIVDEUo
+)>;
+
+// Rotate Operations in IIC_IntRotateD, IIC_IntRotateDI
+def : InstRW<[P9_ALU_2C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ (instrs
+ SLD,
+ SRD,
+ SRAD,
+ SRADI,
+ RLDIC
+)>;
+
+def : InstRW<[P9_ALU_2C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ RLDCL,
+ RLDCR,
+ RLDIMI,
+ RLDICL,
+ RLDICR,
+ RLDICL_32_64
+)>;
+
+// CR access instructions in _BrMCR, IIC_BrMCRX.
+
+def : InstRW<[P9_ALU_2C, P9_ALU_2C, IP_EXEC_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ MTOCRF,
+ MTOCRF8,
+ MTCRF,
+ MTCRF8
+)>;
+
+def : InstRW<[P9_ALU_5C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ (instrs
+ MCRF,
+ MCRXRX
+)>;
+
+def : InstRW<[P9_ALU_5C, P9_ALU_5C, IP_EXEC_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ MCRFS
+)>;
+
+// FP Div instructions in IIC_FPDivD and IIC_FPDivS.
+
+def : InstRW<[P9_DP_33C_8, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ FDIV,
+ XSDIVDP
+)>;
+
+def : InstRW<[P9_DP_22C_5, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ FDIVS,
+ XSDIVSP
+)>;
+
+def : InstRW<[P9_DP_24C_8, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ XVDIVSP
+)>;
+
+def : InstRW<[P9_DP_33C_8, IP_EXECE_1C, IP_EXECO_1C, DISP_1C, DISP_1C],
+ (instrs
+ XVDIVDP
+)>;
+
+// FP Instructions in IIC_FPGeneral, IIC_FPFused
+
+def : InstRW<[P9_DP_7C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ FRSP,
+ FRIND,
+ FRINS,
+ FRIPD,
+ FRIPS,
+ FRIZD,
+ FRIZS,
+ FRIMD,
+ FRIMS,
+ FRE,
+ FRES,
+ FRSQRTE,
+ FRSQRTES,
+ FMADDS,
+ FMADD,
+ FMSUBS,
+ FMSUB,
+ FNMADDS,
+ FNMADD,
+ FNMSUBS,
+ FNMSUB,
+ FSELD,
+ FSELS,
+ FADDS,
+ FMULS,
+ FMUL,
+ FSUBS,
+ FCFID,
+ FCTID,
+ FCTIDZ,
+ FCFIDU,
+ FCFIDS,
+ FCFIDUS,
+ FCTIDUZ,
+ FCTIWUZ,
+ FCTIW,
+ FCTIWZ
+)>;
+
+def : InstRW<[P9_DP_7C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ FMR,
+ FABSD,
+ FABSS,
+ FNABSD,
+ FNABSS,
+ FNEGD,
+ FNEGS,
+ FCPSGND,
+ FCPSGNS
+)>;
+
+def : InstRW<[P9_ALU_3C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ FCMPUS,
+ FCMPUD
+)>;
+
+// Load instructions in IIC_LdStLFDU and IIC_LdStLFDUX.
+
+def : InstRW<[P9_LoadAndALUOp_7C, P9_ALU_2C,
+ IP_AGEN_1C, IP_EXEC_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ LFSU,
+ LFSUX
+)>;
+
+def : InstRW<[P9_LS_5C, P9_ALU_2C, IP_AGEN_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ (instrs
+ LFDU,
+ LFDUX
+)>;
+
diff --git a/contrib/llvm/lib/Target/PowerPC/PPC.td b/contrib/llvm/lib/Target/PowerPC/PPC.td
index 6a8e87e..4650220 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPC.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPC.td
@@ -216,7 +216,7 @@ def ProcessorFeatures {
list<SubtargetFeature> Power8FeatureList =
!listconcat(Power7FeatureList, Power8SpecificFeatures);
list<SubtargetFeature> Power9SpecificFeatures =
- [FeatureP9Altivec, FeatureP9Vector, FeatureISA3_0];
+ [DirectivePwr9, FeatureP9Altivec, FeatureP9Vector, FeatureISA3_0];
list<SubtargetFeature> Power9FeatureList =
!listconcat(Power8FeatureList, Power9SpecificFeatures);
}
@@ -289,7 +289,6 @@ def getAltVSXFMAOpcode : InstrMapping {
include "PPCRegisterInfo.td"
include "PPCSchedule.td"
-include "PPCInstrInfo.td"
//===----------------------------------------------------------------------===//
// PowerPC processors supported.
@@ -418,8 +417,7 @@ def : ProcessorModel<"pwr6x", G5Model,
FeatureMFTB, DeprecatedDST]>;
def : ProcessorModel<"pwr7", P7Model, ProcessorFeatures.Power7FeatureList>;
def : ProcessorModel<"pwr8", P8Model, ProcessorFeatures.Power8FeatureList>;
-// FIXME: Same as P8 until the POWER9 scheduling info is available
-def : ProcessorModel<"pwr9", P8Model, ProcessorFeatures.Power9FeatureList>;
+def : ProcessorModel<"pwr9", P9Model, ProcessorFeatures.Power9FeatureList>;
def : Processor<"ppc", G3Itineraries, [Directive32, FeatureHardFloat,
FeatureMFTB]>;
def : Processor<"ppc32", G3Itineraries, [Directive32, FeatureHardFloat,
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/contrib/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 76c52ab..f0e0ebc 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -17,28 +17,29 @@
//===----------------------------------------------------------------------===//
#include "PPC.h"
+#include "PPCInstrInfo.h"
#include "InstPrinter/PPCInstPrinter.h"
#include "MCTargetDesc/PPCMCExpr.h"
-#include "MCTargetDesc/PPCPredicates.h"
+#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
#include "PPCTargetStreamer.h"
#include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/AsmPrinter.h"
-#include "llvm/CodeGen/MachineConstantPool.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Mangler.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -48,21 +49,30 @@
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/MachO.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetOptions.h"
-#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <new>
+
using namespace llvm;
#define DEBUG_TYPE "asmprinter"
namespace {
+
class PPCAsmPrinter : public AsmPrinter {
protected:
MapVector<MCSymbol *, MCSymbol *> TOC;
@@ -74,17 +84,15 @@ public:
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)), SM(*this) {}
- const char *getPassName() const override {
- return "PowerPC Assembly Printer";
- }
+ StringRef getPassName() const override { return "PowerPC Assembly Printer"; }
- MCSymbol *lookUpOrCreateTOCEntry(MCSymbol *Sym);
+ MCSymbol *lookUpOrCreateTOCEntry(MCSymbol *Sym);
- virtual bool doInitialization(Module &M) override {
- if (!TOC.empty())
- TOC.clear();
- return AsmPrinter::doInitialization(M);
- }
+ bool doInitialization(Module &M) override {
+ if (!TOC.empty())
+ TOC.clear();
+ return AsmPrinter::doInitialization(M);
+ }
void EmitInstruction(const MachineInstr *MI) override;
@@ -115,7 +123,7 @@ public:
std::unique_ptr<MCStreamer> Streamer)
: PPCAsmPrinter(TM, std::move(Streamer)) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Linux PPC Assembly Printer";
}
@@ -136,14 +144,15 @@ public:
std::unique_ptr<MCStreamer> Streamer)
: PPCAsmPrinter(TM, std::move(Streamer)) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Darwin PPC Assembly Printer";
}
bool doFinalization(Module &M) override;
void EmitStartOfAsmFile(Module &M) override;
};
-} // end of anonymous namespace
+
+} // end anonymous namespace
/// stripRegisterPrefix - This method strips the character prefix from a
/// register name so that only the number is left. Used by for linux asm.
@@ -169,7 +178,23 @@ void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
switch (MO.getType()) {
case MachineOperand::MO_Register: {
- const char *RegName = PPCInstPrinter::getRegisterName(MO.getReg());
+ unsigned Reg = MO.getReg();
+
+ // There are VSX instructions that use VSX register numbering (vs0 - vs63)
+ // as well as those that use VMX register numbering (v0 - v31 which
+ // correspond to vs32 - vs63). If we have an instruction that uses VSX
+ // numbering, we need to convert the VMX registers to VSX registers.
+ // Namely, we print 32-63 when the instruction operates on one of the
+ // VMX registers.
+ // (Please synchronize with PPCInstPrinter::printOperand)
+ if (MI->getDesc().TSFlags & PPCII::UseVSXReg) {
+ if (PPCInstrInfo::isVRRegister(Reg))
+ Reg = PPC::VSX32 + (Reg - PPC::V0);
+ else if (PPCInstrInfo::isVFRegister(Reg))
+ Reg = PPC::VSX32 + (Reg - PPC::VF0);
+ }
+ const char *RegName = PPCInstPrinter::getRegisterName(Reg);
+
// Linux assembler (Others?) does not take register mnemonics.
// FIXME - What about special registers used in mfspr/mtspr?
if (!Subtarget->isDarwin())
@@ -347,11 +372,10 @@ void PPCAsmPrinter::LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI) {
PatchPointOpers Opers(&MI);
unsigned EncodedBytes = 0;
- const MachineOperand &CalleeMO =
- Opers.getMetaOper(PatchPointOpers::TargetPos);
+ const MachineOperand &CalleeMO = Opers.getCallTarget();
if (CalleeMO.isImm()) {
- int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm();
+ int64_t CallTarget = CalleeMO.getImm();
if (CallTarget) {
assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget &&
"High 16 bits of call target should be zero.");
@@ -430,7 +454,7 @@ void PPCAsmPrinter::LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI) {
EncodedBytes *= 4;
// Emit padding.
- unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
+ unsigned NumBytes = Opers.getNumPatchBytes();
assert(NumBytes >= EncodedBytes &&
"Patchpoint can't request size less than the length of a call.");
assert((NumBytes - EncodedBytes) % 4 == 0 &&
@@ -674,6 +698,13 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
const MCExpr *Exp =
MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_HA,
OutContext);
+
+ if (!MO.isJTI() && MO.getOffset())
+ Exp = MCBinaryExpr::createAdd(Exp,
+ MCConstantExpr::create(MO.getOffset(),
+ OutContext),
+ OutContext);
+
TmpInst.getOperand(2) = MCOperand::createExpr(Exp);
EmitToStreamer(*OutStreamer, TmpInst);
return;
@@ -1147,10 +1178,12 @@ bool PPCLinuxAsmPrinter::doFinalization(Module &M) {
E = TOC.end(); I != E; ++I) {
OutStreamer->EmitLabel(I->second);
MCSymbol *S = I->first;
- if (isPPC64)
+ if (isPPC64) {
TS.emitTCEntry(*S);
- else
+ } else {
+ OutStreamer->EmitValueToAlignment(4);
OutStreamer->EmitSymbolValue(S, 4);
+ }
}
}
@@ -1193,6 +1226,9 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() {
if (Subtarget->isELFv2ABI()
// Only do all that if the function uses r2 in the first place.
&& !MF->getRegInfo().use_empty(PPC::X2)) {
+ // Note: The logic here must be synchronized with the code in the
+ // branch-selection pass which sets the offset of the first block in the
+ // function. This matters because it affects the alignment.
const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>();
MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol();
@@ -1345,57 +1381,61 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
// Darwin/PPC always uses mach-o.
const TargetLoweringObjectFileMachO &TLOFMacho =
static_cast<const TargetLoweringObjectFileMachO &>(getObjFileLowering());
- MachineModuleInfoMachO &MMIMacho =
- MMI->getObjFileInfo<MachineModuleInfoMachO>();
-
- if (MAI->doesSupportExceptionHandling() && MMI) {
- // Add the (possibly multiple) personalities to the set of global values.
- // Only referenced functions get into the Personalities list.
- for (const Function *Personality : MMI->getPersonalities()) {
- if (Personality) {
- MCSymbol *NLPSym =
- getSymbolWithGlobalValueBase(Personality, "$non_lazy_ptr");
- MachineModuleInfoImpl::StubValueTy &StubSym =
- MMIMacho.getGVStubEntry(NLPSym);
- StubSym =
- MachineModuleInfoImpl::StubValueTy(getSymbol(Personality), true);
+ if (MMI) {
+ MachineModuleInfoMachO &MMIMacho =
+ MMI->getObjFileInfo<MachineModuleInfoMachO>();
+
+ if (MAI->doesSupportExceptionHandling()) {
+ // Add the (possibly multiple) personalities to the set of global values.
+ // Only referenced functions get into the Personalities list.
+ for (const Function *Personality : MMI->getPersonalities()) {
+ if (Personality) {
+ MCSymbol *NLPSym =
+ getSymbolWithGlobalValueBase(Personality, "$non_lazy_ptr");
+ MachineModuleInfoImpl::StubValueTy &StubSym =
+ MMIMacho.getGVStubEntry(NLPSym);
+ StubSym =
+ MachineModuleInfoImpl::StubValueTy(getSymbol(Personality), true);
+ }
}
}
- }
- // Output stubs for dynamically-linked functions.
- MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList();
-
- // Output macho stubs for external and common global variables.
- if (!Stubs.empty()) {
- // Switch with ".non_lazy_symbol_pointer" directive.
- OutStreamer->SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
- EmitAlignment(isPPC64 ? 3 : 2);
-
- for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
- // L_foo$stub:
- OutStreamer->EmitLabel(Stubs[i].first);
- // .indirect_symbol _foo
- MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second;
- OutStreamer->EmitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol);
-
- if (MCSym.getInt())
- // External to current translation unit.
- OutStreamer->EmitIntValue(0, isPPC64 ? 8 : 4/*size*/);
- else
- // Internal to current translation unit.
- //
- // When we place the LSDA into the TEXT section, the type info pointers
- // need to be indirect and pc-rel. We accomplish this by using NLPs.
- // However, sometimes the types are local to the file. So we need to
- // fill in the value for the NLP in those cases.
- OutStreamer->EmitValue(MCSymbolRefExpr::create(MCSym.getPointer(),
- OutContext),
- isPPC64 ? 8 : 4/*size*/);
- }
+ // Output stubs for dynamically-linked functions.
+ MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList();
+
+ // Output macho stubs for external and common global variables.
+ if (!Stubs.empty()) {
+ // Switch with ".non_lazy_symbol_pointer" directive.
+ OutStreamer->SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
+ EmitAlignment(isPPC64 ? 3 : 2);
+
+ for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
+ // L_foo$stub:
+ OutStreamer->EmitLabel(Stubs[i].first);
+ // .indirect_symbol _foo
+ MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second;
+ OutStreamer->EmitSymbolAttribute(MCSym.getPointer(),
+ MCSA_IndirectSymbol);
+
+ if (MCSym.getInt())
+ // External to current translation unit.
+ OutStreamer->EmitIntValue(0, isPPC64 ? 8 : 4 /*size*/);
+ else
+ // Internal to current translation unit.
+ //
+ // When we place the LSDA into the TEXT section, the type info
+ // pointers
+ // need to be indirect and pc-rel. We accomplish this by using NLPs.
+ // However, sometimes the types are local to the file. So we need to
+ // fill in the value for the NLP in those cases.
+ OutStreamer->EmitValue(
+ MCSymbolRefExpr::create(MCSym.getPointer(), OutContext),
+ isPPC64 ? 8 : 4 /*size*/);
+ }
- Stubs.clear();
- OutStreamer->AddBlankLine();
+ Stubs.clear();
+ OutStreamer->AddBlankLine();
+ }
}
// Funny Darwin hack: This flag tells the linker that no global symbols
@@ -1422,7 +1462,10 @@ createPPCAsmPrinterPass(TargetMachine &tm,
// Force static initialization.
extern "C" void LLVMInitializePowerPCAsmPrinter() {
- TargetRegistry::RegisterAsmPrinter(ThePPC32Target, createPPCAsmPrinterPass);
- TargetRegistry::RegisterAsmPrinter(ThePPC64Target, createPPCAsmPrinterPass);
- TargetRegistry::RegisterAsmPrinter(ThePPC64LETarget, createPPCAsmPrinterPass);
+ TargetRegistry::RegisterAsmPrinter(getThePPC32Target(),
+ createPPCAsmPrinterPass);
+ TargetRegistry::RegisterAsmPrinter(getThePPC64Target(),
+ createPPCAsmPrinterPass);
+ TargetRegistry::RegisterAsmPrinter(getThePPC64LETarget(),
+ createPPCAsmPrinterPass);
}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp b/contrib/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp
index bfb4d87..93c201d 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCBoolRetToInt.cpp
@@ -1,4 +1,4 @@
-//===- PPCBoolRetToInt.cpp - Convert bool literals to i32 if they are returned ==//
+//===- PPCBoolRetToInt.cpp ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -33,15 +33,26 @@
//===----------------------------------------------------------------------===//
#include "PPC.h"
-#include "llvm/Transforms/Scalar.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Argument.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/OperandTraits.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Pass.h"
+#include <cassert>
using namespace llvm;
@@ -57,7 +68,6 @@ STATISTIC(NumBoolToIntPromotion,
"Total number of times a bool was promoted to an int");
class PPCBoolRetToInt : public FunctionPass {
-
static SmallPtrSet<Value *, 8> findAllDefs(Value *V) {
SmallPtrSet<Value *, 8> Defs;
SmallVector<Value *, 8> WorkList;
@@ -66,7 +76,10 @@ class PPCBoolRetToInt : public FunctionPass {
while (!WorkList.empty()) {
Value *Curr = WorkList.back();
WorkList.pop_back();
- if (User *CurrUser = dyn_cast<User>(Curr))
+ auto *CurrUser = dyn_cast<User>(Curr);
+ // Operands of CallInst are skipped because they may not be Bool type,
+ // and their positions are defined by ABI.
+ if (CurrUser && !isa<CallInst>(Curr))
for (auto &Op : CurrUser->operands())
if (Defs.insert(Op).second)
WorkList.push_back(Op);
@@ -77,9 +90,9 @@ class PPCBoolRetToInt : public FunctionPass {
// Translate a i1 value to an equivalent i32 value:
static Value *translate(Value *V) {
Type *Int32Ty = Type::getInt32Ty(V->getContext());
- if (Constant *C = dyn_cast<Constant>(V))
+ if (auto *C = dyn_cast<Constant>(V))
return ConstantExpr::getZExt(C, Int32Ty);
- if (PHINode *P = dyn_cast<PHINode>(V)) {
+ if (auto *P = dyn_cast<PHINode>(V)) {
// Temporarily set the operands to 0. We'll fix this later in
// runOnUse.
Value *Zero = Constant::getNullValue(Int32Ty);
@@ -90,8 +103,8 @@ class PPCBoolRetToInt : public FunctionPass {
return Q;
}
- Argument *A = dyn_cast<Argument>(V);
- Instruction *I = dyn_cast<Instruction>(V);
+ auto *A = dyn_cast<Argument>(V);
+ auto *I = dyn_cast<Instruction>(V);
assert((A || I) && "Unknown value type");
auto InstPt =
@@ -114,7 +127,7 @@ class PPCBoolRetToInt : public FunctionPass {
// Condition 1
for (auto &BB : F)
for (auto &I : BB)
- if (const PHINode *P = dyn_cast<PHINode>(&I))
+ if (const auto *P = dyn_cast<PHINode>(&I))
if (P->getType()->isIntegerTy(1))
Promotable.insert(P);
@@ -131,14 +144,14 @@ class PPCBoolRetToInt : public FunctionPass {
};
const auto &Users = P->users();
const auto &Operands = P->operands();
- if (!std::all_of(Users.begin(), Users.end(), IsValidUser) ||
- !std::all_of(Operands.begin(), Operands.end(), IsValidOperand))
+ if (!llvm::all_of(Users, IsValidUser) ||
+ !llvm::all_of(Operands, IsValidOperand))
ToRemove.push_back(P);
}
// Iterate to convergence
auto IsPromotable = [&Promotable] (const Value *V) -> bool {
- const PHINode *Phi = dyn_cast<PHINode>(V);
+ const auto *Phi = dyn_cast<PHINode>(V);
return !Phi || Promotable.count(Phi);
};
while (!ToRemove.empty()) {
@@ -150,8 +163,8 @@ class PPCBoolRetToInt : public FunctionPass {
// Condition 4 and 5
const auto &Users = P->users();
const auto &Operands = P->operands();
- if (!std::all_of(Users.begin(), Users.end(), IsPromotable) ||
- !std::all_of(Operands.begin(), Operands.end(), IsPromotable))
+ if (!llvm::all_of(Users, IsPromotable) ||
+ !llvm::all_of(Operands, IsPromotable))
ToRemove.push_back(P);
}
}
@@ -163,11 +176,12 @@ class PPCBoolRetToInt : public FunctionPass {
public:
static char ID;
+
PPCBoolRetToInt() : FunctionPass(ID) {
initializePPCBoolRetToIntPass(*PassRegistry::getPassRegistry());
}
- bool runOnFunction(Function &F) {
+ bool runOnFunction(Function &F) override {
if (skipFunction(F))
return false;
@@ -176,12 +190,12 @@ class PPCBoolRetToInt : public FunctionPass {
bool Changed = false;
for (auto &BB : F) {
for (auto &I : BB) {
- if (ReturnInst *R = dyn_cast<ReturnInst>(&I))
+ if (auto *R = dyn_cast<ReturnInst>(&I))
if (F.getReturnType()->isIntegerTy(1))
Changed |=
runOnUse(R->getOperandUse(0), PromotablePHINodes, Bool2IntMap);
- if (CallInst *CI = dyn_cast<CallInst>(&I))
+ if (auto *CI = dyn_cast<CallInst>(&I))
for (auto &U : CI->operands())
if (U->getType()->isIntegerTy(1))
Changed |= runOnUse(U, PromotablePHINodes, Bool2IntMap);
@@ -196,18 +210,19 @@ class PPCBoolRetToInt : public FunctionPass {
auto Defs = findAllDefs(U);
// If the values are all Constants or Arguments, don't bother
- if (!std::any_of(Defs.begin(), Defs.end(), isa<Instruction, Value *>))
+ if (llvm::none_of(Defs, isa<Instruction, Value *>))
return false;
- // Presently, we only know how to handle PHINode, Constant, and Arguments.
- // Potentially, bitwise operations (AND, OR, XOR, NOT) and sign extension
- // could also be handled in the future.
+ // Presently, we only know how to handle PHINode, Constant, Arguments and
+ // CallInst. Potentially, bitwise operations (AND, OR, XOR, NOT) and sign
+ // extension could also be handled in the future.
for (Value *V : Defs)
- if (!isa<PHINode>(V) && !isa<Constant>(V) && !isa<Argument>(V))
+ if (!isa<PHINode>(V) && !isa<Constant>(V) &&
+ !isa<Argument>(V) && !isa<CallInst>(V))
return false;
for (Value *V : Defs)
- if (const PHINode *P = dyn_cast<PHINode>(V))
+ if (const auto *P = dyn_cast<PHINode>(V))
if (!PromotablePHINodes.count(P))
return false;
@@ -221,32 +236,35 @@ class PPCBoolRetToInt : public FunctionPass {
if (!BoolToIntMap.count(V))
BoolToIntMap[V] = translate(V);
- // Replace the operands of the translated instructions. There were set to
+ // Replace the operands of the translated instructions. They were set to
// zero in the translate function.
for (auto &Pair : BoolToIntMap) {
- User *First = dyn_cast<User>(Pair.first);
- User *Second = dyn_cast<User>(Pair.second);
+ auto *First = dyn_cast<User>(Pair.first);
+ auto *Second = dyn_cast<User>(Pair.second);
assert((!First || Second) && "translated from user to non-user!?");
- if (First)
+ // Operands of CallInst are skipped because they may not be Bool type,
+ // and their positions are defined by ABI.
+ if (First && !isa<CallInst>(First))
for (unsigned i = 0; i < First->getNumOperands(); ++i)
Second->setOperand(i, BoolToIntMap[First->getOperand(i)]);
}
Value *IntRetVal = BoolToIntMap[U];
Type *Int1Ty = Type::getInt1Ty(U->getContext());
- Instruction *I = cast<Instruction>(U.getUser());
+ auto *I = cast<Instruction>(U.getUser());
Value *BackToBool = new TruncInst(IntRetVal, Int1Ty, "backToBool", I);
U.set(BackToBool);
return true;
}
- void getAnalysisUsage(AnalysisUsage &AU) const {
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addPreserved<DominatorTreeWrapperPass>();
FunctionPass::getAnalysisUsage(AU);
}
};
-}
+
+} // end anonymous namespace
char PPCBoolRetToInt::ID = 0;
INITIALIZE_PASS(PPCBoolRetToInt, "bool-ret-to-int",
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCBranchSelector.cpp b/contrib/llvm/lib/Target/PowerPC/PPCBranchSelector.cpp
index 4d63c5b..ae76386 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCBranchSelector.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCBranchSelector.cpp
@@ -19,8 +19,10 @@
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
+#include "PPCSubtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
@@ -41,19 +43,19 @@ namespace {
initializePPCBSelPass(*PassRegistry::getPassRegistry());
}
- /// BlockSizes - The sizes of the basic blocks in the function.
- std::vector<unsigned> BlockSizes;
+ // The sizes of the basic blocks in the function (the first
+ // element of the pair); the second element of the pair is the amount of the
+ // size that is due to potential padding.
+ std::vector<std::pair<unsigned, unsigned>> BlockSizes;
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
- return "PowerPC Branch Selector";
- }
+ StringRef getPassName() const override { return "PowerPC Branch Selector"; }
};
char PPCBSel::ID = 0;
}
@@ -92,8 +94,19 @@ bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
return AlignAmt + OffsetToAlignment(Offset, AlignAmt);
};
+ // We need to be careful about the offset of the first block in the function
+ // because it might not have the function's alignment. This happens because,
+ // under the ELFv2 ABI, for functions which require a TOC pointer, we add a
+ // two-instruction sequence to the start of the function.
+ // Note: This needs to be synchronized with the check in
+ // PPCLinuxAsmPrinter::EmitFunctionBodyStart.
+ unsigned InitialOffset = 0;
+ if (Fn.getSubtarget<PPCSubtarget>().isELFv2ABI() &&
+ !Fn.getRegInfo().use_empty(PPC::X2))
+ InitialOffset = 8;
+
// Measure each MBB and compute a size for the entire function.
- unsigned FuncSize = 0;
+ unsigned FuncSize = InitialOffset;
for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
++MFI) {
MachineBasicBlock *MBB = &*MFI;
@@ -102,15 +115,19 @@ bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
// alignment requirement.
if (MBB->getNumber() > 0) {
unsigned AlignExtra = GetAlignmentAdjustment(*MBB, FuncSize);
- BlockSizes[MBB->getNumber()-1] += AlignExtra;
+
+ auto &BS = BlockSizes[MBB->getNumber()-1];
+ BS.first += AlignExtra;
+ BS.second = AlignExtra;
+
FuncSize += AlignExtra;
}
unsigned BlockSize = 0;
for (MachineInstr &MI : *MBB)
- BlockSize += TII->GetInstSizeInBytes(MI);
+ BlockSize += TII->getInstSizeInBytes(MI);
- BlockSizes[MBB->getNumber()] = BlockSize;
+ BlockSizes[MBB->getNumber()].first = BlockSize;
FuncSize += BlockSize;
}
@@ -155,7 +172,7 @@ bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
Dest = I->getOperand(0).getMBB();
if (!Dest) {
- MBBStartOffset += TII->GetInstSizeInBytes(*I);
+ MBBStartOffset += TII->getInstSizeInBytes(*I);
continue;
}
@@ -169,14 +186,14 @@ bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
BranchSize = MBBStartOffset;
for (unsigned i = Dest->getNumber(), e = MBB.getNumber(); i != e; ++i)
- BranchSize += BlockSizes[i];
+ BranchSize += BlockSizes[i].first;
} else {
// Otherwise, add the size of the blocks between this block and the
// dest to the number of bytes left in this block.
BranchSize = -MBBStartOffset;
for (unsigned i = MBB.getNumber(), e = Dest->getNumber(); i != e; ++i)
- BranchSize += BlockSizes[i];
+ BranchSize += BlockSizes[i].first;
}
// If this branch is in range, ignore it.
@@ -186,9 +203,9 @@ bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
}
// Otherwise, we have to expand it to a long branch.
- MachineInstr *OldBranch = I;
- DebugLoc dl = OldBranch->getDebugLoc();
-
+ MachineInstr &OldBranch = *I;
+ DebugLoc dl = OldBranch.getDebugLoc();
+
if (I->getOpcode() == PPC::BCC) {
// The BCC operands are:
// 0. PPC branch predicate
@@ -222,16 +239,42 @@ bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
I = BuildMI(MBB, I, dl, TII->get(PPC::B)).addMBB(Dest);
// Remove the old branch from the function.
- OldBranch->eraseFromParent();
-
+ OldBranch.eraseFromParent();
+
// Remember that this instruction is 8-bytes, increase the size of the
// block by 4, remember to iterate.
- BlockSizes[MBB.getNumber()] += 4;
+ BlockSizes[MBB.getNumber()].first += 4;
MBBStartOffset += 8;
++NumExpanded;
MadeChange = true;
}
}
+
+ if (MadeChange) {
+ // If we're going to iterate again, make sure we've updated our
+ // padding-based contributions to the block sizes.
+ unsigned Offset = InitialOffset;
+ for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
+ ++MFI) {
+ MachineBasicBlock *MBB = &*MFI;
+
+ if (MBB->getNumber() > 0) {
+ auto &BS = BlockSizes[MBB->getNumber()-1];
+ BS.first -= BS.second;
+ Offset -= BS.second;
+
+ unsigned AlignExtra = GetAlignmentAdjustment(*MBB, Offset);
+
+ BS.first += AlignExtra;
+ BS.second = AlignExtra;
+
+ Offset += AlignExtra;
+ }
+
+ Offset += BlockSizes[MBB->getNumber()].first;
+ }
+ }
+
EverMadeChange |= MadeChange;
}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCCTRLoops.cpp b/contrib/llvm/lib/Target/PowerPC/PPCCTRLoops.cpp
index 8752266..2c62a0f 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCCTRLoops.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCCTRLoops.cpp
@@ -618,9 +618,9 @@ bool PPCCTRLoops::convertToCTRLoop(Loop *L) {
}
#ifndef NDEBUG
-static bool clobbersCTR(const MachineInstr *MI) {
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
+static bool clobbersCTR(const MachineInstr &MI) {
+ for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
if (MO.isReg()) {
if (MO.isDef() && (MO.getReg() == PPC::CTR || MO.getReg() == PPC::CTR8))
return true;
@@ -659,7 +659,7 @@ check_block:
break;
}
- if (I != BI && clobbersCTR(I)) {
+ if (I != BI && clobbersCTR(*I)) {
DEBUG(dbgs() << "BB#" << MBB->getNumber() << " (" <<
MBB->getFullName() << ") instruction " << *I <<
" clobbers CTR, invalidating " << "BB#" <<
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCCallingConv.td b/contrib/llvm/lib/Target/PowerPC/PPCCallingConv.td
index 53d2f77..a4f4c86 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCCallingConv.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCCallingConv.td
@@ -26,6 +26,9 @@ class CCIfNotSubtarget<string F, CCAction A>
class CCIfOrigArgWasNotPPCF128<CCAction A>
: CCIf<"!static_cast<PPCCCState *>(&State)->WasOriginalArgPPCF128(ValNo)",
A>;
+class CCIfOrigArgWasPPCF128<CCAction A>
+ : CCIf<"static_cast<PPCCCState *>(&State)->WasOriginalArgPPCF128(ValNo)",
+ A>;
//===----------------------------------------------------------------------===//
// Return Value Calling Convention
@@ -65,11 +68,9 @@ def RetCC_PPC : CallingConv<[
// Vector types returned as "direct" go into V2 .. V9; note that only the
// ELFv2 ABI fully utilizes all these registers.
- CCIfType<[v16i8, v8i16, v4i32, v2i64, v1i128, v4f32],
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v1i128, v4f32, v2f64],
CCIfSubtarget<"hasAltivec()",
- CCAssignToReg<[V2, V3, V4, V5, V6, V7, V8, V9]>>>,
- CCIfType<[v2f64, v2i64], CCIfSubtarget<"hasVSX()",
- CCAssignToReg<[VSH2, VSH3, VSH4, VSH5, VSH6, VSH7, VSH8, VSH9]>>>
+ CCAssignToReg<[V2, V3, V4, V5, V6, V7, V8, V9]>>>
]>;
// No explicit register is specified for the AnyReg calling convention. The
@@ -118,11 +119,9 @@ def RetCC_PPC64_ELF_FIS : CallingConv<[
CCIfType<[f64], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>,
CCIfType<[v4f64, v4f32, v4i1],
CCIfSubtarget<"hasQPX()", CCAssignToReg<[QF1, QF2]>>>,
- CCIfType<[v16i8, v8i16, v4i32, v2i64, v1i128, v4f32],
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v1i128, v4f32, v2f64],
CCIfSubtarget<"hasAltivec()",
- CCAssignToReg<[V2, V3, V4, V5, V6, V7, V8, V9]>>>,
- CCIfType<[v2f64, v2i64], CCIfSubtarget<"hasVSX()",
- CCAssignToReg<[VSH2, VSH3, VSH4, VSH5, VSH6, VSH7, VSH8, VSH9]>>>
+ CCAssignToReg<[V2, V3, V4, V5, V6, V7, V8, V9]>>>
]>;
//===----------------------------------------------------------------------===//
@@ -142,6 +141,9 @@ def CC_PPC32_SVR4_Common : CallingConv<[
CCIfType<[i32],
CCIfSplit<CCIfNotSubtarget<"useSoftFloat()",
CCCustom<"CC_PPC32_SVR4_Custom_AlignArgRegs">>>>,
+ CCIfSplit<CCIfSubtarget<"useSoftFloat()",
+ CCIfOrigArgWasPPCF128<CCCustom<
+ "CC_PPC32_SVR4_Custom_SkipLastArgRegsPPCF128">>>>,
// The 'nest' parameter, if any, is passed in R11.
CCIfNest<CCAssignToReg<[R11]>>,
@@ -187,12 +189,9 @@ def CC_PPC32_SVR4 : CallingConv<[
CCAssignToReg<[QF1, QF2, QF3, QF4, QF5, QF6, QF7, QF8]>>>,
// The first 12 Vector arguments are passed in AltiVec registers.
- CCIfType<[v16i8, v8i16, v4i32, v2i64, v1i128, v4f32],
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v1i128, v4f32, v2f64],
CCIfSubtarget<"hasAltivec()", CCAssignToReg<[V2, V3, V4, V5, V6, V7,
V8, V9, V10, V11, V12, V13]>>>,
- CCIfType<[v2f64, v2i64], CCIfSubtarget<"hasVSX()",
- CCAssignToReg<[VSH2, VSH3, VSH4, VSH5, VSH6, VSH7, VSH8, VSH9,
- VSH10, VSH11, VSH12, VSH13]>>>,
CCDelegateTo<CC_PPC32_SVR4_Common>
]>;
@@ -281,6 +280,5 @@ def CSR_64_AllRegs_Altivec : CalleeSavedRegs<(add CSR_64_AllRegs,
(sequence "V%u", 0, 31))>;
def CSR_64_AllRegs_VSX : CalleeSavedRegs<(add CSR_64_AllRegs_Altivec,
- (sequence "VSL%u", 0, 31),
- (sequence "VSH%u", 0, 31))>;
+ (sequence "VSL%u", 0, 31))>;
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp b/contrib/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp
index fcd2f50..6bd2296 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCEarlyReturn.cpp
@@ -58,7 +58,7 @@ protected:
bool Changed = false;
MachineBasicBlock::iterator I = ReturnMBB.begin();
- I = ReturnMBB.SkipPHIsAndLabels(I);
+ I = ReturnMBB.SkipPHIsLabelsAndDebug(I);
// The block must be essentially empty except for the blr.
if (I == ReturnMBB.end() ||
@@ -196,7 +196,7 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCFastISel.cpp b/contrib/llvm/lib/Target/PowerPC/PPCFastISel.cpp
index 7e92042..9b91b9a 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCFastISel.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCFastISel.cpp
@@ -146,11 +146,11 @@ class PPCFastISel final : public FastISel {
bool isTypeLegal(Type *Ty, MVT &VT);
bool isLoadTypeLegal(Type *Ty, MVT &VT);
bool isValueAvailable(const Value *V) const;
- bool isVSFRCRegister(unsigned Register) const {
- return MRI.getRegClass(Register)->getID() == PPC::VSFRCRegClassID;
+ bool isVSFRCRegClass(const TargetRegisterClass *RC) const {
+ return RC->getID() == PPC::VSFRCRegClassID;
}
- bool isVSSRCRegister(unsigned Register) const {
- return MRI.getRegClass(Register)->getID() == PPC::VSSRCRegClassID;
+ bool isVSSRCRegClass(const TargetRegisterClass *RC) const {
+ return RC->getID() == PPC::VSSRCRegClassID;
}
bool PPCEmitCmp(const Value *Src1Value, const Value *Src2Value,
bool isZExt, unsigned DestReg);
@@ -358,7 +358,7 @@ bool PPCFastISel::PPCComputeAddress(const Value *Obj, Address &Addr) {
for (User::const_op_iterator II = U->op_begin() + 1, IE = U->op_end();
II != IE; ++II, ++GTI) {
const Value *Op = *II;
- if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
@@ -458,7 +458,7 @@ void PPCFastISel::PPCSimplifyAddress(Address &Addr, bool &UseOffset,
// Emit a load instruction if possible, returning true if we succeeded,
// otherwise false. See commentary below for how the register class of
-// the load is determined.
+// the load is determined.
bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
const TargetRegisterClass *RC,
bool IsZExt, unsigned FP64LoadOpc) {
@@ -489,20 +489,18 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
Opc = Is32BitInt ? PPC::LBZ : PPC::LBZ8;
break;
case MVT::i16:
- Opc = (IsZExt ?
- (Is32BitInt ? PPC::LHZ : PPC::LHZ8) :
- (Is32BitInt ? PPC::LHA : PPC::LHA8));
+ Opc = (IsZExt ? (Is32BitInt ? PPC::LHZ : PPC::LHZ8)
+ : (Is32BitInt ? PPC::LHA : PPC::LHA8));
break;
case MVT::i32:
- Opc = (IsZExt ?
- (Is32BitInt ? PPC::LWZ : PPC::LWZ8) :
- (Is32BitInt ? PPC::LWA_32 : PPC::LWA));
+ Opc = (IsZExt ? (Is32BitInt ? PPC::LWZ : PPC::LWZ8)
+ : (Is32BitInt ? PPC::LWA_32 : PPC::LWA));
if ((Opc == PPC::LWA || Opc == PPC::LWA_32) && ((Addr.Offset & 3) != 0))
UseOffset = false;
break;
case MVT::i64:
Opc = PPC::LD;
- assert(UseRC->hasSuperClassEq(&PPC::G8RCRegClass) &&
+ assert(UseRC->hasSuperClassEq(&PPC::G8RCRegClass) &&
"64-bit load with 32-bit target??");
UseOffset = ((Addr.Offset & 3) == 0);
break;
@@ -521,10 +519,10 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
// If this is a potential VSX load with an offset of 0, a VSX indexed load can
// be used.
- bool IsVSSRC = (ResultReg != 0) && isVSSRCRegister(ResultReg);
- bool IsVSFRC = (ResultReg != 0) && isVSFRCRegister(ResultReg);
+ bool IsVSSRC = isVSSRCRegClass(UseRC);
+ bool IsVSFRC = isVSFRCRegClass(UseRC);
bool Is32VSXLoad = IsVSSRC && Opc == PPC::LFS;
- bool Is64VSXLoad = IsVSSRC && Opc == PPC::LFD;
+ bool Is64VSXLoad = IsVSFRC && Opc == PPC::LFD;
if ((Is32VSXLoad || Is64VSXLoad) &&
(Addr.BaseType != Address::FrameIndexBase) && UseOffset &&
(Addr.Offset == 0)) {
@@ -579,8 +577,18 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
case PPC::LFS: Opc = IsVSSRC ? PPC::LXSSPX : PPC::LFSX; break;
case PPC::LFD: Opc = IsVSFRC ? PPC::LXSDX : PPC::LFDX; break;
}
- BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
- .addReg(Addr.Base.Reg).addReg(IndexReg);
+
+ auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
+ ResultReg);
+
+ // If we have an index register defined we use it in the store inst,
+ // otherwise we use X0 as base as it makes the vector instructions to
+ // use zero in the computation of the effective address regardless the
+ // content of the register.
+ if (IndexReg)
+ MIB.addReg(Addr.Base.Reg).addReg(IndexReg);
+ else
+ MIB.addReg(PPC::ZERO8).addReg(Addr.Base.Reg);
}
return true;
@@ -657,8 +665,8 @@ bool PPCFastISel::PPCEmitStore(MVT VT, unsigned SrcReg, Address &Addr) {
// If this is a potential VSX store with an offset of 0, a VSX indexed store
// can be used.
- bool IsVSSRC = isVSSRCRegister(SrcReg);
- bool IsVSFRC = isVSFRCRegister(SrcReg);
+ bool IsVSSRC = isVSSRCRegClass(RC);
+ bool IsVSFRC = isVSFRCRegClass(RC);
bool Is32VSXStore = IsVSSRC && Opc == PPC::STFS;
bool Is64VSXStore = IsVSFRC && Opc == PPC::STFD;
if ((Is32VSXStore || Is64VSXStore) &&
@@ -689,8 +697,9 @@ bool PPCFastISel::PPCEmitStore(MVT VT, unsigned SrcReg, Address &Addr) {
// Base reg with offset in range.
} else if (UseOffset) {
// VSX only provides an indexed store.
- if (Is32VSXStore || Is64VSXStore) return false;
-
+ if (Is32VSXStore || Is64VSXStore)
+ return false;
+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
.addReg(SrcReg).addImm(Addr.Offset).addReg(Addr.Base.Reg);
@@ -828,7 +837,7 @@ bool PPCFastISel::PPCEmitCmp(const Value *SrcValue1, const Value *SrcValue2,
long Imm = 0;
bool UseImm = false;
- // Only 16-bit integer constants can be represented in compares for
+ // Only 16-bit integer constants can be represented in compares for
// PowerPC. Others will be materialized into a register.
if (const ConstantInt *ConstInt = dyn_cast<ConstantInt>(SrcValue2)) {
if (SrcVT == MVT::i64 || SrcVT == MVT::i32 || SrcVT == MVT::i16 ||
@@ -1617,7 +1626,7 @@ bool PPCFastISel::SelectRet(const Instruction *I) {
CCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, ValLocs, *Context);
CCInfo.AnalyzeReturn(Outs, RetCC_PPC64_ELF_FIS);
const Value *RV = Ret->getOperand(0);
-
+
// FIXME: Only one output register for now.
if (ValLocs.size() > 1)
return false;
@@ -1663,7 +1672,7 @@ bool PPCFastISel::SelectRet(const Instruction *I) {
if (RVVT != DestVT && RVVT != MVT::i8 &&
RVVT != MVT::i16 && RVVT != MVT::i32)
return false;
-
+
if (RVVT != DestVT) {
switch (VA.getLocInfo()) {
default:
@@ -1907,7 +1916,9 @@ unsigned PPCFastISel::PPCMaterializeFP(const ConstantFP *CFP, MVT VT) {
unsigned Align = DL.getPrefTypeAlignment(CFP->getType());
assert(Align > 0 && "Unexpectedly missing alignment information!");
unsigned Idx = MCP.getConstantPoolIndex(cast<Constant>(CFP), Align);
- unsigned DestReg = createResultReg(TLI.getRegClassFor(VT));
+ const TargetRegisterClass *RC =
+ (VT == MVT::f32) ? &PPC::F4RCRegClass : &PPC::F8RCRegClass;
+ unsigned DestReg = createResultReg(RC);
CodeModel::Model CModel = TM.getCodeModel();
MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand(
@@ -1936,8 +1947,9 @@ unsigned PPCFastISel::PPCMaterializeFP(const ConstantFP *CFP, MVT VT) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::LDtocL),
TmpReg2).addConstantPoolIndex(Idx).addReg(TmpReg);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), DestReg)
- .addImm(0).addReg(TmpReg2);
- } else
+ .addImm(0)
+ .addReg(TmpReg2);
+ } else
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), DestReg)
.addConstantPoolIndex(Idx, 0, PPCII::MO_TOC_LO)
.addReg(TmpReg)
@@ -2028,8 +2040,8 @@ unsigned PPCFastISel::PPCMaterialize32BitInt(int64_t Imm,
// Just Hi bits.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(IsGPRC ? PPC::LIS : PPC::LIS8), ResultReg)
- .addImm(Hi);
-
+ .addImm(Hi);
+
return ResultReg;
}
@@ -2145,7 +2157,12 @@ unsigned PPCFastISel::fastMaterializeConstant(const Constant *C) {
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
return PPCMaterializeGV(GV, VT);
else if (const ConstantInt *CI = dyn_cast<ConstantInt>(C))
- return PPCMaterializeInt(CI, VT, VT != MVT::i1);
+ // Note that the code in FunctionLoweringInfo::ComputePHILiveOutRegInfo
+ // assumes that constant PHI operands will be zero extended, and failure to
+ // match that assumption will cause problems if we sign extend here but
+ // some user of a PHI is in a block for which we fall back to full SDAG
+ // instruction selection.
+ return PPCMaterializeInt(CI, VT, false);
return 0;
}
@@ -2263,7 +2280,7 @@ bool PPCFastISel::fastLowerArguments() {
// Handle materializing integer constants into a register. This is not
// automatically generated for PowerPC, so must be explicitly created here.
unsigned PPCFastISel::fastEmit_i(MVT Ty, MVT VT, unsigned Opc, uint64_t Imm) {
-
+
if (Opc != ISD::Constant)
return 0;
@@ -2276,8 +2293,8 @@ unsigned PPCFastISel::fastEmit_i(MVT Ty, MVT VT, unsigned Opc, uint64_t Imm) {
return ImmReg;
}
- if (VT != MVT::i64 && VT != MVT::i32 && VT != MVT::i16 &&
- VT != MVT::i8 && VT != MVT::i1)
+ if (VT != MVT::i64 && VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 &&
+ VT != MVT::i1)
return 0;
const TargetRegisterClass *RC = ((VT == MVT::i64) ? &PPC::G8RCRegClass :
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index c3a5d3c..e786ef9 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -253,8 +253,8 @@ const PPCFrameLowering::SpillSlot *PPCFrameLowering::getCalleeSavedSpillSlots(
/// contents is spilled and reloaded around the call. Without the prolog code,
/// the spill instruction refers to an undefined register. This code needs
/// to account for all uses of that GPR.
-static void RemoveVRSaveCode(MachineInstr *MI) {
- MachineBasicBlock *Entry = MI->getParent();
+static void RemoveVRSaveCode(MachineInstr &MI) {
+ MachineBasicBlock *Entry = MI.getParent();
MachineFunction *MF = Entry->getParent();
// We know that the MTVRSAVE instruction immediately follows MI. Remove it.
@@ -293,16 +293,16 @@ static void RemoveVRSaveCode(MachineInstr *MI) {
}
// Finally, nuke the UPDATE_VRSAVE.
- MI->eraseFromParent();
+ MI.eraseFromParent();
}
// HandleVRSaveUpdate - MI is the UPDATE_VRSAVE instruction introduced by the
// instruction selector. Based on the vector registers that have been used,
// transform this into the appropriate ORI instruction.
-static void HandleVRSaveUpdate(MachineInstr *MI, const TargetInstrInfo &TII) {
- MachineFunction *MF = MI->getParent()->getParent();
+static void HandleVRSaveUpdate(MachineInstr &MI, const TargetInstrInfo &TII) {
+ MachineFunction *MF = MI.getParent()->getParent();
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
- DebugLoc dl = MI->getDebugLoc();
+ DebugLoc dl = MI.getDebugLoc();
const MachineRegisterInfo &MRI = MF->getRegInfo();
unsigned UsedRegMask = 0;
@@ -343,44 +343,44 @@ static void HandleVRSaveUpdate(MachineInstr *MI, const TargetInstrInfo &TII) {
return;
}
- unsigned SrcReg = MI->getOperand(1).getReg();
- unsigned DstReg = MI->getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned DstReg = MI.getOperand(0).getReg();
if ((UsedRegMask & 0xFFFF) == UsedRegMask) {
if (DstReg != SrcReg)
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORI), DstReg)
- .addReg(SrcReg)
- .addImm(UsedRegMask);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORI), DstReg)
+ .addReg(SrcReg)
+ .addImm(UsedRegMask);
else
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORI), DstReg)
- .addReg(SrcReg, RegState::Kill)
- .addImm(UsedRegMask);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORI), DstReg)
+ .addReg(SrcReg, RegState::Kill)
+ .addImm(UsedRegMask);
} else if ((UsedRegMask & 0xFFFF0000) == UsedRegMask) {
if (DstReg != SrcReg)
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
- .addReg(SrcReg)
- .addImm(UsedRegMask >> 16);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
+ .addReg(SrcReg)
+ .addImm(UsedRegMask >> 16);
else
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
- .addReg(SrcReg, RegState::Kill)
- .addImm(UsedRegMask >> 16);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
+ .addReg(SrcReg, RegState::Kill)
+ .addImm(UsedRegMask >> 16);
} else {
if (DstReg != SrcReg)
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
- .addReg(SrcReg)
- .addImm(UsedRegMask >> 16);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
+ .addReg(SrcReg)
+ .addImm(UsedRegMask >> 16);
else
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
- .addReg(SrcReg, RegState::Kill)
- .addImm(UsedRegMask >> 16);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORIS), DstReg)
+ .addReg(SrcReg, RegState::Kill)
+ .addImm(UsedRegMask >> 16);
- BuildMI(*MI->getParent(), MI, dl, TII.get(PPC::ORI), DstReg)
- .addReg(DstReg, RegState::Kill)
- .addImm(UsedRegMask & 0xFFFF);
+ BuildMI(*MI.getParent(), MI, dl, TII.get(PPC::ORI), DstReg)
+ .addReg(DstReg, RegState::Kill)
+ .addImm(UsedRegMask & 0xFFFF);
}
// Remove the old UPDATE_VRSAVE instruction.
- MI->eraseFromParent();
+ MI.eraseFromParent();
}
static bool spillsCR(const MachineFunction &MF) {
@@ -422,15 +422,15 @@ static bool MustSaveLR(const MachineFunction &MF, unsigned LR) {
unsigned PPCFrameLowering::determineFrameLayout(MachineFunction &MF,
bool UpdateMF,
bool UseEstimate) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
// Get the number of bytes to allocate from the FrameInfo
unsigned FrameSize =
- UseEstimate ? MFI->estimateStackSize(MF) : MFI->getStackSize();
+ UseEstimate ? MFI.estimateStackSize(MF) : MFI.getStackSize();
// Get stack alignments. The frame must be aligned to the greatest of these:
unsigned TargetAlign = getStackAlignment(); // alignment required per the ABI
- unsigned MaxAlign = MFI->getMaxAlignment(); // algmt required by data in frame
+ unsigned MaxAlign = MFI.getMaxAlignment(); // algmt required by data in frame
unsigned AlignMask = std::max(MaxAlign, TargetAlign) - 1;
const PPCRegisterInfo *RegInfo =
@@ -448,18 +448,18 @@ unsigned PPCFrameLowering::determineFrameLayout(MachineFunction &MF,
!Subtarget.isSVR4ABI() || // allocated locals.
FrameSize == 0) &&
FrameSize <= 224 && // Fits in red zone.
- !MFI->hasVarSizedObjects() && // No dynamic alloca.
- !MFI->adjustsStack() && // No calls.
+ !MFI.hasVarSizedObjects() && // No dynamic alloca.
+ !MFI.adjustsStack() && // No calls.
!MustSaveLR(MF, LR) &&
!RegInfo->hasBasePointer(MF)) { // No special alignment.
// No need for frame
if (UpdateMF)
- MFI->setStackSize(0);
+ MFI.setStackSize(0);
return 0;
}
// Get the maximum call frame size of all the calls.
- unsigned maxCallFrameSize = MFI->getMaxCallFrameSize();
+ unsigned maxCallFrameSize = MFI.getMaxCallFrameSize();
// Maximum call frame needs to be at least big enough for linkage area.
unsigned minCallFrameSize = getLinkageSize();
@@ -467,12 +467,12 @@ unsigned PPCFrameLowering::determineFrameLayout(MachineFunction &MF,
// If we have dynamic alloca then maxCallFrameSize needs to be aligned so
// that allocations will be aligned.
- if (MFI->hasVarSizedObjects())
+ if (MFI.hasVarSizedObjects())
maxCallFrameSize = (maxCallFrameSize + AlignMask) & ~AlignMask;
// Update maximum call frame size.
if (UpdateMF)
- MFI->setMaxCallFrameSize(maxCallFrameSize);
+ MFI.setMaxCallFrameSize(maxCallFrameSize);
// Include call frame size in total.
FrameSize += maxCallFrameSize;
@@ -482,7 +482,7 @@ unsigned PPCFrameLowering::determineFrameLayout(MachineFunction &MF,
// Update frame info.
if (UpdateMF)
- MFI->setStackSize(FrameSize);
+ MFI.setStackSize(FrameSize);
return FrameSize;
}
@@ -490,18 +490,18 @@ unsigned PPCFrameLowering::determineFrameLayout(MachineFunction &MF,
// hasFP - Return true if the specified function actually has a dedicated frame
// pointer register.
bool PPCFrameLowering::hasFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// FIXME: This is pretty much broken by design: hasFP() might be called really
// early, before the stack layout was calculated and thus hasFP() might return
// true or false here depending on the time of call.
- return (MFI->getStackSize()) && needsFP(MF);
+ return (MFI.getStackSize()) && needsFP(MF);
}
// needsFP - 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.
bool PPCFrameLowering::needsFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Naked functions have no stack frame pushed, so we don't have a frame
// pointer.
@@ -509,8 +509,7 @@ bool PPCFrameLowering::needsFP(const MachineFunction &MF) const {
return false;
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
- MFI->hasVarSizedObjects() ||
- MFI->hasStackMap() || MFI->hasPatchPoint() ||
+ MFI.hasVarSizedObjects() || MFI.hasStackMap() || MFI.hasPatchPoint() ||
(MF.getTarget().Options.GuaranteedTailCallOpt &&
MF.getInfo<PPCFunctionInfo>()->hasFastCall());
}
@@ -671,8 +670,8 @@ PPCFrameLowering::twoUniqueScratchRegsRequired(MachineBasicBlock *MBB) const {
unsigned FrameSize = determineFrameLayout(MF, false);
int NegFrameSize = -FrameSize;
bool IsLargeFrame = !isInt<16>(NegFrameSize);
- MachineFrameInfo *MFI = MF.getFrameInfo();
- unsigned MaxAlign = MFI->getMaxAlignment();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned MaxAlign = MFI.getMaxAlignment();
bool HasRedZone = Subtarget.isPPC64() || !Subtarget.isSVR4ABI();
return (IsLargeFrame || !HasRedZone) && HasBP && MaxAlign > 1;
@@ -694,7 +693,7 @@ bool PPCFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
void PPCFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.begin();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const PPCInstrInfo &TII =
*static_cast<const PPCInstrInfo *>(Subtarget.getInstrInfo());
const PPCRegisterInfo *RegInfo =
@@ -719,7 +718,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (!isSVR4ABI)
for (unsigned i = 0; MBBI != MBB.end(); ++i, ++MBBI) {
if (MBBI->getOpcode() == PPC::UPDATE_VRSAVE) {
- HandleVRSaveUpdate(MBBI, TII);
+ HandleVRSaveUpdate(*MBBI, TII);
break;
}
}
@@ -733,7 +732,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (!isInt<32>(NegFrameSize))
llvm_unreachable("Unhandled stack size!");
- if (MFI->isFrameAddressTaken())
+ if (MFI.isFrameAddressTaken())
replaceFPWithRealFP(MF);
// Check if the link register (LR) must be saved.
@@ -779,7 +778,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
assert((isPPC64 || !isSVR4ABI || !(!FrameSize && (MustSaveLR || HasFP))) &&
"FrameSize must be >0 to save/restore the FP or LR for 32-bit SVR4.");
- // Using the same bool variable as below to supress compiler warnings.
+ // Using the same bool variable as below to suppress compiler warnings.
bool SingleScratchReg =
findScratchRegister(&MBB, false, twoUniqueScratchRegsRequired(&MBB),
&ScratchReg, &TempReg);
@@ -793,10 +792,10 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
int FPOffset = 0;
if (HasFP) {
if (isSVR4ABI) {
- MachineFrameInfo *FFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
int FPIndex = FI->getFramePointerSaveIndex();
assert(FPIndex && "No Frame Pointer Save Slot!");
- FPOffset = FFI->getObjectOffset(FPIndex);
+ FPOffset = MFI.getObjectOffset(FPIndex);
} else {
FPOffset = getFramePointerSaveOffset();
}
@@ -805,10 +804,10 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
int BPOffset = 0;
if (HasBP) {
if (isSVR4ABI) {
- MachineFrameInfo *FFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
int BPIndex = FI->getBasePointerSaveIndex();
assert(BPIndex && "No Base Pointer Save Slot!");
- BPOffset = FFI->getObjectOffset(BPIndex);
+ BPOffset = MFI.getObjectOffset(BPIndex);
} else {
BPOffset = getBasePointerSaveOffset();
}
@@ -816,14 +815,14 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
int PBPOffset = 0;
if (FI->usesPICBase()) {
- MachineFrameInfo *FFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
int PBPIndex = FI->getPICBasePointerSaveIndex();
assert(PBPIndex && "No PIC Base Pointer Save Slot!");
- PBPOffset = FFI->getObjectOffset(PBPIndex);
+ PBPOffset = MFI.getObjectOffset(PBPIndex);
}
// Get stack alignments.
- unsigned MaxAlign = MFI->getMaxAlignment();
+ unsigned MaxAlign = MFI.getMaxAlignment();
if (HasBP && MaxAlign > 1)
assert(isPowerOf2_32(MaxAlign) && isInt<16>(MaxAlign) &&
"Invalid alignment!");
@@ -1106,12 +1105,12 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
// because if the stack needed aligning then CFA won't be at a fixed
// offset from FP/SP.
unsigned Reg = MRI->getDwarfRegNum(BPReg, true);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, Reg));
} else {
// Adjust the definition of CFA to account for the change in SP.
assert(NegFrameSize);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, NegFrameSize));
}
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
@@ -1120,7 +1119,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (HasFP) {
// Describe where FP was saved, at a fixed offset from CFA.
unsigned Reg = MRI->getDwarfRegNum(FPReg, true);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, FPOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -1129,7 +1128,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (FI->usesPICBase()) {
// Describe where FP was saved, at a fixed offset from CFA.
unsigned Reg = MRI->getDwarfRegNum(PPC::R30, true);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, PBPOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -1138,7 +1137,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (HasBP) {
// Describe where BP was saved, at a fixed offset from CFA.
unsigned Reg = MRI->getDwarfRegNum(BPReg, true);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, BPOffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -1147,7 +1146,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (MustSaveLR) {
// Describe where LR was saved, at a fixed offset from CFA.
unsigned Reg = MRI->getDwarfRegNum(LRReg, true);
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, LROffset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -1164,7 +1163,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
// Change the definition of CFA from SP+offset to FP+offset, because SP
// will change at every alloca.
unsigned Reg = MRI->getDwarfRegNum(FPReg, true);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, Reg));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
@@ -1175,7 +1174,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
if (needsCFI) {
// Describe where callee saved registers were saved, at fixed offsets from
// CFA.
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
unsigned Reg = CSI[I].getReg();
if (Reg == PPC::LR || Reg == PPC::LR8 || Reg == PPC::RM) continue;
@@ -1198,15 +1197,15 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
// the whole CR word. In the ELFv2 ABI, every CR that was
// actually saved gets its own CFI record.
unsigned CRReg = isELFv2ABI? Reg : (unsigned) PPC::CR2;
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(CRReg, true), 8));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
continue;
}
- int Offset = MFI->getObjectOffset(CSI[I].getFrameIdx());
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ int Offset = MFI.getObjectOffset(CSI[I].getFrameIdx());
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, true), Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -1228,10 +1227,10 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
static_cast<const PPCRegisterInfo *>(Subtarget.getRegisterInfo());
// Get alignment info so we know how to restore the SP.
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Get the number of bytes allocated from the FrameInfo.
- int FrameSize = MFI->getStackSize();
+ int FrameSize = MFI.getStackSize();
// Get processor type.
bool isPPC64 = Subtarget.isPPC64();
@@ -1272,7 +1271,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
int FPOffset = 0;
- // Using the same bool variable as below to supress compiler warnings.
+ // Using the same bool variable as below to suppress compiler warnings.
bool SingleScratchReg = findScratchRegister(&MBB, true, false, &ScratchReg,
&TempReg);
assert(SingleScratchReg &&
@@ -1284,7 +1283,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
if (isSVR4ABI) {
int FPIndex = FI->getFramePointerSaveIndex();
assert(FPIndex && "No Frame Pointer Save Slot!");
- FPOffset = MFI->getObjectOffset(FPIndex);
+ FPOffset = MFI.getObjectOffset(FPIndex);
} else {
FPOffset = getFramePointerSaveOffset();
}
@@ -1295,7 +1294,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
if (isSVR4ABI) {
int BPIndex = FI->getBasePointerSaveIndex();
assert(BPIndex && "No Base Pointer Save Slot!");
- BPOffset = MFI->getObjectOffset(BPIndex);
+ BPOffset = MFI.getObjectOffset(BPIndex);
} else {
BPOffset = getBasePointerSaveOffset();
}
@@ -1305,7 +1304,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
if (FI->usesPICBase()) {
int PBPIndex = FI->getPICBasePointerSaveIndex();
assert(PBPIndex && "No PIC Base Pointer Save Slot!");
- PBPOffset = MFI->getObjectOffset(PBPIndex);
+ PBPOffset = MFI.getObjectOffset(PBPIndex);
}
bool IsReturnBlock = (MBBI != MBB.end() && MBBI->isReturn());
@@ -1380,7 +1379,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
.addReg(FPReg)
.addReg(ScratchReg);
}
- } else if (!isLargeFrame && !HasBP && !MFI->hasVarSizedObjects()) {
+ } else if (!isLargeFrame && !HasBP && !MFI.hasVarSizedObjects()) {
if (HasRedZone) {
BuildMI(MBB, MBBI, dl, AddImmInst, SPReg)
.addReg(SPReg)
@@ -1603,14 +1602,14 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
int FPSI = FI->getFramePointerSaveIndex();
bool isPPC64 = Subtarget.isPPC64();
bool isDarwinABI = Subtarget.isDarwinABI();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
// If the frame pointer save index hasn't been defined yet.
if (!FPSI && needsFP(MF)) {
// Find out what the fix offset of the frame pointer save area.
int FPOffset = getFramePointerSaveOffset();
// Allocate the frame index for frame pointer save area.
- FPSI = MFI->CreateFixedObject(isPPC64? 8 : 4, FPOffset, true);
+ FPSI = MFI.CreateFixedObject(isPPC64? 8 : 4, FPOffset, true);
// Save the result.
FI->setFramePointerSaveIndex(FPSI);
}
@@ -1619,7 +1618,7 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
if (!BPSI && RegInfo->hasBasePointer(MF)) {
int BPOffset = getBasePointerSaveOffset();
// Allocate the frame index for the base pointer save area.
- BPSI = MFI->CreateFixedObject(isPPC64? 8 : 4, BPOffset, true);
+ BPSI = MFI.CreateFixedObject(isPPC64? 8 : 4, BPOffset, true);
// Save the result.
FI->setBasePointerSaveIndex(BPSI);
}
@@ -1627,7 +1626,7 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
// Reserve stack space for the PIC Base register (R30).
// Only used in SVR4 32-bit.
if (FI->usesPICBase()) {
- int PBPSI = MFI->CreateFixedObject(4, -8, true);
+ int PBPSI = MFI.CreateFixedObject(4, -8, true);
FI->setPICBasePointerSaveIndex(PBPSI);
}
@@ -1646,7 +1645,7 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
int TCSPDelta = 0;
if (MF.getTarget().Options.GuaranteedTailCallOpt &&
(TCSPDelta = FI->getTailCallSPDelta()) < 0) {
- MFI->CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true);
+ MFI.CreateFixedObject(-1 * TCSPDelta, TCSPDelta, true);
}
// For 32-bit SVR4, allocate the nonvolatile CR spill slot iff the
@@ -1655,7 +1654,7 @@ void PPCFrameLowering::determineCalleeSaves(MachineFunction &MF,
(SavedRegs.test(PPC::CR2) ||
SavedRegs.test(PPC::CR3) ||
SavedRegs.test(PPC::CR4))) {
- int FrameIdx = MFI->CreateFixedObject((uint64_t)4, (int64_t)-4, true);
+ int FrameIdx = MFI.CreateFixedObject((uint64_t)4, (int64_t)-4, true);
FI->setCRSpillFrameIndex(FrameIdx);
}
}
@@ -1669,15 +1668,15 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
}
// Get callee saved register information.
- MachineFrameInfo *FFI = MF.getFrameInfo();
- const std::vector<CalleeSavedInfo> &CSI = FFI->getCalleeSavedInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// If the function is shrink-wrapped, and if the function has a tail call, the
// tail call might not be in the new RestoreBlock, so real branch instruction
// won't be generated by emitEpilogue(), because shrink-wrap has chosen new
// RestoreBlock. So we handle this case here.
- if (FFI->getSavePoint() && FFI->hasTailCall()) {
- MachineBasicBlock *RestoreBlock = FFI->getRestorePoint();
+ if (MFI.getSavePoint() && MFI.hasTailCall()) {
+ MachineBasicBlock *RestoreBlock = MFI.getRestorePoint();
for (MachineBasicBlock &MBB : MF) {
if (MBB.isReturnBlock() && (&MBB) != RestoreBlock)
createTailCallBranchInstr(MBB);
@@ -1768,7 +1767,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
for (unsigned i = 0, e = FPRegs.size(); i != e; ++i) {
int FI = FPRegs[i].getFrameIdx();
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
LowerBound -= (31 - TRI->getEncodingValue(MinFPR) + 1) * 8;
@@ -1782,7 +1781,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
int FI = PFI->getFramePointerSaveIndex();
assert(FI && "No Frame Pointer Save Slot!");
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
if (PFI->usesPICBase()) {
@@ -1791,7 +1790,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
int FI = PFI->getPICBasePointerSaveIndex();
assert(FI && "No PIC Base Pointer Save Slot!");
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
const PPCRegisterInfo *RegInfo =
@@ -1802,7 +1801,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
int FI = PFI->getBasePointerSaveIndex();
assert(FI && "No Base Pointer Save Slot!");
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
// General register save area starts right below the Floating-point
@@ -1813,7 +1812,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
for (unsigned i = 0, e = GPRegs.size(); i != e; ++i) {
int FI = GPRegs[i].getFrameIdx();
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
// Move general register save area spill slots down, taking into account
@@ -1821,7 +1820,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
for (unsigned i = 0, e = G8Regs.size(); i != e; ++i) {
int FI = G8Regs[i].getFrameIdx();
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
unsigned MinReg =
@@ -1852,7 +1851,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
PPC::CRRCRegClass.contains(Reg)))) {
int FI = CSI[i].getFrameIdx();
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
}
@@ -1869,7 +1868,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
if (PPC::VRSAVERCRegClass.contains(Reg)) {
int FI = CSI[i].getFrameIdx();
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
}
@@ -1883,7 +1882,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
for (unsigned i = 0, e = VRegs.size(); i != e; ++i) {
int FI = VRegs[i].getFrameIdx();
- FFI->setObjectOffset(FI, LowerBound + FFI->getObjectOffset(FI));
+ MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
}
}
@@ -1907,25 +1906,25 @@ PPCFrameLowering::addScavengingSpillSlot(MachineFunction &MF,
// because we've not yet computed callee-saved register spills or the
// needed alignment padding.
unsigned StackSize = determineFrameLayout(MF, false, true);
- MachineFrameInfo *MFI = MF.getFrameInfo();
- if (MFI->hasVarSizedObjects() || spillsCR(MF) || spillsVRSAVE(MF) ||
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (MFI.hasVarSizedObjects() || spillsCR(MF) || spillsVRSAVE(MF) ||
hasNonRISpills(MF) || (hasSpills(MF) && !isInt<16>(StackSize))) {
const TargetRegisterClass *GPRC = &PPC::GPRCRegClass;
const TargetRegisterClass *G8RC = &PPC::G8RCRegClass;
const TargetRegisterClass *RC = Subtarget.isPPC64() ? G8RC : GPRC;
- RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
- RC->getAlignment(),
- false));
+ RS->addScavengingFrameIndex(MFI.CreateStackObject(RC->getSize(),
+ RC->getAlignment(),
+ false));
// Might we have over-aligned allocas?
- bool HasAlVars = MFI->hasVarSizedObjects() &&
- MFI->getMaxAlignment() > getStackAlignment();
+ bool HasAlVars = MFI.hasVarSizedObjects() &&
+ MFI.getMaxAlignment() > getStackAlignment();
// These kinds of spills might need two registers.
if (spillsCR(MF) || spillsVRSAVE(MF) || HasAlVars)
- RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
- RC->getAlignment(),
- false));
+ RS->addScavengingFrameIndex(MFI.CreateStackObject(RC->getSize(),
+ RC->getAlignment(),
+ false));
}
}
@@ -2049,8 +2048,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
unsigned ADDInstr = is64Bit ? PPC::ADD8 : PPC::ADD4;
unsigned LISInstr = is64Bit ? PPC::LIS8 : PPC::LIS;
unsigned ORIInstr = is64Bit ? PPC::ORI8 : PPC::ORI;
- MachineInstr *MI = I;
- const DebugLoc &dl = MI->getDebugLoc();
+ const DebugLoc &dl = I->getDebugLoc();
if (isInt<16>(CalleeAmt)) {
BuildMI(MBB, I, dl, TII.get(ADDIInstr), StackReg)
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCHazardRecognizers.cpp b/contrib/llvm/lib/Target/PowerPC/PPCHazardRecognizers.cpp
index caab67d..f327396 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCHazardRecognizers.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCHazardRecognizers.cpp
@@ -226,7 +226,7 @@ void PPCDispatchGroupSBHazardRecognizer::EmitNoop() {
// group-terminating nop, the group is complete.
// FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
- Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR8 ||
+ Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9 ||
CurSlots == 6) {
CurGroup.clear();
CurSlots = CurBranches = 0;
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 0e9b2da..1e51c1f 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -215,7 +215,7 @@ namespace {
void InsertVRSaveCode(MachineFunction &MF);
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "PowerPC DAG->DAG Pattern Instruction Selection";
}
@@ -334,12 +334,12 @@ SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
}
} else {
GlobalBaseReg =
- RegInfo->createVirtualRegister(&PPC::GPRC_NOR0RegClass);
+ RegInfo->createVirtualRegister(&PPC::GPRC_and_GPRC_NOR0RegClass);
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR), GlobalBaseReg);
}
} else {
- GlobalBaseReg = RegInfo->createVirtualRegister(&PPC::G8RC_NOX0RegClass);
+ GlobalBaseReg = RegInfo->createVirtualRegister(&PPC::G8RC_and_G8RC_NOX0RegClass);
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR8));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR8), GlobalBaseReg);
}
@@ -633,6 +633,13 @@ static unsigned getInt64CountDirect(int64_t Imm) {
// If no shift, we're done.
if (!Shift) return Result;
+ // If Hi word == Lo word,
+ // we can use rldimi to insert the Lo word into Hi word.
+ if ((unsigned)(Imm & 0xFFFFFFFF) == Remainder) {
+ ++Result;
+ return Result;
+ }
+
// Shift for next step if the upper 32-bits were not zero.
if (Imm)
++Result;
@@ -731,6 +738,14 @@ static SDNode *getInt64Direct(SelectionDAG *CurDAG, const SDLoc &dl,
// If no shift, we're done.
if (!Shift) return Result;
+ // If Hi word == Lo word,
+ // we can use rldimi to insert the Lo word into Hi word.
+ if ((unsigned)(Imm & 0xFFFFFFFF) == Remainder) {
+ SDValue Ops[] =
+ { SDValue(Result, 0), SDValue(Result, 0), getI32Imm(Shift), getI32Imm(0)};
+ return CurDAG->getMachineNode(PPC::RLDIMI, dl, MVT::i64, Ops);
+ }
+
// Shift for next step if the upper 32-bits were not zero.
if (Imm) {
Result = CurDAG->getMachineNode(PPC::RLDICR, dl, MVT::i64,
@@ -912,84 +927,95 @@ class BitPermutationSelector {
}
};
- // Return true if something interesting was deduced, return false if we're
+ using ValueBitsMemoizedValue = std::pair<bool, SmallVector<ValueBit, 64>>;
+ using ValueBitsMemoizer =
+ DenseMap<SDValue, std::unique_ptr<ValueBitsMemoizedValue>>;
+ ValueBitsMemoizer Memoizer;
+
+ // Return a pair of bool and a SmallVector pointer to a memoization entry.
+ // The bool is true if something interesting was deduced, otherwise if we're
// providing only a generic representation of V (or something else likewise
- // uninteresting for instruction selection).
- bool getValueBits(SDValue V, SmallVector<ValueBit, 64> &Bits) {
+ // uninteresting for instruction selection) through the SmallVector.
+ std::pair<bool, SmallVector<ValueBit, 64> *> getValueBits(SDValue V,
+ unsigned NumBits) {
+ auto &ValueEntry = Memoizer[V];
+ if (ValueEntry)
+ return std::make_pair(ValueEntry->first, &ValueEntry->second);
+ ValueEntry.reset(new ValueBitsMemoizedValue());
+ bool &Interesting = ValueEntry->first;
+ SmallVector<ValueBit, 64> &Bits = ValueEntry->second;
+ Bits.resize(NumBits);
+
switch (V.getOpcode()) {
default: break;
case ISD::ROTL:
if (isa<ConstantSDNode>(V.getOperand(1))) {
unsigned RotAmt = V.getConstantOperandVal(1);
- SmallVector<ValueBit, 64> LHSBits(Bits.size());
- getValueBits(V.getOperand(0), LHSBits);
+ const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
- for (unsigned i = 0; i < Bits.size(); ++i)
- Bits[i] = LHSBits[i < RotAmt ? i + (Bits.size() - RotAmt) : i - RotAmt];
+ for (unsigned i = 0; i < NumBits; ++i)
+ Bits[i] = LHSBits[i < RotAmt ? i + (NumBits - RotAmt) : i - RotAmt];
- return true;
+ return std::make_pair(Interesting = true, &Bits);
}
break;
case ISD::SHL:
if (isa<ConstantSDNode>(V.getOperand(1))) {
unsigned ShiftAmt = V.getConstantOperandVal(1);
- SmallVector<ValueBit, 64> LHSBits(Bits.size());
- getValueBits(V.getOperand(0), LHSBits);
+ const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
- for (unsigned i = ShiftAmt; i < Bits.size(); ++i)
+ for (unsigned i = ShiftAmt; i < NumBits; ++i)
Bits[i] = LHSBits[i - ShiftAmt];
for (unsigned i = 0; i < ShiftAmt; ++i)
Bits[i] = ValueBit(ValueBit::ConstZero);
- return true;
+ return std::make_pair(Interesting = true, &Bits);
}
break;
case ISD::SRL:
if (isa<ConstantSDNode>(V.getOperand(1))) {
unsigned ShiftAmt = V.getConstantOperandVal(1);
- SmallVector<ValueBit, 64> LHSBits(Bits.size());
- getValueBits(V.getOperand(0), LHSBits);
+ const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
- for (unsigned i = 0; i < Bits.size() - ShiftAmt; ++i)
+ for (unsigned i = 0; i < NumBits - ShiftAmt; ++i)
Bits[i] = LHSBits[i + ShiftAmt];
- for (unsigned i = Bits.size() - ShiftAmt; i < Bits.size(); ++i)
+ for (unsigned i = NumBits - ShiftAmt; i < NumBits; ++i)
Bits[i] = ValueBit(ValueBit::ConstZero);
- return true;
+ return std::make_pair(Interesting = true, &Bits);
}
break;
case ISD::AND:
if (isa<ConstantSDNode>(V.getOperand(1))) {
uint64_t Mask = V.getConstantOperandVal(1);
- SmallVector<ValueBit, 64> LHSBits(Bits.size());
- bool LHSTrivial = getValueBits(V.getOperand(0), LHSBits);
+ const SmallVector<ValueBit, 64> *LHSBits;
+ // Mark this as interesting, only if the LHS was also interesting. This
+ // prevents the overall procedure from matching a single immediate 'and'
+ // (which is non-optimal because such an and might be folded with other
+ // things if we don't select it here).
+ std::tie(Interesting, LHSBits) = getValueBits(V.getOperand(0), NumBits);
- for (unsigned i = 0; i < Bits.size(); ++i)
+ for (unsigned i = 0; i < NumBits; ++i)
if (((Mask >> i) & 1) == 1)
- Bits[i] = LHSBits[i];
+ Bits[i] = (*LHSBits)[i];
else
Bits[i] = ValueBit(ValueBit::ConstZero);
- // Mark this as interesting, only if the LHS was also interesting. This
- // prevents the overall procedure from matching a single immediate 'and'
- // (which is non-optimal because such an and might be folded with other
- // things if we don't select it here).
- return LHSTrivial;
+ return std::make_pair(Interesting, &Bits);
}
break;
case ISD::OR: {
- SmallVector<ValueBit, 64> LHSBits(Bits.size()), RHSBits(Bits.size());
- getValueBits(V.getOperand(0), LHSBits);
- getValueBits(V.getOperand(1), RHSBits);
+ const auto &LHSBits = *getValueBits(V.getOperand(0), NumBits).second;
+ const auto &RHSBits = *getValueBits(V.getOperand(1), NumBits).second;
bool AllDisjoint = true;
- for (unsigned i = 0; i < Bits.size(); ++i)
+ for (unsigned i = 0; i < NumBits; ++i)
if (LHSBits[i].isZero())
Bits[i] = RHSBits[i];
else if (RHSBits[i].isZero())
@@ -1002,14 +1028,14 @@ class BitPermutationSelector {
if (!AllDisjoint)
break;
- return true;
+ return std::make_pair(Interesting = true, &Bits);
}
}
- for (unsigned i = 0; i < Bits.size(); ++i)
+ for (unsigned i = 0; i < NumBits; ++i)
Bits[i] = ValueBit(V, i);
- return false;
+ return std::make_pair(Interesting = false, &Bits);
}
// For each value (except the constant ones), compute the left-rotate amount
@@ -1648,9 +1674,12 @@ class BitPermutationSelector {
unsigned NumRLInsts = 0;
bool FirstBG = true;
+ bool MoreBG = false;
for (auto &BG : BitGroups) {
- if (!MatchingBG(BG))
+ if (!MatchingBG(BG)) {
+ MoreBG = true;
continue;
+ }
NumRLInsts +=
SelectRotMask64Count(BG.RLAmt, BG.Repl32, BG.StartIdx, BG.EndIdx,
!FirstBG);
@@ -1668,7 +1697,10 @@ class BitPermutationSelector {
// because that exposes more opportunities for CSE.
if (NumAndInsts > NumRLInsts)
continue;
- if (Use32BitInsts && NumAndInsts == NumRLInsts)
+ // When merging multiple bit groups, instruction or is used.
+ // But when rotate is used, rldimi can inert the rotated value into any
+ // register, so instruction or can be avoided.
+ if ((Use32BitInsts || MoreBG) && NumAndInsts == NumRLInsts)
continue;
DEBUG(dbgs() << "\t\t\t\tusing masking\n");
@@ -1886,8 +1918,7 @@ class BitPermutationSelector {
}
void eraseMatchingBitGroups(function_ref<bool(const BitGroup &)> F) {
- BitGroups.erase(std::remove_if(BitGroups.begin(), BitGroups.end(), F),
- BitGroups.end());
+ BitGroups.erase(remove_if(BitGroups, F), BitGroups.end());
}
SmallVector<ValueBit, 64> Bits;
@@ -1910,9 +1941,12 @@ public:
// rotate-and-shift/shift/and/or instructions, using a set of heuristics
// known to produce optimial code for common cases (like i32 byte swapping).
SDNode *Select(SDNode *N) {
- Bits.resize(N->getValueType(0).getSizeInBits());
- if (!getValueBits(SDValue(N, 0), Bits))
+ Memoizer.clear();
+ auto Result =
+ getValueBits(SDValue(N, 0), N->getValueType(0).getSizeInBits());
+ if (!Result.first)
return nullptr;
+ Bits = std::move(*Result.second);
DEBUG(dbgs() << "Considering bit-permutation-based instruction"
" selection for: ");
@@ -2623,6 +2657,23 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
MB = 64 - countTrailingOnes(Imm64);
SH = 0;
+ if (Val.getOpcode() == ISD::ANY_EXTEND) {
+ auto Op0 = Val.getOperand(0);
+ if ( Op0.getOpcode() == ISD::SRL &&
+ isInt32Immediate(Op0.getOperand(1).getNode(), Imm) && Imm <= MB) {
+
+ auto ResultType = Val.getNode()->getValueType(0);
+ auto ImDef = CurDAG->getMachineNode(PPC::IMPLICIT_DEF, dl,
+ ResultType);
+ SDValue IDVal (ImDef, 0);
+
+ Val = SDValue(CurDAG->getMachineNode(PPC::INSERT_SUBREG, dl,
+ ResultType, IDVal, Op0.getOperand(0),
+ getI32Imm(1, dl)), 0);
+ SH = 64 - Imm;
+ }
+ }
+
// If the operand is a logical right shift, we can fold it into this
// instruction: rldicl(rldicl(x, 64-n, n), 0, mb) -> rldicl(x, 64-n, mb)
// for n <= mb. The right shift is really a left rotate followed by a
@@ -3187,7 +3238,7 @@ SDValue PPCDAGToDAGISel::combineToCMPB(SDNode *N) {
Op0.getOperand(1) == Op1.getOperand(1) && CC == ISD::SETEQ &&
isa<ConstantSDNode>(Op0.getOperand(1))) {
- unsigned Bits = Op0.getValueType().getSizeInBits();
+ unsigned Bits = Op0.getValueSizeInBits();
if (b != Bits/8-1)
return false;
if (Op0.getConstantOperandVal(1) != Bits-8)
@@ -3215,9 +3266,9 @@ SDValue PPCDAGToDAGISel::combineToCMPB(SDNode *N) {
// Now we need to make sure that the upper bytes are known to be
// zero.
- unsigned Bits = Op0.getValueType().getSizeInBits();
- if (!CurDAG->MaskedValueIsZero(Op0,
- APInt::getHighBitsSet(Bits, Bits - (b+1)*8)))
+ unsigned Bits = Op0.getValueSizeInBits();
+ if (!CurDAG->MaskedValueIsZero(
+ Op0, APInt::getHighBitsSet(Bits, Bits - (b + 1) * 8)))
return false;
LHS = Op0.getOperand(0);
@@ -3250,7 +3301,7 @@ SDValue PPCDAGToDAGISel::combineToCMPB(SDNode *N) {
} else if (Op.getOpcode() == ISD::SRL) {
if (!isa<ConstantSDNode>(Op.getOperand(1)))
return false;
- unsigned Bits = Op.getValueType().getSizeInBits();
+ unsigned Bits = Op.getValueSizeInBits();
if (b != Bits/8-1)
return false;
if (Op.getConstantOperandVal(1) != Bits-8)
@@ -3562,7 +3613,8 @@ void PPCDAGToDAGISel::PeepholeCROps() {
Op.getOperand(0) == Op.getOperand(1))
Op2Not = true;
}
- } // fallthrough
+ LLVM_FALLTHROUGH;
+ }
case PPC::BC:
case PPC::BCn:
case PPC::SELECT_I4:
@@ -3989,8 +4041,9 @@ static bool PeepholePPC64ZExtGather(SDValue Op32,
return true;
}
- // CNTLZW always produces a 64-bit value in [0,32], and so is zero extended.
- if (Op32.getMachineOpcode() == PPC::CNTLZW) {
+ // CNT[LT]ZW always produce a 64-bit value in [0,32], and so is zero extended.
+ if (Op32.getMachineOpcode() == PPC::CNTLZW ||
+ Op32.getMachineOpcode() == PPC::CNTTZW) {
ToPromote.insert(Op32.getNode());
return true;
}
@@ -4185,6 +4238,7 @@ void PPCDAGToDAGISel::PeepholePPC64ZExt() {
case PPC::LHBRX: NewOpcode = PPC::LHBRX8; break;
case PPC::LWBRX: NewOpcode = PPC::LWBRX8; break;
case PPC::CNTLZW: NewOpcode = PPC::CNTLZW8; break;
+ case PPC::CNTTZW: NewOpcode = PPC::CNTTZW8; break;
case PPC::RLWIMI: NewOpcode = PPC::RLWIMI8; break;
case PPC::OR: NewOpcode = PPC::OR8; break;
case PPC::SELECT_I4: NewOpcode = PPC::SELECT_I8; break;
@@ -4312,13 +4366,6 @@ void PPCDAGToDAGISel::PeepholePPC64() {
if (!Base.isMachineOpcode())
continue;
- // On targets with fusion, we don't want this to fire and remove a fusion
- // opportunity, unless a) it results in another fusion opportunity or
- // b) optimizing for size.
- if (PPCSubTarget->hasFusion() &&
- (!MF->getFunction()->optForSize() && !Base.hasOneUse()))
- continue;
-
unsigned Flags = 0;
bool ReplaceFlags = true;
@@ -4363,15 +4410,64 @@ void PPCDAGToDAGISel::PeepholePPC64() {
}
SDValue ImmOpnd = Base.getOperand(1);
- int MaxDisplacement = 0;
+
+ // On PPC64, the TOC base pointer is guaranteed by the ABI only to have
+ // 8-byte alignment, and so we can only use offsets less than 8 (otherwise,
+ // we might have needed different @ha relocation values for the offset
+ // pointers).
+ int MaxDisplacement = 7;
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(ImmOpnd)) {
const GlobalValue *GV = GA->getGlobal();
- MaxDisplacement = GV->getAlignment() - 1;
+ MaxDisplacement = std::min((int) GV->getAlignment() - 1, MaxDisplacement);
}
+ bool UpdateHBase = false;
+ SDValue HBase = Base.getOperand(0);
+
int Offset = N->getConstantOperandVal(FirstOp);
- if (Offset < 0 || Offset > MaxDisplacement)
- continue;
+ if (ReplaceFlags) {
+ if (Offset < 0 || Offset > MaxDisplacement) {
+ // If we have a addi(toc@l)/addis(toc@ha) pair, and the addis has only
+ // one use, then we can do this for any offset, we just need to also
+ // update the offset (i.e. the symbol addend) on the addis also.
+ if (Base.getMachineOpcode() != PPC::ADDItocL)
+ continue;
+
+ if (!HBase.isMachineOpcode() ||
+ HBase.getMachineOpcode() != PPC::ADDIStocHA)
+ continue;
+
+ if (!Base.hasOneUse() || !HBase.hasOneUse())
+ continue;
+
+ SDValue HImmOpnd = HBase.getOperand(1);
+ if (HImmOpnd != ImmOpnd)
+ continue;
+
+ UpdateHBase = true;
+ }
+ } else {
+ // If we're directly folding the addend from an addi instruction, then:
+ // 1. In general, the offset on the memory access must be zero.
+ // 2. If the addend is a constant, then it can be combined with a
+ // non-zero offset, but only if the result meets the encoding
+ // requirements.
+ if (auto *C = dyn_cast<ConstantSDNode>(ImmOpnd)) {
+ Offset += C->getSExtValue();
+
+ if ((StorageOpcode == PPC::LWA || StorageOpcode == PPC::LD ||
+ StorageOpcode == PPC::STD) && (Offset % 4) != 0)
+ continue;
+
+ if (!isInt<16>(Offset))
+ continue;
+
+ ImmOpnd = CurDAG->getTargetConstant(Offset, SDLoc(ImmOpnd),
+ ImmOpnd.getValueType());
+ } else if (Offset != 0) {
+ continue;
+ }
+ }
// We found an opportunity. Reverse the operands from the add
// immediate and substitute them into the load or store. If
@@ -4414,6 +4510,10 @@ void PPCDAGToDAGISel::PeepholePPC64() {
(void)CurDAG->UpdateNodeOperands(N, ImmOpnd, Base.getOperand(0),
N->getOperand(2));
+ if (UpdateHBase)
+ (void)CurDAG->UpdateNodeOperands(HBase.getNode(), HBase.getOperand(0),
+ ImmOpnd);
+
// The add-immediate may now be dead, in which case remove it.
if (Base.getNode()->use_empty())
CurDAG->RemoveDeadNode(Base.getNode());
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 9089c6a..2b9195b 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -27,6 +27,7 @@
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
@@ -216,11 +217,17 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FROUND, MVT::f32, Legal);
}
- // PowerPC does not have BSWAP, CTPOP or CTTZ
+ // PowerPC does not have BSWAP
+ // CTPOP or CTTZ were introduced in P8/P9 respectivelly
setOperationAction(ISD::BSWAP, MVT::i32 , Expand);
- setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
setOperationAction(ISD::BSWAP, MVT::i64 , Expand);
- setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
+ if (Subtarget.isISA3_0()) {
+ setOperationAction(ISD::CTTZ , MVT::i32 , Legal);
+ setOperationAction(ISD::CTTZ , MVT::i64 , Legal);
+ } else {
+ setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
+ setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
+ }
if (Subtarget.hasPOPCNTD() == PPCSubtarget::POPCNTD_Fast) {
setOperationAction(ISD::CTPOP, MVT::i32 , Legal);
@@ -433,6 +440,12 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::CTLZ, VT, Expand);
}
+ // Vector instructions introduced in P9
+ if (Subtarget.hasP9Altivec() && (VT.SimpleTy != MVT::v1i128))
+ setOperationAction(ISD::CTTZ, VT, Legal);
+ else
+ setOperationAction(ISD::CTTZ, VT, Expand);
+
// We promote all shuffles to v16i8.
setOperationAction(ISD::VECTOR_SHUFFLE, VT, Promote);
AddPromotedToType (ISD::VECTOR_SHUFFLE, VT, MVT::v16i8);
@@ -489,7 +502,6 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::SCALAR_TO_VECTOR, VT, Expand);
setOperationAction(ISD::FPOW, VT, Expand);
setOperationAction(ISD::BSWAP, VT, Expand);
- setOperationAction(ISD::CTTZ, VT, Expand);
setOperationAction(ISD::VSELECT, VT, Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
setOperationAction(ISD::ROTL, VT, Expand);
@@ -660,6 +672,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
setOperationAction(ISD::FABS, MVT::v4f32, Legal);
setOperationAction(ISD::FABS, MVT::v2f64, Legal);
+ if (Subtarget.hasDirectMove())
+ setOperationAction(ISD::BUILD_VECTOR, MVT::v2i64, Custom);
+ setOperationAction(ISD::BUILD_VECTOR, MVT::v2f64, Custom);
+
addRegisterClass(MVT::v2i64, &PPC::VSRCRegClass);
}
@@ -1061,6 +1077,9 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
case PPCISD::STBRX: return "PPCISD::STBRX";
case PPCISD::LFIWAX: return "PPCISD::LFIWAX";
case PPCISD::LFIWZX: return "PPCISD::LFIWZX";
+ case PPCISD::LXSIZX: return "PPCISD::LXSIZX";
+ case PPCISD::STXSIX: return "PPCISD::STXSIX";
+ case PPCISD::VEXTS: return "PPCISD::VEXTS";
case PPCISD::LXVD2X: return "PPCISD::LXVD2X";
case PPCISD::STXVD2X: return "PPCISD::STXVD2X";
case PPCISD::COND_BRANCH: return "PPCISD::COND_BRANCH";
@@ -1832,9 +1851,9 @@ static void fixupFuncForFI(SelectionDAG &DAG, int FrameIdx, EVT VT) {
return;
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
- unsigned Align = MFI->getObjectAlignment(FrameIdx);
+ unsigned Align = MFI.getObjectAlignment(FrameIdx);
if (Align >= 4)
return;
@@ -2158,6 +2177,55 @@ SDValue PPCTargetLowering::LowerConstantPool(SDValue Op,
return LowerLabelRef(CPIHi, CPILo, IsPIC, DAG);
}
+// For 64-bit PowerPC, prefer the more compact relative encodings.
+// This trades 32 bits per jump table entry for one or two instructions
+// on the jump site.
+unsigned PPCTargetLowering::getJumpTableEncoding() const {
+ if (isJumpTableRelative())
+ return MachineJumpTableInfo::EK_LabelDifference32;
+
+ return TargetLowering::getJumpTableEncoding();
+}
+
+bool PPCTargetLowering::isJumpTableRelative() const {
+ if (Subtarget.isPPC64())
+ return true;
+ return TargetLowering::isJumpTableRelative();
+}
+
+SDValue PPCTargetLowering::getPICJumpTableRelocBase(SDValue Table,
+ SelectionDAG &DAG) const {
+ if (!Subtarget.isPPC64())
+ return TargetLowering::getPICJumpTableRelocBase(Table, DAG);
+
+ switch (getTargetMachine().getCodeModel()) {
+ case CodeModel::Default:
+ case CodeModel::Small:
+ case CodeModel::Medium:
+ return TargetLowering::getPICJumpTableRelocBase(Table, DAG);
+ default:
+ return DAG.getNode(PPCISD::GlobalBaseReg, SDLoc(),
+ getPointerTy(DAG.getDataLayout()));
+ }
+}
+
+const MCExpr *
+PPCTargetLowering::getPICJumpTableRelocBaseExpr(const MachineFunction *MF,
+ unsigned JTI,
+ MCContext &Ctx) const {
+ if (!Subtarget.isPPC64())
+ return TargetLowering::getPICJumpTableRelocBaseExpr(MF, JTI, Ctx);
+
+ switch (getTargetMachine().getCodeModel()) {
+ case CodeModel::Default:
+ case CodeModel::Small:
+ case CodeModel::Medium:
+ return TargetLowering::getPICJumpTableRelocBaseExpr(MF, JTI, Ctx);
+ default:
+ return MCSymbolRefExpr::create(MF->getPICBaseSymbol(), Ctx);
+ }
+}
+
SDValue PPCTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
EVT PtrVT = Op.getValueType();
JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
@@ -2365,20 +2433,10 @@ SDValue PPCTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
// If we're comparing for equality to zero, expose the fact that this is
// implemented as a ctlz/srl pair on ppc, so that the dag combiner can
// fold the new nodes.
+ if (SDValue V = lowerCmpEqZeroToCtlzSrl(Op, DAG))
+ return V;
+
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
- if (C->isNullValue() && CC == ISD::SETEQ) {
- EVT VT = Op.getOperand(0).getValueType();
- SDValue Zext = Op.getOperand(0);
- if (VT.bitsLT(MVT::i32)) {
- VT = MVT::i32;
- Zext = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Op.getOperand(0));
- }
- unsigned Log2b = Log2_32(VT.getSizeInBits());
- SDValue Clz = DAG.getNode(ISD::CTLZ, dl, VT, Zext);
- SDValue Scc = DAG.getNode(ISD::SRL, dl, VT, Clz,
- DAG.getConstant(Log2b, dl, MVT::i32));
- return DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Scc);
- }
// Leave comparisons against 0 and -1 alone for now, since they're usually
// optimized. FIXME: revisit this when we can custom lower all setcc
// optimizations.
@@ -2679,6 +2737,32 @@ bool llvm::CC_PPC32_SVR4_Custom_AlignArgRegs(unsigned &ValNo, MVT &ValVT,
return false;
}
+bool
+llvm::CC_PPC32_SVR4_Custom_SkipLastArgRegsPPCF128(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags,
+ CCState &State) {
+ static const MCPhysReg ArgRegs[] = {
+ PPC::R3, PPC::R4, PPC::R5, PPC::R6,
+ PPC::R7, PPC::R8, PPC::R9, PPC::R10,
+ };
+ const unsigned NumArgRegs = array_lengthof(ArgRegs);
+
+ unsigned RegNum = State.getFirstUnallocated(ArgRegs);
+ int RegsLeft = NumArgRegs - RegNum;
+
+ // Skip if there is not enough registers left for long double type (4 gpr regs
+ // in soft float mode) and put long double argument on the stack.
+ if (RegNum != NumArgRegs && RegsLeft < 4) {
+ for (int i = 0; i < RegsLeft; i++) {
+ State.AllocateReg(ArgRegs[RegNum + i]);
+ }
+ }
+
+ return false;
+}
+
bool llvm::CC_PPC32_SVR4_Custom_AlignFPArgRegs(unsigned &ValNo, MVT &ValVT,
MVT &LocVT,
CCValAssign::LocInfo &LocInfo,
@@ -2896,7 +2980,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
// AltiVec Technology Programming Interface Manual
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
EVT PtrVT = getPointerTy(MF.getDataLayout());
@@ -2956,7 +3040,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
break;
case MVT::v2f64:
case MVT::v2i64:
- RC = &PPC::VSHRCRegClass;
+ RC = &PPC::VRRCRegClass;
break;
case MVT::v4f64:
RC = &PPC::QFRCRegClass;
@@ -2980,8 +3064,8 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
assert(VA.isMemLoc());
unsigned ArgSize = VA.getLocVT().getStoreSize();
- int FI = MFI->CreateFixedObject(ArgSize, VA.getLocMemOffset(),
- isImmutable);
+ int FI = MFI.CreateFixedObject(ArgSize, VA.getLocMemOffset(),
+ isImmutable);
// Create load nodes to retrieve arguments from the stack.
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
@@ -3042,10 +3126,10 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
NumFPArgRegs * MVT(MVT::f64).getSizeInBits()/8;
FuncInfo->setVarArgsStackOffset(
- MFI->CreateFixedObject(PtrVT.getSizeInBits()/8,
- CCInfo.getNextStackOffset(), true));
+ MFI.CreateFixedObject(PtrVT.getSizeInBits()/8,
+ CCInfo.getNextStackOffset(), true));
- FuncInfo->setVarArgsFrameIndex(MFI->CreateStackObject(Depth, 8, false));
+ FuncInfo->setVarArgsFrameIndex(MFI.CreateStackObject(Depth, 8, false));
SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
// The fixed integer arguments of a variadic function are stored to the
@@ -3118,7 +3202,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
bool isELFv2ABI = Subtarget.isELFv2ABI();
bool isLittleEndian = Subtarget.isLittleEndian();
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
assert(!(CallConv == CallingConv::Fast && isVarArg) &&
@@ -3139,10 +3223,6 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
PPC::V2, PPC::V3, PPC::V4, PPC::V5, PPC::V6, PPC::V7, PPC::V8,
PPC::V9, PPC::V10, PPC::V11, PPC::V12, PPC::V13
};
- static const MCPhysReg VSRH[] = {
- PPC::VSH2, PPC::VSH3, PPC::VSH4, PPC::VSH5, PPC::VSH6, PPC::VSH7, PPC::VSH8,
- PPC::VSH9, PPC::VSH10, PPC::VSH11, PPC::VSH12, PPC::VSH13
- };
const unsigned Num_GPR_Regs = array_lengthof(GPR);
const unsigned Num_FPR_Regs = useSoftFloat() ? 0 : 13;
@@ -3231,7 +3311,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
// pretend we have an 8-byte item at the current address for that
// purpose.
if (!ObjSize) {
- int FI = MFI->CreateFixedObject(PtrByteSize, ArgOffset, true);
+ int FI = MFI.CreateFixedObject(PtrByteSize, ArgOffset, true);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
InVals.push_back(FIN);
continue;
@@ -3246,9 +3326,9 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
int FI;
if (HasParameterArea ||
ArgSize + ArgOffset > LinkageSize + Num_GPR_Regs * PtrByteSize)
- FI = MFI->CreateFixedObject(ArgSize, ArgOffset, false, true);
+ FI = MFI.CreateFixedObject(ArgSize, ArgOffset, false, true);
else
- FI = MFI->CreateStackObject(ArgSize, Align, false);
+ FI = MFI.CreateStackObject(ArgSize, Align, false);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
// Handle aggregates smaller than 8 bytes.
@@ -3418,9 +3498,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
// passed directly. The latter are used to implement ELFv2 homogenous
// vector aggregates.
if (VR_idx != Num_VR_Regs) {
- unsigned VReg = (ObjectVT == MVT::v2f64 || ObjectVT == MVT::v2i64) ?
- MF.addLiveIn(VSRH[VR_idx], &PPC::VSHRCRegClass) :
- MF.addLiveIn(VR[VR_idx], &PPC::VRRCRegClass);
+ unsigned VReg = MF.addLiveIn(VR[VR_idx], &PPC::VRRCRegClass);
ArgVal = DAG.getCopyFromReg(Chain, dl, VReg, ObjectVT);
++VR_idx;
} else {
@@ -3469,7 +3547,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
if (needsLoad) {
if (ObjSize < ArgSize && !isLittleEndian)
CurArgOffset += ArgSize - ObjSize;
- int FI = MFI->CreateFixedObject(ObjSize, CurArgOffset, isImmutable);
+ int FI = MFI.CreateFixedObject(ObjSize, CurArgOffset, isImmutable);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
ArgVal = DAG.getLoad(ObjectVT, dl, Chain, FIN, MachinePointerInfo());
}
@@ -3498,7 +3576,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_64SVR4(
int Depth = ArgOffset;
FuncInfo->setVarArgsFrameIndex(
- MFI->CreateFixedObject(PtrByteSize, Depth, true));
+ MFI.CreateFixedObject(PtrByteSize, Depth, true));
SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
// If this function is vararg, store any remaining integer argument regs
@@ -3530,7 +3608,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_Darwin(
// TODO: add description of PPC stack frame format, or at least some docs.
//
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
EVT PtrVT = getPointerTy(MF.getDataLayout());
@@ -3665,7 +3743,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_Darwin(
CurArgOffset = CurArgOffset + (4 - ObjSize);
}
// The value of the object is its address.
- int FI = MFI->CreateFixedObject(ObjSize, CurArgOffset, false, true);
+ int FI = MFI.CreateFixedObject(ObjSize, CurArgOffset, false, true);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
InVals.push_back(FIN);
if (ObjSize==1 || ObjSize==2) {
@@ -3698,7 +3776,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_Darwin(
VReg = MF.addLiveIn(GPR[GPR_idx], &PPC::G8RCRegClass);
else
VReg = MF.addLiveIn(GPR[GPR_idx], &PPC::GPRCRegClass);
- int FI = MFI->CreateFixedObject(PtrByteSize, ArgOffset, true);
+ int FI = MFI.CreateFixedObject(PtrByteSize, ArgOffset, true);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT);
SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN,
@@ -3735,7 +3813,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_Darwin(
ArgOffset += PtrByteSize;
break;
}
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case MVT::i64: // PPC64
if (GPR_idx != Num_GPR_Regs) {
unsigned VReg = MF.addLiveIn(GPR[GPR_idx], &PPC::G8RCRegClass);
@@ -3819,9 +3897,9 @@ SDValue PPCTargetLowering::LowerFormalArguments_Darwin(
// We need to load the argument to a virtual register if we determined above
// that we ran out of physical registers of the appropriate type.
if (needsLoad) {
- int FI = MFI->CreateFixedObject(ObjSize,
- CurArgOffset + (ArgSize - ObjSize),
- isImmutable);
+ int FI = MFI.CreateFixedObject(ObjSize,
+ CurArgOffset + (ArgSize - ObjSize),
+ isImmutable);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
ArgVal = DAG.getLoad(ObjectVT, dl, Chain, FIN, MachinePointerInfo());
}
@@ -3852,8 +3930,8 @@ SDValue PPCTargetLowering::LowerFormalArguments_Darwin(
int Depth = ArgOffset;
FuncInfo->setVarArgsFrameIndex(
- MFI->CreateFixedObject(PtrVT.getSizeInBits()/8,
- Depth, true));
+ MFI.CreateFixedObject(PtrVT.getSizeInBits()/8,
+ Depth, true));
SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
// If this function is vararg, store any remaining integer argument regs
@@ -3903,40 +3981,46 @@ static int CalculateTailCallSPDiff(SelectionDAG& DAG, bool isTailCall,
static bool isFunctionGlobalAddress(SDValue Callee);
static bool
-resideInSameModule(SDValue Callee, Reloc::Model RelMod) {
+resideInSameSection(const Function *Caller, SDValue Callee,
+ const TargetMachine &TM) {
// If !G, Callee can be an external symbol.
GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee);
- if (!G) return false;
+ if (!G)
+ return false;
const GlobalValue *GV = G->getGlobal();
-
- if (GV->isDeclaration()) return false;
-
- switch(GV->getLinkage()) {
- default: llvm_unreachable("unknow linkage type");
- case GlobalValue::AvailableExternallyLinkage:
- case GlobalValue::ExternalWeakLinkage:
+ if (!GV->isStrongDefinitionForLinker())
return false;
- // Callee with weak linkage is allowed if it has hidden or protected
- // visibility
- case GlobalValue::LinkOnceAnyLinkage:
- case GlobalValue::LinkOnceODRLinkage: // e.g. c++ inline functions
- case GlobalValue::WeakAnyLinkage:
- case GlobalValue::WeakODRLinkage: // e.g. c++ template instantiation
- if (GV->hasDefaultVisibility())
+ // Any explicitly-specified sections and section prefixes must also match.
+ // Also, if we're using -ffunction-sections, then each function is always in
+ // a different section (the same is true for COMDAT functions).
+ if (TM.getFunctionSections() || GV->hasComdat() || Caller->hasComdat() ||
+ GV->getSection() != Caller->getSection())
+ return false;
+ if (const auto *F = dyn_cast<Function>(GV)) {
+ if (F->getSectionPrefix() != Caller->getSectionPrefix())
return false;
-
- case GlobalValue::ExternalLinkage:
- case GlobalValue::InternalLinkage:
- case GlobalValue::PrivateLinkage:
- break;
}
- // With '-fPIC', calling default visiblity function need insert 'nop' after
- // function call, no matter that function resides in same module or not, so
- // we treat it as in different module.
- if (RelMod == Reloc::PIC_ && GV->hasDefaultVisibility())
+ // If the callee might be interposed, then we can't assume the ultimate call
+ // target will be in the same section. Even in cases where we can assume that
+ // interposition won't happen, in any case where the linker might insert a
+ // stub to allow for interposition, we must generate code as though
+ // interposition might occur. To understand why this matters, consider a
+ // situation where: a -> b -> c where the arrows indicate calls. b and c are
+ // in the same section, but a is in a different module (i.e. has a different
+ // TOC base pointer). If the linker allows for interposition between b and c,
+ // then it will generate a stub for the call edge between b and c which will
+ // save the TOC pointer into the designated stack slot allocated by b. If we
+ // return true here, and therefore allow a tail call between b and c, that
+ // stack slot won't exist and the b -> c stub will end up saving b'c TOC base
+ // pointer into the stack slot allocated by a (where the a -> b stub saved
+ // a's TOC base pointer). If we're not considering a tail call, but rather,
+ // whether a nop is needed after the call instruction in b, because the linker
+ // will insert a stub, it might complain about a missing nop if we omit it
+ // (although many don't complain in this case).
+ if (!TM.shouldAssumeDSOLocal(*Caller->getParent(), GV))
return false;
return true;
@@ -4037,8 +4121,7 @@ PPCTargetLowering::IsEligibleForTailCallOptimization_64SVR4(
return false;
// Caller contains any byval parameter is not supported.
- if (std::any_of(Ins.begin(), Ins.end(),
- [](const ISD::InputArg& IA) { return IA.Flags.isByVal(); }))
+ if (any_of(Ins, [](const ISD::InputArg &IA) { return IA.Flags.isByVal(); }))
return false;
// Callee contains any byval parameter is not supported, too.
@@ -4053,11 +4136,11 @@ PPCTargetLowering::IsEligibleForTailCallOptimization_64SVR4(
!isa<ExternalSymbolSDNode>(Callee))
return false;
- // Check if Callee resides in the same module, because for now, PPC64 SVR4 ABI
- // (ELFv1/ELFv2) doesn't allow tail calls to a symbol resides in another
- // module.
+ // Check if Callee resides in the same section, because for now, PPC64 SVR4
+ // ABI (ELFv1/ELFv2) doesn't allow tail calls to a symbol resides in another
+ // section.
// ref: https://bugzilla.mozilla.org/show_bug.cgi?id=973977
- if (!resideInSameModule(Callee, getTargetMachine().getRelocationModel()))
+ if (!resideInSameSection(MF.getFunction(), Callee, getTargetMachine()))
return false;
// TCO allows altering callee ABI, so we don't have to check further.
@@ -4174,8 +4257,8 @@ static SDValue EmitTailCallStoreFPAndRetAddr(SelectionDAG &DAG, SDValue Chain,
bool isPPC64 = Subtarget.isPPC64();
int SlotSize = isPPC64 ? 8 : 4;
int NewRetAddrLoc = SPDiff + FL->getReturnSaveOffset();
- int NewRetAddr = MF.getFrameInfo()->CreateFixedObject(SlotSize,
- NewRetAddrLoc, true);
+ int NewRetAddr = MF.getFrameInfo().CreateFixedObject(SlotSize,
+ NewRetAddrLoc, true);
EVT VT = isPPC64 ? MVT::i64 : MVT::i32;
SDValue NewRetAddrFrIdx = DAG.getFrameIndex(NewRetAddr, VT);
Chain = DAG.getStore(Chain, dl, OldRetAddr, NewRetAddrFrIdx,
@@ -4185,8 +4268,8 @@ static SDValue EmitTailCallStoreFPAndRetAddr(SelectionDAG &DAG, SDValue Chain,
// slot as the FP is never overwritten.
if (Subtarget.isDarwinABI()) {
int NewFPLoc = SPDiff + FL->getFramePointerSaveOffset();
- int NewFPIdx = MF.getFrameInfo()->CreateFixedObject(SlotSize, NewFPLoc,
- true);
+ int NewFPIdx = MF.getFrameInfo().CreateFixedObject(SlotSize, NewFPLoc,
+ true);
SDValue NewFramePtrIdx = DAG.getFrameIndex(NewFPIdx, VT);
Chain = DAG.getStore(Chain, dl, OldFP, NewFramePtrIdx,
MachinePointerInfo::getFixedStack(
@@ -4203,8 +4286,8 @@ CalculateTailCallArgDest(SelectionDAG &DAG, MachineFunction &MF, bool isPPC64,
SDValue Arg, int SPDiff, unsigned ArgOffset,
SmallVectorImpl<TailCallArgumentInfo>& TailCallArguments) {
int Offset = ArgOffset + SPDiff;
- uint32_t OpSize = (Arg.getValueType().getSizeInBits()+7)/8;
- int FI = MF.getFrameInfo()->CreateFixedObject(OpSize, Offset, true);
+ uint32_t OpSize = (Arg.getValueSizeInBits() + 7) / 8;
+ int FI = MF.getFrameInfo().CreateFixedObject(OpSize, Offset, true);
EVT VT = isPPC64 ? MVT::i64 : MVT::i32;
SDValue FIN = DAG.getFrameIndex(FI, VT);
TailCallArgumentInfo Info;
@@ -4430,7 +4513,8 @@ PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag, SDValue &Chain,
LDChain = CallSeqStart.getValue(CallSeqStart->getNumValues()-2);
auto MMOFlags = Subtarget.hasInvariantFunctionDescriptors()
- ? MachineMemOperand::MOInvariant
+ ? (MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant)
: MachineMemOperand::MONone;
MachinePointerInfo MPI(CS ? CS->getCalledValue() : nullptr);
@@ -4514,14 +4598,6 @@ PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag, SDValue &Chain,
return CallOpc;
}
-static
-bool isLocalCall(const SDValue &Callee)
-{
- if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
- return G->getGlobal()->isStrongDefinitionForLinker();
- return false;
-}
-
SDValue PPCTargetLowering::LowerCallResult(
SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
@@ -4610,7 +4686,7 @@ SDValue PPCTargetLowering::FinishCall(
isa<ConstantSDNode>(Callee)) &&
"Expecting an global address, external symbol, absolute value or register");
- DAG.getMachineFunction().getFrameInfo()->setHasTailCall();
+ DAG.getMachineFunction().getFrameInfo().setHasTailCall();
return DAG.getNode(PPCISD::TC_RETURN, dl, MVT::Other, Ops);
}
@@ -4623,6 +4699,7 @@ SDValue PPCTargetLowering::FinishCall(
// stack frame. If caller and callee belong to the same module (and have the
// same TOC), the NOP will remain unchanged.
+ MachineFunction &MF = DAG.getMachineFunction();
if (!isTailCall && Subtarget.isSVR4ABI()&& Subtarget.isPPC64() &&
!isPatchPoint) {
if (CallOpc == PPCISD::BCTRL) {
@@ -4646,11 +4723,11 @@ SDValue PPCTargetLowering::FinishCall(
// The address needs to go after the chain input but before the flag (or
// any other variadic arguments).
Ops.insert(std::next(Ops.begin()), AddTOC);
- } else if ((CallOpc == PPCISD::CALL) &&
- (!isLocalCall(Callee) ||
- DAG.getTarget().getRelocationModel() == Reloc::PIC_))
+ } else if (CallOpc == PPCISD::CALL &&
+ !resideInSameSection(MF.getFunction(), Callee, DAG.getTarget())) {
// Otherwise insert NOP for non-local calls.
CallOpc = PPCISD::CALL_NOP;
+ }
}
Chain = DAG.getNode(CallOpc, dl, NodeTys, Ops);
@@ -5026,10 +5103,6 @@ SDValue PPCTargetLowering::LowerCall_64SVR4(
PPC::V2, PPC::V3, PPC::V4, PPC::V5, PPC::V6, PPC::V7, PPC::V8,
PPC::V9, PPC::V10, PPC::V11, PPC::V12, PPC::V13
};
- static const MCPhysReg VSRH[] = {
- PPC::VSH2, PPC::VSH3, PPC::VSH4, PPC::VSH5, PPC::VSH6, PPC::VSH7, PPC::VSH8,
- PPC::VSH9, PPC::VSH10, PPC::VSH11, PPC::VSH12, PPC::VSH13
- };
const unsigned NumGPRs = array_lengthof(GPR);
const unsigned NumFPRs = 13;
@@ -5456,13 +5529,7 @@ SDValue PPCTargetLowering::LowerCall_64SVR4(
SDValue Load =
DAG.getLoad(MVT::v4f32, dl, Store, PtrOff, MachinePointerInfo());
MemOpChains.push_back(Load.getValue(1));
-
- unsigned VReg = (Arg.getSimpleValueType() == MVT::v2f64 ||
- Arg.getSimpleValueType() == MVT::v2i64) ?
- VSRH[VR_idx] : VR[VR_idx];
- ++VR_idx;
-
- RegsToPass.push_back(std::make_pair(VReg, Load));
+ RegsToPass.push_back(std::make_pair(VR[VR_idx++], Load));
}
ArgOffset += 16;
for (unsigned i=0; i<16; i+=PtrByteSize) {
@@ -5480,12 +5547,7 @@ SDValue PPCTargetLowering::LowerCall_64SVR4(
// Non-varargs Altivec params go into VRs or on the stack.
if (VR_idx != NumVRs) {
- unsigned VReg = (Arg.getSimpleValueType() == MVT::v2f64 ||
- Arg.getSimpleValueType() == MVT::v2i64) ?
- VSRH[VR_idx] : VR[VR_idx];
- ++VR_idx;
-
- RegsToPass.push_back(std::make_pair(VReg, Arg));
+ RegsToPass.push_back(std::make_pair(VR[VR_idx++], Arg));
} else {
if (CallConv == CallingConv::Fast)
ComputePtrOff();
@@ -6126,7 +6188,7 @@ SDValue PPCTargetLowering::getReturnAddrFrameIndex(SelectionDAG &DAG) const {
// Find out what the fix offset of the frame pointer save area.
int LROffset = Subtarget.getFrameLowering()->getReturnSaveOffset();
// Allocate the frame index for frame pointer save area.
- RASI = MF.getFrameInfo()->CreateFixedObject(isPPC64? 8 : 4, LROffset, false);
+ RASI = MF.getFrameInfo().CreateFixedObject(isPPC64? 8 : 4, LROffset, false);
// Save the result.
FI->setReturnAddrSaveIndex(RASI);
}
@@ -6149,7 +6211,7 @@ PPCTargetLowering::getFramePointerFrameIndex(SelectionDAG & DAG) const {
// Find out what the fix offset of the frame pointer save area.
int FPOffset = Subtarget.getFrameLowering()->getFramePointerSaveOffset();
// Allocate the frame index for frame pointer save area.
- FPSI = MF.getFrameInfo()->CreateFixedObject(isPPC64? 8 : 4, FPOffset, true);
+ FPSI = MF.getFrameInfo().CreateFixedObject(isPPC64? 8 : 4, FPOffset, true);
// Save the result.
FI->setFramePointerSaveIndex(FPSI);
}
@@ -6183,7 +6245,7 @@ SDValue PPCTargetLowering::LowerEH_DWARF_CFA(SDValue Op,
bool isPPC64 = Subtarget.isPPC64();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
- int FI = MF.getFrameInfo()->CreateFixedObject(isPPC64 ? 8 : 4, 0, false);
+ int FI = MF.getFrameInfo().CreateFixedObject(isPPC64 ? 8 : 4, 0, false);
return DAG.getFrameIndex(FI, PtrVT);
}
@@ -6467,10 +6529,7 @@ SDValue PPCTargetLowering::LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG,
LowerFP_TO_INTForReuse(Op, RLI, DAG, dl);
return DAG.getLoad(Op.getValueType(), dl, RLI.Chain, RLI.Ptr, RLI.MPI,
- RLI.Alignment,
- RLI.IsInvariant ? MachineMemOperand::MOInvariant
- : MachineMemOperand::MONone,
- RLI.AAInfo, RLI.Ranges);
+ RLI.Alignment, RLI.MMOFlags(), RLI.AAInfo, RLI.Ranges);
}
// We're trying to insert a regular store, S, and then a load, L. If the
@@ -6513,6 +6572,7 @@ bool PPCTargetLowering::canReuseLoadAddress(SDValue Op, EVT MemVT,
RLI.Chain = LD->getChain();
RLI.MPI = LD->getPointerInfo();
+ RLI.IsDereferenceable = LD->isDereferenceable();
RLI.IsInvariant = LD->isInvariant();
RLI.Alignment = LD->getAlignment();
RLI.AAInfo = LD->getAAInfo();
@@ -6545,11 +6605,17 @@ void PPCTargetLowering::spliceIntoChain(SDValue ResChain,
/// \brief Analyze profitability of direct move
/// prefer float load to int load plus direct move
/// when there is no integer use of int load
-static bool directMoveIsProfitable(const SDValue &Op) {
+bool PPCTargetLowering::directMoveIsProfitable(const SDValue &Op) const {
SDNode *Origin = Op.getOperand(0).getNode();
if (Origin->getOpcode() != ISD::LOAD)
return true;
+ // If there is no LXSIBZX/LXSIHZX, like Power8,
+ // prefer direct move if the memory size is 1 or 2 bytes.
+ MachineMemOperand *MMO = cast<LoadSDNode>(Origin)->getMemOperand();
+ if (!Subtarget.hasP9Vector() && MMO->getSize() <= 2)
+ return true;
+
for (SDNode::use_iterator UI = Origin->use_begin(),
UE = Origin->use_end();
UI != UE; ++UI) {
@@ -6705,11 +6771,8 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op,
MachineFunction &MF = DAG.getMachineFunction();
if (canReuseLoadAddress(SINT, MVT::i64, RLI, DAG)) {
- Bits =
- DAG.getLoad(MVT::f64, dl, RLI.Chain, RLI.Ptr, RLI.MPI, RLI.Alignment,
- RLI.IsInvariant ? MachineMemOperand::MOInvariant
- : MachineMemOperand::MONone,
- RLI.AAInfo, RLI.Ranges);
+ Bits = DAG.getLoad(MVT::f64, dl, RLI.Chain, RLI.Ptr, RLI.MPI,
+ RLI.Alignment, RLI.MMOFlags(), RLI.AAInfo, RLI.Ranges);
spliceIntoChain(RLI.ResChain, Bits.getValue(1), DAG);
} else if (Subtarget.hasLFIWAX() &&
canReuseLoadAddress(SINT, MVT::i32, RLI, DAG, ISD::SEXTLOAD)) {
@@ -6736,10 +6799,10 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op,
(Subtarget.hasFPCVT() &&
SINT.getOpcode() == ISD::ZERO_EXTEND)) &&
SINT.getOperand(0).getValueType() == MVT::i32) {
- MachineFrameInfo *FrameInfo = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
- int FrameIdx = FrameInfo->CreateStackObject(4, 4, false);
+ int FrameIdx = MFI.CreateStackObject(4, 4, false);
SDValue FIdx = DAG.getFrameIndex(FrameIdx, PtrVT);
SDValue Store =
@@ -6782,7 +6845,7 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op,
// 64-bit register with extsw, store the WHOLE 64-bit value into the stack
// then lfd it and fcfid it.
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *FrameInfo = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
EVT PtrVT = getPointerTy(MF.getDataLayout());
SDValue Ld;
@@ -6791,7 +6854,7 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op,
bool ReusingLoad;
if (!(ReusingLoad = canReuseLoadAddress(Op.getOperand(0), MVT::i32, RLI,
DAG))) {
- int FrameIdx = FrameInfo->CreateStackObject(4, 4, false);
+ int FrameIdx = MFI.CreateStackObject(4, 4, false);
SDValue FIdx = DAG.getFrameIndex(FrameIdx, PtrVT);
SDValue Store =
@@ -6823,7 +6886,7 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op,
assert(Subtarget.isPPC64() &&
"i32->FP without LFIWAX supported only on PPC64");
- int FrameIdx = FrameInfo->CreateStackObject(8, 8, false);
+ int FrameIdx = MFI.CreateStackObject(8, 8, false);
SDValue FIdx = DAG.getFrameIndex(FrameIdx, PtrVT);
SDValue Ext64 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::i64,
@@ -6882,7 +6945,7 @@ SDValue PPCTargetLowering::LowerFLT_ROUNDS_(SDValue Op,
SDValue Chain = DAG.getNode(PPCISD::MFFS, dl, NodeTys, None);
// Save FP register to stack slot
- int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8, false);
+ int SSFI = MF.getFrameInfo().CreateStackObject(8, 8, false);
SDValue StackSlot = DAG.getFrameIndex(SSFI, PtrVT);
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Chain, StackSlot,
MachinePointerInfo());
@@ -7068,6 +7131,57 @@ static SDValue BuildVSLDOI(SDValue LHS, SDValue RHS, unsigned Amt, EVT VT,
return DAG.getNode(ISD::BITCAST, dl, VT, T);
}
+/// Do we have an efficient pattern in a .td file for this node?
+///
+/// \param V - pointer to the BuildVectorSDNode being matched
+/// \param HasDirectMove - does this subtarget have VSR <-> GPR direct moves?
+///
+/// There are some patterns where it is beneficial to keep a BUILD_VECTOR
+/// node as a BUILD_VECTOR node rather than expanding it. The patterns where
+/// the opposite is true (expansion is beneficial) are:
+/// - The node builds a vector out of integers that are not 32 or 64-bits
+/// - The node builds a vector out of constants
+/// - The node is a "load-and-splat"
+/// In all other cases, we will choose to keep the BUILD_VECTOR.
+static bool haveEfficientBuildVectorPattern(BuildVectorSDNode *V,
+ bool HasDirectMove) {
+ EVT VecVT = V->getValueType(0);
+ bool RightType = VecVT == MVT::v2f64 || VecVT == MVT::v4f32 ||
+ (HasDirectMove && (VecVT == MVT::v2i64 || VecVT == MVT::v4i32));
+ if (!RightType)
+ return false;
+
+ bool IsSplat = true;
+ bool IsLoad = false;
+ SDValue Op0 = V->getOperand(0);
+
+ // This function is called in a block that confirms the node is not a constant
+ // splat. So a constant BUILD_VECTOR here means the vector is built out of
+ // different constants.
+ if (V->isConstant())
+ return false;
+ for (int i = 0, e = V->getNumOperands(); i < e; ++i) {
+ if (V->getOperand(i).isUndef())
+ return false;
+ // We want to expand nodes that represent load-and-splat even if the
+ // loaded value is a floating point truncation or conversion to int.
+ if (V->getOperand(i).getOpcode() == ISD::LOAD ||
+ (V->getOperand(i).getOpcode() == ISD::FP_ROUND &&
+ V->getOperand(i).getOperand(0).getOpcode() == ISD::LOAD) ||
+ (V->getOperand(i).getOpcode() == ISD::FP_TO_SINT &&
+ V->getOperand(i).getOperand(0).getOpcode() == ISD::LOAD) ||
+ (V->getOperand(i).getOpcode() == ISD::FP_TO_UINT &&
+ V->getOperand(i).getOperand(0).getOpcode() == ISD::LOAD))
+ IsLoad = true;
+ // If the operands are different or the input is not a load and has more
+ // uses than just this BV node, then it isn't a splat.
+ if (V->getOperand(i) != Op0 ||
+ (!IsLoad && !V->isOnlyUserOf(V->getOperand(i).getNode())))
+ IsSplat = false;
+ }
+ return !(IsSplat && IsLoad);
+}
+
// If this is a case we can't handle, return null and let the default
// expansion code take care of it. If we CAN select this case, and if it
// selects to a single instruction, return Op. Otherwise, if we can codegen
@@ -7083,8 +7197,8 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op,
// We first build an i32 vector, load it into a QPX register,
// then convert it to a floating-point vector and compare it
// to a zero vector to get the boolean result.
- MachineFrameInfo *FrameInfo = DAG.getMachineFunction().getFrameInfo();
- int FrameIdx = FrameInfo->CreateStackObject(16, 16, false);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ int FrameIdx = MFI.CreateStackObject(16, 16, false);
MachinePointerInfo PtrInfo =
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FrameIdx);
EVT PtrVT = getPointerTy(DAG.getDataLayout());
@@ -7189,8 +7303,15 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op,
bool HasAnyUndefs;
if (! BVN->isConstantSplat(APSplatBits, APSplatUndef, SplatBitSize,
HasAnyUndefs, 0, !Subtarget.isLittleEndian()) ||
- SplatBitSize > 32)
+ SplatBitSize > 32) {
+ // BUILD_VECTOR nodes that are not constant splats of up to 32-bits can be
+ // lowered to VSX instructions under certain conditions.
+ // Without VSX, there is no pattern more efficient than expanding the node.
+ if (Subtarget.hasVSX() &&
+ haveEfficientBuildVectorPattern(BVN, Subtarget.hasDirectMove()))
+ return Op;
return SDValue();
+ }
unsigned SplatBits = APSplatBits.getZExtValue();
unsigned SplatUndef = APSplatUndef.getZExtValue();
@@ -7208,6 +7329,22 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op,
return Op;
}
+ // We have XXSPLTIB for constant splats one byte wide
+ if (Subtarget.hasP9Vector() && SplatSize == 1) {
+ // This is a splat of 1-byte elements with some elements potentially undef.
+ // Rather than trying to match undef in the SDAG patterns, ensure that all
+ // elements are the same constant.
+ if (HasAnyUndefs || ISD::isBuildVectorAllOnes(BVN)) {
+ SmallVector<SDValue, 16> Ops(16, DAG.getConstant(SplatBits,
+ dl, MVT::i32));
+ SDValue NewBV = DAG.getBuildVector(MVT::v16i8, dl, Ops);
+ if (Op.getValueType() != MVT::v16i8)
+ return DAG.getBitcast(Op.getValueType(), NewBV);
+ return NewBV;
+ }
+ return Op;
+ }
+
// If the sign extended value is in the range [-16,15], use VSPLTI[bhw].
int32_t SextVal= (int32_t(SplatBits << (32-SplatBitSize)) >>
(32-SplatBitSize));
@@ -7451,6 +7588,18 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
if (Subtarget.hasVSX()) {
if (V2.isUndef() && PPC::isSplatShuffleMask(SVOp, 4)) {
int SplatIdx = PPC::getVSPLTImmediate(SVOp, 4, DAG);
+
+ // If the source for the shuffle is a scalar_to_vector that came from a
+ // 32-bit load, it will have used LXVWSX so we don't need to splat again.
+ if (Subtarget.hasP9Vector() &&
+ ((isLittleEndian && SplatIdx == 3) ||
+ (!isLittleEndian && SplatIdx == 0))) {
+ SDValue Src = V1.getOperand(0);
+ if (Src.getOpcode() == ISD::SCALAR_TO_VECTOR &&
+ Src.getOperand(0).getOpcode() == ISD::LOAD &&
+ Src.getOperand(0).hasOneUse())
+ return V1;
+ }
SDValue Conv = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, V1);
SDValue Splat = DAG.getNode(PPCISD::XXSPLT, dl, MVT::v4i32, Conv,
DAG.getConstant(SplatIdx, dl, MVT::i32));
@@ -7662,6 +7811,27 @@ static bool getVectorCompareInfo(SDValue Intrin, int &CompareOpc,
return false;
break;
+ case Intrinsic::ppc_altivec_vcmpneb_p:
+ case Intrinsic::ppc_altivec_vcmpneh_p:
+ case Intrinsic::ppc_altivec_vcmpnew_p:
+ case Intrinsic::ppc_altivec_vcmpnezb_p:
+ case Intrinsic::ppc_altivec_vcmpnezh_p:
+ case Intrinsic::ppc_altivec_vcmpnezw_p:
+ if (Subtarget.hasP9Altivec()) {
+ switch(IntrinsicID) {
+ default: llvm_unreachable("Unknown comparison intrinsic.");
+ case Intrinsic::ppc_altivec_vcmpneb_p: CompareOpc = 7; break;
+ case Intrinsic::ppc_altivec_vcmpneh_p: CompareOpc = 71; break;
+ case Intrinsic::ppc_altivec_vcmpnew_p: CompareOpc = 135; break;
+ case Intrinsic::ppc_altivec_vcmpnezb_p: CompareOpc = 263; break;
+ case Intrinsic::ppc_altivec_vcmpnezh_p: CompareOpc = 327; break;
+ case Intrinsic::ppc_altivec_vcmpnezw_p: CompareOpc = 391; break;
+ }
+ isDot = 1;
+ } else
+ return false;
+
+ break;
case Intrinsic::ppc_altivec_vcmpgefp_p: CompareOpc = 454; isDot = 1; break;
case Intrinsic::ppc_altivec_vcmpgtfp_p: CompareOpc = 710; isDot = 1; break;
case Intrinsic::ppc_altivec_vcmpgtsb_p: CompareOpc = 774; isDot = 1; break;
@@ -7723,6 +7893,26 @@ static bool getVectorCompareInfo(SDValue Intrin, int &CompareOpc,
return false;
break;
+ case Intrinsic::ppc_altivec_vcmpneb:
+ case Intrinsic::ppc_altivec_vcmpneh:
+ case Intrinsic::ppc_altivec_vcmpnew:
+ case Intrinsic::ppc_altivec_vcmpnezb:
+ case Intrinsic::ppc_altivec_vcmpnezh:
+ case Intrinsic::ppc_altivec_vcmpnezw:
+ if (Subtarget.hasP9Altivec()) {
+ switch (IntrinsicID) {
+ default: llvm_unreachable("Unknown comparison intrinsic.");
+ case Intrinsic::ppc_altivec_vcmpneb: CompareOpc = 7; break;
+ case Intrinsic::ppc_altivec_vcmpneh: CompareOpc = 71; break;
+ case Intrinsic::ppc_altivec_vcmpnew: CompareOpc = 135; break;
+ case Intrinsic::ppc_altivec_vcmpnezb: CompareOpc = 263; break;
+ case Intrinsic::ppc_altivec_vcmpnezh: CompareOpc = 327; break;
+ case Intrinsic::ppc_altivec_vcmpnezw: CompareOpc = 391; break;
+ }
+ isDot = 0;
+ } else
+ return false;
+ break;
case Intrinsic::ppc_altivec_vcmpgefp: CompareOpc = 454; isDot = 0; break;
case Intrinsic::ppc_altivec_vcmpgtfp: CompareOpc = 710; isDot = 0; break;
case Intrinsic::ppc_altivec_vcmpgtsb: CompareOpc = 774; isDot = 0; break;
@@ -7857,8 +8047,8 @@ SDValue PPCTargetLowering::LowerSCALAR_TO_VECTOR(SDValue Op,
SelectionDAG &DAG) const {
SDLoc dl(Op);
// Create a stack slot that is 16-byte aligned.
- MachineFrameInfo *FrameInfo = DAG.getMachineFunction().getFrameInfo();
- int FrameIdx = FrameInfo->CreateStackObject(16, 16, false);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ int FrameIdx = MFI.CreateStackObject(16, 16, false);
EVT PtrVT = getPointerTy(DAG.getDataLayout());
SDValue FIdx = DAG.getFrameIndex(FrameIdx, PtrVT);
@@ -7909,8 +8099,8 @@ SDValue PPCTargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
DAG.getConstant(Intrinsic::ppc_qpx_qvfctiwu, dl, MVT::i32),
Value);
- MachineFrameInfo *FrameInfo = DAG.getMachineFunction().getFrameInfo();
- int FrameIdx = FrameInfo->CreateStackObject(16, 16, false);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ int FrameIdx = MFI.CreateStackObject(16, 16, false);
MachinePointerInfo PtrInfo =
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FrameIdx);
EVT PtrVT = getPointerTy(DAG.getDataLayout());
@@ -8109,8 +8299,8 @@ SDValue PPCTargetLowering::LowerVectorStore(SDValue Op,
DAG.getConstant(Intrinsic::ppc_qpx_qvfctiwu, dl, MVT::i32),
Value);
- MachineFrameInfo *FrameInfo = DAG.getMachineFunction().getFrameInfo();
- int FrameIdx = FrameInfo->CreateStackObject(16, 16, false);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ int FrameIdx = MFI.CreateStackObject(16, 16, false);
MachinePointerInfo PtrInfo =
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FrameIdx);
EVT PtrVT = getPointerTy(DAG.getDataLayout());
@@ -8545,6 +8735,7 @@ PPCTargetLowering::EmitPartwordAtomicBinary(MachineInstr &MI,
// registers without caring whether they're 32 or 64, but here we're
// doing actual arithmetic on the addresses.
bool is64bit = Subtarget.isPPC64();
+ bool isLittleEndian = Subtarget.isLittleEndian();
unsigned ZeroReg = is64bit ? PPC::ZERO8 : PPC::ZERO;
const BasicBlock *LLVM_BB = BB->getBasicBlock();
@@ -8574,7 +8765,8 @@ PPCTargetLowering::EmitPartwordAtomicBinary(MachineInstr &MI,
: &PPC::GPRCRegClass;
unsigned PtrReg = RegInfo.createVirtualRegister(RC);
unsigned Shift1Reg = RegInfo.createVirtualRegister(RC);
- unsigned ShiftReg = RegInfo.createVirtualRegister(RC);
+ unsigned ShiftReg =
+ isLittleEndian ? Shift1Reg : RegInfo.createVirtualRegister(RC);
unsigned Incr2Reg = RegInfo.createVirtualRegister(RC);
unsigned MaskReg = RegInfo.createVirtualRegister(RC);
unsigned Mask2Reg = RegInfo.createVirtualRegister(RC);
@@ -8619,8 +8811,9 @@ PPCTargetLowering::EmitPartwordAtomicBinary(MachineInstr &MI,
}
BuildMI(BB, dl, TII->get(PPC::RLWINM), Shift1Reg).addReg(Ptr1Reg)
.addImm(3).addImm(27).addImm(is8bit ? 28 : 27);
- BuildMI(BB, dl, TII->get(is64bit ? PPC::XORI8 : PPC::XORI), ShiftReg)
- .addReg(Shift1Reg).addImm(is8bit ? 24 : 16);
+ if (!isLittleEndian)
+ BuildMI(BB, dl, TII->get(is64bit ? PPC::XORI8 : PPC::XORI), ShiftReg)
+ .addReg(Shift1Reg).addImm(is8bit ? 24 : 16);
if (is64bit)
BuildMI(BB, dl, TII->get(PPC::RLDICR), PtrReg)
.addReg(Ptr1Reg).addImm(0).addImm(61);
@@ -9325,6 +9518,7 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
// since we're actually doing arithmetic on them. Other registers
// can be 32-bit.
bool is64bit = Subtarget.isPPC64();
+ bool isLittleEndian = Subtarget.isLittleEndian();
bool is8bit = MI.getOpcode() == PPC::ATOMIC_CMP_SWAP_I8;
unsigned dest = MI.getOperand(0).getReg();
@@ -9351,7 +9545,8 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
: &PPC::GPRCRegClass;
unsigned PtrReg = RegInfo.createVirtualRegister(RC);
unsigned Shift1Reg = RegInfo.createVirtualRegister(RC);
- unsigned ShiftReg = RegInfo.createVirtualRegister(RC);
+ unsigned ShiftReg =
+ isLittleEndian ? Shift1Reg : RegInfo.createVirtualRegister(RC);
unsigned NewVal2Reg = RegInfo.createVirtualRegister(RC);
unsigned NewVal3Reg = RegInfo.createVirtualRegister(RC);
unsigned OldVal2Reg = RegInfo.createVirtualRegister(RC);
@@ -9406,8 +9601,9 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
}
BuildMI(BB, dl, TII->get(PPC::RLWINM), Shift1Reg).addReg(Ptr1Reg)
.addImm(3).addImm(27).addImm(is8bit ? 28 : 27);
- BuildMI(BB, dl, TII->get(is64bit ? PPC::XORI8 : PPC::XORI), ShiftReg)
- .addReg(Shift1Reg).addImm(is8bit ? 24 : 16);
+ if (!isLittleEndian)
+ BuildMI(BB, dl, TII->get(is64bit ? PPC::XORI8 : PPC::XORI), ShiftReg)
+ .addReg(Shift1Reg).addImm(is8bit ? 24 : 16);
if (is64bit)
BuildMI(BB, dl, TII->get(PPC::RLDICR), PtrReg)
.addReg(Ptr1Reg).addImm(0).addImm(61);
@@ -9532,23 +9728,21 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
// Target Optimization Hooks
//===----------------------------------------------------------------------===//
-static std::string getRecipOp(const char *Base, EVT VT) {
- std::string RecipOp(Base);
+static int getEstimateRefinementSteps(EVT VT, const PPCSubtarget &Subtarget) {
+ // For the estimates, convergence is quadratic, so we essentially double the
+ // number of digits correct after every iteration. For both FRE and FRSQRTE,
+ // the minimum architected relative accuracy is 2^-5. When hasRecipPrec(),
+ // this is 2^-14. IEEE float has 23 digits and double has 52 digits.
+ int RefinementSteps = Subtarget.hasRecipPrec() ? 1 : 3;
if (VT.getScalarType() == MVT::f64)
- RecipOp += "d";
- else
- RecipOp += "f";
-
- if (VT.isVector())
- RecipOp = "vec-" + RecipOp;
-
- return RecipOp;
+ RefinementSteps++;
+ return RefinementSteps;
}
-SDValue PPCTargetLowering::getRsqrtEstimate(SDValue Operand,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const {
+SDValue PPCTargetLowering::getSqrtEstimate(SDValue Operand, SelectionDAG &DAG,
+ int Enabled, int &RefinementSteps,
+ bool &UseOneConstNR,
+ bool Reciprocal) const {
EVT VT = Operand.getValueType();
if ((VT == MVT::f32 && Subtarget.hasFRSQRTES()) ||
(VT == MVT::f64 && Subtarget.hasFRSQRTE()) ||
@@ -9556,21 +9750,18 @@ SDValue PPCTargetLowering::getRsqrtEstimate(SDValue Operand,
(VT == MVT::v2f64 && Subtarget.hasVSX()) ||
(VT == MVT::v4f32 && Subtarget.hasQPX()) ||
(VT == MVT::v4f64 && Subtarget.hasQPX())) {
- TargetRecip Recips = DCI.DAG.getTarget().Options.Reciprocals;
- std::string RecipOp = getRecipOp("sqrt", VT);
- if (!Recips.isEnabled(RecipOp))
- return SDValue();
+ if (RefinementSteps == ReciprocalEstimate::Unspecified)
+ RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
- RefinementSteps = Recips.getRefinementSteps(RecipOp);
UseOneConstNR = true;
- return DCI.DAG.getNode(PPCISD::FRSQRTE, SDLoc(Operand), VT, Operand);
+ return DAG.getNode(PPCISD::FRSQRTE, SDLoc(Operand), VT, Operand);
}
return SDValue();
}
-SDValue PPCTargetLowering::getRecipEstimate(SDValue Operand,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const {
+SDValue PPCTargetLowering::getRecipEstimate(SDValue Operand, SelectionDAG &DAG,
+ int Enabled,
+ int &RefinementSteps) const {
EVT VT = Operand.getValueType();
if ((VT == MVT::f32 && Subtarget.hasFRES()) ||
(VT == MVT::f64 && Subtarget.hasFRE()) ||
@@ -9578,13 +9769,9 @@ SDValue PPCTargetLowering::getRecipEstimate(SDValue Operand,
(VT == MVT::v2f64 && Subtarget.hasVSX()) ||
(VT == MVT::v4f32 && Subtarget.hasQPX()) ||
(VT == MVT::v4f64 && Subtarget.hasQPX())) {
- TargetRecip Recips = DCI.DAG.getTarget().Options.Reciprocals;
- std::string RecipOp = getRecipOp("div", VT);
- if (!Recips.isEnabled(RecipOp))
- return SDValue();
-
- RefinementSteps = Recips.getRefinementSteps(RecipOp);
- return DCI.DAG.getNode(PPCISD::FRE, SDLoc(Operand), VT, Operand);
+ if (RefinementSteps == ReciprocalEstimate::Unspecified)
+ RefinementSteps = getEstimateRefinementSteps(VT, Subtarget);
+ return DAG.getNode(PPCISD::FRE, SDLoc(Operand), VT, Operand);
}
return SDValue();
}
@@ -9635,13 +9822,13 @@ static bool isConsecutiveLSLoc(SDValue Loc, EVT VT, LSBaseSDNode *Base,
if (Loc.getOpcode() == ISD::FrameIndex) {
if (BaseLoc.getOpcode() != ISD::FrameIndex)
return false;
- const MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ const MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
int FI = cast<FrameIndexSDNode>(Loc)->getIndex();
int BFI = cast<FrameIndexSDNode>(BaseLoc)->getIndex();
- int FS = MFI->getObjectSize(FI);
- int BFS = MFI->getObjectSize(BFI);
+ int FS = MFI.getObjectSize(FI);
+ int BFS = MFI.getObjectSize(BFI);
if (FS != BFS || FS != (int)Bytes) return false;
- return MFI->getObjectOffset(FI) == (MFI->getObjectOffset(BFI) + Dist*Bytes);
+ return MFI.getObjectOffset(FI) == (MFI.getObjectOffset(BFI) + Dist*Bytes);
}
SDValue Base1 = Loc, Base2 = BaseLoc;
@@ -9699,9 +9886,11 @@ static bool isConsecutiveLS(SDNode *N, LSBaseSDNode *Base,
case Intrinsic::ppc_altivec_lvx:
case Intrinsic::ppc_altivec_lvxl:
case Intrinsic::ppc_vsx_lxvw4x:
+ case Intrinsic::ppc_vsx_lxvw4x_be:
VT = MVT::v4i32;
break;
case Intrinsic::ppc_vsx_lxvd2x:
+ case Intrinsic::ppc_vsx_lxvd2x_be:
VT = MVT::v2f64;
break;
case Intrinsic::ppc_altivec_lvebx:
@@ -9748,6 +9937,12 @@ static bool isConsecutiveLS(SDNode *N, LSBaseSDNode *Base,
case Intrinsic::ppc_vsx_stxvd2x:
VT = MVT::v2f64;
break;
+ case Intrinsic::ppc_vsx_stxvw4x_be:
+ VT = MVT::v4i32;
+ break;
+ case Intrinsic::ppc_vsx_stxvd2x_be:
+ VT = MVT::v2f64;
+ break;
case Intrinsic::ppc_altivec_stvebx:
VT = MVT::i8;
break;
@@ -9833,6 +10028,87 @@ static bool findConsecutiveLoad(LoadSDNode *LD, SelectionDAG &DAG) {
return false;
}
+
+/// This function is called when we have proved that a SETCC node can be replaced
+/// by subtraction (and other supporting instructions) so that the result of
+/// comparison is kept in a GPR instead of CR. This function is purely for
+/// codegen purposes and has some flags to guide the codegen process.
+static SDValue generateEquivalentSub(SDNode *N, int Size, bool Complement,
+ bool Swap, SDLoc &DL, SelectionDAG &DAG) {
+
+ assert(N->getOpcode() == ISD::SETCC && "ISD::SETCC Expected.");
+
+ // Zero extend the operands to the largest legal integer. Originally, they
+ // must be of a strictly smaller size.
+ auto Op0 = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, N->getOperand(0),
+ DAG.getConstant(Size, DL, MVT::i32));
+ auto Op1 = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, N->getOperand(1),
+ DAG.getConstant(Size, DL, MVT::i32));
+
+ // Swap if needed. Depends on the condition code.
+ if (Swap)
+ std::swap(Op0, Op1);
+
+ // Subtract extended integers.
+ auto SubNode = DAG.getNode(ISD::SUB, DL, MVT::i64, Op0, Op1);
+
+ // Move the sign bit to the least significant position and zero out the rest.
+ // Now the least significant bit carries the result of original comparison.
+ auto Shifted = DAG.getNode(ISD::SRL, DL, MVT::i64, SubNode,
+ DAG.getConstant(Size - 1, DL, MVT::i32));
+ auto Final = Shifted;
+
+ // Complement the result if needed. Based on the condition code.
+ if (Complement)
+ Final = DAG.getNode(ISD::XOR, DL, MVT::i64, Shifted,
+ DAG.getConstant(1, DL, MVT::i64));
+
+ return DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, Final);
+}
+
+SDValue PPCTargetLowering::ConvertSETCCToSubtract(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+
+ assert(N->getOpcode() == ISD::SETCC && "ISD::SETCC Expected.");
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
+
+ // Size of integers being compared has a critical role in the following
+ // analysis, so we prefer to do this when all types are legal.
+ if (!DCI.isAfterLegalizeVectorOps())
+ return SDValue();
+
+ // If all users of SETCC extend its value to a legal integer type
+ // then we replace SETCC with a subtraction
+ for (SDNode::use_iterator UI = N->use_begin(),
+ UE = N->use_end(); UI != UE; ++UI) {
+ if (UI->getOpcode() != ISD::ZERO_EXTEND)
+ return SDValue();
+ }
+
+ ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
+ auto OpSize = N->getOperand(0).getValueSizeInBits();
+
+ unsigned Size = DAG.getDataLayout().getLargestLegalIntTypeSizeInBits();
+
+ if (OpSize < Size) {
+ switch (CC) {
+ default: break;
+ case ISD::SETULT:
+ return generateEquivalentSub(N, Size, false, false, DL, DAG);
+ case ISD::SETULE:
+ return generateEquivalentSub(N, Size, true, true, DL, DAG);
+ case ISD::SETUGT:
+ return generateEquivalentSub(N, Size, false, true, DL, DAG);
+ case ISD::SETUGE:
+ return generateEquivalentSub(N, Size, true, false, DL, DAG);
+ }
+ }
+
+ return SDValue();
+}
+
SDValue PPCTargetLowering::DAGCombineTruncBoolExt(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
@@ -9874,7 +10150,8 @@ SDValue PPCTargetLowering::DAGCombineTruncBoolExt(SDNode *N,
APInt::getHighBitsSet(OpBits, OpBits-1)) ||
!DAG.MaskedValueIsZero(N->getOperand(1),
APInt::getHighBitsSet(OpBits, OpBits-1)))
- return SDValue();
+ return (N->getOpcode() == ISD::SETCC ? ConvertSETCCToSubtract(N, DCI)
+ : SDValue());
} else {
// This is neither a signed nor an unsigned comparison, just make sure
// that the high bits are equal.
@@ -10398,6 +10675,173 @@ SDValue PPCTargetLowering::DAGCombineExtBoolTrunc(SDNode *N,
ShiftCst);
}
+/// \brief Reduces the number of fp-to-int conversion when building a vector.
+///
+/// If this vector is built out of floating to integer conversions,
+/// transform it to a vector built out of floating point values followed by a
+/// single floating to integer conversion of the vector.
+/// Namely (build_vector (fptosi $A), (fptosi $B), ...)
+/// becomes (fptosi (build_vector ($A, $B, ...)))
+SDValue PPCTargetLowering::
+combineElementTruncationToVectorTruncation(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ assert(N->getOpcode() == ISD::BUILD_VECTOR &&
+ "Should be called with a BUILD_VECTOR node");
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc dl(N);
+
+ SDValue FirstInput = N->getOperand(0);
+ assert(FirstInput.getOpcode() == PPCISD::MFVSR &&
+ "The input operand must be an fp-to-int conversion.");
+
+ // This combine happens after legalization so the fp_to_[su]i nodes are
+ // already converted to PPCSISD nodes.
+ unsigned FirstConversion = FirstInput.getOperand(0).getOpcode();
+ if (FirstConversion == PPCISD::FCTIDZ ||
+ FirstConversion == PPCISD::FCTIDUZ ||
+ FirstConversion == PPCISD::FCTIWZ ||
+ FirstConversion == PPCISD::FCTIWUZ) {
+ bool IsSplat = true;
+ bool Is32Bit = FirstConversion == PPCISD::FCTIWZ ||
+ FirstConversion == PPCISD::FCTIWUZ;
+ EVT SrcVT = FirstInput.getOperand(0).getValueType();
+ SmallVector<SDValue, 4> Ops;
+ EVT TargetVT = N->getValueType(0);
+ for (int i = 0, e = N->getNumOperands(); i < e; ++i) {
+ if (N->getOperand(i).getOpcode() != PPCISD::MFVSR)
+ return SDValue();
+ unsigned NextConversion = N->getOperand(i).getOperand(0).getOpcode();
+ if (NextConversion != FirstConversion)
+ return SDValue();
+ if (N->getOperand(i) != FirstInput)
+ IsSplat = false;
+ }
+
+ // If this is a splat, we leave it as-is since there will be only a single
+ // fp-to-int conversion followed by a splat of the integer. This is better
+ // for 32-bit and smaller ints and neutral for 64-bit ints.
+ if (IsSplat)
+ return SDValue();
+
+ // Now that we know we have the right type of node, get its operands
+ for (int i = 0, e = N->getNumOperands(); i < e; ++i) {
+ SDValue In = N->getOperand(i).getOperand(0);
+ // For 32-bit values, we need to add an FP_ROUND node.
+ if (Is32Bit) {
+ if (In.isUndef())
+ Ops.push_back(DAG.getUNDEF(SrcVT));
+ else {
+ SDValue Trunc = DAG.getNode(ISD::FP_ROUND, dl,
+ MVT::f32, In.getOperand(0),
+ DAG.getIntPtrConstant(1, dl));
+ Ops.push_back(Trunc);
+ }
+ } else
+ Ops.push_back(In.isUndef() ? DAG.getUNDEF(SrcVT) : In.getOperand(0));
+ }
+
+ unsigned Opcode;
+ if (FirstConversion == PPCISD::FCTIDZ ||
+ FirstConversion == PPCISD::FCTIWZ)
+ Opcode = ISD::FP_TO_SINT;
+ else
+ Opcode = ISD::FP_TO_UINT;
+
+ EVT NewVT = TargetVT == MVT::v2i64 ? MVT::v2f64 : MVT::v4f32;
+ SDValue BV = DAG.getBuildVector(NewVT, dl, Ops);
+ return DAG.getNode(Opcode, dl, TargetVT, BV);
+ }
+ return SDValue();
+}
+
+/// \brief Reduce the number of loads when building a vector.
+///
+/// Building a vector out of multiple loads can be converted to a load
+/// of the vector type if the loads are consecutive. If the loads are
+/// consecutive but in descending order, a shuffle is added at the end
+/// to reorder the vector.
+static SDValue combineBVOfConsecutiveLoads(SDNode *N, SelectionDAG &DAG) {
+ assert(N->getOpcode() == ISD::BUILD_VECTOR &&
+ "Should be called with a BUILD_VECTOR node");
+
+ SDLoc dl(N);
+ bool InputsAreConsecutiveLoads = true;
+ bool InputsAreReverseConsecutive = true;
+ unsigned ElemSize = N->getValueType(0).getScalarSizeInBits() / 8;
+ SDValue FirstInput = N->getOperand(0);
+ bool IsRoundOfExtLoad = false;
+
+ if (FirstInput.getOpcode() == ISD::FP_ROUND &&
+ FirstInput.getOperand(0).getOpcode() == ISD::LOAD) {
+ LoadSDNode *LD = dyn_cast<LoadSDNode>(FirstInput.getOperand(0));
+ IsRoundOfExtLoad = LD->getExtensionType() == ISD::EXTLOAD;
+ }
+ // Not a build vector of (possibly fp_rounded) loads.
+ if (!IsRoundOfExtLoad && FirstInput.getOpcode() != ISD::LOAD)
+ return SDValue();
+
+ for (int i = 1, e = N->getNumOperands(); i < e; ++i) {
+ // If any inputs are fp_round(extload), they all must be.
+ if (IsRoundOfExtLoad && N->getOperand(i).getOpcode() != ISD::FP_ROUND)
+ return SDValue();
+
+ SDValue NextInput = IsRoundOfExtLoad ? N->getOperand(i).getOperand(0) :
+ N->getOperand(i);
+ if (NextInput.getOpcode() != ISD::LOAD)
+ return SDValue();
+
+ SDValue PreviousInput =
+ IsRoundOfExtLoad ? N->getOperand(i-1).getOperand(0) : N->getOperand(i-1);
+ LoadSDNode *LD1 = dyn_cast<LoadSDNode>(PreviousInput);
+ LoadSDNode *LD2 = dyn_cast<LoadSDNode>(NextInput);
+
+ // If any inputs are fp_round(extload), they all must be.
+ if (IsRoundOfExtLoad && LD2->getExtensionType() != ISD::EXTLOAD)
+ return SDValue();
+
+ if (!isConsecutiveLS(LD2, LD1, ElemSize, 1, DAG))
+ InputsAreConsecutiveLoads = false;
+ if (!isConsecutiveLS(LD1, LD2, ElemSize, 1, DAG))
+ InputsAreReverseConsecutive = false;
+
+ // Exit early if the loads are neither consecutive nor reverse consecutive.
+ if (!InputsAreConsecutiveLoads && !InputsAreReverseConsecutive)
+ return SDValue();
+ }
+
+ assert(!(InputsAreConsecutiveLoads && InputsAreReverseConsecutive) &&
+ "The loads cannot be both consecutive and reverse consecutive.");
+
+ SDValue FirstLoadOp =
+ IsRoundOfExtLoad ? FirstInput.getOperand(0) : FirstInput;
+ SDValue LastLoadOp =
+ IsRoundOfExtLoad ? N->getOperand(N->getNumOperands()-1).getOperand(0) :
+ N->getOperand(N->getNumOperands()-1);
+
+ LoadSDNode *LD1 = dyn_cast<LoadSDNode>(FirstLoadOp);
+ LoadSDNode *LDL = dyn_cast<LoadSDNode>(LastLoadOp);
+ if (InputsAreConsecutiveLoads) {
+ assert(LD1 && "Input needs to be a LoadSDNode.");
+ return DAG.getLoad(N->getValueType(0), dl, LD1->getChain(),
+ LD1->getBasePtr(), LD1->getPointerInfo(),
+ LD1->getAlignment());
+ }
+ if (InputsAreReverseConsecutive) {
+ assert(LDL && "Input needs to be a LoadSDNode.");
+ SDValue Load = DAG.getLoad(N->getValueType(0), dl, LDL->getChain(),
+ LDL->getBasePtr(), LDL->getPointerInfo(),
+ LDL->getAlignment());
+ SmallVector<int, 16> Ops;
+ for (int i = N->getNumOperands() - 1; i >= 0; i--)
+ Ops.push_back(i);
+
+ return DAG.getVectorShuffle(N->getValueType(0), dl, Load,
+ DAG.getUNDEF(N->getValueType(0)), Ops);
+ }
+ return SDValue();
+}
+
SDValue PPCTargetLowering::DAGCombineBuildVector(SDNode *N,
DAGCombinerInfo &DCI) const {
assert(N->getOpcode() == ISD::BUILD_VECTOR &&
@@ -10405,21 +10849,41 @@ SDValue PPCTargetLowering::DAGCombineBuildVector(SDNode *N,
SelectionDAG &DAG = DCI.DAG;
SDLoc dl(N);
- if (N->getValueType(0) != MVT::v2f64 || !Subtarget.hasVSX())
+
+ if (!Subtarget.hasVSX())
+ return SDValue();
+
+ // The target independent DAG combiner will leave a build_vector of
+ // float-to-int conversions intact. We can generate MUCH better code for
+ // a float-to-int conversion of a vector of floats.
+ SDValue FirstInput = N->getOperand(0);
+ if (FirstInput.getOpcode() == PPCISD::MFVSR) {
+ SDValue Reduced = combineElementTruncationToVectorTruncation(N, DCI);
+ if (Reduced)
+ return Reduced;
+ }
+
+ // If we're building a vector out of consecutive loads, just load that
+ // vector type.
+ SDValue Reduced = combineBVOfConsecutiveLoads(N, DAG);
+ if (Reduced)
+ return Reduced;
+
+ if (N->getValueType(0) != MVT::v2f64)
return SDValue();
// Looking for:
// (build_vector ([su]int_to_fp (extractelt 0)), [su]int_to_fp (extractelt 1))
- if (N->getOperand(0).getOpcode() != ISD::SINT_TO_FP &&
- N->getOperand(0).getOpcode() != ISD::UINT_TO_FP)
+ if (FirstInput.getOpcode() != ISD::SINT_TO_FP &&
+ FirstInput.getOpcode() != ISD::UINT_TO_FP)
return SDValue();
if (N->getOperand(1).getOpcode() != ISD::SINT_TO_FP &&
N->getOperand(1).getOpcode() != ISD::UINT_TO_FP)
return SDValue();
- if (N->getOperand(0).getOpcode() != N->getOperand(1).getOpcode())
+ if (FirstInput.getOpcode() != N->getOperand(1).getOpcode())
return SDValue();
- SDValue Ext1 = N->getOperand(0).getOperand(0);
+ SDValue Ext1 = FirstInput.getOperand(0);
SDValue Ext2 = N->getOperand(1).getOperand(0);
if(Ext1.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
Ext2.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
@@ -10464,6 +10928,34 @@ SDValue PPCTargetLowering::combineFPToIntToFP(SDNode *N,
SDLoc dl(N);
SDValue Op(N, 0);
+ SDValue FirstOperand(Op.getOperand(0));
+ bool SubWordLoad = FirstOperand.getOpcode() == ISD::LOAD &&
+ (FirstOperand.getValueType() == MVT::i8 ||
+ FirstOperand.getValueType() == MVT::i16);
+ if (Subtarget.hasP9Vector() && Subtarget.hasP9Altivec() && SubWordLoad) {
+ bool Signed = N->getOpcode() == ISD::SINT_TO_FP;
+ bool DstDouble = Op.getValueType() == MVT::f64;
+ unsigned ConvOp = Signed ?
+ (DstDouble ? PPCISD::FCFID : PPCISD::FCFIDS) :
+ (DstDouble ? PPCISD::FCFIDU : PPCISD::FCFIDUS);
+ SDValue WidthConst =
+ DAG.getIntPtrConstant(FirstOperand.getValueType() == MVT::i8 ? 1 : 2,
+ dl, false);
+ LoadSDNode *LDN = cast<LoadSDNode>(FirstOperand.getNode());
+ SDValue Ops[] = { LDN->getChain(), LDN->getBasePtr(), WidthConst };
+ SDValue Ld = DAG.getMemIntrinsicNode(PPCISD::LXSIZX, dl,
+ DAG.getVTList(MVT::f64, MVT::Other),
+ Ops, MVT::i8, LDN->getMemOperand());
+
+ // For signed conversion, we need to sign-extend the value in the VSR
+ if (Signed) {
+ SDValue ExtOps[] = { Ld, WidthConst };
+ SDValue Ext = DAG.getNode(PPCISD::VEXTS, dl, MVT::f64, ExtOps);
+ return DAG.getNode(ConvOp, dl, DstDouble ? MVT::f64 : MVT::f32, Ext);
+ } else
+ return DAG.getNode(ConvOp, dl, DstDouble ? MVT::f64 : MVT::f32, Ld);
+ }
+
// Don't handle ppc_fp128 here or i1 conversions.
if (Op.getValueType() != MVT::f32 && Op.getValueType() != MVT::f64)
return SDValue();
@@ -10676,10 +11168,14 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
case ISD::UINT_TO_FP:
return combineFPToIntToFP(N, DCI);
case ISD::STORE: {
+ EVT Op1VT = N->getOperand(1).getValueType();
+ bool ValidTypeForStoreFltAsInt = (Op1VT == MVT::i32) ||
+ (Subtarget.hasP9Vector() && (Op1VT == MVT::i8 || Op1VT == MVT::i16));
+
// Turn STORE (FP_TO_SINT F) -> STFIWX(FCTIWZ(F)).
if (Subtarget.hasSTFIWX() && !cast<StoreSDNode>(N)->isTruncatingStore() &&
N->getOperand(1).getOpcode() == ISD::FP_TO_SINT &&
- N->getOperand(1).getValueType() == MVT::i32 &&
+ ValidTypeForStoreFltAsInt &&
N->getOperand(1).getOperand(0).getValueType() != MVT::ppcf128) {
SDValue Val = N->getOperand(1).getOperand(0);
if (Val.getValueType() == MVT::f32) {
@@ -10689,15 +11185,31 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
Val = DAG.getNode(PPCISD::FCTIWZ, dl, MVT::f64, Val);
DCI.AddToWorklist(Val.getNode());
- SDValue Ops[] = {
- N->getOperand(0), Val, N->getOperand(2),
- DAG.getValueType(N->getOperand(1).getValueType())
- };
+ if (Op1VT == MVT::i32) {
+ SDValue Ops[] = {
+ N->getOperand(0), Val, N->getOperand(2),
+ DAG.getValueType(N->getOperand(1).getValueType())
+ };
+
+ Val = DAG.getMemIntrinsicNode(PPCISD::STFIWX, dl,
+ DAG.getVTList(MVT::Other), Ops,
+ cast<StoreSDNode>(N)->getMemoryVT(),
+ cast<StoreSDNode>(N)->getMemOperand());
+ } else {
+ unsigned WidthInBytes =
+ N->getOperand(1).getValueType() == MVT::i8 ? 1 : 2;
+ SDValue WidthConst = DAG.getIntPtrConstant(WidthInBytes, dl, false);
+
+ SDValue Ops[] = {
+ N->getOperand(0), Val, N->getOperand(2), WidthConst,
+ DAG.getValueType(N->getOperand(1).getValueType())
+ };
+ Val = DAG.getMemIntrinsicNode(PPCISD::STXSIX, dl,
+ DAG.getVTList(MVT::Other), Ops,
+ cast<StoreSDNode>(N)->getMemoryVT(),
+ cast<StoreSDNode>(N)->getMemOperand());
+ }
- Val = DAG.getMemIntrinsicNode(PPCISD::STFIWX, dl,
- DAG.getVTList(MVT::Other), Ops,
- cast<StoreSDNode>(N)->getMemoryVT(),
- cast<StoreSDNode>(N)->getMemOperand());
DCI.AddToWorklist(Val.getNode());
return Val;
}
@@ -10726,10 +11238,11 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
}
// For little endian, VSX stores require generating xxswapd/lxvd2x.
+ // Not needed on ISA 3.0 based CPUs since we have a non-permuting store.
EVT VT = N->getOperand(1).getValueType();
if (VT.isSimple()) {
MVT StoreVT = VT.getSimpleVT();
- if (Subtarget.hasVSX() && Subtarget.isLittleEndian() &&
+ if (Subtarget.needsSwapsForVSXMemOps() &&
(StoreVT == MVT::v2f64 || StoreVT == MVT::v2i64 ||
StoreVT == MVT::v4f32 || StoreVT == MVT::v4i32))
return expandVSXStoreForLE(N, DCI);
@@ -10741,9 +11254,10 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
EVT VT = LD->getValueType(0);
// For little endian, VSX loads require generating lxvd2x/xxswapd.
+ // Not needed on ISA 3.0 based CPUs since we have a non-permuting load.
if (VT.isSimple()) {
MVT LoadVT = VT.getSimpleVT();
- if (Subtarget.hasVSX() && Subtarget.isLittleEndian() &&
+ if (Subtarget.needsSwapsForVSXMemOps() &&
(LoadVT == MVT::v2f64 || LoadVT == MVT::v2i64 ||
LoadVT == MVT::v4f32 || LoadVT == MVT::v4i32))
return expandVSXLoadForLE(N, DCI);
@@ -11014,11 +11528,9 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
int Bits = IID == Intrinsic::ppc_qpx_qvlpcld ?
5 /* 32 byte alignment */ : 4 /* 16 byte alignment */;
- if (DAG.MaskedValueIsZero(
- Add->getOperand(1),
- APInt::getAllOnesValue(Bits /* alignment */)
- .zext(
- Add.getValueType().getScalarType().getSizeInBits()))) {
+ if (DAG.MaskedValueIsZero(Add->getOperand(1),
+ APInt::getAllOnesValue(Bits /* alignment */)
+ .zext(Add.getScalarValueSizeInBits()))) {
SDNode *BasePtr = Add->getOperand(0).getNode();
for (SDNode::use_iterator UI = BasePtr->use_begin(),
UE = BasePtr->use_end();
@@ -11060,7 +11572,8 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
break;
case ISD::INTRINSIC_W_CHAIN: {
// For little endian, VSX loads require generating lxvd2x/xxswapd.
- if (Subtarget.hasVSX() && Subtarget.isLittleEndian()) {
+ // Not needed on ISA 3.0 based CPUs since we have a non-permuting load.
+ if (Subtarget.needsSwapsForVSXMemOps()) {
switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) {
default:
break;
@@ -11073,7 +11586,8 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
}
case ISD::INTRINSIC_VOID: {
// For little endian, VSX stores require generating xxswapd/stxvd2x.
- if (Subtarget.hasVSX() && Subtarget.isLittleEndian()) {
+ // Not needed on ISA 3.0 based CPUs since we have a non-permuting store.
+ if (Subtarget.needsSwapsForVSXMemOps()) {
switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) {
default:
break;
@@ -11392,7 +11906,7 @@ unsigned PPCTargetLowering::getPrefLoopAlignment(MachineLoop *ML) const {
uint64_t LoopSize = 0;
for (auto I = ML->block_begin(), IE = ML->block_end(); I != IE; ++I)
for (auto J = (*I)->begin(), JE = (*I)->end(); J != JE; ++J) {
- LoopSize += TII->GetInstSizeInBytes(*J);
+ LoopSize += TII->getInstSizeInBytes(*J);
if (LoopSize > 32)
break;
}
@@ -11688,8 +12202,8 @@ bool PPCTargetLowering::isLegalAddressingMode(const DataLayout &DL,
SDValue PPCTargetLowering::LowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
@@ -11726,8 +12240,8 @@ SDValue PPCTargetLowering::LowerFRAMEADDR(SDValue Op,
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT PtrVT = getPointerTy(MF.getDataLayout());
bool isPPC64 = PtrVT == MVT::i64;
@@ -12237,3 +12751,20 @@ void PPCTargetLowering::insertSSPDeclarations(Module &M) const {
if (!Subtarget.isTargetLinux())
return TargetLowering::insertSSPDeclarations(M);
}
+
+bool PPCTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
+
+ if (!VT.isSimple() || !Subtarget.hasVSX())
+ return false;
+
+ switch(VT.getSimpleVT().SimpleTy) {
+ default:
+ // For FP types that are currently not supported by PPC backend, return
+ // false. Examples: f16, f80.
+ return false;
+ case MVT::f32:
+ case MVT::f64:
+ case MVT::ppcf128:
+ return Imm.isPosZero();
+ }
+}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.h b/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.h
index cc7222b..05acd25 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -47,9 +47,13 @@ namespace llvm {
FCTIDZ, FCTIWZ,
/// Newer FCTI[D,W]UZ floating-point-to-integer conversion instructions for
- /// unsigned integers.
+ /// unsigned integers with round toward zero.
FCTIDUZ, FCTIWUZ,
+ /// VEXTS, ByteWidth - takes an input in VSFRC and produces an output in
+ /// VSFRC that is sign-extended from ByteWidth to a 64-byte integer.
+ VEXTS,
+
/// Reciprocal estimate instructions (unary FP ops).
FRE, FRSQRTE,
@@ -365,6 +369,16 @@ namespace llvm {
/// destination 64-bit register.
LFIWZX,
+ /// GPRC, CHAIN = LXSIZX, CHAIN, Ptr, ByteWidth - This is a load of an
+ /// integer smaller than 64 bits into a VSR. The integer is zero-extended.
+ /// This can be used for converting loaded integers to floating point.
+ LXSIZX,
+
+ /// STXSIX - The STXSI[bh]X instruction. The first operand is an input
+ /// chain, then an f64 value to store, then an address to store it to,
+ /// followed by a byte-width for the store.
+ STXSIX,
+
/// VSRC, CHAIN = LXVD2X_LE CHAIN, Ptr - Occurs only for little endian.
/// Maps directly to an lxvd2x instruction that will be followed by
/// an xxswapd.
@@ -474,7 +488,7 @@ namespace llvm {
/// then the VPERM for the shuffle. All in all a very slow sequence.
TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(EVT VT)
const override {
- if (VT.getVectorElementType().getSizeInBits() % 8 == 0)
+ if (VT.getScalarSizeInBits() % 8 == 0)
return TypeWidenVector;
return TargetLoweringBase::getPreferredVectorAction(VT);
}
@@ -492,6 +506,14 @@ namespace llvm {
return true;
}
+ bool isCtlzFast() const override {
+ return true;
+ }
+
+ bool hasAndNotCompare(SDValue) const override {
+ return true;
+ }
+
bool supportSplitCSR(MachineFunction *MF) const override {
return
MF->getFunction()->getCallingConv() == CallingConv::CXX_FAST_TLS &&
@@ -747,18 +769,40 @@ namespace llvm {
bool useLoadStackGuardNode() const override;
void insertSSPDeclarations(Module &M) const override;
+ bool isFPImmLegal(const APFloat &Imm, EVT VT) const override;
+
+ unsigned getJumpTableEncoding() const override;
+ bool isJumpTableRelative() const override;
+ SDValue getPICJumpTableRelocBase(SDValue Table,
+ SelectionDAG &DAG) const override;
+ const MCExpr *getPICJumpTableRelocBaseExpr(const MachineFunction *MF,
+ unsigned JTI,
+ MCContext &Ctx) const override;
+
private:
struct ReuseLoadInfo {
SDValue Ptr;
SDValue Chain;
SDValue ResChain;
MachinePointerInfo MPI;
+ bool IsDereferenceable;
bool IsInvariant;
unsigned Alignment;
AAMDNodes AAInfo;
const MDNode *Ranges;
- ReuseLoadInfo() : IsInvariant(false), Alignment(0), Ranges(nullptr) {}
+ ReuseLoadInfo()
+ : IsDereferenceable(false), IsInvariant(false), Alignment(0),
+ Ranges(nullptr) {}
+
+ MachineMemOperand::Flags MMOFlags() const {
+ MachineMemOperand::Flags F = MachineMemOperand::MONone;
+ if (IsDereferenceable)
+ F |= MachineMemOperand::MODereferenceable;
+ if (IsInvariant)
+ F |= MachineMemOperand::MOInvariant;
+ return F;
+ }
};
bool canReuseLoadAddress(SDValue Op, EVT MemVT, ReuseLoadInfo &RLI,
@@ -771,6 +815,8 @@ namespace llvm {
SelectionDAG &DAG, const SDLoc &dl) const;
SDValue LowerFP_TO_INTDirectMove(SDValue Op, SelectionDAG &DAG,
const SDLoc &dl) const;
+
+ bool directMoveIsProfitable(const SDValue &Op) const;
SDValue LowerINT_TO_FPDirectMove(SDValue Op, SelectionDAG &DAG,
const SDLoc &dl) const;
@@ -933,14 +979,23 @@ namespace llvm {
SDValue DAGCombineTruncBoolExt(SDNode *N, DAGCombinerInfo &DCI) const;
SDValue combineFPToIntToFP(SDNode *N, DAGCombinerInfo &DCI) const;
- SDValue getRsqrtEstimate(SDValue Operand, DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const override;
- SDValue getRecipEstimate(SDValue Operand, DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const override;
+ /// ConvertSETCCToSubtract - looks at SETCC that compares ints. It replaces
+ /// SETCC with integer subtraction when (1) there is a legal way of doing it
+ /// (2) keeping the result of comparison in GPR has performance benefit.
+ SDValue ConvertSETCCToSubtract(SDNode *N, DAGCombinerInfo &DCI) const;
+
+ SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps, bool &UseOneConstNR,
+ bool Reciprocal) const override;
+ SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps) const override;
unsigned combineRepeatedFPDivisors() const override;
CCAssignFn *useFastISelCCs(unsigned Flag) const;
+
+ SDValue
+ combineElementTruncationToVectorTruncation(SDNode *N,
+ DAGCombinerInfo &DCI) const;
};
namespace PPC {
@@ -959,6 +1014,13 @@ namespace llvm {
ISD::ArgFlagsTy &ArgFlags,
CCState &State);
+ bool
+ CC_PPC32_SVR4_Custom_SkipLastArgRegsPPCF128(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags,
+ CCState &State);
+
bool CC_PPC32_SVR4_Custom_AlignFPArgRegs(unsigned &ValNo, MVT &ValVT,
MVT &LocVT,
CCValAssign::LocInfo &LocInfo,
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
index 5e514c8..fbec878 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
@@ -65,16 +65,6 @@ def SRL64 : SDNodeXForm<imm, [{
: getI32Imm(0, SDLoc(N));
}]>;
-def HI32_48 : SDNodeXForm<imm, [{
- // Transformation function: shift the immediate value down into the low bits.
- return getI32Imm((unsigned short)(N->getZExtValue() >> 32, SDLoc(N)));
-}]>;
-
-def HI48_64 : SDNodeXForm<imm, [{
- // Transformation function: shift the immediate value down into the low bits.
- return getI32Imm((unsigned short)(N->getZExtValue() >> 48, SDLoc(N)));
-}]>;
-
//===----------------------------------------------------------------------===//
// Calls.
@@ -1164,6 +1154,9 @@ defm FCFID : XForm_26r<63, 846, (outs f8rc:$frD), (ins f8rc:$frB),
defm FCTID : XForm_26r<63, 814, (outs f8rc:$frD), (ins f8rc:$frB),
"fctid", "$frD, $frB", IIC_FPGeneral,
[]>, isPPC64;
+defm FCTIDU : XForm_26r<63, 942, (outs f8rc:$frD), (ins f8rc:$frB),
+ "fctidu", "$frD, $frB", IIC_FPGeneral,
+ []>, isPPC64;
defm FCTIDZ : XForm_26r<63, 815, (outs f8rc:$frD), (ins f8rc:$frB),
"fctidz", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (PPCfctidz f64:$frB))]>, isPPC64;
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrAltivec.td b/contrib/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
index e1c4673..5c02274 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrAltivec.td
@@ -26,6 +26,7 @@
// ** in PPCVSXSwapRemoval::gatherVectorInstructions(). **
// ****************************************************************************
+
//===----------------------------------------------------------------------===//
// Altivec transformation functions and pattern fragments.
//
@@ -242,7 +243,7 @@ def VSPLTISB_get_imm : SDNodeXForm<build_vector, [{
return PPC::get_VSPLTI_elt(N, 1, *CurDAG);
}]>;
def vecspltisb : PatLeaf<(build_vector), [{
- return PPC::get_VSPLTI_elt(N, 1, *CurDAG).getNode() != 0;
+ return PPC::get_VSPLTI_elt(N, 1, *CurDAG).getNode() != nullptr;
}], VSPLTISB_get_imm>;
// VSPLTISH_get_imm xform function: convert build_vector to VSPLTISH imm.
@@ -250,7 +251,7 @@ def VSPLTISH_get_imm : SDNodeXForm<build_vector, [{
return PPC::get_VSPLTI_elt(N, 2, *CurDAG);
}]>;
def vecspltish : PatLeaf<(build_vector), [{
- return PPC::get_VSPLTI_elt(N, 2, *CurDAG).getNode() != 0;
+ return PPC::get_VSPLTI_elt(N, 2, *CurDAG).getNode() != nullptr;
}], VSPLTISH_get_imm>;
// VSPLTISW_get_imm xform function: convert build_vector to VSPLTISW imm.
@@ -258,7 +259,7 @@ def VSPLTISW_get_imm : SDNodeXForm<build_vector, [{
return PPC::get_VSPLTI_elt(N, 4, *CurDAG);
}]>;
def vecspltisw : PatLeaf<(build_vector), [{
- return PPC::get_VSPLTI_elt(N, 4, *CurDAG).getNode() != 0;
+ return PPC::get_VSPLTI_elt(N, 4, *CurDAG).getNode() != nullptr;
}], VSPLTISW_get_imm>;
//===----------------------------------------------------------------------===//
@@ -706,6 +707,12 @@ def VSPLTW : VXForm_1<652, (outs vrrc:$vD), (ins u5imm:$UIMM, vrrc:$vB),
"vspltw $vD, $vB, $UIMM", IIC_VecPerm,
[(set v16i8:$vD,
(vspltw_shuffle:$UIMM v16i8:$vB, (undef)))]>;
+let isCodeGenOnly = 1 in {
+ def VSPLTBs : VXForm_1<524, (outs vrrc:$vD), (ins u5imm:$UIMM, vfrc:$vB),
+ "vspltb $vD, $vB, $UIMM", IIC_VecPerm, []>;
+ def VSPLTHs : VXForm_1<588, (outs vrrc:$vD), (ins u5imm:$UIMM, vfrc:$vB),
+ "vsplth $vD, $vB, $UIMM", IIC_VecPerm, []>;
+}
def VSR : VX1_Int_Ty< 708, "vsr" , int_ppc_altivec_vsr, v4i32>;
def VSRO : VX1_Int_Ty<1100, "vsro" , int_ppc_altivec_vsro, v4i32>;
@@ -1218,34 +1225,23 @@ def VSBOX : VXBX_Int_Ty<1480, "vsbox", int_ppc_altivec_crypto_vsbox, v2i64>;
def HasP9Altivec : Predicate<"PPCSubTarget->hasP9Altivec()">;
let Predicates = [HasP9Altivec] in {
-// Vector Compare Not Equal (Zero)
-class P9VCMP<bits<10> xo, string asmstr, ValueType Ty>
- : VXRForm_1<xo, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB), asmstr,
- IIC_VecFPCompare, []>;
-class P9VCMPo<bits<10> xo, string asmstr, ValueType Ty>
- : VXRForm_1<xo, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB), asmstr,
- IIC_VecFPCompare, []> {
- let Defs = [CR6];
- let RC = 1;
-}
-
// i8 element comparisons.
-def VCMPNEB : P9VCMP < 7, "vcmpneb $vD, $vA, $vB" , v16i8>;
-def VCMPNEBo : P9VCMPo< 7, "vcmpneb. $vD, $vA, $vB" , v16i8>;
-def VCMPNEZB : P9VCMP <263, "vcmpnezb $vD, $vA, $vB" , v16i8>;
-def VCMPNEZBo : P9VCMPo<263, "vcmpnezb. $vD, $vA, $vB", v16i8>;
+def VCMPNEB : VCMP < 7, "vcmpneb $vD, $vA, $vB" , v16i8>;
+def VCMPNEBo : VCMPo < 7, "vcmpneb. $vD, $vA, $vB" , v16i8>;
+def VCMPNEZB : VCMP <263, "vcmpnezb $vD, $vA, $vB" , v16i8>;
+def VCMPNEZBo : VCMPo<263, "vcmpnezb. $vD, $vA, $vB", v16i8>;
// i16 element comparisons.
-def VCMPNEH : P9VCMP < 71, "vcmpneh $vD, $vA, $vB" , v8i16>;
-def VCMPNEHo : P9VCMPo< 71, "vcmpneh. $vD, $vA, $vB" , v8i16>;
-def VCMPNEZH : P9VCMP <327, "vcmpnezh $vD, $vA, $vB" , v8i16>;
-def VCMPNEZHo : P9VCMPo<327, "vcmpnezh. $vD, $vA, $vB", v8i16>;
+def VCMPNEH : VCMP < 71, "vcmpneh $vD, $vA, $vB" , v8i16>;
+def VCMPNEHo : VCMPo< 71, "vcmpneh. $vD, $vA, $vB" , v8i16>;
+def VCMPNEZH : VCMP <327, "vcmpnezh $vD, $vA, $vB" , v8i16>;
+def VCMPNEZHo : VCMPo<327, "vcmpnezh. $vD, $vA, $vB", v8i16>;
// i32 element comparisons.
-def VCMPNEW : P9VCMP <135, "vcmpnew $vD, $vA, $vB" , v4i32>;
-def VCMPNEWo : P9VCMPo<135, "vcmpnew. $vD, $vA, $vB" , v4i32>;
-def VCMPNEZW : P9VCMP <391, "vcmpnezw $vD, $vA, $vB" , v4i32>;
-def VCMPNEZWo : P9VCMPo<391, "vcmpnezw. $vD, $vA, $vB", v4i32>;
+def VCMPNEW : VCMP <135, "vcmpnew $vD, $vA, $vB" , v4i32>;
+def VCMPNEWo : VCMPo<135, "vcmpnew. $vD, $vA, $vB" , v4i32>;
+def VCMPNEZW : VCMP <391, "vcmpnezw $vD, $vA, $vB" , v4i32>;
+def VCMPNEZWo : VCMPo<391, "vcmpnezw. $vD, $vA, $vB", v4i32>;
// VX-Form: [PO VRT / UIM VRB XO].
// We use VXForm_1 to implement it, that is, we use "VRA" (5 bit) to represent
@@ -1281,17 +1277,28 @@ def VINSERTD : VX1_VT5_UIM5_VB5<973, "vinsertd", []>;
class VX_VT5_EO5_VB5<bits<11> xo, bits<5> eo, string opc, list<dag> pattern>
: VXForm_RD5_XO5_RS5<xo, eo, (outs vrrc:$vD), (ins vrrc:$vB),
!strconcat(opc, " $vD, $vB"), IIC_VecGeneral, pattern>;
+class VX_VT5_EO5_VB5s<bits<11> xo, bits<5> eo, string opc, list<dag> pattern>
+ : VXForm_RD5_XO5_RS5<xo, eo, (outs vfrc:$vD), (ins vfrc:$vB),
+ !strconcat(opc, " $vD, $vB"), IIC_VecGeneral, pattern>;
// Vector Count Leading/Trailing Zero LSB. Result is placed into GPR[rD]
-def VCLZLSBB : VXForm_RD5_XO5_RS5<1538, 0, (outs g8rc:$rD), (ins vrrc:$vB),
- "vclzlsbb $rD, $vB", IIC_VecGeneral, []>;
-def VCTZLSBB : VXForm_RD5_XO5_RS5<1538, 1, (outs g8rc:$rD), (ins vrrc:$vB),
- "vctzlsbb $rD, $vB", IIC_VecGeneral, []>;
+def VCLZLSBB : VXForm_RD5_XO5_RS5<1538, 0, (outs gprc:$rD), (ins vrrc:$vB),
+ "vclzlsbb $rD, $vB", IIC_VecGeneral,
+ [(set i32:$rD, (int_ppc_altivec_vclzlsbb
+ v16i8:$vB))]>;
+def VCTZLSBB : VXForm_RD5_XO5_RS5<1538, 1, (outs gprc:$rD), (ins vrrc:$vB),
+ "vctzlsbb $rD, $vB", IIC_VecGeneral,
+ [(set i32:$rD, (int_ppc_altivec_vctzlsbb
+ v16i8:$vB))]>;
// Vector Count Trailing Zeros
-def VCTZB : VX_VT5_EO5_VB5<1538, 28, "vctzb", []>;
-def VCTZH : VX_VT5_EO5_VB5<1538, 29, "vctzh", []>;
-def VCTZW : VX_VT5_EO5_VB5<1538, 30, "vctzw", []>;
-def VCTZD : VX_VT5_EO5_VB5<1538, 31, "vctzd", []>;
+def VCTZB : VX_VT5_EO5_VB5<1538, 28, "vctzb",
+ [(set v16i8:$vD, (cttz v16i8:$vB))]>;
+def VCTZH : VX_VT5_EO5_VB5<1538, 29, "vctzh",
+ [(set v8i16:$vD, (cttz v8i16:$vB))]>;
+def VCTZW : VX_VT5_EO5_VB5<1538, 30, "vctzw",
+ [(set v4i32:$vD, (cttz v4i32:$vB))]>;
+def VCTZD : VX_VT5_EO5_VB5<1538, 31, "vctzd",
+ [(set v2i64:$vD, (cttz v2i64:$vB))]>;
// Vector Extend Sign
def VEXTSB2W : VX_VT5_EO5_VB5<1538, 16, "vextsb2w", []>;
@@ -1299,15 +1306,31 @@ def VEXTSH2W : VX_VT5_EO5_VB5<1538, 17, "vextsh2w", []>;
def VEXTSB2D : VX_VT5_EO5_VB5<1538, 24, "vextsb2d", []>;
def VEXTSH2D : VX_VT5_EO5_VB5<1538, 25, "vextsh2d", []>;
def VEXTSW2D : VX_VT5_EO5_VB5<1538, 26, "vextsw2d", []>;
+let isCodeGenOnly = 1 in {
+ def VEXTSB2Ws : VX_VT5_EO5_VB5s<1538, 16, "vextsb2w", []>;
+ def VEXTSH2Ws : VX_VT5_EO5_VB5s<1538, 17, "vextsh2w", []>;
+ def VEXTSB2Ds : VX_VT5_EO5_VB5s<1538, 24, "vextsb2d", []>;
+ def VEXTSH2Ds : VX_VT5_EO5_VB5s<1538, 25, "vextsh2d", []>;
+ def VEXTSW2Ds : VX_VT5_EO5_VB5s<1538, 26, "vextsw2d", []>;
+}
// Vector Integer Negate
-def VNEGW : VX_VT5_EO5_VB5<1538, 6, "vnegw", []>;
-def VNEGD : VX_VT5_EO5_VB5<1538, 7, "vnegd", []>;
+def VNEGW : VX_VT5_EO5_VB5<1538, 6, "vnegw",
+ [(set v4i32:$vD,
+ (sub (v4i32 immAllZerosV), v4i32:$vB))]>;
+
+def VNEGD : VX_VT5_EO5_VB5<1538, 7, "vnegd",
+ [(set v2i64:$vD,
+ (sub (v2i64 (bitconvert (v4i32 immAllZerosV))),
+ v2i64:$vB))]>;
// Vector Parity Byte
-def VPRTYBW : VX_VT5_EO5_VB5<1538, 8, "vprtybw", []>;
-def VPRTYBD : VX_VT5_EO5_VB5<1538, 9, "vprtybd", []>;
-def VPRTYBQ : VX_VT5_EO5_VB5<1538, 10, "vprtybq", []>;
+def VPRTYBW : VX_VT5_EO5_VB5<1538, 8, "vprtybw", [(set v4i32:$vD,
+ (int_ppc_altivec_vprtybw v4i32:$vB))]>;
+def VPRTYBD : VX_VT5_EO5_VB5<1538, 9, "vprtybd", [(set v2i64:$vD,
+ (int_ppc_altivec_vprtybd v2i64:$vB))]>;
+def VPRTYBQ : VX_VT5_EO5_VB5<1538, 10, "vprtybq", [(set v1i128:$vD,
+ (int_ppc_altivec_vprtybq v1i128:$vB))]>;
// Vector (Bit) Permute (Right-indexed)
def VBPERMD : VXForm_1<1484, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB),
@@ -1320,14 +1343,32 @@ class VX1_VT5_VA5_VB5<bits<11> xo, string opc, list<dag> pattern>
!strconcat(opc, " $vD, $vA, $vB"), IIC_VecFP, pattern>;
// Vector Rotate Left Mask/Mask-Insert
-def VRLWNM : VX1_VT5_VA5_VB5<389, "vrlwnm", []>;
-def VRLWMI : VX1_VT5_VA5_VB5<133, "vrlwmi", []>;
-def VRLDNM : VX1_VT5_VA5_VB5<453, "vrldnm", []>;
-def VRLDMI : VX1_VT5_VA5_VB5<197, "vrldmi", []>;
+def VRLWNM : VX1_VT5_VA5_VB5<389, "vrlwnm",
+ [(set v4i32:$vD,
+ (int_ppc_altivec_vrlwnm v4i32:$vA,
+ v4i32:$vB))]>;
+def VRLWMI : VXForm_1<133, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB, vrrc:$vDi),
+ "vrlwmi $vD, $vA, $vB", IIC_VecFP,
+ [(set v4i32:$vD,
+ (int_ppc_altivec_vrlwmi v4i32:$vA, v4i32:$vB,
+ v4i32:$vDi))]>,
+ RegConstraint<"$vDi = $vD">, NoEncode<"$vDi">;
+def VRLDNM : VX1_VT5_VA5_VB5<453, "vrldnm",
+ [(set v2i64:$vD,
+ (int_ppc_altivec_vrldnm v2i64:$vA,
+ v2i64:$vB))]>;
+def VRLDMI : VXForm_1<197, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB, vrrc:$vDi),
+ "vrldmi $vD, $vA, $vB", IIC_VecFP,
+ [(set v2i64:$vD,
+ (int_ppc_altivec_vrldmi v2i64:$vA, v2i64:$vB,
+ v2i64:$vDi))]>,
+ RegConstraint<"$vDi = $vD">, NoEncode<"$vDi">;
// Vector Shift Left/Right
-def VSLV : VX1_VT5_VA5_VB5<1860, "vslv", []>;
-def VSRV : VX1_VT5_VA5_VB5<1796, "vsrv", []>;
+def VSLV : VX1_VT5_VA5_VB5<1860, "vslv",
+ [(set v16i8 : $vD, (int_ppc_altivec_vslv v16i8 : $vA, v16i8 : $vB))]>;
+def VSRV : VX1_VT5_VA5_VB5<1796, "vsrv",
+ [(set v16i8 : $vD, (int_ppc_altivec_vsrv v16i8 : $vA, v16i8 : $vB))]>;
// Vector Multiply-by-10 (& Write Carry) Unsigned Quadword
def VMUL10UQ : VXForm_BX<513, (outs vrrc:$vD), (ins vrrc:$vA),
@@ -1396,4 +1437,15 @@ def BCDSRo : VX_VT5_VA5_VB5_PS1_XO9_o<449, "bcdsr.", []>;
// Decimal (Unsigned) Truncate
def BCDTRUNCo : VX_VT5_VA5_VB5_PS1_XO9_o<257, "bcdtrunc." , []>;
def BCDUTRUNCo : VX_VT5_VA5_VB5_XO9_o <321, "bcdutrunc.", []>;
+
+// Absolute Difference
+def VABSDUB : VXForm_1<1027, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB),
+ "vabsdub $vD, $vA, $vB", IIC_VecGeneral,
+ [(set v16i8:$vD, (int_ppc_altivec_vabsdub v16i8:$vA, v16i8:$vB))]>;
+def VABSDUH : VXForm_1<1091, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB),
+ "vabsduh $vD, $vA, $vB", IIC_VecGeneral,
+ [(set v8i16:$vD, (int_ppc_altivec_vabsduh v8i16:$vA, v8i16:$vB))]>;
+def VABSDUW : VXForm_1<1155, (outs vrrc:$vD), (ins vrrc:$vA, vrrc:$vB),
+ "vabsduw $vD, $vA, $vB", IIC_VecGeneral,
+ [(set v4i32:$vD, (int_ppc_altivec_vabsduw v4i32:$vA, v4i32:$vB))]>;
} // end HasP9Altivec
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrFormats.td b/contrib/llvm/lib/Target/PowerPC/PPCInstrFormats.td
index 5acff75..ef7d201 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrFormats.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrFormats.td
@@ -38,6 +38,14 @@ class I<bits<6> opcode, dag OOL, dag IOL, string asmstr, InstrItinClass itin>
let TSFlags{2} = PPC970_Cracked;
let TSFlags{5-3} = PPC970_Unit;
+ /// Indicate that the VSX instruction is to use VSX numbering/encoding.
+ /// Since ISA 3.0, there are scalar instructions that use the upper
+ /// half of the VSX register set only. Rather than adding further complexity
+ /// to the register class set, the VSX registers just include the Altivec
+ /// registers and this flag decides the numbering to be used for them.
+ bits<1> UseVSXReg = 0;
+ let TSFlags{6} = UseVSXReg;
+
// Fields used for relation models.
string BaseName = "";
@@ -62,6 +70,8 @@ class PPC970_Unit_VALU { bits<3> PPC970_Unit = 5; }
class PPC970_Unit_VPERM { bits<3> PPC970_Unit = 6; }
class PPC970_Unit_BRU { bits<3> PPC970_Unit = 7; }
+class UseVSXReg { bits<1> UseVSXReg = 1; }
+
// Two joined instructions; used to emit two adjacent instructions as one.
// The itinerary from the first instruction is used for scheduling and
// classification.
@@ -163,6 +173,22 @@ class BForm_3<bits<6> opcode, bit aa, bit lk,
let Inst{31} = lk;
}
+class BForm_3_at<bits<6> opcode, bit aa, bit lk,
+ dag OOL, dag IOL, string asmstr>
+ : I<opcode, OOL, IOL, asmstr, IIC_BrB> {
+ bits<5> BO;
+ bits<2> at;
+ bits<5> BI;
+ bits<14> BD;
+
+ let Inst{6-8} = BO{4-2};
+ let Inst{9-10} = at;
+ let Inst{11-15} = BI;
+ let Inst{16-29} = BD;
+ let Inst{30} = aa;
+ let Inst{31} = lk;
+}
+
class BForm_4<bits<6> opcode, bits<5> bo, bit aa, bit lk,
dag OOL, dag IOL, string asmstr>
: I<opcode, OOL, IOL, asmstr, IIC_BrB> {
@@ -577,6 +603,12 @@ class XForm_17<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
let Inst{31} = 0;
}
+class XForm_17a<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
+ InstrItinClass itin>
+ : XForm_17<opcode, xo, OOL, IOL, asmstr, itin > {
+ let FRA = 0;
+}
+
// Used for QPX
class XForm_18<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
@@ -1043,6 +1075,20 @@ class XX3Form<bits<6> opcode, bits<8> xo, dag OOL, dag IOL, string asmstr,
let Inst{31} = XT{5};
}
+class XX3Form_Zero<bits<6> opcode, bits<8> xo, dag OOL, dag IOL, string asmstr,
+ InstrItinClass itin, list<dag> pattern>
+ : XX3Form<opcode, xo, OOL, IOL, asmstr, itin, pattern> {
+ let XA = XT;
+ let XB = XT;
+}
+
+class XX3Form_SetZero<bits<6> opcode, bits<8> xo, dag OOL, dag IOL, string asmstr,
+ InstrItinClass itin, list<dag> pattern>
+ : XX3Form<opcode, xo, OOL, IOL, asmstr, itin, pattern> {
+ let XB = XT;
+ let XA = XT;
+}
+
class XX3Form_1<bits<6> opcode, bits<8> xo, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
@@ -1193,6 +1239,25 @@ class XLForm_1<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
let Inst{31} = 0;
}
+class XLForm_1_np<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
+ InstrItinClass itin, list<dag> pattern>
+ : XLForm_1<opcode, xo, OOL, IOL, asmstr, itin, pattern> {
+ let CRD = 0;
+ let CRA = 0;
+ let CRB = 0;
+}
+
+class XLForm_1_gen<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
+ InstrItinClass itin, list<dag> pattern>
+ : XLForm_1<opcode, xo, OOL, IOL, asmstr, itin, pattern> {
+ bits<5> RT;
+ bits<5> RB;
+
+ let CRD = RT;
+ let CRA = 0;
+ let CRB = RB;
+}
+
class XLForm_1_ext<bits<6> opcode, bits<10> xo, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<opcode, OOL, IOL, asmstr, itin> {
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
index b6ae70e..2e0b935 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp
@@ -273,6 +273,7 @@ unsigned PPCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
case PPC::RESTORE_CRBIT:
case PPC::LVX:
case PPC::LXVD2X:
+ case PPC::LXVX:
case PPC::QVLFDX:
case PPC::QVLFSXs:
case PPC::QVLFDXb:
@@ -302,6 +303,7 @@ unsigned PPCInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
case PPC::SPILL_CRBIT:
case PPC::STVX:
case PPC::STXVD2X:
+ case PPC::STXVX:
case PPC::QVSTFDX:
case PPC::QVSTFSXs:
case PPC::QVSTFDXb:
@@ -460,57 +462,57 @@ bool PPCInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
// Get the last instruction in the block.
- MachineInstr *LastInst = I;
+ MachineInstr &LastInst = *I;
// If there is only one terminator instruction, process it.
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
- if (LastInst->getOpcode() == PPC::B) {
- if (!LastInst->getOperand(0).isMBB())
+ if (LastInst.getOpcode() == PPC::B) {
+ if (!LastInst.getOperand(0).isMBB())
return true;
- TBB = LastInst->getOperand(0).getMBB();
+ TBB = LastInst.getOperand(0).getMBB();
return false;
- } else if (LastInst->getOpcode() == PPC::BCC) {
- if (!LastInst->getOperand(2).isMBB())
+ } else if (LastInst.getOpcode() == PPC::BCC) {
+ if (!LastInst.getOperand(2).isMBB())
return true;
// Block ends with fall-through condbranch.
- TBB = LastInst->getOperand(2).getMBB();
- Cond.push_back(LastInst->getOperand(0));
- Cond.push_back(LastInst->getOperand(1));
+ TBB = LastInst.getOperand(2).getMBB();
+ Cond.push_back(LastInst.getOperand(0));
+ Cond.push_back(LastInst.getOperand(1));
return false;
- } else if (LastInst->getOpcode() == PPC::BC) {
- if (!LastInst->getOperand(1).isMBB())
+ } else if (LastInst.getOpcode() == PPC::BC) {
+ if (!LastInst.getOperand(1).isMBB())
return true;
// Block ends with fall-through condbranch.
- TBB = LastInst->getOperand(1).getMBB();
+ TBB = LastInst.getOperand(1).getMBB();
Cond.push_back(MachineOperand::CreateImm(PPC::PRED_BIT_SET));
- Cond.push_back(LastInst->getOperand(0));
+ Cond.push_back(LastInst.getOperand(0));
return false;
- } else if (LastInst->getOpcode() == PPC::BCn) {
- if (!LastInst->getOperand(1).isMBB())
+ } else if (LastInst.getOpcode() == PPC::BCn) {
+ if (!LastInst.getOperand(1).isMBB())
return true;
// Block ends with fall-through condbranch.
- TBB = LastInst->getOperand(1).getMBB();
+ TBB = LastInst.getOperand(1).getMBB();
Cond.push_back(MachineOperand::CreateImm(PPC::PRED_BIT_UNSET));
- Cond.push_back(LastInst->getOperand(0));
+ Cond.push_back(LastInst.getOperand(0));
return false;
- } else if (LastInst->getOpcode() == PPC::BDNZ8 ||
- LastInst->getOpcode() == PPC::BDNZ) {
- if (!LastInst->getOperand(0).isMBB())
+ } else if (LastInst.getOpcode() == PPC::BDNZ8 ||
+ LastInst.getOpcode() == PPC::BDNZ) {
+ if (!LastInst.getOperand(0).isMBB())
return true;
if (DisableCTRLoopAnal)
return true;
- TBB = LastInst->getOperand(0).getMBB();
+ TBB = LastInst.getOperand(0).getMBB();
Cond.push_back(MachineOperand::CreateImm(1));
Cond.push_back(MachineOperand::CreateReg(isPPC64 ? PPC::CTR8 : PPC::CTR,
true));
return false;
- } else if (LastInst->getOpcode() == PPC::BDZ8 ||
- LastInst->getOpcode() == PPC::BDZ) {
- if (!LastInst->getOperand(0).isMBB())
+ } else if (LastInst.getOpcode() == PPC::BDZ8 ||
+ LastInst.getOpcode() == PPC::BDZ) {
+ if (!LastInst.getOperand(0).isMBB())
return true;
if (DisableCTRLoopAnal)
return true;
- TBB = LastInst->getOperand(0).getMBB();
+ TBB = LastInst.getOperand(0).getMBB();
Cond.push_back(MachineOperand::CreateImm(0));
Cond.push_back(MachineOperand::CreateReg(isPPC64 ? PPC::CTR8 : PPC::CTR,
true));
@@ -522,80 +524,79 @@ bool PPCInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
}
// Get the instruction before it if it's a terminator.
- MachineInstr *SecondLastInst = I;
+ MachineInstr &SecondLastInst = *I;
// If there are three terminators, we don't know what sort of block this is.
- if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I))
+ if (I != MBB.begin() && isUnpredicatedTerminator(*--I))
return true;
// If the block ends with PPC::B and PPC:BCC, handle it.
- if (SecondLastInst->getOpcode() == PPC::BCC &&
- LastInst->getOpcode() == PPC::B) {
- if (!SecondLastInst->getOperand(2).isMBB() ||
- !LastInst->getOperand(0).isMBB())
+ if (SecondLastInst.getOpcode() == PPC::BCC &&
+ LastInst.getOpcode() == PPC::B) {
+ if (!SecondLastInst.getOperand(2).isMBB() ||
+ !LastInst.getOperand(0).isMBB())
return true;
- TBB = SecondLastInst->getOperand(2).getMBB();
- Cond.push_back(SecondLastInst->getOperand(0));
- Cond.push_back(SecondLastInst->getOperand(1));
- FBB = LastInst->getOperand(0).getMBB();
+ TBB = SecondLastInst.getOperand(2).getMBB();
+ Cond.push_back(SecondLastInst.getOperand(0));
+ Cond.push_back(SecondLastInst.getOperand(1));
+ FBB = LastInst.getOperand(0).getMBB();
return false;
- } else if (SecondLastInst->getOpcode() == PPC::BC &&
- LastInst->getOpcode() == PPC::B) {
- if (!SecondLastInst->getOperand(1).isMBB() ||
- !LastInst->getOperand(0).isMBB())
+ } else if (SecondLastInst.getOpcode() == PPC::BC &&
+ LastInst.getOpcode() == PPC::B) {
+ if (!SecondLastInst.getOperand(1).isMBB() ||
+ !LastInst.getOperand(0).isMBB())
return true;
- TBB = SecondLastInst->getOperand(1).getMBB();
+ TBB = SecondLastInst.getOperand(1).getMBB();
Cond.push_back(MachineOperand::CreateImm(PPC::PRED_BIT_SET));
- Cond.push_back(SecondLastInst->getOperand(0));
- FBB = LastInst->getOperand(0).getMBB();
+ Cond.push_back(SecondLastInst.getOperand(0));
+ FBB = LastInst.getOperand(0).getMBB();
return false;
- } else if (SecondLastInst->getOpcode() == PPC::BCn &&
- LastInst->getOpcode() == PPC::B) {
- if (!SecondLastInst->getOperand(1).isMBB() ||
- !LastInst->getOperand(0).isMBB())
+ } else if (SecondLastInst.getOpcode() == PPC::BCn &&
+ LastInst.getOpcode() == PPC::B) {
+ if (!SecondLastInst.getOperand(1).isMBB() ||
+ !LastInst.getOperand(0).isMBB())
return true;
- TBB = SecondLastInst->getOperand(1).getMBB();
+ TBB = SecondLastInst.getOperand(1).getMBB();
Cond.push_back(MachineOperand::CreateImm(PPC::PRED_BIT_UNSET));
- Cond.push_back(SecondLastInst->getOperand(0));
- FBB = LastInst->getOperand(0).getMBB();
+ Cond.push_back(SecondLastInst.getOperand(0));
+ FBB = LastInst.getOperand(0).getMBB();
return false;
- } else if ((SecondLastInst->getOpcode() == PPC::BDNZ8 ||
- SecondLastInst->getOpcode() == PPC::BDNZ) &&
- LastInst->getOpcode() == PPC::B) {
- if (!SecondLastInst->getOperand(0).isMBB() ||
- !LastInst->getOperand(0).isMBB())
+ } else if ((SecondLastInst.getOpcode() == PPC::BDNZ8 ||
+ SecondLastInst.getOpcode() == PPC::BDNZ) &&
+ LastInst.getOpcode() == PPC::B) {
+ if (!SecondLastInst.getOperand(0).isMBB() ||
+ !LastInst.getOperand(0).isMBB())
return true;
if (DisableCTRLoopAnal)
return true;
- TBB = SecondLastInst->getOperand(0).getMBB();
+ TBB = SecondLastInst.getOperand(0).getMBB();
Cond.push_back(MachineOperand::CreateImm(1));
Cond.push_back(MachineOperand::CreateReg(isPPC64 ? PPC::CTR8 : PPC::CTR,
true));
- FBB = LastInst->getOperand(0).getMBB();
+ FBB = LastInst.getOperand(0).getMBB();
return false;
- } else if ((SecondLastInst->getOpcode() == PPC::BDZ8 ||
- SecondLastInst->getOpcode() == PPC::BDZ) &&
- LastInst->getOpcode() == PPC::B) {
- if (!SecondLastInst->getOperand(0).isMBB() ||
- !LastInst->getOperand(0).isMBB())
+ } else if ((SecondLastInst.getOpcode() == PPC::BDZ8 ||
+ SecondLastInst.getOpcode() == PPC::BDZ) &&
+ LastInst.getOpcode() == PPC::B) {
+ if (!SecondLastInst.getOperand(0).isMBB() ||
+ !LastInst.getOperand(0).isMBB())
return true;
if (DisableCTRLoopAnal)
return true;
- TBB = SecondLastInst->getOperand(0).getMBB();
+ TBB = SecondLastInst.getOperand(0).getMBB();
Cond.push_back(MachineOperand::CreateImm(0));
Cond.push_back(MachineOperand::CreateReg(isPPC64 ? PPC::CTR8 : PPC::CTR,
true));
- FBB = LastInst->getOperand(0).getMBB();
+ FBB = LastInst.getOperand(0).getMBB();
return false;
}
// If the block ends with two PPC:Bs, handle it. The second one is not
// executed, so remove it.
- if (SecondLastInst->getOpcode() == PPC::B &&
- LastInst->getOpcode() == PPC::B) {
- if (!SecondLastInst->getOperand(0).isMBB())
+ if (SecondLastInst.getOpcode() == PPC::B && LastInst.getOpcode() == PPC::B) {
+ if (!SecondLastInst.getOperand(0).isMBB())
return true;
- TBB = SecondLastInst->getOperand(0).getMBB();
+ TBB = SecondLastInst.getOperand(0).getMBB();
I = LastInst;
if (AllowModify)
I->eraseFromParent();
@@ -606,7 +607,10 @@ bool PPCInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}
-unsigned PPCInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned PPCInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end())
return 0;
@@ -635,15 +639,17 @@ unsigned PPCInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return 2;
}
-unsigned PPCInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned PPCInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"PPC branch conditions have two components!");
+ assert(!BytesAdded && "code size not handled");
bool isPPC64 = Subtarget.isPPC64();
@@ -853,15 +859,6 @@ void PPCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
llvm_unreachable("nop VSX copy");
DestReg = SuperReg;
- } else if (PPC::VRRCRegClass.contains(DestReg) &&
- PPC::VSRCRegClass.contains(SrcReg)) {
- unsigned SuperReg =
- TRI->getMatchingSuperReg(DestReg, PPC::sub_128, &PPC::VSRCRegClass);
-
- if (VSXSelfCopyCrash && SrcReg == SuperReg)
- llvm_unreachable("nop VSX copy");
-
- DestReg = SuperReg;
} else if (PPC::F8RCRegClass.contains(SrcReg) &&
PPC::VSRCRegClass.contains(DestReg)) {
unsigned SuperReg =
@@ -871,15 +868,6 @@ void PPCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
llvm_unreachable("nop VSX copy");
SrcReg = SuperReg;
- } else if (PPC::VRRCRegClass.contains(SrcReg) &&
- PPC::VSRCRegClass.contains(DestReg)) {
- unsigned SuperReg =
- TRI->getMatchingSuperReg(SrcReg, PPC::sub_128, &PPC::VSRCRegClass);
-
- if (VSXSelfCopyCrash && DestReg == SuperReg)
- llvm_unreachable("nop VSX copy");
-
- SrcReg = SuperReg;
}
// Different class register copy
@@ -1004,19 +992,22 @@ PPCInstrInfo::StoreRegToStackSlot(MachineFunction &MF,
FrameIdx));
NonRI = true;
} else if (PPC::VSRCRegClass.hasSubClassEq(RC)) {
- NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(PPC::STXVD2X))
+ unsigned Op = Subtarget.hasP9Vector() ? PPC::STXVX : PPC::STXVD2X;
+ NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(Op))
.addReg(SrcReg,
getKillRegState(isKill)),
FrameIdx));
NonRI = true;
} else if (PPC::VSFRCRegClass.hasSubClassEq(RC)) {
- NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(PPC::STXSDX))
+ unsigned Opc = Subtarget.hasP9Vector() ? PPC::DFSTOREf64 : PPC::STXSDX;
+ NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(Opc))
.addReg(SrcReg,
getKillRegState(isKill)),
FrameIdx));
NonRI = true;
} else if (PPC::VSSRCRegClass.hasSubClassEq(RC)) {
- NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(PPC::STXSSPX))
+ unsigned Opc = Subtarget.hasP9Vector() ? PPC::DFSTOREf32 : PPC::STXSSPX;
+ NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(Opc))
.addReg(SrcReg,
getKillRegState(isKill)),
FrameIdx));
@@ -1066,6 +1057,15 @@ PPCInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
FuncInfo->setHasSpills();
+ // We need to avoid a situation in which the value from a VRRC register is
+ // spilled using an Altivec instruction and reloaded into a VSRC register
+ // using a VSX instruction. The issue with this is that the VSX
+ // load/store instructions swap the doublewords in the vector and the Altivec
+ // ones don't. The register classes on the spill/reload may be different if
+ // the register is defined using an Altivec instruction and is then used by a
+ // VSX instruction.
+ RC = updatedRC(RC);
+
bool NonRI = false, SpillsVRS = false;
if (StoreRegToStackSlot(MF, SrcReg, isKill, FrameIdx, RC, NewMIs,
NonRI, SpillsVRS))
@@ -1080,7 +1080,7 @@ PPCInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
for (unsigned i = 0, e = NewMIs.size(); i != e; ++i)
MBB.insert(MI, NewMIs[i]);
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIdx),
MachineMemOperand::MOStore, MFI.getObjectSize(FrameIdx),
@@ -1125,16 +1125,19 @@ bool PPCInstrInfo::LoadRegFromStackSlot(MachineFunction &MF, const DebugLoc &DL,
FrameIdx));
NonRI = true;
} else if (PPC::VSRCRegClass.hasSubClassEq(RC)) {
- NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(PPC::LXVD2X), DestReg),
+ unsigned Op = Subtarget.hasP9Vector() ? PPC::LXVX : PPC::LXVD2X;
+ NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(Op), DestReg),
FrameIdx));
NonRI = true;
} else if (PPC::VSFRCRegClass.hasSubClassEq(RC)) {
- NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(PPC::LXSDX), DestReg),
- FrameIdx));
+ unsigned Opc = Subtarget.hasP9Vector() ? PPC::DFLOADf64 : PPC::LXSDX;
+ NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(Opc),
+ DestReg), FrameIdx));
NonRI = true;
} else if (PPC::VSSRCRegClass.hasSubClassEq(RC)) {
- NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(PPC::LXSSPX), DestReg),
- FrameIdx));
+ unsigned Opc = Subtarget.hasP9Vector() ? PPC::DFLOADf32 : PPC::LXSSPX;
+ NewMIs.push_back(addFrameReference(BuildMI(MF, DL, get(Opc),
+ DestReg), FrameIdx));
NonRI = true;
} else if (PPC::VRSAVERCRegClass.hasSubClassEq(RC)) {
assert(Subtarget.isDarwin() &&
@@ -1177,6 +1180,16 @@ PPCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
PPCFunctionInfo *FuncInfo = MF.getInfo<PPCFunctionInfo>();
FuncInfo->setHasSpills();
+ // We need to avoid a situation in which the value from a VRRC register is
+ // spilled using an Altivec instruction and reloaded into a VSRC register
+ // using a VSX instruction. The issue with this is that the VSX
+ // load/store instructions swap the doublewords in the vector and the Altivec
+ // ones don't. The register classes on the spill/reload may be different if
+ // the register is defined using an Altivec instruction and is then used by a
+ // VSX instruction.
+ if (Subtarget.hasVSX() && RC == &PPC::VRRCRegClass)
+ RC = &PPC::VSRCRegClass;
+
bool NonRI = false, SpillsVRS = false;
if (LoadRegFromStackSlot(MF, DL, DestReg, FrameIdx, RC, NewMIs,
NonRI, SpillsVRS))
@@ -1191,7 +1204,7 @@ PPCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
for (unsigned i = 0, e = NewMIs.size(); i != e; ++i)
MBB.insert(MI, NewMIs[i]);
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIdx),
MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIdx),
@@ -1200,7 +1213,7 @@ PPCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
}
bool PPCInstrInfo::
-ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 2 && "Invalid PPC branch opcode!");
if (Cond[1].getReg() == PPC::CTR8 || Cond[1].getReg() == PPC::CTR)
Cond[0].setImm(Cond[0].getImm() == 0 ? 1 : 0);
@@ -1809,7 +1822,7 @@ bool PPCInstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg,
/// GetInstSize - Return the number of bytes of code the specified
/// instruction may be. This returns the maximum number of bytes.
///
-unsigned PPCInstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
+unsigned PPCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
unsigned Opcode = MI.getOpcode();
if (Opcode == PPC::INLINEASM) {
@@ -1817,10 +1830,11 @@ unsigned PPCInstrInfo::GetInstSizeInBytes(const MachineInstr &MI) const {
const char *AsmStr = MI.getOperand(0).getSymbolName();
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
} else if (Opcode == TargetOpcode::STACKMAP) {
- return MI.getOperand(1).getImm();
+ StackMapOpers Opers(&MI);
+ return Opers.getNumPatchBytes();
} else if (Opcode == TargetOpcode::PATCHPOINT) {
PatchPointOpers Opers(&MI);
- return Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
+ return Opers.getNumPatchBytes();
} else {
const MCInstrDesc &Desc = get(Opcode);
return Desc.getSize();
@@ -1872,6 +1886,48 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
.addReg(Reg);
return true;
}
+ case PPC::DFLOADf32:
+ case PPC::DFLOADf64:
+ case PPC::DFSTOREf32:
+ case PPC::DFSTOREf64: {
+ assert(Subtarget.hasP9Vector() &&
+ "Invalid D-Form Pseudo-ops on non-P9 target.");
+ unsigned UpperOpcode, LowerOpcode;
+ switch (MI.getOpcode()) {
+ case PPC::DFLOADf32:
+ UpperOpcode = PPC::LXSSP;
+ LowerOpcode = PPC::LFS;
+ break;
+ case PPC::DFLOADf64:
+ UpperOpcode = PPC::LXSD;
+ LowerOpcode = PPC::LFD;
+ break;
+ case PPC::DFSTOREf32:
+ UpperOpcode = PPC::STXSSP;
+ LowerOpcode = PPC::STFS;
+ break;
+ case PPC::DFSTOREf64:
+ UpperOpcode = PPC::STXSD;
+ LowerOpcode = PPC::STFD;
+ break;
+ }
+ unsigned TargetReg = MI.getOperand(0).getReg();
+ unsigned Opcode;
+ if ((TargetReg >= PPC::F0 && TargetReg <= PPC::F31) ||
+ (TargetReg >= PPC::VSL0 && TargetReg <= PPC::VSL31))
+ Opcode = LowerOpcode;
+ else
+ Opcode = UpperOpcode;
+ MI.setDesc(get(Opcode));
+ return true;
+ }
}
return false;
}
+
+const TargetRegisterClass *
+PPCInstrInfo::updatedRC(const TargetRegisterClass *RC) const {
+ if (Subtarget.hasVSX() && RC == &PPC::VRRCRegClass)
+ return &PPC::VSRCRegClass;
+ return RC;
+}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h
index 98baf12..32b2f00 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h
@@ -61,6 +61,15 @@ enum PPC970_Unit {
PPC970_VPERM = 6 << PPC970_Shift, // Vector Permute Unit
PPC970_BRU = 7 << PPC970_Shift // Branch Unit
};
+
+enum {
+ /// Shift count to bypass PPC970 flags
+ NewDef_Shift = 6,
+
+ /// The VSX instruction that uses VSX register (vs0-vs63), instead of VMX
+ /// register (v0-v31).
+ UseVSXReg = 0x1 << NewDef_Shift
+};
} // end namespace PPCII
class PPCSubtarget;
@@ -168,10 +177,12 @@ public:
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
// Select analysis.
bool canInsertSelect(const MachineBasicBlock &, ArrayRef<MachineOperand> Cond,
@@ -198,7 +209,7 @@ public:
const TargetRegisterInfo *TRI) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
bool FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, unsigned Reg,
MachineRegisterInfo *MRI) const override;
@@ -256,7 +267,7 @@ public:
/// GetInstSize - Return the number of bytes of code the specified
/// instruction may be. This returns the maximum number of bytes.
///
- unsigned GetInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
void getNoopForMachoTarget(MCInst &NopInst) const override;
@@ -271,6 +282,14 @@ public:
// Lower pseudo instructions after register allocation.
bool expandPostRAPseudo(MachineInstr &MI) const override;
+
+ static bool isVFRegister(unsigned Reg) {
+ return Reg >= PPC::VF0 && Reg <= PPC::VF31;
+ }
+ static bool isVRRegister(unsigned Reg) {
+ return Reg >= PPC::V0 && Reg <= PPC::V31;
+ }
+ const TargetRegisterClass *updatedRC(const TargetRegisterClass *RC) const;
};
}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td
index a40d4e1..f615cc7 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td
@@ -23,6 +23,15 @@ def SDT_PPCstfiwx : SDTypeProfile<0, 2, [ // stfiwx
def SDT_PPClfiwx : SDTypeProfile<1, 1, [ // lfiw[az]x
SDTCisVT<0, f64>, SDTCisPtrTy<1>
]>;
+def SDT_PPCLxsizx : SDTypeProfile<1, 2, [
+ SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2>
+]>;
+def SDT_PPCstxsix : SDTypeProfile<0, 3, [
+ SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2>
+]>;
+def SDT_PPCVexts : SDTypeProfile<1, 2, [
+ SDTCisVT<0, f64>, SDTCisVT<1, f64>, SDTCisPtrTy<2>
+]>;
def SDT_PPCCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
def SDT_PPCCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
@@ -108,6 +117,11 @@ def PPClfiwax : SDNode<"PPCISD::LFIWAX", SDT_PPClfiwx,
[SDNPHasChain, SDNPMayLoad]>;
def PPClfiwzx : SDNode<"PPCISD::LFIWZX", SDT_PPClfiwx,
[SDNPHasChain, SDNPMayLoad]>;
+def PPClxsizx : SDNode<"PPCISD::LXSIZX", SDT_PPCLxsizx,
+ [SDNPHasChain, SDNPMayLoad]>;
+def PPCstxsix : SDNode<"PPCISD::STXSIX", SDT_PPCstxsix,
+ [SDNPHasChain, SDNPMayStore]>;
+def PPCVexts : SDNode<"PPCISD::VEXTS", SDT_PPCVexts, []>;
// Extract FPSCR (not modeled at the DAG level).
def PPCmffs : SDNode<"PPCISD::MFFS",
@@ -312,6 +326,8 @@ def immZExt16 : PatLeaf<(imm), [{
// field. Used by instructions like 'ori'.
return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue();
}], LO16>;
+def immAnyExt8 : ImmLeaf<i32, [{ return isInt<8>(Imm) || isUInt<8>(Imm); }]>;
+def immSExt5NonZero : ImmLeaf<i32, [{ return Imm && isInt<5>(Imm); }]>;
// imm16Shifted* - These match immediates where the low 16-bits are zero. There
// are two forms: imm16ShiftedSExt and imm16ShiftedZExt. These two forms are
@@ -444,6 +460,12 @@ def PPCRegVRRCAsmOperand : AsmOperandClass {
def vrrc : RegisterOperand<VRRC> {
let ParserMatchClass = PPCRegVRRCAsmOperand;
}
+def PPCRegVFRCAsmOperand : AsmOperandClass {
+ let Name = "RegVFRC"; let PredicateMethod = "isRegNumber";
+}
+def vfrc : RegisterOperand<VFRC> {
+ let ParserMatchClass = PPCRegVFRCAsmOperand;
+}
def PPCRegCRBITRCAsmOperand : AsmOperandClass {
let Name = "RegCRBITRC"; let PredicateMethod = "isCRBitNumber";
}
@@ -478,6 +500,15 @@ def u2imm : Operand<i32> {
let ParserMatchClass = PPCU2ImmAsmOperand;
}
+def PPCATBitsAsHintAsmOperand : AsmOperandClass {
+ let Name = "ATBitsAsHint"; let PredicateMethod = "isATBitsAsHint";
+ let RenderMethod = "addImmOperands"; // Irrelevant, predicate always fails.
+}
+def atimm : Operand<i32> {
+ let PrintMethod = "printATBitsAsHint";
+ let ParserMatchClass = PPCATBitsAsHintAsmOperand;
+}
+
def PPCU3ImmAsmOperand : AsmOperandClass {
let Name = "U3Imm"; let PredicateMethod = "isU3Imm";
let RenderMethod = "addImmOperands";
@@ -591,6 +622,9 @@ def s17imm : Operand<i32> {
let ParserMatchClass = PPCS17ImmAsmOperand;
let DecoderMethod = "decodeSImmOperand<16>";
}
+
+def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;
+
def PPCDirectBrAsmOperand : AsmOperandClass {
let Name = "DirectBr"; let PredicateMethod = "isDirectBr";
let RenderMethod = "addBranchTargetOperands";
@@ -1448,9 +1482,6 @@ def RFEBB : XLForm_S<19, 146, (outs), (ins u1imm:$imm), "rfebb $imm",
def DCBA : DCB_Form<758, 0, (outs), (ins memrr:$dst), "dcba $dst",
IIC_LdStDCBF, [(int_ppc_dcba xoaddr:$dst)]>,
PPC970_DGroup_Single;
-def DCBF : DCB_Form<86, 0, (outs), (ins memrr:$dst), "dcbf $dst",
- IIC_LdStDCBF, [(int_ppc_dcbf xoaddr:$dst)]>,
- PPC970_DGroup_Single;
def DCBI : DCB_Form<470, 0, (outs), (ins memrr:$dst), "dcbi $dst",
IIC_LdStDCBF, [(int_ppc_dcbi xoaddr:$dst)]>,
PPC970_DGroup_Single;
@@ -1464,6 +1495,10 @@ def DCBZL : DCB_Form<1014, 1, (outs), (ins memrr:$dst), "dcbzl $dst",
IIC_LdStDCBF, [(int_ppc_dcbzl xoaddr:$dst)]>,
PPC970_DGroup_Single;
+def DCBF : DCB_Form_hint<86, (outs), (ins u5imm:$TH, memrr:$dst),
+ "dcbf $dst, $TH", IIC_LdStDCBF, []>,
+ PPC970_DGroup_Single;
+
let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in {
def DCBT : DCB_Form_hint<278, (outs), (ins u5imm:$TH, memrr:$dst),
"dcbt $dst, $TH", IIC_LdStDCBF, []>,
@@ -1473,13 +1508,21 @@ def DCBTST : DCB_Form_hint<246, (outs), (ins u5imm:$TH, memrr:$dst),
PPC970_DGroup_Single;
} // hasSideEffects = 0
+def ICBLC : XForm_icbt<31, 230, (outs), (ins u4imm:$CT, memrr:$src),
+ "icblc $CT, $src", IIC_LdStStore>, Requires<[HasICBT]>;
+def ICBLQ : XForm_icbt<31, 198, (outs), (ins u4imm:$CT, memrr:$src),
+ "icblq. $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
def ICBT : XForm_icbt<31, 22, (outs), (ins u4imm:$CT, memrr:$src),
"icbt $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
+def ICBTLS : XForm_icbt<31, 486, (outs), (ins u4imm:$CT, memrr:$src),
+ "icbtls $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>;
def : Pat<(int_ppc_dcbt xoaddr:$dst),
(DCBT 0, xoaddr:$dst)>;
def : Pat<(int_ppc_dcbtst xoaddr:$dst),
(DCBTST 0, xoaddr:$dst)>;
+def : Pat<(int_ppc_dcbf xoaddr:$dst),
+ (DCBF 0, xoaddr:$dst)>;
def : Pat<(prefetch xoaddr:$dst, (i32 0), imm, (i32 1)),
(DCBT 0, xoaddr:$dst)>; // data prefetch for loads
@@ -2135,26 +2178,34 @@ let isCompare = 1, hasSideEffects = 0 in {
"fcmpu $crD, $fA, $fB", IIC_FPCompare>;
}
+def FTDIV: XForm_17<63, 128, (outs crrc:$crD), (ins f8rc:$fA, f8rc:$fB),
+ "ftdiv $crD, $fA, $fB", IIC_FPCompare>;
+def FTSQRT: XForm_17a<63, 160, (outs crrc:$crD), (ins f8rc:$fB),
+ "ftsqrt $crD, $fB", IIC_FPCompare>;
+
let Uses = [RM] in {
let hasSideEffects = 0 in {
defm FCTIW : XForm_26r<63, 14, (outs f8rc:$frD), (ins f8rc:$frB),
"fctiw", "$frD, $frB", IIC_FPGeneral,
[]>;
+ defm FCTIWU : XForm_26r<63, 142, (outs f8rc:$frD), (ins f8rc:$frB),
+ "fctiwu", "$frD, $frB", IIC_FPGeneral,
+ []>;
defm FCTIWZ : XForm_26r<63, 15, (outs f8rc:$frD), (ins f8rc:$frB),
"fctiwz", "$frD, $frB", IIC_FPGeneral,
[(set f64:$frD, (PPCfctiwz f64:$frB))]>;
defm FRSP : XForm_26r<63, 12, (outs f4rc:$frD), (ins f8rc:$frB),
"frsp", "$frD, $frB", IIC_FPGeneral,
- [(set f32:$frD, (fround f64:$frB))]>;
+ [(set f32:$frD, (fpround f64:$frB))]>;
let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm FRIND : XForm_26r<63, 392, (outs f8rc:$frD), (ins f8rc:$frB),
"frin", "$frD, $frB", IIC_FPGeneral,
- [(set f64:$frD, (frnd f64:$frB))]>;
+ [(set f64:$frD, (fround f64:$frB))]>;
defm FRINS : XForm_26r<63, 392, (outs f4rc:$frD), (ins f4rc:$frB),
"frin", "$frD, $frB", IIC_FPGeneral,
- [(set f32:$frD, (frnd f32:$frB))]>;
+ [(set f32:$frD, (fround f32:$frB))]>;
}
let hasSideEffects = 0 in {
@@ -2336,6 +2387,13 @@ def MTSPR : XFXForm_1<31, 467, (outs), (ins i32imm:$SPR, gprc:$RT),
def MFTB : XFXForm_1<31, 371, (outs gprc:$RT), (ins i32imm:$SPR),
"mftb $RT, $SPR", IIC_SprMFTB>;
+def MFPMR : XFXForm_1<31, 334, (outs gprc:$RT), (ins i32imm:$SPR),
+ "mfpmr $RT, $SPR", IIC_SprMFPMR>;
+
+def MTPMR : XFXForm_1<31, 462, (outs), (ins i32imm:$SPR, gprc:$RT),
+ "mtpmr $SPR, $RT", IIC_SprMTPMR>;
+
+
// A pseudo-instruction used to implement the read of the 64-bit cycle counter
// on a 32-bit target.
let hasSideEffects = 1, usesCustomInserter = 1 in
@@ -2892,7 +2950,7 @@ def : Pat<(f64 (extloadf32 iaddr:$src)),
def : Pat<(f64 (extloadf32 xaddr:$src)),
(COPY_TO_REGCLASS (LFSX xaddr:$src), F8RC)>;
-def : Pat<(f64 (fextend f32:$src)),
+def : Pat<(f64 (fpextend f32:$src)),
(COPY_TO_REGCLASS $src, F8RC)>;
// Only seq_cst fences require the heavyweight sync (SYNC 0).
@@ -3185,6 +3243,46 @@ defm : ExtSetCCPat<SETLE,
OutPatFrag<(ops node:$in),
(RLDICL $in, 1, 63)> >;
+// An extended SETCC with shift amount.
+multiclass ExtSetCCShiftPat<CondCode cc, PatFrag pfrag,
+ OutPatFrag rfrag, OutPatFrag rfrag8> {
+ def : Pat<(i32 (zext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
+ (rfrag $s1, $sa)>;
+ def : Pat<(i64 (zext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
+ (rfrag8 $s1, $sa)>;
+ def : Pat<(i64 (zext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
+ (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $sa), sub_32)>;
+ def : Pat<(i32 (zext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
+ (EXTRACT_SUBREG (rfrag8 $s1, $sa), sub_32)>;
+
+ def : Pat<(i32 (anyext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
+ (rfrag $s1, $sa)>;
+ def : Pat<(i64 (anyext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
+ (rfrag8 $s1, $sa)>;
+ def : Pat<(i64 (anyext (i1 (pfrag i32:$s1, i32:$sa, cc)))),
+ (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $sa), sub_32)>;
+ def : Pat<(i32 (anyext (i1 (pfrag i64:$s1, i32:$sa, cc)))),
+ (EXTRACT_SUBREG (rfrag8 $s1, $sa), sub_32)>;
+}
+
+defm : ExtSetCCShiftPat<SETNE,
+ PatFrag<(ops node:$in, node:$sa, node:$cc),
+ (setcc (and $in, (shl 1, $sa)), 0, $cc)>,
+ OutPatFrag<(ops node:$in, node:$sa),
+ (RLWNM $in, (SUBFIC $sa, 32), 31, 31)>,
+ OutPatFrag<(ops node:$in, node:$sa),
+ (RLDCL $in, (SUBFIC $sa, 64), 63)> >;
+
+defm : ExtSetCCShiftPat<SETEQ,
+ PatFrag<(ops node:$in, node:$sa, node:$cc),
+ (setcc (and $in, (shl 1, $sa)), 0, $cc)>,
+ OutPatFrag<(ops node:$in, node:$sa),
+ (RLWNM (i32not $in),
+ (SUBFIC $sa, 32), 31, 31)>,
+ OutPatFrag<(ops node:$in, node:$sa),
+ (RLDCL (i64not $in),
+ (SUBFIC $sa, 64), 63)> >;
+
// SETCC for i32.
def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETULT)),
(EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_lt)>;
@@ -3654,6 +3752,9 @@ def SLBMTE : XForm_26<31, 402, (outs), (ins gprc:$RS, gprc:$RB),
def SLBMFEE : XForm_26<31, 915, (outs gprc:$RT), (ins gprc:$RB),
"slbmfee $RT, $RB", IIC_SprSLBMFEE, []>;
+def SLBMFEV : XLForm_1_gen<31, 851, (outs gprc:$RT), (ins gprc:$RB),
+ "slbmfev $RT, $RB", IIC_SprSLBMFEV, []>;
+
def SLBIA : XForm_0<31, 498, (outs), (ins), "slbia", IIC_SprSLBIA, []>;
def TLBIA : XForm_0<31, 370, (outs), (ins),
@@ -3716,6 +3817,9 @@ def MFDCR : XFXForm_1<31, 323, (outs gprc:$RT), (ins i32imm:$SPR),
def MTDCR : XFXForm_1<31, 451, (outs), (ins gprc:$RT, i32imm:$SPR),
"mtdcr $SPR, $RT", IIC_SprMTSPR>, Requires<[IsPPC4xx]>;
+def HRFID : XLForm_1_np<19, 274, (outs), (ins), "hrfid", IIC_BrB, []>;
+def NAP : XLForm_1_np<19, 434, (outs), (ins), "nap", IIC_BrB, []>;
+
def ATTN : XForm_attn<0, 256, (outs), (ins), "attn", IIC_BrB>;
def LBZCIX : XForm_base_r3xo<31, 853, (outs gprc:$RST), (ins gprc:$A, gprc:$B),
@@ -3780,6 +3884,10 @@ def DCBTSTCT : PPCAsmPseudo<"dcbtstct $dst, $TH", (ins memrr:$dst, u5imm:$TH)>;
def DCBTSTDS : PPCAsmPseudo<"dcbtstds $dst, $TH", (ins memrr:$dst, u5imm:$TH)>;
def DCBTSTT : PPCAsmPseudo<"dcbtstt $dst", (ins memrr:$dst)>;
+def DCBFx : PPCAsmPseudo<"dcbf $dst", (ins memrr:$dst)>;
+def DCBFL : PPCAsmPseudo<"dcbfl $dst", (ins memrr:$dst)>;
+def DCBFLP : PPCAsmPseudo<"dcbflp $dst", (ins memrr:$dst)>;
+
def : InstAlias<"crset $bx", (CREQV crbitrc:$bx, crbitrc:$bx, crbitrc:$bx)>;
def : InstAlias<"crclr $bx", (CRXOR crbitrc:$bx, crbitrc:$bx, crbitrc:$bx)>;
def : InstAlias<"crmove $bx, $by", (CROR crbitrc:$bx, crbitrc:$by, crbitrc:$by)>;
@@ -4081,6 +4189,16 @@ let PPC970_Unit = 7 in {
def gBCA : BForm_3<16, 1, 0, (outs),
(ins u5imm:$bo, crbitrc:$bi, abscondbrtarget:$dst),
"bca $bo, $bi, $dst">;
+ let isAsmParserOnly = 1 in {
+ def gBCat : BForm_3_at<16, 0, 0, (outs),
+ (ins u5imm:$bo, atimm:$at, crbitrc:$bi,
+ condbrtarget:$dst),
+ "bc$at $bo, $bi, $dst">;
+ def gBCAat : BForm_3_at<16, 1, 0, (outs),
+ (ins u5imm:$bo, atimm:$at, crbitrc:$bi,
+ abscondbrtarget:$dst),
+ "bca$at $bo, $bi, $dst">;
+ } // isAsmParserOnly = 1
}
let Defs = [LR, CTR], Uses = [CTR, RM] in {
def gBCL : BForm_3<16, 0, 1, (outs),
@@ -4089,6 +4207,16 @@ let PPC970_Unit = 7 in {
def gBCLA : BForm_3<16, 1, 1, (outs),
(ins u5imm:$bo, crbitrc:$bi, abscondbrtarget:$dst),
"bcla $bo, $bi, $dst">;
+ let isAsmParserOnly = 1 in {
+ def gBCLat : BForm_3_at<16, 0, 1, (outs),
+ (ins u5imm:$bo, atimm:$at, crbitrc:$bi,
+ condbrtarget:$dst),
+ "bcl$at $bo, $bi, $dst">;
+ def gBCLAat : BForm_3_at<16, 1, 1, (outs),
+ (ins u5imm:$bo, atimm:$at, crbitrc:$bi,
+ abscondbrtarget:$dst),
+ "bcla$at $bo, $bi, $dst">;
+ } // // isAsmParserOnly = 1
}
let Defs = [CTR], Uses = [CTR, LR, RM] in
def gBCLR : XLForm_2<19, 16, 0, (outs),
@@ -4107,6 +4235,20 @@ let PPC970_Unit = 7 in {
(ins u5imm:$bo, crbitrc:$bi, i32imm:$bh),
"bcctrl $bo, $bi, $bh", IIC_BrB, []>;
}
+
+multiclass BranchSimpleMnemonicAT<string pm, int at> {
+ def : InstAlias<"bc"#pm#" $bo, $bi, $dst", (gBCat u5imm:$bo, at, crbitrc:$bi,
+ condbrtarget:$dst)>;
+ def : InstAlias<"bca"#pm#" $bo, $bi, $dst", (gBCAat u5imm:$bo, at, crbitrc:$bi,
+ condbrtarget:$dst)>;
+ def : InstAlias<"bcl"#pm#" $bo, $bi, $dst", (gBCLat u5imm:$bo, at, crbitrc:$bi,
+ condbrtarget:$dst)>;
+ def : InstAlias<"bcla"#pm#" $bo, $bi, $dst", (gBCLAat u5imm:$bo, at, crbitrc:$bi,
+ condbrtarget:$dst)>;
+}
+defm : BranchSimpleMnemonicAT<"+", 3>;
+defm : BranchSimpleMnemonicAT<"-", 2>;
+
def : InstAlias<"bclr $bo, $bi", (gBCLR u5imm:$bo, crbitrc:$bi, 0)>;
def : InstAlias<"bclrl $bo, $bi", (gBCLRL u5imm:$bo, crbitrc:$bi, 0)>;
def : InstAlias<"bcctr $bo, $bi", (gBCCTR u5imm:$bo, crbitrc:$bi, 0)>;
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrQPX.td b/contrib/llvm/lib/Target/PowerPC/PPCInstrQPX.td
index 4312007..4940c77 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrQPX.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrQPX.td
@@ -88,11 +88,11 @@ def pre_truncstv4f32 : PatFrag<(ops node:$val, node:$base, node:$offset),
return cast<StoreSDNode>(N)->getMemoryVT() == MVT::v4f32;
}]>;
-def fround_inexact : PatFrag<(ops node:$val), (fround node:$val), [{
+def fround_inexact : PatFrag<(ops node:$val), (fpround node:$val), [{
return cast<ConstantSDNode>(N->getOperand(1))->getZExtValue() == 0;
}]>;
-def fround_exact : PatFrag<(ops node:$val), (fround node:$val), [{
+def fround_exact : PatFrag<(ops node:$val), (fpround node:$val), [{
return cast<ConstantSDNode>(N->getOperand(1))->getZExtValue() == 1;
}]>;
@@ -311,11 +311,11 @@ let Uses = [RM] in {
def QVFRIN : XForm_19<4, 392, (outs qfrc:$FRT), (ins qfrc:$FRB),
"qvfrin $FRT, $FRB", IIC_FPGeneral,
- [(set v4f64:$FRT, (frnd v4f64:$FRB))]>;
+ [(set v4f64:$FRT, (fround v4f64:$FRB))]>;
let isCodeGenOnly = 1 in
def QVFRINs : XForm_19<4, 392, (outs qsrc:$FRT), (ins qsrc:$FRB),
"qvfrin $FRT, $FRB", IIC_FPGeneral,
- [(set v4f32:$FRT, (frnd v4f32:$FRB))]>;
+ [(set v4f32:$FRT, (fround v4f32:$FRB))]>;
def QVFRIP : XForm_19<4, 456, (outs qfrc:$FRT), (ins qfrc:$FRB),
"qvfrip $FRT, $FRB", IIC_FPGeneral,
@@ -1103,7 +1103,7 @@ def : Pat<(xor v4i1:$FRA, v4i1:$FRB),
def : Pat<(not v4i1:$FRA),
(QVFLOGICALb $FRA, $FRA, (i32 10))>;
-def : Pat<(v4f64 (fextend v4f32:$src)),
+def : Pat<(v4f64 (fpextend v4f32:$src)),
(COPY_TO_REGCLASS $src, QFRC)>;
def : Pat<(v4f32 (fround_exact v4f64:$src)),
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrVSX.td b/contrib/llvm/lib/Target/PowerPC/PPCInstrVSX.td
index a02ace0..0d9e345 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCInstrVSX.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrVSX.td
@@ -89,22 +89,42 @@ multiclass XX3Form_Rcr<bits<6> opcode, bits<7> xo, string asmbase,
}
}
+// Instruction form with a single input register for instructions such as
+// XXPERMDI. The reason for defining this is that specifying multiple chained
+// operands (such as loads) to an instruction will perform both chained
+// operations rather than coalescing them into a single register - even though
+// the source memory location is the same. This simply forces the instruction
+// to use the same register for both inputs.
+// For example, an output DAG such as this:
+// (XXPERMDI (LXSIBZX xoaddr:$src), (LXSIBZX xoaddr:$src ), 0))
+// would result in two load instructions emitted and used as separate inputs
+// to the XXPERMDI instruction.
+class XX3Form_2s<bits<6> opcode, bits<5> xo, dag OOL, dag IOL, string asmstr,
+ InstrItinClass itin, list<dag> pattern>
+ : XX3Form_2<opcode, xo, OOL, IOL, asmstr, itin, pattern> {
+ let XB = XA;
+}
+
def HasVSX : Predicate<"PPCSubTarget->hasVSX()">;
def IsLittleEndian : Predicate<"PPCSubTarget->isLittleEndian()">;
def IsBigEndian : Predicate<"!PPCSubTarget->isLittleEndian()">;
+def HasOnlySwappingMemOps : Predicate<"!PPCSubTarget->hasP9Vector()">;
let Predicates = [HasVSX] in {
let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
+let UseVSXReg = 1 in {
let hasSideEffects = 0 in { // VSX instructions don't have side effects.
let Uses = [RM] in {
// Load indexed instructions
let mayLoad = 1 in {
+ let CodeSize = 3 in
def LXSDX : XX1Form<31, 588,
(outs vsfrc:$XT), (ins memrr:$src),
"lxsdx $XT, $src", IIC_LdStLFD,
[(set f64:$XT, (load xoaddr:$src))]>;
+ let Predicates = [HasVSX, HasOnlySwappingMemOps] in
def LXVD2X : XX1Form<31, 844,
(outs vsrc:$XT), (ins memrr:$src),
"lxvd2x $XT, $src", IIC_LdStLFD,
@@ -114,6 +134,7 @@ let Uses = [RM] in {
(outs vsrc:$XT), (ins memrr:$src),
"lxvdsx $XT, $src", IIC_LdStLFD, []>;
+ let Predicates = [HasVSX, HasOnlySwappingMemOps] in
def LXVW4X : XX1Form<31, 780,
(outs vsrc:$XT), (ins memrr:$src),
"lxvw4x $XT, $src", IIC_LdStLFD,
@@ -122,21 +143,25 @@ let Uses = [RM] in {
// Store indexed instructions
let mayStore = 1 in {
+ let CodeSize = 3 in
def STXSDX : XX1Form<31, 716,
(outs), (ins vsfrc:$XT, memrr:$dst),
"stxsdx $XT, $dst", IIC_LdStSTFD,
[(store f64:$XT, xoaddr:$dst)]>;
+ let Predicates = [HasVSX, HasOnlySwappingMemOps] in {
+ // The behaviour of this instruction is endianness-specific so we provide no
+ // pattern to match it without considering endianness.
def STXVD2X : XX1Form<31, 972,
(outs), (ins vsrc:$XT, memrr:$dst),
"stxvd2x $XT, $dst", IIC_LdStSTFD,
- [(store v2f64:$XT, xoaddr:$dst)]>;
+ []>;
def STXVW4X : XX1Form<31, 908,
(outs), (ins vsrc:$XT, memrr:$dst),
"stxvw4x $XT, $dst", IIC_LdStSTFD,
[(store v4i32:$XT, xoaddr:$dst)]>;
-
+ }
} // mayStore
// Add/Mul Instructions
@@ -545,18 +570,38 @@ let Uses = [RM] in {
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xscvdpsxds $XT, $XB", IIC_VecFP,
[(set f64:$XT, (PPCfctidz f64:$XB))]>;
+ let isCodeGenOnly = 1 in
+ def XSCVDPSXDSs : XX2Form<60, 344,
+ (outs vssrc:$XT), (ins vssrc:$XB),
+ "xscvdpsxds $XT, $XB", IIC_VecFP,
+ [(set f32:$XT, (PPCfctidz f32:$XB))]>;
def XSCVDPSXWS : XX2Form<60, 88,
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xscvdpsxws $XT, $XB", IIC_VecFP,
[(set f64:$XT, (PPCfctiwz f64:$XB))]>;
+ let isCodeGenOnly = 1 in
+ def XSCVDPSXWSs : XX2Form<60, 88,
+ (outs vssrc:$XT), (ins vssrc:$XB),
+ "xscvdpsxws $XT, $XB", IIC_VecFP,
+ [(set f32:$XT, (PPCfctiwz f32:$XB))]>;
def XSCVDPUXDS : XX2Form<60, 328,
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xscvdpuxds $XT, $XB", IIC_VecFP,
[(set f64:$XT, (PPCfctiduz f64:$XB))]>;
+ let isCodeGenOnly = 1 in
+ def XSCVDPUXDSs : XX2Form<60, 328,
+ (outs vssrc:$XT), (ins vssrc:$XB),
+ "xscvdpuxds $XT, $XB", IIC_VecFP,
+ [(set f32:$XT, (PPCfctiduz f32:$XB))]>;
def XSCVDPUXWS : XX2Form<60, 72,
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xscvdpuxws $XT, $XB", IIC_VecFP,
[(set f64:$XT, (PPCfctiwuz f64:$XB))]>;
+ let isCodeGenOnly = 1 in
+ def XSCVDPUXWSs : XX2Form<60, 72,
+ (outs vssrc:$XT), (ins vssrc:$XB),
+ "xscvdpuxws $XT, $XB", IIC_VecFP,
+ [(set f32:$XT, (PPCfctiwuz f32:$XB))]>;
def XSCVSPDP : XX2Form<60, 329,
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xscvspdp $XT, $XB", IIC_VecFP, []>;
@@ -571,47 +616,55 @@ let Uses = [RM] in {
def XVCVDPSP : XX2Form<60, 393,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvdpsp $XT, $XB", IIC_VecFP, []>;
+ "xvcvdpsp $XT, $XB", IIC_VecFP,
+ [(set v4f32:$XT, (int_ppc_vsx_xvcvdpsp v2f64:$XB))]>;
def XVCVDPSXDS : XX2Form<60, 472,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvcvdpsxds $XT, $XB", IIC_VecFP,
[(set v2i64:$XT, (fp_to_sint v2f64:$XB))]>;
def XVCVDPSXWS : XX2Form<60, 216,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvdpsxws $XT, $XB", IIC_VecFP, []>;
+ "xvcvdpsxws $XT, $XB", IIC_VecFP,
+ [(set v4i32:$XT, (int_ppc_vsx_xvcvdpsxws v2f64:$XB))]>;
def XVCVDPUXDS : XX2Form<60, 456,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvcvdpuxds $XT, $XB", IIC_VecFP,
[(set v2i64:$XT, (fp_to_uint v2f64:$XB))]>;
def XVCVDPUXWS : XX2Form<60, 200,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvdpuxws $XT, $XB", IIC_VecFP, []>;
+ "xvcvdpuxws $XT, $XB", IIC_VecFP,
+ [(set v4i32:$XT, (int_ppc_vsx_xvcvdpuxws v2f64:$XB))]>;
def XVCVSPDP : XX2Form<60, 457,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvspdp $XT, $XB", IIC_VecFP, []>;
+ "xvcvspdp $XT, $XB", IIC_VecFP,
+ [(set v2f64:$XT, (int_ppc_vsx_xvcvspdp v4f32:$XB))]>;
def XVCVSPSXDS : XX2Form<60, 408,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvcvspsxds $XT, $XB", IIC_VecFP, []>;
def XVCVSPSXWS : XX2Form<60, 152,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvspsxws $XT, $XB", IIC_VecFP, []>;
+ "xvcvspsxws $XT, $XB", IIC_VecFP,
+ [(set v4i32:$XT, (fp_to_sint v4f32:$XB))]>;
def XVCVSPUXDS : XX2Form<60, 392,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvcvspuxds $XT, $XB", IIC_VecFP, []>;
def XVCVSPUXWS : XX2Form<60, 136,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvspuxws $XT, $XB", IIC_VecFP, []>;
+ "xvcvspuxws $XT, $XB", IIC_VecFP,
+ [(set v4i32:$XT, (fp_to_uint v4f32:$XB))]>;
def XVCVSXDDP : XX2Form<60, 504,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvcvsxddp $XT, $XB", IIC_VecFP,
[(set v2f64:$XT, (sint_to_fp v2i64:$XB))]>;
def XVCVSXDSP : XX2Form<60, 440,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvsxdsp $XT, $XB", IIC_VecFP, []>;
+ "xvcvsxdsp $XT, $XB", IIC_VecFP,
+ [(set v4f32:$XT, (int_ppc_vsx_xvcvsxdsp v2i64:$XB))]>;
def XVCVSXWDP : XX2Form<60, 248,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvsxwdp $XT, $XB", IIC_VecFP, []>;
+ "xvcvsxwdp $XT, $XB", IIC_VecFP,
+ [(set v2f64:$XT, (int_ppc_vsx_xvcvsxwdp v4i32:$XB))]>;
def XVCVSXWSP : XX2Form<60, 184,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvcvsxwsp $XT, $XB", IIC_VecFP,
@@ -622,19 +675,22 @@ let Uses = [RM] in {
[(set v2f64:$XT, (uint_to_fp v2i64:$XB))]>;
def XVCVUXDSP : XX2Form<60, 424,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvuxdsp $XT, $XB", IIC_VecFP, []>;
+ "xvcvuxdsp $XT, $XB", IIC_VecFP,
+ [(set v4f32:$XT, (int_ppc_vsx_xvcvuxdsp v2i64:$XB))]>;
def XVCVUXWDP : XX2Form<60, 232,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvuxwdp $XT, $XB", IIC_VecFP, []>;
+ "xvcvuxwdp $XT, $XB", IIC_VecFP,
+ [(set v2f64:$XT, (int_ppc_vsx_xvcvuxwdp v4i32:$XB))]>;
def XVCVUXWSP : XX2Form<60, 168,
(outs vsrc:$XT), (ins vsrc:$XB),
- "xvcvuxwsp $XT, $XB", IIC_VecFP, []>;
+ "xvcvuxwsp $XT, $XB", IIC_VecFP,
+ [(set v4f32:$XT, (uint_to_fp v4i32:$XB))]>;
// Rounding Instructions
def XSRDPI : XX2Form<60, 73,
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xsrdpi $XT, $XB", IIC_VecFP,
- [(set f64:$XT, (frnd f64:$XB))]>;
+ [(set f64:$XT, (fround f64:$XB))]>;
def XSRDPIC : XX2Form<60, 107,
(outs vsfrc:$XT), (ins vsfrc:$XB),
"xsrdpic $XT, $XB", IIC_VecFP,
@@ -655,7 +711,7 @@ let Uses = [RM] in {
def XVRDPI : XX2Form<60, 201,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvrdpi $XT, $XB", IIC_VecFP,
- [(set v2f64:$XT, (frnd v2f64:$XB))]>;
+ [(set v2f64:$XT, (fround v2f64:$XB))]>;
def XVRDPIC : XX2Form<60, 235,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvrdpic $XT, $XB", IIC_VecFP,
@@ -676,7 +732,7 @@ let Uses = [RM] in {
def XVRSPI : XX2Form<60, 137,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvrspi $XT, $XB", IIC_VecFP,
- [(set v4f32:$XT, (frnd v4f32:$XB))]>;
+ [(set v4f32:$XT, (fround v4f32:$XB))]>;
def XVRSPIC : XX2Form<60, 171,
(outs vsrc:$XT), (ins vsrc:$XB),
"xvrspic $XT, $XB", IIC_VecFP,
@@ -761,6 +817,21 @@ let Uses = [RM] in {
"xxlxor $XT, $XA, $XB", IIC_VecGeneral,
[(set v4i32:$XT, (xor v4i32:$XA, v4i32:$XB))]>;
} // isCommutable
+ let isCodeGenOnly = 1 in
+ def XXLXORz : XX3Form_Zero<60, 154, (outs vsrc:$XT), (ins),
+ "xxlxor $XT, $XT, $XT", IIC_VecGeneral,
+ [(set v4i32:$XT, (v4i32 immAllZerosV))]>;
+
+ let isCodeGenOnly = 1 in {
+ def XXLXORdpz : XX3Form_SetZero<60, 154,
+ (outs vsfrc:$XT), (ins),
+ "xxlxor $XT, $XT, $XT", IIC_VecGeneral,
+ [(set f64:$XT, (fpimm0))]>;
+ def XXLXORspz : XX3Form_SetZero<60, 154,
+ (outs vssrc:$XT), (ins),
+ "xxlxor $XT, $XT, $XT", IIC_VecGeneral,
+ [(set f32:$XT, (fpimm0))]>;
+ }
// Permutation Instructions
def XXMRGHW : XX3Form<60, 18,
@@ -773,6 +844,9 @@ let Uses = [RM] in {
def XXPERMDI : XX3Form_2<60, 10,
(outs vsrc:$XT), (ins vsrc:$XA, vsrc:$XB, u2imm:$DM),
"xxpermdi $XT, $XA, $XB, $DM", IIC_VecPerm, []>;
+ let isCodeGenOnly = 1 in
+ def XXPERMDIs : XX3Form_2s<60, 10, (outs vsrc:$XT), (ins vsfrc:$XA, u2imm:$DM),
+ "xxpermdi $XT, $XA, $XA, $DM", IIC_VecPerm, []>;
def XXSEL : XX4Form<60, 3,
(outs vsrc:$XT), (ins vsrc:$XA, vsrc:$XB, vsrc:$XC),
"xxsel $XT, $XA, $XB, $XC", IIC_VecPerm, []>;
@@ -787,7 +861,12 @@ let Uses = [RM] in {
"xxspltw $XT, $XB, $UIM", IIC_VecPerm,
[(set v4i32:$XT,
(PPCxxsplt v4i32:$XB, imm32SExt16:$UIM))]>;
+ let isCodeGenOnly = 1 in
+ def XXSPLTWs : XX2Form_2<60, 164,
+ (outs vsrc:$XT), (ins vfrc:$XB, u2imm:$UIM),
+ "xxspltw $XT, $XB, $UIM", IIC_VecPerm, []>;
} // hasSideEffects
+} // UseVSXReg = 1
// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after
// instruction selection into a branch sequence.
@@ -839,9 +918,17 @@ def : InstAlias<"xxmrgld $XT, $XA, $XB",
(XXPERMDI vsrc:$XT, vsrc:$XA, vsrc:$XB, 3)>;
def : InstAlias<"xxswapd $XT, $XB",
(XXPERMDI vsrc:$XT, vsrc:$XB, vsrc:$XB, 2)>;
+def : InstAlias<"xxspltd $XT, $XB, 0",
+ (XXPERMDIs vsrc:$XT, vsfrc:$XB, 0)>;
+def : InstAlias<"xxspltd $XT, $XB, 1",
+ (XXPERMDIs vsrc:$XT, vsfrc:$XB, 3)>;
+def : InstAlias<"xxswapd $XT, $XB",
+ (XXPERMDIs vsrc:$XT, vsfrc:$XB, 2)>;
let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
+def : Pat<(v4i32 (vnot_ppc v4i32:$A)),
+ (v4i32 (XXLNOR $A, $A))>;
let Predicates = [IsBigEndian] in {
def : Pat<(v2f64 (scalar_to_vector f64:$A)),
(v2f64 (SUBREG_TO_REG (i64 1), $A, sub_64))>;
@@ -948,18 +1035,27 @@ def : Pat<(v2f64 (PPCuvec2fp v4i32:$C, 1)),
(v2f64 (XVCVUXWDP (v2i64 (XXMRGLW $C, $C))))>;
// Loads.
-def : Pat<(v2f64 (load xoaddr:$src)), (LXVD2X xoaddr:$src)>;
-def : Pat<(v2i64 (load xoaddr:$src)), (LXVD2X xoaddr:$src)>;
-def : Pat<(v4i32 (load xoaddr:$src)), (LXVW4X xoaddr:$src)>;
-def : Pat<(v2f64 (PPClxvd2x xoaddr:$src)), (LXVD2X xoaddr:$src)>;
-
-// Stores.
-def : Pat<(int_ppc_vsx_stxvd2x v2f64:$rS, xoaddr:$dst),
- (STXVD2X $rS, xoaddr:$dst)>;
-def : Pat<(store v2i64:$rS, xoaddr:$dst), (STXVD2X $rS, xoaddr:$dst)>;
-def : Pat<(int_ppc_vsx_stxvw4x v4i32:$rS, xoaddr:$dst),
- (STXVW4X $rS, xoaddr:$dst)>;
-def : Pat<(PPCstxvd2x v2f64:$rS, xoaddr:$dst), (STXVD2X $rS, xoaddr:$dst)>;
+let Predicates = [HasVSX, HasOnlySwappingMemOps] in {
+ def : Pat<(v2f64 (PPClxvd2x xoaddr:$src)), (LXVD2X xoaddr:$src)>;
+
+ // Stores.
+ def : Pat<(int_ppc_vsx_stxvd2x v2f64:$rS, xoaddr:$dst),
+ (STXVD2X $rS, xoaddr:$dst)>;
+ def : Pat<(int_ppc_vsx_stxvw4x v4i32:$rS, xoaddr:$dst),
+ (STXVW4X $rS, xoaddr:$dst)>;
+ def : Pat<(int_ppc_vsx_stxvd2x_be v2f64:$rS, xoaddr:$dst),
+ (STXVD2X $rS, xoaddr:$dst)>;
+ def : Pat<(int_ppc_vsx_stxvw4x_be v4i32:$rS, xoaddr:$dst),
+ (STXVW4X $rS, xoaddr:$dst)>;
+ def : Pat<(PPCstxvd2x v2f64:$rS, xoaddr:$dst), (STXVD2X $rS, xoaddr:$dst)>;
+}
+let Predicates = [IsBigEndian, HasVSX, HasOnlySwappingMemOps] in {
+ def : Pat<(v2f64 (load xoaddr:$src)), (LXVD2X xoaddr:$src)>;
+ def : Pat<(v2i64 (load xoaddr:$src)), (LXVD2X xoaddr:$src)>;
+ def : Pat<(v4i32 (load xoaddr:$src)), (LXVW4X xoaddr:$src)>;
+ def : Pat<(store v2f64:$rS, xoaddr:$dst), (STXVD2X $rS, xoaddr:$dst)>;
+ def : Pat<(store v2i64:$rS, xoaddr:$dst), (STXVD2X $rS, xoaddr:$dst)>;
+}
// Permutes.
def : Pat<(v2f64 (PPCxxswapd v2f64:$src)), (XXPERMDI $src, $src, 2)>;
@@ -1054,6 +1150,22 @@ def : Pat<(f64 (PPCfcfidu (PPCmtvsra (i64 (vector_extract v2i64:$S, 1))))),
} // AddedComplexity
} // HasVSX
+def ScalarLoads {
+ dag Li8 = (i32 (extloadi8 xoaddr:$src));
+ dag ZELi8 = (i32 (zextloadi8 xoaddr:$src));
+ dag ZELi8i64 = (i64 (zextloadi8 xoaddr:$src));
+ dag SELi8 = (i32 (sext_inreg (extloadi8 xoaddr:$src), i8));
+ dag SELi8i64 = (i64 (sext_inreg (extloadi8 xoaddr:$src), i8));
+
+ dag Li16 = (i32 (extloadi16 xoaddr:$src));
+ dag ZELi16 = (i32 (zextloadi16 xoaddr:$src));
+ dag ZELi16i64 = (i64 (zextloadi16 xoaddr:$src));
+ dag SELi16 = (i32 (sextloadi16 xoaddr:$src));
+ dag SELi16i64 = (i64 (sextloadi16 xoaddr:$src));
+
+ dag Li32 = (i32 (load xoaddr:$src));
+}
+
// The following VSX instructions were introduced in Power ISA 2.07
/* FIXME: if the operands are v2i64, these patterns will not match.
we should define new patterns or otherwise match the same patterns
@@ -1063,7 +1175,7 @@ def HasP8Vector : Predicate<"PPCSubTarget->hasP8Vector()">;
def HasDirectMove : Predicate<"PPCSubTarget->hasDirectMove()">;
let Predicates = [HasP8Vector] in {
let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
- let isCommutable = 1 in {
+ let isCommutable = 1, UseVSXReg = 1 in {
def XXLEQV : XX3Form<60, 186,
(outs vsrc:$XT), (ins vsrc:$XA, vsrc:$XB),
"xxleqv $XT, $XA, $XB", IIC_VecGeneral,
@@ -1073,11 +1185,12 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
"xxlnand $XT, $XA, $XB", IIC_VecGeneral,
[(set v4i32:$XT, (vnot_ppc (and v4i32:$XA,
v4i32:$XB)))]>;
- } // isCommutable
+ } // isCommutable, UseVSXReg
def : Pat<(int_ppc_vsx_xxleqv v4i32:$A, v4i32:$B),
(XXLEQV $A, $B)>;
+ let UseVSXReg = 1 in {
def XXLORC : XX3Form<60, 170,
(outs vsrc:$XT), (ins vsrc:$XA, vsrc:$XB),
"xxlorc $XT, $XA, $XB", IIC_VecGeneral,
@@ -1085,6 +1198,7 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
// VSX scalar loads introduced in ISA 2.07
let mayLoad = 1 in {
+ let CodeSize = 3 in
def LXSSPX : XX1Form<31, 524, (outs vssrc:$XT), (ins memrr:$src),
"lxsspx $XT, $src", IIC_LdStLFD,
[(set f32:$XT, (load xoaddr:$src))]>;
@@ -1098,6 +1212,7 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
// VSX scalar stores introduced in ISA 2.07
let mayStore = 1 in {
+ let CodeSize = 3 in
def STXSSPX : XX1Form<31, 652, (outs), (ins vssrc:$XT, memrr:$dst),
"stxsspx $XT, $dst", IIC_LdStSTFD,
[(store f32:$XT, xoaddr:$dst)]>;
@@ -1105,10 +1220,13 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
"stxsiwx $XT, $dst", IIC_LdStSTFD,
[(PPCstfiwx f64:$XT, xoaddr:$dst)]>;
} // mayStore
+ } // UseVSXReg = 1
def : Pat<(f64 (extloadf32 xoaddr:$src)),
(COPY_TO_REGCLASS (LXSSPX xoaddr:$src), VSFRC)>;
- def : Pat<(f64 (fextend f32:$src)),
+ def : Pat<(f32 (fpround (extloadf32 xoaddr:$src))),
+ (f32 (LXSSPX xoaddr:$src))>;
+ def : Pat<(f64 (fpextend f32:$src)),
(COPY_TO_REGCLASS $src, VSFRC)>;
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETLT)),
@@ -1132,6 +1250,7 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETNE)),
(SELECT_VSSRC (CRXOR $lhs, $rhs), $tval, $fval)>;
+ let UseVSXReg = 1 in {
// VSX Elementary Scalar FP arithmetic (SP)
let isCommutable = 1 in {
def XSADDSP : XX3Form<60, 0,
@@ -1256,6 +1375,7 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
"xscvdpspn $XT, $XB", IIC_VecFP, []>;
def XSCVSPDPN : XX2Form<60, 331, (outs vssrc:$XT), (ins vsrc:$XB),
"xscvspdpn $XT, $XB", IIC_VecFP, []>;
+ } // UseVSXReg = 1
let Predicates = [IsLittleEndian] in {
def : Pat<(f32 (PPCfcfids (PPCmtvsra (i64 (vector_extract v2i64:$S, 0))))),
@@ -1278,9 +1398,12 @@ let AddedComplexity = 400 in { // Prefer VSX patterns over non-VSX patterns.
def : Pat<(f32 (PPCfcfidus (PPCmtvsra (i64 (vector_extract v2i64:$S, 1))))),
(f32 (XSCVUXDSP (COPY_TO_REGCLASS (XXPERMDI $S, $S, 2), VSFRC)))>;
}
+ def : Pat<(v4i32 (scalar_to_vector ScalarLoads.Li32)),
+ (v4i32 (XXSPLTWs (LXSIWAX xoaddr:$src), 1))>;
} // AddedComplexity = 400
} // HasP8Vector
+let UseVSXReg = 1, AddedComplexity = 400 in {
let Predicates = [HasDirectMove] in {
// VSX direct move instructions
def MFVSRD : XX1_RS6_RD5_XO<31, 51, (outs g8rc:$rA), (ins vsfrc:$XT),
@@ -1304,8 +1427,7 @@ let Predicates = [HasDirectMove] in {
let Predicates = [IsISA3_0, HasDirectMove] in {
def MTVSRWS: XX1_RS6_RD5_XO<31, 403, (outs vsrc:$XT), (ins gprc:$rA),
- "mtvsrws $XT, $rA", IIC_VecGeneral,
- []>;
+ "mtvsrws $XT, $rA", IIC_VecGeneral, []>;
def MTVSRDD: XX1Form<31, 435, (outs vsrc:$XT), (ins g8rc:$rA, g8rc:$rB),
"mtvsrdd $XT, $rA, $rB", IIC_VecGeneral,
@@ -1316,6 +1438,7 @@ let Predicates = [IsISA3_0, HasDirectMove] in {
[]>, Requires<[In64BitMode]>;
} // IsISA3_0, HasDirectMove
+} // UseVSXReg = 1
/* Direct moves of various widths from GPR's into VSR's. Each move lines
the value up into element 0 (both BE and LE). Namely, entities smaller than
@@ -1626,6 +1749,7 @@ def VectorExtractions {
dag BE_VARIABLE_DOUBLE = (COPY_TO_REGCLASS BE_VDOUBLE_PERMUTE, VSRC);
}
+let AddedComplexity = 400 in {
// v4f32 scalar <-> vector conversions (BE)
let Predicates = [IsBigEndian, HasP8Vector] in {
def : Pat<(v4f32 (scalar_to_vector f32:$A)),
@@ -1754,6 +1878,9 @@ let Predicates = [IsLittleEndian, HasVSX] in
def : Pat<(f64 (vector_extract v2f64:$S, i64:$Idx)),
(f64 VectorExtractions.LE_VARIABLE_DOUBLE)>;
+ def : Pat<(v4i32 (int_ppc_vsx_lxvw4x_be xoaddr:$src)), (LXVW4X xoaddr:$src)>;
+ def : Pat<(v2f64 (int_ppc_vsx_lxvd2x_be xoaddr:$src)), (LXVD2X xoaddr:$src)>;
+
let Predicates = [IsLittleEndian, HasDirectMove] in {
// v16i8 scalar <-> vector conversions (LE)
def : Pat<(v16i8 (scalar_to_vector i32:$A)),
@@ -1864,6 +1991,11 @@ def : Pat<(f64 (bitconvert i64:$S)),
(f64 (MTVSRD $S))>;
}
+// Materialize a zero-vector of long long
+def : Pat<(v2i64 immAllZerosV),
+ (v2i64 (XXLXORz))>;
+}
+
def AlignValues {
dag F32_TO_BE_WORD1 = (v4f32 (XXSLDWI (XSCVDPSPN $B), (XSCVDPSPN $B), 3));
dag I32_TO_BE_WORD1 = (COPY_TO_REGCLASS (MTVSRWZ $B), VSRC);
@@ -1891,6 +2023,7 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
: X_RD5_XO5_RS5<opcode, xo2, xo, (outs vrrc:$vT), (ins vbtype:$vB),
!strconcat(opc, " $vT, $vB"), IIC_VecFP, pattern>;
+ let UseVSXReg = 1 in {
// [PO T XO B XO BX /]
class XX2_RT5_XO5_XB6<bits<6> opcode, bits<5> xo2, bits<9> xo, string opc,
list<dag> pattern>
@@ -1909,6 +2042,7 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
InstrItinClass itin, list<dag> pattern>
: XX3Form<opcode, xo, (outs xty:$XT), (ins aty:$XA, bty:$XB),
!strconcat(opc, " $XT, $XA, $XB"), itin, pattern>;
+ } // UseVSXReg = 1
// [PO VRT VRA VRB XO /]
class X_VT5_VA5_VB5<bits<6> opcode, bits<10> xo, string opc,
@@ -1977,7 +2111,8 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
// DP/QP Compare Exponents
def XSCMPEXPDP : XX3Form_1<60, 59,
(outs crrc:$crD), (ins vsfrc:$XA, vsfrc:$XB),
- "xscmpexpdp $crD, $XA, $XB", IIC_FPCompare, []>;
+ "xscmpexpdp $crD, $XA, $XB", IIC_FPCompare, []>,
+ UseVSXReg;
def XSCMPEXPQP : X_BF3_VA5_VB5<63, 164, "xscmpexpqp", []>;
// DP Compare ==, >=, >, !=
@@ -1991,6 +2126,7 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
IIC_FPCompare, []>;
def XSCMPNEDP : XX3_XT5_XA5_XB5<60, 27, "xscmpnedp", vsrc, vsfrc, vsfrc,
IIC_FPCompare, []>;
+ let UseVSXReg = 1 in {
// Vector Compare Not Equal
def XVCMPNEDP : XX3Form_Rc<60, 123,
(outs vsrc:$XT), (ins vsrc:$XA, vsrc:$XB),
@@ -2008,12 +2144,13 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
(outs vsrc:$XT), (ins vsrc:$XA, vsrc:$XB),
"xvcmpnesp. $XT, $XA, $XB", IIC_VecFPCompare, []>,
isDOT;
+ } // UseVSXReg = 1
//===--------------------------------------------------------------------===//
// Quad-Precision Floating-Point Conversion Instructions:
// Convert DP -> QP
- def XSCVDPQP : X_VT5_XO5_VB5_TyVB<63, 22, 836, "xscvdpqp", vsfrc, []>;
+ def XSCVDPQP : X_VT5_XO5_VB5_TyVB<63, 22, 836, "xscvdpqp", vfrc, []>;
// Round & Convert QP -> DP (dword[1] is set to zero)
def XSCVQPDP : X_VT5_XO5_VB5 <63, 20, 836, "xscvqpdp" , []>;
@@ -2026,9 +2163,10 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
def XSCVQPUWZ : X_VT5_XO5_VB5<63, 1, 836, "xscvqpuwz", []>;
// Convert (Un)Signed DWord -> QP
- def XSCVSDQP : X_VT5_XO5_VB5_TyVB<63, 10, 836, "xscvsdqp", vsfrc, []>;
- def XSCVUDQP : X_VT5_XO5_VB5_TyVB<63, 2, 836, "xscvudqp", vsfrc, []>;
+ def XSCVSDQP : X_VT5_XO5_VB5_TyVB<63, 10, 836, "xscvsdqp", vfrc, []>;
+ def XSCVUDQP : X_VT5_XO5_VB5_TyVB<63, 2, 836, "xscvudqp", vfrc, []>;
+ let UseVSXReg = 1 in {
//===--------------------------------------------------------------------===//
// Round to Floating-Point Integer Instructions
@@ -2041,7 +2179,17 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
// Vector HP -> SP
def XVCVHPSP : XX2_XT6_XO5_XB6<60, 24, 475, "xvcvhpsp", vsrc, []>;
- def XVCVSPHP : XX2_XT6_XO5_XB6<60, 25, 475, "xvcvsphp", vsrc, []>;
+ def XVCVSPHP : XX2_XT6_XO5_XB6<60, 25, 475, "xvcvsphp", vsrc,
+ [(set v4f32:$XT,
+ (int_ppc_vsx_xvcvsphp v4f32:$XB))]>;
+
+ } // UseVSXReg = 1
+
+ // Pattern for matching Vector HP -> Vector SP intrinsic. Defined as a
+ // seperate pattern so that it can convert the input register class from
+ // VRRC(v8i16) to VSRC.
+ def : Pat<(v4f32 (int_ppc_vsx_xvcvhpsp v8i16:$A)),
+ (v4f32 (XVCVHPSP (COPY_TO_REGCLASS $A, VSRC)))>;
class Z23_VT5_R1_VB5_RMC2_EX1<bits<6> opcode, bits<8> xo, bit ex, string opc,
list<dag> pattern>
@@ -2064,7 +2212,7 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
// Insert Exponent DP/QP
// XT NOTE: XT.dword[1] = 0xUUUU_UUUU_UUUU_UUUU
def XSIEXPDP : XX1Form <60, 918, (outs vsrc:$XT), (ins g8rc:$rA, g8rc:$rB),
- "xsiexpdp $XT, $rA, $rB", IIC_VecFP, []>;
+ "xsiexpdp $XT, $rA, $rB", IIC_VecFP, []>, UseVSXReg;
// vB NOTE: only vB.dword[0] is used, that's why we don't use
// X_VT5_VA5_VB5 form
def XSIEXPQP : XForm_18<63, 868, (outs vrrc:$vT), (ins vrrc:$vA, vsfrc:$vB),
@@ -2073,10 +2221,12 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
// Extract Exponent/Significand DP/QP
def XSXEXPDP : XX2_RT5_XO5_XB6<60, 0, 347, "xsxexpdp", []>;
def XSXSIGDP : XX2_RT5_XO5_XB6<60, 1, 347, "xsxsigdp", []>;
+
def XSXEXPQP : X_VT5_XO5_VB5 <63, 2, 804, "xsxexpqp", []>;
def XSXSIGQP : X_VT5_XO5_VB5 <63, 18, 804, "xsxsigqp", []>;
// Vector Insert Word
+ let UseVSXReg = 1 in {
// XB NOTE: Only XB.dword[1] is used, but we use vsrc on XB.
def XXINSERTW :
XX2_RD6_UIM5_RS6<60, 181, (outs vsrc:$XT),
@@ -2090,39 +2240,64 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
def XXEXTRACTUW : XX2_RD6_UIM5_RS6<60, 165,
(outs vsfrc:$XT), (ins vsrc:$XB, u4imm:$UIMM),
"xxextractuw $XT, $XB, $UIMM", IIC_VecFP, []>;
+ } // UseVSXReg = 1
// Vector Insert Exponent DP/SP
def XVIEXPDP : XX3_XT5_XA5_XB5<60, 248, "xviexpdp", vsrc, vsrc, vsrc,
- IIC_VecFP, []>;
+ IIC_VecFP, [(set v2f64: $XT,(int_ppc_vsx_xviexpdp v2i64:$XA, v2i64:$XB))]>;
def XVIEXPSP : XX3_XT5_XA5_XB5<60, 216, "xviexpsp", vsrc, vsrc, vsrc,
- IIC_VecFP, []>;
+ IIC_VecFP, [(set v4f32: $XT,(int_ppc_vsx_xviexpsp v4i32:$XA, v4i32:$XB))]>;
// Vector Extract Exponent/Significand DP/SP
- def XVXEXPDP : XX2_XT6_XO5_XB6<60, 0, 475, "xvxexpdp", vsrc, []>;
- def XVXEXPSP : XX2_XT6_XO5_XB6<60, 8, 475, "xvxexpsp", vsrc, []>;
- def XVXSIGDP : XX2_XT6_XO5_XB6<60, 1, 475, "xvxsigdp", vsrc, []>;
- def XVXSIGSP : XX2_XT6_XO5_XB6<60, 9, 475, "xvxsigsp", vsrc, []>;
+ def XVXEXPDP : XX2_XT6_XO5_XB6<60, 0, 475, "xvxexpdp", vsrc,
+ [(set v2i64: $XT,
+ (int_ppc_vsx_xvxexpdp v2f64:$XB))]>;
+ def XVXEXPSP : XX2_XT6_XO5_XB6<60, 8, 475, "xvxexpsp", vsrc,
+ [(set v4i32: $XT,
+ (int_ppc_vsx_xvxexpsp v4f32:$XB))]>;
+ def XVXSIGDP : XX2_XT6_XO5_XB6<60, 1, 475, "xvxsigdp", vsrc,
+ [(set v2i64: $XT,
+ (int_ppc_vsx_xvxsigdp v2f64:$XB))]>;
+ def XVXSIGSP : XX2_XT6_XO5_XB6<60, 9, 475, "xvxsigsp", vsrc,
+ [(set v4i32: $XT,
+ (int_ppc_vsx_xvxsigsp v4f32:$XB))]>;
+
+ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
+ // Extra patterns expanding to vector Extract Word/Insert Word
+ def : Pat<(v4i32 (int_ppc_vsx_xxinsertw v4i32:$A, v2i64:$B, imm:$IMM)),
+ (v4i32 (XXINSERTW $A, $B, imm:$IMM))>;
+ def : Pat<(v2i64 (int_ppc_vsx_xxextractuw v2i64:$A, imm:$IMM)),
+ (v2i64 (COPY_TO_REGCLASS (XXEXTRACTUW $A, imm:$IMM), VSRC))>;
+ } // AddedComplexity = 400, HasP9Vector
//===--------------------------------------------------------------------===//
// Test Data Class SP/DP/QP
+ let UseVSXReg = 1 in {
def XSTSTDCSP : XX2_BF3_DCMX7_RS6<60, 298,
(outs crrc:$BF), (ins u7imm:$DCMX, vsfrc:$XB),
"xststdcsp $BF, $XB, $DCMX", IIC_VecFP, []>;
def XSTSTDCDP : XX2_BF3_DCMX7_RS6<60, 362,
(outs crrc:$BF), (ins u7imm:$DCMX, vsfrc:$XB),
"xststdcdp $BF, $XB, $DCMX", IIC_VecFP, []>;
+ } // UseVSXReg = 1
def XSTSTDCQP : X_BF3_DCMX7_RS5 <63, 708,
(outs crrc:$BF), (ins u7imm:$DCMX, vrrc:$vB),
"xststdcqp $BF, $vB, $DCMX", IIC_VecFP, []>;
// Vector Test Data Class SP/DP
+ let UseVSXReg = 1 in {
def XVTSTDCSP : XX2_RD6_DCMX7_RS6<60, 13, 5,
(outs vsrc:$XT), (ins u7imm:$DCMX, vsrc:$XB),
- "xvtstdcsp $XT, $XB, $DCMX", IIC_VecFP, []>;
+ "xvtstdcsp $XT, $XB, $DCMX", IIC_VecFP,
+ [(set v4i32: $XT,
+ (int_ppc_vsx_xvtstdcsp v4f32:$XB, imm:$DCMX))]>;
def XVTSTDCDP : XX2_RD6_DCMX7_RS6<60, 15, 5,
(outs vsrc:$XT), (ins u7imm:$DCMX, vsrc:$XB),
- "xvtstdcdp $XT, $XB, $DCMX", IIC_VecFP, []>;
+ "xvtstdcdp $XT, $XB, $DCMX", IIC_VecFP,
+ [(set v2i64: $XT,
+ (int_ppc_vsx_xvtstdcdp v2f64:$XB, imm:$DCMX))]>;
+ } // UseVSXReg = 1
//===--------------------------------------------------------------------===//
@@ -2153,20 +2328,22 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
// Vector Splat Immediate Byte
def XXSPLTIB : X_RD6_IMM8<60, 360, (outs vsrc:$XT), (ins u8imm:$IMM8),
- "xxspltib $XT, $IMM8", IIC_VecPerm, []>;
+ "xxspltib $XT, $IMM8", IIC_VecPerm, []>, UseVSXReg;
//===--------------------------------------------------------------------===//
// Vector/Scalar Load/Store Instructions
+ // When adding new D-Form loads/stores, be sure to update the ImmToIdxMap in
+ // PPCRegisterInfo::PPCRegisterInfo and maybe save yourself some debugging.
let mayLoad = 1 in {
// Load Vector
def LXV : DQ_RD6_RS5_DQ12<61, 1, (outs vsrc:$XT), (ins memrix16:$src),
- "lxv $XT, $src", IIC_LdStLFD, []>;
+ "lxv $XT, $src", IIC_LdStLFD, []>, UseVSXReg;
// Load DWord
- def LXSD : DSForm_1<57, 2, (outs vrrc:$vD), (ins memrix:$src),
+ def LXSD : DSForm_1<57, 2, (outs vfrc:$vD), (ins memrix:$src),
"lxsd $vD, $src", IIC_LdStLFD, []>;
// Load SP from src, convert it to DP, and place in dword[0]
- def LXSSP : DSForm_1<57, 3, (outs vrrc:$vD), (ins memrix:$src),
+ def LXSSP : DSForm_1<57, 3, (outs vfrc:$vD), (ins memrix:$src),
"lxssp $vD, $src", IIC_LdStLFD, []>;
// [PO T RA RB XO TX] almost equal to [PO S RA RB XO SX], but has different
@@ -2174,59 +2351,83 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
class X_XT6_RA5_RB5<bits<6> opcode, bits<10> xo, string opc,
RegisterOperand vtype, list<dag> pattern>
: XX1Form<opcode, xo, (outs vtype:$XT), (ins memrr:$src),
- !strconcat(opc, " $XT, $src"), IIC_LdStLFD, pattern>;
+ !strconcat(opc, " $XT, $src"), IIC_LdStLFD, pattern>, UseVSXReg;
// Load as Integer Byte/Halfword & Zero Indexed
- def LXSIBZX : X_XT6_RA5_RB5<31, 781, "lxsibzx", vsfrc, []>;
- def LXSIHZX : X_XT6_RA5_RB5<31, 813, "lxsihzx", vsfrc, []>;
+ def LXSIBZX : X_XT6_RA5_RB5<31, 781, "lxsibzx", vsfrc,
+ [(set f64:$XT, (PPClxsizx xoaddr:$src, 1))]>;
+ def LXSIHZX : X_XT6_RA5_RB5<31, 813, "lxsihzx", vsfrc,
+ [(set f64:$XT, (PPClxsizx xoaddr:$src, 2))]>;
// Load Vector Halfword*8/Byte*16 Indexed
def LXVH8X : X_XT6_RA5_RB5<31, 812, "lxvh8x" , vsrc, []>;
def LXVB16X : X_XT6_RA5_RB5<31, 876, "lxvb16x", vsrc, []>;
// Load Vector Indexed
- def LXVX : X_XT6_RA5_RB5<31, 268, "lxvx" , vsrc, []>;
+ def LXVX : X_XT6_RA5_RB5<31, 268, "lxvx" , vsrc,
+ [(set v2f64:$XT, (load xoaddr:$src))]>;
// Load Vector (Left-justified) with Length
- def LXVL : X_XT6_RA5_RB5<31, 269, "lxvl" , vsrc, []>;
- def LXVLL : X_XT6_RA5_RB5<31, 301, "lxvll" , vsrc, []>;
+ def LXVL : XX1Form<31, 269, (outs vsrc:$XT), (ins memr:$src, g8rc:$rB),
+ "lxvl $XT, $src, $rB", IIC_LdStLoad,
+ [(set v4i32:$XT, (int_ppc_vsx_lxvl addr:$src, i64:$rB))]>,
+ UseVSXReg;
+ def LXVLL : XX1Form<31,301, (outs vsrc:$XT), (ins memr:$src, g8rc:$rB),
+ "lxvll $XT, $src, $rB", IIC_LdStLoad,
+ [(set v4i32:$XT, (int_ppc_vsx_lxvll addr:$src, i64:$rB))]>,
+ UseVSXReg;
// Load Vector Word & Splat Indexed
def LXVWSX : X_XT6_RA5_RB5<31, 364, "lxvwsx" , vsrc, []>;
- } // end mayLoad
+ } // mayLoad
+ // When adding new D-Form loads/stores, be sure to update the ImmToIdxMap in
+ // PPCRegisterInfo::PPCRegisterInfo and maybe save yourself some debugging.
let mayStore = 1 in {
// Store Vector
def STXV : DQ_RD6_RS5_DQ12<61, 5, (outs), (ins vsrc:$XT, memrix16:$dst),
- "stxv $XT, $dst", IIC_LdStSTFD, []>;
+ "stxv $XT, $dst", IIC_LdStSTFD, []>, UseVSXReg;
// Store DWord
- def STXSD : DSForm_1<61, 2, (outs), (ins vrrc:$vS, memrix:$dst),
+ def STXSD : DSForm_1<61, 2, (outs), (ins vfrc:$vS, memrix:$dst),
"stxsd $vS, $dst", IIC_LdStSTFD, []>;
// Convert DP of dword[0] to SP, and Store to dst
- def STXSSP : DSForm_1<61, 3, (outs), (ins vrrc:$vS, memrix:$dst),
+ def STXSSP : DSForm_1<61, 3, (outs), (ins vfrc:$vS, memrix:$dst),
"stxssp $vS, $dst", IIC_LdStSTFD, []>;
// [PO S RA RB XO SX]
class X_XS6_RA5_RB5<bits<6> opcode, bits<10> xo, string opc,
RegisterOperand vtype, list<dag> pattern>
: XX1Form<opcode, xo, (outs), (ins vtype:$XT, memrr:$dst),
- !strconcat(opc, " $XT, $dst"), IIC_LdStSTFD, pattern>;
+ !strconcat(opc, " $XT, $dst"), IIC_LdStSTFD, pattern>, UseVSXReg;
// Store as Integer Byte/Halfword Indexed
- def STXSIBX : X_XS6_RA5_RB5<31, 909, "stxsibx" , vsfrc, []>;
- def STXSIHX : X_XS6_RA5_RB5<31, 941, "stxsihx" , vsfrc, []>;
+ def STXSIBX : X_XS6_RA5_RB5<31, 909, "stxsibx" , vsfrc,
+ [(PPCstxsix f64:$XT, xoaddr:$dst, 1)]>;
+ def STXSIHX : X_XS6_RA5_RB5<31, 941, "stxsihx" , vsfrc,
+ [(PPCstxsix f64:$XT, xoaddr:$dst, 2)]>;
+ let isCodeGenOnly = 1 in {
+ def STXSIBXv : X_XS6_RA5_RB5<31, 909, "stxsibx" , vrrc, []>;
+ def STXSIHXv : X_XS6_RA5_RB5<31, 941, "stxsihx" , vrrc, []>;
+ }
// Store Vector Halfword*8/Byte*16 Indexed
def STXVH8X : X_XS6_RA5_RB5<31, 940, "stxvh8x" , vsrc, []>;
def STXVB16X : X_XS6_RA5_RB5<31, 1004, "stxvb16x", vsrc, []>;
// Store Vector Indexed
- def STXVX : X_XS6_RA5_RB5<31, 396, "stxvx" , vsrc, []>;
+ def STXVX : X_XS6_RA5_RB5<31, 396, "stxvx" , vsrc,
+ [(store v2f64:$XT, xoaddr:$dst)]>;
// Store Vector (Left-justified) with Length
- def STXVL : X_XS6_RA5_RB5<31, 397, "stxvl" , vsrc, []>;
- def STXVLL : X_XS6_RA5_RB5<31, 429, "stxvll" , vsrc, []>;
- } // end mayStore
+ def STXVL : XX1Form<31, 397, (outs), (ins vsrc:$XT, memr:$dst, g8rc:$rB),
+ "stxvl $XT, $dst, $rB", IIC_LdStLoad,
+ [(int_ppc_vsx_stxvl v4i32:$XT, addr:$dst, i64:$rB)]>,
+ UseVSXReg;
+ def STXVLL : XX1Form<31, 429, (outs), (ins vsrc:$XT, memr:$dst, g8rc:$rB),
+ "stxvll $XT, $dst, $rB", IIC_LdStLoad,
+ [(int_ppc_vsx_stxvll v4i32:$XT, addr:$dst, i64:$rB)]>,
+ UseVSXReg;
+ } // mayStore
// Patterns for which instructions from ISA 3.0 are a better match
let Predicates = [IsLittleEndian, HasP9Vector] in {
@@ -2282,4 +2483,442 @@ let AddedComplexity = 400, Predicates = [HasP9Vector] in {
def : Pat<(v4f32 (insertelt v4f32:$A, f32:$B, 3)),
(v4f32 (XXINSERTW v4f32:$A, AlignValues.F32_TO_BE_WORD1, 12))>;
} // IsLittleEndian, HasP9Vector
+
+ def : Pat<(v2f64 (load xoaddr:$src)), (LXVX xoaddr:$src)>;
+ def : Pat<(v2i64 (load xoaddr:$src)), (LXVX xoaddr:$src)>;
+ def : Pat<(v4f32 (load xoaddr:$src)), (LXVX xoaddr:$src)>;
+ def : Pat<(v4i32 (load xoaddr:$src)), (LXVX xoaddr:$src)>;
+ def : Pat<(v4i32 (int_ppc_vsx_lxvw4x xoaddr:$src)), (LXVX xoaddr:$src)>;
+ def : Pat<(v2f64 (int_ppc_vsx_lxvd2x xoaddr:$src)), (LXVX xoaddr:$src)>;
+ def : Pat<(store v2f64:$rS, xoaddr:$dst), (STXVX $rS, xoaddr:$dst)>;
+ def : Pat<(store v2i64:$rS, xoaddr:$dst), (STXVX $rS, xoaddr:$dst)>;
+ def : Pat<(store v4f32:$rS, xoaddr:$dst), (STXVX $rS, xoaddr:$dst)>;
+ def : Pat<(store v4i32:$rS, xoaddr:$dst), (STXVX $rS, xoaddr:$dst)>;
+ def : Pat<(int_ppc_vsx_stxvw4x v4i32:$rS, xoaddr:$dst),
+ (STXVX $rS, xoaddr:$dst)>;
+ def : Pat<(int_ppc_vsx_stxvd2x v2f64:$rS, xoaddr:$dst),
+ (STXVX $rS, xoaddr:$dst)>;
+
+ def : Pat<(v4i32 (scalar_to_vector (i32 (load xoaddr:$src)))),
+ (v4i32 (LXVWSX xoaddr:$src))>;
+ def : Pat<(v4f32 (scalar_to_vector (f32 (load xoaddr:$src)))),
+ (v4f32 (LXVWSX xoaddr:$src))>;
+ def : Pat<(v4f32 (scalar_to_vector (f32 (fpround (extloadf32 xoaddr:$src))))),
+ (v4f32 (LXVWSX xoaddr:$src))>;
+
+ // Build vectors from i8 loads
+ def : Pat<(v16i8 (scalar_to_vector ScalarLoads.Li8)),
+ (v16i8 (VSPLTBs 7, (LXSIBZX xoaddr:$src)))>;
+ def : Pat<(v8i16 (scalar_to_vector ScalarLoads.ZELi8)),
+ (v8i16 (VSPLTHs 3, (LXSIBZX xoaddr:$src)))>;
+ def : Pat<(v4i32 (scalar_to_vector ScalarLoads.ZELi8)),
+ (v4i32 (XXSPLTWs (LXSIBZX xoaddr:$src), 1))>;
+ def : Pat<(v2i64 (scalar_to_vector ScalarLoads.ZELi8i64)),
+ (v2i64 (XXPERMDIs (LXSIBZX xoaddr:$src), 0))>;
+ def : Pat<(v4i32 (scalar_to_vector ScalarLoads.SELi8)),
+ (v4i32 (XXSPLTWs (VEXTSB2Ws (LXSIBZX xoaddr:$src)), 1))>;
+ def : Pat<(v2i64 (scalar_to_vector ScalarLoads.SELi8i64)),
+ (v2i64 (XXPERMDIs (VEXTSB2Ds (LXSIBZX xoaddr:$src)), 0))>;
+
+ // Build vectors from i16 loads
+ def : Pat<(v8i16 (scalar_to_vector ScalarLoads.Li16)),
+ (v8i16 (VSPLTHs 3, (LXSIHZX xoaddr:$src)))>;
+ def : Pat<(v4i32 (scalar_to_vector ScalarLoads.ZELi16)),
+ (v4i32 (XXSPLTWs (LXSIHZX xoaddr:$src), 1))>;
+ def : Pat<(v2i64 (scalar_to_vector ScalarLoads.ZELi16i64)),
+ (v2i64 (XXPERMDIs (LXSIHZX xoaddr:$src), 0))>;
+ def : Pat<(v4i32 (scalar_to_vector ScalarLoads.SELi16)),
+ (v4i32 (XXSPLTWs (VEXTSH2Ws (LXSIHZX xoaddr:$src)), 1))>;
+ def : Pat<(v2i64 (scalar_to_vector ScalarLoads.SELi16i64)),
+ (v2i64 (XXPERMDIs (VEXTSH2Ds (LXSIHZX xoaddr:$src)), 0))>;
+
+ let Predicates = [IsBigEndian, HasP9Vector] in {
+ // Scalar stores of i8
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 0)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 9), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 1)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 10), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 2)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 11), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 3)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 12), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 4)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 13), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 5)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 14), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 6)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 15), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 7)), xoaddr:$dst),
+ (STXSIBXv $S, xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 8)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 1), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 9)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 2), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 10)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 3), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 11)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 4), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 12)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 5), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 13)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 6), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 14)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 7), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 15)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 8), xoaddr:$dst)>;
+
+ // Scalar stores of i16
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 0)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 10), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 1)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 12), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 2)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 14), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 3)), xoaddr:$dst),
+ (STXSIHXv $S, xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 4)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 2), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 5)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 4), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 6)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 6), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 7)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 8), xoaddr:$dst)>;
+ } // IsBigEndian, HasP9Vector
+
+ let Predicates = [IsLittleEndian, HasP9Vector] in {
+ // Scalar stores of i8
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 0)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 8), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 1)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 7), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 2)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 6), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 3)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 5), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 4)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 4), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 5)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 3), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 6)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 2), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 7)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 1), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 8)), xoaddr:$dst),
+ (STXSIBXv $S, xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 9)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 15), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 10)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 14), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 11)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 13), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 12)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 12), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 13)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 11), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 14)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 10), xoaddr:$dst)>;
+ def : Pat<(truncstorei8 (i32 (vector_extract v16i8:$S, 15)), xoaddr:$dst),
+ (STXSIBXv (VSLDOI $S, $S, 9), xoaddr:$dst)>;
+
+ // Scalar stores of i16
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 0)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 8), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 1)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 6), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 2)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 4), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 3)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 2), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 4)), xoaddr:$dst),
+ (STXSIHXv $S, xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 5)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 14), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 6)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 12), xoaddr:$dst)>;
+ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 7)), xoaddr:$dst),
+ (STXSIHXv (VSLDOI $S, $S, 10), xoaddr:$dst)>;
+ } // IsLittleEndian, HasP9Vector
+
+
+ // Vector sign extensions
+ def : Pat<(f64 (PPCVexts f64:$A, 1)),
+ (f64 (COPY_TO_REGCLASS (VEXTSB2Ds $A), VSFRC))>;
+ def : Pat<(f64 (PPCVexts f64:$A, 2)),
+ (f64 (COPY_TO_REGCLASS (VEXTSH2Ds $A), VSFRC))>;
+
+ let isPseudo = 1 in {
+ def DFLOADf32 : Pseudo<(outs vssrc:$XT), (ins memrix:$src),
+ "#DFLOADf32",
+ [(set f32:$XT, (load iaddr:$src))]>;
+ def DFLOADf64 : Pseudo<(outs vsfrc:$XT), (ins memrix:$src),
+ "#DFLOADf64",
+ [(set f64:$XT, (load iaddr:$src))]>;
+ def DFSTOREf32 : Pseudo<(outs), (ins vssrc:$XT, memrix:$dst),
+ "#DFSTOREf32",
+ [(store f32:$XT, iaddr:$dst)]>;
+ def DFSTOREf64 : Pseudo<(outs), (ins vsfrc:$XT, memrix:$dst),
+ "#DFSTOREf64",
+ [(store f64:$XT, iaddr:$dst)]>;
+ }
+ def : Pat<(f64 (extloadf32 iaddr:$src)),
+ (COPY_TO_REGCLASS (DFLOADf32 iaddr:$src), VSFRC)>;
+ def : Pat<(f32 (fpround (extloadf32 iaddr:$src))),
+ (f32 (DFLOADf32 iaddr:$src))>;
} // end HasP9Vector, AddedComplexity
+
+// Integer extend helper dags 32 -> 64
+def AnyExts {
+ dag A = (INSERT_SUBREG (i64 (IMPLICIT_DEF)), $A, sub_32);
+ dag B = (INSERT_SUBREG (i64 (IMPLICIT_DEF)), $B, sub_32);
+ dag C = (INSERT_SUBREG (i64 (IMPLICIT_DEF)), $C, sub_32);
+ dag D = (INSERT_SUBREG (i64 (IMPLICIT_DEF)), $D, sub_32);
+}
+
+def DblToFlt {
+ dag A0 = (f32 (fpround (f64 (extractelt v2f64:$A, 0))));
+ dag A1 = (f32 (fpround (f64 (extractelt v2f64:$A, 1))));
+ dag B0 = (f32 (fpround (f64 (extractelt v2f64:$B, 0))));
+ dag B1 = (f32 (fpround (f64 (extractelt v2f64:$B, 1))));
+}
+def FltToIntLoad {
+ dag A = (i32 (PPCmfvsr (PPCfctiwz (f64 (extloadf32 xoaddr:$A)))));
+}
+def FltToUIntLoad {
+ dag A = (i32 (PPCmfvsr (PPCfctiwuz (f64 (extloadf32 xoaddr:$A)))));
+}
+def FltToLongLoad {
+ dag A = (i64 (PPCmfvsr (PPCfctidz (f64 (extloadf32 xoaddr:$A)))));
+}
+def FltToULongLoad {
+ dag A = (i64 (PPCmfvsr (PPCfctiduz (f64 (extloadf32 xoaddr:$A)))));
+}
+def FltToLong {
+ dag A = (i64 (PPCmfvsr (PPCfctidz (fpextend f32:$A))));
+}
+def FltToULong {
+ dag A = (i64 (PPCmfvsr (PPCfctiduz (fpextend f32:$A))));
+}
+def DblToInt {
+ dag A = (i32 (PPCmfvsr (f64 (PPCfctiwz f64:$A))));
+}
+def DblToUInt {
+ dag A = (i32 (PPCmfvsr (f64 (PPCfctiwuz f64:$A))));
+}
+def DblToLong {
+ dag A = (i64 (PPCmfvsr (f64 (PPCfctidz f64:$A))));
+}
+def DblToULong {
+ dag A = (i64 (PPCmfvsr (f64 (PPCfctiduz f64:$A))));
+}
+def DblToIntLoad {
+ dag A = (i32 (PPCmfvsr (PPCfctiwz (f64 (load xoaddr:$A)))));
+}
+def DblToUIntLoad {
+ dag A = (i32 (PPCmfvsr (PPCfctiwuz (f64 (load xoaddr:$A)))));
+}
+def DblToLongLoad {
+ dag A = (i64 (PPCmfvsr (PPCfctidz (f64 (load xoaddr:$A)))));
+}
+def DblToULongLoad {
+ dag A = (i64 (PPCmfvsr (PPCfctiduz (f64 (load xoaddr:$A)))));
+}
+
+// FP merge dags (for f32 -> v4f32)
+def MrgFP {
+ dag AC = (XVCVDPSP (XXPERMDI (COPY_TO_REGCLASS $A, VSRC),
+ (COPY_TO_REGCLASS $C, VSRC), 0));
+ dag BD = (XVCVDPSP (XXPERMDI (COPY_TO_REGCLASS $B, VSRC),
+ (COPY_TO_REGCLASS $D, VSRC), 0));
+ dag ABhToFlt = (XVCVDPSP (XXPERMDI $A, $B, 0));
+ dag ABlToFlt = (XVCVDPSP (XXPERMDI $A, $B, 3));
+ dag BAhToFlt = (XVCVDPSP (XXPERMDI $B, $A, 0));
+ dag BAlToFlt = (XVCVDPSP (XXPERMDI $B, $A, 3));
+}
+
+// Patterns for BUILD_VECTOR nodes.
+def NoP9Vector : Predicate<"!PPCSubTarget->hasP9Vector()">;
+let AddedComplexity = 400 in {
+
+ let Predicates = [HasVSX] in {
+ // Build vectors of floating point converted to i32.
+ def : Pat<(v4i32 (build_vector DblToInt.A, DblToInt.A,
+ DblToInt.A, DblToInt.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS (XSCVDPSXWS $A), VSRC), 1))>;
+ def : Pat<(v4i32 (build_vector DblToUInt.A, DblToUInt.A,
+ DblToUInt.A, DblToUInt.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS (XSCVDPUXWS $A), VSRC), 1))>;
+ def : Pat<(v2i64 (build_vector DblToLong.A, DblToLong.A)),
+ (v2i64 (XXPERMDI (COPY_TO_REGCLASS (XSCVDPSXDS $A), VSRC),
+ (COPY_TO_REGCLASS (XSCVDPSXDS $A), VSRC), 0))>;
+ def : Pat<(v2i64 (build_vector DblToULong.A, DblToULong.A)),
+ (v2i64 (XXPERMDI (COPY_TO_REGCLASS (XSCVDPUXDS $A), VSRC),
+ (COPY_TO_REGCLASS (XSCVDPUXDS $A), VSRC), 0))>;
+ def : Pat<(v4i32 (scalar_to_vector FltToIntLoad.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS
+ (XSCVDPSXWSs (LXSSPX xoaddr:$A)), VSRC), 1))>;
+ def : Pat<(v4i32 (scalar_to_vector FltToUIntLoad.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS
+ (XSCVDPUXWSs (LXSSPX xoaddr:$A)), VSRC), 1))>;
+ def : Pat<(v4f32 (build_vector f32:$A, f32:$A, f32:$A, f32:$A)),
+ (v4f32 (XXSPLTW (v4f32 (XSCVDPSPN $A)), 0))>;
+
+ // Build vectors of floating point converted to i64.
+ def : Pat<(v2i64 (build_vector FltToLong.A, FltToLong.A)),
+ (v2i64 (XXPERMDIs
+ (COPY_TO_REGCLASS (XSCVDPSXDSs $A), VSFRC), 0))>;
+ def : Pat<(v2i64 (build_vector FltToULong.A, FltToULong.A)),
+ (v2i64 (XXPERMDIs
+ (COPY_TO_REGCLASS (XSCVDPUXDSs $A), VSFRC), 0))>;
+ def : Pat<(v2i64 (scalar_to_vector DblToLongLoad.A)),
+ (v2i64 (XVCVDPSXDS (LXVDSX xoaddr:$A)))>;
+ def : Pat<(v2i64 (scalar_to_vector DblToULongLoad.A)),
+ (v2i64 (XVCVDPUXDS (LXVDSX xoaddr:$A)))>;
+ }
+
+ let Predicates = [HasVSX, NoP9Vector] in {
+ // Load-and-splat with fp-to-int conversion (using X-Form VSX loads).
+ def : Pat<(v4i32 (scalar_to_vector DblToIntLoad.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS
+ (XSCVDPSXWS (LXSDX xoaddr:$A)), VSRC), 1))>;
+ def : Pat<(v4i32 (scalar_to_vector DblToUIntLoad.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS
+ (XSCVDPUXWS (LXSDX xoaddr:$A)), VSRC), 1))>;
+ def : Pat<(v2i64 (scalar_to_vector FltToLongLoad.A)),
+ (v2i64 (XXPERMDIs (XSCVDPSXDS (COPY_TO_REGCLASS
+ (LXSSPX xoaddr:$A), VSFRC)), 0))>;
+ def : Pat<(v2i64 (scalar_to_vector FltToULongLoad.A)),
+ (v2i64 (XXPERMDIs (XSCVDPUXDS (COPY_TO_REGCLASS
+ (LXSSPX xoaddr:$A), VSFRC)), 0))>;
+ }
+
+ // Big endian, available on all targets with VSX
+ let Predicates = [IsBigEndian, HasVSX] in {
+ def : Pat<(v2f64 (build_vector f64:$A, f64:$B)),
+ (v2f64 (XXPERMDI
+ (COPY_TO_REGCLASS $A, VSRC),
+ (COPY_TO_REGCLASS $B, VSRC), 0))>;
+
+ def : Pat<(v4f32 (build_vector f32:$A, f32:$B, f32:$C, f32:$D)),
+ (VMRGEW MrgFP.AC, MrgFP.BD)>;
+ def : Pat<(v4f32 (build_vector DblToFlt.A0, DblToFlt.A1,
+ DblToFlt.B0, DblToFlt.B1)),
+ (v4f32 (VMRGEW MrgFP.ABhToFlt, MrgFP.ABlToFlt))>;
+ }
+
+ let Predicates = [IsLittleEndian, HasVSX] in {
+ // Little endian, available on all targets with VSX
+ def : Pat<(v2f64 (build_vector f64:$A, f64:$B)),
+ (v2f64 (XXPERMDI
+ (COPY_TO_REGCLASS $B, VSRC),
+ (COPY_TO_REGCLASS $A, VSRC), 0))>;
+
+ def : Pat<(v4f32 (build_vector f32:$D, f32:$C, f32:$B, f32:$A)),
+ (VMRGEW MrgFP.AC, MrgFP.BD)>;
+ def : Pat<(v4f32 (build_vector DblToFlt.A0, DblToFlt.A1,
+ DblToFlt.B0, DblToFlt.B1)),
+ (v4f32 (VMRGEW MrgFP.BAhToFlt, MrgFP.BAlToFlt))>;
+ }
+
+ let Predicates = [HasDirectMove] in {
+ // Endianness-neutral constant splat on P8 and newer targets. The reason
+ // for this pattern is that on targets with direct moves, we don't expand
+ // BUILD_VECTOR nodes for v4i32.
+ def : Pat<(v4i32 (build_vector immSExt5NonZero:$A, immSExt5NonZero:$A,
+ immSExt5NonZero:$A, immSExt5NonZero:$A)),
+ (v4i32 (VSPLTISW imm:$A))>;
+ }
+
+ let Predicates = [IsBigEndian, HasDirectMove, NoP9Vector] in {
+ // Big endian integer vectors using direct moves.
+ def : Pat<(v2i64 (build_vector i64:$A, i64:$B)),
+ (v2i64 (XXPERMDI
+ (COPY_TO_REGCLASS (MTVSRD $A), VSRC),
+ (COPY_TO_REGCLASS (MTVSRD $B), VSRC), 0))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$B, i32:$C, i32:$D)),
+ (VMRGOW (XXPERMDI (COPY_TO_REGCLASS (MTVSRWZ $A), VSRC),
+ (COPY_TO_REGCLASS (MTVSRWZ $C), VSRC), 0),
+ (XXPERMDI (COPY_TO_REGCLASS (MTVSRWZ $B), VSRC),
+ (COPY_TO_REGCLASS (MTVSRWZ $D), VSRC), 0))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$A, i32:$A, i32:$A)),
+ (XXSPLTW (COPY_TO_REGCLASS (MTVSRWZ $A), VSRC), 1)>;
+ }
+
+ let Predicates = [IsLittleEndian, HasDirectMove, NoP9Vector] in {
+ // Little endian integer vectors using direct moves.
+ def : Pat<(v2i64 (build_vector i64:$A, i64:$B)),
+ (v2i64 (XXPERMDI
+ (COPY_TO_REGCLASS (MTVSRD $B), VSRC),
+ (COPY_TO_REGCLASS (MTVSRD $A), VSRC), 0))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$B, i32:$C, i32:$D)),
+ (VMRGOW (XXPERMDI (COPY_TO_REGCLASS (MTVSRWZ $D), VSRC),
+ (COPY_TO_REGCLASS (MTVSRWZ $B), VSRC), 0),
+ (XXPERMDI (COPY_TO_REGCLASS (MTVSRWZ $C), VSRC),
+ (COPY_TO_REGCLASS (MTVSRWZ $A), VSRC), 0))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$A, i32:$A, i32:$A)),
+ (XXSPLTW (COPY_TO_REGCLASS (MTVSRWZ $A), VSRC), 1)>;
+ }
+
+ let Predicates = [HasP9Vector] in {
+ // Endianness-neutral patterns for const splats with ISA 3.0 instructions.
+ def : Pat<(v4i32 (scalar_to_vector i32:$A)),
+ (v4i32 (MTVSRWS $A))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$A, i32:$A, i32:$A)),
+ (v4i32 (MTVSRWS $A))>;
+ def : Pat<(v16i8 (build_vector immAnyExt8:$A, immAnyExt8:$A, immAnyExt8:$A,
+ immAnyExt8:$A, immAnyExt8:$A, immAnyExt8:$A,
+ immAnyExt8:$A, immAnyExt8:$A, immAnyExt8:$A,
+ immAnyExt8:$A, immAnyExt8:$A, immAnyExt8:$A,
+ immAnyExt8:$A, immAnyExt8:$A, immAnyExt8:$A,
+ immAnyExt8:$A)),
+ (v16i8 (COPY_TO_REGCLASS (XXSPLTIB imm:$A), VSRC))>;
+ def : Pat<(v16i8 immAllOnesV),
+ (v16i8 (COPY_TO_REGCLASS (XXSPLTIB 255), VSRC))>;
+ def : Pat<(v8i16 immAllOnesV),
+ (v8i16 (COPY_TO_REGCLASS (XXSPLTIB 255), VSRC))>;
+ def : Pat<(v4i32 immAllOnesV),
+ (v4i32 (XXSPLTIB 255))>;
+ def : Pat<(v2i64 immAllOnesV),
+ (v2i64 (XXSPLTIB 255))>;
+ def : Pat<(v4i32 (scalar_to_vector FltToIntLoad.A)),
+ (v4i32 (XVCVSPSXWS (LXVWSX xoaddr:$A)))>;
+ def : Pat<(v4i32 (scalar_to_vector FltToUIntLoad.A)),
+ (v4i32 (XVCVSPUXWS (LXVWSX xoaddr:$A)))>;
+ def : Pat<(v4i32 (scalar_to_vector DblToIntLoad.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS
+ (XSCVDPSXWS (DFLOADf64 iaddr:$A)), VSRC), 1))>;
+ def : Pat<(v4i32 (scalar_to_vector DblToUIntLoad.A)),
+ (v4i32 (XXSPLTW (COPY_TO_REGCLASS
+ (XSCVDPUXWS (DFLOADf64 iaddr:$A)), VSRC), 1))>;
+ def : Pat<(v2i64 (scalar_to_vector FltToLongLoad.A)),
+ (v2i64 (XXPERMDIs (XSCVDPSXDS (COPY_TO_REGCLASS
+ (DFLOADf32 iaddr:$A),
+ VSFRC)), 0))>;
+ def : Pat<(v2i64 (scalar_to_vector FltToULongLoad.A)),
+ (v2i64 (XXPERMDIs (XSCVDPUXDS (COPY_TO_REGCLASS
+ (DFLOADf32 iaddr:$A),
+ VSFRC)), 0))>;
+ }
+
+ let Predicates = [IsISA3_0, HasDirectMove, IsBigEndian] in {
+ def : Pat<(i64 (extractelt v2i64:$A, 1)),
+ (i64 (MFVSRLD $A))>;
+ // Better way to build integer vectors if we have MTVSRDD. Big endian.
+ def : Pat<(v2i64 (build_vector i64:$rB, i64:$rA)),
+ (v2i64 (MTVSRDD $rB, $rA))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$B, i32:$C, i32:$D)),
+ (VMRGOW (COPY_TO_REGCLASS (MTVSRDD AnyExts.A, AnyExts.C), VSRC),
+ (COPY_TO_REGCLASS (MTVSRDD AnyExts.B, AnyExts.D), VSRC))>;
+ }
+
+ let Predicates = [IsISA3_0, HasDirectMove, IsLittleEndian] in {
+ def : Pat<(i64 (extractelt v2i64:$A, 0)),
+ (i64 (MFVSRLD $A))>;
+ // Better way to build integer vectors if we have MTVSRDD. Little endian.
+ def : Pat<(v2i64 (build_vector i64:$rA, i64:$rB)),
+ (v2i64 (MTVSRDD $rB, $rA))>;
+ def : Pat<(v4i32 (build_vector i32:$A, i32:$B, i32:$C, i32:$D)),
+ (VMRGOW (COPY_TO_REGCLASS (MTVSRDD AnyExts.D, AnyExts.B), VSRC),
+ (COPY_TO_REGCLASS (MTVSRDD AnyExts.C, AnyExts.A), VSRC))>;
+ }
+}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp b/contrib/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp
index 48a71cf..2c3e755 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp
@@ -20,31 +20,38 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ppc-loop-preinc-prep"
+
#include "PPC.h"
+#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
#include "llvm/ADT/DepthFirstIterator.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/CodeMetrics.h"
-#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
-#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
-#include "llvm/IR/Function.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
-#include "llvm/Transforms/Utils/ValueMapper.h"
+#include <cassert>
+#include <iterator>
+#include <utility>
+
using namespace llvm;
// By default, we limit this to creating 16 PHIs (which is a little over half
@@ -54,14 +61,17 @@ static cl::opt<unsigned> MaxVars("ppc-preinc-prep-max-vars",
cl::desc("Potential PHI threshold for PPC preinc loop prep"));
namespace llvm {
+
void initializePPCLoopPreIncPrepPass(PassRegistry&);
-}
+
+} // end namespace llvm
namespace {
class PPCLoopPreIncPrep : public FunctionPass {
public:
static char ID; // Pass ID, replacement for typeid
+
PPCLoopPreIncPrep() : FunctionPass(ID), TM(nullptr) {
initializePPCLoopPreIncPrepPass(*PassRegistry::getPassRegistry());
}
@@ -89,7 +99,8 @@ namespace {
ScalarEvolution *SE;
bool PreserveLCSSA;
};
-}
+
+} // end anonymous namespace
char PPCLoopPreIncPrep::ID = 0;
static const char *name = "Prepare loop for pre-inc. addressing modes";
@@ -103,6 +114,7 @@ FunctionPass *llvm::createPPCLoopPreIncPrepPass(PPCTargetMachine &TM) {
}
namespace {
+
struct BucketElement {
BucketElement(const SCEVConstant *O, Instruction *I) : Offset(O), Instr(I) {}
BucketElement(Instruction *I) : Offset(nullptr), Instr(I) {}
@@ -118,7 +130,8 @@ namespace {
const SCEV *BaseSCEV;
SmallVector<BucketElement, 16> Elements;
};
-}
+
+} // end anonymous namespace
static bool IsPtrInBounds(Value *BasePtr) {
Value *StrippedBasePtr = BasePtr;
@@ -140,7 +153,7 @@ static Value *GetPointerOperand(Value *MemI) {
return IMemI->getArgOperand(0);
}
- return 0;
+ return nullptr;
}
bool PPCLoopPreIncPrep::runOnFunction(Function &F) {
@@ -394,7 +407,7 @@ bool PPCLoopPreIncPrep::runOnLoop(Loop *L) {
Instruction *PtrIP = dyn_cast<Instruction>(Ptr);
if (PtrIP && isa<Instruction>(NewBasePtr) &&
cast<Instruction>(NewBasePtr)->getParent() == PtrIP->getParent())
- PtrIP = 0;
+ PtrIP = nullptr;
else if (isa<PHINode>(PtrIP))
PtrIP = &*PtrIP->getParent()->getFirstInsertionPt();
else if (!PtrIP)
@@ -437,4 +450,3 @@ bool PPCLoopPreIncPrep::runOnLoop(Loop *L) {
return MadeChange;
}
-
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp b/contrib/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
index 18377a4..e527b01 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
@@ -34,10 +34,10 @@ static MachineModuleInfoMachO &getMachOMMI(AsmPrinter &AP) {
return AP.MMI->getObjFileInfo<MachineModuleInfoMachO>();
}
-
-static MCSymbol *GetSymbolFromOperand(const MachineOperand &MO, AsmPrinter &AP){
+static MCSymbol *GetSymbolFromOperand(const MachineOperand &MO,
+ AsmPrinter &AP) {
const TargetMachine &TM = AP.TM;
- Mangler *Mang = AP.Mang;
+ Mangler &Mang = TM.getObjFileLowering()->getMangler();
const DataLayout &DL = AP.getDataLayout();
MCContext &Ctx = AP.OutContext;
@@ -54,7 +54,7 @@ static MCSymbol *GetSymbolFromOperand(const MachineOperand &MO, AsmPrinter &AP){
Mangler::getNameWithPrefix(Name, MO.getSymbolName(), DL);
} else {
const GlobalValue *GV = MO.getGlobal();
- TM.getNameWithPrefix(Name, GV, *Mang);
+ TM.getNameWithPrefix(Name, GV, Mang);
}
Name += Suffix;
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp b/contrib/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
index a57a83d..2413af3 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCMIPeephole.cpp
@@ -124,10 +124,40 @@ bool PPCMIPeephole::simplifyCode(void) {
if (TrueReg1 == TrueReg2
&& TargetRegisterInfo::isVirtualRegister(TrueReg1)) {
MachineInstr *DefMI = MRI->getVRegDef(TrueReg1);
+ unsigned DefOpc = DefMI ? DefMI->getOpcode() : 0;
+
+ // If this is a splat fed by a splatting load, the splat is
+ // redundant. Replace with a copy. This doesn't happen directly due
+ // to code in PPCDAGToDAGISel.cpp, but it can happen when converting
+ // a load of a double to a vector of 64-bit integers.
+ auto isConversionOfLoadAndSplat = [=]() -> bool {
+ if (DefOpc != PPC::XVCVDPSXDS && DefOpc != PPC::XVCVDPUXDS)
+ return false;
+ unsigned DefReg = lookThruCopyLike(DefMI->getOperand(1).getReg());
+ if (TargetRegisterInfo::isVirtualRegister(DefReg)) {
+ MachineInstr *LoadMI = MRI->getVRegDef(DefReg);
+ if (LoadMI && LoadMI->getOpcode() == PPC::LXVDSX)
+ return true;
+ }
+ return false;
+ };
+ if (DefMI && (Immed == 0 || Immed == 3)) {
+ if (DefOpc == PPC::LXVDSX || isConversionOfLoadAndSplat()) {
+ DEBUG(dbgs()
+ << "Optimizing load-and-splat/splat "
+ "to load-and-splat/copy: ");
+ DEBUG(MI.dump());
+ BuildMI(MBB, &MI, MI.getDebugLoc(),
+ TII->get(PPC::COPY), MI.getOperand(0).getReg())
+ .addOperand(MI.getOperand(1));
+ ToErase = &MI;
+ Simplified = true;
+ }
+ }
// If this is a splat or a swap fed by another splat, we
// can replace it with a copy.
- if (DefMI && DefMI->getOpcode() == PPC::XXPERMDI) {
+ if (DefOpc == PPC::XXPERMDI) {
unsigned FeedImmed = DefMI->getOperand(3).getImm();
unsigned FeedReg1
= lookThruCopyLike(DefMI->getOperand(1).getReg());
@@ -170,14 +200,144 @@ bool PPCMIPeephole::simplifyCode(void) {
ToErase = &MI;
Simplified = true;
}
+ } else if ((Immed == 0 || Immed == 3) && DefOpc == PPC::XXPERMDIs &&
+ (DefMI->getOperand(2).getImm() == 0 ||
+ DefMI->getOperand(2).getImm() == 3)) {
+ // Splat fed by another splat - switch the output of the first
+ // and remove the second.
+ DefMI->getOperand(0).setReg(MI.getOperand(0).getReg());
+ ToErase = &MI;
+ Simplified = true;
+ DEBUG(dbgs() << "Removing redundant splat: ");
+ DEBUG(MI.dump());
+ }
+ }
+ }
+ break;
+ }
+ case PPC::VSPLTB:
+ case PPC::VSPLTH:
+ case PPC::XXSPLTW: {
+ unsigned MyOpcode = MI.getOpcode();
+ unsigned OpNo = MyOpcode == PPC::XXSPLTW ? 1 : 2;
+ unsigned TrueReg = lookThruCopyLike(MI.getOperand(OpNo).getReg());
+ if (!TargetRegisterInfo::isVirtualRegister(TrueReg))
+ break;
+ MachineInstr *DefMI = MRI->getVRegDef(TrueReg);
+ if (!DefMI)
+ break;
+ unsigned DefOpcode = DefMI->getOpcode();
+ auto isConvertOfSplat = [=]() -> bool {
+ if (DefOpcode != PPC::XVCVSPSXWS && DefOpcode != PPC::XVCVSPUXWS)
+ return false;
+ unsigned ConvReg = DefMI->getOperand(1).getReg();
+ if (!TargetRegisterInfo::isVirtualRegister(ConvReg))
+ return false;
+ MachineInstr *Splt = MRI->getVRegDef(ConvReg);
+ return Splt && (Splt->getOpcode() == PPC::LXVWSX ||
+ Splt->getOpcode() == PPC::XXSPLTW);
+ };
+ bool AlreadySplat = (MyOpcode == DefOpcode) ||
+ (MyOpcode == PPC::VSPLTB && DefOpcode == PPC::VSPLTBs) ||
+ (MyOpcode == PPC::VSPLTH && DefOpcode == PPC::VSPLTHs) ||
+ (MyOpcode == PPC::XXSPLTW && DefOpcode == PPC::XXSPLTWs) ||
+ (MyOpcode == PPC::XXSPLTW && DefOpcode == PPC::LXVWSX) ||
+ (MyOpcode == PPC::XXSPLTW && DefOpcode == PPC::MTVSRWS)||
+ (MyOpcode == PPC::XXSPLTW && isConvertOfSplat());
+ // If the instruction[s] that feed this splat have already splat
+ // the value, this splat is redundant.
+ if (AlreadySplat) {
+ DEBUG(dbgs() << "Changing redundant splat to a copy: ");
+ DEBUG(MI.dump());
+ BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
+ MI.getOperand(0).getReg())
+ .addOperand(MI.getOperand(OpNo));
+ ToErase = &MI;
+ Simplified = true;
+ }
+ // Splat fed by a shift. Usually when we align value to splat into
+ // vector element zero.
+ if (DefOpcode == PPC::XXSLDWI) {
+ unsigned ShiftRes = DefMI->getOperand(0).getReg();
+ unsigned ShiftOp1 = DefMI->getOperand(1).getReg();
+ unsigned ShiftOp2 = DefMI->getOperand(2).getReg();
+ unsigned ShiftImm = DefMI->getOperand(3).getImm();
+ unsigned SplatImm = MI.getOperand(2).getImm();
+ if (ShiftOp1 == ShiftOp2) {
+ unsigned NewElem = (SplatImm + ShiftImm) & 0x3;
+ if (MRI->hasOneNonDBGUse(ShiftRes)) {
+ DEBUG(dbgs() << "Removing redundant shift: ");
+ DEBUG(DefMI->dump());
+ ToErase = DefMI;
}
+ Simplified = true;
+ DEBUG(dbgs() << "Changing splat immediate from " << SplatImm <<
+ " to " << NewElem << " in instruction: ");
+ DEBUG(MI.dump());
+ MI.getOperand(1).setReg(ShiftOp1);
+ MI.getOperand(2).setImm(NewElem);
}
}
break;
}
+ case PPC::XVCVDPSP: {
+ // If this is a DP->SP conversion fed by an FRSP, the FRSP is redundant.
+ unsigned TrueReg = lookThruCopyLike(MI.getOperand(1).getReg());
+ if (!TargetRegisterInfo::isVirtualRegister(TrueReg))
+ break;
+ MachineInstr *DefMI = MRI->getVRegDef(TrueReg);
+
+ // This can occur when building a vector of single precision or integer
+ // values.
+ if (DefMI && DefMI->getOpcode() == PPC::XXPERMDI) {
+ unsigned DefsReg1 = lookThruCopyLike(DefMI->getOperand(1).getReg());
+ unsigned DefsReg2 = lookThruCopyLike(DefMI->getOperand(2).getReg());
+ if (!TargetRegisterInfo::isVirtualRegister(DefsReg1) ||
+ !TargetRegisterInfo::isVirtualRegister(DefsReg2))
+ break;
+ MachineInstr *P1 = MRI->getVRegDef(DefsReg1);
+ MachineInstr *P2 = MRI->getVRegDef(DefsReg2);
+
+ if (!P1 || !P2)
+ break;
+
+ // Remove the passed FRSP instruction if it only feeds this MI and
+ // set any uses of that FRSP (in this MI) to the source of the FRSP.
+ auto removeFRSPIfPossible = [&](MachineInstr *RoundInstr) {
+ if (RoundInstr->getOpcode() == PPC::FRSP &&
+ MRI->hasOneNonDBGUse(RoundInstr->getOperand(0).getReg())) {
+ Simplified = true;
+ unsigned ConvReg1 = RoundInstr->getOperand(1).getReg();
+ unsigned FRSPDefines = RoundInstr->getOperand(0).getReg();
+ MachineInstr &Use = *(MRI->use_instr_begin(FRSPDefines));
+ for (int i = 0, e = Use.getNumOperands(); i < e; ++i)
+ if (Use.getOperand(i).isReg() &&
+ Use.getOperand(i).getReg() == FRSPDefines)
+ Use.getOperand(i).setReg(ConvReg1);
+ DEBUG(dbgs() << "Removing redundant FRSP:\n");
+ DEBUG(RoundInstr->dump());
+ DEBUG(dbgs() << "As it feeds instruction:\n");
+ DEBUG(MI.dump());
+ DEBUG(dbgs() << "Through instruction:\n");
+ DEBUG(DefMI->dump());
+ RoundInstr->eraseFromParent();
+ }
+ };
+
+ // If the input to XVCVDPSP is a vector that was built (even
+ // partially) out of FRSP's, the FRSP(s) can safely be removed
+ // since this instruction performs the same operation.
+ if (P1 != P2) {
+ removeFRSPIfPossible(P1);
+ removeFRSPIfPossible(P2);
+ break;
+ }
+ removeFRSPIfPossible(P1);
+ }
+ break;
+ }
}
}
-
// If the last instruction was marked for elimination,
// remove it now.
if (ToErase) {
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCQPXLoadSplat.cpp b/contrib/llvm/lib/Target/PowerPC/PPCQPXLoadSplat.cpp
index bfe20c1..8a18ab9 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCQPXLoadSplat.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCQPXLoadSplat.cpp
@@ -44,7 +44,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &Fn) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "PowerPC QPX Load Splat Simplification";
}
};
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
index f0161a0..e492014 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
@@ -78,6 +78,18 @@ PPCRegisterInfo::PPCRegisterInfo(const PPCTargetMachine &TM)
ImmToIdxMap[PPC::STB8] = PPC::STBX8; ImmToIdxMap[PPC::STH8] = PPC::STHX8;
ImmToIdxMap[PPC::STW8] = PPC::STWX8; ImmToIdxMap[PPC::STDU] = PPC::STDUX;
ImmToIdxMap[PPC::ADDI8] = PPC::ADD8;
+
+ // VSX
+ ImmToIdxMap[PPC::DFLOADf32] = PPC::LXSSPX;
+ ImmToIdxMap[PPC::DFLOADf64] = PPC::LXSDX;
+ ImmToIdxMap[PPC::DFSTOREf32] = PPC::STXSSPX;
+ ImmToIdxMap[PPC::DFSTOREf64] = PPC::STXSDX;
+ ImmToIdxMap[PPC::LXV] = PPC::LXVX;
+ ImmToIdxMap[PPC::LXSD] = PPC::LXSDX;
+ ImmToIdxMap[PPC::LXSSP] = PPC::LXSSPX;
+ ImmToIdxMap[PPC::STXV] = PPC::STXVX;
+ ImmToIdxMap[PPC::STXSD] = PPC::STXSDX;
+ ImmToIdxMap[PPC::STXSSP] = PPC::STXSSPX;
}
/// getPointerRegClass - Return the register class to use to hold pointers.
@@ -303,7 +315,6 @@ unsigned PPCRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
case PPC::VRRCRegClassID:
case PPC::VFRCRegClassID:
case PPC::VSLRCRegClassID:
- case PPC::VSHRCRegClassID:
return 32 - DefaultSafety;
case PPC::VSRCRegClassID:
case PPC::VSFRCRegClassID:
@@ -352,7 +363,7 @@ void PPCRegisterInfo::lowerDynamicAlloc(MachineBasicBlock::iterator II) const {
// Get the basic block's function.
MachineFunction &MF = *MBB.getParent();
// Get the frame info.
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>();
// Get the instruction info.
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
@@ -361,14 +372,14 @@ void PPCRegisterInfo::lowerDynamicAlloc(MachineBasicBlock::iterator II) const {
DebugLoc dl = MI.getDebugLoc();
// Get the maximum call stack size.
- unsigned maxCallFrameSize = MFI->getMaxCallFrameSize();
+ unsigned maxCallFrameSize = MFI.getMaxCallFrameSize();
// Get the total frame size.
- unsigned FrameSize = MFI->getStackSize();
+ unsigned FrameSize = MFI.getStackSize();
// Get stack alignments.
const PPCFrameLowering *TFI = getFrameLowering(MF);
unsigned TargetAlign = TFI->getStackAlignment();
- unsigned MaxAlign = MFI->getMaxAlignment();
+ unsigned MaxAlign = MFI.getMaxAlignment();
assert((maxCallFrameSize & (MaxAlign-1)) == 0 &&
"Maximum call-frame size not sufficiently aligned");
@@ -466,12 +477,12 @@ void PPCRegisterInfo::lowerDynamicAreaOffset(
// Get the basic block's function.
MachineFunction &MF = *MBB.getParent();
// Get the frame info.
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>();
// Get the instruction info.
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
- unsigned maxCallFrameSize = MFI->getMaxCallFrameSize();
+ unsigned maxCallFrameSize = MFI.getMaxCallFrameSize();
DebugLoc dl = MI.getDebugLoc();
BuildMI(MBB, II, dl, TII.get(PPC::LI), MI.getOperand(0).getReg())
.addImm(maxCallFrameSize);
@@ -787,7 +798,7 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// Get the instruction info.
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
// Get the frame info.
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
DebugLoc dl = MI.getDebugLoc();
unsigned OffsetOperandNo = getOffsetONFromFION(MI, FIOperandNum);
@@ -848,7 +859,7 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
OpC != TargetOpcode::PATCHPOINT && !ImmToIdxMap.count(OpC);
// Now add the frame object offset to the offset from r1.
- int Offset = MFI->getObjectOffset(FrameIndex);
+ int Offset = MFI.getObjectOffset(FrameIndex);
Offset += MI.getOperand(OffsetOperandNo).getImm();
// If we're not using a Frame Pointer that has been set to the value of the
@@ -859,7 +870,7 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// functions.
if (!MF.getFunction()->hasFnAttribute(Attribute::Naked)) {
if (!(hasBasePointer(MF) && FrameIndex < 0))
- Offset += MFI->getStackSize();
+ Offset += MFI.getStackSize();
}
// If we can, encode the offset directly into the instruction. If this is a
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.h b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.h
index 459502e..4a96327 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.h
+++ b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.h
@@ -75,7 +75,7 @@ public:
/// Code Generation virtual methods...
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
- const MCPhysReg *getCalleeSavedRegsViaCopy(const MachineFunction *MF) const override;
+ const MCPhysReg *getCalleeSavedRegsViaCopy(const MachineFunction *MF) const;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const override;
const uint32_t *getNoPreservedMask() const override;
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.td b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
index e5f363c..896cec7 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
@@ -17,7 +17,6 @@ def sub_eq : SubRegIndex<1, 2>;
def sub_un : SubRegIndex<1, 3>;
def sub_32 : SubRegIndex<32>;
def sub_64 : SubRegIndex<64>;
-def sub_128 : SubRegIndex<128>;
}
@@ -79,15 +78,6 @@ class VSRL<FPR SubReg, string n> : PPCReg<n> {
let SubRegIndices = [sub_64];
}
-// VSRH - One of the 32 128-bit VSX registers that overlap with the vector
-// registers.
-class VSRH<VR SubReg, string n> : PPCReg<n> {
- let HWEncoding{4-0} = SubReg.HWEncoding{4-0};
- let HWEncoding{5} = 1;
- let SubRegs = [SubReg];
- let SubRegIndices = [sub_128];
-}
-
// CR - One of the 8 4-bit condition registers
class CR<bits<3> num, string n, list<Register> subregs> : PPCReg<n> {
let HWEncoding{2-0} = num;
@@ -116,9 +106,12 @@ foreach Index = 0-31 in {
DwarfRegNum<[!add(Index, 32), !add(Index, 32)]>;
}
-// Floating-point vector subregisters (for VSX)
+// 64-bit Floating-point subregisters of Altivec registers
+// Note: the register names are v0-v31 or vs32-vs63 depending on the use.
+// Custom C++ code is used to produce the correct name and encoding.
foreach Index = 0-31 in {
- def VF#Index : VF<Index, "vs" # !add(Index, 32)>;
+ def VF#Index : VF<Index, "v" #Index>,
+ DwarfRegNum<[!add(Index, 77), !add(Index, 77)]>;
}
// QPX Floating-point registers
@@ -138,9 +131,11 @@ foreach Index = 0-31 in {
def VSL#Index : VSRL<!cast<FPR>("F"#Index), "vs"#Index>,
DwarfRegAlias<!cast<FPR>("F"#Index)>;
}
-foreach Index = 0-31 in {
- def VSH#Index : VSRH<!cast<VR>("V"#Index), "vs" # !add(Index, 32)>,
- DwarfRegAlias<!cast<VR>("V"#Index)>;
+
+// Dummy VSX registers, this defines string: "vs32"-"vs63", and is only used for
+// asm printing.
+foreach Index = 32-63 in {
+ def VSX#Index : PPCReg<"vs"#Index>;
}
// The reprsentation of r0 when treated as the constant 0.
@@ -288,7 +283,7 @@ def F8RC : RegisterClass<"PPC", [f64], 64, (add (sequence "F%u", 0, 13),
(sequence "F%u", 31, 14))>;
def F4RC : RegisterClass<"PPC", [f32], 32, (add F8RC)>;
-def VRRC : RegisterClass<"PPC", [v16i8,v8i16,v4i32,v2i64,v1i128,v4f32], 128,
+def VRRC : RegisterClass<"PPC", [v16i8,v8i16,v4i32,v2i64,v1i128,v4f32,v2f64], 128,
(add V2, V3, V4, V5, V0, V1, V6, V7, V8, V9, V10, V11,
V12, V13, V14, V15, V16, V17, V18, V19, V31, V30,
V29, V28, V27, V26, V25, V24, V23, V22, V21, V20)>;
@@ -298,14 +293,8 @@ def VRRC : RegisterClass<"PPC", [v16i8,v8i16,v4i32,v2i64,v1i128,v4f32], 128,
def VSLRC : RegisterClass<"PPC", [v4i32,v4f32,v2f64,v2i64], 128,
(add (sequence "VSL%u", 0, 13),
(sequence "VSL%u", 31, 14))>;
-def VSHRC : RegisterClass<"PPC", [v4i32,v4f32,v2f64,v2i64], 128,
- (add VSH2, VSH3, VSH4, VSH5, VSH0, VSH1, VSH6, VSH7,
- VSH8, VSH9, VSH10, VSH11, VSH12, VSH13, VSH14,
- VSH15, VSH16, VSH17, VSH18, VSH19, VSH31, VSH30,
- VSH29, VSH28, VSH27, VSH26, VSH25, VSH24, VSH23,
- VSH22, VSH21, VSH20)>;
def VSRC : RegisterClass<"PPC", [v4i32,v4f32,v2f64,v2i64], 128,
- (add VSLRC, VSHRC)>;
+ (add VSLRC, VRRC)>;
// Register classes for the 64-bit "scalar" VSX subregisters.
def VFRC : RegisterClass<"PPC", [f64], 64,
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCSchedule.td b/contrib/llvm/lib/Target/PowerPC/PPCSchedule.td
index b4d72ef..d240529 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCSchedule.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCSchedule.td
@@ -109,6 +109,7 @@ def IIC_SprSLBIE : InstrItinClass;
def IIC_SprSLBIEG : InstrItinClass;
def IIC_SprSLBMTE : InstrItinClass;
def IIC_SprSLBMFEE : InstrItinClass;
+def IIC_SprSLBMFEV : InstrItinClass;
def IIC_SprSLBIA : InstrItinClass;
def IIC_SprSLBSYNC : InstrItinClass;
def IIC_SprTLBIA : InstrItinClass;
@@ -117,6 +118,8 @@ def IIC_SprTLBIE : InstrItinClass;
def IIC_SprABORT : InstrItinClass;
def IIC_SprMSGSYNC : InstrItinClass;
def IIC_SprSTOP : InstrItinClass;
+def IIC_SprMFPMR : InstrItinClass;
+def IIC_SprMTPMR : InstrItinClass;
//===----------------------------------------------------------------------===//
// Processor instruction itineraries.
@@ -128,6 +131,7 @@ include "PPCScheduleG4Plus.td"
include "PPCScheduleG5.td"
include "PPCScheduleP7.td"
include "PPCScheduleP8.td"
+include "PPCScheduleP9.td"
include "PPCScheduleA2.td"
include "PPCScheduleE500mc.td"
include "PPCScheduleE5500.td"
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCScheduleE500mc.td b/contrib/llvm/lib/Target/PowerPC/PPCScheduleE500mc.td
index f687d32..15d5991 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCScheduleE500mc.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCScheduleE500mc.td
@@ -249,6 +249,10 @@ def PPCE500mcItineraries : ProcessorItineraries<
InstrStage<5, [E500_SFX0]>],
[8, 1],
[E500_GPR_Bypass, E500_CR_Bypass]>,
+ InstrItinData<IIC_SprMFPMR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
+ InstrStage<4, [E500_SFX0]>],
+ [7, 1], // Latency = 4, Repeat rate = 4
+ [E500_GPR_Bypass, E500_GPR_Bypass]>,
InstrItinData<IIC_SprMFMSR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
InstrStage<4, [E500_SFX0]>],
[7, 1], // Latency = 4, Repeat rate = 4
@@ -257,6 +261,10 @@ def PPCE500mcItineraries : ProcessorItineraries<
InstrStage<1, [E500_SFX0, E500_SFX1]>],
[4, 1], // Latency = 1, Repeat rate = 1
[E500_GPR_Bypass, E500_CR_Bypass]>,
+ InstrItinData<IIC_SprMTPMR, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
+ InstrStage<1, [E500_SFX0]>],
+ [4, 1], // Latency = 1, Repeat rate = 1
+ [E500_CR_Bypass, E500_GPR_Bypass]>,
InstrItinData<IIC_SprMFTB, [InstrStage<1, [E500_DIS0, E500_DIS1], 0>,
InstrStage<4, [E500_SFX0]>],
[7, 1], // Latency = 4, Repeat rate = 4
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCScheduleE5500.td b/contrib/llvm/lib/Target/PowerPC/PPCScheduleE5500.td
index 5db886c..32f8e65 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCScheduleE5500.td
+++ b/contrib/llvm/lib/Target/PowerPC/PPCScheduleE5500.td
@@ -313,20 +313,24 @@ def PPCE5500Itineraries : ProcessorItineraries<
InstrStage<5, [E5500_CFX_0]>],
[9, 2], // Latency = 5, Repeat rate = 5
[E5500_GPR_Bypass, E5500_CR_Bypass]>,
- InstrItinData<IIC_SprMFMSR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
- InstrStage<4, [E5500_SFX0]>],
+ InstrItinData<IIC_SprMFPMR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
+ InstrStage<4, [E5500_CFX_0]>],
[8, 2], // Latency = 4, Repeat rate = 4
[E5500_GPR_Bypass, E5500_GPR_Bypass]>,
InstrItinData<IIC_SprMFSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
InstrStage<1, [E5500_CFX_0]>],
[5], // Latency = 1, Repeat rate = 1
[E5500_GPR_Bypass]>,
+ InstrItinData<IIC_SprMTPMR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
+ InstrStage<1, [E5500_CFX_0]>],
+ [5], // Latency = 1, Repeat rate = 1
+ [E5500_GPR_Bypass]>,
InstrItinData<IIC_SprMFTB, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
InstrStage<4, [E5500_CFX_0]>],
[8, 2], // Latency = 4, Repeat rate = 4
[NoBypass, E5500_GPR_Bypass]>,
InstrItinData<IIC_SprMTSPR, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
- InstrStage<1, [E5500_SFX0, E5500_SFX1]>],
+ InstrStage<1, [E5500_CFX_0]>],
[5], // Latency = 1, Repeat rate = 1
[E5500_GPR_Bypass]>,
InstrItinData<IIC_FPGeneral, [InstrStage<1, [E5500_DIS0, E5500_DIS1], 0>,
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCScheduleP9.td b/contrib/llvm/lib/Target/PowerPC/PPCScheduleP9.td
new file mode 100644
index 0000000..a9c1bd7
--- /dev/null
+++ b/contrib/llvm/lib/Target/PowerPC/PPCScheduleP9.td
@@ -0,0 +1,335 @@
+//===-- PPCScheduleP9.td - PPC P9 Scheduling Definitions ---*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the itinerary class data for the POWER9 processor.
+//
+//===----------------------------------------------------------------------===//
+include "PPCInstrInfo.td"
+
+def P9Model : SchedMachineModel {
+ let IssueWidth = 8;
+
+ let LoadLatency = 5;
+
+ let MispredictPenalty = 16;
+
+ // Try to make sure we have at least 10 dispatch groups in a loop.
+ let LoopMicroOpBufferSize = 60;
+
+ let CompleteModel = 0;
+
+}
+
+let SchedModel = P9Model in {
+
+ // ***************** Processor Resources *****************
+
+ //Dispatcher:
+ def DISPATCHER : ProcResource<12>;
+
+ // Issue Ports
+ def IP_AGEN : ProcResource<4>;
+ def IP_EXEC : ProcResource<4>;
+ def IP_EXECE : ProcResource<2> {
+ //Even Exec Ports
+ let Super = IP_EXEC;
+ }
+ def IP_EXECO : ProcResource<2> {
+ //Odd Exec Ports
+ let Super = IP_EXEC;
+ }
+
+ // Pipeline Groups
+ def ALU : ProcResource<4>;
+ def ALUE : ProcResource<2> {
+ //Even ALU pipelines
+ let Super = ALU;
+ }
+ def ALUO : ProcResource<2> {
+ //Odd ALU pipelines
+ let Super = ALU;
+ }
+ def DIV : ProcResource<2>;
+ def DP : ProcResource<4>;
+ def DPE : ProcResource<2> {
+ //Even DP pipelines
+ let Super = DP;
+ }
+ def DPO : ProcResource<2> {
+ //Odd DP pipelines
+ let Super = DP;
+ }
+ def LS : ProcResource<4>;
+ def PM : ProcResource<2>;
+ def DFU : ProcResource<1>;
+
+ def TestGroup : ProcResGroup<[ALU, DP]>;
+
+ // ***************** SchedWriteRes Definitions *****************
+
+ //Dispatcher
+ def DISP_1C : SchedWriteRes<[DISPATCHER]> {
+ let NumMicroOps = 0;
+ let Latency = 1;
+ }
+
+ // Issue Ports
+ def IP_AGEN_1C : SchedWriteRes<[IP_AGEN]> {
+ let NumMicroOps = 0;
+ let Latency = 1;
+ }
+
+ def IP_EXEC_1C : SchedWriteRes<[IP_EXEC]> {
+ let NumMicroOps = 0;
+ let Latency = 1;
+ }
+
+ def IP_EXECE_1C : SchedWriteRes<[IP_EXECE]> {
+ let NumMicroOps = 0;
+ let Latency = 1;
+ }
+
+ def IP_EXECO_1C : SchedWriteRes<[IP_EXECO]> {
+ let NumMicroOps = 0;
+ let Latency = 1;
+ }
+
+ //Pipeline Groups
+ def P9_ALU_2C : SchedWriteRes<[ALU]> {
+ let Latency = 2;
+ }
+
+ def P9_ALUE_2C : SchedWriteRes<[ALUE]> {
+ let Latency = 2;
+ }
+
+ def P9_ALUO_2C : SchedWriteRes<[ALUO]> {
+ let Latency = 2;
+ }
+
+ def P9_ALU_3C : SchedWriteRes<[ALU]> {
+ let Latency = 3;
+ }
+
+ def P9_ALUE_3C : SchedWriteRes<[ALUE]> {
+ let Latency = 3;
+ }
+
+ def P9_ALUO_3C : SchedWriteRes<[ALUO]> {
+ let Latency = 3;
+ }
+
+ def P9_ALU_4C : SchedWriteRes<[ALU]> {
+ let Latency = 4;
+ }
+
+ def P9_ALUE_4C : SchedWriteRes<[ALUE]> {
+ let Latency = 4;
+ }
+
+ def P9_ALUO_4C : SchedWriteRes<[ALUO]> {
+ let Latency = 4;
+ }
+
+ def P9_ALU_5C : SchedWriteRes<[ALU]> {
+ let Latency = 5;
+ }
+
+ def P9_ALU_6C : SchedWriteRes<[ALU]> {
+ let Latency = 6;
+ }
+
+ def P9_DIV_16C_8 : SchedWriteRes<[DIV]> {
+ let ResourceCycles = [8];
+ let Latency = 16;
+ }
+
+ def P9_DIV_24C_8 : SchedWriteRes<[DIV]> {
+ let ResourceCycles = [8];
+ let Latency = 24;
+ }
+
+ def P9_DIV_40C_8 : SchedWriteRes<[DIV]> {
+ let ResourceCycles = [8];
+ let Latency = 40;
+ }
+
+ def P9_DP_2C : SchedWriteRes<[DP]> {
+ let Latency = 2;
+ }
+
+ def P9_DP_5C : SchedWriteRes<[DP]> {
+ let Latency = 5;
+ }
+
+ def P9_DP_7C : SchedWriteRes<[DP]> {
+ let Latency = 7;
+ }
+
+ def P9_DPE_7C : SchedWriteRes<[DPE]> {
+ let Latency = 7;
+ }
+
+ def P9_DPO_7C : SchedWriteRes<[DPO]> {
+ let Latency = 7;
+ }
+
+ def P9_DP_22C_5 : SchedWriteRes<[DP]> {
+ let ResourceCycles = [5];
+ let Latency = 22;
+ }
+
+ def P9_DP_24C_8 : SchedWriteRes<[DP]> {
+ let ResourceCycles = [8];
+ let Latency = 24;
+ }
+
+ def P9_DP_26C_5 : SchedWriteRes<[DP]> {
+ let ResourceCycles = [5];
+ let Latency = 22;
+ }
+
+ def P9_DP_27C_7 : SchedWriteRes<[DP]> {
+ let ResourceCycles = [7];
+ let Latency = 27;
+ }
+
+ def P9_DP_33C_8 : SchedWriteRes<[DP]> {
+ let ResourceCycles = [8];
+ let Latency = 33;
+ }
+
+ def P9_DP_36C_10 : SchedWriteRes<[DP]> {
+ let ResourceCycles = [10];
+ let Latency = 36;
+ }
+
+ def P9_PM_3C : SchedWriteRes<[PM]> {
+ let Latency = 3;
+ }
+
+ def P9_PM_7C : SchedWriteRes<[PM]> {
+ let Latency = 3;
+ }
+
+ def P9_LS_1C : SchedWriteRes<[LS]> {
+ let Latency = 1;
+ }
+
+ def P9_LS_4C : SchedWriteRes<[LS]> {
+ let Latency = 4;
+ }
+
+ def P9_LS_5C : SchedWriteRes<[LS]> {
+ let Latency = 5;
+ }
+
+ def P9_DFU_12C : SchedWriteRes<[DFU]> {
+ let Latency = 12;
+ }
+
+ def P9_DFU_24C : SchedWriteRes<[DFU]> {
+ let Latency = 24;
+ let ResourceCycles = [12];
+ }
+
+ def P9_DFU_58C : SchedWriteRes<[DFU]> {
+ let Latency = 58;
+ let ResourceCycles = [44];
+ }
+
+ def P9_DFU_76C : SchedWriteRes<[TestGroup, DFU]> {
+ let Latency = 76;
+ let ResourceCycles = [62];
+ }
+ // ***************** WriteSeq Definitions *****************
+
+ def P9_LoadAndALUOp_6C : WriteSequence<[P9_LS_4C, P9_ALU_2C]>;
+ def P9_LoadAndALUOp_7C : WriteSequence<[P9_LS_5C, P9_ALU_2C]>;
+ def P9_LoadAndPMOp_8C : WriteSequence<[P9_LS_5C, P9_PM_3C]>;
+ def P9_IntDivAndALUOp_26C_8 : WriteSequence<[P9_DIV_24C_8, P9_ALU_2C]>;
+ def P9_IntDivAndALUOp_42C_8 : WriteSequence<[P9_DIV_40C_8, P9_ALU_2C]>;
+ def P9_StoreAndALUOp_4C : WriteSequence<[P9_LS_1C, P9_ALU_3C]>;
+ def P9_ALUOpAndALUOp_4C : WriteSequence<[P9_ALU_2C, P9_ALU_2C]>;
+
+ // ***************** Defining Itinerary Class Resources *****************
+
+ def : ItinRW<[P9_DFU_76C, IP_EXEC_1C, DISP_1C, DISP_1C], [IIC_IntSimple,
+ IIC_IntGeneral]>;
+
+ def : ItinRW<[P9_ALU_2C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_IntISEL, IIC_IntRotate, IIC_IntShift]>;
+
+ def : ItinRW<[P9_ALU_2C, IP_EXEC_1C, DISP_1C, DISP_1C], [IIC_IntCompare]>;
+
+ def : ItinRW<[P9_DP_5C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_IntMulHW, IIC_IntMulHWU, IIC_IntMulLI]>;
+
+ def : ItinRW<[P9_LS_5C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ [IIC_LdStLoad, IIC_LdStLD]>;
+
+ def : ItinRW<[P9_LS_4C, P9_ALU_2C, IP_EXEC_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStLoadUpd, IIC_LdStLDU]>;
+
+ def : ItinRW<[P9_LS_4C, P9_ALU_2C, IP_EXECE_1C, IP_EXECO_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStLoadUpdX, IIC_LdStLDUX]>;
+
+ def : ItinRW<[P9_LS_1C, P9_ALU_2C, IP_EXEC_1C, IP_EXEC_1C, IP_AGEN_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStSTFDU]>;
+
+ def : ItinRW<[P9_LoadAndALUOp_6C,
+ IP_AGEN_1C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStLHA, IIC_LdStLWA]>;
+
+ def : ItinRW<[P9_LoadAndALUOp_6C, P9_ALU_2C,
+ IP_AGEN_1C, IP_EXEC_1C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStLHAU, IIC_LdStLHAUX]>;
+
+ // IIC_LdStLMW contains two microcoded insns. This is not accurate, but
+ // those insns are not used that much, if at all.
+ def : ItinRW<[P9_LS_4C, IP_EXEC_1C, DISP_1C, DISP_1C],
+ [IIC_LdStLWARX, IIC_LdStLDARX, IIC_LdStLMW]>;
+
+ def : ItinRW<[P9_LS_1C, IP_EXEC_1C, IP_AGEN_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStSTFD, IIC_LdStSTD, IIC_LdStStore]>;
+
+ def : ItinRW<[P9_LS_1C, P9_ALU_2C, IP_EXEC_1C, IP_EXEC_1C, IP_AGEN_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStSTDU, IIC_LdStSTDUX]>;
+
+ def : ItinRW<[P9_StoreAndALUOp_4C, IP_EXEC_1C, IP_EXEC_1C, IP_AGEN_1C,
+ DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_LdStSTDCX, IIC_LdStSTWCX]>;
+
+ def : ItinRW<[P9_ALU_5C, IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C],
+ [IIC_BrCR, IIC_IntMTFSB0]>;
+
+ def : ItinRW<[P9_ALUOpAndALUOp_4C, P9_ALU_2C, IP_EXEC_1C, IP_EXEC_1C,
+ IP_EXEC_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C, DISP_1C,
+ DISP_1C, DISP_1C, DISP_1C], [IIC_SprMFCR, IIC_SprMFCRF]>;
+
+ // This class should be broken down to instruction level, once some missing
+ // info is obtained.
+ def : ItinRW<[P9_LoadAndALUOp_6C, IP_EXEC_1C, IP_AGEN_1C,
+ DISP_1C, DISP_1C, DISP_1C], [IIC_SprMTSPR]>;
+
+ def : ItinRW<[P9_DP_7C, IP_EXEC_1C,
+ DISP_1C, DISP_1C, DISP_1C], [IIC_FPGeneral, IIC_FPAddSub]>;
+
+ def : ItinRW<[P9_DP_36C_10, IP_EXEC_1C], [IIC_FPSqrtD]>;
+ def : ItinRW<[P9_DP_26C_5, P9_DP_26C_5, IP_EXEC_1C, IP_EXEC_1C], [IIC_FPSqrtS]>;
+
+ include "P9InstrResources.td"
+
+}
+
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.h b/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.h
index 46da840..7fd9079 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.h
+++ b/contrib/llvm/lib/Target/PowerPC/PPCSubtarget.h
@@ -277,6 +277,9 @@ public:
bool hasFloat128() const { return HasFloat128; }
bool isISA3_0() const { return IsISA3_0; }
bool useLongCalls() const { return UseLongCalls; }
+ bool needsSwapsForVSXMemOps() const {
+ return hasVSX() && isLittleEndian() && !hasP9Vector();
+ }
POPCNTDKind hasPOPCNTD() const { return HasPOPCNTD; }
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp b/contrib/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp
index 61ce48e..0c1260a 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCTLSDynamicCall.cpp
@@ -56,26 +56,26 @@ protected:
for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end();
I != IE;) {
- MachineInstr *MI = I;
+ MachineInstr &MI = *I;
- if (MI->getOpcode() != PPC::ADDItlsgdLADDR &&
- MI->getOpcode() != PPC::ADDItlsldLADDR &&
- MI->getOpcode() != PPC::ADDItlsgdLADDR32 &&
- MI->getOpcode() != PPC::ADDItlsldLADDR32) {
+ if (MI.getOpcode() != PPC::ADDItlsgdLADDR &&
+ MI.getOpcode() != PPC::ADDItlsldLADDR &&
+ MI.getOpcode() != PPC::ADDItlsgdLADDR32 &&
+ MI.getOpcode() != PPC::ADDItlsldLADDR32) {
++I;
continue;
}
- DEBUG(dbgs() << "TLS Dynamic Call Fixup:\n " << *MI;);
+ DEBUG(dbgs() << "TLS Dynamic Call Fixup:\n " << MI);
- unsigned OutReg = MI->getOperand(0).getReg();
- unsigned InReg = MI->getOperand(1).getReg();
- DebugLoc DL = MI->getDebugLoc();
+ unsigned OutReg = MI.getOperand(0).getReg();
+ unsigned InReg = MI.getOperand(1).getReg();
+ DebugLoc DL = MI.getDebugLoc();
unsigned GPR3 = Is64Bit ? PPC::X3 : PPC::R3;
unsigned Opc1, Opc2;
const unsigned OrigRegs[] = {OutReg, InReg, GPR3};
- switch (MI->getOpcode()) {
+ switch (MI.getOpcode()) {
default:
llvm_unreachable("Opcode inconsistency error");
case PPC::ADDItlsgdLADDR:
@@ -104,7 +104,7 @@ protected:
// Expand into two ops built prior to the existing instruction.
MachineInstr *Addi = BuildMI(MBB, I, DL, TII->get(Opc1), GPR3)
.addReg(InReg);
- Addi->addOperand(MI->getOperand(2));
+ Addi->addOperand(MI.getOperand(2));
// The ADDItls* instruction is the first instruction in the
// repair range.
@@ -113,7 +113,7 @@ protected:
MachineInstr *Call = (BuildMI(MBB, I, DL, TII->get(Opc2), GPR3)
.addReg(GPR3));
- Call->addOperand(MI->getOperand(3));
+ Call->addOperand(MI.getOperand(3));
BuildMI(MBB, I, DL, TII->get(PPC::ADJCALLSTACKUP)).addImm(0).addImm(0);
@@ -126,7 +126,7 @@ protected:
// Move past the original instruction and remove it.
++I;
- MI->removeFromParent();
+ MI.removeFromParent();
// Repair the live intervals.
LIS->repairIntervalsInRange(&MBB, First, Last, OrigRegs);
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
index 1bb6b67..91b1d24 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -74,9 +74,9 @@ EnableMachineCombinerPass("ppc-machine-combiner",
extern "C" void LLVMInitializePowerPCTarget() {
// Register the targets
- RegisterTargetMachine<PPC32TargetMachine> A(ThePPC32Target);
- RegisterTargetMachine<PPC64TargetMachine> B(ThePPC64Target);
- RegisterTargetMachine<PPC64TargetMachine> C(ThePPC64LETarget);
+ RegisterTargetMachine<PPC32TargetMachine> A(getThePPC32Target());
+ RegisterTargetMachine<PPC64TargetMachine> B(getThePPC64Target());
+ RegisterTargetMachine<PPC64TargetMachine> C(getThePPC64LETarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
initializePPCBoolRetToIntPass(PR);
@@ -181,6 +181,10 @@ static PPCTargetMachine::PPCABI computeTargetABI(const Triple &TT,
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
Optional<Reloc::Model> RM) {
if (!RM.hasValue()) {
+ if (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le) {
+ if (!TT.isOSBinFormatMachO() && !TT.isMacOSX())
+ return Reloc::PIC_;
+ }
if (TT.isOSDarwin())
return Reloc::DynamicNoPIC;
return Reloc::Static;
@@ -204,23 +208,6 @@ PPCTargetMachine::PPCTargetMachine(const Target &T, const Triple &TT,
TargetABI(computeTargetABI(TT, Options)),
Subtarget(TargetTriple, CPU, computeFSAdditions(FS, OL, TT), *this) {
- // For the estimates, convergence is quadratic, so we essentially double the
- // number of digits correct after every iteration. For both FRE and FRSQRTE,
- // the minimum architected relative accuracy is 2^-5. When hasRecipPrec(),
- // this is 2^-14. IEEE float has 23 digits and double has 52 digits.
- unsigned RefinementSteps = Subtarget.hasRecipPrec() ? 1 : 3,
- RefinementSteps64 = RefinementSteps + 1;
-
- this->Options.Reciprocals.setDefaults("sqrtf", true, RefinementSteps);
- this->Options.Reciprocals.setDefaults("vec-sqrtf", true, RefinementSteps);
- this->Options.Reciprocals.setDefaults("divf", true, RefinementSteps);
- this->Options.Reciprocals.setDefaults("vec-divf", true, RefinementSteps);
-
- this->Options.Reciprocals.setDefaults("sqrtd", true, RefinementSteps64);
- this->Options.Reciprocals.setDefaults("vec-sqrtd", true, RefinementSteps64);
- this->Options.Reciprocals.setDefaults("divd", true, RefinementSteps64);
- this->Options.Reciprocals.setDefaults("vec-divd", true, RefinementSteps64);
-
initAsmInfo();
}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.cpp b/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.cpp
index 8f66035..a049dc3 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.cpp
@@ -23,8 +23,7 @@ Initialize(MCContext &Ctx, const TargetMachine &TM) {
}
MCSection *PPC64LinuxTargetObjectFile::SelectSectionForGlobal(
- const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
// Here override ReadOnlySection to DataRelROSection for PPC64 SVR4 ABI
// when we have a constant that contains global relocations. This is
// necessary because of this ABI's handling of pointers to functions in
@@ -40,14 +39,13 @@ MCSection *PPC64LinuxTargetObjectFile::SelectSectionForGlobal(
// For more information, see the description of ELIMINATE_COPY_RELOCS in
// GNU ld.
if (Kind.isReadOnly()) {
- const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
+ const auto *GVar = dyn_cast<GlobalVariable>(GO);
if (GVar && GVar->isConstant() && GVar->getInitializer()->needsRelocation())
Kind = SectionKind::getReadOnlyWithRel();
}
- return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind,
- Mang, TM);
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
}
const MCExpr *PPC64LinuxTargetObjectFile::
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.h b/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.h
index d248791..c8b9b2e 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetObjectFile.h
@@ -22,8 +22,7 @@ namespace llvm {
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
/// \brief Describe a TLS variable address within debug info.
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp b/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp
index 9331e41..f94d1ea 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp
@@ -131,12 +131,12 @@ int PPCTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
return TTI::TCC_Free;
case Instruction::And:
RunFree = true; // (for the rotate-and-mask instructions)
- // Fallthrough...
+ LLVM_FALLTHROUGH;
case Instruction::Add:
case Instruction::Or:
case Instruction::Xor:
ShiftedFree = true;
- // Fallthrough...
+ LLVM_FALLTHROUGH;
case Instruction::Sub:
case Instruction::Mul:
case Instruction::Shl:
@@ -147,7 +147,8 @@ int PPCTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
case Instruction::ICmp:
UnsignedFree = true;
ImmIdx = 1;
- // Fallthrough... (zero comparisons can use record-form instructions)
+ // Zero comparisons can use record-form instructions.
+ LLVM_FALLTHROUGH;
case Instruction::Select:
ZeroFree = true;
break;
@@ -280,7 +281,7 @@ unsigned PPCTTIImpl::getMaxInterleaveFactor(unsigned VF) {
int PPCTTIImpl::getArithmeticInstrCost(
unsigned Opcode, Type *Ty, TTI::OperandValueKind Op1Info,
TTI::OperandValueKind Op2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ TTI::OperandValueProperties Opd2PropInfo, ArrayRef<const Value *> Args) {
assert(TLI->InstructionOpcodeToISD(Opcode) && "Invalid opcode");
// Fallback to the default implementation.
@@ -359,11 +360,6 @@ int PPCTTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
int Cost = BaseT::getMemoryOpCost(Opcode, Src, Alignment, AddressSpace);
- // Aligned loads and stores are easy.
- unsigned SrcBytes = LT.second.getStoreSize();
- if (!SrcBytes || !Alignment || Alignment >= SrcBytes)
- return Cost;
-
bool IsAltivecType = ST->hasAltivec() &&
(LT.second == MVT::v16i8 || LT.second == MVT::v8i16 ||
LT.second == MVT::v4i32 || LT.second == MVT::v4f32);
@@ -372,6 +368,20 @@ int PPCTTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
bool IsQPXType = ST->hasQPX() &&
(LT.second == MVT::v4f64 || LT.second == MVT::v4f32);
+ // VSX has 32b/64b load instructions. Legalization can handle loading of
+ // 32b/64b to VSR correctly and cheaply. But BaseT::getMemoryOpCost and
+ // PPCTargetLowering can't compute the cost appropriately. So here we
+ // explicitly check this case.
+ unsigned MemBytes = Src->getPrimitiveSizeInBits();
+ if (Opcode == Instruction::Load && ST->hasVSX() && IsAltivecType &&
+ (MemBytes == 64 || (ST->hasP8Vector() && MemBytes == 32)))
+ return 1;
+
+ // Aligned loads and stores are easy.
+ unsigned SrcBytes = LT.second.getStoreSize();
+ if (!SrcBytes || !Alignment || Alignment >= SrcBytes)
+ return Cost;
+
// If we can use the permutation-based load sequence, then this is also
// relatively cheap (not counting loop-invariant instructions): one load plus
// one permute (the last load in a series has extra cost, but we're
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h b/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h
index 5ea9a54..30ee281 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h
@@ -41,13 +41,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- PPCTTIImpl(const PPCTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- PPCTTIImpl(PPCTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
/// \name Scalar TTI Implementations
/// @{
@@ -78,7 +71,8 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
int getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index, Type *SubTp);
int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src);
int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy);
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCVSXCopy.cpp b/contrib/llvm/lib/Target/PowerPC/PPCVSXCopy.cpp
index 60f1ad5..3b5d8f0 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCVSXCopy.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCVSXCopy.cpp
@@ -89,37 +89,31 @@ protected:
bool Changed = false;
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
- for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end();
- I != IE; ++I) {
- MachineInstr *MI = I;
- if (!MI->isFullCopy())
+ for (MachineInstr &MI : MBB) {
+ if (!MI.isFullCopy())
continue;
- MachineOperand &DstMO = MI->getOperand(0);
- MachineOperand &SrcMO = MI->getOperand(1);
+ MachineOperand &DstMO = MI.getOperand(0);
+ MachineOperand &SrcMO = MI.getOperand(1);
if ( IsVSReg(DstMO.getReg(), MRI) &&
!IsVSReg(SrcMO.getReg(), MRI)) {
// This is a copy *to* a VSX register from a non-VSX register.
Changed = true;
- const TargetRegisterClass *SrcRC =
- IsVRReg(SrcMO.getReg(), MRI) ? &PPC::VSHRCRegClass :
- &PPC::VSLRCRegClass;
+ const TargetRegisterClass *SrcRC = &PPC::VSLRCRegClass;
assert((IsF8Reg(SrcMO.getReg(), MRI) ||
- IsVRReg(SrcMO.getReg(), MRI) ||
IsVSSReg(SrcMO.getReg(), MRI) ||
IsVSFReg(SrcMO.getReg(), MRI)) &&
"Unknown source for a VSX copy");
unsigned NewVReg = MRI.createVirtualRegister(SrcRC);
- BuildMI(MBB, MI, MI->getDebugLoc(),
+ BuildMI(MBB, MI, MI.getDebugLoc(),
TII->get(TargetOpcode::SUBREG_TO_REG), NewVReg)
- .addImm(1) // add 1, not 0, because there is no implicit clearing
- // of the high bits.
- .addOperand(SrcMO)
- .addImm(IsVRReg(SrcMO.getReg(), MRI) ? PPC::sub_128 :
- PPC::sub_64);
+ .addImm(1) // add 1, not 0, because there is no implicit clearing
+ // of the high bits.
+ .addOperand(SrcMO)
+ .addImm(PPC::sub_64);
// The source of the original copy is now the new virtual register.
SrcMO.setReg(NewVReg);
@@ -128,25 +122,21 @@ protected:
// This is a copy *from* a VSX register to a non-VSX register.
Changed = true;
- const TargetRegisterClass *DstRC =
- IsVRReg(DstMO.getReg(), MRI) ? &PPC::VSHRCRegClass :
- &PPC::VSLRCRegClass;
+ const TargetRegisterClass *DstRC = &PPC::VSLRCRegClass;
assert((IsF8Reg(DstMO.getReg(), MRI) ||
IsVSFReg(DstMO.getReg(), MRI) ||
- IsVSSReg(DstMO.getReg(), MRI) ||
- IsVRReg(DstMO.getReg(), MRI)) &&
+ IsVSSReg(DstMO.getReg(), MRI)) &&
"Unknown destination for a VSX copy");
// Copy the VSX value into a new VSX register of the correct subclass.
unsigned NewVReg = MRI.createVirtualRegister(DstRC);
- BuildMI(MBB, MI, MI->getDebugLoc(),
- TII->get(TargetOpcode::COPY), NewVReg)
- .addOperand(SrcMO);
+ BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(TargetOpcode::COPY),
+ NewVReg)
+ .addOperand(SrcMO);
// Transform the original copy into a subregister extraction copy.
SrcMO.setReg(NewVReg);
- SrcMO.setSubReg(IsVRReg(DstMO.getReg(), MRI) ? PPC::sub_128 :
- PPC::sub_64);
+ SrcMO.setSubReg(PPC::sub_64);
}
}
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCVSXFMAMutate.cpp b/contrib/llvm/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
index 7c22cb2..f6d20ce 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCVSXFMAMutate.cpp
@@ -21,6 +21,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -74,7 +75,7 @@ protected:
const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end();
I != IE; ++I) {
- MachineInstr *MI = I;
+ MachineInstr &MI = *I;
// The default (A-type) VSX FMA form kills the addend (it is taken from
// the target register, which is then updated to reflect the result of
@@ -82,7 +83,7 @@ protected:
// used for the product, then we can use the M-form instruction (which
// will take that value from the to-be-defined register).
- int AltOpc = PPC::getAltVSXFMAOpcode(MI->getOpcode());
+ int AltOpc = PPC::getAltVSXFMAOpcode(MI.getOpcode());
if (AltOpc == -1)
continue;
@@ -105,10 +106,10 @@ protected:
// %RM<imp-use>; VSLRC:%vreg16,%vreg18,%vreg9
// and we remove: %vreg5<def> = COPY %vreg9; VSLRC:%vreg5,%vreg9
- SlotIndex FMAIdx = LIS->getInstructionIndex(*MI);
+ SlotIndex FMAIdx = LIS->getInstructionIndex(MI);
VNInfo *AddendValNo =
- LIS->getInterval(MI->getOperand(1).getReg()).Query(FMAIdx).valueIn();
+ LIS->getInterval(MI.getOperand(1).getReg()).Query(FMAIdx).valueIn();
// This can be null if the register is undef.
if (!AddendValNo)
@@ -118,7 +119,7 @@ protected:
// The addend and this instruction must be in the same block.
- if (!AddendMI || AddendMI->getParent() != MI->getParent())
+ if (!AddendMI || AddendMI->getParent() != MI.getParent())
continue;
// The addend must be a full copy within the same register class.
@@ -182,12 +183,12 @@ protected:
// %vreg5 = A-form-op %vreg5, %vreg5, %vreg11;
// where vreg5 and vreg11 are both kills. This case would be skipped
// otherwise.
- unsigned OldFMAReg = MI->getOperand(0).getReg();
+ unsigned OldFMAReg = MI.getOperand(0).getReg();
// Find one of the product operands that is killed by this instruction.
unsigned KilledProdOp = 0, OtherProdOp = 0;
- unsigned Reg2 = MI->getOperand(2).getReg();
- unsigned Reg3 = MI->getOperand(3).getReg();
+ unsigned Reg2 = MI.getOperand(2).getReg();
+ unsigned Reg3 = MI.getOperand(3).getReg();
if (LIS->getInterval(Reg2).Query(FMAIdx).isKill()
&& Reg2 != OldFMAReg) {
KilledProdOp = 2;
@@ -214,20 +215,20 @@ protected:
// Transform: (O2 * O3) + O1 -> (O2 * O1) + O3.
- unsigned KilledProdReg = MI->getOperand(KilledProdOp).getReg();
- unsigned OtherProdReg = MI->getOperand(OtherProdOp).getReg();
+ unsigned KilledProdReg = MI.getOperand(KilledProdOp).getReg();
+ unsigned OtherProdReg = MI.getOperand(OtherProdOp).getReg();
unsigned AddSubReg = AddendMI->getOperand(1).getSubReg();
- unsigned KilledProdSubReg = MI->getOperand(KilledProdOp).getSubReg();
- unsigned OtherProdSubReg = MI->getOperand(OtherProdOp).getSubReg();
+ unsigned KilledProdSubReg = MI.getOperand(KilledProdOp).getSubReg();
+ unsigned OtherProdSubReg = MI.getOperand(OtherProdOp).getSubReg();
bool AddRegKill = AddendMI->getOperand(1).isKill();
- bool KilledProdRegKill = MI->getOperand(KilledProdOp).isKill();
- bool OtherProdRegKill = MI->getOperand(OtherProdOp).isKill();
+ bool KilledProdRegKill = MI.getOperand(KilledProdOp).isKill();
+ bool OtherProdRegKill = MI.getOperand(OtherProdOp).isKill();
bool AddRegUndef = AddendMI->getOperand(1).isUndef();
- bool KilledProdRegUndef = MI->getOperand(KilledProdOp).isUndef();
- bool OtherProdRegUndef = MI->getOperand(OtherProdOp).isUndef();
+ bool KilledProdRegUndef = MI.getOperand(KilledProdOp).isUndef();
+ bool OtherProdRegUndef = MI.getOperand(OtherProdOp).isUndef();
// If there isn't a class that fits, we can't perform the transform.
// This is needed for correctness with a mixture of VSX and Altivec
@@ -240,39 +241,39 @@ protected:
assert(OldFMAReg == AddendMI->getOperand(0).getReg() &&
"Addend copy not tied to old FMA output!");
- DEBUG(dbgs() << "VSX FMA Mutation:\n " << *MI;);
+ DEBUG(dbgs() << "VSX FMA Mutation:\n " << MI);
- MI->getOperand(0).setReg(KilledProdReg);
- MI->getOperand(1).setReg(KilledProdReg);
- MI->getOperand(3).setReg(AddendSrcReg);
+ MI.getOperand(0).setReg(KilledProdReg);
+ MI.getOperand(1).setReg(KilledProdReg);
+ MI.getOperand(3).setReg(AddendSrcReg);
- MI->getOperand(0).setSubReg(KilledProdSubReg);
- MI->getOperand(1).setSubReg(KilledProdSubReg);
- MI->getOperand(3).setSubReg(AddSubReg);
+ MI.getOperand(0).setSubReg(KilledProdSubReg);
+ MI.getOperand(1).setSubReg(KilledProdSubReg);
+ MI.getOperand(3).setSubReg(AddSubReg);
- MI->getOperand(1).setIsKill(KilledProdRegKill);
- MI->getOperand(3).setIsKill(AddRegKill);
+ MI.getOperand(1).setIsKill(KilledProdRegKill);
+ MI.getOperand(3).setIsKill(AddRegKill);
- MI->getOperand(1).setIsUndef(KilledProdRegUndef);
- MI->getOperand(3).setIsUndef(AddRegUndef);
+ MI.getOperand(1).setIsUndef(KilledProdRegUndef);
+ MI.getOperand(3).setIsUndef(AddRegUndef);
- MI->setDesc(TII->get(AltOpc));
+ MI.setDesc(TII->get(AltOpc));
// If the addend is also a multiplicand, replace it with the addend
// source in both places.
if (OtherProdReg == AddendMI->getOperand(0).getReg()) {
- MI->getOperand(2).setReg(AddendSrcReg);
- MI->getOperand(2).setSubReg(AddSubReg);
- MI->getOperand(2).setIsKill(AddRegKill);
- MI->getOperand(2).setIsUndef(AddRegUndef);
+ MI.getOperand(2).setReg(AddendSrcReg);
+ MI.getOperand(2).setSubReg(AddSubReg);
+ MI.getOperand(2).setIsKill(AddRegKill);
+ MI.getOperand(2).setIsUndef(AddRegUndef);
} else {
- MI->getOperand(2).setReg(OtherProdReg);
- MI->getOperand(2).setSubReg(OtherProdSubReg);
- MI->getOperand(2).setIsKill(OtherProdRegKill);
- MI->getOperand(2).setIsUndef(OtherProdRegUndef);
+ MI.getOperand(2).setReg(OtherProdReg);
+ MI.getOperand(2).setSubReg(OtherProdSubReg);
+ MI.getOperand(2).setIsKill(OtherProdRegKill);
+ MI.getOperand(2).setIsUndef(OtherProdRegUndef);
}
- DEBUG(dbgs() << " -> " << *MI);
+ DEBUG(dbgs() << " -> " << MI);
// The killed product operand was killed here, so we can reuse it now
// for the result of the fma.
@@ -374,6 +375,8 @@ public:
AU.addPreserved<LiveIntervals>();
AU.addRequired<SlotIndexes>();
AU.addPreserved<SlotIndexes>();
+ AU.addRequired<MachineDominatorTree>();
+ AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
};
@@ -383,6 +386,7 @@ INITIALIZE_PASS_BEGIN(PPCVSXFMAMutate, DEBUG_TYPE,
"PowerPC VSX FMA Mutation", false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
+INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_END(PPCVSXFMAMutate, DEBUG_TYPE,
"PowerPC VSX FMA Mutation", false, false)
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCVSXSwapRemoval.cpp b/contrib/llvm/lib/Target/PowerPC/PPCVSXSwapRemoval.cpp
index d53c8e3..8197285 100644
--- a/contrib/llvm/lib/Target/PowerPC/PPCVSXSwapRemoval.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/PPCVSXSwapRemoval.cpp
@@ -962,7 +962,8 @@ void PPCVSXSwapRemoval::dumpSwapVector() {
DEBUG(dbgs() << format("%6d", ID));
DEBUG(dbgs() << format("%6d", EC->getLeaderValue(ID)));
DEBUG(dbgs() << format(" BB#%3d", MI->getParent()->getNumber()));
- DEBUG(dbgs() << format(" %14s ", TII->getName(MI->getOpcode())));
+ DEBUG(dbgs() << format(" %14s ",
+ TII->getName(MI->getOpcode()).str().c_str()));
if (SwapVector[EntryIdx].IsLoad)
DEBUG(dbgs() << "load ");
diff --git a/contrib/llvm/lib/Target/PowerPC/TargetInfo/PowerPCTargetInfo.cpp b/contrib/llvm/lib/Target/PowerPC/TargetInfo/PowerPCTargetInfo.cpp
index 5b2fe19..a637dd1 100644
--- a/contrib/llvm/lib/Target/PowerPC/TargetInfo/PowerPCTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/PowerPC/TargetInfo/PowerPCTargetInfo.cpp
@@ -12,15 +12,26 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::ThePPC32Target, llvm::ThePPC64Target, llvm::ThePPC64LETarget;
+Target &llvm::getThePPC32Target() {
+ static Target ThePPC32Target;
+ return ThePPC32Target;
+}
+Target &llvm::getThePPC64Target() {
+ static Target ThePPC64Target;
+ return ThePPC64Target;
+}
+Target &llvm::getThePPC64LETarget() {
+ static Target ThePPC64LETarget;
+ return ThePPC64LETarget;
+}
extern "C" void LLVMInitializePowerPCTargetInfo() {
- RegisterTarget<Triple::ppc, /*HasJIT=*/true>
- X(ThePPC32Target, "ppc32", "PowerPC 32");
+ RegisterTarget<Triple::ppc, /*HasJIT=*/true> X(getThePPC32Target(), "ppc32",
+ "PowerPC 32");
- RegisterTarget<Triple::ppc64, /*HasJIT=*/true>
- Y(ThePPC64Target, "ppc64", "PowerPC 64");
+ RegisterTarget<Triple::ppc64, /*HasJIT=*/true> Y(getThePPC64Target(), "ppc64",
+ "PowerPC 64");
- RegisterTarget<Triple::ppc64le, /*HasJIT=*/true>
- Z(ThePPC64LETarget, "ppc64le", "PowerPC 64 LE");
+ RegisterTarget<Triple::ppc64le, /*HasJIT=*/true> Z(
+ getThePPC64LETarget(), "ppc64le", "PowerPC 64 LE");
}
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
new file mode 100644
index 0000000..f8ef142
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -0,0 +1,91 @@
+//===-- RISCVAsmBackend.cpp - RISCV Assembler Backend ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+class RISCVAsmBackend : public MCAsmBackend {
+ uint8_t OSABI;
+ bool Is64Bit;
+
+public:
+ RISCVAsmBackend(uint8_t OSABI, bool Is64Bit)
+ : MCAsmBackend(), OSABI(OSABI), Is64Bit(Is64Bit) {}
+ ~RISCVAsmBackend() override {}
+
+ void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
+ uint64_t Value, bool IsPCRel) const override;
+
+ MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
+
+ bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override {
+ return false;
+ }
+
+ unsigned getNumFixupKinds() const override { return 1; }
+
+ bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
+
+ void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
+ MCInst &Res) const override {
+
+ llvm_unreachable("RISCVAsmBackend::relaxInstruction() unimplemented");
+ }
+
+ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
+};
+
+bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
+ // Once support for the compressed instruction set is added, we will be able
+ // to conditionally support 16-bit NOPs
+ if ((Count % 4) != 0)
+ return false;
+
+ // The canonical nop on RISC-V is addi x0, x0, 0
+ for (uint64_t i = 0; i < Count; i += 4)
+ OW->write32(0x13);
+
+ return true;
+}
+
+void RISCVAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
+ unsigned DataSize, uint64_t Value,
+ bool IsPCRel) const {
+ return;
+}
+
+MCObjectWriter *
+RISCVAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
+ return createRISCVELFObjectWriter(OS, OSABI, Is64Bit);
+}
+
+} // end anonymous namespace
+
+MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
+ const MCRegisterInfo &MRI,
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
+ uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
+ return new RISCVAsmBackend(OSABI, TT.isArch64Bit());
+}
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
new file mode 100644
index 0000000..4f085d3
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -0,0 +1,47 @@
+//===-- RISCVELFObjectWriter.cpp - RISCV ELF Writer -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class RISCVELFObjectWriter : public MCELFObjectTargetWriter {
+public:
+ RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit);
+
+ ~RISCVELFObjectWriter() override;
+
+protected:
+ unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
+ const MCFixup &Fixup, bool IsPCRel) const override;
+};
+}
+
+RISCVELFObjectWriter::RISCVELFObjectWriter(uint8_t OSABI, bool Is64Bit)
+ : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_RISCV,
+ /*HasRelocationAddend*/ false) {}
+
+RISCVELFObjectWriter::~RISCVELFObjectWriter() {}
+
+unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
+ llvm_unreachable("invalid fixup kind!");
+}
+
+MCObjectWriter *llvm::createRISCVELFObjectWriter(raw_pwrite_stream &OS,
+ uint8_t OSABI, bool Is64Bit) {
+ MCELFObjectTargetWriter *MOTW = new RISCVELFObjectWriter(OSABI, Is64Bit);
+ return createELFObjectWriter(MOTW, OS, /*IsLittleEndian*/ true);
+}
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
new file mode 100644
index 0000000..b164df8
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
@@ -0,0 +1,25 @@
+//===-- RISCVMCAsmInfo.cpp - RISCV Asm properties -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declarations of the RISCVMCAsmInfo properties.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVMCAsmInfo.h"
+#include "llvm/ADT/Triple.h"
+using namespace llvm;
+
+void RISCVMCAsmInfo::anchor() {}
+
+RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) {
+ PointerSize = CalleeSaveStackSlotSize = TT.isArch64Bit() ? 8 : 4;
+ CommentString = "#";
+ AlignmentIsInBytes = false;
+ SupportsDebugInformation = true;
+}
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
new file mode 100644
index 0000000..901a1eb
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
@@ -0,0 +1,31 @@
+//===-- RISCVMCAsmInfo.h - RISCV Asm Info ----------------------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declaration of the RISCVMCAsmInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCASMINFO_H
+#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCASMINFO_H
+
+#include "llvm/MC/MCAsmInfoELF.h"
+
+namespace llvm {
+class Triple;
+
+class RISCVMCAsmInfo : public MCAsmInfoELF {
+ void anchor() override;
+
+public:
+ explicit RISCVMCAsmInfo(const Triple &TargetTriple);
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
new file mode 100644
index 0000000..b2ed137
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -0,0 +1,91 @@
+//===-- RISCVMCCodeEmitter.cpp - Convert RISCV code to machine code -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the RISCVMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mccodeemitter"
+
+STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
+
+namespace {
+class RISCVMCCodeEmitter : public MCCodeEmitter {
+ RISCVMCCodeEmitter(const RISCVMCCodeEmitter &) = delete;
+ void operator=(const RISCVMCCodeEmitter &) = delete;
+ MCContext &Ctx;
+
+public:
+ RISCVMCCodeEmitter(MCContext &ctx) : Ctx(ctx) {}
+
+ ~RISCVMCCodeEmitter() override {}
+
+ void encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
+
+ /// TableGen'erated function for getting the binary encoding for an
+ /// instruction.
+ uint64_t getBinaryCodeForInstr(const MCInst &MI,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Return binary encoding of operand. If the machine operand requires
+ /// relocation, record the relocation and return zero.
+ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+};
+} // end anonymous namespace
+
+MCCodeEmitter *llvm::createRISCVMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx) {
+ return new RISCVMCCodeEmitter(Ctx);
+}
+
+void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ // For now, we only support RISC-V instructions with 32-bit length
+ uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
+ support::endian::Writer<support::little>(OS).write(Bits);
+ ++MCNumEmitted; // Keep track of the # of mi's emitted.
+}
+
+unsigned
+RISCVMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+
+ if (MO.isReg())
+ return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
+
+ if (MO.isImm())
+ return static_cast<unsigned>(MO.getImm());
+
+ llvm_unreachable("Unhandled expression!");
+ return 0;
+}
+
+#include "RISCVGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
new file mode 100644
index 0000000..4fc69a7
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -0,0 +1,59 @@
+//===-- RISCVMCTargetDesc.cpp - RISCV Target Descriptions -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file provides RISCV-specific target descriptions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "RISCVMCTargetDesc.h"
+#include "RISCVMCAsmInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+
+#define GET_INSTRINFO_MC_DESC
+#include "RISCVGenInstrInfo.inc"
+
+#define GET_REGINFO_MC_DESC
+#include "RISCVGenRegisterInfo.inc"
+
+using namespace llvm;
+
+static MCInstrInfo *createRISCVMCInstrInfo() {
+ MCInstrInfo *X = new MCInstrInfo();
+ InitRISCVMCInstrInfo(X);
+ return X;
+}
+
+static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) {
+ MCRegisterInfo *X = new MCRegisterInfo();
+ InitRISCVMCRegisterInfo(X, RISCV::X1_32);
+ return X;
+}
+
+static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI,
+ const Triple &TT) {
+ MCAsmInfo *MAI = new RISCVMCAsmInfo(TT);
+ return MAI;
+}
+
+extern "C" void LLVMInitializeRISCVTargetMC() {
+ for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) {
+ RegisterMCAsmInfoFn X(*T, createRISCVMCAsmInfo);
+ TargetRegistry::RegisterMCInstrInfo(*T, createRISCVMCInstrInfo);
+ TargetRegistry::RegisterMCRegInfo(*T, createRISCVMCRegisterInfo);
+ TargetRegistry::RegisterMCAsmBackend(*T, createRISCVAsmBackend);
+ TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter);
+ }
+}
diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
new file mode 100644
index 0000000..ddc3bf3
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
@@ -0,0 +1,58 @@
+//===-- RISCVMCTargetDesc.h - RISCV Target Descriptions ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides RISCV specific target descriptions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCTARGETDESC_H
+#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCTARGETDESC_H
+
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Config/config.h"
+
+namespace llvm {
+class MCAsmBackend;
+class MCCodeEmitter;
+class MCContext;
+class MCInstrInfo;
+class MCObjectWriter;
+class MCRegisterInfo;
+class MCSubtargetInfo;
+class StringRef;
+class Target;
+class Triple;
+class raw_ostream;
+class raw_pwrite_stream;
+
+Target &getTheRISCV32Target();
+Target &getTheRISCV64Target();
+
+MCCodeEmitter *createRISCVMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx);
+
+MCAsmBackend *createRISCVAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
+
+MCObjectWriter *createRISCVELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI,
+ bool Is64Bit);
+}
+
+// Defines symbolic names for RISC-V registers.
+#define GET_REGINFO_ENUM
+#include "RISCVGenRegisterInfo.inc"
+
+// Defines symbolic names for RISC-V instructions.
+#define GET_INSTRINFO_ENUM
+#include "RISCVGenInstrInfo.inc"
+
+#endif
diff --git a/contrib/llvm/lib/Target/RISCV/RISCV.td b/contrib/llvm/lib/Target/RISCV/RISCV.td
new file mode 100644
index 0000000..1483830
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/RISCV.td
@@ -0,0 +1,27 @@
+//===-- RISCV.td - Describe the RISCV Target Machine -------*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+include "llvm/Target/Target.td"
+
+include "RISCVRegisterInfo.td"
+include "RISCVInstrInfo.td"
+
+
+def RISCVInstrInfo : InstrInfo;
+
+def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true",
+ "Implements RV64">;
+
+def : ProcessorModel<"generic-rv32", NoSchedModel, []>;
+
+def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit]>;
+
+def RISCV : Target {
+ let InstructionSet = RISCVInstrInfo;
+}
diff --git a/contrib/llvm/lib/Target/RISCV/RISCVInstrFormats.td b/contrib/llvm/lib/Target/RISCV/RISCVInstrFormats.td
new file mode 100644
index 0000000..1e9bc3b
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/RISCVInstrFormats.td
@@ -0,0 +1,152 @@
+//===-- RISCVInstrFormats.td - RISCV Instruction Formats ---*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//
+// These instruction format definitions are structured to match the
+// description in the RISC-V User-Level ISA specification as closely as
+// possible. For instance, the specification describes instructions with the
+// MSB (31st bit) on the left and the LSB (0th bit) on the right. This is
+// reflected in the order of parameters to each instruction class.
+//
+// One area of divergence is in the description of immediates. The
+// specification describes immediate encoding in terms of bit-slicing
+// operations on the logical value represented. The immediate argument to
+// these instruction formats instead represents the bit sequence that will be
+// inserted into the instruction. e.g. although JAL's immediate is logically
+// a 21-bit value (where the LSB is always zero), we describe it as an imm20
+// to match how it is encoded.
+//
+//===----------------------------------------------------------------------===//
+
+class RISCVInst<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : Instruction {
+ field bits<32> Inst;
+ let Size = 4;
+
+ bits<7> Opcode = 0;
+
+ let Inst{6-0} = Opcode;
+
+ let Namespace = "RISCV";
+
+ dag OutOperandList = outs;
+ dag InOperandList = ins;
+ let AsmString = asmstr;
+ let Pattern = pattern;
+}
+
+// Pseudo instructions
+class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern> {
+ let isPseudo = 1;
+}
+
+class FR<bits<7> funct7, bits<3> funct3, bits<7> opcode, dag outs, dag ins,
+ string asmstr, list<dag> pattern> : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<5> rs2;
+ bits<5> rs1;
+ bits<5> rd;
+
+ let Inst{31-25} = funct7;
+ let Inst{24-20} = rs2;
+ let Inst{19-15} = rs1;
+ let Inst{14-12} = funct3;
+ let Inst{11-7} = rd;
+ let Opcode = opcode;
+}
+
+class FI<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<12> imm12;
+ bits<5> rs1;
+ bits<5> rd;
+
+ let Inst{31-20} = imm12;
+ let Inst{19-15} = rs1;
+ let Inst{14-12} = funct3;
+ let Inst{11-7} = rd;
+ let Opcode = opcode;
+}
+
+class FI32Shift<bit arithshift, bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<5> shamt;
+ bits<5> rs1;
+ bits<5> rd;
+
+ let Inst{31} = 0;
+ let Inst{30} = arithshift;
+ let Inst{29-25} = 0;
+ let Inst{24-20} = shamt;
+ let Inst{19-15} = rs1;
+ let Inst{14-12} = funct3;
+ let Inst{11-7} = rd;
+ let Opcode = opcode;
+}
+
+class FS<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<12> imm12;
+ bits<5> rs2;
+ bits<5> rs1;
+
+ let Inst{31-25} = imm12{11-5};
+ let Inst{24-20} = rs2;
+ let Inst{19-15} = rs1;
+ let Inst{14-12} = funct3;
+ let Inst{11-7} = imm12{4-0};
+ let Opcode = opcode;
+}
+
+class FSB<bits<3> funct3, bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<12> imm12;
+ bits<5> rs2;
+ bits<5> rs1;
+
+ let Inst{31} = imm12{11};
+ let Inst{30-25} = imm12{9-4};
+ let Inst{24-20} = rs2;
+ let Inst{19-15} = rs1;
+ let Inst{14-12} = funct3;
+ let Inst{11-8} = imm12{3-0};
+ let Inst{7} = imm12{10};
+ let Opcode = opcode;
+}
+
+class FU<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<20> imm20;
+ bits<5> rd;
+
+ let Inst{31-12} = imm20;
+ let Inst{11-7} = rd;
+ let Opcode = opcode;
+}
+
+class FUJ<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : RISCVInst<outs, ins, asmstr, pattern>
+{
+ bits<20> imm20;
+ bits<5> rd;
+
+ let Inst{31} = imm20{19};
+ let Inst{30-21} = imm20{9-0};
+ let Inst{20} = imm20{10};
+ let Inst{19-12} = imm20{18-11};
+ let Inst{11-7} = rd;
+ let Opcode = opcode;
+}
diff --git a/contrib/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/contrib/llvm/lib/Target/RISCV/RISCVInstrInfo.td
new file mode 100644
index 0000000..52530c2
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -0,0 +1,55 @@
+//===-- RISCVInstrInfo.td - Target Description for RISCV ---*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the RISC-V instructions in TableGen format.
+//
+//===----------------------------------------------------------------------===//
+
+include "RISCVInstrFormats.td"
+
+def simm12 : Operand<i32>;
+
+// As noted in RISCVRegisterInfo.td, the hope is that support for
+// variable-sized register classes will mean that instruction definitions do
+// not need to be duplicated for 32-bit and 64-bit register classes. For now
+// we use 'GPR', which is 32-bit. When codegen for both RV32 and RV64 is
+// added, we will need to duplicate instruction definitions unless a proposal
+// like <http://lists.llvm.org/pipermail/llvm-dev/2016-September/105027.html>
+// is adopted.
+
+class ALU_ri<bits<3> funct3, string OpcodeStr> :
+ FI<funct3, 0b0010011, (outs GPR:$rd), (ins GPR:$rs1, simm12:$imm12),
+ OpcodeStr#"\t$rd, $rs1, $imm12", []>
+{
+}
+
+def ADDI : ALU_ri<0b000, "addi">;
+def SLTI : ALU_ri<0b010, "slti">;
+def SLTIU : ALU_ri<0b011, "sltiu">;
+def XORI : ALU_ri<0b100, "xori">;
+def ORI : ALU_ri<0b110, "ori">;
+def ANDI : ALU_ri<0b111, "andi">;
+
+class ALU_rr<bits<7> funct7, bits<3> funct3, string OpcodeStr> :
+ FR<funct7, funct3, 0b0110011, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2),
+ OpcodeStr#"\t$rd, $rs1, $rs2", []>
+{
+}
+
+def ADD : ALU_rr<0b0000000, 0b000, "add">;
+def SUB : ALU_rr<0b0100000, 0b000, "sub">;
+def SLL : ALU_rr<0b0000000, 0b001, "sll">;
+def SLT : ALU_rr<0b0000000, 0b010, "slt">;
+def SLTU : ALU_rr<0b0000000, 0b011, "sltu">;
+def XOR : ALU_rr<0b0000000, 0b100, "xor">;
+def SRL : ALU_rr<0b0000000, 0b101, "srl">;
+def SRA : ALU_rr<0b0100000, 0b101, "sra">;
+def OR : ALU_rr<0b0000000, 0b110, "or">;
+def AND : ALU_rr<0b0000000, 0b111, "and">;
+
diff --git a/contrib/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/contrib/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
new file mode 100644
index 0000000..f04de21
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -0,0 +1,90 @@
+//===-- RISCVRegisterInfo.td - RISC-V Register defs --------*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Declarations that describe the RISC-V register file
+//===----------------------------------------------------------------------===//
+
+let Namespace = "RISCV" in {
+ def sub_32 : SubRegIndex<32>;
+
+ class RISCVReg32<bits<5> Enc, string n, list<string> alt = []> : Register<n> {
+ let HWEncoding{4-0} = Enc;
+ let AltNames = alt;
+ }
+
+ // RISCV64 registers don't define an AsmName or AltName. If they specified
+ // names aliasing the RISCVReg32 registers, the generation of the default
+ // MatchRegisterName/MatchRegisterAltName would fail. When necessary,
+ // RISCVAsmParser will need to convert a register number from a RISCVReg32
+ // to the equivalent RISCVReg64.
+ class RISCVReg64<RISCVReg32 subreg> : Register<""> {
+ let HWEncoding{4-0} = subreg.HWEncoding{4-0};
+ let SubRegs = [subreg];
+ let SubRegIndices = [sub_32];
+ }
+
+ def ABIRegAltName : RegAltNameIndex;
+}
+
+// Integer registers
+let RegAltNameIndices = [ABIRegAltName] in {
+ def X0_32 : RISCVReg32<0, "x0", ["zero"]>, DwarfRegNum<[0]>;
+ def X1_32 : RISCVReg32<1, "x1", ["ra"]>, DwarfRegNum<[1]>;
+ def X2_32 : RISCVReg32<2, "x2", ["sp"]>, DwarfRegNum<[2]>;
+ def X3_32 : RISCVReg32<3, "x3", ["gp"]>, DwarfRegNum<[3]>;
+ def X4_32 : RISCVReg32<4, "x4", ["tp"]>, DwarfRegNum<[4]>;
+ def X5_32 : RISCVReg32<5, "x5", ["t0"]>, DwarfRegNum<[5]>;
+ def X6_32 : RISCVReg32<6, "x6", ["t1"]>, DwarfRegNum<[6]>;
+ def X7_32 : RISCVReg32<7, "x7", ["t2"]>, DwarfRegNum<[7]>;
+ def X8_32 : RISCVReg32<8, "x8", ["s0"]>, DwarfRegNum<[8]>;
+ def X9_32 : RISCVReg32<9, "x9", ["s1"]>, DwarfRegNum<[9]>;
+ def X10_32 : RISCVReg32<10,"x10", ["a0"]>, DwarfRegNum<[10]>;
+ def X11_32 : RISCVReg32<11,"x11", ["a1"]>, DwarfRegNum<[11]>;
+ def X12_32 : RISCVReg32<12,"x12", ["a2"]>, DwarfRegNum<[12]>;
+ def X13_32 : RISCVReg32<13,"x13", ["a3"]>, DwarfRegNum<[13]>;
+ def X14_32 : RISCVReg32<14,"x14", ["a4"]>, DwarfRegNum<[14]>;
+ def X15_32 : RISCVReg32<15,"x15", ["a5"]>, DwarfRegNum<[15]>;
+ def X16_32 : RISCVReg32<16,"x16", ["a6"]>, DwarfRegNum<[16]>;
+ def X17_32 : RISCVReg32<17,"x17", ["a7"]>, DwarfRegNum<[17]>;
+ def X18_32 : RISCVReg32<18,"x18", ["s2"]>, DwarfRegNum<[18]>;
+ def X19_32 : RISCVReg32<19,"x19", ["s3"]>, DwarfRegNum<[19]>;
+ def X20_32 : RISCVReg32<20,"x20", ["s4"]>, DwarfRegNum<[20]>;
+ def X21_32 : RISCVReg32<21,"x21", ["s5"]>, DwarfRegNum<[21]>;
+ def X22_32 : RISCVReg32<22,"x22", ["s6"]>, DwarfRegNum<[22]>;
+ def X23_32 : RISCVReg32<23,"x23", ["s7"]>, DwarfRegNum<[23]>;
+ def X24_32 : RISCVReg32<24,"x24", ["s8"]>, DwarfRegNum<[24]>;
+ def X25_32 : RISCVReg32<25,"x25", ["s9"]>, DwarfRegNum<[25]>;
+ def X26_32 : RISCVReg32<26,"x26", ["s10"]>, DwarfRegNum<[26]>;
+ def X27_32 : RISCVReg32<27,"x27", ["s11"]>, DwarfRegNum<[27]>;
+ def X28_32 : RISCVReg32<28,"x28", ["t3"]>, DwarfRegNum<[28]>;
+ def X29_32 : RISCVReg32<29,"x29", ["t4"]>, DwarfRegNum<[29]>;
+ def X30_32 : RISCVReg32<30,"x30", ["t5"]>, DwarfRegNum<[30]>;
+ def X31_32 : RISCVReg32<31,"x31", ["t6"]>, DwarfRegNum<[31]>;
+}
+
+foreach Index = 0-31 in {
+ def X#Index#_64 : RISCVReg64<!cast<RISCVReg32>("X"#Index#"_32")>, DwarfRegNum<[Index]>;
+}
+
+// We currently define separate register classes for the 32-bit and 64-bit
+// GPRs. Once variable-sized register classes
+// <http://lists.llvm.org/pipermail/llvm-dev/2016-September/105027.html> or
+// similar are implemented, we can just use one 'GPR' class for most
+// instruction definitions.
+
+// TODO: once codegen is implemented, registers should be listed in an order
+// reflecting the preferred register allocation sequence.
+def GPR : RegisterClass<"RISCV", [i32], 32, (add
+ (sequence "X%u_32", 0, 31)
+)>;
+
+def GPR64 : RegisterClass<"RISCV", [i64], 64, (add
+ (sequence "X%u_64", 0, 31)
+)>;
diff --git a/contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
new file mode 100644
index 0000000..afbbe00
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -0,0 +1,58 @@
+//===-- RISCVTargetMachine.cpp - Define TargetMachine for RISCV -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements the info about RISCV target spec.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVTargetMachine.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetOptions.h"
+using namespace llvm;
+
+extern "C" void LLVMInitializeRISCVTarget() {
+ RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
+ RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
+}
+
+static std::string computeDataLayout(const Triple &TT) {
+ if (TT.isArch64Bit()) {
+ return "e-m:e-i64:64-n32:64-S128";
+ } else {
+ assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");
+ return "e-m:e-i64:64-n32-S128";
+ }
+}
+
+static Reloc::Model getEffectiveRelocModel(const Triple &TT,
+ Optional<Reloc::Model> RM) {
+ if (!RM.hasValue())
+ return Reloc::Static;
+ return *RM;
+}
+
+RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT,
+ StringRef CPU, StringRef FS,
+ const TargetOptions &Options,
+ Optional<Reloc::Model> RM,
+ CodeModel::Model CM,
+ CodeGenOpt::Level OL)
+ : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
+ getEffectiveRelocModel(TT, RM), CM, OL),
+ TLOF(make_unique<TargetLoweringObjectFileELF>()) {}
+
+TargetPassConfig *RISCVTargetMachine::createPassConfig(PassManagerBase &PM) {
+ return new TargetPassConfig(this, PM);
+}
diff --git a/contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.h b/contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.h
new file mode 100644
index 0000000..d13e574
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/RISCVTargetMachine.h
@@ -0,0 +1,40 @@
+//===-- RISCVTargetMachine.h - Define TargetMachine for RISCV ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the RISCV specific subclass of TargetMachine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_RISCVTARGETMACHINE_H
+#define LLVM_LIB_TARGET_RISCV_RISCVTARGETMACHINE_H
+
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+class RISCVTargetMachine : public LLVMTargetMachine {
+ std::unique_ptr<TargetLoweringObjectFile> TLOF;
+
+public:
+ RISCVTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
+ StringRef FS, const TargetOptions &Options,
+ Optional<Reloc::Model> RM, CodeModel::Model CM,
+ CodeGenOpt::Level OL);
+
+ TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
+
+ TargetLoweringObjectFile *getObjFileLowering() const override {
+ return TLOF.get();
+ }
+};
+}
+
+#endif
diff --git a/contrib/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp b/contrib/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp
new file mode 100644
index 0000000..34932c2
--- /dev/null
+++ b/contrib/llvm/lib/Target/RISCV/TargetInfo/RISCVTargetInfo.cpp
@@ -0,0 +1,30 @@
+//===-- RISCVTargetInfo.cpp - RISCV Target Implementation -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TargetRegistry.h"
+using namespace llvm;
+
+namespace llvm {
+Target &getTheRISCV32Target() {
+ static Target TheRISCV32Target;
+ return TheRISCV32Target;
+}
+
+Target &getTheRISCV64Target() {
+ static Target TheRISCV64Target;
+ return TheRISCV64Target;
+}
+}
+
+extern "C" void LLVMInitializeRISCVTargetInfo() {
+ RegisterTarget<Triple::riscv32> X(getTheRISCV32Target(), "riscv32",
+ "32-bit RISC-V");
+ RegisterTarget<Triple::riscv64> Y(getTheRISCV64Target(), "riscv64",
+ "64-bit RISC-V");
+}
diff --git a/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index b2003b8..e775aa6 100644
--- a/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -84,7 +84,7 @@ class SparcAsmParser : public MCTargetAsmParser {
return getSTI().getTargetTriple().getArch() == Triple::sparcv9;
}
- void expandSET(MCInst &Inst, SMLoc IDLoc,
+ bool expandSET(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions);
public:
@@ -121,7 +121,7 @@ public:
static const MCPhysReg DoubleRegs[32] = {
Sparc::D0, Sparc::D1, Sparc::D2, Sparc::D3,
Sparc::D4, Sparc::D5, Sparc::D6, Sparc::D7,
- Sparc::D8, Sparc::D7, Sparc::D8, Sparc::D9,
+ Sparc::D8, Sparc::D9, Sparc::D10, Sparc::D11,
Sparc::D12, Sparc::D13, Sparc::D14, Sparc::D15,
Sparc::D16, Sparc::D17, Sparc::D18, Sparc::D19,
Sparc::D20, Sparc::D21, Sparc::D22, Sparc::D23,
@@ -466,7 +466,7 @@ public:
} // end namespace
-void SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
+bool SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
SmallVectorImpl<MCInst> &Instructions) {
MCOperand MCRegOp = Inst.getOperand(0);
MCOperand MCValOp = Inst.getOperand(1);
@@ -479,8 +479,8 @@ void SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
// Allow either a signed or unsigned 32-bit immediate.
if (RawImmValue < -2147483648LL || RawImmValue > 4294967295LL) {
- Error(IDLoc, "set: argument must be between -2147483648 and 4294967295");
- return;
+ return Error(IDLoc,
+ "set: argument must be between -2147483648 and 4294967295");
}
// If the value was expressed as a large unsigned number, that's ok.
@@ -537,6 +537,7 @@ void SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
TmpInst.addOperand(MCOperand::createExpr(Expr));
Instructions.push_back(TmpInst);
}
+ return false;
}
bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
@@ -556,7 +557,8 @@ bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
Instructions.push_back(Inst);
break;
case SP::SET:
- expandSET(Inst, IDLoc, Instructions);
+ if (expandSET(Inst, IDLoc, Instructions))
+ return true;
break;
}
@@ -626,13 +628,11 @@ bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
if (getLexer().is(AsmToken::Comma)) {
if (parseBranchModifiers(Operands) != MatchOperand_Success) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token");
}
}
if (parseOperand(Operands, Name) != MatchOperand_Success) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token");
}
@@ -645,14 +645,12 @@ bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
// Parse and remember the operand.
if (parseOperand(Operands, Name) != MatchOperand_Success) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token");
}
}
}
if (getLexer().isNot(AsmToken::EndOfStatement)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token");
}
Parser.Lex(); // Consume the EndOfStatement.
@@ -717,7 +715,7 @@ bool SparcAsmParser:: parseDirectiveWord(unsigned Size, SMLoc L) {
return false;
}
-SparcAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SparcAsmParser::parseMEMOperand(OperandVector &Operands) {
SMLoc S, E;
@@ -755,7 +753,7 @@ SparcAsmParser::parseMEMOperand(OperandVector &Operands) {
return MatchOperand_Success;
}
-SparcAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
@@ -823,7 +821,7 @@ SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
return MatchOperand_Success;
}
-SparcAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op,
bool isCall) {
@@ -910,7 +908,7 @@ SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op,
return (Op) ? MatchOperand_Success : MatchOperand_ParseFail;
}
-SparcAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SparcAsmParser::parseBranchModifiers(OperandVector &Operands) {
// parse (,a|,pn|,pt)+
@@ -1265,9 +1263,9 @@ bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal,
}
extern "C" void LLVMInitializeSparcAsmParser() {
- RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
- RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
- RegisterMCAsmParser<SparcAsmParser> C(TheSparcelTarget);
+ RegisterMCAsmParser<SparcAsmParser> A(getTheSparcTarget());
+ RegisterMCAsmParser<SparcAsmParser> B(getTheSparcV9Target());
+ RegisterMCAsmParser<SparcAsmParser> C(getTheSparcelTarget());
}
#define GET_REGISTER_MATCHER
diff --git a/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index 944f355..6f9cc31 100644
--- a/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -43,9 +43,7 @@ namespace {
static char ID;
Filler() : MachineFunctionPass(ID) {}
- const char *getPassName() const override {
- return "SPARC Delay Slot Filler";
- }
+ StringRef getPassName() const override { return "SPARC Delay Slot Filler"; }
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
bool runOnMachineFunction(MachineFunction &F) override {
@@ -64,7 +62,7 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
void insertCallDefsUses(MachineBasicBlock::iterator MI,
diff --git a/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp b/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
index 1dea379..da7e0b7 100644
--- a/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
+++ b/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
@@ -44,7 +44,9 @@ public:
}
namespace llvm {
-extern Target TheSparcTarget, TheSparcV9Target, TheSparcelTarget;
+Target &getTheSparcTarget();
+Target &getTheSparcV9Target();
+Target &getTheSparcelTarget();
}
static MCDisassembler *createSparcDisassembler(const Target &T,
@@ -56,11 +58,11 @@ static MCDisassembler *createSparcDisassembler(const Target &T,
extern "C" void LLVMInitializeSparcDisassembler() {
// Register the disassembler.
- TargetRegistry::RegisterMCDisassembler(TheSparcTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheSparcTarget(),
createSparcDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheSparcV9Target,
+ TargetRegistry::RegisterMCDisassembler(getTheSparcV9Target(),
createSparcDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheSparcelTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheSparcelTarget(),
createSparcDisassembler);
}
diff --git a/contrib/llvm/lib/Target/Sparc/LeonFeatures.td b/contrib/llvm/lib/Target/Sparc/LeonFeatures.td
index 63f8b33..d06e734 100755
--- a/contrib/llvm/lib/Target/Sparc/LeonFeatures.td
+++ b/contrib/llvm/lib/Target/Sparc/LeonFeatures.td
@@ -10,82 +10,73 @@
//
//===----------------------------------------------------------------------===//
-//===----------------------------------------------------------------------===//
-// CASA Support differs between LEON3-FT GR712RC and LEON3-FT UT699
-// We need to have the option to switch this on and off.
-//===----------------------------------------------------------------------===//
-
-// support to casa instruction; for leon3 subtarget only
-def LeonCASA : SubtargetFeature<
- "hasleoncasa", "HasLeonCasa", "true",
- "Enable CASA instruction for LEON3 and LEON4 processors">;
//===----------------------------------------------------------------------===//
// UMAC and SMAC support for LEON3 and LEON4 processors.
//===----------------------------------------------------------------------===//
-// support to casa instruction; for leon3 subtarget only
-def UMACSMACSupport
- : SubtargetFeature<"hasumacsmac", "HasUmacSmac", "true",
- "Enable UMAC and SMAC for LEON3 and LEON4 processors">;
+//support to casa instruction; for leon3 subtarget only
+def UMACSMACSupport : SubtargetFeature<
+ "hasumacsmac",
+ "HasUmacSmac",
+ "true",
+ "Enable UMAC and SMAC for LEON3 and LEON4 processors"
+>;
+
//===----------------------------------------------------------------------===//
-// LEON Erratum fixes
+// CASA Support differs between LEON3-FT GR712RC and LEON3-FT UT699
+// We need to have the option to switch this on and off.
//===----------------------------------------------------------------------===//
-def ReplaceSDIV
- : SubtargetFeature<
- "replacesdiv", "PerformSDIVReplace", "true",
- "AT697E erratum fix: Do not emit SDIV, emit SDIVCC instead">;
-
-def FixCALL
- : SubtargetFeature<"fixcall", "FixCallImmediates", "true",
- "AT697E erratum fix: Restrict the size of the immediate "
- "operand of the CALL instruction to 20 bits">;
-
-def IgnoreZeroFlag
- : SubtargetFeature<"ignrzeroflag", "IgnoreZeroFlag", "true",
- "AT697E erratum fix: Do not rely on the zero bit flag "
- "on a divide overflow for SDIVCC and UDIVCC">;
-
-def InsertNOPDoublePrecision
- : SubtargetFeature<"insrtnopdblprcsn", "InsertNOPDoublePrecision", "true",
- "LEON2 erratum fix: Insert a NOP before the double "
- "precision floating point instruction">;
-
-def FixFSMULD : SubtargetFeature<"fixfsmuld", "FixFSMULD", "true",
- "LEON3 erratum fix: Do not select FSMULD">;
-
-def ReplaceFMULS
- : SubtargetFeature<"replacefmuls", "ReplaceFMULS", "true",
- "LEON3 erratum fix: Replace FMULS instruction with a "
- "routine using conversions/double precision operations "
- "to replace FMULS">;
-
-def PreventRoundChange
- : SubtargetFeature<"prvntroundchange", "PreventRoundChange", "true",
- "LEON3 erratum fix: Prevent any rounding mode change "
- "request: use only the round-to-nearest rounding mode">;
-
-def FixAllFDIVSQRT
- : SubtargetFeature<"fixallfdivsqrt", "FixAllFDIVSQRT", "true",
- "LEON3 erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD "
- "instructions with NOPs and floating-point store">;
-
-def InsertNOPLoad
- : SubtargetFeature<"insertnopload", "InsertNOPLoad", "true",
- "LEON3 erratum fix: Insert a NOP instruction after "
- "every single-cycle load instruction when the next "
- "instruction is another load/store instruction">;
-
-def FlushCacheLineSWAP
- : SubtargetFeature<"flshcachelineswap", "FlushCacheLineSWAP", "true",
- "LEON3 erratum fix: Flush cache line containing the "
- "lock before performing any of the atomic instructions "
- "SWAP and LDSTUB">;
-
-def InsertNOPsLoadStore
- : SubtargetFeature<"insertnopsloadstore", "InsertNOPsLoadStore", "true",
- "LEON3 erratum fix: Insert NOPs between "
- "single-precision loads and the store, so the number of "
- "instructions between is 4">;
+//support to casa instruction; for leon3 subtarget only
+def LeonCASA : SubtargetFeature<
+ "hasleoncasa",
+ "HasLeonCasa",
+ "true",
+ "Enable CASA instruction for LEON3 and LEON4 processors"
+>;
+
+
+def ReplaceSDIV : SubtargetFeature<
+ "replacesdiv",
+ "PerformSDIVReplace",
+ "true",
+ "AT697E erratum fix: Do not emit SDIV, emit SDIVCC instead"
+>;
+
+def InsertNOPLoad: SubtargetFeature<
+ "insertnopload",
+ "InsertNOPLoad",
+ "true",
+ "LEON3 erratum fix: Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction"
+>;
+
+def FixFSMULD : SubtargetFeature<
+ "fixfsmuld",
+ "FixFSMULD",
+ "true",
+ "LEON erratum fix: Do not use FSMULD"
+>;
+
+def ReplaceFMULS : SubtargetFeature<
+ "replacefmuls",
+ "ReplaceFMULS",
+ "true",
+ "LEON erratum fix: Replace FMULS instruction with FMULD and relevant conversion instructions"
+>;
+
+def DetectRoundChange : SubtargetFeature<
+ "detectroundchange",
+ "DetectRoundChange",
+ "true",
+ "LEON3 erratum detection: Detects any rounding mode change "
+ "request: use only the round-to-nearest rounding mode"
+>;
+
+def FixAllFDIVSQRT : SubtargetFeature<
+ "fixallfdivsqrt",
+ "FixAllFDIVSQRT",
+ "true",
+ "LEON erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD instructions with NOPs and floating-point store"
+>;
diff --git a/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp b/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
index 5d09208..0acc287 100755
--- a/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
+++ b/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
@@ -16,6 +16,7 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -51,8 +52,7 @@ int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI,
int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) {
for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) {
if (!MRI.isPhysRegUsed(RegisterIndex) &&
- !(std::find(UsedRegisters.begin(), UsedRegisters.end(),
- RegisterIndex) != UsedRegisters.end())) {
+ !is_contained(UsedRegisters, RegisterIndex)) {
return RegisterIndex;
}
}
@@ -90,15 +90,6 @@ bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
Modified = true;
- } else if (MI.isInlineAsm()) {
- // Look for an inline ld or ldf instruction.
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("ld")) {
- MachineBasicBlock::iterator NMBBI = std::next(MBBI);
- BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
- Modified = true;
- }
}
}
}
@@ -148,29 +139,6 @@ bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
Reg1Index = MI.getOperand(0).getReg();
Reg2Index = MI.getOperand(1).getReg();
Reg3Index = MI.getOperand(2).getReg();
- } else if (MI.isInlineAsm()) {
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("fsmuld")) {
- // this is an inline FSMULD instruction
-
- unsigned StartOp = InlineAsm::MIOp_FirstOperand;
-
- // extracts the registers from the inline assembly instruction
- for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI.getOperand(i);
- if (MO.isReg()) {
- if (Reg1Index == UNASSIGNED_INDEX)
- Reg1Index = MO.getReg();
- else if (Reg2Index == UNASSIGNED_INDEX)
- Reg2Index = MO.getReg();
- else if (Reg3Index == UNASSIGNED_INDEX)
- Reg3Index = MO.getReg();
- }
- if (Reg3Index != UNASSIGNED_INDEX)
- break;
- }
- }
}
if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
@@ -260,28 +228,6 @@ bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
Reg1Index = MI.getOperand(0).getReg();
Reg2Index = MI.getOperand(1).getReg();
Reg3Index = MI.getOperand(2).getReg();
- } else if (MI.isInlineAsm()) {
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("fmuls")) {
- // this is an inline FMULS instruction
- unsigned StartOp = InlineAsm::MIOp_FirstOperand;
-
- // extracts the registers from the inline assembly instruction
- for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI.getOperand(i);
- if (MO.isReg()) {
- if (Reg1Index == UNASSIGNED_INDEX)
- Reg1Index = MO.getReg();
- else if (Reg2Index == UNASSIGNED_INDEX)
- Reg2Index = MO.getReg();
- else if (Reg3Index == UNASSIGNED_INDEX)
- Reg3Index = MO.getReg();
- }
- if (Reg3Index != UNASSIGNED_INDEX)
- break;
- }
- }
}
if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
@@ -329,391 +275,22 @@ bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
return Modified;
}
-//*****************************************************************************
-//**** FixAllFDIVSQRT pass
-//*****************************************************************************
-// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
-// exist for some earlier versions of the LEON processor line. Five NOP
-// instructions need to be inserted after these instructions to ensure the
-// correct result is placed in the destination registers before they are used.
-//
-// This pass implements two fixes:
-// 1) fixing the FSQRTS and FSQRTD instructions.
-// 2) fixing the FDIVS and FDIVD instructions.
-//
-// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
-// the pipeline when this option is enabled, so this pass needs only to deal
-// with the changes that still need implementing for the "double" versions
-// of these instructions.
-//
-char FixAllFDIVSQRT::ID = 0;
-
-FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm)
- : LEONMachineFunctionPass(tm, ID) {}
-
-bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
- Subtarget = &MF.getSubtarget<SparcSubtarget>();
- const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
- DebugLoc DL = DebugLoc();
-
- bool Modified = false;
- for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
- MachineInstr &MI = *MBBI;
- unsigned Opcode = MI.getOpcode();
-
- if (MI.isInlineAsm()) {
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("fsqrtd")) {
- // this is an inline fsqrts instruction
- Opcode = SP::FSQRTD;
- } else if (AsmString.startswith_lower("fdivd")) {
- // this is an inline fsqrts instruction
- Opcode = SP::FDIVD;
- }
- }
-
- // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
- // switched on so we don't need to check for them here. They will
- // already have been converted to FSQRTD or FDIVD earlier in the
- // pipeline.
- if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
- // Insert 5 NOPs before FSQRTD,FDIVD.
- for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
-
- MachineBasicBlock::iterator NMBBI = std::next(MBBI);
- // ... and inserting 28 NOPs after FSQRTD,FDIVD.
- for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
- BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
-
- Modified = true;
- }
- }
- }
-
- return Modified;
-}
-
-//*****************************************************************************
-//**** ReplaceSDIV pass
-//*****************************************************************************
-// This pass fixes the incorrectly working SDIV instruction that
-// exist for some earlier versions of the LEON processor line. The instruction
-// is replaced with an SDIVcc instruction instead, which is working.
-//
-char ReplaceSDIV::ID = 0;
-
-ReplaceSDIV::ReplaceSDIV() : LEONMachineFunctionPass(ID) {}
-
-ReplaceSDIV::ReplaceSDIV(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}
-
-bool ReplaceSDIV::runOnMachineFunction(MachineFunction &MF) {
- Subtarget = &MF.getSubtarget<SparcSubtarget>();
- const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
-
- bool Modified = false;
- for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
- MachineInstr &MI = *MBBI;
- unsigned Opcode = MI.getOpcode();
- if (Opcode == SP::SDIVrr) {
- MI.setDesc(TII.get(SP::SDIVCCrr));
- Modified = true;
- } else if (Opcode == SP::SDIVri) {
- MI.setDesc(TII.get(SP::SDIVCCri));
- Modified = true;
- }
- }
- }
-
- return Modified;
-}
-
-static RegisterPass<ReplaceSDIV> X("replace-sdiv", "Replase SDIV Pass", false,
- false);
-
-//*****************************************************************************
-//**** FixCALL pass
-//*****************************************************************************
-// This pass restricts the size of the immediate operand of the CALL
-// instruction, which can cause problems on some earlier versions of the LEON
-// processor, which can interpret some of the call address bits incorrectly.
-//
-char FixCALL::ID = 0;
-
-FixCALL::FixCALL(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}
-
-bool FixCALL::runOnMachineFunction(MachineFunction &MF) {
- bool Modified = false;
-
- for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
- MachineInstr &MI = *MBBI;
- MI.print(errs());
- errs() << "\n";
-
- unsigned Opcode = MI.getOpcode();
- if (Opcode == SP::CALL || Opcode == SP::CALLrr) {
- unsigned NumOperands = MI.getNumOperands();
- for (unsigned OperandIndex = 0; OperandIndex < NumOperands;
- OperandIndex++) {
- MachineOperand &MO = MI.getOperand(OperandIndex);
- if (MO.isImm()) {
- int64_t Value = MO.getImm();
- MO.setImm(Value & 0x000fffffL);
- Modified = true;
- break;
- }
- }
- } else if (MI.isInlineAsm()) // inline assembly immediate call
- {
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("call")) {
- // this is an inline call instruction
- unsigned StartOp = InlineAsm::MIOp_FirstOperand;
-
- // extracts the registers from the inline assembly instruction
- for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
- MachineOperand &MO = MI.getOperand(i);
- if (MO.isImm()) {
- int64_t Value = MO.getImm();
- MO.setImm(Value & 0x000fffffL);
- Modified = true;
- }
- }
- }
- }
- }
- }
-
- return Modified;
-}
-
-//*****************************************************************************
-//**** IgnoreZeroFlag pass
-//*****************************************************************************
-// This erratum fix fixes the overflow behavior of SDIVCC and UDIVCC
-// instructions that exists on some earlier LEON processors. Where these
-// instructions are detected, they are replaced by a sequence that will
-// explicitly write the overflow bit flag if this is required.
-//
-char IgnoreZeroFlag::ID = 0;
-
-IgnoreZeroFlag::IgnoreZeroFlag(TargetMachine &tm)
- : LEONMachineFunctionPass(tm, ID) {}
-
-bool IgnoreZeroFlag::runOnMachineFunction(MachineFunction &MF) {
- Subtarget = &MF.getSubtarget<SparcSubtarget>();
- const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
- DebugLoc DL = DebugLoc();
-
- bool Modified = false;
- for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
- MachineInstr &MI = *MBBI;
- unsigned Opcode = MI.getOpcode();
- if (Opcode == SP::SDIVCCrr || Opcode == SP::SDIVCCri ||
- Opcode == SP::UDIVCCrr || Opcode == SP::UDIVCCri) {
-
- // split the current machine basic block - just after the sdivcc/udivcc
- // instruction
- // create a label that help us skip the zero flag update (of PSR -
- // Processor Status Register)
- // if conditions are not met
- const BasicBlock *LLVM_BB = MBB.getBasicBlock();
- MachineFunction::iterator It =
- std::next(MachineFunction::iterator(MBB));
-
- MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
- MF.insert(It, dneBB);
-
- // Transfer the remainder of MBB and its successor edges to dneBB.
- dneBB->splice(dneBB->begin(), &MBB,
- std::next(MachineBasicBlock::iterator(MI)), MBB.end());
- dneBB->transferSuccessorsAndUpdatePHIs(&MBB);
-
- MBB.addSuccessor(dneBB);
-
- MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
-
- // bvc - branch if overflow flag not set
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
- .addMBB(dneBB)
- .addImm(SPCC::ICC_VS);
-
- // bnz - branch if not zero
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
- .addMBB(dneBB)
- .addImm(SPCC::ICC_NE);
-
- // use the WRPSR (Write Processor State Register) instruction to set the
- // zeo flag to 1
- // create wr %g0, 1, %psr
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri))
- .addReg(SP::G0)
- .addImm(1);
-
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP));
-
- Modified = true;
- } else if (MI.isInlineAsm()) {
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("sdivcc") ||
- AsmString.startswith_lower("udivcc")) {
- // this is an inline SDIVCC or UDIVCC instruction
-
- // split the current machine basic block - just after the
- // sdivcc/udivcc instruction
- // create a label that help us skip the zero flag update (of PSR -
- // Processor Status Register)
- // if conditions are not met
- const BasicBlock *LLVM_BB = MBB.getBasicBlock();
- MachineFunction::iterator It =
- std::next(MachineFunction::iterator(MBB));
-
- MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
- MF.insert(It, dneBB);
-
- // Transfer the remainder of MBB and its successor edges to dneBB.
- dneBB->splice(dneBB->begin(), &MBB,
- std::next(MachineBasicBlock::iterator(MI)), MBB.end());
- dneBB->transferSuccessorsAndUpdatePHIs(&MBB);
-
- MBB.addSuccessor(dneBB);
-
- MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
-
- // bvc - branch if overflow flag not set
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
- .addMBB(dneBB)
- .addImm(SPCC::ICC_VS);
-
- // bnz - branch if not zero
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
- .addMBB(dneBB)
- .addImm(SPCC::ICC_NE);
-
- // use the WRPSR (Write Processor State Register) instruction to set
- // the zeo flag to 1
- // create wr %g0, 1, %psr
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri))
- .addReg(SP::G0)
- .addImm(1);
-
- BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP));
-
- Modified = true;
- }
- }
- }
- }
-
- return Modified;
-}
-
-//*****************************************************************************
-//**** InsertNOPDoublePrecision pass
-//*****************************************************************************
-// This erratum fix for some earlier LEON processors fixes a problem where a
-// double precision load will not yield the correct result if used in FMUL,
-// FDIV, FADD, FSUB or FSQRT instructions later. If this sequence is detected,
-// inserting a NOP between the two instructions will fix the erratum.
-// 1.scans the code after register allocation;
-// 2.checks for the problem conditions as described in the AT697E erratum
-// “Odd-Numbered FPU Register Dependency not Properly Checked in some
-// Double-Precision FPU Operations”;
-// 3.inserts NOPs if the problem exists.
-//
-char InsertNOPDoublePrecision::ID = 0;
-
-InsertNOPDoublePrecision::InsertNOPDoublePrecision(TargetMachine &tm)
- : LEONMachineFunctionPass(tm, ID) {}
-
-bool InsertNOPDoublePrecision::runOnMachineFunction(MachineFunction &MF) {
- Subtarget = &MF.getSubtarget<SparcSubtarget>();
- const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
- DebugLoc DL = DebugLoc();
-
- bool Modified = false;
- for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
- MachineInstr &MI = *MBBI;
- unsigned Opcode = MI.getOpcode();
- if (Opcode == SP::LDDFri || Opcode == SP::LDDFrr) {
- MachineBasicBlock::iterator NMBBI = std::next(MBBI);
- MachineInstr &NMI = *NMBBI;
-
- unsigned NextOpcode = NMI.getOpcode();
- // NMI.print(errs());
- if (NextOpcode == SP::FADDD || NextOpcode == SP::FSUBD ||
- NextOpcode == SP::FMULD || NextOpcode == SP::FDIVD) {
- int RegAIndex = GetRegIndexForOperand(MI, 0);
- int RegBIndex = GetRegIndexForOperand(NMI, 0);
- int RegCIndex =
- GetRegIndexForOperand(NMI, 2); // Second source operand is index 2
- int RegDIndex =
- GetRegIndexForOperand(NMI, 1); // Destination operand is index 1
-
- if ((RegAIndex == RegBIndex + 1 && RegBIndex == RegDIndex) ||
- (RegAIndex == RegCIndex + 1 && RegCIndex == RegDIndex) ||
- (RegAIndex == RegBIndex + 1 && RegCIndex == RegDIndex) ||
- (RegAIndex == RegCIndex + 1 && RegBIndex == RegDIndex)) {
- // Insert NOP between the two instructions.
- BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
- Modified = true;
- }
-
- // Check the errata patterns that only happen for FADDD and FMULD
- if (Modified == false &&
- (NextOpcode == SP::FADDD || NextOpcode == SP::FMULD)) {
- RegAIndex = GetRegIndexForOperand(MI, 1);
- if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex &&
- RegBIndex == RegDIndex) {
- // Insert NOP between the two instructions.
- BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
- Modified = true;
- }
- }
- } else if (NextOpcode == SP::FSQRTD) {
- int RegAIndex = GetRegIndexForOperand(MI, 1);
- int RegBIndex = GetRegIndexForOperand(NMI, 0);
- int RegCIndex = GetRegIndexForOperand(NMI, 1);
-
- if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex) {
- // Insert NOP between the two instructions.
- BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
- Modified = true;
- }
- }
- }
- }
- }
-
- return Modified;
-}
//*****************************************************************************
-//**** PreventRoundChange pass
+//**** DetectRoundChange pass
//*****************************************************************************
// To prevent any explicit change of the default rounding mode, this pass
-// detects any call of the fesetround function and removes this call from the
-// list of generated operations.
+// detects any call of the fesetround function.
+// A warning is generated to ensure the user knows this has happened.
//
-char PreventRoundChange::ID = 0;
+// Detects an erratum in UT699 LEON 3 processor
-PreventRoundChange::PreventRoundChange(TargetMachine &tm)
+char DetectRoundChange::ID = 0;
+
+DetectRoundChange::DetectRoundChange(TargetMachine &tm)
: LEONMachineFunctionPass(tm, ID) {}
-bool PreventRoundChange::runOnMachineFunction(MachineFunction &MF) {
+bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) {
Subtarget = &MF.getSubtarget<SparcSubtarget>();
bool Modified = false;
@@ -728,10 +305,11 @@ bool PreventRoundChange::runOnMachineFunction(MachineFunction &MF) {
if (MO.isGlobal()) {
StringRef FuncName = MO.getGlobal()->getName();
if (FuncName.compare_lower("fesetround") == 0) {
- MachineBasicBlock::iterator NMBBI = std::next(MBBI);
- MI.eraseFromParent();
- MBBI = NMBBI;
- Modified = true;
+ errs() << "Error: You are using the detectroundchange "
+ "option to detect rounding changes that will "
+ "cause LEON errata. The only way to fix this "
+ "is to remove the call to fesetround from "
+ "the source code.\n";
}
}
}
@@ -740,17 +318,30 @@ bool PreventRoundChange::runOnMachineFunction(MachineFunction &MF) {
return Modified;
}
+
//*****************************************************************************
-//**** FlushCacheLineSWAP pass
+//**** FixAllFDIVSQRT pass
//*****************************************************************************
-// This pass inserts FLUSHW just before any SWAP atomic instruction.
+// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
+// exist for some earlier versions of the LEON processor line. Five NOP
+// instructions need to be inserted after these instructions to ensure the
+// correct result is placed in the destination registers before they are used.
//
-char FlushCacheLineSWAP::ID = 0;
+// This pass implements two fixes:
+// 1) fixing the FSQRTS and FSQRTD instructions.
+// 2) fixing the FDIVS and FDIVD instructions.
+//
+// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
+// the pipeline when this option is enabled, so this pass needs only to deal
+// with the changes that still need implementing for the "double" versions
+// of these instructions.
+//
+char FixAllFDIVSQRT::ID = 0;
-FlushCacheLineSWAP::FlushCacheLineSWAP(TargetMachine &tm)
+FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm)
: LEONMachineFunctionPass(tm, ID) {}
-bool FlushCacheLineSWAP::runOnMachineFunction(MachineFunction &MF) {
+bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
Subtarget = &MF.getSubtarget<SparcSubtarget>();
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
DebugLoc DL = DebugLoc();
@@ -761,170 +352,20 @@ bool FlushCacheLineSWAP::runOnMachineFunction(MachineFunction &MF) {
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
MachineInstr &MI = *MBBI;
unsigned Opcode = MI.getOpcode();
- if (Opcode == SP::SWAPrr || Opcode == SP::SWAPri ||
- Opcode == SP::LDSTUBrr || Opcode == SP::LDSTUBri) {
- // insert flush and 5 NOPs before the swap/ldstub instruction
- BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- Modified = true;
- } else if (MI.isInlineAsm()) {
- StringRef AsmString =
- MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
- if (AsmString.startswith_lower("swap") ||
- AsmString.startswith_lower("ldstub")) {
- // this is an inline swap or ldstub instruction
-
- // insert flush and 5 NOPs before the swap/ldstub instruction
- BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
+ // switched on so we don't need to check for them here. They will
+ // already have been converted to FSQRTD or FDIVD earlier in the
+ // pipeline.
+ if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
+ for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- Modified = true;
- }
- }
- }
- }
-
- return Modified;
-}
-
-//*****************************************************************************
-//**** InsertNOPsLoadStore pass
-//*****************************************************************************
-// This pass shall insert NOPs between floating point loads and stores when the
-// following circumstances are present [5]:
-// Pattern 1:
-// 1. single-precision load or single-precision FPOP to register %fX, where X is
-// the same register as the store being checked;
-// 2. single-precision load or single-precision FPOP to register %fY , where Y
-// is the opposite register in the same double-precision pair;
-// 3. 0-3 instructions of any kind, except stores from %fX or %fY or operations
-// with %fX as destination;
-// 4. the store (from register %fX) being considered.
-// Pattern 2:
-// 1. double-precision FPOP;
-// 2. any number of operations on any kind, except no double-precision FPOP and
-// at most one (less than two) single-precision or single-to-double FPOPs;
-// 3. the store (from register %fX) being considered.
-//
-char InsertNOPsLoadStore::ID = 0;
-
-InsertNOPsLoadStore::InsertNOPsLoadStore(TargetMachine &tm)
- : LEONMachineFunctionPass(tm, ID) {}
-
-bool InsertNOPsLoadStore::runOnMachineFunction(MachineFunction &MF) {
- Subtarget = &MF.getSubtarget<SparcSubtarget>();
- const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
- DebugLoc DL = DebugLoc();
-
- MachineInstr *Pattern1FirstInstruction = NULL;
- MachineInstr *Pattern2FirstInstruction = NULL;
- unsigned int StoreInstructionsToCheck = 0;
- int FxRegIndex, FyRegIndex;
-
- bool Modified = false;
- for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
- MachineBasicBlock &MBB = *MFI;
- for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
- MachineInstr &MI = *MBBI;
-
- if (StoreInstructionsToCheck > 0) {
- if (((MI.getOpcode() == SP::STFrr || MI.getOpcode() == SP::STFri) &&
- (GetRegIndexForOperand(MI, LAST_OPERAND) == FxRegIndex ||
- GetRegIndexForOperand(MI, LAST_OPERAND) == FyRegIndex)) ||
- GetRegIndexForOperand(MI, 0) == FxRegIndex) {
- // Insert four NOPs
- for (unsigned InsertedCount = 0; InsertedCount < 4; InsertedCount++) {
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- }
- Modified = true;
- }
- StoreInstructionsToCheck--;
- }
-
- switch (MI.getOpcode()) {
- // Watch for Pattern 1 FPop instructions
- case SP::LDrr:
- case SP::LDri:
- case SP::LDFrr:
- case SP::LDFri:
- case SP::FADDS:
- case SP::FSUBS:
- case SP::FMULS:
- case SP::FDIVS:
- case SP::FSQRTS:
- case SP::FCMPS:
- case SP::FMOVS:
- case SP::FNEGS:
- case SP::FABSS:
- case SP::FITOS:
- case SP::FSTOI:
- case SP::FITOD:
- case SP::FDTOI:
- case SP::FDTOS:
- if (Pattern1FirstInstruction != NULL) {
- FxRegIndex = GetRegIndexForOperand(*Pattern1FirstInstruction, 0);
- FyRegIndex = GetRegIndexForOperand(MI, 0);
-
- // Check to see if these registers are part of the same double
- // precision
- // register pair.
- int DoublePrecRegIndexForX = (FxRegIndex - SP::F0) / 2;
- int DoublePrecRegIndexForY = (FyRegIndex - SP::F0) / 2;
-
- if (DoublePrecRegIndexForX == DoublePrecRegIndexForY)
- StoreInstructionsToCheck = 4;
- }
+ MachineBasicBlock::iterator NMBBI = std::next(MBBI);
+ for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
+ BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
- Pattern1FirstInstruction = &MI;
- break;
- // End of Pattern 1
-
- // Search for Pattern 2
- case SP::FADDD:
- case SP::FSUBD:
- case SP::FMULD:
- case SP::FDIVD:
- case SP::FSQRTD:
- case SP::FCMPD:
- Pattern2FirstInstruction = &MI;
- Pattern1FirstInstruction = NULL;
- break;
-
- case SP::STFrr:
- case SP::STFri:
- case SP::STDFrr:
- case SP::STDFri:
- if (Pattern2FirstInstruction != NULL) {
- if (GetRegIndexForOperand(MI, LAST_OPERAND) ==
- GetRegIndexForOperand(*Pattern2FirstInstruction, 0)) {
- // Insert four NOPs
- for (unsigned InsertedCount = 0; InsertedCount < 4;
- InsertedCount++) {
- BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
- }
-
- Pattern2FirstInstruction = NULL;
- }
- }
- Pattern1FirstInstruction = NULL;
- break;
- // End of Pattern 2
-
- default:
- // Ensure we don't count debug-only values while we're testing for the
- // patterns.
- if (!MI.isDebugValue())
- Pattern1FirstInstruction = NULL;
- break;
+ Modified = true;
}
}
}
diff --git a/contrib/llvm/lib/Target/Sparc/LeonPasses.h b/contrib/llvm/lib/Target/Sparc/LeonPasses.h
index 5e21813..2158cb6 100755
--- a/contrib/llvm/lib/Target/Sparc/LeonPasses.h
+++ b/contrib/llvm/lib/Target/Sparc/LeonPasses.h
@@ -44,57 +44,17 @@ protected:
int getUnusedFPRegister(MachineRegisterInfo &MRI);
};
-class LLVM_LIBRARY_VISIBILITY ReplaceSDIV : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- ReplaceSDIV();
- ReplaceSDIV(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "ReplaceSDIV: Erratum Fix LBR25: do not emit SDIV, but emit SDIVCC "
- "instead";
- }
-};
-
-class LLVM_LIBRARY_VISIBILITY FixCALL : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- FixCALL(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "FixCALL: Erratum Fix LBR26: restrict the size of the immediate "
- "operand of the CALL instruction to 20 bits";
- }
-};
-
-class LLVM_LIBRARY_VISIBILITY IgnoreZeroFlag : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- IgnoreZeroFlag(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "IgnoreZeroFlag: Erratum Fix LBR28: do not rely on the zero bit "
- "flag on a divide overflow for SDIVCC and UDIVCC";
- }
-};
-
-class LLVM_LIBRARY_VISIBILITY InsertNOPDoublePrecision
- : public LEONMachineFunctionPass {
+class LLVM_LIBRARY_VISIBILITY InsertNOPLoad : public LEONMachineFunctionPass {
public:
static char ID;
- InsertNOPDoublePrecision(TargetMachine &tm);
+ InsertNOPLoad(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "InsertNOPDoublePrecision: Erratum Fix LBR30: insert a NOP before "
- "the double precision floating point instruction";
+ StringRef getPassName() const override {
+ return "InsertNOPLoad: Erratum Fix LBR35: insert a NOP instruction after "
+ "every single-cycle load instruction when the next instruction is "
+ "another load/store instruction";
}
};
@@ -105,7 +65,7 @@ public:
FixFSMULD(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "FixFSMULD: Erratum Fix LBR31: do not select FSMULD";
}
};
@@ -117,24 +77,24 @@ public:
ReplaceFMULS(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "ReplaceFMULS: Erratum Fix LBR32: replace FMULS instruction with a "
"routine using conversions/double precision operations to replace "
"FMULS";
}
};
-class LLVM_LIBRARY_VISIBILITY PreventRoundChange
+class LLVM_LIBRARY_VISIBILITY DetectRoundChange
: public LEONMachineFunctionPass {
public:
static char ID;
- PreventRoundChange(TargetMachine &tm);
+ DetectRoundChange(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
- return "PreventRoundChange: Erratum Fix LBR33: prevent any rounding mode "
- "change request: use only the round-to-nearest rounding mode";
+ StringRef getPassName() const override {
+ return "DetectRoundChange: Leon erratum detection: detect any rounding "
+ "mode change request: use only the round-to-nearest rounding mode";
}
};
@@ -145,55 +105,11 @@ public:
FixAllFDIVSQRT(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "FixAllFDIVSQRT: Erratum Fix LBR34: fix FDIVS/FDIVD/FSQRTS/FSQRTD "
"instructions with NOPs and floating-point store";
}
};
-
-class LLVM_LIBRARY_VISIBILITY InsertNOPLoad : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- InsertNOPLoad(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "InsertNOPLoad: insert a NOP instruction after "
- "every single-cycle load instruction when the next instruction is "
- "another load/store instruction";
- }
-};
-
-class LLVM_LIBRARY_VISIBILITY FlushCacheLineSWAP
- : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- FlushCacheLineSWAP(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "FlushCacheLineSWAP: Erratum Fix LBR36: flush cache line containing "
- "the lock before performing any of the atomic instructions SWAP and "
- "LDSTUB";
- }
-};
-
-class LLVM_LIBRARY_VISIBILITY InsertNOPsLoadStore
- : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- InsertNOPsLoadStore(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "InsertNOPsLoadStore: Erratum Fix LBR37: insert NOPs between "
- "single-precision loads and the store, so the number of "
- "instructions between is 4";
- }
-};
-} // namespace lllvm
+} // namespace llvm
#endif // LLVM_LIB_TARGET_SPARC_LEON_PASSES_H
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
index 14a70d8..6106a6c 100644
--- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -300,6 +300,7 @@ namespace {
MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
return new ELFSparcAsmBackend(T, TT.getOS());
}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
index 45bc4a1..86341c6 100644
--- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -19,6 +19,7 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -35,10 +36,12 @@ namespace {
class SparcMCCodeEmitter : public MCCodeEmitter {
SparcMCCodeEmitter(const SparcMCCodeEmitter &) = delete;
void operator=(const SparcMCCodeEmitter &) = delete;
+ const MCInstrInfo &MCII;
MCContext &Ctx;
public:
- SparcMCCodeEmitter(MCContext &ctx): Ctx(ctx) {}
+ SparcMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
+ : MCII(mcii), Ctx(ctx) {}
~SparcMCCodeEmitter() override {}
@@ -71,18 +74,25 @@ public:
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+private:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
};
} // end anonymous namespace
MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx) {
- return new SparcMCCodeEmitter(Ctx);
+ return new SparcMCCodeEmitter(MCII, Ctx);
}
void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI);
if (Ctx.getAsmInfo()->isLittleEndian()) {
@@ -215,6 +225,5 @@ getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
return 0;
}
-
-
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "SparcGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
index dceaca7..889e2fd 100644
--- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -128,11 +128,12 @@ static MCInstPrinter *createSparcMCInstPrinter(const Triple &T,
extern "C" void LLVMInitializeSparcTargetMC() {
// Register the MC asm info.
- RegisterMCAsmInfoFn X(TheSparcTarget, createSparcMCAsmInfo);
- RegisterMCAsmInfoFn Y(TheSparcV9Target, createSparcV9MCAsmInfo);
- RegisterMCAsmInfoFn Z(TheSparcelTarget, createSparcMCAsmInfo);
+ RegisterMCAsmInfoFn X(getTheSparcTarget(), createSparcMCAsmInfo);
+ RegisterMCAsmInfoFn Y(getTheSparcV9Target(), createSparcV9MCAsmInfo);
+ RegisterMCAsmInfoFn Z(getTheSparcelTarget(), createSparcMCAsmInfo);
- for (Target *T : {&TheSparcTarget, &TheSparcV9Target, &TheSparcelTarget}) {
+ for (Target *T :
+ {&getTheSparcTarget(), &getTheSparcV9Target(), &getTheSparcelTarget()}) {
// Register the MC instruction info.
TargetRegistry::RegisterMCInstrInfo(*T, createSparcMCInstrInfo);
@@ -160,10 +161,10 @@ extern "C" void LLVMInitializeSparcTargetMC() {
}
// Register the MC codegen info.
- TargetRegistry::registerMCAdjustCodeGenOpts(TheSparcTarget,
+ TargetRegistry::registerMCAdjustCodeGenOpts(getTheSparcTarget(),
adjustCodeGenOpts);
- TargetRegistry::registerMCAdjustCodeGenOpts(TheSparcV9Target,
+ TargetRegistry::registerMCAdjustCodeGenOpts(getTheSparcV9Target(),
adjustCodeGenOptsV9);
- TargetRegistry::registerMCAdjustCodeGenOpts(TheSparcelTarget,
+ TargetRegistry::registerMCAdjustCodeGenOpts(getTheSparcelTarget(),
adjustCodeGenOpts);
}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
index a9c9f15..4e754c1 100644
--- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
@@ -24,21 +24,23 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
class Target;
class Triple;
class StringRef;
class raw_pwrite_stream;
class raw_ostream;
-extern Target TheSparcTarget;
-extern Target TheSparcV9Target;
-extern Target TheSparcelTarget;
+Target &getTheSparcTarget();
+Target &getTheSparcV9Target();
+Target &getTheSparcelTarget();
MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx);
MCAsmBackend *createSparcAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createSparcELFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit,
bool IsLIttleEndian, uint8_t OSABI);
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/Sparc/Sparc.td b/contrib/llvm/lib/Target/Sparc/Sparc.td
index 7a3d124..11004c5 100644
--- a/contrib/llvm/lib/Target/Sparc/Sparc.td
+++ b/contrib/llvm/lib/Target/Sparc/Sparc.td
@@ -21,34 +21,35 @@ include "llvm/Target/Target.td"
//
def FeatureV9
- : SubtargetFeature<"v9", "IsV9", "true", "Enable SPARC-V9 instructions">;
+ : SubtargetFeature<"v9", "IsV9", "true",
+ "Enable SPARC-V9 instructions">;
def FeatureV8Deprecated
- : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true",
- "Enable deprecated V8 instructions in V9 mode">;
+ : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true",
+ "Enable deprecated V8 instructions in V9 mode">;
def FeatureVIS
- : SubtargetFeature<"vis", "IsVIS", "true",
- "Enable UltraSPARC Visual Instruction Set extensions">;
+ : SubtargetFeature<"vis", "IsVIS", "true",
+ "Enable UltraSPARC Visual Instruction Set extensions">;
def FeatureVIS2
- : SubtargetFeature<"vis2", "IsVIS2", "true",
- "Enable Visual Instruction Set extensions II">;
+ : SubtargetFeature<"vis2", "IsVIS2", "true",
+ "Enable Visual Instruction Set extensions II">;
def FeatureVIS3
- : SubtargetFeature<"vis3", "IsVIS3", "true",
- "Enable Visual Instruction Set extensions III">;
+ : SubtargetFeature<"vis3", "IsVIS3", "true",
+ "Enable Visual Instruction Set extensions III">;
def FeatureLeon
- : SubtargetFeature<"leon", "IsLeon", "true", "Enable LEON extensions">;
+ : SubtargetFeature<"leon", "IsLeon", "true",
+ "Enable LEON extensions">;
def FeatureHardQuad
- : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
- "Enable quad-word floating point instructions">;
+ : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
+ "Enable quad-word floating point instructions">;
def UsePopc : SubtargetFeature<"popc", "UsePopc", "true",
"Use the popc (population count) instruction">;
-def FeatureSoftFloat
- : SubtargetFeature<"soft-float", "UseSoftFloat", "true",
- "Use software emulation for floating point">;
+def FeatureSoftFloat : SubtargetFeature<"soft-float", "UseSoftFloat", "true",
+ "Use software emulation for floating point">;
-//==== Features added predmoninantly for LEON subtarget support
+//==== Features added predmoninantly for LEON subtarget support
include "LeonFeatures.td"
//===----------------------------------------------------------------------===//
@@ -62,92 +63,90 @@ include "SparcInstrInfo.td"
def SparcInstrInfo : InstrInfo;
-def SparcAsmParser : AsmParser { bit ShouldEmitMatchRegisterName = 0; }
+def SparcAsmParser : AsmParser {
+ bit ShouldEmitMatchRegisterName = 0;
+}
//===----------------------------------------------------------------------===//
// SPARC processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, list<SubtargetFeature> Features>
- : Processor<Name, NoItineraries, Features>;
-
-def : Proc<"generic", []>;
-def : Proc<"v7", []>;
-def : Proc<"v8", []>;
-def : Proc<"supersparc", []>;
-def : Proc<"sparclite", []>;
-def : Proc<"f934", []>;
-def : Proc<"hypersparc", []>;
-def : Proc<"sparclite86x", []>;
-def : Proc<"sparclet", []>;
-def : Proc<"tsc701", []>;
-def : Proc<"myriad2", []>;
-def : Proc<"myriad2.1", []>;
-def : Proc<"myriad2.2", []>;
-def : Proc<"v9", [ FeatureV9 ]>;
-def : Proc<"ultrasparc", [ FeatureV9, FeatureV8Deprecated, FeatureVIS ]>;
-def : Proc<"ultrasparc3",
- [ FeatureV9, FeatureV8Deprecated, FeatureVIS, FeatureVIS2 ]>;
-def : Proc<"niagara",
- [ FeatureV9, FeatureV8Deprecated, FeatureVIS, FeatureVIS2 ]>;
-def : Proc<"niagara2", [
- FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2
-]>;
-def : Proc<"niagara3", [
- FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2
-]>;
-def : Proc<"niagara4", [
- FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2, FeatureVIS3
-]>;
+ : Processor<Name, NoItineraries, Features>;
+
+def : Proc<"generic", []>;
+def : Proc<"v7", []>;
+def : Proc<"v8", []>;
+def : Proc<"supersparc", []>;
+def : Proc<"sparclite", []>;
+def : Proc<"f934", []>;
+def : Proc<"hypersparc", []>;
+def : Proc<"sparclite86x", []>;
+def : Proc<"sparclet", []>;
+def : Proc<"tsc701", []>;
+def : Proc<"myriad2", [FeatureLeon, LeonCASA]>;
+def : Proc<"myriad2.1", [FeatureLeon, LeonCASA]>;
+def : Proc<"myriad2.2", [FeatureLeon, LeonCASA]>;
+def : Proc<"ma2100", [FeatureLeon, LeonCASA]>;
+def : Proc<"ma2150", [FeatureLeon, LeonCASA]>;
+def : Proc<"ma2450", [FeatureLeon, LeonCASA]>;
+def : Proc<"v9", [FeatureV9]>;
+def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
+def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated, FeatureVIS,
+ FeatureVIS2]>;
+def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated, FeatureVIS,
+ FeatureVIS2]>;
+def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc,
+ FeatureVIS, FeatureVIS2]>;
+def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc,
+ FeatureVIS, FeatureVIS2]>;
+def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc,
+ FeatureVIS, FeatureVIS2, FeatureVIS3]>;
// LEON 2 FT generic
-def : Processor<"leon2", LEON2Itineraries, [ FeatureLeon ]>;
+def : Processor<"leon2", LEON2Itineraries,
+ [FeatureLeon]>;
// LEON 2 FT (AT697E)
-// AT697E: Provides full coverage of AT697E - covers all the erratum fixes for
-// LEON2 AT697E
-def : Processor<"at697e", LEON2Itineraries, [
- FeatureLeon, ReplaceSDIV, FixCALL, IgnoreZeroFlag, InsertNOPDoublePrecision
-]>;
+// TO DO: Place-holder: Processor specific features will be added *very* soon here.
+def : Processor<"at697e", LEON2Itineraries,
+ [FeatureLeon, ReplaceSDIV, InsertNOPLoad]>;
// LEON 2 FT (AT697F)
-// AT697F: Provides full coverage of AT697F - covers all the erratum fixes for
-// LEON2 AT697F
+// TO DO: Place-holder: Processor specific features will be added *very* soon here.
def : Processor<"at697f", LEON2Itineraries,
- [ FeatureLeon, InsertNOPDoublePrecision ]>;
+ [FeatureLeon, InsertNOPLoad]>;
+
// LEON 3 FT generic
-def : Processor<"leon3", LEON3Itineraries, [ FeatureLeon, UMACSMACSupport ]>;
+def : Processor<"leon3", LEON3Itineraries,
+ [FeatureLeon, UMACSMACSupport]>;
// LEON 3 FT (UT699). Provides features for the UT699 processor
-// - covers all the erratum fixes for LEON3, but does not support the CASA
-// instruction.
-def : Processor<"ut699", LEON3Itineraries, [
- FeatureLeon, FixFSMULD, ReplaceFMULS, PreventRoundChange,
- FixAllFDIVSQRT, InsertNOPLoad, FlushCacheLineSWAP, InsertNOPsLoadStore
-]>;
+// - covers all the erratum fixes for LEON3, but does not support the CASA instruction.
+def : Processor<"ut699", LEON3Itineraries,
+ [FeatureLeon, InsertNOPLoad, FixFSMULD, ReplaceFMULS, FixAllFDIVSQRT]>;
// LEON3 FT (GR712RC). Provides features for the GR712RC processor.
-// - covers all the erratum fixed for LEON3 and support for the CASA
-// instruction.
+// - covers all the erratum fixed for LEON3 and support for the CASA instruction.
def : Processor<"gr712rc", LEON3Itineraries,
- [ FeatureLeon, LeonCASA ]>;
+ [FeatureLeon, LeonCASA]>;
// LEON 4 FT generic
def : Processor<"leon4", LEON4Itineraries,
- [ FeatureLeon, LeonCASA ]>;
+ [FeatureLeon, UMACSMACSupport, LeonCASA]>;
-// GR740: Provides full coverage of GR740 - covers all the erratum fixes for
-// LEON3 + support to CASA + LEON 4 instruction timings
-def : Processor<"gr740", LEON4Itineraries,
- [ FeatureLeon, LeonCASA ]> {}
+// LEON 4 FT (GR740)
+// TO DO: Place-holder: Processor specific features will be added *very* soon here.
+def : Processor<"gr740", LEON4Itineraries,
+ [FeatureLeon, UMACSMACSupport, LeonCASA]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def SparcAsmWriter : AsmWriter {
- string AsmWriterClassName = "InstPrinter";
+ string AsmWriterClassName = "InstPrinter";
int PassSubtarget = 1;
int Variant = 0;
}
@@ -155,6 +154,6 @@ def SparcAsmWriter : AsmWriter {
def Sparc : Target {
// Pull in Instruction Info:
let InstructionSet = SparcInstrInfo;
- let AssemblyParsers = [ SparcAsmParser ];
- let AssemblyWriters = [ SparcAsmWriter ];
+ let AssemblyParsers = [SparcAsmParser];
+ let AssemblyWriters = [SparcAsmWriter];
}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
index c068440..31a128a 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -46,9 +46,7 @@ namespace {
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)) {}
- const char *getPassName() const override {
- return "Sparc Assembly Printer";
- }
+ StringRef getPassName() const override { return "Sparc Assembly Printer"; }
void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,
@@ -445,7 +443,7 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
// Force static initialization.
extern "C" void LLVMInitializeSparcAsmPrinter() {
- RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
- RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
- RegisterAsmPrinter<SparcAsmPrinter> Z(TheSparcelTarget);
+ RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget());
+ RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target());
+ RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget());
}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index 87b0155..122f830 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -87,7 +87,7 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const SparcInstrInfo &TII =
*static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
const SparcRegisterInfo &RegInfo =
@@ -103,13 +103,13 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
// rather than reporting an error, as would be sensible. This is
// poor, but fixing that bogosity is going to be a large project.
// For now, just see if it's lied, and report an error here.
- if (!NeedsStackRealignment && MFI->getMaxAlignment() > getStackAlignment())
+ if (!NeedsStackRealignment && MFI.getMaxAlignment() > getStackAlignment())
report_fatal_error("Function \"" + Twine(MF.getName()) + "\" required "
"stack re-alignment, but LLVM couldn't handle it "
"(probably because it has a dynamic alloca).");
// Get the number of bytes to allocate from the FrameInfo
- int NumBytes = (int) MFI->getStackSize();
+ int NumBytes = (int) MFI.getStackSize();
unsigned SAVEri = SP::SAVEri;
unsigned SAVErr = SP::SAVErr;
@@ -136,8 +136,8 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
// Add the extra call frame stack size, if needed. (This is the same
// code as in PrologEpilogInserter, but also gets disabled by
// targetHandlesStackFrameRounding)
- if (MFI->adjustsStack() && hasReservedCallFrame(MF))
- NumBytes += MFI->getMaxCallFrameSize();
+ if (MFI.adjustsStack() && hasReservedCallFrame(MF))
+ NumBytes += MFI.getMaxCallFrameSize();
// Adds the SPARC subtarget-specific spill area to the stack
// size. Also ensures target-required alignment.
@@ -145,40 +145,39 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
// Finally, ensure that the size is sufficiently aligned for the
// data on the stack.
- if (MFI->getMaxAlignment() > 0) {
- NumBytes = alignTo(NumBytes, MFI->getMaxAlignment());
+ if (MFI.getMaxAlignment() > 0) {
+ NumBytes = alignTo(NumBytes, MFI.getMaxAlignment());
}
// Update stack size with corrected value.
- MFI->setStackSize(NumBytes);
+ MFI.setStackSize(NumBytes);
emitSPAdjustment(MF, MBB, MBBI, -NumBytes, SAVErr, SAVEri);
- MachineModuleInfo &MMI = MF.getMMI();
unsigned regFP = RegInfo.getDwarfRegNum(SP::I6, true);
// Emit ".cfi_def_cfa_register 30".
unsigned CFIIndex =
- MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, regFP));
+ MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, regFP));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// Emit ".cfi_window_save".
- CFIIndex = MMI.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
unsigned regInRA = RegInfo.getDwarfRegNum(SP::I7, true);
unsigned regOutRA = RegInfo.getDwarfRegNum(SP::O7, true);
// Emit ".cfi_register 15, 31".
- CFIIndex = MMI.addFrameInst(
+ CFIIndex = MF.addFrameInst(
MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
if (NeedsStackRealignment) {
// andn %o6, MaxAlign-1, %o6
- int MaxAlign = MFI->getMaxAlignment();
+ int MaxAlign = MFI.getMaxAlignment();
BuildMI(MBB, MBBI, dl, TII.get(SP::ANDNri), SP::O6).addReg(SP::O6).addImm(MaxAlign - 1);
}
}
@@ -213,9 +212,9 @@ void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
.addReg(SP::G0);
return;
}
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
- int NumBytes = (int) MFI->getStackSize();
+ int NumBytes = (int) MFI.getStackSize();
if (NumBytes == 0)
return;
@@ -224,7 +223,7 @@ void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
// Reserve call frame if there are no variable sized objects on the stack.
- return !MF.getFrameInfo()->hasVarSizedObjects();
+ return !MF.getFrameInfo().hasVarSizedObjects();
}
// hasFP - Return true if the specified function should have a dedicated frame
@@ -233,21 +232,21 @@ bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
RegInfo->needsStackRealignment(MF) ||
- MFI->hasVarSizedObjects() ||
- MFI->isFrameAddressTaken();
+ MFI.hasVarSizedObjects() ||
+ MFI.isFrameAddressTaken();
}
int SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
unsigned &FrameReg) const {
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const SparcRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
const SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
- bool isFixed = MFI->isFixedObjectIndex(FI);
+ bool isFixed = MFI.isFixedObjectIndex(FI);
// Addressable stack objects are accessed using neg. offsets from
// %fp, or positive offsets from %sp.
@@ -273,7 +272,7 @@ int SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI
UseFP = true;
}
- int64_t FrameOffset = MF.getFrameInfo()->getObjectOffset(FI) +
+ int64_t FrameOffset = MF.getFrameInfo().getObjectOffset(FI) +
Subtarget.getStackPointerBias();
if (UseFP) {
@@ -281,7 +280,7 @@ int SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI
return FrameOffset;
} else {
FrameReg = SP::O6; // %sp
- return FrameOffset + MF.getFrameInfo()->getStackSize();
+ return FrameOffset + MF.getFrameInfo().getStackSize();
}
}
@@ -303,9 +302,9 @@ bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const
{
MachineRegisterInfo &MRI = MF.getRegInfo();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
- return !(MFI->hasCalls() // has calls
+ return !(MFI.hasCalls() // has calls
|| !MRI.reg_nodbg_empty(SP::L0) // Too many registers needed
|| !MRI.reg_nodbg_empty(SP::O6) // %SP is used
|| hasFP(MF)); // need %FP
diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
index 07948a3..c36e75d 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
@@ -53,7 +53,7 @@ public:
unsigned ConstraintID,
std::vector<SDValue> &OutOps) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SPARC DAG->DAG Pattern Instruction Selection";
}
@@ -360,22 +360,15 @@ void SparcDAGToDAGISel::Select(SDNode *N) {
// FIXME: Handle div by immediate.
unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
+ // SDIV is a hardware erratum on some LEON2 processors. Replace it with SDIVcc here.
+ if (((SparcTargetMachine&)TM).getSubtargetImpl()->performSDIVReplace()
+ &&
+ Opcode == SP::SDIVrr) {
+ Opcode = SP::SDIVCCrr;
+ }
CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
return;
}
- case ISD::MULHU:
- case ISD::MULHS: {
- // FIXME: Handle mul by immediate.
- SDValue MulLHS = N->getOperand(0);
- SDValue MulRHS = N->getOperand(1);
- unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
- SDNode *Mul =
- CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS);
- SDValue ResultHigh = SDValue(Mul, 1);
- ReplaceUses(SDValue(N, 0), ResultHigh);
- CurDAG->RemoveDeadNode(N);
- return;
- }
}
SelectCode(N);
diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 8738bc8..2ac9aae 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -32,6 +32,7 @@
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
+
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//===----------------------------------------------------------------------===//
@@ -403,7 +404,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
if (InIdx != 0)
report_fatal_error("sparc only supports sret on the first parameter");
// Get SRet from [%fp+64].
- int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, 64, true);
+ int FrameIdx = MF.getFrameInfo().CreateFixedObject(4, 64, true);
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
SDValue Arg =
DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo());
@@ -424,7 +425,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
SDValue LoVal;
if (NextVA.isMemLoc()) {
- int FrameIdx = MF.getFrameInfo()->
+ int FrameIdx = MF.getFrameInfo().
CreateFixedObject(4, StackOffset+NextVA.getLocMemOffset(),true);
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo());
@@ -466,9 +467,9 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
assert(VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::v2i32);
// If it is double-word aligned, just load.
if (Offset % 8 == 0) {
- int FI = MF.getFrameInfo()->CreateFixedObject(8,
- Offset,
- true);
+ int FI = MF.getFrameInfo().CreateFixedObject(8,
+ Offset,
+ true);
SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
SDValue Load =
DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
@@ -476,15 +477,15 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
continue;
}
- int FI = MF.getFrameInfo()->CreateFixedObject(4,
- Offset,
- true);
+ int FI = MF.getFrameInfo().CreateFixedObject(4,
+ Offset,
+ true);
SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
SDValue HiVal =
DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo());
- int FI2 = MF.getFrameInfo()->CreateFixedObject(4,
- Offset+4,
- true);
+ int FI2 = MF.getFrameInfo().CreateFixedObject(4,
+ Offset+4,
+ true);
SDValue FIPtr2 = DAG.getFrameIndex(FI2, PtrVT);
SDValue LoVal =
@@ -500,9 +501,9 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
continue;
}
- int FI = MF.getFrameInfo()->CreateFixedObject(4,
- Offset,
- true);
+ int FI = MF.getFrameInfo().CreateFixedObject(4,
+ Offset,
+ true);
SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
SDValue Load ;
if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
@@ -554,8 +555,8 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
MF.getRegInfo().addLiveIn(*CurArgReg, VReg);
SDValue Arg = DAG.getCopyFromReg(DAG.getRoot(), dl, VReg, MVT::i32);
- int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset,
- true);
+ int FrameIdx = MF.getFrameInfo().CreateFixedObject(4, ArgOffset,
+ true);
SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
OutChains.push_back(
@@ -638,7 +639,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_64(
// prefer our own extending loads.
if (VA.isExtInLoc())
Offset += 8 - ValSize;
- int FI = MF.getFrameInfo()->CreateFixedObject(ValSize, Offset, true);
+ int FI = MF.getFrameInfo().CreateFixedObject(ValSize, Offset, true);
InVals.push_back(
DAG.getLoad(VA.getValVT(), DL, Chain,
DAG.getFrameIndex(FI, getPointerTy(MF.getDataLayout())),
@@ -668,7 +669,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_64(
for (; ArgOffset < 6*8; ArgOffset += 8) {
unsigned VReg = MF.addLiveIn(SP::I0 + ArgOffset/8, &SP::I64RegsRegClass);
SDValue VArg = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i64);
- int FI = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset + ArgArea, true);
+ int FI = MF.getFrameInfo().CreateFixedObject(8, ArgOffset + ArgArea, true);
auto PtrVT = getPointerTy(MF.getDataLayout());
OutChains.push_back(
DAG.getStore(Chain, DL, VArg, DAG.getFrameIndex(FI, PtrVT),
@@ -740,7 +741,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
// Keep stack frames 8-byte aligned.
ArgsSize = (ArgsSize+7) & ~7;
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
// Create local copies for byval args.
SmallVector<SDValue, 8> ByValArgs;
@@ -754,7 +755,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
unsigned Align = Flags.getByValAlign();
if (Size > 0U) {
- int FI = MFI->CreateStackObject(Size, Align, false);
+ int FI = MFI.CreateStackObject(Size, Align, false);
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
SDValue SizeNode = DAG.getConstant(Size, dl, MVT::i32);
@@ -1207,7 +1208,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
if (VA.isRegLoc()) {
if (VA.needsCustom() && VA.getValVT() == MVT::f128
&& VA.getLocVT() == MVT::i128) {
- // Store and reload into the interger register reg and reg+1.
+ // Store and reload into the integer register reg and reg+1.
unsigned Offset = 8 * (VA.getLocReg() - SP::I0);
unsigned StackOffset = Offset + Subtarget->getStackPointerBias() + 128;
SDValue StackPtr = DAG.getRegister(SP::O6, PtrVT);
@@ -1507,7 +1508,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
// AddPromotedToType(ISD::STORE, MVT::i64, MVT::v2i32);
}
- // Turn FP extload into load/fextend
+ // Turn FP extload into load/fpextend
for (MVT VT : MVT::fp_valuetypes()) {
setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand);
setLoadExtAction(ISD::EXTLOAD, VT, MVT::f64, Expand);
@@ -1616,8 +1617,10 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
// Atomics are supported on SparcV9. 32-bit atomics are also
// supported by some Leon SparcV8 variants. Otherwise, atomics
// are unsupported.
- if (Subtarget->isV9() || Subtarget->hasLeonCasa())
+ if (Subtarget->isV9())
setMaxAtomicSizeInBitsSupported(64);
+ else if (Subtarget->hasLeonCasa())
+ setMaxAtomicSizeInBitsSupported(32);
else
setMaxAtomicSizeInBitsSupported(0);
@@ -1638,6 +1641,13 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom);
}
+ if (!Subtarget->is64Bit()) {
+ // These libcalls are not available in 32-bit.
+ setLibcallName(RTLIB::SHL_I128, nullptr);
+ setLibcallName(RTLIB::SRL_I128, nullptr);
+ setLibcallName(RTLIB::SRA_I128, nullptr);
+ }
+
if (!Subtarget->isV9()) {
// SparcV8 does not have FNEGD and FABSD.
setOperationAction(ISD::FNEG, MVT::f64, Custom);
@@ -1675,9 +1685,10 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
- // FIXME: Sparc provides these multiplies, but we don't have them yet.
- setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
- setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
+ // Expands to [SU]MUL_LOHI.
+ setOperationAction(ISD::MULHU, MVT::i32, Expand);
+ setOperationAction(ISD::MULHS, MVT::i32, Expand);
+ setOperationAction(ISD::MUL, MVT::i32, Expand);
if (Subtarget->is64Bit()) {
setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
@@ -1961,8 +1972,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo);
// GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
// function has calls.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setHasCalls(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setHasCalls(true);
return DAG.getLoad(VT, DL, DAG.getEntryNode(), AbsAddr,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
}
@@ -2089,8 +2100,8 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op,
// GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
// function has calls.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setHasCalls(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setHasCalls(true);
SDValue TGA = makeHiLoPair(Op,
SparcMCExpr::VK_Sparc_TLS_IE_HI22,
@@ -2120,7 +2131,7 @@ SDValue SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain,
ArgListTy &Args, SDValue Arg,
const SDLoc &DL,
SelectionDAG &DAG) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
EVT ArgVT = Arg.getValueType();
Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());
@@ -2130,7 +2141,7 @@ SDValue SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain,
if (ArgTy->isFP128Ty()) {
// Create a stack object and pass the pointer to the library function.
- int FI = MFI->CreateStackObject(16, 8, false);
+ int FI = MFI.CreateStackObject(16, 8, false);
SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
Chain = DAG.getStore(Chain, DL, Entry.Node, FIPtr, MachinePointerInfo(),
/* Alignment = */ 8);
@@ -2149,7 +2160,7 @@ SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG,
ArgListTy Args;
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue Callee = DAG.getExternalSymbol(LibFuncName, PtrVT);
@@ -2161,7 +2172,7 @@ SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG,
if (RetTy->isFP128Ty()) {
// Create a Stack Object to receive the return value of type f128.
ArgListEntry Entry;
- int RetFI = MFI->CreateStackObject(16, 8, false);
+ int RetFI = MFI.CreateStackObject(16, 8, false);
RetPtr = DAG.getFrameIndex(RetFI, PtrVT);
Entry.Node = RetPtr;
Entry.Ty = PointerType::getUnqual(RetTy);
@@ -2517,7 +2528,7 @@ static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG,
auto PtrVT = TLI.getPointerTy(DAG.getDataLayout());
// Need frame address to find the address of VarArgsFrameIndex.
- MF.getFrameInfo()->setFrameAddressIsTaken(true);
+ MF.getFrameInfo().setFrameAddressIsTaken(true);
// vastart just stores the address of the VarArgsFrameIndex slot into the
// memory location argument.
@@ -2557,17 +2568,57 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
const SparcSubtarget *Subtarget) {
SDValue Chain = Op.getOperand(0); // Legalize the chain.
SDValue Size = Op.getOperand(1); // Legalize the size.
+ unsigned Align = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ unsigned StackAlign = Subtarget->getFrameLowering()->getStackAlignment();
EVT VT = Size->getValueType(0);
SDLoc dl(Op);
+ // TODO: implement over-aligned alloca. (Note: also implies
+ // supporting support for overaligned function frames + dynamic
+ // allocations, at all, which currently isn't supported)
+ if (Align > StackAlign) {
+ const MachineFunction &MF = DAG.getMachineFunction();
+ report_fatal_error("Function \"" + Twine(MF.getName()) + "\": "
+ "over-aligned dynamic alloca not supported.");
+ }
+
+ // The resultant pointer needs to be above the register spill area
+ // at the bottom of the stack.
+ unsigned regSpillArea;
+ if (Subtarget->is64Bit()) {
+ regSpillArea = 128;
+ } else {
+ // On Sparc32, the size of the spill area is 92. Unfortunately,
+ // that's only 4-byte aligned, not 8-byte aligned (the stack
+ // pointer is 8-byte aligned). So, if the user asked for an 8-byte
+ // aligned dynamic allocation, we actually need to add 96 to the
+ // bottom of the stack, instead of 92, to ensure 8-byte alignment.
+
+ // That also means adding 4 to the size of the allocation --
+ // before applying the 8-byte rounding. Unfortunately, we the
+ // value we get here has already had rounding applied. So, we need
+ // to add 8, instead, wasting a bit more memory.
+
+ // Further, this only actually needs to be done if the required
+ // alignment is > 4, but, we've lost that info by this point, too,
+ // so we always apply it.
+
+ // (An alternative approach would be to always reserve 96 bytes
+ // instead of the required 92, but then we'd waste 4 extra bytes
+ // in every frame, not just those with dynamic stack allocations)
+
+ // TODO: modify code in SelectionDAGBuilder to make this less sad.
+
+ Size = DAG.getNode(ISD::ADD, dl, VT, Size,
+ DAG.getConstant(8, dl, VT));
+ regSpillArea = 96;
+ }
+
unsigned SPReg = SP::O6;
SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT);
SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value
Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain
- // The resultant pointer is actually 16 words from the bottom of the stack,
- // to provide a register spill area.
- unsigned regSpillArea = Subtarget->is64Bit() ? 128 : 96;
regSpillArea += Subtarget->getStackPointerBias();
SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP,
@@ -2586,8 +2637,8 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) {
static SDValue getFRAMEADDR(uint64_t depth, SDValue Op, SelectionDAG &DAG,
const SparcSubtarget *Subtarget) {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc dl(Op);
@@ -2628,14 +2679,15 @@ static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG,
uint64_t depth = Op.getConstantOperandVal(0);
return getFRAMEADDR(depth, Op, DAG, Subtarget);
+
}
static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG,
const SparcTargetLowering &TLI,
const SparcSubtarget *Subtarget) {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
if (TLI.verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
@@ -2805,7 +2857,7 @@ static SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG)
SDValue Val = DAG.getNode(ISD::BITCAST, dl, MVT::v2i32, St->getValue());
SDValue Chain = DAG.getStore(
St->getChain(), dl, Val, St->getBasePtr(), St->getPointerInfo(),
- St->isVolatile(), St->getMemOperand()->getFlags(), St->getAAInfo());
+ St->getAlignment(), St->getMemOperand()->getFlags(), St->getAAInfo());
return Chain;
}
@@ -3042,7 +3094,7 @@ MachineBasicBlock *
SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const {
switch (MI.getOpcode()) {
- default: llvm_unreachable("Unknown Custom Instruction!");
+ default: llvm_unreachable("Unknown SELECT_CC!");
case SP::SELECT_CC_Int_ICC:
case SP::SELECT_CC_FP_ICC:
case SP::SELECT_CC_DFP_ICC:
@@ -3059,6 +3111,7 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case SP::EH_SJLJ_LONGJMP32rr:
case SP::EH_SJLJ_LONGJMP32ri:
return emitEHSjLjLongJmp(MI, BB);
+
}
}
@@ -3329,11 +3382,8 @@ SparcTargetLowering::ConstraintType
SparcTargetLowering::getConstraintType(StringRef Constraint) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
- default:
- break;
- case 'f':
- case 'r':
- return C_RegisterClass;
+ default: break;
+ case 'r': return C_RegisterClass;
case 'I': // SIMM13
return C_Other;
}
@@ -3407,9 +3457,6 @@ SparcTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
MVT VT) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
- case 'f':
- return std::make_pair(0U, &SP::FPRegsRegClass);
-
case 'r':
if (VT == MVT::v2i32)
return std::make_pair(0U, &SP::IntPairRegClass);
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
index cfd3424..ea8ed83 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
@@ -118,19 +118,19 @@ static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC)
case SPCC::CPCC_A: return SPCC::CPCC_N;
case SPCC::CPCC_N: return SPCC::CPCC_A;
- case SPCC::CPCC_3: // Fall through
- case SPCC::CPCC_2: // Fall through
- case SPCC::CPCC_23: // Fall through
- case SPCC::CPCC_1: // Fall through
- case SPCC::CPCC_13: // Fall through
- case SPCC::CPCC_12: // Fall through
- case SPCC::CPCC_123: // Fall through
- case SPCC::CPCC_0: // Fall through
- case SPCC::CPCC_03: // Fall through
- case SPCC::CPCC_02: // Fall through
- case SPCC::CPCC_023: // Fall through
- case SPCC::CPCC_01: // Fall through
- case SPCC::CPCC_013: // Fall through
+ case SPCC::CPCC_3: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_2: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_23: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_1: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_13: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_12: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_123: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_0: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_03: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_02: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_023: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_01: LLVM_FALLTHROUGH;
+ case SPCC::CPCC_013: LLVM_FALLTHROUGH;
case SPCC::CPCC_012:
// "Opposite" code is not meaningful, as we don't know
// what the CoProc condition means here. The cond-code will
@@ -240,14 +240,16 @@ bool SparcInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}
-unsigned SparcInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned SparcInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"Sparc branch conditions should have one component!");
+ assert(!BytesAdded && "code size not handled");
if (Cond.empty()) {
assert(!FBB && "Unconditional branch with multiple successors!");
@@ -269,8 +271,10 @@ unsigned SparcInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return 2;
}
-unsigned SparcInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const
-{
+unsigned SparcInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
while (I != MBB.begin()) {
@@ -291,7 +295,7 @@ unsigned SparcInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const
return Count;
}
-bool SparcInstrInfo::ReverseBranchCondition(
+bool SparcInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 1);
SPCC::CondCodes CC = static_cast<SPCC::CondCodes>(Cond[0].getImm());
@@ -397,7 +401,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction *MF = MBB.getParent();
- const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore,
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
@@ -436,7 +440,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction *MF = MBB.getParent();
- const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad,
MFI.getObjectSize(FI), MFI.getObjectAlignment(FI));
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h
index 8ed97c1..c053cc4 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h
@@ -70,14 +70,16 @@ public:
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td
index cc55c9c..5a19c62 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -734,8 +734,8 @@ let Defs = [ICC], rd = 0 in {
// Section B.18 - Multiply Instructions, p. 113
let Defs = [Y] in {
- defm UMUL : F3_12np<"umul", 0b001010, IIC_iu_umul>;
- defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, simm13Op, IIC_iu_smul>;
+ defm UMUL : F3_12<"umul", 0b001010, umullohi, IntRegs, i32, simm13Op, IIC_iu_umul>;
+ defm SMUL : F3_12<"smul", 0b001011, smullohi, IntRegs, i32, simm13Op, IIC_iu_smul>;
}
let Defs = [Y, ICC] in {
@@ -1131,32 +1131,32 @@ def FQTOI : F3_3u<2, 0b110100, 0b011010011,
def FSTOD : F3_3u<2, 0b110100, 0b011001001,
(outs DFPRegs:$rd), (ins FPRegs:$rs2),
"fstod $rs2, $rd",
- [(set f64:$rd, (fextend f32:$rs2))],
+ [(set f64:$rd, (fpextend f32:$rs2))],
IIC_fpu_stod>;
def FSTOQ : F3_3u<2, 0b110100, 0b011001101,
(outs QFPRegs:$rd), (ins FPRegs:$rs2),
"fstoq $rs2, $rd",
- [(set f128:$rd, (fextend f32:$rs2))]>,
+ [(set f128:$rd, (fpextend f32:$rs2))]>,
Requires<[HasHardQuad]>;
def FDTOS : F3_3u<2, 0b110100, 0b011000110,
(outs FPRegs:$rd), (ins DFPRegs:$rs2),
"fdtos $rs2, $rd",
- [(set f32:$rd, (fround f64:$rs2))],
+ [(set f32:$rd, (fpround f64:$rs2))],
IIC_fpu_fast_instr>;
def FDTOQ : F3_3u<2, 0b110100, 0b011001110,
(outs QFPRegs:$rd), (ins DFPRegs:$rs2),
"fdtoq $rs2, $rd",
- [(set f128:$rd, (fextend f64:$rs2))]>,
+ [(set f128:$rd, (fpextend f64:$rs2))]>,
Requires<[HasHardQuad]>;
def FQTOS : F3_3u<2, 0b110100, 0b011000111,
(outs FPRegs:$rd), (ins QFPRegs:$rs2),
"fqtos $rs2, $rd",
- [(set f32:$rd, (fround f128:$rs2))]>,
+ [(set f32:$rd, (fpround f128:$rs2))]>,
Requires<[HasHardQuad]>;
def FQTOD : F3_3u<2, 0b110100, 0b011001011,
(outs DFPRegs:$rd), (ins QFPRegs:$rs2),
"fqtod $rs2, $rd",
- [(set f64:$rd, (fround f128:$rs2))]>,
+ [(set f64:$rd, (fpround f128:$rs2))]>,
Requires<[HasHardQuad]>;
// Floating-point Move Instructions, p. 144
@@ -1255,14 +1255,14 @@ let Predicates = [HasNoFsmuldFix] in
def FSMULD : F3_3<2, 0b110100, 0b001101001,
(outs DFPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
"fsmuld $rs1, $rs2, $rd",
- [(set f64:$rd, (fmul (fextend f32:$rs1),
- (fextend f32:$rs2)))],
+ [(set f64:$rd, (fmul (fpextend f32:$rs1),
+ (fpextend f32:$rs2)))],
IIC_fpu_muld>;
def FDMULQ : F3_3<2, 0b110100, 0b001101110,
(outs QFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fdmulq $rs1, $rs2, $rd",
- [(set f128:$rd, (fmul (fextend f64:$rs1),
- (fextend f64:$rs2)))]>,
+ [(set f128:$rd, (fmul (fpextend f64:$rs1),
+ (fpextend f64:$rs2)))]>,
Requires<[HasHardQuad]>;
// FDIVS generates an erratum on LEON processors, so by disabling this instruction
diff --git a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td
index d1ef3b1..6ecfddf 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td
+++ b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td
@@ -331,7 +331,6 @@ def IntRegs : RegisterClass<"SP", [i32, i64], 32,
(sequence "L%u", 0, 7),
(sequence "O%u", 0, 7))>;
-
// Should be in the same order as IntRegs.
def IntPair : RegisterClass<"SP", [v2i32], 64,
(add I0_I1, I2_I3, I4_I5, I6_I7,
diff --git a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp
index a6a4dc5..43ddef3 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp
@@ -40,16 +40,11 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU,
HasLeonCasa = false;
HasUmacSmac = false;
PerformSDIVReplace = false;
- FixCallImmediates = false;
- IgnoreZeroFlag = false;
- InsertNOPDoublePrecision = false;
+ InsertNOPLoad = false;
FixFSMULD = false;
ReplaceFMULS = false;
- PreventRoundChange = false;
FixAllFDIVSQRT = false;
- InsertNOPLoad = false;
- FlushCacheLineSWAP = false;
- InsertNOPsLoadStore = false;
+ DetectRoundChange = false;
// Determine default and user specified characteristics
std::string CPUName = CPU;
diff --git a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h
index 42d6936..fa42da4 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h
+++ b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h
@@ -48,14 +48,8 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
bool FixFSMULD;
bool ReplaceFMULS;
bool FixAllFDIVSQRT;
- bool UseSoftFpu;
+ bool DetectRoundChange;
bool PerformSDIVReplace;
- bool FixCallImmediates;
- bool IgnoreZeroFlag;
- bool InsertNOPDoublePrecision;
- bool PreventRoundChange;
- bool FlushCacheLineSWAP;
- bool InsertNOPsLoadStore;
SparcInstrInfo InstrInfo;
SparcTargetLowering TLInfo;
@@ -93,20 +87,14 @@ public:
bool useSoftFloat() const { return UseSoftFloat; }
// Leon options
- bool useSoftFpu() const { return UseSoftFpu; }
- bool hasLeonCasa() const { return HasLeonCasa; }
bool hasUmacSmac() const { return HasUmacSmac; }
bool performSDIVReplace() const { return PerformSDIVReplace; }
- bool fixCallImmediates() const { return FixCallImmediates; }
- bool ignoreZeroFlag() const { return IgnoreZeroFlag; }
- bool insertNOPDoublePrecision() const { return InsertNOPDoublePrecision; }
+ bool hasLeonCasa() const { return HasLeonCasa; }
+ bool insertNOPLoad() const { return InsertNOPLoad; }
bool fixFSMULD() const { return FixFSMULD; }
bool replaceFMULS() const { return ReplaceFMULS; }
- bool preventRoundChange() const { return PreventRoundChange; }
bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; }
- bool flushCacheLineSWAP() const { return FlushCacheLineSWAP; }
- bool insertNOPsLoadStore() const { return InsertNOPsLoadStore; }
- bool insertNOPLoad() const { return InsertNOPLoad; }
+ bool detectRoundChange() const { return DetectRoundChange; }
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp b/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
index 17fe86a..4ae6406 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
@@ -22,9 +22,9 @@ using namespace llvm;
extern "C" void LLVMInitializeSparcTarget() {
// Register the target.
- RegisterTargetMachine<SparcV8TargetMachine> X(TheSparcTarget);
- RegisterTargetMachine<SparcV9TargetMachine> Y(TheSparcV9Target);
- RegisterTargetMachine<SparcelTargetMachine> Z(TheSparcelTarget);
+ RegisterTargetMachine<SparcV8TargetMachine> X(getTheSparcTarget());
+ RegisterTargetMachine<SparcV9TargetMachine> Y(getTheSparcV9Target());
+ RegisterTargetMachine<SparcelTargetMachine> Z(getTheSparcelTarget());
}
static std::string computeDataLayout(const Triple &T, bool is64Bit) {
@@ -76,7 +76,7 @@ SparcTargetMachine::SparcTargetMachine(const Target &T, const Triple &TT,
SparcTargetMachine::~SparcTargetMachine() {}
-const SparcSubtarget *
+const SparcSubtarget *
SparcTargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
Attribute FSAttr = F.getFnAttribute("target-features");
@@ -95,7 +95,7 @@ SparcTargetMachine::getSubtargetImpl(const Function &F) const {
F.hasFnAttribute("use-soft-float") &&
F.getFnAttribute("use-soft-float").getValueAsString() == "true";
- if (softFloat)
+ if (softFloat)
FS += FS.empty() ? "+soft-float" : ",+soft-float";
auto &I = SubtargetMap[CPU + FS];
@@ -115,7 +115,7 @@ namespace {
class SparcPassConfig : public TargetPassConfig {
public:
SparcPassConfig(SparcTargetMachine *TM, PassManagerBase &PM)
- : TargetPassConfig(TM, PM) {}
+ : TargetPassConfig(TM, PM) {}
SparcTargetMachine &getSparcTargetMachine() const {
return getTM<SparcTargetMachine>();
@@ -142,46 +142,31 @@ bool SparcPassConfig::addInstSelector() {
return false;
}
-void SparcPassConfig::addPreEmitPass() {
+void SparcPassConfig::addPreEmitPass(){
addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine()));
- if (this->getSparcTargetMachine().getSubtargetImpl()->ignoreZeroFlag()) {
- addPass(new IgnoreZeroFlag(getSparcTargetMachine()));
- }
- if (this->getSparcTargetMachine().getSubtargetImpl()->performSDIVReplace()) {
- addPass(new ReplaceSDIV(getSparcTargetMachine()));
- }
- if (this->getSparcTargetMachine().getSubtargetImpl()->fixCallImmediates()) {
- addPass(new FixCALL(getSparcTargetMachine()));
+
+ if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad())
+ {
+ addPass(new InsertNOPLoad(getSparcTargetMachine()));
}
- if (this->getSparcTargetMachine().getSubtargetImpl()->fixFSMULD()) {
+ if (this->getSparcTargetMachine().getSubtargetImpl()->fixFSMULD())
+ {
addPass(new FixFSMULD(getSparcTargetMachine()));
}
- if (this->getSparcTargetMachine().getSubtargetImpl()->replaceFMULS()) {
+ if (this->getSparcTargetMachine().getSubtargetImpl()->replaceFMULS())
+ {
addPass(new ReplaceFMULS(getSparcTargetMachine()));
}
- if (this->getSparcTargetMachine().getSubtargetImpl()->preventRoundChange()) {
- addPass(new PreventRoundChange(getSparcTargetMachine()));
+ if (this->getSparcTargetMachine().getSubtargetImpl()->detectRoundChange()) {
+ addPass(new DetectRoundChange(getSparcTargetMachine()));
}
- if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT()) {
+ if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT())
+ {
addPass(new FixAllFDIVSQRT(getSparcTargetMachine()));
}
- if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPsLoadStore()) {
- addPass(new InsertNOPsLoadStore(getSparcTargetMachine()));
- }
- if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad()) {
- addPass(new InsertNOPLoad(getSparcTargetMachine()));
- }
- if (this->getSparcTargetMachine().getSubtargetImpl()->flushCacheLineSWAP()) {
- addPass(new FlushCacheLineSWAP(getSparcTargetMachine()));
- }
- if (this->getSparcTargetMachine()
- .getSubtargetImpl()
- ->insertNOPDoublePrecision()) {
- addPass(new InsertNOPDoublePrecision(getSparcTargetMachine()));
- }
}
-void SparcV8TargetMachine::anchor() {}
+void SparcV8TargetMachine::anchor() { }
SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
@@ -191,7 +176,7 @@ SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
CodeGenOpt::Level OL)
: SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
-void SparcV9TargetMachine::anchor() {}
+void SparcV9TargetMachine::anchor() { }
SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
index 412e124..8fdde15 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
@@ -16,20 +16,19 @@
using namespace llvm;
const MCExpr *SparcELFTargetObjectFile::getTTypeGlobalReference(
- const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
- const TargetMachine &TM, MachineModuleInfo *MMI,
- MCStreamer &Streamer) const {
+ const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM,
+ MachineModuleInfo *MMI, MCStreamer &Streamer) const {
if (Encoding & dwarf::DW_EH_PE_pcrel) {
MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>();
- MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, ".DW.stub", Mang, TM);
+ MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, ".DW.stub", TM);
// Add information about the stub reference to ELFMMI so that the stub
// gets emitted by the asmprinter.
MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym);
if (!StubSym.getPointer()) {
- MCSymbol *Sym = TM.getSymbol(GV, Mang);
+ MCSymbol *Sym = TM.getSymbol(GV);
StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage());
}
@@ -38,6 +37,6 @@ const MCExpr *SparcELFTargetObjectFile::getTTypeGlobalReference(
MCSymbolRefExpr::create(SSym, Ctx), Ctx);
}
- return TargetLoweringObjectFileELF::getTTypeGlobalReference(
- GV, Encoding, Mang, TM, MMI, Streamer);
+ return TargetLoweringObjectFileELF::getTTypeGlobalReference(GV, Encoding, TM,
+ MMI, Streamer);
}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
index 76c8cca..fe88006 100644
--- a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
@@ -23,11 +23,11 @@ public:
TargetLoweringObjectFileELF()
{}
- const MCExpr *
- getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
- Mangler &Mang, const TargetMachine &TM,
- MachineModuleInfo *MMI,
- MCStreamer &Streamer) const override;
+ const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
+ unsigned Encoding,
+ const TargetMachine &TM,
+ MachineModuleInfo *MMI,
+ MCStreamer &Streamer) const override;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp b/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp
index ab1c6be..66178ac 100644
--- a/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp
@@ -12,15 +12,24 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheSparcTarget;
-Target llvm::TheSparcV9Target;
-Target llvm::TheSparcelTarget;
+Target &llvm::getTheSparcTarget() {
+ static Target TheSparcTarget;
+ return TheSparcTarget;
+}
+Target &llvm::getTheSparcV9Target() {
+ static Target TheSparcV9Target;
+ return TheSparcV9Target;
+}
+Target &llvm::getTheSparcelTarget() {
+ static Target TheSparcelTarget;
+ return TheSparcelTarget;
+}
extern "C" void LLVMInitializeSparcTargetInfo() {
- RegisterTarget<Triple::sparc, /*HasJIT=*/true> X(TheSparcTarget, "sparc",
+ RegisterTarget<Triple::sparc, /*HasJIT=*/true> X(getTheSparcTarget(), "sparc",
"Sparc");
- RegisterTarget<Triple::sparcv9, /*HasJIT=*/true> Y(TheSparcV9Target,
+ RegisterTarget<Triple::sparcv9, /*HasJIT=*/true> Y(getTheSparcV9Target(),
"sparcv9", "Sparc V9");
- RegisterTarget<Triple::sparcel, /*HasJIT=*/true> Z(TheSparcelTarget,
+ RegisterTarget<Triple::sparcel, /*HasJIT=*/true> Z(getTheSparcelTarget(),
"sparcel", "Sparc LE");
}
diff --git a/contrib/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/contrib/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
index 3923614..a94717c 100644
--- a/contrib/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -12,6 +12,7 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCStreamer.h"
@@ -42,13 +43,15 @@ enum RegisterKind {
FP128Reg,
VR32Reg,
VR64Reg,
- VR128Reg
+ VR128Reg,
+ AR32Reg,
};
enum MemoryKind {
BDMem,
BDXMem,
BDLMem,
+ BDRMem,
BDVMem
};
@@ -59,7 +62,6 @@ private:
KindInvalid,
KindToken,
KindReg,
- KindAccessReg,
KindImm,
KindImmTLS,
KindMem
@@ -98,7 +100,10 @@ private:
unsigned MemKind : 4;
unsigned RegKind : 4;
const MCExpr *Disp;
- const MCExpr *Length;
+ union {
+ const MCExpr *Imm;
+ unsigned Reg;
+ } Length;
};
// Imm is an immediate operand, and Sym is an optional TLS symbol
@@ -111,7 +116,6 @@ private:
union {
TokenOp Token;
RegOp Reg;
- unsigned AccessReg;
const MCExpr *Imm;
ImmTLSOp ImmTLS;
MemOp Mem;
@@ -150,12 +154,6 @@ public:
return Op;
}
static std::unique_ptr<SystemZOperand>
- createAccessReg(unsigned Num, SMLoc StartLoc, SMLoc EndLoc) {
- auto Op = make_unique<SystemZOperand>(KindAccessReg, StartLoc, EndLoc);
- Op->AccessReg = Num;
- return Op;
- }
- static std::unique_ptr<SystemZOperand>
createImm(const MCExpr *Expr, SMLoc StartLoc, SMLoc EndLoc) {
auto Op = make_unique<SystemZOperand>(KindImm, StartLoc, EndLoc);
Op->Imm = Expr;
@@ -163,15 +161,18 @@ public:
}
static std::unique_ptr<SystemZOperand>
createMem(MemoryKind MemKind, RegisterKind RegKind, unsigned Base,
- const MCExpr *Disp, unsigned Index, const MCExpr *Length,
- SMLoc StartLoc, SMLoc EndLoc) {
+ const MCExpr *Disp, unsigned Index, const MCExpr *LengthImm,
+ unsigned LengthReg, SMLoc StartLoc, SMLoc EndLoc) {
auto Op = make_unique<SystemZOperand>(KindMem, StartLoc, EndLoc);
Op->Mem.MemKind = MemKind;
Op->Mem.RegKind = RegKind;
Op->Mem.Base = Base;
Op->Mem.Index = Index;
Op->Mem.Disp = Disp;
- Op->Mem.Length = Length;
+ if (MemKind == BDLMem)
+ Op->Mem.Length.Imm = LengthImm;
+ if (MemKind == BDRMem)
+ Op->Mem.Length.Reg = LengthReg;
return Op;
}
static std::unique_ptr<SystemZOperand>
@@ -204,12 +205,6 @@ public:
return Reg.Num;
}
- // Access register operands. Access registers aren't exposed to LLVM
- // as registers.
- bool isAccessReg() const {
- return Kind == KindAccessReg;
- }
-
// Immediate operands.
bool isImm() const override {
return Kind == KindImm;
@@ -248,14 +243,7 @@ public:
return isMem(MemKind, RegKind) && inRange(Mem.Disp, -524288, 524287);
}
bool isMemDisp12Len8(RegisterKind RegKind) const {
- return isMemDisp12(BDLMem, RegKind) && inRange(Mem.Length, 1, 0x100);
- }
- void addBDVAddrOperands(MCInst &Inst, unsigned N) const {
- assert(N == 3 && "Invalid number of operands");
- assert(isMem(BDVMem) && "Invalid operand type");
- Inst.addOperand(MCOperand::createReg(Mem.Base));
- addExpr(Inst, Mem.Disp);
- Inst.addOperand(MCOperand::createReg(Mem.Index));
+ return isMemDisp12(BDLMem, RegKind) && inRange(Mem.Length.Imm, 1, 0x100);
}
// Override MCParsedAsmOperand.
@@ -269,11 +257,6 @@ public:
assert(N == 1 && "Invalid number of operands");
Inst.addOperand(MCOperand::createReg(getReg()));
}
- void addAccessRegOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands");
- assert(Kind == KindAccessReg && "Invalid operand type");
- Inst.addOperand(MCOperand::createImm(AccessReg));
- }
void addImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands");
addExpr(Inst, getImm());
@@ -296,7 +279,21 @@ public:
assert(isMem(BDLMem) && "Invalid operand type");
Inst.addOperand(MCOperand::createReg(Mem.Base));
addExpr(Inst, Mem.Disp);
- addExpr(Inst, Mem.Length);
+ addExpr(Inst, Mem.Length.Imm);
+ }
+ void addBDRAddrOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 3 && "Invalid number of operands");
+ assert(isMem(BDRMem) && "Invalid operand type");
+ Inst.addOperand(MCOperand::createReg(Mem.Base));
+ addExpr(Inst, Mem.Disp);
+ Inst.addOperand(MCOperand::createReg(Mem.Length.Reg));
+ }
+ void addBDVAddrOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 3 && "Invalid number of operands");
+ assert(isMem(BDVMem) && "Invalid operand type");
+ Inst.addOperand(MCOperand::createReg(Mem.Base));
+ addExpr(Inst, Mem.Disp);
+ Inst.addOperand(MCOperand::createReg(Mem.Index));
}
void addImmTLSOperands(MCInst &Inst, unsigned N) const {
assert(N == 2 && "Invalid number of operands");
@@ -322,6 +319,8 @@ public:
bool isVR64() const { return isReg(VR64Reg); }
bool isVF128() const { return false; }
bool isVR128() const { return isReg(VR128Reg); }
+ bool isAR32() const { return isReg(AR32Reg); }
+ bool isAnyReg() const { return (isReg() || isImm(0, 15)); }
bool isBDAddr32Disp12() const { return isMemDisp12(BDMem, ADDR32Reg); }
bool isBDAddr32Disp20() const { return isMemDisp20(BDMem, ADDR32Reg); }
bool isBDAddr64Disp12() const { return isMemDisp12(BDMem, ADDR64Reg); }
@@ -329,6 +328,7 @@ public:
bool isBDXAddr64Disp12() const { return isMemDisp12(BDXMem, ADDR64Reg); }
bool isBDXAddr64Disp20() const { return isMemDisp20(BDXMem, ADDR64Reg); }
bool isBDLAddr64Disp12Len8() const { return isMemDisp12Len8(ADDR64Reg); }
+ bool isBDRAddr64Disp12() const { return isMemDisp12(BDRMem, ADDR64Reg); }
bool isBDVAddr64Disp12() const { return isMemDisp12(BDVMem, ADDR64Reg); }
bool isU1Imm() const { return isImm(0, 1); }
bool isU2Imm() const { return isImm(0, 3); }
@@ -342,6 +342,7 @@ public:
bool isS16Imm() const { return isImm(-32768, 32767); }
bool isU32Imm() const { return isImm(0, (1LL << 32) - 1); }
bool isS32Imm() const { return isImm(-(1LL << 31), (1LL << 31) - 1); }
+ bool isU48Imm() const { return isImm(0, (1LL << 48) - 1); }
};
class SystemZAsmParser : public MCTargetAsmParser {
@@ -354,7 +355,7 @@ private:
RegGR,
RegFP,
RegV,
- RegAccess
+ RegAR
};
struct Register {
RegisterGroup Group;
@@ -371,9 +372,14 @@ private:
RegisterGroup Group, const unsigned *Regs,
RegisterKind Kind);
- bool parseAddress(unsigned &Base, const MCExpr *&Disp,
- unsigned &Index, bool &IsVector, const MCExpr *&Length,
- const unsigned *Regs, RegisterKind RegKind);
+ OperandMatchResultTy parseAnyRegister(OperandVector &Operands);
+
+ bool parseAddress(bool &HaveReg1, Register &Reg1,
+ bool &HaveReg2, Register &Reg2,
+ const MCExpr *&Disp, const MCExpr *&Length);
+ bool parseAddressRegister(Register &Reg);
+
+ bool ParseDirectiveInsn(SMLoc L);
OperandMatchResultTy parseAddress(OperandVector &Operands,
MemoryKind MemKind, const unsigned *Regs,
@@ -454,6 +460,12 @@ public:
OperandMatchResultTy parseVR128(OperandVector &Operands) {
return parseRegister(Operands, RegV, SystemZMC::VR128Regs, VR128Reg);
}
+ OperandMatchResultTy parseAR32(OperandVector &Operands) {
+ return parseRegister(Operands, RegAR, SystemZMC::AR32Regs, AR32Reg);
+ }
+ OperandMatchResultTy parseAnyReg(OperandVector &Operands) {
+ return parseAnyRegister(Operands);
+ }
OperandMatchResultTy parseBDAddr32(OperandVector &Operands) {
return parseAddress(Operands, BDMem, SystemZMC::GR32Regs, ADDR32Reg);
}
@@ -466,13 +478,21 @@ public:
OperandMatchResultTy parseBDLAddr64(OperandVector &Operands) {
return parseAddress(Operands, BDLMem, SystemZMC::GR64Regs, ADDR64Reg);
}
+ OperandMatchResultTy parseBDRAddr64(OperandVector &Operands) {
+ return parseAddress(Operands, BDRMem, SystemZMC::GR64Regs, ADDR64Reg);
+ }
OperandMatchResultTy parseBDVAddr64(OperandVector &Operands) {
return parseAddress(Operands, BDVMem, SystemZMC::GR64Regs, ADDR64Reg);
}
- OperandMatchResultTy parseAccessReg(OperandVector &Operands);
+ OperandMatchResultTy parsePCRel12(OperandVector &Operands) {
+ return parsePCRel(Operands, -(1LL << 12), (1LL << 12) - 1, false);
+ }
OperandMatchResultTy parsePCRel16(OperandVector &Operands) {
return parsePCRel(Operands, -(1LL << 16), (1LL << 16) - 1, false);
}
+ OperandMatchResultTy parsePCRel24(OperandVector &Operands) {
+ return parsePCRel(Operands, -(1LL << 24), (1LL << 24) - 1, false);
+ }
OperandMatchResultTy parsePCRel32(OperandVector &Operands) {
return parsePCRel(Operands, -(1LL << 32), (1LL << 32) - 1, false);
}
@@ -490,6 +510,83 @@ public:
#define GET_MATCHER_IMPLEMENTATION
#include "SystemZGenAsmMatcher.inc"
+// Used for the .insn directives; contains information needed to parse the
+// operands in the directive.
+struct InsnMatchEntry {
+ StringRef Format;
+ uint64_t Opcode;
+ int32_t NumOperands;
+ MatchClassKind OperandKinds[5];
+};
+
+// For equal_range comparison.
+struct CompareInsn {
+ bool operator() (const InsnMatchEntry &LHS, StringRef RHS) {
+ return LHS.Format < RHS;
+ }
+ bool operator() (StringRef LHS, const InsnMatchEntry &RHS) {
+ return LHS < RHS.Format;
+ }
+ bool operator() (const InsnMatchEntry &LHS, const InsnMatchEntry &RHS) {
+ return LHS.Format < RHS.Format;
+ }
+};
+
+// Table initializing information for parsing the .insn directive.
+static struct InsnMatchEntry InsnMatchTable[] = {
+ /* Format, Opcode, NumOperands, OperandKinds */
+ { "e", SystemZ::InsnE, 1,
+ { MCK_U16Imm } },
+ { "ri", SystemZ::InsnRI, 3,
+ { MCK_U32Imm, MCK_AnyReg, MCK_S16Imm } },
+ { "rie", SystemZ::InsnRIE, 4,
+ { MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_PCRel16 } },
+ { "ril", SystemZ::InsnRIL, 3,
+ { MCK_U48Imm, MCK_AnyReg, MCK_PCRel32 } },
+ { "rilu", SystemZ::InsnRILU, 3,
+ { MCK_U48Imm, MCK_AnyReg, MCK_U32Imm } },
+ { "ris", SystemZ::InsnRIS, 5,
+ { MCK_U48Imm, MCK_AnyReg, MCK_S8Imm, MCK_U4Imm, MCK_BDAddr64Disp12 } },
+ { "rr", SystemZ::InsnRR, 3,
+ { MCK_U16Imm, MCK_AnyReg, MCK_AnyReg } },
+ { "rre", SystemZ::InsnRRE, 3,
+ { MCK_U32Imm, MCK_AnyReg, MCK_AnyReg } },
+ { "rrf", SystemZ::InsnRRF, 5,
+ { MCK_U32Imm, MCK_AnyReg, MCK_AnyReg, MCK_AnyReg, MCK_U4Imm } },
+ { "rrs", SystemZ::InsnRRS, 5,
+ { MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_U4Imm, MCK_BDAddr64Disp12 } },
+ { "rs", SystemZ::InsnRS, 4,
+ { MCK_U32Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDAddr64Disp12 } },
+ { "rse", SystemZ::InsnRSE, 4,
+ { MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDAddr64Disp12 } },
+ { "rsi", SystemZ::InsnRSI, 4,
+ { MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_PCRel16 } },
+ { "rsy", SystemZ::InsnRSY, 4,
+ { MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDAddr64Disp20 } },
+ { "rx", SystemZ::InsnRX, 3,
+ { MCK_U32Imm, MCK_AnyReg, MCK_BDXAddr64Disp12 } },
+ { "rxe", SystemZ::InsnRXE, 3,
+ { MCK_U48Imm, MCK_AnyReg, MCK_BDXAddr64Disp12 } },
+ { "rxf", SystemZ::InsnRXF, 4,
+ { MCK_U48Imm, MCK_AnyReg, MCK_AnyReg, MCK_BDXAddr64Disp12 } },
+ { "rxy", SystemZ::InsnRXY, 3,
+ { MCK_U48Imm, MCK_AnyReg, MCK_BDXAddr64Disp20 } },
+ { "s", SystemZ::InsnS, 2,
+ { MCK_U32Imm, MCK_BDAddr64Disp12 } },
+ { "si", SystemZ::InsnSI, 3,
+ { MCK_U32Imm, MCK_BDAddr64Disp12, MCK_S8Imm } },
+ { "sil", SystemZ::InsnSIL, 3,
+ { MCK_U48Imm, MCK_BDAddr64Disp12, MCK_U16Imm } },
+ { "siy", SystemZ::InsnSIY, 3,
+ { MCK_U48Imm, MCK_BDAddr64Disp20, MCK_U8Imm } },
+ { "ss", SystemZ::InsnSS, 4,
+ { MCK_U48Imm, MCK_BDXAddr64Disp12, MCK_BDAddr64Disp12, MCK_AnyReg } },
+ { "sse", SystemZ::InsnSSE, 3,
+ { MCK_U48Imm, MCK_BDAddr64Disp12, MCK_BDAddr64Disp12 } },
+ { "ssf", SystemZ::InsnSSF, 4,
+ { MCK_U48Imm, MCK_BDAddr64Disp12, MCK_BDAddr64Disp12, MCK_AnyReg } }
+};
+
void SystemZOperand::print(raw_ostream &OS) const {
llvm_unreachable("Not implemented");
}
@@ -525,7 +622,7 @@ bool SystemZAsmParser::parseRegister(Register &Reg) {
else if (Prefix == 'v' && Reg.Num < 32)
Reg.Group = RegV;
else if (Prefix == 'a' && Reg.Num < 16)
- Reg.Group = RegAccess;
+ Reg.Group = RegAR;
else
return Error(Reg.StartLoc, "invalid register");
@@ -556,7 +653,7 @@ bool SystemZAsmParser::parseRegister(Register &Reg, RegisterGroup Group,
}
// Parse a register and add it to Operands. The other arguments are as above.
-SystemZAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SystemZAsmParser::parseRegister(OperandVector &Operands, RegisterGroup Group,
const unsigned *Regs, RegisterKind Kind) {
if (Parser.getTok().isNot(AsmToken::Percent))
@@ -572,58 +669,96 @@ SystemZAsmParser::parseRegister(OperandVector &Operands, RegisterGroup Group,
return MatchOperand_Success;
}
-// Parse a memory operand into Base, Disp, Index and Length.
-// Regs maps asm register numbers to LLVM register numbers and RegKind
-// says what kind of address register we're using (ADDR32Reg or ADDR64Reg).
-bool SystemZAsmParser::parseAddress(unsigned &Base, const MCExpr *&Disp,
- unsigned &Index, bool &IsVector,
- const MCExpr *&Length, const unsigned *Regs,
- RegisterKind RegKind) {
+// Parse any type of register (including integers) and add it to Operands.
+OperandMatchResultTy
+SystemZAsmParser::parseAnyRegister(OperandVector &Operands) {
+ // Handle integer values.
+ if (Parser.getTok().is(AsmToken::Integer)) {
+ const MCExpr *Register;
+ SMLoc StartLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(Register))
+ return MatchOperand_ParseFail;
+
+ if (auto *CE = dyn_cast<MCConstantExpr>(Register)) {
+ int64_t Value = CE->getValue();
+ if (Value < 0 || Value > 15) {
+ Error(StartLoc, "invalid register");
+ return MatchOperand_ParseFail;
+ }
+ }
+
+ SMLoc EndLoc =
+ SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+
+ Operands.push_back(SystemZOperand::createImm(Register, StartLoc, EndLoc));
+ }
+ else {
+ Register Reg;
+ if (parseRegister(Reg))
+ return MatchOperand_ParseFail;
+
+ // Map to the correct register kind.
+ RegisterKind Kind;
+ unsigned RegNo;
+ if (Reg.Group == RegGR) {
+ Kind = GR64Reg;
+ RegNo = SystemZMC::GR64Regs[Reg.Num];
+ }
+ else if (Reg.Group == RegFP) {
+ Kind = FP64Reg;
+ RegNo = SystemZMC::FP64Regs[Reg.Num];
+ }
+ else if (Reg.Group == RegV) {
+ Kind = VR128Reg;
+ RegNo = SystemZMC::VR128Regs[Reg.Num];
+ }
+ else if (Reg.Group == RegAR) {
+ Kind = AR32Reg;
+ RegNo = SystemZMC::AR32Regs[Reg.Num];
+ }
+ else {
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(SystemZOperand::createReg(Kind, RegNo,
+ Reg.StartLoc, Reg.EndLoc));
+ }
+ return MatchOperand_Success;
+}
+
+// Parse a memory operand into Reg1, Reg2, Disp, and Length.
+bool SystemZAsmParser::parseAddress(bool &HaveReg1, Register &Reg1,
+ bool &HaveReg2, Register &Reg2,
+ const MCExpr *&Disp,
+ const MCExpr *&Length) {
// Parse the displacement, which must always be present.
if (getParser().parseExpression(Disp))
return true;
// Parse the optional base and index.
- Index = 0;
- Base = 0;
- IsVector = false;
+ HaveReg1 = false;
+ HaveReg2 = false;
Length = nullptr;
if (getLexer().is(AsmToken::LParen)) {
Parser.Lex();
if (getLexer().is(AsmToken::Percent)) {
- // Parse the first register and decide whether it's a base or an index.
- Register Reg;
- if (parseRegister(Reg))
+ // Parse the first register.
+ HaveReg1 = true;
+ if (parseRegister(Reg1))
return true;
- if (Reg.Group == RegV) {
- // A vector index register. The base register is optional.
- IsVector = true;
- Index = SystemZMC::VR128Regs[Reg.Num];
- } else if (Reg.Group == RegGR) {
- if (Reg.Num == 0)
- return Error(Reg.StartLoc, "%r0 used in an address");
- // If the are two registers, the first one is the index and the
- // second is the base.
- if (getLexer().is(AsmToken::Comma))
- Index = Regs[Reg.Num];
- else
- Base = Regs[Reg.Num];
- } else
- return Error(Reg.StartLoc, "invalid address register");
} else {
// Parse the length.
if (getParser().parseExpression(Length))
return true;
}
- // Check whether there's a second register. It's the base if so.
+ // Check whether there's a second register.
if (getLexer().is(AsmToken::Comma)) {
Parser.Lex();
- Register Reg;
- if (parseRegister(Reg, RegGR, Regs, RegKind))
+ HaveReg2 = true;
+ if (parseRegister(Reg2))
return true;
- Base = Reg.Num;
}
// Consume the closing bracket.
@@ -634,56 +769,255 @@ bool SystemZAsmParser::parseAddress(unsigned &Base, const MCExpr *&Disp,
return false;
}
+// Verify that Reg is a valid address register (base or index).
+bool
+SystemZAsmParser::parseAddressRegister(Register &Reg) {
+ if (Reg.Group == RegV) {
+ Error(Reg.StartLoc, "invalid use of vector addressing");
+ return true;
+ } else if (Reg.Group != RegGR) {
+ Error(Reg.StartLoc, "invalid address register");
+ return true;
+ } else if (Reg.Num == 0) {
+ Error(Reg.StartLoc, "%r0 used in an address");
+ return true;
+ }
+ return false;
+}
+
// Parse a memory operand and add it to Operands. The other arguments
// are as above.
-SystemZAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SystemZAsmParser::parseAddress(OperandVector &Operands, MemoryKind MemKind,
const unsigned *Regs, RegisterKind RegKind) {
SMLoc StartLoc = Parser.getTok().getLoc();
- unsigned Base, Index;
- bool IsVector;
+ unsigned Base = 0, Index = 0, LengthReg = 0;
+ Register Reg1, Reg2;
+ bool HaveReg1, HaveReg2;
const MCExpr *Disp;
const MCExpr *Length;
- if (parseAddress(Base, Disp, Index, IsVector, Length, Regs, RegKind))
- return MatchOperand_ParseFail;
-
- if (IsVector && MemKind != BDVMem) {
- Error(StartLoc, "invalid use of vector addressing");
- return MatchOperand_ParseFail;
- }
-
- if (!IsVector && MemKind == BDVMem) {
- Error(StartLoc, "vector index required in address");
- return MatchOperand_ParseFail;
- }
-
- if (Index && MemKind != BDXMem && MemKind != BDVMem) {
- Error(StartLoc, "invalid use of indexed addressing");
+ if (parseAddress(HaveReg1, Reg1, HaveReg2, Reg2, Disp, Length))
return MatchOperand_ParseFail;
- }
- if (Length && MemKind != BDLMem) {
- Error(StartLoc, "invalid use of length addressing");
- return MatchOperand_ParseFail;
- }
-
- if (!Length && MemKind == BDLMem) {
- Error(StartLoc, "missing length in address");
- return MatchOperand_ParseFail;
+ switch (MemKind) {
+ case BDMem:
+ // If we have Reg1, it must be an address register.
+ if (HaveReg1) {
+ if (parseAddressRegister(Reg1))
+ return MatchOperand_ParseFail;
+ Base = Regs[Reg1.Num];
+ }
+ // There must be no Reg2 or length.
+ if (Length) {
+ Error(StartLoc, "invalid use of length addressing");
+ return MatchOperand_ParseFail;
+ }
+ if (HaveReg2) {
+ Error(StartLoc, "invalid use of indexed addressing");
+ return MatchOperand_ParseFail;
+ }
+ break;
+ case BDXMem:
+ // If we have Reg1, it must be an address register.
+ if (HaveReg1) {
+ if (parseAddressRegister(Reg1))
+ return MatchOperand_ParseFail;
+ // If the are two registers, the first one is the index and the
+ // second is the base.
+ if (HaveReg2)
+ Index = Regs[Reg1.Num];
+ else
+ Base = Regs[Reg1.Num];
+ }
+ // If we have Reg2, it must be an address register.
+ if (HaveReg2) {
+ if (parseAddressRegister(Reg2))
+ return MatchOperand_ParseFail;
+ Base = Regs[Reg2.Num];
+ }
+ // There must be no length.
+ if (Length) {
+ Error(StartLoc, "invalid use of length addressing");
+ return MatchOperand_ParseFail;
+ }
+ break;
+ case BDLMem:
+ // If we have Reg2, it must be an address register.
+ if (HaveReg2) {
+ if (parseAddressRegister(Reg2))
+ return MatchOperand_ParseFail;
+ Base = Regs[Reg2.Num];
+ }
+ // We cannot support base+index addressing.
+ if (HaveReg1 && HaveReg2) {
+ Error(StartLoc, "invalid use of indexed addressing");
+ return MatchOperand_ParseFail;
+ }
+ // We must have a length.
+ if (!Length) {
+ Error(StartLoc, "missing length in address");
+ return MatchOperand_ParseFail;
+ }
+ break;
+ case BDRMem:
+ // We must have Reg1, and it must be a GPR.
+ if (!HaveReg1 || Reg1.Group != RegGR) {
+ Error(StartLoc, "invalid operand for instruction");
+ return MatchOperand_ParseFail;
+ }
+ LengthReg = SystemZMC::GR64Regs[Reg1.Num];
+ // If we have Reg2, it must be an address register.
+ if (HaveReg2) {
+ if (parseAddressRegister(Reg2))
+ return MatchOperand_ParseFail;
+ Base = Regs[Reg2.Num];
+ }
+ // There must be no length.
+ if (Length) {
+ Error(StartLoc, "invalid use of length addressing");
+ return MatchOperand_ParseFail;
+ }
+ break;
+ case BDVMem:
+ // We must have Reg1, and it must be a vector register.
+ if (!HaveReg1 || Reg1.Group != RegV) {
+ Error(StartLoc, "vector index required in address");
+ return MatchOperand_ParseFail;
+ }
+ Index = SystemZMC::VR128Regs[Reg1.Num];
+ // If we have Reg2, it must be an address register.
+ if (HaveReg2) {
+ if (parseAddressRegister(Reg2))
+ return MatchOperand_ParseFail;
+ Base = Regs[Reg2.Num];
+ }
+ // There must be no length.
+ if (Length) {
+ Error(StartLoc, "invalid use of length addressing");
+ return MatchOperand_ParseFail;
+ }
+ break;
}
SMLoc EndLoc =
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(SystemZOperand::createMem(MemKind, RegKind, Base, Disp,
- Index, Length, StartLoc,
- EndLoc));
+ Index, Length, LengthReg,
+ StartLoc, EndLoc));
return MatchOperand_Success;
}
bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) {
+ StringRef IDVal = DirectiveID.getIdentifier();
+
+ if (IDVal == ".insn")
+ return ParseDirectiveInsn(DirectiveID.getLoc());
+
return true;
}
+/// ParseDirectiveInsn
+/// ::= .insn [ format, encoding, (operands (, operands)*) ]
+bool SystemZAsmParser::ParseDirectiveInsn(SMLoc L) {
+ MCAsmParser &Parser = getParser();
+
+ // Expect instruction format as identifier.
+ StringRef Format;
+ SMLoc ErrorLoc = Parser.getTok().getLoc();
+ if (Parser.parseIdentifier(Format))
+ return Error(ErrorLoc, "expected instruction format");
+
+ SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> Operands;
+
+ // Find entry for this format in InsnMatchTable.
+ auto EntryRange =
+ std::equal_range(std::begin(InsnMatchTable), std::end(InsnMatchTable),
+ Format, CompareInsn());
+
+ // If first == second, couldn't find a match in the table.
+ if (EntryRange.first == EntryRange.second)
+ return Error(ErrorLoc, "unrecognized format");
+
+ struct InsnMatchEntry *Entry = EntryRange.first;
+
+ // Format should match from equal_range.
+ assert(Entry->Format == Format);
+
+ // Parse the following operands using the table's information.
+ for (int i = 0; i < Entry->NumOperands; i++) {
+ MatchClassKind Kind = Entry->OperandKinds[i];
+
+ SMLoc StartLoc = Parser.getTok().getLoc();
+
+ // Always expect commas as separators for operands.
+ if (getLexer().isNot(AsmToken::Comma))
+ return Error(StartLoc, "unexpected token in directive");
+ Lex();
+
+ // Parse operands.
+ OperandMatchResultTy ResTy;
+ if (Kind == MCK_AnyReg)
+ ResTy = parseAnyReg(Operands);
+ else if (Kind == MCK_BDXAddr64Disp12 || Kind == MCK_BDXAddr64Disp20)
+ ResTy = parseBDXAddr64(Operands);
+ else if (Kind == MCK_BDAddr64Disp12 || Kind == MCK_BDAddr64Disp20)
+ ResTy = parseBDAddr64(Operands);
+ else if (Kind == MCK_PCRel32)
+ ResTy = parsePCRel32(Operands);
+ else if (Kind == MCK_PCRel16)
+ ResTy = parsePCRel16(Operands);
+ else {
+ // Only remaining operand kind is an immediate.
+ const MCExpr *Expr;
+ SMLoc StartLoc = Parser.getTok().getLoc();
+
+ // Expect immediate expression.
+ if (Parser.parseExpression(Expr))
+ return Error(StartLoc, "unexpected token in directive");
+
+ SMLoc EndLoc =
+ SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+
+ Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc));
+ ResTy = MatchOperand_Success;
+ }
+
+ if (ResTy != MatchOperand_Success)
+ return true;
+ }
+
+ // Build the instruction with the parsed operands.
+ MCInst Inst = MCInstBuilder(Entry->Opcode);
+
+ for (size_t i = 0; i < Operands.size(); i++) {
+ MCParsedAsmOperand &Operand = *Operands[i];
+ MatchClassKind Kind = Entry->OperandKinds[i];
+
+ // Verify operand.
+ unsigned Res = validateOperandClass(Operand, Kind);
+ if (Res != Match_Success)
+ return Error(Operand.getStartLoc(), "unexpected operand type");
+
+ // Add operands to instruction.
+ SystemZOperand &ZOperand = static_cast<SystemZOperand &>(Operand);
+ if (ZOperand.isReg())
+ ZOperand.addRegOperands(Inst, 1);
+ else if (ZOperand.isMem(BDMem))
+ ZOperand.addBDAddrOperands(Inst, 2);
+ else if (ZOperand.isMem(BDXMem))
+ ZOperand.addBDXAddrOperands(Inst, 3);
+ else if (ZOperand.isImm())
+ ZOperand.addImmOperands(Inst, 1);
+ else
+ llvm_unreachable("unexpected operand type");
+ }
+
+ // Emit as a regular instruction.
+ Parser.getStreamer().EmitInstruction(Inst, getSTI());
+
+ return false;
+}
+
bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
SMLoc &EndLoc) {
Register Reg;
@@ -695,9 +1029,8 @@ bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
RegNo = SystemZMC::FP64Regs[Reg.Num];
else if (Reg.Group == RegV)
RegNo = SystemZMC::VR128Regs[Reg.Num];
- else
- // FIXME: Access registers aren't modelled as LLVM registers yet.
- return Error(Reg.StartLoc, "invalid operand for instruction");
+ else if (Reg.Group == RegAR)
+ RegNo = SystemZMC::AR32Regs[Reg.Num];
StartLoc = Reg.StartLoc;
EndLoc = Reg.EndLoc;
return false;
@@ -712,7 +1045,6 @@ bool SystemZAsmParser::ParseInstruction(ParseInstructionInfo &Info,
if (getLexer().isNot(AsmToken::EndOfStatement)) {
// Read the first operand.
if (parseOperand(Operands, Name)) {
- Parser.eatToEndOfStatement();
return true;
}
@@ -720,13 +1052,11 @@ bool SystemZAsmParser::ParseInstruction(ParseInstructionInfo &Info,
while (getLexer().is(AsmToken::Comma)) {
Parser.Lex();
if (parseOperand(Operands, Name)) {
- Parser.eatToEndOfStatement();
return true;
}
}
if (getLexer().isNot(AsmToken::EndOfStatement)) {
SMLoc Loc = getLexer().getLoc();
- Parser.eatToEndOfStatement();
return Error(Loc, "unexpected token in argument list");
}
}
@@ -739,8 +1069,14 @@ bool SystemZAsmParser::ParseInstruction(ParseInstructionInfo &Info,
bool SystemZAsmParser::parseOperand(OperandVector &Operands,
StringRef Mnemonic) {
// Check if the current operand has a custom associated parser, if so, try to
- // custom parse the operand, or fallback to the general approach.
+ // custom parse the operand, or fallback to the general approach. Force all
+ // features to be available during the operand check, or else we will fail to
+ // find the custom parser, and then we will later get an InvalidOperand error
+ // instead of a MissingFeature errror.
+ uint64_t AvailableFeatures = getAvailableFeatures();
+ setAvailableFeatures(~(uint64_t)0);
OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
+ setAvailableFeatures(AvailableFeatures);
if (ResTy == MatchOperand_Success)
return false;
@@ -766,16 +1102,23 @@ bool SystemZAsmParser::parseOperand(OperandVector &Operands,
// real address operands should have used a context-dependent parse routine,
// so we treat any plain expression as an immediate.
SMLoc StartLoc = Parser.getTok().getLoc();
- unsigned Base, Index;
- bool IsVector;
- const MCExpr *Expr, *Length;
- if (parseAddress(Base, Expr, Index, IsVector, Length, SystemZMC::GR64Regs,
- ADDR64Reg))
+ Register Reg1, Reg2;
+ bool HaveReg1, HaveReg2;
+ const MCExpr *Expr;
+ const MCExpr *Length;
+ if (parseAddress(HaveReg1, Reg1, HaveReg2, Reg2, Expr, Length))
+ return true;
+ // If the register combination is not valid for any instruction, reject it.
+ // Otherwise, fall back to reporting an unrecognized instruction.
+ if (HaveReg1 && Reg1.Group != RegGR && Reg1.Group != RegV
+ && parseAddressRegister(Reg1))
+ return true;
+ if (HaveReg2 && parseAddressRegister(Reg2))
return true;
SMLoc EndLoc =
SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- if (Base || Index || Length)
+ if (HaveReg1 || HaveReg2 || Length)
Operands.push_back(SystemZOperand::createInvalid(StartLoc, EndLoc));
else
Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc));
@@ -834,22 +1177,7 @@ bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
llvm_unreachable("Unexpected match type");
}
-SystemZAsmParser::OperandMatchResultTy
-SystemZAsmParser::parseAccessReg(OperandVector &Operands) {
- if (Parser.getTok().isNot(AsmToken::Percent))
- return MatchOperand_NoMatch;
-
- Register Reg;
- if (parseRegister(Reg, RegAccess, nullptr))
- return MatchOperand_ParseFail;
-
- Operands.push_back(SystemZOperand::createAccessReg(Reg.Num,
- Reg.StartLoc,
- Reg.EndLoc));
- return MatchOperand_Success;
-}
-
-SystemZAsmParser::OperandMatchResultTy
+OperandMatchResultTy
SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal,
int64_t MaxVal, bool AllowTLS) {
MCContext &Ctx = getContext();
@@ -927,5 +1255,5 @@ SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal,
// Force static initialization.
extern "C" void LLVMInitializeSystemZAsmParser() {
- RegisterMCAsmParser<SystemZAsmParser> X(TheSystemZTarget);
+ RegisterMCAsmParser<SystemZAsmParser> X(getTheSystemZTarget());
}
diff --git a/contrib/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp b/contrib/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp
index 20e015b..1806e01 100644
--- a/contrib/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp
@@ -42,7 +42,7 @@ static MCDisassembler *createSystemZDisassembler(const Target &T,
extern "C" void LLVMInitializeSystemZDisassembler() {
// Register the disassembler.
- TargetRegistry::RegisterMCDisassembler(TheSystemZTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheSystemZTarget(),
createSystemZDisassembler);
}
@@ -150,6 +150,12 @@ static DecodeStatus DecodeVR128BitRegisterClass(MCInst &Inst, uint64_t RegNo,
return decodeRegisterClass(Inst, RegNo, SystemZMC::VR128Regs, 32);
}
+static DecodeStatus DecodeAR32BitRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ return decodeRegisterClass(Inst, RegNo, SystemZMC::AR32Regs, 16);
+}
+
template<unsigned N>
static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm) {
if (!isUInt<N>(Imm))
@@ -166,12 +172,6 @@ static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm) {
return MCDisassembler::Success;
}
-static DecodeStatus decodeAccessRegOperand(MCInst &Inst, uint64_t Imm,
- uint64_t Address,
- const void *Decoder) {
- return decodeUImmOperand<4>(Inst, Imm);
-}
-
static DecodeStatus decodeU1ImmOperand(MCInst &Inst, uint64_t Imm,
uint64_t Address, const void *Decoder) {
return decodeUImmOperand<1>(Inst, Imm);
@@ -247,12 +247,24 @@ static DecodeStatus decodePCDBLOperand(MCInst &Inst, uint64_t Imm,
return MCDisassembler::Success;
}
+static DecodeStatus decodePC12DBLBranchOperand(MCInst &Inst, uint64_t Imm,
+ uint64_t Address,
+ const void *Decoder) {
+ return decodePCDBLOperand<12>(Inst, Imm, Address, true, Decoder);
+}
+
static DecodeStatus decodePC16DBLBranchOperand(MCInst &Inst, uint64_t Imm,
uint64_t Address,
const void *Decoder) {
return decodePCDBLOperand<16>(Inst, Imm, Address, true, Decoder);
}
+static DecodeStatus decodePC24DBLBranchOperand(MCInst &Inst, uint64_t Imm,
+ uint64_t Address,
+ const void *Decoder) {
+ return decodePCDBLOperand<24>(Inst, Imm, Address, true, Decoder);
+}
+
static DecodeStatus decodePC32DBLBranchOperand(MCInst &Inst, uint64_t Imm,
uint64_t Address,
const void *Decoder) {
@@ -321,6 +333,18 @@ static DecodeStatus decodeBDLAddr12Len8Operand(MCInst &Inst, uint64_t Field,
return MCDisassembler::Success;
}
+static DecodeStatus decodeBDRAddr12Operand(MCInst &Inst, uint64_t Field,
+ const unsigned *Regs) {
+ uint64_t Length = Field >> 16;
+ uint64_t Base = (Field >> 12) & 0xf;
+ uint64_t Disp = Field & 0xfff;
+ assert(Length < 16 && "Invalid BDRAddr12");
+ Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
+ Inst.addOperand(MCOperand::createImm(Disp));
+ Inst.addOperand(MCOperand::createReg(Regs[Length]));
+ return MCDisassembler::Success;
+}
+
static DecodeStatus decodeBDVAddr12Operand(MCInst &Inst, uint64_t Field,
const unsigned *Regs) {
uint64_t Index = Field >> 16;
@@ -376,6 +400,13 @@ static DecodeStatus decodeBDLAddr64Disp12Len8Operand(MCInst &Inst,
return decodeBDLAddr12Len8Operand(Inst, Field, SystemZMC::GR64Regs);
}
+static DecodeStatus decodeBDRAddr64Disp12Operand(MCInst &Inst,
+ uint64_t Field,
+ uint64_t Address,
+ const void *Decoder) {
+ return decodeBDRAddr12Operand(Inst, Field, SystemZMC::GR64Regs);
+}
+
static DecodeStatus decodeBDVAddr64Disp12Operand(MCInst &Inst, uint64_t Field,
uint64_t Address,
const void *Decoder) {
diff --git a/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp b/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp
index 6444cf8..1207c7b 100644
--- a/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp
@@ -134,11 +134,9 @@ void SystemZInstPrinter::printU32ImmOperand(const MCInst *MI, int OpNum,
printUImmOperand<32>(MI, OpNum, O);
}
-void SystemZInstPrinter::printAccessRegOperand(const MCInst *MI, int OpNum,
- raw_ostream &O) {
- uint64_t Value = MI->getOperand(OpNum).getImm();
- assert(Value < 16 && "Invalid access register number");
- O << "%a" << (unsigned int)Value;
+void SystemZInstPrinter::printU48ImmOperand(const MCInst *MI, int OpNum,
+ raw_ostream &O) {
+ printUImmOperand<48>(MI, OpNum, O);
}
void SystemZInstPrinter::printPCRelOperand(const MCInst *MI, int OpNum,
@@ -203,6 +201,17 @@ void SystemZInstPrinter::printBDLAddrOperand(const MCInst *MI, int OpNum,
O << ')';
}
+void SystemZInstPrinter::printBDRAddrOperand(const MCInst *MI, int OpNum,
+ raw_ostream &O) {
+ unsigned Base = MI->getOperand(OpNum).getReg();
+ uint64_t Disp = MI->getOperand(OpNum + 1).getImm();
+ unsigned Length = MI->getOperand(OpNum + 2).getReg();
+ O << Disp << "(%" << getRegisterName(Length);
+ if (Base)
+ O << ",%" << getRegisterName(Base);
+ O << ')';
+}
+
void SystemZInstPrinter::printBDVAddrOperand(const MCInst *MI, int OpNum,
raw_ostream &O) {
printAddress(MI->getOperand(OpNum).getReg(),
diff --git a/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h b/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h
index 7ca386f..6336f5e 100644
--- a/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h
+++ b/contrib/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h
@@ -48,6 +48,7 @@ private:
void printBDAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printBDXAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printBDLAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+ void printBDRAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printBDVAddrOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printU1ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printU2ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
@@ -61,9 +62,9 @@ private:
void printU16ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printS32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printU32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+ void printU48ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printPCRelOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printPCRelTLSOperand(const MCInst *MI, int OpNum, raw_ostream &O);
- void printAccessRegOperand(const MCInst *MI, int OpNum, raw_ostream &O);
// Print the mnemonic for a condition-code mask ("ne", "lh", etc.)
// This forms part of the instruction name rather than the operand list.
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
index c4d546c..9192448 100644
--- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
@@ -25,7 +25,9 @@ static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value) {
return Value;
switch (unsigned(Kind)) {
+ case SystemZ::FK_390_PC12DBL:
case SystemZ::FK_390_PC16DBL:
+ case SystemZ::FK_390_PC24DBL:
case SystemZ::FK_390_PC32DBL:
return (int64_t)Value / 2;
@@ -72,7 +74,9 @@ public:
const MCFixupKindInfo &
SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
const static MCFixupKindInfo Infos[SystemZ::NumTargetFixupKinds] = {
+ { "FK_390_PC12DBL", 4, 12, MCFixupKindInfo::FKF_IsPCRel },
{ "FK_390_PC16DBL", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
+ { "FK_390_PC24DBL", 0, 24, MCFixupKindInfo::FKF_IsPCRel },
{ "FK_390_PC32DBL", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
{ "FK_390_TLS_CALL", 0, 0, 0 }
};
@@ -90,12 +94,15 @@ void SystemZMCAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
bool IsPCRel) const {
MCFixupKind Kind = Fixup.getKind();
unsigned Offset = Fixup.getOffset();
- unsigned Size = (getFixupKindInfo(Kind).TargetSize + 7) / 8;
+ unsigned BitSize = getFixupKindInfo(Kind).TargetSize;
+ unsigned Size = (BitSize + 7) / 8;
assert(Offset + Size <= DataSize && "Invalid fixup offset!");
// Big-endian insertion of Size bytes.
Value = extractBitsForFixup(Kind, Value);
+ if (BitSize < 64)
+ Value &= ((uint64_t)1 << BitSize) - 1;
unsigned ShiftValue = (Size * 8) - 8;
for (unsigned I = 0; I != Size; ++I) {
Data[Offset + I] |= uint8_t(Value >> ShiftValue);
@@ -112,7 +119,8 @@ bool SystemZMCAsmBackend::writeNopData(uint64_t Count,
MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU) {
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options) {
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
return new SystemZMCAsmBackend(OSABI);
}
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
index fd52a2e..7082aba 100644
--- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp
@@ -72,6 +72,9 @@ private:
uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ uint64_t getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -110,6 +113,29 @@ private:
return getPCRelEncoding(MI, OpNum, Fixups,
SystemZ::FK_390_PC32DBL, 2, true);
}
+ uint64_t getPC12DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ return getPCRelEncoding(MI, OpNum, Fixups,
+ SystemZ::FK_390_PC12DBL, 1, false);
+ }
+ uint64_t getPC16DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ return getPCRelEncoding(MI, OpNum, Fixups,
+ SystemZ::FK_390_PC16DBL, 4, false);
+ }
+ uint64_t getPC24DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ return getPCRelEncoding(MI, OpNum, Fixups,
+ SystemZ::FK_390_PC24DBL, 3, false);
+ }
+
+private:
+ uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
+ void verifyInstructionPredicates(const MCInst &MI,
+ uint64_t AvailableFeatures) const;
};
} // end anonymous namespace
@@ -123,6 +149,9 @@ void SystemZMCCodeEmitter::
encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
+ verifyInstructionPredicates(MI,
+ computeAvailableFeatures(STI.getFeatureBits()));
+
uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
unsigned Size = MCII.get(MI.getOpcode()).getSize();
// Big-endian insertion of Size bytes.
@@ -199,6 +228,17 @@ getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
}
uint64_t SystemZMCCodeEmitter::
+getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
+ uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
+ uint64_t Len = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
+ assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Len));
+ return (Len << 16) | (Base << 12) | Disp;
+}
+
+uint64_t SystemZMCCodeEmitter::
getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
@@ -240,4 +280,5 @@ SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum,
return 0;
}
+#define ENABLE_INSTR_PREDICATE_VERIFIER
#include "SystemZGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h
index 229ab5d..c012acc 100644
--- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h
+++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h
@@ -16,7 +16,9 @@ namespace llvm {
namespace SystemZ {
enum FixupKind {
// These correspond directly to R_390_* relocations.
- FK_390_PC16DBL = FirstTargetFixupKind,
+ FK_390_PC12DBL = FirstTargetFixupKind,
+ FK_390_PC16DBL,
+ FK_390_PC24DBL,
FK_390_PC32DBL,
FK_390_TLS_CALL,
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
index 368c95f..43a96e8 100644
--- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
@@ -53,7 +53,9 @@ static unsigned getPCRelReloc(unsigned Kind) {
case FK_Data_2: return ELF::R_390_PC16;
case FK_Data_4: return ELF::R_390_PC32;
case FK_Data_8: return ELF::R_390_PC64;
+ case SystemZ::FK_390_PC12DBL: return ELF::R_390_PC12DBL;
case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL;
+ case SystemZ::FK_390_PC24DBL: return ELF::R_390_PC24DBL;
case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL;
}
llvm_unreachable("Unsupported PC-relative address");
@@ -100,7 +102,9 @@ static unsigned getTLSGDReloc(unsigned Kind) {
// Return the PLT relocation counterpart of MCFixupKind Kind.
static unsigned getPLTReloc(unsigned Kind) {
switch (Kind) {
+ case SystemZ::FK_390_PC12DBL: return ELF::R_390_PLT12DBL;
case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL;
+ case SystemZ::FK_390_PC24DBL: return ELF::R_390_PLT24DBL;
case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL;
}
llvm_unreachable("Unsupported absolute address");
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
index e16ba9e..dfea7e3 100644
--- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
@@ -109,6 +109,13 @@ const unsigned SystemZMC::VR128Regs[32] = {
SystemZ::V28, SystemZ::V29, SystemZ::V30, SystemZ::V31
};
+const unsigned SystemZMC::AR32Regs[16] = {
+ SystemZ::A0, SystemZ::A1, SystemZ::A2, SystemZ::A3,
+ SystemZ::A4, SystemZ::A5, SystemZ::A6, SystemZ::A7,
+ SystemZ::A8, SystemZ::A9, SystemZ::A10, SystemZ::A11,
+ SystemZ::A12, SystemZ::A13, SystemZ::A14, SystemZ::A15
+};
+
unsigned SystemZMC::getFirstReg(unsigned Reg) {
static unsigned Map[SystemZ::NUM_TARGET_REGS];
static bool Initialized = false;
@@ -119,6 +126,7 @@ unsigned SystemZMC::getFirstReg(unsigned Reg) {
Map[GR64Regs[I]] = I;
Map[GR128Regs[I]] = I;
Map[FP128Regs[I]] = I;
+ Map[AR32Regs[I]] = I;
}
for (unsigned I = 0; I < 32; ++I) {
Map[VR32Regs[I]] = I;
@@ -205,34 +213,34 @@ static MCInstPrinter *createSystemZMCInstPrinter(const Triple &T,
extern "C" void LLVMInitializeSystemZTargetMC() {
// Register the MCAsmInfo.
- TargetRegistry::RegisterMCAsmInfo(TheSystemZTarget,
+ TargetRegistry::RegisterMCAsmInfo(getTheSystemZTarget(),
createSystemZMCAsmInfo);
// Register the adjustCodeGenOpts.
- TargetRegistry::registerMCAdjustCodeGenOpts(TheSystemZTarget,
+ TargetRegistry::registerMCAdjustCodeGenOpts(getTheSystemZTarget(),
adjustCodeGenOpts);
// Register the MCCodeEmitter.
- TargetRegistry::RegisterMCCodeEmitter(TheSystemZTarget,
+ TargetRegistry::RegisterMCCodeEmitter(getTheSystemZTarget(),
createSystemZMCCodeEmitter);
// Register the MCInstrInfo.
- TargetRegistry::RegisterMCInstrInfo(TheSystemZTarget,
+ TargetRegistry::RegisterMCInstrInfo(getTheSystemZTarget(),
createSystemZMCInstrInfo);
// Register the MCRegisterInfo.
- TargetRegistry::RegisterMCRegInfo(TheSystemZTarget,
+ TargetRegistry::RegisterMCRegInfo(getTheSystemZTarget(),
createSystemZMCRegisterInfo);
// Register the MCSubtargetInfo.
- TargetRegistry::RegisterMCSubtargetInfo(TheSystemZTarget,
+ TargetRegistry::RegisterMCSubtargetInfo(getTheSystemZTarget(),
createSystemZMCSubtargetInfo);
// Register the MCAsmBackend.
- TargetRegistry::RegisterMCAsmBackend(TheSystemZTarget,
+ TargetRegistry::RegisterMCAsmBackend(getTheSystemZTarget(),
createSystemZMCAsmBackend);
// Register the MCInstPrinter.
- TargetRegistry::RegisterMCInstPrinter(TheSystemZTarget,
+ TargetRegistry::RegisterMCInstPrinter(getTheSystemZTarget(),
createSystemZMCInstPrinter);
}
diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
index 0db48fe..d9926c7 100644
--- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
@@ -21,13 +21,14 @@ class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
+class MCTargetOptions;
class StringRef;
class Target;
class Triple;
class raw_pwrite_stream;
class raw_ostream;
-extern Target TheSystemZTarget;
+Target &getTheSystemZTarget();
namespace SystemZMC {
// How many bytes are in the ABI-defined, caller-allocated part of
@@ -53,6 +54,7 @@ extern const unsigned FP128Regs[16];
extern const unsigned VR32Regs[32];
extern const unsigned VR64Regs[32];
extern const unsigned VR128Regs[32];
+extern const unsigned AR32Regs[16];
// Return the 0-based number of the first architectural register that
// contains the given LLVM register. E.g. R1D -> 1.
@@ -85,7 +87,8 @@ MCCodeEmitter *createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
MCAsmBackend *createSystemZMCAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCObjectWriter *createSystemZObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI);
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZ.h b/contrib/llvm/lib/Target/SystemZ/SystemZ.h
index c8ea964..9a8e508 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZ.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZ.h
@@ -175,6 +175,7 @@ static inline bool isImmHF(uint64_t Val) {
FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createSystemZElimComparePass(SystemZTargetMachine &TM);
+FunctionPass *createSystemZExpandPseudoPass(SystemZTargetMachine &TM);
FunctionPass *createSystemZShortenInstPass(SystemZTargetMachine &TM);
FunctionPass *createSystemZLongBranchPass(SystemZTargetMachine &TM);
FunctionPass *createSystemZLDCleanupPass(SystemZTargetMachine &TM);
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZ.td b/contrib/llvm/lib/Target/SystemZ/SystemZ.td
index d4d636d..6bdfd4d 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZ.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZ.td
@@ -14,7 +14,19 @@
include "llvm/Target/Target.td"
//===----------------------------------------------------------------------===//
-// SystemZ supported processors and features
+// SystemZ subtarget features
+//===----------------------------------------------------------------------===//
+
+include "SystemZFeatures.td"
+
+//===----------------------------------------------------------------------===//
+// SystemZ subtarget scheduling models
+//===----------------------------------------------------------------------===//
+
+include "SystemZSchedule.td"
+
+//===----------------------------------------------------------------------===//
+// SystemZ supported processors
//===----------------------------------------------------------------------===//
include "SystemZProcessors.td"
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 9c0f327..b39245b 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -418,10 +418,10 @@ void SystemZAsmPrinter::EmitInstruction(const MachineInstr *MI) {
case SystemZ::Serialize:
if (MF->getSubtarget<SystemZSubtarget>().hasFastSerialization())
- LoweredMI = MCInstBuilder(SystemZ::AsmBCR)
+ LoweredMI = MCInstBuilder(SystemZ::BCRAsm)
.addImm(14).addReg(SystemZ::R0D);
else
- LoweredMI = MCInstBuilder(SystemZ::AsmBCR)
+ LoweredMI = MCInstBuilder(SystemZ::BCRAsm)
.addImm(15).addReg(SystemZ::R0D);
break;
@@ -523,5 +523,5 @@ bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
// Force static initialization.
extern "C" void LLVMInitializeSystemZAsmPrinter() {
- RegisterAsmPrinter<SystemZAsmPrinter> X(TheSystemZTarget);
+ RegisterAsmPrinter<SystemZAsmPrinter> X(getTheSystemZTarget());
}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 7f6e823..fe8c88f 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -27,9 +27,7 @@ public:
: AsmPrinter(TM, std::move(Streamer)) {}
// Override AsmPrinter.
- const char *getPassName() const override {
- return "SystemZ Assembly Printer";
- }
+ StringRef getPassName() const override { return "SystemZ Assembly Printer"; }
void EmitInstruction(const MachineInstr *MI) override;
void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
index 27350b8..b4c843f 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
@@ -28,6 +28,7 @@ using namespace llvm;
#define DEBUG_TYPE "systemz-elim-compare"
STATISTIC(BranchOnCounts, "Number of branch-on-count instructions");
+STATISTIC(LoadAndTraps, "Number of load-and-trap instructions");
STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");
STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");
@@ -58,7 +59,7 @@ public:
SystemZElimCompare(const SystemZTargetMachine &tm)
: MachineFunctionPass(ID), TII(nullptr), TRI(nullptr) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SystemZ Comparison Elimination";
}
@@ -66,13 +67,15 @@ public:
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
Reference getRegReferences(MachineInstr &MI, unsigned Reg);
bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers);
+ bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers);
bool convertToLoadAndTest(MachineInstr &MI);
bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers);
@@ -171,7 +174,7 @@ static unsigned getCompareSourceReg(MachineInstr &Compare) {
// Compare compares the result of MI against zero. If MI is an addition
// of -1 and if CCUsers is a single branch on nonzero, eliminate the addition
-// and convert the branch to a BRCT(G). Return true on success.
+// and convert the branch to a BRCT(G) or BRCTH. Return true on success.
bool SystemZElimCompare::convertToBRCT(
MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers) {
@@ -182,6 +185,8 @@ bool SystemZElimCompare::convertToBRCT(
BRCT = SystemZ::BRCT;
else if (Opcode == SystemZ::AGHI)
BRCT = SystemZ::BRCTG;
+ else if (Opcode == SystemZ::AIH)
+ BRCT = SystemZ::BRCTH;
else
return false;
if (MI.getOperand(2).getImm() != -1)
@@ -205,16 +210,61 @@ bool SystemZElimCompare::convertToBRCT(
if (getRegReferences(*MBBI, SrcReg))
return false;
- // The transformation is OK. Rebuild Branch as a BRCT(G).
+ // The transformation is OK. Rebuild Branch as a BRCT(G) or BRCTH.
MachineOperand Target(Branch->getOperand(2));
while (Branch->getNumOperands())
Branch->RemoveOperand(0);
Branch->setDesc(TII->get(BRCT));
+ MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
+ MIB.addOperand(MI.getOperand(0))
+ .addOperand(MI.getOperand(1))
+ .addOperand(Target);
+ // Add a CC def to BRCT(G), since we may have to split them again if the
+ // branch displacement overflows. BRCTH has a 32-bit displacement, so
+ // this is not necessary there.
+ if (BRCT != SystemZ::BRCTH)
+ MIB.addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
+ MI.eraseFromParent();
+ return true;
+}
+
+// Compare compares the result of MI against zero. If MI is a suitable load
+// instruction and if CCUsers is a single conditional trap on zero, eliminate
+// the load and convert the branch to a load-and-trap. Return true on success.
+bool SystemZElimCompare::convertToLoadAndTrap(
+ MachineInstr &MI, MachineInstr &Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers) {
+ unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode());
+ if (!LATOpcode)
+ return false;
+
+ // Check whether we have a single CondTrap that traps on zero.
+ if (CCUsers.size() != 1)
+ return false;
+ MachineInstr *Branch = CCUsers[0];
+ if (Branch->getOpcode() != SystemZ::CondTrap ||
+ Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||
+ Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ)
+ return false;
+
+ // We already know that there are no references to the register between
+ // MI and Compare. Make sure that there are also no references between
+ // Compare and Branch.
+ unsigned SrcReg = getCompareSourceReg(Compare);
+ MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
+ for (++MBBI; MBBI != MBBE; ++MBBI)
+ if (getRegReferences(*MBBI, SrcReg))
+ return false;
+
+ // The transformation is OK. Rebuild Branch as a load-and-trap.
+ while (Branch->getNumOperands())
+ Branch->RemoveOperand(0);
+ Branch->setDesc(TII->get(LATOpcode));
MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
.addOperand(MI.getOperand(0))
.addOperand(MI.getOperand(1))
- .addOperand(Target)
- .addReg(SystemZ::CC, RegState::ImplicitDefine | RegState::Dead);
+ .addOperand(MI.getOperand(2))
+ .addOperand(MI.getOperand(3));
MI.eraseFromParent();
return true;
}
@@ -347,11 +397,17 @@ bool SystemZElimCompare::optimizeCompareZero(
MachineInstr &MI = *MBBI;
if (resultTests(MI, SrcReg)) {
// Try to remove both MI and Compare by converting a branch to BRCT(G).
- // We don't care in this case whether CC is modified between MI and
- // Compare.
- if (!CCRefs.Use && !SrcRefs && convertToBRCT(MI, Compare, CCUsers)) {
- BranchOnCounts += 1;
- return true;
+ // or a load-and-trap instruction. We don't care in this case whether
+ // CC is modified between MI and Compare.
+ if (!CCRefs.Use && !SrcRefs) {
+ if (convertToBRCT(MI, Compare, CCUsers)) {
+ BranchOnCounts += 1;
+ return true;
+ }
+ if (convertToLoadAndTrap(MI, Compare, CCUsers)) {
+ LoadAndTraps += 1;
+ return true;
+ }
}
// Try to eliminate Compare by reusing a CC result from MI.
if ((!CCRefs && convertToLoadAndTest(MI)) ||
@@ -403,6 +459,9 @@ bool SystemZElimCompare::fuseCompareOperations(
return false;
// Make sure that the operands are available at the branch.
+ // SrcReg2 is the register if the source operand is a register,
+ // 0 if the source operand is immediate, and the base register
+ // if the source operand is memory (index is not supported).
unsigned SrcReg = Compare.getOperand(0).getReg();
unsigned SrcReg2 =
Compare.getOperand(1).isReg() ? Compare.getOperand(1).getReg() : 0;
@@ -435,11 +494,16 @@ bool SystemZElimCompare::fuseCompareOperations(
Branch->RemoveOperand(0);
// Rebuild Branch as a fused compare and branch.
+ // SrcNOps is the number of MI operands of the compare instruction
+ // that we need to copy over.
+ unsigned SrcNOps = 2;
+ if (FusedOpcode == SystemZ::CLT || FusedOpcode == SystemZ::CLGT)
+ SrcNOps = 3;
Branch->setDesc(TII->get(FusedOpcode));
MachineInstrBuilder MIB(*Branch->getParent()->getParent(), Branch);
- MIB.addOperand(Compare.getOperand(0))
- .addOperand(Compare.getOperand(1))
- .addOperand(CCMask);
+ for (unsigned I = 0; I < SrcNOps; I++)
+ MIB.addOperand(Compare.getOperand(I));
+ MIB.addOperand(CCMask);
if (Type == SystemZII::CompareAndBranch) {
// Only conditional branches define CC, as they may be converted back
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZExpandPseudo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZExpandPseudo.cpp
new file mode 100644
index 0000000..92ce808
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZExpandPseudo.cpp
@@ -0,0 +1,153 @@
+//==-- SystemZExpandPseudo.cpp - Expand pseudo instructions -------*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass that expands pseudo instructions into target
+// instructions to allow proper scheduling and other late optimizations. This
+// pass should be run after register allocation but before the post-regalloc
+// scheduling pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZ.h"
+#include "SystemZInstrInfo.h"
+#include "SystemZSubtarget.h"
+#include "llvm/CodeGen/LivePhysRegs.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+using namespace llvm;
+
+#define SYSTEMZ_EXPAND_PSEUDO_NAME "SystemZ pseudo instruction expansion pass"
+
+namespace llvm {
+ void initializeSystemZExpandPseudoPass(PassRegistry&);
+}
+
+namespace {
+class SystemZExpandPseudo : public MachineFunctionPass {
+public:
+ static char ID;
+ SystemZExpandPseudo() : MachineFunctionPass(ID) {
+ initializeSystemZExpandPseudoPass(*PassRegistry::getPassRegistry());
+ }
+
+ const SystemZInstrInfo *TII;
+
+ bool runOnMachineFunction(MachineFunction &Fn) override;
+
+ StringRef getPassName() const override { return SYSTEMZ_EXPAND_PSEUDO_NAME; }
+
+private:
+ bool expandMBB(MachineBasicBlock &MBB);
+ bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI);
+ bool expandLOCRMux(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI);
+};
+char SystemZExpandPseudo::ID = 0;
+}
+
+INITIALIZE_PASS(SystemZExpandPseudo, "systemz-expand-pseudo",
+ SYSTEMZ_EXPAND_PSEUDO_NAME, false, false)
+
+/// \brief Returns an instance of the pseudo instruction expansion pass.
+FunctionPass *llvm::createSystemZExpandPseudoPass(SystemZTargetMachine &TM) {
+ return new SystemZExpandPseudo();
+}
+
+// MI is a load-register-on-condition pseudo instruction that could not be
+// handled as a single hardware instruction. Replace it by a branch sequence.
+bool SystemZExpandPseudo::expandLOCRMux(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI) {
+ MachineFunction &MF = *MBB.getParent();
+ const BasicBlock *BB = MBB.getBasicBlock();
+ MachineInstr &MI = *MBBI;
+ DebugLoc DL = MI.getDebugLoc();
+ unsigned DestReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned CCValid = MI.getOperand(3).getImm();
+ unsigned CCMask = MI.getOperand(4).getImm();
+
+ LivePhysRegs LiveRegs(&TII->getRegisterInfo());
+ LiveRegs.addLiveOuts(MBB);
+ for (auto I = std::prev(MBB.end()); I != MBBI; --I)
+ LiveRegs.stepBackward(*I);
+
+ // Splice MBB at MI, moving the rest of the block into RestMBB.
+ MachineBasicBlock *RestMBB = MF.CreateMachineBasicBlock(BB);
+ MF.insert(std::next(MachineFunction::iterator(MBB)), RestMBB);
+ RestMBB->splice(RestMBB->begin(), &MBB, MI, MBB.end());
+ RestMBB->transferSuccessors(&MBB);
+ for (auto I = LiveRegs.begin(); I != LiveRegs.end(); ++I)
+ RestMBB->addLiveIn(*I);
+
+ // Create a new block MoveMBB to hold the move instruction.
+ MachineBasicBlock *MoveMBB = MF.CreateMachineBasicBlock(BB);
+ MF.insert(std::next(MachineFunction::iterator(MBB)), MoveMBB);
+ MoveMBB->addLiveIn(SrcReg);
+ for (auto I = LiveRegs.begin(); I != LiveRegs.end(); ++I)
+ MoveMBB->addLiveIn(*I);
+
+ // At the end of MBB, create a conditional branch to RestMBB if the
+ // condition is false, otherwise fall through to MoveMBB.
+ BuildMI(&MBB, DL, TII->get(SystemZ::BRC))
+ .addImm(CCValid).addImm(CCMask ^ CCValid).addMBB(RestMBB);
+ MBB.addSuccessor(RestMBB);
+ MBB.addSuccessor(MoveMBB);
+
+ // In MoveMBB, emit an instruction to move SrcReg into DestReg,
+ // then fall through to RestMBB.
+ TII->copyPhysReg(*MoveMBB, MoveMBB->end(), DL, DestReg, SrcReg,
+ MI.getOperand(2).isKill());
+ MoveMBB->addSuccessor(RestMBB);
+
+ NextMBBI = MBB.end();
+ MI.eraseFromParent();
+ return true;
+}
+
+/// \brief If MBBI references a pseudo instruction that should be expanded here,
+/// do the expansion and return true. Otherwise return false.
+bool SystemZExpandPseudo::expandMI(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI) {
+ MachineInstr &MI = *MBBI;
+ switch (MI.getOpcode()) {
+ case SystemZ::LOCRMux:
+ return expandLOCRMux(MBB, MBBI, NextMBBI);
+ default:
+ break;
+ }
+ return false;
+}
+
+/// \brief Iterate over the instructions in basic block MBB and expand any
+/// pseudo instructions. Return true if anything was modified.
+bool SystemZExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
+ bool Modified = false;
+
+ MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
+ while (MBBI != E) {
+ MachineBasicBlock::iterator NMBBI = std::next(MBBI);
+ Modified |= expandMI(MBB, MBBI, NMBBI);
+ MBBI = NMBBI;
+ }
+
+ return Modified;
+}
+
+bool SystemZExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
+ TII = static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo());
+
+ bool Modified = false;
+ for (auto &MBB : MF)
+ Modified |= expandMBB(MBB);
+ return Modified;
+}
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZFeatures.td b/contrib/llvm/lib/Target/SystemZ/SystemZFeatures.td
new file mode 100644
index 0000000..716e5ad
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZFeatures.td
@@ -0,0 +1,171 @@
+//===-- SystemZ.td - SystemZ processors and features ---------*- tblgen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Feature definitions.
+//
+//===----------------------------------------------------------------------===//
+
+class SystemZFeature<string extname, string intname, string desc>
+ : Predicate<"Subtarget->has"##intname##"()">,
+ AssemblerPredicate<"Feature"##intname, extname>,
+ SubtargetFeature<extname, "Has"##intname, "true", desc>;
+
+class SystemZMissingFeature<string intname>
+ : Predicate<"!Subtarget->has"##intname##"()">;
+
+class SystemZFeatureList<list<SystemZFeature> x> {
+ list<SystemZFeature> List = x;
+}
+
+class SystemZFeatureAdd<list<SystemZFeature> x, list<SystemZFeature> y>
+ : SystemZFeatureList<!listconcat(x, y)>;
+
+//===----------------------------------------------------------------------===//
+//
+// New features added in the Ninth Edition of the z/Architecture
+//
+//===----------------------------------------------------------------------===//
+
+def FeatureDistinctOps : SystemZFeature<
+ "distinct-ops", "DistinctOps",
+ "Assume that the distinct-operands facility is installed"
+>;
+
+def FeatureFastSerialization : SystemZFeature<
+ "fast-serialization", "FastSerialization",
+ "Assume that the fast-serialization facility is installed"
+>;
+
+def FeatureFPExtension : SystemZFeature<
+ "fp-extension", "FPExtension",
+ "Assume that the floating-point extension facility is installed"
+>;
+
+def FeatureHighWord : SystemZFeature<
+ "high-word", "HighWord",
+ "Assume that the high-word facility is installed"
+>;
+
+def FeatureInterlockedAccess1 : SystemZFeature<
+ "interlocked-access1", "InterlockedAccess1",
+ "Assume that interlocked-access facility 1 is installed"
+>;
+def FeatureNoInterlockedAccess1 : SystemZMissingFeature<"InterlockedAccess1">;
+
+def FeatureLoadStoreOnCond : SystemZFeature<
+ "load-store-on-cond", "LoadStoreOnCond",
+ "Assume that the load/store-on-condition facility is installed"
+>;
+
+def FeaturePopulationCount : SystemZFeature<
+ "population-count", "PopulationCount",
+ "Assume that the population-count facility is installed"
+>;
+
+def Arch9NewFeatures : SystemZFeatureList<[
+ FeatureDistinctOps,
+ FeatureFastSerialization,
+ FeatureFPExtension,
+ FeatureHighWord,
+ FeatureInterlockedAccess1,
+ FeatureLoadStoreOnCond,
+ FeaturePopulationCount
+]>;
+
+//===----------------------------------------------------------------------===//
+//
+// New features added in the Tenth Edition of the z/Architecture
+//
+//===----------------------------------------------------------------------===//
+
+def FeatureExecutionHint : SystemZFeature<
+ "execution-hint", "ExecutionHint",
+ "Assume that the execution-hint facility is installed"
+>;
+
+def FeatureLoadAndTrap : SystemZFeature<
+ "load-and-trap", "LoadAndTrap",
+ "Assume that the load-and-trap facility is installed"
+>;
+
+def FeatureMiscellaneousExtensions : SystemZFeature<
+ "miscellaneous-extensions", "MiscellaneousExtensions",
+ "Assume that the miscellaneous-extensions facility is installed"
+>;
+
+def FeatureProcessorAssist : SystemZFeature<
+ "processor-assist", "ProcessorAssist",
+ "Assume that the processor-assist facility is installed"
+>;
+
+def FeatureTransactionalExecution : SystemZFeature<
+ "transactional-execution", "TransactionalExecution",
+ "Assume that the transactional-execution facility is installed"
+>;
+
+def Arch10NewFeatures : SystemZFeatureList<[
+ FeatureExecutionHint,
+ FeatureLoadAndTrap,
+ FeatureMiscellaneousExtensions,
+ FeatureProcessorAssist,
+ FeatureTransactionalExecution
+]>;
+
+//===----------------------------------------------------------------------===//
+//
+// New features added in the Eleventh Edition of the z/Architecture
+//
+//===----------------------------------------------------------------------===//
+
+def FeatureLoadAndZeroRightmostByte : SystemZFeature<
+ "load-and-zero-rightmost-byte", "LoadAndZeroRightmostByte",
+ "Assume that the load-and-zero-rightmost-byte facility is installed"
+>;
+
+def FeatureLoadStoreOnCond2 : SystemZFeature<
+ "load-store-on-cond-2", "LoadStoreOnCond2",
+ "Assume that the load/store-on-condition facility 2 is installed"
+>;
+
+def FeatureVector : SystemZFeature<
+ "vector", "Vector",
+ "Assume that the vectory facility is installed"
+>;
+def FeatureNoVector : SystemZMissingFeature<"Vector">;
+
+def Arch11NewFeatures : SystemZFeatureList<[
+ FeatureLoadAndZeroRightmostByte,
+ FeatureLoadStoreOnCond2,
+ FeatureVector
+]>;
+
+//===----------------------------------------------------------------------===//
+//
+// Cumulative supported and unsupported feature sets
+//
+//===----------------------------------------------------------------------===//
+
+def Arch8SupportedFeatures
+ : SystemZFeatureList<[]>;
+def Arch9SupportedFeatures
+ : SystemZFeatureAdd<Arch8SupportedFeatures.List, Arch9NewFeatures.List>;
+def Arch10SupportedFeatures
+ : SystemZFeatureAdd<Arch9SupportedFeatures.List, Arch10NewFeatures.List>;
+def Arch11SupportedFeatures
+ : SystemZFeatureAdd<Arch10SupportedFeatures.List, Arch11NewFeatures.List>;
+
+def Arch11UnsupportedFeatures
+ : SystemZFeatureList<[]>;
+def Arch10UnsupportedFeatures
+ : SystemZFeatureAdd<Arch11UnsupportedFeatures.List, Arch11NewFeatures.List>;
+def Arch9UnsupportedFeatures
+ : SystemZFeatureAdd<Arch10UnsupportedFeatures.List, Arch10NewFeatures.List>;
+def Arch8UnsupportedFeatures
+ : SystemZFeatureAdd<Arch9UnsupportedFeatures.List, Arch9NewFeatures.List>;
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
index ccaed49..a28a91e 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
@@ -67,7 +67,7 @@ void SystemZFrameLowering::determineCalleeSaves(MachineFunction &MF,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
- MachineFrameInfo *MFFrame = MF.getFrameInfo();
+ MachineFrameInfo &MFFrame = MF.getFrameInfo();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
bool HasFP = hasFP(MF);
SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
@@ -82,7 +82,7 @@ void SystemZFrameLowering::determineCalleeSaves(MachineFunction &MF,
SavedRegs.set(SystemZ::ArgGPRs[I]);
// If there are any landing pads, entering them will modify r6/r7.
- if (!MF.getMMI().getLandingPads().empty()) {
+ if (!MF.getLandingPads().empty()) {
SavedRegs.set(SystemZ::R6D);
SavedRegs.set(SystemZ::R7D);
}
@@ -94,7 +94,7 @@ void SystemZFrameLowering::determineCalleeSaves(MachineFunction &MF,
// If the function calls other functions, record that the return
// address register will be clobbered.
- if (MFFrame->hasCalls())
+ if (MFFrame.hasCalls())
SavedRegs.set(SystemZ::R14D);
// If we are saving GPRs other than the stack pointer, we might as well
@@ -276,16 +276,16 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
void SystemZFrameLowering::
processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS) const {
- MachineFrameInfo *MFFrame = MF.getFrameInfo();
- uint64_t MaxReach = (MFFrame->estimateStackSize(MF) +
+ MachineFrameInfo &MFFrame = MF.getFrameInfo();
+ uint64_t MaxReach = (MFFrame.estimateStackSize(MF) +
SystemZMC::CallFrameSize * 2);
if (!isUInt<12>(MaxReach)) {
// We may need register scavenging slots if some parts of the frame
// are outside the reach of an unsigned 12-bit displacement.
// Create 2 for the case where both addresses in an MVC are
// out of range.
- RS->addScavengingFrameIndex(MFFrame->CreateStackObject(8, 8, false));
- RS->addScavengingFrameIndex(MFFrame->CreateStackObject(8, 8, false));
+ RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, 8, false));
+ RS->addScavengingFrameIndex(MFFrame.CreateStackObject(8, 8, false));
}
}
@@ -321,14 +321,14 @@ static void emitIncrement(MachineBasicBlock &MBB,
void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
- MachineFrameInfo *MFFrame = MF.getFrameInfo();
+ MachineFrameInfo &MFFrame = MF.getFrameInfo();
auto *ZII =
static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo());
SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>();
MachineBasicBlock::iterator MBBI = MBB.begin();
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
- const std::vector<CalleeSavedInfo> &CSI = MFFrame->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
bool HasFP = hasFP(MF);
// Debug location must be unknown since the first debug location is used
@@ -350,7 +350,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
unsigned Reg = Save.getReg();
if (SystemZ::GR64BitRegClass.contains(Reg)) {
int64_t Offset = SPOffsetFromCFA + RegSpillOffsets[Reg];
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, true), Offset));
BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -374,7 +374,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
emitIncrement(MBB, MBBI, DL, SystemZ::R15D, Delta, ZII);
// Add CFI for the allocation.
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, SPOffsetFromCFA + Delta));
BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -392,7 +392,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
// Add CFI for the new frame location.
unsigned HardFP = MRI->getDwarfRegNum(SystemZ::R11D, true);
- unsigned CFIIndex = MMI.addFrameInst(
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, HardFP));
BuildMI(MBB, MBBI, DL, ZII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -422,7 +422,7 @@ void SystemZFrameLowering::emitPrologue(MachineFunction &MF,
int64_t Offset =
getFrameIndexReference(MF, Save.getFrameIdx(), IgnoredFrameReg);
- unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, DwarfReg, SPOffsetFromCFA + Offset));
CFIIndexes.push_back(CFIIndex);
}
@@ -478,14 +478,14 @@ void SystemZFrameLowering::emitEpilogue(MachineFunction &MF,
bool SystemZFrameLowering::hasFP(const MachineFunction &MF) const {
return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
- MF.getFrameInfo()->hasVarSizedObjects() ||
+ MF.getFrameInfo().hasVarSizedObjects() ||
MF.getInfo<SystemZMachineFunctionInfo>()->getManipulatesSP());
}
int SystemZFrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI,
unsigned &FrameReg) const {
- const MachineFrameInfo *MFFrame = MF.getFrameInfo();
+ const MachineFrameInfo &MFFrame = MF.getFrameInfo();
const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
// Fill in FrameReg output argument.
@@ -494,8 +494,8 @@ int SystemZFrameLowering::getFrameIndexReference(const MachineFunction &MF,
// Start with the offset of FI from the top of the caller-allocated frame
// (i.e. the top of the 160 bytes allocated by the caller). This initial
// offset is therefore negative.
- int64_t Offset = (MFFrame->getObjectOffset(FI) +
- MFFrame->getOffsetAdjustment());
+ int64_t Offset = (MFFrame.getObjectOffset(FI) +
+ MFFrame.getOffsetAdjustment());
// Make the offset relative to the incoming stack pointer.
Offset -= getOffsetOfLocalArea();
@@ -508,15 +508,15 @@ int SystemZFrameLowering::getFrameIndexReference(const MachineFunction &MF,
uint64_t SystemZFrameLowering::
getAllocatedStackSize(const MachineFunction &MF) const {
- const MachineFrameInfo *MFFrame = MF.getFrameInfo();
+ const MachineFrameInfo &MFFrame = MF.getFrameInfo();
// Start with the size of the local variables and spill slots.
- uint64_t StackSize = MFFrame->getStackSize();
+ uint64_t StackSize = MFFrame.getStackSize();
// We need to allocate the ABI-defined 160-byte base area whenever
// we allocate stack space for our own use and whenever we call another
// function.
- if (StackSize || MFFrame->hasVarSizedObjects() || MFFrame->hasCalls())
+ if (StackSize || MFFrame.hasVarSizedObjects() || MFFrame.hasCalls())
StackSize += SystemZMC::CallFrameSize;
return StackSize;
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp
new file mode 100644
index 0000000..fe4b52b
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp
@@ -0,0 +1,337 @@
+//=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a hazard recognizer for the SystemZ scheduler.
+//
+// This class is used by the SystemZ scheduling strategy to maintain
+// the state during scheduling, and provide cost functions for
+// scheduling candidates. This includes:
+//
+// * Decoder grouping. A decoder group can maximally hold 3 uops, and
+// instructions that always begin a new group should be scheduled when
+// the current decoder group is empty.
+// * Processor resources usage. It is beneficial to balance the use of
+// resources.
+//
+// ===---------------------------------------------------------------------===//
+
+#include "SystemZHazardRecognizer.h"
+#include "llvm/ADT/Statistic.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "misched"
+
+// This is the limit of processor resource usage at which the
+// scheduler should try to look for other instructions (not using the
+// critical resource).
+static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
+ cl::desc("The OOO window for processor "
+ "resources during scheduling."),
+ cl::init(8));
+
+SystemZHazardRecognizer::
+SystemZHazardRecognizer(const MachineSchedContext *C) : DAG(nullptr),
+ SchedModel(nullptr) {}
+
+unsigned SystemZHazardRecognizer::
+getNumDecoderSlots(SUnit *SU) const {
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ if (!SC->isValid())
+ return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
+
+ if (SC->BeginGroup) {
+ if (!SC->EndGroup)
+ return 2; // Cracked instruction
+ else
+ return 3; // Expanded/group-alone instruction
+ }
+
+ return 1; // Normal instruction
+}
+
+unsigned SystemZHazardRecognizer::getCurrCycleIdx() {
+ unsigned Idx = CurrGroupSize;
+ if (GrpCount % 2)
+ Idx += 3;
+ return Idx;
+}
+
+ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
+getHazardType(SUnit *m, int Stalls) {
+ return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard);
+}
+
+void SystemZHazardRecognizer::Reset() {
+ CurrGroupSize = 0;
+ clearProcResCounters();
+ GrpCount = 0;
+ LastFPdOpCycleIdx = UINT_MAX;
+ DEBUG(CurGroupDbg = "";);
+}
+
+bool
+SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ if (!SC->isValid())
+ return true;
+
+ // A cracked instruction only fits into schedule if the current
+ // group is empty.
+ if (SC->BeginGroup)
+ return (CurrGroupSize == 0);
+
+ // Since a full group is handled immediately in EmitInstruction(),
+ // SU should fit into current group. NumSlots should be 1 or 0,
+ // since it is not a cracked or expanded instruction.
+ assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
+ "Expected normal instruction to fit in non-full group!");
+
+ return true;
+}
+
+void SystemZHazardRecognizer::nextGroup(bool DbgOutput) {
+ if (CurrGroupSize > 0) {
+ DEBUG(dumpCurrGroup("Completed decode group"));
+ DEBUG(CurGroupDbg = "";);
+
+ GrpCount++;
+
+ // Reset counter for next group.
+ CurrGroupSize = 0;
+
+ // Decrease counters for execution units by one.
+ for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
+ if (ProcResourceCounters[i] > 0)
+ ProcResourceCounters[i]--;
+
+ // Clear CriticalResourceIdx if it is now below the threshold.
+ if (CriticalResourceIdx != UINT_MAX &&
+ (ProcResourceCounters[CriticalResourceIdx] <=
+ ProcResCostLim))
+ CriticalResourceIdx = UINT_MAX;
+ }
+
+ DEBUG(if (DbgOutput)
+ dumpProcResourceCounters(););
+}
+
+#ifndef NDEBUG // Debug output
+void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
+ OS << "SU(" << SU->NodeNum << "):";
+ OS << SchedModel->getInstrInfo()->getName(SU->getInstr()->getOpcode());
+
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ if (!SC->isValid())
+ return;
+
+ for (TargetSchedModel::ProcResIter
+ PI = SchedModel->getWriteProcResBegin(SC),
+ PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
+ const MCProcResourceDesc &PRD =
+ *SchedModel->getProcResource(PI->ProcResourceIdx);
+ std::string FU(PRD.Name);
+ // trim e.g. Z13_FXaUnit -> FXa
+ FU = FU.substr(FU.find("_") + 1);
+ FU.resize(FU.find("Unit"));
+ OS << "/" << FU;
+
+ if (PI->Cycles > 1)
+ OS << "(" << PI->Cycles << "cyc)";
+ }
+
+ if (SC->NumMicroOps > 1)
+ OS << "/" << SC->NumMicroOps << "uops";
+ if (SC->BeginGroup && SC->EndGroup)
+ OS << "/GroupsAlone";
+ else if (SC->BeginGroup)
+ OS << "/BeginsGroup";
+ else if (SC->EndGroup)
+ OS << "/EndsGroup";
+ if (SU->isUnbuffered)
+ OS << "/Unbuffered";
+}
+
+void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
+ dbgs() << "+++ " << Msg;
+ dbgs() << ": ";
+
+ if (CurGroupDbg.empty())
+ dbgs() << " <empty>\n";
+ else {
+ dbgs() << "{ " << CurGroupDbg << " }";
+ dbgs() << " (" << CurrGroupSize << " decoder slot"
+ << (CurrGroupSize > 1 ? "s":"")
+ << ")\n";
+ }
+}
+
+void SystemZHazardRecognizer::dumpProcResourceCounters() const {
+ bool any = false;
+
+ for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
+ if (ProcResourceCounters[i] > 0) {
+ any = true;
+ break;
+ }
+
+ if (!any)
+ return;
+
+ dbgs() << "+++ Resource counters:\n";
+ for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
+ if (ProcResourceCounters[i] > 0) {
+ dbgs() << "+++ Extra schedule for execution unit "
+ << SchedModel->getProcResource(i)->Name
+ << ": " << ProcResourceCounters[i] << "\n";
+ any = true;
+ }
+}
+#endif //NDEBUG
+
+void SystemZHazardRecognizer::clearProcResCounters() {
+ ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
+ CriticalResourceIdx = UINT_MAX;
+}
+
+// Update state with SU as the next scheduled unit.
+void SystemZHazardRecognizer::
+EmitInstruction(SUnit *SU) {
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ DEBUG( dumpCurrGroup("Decode group before emission"););
+
+ // If scheduling an SU that must begin a new decoder group, move on
+ // to next group.
+ if (!fitsIntoCurrentGroup(SU))
+ nextGroup();
+
+ DEBUG( dbgs() << "+++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
+ dbgs() << "\n";
+ raw_string_ostream cgd(CurGroupDbg);
+ if (CurGroupDbg.length())
+ cgd << ", ";
+ dumpSU(SU, cgd););
+
+ // After returning from a call, we don't know much about the state.
+ if (SU->getInstr()->isCall()) {
+ DEBUG (dbgs() << "+++ Clearing state after call.\n";);
+ clearProcResCounters();
+ LastFPdOpCycleIdx = UINT_MAX;
+ CurrGroupSize += getNumDecoderSlots(SU);
+ assert (CurrGroupSize <= 3);
+ nextGroup();
+ return;
+ }
+
+ // Increase counter for execution unit(s).
+ for (TargetSchedModel::ProcResIter
+ PI = SchedModel->getWriteProcResBegin(SC),
+ PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
+ // Don't handle FPd together with the other resources.
+ if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
+ continue;
+ int &CurrCounter =
+ ProcResourceCounters[PI->ProcResourceIdx];
+ CurrCounter += PI->Cycles;
+ // Check if this is now the new critical resource.
+ if ((CurrCounter > ProcResCostLim) &&
+ (CriticalResourceIdx == UINT_MAX ||
+ (PI->ProcResourceIdx != CriticalResourceIdx &&
+ CurrCounter >
+ ProcResourceCounters[CriticalResourceIdx]))) {
+ DEBUG( dbgs() << "+++ New critical resource: "
+ << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
+ << "\n";);
+ CriticalResourceIdx = PI->ProcResourceIdx;
+ }
+ }
+
+ // Make note of an instruction that uses a blocking resource (FPd).
+ if (SU->isUnbuffered) {
+ LastFPdOpCycleIdx = getCurrCycleIdx();
+ DEBUG (dbgs() << "+++ Last FPd cycle index: "
+ << LastFPdOpCycleIdx << "\n";);
+ }
+
+ // Insert SU into current group by increasing number of slots used
+ // in current group.
+ CurrGroupSize += getNumDecoderSlots(SU);
+ assert (CurrGroupSize <= 3);
+
+ // Check if current group is now full/ended. If so, move on to next
+ // group to be ready to evaluate more candidates.
+ if (CurrGroupSize == 3 || SC->EndGroup)
+ nextGroup();
+}
+
+int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ if (!SC->isValid())
+ return 0;
+
+ // If SU begins new group, it can either break a current group early
+ // or fit naturally if current group is empty (negative cost).
+ if (SC->BeginGroup) {
+ if (CurrGroupSize)
+ return 3 - CurrGroupSize;
+ return -1;
+ }
+
+ // Similarly, a group-ending SU may either fit well (last in group), or
+ // end the group prematurely.
+ if (SC->EndGroup) {
+ unsigned resultingGroupSize =
+ (CurrGroupSize + getNumDecoderSlots(SU));
+ if (resultingGroupSize < 3)
+ return (3 - resultingGroupSize);
+ return -1;
+ }
+
+ // Most instructions can be placed in any decoder slot.
+ return 0;
+}
+
+bool SystemZHazardRecognizer::isFPdOpPreferred_distance(const SUnit *SU) {
+ assert (SU->isUnbuffered);
+ // If this is the first FPd op, it should be scheduled high.
+ if (LastFPdOpCycleIdx == UINT_MAX)
+ return true;
+ // If this is not the first PFd op, it should go into the other side
+ // of the processor to use the other FPd unit there. This should
+ // generally happen if two FPd ops are placed with 2 other
+ // instructions between them (modulo 6).
+ if (LastFPdOpCycleIdx > getCurrCycleIdx())
+ return ((LastFPdOpCycleIdx - getCurrCycleIdx()) == 3);
+ return ((getCurrCycleIdx() - LastFPdOpCycleIdx) == 3);
+}
+
+int SystemZHazardRecognizer::
+resourcesCost(SUnit *SU) {
+ int Cost = 0;
+
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ if (!SC->isValid())
+ return 0;
+
+ // For a FPd op, either return min or max value as indicated by the
+ // distance to any prior FPd op.
+ if (SU->isUnbuffered)
+ Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
+ // For other instructions, give a cost to the use of the critical resource.
+ else if (CriticalResourceIdx != UINT_MAX) {
+ for (TargetSchedModel::ProcResIter
+ PI = SchedModel->getWriteProcResBegin(SC),
+ PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
+ if (PI->ProcResourceIdx == CriticalResourceIdx)
+ Cost = PI->Cycles;
+ }
+
+ return Cost;
+}
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.h b/contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.h
new file mode 100644
index 0000000..8fa54ee
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.h
@@ -0,0 +1,128 @@
+//=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a hazard recognizer for the SystemZ scheduler.
+//
+// This class is used by the SystemZ scheduling strategy to maintain
+// the state during scheduling, and provide cost functions for
+// scheduling candidates. This includes:
+//
+// * Decoder grouping. A decoder group can maximally hold 3 uops, and
+// instructions that always begin a new group should be scheduled when
+// the current decoder group is empty.
+// * Processor resources usage. It is beneficial to balance the use of
+// resources.
+//
+// ===---------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H
+#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H
+
+#include "SystemZSubtarget.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineScheduler.h"
+#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+namespace llvm {
+
+/// SystemZHazardRecognizer maintains the state during scheduling.
+class SystemZHazardRecognizer : public ScheduleHazardRecognizer {
+
+ ScheduleDAGMI *DAG;
+ const TargetSchedModel *SchedModel;
+
+ /// Keep track of the number of decoder slots used in the current
+ /// decoder group.
+ unsigned CurrGroupSize;
+
+ /// The tracking of resources here are quite similar to the common
+ /// code use of a critical resource. However, z13 differs in the way
+ /// that it has two processor sides which may be interesting to
+ /// model in the future (a work in progress).
+
+ /// Counters for the number of uops scheduled per processor
+ /// resource.
+ SmallVector<int, 0> ProcResourceCounters;
+
+ /// This is the resource with the greatest queue, which the
+ /// scheduler tries to avoid.
+ unsigned CriticalResourceIdx;
+
+ /// Return the number of decoder slots MI requires.
+ inline unsigned getNumDecoderSlots(SUnit *SU) const;
+
+ /// Return true if MI fits into current decoder group.
+ bool fitsIntoCurrentGroup(SUnit *SU) const;
+
+ /// Two decoder groups per cycle are formed (for z13), meaning 2x3
+ /// instructions. This function returns a number between 0 and 5,
+ /// representing the current decoder slot of the current cycle.
+ unsigned getCurrCycleIdx();
+
+ /// LastFPdOpCycleIdx stores the numbeer returned by getCurrCycleIdx()
+ /// when a stalling operation is scheduled (which uses the FPd resource).
+ unsigned LastFPdOpCycleIdx;
+
+ /// A counter of decoder groups scheduled.
+ unsigned GrpCount;
+
+ unsigned getCurrGroupSize() {return CurrGroupSize;};
+
+ /// Start next decoder group.
+ void nextGroup(bool DbgOutput = true);
+
+ /// Clear all counters for processor resources.
+ void clearProcResCounters();
+
+ /// With the goal of alternating processor sides for stalling (FPd)
+ /// ops, return true if it seems good to schedule an FPd op next.
+ bool isFPdOpPreferred_distance(const SUnit *SU);
+
+public:
+ SystemZHazardRecognizer(const MachineSchedContext *C);
+
+ void setDAG(ScheduleDAGMI *dag) {
+ DAG = dag;
+ SchedModel = dag->getSchedModel();
+ }
+
+ HazardType getHazardType(SUnit *m, int Stalls = 0) override;
+ void Reset() override;
+ void EmitInstruction(SUnit *SU) override;
+
+ // Cost functions used by SystemZPostRASchedStrategy while
+ // evaluating candidates.
+
+ /// Return the cost of decoder grouping for SU. If SU must start a
+ /// new decoder group, this is negative if this fits the schedule or
+ /// positive if it would mean ending a group prematurely. For normal
+ /// instructions this returns 0.
+ int groupingCost(SUnit *SU) const;
+
+ /// Return the cost of SU in regards to processor resources usage.
+ /// A positive value means it would be better to wait with SU, while
+ /// a negative value means it would be good to schedule SU next.
+ int resourcesCost(SUnit *SU);
+
+#ifndef NDEBUG
+ // Debug dumping.
+ std::string CurGroupDbg; // current group as text
+ void dumpSU(SUnit *SU, raw_ostream &OS) const;
+ void dumpCurrGroup(std::string Msg = "") const;
+ void dumpProcResourceCounters() const;
+#endif
+};
+
+} // namespace llvm
+
+#endif /* LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H */
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index cd7fcc3..920b6e4 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -117,7 +117,7 @@ static uint64_t allOnes(unsigned int Count) {
// case the result will be truncated as part of the operation).
struct RxSBGOperands {
RxSBGOperands(unsigned Op, SDValue N)
- : Opcode(Op), BitSize(N.getValueType().getSizeInBits()),
+ : Opcode(Op), BitSize(N.getValueSizeInBits()),
Mask(allOnes(BitSize)), Input(N), Start(64 - BitSize), End(63),
Rotate(0) {}
@@ -339,7 +339,7 @@ public:
}
// Override MachineFunctionPass.
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SystemZ DAG->DAG Pattern Instruction Selection";
}
@@ -709,7 +709,7 @@ bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op,
// It's only an insertion if all bits are covered or are known to be zero.
// The inner check covers all cases but is more expensive.
- uint64_t Used = allOnes(Op.getValueType().getSizeInBits());
+ uint64_t Used = allOnes(Op.getValueSizeInBits());
if (Used != (AndMask | InsertMask)) {
APInt KnownZero, KnownOne;
CurDAG->computeKnownBits(Op.getOperand(0), KnownZero, KnownOne);
@@ -749,7 +749,7 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const {
case ISD::TRUNCATE: {
if (RxSBG.Opcode == SystemZ::RNSBG)
return false;
- uint64_t BitSize = N.getValueType().getSizeInBits();
+ uint64_t BitSize = N.getValueSizeInBits();
uint64_t Mask = allOnes(BitSize);
if (!refineRxSBGMask(RxSBG, Mask))
return false;
@@ -825,19 +825,19 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const {
case ISD::ZERO_EXTEND:
if (RxSBG.Opcode != SystemZ::RNSBG) {
// Restrict the mask to the extended operand.
- unsigned InnerBitSize = N.getOperand(0).getValueType().getSizeInBits();
+ unsigned InnerBitSize = N.getOperand(0).getValueSizeInBits();
if (!refineRxSBGMask(RxSBG, allOnes(InnerBitSize)))
return false;
RxSBG.Input = N.getOperand(0);
return true;
}
- // Fall through.
+ LLVM_FALLTHROUGH;
case ISD::SIGN_EXTEND: {
// Check that the extension bits are don't-care (i.e. are masked out
// by the final mask).
- unsigned InnerBitSize = N.getOperand(0).getValueType().getSizeInBits();
+ unsigned InnerBitSize = N.getOperand(0).getValueSizeInBits();
if (maskMatters(RxSBG, allOnes(RxSBG.BitSize) - allOnes(InnerBitSize)))
return false;
@@ -851,7 +851,7 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const {
return false;
uint64_t Count = CountNode->getZExtValue();
- unsigned BitSize = N.getValueType().getSizeInBits();
+ unsigned BitSize = N.getValueSizeInBits();
if (Count < 1 || Count >= BitSize)
return false;
@@ -878,7 +878,7 @@ bool SystemZDAGToDAGISel::expandRxSBG(RxSBGOperands &RxSBG) const {
return false;
uint64_t Count = CountNode->getZExtValue();
- unsigned BitSize = N.getValueType().getSizeInBits();
+ unsigned BitSize = N.getValueSizeInBits();
if (Count < 1 || Count >= BitSize)
return false;
@@ -935,49 +935,55 @@ bool SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) {
Count += 1;
if (Count == 0)
return false;
- if (Count == 1) {
- // Prefer to use normal shift instructions over RISBG, since they can handle
- // all cases and are sometimes shorter.
- if (N->getOpcode() != ISD::AND)
- return false;
- // Prefer register extensions like LLC over RISBG. Also prefer to start
- // out with normal ANDs if one instruction would be enough. We can convert
- // these ANDs into an RISBG later if a three-address instruction is useful.
- if (VT == MVT::i32 ||
- RISBG.Mask == 0xff ||
- RISBG.Mask == 0xffff ||
- SystemZ::isImmLF(~RISBG.Mask) ||
- SystemZ::isImmHF(~RISBG.Mask)) {
- // Force the new mask into the DAG, since it may include known-one bits.
- auto *MaskN = cast<ConstantSDNode>(N->getOperand(1).getNode());
- if (MaskN->getZExtValue() != RISBG.Mask) {
- SDValue NewMask = CurDAG->getConstant(RISBG.Mask, DL, VT);
- N = CurDAG->UpdateNodeOperands(N, N->getOperand(0), NewMask);
- SelectCode(N);
- return true;
- }
- return false;
- }
- }
+ // Prefer to use normal shift instructions over RISBG, since they can handle
+ // all cases and are sometimes shorter.
+ if (Count == 1 && N->getOpcode() != ISD::AND)
+ return false;
- // If the RISBG operands require no rotation and just masks the bottom
- // 8/16 bits, attempt to convert this to a LLC zero extension.
- if (RISBG.Rotate == 0 && (RISBG.Mask == 0xff || RISBG.Mask == 0xffff)) {
- unsigned OpCode = (RISBG.Mask == 0xff ? SystemZ::LLGCR : SystemZ::LLGHR);
- if (VT == MVT::i32) {
- if (Subtarget->hasHighWord())
- OpCode = (RISBG.Mask == 0xff ? SystemZ::LLCRMux : SystemZ::LLHRMux);
- else
- OpCode = (RISBG.Mask == 0xff ? SystemZ::LLCR : SystemZ::LLHR);
+ // Prefer register extensions like LLC over RISBG. Also prefer to start
+ // out with normal ANDs if one instruction would be enough. We can convert
+ // these ANDs into an RISBG later if a three-address instruction is useful.
+ if (RISBG.Rotate == 0) {
+ bool PreferAnd = false;
+ // Prefer AND for any 32-bit and-immediate operation.
+ if (VT == MVT::i32)
+ PreferAnd = true;
+ // As well as for any 64-bit operation that can be implemented via LLC(R),
+ // LLH(R), LLGT(R), or one of the and-immediate instructions.
+ else if (RISBG.Mask == 0xff ||
+ RISBG.Mask == 0xffff ||
+ RISBG.Mask == 0x7fffffff ||
+ SystemZ::isImmLF(~RISBG.Mask) ||
+ SystemZ::isImmHF(~RISBG.Mask))
+ PreferAnd = true;
+ // And likewise for the LLZRGF instruction, which doesn't have a register
+ // to register version.
+ else if (auto *Load = dyn_cast<LoadSDNode>(RISBG.Input)) {
+ if (Load->getMemoryVT() == MVT::i32 &&
+ (Load->getExtensionType() == ISD::EXTLOAD ||
+ Load->getExtensionType() == ISD::ZEXTLOAD) &&
+ RISBG.Mask == 0xffffff00 &&
+ Subtarget->hasLoadAndZeroRightmostByte())
+ PreferAnd = true;
+ }
+ if (PreferAnd) {
+ // Replace the current node with an AND. Note that the current node
+ // might already be that same AND, in which case it is already CSE'd
+ // with it, and we must not call ReplaceNode.
+ SDValue In = convertTo(DL, VT, RISBG.Input);
+ SDValue Mask = CurDAG->getConstant(RISBG.Mask, DL, VT);
+ SDValue New = CurDAG->getNode(ISD::AND, DL, VT, In, Mask);
+ if (N != New.getNode()) {
+ insertDAGNode(CurDAG, N, Mask);
+ insertDAGNode(CurDAG, N, New);
+ ReplaceNode(N, New.getNode());
+ N = New.getNode();
+ }
+ // Now, select the machine opcode to implement this operation.
+ SelectCode(N);
+ return true;
}
-
- SDValue In = convertTo(DL, VT, RISBG.Input);
- SDValue New = convertTo(
- DL, VT, SDValue(CurDAG->getMachineNode(OpCode, DL, VT, In), 0));
- ReplaceUses(N, New.getNode());
- CurDAG->RemoveDeadNode(N);
- return true;
}
unsigned Opcode = SystemZ::RISBG;
@@ -1136,8 +1142,7 @@ bool SystemZDAGToDAGISel::tryScatter(StoreSDNode *Store, unsigned Opcode) {
SDValue Value = Store->getValue();
if (Value.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
return false;
- if (Store->getMemoryVT().getSizeInBits() !=
- Value.getValueType().getSizeInBits())
+ if (Store->getMemoryVT().getSizeInBits() != Value.getValueSizeInBits())
return false;
SDValue ElemV = Value.getOperand(1);
@@ -1176,7 +1181,7 @@ bool SystemZDAGToDAGISel::canUseBlockOperation(StoreSDNode *Store,
return false;
// There's no chance of overlap if the load is invariant.
- if (Load->isInvariant())
+ if (Load->isInvariant() && Load->isDereferenceable())
return true;
// Otherwise we need to check whether there's an alias.
@@ -1265,7 +1270,7 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
if (Node->getOperand(1).getOpcode() != ISD::Constant)
if (tryRxSBG(Node, SystemZ::RNSBG))
return;
- // Fall through.
+ LLVM_FALLTHROUGH;
case ISD::ROTL:
case ISD::SHL:
case ISD::SRL:
@@ -1291,8 +1296,14 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
SDValue Op0 = Node->getOperand(0);
SDValue Op1 = Node->getOperand(1);
// Prefer to put any load first, so that it can be matched as a
- // conditional load.
- if (Op1.getOpcode() == ISD::LOAD && Op0.getOpcode() != ISD::LOAD) {
+ // conditional load. Likewise for constants in range for LOCHI.
+ if ((Op1.getOpcode() == ISD::LOAD && Op0.getOpcode() != ISD::LOAD) ||
+ (Subtarget->hasLoadStoreOnCond2() &&
+ Node->getValueType(0).isInteger() &&
+ Op1.getOpcode() == ISD::Constant &&
+ isInt<16>(cast<ConstantSDNode>(Op1)->getSExtValue()) &&
+ !(Op0.getOpcode() == ISD::Constant &&
+ isInt<16>(cast<ConstantSDNode>(Op0)->getSExtValue())))) {
SDValue CCValid = Node->getOperand(2);
SDValue CCMask = Node->getOperand(3);
uint64_t ConstCCValid =
@@ -1310,7 +1321,7 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
case ISD::INSERT_VECTOR_ELT: {
EVT VT = Node->getValueType(0);
- unsigned ElemBitSize = VT.getVectorElementType().getSizeInBits();
+ unsigned ElemBitSize = VT.getScalarSizeInBits();
if (ElemBitSize == 32) {
if (tryGather(Node, SystemZ::VGEF))
return;
@@ -1323,7 +1334,7 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
case ISD::STORE: {
auto *Store = cast<StoreSDNode>(Node);
- unsigned ElemBitSize = Store->getValue().getValueType().getSizeInBits();
+ unsigned ElemBitSize = Store->getValue().getValueSizeInBits();
if (ElemBitSize == 32) {
if (tryScatter(Store, SystemZ::VSCEF))
return;
@@ -1375,6 +1386,29 @@ SelectInlineAsmMemoryOperand(const SDValue &Op,
}
if (selectBDXAddr(Form, DispRange, Op, Base, Disp, Index)) {
+ const TargetRegisterClass *TRC =
+ Subtarget->getRegisterInfo()->getPointerRegClass(*MF);
+ SDLoc DL(Base);
+ SDValue RC = CurDAG->getTargetConstant(TRC->getID(), DL, MVT::i32);
+
+ // Make sure that the base address doesn't go into %r0.
+ // If it's a TargetFrameIndex or a fixed register, we shouldn't do anything.
+ if (Base.getOpcode() != ISD::TargetFrameIndex &&
+ Base.getOpcode() != ISD::Register) {
+ Base =
+ SDValue(CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS,
+ DL, Base.getValueType(),
+ Base, RC), 0);
+ }
+
+ // Make sure that the index register isn't assigned to %r0 either.
+ if (Index.getOpcode() != ISD::Register) {
+ Index =
+ SDValue(CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS,
+ DL, Index.getValueType(),
+ Index, RC), 0);
+ }
+
OutOps.push_back(Base);
OutOps.push_back(Disp);
OutOps.push_back(Index);
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 14991bb..2d0a06a 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -20,6 +20,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/IR/Intrinsics.h"
#include <cctype>
@@ -531,6 +532,46 @@ bool SystemZTargetLowering::isLegalAddressingMode(const DataLayout &DL,
return AM.Scale == 0 || AM.Scale == 1;
}
+bool SystemZTargetLowering::isFoldableMemAccessOffset(Instruction *I,
+ int64_t Offset) const {
+ // This only applies to z13.
+ if (!Subtarget.hasVector())
+ return true;
+
+ // * Use LDE instead of LE/LEY to avoid partial register
+ // dependencies (LDE only supports small offsets).
+ // * Utilize the vector registers to hold floating point
+ // values (vector load / store instructions only support small
+ // offsets).
+
+ assert (isa<LoadInst>(I) || isa<StoreInst>(I));
+ Type *MemAccessTy = (isa<LoadInst>(I) ? I->getType() :
+ I->getOperand(0)->getType());
+ bool IsFPAccess = MemAccessTy->isFloatingPointTy();
+ bool IsVectorAccess = MemAccessTy->isVectorTy();
+
+ // A store of an extracted vector element will be combined into a VSTE type
+ // instruction.
+ if (!IsVectorAccess && isa<StoreInst>(I)) {
+ Value *DataOp = I->getOperand(0);
+ if (isa<ExtractElementInst>(DataOp))
+ IsVectorAccess = true;
+ }
+
+ // A load which gets inserted into a vector element will be combined into a
+ // VLE type instruction.
+ if (!IsVectorAccess && isa<LoadInst>(I) && I->hasOneUse()) {
+ User *LoadUser = *I->user_begin();
+ if (isa<InsertElementInst>(LoadUser))
+ IsVectorAccess = true;
+ }
+
+ if (!isUInt<12>(Offset) && (IsFPAccess || IsVectorAccess))
+ return false;
+
+ return true;
+}
+
bool SystemZTargetLowering::isTruncateFree(Type *FromType, Type *ToType) const {
if (!FromType->isIntegerTy() || !ToType->isIntegerTy())
return false;
@@ -864,7 +905,7 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
SystemZMachineFunctionInfo *FuncInfo =
MF.getInfo<SystemZMachineFunctionInfo>();
@@ -927,8 +968,8 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
assert(VA.isMemLoc() && "Argument not register or memory");
// Create the frame index object for this incoming parameter.
- int FI = MFI->CreateFixedObject(LocVT.getSizeInBits() / 8,
- VA.getLocMemOffset(), true);
+ int FI = MFI.CreateFixedObject(LocVT.getSizeInBits() / 8,
+ VA.getLocMemOffset(), true);
// Create the SelectionDAG nodes corresponding to a load
// from this parameter. Unpromoted ints and floats are
@@ -971,12 +1012,12 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
// Likewise the address (in the form of a frame index) of where the
// first stack vararg would be. The 1-byte size here is arbitrary.
int64_t StackSize = CCInfo.getNextStackOffset();
- FuncInfo->setVarArgsFrameIndex(MFI->CreateFixedObject(1, StackSize, true));
+ FuncInfo->setVarArgsFrameIndex(MFI.CreateFixedObject(1, StackSize, true));
// ...and a similar frame index for the caller-allocated save area
// that will be used to store the incoming registers.
int64_t RegSaveOffset = TFL->getOffsetOfLocalArea();
- unsigned RegSaveIndex = MFI->CreateFixedObject(1, RegSaveOffset, true);
+ unsigned RegSaveIndex = MFI.CreateFixedObject(1, RegSaveOffset, true);
FuncInfo->setRegSaveFrameIndex(RegSaveIndex);
// Store the FPR varargs in the reserved frame slots. (We store the
@@ -985,7 +1026,7 @@ SDValue SystemZTargetLowering::LowerFormalArguments(
SDValue MemOps[SystemZ::NumArgFPRs];
for (unsigned I = NumFixedFPRs; I < SystemZ::NumArgFPRs; ++I) {
unsigned Offset = TFL->getRegSpillOffset(SystemZ::ArgFPRs[I]);
- int FI = MFI->CreateFixedObject(8, RegSaveOffset + Offset, true);
+ int FI = MFI.CreateFixedObject(8, RegSaveOffset + Offset, true);
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
unsigned VReg = MF.addLiveIn(SystemZ::ArgFPRs[I],
&SystemZ::FP64BitRegClass);
@@ -1837,8 +1878,7 @@ static void adjustICmpTruncate(SelectionDAG &DAG, const SDLoc &DL,
C.Op1.getOpcode() == ISD::Constant &&
cast<ConstantSDNode>(C.Op1)->getZExtValue() == 0) {
auto *L = cast<LoadSDNode>(C.Op0.getOperand(0));
- if (L->getMemoryVT().getStoreSizeInBits()
- <= C.Op0.getValueType().getSizeInBits()) {
+ if (L->getMemoryVT().getStoreSizeInBits() <= C.Op0.getValueSizeInBits()) {
unsigned Type = L->getExtensionType();
if ((Type == ISD::ZEXTLOAD && C.ICmpType != SystemZICMP::SignedOnly) ||
(Type == ISD::SEXTLOAD && C.ICmpType != SystemZICMP::UnsignedOnly)) {
@@ -1857,7 +1897,7 @@ static bool isSimpleShift(SDValue N, unsigned &ShiftVal) {
return false;
uint64_t Amount = Shift->getZExtValue();
- if (Amount >= N.getValueType().getSizeInBits())
+ if (Amount >= N.getValueSizeInBits())
return false;
ShiftVal = Amount;
@@ -2008,7 +2048,7 @@ static void adjustForTestUnderMask(SelectionDAG &DAG, const SDLoc &DL,
// Check whether the combination of mask, comparison value and comparison
// type are suitable.
- unsigned BitSize = NewC.Op0.getValueType().getSizeInBits();
+ unsigned BitSize = NewC.Op0.getValueSizeInBits();
unsigned NewCCMask, ShiftVal;
if (NewC.ICmpType != SystemZICMP::SignedOnly &&
NewC.Op0.getOpcode() == ISD::SHL &&
@@ -2542,16 +2582,15 @@ SDValue SystemZTargetLowering::lowerTLSGetOffset(GlobalAddressSDNode *Node,
SDValue SystemZTargetLowering::lowerThreadPointer(const SDLoc &DL,
SelectionDAG &DAG) const {
+ SDValue Chain = DAG.getEntryNode();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
// The high part of the thread pointer is in access register 0.
- SDValue TPHi = DAG.getNode(SystemZISD::EXTRACT_ACCESS, DL, MVT::i32,
- DAG.getConstant(0, DL, MVT::i32));
+ SDValue TPHi = DAG.getCopyFromReg(Chain, DL, SystemZ::A0, MVT::i32);
TPHi = DAG.getNode(ISD::ANY_EXTEND, DL, PtrVT, TPHi);
// The low part of the thread pointer is in access register 1.
- SDValue TPLo = DAG.getNode(SystemZISD::EXTRACT_ACCESS, DL, MVT::i32,
- DAG.getConstant(1, DL, MVT::i32));
+ SDValue TPLo = DAG.getCopyFromReg(Chain, DL, SystemZ::A1, MVT::i32);
TPLo = DAG.getNode(ISD::ZERO_EXTEND, DL, PtrVT, TPLo);
// Merge them into a single 64-bit address.
@@ -2691,8 +2730,8 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP,
SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
SDLoc DL(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
@@ -2703,7 +2742,7 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
int BackChainIdx = FI->getFramePointerSaveIndex();
if (!BackChainIdx) {
// By definition, the frame address is the address of the back chain.
- BackChainIdx = MFI->CreateFixedObject(8, -SystemZMC::CallFrameSize, false);
+ BackChainIdx = MFI.CreateFixedObject(8, -SystemZMC::CallFrameSize, false);
FI->setFramePointerSaveIndex(BackChainIdx);
}
SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);
@@ -2719,8 +2758,8 @@ SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
SDValue SystemZTargetLowering::lowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
@@ -3080,7 +3119,7 @@ SDValue SystemZTargetLowering::lowerCTPOP(SDValue Op,
if (VT.isVector()) {
Op = DAG.getNode(ISD::BITCAST, DL, MVT::v16i8, Op);
Op = DAG.getNode(SystemZISD::POPCNT, DL, MVT::v16i8, Op);
- switch (VT.getVectorElementType().getSizeInBits()) {
+ switch (VT.getScalarSizeInBits()) {
case 8:
break;
case 16: {
@@ -3288,8 +3327,7 @@ SDValue SystemZTargetLowering::lowerATOMIC_LOAD_SUB(SDValue Op,
if (NegSrc2.getNode())
return DAG.getAtomic(ISD::ATOMIC_LOAD_ADD, DL, MemVT,
Node->getChain(), Node->getBasePtr(), NegSrc2,
- Node->getMemOperand(), Node->getOrdering(),
- Node->getSynchScope());
+ Node->getMemOperand());
// Use the node as-is.
return Op;
@@ -4355,7 +4393,7 @@ SDValue SystemZTargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,
}
// Otherwise bitcast to the equivalent integer form and insert via a GPR.
- MVT IntVT = MVT::getIntegerVT(VT.getVectorElementType().getSizeInBits());
+ MVT IntVT = MVT::getIntegerVT(VT.getScalarSizeInBits());
MVT IntVecVT = MVT::getVectorVT(IntVT, VT.getVectorNumElements());
SDValue Res = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, IntVecVT,
DAG.getNode(ISD::BITCAST, DL, IntVecVT, Op0),
@@ -4395,8 +4433,8 @@ SystemZTargetLowering::lowerExtendVectorInreg(SDValue Op, SelectionDAG &DAG,
SDValue PackedOp = Op.getOperand(0);
EVT OutVT = Op.getValueType();
EVT InVT = PackedOp.getValueType();
- unsigned ToBits = OutVT.getVectorElementType().getSizeInBits();
- unsigned FromBits = InVT.getVectorElementType().getSizeInBits();
+ unsigned ToBits = OutVT.getScalarSizeInBits();
+ unsigned FromBits = InVT.getScalarSizeInBits();
do {
FromBits *= 2;
EVT OutVT = MVT::getVectorVT(MVT::getIntegerVT(FromBits),
@@ -4413,7 +4451,7 @@ SDValue SystemZTargetLowering::lowerShift(SDValue Op, SelectionDAG &DAG,
SDValue Op1 = Op.getOperand(1);
SDLoc DL(Op);
EVT VT = Op.getValueType();
- unsigned ElemBitSize = VT.getVectorElementType().getSizeInBits();
+ unsigned ElemBitSize = VT.getScalarSizeInBits();
// See whether the shift vector is a splat represented as BUILD_VECTOR.
if (auto *BVN = dyn_cast<BuildVectorSDNode>(Op1)) {
@@ -4591,7 +4629,6 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
OPCODE(BR_CCMASK);
OPCODE(SELECT_CCMASK);
OPCODE(ADJDYNALLOC);
- OPCODE(EXTRACT_ACCESS);
OPCODE(POPCNT);
OPCODE(UMUL_LOHI64);
OPCODE(SDIVREM32);
@@ -4687,7 +4724,7 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
// Return true if VT is a vector whose elements are a whole number of bytes
// in width.
static bool canTreatAsByteVector(EVT VT) {
- return VT.isVector() && VT.getVectorElementType().getSizeInBits() % 8 == 0;
+ return VT.isVector() && VT.getScalarSizeInBits() % 8 == 0;
}
// Try to simplify an EXTRACT_VECTOR_ELT from a vector of type VecVT
@@ -4748,7 +4785,7 @@ SDValue SystemZTargetLowering::combineExtract(const SDLoc &DL, EVT ResVT,
// We're extracting the low part of one operand of the BUILD_VECTOR.
Op = Op.getOperand(End / OpBytesPerElement - 1);
if (!Op.getValueType().isInteger()) {
- EVT VT = MVT::getIntegerVT(Op.getValueType().getSizeInBits());
+ EVT VT = MVT::getIntegerVT(Op.getValueSizeInBits());
Op = DAG.getNode(ISD::BITCAST, DL, VT, Op);
DCI.AddToWorklist(Op.getNode());
}
@@ -4848,8 +4885,7 @@ SDValue SystemZTargetLowering::combineSIGN_EXTEND(
SDValue Inner = N0.getOperand(0);
if (SraAmt && Inner.hasOneUse() && Inner.getOpcode() == ISD::SHL) {
if (auto *ShlAmt = dyn_cast<ConstantSDNode>(Inner.getOperand(1))) {
- unsigned Extra = (VT.getSizeInBits() -
- N0.getValueType().getSizeInBits());
+ unsigned Extra = (VT.getSizeInBits() - N0.getValueSizeInBits());
unsigned NewShlAmt = ShlAmt->getZExtValue() + Extra;
unsigned NewSraAmt = SraAmt->getZExtValue() + Extra;
EVT ShiftVT = N0.getOperand(1).getValueType();
@@ -4972,8 +5008,8 @@ SDValue SystemZTargetLowering::combineJOIN_DWORDS(
SDValue SystemZTargetLowering::combineFP_ROUND(
SDNode *N, DAGCombinerInfo &DCI) const {
- // (fround (extract_vector_elt X 0))
- // (fround (extract_vector_elt X 1)) ->
+ // (fpround (extract_vector_elt X 0))
+ // (fpround (extract_vector_elt X 1)) ->
// (extract_vector_elt (VROUND X) 0)
// (extract_vector_elt (VROUND X) 1)
//
@@ -5070,14 +5106,20 @@ SDValue SystemZTargetLowering::combineSHIFTROT(
// Shift/rotate instructions only use the last 6 bits of the second operand
// register. If the second operand is the result of an AND with an immediate
// value that has its last 6 bits set, we can safely remove the AND operation.
+ //
+ // If the AND operation doesn't have the last 6 bits set, we can't remove it
+ // entirely, but we can still truncate it to a 16-bit value. This prevents
+ // us from ending up with a NILL with a signed operand, which will cause the
+ // instruction printer to abort.
SDValue N1 = N->getOperand(1);
if (N1.getOpcode() == ISD::AND) {
- auto *AndMask = dyn_cast<ConstantSDNode>(N1.getOperand(1));
+ SDValue AndMaskOp = N1->getOperand(1);
+ auto *AndMask = dyn_cast<ConstantSDNode>(AndMaskOp);
// The AND mask is constant
if (AndMask) {
auto AmtVal = AndMask->getZExtValue();
-
+
// Bottom 6 bits are set
if ((AmtVal & 0x3f) == 0x3f) {
SDValue AndOp = N1->getOperand(0);
@@ -5099,6 +5141,26 @@ SDValue SystemZTargetLowering::combineSHIFTROT(
return Replace;
}
+
+ // We can't remove the AND, but we can use NILL here (normally we would
+ // use NILF). Only keep the last 16 bits of the mask. The actual
+ // transformation will be handled by .td definitions.
+ } else if (AmtVal >> 16 != 0) {
+ SDValue AndOp = N1->getOperand(0);
+
+ auto NewMask = DAG.getConstant(AndMask->getZExtValue() & 0x0000ffff,
+ SDLoc(AndMaskOp),
+ AndMaskOp.getValueType());
+
+ auto NewAnd = DAG.getNode(N1.getOpcode(), SDLoc(N1), N1.getValueType(),
+ AndOp, NewMask);
+
+ SDValue Replace = DAG.getNode(N->getOpcode(), SDLoc(N),
+ N->getValueType(0), N->getOperand(0),
+ NewAnd);
+ DCI.AddToWorklist(Replace.getNode());
+
+ return Replace;
}
}
}
@@ -5180,7 +5242,8 @@ static unsigned forceReg(MachineInstr &MI, MachineOperand &Base,
// Implement EmitInstrWithCustomInserter for pseudo Select* instruction MI.
MachineBasicBlock *
SystemZTargetLowering::emitSelect(MachineInstr &MI,
- MachineBasicBlock *MBB) const {
+ MachineBasicBlock *MBB,
+ unsigned LOCROpcode) const {
const SystemZInstrInfo *TII =
static_cast<const SystemZInstrInfo *>(Subtarget.getInstrInfo());
@@ -5191,6 +5254,15 @@ SystemZTargetLowering::emitSelect(MachineInstr &MI,
unsigned CCMask = MI.getOperand(4).getImm();
DebugLoc DL = MI.getDebugLoc();
+ // Use LOCROpcode if possible.
+ if (LOCROpcode && Subtarget.hasLoadStoreOnCond()) {
+ BuildMI(*MBB, MI, DL, TII->get(LOCROpcode), DestReg)
+ .addReg(FalseReg).addReg(TrueReg)
+ .addImm(CCValid).addImm(CCMask);
+ MI.eraseFromParent();
+ return MBB;
+ }
+
MachineBasicBlock *StartMBB = MBB;
MachineBasicBlock *JoinMBB = splitBlockBefore(MI, MBB);
MachineBasicBlock *FalseMBB = emitBlockAfter(StartMBB);
@@ -5976,12 +6048,16 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
MachineInstr &MI, MachineBasicBlock *MBB) const {
switch (MI.getOpcode()) {
case SystemZ::Select32Mux:
+ return emitSelect(MI, MBB,
+ Subtarget.hasLoadStoreOnCond2()? SystemZ::LOCRMux : 0);
case SystemZ::Select32:
- case SystemZ::SelectF32:
+ return emitSelect(MI, MBB, SystemZ::LOCR);
case SystemZ::Select64:
+ return emitSelect(MI, MBB, SystemZ::LOCGR);
+ case SystemZ::SelectF32:
case SystemZ::SelectF64:
case SystemZ::SelectF128:
- return emitSelect(MI, MBB);
+ return emitSelect(MI, MBB, 0);
case SystemZ::CondStore8Mux:
return emitCondStore(MI, MBB, SystemZ::STCMux, 0, false);
@@ -5991,6 +6067,10 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
return emitCondStore(MI, MBB, SystemZ::STHMux, 0, false);
case SystemZ::CondStore16MuxInv:
return emitCondStore(MI, MBB, SystemZ::STHMux, 0, true);
+ case SystemZ::CondStore32Mux:
+ return emitCondStore(MI, MBB, SystemZ::STMux, SystemZ::STOCMux, false);
+ case SystemZ::CondStore32MuxInv:
+ return emitCondStore(MI, MBB, SystemZ::STMux, SystemZ::STOCMux, true);
case SystemZ::CondStore8:
return emitCondStore(MI, MBB, SystemZ::STC, 0, false);
case SystemZ::CondStore8Inv:
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index b1de893..7a21a47 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -83,10 +83,6 @@ enum NodeType : unsigned {
// base of the dynamically-allocatable area.
ADJDYNALLOC,
- // Extracts the value of a 32-bit access register. Operand 0 is
- // the number of the register.
- EXTRACT_ACCESS,
-
// Count number of bits set in operand 0 per byte.
POPCNT,
@@ -382,7 +378,7 @@ public:
//
// (c) there are no multiplication instructions for the widest integer
// type (v2i64).
- if (VT.getVectorElementType().getSizeInBits() % 8 == 0)
+ if (VT.getScalarSizeInBits() % 8 == 0)
return TypeWidenVector;
return TargetLoweringBase::getPreferredVectorAction(VT);
}
@@ -394,6 +390,7 @@ public:
bool isLegalAddImmediate(int64_t Imm) const override;
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty,
unsigned AS) const override;
+ bool isFoldableMemAccessOffset(Instruction *I, int64_t Offset) const override;
bool allowsMisalignedMemoryAccesses(EVT VT, unsigned AS,
unsigned Align,
bool *Fast) const override;
@@ -564,7 +561,8 @@ private:
MachineBasicBlock *Target) const;
// Implement EmitInstrWithCustomInserter for individual operation types.
- MachineBasicBlock *emitSelect(MachineInstr &MI, MachineBasicBlock *BB) const;
+ MachineBasicBlock *emitSelect(MachineInstr &MI, MachineBasicBlock *BB,
+ unsigned LOCROpcode) const;
MachineBasicBlock *emitCondStore(MachineInstr &MI, MachineBasicBlock *BB,
unsigned StoreOpcode, unsigned STOCOpcode,
bool Invert) const;
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h b/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h
index 2cb8aba..896b665 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrBuilder.h
@@ -27,7 +27,7 @@ static inline const MachineInstrBuilder &
addFrameReference(const MachineInstrBuilder &MIB, int FI) {
MachineInstr *MI = MIB;
MachineFunction &MF = *MI->getParent()->getParent();
- MachineFrameInfo *MFFrame = MF.getFrameInfo();
+ MachineFrameInfo &MFFrame = MF.getFrameInfo();
const MCInstrDesc &MCID = MI->getDesc();
auto Flags = MachineMemOperand::MONone;
if (MCID.mayLoad())
@@ -37,7 +37,7 @@ addFrameReference(const MachineInstrBuilder &MIB, int FI) {
int64_t Offset = 0;
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FI, Offset), Flags,
- MFFrame->getObjectSize(FI), MFFrame->getObjectAlignment(FI));
+ MFFrame.getObjectSize(FI), MFFrame.getObjectAlignment(FI));
return MIB.addFrameIndex(FI).addImm(Offset).addReg(0).addMemOperand(MMO);
}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td
index 8b32047..bb6d27e 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFP.td
@@ -27,28 +27,28 @@ defm CondStoreF64 : CondStores<FP64, nonvolatile_store,
// Load zero.
let hasSideEffects = 0, isAsCheapAsAMove = 1, isMoveImm = 1 in {
- def LZER : InherentRRE<"lzer", 0xB374, FP32, (fpimm0)>;
- def LZDR : InherentRRE<"lzdr", 0xB375, FP64, (fpimm0)>;
- def LZXR : InherentRRE<"lzxr", 0xB376, FP128, (fpimm0)>;
+ def LZER : InherentRRE<"lzer", 0xB374, FP32, fpimm0>;
+ def LZDR : InherentRRE<"lzdr", 0xB375, FP64, fpimm0>;
+ def LZXR : InherentRRE<"lzxr", 0xB376, FP128, fpimm0>;
}
// Moves between two floating-point registers.
let hasSideEffects = 0 in {
- def LER : UnaryRR <"le", 0x38, null_frag, FP32, FP32>;
- def LDR : UnaryRR <"ld", 0x28, null_frag, FP64, FP64>;
- def LXR : UnaryRRE<"lx", 0xB365, null_frag, FP128, FP128>;
+ def LER : UnaryRR <"ler", 0x38, null_frag, FP32, FP32>;
+ def LDR : UnaryRR <"ldr", 0x28, null_frag, FP64, FP64>;
+ def LXR : UnaryRRE<"lxr", 0xB365, null_frag, FP128, FP128>;
// For z13 we prefer LDR over LER to avoid partial register dependencies.
let isCodeGenOnly = 1 in
- def LDR32 : UnaryRR<"ld", 0x28, null_frag, FP32, FP32>;
+ def LDR32 : UnaryRR<"ldr", 0x28, null_frag, FP32, FP32>;
}
// Moves between two floating-point registers that also set the condition
// codes.
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
- defm LTEBR : LoadAndTestRRE<"lteb", 0xB302, FP32>;
- defm LTDBR : LoadAndTestRRE<"ltdb", 0xB312, FP64>;
- defm LTXBR : LoadAndTestRRE<"ltxb", 0xB342, FP128>;
+ defm LTEBR : LoadAndTestRRE<"ltebr", 0xB302, FP32>;
+ defm LTDBR : LoadAndTestRRE<"ltdbr", 0xB312, FP64>;
+ defm LTXBR : LoadAndTestRRE<"ltxbr", 0xB342, FP128>;
}
// Note that LTxBRCompare is not available if we have vector support,
// since load-and-test instructions will partially clobber the target
@@ -73,13 +73,13 @@ let Predicates = [FeatureVector] in {
}
// Moves between 64-bit integer and floating-point registers.
-def LGDR : UnaryRRE<"lgd", 0xB3CD, bitconvert, GR64, FP64>;
-def LDGR : UnaryRRE<"ldg", 0xB3C1, bitconvert, FP64, GR64>;
+def LGDR : UnaryRRE<"lgdr", 0xB3CD, bitconvert, GR64, FP64>;
+def LDGR : UnaryRRE<"ldgr", 0xB3C1, bitconvert, FP64, GR64>;
// fcopysign with an FP32 result.
let isCodeGenOnly = 1 in {
- def CPSDRss : BinaryRRF<"cpsd", 0xB372, fcopysign, FP32, FP32>;
- def CPSDRsd : BinaryRRF<"cpsd", 0xB372, fcopysign, FP32, FP64>;
+ def CPSDRss : BinaryRRFb<"cpsdr", 0xB372, fcopysign, FP32, FP32, FP32>;
+ def CPSDRsd : BinaryRRFb<"cpsdr", 0xB372, fcopysign, FP32, FP32, FP64>;
}
// The sign of an FP128 is in the high register.
@@ -88,8 +88,8 @@ def : Pat<(fcopysign FP32:$src1, FP128:$src2),
// fcopysign with an FP64 result.
let isCodeGenOnly = 1 in
- def CPSDRds : BinaryRRF<"cpsd", 0xB372, fcopysign, FP64, FP32>;
-def CPSDRdd : BinaryRRF<"cpsd", 0xB372, fcopysign, FP64, FP64>;
+ def CPSDRds : BinaryRRFb<"cpsdr", 0xB372, fcopysign, FP64, FP64, FP32>;
+def CPSDRdd : BinaryRRFb<"cpsdr", 0xB372, fcopysign, FP64, FP64, FP64>;
// The sign of an FP128 is in the high register.
def : Pat<(fcopysign FP64:$src1, FP128:$src2),
@@ -154,26 +154,26 @@ let SimpleBDXStore = 1 in {
// Convert floating-point values to narrower representations, rounding
// according to the current mode. The destination of LEXBR and LDXBR
// is a 128-bit value, but only the first register of the pair is used.
-def LEDBR : UnaryRRE<"ledb", 0xB344, fround, FP32, FP64>;
-def LEXBR : UnaryRRE<"lexb", 0xB346, null_frag, FP128, FP128>;
-def LDXBR : UnaryRRE<"ldxb", 0xB345, null_frag, FP128, FP128>;
+def LEDBR : UnaryRRE<"ledbr", 0xB344, fpround, FP32, FP64>;
+def LEXBR : UnaryRRE<"lexbr", 0xB346, null_frag, FP128, FP128>;
+def LDXBR : UnaryRRE<"ldxbr", 0xB345, null_frag, FP128, FP128>;
-def LEDBRA : UnaryRRF4<"ledbra", 0xB344, FP32, FP64>,
+def LEDBRA : TernaryRRFe<"ledbra", 0xB344, FP32, FP64>,
Requires<[FeatureFPExtension]>;
-def LEXBRA : UnaryRRF4<"lexbra", 0xB346, FP128, FP128>,
+def LEXBRA : TernaryRRFe<"lexbra", 0xB346, FP128, FP128>,
Requires<[FeatureFPExtension]>;
-def LDXBRA : UnaryRRF4<"ldxbra", 0xB345, FP128, FP128>,
+def LDXBRA : TernaryRRFe<"ldxbra", 0xB345, FP128, FP128>,
Requires<[FeatureFPExtension]>;
-def : Pat<(f32 (fround FP128:$src)),
+def : Pat<(f32 (fpround FP128:$src)),
(EXTRACT_SUBREG (LEXBR FP128:$src), subreg_hr32)>;
-def : Pat<(f64 (fround FP128:$src)),
+def : Pat<(f64 (fpround FP128:$src)),
(EXTRACT_SUBREG (LDXBR FP128:$src), subreg_h64)>;
// Extend register floating-point values to wider representations.
-def LDEBR : UnaryRRE<"ldeb", 0xB304, fextend, FP64, FP32>;
-def LXEBR : UnaryRRE<"lxeb", 0xB306, fextend, FP128, FP32>;
-def LXDBR : UnaryRRE<"lxdb", 0xB305, fextend, FP128, FP64>;
+def LDEBR : UnaryRRE<"ldebr", 0xB304, fpextend, FP64, FP32>;
+def LXEBR : UnaryRRE<"lxebr", 0xB306, fpextend, FP128, FP32>;
+def LXDBR : UnaryRRE<"lxdbr", 0xB305, fpextend, FP128, FP64>;
// Extend memory floating-point values to wider representations.
def LDEB : UnaryRXE<"ldeb", 0xED04, extloadf32, FP64, 4>;
@@ -181,23 +181,35 @@ def LXEB : UnaryRXE<"lxeb", 0xED06, extloadf32, FP128, 4>;
def LXDB : UnaryRXE<"lxdb", 0xED05, extloadf64, FP128, 8>;
// Convert a signed integer register value to a floating-point one.
-def CEFBR : UnaryRRE<"cefb", 0xB394, sint_to_fp, FP32, GR32>;
-def CDFBR : UnaryRRE<"cdfb", 0xB395, sint_to_fp, FP64, GR32>;
-def CXFBR : UnaryRRE<"cxfb", 0xB396, sint_to_fp, FP128, GR32>;
+def CEFBR : UnaryRRE<"cefbr", 0xB394, sint_to_fp, FP32, GR32>;
+def CDFBR : UnaryRRE<"cdfbr", 0xB395, sint_to_fp, FP64, GR32>;
+def CXFBR : UnaryRRE<"cxfbr", 0xB396, sint_to_fp, FP128, GR32>;
-def CEGBR : UnaryRRE<"cegb", 0xB3A4, sint_to_fp, FP32, GR64>;
-def CDGBR : UnaryRRE<"cdgb", 0xB3A5, sint_to_fp, FP64, GR64>;
-def CXGBR : UnaryRRE<"cxgb", 0xB3A6, sint_to_fp, FP128, GR64>;
+def CEGBR : UnaryRRE<"cegbr", 0xB3A4, sint_to_fp, FP32, GR64>;
+def CDGBR : UnaryRRE<"cdgbr", 0xB3A5, sint_to_fp, FP64, GR64>;
+def CXGBR : UnaryRRE<"cxgbr", 0xB3A6, sint_to_fp, FP128, GR64>;
+
+// The FP extension feature provides versions of the above that allow
+// specifying rounding mode and inexact-exception suppression flags.
+let Predicates = [FeatureFPExtension] in {
+ def CEFBRA : TernaryRRFe<"cefbra", 0xB394, FP32, GR32>;
+ def CDFBRA : TernaryRRFe<"cdfbra", 0xB395, FP64, GR32>;
+ def CXFBRA : TernaryRRFe<"cxfbra", 0xB396, FP128, GR32>;
+
+ def CEGBRA : TernaryRRFe<"cegbra", 0xB3A4, FP32, GR64>;
+ def CDGBRA : TernaryRRFe<"cdgbra", 0xB3A5, FP64, GR64>;
+ def CXGBRA : TernaryRRFe<"cxgbra", 0xB3A6, FP128, GR64>;
+}
// Convert am unsigned integer register value to a floating-point one.
let Predicates = [FeatureFPExtension] in {
- def CELFBR : UnaryRRF4<"celfbr", 0xB390, FP32, GR32>;
- def CDLFBR : UnaryRRF4<"cdlfbr", 0xB391, FP64, GR32>;
- def CXLFBR : UnaryRRF4<"cxlfbr", 0xB392, FP128, GR32>;
+ def CELFBR : TernaryRRFe<"celfbr", 0xB390, FP32, GR32>;
+ def CDLFBR : TernaryRRFe<"cdlfbr", 0xB391, FP64, GR32>;
+ def CXLFBR : TernaryRRFe<"cxlfbr", 0xB392, FP128, GR32>;
- def CELGBR : UnaryRRF4<"celgbr", 0xB3A0, FP32, GR64>;
- def CDLGBR : UnaryRRF4<"cdlgbr", 0xB3A1, FP64, GR64>;
- def CXLGBR : UnaryRRF4<"cxlgbr", 0xB3A2, FP128, GR64>;
+ def CELGBR : TernaryRRFe<"celgbr", 0xB3A0, FP32, GR64>;
+ def CDLGBR : TernaryRRFe<"cdlgbr", 0xB3A1, FP64, GR64>;
+ def CXLGBR : TernaryRRFe<"cxlgbr", 0xB3A2, FP128, GR64>;
def : Pat<(f32 (uint_to_fp GR32:$src)), (CELFBR 0, GR32:$src, 0)>;
def : Pat<(f64 (uint_to_fp GR32:$src)), (CDLFBR 0, GR32:$src, 0)>;
@@ -211,13 +223,13 @@ let Predicates = [FeatureFPExtension] in {
// Convert a floating-point register value to a signed integer value,
// with the second operand (modifier M3) specifying the rounding mode.
let Defs = [CC] in {
- def CFEBR : UnaryRRF<"cfeb", 0xB398, GR32, FP32>;
- def CFDBR : UnaryRRF<"cfdb", 0xB399, GR32, FP64>;
- def CFXBR : UnaryRRF<"cfxb", 0xB39A, GR32, FP128>;
+ def CFEBR : BinaryRRFe<"cfebr", 0xB398, GR32, FP32>;
+ def CFDBR : BinaryRRFe<"cfdbr", 0xB399, GR32, FP64>;
+ def CFXBR : BinaryRRFe<"cfxbr", 0xB39A, GR32, FP128>;
- def CGEBR : UnaryRRF<"cgeb", 0xB3A8, GR64, FP32>;
- def CGDBR : UnaryRRF<"cgdb", 0xB3A9, GR64, FP64>;
- def CGXBR : UnaryRRF<"cgxb", 0xB3AA, GR64, FP128>;
+ def CGEBR : BinaryRRFe<"cgebr", 0xB3A8, GR64, FP32>;
+ def CGDBR : BinaryRRFe<"cgdbr", 0xB3A9, GR64, FP64>;
+ def CGXBR : BinaryRRFe<"cgxbr", 0xB3AA, GR64, FP128>;
}
// fp_to_sint always rounds towards zero, which is modifier value 5.
@@ -229,16 +241,28 @@ def : Pat<(i64 (fp_to_sint FP32:$src)), (CGEBR 5, FP32:$src)>;
def : Pat<(i64 (fp_to_sint FP64:$src)), (CGDBR 5, FP64:$src)>;
def : Pat<(i64 (fp_to_sint FP128:$src)), (CGXBR 5, FP128:$src)>;
+// The FP extension feature provides versions of the above that allow
+// also specifying the inexact-exception suppression flag.
+let Predicates = [FeatureFPExtension], Defs = [CC] in {
+ def CFEBRA : TernaryRRFe<"cfebra", 0xB398, GR32, FP32>;
+ def CFDBRA : TernaryRRFe<"cfdbra", 0xB399, GR32, FP64>;
+ def CFXBRA : TernaryRRFe<"cfxbra", 0xB39A, GR32, FP128>;
+
+ def CGEBRA : TernaryRRFe<"cgebra", 0xB3A8, GR64, FP32>;
+ def CGDBRA : TernaryRRFe<"cgdbra", 0xB3A9, GR64, FP64>;
+ def CGXBRA : TernaryRRFe<"cgxbra", 0xB3AA, GR64, FP128>;
+}
+
// Convert a floating-point register value to an unsigned integer value.
let Predicates = [FeatureFPExtension] in {
let Defs = [CC] in {
- def CLFEBR : UnaryRRF4<"clfebr", 0xB39C, GR32, FP32>;
- def CLFDBR : UnaryRRF4<"clfdbr", 0xB39D, GR32, FP64>;
- def CLFXBR : UnaryRRF4<"clfxbr", 0xB39E, GR32, FP128>;
+ def CLFEBR : TernaryRRFe<"clfebr", 0xB39C, GR32, FP32>;
+ def CLFDBR : TernaryRRFe<"clfdbr", 0xB39D, GR32, FP64>;
+ def CLFXBR : TernaryRRFe<"clfxbr", 0xB39E, GR32, FP128>;
- def CLGEBR : UnaryRRF4<"clgebr", 0xB3AC, GR64, FP32>;
- def CLGDBR : UnaryRRF4<"clgdbr", 0xB3AD, GR64, FP64>;
- def CLGXBR : UnaryRRF4<"clgxbr", 0xB3AE, GR64, FP128>;
+ def CLGEBR : TernaryRRFe<"clgebr", 0xB3AC, GR64, FP32>;
+ def CLGDBR : TernaryRRFe<"clgdbr", 0xB3AD, GR64, FP64>;
+ def CLGXBR : TernaryRRFe<"clgxbr", 0xB3AE, GR64, FP128>;
}
def : Pat<(i32 (fp_to_uint FP32:$src)), (CLFEBR 5, FP32:$src, 0)>;
@@ -265,50 +289,50 @@ let Predicates = [FeatureFPExtension] in {
// Negation (Load Complement).
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
- def LCEBR : UnaryRRE<"lceb", 0xB303, null_frag, FP32, FP32>;
- def LCDBR : UnaryRRE<"lcdb", 0xB313, null_frag, FP64, FP64>;
- def LCXBR : UnaryRRE<"lcxb", 0xB343, fneg, FP128, FP128>;
+ def LCEBR : UnaryRRE<"lcebr", 0xB303, null_frag, FP32, FP32>;
+ def LCDBR : UnaryRRE<"lcdbr", 0xB313, null_frag, FP64, FP64>;
+ def LCXBR : UnaryRRE<"lcxbr", 0xB343, fneg, FP128, FP128>;
}
// Generic form, which does not set CC.
-def LCDFR : UnaryRRE<"lcdf", 0xB373, fneg, FP64, FP64>;
+def LCDFR : UnaryRRE<"lcdfr", 0xB373, fneg, FP64, FP64>;
let isCodeGenOnly = 1 in
- def LCDFR_32 : UnaryRRE<"lcdf", 0xB373, fneg, FP32, FP32>;
+ def LCDFR_32 : UnaryRRE<"lcdfr", 0xB373, fneg, FP32, FP32>;
// Absolute value (Load Positive).
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
- def LPEBR : UnaryRRE<"lpeb", 0xB300, null_frag, FP32, FP32>;
- def LPDBR : UnaryRRE<"lpdb", 0xB310, null_frag, FP64, FP64>;
- def LPXBR : UnaryRRE<"lpxb", 0xB340, fabs, FP128, FP128>;
+ def LPEBR : UnaryRRE<"lpebr", 0xB300, null_frag, FP32, FP32>;
+ def LPDBR : UnaryRRE<"lpdbr", 0xB310, null_frag, FP64, FP64>;
+ def LPXBR : UnaryRRE<"lpxbr", 0xB340, fabs, FP128, FP128>;
}
// Generic form, which does not set CC.
-def LPDFR : UnaryRRE<"lpdf", 0xB370, fabs, FP64, FP64>;
+def LPDFR : UnaryRRE<"lpdfr", 0xB370, fabs, FP64, FP64>;
let isCodeGenOnly = 1 in
- def LPDFR_32 : UnaryRRE<"lpdf", 0xB370, fabs, FP32, FP32>;
+ def LPDFR_32 : UnaryRRE<"lpdfr", 0xB370, fabs, FP32, FP32>;
// Negative absolute value (Load Negative).
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
- def LNEBR : UnaryRRE<"lneb", 0xB301, null_frag, FP32, FP32>;
- def LNDBR : UnaryRRE<"lndb", 0xB311, null_frag, FP64, FP64>;
- def LNXBR : UnaryRRE<"lnxb", 0xB341, fnabs, FP128, FP128>;
+ def LNEBR : UnaryRRE<"lnebr", 0xB301, null_frag, FP32, FP32>;
+ def LNDBR : UnaryRRE<"lndbr", 0xB311, null_frag, FP64, FP64>;
+ def LNXBR : UnaryRRE<"lnxbr", 0xB341, fnabs, FP128, FP128>;
}
// Generic form, which does not set CC.
-def LNDFR : UnaryRRE<"lndf", 0xB371, fnabs, FP64, FP64>;
+def LNDFR : UnaryRRE<"lndfr", 0xB371, fnabs, FP64, FP64>;
let isCodeGenOnly = 1 in
- def LNDFR_32 : UnaryRRE<"lndf", 0xB371, fnabs, FP32, FP32>;
+ def LNDFR_32 : UnaryRRE<"lndfr", 0xB371, fnabs, FP32, FP32>;
// Square root.
-def SQEBR : UnaryRRE<"sqeb", 0xB314, fsqrt, FP32, FP32>;
-def SQDBR : UnaryRRE<"sqdb", 0xB315, fsqrt, FP64, FP64>;
-def SQXBR : UnaryRRE<"sqxb", 0xB316, fsqrt, FP128, FP128>;
+def SQEBR : UnaryRRE<"sqebr", 0xB314, fsqrt, FP32, FP32>;
+def SQDBR : UnaryRRE<"sqdbr", 0xB315, fsqrt, FP64, FP64>;
+def SQXBR : UnaryRRE<"sqxbr", 0xB316, fsqrt, FP128, FP128>;
def SQEB : UnaryRXE<"sqeb", 0xED14, loadu<fsqrt>, FP32, 4>;
def SQDB : UnaryRXE<"sqdb", 0xED15, loadu<fsqrt>, FP64, 8>;
// Round to an integer, with the second operand (modifier M3) specifying
// the rounding mode. These forms always check for inexact conditions.
-def FIEBR : UnaryRRF<"fieb", 0xB357, FP32, FP32>;
-def FIDBR : UnaryRRF<"fidb", 0xB35F, FP64, FP64>;
-def FIXBR : UnaryRRF<"fixb", 0xB347, FP128, FP128>;
+def FIEBR : BinaryRRFe<"fiebr", 0xB357, FP32, FP32>;
+def FIDBR : BinaryRRFe<"fidbr", 0xB35F, FP64, FP64>;
+def FIXBR : BinaryRRFe<"fixbr", 0xB347, FP128, FP128>;
// frint rounds according to the current mode (modifier 0) and detects
// inexact conditions.
@@ -319,9 +343,9 @@ def : Pat<(frint FP128:$src), (FIXBR 0, FP128:$src)>;
let Predicates = [FeatureFPExtension] in {
// Extended forms of the FIxBR instructions. M4 can be set to 4
// to suppress detection of inexact conditions.
- def FIEBRA : UnaryRRF4<"fiebra", 0xB357, FP32, FP32>;
- def FIDBRA : UnaryRRF4<"fidbra", 0xB35F, FP64, FP64>;
- def FIXBRA : UnaryRRF4<"fixbra", 0xB347, FP128, FP128>;
+ def FIEBRA : TernaryRRFe<"fiebra", 0xB357, FP32, FP32>;
+ def FIDBRA : TernaryRRFe<"fidbra", 0xB35F, FP64, FP64>;
+ def FIXBRA : TernaryRRFe<"fixbra", 0xB347, FP128, FP128>;
// fnearbyint is like frint but does not detect inexact conditions.
def : Pat<(fnearbyint FP32:$src), (FIEBRA 0, FP32:$src, 4)>;
@@ -347,9 +371,9 @@ let Predicates = [FeatureFPExtension] in {
// Same idea for round, where mode 1 is round towards nearest with
// ties away from zero.
- def : Pat<(frnd FP32:$src), (FIEBRA 1, FP32:$src, 4)>;
- def : Pat<(frnd FP64:$src), (FIDBRA 1, FP64:$src, 4)>;
- def : Pat<(frnd FP128:$src), (FIXBRA 1, FP128:$src, 4)>;
+ def : Pat<(fround FP32:$src), (FIEBRA 1, FP32:$src, 4)>;
+ def : Pat<(fround FP64:$src), (FIDBRA 1, FP64:$src, 4)>;
+ def : Pat<(fround FP128:$src), (FIXBRA 1, FP128:$src, 4)>;
}
//===----------------------------------------------------------------------===//
@@ -359,9 +383,9 @@ let Predicates = [FeatureFPExtension] in {
// Addition.
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
let isCommutable = 1 in {
- def AEBR : BinaryRRE<"aeb", 0xB30A, fadd, FP32, FP32>;
- def ADBR : BinaryRRE<"adb", 0xB31A, fadd, FP64, FP64>;
- def AXBR : BinaryRRE<"axb", 0xB34A, fadd, FP128, FP128>;
+ def AEBR : BinaryRRE<"aebr", 0xB30A, fadd, FP32, FP32>;
+ def ADBR : BinaryRRE<"adbr", 0xB31A, fadd, FP64, FP64>;
+ def AXBR : BinaryRRE<"axbr", 0xB34A, fadd, FP128, FP128>;
}
def AEB : BinaryRXE<"aeb", 0xED0A, fadd, FP32, load, 4>;
def ADB : BinaryRXE<"adb", 0xED1A, fadd, FP64, load, 8>;
@@ -369,9 +393,9 @@ let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
// Subtraction.
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
- def SEBR : BinaryRRE<"seb", 0xB30B, fsub, FP32, FP32>;
- def SDBR : BinaryRRE<"sdb", 0xB31B, fsub, FP64, FP64>;
- def SXBR : BinaryRRE<"sxb", 0xB34B, fsub, FP128, FP128>;
+ def SEBR : BinaryRRE<"sebr", 0xB30B, fsub, FP32, FP32>;
+ def SDBR : BinaryRRE<"sdbr", 0xB31B, fsub, FP64, FP64>;
+ def SXBR : BinaryRRE<"sxbr", 0xB34B, fsub, FP128, FP128>;
def SEB : BinaryRXE<"seb", 0xED0B, fsub, FP32, load, 4>;
def SDB : BinaryRXE<"sdb", 0xED1B, fsub, FP64, load, 8>;
@@ -379,57 +403,57 @@ let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in {
// Multiplication.
let isCommutable = 1 in {
- def MEEBR : BinaryRRE<"meeb", 0xB317, fmul, FP32, FP32>;
- def MDBR : BinaryRRE<"mdb", 0xB31C, fmul, FP64, FP64>;
- def MXBR : BinaryRRE<"mxb", 0xB34C, fmul, FP128, FP128>;
+ def MEEBR : BinaryRRE<"meebr", 0xB317, fmul, FP32, FP32>;
+ def MDBR : BinaryRRE<"mdbr", 0xB31C, fmul, FP64, FP64>;
+ def MXBR : BinaryRRE<"mxbr", 0xB34C, fmul, FP128, FP128>;
}
def MEEB : BinaryRXE<"meeb", 0xED17, fmul, FP32, load, 4>;
def MDB : BinaryRXE<"mdb", 0xED1C, fmul, FP64, load, 8>;
// f64 multiplication of two FP32 registers.
-def MDEBR : BinaryRRE<"mdeb", 0xB30C, null_frag, FP64, FP32>;
-def : Pat<(fmul (f64 (fextend FP32:$src1)), (f64 (fextend FP32:$src2))),
+def MDEBR : BinaryRRE<"mdebr", 0xB30C, null_frag, FP64, FP32>;
+def : Pat<(fmul (f64 (fpextend FP32:$src1)), (f64 (fpextend FP32:$src2))),
(MDEBR (INSERT_SUBREG (f64 (IMPLICIT_DEF)),
FP32:$src1, subreg_r32), FP32:$src2)>;
// f64 multiplication of an FP32 register and an f32 memory.
def MDEB : BinaryRXE<"mdeb", 0xED0C, null_frag, FP64, load, 4>;
-def : Pat<(fmul (f64 (fextend FP32:$src1)),
+def : Pat<(fmul (f64 (fpextend FP32:$src1)),
(f64 (extloadf32 bdxaddr12only:$addr))),
(MDEB (INSERT_SUBREG (f64 (IMPLICIT_DEF)), FP32:$src1, subreg_r32),
bdxaddr12only:$addr)>;
// f128 multiplication of two FP64 registers.
-def MXDBR : BinaryRRE<"mxdb", 0xB307, null_frag, FP128, FP64>;
-def : Pat<(fmul (f128 (fextend FP64:$src1)), (f128 (fextend FP64:$src2))),
+def MXDBR : BinaryRRE<"mxdbr", 0xB307, null_frag, FP128, FP64>;
+def : Pat<(fmul (f128 (fpextend FP64:$src1)), (f128 (fpextend FP64:$src2))),
(MXDBR (INSERT_SUBREG (f128 (IMPLICIT_DEF)),
FP64:$src1, subreg_h64), FP64:$src2)>;
// f128 multiplication of an FP64 register and an f64 memory.
def MXDB : BinaryRXE<"mxdb", 0xED07, null_frag, FP128, load, 8>;
-def : Pat<(fmul (f128 (fextend FP64:$src1)),
+def : Pat<(fmul (f128 (fpextend FP64:$src1)),
(f128 (extloadf64 bdxaddr12only:$addr))),
(MXDB (INSERT_SUBREG (f128 (IMPLICIT_DEF)), FP64:$src1, subreg_h64),
bdxaddr12only:$addr)>;
// Fused multiply-add.
-def MAEBR : TernaryRRD<"maeb", 0xB30E, z_fma, FP32>;
-def MADBR : TernaryRRD<"madb", 0xB31E, z_fma, FP64>;
+def MAEBR : TernaryRRD<"maebr", 0xB30E, z_fma, FP32>;
+def MADBR : TernaryRRD<"madbr", 0xB31E, z_fma, FP64>;
def MAEB : TernaryRXF<"maeb", 0xED0E, z_fma, FP32, load, 4>;
def MADB : TernaryRXF<"madb", 0xED1E, z_fma, FP64, load, 8>;
// Fused multiply-subtract.
-def MSEBR : TernaryRRD<"mseb", 0xB30F, z_fms, FP32>;
-def MSDBR : TernaryRRD<"msdb", 0xB31F, z_fms, FP64>;
+def MSEBR : TernaryRRD<"msebr", 0xB30F, z_fms, FP32>;
+def MSDBR : TernaryRRD<"msdbr", 0xB31F, z_fms, FP64>;
def MSEB : TernaryRXF<"mseb", 0xED0F, z_fms, FP32, load, 4>;
def MSDB : TernaryRXF<"msdb", 0xED1F, z_fms, FP64, load, 8>;
// Division.
-def DEBR : BinaryRRE<"deb", 0xB30D, fdiv, FP32, FP32>;
-def DDBR : BinaryRRE<"ddb", 0xB31D, fdiv, FP64, FP64>;
-def DXBR : BinaryRRE<"dxb", 0xB34D, fdiv, FP128, FP128>;
+def DEBR : BinaryRRE<"debr", 0xB30D, fdiv, FP32, FP32>;
+def DDBR : BinaryRRE<"ddbr", 0xB31D, fdiv, FP64, FP64>;
+def DXBR : BinaryRRE<"dxbr", 0xB34D, fdiv, FP128, FP128>;
def DEB : BinaryRXE<"deb", 0xED0D, fdiv, FP32, load, 4>;
def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load, 8>;
@@ -439,9 +463,9 @@ def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load, 8>;
//===----------------------------------------------------------------------===//
let Defs = [CC], CCValues = 0xF in {
- def CEBR : CompareRRE<"ceb", 0xB309, z_fcmp, FP32, FP32>;
- def CDBR : CompareRRE<"cdb", 0xB319, z_fcmp, FP64, FP64>;
- def CXBR : CompareRRE<"cxb", 0xB349, z_fcmp, FP128, FP128>;
+ def CEBR : CompareRRE<"cebr", 0xB309, z_fcmp, FP32, FP32>;
+ def CDBR : CompareRRE<"cdbr", 0xB319, z_fcmp, FP64, FP64>;
+ def CXBR : CompareRRE<"cxbr", 0xB349, z_fcmp, FP128, FP128>;
def CEB : CompareRXE<"ceb", 0xED09, z_fcmp, FP32, load, 4>;
def CDB : CompareRXE<"cdb", 0xED19, z_fcmp, FP64, load, 8>;
@@ -455,6 +479,26 @@ let Defs = [CC], CCValues = 0xC in {
}
//===----------------------------------------------------------------------===//
+// Floating-point control register instructions
+//===----------------------------------------------------------------------===//
+
+let hasSideEffects = 1 in {
+ def EFPC : InherentRRE<"efpc", 0xB38C, GR32, int_s390_efpc>;
+ def STFPC : StoreInherentS<"stfpc", 0xB29C, storei<int_s390_efpc>, 4>;
+
+ def SFPC : SideEffectUnaryRRE<"sfpc", 0xB384, GR32, int_s390_sfpc>;
+ def LFPC : SideEffectUnaryS<"lfpc", 0xB29D, loadu<int_s390_sfpc>, 4>;
+
+ def SFASR : SideEffectUnaryRRE<"sfasr", 0xB385, GR32, null_frag>;
+ def LFAS : SideEffectUnaryS<"lfas", 0xB2BD, null_frag, 4>;
+
+ def SRNMB : SideEffectAddressS<"srnmb", 0xB2B8, null_frag, shift12only>,
+ Requires<[FeatureFPExtension]>;
+ def SRNM : SideEffectAddressS<"srnm", 0xB299, null_frag, shift12only>;
+ def SRNMT : SideEffectAddressS<"srnmt", 0xB2B9, null_frag, shift12only>;
+}
+
+//===----------------------------------------------------------------------===//
// Peepholes
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
index 973894d..c727f48 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
@@ -29,7 +29,7 @@ class InstSystemZ<int size, dag outs, dag ins, string asmstr,
string DispSize = "none";
// Many register-based <INSN>R instructions have a memory-based <INSN>
- // counterpart. OpKey uniquely identifies <INSN>, while OpType is
+ // counterpart. OpKey uniquely identifies <INSN>R, while OpType is
// "reg" for <INSN>R and "mem" for <INSN>.
string OpKey = "";
string OpType = "none";
@@ -158,6 +158,14 @@ def getThreeOperandOpcode : InstrMapping {
//
//===----------------------------------------------------------------------===//
+class InstE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<2, outs, ins, asmstr, pattern> {
+ field bits<16> Inst;
+ field bits<16> SoftFail = 0;
+
+ let Inst = op;
+}
+
class InstI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<2, outs, ins, asmstr, pattern> {
field bits<16> Inst;
@@ -169,7 +177,36 @@ class InstI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{7-0} = I1;
}
-class InstRI<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstIE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> I1;
+ bits<4> I2;
+
+ let Inst{31-16} = op;
+ let Inst{15-8} = 0;
+ let Inst{7-4} = I1;
+ let Inst{3-0} = I2;
+}
+
+class InstMII<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> M1;
+ bits<12> RI2;
+ bits<24> RI3;
+
+ let Inst{47-40} = op;
+ let Inst{39-36} = M1;
+ let Inst{35-24} = RI2;
+ let Inst{23-0} = RI3;
+}
+
+class InstRIa<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<4, outs, ins, asmstr, pattern> {
field bits<32> Inst;
field bits<32> SoftFail = 0;
@@ -183,6 +220,34 @@ class InstRI<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{15-0} = I2;
}
+class InstRIb<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> R1;
+ bits<16> RI2;
+
+ let Inst{31-24} = op{11-4};
+ let Inst{23-20} = R1;
+ let Inst{19-16} = op{3-0};
+ let Inst{15-0} = RI2;
+}
+
+class InstRIc<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> M1;
+ bits<16> RI2;
+
+ let Inst{31-24} = op{11-4};
+ let Inst{23-20} = M1;
+ let Inst{19-16} = op{3-0};
+ let Inst{15-0} = RI2;
+}
+
class InstRIEa<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
@@ -255,6 +320,23 @@ class InstRIEd<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{7-0} = op{7-0};
}
+class InstRIEe<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> R3;
+ bits<16> RI2;
+
+ let Inst{47-40} = op{15-8};
+ let Inst{39-36} = R1;
+ let Inst{35-32} = R3;
+ let Inst{31-16} = RI2;
+ let Inst{15-8} = 0;
+ let Inst{7-0} = op{7-0};
+}
+
class InstRIEf<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
@@ -275,7 +357,24 @@ class InstRIEf<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{7-0} = op{7-0};
}
-class InstRIL<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstRIEg<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> M3;
+ bits<16> I2;
+
+ let Inst{47-40} = op{15-8};
+ let Inst{39-36} = R1;
+ let Inst{35-32} = M3;
+ let Inst{31-16} = I2;
+ let Inst{15-8} = 0;
+ let Inst{7-0} = op{7-0};
+}
+
+class InstRILa<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
field bits<48> SoftFail = 0;
@@ -289,6 +388,34 @@ class InstRIL<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{31-0} = I2;
}
+class InstRILb<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> R1;
+ bits<32> RI2;
+
+ let Inst{47-40} = op{11-4};
+ let Inst{39-36} = R1;
+ let Inst{35-32} = op{3-0};
+ let Inst{31-0} = RI2;
+}
+
+class InstRILc<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> M1;
+ bits<32> RI2;
+
+ let Inst{47-40} = op{11-4};
+ let Inst{39-36} = M1;
+ let Inst{35-32} = op{3-0};
+ let Inst{31-0} = RI2;
+}
+
class InstRIS<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
@@ -350,7 +477,7 @@ class InstRRE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{3-0} = R2;
}
-class InstRRF<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstRRFa<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<4, outs, ins, asmstr, pattern> {
field bits<32> Inst;
field bits<32> SoftFail = 0;
@@ -358,11 +485,28 @@ class InstRRF<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
bits<4> R1;
bits<4> R2;
bits<4> R3;
- bits<4> R4;
+ bits<4> M4;
let Inst{31-16} = op;
let Inst{15-12} = R3;
- let Inst{11-8} = R4;
+ let Inst{11-8} = M4;
+ let Inst{7-4} = R1;
+ let Inst{3-0} = R2;
+}
+
+class InstRRFb<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> R2;
+ bits<4> R3;
+ bits<4> M4;
+
+ let Inst{31-16} = op;
+ let Inst{15-12} = R3;
+ let Inst{11-8} = M4;
let Inst{7-4} = R1;
let Inst{3-0} = R2;
}
@@ -383,6 +527,23 @@ class InstRRFc<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{3-0} = R2;
}
+class InstRRFe<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> R2;
+ bits<4> M3;
+ bits<4> M4;
+
+ let Inst{31-16} = op;
+ let Inst{15-12} = M3;
+ let Inst{11-8} = M4;
+ let Inst{7-4} = R1;
+ let Inst{3-0} = R2;
+}
+
class InstRRS<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
@@ -402,7 +563,7 @@ class InstRRS<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{7-0} = op{7-0};
}
-class InstRX<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstRXa<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<4, outs, ins, asmstr, pattern> {
field bits<32> Inst;
field bits<32> SoftFail = 0;
@@ -417,6 +578,21 @@ class InstRX<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let HasIndex = 1;
}
+class InstRXb<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> M1;
+ bits<20> XBD2;
+
+ let Inst{31-24} = op;
+ let Inst{23-20} = M1;
+ let Inst{19-0} = XBD2;
+
+ let HasIndex = 1;
+}
+
class InstRXE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
@@ -455,7 +631,7 @@ class InstRXF<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let HasIndex = 1;
}
-class InstRXY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstRXYa<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
field bits<48> SoftFail = 0;
@@ -472,7 +648,24 @@ class InstRXY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let HasIndex = 1;
}
-class InstRS<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstRXYb<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> M1;
+ bits<28> XBD2;
+
+ let Inst{47-40} = op{15-8};
+ let Inst{39-36} = M1;
+ let Inst{35-8} = XBD2;
+ let Inst{7-0} = op{7-0};
+
+ let Has20BitOffset = 1;
+ let HasIndex = 1;
+}
+
+class InstRSa<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<4, outs, ins, asmstr, pattern> {
field bits<32> Inst;
field bits<32> SoftFail = 0;
@@ -487,7 +680,37 @@ class InstRS<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{15-0} = BD2;
}
-class InstRSY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstRSb<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> M3;
+ bits<16> BD2;
+
+ let Inst{31-24} = op;
+ let Inst{23-20} = R1;
+ let Inst{19-16} = M3;
+ let Inst{15-0} = BD2;
+}
+
+class InstRSI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<4, outs, ins, asmstr, pattern> {
+ field bits<32> Inst;
+ field bits<32> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> R3;
+ bits<16> RI2;
+
+ let Inst{31-24} = op;
+ let Inst{23-20} = R1;
+ let Inst{19-16} = R3;
+ let Inst{15-0} = RI2;
+}
+
+class InstRSYa<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
field bits<48> SoftFail = 0;
@@ -505,6 +728,24 @@ class InstRSY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Has20BitOffset = 1;
}
+class InstRSYb<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> R1;
+ bits<4> M3;
+ bits<24> BD2;
+
+ let Inst{47-40} = op{15-8};
+ let Inst{39-36} = R1;
+ let Inst{35-32} = M3;
+ let Inst{31-8} = BD2;
+ let Inst{7-0} = op{7-0};
+
+ let Has20BitOffset = 1;
+}
+
class InstSI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<4, outs, ins, asmstr, pattern> {
field bits<32> Inst;
@@ -547,7 +788,23 @@ class InstSIY<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Has20BitOffset = 1;
}
-class InstSS<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+class InstSMI<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> M1;
+ bits<16> RI2;
+ bits<16> BD3;
+
+ let Inst{47-40} = op;
+ let Inst{39-36} = M1;
+ let Inst{35-32} = 0;
+ let Inst{31-16} = BD3;
+ let Inst{15-0} = RI2;
+}
+
+class InstSSa<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<6, outs, ins, asmstr, pattern> {
field bits<48> Inst;
field bits<48> SoftFail = 0;
@@ -560,6 +817,68 @@ class InstSS<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let Inst{15-0} = BD2;
}
+class InstSSd<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<20> RBD1;
+ bits<16> BD2;
+ bits<4> R3;
+
+ let Inst{47-40} = op;
+ let Inst{39-36} = RBD1{19-16};
+ let Inst{35-32} = R3;
+ let Inst{31-16} = RBD1{15-0};
+ let Inst{15-0} = BD2;
+}
+
+class InstSSe<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<4> R1;
+ bits<16> BD2;
+ bits<4> R3;
+ bits<16> BD4;
+
+ let Inst{47-40} = op;
+ let Inst{39-36} = R1;
+ let Inst{35-32} = R3;
+ let Inst{31-16} = BD2;
+ let Inst{15-0} = BD4;
+}
+
+class InstSSE<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<16> BD1;
+ bits<16> BD2;
+
+ let Inst{47-32} = op;
+ let Inst{31-16} = BD1;
+ let Inst{15-0} = BD2;
+}
+
+class InstSSF<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSystemZ<6, outs, ins, asmstr, pattern> {
+ field bits<48> Inst;
+ field bits<48> SoftFail = 0;
+
+ bits<16> BD1;
+ bits<16> BD2;
+ bits<4> R3;
+
+ let Inst{47-40} = op{11-4};
+ let Inst{39-36} = R3;
+ let Inst{35-32} = op{3-0};
+ let Inst{31-16} = BD1;
+ let Inst{15-0} = BD2;
+}
+
class InstS<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSystemZ<4, outs, ins, asmstr, pattern> {
field bits<32> Inst;
@@ -948,6 +1267,294 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
}
//===----------------------------------------------------------------------===//
+// Instruction classes for .insn directives
+//===----------------------------------------------------------------------===//
+
+class DirectiveInsnE<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstE<0, outs, ins, asmstr, pattern> {
+ bits<16> enc;
+
+ let Inst = enc;
+}
+
+class DirectiveInsnRI<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRIa<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-24} = enc{31-24};
+ let Inst{19-16} = enc{19-16};
+}
+
+class DirectiveInsnRIE<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRIEd<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRIL<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRILa<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+ string type;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{35-32} = enc{35-32};
+}
+
+class DirectiveInsnRIS<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRIS<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRR<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRR<0, outs, ins, asmstr, pattern> {
+ bits<16> enc;
+
+ let Inst{15-8} = enc{15-8};
+}
+
+class DirectiveInsnRRE<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRRE<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-16} = enc{31-16};
+}
+
+class DirectiveInsnRRF<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRRFa<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-16} = enc{31-16};
+}
+
+class DirectiveInsnRRS<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRRS<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRS<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRSa<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-24} = enc{31-24};
+}
+
+// RSE is like RSY except with a 12 bit displacement (instead of 20).
+class DirectiveInsnRSE<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRSYa<6, outs, ins, asmstr, pattern> {
+ bits <48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{31-16} = BD2{15-0};
+ let Inst{15-8} = 0;
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRSI<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRSI<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-24} = enc{31-24};
+}
+
+class DirectiveInsnRSY<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRSYa<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRX<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRXa<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-24} = enc{31-24};
+}
+
+class DirectiveInsnRXE<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRXE<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let M3 = 0;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRXF<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRXF<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnRXY<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstRXYa<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnS<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstS<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-16} = enc{31-16};
+}
+
+class DirectiveInsnSI<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSI<0, outs, ins, asmstr, pattern> {
+ bits<32> enc;
+
+ let Inst{31-24} = enc{31-24};
+}
+
+class DirectiveInsnSIY<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSIY<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{7-0} = enc{7-0};
+}
+
+class DirectiveInsnSIL<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSIL<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-32} = enc{47-32};
+}
+
+class DirectiveInsnSS<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSSd<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+}
+
+class DirectiveInsnSSE<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSSE<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-32} = enc{47-32};
+}
+
+class DirectiveInsnSSF<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSSF<0, outs, ins, asmstr, pattern> {
+ bits<48> enc;
+
+ let Inst{47-40} = enc{47-40};
+ let Inst{35-32} = enc{35-32};
+}
+
+//===----------------------------------------------------------------------===//
+// Variants of instructions with condition mask
+//===----------------------------------------------------------------------===//
+//
+// For instructions using a condition mask (e.g. conditional branches,
+// compare-and-branch instructions, or conditional move instructions),
+// we generally need to create multiple instruction patterns:
+//
+// - One used for code generation, which encodes the condition mask as an
+// MI operand, but writes out an extended mnemonic for better readability.
+// - One pattern for the base form of the instruction with an explicit
+// condition mask (encoded as a plain integer MI operand).
+// - Specific patterns for each extended mnemonic, where the condition mask
+// is implied by the pattern name and not otherwise encoded at all.
+//
+// We need the latter primarily for the assembler and disassembler, since the
+// assembler parser is not able to decode part of an instruction mnemonic
+// into an operand. Thus we provide separate patterns for each mnemonic.
+//
+// Note that in some cases there are two different mnemonics for the same
+// condition mask. In this case we cannot have both instructions available
+// to the disassembler at the same time since the encodings are not distinct.
+// Therefore the alternate forms are marked isAsmParserOnly.
+//
+// We don't make one of the two names an alias of the other because
+// we need the custom parsing routines to select the correct register class.
+//
+// This section provides helpers for generating the specific forms.
+//
+//===----------------------------------------------------------------------===//
+
+// A class to describe a variant of an instruction with condition mask.
+class CondVariant<bits<4> ccmaskin, string suffixin, bit alternatein> {
+ // The fixed condition mask to use.
+ bits<4> ccmask = ccmaskin;
+
+ // The suffix to use for the extended assembler mnemonic.
+ string suffix = suffixin;
+
+ // Whether this is an alternate that needs to be marked isAsmParserOnly.
+ bit alternate = alternatein;
+}
+
+// Condition mask 15 means "always true", which is used to define
+// unconditional branches as a variant of conditional branches.
+def CondAlways : CondVariant<15, "", 0>;
+
+// Condition masks for general instructions that can set all 4 bits.
+def CondVariantO : CondVariant<1, "o", 0>;
+def CondVariantH : CondVariant<2, "h", 0>;
+def CondVariantP : CondVariant<2, "p", 1>;
+def CondVariantNLE : CondVariant<3, "nle", 0>;
+def CondVariantL : CondVariant<4, "l", 0>;
+def CondVariantM : CondVariant<4, "m", 1>;
+def CondVariantNHE : CondVariant<5, "nhe", 0>;
+def CondVariantLH : CondVariant<6, "lh", 0>;
+def CondVariantNE : CondVariant<7, "ne", 0>;
+def CondVariantNZ : CondVariant<7, "nz", 1>;
+def CondVariantE : CondVariant<8, "e", 0>;
+def CondVariantZ : CondVariant<8, "z", 1>;
+def CondVariantNLH : CondVariant<9, "nlh", 0>;
+def CondVariantHE : CondVariant<10, "he", 0>;
+def CondVariantNL : CondVariant<11, "nl", 0>;
+def CondVariantNM : CondVariant<11, "nm", 1>;
+def CondVariantLE : CondVariant<12, "le", 0>;
+def CondVariantNH : CondVariant<13, "nh", 0>;
+def CondVariantNP : CondVariant<13, "np", 1>;
+def CondVariantNO : CondVariant<14, "no", 0>;
+
+// A helper class to look up one of the above by name.
+class CV<string name>
+ : CondVariant<!cast<CondVariant>("CondVariant"#name).ccmask,
+ !cast<CondVariant>("CondVariant"#name).suffix,
+ !cast<CondVariant>("CondVariant"#name).alternate>;
+
+// Condition masks for integer instructions (e.g. compare-and-branch).
+// This is like the list above, except that condition 3 is not possible
+// and that the low bit of the mask is therefore always 0. This means
+// that each condition has two names. Conditions "o" and "no" are not used.
+def IntCondVariantH : CondVariant<2, "h", 0>;
+def IntCondVariantNLE : CondVariant<2, "nle", 1>;
+def IntCondVariantL : CondVariant<4, "l", 0>;
+def IntCondVariantNHE : CondVariant<4, "nhe", 1>;
+def IntCondVariantLH : CondVariant<6, "lh", 0>;
+def IntCondVariantNE : CondVariant<6, "ne", 1>;
+def IntCondVariantE : CondVariant<8, "e", 0>;
+def IntCondVariantNLH : CondVariant<8, "nlh", 1>;
+def IntCondVariantHE : CondVariant<10, "he", 0>;
+def IntCondVariantNL : CondVariant<10, "nl", 1>;
+def IntCondVariantLE : CondVariant<12, "le", 0>;
+def IntCondVariantNH : CondVariant<12, "nh", 1>;
+
+// A helper class to look up one of the above by name.
+class ICV<string name>
+ : CondVariant<!cast<CondVariant>("IntCondVariant"#name).ccmask,
+ !cast<CondVariant>("IntCondVariant"#name).suffix,
+ !cast<CondVariant>("IntCondVariant"#name).alternate>;
+
+//===----------------------------------------------------------------------===//
// Instruction definitions with semantics
//===----------------------------------------------------------------------===//
//
@@ -960,11 +1567,32 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
// Inherent:
// One register output operand and no input operands.
//
+// StoreInherent:
+// One address operand. The instruction stores to the address.
+//
+// SideEffectInherent:
+// No input or output operands, but causes some side effect.
+//
+// Branch:
+// One branch target. The instruction branches to the target.
+//
+// Call:
+// One output operand and one branch target. The instruction stores
+// the return address to the output operand and branches to the target.
+//
+// CmpBranch:
+// Two input operands and one optional branch target. The instruction
+// compares the two input operands and branches or traps on the result.
+//
// BranchUnary:
-// One register output operand, one register input operand and
-// one branch displacement. The instructions stores a modified
-// form of the source register in the destination register and
-// branches on the result.
+// One register output operand, one register input operand and one branch
+// target. The instructions stores a modified form of the source register
+// in the destination register and branches on the result.
+//
+// BranchBinary:
+// One register output operand, two register input operands and one branch
+// target. The instructions stores a modified form of one of the source
+// registers in the destination register and branches on the result.
//
// LoadMultiple:
// One address input operand and two explicit output operands.
@@ -984,6 +1612,12 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
// doesn't write more than the number of bytes specified by the
// length operand.
//
+// LoadAddress:
+// One register output operand and one address operand.
+//
+// SideEffectAddress:
+// One address operand. No output operands, but causes some side effect.
+//
// Unary:
// One register output operand and one input operand.
//
@@ -991,6 +1625,9 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
// One address operand and one other input operand. The instruction
// stores to the address.
//
+// SideEffectUnary:
+// One input operand. No output operands, but causes some side effect.
+//
// Binary:
// One register output operand and two input operands.
//
@@ -998,6 +1635,9 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
// One address operand and two other input operands. The instruction
// stores to the address.
//
+// SideEffectBinary:
+// Two input operands. No output operands, but causes some side effect.
+//
// Compare:
// Two input operands and an implicit CC output operand.
//
@@ -1008,6 +1648,9 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
// Ternary:
// One register output operand and three input operands.
//
+// SideEffectTernary:
+// Three input operands. No output operands, but causes some side effect.
+//
// Quaternary:
// One register output operand and four input operands.
//
@@ -1027,6 +1670,9 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
// One 4-bit immediate operand and one address operand. The immediate
// operand is 1 for a load prefetch and 2 for a store prefetch.
//
+// BranchPreload:
+// One 4-bit immediate operand and two address operands.
+//
// The format determines which input operands are tied to output operands,
// and also determines the shape of any address operand.
//
@@ -1038,10 +1684,10 @@ class InstVRX<bits<16> op, dag outs, dag ins, string asmstr, list<dag> pattern>
//===----------------------------------------------------------------------===//
class InherentRRE<string mnemonic, bits<16> opcode, RegisterOperand cls,
- dag src>
+ SDPatternOperator operator>
: InstRRE<opcode, (outs cls:$R1), (ins),
mnemonic#"\t$R1",
- [(set cls:$R1, src)]> {
+ [(set cls:$R1, (operator))]> {
let R2 = 0;
}
@@ -1051,26 +1697,380 @@ class InherentVRIa<string mnemonic, bits<16> opcode, bits<16> value>
let M3 = 0;
}
+class StoreInherentS<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator, bits<5> bytes>
+ : InstS<opcode, (outs), (ins bdaddr12only:$BD2),
+ mnemonic#"\t$BD2", [(operator bdaddr12only:$BD2)]> {
+ let mayStore = 1;
+ let AccessBytes = bytes;
+}
+
+class SideEffectInherentE<string mnemonic, bits<16>opcode>
+ : InstE<opcode, (outs), (ins), mnemonic, []>;
+
+class SideEffectInherentS<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator>
+ : InstS<opcode, (outs), (ins), mnemonic, [(operator)]> {
+ let BD2 = 0;
+}
+
+// Allow an optional TLS marker symbol to generate TLS call relocations.
+class CallRI<string mnemonic, bits<12> opcode>
+ : InstRIb<opcode, (outs), (ins GR64:$R1, brtarget16tls:$RI2),
+ mnemonic#"\t$R1, $RI2", []>;
+
+// Allow an optional TLS marker symbol to generate TLS call relocations.
+class CallRIL<string mnemonic, bits<12> opcode>
+ : InstRILb<opcode, (outs), (ins GR64:$R1, brtarget32tls:$RI2),
+ mnemonic#"\t$R1, $RI2", []>;
+
+class CallRR<string mnemonic, bits<8> opcode>
+ : InstRR<opcode, (outs), (ins GR64:$R1, ADDR64:$R2),
+ mnemonic#"\t$R1, $R2", []>;
+
+class CallRX<string mnemonic, bits<8> opcode>
+ : InstRXa<opcode, (outs), (ins GR64:$R1, bdxaddr12only:$XBD2),
+ mnemonic#"\t$R1, $XBD2", []>;
+
+class CondBranchRI<string mnemonic, bits<12> opcode,
+ SDPatternOperator operator = null_frag>
+ : InstRIc<opcode, (outs), (ins cond4:$valid, cond4:$M1, brtarget16:$RI2),
+ !subst("#", "${M1}", mnemonic)#"\t$RI2",
+ [(operator cond4:$valid, cond4:$M1, bb:$RI2)]> {
+ let CCMaskFirst = 1;
+}
+
+class AsmCondBranchRI<string mnemonic, bits<12> opcode>
+ : InstRIc<opcode, (outs), (ins imm32zx4:$M1, brtarget16:$RI2),
+ mnemonic#"\t$M1, $RI2", []>;
+
+class FixedCondBranchRI<CondVariant V, string mnemonic, bits<12> opcode,
+ SDPatternOperator operator = null_frag>
+ : InstRIc<opcode, (outs), (ins brtarget16:$RI2),
+ !subst("#", V.suffix, mnemonic)#"\t$RI2", [(operator bb:$RI2)]> {
+ let isAsmParserOnly = V.alternate;
+ let M1 = V.ccmask;
+}
+
+class CondBranchRIL<string mnemonic, bits<12> opcode>
+ : InstRILc<opcode, (outs), (ins cond4:$valid, cond4:$M1, brtarget32:$RI2),
+ !subst("#", "${M1}", mnemonic)#"\t$RI2", []> {
+ let CCMaskFirst = 1;
+}
+
+class AsmCondBranchRIL<string mnemonic, bits<12> opcode>
+ : InstRILc<opcode, (outs), (ins imm32zx4:$M1, brtarget32:$RI2),
+ mnemonic#"\t$M1, $RI2", []>;
+
+class FixedCondBranchRIL<CondVariant V, string mnemonic, bits<12> opcode>
+ : InstRILc<opcode, (outs), (ins brtarget32:$RI2),
+ !subst("#", V.suffix, mnemonic)#"\t$RI2", []> {
+ let isAsmParserOnly = V.alternate;
+ let M1 = V.ccmask;
+}
+
+class CondBranchRR<string mnemonic, bits<8> opcode>
+ : InstRR<opcode, (outs), (ins cond4:$valid, cond4:$R1, GR64:$R2),
+ !subst("#", "${R1}", mnemonic)#"\t$R2", []> {
+ let CCMaskFirst = 1;
+}
+
+class AsmCondBranchRR<string mnemonic, bits<8> opcode>
+ : InstRR<opcode, (outs), (ins imm32zx4:$R1, GR64:$R2),
+ mnemonic#"\t$R1, $R2", []>;
+
+class FixedCondBranchRR<CondVariant V, string mnemonic, bits<8> opcode,
+ SDPatternOperator operator = null_frag>
+ : InstRR<opcode, (outs), (ins ADDR64:$R2),
+ !subst("#", V.suffix, mnemonic)#"\t$R2", [(operator ADDR64:$R2)]> {
+ let isAsmParserOnly = V.alternate;
+ let R1 = V.ccmask;
+}
+
+class CondBranchRX<string mnemonic, bits<8> opcode>
+ : InstRXb<opcode, (outs), (ins cond4:$valid, cond4:$M1, bdxaddr12only:$XBD2),
+ !subst("#", "${M1}", mnemonic)#"\t$XBD2", []> {
+ let CCMaskFirst = 1;
+}
+
+class AsmCondBranchRX<string mnemonic, bits<8> opcode>
+ : InstRXb<opcode, (outs), (ins imm32zx4:$M1, bdxaddr12only:$XBD2),
+ mnemonic#"\t$M1, $XBD2", []>;
+
+class FixedCondBranchRX<CondVariant V, string mnemonic, bits<8> opcode>
+ : InstRXb<opcode, (outs), (ins bdxaddr12only:$XBD2),
+ !subst("#", V.suffix, mnemonic)#"\t$XBD2", []> {
+ let isAsmParserOnly = V.alternate;
+ let M1 = V.ccmask;
+}
+
+class CmpBranchRIEa<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEa<opcode, (outs), (ins cls:$R1, imm:$I2, cond4:$M3),
+ mnemonic#"$M3\t$R1, $I2", []>;
+
+class AsmCmpBranchRIEa<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEa<opcode, (outs), (ins cls:$R1, imm:$I2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $I2, $M3", []>;
+
+class FixedCmpBranchRIEa<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEa<opcode, (outs), (ins cls:$R1, imm:$I2),
+ mnemonic#V.suffix#"\t$R1, $I2", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CmpBranchRIEaPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRIEa<mnemonic, opcode, cls, imm>;
+ def Asm : AsmCmpBranchRIEa<mnemonic, opcode, cls, imm>;
+}
+
+class CmpBranchRIEb<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRIEb<opcode, (outs),
+ (ins cls:$R1, cls:$R2, cond4:$M3, brtarget16:$RI4),
+ mnemonic#"$M3\t$R1, $R2, $RI4", []>;
+
+class AsmCmpBranchRIEb<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRIEb<opcode, (outs),
+ (ins cls:$R1, cls:$R2, imm32zx4:$M3, brtarget16:$RI4),
+ mnemonic#"\t$R1, $R2, $M3, $RI4", []>;
+
+class FixedCmpBranchRIEb<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRIEb<opcode, (outs), (ins cls:$R1, cls:$R2, brtarget16:$RI4),
+ mnemonic#V.suffix#"\t$R1, $R2, $RI4", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CmpBranchRIEbPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRIEb<mnemonic, opcode, cls>;
+ def Asm : AsmCmpBranchRIEb<mnemonic, opcode, cls>;
+}
+
+class CmpBranchRIEc<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEc<opcode, (outs),
+ (ins cls:$R1, imm:$I2, cond4:$M3, brtarget16:$RI4),
+ mnemonic#"$M3\t$R1, $I2, $RI4", []>;
+
+class AsmCmpBranchRIEc<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEc<opcode, (outs),
+ (ins cls:$R1, imm:$I2, imm32zx4:$M3, brtarget16:$RI4),
+ mnemonic#"\t$R1, $I2, $M3, $RI4", []>;
+
+class FixedCmpBranchRIEc<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEc<opcode, (outs), (ins cls:$R1, imm:$I2, brtarget16:$RI4),
+ mnemonic#V.suffix#"\t$R1, $I2, $RI4", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CmpBranchRIEcPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRIEc<mnemonic, opcode, cls, imm>;
+ def Asm : AsmCmpBranchRIEc<mnemonic, opcode, cls, imm>;
+}
+
+class CmpBranchRRFc<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRRFc<opcode, (outs), (ins cls:$R1, cls:$R2, cond4:$M3),
+ mnemonic#"$M3\t$R1, $R2", []>;
+
+class AsmCmpBranchRRFc<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRRFc<opcode, (outs), (ins cls:$R1, cls:$R2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $R2, $M3", []>;
+
+multiclass CmpBranchRRFcPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRRFc<mnemonic, opcode, cls>;
+ def Asm : AsmCmpBranchRRFc<mnemonic, opcode, cls>;
+}
+
+class FixedCmpBranchRRFc<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRRFc<opcode, (outs), (ins cls:$R1, cls:$R2),
+ mnemonic#V.suffix#"\t$R1, $R2", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+class CmpBranchRRS<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRRS<opcode, (outs),
+ (ins cls:$R1, cls:$R2, cond4:$M3, bdaddr12only:$BD4),
+ mnemonic#"$M3\t$R1, $R2, $BD4", []>;
+
+class AsmCmpBranchRRS<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRRS<opcode, (outs),
+ (ins cls:$R1, cls:$R2, imm32zx4:$M3, bdaddr12only:$BD4),
+ mnemonic#"\t$R1, $R2, $M3, $BD4", []>;
+
+class FixedCmpBranchRRS<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRRS<opcode, (outs), (ins cls:$R1, cls:$R2, bdaddr12only:$BD4),
+ mnemonic#V.suffix#"\t$R1, $R2, $BD4", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CmpBranchRRSPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRRS<mnemonic, opcode, cls>;
+ def Asm : AsmCmpBranchRRS<mnemonic, opcode, cls>;
+}
+
+class CmpBranchRIS<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIS<opcode, (outs),
+ (ins cls:$R1, imm:$I2, cond4:$M3, bdaddr12only:$BD4),
+ mnemonic#"$M3\t$R1, $I2, $BD4", []>;
+
+class AsmCmpBranchRIS<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIS<opcode, (outs),
+ (ins cls:$R1, imm:$I2, imm32zx4:$M3, bdaddr12only:$BD4),
+ mnemonic#"\t$R1, $I2, $M3, $BD4", []>;
+
+class FixedCmpBranchRIS<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIS<opcode, (outs), (ins cls:$R1, imm:$I2, bdaddr12only:$BD4),
+ mnemonic#V.suffix#"\t$R1, $I2, $BD4", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CmpBranchRISPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRIS<mnemonic, opcode, cls, imm>;
+ def Asm : AsmCmpBranchRIS<mnemonic, opcode, cls, imm>;
+}
+
+class CmpBranchRSYb<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRSYb<opcode, (outs), (ins cls:$R1, bdaddr20only:$BD2, cond4:$M3),
+ mnemonic#"$M3\t$R1, $BD2", []>;
+
+class AsmCmpBranchRSYb<string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRSYb<opcode, (outs), (ins cls:$R1, bdaddr20only:$BD2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $M3, $BD2", []>;
+
+multiclass CmpBranchRSYbPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls> {
+ let isCodeGenOnly = 1 in
+ def "" : CmpBranchRSYb<mnemonic, opcode, cls>;
+ def Asm : AsmCmpBranchRSYb<mnemonic, opcode, cls>;
+}
+
+class FixedCmpBranchRSYb<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls>
+ : InstRSYb<opcode, (outs), (ins cls:$R1, bdaddr20only:$BD2),
+ mnemonic#V.suffix#"\t$R1, $BD2", []> {
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
class BranchUnaryRI<string mnemonic, bits<12> opcode, RegisterOperand cls>
- : InstRI<opcode, (outs cls:$R1), (ins cls:$R1src, brtarget16:$I2),
- mnemonic##"\t$R1, $I2", []> {
- let isBranch = 1;
- let isTerminator = 1;
+ : InstRIb<opcode, (outs cls:$R1), (ins cls:$R1src, brtarget16:$RI2),
+ mnemonic##"\t$R1, $RI2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRIL<string mnemonic, bits<12> opcode, RegisterOperand cls>
+ : InstRILb<opcode, (outs cls:$R1), (ins cls:$R1src, brtarget32:$RI2),
+ mnemonic##"\t$R1, $RI2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRR<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRR<opcode, (outs cls:$R1), (ins cls:$R1src, GR64:$R2),
+ mnemonic##"\t$R1, $R2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRRE<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRRE<opcode, (outs cls:$R1), (ins cls:$R1src, GR64:$R2),
+ mnemonic##"\t$R1, $R2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRX<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRXa<opcode, (outs cls:$R1), (ins cls:$R1src, bdxaddr12only:$XBD2),
+ mnemonic##"\t$R1, $XBD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchUnaryRXY<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRXYa<opcode, (outs cls:$R1), (ins cls:$R1src, bdxaddr20only:$XBD2),
+ mnemonic##"\t$R1, $XBD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchBinaryRSI<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRSI<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, brtarget16:$RI2),
+ mnemonic##"\t$R1, $R3, $RI2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchBinaryRIEe<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRIEe<opcode, (outs cls:$R1),
+ (ins cls:$R1src, cls:$R3, brtarget16:$RI2),
+ mnemonic##"\t$R1, $R3, $RI2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchBinaryRS<string mnemonic, bits<8> opcode, RegisterOperand cls>
+ : InstRSa<opcode, (outs cls:$R1),
+ (ins cls:$R1src, cls:$R3, bdaddr12only:$BD2),
+ mnemonic##"\t$R1, $R3, $BD2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+class BranchBinaryRSY<string mnemonic, bits<16> opcode, RegisterOperand cls>
+ : InstRSYa<opcode,
+ (outs cls:$R1), (ins cls:$R1src, cls:$R3, bdaddr20only:$BD2),
+ mnemonic##"\t$R1, $R3, $BD2", []> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
}
class LoadMultipleRS<string mnemonic, bits<8> opcode, RegisterOperand cls,
AddressingMode mode = bdaddr12only>
- : InstRS<opcode, (outs cls:$R1, cls:$R3), (ins mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2", []> {
+ : InstRSa<opcode, (outs cls:$R1, cls:$R3), (ins mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2", []> {
let mayLoad = 1;
}
class LoadMultipleRSY<string mnemonic, bits<16> opcode, RegisterOperand cls,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1, cls:$R3), (ins mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2", []> {
+ : InstRSYa<opcode, (outs cls:$R1, cls:$R3), (ins mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2", []> {
let mayLoad = 1;
}
@@ -1093,9 +2093,9 @@ class LoadMultipleVRSa<string mnemonic, bits<16> opcode>
class StoreRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls>
- : InstRIL<opcode, (outs), (ins cls:$R1, pcrel32:$I2),
- mnemonic#"\t$R1, $I2",
- [(operator cls:$R1, pcrel32:$I2)]> {
+ : InstRILb<opcode, (outs), (ins cls:$R1, pcrel32:$RI2),
+ mnemonic#"\t$R1, $RI2",
+ [(operator cls:$R1, pcrel32:$RI2)]> {
let mayStore = 1;
// We want PC-relative addresses to be tried ahead of BD and BDX addresses.
// However, BDXs have two extra operands and are therefore 6 units more
@@ -1106,10 +2106,10 @@ class StoreRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator,
class StoreRX<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdxaddr12only>
- : InstRX<opcode, (outs), (ins cls:$R1, mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(operator cls:$R1, mode:$XBD2)]> {
- let OpKey = mnemonic ## cls;
+ : InstRXa<opcode, (outs), (ins cls:$R1, mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(operator cls:$R1, mode:$XBD2)]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let mayStore = 1;
let AccessBytes = bytes;
@@ -1118,10 +2118,10 @@ class StoreRX<string mnemonic, bits<8> opcode, SDPatternOperator operator,
class StoreRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdxaddr20only>
- : InstRXY<opcode, (outs), (ins cls:$R1, mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(operator cls:$R1, mode:$XBD2)]> {
- let OpKey = mnemonic ## cls;
+ : InstRXYa<opcode, (outs), (ins cls:$R1, mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(operator cls:$R1, mode:$XBD2)]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let mayStore = 1;
let AccessBytes = bytes;
@@ -1161,15 +2161,15 @@ class StoreLengthVRSb<string mnemonic, bits<16> opcode,
class StoreMultipleRS<string mnemonic, bits<8> opcode, RegisterOperand cls,
AddressingMode mode = bdaddr12only>
- : InstRS<opcode, (outs), (ins cls:$R1, cls:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2", []> {
+ : InstRSa<opcode, (outs), (ins cls:$R1, cls:$R3, mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2", []> {
let mayStore = 1;
}
class StoreMultipleRSY<string mnemonic, bits<16> opcode, RegisterOperand cls,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs), (ins cls:$R1, cls:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2", []> {
+ : InstRSYa<opcode, (outs), (ins cls:$R1, cls:$R3, mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2", []> {
let mayStore = 1;
}
@@ -1230,12 +2230,17 @@ multiclass StoreSIPair<string mnemonic, bits<8> siOpcode, bits<16> siyOpcode,
}
}
+class StoreSSE<string mnemonic, bits<16> opcode>
+ : InstSSE<opcode, (outs), (ins bdaddr12only:$BD1, bdaddr12only:$BD2),
+ mnemonic#"\t$BD1, $BD2", []> {
+ let mayStore = 1;
+}
+
class CondStoreRSY<string mnemonic, bits<16> opcode,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs), (ins cls:$R1, mode:$BD2, cond4:$valid, cond4:$R3),
- mnemonic#"$R3\t$R1, $BD2", []>,
- Requires<[FeatureLoadStoreOnCond]> {
+ : InstRSYb<opcode, (outs), (ins cls:$R1, mode:$BD2, cond4:$valid, cond4:$M3),
+ mnemonic#"$M3\t$R1, $BD2", []> {
let mayStore = 1;
let AccessBytes = bytes;
let CCMaskLast = 1;
@@ -1246,139 +2251,127 @@ class CondStoreRSY<string mnemonic, bits<16> opcode,
class AsmCondStoreRSY<string mnemonic, bits<16> opcode,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs), (ins cls:$R1, mode:$BD2, imm32zx4:$R3),
- mnemonic#"\t$R1, $BD2, $R3", []>,
- Requires<[FeatureLoadStoreOnCond]> {
+ : InstRSYb<opcode, (outs), (ins cls:$R1, mode:$BD2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $BD2, $M3", []> {
let mayStore = 1;
let AccessBytes = bytes;
}
// Like CondStoreRSY, but with a fixed CC mask.
-class FixedCondStoreRSY<string mnemonic, bits<16> opcode,
- RegisterOperand cls, bits<4> ccmask, bits<5> bytes,
+class FixedCondStoreRSY<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs), (ins cls:$R1, mode:$BD2),
- mnemonic#"\t$R1, $BD2", []>,
- Requires<[FeatureLoadStoreOnCond]> {
+ : InstRSYb<opcode, (outs), (ins cls:$R1, mode:$BD2),
+ mnemonic#V.suffix#"\t$R1, $BD2", []> {
let mayStore = 1;
let AccessBytes = bytes;
- let R3 = ccmask;
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
}
-class UnaryRR<string mnemonic, bits<8> opcode, SDPatternOperator operator,
- RegisterOperand cls1, RegisterOperand cls2>
- : InstRR<opcode, (outs cls1:$R1), (ins cls2:$R2),
- mnemonic#"r\t$R1, $R2",
- [(set cls1:$R1, (operator cls2:$R2))]> {
- let OpKey = mnemonic ## cls1;
- let OpType = "reg";
+multiclass CondStoreRSYPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, bits<5> bytes,
+ AddressingMode mode = bdaddr20only> {
+ let isCodeGenOnly = 1 in
+ def "" : CondStoreRSY<mnemonic, opcode, cls, bytes, mode>;
+ def Asm : AsmCondStoreRSY<mnemonic, opcode, cls, bytes, mode>;
}
-class UnaryRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
- RegisterOperand cls1, RegisterOperand cls2>
- : InstRRE<opcode, (outs cls1:$R1), (ins cls2:$R2),
- mnemonic#"r\t$R1, $R2",
- [(set cls1:$R1, (operator cls2:$R2))]> {
- let OpKey = mnemonic ## cls1;
- let OpType = "reg";
-}
+class SideEffectUnaryI<string mnemonic, bits<8> opcode, Immediate imm>
+ : InstI<opcode, (outs), (ins imm:$I1),
+ mnemonic#"\t$I1", []>;
-class UnaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1,
- RegisterOperand cls2>
- : InstRRF<opcode, (outs cls1:$R1), (ins imm32zx4:$R3, cls2:$R2),
- mnemonic#"r\t$R1, $R3, $R2", []> {
- let OpKey = mnemonic ## cls1;
- let OpType = "reg";
- let R4 = 0;
+class SideEffectUnaryRR<string mnemonic, bits<8>opcode, RegisterOperand cls>
+ : InstRR<opcode, (outs), (ins cls:$R1),
+ mnemonic#"\t$R1", []> {
+ let R2 = 0;
}
-class UnaryRRF4<string mnemonic, bits<16> opcode, RegisterOperand cls1,
- RegisterOperand cls2>
- : InstRRF<opcode, (outs cls1:$R1), (ins imm32zx4:$R3, cls2:$R2, imm32zx4:$R4),
- mnemonic#"\t$R1, $R3, $R2, $R4", []>;
-
-// These instructions are generated by if conversion. The old value of R1
-// is added as an implicit use.
-class CondUnaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1,
- RegisterOperand cls2>
- : InstRRF<opcode, (outs cls1:$R1), (ins cls2:$R2, cond4:$valid, cond4:$R3),
- mnemonic#"r$R3\t$R1, $R2", []>,
- Requires<[FeatureLoadStoreOnCond]> {
- let CCMaskLast = 1;
- let R4 = 0;
+class SideEffectUnaryRRE<string mnemonic, bits<16> opcode, RegisterOperand cls,
+ SDPatternOperator operator>
+ : InstRRE<opcode, (outs), (ins cls:$R1),
+ mnemonic#"\t$R1", [(operator cls:$R1)]> {
+ let R2 = 0;
}
-class CondUnaryRIE<string mnemonic, bits<16> opcode, RegisterOperand cls,
- Immediate imm>
- : InstRIEd<opcode, (outs cls:$R1),
- (ins imm:$I2, cond4:$valid, cond4:$R3),
- mnemonic#"$R3\t$R1, $I2", []>,
- Requires<[FeatureLoadStoreOnCond2]> {
- let CCMaskLast = 1;
+class SideEffectUnaryS<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator, bits<5> bytes,
+ AddressingMode mode = bdaddr12only>
+ : InstS<opcode, (outs), (ins mode:$BD2),
+ mnemonic#"\t$BD2", [(operator mode:$BD2)]> {
+ let mayLoad = 1;
+ let AccessBytes = bytes;
}
-// Like CondUnaryRRF, but used for the raw assembly form. The condition-code
-// mask is the third operand rather than being part of the mnemonic.
-class AsmCondUnaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1,
- RegisterOperand cls2>
- : InstRRF<opcode, (outs cls1:$R1), (ins cls1:$R1src, cls2:$R2, imm32zx4:$R3),
- mnemonic#"r\t$R1, $R2, $R3", []>,
- Requires<[FeatureLoadStoreOnCond]> {
- let Constraints = "$R1 = $R1src";
- let DisableEncoding = "$R1src";
- let R4 = 0;
-}
+class SideEffectAddressS<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator,
+ AddressingMode mode = bdaddr12only>
+ : InstS<opcode, (outs), (ins mode:$BD2),
+ mnemonic#"\t$BD2", [(operator mode:$BD2)]>;
-class AsmCondUnaryRIE<string mnemonic, bits<16> opcode, RegisterOperand cls,
- Immediate imm>
- : InstRIEd<opcode, (outs cls:$R1),
- (ins cls:$R1src, imm:$I2, imm32zx4:$R3),
- mnemonic#"\t$R1, $I2, $R3", []>,
- Requires<[FeatureLoadStoreOnCond2]> {
- let Constraints = "$R1 = $R1src";
- let DisableEncoding = "$R1src";
+class LoadAddressRX<string mnemonic, bits<8> opcode,
+ SDPatternOperator operator, AddressingMode mode>
+ : InstRXa<opcode, (outs GR64:$R1), (ins mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(set GR64:$R1, (operator mode:$XBD2))]>;
+
+class LoadAddressRXY<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator, AddressingMode mode>
+ : InstRXYa<opcode, (outs GR64:$R1), (ins mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(set GR64:$R1, (operator mode:$XBD2))]>;
+
+multiclass LoadAddressRXPair<string mnemonic, bits<8> rxOpcode,
+ bits<16> rxyOpcode, SDPatternOperator operator> {
+ let DispKey = mnemonic in {
+ let DispSize = "12" in
+ def "" : LoadAddressRX<mnemonic, rxOpcode, operator, laaddr12pair>;
+ let DispSize = "20" in
+ def Y : LoadAddressRXY<mnemonic#"y", rxyOpcode, operator, laaddr20pair>;
+ }
}
-// Like CondUnaryRRF, but with a fixed CC mask.
-class FixedCondUnaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1,
- RegisterOperand cls2, bits<4> ccmask>
- : InstRRF<opcode, (outs cls1:$R1), (ins cls1:$R1src, cls2:$R2),
- mnemonic#"\t$R1, $R2", []>,
- Requires<[FeatureLoadStoreOnCond]> {
- let Constraints = "$R1 = $R1src";
- let DisableEncoding = "$R1src";
- let R3 = ccmask;
- let R4 = 0;
+class LoadAddressRIL<string mnemonic, bits<12> opcode,
+ SDPatternOperator operator>
+ : InstRILb<opcode, (outs GR64:$R1), (ins pcrel32:$RI2),
+ mnemonic#"\t$R1, $RI2",
+ [(set GR64:$R1, (operator pcrel32:$RI2))]>;
+
+class UnaryRR<string mnemonic, bits<8> opcode, SDPatternOperator operator,
+ RegisterOperand cls1, RegisterOperand cls2>
+ : InstRR<opcode, (outs cls1:$R1), (ins cls2:$R2),
+ mnemonic#"\t$R1, $R2",
+ [(set cls1:$R1, (operator cls2:$R2))]> {
+ let OpKey = mnemonic#cls1;
+ let OpType = "reg";
}
-class FixedCondUnaryRIE<string mnemonic, bits<16> opcode, RegisterOperand cls,
- Immediate imm, bits<4> ccmask>
- : InstRIEd<opcode, (outs cls:$R1),
- (ins cls:$R1src, imm:$I2),
- mnemonic#"\t$R1, $I2", []>,
- Requires<[FeatureLoadStoreOnCond2]> {
- let Constraints = "$R1 = $R1src";
- let DisableEncoding = "$R1src";
- let R3 = ccmask;
+class UnaryRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
+ RegisterOperand cls1, RegisterOperand cls2>
+ : InstRRE<opcode, (outs cls1:$R1), (ins cls2:$R2),
+ mnemonic#"\t$R1, $R2",
+ [(set cls1:$R1, (operator cls2:$R2))]> {
+ let OpKey = mnemonic#cls1;
+ let OpType = "reg";
}
class UnaryRI<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, Immediate imm>
- : InstRI<opcode, (outs cls:$R1), (ins imm:$I2),
- mnemonic#"\t$R1, $I2",
- [(set cls:$R1, (operator imm:$I2))]>;
+ : InstRIa<opcode, (outs cls:$R1), (ins imm:$I2),
+ mnemonic#"\t$R1, $I2",
+ [(set cls:$R1, (operator imm:$I2))]>;
class UnaryRIL<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, Immediate imm>
- : InstRIL<opcode, (outs cls:$R1), (ins imm:$I2),
- mnemonic#"\t$R1, $I2",
- [(set cls:$R1, (operator imm:$I2))]>;
+ : InstRILa<opcode, (outs cls:$R1), (ins imm:$I2),
+ mnemonic#"\t$R1, $I2",
+ [(set cls:$R1, (operator imm:$I2))]>;
class UnaryRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls>
- : InstRIL<opcode, (outs cls:$R1), (ins pcrel32:$I2),
- mnemonic#"\t$R1, $I2",
- [(set cls:$R1, (operator pcrel32:$I2))]> {
+ : InstRILb<opcode, (outs cls:$R1), (ins pcrel32:$RI2),
+ mnemonic#"\t$R1, $RI2",
+ [(set cls:$R1, (operator pcrel32:$RI2))]> {
let mayLoad = 1;
// We want PC-relative addresses to be tried ahead of BD and BDX addresses.
// However, BDXs have two extra operands and are therefore 6 units more
@@ -1389,13 +2382,12 @@ class UnaryRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator,
class CondUnaryRSY<string mnemonic, bits<16> opcode,
SDPatternOperator operator, RegisterOperand cls,
bits<5> bytes, AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1),
- (ins cls:$R1src, mode:$BD2, cond4:$valid, cond4:$R3),
- mnemonic#"$R3\t$R1, $BD2",
- [(set cls:$R1,
- (z_select_ccmask (load bdaddr20only:$BD2), cls:$R1src,
- cond4:$valid, cond4:$R3))]>,
- Requires<[FeatureLoadStoreOnCond]> {
+ : InstRSYb<opcode, (outs cls:$R1),
+ (ins cls:$R1src, mode:$BD2, cond4:$valid, cond4:$M3),
+ mnemonic#"$M3\t$R1, $BD2",
+ [(set cls:$R1,
+ (z_select_ccmask (operator bdaddr20only:$BD2), cls:$R1src,
+ cond4:$valid, cond4:$M3))]> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
let mayLoad = 1;
@@ -1408,9 +2400,8 @@ class CondUnaryRSY<string mnemonic, bits<16> opcode,
class AsmCondUnaryRSY<string mnemonic, bits<16> opcode,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$BD2, imm32zx4:$R3),
- mnemonic#"\t$R1, $BD2, $R3", []>,
- Requires<[FeatureLoadStoreOnCond]> {
+ : InstRSYb<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$BD2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $BD2, $M3", []> {
let mayLoad = 1;
let AccessBytes = bytes;
let Constraints = "$R1 = $R1src";
@@ -1418,26 +2409,36 @@ class AsmCondUnaryRSY<string mnemonic, bits<16> opcode,
}
// Like CondUnaryRSY, but with a fixed CC mask.
-class FixedCondUnaryRSY<string mnemonic, bits<16> opcode,
- RegisterOperand cls, bits<4> ccmask, bits<5> bytes,
+class FixedCondUnaryRSY<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$BD2),
- mnemonic#"\t$R1, $BD2", []>,
- Requires<[FeatureLoadStoreOnCond]> {
+ : InstRSYb<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$BD2),
+ mnemonic#V.suffix#"\t$R1, $BD2", []> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
- let R3 = ccmask;
let mayLoad = 1;
let AccessBytes = bytes;
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
}
+multiclass CondUnaryRSYPair<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator,
+ RegisterOperand cls, bits<5> bytes,
+ AddressingMode mode = bdaddr20only> {
+ let isCodeGenOnly = 1 in
+ def "" : CondUnaryRSY<mnemonic, opcode, operator, cls, bytes, mode>;
+ def Asm : AsmCondUnaryRSY<mnemonic, opcode, cls, bytes, mode>;
+}
+
+
class UnaryRX<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdxaddr12only>
- : InstRX<opcode, (outs cls:$R1), (ins mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(set cls:$R1, (operator mode:$XBD2))]> {
- let OpKey = mnemonic ## cls;
+ : InstRXa<opcode, (outs cls:$R1), (ins mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(set cls:$R1, (operator mode:$XBD2))]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let mayLoad = 1;
let AccessBytes = bytes;
@@ -1448,7 +2449,7 @@ class UnaryRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
: InstRXE<opcode, (outs cls:$R1), (ins bdxaddr12only:$XBD2),
mnemonic#"\t$R1, $XBD2",
[(set cls:$R1, (operator bdxaddr12only:$XBD2))]> {
- let OpKey = mnemonic ## cls;
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let mayLoad = 1;
let AccessBytes = bytes;
@@ -1458,10 +2459,10 @@ class UnaryRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
class UnaryRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls, bits<5> bytes,
AddressingMode mode = bdxaddr20only>
- : InstRXY<opcode, (outs cls:$R1), (ins mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(set cls:$R1, (operator mode:$XBD2))]> {
- let OpKey = mnemonic ## cls;
+ : InstRXYa<opcode, (outs cls:$R1), (ins mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(set cls:$R1, (operator mode:$XBD2))]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let mayLoad = 1;
let AccessBytes = bytes;
@@ -1487,6 +2488,10 @@ class UnaryVRIa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M3 = type;
}
+class UnaryVRIaGeneric<string mnemonic, bits<16> opcode, Immediate imm>
+ : InstVRIa<opcode, (outs VR128:$V1), (ins imm:$I2, imm32zx4:$M3),
+ mnemonic#"\t$V1, $I2, $M3", []>;
+
class UnaryVRRa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, bits<4> type = 0, bits<4> m4 = 0,
bits<4> m5 = 0>
@@ -1498,15 +2503,50 @@ class UnaryVRRa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M5 = m5;
}
-multiclass UnaryVRRaSPair<string mnemonic, bits<16> opcode,
- SDPatternOperator operator,
- SDPatternOperator operator_cc, TypedReg tr1,
- TypedReg tr2, bits<4> type, bits<4> modifier = 0,
- bits<4> modifier_cc = 1> {
- def "" : UnaryVRRa<mnemonic, opcode, operator, tr1, tr2, type, 0, modifier>;
+class UnaryVRRaGeneric<string mnemonic, bits<16> opcode, bits<4> m4 = 0,
+ bits<4> m5 = 0>
+ : InstVRRa<opcode, (outs VR128:$V1), (ins VR128:$V2, imm32zx4:$M3),
+ mnemonic#"\t$V1, $V2, $M3", []> {
+ let M4 = m4;
+ let M5 = m5;
+}
+
+class UnaryVRRaFloatGeneric<string mnemonic, bits<16> opcode, bits<4> m5 = 0>
+ : InstVRRa<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, imm32zx4:$M3, imm32zx4:$M4),
+ mnemonic#"\t$V1, $V2, $M3, $M4", []> {
+ let M5 = m5;
+}
+
+// Declare a pair of instructions, one which sets CC and one which doesn't.
+// The CC-setting form ends with "S" and sets the low bit of M5.
+// The form that does not set CC has an extra operand to optionally allow
+// specifying arbitrary M5 values in assembler.
+multiclass UnaryExtraVRRaSPair<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator,
+ SDPatternOperator operator_cc,
+ TypedReg tr1, TypedReg tr2, bits<4> type> {
+ let M3 = type, M4 = 0 in
+ def "" : InstVRRa<opcode, (outs tr1.op:$V1),
+ (ins tr2.op:$V2, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $M5", []>;
+ def : Pat<(tr1.vt (operator (tr2.vt tr2.op:$V2))),
+ (!cast<Instruction>(NAME) tr2.op:$V2, 0)>;
+ def : InstAlias<mnemonic#"\t$V1, $V2",
+ (!cast<Instruction>(NAME) tr1.op:$V1, tr2.op:$V2, 0)>;
let Defs = [CC] in
- def S : UnaryVRRa<mnemonic##"s", opcode, operator_cc, tr1, tr2, type, 0,
- modifier_cc>;
+ def S : UnaryVRRa<mnemonic##"s", opcode, operator_cc, tr1, tr2,
+ type, 0, 1>;
+}
+
+multiclass UnaryExtraVRRaSPairGeneric<string mnemonic, bits<16> opcode> {
+ let M4 = 0 in
+ def "" : InstVRRa<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, imm32zx4:$M3, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $M3, $M5", []>;
+ def : InstAlias<mnemonic#"\t$V1, $V2, $M3",
+ (!cast<Instruction>(NAME) VR128:$V1, VR128:$V2,
+ imm32zx4:$M3, 0)>;
}
class UnaryVRX<string mnemonic, bits<16> opcode, SDPatternOperator operator,
@@ -1519,12 +2559,43 @@ class UnaryVRX<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let AccessBytes = bytes;
}
+class UnaryVRXGeneric<string mnemonic, bits<16> opcode>
+ : InstVRX<opcode, (outs VR128:$V1), (ins bdxaddr12only:$XBD2, imm32zx4:$M3),
+ mnemonic#"\t$V1, $XBD2, $M3", []> {
+ let mayLoad = 1;
+}
+
+class SideEffectBinaryRX<string mnemonic, bits<8> opcode,
+ RegisterOperand cls>
+ : InstRXa<opcode, (outs), (ins cls:$R1, bdxaddr12only:$XBD2),
+ mnemonic##"\t$R1, $XBD2", []>;
+
+class SideEffectBinaryRILPC<string mnemonic, bits<12> opcode,
+ RegisterOperand cls>
+ : InstRILb<opcode, (outs), (ins cls:$R1, pcrel32:$RI2),
+ mnemonic##"\t$R1, $RI2", []> {
+ // We want PC-relative addresses to be tried ahead of BD and BDX addresses.
+ // However, BDXs have two extra operands and are therefore 6 units more
+ // complex.
+ let AddedComplexity = 7;
+}
+
+class SideEffectBinaryIE<string mnemonic, bits<16> opcode,
+ Immediate imm1, Immediate imm2>
+ : InstIE<opcode, (outs), (ins imm1:$I1, imm2:$I2),
+ mnemonic#"\t$I1, $I2", []>;
+
+class SideEffectBinarySIL<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator, Immediate imm>
+ : InstSIL<opcode, (outs), (ins bdaddr12only:$BD1, imm:$I2),
+ mnemonic#"\t$BD1, $I2", [(operator bdaddr12only:$BD1, imm:$I2)]>;
+
class BinaryRR<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls1, RegisterOperand cls2>
: InstRR<opcode, (outs cls1:$R1), (ins cls1:$R1src, cls2:$R2),
- mnemonic#"r\t$R1, $R2",
+ mnemonic#"\t$R1, $R2",
[(set cls1:$R1, (operator cls1:$R1src, cls2:$R2))]> {
- let OpKey = mnemonic ## cls1;
+ let OpKey = mnemonic#cls1;
let OpType = "reg";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -1533,30 +2604,21 @@ class BinaryRR<string mnemonic, bits<8> opcode, SDPatternOperator operator,
class BinaryRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls1, RegisterOperand cls2>
: InstRRE<opcode, (outs cls1:$R1), (ins cls1:$R1src, cls2:$R2),
- mnemonic#"r\t$R1, $R2",
+ mnemonic#"\t$R1, $R2",
[(set cls1:$R1, (operator cls1:$R1src, cls2:$R2))]> {
- let OpKey = mnemonic ## cls1;
+ let OpKey = mnemonic#cls1;
let OpType = "reg";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
}
-class BinaryRRF<string mnemonic, bits<16> opcode, SDPatternOperator operator,
- RegisterOperand cls1, RegisterOperand cls2>
- : InstRRF<opcode, (outs cls1:$R1), (ins cls1:$R2, cls2:$R3),
- mnemonic#"r\t$R1, $R3, $R2",
- [(set cls1:$R1, (operator cls1:$R2, cls2:$R3))]> {
- let OpKey = mnemonic ## cls1;
- let OpType = "reg";
- let R4 = 0;
-}
-
-class BinaryRRFK<string mnemonic, bits<16> opcode, SDPatternOperator operator,
- RegisterOperand cls1, RegisterOperand cls2>
- : InstRRF<opcode, (outs cls1:$R1), (ins cls1:$R2, cls2:$R3),
- mnemonic#"rk\t$R1, $R2, $R3",
- [(set cls1:$R1, (operator cls1:$R2, cls2:$R3))]> {
- let R4 = 0;
+class BinaryRRFa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
+ RegisterOperand cls1, RegisterOperand cls2,
+ RegisterOperand cls3>
+ : InstRRFa<opcode, (outs cls1:$R1), (ins cls2:$R2, cls3:$R3),
+ mnemonic#"\t$R1, $R2, $R3",
+ [(set cls1:$R1, (operator cls2:$R2, cls3:$R3))]> {
+ let M4 = 0;
}
multiclass BinaryRRAndK<string mnemonic, bits<8> opcode1, bits<16> opcode2,
@@ -1564,7 +2626,7 @@ multiclass BinaryRRAndK<string mnemonic, bits<8> opcode1, bits<16> opcode2,
RegisterOperand cls2> {
let NumOpsKey = mnemonic in {
let NumOpsValue = "3" in
- def K : BinaryRRFK<mnemonic, opcode2, null_frag, cls1, cls2>,
+ def K : BinaryRRFa<mnemonic#"k", opcode2, null_frag, cls1, cls1, cls2>,
Requires<[FeatureDistinctOps]>;
let NumOpsValue = "2", isConvertibleToThreeAddress = 1 in
def "" : BinaryRR<mnemonic, opcode1, operator, cls1, cls2>;
@@ -1576,18 +2638,73 @@ multiclass BinaryRREAndK<string mnemonic, bits<16> opcode1, bits<16> opcode2,
RegisterOperand cls2> {
let NumOpsKey = mnemonic in {
let NumOpsValue = "3" in
- def K : BinaryRRFK<mnemonic, opcode2, null_frag, cls1, cls2>,
+ def K : BinaryRRFa<mnemonic#"k", opcode2, null_frag, cls1, cls1, cls2>,
Requires<[FeatureDistinctOps]>;
let NumOpsValue = "2", isConvertibleToThreeAddress = 1 in
def "" : BinaryRRE<mnemonic, opcode1, operator, cls1, cls2>;
}
}
+class BinaryRRFb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
+ RegisterOperand cls1, RegisterOperand cls2,
+ RegisterOperand cls3>
+ : InstRRFb<opcode, (outs cls1:$R1), (ins cls2:$R2, cls3:$R3),
+ mnemonic#"\t$R1, $R3, $R2",
+ [(set cls1:$R1, (operator cls2:$R2, cls3:$R3))]> {
+ let M4 = 0;
+}
+
+class BinaryRRFe<string mnemonic, bits<16> opcode, RegisterOperand cls1,
+ RegisterOperand cls2>
+ : InstRRFe<opcode, (outs cls1:$R1), (ins imm32zx4:$M3, cls2:$R2),
+ mnemonic#"\t$R1, $M3, $R2", []> {
+ let M4 = 0;
+}
+
+class CondBinaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1,
+ RegisterOperand cls2>
+ : InstRRFc<opcode, (outs cls1:$R1),
+ (ins cls1:$R1src, cls2:$R2, cond4:$valid, cond4:$M3),
+ mnemonic#"$M3\t$R1, $R2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let CCMaskLast = 1;
+}
+
+// Like CondBinaryRRF, but used for the raw assembly form. The condition-code
+// mask is the third operand rather than being part of the mnemonic.
+class AsmCondBinaryRRF<string mnemonic, bits<16> opcode, RegisterOperand cls1,
+ RegisterOperand cls2>
+ : InstRRFc<opcode, (outs cls1:$R1),
+ (ins cls1:$R1src, cls2:$R2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $R2, $M3", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+// Like CondBinaryRRF, but with a fixed CC mask.
+class FixedCondBinaryRRF<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls1, RegisterOperand cls2>
+ : InstRRFc<opcode, (outs cls1:$R1), (ins cls1:$R1src, cls2:$R2),
+ mnemonic#V.suffix#"\t$R1, $R2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CondBinaryRRFPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls1, RegisterOperand cls2> {
+ let isCodeGenOnly = 1 in
+ def "" : CondBinaryRRF<mnemonic, opcode, cls1, cls2>;
+ def Asm : AsmCondBinaryRRF<mnemonic, opcode, cls1, cls2>;
+}
+
class BinaryRI<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, Immediate imm>
- : InstRI<opcode, (outs cls:$R1), (ins cls:$R1src, imm:$I2),
- mnemonic#"\t$R1, $I2",
- [(set cls:$R1, (operator cls:$R1src, imm:$I2))]> {
+ : InstRIa<opcode, (outs cls:$R1), (ins cls:$R1src, imm:$I2),
+ mnemonic#"\t$R1, $I2",
+ [(set cls:$R1, (operator cls:$R1src, imm:$I2))]> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
}
@@ -1610,20 +2727,61 @@ multiclass BinaryRIAndK<string mnemonic, bits<12> opcode1, bits<16> opcode2,
}
}
+class CondBinaryRIE<string mnemonic, bits<16> opcode, RegisterOperand cls,
+ Immediate imm>
+ : InstRIEg<opcode, (outs cls:$R1),
+ (ins cls:$R1src, imm:$I2, cond4:$valid, cond4:$M3),
+ mnemonic#"$M3\t$R1, $I2",
+ [(set cls:$R1, (z_select_ccmask imm:$I2, cls:$R1src,
+ cond4:$valid, cond4:$M3))]> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let CCMaskLast = 1;
+}
+
+// Like CondBinaryRIE, but used for the raw assembly form. The condition-code
+// mask is the third operand rather than being part of the mnemonic.
+class AsmCondBinaryRIE<string mnemonic, bits<16> opcode, RegisterOperand cls,
+ Immediate imm>
+ : InstRIEg<opcode, (outs cls:$R1),
+ (ins cls:$R1src, imm:$I2, imm32zx4:$M3),
+ mnemonic#"\t$R1, $I2, $M3", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+}
+
+// Like CondBinaryRIE, but with a fixed CC mask.
+class FixedCondBinaryRIE<CondVariant V, string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm>
+ : InstRIEg<opcode, (outs cls:$R1), (ins cls:$R1src, imm:$I2),
+ mnemonic#V.suffix#"\t$R1, $I2", []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let isAsmParserOnly = V.alternate;
+ let M3 = V.ccmask;
+}
+
+multiclass CondBinaryRIEPair<string mnemonic, bits<16> opcode,
+ RegisterOperand cls, Immediate imm> {
+ let isCodeGenOnly = 1 in
+ def "" : CondBinaryRIE<mnemonic, opcode, cls, imm>;
+ def Asm : AsmCondBinaryRIE<mnemonic, opcode, cls, imm>;
+}
+
class BinaryRIL<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, Immediate imm>
- : InstRIL<opcode, (outs cls:$R1), (ins cls:$R1src, imm:$I2),
- mnemonic#"\t$R1, $I2",
- [(set cls:$R1, (operator cls:$R1src, imm:$I2))]> {
+ : InstRILa<opcode, (outs cls:$R1), (ins cls:$R1src, imm:$I2),
+ mnemonic#"\t$R1, $I2",
+ [(set cls:$R1, (operator cls:$R1src, imm:$I2))]> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
}
class BinaryRS<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls>
- : InstRS<opcode, (outs cls:$R1), (ins cls:$R1src, shift12only:$BD2),
- mnemonic#"\t$R1, $BD2",
- [(set cls:$R1, (operator cls:$R1src, shift12only:$BD2))]> {
+ : InstRSa<opcode, (outs cls:$R1), (ins cls:$R1src, shift12only:$BD2),
+ mnemonic#"\t$R1, $BD2",
+ [(set cls:$R1, (operator cls:$R1src, shift12only:$BD2))]> {
let R3 = 0;
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -1631,9 +2789,9 @@ class BinaryRS<string mnemonic, bits<8> opcode, SDPatternOperator operator,
class BinaryRSY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls>
- : InstRSY<opcode, (outs cls:$R1), (ins cls:$R3, shift20only:$BD2),
- mnemonic#"\t$R1, $R3, $BD2",
- [(set cls:$R1, (operator cls:$R3, shift20only:$BD2))]>;
+ : InstRSYa<opcode, (outs cls:$R1), (ins cls:$R3, shift20only:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2",
+ [(set cls:$R1, (operator cls:$R3, shift20only:$BD2))]>;
multiclass BinaryRSAndK<string mnemonic, bits<8> opcode1, bits<16> opcode2,
SDPatternOperator operator, RegisterOperand cls> {
@@ -1649,10 +2807,10 @@ multiclass BinaryRSAndK<string mnemonic, bits<8> opcode1, bits<16> opcode2,
class BinaryRX<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls, SDPatternOperator load, bits<5> bytes,
AddressingMode mode = bdxaddr12only>
- : InstRX<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(set cls:$R1, (operator cls:$R1src, (load mode:$XBD2)))]> {
- let OpKey = mnemonic ## cls;
+ : InstRXa<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(set cls:$R1, (operator cls:$R1src, (load mode:$XBD2)))]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -1666,7 +2824,7 @@ class BinaryRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
mnemonic#"\t$R1, $XBD2",
[(set cls:$R1, (operator cls:$R1src,
(load bdxaddr12only:$XBD2)))]> {
- let OpKey = mnemonic ## cls;
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -1678,10 +2836,10 @@ class BinaryRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
class BinaryRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls, SDPatternOperator load, bits<5> bytes,
AddressingMode mode = bdxaddr20only>
- : InstRXY<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(set cls:$R1, (operator cls:$R1src, (load mode:$XBD2)))]> {
- let OpKey = mnemonic ## cls;
+ : InstRXYa<opcode, (outs cls:$R1), (ins cls:$R1src, mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(set cls:$R1, (operator cls:$R1src, (load mode:$XBD2)))]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -1731,6 +2889,12 @@ multiclass BinarySIPair<string mnemonic, bits<8> siOpcode,
}
}
+class BinarySSF<string mnemonic, bits<12> opcode, RegisterOperand cls>
+ : InstSSF<opcode, (outs cls:$R3), (ins bdaddr12pair:$BD1, bdaddr12pair:$BD2),
+ mnemonic#"\t$R3, $BD1, $BD2", []> {
+ let mayLoad = 1;
+}
+
class BinaryVRIb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr, bits<4> type>
: InstVRIb<opcode, (outs tr.op:$V1), (ins imm32zx8:$I2, imm32zx8:$I3),
@@ -1739,6 +2903,11 @@ class BinaryVRIb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M4 = type;
}
+class BinaryVRIbGeneric<string mnemonic, bits<16> opcode>
+ : InstVRIb<opcode, (outs VR128:$V1),
+ (ins imm32zx8:$I2, imm32zx8:$I3, imm32zx4:$M4),
+ mnemonic#"\t$V1, $I2, $I3, $M4", []>;
+
class BinaryVRIc<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, bits<4> type>
: InstVRIc<opcode, (outs tr1.op:$V1), (ins tr2.op:$V3, imm32zx16:$I2),
@@ -1748,6 +2917,11 @@ class BinaryVRIc<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M4 = type;
}
+class BinaryVRIcGeneric<string mnemonic, bits<16> opcode>
+ : InstVRIc<opcode, (outs VR128:$V1),
+ (ins VR128:$V3, imm32zx16:$I2, imm32zx4:$M4),
+ mnemonic#"\t$V1, $V3, $I2, $M4", []>;
+
class BinaryVRIe<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, bits<4> type, bits<4> m5>
: InstVRIe<opcode, (outs tr1.op:$V1), (ins tr2.op:$V2, imm32zx12:$I3),
@@ -1758,13 +2932,26 @@ class BinaryVRIe<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M5 = m5;
}
-class BinaryVRRa<string mnemonic, bits<16> opcode>
- : InstVRRa<opcode, (outs VR128:$V1), (ins VR128:$V2, imm32zx4:$M3),
- mnemonic#"\t$V1, $V2, $M3", []> {
- let M4 = 0;
- let M5 = 0;
+class BinaryVRIeFloatGeneric<string mnemonic, bits<16> opcode>
+ : InstVRIe<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, imm32zx12:$I3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $I3, $M4, $M5", []>;
+
+class BinaryVRRa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
+ TypedReg tr1, TypedReg tr2, bits<4> type = 0, bits<4> m4 = 0>
+ : InstVRRa<opcode, (outs tr1.op:$V1), (ins tr2.op:$V2, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $M5",
+ [(set tr1.op:$V1, (tr1.vt (operator (tr2.vt tr2.op:$V2),
+ imm32zx12:$M5)))]> {
+ let M3 = type;
+ let M4 = m4;
}
+class BinaryVRRaFloatGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRa<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, imm32zx4:$M3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $M3, $M4, $M5", []>;
+
class BinaryVRRb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, bits<4> type = 0,
bits<4> modifier = 0>
@@ -1781,12 +2968,47 @@ class BinaryVRRb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
multiclass BinaryVRRbSPair<string mnemonic, bits<16> opcode,
SDPatternOperator operator,
SDPatternOperator operator_cc, TypedReg tr1,
- TypedReg tr2, bits<4> type,
- bits<4> modifier = 0, bits<4> modifier_cc = 1> {
- def "" : BinaryVRRb<mnemonic, opcode, operator, tr1, tr2, type, modifier>;
+ TypedReg tr2, bits<4> type, bits<4> modifier = 0> {
+ def "" : BinaryVRRb<mnemonic, opcode, operator, tr1, tr2, type,
+ !and (modifier, 14)>;
let Defs = [CC] in
def S : BinaryVRRb<mnemonic##"s", opcode, operator_cc, tr1, tr2, type,
- modifier_cc>;
+ !add (!and (modifier, 14), 1)>;
+}
+
+class BinaryVRRbSPairGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRb<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $M4, $M5", []>;
+
+// Declare a pair of instructions, one which sets CC and one which doesn't.
+// The CC-setting form ends with "S" and sets the low bit of M5.
+// The form that does not set CC has an extra operand to optionally allow
+// specifying arbitrary M5 values in assembler.
+multiclass BinaryExtraVRRbSPair<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator,
+ SDPatternOperator operator_cc,
+ TypedReg tr1, TypedReg tr2, bits<4> type> {
+ let M4 = type in
+ def "" : InstVRRb<opcode, (outs tr1.op:$V1),
+ (ins tr2.op:$V2, tr2.op:$V3, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $M5", []>;
+ def : Pat<(tr1.vt (operator (tr2.vt tr2.op:$V2), (tr2.vt tr2.op:$V3))),
+ (!cast<Instruction>(NAME) tr2.op:$V2, tr2.op:$V3, 0)>;
+ def : InstAlias<mnemonic#"\t$V1, $V2, $V3",
+ (!cast<Instruction>(NAME) tr1.op:$V1, tr2.op:$V2,
+ tr2.op:$V3, 0)>;
+ let Defs = [CC] in
+ def S : BinaryVRRb<mnemonic##"s", opcode, operator_cc, tr1, tr2, type, 1>;
+}
+
+multiclass BinaryExtraVRRbSPairGeneric<string mnemonic, bits<16> opcode> {
+ def "" : InstVRRb<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $M4, $M5", []>;
+ def : InstAlias<mnemonic#"\t$V1, $V2, $V3, $M4",
+ (!cast<Instruction>(NAME) VR128:$V1, VR128:$V2, VR128:$V3,
+ imm32zx4:$M4, 0)>;
}
class BinaryVRRc<string mnemonic, bits<16> opcode, SDPatternOperator operator,
@@ -1801,17 +3023,42 @@ class BinaryVRRc<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M6 = m6;
}
+class BinaryVRRcGeneric<string mnemonic, bits<16> opcode, bits<4> m5 = 0,
+ bits<4> m6 = 0>
+ : InstVRRc<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, imm32zx4:$M4),
+ mnemonic#"\t$V1, $V2, $V3, $M4", []> {
+ let M5 = m5;
+ let M6 = m6;
+}
+
+class BinaryVRRcFloatGeneric<string mnemonic, bits<16> opcode, bits<4> m6 = 0>
+ : InstVRRc<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $M4, $M5", []> {
+ let M6 = m6;
+}
+
+// Declare a pair of instructions, one which sets CC and one which doesn't.
+// The CC-setting form ends with "S" and sets the low bit of M5.
multiclass BinaryVRRcSPair<string mnemonic, bits<16> opcode,
SDPatternOperator operator,
SDPatternOperator operator_cc, TypedReg tr1,
TypedReg tr2, bits<4> type, bits<4> m5,
- bits<4> modifier = 0, bits<4> modifier_cc = 1> {
- def "" : BinaryVRRc<mnemonic, opcode, operator, tr1, tr2, type, m5, modifier>;
+ bits<4> modifier = 0> {
+ def "" : BinaryVRRc<mnemonic, opcode, operator, tr1, tr2, type,
+ m5, !and (modifier, 14)>;
let Defs = [CC] in
def S : BinaryVRRc<mnemonic##"s", opcode, operator_cc, tr1, tr2, type,
- m5, modifier_cc>;
+ m5, !add (!and (modifier, 14), 1)>;
}
+class BinaryVRRcSPairFloatGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRc<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, imm32zx4:$M4, imm32zx4:$M5,
+ imm32zx4:$M6),
+ mnemonic#"\t$V1, $V2, $V3, $M4, $M5, $M6", []>;
+
class BinaryVRRf<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr>
: InstVRRf<opcode, (outs tr.op:$V1), (ins GR64:$R2, GR64:$R3),
@@ -1827,6 +3074,11 @@ class BinaryVRSa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M4 = type;
}
+class BinaryVRSaGeneric<string mnemonic, bits<16> opcode>
+ : InstVRSa<opcode, (outs VR128:$V1),
+ (ins VR128:$V3, shift12only:$BD2, imm32zx4:$M4),
+ mnemonic#"\t$V1, $V3, $BD2, $M4", []>;
+
class BinaryVRSb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
bits<5> bytes>
: InstVRSb<opcode, (outs VR128:$V1), (ins GR32:$R3, bdaddr12only:$BD2),
@@ -1845,6 +3097,11 @@ class BinaryVRSc<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M4 = type;
}
+class BinaryVRScGeneric<string mnemonic, bits<16> opcode>
+ : InstVRSc<opcode, (outs GR64:$R1),
+ (ins VR128:$V3, shift12only:$BD2, imm32zx4: $M4),
+ mnemonic#"\t$R1, $V3, $BD2, $M4", []>;
+
class BinaryVRX<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr, bits<5> bytes>
: InstVRX<opcode, (outs VR128:$V1), (ins bdxaddr12only:$XBD2, imm32zx4:$M3),
@@ -1873,12 +3130,18 @@ class StoreBinaryVRX<string mnemonic, bits<16> opcode,
let AccessBytes = bytes;
}
+class MemoryBinarySSd<string mnemonic, bits<8> opcode,
+ RegisterOperand cls>
+ : InstSSd<opcode, (outs),
+ (ins bdraddr12only:$RBD1, bdaddr12only:$BD2, cls:$R3),
+ mnemonic#"\t$RBD1, $BD2, $R3", []>;
+
class CompareRR<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls1, RegisterOperand cls2>
: InstRR<opcode, (outs), (ins cls1:$R1, cls2:$R2),
- mnemonic#"r\t$R1, $R2",
+ mnemonic#"\t$R1, $R2",
[(operator cls1:$R1, cls2:$R2)]> {
- let OpKey = mnemonic ## cls1;
+ let OpKey = mnemonic#cls1;
let OpType = "reg";
let isCompare = 1;
}
@@ -1886,34 +3149,34 @@ class CompareRR<string mnemonic, bits<8> opcode, SDPatternOperator operator,
class CompareRRE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls1, RegisterOperand cls2>
: InstRRE<opcode, (outs), (ins cls1:$R1, cls2:$R2),
- mnemonic#"r\t$R1, $R2",
+ mnemonic#"\t$R1, $R2",
[(operator cls1:$R1, cls2:$R2)]> {
- let OpKey = mnemonic ## cls1;
+ let OpKey = mnemonic#cls1;
let OpType = "reg";
let isCompare = 1;
}
class CompareRI<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, Immediate imm>
- : InstRI<opcode, (outs), (ins cls:$R1, imm:$I2),
- mnemonic#"\t$R1, $I2",
- [(operator cls:$R1, imm:$I2)]> {
+ : InstRIa<opcode, (outs), (ins cls:$R1, imm:$I2),
+ mnemonic#"\t$R1, $I2",
+ [(operator cls:$R1, imm:$I2)]> {
let isCompare = 1;
}
class CompareRIL<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, Immediate imm>
- : InstRIL<opcode, (outs), (ins cls:$R1, imm:$I2),
- mnemonic#"\t$R1, $I2",
- [(operator cls:$R1, imm:$I2)]> {
+ : InstRILa<opcode, (outs), (ins cls:$R1, imm:$I2),
+ mnemonic#"\t$R1, $I2",
+ [(operator cls:$R1, imm:$I2)]> {
let isCompare = 1;
}
class CompareRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator,
RegisterOperand cls, SDPatternOperator load>
- : InstRIL<opcode, (outs), (ins cls:$R1, pcrel32:$I2),
- mnemonic#"\t$R1, $I2",
- [(operator cls:$R1, (load pcrel32:$I2))]> {
+ : InstRILb<opcode, (outs), (ins cls:$R1, pcrel32:$RI2),
+ mnemonic#"\t$R1, $RI2",
+ [(operator cls:$R1, (load pcrel32:$RI2))]> {
let isCompare = 1;
let mayLoad = 1;
// We want PC-relative addresses to be tried ahead of BD and BDX addresses.
@@ -1925,10 +3188,10 @@ class CompareRILPC<string mnemonic, bits<12> opcode, SDPatternOperator operator,
class CompareRX<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls, SDPatternOperator load, bits<5> bytes,
AddressingMode mode = bdxaddr12only>
- : InstRX<opcode, (outs), (ins cls:$R1, mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(operator cls:$R1, (load mode:$XBD2))]> {
- let OpKey = mnemonic ## cls;
+ : InstRXa<opcode, (outs), (ins cls:$R1, mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(operator cls:$R1, (load mode:$XBD2))]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let isCompare = 1;
let mayLoad = 1;
@@ -1940,7 +3203,7 @@ class CompareRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
: InstRXE<opcode, (outs), (ins cls:$R1, bdxaddr12only:$XBD2),
mnemonic#"\t$R1, $XBD2",
[(operator cls:$R1, (load bdxaddr12only:$XBD2))]> {
- let OpKey = mnemonic ## cls;
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let isCompare = 1;
let mayLoad = 1;
@@ -1951,10 +3214,10 @@ class CompareRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
class CompareRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls, SDPatternOperator load, bits<5> bytes,
AddressingMode mode = bdxaddr20only>
- : InstRXY<opcode, (outs), (ins cls:$R1, mode:$XBD2),
- mnemonic#"\t$R1, $XBD2",
- [(operator cls:$R1, (load mode:$XBD2))]> {
- let OpKey = mnemonic ## cls;
+ : InstRXYa<opcode, (outs), (ins cls:$R1, mode:$XBD2),
+ mnemonic#"\t$R1, $XBD2",
+ [(operator cls:$R1, (load mode:$XBD2))]> {
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let isCompare = 1;
let mayLoad = 1;
@@ -2026,6 +3289,22 @@ class CompareVRRa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M5 = 0;
}
+class CompareVRRaGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRa<opcode, (outs), (ins VR128:$V1, VR128:$V2, imm32zx4:$M3),
+ mnemonic#"\t$V1, $V2, $M3", []> {
+ let isCompare = 1;
+ let M4 = 0;
+ let M5 = 0;
+}
+
+class CompareVRRaFloatGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRa<opcode, (outs),
+ (ins VR64:$V1, VR64:$V2, imm32zx4:$M3, imm32zx4:$M4),
+ mnemonic#"\t$V1, $V2, $M3, $M4", []> {
+ let isCompare = 1;
+ let M5 = 0;
+}
+
class TestRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls>
: InstRXE<opcode, (outs), (ins cls:$R1, bdxaddr12only:$XBD2),
@@ -2034,12 +3313,30 @@ class TestRXE<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M3 = 0;
}
+class SideEffectTernaryRRFc<string mnemonic, bits<16> opcode,
+ RegisterOperand cls1, RegisterOperand cls2,
+ Immediate imm>
+ : InstRRFc<opcode, (outs), (ins cls1:$R1, cls2:$R2, imm:$M3),
+ mnemonic#"\t$R1, $R2, $M3", []>;
+
+class SideEffectTernarySSF<string mnemonic, bits<12> opcode,
+ RegisterOperand cls>
+ : InstSSF<opcode, (outs),
+ (ins bdaddr12only:$BD1, bdaddr12only:$BD2, cls:$R3),
+ mnemonic#"\t$BD1, $BD2, $R3", []>;
+
+class TernaryRRFe<string mnemonic, bits<16> opcode, RegisterOperand cls1,
+ RegisterOperand cls2>
+ : InstRRFe<opcode, (outs cls1:$R1),
+ (ins imm32zx4:$M3, cls2:$R2, imm32zx4:$M4),
+ mnemonic#"\t$R1, $M3, $R2, $M4", []>;
+
class TernaryRRD<string mnemonic, bits<16> opcode,
SDPatternOperator operator, RegisterOperand cls>
: InstRRD<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, cls:$R2),
- mnemonic#"r\t$R1, $R3, $R2",
+ mnemonic#"\t$R1, $R3, $R2",
[(set cls:$R1, (operator cls:$R1src, cls:$R3, cls:$R2))]> {
- let OpKey = mnemonic ## cls;
+ let OpKey = mnemonic#cls;
let OpType = "reg";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -2047,9 +3344,9 @@ class TernaryRRD<string mnemonic, bits<16> opcode,
class TernaryRS<string mnemonic, bits<8> opcode, RegisterOperand cls,
bits<5> bytes, AddressingMode mode = bdaddr12only>
- : InstRS<opcode, (outs cls:$R1),
- (ins cls:$R1src, imm32zx4:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2", []> {
+ : InstRSb<opcode, (outs cls:$R1),
+ (ins cls:$R1src, imm32zx4:$M3, mode:$BD2),
+ mnemonic#"\t$R1, $M3, $BD2", []> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -2059,9 +3356,9 @@ class TernaryRS<string mnemonic, bits<8> opcode, RegisterOperand cls,
class TernaryRSY<string mnemonic, bits<16> opcode, RegisterOperand cls,
bits<5> bytes, AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1),
- (ins cls:$R1src, imm32zx4:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2", []> {
+ : InstRSYb<opcode, (outs cls:$R1),
+ (ins cls:$R1src, imm32zx4:$M3, mode:$BD2),
+ mnemonic#"\t$R1, $M3, $BD2", []> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -2086,7 +3383,7 @@ class TernaryRXF<string mnemonic, bits<16> opcode, SDPatternOperator operator,
mnemonic#"\t$R1, $R3, $XBD2",
[(set cls:$R1, (operator cls:$R1src, cls:$R3,
(load bdxaddr12only:$XBD2)))]> {
- let OpKey = mnemonic ## cls;
+ let OpKey = mnemonic#"r"#cls;
let OpType = "mem";
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
@@ -2127,6 +3424,11 @@ class TernaryVRRa<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M3 = type;
}
+class TernaryVRRaFloatGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRa<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, imm32zx4:$M3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $M3, $M4, $M5", []>;
+
class TernaryVRRb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, bits<4> type,
SDPatternOperator m5mask, bits<4> m5or>
@@ -2140,23 +3442,36 @@ class TernaryVRRb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M4 = type;
}
-multiclass TernaryVRRbSPair<string mnemonic, bits<16> opcode,
- SDPatternOperator operator,
- SDPatternOperator operator_cc, TypedReg tr1,
- TypedReg tr2, bits<4> type, bits<4> m5or> {
+// Declare a pair of instructions, one which sets CC and one which doesn't.
+// The CC-setting form ends with "S" and sets the low bit of M5.
+// Also create aliases to make use of M5 operand optional in assembler.
+multiclass TernaryOptVRRbSPair<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator,
+ SDPatternOperator operator_cc,
+ TypedReg tr1, TypedReg tr2, bits<4> type,
+ bits<4> modifier = 0> {
def "" : TernaryVRRb<mnemonic, opcode, operator, tr1, tr2, type,
- imm32zx4even, !and (m5or, 14)>;
+ imm32zx4even, !and (modifier, 14)>;
def : InstAlias<mnemonic#"\t$V1, $V2, $V3",
(!cast<Instruction>(NAME) tr1.op:$V1, tr2.op:$V2,
tr2.op:$V3, 0)>;
let Defs = [CC] in
def S : TernaryVRRb<mnemonic##"s", opcode, operator_cc, tr1, tr2, type,
- imm32zx4even, !add(!and (m5or, 14), 1)>;
+ imm32zx4even, !add(!and (modifier, 14), 1)>;
def : InstAlias<mnemonic#"s\t$V1, $V2, $V3",
(!cast<Instruction>(NAME#"S") tr1.op:$V1, tr2.op:$V2,
tr2.op:$V3, 0)>;
}
+multiclass TernaryOptVRRbSPairGeneric<string mnemonic, bits<16> opcode> {
+ def "" : InstVRRb<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, imm32zx4:$M4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $M4, $M5", []>;
+ def : InstAlias<mnemonic#"\t$V1, $V2, $V3, $M4",
+ (!cast<Instruction>(NAME) VR128:$V1, VR128:$V2, VR128:$V3,
+ imm32zx4:$M4, 0)>;
+}
+
class TernaryVRRc<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2>
: InstVRRc<opcode, (outs tr1.op:$V1),
@@ -2181,6 +3496,13 @@ class TernaryVRRd<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M6 = 0;
}
+class TernaryVRRdGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRd<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, VR128:$V4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $V4, $M5", []> {
+ let M6 = 0;
+}
+
class TernaryVRRe<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, bits<4> m5 = 0, bits<4> type = 0>
: InstVRRe<opcode, (outs tr1.op:$V1),
@@ -2193,6 +3515,11 @@ class TernaryVRRe<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M6 = type;
}
+class TernaryVRReFloatGeneric<string mnemonic, bits<16> opcode>
+ : InstVRRe<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, VR128:$V4, imm32zx4:$M5, imm32zx4:$M6),
+ mnemonic#"\t$V1, $V2, $V3, $V4, $M5, $M6", []>;
+
class TernaryVRSb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
TypedReg tr1, TypedReg tr2, RegisterOperand cls, bits<4> type>
: InstVRSb<opcode, (outs tr1.op:$V1),
@@ -2206,6 +3533,14 @@ class TernaryVRSb<string mnemonic, bits<16> opcode, SDPatternOperator operator,
let M4 = type;
}
+class TernaryVRSbGeneric<string mnemonic, bits<16> opcode>
+ : InstVRSb<opcode, (outs VR128:$V1),
+ (ins VR128:$V1src, GR64:$R3, shift12only:$BD2, imm32zx4:$M4),
+ mnemonic#"\t$V1, $R3, $BD2, $M4", []> {
+ let Constraints = "$V1 = $V1src";
+ let DisableEncoding = "$V1src";
+}
+
class TernaryVRV<string mnemonic, bits<16> opcode, bits<5> bytes,
Immediate index>
: InstVRV<opcode, (outs VR128:$V1),
@@ -2245,6 +3580,15 @@ class QuaternaryVRId<string mnemonic, bits<16> opcode, SDPatternOperator operato
let M5 = type;
}
+class QuaternaryVRIdGeneric<string mnemonic, bits<16> opcode>
+ : InstVRId<opcode, (outs VR128:$V1),
+ (ins VR128:$V1src, VR128:$V2, VR128:$V3,
+ imm32zx8:$I4, imm32zx4:$M5),
+ mnemonic#"\t$V1, $V2, $V3, $I4, $M5", []> {
+ let Constraints = "$V1 = $V1src";
+ let DisableEncoding = "$V1src";
+}
+
class QuaternaryVRRd<string mnemonic, bits<16> opcode,
SDPatternOperator operator, TypedReg tr1, TypedReg tr2,
bits<4> type, SDPatternOperator m6mask, bits<4> m6or>
@@ -2259,37 +3603,57 @@ class QuaternaryVRRd<string mnemonic, bits<16> opcode,
let M5 = type;
}
-multiclass QuaternaryVRRdSPair<string mnemonic, bits<16> opcode,
- SDPatternOperator operator,
- SDPatternOperator operator_cc, TypedReg tr1,
- TypedReg tr2, bits<4> type, bits<4> m6or> {
+// Declare a pair of instructions, one which sets CC and one which doesn't.
+// The CC-setting form ends with "S" and sets the low bit of M6.
+// Also create aliases to make use of M6 operand optional in assembler.
+multiclass QuaternaryOptVRRdSPair<string mnemonic, bits<16> opcode,
+ SDPatternOperator operator,
+ SDPatternOperator operator_cc,
+ TypedReg tr1, TypedReg tr2, bits<4> type,
+ bits<4> modifier = 0> {
def "" : QuaternaryVRRd<mnemonic, opcode, operator, tr1, tr2, type,
- imm32zx4even, !and (m6or, 14)>;
+ imm32zx4even, !and (modifier, 14)>;
def : InstAlias<mnemonic#"\t$V1, $V2, $V3, $V4",
(!cast<Instruction>(NAME) tr1.op:$V1, tr2.op:$V2,
tr2.op:$V3, tr2.op:$V4, 0)>;
let Defs = [CC] in
def S : QuaternaryVRRd<mnemonic##"s", opcode, operator_cc, tr1, tr2, type,
- imm32zx4even, !add (!and (m6or, 14), 1)>;
+ imm32zx4even, !add (!and (modifier, 14), 1)>;
def : InstAlias<mnemonic#"s\t$V1, $V2, $V3, $V4",
(!cast<Instruction>(NAME#"S") tr1.op:$V1, tr2.op:$V2,
tr2.op:$V3, tr2.op:$V4, 0)>;
}
+multiclass QuaternaryOptVRRdSPairGeneric<string mnemonic, bits<16> opcode> {
+ def "" : InstVRRd<opcode, (outs VR128:$V1),
+ (ins VR128:$V2, VR128:$V3, VR128:$V4,
+ imm32zx4:$M5, imm32zx4:$M6),
+ mnemonic#"\t$V1, $V2, $V3, $V4, $M5, $M6", []>;
+ def : InstAlias<mnemonic#"\t$V1, $V2, $V3, $V4, $M5",
+ (!cast<Instruction>(NAME) VR128:$V1, VR128:$V2, VR128:$V3,
+ VR128:$V4, imm32zx4:$M5, 0)>;
+}
+
+class SideEffectQuaternarySSe<string mnemonic, bits<8> opcode,
+ RegisterOperand cls>
+ : InstSSe<opcode, (outs),
+ (ins cls:$R1, bdaddr12only:$BD2, cls:$R3, bdaddr12only:$BD4),
+ mnemonic#"\t$R1, $BD2, $R3, $BD4", []>;
+
class LoadAndOpRSY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls, AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1), (ins cls:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2",
- [(set cls:$R1, (operator mode:$BD2, cls:$R3))]> {
+ : InstRSYa<opcode, (outs cls:$R1), (ins cls:$R3, mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2",
+ [(set cls:$R1, (operator mode:$BD2, cls:$R3))]> {
let mayLoad = 1;
let mayStore = 1;
}
class CmpSwapRS<string mnemonic, bits<8> opcode, SDPatternOperator operator,
RegisterOperand cls, AddressingMode mode = bdaddr12only>
- : InstRS<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2",
- [(set cls:$R1, (operator mode:$BD2, cls:$R1src, cls:$R3))]> {
+ : InstRSa<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2",
+ [(set cls:$R1, (operator mode:$BD2, cls:$R1src, cls:$R3))]> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
let mayLoad = 1;
@@ -2298,9 +3662,9 @@ class CmpSwapRS<string mnemonic, bits<8> opcode, SDPatternOperator operator,
class CmpSwapRSY<string mnemonic, bits<16> opcode, SDPatternOperator operator,
RegisterOperand cls, AddressingMode mode = bdaddr20only>
- : InstRSY<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, mode:$BD2),
- mnemonic#"\t$R1, $R3, $BD2",
- [(set cls:$R1, (operator mode:$BD2, cls:$R1src, cls:$R3))]> {
+ : InstRSYa<opcode, (outs cls:$R1), (ins cls:$R1src, cls:$R3, mode:$BD2),
+ mnemonic#"\t$R1, $R3, $BD2",
+ [(set cls:$R1, (operator mode:$BD2, cls:$R1src, cls:$R3))]> {
let Constraints = "$R1 = $R1src";
let DisableEncoding = "$R1src";
let mayLoad = 1;
@@ -2328,21 +3692,31 @@ class RotateSelectRIEf<string mnemonic, bits<16> opcode, RegisterOperand cls1,
}
class PrefetchRXY<string mnemonic, bits<16> opcode, SDPatternOperator operator>
- : InstRXY<opcode, (outs), (ins imm32zx4:$R1, bdxaddr20only:$XBD2),
- mnemonic##"\t$R1, $XBD2",
- [(operator imm32zx4:$R1, bdxaddr20only:$XBD2)]>;
+ : InstRXYb<opcode, (outs), (ins imm32zx4:$M1, bdxaddr20only:$XBD2),
+ mnemonic##"\t$M1, $XBD2",
+ [(operator imm32zx4:$M1, bdxaddr20only:$XBD2)]>;
class PrefetchRILPC<string mnemonic, bits<12> opcode,
SDPatternOperator operator>
- : InstRIL<opcode, (outs), (ins imm32zx4:$R1, pcrel32:$I2),
- mnemonic##"\t$R1, $I2",
- [(operator imm32zx4:$R1, pcrel32:$I2)]> {
+ : InstRILc<opcode, (outs), (ins imm32zx4:$M1, pcrel32:$RI2),
+ mnemonic##"\t$M1, $RI2",
+ [(operator imm32zx4:$M1, pcrel32:$RI2)]> {
// We want PC-relative addresses to be tried ahead of BD and BDX addresses.
// However, BDXs have two extra operands and are therefore 6 units more
// complex.
let AddedComplexity = 7;
}
+class BranchPreloadSMI<string mnemonic, bits<8> opcode>
+ : InstSMI<opcode, (outs),
+ (ins imm32zx4:$M1, brtarget16bpp:$RI2, bdxaddr12only:$BD3),
+ mnemonic#"\t$M1, $RI2, $BD3", []>;
+
+class BranchPreloadMII<string mnemonic, bits<8> opcode>
+ : InstMII<opcode, (outs),
+ (ins imm32zx4:$M1, brtarget12bpp:$RI2, brtarget24bpp:$RI3),
+ mnemonic#"\t$M1, $RI2, $RI3", []>;
+
// A floating-point load-and test operation. Create both a normal unary
// operation and one that acts as a comparison against zero.
// Note that the comparison against zero operation is not available if we
@@ -2371,6 +3745,11 @@ class Pseudo<dag outs, dag ins, list<dag> pattern>
let isCodeGenOnly = 1;
}
+// Like SideEffectBinarySIL, but expanded later.
+class SideEffectBinarySILPseudo<SDPatternOperator operator, Immediate imm>
+ : Pseudo<(outs), (ins bdaddr12only:$BD1, imm:$I2),
+ [(operator bdaddr12only:$BD1, imm:$I2)]>;
+
// Like UnaryRI, but expanded after RA depending on the choice of register.
class UnaryRIPseudo<SDPatternOperator operator, RegisterOperand cls,
Immediate imm>
@@ -2383,7 +3762,7 @@ class UnaryRXYPseudo<string key, SDPatternOperator operator,
AddressingMode mode = bdxaddr20only>
: Pseudo<(outs cls:$R1), (ins mode:$XBD2),
[(set cls:$R1, (operator mode:$XBD2))]> {
- let OpKey = key ## cls;
+ let OpKey = key#"r"#cls;
let OpType = "mem";
let mayLoad = 1;
let Has20BitOffset = 1;
@@ -2396,7 +3775,7 @@ class UnaryRRPseudo<string key, SDPatternOperator operator,
RegisterOperand cls1, RegisterOperand cls2>
: Pseudo<(outs cls1:$R1), (ins cls2:$R2),
[(set cls1:$R1, (operator cls2:$R2))]> {
- let OpKey = key ## cls1;
+ let OpKey = key#cls1;
let OpType = "reg";
}
@@ -2430,7 +3809,9 @@ multiclass BinaryRIAndKPseudo<string key, SDPatternOperator operator,
// Like CompareRI, but expanded after RA depending on the choice of register.
class CompareRIPseudo<SDPatternOperator operator, RegisterOperand cls,
Immediate imm>
- : Pseudo<(outs), (ins cls:$R1, imm:$I2), [(operator cls:$R1, imm:$I2)]>;
+ : Pseudo<(outs), (ins cls:$R1, imm:$I2), [(operator cls:$R1, imm:$I2)]> {
+ let isCompare = 1;
+}
// Like CompareRXY, but expanded after RA depending on the choice of register.
class CompareRXYPseudo<SDPatternOperator operator, RegisterOperand cls,
@@ -2444,6 +3825,54 @@ class CompareRXYPseudo<SDPatternOperator operator, RegisterOperand cls,
let AccessBytes = bytes;
}
+// Like CondBinaryRRF, but expanded after RA depending on the choice of
+// register.
+class CondBinaryRRFPseudo<RegisterOperand cls1, RegisterOperand cls2>
+ : Pseudo<(outs cls1:$R1),
+ (ins cls1:$R1src, cls2:$R2, cond4:$valid, cond4:$M3), []> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let CCMaskLast = 1;
+}
+
+// Like CondBinaryRIE, but expanded after RA depending on the choice of
+// register.
+class CondBinaryRIEPseudo<RegisterOperand cls, Immediate imm>
+ : Pseudo<(outs cls:$R1),
+ (ins cls:$R1src, imm:$I2, cond4:$valid, cond4:$M3),
+ [(set cls:$R1, (z_select_ccmask imm:$I2, cls:$R1src,
+ cond4:$valid, cond4:$M3))]> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let CCMaskLast = 1;
+}
+
+// Like CondUnaryRSY, but expanded after RA depending on the choice of
+// register.
+class CondUnaryRSYPseudo<SDPatternOperator operator, RegisterOperand cls,
+ bits<5> bytes, AddressingMode mode = bdaddr20only>
+ : Pseudo<(outs cls:$R1),
+ (ins cls:$R1src, mode:$BD2, cond4:$valid, cond4:$R3),
+ [(set cls:$R1,
+ (z_select_ccmask (operator mode:$BD2), cls:$R1src,
+ cond4:$valid, cond4:$R3))]> {
+ let Constraints = "$R1 = $R1src";
+ let DisableEncoding = "$R1src";
+ let mayLoad = 1;
+ let AccessBytes = bytes;
+ let CCMaskLast = 1;
+}
+
+// Like CondStoreRSY, but expanded after RA depending on the choice of
+// register.
+class CondStoreRSYPseudo<RegisterOperand cls, bits<5> bytes,
+ AddressingMode mode = bdaddr20only>
+ : Pseudo<(outs), (ins cls:$R1, mode:$BD2, cond4:$valid, cond4:$R3), []> {
+ let mayStore = 1;
+ let AccessBytes = bytes;
+ let CCMaskLast = 1;
+}
+
// Like StoreRXY, but expanded after RA depending on the choice of register.
class StoreRXYPseudo<SDPatternOperator operator, RegisterOperand cls,
bits<5> bytes, AddressingMode mode = bdxaddr20only>
@@ -2509,6 +3938,7 @@ class AtomicLoadBinary<SDPatternOperator operator, RegisterOperand cls,
let mayLoad = 1;
let mayStore = 1;
let usesCustomInserter = 1;
+ let hasNoSchedulingInfo = 1;
}
// Specializations of AtomicLoadWBinary.
@@ -2535,6 +3965,7 @@ class AtomicLoadWBinary<SDPatternOperator operator, dag pat,
let mayLoad = 1;
let mayStore = 1;
let usesCustomInserter = 1;
+ let hasNoSchedulingInfo = 1;
}
// Specializations of AtomicLoadWBinary.
@@ -2550,10 +3981,10 @@ class AtomicLoadWBinaryImm<SDPatternOperator operator, Immediate imm>
// another instruction to handle the excess.
multiclass MemorySS<string mnemonic, bits<8> opcode,
SDPatternOperator sequence, SDPatternOperator loop> {
- def "" : InstSS<opcode, (outs), (ins bdladdr12onlylen8:$BDL1,
- bdaddr12only:$BD2),
- mnemonic##"\t$BDL1, $BD2", []>;
- let usesCustomInserter = 1 in {
+ def "" : InstSSa<opcode, (outs), (ins bdladdr12onlylen8:$BDL1,
+ bdaddr12only:$BD2),
+ mnemonic##"\t$BDL1, $BD2", []>;
+ let usesCustomInserter = 1, hasNoSchedulingInfo = 1 in {
def Sequence : Pseudo<(outs), (ins bdaddr12only:$dest, bdaddr12only:$src,
imm64:$length),
[(sequence bdaddr12only:$dest, bdaddr12only:$src,
@@ -2579,7 +4010,7 @@ multiclass StringRRE<string mnemonic, bits<16> opcode,
let Constraints = "$R1 = $R1src, $R2 = $R2src";
let DisableEncoding = "$R1src, $R2src";
}
- let usesCustomInserter = 1 in
+ let usesCustomInserter = 1, hasNoSchedulingInfo = 1 in
def Loop : Pseudo<(outs GR64:$end),
(ins GR64:$start1, GR64:$start2, GR32:$char),
[(set GR64:$end, (operator GR64:$start1, GR64:$start2,
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 4084e93..3565d5f 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -88,10 +88,10 @@ void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI,
void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const {
MachineBasicBlock *MBB = MI->getParent();
MachineFunction &MF = *MBB->getParent();
- MachineFrameInfo *MFFrame = MF.getFrameInfo();
+ MachineFrameInfo &MFFrame = MF.getFrameInfo();
MachineOperand &OffsetMO = MI->getOperand(2);
- uint64_t Offset = (MFFrame->getMaxCallFrameSize() +
+ uint64_t Offset = (MFFrame.getMaxCallFrameSize() +
SystemZMC::CallFrameSize +
OffsetMO.getImm());
unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset);
@@ -149,6 +149,37 @@ void SystemZInstrInfo::expandRXYPseudo(MachineInstr &MI, unsigned LowOpcode,
MI.setDesc(get(Opcode));
}
+// MI is a load-on-condition pseudo instruction with a single register
+// (source or destination) operand. Replace it with LowOpcode if the
+// register is a low GR32 and HighOpcode if the register is a high GR32.
+void SystemZInstrInfo::expandLOCPseudo(MachineInstr &MI, unsigned LowOpcode,
+ unsigned HighOpcode) const {
+ unsigned Reg = MI.getOperand(0).getReg();
+ unsigned Opcode = isHighReg(Reg) ? HighOpcode : LowOpcode;
+ MI.setDesc(get(Opcode));
+}
+
+// MI is a load-register-on-condition pseudo instruction. Replace it with
+// LowOpcode if source and destination are both low GR32s and HighOpcode if
+// source and destination are both high GR32s.
+void SystemZInstrInfo::expandLOCRPseudo(MachineInstr &MI, unsigned LowOpcode,
+ unsigned HighOpcode) const {
+ unsigned DestReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool DestIsHigh = isHighReg(DestReg);
+ bool SrcIsHigh = isHighReg(SrcReg);
+
+ if (!DestIsHigh && !SrcIsHigh)
+ MI.setDesc(get(LowOpcode));
+ else if (DestIsHigh && SrcIsHigh)
+ MI.setDesc(get(HighOpcode));
+
+ // If we were unable to implement the pseudo with a single instruction, we
+ // need to convert it back into a branch sequence. This cannot be done here
+ // since the caller of expandPostRAPseudo does not handle changes to the CFG
+ // correctly. This change is defered to the SystemZExpandPseudo pass.
+}
+
// MI is an RR-style pseudo instruction that zero-extends the low Size bits
// of one GRX32 into another. Replace it with LowOpcode if both operands
// are low registers, otherwise use RISB[LH]G.
@@ -172,7 +203,7 @@ void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const {
MachineInstr *Ear1MI = MF.CloneMachineInstr(MI);
MBB->insert(MI, Ear1MI);
Ear1MI->setDesc(get(SystemZ::EAR));
- MachineInstrBuilder(MF, Ear1MI).addImm(0);
+ MachineInstrBuilder(MF, Ear1MI).addReg(SystemZ::A0);
// sllg <reg>, <reg>, 32
MachineInstr *SllgMI = MF.CloneMachineInstr(MI);
@@ -184,7 +215,7 @@ void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const {
MachineInstr *Ear2MI = MF.CloneMachineInstr(MI);
MBB->insert(MI, Ear2MI);
Ear2MI->setDesc(get(SystemZ::EAR));
- MachineInstrBuilder(MF, Ear2MI).addImm(1);
+ MachineInstrBuilder(MF, Ear2MI).addReg(SystemZ::A1);
// lg <reg>, 40(<reg>)
MI->setDesc(get(SystemZ::LG));
@@ -222,6 +253,36 @@ void SystemZInstrInfo::emitGRX32Move(MachineBasicBlock &MBB,
.addImm(32 - Size).addImm(128 + 31).addImm(Rotate);
}
+
+MachineInstr *SystemZInstrInfo::commuteInstructionImpl(MachineInstr &MI,
+ bool NewMI,
+ unsigned OpIdx1,
+ unsigned OpIdx2) const {
+ auto cloneIfNew = [NewMI](MachineInstr &MI) -> MachineInstr & {
+ if (NewMI)
+ return *MI.getParent()->getParent()->CloneMachineInstr(&MI);
+ return MI;
+ };
+
+ switch (MI.getOpcode()) {
+ case SystemZ::LOCRMux:
+ case SystemZ::LOCFHR:
+ case SystemZ::LOCR:
+ case SystemZ::LOCGR: {
+ auto &WorkingMI = cloneIfNew(MI);
+ // Invert condition.
+ unsigned CCValid = WorkingMI.getOperand(3).getImm();
+ unsigned CCMask = WorkingMI.getOperand(4).getImm();
+ WorkingMI.getOperand(4).setImm(CCMask ^ CCValid);
+ return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
+ OpIdx1, OpIdx2);
+ }
+ default:
+ return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
+ }
+}
+
+
// If MI is a simple load or store for a frame object, return the register
// it loads or stores and set FrameIndex to the index of the frame object.
// Return 0 otherwise.
@@ -252,7 +313,7 @@ bool SystemZInstrInfo::isStackSlotCopy(const MachineInstr &MI,
int &DestFrameIndex,
int &SrcFrameIndex) const {
// Check for MVC 0(Length,FI1),0(FI2)
- const MachineFrameInfo *MFI = MI.getParent()->getParent()->getFrameInfo();
+ const MachineFrameInfo &MFI = MI.getParent()->getParent()->getFrameInfo();
if (MI.getOpcode() != SystemZ::MVC || !MI.getOperand(0).isFI() ||
MI.getOperand(1).getImm() != 0 || !MI.getOperand(3).isFI() ||
MI.getOperand(4).getImm() != 0)
@@ -262,8 +323,8 @@ bool SystemZInstrInfo::isStackSlotCopy(const MachineInstr &MI,
int64_t Length = MI.getOperand(2).getImm();
unsigned FI1 = MI.getOperand(0).getIndex();
unsigned FI2 = MI.getOperand(3).getIndex();
- if (MFI->getObjectSize(FI1) != Length ||
- MFI->getObjectSize(FI2) != Length)
+ if (MFI.getObjectSize(FI1) != Length ||
+ MFI.getObjectSize(FI2) != Length)
return false;
DestFrameIndex = FI1;
@@ -363,7 +424,10 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-unsigned SystemZInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned SystemZInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
// Most of the code and comments here are boilerplate.
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
@@ -386,25 +450,27 @@ unsigned SystemZInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
}
bool SystemZInstrInfo::
-ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 2 && "Invalid condition");
Cond[1].setImm(Cond[1].getImm() ^ Cond[0].getImm());
return false;
}
-unsigned SystemZInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned SystemZInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// In this function we output 32-bit branches, which should always
// have enough range. They can be shortened and relaxed by later code
// in the pipeline, if desired.
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"SystemZ branch conditions have one component!");
+ assert(!BytesAdded && "code size not handled");
if (Cond.empty()) {
// Unconditional branch?
@@ -520,30 +586,128 @@ bool SystemZInstrInfo::optimizeCompareInstr(
removeIPMBasedCompare(Compare, SrcReg, MRI, &RI);
}
-// If Opcode is a move that has a conditional variant, return that variant,
-// otherwise return 0.
-static unsigned getConditionalMove(unsigned Opcode) {
- switch (Opcode) {
- case SystemZ::LR: return SystemZ::LOCR;
- case SystemZ::LGR: return SystemZ::LOCGR;
- default: return 0;
+
+bool SystemZInstrInfo::canInsertSelect(const MachineBasicBlock &MBB,
+ ArrayRef<MachineOperand> Pred,
+ unsigned TrueReg, unsigned FalseReg,
+ int &CondCycles, int &TrueCycles,
+ int &FalseCycles) const {
+ // Not all subtargets have LOCR instructions.
+ if (!STI.hasLoadStoreOnCond())
+ return false;
+ if (Pred.size() != 2)
+ return false;
+
+ // Check register classes.
+ const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+ const TargetRegisterClass *RC =
+ RI.getCommonSubClass(MRI.getRegClass(TrueReg), MRI.getRegClass(FalseReg));
+ if (!RC)
+ return false;
+
+ // We have LOCR instructions for 32 and 64 bit general purpose registers.
+ if ((STI.hasLoadStoreOnCond2() &&
+ SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) ||
+ SystemZ::GR32BitRegClass.hasSubClassEq(RC) ||
+ SystemZ::GR64BitRegClass.hasSubClassEq(RC)) {
+ CondCycles = 2;
+ TrueCycles = 2;
+ FalseCycles = 2;
+ return true;
}
+
+ // Can't do anything else.
+ return false;
}
-static unsigned getConditionalLoadImmediate(unsigned Opcode) {
- switch (Opcode) {
- case SystemZ::LHI: return SystemZ::LOCHI;
- case SystemZ::LGHI: return SystemZ::LOCGHI;
- default: return 0;
+void SystemZInstrInfo::insertSelect(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ const DebugLoc &DL, unsigned DstReg,
+ ArrayRef<MachineOperand> Pred,
+ unsigned TrueReg,
+ unsigned FalseReg) const {
+ MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+ const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
+
+ assert(Pred.size() == 2 && "Invalid condition");
+ unsigned CCValid = Pred[0].getImm();
+ unsigned CCMask = Pred[1].getImm();
+
+ unsigned Opc;
+ if (SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) {
+ if (STI.hasLoadStoreOnCond2())
+ Opc = SystemZ::LOCRMux;
+ else {
+ Opc = SystemZ::LOCR;
+ MRI.constrainRegClass(DstReg, &SystemZ::GR32BitRegClass);
+ }
+ } else if (SystemZ::GR64BitRegClass.hasSubClassEq(RC))
+ Opc = SystemZ::LOCGR;
+ else
+ llvm_unreachable("Invalid register class");
+
+ BuildMI(MBB, I, DL, get(Opc), DstReg)
+ .addReg(FalseReg).addReg(TrueReg)
+ .addImm(CCValid).addImm(CCMask);
+}
+
+bool SystemZInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
+ unsigned Reg,
+ MachineRegisterInfo *MRI) const {
+ unsigned DefOpc = DefMI.getOpcode();
+ if (DefOpc != SystemZ::LHIMux && DefOpc != SystemZ::LHI &&
+ DefOpc != SystemZ::LGHI)
+ return false;
+ if (DefMI.getOperand(0).getReg() != Reg)
+ return false;
+ int32_t ImmVal = (int32_t)DefMI.getOperand(1).getImm();
+
+ unsigned UseOpc = UseMI.getOpcode();
+ unsigned NewUseOpc;
+ unsigned UseIdx;
+ int CommuteIdx = -1;
+ switch (UseOpc) {
+ case SystemZ::LOCRMux:
+ if (!STI.hasLoadStoreOnCond2())
+ return false;
+ NewUseOpc = SystemZ::LOCHIMux;
+ if (UseMI.getOperand(2).getReg() == Reg)
+ UseIdx = 2;
+ else if (UseMI.getOperand(1).getReg() == Reg)
+ UseIdx = 2, CommuteIdx = 1;
+ else
+ return false;
+ break;
+ case SystemZ::LOCGR:
+ if (!STI.hasLoadStoreOnCond2())
+ return false;
+ NewUseOpc = SystemZ::LOCGHI;
+ if (UseMI.getOperand(2).getReg() == Reg)
+ UseIdx = 2;
+ else if (UseMI.getOperand(1).getReg() == Reg)
+ UseIdx = 2, CommuteIdx = 1;
+ else
+ return false;
+ break;
+ default:
+ return false;
}
+
+ if (CommuteIdx != -1)
+ if (!commuteInstruction(UseMI, false, CommuteIdx, UseIdx))
+ return false;
+
+ bool DeleteDef = MRI->hasOneNonDBGUse(Reg);
+ UseMI.setDesc(get(NewUseOpc));
+ UseMI.getOperand(UseIdx).ChangeToImmediate(ImmVal);
+ if (DeleteDef)
+ DefMI.eraseFromParent();
+
+ return true;
}
bool SystemZInstrInfo::isPredicable(MachineInstr &MI) const {
unsigned Opcode = MI.getOpcode();
- if (STI.hasLoadStoreOnCond() && getConditionalMove(Opcode))
- return true;
- if (STI.hasLoadStoreOnCond2() && getConditionalLoadImmediate(Opcode))
- return true;
if (Opcode == SystemZ::Return ||
Opcode == SystemZ::Trap ||
Opcode == SystemZ::CallJG ||
@@ -595,26 +759,6 @@ bool SystemZInstrInfo::PredicateInstruction(
unsigned CCMask = Pred[1].getImm();
assert(CCMask > 0 && CCMask < 15 && "Invalid predicate");
unsigned Opcode = MI.getOpcode();
- if (STI.hasLoadStoreOnCond()) {
- if (unsigned CondOpcode = getConditionalMove(Opcode)) {
- MI.setDesc(get(CondOpcode));
- MachineInstrBuilder(*MI.getParent()->getParent(), MI)
- .addImm(CCValid)
- .addImm(CCMask)
- .addReg(SystemZ::CC, RegState::Implicit);
- return true;
- }
- }
- if (STI.hasLoadStoreOnCond2()) {
- if (unsigned CondOpcode = getConditionalLoadImmediate(Opcode)) {
- MI.setDesc(get(CondOpcode));
- MachineInstrBuilder(*MI.getParent()->getParent(), MI)
- .addImm(CCValid)
- .addImm(CCMask)
- .addReg(SystemZ::CC, RegState::Implicit);
- return true;
- }
- }
if (Opcode == SystemZ::Trap) {
MI.setDesc(get(SystemZ::CondTrap));
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
@@ -690,6 +834,14 @@ void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
Opcode = SystemZ::VLR64;
else if (SystemZ::VR128BitRegClass.contains(DestReg, SrcReg))
Opcode = SystemZ::VLR;
+ else if (SystemZ::AR32BitRegClass.contains(DestReg, SrcReg))
+ Opcode = SystemZ::CPYA;
+ else if (SystemZ::AR32BitRegClass.contains(DestReg) &&
+ SystemZ::GR32BitRegClass.contains(SrcReg))
+ Opcode = SystemZ::SAR;
+ else if (SystemZ::GR32BitRegClass.contains(DestReg) &&
+ SystemZ::AR32BitRegClass.contains(SrcReg))
+ Opcode = SystemZ::EAR;
else
llvm_unreachable("Impossible reg-to-reg copy");
@@ -875,8 +1027,8 @@ MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
MachineBasicBlock::iterator InsertPt, int FrameIndex,
LiveIntervals *LIS) const {
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- unsigned Size = MFI->getObjectSize(FrameIndex);
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned Size = MFI.getObjectSize(FrameIndex);
unsigned Opcode = MI.getOpcode();
if (Ops.size() == 2 && Ops[0] == 0 && Ops[1] == 1) {
@@ -1077,6 +1229,18 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
expandRXYPseudo(MI, SystemZ::L, SystemZ::LFH);
return true;
+ case SystemZ::LOCMux:
+ expandLOCPseudo(MI, SystemZ::LOC, SystemZ::LOCFH);
+ return true;
+
+ case SystemZ::LOCHIMux:
+ expandLOCPseudo(MI, SystemZ::LOCHI, SystemZ::LOCHHI);
+ return true;
+
+ case SystemZ::LOCRMux:
+ expandLOCRPseudo(MI, SystemZ::LOCR, SystemZ::LOCFHR);
+ return true;
+
case SystemZ::STCMux:
expandRXYPseudo(MI, SystemZ::STC, SystemZ::STCH);
return true;
@@ -1089,6 +1253,10 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
expandRXYPseudo(MI, SystemZ::ST, SystemZ::STFH);
return true;
+ case SystemZ::STOCMux:
+ expandLOCPseudo(MI, SystemZ::STOC, SystemZ::STOCFH);
+ return true;
+
case SystemZ::LHIMux:
expandRIPseudo(MI, SystemZ::LHI, SystemZ::IIHF, true);
return true;
@@ -1153,6 +1321,10 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
expandRIPseudo(MI, SystemZ::AFI, SystemZ::AIH, false);
return true;
+ case SystemZ::CHIMux:
+ expandRIPseudo(MI, SystemZ::CHI, SystemZ::CIH, false);
+ return true;
+
case SystemZ::CFIMux:
expandRIPseudo(MI, SystemZ::CFI, SystemZ::CIH, false);
return true;
@@ -1194,7 +1366,7 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
}
}
-uint64_t SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
+unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
if (MI.getOpcode() == TargetOpcode::INLINEASM) {
const MachineFunction *MF = MI.getParent()->getParent();
const char *AsmStr = MI.getOperand(0).getSymbolName();
@@ -1218,6 +1390,7 @@ SystemZInstrInfo::getBranchInfo(const MachineInstr &MI) const {
MI.getOperand(1).getImm(), &MI.getOperand(2));
case SystemZ::BRCT:
+ case SystemZ::BRCTH:
return SystemZII::Branch(SystemZII::BranchCT, SystemZ::CCMASK_ICMP,
SystemZ::CCMASK_CMP_NE, &MI.getOperand(2));
@@ -1403,6 +1576,14 @@ unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode,
case SystemZ::CLGFI:
if (!(MI && isUInt<8>(MI->getOperand(1).getImm())))
return 0;
+ break;
+ case SystemZ::CL:
+ case SystemZ::CLG:
+ if (!STI.hasMiscellaneousExtensions())
+ return 0;
+ if (!(MI && MI->getOperand(3).getReg() == 0))
+ return 0;
+ break;
}
switch (Type) {
case SystemZII::CompareAndBranch:
@@ -1486,6 +1667,10 @@ unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode,
return SystemZ::CLFIT;
case SystemZ::CLGFI:
return SystemZ::CLGIT;
+ case SystemZ::CL:
+ return SystemZ::CLT;
+ case SystemZ::CLG:
+ return SystemZ::CLGT;
default:
return 0;
}
@@ -1493,6 +1678,25 @@ unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode,
return 0;
}
+unsigned SystemZInstrInfo::getLoadAndTrap(unsigned Opcode) const {
+ if (!STI.hasLoadAndTrap())
+ return 0;
+ switch (Opcode) {
+ case SystemZ::L:
+ case SystemZ::LY:
+ return SystemZ::LAT;
+ case SystemZ::LG:
+ return SystemZ::LGAT;
+ case SystemZ::LFH:
+ return SystemZ::LFHAT;
+ case SystemZ::LLGF:
+ return SystemZ::LLGFAT;
+ case SystemZ::LLGT:
+ return SystemZ::LLGTAT;
+ }
+ return 0;
+}
+
void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned Reg, uint64_t Value) const {
@@ -1511,3 +1715,38 @@ void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
}
BuildMI(MBB, MBBI, DL, get(Opcode), Reg).addImm(Value);
}
+
+bool SystemZInstrInfo::
+areMemAccessesTriviallyDisjoint(MachineInstr &MIa, MachineInstr &MIb,
+ AliasAnalysis *AA) const {
+
+ if (!MIa.hasOneMemOperand() || !MIb.hasOneMemOperand())
+ return false;
+
+ // If mem-operands show that the same address Value is used by both
+ // instructions, check for non-overlapping offsets and widths. Not
+ // sure if a register based analysis would be an improvement...
+
+ MachineMemOperand *MMOa = *MIa.memoperands_begin();
+ MachineMemOperand *MMOb = *MIb.memoperands_begin();
+ const Value *VALa = MMOa->getValue();
+ const Value *VALb = MMOb->getValue();
+ bool SameVal = (VALa && VALb && (VALa == VALb));
+ if (!SameVal) {
+ const PseudoSourceValue *PSVa = MMOa->getPseudoValue();
+ const PseudoSourceValue *PSVb = MMOb->getPseudoValue();
+ if (PSVa && PSVb && (PSVa == PSVb))
+ SameVal = true;
+ }
+ if (SameVal) {
+ int OffsetA = MMOa->getOffset(), OffsetB = MMOb->getOffset();
+ int WidthA = MMOa->getSize(), WidthB = MMOb->getSize();
+ int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB;
+ int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA;
+ int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
+ if (LowOffset + LowWidth <= HighOffset)
+ return true;
+ }
+
+ return false;
+}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 010010b..794b193 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -142,6 +142,10 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
unsigned LowOpcodeK, unsigned HighOpcode) const;
void expandRXYPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned HighOpcode) const;
+ void expandLOCPseudo(MachineInstr &MI, unsigned LowOpcode,
+ unsigned HighOpcode) const;
+ void expandLOCRPseudo(MachineInstr &MI, unsigned LowOpcode,
+ unsigned HighOpcode) const;
void expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
unsigned Size) const;
void expandLoadStackGuard(MachineInstr *MI) const;
@@ -149,7 +153,23 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
unsigned LowLowOpcode, unsigned Size, bool KillSrc) const;
virtual void anchor();
-
+
+protected:
+ /// Commutes the operands in the given instruction by changing the operands
+ /// order and/or changing the instruction's opcode and/or the immediate value
+ /// operand.
+ ///
+ /// The arguments 'CommuteOpIdx1' and 'CommuteOpIdx2' specify the operands
+ /// to be commuted.
+ ///
+ /// Do not call this method for a non-commutable instruction or
+ /// non-commutable operands.
+ /// Even though the instruction is commutable, the method may still
+ /// fail to commute the operands, null pointer is returned in such cases.
+ MachineInstr *commuteInstructionImpl(MachineInstr &MI, bool NewMI,
+ unsigned CommuteOpIdx1,
+ unsigned CommuteOpIdx2) const override;
+
public:
explicit SystemZInstrInfo(SystemZSubtarget &STI);
@@ -164,15 +184,25 @@ public:
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
unsigned &SrcReg2, int &Mask, int &Value) const override;
bool optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg,
unsigned SrcReg2, int Mask, int Value,
const MachineRegisterInfo *MRI) const override;
+ bool canInsertSelect(const MachineBasicBlock&, ArrayRef<MachineOperand> Cond,
+ unsigned, unsigned, int&, int&, int&) const override;
+ void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ const DebugLoc &DL, unsigned DstReg,
+ ArrayRef<MachineOperand> Cond, unsigned TrueReg,
+ unsigned FalseReg) const override;
+ bool FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, unsigned Reg,
+ MachineRegisterInfo *MRI) const override;
bool isPredicable(MachineInstr &MI) const override;
bool isProfitableToIfCvt(MachineBasicBlock &MBB, unsigned NumCycles,
unsigned ExtraPredCycles,
@@ -212,14 +242,14 @@ public:
MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI,
LiveIntervals *LIS = nullptr) const override;
bool expandPostRAPseudo(MachineInstr &MBBI) const override;
- bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const
+ bool reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const
override;
// Return the SystemZRegisterInfo, which this class owns.
const SystemZRegisterInfo &getRegisterInfo() const { return RI; }
// Return the size in bytes of MI.
- uint64_t getInstSizeInBytes(const MachineInstr &MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
// Return true if MI is a conditional or unconditional branch.
// When returning true, set Cond to the mask of condition-code
@@ -256,11 +286,23 @@ public:
SystemZII::FusedCompareType Type,
const MachineInstr *MI = nullptr) const;
+ // If Opcode is a LOAD opcode for with an associated LOAD AND TRAP
+ // operation exists, returh the opcode for the latter, otherwise return 0.
+ unsigned getLoadAndTrap(unsigned Opcode) const;
+
// Emit code before MBBI in MI to move immediate value Value into
// physical register Reg.
void loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned Reg, uint64_t Value) const;
+
+ // Sometimes, it is possible for the target to tell, even without
+ // aliasing information, that two MIs access different memory
+ // addresses. This function returns true if two MIs access different
+ // memory addresses and false otherwise.
+ bool
+ areMemAccessesTriviallyDisjoint(MachineInstr &MIa, MachineInstr &MIb,
+ AliasAnalysis *AA = nullptr) const override;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index c510ca7..d63525f 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -11,10 +11,12 @@
// Stack allocation
//===----------------------------------------------------------------------===//
-def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt),
- [(callseq_start timm:$amt)]>;
-def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
- [(callseq_end timm:$amt1, timm:$amt2)]>;
+let hasNoSchedulingInfo = 1 in {
+ def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt),
+ [(callseq_start timm:$amt)]>;
+ def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
+ [(callseq_end timm:$amt1, timm:$amt2)]>;
+}
let hasSideEffects = 0 in {
// Takes as input the value of the stack pointer after a dynamic allocation
@@ -29,348 +31,225 @@ let hasSideEffects = 0 in {
}
//===----------------------------------------------------------------------===//
-// Control flow instructions
+// Branch instructions
//===----------------------------------------------------------------------===//
-// A return instruction (br %r14).
-let isReturn = 1, isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in
- def Return : Alias<2, (outs), (ins), [(z_retflag)]>;
-
-// A conditional return instruction (bcr <cond>, %r14).
-let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, CCMaskFirst = 1, Uses = [CC] in
- def CondReturn : Alias<2, (outs), (ins cond4:$valid, cond4:$R1), []>;
-
-// Fused compare and conditional returns.
-let isReturn = 1, isTerminator = 1, hasCtrlDep = 1 in {
- def CRBReturn : Alias<6, (outs), (ins GR32:$R1, GR32:$R2, cond4:$M3), []>;
- def CGRBReturn : Alias<6, (outs), (ins GR64:$R1, GR64:$R2, cond4:$M3), []>;
- def CIBReturn : Alias<6, (outs), (ins GR32:$R1, imm32sx8:$I2, cond4:$M3), []>;
- def CGIBReturn : Alias<6, (outs), (ins GR64:$R1, imm64sx8:$I2, cond4:$M3), []>;
- def CLRBReturn : Alias<6, (outs), (ins GR32:$R1, GR32:$R2, cond4:$M3), []>;
- def CLGRBReturn : Alias<6, (outs), (ins GR64:$R1, GR64:$R2, cond4:$M3), []>;
- def CLIBReturn : Alias<6, (outs), (ins GR32:$R1, imm32zx8:$I2, cond4:$M3), []>;
- def CLGIBReturn : Alias<6, (outs), (ins GR64:$R1, imm64zx8:$I2, cond4:$M3), []>;
-}
-
-// Unconditional branches. R1 is the condition-code mask (all 1s).
-let isBranch = 1, isTerminator = 1, isBarrier = 1, R1 = 15 in {
- let isIndirectBranch = 1 in
- def BR : InstRR<0x07, (outs), (ins ADDR64:$R2),
- "br\t$R2", [(brind ADDR64:$R2)]>;
-
- // An assembler extended mnemonic for BRC.
- def J : InstRI<0xA74, (outs), (ins brtarget16:$I2), "j\t$I2",
- [(br bb:$I2)]>;
-
- // An assembler extended mnemonic for BRCL. (The extension is "G"
- // rather than "L" because "JL" is "Jump if Less".)
- def JG : InstRIL<0xC04, (outs), (ins brtarget32:$I2), "jg\t$I2", []>;
-}
+// Conditional branches.
+let isBranch = 1, isTerminator = 1, Uses = [CC] in {
+ // It's easier for LLVM to handle these branches in their raw BRC/BRCL form
+ // with the condition-code mask being the first operand. It seems friendlier
+ // to use mnemonic forms like JE and JLH when writing out the assembly though.
+ let isCodeGenOnly = 1 in {
+ // An assembler extended mnemonic for BRC.
+ def BRC : CondBranchRI <"j#", 0xA74, z_br_ccmask>;
+ // An assembler extended mnemonic for BRCL. (The extension is "G"
+ // rather than "L" because "JL" is "Jump if Less".)
+ def BRCL : CondBranchRIL<"jg#", 0xC04>;
+ let isIndirectBranch = 1 in {
+ def BC : CondBranchRX<"b#", 0x47>;
+ def BCR : CondBranchRR<"b#r", 0x07>;
+ }
+ }
-// FIXME: This trap instruction should be marked as isTerminator, but there is
-// currently a general bug that allows non-terminators to be placed between
-// terminators. Temporarily leave this unmarked until the bug is fixed.
-let isBarrier = 1, hasCtrlDep = 1 in {
- def Trap : Alias<4, (outs), (ins), [(trap)]>;
-}
+ // Allow using the raw forms directly from the assembler (and occasional
+ // special code generation needs) as well.
+ def BRCAsm : AsmCondBranchRI <"brc", 0xA74>;
+ def BRCLAsm : AsmCondBranchRIL<"brcl", 0xC04>;
+ let isIndirectBranch = 1 in {
+ def BCAsm : AsmCondBranchRX<"bc", 0x47>;
+ def BCRAsm : AsmCondBranchRR<"bcr", 0x07>;
+ }
-let isTerminator = 1, hasCtrlDep = 1, Uses = [CC] in {
- def CondTrap : Alias<4, (outs), (ins cond4:$valid, cond4:$R1), []>;
+ // Define AsmParser extended mnemonics for each general condition-code mask
+ // (integer or floating-point)
+ foreach V = [ "E", "NE", "H", "NH", "L", "NL", "HE", "NHE", "LE", "NLE",
+ "Z", "NZ", "P", "NP", "M", "NM", "LH", "NLH", "O", "NO" ] in {
+ def JAsm#V : FixedCondBranchRI <CV<V>, "j#", 0xA74>;
+ def JGAsm#V : FixedCondBranchRIL<CV<V>, "jg#", 0xC04>;
+ let isIndirectBranch = 1 in {
+ def BAsm#V : FixedCondBranchRX <CV<V>, "b#", 0x47>;
+ def BRAsm#V : FixedCondBranchRR <CV<V>, "b#r", 0x07>;
+ }
+ }
}
-// Conditional branches. It's easier for LLVM to handle these branches
-// in their raw BRC/BRCL form, with the 4-bit condition-code mask being
-// the first operand. It seems friendlier to use mnemonic forms like
-// JE and JLH when writing out the assembly though.
-let isBranch = 1, isTerminator = 1, Uses = [CC] in {
- let isCodeGenOnly = 1, CCMaskFirst = 1 in {
- def BRC : InstRI<0xA74, (outs), (ins cond4:$valid, cond4:$R1,
- brtarget16:$I2), "j$R1\t$I2",
- [(z_br_ccmask cond4:$valid, cond4:$R1, bb:$I2)]>;
- def BRCL : InstRIL<0xC04, (outs), (ins cond4:$valid, cond4:$R1,
- brtarget32:$I2), "jg$R1\t$I2", []>;
- let isIndirectBranch = 1 in
- def BCR : InstRR<0x07, (outs), (ins cond4:$valid, cond4:$R1, GR64:$R2),
- "b${R1}r\t$R2", []>;
- }
- def AsmBRC : InstRI<0xA74, (outs), (ins imm32zx4:$R1, brtarget16:$I2),
- "brc\t$R1, $I2", []>;
- def AsmBRCL : InstRIL<0xC04, (outs), (ins imm32zx4:$R1, brtarget32:$I2),
- "brcl\t$R1, $I2", []>;
+// Unconditional branches. These are in fact simply variants of the
+// conditional branches with the condition mask set to "always".
+let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
+ def J : FixedCondBranchRI <CondAlways, "j", 0xA74, br>;
+ def JG : FixedCondBranchRIL<CondAlways, "jg", 0xC04>;
let isIndirectBranch = 1 in {
- def AsmBC : InstRX<0x47, (outs), (ins imm32zx4:$R1, bdxaddr12only:$XBD2),
- "bc\t$R1, $XBD2", []>;
- def AsmBCR : InstRR<0x07, (outs), (ins imm32zx4:$R1, GR64:$R2),
- "bcr\t$R1, $R2", []>;
+ def B : FixedCondBranchRX<CondAlways, "b", 0x47>;
+ def BR : FixedCondBranchRR<CondAlways, "br", 0x07, brind>;
}
}
-def AsmNop : InstAlias<"nop\t$XBD", (AsmBC 0, bdxaddr12only:$XBD), 0>;
-def AsmNopR : InstAlias<"nopr\t$R", (AsmBCR 0, GR64:$R), 0>;
+// NOPs. These are again variants of the conditional branches,
+// with the condition mask set to "never".
+def NOP : InstAlias<"nop\t$XBD", (BCAsm 0, bdxaddr12only:$XBD), 0>;
+def NOPR : InstAlias<"nopr\t$R", (BCRAsm 0, GR64:$R), 0>;
-// Fused compare-and-branch instructions. As for normal branches,
-// we handle these instructions internally in their raw CRJ-like form,
-// but use assembly macros like CRJE when writing them out.
+// Fused compare-and-branch instructions.
//
// These instructions do not use or clobber the condition codes.
-// We nevertheless pretend that they clobber CC, so that we can lower
-// them to separate comparisons and BRCLs if the branch ends up being
-// out of range.
-multiclass CompareBranches<Operand ccmask, string pos1, string pos2> {
- let isBranch = 1, isTerminator = 1, Defs = [CC] in {
- def RJ : InstRIEb<0xEC76, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3,
- brtarget16:$RI4),
- "crj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>;
- def GRJ : InstRIEb<0xEC64, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3,
- brtarget16:$RI4),
- "cgrj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>;
- def IJ : InstRIEc<0xEC7E, (outs), (ins GR32:$R1, imm32sx8:$I2, ccmask:$M3,
- brtarget16:$RI4),
- "cij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>;
- def GIJ : InstRIEc<0xEC7C, (outs), (ins GR64:$R1, imm64sx8:$I2, ccmask:$M3,
- brtarget16:$RI4),
- "cgij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>;
- def LRJ : InstRIEb<0xEC77, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3,
- brtarget16:$RI4),
- "clrj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>;
- def LGRJ : InstRIEb<0xEC65, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3,
- brtarget16:$RI4),
- "clgrj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>;
- def LIJ : InstRIEc<0xEC7F, (outs), (ins GR32:$R1, imm32zx8:$I2, ccmask:$M3,
- brtarget16:$RI4),
- "clij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>;
- def LGIJ : InstRIEc<0xEC7D, (outs), (ins GR64:$R1, imm64zx8:$I2, ccmask:$M3,
- brtarget16:$RI4),
- "clgij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>;
- let isIndirectBranch = 1 in {
- def RB : InstRRS<0xECF6, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3,
- bdaddr12only:$BD4),
- "crb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>;
- def GRB : InstRRS<0xECE4, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3,
- bdaddr12only:$BD4),
- "cgrb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>;
- def IB : InstRIS<0xECFE, (outs), (ins GR32:$R1, imm32sx8:$I2, ccmask:$M3,
- bdaddr12only:$BD4),
- "cib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>;
- def GIB : InstRIS<0xECFC, (outs), (ins GR64:$R1, imm64sx8:$I2, ccmask:$M3,
- bdaddr12only:$BD4),
- "cgib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>;
- def LRB : InstRRS<0xECF7, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3,
- bdaddr12only:$BD4),
- "clrb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>;
- def LGRB : InstRRS<0xECE5, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3,
- bdaddr12only:$BD4),
- "clgrb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>;
- def LIB : InstRIS<0xECFF, (outs), (ins GR32:$R1, imm32zx8:$I2, ccmask:$M3,
- bdaddr12only:$BD4),
- "clib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>;
- def LGIB : InstRIS<0xECFD, (outs), (ins GR64:$R1, imm64zx8:$I2, ccmask:$M3,
- bdaddr12only:$BD4),
- "clgib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>;
- }
+// We nevertheless pretend that the relative compare-and-branch
+// instructions clobber CC, so that we can lower them to separate
+// comparisons and BRCLs if the branch ends up being out of range.
+let isBranch = 1, isTerminator = 1 in {
+ // As for normal branches, we handle these instructions internally in
+ // their raw CRJ-like form, but use assembly macros like CRJE when writing
+ // them out. Using the *Pair multiclasses, we also create the raw forms.
+ let Defs = [CC] in {
+ defm CRJ : CmpBranchRIEbPair<"crj", 0xEC76, GR32>;
+ defm CGRJ : CmpBranchRIEbPair<"cgrj", 0xEC64, GR64>;
+ defm CIJ : CmpBranchRIEcPair<"cij", 0xEC7E, GR32, imm32sx8>;
+ defm CGIJ : CmpBranchRIEcPair<"cgij", 0xEC7C, GR64, imm64sx8>;
+ defm CLRJ : CmpBranchRIEbPair<"clrj", 0xEC77, GR32>;
+ defm CLGRJ : CmpBranchRIEbPair<"clgrj", 0xEC65, GR64>;
+ defm CLIJ : CmpBranchRIEcPair<"clij", 0xEC7F, GR32, imm32zx8>;
+ defm CLGIJ : CmpBranchRIEcPair<"clgij", 0xEC7D, GR64, imm64zx8>;
}
-
- let isTerminator = 1, hasCtrlDep = 1 in {
- def RT : InstRRFc<0xB972, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3),
- "crt"##pos1##"\t$R1, $R2"##pos2, []>;
- def GRT : InstRRFc<0xB960, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3),
- "cgrt"##pos1##"\t$R1, $R2"##pos2, []>;
- def LRT : InstRRFc<0xB973, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3),
- "clrt"##pos1##"\t$R1, $R2"##pos2, []>;
- def LGRT : InstRRFc<0xB961, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3),
- "clgrt"##pos1##"\t$R1, $R2"##pos2, []>;
- def IT : InstRIEa<0xEC72, (outs), (ins GR32:$R1, imm32sx16:$I2, ccmask:$M3),
- "cit"##pos1##"\t$R1, $I2"##pos2, []>;
- def GIT : InstRIEa<0xEC70, (outs), (ins GR64:$R1, imm32sx16:$I2, ccmask:$M3),
- "cgit"##pos1##"\t$R1, $I2"##pos2, []>;
- def LFIT : InstRIEa<0xEC73, (outs), (ins GR32:$R1, imm32zx16:$I2, ccmask:$M3),
- "clfit"##pos1##"\t$R1, $I2"##pos2, []>;
- def LGIT : InstRIEa<0xEC71, (outs), (ins GR64:$R1, imm32zx16:$I2, ccmask:$M3),
- "clgit"##pos1##"\t$R1, $I2"##pos2, []>;
- }
-}
-let isCodeGenOnly = 1 in
- defm C : CompareBranches<cond4, "$M3", "">;
-defm AsmC : CompareBranches<imm32zx4, "", ", $M3">;
-
-// Define AsmParser mnemonics for each general condition-code mask
-// (integer or floating-point)
-multiclass CondExtendedMnemonicA<bits<4> ccmask, string name> {
- let isBranch = 1, isTerminator = 1, R1 = ccmask in {
- def J : InstRI<0xA74, (outs), (ins brtarget16:$I2),
- "j"##name##"\t$I2", []>;
- def JG : InstRIL<0xC04, (outs), (ins brtarget32:$I2),
- "jg"##name##"\t$I2", []>;
- def BR : InstRR<0x07, (outs), (ins ADDR64:$R2), "b"##name##"r\t$R2", []>;
+ let isIndirectBranch = 1 in {
+ defm CRB : CmpBranchRRSPair<"crb", 0xECF6, GR32>;
+ defm CGRB : CmpBranchRRSPair<"cgrb", 0xECE4, GR64>;
+ defm CIB : CmpBranchRISPair<"cib", 0xECFE, GR32, imm32sx8>;
+ defm CGIB : CmpBranchRISPair<"cgib", 0xECFC, GR64, imm64sx8>;
+ defm CLRB : CmpBranchRRSPair<"clrb", 0xECF7, GR32>;
+ defm CLGRB : CmpBranchRRSPair<"clgrb", 0xECE5, GR64>;
+ defm CLIB : CmpBranchRISPair<"clib", 0xECFF, GR32, imm32zx8>;
+ defm CLGIB : CmpBranchRISPair<"clgib", 0xECFD, GR64, imm64zx8>;
}
- def LOCR : FixedCondUnaryRRF<"locr"##name, 0xB9F2, GR32, GR32, ccmask>;
- def LOCGR : FixedCondUnaryRRF<"locgr"##name, 0xB9E2, GR64, GR64, ccmask>;
- def LOCHI : FixedCondUnaryRIE<"lochi"##name, 0xEC42, GR64, imm32sx16,
- ccmask>;
- def LOCGHI: FixedCondUnaryRIE<"locghi"##name, 0xEC46, GR64, imm64sx16,
- ccmask>;
- def LOC : FixedCondUnaryRSY<"loc"##name, 0xEBF2, GR32, ccmask, 4>;
- def LOCG : FixedCondUnaryRSY<"locg"##name, 0xEBE2, GR64, ccmask, 8>;
- def STOC : FixedCondStoreRSY<"stoc"##name, 0xEBF3, GR32, ccmask, 4>;
- def STOCG : FixedCondStoreRSY<"stocg"##name, 0xEBE3, GR64, ccmask, 8>;
-}
-
-multiclass CondExtendedMnemonic<bits<4> ccmask, string name1, string name2>
- : CondExtendedMnemonicA<ccmask, name1> {
- let isAsmParserOnly = 1 in
- defm Alt : CondExtendedMnemonicA<ccmask, name2>;
-}
-
-defm AsmO : CondExtendedMnemonicA<1, "o">;
-defm AsmH : CondExtendedMnemonic<2, "h", "p">;
-defm AsmNLE : CondExtendedMnemonicA<3, "nle">;
-defm AsmL : CondExtendedMnemonic<4, "l", "m">;
-defm AsmNHE : CondExtendedMnemonicA<5, "nhe">;
-defm AsmLH : CondExtendedMnemonicA<6, "lh">;
-defm AsmNE : CondExtendedMnemonic<7, "ne", "nz">;
-defm AsmE : CondExtendedMnemonic<8, "e", "z">;
-defm AsmNLH : CondExtendedMnemonicA<9, "nlh">;
-defm AsmHE : CondExtendedMnemonicA<10, "he">;
-defm AsmNL : CondExtendedMnemonic<11, "nl", "nm">;
-defm AsmLE : CondExtendedMnemonicA<12, "le">;
-defm AsmNH : CondExtendedMnemonic<13, "nh", "np">;
-defm AsmNO : CondExtendedMnemonicA<14, "no">;
-
-// Define AsmParser mnemonics for each integer condition-code mask.
-// This is like the list above, except that condition 3 is not possible
-// and that the low bit of the mask is therefore always 0. This means
-// that each condition has two names. Conditions "o" and "no" are not used.
-//
-// We don't make one of the two names an alias of the other because
-// we need the custom parsing routines to select the correct register class.
-multiclass IntCondExtendedMnemonicA<bits<4> ccmask, string name> {
- let isBranch = 1, isTerminator = 1, M3 = ccmask in {
- def CRJ : InstRIEb<0xEC76, (outs), (ins GR32:$R1, GR32:$R2,
- brtarget16:$RI4),
- "crj"##name##"\t$R1, $R2, $RI4", []>;
- def CGRJ : InstRIEb<0xEC64, (outs), (ins GR64:$R1, GR64:$R2,
- brtarget16:$RI4),
- "cgrj"##name##"\t$R1, $R2, $RI4", []>;
- def CIJ : InstRIEc<0xEC7E, (outs), (ins GR32:$R1, imm32sx8:$I2,
- brtarget16:$RI4),
- "cij"##name##"\t$R1, $I2, $RI4", []>;
- def CGIJ : InstRIEc<0xEC7C, (outs), (ins GR64:$R1, imm64sx8:$I2,
- brtarget16:$RI4),
- "cgij"##name##"\t$R1, $I2, $RI4", []>;
- def CLRJ : InstRIEb<0xEC77, (outs), (ins GR32:$R1, GR32:$R2,
- brtarget16:$RI4),
- "clrj"##name##"\t$R1, $R2, $RI4", []>;
- def CLGRJ : InstRIEb<0xEC65, (outs), (ins GR64:$R1, GR64:$R2,
- brtarget16:$RI4),
- "clgrj"##name##"\t$R1, $R2, $RI4", []>;
- def CLIJ : InstRIEc<0xEC7F, (outs), (ins GR32:$R1, imm32zx8:$I2,
- brtarget16:$RI4),
- "clij"##name##"\t$R1, $I2, $RI4", []>;
- def CLGIJ : InstRIEc<0xEC7D, (outs), (ins GR64:$R1, imm64zx8:$I2,
- brtarget16:$RI4),
- "clgij"##name##"\t$R1, $I2, $RI4", []>;
+
+ // Define AsmParser mnemonics for each integer condition-code mask.
+ foreach V = [ "E", "H", "L", "HE", "LE", "LH",
+ "NE", "NH", "NL", "NHE", "NLE", "NLH" ] in {
+ let Defs = [CC] in {
+ def CRJAsm#V : FixedCmpBranchRIEb<ICV<V>, "crj", 0xEC76, GR32>;
+ def CGRJAsm#V : FixedCmpBranchRIEb<ICV<V>, "cgrj", 0xEC64, GR64>;
+ def CIJAsm#V : FixedCmpBranchRIEc<ICV<V>, "cij", 0xEC7E, GR32,
+ imm32sx8>;
+ def CGIJAsm#V : FixedCmpBranchRIEc<ICV<V>, "cgij", 0xEC7C, GR64,
+ imm64sx8>;
+ def CLRJAsm#V : FixedCmpBranchRIEb<ICV<V>, "clrj", 0xEC77, GR32>;
+ def CLGRJAsm#V : FixedCmpBranchRIEb<ICV<V>, "clgrj", 0xEC65, GR64>;
+ def CLIJAsm#V : FixedCmpBranchRIEc<ICV<V>, "clij", 0xEC7F, GR32,
+ imm32zx8>;
+ def CLGIJAsm#V : FixedCmpBranchRIEc<ICV<V>, "clgij", 0xEC7D, GR64,
+ imm64zx8>;
+ }
let isIndirectBranch = 1 in {
- def CRB : InstRRS<0xECF6, (outs), (ins GR32:$R1, GR32:$R2,
- bdaddr12only:$BD4),
- "crb"##name##"\t$R1, $R2, $BD4", []>;
- def CGRB : InstRRS<0xECE4, (outs), (ins GR64:$R1, GR64:$R2,
- bdaddr12only:$BD4),
- "cgrb"##name##"\t$R1, $R2, $BD4", []>;
- def CIB : InstRIS<0xECFE, (outs), (ins GR32:$R1, imm32sx8:$I2,
- bdaddr12only:$BD4),
- "cib"##name##"\t$R1, $I2, $BD4", []>;
- def CGIB : InstRIS<0xECFC, (outs), (ins GR64:$R1, imm64sx8:$I2,
- bdaddr12only:$BD4),
- "cgib"##name##"\t$R1, $I2, $BD4", []>;
- def CLRB : InstRRS<0xECF7, (outs), (ins GR32:$R1, GR32:$R2,
- bdaddr12only:$BD4),
- "clrb"##name##"\t$R1, $R2, $BD4", []>;
- def CLGRB : InstRRS<0xECE5, (outs), (ins GR64:$R1, GR64:$R2,
- bdaddr12only:$BD4),
- "clgrb"##name##"\t$R1, $R2, $BD4", []>;
- def CLIB : InstRIS<0xECFF, (outs), (ins GR32:$R1, imm32zx8:$I2,
- bdaddr12only:$BD4),
- "clib"##name##"\t$R1, $I2, $BD4", []>;
- def CLGIB : InstRIS<0xECFD, (outs), (ins GR64:$R1, imm64zx8:$I2,
- bdaddr12only:$BD4),
- "clgib"##name##"\t$R1, $I2, $BD4", []>;
+ def CRBAsm#V : FixedCmpBranchRRS<ICV<V>, "crb", 0xECF6, GR32>;
+ def CGRBAsm#V : FixedCmpBranchRRS<ICV<V>, "cgrb", 0xECE4, GR64>;
+ def CIBAsm#V : FixedCmpBranchRIS<ICV<V>, "cib", 0xECFE, GR32,
+ imm32sx8>;
+ def CGIBAsm#V : FixedCmpBranchRIS<ICV<V>, "cgib", 0xECFC, GR64,
+ imm64sx8>;
+ def CLRBAsm#V : FixedCmpBranchRRS<ICV<V>, "clrb", 0xECF7, GR32>;
+ def CLGRBAsm#V : FixedCmpBranchRRS<ICV<V>, "clgrb", 0xECE5, GR64>;
+ def CLIBAsm#V : FixedCmpBranchRIS<ICV<V>, "clib", 0xECFF, GR32,
+ imm32zx8>;
+ def CLGIBAsm#V : FixedCmpBranchRIS<ICV<V>, "clgib", 0xECFD, GR64,
+ imm64zx8>;
}
}
+}
- let hasCtrlDep = 1, isTerminator = 1, M3 = ccmask in {
- def CRT : InstRRFc<0xB972, (outs), (ins GR32:$R1, GR32:$R2),
- "crt"##name##"\t$R1, $R2", []>;
- def CGRT : InstRRFc<0xB960, (outs), (ins GR64:$R1, GR64:$R2),
- "cgrt"##name##"\t$R1, $R2", []>;
- def CLRT : InstRRFc<0xB973, (outs), (ins GR32:$R1, GR32:$R2),
- "clrt"##name##"\t$R1, $R2", []>;
- def CLGRT : InstRRFc<0xB961, (outs), (ins GR64:$R1, GR64:$R2),
- "clgrt"##name##"\t$R1, $R2", []>;
- def CIT : InstRIEa<0xEC72, (outs), (ins GR32:$R1, imm32sx16:$I2),
- "cit"##name##"\t$R1, $I2", []>;
- def CGIT : InstRIEa<0xEC70, (outs), (ins GR64:$R1, imm32sx16:$I2),
- "cgit"##name##"\t$R1, $I2", []>;
- def CLFIT : InstRIEa<0xEC73, (outs), (ins GR32:$R1, imm32zx16:$I2),
- "clfit"##name##"\t$R1, $I2", []>;
- def CLGIT : InstRIEa<0xEC71, (outs), (ins GR64:$R1, imm32zx16:$I2),
- "clgit"##name##"\t$R1, $I2", []>;
+// Decrement a register and branch if it is nonzero. These don't clobber CC,
+// but we might need to split long relative branches into sequences that do.
+let isBranch = 1, isTerminator = 1 in {
+ let Defs = [CC] in {
+ def BRCT : BranchUnaryRI<"brct", 0xA76, GR32>;
+ def BRCTG : BranchUnaryRI<"brctg", 0xA77, GR64>;
}
+ // This doesn't need to clobber CC since we never need to split it.
+ def BRCTH : BranchUnaryRIL<"brcth", 0xCC6, GRH32>,
+ Requires<[FeatureHighWord]>;
+
+ def BCT : BranchUnaryRX<"bct", 0x46,GR32>;
+ def BCTR : BranchUnaryRR<"bctr", 0x06, GR32>;
+ def BCTG : BranchUnaryRXY<"bctg", 0xE346, GR64>;
+ def BCTGR : BranchUnaryRRE<"bctgr", 0xB946, GR64>;
}
-multiclass IntCondExtendedMnemonic<bits<4> ccmask, string name1, string name2>
- : IntCondExtendedMnemonicA<ccmask, name1> {
- let isAsmParserOnly = 1 in
- defm Alt : IntCondExtendedMnemonicA<ccmask, name2>;
-}
-defm AsmJH : IntCondExtendedMnemonic<2, "h", "nle">;
-defm AsmJL : IntCondExtendedMnemonic<4, "l", "nhe">;
-defm AsmJLH : IntCondExtendedMnemonic<6, "lh", "ne">;
-defm AsmJE : IntCondExtendedMnemonic<8, "e", "nlh">;
-defm AsmJHE : IntCondExtendedMnemonic<10, "he", "nl">;
-defm AsmJLE : IntCondExtendedMnemonic<12, "le", "nh">;
-// Decrement a register and branch if it is nonzero. These don't clobber CC,
-// but we might need to split long branches into sequences that do.
-let Defs = [CC] in {
- def BRCT : BranchUnaryRI<"brct", 0xA76, GR32>;
- def BRCTG : BranchUnaryRI<"brctg", 0xA77, GR64>;
+let isBranch = 1, isTerminator = 1 in {
+ let Defs = [CC] in {
+ def BRXH : BranchBinaryRSI<"brxh", 0x84, GR32>;
+ def BRXLE : BranchBinaryRSI<"brxle", 0x85, GR32>;
+ def BRXHG : BranchBinaryRIEe<"brxhg", 0xEC44, GR64>;
+ def BRXLG : BranchBinaryRIEe<"brxlg", 0xEC45, GR64>;
+ }
+ def BXH : BranchBinaryRS<"bxh", 0x86, GR32>;
+ def BXLE : BranchBinaryRS<"bxle", 0x87, GR32>;
+ def BXHG : BranchBinaryRSY<"bxhg", 0xEB44, GR64>;
+ def BXLEG : BranchBinaryRSY<"bxleg", 0xEB45, GR64>;
}
//===----------------------------------------------------------------------===//
-// Select instructions
+// Trap instructions
//===----------------------------------------------------------------------===//
-def Select32Mux : SelectWrapper<GRX32>, Requires<[FeatureHighWord]>;
-def Select32 : SelectWrapper<GR32>;
-def Select64 : SelectWrapper<GR64>;
+// Unconditional trap.
+// FIXME: This trap instruction should be marked as isTerminator, but there is
+// currently a general bug that allows non-terminators to be placed between
+// terminators. Temporarily leave this unmarked until the bug is fixed.
+let isBarrier = 1, hasCtrlDep = 1 in
+ def Trap : Alias<4, (outs), (ins), [(trap)]>;
-// We don't define 32-bit Mux stores because the low-only STOC should
-// always be used if possible.
-defm CondStore8Mux : CondStores<GRX32, nonvolatile_truncstorei8,
- nonvolatile_anyextloadi8, bdxaddr20only>,
- Requires<[FeatureHighWord]>;
-defm CondStore16Mux : CondStores<GRX32, nonvolatile_truncstorei16,
- nonvolatile_anyextloadi16, bdxaddr20only>,
- Requires<[FeatureHighWord]>;
-defm CondStore8 : CondStores<GR32, nonvolatile_truncstorei8,
- nonvolatile_anyextloadi8, bdxaddr20only>;
-defm CondStore16 : CondStores<GR32, nonvolatile_truncstorei16,
- nonvolatile_anyextloadi16, bdxaddr20only>;
-defm CondStore32 : CondStores<GR32, nonvolatile_store,
- nonvolatile_load, bdxaddr20only>;
+// Conditional trap.
+let isTerminator = 1, hasCtrlDep = 1, Uses = [CC] in
+ def CondTrap : Alias<4, (outs), (ins cond4:$valid, cond4:$R1), []>;
-defm : CondStores64<CondStore8, CondStore8Inv, nonvolatile_truncstorei8,
- nonvolatile_anyextloadi8, bdxaddr20only>;
-defm : CondStores64<CondStore16, CondStore16Inv, nonvolatile_truncstorei16,
- nonvolatile_anyextloadi16, bdxaddr20only>;
-defm : CondStores64<CondStore32, CondStore32Inv, nonvolatile_truncstorei32,
- nonvolatile_anyextloadi32, bdxaddr20only>;
-defm CondStore64 : CondStores<GR64, nonvolatile_store,
- nonvolatile_load, bdxaddr20only>;
+// Fused compare-and-trap instructions.
+let isTerminator = 1, hasCtrlDep = 1 in {
+ // These patterns work the same way as for compare-and-branch.
+ defm CRT : CmpBranchRRFcPair<"crt", 0xB972, GR32>;
+ defm CGRT : CmpBranchRRFcPair<"cgrt", 0xB960, GR64>;
+ defm CLRT : CmpBranchRRFcPair<"clrt", 0xB973, GR32>;
+ defm CLGRT : CmpBranchRRFcPair<"clgrt", 0xB961, GR64>;
+ defm CIT : CmpBranchRIEaPair<"cit", 0xEC72, GR32, imm32sx16>;
+ defm CGIT : CmpBranchRIEaPair<"cgit", 0xEC70, GR64, imm64sx16>;
+ defm CLFIT : CmpBranchRIEaPair<"clfit", 0xEC73, GR32, imm32zx16>;
+ defm CLGIT : CmpBranchRIEaPair<"clgit", 0xEC71, GR64, imm64zx16>;
+ let Predicates = [FeatureMiscellaneousExtensions] in {
+ defm CLT : CmpBranchRSYbPair<"clt", 0xEB23, GR32>;
+ defm CLGT : CmpBranchRSYbPair<"clgt", 0xEB2B, GR64>;
+ }
+
+ foreach V = [ "E", "H", "L", "HE", "LE", "LH",
+ "NE", "NH", "NL", "NHE", "NLE", "NLH" ] in {
+ def CRTAsm#V : FixedCmpBranchRRFc<ICV<V>, "crt", 0xB972, GR32>;
+ def CGRTAsm#V : FixedCmpBranchRRFc<ICV<V>, "cgrt", 0xB960, GR64>;
+ def CLRTAsm#V : FixedCmpBranchRRFc<ICV<V>, "clrt", 0xB973, GR32>;
+ def CLGRTAsm#V : FixedCmpBranchRRFc<ICV<V>, "clgrt", 0xB961, GR64>;
+ def CITAsm#V : FixedCmpBranchRIEa<ICV<V>, "cit", 0xEC72, GR32,
+ imm32sx16>;
+ def CGITAsm#V : FixedCmpBranchRIEa<ICV<V>, "cgit", 0xEC70, GR64,
+ imm64sx16>;
+ def CLFITAsm#V : FixedCmpBranchRIEa<ICV<V>, "clfit", 0xEC73, GR32,
+ imm32zx16>;
+ def CLGITAsm#V : FixedCmpBranchRIEa<ICV<V>, "clgit", 0xEC71, GR64,
+ imm64zx16>;
+ let Predicates = [FeatureMiscellaneousExtensions] in {
+ def CLTAsm#V : FixedCmpBranchRSYb<ICV<V>, "clt", 0xEB23, GR32>;
+ def CLGTAsm#V : FixedCmpBranchRSYb<ICV<V>, "clgt", 0xEB2B, GR64>;
+ }
+ }
+}
//===----------------------------------------------------------------------===//
-// Call instructions
+// Call and return instructions
//===----------------------------------------------------------------------===//
+// Define the general form of the call instructions for the asm parser.
+// These instructions don't hard-code %r14 as the return address register.
+let isCall = 1, Defs = [CC] in {
+ def BRAS : CallRI <"bras", 0xA75>;
+ def BRASL : CallRIL<"brasl", 0xC05>;
+ def BAS : CallRX <"bas", 0x4D>;
+ def BASR : CallRR <"basr", 0x0D>;
+}
+
+// Regular calls.
let isCall = 1, Defs = [R14D, CC] in {
def CallBRASL : Alias<6, (outs), (ins pcrel32:$I2, variable_ops),
[(z_call pcrel32:$I2)]>;
@@ -378,6 +257,15 @@ let isCall = 1, Defs = [R14D, CC] in {
[(z_call ADDR64:$R2)]>;
}
+// TLS calls. These will be lowered into a call to __tls_get_offset,
+// with an extra relocation specifying the TLS symbol.
+let isCall = 1, Defs = [R14D, CC] in {
+ def TLS_GDCALL : Alias<6, (outs), (ins tlssym:$I2, variable_ops),
+ [(z_tls_gdcall tglobaltlsaddr:$I2)]>;
+ def TLS_LDCALL : Alias<6, (outs), (ins tlssym:$I2, variable_ops),
+ [(z_tls_ldcall tglobaltlsaddr:$I2)]>;
+}
+
// Sibling calls. Indirect sibling calls must be via R1, since R2 upwards
// are argument registers and since branching to R0 is a no-op.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in {
@@ -387,10 +275,10 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in {
def CallBR : Alias<2, (outs), (ins), [(z_sibcall R1D)]>;
}
+// Conditional sibling calls.
let CCMaskFirst = 1, isCall = 1, isTerminator = 1, isReturn = 1 in {
def CallBRCL : Alias<6, (outs), (ins cond4:$valid, cond4:$R1,
pcrel32:$I2), []>;
-
let Uses = [R1D] in
def CallBCR : Alias<2, (outs), (ins cond4:$valid, cond4:$R1), []>;
}
@@ -407,60 +295,76 @@ let isCall = 1, isTerminator = 1, isReturn = 1, Uses = [R1D] in {
def CLGIBCall : Alias<6, (outs), (ins GR64:$R1, imm64zx8:$I2, cond4:$M3), []>;
}
-// TLS calls. These will be lowered into a call to __tls_get_offset,
-// with an extra relocation specifying the TLS symbol.
-let isCall = 1, Defs = [R14D, CC] in {
- def TLS_GDCALL : Alias<6, (outs), (ins tlssym:$I2, variable_ops),
- [(z_tls_gdcall tglobaltlsaddr:$I2)]>;
- def TLS_LDCALL : Alias<6, (outs), (ins tlssym:$I2, variable_ops),
- [(z_tls_ldcall tglobaltlsaddr:$I2)]>;
-}
+// A return instruction (br %r14).
+let isReturn = 1, isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in
+ def Return : Alias<2, (outs), (ins), [(z_retflag)]>;
-// Define the general form of the call instructions for the asm parser.
-// These instructions don't hard-code %r14 as the return address register.
-// Allow an optional TLS marker symbol to generate TLS call relocations.
-let isCall = 1, Defs = [CC] in {
- def BRAS : InstRI<0xA75, (outs), (ins GR64:$R1, brtarget16tls:$I2),
- "bras\t$R1, $I2", []>;
- def BRASL : InstRIL<0xC05, (outs), (ins GR64:$R1, brtarget32tls:$I2),
- "brasl\t$R1, $I2", []>;
- def BASR : InstRR<0x0D, (outs), (ins GR64:$R1, ADDR64:$R2),
- "basr\t$R1, $R2", []>;
+// A conditional return instruction (bcr <cond>, %r14).
+let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, CCMaskFirst = 1, Uses = [CC] in
+ def CondReturn : Alias<2, (outs), (ins cond4:$valid, cond4:$R1), []>;
+
+// Fused compare and conditional returns.
+let isReturn = 1, isTerminator = 1, hasCtrlDep = 1 in {
+ def CRBReturn : Alias<6, (outs), (ins GR32:$R1, GR32:$R2, cond4:$M3), []>;
+ def CGRBReturn : Alias<6, (outs), (ins GR64:$R1, GR64:$R2, cond4:$M3), []>;
+ def CIBReturn : Alias<6, (outs), (ins GR32:$R1, imm32sx8:$I2, cond4:$M3), []>;
+ def CGIBReturn : Alias<6, (outs), (ins GR64:$R1, imm64sx8:$I2, cond4:$M3), []>;
+ def CLRBReturn : Alias<6, (outs), (ins GR32:$R1, GR32:$R2, cond4:$M3), []>;
+ def CLGRBReturn : Alias<6, (outs), (ins GR64:$R1, GR64:$R2, cond4:$M3), []>;
+ def CLIBReturn : Alias<6, (outs), (ins GR32:$R1, imm32zx8:$I2, cond4:$M3), []>;
+ def CLGIBReturn : Alias<6, (outs), (ins GR64:$R1, imm64zx8:$I2, cond4:$M3), []>;
}
//===----------------------------------------------------------------------===//
+// Select instructions
+//===----------------------------------------------------------------------===//
+
+def Select32Mux : SelectWrapper<GRX32>, Requires<[FeatureHighWord]>;
+def Select32 : SelectWrapper<GR32>;
+def Select64 : SelectWrapper<GR64>;
+
+// We don't define 32-bit Mux stores if we don't have STOCFH, because the
+// low-only STOC should then always be used if possible.
+defm CondStore8Mux : CondStores<GRX32, nonvolatile_truncstorei8,
+ nonvolatile_anyextloadi8, bdxaddr20only>,
+ Requires<[FeatureHighWord]>;
+defm CondStore16Mux : CondStores<GRX32, nonvolatile_truncstorei16,
+ nonvolatile_anyextloadi16, bdxaddr20only>,
+ Requires<[FeatureHighWord]>;
+defm CondStore32Mux : CondStores<GRX32, nonvolatile_store,
+ nonvolatile_load, bdxaddr20only>,
+ Requires<[FeatureLoadStoreOnCond2]>;
+defm CondStore8 : CondStores<GR32, nonvolatile_truncstorei8,
+ nonvolatile_anyextloadi8, bdxaddr20only>;
+defm CondStore16 : CondStores<GR32, nonvolatile_truncstorei16,
+ nonvolatile_anyextloadi16, bdxaddr20only>;
+defm CondStore32 : CondStores<GR32, nonvolatile_store,
+ nonvolatile_load, bdxaddr20only>;
+
+defm : CondStores64<CondStore8, CondStore8Inv, nonvolatile_truncstorei8,
+ nonvolatile_anyextloadi8, bdxaddr20only>;
+defm : CondStores64<CondStore16, CondStore16Inv, nonvolatile_truncstorei16,
+ nonvolatile_anyextloadi16, bdxaddr20only>;
+defm : CondStores64<CondStore32, CondStore32Inv, nonvolatile_truncstorei32,
+ nonvolatile_anyextloadi32, bdxaddr20only>;
+defm CondStore64 : CondStores<GR64, nonvolatile_store,
+ nonvolatile_load, bdxaddr20only>;
+
+//===----------------------------------------------------------------------===//
// Move instructions
//===----------------------------------------------------------------------===//
// Register moves.
let hasSideEffects = 0 in {
// Expands to LR, RISBHG or RISBLG, depending on the choice of registers.
- def LRMux : UnaryRRPseudo<"l", null_frag, GRX32, GRX32>,
+ def LRMux : UnaryRRPseudo<"lr", null_frag, GRX32, GRX32>,
Requires<[FeatureHighWord]>;
- def LR : UnaryRR <"l", 0x18, null_frag, GR32, GR32>;
- def LGR : UnaryRRE<"lg", 0xB904, null_frag, GR64, GR64>;
+ def LR : UnaryRR <"lr", 0x18, null_frag, GR32, GR32>;
+ def LGR : UnaryRRE<"lgr", 0xB904, null_frag, GR64, GR64>;
}
let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in {
- def LTR : UnaryRR <"lt", 0x12, null_frag, GR32, GR32>;
- def LTGR : UnaryRRE<"ltg", 0xB902, null_frag, GR64, GR64>;
-}
-
-// Move on condition.
-let isCodeGenOnly = 1, Uses = [CC] in {
- def LOCR : CondUnaryRRF<"loc", 0xB9F2, GR32, GR32>;
- def LOCGR : CondUnaryRRF<"locg", 0xB9E2, GR64, GR64>;
-}
-let Uses = [CC] in {
- def AsmLOCR : AsmCondUnaryRRF<"loc", 0xB9F2, GR32, GR32>;
- def AsmLOCGR : AsmCondUnaryRRF<"locg", 0xB9E2, GR64, GR64>;
-}
-let isCodeGenOnly = 1, Uses = [CC] in {
- def LOCHI : CondUnaryRIE<"lochi", 0xEC42, GR32, imm32sx16>;
- def LOCGHI : CondUnaryRIE<"locghi", 0xEC46, GR64, imm64sx16>;
-}
-let Uses = [CC] in {
- def AsmLOCHI : AsmCondUnaryRIE<"lochi", 0xEC42, GR32, imm32sx16>;
- def AsmLOCGHI : AsmCondUnaryRIE<"locghi", 0xEC46, GR64, imm64sx16>;
+ def LTR : UnaryRR <"ltr", 0x12, null_frag, GR32, GR32>;
+ def LTGR : UnaryRRE<"ltgr", 0xB902, null_frag, GR64, GR64>;
}
// Immediate moves.
@@ -512,14 +416,21 @@ let canFoldAsLoad = 1 in {
def LGRL : UnaryRILPC<"lgrl", 0xC48, aligned_load, GR64>;
}
-// Load on condition.
-let isCodeGenOnly = 1, Uses = [CC] in {
- def LOC : CondUnaryRSY<"loc", 0xEBF2, nonvolatile_load, GR32, 4>;
- def LOCG : CondUnaryRSY<"locg", 0xEBE2, nonvolatile_load, GR64, 8>;
+// Load and zero rightmost byte.
+let Predicates = [FeatureLoadAndZeroRightmostByte] in {
+ def LZRF : UnaryRXY<"lzrf", 0xE33B, null_frag, GR32, 4>;
+ def LZRG : UnaryRXY<"lzrg", 0xE32A, null_frag, GR64, 8>;
+ def : Pat<(and (i32 (load bdxaddr20only:$src)), 0xffffff00),
+ (LZRF bdxaddr20only:$src)>;
+ def : Pat<(and (i64 (load bdxaddr20only:$src)), 0xffffffffffffff00),
+ (LZRG bdxaddr20only:$src)>;
}
-let Uses = [CC] in {
- def AsmLOC : AsmCondUnaryRSY<"loc", 0xEBF2, GR32, 4>;
- def AsmLOCG : AsmCondUnaryRSY<"locg", 0xEBE2, GR64, 8>;
+
+// Load and trap.
+let Predicates = [FeatureLoadAndTrap] in {
+ def LAT : UnaryRXY<"lat", 0xE39F, null_frag, GR32, 4>;
+ def LFHAT : UnaryRXY<"lfhat", 0xE3C8, null_frag, GRH32, 4>;
+ def LGAT : UnaryRXY<"lgat", 0xE385, null_frag, GR64, 8>;
}
// Register stores.
@@ -542,16 +453,6 @@ let SimpleBDXStore = 1 in {
def STRL : StoreRILPC<"strl", 0xC4F, aligned_store, GR32>;
def STGRL : StoreRILPC<"stgrl", 0xC4B, aligned_store, GR64>;
-// Store on condition.
-let isCodeGenOnly = 1, Uses = [CC] in {
- def STOC : CondStoreRSY<"stoc", 0xEBF3, GR32, 4>;
- def STOCG : CondStoreRSY<"stocg", 0xEBE3, GR64, 8>;
-}
-let Uses = [CC] in {
- def AsmSTOC : AsmCondStoreRSY<"stoc", 0xEBF3, GR32, 4>;
- def AsmSTOCG : AsmCondStoreRSY<"stocg", 0xEBE3, GR64, 8>;
-}
-
// 8-bit immediate stores to 8-bit fields.
defm MVI : StoreSIPair<"mvi", 0x92, 0xEB52, truncstorei8, imm32zx8trunc>;
@@ -569,6 +470,82 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in
defm MVST : StringRRE<"mvst", 0xB255, z_stpcpy>;
//===----------------------------------------------------------------------===//
+// Conditional move instructions
+//===----------------------------------------------------------------------===//
+
+let Predicates = [FeatureLoadStoreOnCond2], Uses = [CC] in {
+ // Load immediate on condition. Matched via DAG pattern and created
+ // by the PeepholeOptimizer via FoldImmediate.
+ let hasSideEffects = 0 in {
+ // Expands to LOCHI or LOCHHI, depending on the choice of register.
+ def LOCHIMux : CondBinaryRIEPseudo<GRX32, imm32sx16>;
+ defm LOCHHI : CondBinaryRIEPair<"lochhi", 0xEC4E, GRH32, imm32sx16>;
+ defm LOCHI : CondBinaryRIEPair<"lochi", 0xEC42, GR32, imm32sx16>;
+ defm LOCGHI : CondBinaryRIEPair<"locghi", 0xEC46, GR64, imm64sx16>;
+ }
+
+ // Move register on condition. Expanded from Select* pseudos and
+ // created by early if-conversion.
+ let hasSideEffects = 0, isCommutable = 1 in {
+ // Expands to LOCR or LOCFHR or a branch-and-move sequence,
+ // depending on the choice of registers.
+ def LOCRMux : CondBinaryRRFPseudo<GRX32, GRX32>;
+ defm LOCFHR : CondBinaryRRFPair<"locfhr", 0xB9E0, GRH32, GRH32>;
+ }
+
+ // Load on condition. Matched via DAG pattern.
+ // Expands to LOC or LOCFH, depending on the choice of register.
+ def LOCMux : CondUnaryRSYPseudo<nonvolatile_load, GRX32, 4>;
+ defm LOCFH : CondUnaryRSYPair<"locfh", 0xEBE0, nonvolatile_load, GRH32, 4>;
+
+ // Store on condition. Expanded from CondStore* pseudos.
+ // Expands to STOC or STOCFH, depending on the choice of register.
+ def STOCMux : CondStoreRSYPseudo<GRX32, 4>;
+ defm STOCFH : CondStoreRSYPair<"stocfh", 0xEBE1, GRH32, 4>;
+
+ // Define AsmParser extended mnemonics for each general condition-code mask.
+ foreach V = [ "E", "NE", "H", "NH", "L", "NL", "HE", "NHE", "LE", "NLE",
+ "Z", "NZ", "P", "NP", "M", "NM", "LH", "NLH", "O", "NO" ] in {
+ def LOCHIAsm#V : FixedCondBinaryRIE<CV<V>, "lochi", 0xEC42, GR32,
+ imm32sx16>;
+ def LOCGHIAsm#V : FixedCondBinaryRIE<CV<V>, "locghi", 0xEC46, GR64,
+ imm64sx16>;
+ def LOCHHIAsm#V : FixedCondBinaryRIE<CV<V>, "lochhi", 0xEC4E, GRH32,
+ imm32sx16>;
+ def LOCFHRAsm#V : FixedCondBinaryRRF<CV<V>, "locfhr", 0xB9E0, GRH32, GRH32>;
+ def LOCFHAsm#V : FixedCondUnaryRSY<CV<V>, "locfh", 0xEBE0, GRH32, 4>;
+ def STOCFHAsm#V : FixedCondStoreRSY<CV<V>, "stocfh", 0xEBE1, GRH32, 4>;
+ }
+}
+
+let Predicates = [FeatureLoadStoreOnCond], Uses = [CC] in {
+ // Move register on condition. Expanded from Select* pseudos and
+ // created by early if-conversion.
+ let hasSideEffects = 0, isCommutable = 1 in {
+ defm LOCR : CondBinaryRRFPair<"locr", 0xB9F2, GR32, GR32>;
+ defm LOCGR : CondBinaryRRFPair<"locgr", 0xB9E2, GR64, GR64>;
+ }
+
+ // Load on condition. Matched via DAG pattern.
+ defm LOC : CondUnaryRSYPair<"loc", 0xEBF2, nonvolatile_load, GR32, 4>;
+ defm LOCG : CondUnaryRSYPair<"locg", 0xEBE2, nonvolatile_load, GR64, 8>;
+
+ // Store on condition. Expanded from CondStore* pseudos.
+ defm STOC : CondStoreRSYPair<"stoc", 0xEBF3, GR32, 4>;
+ defm STOCG : CondStoreRSYPair<"stocg", 0xEBE3, GR64, 8>;
+
+ // Define AsmParser extended mnemonics for each general condition-code mask.
+ foreach V = [ "E", "NE", "H", "NH", "L", "NL", "HE", "NHE", "LE", "NLE",
+ "Z", "NZ", "P", "NP", "M", "NM", "LH", "NLH", "O", "NO" ] in {
+ def LOCRAsm#V : FixedCondBinaryRRF<CV<V>, "locr", 0xB9F2, GR32, GR32>;
+ def LOCGRAsm#V : FixedCondBinaryRRF<CV<V>, "locgr", 0xB9E2, GR64, GR64>;
+ def LOCAsm#V : FixedCondUnaryRSY<CV<V>, "loc", 0xEBF2, GR32, 4>;
+ def LOCGAsm#V : FixedCondUnaryRSY<CV<V>, "locg", 0xEBE2, GR64, 8>;
+ def STOCAsm#V : FixedCondStoreRSY<CV<V>, "stoc", 0xEBF3, GR32, 4>;
+ def STOCGAsm#V : FixedCondStoreRSY<CV<V>, "stocg", 0xEBE3, GR64, 8>;
+ }
+}
+//===----------------------------------------------------------------------===//
// Sign extensions
//===----------------------------------------------------------------------===//
//
@@ -581,18 +558,18 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in
// 32-bit extensions from registers.
let hasSideEffects = 0 in {
- def LBR : UnaryRRE<"lb", 0xB926, sext8, GR32, GR32>;
- def LHR : UnaryRRE<"lh", 0xB927, sext16, GR32, GR32>;
+ def LBR : UnaryRRE<"lbr", 0xB926, sext8, GR32, GR32>;
+ def LHR : UnaryRRE<"lhr", 0xB927, sext16, GR32, GR32>;
}
// 64-bit extensions from registers.
let hasSideEffects = 0 in {
- def LGBR : UnaryRRE<"lgb", 0xB906, sext8, GR64, GR64>;
- def LGHR : UnaryRRE<"lgh", 0xB907, sext16, GR64, GR64>;
- def LGFR : UnaryRRE<"lgf", 0xB914, sext32, GR64, GR32>;
+ def LGBR : UnaryRRE<"lgbr", 0xB906, sext8, GR64, GR64>;
+ def LGHR : UnaryRRE<"lghr", 0xB907, sext16, GR64, GR64>;
+ def LGFR : UnaryRRE<"lgfr", 0xB914, sext32, GR64, GR32>;
}
let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in
- def LTGFR : UnaryRRE<"ltgf", 0xB912, null_frag, GR64, GR32>;
+ def LTGFR : UnaryRRE<"ltgfr", 0xB912, null_frag, GR64, GR32>;
// Match 32-to-64-bit sign extensions in which the source is already
// in a 64-bit register.
@@ -632,20 +609,20 @@ let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in
// 32-bit extensions from registers.
let hasSideEffects = 0 in {
// Expands to LLCR or RISB[LH]G, depending on the choice of registers.
- def LLCRMux : UnaryRRPseudo<"llc", zext8, GRX32, GRX32>,
+ def LLCRMux : UnaryRRPseudo<"llcr", zext8, GRX32, GRX32>,
Requires<[FeatureHighWord]>;
- def LLCR : UnaryRRE<"llc", 0xB994, zext8, GR32, GR32>;
+ def LLCR : UnaryRRE<"llcr", 0xB994, zext8, GR32, GR32>;
// Expands to LLHR or RISB[LH]G, depending on the choice of registers.
- def LLHRMux : UnaryRRPseudo<"llh", zext16, GRX32, GRX32>,
+ def LLHRMux : UnaryRRPseudo<"llhr", zext16, GRX32, GRX32>,
Requires<[FeatureHighWord]>;
- def LLHR : UnaryRRE<"llh", 0xB995, zext16, GR32, GR32>;
+ def LLHR : UnaryRRE<"llhr", 0xB995, zext16, GR32, GR32>;
}
// 64-bit extensions from registers.
let hasSideEffects = 0 in {
- def LLGCR : UnaryRRE<"llgc", 0xB984, zext8, GR64, GR64>;
- def LLGHR : UnaryRRE<"llgh", 0xB985, zext16, GR64, GR64>;
- def LLGFR : UnaryRRE<"llgf", 0xB916, zext32, GR64, GR32>;
+ def LLGCR : UnaryRRE<"llgcr", 0xB984, zext8, GR64, GR64>;
+ def LLGHR : UnaryRRE<"llghr", 0xB985, zext16, GR64, GR64>;
+ def LLGFR : UnaryRRE<"llgfr", 0xB916, zext32, GR64, GR32>;
}
// Match 32-to-64-bit zero extensions in which the source is already
@@ -677,6 +654,27 @@ def LLGF : UnaryRXY<"llgf", 0xE316, azextloadi32, GR64, 4>;
def LLGHRL : UnaryRILPC<"llghrl", 0xC46, aligned_azextloadi16, GR64>;
def LLGFRL : UnaryRILPC<"llgfrl", 0xC4E, aligned_azextloadi32, GR64>;
+// 31-to-64-bit zero extensions.
+def LLGTR : UnaryRRE<"llgtr", 0xB917, null_frag, GR64, GR64>;
+def LLGT : UnaryRXY<"llgt", 0xE317, null_frag, GR64, 4>;
+def : Pat<(and GR64:$src, 0x7fffffff),
+ (LLGTR GR64:$src)>;
+def : Pat<(and (i64 (azextloadi32 bdxaddr20only:$src)), 0x7fffffff),
+ (LLGT bdxaddr20only:$src)>;
+
+// Load and zero rightmost byte.
+let Predicates = [FeatureLoadAndZeroRightmostByte] in {
+ def LLZRGF : UnaryRXY<"llzrgf", 0xE33A, null_frag, GR64, 4>;
+ def : Pat<(and (i64 (azextloadi32 bdxaddr20only:$src)), 0xffffff00),
+ (LLZRGF bdxaddr20only:$src)>;
+}
+
+// Load and trap.
+let Predicates = [FeatureLoadAndTrap] in {
+ def LLGFAT : UnaryRXY<"llgfat", 0xE39D, null_frag, GR64, 4>;
+ def LLGTAT : UnaryRXY<"llgtat", 0xE39C, null_frag, GR64, 4>;
+}
+
//===----------------------------------------------------------------------===//
// Truncations
//===----------------------------------------------------------------------===//
@@ -729,8 +727,8 @@ def STMH : StoreMultipleRSY<"stmh", 0xEB26, GRH32>;
// Byte-swapping register moves.
let hasSideEffects = 0 in {
- def LRVR : UnaryRRE<"lrv", 0xB91F, bswap, GR32, GR32>;
- def LRVGR : UnaryRRE<"lrvg", 0xB90F, bswap, GR64, GR64>;
+ def LRVR : UnaryRRE<"lrvr", 0xB91F, bswap, GR32, GR32>;
+ def LRVGR : UnaryRRE<"lrvgr", 0xB90F, bswap, GR64, GR64>;
}
// Byte-swapping loads. Unlike normal loads, these instructions are
@@ -749,26 +747,14 @@ def STRVG : StoreRXY<"strvg", 0xE32F, z_strvg, GR64, 8>;
//===----------------------------------------------------------------------===//
// Load BDX-style addresses.
-let hasSideEffects = 0, isAsCheapAsAMove = 1, isReMaterializable = 1,
- DispKey = "la" in {
- let DispSize = "12" in
- def LA : InstRX<0x41, (outs GR64:$R1), (ins laaddr12pair:$XBD2),
- "la\t$R1, $XBD2",
- [(set GR64:$R1, laaddr12pair:$XBD2)]>;
- let DispSize = "20" in
- def LAY : InstRXY<0xE371, (outs GR64:$R1), (ins laaddr20pair:$XBD2),
- "lay\t$R1, $XBD2",
- [(set GR64:$R1, laaddr20pair:$XBD2)]>;
-}
+let hasSideEffects = 0, isAsCheapAsAMove = 1, isReMaterializable = 1 in
+ defm LA : LoadAddressRXPair<"la", 0x41, 0xE371, bitconvert>;
// Load a PC-relative address. There's no version of this instruction
// with a 16-bit offset, so there's no relaxation.
let hasSideEffects = 0, isAsCheapAsAMove = 1, isMoveImm = 1,
- isReMaterializable = 1 in {
- def LARL : InstRIL<0xC00, (outs GR64:$R1), (ins pcrel32:$I2),
- "larl\t$R1, $I2",
- [(set GR64:$R1, pcrel32:$I2)]>;
-}
+ isReMaterializable = 1 in
+ def LARL : LoadAddressRIL<"larl", 0xC00, bitconvert>;
// Load the Global Offset Table address. This will be lowered into a
// larl $R1, _GLOBAL_OFFSET_TABLE_
@@ -782,11 +768,11 @@ def GOT : Alias<6, (outs GR64:$R1), (ins),
let Defs = [CC] in {
let CCValues = 0xF, CompareZeroCCMask = 0x8 in {
- def LPR : UnaryRR <"lp", 0x10, z_iabs, GR32, GR32>;
- def LPGR : UnaryRRE<"lpg", 0xB900, z_iabs, GR64, GR64>;
+ def LPR : UnaryRR <"lpr", 0x10, z_iabs, GR32, GR32>;
+ def LPGR : UnaryRRE<"lpgr", 0xB900, z_iabs, GR64, GR64>;
}
let CCValues = 0xE, CompareZeroCCMask = 0xE in
- def LPGFR : UnaryRRE<"lpgf", 0xB910, null_frag, GR64, GR32>;
+ def LPGFR : UnaryRRE<"lpgfr", 0xB910, null_frag, GR64, GR32>;
}
def : Pat<(z_iabs32 GR32:$src), (LPR GR32:$src)>;
def : Pat<(z_iabs64 GR64:$src), (LPGR GR64:$src)>;
@@ -795,11 +781,11 @@ defm : SXU<z_iabs64, LPGFR>;
let Defs = [CC] in {
let CCValues = 0xF, CompareZeroCCMask = 0x8 in {
- def LNR : UnaryRR <"ln", 0x11, z_inegabs, GR32, GR32>;
- def LNGR : UnaryRRE<"lng", 0xB901, z_inegabs, GR64, GR64>;
+ def LNR : UnaryRR <"lnr", 0x11, z_inegabs, GR32, GR32>;
+ def LNGR : UnaryRRE<"lngr", 0xB901, z_inegabs, GR64, GR64>;
}
let CCValues = 0xE, CompareZeroCCMask = 0xE in
- def LNGFR : UnaryRRE<"lngf", 0xB911, null_frag, GR64, GR32>;
+ def LNGFR : UnaryRRE<"lngfr", 0xB911, null_frag, GR64, GR32>;
}
def : Pat<(z_inegabs32 GR32:$src), (LNR GR32:$src)>;
def : Pat<(z_inegabs64 GR64:$src), (LNGR GR64:$src)>;
@@ -808,11 +794,11 @@ defm : SXU<z_inegabs64, LNGFR>;
let Defs = [CC] in {
let CCValues = 0xF, CompareZeroCCMask = 0x8 in {
- def LCR : UnaryRR <"lc", 0x13, ineg, GR32, GR32>;
- def LCGR : UnaryRRE<"lcg", 0xB903, ineg, GR64, GR64>;
+ def LCR : UnaryRR <"lcr", 0x13, ineg, GR32, GR32>;
+ def LCGR : UnaryRRE<"lcgr", 0xB903, ineg, GR64, GR64>;
}
let CCValues = 0xE, CompareZeroCCMask = 0xE in
- def LCGFR : UnaryRRE<"lcgf", 0xB913, null_frag, GR64, GR32>;
+ def LCGFR : UnaryRRE<"lcgfr", 0xB913, null_frag, GR64, GR32>;
}
defm : SXU<ineg, LCGFR>;
@@ -880,10 +866,10 @@ def : Pat<(or (zext32 GR32:$src), imm64hf32:$imm),
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
// Addition of a register.
let isCommutable = 1 in {
- defm AR : BinaryRRAndK<"a", 0x1A, 0xB9F8, add, GR32, GR32>;
- defm AGR : BinaryRREAndK<"ag", 0xB908, 0xB9E8, add, GR64, GR64>;
+ defm AR : BinaryRRAndK<"ar", 0x1A, 0xB9F8, add, GR32, GR32>;
+ defm AGR : BinaryRREAndK<"agr", 0xB908, 0xB9E8, add, GR64, GR64>;
}
- def AGFR : BinaryRRE<"agf", 0xB918, null_frag, GR64, GR32>;
+ def AGFR : BinaryRRE<"agfr", 0xB918, null_frag, GR64, GR32>;
// Addition of signed 16-bit immediates.
defm AHIMux : BinaryRIAndKPseudo<"ahimux", add, GRX32, imm32sx16>;
@@ -914,10 +900,10 @@ defm : SXB<add, GR64, AGFR>;
let Defs = [CC] in {
// Addition of a register.
let isCommutable = 1 in {
- defm ALR : BinaryRRAndK<"al", 0x1E, 0xB9FA, addc, GR32, GR32>;
- defm ALGR : BinaryRREAndK<"alg", 0xB90A, 0xB9EA, addc, GR64, GR64>;
+ defm ALR : BinaryRRAndK<"alr", 0x1E, 0xB9FA, addc, GR32, GR32>;
+ defm ALGR : BinaryRREAndK<"algr", 0xB90A, 0xB9EA, addc, GR64, GR64>;
}
- def ALGFR : BinaryRRE<"algf", 0xB91A, null_frag, GR64, GR32>;
+ def ALGFR : BinaryRRE<"algfr", 0xB91A, null_frag, GR64, GR32>;
// Addition of signed 16-bit immediates.
def ALHSIK : BinaryRIE<"alhsik", 0xECDA, addc, GR32, imm32sx16>,
@@ -939,8 +925,8 @@ defm : ZXB<addc, GR64, ALGFR>;
// Addition producing and using a carry.
let Defs = [CC], Uses = [CC] in {
// Addition of a register.
- def ALCR : BinaryRRE<"alc", 0xB998, adde, GR32, GR32>;
- def ALCGR : BinaryRRE<"alcg", 0xB988, adde, GR64, GR64>;
+ def ALCR : BinaryRRE<"alcr", 0xB998, adde, GR32, GR32>;
+ def ALCGR : BinaryRRE<"alcgr", 0xB988, adde, GR64, GR64>;
// Addition of memory.
def ALC : BinaryRXY<"alc", 0xE398, adde, GR32, load, 4>;
@@ -955,9 +941,9 @@ let Defs = [CC], Uses = [CC] in {
// add-immediate instruction instead.
let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
// Subtraction of a register.
- defm SR : BinaryRRAndK<"s", 0x1B, 0xB9F9, sub, GR32, GR32>;
- def SGFR : BinaryRRE<"sgf", 0xB919, null_frag, GR64, GR32>;
- defm SGR : BinaryRREAndK<"sg", 0xB909, 0xB9E9, sub, GR64, GR64>;
+ defm SR : BinaryRRAndK<"sr", 0x1B, 0xB9F9, sub, GR32, GR32>;
+ def SGFR : BinaryRRE<"sgfr", 0xB919, null_frag, GR64, GR32>;
+ defm SGR : BinaryRREAndK<"sgr", 0xB909, 0xB9E9, sub, GR64, GR64>;
// Subtraction of memory.
defm SH : BinaryRXPair<"sh", 0x4B, 0xE37B, sub, GR32, asextloadi16, 2>;
@@ -970,9 +956,9 @@ defm : SXB<sub, GR64, SGFR>;
// Subtraction producing a carry.
let Defs = [CC] in {
// Subtraction of a register.
- defm SLR : BinaryRRAndK<"sl", 0x1F, 0xB9FB, subc, GR32, GR32>;
- def SLGFR : BinaryRRE<"slgf", 0xB91B, null_frag, GR64, GR32>;
- defm SLGR : BinaryRREAndK<"slg", 0xB90B, 0xB9EB, subc, GR64, GR64>;
+ defm SLR : BinaryRRAndK<"slr", 0x1F, 0xB9FB, subc, GR32, GR32>;
+ def SLGFR : BinaryRRE<"slgfr", 0xB91B, null_frag, GR64, GR32>;
+ defm SLGR : BinaryRREAndK<"slgr", 0xB90B, 0xB9EB, subc, GR64, GR64>;
// Subtraction of unsigned 32-bit immediates. These don't match
// subc because we prefer addc for constants.
@@ -989,8 +975,8 @@ defm : ZXB<subc, GR64, SLGFR>;
// Subtraction producing and using a carry.
let Defs = [CC], Uses = [CC] in {
// Subtraction of a register.
- def SLBR : BinaryRRE<"slb", 0xB999, sube, GR32, GR32>;
- def SLBGR : BinaryRRE<"slbg", 0xB989, sube, GR64, GR64>;
+ def SLBR : BinaryRRE<"slbr", 0xB999, sube, GR32, GR32>;
+ def SLBGR : BinaryRRE<"slbgr", 0xB989, sube, GR64, GR64>;
// Subtraction of memory.
def SLB : BinaryRXY<"slb", 0xE399, sube, GR32, load, 4>;
@@ -1004,8 +990,8 @@ let Defs = [CC], Uses = [CC] in {
let Defs = [CC] in {
// ANDs of a register.
let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in {
- defm NR : BinaryRRAndK<"n", 0x14, 0xB9F4, and, GR32, GR32>;
- defm NGR : BinaryRREAndK<"ng", 0xB980, 0xB9E4, and, GR64, GR64>;
+ defm NR : BinaryRRAndK<"nr", 0x14, 0xB9F4, and, GR32, GR32>;
+ defm NGR : BinaryRREAndK<"ngr", 0xB980, 0xB9E4, and, GR64, GR64>;
}
let isConvertibleToThreeAddress = 1 in {
@@ -1063,8 +1049,8 @@ defm : RMWIByte<and, bdaddr20pair, NIY>;
let Defs = [CC] in {
// ORs of a register.
let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in {
- defm OR : BinaryRRAndK<"o", 0x16, 0xB9F6, or, GR32, GR32>;
- defm OGR : BinaryRREAndK<"og", 0xB981, 0xB9E6, or, GR64, GR64>;
+ defm OR : BinaryRRAndK<"or", 0x16, 0xB9F6, or, GR32, GR32>;
+ defm OGR : BinaryRREAndK<"ogr", 0xB981, 0xB9E6, or, GR64, GR64>;
}
// ORs of a 16-bit immediate, leaving other bits unaffected.
@@ -1120,8 +1106,8 @@ defm : RMWIByte<or, bdaddr20pair, OIY>;
let Defs = [CC] in {
// XORs of a register.
let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in {
- defm XR : BinaryRRAndK<"x", 0x17, 0xB9F7, xor, GR32, GR32>;
- defm XGR : BinaryRREAndK<"xg", 0xB982, 0xB9E7, xor, GR64, GR64>;
+ defm XR : BinaryRRAndK<"xr", 0x17, 0xB9F7, xor, GR32, GR32>;
+ defm XGR : BinaryRREAndK<"xgr", 0xB982, 0xB9E7, xor, GR64, GR64>;
}
// XORs of a 32-bit immediate, leaving other bits unaffected.
@@ -1159,10 +1145,10 @@ defm : RMWIByte<xor, bdaddr20pair, XIY>;
// Multiplication of a register.
let isCommutable = 1 in {
- def MSR : BinaryRRE<"ms", 0xB252, mul, GR32, GR32>;
- def MSGR : BinaryRRE<"msg", 0xB90C, mul, GR64, GR64>;
+ def MSR : BinaryRRE<"msr", 0xB252, mul, GR32, GR32>;
+ def MSGR : BinaryRRE<"msgr", 0xB90C, mul, GR64, GR64>;
}
-def MSGFR : BinaryRRE<"msgf", 0xB91C, null_frag, GR64, GR32>;
+def MSGFR : BinaryRRE<"msgfr", 0xB91C, null_frag, GR64, GR32>;
defm : SXB<mul, GR64, MSGFR>;
// Multiplication of a signed 16-bit immediate.
@@ -1180,7 +1166,7 @@ def MSGF : BinaryRXY<"msgf", 0xE31C, mul, GR64, asextloadi32, 4>;
def MSG : BinaryRXY<"msg", 0xE30C, mul, GR64, load, 8>;
// Multiplication of a register, producing two results.
-def MLGR : BinaryRRE<"mlg", 0xB986, z_umul_lohi64, GR128, GR64>;
+def MLGR : BinaryRRE<"mlgr", 0xB986, z_umul_lohi64, GR128, GR64>;
// Multiplication of memory, producing two results.
def MLG : BinaryRXY<"mlg", 0xE386, z_umul_lohi64, GR128, load, 8>;
@@ -1189,17 +1175,19 @@ def MLG : BinaryRXY<"mlg", 0xE386, z_umul_lohi64, GR128, load, 8>;
// Division and remainder
//===----------------------------------------------------------------------===//
-// Division and remainder, from registers.
-def DSGFR : BinaryRRE<"dsgf", 0xB91D, z_sdivrem32, GR128, GR32>;
-def DSGR : BinaryRRE<"dsg", 0xB90D, z_sdivrem64, GR128, GR64>;
-def DLR : BinaryRRE<"dl", 0xB997, z_udivrem32, GR128, GR32>;
-def DLGR : BinaryRRE<"dlg", 0xB987, z_udivrem64, GR128, GR64>;
+let hasSideEffects = 1 in { // Do not speculatively execute.
+ // Division and remainder, from registers.
+ def DSGFR : BinaryRRE<"dsgfr", 0xB91D, z_sdivrem32, GR128, GR32>;
+ def DSGR : BinaryRRE<"dsgr", 0xB90D, z_sdivrem64, GR128, GR64>;
+ def DLR : BinaryRRE<"dlr", 0xB997, z_udivrem32, GR128, GR32>;
+ def DLGR : BinaryRRE<"dlgr", 0xB987, z_udivrem64, GR128, GR64>;
-// Division and remainder, from memory.
-def DSGF : BinaryRXY<"dsgf", 0xE31D, z_sdivrem32, GR128, load, 4>;
-def DSG : BinaryRXY<"dsg", 0xE30D, z_sdivrem64, GR128, load, 8>;
-def DL : BinaryRXY<"dl", 0xE397, z_udivrem32, GR128, load, 4>;
-def DLG : BinaryRXY<"dlg", 0xE387, z_udivrem64, GR128, load, 8>;
+ // Division and remainder, from memory.
+ def DSGF : BinaryRXY<"dsgf", 0xE31D, z_sdivrem32, GR128, load, 4>;
+ def DSG : BinaryRXY<"dsg", 0xE30D, z_sdivrem64, GR128, load, 8>;
+ def DL : BinaryRXY<"dl", 0xE397, z_udivrem32, GR128, load, 4>;
+ def DLG : BinaryRXY<"dlg", 0xE387, z_udivrem64, GR128, load, 8>;
+}
//===----------------------------------------------------------------------===//
// Shifts
@@ -1274,11 +1262,14 @@ let Defs = [CC] in {
// of the unsigned forms do.
let Defs = [CC], CCValues = 0xE in {
// Comparison with a register.
- def CR : CompareRR <"c", 0x19, z_scmp, GR32, GR32>;
- def CGFR : CompareRRE<"cgf", 0xB930, null_frag, GR64, GR32>;
- def CGR : CompareRRE<"cg", 0xB920, z_scmp, GR64, GR64>;
+ def CR : CompareRR <"cr", 0x19, z_scmp, GR32, GR32>;
+ def CGFR : CompareRRE<"cgfr", 0xB930, null_frag, GR64, GR32>;
+ def CGR : CompareRRE<"cgr", 0xB920, z_scmp, GR64, GR64>;
- // Comparison with a signed 16-bit immediate.
+ // Comparison with a signed 16-bit immediate. CHIMux expands to CHI or CIH,
+ // depending on the choice of register.
+ def CHIMux : CompareRIPseudo<z_scmp, GRX32, imm32sx16>,
+ Requires<[FeatureHighWord]>;
def CHI : CompareRI<"chi", 0xA7E, z_scmp, GR32, imm32sx16>;
def CGHI : CompareRI<"cghi", 0xA7F, z_scmp, GR64, imm64sx16>;
@@ -1317,9 +1308,9 @@ defm : SXB<z_scmp, GR64, CGFR>;
// Unsigned comparisons.
let Defs = [CC], CCValues = 0xE, IsLogical = 1 in {
// Comparison with a register.
- def CLR : CompareRR <"cl", 0x15, z_ucmp, GR32, GR32>;
- def CLGFR : CompareRRE<"clgf", 0xB931, null_frag, GR64, GR32>;
- def CLGR : CompareRRE<"clg", 0xB921, z_ucmp, GR64, GR64>;
+ def CLR : CompareRR <"clr", 0x15, z_ucmp, GR32, GR32>;
+ def CLGFR : CompareRRE<"clgfr", 0xB931, null_frag, GR64, GR32>;
+ def CLGR : CompareRRE<"clgr", 0xB921, z_ucmp, GR64, GR64>;
// Comparison with an unsigned 32-bit immediate. CLFIMux expands to CLFI
// or CLIH, depending on the choice of register.
@@ -1391,12 +1382,21 @@ def TML : InstAlias<"tml\t$R, $I", (TMLL GR32:$R, imm32ll16:$I), 0>;
def TMH : InstAlias<"tmh\t$R, $I", (TMLH GR32:$R, imm32lh16:$I), 0>;
//===----------------------------------------------------------------------===//
-// Prefetch
+// Prefetch and execution hint
//===----------------------------------------------------------------------===//
def PFD : PrefetchRXY<"pfd", 0xE336, z_prefetch>;
def PFDRL : PrefetchRILPC<"pfdrl", 0xC62, z_prefetch>;
+let Predicates = [FeatureExecutionHint] in {
+ // Branch Prediction Preload
+ def BPP : BranchPreloadSMI<"bpp", 0xC7>;
+ def BPRP : BranchPreloadMII<"bprp", 0xC5>;
+
+ // Next Instruction Access Intent
+ def NIAI : SideEffectBinaryIE<"niai", 0xB2FA, imm32zx4, imm32zx4>;
+}
+
//===----------------------------------------------------------------------===//
// Atomic operations
//===----------------------------------------------------------------------===//
@@ -1407,7 +1407,7 @@ let hasSideEffects = 1 in
def Serialize : Alias<2, (outs), (ins), [(z_serialize)]>;
// A pseudo instruction that serves as a compiler barrier.
-let hasSideEffects = 1 in
+let hasSideEffects = 1, hasNoSchedulingInfo = 1 in
def MemBarrier : Pseudo<(outs), (ins), [(z_membarrier)]>;
let Predicates = [FeatureInterlockedAccess1], Defs = [CC] in {
@@ -1543,52 +1543,131 @@ def ATOMIC_CMP_SWAPW
let mayLoad = 1;
let mayStore = 1;
let usesCustomInserter = 1;
+ let hasNoSchedulingInfo = 1;
}
+// Test and set.
+let mayLoad = 1, Defs = [CC] in
+ def TS : StoreInherentS<"ts", 0x9300, null_frag, 1>;
+
+// Compare and swap.
let Defs = [CC] in {
defm CS : CmpSwapRSPair<"cs", 0xBA, 0xEB14, atomic_cmp_swap_32, GR32>;
def CSG : CmpSwapRSY<"csg", 0xEB30, atomic_cmp_swap_64, GR64>;
}
+// Compare double and swap.
+let Defs = [CC] in {
+ defm CDS : CmpSwapRSPair<"cds", 0xBB, 0xEB31, null_frag, GR128>;
+ def CDSG : CmpSwapRSY<"cdsg", 0xEB3E, null_frag, GR128>;
+}
+
+// Compare and swap and store.
+let Uses = [R0L, R1D], Defs = [CC], mayStore = 1, mayLoad = 1 in
+ def CSST : SideEffectTernarySSF<"csst", 0xC82, GR64>;
+
+// Perform locked operation.
+let Uses = [R0L, R1D], Defs = [CC], mayStore = 1, mayLoad =1 in
+ def PLO : SideEffectQuaternarySSe<"plo", 0xEE, GR64>;
+
+// Load/store pair from/to quadword.
+def LPQ : UnaryRXY<"lpq", 0xE38F, null_frag, GR128, 16>;
+def STPQ : StoreRXY<"stpq", 0xE38E, null_frag, GR128, 16>;
+
+// Load pair disjoint.
+let Predicates = [FeatureInterlockedAccess1], Defs = [CC] in {
+ def LPD : BinarySSF<"lpd", 0xC84, GR128>;
+ def LPDG : BinarySSF<"lpdg", 0xC85, GR128>;
+}
+
+//===----------------------------------------------------------------------===//
+// Access registers
+//===----------------------------------------------------------------------===//
+
+// Read a 32-bit access register into a GR32. As with all GR32 operations,
+// the upper 32 bits of the enclosing GR64 remain unchanged, which is useful
+// when a 64-bit address is stored in a pair of access registers.
+def EAR : UnaryRRE<"ear", 0xB24F, null_frag, GR32, AR32>;
+
+// Set access register.
+def SAR : UnaryRRE<"sar", 0xB24E, null_frag, AR32, GR32>;
+
+// Copy access register.
+def CPYA : UnaryRRE<"cpya", 0xB24D, null_frag, AR32, AR32>;
+
+// Load address extended.
+defm LAE : LoadAddressRXPair<"lae", 0x51, 0xE375, null_frag>;
+
+// Load access multiple.
+defm LAM : LoadMultipleRSPair<"lam", 0x9A, 0xEB9A, AR32>;
+
+// Load access multiple.
+defm STAM : StoreMultipleRSPair<"stam", 0x9B, 0xEB9B, AR32>;
+
+//===----------------------------------------------------------------------===//
+// Program mask and addressing mode
+//===----------------------------------------------------------------------===//
+
+// Extract CC and program mask into a register. CC ends up in bits 29 and 28.
+let Uses = [CC] in
+ def IPM : InherentRRE<"ipm", 0xB222, GR32, z_ipm>;
+
+// Set CC and program mask from a register.
+let hasSideEffects = 1, Defs = [CC] in
+ def SPM : SideEffectUnaryRR<"spm", 0x04, GR32>;
+
+// Branch and link - like BAS, but also extracts CC and program mask.
+let isCall = 1, Uses = [CC], Defs = [CC] in {
+ def BAL : CallRX<"bal", 0x45>;
+ def BALR : CallRR<"balr", 0x05>;
+}
+
+// Test addressing mode.
+let Defs = [CC] in
+ def TAM : SideEffectInherentE<"tam", 0x010B>;
+
+// Set addressing mode.
+let hasSideEffects = 1 in {
+ def SAM24 : SideEffectInherentE<"sam24", 0x010C>;
+ def SAM31 : SideEffectInherentE<"sam31", 0x010D>;
+ def SAM64 : SideEffectInherentE<"sam64", 0x010E>;
+}
+
+// Branch and set mode. Not really a call, but also sets an output register.
+let isBranch = 1, isTerminator = 1, isBarrier = 1 in
+ def BSM : CallRR<"bsm", 0x0B>;
+
+// Branch and save and set mode.
+let isCall = 1, Defs = [CC] in
+ def BASSM : CallRR<"bassm", 0x0C>;
+
//===----------------------------------------------------------------------===//
// Transactional execution
//===----------------------------------------------------------------------===//
-let Predicates = [FeatureTransactionalExecution] in {
+let hasSideEffects = 1, Predicates = [FeatureTransactionalExecution] in {
// Transaction Begin
- let hasSideEffects = 1, mayStore = 1,
- usesCustomInserter = 1, Defs = [CC] in {
- def TBEGIN : InstSIL<0xE560,
- (outs), (ins bdaddr12only:$BD1, imm32zx16:$I2),
- "tbegin\t$BD1, $I2",
- [(z_tbegin bdaddr12only:$BD1, imm32zx16:$I2)]>;
- def TBEGIN_nofloat : Pseudo<(outs), (ins bdaddr12only:$BD1, imm32zx16:$I2),
- [(z_tbegin_nofloat bdaddr12only:$BD1,
- imm32zx16:$I2)]>;
- def TBEGINC : InstSIL<0xE561,
- (outs), (ins bdaddr12only:$BD1, imm32zx16:$I2),
- "tbeginc\t$BD1, $I2",
- [(int_s390_tbeginc bdaddr12only:$BD1,
- imm32zx16:$I2)]>;
+ let mayStore = 1, usesCustomInserter = 1, Defs = [CC] in {
+ def TBEGIN : SideEffectBinarySIL<"tbegin", 0xE560, z_tbegin, imm32zx16>;
+ def TBEGIN_nofloat : SideEffectBinarySILPseudo<z_tbegin_nofloat, imm32zx16>;
+
+ def TBEGINC : SideEffectBinarySIL<"tbeginc", 0xE561,
+ int_s390_tbeginc, imm32zx16>;
}
// Transaction End
- let hasSideEffects = 1, Defs = [CC], BD2 = 0 in
- def TEND : InstS<0xB2F8, (outs), (ins), "tend", [(z_tend)]>;
+ let Defs = [CC] in
+ def TEND : SideEffectInherentS<"tend", 0xB2F8, z_tend>;
// Transaction Abort
- let hasSideEffects = 1, isTerminator = 1, isBarrier = 1 in
- def TABORT : InstS<0xB2FC, (outs), (ins bdaddr12only:$BD2),
- "tabort\t$BD2",
- [(int_s390_tabort bdaddr12only:$BD2)]>;
+ let isTerminator = 1, isBarrier = 1 in
+ def TABORT : SideEffectAddressS<"tabort", 0xB2FC, int_s390_tabort>;
// Nontransactional Store
- let hasSideEffects = 1 in
- def NTSTG : StoreRXY<"ntstg", 0xE325, int_s390_ntstg, GR64, 8>;
+ def NTSTG : StoreRXY<"ntstg", 0xE325, int_s390_ntstg, GR64, 8>;
// Extract Transaction Nesting Depth
- let hasSideEffects = 1 in
- def ETND : InherentRRE<"etnd", 0xB2EC, GR32, (int_s390_etnd)>;
+ def ETND : InherentRRE<"etnd", 0xB2EC, GR32, int_s390_etnd>;
}
//===----------------------------------------------------------------------===//
@@ -1596,9 +1675,8 @@ let Predicates = [FeatureTransactionalExecution] in {
//===----------------------------------------------------------------------===//
let Predicates = [FeatureProcessorAssist] in {
- let hasSideEffects = 1, R4 = 0 in
- def PPA : InstRRF<0xB2E8, (outs), (ins GR64:$R1, GR64:$R2, imm32zx4:$R3),
- "ppa\t$R1, $R2, $R3", []>;
+ let hasSideEffects = 1 in
+ def PPA : SideEffectTernaryRRFc<"ppa", 0xB2E8, GR64, GR64, imm32zx4>;
def : Pat<(int_s390_ppa_txassist GR32:$src),
(PPA (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_l32),
0, 1)>;
@@ -1608,33 +1686,18 @@ let Predicates = [FeatureProcessorAssist] in {
// Miscellaneous Instructions.
//===----------------------------------------------------------------------===//
-// Extract CC into bits 29 and 28 of a register.
-let Uses = [CC] in
- def IPM : InherentRRE<"ipm", 0xB222, GR32, (z_ipm)>;
-
-// Read a 32-bit access register into a GR32. As with all GR32 operations,
-// the upper 32 bits of the enclosing GR64 remain unchanged, which is useful
-// when a 64-bit address is stored in a pair of access registers.
-def EAR : InstRRE<0xB24F, (outs GR32:$R1), (ins access_reg:$R2),
- "ear\t$R1, $R2",
- [(set GR32:$R1, (z_extract_access access_reg:$R2))]>;
-
// Find leftmost one, AKA count leading zeros. The instruction actually
// returns a pair of GR64s, the first giving the number of leading zeros
// and the second giving a copy of the source with the leftmost one bit
// cleared. We only use the first result here.
-let Defs = [CC] in {
- def FLOGR : UnaryRRE<"flog", 0xB983, null_frag, GR128, GR64>;
-}
+let Defs = [CC] in
+ def FLOGR : UnaryRRE<"flogr", 0xB983, null_frag, GR128, GR64>;
def : Pat<(ctlz GR64:$src),
(EXTRACT_SUBREG (FLOGR GR64:$src), subreg_h64)>;
// Population count. Counts bits set per byte.
-let Predicates = [FeaturePopulationCount], Defs = [CC] in {
- def POPCNT : InstRRE<0xB9E1, (outs GR64:$R1), (ins GR64:$R2),
- "popcnt\t$R1, $R2",
- [(set GR64:$R1, (z_popcnt GR64:$R2))]>;
-}
+let Predicates = [FeaturePopulationCount], Defs = [CC] in
+ def POPCNT : UnaryRRE<"popcnt", 0xB9E1, z_popcnt, GR64, GR64>;
// Use subregs to populate the "don't care" bits in a 32-bit to 64-bit anyext.
def : Pat<(i64 (anyext GR32:$src)),
@@ -1651,35 +1714,137 @@ let usesCustomInserter = 1 in {
let mayLoad = 1, Defs = [CC] in
defm SRST : StringRRE<"srst", 0xb25e, z_search_string>;
-// Other instructions for inline assembly
-let hasSideEffects = 1, Defs = [CC], isCall = 1 in
- def SVC : InstI<0x0A, (outs), (ins imm32zx8:$I1),
- "svc\t$I1",
- []>;
-let hasSideEffects = 1, Defs = [CC], mayStore = 1 in
- def STCK : InstS<0xB205, (outs), (ins bdaddr12only:$BD2),
- "stck\t$BD2",
- []>;
-let hasSideEffects = 1, Defs = [CC], mayStore = 1 in
- def STCKF : InstS<0xB27C, (outs), (ins bdaddr12only:$BD2),
- "stckf\t$BD2",
- []>;
-let hasSideEffects = 1, Defs = [CC], mayStore = 1 in
- def STCKE : InstS<0xB278, (outs), (ins bdaddr12only:$BD2),
- "stcke\t$BD2",
- []>;
-let hasSideEffects = 1, Defs = [CC], mayStore = 1 in
- def STFLE : InstS<0xB2B0, (outs), (ins bdaddr12only:$BD2),
- "stfle\t$BD2",
- []>;
+// Supervisor call.
+let hasSideEffects = 1, isCall = 1, Defs = [CC] in
+ def SVC : SideEffectUnaryI<"svc", 0x0A, imm32zx8>;
+
+// Store clock.
+let hasSideEffects = 1, Defs = [CC] in {
+ def STCK : StoreInherentS<"stck", 0xB205, null_frag, 8>;
+ def STCKF : StoreInherentS<"stckf", 0xB27C, null_frag, 8>;
+ def STCKE : StoreInherentS<"stcke", 0xB278, null_frag, 16>;
+}
+
+// Store facility list.
+let hasSideEffects = 1, Uses = [R0D], Defs = [R0D, CC] in
+ def STFLE : StoreInherentS<"stfle", 0xB2B0, null_frag, 0>;
+
+// Extract CPU time.
+let Defs = [R0D, R1D], hasSideEffects = 1, mayLoad = 1 in
+ def ECTG : SideEffectTernarySSF<"ectg", 0xC81, GR64>;
+// Execute.
let hasSideEffects = 1 in {
- def EX : InstRX<0x44, (outs), (ins GR64:$R1, bdxaddr12only:$XBD2),
- "ex\t$R1, $XBD2", []>;
- def EXRL : InstRIL<0xC60, (outs), (ins GR64:$R1, pcrel32:$I2),
- "exrl\t$R1, $I2", []>;
+ def EX : SideEffectBinaryRX<"ex", 0x44, GR64>;
+ def EXRL : SideEffectBinaryRILPC<"exrl", 0xC60, GR64>;
}
+// Program return.
+let hasSideEffects = 1, Defs = [CC] in
+ def PR : SideEffectInherentE<"pr", 0x0101>;
+
+// Move with key.
+let mayLoad = 1, mayStore = 1, Defs = [CC] in
+ def MVCK : MemoryBinarySSd<"mvck", 0xD9, GR64>;
+
+// Store real address.
+def STRAG : StoreSSE<"strag", 0xE502>;
+
+//===----------------------------------------------------------------------===//
+// .insn directive instructions
+//===----------------------------------------------------------------------===//
+
+let isCodeGenOnly = 1 in {
+ def InsnE : DirectiveInsnE<(outs), (ins imm64zx16:$enc), ".insn e,$enc", []>;
+ def InsnRI : DirectiveInsnRI<(outs), (ins imm64zx32:$enc, AnyReg:$R1,
+ imm32sx16:$I2),
+ ".insn ri,$enc,$R1,$I2", []>;
+ def InsnRIE : DirectiveInsnRIE<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
+ AnyReg:$R3, brtarget16:$I2),
+ ".insn rie,$enc,$R1,$R3,$I2", []>;
+ def InsnRIL : DirectiveInsnRIL<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
+ brtarget32:$I2),
+ ".insn ril,$enc,$R1,$I2", []>;
+ def InsnRILU : DirectiveInsnRIL<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
+ uimm32:$I2),
+ ".insn rilu,$enc,$R1,$I2", []>;
+ def InsnRIS : DirectiveInsnRIS<(outs),
+ (ins imm64zx48:$enc, AnyReg:$R1,
+ imm32sx8:$I2, imm32zx4:$M3,
+ bdaddr12only:$BD4),
+ ".insn ris,$enc,$R1,$I2,$M3,$BD4", []>;
+ def InsnRR : DirectiveInsnRR<(outs),
+ (ins imm64zx16:$enc, AnyReg:$R1, AnyReg:$R2),
+ ".insn rr,$enc,$R1,$R2", []>;
+ def InsnRRE : DirectiveInsnRRE<(outs), (ins imm64zx32:$enc,
+ AnyReg:$R1, AnyReg:$R2),
+ ".insn rre,$enc,$R1,$R2", []>;
+ def InsnRRF : DirectiveInsnRRF<(outs),
+ (ins imm64zx32:$enc, AnyReg:$R1, AnyReg:$R2,
+ AnyReg:$R3, imm32zx4:$M4),
+ ".insn rrf,$enc,$R1,$R2,$R3,$M4", []>;
+ def InsnRRS : DirectiveInsnRRS<(outs),
+ (ins imm64zx48:$enc, AnyReg:$R1,
+ AnyReg:$R2, imm32zx4:$M3,
+ bdaddr12only:$BD4),
+ ".insn rrs,$enc,$R1,$R2,$M3,$BD4", []>;
+ def InsnRS : DirectiveInsnRS<(outs),
+ (ins imm64zx32:$enc, AnyReg:$R1,
+ AnyReg:$R3, bdaddr12only:$BD2),
+ ".insn rs,$enc,$R1,$R3,$BD2", []>;
+ def InsnRSE : DirectiveInsnRSE<(outs),
+ (ins imm64zx48:$enc, AnyReg:$R1,
+ AnyReg:$R3, bdaddr12only:$BD2),
+ ".insn rse,$enc,$R1,$R3,$BD2", []>;
+ def InsnRSI : DirectiveInsnRSI<(outs),
+ (ins imm64zx48:$enc, AnyReg:$R1,
+ AnyReg:$R3, brtarget16:$RI2),
+ ".insn rsi,$enc,$R1,$R3,$RI2", []>;
+ def InsnRSY : DirectiveInsnRSY<(outs),
+ (ins imm64zx48:$enc, AnyReg:$R1,
+ AnyReg:$R3, bdaddr20only:$BD2),
+ ".insn rsy,$enc,$R1,$R3,$BD2", []>;
+ def InsnRX : DirectiveInsnRX<(outs), (ins imm64zx32:$enc, AnyReg:$R1,
+ bdxaddr12only:$XBD2),
+ ".insn rx,$enc,$R1,$XBD2", []>;
+ def InsnRXE : DirectiveInsnRXE<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
+ bdxaddr12only:$XBD2),
+ ".insn rxe,$enc,$R1,$XBD2", []>;
+ def InsnRXF : DirectiveInsnRXF<(outs),
+ (ins imm64zx48:$enc, AnyReg:$R1,
+ AnyReg:$R3, bdxaddr12only:$XBD2),
+ ".insn rxf,$enc,$R1,$R3,$XBD2", []>;
+ def InsnRXY : DirectiveInsnRXY<(outs), (ins imm64zx48:$enc, AnyReg:$R1,
+ bdxaddr20only:$XBD2),
+ ".insn rxy,$enc,$R1,$XBD2", []>;
+ def InsnS : DirectiveInsnS<(outs),
+ (ins imm64zx32:$enc, bdaddr12only:$BD2),
+ ".insn s,$enc,$BD2", []>;
+ def InsnSI : DirectiveInsnSI<(outs),
+ (ins imm64zx32:$enc, bdaddr12only:$BD1,
+ imm32sx8:$I2),
+ ".insn si,$enc,$BD1,$I2", []>;
+ def InsnSIY : DirectiveInsnSIY<(outs),
+ (ins imm64zx48:$enc,
+ bdaddr20only:$BD1, imm32zx8:$I2),
+ ".insn siy,$enc,$BD1,$I2", []>;
+ def InsnSIL : DirectiveInsnSIL<(outs),
+ (ins imm64zx48:$enc, bdaddr12only:$BD1,
+ imm32zx16:$I2),
+ ".insn sil,$enc,$BD1,$I2", []>;
+ def InsnSS : DirectiveInsnSS<(outs),
+ (ins imm64zx48:$enc, bdraddr12only:$RBD1,
+ bdaddr12only:$BD2, AnyReg:$R3),
+ ".insn ss,$enc,$RBD1,$BD2,$R3", []>;
+ def InsnSSE : DirectiveInsnSSE<(outs),
+ (ins imm64zx48:$enc,
+ bdaddr12only:$BD1,bdaddr12only:$BD2),
+ ".insn sse,$enc,$BD1,$BD2", []>;
+ def InsnSSF : DirectiveInsnSSF<(outs),
+ (ins imm64zx48:$enc, bdaddr12only:$BD1,
+ bdaddr12only:$BD2, AnyReg:$R3),
+ ".insn ssf,$enc,$BD1,$BD2,$R3", []>;
+}
//===----------------------------------------------------------------------===//
// Peepholes.
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrVector.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrVector.td
index c101e43..738ea7a 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrVector.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrVector.td
@@ -18,12 +18,14 @@ let Predicates = [FeatureVector] in {
def VLR64 : UnaryAliasVRR<null_frag, v64db, v64db>;
// Load GR from VR element.
+ def VLGV : BinaryVRScGeneric<"vlgv", 0xE721>;
def VLGVB : BinaryVRSc<"vlgvb", 0xE721, null_frag, v128b, 0>;
def VLGVH : BinaryVRSc<"vlgvh", 0xE721, null_frag, v128h, 1>;
def VLGVF : BinaryVRSc<"vlgvf", 0xE721, null_frag, v128f, 2>;
def VLGVG : BinaryVRSc<"vlgvg", 0xE721, z_vector_extract, v128g, 3>;
// Load VR element from GR.
+ def VLVG : TernaryVRSbGeneric<"vlvg", 0xE722>;
def VLVGB : TernaryVRSb<"vlvgb", 0xE722, z_vector_insert,
v128b, v128b, GR32, 0>;
def VLVGH : TernaryVRSb<"vlvgh", 0xE722, z_vector_insert,
@@ -60,6 +62,7 @@ let Predicates = [FeatureVector] in {
def VGBM : UnaryVRIa<"vgbm", 0xE744, z_byte_mask, v128b, imm32zx16>;
// Generate mask.
+ def VGM : BinaryVRIbGeneric<"vgm", 0xE746>;
def VGMB : BinaryVRIb<"vgmb", 0xE746, z_rotate_mask, v128b, 0>;
def VGMH : BinaryVRIb<"vgmh", 0xE746, z_rotate_mask, v128h, 1>;
def VGMF : BinaryVRIb<"vgmf", 0xE746, z_rotate_mask, v128f, 2>;
@@ -85,6 +88,7 @@ let Predicates = [FeatureVector] in {
}
// Replicate immediate.
+ def VREPI : UnaryVRIaGeneric<"vrepi", 0xE745, imm32sx16>;
def VREPIB : UnaryVRIa<"vrepib", 0xE745, z_replicate, v128b, imm32sx16, 0>;
def VREPIH : UnaryVRIa<"vrepih", 0xE745, z_replicate, v128h, imm32sx16, 1>;
def VREPIF : UnaryVRIa<"vrepif", 0xE745, z_replicate, v128f, imm32sx16, 2>;
@@ -119,6 +123,7 @@ let Predicates = [FeatureVector] in {
def VLM : LoadMultipleVRSa<"vlm", 0xE736>;
// Load and replicate
+ def VLREP : UnaryVRXGeneric<"vlrep", 0xE705>;
def VLREPB : UnaryVRX<"vlrepb", 0xE705, z_replicate_loadi8, v128b, 1, 0>;
def VLREPH : UnaryVRX<"vlreph", 0xE705, z_replicate_loadi16, v128h, 2, 1>;
def VLREPF : UnaryVRX<"vlrepf", 0xE705, z_replicate_loadi32, v128f, 4, 2>;
@@ -136,6 +141,7 @@ let Predicates = [FeatureVector] in {
def VL64 : UnaryAliasVRX<load, v64db, bdxaddr12pair>;
// Load logical element and zero.
+ def VLLEZ : UnaryVRXGeneric<"vllez", 0xE704>;
def VLLEZB : UnaryVRX<"vllezb", 0xE704, z_vllezi8, v128b, 1, 0>;
def VLLEZH : UnaryVRX<"vllezh", 0xE704, z_vllezi16, v128h, 2, 1>;
def VLLEZF : UnaryVRX<"vllezf", 0xE704, z_vllezi32, v128f, 4, 2>;
@@ -223,6 +229,7 @@ let Predicates = [FeatureVector] in {
let Predicates = [FeatureVector] in {
// Merge high.
+ def VMRH: BinaryVRRcGeneric<"vmrh", 0xE761>;
def VMRHB : BinaryVRRc<"vmrhb", 0xE761, z_merge_high, v128b, v128b, 0>;
def VMRHH : BinaryVRRc<"vmrhh", 0xE761, z_merge_high, v128h, v128h, 1>;
def VMRHF : BinaryVRRc<"vmrhf", 0xE761, z_merge_high, v128f, v128f, 2>;
@@ -231,6 +238,7 @@ let Predicates = [FeatureVector] in {
def : BinaryRRWithType<VMRHG, VR128, z_merge_high, v2f64>;
// Merge low.
+ def VMRL: BinaryVRRcGeneric<"vmrl", 0xE760>;
def VMRLB : BinaryVRRc<"vmrlb", 0xE760, z_merge_low, v128b, v128b, 0>;
def VMRLH : BinaryVRRc<"vmrlh", 0xE760, z_merge_low, v128h, v128h, 1>;
def VMRLF : BinaryVRRc<"vmrlf", 0xE760, z_merge_low, v128f, v128f, 2>;
@@ -245,6 +253,7 @@ let Predicates = [FeatureVector] in {
def VPDI : TernaryVRRc<"vpdi", 0xE784, z_permute_dwords, v128g, v128g>;
// Replicate.
+ def VREP: BinaryVRIcGeneric<"vrep", 0xE74D>;
def VREPB : BinaryVRIc<"vrepb", 0xE74D, z_splat, v128b, v128b, 0>;
def VREPH : BinaryVRIc<"vreph", 0xE74D, z_splat, v128h, v128h, 1>;
def VREPF : BinaryVRIc<"vrepf", 0xE74D, z_splat, v128f, v128f, 2>;
@@ -264,11 +273,13 @@ let Predicates = [FeatureVector] in {
let Predicates = [FeatureVector] in {
// Pack
+ def VPK : BinaryVRRcGeneric<"vpk", 0xE794>;
def VPKH : BinaryVRRc<"vpkh", 0xE794, z_pack, v128b, v128h, 1>;
def VPKF : BinaryVRRc<"vpkf", 0xE794, z_pack, v128h, v128f, 2>;
def VPKG : BinaryVRRc<"vpkg", 0xE794, z_pack, v128f, v128g, 3>;
// Pack saturate.
+ def VPKS : BinaryVRRbSPairGeneric<"vpks", 0xE797>;
defm VPKSH : BinaryVRRbSPair<"vpksh", 0xE797, int_s390_vpksh, z_packs_cc,
v128b, v128h, 1>;
defm VPKSF : BinaryVRRbSPair<"vpksf", 0xE797, int_s390_vpksf, z_packs_cc,
@@ -277,6 +288,7 @@ let Predicates = [FeatureVector] in {
v128f, v128g, 3>;
// Pack saturate logical.
+ def VPKLS : BinaryVRRbSPairGeneric<"vpkls", 0xE795>;
defm VPKLSH : BinaryVRRbSPair<"vpklsh", 0xE795, int_s390_vpklsh, z_packls_cc,
v128b, v128h, 1>;
defm VPKLSF : BinaryVRRbSPair<"vpklsf", 0xE795, int_s390_vpklsf, z_packls_cc,
@@ -285,6 +297,7 @@ let Predicates = [FeatureVector] in {
v128f, v128g, 3>;
// Sign-extend to doubleword.
+ def VSEG : UnaryVRRaGeneric<"vseg", 0xE75F>;
def VSEGB : UnaryVRRa<"vsegb", 0xE75F, z_vsei8, v128g, v128g, 0>;
def VSEGH : UnaryVRRa<"vsegh", 0xE75F, z_vsei16, v128g, v128g, 1>;
def VSEGF : UnaryVRRa<"vsegf", 0xE75F, z_vsei32, v128g, v128g, 2>;
@@ -293,21 +306,25 @@ let Predicates = [FeatureVector] in {
def : Pat<(z_vsei32_by_parts (v4i32 VR128:$src)), (VSEGF VR128:$src)>;
// Unpack high.
+ def VUPH : UnaryVRRaGeneric<"vuph", 0xE7D7>;
def VUPHB : UnaryVRRa<"vuphb", 0xE7D7, z_unpack_high, v128h, v128b, 0>;
def VUPHH : UnaryVRRa<"vuphh", 0xE7D7, z_unpack_high, v128f, v128h, 1>;
def VUPHF : UnaryVRRa<"vuphf", 0xE7D7, z_unpack_high, v128g, v128f, 2>;
// Unpack logical high.
+ def VUPLH : UnaryVRRaGeneric<"vuplh", 0xE7D5>;
def VUPLHB : UnaryVRRa<"vuplhb", 0xE7D5, z_unpackl_high, v128h, v128b, 0>;
def VUPLHH : UnaryVRRa<"vuplhh", 0xE7D5, z_unpackl_high, v128f, v128h, 1>;
def VUPLHF : UnaryVRRa<"vuplhf", 0xE7D5, z_unpackl_high, v128g, v128f, 2>;
// Unpack low.
+ def VUPL : UnaryVRRaGeneric<"vupl", 0xE7D6>;
def VUPLB : UnaryVRRa<"vuplb", 0xE7D6, z_unpack_low, v128h, v128b, 0>;
def VUPLHW : UnaryVRRa<"vuplhw", 0xE7D6, z_unpack_low, v128f, v128h, 1>;
def VUPLF : UnaryVRRa<"vuplf", 0xE7D6, z_unpack_low, v128g, v128f, 2>;
// Unpack logical low.
+ def VUPLL : UnaryVRRaGeneric<"vupll", 0xE7D4>;
def VUPLLB : UnaryVRRa<"vupllb", 0xE7D4, z_unpackl_low, v128h, v128b, 0>;
def VUPLLH : UnaryVRRa<"vupllh", 0xE7D4, z_unpackl_low, v128f, v128h, 1>;
def VUPLLF : UnaryVRRa<"vupllf", 0xE7D4, z_unpackl_low, v128g, v128f, 2>;
@@ -343,6 +360,7 @@ defm : GenericVectorOps<v2f64, v2i64>;
let Predicates = [FeatureVector] in {
// Add.
+ def VA : BinaryVRRcGeneric<"va", 0xE7F3>;
def VAB : BinaryVRRc<"vab", 0xE7F3, add, v128b, v128b, 0>;
def VAH : BinaryVRRc<"vah", 0xE7F3, add, v128h, v128h, 1>;
def VAF : BinaryVRRc<"vaf", 0xE7F3, add, v128f, v128f, 2>;
@@ -350,6 +368,7 @@ let Predicates = [FeatureVector] in {
def VAQ : BinaryVRRc<"vaq", 0xE7F3, int_s390_vaq, v128q, v128q, 4>;
// Add compute carry.
+ def VACC : BinaryVRRcGeneric<"vacc", 0xE7F1>;
def VACCB : BinaryVRRc<"vaccb", 0xE7F1, int_s390_vaccb, v128b, v128b, 0>;
def VACCH : BinaryVRRc<"vacch", 0xE7F1, int_s390_vacch, v128h, v128h, 1>;
def VACCF : BinaryVRRc<"vaccf", 0xE7F1, int_s390_vaccf, v128f, v128f, 2>;
@@ -357,9 +376,11 @@ let Predicates = [FeatureVector] in {
def VACCQ : BinaryVRRc<"vaccq", 0xE7F1, int_s390_vaccq, v128q, v128q, 4>;
// Add with carry.
+ def VAC : TernaryVRRdGeneric<"vac", 0xE7BB>;
def VACQ : TernaryVRRd<"vacq", 0xE7BB, int_s390_vacq, v128q, v128q, 4>;
// Add with carry compute carry.
+ def VACCC : TernaryVRRdGeneric<"vaccc", 0xE7B9>;
def VACCCQ : TernaryVRRd<"vacccq", 0xE7B9, int_s390_vacccq, v128q, v128q, 4>;
// And.
@@ -369,12 +390,14 @@ let Predicates = [FeatureVector] in {
def VNC : BinaryVRRc<"vnc", 0xE769, null_frag, v128any, v128any>;
// Average.
+ def VAVG : BinaryVRRcGeneric<"vavg", 0xE7F2>;
def VAVGB : BinaryVRRc<"vavgb", 0xE7F2, int_s390_vavgb, v128b, v128b, 0>;
def VAVGH : BinaryVRRc<"vavgh", 0xE7F2, int_s390_vavgh, v128h, v128h, 1>;
def VAVGF : BinaryVRRc<"vavgf", 0xE7F2, int_s390_vavgf, v128f, v128f, 2>;
def VAVGG : BinaryVRRc<"vavgg", 0xE7F2, int_s390_vavgg, v128g, v128g, 3>;
// Average logical.
+ def VAVGL : BinaryVRRcGeneric<"vavgl", 0xE7F0>;
def VAVGLB : BinaryVRRc<"vavglb", 0xE7F0, int_s390_vavglb, v128b, v128b, 0>;
def VAVGLH : BinaryVRRc<"vavglh", 0xE7F0, int_s390_vavglh, v128h, v128h, 1>;
def VAVGLF : BinaryVRRc<"vavglf", 0xE7F0, int_s390_vavglf, v128f, v128f, 2>;
@@ -384,12 +407,14 @@ let Predicates = [FeatureVector] in {
def VCKSM : BinaryVRRc<"vcksm", 0xE766, int_s390_vcksm, v128f, v128f>;
// Count leading zeros.
+ def VCLZ : UnaryVRRaGeneric<"vclz", 0xE753>;
def VCLZB : UnaryVRRa<"vclzb", 0xE753, ctlz, v128b, v128b, 0>;
def VCLZH : UnaryVRRa<"vclzh", 0xE753, ctlz, v128h, v128h, 1>;
def VCLZF : UnaryVRRa<"vclzf", 0xE753, ctlz, v128f, v128f, 2>;
def VCLZG : UnaryVRRa<"vclzg", 0xE753, ctlz, v128g, v128g, 3>;
// Count trailing zeros.
+ def VCTZ : UnaryVRRaGeneric<"vctz", 0xE752>;
def VCTZB : UnaryVRRa<"vctzb", 0xE752, cttz, v128b, v128b, 0>;
def VCTZH : UnaryVRRa<"vctzh", 0xE752, cttz, v128h, v128h, 1>;
def VCTZF : UnaryVRRa<"vctzf", 0xE752, cttz, v128f, v128f, 2>;
@@ -399,134 +424,158 @@ let Predicates = [FeatureVector] in {
def VX : BinaryVRRc<"vx", 0xE76D, null_frag, v128any, v128any>;
// Galois field multiply sum.
+ def VGFM : BinaryVRRcGeneric<"vgfm", 0xE7B4>;
def VGFMB : BinaryVRRc<"vgfmb", 0xE7B4, int_s390_vgfmb, v128h, v128b, 0>;
def VGFMH : BinaryVRRc<"vgfmh", 0xE7B4, int_s390_vgfmh, v128f, v128h, 1>;
def VGFMF : BinaryVRRc<"vgfmf", 0xE7B4, int_s390_vgfmf, v128g, v128f, 2>;
def VGFMG : BinaryVRRc<"vgfmg", 0xE7B4, int_s390_vgfmg, v128q, v128g, 3>;
// Galois field multiply sum and accumulate.
+ def VGFMA : TernaryVRRdGeneric<"vgfma", 0xE7BC>;
def VGFMAB : TernaryVRRd<"vgfmab", 0xE7BC, int_s390_vgfmab, v128h, v128b, 0>;
def VGFMAH : TernaryVRRd<"vgfmah", 0xE7BC, int_s390_vgfmah, v128f, v128h, 1>;
def VGFMAF : TernaryVRRd<"vgfmaf", 0xE7BC, int_s390_vgfmaf, v128g, v128f, 2>;
def VGFMAG : TernaryVRRd<"vgfmag", 0xE7BC, int_s390_vgfmag, v128q, v128g, 3>;
// Load complement.
+ def VLC : UnaryVRRaGeneric<"vlc", 0xE7DE>;
def VLCB : UnaryVRRa<"vlcb", 0xE7DE, z_vneg, v128b, v128b, 0>;
def VLCH : UnaryVRRa<"vlch", 0xE7DE, z_vneg, v128h, v128h, 1>;
def VLCF : UnaryVRRa<"vlcf", 0xE7DE, z_vneg, v128f, v128f, 2>;
def VLCG : UnaryVRRa<"vlcg", 0xE7DE, z_vneg, v128g, v128g, 3>;
// Load positive.
+ def VLP : UnaryVRRaGeneric<"vlp", 0xE7DF>;
def VLPB : UnaryVRRa<"vlpb", 0xE7DF, z_viabs8, v128b, v128b, 0>;
def VLPH : UnaryVRRa<"vlph", 0xE7DF, z_viabs16, v128h, v128h, 1>;
def VLPF : UnaryVRRa<"vlpf", 0xE7DF, z_viabs32, v128f, v128f, 2>;
def VLPG : UnaryVRRa<"vlpg", 0xE7DF, z_viabs64, v128g, v128g, 3>;
// Maximum.
+ def VMX : BinaryVRRcGeneric<"vmx", 0xE7FF>;
def VMXB : BinaryVRRc<"vmxb", 0xE7FF, null_frag, v128b, v128b, 0>;
def VMXH : BinaryVRRc<"vmxh", 0xE7FF, null_frag, v128h, v128h, 1>;
def VMXF : BinaryVRRc<"vmxf", 0xE7FF, null_frag, v128f, v128f, 2>;
def VMXG : BinaryVRRc<"vmxg", 0xE7FF, null_frag, v128g, v128g, 3>;
// Maximum logical.
+ def VMXL : BinaryVRRcGeneric<"vmxl", 0xE7FD>;
def VMXLB : BinaryVRRc<"vmxlb", 0xE7FD, null_frag, v128b, v128b, 0>;
def VMXLH : BinaryVRRc<"vmxlh", 0xE7FD, null_frag, v128h, v128h, 1>;
def VMXLF : BinaryVRRc<"vmxlf", 0xE7FD, null_frag, v128f, v128f, 2>;
def VMXLG : BinaryVRRc<"vmxlg", 0xE7FD, null_frag, v128g, v128g, 3>;
// Minimum.
+ def VMN : BinaryVRRcGeneric<"vmn", 0xE7FE>;
def VMNB : BinaryVRRc<"vmnb", 0xE7FE, null_frag, v128b, v128b, 0>;
def VMNH : BinaryVRRc<"vmnh", 0xE7FE, null_frag, v128h, v128h, 1>;
def VMNF : BinaryVRRc<"vmnf", 0xE7FE, null_frag, v128f, v128f, 2>;
def VMNG : BinaryVRRc<"vmng", 0xE7FE, null_frag, v128g, v128g, 3>;
// Minimum logical.
+ def VMNL : BinaryVRRcGeneric<"vmnl", 0xE7FC>;
def VMNLB : BinaryVRRc<"vmnlb", 0xE7FC, null_frag, v128b, v128b, 0>;
def VMNLH : BinaryVRRc<"vmnlh", 0xE7FC, null_frag, v128h, v128h, 1>;
def VMNLF : BinaryVRRc<"vmnlf", 0xE7FC, null_frag, v128f, v128f, 2>;
def VMNLG : BinaryVRRc<"vmnlg", 0xE7FC, null_frag, v128g, v128g, 3>;
// Multiply and add low.
+ def VMAL : TernaryVRRdGeneric<"vmal", 0xE7AA>;
def VMALB : TernaryVRRd<"vmalb", 0xE7AA, z_muladd, v128b, v128b, 0>;
def VMALHW : TernaryVRRd<"vmalhw", 0xE7AA, z_muladd, v128h, v128h, 1>;
def VMALF : TernaryVRRd<"vmalf", 0xE7AA, z_muladd, v128f, v128f, 2>;
// Multiply and add high.
+ def VMAH : TernaryVRRdGeneric<"vmah", 0xE7AB>;
def VMAHB : TernaryVRRd<"vmahb", 0xE7AB, int_s390_vmahb, v128b, v128b, 0>;
def VMAHH : TernaryVRRd<"vmahh", 0xE7AB, int_s390_vmahh, v128h, v128h, 1>;
def VMAHF : TernaryVRRd<"vmahf", 0xE7AB, int_s390_vmahf, v128f, v128f, 2>;
// Multiply and add logical high.
+ def VMALH : TernaryVRRdGeneric<"vmalh", 0xE7A9>;
def VMALHB : TernaryVRRd<"vmalhb", 0xE7A9, int_s390_vmalhb, v128b, v128b, 0>;
def VMALHH : TernaryVRRd<"vmalhh", 0xE7A9, int_s390_vmalhh, v128h, v128h, 1>;
def VMALHF : TernaryVRRd<"vmalhf", 0xE7A9, int_s390_vmalhf, v128f, v128f, 2>;
// Multiply and add even.
+ def VMAE : TernaryVRRdGeneric<"vmae", 0xE7AE>;
def VMAEB : TernaryVRRd<"vmaeb", 0xE7AE, int_s390_vmaeb, v128h, v128b, 0>;
def VMAEH : TernaryVRRd<"vmaeh", 0xE7AE, int_s390_vmaeh, v128f, v128h, 1>;
def VMAEF : TernaryVRRd<"vmaef", 0xE7AE, int_s390_vmaef, v128g, v128f, 2>;
// Multiply and add logical even.
+ def VMALE : TernaryVRRdGeneric<"vmale", 0xE7AC>;
def VMALEB : TernaryVRRd<"vmaleb", 0xE7AC, int_s390_vmaleb, v128h, v128b, 0>;
def VMALEH : TernaryVRRd<"vmaleh", 0xE7AC, int_s390_vmaleh, v128f, v128h, 1>;
def VMALEF : TernaryVRRd<"vmalef", 0xE7AC, int_s390_vmalef, v128g, v128f, 2>;
// Multiply and add odd.
+ def VMAO : TernaryVRRdGeneric<"vmao", 0xE7AF>;
def VMAOB : TernaryVRRd<"vmaob", 0xE7AF, int_s390_vmaob, v128h, v128b, 0>;
def VMAOH : TernaryVRRd<"vmaoh", 0xE7AF, int_s390_vmaoh, v128f, v128h, 1>;
def VMAOF : TernaryVRRd<"vmaof", 0xE7AF, int_s390_vmaof, v128g, v128f, 2>;
// Multiply and add logical odd.
+ def VMALO : TernaryVRRdGeneric<"vmalo", 0xE7AD>;
def VMALOB : TernaryVRRd<"vmalob", 0xE7AD, int_s390_vmalob, v128h, v128b, 0>;
def VMALOH : TernaryVRRd<"vmaloh", 0xE7AD, int_s390_vmaloh, v128f, v128h, 1>;
def VMALOF : TernaryVRRd<"vmalof", 0xE7AD, int_s390_vmalof, v128g, v128f, 2>;
// Multiply high.
+ def VMH : BinaryVRRcGeneric<"vmh", 0xE7A3>;
def VMHB : BinaryVRRc<"vmhb", 0xE7A3, int_s390_vmhb, v128b, v128b, 0>;
def VMHH : BinaryVRRc<"vmhh", 0xE7A3, int_s390_vmhh, v128h, v128h, 1>;
def VMHF : BinaryVRRc<"vmhf", 0xE7A3, int_s390_vmhf, v128f, v128f, 2>;
// Multiply logical high.
+ def VMLH : BinaryVRRcGeneric<"vmlh", 0xE7A1>;
def VMLHB : BinaryVRRc<"vmlhb", 0xE7A1, int_s390_vmlhb, v128b, v128b, 0>;
def VMLHH : BinaryVRRc<"vmlhh", 0xE7A1, int_s390_vmlhh, v128h, v128h, 1>;
def VMLHF : BinaryVRRc<"vmlhf", 0xE7A1, int_s390_vmlhf, v128f, v128f, 2>;
// Multiply low.
+ def VML : BinaryVRRcGeneric<"vml", 0xE7A2>;
def VMLB : BinaryVRRc<"vmlb", 0xE7A2, mul, v128b, v128b, 0>;
def VMLHW : BinaryVRRc<"vmlhw", 0xE7A2, mul, v128h, v128h, 1>;
def VMLF : BinaryVRRc<"vmlf", 0xE7A2, mul, v128f, v128f, 2>;
// Multiply even.
+ def VME : BinaryVRRcGeneric<"vme", 0xE7A6>;
def VMEB : BinaryVRRc<"vmeb", 0xE7A6, int_s390_vmeb, v128h, v128b, 0>;
def VMEH : BinaryVRRc<"vmeh", 0xE7A6, int_s390_vmeh, v128f, v128h, 1>;
def VMEF : BinaryVRRc<"vmef", 0xE7A6, int_s390_vmef, v128g, v128f, 2>;
// Multiply logical even.
+ def VMLE : BinaryVRRcGeneric<"vmle", 0xE7A4>;
def VMLEB : BinaryVRRc<"vmleb", 0xE7A4, int_s390_vmleb, v128h, v128b, 0>;
def VMLEH : BinaryVRRc<"vmleh", 0xE7A4, int_s390_vmleh, v128f, v128h, 1>;
def VMLEF : BinaryVRRc<"vmlef", 0xE7A4, int_s390_vmlef, v128g, v128f, 2>;
// Multiply odd.
+ def VMO : BinaryVRRcGeneric<"vmo", 0xE7A7>;
def VMOB : BinaryVRRc<"vmob", 0xE7A7, int_s390_vmob, v128h, v128b, 0>;
def VMOH : BinaryVRRc<"vmoh", 0xE7A7, int_s390_vmoh, v128f, v128h, 1>;
def VMOF : BinaryVRRc<"vmof", 0xE7A7, int_s390_vmof, v128g, v128f, 2>;
// Multiply logical odd.
+ def VMLO : BinaryVRRcGeneric<"vmlo", 0xE7A5>;
def VMLOB : BinaryVRRc<"vmlob", 0xE7A5, int_s390_vmlob, v128h, v128b, 0>;
def VMLOH : BinaryVRRc<"vmloh", 0xE7A5, int_s390_vmloh, v128f, v128h, 1>;
def VMLOF : BinaryVRRc<"vmlof", 0xE7A5, int_s390_vmlof, v128g, v128f, 2>;
// Nor.
def VNO : BinaryVRRc<"vno", 0xE76B, null_frag, v128any, v128any>;
+ def : InstAlias<"vnot\t$V1, $V2", (VNO VR128:$V1, VR128:$V2, VR128:$V2), 0>;
// Or.
def VO : BinaryVRRc<"vo", 0xE76A, null_frag, v128any, v128any>;
// Population count.
- def VPOPCT : BinaryVRRa<"vpopct", 0xE750>;
+ def VPOPCT : UnaryVRRaGeneric<"vpopct", 0xE750>;
def : Pat<(v16i8 (z_popcnt VR128:$x)), (VPOPCT VR128:$x, 0)>;
// Element rotate left logical (with vector shift amount).
+ def VERLLV : BinaryVRRcGeneric<"verllv", 0xE773>;
def VERLLVB : BinaryVRRc<"verllvb", 0xE773, int_s390_verllvb,
v128b, v128b, 0>;
def VERLLVH : BinaryVRRc<"verllvh", 0xE773, int_s390_verllvh,
@@ -537,48 +586,56 @@ let Predicates = [FeatureVector] in {
v128g, v128g, 3>;
// Element rotate left logical (with scalar shift amount).
+ def VERLL : BinaryVRSaGeneric<"verll", 0xE733>;
def VERLLB : BinaryVRSa<"verllb", 0xE733, int_s390_verllb, v128b, v128b, 0>;
def VERLLH : BinaryVRSa<"verllh", 0xE733, int_s390_verllh, v128h, v128h, 1>;
def VERLLF : BinaryVRSa<"verllf", 0xE733, int_s390_verllf, v128f, v128f, 2>;
def VERLLG : BinaryVRSa<"verllg", 0xE733, int_s390_verllg, v128g, v128g, 3>;
// Element rotate and insert under mask.
+ def VERIM : QuaternaryVRIdGeneric<"verim", 0xE772>;
def VERIMB : QuaternaryVRId<"verimb", 0xE772, int_s390_verimb, v128b, v128b, 0>;
def VERIMH : QuaternaryVRId<"verimh", 0xE772, int_s390_verimh, v128h, v128h, 1>;
def VERIMF : QuaternaryVRId<"verimf", 0xE772, int_s390_verimf, v128f, v128f, 2>;
def VERIMG : QuaternaryVRId<"verimg", 0xE772, int_s390_verimg, v128g, v128g, 3>;
// Element shift left (with vector shift amount).
+ def VESLV : BinaryVRRcGeneric<"veslv", 0xE770>;
def VESLVB : BinaryVRRc<"veslvb", 0xE770, z_vshl, v128b, v128b, 0>;
def VESLVH : BinaryVRRc<"veslvh", 0xE770, z_vshl, v128h, v128h, 1>;
def VESLVF : BinaryVRRc<"veslvf", 0xE770, z_vshl, v128f, v128f, 2>;
def VESLVG : BinaryVRRc<"veslvg", 0xE770, z_vshl, v128g, v128g, 3>;
// Element shift left (with scalar shift amount).
+ def VESL : BinaryVRSaGeneric<"vesl", 0xE730>;
def VESLB : BinaryVRSa<"veslb", 0xE730, z_vshl_by_scalar, v128b, v128b, 0>;
def VESLH : BinaryVRSa<"veslh", 0xE730, z_vshl_by_scalar, v128h, v128h, 1>;
def VESLF : BinaryVRSa<"veslf", 0xE730, z_vshl_by_scalar, v128f, v128f, 2>;
def VESLG : BinaryVRSa<"veslg", 0xE730, z_vshl_by_scalar, v128g, v128g, 3>;
// Element shift right arithmetic (with vector shift amount).
+ def VESRAV : BinaryVRRcGeneric<"vesrav", 0xE77A>;
def VESRAVB : BinaryVRRc<"vesravb", 0xE77A, z_vsra, v128b, v128b, 0>;
def VESRAVH : BinaryVRRc<"vesravh", 0xE77A, z_vsra, v128h, v128h, 1>;
def VESRAVF : BinaryVRRc<"vesravf", 0xE77A, z_vsra, v128f, v128f, 2>;
def VESRAVG : BinaryVRRc<"vesravg", 0xE77A, z_vsra, v128g, v128g, 3>;
// Element shift right arithmetic (with scalar shift amount).
+ def VESRA : BinaryVRSaGeneric<"vesra", 0xE73A>;
def VESRAB : BinaryVRSa<"vesrab", 0xE73A, z_vsra_by_scalar, v128b, v128b, 0>;
def VESRAH : BinaryVRSa<"vesrah", 0xE73A, z_vsra_by_scalar, v128h, v128h, 1>;
def VESRAF : BinaryVRSa<"vesraf", 0xE73A, z_vsra_by_scalar, v128f, v128f, 2>;
def VESRAG : BinaryVRSa<"vesrag", 0xE73A, z_vsra_by_scalar, v128g, v128g, 3>;
// Element shift right logical (with vector shift amount).
+ def VESRLV : BinaryVRRcGeneric<"vesrlv", 0xE778>;
def VESRLVB : BinaryVRRc<"vesrlvb", 0xE778, z_vsrl, v128b, v128b, 0>;
def VESRLVH : BinaryVRRc<"vesrlvh", 0xE778, z_vsrl, v128h, v128h, 1>;
def VESRLVF : BinaryVRRc<"vesrlvf", 0xE778, z_vsrl, v128f, v128f, 2>;
def VESRLVG : BinaryVRRc<"vesrlvg", 0xE778, z_vsrl, v128g, v128g, 3>;
// Element shift right logical (with scalar shift amount).
+ def VESRL : BinaryVRSaGeneric<"vesrl", 0xE738>;
def VESRLB : BinaryVRSa<"vesrlb", 0xE738, z_vsrl_by_scalar, v128b, v128b, 0>;
def VESRLH : BinaryVRSa<"vesrlh", 0xE738, z_vsrl_by_scalar, v128h, v128h, 1>;
def VESRLF : BinaryVRSa<"vesrlf", 0xE738, z_vsrl_by_scalar, v128f, v128f, 2>;
@@ -608,6 +665,7 @@ let Predicates = [FeatureVector] in {
def VSRLB : BinaryVRRc<"vsrlb", 0xE77D, int_s390_vsrlb, v128b, v128b>;
// Subtract.
+ def VS : BinaryVRRcGeneric<"vs", 0xE7F7>;
def VSB : BinaryVRRc<"vsb", 0xE7F7, sub, v128b, v128b, 0>;
def VSH : BinaryVRRc<"vsh", 0xE7F7, sub, v128h, v128h, 1>;
def VSF : BinaryVRRc<"vsf", 0xE7F7, sub, v128f, v128f, 2>;
@@ -615,6 +673,7 @@ let Predicates = [FeatureVector] in {
def VSQ : BinaryVRRc<"vsq", 0xE7F7, int_s390_vsq, v128q, v128q, 4>;
// Subtract compute borrow indication.
+ def VSCBI : BinaryVRRcGeneric<"vscbi", 0xE7F5>;
def VSCBIB : BinaryVRRc<"vscbib", 0xE7F5, int_s390_vscbib, v128b, v128b, 0>;
def VSCBIH : BinaryVRRc<"vscbih", 0xE7F5, int_s390_vscbih, v128h, v128h, 1>;
def VSCBIF : BinaryVRRc<"vscbif", 0xE7F5, int_s390_vscbif, v128f, v128f, 2>;
@@ -622,21 +681,26 @@ let Predicates = [FeatureVector] in {
def VSCBIQ : BinaryVRRc<"vscbiq", 0xE7F5, int_s390_vscbiq, v128q, v128q, 4>;
// Subtract with borrow indication.
+ def VSBI : TernaryVRRdGeneric<"vsbi", 0xE7BF>;
def VSBIQ : TernaryVRRd<"vsbiq", 0xE7BF, int_s390_vsbiq, v128q, v128q, 4>;
// Subtract with borrow compute borrow indication.
+ def VSBCBI : TernaryVRRdGeneric<"vsbcbi", 0xE7BD>;
def VSBCBIQ : TernaryVRRd<"vsbcbiq", 0xE7BD, int_s390_vsbcbiq,
v128q, v128q, 4>;
// Sum across doubleword.
+ def VSUMG : BinaryVRRcGeneric<"vsumg", 0xE765>;
def VSUMGH : BinaryVRRc<"vsumgh", 0xE765, z_vsum, v128g, v128h, 1>;
def VSUMGF : BinaryVRRc<"vsumgf", 0xE765, z_vsum, v128g, v128f, 2>;
// Sum across quadword.
+ def VSUMQ : BinaryVRRcGeneric<"vsumq", 0xE767>;
def VSUMQF : BinaryVRRc<"vsumqf", 0xE767, z_vsum, v128q, v128f, 2>;
def VSUMQG : BinaryVRRc<"vsumqg", 0xE767, z_vsum, v128q, v128g, 3>;
// Sum across word.
+ def VSUM : BinaryVRRcGeneric<"vsum", 0xE764>;
def VSUMB : BinaryVRRc<"vsumb", 0xE764, z_vsum, v128f, v128b, 0>;
def VSUMH : BinaryVRRc<"vsumh", 0xE764, z_vsum, v128f, v128h, 1>;
}
@@ -737,6 +801,7 @@ defm : IntegerMinMaxVectorOps<v2i64, z_vicmphl, VMNLG, VMXLG>;
let Predicates = [FeatureVector] in {
// Element compare.
let Defs = [CC] in {
+ def VEC : CompareVRRaGeneric<"vec", 0xE7DB>;
def VECB : CompareVRRa<"vecb", 0xE7DB, null_frag, v128b, 0>;
def VECH : CompareVRRa<"vech", 0xE7DB, null_frag, v128h, 1>;
def VECF : CompareVRRa<"vecf", 0xE7DB, null_frag, v128f, 2>;
@@ -745,6 +810,7 @@ let Predicates = [FeatureVector] in {
// Element compare logical.
let Defs = [CC] in {
+ def VECL : CompareVRRaGeneric<"vecl", 0xE7D9>;
def VECLB : CompareVRRa<"veclb", 0xE7D9, null_frag, v128b, 0>;
def VECLH : CompareVRRa<"veclh", 0xE7D9, null_frag, v128h, 1>;
def VECLF : CompareVRRa<"veclf", 0xE7D9, null_frag, v128f, 2>;
@@ -752,6 +818,7 @@ let Predicates = [FeatureVector] in {
}
// Compare equal.
+ def VCEQ : BinaryVRRbSPairGeneric<"vceq", 0xE7F8>;
defm VCEQB : BinaryVRRbSPair<"vceqb", 0xE7F8, z_vicmpe, z_vicmpes,
v128b, v128b, 0>;
defm VCEQH : BinaryVRRbSPair<"vceqh", 0xE7F8, z_vicmpe, z_vicmpes,
@@ -762,6 +829,7 @@ let Predicates = [FeatureVector] in {
v128g, v128g, 3>;
// Compare high.
+ def VCH : BinaryVRRbSPairGeneric<"vch", 0xE7FB>;
defm VCHB : BinaryVRRbSPair<"vchb", 0xE7FB, z_vicmph, z_vicmphs,
v128b, v128b, 0>;
defm VCHH : BinaryVRRbSPair<"vchh", 0xE7FB, z_vicmph, z_vicmphs,
@@ -772,6 +840,7 @@ let Predicates = [FeatureVector] in {
v128g, v128g, 3>;
// Compare high logical.
+ def VCHL : BinaryVRRbSPairGeneric<"vchl", 0xE7F9>;
defm VCHLB : BinaryVRRbSPair<"vchlb", 0xE7F9, z_vicmphl, z_vicmphls,
v128b, v128b, 0>;
defm VCHLH : BinaryVRRbSPair<"vchlh", 0xE7F9, z_vicmphl, z_vicmphls,
@@ -798,69 +867,86 @@ multiclass VectorRounding<Instruction insn, TypedReg tr> {
def : FPConversion<insn, ffloor, tr, tr, 4, 7>;
def : FPConversion<insn, fceil, tr, tr, 4, 6>;
def : FPConversion<insn, ftrunc, tr, tr, 4, 5>;
- def : FPConversion<insn, frnd, tr, tr, 4, 1>;
+ def : FPConversion<insn, fround, tr, tr, 4, 1>;
}
let Predicates = [FeatureVector] in {
// Add.
+ def VFA : BinaryVRRcFloatGeneric<"vfa", 0xE7E3>;
def VFADB : BinaryVRRc<"vfadb", 0xE7E3, fadd, v128db, v128db, 3, 0>;
def WFADB : BinaryVRRc<"wfadb", 0xE7E3, fadd, v64db, v64db, 3, 8>;
// Convert from fixed 64-bit.
+ def VCDG : TernaryVRRaFloatGeneric<"vcdg", 0xE7C3>;
def VCDGB : TernaryVRRa<"vcdgb", 0xE7C3, null_frag, v128db, v128g, 3, 0>;
def WCDGB : TernaryVRRa<"wcdgb", 0xE7C3, null_frag, v64db, v64g, 3, 8>;
def : FPConversion<VCDGB, sint_to_fp, v128db, v128g, 0, 0>;
// Convert from logical 64-bit.
+ def VCDLG : TernaryVRRaFloatGeneric<"vcdlg", 0xE7C1>;
def VCDLGB : TernaryVRRa<"vcdlgb", 0xE7C1, null_frag, v128db, v128g, 3, 0>;
def WCDLGB : TernaryVRRa<"wcdlgb", 0xE7C1, null_frag, v64db, v64g, 3, 8>;
def : FPConversion<VCDLGB, uint_to_fp, v128db, v128g, 0, 0>;
// Convert to fixed 64-bit.
+ def VCGD : TernaryVRRaFloatGeneric<"vcgd", 0xE7C2>;
def VCGDB : TernaryVRRa<"vcgdb", 0xE7C2, null_frag, v128g, v128db, 3, 0>;
def WCGDB : TernaryVRRa<"wcgdb", 0xE7C2, null_frag, v64g, v64db, 3, 8>;
// Rounding mode should agree with SystemZInstrFP.td.
def : FPConversion<VCGDB, fp_to_sint, v128g, v128db, 0, 5>;
// Convert to logical 64-bit.
+ def VCLGD : TernaryVRRaFloatGeneric<"vclgd", 0xE7C0>;
def VCLGDB : TernaryVRRa<"vclgdb", 0xE7C0, null_frag, v128g, v128db, 3, 0>;
def WCLGDB : TernaryVRRa<"wclgdb", 0xE7C0, null_frag, v64g, v64db, 3, 8>;
// Rounding mode should agree with SystemZInstrFP.td.
def : FPConversion<VCLGDB, fp_to_uint, v128g, v128db, 0, 5>;
// Divide.
+ def VFD : BinaryVRRcFloatGeneric<"vfd", 0xE7E5>;
def VFDDB : BinaryVRRc<"vfddb", 0xE7E5, fdiv, v128db, v128db, 3, 0>;
def WFDDB : BinaryVRRc<"wfddb", 0xE7E5, fdiv, v64db, v64db, 3, 8>;
// Load FP integer.
+ def VFI : TernaryVRRaFloatGeneric<"vfi", 0xE7C7>;
def VFIDB : TernaryVRRa<"vfidb", 0xE7C7, int_s390_vfidb, v128db, v128db, 3, 0>;
def WFIDB : TernaryVRRa<"wfidb", 0xE7C7, null_frag, v64db, v64db, 3, 8>;
defm : VectorRounding<VFIDB, v128db>;
defm : VectorRounding<WFIDB, v64db>;
// Load lengthened.
+ def VLDE : UnaryVRRaFloatGeneric<"vlde", 0xE7C4>;
def VLDEB : UnaryVRRa<"vldeb", 0xE7C4, z_vextend, v128db, v128eb, 2, 0>;
- def WLDEB : UnaryVRRa<"wldeb", 0xE7C4, fextend, v64db, v32eb, 2, 8>;
+ def WLDEB : UnaryVRRa<"wldeb", 0xE7C4, fpextend, v64db, v32eb, 2, 8>;
// Load rounded,
+ def VLED : TernaryVRRaFloatGeneric<"vled", 0xE7C5>;
def VLEDB : TernaryVRRa<"vledb", 0xE7C5, null_frag, v128eb, v128db, 3, 0>;
def WLEDB : TernaryVRRa<"wledb", 0xE7C5, null_frag, v32eb, v64db, 3, 8>;
def : Pat<(v4f32 (z_vround (v2f64 VR128:$src))), (VLEDB VR128:$src, 0, 0)>;
- def : FPConversion<WLEDB, fround, v32eb, v64db, 0, 0>;
+ def : FPConversion<WLEDB, fpround, v32eb, v64db, 0, 0>;
// Multiply.
+ def VFM : BinaryVRRcFloatGeneric<"vfm", 0xE7E7>;
def VFMDB : BinaryVRRc<"vfmdb", 0xE7E7, fmul, v128db, v128db, 3, 0>;
def WFMDB : BinaryVRRc<"wfmdb", 0xE7E7, fmul, v64db, v64db, 3, 8>;
// Multiply and add.
+ def VFMA : TernaryVRReFloatGeneric<"vfma", 0xE78F>;
def VFMADB : TernaryVRRe<"vfmadb", 0xE78F, fma, v128db, v128db, 0, 3>;
def WFMADB : TernaryVRRe<"wfmadb", 0xE78F, fma, v64db, v64db, 8, 3>;
// Multiply and subtract.
+ def VFMS : TernaryVRReFloatGeneric<"vfms", 0xE78E>;
def VFMSDB : TernaryVRRe<"vfmsdb", 0xE78E, fms, v128db, v128db, 0, 3>;
def WFMSDB : TernaryVRRe<"wfmsdb", 0xE78E, fms, v64db, v64db, 8, 3>;
- // Load complement,
+ // Perform sign operation.
+ def VFPSO : BinaryVRRaFloatGeneric<"vfpso", 0xE7CC>;
+ def VFPSODB : BinaryVRRa<"vfpsodb", 0xE7CC, null_frag, v128db, v128db, 3, 0>;
+ def WFPSODB : BinaryVRRa<"wfpsodb", 0xE7CC, null_frag, v64db, v64db, 3, 8>;
+
+ // Load complement.
def VFLCDB : UnaryVRRa<"vflcdb", 0xE7CC, fneg, v128db, v128db, 3, 0, 0>;
def WFLCDB : UnaryVRRa<"wflcdb", 0xE7CC, fneg, v64db, v64db, 3, 8, 0>;
@@ -873,15 +959,18 @@ let Predicates = [FeatureVector] in {
def WFLPDB : UnaryVRRa<"wflpdb", 0xE7CC, fabs, v64db, v64db, 3, 8, 2>;
// Square root.
+ def VFSQ : UnaryVRRaFloatGeneric<"vfsq", 0xE7CE>;
def VFSQDB : UnaryVRRa<"vfsqdb", 0xE7CE, fsqrt, v128db, v128db, 3, 0>;
def WFSQDB : UnaryVRRa<"wfsqdb", 0xE7CE, fsqrt, v64db, v64db, 3, 8>;
// Subtract.
+ def VFS : BinaryVRRcFloatGeneric<"vfs", 0xE7E2>;
def VFSDB : BinaryVRRc<"vfsdb", 0xE7E2, fsub, v128db, v128db, 3, 0>;
def WFSDB : BinaryVRRc<"wfsdb", 0xE7E2, fsub, v64db, v64db, 3, 8>;
// Test data class immediate.
let Defs = [CC] in {
+ def VFTCI : BinaryVRIeFloatGeneric<"vftci", 0xE74A>;
def VFTCIDB : BinaryVRIe<"vftcidb", 0xE74A, z_vftci, v128g, v128db, 3, 0>;
def WFTCIDB : BinaryVRIe<"wftcidb", 0xE74A, null_frag, v64g, v64db, 3, 8>;
}
@@ -893,26 +982,33 @@ let Predicates = [FeatureVector] in {
let Predicates = [FeatureVector] in {
// Compare scalar.
- let Defs = [CC] in
+ let Defs = [CC] in {
+ def WFC : CompareVRRaFloatGeneric<"wfc", 0xE7CB>;
def WFCDB : CompareVRRa<"wfcdb", 0xE7CB, z_fcmp, v64db, 3>;
+ }
// Compare and signal scalar.
- let Defs = [CC] in
+ let Defs = [CC] in {
+ def WFK : CompareVRRaFloatGeneric<"wfk", 0xE7CA>;
def WFKDB : CompareVRRa<"wfkdb", 0xE7CA, null_frag, v64db, 3>;
+ }
// Compare equal.
+ def VFCE : BinaryVRRcSPairFloatGeneric<"vfce", 0xE7E8>;
defm VFCEDB : BinaryVRRcSPair<"vfcedb", 0xE7E8, z_vfcmpe, z_vfcmpes,
v128g, v128db, 3, 0>;
defm WFCEDB : BinaryVRRcSPair<"wfcedb", 0xE7E8, null_frag, null_frag,
v64g, v64db, 3, 8>;
// Compare high.
+ def VFCH : BinaryVRRcSPairFloatGeneric<"vfch", 0xE7EB>;
defm VFCHDB : BinaryVRRcSPair<"vfchdb", 0xE7EB, z_vfcmph, z_vfcmphs,
v128g, v128db, 3, 0>;
defm WFCHDB : BinaryVRRcSPair<"wfchdb", 0xE7EB, null_frag, null_frag,
v64g, v64db, 3, 8>;
// Compare high or equal.
+ def VFCHE : BinaryVRRcSPairFloatGeneric<"vfche", 0xE7EA>;
defm VFCHEDB : BinaryVRRcSPair<"vfchedb", 0xE7EA, z_vfcmphe, z_vfcmphes,
v128g, v128db, 3, 0>;
defm WFCHEDB : BinaryVRRcSPair<"wfchedb", 0xE7EA, null_frag, null_frag,
@@ -983,11 +1079,13 @@ def : Pat<(v2i64 (z_replicate GR64:$scalar)),
// Moving 32-bit values between GPRs and FPRs can be done using VLVGF
// and VLGVF.
-def LEFR : UnaryAliasVRS<VR32, GR32>;
-def LFER : UnaryAliasVRS<GR64, VR32>;
-def : Pat<(f32 (bitconvert (i32 GR32:$src))), (LEFR GR32:$src)>;
-def : Pat<(i32 (bitconvert (f32 VR32:$src))),
- (EXTRACT_SUBREG (LFER VR32:$src), subreg_l32)>;
+let Predicates = [FeatureVector] in {
+ def LEFR : UnaryAliasVRS<VR32, GR32>;
+ def LFER : UnaryAliasVRS<GR64, VR32>;
+ def : Pat<(f32 (bitconvert (i32 GR32:$src))), (LEFR GR32:$src)>;
+ def : Pat<(i32 (bitconvert (f32 VR32:$src))),
+ (EXTRACT_SUBREG (LFER VR32:$src), subreg_l32)>;
+}
// Floating-point values are stored in element 0 of the corresponding
// vector register. Scalar to vector conversion is just a subreg and
@@ -1036,62 +1134,67 @@ let AddedComplexity = 4 in {
//===----------------------------------------------------------------------===//
let Predicates = [FeatureVector] in {
- defm VFAEB : TernaryVRRbSPair<"vfaeb", 0xE782, int_s390_vfaeb, z_vfae_cc,
- v128b, v128b, 0, 0>;
- defm VFAEH : TernaryVRRbSPair<"vfaeh", 0xE782, int_s390_vfaeh, z_vfae_cc,
- v128h, v128h, 1, 0>;
- defm VFAEF : TernaryVRRbSPair<"vfaef", 0xE782, int_s390_vfaef, z_vfae_cc,
- v128f, v128f, 2, 0>;
- defm VFAEZB : TernaryVRRbSPair<"vfaezb", 0xE782, int_s390_vfaezb, z_vfaez_cc,
- v128b, v128b, 0, 2>;
- defm VFAEZH : TernaryVRRbSPair<"vfaezh", 0xE782, int_s390_vfaezh, z_vfaez_cc,
- v128h, v128h, 1, 2>;
- defm VFAEZF : TernaryVRRbSPair<"vfaezf", 0xE782, int_s390_vfaezf, z_vfaez_cc,
- v128f, v128f, 2, 2>;
-
- defm VFEEB : BinaryVRRbSPair<"vfeeb", 0xE780, int_s390_vfeeb, z_vfee_cc,
- v128b, v128b, 0, 0, 1>;
- defm VFEEH : BinaryVRRbSPair<"vfeeh", 0xE780, int_s390_vfeeh, z_vfee_cc,
- v128h, v128h, 1, 0, 1>;
- defm VFEEF : BinaryVRRbSPair<"vfeef", 0xE780, int_s390_vfeef, z_vfee_cc,
- v128f, v128f, 2, 0, 1>;
- defm VFEEZB : BinaryVRRbSPair<"vfeezb", 0xE780, int_s390_vfeezb, z_vfeez_cc,
- v128b, v128b, 0, 2, 3>;
- defm VFEEZH : BinaryVRRbSPair<"vfeezh", 0xE780, int_s390_vfeezh, z_vfeez_cc,
- v128h, v128h, 1, 2, 3>;
- defm VFEEZF : BinaryVRRbSPair<"vfeezf", 0xE780, int_s390_vfeezf, z_vfeez_cc,
- v128f, v128f, 2, 2, 3>;
-
- defm VFENEB : BinaryVRRbSPair<"vfeneb", 0xE781, int_s390_vfeneb, z_vfene_cc,
- v128b, v128b, 0, 0, 1>;
- defm VFENEH : BinaryVRRbSPair<"vfeneh", 0xE781, int_s390_vfeneh, z_vfene_cc,
- v128h, v128h, 1, 0, 1>;
- defm VFENEF : BinaryVRRbSPair<"vfenef", 0xE781, int_s390_vfenef, z_vfene_cc,
- v128f, v128f, 2, 0, 1>;
+ defm VFAE : TernaryOptVRRbSPairGeneric<"vfae", 0xE782>;
+ defm VFAEB : TernaryOptVRRbSPair<"vfaeb", 0xE782, int_s390_vfaeb,
+ z_vfae_cc, v128b, v128b, 0>;
+ defm VFAEH : TernaryOptVRRbSPair<"vfaeh", 0xE782, int_s390_vfaeh,
+ z_vfae_cc, v128h, v128h, 1>;
+ defm VFAEF : TernaryOptVRRbSPair<"vfaef", 0xE782, int_s390_vfaef,
+ z_vfae_cc, v128f, v128f, 2>;
+ defm VFAEZB : TernaryOptVRRbSPair<"vfaezb", 0xE782, int_s390_vfaezb,
+ z_vfaez_cc, v128b, v128b, 0, 2>;
+ defm VFAEZH : TernaryOptVRRbSPair<"vfaezh", 0xE782, int_s390_vfaezh,
+ z_vfaez_cc, v128h, v128h, 1, 2>;
+ defm VFAEZF : TernaryOptVRRbSPair<"vfaezf", 0xE782, int_s390_vfaezf,
+ z_vfaez_cc, v128f, v128f, 2, 2>;
+
+ defm VFEE : BinaryExtraVRRbSPairGeneric<"vfee", 0xE780>;
+ defm VFEEB : BinaryExtraVRRbSPair<"vfeeb", 0xE780, int_s390_vfeeb,
+ z_vfee_cc, v128b, v128b, 0>;
+ defm VFEEH : BinaryExtraVRRbSPair<"vfeeh", 0xE780, int_s390_vfeeh,
+ z_vfee_cc, v128h, v128h, 1>;
+ defm VFEEF : BinaryExtraVRRbSPair<"vfeef", 0xE780, int_s390_vfeef,
+ z_vfee_cc, v128f, v128f, 2>;
+ defm VFEEZB : BinaryVRRbSPair<"vfeezb", 0xE780, int_s390_vfeezb,
+ z_vfeez_cc, v128b, v128b, 0, 2>;
+ defm VFEEZH : BinaryVRRbSPair<"vfeezh", 0xE780, int_s390_vfeezh,
+ z_vfeez_cc, v128h, v128h, 1, 2>;
+ defm VFEEZF : BinaryVRRbSPair<"vfeezf", 0xE780, int_s390_vfeezf,
+ z_vfeez_cc, v128f, v128f, 2, 2>;
+
+ defm VFENE : BinaryExtraVRRbSPairGeneric<"vfene", 0xE781>;
+ defm VFENEB : BinaryExtraVRRbSPair<"vfeneb", 0xE781, int_s390_vfeneb,
+ z_vfene_cc, v128b, v128b, 0>;
+ defm VFENEH : BinaryExtraVRRbSPair<"vfeneh", 0xE781, int_s390_vfeneh,
+ z_vfene_cc, v128h, v128h, 1>;
+ defm VFENEF : BinaryExtraVRRbSPair<"vfenef", 0xE781, int_s390_vfenef,
+ z_vfene_cc, v128f, v128f, 2>;
defm VFENEZB : BinaryVRRbSPair<"vfenezb", 0xE781, int_s390_vfenezb,
- z_vfenez_cc, v128b, v128b, 0, 2, 3>;
+ z_vfenez_cc, v128b, v128b, 0, 2>;
defm VFENEZH : BinaryVRRbSPair<"vfenezh", 0xE781, int_s390_vfenezh,
- z_vfenez_cc, v128h, v128h, 1, 2, 3>;
+ z_vfenez_cc, v128h, v128h, 1, 2>;
defm VFENEZF : BinaryVRRbSPair<"vfenezf", 0xE781, int_s390_vfenezf,
- z_vfenez_cc, v128f, v128f, 2, 2, 3>;
-
- defm VISTRB : UnaryVRRaSPair<"vistrb", 0xE75C, int_s390_vistrb, z_vistr_cc,
- v128b, v128b, 0>;
- defm VISTRH : UnaryVRRaSPair<"vistrh", 0xE75C, int_s390_vistrh, z_vistr_cc,
- v128h, v128h, 1>;
- defm VISTRF : UnaryVRRaSPair<"vistrf", 0xE75C, int_s390_vistrf, z_vistr_cc,
- v128f, v128f, 2>;
-
- defm VSTRCB : QuaternaryVRRdSPair<"vstrcb", 0xE78A, int_s390_vstrcb,
- z_vstrc_cc, v128b, v128b, 0, 0>;
- defm VSTRCH : QuaternaryVRRdSPair<"vstrch", 0xE78A, int_s390_vstrch,
- z_vstrc_cc, v128h, v128h, 1, 0>;
- defm VSTRCF : QuaternaryVRRdSPair<"vstrcf", 0xE78A, int_s390_vstrcf,
- z_vstrc_cc, v128f, v128f, 2, 0>;
- defm VSTRCZB : QuaternaryVRRdSPair<"vstrczb", 0xE78A, int_s390_vstrczb,
- z_vstrcz_cc, v128b, v128b, 0, 2>;
- defm VSTRCZH : QuaternaryVRRdSPair<"vstrczh", 0xE78A, int_s390_vstrczh,
- z_vstrcz_cc, v128h, v128h, 1, 2>;
- defm VSTRCZF : QuaternaryVRRdSPair<"vstrczf", 0xE78A, int_s390_vstrczf,
- z_vstrcz_cc, v128f, v128f, 2, 2>;
+ z_vfenez_cc, v128f, v128f, 2, 2>;
+
+ defm VISTR : UnaryExtraVRRaSPairGeneric<"vistr", 0xE75C>;
+ defm VISTRB : UnaryExtraVRRaSPair<"vistrb", 0xE75C, int_s390_vistrb,
+ z_vistr_cc, v128b, v128b, 0>;
+ defm VISTRH : UnaryExtraVRRaSPair<"vistrh", 0xE75C, int_s390_vistrh,
+ z_vistr_cc, v128h, v128h, 1>;
+ defm VISTRF : UnaryExtraVRRaSPair<"vistrf", 0xE75C, int_s390_vistrf,
+ z_vistr_cc, v128f, v128f, 2>;
+
+ defm VSTRC : QuaternaryOptVRRdSPairGeneric<"vstrc", 0xE78A>;
+ defm VSTRCB : QuaternaryOptVRRdSPair<"vstrcb", 0xE78A, int_s390_vstrcb,
+ z_vstrc_cc, v128b, v128b, 0>;
+ defm VSTRCH : QuaternaryOptVRRdSPair<"vstrch", 0xE78A, int_s390_vstrch,
+ z_vstrc_cc, v128h, v128h, 1>;
+ defm VSTRCF : QuaternaryOptVRRdSPair<"vstrcf", 0xE78A, int_s390_vstrcf,
+ z_vstrc_cc, v128f, v128f, 2>;
+ defm VSTRCZB : QuaternaryOptVRRdSPair<"vstrczb", 0xE78A, int_s390_vstrczb,
+ z_vstrcz_cc, v128b, v128b, 0, 2>;
+ defm VSTRCZH : QuaternaryOptVRRdSPair<"vstrczh", 0xE78A, int_s390_vstrczh,
+ z_vstrcz_cc, v128h, v128h, 1, 2>;
+ defm VSTRCZF : QuaternaryOptVRRdSPair<"vstrczf", 0xE78A, int_s390_vstrczf,
+ z_vstrcz_cc, v128f, v128f, 2, 2>;
}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZLDCleanup.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZLDCleanup.cpp
index 2cdf2f9..ec8ce6e 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZLDCleanup.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZLDCleanup.cpp
@@ -33,7 +33,7 @@ public:
SystemZLDCleanup(const SystemZTargetMachine &tm)
: MachineFunctionPass(ID), TII(nullptr), MF(nullptr) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SystemZ Local Dynamic TLS Access Clean-up";
}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
index a24d47d..14ff6af 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
@@ -133,14 +133,12 @@ public:
SystemZLongBranch(const SystemZTargetMachine &tm)
: MachineFunctionPass(ID), TII(nullptr) {}
- const char *getPassName() const override {
- return "SystemZ Long Branch";
- }
+ StringRef getPassName() const override { return "SystemZ Long Branch"; }
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -228,6 +226,10 @@ TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr &MI) {
// Relaxes to A(G)HI and BRCL, which is 6 bytes longer.
Terminator.ExtraRelaxSize = 6;
break;
+ case SystemZ::BRCTH:
+ // Never needs to be relaxed.
+ Terminator.ExtraRelaxSize = 0;
+ break;
case SystemZ::CRJ:
case SystemZ::CLRJ:
// Relaxes to a C(L)R/BRCL sequence, which is 2 bytes longer.
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp
new file mode 100644
index 0000000..ab6020f
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp
@@ -0,0 +1,153 @@
+//-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// -------------------------- Post RA scheduling ---------------------------- //
+// SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
+// the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
+// implementation that looks to optimize decoder grouping and balance the
+// usage of processor resources.
+//===----------------------------------------------------------------------===//
+
+#include "SystemZMachineScheduler.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "misched"
+
+#ifndef NDEBUG
+// Print the set of SUs
+void SystemZPostRASchedStrategy::SUSet::
+dump(SystemZHazardRecognizer &HazardRec) {
+ dbgs() << "{";
+ for (auto &SU : *this) {
+ HazardRec.dumpSU(SU, dbgs());
+ if (SU != *rbegin())
+ dbgs() << ", ";
+ }
+ dbgs() << "}\n";
+}
+#endif
+
+SystemZPostRASchedStrategy::
+SystemZPostRASchedStrategy(const MachineSchedContext *C)
+ : DAG(nullptr), HazardRec(C) {}
+
+void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
+ DAG = dag;
+ HazardRec.setDAG(dag);
+ HazardRec.Reset();
+}
+
+// Pick the next node to schedule.
+SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
+ // Only scheduling top-down.
+ IsTopNode = true;
+
+ if (Available.empty())
+ return nullptr;
+
+ // If only one choice, return it.
+ if (Available.size() == 1) {
+ DEBUG (dbgs() << "+++ Only one: ";
+ HazardRec.dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
+ return *Available.begin();
+ }
+
+ // All nodes that are possible to schedule are stored by in the
+ // Available set.
+ DEBUG(dbgs() << "+++ Available: "; Available.dump(HazardRec););
+
+ Candidate Best;
+ for (auto *SU : Available) {
+
+ // SU is the next candidate to be compared against current Best.
+ Candidate c(SU, HazardRec);
+
+ // Remeber which SU is the best candidate.
+ if (Best.SU == nullptr || c < Best) {
+ Best = c;
+ DEBUG(dbgs() << "+++ Best sofar: ";
+ HazardRec.dumpSU(Best.SU, dbgs());
+ if (Best.GroupingCost != 0)
+ dbgs() << "\tGrouping cost:" << Best.GroupingCost;
+ if (Best.ResourcesCost != 0)
+ dbgs() << " Resource cost:" << Best.ResourcesCost;
+ dbgs() << " Height:" << Best.SU->getHeight();
+ dbgs() << "\n";);
+ }
+
+ // Once we know we have seen all SUs that affect grouping or use unbuffered
+ // resources, we can stop iterating if Best looks good.
+ if (!SU->isScheduleHigh && Best.noCost())
+ break;
+ }
+
+ assert (Best.SU != nullptr);
+ return Best.SU;
+}
+
+SystemZPostRASchedStrategy::Candidate::
+Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
+ SU = SU_;
+
+ // Check the grouping cost. For a node that must begin / end a
+ // group, it is positive if it would do so prematurely, or negative
+ // if it would fit naturally into the schedule.
+ GroupingCost = HazardRec.groupingCost(SU);
+
+ // Check the resources cost for this SU.
+ ResourcesCost = HazardRec.resourcesCost(SU);
+}
+
+bool SystemZPostRASchedStrategy::Candidate::
+operator<(const Candidate &other) {
+
+ // Check decoder grouping.
+ if (GroupingCost < other.GroupingCost)
+ return true;
+ if (GroupingCost > other.GroupingCost)
+ return false;
+
+ // Compare the use of resources.
+ if (ResourcesCost < other.ResourcesCost)
+ return true;
+ if (ResourcesCost > other.ResourcesCost)
+ return false;
+
+ // Higher SU is otherwise generally better.
+ if (SU->getHeight() > other.SU->getHeight())
+ return true;
+ if (SU->getHeight() < other.SU->getHeight())
+ return false;
+
+ // If all same, fall back to original order.
+ if (SU->NodeNum < other.SU->NodeNum)
+ return true;
+
+ return false;
+}
+
+void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
+ DEBUG(dbgs() << "+++ Scheduling SU(" << SU->NodeNum << ")\n";);
+
+ // Remove SU from Available set and update HazardRec.
+ Available.erase(SU);
+ HazardRec.EmitInstruction(SU);
+}
+
+void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
+ // Set isScheduleHigh flag on all SUs that we want to consider first in
+ // pickNode().
+ const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
+ bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
+ SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
+
+ // Put all released SUs in the Available set.
+ Available.insert(SU);
+}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h
new file mode 100644
index 0000000..b919758
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h
@@ -0,0 +1,112 @@
+//==-- SystemZMachineScheduler.h - SystemZ Scheduler Interface -*- C++ -*---==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// -------------------------- Post RA scheduling ---------------------------- //
+// SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
+// the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
+// implementation that looks to optimize decoder grouping and balance the
+// usage of processor resources.
+//===----------------------------------------------------------------------===//
+
+#include "SystemZInstrInfo.h"
+#include "SystemZHazardRecognizer.h"
+#include "llvm/CodeGen/MachineScheduler.h"
+#include "llvm/Support/Debug.h"
+
+#ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZMACHINESCHEDULER_H
+#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZMACHINESCHEDULER_H
+
+using namespace llvm;
+
+namespace llvm {
+
+/// A MachineSchedStrategy implementation for SystemZ post RA scheduling.
+class SystemZPostRASchedStrategy : public MachineSchedStrategy {
+ ScheduleDAGMI *DAG;
+
+ /// A candidate during instruction evaluation.
+ struct Candidate {
+ SUnit *SU;
+
+ /// The decoding cost.
+ int GroupingCost;
+
+ /// The processor resources cost.
+ int ResourcesCost;
+
+ Candidate() : SU(nullptr), GroupingCost(0), ResourcesCost(0) {}
+ Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec);
+
+ // Compare two candidates.
+ bool operator<(const Candidate &other);
+
+ // Check if this node is free of cost ("as good as any").
+ bool inline noCost() {
+ return (GroupingCost <= 0 && !ResourcesCost);
+ }
+ };
+
+ // A sorter for the Available set that makes sure that SUs are considered
+ // in the best order.
+ struct SUSorter {
+ bool operator() (SUnit *lhs, SUnit *rhs) const {
+ if (lhs->isScheduleHigh && !rhs->isScheduleHigh)
+ return true;
+ if (!lhs->isScheduleHigh && rhs->isScheduleHigh)
+ return false;
+
+ if (lhs->getHeight() > rhs->getHeight())
+ return true;
+ else if (lhs->getHeight() < rhs->getHeight())
+ return false;
+
+ return (lhs->NodeNum < rhs->NodeNum);
+ }
+ };
+ // A set of SUs with a sorter and dump method.
+ struct SUSet : std::set<SUnit*, SUSorter> {
+ #ifndef NDEBUG
+ void dump(SystemZHazardRecognizer &HazardRec);
+ #endif
+ };
+
+ /// The set of available SUs to schedule next.
+ SUSet Available;
+
+ // HazardRecognizer that tracks the scheduler state for the current
+ // region.
+ SystemZHazardRecognizer HazardRec;
+
+ public:
+ SystemZPostRASchedStrategy(const MachineSchedContext *C);
+
+ /// PostRA scheduling does not track pressure.
+ bool shouldTrackPressure() const override { return false; }
+
+ /// Initialize the strategy after building the DAG for a new region.
+ void initialize(ScheduleDAGMI *dag) override;
+
+ /// Pick the next node to schedule, or return NULL.
+ SUnit *pickNode(bool &IsTopNode) override;
+
+ /// ScheduleDAGMI has scheduled an instruction - tell HazardRec
+ /// about it.
+ void schedNode(SUnit *SU, bool IsTopNode) override;
+
+ /// SU has had all predecessor dependencies resolved. Put it into
+ /// Available.
+ void releaseTopNode(SUnit *SU) override;
+
+ /// Currently only scheduling top-down, so this method is empty.
+ void releaseBottomNode(SUnit *SU) override {};
+};
+
+} // namespace llvm
+
+#endif /* LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZMACHINESCHEDULER_H */
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td b/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td
index 17b076d..7bb4fe5 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZOperands.td
@@ -133,6 +133,13 @@ class BDLMode<string type, string bitsize, string dispsize, string suffix,
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
!cast<Immediate>("imm"##bitsize))>;
+// A BDMode paired with a register length operand.
+class BDRMode<string type, string bitsize, string dispsize, string suffix>
+ : AddressingMode<type, bitsize, dispsize, suffix, "", 3, "BDRAddr",
+ (ops !cast<RegisterOperand>("ADDR"##bitsize),
+ !cast<Immediate>("disp"##dispsize##"imm"##bitsize),
+ !cast<RegisterOperand>("GR"##bitsize))>;
+
// An addressing mode with a base, displacement and a vector index.
class BDVMode<string bitsize, string dispsize>
: AddressOperand<bitsize, dispsize, "", "BDVAddr",
@@ -230,6 +237,12 @@ def UIMM32 : SDNodeXForm<imm, [{
MVT::i64);
}]>;
+// Truncate an immediate to a 48-bit unsigned quantity.
+def UIMM48 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(uint64_t(N->getZExtValue()) & 0xffffffffffff,
+ SDLoc(N), MVT::i64);
+}]>;
+
// Negate and then truncate an immediate to a 32-bit unsigned quantity.
def NEGIMM32 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(uint32_t(-N->getZExtValue()), SDLoc(N),
@@ -252,6 +265,7 @@ def S16Imm : ImmediateAsmOperand<"S16Imm">;
def U16Imm : ImmediateAsmOperand<"U16Imm">;
def S32Imm : ImmediateAsmOperand<"S32Imm">;
def U32Imm : ImmediateAsmOperand<"U32Imm">;
+def U48Imm : ImmediateAsmOperand<"U48Imm">;
//===----------------------------------------------------------------------===//
// i32 immediates
@@ -425,6 +439,10 @@ def imm64zx32n : Immediate<i64, [{
return isUInt<32>(-N->getSExtValue());
}], NEGIMM32, "U32Imm">;
+def imm64zx48 : Immediate<i64, [{
+ return isUInt<64>(N->getZExtValue());
+}], UIMM48, "U48Imm">;
+
def imm64 : ImmLeaf<i64, [{}]>, Operand<i64>;
//===----------------------------------------------------------------------===//
@@ -442,7 +460,9 @@ def fpimmneg0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>;
//===----------------------------------------------------------------------===//
// PC-relative asm operands.
+def PCRel12 : PCRelAsmOperand<"12">;
def PCRel16 : PCRelAsmOperand<"16">;
+def PCRel24 : PCRelAsmOperand<"24">;
def PCRel32 : PCRelAsmOperand<"32">;
def PCRelTLS16 : PCRelTLSAsmOperand<"16">;
def PCRelTLS32 : PCRelTLSAsmOperand<"32">;
@@ -458,6 +478,20 @@ def brtarget32 : PCRelOperand<OtherVT, PCRel32> {
let DecoderMethod = "decodePC32DBLBranchOperand";
}
+// Variants of brtarget for use with branch prediction preload.
+def brtarget12bpp : PCRelOperand<OtherVT, PCRel12> {
+ let EncoderMethod = "getPC12DBLBPPEncoding";
+ let DecoderMethod = "decodePC12DBLBranchOperand";
+}
+def brtarget16bpp : PCRelOperand<OtherVT, PCRel16> {
+ let EncoderMethod = "getPC16DBLBPPEncoding";
+ let DecoderMethod = "decodePC16DBLBranchOperand";
+}
+def brtarget24bpp : PCRelOperand<OtherVT, PCRel24> {
+ let EncoderMethod = "getPC24DBLBPPEncoding";
+ let DecoderMethod = "decodePC24DBLBranchOperand";
+}
+
// Variants of brtarget16/32 with an optional additional TLS symbol.
// These are used to annotate calls to __tls_get_offset.
def tlssym : Operand<i64> { }
@@ -498,6 +532,7 @@ def BDAddr64Disp20 : AddressAsmOperand<"BDAddr", "64", "20">;
def BDXAddr64Disp12 : AddressAsmOperand<"BDXAddr", "64", "12">;
def BDXAddr64Disp20 : AddressAsmOperand<"BDXAddr", "64", "20">;
def BDLAddr64Disp12Len8 : AddressAsmOperand<"BDLAddr", "64", "12", "Len8">;
+def BDRAddr64Disp12 : AddressAsmOperand<"BDRAddr", "64", "12">;
def BDVAddr64Disp12 : AddressAsmOperand<"BDVAddr", "64", "12">;
// DAG patterns and operands for addressing modes. Each mode has
@@ -544,23 +579,13 @@ def dynalloc12only : BDXMode<"DynAlloc", "64", "12", "Only">;
def laaddr12pair : BDXMode<"LAAddr", "64", "12", "Pair">;
def laaddr20pair : BDXMode<"LAAddr", "64", "20", "Pair">;
def bdladdr12onlylen8 : BDLMode<"BDLAddr", "64", "12", "Only", "8">;
+def bdraddr12only : BDRMode<"BDRAddr", "64", "12", "Only">;
def bdvaddr12only : BDVMode< "64", "12">;
//===----------------------------------------------------------------------===//
// Miscellaneous
//===----------------------------------------------------------------------===//
-// Access registers. At present we just use them for accessing the thread
-// pointer, so we don't expose them as register to LLVM.
-def AccessReg : AsmOperandClass {
- let Name = "AccessReg";
- let ParserMethod = "parseAccessReg";
-}
-def access_reg : Immediate<i32, [{ return N->getZExtValue() < 16; }],
- NOOP_SDNodeXForm, "AccessReg"> {
- let ParserMatchClass = AccessReg;
-}
-
// A 4-bit condition-code mask.
def cond4 : PatLeaf<(i32 imm), [{ return (N->getZExtValue() < 16); }]>,
Operand<i32> {
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td b/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td
index 8d031f1..fde26ed 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -35,9 +35,6 @@ def SDT_ZWrapOffset : SDTypeProfile<1, 2,
SDTCisSameAs<0, 2>,
SDTCisPtrTy<0>]>;
def SDT_ZAdjDynAlloc : SDTypeProfile<1, 0, [SDTCisVT<0, i64>]>;
-def SDT_ZExtractAccess : SDTypeProfile<1, 1,
- [SDTCisVT<0, i32>,
- SDTCisVT<1, i32>]>;
def SDT_ZGR128Binary32 : SDTypeProfile<1, 2,
[SDTCisVT<0, untyped>,
SDTCisVT<1, untyped>,
@@ -186,8 +183,6 @@ def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask,
def z_select_ccmask : SDNode<"SystemZISD::SELECT_CCMASK", SDT_ZSelectCCMask,
[SDNPInGlue]>;
def z_adjdynalloc : SDNode<"SystemZISD::ADJDYNALLOC", SDT_ZAdjDynAlloc>;
-def z_extract_access : SDNode<"SystemZISD::EXTRACT_ACCESS",
- SDT_ZExtractAccess>;
def z_popcnt : SDNode<"SystemZISD::POPCNT", SDTIntUnaryOp>;
def z_umul_lohi64 : SDNode<"SystemZISD::UMUL_LOHI64", SDT_ZGR128Binary64>;
def z_sdivrem32 : SDNode<"SystemZISD::SDIVREM32", SDT_ZGR128Binary32>;
@@ -387,15 +382,6 @@ def zext8 : PatFrag<(ops node:$src), (and node:$src, 0xff)>;
def zext16 : PatFrag<(ops node:$src), (and node:$src, 0xffff)>;
def zext32 : PatFrag<(ops node:$src), (zext (i32 node:$src))>;
-// Match extensions of an i32 to an i64, followed by an AND of the low
-// i8 or i16 part.
-def zext8dbl : PatFrag<(ops node:$src), (zext8 (anyext node:$src))>;
-def zext16dbl : PatFrag<(ops node:$src), (zext16 (anyext node:$src))>;
-
-// Typed floating-point loads.
-def loadf32 : PatFrag<(ops node:$src), (f32 (load node:$src))>;
-def loadf64 : PatFrag<(ops node:$src), (f64 (load node:$src))>;
-
// Extending loads in which the extension type can be signed.
def asextload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr), [{
unsigned Type = cast<LoadSDNode>(N)->getExtensionType();
@@ -529,7 +515,7 @@ def inserthf : PatFrag<(ops node:$src1, node:$src2),
// ORs that can be treated as insertions.
def or_as_inserti8 : PatFrag<(ops node:$src1, node:$src2),
(or node:$src1, node:$src2), [{
- unsigned BitWidth = N->getValueType(0).getScalarType().getSizeInBits();
+ unsigned BitWidth = N->getValueType(0).getScalarSizeInBits();
return CurDAG->MaskedValueIsZero(N->getOperand(0),
APInt::getLowBitsSet(BitWidth, 8));
}]>;
@@ -537,7 +523,7 @@ def or_as_inserti8 : PatFrag<(ops node:$src1, node:$src2),
// ORs that can be treated as reversed insertions.
def or_as_revinserti8 : PatFrag<(ops node:$src1, node:$src2),
(or node:$src1, node:$src2), [{
- unsigned BitWidth = N->getValueType(0).getScalarType().getSizeInBits();
+ unsigned BitWidth = N->getValueType(0).getScalarSizeInBits();
return CurDAG->MaskedValueIsZero(N->getOperand(1),
APInt::getLowBitsSet(BitWidth, 8));
}]>;
@@ -584,6 +570,12 @@ class storeu<SDPatternOperator operator, SDPatternOperator store = store>
: PatFrag<(ops node:$value, node:$addr),
(store (operator node:$value), node:$addr)>;
+// Create a store operator that performs the given inherent operation
+// and stores the resulting value.
+class storei<SDPatternOperator operator, SDPatternOperator store = store>
+ : PatFrag<(ops node:$addr),
+ (store (operator), node:$addr)>;
+
// Vector representation of all-zeros and all-ones.
def z_vzero : PatFrag<(ops), (bitconvert (v16i8 (z_byte_mask (i32 0))))>;
def z_vones : PatFrag<(ops), (bitconvert (v16i8 (z_byte_mask (i32 65535))))>;
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZProcessors.td b/contrib/llvm/lib/Target/SystemZ/SystemZProcessors.td
index 9adc018..1cdc094 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZProcessors.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZProcessors.td
@@ -7,96 +7,29 @@
//
//===----------------------------------------------------------------------===//
//
-// Processor and feature definitions.
+// Processor definitions.
+//
+// For compatibility with other compilers on the platform, each model can
+// be identifed either by the system name (e.g. z10) or the level of the
+// architecture the model supports, as identified by the edition level
+// of the z/Architecture Principles of Operation document (e.g. arch8).
+//
+// The minimum architecture level supported by LLVM is as defined in
+// the Eighth Edition of the PoP (i.e. as implemented on z10).
//
//===----------------------------------------------------------------------===//
-class SystemZFeature<string extname, string intname, string desc>
- : Predicate<"Subtarget->has"##intname##"()">,
- AssemblerPredicate<"Feature"##intname, extname>,
- SubtargetFeature<extname, "Has"##intname, "true", desc>;
-
-class SystemZMissingFeature<string intname>
- : Predicate<"!Subtarget->has"##intname##"()">;
-
-def FeatureDistinctOps : SystemZFeature<
- "distinct-ops", "DistinctOps",
- "Assume that the distinct-operands facility is installed"
->;
-
-def FeatureLoadStoreOnCond : SystemZFeature<
- "load-store-on-cond", "LoadStoreOnCond",
- "Assume that the load/store-on-condition facility is installed"
->;
-
-def FeatureLoadStoreOnCond2 : SystemZFeature<
- "load-store-on-cond-2", "LoadStoreOnCond2",
- "Assume that the load/store-on-condition facility 2 is installed"
->;
-
-def FeatureHighWord : SystemZFeature<
- "high-word", "HighWord",
- "Assume that the high-word facility is installed"
->;
-
-def FeatureFPExtension : SystemZFeature<
- "fp-extension", "FPExtension",
- "Assume that the floating-point extension facility is installed"
->;
-
-def FeaturePopulationCount : SystemZFeature<
- "population-count", "PopulationCount",
- "Assume that the population-count facility is installed"
->;
-
-def FeatureFastSerialization : SystemZFeature<
- "fast-serialization", "FastSerialization",
- "Assume that the fast-serialization facility is installed"
->;
-
-def FeatureInterlockedAccess1 : SystemZFeature<
- "interlocked-access1", "InterlockedAccess1",
- "Assume that interlocked-access facility 1 is installed"
->;
-def FeatureNoInterlockedAccess1 : SystemZMissingFeature<"InterlockedAccess1">;
+def : ProcessorModel<"generic", NoSchedModel, []>;
-def FeatureMiscellaneousExtensions : SystemZFeature<
- "miscellaneous-extensions", "MiscellaneousExtensions",
- "Assume that the miscellaneous-extensions facility is installed"
->;
+def : ProcessorModel<"arch8", NoSchedModel, Arch8SupportedFeatures.List>;
+def : ProcessorModel<"z10", NoSchedModel, Arch8SupportedFeatures.List>;
-def FeatureTransactionalExecution : SystemZFeature<
- "transactional-execution", "TransactionalExecution",
- "Assume that the transactional-execution facility is installed"
->;
+def : ProcessorModel<"arch9", Z196Model, Arch9SupportedFeatures.List>;
+def : ProcessorModel<"z196", Z196Model, Arch9SupportedFeatures.List>;
-def FeatureProcessorAssist : SystemZFeature<
- "processor-assist", "ProcessorAssist",
- "Assume that the processor-assist facility is installed"
->;
+def : ProcessorModel<"arch10", ZEC12Model, Arch10SupportedFeatures.List>;
+def : ProcessorModel<"zEC12", ZEC12Model, Arch10SupportedFeatures.List>;
-def FeatureVector : SystemZFeature<
- "vector", "Vector",
- "Assume that the vectory facility is installed"
->;
-def FeatureNoVector : SystemZMissingFeature<"Vector">;
+def : ProcessorModel<"arch11", Z13Model, Arch11SupportedFeatures.List>;
+def : ProcessorModel<"z13", Z13Model, Arch11SupportedFeatures.List>;
-def : Processor<"generic", NoItineraries, []>;
-def : Processor<"z10", NoItineraries, []>;
-def : Processor<"z196", NoItineraries,
- [FeatureDistinctOps, FeatureLoadStoreOnCond, FeatureHighWord,
- FeatureFPExtension, FeaturePopulationCount,
- FeatureFastSerialization, FeatureInterlockedAccess1]>;
-def : Processor<"zEC12", NoItineraries,
- [FeatureDistinctOps, FeatureLoadStoreOnCond, FeatureHighWord,
- FeatureFPExtension, FeaturePopulationCount,
- FeatureFastSerialization, FeatureInterlockedAccess1,
- FeatureMiscellaneousExtensions,
- FeatureTransactionalExecution, FeatureProcessorAssist]>;
-def : Processor<"z13", NoItineraries,
- [FeatureDistinctOps, FeatureLoadStoreOnCond, FeatureHighWord,
- FeatureFPExtension, FeaturePopulationCount,
- FeatureFastSerialization, FeatureInterlockedAccess1,
- FeatureMiscellaneousExtensions,
- FeatureTransactionalExecution, FeatureProcessorAssist,
- FeatureVector, FeatureLoadStoreOnCond2]>;
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
index b5e5fd4..6ef8000 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -59,6 +59,11 @@ SystemZRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
Reserved.set(SystemZ::R15L);
Reserved.set(SystemZ::R15H);
Reserved.set(SystemZ::R14Q);
+
+ // A0 and A1 hold the thread pointer.
+ Reserved.set(SystemZ::A0);
+ Reserved.set(SystemZ::A1);
+
return Reserved;
}
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td
index 0d8b08b..47d2f75 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZRegisterInfo.td
@@ -36,15 +36,16 @@ def subreg_hr32 : ComposedSubRegIndex<subreg_h64, subreg_r32>;
// associated operand called NAME. SIZE is the size and alignment
// of the registers and REGLIST is the list of individual registers.
multiclass SystemZRegClass<string name, list<ValueType> types, int size,
- dag regList> {
+ dag regList, bit allocatable = 1> {
def AsmOperand : AsmOperandClass {
let Name = name;
let ParserMethod = "parse"##name;
let RenderMethod = "addRegOperands";
}
- def Bit : RegisterClass<"SystemZ", types, size, regList> {
- let Size = size;
- }
+ let isAllocatable = allocatable in
+ def Bit : RegisterClass<"SystemZ", types, size, regList> {
+ let Size = size;
+ }
def "" : RegisterOperand<!cast<RegisterClass>(name##"Bit")> {
let ParserMatchClass = !cast<AsmOperandClass>(name##"AsmOperand");
}
@@ -121,6 +122,14 @@ defm ADDR64 : SystemZRegClass<"ADDR64", [i64], 64, (sub GR64Bit, R0D)>;
// of a GR128.
defm ADDR128 : SystemZRegClass<"ADDR128", [untyped], 128, (sub GR128Bit, R0Q)>;
+// Any type register. Used for .insn directives when we don't know what the
+// register types could be.
+defm AnyReg : SystemZRegClass<"AnyReg",
+ [i64, f64, v8i8, v4i16, v2i32, v2f32], 64,
+ (add (sequence "R%uD", 0, 15),
+ (sequence "F%uD", 0, 15),
+ (sequence "V%u", 0, 15))>;
+
//===----------------------------------------------------------------------===//
// Floating-point registers
//===----------------------------------------------------------------------===//
@@ -284,3 +293,14 @@ def v128any : TypedReg<untyped, VR128>;
def CC : SystemZReg<"cc">;
let isAllocatable = 0 in
def CCRegs : RegisterClass<"SystemZ", [i32], 32, (add CC)>;
+
+// Access registers.
+class ACR32<bits<16> num, string n> : SystemZReg<n> {
+ let HWEncoding = num;
+}
+foreach I = 0-15 in {
+ def A#I : ACR32<I, "a"#I>, DwarfRegNum<[!add(I, 48)]>;
+}
+defm AR32 : SystemZRegClass<"AR32", [i32], 32,
+ (add (sequence "A%u", 0, 15)), 0>;
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSchedule.td b/contrib/llvm/lib/Target/SystemZ/SystemZSchedule.td
new file mode 100644
index 0000000..dbba8ab
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZSchedule.td
@@ -0,0 +1,77 @@
+//==-- SystemZSchedule.td - SystemZ Scheduling Definitions ----*- tblgen -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Scheduler resources
+// Resources ending with a '2' use that resource for 2 cycles. An instruction
+// using two such resources use the mapped unit for 4 cycles, and 2 is added
+// to the total number of uops of the sched class.
+
+// These three resources are used to express decoder grouping rules.
+// The number of decoder slots needed by an instructions is normally
+// one. For a cracked instruction (BeginGroup && !EndGroup) it is
+// two. Expanded instructions (BeginGroup && EndGroup) group alone.
+def GroupAlone : SchedWrite;
+def BeginGroup : SchedWrite;
+def EndGroup : SchedWrite;
+
+// Latencies, to make code a bit neater. If more than one resource is
+// used for an instruction, the greatest latency (not the sum) will be
+// output by Tablegen. Therefore, in such cases one of these resources
+// is needed.
+def Lat2 : SchedWrite;
+def Lat3 : SchedWrite;
+def Lat4 : SchedWrite;
+def Lat5 : SchedWrite;
+def Lat6 : SchedWrite;
+def Lat7 : SchedWrite;
+def Lat8 : SchedWrite;
+def Lat9 : SchedWrite;
+def Lat10 : SchedWrite;
+def Lat11 : SchedWrite;
+def Lat12 : SchedWrite;
+def Lat15 : SchedWrite;
+def Lat20 : SchedWrite;
+def Lat30 : SchedWrite;
+
+// Fixed-point
+def FXa : SchedWrite;
+def FXa2 : SchedWrite;
+def FXb : SchedWrite;
+def FXU : SchedWrite;
+
+// Load/store unit
+def LSU : SchedWrite;
+
+// Model a return without latency, otherwise if-converter will model
+// extra cost and abort (currently there is an assert that checks that
+// all instructions have at least one uop).
+def LSU_lat1 : SchedWrite;
+
+// Floating point unit (zEC12 and earlier)
+def FPU : SchedWrite;
+def FPU2 : SchedWrite;
+
+// Vector sub units (z13)
+def VecBF : SchedWrite;
+def VecBF2 : SchedWrite;
+def VecDF : SchedWrite;
+def VecDF2 : SchedWrite;
+def VecFPd : SchedWrite; // Blocking BFP div/sqrt unit.
+def VecMul : SchedWrite;
+def VecStr : SchedWrite;
+def VecXsPm : SchedWrite;
+
+// Virtual branching unit
+def VBU : SchedWrite;
+
+
+include "SystemZScheduleZ13.td"
+include "SystemZScheduleZEC12.td"
+include "SystemZScheduleZ196.td"
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td b/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td
new file mode 100644
index 0000000..e97d61d
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ13.td
@@ -0,0 +1,1064 @@
+//-- SystemZScheduleZ13.td - SystemZ Scheduling Definitions ----*- tblgen -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the machine model for Z13 to support instruction
+// scheduling and other instruction cost heuristics.
+//
+//===----------------------------------------------------------------------===//
+
+def Z13Model : SchedMachineModel {
+
+ let UnsupportedFeatures = Arch11UnsupportedFeatures.List;
+
+ let IssueWidth = 8;
+ let MicroOpBufferSize = 60; // Issue queues
+ let LoadLatency = 1; // Optimistic load latency.
+
+ let PostRAScheduler = 1;
+
+ // Extra cycles for a mispredicted branch.
+ let MispredictPenalty = 20;
+}
+
+let SchedModel = Z13Model in {
+
+// These definitions could be put in a subtarget common include file,
+// but it seems the include system in Tablegen currently rejects
+// multiple includes of same file.
+def : WriteRes<GroupAlone, []> {
+ let NumMicroOps = 0;
+ let BeginGroup = 1;
+ let EndGroup = 1;
+}
+def : WriteRes<BeginGroup, []> {
+ let NumMicroOps = 0;
+ let BeginGroup = 1;
+}
+def : WriteRes<EndGroup, []> {
+ let NumMicroOps = 0;
+ let EndGroup = 1;
+}
+def : WriteRes<Lat2, []> { let Latency = 2; let NumMicroOps = 0;}
+def : WriteRes<Lat3, []> { let Latency = 3; let NumMicroOps = 0;}
+def : WriteRes<Lat4, []> { let Latency = 4; let NumMicroOps = 0;}
+def : WriteRes<Lat5, []> { let Latency = 5; let NumMicroOps = 0;}
+def : WriteRes<Lat6, []> { let Latency = 6; let NumMicroOps = 0;}
+def : WriteRes<Lat7, []> { let Latency = 7; let NumMicroOps = 0;}
+def : WriteRes<Lat8, []> { let Latency = 8; let NumMicroOps = 0;}
+def : WriteRes<Lat9, []> { let Latency = 9; let NumMicroOps = 0;}
+def : WriteRes<Lat10, []> { let Latency = 10; let NumMicroOps = 0;}
+def : WriteRes<Lat11, []> { let Latency = 11; let NumMicroOps = 0;}
+def : WriteRes<Lat12, []> { let Latency = 12; let NumMicroOps = 0;}
+def : WriteRes<Lat15, []> { let Latency = 15; let NumMicroOps = 0;}
+def : WriteRes<Lat20, []> { let Latency = 20; let NumMicroOps = 0;}
+def : WriteRes<Lat30, []> { let Latency = 30; let NumMicroOps = 0;}
+
+// Execution units.
+def Z13_FXaUnit : ProcResource<2>;
+def Z13_FXbUnit : ProcResource<2>;
+def Z13_LSUnit : ProcResource<2>;
+def Z13_VecUnit : ProcResource<2>;
+def Z13_VecFPdUnit : ProcResource<2> { let BufferSize = 1; /* blocking */ }
+def Z13_VBUnit : ProcResource<2>;
+
+// Subtarget specific definitions of scheduling resources.
+def : WriteRes<FXa, [Z13_FXaUnit]> { let Latency = 1; }
+def : WriteRes<FXa2, [Z13_FXaUnit, Z13_FXaUnit]> { let Latency = 2; }
+def : WriteRes<FXb, [Z13_FXbUnit]> { let Latency = 1; }
+def : WriteRes<LSU, [Z13_LSUnit]> { let Latency = 4; }
+def : WriteRes<VecBF, [Z13_VecUnit]> { let Latency = 8; }
+def : WriteRes<VecBF2, [Z13_VecUnit, Z13_VecUnit]> { let Latency = 9; }
+def : WriteRes<VecDF, [Z13_VecUnit]> { let Latency = 8; }
+def : WriteRes<VecDF2, [Z13_VecUnit, Z13_VecUnit]> { let Latency = 9; }
+def : WriteRes<VecFPd, [Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit,
+ Z13_VecFPdUnit, Z13_VecFPdUnit, Z13_VecFPdUnit]>
+ { let Latency = 30; }
+def : WriteRes<VecMul, [Z13_VecUnit]> { let Latency = 5; }
+def : WriteRes<VecStr, [Z13_VecUnit]> { let Latency = 4; }
+def : WriteRes<VecXsPm, [Z13_VecUnit]> { let Latency = 3; }
+def : WriteRes<VBU, [Z13_VBUnit]>; // Virtual Branching Unit
+
+// -------------------------- INSTRUCTIONS ---------------------------------- //
+
+// InstRW constructs have been used in order to preserve the
+// readability of the InstrInfo files.
+
+// For each instruction, as matched by a regexp, provide a list of
+// resources that it needs. These will be combined into a SchedClass.
+
+//===----------------------------------------------------------------------===//
+// Stack allocation
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "ADJDYNALLOC$")>; // Pseudo -> LA / LAY
+
+//===----------------------------------------------------------------------===//
+// Branch instructions
+//===----------------------------------------------------------------------===//
+
+// Branch
+def : InstRW<[VBU], (instregex "(Call)?BRC(L)?(Asm.*)?$")>;
+def : InstRW<[VBU], (instregex "(Call)?J(G)?(Asm.*)?$")>;
+def : InstRW<[FXb], (instregex "(Call)?BC(R)?(Asm.*)?$")>;
+def : InstRW<[FXb], (instregex "(Call)?B(R)?(Asm.*)?$")>;
+def : InstRW<[FXa, EndGroup], (instregex "BRCT(G)?$")>;
+def : InstRW<[FXb, FXa, Lat2, GroupAlone], (instregex "BRCTH$")>;
+def : InstRW<[FXb, FXa, Lat2, GroupAlone], (instregex "BCT(G)?(R)?$")>;
+def : InstRW<[FXa, FXa, FXb, FXb, Lat4, GroupAlone],
+ (instregex "B(R)?X(H|L).*$")>;
+
+// Compare and branch
+def : InstRW<[FXb], (instregex "C(L)?(G)?(I|R)J(Asm.*)?$")>;
+def : InstRW<[FXb, FXb, Lat2, GroupAlone],
+ (instregex "C(L)?(G)?(I|R)B(Call|Return|Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Trap instructions
+//===----------------------------------------------------------------------===//
+
+// Trap
+def : InstRW<[VBU], (instregex "(Cond)?Trap$")>;
+
+// Compare and trap
+def : InstRW<[FXb], (instregex "C(G)?(I|R)T(Asm.*)?$")>;
+def : InstRW<[FXb], (instregex "CL(G)?RT(Asm.*)?$")>;
+def : InstRW<[FXb], (instregex "CL(F|G)IT(Asm.*)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CL(G)?T(Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Call and return instructions
+//===----------------------------------------------------------------------===//
+
+// Call
+def : InstRW<[VBU, FXa, FXa, Lat3, GroupAlone], (instregex "(Call)?BRAS$")>;
+def : InstRW<[FXa, FXa, FXb, Lat3, GroupAlone], (instregex "(Call)?BRASL$")>;
+def : InstRW<[FXa, FXa, FXb, Lat3, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
+def : InstRW<[FXa, FXa, FXb, Lat3, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
+
+// Return
+def : InstRW<[FXb, EndGroup], (instregex "Return$")>;
+def : InstRW<[FXb], (instregex "CondReturn$")>;
+
+//===----------------------------------------------------------------------===//
+// Select instructions
+//===----------------------------------------------------------------------===//
+
+// Select pseudo
+def : InstRW<[FXa], (instregex "Select(32|64|32Mux)$")>;
+
+// CondStore pseudos
+def : InstRW<[FXa], (instregex "CondStore16(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStore16Mux(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStore32(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStore32Mux(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStore64(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStore8(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStore8Mux(Inv)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Move instructions
+//===----------------------------------------------------------------------===//
+
+// Moves
+def : InstRW<[FXb, LSU, Lat5], (instregex "MV(G|H)?HI$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "MVI(Y)?$")>;
+
+// Move character
+def : InstRW<[FXb, LSU, LSU, LSU, Lat8, GroupAlone], (instregex "MVC$")>;
+
+// Pseudo -> reg move
+def : InstRW<[FXa], (instregex "COPY(_TO_REGCLASS)?$")>;
+def : InstRW<[FXa], (instregex "EXTRACT_SUBREG$")>;
+def : InstRW<[FXa], (instregex "INSERT_SUBREG$")>;
+def : InstRW<[FXa], (instregex "REG_SEQUENCE$")>;
+def : InstRW<[FXa], (instregex "SUBREG_TO_REG$")>;
+
+// Loads
+def : InstRW<[LSU], (instregex "L(Y|FH|RL|Mux|CBB)?$")>;
+def : InstRW<[LSU], (instregex "LG(RL)?$")>;
+def : InstRW<[LSU], (instregex "L128$")>;
+
+def : InstRW<[FXa], (instregex "LLIH(F|H|L)$")>;
+def : InstRW<[FXa], (instregex "LLIL(F|H|L)$")>;
+
+def : InstRW<[FXa], (instregex "LG(F|H)I$")>;
+def : InstRW<[FXa], (instregex "LHI(Mux)?$")>;
+def : InstRW<[FXa], (instregex "LR(Mux)?$")>;
+
+// Load and zero rightmost byte
+def : InstRW<[LSU], (instregex "LZR(F|G)$")>;
+
+// Load and trap
+def : InstRW<[FXb, LSU, Lat5], (instregex "L(FH|G)?AT$")>;
+
+// Load and test
+def : InstRW<[FXa, LSU, Lat5], (instregex "LT(G)?$")>;
+def : InstRW<[FXa], (instregex "LT(G)?R$")>;
+
+// Stores
+def : InstRW<[FXb, LSU, Lat5], (instregex "STG(RL)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "ST128$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "ST(Y|FH|RL|Mux)?$")>;
+
+// String moves.
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "MVST$")>;
+
+//===----------------------------------------------------------------------===//
+// Conditional move instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, Lat2], (instregex "LOCRMux$")>;
+def : InstRW<[FXa, Lat2], (instregex "LOC(G|FH)?R(Asm.*)?$")>;
+def : InstRW<[FXa, Lat2], (instregex "LOC(G|H)?HI(Asm.*)?$")>;
+def : InstRW<[FXa, LSU, Lat6], (instregex "LOC(G|FH|Mux)?(Asm.*)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "STOC(G|FH|Mux)?(Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Sign extensions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "L(B|H|G)R$")>;
+def : InstRW<[FXa], (instregex "LG(B|H|F)R$")>;
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "LTGF$")>;
+def : InstRW<[FXa], (instregex "LTGFR$")>;
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "LB(H|Mux)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "LH(Y)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "LH(H|Mux|RL)$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "LG(B|H|F)$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "LG(H|F)RL$")>;
+
+//===----------------------------------------------------------------------===//
+// Zero extensions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "LLCR(Mux)?$")>;
+def : InstRW<[FXa], (instregex "LLHR(Mux)?$")>;
+def : InstRW<[FXa], (instregex "LLG(C|H|F|T)R$")>;
+def : InstRW<[LSU], (instregex "LLC(Mux)?$")>;
+def : InstRW<[LSU], (instregex "LLH(Mux)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "LL(C|H)H$")>;
+def : InstRW<[LSU], (instregex "LLHRL$")>;
+def : InstRW<[LSU], (instregex "LLG(C|H|F|T|HRL|FRL)$")>;
+
+// Load and zero rightmost byte
+def : InstRW<[LSU], (instregex "LLZRGF$")>;
+
+// Load and trap
+def : InstRW<[FXb, LSU, Lat5], (instregex "LLG(F|T)?AT$")>;
+
+//===----------------------------------------------------------------------===//
+// Truncations
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb, LSU, Lat5], (instregex "STC(H|Y|Mux)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "STH(H|Y|RL|Mux)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Multi-register moves
+//===----------------------------------------------------------------------===//
+
+// Load multiple (estimated average of 5 ops)
+def : InstRW<[LSU, LSU, LSU, LSU, LSU, Lat10, GroupAlone],
+ (instregex "LM(H|Y|G)?$")>;
+
+// Store multiple (estimated average of ceil(5/2) FXb ops)
+def : InstRW<[LSU, LSU, FXb, FXb, FXb, Lat10,
+ GroupAlone], (instregex "STM(G|H|Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Byte swaps
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "LRV(G)?R$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "LRV(G|H)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "STRV(G|H)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Load address instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "LA(Y|RL)?$")>;
+
+// Load the Global Offset Table address ( -> larl )
+def : InstRW<[FXa], (instregex "GOT$")>;
+
+//===----------------------------------------------------------------------===//
+// Absolute and Negation
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, Lat2], (instregex "LP(G)?R$")>;
+def : InstRW<[FXa, FXa, Lat3, BeginGroup], (instregex "L(N|P)GFR$")>;
+def : InstRW<[FXa, Lat2], (instregex "LN(R|GR)$")>;
+def : InstRW<[FXa], (instregex "LC(R|GR)$")>;
+def : InstRW<[FXa, FXa, Lat2, BeginGroup], (instregex "LCGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// Insertion
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "IC(Y)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "IC32(Y)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "ICM(H|Y)?$")>;
+def : InstRW<[FXa], (instregex "II(F|H|L)Mux$")>;
+def : InstRW<[FXa], (instregex "IIHF(64)?$")>;
+def : InstRW<[FXa], (instregex "IIHH(64)?$")>;
+def : InstRW<[FXa], (instregex "IIHL(64)?$")>;
+def : InstRW<[FXa], (instregex "IILF(64)?$")>;
+def : InstRW<[FXa], (instregex "IILH(64)?$")>;
+def : InstRW<[FXa], (instregex "IILL(64)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Addition
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "A(Y)?$")>;
+def : InstRW<[FXa, LSU, Lat6], (instregex "AH(Y)?$")>;
+def : InstRW<[FXa], (instregex "AIH$")>;
+def : InstRW<[FXa], (instregex "AFI(Mux)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "AG$")>;
+def : InstRW<[FXa], (instregex "AGFI$")>;
+def : InstRW<[FXa], (instregex "AGHI(K)?$")>;
+def : InstRW<[FXa], (instregex "AGR(K)?$")>;
+def : InstRW<[FXa], (instregex "AHI(K)?$")>;
+def : InstRW<[FXa], (instregex "AHIMux(K)?$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "AL(Y)?$")>;
+def : InstRW<[FXa], (instregex "AL(FI|HSIK)$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "ALG(F)?$")>;
+def : InstRW<[FXa], (instregex "ALGHSIK$")>;
+def : InstRW<[FXa], (instregex "ALGF(I|R)$")>;
+def : InstRW<[FXa], (instregex "ALGR(K)?$")>;
+def : InstRW<[FXa], (instregex "ALR(K)?$")>;
+def : InstRW<[FXa], (instregex "AR(K)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "A(G)?SI$")>;
+
+// Logical addition with carry
+def : InstRW<[FXa, LSU, Lat6, GroupAlone], (instregex "ALC(G)?$")>;
+def : InstRW<[FXa, Lat2, GroupAlone], (instregex "ALC(G)?R$")>;
+
+// Add with sign extension (32 -> 64)
+def : InstRW<[FXa, LSU, Lat6], (instregex "AGF$")>;
+def : InstRW<[FXa, Lat2], (instregex "AGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// Subtraction
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "S(G|Y)?$")>;
+def : InstRW<[FXa, LSU, Lat6], (instregex "SH(Y)?$")>;
+def : InstRW<[FXa], (instregex "SGR(K)?$")>;
+def : InstRW<[FXa], (instregex "SLFI$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "SL(G|GF|Y)?$")>;
+def : InstRW<[FXa], (instregex "SLGF(I|R)$")>;
+def : InstRW<[FXa], (instregex "SLGR(K)?$")>;
+def : InstRW<[FXa], (instregex "SLR(K)?$")>;
+def : InstRW<[FXa], (instregex "SR(K)?$")>;
+
+// Subtraction with borrow
+def : InstRW<[FXa, LSU, Lat6, GroupAlone], (instregex "SLB(G)?$")>;
+def : InstRW<[FXa, Lat2, GroupAlone], (instregex "SLB(G)?R$")>;
+
+// Subtraction with sign extension (32 -> 64)
+def : InstRW<[FXa, LSU, Lat6], (instregex "SGF$")>;
+def : InstRW<[FXa, Lat2], (instregex "SGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// AND
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "N(G|Y)?$")>;
+def : InstRW<[FXa], (instregex "NGR(K)?$")>;
+def : InstRW<[FXa], (instregex "NI(FMux|HMux|LMux)$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "NI(Y)?$")>;
+def : InstRW<[FXa], (instregex "NIHF(64)?$")>;
+def : InstRW<[FXa], (instregex "NIHH(64)?$")>;
+def : InstRW<[FXa], (instregex "NIHL(64)?$")>;
+def : InstRW<[FXa], (instregex "NILF(64)?$")>;
+def : InstRW<[FXa], (instregex "NILH(64)?$")>;
+def : InstRW<[FXa], (instregex "NILL(64)?$")>;
+def : InstRW<[FXa], (instregex "NR(K)?$")>;
+def : InstRW<[LSU, LSU, FXb, Lat9, BeginGroup], (instregex "NC$")>;
+
+//===----------------------------------------------------------------------===//
+// OR
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "O(G|Y)?$")>;
+def : InstRW<[FXa], (instregex "OGR(K)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "OI(Y)?$")>;
+def : InstRW<[FXa], (instregex "OI(FMux|HMux|LMux)$")>;
+def : InstRW<[FXa], (instregex "OIHF(64)?$")>;
+def : InstRW<[FXa], (instregex "OIHH(64)?$")>;
+def : InstRW<[FXa], (instregex "OIHL(64)?$")>;
+def : InstRW<[FXa], (instregex "OILF(64)?$")>;
+def : InstRW<[FXa], (instregex "OILH(64)?$")>;
+def : InstRW<[FXa], (instregex "OILL(64)?$")>;
+def : InstRW<[FXa], (instregex "OR(K)?$")>;
+def : InstRW<[LSU, LSU, FXb, Lat9, BeginGroup], (instregex "OC$")>;
+
+//===----------------------------------------------------------------------===//
+// XOR
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat5], (instregex "X(G|Y)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "XI(Y)?$")>;
+def : InstRW<[FXa], (instregex "XIFMux$")>;
+def : InstRW<[FXa], (instregex "XGR(K)?$")>;
+def : InstRW<[FXa], (instregex "XIHF(64)?$")>;
+def : InstRW<[FXa], (instregex "XILF(64)?$")>;
+def : InstRW<[FXa], (instregex "XR(K)?$")>;
+def : InstRW<[LSU, LSU, FXb, Lat9, BeginGroup], (instregex "XC$")>;
+
+//===----------------------------------------------------------------------===//
+// Multiplication
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat10], (instregex "MS(GF|Y)?$")>;
+def : InstRW<[FXa, Lat6], (instregex "MS(R|FI)$")>;
+def : InstRW<[FXa, LSU, Lat12], (instregex "MSG$")>;
+def : InstRW<[FXa, Lat8], (instregex "MSGR$")>;
+def : InstRW<[FXa, Lat6], (instregex "MSGF(I|R)$")>;
+def : InstRW<[FXa, LSU, Lat15, GroupAlone], (instregex "MLG$")>;
+def : InstRW<[FXa, Lat9, GroupAlone], (instregex "MLGR$")>;
+def : InstRW<[FXa, Lat5], (instregex "MGHI$")>;
+def : InstRW<[FXa, Lat5], (instregex "MHI$")>;
+def : InstRW<[FXa, LSU, Lat9], (instregex "MH(Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Division and remainder
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, Lat30, GroupAlone], (instregex "DSG(F)?R$")>;
+def : InstRW<[LSU, FXa, Lat30, GroupAlone], (instregex "DSG(F)?$")>;
+def : InstRW<[FXa2, FXa2, Lat20, GroupAlone], (instregex "DLR$")>;
+def : InstRW<[FXa2, FXa2, Lat30, GroupAlone], (instregex "DLGR$")>;
+def : InstRW<[FXa2, FXa2, LSU, Lat30, GroupAlone], (instregex "DL(G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Shifts
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "SLL(G|K)?$")>;
+def : InstRW<[FXa], (instregex "SRL(G|K)?$")>;
+def : InstRW<[FXa], (instregex "SRA(G|K)?$")>;
+def : InstRW<[FXa], (instregex "SLA(K)?$")>;
+
+// Rotate
+def : InstRW<[FXa, LSU, Lat6], (instregex "RLL(G)?$")>;
+
+// Rotate and insert
+def : InstRW<[FXa], (instregex "RISBG(N|32)?$")>;
+def : InstRW<[FXa], (instregex "RISBH(G|H|L)$")>;
+def : InstRW<[FXa], (instregex "RISBL(G|H|L)$")>;
+def : InstRW<[FXa], (instregex "RISBMux$")>;
+
+// Rotate and Select
+def : InstRW<[FXa, FXa, Lat3, BeginGroup], (instregex "R(N|O|X)SBG$")>;
+
+//===----------------------------------------------------------------------===//
+// Comparison
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb, LSU, Lat5], (instregex "C(G|Y|Mux|RL)?$")>;
+def : InstRW<[FXb], (instregex "C(F|H)I(Mux)?$")>;
+def : InstRW<[FXb], (instregex "CG(F|H)I$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CG(HSI|RL)$")>;
+def : InstRW<[FXb], (instregex "C(G)?R$")>;
+def : InstRW<[FXb], (instregex "CIH$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CH(F|SI)$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CL(Y|Mux|FHSI)?$")>;
+def : InstRW<[FXb], (instregex "CLFI(Mux)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CLG(HRL|HSI)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CLGF(RL)?$")>;
+def : InstRW<[FXb], (instregex "CLGF(I|R)$")>;
+def : InstRW<[FXb], (instregex "CLGR$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CLGRL$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CLH(F|RL|HSI)$")>;
+def : InstRW<[FXb], (instregex "CLIH$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CLI(Y)?$")>;
+def : InstRW<[FXb], (instregex "CLR$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "CLRL$")>;
+
+// Compare halfword
+def : InstRW<[FXb, LSU, Lat6], (instregex "CH(Y|RL)?$")>;
+def : InstRW<[FXb, LSU, Lat6], (instregex "CGH(RL)?$")>;
+def : InstRW<[FXa, FXb, LSU, Lat6, BeginGroup], (instregex "CHHSI$")>;
+
+// Compare with sign extension (32 -> 64)
+def : InstRW<[FXb, LSU, Lat6], (instregex "CGF(RL)?$")>;
+def : InstRW<[FXb, Lat2], (instregex "CGFR$")>;
+
+// Compare logical character
+def : InstRW<[FXb, LSU, LSU, Lat9, BeginGroup], (instregex "CLC$")>;
+
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "CLST$")>;
+
+// Test under mask
+def : InstRW<[FXb, LSU, Lat5], (instregex "TM(Y)?$")>;
+def : InstRW<[FXb], (instregex "TM(H|L)Mux$")>;
+def : InstRW<[FXb], (instregex "TMHH(64)?$")>;
+def : InstRW<[FXb], (instregex "TMHL(64)?$")>;
+def : InstRW<[FXb], (instregex "TMLH(64)?$")>;
+def : InstRW<[FXb], (instregex "TMLL(64)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Prefetch and execution hint
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU], (instregex "PFD(RL)?$")>;
+def : InstRW<[FXb, Lat2], (instregex "BPP$")>;
+def : InstRW<[FXb, EndGroup], (instregex "BPRP$")>;
+def : InstRW<[FXb], (instregex "NIAI$")>;
+
+//===----------------------------------------------------------------------===//
+// Atomic operations
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb, EndGroup], (instregex "Serialize$")>;
+
+def : InstRW<[FXb, LSU, Lat5], (instregex "LAA(G)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "LAAL(G)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "LAN(G)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "LAO(G)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "LAX(G)?$")>;
+
+// Test and set
+def : InstRW<[FXb, LSU, Lat5, EndGroup], (instregex "TS$")>;
+
+// Compare and swap
+def : InstRW<[FXa, FXb, LSU, Lat6, GroupAlone], (instregex "CS(G|Y)?$")>;
+
+// Compare double and swap
+def : InstRW<[FXa, FXa, FXb, FXb, FXa, LSU, Lat10, GroupAlone],
+ (instregex "CDS(Y)?$")>;
+def : InstRW<[FXa, FXa, FXb, FXb, LSU, FXb, FXb, LSU, LSU, Lat20, GroupAlone],
+ (instregex "CDSG$")>;
+
+// Compare and swap and store
+def : InstRW<[FXa, Lat30, GroupAlone], (instregex "CSST$")>;
+
+// Perform locked operation
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "PLO$")>;
+
+// Load/store pair from/to quadword
+def : InstRW<[LSU, LSU, Lat5, GroupAlone], (instregex "LPQ$")>;
+def : InstRW<[FXb, FXb, LSU, Lat6, GroupAlone], (instregex "STPQ$")>;
+
+// Load pair disjoint
+def : InstRW<[LSU, LSU, Lat5, GroupAlone], (instregex "LPD(G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Access registers
+//===----------------------------------------------------------------------===//
+
+// Extract/set/copy access register
+def : InstRW<[LSU], (instregex "(EAR|SAR|CPYA)$")>;
+
+// Load address extended
+def : InstRW<[LSU, FXa, Lat5, BeginGroup], (instregex "LAE(Y)?$")>;
+
+// Load/store access multiple (not modeled precisely)
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "(L|ST)AM(Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Program mask and addressing mode
+//===----------------------------------------------------------------------===//
+
+// Insert Program Mask
+def : InstRW<[FXa, Lat3, EndGroup], (instregex "IPM$")>;
+
+// Set Program Mask
+def : InstRW<[LSU, EndGroup], (instregex "SPM$")>;
+
+// Branch and link
+def : InstRW<[FXa, FXa, FXb, Lat5, GroupAlone], (instregex "BAL(R)?$")>;
+
+// Test addressing mode
+def : InstRW<[FXb], (instregex "TAM$")>;
+
+// Set addressing mode
+def : InstRW<[FXb, Lat2, EndGroup], (instregex "SAM(24|31|64)$")>;
+
+// Branch (and save) and set mode.
+def : InstRW<[FXa, FXb, Lat2, GroupAlone], (instregex "BSM$")>;
+def : InstRW<[FXa, FXa, FXb, Lat3, GroupAlone], (instregex "BASSM$")>;
+
+//===----------------------------------------------------------------------===//
+// Transactional execution
+//===----------------------------------------------------------------------===//
+
+// Transaction begin
+def : InstRW<[LSU, LSU, FXb, FXb, FXb, FXb, FXb, Lat15, GroupAlone],
+ (instregex "TBEGIN(C|_nofloat)?$")>;
+
+// Transaction end
+def : InstRW<[FXb, GroupAlone], (instregex "TEND$")>;
+
+// Transaction abort
+def : InstRW<[LSU, GroupAlone], (instregex "TABORT$")>;
+
+// Extract Transaction Nesting Depth
+def : InstRW<[FXa], (instregex "ETND$")>;
+
+// Nontransactional store
+def : InstRW<[FXb, LSU, Lat5], (instregex "NTSTG$")>;
+
+//===----------------------------------------------------------------------===//
+// Processor assist
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb], (instregex "PPA$")>;
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Instructions.
+//===----------------------------------------------------------------------===//
+
+// Find leftmost one
+def : InstRW<[FXa, Lat6, GroupAlone], (instregex "FLOGR$")>;
+
+// Population count
+def : InstRW<[FXa, Lat3], (instregex "POPCNT$")>;
+
+// Extend
+def : InstRW<[FXa], (instregex "AEXT128_64$")>;
+def : InstRW<[FXa], (instregex "ZEXT128_(32|64)$")>;
+
+// String instructions
+def : InstRW<[FXa, LSU, Lat30], (instregex "SRST$")>;
+
+// Move with key
+def : InstRW<[FXa, FXa, FXb, LSU, Lat8, GroupAlone], (instregex "MVCK$")>;
+
+// Extract CPU Time
+def : InstRW<[FXa, Lat5, LSU], (instregex "ECTG$")>;
+
+// Execute
+def : InstRW<[FXb, GroupAlone], (instregex "EX(RL)?$")>;
+
+// Program return
+def : InstRW<[FXb, Lat30], (instregex "PR$")>;
+
+// Inline assembly
+def : InstRW<[LSU, LSU, LSU, FXa, FXa, FXb, Lat9, GroupAlone],
+ (instregex "STCK(F)?$")>;
+def : InstRW<[LSU, LSU, LSU, LSU, FXa, FXa, FXb, FXb, Lat11, GroupAlone],
+ (instregex "STCKE$")>;
+def : InstRW<[FXa, LSU, Lat5], (instregex "STFLE$")>;
+def : InstRW<[FXb, Lat30], (instregex "SVC$")>;
+
+// Store real address
+def : InstRW<[FXb, LSU, Lat5], (instregex "STRAG$")>;
+
+//===----------------------------------------------------------------------===//
+// .insn directive instructions
+//===----------------------------------------------------------------------===//
+
+// An "empty" sched-class will be assigned instead of the "invalid sched-class".
+// getNumDecoderSlots() will then return 1 instead of 0.
+def : InstRW<[], (instregex "Insn.*")>;
+
+
+// ----------------------------- Floating point ----------------------------- //
+
+//===----------------------------------------------------------------------===//
+// FP: Select instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa], (instregex "SelectF(32|64|128)$")>;
+def : InstRW<[FXa], (instregex "CondStoreF32(Inv)?$")>;
+def : InstRW<[FXa], (instregex "CondStoreF64(Inv)?$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Move instructions
+//===----------------------------------------------------------------------===//
+
+// Load zero
+def : InstRW<[FXb], (instregex "LZ(DR|ER)$")>;
+def : InstRW<[FXb, FXb, Lat2, BeginGroup], (instregex "LZXR$")>;
+
+// Load
+def : InstRW<[VecXsPm], (instregex "LER$")>;
+def : InstRW<[FXb], (instregex "LD(R|R32|GR)$")>;
+def : InstRW<[FXb, Lat3], (instregex "LGDR$")>;
+def : InstRW<[FXb, FXb, Lat2, GroupAlone], (instregex "LXR$")>;
+
+// Load and Test
+def : InstRW<[VecXsPm, Lat4], (instregex "LT(D|E)BR$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "LTEBRCompare(_VecPseudo)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "LTDBRCompare(_VecPseudo)?$")>;
+def : InstRW<[VecDF2, VecDF2, Lat11, GroupAlone], (instregex "LTXBR$")>;
+def : InstRW<[VecDF2, VecDF2, Lat11, GroupAlone],
+ (instregex "LTXBRCompare(_VecPseudo)?$")>;
+
+// Copy sign
+def : InstRW<[VecXsPm], (instregex "CPSDRd(d|s)$")>;
+def : InstRW<[VecXsPm], (instregex "CPSDRs(d|s)$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Load instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm, LSU, Lat7], (instregex "LE(Y)?$")>;
+def : InstRW<[LSU], (instregex "LD(Y|E32)?$")>;
+def : InstRW<[LSU], (instregex "LX$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Store instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb, LSU, Lat7], (instregex "STD(Y)?$")>;
+def : InstRW<[FXb, LSU, Lat7], (instregex "STE(Y)?$")>;
+def : InstRW<[FXb, LSU, Lat5], (instregex "STX$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Conversion instructions
+//===----------------------------------------------------------------------===//
+
+// Load rounded
+def : InstRW<[VecBF], (instregex "LEDBR(A)?$")>;
+def : InstRW<[VecDF, VecDF, Lat20], (instregex "LEXBR(A)?$")>;
+def : InstRW<[VecDF, VecDF, Lat20], (instregex "LDXBR(A)?$")>;
+
+// Load lengthened
+def : InstRW<[VecBF, LSU, Lat12], (instregex "LDEB$")>;
+def : InstRW<[VecBF], (instregex "LDEBR$")>;
+def : InstRW<[VecBF2, VecBF2, LSU, Lat12 , GroupAlone], (instregex "LX(D|E)B$")>;
+def : InstRW<[VecBF2, VecBF2, GroupAlone], (instregex "LX(D|E)BR$")>;
+
+// Convert from fixed / logical
+def : InstRW<[FXb, VecBF, Lat9, BeginGroup], (instregex "CE(F|G)BR(A)?$")>;
+def : InstRW<[FXb, VecBF, Lat9, BeginGroup], (instregex "CD(F|G)BR(A)?$")>;
+def : InstRW<[FXb, VecDF2, VecDF2, Lat12, GroupAlone], (instregex "CX(F|G)BR(A)?$")>;
+def : InstRW<[FXb, VecBF, Lat9, BeginGroup], (instregex "CEL(F|G)BR$")>;
+def : InstRW<[FXb, VecBF, Lat9, BeginGroup], (instregex "CDL(F|G)BR$")>;
+def : InstRW<[FXb, VecDF2, VecDF2, Lat12, GroupAlone], (instregex "CXL(F|G)BR$")>;
+
+// Convert to fixed / logical
+def : InstRW<[FXb, VecBF, Lat11, BeginGroup], (instregex "CF(E|D)BR(A)?$")>;
+def : InstRW<[FXb, VecBF, Lat11, BeginGroup], (instregex "CG(E|D)BR(A)?$")>;
+def : InstRW<[FXb, VecDF, VecDF, Lat20, BeginGroup], (instregex "C(F|G)XBR(A)?$")>;
+def : InstRW<[FXb, VecBF, Lat11, GroupAlone], (instregex "CLFEBR$")>;
+def : InstRW<[FXb, VecBF, Lat11, BeginGroup], (instregex "CLFDBR$")>;
+def : InstRW<[FXb, VecBF, Lat11, BeginGroup], (instregex "CLG(E|D)BR$")>;
+def : InstRW<[FXb, VecDF, VecDF, Lat20, BeginGroup], (instregex "CL(F|G)XBR$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Unary arithmetic
+//===----------------------------------------------------------------------===//
+
+// Load Complement / Negative / Positive
+def : InstRW<[VecXsPm, Lat4], (instregex "L(C|N|P)DBR$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "L(C|N|P)EBR$")>;
+def : InstRW<[FXb], (instregex "LCDFR(_32)?$")>;
+def : InstRW<[FXb], (instregex "LNDFR(_32)?$")>;
+def : InstRW<[FXb], (instregex "LPDFR(_32)?$")>;
+def : InstRW<[VecDF2, VecDF2, Lat11, GroupAlone], (instregex "L(C|N|P)XBR$")>;
+
+// Square root
+def : InstRW<[VecFPd, LSU], (instregex "SQ(E|D)B$")>;
+def : InstRW<[VecFPd], (instregex "SQ(E|D)BR$")>;
+def : InstRW<[VecFPd, VecFPd, GroupAlone], (instregex "SQXBR$")>;
+
+// Load FP integer
+def : InstRW<[VecBF], (instregex "FIEBR(A)?$")>;
+def : InstRW<[VecBF], (instregex "FIDBR(A)?$")>;
+def : InstRW<[VecDF2, VecDF2, Lat11, GroupAlone], (instregex "FIXBR(A)?$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Binary arithmetic
+//===----------------------------------------------------------------------===//
+
+// Addition
+def : InstRW<[VecBF, LSU, Lat12], (instregex "A(E|D)B$")>;
+def : InstRW<[VecBF], (instregex "A(E|D)BR$")>;
+def : InstRW<[VecDF2, VecDF2, Lat11, GroupAlone], (instregex "AXBR$")>;
+
+// Subtraction
+def : InstRW<[VecBF, LSU, Lat12], (instregex "S(E|D)B$")>;
+def : InstRW<[VecBF], (instregex "S(E|D)BR$")>;
+def : InstRW<[VecDF2, VecDF2, Lat11, GroupAlone], (instregex "SXBR$")>;
+
+// Multiply
+def : InstRW<[VecBF, LSU, Lat12], (instregex "M(D|DE|EE)B$")>;
+def : InstRW<[VecBF], (instregex "M(D|DE|EE)BR$")>;
+def : InstRW<[VecBF2, VecBF2, LSU, Lat12, GroupAlone], (instregex "MXDB$")>;
+def : InstRW<[VecBF2, VecBF2, GroupAlone], (instregex "MXDBR$")>;
+def : InstRW<[VecDF2, VecDF2, Lat20, GroupAlone], (instregex "MXBR$")>;
+
+// Multiply and add / subtract
+def : InstRW<[VecBF, LSU, Lat12, GroupAlone], (instregex "M(A|S)EB$")>;
+def : InstRW<[VecBF, GroupAlone], (instregex "M(A|S)EBR$")>;
+def : InstRW<[VecBF, LSU, Lat12, GroupAlone], (instregex "M(A|S)DB$")>;
+def : InstRW<[VecBF], (instregex "M(A|S)DBR$")>;
+
+// Division
+def : InstRW<[VecFPd, LSU], (instregex "D(E|D)B$")>;
+def : InstRW<[VecFPd], (instregex "D(E|D)BR$")>;
+def : InstRW<[VecFPd, VecFPd, GroupAlone], (instregex "DXBR$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Comparisons
+//===----------------------------------------------------------------------===//
+
+// Compare
+def : InstRW<[VecXsPm, LSU, Lat8], (instregex "C(E|D)B$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "C(E|D)BR?$")>;
+def : InstRW<[VecDF, VecDF, Lat20, GroupAlone], (instregex "CXBR$")>;
+
+// Test Data Class
+def : InstRW<[LSU, VecXsPm, Lat9], (instregex "TC(E|D)B$")>;
+def : InstRW<[LSU, VecDF2, VecDF2, Lat15, GroupAlone], (instregex "TCXB$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Floating-point control register instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXa, LSU, Lat4, GroupAlone], (instregex "EFPC$")>;
+def : InstRW<[FXb, LSU, Lat5, GroupAlone], (instregex "STFPC$")>;
+def : InstRW<[LSU, Lat3, GroupAlone], (instregex "SFPC$")>;
+def : InstRW<[LSU, LSU, Lat6, GroupAlone], (instregex "LFPC$")>;
+def : InstRW<[FXa, Lat30, GroupAlone], (instregex "SFASR$")>;
+def : InstRW<[FXa, LSU, Lat30, GroupAlone], (instregex "LFAS$")>;
+def : InstRW<[FXb, Lat3, GroupAlone], (instregex "SRNM(B|T)?$")>;
+
+// --------------------------------- Vector --------------------------------- //
+
+//===----------------------------------------------------------------------===//
+// Vector: Move instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb], (instregex "VLR(32|64)?$")>;
+def : InstRW<[FXb, Lat4], (instregex "VLGV(B|F|G|H)?$")>;
+def : InstRW<[FXb], (instregex "VLVG(B|F|G|H)?$")>;
+def : InstRW<[FXb, Lat2], (instregex "VLVGP(32)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Immediate instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm], (instregex "VZERO$")>;
+def : InstRW<[VecXsPm], (instregex "VONE$")>;
+def : InstRW<[VecXsPm], (instregex "VGBM$")>;
+def : InstRW<[VecXsPm], (instregex "VGM(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VLEI(B|F|G|H)$")>;
+def : InstRW<[VecXsPm], (instregex "VREPI(B|F|G|H)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Loads
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU], (instregex "VL(L|BB)?$")>;
+def : InstRW<[LSU], (instregex "VL(32|64)$")>;
+def : InstRW<[LSU], (instregex "VLLEZ(B|F|G|H)?$")>;
+def : InstRW<[LSU], (instregex "VLREP(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm, LSU, Lat7], (instregex "VLE(B|F|G|H)$")>;
+def : InstRW<[FXb, LSU, VecXsPm, Lat11, BeginGroup], (instregex "VGE(F|G)$")>;
+def : InstRW<[LSU, LSU, LSU, LSU, LSU, Lat10, GroupAlone],
+ (instregex "VLM$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Stores
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb, LSU, Lat8], (instregex "VST(L|32|64)?$")>;
+def : InstRW<[FXb, LSU, Lat8], (instregex "VSTE(F|G)$")>;
+def : InstRW<[FXb, LSU, VecXsPm, Lat11, BeginGroup], (instregex "VSTE(B|H)$")>;
+def : InstRW<[LSU, LSU, FXb, FXb, FXb, FXb, FXb, Lat20, GroupAlone],
+ (instregex "VSTM$")>;
+def : InstRW<[FXb, FXb, LSU, Lat12, BeginGroup], (instregex "VSCE(F|G)$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Selects and permutes
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm], (instregex "VMRH(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VMRL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VPERM$")>;
+def : InstRW<[VecXsPm], (instregex "VPDI$")>;
+def : InstRW<[VecXsPm], (instregex "VREP(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VSEL$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Widening and narrowing
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm], (instregex "VPK(F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VPKS(F|G|H)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VPKS(F|G|H)S$")>;
+def : InstRW<[VecXsPm], (instregex "VPKLS(F|G|H)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VPKLS(F|G|H)S$")>;
+def : InstRW<[VecXsPm], (instregex "VSEG(B|F|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VUPH(B|F|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VUPL(B|F)?$")>;
+def : InstRW<[VecXsPm], (instregex "VUPLH(B|F|H|W)?$")>;
+def : InstRW<[VecXsPm], (instregex "VUPLL(B|F|H)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Integer arithmetic
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm], (instregex "VA(B|F|G|H|Q|C|CQ)?$")>;
+def : InstRW<[VecXsPm], (instregex "VACC(B|F|G|H|Q|C|CQ)?$")>;
+def : InstRW<[VecXsPm], (instregex "VAVG(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VAVGL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VN(C|O)?$")>;
+def : InstRW<[VecXsPm], (instregex "VO$")>;
+def : InstRW<[VecMul], (instregex "VCKSM$")>;
+def : InstRW<[VecXsPm], (instregex "VCLZ(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VCTZ(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VX$")>;
+def : InstRW<[VecMul], (instregex "VGFM?$")>;
+def : InstRW<[VecMul], (instregex "VGFMA(B|F|G|H)?$")>;
+def : InstRW<[VecMul], (instregex "VGFM(B|F|G|H)$")>;
+def : InstRW<[VecXsPm], (instregex "VLC(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VLP(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VMX(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VMXL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VMN(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VMNL(B|F|G|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMAL(B|F)?$")>;
+def : InstRW<[VecMul], (instregex "VMALE(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMALH(B|F|H|W)?$")>;
+def : InstRW<[VecMul], (instregex "VMALO(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMAO(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMAE(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMAH(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VME(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMH(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VML(B|F)?$")>;
+def : InstRW<[VecMul], (instregex "VMLE(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMLH(B|F|H|W)?$")>;
+def : InstRW<[VecMul], (instregex "VMLO(B|F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VMO(B|F|H)?$")>;
+
+def : InstRW<[VecXsPm], (instregex "VPOPCT$")>;
+
+def : InstRW<[VecXsPm], (instregex "VERLL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VERLLV(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VERIM(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VESL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VESLV(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VESRA(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VESRAV(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VESRL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VESRLV(B|F|G|H)?$")>;
+
+def : InstRW<[VecXsPm], (instregex "VSL(DB)?$")>;
+def : InstRW<[VecXsPm, VecXsPm, Lat8], (instregex "VSLB$")>;
+def : InstRW<[VecXsPm], (instregex "VSR(A|L)$")>;
+def : InstRW<[VecXsPm, VecXsPm, Lat8], (instregex "VSR(A|L)B$")>;
+
+def : InstRW<[VecXsPm], (instregex "VSB(I|IQ|CBI|CBIQ)?$")>;
+def : InstRW<[VecXsPm], (instregex "VSCBI(B|F|G|H|Q)?$")>;
+def : InstRW<[VecXsPm], (instregex "VS(F|G|H|Q)?$")>;
+
+def : InstRW<[VecMul], (instregex "VSUM(B|H)?$")>;
+def : InstRW<[VecMul], (instregex "VSUMG(F|H)?$")>;
+def : InstRW<[VecMul], (instregex "VSUMQ(F|G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Integer comparison
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm, Lat4], (instregex "VEC(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VECL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm], (instregex "VCEQ(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VCEQ(B|F|G|H)S$")>;
+def : InstRW<[VecXsPm], (instregex "VCH(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VCH(B|F|G|H)S$")>;
+def : InstRW<[VecXsPm], (instregex "VCHL(B|F|G|H)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VCHL(B|F|G|H)S$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VTM$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Floating-point arithmetic
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecBF2], (instregex "VCD(G|GB|LG|LGB)$")>;
+def : InstRW<[VecBF], (instregex "WCD(GB|LGB)$")>;
+def : InstRW<[VecBF2], (instregex "VC(L)?GD$")>;
+def : InstRW<[VecBF2], (instregex "VFADB$")>;
+def : InstRW<[VecBF], (instregex "WFADB$")>;
+def : InstRW<[VecBF2], (instregex "VCGDB$")>;
+def : InstRW<[VecBF], (instregex "WCGDB$")>;
+def : InstRW<[VecBF2], (instregex "VF(I|M|A|S)$")>;
+def : InstRW<[VecBF2], (instregex "VF(I|M|S)DB$")>;
+def : InstRW<[VecBF], (instregex "WF(I|M|S)DB$")>;
+def : InstRW<[VecBF2], (instregex "VCLGDB$")>;
+def : InstRW<[VecBF], (instregex "WCLGDB$")>;
+def : InstRW<[VecXsPm], (instregex "VFL(C|N|P)DB$")>;
+def : InstRW<[VecXsPm], (instregex "WFL(C|N|P)DB$")>;
+def : InstRW<[VecBF2], (instregex "VFM(A|S)$")>;
+def : InstRW<[VecBF2], (instregex "VFM(A|S)DB$")>;
+def : InstRW<[VecBF], (instregex "WFM(A|S)DB$")>;
+def : InstRW<[VecXsPm], (instregex "VFPSO$")>;
+def : InstRW<[VecXsPm], (instregex "(V|W)FPSODB$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VFTCI(DB)?$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "WFTCIDB$")>;
+def : InstRW<[VecBF2], (instregex "VL(DE|ED)$")>;
+def : InstRW<[VecBF2], (instregex "VL(DE|ED)B$")>;
+def : InstRW<[VecBF], (instregex "WL(DE|ED)B$")>;
+
+// divide / square root
+def : InstRW<[VecFPd], (instregex "VFD$")>;
+def : InstRW<[VecFPd], (instregex "(V|W)FDDB$")>;
+def : InstRW<[VecFPd], (instregex "VFSQ$")>;
+def : InstRW<[VecFPd], (instregex "(V|W)FSQDB$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Floating-point comparison
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecXsPm], (instregex "VFC(E|H|HE)$")>;
+def : InstRW<[VecXsPm], (instregex "VFC(E|H|HE)DB$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "WF(C|K)$")>;
+def : InstRW<[VecXsPm], (instregex "WFC(E|H|HE)DB$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "VFC(E|H|HE)DBS$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "WFC(E|H|HE)DBS$")>;
+def : InstRW<[VecXsPm, Lat4], (instregex "WF(C|K)DB$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: Floating-point insertion and extraction
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXb], (instregex "LEFR$")>;
+def : InstRW<[FXb, Lat4], (instregex "LFER$")>;
+
+//===----------------------------------------------------------------------===//
+// Vector: String instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[VecStr], (instregex "VFAE(B)?$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VFAEBS$")>;
+def : InstRW<[VecStr], (instregex "VFAE(F|H)$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VFAE(F|H)S$")>;
+def : InstRW<[VecStr], (instregex "VFAEZ(B|F|H)$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VFAEZ(B|F|H)S$")>;
+def : InstRW<[VecStr], (instregex "VFEE(B|F|H|ZB|ZF|ZH)?$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VFEE(B|F|H|ZB|ZF|ZH)S$")>;
+def : InstRW<[VecStr], (instregex "VFENE(B|F|H|ZB|ZF|ZH)?$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VFENE(B|F|H|ZB|ZF|ZH)S$")>;
+def : InstRW<[VecStr], (instregex "VISTR(B|F|H)?$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VISTR(B|F|H)S$")>;
+def : InstRW<[VecStr], (instregex "VSTRC(B|F|H)?$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VSTRC(B|F|H)S$")>;
+def : InstRW<[VecStr], (instregex "VSTRCZ(B|F|H)$")>;
+def : InstRW<[VecStr, Lat5], (instregex "VSTRCZ(B|F|H)S$")>;
+
+}
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td b/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td
new file mode 100644
index 0000000..a950e54
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZ196.td
@@ -0,0 +1,769 @@
+//=- SystemZScheduleZ196.td - SystemZ Scheduling Definitions ---*- tblgen -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the machine model for Z196 to support instruction
+// scheduling and other instruction cost heuristics.
+//
+//===----------------------------------------------------------------------===//
+
+def Z196Model : SchedMachineModel {
+
+ let UnsupportedFeatures = Arch9UnsupportedFeatures.List;
+
+ let IssueWidth = 5;
+ let MicroOpBufferSize = 40; // Issue queues
+ let LoadLatency = 1; // Optimistic load latency.
+
+ let PostRAScheduler = 1;
+
+ // Extra cycles for a mispredicted branch.
+ let MispredictPenalty = 16;
+}
+
+let SchedModel = Z196Model in {
+
+// These definitions could be put in a subtarget common include file,
+// but it seems the include system in Tablegen currently rejects
+// multiple includes of same file.
+def : WriteRes<GroupAlone, []> {
+ let NumMicroOps = 0;
+ let BeginGroup = 1;
+ let EndGroup = 1;
+}
+def : WriteRes<EndGroup, []> {
+ let NumMicroOps = 0;
+ let EndGroup = 1;
+}
+def : WriteRes<Lat2, []> { let Latency = 2; let NumMicroOps = 0;}
+def : WriteRes<Lat3, []> { let Latency = 3; let NumMicroOps = 0;}
+def : WriteRes<Lat4, []> { let Latency = 4; let NumMicroOps = 0;}
+def : WriteRes<Lat5, []> { let Latency = 5; let NumMicroOps = 0;}
+def : WriteRes<Lat6, []> { let Latency = 6; let NumMicroOps = 0;}
+def : WriteRes<Lat7, []> { let Latency = 7; let NumMicroOps = 0;}
+def : WriteRes<Lat8, []> { let Latency = 8; let NumMicroOps = 0;}
+def : WriteRes<Lat9, []> { let Latency = 9; let NumMicroOps = 0;}
+def : WriteRes<Lat10, []> { let Latency = 10; let NumMicroOps = 0;}
+def : WriteRes<Lat11, []> { let Latency = 11; let NumMicroOps = 0;}
+def : WriteRes<Lat12, []> { let Latency = 12; let NumMicroOps = 0;}
+def : WriteRes<Lat15, []> { let Latency = 15; let NumMicroOps = 0;}
+def : WriteRes<Lat20, []> { let Latency = 20; let NumMicroOps = 0;}
+def : WriteRes<Lat30, []> { let Latency = 30; let NumMicroOps = 0;}
+
+// Execution units.
+def Z196_FXUnit : ProcResource<2>;
+def Z196_LSUnit : ProcResource<2>;
+def Z196_FPUnit : ProcResource<1>;
+
+// Subtarget specific definitions of scheduling resources.
+def : WriteRes<FXU, [Z196_FXUnit]> { let Latency = 1; }
+def : WriteRes<LSU, [Z196_LSUnit]> { let Latency = 4; }
+def : WriteRes<LSU_lat1, [Z196_LSUnit]> { let Latency = 1; }
+def : WriteRes<FPU, [Z196_FPUnit]> { let Latency = 8; }
+def : WriteRes<FPU2, [Z196_FPUnit, Z196_FPUnit]> { let Latency = 9; }
+
+// -------------------------- INSTRUCTIONS ---------------------------------- //
+
+// InstRW constructs have been used in order to preserve the
+// readability of the InstrInfo files.
+
+// For each instruction, as matched by a regexp, provide a list of
+// resources that it needs. These will be combined into a SchedClass.
+
+//===----------------------------------------------------------------------===//
+// Stack allocation
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "ADJDYNALLOC$")>; // Pseudo -> LA / LAY
+
+//===----------------------------------------------------------------------===//
+// Branch instructions
+//===----------------------------------------------------------------------===//
+
+// Branch
+def : InstRW<[LSU, EndGroup], (instregex "(Call)?BRC(L)?(Asm.*)?$")>;
+def : InstRW<[LSU, EndGroup], (instregex "(Call)?J(G)?(Asm.*)?$")>;
+def : InstRW<[LSU, EndGroup], (instregex "(Call)?BC(R)?(Asm.*)?$")>;
+def : InstRW<[LSU, EndGroup], (instregex "(Call)?B(R)?(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BRCT(G|H)?$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BCT(G)?(R)?$")>;
+def : InstRW<[FXU, FXU, FXU, LSU, Lat7, GroupAlone],
+ (instregex "B(R)?X(H|L).*$")>;
+
+// Compare and branch
+def : InstRW<[FXU, LSU, Lat5, GroupAlone],
+ (instregex "C(L)?(G)?(I|R)J(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone],
+ (instregex "C(L)?(G)?(I|R)B(Call|Return|Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Trap instructions
+//===----------------------------------------------------------------------===//
+
+// Trap
+def : InstRW<[LSU, EndGroup], (instregex "(Cond)?Trap$")>;
+
+// Compare and trap
+def : InstRW<[FXU], (instregex "C(G)?(I|R)T(Asm.*)?$")>;
+def : InstRW<[FXU], (instregex "CL(G)?RT(Asm.*)?$")>;
+def : InstRW<[FXU], (instregex "CL(F|G)IT(Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Call and return instructions
+//===----------------------------------------------------------------------===//
+
+// Call
+def : InstRW<[LSU, FXU, FXU, Lat6, GroupAlone], (instregex "(Call)?BRAS$")>;
+def : InstRW<[LSU, FXU, FXU, Lat6, GroupAlone], (instregex "(Call)?BRASL$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
+def : InstRW<[LSU, FXU, FXU, Lat6, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
+
+// Return
+def : InstRW<[LSU_lat1, EndGroup], (instregex "Return$")>;
+def : InstRW<[LSU_lat1, EndGroup], (instregex "CondReturn$")>;
+
+//===----------------------------------------------------------------------===//
+// Select instructions
+//===----------------------------------------------------------------------===//
+
+// Select pseudo
+def : InstRW<[FXU], (instregex "Select(32|64|32Mux)$")>;
+
+// CondStore pseudos
+def : InstRW<[FXU], (instregex "CondStore16(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore16Mux(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore32(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore64(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore8(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore8Mux(Inv)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Move instructions
+//===----------------------------------------------------------------------===//
+
+// Moves
+def : InstRW<[FXU, LSU, Lat5], (instregex "MV(G|H)?HI$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "MVI(Y)?$")>;
+
+// Move character
+def : InstRW<[LSU, LSU, LSU, FXU, Lat8, GroupAlone], (instregex "MVC$")>;
+
+// Pseudo -> reg move
+def : InstRW<[FXU], (instregex "COPY(_TO_REGCLASS)?$")>;
+def : InstRW<[FXU], (instregex "EXTRACT_SUBREG$")>;
+def : InstRW<[FXU], (instregex "INSERT_SUBREG$")>;
+def : InstRW<[FXU], (instregex "REG_SEQUENCE$")>;
+def : InstRW<[FXU], (instregex "SUBREG_TO_REG$")>;
+
+// Loads
+def : InstRW<[LSU], (instregex "L(Y|FH|RL|Mux)?$")>;
+def : InstRW<[LSU], (instregex "LG(RL)?$")>;
+def : InstRW<[LSU], (instregex "L128$")>;
+
+def : InstRW<[FXU], (instregex "LLIH(F|H|L)$")>;
+def : InstRW<[FXU], (instregex "LLIL(F|H|L)$")>;
+
+def : InstRW<[FXU], (instregex "LG(F|H)I$")>;
+def : InstRW<[FXU], (instregex "LHI(Mux)?$")>;
+def : InstRW<[FXU], (instregex "LR(Mux)?$")>;
+
+// Load and test
+def : InstRW<[FXU, LSU, Lat5], (instregex "LT(G)?$")>;
+def : InstRW<[FXU], (instregex "LT(G)?R$")>;
+
+// Stores
+def : InstRW<[FXU, LSU, Lat5], (instregex "STG(RL)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ST128$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ST(Y|FH|RL|Mux)?$")>;
+
+// String moves.
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "MVST$")>;
+
+//===----------------------------------------------------------------------===//
+// Conditional move instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, Lat2, EndGroup], (instregex "LOC(G)?R(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat6, EndGroup], (instregex "LOC(G)?(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat5, EndGroup], (instregex "STOC(G)?(Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Sign extensions
+//===----------------------------------------------------------------------===//
+def : InstRW<[FXU], (instregex "L(B|H|G)R$")>;
+def : InstRW<[FXU], (instregex "LG(B|H|F)R$")>;
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "LTGF$")>;
+def : InstRW<[FXU], (instregex "LTGFR$")>;
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "LB(H|Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LH(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LH(H|Mux|RL)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LG(B|H|F)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LG(H|F)RL$")>;
+
+//===----------------------------------------------------------------------===//
+// Zero extensions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "LLCR(Mux)?$")>;
+def : InstRW<[FXU], (instregex "LLHR(Mux)?$")>;
+def : InstRW<[FXU], (instregex "LLG(C|F|H|T)R$")>;
+def : InstRW<[LSU], (instregex "LLC(Mux)?$")>;
+def : InstRW<[LSU], (instregex "LLH(Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LL(C|H)H$")>;
+def : InstRW<[LSU], (instregex "LLHRL$")>;
+def : InstRW<[LSU], (instregex "LLG(C|F|H|T|FRL|HRL)$")>;
+
+//===----------------------------------------------------------------------===//
+// Truncations
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "STC(H|Y|Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STH(H|Y|RL|Mux)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Multi-register moves
+//===----------------------------------------------------------------------===//
+
+// Load multiple (estimated average of 5 ops)
+def : InstRW<[LSU, LSU, LSU, LSU, LSU, Lat10, GroupAlone],
+ (instregex "LM(H|Y|G)?$")>;
+
+// Store multiple (estimated average of 3 ops)
+def : InstRW<[LSU, LSU, FXU, FXU, FXU, Lat10, GroupAlone],
+ (instregex "STM(H|Y|G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Byte swaps
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "LRV(G)?R$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LRV(G|H)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STRV(G|H)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Load address instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "LA(Y|RL)?$")>;
+
+// Load the Global Offset Table address
+def : InstRW<[FXU], (instregex "GOT$")>;
+
+//===----------------------------------------------------------------------===//
+// Absolute and Negation
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, Lat2], (instregex "LP(G)?R$")>;
+def : InstRW<[FXU, FXU, Lat3, GroupAlone], (instregex "L(N|P)GFR$")>;
+def : InstRW<[FXU, Lat2], (instregex "LN(R|GR)$")>;
+def : InstRW<[FXU], (instregex "LC(R|GR)$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "LCGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// Insertion
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "IC(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "IC32(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ICM(H|Y)?$")>;
+def : InstRW<[FXU], (instregex "II(F|H|L)Mux$")>;
+def : InstRW<[FXU], (instregex "IIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "IIHH(64)?$")>;
+def : InstRW<[FXU], (instregex "IIHL(64)?$")>;
+def : InstRW<[FXU], (instregex "IILF(64)?$")>;
+def : InstRW<[FXU], (instregex "IILH(64)?$")>;
+def : InstRW<[FXU], (instregex "IILL(64)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Addition
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "A(Y|SI)?$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "AH(Y)?$")>;
+def : InstRW<[FXU], (instregex "AIH$")>;
+def : InstRW<[FXU], (instregex "AFI(Mux)?$")>;
+def : InstRW<[FXU], (instregex "AGFI$")>;
+def : InstRW<[FXU], (instregex "AGHI(K)?$")>;
+def : InstRW<[FXU], (instregex "AGR(K)?$")>;
+def : InstRW<[FXU], (instregex "AHI(K)?$")>;
+def : InstRW<[FXU], (instregex "AHIMux(K)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "AL(Y)?$")>;
+def : InstRW<[FXU], (instregex "AL(FI|HSIK)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ALG(F)?$")>;
+def : InstRW<[FXU], (instregex "ALGHSIK$")>;
+def : InstRW<[FXU], (instregex "ALGF(I|R)$")>;
+def : InstRW<[FXU], (instregex "ALGR(K)?$")>;
+def : InstRW<[FXU], (instregex "ALR(K)?$")>;
+def : InstRW<[FXU], (instregex "AR(K)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "AG(SI)?$")>;
+
+// Logical addition with carry
+def : InstRW<[FXU, LSU, Lat7, GroupAlone], (instregex "ALC(G)?$")>;
+def : InstRW<[FXU, Lat3, GroupAlone], (instregex "ALC(G)?R$")>;
+
+// Add with sign extension (32 -> 64)
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "AGF$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "AGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// Subtraction
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "S(G|Y)?$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "SH(Y)?$")>;
+def : InstRW<[FXU], (instregex "SGR(K)?$")>;
+def : InstRW<[FXU], (instregex "SLFI$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "SL(G|GF|Y)?$")>;
+def : InstRW<[FXU], (instregex "SLGF(I|R)$")>;
+def : InstRW<[FXU], (instregex "SLGR(K)?$")>;
+def : InstRW<[FXU], (instregex "SLR(K)?$")>;
+def : InstRW<[FXU], (instregex "SR(K)?$")>;
+
+// Subtraction with borrow
+def : InstRW<[FXU, LSU, Lat7, GroupAlone], (instregex "SLB(G)?$")>;
+def : InstRW<[FXU, Lat3, GroupAlone], (instregex "SLB(G)?R$")>;
+
+// Subtraction with sign extension (32 -> 64)
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "SGF$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "SGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// AND
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "N(G|Y)?$")>;
+def : InstRW<[FXU], (instregex "NGR(K)?$")>;
+def : InstRW<[FXU], (instregex "NI(FMux|HMux|LMux)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "NI(Y)?$")>;
+def : InstRW<[FXU], (instregex "NIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "NIHH(64)?$")>;
+def : InstRW<[FXU], (instregex "NIHL(64)?$")>;
+def : InstRW<[FXU], (instregex "NILF(64)?$")>;
+def : InstRW<[FXU], (instregex "NILH(64)?$")>;
+def : InstRW<[FXU], (instregex "NILL(64)?$")>;
+def : InstRW<[FXU], (instregex "NR(K)?$")>;
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "NC$")>;
+
+//===----------------------------------------------------------------------===//
+// OR
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "O(G|Y)?$")>;
+def : InstRW<[FXU], (instregex "OGR(K)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "OI(Y)?$")>;
+def : InstRW<[FXU], (instregex "OI(FMux|HMux|LMux)$")>;
+def : InstRW<[FXU], (instregex "OIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "OIHH(64)?$")>;
+def : InstRW<[FXU], (instregex "OIHL(64)?$")>;
+def : InstRW<[FXU], (instregex "OILF(64)?$")>;
+def : InstRW<[FXU], (instregex "OILH(64)?$")>;
+def : InstRW<[FXU], (instregex "OILL(64)?$")>;
+def : InstRW<[FXU], (instregex "OR(K)?$")>;
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "OC$")>;
+
+//===----------------------------------------------------------------------===//
+// XOR
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "X(G|Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "XI(Y)?$")>;
+def : InstRW<[FXU], (instregex "XIFMux$")>;
+def : InstRW<[FXU], (instregex "XGR(K)?$")>;
+def : InstRW<[FXU], (instregex "XIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "XILF(64)?$")>;
+def : InstRW<[FXU], (instregex "XR(K)?$")>;
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "XC$")>;
+
+//===----------------------------------------------------------------------===//
+// Multiplication
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat10], (instregex "MS(GF|Y)?$")>;
+def : InstRW<[FXU, Lat6], (instregex "MS(R|FI)$")>;
+def : InstRW<[FXU, LSU, Lat12], (instregex "MSG$")>;
+def : InstRW<[FXU, Lat8], (instregex "MSGR$")>;
+def : InstRW<[FXU, Lat6], (instregex "MSGF(I|R)$")>;
+def : InstRW<[FXU, LSU, Lat15, GroupAlone], (instregex "MLG$")>;
+def : InstRW<[FXU, Lat9, GroupAlone], (instregex "MLGR$")>;
+def : InstRW<[FXU, Lat5], (instregex "MGHI$")>;
+def : InstRW<[FXU, Lat5], (instregex "MHI$")>;
+def : InstRW<[FXU, LSU, Lat9], (instregex "MH(Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Division and remainder
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FPU2, FPU2, FXU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DSG(F)?R$")>;
+def : InstRW<[FPU2, FPU2, LSU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DSG(F)?$")>;
+def : InstRW<[FPU2, FPU2, FXU, FXU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DL(G)?R$")>;
+def : InstRW<[FPU2, FPU2, LSU, FXU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DL(G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Shifts
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "SLL(G|K)?$")>;
+def : InstRW<[FXU], (instregex "SRL(G|K)?$")>;
+def : InstRW<[FXU], (instregex "SRA(G|K)?$")>;
+def : InstRW<[FXU, Lat2], (instregex "SLA(K)?$")>;
+
+// Rotate
+def : InstRW<[FXU, LSU, Lat6], (instregex "RLL(G)?$")>;
+
+// Rotate and insert
+def : InstRW<[FXU], (instregex "RISBG(32)?$")>;
+def : InstRW<[FXU], (instregex "RISBH(G|H|L)$")>;
+def : InstRW<[FXU], (instregex "RISBL(G|H|L)$")>;
+def : InstRW<[FXU], (instregex "RISBMux$")>;
+
+// Rotate and Select
+def : InstRW<[FXU, FXU, Lat3, GroupAlone], (instregex "R(N|O|X)SBG$")>;
+
+//===----------------------------------------------------------------------===//
+// Comparison
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "C(G|Y|Mux|RL)?$")>;
+def : InstRW<[FXU], (instregex "C(F|H)I(Mux)?$")>;
+def : InstRW<[FXU], (instregex "CG(F|H)I$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CG(HSI|RL)$")>;
+def : InstRW<[FXU], (instregex "C(G)?R$")>;
+def : InstRW<[FXU], (instregex "CIH$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CH(F|SI)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CL(Y|Mux|FHSI)?$")>;
+def : InstRW<[FXU], (instregex "CLFI(Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLG(HRL|HSI)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLGF(RL)?$")>;
+def : InstRW<[FXU], (instregex "CLGF(I|R)$")>;
+def : InstRW<[FXU], (instregex "CLGR$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLGRL$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLH(F|RL|HSI)$")>;
+def : InstRW<[FXU], (instregex "CLIH$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLI(Y)?$")>;
+def : InstRW<[FXU], (instregex "CLR$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLRL$")>;
+
+// Compare halfword
+def : InstRW<[FXU, LSU, FXU, Lat6, GroupAlone], (instregex "CH(Y|RL)?$")>;
+def : InstRW<[FXU, LSU, FXU, Lat6, GroupAlone], (instregex "CGH(RL)?$")>;
+def : InstRW<[FXU, LSU, FXU, Lat6, GroupAlone], (instregex "CHHSI$")>;
+
+// Compare with sign extension (32 -> 64)
+def : InstRW<[FXU, FXU, LSU, Lat6, Lat2, GroupAlone], (instregex "CGF(RL)?$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "CGFR$")>;
+
+// Compare logical character
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "CLC$")>;
+
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "CLST$")>;
+
+// Test under mask
+def : InstRW<[FXU, LSU, Lat5], (instregex "TM(Y)?$")>;
+def : InstRW<[FXU], (instregex "TM(H|L)Mux$")>;
+def : InstRW<[FXU], (instregex "TMHH(64)?$")>;
+def : InstRW<[FXU], (instregex "TMHL(64)?$")>;
+def : InstRW<[FXU], (instregex "TMLH(64)?$")>;
+def : InstRW<[FXU], (instregex "TMLL(64)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Prefetch
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU, GroupAlone], (instregex "PFD(RL)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Atomic operations
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU, EndGroup], (instregex "Serialize$")>;
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAA(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAAL(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAN(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAO(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAX(G)?$")>;
+
+// Test and set
+def : InstRW<[FXU, LSU, Lat5, EndGroup], (instregex "TS$")>;
+
+// Compare and swap
+def : InstRW<[FXU, LSU, FXU, Lat6, GroupAlone], (instregex "CS(G|Y)?$")>;
+
+// Compare double and swap
+def : InstRW<[FXU, FXU, FXU, FXU, FXU, LSU, Lat10, GroupAlone],
+ (instregex "CDS(Y)?$")>;
+def : InstRW<[FXU, FXU, FXU, FXU, FXU, FXU, LSU, LSU, Lat12, GroupAlone],
+ (instregex "CDSG$")>;
+
+// Compare and swap and store
+def : InstRW<[FXU, Lat30, GroupAlone], (instregex "CSST$")>;
+
+// Perform locked operation
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "PLO$")>;
+
+// Load/store pair from/to quadword
+def : InstRW<[LSU, LSU, Lat5, GroupAlone], (instregex "LPQ$")>;
+def : InstRW<[FXU, FXU, LSU, LSU, Lat6, GroupAlone], (instregex "STPQ$")>;
+
+// Load pair disjoint
+def : InstRW<[LSU, LSU, Lat5, GroupAlone], (instregex "LPD(G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Access registers
+//===----------------------------------------------------------------------===//
+
+// Extract/set/copy access register
+def : InstRW<[LSU], (instregex "(EAR|SAR|CPYA)$")>;
+
+// Load address extended
+def : InstRW<[LSU, FXU, Lat5, GroupAlone], (instregex "LAE(Y)?$")>;
+
+// Load/store access multiple (not modeled precisely)
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "(L|ST)AM(Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Program mask and addressing mode
+//===----------------------------------------------------------------------===//
+
+// Insert Program Mask
+def : InstRW<[FXU, Lat3, EndGroup], (instregex "IPM$")>;
+
+// Set Program Mask
+def : InstRW<[LSU, EndGroup], (instregex "SPM$")>;
+
+// Branch and link
+def : InstRW<[FXU, FXU, LSU, Lat8, GroupAlone], (instregex "BAL(R)?$")>;
+
+// Test addressing mode
+def : InstRW<[FXU], (instregex "TAM$")>;
+
+// Set addressing mode
+def : InstRW<[LSU, EndGroup], (instregex "SAM(24|31|64)$")>;
+
+// Branch (and save) and set mode.
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BSM$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "BASSM$")>;
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Instructions.
+//===----------------------------------------------------------------------===//
+
+// Find leftmost one
+def : InstRW<[FXU, Lat7, GroupAlone], (instregex "FLOGR$")>;
+
+// Population count
+def : InstRW<[FXU, Lat3], (instregex "POPCNT$")>;
+
+// Extend
+def : InstRW<[FXU], (instregex "AEXT128_64$")>;
+def : InstRW<[FXU], (instregex "ZEXT128_(32|64)$")>;
+
+// String instructions
+def : InstRW<[FXU, LSU, Lat30], (instregex "SRST$")>;
+
+// Move with key
+def : InstRW<[LSU, Lat8, GroupAlone], (instregex "MVCK$")>;
+
+// Extract CPU Time
+def : InstRW<[FXU, Lat5, LSU], (instregex "ECTG$")>;
+
+// Execute
+def : InstRW<[LSU, GroupAlone], (instregex "EX(RL)?$")>;
+
+// Program return
+def : InstRW<[FXU, Lat30], (instregex "PR$")>;
+
+// Inline assembly
+def : InstRW<[FXU, LSU, Lat15], (instregex "STCK$")>;
+def : InstRW<[FXU, LSU, Lat12], (instregex "STCKF$")>;
+def : InstRW<[LSU, FXU, Lat5], (instregex "STCKE$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STFLE$")>;
+def : InstRW<[FXU, Lat30], (instregex "SVC$")>;
+
+// Store real address
+def : InstRW<[FXU, LSU, Lat5], (instregex "STRAG$")>;
+
+//===----------------------------------------------------------------------===//
+// .insn directive instructions
+//===----------------------------------------------------------------------===//
+
+// An "empty" sched-class will be assigned instead of the "invalid sched-class".
+// getNumDecoderSlots() will then return 1 instead of 0.
+def : InstRW<[], (instregex "Insn.*")>;
+
+
+// ----------------------------- Floating point ----------------------------- //
+
+//===----------------------------------------------------------------------===//
+// FP: Select instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "SelectF(32|64|128)$")>;
+def : InstRW<[FXU], (instregex "CondStoreF32(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStoreF64(Inv)?$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Move instructions
+//===----------------------------------------------------------------------===//
+
+// Load zero
+def : InstRW<[FXU], (instregex "LZ(DR|ER)$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "LZXR$")>;
+
+// Load
+def : InstRW<[FXU], (instregex "LER$")>;
+def : InstRW<[FXU], (instregex "LD(R|R32|GR)$")>;
+def : InstRW<[FXU, Lat3], (instregex "LGDR$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "LXR$")>;
+
+// Load and Test
+def : InstRW<[FPU], (instregex "LT(D|E)BR$")>;
+def : InstRW<[FPU], (instregex "LTEBRCompare(_VecPseudo)?$")>;
+def : InstRW<[FPU], (instregex "LTDBRCompare(_VecPseudo)?$")>;
+def : InstRW<[FPU2, FPU2, Lat9, GroupAlone], (instregex "LTXBR$")>;
+def : InstRW<[FPU2, FPU2, Lat9, GroupAlone],
+ (instregex "LTXBRCompare(_VecPseudo)?$")>;
+
+// Copy sign
+def : InstRW<[FXU, FXU, Lat5, GroupAlone], (instregex "CPSDRd(d|s)$")>;
+def : InstRW<[FXU, FXU, Lat5, GroupAlone], (instregex "CPSDRs(d|s)$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Load instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU], (instregex "LE(Y)?$")>;
+def : InstRW<[LSU], (instregex "LD(Y|E32)?$")>;
+def : InstRW<[LSU], (instregex "LX$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Store instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat7], (instregex "STD(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat7], (instregex "STE(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STX$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Conversion instructions
+//===----------------------------------------------------------------------===//
+
+// Load rounded
+def : InstRW<[FPU], (instregex "LEDBR(A)?$")>;
+def : InstRW<[FPU, FPU, Lat20], (instregex "LEXBR(A)?$")>;
+def : InstRW<[FPU, FPU, Lat20], (instregex "LDXBR(A)?$")>;
+
+// Load lengthened
+def : InstRW<[FPU, LSU, Lat12], (instregex "LDEB$")>;
+def : InstRW<[FPU], (instregex "LDEBR$")>;
+def : InstRW<[FPU2, FPU2, LSU, Lat15, GroupAlone], (instregex "LX(D|E)B$")>;
+def : InstRW<[FPU2, FPU2, Lat10, GroupAlone], (instregex "LX(D|E)BR$")>;
+
+// Convert from fixed / logical
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CE(F|G)BR(A)?$")>;
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CD(F|G)BR(A)?$")>;
+def : InstRW<[FXU, FPU2, FPU2, Lat11, GroupAlone], (instregex "CX(F|G)BR(A)?$")>;
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CEL(F|G)BR$")>;
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CDL(F|G)BR$")>;
+def : InstRW<[FXU, FPU2, FPU2, Lat11, GroupAlone], (instregex "CXL(F|G)BR$")>;
+
+// Convert to fixed / logical
+def : InstRW<[FXU, FPU, Lat12, GroupAlone], (instregex "CF(E|D)BR(A)?$")>;
+def : InstRW<[FXU, FPU, Lat12, GroupAlone], (instregex "CG(E|D)BR(A)?$")>;
+def : InstRW<[FXU, FPU, FPU, Lat20, GroupAlone], (instregex "C(F|G)XBR(A)?$")>;
+def : InstRW<[FXU, FPU, Lat11, GroupAlone], (instregex "CLF(E|D)BR$")>;
+def : InstRW<[FXU, FPU, Lat11, GroupAlone], (instregex "CLG(E|D)BR$")>;
+def : InstRW<[FXU, FPU, FPU, Lat20, GroupAlone], (instregex "CL(F|G)XBR$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Unary arithmetic
+//===----------------------------------------------------------------------===//
+
+// Load Complement / Negative / Positive
+def : InstRW<[FPU], (instregex "L(C|N|P)DBR$")>;
+def : InstRW<[FPU], (instregex "L(C|N|P)EBR$")>;
+def : InstRW<[FXU], (instregex "LCDFR(_32)?$")>;
+def : InstRW<[FXU], (instregex "LNDFR(_32)?$")>;
+def : InstRW<[FXU], (instregex "LPDFR(_32)?$")>;
+def : InstRW<[FPU2, FPU2, Lat9, GroupAlone], (instregex "L(C|N|P)XBR$")>;
+
+// Square root
+def : InstRW<[FPU, LSU, Lat30], (instregex "SQ(E|D)B$")>;
+def : InstRW<[FPU, Lat30], (instregex "SQ(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat30, GroupAlone], (instregex "SQXBR$")>;
+
+// Load FP integer
+def : InstRW<[FPU], (instregex "FIEBR(A)?$")>;
+def : InstRW<[FPU], (instregex "FIDBR(A)?$")>;
+def : InstRW<[FPU2, FPU2, Lat15, GroupAlone], (instregex "FIXBR(A)?$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Binary arithmetic
+//===----------------------------------------------------------------------===//
+
+// Addition
+def : InstRW<[FPU, LSU, Lat12], (instregex "A(E|D)B$")>;
+def : InstRW<[FPU], (instregex "A(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat20, GroupAlone], (instregex "AXBR$")>;
+
+// Subtraction
+def : InstRW<[FPU, LSU, Lat12], (instregex "S(E|D)B$")>;
+def : InstRW<[FPU], (instregex "S(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat20, GroupAlone], (instregex "SXBR$")>;
+
+// Multiply
+def : InstRW<[FPU, LSU, Lat12], (instregex "M(D|DE|EE)B$")>;
+def : InstRW<[FPU], (instregex "M(D|DE|EE)BR$")>;
+def : InstRW<[FPU2, FPU2, LSU, Lat15, GroupAlone], (instregex "MXDB$")>;
+def : InstRW<[FPU2, FPU2, Lat10, GroupAlone], (instregex "MXDBR$")>;
+def : InstRW<[FPU2, FPU2, Lat30, GroupAlone], (instregex "MXBR$")>;
+
+// Multiply and add / subtract
+def : InstRW<[FPU, LSU, Lat12, GroupAlone], (instregex "M(A|S)EB$")>;
+def : InstRW<[FPU, GroupAlone], (instregex "M(A|S)EBR$")>;
+def : InstRW<[FPU, LSU, Lat12, GroupAlone], (instregex "M(A|S)DB$")>;
+def : InstRW<[FPU, GroupAlone], (instregex "M(A|S)DBR$")>;
+
+// Division
+def : InstRW<[FPU, LSU, Lat30], (instregex "D(E|D)B$")>;
+def : InstRW<[FPU, Lat30], (instregex "D(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat30, GroupAlone], (instregex "DXBR$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Comparisons
+//===----------------------------------------------------------------------===//
+
+// Compare
+def : InstRW<[FPU, LSU, Lat12], (instregex "C(E|D)B$")>;
+def : InstRW<[FPU], (instregex "C(E|D)BR$")>;
+def : InstRW<[FPU, FPU, Lat30], (instregex "CXBR$")>;
+
+// Test Data Class
+def : InstRW<[FPU, LSU, Lat15], (instregex "TC(E|D)B$")>;
+def : InstRW<[FPU2, FPU2, LSU, Lat15, GroupAlone], (instregex "TCXB$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Floating-point control register instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat4, GroupAlone], (instregex "EFPC$")>;
+def : InstRW<[LSU, Lat3, GroupAlone], (instregex "SFPC$")>;
+def : InstRW<[LSU, LSU, Lat6, GroupAlone], (instregex "LFPC$")>;
+def : InstRW<[LSU, Lat3, GroupAlone], (instregex "STFPC$")>;
+def : InstRW<[FXU, Lat30, GroupAlone], (instregex "SFASR$")>;
+def : InstRW<[FXU, LSU, Lat30, GroupAlone], (instregex "LFAS$")>;
+def : InstRW<[FXU, Lat2, GroupAlone], (instregex "SRNM(B|T)?$")>;
+
+}
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td b/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td
new file mode 100644
index 0000000..8ab6c82
--- /dev/null
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td
@@ -0,0 +1,807 @@
+//=- SystemZScheduleZEC12.td - SystemZ Scheduling Definitions --*- tblgen -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the machine model for ZEC12 to support instruction
+// scheduling and other instruction cost heuristics.
+//
+//===----------------------------------------------------------------------===//
+
+def ZEC12Model : SchedMachineModel {
+
+ let UnsupportedFeatures = Arch10UnsupportedFeatures.List;
+
+ let IssueWidth = 5;
+ let MicroOpBufferSize = 40; // Issue queues
+ let LoadLatency = 1; // Optimistic load latency.
+
+ let PostRAScheduler = 1;
+
+ // Extra cycles for a mispredicted branch.
+ let MispredictPenalty = 16;
+}
+
+let SchedModel = ZEC12Model in {
+
+// These definitions could be put in a subtarget common include file,
+// but it seems the include system in Tablegen currently rejects
+// multiple includes of same file.
+def : WriteRes<GroupAlone, []> {
+ let NumMicroOps = 0;
+ let BeginGroup = 1;
+ let EndGroup = 1;
+}
+def : WriteRes<EndGroup, []> {
+ let NumMicroOps = 0;
+ let EndGroup = 1;
+}
+def : WriteRes<Lat2, []> { let Latency = 2; let NumMicroOps = 0;}
+def : WriteRes<Lat3, []> { let Latency = 3; let NumMicroOps = 0;}
+def : WriteRes<Lat4, []> { let Latency = 4; let NumMicroOps = 0;}
+def : WriteRes<Lat5, []> { let Latency = 5; let NumMicroOps = 0;}
+def : WriteRes<Lat6, []> { let Latency = 6; let NumMicroOps = 0;}
+def : WriteRes<Lat7, []> { let Latency = 7; let NumMicroOps = 0;}
+def : WriteRes<Lat8, []> { let Latency = 8; let NumMicroOps = 0;}
+def : WriteRes<Lat9, []> { let Latency = 9; let NumMicroOps = 0;}
+def : WriteRes<Lat10, []> { let Latency = 10; let NumMicroOps = 0;}
+def : WriteRes<Lat11, []> { let Latency = 11; let NumMicroOps = 0;}
+def : WriteRes<Lat12, []> { let Latency = 12; let NumMicroOps = 0;}
+def : WriteRes<Lat15, []> { let Latency = 15; let NumMicroOps = 0;}
+def : WriteRes<Lat20, []> { let Latency = 20; let NumMicroOps = 0;}
+def : WriteRes<Lat30, []> { let Latency = 30; let NumMicroOps = 0;}
+
+// Execution units.
+def ZEC12_FXUnit : ProcResource<2>;
+def ZEC12_LSUnit : ProcResource<2>;
+def ZEC12_FPUnit : ProcResource<1>;
+def ZEC12_VBUnit : ProcResource<1>;
+
+// Subtarget specific definitions of scheduling resources.
+def : WriteRes<FXU, [ZEC12_FXUnit]> { let Latency = 1; }
+def : WriteRes<LSU, [ZEC12_LSUnit]> { let Latency = 4; }
+def : WriteRes<LSU_lat1, [ZEC12_LSUnit]> { let Latency = 1; }
+def : WriteRes<FPU, [ZEC12_FPUnit]> { let Latency = 8; }
+def : WriteRes<FPU2, [ZEC12_FPUnit, ZEC12_FPUnit]> { let Latency = 9; }
+def : WriteRes<VBU, [ZEC12_VBUnit]>; // Virtual Branching Unit
+
+// -------------------------- INSTRUCTIONS ---------------------------------- //
+
+// InstRW constructs have been used in order to preserve the
+// readability of the InstrInfo files.
+
+// For each instruction, as matched by a regexp, provide a list of
+// resources that it needs. These will be combined into a SchedClass.
+
+//===----------------------------------------------------------------------===//
+// Stack allocation
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "ADJDYNALLOC$")>; // Pseudo -> LA / LAY
+
+//===----------------------------------------------------------------------===//
+// Branch instructions
+//===----------------------------------------------------------------------===//
+
+// Branch
+def : InstRW<[VBU], (instregex "(Call)?BRC(L)?(Asm.*)?$")>;
+def : InstRW<[VBU], (instregex "(Call)?J(G)?(Asm.*)?$")>;
+def : InstRW<[LSU, Lat4], (instregex "(Call)?BC(R)?(Asm.*)?$")>;
+def : InstRW<[LSU, Lat4], (instregex "(Call)?B(R)?(Asm.*)?$")>;
+def : InstRW<[FXU, EndGroup], (instregex "BRCT(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BRCTH$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BCT(G)?(R)?$")>;
+def : InstRW<[FXU, FXU, FXU, LSU, Lat7, GroupAlone],
+ (instregex "B(R)?X(H|L).*$")>;
+
+// Compare and branch
+def : InstRW<[FXU], (instregex "C(L)?(G)?(I|R)J(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat5, GroupAlone],
+ (instregex "C(L)?(G)?(I|R)B(Call|Return|Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Trap instructions
+//===----------------------------------------------------------------------===//
+
+// Trap
+def : InstRW<[VBU], (instregex "(Cond)?Trap$")>;
+
+// Compare and trap
+def : InstRW<[FXU], (instregex "C(G)?(I|R)T(Asm.*)?$")>;
+def : InstRW<[FXU], (instregex "CL(G)?RT(Asm.*)?$")>;
+def : InstRW<[FXU], (instregex "CL(F|G)IT(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CL(G)?T(Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Call and return instructions
+//===----------------------------------------------------------------------===//
+
+// Call
+def : InstRW<[VBU, FXU, FXU, Lat3, GroupAlone], (instregex "(Call)?BRAS$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "(Call)?BRASL$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "(Call)?BAS(R)?$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "TLS_(G|L)DCALL$")>;
+
+// Return
+def : InstRW<[LSU_lat1, EndGroup], (instregex "Return$")>;
+def : InstRW<[LSU_lat1], (instregex "CondReturn$")>;
+
+//===----------------------------------------------------------------------===//
+// Select instructions
+//===----------------------------------------------------------------------===//
+
+// Select pseudo
+def : InstRW<[FXU], (instregex "Select(32|64|32Mux)$")>;
+
+// CondStore pseudos
+def : InstRW<[FXU], (instregex "CondStore16(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore16Mux(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore32(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore64(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore8(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStore8Mux(Inv)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Move instructions
+//===----------------------------------------------------------------------===//
+
+// Moves
+def : InstRW<[FXU, LSU, Lat5], (instregex "MV(G|H)?HI$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "MVI(Y)?$")>;
+
+// Move character
+def : InstRW<[LSU, LSU, LSU, FXU, Lat8, GroupAlone], (instregex "MVC$")>;
+
+// Pseudo -> reg move
+def : InstRW<[FXU], (instregex "COPY(_TO_REGCLASS)?$")>;
+def : InstRW<[FXU], (instregex "EXTRACT_SUBREG$")>;
+def : InstRW<[FXU], (instregex "INSERT_SUBREG$")>;
+def : InstRW<[FXU], (instregex "REG_SEQUENCE$")>;
+def : InstRW<[FXU], (instregex "SUBREG_TO_REG$")>;
+
+// Loads
+def : InstRW<[LSU], (instregex "L(Y|FH|RL|Mux)?$")>;
+def : InstRW<[LSU], (instregex "LG(RL)?$")>;
+def : InstRW<[LSU], (instregex "L128$")>;
+
+def : InstRW<[FXU], (instregex "LLIH(F|H|L)$")>;
+def : InstRW<[FXU], (instregex "LLIL(F|H|L)$")>;
+
+def : InstRW<[FXU], (instregex "LG(F|H)I$")>;
+def : InstRW<[FXU], (instregex "LHI(Mux)?$")>;
+def : InstRW<[FXU], (instregex "LR(Mux)?$")>;
+
+// Load and trap
+def : InstRW<[FXU, LSU, Lat5], (instregex "L(FH|G)?AT$")>;
+
+// Load and test
+def : InstRW<[FXU, LSU, Lat5], (instregex "LT(G)?$")>;
+def : InstRW<[FXU], (instregex "LT(G)?R$")>;
+
+// Stores
+def : InstRW<[FXU, LSU, Lat5], (instregex "STG(RL)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ST128$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ST(Y|FH|RL|Mux)?$")>;
+
+// String moves.
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "MVST$")>;
+
+//===----------------------------------------------------------------------===//
+// Conditional move instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, Lat2], (instregex "LOC(G)?R(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat6], (instregex "LOC(G)?(Asm.*)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STOC(G)?(Asm.*)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Sign extensions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "L(B|H|G)R$")>;
+def : InstRW<[FXU], (instregex "LG(B|H|F)R$")>;
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "LTGF$")>;
+def : InstRW<[FXU], (instregex "LTGFR$")>;
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "LB(H|Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LH(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LH(H|Mux|RL)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LG(B|H|F)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LG(H|F)RL$")>;
+
+//===----------------------------------------------------------------------===//
+// Zero extensions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "LLCR(Mux)?$")>;
+def : InstRW<[FXU], (instregex "LLHR(Mux)?$")>;
+def : InstRW<[FXU], (instregex "LLG(C|H|F|T)R$")>;
+def : InstRW<[LSU], (instregex "LLC(Mux)?$")>;
+def : InstRW<[LSU], (instregex "LLH(Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LL(C|H)H$")>;
+def : InstRW<[LSU], (instregex "LLHRL$")>;
+def : InstRW<[LSU], (instregex "LLG(C|H|F|T|HRL|FRL)$")>;
+
+// Load and trap
+def : InstRW<[FXU, LSU, Lat5], (instregex "LLG(F|T)?AT$")>;
+
+//===----------------------------------------------------------------------===//
+// Truncations
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "STC(H|Y|Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STH(H|Y|RL|Mux)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Multi-register moves
+//===----------------------------------------------------------------------===//
+
+// Load multiple (estimated average of 5 ops)
+def : InstRW<[LSU, LSU, LSU, LSU, LSU, Lat10, GroupAlone],
+ (instregex "LM(H|Y|G)?$")>;
+
+// Store multiple (estimated average of 3 ops)
+def : InstRW<[LSU, LSU, FXU, FXU, FXU, Lat10, GroupAlone],
+ (instregex "STM(H|Y|G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Byte swaps
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "LRV(G)?R$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LRV(G|H)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STRV(G|H)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Load address instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "LA(Y|RL)?$")>;
+
+// Load the Global Offset Table address
+def : InstRW<[FXU], (instregex "GOT$")>;
+
+//===----------------------------------------------------------------------===//
+// Absolute and Negation
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, Lat2], (instregex "LP(G)?R$")>;
+def : InstRW<[FXU, FXU, Lat3, GroupAlone], (instregex "L(N|P)GFR$")>;
+def : InstRW<[FXU, Lat2], (instregex "LN(R|GR)$")>;
+def : InstRW<[FXU], (instregex "LC(R|GR)$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "LCGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// Insertion
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "IC(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "IC32(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ICM(H|Y)?$")>;
+def : InstRW<[FXU], (instregex "II(F|H|L)Mux$")>;
+def : InstRW<[FXU], (instregex "IIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "IIHH(64)?$")>;
+def : InstRW<[FXU], (instregex "IIHL(64)?$")>;
+def : InstRW<[FXU], (instregex "IILF(64)?$")>;
+def : InstRW<[FXU], (instregex "IILH(64)?$")>;
+def : InstRW<[FXU], (instregex "IILL(64)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Addition
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "A(Y|SI)?$")>;
+def : InstRW<[FXU, LSU, Lat6], (instregex "AH(Y)?$")>;
+def : InstRW<[FXU], (instregex "AIH$")>;
+def : InstRW<[FXU], (instregex "AFI(Mux)?$")>;
+def : InstRW<[FXU], (instregex "AGFI$")>;
+def : InstRW<[FXU], (instregex "AGHI(K)?$")>;
+def : InstRW<[FXU], (instregex "AGR(K)?$")>;
+def : InstRW<[FXU], (instregex "AHI(K)?$")>;
+def : InstRW<[FXU], (instregex "AHIMux(K)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "AL(Y)?$")>;
+def : InstRW<[FXU], (instregex "AL(FI|HSIK)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "ALG(F)?$")>;
+def : InstRW<[FXU], (instregex "ALGHSIK$")>;
+def : InstRW<[FXU], (instregex "ALGF(I|R)$")>;
+def : InstRW<[FXU], (instregex "ALGR(K)?$")>;
+def : InstRW<[FXU], (instregex "ALR(K)?$")>;
+def : InstRW<[FXU], (instregex "AR(K)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "AG(SI)?$")>;
+
+// Logical addition with carry
+def : InstRW<[FXU, LSU, Lat7, GroupAlone], (instregex "ALC(G)?$")>;
+def : InstRW<[FXU, Lat3, GroupAlone], (instregex "ALC(G)?R$")>;
+
+// Add with sign extension (32 -> 64)
+def : InstRW<[FXU, LSU, Lat6], (instregex "AGF$")>;
+def : InstRW<[FXU, Lat2], (instregex "AGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// Subtraction
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "S(G|Y)?$")>;
+def : InstRW<[FXU, LSU, Lat6], (instregex "SH(Y)?$")>;
+def : InstRW<[FXU], (instregex "SGR(K)?$")>;
+def : InstRW<[FXU], (instregex "SLFI$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "SL(G|GF|Y)?$")>;
+def : InstRW<[FXU], (instregex "SLGF(I|R)$")>;
+def : InstRW<[FXU], (instregex "SLGR(K)?$")>;
+def : InstRW<[FXU], (instregex "SLR(K)?$")>;
+def : InstRW<[FXU], (instregex "SR(K)?$")>;
+
+// Subtraction with borrow
+def : InstRW<[FXU, LSU, Lat7, GroupAlone], (instregex "SLB(G)?$")>;
+def : InstRW<[FXU, Lat3, GroupAlone], (instregex "SLB(G)?R$")>;
+
+// Subtraction with sign extension (32 -> 64)
+def : InstRW<[FXU, LSU, Lat6], (instregex "SGF$")>;
+def : InstRW<[FXU, Lat2], (instregex "SGFR$")>;
+
+//===----------------------------------------------------------------------===//
+// AND
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "N(G|Y)?$")>;
+def : InstRW<[FXU], (instregex "NGR(K)?$")>;
+def : InstRW<[FXU], (instregex "NI(FMux|HMux|LMux)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "NI(Y)?$")>;
+def : InstRW<[FXU], (instregex "NIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "NIHH(64)?$")>;
+def : InstRW<[FXU], (instregex "NIHL(64)?$")>;
+def : InstRW<[FXU], (instregex "NILF(64)?$")>;
+def : InstRW<[FXU], (instregex "NILH(64)?$")>;
+def : InstRW<[FXU], (instregex "NILL(64)?$")>;
+def : InstRW<[FXU], (instregex "NR(K)?$")>;
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "NC$")>;
+
+//===----------------------------------------------------------------------===//
+// OR
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "O(G|Y)?$")>;
+def : InstRW<[FXU], (instregex "OGR(K)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "OI(Y)?$")>;
+def : InstRW<[FXU], (instregex "OI(FMux|HMux|LMux)$")>;
+def : InstRW<[FXU], (instregex "OIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "OIHH(64)?$")>;
+def : InstRW<[FXU], (instregex "OIHL(64)?$")>;
+def : InstRW<[FXU], (instregex "OILF(64)?$")>;
+def : InstRW<[FXU], (instregex "OILH(64)?$")>;
+def : InstRW<[FXU], (instregex "OILL(64)?$")>;
+def : InstRW<[FXU], (instregex "OR(K)?$")>;
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "OC$")>;
+
+//===----------------------------------------------------------------------===//
+// XOR
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "X(G|Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "XI(Y)?$")>;
+def : InstRW<[FXU], (instregex "XIFMux$")>;
+def : InstRW<[FXU], (instregex "XGR(K)?$")>;
+def : InstRW<[FXU], (instregex "XIHF(64)?$")>;
+def : InstRW<[FXU], (instregex "XILF(64)?$")>;
+def : InstRW<[FXU], (instregex "XR(K)?$")>;
+def : InstRW<[LSU, LSU, FXU, Lat9, GroupAlone], (instregex "XC$")>;
+
+//===----------------------------------------------------------------------===//
+// Multiplication
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat10], (instregex "MS(GF|Y)?$")>;
+def : InstRW<[FXU, Lat6], (instregex "MS(R|FI)$")>;
+def : InstRW<[FXU, LSU, Lat12], (instregex "MSG$")>;
+def : InstRW<[FXU, Lat8], (instregex "MSGR$")>;
+def : InstRW<[FXU, Lat6], (instregex "MSGF(I|R)$")>;
+def : InstRW<[FXU, LSU, Lat15, GroupAlone], (instregex "MLG$")>;
+def : InstRW<[FXU, Lat9, GroupAlone], (instregex "MLGR$")>;
+def : InstRW<[FXU, Lat5], (instregex "MGHI$")>;
+def : InstRW<[FXU, Lat5], (instregex "MHI$")>;
+def : InstRW<[FXU, LSU, Lat9], (instregex "MH(Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Division and remainder
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FPU2, FPU2, FXU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DSG(F)?R$")>;
+def : InstRW<[FPU2, FPU2, LSU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DSG(F)?$")>;
+def : InstRW<[FPU2, FPU2, FXU, FXU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DL(G)?R$")>;
+def : InstRW<[FPU2, FPU2, LSU, FXU, FXU, FXU, FXU, Lat30, GroupAlone],
+ (instregex "DL(G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Shifts
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "SLL(G|K)?$")>;
+def : InstRW<[FXU], (instregex "SRL(G|K)?$")>;
+def : InstRW<[FXU], (instregex "SRA(G|K)?$")>;
+def : InstRW<[FXU], (instregex "SLA(K)?$")>;
+
+// Rotate
+def : InstRW<[FXU, LSU, Lat6], (instregex "RLL(G)?$")>;
+
+// Rotate and insert
+def : InstRW<[FXU], (instregex "RISBG(N|32)?$")>;
+def : InstRW<[FXU], (instregex "RISBH(G|H|L)$")>;
+def : InstRW<[FXU], (instregex "RISBL(G|H|L)$")>;
+def : InstRW<[FXU], (instregex "RISBMux$")>;
+
+// Rotate and Select
+def : InstRW<[FXU, FXU, Lat3, GroupAlone], (instregex "R(N|O|X)SBG$")>;
+
+//===----------------------------------------------------------------------===//
+// Comparison
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "C(G|Y|Mux|RL)?$")>;
+def : InstRW<[FXU], (instregex "C(F|H)I(Mux)?$")>;
+def : InstRW<[FXU], (instregex "CG(F|H)I$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CG(HSI|RL)$")>;
+def : InstRW<[FXU], (instregex "C(G)?R$")>;
+def : InstRW<[FXU], (instregex "CIH$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CH(F|SI)$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CL(Y|Mux|FHSI)?$")>;
+def : InstRW<[FXU], (instregex "CLFI(Mux)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLG(HRL|HSI)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLGF(RL)?$")>;
+def : InstRW<[FXU], (instregex "CLGF(I|R)$")>;
+def : InstRW<[FXU], (instregex "CLGR$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLGRL$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLH(F|RL|HSI)$")>;
+def : InstRW<[FXU], (instregex "CLIH$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLI(Y)?$")>;
+def : InstRW<[FXU], (instregex "CLR$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "CLRL$")>;
+
+// Compare halfword
+def : InstRW<[FXU, LSU, Lat6], (instregex "CH(Y|RL)?$")>;
+def : InstRW<[FXU, LSU, Lat6], (instregex "CGH(RL)?$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "CHHSI$")>;
+
+// Compare with sign extension (32 -> 64)
+def : InstRW<[FXU, LSU, Lat6], (instregex "CGF(RL)?$")>;
+def : InstRW<[FXU, Lat2], (instregex "CGFR$")>;
+
+// Compare logical character
+def : InstRW<[FXU, LSU, LSU, Lat9, GroupAlone], (instregex "CLC$")>;
+
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "CLST$")>;
+
+// Test under mask
+def : InstRW<[FXU, LSU, Lat5], (instregex "TM(Y)?$")>;
+def : InstRW<[FXU], (instregex "TM(H|L)Mux$")>;
+def : InstRW<[FXU], (instregex "TMHH(64)?$")>;
+def : InstRW<[FXU], (instregex "TMHL(64)?$")>;
+def : InstRW<[FXU], (instregex "TMLH(64)?$")>;
+def : InstRW<[FXU], (instregex "TMLL(64)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Prefetch and execution hint
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU], (instregex "PFD(RL)?$")>;
+def : InstRW<[LSU], (instregex "BP(R)?P$")>;
+def : InstRW<[FXU], (instregex "NIAI$")>;
+
+//===----------------------------------------------------------------------===//
+// Atomic operations
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU, EndGroup], (instregex "Serialize$")>;
+
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAA(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAAL(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAN(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAO(G)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "LAX(G)?$")>;
+
+// Test and set
+def : InstRW<[FXU, LSU, Lat5, EndGroup], (instregex "TS$")>;
+
+// Compare and swap
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "CS(G|Y)?$")>;
+
+// Compare double and swap
+def : InstRW<[FXU, FXU, FXU, FXU, FXU, LSU, Lat10, GroupAlone],
+ (instregex "CDS(Y)?$")>;
+def : InstRW<[FXU, FXU, FXU, FXU, FXU, FXU, LSU, LSU, Lat12, GroupAlone],
+ (instregex "CDSG$")>;
+
+// Compare and swap and store
+def : InstRW<[FXU, Lat30, GroupAlone], (instregex "CSST$")>;
+
+// Perform locked operation
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "PLO$")>;
+
+// Load/store pair from/to quadword
+def : InstRW<[LSU, LSU, Lat5, GroupAlone], (instregex "LPQ$")>;
+def : InstRW<[FXU, FXU, LSU, LSU, Lat6, GroupAlone], (instregex "STPQ$")>;
+
+// Load pair disjoint
+def : InstRW<[LSU, LSU, Lat5, GroupAlone], (instregex "LPD(G)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Access registers
+//===----------------------------------------------------------------------===//
+
+// Extract/set/copy access register
+def : InstRW<[LSU], (instregex "(EAR|SAR|CPYA)$")>;
+
+// Load address extended
+def : InstRW<[LSU, FXU, Lat5, GroupAlone], (instregex "LAE(Y)?$")>;
+
+// Load/store access multiple (not modeled precisely)
+def : InstRW<[LSU, Lat30, GroupAlone], (instregex "(L|ST)AM(Y)?$")>;
+
+//===----------------------------------------------------------------------===//
+// Program mask and addressing mode
+//===----------------------------------------------------------------------===//
+
+// Insert Program Mask
+def : InstRW<[FXU, Lat3, EndGroup], (instregex "IPM$")>;
+
+// Set Program Mask
+def : InstRW<[LSU, EndGroup], (instregex "SPM$")>;
+
+// Branch and link
+def : InstRW<[FXU, FXU, LSU, Lat8, GroupAlone], (instregex "BAL(R)?$")>;
+
+// Test addressing mode
+def : InstRW<[FXU], (instregex "TAM$")>;
+
+// Set addressing mode
+def : InstRW<[LSU, EndGroup], (instregex "SAM(24|31|64)$")>;
+
+// Branch (and save) and set mode.
+def : InstRW<[FXU, LSU, Lat5, GroupAlone], (instregex "BSM$")>;
+def : InstRW<[FXU, FXU, LSU, Lat6, GroupAlone], (instregex "BASSM$")>;
+
+//===----------------------------------------------------------------------===//
+// Transactional execution
+//===----------------------------------------------------------------------===//
+
+// Transaction begin
+def : InstRW<[LSU, LSU, FXU, FXU, FXU, FXU, FXU, Lat15, GroupAlone],
+ (instregex "TBEGIN(C|_nofloat)?$")>;
+
+// Transaction end
+def : InstRW<[LSU, GroupAlone], (instregex "TEND$")>;
+
+// Transaction abort
+def : InstRW<[LSU, GroupAlone], (instregex "TABORT$")>;
+
+// Extract Transaction Nesting Depth
+def : InstRW<[FXU], (instregex "ETND$")>;
+
+// Nontransactional store
+def : InstRW<[FXU, LSU, Lat5], (instregex "NTSTG$")>;
+
+//===----------------------------------------------------------------------===//
+// Processor assist
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "PPA$")>;
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Instructions.
+//===----------------------------------------------------------------------===//
+
+// Find leftmost one
+def : InstRW<[FXU, Lat7, GroupAlone], (instregex "FLOGR$")>;
+
+// Population count
+def : InstRW<[FXU, Lat3], (instregex "POPCNT$")>;
+
+// Extend
+def : InstRW<[FXU], (instregex "AEXT128_64$")>;
+def : InstRW<[FXU], (instregex "ZEXT128_(32|64)$")>;
+
+// String instructions
+def : InstRW<[FXU, LSU, Lat30], (instregex "SRST$")>;
+
+// Move with key
+def : InstRW<[LSU, Lat8, GroupAlone], (instregex "MVCK$")>;
+
+// Extract CPU Time
+def : InstRW<[FXU, Lat5, LSU], (instregex "ECTG$")>;
+
+// Execute
+def : InstRW<[LSU, GroupAlone], (instregex "EX(RL)?$")>;
+
+// Program return
+def : InstRW<[FXU, Lat30], (instregex "PR$")>;
+
+// Inline assembly
+def : InstRW<[FXU, LSU, LSU, Lat9, GroupAlone], (instregex "STCK(F)?$")>;
+def : InstRW<[LSU, LSU, LSU, LSU, FXU, FXU, Lat20, GroupAlone],
+ (instregex "STCKE$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STFLE$")>;
+def : InstRW<[FXU, Lat30], (instregex "SVC$")>;
+
+// Store real address
+def : InstRW<[FXU, LSU, Lat5], (instregex "STRAG$")>;
+
+//===----------------------------------------------------------------------===//
+// .insn directive instructions
+//===----------------------------------------------------------------------===//
+
+// An "empty" sched-class will be assigned instead of the "invalid sched-class".
+// getNumDecoderSlots() will then return 1 instead of 0.
+def : InstRW<[], (instregex "Insn.*")>;
+
+
+// ----------------------------- Floating point ----------------------------- //
+
+//===----------------------------------------------------------------------===//
+// FP: Select instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU], (instregex "SelectF(32|64|128)$")>;
+def : InstRW<[FXU], (instregex "CondStoreF32(Inv)?$")>;
+def : InstRW<[FXU], (instregex "CondStoreF64(Inv)?$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Move instructions
+//===----------------------------------------------------------------------===//
+
+// Load zero
+def : InstRW<[FXU], (instregex "LZ(DR|ER)$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "LZXR$")>;
+
+// Load
+def : InstRW<[FXU], (instregex "LER$")>;
+def : InstRW<[FXU], (instregex "LD(R|R32|GR)$")>;
+def : InstRW<[FXU, Lat3], (instregex "LGDR$")>;
+def : InstRW<[FXU, FXU, Lat2, GroupAlone], (instregex "LXR$")>;
+
+// Load and Test
+def : InstRW<[FPU], (instregex "LT(D|E)BR$")>;
+def : InstRW<[FPU], (instregex "LTEBRCompare(_VecPseudo)?$")>;
+def : InstRW<[FPU], (instregex "LTDBRCompare(_VecPseudo)?$")>;
+def : InstRW<[FPU2, FPU2, Lat9, GroupAlone], (instregex "LTXBR$")>;
+def : InstRW<[FPU2, FPU2, Lat9, GroupAlone],
+ (instregex "LTXBRCompare(_VecPseudo)?$")>;
+
+// Copy sign
+def : InstRW<[FXU, FXU, Lat5, GroupAlone], (instregex "CPSDRd(d|s)$")>;
+def : InstRW<[FXU, FXU, Lat5, GroupAlone], (instregex "CPSDRs(d|s)$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Load instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[LSU], (instregex "LE(Y)?$")>;
+def : InstRW<[LSU], (instregex "LD(Y|E32)?$")>;
+def : InstRW<[LSU], (instregex "LX$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Store instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat7], (instregex "STD(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat7], (instregex "STE(Y)?$")>;
+def : InstRW<[FXU, LSU, Lat5], (instregex "STX$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Conversion instructions
+//===----------------------------------------------------------------------===//
+
+// Load rounded
+def : InstRW<[FPU], (instregex "LEDBR(A)?$")>;
+def : InstRW<[FPU, FPU, Lat20], (instregex "LEXBR(A)?$")>;
+def : InstRW<[FPU, FPU, Lat20], (instregex "LDXBR(A)?$")>;
+
+// Load lengthened
+def : InstRW<[FPU, LSU, Lat12], (instregex "LDEB$")>;
+def : InstRW<[FPU], (instregex "LDEBR$")>;
+def : InstRW<[FPU2, FPU2, LSU, Lat15, GroupAlone], (instregex "LX(D|E)B$")>;
+def : InstRW<[FPU2, FPU2, Lat10, GroupAlone], (instregex "LX(D|E)BR$")>;
+
+// Convert from fixed / logical
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CE(F|G)BR(A?)$")>;
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CD(F|G)BR(A?)$")>;
+def : InstRW<[FXU, FPU2, FPU2, Lat11, GroupAlone], (instregex "CX(F|G)BR(A?)$")>;
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CEL(F|G)BR$")>;
+def : InstRW<[FXU, FPU, Lat9, GroupAlone], (instregex "CDL(F|G)BR$")>;
+def : InstRW<[FXU, FPU2, FPU2, Lat11, GroupAlone], (instregex "CXL(F|G)BR$")>;
+
+// Convert to fixed / logical
+def : InstRW<[FXU, FPU, Lat12, GroupAlone], (instregex "CF(E|D)BR(A?)$")>;
+def : InstRW<[FXU, FPU, Lat12, GroupAlone], (instregex "CG(E|D)BR(A?)$")>;
+def : InstRW<[FXU, FPU, FPU, Lat20, GroupAlone], (instregex "C(F|G)XBR(A?)$")>;
+def : InstRW<[FXU, FPU, Lat11, GroupAlone], (instregex "CLF(E|D)BR$")>;
+def : InstRW<[FXU, FPU, Lat11, GroupAlone], (instregex "CLG(E|D)BR$")>;
+def : InstRW<[FXU, FPU, FPU, Lat20, GroupAlone], (instregex "CL(F|G)XBR$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Unary arithmetic
+//===----------------------------------------------------------------------===//
+
+// Load Complement / Negative / Positive
+def : InstRW<[FPU], (instregex "L(C|N|P)DBR$")>;
+def : InstRW<[FPU], (instregex "L(C|N|P)EBR$")>;
+def : InstRW<[FXU], (instregex "LCDFR(_32)?$")>;
+def : InstRW<[FXU], (instregex "LNDFR(_32)?$")>;
+def : InstRW<[FXU], (instregex "LPDFR(_32)?$")>;
+def : InstRW<[FPU2, FPU2, Lat9, GroupAlone], (instregex "L(C|N|P)XBR$")>;
+
+// Square root
+def : InstRW<[FPU, LSU, Lat30], (instregex "SQ(E|D)B$")>;
+def : InstRW<[FPU, Lat30], (instregex "SQ(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat30, GroupAlone], (instregex "SQXBR$")>;
+
+// Load FP integer
+def : InstRW<[FPU], (instregex "FIEBR(A)?$")>;
+def : InstRW<[FPU], (instregex "FIDBR(A)?$")>;
+def : InstRW<[FPU2, FPU2, Lat15, GroupAlone], (instregex "FIXBR(A)?$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Binary arithmetic
+//===----------------------------------------------------------------------===//
+
+// Addition
+def : InstRW<[FPU, LSU, Lat12], (instregex "A(E|D)B$")>;
+def : InstRW<[FPU], (instregex "A(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat20, GroupAlone], (instregex "AXBR$")>;
+
+// Subtraction
+def : InstRW<[FPU, LSU, Lat12], (instregex "S(E|D)B$")>;
+def : InstRW<[FPU], (instregex "S(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat20, GroupAlone], (instregex "SXBR$")>;
+
+// Multiply
+def : InstRW<[FPU, LSU, Lat12], (instregex "M(D|DE|EE)B$")>;
+def : InstRW<[FPU], (instregex "M(D|DE|EE)BR$")>;
+def : InstRW<[FPU2, FPU2, LSU, Lat15, GroupAlone], (instregex "MXDB$")>;
+def : InstRW<[FPU2, FPU2, Lat10, GroupAlone], (instregex "MXDBR$")>;
+def : InstRW<[FPU2, FPU2, Lat30, GroupAlone], (instregex "MXBR$")>;
+
+// Multiply and add / subtract
+def : InstRW<[FPU, LSU, Lat12, GroupAlone], (instregex "M(A|S)EB$")>;
+def : InstRW<[FPU, GroupAlone], (instregex "M(A|S)EBR$")>;
+def : InstRW<[FPU, LSU, Lat12, GroupAlone], (instregex "M(A|S)DB$")>;
+def : InstRW<[FPU, GroupAlone], (instregex "M(A|S)DBR$")>;
+
+// Division
+def : InstRW<[FPU, LSU, Lat30], (instregex "D(E|D)B$")>;
+def : InstRW<[FPU, Lat30], (instregex "D(E|D)BR$")>;
+def : InstRW<[FPU2, FPU2, Lat30, GroupAlone], (instregex "DXBR$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Comparisons
+//===----------------------------------------------------------------------===//
+
+// Compare
+def : InstRW<[FPU, LSU, Lat12], (instregex "C(E|D)B$")>;
+def : InstRW<[FPU], (instregex "C(E|D)BR$")>;
+def : InstRW<[FPU, FPU, Lat30], (instregex "CXBR$")>;
+
+// Test Data Class
+def : InstRW<[FPU, LSU, Lat15], (instregex "TC(E|D)B$")>;
+def : InstRW<[FPU2, FPU2, LSU, Lat15, GroupAlone], (instregex "TCXB$")>;
+
+//===----------------------------------------------------------------------===//
+// FP: Floating-point control register instructions
+//===----------------------------------------------------------------------===//
+
+def : InstRW<[FXU, LSU, Lat4, GroupAlone], (instregex "EFPC$")>;
+def : InstRW<[LSU, Lat3, GroupAlone], (instregex "SFPC$")>;
+def : InstRW<[LSU, LSU, Lat6, GroupAlone], (instregex "LFPC$")>;
+def : InstRW<[LSU, Lat3, GroupAlone], (instregex "STFPC$")>;
+def : InstRW<[FXU, Lat30, GroupAlone], (instregex "SFASR$")>;
+def : InstRW<[FXU, LSU, Lat30, GroupAlone], (instregex "LFAS$")>;
+def : InstRW<[FXU, Lat2, GroupAlone], (instregex "SRNM(B|T)?$")>;
+
+}
+
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZShortenInst.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZShortenInst.cpp
index 7f26a35..83882fc 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZShortenInst.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZShortenInst.cpp
@@ -29,7 +29,7 @@ public:
static char ID;
SystemZShortenInst(const SystemZTargetMachine &tm);
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "SystemZ Instruction Shortening";
}
@@ -37,7 +37,7 @@ public:
bool runOnMachineFunction(MachineFunction &F) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -275,7 +275,7 @@ bool SystemZShortenInst::runOnMachineFunction(MachineFunction &F) {
const SystemZSubtarget &ST = F.getSubtarget<SystemZSubtarget>();
TII = ST.getInstrInfo();
TRI = ST.getRegisterInfo();
- LiveRegs.init(TRI);
+ LiveRegs.init(*TRI);
bool Changed = false;
for (auto &MBB : F)
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
index 67d5e01..ce07ea3 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
@@ -39,10 +39,12 @@ SystemZSubtarget::SystemZSubtarget(const Triple &TT, const std::string &CPU,
HasLoadStoreOnCond(false), HasHighWord(false), HasFPExtension(false),
HasPopulationCount(false), HasFastSerialization(false),
HasInterlockedAccess1(false), HasMiscellaneousExtensions(false),
+ HasExecutionHint(false), HasLoadAndTrap(false),
HasTransactionalExecution(false), HasProcessorAssist(false),
- HasVector(false), HasLoadStoreOnCond2(false), TargetTriple(TT),
- InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this),
- TSInfo(), FrameLowering() {}
+ HasVector(false), HasLoadStoreOnCond2(false),
+ HasLoadAndZeroRightmostByte(false),
+ TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)),
+ TLInfo(TM, *this), TSInfo(), FrameLowering() {}
bool SystemZSubtarget::isPC32DBLSymbol(const GlobalValue *GV,
CodeModel::Model CM) const {
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h
index 6007f6f..cdb6132 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZSubtarget.h
@@ -42,10 +42,13 @@ protected:
bool HasFastSerialization;
bool HasInterlockedAccess1;
bool HasMiscellaneousExtensions;
+ bool HasExecutionHint;
+ bool HasLoadAndTrap;
bool HasTransactionalExecution;
bool HasProcessorAssist;
bool HasVector;
bool HasLoadStoreOnCond2;
+ bool HasLoadAndZeroRightmostByte;
private:
Triple TargetTriple;
@@ -77,6 +80,9 @@ public:
// This is important for reducing register pressure in vector code.
bool useAA() const override { return true; }
+ // Always enable the early if-conversion pass.
+ bool enableEarlyIfConversion() const override { return true; }
+
// Automatically generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
@@ -109,12 +115,23 @@ public:
return HasMiscellaneousExtensions;
}
+ // Return true if the target has the execution-hint facility.
+ bool hasExecutionHint() const { return HasExecutionHint; }
+
+ // Return true if the target has the load-and-trap facility.
+ bool hasLoadAndTrap() const { return HasLoadAndTrap; }
+
// Return true if the target has the transactional-execution facility.
bool hasTransactionalExecution() const { return HasTransactionalExecution; }
// Return true if the target has the processor-assist facility.
bool hasProcessorAssist() const { return HasProcessorAssist; }
+ // Return true if the target has the load-and-zero-rightmost-byte facility.
+ bool hasLoadAndZeroRightmostByte() const {
+ return HasLoadAndZeroRightmostByte;
+ }
+
// Return true if the target has the vector facility.
bool hasVector() const { return HasVector; }
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
index 85a3f6f..33fdb8f 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp
@@ -9,6 +9,7 @@
#include "SystemZTargetMachine.h"
#include "SystemZTargetTransformInfo.h"
+#include "SystemZMachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/Support/TargetRegistry.h"
@@ -17,10 +18,9 @@
using namespace llvm;
-extern cl::opt<bool> MISchedPostRA;
extern "C" void LLVMInitializeSystemZTarget() {
// Register the target.
- RegisterTargetMachine<SystemZTargetMachine> X(TheSystemZTarget);
+ RegisterTargetMachine<SystemZTargetMachine> X(getTheSystemZTarget());
}
// Determine whether we use the vector ABI.
@@ -114,8 +114,15 @@ public:
return getTM<SystemZTargetMachine>();
}
+ ScheduleDAGInstrs *
+ createPostMachineScheduler(MachineSchedContext *C) const override {
+ return new ScheduleDAGMI(C, make_unique<SystemZPostRASchedStrategy>(C),
+ /*RemoveKillFlags=*/true);
+ }
+
void addIRPasses() override;
bool addInstSelector() override;
+ bool addILPOpts() override;
void addPreSched2() override;
void addPreEmitPass() override;
};
@@ -137,7 +144,14 @@ bool SystemZPassConfig::addInstSelector() {
return false;
}
+bool SystemZPassConfig::addILPOpts() {
+ addPass(&EarlyIfConverterID);
+ return true;
+}
+
void SystemZPassConfig::addPreSched2() {
+ addPass(createSystemZExpandPseudoPass(getSystemZTargetMachine()));
+
if (getOptLevel() != CodeGenOpt::None)
addPass(&IfConverterID);
}
@@ -180,12 +194,8 @@ void SystemZPassConfig::addPreEmitPass() {
// Do final scheduling after all other optimizations, to get an
// optimal input for the decoder (branch relaxation must happen
// after block placement).
- if (getOptLevel() != CodeGenOpt::None) {
- if (MISchedPostRA)
- addPass(&PostMachineSchedulerID);
- else
- addPass(&PostRASchedulerID);
- }
+ if (getOptLevel() != CodeGenOpt::None)
+ addPass(&PostMachineSchedulerID);
}
TargetPassConfig *SystemZTargetMachine::createPassConfig(PassManagerBase &PM) {
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
index 5ff5b21..b10c0e0 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
@@ -238,6 +238,63 @@ SystemZTTIImpl::getPopcntSupport(unsigned TyWidth) {
return TTI::PSK_Software;
}
+void SystemZTTIImpl::getUnrollingPreferences(Loop *L,
+ TTI::UnrollingPreferences &UP) {
+ // Find out if L contains a call, what the machine instruction count
+ // estimate is, and how many stores there are.
+ bool HasCall = false;
+ unsigned NumStores = 0;
+ for (auto &BB : L->blocks())
+ for (auto &I : *BB) {
+ if (isa<CallInst>(&I) || isa<InvokeInst>(&I)) {
+ ImmutableCallSite CS(&I);
+ if (const Function *F = CS.getCalledFunction()) {
+ if (isLoweredToCall(F))
+ HasCall = true;
+ if (F->getIntrinsicID() == Intrinsic::memcpy ||
+ F->getIntrinsicID() == Intrinsic::memset)
+ NumStores++;
+ } else { // indirect call.
+ HasCall = true;
+ }
+ }
+ if (isa<StoreInst>(&I)) {
+ NumStores++;
+ Type *MemAccessTy = I.getOperand(0)->getType();
+ if((MemAccessTy->isIntegerTy() || MemAccessTy->isFloatingPointTy()) &&
+ (getDataLayout().getTypeSizeInBits(MemAccessTy) == 128))
+ NumStores++; // 128 bit fp/int stores get split.
+ }
+ }
+
+ // The z13 processor will run out of store tags if too many stores
+ // are fed into it too quickly. Therefore make sure there are not
+ // too many stores in the resulting unrolled loop.
+ unsigned const Max = (NumStores ? (12 / NumStores) : UINT_MAX);
+
+ if (HasCall) {
+ // Only allow full unrolling if loop has any calls.
+ UP.FullUnrollMaxCount = Max;
+ UP.MaxCount = 1;
+ return;
+ }
+
+ UP.MaxCount = Max;
+ if (UP.MaxCount <= 1)
+ return;
+
+ // Allow partial and runtime trip count unrolling.
+ UP.Partial = UP.Runtime = true;
+
+ UP.PartialThreshold = 75;
+ UP.DefaultUnrollRuntimeCount = 4;
+
+ // Allow expensive instructions in the pre-header of the loop.
+ UP.AllowExpensiveTripCount = true;
+
+ UP.Force = true;
+}
+
unsigned SystemZTTIImpl::getNumberOfRegisters(bool Vector) {
if (!Vector)
// Discount the stack pointer. Also leave out %r0, since it can't
diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.h b/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.h
index 9ae736d..f7d2d82 100644
--- a/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.h
@@ -32,13 +32,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- SystemZTTIImpl(const SystemZTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- SystemZTTIImpl(SystemZTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
/// \name Scalar TTI Implementations
/// @{
@@ -50,6 +43,8 @@ public:
TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth);
+ void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP);
+
/// @}
/// \name Vector TTI Implementations
diff --git a/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp b/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp
index 8f9aa28..d3c53a4 100644
--- a/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/SystemZ/TargetInfo/SystemZTargetInfo.cpp
@@ -12,9 +12,12 @@
using namespace llvm;
-Target llvm::TheSystemZTarget;
+Target &llvm::getTheSystemZTarget() {
+ static Target TheSystemZTarget;
+ return TheSystemZTarget;
+}
extern "C" void LLVMInitializeSystemZTargetInfo() {
- RegisterTarget<Triple::systemz, /*HasJIT=*/true>
- X(TheSystemZTarget, "systemz", "SystemZ");
+ RegisterTarget<Triple::systemz, /*HasJIT=*/true> X(getTheSystemZTarget(),
+ "systemz", "SystemZ");
}
diff --git a/contrib/llvm/lib/Target/TargetIntrinsicInfo.cpp b/contrib/llvm/lib/Target/TargetIntrinsicInfo.cpp
index 64bd56f..e8b7192 100644
--- a/contrib/llvm/lib/Target/TargetIntrinsicInfo.cpp
+++ b/contrib/llvm/lib/Target/TargetIntrinsicInfo.cpp
@@ -22,7 +22,7 @@ TargetIntrinsicInfo::TargetIntrinsicInfo() {
TargetIntrinsicInfo::~TargetIntrinsicInfo() {
}
-unsigned TargetIntrinsicInfo::getIntrinsicID(Function *F) const {
+unsigned TargetIntrinsicInfo::getIntrinsicID(const Function *F) const {
const ValueName *ValName = F->getValueName();
if (!ValName)
return 0;
diff --git a/contrib/llvm/lib/Target/TargetLoweringObjectFile.cpp b/contrib/llvm/lib/Target/TargetLoweringObjectFile.cpp
index f863f42..375f851 100644
--- a/contrib/llvm/lib/Target/TargetLoweringObjectFile.cpp
+++ b/contrib/llvm/lib/Target/TargetLoweringObjectFile.cpp
@@ -43,11 +43,15 @@ using namespace llvm;
void TargetLoweringObjectFile::Initialize(MCContext &ctx,
const TargetMachine &TM) {
Ctx = &ctx;
+ // `Initialize` can be called more than once.
+ if (Mang != nullptr) delete Mang;
+ Mang = new Mangler();
InitMCObjectFileInfo(TM.getTargetTriple(), TM.isPositionIndependent(),
TM.getCodeModel(), *Ctx);
}
TargetLoweringObjectFile::~TargetLoweringObjectFile() {
+ delete Mang;
}
static bool isSuitableForBSS(const GlobalVariable *GV, bool NoZerosInBSS) {
@@ -101,21 +105,20 @@ static bool IsNullTerminatedString(const Constant *C) {
}
MCSymbol *TargetLoweringObjectFile::getSymbolWithGlobalValueBase(
- const GlobalValue *GV, StringRef Suffix, Mangler &Mang,
- const TargetMachine &TM) const {
+ const GlobalValue *GV, StringRef Suffix, const TargetMachine &TM) const {
assert(!Suffix.empty());
SmallString<60> NameStr;
NameStr += GV->getParent()->getDataLayout().getPrivateGlobalPrefix();
- TM.getNameWithPrefix(NameStr, GV, Mang);
+ TM.getNameWithPrefix(NameStr, GV, *Mang);
NameStr.append(Suffix.begin(), Suffix.end());
return Ctx->getOrCreateSymbol(NameStr);
}
MCSymbol *TargetLoweringObjectFile::getCFIPersonalitySymbol(
- const GlobalValue *GV, Mangler &Mang, const TargetMachine &TM,
+ const GlobalValue *GV, const TargetMachine &TM,
MachineModuleInfo *MMI) const {
- return TM.getSymbol(GV, Mang);
+ return TM.getSymbol(GV);
}
void TargetLoweringObjectFile::emitPersonalityValue(MCStreamer &Streamer,
@@ -129,15 +132,15 @@ void TargetLoweringObjectFile::emitPersonalityValue(MCStreamer &Streamer,
/// classifies the global in a variety of ways that make various target
/// implementations simpler. The target implementation is free to ignore this
/// extra info of course.
-SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalValue *GV,
+SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalObject *GO,
const TargetMachine &TM){
- assert(!GV->isDeclaration() && !GV->hasAvailableExternallyLinkage() &&
+ assert(!GO->isDeclaration() && !GO->hasAvailableExternallyLinkage() &&
"Can only be used for global definitions");
Reloc::Model ReloModel = TM.getRelocationModel();
// Early exit - functions should be always in text sections.
- const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
+ const auto *GVar = dyn_cast<GlobalVariable>(GO);
if (!GVar)
return SectionKind::getText();
@@ -198,7 +201,8 @@ SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalValue *GV,
// Otherwise, just drop it into a mergable constant section. If we have
// a section for this size, use it, otherwise use the arbitrary sized
// mergable section.
- switch (GV->getParent()->getDataLayout().getTypeAllocSize(C->getType())) {
+ switch (
+ GVar->getParent()->getDataLayout().getTypeAllocSize(C->getType())) {
case 4: return SectionKind::getMergeableConst4();
case 8: return SectionKind::getMergeableConst8();
case 16: return SectionKind::getMergeableConst16();
@@ -208,12 +212,13 @@ SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalValue *GV,
}
} else {
- // In static relocation model, the linker will resolve all addresses, so
- // the relocation entries will actually be constants by the time the app
- // starts up. However, we can't put this into a mergable section, because
- // the linker doesn't take relocations into consideration when it tries to
- // merge entries in the section.
- if (ReloModel == Reloc::Static)
+ // In static, ROPI and RWPI relocation models, the linker will resolve
+ // all addresses, so the relocation entries will actually be constants by
+ // the time the app starts up. However, we can't put this into a
+ // mergable section, because the linker doesn't take relocations into
+ // consideration when it tries to merge entries in the section.
+ if (ReloModel == Reloc::Static || ReloModel == Reloc::ROPI ||
+ ReloModel == Reloc::RWPI || ReloModel == Reloc::ROPI_RWPI)
return SectionKind::getReadOnly();
// Otherwise, the dynamic linker needs to fix it up, put it in the
@@ -229,21 +234,18 @@ SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalValue *GV,
/// This method computes the appropriate section to emit the specified global
/// variable or function definition. This should not be passed external (or
/// available externally) globals.
-MCSection *
-TargetLoweringObjectFile::SectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
+MCSection *TargetLoweringObjectFile::SectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
// Select section name.
- if (GV->hasSection())
- return getExplicitSectionGlobal(GV, Kind, Mang, TM);
-
+ if (GO->hasSection())
+ return getExplicitSectionGlobal(GO, Kind, TM);
// Use default section depending on the 'type' of global
- return SelectSectionForGlobal(GV, Kind, Mang, TM);
+ return SelectSectionForGlobal(GO, Kind, TM);
}
MCSection *TargetLoweringObjectFile::getSectionForJumpTable(
- const Function &F, Mangler &Mang, const TargetMachine &TM) const {
+ const Function &F, const TargetMachine &TM) const {
unsigned Align = 0;
return getSectionForConstant(F.getParent()->getDataLayout(),
SectionKind::getReadOnly(), /*C=*/nullptr,
@@ -283,11 +285,10 @@ MCSection *TargetLoweringObjectFile::getSectionForConstant(
/// reference to the specified global variable from exception
/// handling information.
const MCExpr *TargetLoweringObjectFile::getTTypeGlobalReference(
- const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
- const TargetMachine &TM, MachineModuleInfo *MMI,
- MCStreamer &Streamer) const {
+ const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM,
+ MachineModuleInfo *MMI, MCStreamer &Streamer) const {
const MCSymbolRefExpr *Ref =
- MCSymbolRefExpr::create(TM.getSymbol(GV, Mang), getContext());
+ MCSymbolRefExpr::create(TM.getSymbol(GV), getContext());
return getTTypeReference(Ref, Encoding, Streamer);
}
@@ -319,7 +320,7 @@ const MCExpr *TargetLoweringObjectFile::getDebugThreadLocalSymbol(const MCSymbol
}
void TargetLoweringObjectFile::getNameWithPrefix(
- SmallVectorImpl<char> &OutName, const GlobalValue *GV, Mangler &Mang,
+ SmallVectorImpl<char> &OutName, const GlobalValue *GV,
const TargetMachine &TM) const {
- Mang.getNameWithPrefix(OutName, GV, /*CannotUsePrivateLabel=*/false);
+ Mang->getNameWithPrefix(OutName, GV, /*CannotUsePrivateLabel=*/false);
}
diff --git a/contrib/llvm/lib/Target/TargetMachine.cpp b/contrib/llvm/lib/Target/TargetMachine.cpp
index 82c6850..8a6d284 100644
--- a/contrib/llvm/lib/Target/TargetMachine.cpp
+++ b/contrib/llvm/lib/Target/TargetMachine.cpp
@@ -44,7 +44,7 @@ TargetMachine::TargetMachine(const Target &T, StringRef DataLayoutString,
const TargetOptions &Options)
: TheTarget(T), DL(DataLayoutString), TargetTriple(TT), TargetCPU(CPU),
TargetFS(FS), AsmInfo(nullptr), MRI(nullptr), MII(nullptr), STI(nullptr),
- RequireStructuredCFG(false), Options(Options) {
+ RequireStructuredCFG(false), DefaultOptions(Options), Options(Options) {
if (EnableIPRA.getNumOccurrences())
this->Options.EnableIPRA = EnableIPRA;
}
@@ -63,20 +63,33 @@ bool TargetMachine::isPositionIndependent() const {
/// \brief Reset the target options based on the function's attributes.
// FIXME: This function needs to go away for a number of reasons:
// a) global state on the TargetMachine is terrible in general,
-// b) there's no default state here to keep,
-// c) these target options should be passed only on the function
+// b) these target options should be passed only on the function
// and not on the TargetMachine (via TargetOptions) at all.
void TargetMachine::resetTargetOptions(const Function &F) const {
#define RESET_OPTION(X, Y) \
do { \
if (F.hasFnAttribute(Y)) \
Options.X = (F.getFnAttribute(Y).getValueAsString() == "true"); \
+ else \
+ Options.X = DefaultOptions.X; \
} while (0)
RESET_OPTION(LessPreciseFPMADOption, "less-precise-fpmad");
RESET_OPTION(UnsafeFPMath, "unsafe-fp-math");
RESET_OPTION(NoInfsFPMath, "no-infs-fp-math");
RESET_OPTION(NoNaNsFPMath, "no-nans-fp-math");
+ RESET_OPTION(NoTrappingFPMath, "no-trapping-math");
+
+ StringRef Denormal =
+ F.getFnAttribute("denormal-fp-math").getValueAsString();
+ if (Denormal == "ieee")
+ Options.FPDenormalMode = FPDenormal::IEEE;
+ else if (Denormal == "preserve-sign")
+ Options.FPDenormalMode = FPDenormal::PreserveSign;
+ else if (Denormal == "positive-zero")
+ Options.FPDenormalMode = FPDenormal::PositiveZero;
+ else
+ Options.FPDenormalMode = DefaultOptions.FPDenormalMode;
}
/// Returns the code generation relocation model. The choices are static, PIC,
@@ -105,9 +118,6 @@ static TLSModel::Model getSelectedTLSModel(const GlobalValue *GV) {
llvm_unreachable("invalid TLS model");
}
-// FIXME: make this a proper option
-static bool CanUseCopyRelocWithPIE = false;
-
bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
const GlobalValue *GV) const {
Reloc::Model RM = getRelocationModel();
@@ -117,8 +127,11 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
if (GV && GV->hasDLLImportStorageClass())
return false;
- // Every other GV is local on COFF
- if (TT.isOSBinFormatCOFF())
+ // Every other GV is local on COFF.
+ // Make an exception for windows OS in the triple: Some firmwares builds use
+ // *-win32-macho triples. This (accidentally?) produced windows relocations
+ // without GOT tables in older clang versions; Keep this behaviour.
+ if (TT.isOSBinFormatCOFF() || (TT.isOSWindows() && TT.isOSBinFormatMachO()))
return true;
if (GV && (GV->hasLocalLinkage() || !GV->hasDefaultVisibility()))
@@ -141,8 +154,10 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
return true;
bool IsTLS = GV && GV->isThreadLocal();
+ bool IsAccessViaCopyRelocs =
+ Options.MCOptions.MCPIECopyRelocations && GV && isa<GlobalVariable>(GV);
// Check if we can use copy relocations.
- if (!IsTLS && (RM == Reloc::Static || CanUseCopyRelocWithPIE))
+ if (!IsTLS && (RM == Reloc::Static || IsAccessViaCopyRelocs))
return true;
}
@@ -198,12 +213,12 @@ void TargetMachine::getNameWithPrefix(SmallVectorImpl<char> &Name,
return;
}
const TargetLoweringObjectFile *TLOF = getObjFileLowering();
- TLOF->getNameWithPrefix(Name, GV, Mang, *this);
+ TLOF->getNameWithPrefix(Name, GV, *this);
}
-MCSymbol *TargetMachine::getSymbol(const GlobalValue *GV, Mangler &Mang) const {
- SmallString<128> NameStr;
- getNameWithPrefix(NameStr, GV, Mang);
+MCSymbol *TargetMachine::getSymbol(const GlobalValue *GV) const {
const TargetLoweringObjectFile *TLOF = getObjFileLowering();
+ SmallString<128> NameStr;
+ getNameWithPrefix(NameStr, GV, TLOF->getMangler());
return TLOF->getContext().getOrCreateSymbol(NameStr);
}
diff --git a/contrib/llvm/lib/Target/TargetMachineC.cpp b/contrib/llvm/lib/Target/TargetMachineC.cpp
index 02836ea..df12e0e 100644
--- a/contrib/llvm/lib/Target/TargetMachineC.cpp
+++ b/contrib/llvm/lib/Target/TargetMachineC.cpp
@@ -59,9 +59,8 @@ LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T) {
LLVMTargetRef LLVMGetTargetFromName(const char *Name) {
StringRef NameRef = Name;
- auto I = std::find_if(
- TargetRegistry::targets().begin(), TargetRegistry::targets().end(),
- [&](const Target &T) { return T.getName() == NameRef; });
+ auto I = find_if(TargetRegistry::targets(),
+ [&](const Target &T) { return T.getName() == NameRef; });
return I != TargetRegistry::targets().end() ? wrap(&*I) : nullptr;
}
@@ -102,7 +101,7 @@ LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T) {
}
LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T,
- const char* Triple, const char* CPU, const char* Features,
+ const char *Triple, const char *CPU, const char *Features,
LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc,
LLVMCodeModel CodeModel) {
Optional<Reloc::Model> RM;
@@ -140,7 +139,7 @@ LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T,
TargetOptions opt;
return wrap(unwrap(T)->createTargetMachine(Triple, CPU, Features, opt, RM,
- CM, OL));
+ CM, OL));
}
void LLVMDisposeTargetMachine(LLVMTargetMachineRef T) { delete unwrap(T); }
diff --git a/contrib/llvm/lib/Target/TargetRecip.cpp b/contrib/llvm/lib/Target/TargetRecip.cpp
deleted file mode 100644
index 183fa50..0000000
--- a/contrib/llvm/lib/Target/TargetRecip.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-//===-------------------------- TargetRecip.cpp ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class is used to customize machine-specific reciprocal estimate code
-// generation in a target-independent way.
-// If a target does not support operations in this specification, then code
-// generation will default to using supported operations.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Target/TargetRecip.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ErrorHandling.h"
-
-using namespace llvm;
-
-// These are the names of the individual reciprocal operations. These are
-// the key strings for queries and command-line inputs.
-// In addition, the command-line interface recognizes the global parameters
-// "all", "none", and "default".
-static const char *const RecipOps[] = {
- "divd",
- "divf",
- "vec-divd",
- "vec-divf",
- "sqrtd",
- "sqrtf",
- "vec-sqrtd",
- "vec-sqrtf",
-};
-
-// The uninitialized state is needed for the enabled settings and refinement
-// steps because custom settings may arrive via the command-line before target
-// defaults are set.
-TargetRecip::TargetRecip() {
- unsigned NumStrings = llvm::array_lengthof(RecipOps);
- for (unsigned i = 0; i < NumStrings; ++i)
- RecipMap.insert(std::make_pair(RecipOps[i], RecipParams()));
-}
-
-static bool parseRefinementStep(StringRef In, size_t &Position,
- uint8_t &Value) {
- const char RefStepToken = ':';
- Position = In.find(RefStepToken);
- if (Position == StringRef::npos)
- return false;
-
- StringRef RefStepString = In.substr(Position + 1);
- // Allow exactly one numeric character for the additional refinement
- // step parameter.
- if (RefStepString.size() == 1) {
- char RefStepChar = RefStepString[0];
- if (RefStepChar >= '0' && RefStepChar <= '9') {
- Value = RefStepChar - '0';
- return true;
- }
- }
- report_fatal_error("Invalid refinement step for -recip.");
-}
-
-bool TargetRecip::parseGlobalParams(const std::string &Arg) {
- StringRef ArgSub = Arg;
-
- // Look for an optional setting of the number of refinement steps needed
- // for this type of reciprocal operation.
- size_t RefPos;
- uint8_t RefSteps;
- StringRef RefStepString;
- if (parseRefinementStep(ArgSub, RefPos, RefSteps)) {
- // Split the string for further processing.
- RefStepString = ArgSub.substr(RefPos + 1);
- ArgSub = ArgSub.substr(0, RefPos);
- }
- bool Enable;
- bool UseDefaults;
- if (ArgSub == "all") {
- UseDefaults = false;
- Enable = true;
- } else if (ArgSub == "none") {
- UseDefaults = false;
- Enable = false;
- } else if (ArgSub == "default") {
- UseDefaults = true;
- } else {
- // Any other string is invalid or an individual setting.
- return false;
- }
-
- // All enable values will be initialized to target defaults if 'default' was
- // specified.
- if (!UseDefaults)
- for (auto &KV : RecipMap)
- KV.second.Enabled = Enable;
-
- // Custom refinement count was specified with all, none, or default.
- if (!RefStepString.empty())
- for (auto &KV : RecipMap)
- KV.second.RefinementSteps = RefSteps;
-
- return true;
-}
-
-void TargetRecip::parseIndividualParams(const std::vector<std::string> &Args) {
- static const char DisabledPrefix = '!';
- unsigned NumArgs = Args.size();
-
- for (unsigned i = 0; i != NumArgs; ++i) {
- StringRef Val = Args[i];
-
- bool IsDisabled = Val[0] == DisabledPrefix;
- // Ignore the disablement token for string matching.
- if (IsDisabled)
- Val = Val.substr(1);
-
- size_t RefPos;
- uint8_t RefSteps;
- StringRef RefStepString;
- if (parseRefinementStep(Val, RefPos, RefSteps)) {
- // Split the string for further processing.
- RefStepString = Val.substr(RefPos + 1);
- Val = Val.substr(0, RefPos);
- }
-
- RecipIter Iter = RecipMap.find(Val);
- if (Iter == RecipMap.end()) {
- // Try again specifying float suffix.
- Iter = RecipMap.find(Val.str() + 'f');
- if (Iter == RecipMap.end()) {
- Iter = RecipMap.find(Val.str() + 'd');
- assert(Iter == RecipMap.end() && "Float entry missing from map");
- report_fatal_error("Invalid option for -recip.");
- }
-
- // The option was specified without a float or double suffix.
- if (RecipMap[Val.str() + 'd'].Enabled != Uninitialized) {
- // Make sure that the double entry was not already specified.
- // The float entry will be checked below.
- report_fatal_error("Duplicate option for -recip.");
- }
- }
-
- if (Iter->second.Enabled != Uninitialized)
- report_fatal_error("Duplicate option for -recip.");
-
- // Mark the matched option as found. Do not allow duplicate specifiers.
- Iter->second.Enabled = !IsDisabled;
- if (!RefStepString.empty())
- Iter->second.RefinementSteps = RefSteps;
-
- // If the precision was not specified, the double entry is also initialized.
- if (Val.back() != 'f' && Val.back() != 'd') {
- RecipParams &Params = RecipMap[Val.str() + 'd'];
- Params.Enabled = !IsDisabled;
- if (!RefStepString.empty())
- Params.RefinementSteps = RefSteps;
- }
- }
-}
-
-TargetRecip::TargetRecip(const std::vector<std::string> &Args) :
- TargetRecip() {
- unsigned NumArgs = Args.size();
-
- // Check if "all", "default", or "none" was specified.
- if (NumArgs == 1 && parseGlobalParams(Args[0]))
- return;
-
- parseIndividualParams(Args);
-}
-
-bool TargetRecip::isEnabled(StringRef Key) const {
- ConstRecipIter Iter = RecipMap.find(Key);
- assert(Iter != RecipMap.end() && "Unknown name for reciprocal map");
- assert(Iter->second.Enabled != Uninitialized &&
- "Enablement setting was not initialized");
- return Iter->second.Enabled;
-}
-
-unsigned TargetRecip::getRefinementSteps(StringRef Key) const {
- ConstRecipIter Iter = RecipMap.find(Key);
- assert(Iter != RecipMap.end() && "Unknown name for reciprocal map");
- assert(Iter->second.RefinementSteps != Uninitialized &&
- "Refinement step setting was not initialized");
- return Iter->second.RefinementSteps;
-}
-
-/// Custom settings (previously initialized values) override target defaults.
-void TargetRecip::setDefaults(StringRef Key, bool Enable,
- unsigned RefSteps) {
- if (Key == "all") {
- for (auto &KV : RecipMap) {
- RecipParams &RP = KV.second;
- if (RP.Enabled == Uninitialized)
- RP.Enabled = Enable;
- if (RP.RefinementSteps == Uninitialized)
- RP.RefinementSteps = RefSteps;
- }
- } else {
- RecipParams &RP = RecipMap[Key];
- if (RP.Enabled == Uninitialized)
- RP.Enabled = Enable;
- if (RP.RefinementSteps == Uninitialized)
- RP.RefinementSteps = RefSteps;
- }
-}
-
-bool TargetRecip::operator==(const TargetRecip &Other) const {
- for (const auto &KV : RecipMap) {
- StringRef Op = KV.first;
- const RecipParams &RP = KV.second;
- const RecipParams &OtherRP = Other.RecipMap.find(Op)->second;
- if (RP.RefinementSteps != OtherRP.RefinementSteps)
- return false;
- if (RP.Enabled != OtherRP.Enabled)
- return false;
- }
- return true;
-}
diff --git a/contrib/llvm/lib/Target/TargetSubtargetInfo.cpp b/contrib/llvm/lib/Target/TargetSubtargetInfo.cpp
deleted file mode 100644
index c3f94a9..0000000
--- a/contrib/llvm/lib/Target/TargetSubtargetInfo.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//===-- TargetSubtargetInfo.cpp - General Target Information ---------------==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file describes the general parts of a Subtarget.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Target/TargetSubtargetInfo.h"
-using namespace llvm;
-
-//---------------------------------------------------------------------------
-// TargetSubtargetInfo Class
-//
-TargetSubtargetInfo::TargetSubtargetInfo(
- const Triple &TT, StringRef CPU, StringRef FS,
- ArrayRef<SubtargetFeatureKV> PF, ArrayRef<SubtargetFeatureKV> PD,
- const SubtargetInfoKV *ProcSched, const MCWriteProcResEntry *WPR,
- const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA,
- const InstrStage *IS, const unsigned *OC, const unsigned *FP)
- : MCSubtargetInfo(TT, CPU, FS, PF, PD, ProcSched, WPR, WL, RA, IS, OC, FP) {
-}
-
-TargetSubtargetInfo::~TargetSubtargetInfo() {}
-
-bool TargetSubtargetInfo::enableAtomicExpand() const {
- return true;
-}
-
-bool TargetSubtargetInfo::enableMachineScheduler() const {
- return false;
-}
-
-bool TargetSubtargetInfo::enableJoinGlobalCopies() const {
- return enableMachineScheduler();
-}
-
-bool TargetSubtargetInfo::enableRALocalReassignment(
- CodeGenOpt::Level OptLevel) const {
- return true;
-}
-
-bool TargetSubtargetInfo::enablePostRAScheduler() const {
- return getSchedModel().PostRAScheduler;
-}
-
-bool TargetSubtargetInfo::useAA() const {
- return false;
-}
diff --git a/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index c0355ae..b4763ca 100644
--- a/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -54,9 +54,9 @@ static MCDisassembler *createWebAssemblyDisassembler(const Target &T,
extern "C" void LLVMInitializeWebAssemblyDisassembler() {
// Register the disassembler for each target.
- TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget32,
+ TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget32(),
createWebAssemblyDisassembler);
- TargetRegistry::RegisterMCDisassembler(TheWebAssemblyTarget64,
+ TargetRegistry::RegisterMCDisassembler(getTheWebAssemblyTarget64(),
createWebAssemblyDisassembler);
}
@@ -93,6 +93,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
const MCOperandInfo &Info = Desc.OpInfo[i];
switch (Info.OperandType) {
case MCOI::OPERAND_IMMEDIATE:
+ case WebAssembly::OPERAND_LOCAL:
case WebAssembly::OPERAND_P2ALIGN:
case WebAssembly::OPERAND_BASIC_BLOCK: {
if (Pos + sizeof(uint64_t) > Bytes.size())
@@ -110,8 +111,8 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
MI.addOperand(MCOperand::createReg(Reg));
break;
}
- case WebAssembly::OPERAND_FP32IMM:
- case WebAssembly::OPERAND_FP64IMM: {
+ case WebAssembly::OPERAND_F32IMM:
+ case WebAssembly::OPERAND_F64IMM: {
// TODO: MC converts all floating point immediate operands to double.
// This is fine for numeric values, but may cause NaNs to change bits.
if (Pos + sizeof(uint64_t) > Bytes.size())
diff --git a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
index 267d716..0af13cf 100644
--- a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
@@ -54,7 +54,12 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
const MCInstrDesc &Desc = MII.get(MI->getOpcode());
if (Desc.isVariadic())
for (auto i = Desc.getNumOperands(), e = MI->getNumOperands(); i < e; ++i) {
- if (i != 0)
+ // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because
+ // we have an extra flags operand which is not currently printed, for
+ // compatiblity reasons.
+ if (i != 0 &&
+ (MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID ||
+ i != Desc.getNumOperands()))
OS << ", ";
printOperand(MI, i, OS);
}
@@ -69,11 +74,8 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
default:
break;
case WebAssembly::LOOP: {
- // Grab the TopLabel value first so that labels print in numeric order.
- uint64_t TopLabel = ControlFlowCounter++;
- ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
- printAnnotation(OS, "label" + utostr(TopLabel) + ':');
- ControlFlowStack.push_back(std::make_pair(TopLabel, true));
+ printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
+ ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
break;
}
case WebAssembly::BLOCK:
@@ -81,8 +83,6 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
break;
case WebAssembly::END_LOOP:
ControlFlowStack.pop_back();
- printAnnotation(
- OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
break;
case WebAssembly::END_BLOCK:
printAnnotation(
@@ -94,9 +94,9 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
unsigned NumFixedOperands = Desc.NumOperands;
SmallSet<uint64_t, 8> Printed;
for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
- const MCOperandInfo &Info = Desc.OpInfo[i];
if (!(i < NumFixedOperands
- ? (Info.OperandType == WebAssembly::OPERAND_BASIC_BLOCK)
+ ? (Desc.OpInfo[i].OperandType ==
+ WebAssembly::OPERAND_BASIC_BLOCK)
: (Desc.TSFlags & WebAssemblyII::VariableOpImmediateIsLabel)))
continue;
uint64_t Depth = MI->getOperand(i).getImm();
@@ -113,7 +113,8 @@ static std::string toString(const APFloat &FP) {
// Print NaNs with custom payloads specially.
if (FP.isNaN() &&
!FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
- !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
+ !FP.bitwiseIsEqual(
+ APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
APInt AI = FP.bitcastToAPInt();
return
std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
@@ -154,11 +155,12 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
O << '=';
} else if (Op.isImm()) {
- assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() ||
- (MII.get(MI->getOpcode()).TSFlags &
- WebAssemblyII::VariableOpIsImmediate)) &&
+ const MCInstrDesc &Desc = MII.get(MI->getOpcode());
+ assert((OpNo < Desc.getNumOperands() ||
+ (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate)) &&
"WebAssemblyII::VariableOpIsImmediate should be set for "
"variable_ops immediate ops");
+ (void)Desc;
// TODO: (MII.get(MI->getOpcode()).TSFlags &
// WebAssemblyII::VariableOpImmediateIsLabel)
// can tell us whether this is an immediate referencing a label in the
@@ -171,12 +173,12 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
assert(Desc.TSFlags == 0 &&
"WebAssembly variable_ops floating point ops don't use TSFlags");
const MCOperandInfo &Info = Desc.OpInfo[OpNo];
- if (Info.OperandType == WebAssembly::OPERAND_FP32IMM) {
+ if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
// TODO: MC converts all floating point immediate operands to double.
// This is fine for numeric values, but may cause NaNs to change bits.
O << toString(APFloat(float(Op.getFPImm())));
} else {
- assert(Info.OperandType == WebAssembly::OPERAND_FP64IMM);
+ assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
O << toString(APFloat(Op.getFPImm()));
}
} else {
@@ -200,6 +202,27 @@ WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
O << ":p2align=" << Imm;
}
+void
+WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
+ unsigned OpNo,
+ raw_ostream &O) {
+ int64_t Imm = MI->getOperand(OpNo).getImm();
+ switch (WebAssembly::ExprType(Imm)) {
+ case WebAssembly::ExprType::Void: break;
+ case WebAssembly::ExprType::I32: O << "i32"; break;
+ case WebAssembly::ExprType::I64: O << "i64"; break;
+ case WebAssembly::ExprType::F32: O << "f32"; break;
+ case WebAssembly::ExprType::F64: O << "f64"; break;
+ case WebAssembly::ExprType::I8x16: O << "i8x16"; break;
+ case WebAssembly::ExprType::I16x8: O << "i16x8"; break;
+ case WebAssembly::ExprType::I32x4: O << "i32x4"; break;
+ case WebAssembly::ExprType::F32x4: O << "f32x4"; break;
+ case WebAssembly::ExprType::B8x16: O << "b8x16"; break;
+ case WebAssembly::ExprType::B16x8: O << "b16x8"; break;
+ case WebAssembly::ExprType::B32x4: O << "b32x4"; break;
+ }
+}
+
const char *llvm::WebAssembly::TypeToString(MVT Ty) {
switch (Ty.SimpleTy) {
case MVT::i32:
@@ -210,6 +233,11 @@ const char *llvm::WebAssembly::TypeToString(MVT Ty) {
return "f32";
case MVT::f64:
return "f64";
+ case MVT::v16i8:
+ case MVT::v8i16:
+ case MVT::v4i32:
+ case MVT::v4f32:
+ return "v128";
default:
llvm_unreachable("unsupported type");
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h
index 07b0f91..d11f99c 100644
--- a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h
+++ b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h
@@ -39,6 +39,8 @@ public:
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O);
+ void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O);
// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, raw_ostream &O);
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
index df6fb89..97454a8 100644
--- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
@@ -66,8 +66,10 @@ bool WebAssemblyAsmBackend::writeNopData(uint64_t Count,
if (Count == 0)
return true;
- // FIXME: Do something.
- return false;
+ for (uint64_t i = 0; i < Count; ++i)
+ OW->write8(WebAssembly::Nop);
+
+ return true;
}
void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 23f8b3d..d0e0eec 100644
--- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -23,6 +23,7 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -45,7 +46,7 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
const MCSubtargetInfo &STI) const override;
public:
- WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
+ explicit WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
};
} // end anonymous namespace
@@ -56,30 +57,59 @@ MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) {
void WebAssemblyMCCodeEmitter::encodeInstruction(
const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
- // FIXME: This is not the real binary encoding. This is an extremely
- // over-simplified encoding where we just use uint64_t for everything. This
- // is a temporary measure.
- support::endian::Writer<support::little>(OS).write<uint64_t>(MI.getOpcode());
+ uint64_t Start = OS.tell();
+
+ uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
+ assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet");
+ OS << uint8_t(Binary);
+
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
- if (Desc.isVariadic())
- support::endian::Writer<support::little>(OS).write<uint64_t>(
- MI.getNumOperands() - Desc.NumOperands);
for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
const MCOperand &MO = MI.getOperand(i);
if (MO.isReg()) {
- support::endian::Writer<support::little>(OS).write<uint64_t>(MO.getReg());
+ /* nothing to encode */
} else if (MO.isImm()) {
- support::endian::Writer<support::little>(OS).write<uint64_t>(MO.getImm());
+ if (i < Desc.getNumOperands()) {
+ assert(Desc.TSFlags == 0 &&
+ "WebAssembly non-variable_ops don't use TSFlags");
+ const MCOperandInfo &Info = Desc.OpInfo[i];
+ if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
+ encodeSLEB128(int32_t(MO.getImm()), OS);
+ } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
+ encodeSLEB128(int64_t(MO.getImm()), OS);
+ } else {
+ encodeULEB128(uint64_t(MO.getImm()), OS);
+ }
+ } else {
+ assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate |
+ WebAssemblyII::VariableOpImmediateIsLabel));
+ encodeULEB128(uint64_t(MO.getImm()), OS);
+ }
} else if (MO.isFPImm()) {
- support::endian::Writer<support::little>(OS).write<double>(MO.getFPImm());
+ assert(i < Desc.getNumOperands() &&
+ "Unexpected floating-point immediate as a non-fixed operand");
+ assert(Desc.TSFlags == 0 &&
+ "WebAssembly variable_ops floating point ops don't use TSFlags");
+ const MCOperandInfo &Info = Desc.OpInfo[i];
+ if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
+ // TODO: MC converts all floating point immediate operands to double.
+ // This is fine for numeric values, but may cause NaNs to change bits.
+ float f = float(MO.getFPImm());
+ support::endian::Writer<support::little>(OS).write<float>(f);
+ } else {
+ assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
+ double d = MO.getFPImm();
+ support::endian::Writer<support::little>(OS).write<double>(d);
+ }
} else if (MO.isExpr()) {
- support::endian::Writer<support::little>(OS).write<uint64_t>(0);
Fixups.push_back(MCFixup::create(
- (1 + MCII.get(MI.getOpcode()).isVariadic() + i) * sizeof(uint64_t),
- MO.getExpr(),
+ OS.tell() - Start, MO.getExpr(),
STI.getTargetTriple().isArch64Bit() ? FK_Data_8 : FK_Data_4,
MI.getLoc()));
++MCNumFixups;
+ encodeULEB128(STI.getTargetTriple().isArch64Bit() ? UINT64_MAX
+ : uint64_t(UINT32_MAX),
+ OS);
} else {
llvm_unreachable("unexpected operand kind");
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp
index ac11a64..3dc1ded 100644
--- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp
@@ -77,7 +77,8 @@ static MCCodeEmitter *createCodeEmitter(const MCInstrInfo &MCII,
static MCAsmBackend *createAsmBackend(const Target & /*T*/,
const MCRegisterInfo & /*MRI*/,
- const Triple &TT, StringRef /*CPU*/) {
+ const Triple &TT, StringRef /*CPU*/,
+ const MCTargetOptions & /*Options*/) {
return createWebAssemblyAsmBackend(TT);
}
@@ -100,7 +101,8 @@ static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S,
// Force static initialization.
extern "C" void LLVMInitializeWebAssemblyTargetMC() {
- for (Target *T : {&TheWebAssemblyTarget32, &TheWebAssemblyTarget64}) {
+ for (Target *T :
+ {&getTheWebAssemblyTarget32(), &getTheWebAssemblyTarget64()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createMCAsmInfo);
@@ -132,3 +134,13 @@ extern "C" void LLVMInitializeWebAssemblyTargetMC() {
TargetRegistry::RegisterAsmTargetStreamer(*T, createAsmTargetStreamer);
}
}
+
+WebAssembly::ValType WebAssembly::toValType(const MVT &Ty) {
+ switch (Ty.SimpleTy) {
+ case MVT::i32: return WebAssembly::ValType::I32;
+ case MVT::i64: return WebAssembly::ValType::I64;
+ case MVT::f32: return WebAssembly::ValType::F32;
+ case MVT::f64: return WebAssembly::ValType::F64;
+ default: llvm_unreachable("unexpected type");
+ }
+}
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 001bd7f..8583b77 100644
--- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -26,12 +26,13 @@ class MCContext;
class MCInstrInfo;
class MCObjectWriter;
class MCSubtargetInfo;
+class MVT;
class Target;
class Triple;
class raw_pwrite_stream;
-extern Target TheWebAssemblyTarget32;
-extern Target TheWebAssemblyTarget64;
+Target &getTheWebAssemblyTarget32();
+Target &getTheWebAssemblyTarget64();
MCCodeEmitter *createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII);
@@ -44,23 +45,25 @@ namespace WebAssembly {
enum OperandType {
/// Basic block label in a branch construct.
OPERAND_BASIC_BLOCK = MCOI::OPERAND_FIRST_TARGET,
+ /// Local index.
+ OPERAND_LOCAL,
+ /// 32-bit integer immediates.
+ OPERAND_I32IMM,
+ /// 64-bit integer immediates.
+ OPERAND_I64IMM,
/// 32-bit floating-point immediates.
- OPERAND_FP32IMM,
+ OPERAND_F32IMM,
/// 64-bit floating-point immediates.
- OPERAND_FP64IMM,
+ OPERAND_F64IMM,
+ /// 32-bit unsigned function indices.
+ OPERAND_FUNCTION32,
+ /// 32-bit unsigned memory offsets.
+ OPERAND_OFFSET32,
/// p2align immediate for load and store address alignment.
- OPERAND_P2ALIGN
+ OPERAND_P2ALIGN,
+ /// signature immediate for block/loop.
+ OPERAND_SIGNATURE
};
-
-/// WebAssembly-specific directive identifiers.
-enum Directive {
- // FIXME: This is not the real binary encoding.
- DotParam = UINT64_MAX - 0, ///< .param
- DotResult = UINT64_MAX - 1, ///< .result
- DotLocal = UINT64_MAX - 2, ///< .local
- DotEndFunc = UINT64_MAX - 3, ///< .endfunc
-};
-
} // end namespace WebAssembly
namespace WebAssemblyII {
@@ -70,7 +73,7 @@ enum {
VariableOpIsImmediate = (1 << 0),
// For immediate values in the variable_ops range, this flag indicates
// whether the value represents a control-flow label.
- VariableOpImmediateIsLabel = (1 << 1),
+ VariableOpImmediateIsLabel = (1 << 1)
};
} // end namespace WebAssemblyII
@@ -123,14 +126,55 @@ inline unsigned GetDefaultP2Align(unsigned Opcode) {
case WebAssembly::STORE_I64:
case WebAssembly::STORE_F64:
return 3;
- default: llvm_unreachable("Only loads and stores have p2align values");
+ default:
+ llvm_unreachable("Only loads and stores have p2align values");
}
}
/// The operand number of the load or store address in load/store instructions.
-static const unsigned MemOpAddressOperandNo = 2;
-/// The operand number of the stored value in a store instruction.
-static const unsigned StoreValueOperandNo = 4;
+static const unsigned LoadAddressOperandNo = 3;
+static const unsigned StoreAddressOperandNo = 2;
+
+/// The operand number of the load or store p2align in load/store instructions.
+static const unsigned LoadP2AlignOperandNo = 1;
+static const unsigned StoreP2AlignOperandNo = 0;
+
+/// This is used to indicate block signatures.
+enum class ExprType {
+ Void = 0x40,
+ I32 = 0x7f,
+ I64 = 0x7e,
+ F32 = 0x7d,
+ F64 = 0x7c,
+ I8x16 = 0x7b,
+ I16x8 = 0x7a,
+ I32x4 = 0x79,
+ F32x4 = 0x78,
+ B8x16 = 0x77,
+ B16x8 = 0x76,
+ B32x4 = 0x75
+};
+
+/// This is used to indicate local types.
+enum class ValType {
+ I32 = 0x7f,
+ I64 = 0x7e,
+ F32 = 0x7d,
+ F64 = 0x7c,
+ I8x16 = 0x7b,
+ I16x8 = 0x7a,
+ I32x4 = 0x79,
+ F32x4 = 0x78,
+ B8x16 = 0x77,
+ B16x8 = 0x76,
+ B32x4 = 0x75
+};
+
+/// Instruction opcodes emitted via means other than CodeGen.
+static const unsigned Nop = 0x01;
+static const unsigned End = 0x0b;
+
+ValType toValType(const MVT &Ty);
} // end namespace WebAssembly
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index 3d61c15..3cee8b2 100644
--- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -58,45 +58,63 @@ void WebAssemblyTargetAsmStreamer::emitResult(ArrayRef<MVT> Types) {
}
void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> Types) {
- OS << "\t.local \t";
- PrintTypes(OS, Types);
+ if (!Types.empty()) {
+ OS << "\t.local \t";
+ PrintTypes(OS, Types);
+ }
}
void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; }
void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
- StringRef name, SmallVectorImpl<MVT> &SignatureVTs, size_t NumResults) {
+ StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) {
OS << "\t.functype\t" << name;
- if (NumResults == 0) OS << ", void";
- for (auto Ty : SignatureVTs) {
- OS << ", " << WebAssembly::TypeToString(Ty);
+ if (Results.empty())
+ OS << ", void";
+ else {
+ assert(Results.size() == 1);
+ OS << ", " << WebAssembly::TypeToString(Results.front());
}
- OS << "\n";
+ for (auto Ty : Params)
+ OS << ", " << WebAssembly::TypeToString(Ty);
+ OS << '\n';
}
-// FIXME: What follows is not the real binary encoding.
+void WebAssemblyTargetAsmStreamer::emitGlobalImport(StringRef name) {
+ OS << "\t.import_global\t" << name << '\n';
+}
-static void EncodeTypes(MCStreamer &Streamer, ArrayRef<MVT> Types) {
- Streamer.EmitIntValue(Types.size(), sizeof(uint64_t));
- for (MVT Type : Types)
- Streamer.EmitIntValue(Type.SimpleTy, sizeof(uint64_t));
+void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
+ OS << "\t.indidx \t" << *Value << '\n';
}
void WebAssemblyTargetELFStreamer::emitParam(ArrayRef<MVT> Types) {
- Streamer.EmitIntValue(WebAssembly::DotParam, sizeof(uint64_t));
- EncodeTypes(Streamer, Types);
+ // Nothing to emit; params are declared as part of the function signature.
}
void WebAssemblyTargetELFStreamer::emitResult(ArrayRef<MVT> Types) {
- Streamer.EmitIntValue(WebAssembly::DotResult, sizeof(uint64_t));
- EncodeTypes(Streamer, Types);
+ // Nothing to emit; results are declared as part of the function signature.
}
void WebAssemblyTargetELFStreamer::emitLocal(ArrayRef<MVT> Types) {
- Streamer.EmitIntValue(WebAssembly::DotLocal, sizeof(uint64_t));
- EncodeTypes(Streamer, Types);
+ Streamer.EmitULEB128IntValue(Types.size());
+ for (MVT Type : Types)
+ Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1);
}
void WebAssemblyTargetELFStreamer::emitEndFunc() {
- Streamer.EmitIntValue(WebAssembly::DotEndFunc, sizeof(uint64_t));
+ Streamer.EmitIntValue(WebAssembly::End, 1);
+}
+
+void WebAssemblyTargetELFStreamer::emitIndIdx(const MCExpr *Value) {
+ llvm_unreachable(".indidx encoding not yet implemented");
}
+
+void WebAssemblyTargetELFStreamer::emitIndirectFunctionType(
+ StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) {
+ // Nothing to emit here. TODO: Re-design how linking works and re-evaluate
+ // whether it's necessary for .o files to declare indirect function types.
+}
+
+void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) {
+} \ No newline at end of file
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
index 51354ef..23ac319 100644
--- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
+++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
@@ -39,10 +39,14 @@ public:
virtual void emitEndFunc() = 0;
/// .functype
virtual void emitIndirectFunctionType(StringRef name,
- SmallVectorImpl<MVT> &SignatureVTs,
- size_t NumResults) {
+ SmallVectorImpl<MVT> &Params,
+ SmallVectorImpl<MVT> &Results) {
llvm_unreachable("emitIndirectFunctionType not implemented");
}
+ /// .indidx
+ virtual void emitIndIdx(const MCExpr *Value) = 0;
+ /// .import_global
+ virtual void emitGlobalImport(StringRef name) = 0;
};
/// This part is for ascii assembly output
@@ -57,8 +61,10 @@ public:
void emitLocal(ArrayRef<MVT> Types) override;
void emitEndFunc() override;
void emitIndirectFunctionType(StringRef name,
- SmallVectorImpl<MVT> &SignatureVTs,
- size_t NumResults) override;
+ SmallVectorImpl<MVT> &Params,
+ SmallVectorImpl<MVT> &Results) override;
+ void emitIndIdx(const MCExpr *Value) override;
+ void emitGlobalImport(StringRef name) override;
};
/// This part is for ELF object output
@@ -70,6 +76,11 @@ public:
void emitResult(ArrayRef<MVT> Types) override;
void emitLocal(ArrayRef<MVT> Types) override;
void emitEndFunc() override;
+ void emitIndirectFunctionType(StringRef name,
+ SmallVectorImpl<MVT> &Params,
+ SmallVectorImpl<MVT> &Results) override;
+ void emitIndIdx(const MCExpr *Value) override;
+ void emitGlobalImport(StringRef name) override;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/WebAssembly/README.txt b/contrib/llvm/lib/Target/WebAssembly/README.txt
index a6c2eef..64991ad 100644
--- a/contrib/llvm/lib/Target/WebAssembly/README.txt
+++ b/contrib/llvm/lib/Target/WebAssembly/README.txt
@@ -1,22 +1,30 @@
//===-- README.txt - Notes for WebAssembly code gen -----------------------===//
-This WebAssembly backend is presently in a very early stage of development.
-The code should build and not break anything else, but don't expect a lot more
-at this point.
+This WebAssembly backend is presently under development.
-For more information on WebAssembly itself, see the design documents:
- * https://github.com/WebAssembly/design/blob/master/README.md
+Currently the easiest way to use it is through Emscripten, which provides a
+compilation environment that includes standard libraries, tools, and packaging
+for producing WebAssembly applications that can run in browsers and other
+environments. For more information, see the Emscripten documentation in
+general, and this page in particular:
+ * https://github.com/kripken/emscripten/wiki/New-WebAssembly-Backend
-The following documents contain some information on the planned semantics and
-binary encoding of WebAssembly itself:
- * https://github.com/WebAssembly/design/blob/master/AstSemantics.md
+Other ways of using this backend, such as via a standalone "clang", are also
+under development, though they are not generally usable yet.
+
+For more information on WebAssembly itself, see the home page:
+ * https://webassembly.github.io/
+
+The following documents contain some information on the semantics and binary
+encoding of WebAssembly itself:
+ * https://github.com/WebAssembly/design/blob/master/Semantics.md
* https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md
The backend is built, tested and archived on the following waterfall:
https://wasm-stat.us
-The backend's bringup is done using the GCC torture test suite first since it
-doesn't require C library support. Current known failures are in
+The backend's bringup is done in part by using the GCC torture test suite, since
+it doesn't require C library support. Current known failures are in
known_gcc_test_failures.txt, all other tests should pass. The waterfall will
turn red if not. Once most of these pass, further testing will use LLVM's own
test suite. The tests can be run locally using:
@@ -24,13 +32,13 @@ test suite. The tests can be run locally using:
//===---------------------------------------------------------------------===//
-Br, br_if, and br_table instructions can support having a value on the
-expression stack across the jump (sometimes). We should (a) model this, and
-(b) extend the stackifier to utilize it.
+Br, br_if, and br_table instructions can support having a value on the value
+stack across the jump (sometimes). We should (a) model this, and (b) extend
+the stackifier to utilize it.
//===---------------------------------------------------------------------===//
-The min/max operators aren't exactly a<b?a:b because of NaN and negative zero
+The min/max instructions aren't exactly a<b?a:b because of NaN and negative zero
behavior. The ARM target has the same kind of min/max instructions and has
implemented optimizations for them; we should do similar optimizations for
WebAssembly.
@@ -44,7 +52,7 @@ us too?
//===---------------------------------------------------------------------===//
-Register stackification uses the EXPR_STACK physical register to impose
+Register stackification uses the VALUE_STACK physical register to impose
ordering dependencies on instructions with stack operands. This is pessimistic;
we should consider alternate ways to model stack dependencies.
@@ -99,12 +107,6 @@ according to their usage frequency to maximize the usage of smaller encodings.
//===---------------------------------------------------------------------===//
-When the last statement in a function body computes the return value, it can
-just let that value be the exit value of the outermost block, rather than
-needing an explicit return operation.
-
-//===---------------------------------------------------------------------===//
-
Many cases of irreducible control flow could be transformed more optimally
than via the transform in WebAssemblyFixIrreducibleControlFlow.cpp.
@@ -135,3 +137,11 @@ enableMachineScheduler) and determine if it can be configured to schedule
instructions advantageously for this purpose.
//===---------------------------------------------------------------------===//
+
+WebAssembly is now officially a stack machine, rather than an AST, and this
+comes with additional opportunities for WebAssemblyRegStackify. Specifically,
+the stack doesn't need to be empty after an instruction with no return values.
+WebAssemblyRegStackify could be extended, or possibly rewritten, to take
+advantage of the new opportunities.
+
+//===---------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.cpp
index ddb1eb1..f310f0a 100644
--- a/contrib/llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/TargetInfo/WebAssemblyTargetInfo.cpp
@@ -19,12 +19,18 @@ using namespace llvm;
#define DEBUG_TYPE "wasm-target-info"
-Target llvm::TheWebAssemblyTarget32;
-Target llvm::TheWebAssemblyTarget64;
+Target &llvm::getTheWebAssemblyTarget32() {
+ static Target TheWebAssemblyTarget32;
+ return TheWebAssemblyTarget32;
+}
+Target &llvm::getTheWebAssemblyTarget64() {
+ static Target TheWebAssemblyTarget64;
+ return TheWebAssemblyTarget64;
+}
extern "C" void LLVMInitializeWebAssemblyTargetInfo() {
- RegisterTarget<Triple::wasm32> X(TheWebAssemblyTarget32, "wasm32",
+ RegisterTarget<Triple::wasm32> X(getTheWebAssemblyTarget32(), "wasm32",
"WebAssembly 32-bit");
- RegisterTarget<Triple::wasm64> Y(TheWebAssemblyTarget64, "wasm64",
+ RegisterTarget<Triple::wasm64> Y(getTheWebAssemblyTarget64(), "wasm64",
"WebAssembly 64-bit");
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h b/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h
index 957f31c..8738263 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -16,14 +16,19 @@
#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLY_H
#define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLY_H
+#include "llvm/PassRegistry.h"
#include "llvm/Support/CodeGen.h"
namespace llvm {
class WebAssemblyTargetMachine;
+class ModulePass;
class FunctionPass;
// LLVM IR passes.
+ModulePass *createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, bool DoSjLj);
+void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &);
+ModulePass *createWebAssemblyFixFunctionBitcasts();
FunctionPass *createWebAssemblyOptimizeReturned();
// ISel and immediate followup passes.
@@ -39,11 +44,13 @@ FunctionPass *createWebAssemblyOptimizeLiveIntervals();
FunctionPass *createWebAssemblyStoreResults();
FunctionPass *createWebAssemblyRegStackify();
FunctionPass *createWebAssemblyRegColoring();
+FunctionPass *createWebAssemblyExplicitLocals();
FunctionPass *createWebAssemblyFixIrreducibleControlFlow();
FunctionPass *createWebAssemblyCFGStackify();
FunctionPass *createWebAssemblyLowerBrUnless();
FunctionPass *createWebAssemblyRegNumbering();
FunctionPass *createWebAssemblyPeephole();
+FunctionPass *createWebAssemblyCallIndirectFixup();
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssembly.td b/contrib/llvm/lib/Target/WebAssembly/WebAssembly.td
index 551ad93..f647349 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssembly.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssembly.td
@@ -23,7 +23,7 @@ include "llvm/Target/Target.td"
// WebAssembly Subtarget features.
//===----------------------------------------------------------------------===//
-def FeatureSIMD128 : SubtargetFeature<"simd128", "HasSIMD128", "false",
+def FeatureSIMD128 : SubtargetFeature<"simd128", "HasSIMD128", "true",
"Enable 128-bit SIMD">;
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyArgumentMove.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyArgumentMove.cpp
index 5887f45..5fadca3 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyArgumentMove.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyArgumentMove.cpp
@@ -26,9 +26,11 @@
///
//===----------------------------------------------------------------------===//
-#include "WebAssembly.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "WebAssembly.h"
#include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
@@ -44,9 +46,7 @@ public:
static char ID; // Pass identification, replacement for typeid
WebAssemblyArgumentMove() : MachineFunctionPass(ID) {}
- const char *getPassName() const override {
- return "WebAssembly Argument Move";
- }
+ StringRef getPassName() const override { return "WebAssembly Argument Move"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -64,19 +64,6 @@ FunctionPass *llvm::createWebAssemblyArgumentMove() {
return new WebAssemblyArgumentMove();
}
-/// Test whether the given instruction is an ARGUMENT.
-static bool IsArgument(const MachineInstr &MI) {
- switch (MI.getOpcode()) {
- case WebAssembly::ARGUMENT_I32:
- case WebAssembly::ARGUMENT_I64:
- case WebAssembly::ARGUMENT_F32:
- case WebAssembly::ARGUMENT_F64:
- return true;
- default:
- return false;
- }
-}
-
bool WebAssemblyArgumentMove::runOnMachineFunction(MachineFunction &MF) {
DEBUG({
dbgs() << "********** Argument Move **********\n"
@@ -89,7 +76,7 @@ bool WebAssemblyArgumentMove::runOnMachineFunction(MachineFunction &MF) {
// Look for the first NonArg instruction.
for (MachineInstr &MI : EntryMBB) {
- if (!IsArgument(MI)) {
+ if (!WebAssembly::isArgument(MI)) {
InsertPt = MI;
break;
}
@@ -98,7 +85,7 @@ bool WebAssemblyArgumentMove::runOnMachineFunction(MachineFunction &MF) {
// Now move any argument instructions later in the block
// to before our first NonArg instruction.
for (MachineInstr &MI : llvm::make_range(InsertPt, EntryMBB.end())) {
- if (IsArgument(MI)) {
+ if (WebAssembly::isArgument(MI)) {
EntryMBB.insert(InsertPt, MI.removeFromParent());
Changed = true;
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 54e9f7f..5b4b82e 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -14,10 +14,10 @@
///
//===----------------------------------------------------------------------===//
-#include "WebAssembly.h"
#include "InstPrinter/WebAssemblyInstPrinter.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "MCTargetDesc/WebAssemblyTargetStreamer.h"
+#include "WebAssembly.h"
#include "WebAssemblyMCInstLower.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyRegisterInfo.h"
@@ -42,14 +42,14 @@ namespace {
class WebAssemblyAsmPrinter final : public AsmPrinter {
const MachineRegisterInfo *MRI;
- const WebAssemblyFunctionInfo *MFI;
+ WebAssemblyFunctionInfo *MFI;
public:
WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)), MRI(nullptr), MFI(nullptr) {}
private:
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Assembly Printer";
}
@@ -82,7 +82,6 @@ private:
raw_ostream &OS) override;
MVT getRegType(unsigned RegNo) const;
- const char *toString(MVT VT) const;
std::string regToString(const MachineOperand &MO);
WebAssemblyTargetStreamer *getTargetStreamer();
};
@@ -95,7 +94,8 @@ private:
MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
const TargetRegisterClass *TRC = MRI->getRegClass(RegNo);
- for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64})
+ for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16,
+ MVT::v4i32, MVT::v4f32})
if (TRC->hasType(T))
return T;
DEBUG(errs() << "Unknown type for register number: " << RegNo);
@@ -103,10 +103,6 @@ MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const {
return MVT::Other;
}
-const char *WebAssemblyAsmPrinter::toString(MVT VT) const {
- return WebAssembly::TypeToString(VT);
-}
-
std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) {
unsigned RegNo = MO.getReg();
assert(TargetRegisterInfo::isVirtualRegister(RegNo) &&
@@ -125,45 +121,21 @@ WebAssemblyTargetStreamer *WebAssemblyAsmPrinter::getTargetStreamer() {
//===----------------------------------------------------------------------===//
// WebAssemblyAsmPrinter Implementation.
//===----------------------------------------------------------------------===//
-static void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
- Type *Ty, SmallVectorImpl<MVT> &ValueVTs) {
- const DataLayout &DL(F.getParent()->getDataLayout());
- const WebAssemblyTargetLowering &TLI =
- *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering();
- SmallVector<EVT, 4> VTs;
- ComputeValueVTs(TLI, DL, Ty, VTs);
-
- for (EVT VT : VTs) {
- unsigned NumRegs = TLI.getNumRegisters(F.getContext(), VT);
- MVT RegisterVT = TLI.getRegisterType(F.getContext(), VT);
- for (unsigned i = 0; i != NumRegs; ++i)
- ValueVTs.push_back(RegisterVT);
- }
-}
void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
for (const auto &F : M) {
// Emit function type info for all undefined functions
if (F.isDeclarationForLinker() && !F.isIntrinsic()) {
- SmallVector<MVT, 4> SignatureVTs;
- ComputeLegalValueVTs(F, TM, F.getReturnType(), SignatureVTs);
- size_t NumResults = SignatureVTs.size();
- if (SignatureVTs.size() > 1) {
- // WebAssembly currently can't lower returns of multiple values without
- // demoting to sret (see WebAssemblyTargetLowering::CanLowerReturn). So
- // replace multiple return values with a pointer parameter.
- SignatureVTs.clear();
- SignatureVTs.push_back(
- MVT::getIntegerVT(M.getDataLayout().getPointerSizeInBits()));
- NumResults = 0;
- }
-
- for (auto &Arg : F.args()) {
- ComputeLegalValueVTs(F, TM, Arg.getType(), SignatureVTs);
- }
-
- getTargetStreamer()->emitIndirectFunctionType(F.getName(), SignatureVTs,
- NumResults);
+ SmallVector<MVT, 4> Results;
+ SmallVector<MVT, 4> Params;
+ ComputeSignatureVTs(F, TM, Params, Results);
+ getTargetStreamer()->emitIndirectFunctionType(F.getName(), Params,
+ Results);
+ }
+ }
+ for (const auto &G : M.globals()) {
+ if (!G.hasInitializer() && G.hasExternalLinkage()) {
+ getTargetStreamer()->emitGlobalImport(G.getGlobalIdentifier());
}
}
}
@@ -183,6 +155,15 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
SmallVector<MVT, 4> ResultVTs;
const Function &F(*MF->getFunction());
+
+ // Emit the function index.
+ if (MDNode *Idx = F.getMetadata("wasm.index")) {
+ assert(Idx->getNumOperands() == 1);
+
+ getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
+ cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
+ }
+
ComputeLegalValueVTs(F, TM, F.getReturnType(), ResultVTs);
// If the return type needs to be legalized it will get converted into
@@ -190,8 +171,8 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
if (ResultVTs.size() == 1)
getTargetStreamer()->emitResult(ResultVTs);
- bool AnyWARegs = false;
- SmallVector<MVT, 16> LocalTypes;
+ // FIXME: When ExplicitLocals is enabled by default, we won't need
+ // to define the locals here (and MFI can go back to being pointer-to-const).
for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
unsigned WAReg = MFI->getWAReg(VReg);
@@ -204,11 +185,10 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
// Don't declare stackified registers.
if (int(WAReg) < 0)
continue;
- LocalTypes.push_back(getRegType(VReg));
- AnyWARegs = true;
+ MFI->addLocal(getRegType(VReg));
}
- if (AnyWARegs)
- getTargetStreamer()->emitLocal(LocalTypes);
+
+ getTargetStreamer()->emitLocal(MFI->getLocals());
AsmPrinter::EmitFunctionBodyStart();
}
@@ -225,13 +205,21 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
case WebAssembly::ARGUMENT_I64:
case WebAssembly::ARGUMENT_F32:
case WebAssembly::ARGUMENT_F64:
+ case WebAssembly::ARGUMENT_v16i8:
+ case WebAssembly::ARGUMENT_v8i16:
+ case WebAssembly::ARGUMENT_v4i32:
+ case WebAssembly::ARGUMENT_v4f32:
// These represent values which are live into the function entry, so there's
// no instruction to emit.
break;
case WebAssembly::FALLTHROUGH_RETURN_I32:
case WebAssembly::FALLTHROUGH_RETURN_I64:
case WebAssembly::FALLTHROUGH_RETURN_F32:
- case WebAssembly::FALLTHROUGH_RETURN_F64: {
+ case WebAssembly::FALLTHROUGH_RETURN_F64:
+ case WebAssembly::FALLTHROUGH_RETURN_v16i8:
+ case WebAssembly::FALLTHROUGH_RETURN_v8i16:
+ case WebAssembly::FALLTHROUGH_RETURN_v4i32:
+ case WebAssembly::FALLTHROUGH_RETURN_v4f32: {
// These instructions represent the implicit return at the end of a
// function body. The operand is always a pop.
assert(MFI->isVRegStackified(MI->getOperand(0).getReg()));
@@ -329,6 +317,6 @@ bool WebAssemblyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
// Force static initialization.
extern "C" void LLVMInitializeWebAssemblyAsmPrinter() {
- RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32);
- RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64);
+ RegisterAsmPrinter<WebAssemblyAsmPrinter> X(getTheWebAssemblyTarget32());
+ RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(getTheWebAssemblyTarget64());
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 33166f5..49b9754 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -27,6 +27,7 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/ADT/PriorityQueue.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/CodeGen/MachineDominators.h"
@@ -43,9 +44,7 @@ using namespace llvm;
namespace {
class WebAssemblyCFGStackify final : public MachineFunctionPass {
- const char *getPassName() const override {
- return "WebAssembly CFG Stackify";
- }
+ StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -294,26 +293,16 @@ static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,
return false;
}
-/// Test whether MI is a child of some other node in an expression tree.
-static bool IsChild(const MachineInstr &MI,
- const WebAssemblyFunctionInfo &MFI) {
- if (MI.getNumOperands() == 0)
- return false;
- const MachineOperand &MO = MI.getOperand(0);
- if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
- return false;
- unsigned Reg = MO.getReg();
- return TargetRegisterInfo::isVirtualRegister(Reg) &&
- MFI.isVRegStackified(Reg);
-}
-
/// Insert a BLOCK marker for branches to MBB (if needed).
-static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
- SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
- const WebAssemblyInstrInfo &TII,
- const MachineLoopInfo &MLI,
- MachineDominatorTree &MDT,
- WebAssemblyFunctionInfo &MFI) {
+static void PlaceBlockMarker(
+ MachineBasicBlock &MBB, MachineFunction &MF,
+ SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
+ DenseMap<const MachineInstr *, MachineInstr *> &BlockTops,
+ DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,
+ const WebAssemblyInstrInfo &TII,
+ const MachineLoopInfo &MLI,
+ MachineDominatorTree &MDT,
+ WebAssemblyFunctionInfo &MFI) {
// First compute the nearest common dominator of all forward non-fallthrough
// predecessors so that we minimize the time that the BLOCK is on the stack,
// which reduces overall stack height.
@@ -332,7 +321,7 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
return;
assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
- MachineBasicBlock *LayoutPred = &*prev(MachineFunction::iterator(&MBB));
+ MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB));
// If the nearest common dominator is inside a more deeply nested context,
// walk out to the nearest scope which isn't more deeply nested.
@@ -340,7 +329,7 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
if (ScopeTop->getNumber() > Header->getNumber()) {
// Skip over an intervening scope.
- I = next(MachineFunction::iterator(ScopeTop));
+ I = std::next(MachineFunction::iterator(ScopeTop));
} else {
// We found a scope level at an appropriate depth.
Header = ScopeTop;
@@ -349,13 +338,6 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
}
}
- // If there's a loop which ends just before MBB which contains Header, we can
- // reuse its label instead of inserting a new BLOCK.
- for (MachineLoop *Loop = MLI.getLoopFor(LayoutPred);
- Loop && Loop->contains(LayoutPred); Loop = Loop->getParentLoop())
- if (Loop && LoopBottom(Loop) == LayoutPred && Loop->contains(Header))
- return;
-
// Decide where in Header to put the BLOCK.
MachineBasicBlock::iterator InsertPos;
MachineLoop *HeaderLoop = MLI.getLoopFor(Header);
@@ -363,28 +345,35 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
// Header is the header of a loop that does not lexically contain MBB, so
// the BLOCK needs to be above the LOOP, after any END constructs.
InsertPos = Header->begin();
- while (InsertPos->getOpcode() != WebAssembly::LOOP)
+ while (InsertPos->getOpcode() == WebAssembly::END_BLOCK ||
+ InsertPos->getOpcode() == WebAssembly::END_LOOP)
++InsertPos;
} else {
// Otherwise, insert the BLOCK as late in Header as we can, but before the
// beginning of the local expression tree and any nested BLOCKs.
InsertPos = Header->getFirstTerminator();
- while (InsertPos != Header->begin() && IsChild(*prev(InsertPos), MFI) &&
- prev(InsertPos)->getOpcode() != WebAssembly::LOOP &&
- prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK &&
- prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP)
+ while (InsertPos != Header->begin() &&
+ WebAssembly::isChild(*std::prev(InsertPos), MFI) &&
+ std::prev(InsertPos)->getOpcode() != WebAssembly::LOOP &&
+ std::prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK &&
+ std::prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP)
--InsertPos;
}
// Add the BLOCK.
- BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK));
+ MachineInstr *Begin = BuildMI(*Header, InsertPos, DebugLoc(),
+ TII.get(WebAssembly::BLOCK))
+ .addImm(int64_t(WebAssembly::ExprType::Void));
// Mark the end of the block.
InsertPos = MBB.begin();
while (InsertPos != MBB.end() &&
- InsertPos->getOpcode() == WebAssembly::END_LOOP)
+ InsertPos->getOpcode() == WebAssembly::END_LOOP &&
+ LoopTops[&*InsertPos]->getParent()->getNumber() >= Header->getNumber())
++InsertPos;
- BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::END_BLOCK));
+ MachineInstr *End = BuildMI(MBB, InsertPos, DebugLoc(),
+ TII.get(WebAssembly::END_BLOCK));
+ BlockTops[End] = Begin;
// Track the farthest-spanning scope that ends at this point.
int Number = MBB.getNumber();
@@ -397,7 +386,7 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,
static void PlaceLoopMarker(
MachineBasicBlock &MBB, MachineFunction &MF,
SmallVectorImpl<MachineBasicBlock *> &ScopeTops,
- DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops,
+ DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,
const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) {
MachineLoop *Loop = MLI.getLoopFor(&MBB);
if (!Loop || Loop->getHeader() != &MBB)
@@ -406,13 +395,13 @@ static void PlaceLoopMarker(
// The operand of a LOOP is the first block after the loop. If the loop is the
// bottom of the function, insert a dummy block at the end.
MachineBasicBlock *Bottom = LoopBottom(Loop);
- auto Iter = next(MachineFunction::iterator(Bottom));
+ auto Iter = std::next(MachineFunction::iterator(Bottom));
if (Iter == MF.end()) {
MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
// Give it a fake predecessor so that AsmPrinter prints its label.
Label->addSuccessor(Label);
MF.push_back(Label);
- Iter = next(MachineFunction::iterator(Bottom));
+ Iter = std::next(MachineFunction::iterator(Bottom));
}
MachineBasicBlock *AfterLoop = &*Iter;
@@ -422,12 +411,14 @@ static void PlaceLoopMarker(
while (InsertPos != MBB.end() &&
InsertPos->getOpcode() == WebAssembly::END_LOOP)
++InsertPos;
- BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::LOOP));
+ MachineInstr *Begin = BuildMI(MBB, InsertPos, DebugLoc(),
+ TII.get(WebAssembly::LOOP))
+ .addImm(int64_t(WebAssembly::ExprType::Void));
// Mark the end of the loop.
MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(),
TII.get(WebAssembly::END_LOOP));
- LoopTops[End] = &MBB;
+ LoopTops[End] = Begin;
assert((!ScopeTops[AfterLoop->getNumber()] ||
ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
@@ -449,6 +440,54 @@ GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
return Depth;
}
+/// In normal assembly languages, when the end of a function is unreachable,
+/// because the function ends in an infinite loop or a noreturn call or similar,
+/// it isn't necessary to worry about the function return type at the end of
+/// the function, because it's never reached. However, in WebAssembly, blocks
+/// that end at the function end need to have a return type signature that
+/// matches the function signature, even though it's unreachable. This function
+/// checks for such cases and fixes up the signatures.
+static void FixEndsAtEndOfFunction(
+ MachineFunction &MF,
+ const WebAssemblyFunctionInfo &MFI,
+ DenseMap<const MachineInstr *, MachineInstr *> &BlockTops,
+ DenseMap<const MachineInstr *, MachineInstr *> &LoopTops) {
+ assert(MFI.getResults().size() <= 1);
+
+ if (MFI.getResults().empty())
+ return;
+
+ WebAssembly::ExprType retType;
+ switch (MFI.getResults().front().SimpleTy) {
+ case MVT::i32: retType = WebAssembly::ExprType::I32; break;
+ case MVT::i64: retType = WebAssembly::ExprType::I64; break;
+ case MVT::f32: retType = WebAssembly::ExprType::F32; break;
+ case MVT::f64: retType = WebAssembly::ExprType::F64; break;
+ case MVT::v16i8: retType = WebAssembly::ExprType::I8x16; break;
+ case MVT::v8i16: retType = WebAssembly::ExprType::I16x8; break;
+ case MVT::v4i32: retType = WebAssembly::ExprType::I32x4; break;
+ case MVT::v4f32: retType = WebAssembly::ExprType::F32x4; break;
+ default: llvm_unreachable("unexpected return type");
+ }
+
+ for (MachineBasicBlock &MBB : reverse(MF)) {
+ for (MachineInstr &MI : reverse(MBB)) {
+ if (MI.isPosition() || MI.isDebugValue())
+ continue;
+ if (MI.getOpcode() == WebAssembly::END_BLOCK) {
+ BlockTops[&MI]->getOperand(0).setImm(int32_t(retType));
+ continue;
+ }
+ if (MI.getOpcode() == WebAssembly::END_LOOP) {
+ LoopTops[&MI]->getOperand(0).setImm(int32_t(retType));
+ continue;
+ }
+ // Something other than an `end`. We're done.
+ return;
+ }
+ }
+}
+
/// Insert LOOP and BLOCK markers at appropriate places.
static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
const WebAssemblyInstrInfo &TII,
@@ -461,15 +500,18 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
// we may insert at the end.
SmallVector<MachineBasicBlock *, 8> ScopeTops(MF.getNumBlockIDs() + 1);
- // For eacn LOOP_END, the corresponding LOOP.
- DenseMap<const MachineInstr *, const MachineBasicBlock *> LoopTops;
+ // For each LOOP_END, the corresponding LOOP.
+ DenseMap<const MachineInstr *, MachineInstr *> LoopTops;
+
+ // For each END_BLOCK, the corresponding BLOCK.
+ DenseMap<const MachineInstr *, MachineInstr *> BlockTops;
for (auto &MBB : MF) {
// Place the LOOP for MBB if MBB is the header of a loop.
PlaceLoopMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI);
// Place the BLOCK for MBB if MBB is branched to from above.
- PlaceBlockMarker(MBB, MF, ScopeTops, TII, MLI, MDT, MFI);
+ PlaceBlockMarker(MBB, MF, ScopeTops, BlockTops, LoopTops, TII, MLI, MDT, MFI);
}
// Now rewrite references to basic blocks to be depth immediates.
@@ -478,21 +520,19 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
for (auto &MI : reverse(MBB)) {
switch (MI.getOpcode()) {
case WebAssembly::BLOCK:
- assert(ScopeTops[Stack.back()->getNumber()] == &MBB &&
+ assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= MBB.getNumber() &&
"Block should be balanced");
Stack.pop_back();
break;
case WebAssembly::LOOP:
assert(Stack.back() == &MBB && "Loop top should be balanced");
Stack.pop_back();
- Stack.pop_back();
break;
case WebAssembly::END_BLOCK:
Stack.push_back(&MBB);
break;
case WebAssembly::END_LOOP:
- Stack.push_back(&MBB);
- Stack.push_back(LoopTops[&MI]);
+ Stack.push_back(LoopTops[&MI]->getParent());
break;
default:
if (MI.isTerminator()) {
@@ -511,6 +551,10 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
}
}
assert(Stack.empty() && "Control flow should be balanced");
+
+ // Fix up block/loop signatures at the end of the function to conform to
+ // WebAssembly's rules.
+ FixEndsAtEndOfFunction(MF, MFI, BlockTops, LoopTops);
}
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
@@ -520,7 +564,7 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
const auto &MLI = getAnalysis<MachineLoopInfo>();
auto &MDT = getAnalysis<MachineDominatorTree>();
- // Liveness is not tracked for EXPR_STACK physreg.
+ // Liveness is not tracked for VALUE_STACK physreg.
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
MF.getRegInfo().invalidateLiveness();
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
new file mode 100644
index 0000000..fc0a01c
--- /dev/null
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
@@ -0,0 +1,120 @@
+//===-- WebAssemblyCallIndirectFixup.cpp - Fix call_indirects -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file converts pseudo call_indirect instructions into real
+/// call_indirects.
+///
+/// The order of arguments for a call_indirect is the arguments to the function
+/// call, followed by the function pointer. There's no natural way to express
+/// a machineinstr with varargs followed by one more arg, so we express it as
+/// the function pointer followed by varargs, then rewrite it here.
+///
+/// We need to rewrite the order of the arguments on the machineinstrs
+/// themselves so that register stackification knows the order they'll be
+/// executed in.
+///
+//===----------------------------------------------------------------------===//
+
+#include "WebAssembly.h"
+#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_*
+#include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblySubtarget.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-call-indirect-fixup"
+
+namespace {
+class WebAssemblyCallIndirectFixup final : public MachineFunctionPass {
+ StringRef getPassName() const override {
+ return "WebAssembly CallIndirect Fixup";
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+public:
+ static char ID; // Pass identification, replacement for typeid
+ WebAssemblyCallIndirectFixup() : MachineFunctionPass(ID) {}
+};
+} // end anonymous namespace
+
+char WebAssemblyCallIndirectFixup::ID = 0;
+FunctionPass *llvm::createWebAssemblyCallIndirectFixup() {
+ return new WebAssemblyCallIndirectFixup();
+}
+
+static unsigned GetNonPseudoCallIndirectOpcode(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ using namespace WebAssembly;
+ case PCALL_INDIRECT_VOID: return CALL_INDIRECT_VOID;
+ case PCALL_INDIRECT_I32: return CALL_INDIRECT_I32;
+ case PCALL_INDIRECT_I64: return CALL_INDIRECT_I64;
+ case PCALL_INDIRECT_F32: return CALL_INDIRECT_F32;
+ case PCALL_INDIRECT_F64: return CALL_INDIRECT_F64;
+ case PCALL_INDIRECT_v16i8: return CALL_INDIRECT_v16i8;
+ case PCALL_INDIRECT_v8i16: return CALL_INDIRECT_v8i16;
+ case PCALL_INDIRECT_v4i32: return CALL_INDIRECT_v4i32;
+ case PCALL_INDIRECT_v4f32: return CALL_INDIRECT_v4f32;
+ default: return INSTRUCTION_LIST_END;
+ }
+}
+
+static bool IsPseudoCallIndirect(const MachineInstr &MI) {
+ return GetNonPseudoCallIndirectOpcode(MI) !=
+ WebAssembly::INSTRUCTION_LIST_END;
+}
+
+bool WebAssemblyCallIndirectFixup::runOnMachineFunction(MachineFunction &MF) {
+ DEBUG(dbgs() << "********** Fixing up CALL_INDIRECTs **********\n"
+ << MF.getName() << '\n');
+
+ bool Changed = false;
+ const WebAssemblyInstrInfo *TII =
+ MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+
+ for (MachineBasicBlock &MBB : MF) {
+ for (MachineInstr &MI : MBB) {
+ if (IsPseudoCallIndirect(MI)) {
+ DEBUG(dbgs() << "Found call_indirect: " << MI << '\n');
+
+ // Rewrite pseudo to non-pseudo
+ const MCInstrDesc &Desc = TII->get(GetNonPseudoCallIndirectOpcode(MI));
+ MI.setDesc(Desc);
+
+ // Rewrite argument order
+ auto Uses = MI.explicit_uses();
+ MachineInstr::mop_iterator it = Uses.begin();
+ const MachineOperand MO = *it;
+
+ // Set up the flags immediate, which currently has no defined flags
+ // so it's always zero.
+ it->ChangeToImmediate(0);
+
+ MI.addOperand(MF, MO);
+
+ DEBUG(dbgs() << " After transform: " << MI);
+ Changed = true;
+ }
+ }
+ }
+
+ DEBUG(dbgs() << "\nDone fixing up CALL_INDIRECTs\n\n");
+
+ return Changed;
+}
+
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
new file mode 100644
index 0000000..04ede7f
--- /dev/null
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
@@ -0,0 +1,308 @@
+//===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file converts any remaining registers into WebAssembly locals.
+///
+/// After register stackification and register coloring, convert non-stackified
+/// registers into locals, inserting explicit get_local and set_local
+/// instructions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "WebAssembly.h"
+#include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
+#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-explicit-locals"
+
+namespace {
+class WebAssemblyExplicitLocals final : public MachineFunctionPass {
+ StringRef getPassName() const override {
+ return "WebAssembly Explicit Locals";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ AU.addPreserved<MachineBlockFrequencyInfo>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+public:
+ static char ID; // Pass identification, replacement for typeid
+ WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
+};
+} // end anonymous namespace
+
+char WebAssemblyExplicitLocals::ID = 0;
+FunctionPass *llvm::createWebAssemblyExplicitLocals() {
+ return new WebAssemblyExplicitLocals();
+}
+
+/// Return a local id number for the given register, assigning it a new one
+/// if it doesn't yet have one.
+static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
+ unsigned &CurLocal, unsigned Reg) {
+ return Reg2Local.insert(std::make_pair(Reg, CurLocal++)).first->second;
+}
+
+/// Get the appropriate get_local opcode for the given register class.
+static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
+ if (RC == &WebAssembly::I32RegClass)
+ return WebAssembly::GET_LOCAL_I32;
+ if (RC == &WebAssembly::I64RegClass)
+ return WebAssembly::GET_LOCAL_I64;
+ if (RC == &WebAssembly::F32RegClass)
+ return WebAssembly::GET_LOCAL_F32;
+ if (RC == &WebAssembly::F64RegClass)
+ return WebAssembly::GET_LOCAL_F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return WebAssembly::GET_LOCAL_V128;
+ llvm_unreachable("Unexpected register class");
+}
+
+/// Get the appropriate set_local opcode for the given register class.
+static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
+ if (RC == &WebAssembly::I32RegClass)
+ return WebAssembly::SET_LOCAL_I32;
+ if (RC == &WebAssembly::I64RegClass)
+ return WebAssembly::SET_LOCAL_I64;
+ if (RC == &WebAssembly::F32RegClass)
+ return WebAssembly::SET_LOCAL_F32;
+ if (RC == &WebAssembly::F64RegClass)
+ return WebAssembly::SET_LOCAL_F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return WebAssembly::SET_LOCAL_V128;
+ llvm_unreachable("Unexpected register class");
+}
+
+/// Get the appropriate tee_local opcode for the given register class.
+static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
+ if (RC == &WebAssembly::I32RegClass)
+ return WebAssembly::TEE_LOCAL_I32;
+ if (RC == &WebAssembly::I64RegClass)
+ return WebAssembly::TEE_LOCAL_I64;
+ if (RC == &WebAssembly::F32RegClass)
+ return WebAssembly::TEE_LOCAL_F32;
+ if (RC == &WebAssembly::F64RegClass)
+ return WebAssembly::TEE_LOCAL_F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return WebAssembly::TEE_LOCAL_V128;
+ llvm_unreachable("Unexpected register class");
+}
+
+/// Get the type associated with the given register class.
+static MVT typeForRegClass(const TargetRegisterClass *RC) {
+ if (RC == &WebAssembly::I32RegClass)
+ return MVT::i32;
+ if (RC == &WebAssembly::I64RegClass)
+ return MVT::i64;
+ if (RC == &WebAssembly::F32RegClass)
+ return MVT::f32;
+ if (RC == &WebAssembly::F64RegClass)
+ return MVT::f64;
+ llvm_unreachable("unrecognized register class");
+}
+
+/// Given a MachineOperand of a stackified vreg, return the instruction at the
+/// start of the expression tree.
+static MachineInstr *FindStartOfTree(MachineOperand &MO,
+ MachineRegisterInfo &MRI,
+ WebAssemblyFunctionInfo &MFI) {
+ unsigned Reg = MO.getReg();
+ assert(MFI.isVRegStackified(Reg));
+ MachineInstr *Def = MRI.getVRegDef(Reg);
+
+ // Find the first stackified use and proceed from there.
+ for (MachineOperand &DefMO : Def->explicit_uses()) {
+ if (!DefMO.isReg())
+ continue;
+ return FindStartOfTree(DefMO, MRI, MFI);
+ }
+
+ // If there were no stackified uses, we've reached the start.
+ return Def;
+}
+
+bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
+ DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
+ "********** Function: "
+ << MF.getName() << '\n');
+
+ // Disable this pass if we aren't doing direct wasm object emission.
+ if (MF.getSubtarget<WebAssemblySubtarget>()
+ .getTargetTriple().isOSBinFormatELF())
+ return false;
+
+ bool Changed = false;
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
+ const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+
+ // Map non-stackified virtual registers to their local ids.
+ DenseMap<unsigned, unsigned> Reg2Local;
+
+ // Handle ARGUMENTS first to ensure that they get the designated numbers.
+ for (MachineBasicBlock::iterator I = MF.begin()->begin(),
+ E = MF.begin()->end();
+ I != E;) {
+ MachineInstr &MI = *I++;
+ if (!WebAssembly::isArgument(MI))
+ break;
+ unsigned Reg = MI.getOperand(0).getReg();
+ assert(!MFI.isVRegStackified(Reg));
+ Reg2Local[Reg] = MI.getOperand(1).getImm();
+ MI.eraseFromParent();
+ Changed = true;
+ }
+
+ // Start assigning local numbers after the last parameter.
+ unsigned CurLocal = MFI.getParams().size();
+
+ // Visit each instruction in the function.
+ for (MachineBasicBlock &MBB : MF) {
+ for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
+ MachineInstr &MI = *I++;
+ assert(!WebAssembly::isArgument(MI));
+
+ if (MI.isDebugValue() || MI.isLabel())
+ continue;
+
+ // Replace tee instructions with tee_local. The difference is that tee
+ // instructins have two defs, while tee_local instructions have one def
+ // and an index of a local to write to.
+ if (WebAssembly::isTee(MI)) {
+ assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
+ assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
+ unsigned OldReg = MI.getOperand(2).getReg();
+ const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
+
+ // Stackify the input if it isn't stackified yet.
+ if (!MFI.isVRegStackified(OldReg)) {
+ unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+ unsigned NewReg = MRI.createVirtualRegister(RC);
+ unsigned Opc = getGetLocalOpcode(RC);
+ BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
+ .addImm(LocalId);
+ MI.getOperand(2).setReg(NewReg);
+ MFI.stackifyVReg(NewReg);
+ }
+
+ // Replace the TEE with a TEE_LOCAL.
+ unsigned LocalId =
+ getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
+ unsigned Opc = getTeeLocalOpcode(RC);
+ BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
+ MI.getOperand(0).getReg())
+ .addImm(LocalId)
+ .addReg(MI.getOperand(2).getReg());
+
+ MI.eraseFromParent();
+ Changed = true;
+ continue;
+ }
+
+ // Insert set_locals for any defs that aren't stackified yet. Currently
+ // we handle at most one def.
+ assert(MI.getDesc().getNumDefs() <= 1);
+ if (MI.getDesc().getNumDefs() == 1) {
+ unsigned OldReg = MI.getOperand(0).getReg();
+ if (!MFI.isVRegStackified(OldReg) && !MRI.use_empty(OldReg)) {
+ unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+ const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
+ unsigned NewReg = MRI.createVirtualRegister(RC);
+ auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
+ unsigned Opc = getSetLocalOpcode(RC);
+ BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
+ .addImm(LocalId)
+ .addReg(NewReg);
+ MI.getOperand(0).setReg(NewReg);
+ MFI.stackifyVReg(NewReg);
+ Changed = true;
+ }
+ }
+
+ // Insert get_locals for any uses that aren't stackified yet.
+ MachineInstr *InsertPt = &MI;
+ for (MachineOperand &MO : reverse(MI.explicit_uses())) {
+ if (!MO.isReg())
+ continue;
+
+ unsigned OldReg = MO.getReg();
+
+ // If we see a stackified register, prepare to insert subsequent
+ // get_locals before the start of its tree.
+ if (MFI.isVRegStackified(OldReg)) {
+ InsertPt = FindStartOfTree(MO, MRI, MFI);
+ continue;
+ }
+
+ // Insert a get_local.
+ unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+ const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
+ unsigned NewReg = MRI.createVirtualRegister(RC);
+ unsigned Opc = getGetLocalOpcode(RC);
+ InsertPt =
+ BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
+ .addImm(LocalId);
+ MO.setReg(NewReg);
+ MFI.stackifyVReg(NewReg);
+ Changed = true;
+ }
+
+ // Coalesce and eliminate COPY instructions.
+ if (WebAssembly::isCopy(MI)) {
+ MRI.replaceRegWith(MI.getOperand(1).getReg(),
+ MI.getOperand(0).getReg());
+ MI.eraseFromParent();
+ Changed = true;
+ }
+ }
+ }
+
+ // Define the locals.
+ for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
+ unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
+ auto I = Reg2Local.find(Reg);
+ if (I == Reg2Local.end() || I->second < MFI.getParams().size())
+ continue;
+
+ MFI.addLocal(typeForRegClass(MRI.getRegClass(Reg)));
+ Changed = true;
+ }
+
+#ifndef NDEBUG
+ // Assert that all registers have been stackified at this point.
+ for (const MachineBasicBlock &MBB : MF) {
+ for (const MachineInstr &MI : MBB) {
+ if (MI.isDebugValue() || MI.isLabel())
+ continue;
+ for (const MachineOperand &MO : MI.explicit_operands()) {
+ assert(
+ (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
+ MFI.isVRegStackified(MO.getReg())) &&
+ "WebAssemblyExplicitLocals failed to stackify a register operand");
+ }
+ }
+ }
+#endif
+
+ return Changed;
+}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
index 7bfa407..bc7020f 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
@@ -84,7 +84,10 @@ class WebAssemblyFastISel final : public FastISel {
return Base.FI;
}
- void setOffset(int64_t Offset_) { Offset = Offset_; }
+ void setOffset(int64_t Offset_) {
+ assert(Offset_ >= 0 && "Offsets must be non-negative");
+ Offset = Offset_;
+ }
int64_t getOffset() const { return Offset; }
void setGlobalValue(const GlobalValue *G) { GV = G; }
const GlobalValue *getGlobalValue() const { return GV; }
@@ -113,6 +116,13 @@ private:
case MVT::f32:
case MVT::f64:
return VT;
+ case MVT::v16i8:
+ case MVT::v8i16:
+ case MVT::v4i32:
+ case MVT::v4f32:
+ if (Subtarget->hasSIMD128())
+ return VT;
+ break;
default:
break;
}
@@ -229,12 +239,15 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
case Instruction::GetElementPtr: {
Address SavedAddr = Addr;
uint64_t TmpOffset = Addr.getOffset();
+ // Non-inbounds geps can wrap; wasm's offsets can't.
+ if (!cast<GEPOperator>(U)->isInBounds())
+ goto unsupported_gep;
// Iterate through the GEP folding the constants into offsets where
// we can.
for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
GTI != E; ++GTI) {
const Value *Op = GTI.getOperand();
- if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
@@ -265,10 +278,13 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
}
}
}
- // Try to grab the base operand now.
- Addr.setOffset(TmpOffset);
- if (computeAddress(U->getOperand(0), Addr))
- return true;
+ // Don't fold in negative offsets.
+ if (int64_t(TmpOffset) >= 0) {
+ // Try to grab the base operand now.
+ Addr.setOffset(TmpOffset);
+ if (computeAddress(U->getOperand(0), Addr))
+ return true;
+ }
// We failed, restore everything and try the other options.
Addr = SavedAddr;
unsupported_gep:
@@ -294,8 +310,11 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
std::swap(LHS, RHS);
if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
- Addr.setOffset(Addr.getOffset() + CI->getSExtValue());
- return computeAddress(LHS, Addr);
+ uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
+ if (int64_t(TmpOffset) >= 0) {
+ Addr.setOffset(TmpOffset);
+ return computeAddress(LHS, Addr);
+ }
}
Address Backup = Addr;
@@ -311,8 +330,11 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
const Value *RHS = U->getOperand(1);
if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
- Addr.setOffset(Addr.getOffset() - CI->getSExtValue());
- return computeAddress(LHS, Addr);
+ int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
+ if (TmpOffset >= 0) {
+ Addr.setOffset(TmpOffset);
+ return computeAddress(LHS, Addr);
+ }
}
break;
}
@@ -341,6 +363,10 @@ void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
const MachineInstrBuilder &MIB,
MachineMemOperand *MMO) {
+ // Set the alignment operand (this is rewritten in SetP2AlignOperands).
+ // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
+ MIB.addImm(0);
+
if (const GlobalValue *GV = Addr.getGlobalValue())
MIB.addGlobalAddress(GV, Addr.getOffset());
else
@@ -351,10 +377,6 @@ void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
else
MIB.addFrameIndex(Addr.getFI());
- // Set the alignment operand (this is rewritten in SetP2AlignOperands).
- // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
- MIB.addImm(0);
-
MIB.addMemOperand(MMO);
}
@@ -381,6 +403,9 @@ unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
MVT::SimpleValueType From) {
+ if (Reg == 0)
+ return 0;
+
switch (From) {
case MVT::i1:
// If the value is naturally an i1, we don't need to mask it.
@@ -415,6 +440,9 @@ unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
MVT::SimpleValueType From) {
+ if (Reg == 0)
+ return 0;
+
switch (From) {
case MVT::i1:
case MVT::i8:
@@ -529,8 +557,8 @@ unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
&WebAssembly::I64RegClass :
&WebAssembly::I32RegClass);
unsigned Opc = Subtarget->hasAddr64() ?
- WebAssembly::COPY_LOCAL_I64 :
- WebAssembly::COPY_LOCAL_I32;
+ WebAssembly::COPY_I64 :
+ WebAssembly::COPY_I32;
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
.addFrameIndex(SI->second);
return ResultReg;
@@ -575,7 +603,9 @@ bool WebAssemblyFastISel::fastLowerArguments() {
return false;
Type *ArgTy = Arg.getType();
- if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy())
+ if (ArgTy->isStructTy() || ArgTy->isArrayTy())
+ return false;
+ if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
return false;
unsigned Opc;
@@ -600,6 +630,22 @@ bool WebAssemblyFastISel::fastLowerArguments() {
Opc = WebAssembly::ARGUMENT_F64;
RC = &WebAssembly::F64RegClass;
break;
+ case MVT::v16i8:
+ Opc = WebAssembly::ARGUMENT_v16i8;
+ RC = &WebAssembly::V128RegClass;
+ break;
+ case MVT::v8i16:
+ Opc = WebAssembly::ARGUMENT_v8i16;
+ RC = &WebAssembly::V128RegClass;
+ break;
+ case MVT::v4i32:
+ Opc = WebAssembly::ARGUMENT_v4i32;
+ RC = &WebAssembly::V128RegClass;
+ break;
+ case MVT::v4f32:
+ Opc = WebAssembly::ARGUMENT_v4f32;
+ RC = &WebAssembly::V128RegClass;
+ break;
default:
return false;
}
@@ -617,6 +663,9 @@ bool WebAssemblyFastISel::fastLowerArguments() {
for (auto const &Arg : F->args())
MFI->addParam(getLegalType(getSimpleType(Arg.getType())));
+ if (!F->getReturnType()->isVoidTy())
+ MFI->addResult(getLegalType(getSimpleType(F->getReturnType())));
+
return true;
}
@@ -637,29 +686,52 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
bool IsVoid = FuncTy->getReturnType()->isVoidTy();
unsigned ResultReg;
if (IsVoid) {
- Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::CALL_INDIRECT_VOID;
+ Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
} else {
+ if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
+ return false;
+
MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
switch (RetTy) {
case MVT::i1:
case MVT::i8:
case MVT::i16:
case MVT::i32:
- Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::CALL_INDIRECT_I32;
+ Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
ResultReg = createResultReg(&WebAssembly::I32RegClass);
break;
case MVT::i64:
- Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::CALL_INDIRECT_I64;
+ Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
ResultReg = createResultReg(&WebAssembly::I64RegClass);
break;
case MVT::f32:
- Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::CALL_INDIRECT_F32;
+ Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
ResultReg = createResultReg(&WebAssembly::F32RegClass);
break;
case MVT::f64:
- Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::CALL_INDIRECT_F64;
+ Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
ResultReg = createResultReg(&WebAssembly::F64RegClass);
break;
+ case MVT::v16i8:
+ Opc =
+ IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8;
+ ResultReg = createResultReg(&WebAssembly::V128RegClass);
+ break;
+ case MVT::v8i16:
+ Opc =
+ IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16;
+ ResultReg = createResultReg(&WebAssembly::V128RegClass);
+ break;
+ case MVT::v4i32:
+ Opc =
+ IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32;
+ ResultReg = createResultReg(&WebAssembly::V128RegClass);
+ break;
+ case MVT::v4f32:
+ Opc =
+ IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32;
+ ResultReg = createResultReg(&WebAssembly::V128RegClass);
+ break;
default:
return false;
}
@@ -972,6 +1044,8 @@ bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
const LoadInst *Load = cast<LoadInst>(I);
if (Load->isAtomic())
return false;
+ if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
+ return false;
Address Addr;
if (!computeAddress(Load->getPointerOperand(), Addr))
@@ -1027,40 +1101,36 @@ bool WebAssemblyFastISel::selectStore(const Instruction *I) {
const StoreInst *Store = cast<StoreInst>(I);
if (Store->isAtomic())
return false;
+ if (!Subtarget->hasSIMD128() &&
+ Store->getValueOperand()->getType()->isVectorTy())
+ return false;
Address Addr;
if (!computeAddress(Store->getPointerOperand(), Addr))
return false;
unsigned Opc;
- const TargetRegisterClass *RC;
bool VTIsi1 = false;
switch (getSimpleType(Store->getValueOperand()->getType())) {
case MVT::i1:
VTIsi1 = true;
case MVT::i8:
Opc = WebAssembly::STORE8_I32;
- RC = &WebAssembly::I32RegClass;
break;
case MVT::i16:
Opc = WebAssembly::STORE16_I32;
- RC = &WebAssembly::I32RegClass;
break;
case MVT::i32:
Opc = WebAssembly::STORE_I32;
- RC = &WebAssembly::I32RegClass;
break;
case MVT::i64:
Opc = WebAssembly::STORE_I64;
- RC = &WebAssembly::I64RegClass;
break;
case MVT::f32:
Opc = WebAssembly::STORE_F32;
- RC = &WebAssembly::F32RegClass;
break;
case MVT::f64:
Opc = WebAssembly::STORE_F64;
- RC = &WebAssembly::F64RegClass;
break;
default: return false;
}
@@ -1068,12 +1138,12 @@ bool WebAssemblyFastISel::selectStore(const Instruction *I) {
materializeLoadStoreOperands(Addr);
unsigned ValueReg = getRegForValue(Store->getValueOperand());
+ if (ValueReg == 0)
+ return false;
if (VTIsi1)
ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
- unsigned ResultReg = createResultReg(RC);
- auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
- ResultReg);
+ auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
@@ -1094,6 +1164,8 @@ bool WebAssemblyFastISel::selectBr(const Instruction *I) {
bool Not;
unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
+ if (CondReg == 0)
+ return false;
unsigned Opc = WebAssembly::BR_IF;
if (Not)
@@ -1102,7 +1174,7 @@ bool WebAssemblyFastISel::selectBr(const Instruction *I) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
.addMBB(TBB)
.addReg(CondReg);
-
+
finishCondBranch(Br->getParent(), TBB, FBB);
return true;
}
@@ -1120,6 +1192,9 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
}
Value *RV = Ret->getOperand(0);
+ if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
+ return false;
+
unsigned Opc;
switch (getSimpleType(RV->getType())) {
case MVT::i1: case MVT::i8:
@@ -1129,8 +1204,24 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
case MVT::i64:
Opc = WebAssembly::RETURN_I64;
break;
- case MVT::f32: Opc = WebAssembly::RETURN_F32; break;
- case MVT::f64: Opc = WebAssembly::RETURN_F64; break;
+ case MVT::f32:
+ Opc = WebAssembly::RETURN_F32;
+ break;
+ case MVT::f64:
+ Opc = WebAssembly::RETURN_F64;
+ break;
+ case MVT::v16i8:
+ Opc = WebAssembly::RETURN_v16i8;
+ break;
+ case MVT::v8i16:
+ Opc = WebAssembly::RETURN_v8i16;
+ break;
+ case MVT::v4i32:
+ Opc = WebAssembly::RETURN_v4i32;
+ break;
+ case MVT::v4f32:
+ Opc = WebAssembly::RETURN_v4f32;
+ break;
default: return false;
}
@@ -1142,6 +1233,9 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) {
else
Reg = getRegForValue(RV);
+ if (Reg == 0)
+ return false;
+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
return true;
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
new file mode 100644
index 0000000..adf904e
--- /dev/null
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp
@@ -0,0 +1,166 @@
+//===-- WebAssemblyFixFunctionBitcasts.cpp - Fix function bitcasts --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Fix bitcasted functions.
+///
+/// WebAssembly requires caller and callee signatures to match, however in LLVM,
+/// some amount of slop is vaguely permitted. Detect mismatch by looking for
+/// bitcasts of functions and rewrite them to use wrapper functions instead.
+///
+/// This doesn't catch all cases, such as when a function's address is taken in
+/// one place and casted in another, but it works for many common cases.
+///
+/// Note that LLVM already optimizes away function bitcasts in common cases by
+/// dropping arguments as needed, so this pass only ends up getting used in less
+/// common cases.
+///
+//===----------------------------------------------------------------------===//
+
+#include "WebAssembly.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-fix-function-bitcasts"
+
+namespace {
+class FixFunctionBitcasts final : public ModulePass {
+ StringRef getPassName() const override {
+ return "WebAssembly Fix Function Bitcasts";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ ModulePass::getAnalysisUsage(AU);
+ }
+
+ bool runOnModule(Module &M) override;
+
+public:
+ static char ID;
+ FixFunctionBitcasts() : ModulePass(ID) {}
+};
+} // End anonymous namespace
+
+char FixFunctionBitcasts::ID = 0;
+ModulePass *llvm::createWebAssemblyFixFunctionBitcasts() {
+ return new FixFunctionBitcasts();
+}
+
+// Recursively descend the def-use lists from V to find non-bitcast users of
+// bitcasts of V.
+static void FindUses(Value *V, Function &F,
+ SmallVectorImpl<std::pair<Use *, Function *>> &Uses,
+ SmallPtrSetImpl<Constant *> &ConstantBCs) {
+ for (Use &U : V->uses()) {
+ if (BitCastOperator *BC = dyn_cast<BitCastOperator>(U.getUser()))
+ FindUses(BC, F, Uses, ConstantBCs);
+ else if (U.get()->getType() != F.getType()) {
+ if (isa<Constant>(U.get())) {
+ // Only add constant bitcasts to the list once; they get RAUW'd
+ auto c = ConstantBCs.insert(cast<Constant>(U.get()));
+ if (!c.second) continue;
+ }
+ Uses.push_back(std::make_pair(&U, &F));
+ }
+ }
+}
+
+// Create a wrapper function with type Ty that calls F (which may have a
+// different type). Attempt to support common bitcasted function idioms:
+// - Call with more arguments than needed: arguments are dropped
+// - Call with fewer arguments than needed: arguments are filled in with undef
+// - Return value is not needed: drop it
+// - Return value needed but not present: supply an undef
+//
+// For now, return nullptr without creating a wrapper if the wrapper cannot
+// be generated due to incompatible types.
+static Function *CreateWrapper(Function *F, FunctionType *Ty) {
+ Module *M = F->getParent();
+
+ Function *Wrapper =
+ Function::Create(Ty, Function::PrivateLinkage, "bitcast", M);
+ BasicBlock *BB = BasicBlock::Create(M->getContext(), "body", Wrapper);
+
+ // Determine what arguments to pass.
+ SmallVector<Value *, 4> Args;
+ Function::arg_iterator AI = Wrapper->arg_begin();
+ FunctionType::param_iterator PI = F->getFunctionType()->param_begin();
+ FunctionType::param_iterator PE = F->getFunctionType()->param_end();
+ for (; AI != Wrapper->arg_end() && PI != PE; ++AI, ++PI) {
+ if (AI->getType() != *PI) {
+ Wrapper->eraseFromParent();
+ return nullptr;
+ }
+ Args.push_back(&*AI);
+ }
+ for (; PI != PE; ++PI)
+ Args.push_back(UndefValue::get(*PI));
+
+ CallInst *Call = CallInst::Create(F, Args, "", BB);
+
+ // Determine what value to return.
+ if (Ty->getReturnType()->isVoidTy())
+ ReturnInst::Create(M->getContext(), BB);
+ else if (F->getFunctionType()->getReturnType()->isVoidTy())
+ ReturnInst::Create(M->getContext(), UndefValue::get(Ty->getReturnType()),
+ BB);
+ else if (F->getFunctionType()->getReturnType() == Ty->getReturnType())
+ ReturnInst::Create(M->getContext(), Call, BB);
+ else {
+ Wrapper->eraseFromParent();
+ return nullptr;
+ }
+
+ return Wrapper;
+}
+
+bool FixFunctionBitcasts::runOnModule(Module &M) {
+ SmallVector<std::pair<Use *, Function *>, 0> Uses;
+ SmallPtrSet<Constant *, 2> ConstantBCs;
+
+ // Collect all the places that need wrappers.
+ for (Function &F : M) FindUses(&F, F, Uses, ConstantBCs);
+
+ DenseMap<std::pair<Function *, FunctionType *>, Function *> Wrappers;
+
+ for (auto &UseFunc : Uses) {
+ Use *U = UseFunc.first;
+ Function *F = UseFunc.second;
+ PointerType *PTy = cast<PointerType>(U->get()->getType());
+ FunctionType *Ty = dyn_cast<FunctionType>(PTy->getElementType());
+
+ // If the function is casted to something like i8* as a "generic pointer"
+ // to be later casted to something else, we can't generate a wrapper for it.
+ // Just ignore such casts for now.
+ if (!Ty)
+ continue;
+
+ auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr));
+ if (Pair.second)
+ Pair.first->second = CreateWrapper(F, Ty);
+
+ Function *Wrapper = Pair.first->second;
+ if (!Wrapper)
+ continue;
+
+ if (isa<Constant>(U->get()))
+ U->get()->replaceAllUsesWith(Wrapper);
+ else
+ U->set(Wrapper);
+ }
+
+ return true;
+}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp
index 5dc9092..2bbf7a2 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp
@@ -47,7 +47,7 @@ using namespace llvm;
namespace {
class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Fix Irreducible Control Flow";
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
index 0a5782e..a6a2c0b 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
@@ -37,15 +37,34 @@ using namespace llvm;
// TODO: wasm64
// TODO: Emit TargetOpcode::CFI_INSTRUCTION instructions
+/// We need a base pointer in the case of having items on the stack that
+/// require stricter alignment than the stack pointer itself. Because we need
+/// to shift the stack pointer by some unknown amount to force the alignment,
+/// we need to record the value of the stack pointer on entry to the function.
+bool WebAssemblyFrameLowering::hasBP(
+ const MachineFunction &MF) const {
+ const auto *RegInfo =
+ MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
+ return RegInfo->needsStackRealignment(MF);
+}
+
/// Return true if the specified function should have a dedicated frame pointer
/// register.
bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- const auto *RegInfo =
- MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
- return MFI->isFrameAddressTaken() || MFI->hasVarSizedObjects() ||
- MFI->hasStackMap() || MFI->hasPatchPoint() ||
- RegInfo->needsStackRealignment(MF);
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+
+ // When we have var-sized objects, we move the stack pointer by an unknown
+ // amount, and need to emit a frame pointer to restore the stack to where we
+ // were on function entry.
+ // If we already need a base pointer, we use that to fix up the stack pointer.
+ // If there are no fixed-size objects, we would have no use of a frame
+ // pointer, and thus should not emit one.
+ bool HasFixedSizedObjects = MFI.getStackSize() > 0;
+ bool NeedsFixedReference = !hasBP(MF) || HasFixedSizedObjects;
+
+ return MFI.isFrameAddressTaken() ||
+ (MFI.hasVarSizedObjects() && NeedsFixedReference) ||
+ MFI.hasStackMap() || MFI.hasPatchPoint();
}
/// Under normal circumstances, when a frame pointer is not required, we reserve
@@ -55,7 +74,7 @@ bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
/// frame.
bool WebAssemblyFrameLowering::hasReservedCallFrame(
const MachineFunction &MF) const {
- return !MF.getFrameInfo()->hasVarSizedObjects();
+ return !MF.getFrameInfo().hasVarSizedObjects();
}
@@ -88,18 +107,17 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF,
const TargetRegisterClass *PtrRC =
MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
unsigned Zero = MRI.createVirtualRegister(PtrRC);
- unsigned Drop = MRI.createVirtualRegister(PtrRC);
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero)
.addImm(0);
- auto *MMO = new MachineMemOperand(MachinePointerInfo(MF.getPSVManager()
- .getExternalSymbolCallEntry(ES)),
- MachineMemOperand::MOStore, 4, 4);
- BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32), Drop)
+ MachineMemOperand *MMO = MF.getMachineMemOperand(
+ MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)),
+ MachineMemOperand::MOStore, 4, 4);
+ BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32))
+ .addImm(2) // p2align
.addExternalSymbol(SPSymbol)
.addReg(Zero)
- .addImm(2) // p2align
.addReg(SrcReg)
.addMemOperand(MMO);
}
@@ -108,11 +126,11 @@ MachineBasicBlock::iterator
WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
- assert(!I->getOperand(0).getImm() && hasFP(MF) &&
+ assert(!I->getOperand(0).getImm() && (hasFP(MF) || hasBP(MF)) &&
"Call frame pseudos should only be used for dynamic stack adjustment");
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
if (I->getOpcode() == TII->getCallFrameDestroyOpcode() &&
- needsSPWriteback(MF, *MF.getFrameInfo())) {
+ needsSPWriteback(MF, MF.getFrameInfo())) {
DebugLoc DL = I->getDebugLoc();
writeSPToMemory(WebAssembly::SP32, MF, MBB, I, I, DL);
}
@@ -122,12 +140,12 @@ WebAssemblyFrameLowering::eliminateCallFramePseudoInstr(
void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
// TODO: Do ".setMIFlag(MachineInstr::FrameSetup)" on emitted instructions
- auto *MFI = MF.getFrameInfo();
- assert(MFI->getCalleeSavedInfo().empty() &&
+ auto &MFI = MF.getFrameInfo();
+ assert(MFI.getCalleeSavedInfo().empty() &&
"WebAssembly should not have callee-saved registers");
- if (!needsSP(MF, *MFI)) return;
- uint64_t StackSize = MFI->getStackSize();
+ if (!needsSP(MF, MFI)) return;
+ uint64_t StackSize = MFI.getStackSize();
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
auto &MRI = MF.getRegInfo();
@@ -138,22 +156,31 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
const TargetRegisterClass *PtrRC =
MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
unsigned Zero = MRI.createVirtualRegister(PtrRC);
- unsigned SPReg = MRI.createVirtualRegister(PtrRC);
+ unsigned SPReg = WebAssembly::SP32;
+ if (StackSize)
+ SPReg = MRI.createVirtualRegister(PtrRC);
const char *ES = "__stack_pointer";
auto *SPSymbol = MF.createExternalSymbolName(ES);
BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero)
.addImm(0);
- auto *LoadMMO = new MachineMemOperand(MachinePointerInfo(MF.getPSVManager()
- .getExternalSymbolCallEntry(ES)),
- MachineMemOperand::MOLoad, 4, 4);
+ MachineMemOperand *LoadMMO = MF.getMachineMemOperand(
+ MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)),
+ MachineMemOperand::MOLoad, 4, 4);
// Load the SP value.
- BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32),
- StackSize ? SPReg : (unsigned)WebAssembly::SP32)
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg)
+ .addImm(2) // p2align
.addExternalSymbol(SPSymbol)
.addReg(Zero) // addr
- .addImm(2) // p2align
.addMemOperand(LoadMMO);
+ bool HasBP = hasBP(MF);
+ if (HasBP) {
+ auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
+ unsigned BasePtr = MRI.createVirtualRegister(PtrRC);
+ FI->setBasePointerVreg(BasePtr);
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::COPY), BasePtr)
+ .addReg(SPReg);
+ }
if (StackSize) {
// Subtract the frame size
unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
@@ -164,6 +191,18 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
.addReg(SPReg)
.addReg(OffsetReg);
}
+ if (HasBP) {
+ unsigned BitmaskReg = MRI.createVirtualRegister(PtrRC);
+ unsigned Alignment = MFI.getMaxAlignment();
+ assert((1u << countTrailingZeros(Alignment)) == Alignment &&
+ "Alignment must be a power of 2");
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), BitmaskReg)
+ .addImm((int)~(Alignment - 1));
+ BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::AND_I32),
+ WebAssembly::SP32)
+ .addReg(WebAssembly::SP32)
+ .addReg(BitmaskReg);
+ }
if (hasFP(MF)) {
// Unlike most conventional targets (where FP points to the saved FP),
// FP points to the bottom of the fixed-size locals, so we can use positive
@@ -172,16 +211,16 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
WebAssembly::FP32)
.addReg(WebAssembly::SP32);
}
- if (StackSize && needsSPWriteback(MF, *MFI)) {
+ if (StackSize && needsSPWriteback(MF, MFI)) {
writeSPToMemory(WebAssembly::SP32, MF, MBB, InsertPt, InsertPt, DL);
}
}
void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- auto *MFI = MF.getFrameInfo();
- uint64_t StackSize = MFI->getStackSize();
- if (!needsSP(MF, *MFI) || !needsSPWriteback(MF, *MFI)) return;
+ auto &MFI = MF.getFrameInfo();
+ uint64_t StackSize = MFI.getStackSize();
+ if (!needsSP(MF, MFI) || !needsSPWriteback(MF, MFI)) return;
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
auto &MRI = MF.getRegInfo();
auto InsertPt = MBB.getFirstTerminator();
@@ -194,7 +233,10 @@ void WebAssemblyFrameLowering::emitEpilogue(MachineFunction &MF,
// subtracted in the prolog.
unsigned SPReg = 0;
MachineBasicBlock::iterator InsertAddr = InsertPt;
- if (StackSize) {
+ if (hasBP(MF)) {
+ auto FI = MF.getInfo<WebAssemblyFunctionInfo>();
+ SPReg = FI->getBasePointerVreg();
+ } else if (StackSize) {
const TargetRegisterClass *PtrRC =
MRI.getTargetRegisterInfo()->getPointerRegClass(MF);
unsigned OffsetReg = MRI.createVirtualRegister(PtrRC);
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
index e20fc5d..bf326fc 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
@@ -46,6 +46,7 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering {
bool hasReservedCallFrame(const MachineFunction &MF) const override;
private:
+ bool hasBP(const MachineFunction &MF) const;
bool needsSP(const MachineFunction &MF, const MachineFrameInfo &MFI) const;
bool needsSPWriteback(const MachineFunction &MF,
const MachineFrameInfo &MFI) const;
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 88c38b3..a67137f 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -42,7 +42,7 @@ public:
: SelectionDAGISel(tm, OptLevel), Subtarget(nullptr), ForCodeSize(false) {
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Instruction Selection";
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 9e77319..6a7f75a 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -54,6 +54,12 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
addRegisterClass(MVT::i64, &WebAssembly::I64RegClass);
addRegisterClass(MVT::f32, &WebAssembly::F32RegClass);
addRegisterClass(MVT::f64, &WebAssembly::F64RegClass);
+ if (Subtarget->hasSIMD128()) {
+ addRegisterClass(MVT::v16i8, &WebAssembly::V128RegClass);
+ addRegisterClass(MVT::v8i16, &WebAssembly::V128RegClass);
+ addRegisterClass(MVT::v4i32, &WebAssembly::V128RegClass);
+ addRegisterClass(MVT::v4f32, &WebAssembly::V128RegClass);
+ }
// Compute derived properties from the register classes.
computeRegisterProperties(Subtarget->getRegisterInfo());
@@ -190,6 +196,10 @@ WebAssemblyTargetLowering::getRegForInlineAsmConstraint(
switch (Constraint[0]) {
case 'r':
assert(VT != MVT::iPTR && "Pointer MVT not expected here");
+ if (Subtarget->hasSIMD128() && VT.isVector()) {
+ if (VT.getSizeInBits() == 128)
+ return std::make_pair(0U, &WebAssembly::V128RegClass);
+ }
if (VT.isInteger() && !VT.isVector()) {
if (VT.getSizeInBits() <= 32)
return std::make_pair(0U, &WebAssembly::I32RegClass);
@@ -319,10 +329,10 @@ SDValue WebAssemblyTargetLowering::LowerCall(
if (Out.Flags.isInConsecutiveRegsLast())
fail(DL, DAG, "WebAssembly hasn't implemented cons regs last arguments");
if (Out.Flags.isByVal() && Out.Flags.getByValSize() != 0) {
- auto *MFI = MF.getFrameInfo();
- int FI = MFI->CreateStackObject(Out.Flags.getByValSize(),
- Out.Flags.getByValAlign(),
- /*isSS=*/false);
+ auto &MFI = MF.getFrameInfo();
+ int FI = MFI.CreateStackObject(Out.Flags.getByValSize(),
+ Out.Flags.getByValAlign(),
+ /*isSS=*/false);
SDValue SizeNode =
DAG.getConstant(Out.Flags.getByValSize(), DL, MVT::i32);
SDValue FINode = DAG.getFrameIndex(FI, getPointerTy(Layout));
@@ -365,9 +375,9 @@ SDValue WebAssemblyTargetLowering::LowerCall(
if (IsVarArg && NumBytes) {
// For non-fixed arguments, next emit stores to store the argument values
// to the stack buffer at the offsets computed above.
- int FI = MF.getFrameInfo()->CreateStackObject(NumBytes,
- Layout.getStackAlignment(),
- /*isSS=*/false);
+ int FI = MF.getFrameInfo().CreateStackObject(NumBytes,
+ Layout.getStackAlignment(),
+ /*isSS=*/false);
unsigned ValNo = 0;
SmallVector<SDValue, 8> Chains;
for (SDValue Arg :
@@ -471,12 +481,12 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
- MachineFunction &MF = DAG.getMachineFunction();
- auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
-
if (!CallingConvSupported(CallConv))
fail(DL, DAG, "WebAssembly doesn't support non-C calling conventions");
+ MachineFunction &MF = DAG.getMachineFunction();
+ auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
+
// Set up the incoming ARGUMENTS value, which serves to represent the liveness
// of the incoming values before they're represented by virtual registers.
MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
@@ -516,6 +526,13 @@ SDValue WebAssemblyTargetLowering::LowerFormalArguments(
MFI->addParam(PtrVT);
}
+ // Record the number and types of results.
+ SmallVector<MVT, 4> Params;
+ SmallVector<MVT, 4> Results;
+ ComputeSignatureVTs(*MF.getFunction(), DAG.getTarget(), Params, Results);
+ for (MVT VT : Results)
+ MFI->addResult(VT);
+
return Chain;
}
@@ -570,8 +587,8 @@ SDValue WebAssemblyTargetLowering::LowerCopyToReg(SDValue Op,
unsigned Reg = cast<RegisterSDNode>(Op.getOperand(1))->getReg();
EVT VT = Src.getValueType();
SDValue Copy(
- DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_LOCAL_I32
- : WebAssembly::COPY_LOCAL_I64,
+ DAG.getMachineNode(VT == MVT::i32 ? WebAssembly::COPY_I32
+ : WebAssembly::COPY_I64,
DL, VT, Src),
0);
return Op.getNode()->getNumValues() == 1
@@ -597,7 +614,7 @@ SDValue WebAssemblyTargetLowering::LowerFRAMEADDR(SDValue Op,
if (Op.getConstantOperandVal(0) > 0)
return SDValue();
- DAG.getMachineFunction().getFrameInfo()->setFrameAddressIsTaken(true);
+ DAG.getMachineFunction().getFrameInfo().setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
unsigned FP =
Subtarget->getRegisterInfo()->getFrameRegister(DAG.getMachineFunction());
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
index cfa1519..047f4be 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
@@ -26,25 +26,65 @@ def ADJCALLSTACKUP : I<(outs), (ins i32imm:$amt, i32imm:$amt2),
} // isCodeGenOnly = 1
multiclass CALL<WebAssemblyRegClass vt, string prefix> {
- def CALL_#vt : I<(outs vt:$dst), (ins i32imm:$callee, variable_ops),
+ def CALL_#vt : I<(outs vt:$dst), (ins function32_op:$callee, variable_ops),
[(set vt:$dst, (WebAssemblycall1 (i32 imm:$callee)))],
- !strconcat(prefix, "call\t$dst, $callee")>;
- def CALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops),
- [(set vt:$dst, (WebAssemblycall1 I32:$callee))],
- !strconcat(prefix, "call_indirect\t$dst, $callee")>;
+ !strconcat(prefix, "call\t$dst, $callee"),
+ 0x10>;
+ let isCodeGenOnly = 1 in {
+ def PCALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops),
+ [(set vt:$dst, (WebAssemblycall1 I32:$callee))],
+ "PSEUDO CALL INDIRECT\t$callee">;
+ } // isCodeGenOnly = 1
+
+ def CALL_INDIRECT_#vt : I<(outs vt:$dst), (ins i32imm:$flags, variable_ops),
+ [],
+ !strconcat(prefix, "call_indirect\t$dst"),
+ 0x11>;
+}
+
+multiclass SIMD_CALL<ValueType vt, string prefix> {
+ def CALL_#vt : SIMD_I<(outs V128:$dst), (ins function32_op:$callee, variable_ops),
+ [(set (vt V128:$dst),
+ (WebAssemblycall1 (i32 imm:$callee)))],
+ !strconcat(prefix, "call\t$dst, $callee"),
+ 0x10>;
+ let isCodeGenOnly = 1 in {
+ def PCALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst),
+ (ins I32:$callee, variable_ops),
+ [(set (vt V128:$dst),
+ (WebAssemblycall1 I32:$callee))],
+ "PSEUDO CALL INDIRECT\t$callee">;
+ } // isCodeGenOnly = 1
+
+ def CALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst),
+ (ins i32imm:$flags, variable_ops),
+ [],
+ !strconcat(prefix, "call_indirect\t$dst"),
+ 0x11>;
}
+
let Uses = [SP32, SP64], isCall = 1 in {
defm : CALL<I32, "i32.">;
defm : CALL<I64, "i64.">;
defm : CALL<F32, "f32.">;
defm : CALL<F64, "f64.">;
+ defm : SIMD_CALL<v16i8, "i8x16.">;
+ defm : SIMD_CALL<v8i16, "i16x8.">;
+ defm : SIMD_CALL<v4i32, "i32x4.">;
+ defm : SIMD_CALL<v4f32, "f32x4.">;
- def CALL_VOID : I<(outs), (ins i32imm:$callee, variable_ops),
+ def CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops),
[(WebAssemblycall0 (i32 imm:$callee))],
- "call \t$callee">;
- def CALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops),
- [(WebAssemblycall0 I32:$callee)],
- "call_indirect\t$callee">;
+ "call \t$callee", 0x10>;
+ let isCodeGenOnly = 1 in {
+ def PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops),
+ [(WebAssemblycall0 I32:$callee)],
+ "PSEUDO CALL INDIRECT\t$callee">;
+ } // isCodeGenOnly = 1
+
+ def CALL_INDIRECT_VOID : I<(outs), (ins i32imm:$flags, variable_ops),
+ [],
+ "call_indirect\t", 0x11>;
} // Uses = [SP32,SP64], isCall = 1
} // Defs = [ARGUMENTS]
@@ -58,6 +98,14 @@ def : Pat<(f32 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_F32 tglobaladdr:$callee)>;
def : Pat<(f64 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
(CALL_F64 tglobaladdr:$callee)>;
+def : Pat<(v16i8 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
+ (CALL_v16i8 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
+def : Pat<(v8i16 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
+ (CALL_v8i16 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
+def : Pat<(v4i32 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
+ (CALL_v4i32 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
+def : Pat<(v4f32 (WebAssemblycall1 (WebAssemblywrapper tglobaladdr:$callee))),
+ (CALL_v4f32 tglobaladdr:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(WebAssemblycall0 (WebAssemblywrapper tglobaladdr:$callee)),
(CALL_VOID tglobaladdr:$callee)>;
@@ -70,5 +118,13 @@ def : Pat<(f32 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_F32 texternalsym:$callee)>;
def : Pat<(f64 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
(CALL_F64 texternalsym:$callee)>;
+def : Pat<(v16i8 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
+ (CALL_v16i8 texternalsym:$callee)>, Requires<[HasSIMD128]>;
+def : Pat<(v8i16 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
+ (CALL_v8i16 texternalsym:$callee)>, Requires<[HasSIMD128]>;
+def : Pat<(v4i32 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
+ (CALL_v4i32 texternalsym:$callee)>, Requires<[HasSIMD128]>;
+def : Pat<(v4f32 (WebAssemblycall1 (WebAssemblywrapper texternalsym:$callee))),
+ (CALL_v4f32 texternalsym:$callee)>, Requires<[HasSIMD128]>;
def : Pat<(WebAssemblycall0 (WebAssemblywrapper texternalsym:$callee)),
(CALL_VOID texternalsym:$callee)>;
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
index 444e275..1146431 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
@@ -18,14 +18,13 @@ let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in {
// The condition operand is a boolean value which WebAssembly represents as i32.
def BR_IF : I<(outs), (ins bb_op:$dst, I32:$cond),
[(brcond I32:$cond, bb:$dst)],
- "br_if \t$dst, $cond">;
+ "br_if \t$dst, $cond", 0x0d>;
let isCodeGenOnly = 1 in
-def BR_UNLESS : I<(outs), (ins bb_op:$dst, I32:$cond), [],
- "br_unless\t$dst, $cond">;
+def BR_UNLESS : I<(outs), (ins bb_op:$dst, I32:$cond), []>;
let isBarrier = 1 in {
def BR : I<(outs), (ins bb_op:$dst),
[(br bb:$dst)],
- "br \t$dst">;
+ "br \t$dst", 0x0c>;
} // isBarrier = 1
} // isBranch = 1, isTerminator = 1, hasCtrlDep = 1
@@ -46,7 +45,7 @@ let Defs = [ARGUMENTS] in {
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
def BR_TABLE_I32 : I<(outs), (ins I32:$index, variable_ops),
[(WebAssemblybr_table I32:$index)],
- "br_table \t$index"> {
+ "br_table \t$index", 0x0e> {
let TSFlags{0} = 1;
let TSFlags{1} = 1;
}
@@ -59,37 +58,57 @@ def BR_TABLE_I64 : I<(outs), (ins I64:$index, variable_ops),
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
// Placemarkers to indicate the start or end of a block or loop scope. These
-// use/clobber EXPR_STACK to prevent them from being moved into the middle of
+// use/clobber VALUE_STACK to prevent them from being moved into the middle of
// an expression tree.
-let Uses = [EXPR_STACK], Defs = [EXPR_STACK] in {
-def BLOCK : I<(outs), (ins), [], "block">;
-def LOOP : I<(outs), (ins), [], "loop">;
-def END_BLOCK : I<(outs), (ins), [], "end_block">;
-def END_LOOP : I<(outs), (ins), [], "end_loop">;
-} // Uses = [EXPR_STACK], Defs = [EXPR_STACK]
+let Uses = [VALUE_STACK], Defs = [VALUE_STACK] in {
+def BLOCK : I<(outs), (ins Signature:$sig), [], "block \t$sig", 0x02>;
+def LOOP : I<(outs), (ins Signature:$sig), [], "loop \t$sig", 0x03>;
+
+// END_BLOCK and END_LOOP are represented with the same opcode in wasm.
+def END_BLOCK : I<(outs), (ins), [], "end_block", 0x0b>;
+def END_LOOP : I<(outs), (ins), [], "end_loop", 0x0b>;
+} // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
multiclass RETURN<WebAssemblyRegClass vt> {
def RETURN_#vt : I<(outs), (ins vt:$val), [(WebAssemblyreturn vt:$val)],
- "return \t$val">;
+ "return \t$val", 0x0f>;
// Equivalent to RETURN_#vt, for use at the end of a function when wasm
// semantics return by falling off the end of the block.
let isCodeGenOnly = 1 in
def FALLTHROUGH_RETURN_#vt : I<(outs), (ins vt:$val), []>;
}
+multiclass SIMD_RETURN<ValueType vt> {
+ def RETURN_#vt : SIMD_I<(outs), (ins V128:$val),
+ [(WebAssemblyreturn (vt V128:$val))],
+ "return \t$val", 0x0f>;
+ // Equivalent to RETURN_#vt, for use at the end of a function when wasm
+ // semantics return by falling off the end of the block.
+ let isCodeGenOnly = 1 in
+ def FALLTHROUGH_RETURN_#vt : SIMD_I<(outs), (ins V128:$val), []>;
+}
+
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
+
let isReturn = 1 in {
defm : RETURN<I32>;
defm : RETURN<I64>;
defm : RETURN<F32>;
defm : RETURN<F64>;
- def RETURN_VOID : I<(outs), (ins), [(WebAssemblyreturn)], "return">;
+ defm : SIMD_RETURN<v16i8>;
+ defm : SIMD_RETURN<v8i16>;
+ defm : SIMD_RETURN<v4i32>;
+ defm : SIMD_RETURN<v4f32>;
+
+ def RETURN_VOID : I<(outs), (ins), [(WebAssemblyreturn)], "return", 0x0f>;
// This is to RETURN_VOID what FALLTHROUGH_RETURN_#vt is to RETURN_#vt.
let isCodeGenOnly = 1 in
def FALLTHROUGH_RETURN_VOID : I<(outs), (ins), []>;
} // isReturn = 1
- def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable">;
+
+def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable", 0x00>;
+
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
} // Defs = [ARGUMENTS]
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td
index 931f4a9..29483ba 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrConv.td
@@ -17,14 +17,14 @@ let Defs = [ARGUMENTS] in {
def I32_WRAP_I64 : I<(outs I32:$dst), (ins I64:$src),
[(set I32:$dst, (trunc I64:$src))],
- "i32.wrap/i64\t$dst, $src">;
+ "i32.wrap/i64\t$dst, $src", 0xa7>;
def I64_EXTEND_S_I32 : I<(outs I64:$dst), (ins I32:$src),
[(set I64:$dst, (sext I32:$src))],
- "i64.extend_s/i32\t$dst, $src">;
+ "i64.extend_s/i32\t$dst, $src", 0xac>;
def I64_EXTEND_U_I32 : I<(outs I64:$dst), (ins I32:$src),
[(set I64:$dst, (zext I32:$src))],
- "i64.extend_u/i32\t$dst, $src">;
+ "i64.extend_u/i32\t$dst, $src", 0xad>;
} // defs = [ARGUMENTS]
@@ -39,73 +39,73 @@ let Defs = [ARGUMENTS] in {
let hasSideEffects = 1 in {
def I32_TRUNC_S_F32 : I<(outs I32:$dst), (ins F32:$src),
[(set I32:$dst, (fp_to_sint F32:$src))],
- "i32.trunc_s/f32\t$dst, $src">;
+ "i32.trunc_s/f32\t$dst, $src", 0xa8>;
def I32_TRUNC_U_F32 : I<(outs I32:$dst), (ins F32:$src),
[(set I32:$dst, (fp_to_uint F32:$src))],
- "i32.trunc_u/f32\t$dst, $src">;
+ "i32.trunc_u/f32\t$dst, $src", 0xa9>;
def I64_TRUNC_S_F32 : I<(outs I64:$dst), (ins F32:$src),
[(set I64:$dst, (fp_to_sint F32:$src))],
- "i64.trunc_s/f32\t$dst, $src">;
+ "i64.trunc_s/f32\t$dst, $src", 0xae>;
def I64_TRUNC_U_F32 : I<(outs I64:$dst), (ins F32:$src),
[(set I64:$dst, (fp_to_uint F32:$src))],
- "i64.trunc_u/f32\t$dst, $src">;
+ "i64.trunc_u/f32\t$dst, $src", 0xaf>;
def I32_TRUNC_S_F64 : I<(outs I32:$dst), (ins F64:$src),
[(set I32:$dst, (fp_to_sint F64:$src))],
- "i32.trunc_s/f64\t$dst, $src">;
+ "i32.trunc_s/f64\t$dst, $src", 0xaa>;
def I32_TRUNC_U_F64 : I<(outs I32:$dst), (ins F64:$src),
[(set I32:$dst, (fp_to_uint F64:$src))],
- "i32.trunc_u/f64\t$dst, $src">;
+ "i32.trunc_u/f64\t$dst, $src", 0xab>;
def I64_TRUNC_S_F64 : I<(outs I64:$dst), (ins F64:$src),
[(set I64:$dst, (fp_to_sint F64:$src))],
- "i64.trunc_s/f64\t$dst, $src">;
+ "i64.trunc_s/f64\t$dst, $src", 0xb0>;
def I64_TRUNC_U_F64 : I<(outs I64:$dst), (ins F64:$src),
[(set I64:$dst, (fp_to_uint F64:$src))],
- "i64.trunc_u/f64\t$dst, $src">;
+ "i64.trunc_u/f64\t$dst, $src", 0xb1>;
} // hasSideEffects = 1
def F32_CONVERT_S_I32 : I<(outs F32:$dst), (ins I32:$src),
[(set F32:$dst, (sint_to_fp I32:$src))],
- "f32.convert_s/i32\t$dst, $src">;
+ "f32.convert_s/i32\t$dst, $src", 0xb2>;
def F32_CONVERT_U_I32 : I<(outs F32:$dst), (ins I32:$src),
[(set F32:$dst, (uint_to_fp I32:$src))],
- "f32.convert_u/i32\t$dst, $src">;
+ "f32.convert_u/i32\t$dst, $src", 0xb3>;
def F64_CONVERT_S_I32 : I<(outs F64:$dst), (ins I32:$src),
[(set F64:$dst, (sint_to_fp I32:$src))],
- "f64.convert_s/i32\t$dst, $src">;
+ "f64.convert_s/i32\t$dst, $src", 0xb7>;
def F64_CONVERT_U_I32 : I<(outs F64:$dst), (ins I32:$src),
[(set F64:$dst, (uint_to_fp I32:$src))],
- "f64.convert_u/i32\t$dst, $src">;
+ "f64.convert_u/i32\t$dst, $src", 0xb8>;
def F32_CONVERT_S_I64 : I<(outs F32:$dst), (ins I64:$src),
[(set F32:$dst, (sint_to_fp I64:$src))],
- "f32.convert_s/i64\t$dst, $src">;
+ "f32.convert_s/i64\t$dst, $src", 0xb4>;
def F32_CONVERT_U_I64 : I<(outs F32:$dst), (ins I64:$src),
[(set F32:$dst, (uint_to_fp I64:$src))],
- "f32.convert_u/i64\t$dst, $src">;
+ "f32.convert_u/i64\t$dst, $src", 0xb5>;
def F64_CONVERT_S_I64 : I<(outs F64:$dst), (ins I64:$src),
[(set F64:$dst, (sint_to_fp I64:$src))],
- "f64.convert_s/i64\t$dst, $src">;
+ "f64.convert_s/i64\t$dst, $src", 0xb9>;
def F64_CONVERT_U_I64 : I<(outs F64:$dst), (ins I64:$src),
[(set F64:$dst, (uint_to_fp I64:$src))],
- "f64.convert_u/i64\t$dst, $src">;
+ "f64.convert_u/i64\t$dst, $src", 0xba>;
def F64_PROMOTE_F32 : I<(outs F64:$dst), (ins F32:$src),
- [(set F64:$dst, (fextend F32:$src))],
- "f64.promote/f32\t$dst, $src">;
+ [(set F64:$dst, (fpextend F32:$src))],
+ "f64.promote/f32\t$dst, $src", 0xbb>;
def F32_DEMOTE_F64 : I<(outs F32:$dst), (ins F64:$src),
- [(set F32:$dst, (fround F64:$src))],
- "f32.demote/f64\t$dst, $src">;
+ [(set F32:$dst, (fpround F64:$src))],
+ "f32.demote/f64\t$dst, $src", 0xb6>;
def I32_REINTERPRET_F32 : I<(outs I32:$dst), (ins F32:$src),
[(set I32:$dst, (bitconvert F32:$src))],
- "i32.reinterpret/f32\t$dst, $src">;
+ "i32.reinterpret/f32\t$dst, $src", 0xbc>;
def F32_REINTERPRET_I32 : I<(outs F32:$dst), (ins I32:$src),
[(set F32:$dst, (bitconvert I32:$src))],
- "f32.reinterpret/i32\t$dst, $src">;
+ "f32.reinterpret/i32\t$dst, $src", 0xbe>;
def I64_REINTERPRET_F64 : I<(outs I64:$dst), (ins F64:$src),
[(set I64:$dst, (bitconvert F64:$src))],
- "i64.reinterpret/f64\t$dst, $src">;
+ "i64.reinterpret/f64\t$dst, $src", 0xbd>;
def F64_REINTERPRET_I64 : I<(outs F64:$dst), (ins I64:$src),
[(set F64:$dst, (bitconvert I64:$src))],
- "f64.reinterpret/i64\t$dst, $src">;
+ "f64.reinterpret/i64\t$dst, $src", 0xbf>;
} // Defs = [ARGUMENTS]
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td
index 6456972..030be08 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td
@@ -15,26 +15,26 @@
let Defs = [ARGUMENTS] in {
let isCommutable = 1 in
-defm ADD : BinaryFP<fadd, "add ">;
-defm SUB : BinaryFP<fsub, "sub ">;
+defm ADD : BinaryFP<fadd, "add ", 0x92, 0xa0>;
+defm SUB : BinaryFP<fsub, "sub ", 0x93, 0xa1>;
let isCommutable = 1 in
-defm MUL : BinaryFP<fmul, "mul ">;
-defm DIV : BinaryFP<fdiv, "div ">;
-defm SQRT : UnaryFP<fsqrt, "sqrt">;
+defm MUL : BinaryFP<fmul, "mul ", 0x94, 0xa2>;
+defm DIV : BinaryFP<fdiv, "div ", 0x95, 0xa3>;
+defm SQRT : UnaryFP<fsqrt, "sqrt", 0x91, 0x9f>;
-defm ABS : UnaryFP<fabs, "abs ">;
-defm NEG : UnaryFP<fneg, "neg ">;
-defm COPYSIGN : BinaryFP<fcopysign, "copysign">;
+defm ABS : UnaryFP<fabs, "abs ", 0x8b, 0x99>;
+defm NEG : UnaryFP<fneg, "neg ", 0x8c, 0x9a>;
+defm COPYSIGN : BinaryFP<fcopysign, "copysign", 0x98, 0xa6>;
let isCommutable = 1 in {
-defm MIN : BinaryFP<fminnan, "min ">;
-defm MAX : BinaryFP<fmaxnan, "max ">;
+defm MIN : BinaryFP<fminnan, "min ", 0x96, 0xa4>;
+defm MAX : BinaryFP<fmaxnan, "max ", 0x97, 0xa5>;
} // isCommutable = 1
-defm CEIL : UnaryFP<fceil, "ceil">;
-defm FLOOR : UnaryFP<ffloor, "floor">;
-defm TRUNC : UnaryFP<ftrunc, "trunc">;
-defm NEAREST : UnaryFP<fnearbyint, "nearest">;
+defm CEIL : UnaryFP<fceil, "ceil", 0x8d, 0x9b>;
+defm FLOOR : UnaryFP<ffloor, "floor", 0x8e, 0x9c>;
+defm TRUNC : UnaryFP<ftrunc, "trunc", 0x8f, 0x9d>;
+defm NEAREST : UnaryFP<fnearbyint, "nearest", 0x90, 0x9e>;
} // Defs = [ARGUMENTS]
@@ -51,13 +51,13 @@ def : Pat<(frint f64:$src), (NEAREST_F64 f64:$src)>;
let Defs = [ARGUMENTS] in {
let isCommutable = 1 in {
-defm EQ : ComparisonFP<SETOEQ, "eq ">;
-defm NE : ComparisonFP<SETUNE, "ne ">;
+defm EQ : ComparisonFP<SETOEQ, "eq ", 0x5b, 0x61>;
+defm NE : ComparisonFP<SETUNE, "ne ", 0x5c, 0x62>;
} // isCommutable = 1
-defm LT : ComparisonFP<SETOLT, "lt ">;
-defm LE : ComparisonFP<SETOLE, "le ">;
-defm GT : ComparisonFP<SETOGT, "gt ">;
-defm GE : ComparisonFP<SETOGE, "ge ">;
+defm LT : ComparisonFP<SETOLT, "lt ", 0x5d, 0x63>;
+defm LE : ComparisonFP<SETOLE, "le ", 0x5e, 0x64>;
+defm GT : ComparisonFP<SETOGT, "gt ", 0x5f, 0x65>;
+defm GE : ComparisonFP<SETOGE, "ge ", 0x60, 0x66>;
} // Defs = [ARGUMENTS]
@@ -79,10 +79,10 @@ let Defs = [ARGUMENTS] in {
def SELECT_F32 : I<(outs F32:$dst), (ins F32:$lhs, F32:$rhs, I32:$cond),
[(set F32:$dst, (select I32:$cond, F32:$lhs, F32:$rhs))],
- "f32.select\t$dst, $lhs, $rhs, $cond">;
+ "f32.select\t$dst, $lhs, $rhs, $cond", 0x1b>;
def SELECT_F64 : I<(outs F64:$dst), (ins F64:$lhs, F64:$rhs, I32:$cond),
[(set F64:$dst, (select I32:$cond, F64:$lhs, F64:$rhs))],
- "f64.select\t$dst, $lhs, $rhs, $cond">;
+ "f64.select\t$dst, $lhs, $rhs, $cond", 0x1b>;
} // Defs = [ARGUMENTS]
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td
index 8008dd3..5b24984 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFormats.td
@@ -13,67 +13,90 @@
//===----------------------------------------------------------------------===//
// WebAssembly Instruction Format.
-class WebAssemblyInst<string asmstr> : Instruction {
- field bits<0> Inst; // Instruction encoding.
+class WebAssemblyInst<bits<32> inst, string asmstr> : Instruction {
+ field bits<32> Inst = inst; // Instruction encoding.
let Namespace = "WebAssembly";
let Pattern = [];
let AsmString = asmstr;
}
// Normal instructions.
-class I<dag oops, dag iops, list<dag> pattern, string asmstr = "">
- : WebAssemblyInst<asmstr> {
+class I<dag oops, dag iops, list<dag> pattern, string asmstr = "", bits<32> inst = -1>
+ : WebAssemblyInst<inst, asmstr> {
dag OutOperandList = oops;
dag InOperandList = iops;
let Pattern = pattern;
}
+class SIMD_I<dag oops, dag iops, list<dag> pattern,
+ string asmstr = "", bits<32> inst = -1>
+ : I<oops, iops, pattern, asmstr, inst>, Requires<[HasSIMD128]>;
+
// Unary and binary instructions, for the local types that WebAssembly supports.
-multiclass UnaryInt<SDNode node, string name> {
+multiclass UnaryInt<SDNode node, string name, bits<32> i32Inst, bits<32> i64Inst> {
def _I32 : I<(outs I32:$dst), (ins I32:$src),
[(set I32:$dst, (node I32:$src))],
- !strconcat("i32.", !strconcat(name, "\t$dst, $src"))>;
+ !strconcat("i32.", !strconcat(name, "\t$dst, $src")), i32Inst>;
def _I64 : I<(outs I64:$dst), (ins I64:$src),
[(set I64:$dst, (node I64:$src))],
- !strconcat("i64.", !strconcat(name, "\t$dst, $src"))>;
+ !strconcat("i64.", !strconcat(name, "\t$dst, $src")), i64Inst>;
}
-multiclass BinaryInt<SDNode node, string name> {
+multiclass BinaryInt<SDNode node, string name, bits<32> i32Inst, bits<32> i64Inst> {
def _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs),
[(set I32:$dst, (node I32:$lhs, I32:$rhs))],
- !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs")), i32Inst>;
def _I64 : I<(outs I64:$dst), (ins I64:$lhs, I64:$rhs),
[(set I64:$dst, (node I64:$lhs, I64:$rhs))],
- !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs")), i64Inst>;
}
-multiclass UnaryFP<SDNode node, string name> {
+multiclass UnaryFP<SDNode node, string name, bits<32> f32Inst, bits<32> f64Inst> {
def _F32 : I<(outs F32:$dst), (ins F32:$src),
[(set F32:$dst, (node F32:$src))],
- !strconcat("f32.", !strconcat(name, "\t$dst, $src"))>;
+ !strconcat("f32.", !strconcat(name, "\t$dst, $src")), f32Inst>;
def _F64 : I<(outs F64:$dst), (ins F64:$src),
[(set F64:$dst, (node F64:$src))],
- !strconcat("f64.", !strconcat(name, "\t$dst, $src"))>;
+ !strconcat("f64.", !strconcat(name, "\t$dst, $src")), f64Inst>;
}
-multiclass BinaryFP<SDNode node, string name> {
+multiclass BinaryFP<SDNode node, string name, bits<32> f32Inst, bits<32> f64Inst> {
def _F32 : I<(outs F32:$dst), (ins F32:$lhs, F32:$rhs),
[(set F32:$dst, (node F32:$lhs, F32:$rhs))],
- !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs")), f32Inst>;
def _F64 : I<(outs F64:$dst), (ins F64:$lhs, F64:$rhs),
[(set F64:$dst, (node F64:$lhs, F64:$rhs))],
- !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")), f64Inst>;
+}
+multiclass SIMDBinary<SDNode node, SDNode fnode, string name> {
+ def _I8x16 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
+ [(set (v16i8 V128:$dst), (node V128:$lhs, V128:$rhs))],
+ !strconcat("i8x16.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ def _I16x8 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
+ [(set (v8i16 V128:$dst), (node V128:$lhs, V128:$rhs))],
+ !strconcat("i16x8.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ def _I32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
+ [(set (v4i32 V128:$dst), (node V128:$lhs, V128:$rhs))],
+ !strconcat("i32x4.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ def _F32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs),
+ [(set (v4f32 V128:$dst), (fnode V128:$lhs, V128:$rhs))],
+ !strconcat("f32x4.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+
}
-multiclass ComparisonInt<CondCode cond, string name> {
+multiclass ComparisonInt<CondCode cond, string name, bits<32> i32Inst, bits<32> i64Inst> {
def _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs),
[(set I32:$dst, (setcc I32:$lhs, I32:$rhs, cond))],
- !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs")),
+ i32Inst>;
def _I64 : I<(outs I32:$dst), (ins I64:$lhs, I64:$rhs),
[(set I32:$dst, (setcc I64:$lhs, I64:$rhs, cond))],
- !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs")),
+ i64Inst>;
}
-multiclass ComparisonFP<CondCode cond, string name> {
+multiclass ComparisonFP<CondCode cond, string name, bits<32> f32Inst, bits<32> f64Inst> {
def _F32 : I<(outs I32:$dst), (ins F32:$lhs, F32:$rhs),
[(set I32:$dst, (setcc F32:$lhs, F32:$rhs, cond))],
- !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs")),
+ f32Inst>;
def _F64 : I<(outs I32:$dst), (ins F64:$lhs, F64:$rhs),
[(set I32:$dst, (setcc F64:$lhs, F64:$rhs, cond))],
- !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs"))>;
+ !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")),
+ f64Inst>;
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
index 2fd3eab..0e2d8bb 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
@@ -60,19 +60,19 @@ void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
? MRI.getRegClass(DestReg)
: MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
- unsigned CopyLocalOpcode;
+ unsigned CopyOpcode;
if (RC == &WebAssembly::I32RegClass)
- CopyLocalOpcode = WebAssembly::COPY_LOCAL_I32;
+ CopyOpcode = WebAssembly::COPY_I32;
else if (RC == &WebAssembly::I64RegClass)
- CopyLocalOpcode = WebAssembly::COPY_LOCAL_I64;
+ CopyOpcode = WebAssembly::COPY_I64;
else if (RC == &WebAssembly::F32RegClass)
- CopyLocalOpcode = WebAssembly::COPY_LOCAL_F32;
+ CopyOpcode = WebAssembly::COPY_F32;
else if (RC == &WebAssembly::F64RegClass)
- CopyLocalOpcode = WebAssembly::COPY_LOCAL_F64;
+ CopyOpcode = WebAssembly::COPY_F64;
else
llvm_unreachable("Unexpected register class");
- BuildMI(MBB, I, DL, get(CopyLocalOpcode), DestReg)
+ BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)
.addReg(SrcReg, KillSrc ? RegState::Kill : 0);
}
@@ -142,7 +142,10 @@ bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-unsigned WebAssemblyInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::instr_iterator I = MBB.instr_end();
unsigned Count = 0;
@@ -161,11 +164,14 @@ unsigned WebAssemblyInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return Count;
}
-unsigned WebAssemblyInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned WebAssemblyInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(!BytesAdded && "code size not handled");
+
if (Cond.empty()) {
if (!TBB)
return 0;
@@ -190,7 +196,7 @@ unsigned WebAssemblyInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return 2;
}
-bool WebAssemblyInstrInfo::ReverseBranchCondition(
+bool WebAssemblyInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 2 && "Expected a flag and a successor block");
Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
index d93f958..df6c937 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
@@ -48,12 +48,14 @@ public:
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 4b31987..dcfd1a4 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -71,18 +71,39 @@ let OperandNamespace = "WebAssembly" in {
let OperandType = "OPERAND_BASIC_BLOCK" in
def bb_op : Operand<OtherVT>;
-let OperandType = "OPERAND_FP32IMM" in
+let OperandType = "OPERAND_LOCAL" in
+def local_op : Operand<i32>;
+
+let OperandType = "OPERAND_I32IMM" in
+def i32imm_op : Operand<i32>;
+
+let OperandType = "OPERAND_I64IMM" in
+def i64imm_op : Operand<i64>;
+
+let OperandType = "OPERAND_F32IMM" in
def f32imm_op : Operand<f32>;
-let OperandType = "OPERAND_FP64IMM" in
+let OperandType = "OPERAND_F64IMM" in
def f64imm_op : Operand<f64>;
+let OperandType = "OPERAND_FUNCTION32" in
+def function32_op : Operand<i32>;
+
+let OperandType = "OPERAND_OFFSET32" in
+def offset32_op : Operand<i32>;
+
let OperandType = "OPERAND_P2ALIGN" in {
def P2Align : Operand<i32> {
let PrintMethod = "printWebAssemblyP2AlignOperand";
}
} // OperandType = "OPERAND_P2ALIGN"
+let OperandType = "OPERAND_SIGNATURE" in {
+def Signature : Operand<i32> {
+ let PrintMethod = "printWebAssemblySignatureOperand";
+}
+} // OperandType = "OPERAND_SIGNATURE"
+
} // OperandNamespace = "WebAssembly"
//===----------------------------------------------------------------------===//
@@ -100,10 +121,20 @@ multiclass ARGUMENT<WebAssemblyRegClass vt> {
def ARGUMENT_#vt : I<(outs vt:$res), (ins i32imm:$argno),
[(set vt:$res, (WebAssemblyargument timm:$argno))]>;
}
+multiclass SIMD_ARGUMENT<ValueType vt> {
+ let hasSideEffects = 1, Uses = [ARGUMENTS], isCodeGenOnly = 1 in
+ def ARGUMENT_#vt : SIMD_I<(outs V128:$res), (ins i32imm:$argno),
+ [(set (vt V128:$res),
+ (WebAssemblyargument timm:$argno))]>;
+}
defm : ARGUMENT<I32>;
defm : ARGUMENT<I64>;
defm : ARGUMENT<F32>;
defm : ARGUMENT<F64>;
+defm : SIMD_ARGUMENT<v16i8>;
+defm : SIMD_ARGUMENT<v8i16>;
+defm : SIMD_ARGUMENT<v4i32>;
+defm : SIMD_ARGUMENT<v4f32>;
let Defs = [ARGUMENTS] in {
@@ -111,40 +142,63 @@ let Defs = [ARGUMENTS] in {
// are implied by virtual register uses and defs.
multiclass LOCAL<WebAssemblyRegClass vt> {
let hasSideEffects = 0 in {
- // COPY_LOCAL is not an actual instruction in wasm, but since we allow
- // get_local and set_local to be implicit, we can have a COPY_LOCAL which
- // is actually a no-op because all the work is done in the implied
- // get_local and set_local.
- let isAsCheapAsAMove = 1 in
- def COPY_LOCAL_#vt : I<(outs vt:$res), (ins vt:$src), [],
- "copy_local\t$res, $src">;
-
- // TEE_LOCAL is similar to COPY_LOCAL, but writes two copies of its result.
- // Typically this would be used to stackify one result and write the other
- // result to a local.
- let isAsCheapAsAMove = 1 in
- def TEE_LOCAL_#vt : I<(outs vt:$res, vt:$also), (ins vt:$src), [],
- "tee_local\t$res, $also, $src">;
+ // COPY is not an actual instruction in wasm, but since we allow get_local and
+ // set_local to be implicit during most of codegen, we can have a COPY which
+ // is actually a no-op because all the work is done in the implied get_local
+ // and set_local. COPYs are eliminated (and replaced with
+ // get_local/set_local) in the ExplicitLocals pass.
+ let isAsCheapAsAMove = 1, isCodeGenOnly = 1 in
+ def COPY_#vt : I<(outs vt:$res), (ins vt:$src), [], "copy_local\t$res, $src">;
+
+ // TEE is similar to COPY, but writes two copies of its result. Typically
+ // this would be used to stackify one result and write the other result to a
+ // local.
+ let isAsCheapAsAMove = 1, isCodeGenOnly = 1 in
+ def TEE_#vt : I<(outs vt:$res, vt:$also), (ins vt:$src), [],
+ "tee_local\t$res, $also, $src">;
+
+ // This is the actual get_local instruction in wasm. These are made explicit
+ // by the ExplicitLocals pass. It has mayLoad because it reads from a wasm
+ // local, which is a side effect not otherwise modeled in LLVM.
+ let mayLoad = 1, isAsCheapAsAMove = 1 in
+ def GET_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local), [],
+ "get_local\t$res, $local", 0x20>;
+
+ // This is the actual set_local instruction in wasm. These are made explicit
+ // by the ExplicitLocals pass. It has mayStore because it writes to a wasm
+ // local, which is a side effect not otherwise modeled in LLVM.
+ let mayStore = 1, isAsCheapAsAMove = 1 in
+ def SET_LOCAL_#vt : I<(outs), (ins local_op:$local, vt:$src), [],
+ "set_local\t$local, $src", 0x21>;
+
+ // This is the actual tee_local instruction in wasm. TEEs are turned into
+ // TEE_LOCALs by the ExplicitLocals pass. It has mayStore for the same reason
+ // as SET_LOCAL.
+ let mayStore = 1, isAsCheapAsAMove = 1 in
+ def TEE_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local, vt:$src), [],
+ "tee_local\t$res, $local, $src", 0x22>;
+
} // hasSideEffects = 0
}
defm : LOCAL<I32>;
defm : LOCAL<I64>;
defm : LOCAL<F32>;
defm : LOCAL<F64>;
+defm : LOCAL<V128>, Requires<[HasSIMD128]>;
let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in {
-def CONST_I32 : I<(outs I32:$res), (ins i32imm:$imm),
+def CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm),
[(set I32:$res, imm:$imm)],
- "i32.const\t$res, $imm">;
-def CONST_I64 : I<(outs I64:$res), (ins i64imm:$imm),
+ "i32.const\t$res, $imm", 0x41>;
+def CONST_I64 : I<(outs I64:$res), (ins i64imm_op:$imm),
[(set I64:$res, imm:$imm)],
- "i64.const\t$res, $imm">;
+ "i64.const\t$res, $imm", 0x42>;
def CONST_F32 : I<(outs F32:$res), (ins f32imm_op:$imm),
[(set F32:$res, fpimm:$imm)],
- "f32.const\t$res, $imm">;
+ "f32.const\t$res, $imm", 0x43>;
def CONST_F64 : I<(outs F64:$res), (ins f64imm_op:$imm),
[(set F64:$res, fpimm:$imm)],
- "f64.const\t$res, $imm">;
+ "f64.const\t$res, $imm", 0x44>;
} // isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1
} // Defs = [ARGUMENTS]
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
index 7eaa57b..e872dc2 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
@@ -17,51 +17,51 @@ let Defs = [ARGUMENTS] in {
// The spaces after the names are for aesthetic purposes only, to make
// operands line up vertically after tab expansion.
let isCommutable = 1 in
-defm ADD : BinaryInt<add, "add ">;
-defm SUB : BinaryInt<sub, "sub ">;
+defm ADD : BinaryInt<add, "add ", 0x6a, 0x7c>;
+defm SUB : BinaryInt<sub, "sub ", 0x6b, 0x7d>;
let isCommutable = 1 in
-defm MUL : BinaryInt<mul, "mul ">;
+defm MUL : BinaryInt<mul, "mul ", 0x6c, 0x7e>;
// Divide and remainder trap on a zero denominator.
let hasSideEffects = 1 in {
-defm DIV_S : BinaryInt<sdiv, "div_s">;
-defm DIV_U : BinaryInt<udiv, "div_u">;
-defm REM_S : BinaryInt<srem, "rem_s">;
-defm REM_U : BinaryInt<urem, "rem_u">;
+defm DIV_S : BinaryInt<sdiv, "div_s", 0x6d, 0x7f>;
+defm DIV_U : BinaryInt<udiv, "div_u", 0x6e, 0x80>;
+defm REM_S : BinaryInt<srem, "rem_s", 0x6f, 0x81>;
+defm REM_U : BinaryInt<urem, "rem_u", 0x70, 0x82>;
} // hasSideEffects = 1
let isCommutable = 1 in {
-defm AND : BinaryInt<and, "and ">;
-defm OR : BinaryInt<or, "or ">;
-defm XOR : BinaryInt<xor, "xor ">;
+defm AND : BinaryInt<and, "and ", 0x71, 0x83>;
+defm OR : BinaryInt<or, "or ", 0x72, 0x84>;
+defm XOR : BinaryInt<xor, "xor ", 0x73, 0x85>;
} // isCommutable = 1
-defm SHL : BinaryInt<shl, "shl ">;
-defm SHR_U : BinaryInt<srl, "shr_u">;
-defm SHR_S : BinaryInt<sra, "shr_s">;
-defm ROTL : BinaryInt<rotl, "rotl">;
-defm ROTR : BinaryInt<rotr, "rotr">;
+defm SHL : BinaryInt<shl, "shl ", 0x74, 0x86>;
+defm SHR_S : BinaryInt<sra, "shr_s", 0x75, 0x87>;
+defm SHR_U : BinaryInt<srl, "shr_u", 0x76, 0x88>;
+defm ROTL : BinaryInt<rotl, "rotl", 0x77, 0x89>;
+defm ROTR : BinaryInt<rotr, "rotr", 0x78, 0x8a>;
let isCommutable = 1 in {
-defm EQ : ComparisonInt<SETEQ, "eq ">;
-defm NE : ComparisonInt<SETNE, "ne ">;
+defm EQ : ComparisonInt<SETEQ, "eq ", 0x46, 0x51>;
+defm NE : ComparisonInt<SETNE, "ne ", 0x47, 0x52>;
} // isCommutable = 1
-defm LT_S : ComparisonInt<SETLT, "lt_s">;
-defm LE_S : ComparisonInt<SETLE, "le_s">;
-defm LT_U : ComparisonInt<SETULT, "lt_u">;
-defm LE_U : ComparisonInt<SETULE, "le_u">;
-defm GT_S : ComparisonInt<SETGT, "gt_s">;
-defm GE_S : ComparisonInt<SETGE, "ge_s">;
-defm GT_U : ComparisonInt<SETUGT, "gt_u">;
-defm GE_U : ComparisonInt<SETUGE, "ge_u">;
+defm LT_S : ComparisonInt<SETLT, "lt_s", 0x48, 0x53>;
+defm LT_U : ComparisonInt<SETULT, "lt_u", 0x49, 0x54>;
+defm GT_S : ComparisonInt<SETGT, "gt_s", 0x4a, 0x55>;
+defm GT_U : ComparisonInt<SETUGT, "gt_u", 0x4b, 0x56>;
+defm LE_S : ComparisonInt<SETLE, "le_s", 0x4c, 0x57>;
+defm LE_U : ComparisonInt<SETULE, "le_u", 0x4d, 0x58>;
+defm GE_S : ComparisonInt<SETGE, "ge_s", 0x4e, 0x59>;
+defm GE_U : ComparisonInt<SETUGE, "ge_u", 0x4f, 0x5a>;
-defm CLZ : UnaryInt<ctlz, "clz ">;
-defm CTZ : UnaryInt<cttz, "ctz ">;
-defm POPCNT : UnaryInt<ctpop, "popcnt">;
+defm CLZ : UnaryInt<ctlz, "clz ", 0x67, 0x79>;
+defm CTZ : UnaryInt<cttz, "ctz ", 0x68, 0x7a>;
+defm POPCNT : UnaryInt<ctpop, "popcnt", 0x69, 0x7b>;
def EQZ_I32 : I<(outs I32:$dst), (ins I32:$src),
[(set I32:$dst, (setcc I32:$src, 0, SETEQ))],
- "i32.eqz \t$dst, $src">;
+ "i32.eqz \t$dst, $src", 0x45>;
def EQZ_I64 : I<(outs I32:$dst), (ins I64:$src),
[(set I32:$dst, (setcc I64:$src, 0, SETEQ))],
- "i64.eqz \t$dst, $src">;
+ "i64.eqz \t$dst, $src", 0x50>;
} // Defs = [ARGUMENTS]
@@ -75,10 +75,10 @@ let Defs = [ARGUMENTS] in {
def SELECT_I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs, I32:$cond),
[(set I32:$dst, (select I32:$cond, I32:$lhs, I32:$rhs))],
- "i32.select\t$dst, $lhs, $rhs, $cond">;
+ "i32.select\t$dst, $lhs, $rhs, $cond", 0x1b>;
def SELECT_I64 : I<(outs I64:$dst), (ins I64:$lhs, I64:$rhs, I32:$cond),
[(set I64:$dst, (select I32:$cond, I64:$lhs, I64:$rhs))],
- "i64.select\t$dst, $lhs, $rhs, $cond">;
+ "i64.select\t$dst, $lhs, $rhs, $cond", 0x1b>;
} // Defs = [ARGUMENTS]
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td
index 521c664..b606ebb 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td
@@ -41,15 +41,13 @@ def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
}]>;
// GlobalAddresses are conceptually unsigned values, so we can also fold them
-// into immediate values as long as their offsets are non-negative.
+// into immediate values as long as the add is 'nuw'.
+// TODO: We'd like to also match GA offsets but there are cases where the
+// register can have a negative value. Find out what more we can do.
def regPlusGA : PatFrag<(ops node:$addr, node:$off),
(add node:$addr, node:$off),
[{
- return N->getFlags()->hasNoUnsignedWrap() ||
- (N->getOperand(1)->getOpcode() == WebAssemblyISD::Wrapper &&
- isa<GlobalAddressSDNode>(N->getOperand(1)->getOperand(0)) &&
- cast<GlobalAddressSDNode>(N->getOperand(1)->getOperand(0))
- ->getOffset() >= 0);
+ return N->getFlags()->hasNoUnsignedWrap();
}]>;
// We don't need a regPlusES because external symbols never have constant
@@ -58,636 +56,631 @@ def regPlusGA : PatFrag<(ops node:$addr, node:$off),
let Defs = [ARGUMENTS] in {
// Basic load.
-def LOAD_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i32.load\t$dst, ${off}(${addr})${p2align}">;
-def LOAD_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load\t$dst, ${off}(${addr})${p2align}">;
-def LOAD_F32 : I<(outs F32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "f32.load\t$dst, ${off}(${addr})${p2align}">;
-def LOAD_F64 : I<(outs F64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "f64.load\t$dst, ${off}(${addr})${p2align}">;
+// FIXME: When we can break syntax compatibility, reorder the fields in the
+// asmstrings to match the binary encoding.
+def LOAD_I32 : I<(outs I32:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i32.load\t$dst, ${off}(${addr})${p2align}", 0x28>;
+def LOAD_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load\t$dst, ${off}(${addr})${p2align}", 0x29>;
+def LOAD_F32 : I<(outs F32:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "f32.load\t$dst, ${off}(${addr})${p2align}", 0x2a>;
+def LOAD_F64 : I<(outs F64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "f64.load\t$dst, ${off}(${addr})${p2align}", 0x2b>;
} // Defs = [ARGUMENTS]
// Select loads with no constant offset.
-def : Pat<(i32 (load I32:$addr)), (LOAD_I32 0, $addr, 0)>;
-def : Pat<(i64 (load I32:$addr)), (LOAD_I64 0, $addr, 0)>;
-def : Pat<(f32 (load I32:$addr)), (LOAD_F32 0, $addr, 0)>;
-def : Pat<(f64 (load I32:$addr)), (LOAD_F64 0, $addr, 0)>;
+def : Pat<(i32 (load I32:$addr)), (LOAD_I32 0, 0, $addr)>;
+def : Pat<(i64 (load I32:$addr)), (LOAD_I64 0, 0, $addr)>;
+def : Pat<(f32 (load I32:$addr)), (LOAD_F32 0, 0, $addr)>;
+def : Pat<(f64 (load I32:$addr)), (LOAD_F64 0, 0, $addr)>;
// Select loads with a constant offset.
def : Pat<(i32 (load (regPlusImm I32:$addr, imm:$off))),
- (LOAD_I32 imm:$off, $addr, 0)>;
+ (LOAD_I32 0, imm:$off, $addr)>;
def : Pat<(i64 (load (regPlusImm I32:$addr, imm:$off))),
- (LOAD_I64 imm:$off, $addr, 0)>;
+ (LOAD_I64 0, imm:$off, $addr)>;
def : Pat<(f32 (load (regPlusImm I32:$addr, imm:$off))),
- (LOAD_F32 imm:$off, $addr, 0)>;
+ (LOAD_F32 0, imm:$off, $addr)>;
def : Pat<(f64 (load (regPlusImm I32:$addr, imm:$off))),
- (LOAD_F64 imm:$off, $addr, 0)>;
+ (LOAD_F64 0, imm:$off, $addr)>;
def : Pat<(i32 (load (or_is_add I32:$addr, imm:$off))),
- (LOAD_I32 imm:$off, $addr, 0)>;
+ (LOAD_I32 0, imm:$off, $addr)>;
def : Pat<(i64 (load (or_is_add I32:$addr, imm:$off))),
- (LOAD_I64 imm:$off, $addr, 0)>;
+ (LOAD_I64 0, imm:$off, $addr)>;
def : Pat<(f32 (load (or_is_add I32:$addr, imm:$off))),
- (LOAD_F32 imm:$off, $addr, 0)>;
+ (LOAD_F32 0, imm:$off, $addr)>;
def : Pat<(f64 (load (or_is_add I32:$addr, imm:$off))),
- (LOAD_F64 imm:$off, $addr, 0)>;
+ (LOAD_F64 0, imm:$off, $addr)>;
def : Pat<(i32 (load (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (load (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(f32 (load (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD_F32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD_F32 0, tglobaladdr:$off, $addr)>;
def : Pat<(f64 (load (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD_F64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD_F64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
- (LOAD_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
- (LOAD_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD_I64 0, texternalsym:$off, $addr)>;
def : Pat<(f32 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
- (LOAD_F32 texternalsym:$off, $addr, 0)>;
+ (LOAD_F32 0, texternalsym:$off, $addr)>;
def : Pat<(f64 (load (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
- (LOAD_F64 texternalsym:$off, $addr, 0)>;
+ (LOAD_F64 0, texternalsym:$off, $addr)>;
// Select loads with just a constant offset.
-def : Pat<(i32 (load imm:$off)), (LOAD_I32 imm:$off, (CONST_I32 0), 0)>;
-def : Pat<(i64 (load imm:$off)), (LOAD_I64 imm:$off, (CONST_I32 0), 0)>;
-def : Pat<(f32 (load imm:$off)), (LOAD_F32 imm:$off, (CONST_I32 0), 0)>;
-def : Pat<(f64 (load imm:$off)), (LOAD_F64 imm:$off, (CONST_I32 0), 0)>;
+def : Pat<(i32 (load imm:$off)), (LOAD_I32 0, imm:$off, (CONST_I32 0))>;
+def : Pat<(i64 (load imm:$off)), (LOAD_I64 0, imm:$off, (CONST_I32 0))>;
+def : Pat<(f32 (load imm:$off)), (LOAD_F32 0, imm:$off, (CONST_I32 0))>;
+def : Pat<(f64 (load imm:$off)), (LOAD_F64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (load (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (load (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(f32 (load (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD_F32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD_F32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(f64 (load (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD_F64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD_F64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (load (WebAssemblywrapper texternalsym:$off))),
- (LOAD_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (load (WebAssemblywrapper texternalsym:$off))),
- (LOAD_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(f32 (load (WebAssemblywrapper texternalsym:$off))),
- (LOAD_F32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD_F32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(f64 (load (WebAssemblywrapper texternalsym:$off))),
- (LOAD_F64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD_F64 0, texternalsym:$off, (CONST_I32 0))>;
let Defs = [ARGUMENTS] in {
// Extending load.
-def LOAD8_S_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i32.load8_s\t$dst, ${off}(${addr})${p2align}">;
-def LOAD8_U_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i32.load8_u\t$dst, ${off}(${addr})${p2align}">;
-def LOAD16_S_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i32.load16_s\t$dst, ${off}(${addr})${p2align}">;
-def LOAD16_U_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i32.load16_u\t$dst, ${off}(${addr})${p2align}">;
-def LOAD8_S_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load8_s\t$dst, ${off}(${addr})${p2align}">;
-def LOAD8_U_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load8_u\t$dst, ${off}(${addr})${p2align}">;
-def LOAD16_S_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load16_s\t$dst, ${off}(${addr})${p2align}">;
-def LOAD16_U_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load16_u\t$dst, ${off}(${addr})${p2align}">;
-def LOAD32_S_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load32_s\t$dst, ${off}(${addr})${p2align}">;
-def LOAD32_U_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align), [],
- "i64.load32_u\t$dst, ${off}(${addr})${p2align}">;
+def LOAD8_S_I32 : I<(outs I32:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i32.load8_s\t$dst, ${off}(${addr})${p2align}", 0x2c>;
+def LOAD8_U_I32 : I<(outs I32:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i32.load8_u\t$dst, ${off}(${addr})${p2align}", 0x2d>;
+def LOAD16_S_I32 : I<(outs I32:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i32.load16_s\t$dst, ${off}(${addr})${p2align}", 0x2e>;
+def LOAD16_U_I32 : I<(outs I32:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i32.load16_u\t$dst, ${off}(${addr})${p2align}", 0x2f>;
+def LOAD8_S_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load8_s\t$dst, ${off}(${addr})${p2align}", 0x30>;
+def LOAD8_U_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load8_u\t$dst, ${off}(${addr})${p2align}", 0x31>;
+def LOAD16_S_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load16_s\t$dst, ${off}(${addr})${p2align}", 0x32>;
+def LOAD16_U_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load16_u\t$dst, ${off}(${addr})${p2align}", 0x33>;
+def LOAD32_S_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load32_s\t$dst, ${off}(${addr})${p2align}", 0x34>;
+def LOAD32_U_I64 : I<(outs I64:$dst),
+ (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
+ [], "i64.load32_u\t$dst, ${off}(${addr})${p2align}", 0x35>;
} // Defs = [ARGUMENTS]
// Select extending loads with no constant offset.
-def : Pat<(i32 (sextloadi8 I32:$addr)), (LOAD8_S_I32 0, $addr, 0)>;
-def : Pat<(i32 (zextloadi8 I32:$addr)), (LOAD8_U_I32 0, $addr, 0)>;
-def : Pat<(i32 (sextloadi16 I32:$addr)), (LOAD16_S_I32 0, $addr, 0)>;
-def : Pat<(i32 (zextloadi16 I32:$addr)), (LOAD16_U_I32 0, $addr, 0)>;
-def : Pat<(i64 (sextloadi8 I32:$addr)), (LOAD8_S_I64 0, $addr, 0)>;
-def : Pat<(i64 (zextloadi8 I32:$addr)), (LOAD8_U_I64 0, $addr, 0)>;
-def : Pat<(i64 (sextloadi16 I32:$addr)), (LOAD16_S_I64 0, $addr, 0)>;
-def : Pat<(i64 (zextloadi16 I32:$addr)), (LOAD16_U_I64 0, $addr, 0)>;
-def : Pat<(i64 (sextloadi32 I32:$addr)), (LOAD32_S_I64 0, $addr, 0)>;
-def : Pat<(i64 (zextloadi32 I32:$addr)), (LOAD32_U_I64 0, $addr, 0)>;
+def : Pat<(i32 (sextloadi8 I32:$addr)), (LOAD8_S_I32 0, 0, $addr)>;
+def : Pat<(i32 (zextloadi8 I32:$addr)), (LOAD8_U_I32 0, 0, $addr)>;
+def : Pat<(i32 (sextloadi16 I32:$addr)), (LOAD16_S_I32 0, 0, $addr)>;
+def : Pat<(i32 (zextloadi16 I32:$addr)), (LOAD16_U_I32 0, 0, $addr)>;
+def : Pat<(i64 (sextloadi8 I32:$addr)), (LOAD8_S_I64 0, 0, $addr)>;
+def : Pat<(i64 (zextloadi8 I32:$addr)), (LOAD8_U_I64 0, 0, $addr)>;
+def : Pat<(i64 (sextloadi16 I32:$addr)), (LOAD16_S_I64 0, 0, $addr)>;
+def : Pat<(i64 (zextloadi16 I32:$addr)), (LOAD16_U_I64 0, 0, $addr)>;
+def : Pat<(i64 (sextloadi32 I32:$addr)), (LOAD32_S_I64 0, 0, $addr)>;
+def : Pat<(i64 (zextloadi32 I32:$addr)), (LOAD32_U_I64 0, 0, $addr)>;
// Select extending loads with a constant offset.
def : Pat<(i32 (sextloadi8 (regPlusImm I32:$addr, imm:$off))),
- (LOAD8_S_I32 imm:$off, $addr, 0)>;
+ (LOAD8_S_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (zextloadi8 (regPlusImm I32:$addr, imm:$off))),
- (LOAD8_U_I32 imm:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (sextloadi16 (regPlusImm I32:$addr, imm:$off))),
- (LOAD16_S_I32 imm:$off, $addr, 0)>;
+ (LOAD16_S_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (zextloadi16 (regPlusImm I32:$addr, imm:$off))),
- (LOAD16_U_I32 imm:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, imm:$off, $addr)>;
def : Pat<(i64 (sextloadi8 (regPlusImm I32:$addr, imm:$off))),
- (LOAD8_S_I64 imm:$off, $addr, 0)>;
+ (LOAD8_S_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (zextloadi8 (regPlusImm I32:$addr, imm:$off))),
- (LOAD8_U_I64 imm:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (sextloadi16 (regPlusImm I32:$addr, imm:$off))),
- (LOAD16_S_I64 imm:$off, $addr, 0)>;
+ (LOAD16_S_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (zextloadi16 (regPlusImm I32:$addr, imm:$off))),
- (LOAD16_U_I64 imm:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (sextloadi32 (regPlusImm I32:$addr, imm:$off))),
- (LOAD32_S_I64 imm:$off, $addr, 0)>;
+ (LOAD32_S_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (zextloadi32 (regPlusImm I32:$addr, imm:$off))),
- (LOAD32_U_I64 imm:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, imm:$off, $addr)>;
def : Pat<(i32 (sextloadi8 (or_is_add I32:$addr, imm:$off))),
- (LOAD8_S_I32 imm:$off, $addr, 0)>;
+ (LOAD8_S_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (zextloadi8 (or_is_add I32:$addr, imm:$off))),
- (LOAD8_U_I32 imm:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (sextloadi16 (or_is_add I32:$addr, imm:$off))),
- (LOAD16_S_I32 imm:$off, $addr, 0)>;
+ (LOAD16_S_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (zextloadi16 (or_is_add I32:$addr, imm:$off))),
- (LOAD16_U_I32 imm:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, imm:$off, $addr)>;
def : Pat<(i64 (sextloadi8 (or_is_add I32:$addr, imm:$off))),
- (LOAD8_S_I64 imm:$off, $addr, 0)>;
+ (LOAD8_S_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (zextloadi8 (or_is_add I32:$addr, imm:$off))),
- (LOAD8_U_I64 imm:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (sextloadi16 (or_is_add I32:$addr, imm:$off))),
- (LOAD16_S_I64 imm:$off, $addr, 0)>;
+ (LOAD16_S_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (zextloadi16 (or_is_add I32:$addr, imm:$off))),
- (LOAD16_U_I64 imm:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (sextloadi32 (or_is_add I32:$addr, imm:$off))),
- (LOAD32_S_I64 imm:$off, $addr, 0)>;
+ (LOAD32_S_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (zextloadi32 (or_is_add I32:$addr, imm:$off))),
- (LOAD32_U_I64 imm:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, imm:$off, $addr)>;
def : Pat<(i32 (sextloadi8 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD8_S_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD8_S_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (zextloadi8 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD8_U_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (sextloadi16 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD16_S_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD16_S_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (zextloadi16 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD16_U_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (sextloadi8 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD8_S_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD8_S_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (zextloadi8 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD8_U_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (sextloadi16 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD16_S_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD16_S_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (zextloadi16 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD16_U_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (sextloadi32 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD32_S_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD32_S_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (zextloadi32 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD32_U_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (sextloadi8 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD8_S_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD8_S_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i32 (zextloadi8 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD8_U_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i32 (sextloadi16 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD16_S_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD16_S_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i32 (zextloadi16 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD16_U_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (sextloadi8 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD8_S_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD8_S_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (zextloadi8 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD8_U_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (sextloadi16 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD16_S_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD16_S_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (zextloadi16 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD16_U_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (sextloadi32 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD32_S_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD32_S_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (zextloadi32 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD32_U_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, texternalsym:$off, $addr)>;
// Select extending loads with just a constant offset.
def : Pat<(i32 (sextloadi8 imm:$off)),
- (LOAD8_S_I32 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD8_S_I32 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (zextloadi8 imm:$off)),
- (LOAD8_U_I32 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I32 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (sextloadi16 imm:$off)),
- (LOAD16_S_I32 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD16_S_I32 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (zextloadi16 imm:$off)),
- (LOAD16_U_I32 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I32 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi8 imm:$off)),
- (LOAD8_S_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD8_S_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi8 imm:$off)),
- (LOAD8_U_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi16 imm:$off)),
- (LOAD16_S_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD16_S_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi16 imm:$off)),
- (LOAD16_U_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi32 imm:$off)),
- (LOAD32_S_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD32_S_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi32 imm:$off)),
- (LOAD32_U_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD32_U_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (sextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD8_S_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD8_S_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (zextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD8_U_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (sextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD16_S_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD16_S_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (zextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD16_U_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD8_S_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD8_S_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi8 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD8_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD16_S_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD16_S_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi16 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD16_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi32 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD32_S_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD32_S_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi32 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD32_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD32_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (sextloadi8 (WebAssemblywrapper texternalsym:$off))),
- (LOAD8_S_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD8_S_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i32 (zextloadi8 (WebAssemblywrapper texternalsym:$off))),
- (LOAD8_U_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i32 (sextloadi16 (WebAssemblywrapper texternalsym:$off))),
- (LOAD16_S_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD16_S_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i32 (zextloadi16 (WebAssemblywrapper texternalsym:$off))),
- (LOAD16_U_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi8 (WebAssemblywrapper texternalsym:$off))),
- (LOAD8_S_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD8_S_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi8 (WebAssemblywrapper texternalsym:$off))),
- (LOAD8_U_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi16 (WebAssemblywrapper texternalsym:$off))),
- (LOAD16_S_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD16_S_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi16 (WebAssemblywrapper texternalsym:$off))),
- (LOAD16_U_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (sextloadi32 (WebAssemblywrapper texternalsym:$off))),
- (LOAD32_S_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD32_S_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (zextloadi32 (WebAssemblywrapper texternalsym:$off))),
- (LOAD32_U_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD32_U_I64 0, texternalsym:$off, (CONST_I32 0))>;
// Resolve "don't care" extending loads to zero-extending loads. This is
// somewhat arbitrary, but zero-extending is conceptually simpler.
// Select "don't care" extending loads with no constant offset.
-def : Pat<(i32 (extloadi8 I32:$addr)), (LOAD8_U_I32 0, $addr, 0)>;
-def : Pat<(i32 (extloadi16 I32:$addr)), (LOAD16_U_I32 0, $addr, 0)>;
-def : Pat<(i64 (extloadi8 I32:$addr)), (LOAD8_U_I64 0, $addr, 0)>;
-def : Pat<(i64 (extloadi16 I32:$addr)), (LOAD16_U_I64 0, $addr, 0)>;
-def : Pat<(i64 (extloadi32 I32:$addr)), (LOAD32_U_I64 0, $addr, 0)>;
+def : Pat<(i32 (extloadi8 I32:$addr)), (LOAD8_U_I32 0, 0, $addr)>;
+def : Pat<(i32 (extloadi16 I32:$addr)), (LOAD16_U_I32 0, 0, $addr)>;
+def : Pat<(i64 (extloadi8 I32:$addr)), (LOAD8_U_I64 0, 0, $addr)>;
+def : Pat<(i64 (extloadi16 I32:$addr)), (LOAD16_U_I64 0, 0, $addr)>;
+def : Pat<(i64 (extloadi32 I32:$addr)), (LOAD32_U_I64 0, 0, $addr)>;
// Select "don't care" extending loads with a constant offset.
def : Pat<(i32 (extloadi8 (regPlusImm I32:$addr, imm:$off))),
- (LOAD8_U_I32 imm:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (extloadi16 (regPlusImm I32:$addr, imm:$off))),
- (LOAD16_U_I32 imm:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, imm:$off, $addr)>;
def : Pat<(i64 (extloadi8 (regPlusImm I32:$addr, imm:$off))),
- (LOAD8_U_I64 imm:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (extloadi16 (regPlusImm I32:$addr, imm:$off))),
- (LOAD16_U_I64 imm:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (extloadi32 (regPlusImm I32:$addr, imm:$off))),
- (LOAD32_U_I64 imm:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, imm:$off, $addr)>;
def : Pat<(i32 (extloadi8 (or_is_add I32:$addr, imm:$off))),
- (LOAD8_U_I32 imm:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, imm:$off, $addr)>;
def : Pat<(i32 (extloadi16 (or_is_add I32:$addr, imm:$off))),
- (LOAD16_U_I32 imm:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, imm:$off, $addr)>;
def : Pat<(i64 (extloadi8 (or_is_add I32:$addr, imm:$off))),
- (LOAD8_U_I64 imm:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (extloadi16 (or_is_add I32:$addr, imm:$off))),
- (LOAD16_U_I64 imm:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, imm:$off, $addr)>;
def : Pat<(i64 (extloadi32 (or_is_add I32:$addr, imm:$off))),
- (LOAD32_U_I64 imm:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, imm:$off, $addr)>;
def : Pat<(i32 (extloadi8 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD8_U_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (extloadi16 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD16_U_I32 tglobaladdr:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (extloadi8 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD8_U_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (extloadi16 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD16_U_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i64 (extloadi32 (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off)))),
- (LOAD32_U_I64 tglobaladdr:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, tglobaladdr:$off, $addr)>;
def : Pat<(i32 (extloadi8 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD8_U_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD8_U_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i32 (extloadi16 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD16_U_I32 texternalsym:$off, $addr, 0)>;
+ (LOAD16_U_I32 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (extloadi8 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD8_U_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD8_U_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (extloadi16 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD16_U_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD16_U_I64 0, texternalsym:$off, $addr)>;
def : Pat<(i64 (extloadi32 (add I32:$addr,
(WebAssemblywrapper texternalsym:$off)))),
- (LOAD32_U_I64 texternalsym:$off, $addr, 0)>;
+ (LOAD32_U_I64 0, texternalsym:$off, $addr)>;
// Select "don't care" extending loads with just a constant offset.
def : Pat<(i32 (extloadi8 imm:$off)),
- (LOAD8_U_I32 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I32 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (extloadi16 imm:$off)),
- (LOAD16_U_I32 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I32 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi8 imm:$off)),
- (LOAD8_U_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi16 imm:$off)),
- (LOAD16_U_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi32 imm:$off)),
- (LOAD32_U_I64 imm:$off, (CONST_I32 0), 0)>;
+ (LOAD32_U_I64 0, imm:$off, (CONST_I32 0))>;
def : Pat<(i32 (extloadi8 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD8_U_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (extloadi16 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD16_U_I32 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I32 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi8 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD8_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi16 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD16_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi32 (WebAssemblywrapper tglobaladdr:$off))),
- (LOAD32_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD32_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
def : Pat<(i32 (extloadi8 (WebAssemblywrapper texternalsym:$off))),
- (LOAD8_U_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i32 (extloadi16 (WebAssemblywrapper texternalsym:$off))),
- (LOAD16_U_I32 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I32 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi8 (WebAssemblywrapper texternalsym:$off))),
- (LOAD8_U_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD8_U_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi16 (WebAssemblywrapper texternalsym:$off))),
- (LOAD16_U_I64 texternalsym:$off, (CONST_I32 0), 0)>;
+ (LOAD16_U_I64 0, texternalsym:$off, (CONST_I32 0))>;
def : Pat<(i64 (extloadi32 (WebAssemblywrapper texternalsym:$off))),
- (LOAD32_U_I64 tglobaladdr:$off, (CONST_I32 0), 0)>;
+ (LOAD32_U_I64 0, tglobaladdr:$off, (CONST_I32 0))>;
let Defs = [ARGUMENTS] in {
// Basic store.
-// Note that we split the patterns out of the instruction definitions because
-// WebAssembly's stores return their operand value, and tablegen doesn't like
-// instruction definition patterns that don't reference all of the output
-// operands.
// Note: WebAssembly inverts SelectionDAG's usual operand order.
-def STORE_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I32:$val), [],
- "i32.store\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I64:$val), [],
- "i64.store\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE_F32 : I<(outs F32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, F32:$val), [],
- "f32.store\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE_F64 : I<(outs F64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, F64:$val), [],
- "f64.store\t$dst, ${off}(${addr})${p2align}, $val">;
+def STORE_I32 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I32:$val), [],
+ "i32.store\t${off}(${addr})${p2align}, $val", 0x36>;
+def STORE_I64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I64:$val), [],
+ "i64.store\t${off}(${addr})${p2align}, $val", 0x37>;
+def STORE_F32 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ F32:$val), [],
+ "f32.store\t${off}(${addr})${p2align}, $val", 0x38>;
+def STORE_F64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ F64:$val), [],
+ "f64.store\t${off}(${addr})${p2align}, $val", 0x39>;
} // Defs = [ARGUMENTS]
// Select stores with no constant offset.
-def : Pat<(store I32:$val, I32:$addr), (STORE_I32 0, I32:$addr, 0, I32:$val)>;
-def : Pat<(store I64:$val, I32:$addr), (STORE_I64 0, I32:$addr, 0, I64:$val)>;
-def : Pat<(store F32:$val, I32:$addr), (STORE_F32 0, I32:$addr, 0, F32:$val)>;
-def : Pat<(store F64:$val, I32:$addr), (STORE_F64 0, I32:$addr, 0, F64:$val)>;
+def : Pat<(store I32:$val, I32:$addr), (STORE_I32 0, 0, I32:$addr, I32:$val)>;
+def : Pat<(store I64:$val, I32:$addr), (STORE_I64 0, 0, I32:$addr, I64:$val)>;
+def : Pat<(store F32:$val, I32:$addr), (STORE_F32 0, 0, I32:$addr, F32:$val)>;
+def : Pat<(store F64:$val, I32:$addr), (STORE_F64 0, 0, I32:$addr, F64:$val)>;
// Select stores with a constant offset.
def : Pat<(store I32:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE_I32 imm:$off, I32:$addr, 0, I32:$val)>;
+ (STORE_I32 0, imm:$off, I32:$addr, I32:$val)>;
def : Pat<(store I64:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(store F32:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE_F32 imm:$off, I32:$addr, 0, F32:$val)>;
+ (STORE_F32 0, imm:$off, I32:$addr, F32:$val)>;
def : Pat<(store F64:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE_F64 imm:$off, I32:$addr, 0, F64:$val)>;
+ (STORE_F64 0, imm:$off, I32:$addr, F64:$val)>;
def : Pat<(store I32:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE_I32 imm:$off, I32:$addr, 0, I32:$val)>;
+ (STORE_I32 0, imm:$off, I32:$addr, I32:$val)>;
def : Pat<(store I64:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(store F32:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE_F32 imm:$off, I32:$addr, 0, F32:$val)>;
+ (STORE_F32 0, imm:$off, I32:$addr, F32:$val)>;
def : Pat<(store F64:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE_F64 imm:$off, I32:$addr, 0, F64:$val)>;
+ (STORE_F64 0, imm:$off, I32:$addr, F64:$val)>;
def : Pat<(store I32:$val, (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE_I32 tglobaladdr:$off, I32:$addr, 0, I32:$val)>;
+ (STORE_I32 0, tglobaladdr:$off, I32:$addr, I32:$val)>;
def : Pat<(store I64:$val, (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
+ (STORE_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
def : Pat<(store F32:$val, (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE_F32 tglobaladdr:$off, I32:$addr, 0, F32:$val)>;
+ (STORE_F32 0, tglobaladdr:$off, I32:$addr, F32:$val)>;
def : Pat<(store F64:$val, (regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE_F64 tglobaladdr:$off, I32:$addr, 0, F64:$val)>;
+ (STORE_F64 0, tglobaladdr:$off, I32:$addr, F64:$val)>;
def : Pat<(store I32:$val, (add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE_I32 texternalsym:$off, I32:$addr, 0, I32:$val)>;
+ (STORE_I32 0, texternalsym:$off, I32:$addr, I32:$val)>;
def : Pat<(store I64:$val, (add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
+ (STORE_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
def : Pat<(store F32:$val, (add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE_F32 texternalsym:$off, I32:$addr, 0, F32:$val)>;
+ (STORE_F32 0, texternalsym:$off, I32:$addr, F32:$val)>;
def : Pat<(store F64:$val, (add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE_F64 texternalsym:$off, I32:$addr, 0, F64:$val)>;
+ (STORE_F64 0, texternalsym:$off, I32:$addr, F64:$val)>;
// Select stores with just a constant offset.
def : Pat<(store I32:$val, imm:$off),
- (STORE_I32 imm:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE_I32 0, imm:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(store I64:$val, imm:$off),
- (STORE_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(store F32:$val, imm:$off),
- (STORE_F32 imm:$off, (CONST_I32 0), 0, F32:$val)>;
+ (STORE_F32 0, imm:$off, (CONST_I32 0), F32:$val)>;
def : Pat<(store F64:$val, imm:$off),
- (STORE_F64 imm:$off, (CONST_I32 0), 0, F64:$val)>;
+ (STORE_F64 0, imm:$off, (CONST_I32 0), F64:$val)>;
def : Pat<(store I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE_I32 tglobaladdr:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE_I32 0, tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(store I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(store F32:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE_F32 tglobaladdr:$off, (CONST_I32 0), 0, F32:$val)>;
+ (STORE_F32 0, tglobaladdr:$off, (CONST_I32 0), F32:$val)>;
def : Pat<(store F64:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE_F64 tglobaladdr:$off, (CONST_I32 0), 0, F64:$val)>;
+ (STORE_F64 0, tglobaladdr:$off, (CONST_I32 0), F64:$val)>;
def : Pat<(store I32:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE_I32 texternalsym:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE_I32 0, texternalsym:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(store I64:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(store F32:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE_F32 texternalsym:$off, (CONST_I32 0), 0, F32:$val)>;
+ (STORE_F32 0, texternalsym:$off, (CONST_I32 0), F32:$val)>;
def : Pat<(store F64:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE_F64 texternalsym:$off, (CONST_I32 0), 0, F64:$val)>;
+ (STORE_F64 0, texternalsym:$off, (CONST_I32 0), F64:$val)>;
let Defs = [ARGUMENTS] in {
// Truncating store.
-def STORE8_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I32:$val), [],
- "i32.store8\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE16_I32 : I<(outs I32:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I32:$val), [],
- "i32.store16\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE8_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I64:$val), [],
- "i64.store8\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE16_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I64:$val), [],
- "i64.store16\t$dst, ${off}(${addr})${p2align}, $val">;
-def STORE32_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
- P2Align:$p2align, I64:$val), [],
- "i64.store32\t$dst, ${off}(${addr})${p2align}, $val">;
+def STORE8_I32 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I32:$val), [],
+ "i32.store8\t${off}(${addr})${p2align}, $val", 0x3a>;
+def STORE16_I32 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I32:$val), [],
+ "i32.store16\t${off}(${addr})${p2align}, $val", 0x3b>;
+def STORE8_I64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I64:$val), [],
+ "i64.store8\t${off}(${addr})${p2align}, $val", 0x3c>;
+def STORE16_I64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I64:$val), [],
+ "i64.store16\t${off}(${addr})${p2align}, $val", 0x3d>;
+def STORE32_I64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
+ I64:$val), [],
+ "i64.store32\t${off}(${addr})${p2align}, $val", 0x3e>;
} // Defs = [ARGUMENTS]
// Select truncating stores with no constant offset.
def : Pat<(truncstorei8 I32:$val, I32:$addr),
- (STORE8_I32 0, I32:$addr, 0, I32:$val)>;
+ (STORE8_I32 0, 0, I32:$addr, I32:$val)>;
def : Pat<(truncstorei16 I32:$val, I32:$addr),
- (STORE16_I32 0, I32:$addr, 0, I32:$val)>;
+ (STORE16_I32 0, 0, I32:$addr, I32:$val)>;
def : Pat<(truncstorei8 I64:$val, I32:$addr),
- (STORE8_I64 0, I32:$addr, 0, I64:$val)>;
+ (STORE8_I64 0, 0, I32:$addr, I64:$val)>;
def : Pat<(truncstorei16 I64:$val, I32:$addr),
- (STORE16_I64 0, I32:$addr, 0, I64:$val)>;
+ (STORE16_I64 0, 0, I32:$addr, I64:$val)>;
def : Pat<(truncstorei32 I64:$val, I32:$addr),
- (STORE32_I64 0, I32:$addr, 0, I64:$val)>;
+ (STORE32_I64 0, 0, I32:$addr, I64:$val)>;
// Select truncating stores with a constant offset.
def : Pat<(truncstorei8 I32:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE8_I32 imm:$off, I32:$addr, 0, I32:$val)>;
+ (STORE8_I32 0, imm:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei16 I32:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE16_I32 imm:$off, I32:$addr, 0, I32:$val)>;
+ (STORE16_I32 0, imm:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei8 I64:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE8_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE8_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei16 I64:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE16_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE16_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei32 I64:$val, (regPlusImm I32:$addr, imm:$off)),
- (STORE32_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE32_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei8 I32:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE8_I32 imm:$off, I32:$addr, 0, I32:$val)>;
+ (STORE8_I32 0, imm:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei16 I32:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE16_I32 imm:$off, I32:$addr, 0, I32:$val)>;
+ (STORE16_I32 0, imm:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei8 I64:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE8_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE8_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei16 I64:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE16_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE16_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei32 I64:$val, (or_is_add I32:$addr, imm:$off)),
- (STORE32_I64 imm:$off, I32:$addr, 0, I64:$val)>;
+ (STORE32_I64 0, imm:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei8 I32:$val,
(regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE8_I32 tglobaladdr:$off, I32:$addr, 0, I32:$val)>;
+ (STORE8_I32 0, tglobaladdr:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei16 I32:$val,
(regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE16_I32 tglobaladdr:$off, I32:$addr, 0, I32:$val)>;
+ (STORE16_I32 0, tglobaladdr:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei8 I64:$val,
(regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE8_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
+ (STORE8_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei16 I64:$val,
(regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE16_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
+ (STORE16_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei32 I64:$val,
(regPlusGA I32:$addr,
(WebAssemblywrapper tglobaladdr:$off))),
- (STORE32_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
+ (STORE32_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei8 I32:$val, (add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE8_I32 texternalsym:$off, I32:$addr, 0, I32:$val)>;
+ (STORE8_I32 0, texternalsym:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei16 I32:$val,
(add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE16_I32 texternalsym:$off, I32:$addr, 0, I32:$val)>;
+ (STORE16_I32 0, texternalsym:$off, I32:$addr, I32:$val)>;
def : Pat<(truncstorei8 I64:$val,
(add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE8_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
+ (STORE8_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei16 I64:$val,
(add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE16_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
+ (STORE16_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
def : Pat<(truncstorei32 I64:$val,
(add I32:$addr,
(WebAssemblywrapper texternalsym:$off))),
- (STORE32_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
+ (STORE32_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
// Select truncating stores with just a constant offset.
def : Pat<(truncstorei8 I32:$val, imm:$off),
- (STORE8_I32 imm:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE8_I32 0, imm:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(truncstorei16 I32:$val, imm:$off),
- (STORE16_I32 imm:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE16_I32 0, imm:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(truncstorei8 I64:$val, imm:$off),
- (STORE8_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE8_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei16 I64:$val, imm:$off),
- (STORE16_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE16_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei32 I64:$val, imm:$off),
- (STORE32_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE32_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE8_I32 tglobaladdr:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE8_I32 0, tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE16_I32 tglobaladdr:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE16_I32 0, tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE8_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE8_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE16_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE16_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
- (STORE32_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE32_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE8_I32 texternalsym:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE8_I32 0, texternalsym:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE16_I32 texternalsym:$off, (CONST_I32 0), 0, I32:$val)>;
+ (STORE16_I32 0, texternalsym:$off, (CONST_I32 0), I32:$val)>;
def : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE8_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE8_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE16_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE16_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
def : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper texternalsym:$off)),
- (STORE32_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
+ (STORE32_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
let Defs = [ARGUMENTS] in {
// Current memory size.
-def CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins),
- [(set I32:$dst, (int_wasm_current_memory))],
- "current_memory\t$dst">,
+def CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
+ [],
+ "current_memory\t$dst", 0x3f>,
Requires<[HasAddr32]>;
-def CURRENT_MEMORY_I64 : I<(outs I64:$dst), (ins),
- [(set I64:$dst, (int_wasm_current_memory))],
- "current_memory\t$dst">,
- Requires<[HasAddr64]>;
// Grow memory.
-def GROW_MEMORY_I32 : I<(outs), (ins I32:$delta),
- [(int_wasm_grow_memory I32:$delta)],
- "grow_memory\t$delta">,
+def GROW_MEMORY_I32 : I<(outs), (ins i32imm:$flags, I32:$delta),
+ [],
+ "grow_memory\t$delta", 0x40>,
Requires<[HasAddr32]>;
-def GROW_MEMORY_I64 : I<(outs), (ins I64:$delta),
- [(int_wasm_grow_memory I64:$delta)],
- "grow_memory\t$delta">,
- Requires<[HasAddr64]>;
} // Defs = [ARGUMENTS]
+
+def : Pat<(int_wasm_current_memory),
+ (CURRENT_MEMORY_I32 0)>;
+def : Pat<(int_wasm_grow_memory I32:$delta),
+ (GROW_MEMORY_I32 0, $delta)>;
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
index 3e29906..e403534 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
@@ -12,5 +12,8 @@
///
//===----------------------------------------------------------------------===//
-// TODO: Implement SIMD instructions.
-// Note: use Requires<[HasSIMD128]>.
+let isCommutable = 1 in {
+defm ADD : SIMDBinary<add, fadd, "add ">;
+defm MUL: SIMDBinary<mul, fmul, "mul ">;
+} // isCommutable = 1
+defm SUB: SIMDBinary<sub, fsub, "sub ">;
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp
index af53f3d..7ea5d05 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp
@@ -29,7 +29,7 @@ using namespace llvm;
namespace {
class WebAssemblyLowerBrUnless final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Lower br_unless";
}
@@ -104,12 +104,12 @@ bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) {
}
// If we weren't able to invert the condition in place. Insert an
- // expression to invert it.
+ // instruction to invert it.
if (!Inverted) {
unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
- MFI.stackifyVReg(Tmp);
BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp)
.addReg(Cond);
+ MFI.stackifyVReg(Tmp);
Cond = Tmp;
Inverted = true;
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
new file mode 100644
index 0000000..72cb1cc
--- /dev/null
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -0,0 +1,1184 @@
+//=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file lowers exception-related instructions and setjmp/longjmp
+/// function calls in order to use Emscripten's JavaScript try and catch
+/// mechanism.
+///
+/// To handle exceptions and setjmp/longjmps, this scheme relies on JavaScript's
+/// try and catch syntax and relevant exception-related libraries implemented
+/// in JavaScript glue code that will be produced by Emscripten. This is similar
+/// to the current Emscripten asm.js exception handling in fastcomp. For
+/// fastcomp's EH / SjLj scheme, see these files in fastcomp LLVM branch:
+/// (Location: https://github.com/kripken/emscripten-fastcomp)
+/// lib/Target/JSBackend/NaCl/LowerEmExceptionsPass.cpp
+/// lib/Target/JSBackend/NaCl/LowerEmSetjmp.cpp
+/// lib/Target/JSBackend/JSBackend.cpp
+/// lib/Target/JSBackend/CallHandlers.h
+///
+/// * Exception handling
+/// This pass lowers invokes and landingpads into library functions in JS glue
+/// code. Invokes are lowered into function wrappers called invoke wrappers that
+/// exist in JS side, which wraps the original function call with JS try-catch.
+/// If an exception occurred, cxa_throw() function in JS side sets some
+/// variables (see below) so we can check whether an exception occurred from
+/// wasm code and handle it appropriately.
+///
+/// * Setjmp-longjmp handling
+/// This pass lowers setjmp to a reasonably-performant approach for emscripten.
+/// The idea is that each block with a setjmp is broken up into two parts: the
+/// part containing setjmp and the part right after the setjmp. The latter part
+/// is either reached from the setjmp, or later from a longjmp. To handle the
+/// longjmp, all calls that might longjmp are also called using invoke wrappers
+/// and thus JS / try-catch. JS longjmp() function also sets some variables so
+/// we can check / whether a longjmp occurred from wasm code. Each block with a
+/// function call that might longjmp is also split up after the longjmp call.
+/// After the longjmp call, we check whether a longjmp occurred, and if it did,
+/// which setjmp it corresponds to, and jump to the right post-setjmp block.
+/// We assume setjmp-longjmp handling always run after EH handling, which means
+/// we don't expect any exception-related instructions when SjLj runs.
+/// FIXME Currently this scheme does not support indirect call of setjmp,
+/// because of the limitation of the scheme itself. fastcomp does not support it
+/// either.
+///
+/// In detail, this pass does following things:
+///
+/// 1) Create three global variables: __THREW__, __threwValue, and __tempRet0.
+/// __tempRet0 will be set within __cxa_find_matching_catch() function in
+/// JS library, and __THREW__ and __threwValue will be set in invoke wrappers
+/// in JS glue code. For what invoke wrappers are, refer to 3). These
+/// variables are used for both exceptions and setjmp/longjmps.
+/// __THREW__ indicates whether an exception or a longjmp occurred or not. 0
+/// means nothing occurred, 1 means an exception occurred, and other numbers
+/// mean a longjmp occurred. In the case of longjmp, __threwValue variable
+/// indicates the corresponding setjmp buffer the longjmp corresponds to.
+/// In exception handling, __tempRet0 indicates the type of an exception
+/// caught, and in setjmp/longjmp, it means the second argument to longjmp
+/// function.
+///
+/// * Exception handling
+///
+/// 2) Create setThrew and setTempRet0 functions.
+/// The global variables created in 1) will exist in wasm address space,
+/// but their values should be set in JS code, so we provide these functions
+/// as interfaces to JS glue code. These functions are equivalent to the
+/// following JS functions, which actually exist in asm.js version of JS
+/// library.
+///
+/// function setThrew(threw, value) {
+/// if (__THREW__ == 0) {
+/// __THREW__ = threw;
+/// __threwValue = value;
+/// }
+/// }
+///
+/// function setTempRet0(value) {
+/// __tempRet0 = value;
+/// }
+///
+/// 3) Lower
+/// invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
+/// into
+/// __THREW__ = 0;
+/// call @__invoke_SIG(func, arg1, arg2)
+/// %__THREW__.val = __THREW__;
+/// __THREW__ = 0;
+/// if (%__THREW__.val == 1)
+/// goto %lpad
+/// else
+/// goto %invoke.cont
+/// SIG is a mangled string generated based on the LLVM IR-level function
+/// signature. After LLVM IR types are lowered to the target wasm types,
+/// the names for these wrappers will change based on wasm types as well,
+/// as in invoke_vi (function takes an int and returns void). The bodies of
+/// these wrappers will be generated in JS glue code, and inside those
+/// wrappers we use JS try-catch to generate actual exception effects. It
+/// also calls the original callee function. An example wrapper in JS code
+/// would look like this:
+/// function invoke_vi(index,a1) {
+/// try {
+/// Module["dynCall_vi"](index,a1); // This calls original callee
+/// } catch(e) {
+/// if (typeof e !== 'number' && e !== 'longjmp') throw e;
+/// asm["setThrew"](1, 0); // setThrew is called here
+/// }
+/// }
+/// If an exception is thrown, __THREW__ will be set to true in a wrapper,
+/// so we can jump to the right BB based on this value.
+///
+/// 4) Lower
+/// %val = landingpad catch c1 catch c2 catch c3 ...
+/// ... use %val ...
+/// into
+/// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
+/// %val = {%fmc, __tempRet0}
+/// ... use %val ...
+/// Here N is a number calculated based on the number of clauses.
+/// Global variable __tempRet0 is set within __cxa_find_matching_catch() in
+/// JS glue code.
+///
+/// 5) Lower
+/// resume {%a, %b}
+/// into
+/// call @__resumeException(%a)
+/// where __resumeException() is a function in JS glue code.
+///
+/// 6) Lower
+/// call @llvm.eh.typeid.for(type) (intrinsic)
+/// into
+/// call @llvm_eh_typeid_for(type)
+/// llvm_eh_typeid_for function will be generated in JS glue code.
+///
+/// * Setjmp / Longjmp handling
+///
+/// 7) In the function entry that calls setjmp, initialize setjmpTable and
+/// sejmpTableSize as follows:
+/// setjmpTableSize = 4;
+/// setjmpTable = (int *) malloc(40);
+/// setjmpTable[0] = 0;
+/// setjmpTable and setjmpTableSize are used in saveSetjmp() function in JS
+/// code.
+///
+/// 8) Lower
+/// setjmp(buf)
+/// into
+/// setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
+/// setjmpTableSize = __tempRet0;
+/// For each dynamic setjmp call, setjmpTable stores its ID (a number which
+/// is incrementally assigned from 0) and its label (a unique number that
+/// represents each callsite of setjmp). When we need more entries in
+/// setjmpTable, it is reallocated in saveSetjmp() in JS code and it will
+/// return the new table address, and assign the new table size in
+/// __tempRet0. saveSetjmp also stores the setjmp's ID into the buffer buf.
+/// A BB with setjmp is split into two after setjmp call in order to make the
+/// post-setjmp BB the possible destination of longjmp BB.
+///
+/// 9) Lower
+/// longjmp(buf, value)
+/// into
+/// emscripten_longjmp_jmpbuf(buf, value)
+/// emscripten_longjmp_jmpbuf will be lowered to emscripten_longjmp later.
+///
+/// 10) Lower every call that might longjmp into
+/// __THREW__ = 0;
+/// call @__invoke_SIG(func, arg1, arg2)
+/// %__THREW__.val = __THREW__;
+/// __THREW__ = 0;
+/// if (%__THREW__.val != 0 & __threwValue != 0) {
+/// %label = testSetjmp(mem[%__THREW__.val], setjmpTable,
+/// setjmpTableSize);
+/// if (%label == 0)
+/// emscripten_longjmp(%__THREW__.val, __threwValue);
+/// __tempRet0 = __threwValue;
+/// } else {
+/// %label = -1;
+/// }
+/// longjmp_result = __tempRet0;
+/// switch label {
+/// label 1: goto post-setjmp BB 1
+/// label 2: goto post-setjmp BB 2
+/// ...
+/// default: goto splitted next BB
+/// }
+/// testSetjmp examines setjmpTable to see if there is a matching setjmp
+/// call. After calling an invoke wrapper, if a longjmp occurred, __THREW__
+/// will be the address of matching jmp_buf buffer and __threwValue be the
+/// second argument to longjmp. mem[__THREW__.val] is a setjmp ID that is
+/// stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to
+/// each setjmp callsite. Label 0 means this longjmp buffer does not
+/// correspond to one of the setjmp callsites in this function, so in this
+/// case we just chain the longjmp to the caller. (Here we call
+/// emscripten_longjmp, which is different from emscripten_longjmp_jmpbuf.
+/// emscripten_longjmp_jmpbuf takes jmp_buf as its first argument, while
+/// emscripten_longjmp takes an int. Both of them will eventually be lowered
+/// to emscripten_longjmp in s2wasm, but here we need two signatures - we
+/// can't translate an int value to a jmp_buf.)
+/// Label -1 means no longjmp occurred. Otherwise we jump to the right
+/// post-setjmp BB based on the label.
+///
+///===----------------------------------------------------------------------===//
+
+#include "WebAssembly.h"
+#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/SSAUpdater.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-lower-em-ehsjlj"
+
+static cl::list<std::string>
+ EHWhitelist("emscripten-cxx-exceptions-whitelist",
+ cl::desc("The list of function names in which Emscripten-style "
+ "exception handling is enabled (see emscripten "
+ "EMSCRIPTEN_CATCHING_WHITELIST options)"),
+ cl::CommaSeparated);
+
+namespace {
+class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
+ static const char *ThrewGVName;
+ static const char *ThrewValueGVName;
+ static const char *TempRet0GVName;
+ static const char *ResumeFName;
+ static const char *EHTypeIDFName;
+ static const char *SetThrewFName;
+ static const char *SetTempRet0FName;
+ static const char *EmLongjmpFName;
+ static const char *EmLongjmpJmpbufFName;
+ static const char *SaveSetjmpFName;
+ static const char *TestSetjmpFName;
+ static const char *FindMatchingCatchPrefix;
+ static const char *InvokePrefix;
+
+ bool EnableEH; // Enable exception handling
+ bool EnableSjLj; // Enable setjmp/longjmp handling
+
+ GlobalVariable *ThrewGV;
+ GlobalVariable *ThrewValueGV;
+ GlobalVariable *TempRet0GV;
+ Function *ResumeF;
+ Function *EHTypeIDF;
+ Function *EmLongjmpF;
+ Function *EmLongjmpJmpbufF;
+ Function *SaveSetjmpF;
+ Function *TestSetjmpF;
+
+ // __cxa_find_matching_catch_N functions.
+ // Indexed by the number of clauses in an original landingpad instruction.
+ DenseMap<int, Function *> FindMatchingCatches;
+ // Map of <function signature string, invoke_ wrappers>
+ StringMap<Function *> InvokeWrappers;
+ // Set of whitelisted function names for exception handling
+ std::set<std::string> EHWhitelistSet;
+
+ StringRef getPassName() const override {
+ return "WebAssembly Lower Emscripten Exceptions";
+ }
+
+ bool runEHOnFunction(Function &F);
+ bool runSjLjOnFunction(Function &F);
+ Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
+
+ template <typename CallOrInvoke> Value *wrapInvoke(CallOrInvoke *CI);
+ void wrapTestSetjmp(BasicBlock *BB, Instruction *InsertPt, Value *Threw,
+ Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label,
+ Value *&LongjmpResult, BasicBlock *&EndBB);
+ template <typename CallOrInvoke> Function *getInvokeWrapper(CallOrInvoke *CI);
+
+ bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); }
+ bool canLongjmp(Module &M, const Value *Callee) const;
+
+ void createSetThrewFunction(Module &M);
+ void createSetTempRet0Function(Module &M);
+
+ void rebuildSSA(Function &F);
+
+public:
+ static char ID;
+
+ WebAssemblyLowerEmscriptenEHSjLj(bool EnableEH = true, bool EnableSjLj = true)
+ : ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
+ ThrewGV(nullptr), ThrewValueGV(nullptr), TempRet0GV(nullptr),
+ ResumeF(nullptr), EHTypeIDF(nullptr), EmLongjmpF(nullptr),
+ EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr), TestSetjmpF(nullptr) {
+ EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end());
+ }
+ bool runOnModule(Module &M) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<DominatorTreeWrapperPass>();
+ }
+};
+} // End anonymous namespace
+
+const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewGVName = "__THREW__";
+const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewValueGVName = "__threwValue";
+const char *WebAssemblyLowerEmscriptenEHSjLj::TempRet0GVName = "__tempRet0";
+const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException";
+const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName =
+ "llvm_eh_typeid_for";
+const char *WebAssemblyLowerEmscriptenEHSjLj::SetThrewFName = "setThrew";
+const char *WebAssemblyLowerEmscriptenEHSjLj::SetTempRet0FName = "setTempRet0";
+const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName =
+ "emscripten_longjmp";
+const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName =
+ "emscripten_longjmp_jmpbuf";
+const char *WebAssemblyLowerEmscriptenEHSjLj::SaveSetjmpFName = "saveSetjmp";
+const char *WebAssemblyLowerEmscriptenEHSjLj::TestSetjmpFName = "testSetjmp";
+const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
+ "__cxa_find_matching_catch_";
+const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_";
+
+char WebAssemblyLowerEmscriptenEHSjLj::ID = 0;
+INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
+ "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
+ false, false)
+
+ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj(bool EnableEH,
+ bool EnableSjLj) {
+ return new WebAssemblyLowerEmscriptenEHSjLj(EnableEH, EnableSjLj);
+}
+
+static bool canThrow(const Value *V) {
+ if (const auto *F = dyn_cast<const Function>(V)) {
+ // Intrinsics cannot throw
+ if (F->isIntrinsic())
+ return false;
+ StringRef Name = F->getName();
+ // leave setjmp and longjmp (mostly) alone, we process them properly later
+ if (Name == "setjmp" || Name == "longjmp")
+ return false;
+ return !F->doesNotThrow();
+ }
+ // not a function, so an indirect call - can throw, we can't tell
+ return true;
+}
+
+// Returns an available name for a global value.
+// If the proposed name already exists in the module, adds '_' at the end of
+// the name until the name is available.
+static inline std::string createGlobalValueName(const Module &M,
+ const std::string &Propose) {
+ std::string Name = Propose;
+ while (M.getNamedGlobal(Name))
+ Name += "_";
+ return Name;
+}
+
+// Simple function name mangler.
+// This function simply takes LLVM's string representation of parameter types
+// and concatenate them with '_'. There are non-alphanumeric characters but llc
+// is ok with it, and we need to postprocess these names after the lowering
+// phase anyway.
+static std::string getSignature(FunctionType *FTy) {
+ std::string Sig;
+ raw_string_ostream OS(Sig);
+ OS << *FTy->getReturnType();
+ for (Type *ParamTy : FTy->params())
+ OS << "_" << *ParamTy;
+ if (FTy->isVarArg())
+ OS << "_...";
+ Sig = OS.str();
+ Sig.erase(remove_if(Sig, isspace), Sig.end());
+ // When s2wasm parses .s file, a comma means the end of an argument. So a
+ // mangled function name can contain any character but a comma.
+ std::replace(Sig.begin(), Sig.end(), ',', '.');
+ return Sig;
+}
+
+// Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
+// This is because a landingpad instruction contains two more arguments, a
+// personality function and a cleanup bit, and __cxa_find_matching_catch_N
+// functions are named after the number of arguments in the original landingpad
+// instruction.
+Function *
+WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
+ unsigned NumClauses) {
+ if (FindMatchingCatches.count(NumClauses))
+ return FindMatchingCatches[NumClauses];
+ PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
+ SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
+ FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
+ Function *F =
+ Function::Create(FTy, GlobalValue::ExternalLinkage,
+ FindMatchingCatchPrefix + Twine(NumClauses + 2), &M);
+ FindMatchingCatches[NumClauses] = F;
+ return F;
+}
+
+// Generate invoke wrapper seqence with preamble and postamble
+// Preamble:
+// __THREW__ = 0;
+// Postamble:
+// %__THREW__.val = __THREW__; __THREW__ = 0;
+// Returns %__THREW__.val, which indicates whether an exception is thrown (or
+// whether longjmp occurred), for future use.
+template <typename CallOrInvoke>
+Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
+ LLVMContext &C = CI->getModule()->getContext();
+
+ // If we are calling a function that is noreturn, we must remove that
+ // attribute. The code we insert here does expect it to return, after we
+ // catch the exception.
+ if (CI->doesNotReturn()) {
+ if (auto *F = dyn_cast<Function>(CI->getCalledValue()))
+ F->removeFnAttr(Attribute::NoReturn);
+ CI->removeAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn);
+ }
+
+ IRBuilder<> IRB(C);
+ IRB.SetInsertPoint(CI);
+
+ // Pre-invoke
+ // __THREW__ = 0;
+ IRB.CreateStore(IRB.getInt32(0), ThrewGV);
+
+ // Invoke function wrapper in JavaScript
+ SmallVector<Value *, 16> Args;
+ // Put the pointer to the callee as first argument, so it can be called
+ // within the invoke wrapper later
+ Args.push_back(CI->getCalledValue());
+ Args.append(CI->arg_begin(), CI->arg_end());
+ CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
+ NewCall->takeName(CI);
+ NewCall->setCallingConv(CI->getCallingConv());
+ NewCall->setDebugLoc(CI->getDebugLoc());
+
+ // Because we added the pointer to the callee as first argument, all
+ // argument attribute indices have to be incremented by one.
+ SmallVector<AttributeSet, 8> AttributesVec;
+ const AttributeSet &InvokePAL = CI->getAttributes();
+ CallSite::arg_iterator AI = CI->arg_begin();
+ unsigned i = 1; // Argument attribute index starts from 1
+ for (unsigned e = CI->getNumArgOperands(); i <= e; ++AI, ++i) {
+ if (InvokePAL.hasAttributes(i)) {
+ AttrBuilder B(InvokePAL, i);
+ AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
+ }
+ }
+ // Add any return attributes.
+ if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
+ AttributesVec.push_back(AttributeSet::get(C, InvokePAL.getRetAttributes()));
+ // Add any function attributes.
+ if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
+ AttributesVec.push_back(AttributeSet::get(C, InvokePAL.getFnAttributes()));
+ // Reconstruct the AttributesList based on the vector we constructed.
+ AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
+ NewCall->setAttributes(NewCallPAL);
+
+ CI->replaceAllUsesWith(NewCall);
+
+ // Post-invoke
+ // %__THREW__.val = __THREW__; __THREW__ = 0;
+ Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
+ IRB.CreateStore(IRB.getInt32(0), ThrewGV);
+ return Threw;
+}
+
+// Get matching invoke wrapper based on callee signature
+template <typename CallOrInvoke>
+Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallOrInvoke *CI) {
+ Module *M = CI->getModule();
+ SmallVector<Type *, 16> ArgTys;
+ Value *Callee = CI->getCalledValue();
+ FunctionType *CalleeFTy;
+ if (auto *F = dyn_cast<Function>(Callee))
+ CalleeFTy = F->getFunctionType();
+ else {
+ auto *CalleeTy = cast<PointerType>(Callee->getType())->getElementType();
+ CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
+ }
+
+ std::string Sig = getSignature(CalleeFTy);
+ if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
+ return InvokeWrappers[Sig];
+
+ // Put the pointer to the callee as first argument
+ ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
+ // Add argument types
+ ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
+
+ FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
+ CalleeFTy->isVarArg());
+ Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
+ InvokePrefix + Sig, M);
+ InvokeWrappers[Sig] = F;
+ return F;
+}
+
+bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
+ const Value *Callee) const {
+ if (auto *CalleeF = dyn_cast<Function>(Callee))
+ if (CalleeF->isIntrinsic())
+ return false;
+
+ // The reason we include malloc/free here is to exclude the malloc/free
+ // calls generated in setjmp prep / cleanup routines.
+ Function *SetjmpF = M.getFunction("setjmp");
+ Function *MallocF = M.getFunction("malloc");
+ Function *FreeF = M.getFunction("free");
+ if (Callee == SetjmpF || Callee == MallocF || Callee == FreeF)
+ return false;
+
+ // There are functions in JS glue code
+ if (Callee == ResumeF || Callee == EHTypeIDF || Callee == SaveSetjmpF ||
+ Callee == TestSetjmpF)
+ return false;
+
+ // __cxa_find_matching_catch_N functions cannot longjmp
+ if (Callee->getName().startswith(FindMatchingCatchPrefix))
+ return false;
+
+ // Exception-catching related functions
+ Function *BeginCatchF = M.getFunction("__cxa_begin_catch");
+ Function *EndCatchF = M.getFunction("__cxa_end_catch");
+ Function *AllocExceptionF = M.getFunction("__cxa_allocate_exception");
+ Function *ThrowF = M.getFunction("__cxa_throw");
+ Function *TerminateF = M.getFunction("__clang_call_terminate");
+ if (Callee == BeginCatchF || Callee == EndCatchF ||
+ Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF)
+ return false;
+
+ // Otherwise we don't know
+ return true;
+}
+
+// Generate testSetjmp function call seqence with preamble and postamble.
+// The code this generates is equivalent to the following JavaScript code:
+// if (%__THREW__.val != 0 & threwValue != 0) {
+// %label = _testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
+// if (%label == 0)
+// emscripten_longjmp(%__THREW__.val, threwValue);
+// __tempRet0 = threwValue;
+// } else {
+// %label = -1;
+// }
+// %longjmp_result = __tempRet0;
+//
+// As output parameters. returns %label, %longjmp_result, and the BB the last
+// instruction (%longjmp_result = ...) is in.
+void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
+ BasicBlock *BB, Instruction *InsertPt, Value *Threw, Value *SetjmpTable,
+ Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
+ BasicBlock *&EndBB) {
+ Function *F = BB->getParent();
+ LLVMContext &C = BB->getModule()->getContext();
+ IRBuilder<> IRB(C);
+ IRB.SetInsertPoint(InsertPt);
+
+ // if (%__THREW__.val != 0 & threwValue != 0)
+ IRB.SetInsertPoint(BB);
+ BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
+ BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
+ BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
+ Value *ThrewCmp = IRB.CreateICmpNE(Threw, IRB.getInt32(0));
+ Value *ThrewValue =
+ IRB.CreateLoad(ThrewValueGV, ThrewValueGV->getName() + ".val");
+ Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
+ Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
+ IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
+
+ // %label = _testSetjmp(mem[%__THREW__.val], _setjmpTable, _setjmpTableSize);
+ // if (%label == 0)
+ IRB.SetInsertPoint(ThenBB1);
+ BasicBlock *ThenBB2 = BasicBlock::Create(C, "if.then2", F);
+ BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
+ Value *ThrewInt = IRB.CreateIntToPtr(Threw, Type::getInt32PtrTy(C),
+ Threw->getName() + ".i32p");
+ Value *LoadedThrew =
+ IRB.CreateLoad(ThrewInt, ThrewInt->getName() + ".loaded");
+ Value *ThenLabel = IRB.CreateCall(
+ TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
+ Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
+ IRB.CreateCondBr(Cmp2, ThenBB2, EndBB2);
+
+ // emscripten_longjmp(%__THREW__.val, threwValue);
+ IRB.SetInsertPoint(ThenBB2);
+ IRB.CreateCall(EmLongjmpF, {Threw, ThrewValue});
+ IRB.CreateUnreachable();
+
+ // __tempRet0 = threwValue;
+ IRB.SetInsertPoint(EndBB2);
+ IRB.CreateStore(ThrewValue, TempRet0GV);
+ IRB.CreateBr(EndBB1);
+
+ IRB.SetInsertPoint(ElseBB1);
+ IRB.CreateBr(EndBB1);
+
+ // longjmp_result = __tempRet0;
+ IRB.SetInsertPoint(EndBB1);
+ PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
+ LabelPHI->addIncoming(ThenLabel, EndBB2);
+
+ LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
+
+ // Output parameter assignment
+ Label = LabelPHI;
+ EndBB = EndBB1;
+ LongjmpResult = IRB.CreateLoad(TempRet0GV, "longjmp_result");
+}
+
+// Create setThrew function
+// function setThrew(threw, value) {
+// if (__THREW__ == 0) {
+// __THREW__ = threw;
+// __threwValue = value;
+// }
+// }
+void WebAssemblyLowerEmscriptenEHSjLj::createSetThrewFunction(Module &M) {
+ LLVMContext &C = M.getContext();
+ IRBuilder<> IRB(C);
+
+ assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists");
+ Type *Params[] = {IRB.getInt32Ty(), IRB.getInt32Ty()};
+ FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false);
+ Function *F =
+ Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M);
+ Argument *Arg1 = &*(F->arg_begin());
+ Argument *Arg2 = &*(++F->arg_begin());
+ Arg1->setName("threw");
+ Arg2->setName("value");
+ BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
+ BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
+ BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
+
+ IRB.SetInsertPoint(EntryBB);
+ Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
+ Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(0), "cmp");
+ IRB.CreateCondBr(Cmp, ThenBB, EndBB);
+
+ IRB.SetInsertPoint(ThenBB);
+ IRB.CreateStore(Arg1, ThrewGV);
+ IRB.CreateStore(Arg2, ThrewValueGV);
+ IRB.CreateBr(EndBB);
+
+ IRB.SetInsertPoint(EndBB);
+ IRB.CreateRetVoid();
+}
+
+// Create setTempRet0 function
+// function setTempRet0(value) {
+// __tempRet0 = value;
+// }
+void WebAssemblyLowerEmscriptenEHSjLj::createSetTempRet0Function(Module &M) {
+ LLVMContext &C = M.getContext();
+ IRBuilder<> IRB(C);
+
+ assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists");
+ Type *Params[] = {IRB.getInt32Ty()};
+ FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false);
+ Function *F =
+ Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M);
+ F->arg_begin()->setName("value");
+ BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
+ IRB.SetInsertPoint(EntryBB);
+ IRB.CreateStore(&*F->arg_begin(), TempRet0GV);
+ IRB.CreateRetVoid();
+}
+
+void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
+ DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
+ DT.recalculate(F); // CFG has been changed
+ SSAUpdater SSA;
+ for (BasicBlock &BB : F) {
+ for (Instruction &I : BB) {
+ for (auto UI = I.use_begin(), UE = I.use_end(); UI != UE;) {
+ Use &U = *UI;
+ ++UI;
+ SSA.Initialize(I.getType(), I.getName());
+ SSA.AddAvailableValue(&BB, &I);
+ Instruction *User = cast<Instruction>(U.getUser());
+ if (User->getParent() == &BB)
+ continue;
+
+ if (PHINode *UserPN = dyn_cast<PHINode>(User))
+ if (UserPN->getIncomingBlock(U) == &BB)
+ continue;
+
+ if (DT.dominates(&I, User))
+ continue;
+ SSA.RewriteUseAfterInsertions(U);
+ }
+ }
+ }
+}
+
+bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
+ LLVMContext &C = M.getContext();
+ IRBuilder<> IRB(C);
+
+ Function *SetjmpF = M.getFunction("setjmp");
+ Function *LongjmpF = M.getFunction("longjmp");
+ bool SetjmpUsed = SetjmpF && !SetjmpF->use_empty();
+ bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
+ bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
+
+ // Create global variables __THREW__, threwValue, and __tempRet0, which are
+ // used in common for both exception handling and setjmp/longjmp handling
+ ThrewGV = new GlobalVariable(M, IRB.getInt32Ty(), false,
+ GlobalValue::ExternalLinkage, IRB.getInt32(0),
+ createGlobalValueName(M, ThrewGVName));
+ ThrewValueGV = new GlobalVariable(
+ M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage, IRB.getInt32(0),
+ createGlobalValueName(M, ThrewValueGVName));
+ TempRet0GV = new GlobalVariable(M, IRB.getInt32Ty(), false,
+ GlobalValue::ExternalLinkage, IRB.getInt32(0),
+ createGlobalValueName(M, TempRet0GVName));
+
+ bool Changed = false;
+
+ // Exception handling
+ if (EnableEH) {
+ // Register __resumeException function
+ FunctionType *ResumeFTy =
+ FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
+ ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
+ ResumeFName, &M);
+
+ // Register llvm_eh_typeid_for function
+ FunctionType *EHTypeIDTy =
+ FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
+ EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
+ EHTypeIDFName, &M);
+
+ for (Function &F : M) {
+ if (F.isDeclaration())
+ continue;
+ Changed |= runEHOnFunction(F);
+ }
+ }
+
+ // Setjmp/longjmp handling
+ if (DoSjLj) {
+ Changed = true; // We have setjmp or longjmp somewhere
+
+ Function *MallocF = M.getFunction("malloc");
+ Function *FreeF = M.getFunction("free");
+ if (!MallocF || !FreeF)
+ report_fatal_error(
+ "malloc and free must be linked into the module if setjmp is used");
+
+ // Register saveSetjmp function
+ FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
+ SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0),
+ IRB.getInt32Ty(), Type::getInt32PtrTy(C),
+ IRB.getInt32Ty()};
+ FunctionType *FTy =
+ FunctionType::get(Type::getInt32PtrTy(C), Params, false);
+ SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
+ SaveSetjmpFName, &M);
+
+ // Register testSetjmp function
+ Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()};
+ FTy = FunctionType::get(IRB.getInt32Ty(), Params, false);
+ TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
+ TestSetjmpFName, &M);
+
+ if (LongjmpF) {
+ // Replace all uses of longjmp with emscripten_longjmp_jmpbuf, which is
+ // defined in JS code
+ EmLongjmpJmpbufF = Function::Create(LongjmpF->getFunctionType(),
+ GlobalValue::ExternalLinkage,
+ EmLongjmpJmpbufFName, &M);
+
+ LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF);
+ }
+ FTy = FunctionType::get(IRB.getVoidTy(),
+ {IRB.getInt32Ty(), IRB.getInt32Ty()}, false);
+ EmLongjmpF =
+ Function::Create(FTy, GlobalValue::ExternalLinkage, EmLongjmpFName, &M);
+
+ // Only traverse functions that uses setjmp in order not to insert
+ // unnecessary prep / cleanup code in every function
+ SmallPtrSet<Function *, 8> SetjmpUsers;
+ for (User *U : SetjmpF->users()) {
+ auto *UI = cast<Instruction>(U);
+ SetjmpUsers.insert(UI->getFunction());
+ }
+ for (Function *F : SetjmpUsers)
+ runSjLjOnFunction(*F);
+ }
+
+ if (!Changed) {
+ // Delete unused global variables and functions
+ ThrewGV->eraseFromParent();
+ ThrewValueGV->eraseFromParent();
+ TempRet0GV->eraseFromParent();
+ if (ResumeF)
+ ResumeF->eraseFromParent();
+ if (EHTypeIDF)
+ EHTypeIDF->eraseFromParent();
+ if (EmLongjmpF)
+ EmLongjmpF->eraseFromParent();
+ if (SaveSetjmpF)
+ SaveSetjmpF->eraseFromParent();
+ if (TestSetjmpF)
+ TestSetjmpF->eraseFromParent();
+ return false;
+ }
+
+ // If we have made any changes while doing exception handling or
+ // setjmp/longjmp handling, we have to create these functions for JavaScript
+ // to call.
+ createSetThrewFunction(M);
+ createSetTempRet0Function(M);
+
+ return true;
+}
+
+bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
+ Module &M = *F.getParent();
+ LLVMContext &C = F.getContext();
+ IRBuilder<> IRB(C);
+ bool Changed = false;
+ SmallVector<Instruction *, 64> ToErase;
+ SmallPtrSet<LandingPadInst *, 32> LandingPads;
+ bool AllowExceptions =
+ areAllExceptionsAllowed() || EHWhitelistSet.count(F.getName());
+
+ for (BasicBlock &BB : F) {
+ auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
+ if (!II)
+ continue;
+ Changed = true;
+ LandingPads.insert(II->getLandingPadInst());
+ IRB.SetInsertPoint(II);
+
+ bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
+ if (NeedInvoke) {
+ // Wrap invoke with invoke wrapper and generate preamble/postamble
+ Value *Threw = wrapInvoke(II);
+ ToErase.push_back(II);
+
+ // Insert a branch based on __THREW__ variable
+ Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(1), "cmp");
+ IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
+
+ } else {
+ // This can't throw, and we don't need this invoke, just replace it with a
+ // call+branch
+ SmallVector<Value *, 16> Args(II->arg_begin(), II->arg_end());
+ CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), Args);
+ NewCall->takeName(II);
+ NewCall->setCallingConv(II->getCallingConv());
+ NewCall->setDebugLoc(II->getDebugLoc());
+ NewCall->setAttributes(II->getAttributes());
+ II->replaceAllUsesWith(NewCall);
+ ToErase.push_back(II);
+
+ IRB.CreateBr(II->getNormalDest());
+
+ // Remove any PHI node entries from the exception destination
+ II->getUnwindDest()->removePredecessor(&BB);
+ }
+ }
+
+ // Process resume instructions
+ for (BasicBlock &BB : F) {
+ // Scan the body of the basic block for resumes
+ for (Instruction &I : BB) {
+ auto *RI = dyn_cast<ResumeInst>(&I);
+ if (!RI)
+ continue;
+
+ // Split the input into legal values
+ Value *Input = RI->getValue();
+ IRB.SetInsertPoint(RI);
+ Value *Low = IRB.CreateExtractValue(Input, 0, "low");
+ // Create a call to __resumeException function
+ IRB.CreateCall(ResumeF, {Low});
+ // Add a terminator to the block
+ IRB.CreateUnreachable();
+ ToErase.push_back(RI);
+ }
+ }
+
+ // Process llvm.eh.typeid.for intrinsics
+ for (BasicBlock &BB : F) {
+ for (Instruction &I : BB) {
+ auto *CI = dyn_cast<CallInst>(&I);
+ if (!CI)
+ continue;
+ const Function *Callee = CI->getCalledFunction();
+ if (!Callee)
+ continue;
+ if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
+ continue;
+
+ IRB.SetInsertPoint(CI);
+ CallInst *NewCI =
+ IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
+ CI->replaceAllUsesWith(NewCI);
+ ToErase.push_back(CI);
+ }
+ }
+
+ // Look for orphan landingpads, can occur in blocks with no predecesors
+ for (BasicBlock &BB : F) {
+ Instruction *I = BB.getFirstNonPHI();
+ if (auto *LPI = dyn_cast<LandingPadInst>(I))
+ LandingPads.insert(LPI);
+ }
+
+ // Handle all the landingpad for this function together, as multiple invokes
+ // may share a single lp
+ for (LandingPadInst *LPI : LandingPads) {
+ IRB.SetInsertPoint(LPI);
+ SmallVector<Value *, 16> FMCArgs;
+ for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
+ Constant *Clause = LPI->getClause(i);
+ // As a temporary workaround for the lack of aggregate varargs support
+ // in the interface between JS and wasm, break out filter operands into
+ // their component elements.
+ if (LPI->isFilter(i)) {
+ auto *ATy = cast<ArrayType>(Clause->getType());
+ for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
+ Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter");
+ FMCArgs.push_back(EV);
+ }
+ } else
+ FMCArgs.push_back(Clause);
+ }
+
+ // Create a call to __cxa_find_matching_catch_N function
+ Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
+ CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
+ Value *Undef = UndefValue::get(LPI->getType());
+ Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
+ Value *TempRet0 =
+ IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + ".val");
+ Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
+
+ LPI->replaceAllUsesWith(Pair1);
+ ToErase.push_back(LPI);
+ }
+
+ // Erase everything we no longer need in this function
+ for (Instruction *I : ToErase)
+ I->eraseFromParent();
+
+ return Changed;
+}
+
+bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
+ Module &M = *F.getParent();
+ LLVMContext &C = F.getContext();
+ IRBuilder<> IRB(C);
+ SmallVector<Instruction *, 64> ToErase;
+ // Vector of %setjmpTable values
+ std::vector<Instruction *> SetjmpTableInsts;
+ // Vector of %setjmpTableSize values
+ std::vector<Instruction *> SetjmpTableSizeInsts;
+
+ // Setjmp preparation
+
+ // This instruction effectively means %setjmpTableSize = 4.
+ // We create this as an instruction intentionally, and we don't want to fold
+ // this instruction to a constant 4, because this value will be used in
+ // SSAUpdater.AddAvailableValue(...) later.
+ BasicBlock &EntryBB = F.getEntryBlock();
+ BinaryOperator *SetjmpTableSize = BinaryOperator::Create(
+ Instruction::Add, IRB.getInt32(4), IRB.getInt32(0), "setjmpTableSize",
+ &*EntryBB.getFirstInsertionPt());
+ // setjmpTable = (int *) malloc(40);
+ Instruction *SetjmpTable = CallInst::CreateMalloc(
+ SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
+ nullptr, nullptr, "setjmpTable");
+ // setjmpTable[0] = 0;
+ IRB.SetInsertPoint(SetjmpTableSize);
+ IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
+ SetjmpTableInsts.push_back(SetjmpTable);
+ SetjmpTableSizeInsts.push_back(SetjmpTableSize);
+
+ // Setjmp transformation
+ std::vector<PHINode *> SetjmpRetPHIs;
+ Function *SetjmpF = M.getFunction("setjmp");
+ for (User *U : SetjmpF->users()) {
+ auto *CI = dyn_cast<CallInst>(U);
+ if (!CI)
+ report_fatal_error("Does not support indirect calls to setjmp");
+
+ BasicBlock *BB = CI->getParent();
+ if (BB->getParent() != &F) // in other function
+ continue;
+
+ // The tail is everything right after the call, and will be reached once
+ // when setjmp is called, and later when longjmp returns to the setjmp
+ BasicBlock *Tail = SplitBlock(BB, CI->getNextNode());
+ // Add a phi to the tail, which will be the output of setjmp, which
+ // indicates if this is the first call or a longjmp back. The phi directly
+ // uses the right value based on where we arrive from
+ IRB.SetInsertPoint(Tail->getFirstNonPHI());
+ PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
+
+ // setjmp initial call returns 0
+ SetjmpRet->addIncoming(IRB.getInt32(0), BB);
+ // The proper output is now this, not the setjmp call itself
+ CI->replaceAllUsesWith(SetjmpRet);
+ // longjmp returns to the setjmp will add themselves to this phi
+ SetjmpRetPHIs.push_back(SetjmpRet);
+
+ // Fix call target
+ // Our index in the function is our place in the array + 1 to avoid index
+ // 0, because index 0 means the longjmp is not ours to handle.
+ IRB.SetInsertPoint(CI);
+ Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
+ SetjmpTable, SetjmpTableSize};
+ Instruction *NewSetjmpTable =
+ IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
+ Instruction *NewSetjmpTableSize =
+ IRB.CreateLoad(TempRet0GV, "setjmpTableSize");
+ SetjmpTableInsts.push_back(NewSetjmpTable);
+ SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
+ ToErase.push_back(CI);
+ }
+
+ // Update each call that can longjmp so it can return to a setjmp where
+ // relevant.
+
+ // Because we are creating new BBs while processing and don't want to make
+ // all these newly created BBs candidates again for longjmp processing, we
+ // first make the vector of candidate BBs.
+ std::vector<BasicBlock *> BBs;
+ for (BasicBlock &BB : F)
+ BBs.push_back(&BB);
+
+ // BBs.size() will change within the loop, so we query it every time
+ for (unsigned i = 0; i < BBs.size(); i++) {
+ BasicBlock *BB = BBs[i];
+ for (Instruction &I : *BB) {
+ assert(!isa<InvokeInst>(&I));
+ auto *CI = dyn_cast<CallInst>(&I);
+ if (!CI)
+ continue;
+
+ const Value *Callee = CI->getCalledValue();
+ if (!canLongjmp(M, Callee))
+ continue;
+
+ Value *Threw = nullptr;
+ BasicBlock *Tail;
+ if (Callee->getName().startswith(InvokePrefix)) {
+ // If invoke wrapper has already been generated for this call in
+ // previous EH phase, search for the load instruction
+ // %__THREW__.val = __THREW__;
+ // in postamble after the invoke wrapper call
+ LoadInst *ThrewLI = nullptr;
+ StoreInst *ThrewResetSI = nullptr;
+ for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
+ I != IE; ++I) {
+ if (auto *LI = dyn_cast<LoadInst>(I))
+ if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
+ if (GV == ThrewGV) {
+ Threw = ThrewLI = LI;
+ break;
+ }
+ }
+ // Search for the store instruction after the load above
+ // __THREW__ = 0;
+ for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
+ I != IE; ++I) {
+ if (auto *SI = dyn_cast<StoreInst>(I))
+ if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand()))
+ if (GV == ThrewGV && SI->getValueOperand() == IRB.getInt32(0)) {
+ ThrewResetSI = SI;
+ break;
+ }
+ }
+ assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
+ assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
+ Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
+
+ } else {
+ // Wrap call with invoke wrapper and generate preamble/postamble
+ Threw = wrapInvoke(CI);
+ ToErase.push_back(CI);
+ Tail = SplitBlock(BB, CI->getNextNode());
+ }
+
+ // We need to replace the terminator in Tail - SplitBlock makes BB go
+ // straight to Tail, we need to check if a longjmp occurred, and go to the
+ // right setjmp-tail if so
+ ToErase.push_back(BB->getTerminator());
+
+ // Generate a function call to testSetjmp function and preamble/postamble
+ // code to figure out (1) whether longjmp occurred (2) if longjmp
+ // occurred, which setjmp it corresponds to
+ Value *Label = nullptr;
+ Value *LongjmpResult = nullptr;
+ BasicBlock *EndBB = nullptr;
+ wrapTestSetjmp(BB, CI, Threw, SetjmpTable, SetjmpTableSize, Label,
+ LongjmpResult, EndBB);
+ assert(Label && LongjmpResult && EndBB);
+
+ // Create switch instruction
+ IRB.SetInsertPoint(EndBB);
+ SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
+ // -1 means no longjmp happened, continue normally (will hit the default
+ // switch case). 0 means a longjmp that is not ours to handle, needs a
+ // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
+ // 0).
+ for (unsigned i = 0; i < SetjmpRetPHIs.size(); i++) {
+ SI->addCase(IRB.getInt32(i + 1), SetjmpRetPHIs[i]->getParent());
+ SetjmpRetPHIs[i]->addIncoming(LongjmpResult, EndBB);
+ }
+
+ // We are splitting the block here, and must continue to find other calls
+ // in the block - which is now split. so continue to traverse in the Tail
+ BBs.push_back(Tail);
+ }
+ }
+
+ // Erase everything we no longer need in this function
+ for (Instruction *I : ToErase)
+ I->eraseFromParent();
+
+ // Free setjmpTable buffer before each return instruction
+ for (BasicBlock &BB : F) {
+ TerminatorInst *TI = BB.getTerminator();
+ if (isa<ReturnInst>(TI))
+ CallInst::CreateFree(SetjmpTable, TI);
+ }
+
+ // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
+ // (when buffer reallocation occurs)
+ // entry:
+ // setjmpTableSize = 4;
+ // setjmpTable = (int *) malloc(40);
+ // setjmpTable[0] = 0;
+ // ...
+ // somebb:
+ // setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
+ // setjmpTableSize = __tempRet0;
+ // So we need to make sure the SSA for these variables is valid so that every
+ // saveSetjmp and testSetjmp calls have the correct arguments.
+ SSAUpdater SetjmpTableSSA;
+ SSAUpdater SetjmpTableSizeSSA;
+ SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
+ SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
+ for (Instruction *I : SetjmpTableInsts)
+ SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
+ for (Instruction *I : SetjmpTableSizeInsts)
+ SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
+
+ for (auto UI = SetjmpTable->use_begin(), UE = SetjmpTable->use_end();
+ UI != UE;) {
+ // Grab the use before incrementing the iterator.
+ Use &U = *UI;
+ // Increment the iterator before removing the use from the list.
+ ++UI;
+ if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
+ if (I->getParent() != &EntryBB)
+ SetjmpTableSSA.RewriteUse(U);
+ }
+ for (auto UI = SetjmpTableSize->use_begin(), UE = SetjmpTableSize->use_end();
+ UI != UE;) {
+ Use &U = *UI;
+ ++UI;
+ if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
+ if (I->getParent() != &EntryBB)
+ SetjmpTableSizeSSA.RewriteUse(U);
+ }
+
+ // Finally, our modifications to the cfg can break dominance of SSA variables.
+ // For example, in this code,
+ // if (x()) { .. setjmp() .. }
+ // if (y()) { .. longjmp() .. }
+ // We must split the longjmp block, and it can jump into the block splitted
+ // from setjmp one. But that means that when we split the setjmp block, it's
+ // first part no longer dominates its second part - there is a theoretically
+ // possible control flow path where x() is false, then y() is true and we
+ // reach the second part of the setjmp block, without ever reaching the first
+ // part. So, we rebuild SSA form here.
+ rebuildSSA(F);
+ return true;
+}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
index 225c5d3..ccf6a18 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp
@@ -14,6 +14,9 @@
//===----------------------------------------------------------------------===//
#include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblyISelLowering.h"
+#include "WebAssemblySubtarget.h"
+#include "llvm/CodeGen/Analysis.h"
using namespace llvm;
WebAssemblyFunctionInfo::~WebAssemblyFunctionInfo() {}
@@ -23,3 +26,37 @@ void WebAssemblyFunctionInfo::initWARegs() {
unsigned Reg = UnusedReg;
WARegs.resize(MF.getRegInfo().getNumVirtRegs(), Reg);
}
+
+void llvm::ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
+ Type *Ty, SmallVectorImpl<MVT> &ValueVTs) {
+ const DataLayout &DL(F.getParent()->getDataLayout());
+ const WebAssemblyTargetLowering &TLI =
+ *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering();
+ SmallVector<EVT, 4> VTs;
+ ComputeValueVTs(TLI, DL, Ty, VTs);
+
+ for (EVT VT : VTs) {
+ unsigned NumRegs = TLI.getNumRegisters(F.getContext(), VT);
+ MVT RegisterVT = TLI.getRegisterType(F.getContext(), VT);
+ for (unsigned i = 0; i != NumRegs; ++i)
+ ValueVTs.push_back(RegisterVT);
+ }
+}
+
+void llvm::ComputeSignatureVTs(const Function &F, const TargetMachine &TM,
+ SmallVectorImpl<MVT> &Params,
+ SmallVectorImpl<MVT> &Results) {
+ ComputeLegalValueVTs(F, TM, F.getReturnType(), Results);
+
+ if (Results.size() > 1) {
+ // WebAssembly currently can't lower returns of multiple values without
+ // demoting to sret (see WebAssemblyTargetLowering::CanLowerReturn). So
+ // replace multiple return values with a pointer parameter.
+ Results.clear();
+ Params.push_back(
+ MVT::getIntegerVT(TM.createDataLayout().getPointerSizeInBits()));
+ }
+
+ for (auto &Arg : F.args())
+ ComputeLegalValueVTs(F, TM, Arg.getType(), Params);
+}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
index 89f607d..756619b 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
@@ -27,6 +27,8 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
MachineFunction &MF;
std::vector<MVT> Params;
+ std::vector<MVT> Results;
+ std::vector<MVT> Locals;
/// A mapping from CodeGen vreg index to WebAssembly register number.
std::vector<unsigned> WARegs;
@@ -44,6 +46,10 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
// TLI::LowerVASTART
unsigned VarargVreg = -1U;
+ // A virtual register holding the base pointer for functions that have
+ // overaligned values on the user stack.
+ unsigned BasePtrVreg = -1U;
+
public:
explicit WebAssemblyFunctionInfo(MachineFunction &MF) : MF(MF) {}
~WebAssemblyFunctionInfo() override;
@@ -51,15 +57,28 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
void addParam(MVT VT) { Params.push_back(VT); }
const std::vector<MVT> &getParams() const { return Params; }
+ void addResult(MVT VT) { Results.push_back(VT); }
+ const std::vector<MVT> &getResults() const { return Results; }
+
+ void addLocal(MVT VT) { Locals.push_back(VT); }
+ const std::vector<MVT> &getLocals() const { return Locals; }
+
unsigned getVarargBufferVreg() const {
assert(VarargVreg != -1U && "Vararg vreg hasn't been set");
return VarargVreg;
}
void setVarargBufferVreg(unsigned Reg) { VarargVreg = Reg; }
+ unsigned getBasePointerVreg() const {
+ assert(BasePtrVreg != -1U && "Base ptr vreg hasn't been set");
+ return BasePtrVreg;
+ }
+ void setBasePointerVreg(unsigned Reg) { BasePtrVreg = Reg; }
+
static const unsigned UnusedReg = -1u;
void stackifyVReg(unsigned VReg) {
+ assert(MF.getRegInfo().getUniqueVRegDef(VReg));
if (TargetRegisterInfo::virtReg2Index(VReg) >= VRegStackified.size())
VRegStackified.resize(TargetRegisterInfo::virtReg2Index(VReg) + 1);
VRegStackified.set(TargetRegisterInfo::virtReg2Index(VReg));
@@ -88,6 +107,13 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
}
};
+void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM,
+ Type *Ty, SmallVectorImpl<MVT> &ValueVTs);
+
+void ComputeSignatureVTs(const Function &F, const TargetMachine &TM,
+ SmallVectorImpl<MVT> &Params,
+ SmallVectorImpl<MVT> &Results);
+
} // end namespace llvm
#endif
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp
index 473de7d..5a3a741 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeLiveIntervals.cpp
@@ -34,7 +34,7 @@ using namespace llvm;
namespace {
class WebAssemblyOptimizeLiveIntervals final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Optimize Live Intervals";
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp
index 4dc401a..96520aa 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp
@@ -24,7 +24,7 @@ using namespace llvm;
namespace {
class OptimizeReturned final : public FunctionPass,
public InstVisitor<OptimizeReturned> {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Optimize Returned";
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
index 56d44e6..32dde88 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
@@ -31,7 +31,7 @@ static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt(
namespace {
class WebAssemblyPeephole final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly late peephole optimizer";
}
@@ -83,8 +83,8 @@ static bool MaybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
if (&MI != &MBB.back())
return false;
- // If the operand isn't stackified, insert a COPY_LOCAL to read the operand
- // and stackify it.
+ // If the operand isn't stackified, insert a COPY to read the operand and
+ // stackify it.
MachineOperand &MO = MI.getOperand(0);
unsigned Reg = MO.getReg();
if (!MFI.isVRegStackified(Reg)) {
@@ -119,25 +119,6 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
switch (MI.getOpcode()) {
default:
break;
- case WebAssembly::STORE8_I32:
- case WebAssembly::STORE16_I32:
- case WebAssembly::STORE8_I64:
- case WebAssembly::STORE16_I64:
- case WebAssembly::STORE32_I64:
- case WebAssembly::STORE_F32:
- case WebAssembly::STORE_F64:
- case WebAssembly::STORE_I32:
- case WebAssembly::STORE_I64: {
- // Store instructions return their value operand. If we ended up using
- // the same register for both, replace it with a dead def so that it
- // can use $drop instead.
- MachineOperand &MO = MI.getOperand(0);
- unsigned OldReg = MO.getReg();
- unsigned NewReg =
- MI.getOperand(WebAssembly::StoreValueOperandNo).getReg();
- Changed |= MaybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI);
- break;
- }
case WebAssembly::CALL_I32:
case WebAssembly::CALL_I64: {
MachineOperand &Op1 = MI.getOperand(1);
@@ -169,22 +150,42 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
case WebAssembly::RETURN_I32:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I32,
- WebAssembly::COPY_LOCAL_I32);
+ WebAssembly::COPY_I32);
break;
case WebAssembly::RETURN_I64:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I64,
- WebAssembly::COPY_LOCAL_I64);
+ WebAssembly::COPY_I64);
break;
case WebAssembly::RETURN_F32:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F32,
- WebAssembly::COPY_LOCAL_F32);
+ WebAssembly::COPY_F32);
break;
case WebAssembly::RETURN_F64:
Changed |= MaybeRewriteToFallthrough(
MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F64,
- WebAssembly::COPY_LOCAL_F64);
+ WebAssembly::COPY_F64);
+ break;
+ case WebAssembly::RETURN_v16i8:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v16i8,
+ WebAssembly::COPY_V128);
+ break;
+ case WebAssembly::RETURN_v8i16:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v8i16,
+ WebAssembly::COPY_V128);
+ break;
+ case WebAssembly::RETURN_v4i32:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4i32,
+ WebAssembly::COPY_V128);
+ break;
+ case WebAssembly::RETURN_v4f32:
+ Changed |= MaybeRewriteToFallthrough(
+ MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4f32,
+ WebAssembly::COPY_V128);
break;
case WebAssembly::RETURN_VOID:
if (!DisableWebAssemblyFallthroughReturnOpt &&
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp
index 30444ac..473dcb7 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp
@@ -23,6 +23,7 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
@@ -40,7 +41,7 @@ public:
WebAssemblyPrepareForLiveIntervals() : MachineFunctionPass(ID) {}
private:
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Prepare For LiveIntervals";
}
@@ -58,23 +59,10 @@ FunctionPass *llvm::createWebAssemblyPrepareForLiveIntervals() {
return new WebAssemblyPrepareForLiveIntervals();
}
-/// Test whether the given instruction is an ARGUMENT.
-static bool IsArgument(const MachineInstr *MI) {
- switch (MI->getOpcode()) {
- case WebAssembly::ARGUMENT_I32:
- case WebAssembly::ARGUMENT_I64:
- case WebAssembly::ARGUMENT_F32:
- case WebAssembly::ARGUMENT_F64:
- return true;
- default:
- return false;
- }
-}
-
// Test whether the given register has an ARGUMENT def.
static bool HasArgumentDef(unsigned Reg, const MachineRegisterInfo &MRI) {
- for (auto &Def : MRI.def_instructions(Reg))
- if (IsArgument(&Def))
+ for (const auto &Def : MRI.def_instructions(Reg))
+ if (WebAssembly::isArgument(Def))
return true;
return false;
}
@@ -122,10 +110,10 @@ bool WebAssemblyPrepareForLiveIntervals::runOnMachineFunction(MachineFunction &M
// Move ARGUMENT_* instructions to the top of the entry block, so that their
// liveness reflects the fact that these really are live-in values.
for (auto MII = Entry.begin(), MIE = Entry.end(); MII != MIE; ) {
- MachineInstr *MI = &*MII++;
- if (IsArgument(MI)) {
- MI->removeFromParent();
- Entry.insert(Entry.begin(), MI);
+ MachineInstr &MI = *MII++;
+ if (WebAssembly::isArgument(MI)) {
+ MI.removeFromParent();
+ Entry.insert(Entry.begin(), &MI);
}
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp
index dedd910..5fd4a8d 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp
@@ -35,7 +35,7 @@ public:
static char ID; // Pass identification, replacement for typeid
WebAssemblyRegColoring() : MachineFunctionPass(ID) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Register Coloring";
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
index 4a8fd96..e347082 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp
@@ -17,6 +17,7 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -32,7 +33,7 @@ using namespace llvm;
namespace {
class WebAssemblyRegNumbering final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Register Numbering";
}
@@ -68,20 +69,13 @@ bool WebAssemblyRegNumbering::runOnMachineFunction(MachineFunction &MF) {
// variables. Assign the numbers for them first.
MachineBasicBlock &EntryMBB = MF.front();
for (MachineInstr &MI : EntryMBB) {
- switch (MI.getOpcode()) {
- case WebAssembly::ARGUMENT_I32:
- case WebAssembly::ARGUMENT_I64:
- case WebAssembly::ARGUMENT_F32:
- case WebAssembly::ARGUMENT_F64: {
- int64_t Imm = MI.getOperand(1).getImm();
- DEBUG(dbgs() << "Arg VReg " << MI.getOperand(0).getReg() << " -> WAReg "
- << Imm << "\n");
- MFI.setWAReg(MI.getOperand(0).getReg(), Imm);
+ if (!WebAssembly::isArgument(MI))
break;
- }
- default:
- break;
- }
+
+ int64_t Imm = MI.getOperand(1).getImm();
+ DEBUG(dbgs() << "Arg VReg " << MI.getOperand(0).getReg() << " -> WAReg "
+ << Imm << "\n");
+ MFI.setWAReg(MI.getOperand(0).getReg(), Imm);
}
// Then assign regular WebAssembly registers for all remaining used
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
index 0aa3b62..32ee09e 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
@@ -13,10 +13,10 @@
/// This pass reorders instructions to put register uses and defs in an order
/// such that they form single-use expression trees. Registers fitting this form
/// are then marked as "stackified", meaning references to them are replaced by
-/// "push" and "pop" from the stack.
+/// "push" and "pop" from the value stack.
///
/// This is primarily a code size optimization, since temporary values on the
-/// expression don't need to be named.
+/// value stack don't need to be named.
///
//===----------------------------------------------------------------------===//
@@ -24,6 +24,7 @@
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_*
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
@@ -39,7 +40,7 @@ using namespace llvm;
namespace {
class WebAssemblyRegStackify final : public MachineFunctionPass {
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Register Stackify";
}
@@ -73,19 +74,50 @@ FunctionPass *llvm::createWebAssemblyRegStackify() {
// expression stack ordering constraints for an instruction which is on
// the expression stack.
static void ImposeStackOrdering(MachineInstr *MI) {
- // Write the opaque EXPR_STACK register.
- if (!MI->definesRegister(WebAssembly::EXPR_STACK))
- MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
+ // Write the opaque VALUE_STACK register.
+ if (!MI->definesRegister(WebAssembly::VALUE_STACK))
+ MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK,
/*isDef=*/true,
/*isImp=*/true));
- // Also read the opaque EXPR_STACK register.
- if (!MI->readsRegister(WebAssembly::EXPR_STACK))
- MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
+ // Also read the opaque VALUE_STACK register.
+ if (!MI->readsRegister(WebAssembly::VALUE_STACK))
+ MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK,
/*isDef=*/false,
/*isImp=*/true));
}
+// Convert an IMPLICIT_DEF instruction into an instruction which defines
+// a constant zero value.
+static void ConvertImplicitDefToConstZero(MachineInstr *MI,
+ MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII,
+ MachineFunction &MF) {
+ assert(MI->getOpcode() == TargetOpcode::IMPLICIT_DEF);
+
+ const auto *RegClass =
+ MRI.getRegClass(MI->getOperand(0).getReg());
+ if (RegClass == &WebAssembly::I32RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_I32));
+ MI->addOperand(MachineOperand::CreateImm(0));
+ } else if (RegClass == &WebAssembly::I64RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_I64));
+ MI->addOperand(MachineOperand::CreateImm(0));
+ } else if (RegClass == &WebAssembly::F32RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_F32));
+ ConstantFP *Val = cast<ConstantFP>(Constant::getNullValue(
+ Type::getFloatTy(MF.getFunction()->getContext())));
+ MI->addOperand(MachineOperand::CreateFPImm(Val));
+ } else if (RegClass == &WebAssembly::F64RegClass) {
+ MI->setDesc(TII->get(WebAssembly::CONST_F64));
+ ConstantFP *Val = cast<ConstantFP>(Constant::getNullValue(
+ Type::getDoubleTy(MF.getFunction()->getContext())));
+ MI->addOperand(MachineOperand::CreateFPImm(Val));
+ } else {
+ llvm_unreachable("Unexpected reg class");
+ }
+}
+
// Determine whether a call to the callee referenced by
// MI->getOperand(CalleeOpNo) reads memory, writes memory, and/or has side
// effects.
@@ -130,7 +162,7 @@ static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read,
return;
// Check for loads.
- if (MI.mayLoad() && !MI.isInvariantLoad(&AA))
+ if (MI.mayLoad() && !MI.isDereferenceableInvariantLoad(&AA))
Read = true;
// Check for stores.
@@ -255,7 +287,7 @@ static bool HasOneUse(unsigned Reg, MachineInstr *Def,
const VNInfo *DefVNI = LI.getVNInfoAt(
LIS.getInstructionIndex(*Def).getRegSlot());
assert(DefVNI);
- for (auto I : MRI.use_nodbg_operands(Reg)) {
+ for (auto &I : MRI.use_nodbg_operands(Reg)) {
const auto &Result = LI.Query(LIS.getInstructionIndex(*I.getParent()));
if (Result.valueIn() == DefVNI) {
if (!Result.isKill())
@@ -274,11 +306,11 @@ static bool HasOneUse(unsigned Reg, MachineInstr *Def,
// TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
// more precise.
static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
- AliasAnalysis &AA, const LiveIntervals &LIS,
- const MachineRegisterInfo &MRI) {
+ AliasAnalysis &AA, const MachineRegisterInfo &MRI) {
assert(Def->getParent() == Insert->getParent());
// Check for register dependencies.
+ SmallVector<unsigned, 4> MutableRegisters;
for (const MachineOperand &MO : Def->operands()) {
if (!MO.isReg() || MO.isUndef())
continue;
@@ -301,21 +333,11 @@ static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
return false;
}
- // Ask LiveIntervals whether moving this virtual register use or def to
- // Insert will change which value numbers are seen.
- //
- // If the operand is a use of a register that is also defined in the same
- // instruction, test that the newly defined value reaches the insert point,
- // since the operand will be moving along with the def.
- const LiveInterval &LI = LIS.getInterval(Reg);
- VNInfo *DefVNI =
- (MO.isDef() || Def->definesRegister(Reg)) ?
- LI.getVNInfoAt(LIS.getInstructionIndex(*Def).getRegSlot()) :
- LI.getVNInfoBefore(LIS.getInstructionIndex(*Def));
- assert(DefVNI && "Instruction input missing value number");
- VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*Insert));
- if (InsVNI && DefVNI != InsVNI)
- return false;
+ // If one of the operands isn't in SSA form, it has different values at
+ // different times, and we need to make sure we don't move our use across
+ // a different def.
+ if (!MO.isDef() && !MRI.hasOneDef(Reg))
+ MutableRegisters.push_back(Reg);
}
bool Read = false, Write = false, Effects = false, StackPointer = false;
@@ -323,7 +345,8 @@ static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
// If the instruction does not access memory and has no side effects, it has
// no additional dependencies.
- if (!Read && !Write && !Effects && !StackPointer)
+ bool HasMutableRegisters = !MutableRegisters.empty();
+ if (!Read && !Write && !Effects && !StackPointer && !HasMutableRegisters)
return true;
// Scan through the intervening instructions between Def and Insert.
@@ -343,6 +366,11 @@ static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
return false;
if (StackPointer && InterveningStackPointer)
return false;
+
+ for (unsigned Reg : MutableRegisters)
+ for (const MachineOperand &MO : I->operands())
+ if (MO.isReg() && MO.isDef() && MO.getReg() == Reg)
+ return false;
}
return true;
@@ -360,7 +388,7 @@ static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
const MachineInstr *OneUseInst = OneUse.getParent();
VNInfo *OneUseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*OneUseInst));
- for (const MachineOperand &Use : MRI.use_operands(Reg)) {
+ for (const MachineOperand &Use : MRI.use_nodbg_operands(Reg)) {
if (&Use == &OneUse)
continue;
@@ -384,7 +412,7 @@ static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
//
// This is needed as a consequence of using implicit get_locals for
// uses and implicit set_locals for defs.
- if (UseInst->getDesc().getNumDefs() == 0)
+ if (UseInst->getDesc().getNumDefs() == 0)
return false;
const MachineOperand &MO = UseInst->getOperand(0);
if (!MO.isReg())
@@ -408,16 +436,18 @@ static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse,
return true;
}
-/// Get the appropriate tee_local opcode for the given register class.
-static unsigned GetTeeLocalOpcode(const TargetRegisterClass *RC) {
+/// Get the appropriate tee opcode for the given register class.
+static unsigned GetTeeOpcode(const TargetRegisterClass *RC) {
if (RC == &WebAssembly::I32RegClass)
- return WebAssembly::TEE_LOCAL_I32;
+ return WebAssembly::TEE_I32;
if (RC == &WebAssembly::I64RegClass)
- return WebAssembly::TEE_LOCAL_I64;
+ return WebAssembly::TEE_I64;
if (RC == &WebAssembly::F32RegClass)
- return WebAssembly::TEE_LOCAL_F32;
+ return WebAssembly::TEE_F32;
if (RC == &WebAssembly::F64RegClass)
- return WebAssembly::TEE_LOCAL_F64;
+ return WebAssembly::TEE_F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return WebAssembly::TEE_V128;
llvm_unreachable("Unexpected register class");
}
@@ -515,8 +545,8 @@ static MachineInstr *RematerializeCheapDef(
/// A multiple-use def in the same block with no intervening memory or register
/// dependencies; move the def down, nest it with the current instruction, and
-/// insert a tee_local to satisfy the rest of the uses. As an illustration,
-/// rewrite this:
+/// insert a tee to satisfy the rest of the uses. As an illustration, rewrite
+/// this:
///
/// Reg = INST ... // Def
/// INST ..., Reg, ... // Insert
@@ -526,7 +556,7 @@ static MachineInstr *RematerializeCheapDef(
/// to this:
///
/// DefReg = INST ... // Def (to become the new Insert)
-/// TeeReg, Reg = TEE_LOCAL_... DefReg
+/// TeeReg, Reg = TEE_... DefReg
/// INST ..., TeeReg, ... // Insert
/// INST ..., Reg, ...
/// INST ..., Reg, ...
@@ -549,7 +579,7 @@ static MachineInstr *MoveAndTeeForMultiUse(
unsigned DefReg = MRI.createVirtualRegister(RegClass);
MachineOperand &DefMO = Def->getOperand(0);
MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(),
- TII->get(GetTeeLocalOpcode(RegClass)), TeeReg)
+ TII->get(GetTeeOpcode(RegClass)), TeeReg)
.addReg(Reg, RegState::Define)
.addReg(DefReg, getUndefRegState(DefMO.isDead()));
Op.setReg(TeeReg);
@@ -749,8 +779,7 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
if (TargetRegisterInfo::isPhysicalRegister(Reg))
continue;
- // Identify the definition for this register at this point. Most
- // registers are in SSA form here so we try a quick MRI query first.
+ // Identify the definition for this register at this point.
MachineInstr *Def = GetVRegDef(Reg, Insert, MRI, LIS);
if (!Def)
continue;
@@ -762,20 +791,17 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
// Argument instructions represent live-in registers and not real
// instructions.
- if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 ||
- Def->getOpcode() == WebAssembly::ARGUMENT_I64 ||
- Def->getOpcode() == WebAssembly::ARGUMENT_F32 ||
- Def->getOpcode() == WebAssembly::ARGUMENT_F64)
+ if (WebAssembly::isArgument(*Def))
continue;
// Decide which strategy to take. Prefer to move a single-use value
- // over cloning it, and prefer cloning over introducing a tee_local.
+ // over cloning it, and prefer cloning over introducing a tee.
// For moving, we require the def to be in the same block as the use;
// this makes things simpler (LiveIntervals' handleMove function only
// supports intra-block moves) and it's MachineSink's job to catch all
// the sinking opportunities anyway.
bool SameBlock = Def->getParent() == &MBB;
- bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, LIS, MRI) &&
+ bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, MRI) &&
!TreeWalker.IsOnStack(Reg);
if (CanMove && HasOneUse(Reg, Def, MRI, MDT, LIS)) {
Insert = MoveForSingleUse(Reg, Op, Def, MBB, Insert, LIS, MFI, MRI);
@@ -796,6 +822,12 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
continue;
}
+ // If the instruction we just stackified is an IMPLICIT_DEF, convert it
+ // to a constant 0 so that the def is explicit, and the push/pop
+ // correspondence is maintained.
+ if (Insert->getOpcode() == TargetOpcode::IMPLICIT_DEF)
+ ConvertImplicitDefToConstZero(Insert, MRI, TII, MF);
+
// We stackified an operand. Add the defining instruction's operands to
// the worklist stack now to continue to build an ever deeper tree.
Commuting.Reset();
@@ -806,19 +838,18 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
// the next instruction we can build a tree on.
if (Insert != &*MII) {
ImposeStackOrdering(&*MII);
- MII = std::prev(
- llvm::make_reverse_iterator(MachineBasicBlock::iterator(Insert)));
+ MII = MachineBasicBlock::iterator(Insert).getReverse();
Changed = true;
}
}
}
- // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere so
+ // If we used VALUE_STACK anywhere, add it to the live-in sets everywhere so
// that it never looks like a use-before-def.
if (Changed) {
- MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
+ MF.getRegInfo().addLiveIn(WebAssembly::VALUE_STACK);
for (MachineBasicBlock &MBB : MF)
- MBB.addLiveIn(WebAssembly::EXPR_STACK);
+ MBB.addLiveIn(WebAssembly::VALUE_STACK);
}
#ifndef NDEBUG
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
index 239fe89..9367464 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
@@ -61,19 +61,25 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex(
MachineFunction &MF = *MBB.getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
int64_t FrameOffset = MFI.getStackSize() + MFI.getObjectOffset(FrameIndex);
+ assert(MFI.getObjectSize(FrameIndex) != 0 &&
+ "We assume that variable-sized objects have already been lowered, "
+ "and don't use FrameIndex operands.");
+ unsigned FrameRegister = getFrameRegister(MF);
+
// If this is the address operand of a load or store, make it relative to SP
// and fold the frame offset directly in.
- if (MI.mayLoadOrStore() && FIOperandNum == WebAssembly::MemOpAddressOperandNo) {
- assert(FrameOffset >= 0 && MI.getOperand(1).getImm() >= 0);
- int64_t Offset = MI.getOperand(1).getImm() + FrameOffset;
+ if ((MI.mayLoad() && FIOperandNum == WebAssembly::LoadAddressOperandNo) ||
+ (MI.mayStore() && FIOperandNum == WebAssembly::StoreAddressOperandNo)) {
+ assert(FrameOffset >= 0 && MI.getOperand(FIOperandNum - 1).getImm() >= 0);
+ int64_t Offset = MI.getOperand(FIOperandNum - 1).getImm() + FrameOffset;
if (static_cast<uint64_t>(Offset) <= std::numeric_limits<uint32_t>::max()) {
MI.getOperand(FIOperandNum - 1).setImm(Offset);
MI.getOperand(FIOperandNum)
- .ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false);
+ .ChangeToRegister(FrameRegister, /*IsDef=*/false);
return;
}
}
@@ -94,7 +100,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex(
MachineOperand &ImmMO = Def->getOperand(1);
ImmMO.setImm(ImmMO.getImm() + uint32_t(FrameOffset));
MI.getOperand(FIOperandNum)
- .ChangeToRegister(WebAssembly::SP32, /*IsDef=*/false);
+ .ChangeToRegister(FrameRegister, /*IsDef=*/false);
return;
}
}
@@ -104,7 +110,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex(
// Otherwise create an i32.add SP, offset and make it the operand.
const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
- unsigned FIRegOperand = WebAssembly::SP32;
+ unsigned FIRegOperand = FrameRegister;
if (FrameOffset) {
// Create i32.add SP, offset and make it the operand.
const TargetRegisterClass *PtrRC =
@@ -116,7 +122,7 @@ void WebAssemblyRegisterInfo::eliminateFrameIndex(
FIRegOperand = MRI.createVirtualRegister(PtrRC);
BuildMI(MBB, *II, II->getDebugLoc(), TII->get(WebAssembly::ADD_I32),
FIRegOperand)
- .addReg(WebAssembly::SP32)
+ .addReg(FrameRegister)
.addReg(OffsetOp);
}
MI.getOperand(FIOperandNum).ChangeToRegister(FIRegOperand, /*IsDef=*/false);
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
index 80a83fa..9088810 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
@@ -39,9 +39,11 @@ def SP64 : WebAssemblyReg<"%SP64">;
def F32_0 : WebAssemblyReg<"%f32.0">;
def F64_0 : WebAssemblyReg<"%f64.0">;
-// The expression stack "register". This is an opaque entity which serves to
-// order uses and defs that must remain in LIFO order.
-def EXPR_STACK : WebAssemblyReg<"STACK">;
+def V128_0: WebAssemblyReg<"%v128">;
+
+// The value stack "register". This is an opaque entity which serves to order
+// uses and defs that must remain in LIFO order.
+def VALUE_STACK : WebAssemblyReg<"STACK">;
// The incoming arguments "register". This is an opaque entity which serves to
// order the ARGUMENT instructions that are emulating live-in registers and
@@ -56,3 +58,5 @@ def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32)>;
def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64)>;
def F32 : WebAssemblyRegClass<[f32], 32, (add F32_0)>;
def F64 : WebAssemblyRegClass<[f64], 64, (add F64_0)>;
+def V128 : WebAssemblyRegClass<[v4f32, v4i32, v16i8, v8i16], 128, (add V128_0)>;
+
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
index 11bda47..9e944df 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
@@ -39,7 +39,7 @@ public:
WebAssemblyReplacePhysRegs() : MachineFunctionPass(ID) {}
private:
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Replace Physical Registers";
}
@@ -76,7 +76,7 @@ bool WebAssemblyReplacePhysRegs::runOnMachineFunction(MachineFunction &MF) {
for (unsigned PReg = WebAssembly::NoRegister + 1;
PReg < WebAssembly::NUM_TARGET_REGS; ++PReg) {
// Skip fake registers that are never used explicitly.
- if (PReg == WebAssembly::EXPR_STACK || PReg == WebAssembly::ARGUMENTS)
+ if (PReg == WebAssembly::VALUE_STACK || PReg == WebAssembly::ARGUMENTS)
continue;
// Replace explicit uses of the physical register with a virtual register.
@@ -88,6 +88,8 @@ bool WebAssemblyReplacePhysRegs::runOnMachineFunction(MachineFunction &MF) {
if (VReg == WebAssembly::NoRegister)
VReg = MRI.createVirtualRegister(RC);
MO.setReg(VReg);
+ if (MO.getParent()->isDebugValue())
+ MO.setIsDebug();
Changed = true;
}
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp
index 4ebea68..2441ead 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp
@@ -30,7 +30,7 @@ public:
static char ID; // Pass identification, replacement for typeid
WebAssemblySetP2AlignOperands() : MachineFunctionPass(ID) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "WebAssembly Set p2align Operands";
}
@@ -50,6 +50,27 @@ FunctionPass *llvm::createWebAssemblySetP2AlignOperands() {
return new WebAssemblySetP2AlignOperands();
}
+static void RewriteP2Align(MachineInstr &MI, unsigned OperandNo) {
+ assert(MI.getOperand(OperandNo).getImm() == 0 &&
+ "ISel should set p2align operands to 0");
+ assert(MI.hasOneMemOperand() &&
+ "Load and store instructions have exactly one mem operand");
+ assert((*MI.memoperands_begin())->getSize() ==
+ (UINT64_C(1)
+ << WebAssembly::GetDefaultP2Align(MI.getOpcode())) &&
+ "Default p2align value should be natural");
+ assert(MI.getDesc().OpInfo[OperandNo].OperandType ==
+ WebAssembly::OPERAND_P2ALIGN &&
+ "Load and store instructions should have a p2align operand");
+ uint64_t P2Align = Log2_64((*MI.memoperands_begin())->getAlignment());
+
+ // WebAssembly does not currently support supernatural alignment.
+ P2Align = std::min(
+ P2Align, uint64_t(WebAssembly::GetDefaultP2Align(MI.getOpcode())));
+
+ MI.getOperand(OperandNo).setImm(P2Align);
+}
+
bool WebAssemblySetP2AlignOperands::runOnMachineFunction(MachineFunction &MF) {
DEBUG({
dbgs() << "********** Set p2align Operands **********\n"
@@ -75,6 +96,8 @@ bool WebAssemblySetP2AlignOperands::runOnMachineFunction(MachineFunction &MF) {
case WebAssembly::LOAD16_U_I64:
case WebAssembly::LOAD32_S_I64:
case WebAssembly::LOAD32_U_I64:
+ RewriteP2Align(MI, WebAssembly::LoadP2AlignOperandNo);
+ break;
case WebAssembly::STORE_I32:
case WebAssembly::STORE_I64:
case WebAssembly::STORE_F32:
@@ -83,27 +106,9 @@ bool WebAssemblySetP2AlignOperands::runOnMachineFunction(MachineFunction &MF) {
case WebAssembly::STORE16_I32:
case WebAssembly::STORE8_I64:
case WebAssembly::STORE16_I64:
- case WebAssembly::STORE32_I64: {
- assert(MI.getOperand(3).getImm() == 0 &&
- "ISel should set p2align operands to 0");
- assert(MI.hasOneMemOperand() &&
- "Load and store instructions have exactly one mem operand");
- assert((*MI.memoperands_begin())->getSize() ==
- (UINT64_C(1)
- << WebAssembly::GetDefaultP2Align(MI.getOpcode())) &&
- "Default p2align value should be natural");
- assert(MI.getDesc().OpInfo[3].OperandType ==
- WebAssembly::OPERAND_P2ALIGN &&
- "Load and store instructions should have a p2align operand");
- uint64_t P2Align = Log2_64((*MI.memoperands_begin())->getAlignment());
-
- // WebAssembly does not currently support supernatural alignment.
- P2Align = std::min(
- P2Align, uint64_t(WebAssembly::GetDefaultP2Align(MI.getOpcode())));
-
- MI.getOperand(3).setImm(P2Align);
+ case WebAssembly::STORE32_I64:
+ RewriteP2Align(MI, WebAssembly::StoreP2AlignOperandNo);
break;
- }
default:
break;
}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp
index 1e9a773..34ec6f2 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp
@@ -46,9 +46,7 @@ public:
static char ID; // Pass identification, replacement for typeid
WebAssemblyStoreResults() : MachineFunctionPass(ID) {}
- const char *getPassName() const override {
- return "WebAssembly Store Results";
- }
+ StringRef getPassName() const override { return "WebAssembly Store Results"; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
@@ -90,7 +88,7 @@ static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
SmallVector<SlotIndex, 4> Indices;
- for (auto I = MRI.use_begin(FromReg), E = MRI.use_end(); I != E;) {
+ for (auto I = MRI.use_nodbg_begin(FromReg), E = MRI.use_nodbg_end(); I != E;) {
MachineOperand &O = *I++;
MachineInstr *Where = O.getParent();
@@ -139,15 +137,6 @@ static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
return Changed;
}
-static bool optimizeStore(MachineBasicBlock &MBB, MachineInstr &MI,
- const MachineRegisterInfo &MRI,
- MachineDominatorTree &MDT,
- LiveIntervals &LIS) {
- unsigned ToReg = MI.getOperand(0).getReg();
- unsigned FromReg = MI.getOperand(WebAssembly::StoreValueOperandNo).getReg();
- return ReplaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
-}
-
static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI,
const MachineRegisterInfo &MRI,
MachineDominatorTree &MDT,
@@ -202,17 +191,6 @@ bool WebAssemblyStoreResults::runOnMachineFunction(MachineFunction &MF) {
switch (MI.getOpcode()) {
default:
break;
- case WebAssembly::STORE8_I32:
- case WebAssembly::STORE16_I32:
- case WebAssembly::STORE8_I64:
- case WebAssembly::STORE16_I64:
- case WebAssembly::STORE32_I64:
- case WebAssembly::STORE_F32:
- case WebAssembly::STORE_F64:
- case WebAssembly::STORE_I32:
- case WebAssembly::STORE_I64:
- Changed |= optimizeStore(MBB, MI, MRI, MDT, LIS);
- break;
case WebAssembly::CALL_I32:
case WebAssembly::CALL_I64:
Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo);
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 32154af..f5ef35a 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -29,10 +29,28 @@ using namespace llvm;
#define DEBUG_TYPE "wasm"
+// Emscripten's asm.js-style exception handling
+static cl::opt<bool> EnableEmException(
+ "enable-emscripten-cxx-exceptions",
+ cl::desc("WebAssembly Emscripten-style exception handling"),
+ cl::init(false));
+
+// Emscripten's asm.js-style setjmp/longjmp handling
+static cl::opt<bool> EnableEmSjLj(
+ "enable-emscripten-sjlj",
+ cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
+ cl::init(false));
+
extern "C" void LLVMInitializeWebAssemblyTarget() {
// Register the target.
- RegisterTargetMachine<WebAssemblyTargetMachine> X(TheWebAssemblyTarget32);
- RegisterTargetMachine<WebAssemblyTargetMachine> Y(TheWebAssemblyTarget64);
+ RegisterTargetMachine<WebAssemblyTargetMachine> X(
+ getTheWebAssemblyTarget32());
+ RegisterTargetMachine<WebAssemblyTargetMachine> Y(
+ getTheWebAssemblyTarget64());
+
+ // Register exception handling pass to opt
+ initializeWebAssemblyLowerEmscriptenEHSjLjPass(
+ *PassRegistry::getPassRegistry());
}
//===----------------------------------------------------------------------===//
@@ -57,10 +75,10 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
TT, CPU, FS, Options, getEffectiveRelocModel(RM),
CM, OL),
TLOF(make_unique<WebAssemblyTargetObjectFile>()) {
- // WebAssembly type-checks expressions, but a noreturn function with a return
+ // WebAssembly type-checks instructions, but a noreturn function with a return
// type that doesn't match the context will cause a check failure. So we lower
// LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
- // 'unreachable' expression which is meant for that case.
+ // 'unreachable' instructions which is meant for that case.
this->Options.TrapUnreachable = true;
initAsmInfo();
@@ -145,10 +163,31 @@ void WebAssemblyPassConfig::addIRPasses() {
// control specifically what gets lowered.
addPass(createAtomicExpandPass(TM));
+ // Fix function bitcasts, as WebAssembly requires caller and callee signatures
+ // to match.
+ addPass(createWebAssemblyFixFunctionBitcasts());
+
// Optimize "returned" function attributes.
if (getOptLevel() != CodeGenOpt::None)
addPass(createWebAssemblyOptimizeReturned());
+ // If exception handling is not enabled and setjmp/longjmp handling is
+ // enabled, we lower invokes into calls and delete unreachable landingpad
+ // blocks. Lowering invokes when there is no EH support is done in
+ // TargetPassConfig::addPassesToHandleExceptions, but this runs after this
+ // function and SjLj handling expects all invokes to be lowered before.
+ if (!EnableEmException) {
+ addPass(createLowerInvokePass());
+ // The lower invoke pass may create unreachable code. Remove it in order not
+ // to process dead blocks in setjmp/longjmp handling.
+ addPass(createUnreachableBlockEliminationPass());
+ }
+
+ // Handle exceptions and setjmp/longjmp if enabled.
+ if (EnableEmException || EnableEmSjLj)
+ addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
+ EnableEmSjLj));
+
TargetPassConfig::addIRPasses();
}
@@ -175,7 +214,7 @@ void WebAssemblyPassConfig::addPostRegAlloc() {
// Has no asserts of its own, but was not written to handle virtual regs.
disablePass(&ShrinkWrapID);
- // These functions all require the AllVRegsAllocated property.
+ // These functions all require the NoVRegs property.
disablePass(&MachineCopyPropagationID);
disablePass(&PostRASchedulerID);
disablePass(&FuncletLayoutID);
@@ -194,6 +233,11 @@ void WebAssemblyPassConfig::addPreEmitPass() {
// colored, and numbered with the rest of the registers.
addPass(createWebAssemblyReplacePhysRegs());
+ // Rewrite pseudo call_indirect instructions as real instructions.
+ // This needs to run before register stackification, because we change the
+ // order of the arguments.
+ addPass(createWebAssemblyCallIndirectFixup());
+
if (getOptLevel() != CodeGenOpt::None) {
// LiveIntervals isn't commonly run this late. Re-establish preconditions.
addPass(createWebAssemblyPrepareForLiveIntervals());
@@ -204,7 +248,7 @@ void WebAssemblyPassConfig::addPreEmitPass() {
// Prepare store instructions for register stackifying.
addPass(createWebAssemblyStoreResults());
- // Mark registers as representing wasm's expression stack. This is a key
+ // Mark registers as representing wasm's value stack. This is a key
// code-compression technique in WebAssembly. We run this pass (and
// StoreResults above) very late, so that it sees as much code as possible,
// including code emitted by PEI and expanded by late tail duplication.
@@ -216,6 +260,9 @@ void WebAssemblyPassConfig::addPreEmitPass() {
addPass(createWebAssemblyRegColoring());
}
+ // Insert explicit get_local and set_local operators.
+ addPass(createWebAssemblyExplicitLocals());
+
// Eliminate multiple-entry loops.
addPass(createWebAssemblyFixIrreducibleControlFlow());
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
index bf546da..47aadf9 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
@@ -46,7 +46,7 @@ unsigned WebAssemblyTTIImpl::getRegisterBitWidth(bool Vector) {
unsigned WebAssemblyTTIImpl::getArithmeticInstrCost(
unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info,
TTI::OperandValueKind Opd2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ TTI::OperandValueProperties Opd2PropInfo, ArrayRef<const Value *> Args) {
unsigned Cost = BasicTTIImplBase<WebAssemblyTTIImpl>::getArithmeticInstrCost(
Opcode, Ty, Opd1Info, Opd2Info, Opd1PropInfo, Opd2PropInfo);
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
index fe99e96..f658609 100644
--- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
@@ -42,13 +42,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- WebAssemblyTTIImpl(const WebAssemblyTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- WebAssemblyTTIImpl(WebAssemblyTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
/// \name Scalar TTI Implementations
/// @{
@@ -68,7 +61,8 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
unsigned getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index);
/// @}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
new file mode 100644
index 0000000..a0049c1
--- /dev/null
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
@@ -0,0 +1,71 @@
+//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements several utility functions for WebAssembly.
+///
+//===----------------------------------------------------------------------===//
+
+#include "WebAssemblyUtilities.h"
+#include "WebAssemblyMachineFunctionInfo.h"
+#include "llvm/CodeGen/MachineInstr.h"
+using namespace llvm;
+
+bool WebAssembly::isArgument(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case WebAssembly::ARGUMENT_I32:
+ case WebAssembly::ARGUMENT_I64:
+ case WebAssembly::ARGUMENT_F32:
+ case WebAssembly::ARGUMENT_F64:
+ case WebAssembly::ARGUMENT_v16i8:
+ case WebAssembly::ARGUMENT_v8i16:
+ case WebAssembly::ARGUMENT_v4i32:
+ case WebAssembly::ARGUMENT_v4f32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool WebAssembly::isCopy(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case WebAssembly::COPY_I32:
+ case WebAssembly::COPY_I64:
+ case WebAssembly::COPY_F32:
+ case WebAssembly::COPY_F64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool WebAssembly::isTee(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case WebAssembly::TEE_I32:
+ case WebAssembly::TEE_I64:
+ case WebAssembly::TEE_F32:
+ case WebAssembly::TEE_F64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// Test whether MI is a child of some other node in an expression tree.
+bool WebAssembly::isChild(const MachineInstr &MI,
+ const WebAssemblyFunctionInfo &MFI) {
+ if (MI.getNumOperands() == 0)
+ return false;
+ const MachineOperand &MO = MI.getOperand(0);
+ if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
+ return false;
+ unsigned Reg = MO.getReg();
+ return TargetRegisterInfo::isVirtualRegister(Reg) &&
+ MFI.isVRegStackified(Reg);
+}
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
new file mode 100644
index 0000000..eb11440
--- /dev/null
+++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
@@ -0,0 +1,34 @@
+//===-- WebAssemblyUtilities - WebAssembly Utility Functions ---*- C++ -*-====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the declaration of the WebAssembly-specific
+/// utility functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYUTILITIES_H
+#define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYUTILITIES_H
+
+namespace llvm {
+
+class MachineInstr;
+class WebAssemblyFunctionInfo;
+
+namespace WebAssembly {
+
+bool isArgument(const MachineInstr &MI);
+bool isCopy(const MachineInstr &MI);
+bool isTee(const MachineInstr &MI);
+bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI);
+
+} // end namespace WebAssembly
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt b/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt
index f074000..8dd5e8a 100644
--- a/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt
+++ b/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt
@@ -66,4 +66,3 @@ pr41935.c
920728-1.c
pr28865.c
widechar-2.c
-pr41463.c
diff --git a/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 4e0ad8bf..e692118 100644
--- a/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -59,6 +59,7 @@ class X86AsmParser : public MCTargetAsmParser {
const MCInstrInfo &MII;
ParseInstructionInfo *InstInfo;
std::unique_ptr<X86AsmInstrumentation> Instrumentation;
+ bool Code16GCC;
private:
SMLoc consumeToken() {
@@ -68,6 +69,19 @@ private:
return Result;
}
+ unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst,
+ uint64_t &ErrorInfo, bool matchingInlineAsm,
+ unsigned VariantID = 0) {
+ // In Code16GCC mode, match as 32-bit.
+ if (Code16GCC)
+ SwitchMode(X86::Mode32Bit);
+ unsigned rv = MatchInstructionImpl(Operands, Inst, ErrorInfo,
+ matchingInlineAsm, VariantID);
+ if (Code16GCC)
+ SwitchMode(X86::Mode16Bit);
+ return rv;
+ }
+
enum InfixCalculatorTok {
IC_OR = 0,
IC_XOR,
@@ -659,20 +673,15 @@ private:
}
};
- bool Error(SMLoc L, const Twine &Msg,
- ArrayRef<SMRange> Ranges = None,
+ bool Error(SMLoc L, const Twine &Msg, SMRange Range = None,
bool MatchingInlineAsm = false) {
MCAsmParser &Parser = getParser();
- if (MatchingInlineAsm) return true;
- return Parser.Error(L, Msg, Ranges);
- }
-
- bool ErrorAndEatStatement(SMLoc L, const Twine &Msg,
- ArrayRef<SMRange> Ranges = None,
- bool MatchingInlineAsm = false) {
- MCAsmParser &Parser = getParser();
- Parser.eatToEndOfStatement();
- return Error(L, Msg, Ranges, MatchingInlineAsm);
+ if (MatchingInlineAsm) {
+ if (!getLexer().isAtStartOfStatement())
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ return Parser.Error(L, Msg, Range);
}
std::nullptr_t ErrorOperand(SMLoc Loc, StringRef Msg) {
@@ -698,14 +707,11 @@ private:
std::unique_ptr<X86Operand> ParseIntelOperator(unsigned OpKind);
std::unique_ptr<X86Operand>
ParseIntelSegmentOverride(unsigned SegReg, SMLoc Start, unsigned Size);
- std::unique_ptr<X86Operand>
- ParseIntelMemOperand(int64_t ImmDisp, SMLoc StartLoc, unsigned Size);
std::unique_ptr<X86Operand> ParseRoundingModeOp(SMLoc Start, SMLoc End);
bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End);
- std::unique_ptr<X86Operand> ParseIntelBracExpression(unsigned SegReg,
- SMLoc Start,
- int64_t ImmDisp,
- unsigned Size);
+ std::unique_ptr<X86Operand>
+ ParseIntelBracExpression(unsigned SegReg, SMLoc Start, int64_t ImmDisp,
+ bool isSymbol, unsigned Size);
bool ParseIntelIdentifier(const MCExpr *&Val, StringRef &Identifier,
InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedOperand, SMLoc &End);
@@ -716,7 +722,8 @@ private:
CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp, unsigned BaseReg,
unsigned IndexReg, unsigned Scale, SMLoc Start,
SMLoc End, unsigned Size, StringRef Identifier,
- InlineAsmIdentifierInfo &Info);
+ InlineAsmIdentifierInfo &Info,
+ bool AllowBetterSizeMatch = false);
bool parseDirectiveEven(SMLoc L);
bool ParseDirectiveWord(unsigned Size, SMLoc L);
@@ -753,10 +760,17 @@ private:
/// Parses AVX512 specific operand primitives: masked registers ({%k<NUM>}, {z})
/// and memory broadcasting ({1to<NUM>}) primitives, updating Operands vector if required.
- /// \return \c true if no parsing errors occurred, \c false otherwise.
+ /// return false if no parsing errors occurred, true otherwise.
bool HandleAVX512Operand(OperandVector &Operands,
const MCParsedAsmOperand &Op);
+ bool ParseZ(std::unique_ptr<X86Operand> &Z, const SMLoc &StartLoc);
+
+ /// MS-compatibility:
+ /// Obtain an appropriate size qualifier, when facing its absence,
+ /// upon AVX512 vector/broadcast memory operand
+ unsigned AdjustAVX512Mem(unsigned Size, X86Operand* UnsizedMemOpNext);
+
bool is64BitMode() const {
// FIXME: Can tablegen auto-generate this?
return getSTI().getFeatureBits()[X86::Mode64Bit];
@@ -802,7 +816,8 @@ private:
public:
X86AsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser,
const MCInstrInfo &mii, const MCTargetOptions &Options)
- : MCTargetAsmParser(Options, sti), MII(mii), InstInfo(nullptr) {
+ : MCTargetAsmParser(Options, sti), MII(mii), InstInfo(nullptr),
+ Code16GCC(false) {
// Initialize the set of available features.
setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
@@ -833,6 +848,11 @@ static bool CheckBaseRegAndIndexReg(unsigned BaseReg, unsigned IndexReg,
// If we have both a base register and an index register make sure they are
// both 64-bit or 32-bit registers.
// To support VSIB, IndexReg can be 128-bit or 256-bit registers.
+
+ if ((BaseReg == X86::RIP && IndexReg != 0) || (IndexReg == X86::RIP)) {
+ ErrMsg = "invalid base+index expression";
+ return true;
+ }
if (BaseReg != 0 && IndexReg != 0) {
if (X86MCRegisterClasses[X86::GR64RegClassID].contains(BaseReg) &&
(X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg) ||
@@ -907,8 +927,7 @@ bool X86AsmParser::ParseRegister(unsigned &RegNo,
if (RegNo == X86::RIZ ||
X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo) ||
X86II::isX86_64NonExtLowByteReg(RegNo) ||
- X86II::isX86_64ExtendedReg(RegNo) ||
- X86II::is32ExtendedReg(RegNo))
+ X86II::isX86_64ExtendedReg(RegNo))
return Error(StartLoc, "register %"
+ Tok.getString() + " is only available in 64-bit mode",
SMRange(StartLoc, EndLoc));
@@ -992,20 +1011,20 @@ void X86AsmParser::SetFrameRegister(unsigned RegNo) {
}
std::unique_ptr<X86Operand> X86AsmParser::DefaultMemSIOperand(SMLoc Loc) {
- unsigned basereg =
- is64BitMode() ? X86::RSI : (is32BitMode() ? X86::ESI : X86::SI);
+ bool Parse32 = is32BitMode() || Code16GCC;
+ unsigned Basereg = is64BitMode() ? X86::RSI : (Parse32 ? X86::ESI : X86::SI);
const MCExpr *Disp = MCConstantExpr::create(0, getContext());
return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp,
- /*BaseReg=*/basereg, /*IndexReg=*/0, /*Scale=*/1,
+ /*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1,
Loc, Loc, 0);
}
std::unique_ptr<X86Operand> X86AsmParser::DefaultMemDIOperand(SMLoc Loc) {
- unsigned basereg =
- is64BitMode() ? X86::RDI : (is32BitMode() ? X86::EDI : X86::DI);
+ bool Parse32 = is32BitMode() || Code16GCC;
+ unsigned Basereg = is64BitMode() ? X86::RDI : (Parse32 ? X86::EDI : X86::DI);
const MCExpr *Disp = MCConstantExpr::create(0, getContext());
return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp,
- /*BaseReg=*/basereg, /*IndexReg=*/0, /*Scale=*/1,
+ /*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1,
Loc, Loc, 0);
}
@@ -1159,7 +1178,7 @@ static unsigned getIntelMemOperandSize(StringRef OpStr) {
std::unique_ptr<X86Operand> X86AsmParser::CreateMemForInlineAsm(
unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg,
unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier,
- InlineAsmIdentifierInfo &Info) {
+ InlineAsmIdentifierInfo &Info, bool AllowBetterSizeMatch) {
// If we found a decl other than a VarDecl, then assume it is a FuncDecl or
// some other label reference.
if (isa<MCSymbolRefExpr>(Disp) && Info.OpDecl && !Info.IsVarDecl) {
@@ -1188,6 +1207,13 @@ std::unique_ptr<X86Operand> X86AsmParser::CreateMemForInlineAsm(
if (Size)
InstInfo->AsmRewrites->emplace_back(AOK_SizeDirective, Start,
/*Len=*/0, Size);
+ if (AllowBetterSizeMatch)
+ // Handle cases where size qualifier is absent, upon an indirect symbol
+ // reference - e.g. "vaddps zmm1, zmm2, [var]"
+ // set Size to zero to allow matching mechansim to try and find a better
+ // size qualifier than our initial guess, based on available variants of
+ // the given instruction
+ Size = 0;
}
}
@@ -1271,7 +1297,7 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
// The period in the dot operator (e.g., [ebx].foo.bar) is parsed as an
// identifier. Don't try an parse it as a register.
- if (Tok.getString().startswith("."))
+ if (PrevTK != AsmToken::Error && Tok.getString().startswith("."))
break;
// If we're parsing an immediate expression, we don't expect a '['.
@@ -1386,7 +1412,8 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
std::unique_ptr<X86Operand>
X86AsmParser::ParseIntelBracExpression(unsigned SegReg, SMLoc Start,
- int64_t ImmDisp, unsigned Size) {
+ int64_t ImmDisp, bool isSymbol,
+ unsigned Size) {
MCAsmParser &Parser = getParser();
const AsmToken &Tok = Parser.getTok();
SMLoc BracLoc = Tok.getLoc(), End = Tok.getEndLoc();
@@ -1436,6 +1463,21 @@ X86AsmParser::ParseIntelBracExpression(unsigned SegReg, SMLoc Start,
Disp = NewDisp;
}
+ if (isSymbol) {
+ if (SM.getSym()) {
+ Error(Start, "cannot use more than one symbol in memory operand");
+ return nullptr;
+ }
+ if (SM.getBaseReg()) {
+ Error(Start, "cannot use base register with variable reference");
+ return nullptr;
+ }
+ if (SM.getIndexReg()) {
+ Error(Start, "cannot use index register with variable reference");
+ return nullptr;
+ }
+ }
+
int BaseReg = SM.getBaseReg();
int IndexReg = SM.getIndexReg();
int Scale = SM.getScale();
@@ -1458,7 +1500,8 @@ X86AsmParser::ParseIntelBracExpression(unsigned SegReg, SMLoc Start,
InlineAsmIdentifierInfo &Info = SM.getIdentifierInfo();
return CreateMemForInlineAsm(SegReg, Disp, BaseReg, IndexReg, Scale, Start,
- End, Size, SM.getSymName(), Info);
+ End, Size, SM.getSymName(), Info,
+ isParsingInlineAsm());
}
// Inline assembly may use variable names with namespace alias qualifiers.
@@ -1541,7 +1584,7 @@ X86AsmParser::ParseIntelSegmentOverride(unsigned SegReg, SMLoc Start,
}
if (getLexer().is(AsmToken::LBrac))
- return ParseIntelBracExpression(SegReg, Start, ImmDisp, Size);
+ return ParseIntelBracExpression(SegReg, Start, ImmDisp, false, Size);
const MCExpr *Val;
SMLoc End;
@@ -1598,66 +1641,6 @@ X86AsmParser::ParseRoundingModeOp(SMLoc Start, SMLoc End) {
}
return ErrorOperand(Tok.getLoc(), "unknown token in expression");
}
-/// ParseIntelMemOperand - Parse intel style memory operand.
-std::unique_ptr<X86Operand> X86AsmParser::ParseIntelMemOperand(int64_t ImmDisp,
- SMLoc Start,
- unsigned Size) {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
- SMLoc End;
-
- // Parse ImmDisp [ BaseReg + Scale*IndexReg + Disp ].
- if (getLexer().is(AsmToken::LBrac))
- return ParseIntelBracExpression(/*SegReg=*/0, Start, ImmDisp, Size);
- assert(ImmDisp == 0);
-
- const MCExpr *Val;
- if (!isParsingInlineAsm()) {
- if (getParser().parsePrimaryExpr(Val, End))
- return ErrorOperand(Tok.getLoc(), "unknown token in expression");
-
- return X86Operand::CreateMem(getPointerWidth(), Val, Start, End, Size);
- }
-
- InlineAsmIdentifierInfo Info;
- StringRef Identifier = Tok.getString();
- if (ParseIntelIdentifier(Val, Identifier, Info,
- /*Unevaluated=*/false, End))
- return nullptr;
-
- if (!getLexer().is(AsmToken::LBrac))
- return CreateMemForInlineAsm(/*SegReg=*/0, Val, /*BaseReg=*/0, /*IndexReg=*/0,
- /*Scale=*/1, Start, End, Size, Identifier, Info);
-
- Parser.Lex(); // Eat '['
-
- // Parse Identifier [ ImmDisp ]
- IntelExprStateMachine SM(/*ImmDisp=*/0, /*StopOnLBrac=*/true,
- /*AddImmPrefix=*/false);
- if (ParseIntelExpression(SM, End))
- return nullptr;
-
- if (SM.getSym()) {
- Error(Start, "cannot use more than one symbol in memory operand");
- return nullptr;
- }
- if (SM.getBaseReg()) {
- Error(Start, "cannot use base register with variable reference");
- return nullptr;
- }
- if (SM.getIndexReg()) {
- Error(Start, "cannot use index register with variable reference");
- return nullptr;
- }
-
- const MCExpr *Disp = MCConstantExpr::create(SM.getImm(), getContext());
- // BaseReg is non-zero to avoid assertions. In the context of inline asm,
- // we're pointing to a local variable in memory, so the base register is
- // really the frame or stack pointer.
- return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp,
- /*BaseReg=*/1, /*IndexReg=*/0, /*Scale=*/1,
- Start, End, Size, Identifier, Info.OpDecl);
-}
/// Parse the '.' operator.
bool X86AsmParser::ParseIntelDotOperator(const MCExpr *Disp,
@@ -1725,8 +1708,9 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOffsetOfOperator() {
// The offset operator will have an 'r' constraint, thus we need to create
// register operand to ensure proper matching. Just pick a GPR based on
// the size of a pointer.
- unsigned RegNo =
- is64BitMode() ? X86::RBX : (is32BitMode() ? X86::EBX : X86::BX);
+ bool Parse32 = is32BitMode() || Code16GCC;
+ unsigned RegNo = is64BitMode() ? X86::RBX : (Parse32 ? X86::EBX : X86::BX);
+
return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true,
OffsetOfLoc, Identifier, Info.OpDecl);
}
@@ -1804,49 +1788,8 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOperand() {
Parser.Lex(); // Eat ptr.
PtrInOperand = true;
}
- Start = Tok.getLoc();
- // Immediate.
- if (getLexer().is(AsmToken::Integer) || getLexer().is(AsmToken::Minus) ||
- getLexer().is(AsmToken::Tilde) || getLexer().is(AsmToken::LParen)) {
- AsmToken StartTok = Tok;
- IntelExprStateMachine SM(/*Imm=*/0, /*StopOnLBrac=*/true,
- /*AddImmPrefix=*/false);
- if (ParseIntelExpression(SM, End))
- return nullptr;
-
- int64_t Imm = SM.getImm();
- if (isParsingInlineAsm()) {
- unsigned Len = Tok.getLoc().getPointer() - Start.getPointer();
- if (StartTok.getString().size() == Len)
- // Just add a prefix if this wasn't a complex immediate expression.
- InstInfo->AsmRewrites->emplace_back(AOK_ImmPrefix, Start);
- else
- // Otherwise, rewrite the complex expression as a single immediate.
- InstInfo->AsmRewrites->emplace_back(AOK_Imm, Start, Len, Imm);
- }
-
- if (getLexer().isNot(AsmToken::LBrac)) {
- // If a directional label (ie. 1f or 2b) was parsed above from
- // ParseIntelExpression() then SM.getSym() was set to a pointer to
- // to the MCExpr with the directional local symbol and this is a
- // memory operand not an immediate operand.
- if (SM.getSym())
- return X86Operand::CreateMem(getPointerWidth(), SM.getSym(), Start, End,
- Size);
-
- const MCExpr *ImmExpr = MCConstantExpr::create(Imm, getContext());
- return X86Operand::CreateImm(ImmExpr, Start, End);
- }
-
- // Only positive immediates are valid.
- if (Imm < 0)
- return ErrorOperand(Start, "expected a positive immediate displacement "
- "before bracketed expr.");
-
- // Parse ImmDisp [ BaseReg + Scale*IndexReg + Disp ].
- return ParseIntelMemOperand(Imm, Start, Size);
- }
+ Start = Tok.getLoc();
// rounding mode token
if (getSTI().getFeatureBits()[X86::FeatureAVX512] &&
@@ -1855,24 +1798,78 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOperand() {
// Register.
unsigned RegNo = 0;
- if (!ParseRegister(RegNo, Start, End)) {
+ if (getLexer().is(AsmToken::Identifier) &&
+ !ParseRegister(RegNo, Start, End)) {
// If this is a segment register followed by a ':', then this is the start
// of a segment override, otherwise this is a normal register reference.
- // In case it is a normal register and there is ptr in the operand this
+ // In case it is a normal register and there is ptr in the operand this
// is an error
- if (getLexer().isNot(AsmToken::Colon)){
- if (PtrInOperand){
+ if (RegNo == X86::RIP)
+ return ErrorOperand(Start, "rip can only be used as a base register");
+ if (getLexer().isNot(AsmToken::Colon)) {
+ if (PtrInOperand) {
return ErrorOperand(Start, "expected memory operand after "
"'ptr', found register operand instead");
}
return X86Operand::CreateReg(RegNo, Start, End);
}
-
return ParseIntelSegmentOverride(/*SegReg=*/RegNo, Start, Size);
}
- // Memory operand.
- return ParseIntelMemOperand(/*Disp=*/0, Start, Size);
+ // Immediates and Memory
+
+ // Parse [ BaseReg + Scale*IndexReg + Disp ].
+ if (getLexer().is(AsmToken::LBrac))
+ return ParseIntelBracExpression(/*SegReg=*/0, Start, /*ImmDisp=*/0, false,
+ Size);
+
+ AsmToken StartTok = Tok;
+ IntelExprStateMachine SM(/*Imm=*/0, /*StopOnLBrac=*/true,
+ /*AddImmPrefix=*/false);
+ if (ParseIntelExpression(SM, End))
+ return nullptr;
+
+ bool isSymbol = SM.getSym() && SM.getSym()->getKind() != MCExpr::Constant;
+ int64_t Imm = SM.getImm();
+ if (SM.getSym() && SM.getSym()->getKind() == MCExpr::Constant)
+ SM.getSym()->evaluateAsAbsolute(Imm);
+
+ if (StartTok.isNot(AsmToken::Identifier) &&
+ StartTok.isNot(AsmToken::String) && isParsingInlineAsm()) {
+ unsigned Len = Tok.getLoc().getPointer() - Start.getPointer();
+ if (StartTok.getString().size() == Len)
+ // Just add a prefix if this wasn't a complex immediate expression.
+ InstInfo->AsmRewrites->emplace_back(AOK_ImmPrefix, Start);
+ else
+ // Otherwise, rewrite the complex expression as a single immediate.
+ InstInfo->AsmRewrites->emplace_back(AOK_Imm, Start, Len, Imm);
+ }
+
+ if (getLexer().isNot(AsmToken::LBrac)) {
+ // If a directional label (ie. 1f or 2b) was parsed above from
+ // ParseIntelExpression() then SM.getSym() was set to a pointer to
+ // to the MCExpr with the directional local symbol and this is a
+ // memory operand not an immediate operand.
+ if (isSymbol) {
+ if (isParsingInlineAsm())
+ return CreateMemForInlineAsm(/*SegReg=*/0, SM.getSym(), /*BaseReg=*/0,
+ /*IndexReg=*/0,
+ /*Scale=*/1, Start, End, Size,
+ SM.getSymName(), SM.getIdentifierInfo());
+ return X86Operand::CreateMem(getPointerWidth(), SM.getSym(), Start, End,
+ Size);
+ }
+
+ const MCExpr *ImmExpr = MCConstantExpr::create(Imm, getContext());
+ return X86Operand::CreateImm(ImmExpr, Start, End);
+ }
+
+ // Only positive immediates are valid.
+ if (Imm < 0)
+ return ErrorOperand(Start, "expected a positive immediate displacement "
+ "before bracketed expr.");
+
+ return ParseIntelBracExpression(/*SegReg=*/0, Start, Imm, isSymbol, Size);
}
std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand() {
@@ -1891,6 +1888,11 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand() {
SMRange(Start, End));
return nullptr;
}
+ if (RegNo == X86::RIP) {
+ Error(Start, "%rip can only be used as a base register",
+ SMRange(Start, End));
+ return nullptr;
+ }
// If this is a segment register followed by a ':', then this is the start
// of a memory reference, otherwise this is a normal register reference.
@@ -1916,11 +1918,33 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand() {
SMLoc Start = Parser.getTok().getLoc(), End;
if (getSTI().getFeatureBits()[X86::FeatureAVX512])
return ParseRoundingModeOp(Start, End);
- return ErrorOperand(Start, "unknown token in expression");
+ return ErrorOperand(Start, "Unexpected '{' in expression");
}
}
}
+// true on failure, false otherwise
+// If no {z} mark was found - Parser doesn't advance
+bool X86AsmParser::ParseZ(std::unique_ptr<X86Operand> &Z,
+ const SMLoc &StartLoc) {
+ MCAsmParser &Parser = getParser();
+ // Assuming we are just pass the '{' mark, quering the next token
+ // Searched for {z}, but none was found. Return false, as no parsing error was
+ // encountered
+ if (!(getLexer().is(AsmToken::Identifier) &&
+ (getLexer().getTok().getIdentifier() == "z")))
+ return false;
+ Parser.Lex(); // Eat z
+ // Query and eat the '}' mark
+ if (!getLexer().is(AsmToken::RCurly))
+ return Error(getLexer().getLoc(), "Expected } at this point");
+ Parser.Lex(); // Eat '}'
+ // Assign Z with the {z} mark opernad
+ Z = X86Operand::CreateToken("{z}", StartLoc);
+ return false;
+}
+
+// true on failure, false otherwise
bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands,
const MCParsedAsmOperand &Op) {
MCAsmParser &Parser = getParser();
@@ -1932,13 +1956,11 @@ bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands,
if(getLexer().is(AsmToken::Integer)) {
// Parse memory broadcasting ({1to<NUM>}).
if (getLexer().getTok().getIntVal() != 1)
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Expected 1to<NUM> at this point");
+ return TokError("Expected 1to<NUM> at this point");
Parser.Lex(); // Eat "1" of 1to8
if (!getLexer().is(AsmToken::Identifier) ||
!getLexer().getTok().getIdentifier().startswith("to"))
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Expected 1to<NUM> at this point");
+ return TokError("Expected 1to<NUM> at this point");
// Recognize only reasonable suffixes.
const char *BroadcastPrimitive =
StringSwitch<const char*>(getLexer().getTok().getIdentifier())
@@ -1948,46 +1970,57 @@ bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands,
.Case("to16", "{1to16}")
.Default(nullptr);
if (!BroadcastPrimitive)
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Invalid memory broadcast primitive.");
+ return TokError("Invalid memory broadcast primitive.");
Parser.Lex(); // Eat "toN" of 1toN
if (!getLexer().is(AsmToken::RCurly))
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Expected } at this point");
+ return TokError("Expected } at this point");
Parser.Lex(); // Eat "}"
Operands.push_back(X86Operand::CreateToken(BroadcastPrimitive,
consumedToken));
// No AVX512 specific primitives can pass
// after memory broadcasting, so return.
- return true;
+ return false;
} else {
- // Parse mask register {%k1}
- Operands.push_back(X86Operand::CreateToken("{", consumedToken));
- if (std::unique_ptr<X86Operand> Op = ParseOperand()) {
- Operands.push_back(std::move(Op));
- if (!getLexer().is(AsmToken::RCurly))
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Expected } at this point");
- Operands.push_back(X86Operand::CreateToken("}", consumeToken()));
-
- // Parse "zeroing non-masked" semantic {z}
- if (getLexer().is(AsmToken::LCurly)) {
- Operands.push_back(X86Operand::CreateToken("{z}", consumeToken()));
- if (!getLexer().is(AsmToken::Identifier) ||
- getLexer().getTok().getIdentifier() != "z")
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Expected z at this point");
- Parser.Lex(); // Eat the z
+ // Parse either {k}{z}, {z}{k}, {k} or {z}
+ // last one have no meaning, but GCC accepts it
+ // Currently, we're just pass a '{' mark
+ std::unique_ptr<X86Operand> Z;
+ if (ParseZ(Z, consumedToken))
+ return true;
+ // Reaching here means that parsing of the allegadly '{z}' mark yielded
+ // no errors.
+ // Query for the need of further parsing for a {%k<NUM>} mark
+ if (!Z || getLexer().is(AsmToken::LCurly)) {
+ const SMLoc StartLoc = Z ? consumeToken() : consumedToken;
+ // Parse an op-mask register mark ({%k<NUM>}), which is now to be
+ // expected
+ if (std::unique_ptr<X86Operand> Op = ParseOperand()) {
if (!getLexer().is(AsmToken::RCurly))
- return !ErrorAndEatStatement(getLexer().getLoc(),
- "Expected } at this point");
- Parser.Lex(); // Eat the }
+ return Error(getLexer().getLoc(), "Expected } at this point");
+ Operands.push_back(X86Operand::CreateToken("{", StartLoc));
+ Operands.push_back(std::move(Op));
+ Operands.push_back(X86Operand::CreateToken("}", consumeToken()));
+ } else
+ return Error(getLexer().getLoc(),
+ "Expected an op-mask register at this point");
+ // {%k<NUM>} mark is found, inquire for {z}
+ if (getLexer().is(AsmToken::LCurly) && !Z) {
+ // Have we've found a parsing error, or found no (expected) {z} mark
+ // - report an error
+ if (ParseZ(Z, consumeToken()) || !Z)
+ return true;
+
}
+ // '{z}' on its own is meaningless, hence should be ignored.
+ // on the contrary - have it been accompanied by a K register,
+ // allow it.
+ if (Z)
+ Operands.push_back(std::move(Z));
}
}
}
}
- return true;
+ return false;
}
/// ParseMemOperand: segment: disp(basereg, indexreg, scale). The '%ds:' prefix
@@ -2077,7 +2110,16 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseMemOperand(unsigned SegReg,
// like "1(%eax,,1)", the assembler doesn't. Use "eiz" or "riz" for this.
if (getLexer().is(AsmToken::Percent)) {
SMLoc L;
- if (ParseRegister(IndexReg, L, L)) return nullptr;
+ if (ParseRegister(IndexReg, L, L))
+ return nullptr;
+ if (BaseReg == X86::RIP) {
+ Error(IndexLoc, "%rip as base register can not have an index register");
+ return nullptr;
+ }
+ if (IndexReg == X86::RIP) {
+ Error(IndexLoc, "%rip is not allowed as an index register");
+ return nullptr;
+ }
if (getLexer().isNot(AsmToken::RParen)) {
// Parse the scale amount:
@@ -2169,6 +2211,20 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
InstInfo = &Info;
StringRef PatchedName = Name;
+ if (Name == "jmp" && isParsingIntelSyntax() && isParsingInlineAsm()) {
+ StringRef NextTok = Parser.getTok().getString();
+ if (NextTok == "short") {
+ SMLoc NameEndLoc =
+ NameLoc.getFromPointer(NameLoc.getPointer() + Name.size());
+ // Eat the short keyword
+ Parser.Lex();
+ // MS ignores the short keyword, it determines the jmp type based
+ // on the distance of the label
+ InstInfo->AsmRewrites->emplace_back(AOK_Skip, NameEndLoc,
+ NextTok.size() + 1);
+ }
+ }
+
// FIXME: Hack to recognize setneb as setne.
if (PatchedName.startswith("set") && PatchedName.endswith("b") &&
PatchedName != "setb" && PatchedName != "setnb")
@@ -2321,10 +2377,9 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
while(1) {
if (std::unique_ptr<X86Operand> Op = ParseOperand()) {
Operands.push_back(std::move(Op));
- if (!HandleAVX512Operand(Operands, *Operands.back()))
+ if (HandleAVX512Operand(Operands, *Operands.back()))
return true;
} else {
- Parser.eatToEndOfStatement();
return true;
}
// check for comma and eat it
@@ -2340,8 +2395,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
isParsingIntelSyntax() && isParsingInlineAsm() &&
(getLexer().is(AsmToken::LCurly) || getLexer().is(AsmToken::RCurly));
if (getLexer().isNot(AsmToken::EndOfStatement) && !CurlyAsEndOfStatement)
- return ErrorAndEatStatement(getLexer().getLoc(),
- "unexpected token in argument list");
+ return TokError("unexpected token in argument list");
}
// Consume the EndOfStatement or the prefix separator Slash
@@ -2367,6 +2421,30 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
static_cast<X86Operand &>(*Operands[0]).setTokenValue(Repl);
}
+ // Moving a 32 or 16 bit value into a segment register has the same
+ // behavior. Modify such instructions to always take shorter form.
+ if ((Name == "mov" || Name == "movw" || Name == "movl") &&
+ (Operands.size() == 3)) {
+ X86Operand &Op1 = (X86Operand &)*Operands[1];
+ X86Operand &Op2 = (X86Operand &)*Operands[2];
+ SMLoc Loc = Op1.getEndLoc();
+ if (Op1.isReg() && Op2.isReg() &&
+ X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(
+ Op2.getReg()) &&
+ (X86MCRegisterClasses[X86::GR16RegClassID].contains(Op1.getReg()) ||
+ X86MCRegisterClasses[X86::GR32RegClassID].contains(Op1.getReg()))) {
+ // Change instruction name to match new instruction.
+ if (Name != "mov" && Name[3] == (is16BitMode() ? 'l' : 'w')) {
+ Name = is16BitMode() ? "movw" : "movl";
+ Operands[0] = X86Operand::CreateToken(Name, NameLoc);
+ }
+ // Select the correct equivalent 16-/32-bit source register.
+ unsigned Reg =
+ getX86SubSuperRegisterOrZero(Op1.getReg(), is16BitMode() ? 16 : 32);
+ Operands[1] = X86Operand::CreateReg(Reg, Loc, Loc);
+ }
+ }
+
// This is a terrible hack to handle "out[s]?[bwl]? %al, (%dx)" ->
// "outb %al, %dx". Out doesn't take a memory form, but this is a widely
// documented form in various unofficial manuals, so a lot of code uses it.
@@ -2472,7 +2550,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
(Name == "smov" || Name == "smovb" || Name == "smovw" ||
Name == "smovl" || Name == "smovd" || Name == "smovq"))) &&
(Operands.size() == 1 || Operands.size() == 3)) {
- if (Name == "movsd" && Operands.size() == 1)
+ if (Name == "movsd" && Operands.size() == 1 && !isParsingIntelSyntax())
Operands.back() = X86Operand::CreateToken("movsl", NameLoc);
AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc),
DefaultMemDIOperand(NameLoc));
@@ -2583,7 +2661,6 @@ void X86AsmParser::MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op,
bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo,
bool MatchingInlineAsm) {
assert(ErrorInfo && "Unknown missing feature!");
- ArrayRef<SMRange> EmptyRanges = None;
SmallString<126> Msg;
raw_svector_ostream OS(Msg);
OS << "instruction requires:";
@@ -2593,7 +2670,7 @@ bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo,
OS << ' ' << getSubtargetFeatureName(ErrorInfo & Mask);
Mask <<= 1;
}
- return Error(IDLoc, OS.str(), EmptyRanges, MatchingInlineAsm);
+ return Error(IDLoc, OS.str(), SMRange(), MatchingInlineAsm);
}
bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
@@ -2604,7 +2681,7 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
assert(!Operands.empty() && "Unexpect empty operand list!");
X86Operand &Op = static_cast<X86Operand &>(*Operands[0]);
assert(Op.isToken() && "Leading operand should always be a mnemonic!");
- ArrayRef<SMRange> EmptyRanges = None;
+ SMRange EmptyRange = None;
// First, handle aliases that expand to multiple instructions.
MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm);
@@ -2613,9 +2690,8 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
MCInst Inst;
// First, try a direct match.
- switch (MatchInstructionImpl(Operands, Inst,
- ErrorInfo, MatchingInlineAsm,
- isParsingIntelSyntax())) {
+ switch (MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
+ isParsingIntelSyntax())) {
default: llvm_unreachable("Unexpected match result!");
case Match_Success:
// Some instructions need post-processing to, for example, tweak which
@@ -2666,8 +2742,8 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I) {
Tmp.back() = Suffixes[I];
- Match[I] = MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore,
- MatchingInlineAsm, isParsingIntelSyntax());
+ Match[I] = MatchInstruction(Operands, Inst, ErrorInfoIgnore,
+ MatchingInlineAsm, isParsingIntelSyntax());
// If this returned as a missing feature failure, remember that.
if (Match[I] == Match_MissingFeature)
ErrorInfoMissingFeature = ErrorInfoIgnore;
@@ -2711,7 +2787,7 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
OS << "'" << Base << MatchChars[i] << "'";
}
OS << ")";
- Error(IDLoc, OS.str(), EmptyRanges, MatchingInlineAsm);
+ Error(IDLoc, OS.str(), EmptyRange, MatchingInlineAsm);
return true;
}
@@ -2721,17 +2797,15 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
// mnemonic was invalid.
if (std::count(std::begin(Match), std::end(Match), Match_MnemonicFail) == 4) {
if (!WasOriginallyInvalidOperand) {
- ArrayRef<SMRange> Ranges =
- MatchingInlineAsm ? EmptyRanges : Op.getLocRange();
return Error(IDLoc, "invalid instruction mnemonic '" + Base + "'",
- Ranges, MatchingInlineAsm);
+ Op.getLocRange(), MatchingInlineAsm);
}
// Recover location info for the operand if we know which was the problem.
if (ErrorInfo != ~0ULL) {
if (ErrorInfo >= Operands.size())
- return Error(IDLoc, "too few operands for instruction",
- EmptyRanges, MatchingInlineAsm);
+ return Error(IDLoc, "too few operands for instruction", EmptyRange,
+ MatchingInlineAsm);
X86Operand &Operand = (X86Operand &)*Operands[ErrorInfo];
if (Operand.getStartLoc().isValid()) {
@@ -2741,7 +2815,7 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
}
}
- return Error(IDLoc, "invalid operand for instruction", EmptyRanges,
+ return Error(IDLoc, "invalid operand for instruction", EmptyRange,
MatchingInlineAsm);
}
@@ -2758,16 +2832,33 @@ bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode,
// operand failure.
if (std::count(std::begin(Match), std::end(Match),
Match_InvalidOperand) == 1) {
- return Error(IDLoc, "invalid operand for instruction", EmptyRanges,
+ return Error(IDLoc, "invalid operand for instruction", EmptyRange,
MatchingInlineAsm);
}
// If all of these were an outright failure, report it in a useless way.
Error(IDLoc, "unknown use of instruction mnemonic without a size suffix",
- EmptyRanges, MatchingInlineAsm);
+ EmptyRange, MatchingInlineAsm);
return true;
}
+unsigned X86AsmParser::AdjustAVX512Mem(unsigned Size,
+ X86Operand* UnsizedMemOpNext) {
+ // Check for the existence of an AVX512 platform
+ if (!getSTI().getFeatureBits()[X86::FeatureAVX512])
+ return 0;
+ // Allow adjusting upon a (x|y|z)mm
+ if (Size == 512 || Size == 256 || Size == 128)
+ return Size;
+ // This is an allegadly broadcasting mem op adjustment,
+ // allow some more inquiring to validate it
+ if (Size == 64 || Size == 32)
+ return UnsizedMemOpNext && UnsizedMemOpNext->isToken() &&
+ UnsizedMemOpNext->getToken().substr(0, 4).equals("{1to") ? Size : 0;
+ // Do not allow any other type of adjustments
+ return 0;
+}
+
bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
MCStreamer &Out,
@@ -2777,7 +2868,8 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
X86Operand &Op = static_cast<X86Operand &>(*Operands[0]);
assert(Op.isToken() && "Leading operand should always be a mnemonic!");
StringRef Mnemonic = Op.getToken();
- ArrayRef<SMRange> EmptyRanges = None;
+ SMRange EmptyRange = None;
+ StringRef Base = Op.getToken();
// First, handle aliases that expand to multiple instructions.
MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm);
@@ -2786,8 +2878,17 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
// Find one unsized memory operand, if present.
X86Operand *UnsizedMemOp = nullptr;
+ // If unsized memory operand was found - obtain following operand.
+ // For use in AdjustAVX512Mem
+ X86Operand *UnsizedMemOpNext = nullptr;
for (const auto &Op : Operands) {
X86Operand *X86Op = static_cast<X86Operand *>(Op.get());
+ if (UnsizedMemOp) {
+ UnsizedMemOpNext = X86Op;
+ // Have we found an unqualified memory operand,
+ // break. IA allows only one memory operand.
+ break;
+ }
if (X86Op->isMemUnsized())
UnsizedMemOp = X86Op;
}
@@ -2804,26 +2905,58 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
}
}
+ SmallVector<unsigned, 8> Match;
+ uint64_t ErrorInfoMissingFeature = 0;
+
+ // If unsized push has immediate operand we should default the default pointer
+ // size for the size.
+ if (Mnemonic == "push" && Operands.size() == 2) {
+ auto *X86Op = static_cast<X86Operand *>(Operands[1].get());
+ if (X86Op->isImm()) {
+ // If it's not a constant fall through and let remainder take care of it.
+ const auto *CE = dyn_cast<MCConstantExpr>(X86Op->getImm());
+ unsigned Size = getPointerWidth();
+ if (CE &&
+ (isIntN(Size, CE->getValue()) || isUIntN(Size, CE->getValue()))) {
+ SmallString<16> Tmp;
+ Tmp += Base;
+ Tmp += (is64BitMode())
+ ? "q"
+ : (is32BitMode()) ? "l" : (is16BitMode()) ? "w" : " ";
+ Op.setTokenValue(Tmp);
+ // Do match in ATT mode to allow explicit suffix usage.
+ Match.push_back(MatchInstruction(Operands, Inst, ErrorInfo,
+ MatchingInlineAsm,
+ false /*isParsingIntelSyntax()*/));
+ Op.setTokenValue(Base);
+ }
+ }
+ }
+
// If an unsized memory operand is present, try to match with each memory
// operand size. In Intel assembly, the size is not part of the instruction
// mnemonic.
- SmallVector<unsigned, 8> Match;
- uint64_t ErrorInfoMissingFeature = 0;
+ unsigned MatchedSize = 0;
if (UnsizedMemOp && UnsizedMemOp->isMemUnsized()) {
static const unsigned MopSizes[] = {8, 16, 32, 64, 80, 128, 256, 512};
for (unsigned Size : MopSizes) {
UnsizedMemOp->Mem.Size = Size;
uint64_t ErrorInfoIgnore;
unsigned LastOpcode = Inst.getOpcode();
- unsigned M =
- MatchInstructionImpl(Operands, Inst, ErrorInfoIgnore,
- MatchingInlineAsm, isParsingIntelSyntax());
+ unsigned M = MatchInstruction(Operands, Inst, ErrorInfoIgnore,
+ MatchingInlineAsm, isParsingIntelSyntax());
if (Match.empty() || LastOpcode != Inst.getOpcode())
Match.push_back(M);
// If this returned as a missing feature failure, remember that.
if (Match.back() == Match_MissingFeature)
ErrorInfoMissingFeature = ErrorInfoIgnore;
+ if (M == Match_Success)
+ // MS-compatability:
+ // Adjust AVX512 vector/broadcast memory operand,
+ // when facing the absence of a size qualifier.
+ // Match GCC behavior on respective cases.
+ MatchedSize = AdjustAVX512Mem(Size, UnsizedMemOpNext);
}
// Restore the size of the unsized memory operand if we modified it.
@@ -2835,9 +2968,8 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
// operation. There shouldn't be any ambiguity in our mnemonic table, so try
// matching with the unsized operand.
if (Match.empty()) {
- Match.push_back(MatchInstructionImpl(Operands, Inst, ErrorInfo,
- MatchingInlineAsm,
- isParsingIntelSyntax()));
+ Match.push_back(MatchInstruction(
+ Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax()));
// If this returned as a missing feature failure, remember that.
if (Match.back() == Match_MissingFeature)
ErrorInfoMissingFeature = ErrorInfo;
@@ -2849,10 +2981,8 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
// If it's a bad mnemonic, all results will be the same.
if (Match.back() == Match_MnemonicFail) {
- ArrayRef<SMRange> Ranges =
- MatchingInlineAsm ? EmptyRanges : Op.getLocRange();
return Error(IDLoc, "invalid instruction mnemonic '" + Mnemonic + "'",
- Ranges, MatchingInlineAsm);
+ Op.getLocRange(), MatchingInlineAsm);
}
// If exactly one matched, then we treat that as a successful match (and the
@@ -2861,6 +2991,14 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
unsigned NumSuccessfulMatches =
std::count(std::begin(Match), std::end(Match), Match_Success);
if (NumSuccessfulMatches == 1) {
+ if (MatchedSize && isParsingInlineAsm() && isParsingIntelSyntax())
+ // MS compatibility -
+ // Fix the rewrite according to the matched memory size
+ // MS inline assembly only
+ for (AsmRewrite &AR : *InstInfo->AsmRewrites)
+ if ((AR.Loc.getPointer() == UnsizedMemOp->StartLoc.getPointer()) &&
+ (AR.Kind == AOK_SizeDirective))
+ AR.Val = MatchedSize;
// Some instructions need post-processing to, for example, tweak which
// encoding is selected. Loop on it while changes happen so the individual
// transformations can chain off each other.
@@ -2875,11 +3013,9 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
} else if (NumSuccessfulMatches > 1) {
assert(UnsizedMemOp &&
"multiple matches only possible with unsized memory operands");
- ArrayRef<SMRange> Ranges =
- MatchingInlineAsm ? EmptyRanges : UnsizedMemOp->getLocRange();
return Error(UnsizedMemOp->getStartLoc(),
"ambiguous operand size for instruction '" + Mnemonic + "\'",
- Ranges, MatchingInlineAsm);
+ UnsizedMemOp->getLocRange(), MatchingInlineAsm);
}
// If one instruction matched with a missing feature, report this as a
@@ -2895,12 +3031,12 @@ bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode,
// operand failure.
if (std::count(std::begin(Match), std::end(Match),
Match_InvalidOperand) == 1) {
- return Error(IDLoc, "invalid operand for instruction", EmptyRanges,
+ return Error(IDLoc, "invalid operand for instruction", EmptyRange,
MatchingInlineAsm);
}
// If all of these were an outright failure, report it in a useless way.
- return Error(IDLoc, "unknown instruction mnemonic", EmptyRanges,
+ return Error(IDLoc, "unknown instruction mnemonic", EmptyRange,
MatchingInlineAsm);
}
@@ -2945,14 +3081,14 @@ bool X86AsmParser::ParseDirective(AsmToken DirectiveID) {
/// parseDirectiveEven
/// ::= .even
bool X86AsmParser::parseDirectiveEven(SMLoc L) {
- const MCSection *Section = getStreamer().getCurrentSection().first;
if (getLexer().isNot(AsmToken::EndOfStatement)) {
TokError("unexpected token in directive");
return false;
}
+ const MCSection *Section = getStreamer().getCurrentSectionOnly();
if (!Section) {
getStreamer().InitSections(false);
- Section = getStreamer().getCurrentSection().first;
+ Section = getStreamer().getCurrentSectionOnly();
}
if (Section->UseCodeAlign())
getStreamer().EmitCodeAlignment(2, 0);
@@ -3001,12 +3137,21 @@ bool X86AsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
/// ::= .code16 | .code32 | .code64
bool X86AsmParser::ParseDirectiveCode(StringRef IDVal, SMLoc L) {
MCAsmParser &Parser = getParser();
+ Code16GCC = false;
if (IDVal == ".code16") {
Parser.Lex();
if (!is16BitMode()) {
SwitchMode(X86::Mode16Bit);
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
}
+ } else if (IDVal == ".code16gcc") {
+ // .code16gcc parses as if in 32-bit mode, but emits code in 16-bit mode.
+ Parser.Lex();
+ Code16GCC = true;
+ if (!is16BitMode()) {
+ SwitchMode(X86::Mode16Bit);
+ getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
+ }
} else if (IDVal == ".code32") {
Parser.Lex();
if (!is32BitMode()) {
@@ -3029,8 +3174,8 @@ bool X86AsmParser::ParseDirectiveCode(StringRef IDVal, SMLoc L) {
// Force static initialization.
extern "C" void LLVMInitializeX86AsmParser() {
- RegisterMCAsmParser<X86AsmParser> X(TheX86_32Target);
- RegisterMCAsmParser<X86AsmParser> Y(TheX86_64Target);
+ RegisterMCAsmParser<X86AsmParser> X(getTheX86_32Target());
+ RegisterMCAsmParser<X86AsmParser> Y(getTheX86_64Target());
}
#define GET_REGISTER_MATCHER
diff --git a/contrib/llvm/lib/Target/X86/AsmParser/X86Operand.h b/contrib/llvm/lib/Target/X86/AsmParser/X86Operand.h
index a04c2f5..9db1a84 100644
--- a/contrib/llvm/lib/Target/X86/AsmParser/X86Operand.h
+++ b/contrib/llvm/lib/Target/X86/AsmParser/X86Operand.h
@@ -192,8 +192,10 @@ struct X86Operand : public MCParsedAsmOperand {
bool isImmUnsignedi8() const {
if (!isImm()) return false;
+ // If this isn't a constant expr, just assume it fits and let relaxation
+ // handle it.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- if (!CE) return false;
+ if (!CE) return true;
return isImmUnsignedi8Value(CE->getValue());
}
diff --git a/contrib/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp b/contrib/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
index 008dead..0871888 100644
--- a/contrib/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
+++ b/contrib/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
@@ -96,7 +96,7 @@ void llvm::X86Disassembler::Debug(const char *file, unsigned line,
dbgs() << file << ":" << line << ": " << s;
}
-const char *llvm::X86Disassembler::GetInstrName(unsigned Opcode,
+StringRef llvm::X86Disassembler::GetInstrName(unsigned Opcode,
const void *mii) {
const MCInstrInfo *MII = static_cast<const MCInstrInfo *>(mii);
return MII->getName(Opcode);
@@ -470,10 +470,20 @@ static void translateImmediate(MCInst &mcInst, uint64_t immediate,
case X86::VCMPPSZrmi: NewOpc = X86::VCMPPSZrmi_alt; break;
case X86::VCMPPSZrri: NewOpc = X86::VCMPPSZrri_alt; break;
case X86::VCMPPSZrrib: NewOpc = X86::VCMPPSZrrib_alt; break;
- case X86::VCMPSDZrm: NewOpc = X86::VCMPSDZrmi_alt; break;
- case X86::VCMPSDZrr: NewOpc = X86::VCMPSDZrri_alt; break;
- case X86::VCMPSSZrm: NewOpc = X86::VCMPSSZrmi_alt; break;
- case X86::VCMPSSZrr: NewOpc = X86::VCMPSSZrri_alt; break;
+ case X86::VCMPPDZ128rmi: NewOpc = X86::VCMPPDZ128rmi_alt; break;
+ case X86::VCMPPDZ128rri: NewOpc = X86::VCMPPDZ128rri_alt; break;
+ case X86::VCMPPSZ128rmi: NewOpc = X86::VCMPPSZ128rmi_alt; break;
+ case X86::VCMPPSZ128rri: NewOpc = X86::VCMPPSZ128rri_alt; break;
+ case X86::VCMPPDZ256rmi: NewOpc = X86::VCMPPDZ256rmi_alt; break;
+ case X86::VCMPPDZ256rri: NewOpc = X86::VCMPPDZ256rri_alt; break;
+ case X86::VCMPPSZ256rmi: NewOpc = X86::VCMPPSZ256rmi_alt; break;
+ case X86::VCMPPSZ256rri: NewOpc = X86::VCMPPSZ256rri_alt; break;
+ case X86::VCMPSDZrm_Int: NewOpc = X86::VCMPSDZrmi_alt; break;
+ case X86::VCMPSDZrr_Int: NewOpc = X86::VCMPSDZrri_alt; break;
+ case X86::VCMPSDZrrb_Int: NewOpc = X86::VCMPSDZrrb_alt; break;
+ case X86::VCMPSSZrm_Int: NewOpc = X86::VCMPSSZrmi_alt; break;
+ case X86::VCMPSSZrr_Int: NewOpc = X86::VCMPSSZrri_alt; break;
+ case X86::VCMPSSZrrb_Int: NewOpc = X86::VCMPSSZrrb_alt; break;
}
// Switch opcode to the one that doesn't get special printing.
mcInst.setOpcode(NewOpc);
@@ -1066,8 +1076,8 @@ static MCDisassembler *createX86Disassembler(const Target &T,
extern "C" void LLVMInitializeX86Disassembler() {
// Register the disassembler.
- TargetRegistry::RegisterMCDisassembler(TheX86_32Target,
+ TargetRegistry::RegisterMCDisassembler(getTheX86_32Target(),
createX86Disassembler);
- TargetRegistry::RegisterMCDisassembler(TheX86_64Target,
+ TargetRegistry::RegisterMCDisassembler(getTheX86_64Target(),
createX86Disassembler);
}
diff --git a/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp b/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
index b0a150a..ab64d6f 100644
--- a/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
+++ b/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
@@ -825,7 +825,7 @@ static int getIDWithAttrMask(uint16_t* instructionID,
* @param orig - The instruction that is not 16-bit
* @param equiv - The instruction that is 16-bit
*/
-static bool is16BitEquivalent(const char* orig, const char* equiv) {
+static bool is16BitEquivalent(const char *orig, const char *equiv) {
off_t i;
for (i = 0;; i++) {
@@ -850,7 +850,7 @@ static bool is16BitEquivalent(const char* orig, const char* equiv) {
*
* @param name - The instruction that is not 16-bit
*/
-static bool is64Bit(const char* name) {
+static bool is64Bit(const char *name) {
off_t i;
for (i = 0;; ++i) {
@@ -1044,9 +1044,9 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
return 0;
}
- const char *SpecName = GetInstrName(instructionIDWithREXW, miiArg);
+ auto SpecName = GetInstrName(instructionIDWithREXW, miiArg);
// If not a 64-bit instruction. Switch the opcode.
- if (!is64Bit(SpecName)) {
+ if (!is64Bit(SpecName.data())) {
insn->instructionID = instructionIDWithREXW;
insn->spec = specifierForUID(instructionIDWithREXW);
return 0;
@@ -1092,7 +1092,7 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
const struct InstructionSpecifier *spec;
uint16_t instructionIDWithOpsize;
- const char *specName, *specWithOpSizeName;
+ llvm::StringRef specName, specWithOpSizeName;
spec = specifierForUID(instructionID);
@@ -1112,7 +1112,7 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
specName = GetInstrName(instructionID, miiArg);
specWithOpSizeName = GetInstrName(instructionIDWithOpsize, miiArg);
- if (is16BitEquivalent(specName, specWithOpSizeName) &&
+ if (is16BitEquivalent(specName.data(), specWithOpSizeName.data()) &&
(insn->mode == MODE_16BIT) ^ insn->prefixPresent[0x66]) {
insn->instructionID = instructionIDWithOpsize;
insn->spec = specifierForUID(instructionIDWithOpsize);
diff --git a/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
index 24d24a2..b07fd0b 100644
--- a/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
+++ b/contrib/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
@@ -674,7 +674,7 @@ int decodeInstruction(InternalInstruction *insn,
/// \param s The message to print.
void Debug(const char *file, unsigned line, const char *s);
-const char *GetInstrName(unsigned Opcode, const void *mii);
+StringRef GetInstrName(unsigned Opcode, const void *mii);
} // namespace X86Disassembler
} // namespace llvm
diff --git a/contrib/llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp b/contrib/llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp
index 3a5d056..10b7e6f 100644
--- a/contrib/llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp
@@ -291,6 +291,9 @@ void X86ATTInstPrinter::printMemOffset(const MCInst *MI, unsigned Op,
void X86ATTInstPrinter::printU8Imm(const MCInst *MI, unsigned Op,
raw_ostream &O) {
+ if (MI->getOperand(Op).isExpr())
+ return printOperand(MI, Op, O);
+
O << markup("<imm:") << '$' << formatImm(MI->getOperand(Op).getImm() & 0xff)
<< markup(">");
}
diff --git a/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.cpp b/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.cpp
index f537956..8594add 100644
--- a/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.cpp
+++ b/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.cpp
@@ -255,6 +255,10 @@ static std::string getMaskName(const MCInst *MI, const char *DestName,
CASE_MASKZ_UNPCK(UNPCKLPS, r)
CASE_MASKZ_SHUF(PALIGNR, r)
CASE_MASKZ_SHUF(PALIGNR, m)
+ CASE_MASKZ_SHUF(ALIGNQ, r)
+ CASE_MASKZ_SHUF(ALIGNQ, m)
+ CASE_MASKZ_SHUF(ALIGND, r)
+ CASE_MASKZ_SHUF(ALIGND, m)
CASE_MASKZ_SHUF(SHUFPD, m)
CASE_MASKZ_SHUF(SHUFPD, r)
CASE_MASKZ_SHUF(SHUFPS, m)
@@ -277,6 +281,26 @@ static std::string getMaskName(const MCInst *MI, const char *DestName,
CASE_MASKZ_VSHUF(64X2, r)
CASE_MASKZ_VSHUF(32X4, m)
CASE_MASKZ_VSHUF(32X4, r)
+ CASE_MASKZ_INS_COMMON(BROADCASTF64X2, Z128, rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTI64X2, Z128, rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTF64X2, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTI64X2, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTF64X4, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTI64X4, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X4, Z256, rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X4, Z256, rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X4, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X4, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X8, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X8, , rm)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X2, Z256, r)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X2, Z256, r)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X2, Z256, m)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X2, Z256, m)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X2, Z, r)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X2, Z, r)
+ CASE_MASKZ_INS_COMMON(BROADCASTF32X2, Z, m)
+ CASE_MASKZ_INS_COMMON(BROADCASTI32X2, Z, m)
MaskWithZero = true;
MaskRegName = getRegName(MI->getOperand(1).getReg());
break;
@@ -320,6 +344,10 @@ static std::string getMaskName(const MCInst *MI, const char *DestName,
CASE_MASK_UNPCK(UNPCKLPS, r)
CASE_MASK_SHUF(PALIGNR, r)
CASE_MASK_SHUF(PALIGNR, m)
+ CASE_MASK_SHUF(ALIGNQ, r)
+ CASE_MASK_SHUF(ALIGNQ, m)
+ CASE_MASK_SHUF(ALIGND, r)
+ CASE_MASK_SHUF(ALIGND, m)
CASE_MASK_SHUF(SHUFPD, m)
CASE_MASK_SHUF(SHUFPD, r)
CASE_MASK_SHUF(SHUFPS, m)
@@ -342,6 +370,26 @@ static std::string getMaskName(const MCInst *MI, const char *DestName,
CASE_MASK_VSHUF(64X2, r)
CASE_MASK_VSHUF(32X4, m)
CASE_MASK_VSHUF(32X4, r)
+ CASE_MASK_INS_COMMON(BROADCASTF64X2, Z128, rm)
+ CASE_MASK_INS_COMMON(BROADCASTI64X2, Z128, rm)
+ CASE_MASK_INS_COMMON(BROADCASTF64X2, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTI64X2, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTF64X4, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTI64X4, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTF32X4, Z256, rm)
+ CASE_MASK_INS_COMMON(BROADCASTI32X4, Z256, rm)
+ CASE_MASK_INS_COMMON(BROADCASTF32X4, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTI32X4, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTF32X8, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTI32X8, , rm)
+ CASE_MASK_INS_COMMON(BROADCASTF32X2, Z256, r)
+ CASE_MASK_INS_COMMON(BROADCASTI32X2, Z256, r)
+ CASE_MASK_INS_COMMON(BROADCASTF32X2, Z256, m)
+ CASE_MASK_INS_COMMON(BROADCASTI32X2, Z256, m)
+ CASE_MASK_INS_COMMON(BROADCASTF32X2, Z, r)
+ CASE_MASK_INS_COMMON(BROADCASTI32X2, Z, r)
+ CASE_MASK_INS_COMMON(BROADCASTF32X2, Z, m)
+ CASE_MASK_INS_COMMON(BROADCASTI32X2, Z, m)
MaskRegName = getRegName(MI->getOperand(2).getReg());
break;
}
@@ -382,7 +430,7 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VBLENDPDrri:
case X86::VBLENDPDYrri:
Src2Name = getRegName(MI->getOperand(2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
case X86::BLENDPDrmi:
case X86::VBLENDPDrmi:
case X86::VBLENDPDYrmi:
@@ -398,7 +446,7 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VBLENDPSrri:
case X86::VBLENDPSYrri:
Src2Name = getRegName(MI->getOperand(2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
case X86::BLENDPSrmi:
case X86::VBLENDPSrmi:
case X86::VBLENDPSYrmi:
@@ -414,7 +462,7 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VPBLENDWrri:
case X86::VPBLENDWYrri:
Src2Name = getRegName(MI->getOperand(2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
case X86::PBLENDWrmi:
case X86::VPBLENDWrmi:
case X86::VPBLENDWYrmi:
@@ -429,7 +477,7 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VPBLENDDrri:
case X86::VPBLENDDYrri:
Src2Name = getRegName(MI->getOperand(2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
case X86::VPBLENDDrmi:
case X86::VPBLENDDYrmi:
if (MI->getOperand(NumOperands - 1).isImm())
@@ -442,12 +490,12 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::INSERTPSrr:
case X86::VINSERTPSrr:
- case X86::VINSERTPSzrr:
+ case X86::VINSERTPSZrr:
Src2Name = getRegName(MI->getOperand(2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
case X86::INSERTPSrm:
case X86::VINSERTPSrm:
- case X86::VINSERTPSzrm:
+ case X86::VINSERTPSZrm:
DestName = getRegName(MI->getOperand(0).getReg());
Src1Name = getRegName(MI->getOperand(1).getReg());
if (MI->getOperand(NumOperands - 1).isImm())
@@ -507,7 +555,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_MOVDUP(MOVSLDUP, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_MOVDUP(MOVSLDUP, m)
DestName = getRegName(MI->getOperand(0).getReg());
DecodeMOVSLDUPMask(getRegOperandVectorVT(MI, MVT::f32, 0), ShuffleMask);
@@ -515,7 +564,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_MOVDUP(MOVSHDUP, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_MOVDUP(MOVSHDUP, m)
DestName = getRegName(MI->getOperand(0).getReg());
DecodeMOVSHDUPMask(getRegOperandVectorVT(MI, MVT::f32, 0), ShuffleMask);
@@ -523,7 +573,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_MOVDUP(MOVDDUP, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_MOVDUP(MOVDDUP, m)
DestName = getRegName(MI->getOperand(0).getReg());
DecodeMOVDDUPMask(getRegOperandVectorVT(MI, MVT::f64, 0), ShuffleMask);
@@ -566,7 +617,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_SHUF(PALIGNR, rri)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_SHUF(PALIGNR, rmi)
Src2Name = getRegName(MI->getOperand(NumOperands-(RegForm?3:7)).getReg());
DestName = getRegName(MI->getOperand(0).getReg());
@@ -576,9 +628,46 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
ShuffleMask);
break;
+ CASE_AVX512_INS_COMMON(ALIGNQ, Z, rri)
+ CASE_AVX512_INS_COMMON(ALIGNQ, Z256, rri)
+ CASE_AVX512_INS_COMMON(ALIGNQ, Z128, rri)
+ Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
+ RegForm = true;
+ LLVM_FALLTHROUGH;
+
+ CASE_AVX512_INS_COMMON(ALIGNQ, Z, rmi)
+ CASE_AVX512_INS_COMMON(ALIGNQ, Z256, rmi)
+ CASE_AVX512_INS_COMMON(ALIGNQ, Z128, rmi)
+ Src2Name = getRegName(MI->getOperand(NumOperands-(RegForm?3:7)).getReg());
+ DestName = getRegName(MI->getOperand(0).getReg());
+ if (MI->getOperand(NumOperands - 1).isImm())
+ DecodeVALIGNMask(getRegOperandVectorVT(MI, MVT::i64, 0),
+ MI->getOperand(NumOperands - 1).getImm(),
+ ShuffleMask);
+ break;
+
+ CASE_AVX512_INS_COMMON(ALIGND, Z, rri)
+ CASE_AVX512_INS_COMMON(ALIGND, Z256, rri)
+ CASE_AVX512_INS_COMMON(ALIGND, Z128, rri)
+ Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
+ RegForm = true;
+ LLVM_FALLTHROUGH;
+
+ CASE_AVX512_INS_COMMON(ALIGND, Z, rmi)
+ CASE_AVX512_INS_COMMON(ALIGND, Z256, rmi)
+ CASE_AVX512_INS_COMMON(ALIGND, Z128, rmi)
+ Src2Name = getRegName(MI->getOperand(NumOperands-(RegForm?3:7)).getReg());
+ DestName = getRegName(MI->getOperand(0).getReg());
+ if (MI->getOperand(NumOperands - 1).isImm())
+ DecodeVALIGNMask(getRegOperandVectorVT(MI, MVT::i32, 0),
+ MI->getOperand(NumOperands - 1).getImm(),
+ ShuffleMask);
+ break;
+
CASE_SHUF(PSHUFD, ri)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_SHUF(PSHUFD, mi)
DestName = getRegName(MI->getOperand(0).getReg());
if (MI->getOperand(NumOperands - 1).isImm())
@@ -589,7 +678,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_SHUF(PSHUFHW, ri)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_SHUF(PSHUFHW, mi)
DestName = getRegName(MI->getOperand(0).getReg());
if (MI->getOperand(NumOperands - 1).isImm())
@@ -600,7 +690,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_SHUF(PSHUFLW, ri)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_SHUF(PSHUFLW, mi)
DestName = getRegName(MI->getOperand(0).getReg());
if (MI->getOperand(NumOperands - 1).isImm())
@@ -611,7 +702,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PSHUFWri:
Src1Name = getRegName(MI->getOperand(1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
case X86::MMX_PSHUFWmi:
DestName = getRegName(MI->getOperand(0).getReg());
if (MI->getOperand(NumOperands - 1).isImm())
@@ -622,7 +714,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::PSWAPDrr:
Src1Name = getRegName(MI->getOperand(1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
case X86::PSWAPDrm:
DestName = getRegName(MI->getOperand(0).getReg());
DecodePSWAPMask(MVT::v2i32, ShuffleMask);
@@ -632,7 +725,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PUNPCKHBWirr:
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKHBW, m)
case X86::MMX_PUNPCKHBWirm:
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -644,7 +738,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PUNPCKHWDirr:
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKHWD, m)
case X86::MMX_PUNPCKHWDirm:
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -656,7 +751,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PUNPCKHDQirr:
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKHDQ, m)
case X86::MMX_PUNPCKHDQirm:
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -667,7 +763,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_UNPCK(PUNPCKHQDQ, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKHQDQ, m)
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
DestName = getRegName(MI->getOperand(0).getReg());
@@ -678,7 +775,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PUNPCKLBWirr:
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKLBW, m)
case X86::MMX_PUNPCKLBWirm:
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -690,7 +788,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PUNPCKLWDirr:
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKLWD, m)
case X86::MMX_PUNPCKLWDirm:
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -702,7 +801,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::MMX_PUNPCKLDQirr:
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKLDQ, m)
case X86::MMX_PUNPCKLDQirm:
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -713,7 +813,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_UNPCK(PUNPCKLQDQ, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(PUNPCKLQDQ, m)
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
DestName = getRegName(MI->getOperand(0).getReg());
@@ -723,7 +824,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_SHUF(SHUFPD, rri)
Src2Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_SHUF(SHUFPD, rmi)
if (MI->getOperand(NumOperands - 1).isImm())
DecodeSHUFPMask(getRegOperandVectorVT(MI, MVT::f64, 0),
@@ -736,7 +838,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_SHUF(SHUFPS, rri)
Src2Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_SHUF(SHUFPS, rmi)
if (MI->getOperand(NumOperands - 1).isImm())
DecodeSHUFPMask(getRegOperandVectorVT(MI, MVT::f32, 0),
@@ -749,7 +852,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_VSHUF(64X2, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_VSHUF(64X2, m)
decodeVSHUF64x2FamilyMask(getRegOperandVectorVT(MI, MVT::i64, 0),
MI->getOperand(NumOperands - 1).getImm(),
@@ -761,7 +865,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_VSHUF(32X4, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_VSHUF(32X4, m)
decodeVSHUF64x2FamilyMask(getRegOperandVectorVT(MI, MVT::i32, 0),
MI->getOperand(NumOperands - 1).getImm(),
@@ -773,7 +878,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_UNPCK(UNPCKLPD, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(UNPCKLPD, m)
DecodeUNPCKLMask(getRegOperandVectorVT(MI, MVT::f64, 0), ShuffleMask);
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -783,7 +889,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_UNPCK(UNPCKLPS, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(UNPCKLPS, m)
DecodeUNPCKLMask(getRegOperandVectorVT(MI, MVT::f32, 0), ShuffleMask);
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -793,7 +900,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_UNPCK(UNPCKHPD, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(UNPCKHPD, m)
DecodeUNPCKHMask(getRegOperandVectorVT(MI, MVT::f64, 0), ShuffleMask);
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -803,7 +911,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_UNPCK(UNPCKHPS, r)
Src2Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
RegForm = true;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_UNPCK(UNPCKHPS, m)
DecodeUNPCKHMask(getRegOperandVectorVT(MI, MVT::f32, 0), ShuffleMask);
Src1Name = getRegName(MI->getOperand(NumOperands-(RegForm?2:6)).getReg());
@@ -812,7 +921,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_VPERMILPI(PERMILPS, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_VPERMILPI(PERMILPS, m)
if (MI->getOperand(NumOperands - 1).isImm())
DecodePSHUFMask(getRegOperandVectorVT(MI, MVT::f32, 0),
@@ -823,7 +933,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_VPERMILPI(PERMILPD, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_VPERMILPI(PERMILPD, m)
if (MI->getOperand(NumOperands - 1).isImm())
DecodePSHUFMask(getRegOperandVectorVT(MI, MVT::f64, 0),
@@ -835,7 +946,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VPERM2F128rr:
case X86::VPERM2I128rr:
Src2Name = getRegName(MI->getOperand(2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
case X86::VPERM2F128rm:
case X86::VPERM2I128rm:
// For instruction comments purpose, assume the 256-bit vector is v4i64.
@@ -849,7 +961,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_VPERM(PERMPD, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_VPERM(PERMPD, m)
if (MI->getOperand(NumOperands - 1).isImm())
DecodeVPERMMask(getRegOperandVectorVT(MI, MVT::f64, 0),
@@ -860,7 +973,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_VPERM(PERMQ, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 2).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_VPERM(PERMQ, m)
if (MI->getOperand(NumOperands - 1).isImm())
DecodeVPERMMask(getRegOperandVectorVT(MI, MVT::i64, 0),
@@ -874,7 +988,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VMOVSDZrr:
Src2Name = getRegName(MI->getOperand(2).getReg());
Src1Name = getRegName(MI->getOperand(1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
case X86::MOVSDrm:
case X86::VMOVSDrm:
case X86::VMOVSDZrm:
@@ -887,7 +1002,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VMOVSSZrr:
Src2Name = getRegName(MI->getOperand(2).getReg());
Src1Name = getRegName(MI->getOperand(1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
case X86::MOVSSrm:
case X86::VMOVSSrm:
case X86::VMOVSSZrm:
@@ -901,15 +1017,11 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VMOVZPQILo2PQIrr:
case X86::VMOVZPQILo2PQIZrr:
Src1Name = getRegName(MI->getOperand(1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
case X86::MOVQI2PQIrm:
- case X86::MOVZQI2PQIrm:
- case X86::MOVZPQILo2PQIrm:
case X86::VMOVQI2PQIrm:
case X86::VMOVQI2PQIZrm:
- case X86::VMOVZQI2PQIrm:
- case X86::VMOVZPQILo2PQIrm:
- case X86::VMOVZPQILo2PQIZrm:
DecodeZeroMoveLowMask(MVT::v2i64, ShuffleMask);
DestName = getRegName(MI->getOperand(0).getReg());
break;
@@ -946,15 +1058,59 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
case X86::VBROADCASTF128:
case X86::VBROADCASTI128:
+ CASE_AVX512_INS_COMMON(BROADCASTF64X2, Z128, rm)
+ CASE_AVX512_INS_COMMON(BROADCASTI64X2, Z128, rm)
DecodeSubVectorBroadcast(MVT::v4f64, MVT::v2f64, ShuffleMask);
DestName = getRegName(MI->getOperand(0).getReg());
break;
+ CASE_AVX512_INS_COMMON(BROADCASTF64X2, , rm)
+ CASE_AVX512_INS_COMMON(BROADCASTI64X2, , rm)
+ DecodeSubVectorBroadcast(MVT::v8f64, MVT::v2f64, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
+ CASE_AVX512_INS_COMMON(BROADCASTF64X4, , rm)
+ CASE_AVX512_INS_COMMON(BROADCASTI64X4, , rm)
+ DecodeSubVectorBroadcast(MVT::v8f64, MVT::v4f64, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
+ CASE_AVX512_INS_COMMON(BROADCASTF32X4, Z256, rm)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X4, Z256, rm)
+ DecodeSubVectorBroadcast(MVT::v8f32, MVT::v4f32, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
+ CASE_AVX512_INS_COMMON(BROADCASTF32X4, , rm)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X4, , rm)
+ DecodeSubVectorBroadcast(MVT::v16f32, MVT::v4f32, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
+ CASE_AVX512_INS_COMMON(BROADCASTF32X8, , rm)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X8, , rm)
+ DecodeSubVectorBroadcast(MVT::v16f32, MVT::v8f32, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
+ CASE_AVX512_INS_COMMON(BROADCASTF32X2, Z256, r)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X2, Z256, r)
+ Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
+ CASE_AVX512_INS_COMMON(BROADCASTF32X2, Z256, m)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X2, Z256, m)
+ DecodeSubVectorBroadcast(MVT::v8f32, MVT::v2f32, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
+ CASE_AVX512_INS_COMMON(BROADCASTF32X2, Z, r)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X2, Z, r)
+ Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
+ CASE_AVX512_INS_COMMON(BROADCASTF32X2, Z, m)
+ CASE_AVX512_INS_COMMON(BROADCASTI32X2, Z, m)
+ DecodeSubVectorBroadcast(MVT::v16f32, MVT::v2f32, ShuffleMask);
+ DestName = getRegName(MI->getOperand(0).getReg());
+ break;
CASE_PMOVZX(PMOVZXBW, r)
CASE_PMOVZX(PMOVZXBD, r)
CASE_PMOVZX(PMOVZXBQ, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_PMOVZX(PMOVZXBW, m)
CASE_PMOVZX(PMOVZXBD, m)
CASE_PMOVZX(PMOVZXBQ, m)
@@ -965,7 +1121,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_PMOVZX(PMOVZXWD, r)
CASE_PMOVZX(PMOVZXWQ, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_PMOVZX(PMOVZXWD, m)
CASE_PMOVZX(PMOVZXWQ, m)
DecodeZeroExtendMask(MVT::i16, getZeroExtensionResultType(MI), ShuffleMask);
@@ -974,7 +1131,8 @@ bool llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
CASE_PMOVZX(PMOVZXDQ, r)
Src1Name = getRegName(MI->getOperand(NumOperands - 1).getReg());
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+
CASE_PMOVZX(PMOVZXDQ, m)
DecodeZeroExtendMask(MVT::i32, getZeroExtensionResultType(MI), ShuffleMask);
DestName = getRegName(MI->getOperand(0).getReg());
diff --git a/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.h b/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.h
index 687581b..c6d0d85 100644
--- a/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.h
+++ b/contrib/llvm/lib/Target/X86/InstPrinter/X86InstComments.h
@@ -16,6 +16,11 @@
#define LLVM_LIB_TARGET_X86_INSTPRINTER_X86INSTCOMMENTS_H
namespace llvm {
+
+ enum AsmComments {
+ AC_EVEX_2_VEX = 0x2 // For instr that was compressed from EVEX to VEX.
+ };
+
class MCInst;
class raw_ostream;
bool EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS,
diff --git a/contrib/llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp b/contrib/llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp
index 879378f..4443edb 100644
--- a/contrib/llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp
+++ b/contrib/llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp
@@ -253,5 +253,8 @@ void X86IntelInstPrinter::printMemOffset(const MCInst *MI, unsigned Op,
void X86IntelInstPrinter::printU8Imm(const MCInst *MI, unsigned Op,
raw_ostream &O) {
+ if (MI->getOperand(Op).isExpr())
+ return MI->getOperand(Op).getExpr()->print(O, &MAI);
+
O << formatImm(MI->getOperand(Op).getImm() & 0xff);
}
diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
index e77a0dc..e83ec9f 100644
--- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
+++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
@@ -76,12 +76,12 @@ class X86AsmBackend : public MCAsmBackend {
public:
X86AsmBackend(const Target &T, StringRef CPU)
: MCAsmBackend(), CPU(CPU),
- MaxNopLength((CPU == "slm" || CPU == "lakemont") ? 7 : 15) {
+ MaxNopLength((CPU == "slm") ? 7 : 15) {
HasNopl = CPU != "generic" && CPU != "i386" && CPU != "i486" &&
CPU != "i586" && CPU != "pentium" && CPU != "pentium-mmx" &&
CPU != "i686" && CPU != "k6" && CPU != "k6-2" && CPU != "k6-3" &&
CPU != "geode" && CPU != "winchip-c6" && CPU != "winchip2" &&
- CPU != "c3" && CPU != "c3-2";
+ CPU != "c3" && CPU != "c3-2" && CPU != "lakemont";
}
unsigned getNumFixupKinds() const override {
@@ -546,8 +546,12 @@ protected:
// .cfi_def_cfa_register %rbp
//
HasFP = true;
- assert(MRI.getLLVMRegNum(Inst.getRegister(), true) ==
- (Is64Bit ? X86::RBP : X86::EBP) && "Invalid frame pointer!");
+
+ // If the frame pointer is other than esp/rsp, we do not have a way to
+ // generate a compact unwinding representation, so bail out.
+ if (MRI.getLLVMRegNum(Inst.getRegister(), true) !=
+ (Is64Bit ? X86::RBP : X86::EBP))
+ return 0;
// Reset the counts.
memset(SavedRegs, 0, sizeof(SavedRegs));
@@ -837,7 +841,8 @@ public:
MCAsmBackend *llvm::createX86_32AsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const Triple &TheTriple,
- StringRef CPU) {
+ StringRef CPU,
+ const MCTargetOptions &Options) {
if (TheTriple.isOSBinFormatMachO())
return new DarwinX86_32AsmBackend(T, MRI, CPU);
@@ -855,7 +860,8 @@ MCAsmBackend *llvm::createX86_32AsmBackend(const Target &T,
MCAsmBackend *llvm::createX86_64AsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const Triple &TheTriple,
- StringRef CPU) {
+ StringRef CPU,
+ const MCTargetOptions &Options) {
if (TheTriple.isOSBinFormatMachO()) {
MachO::CPUSubTypeX86 CS =
StringSwitch<MachO::CPUSubTypeX86>(TheTriple.getArchName())
diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index b419517..aab5525 100644
--- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -234,88 +234,114 @@ namespace X86II {
/// their one register operand added to their opcode.
AddRegFrm = 2,
- /// MRMDestReg - This form is used for instructions that use the Mod/RM byte
- /// to specify a destination, which in this case is a register.
- ///
- MRMDestReg = 3,
-
- /// MRMDestMem - This form is used for instructions that use the Mod/RM byte
- /// to specify a destination, which in this case is memory.
- ///
- MRMDestMem = 4,
-
- /// MRMSrcReg - This form is used for instructions that use the Mod/RM byte
- /// to specify a source, which in this case is a register.
- ///
- MRMSrcReg = 5,
-
- /// MRMSrcMem - This form is used for instructions that use the Mod/RM byte
- /// to specify a source, which in this case is memory.
- ///
- MRMSrcMem = 6,
-
/// RawFrmMemOffs - This form is for instructions that store an absolute
/// memory offset as an immediate with a possible segment override.
- RawFrmMemOffs = 7,
+ RawFrmMemOffs = 3,
/// RawFrmSrc - This form is for instructions that use the source index
/// register SI/ESI/RSI with a possible segment override.
- RawFrmSrc = 8,
+ RawFrmSrc = 4,
/// RawFrmDst - This form is for instructions that use the destination index
/// register DI/EDI/ESI.
- RawFrmDst = 9,
+ RawFrmDst = 5,
/// RawFrmSrc - This form is for instructions that use the source index
/// register SI/ESI/ERI with a possible segment override, and also the
/// destination index register DI/ESI/RDI.
- RawFrmDstSrc = 10,
+ RawFrmDstSrc = 6,
/// RawFrmImm8 - This is used for the ENTER instruction, which has two
/// immediates, the first of which is a 16-bit immediate (specified by
/// the imm encoding) and the second is a 8-bit fixed value.
- RawFrmImm8 = 11,
+ RawFrmImm8 = 7,
/// RawFrmImm16 - This is used for CALL FAR instructions, which have two
/// immediates, the first of which is a 16 or 32-bit immediate (specified by
/// the imm encoding) and the second is a 16-bit fixed value. In the AMD
/// manual, this operand is described as pntr16:32 and pntr16:16
- RawFrmImm16 = 12,
-
- /// MRMX[rm] - The forms are used to represent instructions that use a
- /// Mod/RM byte, and don't use the middle field for anything.
- MRMXr = 14, MRMXm = 15,
+ RawFrmImm16 = 8,
/// MRM[0-7][rm] - These forms are used to represent instructions that use
/// a Mod/RM byte, and use the middle field to hold extended opcode
/// information. In the intel manual these are represented as /0, /1, ...
///
- // First, instructions that operate on a register r/m operand...
- MRM0r = 16, MRM1r = 17, MRM2r = 18, MRM3r = 19, // Format /0 /1 /2 /3
- MRM4r = 20, MRM5r = 21, MRM6r = 22, MRM7r = 23, // Format /4 /5 /6 /7
+ /// MRMDestMem - This form is used for instructions that use the Mod/RM byte
+ /// to specify a destination, which in this case is memory.
+ ///
+ MRMDestMem = 32,
+
+ /// MRMSrcMem - This form is used for instructions that use the Mod/RM byte
+ /// to specify a source, which in this case is memory.
+ ///
+ MRMSrcMem = 33,
+
+ /// MRMSrcMem4VOp3 - This form is used for instructions that encode
+ /// operand 3 with VEX.VVVV and load from memory.
+ ///
+ MRMSrcMem4VOp3 = 34,
+
+ /// MRMSrcMemOp4 - This form is used for instructions that use the Mod/RM
+ /// byte to specify the fourth source, which in this case is memory.
+ ///
+ MRMSrcMemOp4 = 35,
+
+ /// MRMXm - This form is used for instructions that use the Mod/RM byte
+ /// to specify a memory source, but doesn't use the middle field.
+ ///
+ MRMXm = 39, // Instruction that uses Mod/RM but not the middle field.
// Next, instructions that operate on a memory r/m operand...
- MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27, // Format /0 /1 /2 /3
- MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31, // Format /4 /5 /6 /7
-
- //// MRM_XX - A mod/rm byte of exactly 0xXX.
- MRM_C0 = 32, MRM_C1 = 33, MRM_C2 = 34, MRM_C3 = 35,
- MRM_C4 = 36, MRM_C5 = 37, MRM_C6 = 38, MRM_C7 = 39,
- MRM_C8 = 40, MRM_C9 = 41, MRM_CA = 42, MRM_CB = 43,
- MRM_CC = 44, MRM_CD = 45, MRM_CE = 46, MRM_CF = 47,
- MRM_D0 = 48, MRM_D1 = 49, MRM_D2 = 50, MRM_D3 = 51,
- MRM_D4 = 52, MRM_D5 = 53, MRM_D6 = 54, MRM_D7 = 55,
- MRM_D8 = 56, MRM_D9 = 57, MRM_DA = 58, MRM_DB = 59,
- MRM_DC = 60, MRM_DD = 61, MRM_DE = 62, MRM_DF = 63,
- MRM_E0 = 64, MRM_E1 = 65, MRM_E2 = 66, MRM_E3 = 67,
- MRM_E4 = 68, MRM_E5 = 69, MRM_E6 = 70, MRM_E7 = 71,
- MRM_E8 = 72, MRM_E9 = 73, MRM_EA = 74, MRM_EB = 75,
- MRM_EC = 76, MRM_ED = 77, MRM_EE = 78, MRM_EF = 79,
- MRM_F0 = 80, MRM_F1 = 81, MRM_F2 = 82, MRM_F3 = 83,
- MRM_F4 = 84, MRM_F5 = 85, MRM_F6 = 86, MRM_F7 = 87,
- MRM_F8 = 88, MRM_F9 = 89, MRM_FA = 90, MRM_FB = 91,
- MRM_FC = 92, MRM_FD = 93, MRM_FE = 94, MRM_FF = 95,
+ MRM0m = 40, MRM1m = 41, MRM2m = 42, MRM3m = 43, // Format /0 /1 /2 /3
+ MRM4m = 44, MRM5m = 45, MRM6m = 46, MRM7m = 47, // Format /4 /5 /6 /7
+
+ /// MRMDestReg - This form is used for instructions that use the Mod/RM byte
+ /// to specify a destination, which in this case is a register.
+ ///
+ MRMDestReg = 48,
+
+ /// MRMSrcReg - This form is used for instructions that use the Mod/RM byte
+ /// to specify a source, which in this case is a register.
+ ///
+ MRMSrcReg = 49,
+
+ /// MRMSrcReg4VOp3 - This form is used for instructions that encode
+ /// operand 3 with VEX.VVVV and do not load from memory.
+ ///
+ MRMSrcReg4VOp3 = 50,
+
+ /// MRMSrcRegOp4 - This form is used for instructions that use the Mod/RM
+ /// byte to specify the fourth source, which in this case is a register.
+ ///
+ MRMSrcRegOp4 = 51,
+
+ /// MRMXr - This form is used for instructions that use the Mod/RM byte
+ /// to specify a register source, but doesn't use the middle field.
+ ///
+ MRMXr = 55, // Instruction that uses Mod/RM but not the middle field.
+
+ // Instructions that operate on a register r/m operand...
+ MRM0r = 56, MRM1r = 57, MRM2r = 58, MRM3r = 59, // Format /0 /1 /2 /3
+ MRM4r = 60, MRM5r = 61, MRM6r = 62, MRM7r = 63, // Format /4 /5 /6 /7
+
+ /// MRM_XX - A mod/rm byte of exactly 0xXX.
+ MRM_C0 = 64, MRM_C1 = 65, MRM_C2 = 66, MRM_C3 = 67,
+ MRM_C4 = 68, MRM_C5 = 69, MRM_C6 = 70, MRM_C7 = 71,
+ MRM_C8 = 72, MRM_C9 = 73, MRM_CA = 74, MRM_CB = 75,
+ MRM_CC = 76, MRM_CD = 77, MRM_CE = 78, MRM_CF = 79,
+ MRM_D0 = 80, MRM_D1 = 81, MRM_D2 = 82, MRM_D3 = 83,
+ MRM_D4 = 84, MRM_D5 = 85, MRM_D6 = 86, MRM_D7 = 87,
+ MRM_D8 = 88, MRM_D9 = 89, MRM_DA = 90, MRM_DB = 91,
+ MRM_DC = 92, MRM_DD = 93, MRM_DE = 94, MRM_DF = 95,
+ MRM_E0 = 96, MRM_E1 = 97, MRM_E2 = 98, MRM_E3 = 99,
+ MRM_E4 = 100, MRM_E5 = 101, MRM_E6 = 102, MRM_E7 = 103,
+ MRM_E8 = 104, MRM_E9 = 105, MRM_EA = 106, MRM_EB = 107,
+ MRM_EC = 108, MRM_ED = 109, MRM_EE = 110, MRM_EF = 111,
+ MRM_F0 = 112, MRM_F1 = 113, MRM_F2 = 114, MRM_F3 = 115,
+ MRM_F4 = 116, MRM_F5 = 117, MRM_F6 = 118, MRM_F7 = 119,
+ MRM_F8 = 120, MRM_F9 = 121, MRM_FA = 122, MRM_FB = 123,
+ MRM_FC = 124, MRM_FD = 125, MRM_FE = 126, MRM_FF = 127,
FormMask = 127,
@@ -403,12 +429,13 @@ namespace X86II {
ImmMask = 15 << ImmShift,
Imm8 = 1 << ImmShift,
Imm8PCRel = 2 << ImmShift,
- Imm16 = 3 << ImmShift,
- Imm16PCRel = 4 << ImmShift,
- Imm32 = 5 << ImmShift,
- Imm32PCRel = 6 << ImmShift,
- Imm32S = 7 << ImmShift,
- Imm64 = 8 << ImmShift,
+ Imm8Reg = 3 << ImmShift,
+ Imm16 = 4 << ImmShift,
+ Imm16PCRel = 5 << ImmShift,
+ Imm32 = 6 << ImmShift,
+ Imm32PCRel = 7 << ImmShift,
+ Imm32S = 8 << ImmShift,
+ Imm64 = 9 << ImmShift,
//===------------------------------------------------------------------===//
// FP Instruction Classification... Zero is non-fp instruction.
@@ -488,39 +515,15 @@ namespace X86II {
VEX_4VShift = VEX_WShift + 1,
VEX_4V = 1ULL << VEX_4VShift,
- /// VEX_4VOp3 - Similar to VEX_4V, but used on instructions that encode
- /// operand 3 with VEX.vvvv.
- VEX_4VOp3Shift = VEX_4VShift + 1,
- VEX_4VOp3 = 1ULL << VEX_4VOp3Shift,
-
- /// VEX_I8IMM - Specifies that the last register used in a AVX instruction,
- /// must be encoded in the i8 immediate field. This usually happens in
- /// instructions with 4 operands.
- VEX_I8IMMShift = VEX_4VOp3Shift + 1,
- VEX_I8IMM = 1ULL << VEX_I8IMMShift,
-
/// VEX_L - Stands for a bit in the VEX opcode prefix meaning the current
/// instruction uses 256-bit wide registers. This is usually auto detected
/// if a VR256 register is used, but some AVX instructions also have this
/// field marked when using a f256 memory references.
- VEX_LShift = VEX_I8IMMShift + 1,
+ VEX_LShift = VEX_4VShift + 1,
VEX_L = 1ULL << VEX_LShift,
- // VEX_LIG - Specifies that this instruction ignores the L-bit in the VEX
- // prefix. Usually used for scalar instructions. Needed by disassembler.
- VEX_LIGShift = VEX_LShift + 1,
- VEX_LIG = 1ULL << VEX_LIGShift,
-
- // TODO: we should combine VEX_L and VEX_LIG together to form a 2-bit field
- // with following encoding:
- // - 00 V128
- // - 01 V256
- // - 10 V512
- // - 11 LIG (but, in insn encoding, leave VEX.L and EVEX.L in zeros.
- // this will save 1 tsflag bit
-
// EVEX_K - Set if this instruction requires masking
- EVEX_KShift = VEX_LIGShift + 1,
+ EVEX_KShift = VEX_LShift + 1,
EVEX_K = 1ULL << EVEX_KShift,
// EVEX_Z - Set if this instruction has EVEX.Z field set.
@@ -548,13 +551,8 @@ namespace X86II {
Has3DNow0F0FOpcodeShift = CD8_Scale_Shift + 7,
Has3DNow0F0FOpcode = 1ULL << Has3DNow0F0FOpcodeShift,
- /// MemOp4 - Used to indicate swapping of operand 3 and 4 to be encoded in
- /// ModRM or I8IMM. This is used for FMA4 and XOP instructions.
- MemOp4Shift = Has3DNow0F0FOpcodeShift + 1,
- MemOp4 = 1ULL << MemOp4Shift,
-
/// Explicitly specified rounding control
- EVEX_RCShift = MemOp4Shift + 1,
+ EVEX_RCShift = Has3DNow0F0FOpcodeShift + 1,
EVEX_RC = 1ULL << EVEX_RCShift
};
@@ -575,7 +573,8 @@ namespace X86II {
switch (TSFlags & X86II::ImmMask) {
default: llvm_unreachable("Unknown immediate size");
case X86II::Imm8:
- case X86II::Imm8PCRel: return 1;
+ case X86II::Imm8PCRel:
+ case X86II::Imm8Reg: return 1;
case X86II::Imm16:
case X86II::Imm16PCRel: return 2;
case X86II::Imm32:
@@ -595,6 +594,7 @@ namespace X86II {
case X86II::Imm32PCRel:
return true;
case X86II::Imm8:
+ case X86II::Imm8Reg:
case X86II::Imm16:
case X86II::Imm32:
case X86II::Imm32S:
@@ -612,6 +612,7 @@ namespace X86II {
return true;
case X86II::Imm8:
case X86II::Imm8PCRel:
+ case X86II::Imm8Reg:
case X86II::Imm16:
case X86II::Imm16PCRel:
case X86II::Imm32:
@@ -626,26 +627,25 @@ namespace X86II {
/// in this instruction.
/// If this is a two-address instruction,skip one of the register operands.
/// FIXME: This should be handled during MCInst lowering.
- inline int getOperandBias(const MCInstrDesc& Desc)
+ inline unsigned getOperandBias(const MCInstrDesc& Desc)
{
unsigned NumOps = Desc.getNumOperands();
- unsigned CurOp = 0;
if (NumOps > 1 && Desc.getOperandConstraint(1, MCOI::TIED_TO) == 0)
- ++CurOp;
- else if (NumOps > 3 && Desc.getOperandConstraint(2, MCOI::TIED_TO) == 0 &&
- Desc.getOperandConstraint(3, MCOI::TIED_TO) == 1)
+ return 1;
+ if (NumOps > 3 && Desc.getOperandConstraint(2, MCOI::TIED_TO) == 0 &&
+ Desc.getOperandConstraint(3, MCOI::TIED_TO) == 1)
// Special case for AVX-512 GATHER with 2 TIED_TO operands
// Skip the first 2 operands: dst, mask_wb
- CurOp += 2;
- else if (NumOps > 3 && Desc.getOperandConstraint(2, MCOI::TIED_TO) == 0 &&
- Desc.getOperandConstraint(NumOps - 1, MCOI::TIED_TO) == 1)
+ return 2;
+ if (NumOps > 3 && Desc.getOperandConstraint(2, MCOI::TIED_TO) == 0 &&
+ Desc.getOperandConstraint(NumOps - 1, MCOI::TIED_TO) == 1)
// Special case for GATHER with 2 TIED_TO operands
// Skip the first 2 operands: dst, mask_wb
- CurOp += 2;
- else if (NumOps > 2 && Desc.getOperandConstraint(NumOps - 2, MCOI::TIED_TO) == 0)
+ return 2;
+ if (NumOps > 2 && Desc.getOperandConstraint(NumOps - 2, MCOI::TIED_TO) == 0)
// SCATTER
- ++CurOp;
- return CurOp;
+ return 1;
+ return 0;
}
/// getMemoryOperandNo - The function returns the MCInst operand # for the
@@ -658,7 +658,6 @@ namespace X86II {
///
inline int getMemoryOperandNo(uint64_t TSFlags) {
bool HasVEX_4V = TSFlags & X86II::VEX_4V;
- bool HasMemOp4 = TSFlags & X86II::MemOp4;
bool HasEVEX_K = TSFlags & X86II::EVEX_K;
switch (TSFlags & X86II::FormMask) {
@@ -666,8 +665,6 @@ namespace X86II {
case X86II::Pseudo:
case X86II::RawFrm:
case X86II::AddRegFrm:
- case X86II::MRMDestReg:
- case X86II::MRMSrcReg:
case X86II::RawFrmImm8:
case X86II::RawFrmImm16:
case X86II::RawFrmMemOffs:
@@ -680,7 +677,17 @@ namespace X86II {
case X86II::MRMSrcMem:
// Start from 1, skip any registers encoded in VEX_VVVV or I8IMM, or a
// mask register.
- return 1 + HasVEX_4V + HasMemOp4 + HasEVEX_K;
+ return 1 + HasVEX_4V + HasEVEX_K;
+ case X86II::MRMSrcMem4VOp3:
+ // Skip registers encoded in reg.
+ return 1 + HasEVEX_K;
+ case X86II::MRMSrcMemOp4:
+ // Skip registers encoded in reg, VEX_VVVV, and I8IMM.
+ return 3;
+ case X86II::MRMDestReg:
+ case X86II::MRMSrcReg:
+ case X86II::MRMSrcReg4VOp3:
+ case X86II::MRMSrcRegOp4:
case X86II::MRMXr:
case X86II::MRM0r: case X86II::MRM1r:
case X86II::MRM2r: case X86II::MRM3r:
@@ -723,12 +730,9 @@ namespace X86II {
/// isX86_64ExtendedReg - Is the MachineOperand a x86-64 extended (r8 or
/// higher) register? e.g. r8, xmm8, xmm13, etc.
inline bool isX86_64ExtendedReg(unsigned RegNo) {
- if ((RegNo >= X86::XMM8 && RegNo <= X86::XMM15) ||
- (RegNo >= X86::XMM24 && RegNo <= X86::XMM31) ||
- (RegNo >= X86::YMM8 && RegNo <= X86::YMM15) ||
- (RegNo >= X86::YMM24 && RegNo <= X86::YMM31) ||
- (RegNo >= X86::ZMM8 && RegNo <= X86::ZMM15) ||
- (RegNo >= X86::ZMM24 && RegNo <= X86::ZMM31))
+ if ((RegNo >= X86::XMM8 && RegNo <= X86::XMM31) ||
+ (RegNo >= X86::YMM8 && RegNo <= X86::YMM31) ||
+ (RegNo >= X86::ZMM8 && RegNo <= X86::ZMM31))
return true;
switch (RegNo) {
@@ -743,6 +747,8 @@ namespace X86II {
case X86::R12B: case X86::R13B: case X86::R14B: case X86::R15B:
case X86::CR8: case X86::CR9: case X86::CR10: case X86::CR11:
case X86::CR12: case X86::CR13: case X86::CR14: case X86::CR15:
+ case X86::DR8: case X86::DR9: case X86::DR10: case X86::DR11:
+ case X86::DR12: case X86::DR13: case X86::DR14: case X86::DR15:
return true;
}
return false;
@@ -761,6 +767,16 @@ namespace X86II {
return (reg == X86::SPL || reg == X86::BPL ||
reg == X86::SIL || reg == X86::DIL);
}
+
+ /// isKMasked - Is this a masked instruction.
+ inline bool isKMasked(uint64_t TSFlags) {
+ return (TSFlags & X86II::EVEX_K) != 0;
+ }
+
+ /// isKMergedMasked - Is this a merge masked instruction.
+ inline bool isKMergeMasked(uint64_t TSFlags) {
+ return isKMasked(TSFlags) && (TSFlags & X86II::EVEX_Z) == 0;
+ }
}
} // end namespace llvm;
diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
index b7c56ce..48a1d8f 100644
--- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
+++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp
@@ -31,8 +31,7 @@ static cl::opt<AsmWriterFlavorTy>
AsmWriterFlavor("x86-asm-syntax", cl::init(ATT),
cl::desc("Choose style of code to emit from X86 backend:"),
cl::values(clEnumValN(ATT, "att", "Emit AT&T-style assembly"),
- clEnumValN(Intel, "intel", "Emit Intel-style assembly"),
- clEnumValEnd));
+ clEnumValN(Intel, "intel", "Emit Intel-style assembly")));
static cl::opt<bool>
MarkedJTDataRegions("mark-data-regions", cl::init(true),
diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 96c2e81..8045e7c 100644
--- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -81,7 +81,8 @@ public:
MI.getOperand(OpNum).getReg());
}
- bool isX86_64ExtendedReg(const MCInst &MI, unsigned OpNum) const {
+ // Does this register require a bit to be set in REX prefix.
+ bool isREXExtendedReg(const MCInst &MI, unsigned OpNum) const {
return (getX86RegEncoding(MI, OpNum) >> 3) & 1;
}
@@ -602,8 +603,6 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
uint64_t Encoding = TSFlags & X86II::EncodingMask;
bool HasEVEX_K = TSFlags & X86II::EVEX_K;
bool HasVEX_4V = TSFlags & X86II::VEX_4V;
- bool HasVEX_4VOp3 = TSFlags & X86II::VEX_4VOp3;
- bool HasMemOp4 = TSFlags & X86II::MemOp4;
bool HasEVEX_RC = TSFlags & X86II::EVEX_RC;
// VEX_R: opcode externsion equivalent to REX.R in
@@ -745,11 +744,10 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
// src1(ModR/M), MemAddr
// src1(ModR/M), src2(VEX_4V), MemAddr
// src1(ModR/M), MemAddr, imm8
- // src1(ModR/M), MemAddr, src2(VEX_I8IMM)
+ // src1(ModR/M), MemAddr, src2(Imm[7:4])
//
// FMA4:
- // dst(ModR/M.reg), src1(VEX_4V), src2(ModR/M), src3(VEX_I8IMM)
- // dst(ModR/M.reg), src1(VEX_4V), src2(VEX_I8IMM), src3(ModR/M),
+ // dst(ModR/M.reg), src1(VEX_4V), src2(ModR/M), src3(Imm[7:4])
unsigned RegEnc = getX86RegEncoding(MI, CurOp++);
VEX_R = ~(RegEnc >> 3) & 1;
EVEX_R2 = ~(RegEnc >> 4) & 1;
@@ -770,13 +768,34 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
if (!HasVEX_4V) // Only needed with VSIB which don't use VVVV.
EVEX_V2 = ~(IndexRegEnc >> 4) & 1;
- if (HasVEX_4VOp3)
- // Instruction format for 4VOp3:
- // src1(ModR/M), MemAddr, src3(VEX_4V)
- // CurOp points to start of the MemoryOperand,
- // it skips TIED_TO operands if exist, then increments past src1.
- // CurOp + X86::AddrNumOperands will point to src3.
- VEX_4V = ~getX86RegEncoding(MI, CurOp + X86::AddrNumOperands) & 0xf;
+ break;
+ }
+ case X86II::MRMSrcMem4VOp3: {
+ // Instruction format for 4VOp3:
+ // src1(ModR/M), MemAddr, src3(VEX_4V)
+ unsigned RegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_R = ~(RegEnc >> 3) & 1;
+
+ unsigned BaseRegEnc = getX86RegEncoding(MI, MemOperand + X86::AddrBaseReg);
+ VEX_B = ~(BaseRegEnc >> 3) & 1;
+ unsigned IndexRegEnc = getX86RegEncoding(MI, MemOperand+X86::AddrIndexReg);
+ VEX_X = ~(IndexRegEnc >> 3) & 1;
+
+ VEX_4V = ~getX86RegEncoding(MI, CurOp + X86::AddrNumOperands) & 0xf;
+ break;
+ }
+ case X86II::MRMSrcMemOp4: {
+ // dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
+ unsigned RegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_R = ~(RegEnc >> 3) & 1;
+
+ unsigned VRegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_4V = ~VRegEnc & 0xf;
+
+ unsigned BaseRegEnc = getX86RegEncoding(MI, MemOperand + X86::AddrBaseReg);
+ VEX_B = ~(BaseRegEnc >> 3) & 1;
+ unsigned IndexRegEnc = getX86RegEncoding(MI, MemOperand+X86::AddrIndexReg);
+ VEX_X = ~(IndexRegEnc >> 3) & 1;
break;
}
case X86II::MRM0m: case X86II::MRM1m:
@@ -803,13 +822,12 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
}
case X86II::MRMSrcReg: {
// MRMSrcReg instructions forms:
- // dst(ModR/M), src1(VEX_4V), src2(ModR/M), src3(VEX_I8IMM)
+ // dst(ModR/M), src1(VEX_4V), src2(ModR/M), src3(Imm[7:4])
// dst(ModR/M), src1(ModR/M)
// dst(ModR/M), src1(ModR/M), imm8
//
// FMA4:
- // dst(ModR/M.reg), src1(VEX_4V), src2(ModR/M), src3(VEX_I8IMM)
- // dst(ModR/M.reg), src1(VEX_4V), src2(VEX_I8IMM), src3(ModR/M),
+ // dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
unsigned RegEnc = getX86RegEncoding(MI, CurOp++);
VEX_R = ~(RegEnc >> 3) & 1;
EVEX_R2 = ~(RegEnc >> 4) & 1;
@@ -823,14 +841,10 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
EVEX_V2 = ~(VRegEnc >> 4) & 1;
}
- if (HasMemOp4) // Skip second register source (encoded in I8IMM)
- CurOp++;
-
RegEnc = getX86RegEncoding(MI, CurOp++);
VEX_B = ~(RegEnc >> 3) & 1;
VEX_X = ~(RegEnc >> 4) & 1;
- if (HasVEX_4VOp3)
- VEX_4V = ~getX86RegEncoding(MI, CurOp++) & 0xf;
+
if (EVEX_b) {
if (HasEVEX_RC) {
unsigned RcOperand = NumOps-1;
@@ -841,6 +855,34 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
}
break;
}
+ case X86II::MRMSrcReg4VOp3: {
+ // Instruction format for 4VOp3:
+ // src1(ModR/M), src2(ModR/M), src3(VEX_4V)
+ unsigned RegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_R = ~(RegEnc >> 3) & 1;
+
+ RegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_B = ~(RegEnc >> 3) & 1;
+
+ VEX_4V = ~getX86RegEncoding(MI, CurOp++) & 0xf;
+ break;
+ }
+ case X86II::MRMSrcRegOp4: {
+ // dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
+ unsigned RegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_R = ~(RegEnc >> 3) & 1;
+
+ unsigned VRegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_4V = ~VRegEnc & 0xf;
+
+ // Skip second register source (encoded in Imm[7:4])
+ ++CurOp;
+
+ RegEnc = getX86RegEncoding(MI, CurOp++);
+ VEX_B = ~(RegEnc >> 3) & 1;
+ VEX_X = ~(RegEnc >> 4) & 1;
+ break;
+ }
case X86II::MRMDestReg: {
// MRMDestReg instructions forms:
// dst(ModR/M), src(ModR/M)
@@ -976,52 +1018,51 @@ uint8_t X86MCCodeEmitter::DetermineREXPrefix(const MCInst &MI, uint64_t TSFlags,
unsigned Reg = MO.getReg();
if (Reg == X86::AH || Reg == X86::BH || Reg == X86::CH || Reg == X86::DH)
UsesHighByteReg = true;
- if (!X86II::isX86_64NonExtLowByteReg(Reg)) continue;
- // FIXME: The caller of DetermineREXPrefix slaps this prefix onto anything
- // that returns non-zero.
- REX |= 0x40; // REX fixed encoding prefix
- break;
+ if (X86II::isX86_64NonExtLowByteReg(Reg))
+ // FIXME: The caller of DetermineREXPrefix slaps this prefix onto anything
+ // that returns non-zero.
+ REX |= 0x40; // REX fixed encoding prefix
}
switch (TSFlags & X86II::FormMask) {
case X86II::AddRegFrm:
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
break;
case X86II::MRMSrcReg:
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 2; // REX.R
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
+ REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
break;
case X86II::MRMSrcMem: {
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 2; // REX.R
- REX |= isX86_64ExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
- REX |= isX86_64ExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
+ REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
+ REX |= isREXExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
CurOp += X86::AddrNumOperands;
break;
}
case X86II::MRMDestReg:
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 0; // REX.B
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 2; // REX.R
+ REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
break;
case X86II::MRMDestMem:
- REX |= isX86_64ExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
- REX |= isX86_64ExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
+ REX |= isREXExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
CurOp += X86::AddrNumOperands;
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 2; // REX.R
+ REX |= isREXExtendedReg(MI, CurOp++) << 2; // REX.R
break;
case X86II::MRMXm:
case X86II::MRM0m: case X86II::MRM1m:
case X86II::MRM2m: case X86II::MRM3m:
case X86II::MRM4m: case X86II::MRM5m:
case X86II::MRM6m: case X86II::MRM7m:
- REX |= isX86_64ExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
- REX |= isX86_64ExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
+ REX |= isREXExtendedReg(MI, MemOperand+X86::AddrBaseReg) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, MemOperand+X86::AddrIndexReg) << 1; // REX.X
break;
case X86II::MRMXr:
case X86II::MRM0r: case X86II::MRM1r:
case X86II::MRM2r: case X86II::MRM3r:
case X86II::MRM4r: case X86II::MRM5r:
case X86II::MRM6r: case X86II::MRM7r:
- REX |= isX86_64ExtendedReg(MI, CurOp++) << 0; // REX.B
+ REX |= isREXExtendedReg(MI, CurOp++) << 0; // REX.B
break;
}
if (REX && UsesHighByteReg)
@@ -1133,10 +1174,7 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
// It uses the VEX.VVVV field?
bool HasVEX_4V = TSFlags & X86II::VEX_4V;
- bool HasVEX_4VOp3 = TSFlags & X86II::VEX_4VOp3;
- bool HasMemOp4 = TSFlags & X86II::MemOp4;
- bool HasVEX_I8IMM = TSFlags & X86II::VEX_I8IMM;
- assert((!HasMemOp4 || HasVEX_I8IMM) && "MemOp4 should imply VEX_I8IMM");
+ bool HasVEX_I8Reg = (TSFlags & X86II::ImmMask) == X86II::Imm8Reg;
// It uses the EVEX.aaa field?
bool HasEVEX_K = TSFlags & X86II::EVEX_K;
@@ -1312,21 +1350,42 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV)
++SrcRegNum;
- if (HasMemOp4) // Capture 2nd src (which is encoded in I8IMM)
- I8RegNum = getX86RegEncoding(MI, SrcRegNum++);
-
EmitRegModRMByte(MI.getOperand(SrcRegNum),
GetX86RegNum(MI.getOperand(CurOp)), CurByte, OS);
CurOp = SrcRegNum + 1;
- if (HasVEX_4VOp3)
- ++CurOp;
- if (!HasMemOp4 && HasVEX_I8IMM)
+ if (HasVEX_I8Reg)
I8RegNum = getX86RegEncoding(MI, CurOp++);
// do not count the rounding control operand
if (HasEVEX_RC)
--NumOps;
break;
}
+ case X86II::MRMSrcReg4VOp3: {
+ EmitByte(BaseOpcode, CurByte, OS);
+ unsigned SrcRegNum = CurOp + 1;
+
+ EmitRegModRMByte(MI.getOperand(SrcRegNum),
+ GetX86RegNum(MI.getOperand(CurOp)), CurByte, OS);
+ CurOp = SrcRegNum + 1;
+ ++CurOp; // Encoded in VEX.VVVV
+ break;
+ }
+ case X86II::MRMSrcRegOp4: {
+ EmitByte(BaseOpcode, CurByte, OS);
+ unsigned SrcRegNum = CurOp + 1;
+
+ // Skip 1st src (which is encoded in VEX_VVVV)
+ ++SrcRegNum;
+
+ // Capture 2nd src (which is encoded in Imm[7:4])
+ assert(HasVEX_I8Reg && "MRMSrcRegOp4 should imply VEX_I8Reg");
+ I8RegNum = getX86RegEncoding(MI, SrcRegNum++);
+
+ EmitRegModRMByte(MI.getOperand(SrcRegNum),
+ GetX86RegNum(MI.getOperand(CurOp)), CurByte, OS);
+ CurOp = SrcRegNum + 1;
+ break;
+ }
case X86II::MRMSrcMem: {
unsigned FirstMemOp = CurOp+1;
@@ -1336,20 +1395,42 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
if (HasVEX_4V)
++FirstMemOp; // Skip the register source (which is encoded in VEX_VVVV).
- if (HasMemOp4) // Capture second register source (encoded in I8IMM)
- I8RegNum = getX86RegEncoding(MI, FirstMemOp++);
-
EmitByte(BaseOpcode, CurByte, OS);
emitMemModRMByte(MI, FirstMemOp, GetX86RegNum(MI.getOperand(CurOp)),
TSFlags, Rex, CurByte, OS, Fixups, STI);
CurOp = FirstMemOp + X86::AddrNumOperands;
- if (HasVEX_4VOp3)
- ++CurOp;
- if (!HasMemOp4 && HasVEX_I8IMM)
+ if (HasVEX_I8Reg)
I8RegNum = getX86RegEncoding(MI, CurOp++);
break;
}
+ case X86II::MRMSrcMem4VOp3: {
+ unsigned FirstMemOp = CurOp+1;
+
+ EmitByte(BaseOpcode, CurByte, OS);
+
+ emitMemModRMByte(MI, FirstMemOp, GetX86RegNum(MI.getOperand(CurOp)),
+ TSFlags, Rex, CurByte, OS, Fixups, STI);
+ CurOp = FirstMemOp + X86::AddrNumOperands;
+ ++CurOp; // Encoded in VEX.VVVV.
+ break;
+ }
+ case X86II::MRMSrcMemOp4: {
+ unsigned FirstMemOp = CurOp+1;
+
+ ++FirstMemOp; // Skip the register source (which is encoded in VEX_VVVV).
+
+ // Capture second register source (encoded in Imm[7:4])
+ assert(HasVEX_I8Reg && "MRMSrcRegOp4 should imply VEX_I8Reg");
+ I8RegNum = getX86RegEncoding(MI, FirstMemOp++);
+
+ EmitByte(BaseOpcode, CurByte, OS);
+
+ emitMemModRMByte(MI, FirstMemOp, GetX86RegNum(MI.getOperand(CurOp)),
+ TSFlags, Rex, CurByte, OS, Fixups, STI);
+ CurOp = FirstMemOp + X86::AddrNumOperands;
+ break;
+ }
case X86II::MRMXr:
case X86II::MRM0r: case X86II::MRM1r:
@@ -1410,7 +1491,7 @@ encodeInstruction(const MCInst &MI, raw_ostream &OS,
break;
}
- if (HasVEX_I8IMM) {
+ if (HasVEX_I8Reg) {
// The last source register of a 4 operand instruction in AVX is encoded
// in bits[7:4] of a immediate byte.
assert(I8RegNum < 16 && "Register encoding out of range");
diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
index 311a8d6..22cb0fa 100644
--- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp
@@ -234,7 +234,7 @@ static MCInstrAnalysis *createX86MCInstrAnalysis(const MCInstrInfo *Info) {
// Force static initialization.
extern "C" void LLVMInitializeX86TargetMC() {
- for (Target *T : {&TheX86_32Target, &TheX86_64Target}) {
+ for (Target *T : {&getTheX86_32Target(), &getTheX86_64Target()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createX86MCAsmInfo);
@@ -268,9 +268,9 @@ extern "C" void LLVMInitializeX86TargetMC() {
}
// Register the asm backend.
- TargetRegistry::RegisterMCAsmBackend(TheX86_32Target,
+ TargetRegistry::RegisterMCAsmBackend(getTheX86_32Target(),
createX86_32AsmBackend);
- TargetRegistry::RegisterMCAsmBackend(TheX86_64Target,
+ TargetRegistry::RegisterMCAsmBackend(getTheX86_64Target(),
createX86_64AsmBackend);
}
diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
index ca4f0d3..f73e734 100644
--- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
+++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MCTargetDesc.h
@@ -27,13 +27,15 @@ class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
class MCRelocationInfo;
+class MCTargetOptions;
class Target;
class Triple;
class StringRef;
class raw_ostream;
class raw_pwrite_stream;
-extern Target TheX86_32Target, TheX86_64Target;
+Target &getTheX86_32Target();
+Target &getTheX86_64Target();
/// Flavour of dwarf regnumbers
///
@@ -69,9 +71,11 @@ MCCodeEmitter *createX86MCCodeEmitter(const MCInstrInfo &MCII,
MCContext &Ctx);
MCAsmBackend *createX86_32AsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
MCAsmBackend *createX86_64AsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const MCTargetOptions &Options);
/// Construct an X86 Windows COFF machine code streamer which will generate
/// PE/COFF format object files.
diff --git a/contrib/llvm/lib/Target/X86/TargetInfo/X86TargetInfo.cpp b/contrib/llvm/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
index fceb083..d2654fc 100644
--- a/contrib/llvm/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
+++ b/contrib/llvm/lib/Target/X86/TargetInfo/X86TargetInfo.cpp
@@ -11,12 +11,19 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheX86_32Target, llvm::TheX86_64Target;
+Target &llvm::getTheX86_32Target() {
+ static Target TheX86_32Target;
+ return TheX86_32Target;
+}
+Target &llvm::getTheX86_64Target() {
+ static Target TheX86_64Target;
+ return TheX86_64Target;
+}
extern "C" void LLVMInitializeX86TargetInfo() {
- RegisterTarget<Triple::x86, /*HasJIT=*/true>
- X(TheX86_32Target, "x86", "32-bit X86: Pentium-Pro and above");
+ RegisterTarget<Triple::x86, /*HasJIT=*/true> X(
+ getTheX86_32Target(), "x86", "32-bit X86: Pentium-Pro and above");
- RegisterTarget<Triple::x86_64, /*HasJIT=*/true>
- Y(TheX86_64Target, "x86-64", "64-bit X86: EM64T and AMD64");
+ RegisterTarget<Triple::x86_64, /*HasJIT=*/true> Y(
+ getTheX86_64Target(), "x86-64", "64-bit X86: EM64T and AMD64");
}
diff --git a/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.cpp b/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.cpp
index 18f7167..1be5aec 100644
--- a/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.cpp
+++ b/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.cpp
@@ -136,7 +136,7 @@ void DecodePSRLDQMask(MVT VT, unsigned Imm, SmallVectorImpl<int> &ShuffleMask) {
void DecodePALIGNRMask(MVT VT, unsigned Imm,
SmallVectorImpl<int> &ShuffleMask) {
unsigned NumElts = VT.getVectorNumElements();
- unsigned Offset = Imm * (VT.getVectorElementType().getSizeInBits() / 8);
+ unsigned Offset = Imm * (VT.getScalarSizeInBits() / 8);
unsigned NumLanes = VT.getSizeInBits() / 128;
unsigned NumLaneElts = NumElts / NumLanes;
@@ -151,6 +151,16 @@ void DecodePALIGNRMask(MVT VT, unsigned Imm,
}
}
+void DecodeVALIGNMask(MVT VT, unsigned Imm,
+ SmallVectorImpl<int> &ShuffleMask) {
+ int NumElts = VT.getVectorNumElements();
+ // Not all bits of the immediate are used so mask it.
+ assert(isPowerOf2_32(NumElts) && "NumElts should be power of 2");
+ Imm = Imm & (NumElts - 1);
+ for (int i = 0; i != NumElts; ++i)
+ ShuffleMask.push_back(i + Imm);
+}
+
/// DecodePSHUFMask - This decodes the shuffle masks for pshufw, pshufd, and vpermilp*.
/// VT indicates the type of the vector allowing it to handle different
/// datatypes and vector widths.
@@ -538,10 +548,11 @@ void DecodeVPERMIL2PMask(MVT VT, unsigned M2Z, ArrayRef<uint64_t> RawMask,
unsigned VecSize = VT.getSizeInBits();
unsigned EltSize = VT.getScalarSizeInBits();
unsigned NumLanes = VecSize / 128;
- unsigned NumEltsPerLane = VT.getVectorNumElements() / NumLanes;
- assert((VecSize == 128 || VecSize == 256) &&
- "Unexpected vector size");
+ unsigned NumElts = VT.getVectorNumElements();
+ unsigned NumEltsPerLane = NumElts / NumLanes;
+ assert((VecSize == 128 || VecSize == 256) && "Unexpected vector size");
assert((EltSize == 32 || EltSize == 64) && "Unexpected element size");
+ assert((NumElts == RawMask.size()) && "Unexpected mask size");
for (unsigned i = 0, e = RawMask.size(); i < e; ++i) {
// VPERMIL2 Operation.
@@ -562,14 +573,15 @@ void DecodeVPERMIL2PMask(MVT VT, unsigned M2Z, ArrayRef<uint64_t> RawMask,
continue;
}
- unsigned Index = i & ~(NumEltsPerLane - 1);
+ int Index = i & ~(NumEltsPerLane - 1);
if (EltSize == 64)
Index += (Selector >> 1) & 0x1;
else
Index += Selector & 0x3;
- unsigned SrcOffset = (Selector >> 2) & 1;
- ShuffleMask.push_back((int)(SrcOffset + Index));
+ int Src = (Selector >> 2) & 0x1;
+ Index += Src * NumElts;
+ ShuffleMask.push_back(Index);
}
}
diff --git a/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.h b/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.h
index dc21c19..17619d0 100644
--- a/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.h
+++ b/contrib/llvm/lib/Target/X86/Utils/X86ShuffleDecode.h
@@ -55,6 +55,8 @@ void DecodePSRLDQMask(MVT VT, unsigned Imm, SmallVectorImpl<int> &ShuffleMask);
void DecodePALIGNRMask(MVT VT, unsigned Imm, SmallVectorImpl<int> &ShuffleMask);
+void DecodeVALIGNMask(MVT VT, unsigned Imm, SmallVectorImpl<int> &ShuffleMask);
+
/// Decodes the shuffle masks for pshufd/pshufw/vpermilpd/vpermilps.
/// VT indicates the type of the vector allowing it to handle different
/// datatypes and vector widths.
diff --git a/contrib/llvm/lib/Target/X86/X86.h b/contrib/llvm/lib/Target/X86/X86.h
index 23d6c71..2cb80a4 100644
--- a/contrib/llvm/lib/Target/X86/X86.h
+++ b/contrib/llvm/lib/Target/X86/X86.h
@@ -87,6 +87,13 @@ FunctionPass *createX86ExpandPseudoPass();
FunctionPass *createX86FixupBWInsts();
void initializeFixupBWInstPassPass(PassRegistry &);
+
+/// This pass replaces EVEX ecnoded of AVX-512 instructiosn by VEX
+/// encoding when possible in order to reduce code size.
+FunctionPass *createX86EvexToVexInsts();
+
+void initializeEvexToVexInstPassPass(PassRegistry &);
+
} // End llvm namespace
#endif
diff --git a/contrib/llvm/lib/Target/X86/X86.td b/contrib/llvm/lib/Target/X86/X86.td
index 8267a84..83a23d4 100644
--- a/contrib/llvm/lib/Target/X86/X86.td
+++ b/contrib/llvm/lib/Target/X86/X86.td
@@ -99,6 +99,8 @@ def FeatureSlowBTMem : SubtargetFeature<"slow-bt-mem", "IsBTMemSlow", "true",
"Bit testing of memory is slow">;
def FeatureSlowSHLD : SubtargetFeature<"slow-shld", "IsSHLDSlow", "true",
"SHLD instruction is slow">;
+def FeatureSlowPMULLD : SubtargetFeature<"slow-pmulld", "IsPMULLDSlow", "true",
+ "PMULLD instruction is slow">;
// FIXME: This should not apply to CPUs that do not have SSE.
def FeatureSlowUAMem16 : SubtargetFeature<"slow-unaligned-mem-16",
"IsUAMem16Slow", "true",
@@ -141,8 +143,8 @@ def FeatureVLX : SubtargetFeature<"avx512vl", "HasVLX", "true",
"Enable AVX-512 Vector Length eXtensions",
[FeatureAVX512]>;
def FeatureVBMI : SubtargetFeature<"avx512vbmi", "HasVBMI", "true",
- "Enable AVX-512 Vector Bit Manipulation Instructions",
- [FeatureAVX512]>;
+ "Enable AVX-512 Vector Byte Manipulation Instructions",
+ [FeatureBWI]>;
def FeatureIFMA : SubtargetFeature<"avx512ifma", "HasIFMA", "true",
"Enable AVX-512 Integer Fused Multiple-Add",
[FeatureAVX512]>;
@@ -207,9 +209,9 @@ def FeatureLEAForSP : SubtargetFeature<"lea-sp", "UseLeaForSP", "true",
def FeatureSlowDivide32 : SubtargetFeature<"idivl-to-divb",
"HasSlowDivide32", "true",
"Use 8-bit divide for positive values less than 256">;
-def FeatureSlowDivide64 : SubtargetFeature<"idivq-to-divw",
+def FeatureSlowDivide64 : SubtargetFeature<"idivq-to-divl",
"HasSlowDivide64", "true",
- "Use 16-bit divide for positive values less than 65536">;
+ "Use 32-bit divide for positive values less than 2^32">;
def FeaturePadShortFunctions : SubtargetFeature<"pad-short-functions",
"PadShortFunctions", "true",
"Pad short functions">;
@@ -249,6 +251,25 @@ def FeatureSoftFloat
def FeatureFastPartialYMMWrite
: SubtargetFeature<"fast-partial-ymm-write", "HasFastPartialYMMWrite",
"true", "Partial writes to YMM registers are fast">;
+// FeatureFastScalarFSQRT should be enabled if scalar FSQRT has shorter latency
+// than the corresponding NR code. FeatureFastVectorFSQRT should be enabled if
+// vector FSQRT has higher throughput than the corresponding NR code.
+// The idea is that throughput bound code is likely to be vectorized, so for
+// vectorized code we should care about the throughput of SQRT operations.
+// But if the code is scalar that probably means that the code has some kind of
+// dependency and we should care more about reducing the latency.
+def FeatureFastScalarFSQRT
+ : SubtargetFeature<"fast-scalar-fsqrt", "HasFastScalarFSQRT",
+ "true", "Scalar SQRT is fast (disable Newton-Raphson)">;
+def FeatureFastVectorFSQRT
+ : SubtargetFeature<"fast-vector-fsqrt", "HasFastVectorFSQRT",
+ "true", "Vector SQRT is fast (disable Newton-Raphson)">;
+// If lzcnt has equivalent latency/throughput to most simple integer ops, it can
+// be used to replace test/set sequences.
+def FeatureFastLZCNT
+ : SubtargetFeature<
+ "fast-lzcnt", "HasFastLZCNT", "true",
+ "LZCNT instructions are as fast as most simple integer ops">;
//===----------------------------------------------------------------------===//
// X86 processors supported.
@@ -384,6 +405,7 @@ class SilvermontProc<string Name> : ProcessorModel<Name, SLMModel, [
FeatureSlowLEA,
FeatureSlowIncDec,
FeatureSlowBTMem,
+ FeatureSlowPMULLD,
FeatureLAHFSAHF
]>;
def : SilvermontProc<"silvermont">;
@@ -439,10 +461,12 @@ def SNBFeatures : ProcessorFeatures<[], [
FeatureCMPXCHG16B,
FeaturePOPCNT,
FeatureAES,
+ FeatureSlowDivide64,
FeaturePCLMUL,
FeatureXSAVE,
FeatureXSAVEOPT,
- FeatureLAHFSAHF
+ FeatureLAHFSAHF,
+ FeatureFastScalarFSQRT
]>;
class SandyBridgeProc<string Name> : ProcModel<Name, SandyBridgeModel,
@@ -500,7 +524,8 @@ def SKLFeatures : ProcessorFeatures<BDWFeatures.Value, [
FeatureXSAVEC,
FeatureXSAVES,
FeatureSGX,
- FeatureCLFLUSHOPT
+ FeatureCLFLUSHOPT,
+ FeatureFastVectorFSQRT
]>;
// FIXME: define SKL model
@@ -631,6 +656,7 @@ def : ProcessorModel<"btver2", BtVer2Model, [
FeatureF16C,
FeatureMOVBE,
FeatureLZCNT,
+ FeatureFastLZCNT,
FeaturePOPCNT,
FeatureXSAVE,
FeatureXSAVEOPT,
@@ -729,11 +755,48 @@ def : Proc<"bdver4", [
FeatureTBM,
FeatureFMA,
FeatureXSAVEOPT,
+ FeatureSlowSHLD,
FeatureFSGSBase,
FeatureLAHFSAHF,
FeatureMWAITX
]>;
+// TODO: The scheduler model falls to BTVER2 model.
+// The znver1 model has to be put in place.
+// Zen
+def: ProcessorModel<"znver1", BtVer2Model, [
+ FeatureADX,
+ FeatureAES,
+ FeatureAVX2,
+ FeatureBMI,
+ FeatureBMI2,
+ FeatureCLFLUSHOPT,
+ FeatureCMPXCHG16B,
+ FeatureF16C,
+ FeatureFMA,
+ FeatureFSGSBase,
+ FeatureFXSR,
+ FeatureFastLZCNT,
+ FeatureLAHFSAHF,
+ FeatureLZCNT,
+ FeatureMMX,
+ FeatureMOVBE,
+ FeatureMWAITX,
+ FeaturePCLMUL,
+ FeaturePOPCNT,
+ FeaturePRFCHW,
+ FeatureRDRAND,
+ FeatureRDSEED,
+ FeatureSHA,
+ FeatureSMAP,
+ FeatureSSE4A,
+ FeatureSlowSHLD,
+ FeatureX87,
+ FeatureXSAVE,
+ FeatureXSAVEC,
+ FeatureXSAVEOPT,
+ FeatureXSAVES]>;
+
def : Proc<"geode", [FeatureX87, FeatureSlowUAMem16, Feature3DNowA]>;
def : Proc<"winchip-c6", [FeatureX87, FeatureSlowUAMem16, FeatureMMX]>;
diff --git a/contrib/llvm/lib/Target/X86/X86AsmPrinter.cpp b/contrib/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 67e51f1..e1825ca 100644
--- a/contrib/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -57,10 +57,10 @@ bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
SetupMachineFunction(MF);
if (Subtarget->isTargetCOFF()) {
- bool Intrn = MF.getFunction()->hasInternalLinkage();
+ bool Local = MF.getFunction()->hasLocalLinkage();
OutStreamer->BeginCOFFSymbolDef(CurrentFnSym);
- OutStreamer->EmitCOFFSymbolStorageClass(Intrn ? COFF::IMAGE_SYM_CLASS_STATIC
- : COFF::IMAGE_SYM_CLASS_EXTERNAL);
+ OutStreamer->EmitCOFFSymbolStorageClass(
+ Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL);
OutStreamer->EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
<< COFF::SCT_COMPLEX_TYPE_SHIFT);
OutStreamer->EndCOFFSymbolDef();
@@ -70,7 +70,7 @@ bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
EmitFunctionBody();
// Emit the XRay table for this function.
- EmitXRayTable();
+ emitXRayTable();
// We didn't modify anything.
return false;
@@ -627,11 +627,11 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) {
raw_string_ostream FlagsOS(Flags);
for (const auto &Function : M)
- TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Function, *Mang);
+ TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Function);
for (const auto &Global : M.globals())
- TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Global, *Mang);
+ TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Global);
for (const auto &Alias : M.aliases())
- TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Alias, *Mang);
+ TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Alias);
FlagsOS.flush();
@@ -656,6 +656,6 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) {
// Force static initialization.
extern "C" void LLVMInitializeX86AsmPrinter() {
- RegisterAsmPrinter<X86AsmPrinter> X(TheX86_32Target);
- RegisterAsmPrinter<X86AsmPrinter> Y(TheX86_64Target);
+ RegisterAsmPrinter<X86AsmPrinter> X(getTheX86_32Target());
+ RegisterAsmPrinter<X86AsmPrinter> Y(getTheX86_64Target());
}
diff --git a/contrib/llvm/lib/Target/X86/X86AsmPrinter.h b/contrib/llvm/lib/Target/X86/X86AsmPrinter.h
index dcb7b5a..6798253 100644
--- a/contrib/llvm/lib/Target/X86/X86AsmPrinter.h
+++ b/contrib/llvm/lib/Target/X86/X86AsmPrinter.h
@@ -71,27 +71,6 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
StackMapShadowTracker SMShadowTracker;
- // This describes the kind of sled we're storing in the XRay table.
- enum class SledKind : uint8_t {
- FUNCTION_ENTER = 0,
- FUNCTION_EXIT = 1,
- TAIL_CALL = 2,
- };
-
- // The table will contain these structs that point to the sled, the function
- // containing the sled, and what kind of sled (and whether they should always
- // be instrumented).
- struct XRayFunctionEntry {
- const MCSymbol *Sled;
- const MCSymbol *Function;
- SledKind Kind;
- bool AlwaysInstrument;
- const class Function *Fn;
- };
-
- // All the sleds to be emitted.
- std::vector<XRayFunctionEntry> Sleds;
-
// All instructions emitted by the X86AsmPrinter should use this helper
// method.
//
@@ -117,15 +96,13 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
// function.
void EmitXRayTable();
- // Helper function to record a given XRay sled.
- void recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind);
public:
explicit X86AsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)), SM(*this), FM(*this) {}
- const char *getPassName() const override {
- return "X86 Assembly / Object Emitter";
+ StringRef getPassName() const override {
+ return "X86 Assembly Printer";
}
const X86Subtarget &getSubtarget() const { return *Subtarget; }
diff --git a/contrib/llvm/lib/Target/X86/X86CallFrameOptimization.cpp b/contrib/llvm/lib/Target/X86/X86CallFrameOptimization.cpp
index 8f6fc40..844c66d 100644
--- a/contrib/llvm/lib/Target/X86/X86CallFrameOptimization.cpp
+++ b/contrib/llvm/lib/Target/X86/X86CallFrameOptimization.cpp
@@ -100,7 +100,7 @@ private:
const X86RegisterInfo &RegInfo,
DenseSet<unsigned int> &UsedRegs);
- const char *getPassName() const override { return "X86 Optimize Call Frame"; }
+ StringRef getPassName() const override { return "X86 Optimize Call Frame"; }
const TargetInstrInfo *TII;
const X86FrameLowering *TFL;
@@ -134,7 +134,7 @@ bool X86CallFrameOptimization::isLegal(MachineFunction &MF) {
// in the compact unwind encoding that Darwin uses. So, bail if there
// is a danger of that being generated.
if (STI->isTargetDarwin() &&
- (!MF.getMMI().getLandingPads().empty() ||
+ (!MF.getLandingPads().empty() ||
(MF.getFunction()->needsUnwindTableEntry() && !TFL->hasFP(MF))))
return false;
@@ -180,7 +180,7 @@ bool X86CallFrameOptimization::isProfitable(MachineFunction &MF,
// This transformation is always a win when we do not expect to have
// a reserved call frame. Under other circumstances, it may be either
// a win or a loss, and requires a heuristic.
- bool CannotReserveFrame = MF.getFrameInfo()->hasVarSizedObjects();
+ bool CannotReserveFrame = MF.getFrameInfo().hasVarSizedObjects();
if (CannotReserveFrame)
return true;
@@ -230,7 +230,7 @@ bool X86CallFrameOptimization::runOnMachineFunction(MachineFunction &MF) {
assert(isPowerOf2_32(SlotSize) && "Expect power of 2 stack slot size");
Log2SlotSize = Log2_32(SlotSize);
- if (!isLegal(MF))
+ if (skipFunction(*MF.getFunction()) || !isLegal(MF))
return false;
unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
@@ -345,10 +345,10 @@ void X86CallFrameOptimization::collectCallInfo(MachineFunction &MF,
return;
}
- // For globals in PIC mode, we can have some LEAs here.
- // Ignore them, they don't bother us.
+ // Skip over DEBUG_VALUE.
+ // For globals in PIC mode, we can have some LEAs here. Skip them as well.
// TODO: Extend this to something that covers more cases.
- while (I->getOpcode() == X86::LEA32r)
+ while (I->getOpcode() == X86::LEA32r || I->isDebugValue())
++I;
unsigned StackPtr = RegInfo.getStackRegister();
diff --git a/contrib/llvm/lib/Target/X86/X86CallLowering.cpp b/contrib/llvm/lib/Target/X86/X86CallLowering.cpp
new file mode 100644
index 0000000..5ae4962
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86CallLowering.cpp
@@ -0,0 +1,46 @@
+//===-- llvm/lib/Target/X86/X86CallLowering.cpp - Call lowering -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the lowering of LLVM calls to machine code calls for
+/// GlobalISel.
+///
+//===----------------------------------------------------------------------===//
+
+#include "X86CallLowering.h"
+#include "X86ISelLowering.h"
+#include "X86InstrInfo.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+
+using namespace llvm;
+
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+#error "This shouldn't be built without GISel"
+#endif
+
+X86CallLowering::X86CallLowering(const X86TargetLowering &TLI)
+ : CallLowering(&TLI) {}
+
+bool X86CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
+ const Value *Val, unsigned VReg) const {
+ // TODO: handle functions returning non-void values.
+ if (Val)
+ return false;
+
+ MIRBuilder.buildInstr(X86::RET).addImm(0);
+
+ return true;
+}
+
+bool X86CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
+ const Function &F,
+ ArrayRef<unsigned> VRegs) const {
+ // TODO: handle functions with one or more arguments.
+ return F.arg_empty();
+}
diff --git a/contrib/llvm/lib/Target/X86/X86CallLowering.h b/contrib/llvm/lib/Target/X86/X86CallLowering.h
new file mode 100644
index 0000000..f2672f0
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86CallLowering.h
@@ -0,0 +1,39 @@
+//===-- llvm/lib/Target/X86/X86CallLowering.h - Call lowering -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file describes how to lower LLVM calls to machine code calls.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_X86_X86CALLLOWERING
+#define LLVM_LIB_TARGET_X86_X86CALLLOWERING
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+
+namespace llvm {
+
+class Function;
+class MachineIRBuilder;
+class X86TargetLowering;
+class Value;
+
+class X86CallLowering : public CallLowering {
+public:
+ X86CallLowering(const X86TargetLowering &TLI);
+
+ bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val,
+ unsigned VReg) const override;
+
+ bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
+ ArrayRef<unsigned> VRegs) const override;
+};
+} // End of namespace llvm;
+#endif
diff --git a/contrib/llvm/lib/Target/X86/X86CallingConv.cpp b/contrib/llvm/lib/Target/X86/X86CallingConv.cpp
new file mode 100644
index 0000000..c96e76b
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86CallingConv.cpp
@@ -0,0 +1,208 @@
+//=== X86CallingConv.cpp - X86 Custom Calling Convention Impl -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of custom routines for the X86
+// Calling Convention that aren't done by tablegen.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/X86MCTargetDesc.h"
+#include "X86Subtarget.h"
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/IR/CallingConv.h"
+
+namespace llvm {
+
+bool CC_X86_32_RegCall_Assign2Regs(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+ // List of GPR registers that are available to store values in regcall
+ // calling convention.
+ static const MCPhysReg RegList[] = {X86::EAX, X86::ECX, X86::EDX, X86::EDI,
+ X86::ESI};
+
+ // The vector will save all the available registers for allocation.
+ SmallVector<unsigned, 5> AvailableRegs;
+
+ // searching for the available registers.
+ for (auto Reg : RegList) {
+ if (!State.isAllocated(Reg))
+ AvailableRegs.push_back(Reg);
+ }
+
+ const size_t RequiredGprsUponSplit = 2;
+ if (AvailableRegs.size() < RequiredGprsUponSplit)
+ return false; // Not enough free registers - continue the search.
+
+ // Allocating the available registers.
+ for (unsigned I = 0; I < RequiredGprsUponSplit; I++) {
+
+ // Marking the register as located.
+ unsigned Reg = State.AllocateReg(AvailableRegs[I]);
+
+ // Since we previously made sure that 2 registers are available
+ // we expect that a real register number will be returned.
+ assert(Reg && "Expecting a register will be available");
+
+ // Assign the value to the allocated register
+ State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ }
+
+ // Successful in allocating regsiters - stop scanning next rules.
+ return true;
+}
+
+static ArrayRef<MCPhysReg> CC_X86_VectorCallGetSSEs(const MVT &ValVT) {
+ if (ValVT.is512BitVector()) {
+ static const MCPhysReg RegListZMM[] = {X86::ZMM0, X86::ZMM1, X86::ZMM2,
+ X86::ZMM3, X86::ZMM4, X86::ZMM5};
+ return makeArrayRef(std::begin(RegListZMM), std::end(RegListZMM));
+ }
+
+ if (ValVT.is256BitVector()) {
+ static const MCPhysReg RegListYMM[] = {X86::YMM0, X86::YMM1, X86::YMM2,
+ X86::YMM3, X86::YMM4, X86::YMM5};
+ return makeArrayRef(std::begin(RegListYMM), std::end(RegListYMM));
+ }
+
+ static const MCPhysReg RegListXMM[] = {X86::XMM0, X86::XMM1, X86::XMM2,
+ X86::XMM3, X86::XMM4, X86::XMM5};
+ return makeArrayRef(std::begin(RegListXMM), std::end(RegListXMM));
+}
+
+static ArrayRef<MCPhysReg> CC_X86_64_VectorCallGetGPRs() {
+ static const MCPhysReg RegListGPR[] = {X86::RCX, X86::RDX, X86::R8, X86::R9};
+ return makeArrayRef(std::begin(RegListGPR), std::end(RegListGPR));
+}
+
+static bool CC_X86_VectorCallAssignRegister(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags,
+ CCState &State) {
+
+ ArrayRef<MCPhysReg> RegList = CC_X86_VectorCallGetSSEs(ValVT);
+ bool Is64bit = static_cast<const X86Subtarget &>(
+ State.getMachineFunction().getSubtarget())
+ .is64Bit();
+
+ for (auto Reg : RegList) {
+ // If the register is not marked as allocated - assign to it.
+ if (!State.isAllocated(Reg)) {
+ unsigned AssigedReg = State.AllocateReg(Reg);
+ assert(AssigedReg == Reg && "Expecting a valid register allocation");
+ State.addLoc(
+ CCValAssign::getReg(ValNo, ValVT, AssigedReg, LocVT, LocInfo));
+ return true;
+ }
+ // If the register is marked as shadow allocated - assign to it.
+ if (Is64bit && State.IsShadowAllocatedReg(Reg)) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return true;
+ }
+ }
+
+ llvm_unreachable("Clang should ensure that hva marked vectors will have "
+ "an available register.");
+ return false;
+}
+
+bool CC_X86_64_VectorCall(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+ // On the second pass, go through the HVAs only.
+ if (ArgFlags.isSecArgPass()) {
+ if (ArgFlags.isHva())
+ return CC_X86_VectorCallAssignRegister(ValNo, ValVT, LocVT, LocInfo,
+ ArgFlags, State);
+ return true;
+ }
+
+ // Process only vector types as defined by vectorcall spec:
+ // "A vector type is either a floating-point type, for example,
+ // a float or double, or an SIMD vector type, for example, __m128 or __m256".
+ if (!(ValVT.isFloatingPoint() ||
+ (ValVT.isVector() && ValVT.getSizeInBits() >= 128))) {
+ // If R9 was already assigned it means that we are after the fourth element
+ // and because this is not an HVA / Vector type, we need to allocate
+ // shadow XMM register.
+ if (State.isAllocated(X86::R9)) {
+ // Assign shadow XMM register.
+ (void)State.AllocateReg(CC_X86_VectorCallGetSSEs(ValVT));
+ }
+
+ return false;
+ }
+
+ if (!ArgFlags.isHva() || ArgFlags.isHvaStart()) {
+ // Assign shadow GPR register.
+ (void)State.AllocateReg(CC_X86_64_VectorCallGetGPRs());
+
+ // Assign XMM register - (shadow for HVA and non-shadow for non HVA).
+ if (unsigned Reg = State.AllocateReg(CC_X86_VectorCallGetSSEs(ValVT))) {
+ // In Vectorcall Calling convention, additional shadow stack can be
+ // created on top of the basic 32 bytes of win64.
+ // It can happen if the fifth or sixth argument is vector type or HVA.
+ // At that case for each argument a shadow stack of 8 bytes is allocated.
+ if (Reg == X86::XMM4 || Reg == X86::XMM5)
+ State.AllocateStack(8, 8);
+
+ if (!ArgFlags.isHva()) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return true; // Allocated a register - Stop the search.
+ }
+ }
+ }
+
+ // If this is an HVA - Stop the search,
+ // otherwise continue the search.
+ return ArgFlags.isHva();
+}
+
+bool CC_X86_32_VectorCall(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+ // On the second pass, go through the HVAs only.
+ if (ArgFlags.isSecArgPass()) {
+ if (ArgFlags.isHva())
+ return CC_X86_VectorCallAssignRegister(ValNo, ValVT, LocVT, LocInfo,
+ ArgFlags, State);
+ return true;
+ }
+
+ // Process only vector types as defined by vectorcall spec:
+ // "A vector type is either a floating point type, for example,
+ // a float or double, or an SIMD vector type, for example, __m128 or __m256".
+ if (!(ValVT.isFloatingPoint() ||
+ (ValVT.isVector() && ValVT.getSizeInBits() >= 128))) {
+ return false;
+ }
+
+ if (ArgFlags.isHva())
+ return true; // If this is an HVA - Stop the search.
+
+ // Assign XMM register.
+ if (unsigned Reg = State.AllocateReg(CC_X86_VectorCallGetSSEs(ValVT))) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return true;
+ }
+
+ // In case we did not find an available XMM register for a vector -
+ // pass it indirectly.
+ // It is similar to CCPassIndirect, with the addition of inreg.
+ if (!ValVT.isFloatingPoint()) {
+ LocVT = MVT::i32;
+ LocInfo = CCValAssign::Indirect;
+ ArgFlags.setInReg();
+ }
+
+ return false; // No register was assigned - Continue the search.
+}
+
+} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/X86/X86CallingConv.h b/contrib/llvm/lib/Target/X86/X86CallingConv.h
index a08160f..c49a683 100644
--- a/contrib/llvm/lib/Target/X86/X86CallingConv.h
+++ b/contrib/llvm/lib/Target/X86/X86CallingConv.h
@@ -21,18 +21,32 @@
namespace llvm {
-inline bool CC_X86_32_VectorCallIndirect(unsigned &ValNo, MVT &ValVT,
- MVT &LocVT,
- CCValAssign::LocInfo &LocInfo,
- ISD::ArgFlagsTy &ArgFlags,
- CCState &State) {
- // Similar to CCPassIndirect, with the addition of inreg.
- LocVT = MVT::i32;
- LocInfo = CCValAssign::Indirect;
- ArgFlags.setInReg();
- return false; // Continue the search, but now for i32.
-}
-
+/// When regcall calling convention compiled to 32 bit arch, special treatment
+/// is required for 64 bit masks.
+/// The value should be assigned to two GPRs.
+/// \return true if registers were allocated and false otherwise.
+bool CC_X86_32_RegCall_Assign2Regs(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State);
+
+/// Vectorcall calling convention has special handling for vector types or
+/// HVA for 64 bit arch.
+/// For HVAs shadow registers might be allocated on the first pass
+/// and actual XMM registers are allocated on the second pass.
+/// For vector types, actual XMM registers are allocated on the first pass.
+/// \return true if registers were allocated and false otherwise.
+bool CC_X86_64_VectorCall(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State);
+
+/// Vectorcall calling convention has special handling for vector types or
+/// HVA for 32 bit arch.
+/// For HVAs actual XMM registers are allocated on the second pass.
+/// For vector types, actual XMM registers are allocated on the first pass.
+/// \return true if registers were allocated and false otherwise.
+bool CC_X86_32_VectorCall(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+ CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State);
inline bool CC_X86_AnyReg_Error(unsigned &, MVT &, MVT &,
CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
diff --git a/contrib/llvm/lib/Target/X86/X86CallingConv.td b/contrib/llvm/lib/Target/X86/X86CallingConv.td
index 4cb62b5..cf7bc98 100644
--- a/contrib/llvm/lib/Target/X86/X86CallingConv.td
+++ b/contrib/llvm/lib/Target/X86/X86CallingConv.td
@@ -18,6 +18,179 @@ class CCIfSubtarget<string F, CCAction A>
"(State.getMachineFunction().getSubtarget()).", F),
A>;
+// Register classes for RegCall
+class RC_X86_RegCall {
+ list<Register> GPR_8 = [];
+ list<Register> GPR_16 = [];
+ list<Register> GPR_32 = [];
+ list<Register> GPR_64 = [];
+ list<Register> FP_CALL = [FP0];
+ list<Register> FP_RET = [FP0, FP1];
+ list<Register> XMM = [];
+ list<Register> YMM = [];
+ list<Register> ZMM = [];
+}
+
+// RegCall register classes for 32 bits
+def RC_X86_32_RegCall : RC_X86_RegCall {
+ let GPR_8 = [AL, CL, DL, DIL, SIL];
+ let GPR_16 = [AX, CX, DX, DI, SI];
+ let GPR_32 = [EAX, ECX, EDX, EDI, ESI];
+ let GPR_64 = [RAX]; ///< Not actually used, but AssignToReg can't handle []
+ ///< \todo Fix AssignToReg to enable empty lists
+ let XMM = [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7];
+ let YMM = [YMM0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7];
+ let ZMM = [ZMM0, ZMM1, ZMM2, ZMM3, ZMM4, ZMM5, ZMM6, ZMM7];
+}
+
+class RC_X86_64_RegCall : RC_X86_RegCall {
+ let XMM = [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
+ XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15];
+ let YMM = [YMM0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7,
+ YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15];
+ let ZMM = [ZMM0, ZMM1, ZMM2, ZMM3, ZMM4, ZMM5, ZMM6, ZMM7,
+ ZMM8, ZMM9, ZMM10, ZMM11, ZMM12, ZMM13, ZMM14, ZMM15];
+}
+
+def RC_X86_64_RegCall_Win : RC_X86_64_RegCall {
+ let GPR_8 = [AL, CL, DL, DIL, SIL, R8B, R9B, R10B, R11B, R12B, R14B, R15B];
+ let GPR_16 = [AX, CX, DX, DI, SI, R8W, R9W, R10W, R11W, R12W, R14W, R15W];
+ let GPR_32 = [EAX, ECX, EDX, EDI, ESI, R8D, R9D, R10D, R11D, R12D, R14D, R15D];
+ let GPR_64 = [RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11, R12, R14, R15];
+}
+
+def RC_X86_64_RegCall_SysV : RC_X86_64_RegCall {
+ let GPR_8 = [AL, CL, DL, DIL, SIL, R8B, R9B, R12B, R13B, R14B, R15B];
+ let GPR_16 = [AX, CX, DX, DI, SI, R8W, R9W, R12W, R13W, R14W, R15W];
+ let GPR_32 = [EAX, ECX, EDX, EDI, ESI, R8D, R9D, R12D, R13D, R14D, R15D];
+ let GPR_64 = [RAX, RCX, RDX, RDI, RSI, R8, R9, R12, R13, R14, R15];
+}
+
+// X86-64 Intel regcall calling convention.
+multiclass X86_RegCall_base<RC_X86_RegCall RC> {
+def CC_#NAME : CallingConv<[
+ // Handles byval parameters.
+ CCIfSubtarget<"is64Bit()", CCIfByVal<CCPassByVal<8, 8>>>,
+ CCIfByVal<CCPassByVal<4, 4>>,
+
+ // Promote i1/i8/i16 arguments to i32.
+ CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+
+ // Promote v8i1/v16i1/v32i1 arguments to i32.
+ CCIfType<[v8i1, v16i1, v32i1], CCPromoteToType<i32>>,
+
+ // bool, char, int, enum, long, pointer --> GPR
+ CCIfType<[i32], CCAssignToReg<RC.GPR_32>>,
+
+ // long long, __int64 --> GPR
+ CCIfType<[i64], CCAssignToReg<RC.GPR_64>>,
+
+ // __mmask64 (v64i1) --> GPR64 (for x64) or 2 x GPR32 (for IA32)
+ CCIfType<[v64i1], CCPromoteToType<i64>>,
+ CCIfSubtarget<"is64Bit()", CCIfType<[i64],
+ CCAssignToReg<RC.GPR_64>>>,
+ CCIfSubtarget<"is32Bit()", CCIfType<[i64],
+ CCCustom<"CC_X86_32_RegCall_Assign2Regs">>>,
+
+ // float, double, float128 --> XMM
+ // In the case of SSE disabled --> save to stack
+ CCIfType<[f32, f64, f128],
+ CCIfSubtarget<"hasSSE1()", CCAssignToReg<RC.XMM>>>,
+
+ // long double --> FP
+ CCIfType<[f80], CCAssignToReg<RC.FP_CALL>>,
+
+ // __m128, __m128i, __m128d --> XMM
+ // In the case of SSE disabled --> save to stack
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+ CCIfSubtarget<"hasSSE1()", CCAssignToReg<RC.XMM>>>,
+
+ // __m256, __m256i, __m256d --> YMM
+ // In the case of SSE disabled --> save to stack
+ CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],
+ CCIfSubtarget<"hasAVX()", CCAssignToReg<RC.YMM>>>,
+
+ // __m512, __m512i, __m512d --> ZMM
+ // In the case of SSE disabled --> save to stack
+ CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],
+ CCIfSubtarget<"hasAVX512()",CCAssignToReg<RC.ZMM>>>,
+
+ // If no register was found -> assign to stack
+
+ // In 64 bit, assign 64/32 bit values to 8 byte stack
+ CCIfSubtarget<"is64Bit()", CCIfType<[i32, i64, f32, f64],
+ CCAssignToStack<8, 8>>>,
+
+ // In 32 bit, assign 64/32 bit values to 8/4 byte stack
+ CCIfType<[i32, f32], CCAssignToStack<4, 4>>,
+ CCIfType<[i64, f64], CCAssignToStack<8, 4>>,
+
+ // MMX type gets 8 byte slot in stack , while alignment depends on target
+ CCIfSubtarget<"is64Bit()", CCIfType<[x86mmx], CCAssignToStack<8, 8>>>,
+ CCIfType<[x86mmx], CCAssignToStack<8, 4>>,
+
+ // float 128 get stack slots whose size and alignment depends
+ // on the subtarget.
+ CCIfType<[f80, f128], CCAssignToStack<0, 0>>,
+
+ // Vectors get 16-byte stack slots that are 16-byte aligned.
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+ CCAssignToStack<16, 16>>,
+
+ // 256-bit vectors get 32-byte stack slots that are 32-byte aligned.
+ CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],
+ CCAssignToStack<32, 32>>,
+
+ // 512-bit vectors get 64-byte stack slots that are 64-byte aligned.
+ CCIfType<[v16i32, v8i64, v16f32, v8f64], CCAssignToStack<64, 64>>
+]>;
+
+def RetCC_#NAME : CallingConv<[
+ // Promote i1, v8i1 arguments to i8.
+ CCIfType<[i1, v8i1], CCPromoteToType<i8>>,
+
+ // Promote v16i1 arguments to i16.
+ CCIfType<[v16i1], CCPromoteToType<i16>>,
+
+ // Promote v32i1 arguments to i32.
+ CCIfType<[v32i1], CCPromoteToType<i32>>,
+
+ // bool, char, int, enum, long, pointer --> GPR
+ CCIfType<[i8], CCAssignToReg<RC.GPR_8>>,
+ CCIfType<[i16], CCAssignToReg<RC.GPR_16>>,
+ CCIfType<[i32], CCAssignToReg<RC.GPR_32>>,
+
+ // long long, __int64 --> GPR
+ CCIfType<[i64], CCAssignToReg<RC.GPR_64>>,
+
+ // __mmask64 (v64i1) --> GPR64 (for x64) or 2 x GPR32 (for IA32)
+ CCIfType<[v64i1], CCPromoteToType<i64>>,
+ CCIfSubtarget<"is64Bit()", CCIfType<[i64],
+ CCAssignToReg<RC.GPR_64>>>,
+ CCIfSubtarget<"is32Bit()", CCIfType<[i64],
+ CCCustom<"CC_X86_32_RegCall_Assign2Regs">>>,
+
+ // long double --> FP
+ CCIfType<[f80], CCAssignToReg<RC.FP_RET>>,
+
+ // float, double, float128 --> XMM
+ CCIfType<[f32, f64, f128],
+ CCIfSubtarget<"hasSSE1()", CCAssignToReg<RC.XMM>>>,
+
+ // __m128, __m128i, __m128d --> XMM
+ CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+ CCIfSubtarget<"hasSSE1()", CCAssignToReg<RC.XMM>>>,
+
+ // __m256, __m256i, __m256d --> YMM
+ CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],
+ CCIfSubtarget<"hasAVX()", CCAssignToReg<RC.YMM>>>,
+
+ // __m512, __m512i, __m512d --> ZMM
+ CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],
+ CCIfSubtarget<"hasAVX512()", CCAssignToReg<RC.ZMM>>>
+]>;
+}
+
//===----------------------------------------------------------------------===//
// Return Value Calling Conventions
//===----------------------------------------------------------------------===//
@@ -135,20 +308,12 @@ def RetCC_X86_32_HiPE : CallingConv<[
CCIfType<[i32], CCAssignToReg<[ESI, EBP, EAX, EDX]>>
]>;
-// X86-32 HiPE return-value convention.
+// X86-32 Vectorcall return-value convention.
def RetCC_X86_32_VectorCall : CallingConv<[
- // Vector types are returned in XMM0,XMM1,XMMM2 and XMM3.
- CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
+ // Floating Point types are returned in XMM0,XMM1,XMMM2 and XMM3.
+ CCIfType<[f32, f64, f128],
CCAssignToReg<[XMM0,XMM1,XMM2,XMM3]>>,
- // 256-bit FP vectors
- CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],
- CCAssignToReg<[YMM0,YMM1,YMM2,YMM3]>>,
-
- // 512-bit FP vectors
- CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],
- CCAssignToReg<[ZMM0,ZMM1,ZMM2,ZMM3]>>,
-
// Return integers in the standard way.
CCDelegateTo<RetCC_X86Common>
]>;
@@ -177,6 +342,16 @@ def RetCC_X86_Win64_C : CallingConv<[
CCDelegateTo<RetCC_X86_64_C>
]>;
+// X86-64 vectorcall return-value convention.
+def RetCC_X86_64_Vectorcall : CallingConv<[
+ // Vectorcall calling convention always returns FP values in XMMs.
+ CCIfType<[f32, f64, f128],
+ CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>,
+
+ // Otherwise, everything is the same as Windows X86-64 C CC.
+ CCDelegateTo<RetCC_X86_Win64_C>
+]>;
+
// X86-64 HiPE return-value convention.
def RetCC_X86_64_HiPE : CallingConv<[
// Promote all types to i64
@@ -196,6 +371,9 @@ def RetCC_X86_64_WebKit_JS : CallingConv<[
]>;
def RetCC_X86_64_Swift : CallingConv<[
+
+ CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R12]>>>,
+
// For integers, ECX, R8D can be used as extra return registers.
CCIfType<[i1], CCPromoteToType<i8>>,
CCIfType<[i8] , CCAssignToReg<[AL, DL, CL, R8B]>>,
@@ -234,6 +412,14 @@ def RetCC_X86_64_HHVM: CallingConv<[
RAX, R10, R11, R13, R14, R15]>>
]>;
+
+defm X86_32_RegCall :
+ X86_RegCall_base<RC_X86_32_RegCall>;
+defm X86_Win64_RegCall :
+ X86_RegCall_base<RC_X86_64_RegCall_Win>;
+defm X86_SysV64_RegCall :
+ X86_RegCall_base<RC_X86_64_RegCall_SysV>;
+
// This is the root return-value convention for the X86-32 backend.
def RetCC_X86_32 : CallingConv<[
// If FastCC, use RetCC_X86_32_Fast.
@@ -241,6 +427,7 @@ def RetCC_X86_32 : CallingConv<[
// If HiPE, use RetCC_X86_32_HiPE.
CCIfCC<"CallingConv::HiPE", CCDelegateTo<RetCC_X86_32_HiPE>>,
CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<RetCC_X86_32_VectorCall>>,
+ CCIfCC<"CallingConv::X86_RegCall", CCDelegateTo<RetCC_X86_32_RegCall>>,
// Otherwise, use RetCC_X86_32_C.
CCDelegateTo<RetCC_X86_32_C>
@@ -262,9 +449,17 @@ def RetCC_X86_64 : CallingConv<[
CCIfCC<"CallingConv::X86_64_Win64", CCDelegateTo<RetCC_X86_Win64_C>>,
CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo<RetCC_X86_64_C>>,
+ // Handle Vectorcall CC
+ CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<RetCC_X86_64_Vectorcall>>,
+
// Handle HHVM calls.
CCIfCC<"CallingConv::HHVM", CCDelegateTo<RetCC_X86_64_HHVM>>,
+ CCIfCC<"CallingConv::X86_RegCall",
+ CCIfSubtarget<"isTargetWin64()",
+ CCDelegateTo<RetCC_X86_Win64_RegCall>>>,
+ CCIfCC<"CallingConv::X86_RegCall", CCDelegateTo<RetCC_X86_SysV64_RegCall>>,
+
// Mingw64 and native Win64 use Win64 CC
CCIfSubtarget<"isTargetWin64()", CCDelegateTo<RetCC_X86_Win64_C>>,
@@ -436,18 +631,7 @@ def CC_X86_Win64_C : CallingConv<[
]>;
def CC_X86_Win64_VectorCall : CallingConv<[
- // The first 6 floating point and vector types of 128 bits or less use
- // XMM0-XMM5.
- CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
- CCAssignToReg<[XMM0, XMM1, XMM2, XMM3, XMM4, XMM5]>>,
-
- // 256-bit vectors use YMM registers.
- CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],
- CCAssignToReg<[YMM0, YMM1, YMM2, YMM3, YMM4, YMM5]>>,
-
- // 512-bit vectors use ZMM registers.
- CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],
- CCAssignToReg<[ZMM0, ZMM1, ZMM2, ZMM3, ZMM4, ZMM5]>>,
+ CCCustom<"CC_X86_64_VectorCall">,
// Delegate to fastcall to handle integer types.
CCDelegateTo<CC_X86_Win64_C>
@@ -657,25 +841,9 @@ def CC_X86_32_FastCall : CallingConv<[
CCDelegateTo<CC_X86_32_Common>
]>;
-def CC_X86_32_VectorCall : CallingConv<[
- // The first 6 floating point and vector types of 128 bits or less use
- // XMM0-XMM5.
- CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
- CCAssignToReg<[XMM0, XMM1, XMM2, XMM3, XMM4, XMM5]>>,
-
- // 256-bit vectors use YMM registers.
- CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64],
- CCAssignToReg<[YMM0, YMM1, YMM2, YMM3, YMM4, YMM5]>>,
-
- // 512-bit vectors use ZMM registers.
- CCIfType<[v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],
- CCAssignToReg<[ZMM0, ZMM1, ZMM2, ZMM3, ZMM4, ZMM5]>>,
-
- // Otherwise, pass it indirectly.
- CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64,
- v32i8, v16i16, v8i32, v4i64, v8f32, v4f64,
- v64i8, v32i16, v16i32, v8i64, v16f32, v8f64],
- CCCustom<"CC_X86_32_VectorCallIndirect">>,
+def CC_X86_Win32_VectorCall : CallingConv<[
+ // Pass floating point in XMMs
+ CCCustom<"CC_X86_32_VectorCall">,
// Delegate to fastcall to handle integer types.
CCDelegateTo<CC_X86_32_FastCall>
@@ -809,11 +977,12 @@ def CC_X86_32 : CallingConv<[
CCIfCC<"CallingConv::X86_INTR", CCDelegateTo<CC_X86_32_Intr>>,
CCIfSubtarget<"isTargetMCU()", CCDelegateTo<CC_X86_32_MCU>>,
CCIfCC<"CallingConv::X86_FastCall", CCDelegateTo<CC_X86_32_FastCall>>,
- CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<CC_X86_32_VectorCall>>,
+ CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<CC_X86_Win32_VectorCall>>,
CCIfCC<"CallingConv::X86_ThisCall", CCDelegateTo<CC_X86_32_ThisCall>>,
CCIfCC<"CallingConv::Fast", CCDelegateTo<CC_X86_32_FastCC>>,
CCIfCC<"CallingConv::GHC", CCDelegateTo<CC_X86_32_GHC>>,
CCIfCC<"CallingConv::HiPE", CCDelegateTo<CC_X86_32_HiPE>>,
+ CCIfCC<"CallingConv::X86_RegCall", CCDelegateTo<CC_X86_32_RegCall>>,
// Otherwise, drop to normal X86-32 CC
CCDelegateTo<CC_X86_32_C>
@@ -830,6 +999,9 @@ def CC_X86_64 : CallingConv<[
CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<CC_X86_Win64_VectorCall>>,
CCIfCC<"CallingConv::HHVM", CCDelegateTo<CC_X86_64_HHVM>>,
CCIfCC<"CallingConv::HHVM_C", CCDelegateTo<CC_X86_64_HHVM_C>>,
+ CCIfCC<"CallingConv::X86_RegCall",
+ CCIfSubtarget<"isTargetWin64()", CCDelegateTo<CC_X86_Win64_RegCall>>>,
+ CCIfCC<"CallingConv::X86_RegCall", CCDelegateTo<CC_X86_SysV64_RegCall>>,
CCIfCC<"CallingConv::X86_INTR", CCDelegateTo<CC_X86_64_Intr>>,
// Mingw64 and native Win64 use Win64 CC
@@ -860,7 +1032,9 @@ def CSR_64_SwiftError : CalleeSavedRegs<(sub CSR_64, R12)>;
def CSR_32EHRet : CalleeSavedRegs<(add EAX, EDX, CSR_32)>;
def CSR_64EHRet : CalleeSavedRegs<(add RAX, RDX, CSR_64)>;
-def CSR_Win64 : CalleeSavedRegs<(add RBX, RBP, RDI, RSI, R12, R13, R14, R15,
+def CSR_Win64_NoSSE : CalleeSavedRegs<(add RBX, RBP, RDI, RSI, R12, R13, R14, R15)>;
+
+def CSR_Win64 : CalleeSavedRegs<(add CSR_Win64_NoSSE,
(sequence "XMM%u", 6, 15))>;
// The function used by Darwin to obtain the address of a thread-local variable
@@ -931,3 +1105,17 @@ def CSR_64_Intel_OCL_BI_AVX512 : CalleeSavedRegs<(add RBX, RDI, RSI, R14, R15,
// Only R12 is preserved for PHP calls in HHVM.
def CSR_64_HHVM : CalleeSavedRegs<(add R12)>;
+
+// Register calling convention preserves few GPR and XMM8-15
+def CSR_32_RegCall_NoSSE : CalleeSavedRegs<(add ESI, EDI, EBX, EBP, ESP)>;
+def CSR_32_RegCall : CalleeSavedRegs<(add CSR_32_RegCall_NoSSE,
+ (sequence "XMM%u", 4, 7))>;
+def CSR_Win64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP, RSP,
+ (sequence "R%u", 10, 15))>;
+def CSR_Win64_RegCall : CalleeSavedRegs<(add CSR_Win64_RegCall_NoSSE,
+ (sequence "XMM%u", 8, 15))>;
+def CSR_SysV64_RegCall_NoSSE : CalleeSavedRegs<(add RBX, RBP, RSP,
+ (sequence "R%u", 12, 15))>;
+def CSR_SysV64_RegCall : CalleeSavedRegs<(add CSR_SysV64_RegCall_NoSSE,
+ (sequence "XMM%u", 8, 15))>;
+
diff --git a/contrib/llvm/lib/Target/X86/X86EvexToVex.cpp b/contrib/llvm/lib/Target/X86/X86EvexToVex.cpp
new file mode 100755
index 0000000..bdd1ab5
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86EvexToVex.cpp
@@ -0,0 +1,213 @@
+//===----------------------- X86EvexToVex.cpp ----------------------------===//
+// Compress EVEX instructions to VEX encoding when possible to reduce code size
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+/// \file
+/// This file defines the pass that goes over all AVX-512 instructions which
+/// are encoded using the EVEX prefix and if possible replaces them by their
+/// corresponding VEX encoding which is usually shorter by 2 bytes.
+/// EVEX instructions may be encoded via the VEX prefix when the AVX-512
+/// instruction has a corresponding AVX/AVX2 opcode and when it does not
+/// use the xmm or the mask registers or xmm/ymm registers wuith indexes
+/// higher than 15.
+/// The pass applies code reduction on the generated code for AVX-512 instrs.
+///
+//===---------------------------------------------------------------------===//
+
+#include "InstPrinter/X86InstComments.h"
+#include "X86.h"
+#include "X86InstrBuilder.h"
+#include "X86InstrInfo.h"
+#include "X86InstrTablesInfo.h"
+#include "X86MachineFunctionInfo.h"
+#include "X86Subtarget.h"
+#include "X86TargetMachine.h"
+
+using namespace llvm;
+
+#define EVEX2VEX_DESC "Compressing EVEX instrs to VEX encoding when possible"
+#define EVEX2VEX_NAME "x86-evex-to-vex-compress"
+
+#define DEBUG_TYPE EVEX2VEX_NAME
+
+namespace {
+
+class EvexToVexInstPass : public MachineFunctionPass {
+
+ /// X86EvexToVexCompressTable - Evex to Vex encoding opcode map.
+ typedef DenseMap<unsigned, uint16_t> EvexToVexTableType;
+ EvexToVexTableType EvexToVex128Table;
+ EvexToVexTableType EvexToVex256Table;
+
+ /// For EVEX instructions that can be encoded using VEX encoding, replace
+ /// them by the VEX encoding in order to reduce size.
+ bool CompressEvexToVexImpl(MachineInstr &MI) const;
+
+ /// For initializing the hash map tables of all AVX-512 EVEX
+ /// corresponding to AVX/AVX2 opcodes.
+ void AddTableEntry(EvexToVexTableType &EvexToVexTable, uint16_t EvexOp,
+ uint16_t VexOp);
+
+public:
+ static char ID;
+
+ StringRef getPassName() const override { return EVEX2VEX_DESC; }
+
+ EvexToVexInstPass() : MachineFunctionPass(ID) {
+ initializeEvexToVexInstPassPass(*PassRegistry::getPassRegistry());
+
+ // Initialize the EVEX to VEX 128 table map.
+ for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex128CompressTable) {
+ AddTableEntry(EvexToVex128Table, Entry.EvexOpcode, Entry.VexOpcode);
+ }
+
+ // Initialize the EVEX to VEX 256 table map.
+ for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex256CompressTable) {
+ AddTableEntry(EvexToVex256Table, Entry.EvexOpcode, Entry.VexOpcode);
+ }
+ }
+
+ /// Loop over all of the basic blocks, replacing EVEX instructions
+ /// by equivalent VEX instructions when possible for reducing code size.
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ // This pass runs after regalloc and doesn't support VReg operands.
+ MachineFunctionProperties getRequiredProperties() const override {
+ return MachineFunctionProperties().set(
+ MachineFunctionProperties::Property::NoVRegs);
+ }
+
+private:
+ /// Machine instruction info used throughout the class.
+ const X86InstrInfo *TII;
+};
+
+char EvexToVexInstPass::ID = 0;
+}
+
+INITIALIZE_PASS(EvexToVexInstPass, EVEX2VEX_NAME, EVEX2VEX_DESC, false, false)
+
+FunctionPass *llvm::createX86EvexToVexInsts() {
+ return new EvexToVexInstPass();
+}
+
+bool EvexToVexInstPass::runOnMachineFunction(MachineFunction &MF) {
+ TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
+
+ const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
+ if (!ST.hasAVX512())
+ return false;
+
+ bool Changed = false;
+
+ /// Go over all basic blocks in function and replace
+ /// EVEX encoded instrs by VEX encoding when possible.
+ for (MachineBasicBlock &MBB : MF) {
+
+ // Traverse the basic block.
+ for (MachineInstr &MI : MBB)
+ Changed |= CompressEvexToVexImpl(MI);
+ }
+
+ return Changed;
+}
+
+void EvexToVexInstPass::AddTableEntry(EvexToVexTableType &EvexToVexTable,
+ uint16_t EvexOp, uint16_t VexOp) {
+ EvexToVexTable[EvexOp] = VexOp;
+}
+
+// For EVEX instructions that can be encoded using VEX encoding
+// replace them by the VEX encoding in order to reduce size.
+bool EvexToVexInstPass::CompressEvexToVexImpl(MachineInstr &MI) const {
+
+ // VEX format.
+ // # of bytes: 0,2,3 1 1 0,1 0,1,2,4 0,1
+ // [Prefixes] [VEX] OPCODE ModR/M [SIB] [DISP] [IMM]
+ //
+ // EVEX format.
+ // # of bytes: 4 1 1 1 4 / 1 1
+ // [Prefixes] EVEX Opcode ModR/M [SIB] [Disp32] / [Disp8*N] [Immediate]
+
+ const MCInstrDesc &Desc = MI.getDesc();
+
+ // Check for EVEX instructions only.
+ if ((Desc.TSFlags & X86II::EncodingMask) != X86II::EVEX)
+ return false;
+
+ // Check for EVEX instructions with mask or broadcast as in these cases
+ // the EVEX prefix is needed in order to carry this information
+ // thus preventing the transformation to VEX encoding.
+ if (Desc.TSFlags & (X86II::EVEX_K | X86II::EVEX_B))
+ return false;
+
+ // Check for non EVEX_V512 instrs only.
+ // EVEX_V512 instr: bit EVEX_L2 = 1; bit VEX_L = 0.
+ if ((Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L))
+ return false;
+
+ // EVEX_V128 instr: bit EVEX_L2 = 0, bit VEX_L = 0.
+ bool IsEVEX_V128 =
+ (!(Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L));
+
+ // EVEX_V256 instr: bit EVEX_L2 = 0, bit VEX_L = 1.
+ bool IsEVEX_V256 =
+ (!(Desc.TSFlags & X86II::EVEX_L2) && (Desc.TSFlags & X86II::VEX_L));
+
+ unsigned NewOpc = 0;
+
+ // Check for EVEX_V256 instructions.
+ if (IsEVEX_V256) {
+ // Search for opcode in the EvexToVex256 table.
+ auto It = EvexToVex256Table.find(MI.getOpcode());
+ if (It != EvexToVex256Table.end())
+ NewOpc = It->second;
+ }
+
+ // Check for EVEX_V128 or Scalar instructions.
+ else if (IsEVEX_V128) {
+ // Search for opcode in the EvexToVex128 table.
+ auto It = EvexToVex128Table.find(MI.getOpcode());
+ if (It != EvexToVex128Table.end())
+ NewOpc = It->second;
+ }
+
+ if (!NewOpc)
+ return false;
+
+ auto isHiRegIdx = [](unsigned Reg) {
+ // Check for XMM register with indexes between 16 - 31.
+ if (Reg >= X86::XMM16 && Reg <= X86::XMM31)
+ return true;
+
+ // Check for YMM register with indexes between 16 - 31.
+ if (Reg >= X86::YMM16 && Reg <= X86::YMM31)
+ return true;
+
+ return false;
+ };
+
+ // Check that operands are not ZMM regs or
+ // XMM/YMM regs with hi indexes between 16 - 31.
+ for (const MachineOperand &MO : MI.explicit_operands()) {
+ if (!MO.isReg())
+ continue;
+
+ unsigned Reg = MO.getReg();
+
+ assert (!(Reg >= X86::ZMM0 && Reg <= X86::ZMM31));
+
+ if (isHiRegIdx(Reg))
+ return false;
+ }
+
+ const MCInstrDesc &MCID = TII->get(NewOpc);
+ MI.setDesc(MCID);
+ MI.setAsmPrinterFlag(AC_EVEX_2_VEX);
+ return true;
+}
diff --git a/contrib/llvm/lib/Target/X86/X86ExpandPseudo.cpp b/contrib/llvm/lib/Target/X86/X86ExpandPseudo.cpp
index 093fed7..985acf9 100644
--- a/contrib/llvm/lib/Target/X86/X86ExpandPseudo.cpp
+++ b/contrib/llvm/lib/Target/X86/X86ExpandPseudo.cpp
@@ -51,10 +51,10 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "X86 pseudo instruction expansion pass";
}
@@ -94,7 +94,7 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive");
// Incoporate the retaddr area.
- Offset = StackAdj-MaxTCDelta;
+ Offset = StackAdj - MaxTCDelta;
assert(Offset >= 0 && "Offset should never be negative");
if (Offset) {
@@ -106,14 +106,22 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
// Jump to label or value in register.
bool IsWin64 = STI->isTargetWin64();
if (Opcode == X86::TCRETURNdi || Opcode == X86::TCRETURNdi64) {
- unsigned Op = (Opcode == X86::TCRETURNdi)
- ? X86::TAILJMPd
- : (IsWin64 ? X86::TAILJMPd64_REX : X86::TAILJMPd64);
+ unsigned Op;
+ switch (Opcode) {
+ case X86::TCRETURNdi:
+ Op = X86::TAILJMPd;
+ break;
+ default:
+ // Note: Win64 uses REX prefixes indirect jumps out of functions, but
+ // not direct ones.
+ Op = X86::TAILJMPd64;
+ break;
+ }
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(Op));
- if (JumpTarget.isGlobal())
+ if (JumpTarget.isGlobal()) {
MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(),
JumpTarget.getTargetFlags());
- else {
+ } else {
assert(JumpTarget.isSymbol());
MIB.addExternalSymbol(JumpTarget.getSymbolName(),
JumpTarget.getTargetFlags());
diff --git a/contrib/llvm/lib/Target/X86/X86FastISel.cpp b/contrib/llvm/lib/Target/X86/X86FastISel.cpp
index dfe3c80..c890fdd 100644
--- a/contrib/llvm/lib/Target/X86/X86FastISel.cpp
+++ b/contrib/llvm/lib/Target/X86/X86FastISel.cpp
@@ -170,6 +170,12 @@ private:
const MachineInstrBuilder &addFullAddress(const MachineInstrBuilder &MIB,
X86AddressMode &AM);
+
+ unsigned fastEmitInst_rrrr(unsigned MachineInstOpcode,
+ const TargetRegisterClass *RC, unsigned Op0,
+ bool Op0IsKill, unsigned Op1, bool Op1IsKill,
+ unsigned Op2, bool Op2IsKill, unsigned Op3,
+ bool Op3IsKill);
};
} // end anonymous namespace.
@@ -182,18 +188,18 @@ getX86ConditionCode(CmpInst::Predicate Predicate) {
default: break;
// Floating-point Predicates
case CmpInst::FCMP_UEQ: CC = X86::COND_E; break;
- case CmpInst::FCMP_OLT: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_OLT: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_OGT: CC = X86::COND_A; break;
- case CmpInst::FCMP_OLE: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_OLE: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_OGE: CC = X86::COND_AE; break;
- case CmpInst::FCMP_UGT: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_UGT: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_ULT: CC = X86::COND_B; break;
- case CmpInst::FCMP_UGE: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_UGE: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_ULE: CC = X86::COND_BE; break;
case CmpInst::FCMP_ONE: CC = X86::COND_NE; break;
case CmpInst::FCMP_UNO: CC = X86::COND_P; break;
case CmpInst::FCMP_ORD: CC = X86::COND_NP; break;
- case CmpInst::FCMP_OEQ: // fall-through
+ case CmpInst::FCMP_OEQ: LLVM_FALLTHROUGH;
case CmpInst::FCMP_UNE: CC = X86::COND_INVALID; break;
// Integer Predicates
@@ -229,15 +235,15 @@ getX86SSEConditionCode(CmpInst::Predicate Predicate) {
switch (Predicate) {
default: llvm_unreachable("Unexpected predicate");
case CmpInst::FCMP_OEQ: CC = 0; break;
- case CmpInst::FCMP_OGT: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_OGT: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_OLT: CC = 1; break;
- case CmpInst::FCMP_OGE: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_OGE: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_OLE: CC = 2; break;
case CmpInst::FCMP_UNO: CC = 3; break;
case CmpInst::FCMP_UNE: CC = 4; break;
- case CmpInst::FCMP_ULE: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_ULE: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_UGE: CC = 5; break;
- case CmpInst::FCMP_ULT: NeedSwap = true; // fall-through
+ case CmpInst::FCMP_ULT: NeedSwap = true; LLVM_FALLTHROUGH;
case CmpInst::FCMP_UGT: CC = 6; break;
case CmpInst::FCMP_ORD: CC = 7; break;
case CmpInst::FCMP_UEQ:
@@ -351,6 +357,8 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
bool HasSSE41 = Subtarget->hasSSE41();
bool HasAVX = Subtarget->hasAVX();
bool HasAVX2 = Subtarget->hasAVX2();
+ bool HasAVX512 = Subtarget->hasAVX512();
+ bool HasVLX = Subtarget->hasVLX();
bool IsNonTemporal = MMO && MMO->isNonTemporal();
// Get opcode and regclass of the output for the given load instruction.
@@ -378,7 +386,7 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
break;
case MVT::f32:
if (X86ScalarSSEf32) {
- Opc = HasAVX ? X86::VMOVSSrm : X86::MOVSSrm;
+ Opc = HasAVX512 ? X86::VMOVSSZrm : HasAVX ? X86::VMOVSSrm : X86::MOVSSrm;
RC = &X86::FR32RegClass;
} else {
Opc = X86::LD_Fp32m;
@@ -387,7 +395,7 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
break;
case MVT::f64:
if (X86ScalarSSEf64) {
- Opc = HasAVX ? X86::VMOVSDrm : X86::MOVSDrm;
+ Opc = HasAVX512 ? X86::VMOVSDZrm : HasAVX ? X86::VMOVSDrm : X86::MOVSDrm;
RC = &X86::FR64RegClass;
} else {
Opc = X86::LD_Fp64m;
@@ -399,20 +407,26 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
return false;
case MVT::v4f32:
if (IsNonTemporal && Alignment >= 16 && HasSSE41)
- Opc = HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
+ Opc = HasVLX ? X86::VMOVNTDQAZ128rm :
+ HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
else if (Alignment >= 16)
- Opc = HasAVX ? X86::VMOVAPSrm : X86::MOVAPSrm;
+ Opc = HasVLX ? X86::VMOVAPSZ128rm :
+ HasAVX ? X86::VMOVAPSrm : X86::MOVAPSrm;
else
- Opc = HasAVX ? X86::VMOVUPSrm : X86::MOVUPSrm;
+ Opc = HasVLX ? X86::VMOVUPSZ128rm :
+ HasAVX ? X86::VMOVUPSrm : X86::MOVUPSrm;
RC = &X86::VR128RegClass;
break;
case MVT::v2f64:
if (IsNonTemporal && Alignment >= 16 && HasSSE41)
- Opc = HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
+ Opc = HasVLX ? X86::VMOVNTDQAZ128rm :
+ HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
else if (Alignment >= 16)
- Opc = HasAVX ? X86::VMOVAPDrm : X86::MOVAPDrm;
+ Opc = HasVLX ? X86::VMOVAPDZ128rm :
+ HasAVX ? X86::VMOVAPDrm : X86::MOVAPDrm;
else
- Opc = HasAVX ? X86::VMOVUPDrm : X86::MOVUPDrm;
+ Opc = HasVLX ? X86::VMOVUPDZ128rm :
+ HasAVX ? X86::VMOVUPDrm : X86::MOVUPDrm;
RC = &X86::VR128RegClass;
break;
case MVT::v4i32:
@@ -420,27 +434,34 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
case MVT::v8i16:
case MVT::v16i8:
if (IsNonTemporal && Alignment >= 16)
- Opc = HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
+ Opc = HasVLX ? X86::VMOVNTDQAZ128rm :
+ HasAVX ? X86::VMOVNTDQArm : X86::MOVNTDQArm;
else if (Alignment >= 16)
- Opc = HasAVX ? X86::VMOVDQArm : X86::MOVDQArm;
+ Opc = HasVLX ? X86::VMOVDQA64Z128rm :
+ HasAVX ? X86::VMOVDQArm : X86::MOVDQArm;
else
- Opc = HasAVX ? X86::VMOVDQUrm : X86::MOVDQUrm;
+ Opc = HasVLX ? X86::VMOVDQU64Z128rm :
+ HasAVX ? X86::VMOVDQUrm : X86::MOVDQUrm;
RC = &X86::VR128RegClass;
break;
case MVT::v8f32:
assert(HasAVX);
if (IsNonTemporal && Alignment >= 32 && HasAVX2)
- Opc = X86::VMOVNTDQAYrm;
+ Opc = HasVLX ? X86::VMOVNTDQAZ256rm : X86::VMOVNTDQAYrm;
+ else if (Alignment >= 32)
+ Opc = HasVLX ? X86::VMOVAPSZ256rm : X86::VMOVAPSYrm;
else
- Opc = (Alignment >= 32) ? X86::VMOVAPSYrm : X86::VMOVUPSYrm;
+ Opc = HasVLX ? X86::VMOVUPSZ256rm : X86::VMOVUPSYrm;
RC = &X86::VR256RegClass;
break;
case MVT::v4f64:
assert(HasAVX);
if (IsNonTemporal && Alignment >= 32 && HasAVX2)
Opc = X86::VMOVNTDQAYrm;
+ else if (Alignment >= 32)
+ Opc = HasVLX ? X86::VMOVAPDZ256rm : X86::VMOVAPDYrm;
else
- Opc = (Alignment >= 32) ? X86::VMOVAPDYrm : X86::VMOVUPDYrm;
+ Opc = HasVLX ? X86::VMOVUPDZ256rm : X86::VMOVUPDYrm;
RC = &X86::VR256RegClass;
break;
case MVT::v8i32:
@@ -450,12 +471,14 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
assert(HasAVX);
if (IsNonTemporal && Alignment >= 32 && HasAVX2)
Opc = X86::VMOVNTDQAYrm;
+ else if (Alignment >= 32)
+ Opc = HasVLX ? X86::VMOVDQA64Z256rm : X86::VMOVDQAYrm;
else
- Opc = (Alignment >= 32) ? X86::VMOVDQAYrm : X86::VMOVDQUYrm;
+ Opc = HasVLX ? X86::VMOVDQU64Z256rm : X86::VMOVDQUYrm;
RC = &X86::VR256RegClass;
break;
case MVT::v16f32:
- assert(Subtarget->hasAVX512());
+ assert(HasAVX512);
if (IsNonTemporal && Alignment >= 64)
Opc = X86::VMOVNTDQAZrm;
else
@@ -463,7 +486,7 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
RC = &X86::VR512RegClass;
break;
case MVT::v8f64:
- assert(Subtarget->hasAVX512());
+ assert(HasAVX512);
if (IsNonTemporal && Alignment >= 64)
Opc = X86::VMOVNTDQAZrm;
else
@@ -474,7 +497,7 @@ bool X86FastISel::X86FastEmitLoad(EVT VT, X86AddressMode &AM,
case MVT::v16i32:
case MVT::v32i16:
case MVT::v64i8:
- assert(Subtarget->hasAVX512());
+ assert(HasAVX512);
// Note: There are a lot more choices based on type with AVX-512, but
// there's really no advantage when the load isn't masked.
if (IsNonTemporal && Alignment >= 64)
@@ -504,6 +527,8 @@ bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
bool HasSSE2 = Subtarget->hasSSE2();
bool HasSSE4A = Subtarget->hasSSE4A();
bool HasAVX = Subtarget->hasAVX();
+ bool HasAVX512 = Subtarget->hasAVX512();
+ bool HasVLX = Subtarget->hasVLX();
bool IsNonTemporal = MMO && MMO->isNonTemporal();
// Get opcode and regclass of the output for the given store instruction.
@@ -518,8 +543,8 @@ bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
TII.get(X86::AND8ri), AndResult)
.addReg(ValReg, getKillRegState(ValIsKill)).addImm(1);
ValReg = AndResult;
+ LLVM_FALLTHROUGH; // handle i1 as i8.
}
- // FALLTHROUGH, handling i1 as i8.
case MVT::i8: Opc = X86::MOV8mr; break;
case MVT::i16: Opc = X86::MOV16mr; break;
case MVT::i32:
@@ -534,7 +559,8 @@ bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
if (IsNonTemporal && HasSSE4A)
Opc = X86::MOVNTSS;
else
- Opc = HasAVX ? X86::VMOVSSmr : X86::MOVSSmr;
+ Opc = HasAVX512 ? X86::VMOVSSZmr :
+ HasAVX ? X86::VMOVSSmr : X86::MOVSSmr;
} else
Opc = X86::ST_Fp32m;
break;
@@ -543,27 +569,34 @@ bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
if (IsNonTemporal && HasSSE4A)
Opc = X86::MOVNTSD;
else
- Opc = HasAVX ? X86::VMOVSDmr : X86::MOVSDmr;
+ Opc = HasAVX512 ? X86::VMOVSDZmr :
+ HasAVX ? X86::VMOVSDmr : X86::MOVSDmr;
} else
Opc = X86::ST_Fp64m;
break;
case MVT::v4f32:
if (Aligned) {
if (IsNonTemporal)
- Opc = HasAVX ? X86::VMOVNTPSmr : X86::MOVNTPSmr;
+ Opc = HasVLX ? X86::VMOVNTPSZ128mr :
+ HasAVX ? X86::VMOVNTPSmr : X86::MOVNTPSmr;
else
- Opc = HasAVX ? X86::VMOVAPSmr : X86::MOVAPSmr;
+ Opc = HasVLX ? X86::VMOVAPSZ128mr :
+ HasAVX ? X86::VMOVAPSmr : X86::MOVAPSmr;
} else
- Opc = HasAVX ? X86::VMOVUPSmr : X86::MOVUPSmr;
+ Opc = HasVLX ? X86::VMOVUPSZ128mr :
+ HasAVX ? X86::VMOVUPSmr : X86::MOVUPSmr;
break;
case MVT::v2f64:
if (Aligned) {
if (IsNonTemporal)
- Opc = HasAVX ? X86::VMOVNTPDmr : X86::MOVNTPDmr;
+ Opc = HasVLX ? X86::VMOVNTPDZ128mr :
+ HasAVX ? X86::VMOVNTPDmr : X86::MOVNTPDmr;
else
- Opc = HasAVX ? X86::VMOVAPDmr : X86::MOVAPDmr;
+ Opc = HasVLX ? X86::VMOVAPDZ128mr :
+ HasAVX ? X86::VMOVAPDmr : X86::MOVAPDmr;
} else
- Opc = HasAVX ? X86::VMOVUPDmr : X86::MOVUPDmr;
+ Opc = HasVLX ? X86::VMOVUPDZ128mr :
+ HasAVX ? X86::VMOVUPDmr : X86::MOVUPDmr;
break;
case MVT::v4i32:
case MVT::v2i64:
@@ -571,45 +604,57 @@ bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
case MVT::v16i8:
if (Aligned) {
if (IsNonTemporal)
- Opc = HasAVX ? X86::VMOVNTDQmr : X86::MOVNTDQmr;
+ Opc = HasVLX ? X86::VMOVNTDQZ128mr :
+ HasAVX ? X86::VMOVNTDQmr : X86::MOVNTDQmr;
else
- Opc = HasAVX ? X86::VMOVDQAmr : X86::MOVDQAmr;
+ Opc = HasVLX ? X86::VMOVDQA64Z128mr :
+ HasAVX ? X86::VMOVDQAmr : X86::MOVDQAmr;
} else
- Opc = HasAVX ? X86::VMOVDQUmr : X86::MOVDQUmr;
+ Opc = HasVLX ? X86::VMOVDQU64Z128mr :
+ HasAVX ? X86::VMOVDQUmr : X86::MOVDQUmr;
break;
case MVT::v8f32:
assert(HasAVX);
- if (Aligned)
- Opc = IsNonTemporal ? X86::VMOVNTPSYmr : X86::VMOVAPSYmr;
- else
- Opc = X86::VMOVUPSYmr;
+ if (Aligned) {
+ if (IsNonTemporal)
+ Opc = HasVLX ? X86::VMOVNTPSZ256mr : X86::VMOVNTPSYmr;
+ else
+ Opc = HasVLX ? X86::VMOVAPSZ256mr : X86::VMOVAPSYmr;
+ } else
+ Opc = HasVLX ? X86::VMOVUPSZ256mr : X86::VMOVUPSYmr;
break;
case MVT::v4f64:
assert(HasAVX);
if (Aligned) {
- Opc = IsNonTemporal ? X86::VMOVNTPDYmr : X86::VMOVAPDYmr;
+ if (IsNonTemporal)
+ Opc = HasVLX ? X86::VMOVNTPDZ256mr : X86::VMOVNTPDYmr;
+ else
+ Opc = HasVLX ? X86::VMOVAPDZ256mr : X86::VMOVAPDYmr;
} else
- Opc = X86::VMOVUPDYmr;
+ Opc = HasVLX ? X86::VMOVUPDZ256mr : X86::VMOVUPDYmr;
break;
case MVT::v8i32:
case MVT::v4i64:
case MVT::v16i16:
case MVT::v32i8:
assert(HasAVX);
- if (Aligned)
- Opc = IsNonTemporal ? X86::VMOVNTDQYmr : X86::VMOVDQAYmr;
- else
- Opc = X86::VMOVDQUYmr;
+ if (Aligned) {
+ if (IsNonTemporal)
+ Opc = HasVLX ? X86::VMOVNTDQZ256mr : X86::VMOVNTDQYmr;
+ else
+ Opc = HasVLX ? X86::VMOVDQA64Z256mr : X86::VMOVDQAYmr;
+ } else
+ Opc = HasVLX ? X86::VMOVDQU64Z256mr : X86::VMOVDQUYmr;
break;
case MVT::v16f32:
- assert(Subtarget->hasAVX512());
+ assert(HasAVX512);
if (Aligned)
Opc = IsNonTemporal ? X86::VMOVNTPSZmr : X86::VMOVAPSZmr;
else
Opc = X86::VMOVUPSZmr;
break;
case MVT::v8f64:
- assert(Subtarget->hasAVX512());
+ assert(HasAVX512);
if (Aligned) {
Opc = IsNonTemporal ? X86::VMOVNTPDZmr : X86::VMOVAPDZmr;
} else
@@ -619,7 +664,7 @@ bool X86FastISel::X86FastEmitStore(EVT VT, unsigned ValReg, bool ValIsKill,
case MVT::v16i32:
case MVT::v32i16:
case MVT::v64i8:
- assert(Subtarget->hasAVX512());
+ assert(HasAVX512);
// Note: There are a lot more choices based on type with AVX-512, but
// there's really no advantage when the store isn't masked.
if (Aligned)
@@ -659,7 +704,9 @@ bool X86FastISel::X86FastEmitStore(EVT VT, const Value *Val,
bool Signed = true;
switch (VT.getSimpleVT().SimpleTy) {
default: break;
- case MVT::i1: Signed = false; // FALLTHROUGH to handle as i8.
+ case MVT::i1:
+ Signed = false;
+ LLVM_FALLTHROUGH; // Handle as i8.
case MVT::i8: Opc = X86::MOV8mi; break;
case MVT::i16: Opc = X86::MOV16mi; break;
case MVT::i32: Opc = X86::MOV32mi; break;
@@ -895,7 +942,7 @@ redo_gep:
for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end();
i != e; ++i, ++GTI) {
const Value *Op = *i;
- if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
const StructLayout *SL = DL.getStructLayout(STy);
Disp += SL->getElementOffset(cast<ConstantInt>(Op)->getZExtValue());
continue;
@@ -1454,11 +1501,11 @@ bool X86FastISel::X86SelectCmp(const Instruction *I) {
}
// FCMP_OEQ and FCMP_UNE cannot be checked with a single instruction.
- static unsigned SETFOpcTable[2][3] = {
+ static const uint16_t SETFOpcTable[2][3] = {
{ X86::SETEr, X86::SETNPr, X86::AND8rr },
{ X86::SETNEr, X86::SETPr, X86::OR8rr }
};
- unsigned *SETFOpc = nullptr;
+ const uint16_t *SETFOpc = nullptr;
switch (Predicate) {
default: break;
case CmpInst::FCMP_OEQ: SETFOpc = &SETFOpcTable[0][0]; break;
@@ -1511,7 +1558,7 @@ bool X86FastISel::X86SelectZExt(const Instruction *I) {
// Handle zero-extension from i1 to i8, which is common.
MVT SrcVT = TLI.getSimpleValueType(DL, I->getOperand(0)->getType());
- if (SrcVT.SimpleTy == MVT::i1) {
+ if (SrcVT == MVT::i1) {
// Set the high bits to zero.
ResultReg = fastEmitZExtFromI1(MVT::i8, ResultReg, /*TODO: Kill=*/false);
SrcVT = MVT::i8;
@@ -1601,7 +1648,8 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) {
switch (Predicate) {
default: break;
case CmpInst::FCMP_OEQ:
- std::swap(TrueMBB, FalseMBB); // fall-through
+ std::swap(TrueMBB, FalseMBB);
+ LLVM_FALLTHROUGH;
case CmpInst::FCMP_UNE:
NeedExtraBranch = true;
Predicate = CmpInst::FCMP_ONE;
@@ -1651,6 +1699,7 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) {
if (TestOpc) {
unsigned OpReg = getRegForValue(TI->getOperand(0));
if (OpReg == 0) return false;
+
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TestOpc))
.addReg(OpReg).addImm(1);
@@ -1688,8 +1737,17 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) {
unsigned OpReg = getRegForValue(BI->getCondition());
if (OpReg == 0) return false;
+ // In case OpReg is a K register, COPY to a GPR
+ if (MRI.getRegClass(OpReg) == &X86::VK1RegClass) {
+ unsigned KOpReg = OpReg;
+ OpReg = createResultReg(&X86::GR8RegClass);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), OpReg)
+ .addReg(KOpReg);
+ }
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TEST8ri))
- .addReg(OpReg).addImm(1);
+ .addReg(OpReg)
+ .addImm(1);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::JNE_1))
.addMBB(TrueMBB);
finishCondBranch(BI->getParent(), TrueMBB, FalseMBB);
@@ -1875,15 +1933,15 @@ bool X86FastISel::X86SelectDivRem(const Instruction *I) {
// Copy the zero into the appropriate sub/super/identical physical
// register. Unfortunately the operations needed are not uniform enough
// to fit neatly into the table above.
- if (VT.SimpleTy == MVT::i16) {
+ if (VT == MVT::i16) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Copy), TypeEntry.HighInReg)
.addReg(Zero32, 0, X86::sub_16bit);
- } else if (VT.SimpleTy == MVT::i32) {
+ } else if (VT == MVT::i32) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Copy), TypeEntry.HighInReg)
.addReg(Zero32);
- } else if (VT.SimpleTy == MVT::i64) {
+ } else if (VT == MVT::i64) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::SUBREG_TO_REG), TypeEntry.HighInReg)
.addImm(0).addReg(Zero32).addImm(X86::sub_32bit);
@@ -1953,11 +2011,11 @@ bool X86FastISel::X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I) {
CmpInst::Predicate Predicate = optimizeCmpPredicate(CI);
// FCMP_OEQ and FCMP_UNE cannot be checked with a single instruction.
- static unsigned SETFOpcTable[2][3] = {
+ static const uint16_t SETFOpcTable[2][3] = {
{ X86::SETNPr, X86::SETEr , X86::TEST8rr },
{ X86::SETPr, X86::SETNEr, X86::OR8rr }
};
- unsigned *SETFOpc = nullptr;
+ const uint16_t *SETFOpc = nullptr;
switch (Predicate) {
default: break;
case CmpInst::FCMP_OEQ:
@@ -2023,8 +2081,17 @@ bool X86FastISel::X86FastEmitCMoveSelect(MVT RetVT, const Instruction *I) {
return false;
bool CondIsKill = hasTrivialKill(Cond);
+ // In case OpReg is a K register, COPY to a GPR
+ if (MRI.getRegClass(CondReg) == &X86::VK1RegClass) {
+ unsigned KCondReg = CondReg;
+ CondReg = createResultReg(&X86::GR8RegClass);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), CondReg)
+ .addReg(KCondReg, getKillRegState(CondIsKill));
+ }
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TEST8ri))
- .addReg(CondReg, getKillRegState(CondIsKill)).addImm(1);
+ .addReg(CondReg, getKillRegState(CondIsKill))
+ .addImm(1);
}
const Value *LHS = I->getOperand(1);
@@ -2087,12 +2154,12 @@ bool X86FastISel::X86FastEmitSSESelect(MVT RetVT, const Instruction *I) {
std::swap(CmpLHS, CmpRHS);
// Choose the SSE instruction sequence based on data type (float or double).
- static unsigned OpcTable[2][4] = {
- { X86::CMPSSrr, X86::FsANDPSrr, X86::FsANDNPSrr, X86::FsORPSrr },
- { X86::CMPSDrr, X86::FsANDPDrr, X86::FsANDNPDrr, X86::FsORPDrr }
+ static const uint16_t OpcTable[2][4] = {
+ { X86::CMPSSrr, X86::ANDPSrr, X86::ANDNPSrr, X86::ORPSrr },
+ { X86::CMPSDrr, X86::ANDPDrr, X86::ANDNPDrr, X86::ORPDrr }
};
- unsigned *Opc = nullptr;
+ const uint16_t *Opc = nullptr;
switch (RetVT.SimpleTy) {
default: return false;
case MVT::f32: Opc = &OpcTable[0][0]; break;
@@ -2119,9 +2186,36 @@ bool X86FastISel::X86FastEmitSSESelect(MVT RetVT, const Instruction *I) {
const TargetRegisterClass *RC = TLI.getRegClassFor(RetVT);
unsigned ResultReg;
-
- if (Subtarget->hasAVX()) {
- const TargetRegisterClass *FR32 = &X86::FR32RegClass;
+
+ if (Subtarget->hasAVX512()) {
+ // If we have AVX512 we can use a mask compare and masked movss/sd.
+ const TargetRegisterClass *VR128X = &X86::VR128XRegClass;
+ const TargetRegisterClass *VK1 = &X86::VK1RegClass;
+
+ unsigned CmpOpcode =
+ (RetVT == MVT::f32) ? X86::VCMPSSZrr : X86::VCMPSDZrr;
+ unsigned CmpReg = fastEmitInst_rri(CmpOpcode, VK1, CmpLHSReg, CmpLHSIsKill,
+ CmpRHSReg, CmpRHSIsKill, CC);
+
+ // Need an IMPLICIT_DEF for the input that is used to generate the upper
+ // bits of the result register since its not based on any of the inputs.
+ unsigned ImplicitDefReg = createResultReg(VR128X);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::IMPLICIT_DEF), ImplicitDefReg);
+
+ // Place RHSReg is the passthru of the masked movss/sd operation and put
+ // LHS in the input. The mask input comes from the compare.
+ unsigned MovOpcode =
+ (RetVT == MVT::f32) ? X86::VMOVSSZrrk : X86::VMOVSDZrrk;
+ unsigned MovReg = fastEmitInst_rrrr(MovOpcode, VR128X, RHSReg, RHSIsKill,
+ CmpReg, true, ImplicitDefReg, true,
+ LHSReg, LHSIsKill);
+
+ ResultReg = createResultReg(RC);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), ResultReg).addReg(MovReg);
+
+ } else if (Subtarget->hasAVX()) {
const TargetRegisterClass *VR128 = &X86::VR128RegClass;
// If we have AVX, create 1 blendv instead of 3 logic instructions.
@@ -2130,11 +2224,11 @@ bool X86FastISel::X86FastEmitSSESelect(MVT RetVT, const Instruction *I) {
// instructions as the AND/ANDN/OR sequence due to register moves, so
// don't bother.
unsigned CmpOpcode =
- (RetVT.SimpleTy == MVT::f32) ? X86::VCMPSSrr : X86::VCMPSDrr;
+ (RetVT == MVT::f32) ? X86::VCMPSSrr : X86::VCMPSDrr;
unsigned BlendOpcode =
- (RetVT.SimpleTy == MVT::f32) ? X86::VBLENDVPSrr : X86::VBLENDVPDrr;
-
- unsigned CmpReg = fastEmitInst_rri(CmpOpcode, FR32, CmpLHSReg, CmpLHSIsKill,
+ (RetVT == MVT::f32) ? X86::VBLENDVPSrr : X86::VBLENDVPDrr;
+
+ unsigned CmpReg = fastEmitInst_rri(CmpOpcode, RC, CmpLHSReg, CmpLHSIsKill,
CmpRHSReg, CmpRHSIsKill, CC);
unsigned VBlendReg = fastEmitInst_rrr(BlendOpcode, VR128, RHSReg, RHSIsKill,
LHSReg, LHSIsKill, CmpReg, true);
@@ -2142,14 +2236,18 @@ bool X86FastISel::X86FastEmitSSESelect(MVT RetVT, const Instruction *I) {
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::COPY), ResultReg).addReg(VBlendReg);
} else {
+ const TargetRegisterClass *VR128 = &X86::VR128RegClass;
unsigned CmpReg = fastEmitInst_rri(Opc[0], RC, CmpLHSReg, CmpLHSIsKill,
CmpRHSReg, CmpRHSIsKill, CC);
- unsigned AndReg = fastEmitInst_rr(Opc[1], RC, CmpReg, /*IsKill=*/false,
+ unsigned AndReg = fastEmitInst_rr(Opc[1], VR128, CmpReg, /*IsKill=*/false,
LHSReg, LHSIsKill);
- unsigned AndNReg = fastEmitInst_rr(Opc[2], RC, CmpReg, /*IsKill=*/true,
+ unsigned AndNReg = fastEmitInst_rr(Opc[2], VR128, CmpReg, /*IsKill=*/true,
RHSReg, RHSIsKill);
- ResultReg = fastEmitInst_rr(Opc[3], RC, AndNReg, /*IsKill=*/true,
- AndReg, /*IsKill=*/true);
+ unsigned OrReg = fastEmitInst_rr(Opc[3], VR128, AndNReg, /*IsKill=*/true,
+ AndReg, /*IsKill=*/true);
+ ResultReg = createResultReg(RC);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), ResultReg).addReg(OrReg);
}
updateValueMap(I, ResultReg);
return true;
@@ -2195,8 +2293,18 @@ bool X86FastISel::X86FastEmitPseudoSelect(MVT RetVT, const Instruction *I) {
if (CondReg == 0)
return false;
bool CondIsKill = hasTrivialKill(Cond);
+
+ // In case OpReg is a K register, COPY to a GPR
+ if (MRI.getRegClass(CondReg) == &X86::VK1RegClass) {
+ unsigned KCondReg = CondReg;
+ CondReg = createResultReg(&X86::GR8RegClass);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), CondReg)
+ .addReg(KCondReg, getKillRegState(CondIsKill));
+ }
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(X86::TEST8ri))
- .addReg(CondReg, getKillRegState(CondIsKill)).addImm(1);
+ .addReg(CondReg, getKillRegState(CondIsKill))
+ .addImm(1);
}
const Value *LHS = I->getOperand(1);
@@ -2522,8 +2630,8 @@ bool X86FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
// This needs to be set before we call getPtrSizedFrameRegister, otherwise
// we get the wrong frame register.
- MachineFrameInfo *MFI = MF->getFrameInfo();
- MFI->setFrameAddressIsTaken(true);
+ MachineFrameInfo &MFI = MF->getFrameInfo();
+ MFI.setFrameAddressIsTaken(true);
const X86RegisterInfo *RegInfo = Subtarget->getRegisterInfo();
unsigned FrameReg = RegInfo->getPtrSizedFrameRegister(*MF);
@@ -2698,7 +2806,9 @@ bool X86FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
const Function *Callee = II->getCalledFunction();
auto *Ty = cast<StructType>(Callee->getReturnType());
Type *RetTy = Ty->getTypeAtIndex(0U);
- Type *CondTy = Ty->getTypeAtIndex(1);
+ assert(Ty->getTypeAtIndex(1)->isIntegerTy() &&
+ Ty->getTypeAtIndex(1)->getScalarSizeInBits() == 1 &&
+ "Overflow value expected to be an i1");
MVT VT;
if (!isTypeLegal(RetTy, VT))
@@ -2808,7 +2918,8 @@ bool X86FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) {
if (!ResultReg)
return false;
- unsigned ResultReg2 = FuncInfo.CreateRegs(CondTy);
+ // Assign to a GPR since the overflow return value is lowered to a SETcc.
+ unsigned ResultReg2 = createResultReg(&X86::GR8RegClass);
assert((ResultReg+1) == ResultReg2 && "Nonconsecutive result registers.");
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CondOpc),
ResultReg2);
@@ -2966,7 +3077,7 @@ bool X86FastISel::fastLowerArguments() {
default: llvm_unreachable("Unexpected value type.");
case MVT::i32: SrcReg = GPR32ArgRegs[GPRIdx++]; break;
case MVT::i64: SrcReg = GPR64ArgRegs[GPRIdx++]; break;
- case MVT::f32: // fall-through
+ case MVT::f32: LLVM_FALLTHROUGH;
case MVT::f64: SrcReg = XMMArgRegs[FPRIdx++]; break;
}
unsigned DstReg = FuncInfo.MF->addLiveIn(SrcReg, RC);
@@ -3140,7 +3251,7 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
"Unexpected extend");
- if (ArgVT.SimpleTy == MVT::i1)
+ if (ArgVT == MVT::i1)
return false;
bool Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), ArgReg,
@@ -3154,7 +3265,7 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) {
"Unexpected extend");
// Handle zero-extension from i1 to i8, which is common.
- if (ArgVT.SimpleTy == MVT::i1) {
+ if (ArgVT == MVT::i1) {
// Set the high bits to zero.
ArgReg = fastEmitZExtFromI1(MVT::i8, ArgReg, /*TODO: Kill=*/false);
ArgVT = MVT::i8;
@@ -3456,8 +3567,14 @@ X86FastISel::fastSelectInstruction(const Instruction *I) {
if (!SrcVT.isSimple() || !DstVT.isSimple())
return false;
- if (!SrcVT.is128BitVector() &&
- !(Subtarget->hasAVX() && SrcVT.is256BitVector()))
+ MVT SVT = SrcVT.getSimpleVT();
+ MVT DVT = DstVT.getSimpleVT();
+
+ if (!SVT.is128BitVector() &&
+ !(Subtarget->hasAVX() && SVT.is256BitVector()) &&
+ !(Subtarget->hasAVX512() && SVT.is512BitVector() &&
+ (Subtarget->hasBWI() || (SVT.getScalarSizeInBits() >= 32 &&
+ DVT.getScalarSizeInBits() >= 32))))
return false;
unsigned Reg = getRegForValue(I->getOperand(0));
@@ -3505,7 +3622,7 @@ unsigned X86FastISel::X86MaterializeInt(const ConstantInt *CI, MVT VT) {
unsigned Opc = 0;
switch (VT.SimpleTy) {
default: llvm_unreachable("Unexpected value type");
- case MVT::i1: VT = MVT::i8; // fall-through
+ case MVT::i1: VT = MVT::i8; LLVM_FALLTHROUGH;
case MVT::i8: Opc = X86::MOV8ri; break;
case MVT::i16: Opc = X86::MOV16ri; break;
case MVT::i32: Opc = X86::MOV32ri; break;
@@ -3775,6 +3892,38 @@ bool X86FastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
return true;
}
+unsigned X86FastISel::fastEmitInst_rrrr(unsigned MachineInstOpcode,
+ const TargetRegisterClass *RC,
+ unsigned Op0, bool Op0IsKill,
+ unsigned Op1, bool Op1IsKill,
+ unsigned Op2, bool Op2IsKill,
+ unsigned Op3, bool Op3IsKill) {
+ const MCInstrDesc &II = TII.get(MachineInstOpcode);
+
+ unsigned ResultReg = createResultReg(RC);
+ Op0 = constrainOperandRegClass(II, Op0, II.getNumDefs());
+ Op1 = constrainOperandRegClass(II, Op1, II.getNumDefs() + 1);
+ Op2 = constrainOperandRegClass(II, Op2, II.getNumDefs() + 2);
+ Op2 = constrainOperandRegClass(II, Op2, II.getNumDefs() + 3);
+
+ if (II.getNumDefs() >= 1)
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg)
+ .addReg(Op0, getKillRegState(Op0IsKill))
+ .addReg(Op1, getKillRegState(Op1IsKill))
+ .addReg(Op2, getKillRegState(Op2IsKill))
+ .addReg(Op3, getKillRegState(Op3IsKill));
+ else {
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+ .addReg(Op0, getKillRegState(Op0IsKill))
+ .addReg(Op1, getKillRegState(Op1IsKill))
+ .addReg(Op2, getKillRegState(Op2IsKill))
+ .addReg(Op3, getKillRegState(Op3IsKill));
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), ResultReg).addReg(II.ImplicitDefs[0]);
+ }
+ return ResultReg;
+}
+
namespace llvm {
FastISel *X86::createFastISel(FunctionLoweringInfo &funcInfo,
diff --git a/contrib/llvm/lib/Target/X86/X86FixupBWInsts.cpp b/contrib/llvm/lib/Target/X86/X86FixupBWInsts.cpp
index 90e758d..8bde4bf 100644
--- a/contrib/llvm/lib/Target/X86/X86FixupBWInsts.cpp
+++ b/contrib/llvm/lib/Target/X86/X86FixupBWInsts.cpp
@@ -66,8 +66,6 @@ using namespace llvm;
#define DEBUG_TYPE FIXUPBW_NAME
// Option to allow this optimization pass to have fine-grained control.
-// This is turned off by default so as not to affect a large number of
-// existing lit tests.
static cl::opt<bool>
FixupBWInsts("fixup-byte-word-insts",
cl::desc("Change byte and word instructions to larger sizes"),
@@ -104,9 +102,7 @@ class FixupBWInstPass : public MachineFunctionPass {
public:
static char ID;
- const char *getPassName() const override {
- return FIXUPBW_DESC;
- }
+ StringRef getPassName() const override { return FIXUPBW_DESC; }
FixupBWInstPass() : MachineFunctionPass(ID) {
initializeFixupBWInstPassPass(*PassRegistry::getPassRegistry());
@@ -125,7 +121,7 @@ public:
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
@@ -158,7 +154,7 @@ bool FixupBWInstPass::runOnMachineFunction(MachineFunction &MF) {
TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
OptForSize = MF.getFunction()->optForSize();
MLI = &getAnalysis<MachineLoopInfo>();
- LiveRegs.init(&TII->getRegisterInfo());
+ LiveRegs.init(TII->getRegisterInfo());
DEBUG(dbgs() << "Start X86FixupBWInsts\n";);
diff --git a/contrib/llvm/lib/Target/X86/X86FixupLEAs.cpp b/contrib/llvm/lib/Target/X86/X86FixupLEAs.cpp
index 013ee24..1209591 100644
--- a/contrib/llvm/lib/Target/X86/X86FixupLEAs.cpp
+++ b/contrib/llvm/lib/Target/X86/X86FixupLEAs.cpp
@@ -40,7 +40,7 @@ class FixupLEAPass : public MachineFunctionPass {
/// where appropriate.
bool processBasicBlock(MachineFunction &MF, MachineFunction::iterator MFI);
- const char *getPassName() const override { return "X86 LEA Fixup"; }
+ StringRef getPassName() const override { return "X86 LEA Fixup"; }
/// \brief Given a machine register, look for the instruction
/// which writes it in the current basic block. If found,
@@ -95,7 +95,7 @@ public:
// This pass runs after regalloc and doesn't support VReg operands.
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
private:
diff --git a/contrib/llvm/lib/Target/X86/X86FixupSetCC.cpp b/contrib/llvm/lib/Target/X86/X86FixupSetCC.cpp
index fb317da..a86eb99 100644
--- a/contrib/llvm/lib/Target/X86/X86FixupSetCC.cpp
+++ b/contrib/llvm/lib/Target/X86/X86FixupSetCC.cpp
@@ -39,7 +39,7 @@ class X86FixupSetCCPass : public MachineFunctionPass {
public:
X86FixupSetCCPass() : MachineFunctionPass(ID) {}
- const char *getPassName() const override { return "X86 Fixup SetCC"; }
+ StringRef getPassName() const override { return "X86 Fixup SetCC"; }
bool runOnMachineFunction(MachineFunction &MF) override;
@@ -99,7 +99,8 @@ bool X86FixupSetCCPass::isSetCCr(unsigned Opcode) {
MachineInstr *
X86FixupSetCCPass::findFlagsImpDef(MachineBasicBlock *MBB,
MachineBasicBlock::reverse_iterator MI) {
- auto MBBStart = MBB->instr_rend();
+ // FIXME: Should this be instr_rend(), and MI be reverse_instr_iterator?
+ auto MBBStart = MBB->rend();
for (int i = 0; (i < SearchBound) && (MI != MBBStart); ++i, ++MI)
for (auto &Op : MI->implicit_operands())
if ((Op.getReg() == X86::EFLAGS) && (Op.isDef()))
diff --git a/contrib/llvm/lib/Target/X86/X86FloatingPoint.cpp b/contrib/llvm/lib/Target/X86/X86FloatingPoint.cpp
index 55c1bff..a5489b9 100644
--- a/contrib/llvm/lib/Target/X86/X86FloatingPoint.cpp
+++ b/contrib/llvm/lib/Target/X86/X86FloatingPoint.cpp
@@ -78,10 +78,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override { return "X86 FP Stackifier"; }
+ StringRef getPassName() const override { return "X86 FP Stackifier"; }
private:
const TargetInstrInfo *TII; // Machine instruction info.
@@ -206,6 +206,13 @@ namespace {
RegMap[Reg] = StackTop++;
}
+ // popReg - Pop a register from the stack.
+ void popReg() {
+ if (StackTop == 0)
+ report_fatal_error("Cannot pop empty stack!");
+ RegMap[Stack[--StackTop]] = ~0; // Update state
+ }
+
bool isAtTop(unsigned RegNo) const { return getSlot(RegNo) == StackTop-1; }
void moveToTop(unsigned RegNo, MachineBasicBlock::iterator I) {
DebugLoc dl = I == MBB->end() ? DebugLoc() : I->getDebugLoc();
@@ -326,9 +333,28 @@ bool FPS::runOnMachineFunction(MachineFunction &MF) {
// Process the function in depth first order so that we process at least one
// of the predecessors for every reachable block in the function.
- SmallPtrSet<MachineBasicBlock*, 8> Processed;
+ df_iterator_default_set<MachineBasicBlock*> Processed;
MachineBasicBlock *Entry = &MF.front();
+ LiveBundle &Bundle =
+ LiveBundles[Bundles->getBundle(Entry->getNumber(), false)];
+
+ // In regcall convention, some FP registers may not be passed through
+ // the stack, so they will need to be assigned to the stack first
+ if ((Entry->getParent()->getFunction()->getCallingConv() ==
+ CallingConv::X86_RegCall) && (Bundle.Mask && !Bundle.FixCount)) {
+ // In the register calling convention, up to one FP argument could be
+ // saved in the first FP register.
+ // If bundle.mask is non-zero and Bundle.FixCount is zero, it means
+ // that the FP registers contain arguments.
+ // The actual value is passed in FP0.
+ // Here we fix the stack and mark FP0 as pre-assigned register.
+ assert((Bundle.Mask & 0xFE) == 0 &&
+ "Only FP0 could be passed as an argument");
+ Bundle.FixCount = 1;
+ Bundle.FixStack[0] = 0;
+ }
+
bool Changed = false;
for (MachineBasicBlock *BB : depth_first_ext(Entry, Processed))
Changed |= processBasicBlock(MF, *BB);
@@ -791,9 +817,8 @@ void FPS::popStackAfter(MachineBasicBlock::iterator &I) {
MachineInstr &MI = *I;
const DebugLoc &dl = MI.getDebugLoc();
ASSERT_SORTED(PopTable);
- if (StackTop == 0)
- report_fatal_error("Cannot pop empty stack!");
- RegMap[Stack[--StackTop]] = ~0; // Update state
+
+ popReg();
// Check to see if there is a popping version of this instruction...
int Opcode = Lookup(PopTable, I->getOpcode());
@@ -929,6 +954,7 @@ void FPS::shuffleStackTop(const unsigned char *FixStack,
void FPS::handleCall(MachineBasicBlock::iterator &I) {
unsigned STReturns = 0;
+ const MachineFunction* MF = I->getParent()->getParent();
for (const auto &MO : I->operands()) {
if (!MO.isReg())
@@ -937,7 +963,10 @@ void FPS::handleCall(MachineBasicBlock::iterator &I) {
unsigned R = MO.getReg() - X86::FP0;
if (R < 8) {
- assert(MO.isDef() && MO.isImplicit());
+ if (MF->getFunction()->getCallingConv() != CallingConv::X86_RegCall) {
+ assert(MO.isDef() && MO.isImplicit());
+ }
+
STReturns |= 1 << R;
}
}
@@ -945,9 +974,15 @@ void FPS::handleCall(MachineBasicBlock::iterator &I) {
unsigned N = countTrailingOnes(STReturns);
// FP registers used for function return must be consecutive starting at
- // FP0.
+ // FP0
assert(STReturns == 0 || (isMask_32(STReturns) && N <= 2));
+ // Reset the FP Stack - It is required because of possible leftovers from
+ // passed arguments. The caller should assume that the FP stack is
+ // returned empty (unless the callee returns values on FP stack).
+ while (StackTop > 0)
+ popReg();
+
for (unsigned I = 0; I < N; ++I)
pushReg(N - I - 1);
}
diff --git a/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp b/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp
index 03d9256..cd69044 100644
--- a/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -50,7 +50,7 @@ X86FrameLowering::X86FrameLowering(const X86Subtarget &STI,
}
bool X86FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- return !MF.getFrameInfo()->hasVarSizedObjects() &&
+ return !MF.getFrameInfo().hasVarSizedObjects() &&
!MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences();
}
@@ -74,7 +74,7 @@ X86FrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const {
// when there are no stack objects.
bool
X86FrameLowering::needsFrameIndexResolution(const MachineFunction &MF) const {
- return MF.getFrameInfo()->hasStackObjects() ||
+ return MF.getFrameInfo().hasStackObjects() ||
MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences();
}
@@ -82,17 +82,15 @@ X86FrameLowering::needsFrameIndexResolution(const MachineFunction &MF) const {
/// pointer register. This is true if the function has variable sized allocas
/// or if frame pointer elimination is disabled.
bool X86FrameLowering::hasFP(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- const MachineModuleInfo &MMI = MF.getMMI();
-
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
TRI->needsStackRealignment(MF) ||
- MFI->hasVarSizedObjects() ||
- MFI->isFrameAddressTaken() || MFI->hasOpaqueSPAdjustment() ||
+ MFI.hasVarSizedObjects() ||
+ MFI.isFrameAddressTaken() || MFI.hasOpaqueSPAdjustment() ||
MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
- MMI.callsUnwindInit() || MMI.hasEHFunclets() || MMI.callsEHReturn() ||
- MFI->hasStackMap() || MFI->hasPatchPoint() ||
- MFI->hasCopyImplyingStackAdjustment());
+ MF.callsUnwindInit() || MF.hasEHFunclets() || MF.callsEHReturn() ||
+ MFI.hasStackMap() || MFI.hasPatchPoint() ||
+ MFI.hasCopyImplyingStackAdjustment());
}
static unsigned getSUBriOpcode(unsigned IsLP64, int64_t Imm) {
@@ -151,13 +149,15 @@ static unsigned findDeadCallerSavedReg(MachineBasicBlock &MBB,
bool Is64Bit) {
const MachineFunction *MF = MBB.getParent();
const Function *F = MF->getFunction();
- if (!F || MF->getMMI().callsEHReturn())
+ if (!F || MF->callsEHReturn())
return 0;
const TargetRegisterClass &AvailableRegs = *TRI->getGPRsForTailCall(*MF);
- unsigned Opc = MBBI->getOpcode();
- switch (Opc) {
+ if (MBBI == MBB.end())
+ return 0;
+
+ switch (MBBI->getOpcode()) {
default: return 0;
case TargetOpcode::PATCHABLE_RET:
case X86::RET:
@@ -373,6 +373,10 @@ int X86FrameLowering::mergeSPUpdates(MachineBasicBlock &MBB,
MachineBasicBlock::iterator PI = doMergeWithPrevious ? std::prev(MBBI) : MBBI;
MachineBasicBlock::iterator NI = doMergeWithPrevious ? nullptr
: std::next(MBBI);
+ PI = skipDebugInstructionsBackward(PI, MBB.begin());
+ if (NI != nullptr)
+ NI = skipDebugInstructionsForward(NI, MBB.end());
+
unsigned Opc = PI->getOpcode();
int Offset = 0;
@@ -416,7 +420,7 @@ void X86FrameLowering::BuildCFI(MachineBasicBlock &MBB,
const DebugLoc &DL,
const MCCFIInstruction &CFIInst) const {
MachineFunction &MF = *MBB.getParent();
- unsigned CFIIndex = MF.getMMI().addFrameInst(CFIInst);
+ unsigned CFIIndex = MF.addFrameInst(CFIInst);
BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
@@ -425,18 +429,18 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
const DebugLoc &DL) const {
MachineFunction &MF = *MBB.getParent();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
// Add callee saved registers to move list.
- const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
if (CSI.empty()) return;
// Calculate offsets.
for (std::vector<CalleeSavedInfo>::const_iterator
I = CSI.begin(), E = CSI.end(); I != E; ++I) {
- int64_t Offset = MFI->getObjectOffset(I->getFrameIdx());
+ int64_t Offset = MFI.getObjectOffset(I->getFrameIdx());
unsigned Reg = I->getReg();
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
@@ -445,20 +449,19 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(
}
}
-MachineInstr *X86FrameLowering::emitStackProbe(MachineFunction &MF,
- MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL,
- bool InProlog) const {
+void X86FrameLowering::emitStackProbe(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL, bool InProlog) const {
const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
if (STI.isTargetWindowsCoreCLR()) {
if (InProlog) {
- return emitStackProbeInlineStub(MF, MBB, MBBI, DL, true);
+ emitStackProbeInlineStub(MF, MBB, MBBI, DL, true);
} else {
- return emitStackProbeInline(MF, MBB, MBBI, DL, false);
+ emitStackProbeInline(MF, MBB, MBBI, DL, false);
}
} else {
- return emitStackProbeCall(MF, MBB, MBBI, DL, InProlog);
+ emitStackProbeCall(MF, MBB, MBBI, DL, InProlog);
}
}
@@ -479,17 +482,19 @@ void X86FrameLowering::inlineStackProbe(MachineFunction &MF,
assert(!ChkStkStub->isBundled() &&
"Not expecting bundled instructions here");
MachineBasicBlock::iterator MBBI = std::next(ChkStkStub->getIterator());
- assert(std::prev(MBBI).operator==(ChkStkStub) &&
- "MBBI expected after __chkstk_stub.");
+ assert(std::prev(MBBI) == ChkStkStub &&
+ "MBBI expected after __chkstk_stub.");
DebugLoc DL = PrologMBB.findDebugLoc(MBBI);
emitStackProbeInline(MF, PrologMBB, MBBI, DL, true);
ChkStkStub->eraseFromParent();
}
}
-MachineInstr *X86FrameLowering::emitStackProbeInline(
- MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool InProlog) const {
+void X86FrameLowering::emitStackProbeInline(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL,
+ bool InProlog) const {
const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
assert(STI.is64Bit() && "different expansion needed for 32 bit");
assert(STI.isTargetWindowsCoreCLR() && "custom expansion expects CoreCLR");
@@ -612,7 +617,7 @@ MachineInstr *X86FrameLowering::emitStackProbeInline(
// lowest touched page on the stack, not the point at which the OS
// will cause an overflow exception, so this is just an optimization
// to avoid unnecessarily touching pages that are below the current
- // SP but already commited to the stack by the OS.
+ // SP but already committed to the stack by the OS.
BuildMI(&MBB, DL, TII.get(X86::MOV64rm), LimitReg)
.addReg(0)
.addImm(1)
@@ -699,13 +704,13 @@ MachineInstr *X86FrameLowering::emitStackProbeInline(
}
// Possible TODO: physreg liveness for InProlog case.
-
- return &*ContinueMBBI;
}
-MachineInstr *X86FrameLowering::emitStackProbeCall(
- MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool InProlog) const {
+void X86FrameLowering::emitStackProbeCall(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL,
+ bool InProlog) const {
bool IsLargeCodeModel = MF.getTarget().getCodeModel() == CodeModel::Large;
unsigned CallOp;
@@ -763,11 +768,9 @@ MachineInstr *X86FrameLowering::emitStackProbeCall(
for (++ExpansionMBBI; ExpansionMBBI != MBBI; ++ExpansionMBBI)
ExpansionMBBI->setFlag(MachineInstr::FrameSetup);
}
-
- return &*MBBI;
}
-MachineInstr *X86FrameLowering::emitStackProbeInlineStub(
+void X86FrameLowering::emitStackProbeInlineStub(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool InProlog) const {
@@ -775,8 +778,6 @@ MachineInstr *X86FrameLowering::emitStackProbeInlineStub(
BuildMI(MBB, MBBI, DL, TII.get(X86::CALLpcrel32))
.addExternalSymbol("__chkstk_stub");
-
- return &*MBBI;
}
static unsigned calculateSetFPREG(uint64_t SPAdjust) {
@@ -793,11 +794,11 @@ static unsigned calculateSetFPREG(uint64_t SPAdjust) {
// have a call out. Otherwise just make sure we have some alignment - we'll
// go with the minimum SlotSize.
uint64_t X86FrameLowering::calculateMaxStackAlign(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- uint64_t MaxAlign = MFI->getMaxAlignment(); // Desired stack alignment.
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ uint64_t MaxAlign = MFI.getMaxAlignment(); // Desired stack alignment.
unsigned StackAlign = getStackAlignment();
if (MF.getFunction()->hasFnAttribute("stackrealign")) {
- if (MFI->hasCalls())
+ if (MFI.hasCalls())
MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign;
else if (MaxAlign < SlotSize)
MaxAlign = SlotSize;
@@ -909,18 +910,18 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
assert(&STI == &MF.getSubtarget<X86Subtarget>() &&
"MF used frame lowering for wrong subtarget");
MachineBasicBlock::iterator MBBI = MBB.begin();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const Function *Fn = MF.getFunction();
MachineModuleInfo &MMI = MF.getMMI();
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
uint64_t MaxAlign = calculateMaxStackAlign(MF); // Desired stack alignment.
- uint64_t StackSize = MFI->getStackSize(); // Number of bytes to allocate.
+ uint64_t StackSize = MFI.getStackSize(); // Number of bytes to allocate.
bool IsFunclet = MBB.isEHFuncletEntry();
EHPersonality Personality = EHPersonality::Unknown;
if (Fn->hasPersonalityFn())
Personality = classifyEHPersonality(Fn->getPersonalityFn());
bool FnHasClrFunclet =
- MMI.hasEHFunclets() && Personality == EHPersonality::CoreCLR;
+ MF.hasEHFunclets() && Personality == EHPersonality::CoreCLR;
bool IsClrFunclet = IsFunclet && FnHasClrFunclet;
bool HasFP = hasFP(MF);
bool IsWin64CC = STI.isCallingConvWin64(Fn->getCallingConv());
@@ -933,6 +934,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
STI.isTarget64BitILP32()
? getX86SubSuperRegister(FramePtr, 64) : FramePtr;
unsigned BasePtr = TRI->getBaseRegister();
+ bool HasWinCFI = false;
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
@@ -964,16 +966,16 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
// push and pop from the stack.
if (Is64Bit && !Fn->hasFnAttribute(Attribute::NoRedZone) &&
!TRI->needsStackRealignment(MF) &&
- !MFI->hasVarSizedObjects() && // No dynamic alloca.
- !MFI->adjustsStack() && // No calls.
- !IsWin64CC && // Win64 has no Red Zone
- !MFI->hasCopyImplyingStackAdjustment() && // Don't push and pop.
- !MF.shouldSplitStack()) { // Regular stack
+ !MFI.hasVarSizedObjects() && // No dynamic alloca.
+ !MFI.adjustsStack() && // No calls.
+ !IsWin64CC && // Win64 has no Red Zone
+ !MFI.hasCopyImplyingStackAdjustment() && // Don't push and pop.
+ !MF.shouldSplitStack()) { // Regular stack
uint64_t MinSize = X86FI->getCalleeSavedFrameSize();
if (HasFP) MinSize += SlotSize;
X86FI->setUsesRedZone(MinSize > 0 || StackSize > 0);
StackSize = std::max(MinSize, StackSize > 128 ? StackSize - 128 : 0);
- MFI->setStackSize(StackSize);
+ MFI.setStackSize(StackSize);
}
// Insert stack pointer adjustment for later moving of return addr. Only
@@ -1037,9 +1039,9 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
// guaranteed to be the last slot by processFunctionBeforeFrameFinalized.
// Update the frame offset adjustment.
if (!IsFunclet)
- MFI->setOffsetAdjustment(-NumBytes);
+ MFI.setOffsetAdjustment(-NumBytes);
else
- assert(MFI->getOffsetAdjustment() == -(int)NumBytes &&
+ assert(MFI.getOffsetAdjustment() == -(int)NumBytes &&
"should calculate same local variable offset for funclets");
// Save EBP/RBP into the appropriate stack slot.
@@ -1061,6 +1063,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
}
if (NeedsWinCFI) {
+ HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg))
.addImm(FramePtr)
.setMIFlag(MachineInstr::FrameSetup);
@@ -1122,6 +1125,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
}
if (NeedsWinCFI) {
+ HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_PushReg)).addImm(Reg).setMIFlag(
MachineInstr::FrameSetup);
}
@@ -1207,10 +1211,12 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
emitSPUpdate(MBB, MBBI, -(int64_t)NumBytes, /*InEpilogue=*/false);
}
- if (NeedsWinCFI && NumBytes)
+ if (NeedsWinCFI && NumBytes) {
+ HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_StackAlloc))
.addImm(NumBytes)
.setMIFlag(MachineInstr::FrameSetup);
+ }
int SEHFrameOffset = 0;
unsigned SPOrEstablisher;
@@ -1257,6 +1263,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
// If this is not a funclet, emit the CFI describing our frame pointer.
if (NeedsWinCFI && !IsFunclet) {
+ HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SetFrame))
.addImm(FramePtr)
.addImm(SEHFrameOffset)
@@ -1293,6 +1300,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
int Offset = getFrameIndexReference(MF, FI, IgnoredFrameReg);
Offset += SEHFrameOffset;
+ HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_SaveXMM))
.addImm(Reg)
.addImm(Offset)
@@ -1302,7 +1310,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
}
}
- if (NeedsWinCFI)
+ if (NeedsWinCFI && HasWinCFI)
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_EndPrologue))
.setMIFlag(MachineInstr::FrameSetup);
@@ -1394,13 +1402,16 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
if (Fn->getCallingConv() == CallingConv::X86_INTR)
BuildMI(MBB, MBBI, DL, TII.get(X86::CLD))
.setMIFlag(MachineInstr::FrameSetup);
+
+ // At this point we know if the function has WinCFI or not.
+ MF.setHasWinCFI(HasWinCFI);
}
bool X86FrameLowering::canUseLEAForSPInEpilogue(
const MachineFunction &MF) const {
- // We can't use LEA instructions for adjusting the stack pointer if this is a
- // leaf function in the Win64 ABI. Only ADD instructions may be used to
- // deallocate the stack.
+ // We can't use LEA instructions for adjusting the stack pointer if we don't
+ // have a frame pointer in the Win64 ABI. Only ADD instructions may be used
+ // to deallocate the stack.
// This means that we can use LEA for SP in two situations:
// 1. We *aren't* using the Win64 ABI which means we are free to use LEA.
// 2. We *have* a frame pointer which means we are permitted to use LEA.
@@ -1457,7 +1468,7 @@ X86FrameLowering::getWinEHFuncletFrameSize(const MachineFunction &MF) const {
UsedSize = getPSPSlotOffsetFromSP(MF) + SlotSize;
} else {
// Other funclets just need enough stack for outgoing call arguments.
- UsedSize = MF.getFrameInfo()->getMaxCallFrameSize();
+ UsedSize = MF.getFrameInfo().getMaxCallFrameSize();
}
// RBP is not included in the callee saved register block. After pushing RBP,
// everything is 16 byte aligned. Everything we allocate before an outgoing
@@ -1477,10 +1488,12 @@ static bool isTailCallOpcode(unsigned Opc) {
void X86FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
- unsigned RetOpcode = MBBI->getOpcode();
+ Optional<unsigned> RetOpcode;
+ if (MBBI != MBB.end())
+ RetOpcode = MBBI->getOpcode();
DebugLoc DL;
if (MBBI != MBB.end())
DL = MBBI->getDebugLoc();
@@ -1493,16 +1506,16 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
bool NeedsWinCFI =
IsWin64Prologue && MF.getFunction()->needsUnwindTableEntry();
- bool IsFunclet = isFuncletReturnInstr(*MBBI);
+ bool IsFunclet = MBBI == MBB.end() ? false : isFuncletReturnInstr(*MBBI);
MachineBasicBlock *TargetMBB = nullptr;
// Get the number of bytes to allocate from the FrameInfo.
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
uint64_t MaxAlign = calculateMaxStackAlign(MF);
unsigned CSSize = X86FI->getCalleeSavedFrameSize();
uint64_t NumBytes = 0;
- if (MBBI->getOpcode() == X86::CATCHRET) {
+ if (RetOpcode && *RetOpcode == X86::CATCHRET) {
// SEH shouldn't use catchret.
assert(!isAsynchronousEHPersonality(
classifyEHPersonality(MF.getFunction()->getPersonalityFn())) &&
@@ -1516,7 +1529,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
MachineFramePtr)
.setMIFlag(MachineInstr::FrameDestroy);
- } else if (MBBI->getOpcode() == X86::CLEANUPRET) {
+ } else if (RetOpcode && *RetOpcode == X86::CLEANUPRET) {
NumBytes = getWinEHFuncletFrameSize(MF);
assert(hasFP(MF) && "EH funclets without FP not yet implemented");
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
@@ -1541,19 +1554,22 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
}
uint64_t SEHStackAllocAmt = NumBytes;
+ MachineBasicBlock::iterator FirstCSPop = MBBI;
// Skip the callee-saved pop instructions.
while (MBBI != MBB.begin()) {
MachineBasicBlock::iterator PI = std::prev(MBBI);
unsigned Opc = PI->getOpcode();
- if ((Opc != X86::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
- (Opc != X86::POP64r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
- Opc != X86::DBG_VALUE && !PI->isTerminator())
- break;
+ if (Opc != X86::DBG_VALUE && !PI->isTerminator()) {
+ if ((Opc != X86::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
+ (Opc != X86::POP64r || !PI->getFlag(MachineInstr::FrameDestroy)))
+ break;
+ FirstCSPop = PI;
+ }
--MBBI;
}
- MachineBasicBlock::iterator FirstCSPop = MBBI;
+ MBBI = FirstCSPop;
if (TargetMBB) {
// Fill EAX/RAX with the address of the target block.
@@ -1581,14 +1597,14 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
// If there is an ADD32ri or SUB32ri of ESP immediately before this
// instruction, merge the two instructions.
- if (NumBytes || MFI->hasVarSizedObjects())
+ if (NumBytes || MFI.hasVarSizedObjects())
NumBytes += mergeSPUpdates(MBB, MBBI, true);
// If dynamic alloca is used, then reset esp to point to the last callee-saved
// slot before popping them off! Same applies for the case, when stack was
// realigned. Don't do this if this was a funclet epilogue, since the funclets
// will not do realignment or dynamic stack allocation.
- if ((TRI->needsStackRealignment(MF) || MFI->hasVarSizedObjects()) &&
+ if ((TRI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) &&
!IsFunclet) {
if (TRI->needsStackRealignment(MF))
MBBI = FirstCSPop;
@@ -1626,10 +1642,10 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
// into the epilogue. To cope with that, we insert an epilogue marker here,
// then replace it with a 'nop' if it ends up immediately after a CALL in the
// final emitted code.
- if (NeedsWinCFI)
+ if (NeedsWinCFI && MF.hasWinCFI())
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_Epilogue));
- if (!isTailCallOpcode(RetOpcode)) {
+ if (!RetOpcode || !isTailCallOpcode(*RetOpcode)) {
// Add the return addr area delta back since we are not tail calling.
int Offset = -1 * X86FI->getTCReturnAddrDelta();
assert(Offset >= 0 && "TCDelta should never be positive");
@@ -1649,7 +1665,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
// (probably?) it should be moved into here.
int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
unsigned &FrameReg) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// We can't calculate offset from frame pointer if the stack is realigned,
// so enforce usage of stack/base pointer. The base pointer is used when we
@@ -1665,16 +1681,16 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
// object.
// We need to factor in additional offsets applied during the prologue to the
// frame, base, and stack pointer depending on which is used.
- int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea();
+ int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea();
const X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
unsigned CSSize = X86FI->getCalleeSavedFrameSize();
- uint64_t StackSize = MFI->getStackSize();
+ uint64_t StackSize = MFI.getStackSize();
bool HasFP = hasFP(MF);
bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
int64_t FPDelta = 0;
if (IsWin64Prologue) {
- assert(!MFI->hasCalls() || (StackSize % 16) == 8);
+ assert(!MFI.hasCalls() || (StackSize % 16) == 8);
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
@@ -1692,7 +1708,7 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
// restricted Win64 prologue.
// Add FPDelta to all offsets below that go through the frame pointer.
FPDelta = FrameSize - SEHFrameOffset;
- assert((!MFI->hasCalls() || (FPDelta % 16) == 0) &&
+ assert((!MFI.hasCalls() || (FPDelta % 16) == 0) &&
"FPDelta isn't aligned per the Win64 ABI!");
}
@@ -1703,7 +1719,7 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
// Skip the saved EBP.
return Offset + SlotSize + FPDelta;
} else {
- assert((-(Offset + StackSize)) % MFI->getObjectAlignment(FI) == 0);
+ assert((-(Offset + StackSize)) % MFI.getObjectAlignment(FI) == 0);
return Offset + StackSize;
}
} else if (TRI->needsStackRealignment(MF)) {
@@ -1711,7 +1727,7 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
// Skip the saved EBP.
return Offset + SlotSize + FPDelta;
} else {
- assert((-(Offset + StackSize)) % MFI->getObjectAlignment(FI) == 0);
+ assert((-(Offset + StackSize)) % MFI.getObjectAlignment(FI) == 0);
return Offset + StackSize;
}
// FIXME: Support tail calls
@@ -1736,9 +1752,9 @@ X86FrameLowering::getFrameIndexReferencePreferSP(const MachineFunction &MF,
int FI, unsigned &FrameReg,
bool IgnoreSPUpdates) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Does not include any dynamic realign.
- const uint64_t StackSize = MFI->getStackSize();
+ const uint64_t StackSize = MFI.getStackSize();
// LLVM arranges the stack as follows:
// ...
// ARG2
@@ -1772,7 +1788,7 @@ X86FrameLowering::getFrameIndexReferencePreferSP(const MachineFunction &MF,
// answer we give is relative to the SP after the prologue, and not the
// SP in the middle of the function.
- if (MFI->isFixedObjectIndex(FI) && TRI->needsStackRealignment(MF) &&
+ if (MFI.isFixedObjectIndex(FI) && TRI->needsStackRealignment(MF) &&
!STI.isTargetWin64())
return getFrameIndexReference(MF, FI, FrameReg);
@@ -1804,7 +1820,7 @@ X86FrameLowering::getFrameIndexReferencePreferSP(const MachineFunction &MF,
//
// A is the incoming stack pointer.
// (B - A) is the local area offset (-8 for x86-64) [1]
- // (C - A) is the Offset returned by MFI->getObjectOffset for Obj0 [2]
+ // (C - A) is the Offset returned by MFI.getObjectOffset for Obj0 [2]
//
// |(E - B)| is the StackSize (absolute value, positive). For a
// stack that grown down, this works out to be (B - E). [3]
@@ -1817,7 +1833,7 @@ X86FrameLowering::getFrameIndexReferencePreferSP(const MachineFunction &MF,
//
// Get the Offset from the StackPointer
- int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea();
+ int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea();
return Offset + StackSize;
}
@@ -1825,7 +1841,7 @@ X86FrameLowering::getFrameIndexReferencePreferSP(const MachineFunction &MF,
bool X86FrameLowering::assignCalleeSavedSpillSlots(
MachineFunction &MF, const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
unsigned CalleeSavedFrameSize = 0;
@@ -1834,7 +1850,7 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
if (hasFP(MF)) {
// emitPrologue always spills frame register the first thing.
SpillSlotOffset -= SlotSize;
- MFI->CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
// Since emitPrologue and emitEpilogue will handle spilling and restoring of
// the frame register, we can delete it from CSI list and not have to worry
@@ -1858,7 +1874,7 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
SpillSlotOffset -= SlotSize;
CalleeSavedFrameSize += SlotSize;
- int SlotIndex = MFI->CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
+ int SlotIndex = MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
CSI[i - 1].setFrameIdx(SlotIndex);
}
@@ -1876,9 +1892,9 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
// spill into slot
SpillSlotOffset -= RC->getSize();
int SlotIndex =
- MFI->CreateFixedSpillStackObject(RC->getSize(), SpillSlotOffset);
+ MFI.CreateFixedSpillStackObject(RC->getSize(), SpillSlotOffset);
CSI[i - 1].setFrameIdx(SlotIndex);
- MFI->ensureMaxAlignment(RC->getAlignment());
+ MFI.ensureMaxAlignment(RC->getAlignment());
}
return true;
@@ -1957,7 +1973,7 @@ bool X86FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
if (CSI.empty())
return false;
- if (isFuncletReturnInstr(*MI) && STI.isOSWindows()) {
+ if (MI != MBB.end() && isFuncletReturnInstr(*MI) && STI.isOSWindows()) {
// Don't restore CSRs in 32-bit EH funclets. Matches
// spillCalleeSavedRegisters.
if (STI.is32Bit())
@@ -2005,7 +2021,7 @@ void X86FrameLowering::determineCalleeSaves(MachineFunction &MF,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
int64_t TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta();
@@ -2020,7 +2036,7 @@ void X86FrameLowering::determineCalleeSaves(MachineFunction &MF,
// ...
// }
// [EBP]
- MFI->CreateFixedObject(-TailCallReturnAddrDelta,
+ MFI.CreateFixedObject(-TailCallReturnAddrDelta,
TailCallReturnAddrDelta - SlotSize, true);
}
@@ -2029,8 +2045,8 @@ void X86FrameLowering::determineCalleeSaves(MachineFunction &MF,
SavedRegs.set(TRI->getBaseRegister());
// Allocate a spill slot for EBP if we have a base pointer and EH funclets.
- if (MF.getMMI().hasEHFunclets()) {
- int FI = MFI->CreateSpillStackObject(SlotSize, SlotSize);
+ if (MF.hasEHFunclets()) {
+ int FI = MFI.CreateSpillStackObject(SlotSize, SlotSize);
X86FI->setHasSEHFramePtrSave(true);
X86FI->setSEHFramePtrSaveIndex(FI);
}
@@ -2091,7 +2107,7 @@ static const uint64_t kSplitStackAvailable = 256;
void X86FrameLowering::adjustForSegmentedStacks(
MachineFunction &MF, MachineBasicBlock &PrologueMBB) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
uint64_t StackSize;
unsigned TlsReg, TlsOffset;
DebugLoc DL;
@@ -2114,7 +2130,7 @@ void X86FrameLowering::adjustForSegmentedStacks(
// Eventually StackSize will be calculated by a link-time pass; which will
// also decide whether checking code needs to be injected into this particular
// prologue.
- StackSize = MFI->getStackSize();
+ StackSize = MFI.getStackSize();
// Do not generate a prologue for functions with a stack of size zero
if (StackSize == 0)
@@ -2360,7 +2376,7 @@ static unsigned getHiPELiteral(
/// if( temp0 < SP_LIMIT(P) ) goto IncStack else goto OldStart
void X86FrameLowering::adjustForHiPEPrologue(
MachineFunction &MF, MachineBasicBlock &PrologueMBB) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
DebugLoc DL;
// To support shrink-wrapping we would need to insert the new blocks
@@ -2380,7 +2396,7 @@ void X86FrameLowering::adjustForHiPEPrologue(
const unsigned Guaranteed = HipeLeafWords * SlotSize;
unsigned CallerStkArity = MF.getFunction()->arg_size() > CCRegisteredArgs ?
MF.getFunction()->arg_size() - CCRegisteredArgs : 0;
- unsigned MaxStack = MFI->getStackSize() + CallerStkArity*SlotSize + SlotSize;
+ unsigned MaxStack = MFI.getStackSize() + CallerStkArity*SlotSize + SlotSize;
assert(STI.isTargetLinux() &&
"HiPE prologue is only supported on Linux operating systems.");
@@ -2392,7 +2408,7 @@ void X86FrameLowering::adjustForHiPEPrologue(
// b) outgoing on-stack parameter areas, and
// c) the minimum stack space this function needs to make available for the
// functions it calls (a tunable ABI property).
- if (MFI->hasCalls()) {
+ if (MFI.hasCalls()) {
unsigned MoreStackForCalls = 0;
for (auto &MBB : MF) {
@@ -2574,6 +2590,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
uint64_t Amount = !reserveCallFrame ? I->getOperand(0).getImm() : 0;
uint64_t InternalAmt = (isDestroy || Amount) ? I->getOperand(1).getImm() : 0;
I = MBB.erase(I);
+ auto InsertPos = skipDebugInstructionsForward(I, MBB.end());
if (!reserveCallFrame) {
// If the stack pointer can be changed after prologue, turn the
@@ -2599,12 +2616,11 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
// GNU_ARGS_SIZE.
// TODO: We don't need to reset this between subsequent functions,
// if it didn't change.
- bool HasDwarfEHHandlers = !WindowsCFI &&
- !MF.getMMI().getLandingPads().empty();
+ bool HasDwarfEHHandlers = !WindowsCFI && !MF.getLandingPads().empty();
if (HasDwarfEHHandlers && !isDestroy &&
MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences())
- BuildCFI(MBB, I, DL,
+ BuildCFI(MBB, InsertPos, DL,
MCCFIInstruction::createGnuArgsSize(nullptr, Amount));
if (Amount == 0)
@@ -2618,7 +2634,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
// If this is a callee-pop calling convention, emit a CFA adjust for
// the amount the callee popped.
if (isDestroy && InternalAmt && DwarfCFI && !hasFP(MF))
- BuildCFI(MBB, I, DL,
+ BuildCFI(MBB, InsertPos, DL,
MCCFIInstruction::createAdjustCfaOffset(nullptr, -InternalAmt));
// Add Amount to SP to destroy a frame, or subtract to setup.
@@ -2629,13 +2645,13 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
// Merge with any previous or following adjustment instruction. Note: the
// instructions merged with here do not have CFI, so their stack
// adjustments do not feed into CfaAdjustment.
- StackAdjustment += mergeSPUpdates(MBB, I, true);
- StackAdjustment += mergeSPUpdates(MBB, I, false);
+ StackAdjustment += mergeSPUpdates(MBB, InsertPos, true);
+ StackAdjustment += mergeSPUpdates(MBB, InsertPos, false);
if (StackAdjustment) {
if (!(Fn->optForMinSize() &&
- adjustStackWithPops(MBB, I, DL, StackAdjustment)))
- BuildStackAdjustment(MBB, I, DL, StackAdjustment,
+ adjustStackWithPops(MBB, InsertPos, DL, StackAdjustment)))
+ BuildStackAdjustment(MBB, InsertPos, DL, StackAdjustment,
/*InEpilogue=*/false);
}
}
@@ -2651,8 +2667,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
// TODO: When not using precise CFA, we also need to adjust for the
// InternalAmt here.
if (CfaAdjustment) {
- BuildCFI(MBB, I, DL, MCCFIInstruction::createAdjustCfaOffset(
- nullptr, CfaAdjustment));
+ BuildCFI(MBB, InsertPos, DL,
+ MCCFIInstruction::createAdjustCfaOffset(nullptr,
+ CfaAdjustment));
}
}
@@ -2728,12 +2745,12 @@ MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHStackPointers(
unsigned BasePtr = TRI->getBaseRegister();
WinEHFuncInfo &FuncInfo = *MF.getWinEHFuncInfo();
X86MachineFunctionInfo *X86FI = MF.getInfo<X86MachineFunctionInfo>();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
// FIXME: Don't set FrameSetup flag in catchret case.
int FI = FuncInfo.EHRegNodeFrameIndex;
- int EHRegSize = MFI->getObjectSize(FI);
+ int EHRegSize = MFI.getObjectSize(FI);
if (RestoreSP) {
// MOV32rm -EHRegSize(%ebp), %esp
@@ -2850,7 +2867,7 @@ struct X86FrameSortingComparator {
// of uses and size of object in order to minimize code size.
void X86FrameLowering::orderFrameObjects(
const MachineFunction &MF, SmallVectorImpl<int> &ObjectsToAllocate) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
// Don't waste time if there's nothing to do.
if (ObjectsToAllocate.empty())
@@ -2861,16 +2878,16 @@ void X86FrameLowering::orderFrameObjects(
// it easier to index into when we're counting "uses" down below.
// We want to be able to easily/cheaply access an object by simply
// indexing into it, instead of having to search for it every time.
- std::vector<X86FrameSortingObject> SortingObjects(MFI->getObjectIndexEnd());
+ std::vector<X86FrameSortingObject> SortingObjects(MFI.getObjectIndexEnd());
// Walk the objects we care about and mark them as such in our working
// struct.
for (auto &Obj : ObjectsToAllocate) {
SortingObjects[Obj].IsValid = true;
SortingObjects[Obj].ObjectIndex = Obj;
- SortingObjects[Obj].ObjectAlignment = MFI->getObjectAlignment(Obj);
+ SortingObjects[Obj].ObjectAlignment = MFI.getObjectAlignment(Obj);
// Set the size.
- int ObjectSize = MFI->getObjectSize(Obj);
+ int ObjectSize = MFI.getObjectSize(Obj);
if (ObjectSize == 0)
// Variable size. Just use 4.
SortingObjects[Obj].ObjectSize = 4;
@@ -2890,7 +2907,7 @@ void X86FrameLowering::orderFrameObjects(
int Index = MO.getIndex();
// Check to see if it falls within our range, and is tagged
// to require ordering.
- if (Index >= 0 && Index < MFI->getObjectIndexEnd() &&
+ if (Index >= 0 && Index < MFI.getObjectIndexEnd() &&
SortingObjects[Index].IsValid)
SortingObjects[Index].ObjectNumUses++;
}
@@ -2938,7 +2955,7 @@ void X86FrameLowering::processFunctionBeforeFrameFinalized(
// If this function isn't doing Win64-style C++ EH, we don't need to do
// anything.
const Function *Fn = MF.getFunction();
- if (!STI.is64Bit() || !MF.getMMI().hasEHFunclets() ||
+ if (!STI.is64Bit() || !MF.hasEHFunclets() ||
classifyEHPersonality(Fn->getPersonalityFn()) != EHPersonality::MSVC_CXX)
return;
@@ -2947,21 +2964,21 @@ void X86FrameLowering::processFunctionBeforeFrameFinalized(
// object, so that we can allocate a slot immediately following it. If there
// were no fixed objects, use offset -SlotSize, which is immediately after the
// return address. Fixed objects have negative frame indices.
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
WinEHFuncInfo &EHInfo = *MF.getWinEHFuncInfo();
int64_t MinFixedObjOffset = -SlotSize;
- for (int I = MFI->getObjectIndexBegin(); I < 0; ++I)
- MinFixedObjOffset = std::min(MinFixedObjOffset, MFI->getObjectOffset(I));
+ for (int I = MFI.getObjectIndexBegin(); I < 0; ++I)
+ MinFixedObjOffset = std::min(MinFixedObjOffset, MFI.getObjectOffset(I));
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
for (WinEHHandlerType &H : TBME.HandlerArray) {
int FrameIndex = H.CatchObj.FrameIndex;
if (FrameIndex != INT_MAX) {
// Ensure alignment.
- unsigned Align = MFI->getObjectAlignment(FrameIndex);
+ unsigned Align = MFI.getObjectAlignment(FrameIndex);
MinFixedObjOffset -= std::abs(MinFixedObjOffset) % Align;
- MinFixedObjOffset -= MFI->getObjectSize(FrameIndex);
- MFI->setObjectOffset(FrameIndex, MinFixedObjOffset);
+ MinFixedObjOffset -= MFI.getObjectSize(FrameIndex);
+ MFI.setObjectOffset(FrameIndex, MinFixedObjOffset);
}
}
}
@@ -2970,7 +2987,7 @@ void X86FrameLowering::processFunctionBeforeFrameFinalized(
MinFixedObjOffset -= std::abs(MinFixedObjOffset) % 8;
int64_t UnwindHelpOffset = MinFixedObjOffset - SlotSize;
int UnwindHelpFI =
- MFI->CreateFixedObject(SlotSize, UnwindHelpOffset, /*Immutable=*/false);
+ MFI.CreateFixedObject(SlotSize, UnwindHelpOffset, /*Immutable=*/false);
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
// Store -2 into UnwindHelp on function entry. We have to scan forwards past
diff --git a/contrib/llvm/lib/Target/X86/X86FrameLowering.h b/contrib/llvm/lib/Target/X86/X86FrameLowering.h
index 4a01014..e1b04d6 100644
--- a/contrib/llvm/lib/Target/X86/X86FrameLowering.h
+++ b/contrib/llvm/lib/Target/X86/X86FrameLowering.h
@@ -49,11 +49,10 @@ public:
/// Emit target stack probe code. This is required for all
/// large stack allocations on Windows. The caller is required to materialize
- /// the number of bytes to probe in RAX/EAX. Returns instruction just
- /// after the expansion.
- MachineInstr *emitStackProbe(MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL, bool InProlog) const;
+ /// the number of bytes to probe in RAX/EAX.
+ void emitStackProbe(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
+ bool InProlog) const;
/// Replace a StackProbe inline-stub with the actual probe code inline.
void inlineStackProbe(MachineFunction &MF,
@@ -179,22 +178,19 @@ private:
uint64_t calculateMaxStackAlign(const MachineFunction &MF) const;
/// Emit target stack probe as a call to a helper function
- MachineInstr *emitStackProbeCall(MachineFunction &MF, MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL, bool InProlog) const;
+ void emitStackProbeCall(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
+ bool InProlog) const;
/// Emit target stack probe as an inline sequence.
- MachineInstr *emitStackProbeInline(MachineFunction &MF,
- MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL, bool InProlog) const;
+ void emitStackProbeInline(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL, bool InProlog) const;
/// Emit a stub to later inline the target stack probe.
- MachineInstr *emitStackProbeInlineStub(MachineFunction &MF,
- MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- const DebugLoc &DL,
- bool InProlog) const;
+ void emitStackProbeInlineStub(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ const DebugLoc &DL, bool InProlog) const;
/// Aligns the stack pointer by ANDing it with -MaxAlign.
void BuildStackAlignAND(MachineBasicBlock &MBB,
diff --git a/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 7d53b3d..8ab4c06 100644
--- a/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -24,6 +24,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
@@ -165,7 +166,7 @@ namespace {
: SelectionDAGISel(tm, OptLevel), OptForSize(false),
OptForMinSize(false) {}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "X86 DAG->DAG Instruction Selection";
}
@@ -182,16 +183,6 @@ namespace {
void PreprocessISelDAG() override;
- inline bool immSext8(SDNode *N) const {
- return isInt<8>(cast<ConstantSDNode>(N)->getSExtValue());
- }
-
- // True if the 64-bit immediate fits in a 32-bit sign-extended field.
- inline bool i64immSExt32(SDNode *N) const {
- uint64_t v = cast<ConstantSDNode>(N)->getZExtValue();
- return (int64_t)v == (int32_t)v;
- }
-
// Include the pieces autogenerated from the target description.
#include "X86GenDAGISel.inc"
@@ -228,6 +219,7 @@ namespace {
SDValue &Index, SDValue &Disp,
SDValue &Segment,
SDValue &NodeWithChain);
+ bool selectRelocImm(SDValue N, SDValue &Op);
bool tryFoldLoad(SDNode *P, SDValue N,
SDValue &Base, SDValue &Scale,
@@ -1234,7 +1226,7 @@ bool X86DAGToDAGISel::matchAddressRecursively(SDValue N, X86ISelAddressMode &AM,
case ISD::UMUL_LOHI:
// A mul_lohi where we need the low part can be folded as a plain multiply.
if (N.getResNo() != 0) break;
- // FALL THROUGH
+ LLVM_FALLTHROUGH;
case ISD::MUL:
case X86ISD::MUL_IMM:
// X*[3,5,9] -> X+X*[2,4,8]
@@ -1435,7 +1427,7 @@ bool X86DAGToDAGISel::selectVectorAddr(SDNode *Parent, SDValue N, SDValue &Base,
SDLoc DL(N);
Base = Mgs->getBasePtr();
Index = Mgs->getIndex();
- unsigned ScalarSize = Mgs->getValue().getValueType().getScalarSizeInBits();
+ unsigned ScalarSize = Mgs->getValue().getScalarValueSizeInBits();
Scale = getI8Imm(ScalarSize/8, DL);
// If Base is 0, the whole address is in index and the Scale is 1
@@ -1512,16 +1504,39 @@ bool X86DAGToDAGISel::selectScalarSSELoad(SDNode *Root,
SDValue &Scale, SDValue &Index,
SDValue &Disp, SDValue &Segment,
SDValue &PatternNodeWithChain) {
- if (N.getOpcode() == ISD::SCALAR_TO_VECTOR) {
+ // We can allow a full vector load here since narrowing a load is ok.
+ if (ISD::isNON_EXTLoad(N.getNode())) {
+ PatternNodeWithChain = N;
+ if (IsProfitableToFold(PatternNodeWithChain, N.getNode(), Root) &&
+ IsLegalToFold(PatternNodeWithChain, *N->use_begin(), Root, OptLevel)) {
+ LoadSDNode *LD = cast<LoadSDNode>(PatternNodeWithChain);
+ return selectAddr(LD, LD->getBasePtr(), Base, Scale, Index, Disp,
+ Segment);
+ }
+ }
+
+ // We can also match the special zero extended load opcode.
+ if (N.getOpcode() == X86ISD::VZEXT_LOAD) {
+ PatternNodeWithChain = N;
+ if (IsProfitableToFold(PatternNodeWithChain, N.getNode(), Root) &&
+ IsLegalToFold(PatternNodeWithChain, *N->use_begin(), Root, OptLevel)) {
+ auto *MI = cast<MemIntrinsicSDNode>(PatternNodeWithChain);
+ return selectAddr(MI, MI->getBasePtr(), Base, Scale, Index, Disp,
+ Segment);
+ }
+ }
+
+ // Need to make sure that the SCALAR_TO_VECTOR and load are both only used
+ // once. Otherwise the load might get duplicated and the chain output of the
+ // duplicate load will not be observed by all dependencies.
+ if (N.getOpcode() == ISD::SCALAR_TO_VECTOR && N.getNode()->hasOneUse()) {
PatternNodeWithChain = N.getOperand(0);
if (ISD::isNON_EXTLoad(PatternNodeWithChain.getNode()) &&
- PatternNodeWithChain.hasOneUse() &&
- IsProfitableToFold(N.getOperand(0), N.getNode(), Root) &&
- IsLegalToFold(N.getOperand(0), N.getNode(), Root, OptLevel)) {
+ IsProfitableToFold(PatternNodeWithChain, N.getNode(), Root) &&
+ IsLegalToFold(PatternNodeWithChain, N.getNode(), Root, OptLevel)) {
LoadSDNode *LD = cast<LoadSDNode>(PatternNodeWithChain);
- if (!selectAddr(LD, LD->getBasePtr(), Base, Scale, Index, Disp, Segment))
- return false;
- return true;
+ return selectAddr(LD, LD->getBasePtr(), Base, Scale, Index, Disp,
+ Segment);
}
}
@@ -1530,18 +1545,18 @@ bool X86DAGToDAGISel::selectScalarSSELoad(SDNode *Root,
if (N.getOpcode() == X86ISD::VZEXT_MOVL && N.getNode()->hasOneUse() &&
// Check to see if the top elements are all zeros (or bitcast of zeros).
N.getOperand(0).getOpcode() == ISD::SCALAR_TO_VECTOR &&
- N.getOperand(0).getNode()->hasOneUse() &&
- ISD::isNON_EXTLoad(N.getOperand(0).getOperand(0).getNode()) &&
- N.getOperand(0).getOperand(0).hasOneUse() &&
- IsProfitableToFold(N.getOperand(0), N.getNode(), Root) &&
- IsLegalToFold(N.getOperand(0), N.getNode(), Root, OptLevel)) {
- // Okay, this is a zero extending load. Fold it.
- LoadSDNode *LD = cast<LoadSDNode>(N.getOperand(0).getOperand(0));
- if (!selectAddr(LD, LD->getBasePtr(), Base, Scale, Index, Disp, Segment))
- return false;
- PatternNodeWithChain = SDValue(LD, 0);
- return true;
+ N.getOperand(0).getNode()->hasOneUse()) {
+ PatternNodeWithChain = N.getOperand(0).getOperand(0);
+ if (ISD::isNON_EXTLoad(PatternNodeWithChain.getNode()) &&
+ IsProfitableToFold(PatternNodeWithChain, N.getNode(), Root) &&
+ IsLegalToFold(PatternNodeWithChain, N.getNode(), Root, OptLevel)) {
+ // Okay, this is a zero extending load. Fold it.
+ LoadSDNode *LD = cast<LoadSDNode>(PatternNodeWithChain);
+ return selectAddr(LD, LD->getBasePtr(), Base, Scale, Index, Disp,
+ Segment);
+ }
}
+
return false;
}
@@ -1563,16 +1578,21 @@ bool X86DAGToDAGISel::selectMOV64Imm32(SDValue N, SDValue &Imm) {
"Unexpected node type for MOV32ri64");
N = N.getOperand(0);
- if (N->getOpcode() != ISD::TargetConstantPool &&
- N->getOpcode() != ISD::TargetJumpTable &&
- N->getOpcode() != ISD::TargetGlobalAddress &&
- N->getOpcode() != ISD::TargetExternalSymbol &&
- N->getOpcode() != ISD::MCSymbol &&
- N->getOpcode() != ISD::TargetBlockAddress)
+ // At least GNU as does not accept 'movl' for TPOFF relocations.
+ // FIXME: We could use 'movl' when we know we are targeting MC.
+ if (N->getOpcode() == ISD::TargetGlobalTLSAddress)
return false;
Imm = N;
- return TM.getCodeModel() == CodeModel::Small;
+ if (N->getOpcode() != ISD::TargetGlobalAddress)
+ return TM.getCodeModel() == CodeModel::Small;
+
+ Optional<ConstantRange> CR =
+ cast<GlobalAddressSDNode>(N)->getGlobal()->getAbsoluteSymbolRange();
+ if (!CR)
+ return TM.getCodeModel() == CodeModel::Small;
+
+ return CR->getUnsignedMax().ult(1ull << 32);
}
bool X86DAGToDAGISel::selectLEA64_32Addr(SDValue N, SDValue &Base,
@@ -1704,6 +1724,48 @@ bool X86DAGToDAGISel::selectTLSADDRAddr(SDValue N, SDValue &Base,
return true;
}
+bool X86DAGToDAGISel::selectRelocImm(SDValue N, SDValue &Op) {
+ if (auto *CN = dyn_cast<ConstantSDNode>(N)) {
+ Op = CurDAG->getTargetConstant(CN->getAPIntValue(), SDLoc(CN),
+ N.getValueType());
+ return true;
+ }
+
+ // Keep track of the original value type and whether this value was
+ // truncated. If we see a truncation from pointer type to VT that truncates
+ // bits that are known to be zero, we can use a narrow reference.
+ EVT VT = N.getValueType();
+ bool WasTruncated = false;
+ if (N.getOpcode() == ISD::TRUNCATE) {
+ WasTruncated = true;
+ N = N.getOperand(0);
+ }
+
+ if (N.getOpcode() != X86ISD::Wrapper)
+ return false;
+
+ // We can only use non-GlobalValues as immediates if they were not truncated,
+ // as we do not have any range information. If we have a GlobalValue and the
+ // address was not truncated, we can select it as an operand directly.
+ unsigned Opc = N.getOperand(0)->getOpcode();
+ if (Opc != ISD::TargetGlobalAddress || !WasTruncated) {
+ Op = N.getOperand(0);
+ // We can only select the operand directly if we didn't have to look past a
+ // truncate.
+ return !WasTruncated;
+ }
+
+ // Check that the global's range fits into VT.
+ auto *GA = cast<GlobalAddressSDNode>(N.getOperand(0));
+ Optional<ConstantRange> CR = GA->getGlobal()->getAbsoluteSymbolRange();
+ if (!CR || CR->getUnsignedMax().uge(1ull << VT.getSizeInBits()))
+ return false;
+
+ // Okay, we can use a narrow reference.
+ Op = CurDAG->getTargetGlobalAddress(GA->getGlobal(), SDLoc(N), VT,
+ GA->getOffset(), GA->getTargetFlags());
+ return true;
+}
bool X86DAGToDAGISel::tryFoldLoad(SDNode *P, SDValue N,
SDValue &Base, SDValue &Scale,
@@ -2700,7 +2762,7 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
case InlineAsm::Constraint_i:
// FIXME: It seems strange that 'i' is needed here since it's supposed to
// be an immediate and not a memory constraint.
- // Fallthrough.
+ LLVM_FALLTHROUGH;
case InlineAsm::Constraint_o: // offsetable ??
case InlineAsm::Constraint_v: // not offsetable ??
case InlineAsm::Constraint_m: // memory
diff --git a/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp b/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp
index f499e56..08fe2ba 100644
--- a/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -17,6 +17,7 @@
#include "X86CallingConv.h"
#include "X86FrameLowering.h"
#include "X86InstrBuilder.h"
+#include "X86IntrinsicsInfo.h"
#include "X86MachineFunctionInfo.h"
#include "X86ShuffleDecodeConstantPool.h"
#include "X86TargetMachine.h"
@@ -53,10 +54,10 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetOptions.h"
-#include "X86IntrinsicsInfo.h"
+#include <algorithm>
#include <bitset>
-#include <numeric>
#include <cctype>
+#include <numeric>
using namespace llvm;
#define DEBUG_TYPE "x86-isel"
@@ -96,15 +97,16 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
setStackPointerRegisterToSaveRestore(RegInfo->getStackRegister());
- // Bypass expensive divides on Atom when compiling with O2.
+ // Bypass expensive divides and use cheaper ones.
if (TM.getOptLevel() >= CodeGenOpt::Default) {
if (Subtarget.hasSlowDivide32())
addBypassSlowDiv(32, 8);
if (Subtarget.hasSlowDivide64() && Subtarget.is64Bit())
- addBypassSlowDiv(64, 16);
+ addBypassSlowDiv(64, 32);
}
- if (Subtarget.isTargetKnownWindowsMSVC()) {
+ if (Subtarget.isTargetKnownWindowsMSVC() ||
+ Subtarget.isTargetWindowsItanium()) {
// Setup Windows compiler runtime calls.
setLibcallName(RTLIB::SDIV_I64, "_alldiv");
setLibcallName(RTLIB::UDIV_I64, "_aulldiv");
@@ -286,7 +288,11 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::UDIV, VT, Expand);
setOperationAction(ISD::SREM, VT, Expand);
setOperationAction(ISD::UREM, VT, Expand);
+ }
+ for (auto VT : { MVT::i8, MVT::i16, MVT::i32, MVT::i64 }) {
+ if (VT == MVT::i64 && !Subtarget.is64Bit())
+ continue;
// Add/Sub overflow ops with MVT::Glues are lowered to EFLAGS dependences.
setOperationAction(ISD::ADDC, VT, Custom);
setOperationAction(ISD::ADDE, VT, Custom);
@@ -349,7 +355,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
// Special handling for half-precision floating point conversions.
// If we don't have F16C support, then lower half float conversions
// into library calls.
- if (Subtarget.useSoftFloat() || !Subtarget.hasF16C()) {
+ if (Subtarget.useSoftFloat() ||
+ (!Subtarget.hasF16C() && !Subtarget.hasAVX512())) {
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
}
@@ -484,8 +491,10 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
if (!Subtarget.useSoftFloat() && X86ScalarSSEf64) {
// f32 and f64 use SSE.
// Set up the FP register classes.
- addRegisterClass(MVT::f32, &X86::FR32RegClass);
- addRegisterClass(MVT::f64, &X86::FR64RegClass);
+ addRegisterClass(MVT::f32, Subtarget.hasAVX512() ? &X86::FR32XRegClass
+ : &X86::FR32RegClass);
+ addRegisterClass(MVT::f64, Subtarget.hasAVX512() ? &X86::FR64XRegClass
+ : &X86::FR64RegClass);
for (auto VT : { MVT::f32, MVT::f64 }) {
// Use ANDPD to simulate FABS.
@@ -514,7 +523,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
} else if (UseX87 && X86ScalarSSEf32) {
// Use SSE for f32, x87 for f64.
// Set up the FP register classes.
- addRegisterClass(MVT::f32, &X86::FR32RegClass);
+ addRegisterClass(MVT::f32, Subtarget.hasAVX512() ? &X86::FR32XRegClass
+ : &X86::FR32RegClass);
addRegisterClass(MVT::f64, &X86::RFP64RegClass);
// Use ANDPS to simulate FABS.
@@ -590,14 +600,14 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::UNDEF, MVT::f80, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f80, Expand);
{
- APFloat TmpFlt = APFloat::getZero(APFloat::x87DoubleExtended);
+ APFloat TmpFlt = APFloat::getZero(APFloat::x87DoubleExtended());
addLegalFPImmediate(TmpFlt); // FLD0
TmpFlt.changeSign();
addLegalFPImmediate(TmpFlt); // FLD0/FCHS
bool ignored;
APFloat TmpFlt2(+1.0);
- TmpFlt2.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
+ TmpFlt2.convert(APFloat::x87DoubleExtended(), APFloat::rmNearestTiesToEven,
&ignored);
addLegalFPImmediate(TmpFlt2); // FLD1
TmpFlt2.changeSign();
@@ -717,10 +727,12 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
}
if (!Subtarget.useSoftFloat() && Subtarget.hasSSE1()) {
- addRegisterClass(MVT::v4f32, &X86::VR128RegClass);
+ addRegisterClass(MVT::v4f32, Subtarget.hasVLX() ? &X86::VR128XRegClass
+ : &X86::VR128RegClass);
setOperationAction(ISD::FNEG, MVT::v4f32, Custom);
setOperationAction(ISD::FABS, MVT::v4f32, Custom);
+ setOperationAction(ISD::FCOPYSIGN, MVT::v4f32, Custom);
setOperationAction(ISD::BUILD_VECTOR, MVT::v4f32, Custom);
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4f32, Custom);
setOperationAction(ISD::VSELECT, MVT::v4f32, Custom);
@@ -730,14 +742,19 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
}
if (!Subtarget.useSoftFloat() && Subtarget.hasSSE2()) {
- addRegisterClass(MVT::v2f64, &X86::VR128RegClass);
+ addRegisterClass(MVT::v2f64, Subtarget.hasVLX() ? &X86::VR128XRegClass
+ : &X86::VR128RegClass);
// FIXME: Unfortunately, -soft-float and -no-implicit-float mean XMM
// registers cannot be used even for integer operations.
- addRegisterClass(MVT::v16i8, &X86::VR128RegClass);
- addRegisterClass(MVT::v8i16, &X86::VR128RegClass);
- addRegisterClass(MVT::v4i32, &X86::VR128RegClass);
- addRegisterClass(MVT::v2i64, &X86::VR128RegClass);
+ addRegisterClass(MVT::v16i8, Subtarget.hasVLX() ? &X86::VR128XRegClass
+ : &X86::VR128RegClass);
+ addRegisterClass(MVT::v8i16, Subtarget.hasVLX() ? &X86::VR128XRegClass
+ : &X86::VR128RegClass);
+ addRegisterClass(MVT::v4i32, Subtarget.hasVLX() ? &X86::VR128XRegClass
+ : &X86::VR128RegClass);
+ addRegisterClass(MVT::v2i64, Subtarget.hasVLX() ? &X86::VR128XRegClass
+ : &X86::VR128RegClass);
setOperationAction(ISD::MUL, MVT::v16i8, Custom);
setOperationAction(ISD::MUL, MVT::v4i32, Custom);
@@ -751,6 +768,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::MUL, MVT::v8i16, Legal);
setOperationAction(ISD::FNEG, MVT::v2f64, Custom);
setOperationAction(ISD::FABS, MVT::v2f64, Custom);
+ setOperationAction(ISD::FCOPYSIGN, MVT::v2f64, Custom);
setOperationAction(ISD::SMAX, MVT::v8i16, Legal);
setOperationAction(ISD::UMAX, MVT::v16i8, Legal);
@@ -776,7 +794,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::CTTZ, MVT::v16i8, Custom);
setOperationAction(ISD::CTTZ, MVT::v8i16, Custom);
setOperationAction(ISD::CTTZ, MVT::v4i32, Custom);
- // ISD::CTTZ v2i64 - scalarization is faster.
+ setOperationAction(ISD::CTTZ, MVT::v2i64, Custom);
// Custom lower build_vector, vector_shuffle, and extract_vector_elt.
for (auto VT : { MVT::v16i8, MVT::v8i16, MVT::v4i32 }) {
@@ -828,16 +846,17 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::SELECT, MVT::v2i64, Custom);
setOperationAction(ISD::FP_TO_SINT, MVT::v4i32, Legal);
- setOperationAction(ISD::SINT_TO_FP, MVT::v4i32, Legal);
+ setOperationAction(ISD::FP_TO_SINT, MVT::v2i32, Custom);
+ setOperationAction(ISD::SINT_TO_FP, MVT::v4i32, Legal);
setOperationAction(ISD::SINT_TO_FP, MVT::v2i32, Custom);
setOperationAction(ISD::UINT_TO_FP, MVT::v4i8, Custom);
setOperationAction(ISD::UINT_TO_FP, MVT::v4i16, Custom);
- // As there is no 64-bit GPR available, we need build a special custom
- // sequence to convert from v2i32 to v2f32.
- if (!Subtarget.is64Bit())
- setOperationAction(ISD::UINT_TO_FP, MVT::v2f32, Custom);
+ setOperationAction(ISD::UINT_TO_FP, MVT::v2i32, Custom);
+
+ // Fast v2f32 UINT_TO_FP( v2i32 ) custom conversion.
+ setOperationAction(ISD::UINT_TO_FP, MVT::v2f32, Custom);
setOperationAction(ISD::FP_EXTEND, MVT::v2f32, Custom);
setOperationAction(ISD::FP_ROUND, MVT::v2f32, Custom);
@@ -872,8 +891,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::BITREVERSE, MVT::v16i8, Custom);
setOperationAction(ISD::CTLZ, MVT::v16i8, Custom);
setOperationAction(ISD::CTLZ, MVT::v8i16, Custom);
- // ISD::CTLZ v4i32 - scalarization is faster.
- // ISD::CTLZ v2i64 - scalarization is faster.
+ setOperationAction(ISD::CTLZ, MVT::v4i32, Custom);
+ setOperationAction(ISD::CTLZ, MVT::v2i64, Custom);
}
if (!Subtarget.useSoftFloat() && Subtarget.hasSSE41()) {
@@ -946,12 +965,18 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
if (!Subtarget.useSoftFloat() && Subtarget.hasFp256()) {
bool HasInt256 = Subtarget.hasInt256();
- addRegisterClass(MVT::v32i8, &X86::VR256RegClass);
- addRegisterClass(MVT::v16i16, &X86::VR256RegClass);
- addRegisterClass(MVT::v8i32, &X86::VR256RegClass);
- addRegisterClass(MVT::v8f32, &X86::VR256RegClass);
- addRegisterClass(MVT::v4i64, &X86::VR256RegClass);
- addRegisterClass(MVT::v4f64, &X86::VR256RegClass);
+ addRegisterClass(MVT::v32i8, Subtarget.hasVLX() ? &X86::VR256XRegClass
+ : &X86::VR256RegClass);
+ addRegisterClass(MVT::v16i16, Subtarget.hasVLX() ? &X86::VR256XRegClass
+ : &X86::VR256RegClass);
+ addRegisterClass(MVT::v8i32, Subtarget.hasVLX() ? &X86::VR256XRegClass
+ : &X86::VR256RegClass);
+ addRegisterClass(MVT::v8f32, Subtarget.hasVLX() ? &X86::VR256XRegClass
+ : &X86::VR256RegClass);
+ addRegisterClass(MVT::v4i64, Subtarget.hasVLX() ? &X86::VR256XRegClass
+ : &X86::VR256RegClass);
+ addRegisterClass(MVT::v4f64, Subtarget.hasVLX() ? &X86::VR256XRegClass
+ : &X86::VR256RegClass);
for (auto VT : { MVT::v8f32, MVT::v4f64 }) {
setOperationAction(ISD::FFLOOR, VT, Legal);
@@ -961,6 +986,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::FNEARBYINT, VT, Legal);
setOperationAction(ISD::FNEG, VT, Custom);
setOperationAction(ISD::FABS, VT, Custom);
+ setOperationAction(ISD::FCOPYSIGN, VT, Custom);
}
// (fp_to_int:v8i16 (v8f32 ..)) requires the result type to be promoted
@@ -1011,16 +1037,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
for (auto VT : { MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64 }) {
setOperationAction(ISD::CTPOP, VT, Custom);
setOperationAction(ISD::CTTZ, VT, Custom);
- }
-
- // ISD::CTLZ v8i32/v4i64 - scalarization is faster without AVX2
- // as we end up splitting the 256-bit vectors.
- for (auto VT : { MVT::v32i8, MVT::v16i16 })
setOperationAction(ISD::CTLZ, VT, Custom);
-
- if (HasInt256)
- for (auto VT : { MVT::v8i32, MVT::v4i64 })
- setOperationAction(ISD::CTLZ, VT, Custom);
+ }
if (Subtarget.hasAnyFMA()) {
for (auto VT : { MVT::f32, MVT::f64, MVT::v4f32, MVT::v8f32,
@@ -1171,12 +1189,14 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::FNEG, VT, Custom);
setOperationAction(ISD::FABS, VT, Custom);
setOperationAction(ISD::FMA, VT, Legal);
+ setOperationAction(ISD::FCOPYSIGN, VT, Custom);
}
setOperationAction(ISD::FP_TO_SINT, MVT::v16i32, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::v16i32, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::v8i32, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::v4i32, Legal);
+ setOperationAction(ISD::FP_TO_UINT, MVT::v2i32, Custom);
setOperationAction(ISD::SINT_TO_FP, MVT::v16i32, Legal);
setOperationAction(ISD::SINT_TO_FP, MVT::v8i1, Custom);
setOperationAction(ISD::SINT_TO_FP, MVT::v16i1, Custom);
@@ -1216,10 +1236,11 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setTruncStoreAction(MVT::v4i32, MVT::v4i8, Legal);
setTruncStoreAction(MVT::v4i32, MVT::v4i16, Legal);
} else {
- setOperationAction(ISD::MLOAD, MVT::v8i32, Custom);
- setOperationAction(ISD::MLOAD, MVT::v8f32, Custom);
- setOperationAction(ISD::MSTORE, MVT::v8i32, Custom);
- setOperationAction(ISD::MSTORE, MVT::v8f32, Custom);
+ for (auto VT : {MVT::v4i32, MVT::v8i32, MVT::v2i64, MVT::v4i64,
+ MVT::v4f32, MVT::v8f32, MVT::v2f64, MVT::v4f64}) {
+ setOperationAction(ISD::MLOAD, VT, Custom);
+ setOperationAction(ISD::MSTORE, VT, Custom);
+ }
}
setOperationAction(ISD::TRUNCATE, MVT::i1, Custom);
setOperationAction(ISD::TRUNCATE, MVT::v16i8, Custom);
@@ -1230,18 +1251,23 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::VSELECT, MVT::v16i1, Expand);
if (Subtarget.hasDQI()) {
setOperationAction(ISD::SINT_TO_FP, MVT::v8i64, Legal);
+ setOperationAction(ISD::SINT_TO_FP, MVT::v4i64, Legal);
+ setOperationAction(ISD::SINT_TO_FP, MVT::v2i64, Legal);
setOperationAction(ISD::UINT_TO_FP, MVT::v8i64, Legal);
+ setOperationAction(ISD::UINT_TO_FP, MVT::v4i64, Legal);
+ setOperationAction(ISD::UINT_TO_FP, MVT::v2i64, Legal);
setOperationAction(ISD::FP_TO_SINT, MVT::v8i64, Legal);
+ setOperationAction(ISD::FP_TO_SINT, MVT::v4i64, Legal);
+ setOperationAction(ISD::FP_TO_SINT, MVT::v2i64, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::v8i64, Legal);
+ setOperationAction(ISD::FP_TO_UINT, MVT::v4i64, Legal);
+ setOperationAction(ISD::FP_TO_UINT, MVT::v2i64, Legal);
+
if (Subtarget.hasVLX()) {
- setOperationAction(ISD::SINT_TO_FP, MVT::v4i64, Legal);
- setOperationAction(ISD::SINT_TO_FP, MVT::v2i64, Legal);
- setOperationAction(ISD::UINT_TO_FP, MVT::v4i64, Legal);
- setOperationAction(ISD::UINT_TO_FP, MVT::v2i64, Legal);
- setOperationAction(ISD::FP_TO_SINT, MVT::v4i64, Legal);
- setOperationAction(ISD::FP_TO_SINT, MVT::v2i64, Legal);
- setOperationAction(ISD::FP_TO_UINT, MVT::v4i64, Legal);
- setOperationAction(ISD::FP_TO_UINT, MVT::v2i64, Legal);
+ // Fast v2f32 SINT_TO_FP( v2i32 ) custom conversion.
+ setOperationAction(ISD::SINT_TO_FP, MVT::v2f32, Custom);
+ setOperationAction(ISD::FP_TO_SINT, MVT::v2f32, Custom);
+ setOperationAction(ISD::FP_TO_UINT, MVT::v2f32, Custom);
}
}
if (Subtarget.hasVLX()) {
@@ -1250,11 +1276,12 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::FP_TO_SINT, MVT::v8i32, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::v8i32, Legal);
setOperationAction(ISD::SINT_TO_FP, MVT::v4i32, Legal);
- setOperationAction(ISD::UINT_TO_FP, MVT::v4i32, Legal);
setOperationAction(ISD::FP_TO_SINT, MVT::v4i32, Legal);
setOperationAction(ISD::FP_TO_UINT, MVT::v4i32, Legal);
setOperationAction(ISD::ZERO_EXTEND, MVT::v4i32, Custom);
setOperationAction(ISD::ZERO_EXTEND, MVT::v2i64, Custom);
+ setOperationAction(ISD::SIGN_EXTEND, MVT::v4i32, Custom);
+ setOperationAction(ISD::SIGN_EXTEND, MVT::v2i64, Custom);
// FIXME. This commands are available on SSE/AVX2, add relevant patterns.
setLoadExtAction(ISD::EXTLOAD, MVT::v8i32, MVT::v8i8, Legal);
@@ -1281,10 +1308,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::SIGN_EXTEND, MVT::v16i8, Custom);
setOperationAction(ISD::SIGN_EXTEND, MVT::v8i16, Custom);
setOperationAction(ISD::SIGN_EXTEND, MVT::v16i16, Custom);
- if (Subtarget.hasDQI()) {
- setOperationAction(ISD::SIGN_EXTEND, MVT::v4i32, Custom);
- setOperationAction(ISD::SIGN_EXTEND, MVT::v2i64, Custom);
- }
+
for (auto VT : { MVT::v16f32, MVT::v8f64 }) {
setOperationAction(ISD::FFLOOR, VT, Legal);
setOperationAction(ISD::FCEIL, VT, Legal);
@@ -1293,6 +1317,13 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::FNEARBYINT, VT, Legal);
}
+ setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, MVT::v8i64, Custom);
+ setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, MVT::v16i32, Custom);
+
+ // Without BWI we need to use custom lowering to handle MVT::v64i8 input.
+ setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, MVT::v64i8, Custom);
+ setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, MVT::v64i8, Custom);
+
setOperationAction(ISD::CONCAT_VECTORS, MVT::v8f64, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v8i64, Custom);
setOperationAction(ISD::CONCAT_VECTORS, MVT::v16f32, Custom);
@@ -1339,13 +1370,17 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::SRL, VT, Custom);
setOperationAction(ISD::SHL, VT, Custom);
setOperationAction(ISD::SRA, VT, Custom);
- setOperationAction(ISD::AND, VT, Legal);
- setOperationAction(ISD::OR, VT, Legal);
- setOperationAction(ISD::XOR, VT, Legal);
setOperationAction(ISD::CTPOP, VT, Custom);
setOperationAction(ISD::CTTZ, VT, Custom);
}
+ // Need to promote to 64-bit even though we have 32-bit masked instructions
+ // because the IR optimizers rearrange bitcasts around logic ops leaving
+ // too many variations to handle if we don't promote them.
+ setOperationPromotedToType(ISD::AND, MVT::v16i32, MVT::v8i64);
+ setOperationPromotedToType(ISD::OR, MVT::v16i32, MVT::v8i64);
+ setOperationPromotedToType(ISD::XOR, MVT::v16i32, MVT::v8i64);
+
if (Subtarget.hasCDI()) {
setOperationAction(ISD::CTLZ, MVT::v8i64, Legal);
setOperationAction(ISD::CTLZ, MVT::v16i32, Legal);
@@ -1377,12 +1412,12 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
} // Subtarget.hasCDI()
if (Subtarget.hasDQI()) {
- if (Subtarget.hasVLX()) {
- setOperationAction(ISD::MUL, MVT::v2i64, Legal);
- setOperationAction(ISD::MUL, MVT::v4i64, Legal);
- }
+ // NonVLX sub-targets extend 128/256 vectors to use the 512 version.
+ setOperationAction(ISD::MUL, MVT::v2i64, Legal);
+ setOperationAction(ISD::MUL, MVT::v4i64, Legal);
setOperationAction(ISD::MUL, MVT::v8i64, Legal);
}
+
// Custom lower several nodes.
for (auto VT : { MVT::v4i32, MVT::v8i32, MVT::v2i64, MVT::v4i64,
MVT::v4f32, MVT::v8f32, MVT::v2f64, MVT::v4f64 }) {
@@ -1413,6 +1448,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::MSCATTER, VT, Custom);
}
for (auto VT : { MVT::v64i8, MVT::v32i16, MVT::v16i32 }) {
+ setOperationPromotedToType(ISD::LOAD, VT, MVT::v8i64);
setOperationPromotedToType(ISD::SELECT, VT, MVT::v8i64);
}
}// has AVX-512
@@ -1447,6 +1483,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::INSERT_SUBVECTOR, MVT::v64i8, Custom);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v32i16, Custom);
setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v64i8, Custom);
+ setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v32i1, Custom);
+ setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v64i1, Custom);
setOperationAction(ISD::SCALAR_TO_VECTOR, MVT::v32i16, Custom);
setOperationAction(ISD::SCALAR_TO_VECTOR, MVT::v64i8, Custom);
setOperationAction(ISD::SELECT, MVT::v32i1, Custom);
@@ -1486,10 +1524,13 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::UMIN, MVT::v64i8, Legal);
setOperationAction(ISD::UMIN, MVT::v32i16, Legal);
+ setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, MVT::v32i16, Custom);
+
setTruncStoreAction(MVT::v32i16, MVT::v32i8, Legal);
- setTruncStoreAction(MVT::v16i16, MVT::v16i8, Legal);
- if (Subtarget.hasVLX())
+ if (Subtarget.hasVLX()) {
+ setTruncStoreAction(MVT::v16i16, MVT::v16i8, Legal);
setTruncStoreAction(MVT::v8i16, MVT::v8i8, Legal);
+ }
LegalizeAction Action = Subtarget.hasVLX() ? Legal : Custom;
for (auto VT : { MVT::v32i8, MVT::v16i8, MVT::v16i16, MVT::v8i16 }) {
@@ -1532,35 +1573,25 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
addRegisterClass(MVT::v4i1, &X86::VK4RegClass);
addRegisterClass(MVT::v2i1, &X86::VK2RegClass);
- setOperationAction(ISD::ADD, MVT::v2i1, Expand);
- setOperationAction(ISD::ADD, MVT::v4i1, Expand);
- setOperationAction(ISD::SUB, MVT::v2i1, Expand);
- setOperationAction(ISD::SUB, MVT::v4i1, Expand);
- setOperationAction(ISD::MUL, MVT::v2i1, Expand);
- setOperationAction(ISD::MUL, MVT::v4i1, Expand);
-
- setOperationAction(ISD::TRUNCATE, MVT::v2i1, Custom);
- setOperationAction(ISD::TRUNCATE, MVT::v4i1, Custom);
- setOperationAction(ISD::SETCC, MVT::v4i1, Custom);
- setOperationAction(ISD::SETCC, MVT::v2i1, Custom);
- setOperationAction(ISD::CONCAT_VECTORS, MVT::v4i1, Custom);
+ for (auto VT : { MVT::v2i1, MVT::v4i1 }) {
+ setOperationAction(ISD::ADD, VT, Expand);
+ setOperationAction(ISD::SUB, VT, Expand);
+ setOperationAction(ISD::MUL, VT, Expand);
+ setOperationAction(ISD::VSELECT, VT, Expand);
+
+ setOperationAction(ISD::TRUNCATE, VT, Custom);
+ setOperationAction(ISD::SETCC, VT, Custom);
+ setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom);
+ setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom);
+ setOperationAction(ISD::SELECT, VT, Custom);
+ setOperationAction(ISD::BUILD_VECTOR, VT, Custom);
+ setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom);
+ }
+
setOperationAction(ISD::CONCAT_VECTORS, MVT::v8i1, Custom);
+ setOperationAction(ISD::CONCAT_VECTORS, MVT::v4i1, Custom);
setOperationAction(ISD::INSERT_SUBVECTOR, MVT::v8i1, Custom);
setOperationAction(ISD::INSERT_SUBVECTOR, MVT::v4i1, Custom);
- setOperationAction(ISD::SELECT, MVT::v4i1, Custom);
- setOperationAction(ISD::SELECT, MVT::v2i1, Custom);
- setOperationAction(ISD::BUILD_VECTOR, MVT::v4i1, Custom);
- setOperationAction(ISD::BUILD_VECTOR, MVT::v2i1, Custom);
- setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2i1, Custom);
- setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4i1, Custom);
- setOperationAction(ISD::VSELECT, MVT::v2i1, Expand);
- setOperationAction(ISD::VSELECT, MVT::v4i1, Expand);
-
- for (auto VT : { MVT::v4i32, MVT::v8i32 }) {
- setOperationAction(ISD::AND, VT, Legal);
- setOperationAction(ISD::OR, VT, Legal);
- setOperationAction(ISD::XOR, VT, Legal);
- }
for (auto VT : { MVT::v2i64, MVT::v4i64 }) {
setOperationAction(ISD::SMAX, VT, Legal);
@@ -1629,7 +1660,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
// is. We should promote the value to 64-bits to solve this.
// This is what the CRT headers do - `fmodf` is an inline header
// function casting to f64 and calling `fmod`.
- if (Subtarget.is32Bit() && Subtarget.isTargetKnownWindowsMSVC())
+ if (Subtarget.is32Bit() && (Subtarget.isTargetKnownWindowsMSVC() ||
+ Subtarget.isTargetWindowsItanium()))
for (ISD::NodeType Op :
{ISD::FCEIL, ISD::FCOS, ISD::FEXP, ISD::FFLOOR, ISD::FREM, ISD::FLOG,
ISD::FLOG10, ISD::FPOW, ISD::FSIN})
@@ -1953,9 +1985,11 @@ X86TargetLowering::findRepresentativeClass(const TargetRegisterInfo *TRI,
case MVT::f32: case MVT::f64:
case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: case MVT::v2i64:
case MVT::v4f32: case MVT::v2f64:
- case MVT::v32i8: case MVT::v8i32: case MVT::v4i64: case MVT::v8f32:
- case MVT::v4f64:
- RRC = &X86::VR128RegClass;
+ case MVT::v32i8: case MVT::v16i16: case MVT::v8i32: case MVT::v4i64:
+ case MVT::v8f32: case MVT::v4f64:
+ case MVT::v64i8: case MVT::v32i16: case MVT::v16i32: case MVT::v8i64:
+ case MVT::v16f32: case MVT::v8f64:
+ RRC = &X86::VR128XRegClass;
break;
}
return std::make_pair(RRC, Cost);
@@ -2019,6 +2053,9 @@ Value *X86TargetLowering::getSSPStackGuardCheck(const Module &M) const {
}
Value *X86TargetLowering::getSafeStackPointerLocation(IRBuilder<> &IRB) const {
+ if (Subtarget.getTargetTriple().isOSContiki())
+ return getDefaultSafeStackPointerLocation(IRB, false);
+
if (!Subtarget.isTargetAndroid())
return TargetLowering::getSafeStackPointerLocation(IRB);
@@ -2062,6 +2099,58 @@ const MCPhysReg *X86TargetLowering::getScratchRegisters(CallingConv::ID) const {
return ScratchRegs;
}
+/// Lowers masks values (v*i1) to the local register values
+/// \returns DAG node after lowering to register type
+static SDValue lowerMasksToReg(const SDValue &ValArg, const EVT &ValLoc,
+ const SDLoc &Dl, SelectionDAG &DAG) {
+ EVT ValVT = ValArg.getValueType();
+
+ if ((ValVT == MVT::v8i1 && (ValLoc == MVT::i8 || ValLoc == MVT::i32)) ||
+ (ValVT == MVT::v16i1 && (ValLoc == MVT::i16 || ValLoc == MVT::i32))) {
+ // Two stage lowering might be required
+ // bitcast: v8i1 -> i8 / v16i1 -> i16
+ // anyextend: i8 -> i32 / i16 -> i32
+ EVT TempValLoc = ValVT == MVT::v8i1 ? MVT::i8 : MVT::i16;
+ SDValue ValToCopy = DAG.getBitcast(TempValLoc, ValArg);
+ if (ValLoc == MVT::i32)
+ ValToCopy = DAG.getNode(ISD::ANY_EXTEND, Dl, ValLoc, ValToCopy);
+ return ValToCopy;
+ } else if ((ValVT == MVT::v32i1 && ValLoc == MVT::i32) ||
+ (ValVT == MVT::v64i1 && ValLoc == MVT::i64)) {
+ // One stage lowering is required
+ // bitcast: v32i1 -> i32 / v64i1 -> i64
+ return DAG.getBitcast(ValLoc, ValArg);
+ } else
+ return DAG.getNode(ISD::SIGN_EXTEND, Dl, ValLoc, ValArg);
+}
+
+/// Breaks v64i1 value into two registers and adds the new node to the DAG
+static void Passv64i1ArgInRegs(
+ const SDLoc &Dl, SelectionDAG &DAG, SDValue Chain, SDValue &Arg,
+ SmallVector<std::pair<unsigned, SDValue>, 8> &RegsToPass, CCValAssign &VA,
+ CCValAssign &NextVA, const X86Subtarget &Subtarget) {
+ assert((Subtarget.hasBWI() || Subtarget.hasBMI()) &&
+ "Expected AVX512BW or AVX512BMI target!");
+ assert(Subtarget.is32Bit() && "Expecting 32 bit target");
+ assert(Arg.getValueType() == MVT::i64 && "Expecting 64 bit value");
+ assert(VA.isRegLoc() && NextVA.isRegLoc() &&
+ "The value should reside in two registers");
+
+ // Before splitting the value we cast it to i64
+ Arg = DAG.getBitcast(MVT::i64, Arg);
+
+ // Splitting the value into two i32 types
+ SDValue Lo, Hi;
+ Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, Dl, MVT::i32, Arg,
+ DAG.getConstant(0, Dl, MVT::i32));
+ Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, Dl, MVT::i32, Arg,
+ DAG.getConstant(1, Dl, MVT::i32));
+
+ // Attach the two i32 types into corresponding registers
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Lo));
+ RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), Hi));
+}
+
SDValue
X86TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
bool isVarArg,
@@ -2086,10 +2175,11 @@ X86TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
MVT::i32));
// Copy the result values into the output registers.
- for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
- CCValAssign &VA = RVLocs[i];
+ for (unsigned I = 0, OutsIndex = 0, E = RVLocs.size(); I != E;
+ ++I, ++OutsIndex) {
+ CCValAssign &VA = RVLocs[I];
assert(VA.isRegLoc() && "Can only return in registers!");
- SDValue ValToCopy = OutVals[i];
+ SDValue ValToCopy = OutVals[OutsIndex];
EVT ValVT = ValToCopy.getValueType();
// Promote values to the appropriate types.
@@ -2099,7 +2189,7 @@ X86TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
ValToCopy = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), ValToCopy);
else if (VA.getLocInfo() == CCValAssign::AExt) {
if (ValVT.isVector() && ValVT.getVectorElementType() == MVT::i1)
- ValToCopy = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), ValToCopy);
+ ValToCopy = lowerMasksToReg(ValToCopy, VA.getLocVT(), dl, DAG);
else
ValToCopy = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), ValToCopy);
}
@@ -2152,9 +2242,27 @@ X86TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
}
}
- Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), ValToCopy, Flag);
- Flag = Chain.getValue(1);
- RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
+ SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
+
+ if (VA.needsCustom()) {
+ assert(VA.getValVT() == MVT::v64i1 &&
+ "Currently the only custom case is when we split v64i1 to 2 regs");
+
+ Passv64i1ArgInRegs(dl, DAG, Chain, ValToCopy, RegsToPass, VA, RVLocs[++I],
+ Subtarget);
+
+ assert(2 == RegsToPass.size() &&
+ "Expecting two registers after Pass64BitArgInRegs");
+ } else {
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), ValToCopy));
+ }
+
+ // Add nodes to the DAG and add the values into the RetOps list
+ for (auto &Reg : RegsToPass) {
+ Chain = DAG.getCopyToReg(Chain, dl, Reg.first, Reg.second, Flag);
+ Flag = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
+ }
}
// Swift calling convention does not require we copy the sret argument
@@ -2282,6 +2390,98 @@ EVT X86TargetLowering::getTypeForExtReturn(LLVMContext &Context, EVT VT,
return VT.bitsLT(MinVT) ? MinVT : VT;
}
+/// Reads two 32 bit registers and creates a 64 bit mask value.
+/// \param VA The current 32 bit value that need to be assigned.
+/// \param NextVA The next 32 bit value that need to be assigned.
+/// \param Root The parent DAG node.
+/// \param [in,out] InFlag Represents SDvalue in the parent DAG node for
+/// glue purposes. In the case the DAG is already using
+/// physical register instead of virtual, we should glue
+/// our new SDValue to InFlag SDvalue.
+/// \return a new SDvalue of size 64bit.
+static SDValue getv64i1Argument(CCValAssign &VA, CCValAssign &NextVA,
+ SDValue &Root, SelectionDAG &DAG,
+ const SDLoc &Dl, const X86Subtarget &Subtarget,
+ SDValue *InFlag = nullptr) {
+ assert((Subtarget.hasBWI()) && "Expected AVX512BW target!");
+ assert(Subtarget.is32Bit() && "Expecting 32 bit target");
+ assert(VA.getValVT() == MVT::v64i1 &&
+ "Expecting first location of 64 bit width type");
+ assert(NextVA.getValVT() == VA.getValVT() &&
+ "The locations should have the same type");
+ assert(VA.isRegLoc() && NextVA.isRegLoc() &&
+ "The values should reside in two registers");
+
+ SDValue Lo, Hi;
+ unsigned Reg;
+ SDValue ArgValueLo, ArgValueHi;
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ const TargetRegisterClass *RC = &X86::GR32RegClass;
+
+ // Read a 32 bit value from the registers
+ if (nullptr == InFlag) {
+ // When no physical register is present,
+ // create an intermediate virtual register
+ Reg = MF.addLiveIn(VA.getLocReg(), RC);
+ ArgValueLo = DAG.getCopyFromReg(Root, Dl, Reg, MVT::i32);
+ Reg = MF.addLiveIn(NextVA.getLocReg(), RC);
+ ArgValueHi = DAG.getCopyFromReg(Root, Dl, Reg, MVT::i32);
+ } else {
+ // When a physical register is available read the value from it and glue
+ // the reads together.
+ ArgValueLo =
+ DAG.getCopyFromReg(Root, Dl, VA.getLocReg(), MVT::i32, *InFlag);
+ *InFlag = ArgValueLo.getValue(2);
+ ArgValueHi =
+ DAG.getCopyFromReg(Root, Dl, NextVA.getLocReg(), MVT::i32, *InFlag);
+ *InFlag = ArgValueHi.getValue(2);
+ }
+
+ // Convert the i32 type into v32i1 type
+ Lo = DAG.getBitcast(MVT::v32i1, ArgValueLo);
+
+ // Convert the i32 type into v32i1 type
+ Hi = DAG.getBitcast(MVT::v32i1, ArgValueHi);
+
+ // Concantenate the two values together
+ return DAG.getNode(ISD::CONCAT_VECTORS, Dl, MVT::v64i1, Lo, Hi);
+}
+
+/// The function will lower a register of various sizes (8/16/32/64)
+/// to a mask value of the expected size (v8i1/v16i1/v32i1/v64i1)
+/// \returns a DAG node contains the operand after lowering to mask type.
+static SDValue lowerRegToMasks(const SDValue &ValArg, const EVT &ValVT,
+ const EVT &ValLoc, const SDLoc &Dl,
+ SelectionDAG &DAG) {
+ SDValue ValReturned = ValArg;
+
+ if (ValVT == MVT::v64i1) {
+ // In 32 bit machine, this case is handled by getv64i1Argument
+ assert(ValLoc == MVT::i64 && "Expecting only i64 locations");
+ // In 64 bit machine, There is no need to truncate the value only bitcast
+ } else {
+ MVT maskLen;
+ switch (ValVT.getSimpleVT().SimpleTy) {
+ case MVT::v8i1:
+ maskLen = MVT::i8;
+ break;
+ case MVT::v16i1:
+ maskLen = MVT::i16;
+ break;
+ case MVT::v32i1:
+ maskLen = MVT::i32;
+ break;
+ default:
+ llvm_unreachable("Expecting a vector of i1 types");
+ }
+
+ ValReturned = DAG.getNode(ISD::TRUNCATE, Dl, maskLen, ValReturned);
+ }
+
+ return DAG.getBitcast(ValVT, ValReturned);
+}
+
/// Lower the result values of a call into the
/// appropriate copies out of appropriate physical registers.
///
@@ -2298,13 +2498,14 @@ SDValue X86TargetLowering::LowerCallResult(
CCInfo.AnalyzeCallResult(Ins, RetCC_X86);
// Copy all of the result registers out of their specified physreg.
- for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
- CCValAssign &VA = RVLocs[i];
+ for (unsigned I = 0, InsIndex = 0, E = RVLocs.size(); I != E;
+ ++I, ++InsIndex) {
+ CCValAssign &VA = RVLocs[I];
EVT CopyVT = VA.getLocVT();
// If this is x86-64, and we disabled SSE, we can't return FP values
if ((CopyVT == MVT::f32 || CopyVT == MVT::f64 || CopyVT == MVT::f128) &&
- ((Is64Bit || Ins[i].Flags.isInReg()) && !Subtarget.hasSSE1())) {
+ ((Is64Bit || Ins[InsIndex].Flags.isInReg()) && !Subtarget.hasSSE1())) {
report_fatal_error("SSE register return with SSE disabled");
}
@@ -2319,19 +2520,34 @@ SDValue X86TargetLowering::LowerCallResult(
RoundAfterCopy = (CopyVT != VA.getLocVT());
}
- Chain = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(),
- CopyVT, InFlag).getValue(1);
- SDValue Val = Chain.getValue(0);
+ SDValue Val;
+ if (VA.needsCustom()) {
+ assert(VA.getValVT() == MVT::v64i1 &&
+ "Currently the only custom case is when we split v64i1 to 2 regs");
+ Val =
+ getv64i1Argument(VA, RVLocs[++I], Chain, DAG, dl, Subtarget, &InFlag);
+ } else {
+ Chain = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), CopyVT, InFlag)
+ .getValue(1);
+ Val = Chain.getValue(0);
+ InFlag = Chain.getValue(2);
+ }
if (RoundAfterCopy)
Val = DAG.getNode(ISD::FP_ROUND, dl, VA.getValVT(), Val,
// This truncation won't change the value.
DAG.getIntPtrConstant(1, dl));
- if (VA.isExtInLoc() && VA.getValVT().getScalarType() == MVT::i1)
- Val = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Val);
+ if (VA.isExtInLoc() && (VA.getValVT().getScalarType() == MVT::i1)) {
+ if (VA.getValVT().isVector() &&
+ ((VA.getLocVT() == MVT::i64) || (VA.getLocVT() == MVT::i32) ||
+ (VA.getLocVT() == MVT::i16) || (VA.getLocVT() == MVT::i8))) {
+ // promoting a mask type (v*i1) into a register of type i64/i32/i16/i8
+ Val = lowerRegToMasks(Val, VA.getValVT(), VA.getLocVT(), dl, DAG);
+ } else
+ Val = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Val);
+ }
- InFlag = Chain.getValue(2);
InVals.push_back(Val);
}
@@ -2399,7 +2615,8 @@ static SDValue CreateCopyOfByValArgument(SDValue Src, SDValue Dst,
/// Return true if the calling convention is one that we can guarantee TCO for.
static bool canGuaranteeTCO(CallingConv::ID CC) {
return (CC == CallingConv::Fast || CC == CallingConv::GHC ||
- CC == CallingConv::HiPE || CC == CallingConv::HHVM);
+ CC == CallingConv::X86_RegCall || CC == CallingConv::HiPE ||
+ CC == CallingConv::HHVM);
}
/// Return true if we might ever do TCO for calls with this calling convention.
@@ -2445,7 +2662,7 @@ X86TargetLowering::LowerMemArgument(SDValue Chain, CallingConv::ID CallConv,
const SmallVectorImpl<ISD::InputArg> &Ins,
const SDLoc &dl, SelectionDAG &DAG,
const CCValAssign &VA,
- MachineFrameInfo *MFI, unsigned i) const {
+ MachineFrameInfo &MFI, unsigned i) const {
// Create the nodes corresponding to a load from this parameter slot.
ISD::ArgFlagsTy Flags = Ins[i].Flags;
bool AlwaysUseMutable = shouldGuaranteeTCO(
@@ -2454,9 +2671,11 @@ X86TargetLowering::LowerMemArgument(SDValue Chain, CallingConv::ID CallConv,
EVT ValVT;
// If value is passed by pointer we have address passed instead of the value
- // itself.
- bool ExtendedInMem = VA.isExtInLoc() &&
- VA.getValVT().getScalarType() == MVT::i1;
+ // itself. No need to extend if the mask value and location share the same
+ // absolute size.
+ bool ExtendedInMem =
+ VA.isExtInLoc() && VA.getValVT().getScalarType() == MVT::i1 &&
+ VA.getValVT().getSizeInBits() != VA.getLocVT().getSizeInBits();
if (VA.getLocInfo() == CCValAssign::Indirect || ExtendedInMem)
ValVT = VA.getLocVT();
@@ -2483,26 +2702,26 @@ X86TargetLowering::LowerMemArgument(SDValue Chain, CallingConv::ID CallConv,
if (Flags.isByVal()) {
unsigned Bytes = Flags.getByValSize();
if (Bytes == 0) Bytes = 1; // Don't create zero-sized stack objects.
- int FI = MFI->CreateFixedObject(Bytes, VA.getLocMemOffset(), isImmutable);
+ int FI = MFI.CreateFixedObject(Bytes, VA.getLocMemOffset(), isImmutable);
// Adjust SP offset of interrupt parameter.
if (CallConv == CallingConv::X86_INTR) {
- MFI->setObjectOffset(FI, Offset);
+ MFI.setObjectOffset(FI, Offset);
}
return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
} else {
- int FI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8,
- VA.getLocMemOffset(), isImmutable);
+ int FI = MFI.CreateFixedObject(ValVT.getSizeInBits()/8,
+ VA.getLocMemOffset(), isImmutable);
// Set SExt or ZExt flag.
if (VA.getLocInfo() == CCValAssign::ZExt) {
- MFI->setObjectZExt(FI, true);
+ MFI.setObjectZExt(FI, true);
} else if (VA.getLocInfo() == CCValAssign::SExt) {
- MFI->setObjectSExt(FI, true);
+ MFI.setObjectSExt(FI, true);
}
// Adjust SP offset of interrupt parameter.
if (CallConv == CallingConv::X86_INTR) {
- MFI->setObjectOffset(FI, Offset);
+ MFI.setObjectOffset(FI, Offset);
}
SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
@@ -2562,6 +2781,13 @@ static ArrayRef<MCPhysReg> get64BitArgumentXMMs(MachineFunction &MF,
return makeArrayRef(std::begin(XMMArgRegs64Bit), std::end(XMMArgRegs64Bit));
}
+static bool isSortedByValueNo(const SmallVectorImpl<CCValAssign> &ArgLocs) {
+ return std::is_sorted(ArgLocs.begin(), ArgLocs.end(),
+ [](const CCValAssign &A, const CCValAssign &B) -> bool {
+ return A.getValNo() < B.getValNo();
+ });
+}
+
SDValue X86TargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
@@ -2576,12 +2802,13 @@ SDValue X86TargetLowering::LowerFormalArguments(
Fn->getName() == "main")
FuncInfo->setForceFramePointer(true);
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
bool Is64Bit = Subtarget.is64Bit();
bool IsWin64 = Subtarget.isCallingConvWin64(CallConv);
- assert(!(isVarArg && canGuaranteeTCO(CallConv)) &&
- "Var args not supported with calling convention fastcc, ghc or hipe");
+ assert(
+ !(isVarArg && canGuaranteeTCO(CallConv)) &&
+ "Var args not supported with calling conv' regcall, fastcc, ghc or hipe");
if (CallConv == CallingConv::X86_INTR) {
bool isLegal = Ins.size() == 1 ||
@@ -2595,59 +2822,78 @@ SDValue X86TargetLowering::LowerFormalArguments(
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, isVarArg, MF, ArgLocs, *DAG.getContext());
- // Allocate shadow area for Win64
+ // Allocate shadow area for Win64.
if (IsWin64)
CCInfo.AllocateStack(32, 8);
- CCInfo.AnalyzeFormalArguments(Ins, CC_X86);
+ CCInfo.AnalyzeArguments(Ins, CC_X86);
+
+ // In vectorcall calling convention a second pass is required for the HVA
+ // types.
+ if (CallingConv::X86_VectorCall == CallConv) {
+ CCInfo.AnalyzeArgumentsSecondPass(Ins, CC_X86);
+ }
+
+ // The next loop assumes that the locations are in the same order of the
+ // input arguments.
+ if (!isSortedByValueNo(ArgLocs))
+ llvm_unreachable("Argument Location list must be sorted before lowering");
- unsigned LastVal = ~0U;
SDValue ArgValue;
- for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
- CCValAssign &VA = ArgLocs[i];
- // TODO: If an arg is passed in two places (e.g. reg and stack), skip later
- // places.
- assert(VA.getValNo() != LastVal &&
- "Don't support value assigned to multiple locs yet");
- (void)LastVal;
- LastVal = VA.getValNo();
+ for (unsigned I = 0, InsIndex = 0, E = ArgLocs.size(); I != E;
+ ++I, ++InsIndex) {
+ assert(InsIndex < Ins.size() && "Invalid Ins index");
+ CCValAssign &VA = ArgLocs[I];
if (VA.isRegLoc()) {
EVT RegVT = VA.getLocVT();
- const TargetRegisterClass *RC;
- if (RegVT == MVT::i32)
- RC = &X86::GR32RegClass;
- else if (Is64Bit && RegVT == MVT::i64)
- RC = &X86::GR64RegClass;
- else if (RegVT == MVT::f32)
- RC = &X86::FR32RegClass;
- else if (RegVT == MVT::f64)
- RC = &X86::FR64RegClass;
- else if (RegVT == MVT::f128)
- RC = &X86::FR128RegClass;
- else if (RegVT.is512BitVector())
- RC = &X86::VR512RegClass;
- else if (RegVT.is256BitVector())
- RC = &X86::VR256RegClass;
- else if (RegVT.is128BitVector())
- RC = &X86::VR128RegClass;
- else if (RegVT == MVT::x86mmx)
- RC = &X86::VR64RegClass;
- else if (RegVT == MVT::i1)
- RC = &X86::VK1RegClass;
- else if (RegVT == MVT::v8i1)
- RC = &X86::VK8RegClass;
- else if (RegVT == MVT::v16i1)
- RC = &X86::VK16RegClass;
- else if (RegVT == MVT::v32i1)
- RC = &X86::VK32RegClass;
- else if (RegVT == MVT::v64i1)
- RC = &X86::VK64RegClass;
- else
- llvm_unreachable("Unknown argument type!");
+ if (VA.needsCustom()) {
+ assert(
+ VA.getValVT() == MVT::v64i1 &&
+ "Currently the only custom case is when we split v64i1 to 2 regs");
+
+ // v64i1 values, in regcall calling convention, that are
+ // compiled to 32 bit arch, are splited up into two registers.
+ ArgValue =
+ getv64i1Argument(VA, ArgLocs[++I], Chain, DAG, dl, Subtarget);
+ } else {
+ const TargetRegisterClass *RC;
+ if (RegVT == MVT::i32)
+ RC = &X86::GR32RegClass;
+ else if (Is64Bit && RegVT == MVT::i64)
+ RC = &X86::GR64RegClass;
+ else if (RegVT == MVT::f32)
+ RC = Subtarget.hasAVX512() ? &X86::FR32XRegClass : &X86::FR32RegClass;
+ else if (RegVT == MVT::f64)
+ RC = Subtarget.hasAVX512() ? &X86::FR64XRegClass : &X86::FR64RegClass;
+ else if (RegVT == MVT::f80)
+ RC = &X86::RFP80RegClass;
+ else if (RegVT == MVT::f128)
+ RC = &X86::FR128RegClass;
+ else if (RegVT.is512BitVector())
+ RC = &X86::VR512RegClass;
+ else if (RegVT.is256BitVector())
+ RC = Subtarget.hasVLX() ? &X86::VR256XRegClass : &X86::VR256RegClass;
+ else if (RegVT.is128BitVector())
+ RC = Subtarget.hasVLX() ? &X86::VR128XRegClass : &X86::VR128RegClass;
+ else if (RegVT == MVT::x86mmx)
+ RC = &X86::VR64RegClass;
+ else if (RegVT == MVT::i1)
+ RC = &X86::VK1RegClass;
+ else if (RegVT == MVT::v8i1)
+ RC = &X86::VK8RegClass;
+ else if (RegVT == MVT::v16i1)
+ RC = &X86::VK16RegClass;
+ else if (RegVT == MVT::v32i1)
+ RC = &X86::VK32RegClass;
+ else if (RegVT == MVT::v64i1)
+ RC = &X86::VK64RegClass;
+ else
+ llvm_unreachable("Unknown argument type!");
- unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC);
- ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
+ unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC);
+ ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
+ }
// If this is an 8 or 16-bit value, it is really passed promoted to 32
// bits. Insert an assert[sz]ext to capture this, then truncate to the
@@ -2665,12 +2911,19 @@ SDValue X86TargetLowering::LowerFormalArguments(
// Handle MMX values passed in XMM regs.
if (RegVT.isVector() && VA.getValVT().getScalarType() != MVT::i1)
ArgValue = DAG.getNode(X86ISD::MOVDQ2Q, dl, VA.getValVT(), ArgValue);
- else
+ else if (VA.getValVT().isVector() &&
+ VA.getValVT().getScalarType() == MVT::i1 &&
+ ((VA.getLocVT() == MVT::i64) || (VA.getLocVT() == MVT::i32) ||
+ (VA.getLocVT() == MVT::i16) || (VA.getLocVT() == MVT::i8))) {
+ // Promoting a mask type (v*i1) into a register of type i64/i32/i16/i8
+ ArgValue = lowerRegToMasks(ArgValue, VA.getValVT(), RegVT, dl, DAG);
+ } else
ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
}
} else {
assert(VA.isMemLoc());
- ArgValue = LowerMemArgument(Chain, CallConv, Ins, dl, DAG, VA, MFI, i);
+ ArgValue =
+ LowerMemArgument(Chain, CallConv, Ins, dl, DAG, VA, MFI, InsIndex);
}
// If value is passed via pointer - do a load.
@@ -2681,7 +2934,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
InVals.push_back(ArgValue);
}
- for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ for (unsigned I = 0, E = Ins.size(); I != E; ++I) {
// Swift calling convention does not require we copy the sret argument
// into %rax/%eax for the return. We don't set SRetReturnReg for Swift.
if (CallConv == CallingConv::Swift)
@@ -2691,14 +2944,14 @@ SDValue X86TargetLowering::LowerFormalArguments(
// sret argument into %rax/%eax (depending on ABI) for the return. Save
// the argument into a virtual register so that we can access it from the
// return points.
- if (Ins[i].Flags.isSRet()) {
+ if (Ins[I].Flags.isSRet()) {
unsigned Reg = FuncInfo->getSRetReturnReg();
if (!Reg) {
MVT PtrTy = getPointerTy(DAG.getDataLayout());
Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(PtrTy));
FuncInfo->setSRetReturnReg(Reg);
}
- SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[i]);
+ SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[I]);
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
break;
}
@@ -2713,11 +2966,10 @@ SDValue X86TargetLowering::LowerFormalArguments(
// If the function takes variable number of arguments, make a frame index for
// the start of the first vararg value... for expansion of llvm.va_start. We
// can skip this if there are no va_start calls.
- if (MFI->hasVAStart() &&
+ if (MFI.hasVAStart() &&
(Is64Bit || (CallConv != CallingConv::X86_FastCall &&
CallConv != CallingConv::X86_ThisCall))) {
- FuncInfo->setVarArgsFrameIndex(
- MFI->CreateFixedObject(1, StackSize, true));
+ FuncInfo->setVarArgsFrameIndex(MFI.CreateFixedObject(1, StackSize, true));
}
// Figure out if XMM registers are in use.
@@ -2727,7 +2979,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
// 64-bit calling conventions support varargs and register parameters, so we
// have to do extra work to spill them in the prologue.
- if (Is64Bit && isVarArg && MFI->hasVAStart()) {
+ if (Is64Bit && isVarArg && MFI.hasVAStart()) {
// Find the first unallocated argument registers.
ArrayRef<MCPhysReg> ArgGPRs = get64BitArgumentGPRs(CallConv, Subtarget);
ArrayRef<MCPhysReg> ArgXMMs = get64BitArgumentXMMs(MF, CallConv, Subtarget);
@@ -2760,7 +3012,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
// for the return address.
int HomeOffset = TFI.getOffsetOfLocalArea() + 8;
FuncInfo->setRegSaveFrameIndex(
- MFI->CreateFixedObject(1, NumIntRegs * 8 + HomeOffset, false));
+ MFI.CreateFixedObject(1, NumIntRegs * 8 + HomeOffset, false));
// Fixup to set vararg frame on shadow area (4 x i64).
if (NumIntRegs < 4)
FuncInfo->setVarArgsFrameIndex(FuncInfo->getRegSaveFrameIndex());
@@ -2770,7 +3022,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
// they may be loaded by dereferencing the result of va_next.
FuncInfo->setVarArgsGPOffset(NumIntRegs * 8);
FuncInfo->setVarArgsFPOffset(ArgGPRs.size() * 8 + NumXMMRegs * 16);
- FuncInfo->setRegSaveFrameIndex(MFI->CreateStackObject(
+ FuncInfo->setRegSaveFrameIndex(MFI.CreateStackObject(
ArgGPRs.size() * 8 + ArgXMMs.size() * 16, 16, false));
}
@@ -2810,7 +3062,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
}
- if (isVarArg && MFI->hasMustTailInVarArgFunc()) {
+ if (isVarArg && MFI.hasMustTailInVarArgFunc()) {
// Find the largest legal vector type.
MVT VecVT = MVT::Other;
// FIXME: Only some x86_32 calling conventions support AVX512.
@@ -2889,7 +3141,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
// same, so the size of funclets' (mostly empty) frames is dictated by
// how far this slot is from the bottom (since they allocate just enough
// space to accommodate holding this slot at the correct offset).
- int PSPSymFI = MFI->CreateStackObject(8, 8, /*isSS=*/false);
+ int PSPSymFI = MFI.CreateStackObject(8, 8, /*isSS=*/false);
EHInfo->PSPSymFrameIdx = PSPSymFI;
}
}
@@ -2938,7 +3190,7 @@ static SDValue EmitTailCallStoreRetAddr(SelectionDAG &DAG, MachineFunction &MF,
if (!FPDiff) return Chain;
// Calculate the new stack slot for the return address.
int NewReturnAddrFI =
- MF.getFrameInfo()->CreateFixedObject(SlotSize, (int64_t)FPDiff - SlotSize,
+ MF.getFrameInfo().CreateFixedObject(SlotSize, (int64_t)FPDiff - SlotSize,
false);
SDValue NewRetAddrFrIdx = DAG.getFrameIndex(NewReturnAddrFI, PtrVT);
Chain = DAG.getStore(Chain, dl, RetAddrFrIdx, NewRetAddrFrIdx,
@@ -3029,11 +3281,17 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, isVarArg, MF, ArgLocs, *DAG.getContext());
- // Allocate shadow area for Win64
+ // Allocate shadow area for Win64.
if (IsWin64)
CCInfo.AllocateStack(32, 8);
- CCInfo.AnalyzeCallOperands(Outs, CC_X86);
+ CCInfo.AnalyzeArguments(Outs, CC_X86);
+
+ // In vectorcall calling convention a second pass is required for the HVA
+ // types.
+ if (CallingConv::X86_VectorCall == CallConv) {
+ CCInfo.AnalyzeArgumentsSecondPass(Outs, CC_X86);
+ }
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getAlignedCallFrameSize();
@@ -3088,18 +3346,25 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVector<SDValue, 8> MemOpChains;
SDValue StackPtr;
+ // The next loop assumes that the locations are in the same order of the
+ // input arguments.
+ if (!isSortedByValueNo(ArgLocs))
+ llvm_unreachable("Argument Location list must be sorted before lowering");
+
// Walk the register/memloc assignments, inserting copies/loads. In the case
// of tail call optimization arguments are handle later.
const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
- for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ for (unsigned I = 0, OutIndex = 0, E = ArgLocs.size(); I != E;
+ ++I, ++OutIndex) {
+ assert(OutIndex < Outs.size() && "Invalid Out index");
// Skip inalloca arguments, they have already been written.
- ISD::ArgFlagsTy Flags = Outs[i].Flags;
+ ISD::ArgFlagsTy Flags = Outs[OutIndex].Flags;
if (Flags.isInAlloca())
continue;
- CCValAssign &VA = ArgLocs[i];
+ CCValAssign &VA = ArgLocs[I];
EVT RegVT = VA.getLocVT();
- SDValue Arg = OutVals[i];
+ SDValue Arg = OutVals[OutIndex];
bool isByVal = Flags.isByVal();
// Promote the value if needed.
@@ -3115,7 +3380,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
case CCValAssign::AExt:
if (Arg.getValueType().isVector() &&
Arg.getValueType().getVectorElementType() == MVT::i1)
- Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, RegVT, Arg);
+ Arg = lowerMasksToReg(Arg, RegVT, dl, DAG);
else if (RegVT.is128BitVector()) {
// Special case: passing MMX values in XMM registers.
Arg = DAG.getBitcast(MVT::i64, Arg);
@@ -3139,7 +3404,13 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
}
}
- if (VA.isRegLoc()) {
+ if (VA.needsCustom()) {
+ assert(VA.getValVT() == MVT::v64i1 &&
+ "Currently the only custom case is when we split v64i1 to 2 regs");
+ // Split v64i1 value into two registers
+ Passv64i1ArgInRegs(dl, DAG, Chain, Arg, RegsToPass, VA, ArgLocs[++I],
+ Subtarget);
+ } else if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
if (isVarArg && IsWin64) {
// Win64 ABI requires argument XMM reg to be copied to the corresponding
@@ -3239,20 +3510,32 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVector<SDValue, 8> MemOpChains2;
SDValue FIN;
int FI = 0;
- for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
- CCValAssign &VA = ArgLocs[i];
- if (VA.isRegLoc())
+ for (unsigned I = 0, OutsIndex = 0, E = ArgLocs.size(); I != E;
+ ++I, ++OutsIndex) {
+ CCValAssign &VA = ArgLocs[I];
+
+ if (VA.isRegLoc()) {
+ if (VA.needsCustom()) {
+ assert((CallConv == CallingConv::X86_RegCall) &&
+ "Expecting custome case only in regcall calling convention");
+ // This means that we are in special case where one argument was
+ // passed through two register locations - Skip the next location
+ ++I;
+ }
+
continue;
+ }
+
assert(VA.isMemLoc());
- SDValue Arg = OutVals[i];
- ISD::ArgFlagsTy Flags = Outs[i].Flags;
+ SDValue Arg = OutVals[OutsIndex];
+ ISD::ArgFlagsTy Flags = Outs[OutsIndex].Flags;
// Skip inalloca arguments. They don't require any work.
if (Flags.isInAlloca())
continue;
// Create frame index.
int32_t Offset = VA.getLocMemOffset()+FPDiff;
uint32_t OpSize = (VA.getLocVT().getSizeInBits()+7)/8;
- FI = MF.getFrameInfo()->CreateFixedObject(OpSize, Offset, true);
+ FI = MF.getFrameInfo().CreateFixedObject(OpSize, Offset, true);
FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
if (Flags.isByVal()) {
@@ -3391,7 +3674,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// This isn't right, although it's probably harmless on x86; liveouts
// should be computed from returns not tail calls. Consider a void
// function making a tail call to a function returning int.
- MF.getFrameInfo()->setHasTailCall();
+ MF.getFrameInfo().setHasTailCall();
return DAG.getNode(X86ISD::TC_RETURN, dl, NodeTys, Ops);
}
@@ -3493,9 +3776,9 @@ X86TargetLowering::GetAlignedArgumentStackSize(unsigned StackSize,
/// same position (relatively) of the caller's incoming argument stack.
static
bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
- MachineFrameInfo *MFI, const MachineRegisterInfo *MRI,
+ MachineFrameInfo &MFI, const MachineRegisterInfo *MRI,
const X86InstrInfo *TII, const CCValAssign &VA) {
- unsigned Bytes = Arg.getValueType().getSizeInBits() / 8;
+ unsigned Bytes = Arg.getValueSizeInBits() / 8;
for (;;) {
// Look through nodes that don't alter the bits of the incoming value.
@@ -3558,22 +3841,22 @@ bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
return false;
assert(FI != INT_MAX);
- if (!MFI->isFixedObjectIndex(FI))
+ if (!MFI.isFixedObjectIndex(FI))
return false;
- if (Offset != MFI->getObjectOffset(FI))
+ if (Offset != MFI.getObjectOffset(FI))
return false;
- if (VA.getLocVT().getSizeInBits() > Arg.getValueType().getSizeInBits()) {
+ if (VA.getLocVT().getSizeInBits() > Arg.getValueSizeInBits()) {
// If the argument location is wider than the argument type, check that any
// extension flags match.
- if (Flags.isZExt() != MFI->isObjectZExt(FI) ||
- Flags.isSExt() != MFI->isObjectSExt(FI)) {
+ if (Flags.isZExt() != MFI.isObjectZExt(FI) ||
+ Flags.isSExt() != MFI.isObjectSExt(FI)) {
return false;
}
}
- return Bytes == MFI->getObjectSize(FI);
+ return Bytes == MFI.getObjectSize(FI);
}
/// Check whether the call is eligible for tail call optimization. Targets
@@ -3700,7 +3983,7 @@ bool X86TargetLowering::IsEligibleForTailCallOptimization(
if (CCInfo.getNextStackOffset()) {
// Check if the arguments are already laid out in the right way as
// the caller's fixed stack objects.
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const MachineRegisterInfo *MRI = &MF.getRegInfo();
const X86InstrInfo *TII = Subtarget.getInstrInfo();
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
@@ -3787,6 +4070,14 @@ static bool MayFoldIntoStore(SDValue Op) {
return Op.hasOneUse() && ISD::isNormalStore(*Op.getNode()->use_begin());
}
+static bool MayFoldIntoZeroExtend(SDValue Op) {
+ if (Op.hasOneUse()) {
+ unsigned Opcode = Op.getNode()->use_begin()->getOpcode();
+ return (ISD::ZERO_EXTEND == Opcode);
+ }
+ return false;
+}
+
static bool isTargetShuffle(unsigned Opcode) {
switch(Opcode) {
default: return false;
@@ -3821,6 +4112,7 @@ static bool isTargetShuffle(unsigned Opcode) {
case X86ISD::VPPERM:
case X86ISD::VPERMV:
case X86ISD::VPERMV3:
+ case X86ISD::VPERMIV3:
case X86ISD::VZEXT_MOVL:
return true;
}
@@ -3829,41 +4121,18 @@ static bool isTargetShuffle(unsigned Opcode) {
static bool isTargetShuffleVariableMask(unsigned Opcode) {
switch (Opcode) {
default: return false;
+ // Target Shuffles.
case X86ISD::PSHUFB:
case X86ISD::VPERMILPV:
+ case X86ISD::VPERMIL2:
+ case X86ISD::VPPERM:
+ case X86ISD::VPERMV:
+ case X86ISD::VPERMV3:
+ case X86ISD::VPERMIV3:
+ return true;
+ // 'Faux' Target Shuffles.
+ case ISD::AND:
return true;
- }
-}
-
-static SDValue getTargetShuffleNode(unsigned Opc, const SDLoc &dl, MVT VT,
- SDValue V1, unsigned TargetMask,
- SelectionDAG &DAG) {
- switch(Opc) {
- default: llvm_unreachable("Unknown x86 shuffle node");
- case X86ISD::PSHUFD:
- case X86ISD::PSHUFHW:
- case X86ISD::PSHUFLW:
- case X86ISD::VPERMILPI:
- case X86ISD::VPERMI:
- return DAG.getNode(Opc, dl, VT, V1,
- DAG.getConstant(TargetMask, dl, MVT::i8));
- }
-}
-
-static SDValue getTargetShuffleNode(unsigned Opc, const SDLoc &dl, MVT VT,
- SDValue V1, SDValue V2, SelectionDAG &DAG) {
- switch(Opc) {
- default: llvm_unreachable("Unknown x86 shuffle node");
- case X86ISD::MOVLHPS:
- case X86ISD::MOVLHPD:
- case X86ISD::MOVHLPS:
- case X86ISD::MOVLPS:
- case X86ISD::MOVLPD:
- case X86ISD::MOVSS:
- case X86ISD::MOVSD:
- case X86ISD::UNPCKL:
- case X86ISD::UNPCKH:
- return DAG.getNode(Opc, dl, VT, V1, V2);
}
}
@@ -3876,9 +4145,9 @@ SDValue X86TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const {
if (ReturnAddrIndex == 0) {
// Set up a frame object for the return address.
unsigned SlotSize = RegInfo->getSlotSize();
- ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(SlotSize,
- -(int64_t)SlotSize,
- false);
+ ReturnAddrIndex = MF.getFrameInfo().CreateFixedObject(SlotSize,
+ -(int64_t)SlotSize,
+ false);
FuncInfo->setRAIndex(ReturnAddrIndex);
}
@@ -3974,7 +4243,7 @@ static X86::CondCode TranslateIntegerX86CC(ISD::CondCode SetCCOpcode) {
/// Do a one-to-one translation of a ISD::CondCode to the X86-specific
/// condition code, returning the condition code and the LHS/RHS of the
/// comparison to make.
-static unsigned TranslateX86CC(ISD::CondCode SetCCOpcode, const SDLoc &DL,
+static X86::CondCode TranslateX86CC(ISD::CondCode SetCCOpcode, const SDLoc &DL,
bool isFP, SDValue &LHS, SDValue &RHS,
SelectionDAG &DAG) {
if (!isFP) {
@@ -4175,6 +4444,10 @@ bool X86TargetLowering::isCheapToSpeculateCtlz() const {
return Subtarget.hasLZCNT();
}
+bool X86TargetLowering::isCtlzFast() const {
+ return Subtarget.hasFastLZCNT();
+}
+
bool X86TargetLowering::hasAndNotCompare(SDValue Y) const {
if (!Subtarget.hasBMI())
return false;
@@ -4187,11 +4460,21 @@ bool X86TargetLowering::hasAndNotCompare(SDValue Y) const {
return true;
}
+/// Val is the undef sentinel value or equal to the specified value.
+static bool isUndefOrEqual(int Val, int CmpVal) {
+ return ((Val == SM_SentinelUndef) || (Val == CmpVal));
+}
+
+/// Val is either the undef or zero sentinel value.
+static bool isUndefOrZero(int Val) {
+ return ((Val == SM_SentinelUndef) || (Val == SM_SentinelZero));
+}
+
/// Return true if every element in Mask, beginning
-/// from position Pos and ending in Pos+Size is undef.
+/// from position Pos and ending in Pos+Size is the undef sentinel value.
static bool isUndefInRange(ArrayRef<int> Mask, unsigned Pos, unsigned Size) {
for (unsigned i = Pos, e = Pos + Size; i != e; ++i)
- if (0 <= Mask[i])
+ if (Mask[i] != SM_SentinelUndef)
return false;
return true;
}
@@ -4199,7 +4482,7 @@ static bool isUndefInRange(ArrayRef<int> Mask, unsigned Pos, unsigned Size) {
/// Return true if Val is undef or if its value falls within the
/// specified range (L, H].
static bool isUndefOrInRange(int Val, int Low, int Hi) {
- return (Val < 0) || (Val >= Low && Val < Hi);
+ return (Val == SM_SentinelUndef) || (Val >= Low && Val < Hi);
}
/// Return true if every element in Mask is undef or if its value
@@ -4212,14 +4495,19 @@ static bool isUndefOrInRange(ArrayRef<int> Mask,
return true;
}
-/// Val is either less than zero (undef) or equal to the specified value.
-static bool isUndefOrEqual(int Val, int CmpVal) {
- return (Val < 0 || Val == CmpVal);
+/// Return true if Val is undef, zero or if its value falls within the
+/// specified range (L, H].
+static bool isUndefOrZeroOrInRange(int Val, int Low, int Hi) {
+ return isUndefOrZero(Val) || (Val >= Low && Val < Hi);
}
-/// Val is either the undef or zero sentinel value.
-static bool isUndefOrZero(int Val) {
- return (Val == SM_SentinelUndef || Val == SM_SentinelZero);
+/// Return true if every element in Mask is undef, zero or if its value
+/// falls within the specified range (L, H].
+static bool isUndefOrZeroOrInRange(ArrayRef<int> Mask, int Low, int Hi) {
+ for (int M : Mask)
+ if (!isUndefOrZeroOrInRange(M, Low, Hi))
+ return false;
+ return true;
}
/// Return true if every element in Mask, beginning
@@ -4244,6 +4532,100 @@ static bool isSequentialOrUndefOrZeroInRange(ArrayRef<int> Mask, unsigned Pos,
return true;
}
+/// Return true if every element in Mask, beginning
+/// from position Pos and ending in Pos+Size is undef or is zero.
+static bool isUndefOrZeroInRange(ArrayRef<int> Mask, unsigned Pos,
+ unsigned Size) {
+ for (unsigned i = Pos, e = Pos + Size; i != e; ++i)
+ if (!isUndefOrZero(Mask[i]))
+ return false;
+ return true;
+}
+
+/// \brief Helper function to test whether a shuffle mask could be
+/// simplified by widening the elements being shuffled.
+///
+/// Appends the mask for wider elements in WidenedMask if valid. Otherwise
+/// leaves it in an unspecified state.
+///
+/// NOTE: This must handle normal vector shuffle masks and *target* vector
+/// shuffle masks. The latter have the special property of a '-2' representing
+/// a zero-ed lane of a vector.
+static bool canWidenShuffleElements(ArrayRef<int> Mask,
+ SmallVectorImpl<int> &WidenedMask) {
+ WidenedMask.assign(Mask.size() / 2, 0);
+ for (int i = 0, Size = Mask.size(); i < Size; i += 2) {
+ // If both elements are undef, its trivial.
+ if (Mask[i] == SM_SentinelUndef && Mask[i + 1] == SM_SentinelUndef) {
+ WidenedMask[i / 2] = SM_SentinelUndef;
+ continue;
+ }
+
+ // Check for an undef mask and a mask value properly aligned to fit with
+ // a pair of values. If we find such a case, use the non-undef mask's value.
+ if (Mask[i] == SM_SentinelUndef && Mask[i + 1] >= 0 &&
+ Mask[i + 1] % 2 == 1) {
+ WidenedMask[i / 2] = Mask[i + 1] / 2;
+ continue;
+ }
+ if (Mask[i + 1] == SM_SentinelUndef && Mask[i] >= 0 && Mask[i] % 2 == 0) {
+ WidenedMask[i / 2] = Mask[i] / 2;
+ continue;
+ }
+
+ // When zeroing, we need to spread the zeroing across both lanes to widen.
+ if (Mask[i] == SM_SentinelZero || Mask[i + 1] == SM_SentinelZero) {
+ if ((Mask[i] == SM_SentinelZero || Mask[i] == SM_SentinelUndef) &&
+ (Mask[i + 1] == SM_SentinelZero || Mask[i + 1] == SM_SentinelUndef)) {
+ WidenedMask[i / 2] = SM_SentinelZero;
+ continue;
+ }
+ return false;
+ }
+
+ // Finally check if the two mask values are adjacent and aligned with
+ // a pair.
+ if (Mask[i] != SM_SentinelUndef && Mask[i] % 2 == 0 &&
+ Mask[i] + 1 == Mask[i + 1]) {
+ WidenedMask[i / 2] = Mask[i] / 2;
+ continue;
+ }
+
+ // Otherwise we can't safely widen the elements used in this shuffle.
+ return false;
+ }
+ assert(WidenedMask.size() == Mask.size() / 2 &&
+ "Incorrect size of mask after widening the elements!");
+
+ return true;
+}
+
+/// Helper function to scale a shuffle or target shuffle mask, replacing each
+/// mask index with the scaled sequential indices for an equivalent narrowed
+/// mask. This is the reverse process to canWidenShuffleElements, but can always
+/// succeed.
+static void scaleShuffleMask(int Scale, ArrayRef<int> Mask,
+ SmallVectorImpl<int> &ScaledMask) {
+ assert(0 < Scale && "Unexpected scaling factor");
+ int NumElts = Mask.size();
+ ScaledMask.assign(NumElts * Scale, -1);
+
+ for (int i = 0; i != NumElts; ++i) {
+ int M = Mask[i];
+
+ // Repeat sentinel values in every mask element.
+ if (M < 0) {
+ for (int s = 0; s != Scale; ++s)
+ ScaledMask[(Scale * i) + s] = M;
+ continue;
+ }
+
+ // Scale mask element and increment across each mask element.
+ for (int s = 0; s != Scale; ++s)
+ ScaledMask[(Scale * i) + s] = (Scale * M) + s;
+ }
+}
+
/// Return true if the specified EXTRACT_SUBVECTOR operand specifies a vector
/// extract that is suitable for instruction that extract 128 or 256 bit vectors
static bool isVEXTRACTIndex(SDNode *N, unsigned vecWidth) {
@@ -4256,7 +4638,7 @@ static bool isVEXTRACTIndex(SDNode *N, unsigned vecWidth) {
cast<ConstantSDNode>(N->getOperand(1).getNode())->getZExtValue();
MVT VT = N->getSimpleValueType(0);
- unsigned ElSize = VT.getVectorElementType().getSizeInBits();
+ unsigned ElSize = VT.getScalarSizeInBits();
bool Result = (Index * ElSize) % vecWidth == 0;
return Result;
@@ -4274,7 +4656,7 @@ static bool isVINSERTIndex(SDNode *N, unsigned vecWidth) {
cast<ConstantSDNode>(N->getOperand(2).getNode())->getZExtValue();
MVT VT = N->getSimpleValueType(0);
- unsigned ElSize = VT.getVectorElementType().getSizeInBits();
+ unsigned ElSize = VT.getScalarSizeInBits();
bool Result = (Index * ElSize) % vecWidth == 0;
return Result;
@@ -4388,6 +4770,46 @@ static SDValue getConstVector(ArrayRef<int> Values, MVT VT, SelectionDAG &DAG,
return ConstsNode;
}
+static SDValue getConstVector(ArrayRef<APInt> Bits, SmallBitVector &Undefs,
+ MVT VT, SelectionDAG &DAG, const SDLoc &dl) {
+ assert(Bits.size() == Undefs.size() && "Unequal constant and undef arrays");
+ SmallVector<SDValue, 32> Ops;
+ bool Split = false;
+
+ MVT ConstVecVT = VT;
+ unsigned NumElts = VT.getVectorNumElements();
+ bool In64BitMode = DAG.getTargetLoweringInfo().isTypeLegal(MVT::i64);
+ if (!In64BitMode && VT.getVectorElementType() == MVT::i64) {
+ ConstVecVT = MVT::getVectorVT(MVT::i32, NumElts * 2);
+ Split = true;
+ }
+
+ MVT EltVT = ConstVecVT.getVectorElementType();
+ for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
+ if (Undefs[i]) {
+ Ops.append(Split ? 2 : 1, DAG.getUNDEF(EltVT));
+ continue;
+ }
+ const APInt &V = Bits[i];
+ assert(V.getBitWidth() == VT.getScalarSizeInBits() && "Unexpected sizes");
+ if (Split) {
+ Ops.push_back(DAG.getConstant(V.trunc(32), dl, EltVT));
+ Ops.push_back(DAG.getConstant(V.lshr(32).trunc(32), dl, EltVT));
+ } else if (EltVT == MVT::f32) {
+ APFloat FV(APFloat::IEEEsingle(), V);
+ Ops.push_back(DAG.getConstantFP(FV, dl, EltVT));
+ } else if (EltVT == MVT::f64) {
+ APFloat FV(APFloat::IEEEdouble(), V);
+ Ops.push_back(DAG.getConstantFP(FV, dl, EltVT));
+ } else {
+ Ops.push_back(DAG.getConstant(V, dl, EltVT));
+ }
+ }
+
+ SDValue ConstsNode = DAG.getBuildVector(ConstVecVT, dl, Ops);
+ return DAG.getBitcast(VT, ConstsNode);
+}
+
/// Returns a vector of specified type with all zero elements.
static SDValue getZeroVector(MVT VT, const X86Subtarget &Subtarget,
SelectionDAG &DAG, const SDLoc &dl) {
@@ -4416,8 +4838,6 @@ static SDValue getZeroVector(MVT VT, const X86Subtarget &Subtarget,
static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
const SDLoc &dl, unsigned vectorWidth) {
- assert((vectorWidth == 128 || vectorWidth == 256) &&
- "Unsupported vector width");
EVT VT = Vec.getValueType();
EVT ElVT = VT.getVectorElementType();
unsigned Factor = VT.getSizeInBits()/vectorWidth;
@@ -4438,8 +4858,8 @@ static SDValue extractSubVector(SDValue Vec, unsigned IdxVal, SelectionDAG &DAG,
// If the input is a buildvector just emit a smaller one.
if (Vec.getOpcode() == ISD::BUILD_VECTOR)
- return DAG.getNode(ISD::BUILD_VECTOR,
- dl, ResultVT, makeArrayRef(Vec->op_begin() + IdxVal, ElemsPerChunk));
+ return DAG.getNode(ISD::BUILD_VECTOR, dl, ResultVT,
+ makeArrayRef(Vec->op_begin() + IdxVal, ElemsPerChunk));
SDValue VecIdx = DAG.getIntPtrConstant(IdxVal, dl);
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, ResultVT, Vec, VecIdx);
@@ -4694,29 +5114,35 @@ static SDValue getOnesVector(EVT VT, const X86Subtarget &Subtarget,
return DAG.getBitcast(VT, Vec);
}
+/// Generate unpacklo/unpackhi shuffle mask.
+static void createUnpackShuffleMask(MVT VT, SmallVectorImpl<int> &Mask, bool Lo,
+ bool Unary) {
+ assert(Mask.empty() && "Expected an empty shuffle mask vector");
+ int NumElts = VT.getVectorNumElements();
+ int NumEltsInLane = 128 / VT.getScalarSizeInBits();
+
+ for (int i = 0; i < NumElts; ++i) {
+ unsigned LaneStart = (i / NumEltsInLane) * NumEltsInLane;
+ int Pos = (i % NumEltsInLane) / 2 + LaneStart;
+ Pos += (Unary ? 0 : NumElts * (i % 2));
+ Pos += (Lo ? 0 : NumEltsInLane / 2);
+ Mask.push_back(Pos);
+ }
+}
+
/// Returns a vector_shuffle node for an unpackl operation.
static SDValue getUnpackl(SelectionDAG &DAG, const SDLoc &dl, MVT VT,
SDValue V1, SDValue V2) {
- assert(VT.is128BitVector() && "Expected a 128-bit vector type");
- unsigned NumElems = VT.getVectorNumElements();
- SmallVector<int, 8> Mask(NumElems);
- for (unsigned i = 0, e = NumElems/2; i != e; ++i) {
- Mask[i * 2] = i;
- Mask[i * 2 + 1] = i + NumElems;
- }
+ SmallVector<int, 8> Mask;
+ createUnpackShuffleMask(VT, Mask, /* Lo = */ true, /* Unary = */ false);
return DAG.getVectorShuffle(VT, dl, V1, V2, Mask);
}
/// Returns a vector_shuffle node for an unpackh operation.
static SDValue getUnpackh(SelectionDAG &DAG, const SDLoc &dl, MVT VT,
SDValue V1, SDValue V2) {
- assert(VT.is128BitVector() && "Expected a 128-bit vector type");
- unsigned NumElems = VT.getVectorNumElements();
- SmallVector<int, 8> Mask(NumElems);
- for (unsigned i = 0, Half = NumElems/2; i != Half; ++i) {
- Mask[i * 2] = i + Half;
- Mask[i * 2 + 1] = i + NumElems + Half;
- }
+ SmallVector<int, 8> Mask;
+ createUnpackShuffleMask(VT, Mask, /* Lo = */ false, /* Unary = */ false);
return DAG.getVectorShuffle(VT, dl, V1, V2, Mask);
}
@@ -4745,6 +5171,135 @@ static SDValue peekThroughBitcasts(SDValue V) {
return V;
}
+static SDValue peekThroughOneUseBitcasts(SDValue V) {
+ while (V.getNode() && V.getOpcode() == ISD::BITCAST &&
+ V.getOperand(0).hasOneUse())
+ V = V.getOperand(0);
+ return V;
+}
+
+static const Constant *getTargetConstantFromNode(SDValue Op) {
+ Op = peekThroughBitcasts(Op);
+
+ auto *Load = dyn_cast<LoadSDNode>(Op);
+ if (!Load)
+ return nullptr;
+
+ SDValue Ptr = Load->getBasePtr();
+ if (Ptr->getOpcode() == X86ISD::Wrapper ||
+ Ptr->getOpcode() == X86ISD::WrapperRIP)
+ Ptr = Ptr->getOperand(0);
+
+ auto *CNode = dyn_cast<ConstantPoolSDNode>(Ptr);
+ if (!CNode || CNode->isMachineConstantPoolEntry())
+ return nullptr;
+
+ return dyn_cast<Constant>(CNode->getConstVal());
+}
+
+// Extract raw constant bits from constant pools.
+static bool getTargetConstantBitsFromNode(SDValue Op, unsigned EltSizeInBits,
+ SmallBitVector &UndefElts,
+ SmallVectorImpl<APInt> &EltBits) {
+ assert(UndefElts.empty() && "Expected an empty UndefElts vector");
+ assert(EltBits.empty() && "Expected an empty EltBits vector");
+
+ Op = peekThroughBitcasts(Op);
+
+ EVT VT = Op.getValueType();
+ unsigned SizeInBits = VT.getSizeInBits();
+ assert((SizeInBits % EltSizeInBits) == 0 && "Can't split constant!");
+ unsigned NumElts = SizeInBits / EltSizeInBits;
+
+ // Extract all the undef/constant element data and pack into single bitsets.
+ APInt UndefBits(SizeInBits, 0);
+ APInt MaskBits(SizeInBits, 0);
+
+ // Split the undef/constant single bitset data into the target elements.
+ auto SplitBitData = [&]() {
+ UndefElts = SmallBitVector(NumElts, false);
+ EltBits.resize(NumElts, APInt(EltSizeInBits, 0));
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ APInt UndefEltBits = UndefBits.lshr(i * EltSizeInBits);
+ UndefEltBits = UndefEltBits.zextOrTrunc(EltSizeInBits);
+
+ // Only treat an element as UNDEF if all bits are UNDEF, otherwise
+ // treat it as zero.
+ if (UndefEltBits.isAllOnesValue()) {
+ UndefElts[i] = true;
+ continue;
+ }
+
+ APInt Bits = MaskBits.lshr(i * EltSizeInBits);
+ Bits = Bits.zextOrTrunc(EltSizeInBits);
+ EltBits[i] = Bits.getZExtValue();
+ }
+ return true;
+ };
+
+ auto ExtractConstantBits = [SizeInBits](const Constant *Cst, APInt &Mask,
+ APInt &Undefs) {
+ if (!Cst)
+ return false;
+ unsigned CstSizeInBits = Cst->getType()->getPrimitiveSizeInBits();
+ if (isa<UndefValue>(Cst)) {
+ Mask = APInt::getNullValue(SizeInBits);
+ Undefs = APInt::getLowBitsSet(SizeInBits, CstSizeInBits);
+ return true;
+ }
+ if (auto *CInt = dyn_cast<ConstantInt>(Cst)) {
+ Mask = CInt->getValue().zextOrTrunc(SizeInBits);
+ Undefs = APInt::getNullValue(SizeInBits);
+ return true;
+ }
+ if (auto *CFP = dyn_cast<ConstantFP>(Cst)) {
+ Mask = CFP->getValueAPF().bitcastToAPInt().zextOrTrunc(SizeInBits);
+ Undefs = APInt::getNullValue(SizeInBits);
+ return true;
+ }
+ return false;
+ };
+
+ // Extract constant bits from constant pool vector.
+ if (auto *Cst = getTargetConstantFromNode(Op)) {
+ Type *CstTy = Cst->getType();
+ if (!CstTy->isVectorTy() || (SizeInBits != CstTy->getPrimitiveSizeInBits()))
+ return false;
+
+ unsigned CstEltSizeInBits = CstTy->getScalarSizeInBits();
+ for (unsigned i = 0, e = CstTy->getVectorNumElements(); i != e; ++i) {
+ APInt Bits, Undefs;
+ if (!ExtractConstantBits(Cst->getAggregateElement(i), Bits, Undefs))
+ return false;
+ MaskBits |= Bits.shl(i * CstEltSizeInBits);
+ UndefBits |= Undefs.shl(i * CstEltSizeInBits);
+ }
+
+ return SplitBitData();
+ }
+
+ // Extract constant bits from a broadcasted constant pool scalar.
+ if (Op.getOpcode() == X86ISD::VBROADCAST &&
+ EltSizeInBits <= Op.getScalarValueSizeInBits()) {
+ if (auto *Broadcast = getTargetConstantFromNode(Op.getOperand(0))) {
+ APInt Bits, Undefs;
+ if (ExtractConstantBits(Broadcast, Bits, Undefs)) {
+ unsigned NumBroadcastBits = Op.getScalarValueSizeInBits();
+ unsigned NumBroadcastElts = SizeInBits / NumBroadcastBits;
+ for (unsigned i = 0; i != NumBroadcastElts; ++i) {
+ MaskBits |= Bits.shl(i * NumBroadcastBits);
+ UndefBits |= Undefs.shl(i * NumBroadcastBits);
+ }
+ return SplitBitData();
+ }
+ }
+ }
+
+ return false;
+}
+
+// TODO: Merge more of this with getTargetConstantBitsFromNode.
static bool getTargetShuffleMaskIndices(SDValue MaskNode,
unsigned MaskEltSizeInBits,
SmallVectorImpl<uint64_t> &RawMask) {
@@ -4752,6 +5307,7 @@ static bool getTargetShuffleMaskIndices(SDValue MaskNode,
MVT VT = MaskNode.getSimpleValueType();
assert(VT.isVector() && "Can't produce a non-vector with a build_vector!");
+ unsigned NumMaskElts = VT.getSizeInBits() / MaskEltSizeInBits;
// Split an APInt element into MaskEltSizeInBits sized pieces and
// insert into the shuffle mask.
@@ -4783,17 +5339,20 @@ static bool getTargetShuffleMaskIndices(SDValue MaskNode,
if (MaskNode.getOpcode() == X86ISD::VZEXT_MOVL &&
MaskNode.getOperand(0).getOpcode() == ISD::SCALAR_TO_VECTOR) {
-
- // TODO: Handle (MaskEltSizeInBits % VT.getScalarSizeInBits()) == 0
- if ((VT.getScalarSizeInBits() % MaskEltSizeInBits) != 0)
- return false;
- unsigned ElementSplit = VT.getScalarSizeInBits() / MaskEltSizeInBits;
-
SDValue MaskOp = MaskNode.getOperand(0).getOperand(0);
if (auto *CN = dyn_cast<ConstantSDNode>(MaskOp)) {
- SplitElementToMask(CN->getAPIntValue());
- RawMask.append((VT.getVectorNumElements() - 1) * ElementSplit, 0);
- return true;
+ if ((MaskEltSizeInBits % VT.getScalarSizeInBits()) == 0) {
+ RawMask.push_back(CN->getZExtValue());
+ RawMask.append(NumMaskElts - 1, 0);
+ return true;
+ }
+
+ if ((VT.getScalarSizeInBits() % MaskEltSizeInBits) == 0) {
+ unsigned ElementSplit = VT.getScalarSizeInBits() / MaskEltSizeInBits;
+ SplitElementToMask(CN->getAPIntValue());
+ RawMask.append((VT.getVectorNumElements() - 1) * ElementSplit, 0);
+ return true;
+ }
}
return false;
}
@@ -4803,8 +5362,8 @@ static bool getTargetShuffleMaskIndices(SDValue MaskNode,
// We can always decode if the buildvector is all zero constants,
// but can't use isBuildVectorAllZeros as it might contain UNDEFs.
- if (llvm::all_of(MaskNode->ops(), X86::isZeroNode)) {
- RawMask.append(VT.getSizeInBits() / MaskEltSizeInBits, 0);
+ if (all_of(MaskNode->ops(), X86::isZeroNode)) {
+ RawMask.append(NumMaskElts, 0);
return true;
}
@@ -4824,25 +5383,6 @@ static bool getTargetShuffleMaskIndices(SDValue MaskNode,
return true;
}
-static const Constant *getTargetShuffleMaskConstant(SDValue MaskNode) {
- MaskNode = peekThroughBitcasts(MaskNode);
-
- auto *MaskLoad = dyn_cast<LoadSDNode>(MaskNode);
- if (!MaskLoad)
- return nullptr;
-
- SDValue Ptr = MaskLoad->getBasePtr();
- if (Ptr->getOpcode() == X86ISD::Wrapper ||
- Ptr->getOpcode() == X86ISD::WrapperRIP)
- Ptr = Ptr->getOperand(0);
-
- auto *MaskCP = dyn_cast<ConstantPoolSDNode>(Ptr);
- if (!MaskCP || MaskCP->isMachineConstantPoolEntry())
- return nullptr;
-
- return dyn_cast<Constant>(MaskCP->getConstVal());
-}
-
/// Calculates the shuffle mask corresponding to the target-specific opcode.
/// If the mask could be calculated, returns it in \p Mask, returns the shuffle
/// operands in \p Ops, and returns true.
@@ -4896,6 +5436,9 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
assert(VT.getScalarType() == MVT::i8 && "Byte vector expected");
ImmN = N->getOperand(N->getNumOperands()-1);
DecodePALIGNRMask(VT, cast<ConstantSDNode>(ImmN)->getZExtValue(), Mask);
+ IsUnary = IsFakeUnary = N->getOperand(0) == N->getOperand(1);
+ Ops.push_back(N->getOperand(1));
+ Ops.push_back(N->getOperand(0));
break;
case X86ISD::VSHLDQ:
assert(VT.getScalarType() == MVT::i8 && "Byte vector expected");
@@ -4947,7 +5490,7 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
DecodeVPERMILPMask(VT, RawMask, Mask);
break;
}
- if (auto *C = getTargetShuffleMaskConstant(MaskNode)) {
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
DecodeVPERMILPMask(C, MaskEltSize, Mask);
break;
}
@@ -4961,7 +5504,7 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
DecodePSHUFBMask(RawMask, Mask);
break;
}
- if (auto *C = getTargetShuffleMaskConstant(MaskNode)) {
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
DecodePSHUFBMask(C, Mask);
break;
}
@@ -5010,7 +5553,7 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
DecodeVPERMIL2PMask(VT, CtrlImm, RawMask, Mask);
break;
}
- if (auto *C = getTargetShuffleMaskConstant(MaskNode)) {
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
DecodeVPERMIL2PMask(C, CtrlImm, MaskEltSize, Mask);
break;
}
@@ -5025,7 +5568,7 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
DecodeVPPERMMask(RawMask, Mask);
break;
}
- if (auto *C = getTargetShuffleMaskConstant(MaskNode)) {
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
DecodeVPPERMMask(C, Mask);
break;
}
@@ -5042,8 +5585,8 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
DecodeVPERMVMask(RawMask, Mask);
break;
}
- if (auto *C = getTargetShuffleMaskConstant(MaskNode)) {
- DecodeVPERMVMask(C, VT, Mask);
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
+ DecodeVPERMVMask(C, MaskEltSize, Mask);
break;
}
return false;
@@ -5054,8 +5597,22 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
Ops.push_back(N->getOperand(0));
Ops.push_back(N->getOperand(2));
SDValue MaskNode = N->getOperand(1);
- if (auto *C = getTargetShuffleMaskConstant(MaskNode)) {
- DecodeVPERMV3Mask(C, VT, Mask);
+ unsigned MaskEltSize = VT.getScalarSizeInBits();
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
+ DecodeVPERMV3Mask(C, MaskEltSize, Mask);
+ break;
+ }
+ return false;
+ }
+ case X86ISD::VPERMIV3: {
+ IsUnary = IsFakeUnary = N->getOperand(1) == N->getOperand(2);
+ // Unlike most shuffle nodes, VPERMIV3's mask operand is the first one.
+ Ops.push_back(N->getOperand(1));
+ Ops.push_back(N->getOperand(2));
+ SDValue MaskNode = N->getOperand(0);
+ unsigned MaskEltSize = VT.getScalarSizeInBits();
+ if (auto *C = getTargetConstantFromNode(MaskNode)) {
+ DecodeVPERMV3Mask(C, MaskEltSize, Mask);
break;
}
return false;
@@ -5069,7 +5626,7 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
// Check if we're getting a shuffle mask with zero'd elements.
if (!AllowSentinelZero)
- if (llvm::any_of(Mask, [](int M) { return M == SM_SentinelZero; }))
+ if (any_of(Mask, [](int M) { return M == SM_SentinelZero; }))
return false;
// If we have a fake unary shuffle, the shuffle mask is spread across two
@@ -5101,8 +5658,9 @@ static bool setTargetShuffleZeroElements(SDValue N,
bool IsUnary;
if (!isTargetShuffle(N.getOpcode()))
return false;
- if (!getTargetShuffleMask(N.getNode(), N.getSimpleValueType(), true, Ops,
- Mask, IsUnary))
+
+ MVT VT = N.getSimpleValueType();
+ if (!getTargetShuffleMask(N.getNode(), VT, true, Ops, Mask, IsUnary))
return false;
SDValue V1 = Ops[0];
@@ -5164,9 +5722,94 @@ static bool setTargetShuffleZeroElements(SDValue N,
}
}
+ assert(VT.getVectorNumElements() == Mask.size() &&
+ "Different mask size from vector size!");
return true;
}
+// Attempt to decode ops that could be represented as a shuffle mask.
+// The decoded shuffle mask may contain a different number of elements to the
+// destination value type.
+static bool getFauxShuffleMask(SDValue N, SmallVectorImpl<int> &Mask,
+ SmallVectorImpl<SDValue> &Ops) {
+ Mask.clear();
+ Ops.clear();
+
+ MVT VT = N.getSimpleValueType();
+ unsigned NumElts = VT.getVectorNumElements();
+ unsigned NumSizeInBits = VT.getSizeInBits();
+ unsigned NumBitsPerElt = VT.getScalarSizeInBits();
+ assert((NumBitsPerElt % 8) == 0 && (NumSizeInBits % 8) == 0 &&
+ "Expected byte aligned value types");
+
+ unsigned Opcode = N.getOpcode();
+ switch (Opcode) {
+ case ISD::AND: {
+ // Attempt to decode as a per-byte mask.
+ SmallBitVector UndefElts;
+ SmallVector<APInt, 32> EltBits;
+ if (!getTargetConstantBitsFromNode(N.getOperand(1), 8, UndefElts, EltBits))
+ return false;
+ for (int i = 0, e = (int)EltBits.size(); i != e; ++i) {
+ if (UndefElts[i]) {
+ Mask.push_back(SM_SentinelUndef);
+ continue;
+ }
+ uint64_t ByteBits = EltBits[i].getZExtValue();
+ if (ByteBits != 0 && ByteBits != 255)
+ return false;
+ Mask.push_back(ByteBits == 0 ? SM_SentinelZero : i);
+ }
+ Ops.push_back(N.getOperand(0));
+ return true;
+ }
+ case X86ISD::VSHLI:
+ case X86ISD::VSRLI: {
+ uint64_t ShiftVal = N.getConstantOperandVal(1);
+ // Out of range bit shifts are guaranteed to be zero.
+ if (NumBitsPerElt <= ShiftVal) {
+ Mask.append(NumElts, SM_SentinelZero);
+ return true;
+ }
+
+ // We can only decode 'whole byte' bit shifts as shuffles.
+ if ((ShiftVal % 8) != 0)
+ break;
+
+ uint64_t ByteShift = ShiftVal / 8;
+ unsigned NumBytes = NumSizeInBits / 8;
+ unsigned NumBytesPerElt = NumBitsPerElt / 8;
+ Ops.push_back(N.getOperand(0));
+
+ // Clear mask to all zeros and insert the shifted byte indices.
+ Mask.append(NumBytes, SM_SentinelZero);
+
+ if (X86ISD::VSHLI == Opcode) {
+ for (unsigned i = 0; i != NumBytes; i += NumBytesPerElt)
+ for (unsigned j = ByteShift; j != NumBytesPerElt; ++j)
+ Mask[i + j] = i + j - ByteShift;
+ } else {
+ for (unsigned i = 0; i != NumBytes; i += NumBytesPerElt)
+ for (unsigned j = ByteShift; j != NumBytesPerElt; ++j)
+ Mask[i + j - ByteShift] = i + j;
+ }
+ return true;
+ }
+ case X86ISD::VZEXT: {
+ // TODO - add support for VPMOVZX with smaller input vector types.
+ SDValue Src = N.getOperand(0);
+ MVT SrcVT = Src.getSimpleValueType();
+ if (NumSizeInBits != SrcVT.getSizeInBits())
+ break;
+ DecodeZeroExtendMask(SrcVT.getScalarType(), VT, Mask);
+ Ops.push_back(Src);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Calls setTargetShuffleZeroElements to resolve a target shuffle mask's inputs
/// and set the SM_SentinelUndef and SM_SentinelZero values. Then check the
/// remaining input indices in case we now have a unary shuffle and adjust the
@@ -5176,14 +5819,14 @@ static bool resolveTargetShuffleInputs(SDValue Op, SDValue &Op0, SDValue &Op1,
SmallVectorImpl<int> &Mask) {
SmallVector<SDValue, 2> Ops;
if (!setTargetShuffleZeroElements(Op, Mask, Ops))
- return false;
+ if (!getFauxShuffleMask(Op, Mask, Ops))
+ return false;
int NumElts = Mask.size();
- bool Op0InUse = std::any_of(Mask.begin(), Mask.end(), [NumElts](int Idx) {
+ bool Op0InUse = any_of(Mask, [NumElts](int Idx) {
return 0 <= Idx && Idx < NumElts;
});
- bool Op1InUse = std::any_of(Mask.begin(), Mask.end(),
- [NumElts](int Idx) { return NumElts <= Idx; });
+ bool Op1InUse = any_of(Mask, [NumElts](int Idx) { return NumElts <= Idx; });
Op0 = Op0InUse ? Ops[0] : SDValue();
Op1 = Op1InUse ? Ops[1] : SDValue();
@@ -5523,15 +6166,15 @@ static SDValue LowerAsSplatVectorLoad(SDValue SrcOp, MVT VT, const SDLoc &dl,
unsigned RequiredAlign = VT.getSizeInBits()/8;
SDValue Chain = LD->getChain();
// Make sure the stack object alignment is at least 16 or 32.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
if (DAG.InferPtrAlignment(Ptr) < RequiredAlign) {
- if (MFI->isFixedObjectIndex(FI)) {
+ if (MFI.isFixedObjectIndex(FI)) {
// Can't change the alignment. FIXME: It's possible to compute
// the exact stack offset and reference FI + adjust offset instead.
// If someone *really* cares about this. That's the way to implement it.
return SDValue();
} else {
- MFI->setObjectAlignment(FI, RequiredAlign);
+ MFI.setObjectAlignment(FI, RequiredAlign);
}
}
@@ -5697,11 +6340,13 @@ static SDValue EltsFromConsecutiveLoads(EVT VT, ArrayRef<SDValue> Elts,
int LoadSize =
(1 + LastLoadedElt - FirstLoadedElt) * LDBaseVT.getStoreSizeInBits();
- // VZEXT_LOAD - consecutive load/undefs followed by zeros/undefs.
- if (IsConsecutiveLoad && FirstLoadedElt == 0 && LoadSize == 64 &&
+ // VZEXT_LOAD - consecutive 32/64-bit load/undefs followed by zeros/undefs.
+ if (IsConsecutiveLoad && FirstLoadedElt == 0 &&
+ (LoadSize == 32 || LoadSize == 64) &&
((VT.is128BitVector() || VT.is256BitVector() || VT.is512BitVector()))) {
- MVT VecSVT = VT.isFloatingPoint() ? MVT::f64 : MVT::i64;
- MVT VecVT = MVT::getVectorVT(VecSVT, VT.getSizeInBits() / 64);
+ MVT VecSVT = VT.isFloatingPoint() ? MVT::getFloatingPointVT(LoadSize)
+ : MVT::getIntegerVT(LoadSize);
+ MVT VecVT = MVT::getVectorVT(VecSVT, VT.getSizeInBits() / LoadSize);
if (TLI.isTypeLegal(VecVT)) {
SDVTList Tys = DAG.getVTList(VecVT, MVT::Other);
SDValue Ops[] = { LDBase->getChain(), LDBase->getBasePtr() };
@@ -5728,31 +6373,53 @@ static SDValue EltsFromConsecutiveLoads(EVT VT, ArrayRef<SDValue> Elts,
}
}
- // VZEXT_MOVL - consecutive 32-bit load/undefs followed by zeros/undefs.
- if (IsConsecutiveLoad && FirstLoadedElt == 0 && LoadSize == 32 &&
- ((VT.is128BitVector() || VT.is256BitVector() || VT.is512BitVector()))) {
- MVT VecSVT = VT.isFloatingPoint() ? MVT::f32 : MVT::i32;
- MVT VecVT = MVT::getVectorVT(VecSVT, VT.getSizeInBits() / 32);
- if (TLI.isTypeLegal(VecVT)) {
- SDValue V = LastLoadedElt != 0 ? CreateLoad(VecSVT, LDBase)
- : DAG.getBitcast(VecSVT, EltBase);
- V = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, V);
- V = DAG.getNode(X86ISD::VZEXT_MOVL, DL, VecVT, V);
- return DAG.getBitcast(VT, V);
- }
+ return SDValue();
+}
+
+static Constant *getConstantVector(MVT VT, APInt SplatValue,
+ unsigned SplatBitSize, LLVMContext &C) {
+ unsigned ScalarSize = VT.getScalarSizeInBits();
+ unsigned NumElm = SplatBitSize / ScalarSize;
+
+ SmallVector<Constant *, 32> ConstantVec;
+ for (unsigned i = 0; i < NumElm; i++) {
+ APInt Val = SplatValue.lshr(ScalarSize * i).trunc(ScalarSize);
+ Constant *Const;
+ if (VT.isFloatingPoint()) {
+ assert((ScalarSize == 32 || ScalarSize == 64) &&
+ "Unsupported floating point scalar size");
+ if (ScalarSize == 32)
+ Const = ConstantFP::get(Type::getFloatTy(C), Val.bitsToFloat());
+ else
+ Const = ConstantFP::get(Type::getDoubleTy(C), Val.bitsToDouble());
+ } else
+ Const = Constant::getIntegerValue(Type::getIntNTy(C, ScalarSize), Val);
+ ConstantVec.push_back(Const);
}
+ return ConstantVector::get(ArrayRef<Constant *>(ConstantVec));
+}
- return SDValue();
+static bool isUseOfShuffle(SDNode *N) {
+ for (auto *U : N->uses()) {
+ if (isTargetShuffle(U->getOpcode()))
+ return true;
+ if (U->getOpcode() == ISD::BITCAST) // Ignore bitcasts
+ return isUseOfShuffle(U);
+ }
+ return false;
}
/// Attempt to use the vbroadcast instruction to generate a splat value for the
/// following cases:
-/// 1. A splat BUILD_VECTOR which uses a single scalar load, or a constant.
+/// 1. A splat BUILD_VECTOR which uses:
+/// a. A single scalar load, or a constant.
+/// b. Repeated pattern of constants (e.g. <0,1,0,1> or <0,1,2,3,0,1,2,3>).
/// 2. A splat shuffle which uses a scalar_to_vector node which comes from
/// a scalar load, or a constant.
+///
/// The VBROADCAST node is returned when a pattern is found,
/// or SDValue() otherwise.
-static SDValue LowerVectorBroadcast(SDValue Op, const X86Subtarget &Subtarget,
+static SDValue LowerVectorBroadcast(BuildVectorSDNode *BVOp, const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
// VBROADCAST requires AVX.
// TODO: Splats could be generated for non-AVX CPUs using SSE
@@ -5760,81 +6427,103 @@ static SDValue LowerVectorBroadcast(SDValue Op, const X86Subtarget &Subtarget,
if (!Subtarget.hasAVX())
return SDValue();
- MVT VT = Op.getSimpleValueType();
- SDLoc dl(Op);
+ MVT VT = BVOp->getSimpleValueType(0);
+ SDLoc dl(BVOp);
assert((VT.is128BitVector() || VT.is256BitVector() || VT.is512BitVector()) &&
"Unsupported vector type for broadcast.");
- SDValue Ld;
- bool ConstSplatVal;
-
- switch (Op.getOpcode()) {
- default:
- // Unknown pattern found.
- return SDValue();
-
- case ISD::BUILD_VECTOR: {
- auto *BVOp = cast<BuildVectorSDNode>(Op.getNode());
- BitVector UndefElements;
- SDValue Splat = BVOp->getSplatValue(&UndefElements);
-
- // We need a splat of a single value to use broadcast, and it doesn't
- // make any sense if the value is only in one element of the vector.
- if (!Splat || (VT.getVectorNumElements() - UndefElements.count()) <= 1)
+ BitVector UndefElements;
+ SDValue Ld = BVOp->getSplatValue(&UndefElements);
+
+ // We need a splat of a single value to use broadcast, and it doesn't
+ // make any sense if the value is only in one element of the vector.
+ if (!Ld || (VT.getVectorNumElements() - UndefElements.count()) <= 1) {
+ APInt SplatValue, Undef;
+ unsigned SplatBitSize;
+ bool HasUndef;
+ // Check if this is a repeated constant pattern suitable for broadcasting.
+ if (BVOp->isConstantSplat(SplatValue, Undef, SplatBitSize, HasUndef) &&
+ SplatBitSize > VT.getScalarSizeInBits() &&
+ SplatBitSize < VT.getSizeInBits()) {
+ // Avoid replacing with broadcast when it's a use of a shuffle
+ // instruction to preserve the present custom lowering of shuffles.
+ if (isUseOfShuffle(BVOp) || BVOp->hasOneUse())
return SDValue();
-
- Ld = Splat;
- ConstSplatVal = (Ld.getOpcode() == ISD::Constant ||
- Ld.getOpcode() == ISD::ConstantFP);
-
- // Make sure that all of the users of a non-constant load are from the
- // BUILD_VECTOR node.
- if (!ConstSplatVal && !BVOp->isOnlyUserOf(Ld.getNode()))
- return SDValue();
- break;
- }
-
- case ISD::VECTOR_SHUFFLE: {
- ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op);
-
- // Shuffles must have a splat mask where the first element is
- // broadcasted.
- if ((!SVOp->isSplat()) || SVOp->getMaskElt(0) != 0)
- return SDValue();
-
- SDValue Sc = Op.getOperand(0);
- if (Sc.getOpcode() != ISD::SCALAR_TO_VECTOR &&
- Sc.getOpcode() != ISD::BUILD_VECTOR) {
-
- if (!Subtarget.hasInt256())
- return SDValue();
-
- // Use the register form of the broadcast instruction available on AVX2.
- if (VT.getSizeInBits() >= 256)
- Sc = extract128BitVector(Sc, 0, DAG, dl);
- return DAG.getNode(X86ISD::VBROADCAST, dl, VT, Sc);
+ // replace BUILD_VECTOR with broadcast of the repeated constants.
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ LLVMContext *Ctx = DAG.getContext();
+ MVT PVT = TLI.getPointerTy(DAG.getDataLayout());
+ if (Subtarget.hasAVX()) {
+ if (SplatBitSize <= 64 && Subtarget.hasAVX2() &&
+ !(SplatBitSize == 64 && Subtarget.is32Bit())) {
+ // Splatted value can fit in one INTEGER constant in constant pool.
+ // Load the constant and broadcast it.
+ MVT CVT = MVT::getIntegerVT(SplatBitSize);
+ Type *ScalarTy = Type::getIntNTy(*Ctx, SplatBitSize);
+ Constant *C = Constant::getIntegerValue(ScalarTy, SplatValue);
+ SDValue CP = DAG.getConstantPool(C, PVT);
+ unsigned Repeat = VT.getSizeInBits() / SplatBitSize;
+
+ unsigned Alignment = cast<ConstantPoolSDNode>(CP)->getAlignment();
+ Ld = DAG.getLoad(
+ CVT, dl, DAG.getEntryNode(), CP,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()),
+ Alignment);
+ SDValue Brdcst = DAG.getNode(X86ISD::VBROADCAST, dl,
+ MVT::getVectorVT(CVT, Repeat), Ld);
+ return DAG.getBitcast(VT, Brdcst);
+ } else if (SplatBitSize == 32 || SplatBitSize == 64) {
+ // Splatted value can fit in one FLOAT constant in constant pool.
+ // Load the constant and broadcast it.
+ // AVX have support for 32 and 64 bit broadcast for floats only.
+ // No 64bit integer in 32bit subtarget.
+ MVT CVT = MVT::getFloatingPointVT(SplatBitSize);
+ Constant *C = SplatBitSize == 32
+ ? ConstantFP::get(Type::getFloatTy(*Ctx),
+ SplatValue.bitsToFloat())
+ : ConstantFP::get(Type::getDoubleTy(*Ctx),
+ SplatValue.bitsToDouble());
+ SDValue CP = DAG.getConstantPool(C, PVT);
+ unsigned Repeat = VT.getSizeInBits() / SplatBitSize;
+
+ unsigned Alignment = cast<ConstantPoolSDNode>(CP)->getAlignment();
+ Ld = DAG.getLoad(
+ CVT, dl, DAG.getEntryNode(), CP,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()),
+ Alignment);
+ SDValue Brdcst = DAG.getNode(X86ISD::VBROADCAST, dl,
+ MVT::getVectorVT(CVT, Repeat), Ld);
+ return DAG.getBitcast(VT, Brdcst);
+ } else if (SplatBitSize > 64) {
+ // Load the vector of constants and broadcast it.
+ MVT CVT = VT.getScalarType();
+ Constant *VecC = getConstantVector(VT, SplatValue, SplatBitSize,
+ *Ctx);
+ SDValue VCP = DAG.getConstantPool(VecC, PVT);
+ unsigned NumElm = SplatBitSize / VT.getScalarSizeInBits();
+ unsigned Alignment = cast<ConstantPoolSDNode>(VCP)->getAlignment();
+ Ld = DAG.getLoad(
+ MVT::getVectorVT(CVT, NumElm), dl, DAG.getEntryNode(), VCP,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()),
+ Alignment);
+ SDValue Brdcst = DAG.getNode(X86ISD::SUBV_BROADCAST, dl, VT, Ld);
+ return DAG.getBitcast(VT, Brdcst);
+ }
}
-
- Ld = Sc.getOperand(0);
- ConstSplatVal = (Ld.getOpcode() == ISD::Constant ||
- Ld.getOpcode() == ISD::ConstantFP);
-
- // The scalar_to_vector node and the suspected
- // load node must have exactly one user.
- // Constants may have multiple users.
-
- // AVX-512 has register version of the broadcast
- bool hasRegVer = Subtarget.hasAVX512() && VT.is512BitVector() &&
- Ld.getValueType().getSizeInBits() >= 32;
- if (!ConstSplatVal && ((!Sc.hasOneUse() || !Ld.hasOneUse()) &&
- !hasRegVer))
- return SDValue();
- break;
}
+ return SDValue();
}
- unsigned ScalarSize = Ld.getValueType().getSizeInBits();
+ bool ConstSplatVal =
+ (Ld.getOpcode() == ISD::Constant || Ld.getOpcode() == ISD::ConstantFP);
+
+ // Make sure that all of the users of a non-constant load are from the
+ // BUILD_VECTOR node.
+ if (!ConstSplatVal && !BVOp->isOnlyUserOf(Ld.getNode()))
+ return SDValue();
+
+ unsigned ScalarSize = Ld.getValueSizeInBits();
bool IsGE256 = (VT.getSizeInBits() >= 256);
// When optimizing for size, generate up to 5 extra bytes for a broadcast
@@ -6025,8 +6714,7 @@ static SDValue ConvertI1VectorToInteger(SDValue Op, SelectionDAG &DAG) {
Immediate |= cast<ConstantSDNode>(In)->getZExtValue() << idx;
}
SDLoc dl(Op);
- MVT VT =
- MVT::getIntegerVT(std::max((int)Op.getValueType().getSizeInBits(), 8));
+ MVT VT = MVT::getIntegerVT(std::max((int)Op.getValueSizeInBits(), 8));
return DAG.getConstant(Immediate, dl, VT);
}
// Lower BUILD_VECTOR operation for v8i1 and v16i1 types.
@@ -6273,23 +6961,24 @@ static SDValue ExpandHorizontalBinOp(const SDValue &V0, const SDValue &V1,
return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, LO, HI);
}
-/// Try to fold a build_vector that performs an 'addsub' to an X86ISD::ADDSUB
-/// node.
-static SDValue LowerToAddSub(const BuildVectorSDNode *BV,
- const X86Subtarget &Subtarget, SelectionDAG &DAG) {
+/// Returns true iff \p BV builds a vector with the result equivalent to
+/// the result of ADDSUB operation.
+/// If true is returned then the operands of ADDSUB = Opnd0 +- Opnd1 operation
+/// are written to the parameters \p Opnd0 and \p Opnd1.
+static bool isAddSub(const BuildVectorSDNode *BV,
+ const X86Subtarget &Subtarget, SelectionDAG &DAG,
+ SDValue &Opnd0, SDValue &Opnd1) {
+
MVT VT = BV->getSimpleValueType(0);
if ((!Subtarget.hasSSE3() || (VT != MVT::v4f32 && VT != MVT::v2f64)) &&
- (!Subtarget.hasAVX() || (VT != MVT::v8f32 && VT != MVT::v4f64)))
- return SDValue();
+ (!Subtarget.hasAVX() || (VT != MVT::v8f32 && VT != MVT::v4f64)) &&
+ (!Subtarget.hasAVX512() || (VT != MVT::v16f32 && VT != MVT::v8f64)))
+ return false;
- SDLoc DL(BV);
unsigned NumElts = VT.getVectorNumElements();
SDValue InVec0 = DAG.getUNDEF(VT);
SDValue InVec1 = DAG.getUNDEF(VT);
- assert((VT == MVT::v8f32 || VT == MVT::v4f64 || VT == MVT::v4f32 ||
- VT == MVT::v2f64) && "build_vector with an invalid type found!");
-
// Odd-numbered elements in the input build vector are obtained from
// adding two integer/float elements.
// Even-numbered elements in the input build vector are obtained from
@@ -6311,7 +7000,7 @@ static SDValue LowerToAddSub(const BuildVectorSDNode *BV,
// Early exit if we found an unexpected opcode.
if (Opcode != ExpectedOpcode)
- return SDValue();
+ return false;
SDValue Op0 = Op.getOperand(0);
SDValue Op1 = Op.getOperand(1);
@@ -6324,11 +7013,11 @@ static SDValue LowerToAddSub(const BuildVectorSDNode *BV,
!isa<ConstantSDNode>(Op0.getOperand(1)) ||
!isa<ConstantSDNode>(Op1.getOperand(1)) ||
Op0.getOperand(1) != Op1.getOperand(1))
- return SDValue();
+ return false;
unsigned I0 = cast<ConstantSDNode>(Op0.getOperand(1))->getZExtValue();
if (I0 != i)
- return SDValue();
+ return false;
// We found a valid add/sub node. Update the information accordingly.
if (i & 1)
@@ -6340,39 +7029,118 @@ static SDValue LowerToAddSub(const BuildVectorSDNode *BV,
if (InVec0.isUndef()) {
InVec0 = Op0.getOperand(0);
if (InVec0.getSimpleValueType() != VT)
- return SDValue();
+ return false;
}
if (InVec1.isUndef()) {
InVec1 = Op1.getOperand(0);
if (InVec1.getSimpleValueType() != VT)
- return SDValue();
+ return false;
}
// Make sure that operands in input to each add/sub node always
// come from a same pair of vectors.
if (InVec0 != Op0.getOperand(0)) {
if (ExpectedOpcode == ISD::FSUB)
- return SDValue();
+ return false;
// FADD is commutable. Try to commute the operands
// and then test again.
std::swap(Op0, Op1);
if (InVec0 != Op0.getOperand(0))
- return SDValue();
+ return false;
}
if (InVec1 != Op1.getOperand(0))
- return SDValue();
+ return false;
// Update the pair of expected opcodes.
std::swap(ExpectedOpcode, NextExpectedOpcode);
}
// Don't try to fold this build_vector into an ADDSUB if the inputs are undef.
- if (AddFound && SubFound && !InVec0.isUndef() && !InVec1.isUndef())
- return DAG.getNode(X86ISD::ADDSUB, DL, VT, InVec0, InVec1);
+ if (!AddFound || !SubFound || InVec0.isUndef() || InVec1.isUndef())
+ return false;
- return SDValue();
+ Opnd0 = InVec0;
+ Opnd1 = InVec1;
+ return true;
+}
+
+/// Returns true if is possible to fold MUL and an idiom that has already been
+/// recognized as ADDSUB(\p Opnd0, \p Opnd1) into FMADDSUB(x, y, \p Opnd1).
+/// If (and only if) true is returned, the operands of FMADDSUB are written to
+/// parameters \p Opnd0, \p Opnd1, \p Opnd2.
+///
+/// Prior to calling this function it should be known that there is some
+/// SDNode that potentially can be replaced with an X86ISD::ADDSUB operation
+/// using \p Opnd0 and \p Opnd1 as operands. Also, this method is called
+/// before replacement of such SDNode with ADDSUB operation. Thus the number
+/// of \p Opnd0 uses is expected to be equal to 2.
+/// For example, this function may be called for the following IR:
+/// %AB = fmul fast <2 x double> %A, %B
+/// %Sub = fsub fast <2 x double> %AB, %C
+/// %Add = fadd fast <2 x double> %AB, %C
+/// %Addsub = shufflevector <2 x double> %Sub, <2 x double> %Add,
+/// <2 x i32> <i32 0, i32 3>
+/// There is a def for %Addsub here, which potentially can be replaced by
+/// X86ISD::ADDSUB operation:
+/// %Addsub = X86ISD::ADDSUB %AB, %C
+/// and such ADDSUB can further be replaced with FMADDSUB:
+/// %Addsub = FMADDSUB %A, %B, %C.
+///
+/// The main reason why this method is called before the replacement of the
+/// recognized ADDSUB idiom with ADDSUB operation is that such replacement
+/// is illegal sometimes. E.g. 512-bit ADDSUB is not available, while 512-bit
+/// FMADDSUB is.
+static bool isFMAddSub(const X86Subtarget &Subtarget, SelectionDAG &DAG,
+ SDValue &Opnd0, SDValue &Opnd1, SDValue &Opnd2) {
+ if (Opnd0.getOpcode() != ISD::FMUL || Opnd0->use_size() != 2 ||
+ !Subtarget.hasAnyFMA())
+ return false;
+
+ // FIXME: These checks must match the similar ones in
+ // DAGCombiner::visitFADDForFMACombine. It would be good to have one
+ // function that would answer if it is Ok to fuse MUL + ADD to FMADD
+ // or MUL + ADDSUB to FMADDSUB.
+ const TargetOptions &Options = DAG.getTarget().Options;
+ bool AllowFusion =
+ (Options.AllowFPOpFusion == FPOpFusion::Fast || Options.UnsafeFPMath);
+ if (!AllowFusion)
+ return false;
+
+ Opnd2 = Opnd1;
+ Opnd1 = Opnd0.getOperand(1);
+ Opnd0 = Opnd0.getOperand(0);
+
+ return true;
+}
+
+/// Try to fold a build_vector that performs an 'addsub' or 'fmaddsub' operation
+/// accordingly to X86ISD::ADDSUB or X86ISD::FMADDSUB node.
+static SDValue lowerToAddSubOrFMAddSub(const BuildVectorSDNode *BV,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
+ SDValue Opnd0, Opnd1;
+ if (!isAddSub(BV, Subtarget, DAG, Opnd0, Opnd1))
+ return SDValue();
+
+ MVT VT = BV->getSimpleValueType(0);
+ SDLoc DL(BV);
+
+ // Try to generate X86ISD::FMADDSUB node here.
+ SDValue Opnd2;
+ if (isFMAddSub(Subtarget, DAG, Opnd0, Opnd1, Opnd2))
+ return DAG.getNode(X86ISD::FMADDSUB, DL, VT, Opnd0, Opnd1, Opnd2);
+
+ // Do not generate X86ISD::ADDSUB node for 512-bit types even though
+ // the ADDSUB idiom has been successfully recognized. There are no known
+ // X86 targets with 512-bit ADDSUB instructions!
+ // 512-bit ADDSUB idiom recognition was needed only as part of FMADDSUB idiom
+ // recognition.
+ if (VT.is512BitVector())
+ return SDValue();
+
+ return DAG.getNode(X86ISD::ADDSUB, DL, VT, Opnd0, Opnd1);
}
/// Lower BUILD_VECTOR to a horizontal add/sub operation if possible.
@@ -6510,17 +7278,18 @@ static SDValue LowerToHorizontalOp(const BuildVectorSDNode *BV,
/// NOTE: Its not in our interest to start make a general purpose vectorizer
/// from this, but enough scalar bit operations are created from the later
/// legalization + scalarization stages to need basic support.
-static SDValue lowerBuildVectorToBitOp(SDValue Op, SelectionDAG &DAG) {
+static SDValue lowerBuildVectorToBitOp(BuildVectorSDNode *Op,
+ SelectionDAG &DAG) {
SDLoc DL(Op);
- MVT VT = Op.getSimpleValueType();
+ MVT VT = Op->getSimpleValueType(0);
unsigned NumElems = VT.getVectorNumElements();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
// Check that all elements have the same opcode.
// TODO: Should we allow UNDEFS and if so how many?
- unsigned Opcode = Op.getOperand(0).getOpcode();
+ unsigned Opcode = Op->getOperand(0).getOpcode();
for (unsigned i = 1; i < NumElems; ++i)
- if (Opcode != Op.getOperand(i).getOpcode())
+ if (Opcode != Op->getOperand(i).getOpcode())
return SDValue();
// TODO: We may be able to add support for other Ops (ADD/SUB + shifts).
@@ -6600,13 +7369,13 @@ X86TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
return VectorConstant;
BuildVectorSDNode *BV = cast<BuildVectorSDNode>(Op.getNode());
- if (SDValue AddSub = LowerToAddSub(BV, Subtarget, DAG))
+ if (SDValue AddSub = lowerToAddSubOrFMAddSub(BV, Subtarget, DAG))
return AddSub;
if (SDValue HorizontalOp = LowerToHorizontalOp(BV, Subtarget, DAG))
return HorizontalOp;
- if (SDValue Broadcast = LowerVectorBroadcast(Op, Subtarget, DAG))
+ if (SDValue Broadcast = LowerVectorBroadcast(BV, Subtarget, DAG))
return Broadcast;
- if (SDValue BitOp = lowerBuildVectorToBitOp(Op, DAG))
+ if (SDValue BitOp = lowerBuildVectorToBitOp(BV, DAG))
return BitOp;
unsigned EVTBits = ExtVT.getSizeInBits();
@@ -6673,12 +7442,8 @@ X86TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
if (ExtVT == MVT::i32 || ExtVT == MVT::f32 || ExtVT == MVT::f64 ||
(ExtVT == MVT::i64 && Subtarget.is64Bit())) {
- if (VT.is512BitVector()) {
- SDValue ZeroVec = getZeroVector(VT, Subtarget, DAG, dl);
- return DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, ZeroVec,
- Item, DAG.getIntPtrConstant(0, dl));
- }
- assert((VT.is128BitVector() || VT.is256BitVector()) &&
+ assert((VT.is128BitVector() || VT.is256BitVector() ||
+ VT.is512BitVector()) &&
"Expected an SSE value type!");
Item = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Item);
// Turn it into a MOVL (i.e. movss, movsd, or movd) to a zero vector.
@@ -7088,6 +7853,7 @@ static bool isRepeatedShuffleMask(unsigned LaneSizeInBits, MVT VT,
RepeatedMask.assign(LaneSize, -1);
int Size = Mask.size();
for (int i = 0; i < Size; ++i) {
+ assert(Mask[i] == SM_SentinelUndef || Mask[i] >= 0);
if (Mask[i] < 0)
continue;
if ((Mask[i] % Size) / LaneSize != i / LaneSize)
@@ -7122,26 +7888,40 @@ is256BitLaneRepeatedShuffleMask(MVT VT, ArrayRef<int> Mask,
return isRepeatedShuffleMask(256, VT, Mask, RepeatedMask);
}
-static void scaleShuffleMask(int Scale, ArrayRef<int> Mask,
- SmallVectorImpl<int> &ScaledMask) {
- assert(0 < Scale && "Unexpected scaling factor");
- int NumElts = Mask.size();
- ScaledMask.assign(NumElts * Scale, -1);
-
- for (int i = 0; i != NumElts; ++i) {
- int M = Mask[i];
-
- // Repeat sentinel values in every mask element.
- if (M < 0) {
- for (int s = 0; s != Scale; ++s)
- ScaledMask[(Scale * i) + s] = M;
+/// Test whether a target shuffle mask is equivalent within each sub-lane.
+/// Unlike isRepeatedShuffleMask we must respect SM_SentinelZero.
+static bool isRepeatedTargetShuffleMask(unsigned LaneSizeInBits, MVT VT,
+ ArrayRef<int> Mask,
+ SmallVectorImpl<int> &RepeatedMask) {
+ int LaneSize = LaneSizeInBits / VT.getScalarSizeInBits();
+ RepeatedMask.assign(LaneSize, SM_SentinelUndef);
+ int Size = Mask.size();
+ for (int i = 0; i < Size; ++i) {
+ assert(isUndefOrZero(Mask[i]) || (Mask[i] >= 0));
+ if (Mask[i] == SM_SentinelUndef)
+ continue;
+ if (Mask[i] == SM_SentinelZero) {
+ if (!isUndefOrZero(RepeatedMask[i % LaneSize]))
+ return false;
+ RepeatedMask[i % LaneSize] = SM_SentinelZero;
continue;
}
+ if ((Mask[i] % Size) / LaneSize != i / LaneSize)
+ // This entry crosses lanes, so there is no way to model this shuffle.
+ return false;
- // Scale mask element and increment across each mask element.
- for (int s = 0; s != Scale; ++s)
- ScaledMask[(Scale * i) + s] = (Scale * M) + s;
+ // Ok, handle the in-lane shuffles by detecting if and when they repeat.
+ // Adjust second vector indices to start at LaneSize instead of Size.
+ int LocalM =
+ Mask[i] < Size ? Mask[i] % LaneSize : Mask[i] % LaneSize + LaneSize;
+ if (RepeatedMask[i % LaneSize] == SM_SentinelUndef)
+ // This is the first non-undef entry in this slot of a 128-bit lane.
+ RepeatedMask[i % LaneSize] = LocalM;
+ else if (RepeatedMask[i % LaneSize] != LocalM)
+ // Found a mismatch with the repeated mask.
+ return false;
}
+ return true;
}
/// \brief Checks whether a shuffle mask is equivalent to an explicit list of
@@ -7251,7 +8031,7 @@ static SmallBitVector computeZeroableShuffleElements(ArrayRef<int> Mask,
bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
- int VectorSizeInBits = V1.getValueType().getSizeInBits();
+ int VectorSizeInBits = V1.getValueSizeInBits();
int ScalarSizeInBits = VectorSizeInBits / Mask.size();
assert(!(VectorSizeInBits % ScalarSizeInBits) && "Illegal shuffle mask size");
@@ -7309,11 +8089,42 @@ static SmallBitVector computeZeroableShuffleElements(ArrayRef<int> Mask,
return Zeroable;
}
-/// Try to lower a shuffle with a single PSHUFB of V1.
-/// This is only possible if V2 is unused (at all, or only for zero elements).
+// The Shuffle result is as follow:
+// 0*a[0]0*a[1]...0*a[n] , n >=0 where a[] elements in a ascending order.
+// Each Zeroable's element correspond to a particular Mask's element.
+// As described in computeZeroableShuffleElements function.
+//
+// The function looks for a sub-mask that the nonzero elements are in
+// increasing order. If such sub-mask exist. The function returns true.
+static bool isNonZeroElementsInOrder(const SmallBitVector Zeroable,
+ ArrayRef<int> Mask,const EVT &VectorType,
+ bool &IsZeroSideLeft) {
+ int NextElement = -1;
+ // Check if the Mask's nonzero elements are in increasing order.
+ for (int i = 0, e = Zeroable.size(); i < e; i++) {
+ // Checks if the mask's zeros elements are built from only zeros.
+ if (Mask[i] == -1)
+ return false;
+ if (Zeroable[i])
+ continue;
+ // Find the lowest non zero element
+ if (NextElement == -1) {
+ NextElement = Mask[i] != 0 ? VectorType.getVectorNumElements() : 0;
+ IsZeroSideLeft = NextElement != 0;
+ }
+ // Exit if the mask's non zero elements are not in increasing order.
+ if (NextElement != Mask[i])
+ return false;
+ NextElement++;
+ }
+ return true;
+}
+
+/// Try to lower a shuffle with a single PSHUFB of V1 or V2.
static SDValue lowerVectorShuffleWithPSHUFB(const SDLoc &DL, MVT VT,
ArrayRef<int> Mask, SDValue V1,
SDValue V2,
+ const SmallBitVector &Zeroable,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
int Size = Mask.size();
@@ -7325,12 +8136,11 @@ static SDValue lowerVectorShuffleWithPSHUFB(const SDLoc &DL, MVT VT,
(Subtarget.hasAVX2() && VT.is256BitVector()) ||
(Subtarget.hasBWI() && VT.is512BitVector()));
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
-
SmallVector<SDValue, 64> PSHUFBMask(NumBytes);
// Sign bit set in i8 mask means zero element.
SDValue ZeroMask = DAG.getConstant(0x80, DL, MVT::i8);
+ SDValue V;
for (int i = 0; i < NumBytes; ++i) {
int M = Mask[i / NumEltBytes];
if (M < 0) {
@@ -7341,9 +8151,13 @@ static SDValue lowerVectorShuffleWithPSHUFB(const SDLoc &DL, MVT VT,
PSHUFBMask[i] = ZeroMask;
continue;
}
- // Only allow V1.
- if (M >= Size)
+
+ // We can only use a single input of V1 or V2.
+ SDValue SrcV = (M >= Size ? V2 : V1);
+ if (V && V != SrcV)
return SDValue();
+ V = SrcV;
+ M %= Size;
// PSHUFB can't cross lanes, ensure this doesn't happen.
if ((M / LaneSize) != ((i / NumEltBytes) / LaneSize))
@@ -7353,33 +8167,66 @@ static SDValue lowerVectorShuffleWithPSHUFB(const SDLoc &DL, MVT VT,
M = M * NumEltBytes + (i % NumEltBytes);
PSHUFBMask[i] = DAG.getConstant(M, DL, MVT::i8);
}
+ assert(V && "Failed to find a source input");
MVT I8VT = MVT::getVectorVT(MVT::i8, NumBytes);
return DAG.getBitcast(
- VT, DAG.getNode(X86ISD::PSHUFB, DL, I8VT, DAG.getBitcast(I8VT, V1),
+ VT, DAG.getNode(X86ISD::PSHUFB, DL, I8VT, DAG.getBitcast(I8VT, V),
DAG.getBuildVector(I8VT, DL, PSHUFBMask)));
}
+static SDValue getMaskNode(SDValue Mask, MVT MaskVT,
+ const X86Subtarget &Subtarget, SelectionDAG &DAG,
+ const SDLoc &dl);
+
+// Function convertBitVectorToUnsigned - The function gets SmallBitVector
+// as argument and convert him to unsigned.
+// The output of the function is not(zeroable)
+static unsigned convertBitVectorToUnsiged(const SmallBitVector &Zeroable) {
+ unsigned convertBit = 0;
+ for (int i = 0, e = Zeroable.size(); i < e; i++)
+ convertBit |= !(Zeroable[i]) << i;
+ return convertBit;
+}
+
+// X86 has dedicated shuffle that can be lowered to VEXPAND
+static SDValue lowerVectorShuffleToEXPAND(const SDLoc &DL, MVT VT,
+ const SmallBitVector &Zeroable,
+ ArrayRef<int> Mask, SDValue &V1,
+ SDValue &V2, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ bool IsLeftZeroSide = true;
+ if (!isNonZeroElementsInOrder(Zeroable, Mask, V1.getValueType(),
+ IsLeftZeroSide))
+ return SDValue();
+ unsigned VEXPANDMask = convertBitVectorToUnsiged(Zeroable);
+ MVT IntegerType =
+ MVT::getIntegerVT(std::max((int)VT.getVectorNumElements(), 8));
+ SDValue MaskNode = DAG.getConstant(VEXPANDMask, DL, IntegerType);
+ unsigned NumElts = VT.getVectorNumElements();
+ assert((NumElts == 4 || NumElts == 8 || NumElts == 16) &&
+ "Unexpected number of vector elements");
+ SDValue VMask = getMaskNode(MaskNode, MVT::getVectorVT(MVT::i1, NumElts),
+ Subtarget, DAG, DL);
+ SDValue ZeroVector = getZeroVector(VT, Subtarget, DAG, DL);
+ SDValue ExpandedVector = IsLeftZeroSide ? V2 : V1;
+ return DAG.getNode(ISD::VSELECT, DL, VT, VMask,
+ DAG.getNode(X86ISD::EXPAND, DL, VT, ExpandedVector),
+ ZeroVector);
+}
+
// X86 has dedicated unpack instructions that can handle specific blend
// operations: UNPCKH and UNPCKL.
static SDValue lowerVectorShuffleWithUNPCK(const SDLoc &DL, MVT VT,
ArrayRef<int> Mask, SDValue V1,
SDValue V2, SelectionDAG &DAG) {
- int NumElts = VT.getVectorNumElements();
- int NumEltsInLane = 128 / VT.getScalarSizeInBits();
- SmallVector<int, 8> Unpckl(NumElts);
- SmallVector<int, 8> Unpckh(NumElts);
-
- for (int i = 0; i < NumElts; ++i) {
- unsigned LaneStart = (i / NumEltsInLane) * NumEltsInLane;
- int LoPos = (i % NumEltsInLane) / 2 + LaneStart + NumElts * (i % 2);
- int HiPos = LoPos + NumEltsInLane / 2;
- Unpckl[i] = LoPos;
- Unpckh[i] = HiPos;
- }
-
+ SmallVector<int, 8> Unpckl;
+ createUnpackShuffleMask(VT, Unpckl, /* Lo = */ true, /* Unary = */ false);
if (isShuffleEquivalent(V1, V2, Mask, Unpckl))
return DAG.getNode(X86ISD::UNPCKL, DL, VT, V1, V2);
+
+ SmallVector<int, 8> Unpckh;
+ createUnpackShuffleMask(VT, Unpckh, /* Lo = */ false, /* Unary = */ false);
if (isShuffleEquivalent(V1, V2, Mask, Unpckh))
return DAG.getNode(X86ISD::UNPCKH, DL, VT, V1, V2);
@@ -7401,19 +8248,14 @@ static SDValue lowerVectorShuffleWithUNPCK(const SDLoc &DL, MVT VT,
/// one of the inputs being zeroable.
static SDValue lowerVectorShuffleAsBitMask(const SDLoc &DL, MVT VT, SDValue V1,
SDValue V2, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SelectionDAG &DAG) {
+ assert(!VT.isFloatingPoint() && "Floating point types are not supported");
MVT EltVT = VT.getVectorElementType();
- int NumEltBits = EltVT.getSizeInBits();
- MVT IntEltVT = MVT::getIntegerVT(NumEltBits);
- SDValue Zero = DAG.getConstant(0, DL, IntEltVT);
- SDValue AllOnes = DAG.getConstant(APInt::getAllOnesValue(NumEltBits), DL,
- IntEltVT);
- if (EltVT.isFloatingPoint()) {
- Zero = DAG.getBitcast(EltVT, Zero);
- AllOnes = DAG.getBitcast(EltVT, AllOnes);
- }
+ SDValue Zero = DAG.getConstant(0, DL, EltVT);
+ SDValue AllOnes =
+ DAG.getConstant(APInt::getAllOnesValue(EltVT.getSizeInBits()), DL, EltVT);
SmallVector<SDValue, 16> VMaskOps(Mask.size(), Zero);
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
SDValue V;
for (int i = 0, Size = Mask.size(); i < Size; ++i) {
if (Zeroable[i])
@@ -7431,10 +8273,7 @@ static SDValue lowerVectorShuffleAsBitMask(const SDLoc &DL, MVT VT, SDValue V1,
return SDValue(); // No non-zeroable elements!
SDValue VMask = DAG.getBuildVector(VT, DL, VMaskOps);
- V = DAG.getNode(VT.isFloatingPoint()
- ? (unsigned) X86ISD::FAND : (unsigned) ISD::AND,
- DL, VT, V, VMask);
- return V;
+ return DAG.getNode(ISD::AND, DL, VT, V, VMask);
}
/// \brief Try to emit a blend instruction for a shuffle using bit math.
@@ -7476,12 +8315,12 @@ static SDValue lowerVectorShuffleAsBitBlend(const SDLoc &DL, MVT VT, SDValue V1,
/// that the shuffle mask is a blend, or convertible into a blend with zero.
static SDValue lowerVectorShuffleAsBlend(const SDLoc &DL, MVT VT, SDValue V1,
SDValue V2, ArrayRef<int> Original,
+ const SmallBitVector &Zeroable,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
bool V1IsZero = ISD::isBuildVectorAllZeros(V1.getNode());
bool V2IsZero = ISD::isBuildVectorAllZeros(V2.getNode());
SmallVector<int, 8> Mask(Original.begin(), Original.end());
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
bool ForceV1Zero = false, ForceV2Zero = false;
// Attempt to generate the binary blend mask. If an input is zero then
@@ -7540,7 +8379,7 @@ static SDValue lowerVectorShuffleAsBlend(const SDLoc &DL, MVT VT, SDValue V1,
case MVT::v4i64:
case MVT::v8i32:
assert(Subtarget.hasAVX2() && "256-bit integer blends require AVX2!");
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case MVT::v2i64:
case MVT::v4i32:
// If we have AVX2 it is faster to use VPBLENDD when the shuffle fits into
@@ -7556,7 +8395,7 @@ static SDValue lowerVectorShuffleAsBlend(const SDLoc &DL, MVT VT, SDValue V1,
VT, DAG.getNode(X86ISD::BLENDI, DL, BlendVT, V1, V2,
DAG.getConstant(BlendMask, DL, MVT::i8)));
}
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case MVT::v8i16: {
// For integer shuffles we need to expand the mask and cast the inputs to
// v8i16s prior to blending.
@@ -7582,15 +8421,16 @@ static SDValue lowerVectorShuffleAsBlend(const SDLoc &DL, MVT VT, SDValue V1,
return DAG.getNode(X86ISD::BLENDI, DL, MVT::v16i16, V1, V2,
DAG.getConstant(BlendMask, DL, MVT::i8));
}
+ LLVM_FALLTHROUGH;
}
- // FALLTHROUGH
case MVT::v16i8:
case MVT::v32i8: {
assert((VT.is128BitVector() || Subtarget.hasAVX2()) &&
"256-bit byte-blends require AVX2 support!");
// Attempt to lower to a bitmask if we can. VPAND is faster than VPBLENDVB.
- if (SDValue Masked = lowerVectorShuffleAsBitMask(DL, VT, V1, V2, Mask, DAG))
+ if (SDValue Masked =
+ lowerVectorShuffleAsBitMask(DL, VT, V1, V2, Mask, Zeroable, DAG))
return Masked;
// Scale the blend by the number of bytes per element.
@@ -7704,32 +8544,12 @@ static SDValue lowerVectorShuffleAsDecomposedShuffleBlend(const SDLoc &DL,
return DAG.getVectorShuffle(VT, DL, V1, V2, BlendMask);
}
-/// \brief Try to lower a vector shuffle as a byte rotation.
-///
-/// SSSE3 has a generic PALIGNR instruction in x86 that will do an arbitrary
-/// byte-rotation of the concatenation of two vectors; pre-SSSE3 can use
-/// a PSRLDQ/PSLLDQ/POR pattern to get a similar effect. This routine will
-/// try to generically lower a vector shuffle through such an pattern. It
-/// does not check for the profitability of lowering either as PALIGNR or
-/// PSRLDQ/PSLLDQ/POR, only whether the mask is valid to lower in that form.
-/// This matches shuffle vectors that look like:
-///
-/// v8i16 [11, 12, 13, 14, 15, 0, 1, 2]
+/// \brief Try to lower a vector shuffle as a rotation.
///
-/// Essentially it concatenates V1 and V2, shifts right by some number of
-/// elements, and takes the low elements as the result. Note that while this is
-/// specified as a *right shift* because x86 is little-endian, it is a *left
-/// rotate* of the vector lanes.
-static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
- SDValue V1, SDValue V2,
- ArrayRef<int> Mask,
- const X86Subtarget &Subtarget,
- SelectionDAG &DAG) {
- assert(!isNoopShuffleMask(Mask) && "We shouldn't lower no-op shuffles!");
-
+/// This is used for support PALIGNR for SSSE3 or VALIGND/Q for AVX512.
+static int matchVectorShuffleAsRotate(SDValue &V1, SDValue &V2,
+ ArrayRef<int> Mask) {
int NumElts = Mask.size();
- int NumLanes = VT.getSizeInBits() / 128;
- int NumLaneElts = NumElts / NumLanes;
// We need to detect various ways of spelling a rotation:
// [11, 12, 13, 14, 15, 0, 1, 2]
@@ -7740,51 +8560,46 @@ static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
// [-1, 4, 5, 6, -1, -1, -1, -1]
int Rotation = 0;
SDValue Lo, Hi;
- for (int l = 0; l < NumElts; l += NumLaneElts) {
- for (int i = 0; i < NumLaneElts; ++i) {
- if (Mask[l + i] < 0)
- continue;
-
- // Get the mod-Size index and lane correct it.
- int LaneIdx = (Mask[l + i] % NumElts) - l;
- // Make sure it was in this lane.
- if (LaneIdx < 0 || LaneIdx >= NumLaneElts)
- return SDValue();
+ for (int i = 0; i < NumElts; ++i) {
+ int M = Mask[i];
+ assert((M == SM_SentinelUndef || (0 <= M && M < (2*NumElts))) &&
+ "Unexpected mask index.");
+ if (M < 0)
+ continue;
- // Determine where a rotated vector would have started.
- int StartIdx = i - LaneIdx;
- if (StartIdx == 0)
- // The identity rotation isn't interesting, stop.
- return SDValue();
+ // Determine where a rotated vector would have started.
+ int StartIdx = i - (M % NumElts);
+ if (StartIdx == 0)
+ // The identity rotation isn't interesting, stop.
+ return -1;
- // If we found the tail of a vector the rotation must be the missing
- // front. If we found the head of a vector, it must be how much of the
- // head.
- int CandidateRotation = StartIdx < 0 ? -StartIdx : NumLaneElts - StartIdx;
+ // If we found the tail of a vector the rotation must be the missing
+ // front. If we found the head of a vector, it must be how much of the
+ // head.
+ int CandidateRotation = StartIdx < 0 ? -StartIdx : NumElts - StartIdx;
- if (Rotation == 0)
- Rotation = CandidateRotation;
- else if (Rotation != CandidateRotation)
- // The rotations don't match, so we can't match this mask.
- return SDValue();
+ if (Rotation == 0)
+ Rotation = CandidateRotation;
+ else if (Rotation != CandidateRotation)
+ // The rotations don't match, so we can't match this mask.
+ return -1;
- // Compute which value this mask is pointing at.
- SDValue MaskV = Mask[l + i] < NumElts ? V1 : V2;
-
- // Compute which of the two target values this index should be assigned
- // to. This reflects whether the high elements are remaining or the low
- // elements are remaining.
- SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
-
- // Either set up this value if we've not encountered it before, or check
- // that it remains consistent.
- if (!TargetV)
- TargetV = MaskV;
- else if (TargetV != MaskV)
- // This may be a rotation, but it pulls from the inputs in some
- // unsupported interleaving.
- return SDValue();
- }
+ // Compute which value this mask is pointing at.
+ SDValue MaskV = M < NumElts ? V1 : V2;
+
+ // Compute which of the two target values this index should be assigned
+ // to. This reflects whether the high elements are remaining or the low
+ // elements are remaining.
+ SDValue &TargetV = StartIdx < 0 ? Hi : Lo;
+
+ // Either set up this value if we've not encountered it before, or check
+ // that it remains consistent.
+ if (!TargetV)
+ TargetV = MaskV;
+ else if (TargetV != MaskV)
+ // This may be a rotation, but it pulls from the inputs in some
+ // unsupported interleaving.
+ return -1;
}
// Check that we successfully analyzed the mask, and normalize the results.
@@ -7795,23 +8610,75 @@ static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
else if (!Hi)
Hi = Lo;
+ V1 = Lo;
+ V2 = Hi;
+
+ return Rotation;
+}
+
+/// \brief Try to lower a vector shuffle as a byte rotation.
+///
+/// SSSE3 has a generic PALIGNR instruction in x86 that will do an arbitrary
+/// byte-rotation of the concatenation of two vectors; pre-SSSE3 can use
+/// a PSRLDQ/PSLLDQ/POR pattern to get a similar effect. This routine will
+/// try to generically lower a vector shuffle through such an pattern. It
+/// does not check for the profitability of lowering either as PALIGNR or
+/// PSRLDQ/PSLLDQ/POR, only whether the mask is valid to lower in that form.
+/// This matches shuffle vectors that look like:
+///
+/// v8i16 [11, 12, 13, 14, 15, 0, 1, 2]
+///
+/// Essentially it concatenates V1 and V2, shifts right by some number of
+/// elements, and takes the low elements as the result. Note that while this is
+/// specified as a *right shift* because x86 is little-endian, it is a *left
+/// rotate* of the vector lanes.
+static int matchVectorShuffleAsByteRotate(MVT VT, SDValue &V1, SDValue &V2,
+ ArrayRef<int> Mask) {
+ // Don't accept any shuffles with zero elements.
+ if (any_of(Mask, [](int M) { return M == SM_SentinelZero; }))
+ return -1;
+
+ // PALIGNR works on 128-bit lanes.
+ SmallVector<int, 16> RepeatedMask;
+ if (!is128BitLaneRepeatedShuffleMask(VT, Mask, RepeatedMask))
+ return -1;
+
+ int Rotation = matchVectorShuffleAsRotate(V1, V2, RepeatedMask);
+ if (Rotation <= 0)
+ return -1;
+
+ // PALIGNR rotates bytes, so we need to scale the
+ // rotation based on how many bytes are in the vector lane.
+ int NumElts = RepeatedMask.size();
+ int Scale = 16 / NumElts;
+ return Rotation * Scale;
+}
+
+static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
+ SDValue V1, SDValue V2,
+ ArrayRef<int> Mask,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
+ assert(!isNoopShuffleMask(Mask) && "We shouldn't lower no-op shuffles!");
+
+ SDValue Lo = V1, Hi = V2;
+ int ByteRotation = matchVectorShuffleAsByteRotate(VT, Lo, Hi, Mask);
+ if (ByteRotation <= 0)
+ return SDValue();
+
// Cast the inputs to i8 vector of correct length to match PALIGNR or
// PSLLDQ/PSRLDQ.
- MVT ByteVT = MVT::getVectorVT(MVT::i8, 16 * NumLanes);
+ MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
Lo = DAG.getBitcast(ByteVT, Lo);
Hi = DAG.getBitcast(ByteVT, Hi);
- // The actual rotate instruction rotates bytes, so we need to scale the
- // rotation based on how many bytes are in the vector lane.
- int Scale = 16 / NumLaneElts;
-
// SSSE3 targets can use the palignr instruction.
if (Subtarget.hasSSSE3()) {
assert((!VT.is512BitVector() || Subtarget.hasBWI()) &&
"512-bit PALIGNR requires BWI instructions");
return DAG.getBitcast(
VT, DAG.getNode(X86ISD::PALIGNR, DL, ByteVT, Lo, Hi,
- DAG.getConstant(Rotation * Scale, DL, MVT::i8)));
+ DAG.getConstant(ByteRotation, DL, MVT::i8)));
}
assert(VT.is128BitVector() &&
@@ -7822,8 +8689,8 @@ static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
"SSE2 rotate lowering only needed for v16i8!");
// Default SSE2 implementation
- int LoByteShift = 16 - Rotation * Scale;
- int HiByteShift = Rotation * Scale;
+ int LoByteShift = 16 - ByteRotation;
+ int HiByteShift = ByteRotation;
SDValue LoShift = DAG.getNode(X86ISD::VSHLDQ, DL, MVT::v16i8, Lo,
DAG.getConstant(LoByteShift, DL, MVT::i8));
@@ -7833,6 +8700,37 @@ static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
DAG.getNode(ISD::OR, DL, MVT::v16i8, LoShift, HiShift));
}
+/// \brief Try to lower a vector shuffle as a dword/qword rotation.
+///
+/// AVX512 has a VALIGND/VALIGNQ instructions that will do an arbitrary
+/// rotation of the concatenation of two vectors; This routine will
+/// try to generically lower a vector shuffle through such an pattern.
+///
+/// Essentially it concatenates V1 and V2, shifts right by some number of
+/// elements, and takes the low elements as the result. Note that while this is
+/// specified as a *right shift* because x86 is little-endian, it is a *left
+/// rotate* of the vector lanes.
+static SDValue lowerVectorShuffleAsRotate(const SDLoc &DL, MVT VT,
+ SDValue V1, SDValue V2,
+ ArrayRef<int> Mask,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
+ assert((VT.getScalarType() == MVT::i32 || VT.getScalarType() == MVT::i64) &&
+ "Only 32-bit and 64-bit elements are supported!");
+
+ // 128/256-bit vectors are only supported with VLX.
+ assert((Subtarget.hasVLX() || (!VT.is128BitVector() && !VT.is256BitVector()))
+ && "VLX required for 128/256-bit vectors");
+
+ SDValue Lo = V1, Hi = V2;
+ int Rotation = matchVectorShuffleAsRotate(Lo, Hi, Mask);
+ if (Rotation <= 0)
+ return SDValue();
+
+ return DAG.getNode(X86ISD::VALIGN, DL, VT, Lo, Hi,
+ DAG.getConstant(Rotation, DL, MVT::i8));
+}
+
/// \brief Try to lower a vector shuffle as a bit shift (shifts in zeros).
///
/// Attempts to match a shuffle mask against the PSLL(W/D/Q/DQ) and
@@ -7856,14 +8754,13 @@ static SDValue lowerVectorShuffleAsByteRotate(const SDLoc &DL, MVT VT,
/// [ 5, 6, 7, zz, zz, zz, zz, zz]
/// [ -1, 5, 6, 7, zz, zz, zz, zz]
/// [ 1, 2, -1, -1, -1, -1, zz, zz]
-static SDValue lowerVectorShuffleAsShift(const SDLoc &DL, MVT VT, SDValue V1,
- SDValue V2, ArrayRef<int> Mask,
- const X86Subtarget &Subtarget,
- SelectionDAG &DAG) {
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
-
+static int matchVectorShuffleAsShift(MVT &ShiftVT, unsigned &Opcode,
+ unsigned ScalarSizeInBits,
+ ArrayRef<int> Mask, int MaskOffset,
+ const SmallBitVector &Zeroable,
+ const X86Subtarget &Subtarget) {
int Size = Mask.size();
- assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
+ unsigned SizeInBits = Size * ScalarSizeInBits;
auto CheckZeros = [&](int Shift, int Scale, bool Left) {
for (int i = 0; i < Size; i += Scale)
@@ -7874,37 +8771,30 @@ static SDValue lowerVectorShuffleAsShift(const SDLoc &DL, MVT VT, SDValue V1,
return true;
};
- auto MatchShift = [&](int Shift, int Scale, bool Left, SDValue V) {
+ auto MatchShift = [&](int Shift, int Scale, bool Left) {
for (int i = 0; i != Size; i += Scale) {
unsigned Pos = Left ? i + Shift : i;
unsigned Low = Left ? i : i + Shift;
unsigned Len = Scale - Shift;
- if (!isSequentialOrUndefInRange(Mask, Pos, Len,
- Low + (V == V1 ? 0 : Size)))
- return SDValue();
+ if (!isSequentialOrUndefInRange(Mask, Pos, Len, Low + MaskOffset))
+ return -1;
}
- int ShiftEltBits = VT.getScalarSizeInBits() * Scale;
+ int ShiftEltBits = ScalarSizeInBits * Scale;
bool ByteShift = ShiftEltBits > 64;
- unsigned OpCode = Left ? (ByteShift ? X86ISD::VSHLDQ : X86ISD::VSHLI)
- : (ByteShift ? X86ISD::VSRLDQ : X86ISD::VSRLI);
- int ShiftAmt = Shift * VT.getScalarSizeInBits() / (ByteShift ? 8 : 1);
+ Opcode = Left ? (ByteShift ? X86ISD::VSHLDQ : X86ISD::VSHLI)
+ : (ByteShift ? X86ISD::VSRLDQ : X86ISD::VSRLI);
+ int ShiftAmt = Shift * ScalarSizeInBits / (ByteShift ? 8 : 1);
// Normalize the scale for byte shifts to still produce an i64 element
// type.
Scale = ByteShift ? Scale / 2 : Scale;
// We need to round trip through the appropriate type for the shift.
- MVT ShiftSVT = MVT::getIntegerVT(VT.getScalarSizeInBits() * Scale);
- MVT ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8)
- : MVT::getVectorVT(ShiftSVT, Size / Scale);
- assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
- "Illegal integer vector type");
- V = DAG.getBitcast(ShiftVT, V);
-
- V = DAG.getNode(OpCode, DL, ShiftVT, V,
- DAG.getConstant(ShiftAmt, DL, MVT::i8));
- return DAG.getBitcast(VT, V);
+ MVT ShiftSVT = MVT::getIntegerVT(ScalarSizeInBits * Scale);
+ ShiftVT = ByteShift ? MVT::getVectorVT(MVT::i8, SizeInBits / 8)
+ : MVT::getVectorVT(ShiftSVT, Size / Scale);
+ return (int)ShiftAmt;
};
// SSE/AVX supports logical shifts up to 64-bit integers - so we can just
@@ -7913,29 +8803,64 @@ static SDValue lowerVectorShuffleAsShift(const SDLoc &DL, MVT VT, SDValue V1,
// their width within the elements of the larger integer vector. Test each
// multiple to see if we can find a match with the moved element indices
// and that the shifted in elements are all zeroable.
- unsigned MaxWidth = (VT.is512BitVector() && !Subtarget.hasBWI() ? 64 : 128);
- for (int Scale = 2; Scale * VT.getScalarSizeInBits() <= MaxWidth; Scale *= 2)
+ unsigned MaxWidth = ((SizeInBits == 512) && !Subtarget.hasBWI() ? 64 : 128);
+ for (int Scale = 2; Scale * ScalarSizeInBits <= MaxWidth; Scale *= 2)
for (int Shift = 1; Shift != Scale; ++Shift)
for (bool Left : {true, false})
- if (CheckZeros(Shift, Scale, Left))
- for (SDValue V : {V1, V2})
- if (SDValue Match = MatchShift(Shift, Scale, Left, V))
- return Match;
+ if (CheckZeros(Shift, Scale, Left)) {
+ int ShiftAmt = MatchShift(Shift, Scale, Left);
+ if (0 < ShiftAmt)
+ return ShiftAmt;
+ }
// no match
- return SDValue();
+ return -1;
+}
+
+static SDValue lowerVectorShuffleAsShift(const SDLoc &DL, MVT VT, SDValue V1,
+ SDValue V2, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
+ int Size = Mask.size();
+ assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
+
+ MVT ShiftVT;
+ SDValue V = V1;
+ unsigned Opcode;
+
+ // Try to match shuffle against V1 shift.
+ int ShiftAmt = matchVectorShuffleAsShift(
+ ShiftVT, Opcode, VT.getScalarSizeInBits(), Mask, 0, Zeroable, Subtarget);
+
+ // If V1 failed, try to match shuffle against V2 shift.
+ if (ShiftAmt < 0) {
+ ShiftAmt =
+ matchVectorShuffleAsShift(ShiftVT, Opcode, VT.getScalarSizeInBits(),
+ Mask, Size, Zeroable, Subtarget);
+ V = V2;
+ }
+
+ if (ShiftAmt < 0)
+ return SDValue();
+
+ assert(DAG.getTargetLoweringInfo().isTypeLegal(ShiftVT) &&
+ "Illegal integer vector type");
+ V = DAG.getBitcast(ShiftVT, V);
+ V = DAG.getNode(Opcode, DL, ShiftVT, V,
+ DAG.getConstant(ShiftAmt, DL, MVT::i8));
+ return DAG.getBitcast(VT, V);
}
/// \brief Try to lower a vector shuffle using SSE4a EXTRQ/INSERTQ.
static SDValue lowerVectorShuffleWithSSE4A(const SDLoc &DL, MVT VT, SDValue V1,
SDValue V2, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SelectionDAG &DAG) {
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
- assert(!Zeroable.all() && "Fully zeroable shuffle mask");
-
int Size = Mask.size();
int HalfSize = Size / 2;
assert(Size == (int)VT.getVectorNumElements() && "Unexpected mask size");
+ assert(!Zeroable.all() && "Fully zeroable shuffle mask");
// Upper half must be undefined.
if (!isUndefInRange(Mask, HalfSize, HalfSize))
@@ -8111,8 +9036,10 @@ static SDValue lowerVectorShuffleAsSpecificZeroOrAnyExtend(
InputV = ShuffleOffset(InputV);
// For 256-bit vectors, we only need the lower (128-bit) input half.
- if (VT.is256BitVector())
- InputV = extract128BitVector(InputV, 0, DAG, DL);
+ // For 512-bit vectors, we only need the lower input half or quarter.
+ if (VT.getSizeInBits() > 128)
+ InputV = extractSubVector(InputV, 0, DAG, DL,
+ std::max(128, (int)VT.getSizeInBits() / Scale));
InputV = DAG.getNode(X86ISD::VZEXT, DL, ExtVT, InputV);
return DAG.getBitcast(VT, InputV);
@@ -8231,9 +9158,8 @@ static SDValue lowerVectorShuffleAsSpecificZeroOrAnyExtend(
/// are both incredibly common and often quite performance sensitive.
static SDValue lowerVectorShuffleAsZeroOrAnyExtend(
const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<int> Mask,
- const X86Subtarget &Subtarget, SelectionDAG &DAG) {
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
-
+ const SmallBitVector &Zeroable, const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
int Bits = VT.getSizeInBits();
int NumLanes = Bits / 128;
int NumElements = VT.getVectorNumElements();
@@ -8388,14 +9314,14 @@ static bool isShuffleFoldableLoad(SDValue V) {
/// across all subtarget feature sets.
static SDValue lowerVectorShuffleAsElementInsertion(
const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<int> Mask,
- const X86Subtarget &Subtarget, SelectionDAG &DAG) {
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
+ const SmallBitVector &Zeroable, const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
MVT ExtVT = VT;
MVT EltVT = VT.getVectorElementType();
- int V2Index = std::find_if(Mask.begin(), Mask.end(),
- [&Mask](int M) { return M >= (int)Mask.size(); }) -
- Mask.begin();
+ int V2Index =
+ find_if(Mask, [&Mask](int M) { return M >= (int)Mask.size(); }) -
+ Mask.begin();
bool IsV1Zeroable = true;
for (int i = 0, Size = Mask.size(); i < Size; ++i)
if (i != V2Index && !Zeroable[i]) {
@@ -8709,6 +9635,13 @@ static SDValue lowerVectorShuffleAsBroadcast(const SDLoc &DL, MVT VT,
V = DAG.getBitcast(SrcVT, V);
}
+ // 32-bit targets need to load i64 as a f64 and then bitcast the result.
+ if (!Subtarget.is64Bit() && SrcVT == MVT::i64) {
+ V = DAG.getBitcast(MVT::f64, V);
+ unsigned NumBroadcastElts = BroadcastVT.getVectorNumElements();
+ BroadcastVT = MVT::getVectorVT(MVT::f64, NumBroadcastElts);
+ }
+
return DAG.getBitcast(VT, DAG.getNode(Opcode, DL, BroadcastVT, V));
}
@@ -8726,71 +9659,93 @@ static bool matchVectorShuffleAsInsertPS(SDValue &V1, SDValue &V2,
assert(V1.getSimpleValueType().is128BitVector() && "Bad operand type!");
assert(V2.getSimpleValueType().is128BitVector() && "Bad operand type!");
assert(Mask.size() == 4 && "Unexpected mask size for v4 shuffle!");
- unsigned ZMask = 0;
- int V1DstIndex = -1;
- int V2DstIndex = -1;
- bool V1UsedInPlace = false;
- for (int i = 0; i < 4; ++i) {
- // Synthesize a zero mask from the zeroable elements (includes undefs).
- if (Zeroable[i]) {
- ZMask |= 1 << i;
- continue;
- }
+ // Attempt to match INSERTPS with one element from VA or VB being
+ // inserted into VA (or undef). If successful, V1, V2 and InsertPSMask
+ // are updated.
+ auto matchAsInsertPS = [&](SDValue VA, SDValue VB,
+ ArrayRef<int> CandidateMask) {
+ unsigned ZMask = 0;
+ int VADstIndex = -1;
+ int VBDstIndex = -1;
+ bool VAUsedInPlace = false;
+
+ for (int i = 0; i < 4; ++i) {
+ // Synthesize a zero mask from the zeroable elements (includes undefs).
+ if (Zeroable[i]) {
+ ZMask |= 1 << i;
+ continue;
+ }
- // Flag if we use any V1 inputs in place.
- if (i == Mask[i]) {
- V1UsedInPlace = true;
- continue;
+ // Flag if we use any VA inputs in place.
+ if (i == CandidateMask[i]) {
+ VAUsedInPlace = true;
+ continue;
+ }
+
+ // We can only insert a single non-zeroable element.
+ if (VADstIndex >= 0 || VBDstIndex >= 0)
+ return false;
+
+ if (CandidateMask[i] < 4) {
+ // VA input out of place for insertion.
+ VADstIndex = i;
+ } else {
+ // VB input for insertion.
+ VBDstIndex = i;
+ }
}
- // We can only insert a single non-zeroable element.
- if (V1DstIndex >= 0 || V2DstIndex >= 0)
+ // Don't bother if we have no (non-zeroable) element for insertion.
+ if (VADstIndex < 0 && VBDstIndex < 0)
return false;
- if (Mask[i] < 4) {
- // V1 input out of place for insertion.
- V1DstIndex = i;
+ // Determine element insertion src/dst indices. The src index is from the
+ // start of the inserted vector, not the start of the concatenated vector.
+ unsigned VBSrcIndex = 0;
+ if (VADstIndex >= 0) {
+ // If we have a VA input out of place, we use VA as the V2 element
+ // insertion and don't use the original V2 at all.
+ VBSrcIndex = CandidateMask[VADstIndex];
+ VBDstIndex = VADstIndex;
+ VB = VA;
} else {
- // V2 input for insertion.
- V2DstIndex = i;
+ VBSrcIndex = CandidateMask[VBDstIndex] - 4;
}
- }
- // Don't bother if we have no (non-zeroable) element for insertion.
- if (V1DstIndex < 0 && V2DstIndex < 0)
- return false;
+ // If no V1 inputs are used in place, then the result is created only from
+ // the zero mask and the V2 insertion - so remove V1 dependency.
+ if (!VAUsedInPlace)
+ VA = DAG.getUNDEF(MVT::v4f32);
- // Determine element insertion src/dst indices. The src index is from the
- // start of the inserted vector, not the start of the concatenated vector.
- unsigned V2SrcIndex = 0;
- if (V1DstIndex >= 0) {
- // If we have a V1 input out of place, we use V1 as the V2 element insertion
- // and don't use the original V2 at all.
- V2SrcIndex = Mask[V1DstIndex];
- V2DstIndex = V1DstIndex;
- V2 = V1;
- } else {
- V2SrcIndex = Mask[V2DstIndex] - 4;
- }
+ // Update V1, V2 and InsertPSMask accordingly.
+ V1 = VA;
+ V2 = VB;
- // If no V1 inputs are used in place, then the result is created only from
- // the zero mask and the V2 insertion - so remove V1 dependency.
- if (!V1UsedInPlace)
- V1 = DAG.getUNDEF(MVT::v4f32);
+ // Insert the V2 element into the desired position.
+ InsertPSMask = VBSrcIndex << 6 | VBDstIndex << 4 | ZMask;
+ assert((InsertPSMask & ~0xFFu) == 0 && "Invalid mask!");
+ return true;
+ };
- // Insert the V2 element into the desired position.
- InsertPSMask = V2SrcIndex << 6 | V2DstIndex << 4 | ZMask;
- assert((InsertPSMask & ~0xFFu) == 0 && "Invalid mask!");
- return true;
+ if (matchAsInsertPS(V1, V2, Mask))
+ return true;
+
+ // Commute and try again.
+ SmallVector<int, 4> CommutedMask(Mask.begin(), Mask.end());
+ ShuffleVectorSDNode::commuteMask(CommutedMask);
+ if (matchAsInsertPS(V2, V1, CommutedMask))
+ return true;
+
+ return false;
}
static SDValue lowerVectorShuffleAsInsertPS(const SDLoc &DL, SDValue V1,
SDValue V2, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SelectionDAG &DAG) {
assert(V1.getSimpleValueType() == MVT::v4f32 && "Bad operand type!");
assert(V2.getSimpleValueType() == MVT::v4f32 && "Bad operand type!");
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
// Attempt to match the insertps pattern.
unsigned InsertPSMask;
@@ -8922,6 +9877,7 @@ static SDValue lowerVectorShuffleAsPermuteAndUnpack(const SDLoc &DL, MVT VT,
/// it is better to avoid lowering through this for integer vectors where
/// possible.
static SDValue lowerV2F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -8946,8 +9902,11 @@ static SDValue lowerV2F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
DAG.getConstant(SHUFPDMask, DL, MVT::i8));
}
- return DAG.getNode(X86ISD::SHUFP, DL, MVT::v2f64, V1, V1,
- DAG.getConstant(SHUFPDMask, DL, MVT::i8));
+ return DAG.getNode(
+ X86ISD::SHUFP, DL, MVT::v2f64,
+ Mask[0] == SM_SentinelUndef ? DAG.getUNDEF(MVT::v2f64) : V1,
+ Mask[1] == SM_SentinelUndef ? DAG.getUNDEF(MVT::v2f64) : V1,
+ DAG.getConstant(SHUFPDMask, DL, MVT::i8));
}
assert(Mask[0] >= 0 && Mask[0] < 2 && "Non-canonicalized blend!");
assert(Mask[1] >= 2 && "Non-canonicalized blend!");
@@ -8955,14 +9914,14 @@ static SDValue lowerV2F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// If we have a single input, insert that into V1 if we can do so cheaply.
if ((Mask[0] >= 2) + (Mask[1] >= 2) == 1) {
if (SDValue Insertion = lowerVectorShuffleAsElementInsertion(
- DL, MVT::v2f64, V1, V2, Mask, Subtarget, DAG))
+ DL, MVT::v2f64, V1, V2, Mask, Zeroable, Subtarget, DAG))
return Insertion;
// Try inverting the insertion since for v2 masks it is easy to do and we
// can't reliably sort the mask one way or the other.
int InverseMask[2] = {Mask[0] < 0 ? -1 : (Mask[0] ^ 2),
Mask[1] < 0 ? -1 : (Mask[1] ^ 2)};
if (SDValue Insertion = lowerVectorShuffleAsElementInsertion(
- DL, MVT::v2f64, V2, V1, InverseMask, Subtarget, DAG))
+ DL, MVT::v2f64, V2, V1, InverseMask, Zeroable, Subtarget, DAG))
return Insertion;
}
@@ -8980,7 +9939,7 @@ static SDValue lowerV2F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
if (Subtarget.hasSSE41())
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v2f64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -9000,6 +9959,7 @@ static SDValue lowerV2F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// it falls back to the floating point shuffle operation with appropriate bit
/// casting.
static SDValue lowerV2I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -9052,19 +10012,19 @@ static SDValue lowerV2I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v2i64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// When loading a scalar and then shuffling it into a vector we can often do
// the insertion cheaply.
if (SDValue Insertion = lowerVectorShuffleAsElementInsertion(
- DL, MVT::v2i64, V1, V2, Mask, Subtarget, DAG))
+ DL, MVT::v2i64, V1, V2, Mask, Zeroable, Subtarget, DAG))
return Insertion;
// Try inverting the insertion since for v2 masks it is easy to do and we
// can't reliably sort the mask one way or the other.
int InverseMask[2] = {Mask[0] ^ 2, Mask[1] ^ 2};
if (SDValue Insertion = lowerVectorShuffleAsElementInsertion(
- DL, MVT::v2i64, V2, V1, InverseMask, Subtarget, DAG))
+ DL, MVT::v2i64, V2, V1, InverseMask, Zeroable, Subtarget, DAG))
return Insertion;
// We have different paths for blend lowering, but they all must use the
@@ -9072,7 +10032,7 @@ static SDValue lowerV2I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
bool IsBlendSupported = Subtarget.hasSSE41();
if (IsBlendSupported)
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v2i64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -9139,9 +10099,7 @@ static SDValue lowerVectorShuffleWithSHUFPS(const SDLoc &DL, MVT VT,
int NumV2Elements = count_if(Mask, [](int M) { return M >= 4; });
if (NumV2Elements == 1) {
- int V2Index =
- std::find_if(Mask.begin(), Mask.end(), [](int M) { return M >= 4; }) -
- Mask.begin();
+ int V2Index = find_if(Mask, [](int M) { return M >= 4; }) - Mask.begin();
// Compute the index adjacent to V2Index and in the same half by toggling
// the low bit.
@@ -9220,6 +10178,7 @@ static SDValue lowerVectorShuffleWithSHUFPS(const SDLoc &DL, MVT VT,
/// domain crossing penalties, as these are sufficient to implement all v4f32
/// shuffles.
static SDValue lowerV4F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -9262,17 +10221,18 @@ static SDValue lowerV4F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// when the V2 input is targeting element 0 of the mask -- that is the fast
// case here.
if (NumV2Elements == 1 && Mask[0] >= 4)
- if (SDValue V = lowerVectorShuffleAsElementInsertion(DL, MVT::v4f32, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue V = lowerVectorShuffleAsElementInsertion(
+ DL, MVT::v4f32, V1, V2, Mask, Zeroable, Subtarget, DAG))
return V;
if (Subtarget.hasSSE41()) {
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v4f32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Use INSERTPS if we can complete the shuffle efficiently.
- if (SDValue V = lowerVectorShuffleAsInsertPS(DL, V1, V2, Mask, DAG))
+ if (SDValue V =
+ lowerVectorShuffleAsInsertPS(DL, V1, V2, Mask, Zeroable, DAG))
return V;
if (!isSingleSHUFPSMask(Mask))
@@ -9301,6 +10261,7 @@ static SDValue lowerV4F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// We try to handle these with integer-domain shuffles where we can, but for
/// blends we use the floating point domain blend instructions.
static SDValue lowerV4I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -9311,8 +10272,8 @@ static SDValue lowerV4I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Whenever we can lower this as a zext, that instruction is strictly faster
// than any alternative. It also allows us to fold memory operands into the
// shuffle in many cases.
- if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(DL, MVT::v4i32, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v4i32, V1, V2, Mask, Zeroable, Subtarget, DAG))
return ZExt;
int NumV2Elements = count_if(Mask, [](int M) { return M >= 4; });
@@ -9341,13 +10302,13 @@ static SDValue lowerV4I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v4i32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// There are special ways we can lower some single-element blends.
if (NumV2Elements == 1)
- if (SDValue V = lowerVectorShuffleAsElementInsertion(DL, MVT::v4i32, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue V = lowerVectorShuffleAsElementInsertion(
+ DL, MVT::v4i32, V1, V2, Mask, Zeroable, Subtarget, DAG))
return V;
// We have different paths for blend lowering, but they all must use the
@@ -9355,11 +10316,11 @@ static SDValue lowerV4I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
bool IsBlendSupported = Subtarget.hasSSE41();
if (IsBlendSupported)
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v4i32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
- if (SDValue Masked =
- lowerVectorShuffleAsBitMask(DL, MVT::v4i32, V1, V2, Mask, DAG))
+ if (SDValue Masked = lowerVectorShuffleAsBitMask(DL, MVT::v4i32, V1, V2, Mask,
+ Zeroable, DAG))
return Masked;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -9374,26 +10335,31 @@ static SDValue lowerV4I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
DL, MVT::v4i32, V1, V2, Mask, Subtarget, DAG))
return Rotate;
- // If we have direct support for blends, we should lower by decomposing into
- // a permute. That will be faster than the domain cross.
- if (IsBlendSupported)
- return lowerVectorShuffleAsDecomposedShuffleBlend(DL, MVT::v4i32, V1, V2,
- Mask, DAG);
-
- // Try to lower by permuting the inputs into an unpack instruction.
- if (SDValue Unpack = lowerVectorShuffleAsPermuteAndUnpack(DL, MVT::v4i32, V1,
- V2, Mask, DAG))
- return Unpack;
+ // Assume that a single SHUFPS is faster than an alternative sequence of
+ // multiple instructions (even if the CPU has a domain penalty).
+ // If some CPU is harmed by the domain switch, we can fix it in a later pass.
+ if (!isSingleSHUFPSMask(Mask)) {
+ // If we have direct support for blends, we should lower by decomposing into
+ // a permute. That will be faster than the domain cross.
+ if (IsBlendSupported)
+ return lowerVectorShuffleAsDecomposedShuffleBlend(DL, MVT::v4i32, V1, V2,
+ Mask, DAG);
+
+ // Try to lower by permuting the inputs into an unpack instruction.
+ if (SDValue Unpack = lowerVectorShuffleAsPermuteAndUnpack(
+ DL, MVT::v4i32, V1, V2, Mask, DAG))
+ return Unpack;
+ }
// We implement this with SHUFPS because it can blend from two vectors.
// Because we're going to eventually use SHUFPS, we use SHUFPS even to build
// up the inputs, bypassing domain shift penalties that we would encur if we
// directly used PSHUFD on Nehalem and older. For newer chips, this isn't
// relevant.
- return DAG.getBitcast(
- MVT::v4i32,
- DAG.getVectorShuffle(MVT::v4f32, DL, DAG.getBitcast(MVT::v4f32, V1),
- DAG.getBitcast(MVT::v4f32, V2), Mask));
+ SDValue CastV1 = DAG.getBitcast(MVT::v4f32, V1);
+ SDValue CastV2 = DAG.getBitcast(MVT::v4f32, V2);
+ SDValue ShufPS = DAG.getVectorShuffle(MVT::v4f32, DL, CastV1, CastV2, Mask);
+ return DAG.getBitcast(MVT::v4i32, ShufPS);
}
/// \brief Lowering of single-input v8i16 shuffles is the cornerstone of SSE2
@@ -9551,18 +10517,15 @@ static SDValue lowerV8I16GeneralSingleInputVectorShuffle(
auto FixFlippedInputs = [&V, &DL, &Mask, &DAG](int PinnedIdx, int DWord,
ArrayRef<int> Inputs) {
int FixIdx = PinnedIdx ^ 1; // The adjacent slot to the pinned slot.
- bool IsFixIdxInput = std::find(Inputs.begin(), Inputs.end(),
- PinnedIdx ^ 1) != Inputs.end();
+ bool IsFixIdxInput = is_contained(Inputs, PinnedIdx ^ 1);
// Determine whether the free index is in the flipped dword or the
// unflipped dword based on where the pinned index is. We use this bit
// in an xor to conditionally select the adjacent dword.
int FixFreeIdx = 2 * (DWord ^ (PinnedIdx / 2 == DWord));
- bool IsFixFreeIdxInput = std::find(Inputs.begin(), Inputs.end(),
- FixFreeIdx) != Inputs.end();
+ bool IsFixFreeIdxInput = is_contained(Inputs, FixFreeIdx);
if (IsFixIdxInput == IsFixFreeIdxInput)
FixFreeIdx += 1;
- IsFixFreeIdxInput = std::find(Inputs.begin(), Inputs.end(),
- FixFreeIdx) != Inputs.end();
+ IsFixFreeIdxInput = is_contained(Inputs, FixFreeIdx);
assert(IsFixIdxInput != IsFixFreeIdxInput &&
"We need to be changing the number of flipped inputs!");
int PSHUFHalfMask[] = {0, 1, 2, 3};
@@ -9734,9 +10697,8 @@ static SDValue lowerV8I16GeneralSingleInputVectorShuffle(
// by inputs being moved and *staying* in that half.
if (IncomingInputs.size() == 1) {
if (isWordClobbered(SourceHalfMask, IncomingInputs[0] - SourceOffset)) {
- int InputFixed = std::find(std::begin(SourceHalfMask),
- std::end(SourceHalfMask), -1) -
- std::begin(SourceHalfMask) + SourceOffset;
+ int InputFixed = find(SourceHalfMask, -1) - std::begin(SourceHalfMask) +
+ SourceOffset;
SourceHalfMask[InputFixed - SourceOffset] =
IncomingInputs[0] - SourceOffset;
std::replace(HalfMask.begin(), HalfMask.end(), IncomingInputs[0],
@@ -9868,8 +10830,8 @@ static SDValue lowerV8I16GeneralSingleInputVectorShuffle(
/// blend if only one input is used.
static SDValue lowerVectorShuffleAsBlendOfPSHUFBs(
const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<int> Mask,
- SelectionDAG &DAG, bool &V1InUse, bool &V2InUse) {
- SmallBitVector Zeroable = computeZeroableShuffleElements(Mask, V1, V2);
+ const SmallBitVector &Zeroable, SelectionDAG &DAG, bool &V1InUse,
+ bool &V2InUse) {
SDValue V1Mask[16];
SDValue V2Mask[16];
V1InUse = false;
@@ -9929,6 +10891,7 @@ static SDValue lowerVectorShuffleAsBlendOfPSHUFBs(
/// halves of the inputs separately (making them have relatively few inputs)
/// and then concatenate them.
static SDValue lowerV8I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -9939,7 +10902,7 @@ static SDValue lowerV8I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Whenever we can lower this as a zext, that instruction is strictly faster
// than any alternative.
if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
- DL, MVT::v8i16, V1, V2, Mask, Subtarget, DAG))
+ DL, MVT::v8i16, V1, V2, Mask, Zeroable, Subtarget, DAG))
return ZExt;
int NumV2Inputs = count_if(Mask, [](int M) { return M >= 8; });
@@ -9952,7 +10915,7 @@ static SDValue lowerV8I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v8i16, V1, V1, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -9978,18 +10941,19 @@ static SDValue lowerV8I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v8i16, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// See if we can use SSE4A Extraction / Insertion.
if (Subtarget.hasSSE4A())
- if (SDValue V = lowerVectorShuffleWithSSE4A(DL, MVT::v8i16, V1, V2, Mask, DAG))
+ if (SDValue V = lowerVectorShuffleWithSSE4A(DL, MVT::v8i16, V1, V2, Mask,
+ Zeroable, DAG))
return V;
// There are special ways we can lower some single-element blends.
if (NumV2Inputs == 1)
- if (SDValue V = lowerVectorShuffleAsElementInsertion(DL, MVT::v8i16, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue V = lowerVectorShuffleAsElementInsertion(
+ DL, MVT::v8i16, V1, V2, Mask, Zeroable, Subtarget, DAG))
return V;
// We have different paths for blend lowering, but they all must use the
@@ -9997,11 +10961,11 @@ static SDValue lowerV8I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
bool IsBlendSupported = Subtarget.hasSSE41();
if (IsBlendSupported)
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v8i16, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
- if (SDValue Masked =
- lowerVectorShuffleAsBitMask(DL, MVT::v8i16, V1, V2, Mask, DAG))
+ if (SDValue Masked = lowerVectorShuffleAsBitMask(DL, MVT::v8i16, V1, V2, Mask,
+ Zeroable, DAG))
return Masked;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -10027,14 +10991,14 @@ static SDValue lowerV8I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// can both shuffle and set up the inefficient blend.
if (!IsBlendSupported && Subtarget.hasSSSE3()) {
bool V1InUse, V2InUse;
- return lowerVectorShuffleAsBlendOfPSHUFBs(DL, MVT::v8i16, V1, V2, Mask, DAG,
- V1InUse, V2InUse);
+ return lowerVectorShuffleAsBlendOfPSHUFBs(DL, MVT::v8i16, V1, V2, Mask,
+ Zeroable, DAG, V1InUse, V2InUse);
}
// We can always bit-blend if we have to so the fallback strategy is to
// decompose into single-input permutes and blends.
return lowerVectorShuffleAsDecomposedShuffleBlend(DL, MVT::v8i16, V1, V2,
- Mask, DAG);
+ Mask, DAG);
}
/// \brief Check whether a compaction lowering can be done by dropping even
@@ -10111,6 +11075,7 @@ static int canLowerByDroppingEvenElements(ArrayRef<int> Mask,
/// the existing lowering for v8i16 blends on each half, finally PACK-ing them
/// back together.
static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -10120,7 +11085,7 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v16i8, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// Try to use byte rotation instructions.
@@ -10130,12 +11095,13 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use a zext lowering.
if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
- DL, MVT::v16i8, V1, V2, Mask, Subtarget, DAG))
+ DL, MVT::v16i8, V1, V2, Mask, Zeroable, Subtarget, DAG))
return ZExt;
// See if we can use SSE4A Extraction / Insertion.
if (Subtarget.hasSSE4A())
- if (SDValue V = lowerVectorShuffleWithSSE4A(DL, MVT::v16i8, V1, V2, Mask, DAG))
+ if (SDValue V = lowerVectorShuffleWithSSE4A(DL, MVT::v16i8, V1, V2, Mask,
+ Zeroable, DAG))
return V;
int NumV2Elements = count_if(Mask, [](int M) { return M >= 16; });
@@ -10238,8 +11204,8 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
return V;
}
- if (SDValue Masked =
- lowerVectorShuffleAsBitMask(DL, MVT::v16i8, V1, V2, Mask, DAG))
+ if (SDValue Masked = lowerVectorShuffleAsBitMask(DL, MVT::v16i8, V1, V2, Mask,
+ Zeroable, DAG))
return Masked;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -10265,15 +11231,15 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
bool V2InUse = false;
SDValue PSHUFB = lowerVectorShuffleAsBlendOfPSHUFBs(
- DL, MVT::v16i8, V1, V2, Mask, DAG, V1InUse, V2InUse);
+ DL, MVT::v16i8, V1, V2, Mask, Zeroable, DAG, V1InUse, V2InUse);
// If both V1 and V2 are in use and we can use a direct blend or an unpack,
// do so. This avoids using them to handle blends-with-zero which is
// important as a single pshufb is significantly faster for that.
if (V1InUse && V2InUse) {
if (Subtarget.hasSSE41())
- if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v16i8, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue Blend = lowerVectorShuffleAsBlend(
+ DL, MVT::v16i8, V1, V2, Mask, Zeroable, Subtarget, DAG))
return Blend;
// We can use an unpack to do the blending rather than an or in some
@@ -10294,8 +11260,8 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// There are special ways we can lower some single-element blends.
if (NumV2Elements == 1)
- if (SDValue V = lowerVectorShuffleAsElementInsertion(DL, MVT::v16i8, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue V = lowerVectorShuffleAsElementInsertion(
+ DL, MVT::v16i8, V1, V2, Mask, Zeroable, Subtarget, DAG))
return V;
if (SDValue BitBlend =
@@ -10349,22 +11315,18 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// with a pack.
SDValue V = V1;
- int LoBlendMask[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
- int HiBlendMask[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
+ std::array<int, 8> LoBlendMask = {{-1, -1, -1, -1, -1, -1, -1, -1}};
+ std::array<int, 8> HiBlendMask = {{-1, -1, -1, -1, -1, -1, -1, -1}};
for (int i = 0; i < 16; ++i)
if (Mask[i] >= 0)
(i < 8 ? LoBlendMask[i] : HiBlendMask[i % 8]) = Mask[i];
- SDValue Zero = getZeroVector(MVT::v8i16, Subtarget, DAG, DL);
-
SDValue VLoHalf, VHiHalf;
// Check if any of the odd lanes in the v16i8 are used. If not, we can mask
// them out and avoid using UNPCK{L,H} to extract the elements of V as
// i16s.
- if (std::none_of(std::begin(LoBlendMask), std::end(LoBlendMask),
- [](int M) { return M >= 0 && M % 2 == 1; }) &&
- std::none_of(std::begin(HiBlendMask), std::end(HiBlendMask),
- [](int M) { return M >= 0 && M % 2 == 1; })) {
+ if (none_of(LoBlendMask, [](int M) { return M >= 0 && M % 2 == 1; }) &&
+ none_of(HiBlendMask, [](int M) { return M >= 0 && M % 2 == 1; })) {
// Use a mask to drop the high bytes.
VLoHalf = DAG.getBitcast(MVT::v8i16, V);
VLoHalf = DAG.getNode(ISD::AND, DL, MVT::v8i16, VLoHalf,
@@ -10383,6 +11345,8 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
} else {
// Otherwise just unpack the low half of V into VLoHalf and the high half into
// VHiHalf so that we can blend them as i16s.
+ SDValue Zero = getZeroVector(MVT::v16i8, Subtarget, DAG, DL);
+
VLoHalf = DAG.getBitcast(
MVT::v8i16, DAG.getNode(X86ISD::UNPCKL, DL, MVT::v16i8, V, Zero));
VHiHalf = DAG.getBitcast(
@@ -10401,83 +11365,28 @@ static SDValue lowerV16I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// dispatches to the lowering routines accordingly.
static SDValue lower128BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
MVT VT, SDValue V1, SDValue V2,
+ const SmallBitVector &Zeroable,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
switch (VT.SimpleTy) {
case MVT::v2i64:
- return lowerV2I64VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV2I64VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v2f64:
- return lowerV2F64VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV2F64VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v4i32:
- return lowerV4I32VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV4I32VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v4f32:
- return lowerV4F32VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV4F32VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v8i16:
- return lowerV8I16VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV8I16VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v16i8:
- return lowerV16I8VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV16I8VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
default:
llvm_unreachable("Unimplemented!");
}
}
-/// \brief Helper function to test whether a shuffle mask could be
-/// simplified by widening the elements being shuffled.
-///
-/// Appends the mask for wider elements in WidenedMask if valid. Otherwise
-/// leaves it in an unspecified state.
-///
-/// NOTE: This must handle normal vector shuffle masks and *target* vector
-/// shuffle masks. The latter have the special property of a '-2' representing
-/// a zero-ed lane of a vector.
-static bool canWidenShuffleElements(ArrayRef<int> Mask,
- SmallVectorImpl<int> &WidenedMask) {
- WidenedMask.assign(Mask.size() / 2, 0);
- for (int i = 0, Size = Mask.size(); i < Size; i += 2) {
- // If both elements are undef, its trivial.
- if (Mask[i] == SM_SentinelUndef && Mask[i + 1] == SM_SentinelUndef) {
- WidenedMask[i/2] = SM_SentinelUndef;
- continue;
- }
-
- // Check for an undef mask and a mask value properly aligned to fit with
- // a pair of values. If we find such a case, use the non-undef mask's value.
- if (Mask[i] == SM_SentinelUndef && Mask[i + 1] >= 0 && Mask[i + 1] % 2 == 1) {
- WidenedMask[i/2] = Mask[i + 1] / 2;
- continue;
- }
- if (Mask[i + 1] == SM_SentinelUndef && Mask[i] >= 0 && Mask[i] % 2 == 0) {
- WidenedMask[i/2] = Mask[i] / 2;
- continue;
- }
-
- // When zeroing, we need to spread the zeroing across both lanes to widen.
- if (Mask[i] == SM_SentinelZero || Mask[i + 1] == SM_SentinelZero) {
- if ((Mask[i] == SM_SentinelZero || Mask[i] == SM_SentinelUndef) &&
- (Mask[i + 1] == SM_SentinelZero || Mask[i + 1] == SM_SentinelUndef)) {
- WidenedMask[i/2] = SM_SentinelZero;
- continue;
- }
- return false;
- }
-
- // Finally check if the two mask values are adjacent and aligned with
- // a pair.
- if (Mask[i] != SM_SentinelUndef && Mask[i] % 2 == 0 && Mask[i] + 1 == Mask[i + 1]) {
- WidenedMask[i/2] = Mask[i] / 2;
- continue;
- }
-
- // Otherwise we can't safely widen the elements used in this shuffle.
- return false;
- }
- assert(WidenedMask.size() == Mask.size() / 2 &&
- "Incorrect size of mask after widening the elements!");
-
- return true;
-}
-
/// \brief Generic routine to split vector shuffle into half-sized shuffles.
///
/// This routine just extracts two subvectors, shuffles them independently, and
@@ -10712,15 +11621,20 @@ static SDValue lowerVectorShuffleAsLanePermuteAndBlend(const SDLoc &DL, MVT VT,
/// \brief Handle lowering 2-lane 128-bit shuffles.
static SDValue lowerV2X128VectorShuffle(const SDLoc &DL, MVT VT, SDValue V1,
SDValue V2, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
+ SmallVector<int, 4> WidenedMask;
+ if (!canWidenShuffleElements(Mask, WidenedMask))
+ return SDValue();
+
// TODO: If minimizing size and one of the inputs is a zero vector and the
// the zero vector has only one use, we could use a VPERM2X128 to save the
// instruction bytes needed to explicitly generate the zero vector.
// Blends are faster and handle all the non-lane-crossing cases.
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, VT, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
bool IsV1Zero = ISD::isBuildVectorAllZeros(V1.getNode());
@@ -10761,15 +11675,10 @@ static SDValue lowerV2X128VectorShuffle(const SDLoc &DL, MVT VT, SDValue V1,
// [6] - ignore
// [7] - zero high half of destination
- int MaskLO = Mask[0];
- if (MaskLO == SM_SentinelUndef)
- MaskLO = Mask[1] == SM_SentinelUndef ? 0 : Mask[1];
-
- int MaskHI = Mask[2];
- if (MaskHI == SM_SentinelUndef)
- MaskHI = Mask[3] == SM_SentinelUndef ? 0 : Mask[3];
+ int MaskLO = WidenedMask[0] < 0 ? 0 : WidenedMask[0];
+ int MaskHI = WidenedMask[1] < 0 ? 0 : WidenedMask[1];
- unsigned PermMask = MaskLO / 2 | (MaskHI / 2) << 4;
+ unsigned PermMask = MaskLO | (MaskHI << 4);
// If either input is a zero vector, replace it with an undef input.
// Shuffle mask values < 4 are selecting elements of V1.
@@ -10778,16 +11687,16 @@ static SDValue lowerV2X128VectorShuffle(const SDLoc &DL, MVT VT, SDValue V1,
// selecting the zero vector and setting the zero mask bit.
if (IsV1Zero) {
V1 = DAG.getUNDEF(VT);
- if (MaskLO < 4)
+ if (MaskLO < 2)
PermMask = (PermMask & 0xf0) | 0x08;
- if (MaskHI < 4)
+ if (MaskHI < 2)
PermMask = (PermMask & 0x0f) | 0x80;
}
if (IsV2Zero) {
V2 = DAG.getUNDEF(VT);
- if (MaskLO >= 4)
+ if (MaskLO >= 2)
PermMask = (PermMask & 0xf0) | 0x08;
- if (MaskHI >= 4)
+ if (MaskHI >= 2)
PermMask = (PermMask & 0x0f) | 0x80;
}
@@ -11178,35 +12087,65 @@ static SDValue lowerShuffleAsRepeatedMaskAndLanePermute(
SubLaneMask);
}
-static SDValue lowerVectorShuffleWithSHUFPD(const SDLoc &DL, MVT VT,
- ArrayRef<int> Mask, SDValue V1,
- SDValue V2, SelectionDAG &DAG) {
+static bool matchVectorShuffleWithSHUFPD(MVT VT, SDValue &V1, SDValue &V2,
+ unsigned &ShuffleImm,
+ ArrayRef<int> Mask) {
+ int NumElts = VT.getVectorNumElements();
+ assert(VT.getScalarType() == MVT::f64 &&
+ (NumElts == 2 || NumElts == 4 || NumElts == 8) &&
+ "Unexpected data type for VSHUFPD");
// Mask for V8F64: 0/1, 8/9, 2/3, 10/11, 4/5, ..
// Mask for V4F64; 0/1, 4/5, 2/3, 6/7..
- assert(VT.getScalarSizeInBits() == 64 && "Unexpected data type for VSHUFPD");
- int NumElts = VT.getVectorNumElements();
+ ShuffleImm = 0;
bool ShufpdMask = true;
bool CommutableMask = true;
- unsigned Immediate = 0;
for (int i = 0; i < NumElts; ++i) {
- if (Mask[i] < 0)
+ if (Mask[i] == SM_SentinelUndef)
continue;
+ if (Mask[i] < 0)
+ return false;
int Val = (i & 6) + NumElts * (i & 1);
- int CommutVal = (i & 0xe) + NumElts * ((i & 1)^1);
- if (Mask[i] < Val || Mask[i] > Val + 1)
+ int CommutVal = (i & 0xe) + NumElts * ((i & 1) ^ 1);
+ if (Mask[i] < Val || Mask[i] > Val + 1)
ShufpdMask = false;
- if (Mask[i] < CommutVal || Mask[i] > CommutVal + 1)
+ if (Mask[i] < CommutVal || Mask[i] > CommutVal + 1)
CommutableMask = false;
- Immediate |= (Mask[i] % 2) << i;
+ ShuffleImm |= (Mask[i] % 2) << i;
}
+
if (ShufpdMask)
- return DAG.getNode(X86ISD::SHUFP, DL, VT, V1, V2,
- DAG.getConstant(Immediate, DL, MVT::i8));
- if (CommutableMask)
- return DAG.getNode(X86ISD::SHUFP, DL, VT, V2, V1,
- DAG.getConstant(Immediate, DL, MVT::i8));
- return SDValue();
+ return true;
+ if (CommutableMask) {
+ std::swap(V1, V2);
+ return true;
+ }
+
+ return false;
+}
+
+static SDValue lowerVectorShuffleWithSHUFPD(const SDLoc &DL, MVT VT,
+ ArrayRef<int> Mask, SDValue V1,
+ SDValue V2, SelectionDAG &DAG) {
+ unsigned Immediate = 0;
+ if (!matchVectorShuffleWithSHUFPD(VT, V1, V2, Immediate, Mask))
+ return SDValue();
+
+ return DAG.getNode(X86ISD::SHUFP, DL, VT, V1, V2,
+ DAG.getConstant(Immediate, DL, MVT::i8));
+}
+
+static SDValue lowerVectorShuffleWithPERMV(const SDLoc &DL, MVT VT,
+ ArrayRef<int> Mask, SDValue V1,
+ SDValue V2, SelectionDAG &DAG) {
+ MVT MaskEltVT = MVT::getIntegerVT(VT.getScalarSizeInBits());
+ MVT MaskVecVT = MVT::getVectorVT(MaskEltVT, VT.getVectorNumElements());
+
+ SDValue MaskNode = getConstVector(Mask, MaskVecVT, DAG, DL, true);
+ if (V2.isUndef())
+ return DAG.getNode(X86ISD::VPERMV, DL, VT, MaskNode, V1);
+
+ return DAG.getNode(X86ISD::VPERMV3, DL, VT, V1, MaskNode, V2);
}
/// \brief Handle lowering of 4-lane 64-bit floating point shuffles.
@@ -11214,6 +12153,7 @@ static SDValue lowerVectorShuffleWithSHUFPD(const SDLoc &DL, MVT VT,
/// Also ends up handling lowering of 4-lane 64-bit integer shuffles when AVX2
/// isn't available.
static SDValue lowerV4F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11221,11 +12161,9 @@ static SDValue lowerV4F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
assert(V2.getSimpleValueType() == MVT::v4f64 && "Bad operand type!");
assert(Mask.size() == 4 && "Unexpected mask size for v4 shuffle!");
- SmallVector<int, 4> WidenedMask;
- if (canWidenShuffleElements(Mask, WidenedMask))
- if (SDValue V = lowerV2X128VectorShuffle(DL, MVT::v4f64, V1, V2, Mask,
- Subtarget, DAG))
- return V;
+ if (SDValue V = lowerV2X128VectorShuffle(DL, MVT::v4f64, V1, V2, Mask,
+ Zeroable, Subtarget, DAG))
+ return V;
if (V2.isUndef()) {
// Check for being able to broadcast a single element.
@@ -11268,7 +12206,7 @@ static SDValue lowerV4F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
return V;
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v4f64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Check if the blend happens to exactly fit that of SHUFPD.
@@ -11280,7 +12218,7 @@ static SDValue lowerV4F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// the results into the target lanes.
if (SDValue V = lowerShuffleAsRepeatedMaskAndLanePermute(
DL, MVT::v4f64, V1, V2, Mask, Subtarget, DAG))
- return V;
+ return V;
// Try to simplify this by merging 128-bit lanes to enable a lane-based
// shuffle. However, if we have AVX2 and either inputs are already in place,
@@ -11291,6 +12229,11 @@ static SDValue lowerV4F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
if (SDValue Result = lowerVectorShuffleByMerging128BitLanes(
DL, MVT::v4f64, V1, V2, Mask, Subtarget, DAG))
return Result;
+ // If we have VLX support, we can use VEXPAND.
+ if (Subtarget.hasVLX())
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v4f64, Zeroable, Mask,
+ V1, V2, DAG, Subtarget))
+ return V;
// If we have AVX2 then we always want to lower with a blend because an v4 we
// can fully permute the elements.
@@ -11307,6 +12250,7 @@ static SDValue lowerV4F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// This routine is only called when we have AVX2 and thus a reasonable
/// instruction set for v4i64 shuffling..
static SDValue lowerV4I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11315,14 +12259,12 @@ static SDValue lowerV4I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
assert(Mask.size() == 4 && "Unexpected mask size for v4 shuffle!");
assert(Subtarget.hasAVX2() && "We can only lower v4i64 with AVX2!");
- SmallVector<int, 4> WidenedMask;
- if (canWidenShuffleElements(Mask, WidenedMask))
- if (SDValue V = lowerV2X128VectorShuffle(DL, MVT::v4i64, V1, V2, Mask,
- Subtarget, DAG))
- return V;
+ if (SDValue V = lowerV2X128VectorShuffle(DL, MVT::v4i64, V1, V2, Mask,
+ Zeroable, Subtarget, DAG))
+ return V;
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v4i64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Check for being able to broadcast a single element.
@@ -11352,9 +12294,25 @@ static SDValue lowerV4I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v4i64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
+ // If we have VLX support, we can use VALIGN or VEXPAND.
+ if (Subtarget.hasVLX()) {
+ if (SDValue Rotate = lowerVectorShuffleAsRotate(DL, MVT::v4i64, V1, V2,
+ Mask, Subtarget, DAG))
+ return Rotate;
+
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v4i64, Zeroable, Mask,
+ V1, V2, DAG, Subtarget))
+ return V;
+ }
+
+ // Try to use PALIGNR.
+ if (SDValue Rotate = lowerVectorShuffleAsByteRotate(DL, MVT::v4i64, V1, V2,
+ Mask, Subtarget, DAG))
+ return Rotate;
+
// Use dedicated unpack instructions for masks that match their pattern.
if (SDValue V =
lowerVectorShuffleWithUNPCK(DL, MVT::v4i64, Mask, V1, V2, DAG))
@@ -11364,8 +12322,8 @@ static SDValue lowerV4I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// shuffle. However, if we have AVX2 and either inputs are already in place,
// we will be able to shuffle even across lanes the other input in a single
// instruction so skip this pattern.
- if (!(Subtarget.hasAVX2() && (isShuffleMaskInputInPlace(0, Mask) ||
- isShuffleMaskInputInPlace(1, Mask))))
+ if (!isShuffleMaskInputInPlace(0, Mask) &&
+ !isShuffleMaskInputInPlace(1, Mask))
if (SDValue Result = lowerVectorShuffleByMerging128BitLanes(
DL, MVT::v4i64, V1, V2, Mask, Subtarget, DAG))
return Result;
@@ -11380,6 +12338,7 @@ static SDValue lowerV4I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// Also ends up handling lowering of 8-lane 32-bit integer shuffles when AVX2
/// isn't available.
static SDValue lowerV8F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11388,7 +12347,7 @@ static SDValue lowerV8F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
assert(Mask.size() == 8 && "Unexpected mask size for v8 shuffle!");
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v8f32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Check for being able to broadcast a single element.
@@ -11432,17 +12391,12 @@ static SDValue lowerV8F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// If we have a single input shuffle with different shuffle patterns in the
// two 128-bit lanes use the variable mask to VPERMILPS.
if (V2.isUndef()) {
- SDValue VPermMask[8];
- for (int i = 0; i < 8; ++i)
- VPermMask[i] = Mask[i] < 0 ? DAG.getUNDEF(MVT::i32)
- : DAG.getConstant(Mask[i], DL, MVT::i32);
+ SDValue VPermMask = getConstVector(Mask, MVT::v8i32, DAG, DL, true);
if (!is128BitLaneCrossingShuffleMask(MVT::v8f32, Mask))
- return DAG.getNode(X86ISD::VPERMILPV, DL, MVT::v8f32, V1,
- DAG.getBuildVector(MVT::v8i32, DL, VPermMask));
+ return DAG.getNode(X86ISD::VPERMILPV, DL, MVT::v8f32, V1, VPermMask);
if (Subtarget.hasAVX2())
- return DAG.getNode(X86ISD::VPERMV, DL, MVT::v8f32,
- DAG.getBuildVector(MVT::v8i32, DL, VPermMask), V1);
+ return DAG.getNode(X86ISD::VPERMV, DL, MVT::v8f32, VPermMask, V1);
// Otherwise, fall back.
return lowerVectorShuffleAsLanePermuteAndBlend(DL, MVT::v8f32, V1, V2, Mask,
@@ -11454,6 +12408,11 @@ static SDValue lowerV8F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
if (SDValue Result = lowerVectorShuffleByMerging128BitLanes(
DL, MVT::v8f32, V1, V2, Mask, Subtarget, DAG))
return Result;
+ // If we have VLX support, we can use VEXPAND.
+ if (Subtarget.hasVLX())
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v8f32, Zeroable, Mask,
+ V1, V2, DAG, Subtarget))
+ return V;
// If we have AVX2 then we always want to lower with a blend because at v8 we
// can fully permute the elements.
@@ -11470,6 +12429,7 @@ static SDValue lowerV8F32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// This routine is only called when we have AVX2 and thus a reasonable
/// instruction set for v8i32 shuffling..
static SDValue lowerV8I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11481,12 +12441,12 @@ static SDValue lowerV8I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Whenever we can lower this as a zext, that instruction is strictly faster
// than any alternative. It also allows us to fold memory operands into the
// shuffle in many cases.
- if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(DL, MVT::v8i32, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v8i32, V1, V2, Mask, Zeroable, Subtarget, DAG))
return ZExt;
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v8i32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Check for being able to broadcast a single element.
@@ -11498,7 +12458,9 @@ static SDValue lowerV8I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// efficient instructions that mirror the shuffles across the two 128-bit
// lanes.
SmallVector<int, 4> RepeatedMask;
- if (is128BitLaneRepeatedShuffleMask(MVT::v8i32, Mask, RepeatedMask)) {
+ bool Is128BitLaneRepeatedShuffle =
+ is128BitLaneRepeatedShuffleMask(MVT::v8i32, Mask, RepeatedMask);
+ if (Is128BitLaneRepeatedShuffle) {
assert(RepeatedMask.size() == 4 && "Unexpected repeated mask size!");
if (V2.isUndef())
return DAG.getNode(X86ISD::PSHUFD, DL, MVT::v8i32, V1,
@@ -11512,16 +12474,27 @@ static SDValue lowerV8I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v8i32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
+ // If we have VLX support, we can use VALIGN or EXPAND.
+ if (Subtarget.hasVLX()) {
+ if (SDValue Rotate = lowerVectorShuffleAsRotate(DL, MVT::v8i32, V1, V2,
+ Mask, Subtarget, DAG))
+ return Rotate;
+
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v8i32, Zeroable, Mask,
+ V1, V2, DAG, Subtarget))
+ return V;
+ }
+
// Try to use byte rotation instructions.
if (SDValue Rotate = lowerVectorShuffleAsByteRotate(
DL, MVT::v8i32, V1, V2, Mask, Subtarget, DAG))
return Rotate;
// Try to create an in-lane repeating shuffle mask and then shuffle the
- // the results into the target lanes.
+ // results into the target lanes.
if (SDValue V = lowerShuffleAsRepeatedMaskAndLanePermute(
DL, MVT::v8i32, V1, V2, Mask, Subtarget, DAG))
return V;
@@ -11529,12 +12502,19 @@ static SDValue lowerV8I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// If the shuffle patterns aren't repeated but it is a single input, directly
// generate a cross-lane VPERMD instruction.
if (V2.isUndef()) {
- SDValue VPermMask[8];
- for (int i = 0; i < 8; ++i)
- VPermMask[i] = Mask[i] < 0 ? DAG.getUNDEF(MVT::i32)
- : DAG.getConstant(Mask[i], DL, MVT::i32);
- return DAG.getNode(X86ISD::VPERMV, DL, MVT::v8i32,
- DAG.getBuildVector(MVT::v8i32, DL, VPermMask), V1);
+ SDValue VPermMask = getConstVector(Mask, MVT::v8i32, DAG, DL, true);
+ return DAG.getNode(X86ISD::VPERMV, DL, MVT::v8i32, VPermMask, V1);
+ }
+
+ // Assume that a single SHUFPS is faster than an alternative sequence of
+ // multiple instructions (even if the CPU has a domain penalty).
+ // If some CPU is harmed by the domain switch, we can fix it in a later pass.
+ if (Is128BitLaneRepeatedShuffle && isSingleSHUFPSMask(RepeatedMask)) {
+ SDValue CastV1 = DAG.getBitcast(MVT::v8f32, V1);
+ SDValue CastV2 = DAG.getBitcast(MVT::v8f32, V2);
+ SDValue ShufPS = lowerVectorShuffleWithSHUFPS(DL, MVT::v8f32, RepeatedMask,
+ CastV1, CastV2, DAG);
+ return DAG.getBitcast(MVT::v8i32, ShufPS);
}
// Try to simplify this by merging 128-bit lanes to enable a lane-based
@@ -11553,6 +12533,7 @@ static SDValue lowerV8I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// This routine is only called when we have AVX2 and thus a reasonable
/// instruction set for v16i16 shuffling..
static SDValue lowerV16I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11564,8 +12545,8 @@ static SDValue lowerV16I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Whenever we can lower this as a zext, that instruction is strictly faster
// than any alternative. It also allows us to fold memory operands into the
// shuffle in many cases.
- if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(DL, MVT::v16i16, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v16i16, V1, V2, Mask, Zeroable, Subtarget, DAG))
return ZExt;
// Check for being able to broadcast a single element.
@@ -11574,7 +12555,7 @@ static SDValue lowerV16I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
return Broadcast;
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v16i16, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -11584,7 +12565,7 @@ static SDValue lowerV16I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v16i16, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// Try to use byte rotation instructions.
@@ -11615,10 +12596,14 @@ static SDValue lowerV16I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
}
}
- if (SDValue PSHUFB = lowerVectorShuffleWithPSHUFB(DL, MVT::v16i16, Mask, V1,
- V2, Subtarget, DAG))
+ if (SDValue PSHUFB = lowerVectorShuffleWithPSHUFB(
+ DL, MVT::v16i16, Mask, V1, V2, Zeroable, Subtarget, DAG))
return PSHUFB;
+ // AVX512BWVL can lower to VPERMW.
+ if (Subtarget.hasBWI() && Subtarget.hasVLX())
+ return lowerVectorShuffleWithPERMV(DL, MVT::v16i16, Mask, V1, V2, DAG);
+
// Try to simplify this by merging 128-bit lanes to enable a lane-based
// shuffle.
if (SDValue Result = lowerVectorShuffleByMerging128BitLanes(
@@ -11634,6 +12619,7 @@ static SDValue lowerV16I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// This routine is only called when we have AVX2 and thus a reasonable
/// instruction set for v32i8 shuffling..
static SDValue lowerV32I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11645,8 +12631,8 @@ static SDValue lowerV32I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Whenever we can lower this as a zext, that instruction is strictly faster
// than any alternative. It also allows us to fold memory operands into the
// shuffle in many cases.
- if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(DL, MVT::v32i8, V1, V2,
- Mask, Subtarget, DAG))
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v32i8, V1, V2, Mask, Zeroable, Subtarget, DAG))
return ZExt;
// Check for being able to broadcast a single element.
@@ -11655,7 +12641,7 @@ static SDValue lowerV32I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
return Broadcast;
if (SDValue Blend = lowerVectorShuffleAsBlend(DL, MVT::v32i8, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Blend;
// Use dedicated unpack instructions for masks that match their pattern.
@@ -11665,7 +12651,7 @@ static SDValue lowerV32I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v32i8, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// Try to use byte rotation instructions.
@@ -11685,8 +12671,8 @@ static SDValue lowerV32I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
return lowerVectorShuffleAsLanePermuteAndBlend(DL, MVT::v32i8, V1, V2, Mask,
DAG);
- if (SDValue PSHUFB = lowerVectorShuffleWithPSHUFB(DL, MVT::v32i8, Mask, V1,
- V2, Subtarget, DAG))
+ if (SDValue PSHUFB = lowerVectorShuffleWithPSHUFB(
+ DL, MVT::v32i8, Mask, V1, V2, Zeroable, Subtarget, DAG))
return PSHUFB;
// Try to simplify this by merging 128-bit lanes to enable a lane-based
@@ -11706,6 +12692,7 @@ static SDValue lowerV32I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// together based on the available instructions.
static SDValue lower256BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
MVT VT, SDValue V1, SDValue V2,
+ const SmallBitVector &Zeroable,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
// If we have a single input to the zero element, insert that into V1 if we
@@ -11715,7 +12702,7 @@ static SDValue lower256BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
if (NumV2Elements == 1 && Mask[0] >= NumElts)
if (SDValue Insertion = lowerVectorShuffleAsElementInsertion(
- DL, VT, V1, V2, Mask, Subtarget, DAG))
+ DL, VT, V1, V2, Mask, Zeroable, Subtarget, DAG))
return Insertion;
// Handle special cases where the lower or upper half is UNDEF.
@@ -11734,7 +12721,8 @@ static SDValue lower256BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
if (ElementBits < 32) {
// No floating point type available, if we can't use the bit operations
// for masking/blending then decompose into 128-bit vectors.
- if (SDValue V = lowerVectorShuffleAsBitMask(DL, VT, V1, V2, Mask, DAG))
+ if (SDValue V =
+ lowerVectorShuffleAsBitMask(DL, VT, V1, V2, Mask, Zeroable, DAG))
return V;
if (SDValue V = lowerVectorShuffleAsBitBlend(DL, VT, V1, V2, Mask, DAG))
return V;
@@ -11750,17 +12738,17 @@ static SDValue lower256BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
switch (VT.SimpleTy) {
case MVT::v4f64:
- return lowerV4F64VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV4F64VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v4i64:
- return lowerV4I64VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV4I64VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v8f32:
- return lowerV8F32VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV8F32VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v8i32:
- return lowerV8I32VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV8I32VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v16i16:
- return lowerV16I16VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV16I16VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v32i8:
- return lowerV32I8VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV32I8VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
default:
llvm_unreachable("Not a valid 256-bit x86 vector type!");
@@ -11782,57 +12770,81 @@ static SDValue lowerV4X128VectorShuffle(const SDLoc &DL, MVT VT,
if (!canWidenShuffleElements(Mask, WidenedMask))
return SDValue();
+ // Check for patterns which can be matched with a single insert of a 256-bit
+ // subvector.
+ bool OnlyUsesV1 = isShuffleEquivalent(V1, V2, Mask,
+ {0, 1, 2, 3, 0, 1, 2, 3});
+ if (OnlyUsesV1 || isShuffleEquivalent(V1, V2, Mask,
+ {0, 1, 2, 3, 8, 9, 10, 11})) {
+ MVT SubVT = MVT::getVectorVT(VT.getVectorElementType(), 4);
+ SDValue LoV = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT, V1,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue HiV = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT,
+ OnlyUsesV1 ? V1 : V2,
+ DAG.getIntPtrConstant(0, DL));
+ return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, LoV, HiV);
+ }
+
+ assert(WidenedMask.size() == 4);
+
+ // See if this is an insertion of the lower 128-bits of V2 into V1.
+ bool IsInsert = true;
+ int V2Index = -1;
+ for (int i = 0; i < 4; ++i) {
+ assert(WidenedMask[i] >= -1);
+ if (WidenedMask[i] < 0)
+ continue;
+
+ // Make sure all V1 subvectors are in place.
+ if (WidenedMask[i] < 4) {
+ if (WidenedMask[i] != i) {
+ IsInsert = false;
+ break;
+ }
+ } else {
+ // Make sure we only have a single V2 index and its the lowest 128-bits.
+ if (V2Index >= 0 || WidenedMask[i] != 4) {
+ IsInsert = false;
+ break;
+ }
+ V2Index = i;
+ }
+ }
+ if (IsInsert && V2Index >= 0) {
+ MVT SubVT = MVT::getVectorVT(VT.getVectorElementType(), 2);
+ SDValue Subvec = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, SubVT, V2,
+ DAG.getIntPtrConstant(0, DL));
+ return insert128BitVector(V1, Subvec, V2Index * 2, DAG, DL);
+ }
+
+ // Try to lower to to vshuf64x2/vshuf32x4.
SDValue Ops[2] = {DAG.getUNDEF(VT), DAG.getUNDEF(VT)};
+ unsigned PermMask = 0;
// Insure elements came from the same Op.
- int MaxOp1Index = VT.getVectorNumElements()/2 - 1;
- for (int i = 0, Size = WidenedMask.size(); i < Size; ++i) {
- if (WidenedMask[i] == SM_SentinelZero)
- return SDValue();
- if (WidenedMask[i] == SM_SentinelUndef)
+ for (int i = 0; i < 4; ++i) {
+ assert(WidenedMask[i] >= -1);
+ if (WidenedMask[i] < 0)
continue;
- SDValue Op = WidenedMask[i] > MaxOp1Index ? V2 : V1;
- unsigned OpIndex = (i < Size/2) ? 0 : 1;
+ SDValue Op = WidenedMask[i] >= 4 ? V2 : V1;
+ unsigned OpIndex = i / 2;
if (Ops[OpIndex].isUndef())
Ops[OpIndex] = Op;
else if (Ops[OpIndex] != Op)
return SDValue();
- }
-
- // Form a 128-bit permutation.
- // Convert the 64-bit shuffle mask selection values into 128-bit selection
- // bits defined by a vshuf64x2 instruction's immediate control byte.
- unsigned PermMask = 0, Imm = 0;
- unsigned ControlBitsNum = WidenedMask.size() / 2;
- for (int i = 0, Size = WidenedMask.size(); i < Size; ++i) {
- // Use first element in place of undef mask.
- Imm = (WidenedMask[i] == SM_SentinelUndef) ? 0 : WidenedMask[i];
- PermMask |= (Imm % WidenedMask.size()) << (i * ControlBitsNum);
+ // Convert the 128-bit shuffle mask selection values into 128-bit selection
+ // bits defined by a vshuf64x2 instruction's immediate control byte.
+ PermMask |= (WidenedMask[i] % 4) << (i * 2);
}
return DAG.getNode(X86ISD::SHUF128, DL, VT, Ops[0], Ops[1],
DAG.getConstant(PermMask, DL, MVT::i8));
}
-static SDValue lowerVectorShuffleWithPERMV(const SDLoc &DL, MVT VT,
- ArrayRef<int> Mask, SDValue V1,
- SDValue V2, SelectionDAG &DAG) {
-
- assert(VT.getScalarSizeInBits() >= 16 && "Unexpected data type for PERMV");
-
- MVT MaskEltVT = MVT::getIntegerVT(VT.getScalarSizeInBits());
- MVT MaskVecVT = MVT::getVectorVT(MaskEltVT, VT.getVectorNumElements());
-
- SDValue MaskNode = getConstVector(Mask, MaskVecVT, DAG, DL, true);
- if (V2.isUndef())
- return DAG.getNode(X86ISD::VPERMV, DL, VT, MaskNode, V1);
-
- return DAG.getNode(X86ISD::VPERMV3, DL, VT, V1, MaskNode, V2);
-}
-
/// \brief Handle lowering of 8-lane 64-bit floating point shuffles.
static SDValue lowerV8F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11875,11 +12887,16 @@ static SDValue lowerV8F64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
lowerVectorShuffleWithSHUFPD(DL, MVT::v8f64, Mask, V1, V2, DAG))
return Op;
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v8f64, Zeroable, Mask, V1,
+ V2, DAG, Subtarget))
+ return V;
+
return lowerVectorShuffleWithPERMV(DL, MVT::v8f64, Mask, V1, V2, DAG);
}
/// \brief Handle lowering of 16-lane 32-bit floating point shuffles.
static SDValue lowerV16F32VectorShuffle(SDLoc DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11911,12 +12928,17 @@ static SDValue lowerV16F32VectorShuffle(SDLoc DL, ArrayRef<int> Mask,
// Otherwise, fall back to a SHUFPS sequence.
return lowerVectorShuffleWithSHUFPS(DL, MVT::v16f32, RepeatedMask, V1, V2, DAG);
}
+ // If we have AVX512F support, we can use VEXPAND.
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v16f32, Zeroable, Mask,
+ V1, V2, DAG, Subtarget))
+ return V;
return lowerVectorShuffleWithPERMV(DL, MVT::v16f32, Mask, V1, V2, DAG);
}
/// \brief Handle lowering of 8-lane 64-bit integer shuffles.
static SDValue lowerV8I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11951,18 +12973,33 @@ static SDValue lowerV8I64VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v8i64, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
+ // Try to use VALIGN.
+ if (SDValue Rotate = lowerVectorShuffleAsRotate(DL, MVT::v8i64, V1, V2,
+ Mask, Subtarget, DAG))
+ return Rotate;
+
+ // Try to use PALIGNR.
+ if (SDValue Rotate = lowerVectorShuffleAsByteRotate(DL, MVT::v8i64, V1, V2,
+ Mask, Subtarget, DAG))
+ return Rotate;
+
if (SDValue Unpck =
lowerVectorShuffleWithUNPCK(DL, MVT::v8i64, Mask, V1, V2, DAG))
return Unpck;
+ // If we have AVX512F support, we can use VEXPAND.
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v8i64, Zeroable, Mask, V1,
+ V2, DAG, Subtarget))
+ return V;
return lowerVectorShuffleWithPERMV(DL, MVT::v8i64, Mask, V1, V2, DAG);
}
/// \brief Handle lowering of 16-lane 32-bit integer shuffles.
static SDValue lowerV16I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -11970,11 +13007,20 @@ static SDValue lowerV16I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
assert(V2.getSimpleValueType() == MVT::v16i32 && "Bad operand type!");
assert(Mask.size() == 16 && "Unexpected mask size for v16 shuffle!");
+ // Whenever we can lower this as a zext, that instruction is strictly faster
+ // than any alternative. It also allows us to fold memory operands into the
+ // shuffle in many cases.
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v16i32, V1, V2, Mask, Zeroable, Subtarget, DAG))
+ return ZExt;
+
// If the shuffle mask is repeated in each 128-bit lane we can use more
// efficient instructions that mirror the shuffles across the four 128-bit
// lanes.
SmallVector<int, 4> RepeatedMask;
- if (is128BitLaneRepeatedShuffleMask(MVT::v16i32, Mask, RepeatedMask)) {
+ bool Is128BitLaneRepeatedShuffle =
+ is128BitLaneRepeatedShuffleMask(MVT::v16i32, Mask, RepeatedMask);
+ if (Is128BitLaneRepeatedShuffle) {
assert(RepeatedMask.size() == 4 && "Unexpected repeated mask size!");
if (V2.isUndef())
return DAG.getNode(X86ISD::PSHUFD, DL, MVT::v16i32, V1,
@@ -11988,20 +13034,40 @@ static SDValue lowerV16I32VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v16i32, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
+ // Try to use VALIGN.
+ if (SDValue Rotate = lowerVectorShuffleAsRotate(DL, MVT::v16i32, V1, V2,
+ Mask, Subtarget, DAG))
+ return Rotate;
+
// Try to use byte rotation instructions.
if (Subtarget.hasBWI())
if (SDValue Rotate = lowerVectorShuffleAsByteRotate(
DL, MVT::v16i32, V1, V2, Mask, Subtarget, DAG))
return Rotate;
+ // Assume that a single SHUFPS is faster than using a permv shuffle.
+ // If some CPU is harmed by the domain switch, we can fix it in a later pass.
+ if (Is128BitLaneRepeatedShuffle && isSingleSHUFPSMask(RepeatedMask)) {
+ SDValue CastV1 = DAG.getBitcast(MVT::v16f32, V1);
+ SDValue CastV2 = DAG.getBitcast(MVT::v16f32, V2);
+ SDValue ShufPS = lowerVectorShuffleWithSHUFPS(DL, MVT::v16f32, RepeatedMask,
+ CastV1, CastV2, DAG);
+ return DAG.getBitcast(MVT::v16i32, ShufPS);
+ }
+ // If we have AVX512F support, we can use VEXPAND.
+ if (SDValue V = lowerVectorShuffleToEXPAND(DL, MVT::v16i32, Zeroable, Mask,
+ V1, V2, DAG, Subtarget))
+ return V;
+
return lowerVectorShuffleWithPERMV(DL, MVT::v16i32, Mask, V1, V2, DAG);
}
/// \brief Handle lowering of 32-lane 16-bit integer shuffles.
static SDValue lowerV32I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -12010,6 +13076,13 @@ static SDValue lowerV32I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
assert(Mask.size() == 32 && "Unexpected mask size for v32 shuffle!");
assert(Subtarget.hasBWI() && "We can only lower v32i16 with AVX-512-BWI!");
+ // Whenever we can lower this as a zext, that instruction is strictly faster
+ // than any alternative. It also allows us to fold memory operands into the
+ // shuffle in many cases.
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v32i16, V1, V2, Mask, Zeroable, Subtarget, DAG))
+ return ZExt;
+
// Use dedicated unpack instructions for masks that match their pattern.
if (SDValue V =
lowerVectorShuffleWithUNPCK(DL, MVT::v32i16, Mask, V1, V2, DAG))
@@ -12017,7 +13090,7 @@ static SDValue lowerV32I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v32i16, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// Try to use byte rotation instructions.
@@ -12041,6 +13114,7 @@ static SDValue lowerV32I16VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// \brief Handle lowering of 64-lane 8-bit integer shuffles.
static SDValue lowerV64I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
+ const SmallBitVector &Zeroable,
SDValue V1, SDValue V2,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
@@ -12049,6 +13123,13 @@ static SDValue lowerV64I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
assert(Mask.size() == 64 && "Unexpected mask size for v64 shuffle!");
assert(Subtarget.hasBWI() && "We can only lower v64i8 with AVX-512-BWI!");
+ // Whenever we can lower this as a zext, that instruction is strictly faster
+ // than any alternative. It also allows us to fold memory operands into the
+ // shuffle in many cases.
+ if (SDValue ZExt = lowerVectorShuffleAsZeroOrAnyExtend(
+ DL, MVT::v64i8, V1, V2, Mask, Zeroable, Subtarget, DAG))
+ return ZExt;
+
// Use dedicated unpack instructions for masks that match their pattern.
if (SDValue V =
lowerVectorShuffleWithUNPCK(DL, MVT::v64i8, Mask, V1, V2, DAG))
@@ -12056,7 +13137,7 @@ static SDValue lowerV64I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// Try to use shift instructions.
if (SDValue Shift = lowerVectorShuffleAsShift(DL, MVT::v64i8, V1, V2, Mask,
- Subtarget, DAG))
+ Zeroable, Subtarget, DAG))
return Shift;
// Try to use byte rotation instructions.
@@ -12064,10 +13145,20 @@ static SDValue lowerV64I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
DL, MVT::v64i8, V1, V2, Mask, Subtarget, DAG))
return Rotate;
- if (SDValue PSHUFB = lowerVectorShuffleWithPSHUFB(DL, MVT::v64i8, Mask, V1,
- V2, Subtarget, DAG))
+ if (SDValue PSHUFB = lowerVectorShuffleWithPSHUFB(
+ DL, MVT::v64i8, Mask, V1, V2, Zeroable, Subtarget, DAG))
return PSHUFB;
+ // VBMI can use VPERMV/VPERMV3 byte shuffles.
+ if (Subtarget.hasVBMI())
+ return lowerVectorShuffleWithPERMV(DL, MVT::v64i8, Mask, V1, V2, DAG);
+
+ // Try to create an in-lane repeating shuffle mask and then shuffle the
+ // the results into the target lanes.
+ if (SDValue V = lowerShuffleAsRepeatedMaskAndLanePermute(
+ DL, MVT::v64i8, V1, V2, Mask, Subtarget, DAG))
+ return V;
+
// FIXME: Implement direct support for this type!
return splitAndLowerVectorShuffle(DL, MVT::v64i8, V1, V2, Mask, DAG);
}
@@ -12079,11 +13170,22 @@ static SDValue lowerV64I8VectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
/// together based on the available instructions.
static SDValue lower512BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
MVT VT, SDValue V1, SDValue V2,
+ const SmallBitVector &Zeroable,
const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
assert(Subtarget.hasAVX512() &&
"Cannot lower 512-bit vectors w/ basic ISA!");
+ // If we have a single input to the zero element, insert that into V1 if we
+ // can do so cheaply.
+ int NumElts = Mask.size();
+ int NumV2Elements = count_if(Mask, [NumElts](int M) { return M >= NumElts; });
+
+ if (NumV2Elements == 1 && Mask[0] >= NumElts)
+ if (SDValue Insertion = lowerVectorShuffleAsElementInsertion(
+ DL, VT, V1, V2, Mask, Zeroable, Subtarget, DAG))
+ return Insertion;
+
// Check for being able to broadcast a single element.
if (SDValue Broadcast =
lowerVectorShuffleAsBroadcast(DL, VT, V1, V2, Mask, Subtarget, DAG))
@@ -12095,17 +13197,17 @@ static SDValue lower512BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
// the requisite ISA extensions for that element type are available.
switch (VT.SimpleTy) {
case MVT::v8f64:
- return lowerV8F64VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV8F64VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v16f32:
- return lowerV16F32VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV16F32VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v8i64:
- return lowerV8I64VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV8I64VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v16i32:
- return lowerV16I32VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV16I32VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v32i16:
- return lowerV32I16VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV32I16VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
case MVT::v64i8:
- return lowerV64I8VectorShuffle(DL, Mask, V1, V2, Subtarget, DAG);
+ return lowerV64I8VectorShuffle(DL, Mask, Zeroable, V1, V2, Subtarget, DAG);
default:
llvm_unreachable("Not a valid 512-bit x86 vector type!");
@@ -12161,9 +13263,81 @@ static SDValue lower1BitVectorShuffle(const SDLoc &DL, ArrayRef<int> Mask,
V2 = getOnesVector(ExtVT, Subtarget, DAG, DL);
else
V2 = DAG.getNode(ISD::SIGN_EXTEND, DL, ExtVT, V2);
- return DAG.getNode(ISD::TRUNCATE, DL, VT,
- DAG.getVectorShuffle(ExtVT, DL, V1, V2, Mask));
+
+ SDValue Shuffle = DAG.getVectorShuffle(ExtVT, DL, V1, V2, Mask);
+ // i1 was sign extended we can use X86ISD::CVT2MASK.
+ int NumElems = VT.getVectorNumElements();
+ if ((Subtarget.hasBWI() && (NumElems >= 32)) ||
+ (Subtarget.hasDQI() && (NumElems < 32)))
+ return DAG.getNode(X86ISD::CVT2MASK, DL, VT, Shuffle);
+
+ return DAG.getNode(ISD::TRUNCATE, DL, VT, Shuffle);
}
+
+/// Helper function that returns true if the shuffle mask should be
+/// commuted to improve canonicalization.
+static bool canonicalizeShuffleMaskWithCommute(ArrayRef<int> Mask) {
+ int NumElements = Mask.size();
+
+ int NumV1Elements = 0, NumV2Elements = 0;
+ for (int M : Mask)
+ if (M < 0)
+ continue;
+ else if (M < NumElements)
+ ++NumV1Elements;
+ else
+ ++NumV2Elements;
+
+ // Commute the shuffle as needed such that more elements come from V1 than
+ // V2. This allows us to match the shuffle pattern strictly on how many
+ // elements come from V1 without handling the symmetric cases.
+ if (NumV2Elements > NumV1Elements)
+ return true;
+
+ assert(NumV1Elements > 0 && "No V1 indices");
+
+ if (NumV2Elements == 0)
+ return false;
+
+ // When the number of V1 and V2 elements are the same, try to minimize the
+ // number of uses of V2 in the low half of the vector. When that is tied,
+ // ensure that the sum of indices for V1 is equal to or lower than the sum
+ // indices for V2. When those are equal, try to ensure that the number of odd
+ // indices for V1 is lower than the number of odd indices for V2.
+ if (NumV1Elements == NumV2Elements) {
+ int LowV1Elements = 0, LowV2Elements = 0;
+ for (int M : Mask.slice(0, NumElements / 2))
+ if (M >= NumElements)
+ ++LowV2Elements;
+ else if (M >= 0)
+ ++LowV1Elements;
+ if (LowV2Elements > LowV1Elements)
+ return true;
+ if (LowV2Elements == LowV1Elements) {
+ int SumV1Indices = 0, SumV2Indices = 0;
+ for (int i = 0, Size = Mask.size(); i < Size; ++i)
+ if (Mask[i] >= NumElements)
+ SumV2Indices += i;
+ else if (Mask[i] >= 0)
+ SumV1Indices += i;
+ if (SumV2Indices < SumV1Indices)
+ return true;
+ if (SumV2Indices == SumV1Indices) {
+ int NumV1OddIndices = 0, NumV2OddIndices = 0;
+ for (int i = 0, Size = Mask.size(); i < Size; ++i)
+ if (Mask[i] >= NumElements)
+ NumV2OddIndices += i % 2;
+ else if (Mask[i] >= 0)
+ NumV1OddIndices += i % 2;
+ if (NumV2OddIndices < NumV1OddIndices)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
/// \brief Top-level lowering for x86 vector shuffles.
///
/// This handles decomposition, canonicalization, and lowering of all x86
@@ -12209,6 +13383,12 @@ static SDValue lowerVectorShuffle(SDValue Op, const X86Subtarget &Subtarget,
return DAG.getVectorShuffle(VT, DL, V1, V2, NewMask);
}
+ // Check for illegal shuffle mask element index values.
+ int MaskUpperLimit = Mask.size() * (V2IsUndef ? 1 : 2); (void)MaskUpperLimit;
+ assert(llvm::all_of(Mask,
+ [&](int M) { return -1 <= M && M < MaskUpperLimit; }) &&
+ "Out of bounds shuffle index");
+
// We actually see shuffles that are entirely re-arrangements of a set of
// zero inputs. This mostly happens while decomposing complex shuffles into
// simple ones. Directly lower these as a buildvector of zeros.
@@ -12237,69 +13417,22 @@ static SDValue lowerVectorShuffle(SDValue Op, const X86Subtarget &Subtarget,
}
}
- int NumV1Elements = 0, NumUndefElements = 0, NumV2Elements = 0;
- for (int M : Mask)
- if (M < 0)
- ++NumUndefElements;
- else if (M < NumElements)
- ++NumV1Elements;
- else
- ++NumV2Elements;
-
- // Commute the shuffle as needed such that more elements come from V1 than
- // V2. This allows us to match the shuffle pattern strictly on how many
- // elements come from V1 without handling the symmetric cases.
- if (NumV2Elements > NumV1Elements)
+ // Commute the shuffle if it will improve canonicalization.
+ if (canonicalizeShuffleMaskWithCommute(Mask))
return DAG.getCommutedVectorShuffle(*SVOp);
- assert(NumV1Elements > 0 && "No V1 indices");
- assert((NumV2Elements > 0 || V2IsUndef) && "V2 not undef, but not used");
-
- // When the number of V1 and V2 elements are the same, try to minimize the
- // number of uses of V2 in the low half of the vector. When that is tied,
- // ensure that the sum of indices for V1 is equal to or lower than the sum
- // indices for V2. When those are equal, try to ensure that the number of odd
- // indices for V1 is lower than the number of odd indices for V2.
- if (NumV1Elements == NumV2Elements) {
- int LowV1Elements = 0, LowV2Elements = 0;
- for (int M : Mask.slice(0, NumElements / 2))
- if (M >= NumElements)
- ++LowV2Elements;
- else if (M >= 0)
- ++LowV1Elements;
- if (LowV2Elements > LowV1Elements)
- return DAG.getCommutedVectorShuffle(*SVOp);
- if (LowV2Elements == LowV1Elements) {
- int SumV1Indices = 0, SumV2Indices = 0;
- for (int i = 0, Size = Mask.size(); i < Size; ++i)
- if (Mask[i] >= NumElements)
- SumV2Indices += i;
- else if (Mask[i] >= 0)
- SumV1Indices += i;
- if (SumV2Indices < SumV1Indices)
- return DAG.getCommutedVectorShuffle(*SVOp);
- if (SumV2Indices == SumV1Indices) {
- int NumV1OddIndices = 0, NumV2OddIndices = 0;
- for (int i = 0, Size = Mask.size(); i < Size; ++i)
- if (Mask[i] >= NumElements)
- NumV2OddIndices += i % 2;
- else if (Mask[i] >= 0)
- NumV1OddIndices += i % 2;
- if (NumV2OddIndices < NumV1OddIndices)
- return DAG.getCommutedVectorShuffle(*SVOp);
- }
- }
- }
-
// For each vector width, delegate to a specialized lowering routine.
if (VT.is128BitVector())
- return lower128BitVectorShuffle(DL, Mask, VT, V1, V2, Subtarget, DAG);
+ return lower128BitVectorShuffle(DL, Mask, VT, V1, V2, Zeroable, Subtarget,
+ DAG);
if (VT.is256BitVector())
- return lower256BitVectorShuffle(DL, Mask, VT, V1, V2, Subtarget, DAG);
+ return lower256BitVectorShuffle(DL, Mask, VT, V1, V2, Zeroable, Subtarget,
+ DAG);
if (VT.is512BitVector())
- return lower512BitVectorShuffle(DL, Mask, VT, V1, V2, Subtarget, DAG);
+ return lower512BitVectorShuffle(DL, Mask, VT, V1, V2, Zeroable, Subtarget,
+ DAG);
if (Is1BitVector)
return lower1BitVectorShuffle(DL, Mask, VT, V1, V2, Subtarget, DAG);
@@ -12392,21 +13525,6 @@ static SDValue LowerEXTRACT_VECTOR_ELT_SSE4(SDValue Op, SelectionDAG &DAG) {
return DAG.getNode(ISD::TRUNCATE, dl, VT, Assert);
}
- if (VT.getSizeInBits() == 16) {
- // If Idx is 0, it's cheaper to do a move instead of a pextrw.
- if (isNullConstant(Op.getOperand(1)))
- return DAG.getNode(
- ISD::TRUNCATE, dl, MVT::i16,
- DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32,
- DAG.getBitcast(MVT::v4i32, Op.getOperand(0)),
- Op.getOperand(1)));
- SDValue Extract = DAG.getNode(X86ISD::PEXTRW, dl, MVT::i32,
- Op.getOperand(0), Op.getOperand(1));
- SDValue Assert = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Extract,
- DAG.getValueType(VT));
- return DAG.getNode(ISD::TRUNCATE, dl, VT, Assert);
- }
-
if (VT == MVT::f32) {
// EXTRACTPS outputs to a GPR32 register which will require a movd to copy
// the result back to FR32 register. It's only worth matching if the
@@ -12432,6 +13550,7 @@ static SDValue LowerEXTRACT_VECTOR_ELT_SSE4(SDValue Op, SelectionDAG &DAG) {
if (isa<ConstantSDNode>(Op.getOperand(1)))
return Op;
}
+
return SDValue();
}
@@ -12460,7 +13579,8 @@ X86TargetLowering::ExtractBitFromMaskVector(SDValue Op, SelectionDAG &DAG) const
}
unsigned IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
- if (!Subtarget.hasDQI() && (VecVT.getVectorNumElements() <= 8)) {
+ if ((!Subtarget.hasDQI() && (VecVT.getVectorNumElements() == 8)) ||
+ (VecVT.getVectorNumElements() < 8)) {
// Use kshiftlw/rw instruction.
VecVT = MVT::v16i1;
Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, dl, VecVT,
@@ -12469,8 +13589,9 @@ X86TargetLowering::ExtractBitFromMaskVector(SDValue Op, SelectionDAG &DAG) const
DAG.getIntPtrConstant(0, dl));
}
unsigned MaxSift = VecVT.getVectorNumElements() - 1;
- Vec = DAG.getNode(X86ISD::VSHLI, dl, VecVT, Vec,
- DAG.getConstant(MaxSift - IdxVal, dl, MVT::i8));
+ if (MaxSift - IdxVal)
+ Vec = DAG.getNode(X86ISD::VSHLI, dl, VecVT, Vec,
+ DAG.getConstant(MaxSift - IdxVal, dl, MVT::i8));
Vec = DAG.getNode(X86ISD::VSRLI, dl, VecVT, Vec,
DAG.getConstant(MaxSift, dl, MVT::i8));
return DAG.getNode(X86ISD::VEXTRACT, dl, MVT::i1, Vec,
@@ -12491,10 +13612,10 @@ X86TargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
if (!isa<ConstantSDNode>(Idx)) {
if (VecVT.is512BitVector() ||
(VecVT.is256BitVector() && Subtarget.hasInt256() &&
- VecVT.getVectorElementType().getSizeInBits() == 32)) {
+ VecVT.getScalarSizeInBits() == 32)) {
MVT MaskEltVT =
- MVT::getIntegerVT(VecVT.getVectorElementType().getSizeInBits());
+ MVT::getIntegerVT(VecVT.getScalarSizeInBits());
MVT MaskVT = MVT::getVectorVT(MaskEltVT, VecVT.getSizeInBits() /
MaskEltVT.getSizeInBits());
@@ -12531,26 +13652,31 @@ X86TargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
assert(VecVT.is128BitVector() && "Unexpected vector length");
- if (Subtarget.hasSSE41())
- if (SDValue Res = LowerEXTRACT_VECTOR_ELT_SSE4(Op, DAG))
- return Res;
-
MVT VT = Op.getSimpleValueType();
- // TODO: handle v16i8.
+
if (VT.getSizeInBits() == 16) {
- if (IdxVal == 0)
+ // If IdxVal is 0, it's cheaper to do a move instead of a pextrw, unless
+ // we're going to zero extend the register or fold the store (SSE41 only).
+ if (IdxVal == 0 && !MayFoldIntoZeroExtend(Op) &&
+ !(Subtarget.hasSSE41() && MayFoldIntoStore(Op)))
return DAG.getNode(ISD::TRUNCATE, dl, MVT::i16,
DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32,
DAG.getBitcast(MVT::v4i32, Vec), Idx));
// Transform it so it match pextrw which produces a 32-bit result.
- MVT EltVT = MVT::i32;
- SDValue Extract = DAG.getNode(X86ISD::PEXTRW, dl, EltVT, Vec, Idx);
- SDValue Assert = DAG.getNode(ISD::AssertZext, dl, EltVT, Extract,
+ SDValue Extract = DAG.getNode(X86ISD::PEXTRW, dl, MVT::i32,
+ Op.getOperand(0), Op.getOperand(1));
+ SDValue Assert = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Extract,
DAG.getValueType(VT));
return DAG.getNode(ISD::TRUNCATE, dl, VT, Assert);
}
+ if (Subtarget.hasSSE41())
+ if (SDValue Res = LowerEXTRACT_VECTOR_ELT_SSE4(Op, DAG))
+ return Res;
+
+ // TODO: handle v16i8.
+
if (VT.getSizeInBits() == 32) {
if (IdxVal == 0)
return Op;
@@ -12604,12 +13730,46 @@ X86TargetLowering::InsertBitToMaskVector(SDValue Op, SelectionDAG &DAG) const {
unsigned IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
SDValue EltInVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VecVT, Elt);
- if (IdxVal)
+ unsigned NumElems = VecVT.getVectorNumElements();
+
+ if(Vec.isUndef()) {
+ if (IdxVal)
+ EltInVec = DAG.getNode(X86ISD::VSHLI, dl, VecVT, EltInVec,
+ DAG.getConstant(IdxVal, dl, MVT::i8));
+ return EltInVec;
+ }
+
+ // Insertion of one bit into first or last position
+ // can be done with two SHIFTs + OR.
+ if (IdxVal == 0 ) {
+ // EltInVec already at correct index and other bits are 0.
+ // Clean the first bit in source vector.
+ Vec = DAG.getNode(X86ISD::VSRLI, dl, VecVT, Vec,
+ DAG.getConstant(1 , dl, MVT::i8));
+ Vec = DAG.getNode(X86ISD::VSHLI, dl, VecVT, Vec,
+ DAG.getConstant(1, dl, MVT::i8));
+
+ return DAG.getNode(ISD::OR, dl, VecVT, Vec, EltInVec);
+ }
+ if (IdxVal == NumElems -1) {
+ // Move the bit to the last position inside the vector.
EltInVec = DAG.getNode(X86ISD::VSHLI, dl, VecVT, EltInVec,
DAG.getConstant(IdxVal, dl, MVT::i8));
- if (Vec.isUndef())
- return EltInVec;
- return DAG.getNode(ISD::OR, dl, VecVT, Vec, EltInVec);
+ // Clean the last bit in the source vector.
+ Vec = DAG.getNode(X86ISD::VSHLI, dl, VecVT, Vec,
+ DAG.getConstant(1, dl, MVT::i8));
+ Vec = DAG.getNode(X86ISD::VSRLI, dl, VecVT, Vec,
+ DAG.getConstant(1 , dl, MVT::i8));
+
+ return DAG.getNode(ISD::OR, dl, VecVT, Vec, EltInVec);
+ }
+
+ // Use shuffle to insert element.
+ SmallVector<int, 64> MaskVec(NumElems);
+ for (unsigned i = 0; i != NumElems; ++i)
+ MaskVec[i] = (i == IdxVal) ? NumElems : i;
+
+ return DAG.getVectorShuffle(VecVT, dl, Vec, EltInVec, MaskVec);
}
SDValue X86TargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op,
@@ -12764,10 +13924,6 @@ static SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) {
return insert128BitVector(DAG.getUNDEF(OpVT), Op, 0, DAG, dl);
}
- if (OpVT == MVT::v1i64 &&
- Op.getOperand(0).getValueType() == MVT::i64)
- return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v1i64, Op.getOperand(0));
-
SDValue AnyExt = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i32, Op.getOperand(0));
assert(OpVT.is128BitVector() && "Expected an SSE type!");
return DAG.getBitcast(
@@ -12779,25 +13935,32 @@ static SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) {
// upper bits of a vector.
static SDValue LowerEXTRACT_SUBVECTOR(SDValue Op, const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
+ assert(Subtarget.hasAVX() && "EXTRACT_SUBVECTOR requires AVX");
+
SDLoc dl(Op);
SDValue In = Op.getOperand(0);
SDValue Idx = Op.getOperand(1);
unsigned IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
- MVT ResVT = Op.getSimpleValueType();
- MVT InVT = In.getSimpleValueType();
+ MVT ResVT = Op.getSimpleValueType();
- if (Subtarget.hasFp256()) {
- if (ResVT.is128BitVector() &&
- (InVT.is256BitVector() || InVT.is512BitVector()) &&
- isa<ConstantSDNode>(Idx)) {
- return extract128BitVector(In, IdxVal, DAG, dl);
- }
- if (ResVT.is256BitVector() && InVT.is512BitVector() &&
- isa<ConstantSDNode>(Idx)) {
- return extract256BitVector(In, IdxVal, DAG, dl);
- }
- }
- return SDValue();
+ assert((In.getSimpleValueType().is256BitVector() ||
+ In.getSimpleValueType().is512BitVector()) &&
+ "Can only extract from 256-bit or 512-bit vectors");
+
+ if (ResVT.is128BitVector())
+ return extract128BitVector(In, IdxVal, DAG, dl);
+ if (ResVT.is256BitVector())
+ return extract256BitVector(In, IdxVal, DAG, dl);
+
+ llvm_unreachable("Unimplemented!");
+}
+
+static bool areOnlyUsersOf(SDNode *N, ArrayRef<SDValue> ValidUsers) {
+ for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I)
+ if (llvm::all_of(ValidUsers,
+ [&I](SDValue V) { return V.getNode() != *I; }))
+ return false;
+ return true;
}
// Lower a node with an INSERT_SUBVECTOR opcode. This may result in a
@@ -12805,58 +13968,97 @@ static SDValue LowerEXTRACT_SUBVECTOR(SDValue Op, const X86Subtarget &Subtarget,
// the upper bits of a vector.
static SDValue LowerINSERT_SUBVECTOR(SDValue Op, const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
- if (!Subtarget.hasAVX())
- return SDValue();
+ assert(Subtarget.hasAVX() && "INSERT_SUBVECTOR requires AVX");
SDLoc dl(Op);
SDValue Vec = Op.getOperand(0);
SDValue SubVec = Op.getOperand(1);
SDValue Idx = Op.getOperand(2);
- if (!isa<ConstantSDNode>(Idx))
- return SDValue();
-
unsigned IdxVal = cast<ConstantSDNode>(Idx)->getZExtValue();
MVT OpVT = Op.getSimpleValueType();
MVT SubVecVT = SubVec.getSimpleValueType();
- // Fold two 16-byte subvector loads into one 32-byte load:
- // (insert_subvector (insert_subvector undef, (load addr), 0),
- // (load addr + 16), Elts/2)
+ if (OpVT.getVectorElementType() == MVT::i1)
+ return insert1BitVector(Op, DAG, Subtarget);
+
+ assert((OpVT.is256BitVector() || OpVT.is512BitVector()) &&
+ "Can only insert into 256-bit or 512-bit vectors");
+
+ // Fold two 16-byte or 32-byte subvector loads into one 32-byte or 64-byte
+ // load:
+ // (insert_subvector (insert_subvector undef, (load16 addr), 0),
+ // (load16 addr + 16), Elts/2)
// --> load32 addr
+ // or:
+ // (insert_subvector (insert_subvector undef, (load32 addr), 0),
+ // (load32 addr + 32), Elts/2)
+ // --> load64 addr
+ // or a 16-byte or 32-byte broadcast:
+ // (insert_subvector (insert_subvector undef, (load16 addr), 0),
+ // (load16 addr), Elts/2)
+ // --> X86SubVBroadcast(load16 addr)
+ // or:
+ // (insert_subvector (insert_subvector undef, (load32 addr), 0),
+ // (load32 addr), Elts/2)
+ // --> X86SubVBroadcast(load32 addr)
if ((IdxVal == OpVT.getVectorNumElements() / 2) &&
Vec.getOpcode() == ISD::INSERT_SUBVECTOR &&
- OpVT.is256BitVector() && SubVecVT.is128BitVector()) {
+ OpVT.getSizeInBits() == SubVecVT.getSizeInBits() * 2) {
auto *Idx2 = dyn_cast<ConstantSDNode>(Vec.getOperand(2));
if (Idx2 && Idx2->getZExtValue() == 0) {
+ SDValue SubVec2 = Vec.getOperand(1);
// If needed, look through bitcasts to get to the load.
- SDValue SubVec2 = peekThroughBitcasts(Vec.getOperand(1));
- if (auto *FirstLd = dyn_cast<LoadSDNode>(SubVec2)) {
+ if (auto *FirstLd = dyn_cast<LoadSDNode>(peekThroughBitcasts(SubVec2))) {
bool Fast;
unsigned Alignment = FirstLd->getAlignment();
unsigned AS = FirstLd->getAddressSpace();
const X86TargetLowering *TLI = Subtarget.getTargetLowering();
if (TLI->allowsMemoryAccess(*DAG.getContext(), DAG.getDataLayout(),
OpVT, AS, Alignment, &Fast) && Fast) {
- SDValue Ops[] = { SubVec2, SubVec };
+ SDValue Ops[] = {SubVec2, SubVec};
if (SDValue Ld = EltsFromConsecutiveLoads(OpVT, Ops, dl, DAG, false))
return Ld;
}
}
+ // If lower/upper loads are the same and the only users of the load, then
+ // lower to a VBROADCASTF128/VBROADCASTI128/etc.
+ if (auto *Ld = dyn_cast<LoadSDNode>(peekThroughOneUseBitcasts(SubVec2))) {
+ if (SubVec2 == SubVec && ISD::isNormalLoad(Ld) &&
+ areOnlyUsersOf(SubVec2.getNode(), {Op, Vec})) {
+ return DAG.getNode(X86ISD::SUBV_BROADCAST, dl, OpVT, SubVec);
+ }
+ }
+ // If this is subv_broadcast insert into both halves, use a larger
+ // subv_broadcast.
+ if (SubVec.getOpcode() == X86ISD::SUBV_BROADCAST && SubVec == SubVec2) {
+ return DAG.getNode(X86ISD::SUBV_BROADCAST, dl, OpVT,
+ SubVec.getOperand(0));
+ }
}
}
- if ((OpVT.is256BitVector() || OpVT.is512BitVector()) &&
- SubVecVT.is128BitVector())
+ if (SubVecVT.is128BitVector())
return insert128BitVector(Vec, SubVec, IdxVal, DAG, dl);
- if (OpVT.is512BitVector() && SubVecVT.is256BitVector())
+ if (SubVecVT.is256BitVector())
return insert256BitVector(Vec, SubVec, IdxVal, DAG, dl);
- if (OpVT.getVectorElementType() == MVT::i1)
- return insert1BitVector(Op, DAG, Subtarget);
+ llvm_unreachable("Unimplemented!");
+}
- return SDValue();
+// Returns the appropriate wrapper opcode for a global reference.
+unsigned X86TargetLowering::getGlobalWrapperKind(const GlobalValue *GV) const {
+ // References to absolute symbols are never PC-relative.
+ if (GV && GV->isAbsoluteSymbolRef())
+ return X86ISD::Wrapper;
+
+ CodeModel::Model M = getTargetMachine().getCodeModel();
+ if (Subtarget.isPICStyleRIPRel() &&
+ (M == CodeModel::Small || M == CodeModel::Kernel))
+ return X86ISD::WrapperRIP;
+
+ return X86ISD::Wrapper;
}
// ConstantPool, JumpTable, GlobalAddress, and ExternalSymbol are lowered as
@@ -12872,18 +14074,12 @@ X86TargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const {
// In PIC mode (unless we're in RIPRel PIC mode) we add an offset to the
// global base reg.
unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr);
- unsigned WrapperKind = X86ISD::Wrapper;
- CodeModel::Model M = DAG.getTarget().getCodeModel();
-
- if (Subtarget.isPICStyleRIPRel() &&
- (M == CodeModel::Small || M == CodeModel::Kernel))
- WrapperKind = X86ISD::WrapperRIP;
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue Result = DAG.getTargetConstantPool(
CP->getConstVal(), PtrVT, CP->getAlignment(), CP->getOffset(), OpFlag);
SDLoc DL(CP);
- Result = DAG.getNode(WrapperKind, DL, PtrVT, Result);
+ Result = DAG.getNode(getGlobalWrapperKind(), DL, PtrVT, Result);
// With PIC, the address is actually $g + Offset.
if (OpFlag) {
Result =
@@ -12900,17 +14096,11 @@ SDValue X86TargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
// In PIC mode (unless we're in RIPRel PIC mode) we add an offset to the
// global base reg.
unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr);
- unsigned WrapperKind = X86ISD::Wrapper;
- CodeModel::Model M = DAG.getTarget().getCodeModel();
-
- if (Subtarget.isPICStyleRIPRel() &&
- (M == CodeModel::Small || M == CodeModel::Kernel))
- WrapperKind = X86ISD::WrapperRIP;
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue Result = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OpFlag);
SDLoc DL(JT);
- Result = DAG.getNode(WrapperKind, DL, PtrVT, Result);
+ Result = DAG.getNode(getGlobalWrapperKind(), DL, PtrVT, Result);
// With PIC, the address is actually $g + Offset.
if (OpFlag)
@@ -12929,18 +14119,12 @@ X86TargetLowering::LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const {
// global base reg.
const Module *Mod = DAG.getMachineFunction().getFunction()->getParent();
unsigned char OpFlag = Subtarget.classifyGlobalReference(nullptr, *Mod);
- unsigned WrapperKind = X86ISD::Wrapper;
- CodeModel::Model M = DAG.getTarget().getCodeModel();
-
- if (Subtarget.isPICStyleRIPRel() &&
- (M == CodeModel::Small || M == CodeModel::Kernel))
- WrapperKind = X86ISD::WrapperRIP;
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue Result = DAG.getTargetExternalSymbol(Sym, PtrVT, OpFlag);
SDLoc DL(Op);
- Result = DAG.getNode(WrapperKind, DL, PtrVT, Result);
+ Result = DAG.getNode(getGlobalWrapperKind(), DL, PtrVT, Result);
// With PIC, the address is actually $g + Offset.
if (isPositionIndependent() && !Subtarget.is64Bit()) {
@@ -12963,18 +14147,12 @@ X86TargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const {
// Create the TargetBlockAddressAddress node.
unsigned char OpFlags =
Subtarget.classifyBlockAddressReference();
- CodeModel::Model M = DAG.getTarget().getCodeModel();
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
int64_t Offset = cast<BlockAddressSDNode>(Op)->getOffset();
SDLoc dl(Op);
auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue Result = DAG.getTargetBlockAddress(BA, PtrVT, Offset, OpFlags);
-
- if (Subtarget.isPICStyleRIPRel() &&
- (M == CodeModel::Small || M == CodeModel::Kernel))
- Result = DAG.getNode(X86ISD::WrapperRIP, dl, PtrVT, Result);
- else
- Result = DAG.getNode(X86ISD::Wrapper, dl, PtrVT, Result);
+ Result = DAG.getNode(getGlobalWrapperKind(), dl, PtrVT, Result);
// With PIC, the address is actually $g + Offset.
if (isGlobalRelativeToPICBase(OpFlags)) {
@@ -13003,11 +14181,7 @@ SDValue X86TargetLowering::LowerGlobalAddress(const GlobalValue *GV,
Result = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, OpFlags);
}
- if (Subtarget.isPICStyleRIPRel() &&
- (M == CodeModel::Small || M == CodeModel::Kernel))
- Result = DAG.getNode(X86ISD::WrapperRIP, dl, PtrVT, Result);
- else
- Result = DAG.getNode(X86ISD::Wrapper, dl, PtrVT, Result);
+ Result = DAG.getNode(getGlobalWrapperKind(GV), dl, PtrVT, Result);
// With PIC, the address is actually $g + Offset.
if (isGlobalRelativeToPICBase(OpFlags)) {
@@ -13041,7 +14215,7 @@ static SDValue
GetTLSADDR(SelectionDAG &DAG, SDValue Chain, GlobalAddressSDNode *GA,
SDValue *InFlag, const EVT PtrVT, unsigned ReturnReg,
unsigned char OperandFlags, bool LocalDynamic = false) {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SDLoc dl(GA);
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl,
@@ -13061,8 +14235,8 @@ GetTLSADDR(SelectionDAG &DAG, SDValue Chain, GlobalAddressSDNode *GA,
}
// TLSADDR will be codegen'ed as call. Inform MFI that function has calls.
- MFI->setAdjustsStack(true);
- MFI->setHasCalls(true);
+ MFI.setAdjustsStack(true);
+ MFI.setHasCalls(true);
SDValue Flag = Chain.getValue(1);
return DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Flag);
@@ -13097,7 +14271,7 @@ static SDValue LowerToTLSLocalDynamicModel(GlobalAddressSDNode *GA,
SDLoc dl(GA);
// Get the start address of the TLS block for this module.
- X86MachineFunctionInfo* MFI = DAG.getMachineFunction()
+ X86MachineFunctionInfo *MFI = DAG.getMachineFunction()
.getInfo<X86MachineFunctionInfo>();
MFI->incNumLocalDynamicTLSAccesses();
@@ -13251,8 +14425,8 @@ X86TargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const {
Chain.getValue(1), DL);
// TLSCALL will be codegen'ed as call. Inform MFI that function has calls.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setAdjustsStack(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setAdjustsStack(true);
// And our return value (tls address) is in the standard call return value
// location.
@@ -13395,9 +14569,9 @@ SDValue X86TargetLowering::LowerSINT_TO_FP(SDValue Op,
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
if (SrcVT.isVector()) {
if (SrcVT == MVT::v2i32 && VT == MVT::v2f64) {
- return DAG.getNode(X86ISD::CVTDQ2PD, dl, VT,
+ return DAG.getNode(X86ISD::CVTSI2P, dl, VT,
DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v4i32, Src,
- DAG.getUNDEF(SrcVT)));
+ DAG.getUNDEF(SrcVT)));
}
if (SrcVT.getVectorElementType() == MVT::i1) {
if (SrcVT == MVT::v2i1 && TLI.isTypeLegal(SrcVT))
@@ -13433,7 +14607,7 @@ SDValue X86TargetLowering::LowerSINT_TO_FP(SDValue Op,
unsigned Size = SrcVT.getSizeInBits()/8;
MachineFunction &MF = DAG.getMachineFunction();
auto PtrVT = getPointerTy(MF.getDataLayout());
- int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size, false);
+ int SSFI = MF.getFrameInfo().CreateStackObject(Size, Size, false);
SDValue StackSlot = DAG.getFrameIndex(SSFI, PtrVT);
SDValue Chain = DAG.getStore(
DAG.getEntryNode(), dl, ValueToStore, StackSlot,
@@ -13479,8 +14653,8 @@ SDValue X86TargetLowering::BuildFILD(SDValue Op, EVT SrcVT, SDValue Chain,
// shouldn't be necessary except that RFP cannot be live across
// multiple blocks. When stackifier is fixed, they can be uncoupled.
MachineFunction &MF = DAG.getMachineFunction();
- unsigned SSFISize = Op.getValueType().getSizeInBits()/8;
- int SSFI = MF.getFrameInfo()->CreateStackObject(SSFISize, SSFISize, false);
+ unsigned SSFISize = Op.getValueSizeInBits()/8;
+ int SSFI = MF.getFrameInfo().CreateStackObject(SSFISize, SSFISize, false);
auto PtrVT = getPointerTy(MF.getDataLayout());
SDValue StackSlot = DAG.getFrameIndex(SSFI, PtrVT);
Tys = DAG.getVTList(MVT::Other);
@@ -13528,10 +14702,10 @@ SDValue X86TargetLowering::LowerUINT_TO_FP_i64(SDValue Op,
SmallVector<Constant*,2> CV1;
CV1.push_back(
- ConstantFP::get(*Context, APFloat(APFloat::IEEEdouble,
+ ConstantFP::get(*Context, APFloat(APFloat::IEEEdouble(),
APInt(64, 0x4330000000000000ULL))));
CV1.push_back(
- ConstantFP::get(*Context, APFloat(APFloat::IEEEdouble,
+ ConstantFP::get(*Context, APFloat(APFloat::IEEEdouble(),
APInt(64, 0x4530000000000000ULL))));
Constant *C1 = ConstantVector::get(CV1);
SDValue CPIdx1 = DAG.getConstantPool(C1, PtrVT, 16);
@@ -13560,8 +14734,7 @@ SDValue X86TargetLowering::LowerUINT_TO_FP_i64(SDValue Op,
Result = DAG.getNode(X86ISD::FHADD, dl, MVT::v2f64, Sub, Sub);
} else {
SDValue S2F = DAG.getBitcast(MVT::v4i32, Sub);
- SDValue Shuffle = getTargetShuffleNode(X86ISD::PSHUFD, dl, MVT::v4i32,
- S2F, 0x4E, DAG);
+ SDValue Shuffle = DAG.getVectorShuffle(MVT::v4i32, dl, S2F, S2F, {2,3,0,1});
Result = DAG.getNode(ISD::FADD, dl, MVT::v2f64,
DAG.getBitcast(MVT::v2f64, Shuffle), Sub);
}
@@ -13617,6 +14790,41 @@ SDValue X86TargetLowering::LowerUINT_TO_FP_i32(SDValue Op,
return Sub;
}
+static SDValue lowerUINT_TO_FP_v2i32(SDValue Op, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget, SDLoc &DL) {
+ if (Op.getSimpleValueType() != MVT::v2f64)
+ return SDValue();
+
+ SDValue N0 = Op.getOperand(0);
+ assert(N0.getSimpleValueType() == MVT::v2i32 && "Unexpected input type");
+
+ // Legalize to v4i32 type.
+ N0 = DAG.getNode(ISD::CONCAT_VECTORS, DL, MVT::v4i32, N0,
+ DAG.getUNDEF(MVT::v2i32));
+
+ if (Subtarget.hasAVX512())
+ return DAG.getNode(X86ISD::CVTUI2P, DL, MVT::v2f64, N0);
+
+ // Same implementation as VectorLegalizer::ExpandUINT_TO_FLOAT,
+ // but using v2i32 to v2f64 with X86ISD::CVTSI2P.
+ SDValue HalfWord = DAG.getConstant(16, DL, MVT::v4i32);
+ SDValue HalfWordMask = DAG.getConstant(0x0000FFFF, DL, MVT::v4i32);
+
+ // Two to the power of half-word-size.
+ SDValue TWOHW = DAG.getConstantFP(1 << 16, DL, MVT::v2f64);
+
+ // Clear upper part of LO, lower HI.
+ SDValue HI = DAG.getNode(ISD::SRL, DL, MVT::v4i32, N0, HalfWord);
+ SDValue LO = DAG.getNode(ISD::AND, DL, MVT::v4i32, N0, HalfWordMask);
+
+ SDValue fHI = DAG.getNode(X86ISD::CVTSI2P, DL, MVT::v2f64, HI);
+ fHI = DAG.getNode(ISD::FMUL, DL, MVT::v2f64, fHI, TWOHW);
+ SDValue fLO = DAG.getNode(X86ISD::CVTSI2P, DL, MVT::v2f64, LO);
+
+ // Add the two halves.
+ return DAG.getNode(ISD::FADD, DL, MVT::v2f64, fHI, fLO);
+}
+
static SDValue lowerUINT_TO_FP_vXi32(SDValue Op, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
// The algorithm is the following:
@@ -13699,7 +14907,7 @@ static SDValue lowerUINT_TO_FP_vXi32(SDValue Op, SelectionDAG &DAG,
// Create the vector constant for -(0x1.0p39f + 0x1.0p23f).
SDValue VecCstFAdd = DAG.getConstantFP(
- APFloat(APFloat::IEEEsingle, APInt(32, 0xD3000080)), DL, VecFloatVT);
+ APFloat(APFloat::IEEEsingle(), APInt(32, 0xD3000080)), DL, VecFloatVT);
// float4 fhi = (float4) hi - (0x1.0p39f + 0x1.0p23f);
SDValue HighBitcast = DAG.getBitcast(VecFloatVT, High);
@@ -13714,29 +14922,31 @@ static SDValue lowerUINT_TO_FP_vXi32(SDValue Op, SelectionDAG &DAG,
SDValue X86TargetLowering::lowerUINT_TO_FP_vec(SDValue Op,
SelectionDAG &DAG) const {
SDValue N0 = Op.getOperand(0);
- MVT SVT = N0.getSimpleValueType();
+ MVT SrcVT = N0.getSimpleValueType();
SDLoc dl(Op);
- if (SVT.getVectorElementType() == MVT::i1) {
- if (SVT == MVT::v2i1)
+ if (SrcVT.getVectorElementType() == MVT::i1) {
+ if (SrcVT == MVT::v2i1)
return DAG.getNode(ISD::UINT_TO_FP, dl, Op.getValueType(),
DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v2i64, N0));
- MVT IntegerVT = MVT::getVectorVT(MVT::i32, SVT.getVectorNumElements());
+ MVT IntegerVT = MVT::getVectorVT(MVT::i32, SrcVT.getVectorNumElements());
return DAG.getNode(ISD::UINT_TO_FP, dl, Op.getValueType(),
DAG.getNode(ISD::ZERO_EXTEND, dl, IntegerVT, N0));
}
- switch (SVT.SimpleTy) {
+ switch (SrcVT.SimpleTy) {
default:
llvm_unreachable("Custom UINT_TO_FP is not supported!");
case MVT::v4i8:
case MVT::v4i16:
case MVT::v8i8:
case MVT::v8i16: {
- MVT NVT = MVT::getVectorVT(MVT::i32, SVT.getVectorNumElements());
+ MVT NVT = MVT::getVectorVT(MVT::i32, SrcVT.getVectorNumElements());
return DAG.getNode(ISD::SINT_TO_FP, dl, Op.getValueType(),
DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, N0));
}
+ case MVT::v2i32:
+ return lowerUINT_TO_FP_v2i32(Op, DAG, Subtarget, dl);
case MVT::v4i32:
case MVT::v8i32:
return lowerUINT_TO_FP_vXi32(Op, DAG, Subtarget);
@@ -13754,15 +14964,15 @@ SDValue X86TargetLowering::LowerUINT_TO_FP(SDValue Op,
SDLoc dl(Op);
auto PtrVT = getPointerTy(DAG.getDataLayout());
- if (Op.getSimpleValueType().isVector())
- return lowerUINT_TO_FP_vec(Op, DAG);
-
// Since UINT_TO_FP is legal (it's marked custom), dag combiner won't
// optimize it to a SINT_TO_FP when the sign bit is known zero. Perform
// the optimization here.
if (DAG.SignBitIsZero(N0))
return DAG.getNode(ISD::SINT_TO_FP, dl, Op.getValueType(), N0);
+ if (Op.getSimpleValueType().isVector())
+ return lowerUINT_TO_FP_vec(Op, DAG);
+
MVT SrcVT = N0.getSimpleValueType();
MVT DstVT = Op.getSimpleValueType();
@@ -13903,7 +15113,7 @@ X86TargetLowering::FP_TO_INTHelper(SDValue Op, SelectionDAG &DAG,
// stack slot.
MachineFunction &MF = DAG.getMachineFunction();
unsigned MemSize = DstTy.getSizeInBits()/8;
- int SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize, false);
+ int SSFI = MF.getFrameInfo().CreateStackObject(MemSize, MemSize, false);
SDValue StackSlot = DAG.getFrameIndex(SSFI, PtrVT);
unsigned Opc;
@@ -13935,15 +15145,15 @@ X86TargetLowering::FP_TO_INTHelper(SDValue Op, SelectionDAG &DAG,
// For X87 we'd like to use the smallest FP type for this constant, but
// for DAG type consistency we have to match the FP operand type.
- APFloat Thresh(APFloat::IEEEsingle, APInt(32, 0x5f000000));
+ APFloat Thresh(APFloat::IEEEsingle(), APInt(32, 0x5f000000));
LLVM_ATTRIBUTE_UNUSED APFloat::opStatus Status = APFloat::opOK;
bool LosesInfo = false;
if (TheVT == MVT::f64)
// The rounding mode is irrelevant as the conversion should be exact.
- Status = Thresh.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven,
+ Status = Thresh.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
&LosesInfo);
else if (TheVT == MVT::f80)
- Status = Thresh.convert(APFloat::x87DoubleExtended,
+ Status = Thresh.convert(APFloat::x87DoubleExtended(),
APFloat::rmNearestTiesToEven, &LosesInfo);
assert(Status == APFloat::opOK && !LosesInfo &&
@@ -13981,7 +15191,7 @@ X86TargetLowering::FP_TO_INTHelper(SDValue Op, SelectionDAG &DAG,
MachineMemOperand::MOLoad, MemSize, MemSize);
Value = DAG.getMemIntrinsicNode(X86ISD::FLD, DL, Tys, Ops, DstTy, MMO);
Chain = Value.getValue(1);
- SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize, false);
+ SSFI = MF.getFrameInfo().CreateStackObject(MemSize, MemSize, false);
StackSlot = DAG.getFrameIndex(SSFI, PtrVT);
}
@@ -14084,14 +15294,14 @@ static SDValue LowerZERO_EXTEND_AVX512(SDValue Op,
SDValue In = Op->getOperand(0);
MVT InVT = In.getSimpleValueType();
SDLoc DL(Op);
- unsigned int NumElts = VT.getVectorNumElements();
- if (NumElts != 8 && NumElts != 16 && !Subtarget.hasBWI())
- return SDValue();
+ unsigned NumElts = VT.getVectorNumElements();
- if (VT.is512BitVector() && InVT.getVectorElementType() != MVT::i1)
+ if (VT.is512BitVector() && InVT.getVectorElementType() != MVT::i1 &&
+ (NumElts == 8 || NumElts == 16 || Subtarget.hasBWI()))
return DAG.getNode(X86ISD::VZEXT, DL, VT, In);
- assert(InVT.getVectorElementType() == MVT::i1);
+ if (InVT.getVectorElementType() != MVT::i1)
+ return SDValue();
// Extend VT if the target is 256 or 128bit vector and VLX is not supported.
MVT ExtVT = VT;
@@ -14137,6 +15347,85 @@ static SDValue LowerZERO_EXTEND(SDValue Op, const X86Subtarget &Subtarget,
return SDValue();
}
+/// Helper to recursively truncate vector elements in half with PACKSS.
+/// It makes use of the fact that vector comparison results will be all-zeros
+/// or all-ones to use (vXi8 PACKSS(vYi16, vYi16)) instead of matching types.
+/// AVX2 (Int256) sub-targets require extra shuffling as the PACKSS operates
+/// within each 128-bit lane.
+static SDValue truncateVectorCompareWithPACKSS(EVT DstVT, SDValue In,
+ const SDLoc &DL,
+ SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ // Requires SSE2 but AVX512 has fast truncate.
+ if (!Subtarget.hasSSE2() || Subtarget.hasAVX512())
+ return SDValue();
+
+ EVT SrcVT = In.getValueType();
+
+ // No truncation required, we might get here due to recursive calls.
+ if (SrcVT == DstVT)
+ return In;
+
+ // We only support vector truncation to 128bits or greater from a
+ // 256bits or greater source.
+ if ((DstVT.getSizeInBits() % 128) != 0)
+ return SDValue();
+ if ((SrcVT.getSizeInBits() % 256) != 0)
+ return SDValue();
+
+ unsigned NumElems = SrcVT.getVectorNumElements();
+ assert(DstVT.getVectorNumElements() == NumElems && "Illegal truncation");
+ assert(SrcVT.getSizeInBits() > DstVT.getSizeInBits() && "Illegal truncation");
+
+ EVT PackedSVT =
+ EVT::getIntegerVT(*DAG.getContext(), SrcVT.getScalarSizeInBits() / 2);
+
+ // Extract lower/upper subvectors.
+ unsigned NumSubElts = NumElems / 2;
+ unsigned SrcSizeInBits = SrcVT.getSizeInBits();
+ SDValue Lo = extractSubVector(In, 0 * NumSubElts, DAG, DL, SrcSizeInBits / 2);
+ SDValue Hi = extractSubVector(In, 1 * NumSubElts, DAG, DL, SrcSizeInBits / 2);
+
+ // 256bit -> 128bit truncate - PACKSS lower/upper 128-bit subvectors.
+ if (SrcVT.is256BitVector()) {
+ Lo = DAG.getBitcast(MVT::v8i16, Lo);
+ Hi = DAG.getBitcast(MVT::v8i16, Hi);
+ SDValue Res = DAG.getNode(X86ISD::PACKSS, DL, MVT::v16i8, Lo, Hi);
+ return DAG.getBitcast(DstVT, Res);
+ }
+
+ // AVX2: 512bit -> 256bit truncate - PACKSS lower/upper 256-bit subvectors.
+ // AVX2: 512bit -> 128bit truncate - PACKSS(PACKSS, PACKSS).
+ if (SrcVT.is512BitVector() && Subtarget.hasInt256()) {
+ Lo = DAG.getBitcast(MVT::v16i16, Lo);
+ Hi = DAG.getBitcast(MVT::v16i16, Hi);
+ SDValue Res = DAG.getNode(X86ISD::PACKSS, DL, MVT::v32i8, Lo, Hi);
+
+ // 256-bit PACKSS(ARG0, ARG1) leaves us with ((LO0,LO1),(HI0,HI1)),
+ // so we need to shuffle to get ((LO0,HI0),(LO1,HI1)).
+ Res = DAG.getBitcast(MVT::v4i64, Res);
+ Res = DAG.getVectorShuffle(MVT::v4i64, DL, Res, Res, {0, 2, 1, 3});
+
+ if (DstVT.is256BitVector())
+ return DAG.getBitcast(DstVT, Res);
+
+ // If 512bit -> 128bit truncate another stage.
+ EVT PackedVT = EVT::getVectorVT(*DAG.getContext(), PackedSVT, NumElems);
+ Res = DAG.getBitcast(PackedVT, Res);
+ return truncateVectorCompareWithPACKSS(DstVT, Res, DL, DAG, Subtarget);
+ }
+
+ // Recursively pack lower/upper subvectors, concat result and pack again.
+ assert(SrcVT.getSizeInBits() >= 512 && "Expected 512-bit vector or greater");
+ EVT PackedVT = EVT::getVectorVT(*DAG.getContext(), PackedSVT, NumElems / 2);
+ Lo = truncateVectorCompareWithPACKSS(PackedVT, Lo, DL, DAG, Subtarget);
+ Hi = truncateVectorCompareWithPACKSS(PackedVT, Hi, DL, DAG, Subtarget);
+
+ PackedVT = EVT::getVectorVT(*DAG.getContext(), PackedSVT, NumElems);
+ SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, PackedVT, Lo, Hi);
+ return truncateVectorCompareWithPACKSS(DstVT, Res, DL, DAG, Subtarget);
+}
+
static SDValue LowerTruncateVecI1(SDValue Op, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
@@ -14203,6 +15492,22 @@ SDValue X86TargetLowering::LowerTRUNCATE(SDValue Op, SelectionDAG &DAG) const {
DAG.getNode(X86ISD::VSEXT, DL, MVT::v16i32, In));
return DAG.getNode(X86ISD::VTRUNC, DL, VT, In);
}
+
+ // Truncate with PACKSS if we are truncating a vector comparison result.
+ // TODO: We should be able to support other operations as long as we
+ // we are saturating+packing zero/all bits only.
+ auto IsPackableComparison = [](SDValue V) {
+ unsigned Opcode = V.getOpcode();
+ return (Opcode == X86ISD::PCMPGT || Opcode == X86ISD::PCMPEQ ||
+ Opcode == X86ISD::CMPP);
+ };
+
+ if (IsPackableComparison(In) || (In.getOpcode() == ISD::CONCAT_VECTORS &&
+ all_of(In->ops(), IsPackableComparison))) {
+ if (SDValue V = truncateVectorCompareWithPACKSS(VT, In, DL, DAG, Subtarget))
+ return V;
+ }
+
if ((VT == MVT::v4i32) && (InVT == MVT::v4i64)) {
// On AVX2, v4i64 -> v4i32 becomes VPERMD.
if (Subtarget.hasInt256()) {
@@ -14299,30 +15604,31 @@ SDValue X86TargetLowering::LowerTRUNCATE(SDValue Op, SelectionDAG &DAG) const {
DAG.getIntPtrConstant(0, DL));
}
-SDValue X86TargetLowering::LowerFP_TO_SINT(SDValue Op,
- SelectionDAG &DAG) const {
- assert(!Op.getSimpleValueType().isVector());
+SDValue X86TargetLowering::LowerFP_TO_INT(SDValue Op,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) const {
+ bool IsSigned = Op.getOpcode() == ISD::FP_TO_SINT;
- std::pair<SDValue,SDValue> Vals = FP_TO_INTHelper(Op, DAG,
- /*IsSigned=*/ true, /*IsReplace=*/ false);
- SDValue FIST = Vals.first, StackSlot = Vals.second;
- // If FP_TO_INTHelper failed, the node is actually supposed to be Legal.
- if (!FIST.getNode())
- return Op;
+ MVT VT = Op.getSimpleValueType();
- if (StackSlot.getNode())
- // Load the result.
- return DAG.getLoad(Op.getValueType(), SDLoc(Op), FIST, StackSlot,
- MachinePointerInfo());
+ if (VT.isVector()) {
+ assert(Subtarget.hasDQI() && Subtarget.hasVLX() && "Requires AVX512DQVL!");
+ SDValue Src = Op.getOperand(0);
+ SDLoc dl(Op);
+ if (VT == MVT::v2i64 && Src.getSimpleValueType() == MVT::v2f32) {
+ return DAG.getNode(IsSigned ? X86ISD::CVTTP2SI : X86ISD::CVTTP2UI,
+ dl, VT,
+ DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v4f32, Src,
+ DAG.getUNDEF(MVT::v2f32)));
+ }
- // The node is the result.
- return FIST;
-}
+ return SDValue();
+ }
+
+ assert(!VT.isVector());
-SDValue X86TargetLowering::LowerFP_TO_UINT(SDValue Op,
- SelectionDAG &DAG) const {
std::pair<SDValue,SDValue> Vals = FP_TO_INTHelper(Op, DAG,
- /*IsSigned=*/ false, /*IsReplace=*/ false);
+ IsSigned, /*IsReplace=*/ false);
SDValue FIST = Vals.first, StackSlot = Vals.second;
// If FP_TO_INTHelper failed, the node is actually supposed to be Legal.
if (!FIST.getNode())
@@ -14330,8 +15636,7 @@ SDValue X86TargetLowering::LowerFP_TO_UINT(SDValue Op,
if (StackSlot.getNode())
// Load the result.
- return DAG.getLoad(Op.getValueType(), SDLoc(Op), FIST, StackSlot,
- MachinePointerInfo());
+ return DAG.getLoad(VT, SDLoc(Op), FIST, StackSlot, MachinePointerInfo());
// The node is the result.
return FIST;
@@ -14376,17 +15681,14 @@ static SDValue LowerFABSorFNEG(SDValue Op, SelectionDAG &DAG) {
MVT LogicVT;
MVT EltVT;
- unsigned NumElts;
if (VT.isVector()) {
LogicVT = VT;
EltVT = VT.getVectorElementType();
- NumElts = VT.getVectorNumElements();
} else if (IsF128) {
// SSE instructions are used for optimized f128 logical operations.
LogicVT = MVT::f128;
EltVT = VT;
- NumElts = 1;
} else {
// There are no scalar bitwise logical SSE/AVX instructions, so we
// generate a 16-byte vector constant and logic op even for the scalar case.
@@ -14394,22 +15696,16 @@ static SDValue LowerFABSorFNEG(SDValue Op, SelectionDAG &DAG) {
// the logic op, so it can save (~4 bytes) on code size.
LogicVT = (VT == MVT::f64) ? MVT::v2f64 : MVT::v4f32;
EltVT = VT;
- NumElts = (VT == MVT::f64) ? 2 : 4;
}
unsigned EltBits = EltVT.getSizeInBits();
- LLVMContext *Context = DAG.getContext();
// For FABS, mask is 0x7f...; for FNEG, mask is 0x80...
APInt MaskElt =
IsFABS ? APInt::getSignedMaxValue(EltBits) : APInt::getSignBit(EltBits);
- Constant *C = ConstantInt::get(*Context, MaskElt);
- C = ConstantVector::getSplat(NumElts, C);
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- SDValue CPIdx = DAG.getConstantPool(C, TLI.getPointerTy(DAG.getDataLayout()));
- unsigned Alignment = cast<ConstantPoolSDNode>(CPIdx)->getAlignment();
- SDValue Mask = DAG.getLoad(
- LogicVT, dl, DAG.getEntryNode(), CPIdx,
- MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), Alignment);
+ const fltSemantics &Sem =
+ EltVT == MVT::f64 ? APFloat::IEEEdouble() :
+ (IsF128 ? APFloat::IEEEquad() : APFloat::IEEEsingle());
+ SDValue Mask = DAG.getConstantFP(APFloat(Sem, MaskElt), dl, LogicVT);
SDValue Op0 = Op.getOperand(0);
bool IsFNABS = !IsFABS && (Op0.getOpcode() == ISD::FABS);
@@ -14429,92 +15725,73 @@ static SDValue LowerFABSorFNEG(SDValue Op, SelectionDAG &DAG) {
}
static SDValue LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) {
- const TargetLowering &TLI = DAG.getTargetLoweringInfo();
- LLVMContext *Context = DAG.getContext();
- SDValue Op0 = Op.getOperand(0);
- SDValue Op1 = Op.getOperand(1);
+ SDValue Mag = Op.getOperand(0);
+ SDValue Sign = Op.getOperand(1);
SDLoc dl(Op);
+
+ // If the sign operand is smaller, extend it first.
MVT VT = Op.getSimpleValueType();
- MVT SrcVT = Op1.getSimpleValueType();
- bool IsF128 = (VT == MVT::f128);
+ if (Sign.getSimpleValueType().bitsLT(VT))
+ Sign = DAG.getNode(ISD::FP_EXTEND, dl, VT, Sign);
- // If second operand is smaller, extend it first.
- if (SrcVT.bitsLT(VT)) {
- Op1 = DAG.getNode(ISD::FP_EXTEND, dl, VT, Op1);
- SrcVT = VT;
- }
// And if it is bigger, shrink it first.
- if (SrcVT.bitsGT(VT)) {
- Op1 = DAG.getNode(ISD::FP_ROUND, dl, VT, Op1, DAG.getIntPtrConstant(1, dl));
- SrcVT = VT;
- }
+ if (Sign.getSimpleValueType().bitsGT(VT))
+ Sign = DAG.getNode(ISD::FP_ROUND, dl, VT, Sign, DAG.getIntPtrConstant(1, dl));
// At this point the operands and the result should have the same
// type, and that won't be f80 since that is not custom lowered.
- assert((VT == MVT::f64 || VT == MVT::f32 || IsF128) &&
+ bool IsF128 = (VT == MVT::f128);
+ assert((VT == MVT::f64 || VT == MVT::f32 || VT == MVT::f128 ||
+ VT == MVT::v2f64 || VT == MVT::v4f64 || VT == MVT::v4f32 ||
+ VT == MVT::v8f32 || VT == MVT::v8f64 || VT == MVT::v16f32) &&
"Unexpected type in LowerFCOPYSIGN");
+ MVT EltVT = VT.getScalarType();
const fltSemantics &Sem =
- VT == MVT::f64 ? APFloat::IEEEdouble :
- (IsF128 ? APFloat::IEEEquad : APFloat::IEEEsingle);
- const unsigned SizeInBits = VT.getSizeInBits();
+ EltVT == MVT::f64 ? APFloat::IEEEdouble()
+ : (IsF128 ? APFloat::IEEEquad() : APFloat::IEEEsingle());
+
+ // Perform all scalar logic operations as 16-byte vectors because there are no
+ // scalar FP logic instructions in SSE.
+ // TODO: This isn't necessary. If we used scalar types, we might avoid some
+ // unnecessary splats, but we might miss load folding opportunities. Should
+ // this decision be based on OptimizeForSize?
+ bool IsFakeVector = !VT.isVector() && !IsF128;
+ MVT LogicVT = VT;
+ if (IsFakeVector)
+ LogicVT = (VT == MVT::f64) ? MVT::v2f64 : MVT::v4f32;
- SmallVector<Constant *, 4> CV(
- VT == MVT::f64 ? 2 : (IsF128 ? 1 : 4),
- ConstantFP::get(*Context, APFloat(Sem, APInt(SizeInBits, 0))));
+ // The mask constants are automatically splatted for vector types.
+ unsigned EltSizeInBits = VT.getScalarSizeInBits();
+ SDValue SignMask = DAG.getConstantFP(
+ APFloat(Sem, APInt::getSignBit(EltSizeInBits)), dl, LogicVT);
+ SDValue MagMask = DAG.getConstantFP(
+ APFloat(Sem, ~APInt::getSignBit(EltSizeInBits)), dl, LogicVT);
// First, clear all bits but the sign bit from the second operand (sign).
- CV[0] = ConstantFP::get(*Context,
- APFloat(Sem, APInt::getHighBitsSet(SizeInBits, 1)));
- Constant *C = ConstantVector::get(CV);
- auto PtrVT = TLI.getPointerTy(DAG.getDataLayout());
- SDValue CPIdx = DAG.getConstantPool(C, PtrVT, 16);
-
- // Perform all logic operations as 16-byte vectors because there are no
- // scalar FP logic instructions in SSE. This allows load folding of the
- // constants into the logic instructions.
- MVT LogicVT = (VT == MVT::f64) ? MVT::v2f64 : (IsF128 ? MVT::f128 : MVT::v4f32);
- SDValue Mask1 =
- DAG.getLoad(LogicVT, dl, DAG.getEntryNode(), CPIdx,
- MachinePointerInfo::getConstantPool(DAG.getMachineFunction()),
- /* Alignment = */ 16);
- if (!IsF128)
- Op1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, LogicVT, Op1);
- SDValue SignBit = DAG.getNode(X86ISD::FAND, dl, LogicVT, Op1, Mask1);
+ if (IsFakeVector)
+ Sign = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, LogicVT, Sign);
+ SDValue SignBit = DAG.getNode(X86ISD::FAND, dl, LogicVT, Sign, SignMask);
// Next, clear the sign bit from the first operand (magnitude).
- // If it's a constant, we can clear it here.
- if (ConstantFPSDNode *Op0CN = dyn_cast<ConstantFPSDNode>(Op0)) {
+ // TODO: If we had general constant folding for FP logic ops, this check
+ // wouldn't be necessary.
+ SDValue MagBits;
+ if (ConstantFPSDNode *Op0CN = dyn_cast<ConstantFPSDNode>(Mag)) {
APFloat APF = Op0CN->getValueAPF();
- // If the magnitude is a positive zero, the sign bit alone is enough.
- if (APF.isPosZero())
- return IsF128 ? SignBit :
- DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, SrcVT, SignBit,
- DAG.getIntPtrConstant(0, dl));
APF.clearSign();
- CV[0] = ConstantFP::get(*Context, APF);
+ MagBits = DAG.getConstantFP(APF, dl, LogicVT);
} else {
- CV[0] = ConstantFP::get(
- *Context,
- APFloat(Sem, APInt::getLowBitsSet(SizeInBits, SizeInBits - 1)));
- }
- C = ConstantVector::get(CV);
- CPIdx = DAG.getConstantPool(C, PtrVT, 16);
- SDValue Val =
- DAG.getLoad(LogicVT, dl, DAG.getEntryNode(), CPIdx,
- MachinePointerInfo::getConstantPool(DAG.getMachineFunction()),
- /* Alignment = */ 16);
- // If the magnitude operand wasn't a constant, we need to AND out the sign.
- if (!isa<ConstantFPSDNode>(Op0)) {
- if (!IsF128)
- Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, LogicVT, Op0);
- Val = DAG.getNode(X86ISD::FAND, dl, LogicVT, Op0, Val);
+ // If the magnitude operand wasn't a constant, we need to AND out the sign.
+ if (IsFakeVector)
+ Mag = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, LogicVT, Mag);
+ MagBits = DAG.getNode(X86ISD::FAND, dl, LogicVT, Mag, MagMask);
}
+
// OR the magnitude value with the sign bit.
- Val = DAG.getNode(X86ISD::FOR, dl, LogicVT, Val, SignBit);
- return IsF128 ? Val :
- DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, SrcVT, Val,
- DAG.getIntPtrConstant(0, dl));
+ SDValue Or = DAG.getNode(X86ISD::FOR, dl, LogicVT, MagBits, SignBit);
+ return !IsFakeVector ? Or : DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, VT, Or,
+ DAG.getIntPtrConstant(0, dl));
}
static SDValue LowerFGETSIGN(SDValue Op, SelectionDAG &DAG) {
@@ -14741,6 +16018,12 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
}
}
+ // Sometimes flags can be set either with an AND or with an SRL/SHL
+ // instruction. SRL/SHL variant should be preferred for masks longer than this
+ // number of bits.
+ const int ShiftToAndMaxMaskWidth = 32;
+ const bool ZeroCheck = (X86CC == X86::COND_E || X86CC == X86::COND_NE);
+
// NOTICE: In the code below we use ArithOp to hold the arithmetic operation
// which may be the result of a CAST. We use the variable 'Op', which is the
// non-casted variable when we check for possible users.
@@ -14764,7 +16047,7 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
goto default_case;
if (ConstantSDNode *C =
- dyn_cast<ConstantSDNode>(ArithOp.getNode()->getOperand(1))) {
+ dyn_cast<ConstantSDNode>(ArithOp.getOperand(1))) {
// An add of one will be selected as an INC.
if (C->isOne() && !Subtarget.slowIncDec()) {
Opcode = X86ISD::INC;
@@ -14789,7 +16072,7 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
// If we have a constant logical shift that's only used in a comparison
// against zero turn it into an equivalent AND. This allows turning it into
// a TEST instruction later.
- if ((X86CC == X86::COND_E || X86CC == X86::COND_NE) && Op->hasOneUse() &&
+ if (ZeroCheck && Op->hasOneUse() &&
isa<ConstantSDNode>(Op->getOperand(1)) && !hasNonFlagsUse(Op)) {
EVT VT = Op.getValueType();
unsigned BitWidth = VT.getSizeInBits();
@@ -14799,7 +16082,7 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
APInt Mask = ArithOp.getOpcode() == ISD::SRL
? APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt)
: APInt::getLowBitsSet(BitWidth, BitWidth - ShAmt);
- if (!Mask.isSignedIntN(32)) // Avoid large immediates.
+ if (!Mask.isSignedIntN(ShiftToAndMaxMaskWidth))
break;
Op = DAG.getNode(ISD::AND, dl, VT, Op->getOperand(0),
DAG.getConstant(Mask, dl, VT));
@@ -14808,20 +16091,61 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
case ISD::AND:
// If the primary 'and' result isn't used, don't bother using X86ISD::AND,
- // because a TEST instruction will be better.
+ // because a TEST instruction will be better. However, AND should be
+ // preferred if the instruction can be combined into ANDN.
if (!hasNonFlagsUse(Op)) {
SDValue Op0 = ArithOp->getOperand(0);
SDValue Op1 = ArithOp->getOperand(1);
EVT VT = ArithOp.getValueType();
bool isAndn = isBitwiseNot(Op0) || isBitwiseNot(Op1);
bool isLegalAndnType = VT == MVT::i32 || VT == MVT::i64;
+ bool isProperAndn = isAndn && isLegalAndnType && Subtarget.hasBMI();
+
+ // If we cannot select an ANDN instruction, check if we can replace
+ // AND+IMM64 with a shift before giving up. This is possible for masks
+ // like 0xFF000000 or 0x00FFFFFF and if we care only about the zero flag.
+ if (!isProperAndn) {
+ if (!ZeroCheck)
+ break;
+
+ assert(!isa<ConstantSDNode>(Op0) && "AND node isn't canonicalized");
+ auto *CN = dyn_cast<ConstantSDNode>(Op1);
+ if (!CN)
+ break;
+
+ const APInt &Mask = CN->getAPIntValue();
+ if (Mask.isSignedIntN(ShiftToAndMaxMaskWidth))
+ break; // Prefer TEST instruction.
+
+ unsigned BitWidth = Mask.getBitWidth();
+ unsigned LeadingOnes = Mask.countLeadingOnes();
+ unsigned TrailingZeros = Mask.countTrailingZeros();
+
+ if (LeadingOnes + TrailingZeros == BitWidth) {
+ assert(TrailingZeros < VT.getSizeInBits() &&
+ "Shift amount should be less than the type width");
+ MVT ShTy = getScalarShiftAmountTy(DAG.getDataLayout(), VT);
+ SDValue ShAmt = DAG.getConstant(TrailingZeros, dl, ShTy);
+ Op = DAG.getNode(ISD::SRL, dl, VT, Op0, ShAmt);
+ break;
+ }
+
+ unsigned LeadingZeros = Mask.countLeadingZeros();
+ unsigned TrailingOnes = Mask.countTrailingOnes();
+
+ if (LeadingZeros + TrailingOnes == BitWidth) {
+ assert(LeadingZeros < VT.getSizeInBits() &&
+ "Shift amount should be less than the type width");
+ MVT ShTy = getScalarShiftAmountTy(DAG.getDataLayout(), VT);
+ SDValue ShAmt = DAG.getConstant(LeadingZeros, dl, ShTy);
+ Op = DAG.getNode(ISD::SHL, dl, VT, Op0, ShAmt);
+ break;
+ }
- // But if we can combine this into an ANDN operation, then create an AND
- // now and allow it to be pattern matched into an ANDN.
- if (!Subtarget.hasBMI() || !isAndn || !isLegalAndnType)
break;
+ }
}
- // FALL THROUGH
+ LLVM_FALLTHROUGH;
case ISD::SUB:
case ISD::OR:
case ISD::XOR:
@@ -14839,7 +16163,7 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,
case ISD::XOR: Opcode = X86ISD::XOR; break;
case ISD::AND: Opcode = X86ISD::AND; break;
case ISD::OR: {
- if (!NeedTruncation && (X86CC == X86::COND_E || X86CC == X86::COND_NE)) {
+ if (!NeedTruncation && ZeroCheck) {
if (SDValue EFLAGS = LowerVectorAllZeroTest(Op, Subtarget, DAG))
return EFLAGS;
}
@@ -14968,14 +16292,27 @@ SDValue X86TargetLowering::ConvertCmpIfNecessary(SDValue Cmp,
return DAG.getNode(X86ISD::SAHF, dl, MVT::i32, TruncSrl);
}
+/// Check if replacement of SQRT with RSQRT should be disabled.
+bool X86TargetLowering::isFsqrtCheap(SDValue Op, SelectionDAG &DAG) const {
+ EVT VT = Op.getValueType();
+
+ // We never want to use both SQRT and RSQRT instructions for the same input.
+ if (DAG.getNodeIfExists(X86ISD::FRSQRT, DAG.getVTList(VT), Op))
+ return false;
+
+ if (VT.isVector())
+ return Subtarget.hasFastVectorFSQRT();
+ return Subtarget.hasFastScalarFSQRT();
+}
+
/// The minimum architected relative accuracy is 2^-12. We need one
/// Newton-Raphson step to have a good float result (24 bits of precision).
-SDValue X86TargetLowering::getRsqrtEstimate(SDValue Op,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const {
+SDValue X86TargetLowering::getSqrtEstimate(SDValue Op,
+ SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps,
+ bool &UseOneConstNR,
+ bool Reciprocal) const {
EVT VT = Op.getValueType();
- const char *RecipOp;
// SSE1 has rsqrtss and rsqrtps. AVX adds a 256-bit variant for rsqrtps.
// TODO: Add support for AVX512 (v16f32).
@@ -14984,30 +16321,24 @@ SDValue X86TargetLowering::getRsqrtEstimate(SDValue Op,
// instructions: convert to single, rsqrtss, convert back to double, refine
// (3 steps = at least 13 insts). If an 'rsqrtsd' variant was added to the ISA
// along with FMA, this could be a throughput win.
- if (VT == MVT::f32 && Subtarget.hasSSE1())
- RecipOp = "sqrtf";
- else if ((VT == MVT::v4f32 && Subtarget.hasSSE1()) ||
- (VT == MVT::v8f32 && Subtarget.hasAVX()))
- RecipOp = "vec-sqrtf";
- else
- return SDValue();
-
- TargetRecip Recips = DCI.DAG.getTarget().Options.Reciprocals;
- if (!Recips.isEnabled(RecipOp))
- return SDValue();
+ if ((VT == MVT::f32 && Subtarget.hasSSE1()) ||
+ (VT == MVT::v4f32 && Subtarget.hasSSE1()) ||
+ (VT == MVT::v8f32 && Subtarget.hasAVX())) {
+ if (RefinementSteps == ReciprocalEstimate::Unspecified)
+ RefinementSteps = 1;
- RefinementSteps = Recips.getRefinementSteps(RecipOp);
- UseOneConstNR = false;
- return DCI.DAG.getNode(X86ISD::FRSQRT, SDLoc(Op), VT, Op);
+ UseOneConstNR = false;
+ return DAG.getNode(X86ISD::FRSQRT, SDLoc(Op), VT, Op);
+ }
+ return SDValue();
}
/// The minimum architected relative accuracy is 2^-12. We need one
/// Newton-Raphson step to have a good float result (24 bits of precision).
-SDValue X86TargetLowering::getRecipEstimate(SDValue Op,
- DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const {
+SDValue X86TargetLowering::getRecipEstimate(SDValue Op, SelectionDAG &DAG,
+ int Enabled,
+ int &RefinementSteps) const {
EVT VT = Op.getValueType();
- const char *RecipOp;
// SSE1 has rcpss and rcpps. AVX adds a 256-bit variant for rcpps.
// TODO: Add support for AVX512 (v16f32).
@@ -15016,20 +16347,22 @@ SDValue X86TargetLowering::getRecipEstimate(SDValue Op,
// 15 instructions: convert to single, rcpss, convert back to double, refine
// (3 steps = 12 insts). If an 'rcpsd' variant was added to the ISA
// along with FMA, this could be a throughput win.
- if (VT == MVT::f32 && Subtarget.hasSSE1())
- RecipOp = "divf";
- else if ((VT == MVT::v4f32 && Subtarget.hasSSE1()) ||
- (VT == MVT::v8f32 && Subtarget.hasAVX()))
- RecipOp = "vec-divf";
- else
- return SDValue();
- TargetRecip Recips = DCI.DAG.getTarget().Options.Reciprocals;
- if (!Recips.isEnabled(RecipOp))
- return SDValue();
+ if ((VT == MVT::f32 && Subtarget.hasSSE1()) ||
+ (VT == MVT::v4f32 && Subtarget.hasSSE1()) ||
+ (VT == MVT::v8f32 && Subtarget.hasAVX())) {
+ // Enable estimate codegen with 1 refinement step for vector division.
+ // Scalar division estimates are disabled because they break too much
+ // real-world code. These defaults are intended to match GCC behavior.
+ if (VT == MVT::f32 && Enabled == ReciprocalEstimate::Unspecified)
+ return SDValue();
+
+ if (RefinementSteps == ReciprocalEstimate::Unspecified)
+ RefinementSteps = 1;
- RefinementSteps = Recips.getRefinementSteps(RecipOp);
- return DCI.DAG.getNode(X86ISD::FRCP, SDLoc(Op), VT, Op);
+ return DAG.getNode(X86ISD::FRCP, SDLoc(Op), VT, Op);
+ }
+ return SDValue();
}
/// If we have at least two divisions that use the same divisor, convert to
@@ -15042,9 +16375,46 @@ unsigned X86TargetLowering::combineRepeatedFPDivisors() const {
return 2;
}
+/// Helper for creating a X86ISD::SETCC node.
+static SDValue getSETCC(X86::CondCode Cond, SDValue EFLAGS, const SDLoc &dl,
+ SelectionDAG &DAG) {
+ return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
+ DAG.getConstant(Cond, dl, MVT::i8), EFLAGS);
+}
+
+/// Create a BT (Bit Test) node - Test bit \p BitNo in \p Src and set condition
+/// according to equal/not-equal condition code \p CC.
+static SDValue getBitTestCondition(SDValue Src, SDValue BitNo, ISD::CondCode CC,
+ const SDLoc &dl, SelectionDAG &DAG) {
+ // If Src is i8, promote it to i32 with any_extend. There is no i8 BT
+ // instruction. Since the shift amount is in-range-or-undefined, we know
+ // that doing a bittest on the i32 value is ok. We extend to i32 because
+ // the encoding for the i16 version is larger than the i32 version.
+ // Also promote i16 to i32 for performance / code size reason.
+ if (Src.getValueType() == MVT::i8 || Src.getValueType() == MVT::i16)
+ Src = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i32, Src);
+
+ // See if we can use the 32-bit instruction instead of the 64-bit one for a
+ // shorter encoding. Since the former takes the modulo 32 of BitNo and the
+ // latter takes the modulo 64, this is only valid if the 5th bit of BitNo is
+ // known to be zero.
+ if (Src.getValueType() == MVT::i64 &&
+ DAG.MaskedValueIsZero(BitNo, APInt(BitNo.getValueSizeInBits(), 32)))
+ Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
+
+ // If the operand types disagree, extend the shift amount to match. Since
+ // BT ignores high bits (like shifts) we can use anyextend.
+ if (Src.getValueType() != BitNo.getValueType())
+ BitNo = DAG.getNode(ISD::ANY_EXTEND, dl, Src.getValueType(), BitNo);
+
+ SDValue BT = DAG.getNode(X86ISD::BT, dl, MVT::i32, Src, BitNo);
+ X86::CondCode Cond = CC == ISD::SETEQ ? X86::COND_AE : X86::COND_B;
+ return getSETCC(Cond, BT, dl , DAG);
+}
+
/// Result of 'and' is compared against zero. Change to a BT node if possible.
-SDValue X86TargetLowering::LowerToBT(SDValue And, ISD::CondCode CC,
- const SDLoc &dl, SelectionDAG &DAG) const {
+static SDValue LowerAndToBT(SDValue And, ISD::CondCode CC,
+ const SDLoc &dl, SelectionDAG &DAG) {
SDValue Op0 = And.getOperand(0);
SDValue Op1 = And.getOperand(1);
if (Op0.getOpcode() == ISD::TRUNCATE)
@@ -15087,27 +16457,35 @@ SDValue X86TargetLowering::LowerToBT(SDValue And, ISD::CondCode CC,
}
}
- if (LHS.getNode()) {
- // If LHS is i8, promote it to i32 with any_extend. There is no i8 BT
- // instruction. Since the shift amount is in-range-or-undefined, we know
- // that doing a bittest on the i32 value is ok. We extend to i32 because
- // the encoding for the i16 version is larger than the i32 version.
- // Also promote i16 to i32 for performance / code size reason.
- if (LHS.getValueType() == MVT::i8 ||
- LHS.getValueType() == MVT::i16)
- LHS = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i32, LHS);
+ if (LHS.getNode())
+ return getBitTestCondition(LHS, RHS, CC, dl, DAG);
- // If the operand types disagree, extend the shift amount to match. Since
- // BT ignores high bits (like shifts) we can use anyextend.
- if (LHS.getValueType() != RHS.getValueType())
- RHS = DAG.getNode(ISD::ANY_EXTEND, dl, LHS.getValueType(), RHS);
+ return SDValue();
+}
- SDValue BT = DAG.getNode(X86ISD::BT, dl, MVT::i32, LHS, RHS);
- X86::CondCode Cond = CC == ISD::SETEQ ? X86::COND_AE : X86::COND_B;
- return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(Cond, dl, MVT::i8), BT);
- }
+// Convert (truncate (srl X, N) to i1) to (bt X, N)
+static SDValue LowerTruncateToBT(SDValue Op, ISD::CondCode CC,
+ const SDLoc &dl, SelectionDAG &DAG) {
+
+ assert(Op.getOpcode() == ISD::TRUNCATE && Op.getValueType() == MVT::i1 &&
+ "Expected TRUNCATE to i1 node");
+ if (Op.getOperand(0).getOpcode() != ISD::SRL)
+ return SDValue();
+
+ SDValue ShiftRight = Op.getOperand(0);
+ return getBitTestCondition(ShiftRight.getOperand(0), ShiftRight.getOperand(1),
+ CC, dl, DAG);
+}
+
+/// Result of 'and' or 'trunc to i1' is compared against zero.
+/// Change to a BT node if possible.
+SDValue X86TargetLowering::LowerToBT(SDValue Op, ISD::CondCode CC,
+ const SDLoc &dl, SelectionDAG &DAG) const {
+ if (Op.getOpcode() == ISD::AND)
+ return LowerAndToBT(Op, CC, dl, DAG);
+ if (Op.getOpcode() == ISD::TRUNCATE && Op.getValueType() == MVT::i1)
+ return LowerTruncateToBT(Op, CC, dl, DAG);
return SDValue();
}
@@ -15132,19 +16510,19 @@ static int translateX86FSETCC(ISD::CondCode SetCCOpcode, SDValue &Op0,
case ISD::SETOEQ:
case ISD::SETEQ: SSECC = 0; break;
case ISD::SETOGT:
- case ISD::SETGT: Swap = true; // Fallthrough
+ case ISD::SETGT: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETLT:
case ISD::SETOLT: SSECC = 1; break;
case ISD::SETOGE:
- case ISD::SETGE: Swap = true; // Fallthrough
+ case ISD::SETGE: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETLE:
case ISD::SETOLE: SSECC = 2; break;
case ISD::SETUO: SSECC = 3; break;
case ISD::SETUNE:
case ISD::SETNE: SSECC = 4; break;
- case ISD::SETULE: Swap = true; // Fallthrough
+ case ISD::SETULE: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETUGE: SSECC = 5; break;
- case ISD::SETULT: Swap = true; // Fallthrough
+ case ISD::SETULT: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETUGT: SSECC = 6; break;
case ISD::SETO: SSECC = 7; break;
case ISD::SETUEQ:
@@ -15250,12 +16628,12 @@ static SDValue LowerIntVSETCC_AVX512(SDValue Op, SelectionDAG &DAG) {
case ISD::SETNE: SSECC = 4; break;
case ISD::SETEQ: Opc = X86ISD::PCMPEQM; break;
case ISD::SETUGT: SSECC = 6; Unsigned = true; break;
- case ISD::SETLT: Swap = true; //fall-through
+ case ISD::SETLT: Swap = true; LLVM_FALLTHROUGH;
case ISD::SETGT: Opc = X86ISD::PCMPGTM; break;
case ISD::SETULT: SSECC = 1; Unsigned = true; break;
case ISD::SETUGE: SSECC = 5; Unsigned = true; break; //NLT
case ISD::SETGE: Swap = true; SSECC = 2; break; // LE + swap
- case ISD::SETULE: Unsigned = true; //fall-through
+ case ISD::SETULE: Unsigned = true; LLVM_FALLTHROUGH;
case ISD::SETLE: SSECC = 2; break;
}
@@ -15414,7 +16792,7 @@ static SDValue LowerVSETCC(SDValue Op, const X86Subtarget &Subtarget,
// In this case use SSE compare
bool UseAVX512Inst =
(OpVT.is512BitVector() ||
- OpVT.getVectorElementType().getSizeInBits() >= 32 ||
+ OpVT.getScalarSizeInBits() >= 32 ||
(Subtarget.hasBWI() && Subtarget.hasVLX()));
if (UseAVX512Inst)
@@ -15638,15 +17016,12 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
// Lower (X & (1 << N)) == 0 to BT(X, N).
// Lower ((X >>u N) & 1) != 0 to BT(X, N).
// Lower ((X >>s N) & 1) != 0 to BT(X, N).
- if (Op0.getOpcode() == ISD::AND && Op0.hasOneUse() &&
- isNullConstant(Op1) &&
+ // Lower (trunc (X >> N) to i1) to BT(X, N).
+ if (Op0.hasOneUse() && isNullConstant(Op1) &&
(CC == ISD::SETEQ || CC == ISD::SETNE)) {
if (SDValue NewSetCC = LowerToBT(Op0, CC, dl, DAG)) {
- if (VT == MVT::i1) {
- NewSetCC = DAG.getNode(ISD::AssertZext, dl, MVT::i8, NewSetCC,
- DAG.getValueType(MVT::i1));
+ if (VT == MVT::i1)
return DAG.getNode(ISD::TRUNCATE, dl, MVT::i1, NewSetCC);
- }
return NewSetCC;
}
}
@@ -15665,14 +17040,9 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
return Op0;
CCode = X86::GetOppositeBranchCondition(CCode);
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(CCode, dl, MVT::i8),
- Op0.getOperand(1));
- if (VT == MVT::i1) {
- SetCC = DAG.getNode(ISD::AssertZext, dl, MVT::i8, SetCC,
- DAG.getValueType(MVT::i1));
+ SDValue SetCC = getSETCC(CCode, Op0.getOperand(1), dl, DAG);
+ if (VT == MVT::i1)
return DAG.getNode(ISD::TRUNCATE, dl, MVT::i1, SetCC);
- }
return SetCC;
}
}
@@ -15687,20 +17057,16 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
}
}
- bool isFP = Op1.getSimpleValueType().isFloatingPoint();
- unsigned X86CC = TranslateX86CC(CC, dl, isFP, Op0, Op1, DAG);
+ bool IsFP = Op1.getSimpleValueType().isFloatingPoint();
+ X86::CondCode X86CC = TranslateX86CC(CC, dl, IsFP, Op0, Op1, DAG);
if (X86CC == X86::COND_INVALID)
return SDValue();
SDValue EFLAGS = EmitCmp(Op0, Op1, X86CC, dl, DAG);
EFLAGS = ConvertCmpIfNecessary(EFLAGS, DAG);
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86CC, dl, MVT::i8), EFLAGS);
- if (VT == MVT::i1) {
- SetCC = DAG.getNode(ISD::AssertZext, dl, MVT::i8, SetCC,
- DAG.getValueType(MVT::i1));
+ SDValue SetCC = getSETCC(X86CC, EFLAGS, dl, DAG);
+ if (VT == MVT::i1)
return DAG.getNode(ISD::TRUNCATE, dl, MVT::i1, SetCC);
- }
return SetCC;
}
@@ -15717,34 +17083,23 @@ SDValue X86TargetLowering::LowerSETCCE(SDValue Op, SelectionDAG &DAG) const {
assert(Carry.getOpcode() != ISD::CARRY_FALSE);
SDVTList VTs = DAG.getVTList(LHS.getValueType(), MVT::i32);
SDValue Cmp = DAG.getNode(X86ISD::SBB, DL, VTs, LHS, RHS, Carry);
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, DL, MVT::i8,
- DAG.getConstant(CC, DL, MVT::i8), Cmp.getValue(1));
- if (Op.getSimpleValueType() == MVT::i1) {
- SetCC = DAG.getNode(ISD::AssertZext, DL, MVT::i8, SetCC,
- DAG.getValueType(MVT::i1));
+ SDValue SetCC = getSETCC(CC, Cmp.getValue(1), DL, DAG);
+ if (Op.getSimpleValueType() == MVT::i1)
return DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, SetCC);
- }
return SetCC;
}
/// Return true if opcode is a X86 logical comparison.
static bool isX86LogicalCmp(SDValue Op) {
- unsigned Opc = Op.getNode()->getOpcode();
+ unsigned Opc = Op.getOpcode();
if (Opc == X86ISD::CMP || Opc == X86ISD::COMI || Opc == X86ISD::UCOMI ||
Opc == X86ISD::SAHF)
return true;
if (Op.getResNo() == 1 &&
- (Opc == X86ISD::ADD ||
- Opc == X86ISD::SUB ||
- Opc == X86ISD::ADC ||
- Opc == X86ISD::SBB ||
- Opc == X86ISD::SMUL ||
- Opc == X86ISD::UMUL ||
- Opc == X86ISD::INC ||
- Opc == X86ISD::DEC ||
- Opc == X86ISD::OR ||
- Opc == X86ISD::XOR ||
- Opc == X86ISD::AND))
+ (Opc == X86ISD::ADD || Opc == X86ISD::SUB || Opc == X86ISD::ADC ||
+ Opc == X86ISD::SBB || Opc == X86ISD::SMUL || Opc == X86ISD::UMUL ||
+ Opc == X86ISD::INC || Opc == X86ISD::DEC || Opc == X86ISD::OR ||
+ Opc == X86ISD::XOR || Opc == X86ISD::AND))
return true;
if (Op.getResNo() == 2 && Opc == X86ISD::UMUL)
@@ -15753,27 +17108,18 @@ static bool isX86LogicalCmp(SDValue Op) {
return false;
}
-/// Returns the "condition" node, that may be wrapped with "truncate".
-/// Like this: (i1 (trunc (i8 X86ISD::SETCC))).
-static SDValue getCondAfterTruncWithZeroHighBitsInput(SDValue V, SelectionDAG &DAG) {
+static bool isTruncWithZeroHighBitsInput(SDValue V, SelectionDAG &DAG) {
if (V.getOpcode() != ISD::TRUNCATE)
- return V;
+ return false;
SDValue VOp0 = V.getOperand(0);
- if (VOp0.getOpcode() == ISD::AssertZext &&
- V.getValueSizeInBits() ==
- cast<VTSDNode>(VOp0.getOperand(1))->getVT().getSizeInBits())
- return VOp0.getOperand(0);
-
unsigned InBits = VOp0.getValueSizeInBits();
unsigned Bits = V.getValueSizeInBits();
- if (DAG.MaskedValueIsZero(VOp0, APInt::getHighBitsSet(InBits,InBits-Bits)))
- return V.getOperand(0);
- return V;
+ return DAG.MaskedValueIsZero(VOp0, APInt::getHighBitsSet(InBits,InBits-Bits));
}
SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
- bool addTest = true;
+ bool AddTest = true;
SDValue Cond = Op.getOperand(0);
SDValue Op1 = Op.getOperand(1);
SDValue Op2 = Op.getOperand(2);
@@ -15794,9 +17140,10 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if (SSECC != 8) {
if (Subtarget.hasAVX512()) {
- SDValue Cmp = DAG.getNode(X86ISD::FSETCC, DL, MVT::i1, CondOp0, CondOp1,
- DAG.getConstant(SSECC, DL, MVT::i8));
- return DAG.getNode(X86ISD::SELECT, DL, VT, Cmp, Op1, Op2);
+ SDValue Cmp = DAG.getNode(X86ISD::FSETCCM, DL, MVT::i1, CondOp0,
+ CondOp1, DAG.getConstant(SSECC, DL, MVT::i8));
+ return DAG.getNode(VT.isVector() ? X86ISD::SELECT : X86ISD::SELECTS,
+ DL, VT, Cmp, Op1, Op2);
}
SDValue Cmp = DAG.getNode(X86ISD::FSETCC, DL, VT, CondOp0, CondOp1,
@@ -15840,6 +17187,11 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
}
}
+ // AVX512 fallback is to lower selects of scalar floats to masked moves.
+ if (Cond.getValueType() == MVT::i1 && (VT == MVT::f64 || VT == MVT::f32) &&
+ Subtarget.hasAVX512())
+ return DAG.getNode(X86ISD::SELECTS, DL, VT, Cond, Op1, Op2);
+
if (VT.isVector() && VT.getVectorElementType() == MVT::i1) {
SDValue Op1Scalar;
if (ISD::isBuildVectorOfConstantSDNodes(Op1.getNode()))
@@ -15875,8 +17227,14 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
}
if (Cond.getOpcode() == ISD::SETCC) {
- if (SDValue NewCond = LowerSETCC(Cond, DAG))
+ if (SDValue NewCond = LowerSETCC(Cond, DAG)) {
Cond = NewCond;
+ // If the condition was updated, it's possible that the operands of the
+ // select were also updated (for example, EmitTest has a RAUW). Refresh
+ // the local references to the select operands in case they got stale.
+ Op1 = Op.getOperand(1);
+ Op2 = Op.getOperand(2);
+ }
}
// (select (x == 0), -1, y) -> (sign_bit (x - 1)) | y
@@ -15953,7 +17311,7 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if ((isX86LogicalCmp(Cmp) && !IllegalFPCMov) ||
Opc == X86ISD::BT) { // FIXME
Cond = Cmp;
- addTest = false;
+ AddTest = false;
}
} else if (CondOpcode == ISD::USUBO || CondOpcode == ISD::SSUBO ||
CondOpcode == ISD::UADDO || CondOpcode == ISD::SADDO ||
@@ -15987,12 +17345,13 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
Cond = X86Op.getValue(1);
CC = DAG.getConstant(X86Cond, DL, MVT::i8);
- addTest = false;
+ AddTest = false;
}
- if (addTest) {
+ if (AddTest) {
// Look past the truncate if the high bits are known zero.
- Cond = getCondAfterTruncWithZeroHighBitsInput(Cond, DAG);
+ if (isTruncWithZeroHighBitsInput(Cond, DAG))
+ Cond = Cond.getOperand(0);
// We know the result of AND is compared against zero. Try to match
// it to BT.
@@ -16000,12 +17359,12 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if (SDValue NewSetCC = LowerToBT(Cond, ISD::SETNE, DL, DAG)) {
CC = NewSetCC.getOperand(0);
Cond = NewSetCC.getOperand(1);
- addTest = false;
+ AddTest = false;
}
}
}
- if (addTest) {
+ if (AddTest) {
CC = DAG.getConstant(X86::COND_NE, DL, MVT::i8);
Cond = EmitTest(Cond, X86::COND_NE, DL, DAG);
}
@@ -16077,34 +17436,44 @@ static SDValue LowerSIGN_EXTEND_AVX512(SDValue Op,
VTElt.getSizeInBits() >= 32))))
return DAG.getNode(X86ISD::VSEXT, dl, VT, In);
- unsigned int NumElts = VT.getVectorNumElements();
-
- if (NumElts != 8 && NumElts != 16 && !Subtarget.hasBWI())
- return SDValue();
+ unsigned NumElts = VT.getVectorNumElements();
- if (VT.is512BitVector() && InVT.getVectorElementType() != MVT::i1) {
+ if (VT.is512BitVector() && InVTElt != MVT::i1 &&
+ (NumElts == 8 || NumElts == 16 || Subtarget.hasBWI())) {
if (In.getOpcode() == X86ISD::VSEXT || In.getOpcode() == X86ISD::VZEXT)
return DAG.getNode(In.getOpcode(), dl, VT, In.getOperand(0));
return DAG.getNode(X86ISD::VSEXT, dl, VT, In);
}
- assert (InVT.getVectorElementType() == MVT::i1 && "Unexpected vector type");
- MVT ExtVT = NumElts == 8 ? MVT::v8i64 : MVT::v16i32;
- SDValue NegOne =
- DAG.getConstant(APInt::getAllOnesValue(ExtVT.getScalarSizeInBits()), dl,
- ExtVT);
- SDValue Zero =
- DAG.getConstant(APInt::getNullValue(ExtVT.getScalarSizeInBits()), dl, ExtVT);
+ if (InVTElt != MVT::i1)
+ return SDValue();
+
+ MVT ExtVT = VT;
+ if (!VT.is512BitVector() && !Subtarget.hasVLX())
+ ExtVT = MVT::getVectorVT(MVT::getIntegerVT(512/NumElts), NumElts);
+
+ SDValue V;
+ if (Subtarget.hasDQI()) {
+ V = DAG.getNode(X86ISD::VSEXT, dl, ExtVT, In);
+ assert(!VT.is512BitVector() && "Unexpected vector type");
+ } else {
+ SDValue NegOne = getOnesVector(ExtVT, Subtarget, DAG, dl);
+ SDValue Zero = getZeroVector(ExtVT, Subtarget, DAG, dl);
+ V = DAG.getNode(ISD::VSELECT, dl, ExtVT, In, NegOne, Zero);
+ if (ExtVT == VT)
+ return V;
+ }
- SDValue V = DAG.getNode(ISD::VSELECT, dl, ExtVT, In, NegOne, Zero);
- if (VT.is512BitVector())
- return V;
return DAG.getNode(X86ISD::VTRUNC, dl, VT, V);
}
-static SDValue LowerSIGN_EXTEND_VECTOR_INREG(SDValue Op,
- const X86Subtarget &Subtarget,
- SelectionDAG &DAG) {
+// Lowering for SIGN_EXTEND_VECTOR_INREG and ZERO_EXTEND_VECTOR_INREG.
+// For sign extend this needs to handle all vector sizes and SSE4.1 and
+// non-SSE4.1 targets. For zero extend this should only handle inputs of
+// MVT::v64i8 when BWI is not supported, but AVX512 is.
+static SDValue LowerEXTEND_VECTOR_INREG(SDValue Op,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
SDValue In = Op->getOperand(0);
MVT VT = Op->getSimpleValueType(0);
MVT InVT = In.getSimpleValueType();
@@ -16119,20 +17488,33 @@ static SDValue LowerSIGN_EXTEND_VECTOR_INREG(SDValue Op,
if (InSVT != MVT::i32 && InSVT != MVT::i16 && InSVT != MVT::i8)
return SDValue();
if (!(VT.is128BitVector() && Subtarget.hasSSE2()) &&
- !(VT.is256BitVector() && Subtarget.hasInt256()))
+ !(VT.is256BitVector() && Subtarget.hasInt256()) &&
+ !(VT.is512BitVector() && Subtarget.hasAVX512()))
return SDValue();
SDLoc dl(Op);
// For 256-bit vectors, we only need the lower (128-bit) half of the input.
- if (VT.is256BitVector())
- In = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl,
- MVT::getVectorVT(InSVT, InVT.getVectorNumElements() / 2),
- In, DAG.getIntPtrConstant(0, dl));
+ // For 512-bit vectors, we need 128-bits or 256-bits.
+ if (VT.getSizeInBits() > 128) {
+ // Input needs to be at least the same number of elements as output, and
+ // at least 128-bits.
+ int InSize = InSVT.getSizeInBits() * VT.getVectorNumElements();
+ In = extractSubVector(In, 0, DAG, dl, std::max(InSize, 128));
+ }
+
+ assert((Op.getOpcode() != ISD::ZERO_EXTEND_VECTOR_INREG ||
+ InVT == MVT::v64i8) && "Zero extend only for v64i8 input!");
// SSE41 targets can use the pmovsx* instructions directly.
+ unsigned ExtOpc = Op.getOpcode() == ISD::SIGN_EXTEND_VECTOR_INREG ?
+ X86ISD::VSEXT : X86ISD::VZEXT;
if (Subtarget.hasSSE41())
- return DAG.getNode(X86ISD::VSEXT, dl, VT, In);
+ return DAG.getNode(ExtOpc, dl, VT, In);
+
+ // We should only get here for sign extend.
+ assert(Op.getOpcode() == ISD::SIGN_EXTEND_VECTOR_INREG &&
+ "Unexpected opcode!");
// pre-SSE41 targets unpack lower lanes and then sign-extend using SRAI.
SDValue Curr = In;
@@ -16150,7 +17532,7 @@ static SDValue LowerSIGN_EXTEND_VECTOR_INREG(SDValue Op,
SDValue SignExt = Curr;
if (CurrVT != InVT) {
unsigned SignExtShift =
- CurrVT.getVectorElementType().getSizeInBits() - InSVT.getSizeInBits();
+ CurrVT.getScalarSizeInBits() - InSVT.getSizeInBits();
SignExt = DAG.getNode(X86ISD::VSRAI, dl, CurrVT, Curr,
DAG.getConstant(SignExtShift, dl, MVT::i8));
}
@@ -16211,7 +17593,7 @@ static SDValue LowerSIGN_EXTEND(SDValue Op, const X86Subtarget &Subtarget,
SDValue OpHi = DAG.getVectorShuffle(InVT, dl, In, Undef, ShufMask2);
MVT HalfVT = MVT::getVectorVT(VT.getVectorElementType(),
- VT.getVectorNumElements()/2);
+ VT.getVectorNumElements() / 2);
OpLo = DAG.getNode(X86ISD::VSEXT, dl, HalfVT, OpLo);
OpHi = DAG.getNode(X86ISD::VSEXT, dl, HalfVT, OpHi);
@@ -16643,7 +18025,7 @@ SDValue X86TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
case X86::COND_B:
// These can only come from an arithmetic instruction with overflow,
// e.g. SADDO, UADDO.
- Cond = Cond.getNode()->getOperand(1);
+ Cond = Cond.getOperand(1);
addTest = false;
break;
}
@@ -16828,11 +18210,11 @@ SDValue X86TargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
if (addTest) {
// Look pass the truncate if the high bits are known zero.
- Cond = getCondAfterTruncWithZeroHighBitsInput(Cond, DAG);
+ if (isTruncWithZeroHighBitsInput(Cond, DAG))
+ Cond = Cond.getOperand(0);
- // We know the result of AND is compared against zero. Try to match
- // it to BT.
- if (Cond.getOpcode() == ISD::AND && Cond.hasOneUse()) {
+ // We know the result is compared against zero. Try to match it to BT.
+ if (Cond.hasOneUse()) {
if (SDValue NewSetCC = LowerToBT(Cond, ISD::SETNE, dl, DAG)) {
CC = NewSetCC.getOperand(0);
Cond = NewSetCC.getOperand(1);
@@ -17000,7 +18382,7 @@ SDValue X86TargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
SDValue X86TargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
assert(Subtarget.is64Bit() &&
"LowerVAARG only handles 64-bit va_arg!");
- assert(Op.getNode()->getNumOperands() == 4);
+ assert(Op.getNumOperands() == 4);
MachineFunction &MF = DAG.getMachineFunction();
if (Subtarget.isCallingConvWin64(MF.getFunction()->getCallingConv()))
@@ -17161,6 +18543,7 @@ static SDValue getTargetVShiftByConstNode(unsigned Opc, const SDLoc &dl, MVT VT,
/// constant. Takes immediate version of shift as input.
static SDValue getTargetVShiftNode(unsigned Opc, const SDLoc &dl, MVT VT,
SDValue SrcOp, SDValue ShAmt,
+ const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
MVT SVT = ShAmt.getSimpleValueType();
assert((SVT == MVT::i32 || SVT == MVT::i64) && "Unexpected value type!");
@@ -17178,27 +18561,32 @@ static SDValue getTargetVShiftNode(unsigned Opc, const SDLoc &dl, MVT VT,
case X86ISD::VSRAI: Opc = X86ISD::VSRA; break;
}
- const X86Subtarget &Subtarget =
- static_cast<const X86Subtarget &>(DAG.getSubtarget());
- if (Subtarget.hasSSE41() && ShAmt.getOpcode() == ISD::ZERO_EXTEND &&
- ShAmt.getOperand(0).getSimpleValueType() == MVT::i16) {
- // Let the shuffle legalizer expand this shift amount node.
- SDValue Op0 = ShAmt.getOperand(0);
- Op0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(Op0), MVT::v8i16, Op0);
- ShAmt = getShuffleVectorZeroOrUndef(Op0, 0, true, Subtarget, DAG);
+ // Need to build a vector containing shift amount.
+ // SSE/AVX packed shifts only use the lower 64-bit of the shift count.
+ // +=================+============+=======================================+
+ // | ShAmt is | HasSSE4.1? | Construct ShAmt vector as |
+ // +=================+============+=======================================+
+ // | i64 | Yes, No | Use ShAmt as lowest elt |
+ // | i32 | Yes | zero-extend in-reg |
+ // | (i32 zext(i16)) | Yes | zero-extend in-reg |
+ // | i16/i32 | No | v4i32 build_vector(ShAmt, 0, ud, ud)) |
+ // +=================+============+=======================================+
+
+ if (SVT == MVT::i64)
+ ShAmt = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(ShAmt), MVT::v2i64, ShAmt);
+ else if (Subtarget.hasSSE41() && ShAmt.getOpcode() == ISD::ZERO_EXTEND &&
+ ShAmt.getOperand(0).getSimpleValueType() == MVT::i16) {
+ ShAmt = ShAmt.getOperand(0);
+ ShAmt = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(ShAmt), MVT::v8i16, ShAmt);
+ ShAmt = DAG.getNode(X86ISD::VZEXT, SDLoc(ShAmt), MVT::v2i64, ShAmt);
+ } else if (Subtarget.hasSSE41() &&
+ ShAmt.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
+ ShAmt = DAG.getNode(ISD::SCALAR_TO_VECTOR, SDLoc(ShAmt), MVT::v4i32, ShAmt);
+ ShAmt = DAG.getNode(X86ISD::VZEXT, SDLoc(ShAmt), MVT::v2i64, ShAmt);
} else {
- // Need to build a vector containing shift amount.
- // SSE/AVX packed shifts only use the lower 64-bit of the shift count.
- SmallVector<SDValue, 4> ShOps;
- ShOps.push_back(ShAmt);
- if (SVT == MVT::i32) {
- ShOps.push_back(DAG.getConstant(0, dl, SVT));
- ShOps.push_back(DAG.getUNDEF(SVT));
- }
- ShOps.push_back(DAG.getUNDEF(SVT));
-
- MVT BVT = SVT == MVT::i32 ? MVT::v4i32 : MVT::v2i64;
- ShAmt = DAG.getBuildVector(BVT, dl, ShOps);
+ SmallVector<SDValue, 4> ShOps = {ShAmt, DAG.getConstant(0, dl, SVT),
+ DAG.getUNDEF(SVT), DAG.getUNDEF(SVT)};
+ ShAmt = DAG.getBuildVector(MVT::v4i32, dl, ShOps);
}
// The return type has to be a 128-bit type with the same element
@@ -17290,7 +18678,7 @@ static SDValue getVectorMaskingNode(SDValue Op, SDValue Mask,
case X86ISD::VTRUNC:
case X86ISD::VTRUNCS:
case X86ISD::VTRUNCUS:
- case ISD::FP_TO_FP16:
+ case X86ISD::CVTPS2PH:
// We can't use ISD::VSELECT here because it is not always "Legal"
// for the destination type. For example vpmovqb require only AVX512
// and vselect that can operate on byte element type require BWI
@@ -17321,7 +18709,8 @@ static SDValue getScalarMaskingNode(SDValue Op, SDValue Mask,
// The mask should be of type MVT::i1
SDValue IMask = DAG.getNode(ISD::TRUNCATE, dl, MVT::i1, Mask);
- if (Op.getOpcode() == X86ISD::FSETCC)
+ if (Op.getOpcode() == X86ISD::FSETCCM ||
+ Op.getOpcode() == X86ISD::FSETCCM_RND)
return DAG.getNode(ISD::AND, dl, VT, Op, IMask);
if (Op.getOpcode() == X86ISD::VFPCLASS ||
Op.getOpcode() == X86ISD::VFPCLASSS)
@@ -17329,7 +18718,7 @@ static SDValue getScalarMaskingNode(SDValue Op, SDValue Mask,
if (PreservedSrc.isUndef())
PreservedSrc = getZeroVector(VT, Subtarget, DAG, dl);
- return DAG.getNode(X86ISD::SELECT, dl, VT, IMask, Op, PreservedSrc);
+ return DAG.getNode(X86ISD::SELECTS, dl, VT, IMask, Op, PreservedSrc);
}
static int getSEHRegistrationNodeSize(const Function *Fn) {
@@ -17395,6 +18784,15 @@ static SDValue recoverFramePointer(SelectionDAG &DAG, const Function *Fn,
static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
+ // Helper to detect if the operand is CUR_DIRECTION rounding mode.
+ auto isRoundModeCurDirection = [](SDValue Rnd) {
+ if (!isa<ConstantSDNode>(Rnd))
+ return false;
+
+ unsigned Round = cast<ConstantSDNode>(Rnd)->getZExtValue();
+ return Round == X86::STATIC_ROUNDING::CUR_DIRECTION;
+ };
+
SDLoc dl(Op);
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
MVT VT = Op.getSimpleValueType();
@@ -17406,9 +18804,6 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
case INTR_TYPE_2OP:
return DAG.getNode(IntrData->Opc0, dl, Op.getValueType(), Op.getOperand(1),
Op.getOperand(2));
- case INTR_TYPE_2OP_IMM8:
- return DAG.getNode(IntrData->Opc0, dl, Op.getValueType(), Op.getOperand(1),
- DAG.getNode(ISD::TRUNCATE, dl, MVT::i8, Op.getOperand(2)));
case INTR_TYPE_3OP:
return DAG.getNode(IntrData->Opc0, dl, Op.getValueType(), Op.getOperand(1),
Op.getOperand(2), Op.getOperand(3));
@@ -17420,7 +18815,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SDValue PassThru = Op.getOperand(2);
SDValue Mask = Op.getOperand(3);
SDValue RoundingMode;
- // We allways add rounding mode to the Node.
+ // We always add rounding mode to the Node.
// If the rounding mode is not specified, we add the
// "current direction" mode.
if (Op.getNumOperands() == 4)
@@ -17428,13 +18823,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
DAG.getConstant(X86::STATIC_ROUNDING::CUR_DIRECTION, dl, MVT::i32);
else
RoundingMode = Op.getOperand(4);
- unsigned IntrWithRoundingModeOpcode = IntrData->Opc1;
- if (IntrWithRoundingModeOpcode != 0)
- if (cast<ConstantSDNode>(RoundingMode)->getZExtValue() !=
- X86::STATIC_ROUNDING::CUR_DIRECTION)
- return getVectorMaskingNode(DAG.getNode(IntrWithRoundingModeOpcode,
- dl, Op.getValueType(), Src, RoundingMode),
- Mask, PassThru, Subtarget, DAG);
+ assert(IntrData->Opc1 == 0 && "Unexpected second opcode!");
return getVectorMaskingNode(DAG.getNode(IntrData->Opc0, dl, VT, Src,
RoundingMode),
Mask, PassThru, Subtarget, DAG);
@@ -17449,8 +18838,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
unsigned IntrWithRoundingModeOpcode = IntrData->Opc1;
if (IntrWithRoundingModeOpcode != 0) {
SDValue Rnd = Op.getOperand(4);
- unsigned Round = cast<ConstantSDNode>(Rnd)->getZExtValue();
- if (Round != X86::STATIC_ROUNDING::CUR_DIRECTION) {
+ if (!isRoundModeCurDirection(Rnd)) {
return getVectorMaskingNode(DAG.getNode(IntrWithRoundingModeOpcode,
dl, Op.getValueType(),
Src, Rnd),
@@ -17478,8 +18866,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
// (2) With rounding mode and sae - 7 operands.
if (Op.getNumOperands() == 6) {
SDValue Sae = Op.getOperand(5);
- unsigned Opc = IntrData->Opc1 ? IntrData->Opc1 : IntrData->Opc0;
- return getScalarMaskingNode(DAG.getNode(Opc, dl, VT, Src1, Src2,
+ return getScalarMaskingNode(DAG.getNode(IntrData->Opc0, dl, VT, Src1, Src2,
Sae),
Mask, Src0, Subtarget, DAG);
}
@@ -17506,8 +18893,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
unsigned IntrWithRoundingModeOpcode = IntrData->Opc1;
if (IntrWithRoundingModeOpcode != 0) {
SDValue Rnd = Op.getOperand(5);
- unsigned Round = cast<ConstantSDNode>(Rnd)->getZExtValue();
- if (Round != X86::STATIC_ROUNDING::CUR_DIRECTION) {
+ if (!isRoundModeCurDirection(Rnd)) {
return getVectorMaskingNode(DAG.getNode(IntrWithRoundingModeOpcode,
dl, Op.getValueType(),
Src1, Src2, Rnd),
@@ -17564,12 +18950,11 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
else
Rnd = DAG.getConstant(X86::STATIC_ROUNDING::CUR_DIRECTION, dl, MVT::i32);
return getVectorMaskingNode(DAG.getNode(IntrData->Opc0, dl, VT,
- Src1, Src2, Imm, Rnd),
- Mask, PassThru, Subtarget, DAG);
+ Src1, Src2, Imm, Rnd),
+ Mask, PassThru, Subtarget, DAG);
}
case INTR_TYPE_3OP_IMM8_MASK:
- case INTR_TYPE_3OP_MASK:
- case INSERT_SUBVEC: {
+ case INTR_TYPE_3OP_MASK: {
SDValue Src1 = Op.getOperand(1);
SDValue Src2 = Op.getOperand(2);
SDValue Src3 = Op.getOperand(3);
@@ -17578,13 +18963,6 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
if (IntrData->Type == INTR_TYPE_3OP_IMM8_MASK)
Src3 = DAG.getNode(ISD::TRUNCATE, dl, MVT::i8, Src3);
- else if (IntrData->Type == INSERT_SUBVEC) {
- // imm should be adapted to ISD::INSERT_SUBVECTOR behavior
- assert(isa<ConstantSDNode>(Src3) && "Expected a ConstantSDNode here!");
- unsigned Imm = cast<ConstantSDNode>(Src3)->getZExtValue();
- Imm *= Src2.getSimpleValueType().getVectorNumElements();
- Src3 = DAG.getTargetConstant(Imm, dl, MVT::i32);
- }
// We specify 2 possible opcodes for intrinsics with rounding modes.
// First, we check if the intrinsic may have non-default rounding mode,
@@ -17592,8 +18970,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
unsigned IntrWithRoundingModeOpcode = IntrData->Opc1;
if (IntrWithRoundingModeOpcode != 0) {
SDValue Rnd = Op.getOperand(6);
- unsigned Round = cast<ConstantSDNode>(Rnd)->getZExtValue();
- if (Round != X86::STATIC_ROUNDING::CUR_DIRECTION) {
+ if (!isRoundModeCurDirection(Rnd)) {
return getVectorMaskingNode(DAG.getNode(IntrWithRoundingModeOpcode,
dl, Op.getValueType(),
Src1, Src2, Src3, Rnd),
@@ -17616,19 +18993,21 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
}
case VPERM_3OP_MASKZ:
case VPERM_3OP_MASK:{
+ MVT VT = Op.getSimpleValueType();
// Src2 is the PassThru
SDValue Src1 = Op.getOperand(1);
- SDValue Src2 = Op.getOperand(2);
+ // PassThru needs to be the same type as the destination in order
+ // to pattern match correctly.
+ SDValue Src2 = DAG.getBitcast(VT, Op.getOperand(2));
SDValue Src3 = Op.getOperand(3);
SDValue Mask = Op.getOperand(4);
- MVT VT = Op.getSimpleValueType();
SDValue PassThru = SDValue();
// set PassThru element
if (IntrData->Type == VPERM_3OP_MASKZ)
PassThru = getZeroVector(VT, Subtarget, DAG, dl);
else
- PassThru = DAG.getBitcast(VT, Src2);
+ PassThru = Src2;
// Swap Src1 and Src2 in the node creation
return getVectorMaskingNode(DAG.getNode(IntrData->Opc0,
@@ -17660,8 +19039,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
unsigned IntrWithRoundingModeOpcode = IntrData->Opc1;
if (IntrWithRoundingModeOpcode != 0) {
SDValue Rnd = Op.getOperand(5);
- if (cast<ConstantSDNode>(Rnd)->getZExtValue() !=
- X86::STATIC_ROUNDING::CUR_DIRECTION)
+ if (!isRoundModeCurDirection(Rnd))
return getVectorMaskingNode(DAG.getNode(IntrWithRoundingModeOpcode,
dl, Op.getValueType(),
Src1, Src2, Src3, Rnd),
@@ -17713,6 +19091,35 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
Src1, Src2, Src3, Src4),
Mask, PassThru, Subtarget, DAG);
}
+ case CVTPD2PS:
+ // ISD::FP_ROUND has a second argument that indicates if the truncation
+ // does not change the value. Set it to 0 since it can change.
+ return DAG.getNode(IntrData->Opc0, dl, VT, Op.getOperand(1),
+ DAG.getIntPtrConstant(0, dl));
+ case CVTPD2PS_MASK: {
+ SDValue Src = Op.getOperand(1);
+ SDValue PassThru = Op.getOperand(2);
+ SDValue Mask = Op.getOperand(3);
+ // We add rounding mode to the Node when
+ // - RM Opcode is specified and
+ // - RM is not "current direction".
+ unsigned IntrWithRoundingModeOpcode = IntrData->Opc1;
+ if (IntrWithRoundingModeOpcode != 0) {
+ SDValue Rnd = Op.getOperand(4);
+ if (!isRoundModeCurDirection(Rnd)) {
+ return getVectorMaskingNode(DAG.getNode(IntrWithRoundingModeOpcode,
+ dl, Op.getValueType(),
+ Src, Rnd),
+ Mask, PassThru, Subtarget, DAG);
+ }
+ }
+ assert(IntrData->Opc0 == ISD::FP_ROUND && "Unexpected opcode!");
+ // ISD::FP_ROUND has a second argument that indicates if the truncation
+ // does not change the value. Set it to 0 since it can change.
+ return getVectorMaskingNode(DAG.getNode(IntrData->Opc0, dl, VT, Src,
+ DAG.getIntPtrConstant(0, dl)),
+ Mask, PassThru, Subtarget, DAG);
+ }
case FPCLASS: {
// FPclass intrinsics with mask
SDValue Src1 = Op.getOperand(1);
@@ -17738,7 +19145,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SDValue FPclass = DAG.getNode(IntrData->Opc0, dl, MVT::i1, Src1, Imm);
SDValue FPclassMask = getScalarMaskingNode(FPclass, Mask,
DAG.getTargetConstant(0, dl, MVT::i1), Subtarget, DAG);
- return DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::i8, FPclassMask);
+ return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i8, FPclassMask);
}
case CMP_MASK:
case CMP_MASK_CC: {
@@ -17765,8 +19172,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
// (IntrData->Opc1 != 0), then we check the rounding mode operand.
if (IntrData->Opc1 != 0) {
SDValue Rnd = Op.getOperand(5);
- if (cast<ConstantSDNode>(Rnd)->getZExtValue() !=
- X86::STATIC_ROUNDING::CUR_DIRECTION)
+ if (!isRoundModeCurDirection(Rnd))
Cmp = DAG.getNode(IntrData->Opc1, dl, MaskVT, Op.getOperand(1),
Op.getOperand(2), CC, Rnd);
}
@@ -17798,8 +19204,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SDValue Cmp;
if (IntrData->Opc1 != 0) {
SDValue Rnd = Op.getOperand(5);
- if (cast<ConstantSDNode>(Rnd)->getZExtValue() !=
- X86::STATIC_ROUNDING::CUR_DIRECTION)
+ if (!isRoundModeCurDirection(Rnd))
Cmp = DAG.getNode(IntrData->Opc1, dl, MVT::i1, Src1, Src2, CC, Rnd);
}
//default rounding mode
@@ -17822,39 +19227,29 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SDValue SetCC;
switch (CC) {
case ISD::SETEQ: { // (ZF = 0 and PF = 0)
- SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_E, dl, MVT::i8), Comi);
- SDValue SetNP = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_NP, dl, MVT::i8),
- Comi);
+ SetCC = getSETCC(X86::COND_E, Comi, dl, DAG);
+ SDValue SetNP = getSETCC(X86::COND_NP, Comi, dl, DAG);
SetCC = DAG.getNode(ISD::AND, dl, MVT::i8, SetCC, SetNP);
break;
}
case ISD::SETNE: { // (ZF = 1 or PF = 1)
- SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_NE, dl, MVT::i8), Comi);
- SDValue SetP = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_P, dl, MVT::i8),
- Comi);
+ SetCC = getSETCC(X86::COND_NE, Comi, dl, DAG);
+ SDValue SetP = getSETCC(X86::COND_P, Comi, dl, DAG);
SetCC = DAG.getNode(ISD::OR, dl, MVT::i8, SetCC, SetP);
break;
}
case ISD::SETGT: // (CF = 0 and ZF = 0)
- SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_A, dl, MVT::i8), Comi);
+ SetCC = getSETCC(X86::COND_A, Comi, dl, DAG);
break;
case ISD::SETLT: { // The condition is opposite to GT. Swap the operands.
- SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_A, dl, MVT::i8), InvComi);
+ SetCC = getSETCC(X86::COND_A, InvComi, dl, DAG);
break;
}
case ISD::SETGE: // CF = 0
- SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_AE, dl, MVT::i8), Comi);
+ SetCC = getSETCC(X86::COND_AE, Comi, dl, DAG);
break;
case ISD::SETLE: // The condition is opposite to GE. Swap the operands.
- SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_AE, dl, MVT::i8), InvComi);
+ SetCC = getSETCC(X86::COND_AE, InvComi, dl, DAG);
break;
default:
llvm_unreachable("Unexpected illegal condition!");
@@ -17868,19 +19263,19 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SDValue Sae = Op.getOperand(4);
SDValue FCmp;
- if (cast<ConstantSDNode>(Sae)->getZExtValue() ==
- X86::STATIC_ROUNDING::CUR_DIRECTION)
- FCmp = DAG.getNode(X86ISD::FSETCC, dl, MVT::i1, LHS, RHS,
+ if (isRoundModeCurDirection(Sae))
+ FCmp = DAG.getNode(X86ISD::FSETCCM, dl, MVT::i1, LHS, RHS,
DAG.getConstant(CondVal, dl, MVT::i8));
else
- FCmp = DAG.getNode(X86ISD::FSETCC, dl, MVT::i1, LHS, RHS,
+ FCmp = DAG.getNode(X86ISD::FSETCCM_RND, dl, MVT::i1, LHS, RHS,
DAG.getConstant(CondVal, dl, MVT::i8), Sae);
// AnyExt just uses KMOVW %kreg, %r32; ZeroExt emits "and $1, %reg"
return DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i32, FCmp);
}
case VSHIFT:
return getTargetVShiftNode(IntrData->Opc0, dl, Op.getSimpleValueType(),
- Op.getOperand(1), Op.getOperand(2), DAG);
+ Op.getOperand(1), Op.getOperand(2), Subtarget,
+ DAG);
case COMPRESS_EXPAND_IN_REG: {
SDValue Mask = Op.getOperand(3);
SDValue DataToCompress = Op.getOperand(1);
@@ -18027,14 +19422,15 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
case Intrinsic::x86_avx_vtestc_pd_256:
case Intrinsic::x86_avx_vtestnzc_pd_256: {
bool IsTestPacked = false;
- unsigned X86CC;
+ X86::CondCode X86CC;
switch (IntNo) {
default: llvm_unreachable("Bad fallthrough in Intrinsic lowering.");
case Intrinsic::x86_avx_vtestz_ps:
case Intrinsic::x86_avx_vtestz_pd:
case Intrinsic::x86_avx_vtestz_ps_256:
case Intrinsic::x86_avx_vtestz_pd_256:
- IsTestPacked = true; // Fallthrough
+ IsTestPacked = true;
+ LLVM_FALLTHROUGH;
case Intrinsic::x86_sse41_ptestz:
case Intrinsic::x86_avx_ptestz_256:
// ZF = 1
@@ -18044,7 +19440,8 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
case Intrinsic::x86_avx_vtestc_pd:
case Intrinsic::x86_avx_vtestc_ps_256:
case Intrinsic::x86_avx_vtestc_pd_256:
- IsTestPacked = true; // Fallthrough
+ IsTestPacked = true;
+ LLVM_FALLTHROUGH;
case Intrinsic::x86_sse41_ptestc:
case Intrinsic::x86_avx_ptestc_256:
// CF = 1
@@ -18054,7 +19451,8 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
case Intrinsic::x86_avx_vtestnzc_pd:
case Intrinsic::x86_avx_vtestnzc_ps_256:
case Intrinsic::x86_avx_vtestnzc_pd_256:
- IsTestPacked = true; // Fallthrough
+ IsTestPacked = true;
+ LLVM_FALLTHROUGH;
case Intrinsic::x86_sse41_ptestnzc:
case Intrinsic::x86_avx_ptestnzc_256:
// ZF and CF = 0
@@ -18066,18 +19464,17 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SDValue RHS = Op.getOperand(2);
unsigned TestOpc = IsTestPacked ? X86ISD::TESTP : X86ISD::PTEST;
SDValue Test = DAG.getNode(TestOpc, dl, MVT::i32, LHS, RHS);
- SDValue CC = DAG.getConstant(X86CC, dl, MVT::i8);
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8, CC, Test);
+ SDValue SetCC = getSETCC(X86CC, Test, dl, DAG);
return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, SetCC);
}
case Intrinsic::x86_avx512_kortestz_w:
case Intrinsic::x86_avx512_kortestc_w: {
- unsigned X86CC = (IntNo == Intrinsic::x86_avx512_kortestz_w)? X86::COND_E: X86::COND_B;
+ X86::CondCode X86CC =
+ (IntNo == Intrinsic::x86_avx512_kortestz_w) ? X86::COND_E : X86::COND_B;
SDValue LHS = DAG.getBitcast(MVT::v16i1, Op.getOperand(1));
SDValue RHS = DAG.getBitcast(MVT::v16i1, Op.getOperand(2));
- SDValue CC = DAG.getConstant(X86CC, dl, MVT::i8);
SDValue Test = DAG.getNode(X86ISD::KORTEST, dl, MVT::i32, LHS, RHS);
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8, CC, Test);
+ SDValue SetCC = getSETCC(X86CC, Test, dl, DAG);
return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, SetCC);
}
@@ -18092,7 +19489,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
case Intrinsic::x86_sse42_pcmpistriz128:
case Intrinsic::x86_sse42_pcmpestriz128: {
unsigned Opcode;
- unsigned X86CC;
+ X86::CondCode X86CC;
switch (IntNo) {
default: llvm_unreachable("Impossible intrinsic"); // Can't reach here.
case Intrinsic::x86_sse42_pcmpistria128:
@@ -18139,9 +19536,7 @@ static SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, const X86Subtarget &Subtarget
SmallVector<SDValue, 5> NewOps(Op->op_begin()+1, Op->op_end());
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::i32);
SDValue PCMP = DAG.getNode(Opcode, dl, VTs, NewOps);
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86CC, dl, MVT::i8),
- SDValue(PCMP.getNode(), 1));
+ SDValue SetCC = getSETCC(X86CC, SDValue(PCMP.getNode(), 1), dl, DAG);
return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, SetCC);
}
@@ -18267,6 +19662,51 @@ static SDValue getPrefetchNode(unsigned Opc, SDValue Op, SelectionDAG &DAG,
return SDValue(Res, 0);
}
+/// Handles the lowering of builtin intrinsic that return the value
+/// of the extended control register.
+static void getExtendedControlRegister(SDNode *N, const SDLoc &DL,
+ SelectionDAG &DAG,
+ const X86Subtarget &Subtarget,
+ SmallVectorImpl<SDValue> &Results) {
+ assert(N->getNumOperands() == 3 && "Unexpected number of operands!");
+ SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Glue);
+ SDValue LO, HI;
+
+ // The ECX register is used to select the index of the XCR register to
+ // return.
+ SDValue Chain =
+ DAG.getCopyToReg(N->getOperand(0), DL, X86::ECX, N->getOperand(2));
+ SDNode *N1 = DAG.getMachineNode(X86::XGETBV, DL, Tys, Chain);
+ Chain = SDValue(N1, 0);
+
+ // Reads the content of XCR and returns it in registers EDX:EAX.
+ if (Subtarget.is64Bit()) {
+ LO = DAG.getCopyFromReg(Chain, DL, X86::RAX, MVT::i64, SDValue(N1, 1));
+ HI = DAG.getCopyFromReg(LO.getValue(1), DL, X86::RDX, MVT::i64,
+ LO.getValue(2));
+ } else {
+ LO = DAG.getCopyFromReg(Chain, DL, X86::EAX, MVT::i32, SDValue(N1, 1));
+ HI = DAG.getCopyFromReg(LO.getValue(1), DL, X86::EDX, MVT::i32,
+ LO.getValue(2));
+ }
+ Chain = HI.getValue(1);
+
+ if (Subtarget.is64Bit()) {
+ // Merge the two 32-bit values into a 64-bit one..
+ SDValue Tmp = DAG.getNode(ISD::SHL, DL, MVT::i64, HI,
+ DAG.getConstant(32, DL, MVT::i8));
+ Results.push_back(DAG.getNode(ISD::OR, DL, MVT::i64, LO, Tmp));
+ Results.push_back(Chain);
+ return;
+ }
+
+ // Use a buildpair to merge the two 32-bit values into a 64-bit one.
+ SDValue Ops[] = { LO, HI };
+ SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Ops);
+ Results.push_back(Pair);
+ Results.push_back(Chain);
+}
+
/// Handles the lowering of builtin intrinsics that read performance monitor
/// counters (x86_rdpmc).
static void getReadPerformanceCounter(SDNode *N, const SDLoc &DL,
@@ -18413,6 +19853,33 @@ static SDValue MarkEHGuard(SDValue Op, SelectionDAG &DAG) {
return Chain;
}
+/// Emit Truncating Store with signed or unsigned saturation.
+static SDValue
+EmitTruncSStore(bool SignedSat, SDValue Chain, const SDLoc &Dl, SDValue Val,
+ SDValue Ptr, EVT MemVT, MachineMemOperand *MMO,
+ SelectionDAG &DAG) {
+
+ SDVTList VTs = DAG.getVTList(MVT::Other);
+ SDValue Undef = DAG.getUNDEF(Ptr.getValueType());
+ SDValue Ops[] = { Chain, Val, Ptr, Undef };
+ return SignedSat ?
+ DAG.getTargetMemSDNode<TruncSStoreSDNode>(VTs, Ops, Dl, MemVT, MMO) :
+ DAG.getTargetMemSDNode<TruncUSStoreSDNode>(VTs, Ops, Dl, MemVT, MMO);
+}
+
+/// Emit Masked Truncating Store with signed or unsigned saturation.
+static SDValue
+EmitMaskedTruncSStore(bool SignedSat, SDValue Chain, const SDLoc &Dl,
+ SDValue Val, SDValue Ptr, SDValue Mask, EVT MemVT,
+ MachineMemOperand *MMO, SelectionDAG &DAG) {
+
+ SDVTList VTs = DAG.getVTList(MVT::Other);
+ SDValue Ops[] = { Chain, Ptr, Mask, Val };
+ return SignedSat ?
+ DAG.getTargetMemSDNode<MaskedTruncSStoreSDNode>(VTs, Ops, Dl, MemVT, MMO) :
+ DAG.getTargetMemSDNode<MaskedTruncUSStoreSDNode>(VTs, Ops, Dl, MemVT, MMO);
+}
+
static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
@@ -18429,8 +19896,8 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
IntNo == llvm::Intrinsic::x86_flags_write_u64) {
// We need a frame pointer because this will get lowered to a PUSH/POP
// sequence.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setHasCopyImplyingStackAdjustment(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setHasCopyImplyingStackAdjustment(true);
// Don't do anything here, we will expand these intrinsics out later
// during ExpandISelPseudos in EmitInstrWithCustomInserter.
return SDValue();
@@ -18509,13 +19976,18 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
getReadPerformanceCounter(Op.getNode(), dl, DAG, Subtarget, Results);
return DAG.getMergeValues(Results, dl);
}
+ // Get Extended Control Register.
+ case XGETBV: {
+ SmallVector<SDValue, 2> Results;
+ getExtendedControlRegister(Op.getNode(), dl, DAG, Subtarget, Results);
+ return DAG.getMergeValues(Results, dl);
+ }
// XTEST intrinsics.
case XTEST: {
SDVTList VTs = DAG.getVTList(Op->getValueType(0), MVT::Other);
SDValue InTrans = DAG.getNode(IntrData->Opc0, dl, VTs, Op.getOperand(0));
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_NE, dl, MVT::i8),
- InTrans);
+
+ SDValue SetCC = getSETCC(X86::COND_NE, InTrans, dl, DAG);
SDValue Ret = DAG.getNode(ISD::ZERO_EXTEND, dl, Op->getValueType(0), SetCC);
return DAG.getNode(ISD::MERGE_VALUES, dl, Op->getVTList(),
Ret, SDValue(InTrans.getNode(), 1));
@@ -18530,9 +20002,7 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
Op.getOperand(4), GenCF.getValue(1));
SDValue Store = DAG.getStore(Op.getOperand(0), dl, Res.getValue(0),
Op.getOperand(5), MachinePointerInfo());
- SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_B, dl, MVT::i8),
- Res.getValue(1));
+ SDValue SetCC = getSETCC(X86::COND_B, Res.getValue(1), dl, DAG);
SDValue Results[] = { SetCC, Store };
return DAG.getMergeValues(Results, dl);
}
@@ -18550,11 +20020,12 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
return DAG.getStore(Chain, dl, DataToCompress, Addr,
MemIntr->getMemOperand());
- SDValue Compressed =
- getVectorMaskingNode(DAG.getNode(IntrData->Opc0, dl, VT, DataToCompress),
- Mask, DAG.getUNDEF(VT), Subtarget, DAG);
- return DAG.getStore(Chain, dl, Compressed, Addr,
- MemIntr->getMemOperand());
+ MVT MaskVT = MVT::getVectorVT(MVT::i1, VT.getVectorNumElements());
+ SDValue VMask = getMaskNode(Mask, MaskVT, Subtarget, DAG, dl);
+
+ return DAG.getMaskedStore(Chain, dl, DataToCompress, Addr, VMask, VT,
+ MemIntr->getMemOperand(),
+ false /* truncating */, true /* compressing */);
}
case TRUNCATE_TO_MEM_VI8:
case TRUNCATE_TO_MEM_VI16:
@@ -18567,18 +20038,39 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
MemIntrinsicSDNode *MemIntr = dyn_cast<MemIntrinsicSDNode>(Op);
assert(MemIntr && "Expected MemIntrinsicSDNode!");
- EVT VT = MemIntr->getMemoryVT();
+ EVT MemVT = MemIntr->getMemoryVT();
- if (isAllOnesConstant(Mask)) // return just a truncate store
- return DAG.getTruncStore(Chain, dl, DataToTruncate, Addr, VT,
- MemIntr->getMemOperand());
+ uint16_t TruncationOp = IntrData->Opc0;
+ switch (TruncationOp) {
+ case X86ISD::VTRUNC: {
+ if (isAllOnesConstant(Mask)) // return just a truncate store
+ return DAG.getTruncStore(Chain, dl, DataToTruncate, Addr, MemVT,
+ MemIntr->getMemOperand());
- MVT MaskVT = MVT::getVectorVT(MVT::i1, VT.getVectorNumElements());
- SDValue VMask = getMaskNode(Mask, MaskVT, Subtarget, DAG, dl);
+ MVT MaskVT = MVT::getVectorVT(MVT::i1, MemVT.getVectorNumElements());
+ SDValue VMask = getMaskNode(Mask, MaskVT, Subtarget, DAG, dl);
- return DAG.getMaskedStore(Chain, dl, DataToTruncate, Addr, VMask, VT,
- MemIntr->getMemOperand(), true);
+ return DAG.getMaskedStore(Chain, dl, DataToTruncate, Addr, VMask, MemVT,
+ MemIntr->getMemOperand(), true /* truncating */);
+ }
+ case X86ISD::VTRUNCUS:
+ case X86ISD::VTRUNCS: {
+ bool IsSigned = (TruncationOp == X86ISD::VTRUNCS);
+ if (isAllOnesConstant(Mask))
+ return EmitTruncSStore(IsSigned, Chain, dl, DataToTruncate, Addr, MemVT,
+ MemIntr->getMemOperand(), DAG);
+
+ MVT MaskVT = MVT::getVectorVT(MVT::i1, MemVT.getVectorNumElements());
+ SDValue VMask = getMaskNode(Mask, MaskVT, Subtarget, DAG, dl);
+
+ return EmitMaskedTruncSStore(IsSigned, Chain, dl, DataToTruncate, Addr,
+ VMask, MemVT, MemIntr->getMemOperand(), DAG);
+ }
+ default:
+ llvm_unreachable("Unsupported truncstore intrinsic");
+ }
}
+
case EXPAND_FROM_MEM: {
SDValue Mask = Op.getOperand(4);
SDValue PassThru = Op.getOperand(3);
@@ -18589,24 +20081,24 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
MemIntrinsicSDNode *MemIntr = dyn_cast<MemIntrinsicSDNode>(Op);
assert(MemIntr && "Expected MemIntrinsicSDNode!");
- SDValue DataToExpand = DAG.getLoad(VT, dl, Chain, Addr,
- MemIntr->getMemOperand());
+ if (isAllOnesConstant(Mask)) // Return a regular (unmasked) vector load.
+ return DAG.getLoad(VT, dl, Chain, Addr, MemIntr->getMemOperand());
+ if (X86::isZeroNode(Mask))
+ return DAG.getUNDEF(VT);
- if (isAllOnesConstant(Mask)) // return just a load
- return DataToExpand;
-
- SDValue Results[] = {
- getVectorMaskingNode(DAG.getNode(IntrData->Opc0, dl, VT, DataToExpand),
- Mask, PassThru, Subtarget, DAG), Chain};
- return DAG.getMergeValues(Results, dl);
+ MVT MaskVT = MVT::getVectorVT(MVT::i1, VT.getVectorNumElements());
+ SDValue VMask = getMaskNode(Mask, MaskVT, Subtarget, DAG, dl);
+ return DAG.getMaskedLoad(VT, dl, Chain, Addr, VMask, PassThru, VT,
+ MemIntr->getMemOperand(), ISD::NON_EXTLOAD,
+ true /* expanding */);
}
}
}
SDValue X86TargetLowering::LowerRETURNADDR(SDValue Op,
SelectionDAG &DAG) const {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setReturnAddressIsTaken(true);
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setReturnAddressIsTaken(true);
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
return SDValue();
@@ -18630,14 +20122,20 @@ SDValue X86TargetLowering::LowerRETURNADDR(SDValue Op,
MachinePointerInfo());
}
+SDValue X86TargetLowering::LowerADDROFRETURNADDR(SDValue Op,
+ SelectionDAG &DAG) const {
+ DAG.getMachineFunction().getFrameInfo().setReturnAddressIsTaken(true);
+ return getReturnAddressFrameIndex(DAG);
+}
+
SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
X86MachineFunctionInfo *FuncInfo = MF.getInfo<X86MachineFunctionInfo>();
const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
EVT VT = Op.getValueType();
- MFI->setFrameAddressIsTaken(true);
+ MFI.setFrameAddressIsTaken(true);
if (MF.getTarget().getMCAsmInfo()->usesWindowsCFI()) {
// Depth > 0 makes no sense on targets which use Windows unwind codes. It
@@ -18647,7 +20145,7 @@ SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
if (!FrameAddrIndex) {
// Set up a frame object for the return address.
unsigned SlotSize = RegInfo->getSlotSize();
- FrameAddrIndex = MF.getFrameInfo()->CreateFixedObject(
+ FrameAddrIndex = MF.getFrameInfo().CreateFixedObject(
SlotSize, /*Offset=*/0, /*IsImmutable=*/false);
FuncInfo->setFAIndex(FrameAddrIndex);
}
@@ -18965,7 +20463,7 @@ SDValue X86TargetLowering::LowerFLT_ROUNDS_(SDValue Op,
SDLoc DL(Op);
// Save FP Control Word to stack slot
- int SSFI = MF.getFrameInfo()->CreateStackObject(2, StackAlignment, false);
+ int SSFI = MF.getFrameInfo().CreateStackObject(2, StackAlignment, false);
SDValue StackSlot =
DAG.getFrameIndex(SSFI, getPointerTy(DAG.getDataLayout()));
@@ -19083,7 +20581,7 @@ static SDValue LowerVectorCTLZInRegLUT(SDValue Op, const SDLoc &DL,
SmallVector<SDValue, 64> LUTVec;
for (int i = 0; i < NumBytes; ++i)
LUTVec.push_back(DAG.getConstant(LUT[i % 16], DL, MVT::i8));
- SDValue InRegLUT = DAG.getNode(ISD::BUILD_VECTOR, DL, CurrVT, LUTVec);
+ SDValue InRegLUT = DAG.getBuildVector(CurrVT, DL, LUTVec);
// Begin by bitcasting the input to byte vector, then split those bytes
// into lo/hi nibbles and use the PSHUFB LUT to perform CLTZ on each of them.
@@ -19444,43 +20942,63 @@ static SDValue LowerMUL(SDValue Op, const X86Subtarget &Subtarget,
assert((VT == MVT::v2i64 || VT == MVT::v4i64 || VT == MVT::v8i64) &&
"Only know how to lower V2I64/V4I64/V8I64 multiply");
+ // 32-bit vector types used for MULDQ/MULUDQ.
+ MVT MulVT = MVT::getVectorVT(MVT::i32, VT.getSizeInBits() / 32);
+
+ // MULDQ returns the 64-bit result of the signed multiplication of the lower
+ // 32-bits. We can lower with this if the sign bits stretch that far.
+ if (Subtarget.hasSSE41() && DAG.ComputeNumSignBits(A) > 32 &&
+ DAG.ComputeNumSignBits(B) > 32) {
+ return DAG.getNode(X86ISD::PMULDQ, dl, VT, DAG.getBitcast(MulVT, A),
+ DAG.getBitcast(MulVT, B));
+ }
+
// Ahi = psrlqi(a, 32);
// Bhi = psrlqi(b, 32);
//
// AloBlo = pmuludq(a, b);
// AloBhi = pmuludq(a, Bhi);
// AhiBlo = pmuludq(Ahi, b);
+ //
+ // Hi = psllqi(AloBhi + AhiBlo, 32);
+ // return AloBlo + Hi;
+ APInt LowerBitsMask = APInt::getLowBitsSet(64, 32);
+ bool ALoIsZero = DAG.MaskedValueIsZero(A, LowerBitsMask);
+ bool BLoIsZero = DAG.MaskedValueIsZero(B, LowerBitsMask);
+
+ APInt UpperBitsMask = APInt::getHighBitsSet(64, 32);
+ bool AHiIsZero = DAG.MaskedValueIsZero(A, UpperBitsMask);
+ bool BHiIsZero = DAG.MaskedValueIsZero(B, UpperBitsMask);
- // AloBhi = psllqi(AloBhi, 32);
- // AhiBlo = psllqi(AhiBlo, 32);
- // return AloBlo + AloBhi + AhiBlo;
+ // Bit cast to 32-bit vectors for MULUDQ.
+ SDValue Alo = DAG.getBitcast(MulVT, A);
+ SDValue Blo = DAG.getBitcast(MulVT, B);
- SDValue Ahi = getTargetVShiftByConstNode(X86ISD::VSRLI, dl, VT, A, 32, DAG);
- SDValue Bhi = getTargetVShiftByConstNode(X86ISD::VSRLI, dl, VT, B, 32, DAG);
+ SDValue Zero = getZeroVector(VT, Subtarget, DAG, dl);
- SDValue AhiBlo = Ahi;
- SDValue AloBhi = Bhi;
- // Bit cast to 32-bit vectors for MULUDQ
- MVT MulVT = (VT == MVT::v2i64) ? MVT::v4i32 :
- (VT == MVT::v4i64) ? MVT::v8i32 : MVT::v16i32;
- A = DAG.getBitcast(MulVT, A);
- B = DAG.getBitcast(MulVT, B);
- Ahi = DAG.getBitcast(MulVT, Ahi);
- Bhi = DAG.getBitcast(MulVT, Bhi);
+ // Only multiply lo/hi halves that aren't known to be zero.
+ SDValue AloBlo = Zero;
+ if (!ALoIsZero && !BLoIsZero)
+ AloBlo = DAG.getNode(X86ISD::PMULUDQ, dl, VT, Alo, Blo);
- SDValue AloBlo = DAG.getNode(X86ISD::PMULUDQ, dl, VT, A, B);
- // After shifting right const values the result may be all-zero.
- if (!ISD::isBuildVectorAllZeros(Ahi.getNode())) {
- AhiBlo = DAG.getNode(X86ISD::PMULUDQ, dl, VT, Ahi, B);
- AhiBlo = getTargetVShiftByConstNode(X86ISD::VSHLI, dl, VT, AhiBlo, 32, DAG);
+ SDValue AloBhi = Zero;
+ if (!ALoIsZero && !BHiIsZero) {
+ SDValue Bhi = getTargetVShiftByConstNode(X86ISD::VSRLI, dl, VT, B, 32, DAG);
+ Bhi = DAG.getBitcast(MulVT, Bhi);
+ AloBhi = DAG.getNode(X86ISD::PMULUDQ, dl, VT, Alo, Bhi);
}
- if (!ISD::isBuildVectorAllZeros(Bhi.getNode())) {
- AloBhi = DAG.getNode(X86ISD::PMULUDQ, dl, VT, A, Bhi);
- AloBhi = getTargetVShiftByConstNode(X86ISD::VSHLI, dl, VT, AloBhi, 32, DAG);
+
+ SDValue AhiBlo = Zero;
+ if (!AHiIsZero && !BLoIsZero) {
+ SDValue Ahi = getTargetVShiftByConstNode(X86ISD::VSRLI, dl, VT, A, 32, DAG);
+ Ahi = DAG.getBitcast(MulVT, Ahi);
+ AhiBlo = DAG.getNode(X86ISD::PMULUDQ, dl, VT, Ahi, Blo);
}
- SDValue Res = DAG.getNode(ISD::ADD, dl, VT, AloBlo, AloBhi);
- return DAG.getNode(ISD::ADD, dl, VT, Res, AhiBlo);
+ SDValue Hi = DAG.getNode(ISD::ADD, dl, VT, AloBhi, AhiBlo);
+ Hi = getTargetVShiftByConstNode(X86ISD::VSHLI, dl, VT, Hi, 32, DAG);
+
+ return DAG.getNode(ISD::ADD, dl, VT, AloBlo, Hi);
}
static SDValue LowerMULH(SDValue Op, const X86Subtarget &Subtarget,
@@ -19905,7 +21423,8 @@ static SDValue LowerScalarImmediateShift(SDValue Op, SelectionDAG &DAG,
// Special case in 32-bit mode, where i64 is expanded into high and low parts.
if (!Subtarget.is64Bit() && !Subtarget.hasXOP() &&
- (VT == MVT::v2i64 || (Subtarget.hasInt256() && VT == MVT::v4i64))) {
+ (VT == MVT::v2i64 || (Subtarget.hasInt256() && VT == MVT::v4i64) ||
+ (Subtarget.hasAVX512() && VT == MVT::v8i64))) {
// Peek through any splat that was introduced for i64 shift vectorization.
int SplatIndex = -1;
@@ -20018,7 +21537,7 @@ static SDValue LowerScalarVariableShift(SDValue Op, SelectionDAG &DAG,
else if (EltVT.bitsLT(MVT::i32))
BaseShAmt = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, BaseShAmt);
- return getTargetVShiftNode(X86OpcI, dl, VT, R, BaseShAmt, DAG);
+ return getTargetVShiftNode(X86OpcI, dl, VT, R, BaseShAmt, Subtarget, DAG);
}
}
@@ -20147,7 +21666,7 @@ static SDValue LowerShift(SDValue Op, const X86Subtarget &Subtarget,
}
// If possible, lower this shift as a sequence of two shifts by
- // constant plus a MOVSS/MOVSD instead of scalarizing it.
+ // constant plus a MOVSS/MOVSD/PBLEND instead of scalarizing it.
// Example:
// (v4i32 (srl A, (build_vector < X, Y, Y, Y>)))
//
@@ -20167,7 +21686,7 @@ static SDValue LowerShift(SDValue Op, const X86Subtarget &Subtarget,
SDValue Amt2 = (VT == MVT::v4i32) ? Amt->getOperand(1) : Amt->getOperand(2);
// See if it is possible to replace this node with a sequence of
- // two shifts followed by a MOVSS/MOVSD
+ // two shifts followed by a MOVSS/MOVSD/PBLEND.
if (VT == MVT::v4i32) {
// Check if it is legal to use a MOVSS.
CanBeSimplified = Amt2 == Amt->getOperand(2) &&
@@ -20199,21 +21718,21 @@ static SDValue LowerShift(SDValue Op, const X86Subtarget &Subtarget,
if (CanBeSimplified && isa<ConstantSDNode>(Amt1) &&
isa<ConstantSDNode>(Amt2)) {
- // Replace this node with two shifts followed by a MOVSS/MOVSD.
+ // Replace this node with two shifts followed by a MOVSS/MOVSD/PBLEND.
MVT CastVT = MVT::v4i32;
SDValue Splat1 =
- DAG.getConstant(cast<ConstantSDNode>(Amt1)->getAPIntValue(), dl, VT);
+ DAG.getConstant(cast<ConstantSDNode>(Amt1)->getAPIntValue(), dl, VT);
SDValue Shift1 = DAG.getNode(Op->getOpcode(), dl, VT, R, Splat1);
SDValue Splat2 =
- DAG.getConstant(cast<ConstantSDNode>(Amt2)->getAPIntValue(), dl, VT);
+ DAG.getConstant(cast<ConstantSDNode>(Amt2)->getAPIntValue(), dl, VT);
SDValue Shift2 = DAG.getNode(Op->getOpcode(), dl, VT, R, Splat2);
- if (TargetOpcode == X86ISD::MOVSD)
- CastVT = MVT::v2i64;
SDValue BitCast1 = DAG.getBitcast(CastVT, Shift1);
SDValue BitCast2 = DAG.getBitcast(CastVT, Shift2);
- SDValue Result = getTargetShuffleNode(TargetOpcode, dl, CastVT, BitCast2,
- BitCast1, DAG);
- return DAG.getBitcast(VT, Result);
+ if (TargetOpcode == X86ISD::MOVSD)
+ return DAG.getBitcast(VT, DAG.getVectorShuffle(CastVT, dl, BitCast1,
+ BitCast2, {0, 1, 6, 7}));
+ return DAG.getBitcast(VT, DAG.getVectorShuffle(CastVT, dl, BitCast1,
+ BitCast2, {0, 5, 6, 7}));
}
}
@@ -20264,15 +21783,44 @@ static SDValue LowerShift(SDValue Op, const X86Subtarget &Subtarget,
return DAG.getVectorShuffle(VT, dl, R02, R13, {0, 5, 2, 7});
}
+ // It's worth extending once and using the vXi16/vXi32 shifts for smaller
+ // types, but without AVX512 the extra overheads to get from vXi8 to vXi32
+ // make the existing SSE solution better.
+ if ((Subtarget.hasInt256() && VT == MVT::v8i16) ||
+ (Subtarget.hasAVX512() && VT == MVT::v16i16) ||
+ (Subtarget.hasAVX512() && VT == MVT::v16i8) ||
+ (Subtarget.hasBWI() && VT == MVT::v32i8)) {
+ MVT EvtSVT = (VT == MVT::v32i8 ? MVT::i16 : MVT::i32);
+ MVT ExtVT = MVT::getVectorVT(EvtSVT, VT.getVectorNumElements());
+ unsigned ExtOpc =
+ Op.getOpcode() == ISD::SRA ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+ R = DAG.getNode(ExtOpc, dl, ExtVT, R);
+ Amt = DAG.getNode(ISD::ANY_EXTEND, dl, ExtVT, Amt);
+ return DAG.getNode(ISD::TRUNCATE, dl, VT,
+ DAG.getNode(Op.getOpcode(), dl, ExtVT, R, Amt));
+ }
+
if (VT == MVT::v16i8 ||
- (VT == MVT::v32i8 && Subtarget.hasInt256() && !Subtarget.hasXOP())) {
+ (VT == MVT::v32i8 && Subtarget.hasInt256() && !Subtarget.hasXOP()) ||
+ (VT == MVT::v64i8 && Subtarget.hasBWI())) {
MVT ExtVT = MVT::getVectorVT(MVT::i16, VT.getVectorNumElements() / 2);
unsigned ShiftOpcode = Op->getOpcode();
auto SignBitSelect = [&](MVT SelVT, SDValue Sel, SDValue V0, SDValue V1) {
- // On SSE41 targets we make use of the fact that VSELECT lowers
- // to PBLENDVB which selects bytes based just on the sign bit.
- if (Subtarget.hasSSE41()) {
+ if (VT.is512BitVector()) {
+ // On AVX512BW targets we make use of the fact that VSELECT lowers
+ // to a masked blend which selects bytes based just on the sign bit
+ // extracted to a mask.
+ MVT MaskVT = MVT::getVectorVT(MVT::i1, VT.getVectorNumElements());
+ V0 = DAG.getBitcast(VT, V0);
+ V1 = DAG.getBitcast(VT, V1);
+ Sel = DAG.getBitcast(VT, Sel);
+ Sel = DAG.getNode(X86ISD::CVT2MASK, dl, MaskVT, Sel);
+ return DAG.getBitcast(SelVT,
+ DAG.getNode(ISD::VSELECT, dl, VT, Sel, V0, V1));
+ } else if (Subtarget.hasSSE41()) {
+ // On SSE41 targets we make use of the fact that VSELECT lowers
+ // to PBLENDVB which selects bytes based just on the sign bit.
V0 = DAG.getBitcast(VT, V0);
V1 = DAG.getBitcast(VT, V1);
Sel = DAG.getBitcast(VT, Sel);
@@ -20372,19 +21920,6 @@ static SDValue LowerShift(SDValue Op, const X86Subtarget &Subtarget,
}
}
- // It's worth extending once and using the v8i32 shifts for 16-bit types, but
- // the extra overheads to get from v16i8 to v8i32 make the existing SSE
- // solution better.
- if (Subtarget.hasInt256() && VT == MVT::v8i16) {
- MVT ExtVT = MVT::v8i32;
- unsigned ExtOpc =
- Op.getOpcode() == ISD::SRA ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
- R = DAG.getNode(ExtOpc, dl, ExtVT, R);
- Amt = DAG.getNode(ISD::ANY_EXTEND, dl, ExtVT, Amt);
- return DAG.getNode(ISD::TRUNCATE, dl, VT,
- DAG.getNode(Op.getOpcode(), dl, ExtVT, R, Amt));
- }
-
if (Subtarget.hasInt256() && !Subtarget.hasXOP() && VT == MVT::v16i16) {
MVT ExtVT = MVT::v8i32;
SDValue Z = getZeroVector(VT, Subtarget, DAG, dl);
@@ -20519,7 +22054,7 @@ static SDValue LowerXALUO(SDValue Op, SelectionDAG &DAG) {
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
unsigned BaseOp = 0;
- unsigned Cond = 0;
+ X86::CondCode Cond;
SDLoc DL(Op);
switch (Op.getOpcode()) {
default: llvm_unreachable("Unknown ovf instruction!");
@@ -20567,16 +22102,11 @@ static SDValue LowerXALUO(SDValue Op, SelectionDAG &DAG) {
MVT::i32);
SDValue Sum = DAG.getNode(X86ISD::UMUL, DL, VTs, LHS, RHS);
- SDValue SetCC =
- DAG.getNode(X86ISD::SETCC, DL, MVT::i8,
- DAG.getConstant(X86::COND_O, DL, MVT::i32),
- SDValue(Sum.getNode(), 2));
+ SDValue SetCC = getSETCC(X86::COND_O, SDValue(Sum.getNode(), 2), DL, DAG);
- if (N->getValueType(1) == MVT::i1) {
- SetCC = DAG.getNode(ISD::AssertZext, DL, MVT::i8, SetCC,
- DAG.getValueType(MVT::i1));
+ if (N->getValueType(1) == MVT::i1)
SetCC = DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, SetCC);
- }
+
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Sum, SetCC);
}
}
@@ -20585,16 +22115,11 @@ static SDValue LowerXALUO(SDValue Op, SelectionDAG &DAG) {
SDVTList VTs = DAG.getVTList(N->getValueType(0), MVT::i32);
SDValue Sum = DAG.getNode(BaseOp, DL, VTs, LHS, RHS);
- SDValue SetCC =
- DAG.getNode(X86ISD::SETCC, DL, MVT::i8,
- DAG.getConstant(Cond, DL, MVT::i32),
- SDValue(Sum.getNode(), 1));
+ SDValue SetCC = getSETCC(Cond, SDValue(Sum.getNode(), 1), DL, DAG);
- if (N->getValueType(1) == MVT::i1) {
- SetCC = DAG.getNode(ISD::AssertZext, DL, MVT::i8, SetCC,
- DAG.getValueType(MVT::i1));
+ if (N->getValueType(1) == MVT::i1)
SetCC = DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, SetCC);
- }
+
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Sum, SetCC);
}
@@ -20790,9 +22315,7 @@ static SDValue LowerCMP_SWAP(SDValue Op, const X86Subtarget &Subtarget,
DAG.getCopyFromReg(Result.getValue(0), DL, Reg, T, Result.getValue(1));
SDValue EFLAGS = DAG.getCopyFromReg(cpOut.getValue(1), DL, X86::EFLAGS,
MVT::i32, cpOut.getValue(2));
- SDValue Success = DAG.getNode(X86ISD::SETCC, DL, Op->getValueType(1),
- DAG.getConstant(X86::COND_E, DL, MVT::i8),
- EFLAGS);
+ SDValue Success = getSETCC(X86::COND_E, EFLAGS, DL, DAG);
DAG.ReplaceAllUsesOfValueWith(Op.getValue(0), cpOut);
DAG.ReplaceAllUsesOfValueWith(Op.getValue(1), Success);
@@ -20898,8 +22421,9 @@ static SDValue LowerHorizontalByteSum(SDValue V, MVT VT,
// two v2i64 vectors which concatenated are the 4 population counts. We can
// then use PACKUSWB to shrink and concatenate them into a v4i32 again.
SDValue Zeros = getZeroVector(VT, Subtarget, DAG, DL);
- SDValue Low = DAG.getNode(X86ISD::UNPCKL, DL, VT, V, Zeros);
- SDValue High = DAG.getNode(X86ISD::UNPCKH, DL, VT, V, Zeros);
+ SDValue V32 = DAG.getBitcast(VT, V);
+ SDValue Low = DAG.getNode(X86ISD::UNPCKL, DL, VT, V32, Zeros);
+ SDValue High = DAG.getNode(X86ISD::UNPCKH, DL, VT, V32, Zeros);
// Do the horizontal sums into two v2i64s.
Zeros = getZeroVector(ByteVecVT, Subtarget, DAG, DL);
@@ -21054,6 +22578,8 @@ static SDValue LowerVectorCTPOPBitmath(SDValue Op, const SDLoc &DL,
DAG);
}
+// Please ensure that any codegen change from LowerVectorCTPOP is reflected in
+// updated cost models in X86TTIImpl::getIntrinsicInstrCost.
static SDValue LowerVectorCTPOP(SDValue Op, const X86Subtarget &Subtarget,
SelectionDAG &DAG) {
MVT VT = Op.getSimpleValueType();
@@ -21260,8 +22786,7 @@ static SDValue lowerAtomicArith(SDValue N, SelectionDAG &DAG,
AtomicSDNode *AN = cast<AtomicSDNode>(N.getNode());
RHS = DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT), RHS);
return DAG.getAtomic(ISD::ATOMIC_LOAD_ADD, DL, VT, Chain, LHS,
- RHS, AN->getMemOperand(), AN->getOrdering(),
- AN->getSynchScope());
+ RHS, AN->getMemOperand());
}
assert(Opc == ISD::ATOMIC_LOAD_ADD &&
"Used AtomicRMW ops other than Add should have been expanded!");
@@ -21292,9 +22817,7 @@ static SDValue LowerATOMIC_STORE(SDValue Op, SelectionDAG &DAG) {
cast<AtomicSDNode>(Node)->getMemoryVT(),
Node->getOperand(0),
Node->getOperand(1), Node->getOperand(2),
- cast<AtomicSDNode>(Node)->getMemOperand(),
- cast<AtomicSDNode>(Node)->getOrdering(),
- cast<AtomicSDNode>(Node)->getSynchScope());
+ cast<AtomicSDNode>(Node)->getMemOperand());
return Swap.getValue(1);
}
// Other atomic stores have a simple pattern.
@@ -21534,26 +23057,48 @@ static SDValue LowerMLOAD(SDValue Op, const X86Subtarget &Subtarget,
SDValue Mask = N->getMask();
SDLoc dl(Op);
+ assert((!N->isExpandingLoad() || Subtarget.hasAVX512()) &&
+ "Expanding masked load is supported on AVX-512 target only!");
+
+ assert((!N->isExpandingLoad() || ScalarVT.getSizeInBits() >= 32) &&
+ "Expanding masked load is supported for 32 and 64-bit types only!");
+
+ // 4x32, 4x64 and 2x64 vectors of non-expanding loads are legal regardless of
+ // VLX. These types for exp-loads are handled here.
+ if (!N->isExpandingLoad() && VT.getVectorNumElements() <= 4)
+ return Op;
+
assert(Subtarget.hasAVX512() && !Subtarget.hasVLX() && !VT.is512BitVector() &&
"Cannot lower masked load op.");
- assert(((ScalarVT == MVT::i32 || ScalarVT == MVT::f32) ||
+ assert((ScalarVT.getSizeInBits() >= 32 ||
(Subtarget.hasBWI() &&
(ScalarVT == MVT::i8 || ScalarVT == MVT::i16))) &&
"Unsupported masked load op.");
// This operation is legal for targets with VLX, but without
// VLX the vector should be widened to 512 bit
- unsigned NumEltsInWideVec = 512/VT.getScalarSizeInBits();
+ unsigned NumEltsInWideVec = 512 / VT.getScalarSizeInBits();
MVT WideDataVT = MVT::getVectorVT(ScalarVT, NumEltsInWideVec);
- MVT WideMaskVT = MVT::getVectorVT(MVT::i1, NumEltsInWideVec);
SDValue Src0 = N->getSrc0();
Src0 = ExtendToType(Src0, WideDataVT, DAG);
+
+ // Mask element has to be i1.
+ MVT MaskEltTy = Mask.getSimpleValueType().getScalarType();
+ assert((MaskEltTy == MVT::i1 || VT.getVectorNumElements() <= 4) &&
+ "We handle 4x32, 4x64 and 2x64 vectors only in this casse");
+
+ MVT WideMaskVT = MVT::getVectorVT(MaskEltTy, NumEltsInWideVec);
+
Mask = ExtendToType(Mask, WideMaskVT, DAG, true);
+ if (MaskEltTy != MVT::i1)
+ Mask = DAG.getNode(ISD::TRUNCATE, dl,
+ MVT::getVectorVT(MVT::i1, NumEltsInWideVec), Mask);
SDValue NewLoad = DAG.getMaskedLoad(WideDataVT, dl, N->getChain(),
N->getBasePtr(), Mask, Src0,
N->getMemoryVT(), N->getMemOperand(),
- N->getExtensionType());
+ N->getExtensionType(),
+ N->isExpandingLoad());
SDValue Exract = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT,
NewLoad.getValue(0),
@@ -21571,10 +23116,20 @@ static SDValue LowerMSTORE(SDValue Op, const X86Subtarget &Subtarget,
SDValue Mask = N->getMask();
SDLoc dl(Op);
+ assert((!N->isCompressingStore() || Subtarget.hasAVX512()) &&
+ "Expanding masked load is supported on AVX-512 target only!");
+
+ assert((!N->isCompressingStore() || ScalarVT.getSizeInBits() >= 32) &&
+ "Expanding masked load is supported for 32 and 64-bit types only!");
+
+ // 4x32 and 2x64 vectors of non-compressing stores are legal regardless to VLX.
+ if (!N->isCompressingStore() && VT.getVectorNumElements() <= 4)
+ return Op;
+
assert(Subtarget.hasAVX512() && !Subtarget.hasVLX() && !VT.is512BitVector() &&
"Cannot lower masked store op.");
- assert(((ScalarVT == MVT::i32 || ScalarVT == MVT::f32) ||
+ assert((ScalarVT.getSizeInBits() >= 32 ||
(Subtarget.hasBWI() &&
(ScalarVT == MVT::i8 || ScalarVT == MVT::i16))) &&
"Unsupported masked store op.");
@@ -21583,12 +23138,22 @@ static SDValue LowerMSTORE(SDValue Op, const X86Subtarget &Subtarget,
// VLX the vector should be widened to 512 bit
unsigned NumEltsInWideVec = 512/VT.getScalarSizeInBits();
MVT WideDataVT = MVT::getVectorVT(ScalarVT, NumEltsInWideVec);
- MVT WideMaskVT = MVT::getVectorVT(MVT::i1, NumEltsInWideVec);
+
+ // Mask element has to be i1.
+ MVT MaskEltTy = Mask.getSimpleValueType().getScalarType();
+ assert((MaskEltTy == MVT::i1 || VT.getVectorNumElements() <= 4) &&
+ "We handle 4x32, 4x64 and 2x64 vectors only in this casse");
+
+ MVT WideMaskVT = MVT::getVectorVT(MaskEltTy, NumEltsInWideVec);
+
DataToStore = ExtendToType(DataToStore, WideDataVT, DAG);
Mask = ExtendToType(Mask, WideMaskVT, DAG, true);
+ if (MaskEltTy != MVT::i1)
+ Mask = DAG.getNode(ISD::TRUNCATE, dl,
+ MVT::getVectorVT(MVT::i1, NumEltsInWideVec), Mask);
return DAG.getMaskedStore(N->getChain(), dl, DataToStore, N->getBasePtr(),
Mask, N->getMemoryVT(), N->getMemOperand(),
- N->isTruncatingStore());
+ N->isTruncatingStore(), N->isCompressingStore());
}
static SDValue LowerMGATHER(SDValue Op, const X86Subtarget &Subtarget,
@@ -21734,10 +23299,11 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::ZERO_EXTEND: return LowerZERO_EXTEND(Op, Subtarget, DAG);
case ISD::SIGN_EXTEND: return LowerSIGN_EXTEND(Op, Subtarget, DAG);
case ISD::ANY_EXTEND: return LowerANY_EXTEND(Op, Subtarget, DAG);
+ case ISD::ZERO_EXTEND_VECTOR_INREG:
case ISD::SIGN_EXTEND_VECTOR_INREG:
- return LowerSIGN_EXTEND_VECTOR_INREG(Op, Subtarget, DAG);
- case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
- case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG);
+ return LowerEXTEND_VECTOR_INREG(Op, Subtarget, DAG);
+ case ISD::FP_TO_SINT:
+ case ISD::FP_TO_UINT: return LowerFP_TO_INT(Op, Subtarget, DAG);
case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG);
case ISD::LOAD: return LowerExtendedLoad(Op, Subtarget, DAG);
case ISD::FABS:
@@ -21756,6 +23322,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::INTRINSIC_VOID:
case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, Subtarget, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
+ case ISD::ADDROFRETURNADDR: return LowerADDROFRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
case ISD::FRAME_TO_ARGS_OFFSET:
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
@@ -21830,7 +23397,7 @@ void X86TargetLowering::LowerOperationWrapper(SDNode *N,
// In some cases (LowerSINT_TO_FP for example) Res has more result values
// than original node, chain should be dropped(last value).
for (unsigned I = 0, E = N->getNumValues(); I != E; ++I)
- Results.push_back(Res.getValue(I));
+ Results.push_back(Res.getValue(I));
}
/// Replace a node with an illegal result type with a new node built out of
@@ -21851,9 +23418,9 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
auto InVTSize = InVT.getSizeInBits();
const unsigned RegSize =
(InVTSize > 128) ? ((InVTSize > 256) ? 512 : 256) : 128;
- assert((!Subtarget.hasAVX512() || RegSize < 512) &&
- "512-bit vector requires AVX512");
- assert((!Subtarget.hasAVX2() || RegSize < 256) &&
+ assert((Subtarget.hasBWI() || RegSize < 512) &&
+ "512-bit vector requires AVX512BW");
+ assert((Subtarget.hasAVX2() || RegSize < 256) &&
"256-bit vector requires AVX2");
auto ElemVT = InVT.getVectorElementType();
@@ -21888,13 +23455,6 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
Results.push_back(DAG.getNode(N->getOpcode(), dl, MVT::v4f32, LHS, RHS));
return;
}
- case ISD::SIGN_EXTEND_INREG:
- case ISD::ADDC:
- case ISD::ADDE:
- case ISD::SUBC:
- case ISD::SUBE:
- // We don't want to expand or promote these.
- return;
case ISD::SDIV:
case ISD::UDIV:
case ISD::SREM:
@@ -21909,6 +23469,36 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
case ISD::FP_TO_UINT: {
bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
+ if (N->getValueType(0) == MVT::v2i32) {
+ assert((IsSigned || Subtarget.hasAVX512()) &&
+ "Can only handle signed conversion without AVX512");
+ assert(Subtarget.hasSSE2() && "Requires at least SSE2!");
+ SDValue Src = N->getOperand(0);
+ if (Src.getValueType() == MVT::v2f64) {
+ SDValue Idx = DAG.getIntPtrConstant(0, dl);
+ SDValue Res = DAG.getNode(IsSigned ? X86ISD::CVTTP2SI
+ : X86ISD::CVTTP2UI,
+ dl, MVT::v4i32, Src);
+ Res = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v2i32, Res, Idx);
+ Results.push_back(Res);
+ return;
+ }
+ if (Src.getValueType() == MVT::v2f32) {
+ SDValue Idx = DAG.getIntPtrConstant(0, dl);
+ SDValue Res = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v4f32, Src,
+ DAG.getUNDEF(MVT::v2f32));
+ Res = DAG.getNode(IsSigned ? ISD::FP_TO_SINT
+ : ISD::FP_TO_UINT, dl, MVT::v4i32, Res);
+ Res = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v2i32, Res, Idx);
+ Results.push_back(Res);
+ return;
+ }
+
+ // The FP_TO_INTHelper below only handles f32/f64/f80 scalar inputs,
+ // so early out here.
+ return;
+ }
+
std::pair<SDValue,SDValue> Vals =
FP_TO_INTHelper(SDValue(N, 0), DAG, IsSigned, /*IsReplace=*/ true);
SDValue FIST = Vals.first, StackSlot = Vals.second;
@@ -21923,13 +23513,28 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
}
return;
}
+ case ISD::SINT_TO_FP: {
+ assert(Subtarget.hasDQI() && Subtarget.hasVLX() && "Requires AVX512DQVL!");
+ SDValue Src = N->getOperand(0);
+ if (N->getValueType(0) != MVT::v2f32 || Src.getValueType() != MVT::v2i64)
+ return;
+ Results.push_back(DAG.getNode(X86ISD::CVTSI2P, dl, MVT::v4f32, Src));
+ return;
+ }
case ISD::UINT_TO_FP: {
assert(Subtarget.hasSSE2() && "Requires at least SSE2!");
- if (N->getOperand(0).getValueType() != MVT::v2i32 ||
- N->getValueType(0) != MVT::v2f32)
+ EVT VT = N->getValueType(0);
+ if (VT != MVT::v2f32)
return;
- SDValue ZExtIn = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v2i64,
- N->getOperand(0));
+ SDValue Src = N->getOperand(0);
+ EVT SrcVT = Src.getValueType();
+ if (Subtarget.hasDQI() && Subtarget.hasVLX() && SrcVT == MVT::v2i64) {
+ Results.push_back(DAG.getNode(X86ISD::CVTUI2P, dl, MVT::v4f32, Src));
+ return;
+ }
+ if (SrcVT != MVT::v2i32)
+ return;
+ SDValue ZExtIn = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v2i64, Src);
SDValue VBias =
DAG.getConstantFP(BitsToDouble(0x4330000000000000ULL), dl, MVT::v2f64);
SDValue Or = DAG.getNode(ISD::OR, dl, MVT::v2i64, ZExtIn,
@@ -21967,6 +23572,9 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
Results);
case Intrinsic::x86_rdpmc:
return getReadPerformanceCounter(N, dl, DAG, Subtarget, Results);
+
+ case Intrinsic::x86_xgetbv:
+ return getExtendedControlRegister(N, dl, DAG, Subtarget, Results);
}
}
case ISD::INTRINSIC_WO_CHAIN: {
@@ -22052,9 +23660,7 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
SDValue EFLAGS = DAG.getCopyFromReg(cpOutH.getValue(1), dl, X86::EFLAGS,
MVT::i32, cpOutH.getValue(2));
- SDValue Success =
- DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
- DAG.getConstant(X86::COND_E, dl, MVT::i8), EFLAGS);
+ SDValue Success = getSETCC(X86::COND_E, EFLAGS, dl, DAG);
Success = DAG.getZExtOrTrunc(Success, dl, N->getValueType(1));
Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, T, OpsF));
@@ -22143,6 +23749,8 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
case X86ISD::SETCC: return "X86ISD::SETCC";
case X86ISD::SETCC_CARRY: return "X86ISD::SETCC_CARRY";
case X86ISD::FSETCC: return "X86ISD::FSETCC";
+ case X86ISD::FSETCCM: return "X86ISD::FSETCCM";
+ case X86ISD::FSETCCM_RND: return "X86ISD::FSETCCM_RND";
case X86ISD::CMOV: return "X86ISD::CMOV";
case X86ISD::BRCOND: return "X86ISD::BRCOND";
case X86ISD::RET_FLAG: return "X86ISD::RET_FLAG";
@@ -22215,11 +23823,17 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
case X86ISD::VTRUNC: return "X86ISD::VTRUNC";
case X86ISD::VTRUNCS: return "X86ISD::VTRUNCS";
case X86ISD::VTRUNCUS: return "X86ISD::VTRUNCUS";
+ case X86ISD::VTRUNCSTORES: return "X86ISD::VTRUNCSTORES";
+ case X86ISD::VTRUNCSTOREUS: return "X86ISD::VTRUNCSTOREUS";
+ case X86ISD::VMTRUNCSTORES: return "X86ISD::VMTRUNCSTORES";
+ case X86ISD::VMTRUNCSTOREUS: return "X86ISD::VMTRUNCSTOREUS";
case X86ISD::VINSERT: return "X86ISD::VINSERT";
case X86ISD::VFPEXT: return "X86ISD::VFPEXT";
+ case X86ISD::VFPEXT_RND: return "X86ISD::VFPEXT_RND";
+ case X86ISD::VFPEXTS_RND: return "X86ISD::VFPEXTS_RND";
case X86ISD::VFPROUND: return "X86ISD::VFPROUND";
- case X86ISD::CVTDQ2PD: return "X86ISD::CVTDQ2PD";
- case X86ISD::CVTUDQ2PD: return "X86ISD::CVTUDQ2PD";
+ case X86ISD::VFPROUND_RND: return "X86ISD::VFPROUND_RND";
+ case X86ISD::VFPROUNDS_RND: return "X86ISD::VFPROUNDS_RND";
case X86ISD::CVT2MASK: return "X86ISD::CVT2MASK";
case X86ISD::VSHLDQ: return "X86ISD::VSHLDQ";
case X86ISD::VSRLDQ: return "X86ISD::VSRLDQ";
@@ -22332,27 +23946,43 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
case X86ISD::FNMSUB_RND: return "X86ISD::FNMSUB_RND";
case X86ISD::FMADDSUB_RND: return "X86ISD::FMADDSUB_RND";
case X86ISD::FMSUBADD_RND: return "X86ISD::FMSUBADD_RND";
+ case X86ISD::FMADDS1_RND: return "X86ISD::FMADDS1_RND";
+ case X86ISD::FNMADDS1_RND: return "X86ISD::FNMADDS1_RND";
+ case X86ISD::FMSUBS1_RND: return "X86ISD::FMSUBS1_RND";
+ case X86ISD::FNMSUBS1_RND: return "X86ISD::FNMSUBS1_RND";
+ case X86ISD::FMADDS3_RND: return "X86ISD::FMADDS3_RND";
+ case X86ISD::FNMADDS3_RND: return "X86ISD::FNMADDS3_RND";
+ case X86ISD::FMSUBS3_RND: return "X86ISD::FMSUBS3_RND";
+ case X86ISD::FNMSUBS3_RND: return "X86ISD::FNMSUBS3_RND";
case X86ISD::VPMADD52H: return "X86ISD::VPMADD52H";
case X86ISD::VPMADD52L: return "X86ISD::VPMADD52L";
case X86ISD::VRNDSCALE: return "X86ISD::VRNDSCALE";
+ case X86ISD::VRNDSCALES: return "X86ISD::VRNDSCALES";
case X86ISD::VREDUCE: return "X86ISD::VREDUCE";
+ case X86ISD::VREDUCES: return "X86ISD::VREDUCES";
case X86ISD::VGETMANT: return "X86ISD::VGETMANT";
+ case X86ISD::VGETMANTS: return "X86ISD::VGETMANTS";
case X86ISD::PCMPESTRI: return "X86ISD::PCMPESTRI";
case X86ISD::PCMPISTRI: return "X86ISD::PCMPISTRI";
case X86ISD::XTEST: return "X86ISD::XTEST";
case X86ISD::COMPRESS: return "X86ISD::COMPRESS";
case X86ISD::EXPAND: return "X86ISD::EXPAND";
case X86ISD::SELECT: return "X86ISD::SELECT";
+ case X86ISD::SELECTS: return "X86ISD::SELECTS";
case X86ISD::ADDSUB: return "X86ISD::ADDSUB";
case X86ISD::RCP28: return "X86ISD::RCP28";
+ case X86ISD::RCP28S: return "X86ISD::RCP28S";
case X86ISD::EXP2: return "X86ISD::EXP2";
case X86ISD::RSQRT28: return "X86ISD::RSQRT28";
+ case X86ISD::RSQRT28S: return "X86ISD::RSQRT28S";
case X86ISD::FADD_RND: return "X86ISD::FADD_RND";
case X86ISD::FSUB_RND: return "X86ISD::FSUB_RND";
case X86ISD::FMUL_RND: return "X86ISD::FMUL_RND";
case X86ISD::FDIV_RND: return "X86ISD::FDIV_RND";
case X86ISD::FSQRT_RND: return "X86ISD::FSQRT_RND";
+ case X86ISD::FSQRTS_RND: return "X86ISD::FSQRTS_RND";
case X86ISD::FGETEXP_RND: return "X86ISD::FGETEXP_RND";
+ case X86ISD::FGETEXPS_RND: return "X86ISD::FGETEXPS_RND";
case X86ISD::SCALEF: return "X86ISD::SCALEF";
case X86ISD::SCALEFS: return "X86ISD::SCALEFS";
case X86ISD::ADDS: return "X86ISD::ADDS";
@@ -22361,13 +23991,27 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
case X86ISD::MULHRS: return "X86ISD::MULHRS";
case X86ISD::SINT_TO_FP_RND: return "X86ISD::SINT_TO_FP_RND";
case X86ISD::UINT_TO_FP_RND: return "X86ISD::UINT_TO_FP_RND";
- case X86ISD::FP_TO_SINT_RND: return "X86ISD::FP_TO_SINT_RND";
- case X86ISD::FP_TO_UINT_RND: return "X86ISD::FP_TO_UINT_RND";
+ case X86ISD::CVTTP2SI: return "X86ISD::CVTTP2SI";
+ case X86ISD::CVTTP2UI: return "X86ISD::CVTTP2UI";
+ case X86ISD::CVTTP2SI_RND: return "X86ISD::CVTTP2SI_RND";
+ case X86ISD::CVTTP2UI_RND: return "X86ISD::CVTTP2UI_RND";
+ case X86ISD::CVTTS2SI_RND: return "X86ISD::CVTTS2SI_RND";
+ case X86ISD::CVTTS2UI_RND: return "X86ISD::CVTTS2UI_RND";
+ case X86ISD::CVTSI2P: return "X86ISD::CVTSI2P";
+ case X86ISD::CVTUI2P: return "X86ISD::CVTUI2P";
case X86ISD::VFPCLASS: return "X86ISD::VFPCLASS";
case X86ISD::VFPCLASSS: return "X86ISD::VFPCLASSS";
case X86ISD::MULTISHIFT: return "X86ISD::MULTISHIFT";
- case X86ISD::SCALAR_FP_TO_SINT_RND: return "X86ISD::SCALAR_FP_TO_SINT_RND";
- case X86ISD::SCALAR_FP_TO_UINT_RND: return "X86ISD::SCALAR_FP_TO_UINT_RND";
+ case X86ISD::SCALAR_SINT_TO_FP_RND: return "X86ISD::SCALAR_SINT_TO_FP_RND";
+ case X86ISD::SCALAR_UINT_TO_FP_RND: return "X86ISD::SCALAR_UINT_TO_FP_RND";
+ case X86ISD::CVTPS2PH: return "X86ISD::CVTPS2PH";
+ case X86ISD::CVTPH2PS: return "X86ISD::CVTPH2PS";
+ case X86ISD::CVTP2SI: return "X86ISD::CVTP2SI";
+ case X86ISD::CVTP2UI: return "X86ISD::CVTP2UI";
+ case X86ISD::CVTP2SI_RND: return "X86ISD::CVTP2SI_RND";
+ case X86ISD::CVTP2UI_RND: return "X86ISD::CVTP2UI_RND";
+ case X86ISD::CVTS2SI_RND: return "X86ISD::CVTS2SI_RND";
+ case X86ISD::CVTS2UI_RND: return "X86ISD::CVTS2UI_RND";
}
return nullptr;
}
@@ -24031,11 +25675,10 @@ X86TargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
MachineBasicBlock *BB) const {
DebugLoc DL = MI.getDebugLoc();
MachineFunction *MF = BB->getParent();
- MachineModuleInfo *MMI = &MF->getMMI();
- MachineFrameInfo *MFI = MF->getFrameInfo();
+ MachineFrameInfo &MFI = MF->getFrameInfo();
MachineRegisterInfo *MRI = &MF->getRegInfo();
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
- int FI = MFI->getFunctionContextIndex();
+ int FI = MFI.getFunctionContextIndex();
// Get a mapping of the call site numbers to all of the landing pads they're
// associated with.
@@ -24055,10 +25698,10 @@ X86TargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
break;
}
- if (!MMI->hasCallSiteLandingPad(Sym))
+ if (!MF->hasCallSiteLandingPad(Sym))
continue;
- for (unsigned CSI : MMI->getCallSiteLandingPad(Sym)) {
+ for (unsigned CSI : MF->getCallSiteLandingPad(Sym)) {
CallSiteNumToLPad[CSI].push_back(&MBB);
MaxCSNum = std::max(MaxCSNum, CSI);
}
@@ -24208,173 +25851,18 @@ X86TargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI,
return BB;
}
-// Replace 213-type (isel default) FMA3 instructions with 231-type for
-// accumulator loops. Writing back to the accumulator allows the coalescer
-// to remove extra copies in the loop.
-// FIXME: Do this on AVX512. We don't support 231 variants yet (PR23937).
-MachineBasicBlock *
-X86TargetLowering::emitFMA3Instr(MachineInstr &MI,
- MachineBasicBlock *MBB) const {
- MachineOperand &AddendOp = MI.getOperand(3);
-
- // Bail out early if the addend isn't a register - we can't switch these.
- if (!AddendOp.isReg())
- return MBB;
-
- MachineFunction &MF = *MBB->getParent();
- MachineRegisterInfo &MRI = MF.getRegInfo();
-
- // Check whether the addend is defined by a PHI:
- assert(MRI.hasOneDef(AddendOp.getReg()) && "Multiple defs in SSA?");
- MachineInstr &AddendDef = *MRI.def_instr_begin(AddendOp.getReg());
- if (!AddendDef.isPHI())
- return MBB;
-
- // Look for the following pattern:
- // loop:
- // %addend = phi [%entry, 0], [%loop, %result]
- // ...
- // %result<tied1> = FMA213 %m2<tied0>, %m1, %addend
-
- // Replace with:
- // loop:
- // %addend = phi [%entry, 0], [%loop, %result]
- // ...
- // %result<tied1> = FMA231 %addend<tied0>, %m1, %m2
-
- for (unsigned i = 1, e = AddendDef.getNumOperands(); i < e; i += 2) {
- assert(AddendDef.getOperand(i).isReg());
- MachineOperand PHISrcOp = AddendDef.getOperand(i);
- MachineInstr &PHISrcInst = *MRI.def_instr_begin(PHISrcOp.getReg());
- if (&PHISrcInst == &MI) {
- // Found a matching instruction.
- unsigned NewFMAOpc = 0;
- switch (MI.getOpcode()) {
- case X86::VFMADDPDr213r:
- NewFMAOpc = X86::VFMADDPDr231r;
- break;
- case X86::VFMADDPSr213r:
- NewFMAOpc = X86::VFMADDPSr231r;
- break;
- case X86::VFMADDSDr213r:
- NewFMAOpc = X86::VFMADDSDr231r;
- break;
- case X86::VFMADDSSr213r:
- NewFMAOpc = X86::VFMADDSSr231r;
- break;
- case X86::VFMSUBPDr213r:
- NewFMAOpc = X86::VFMSUBPDr231r;
- break;
- case X86::VFMSUBPSr213r:
- NewFMAOpc = X86::VFMSUBPSr231r;
- break;
- case X86::VFMSUBSDr213r:
- NewFMAOpc = X86::VFMSUBSDr231r;
- break;
- case X86::VFMSUBSSr213r:
- NewFMAOpc = X86::VFMSUBSSr231r;
- break;
- case X86::VFNMADDPDr213r:
- NewFMAOpc = X86::VFNMADDPDr231r;
- break;
- case X86::VFNMADDPSr213r:
- NewFMAOpc = X86::VFNMADDPSr231r;
- break;
- case X86::VFNMADDSDr213r:
- NewFMAOpc = X86::VFNMADDSDr231r;
- break;
- case X86::VFNMADDSSr213r:
- NewFMAOpc = X86::VFNMADDSSr231r;
- break;
- case X86::VFNMSUBPDr213r:
- NewFMAOpc = X86::VFNMSUBPDr231r;
- break;
- case X86::VFNMSUBPSr213r:
- NewFMAOpc = X86::VFNMSUBPSr231r;
- break;
- case X86::VFNMSUBSDr213r:
- NewFMAOpc = X86::VFNMSUBSDr231r;
- break;
- case X86::VFNMSUBSSr213r:
- NewFMAOpc = X86::VFNMSUBSSr231r;
- break;
- case X86::VFMADDSUBPDr213r:
- NewFMAOpc = X86::VFMADDSUBPDr231r;
- break;
- case X86::VFMADDSUBPSr213r:
- NewFMAOpc = X86::VFMADDSUBPSr231r;
- break;
- case X86::VFMSUBADDPDr213r:
- NewFMAOpc = X86::VFMSUBADDPDr231r;
- break;
- case X86::VFMSUBADDPSr213r:
- NewFMAOpc = X86::VFMSUBADDPSr231r;
- break;
-
- case X86::VFMADDPDr213rY:
- NewFMAOpc = X86::VFMADDPDr231rY;
- break;
- case X86::VFMADDPSr213rY:
- NewFMAOpc = X86::VFMADDPSr231rY;
- break;
- case X86::VFMSUBPDr213rY:
- NewFMAOpc = X86::VFMSUBPDr231rY;
- break;
- case X86::VFMSUBPSr213rY:
- NewFMAOpc = X86::VFMSUBPSr231rY;
- break;
- case X86::VFNMADDPDr213rY:
- NewFMAOpc = X86::VFNMADDPDr231rY;
- break;
- case X86::VFNMADDPSr213rY:
- NewFMAOpc = X86::VFNMADDPSr231rY;
- break;
- case X86::VFNMSUBPDr213rY:
- NewFMAOpc = X86::VFNMSUBPDr231rY;
- break;
- case X86::VFNMSUBPSr213rY:
- NewFMAOpc = X86::VFNMSUBPSr231rY;
- break;
- case X86::VFMADDSUBPDr213rY:
- NewFMAOpc = X86::VFMADDSUBPDr231rY;
- break;
- case X86::VFMADDSUBPSr213rY:
- NewFMAOpc = X86::VFMADDSUBPSr231rY;
- break;
- case X86::VFMSUBADDPDr213rY:
- NewFMAOpc = X86::VFMSUBADDPDr231rY;
- break;
- case X86::VFMSUBADDPSr213rY:
- NewFMAOpc = X86::VFMSUBADDPSr231rY;
- break;
- default:
- llvm_unreachable("Unrecognized FMA variant.");
- }
-
- const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
- MachineInstrBuilder MIB =
- BuildMI(MF, MI.getDebugLoc(), TII.get(NewFMAOpc))
- .addOperand(MI.getOperand(0))
- .addOperand(MI.getOperand(3))
- .addOperand(MI.getOperand(2))
- .addOperand(MI.getOperand(1));
- MBB->insert(MachineBasicBlock::iterator(MI), MIB);
- MI.eraseFromParent();
- }
- }
-
- return MBB;
-}
-
MachineBasicBlock *
X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const {
+ MachineFunction *MF = BB->getParent();
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+
switch (MI.getOpcode()) {
default: llvm_unreachable("Unexpected instr type to insert");
case X86::TAILJMPd64:
case X86::TAILJMPr64:
case X86::TAILJMPm64:
- case X86::TAILJMPd64_REX:
case X86::TAILJMPr64_REX:
case X86::TAILJMPm64_REX:
llvm_unreachable("TAILJMP64 would not be touched here.");
@@ -24423,8 +25911,6 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case X86::RDFLAGS32:
case X86::RDFLAGS64: {
- DebugLoc DL = MI.getDebugLoc();
- const TargetInstrInfo *TII = Subtarget.getInstrInfo();
unsigned PushF =
MI.getOpcode() == X86::RDFLAGS32 ? X86::PUSHF32 : X86::PUSHF64;
unsigned Pop = MI.getOpcode() == X86::RDFLAGS32 ? X86::POP32r : X86::POP64r;
@@ -24442,8 +25928,6 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case X86::WRFLAGS32:
case X86::WRFLAGS64: {
- DebugLoc DL = MI.getDebugLoc();
- const TargetInstrInfo *TII = Subtarget.getInstrInfo();
unsigned Push =
MI.getOpcode() == X86::WRFLAGS32 ? X86::PUSH32r : X86::PUSH64r;
unsigned PopF =
@@ -24468,19 +25952,15 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case X86::FP80_TO_INT16_IN_MEM:
case X86::FP80_TO_INT32_IN_MEM:
case X86::FP80_TO_INT64_IN_MEM: {
- MachineFunction *F = BB->getParent();
- const TargetInstrInfo *TII = Subtarget.getInstrInfo();
- DebugLoc DL = MI.getDebugLoc();
-
// Change the floating point control register to use "round towards zero"
// mode when truncating to an integer value.
- int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2, false);
+ int CWFrameIdx = MF->getFrameInfo().CreateStackObject(2, 2, false);
addFrameReference(BuildMI(*BB, MI, DL,
TII->get(X86::FNSTCW16m)), CWFrameIdx);
// Load the old value of the high byte of the control word...
unsigned OldCW =
- F->getRegInfo().createVirtualRegister(&X86::GR16RegClass);
+ MF->getRegInfo().createVirtualRegister(&X86::GR16RegClass);
addFrameReference(BuildMI(*BB, MI, DL, TII->get(X86::MOV16rm), OldCW),
CWFrameIdx);
@@ -24588,39 +26068,57 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case TargetOpcode::PATCHPOINT:
return emitPatchPoint(MI, BB);
- case X86::VFMADDPDr213r:
- case X86::VFMADDPSr213r:
- case X86::VFMADDSDr213r:
- case X86::VFMADDSSr213r:
- case X86::VFMSUBPDr213r:
- case X86::VFMSUBPSr213r:
- case X86::VFMSUBSDr213r:
- case X86::VFMSUBSSr213r:
- case X86::VFNMADDPDr213r:
- case X86::VFNMADDPSr213r:
- case X86::VFNMADDSDr213r:
- case X86::VFNMADDSSr213r:
- case X86::VFNMSUBPDr213r:
- case X86::VFNMSUBPSr213r:
- case X86::VFNMSUBSDr213r:
- case X86::VFNMSUBSSr213r:
- case X86::VFMADDSUBPDr213r:
- case X86::VFMADDSUBPSr213r:
- case X86::VFMSUBADDPDr213r:
- case X86::VFMSUBADDPSr213r:
- case X86::VFMADDPDr213rY:
- case X86::VFMADDPSr213rY:
- case X86::VFMSUBPDr213rY:
- case X86::VFMSUBPSr213rY:
- case X86::VFNMADDPDr213rY:
- case X86::VFNMADDPSr213rY:
- case X86::VFNMSUBPDr213rY:
- case X86::VFNMSUBPSr213rY:
- case X86::VFMADDSUBPDr213rY:
- case X86::VFMADDSUBPSr213rY:
- case X86::VFMSUBADDPDr213rY:
- case X86::VFMSUBADDPSr213rY:
- return emitFMA3Instr(MI, BB);
+ case X86::LCMPXCHG8B: {
+ const X86RegisterInfo *TRI = Subtarget.getRegisterInfo();
+ // In addition to 4 E[ABCD] registers implied by encoding, CMPXCHG8B
+ // requires a memory operand. If it happens that current architecture is
+ // i686 and for current function we need a base pointer
+ // - which is ESI for i686 - register allocator would not be able to
+ // allocate registers for an address in form of X(%reg, %reg, Y)
+ // - there never would be enough unreserved registers during regalloc
+ // (without the need for base ptr the only option would be X(%edi, %esi, Y).
+ // We are giving a hand to register allocator by precomputing the address in
+ // a new vreg using LEA.
+
+ // If it is not i686 or there is no base pointer - nothing to do here.
+ if (!Subtarget.is32Bit() || !TRI->hasBasePointer(*MF))
+ return BB;
+
+ // Even though this code does not necessarily needs the base pointer to
+ // be ESI, we check for that. The reason: if this assert fails, there are
+ // some changes happened in the compiler base pointer handling, which most
+ // probably have to be addressed somehow here.
+ assert(TRI->getBaseRegister() == X86::ESI &&
+ "LCMPXCHG8B custom insertion for i686 is written with X86::ESI as a "
+ "base pointer in mind");
+
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ MVT SPTy = getPointerTy(MF->getDataLayout());
+ const TargetRegisterClass *AddrRegClass = getRegClassFor(SPTy);
+ unsigned computedAddrVReg = MRI.createVirtualRegister(AddrRegClass);
+
+ X86AddressMode AM = getAddressFromInstr(&MI, 0);
+ // Regalloc does not need any help when the memory operand of CMPXCHG8B
+ // does not use index register.
+ if (AM.IndexReg == X86::NoRegister)
+ return BB;
+
+ // After X86TargetLowering::ReplaceNodeResults CMPXCHG8B is glued to its
+ // four operand definitions that are E[ABCD] registers. We skip them and
+ // then insert the LEA.
+ MachineBasicBlock::iterator MBBI(MI);
+ while (MBBI->definesRegister(X86::EAX) || MBBI->definesRegister(X86::EBX) ||
+ MBBI->definesRegister(X86::ECX) || MBBI->definesRegister(X86::EDX))
+ --MBBI;
+ addFullAddress(
+ BuildMI(*BB, *MBBI, DL, TII->get(X86::LEA32r), computedAddrVReg), AM);
+
+ setDirectAddressInInstr(&MI, 0, computedAddrVReg);
+
+ return BB;
+ }
+ case X86::LCMPXCHG16B:
+ return BB;
case X86::LCMPXCHG8B_SAVE_EBX:
case X86::LCMPXCHG16B_SAVE_RBX: {
unsigned BasePtr =
@@ -24667,7 +26165,7 @@ void X86TargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
// These nodes' second result is a boolean.
if (Op.getResNo() == 0)
break;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case X86ISD::SETCC:
KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - 1);
break;
@@ -24676,16 +26174,36 @@ void X86TargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
KnownZero = APInt::getHighBitsSet(BitWidth, BitWidth - NumLoBits);
break;
}
+ case X86ISD::VZEXT: {
+ SDValue N0 = Op.getOperand(0);
+ unsigned NumElts = Op.getValueType().getVectorNumElements();
+ unsigned InNumElts = N0.getValueType().getVectorNumElements();
+ unsigned InBitWidth = N0.getValueType().getScalarSizeInBits();
+
+ KnownZero = KnownOne = APInt(InBitWidth, 0);
+ APInt DemandedElts = APInt::getLowBitsSet(InNumElts, NumElts);
+ DAG.computeKnownBits(N0, KnownZero, KnownOne, DemandedElts, Depth + 1);
+ KnownOne = KnownOne.zext(BitWidth);
+ KnownZero = KnownZero.zext(BitWidth);
+ KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - InBitWidth);
+ break;
+ }
}
}
unsigned X86TargetLowering::ComputeNumSignBitsForTargetNode(
- SDValue Op,
- const SelectionDAG &,
- unsigned Depth) const {
+ SDValue Op, const SelectionDAG &DAG, unsigned Depth) const {
// SETCC_CARRY sets the dest to ~0 for true or 0 for false.
if (Op.getOpcode() == X86ISD::SETCC_CARRY)
- return Op.getValueType().getScalarSizeInBits();
+ return Op.getScalarValueSizeInBits();
+
+ if (Op.getOpcode() == X86ISD::VSEXT) {
+ EVT VT = Op.getValueType();
+ EVT SrcVT = Op.getOperand(0).getValueType();
+ unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1);
+ Tmp += VT.getScalarSizeInBits() - SrcVT.getScalarSizeInBits();
+ return Tmp;
+ }
// Fallback case.
return 1;
@@ -24706,171 +26224,113 @@ bool X86TargetLowering::isGAPlusOffset(SDNode *N,
return TargetLowering::isGAPlusOffset(N, GA, Offset);
}
-/// Performs shuffle combines for 256-bit vectors.
-/// FIXME: This could be expanded to support 512 bit vectors as well.
-static SDValue combineShuffle256(SDNode *N, SelectionDAG &DAG,
- TargetLowering::DAGCombinerInfo &DCI,
- const X86Subtarget &Subtarget) {
- SDLoc dl(N);
- ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N);
- SDValue V1 = SVOp->getOperand(0);
- SDValue V2 = SVOp->getOperand(1);
- MVT VT = SVOp->getSimpleValueType(0);
- unsigned NumElems = VT.getVectorNumElements();
-
- if (V1.getOpcode() == ISD::CONCAT_VECTORS &&
- V2.getOpcode() == ISD::CONCAT_VECTORS) {
- //
- // 0,0,0,...
- // |
- // V UNDEF BUILD_VECTOR UNDEF
- // \ / \ /
- // CONCAT_VECTOR CONCAT_VECTOR
- // \ /
- // \ /
- // RESULT: V + zero extended
- //
- if (V2.getOperand(0).getOpcode() != ISD::BUILD_VECTOR ||
- !V2.getOperand(1).isUndef() || !V1.getOperand(1).isUndef())
- return SDValue();
-
- if (!ISD::isBuildVectorAllZeros(V2.getOperand(0).getNode()))
- return SDValue();
-
- // To match the shuffle mask, the first half of the mask should
- // be exactly the first vector, and all the rest a splat with the
- // first element of the second one.
- for (unsigned i = 0; i != NumElems/2; ++i)
- if (!isUndefOrEqual(SVOp->getMaskElt(i), i) ||
- !isUndefOrEqual(SVOp->getMaskElt(i+NumElems/2), NumElems))
- return SDValue();
-
- // If V1 is coming from a vector load then just fold to a VZEXT_LOAD.
- if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(V1.getOperand(0))) {
- if (Ld->hasNUsesOfValue(1, 0)) {
- SDVTList Tys = DAG.getVTList(MVT::v4i64, MVT::Other);
- SDValue Ops[] = { Ld->getChain(), Ld->getBasePtr() };
- SDValue ResNode =
- DAG.getMemIntrinsicNode(X86ISD::VZEXT_LOAD, dl, Tys, Ops,
- Ld->getMemoryVT(),
- Ld->getPointerInfo(),
- Ld->getAlignment(),
- false/*isVolatile*/, true/*ReadMem*/,
- false/*WriteMem*/);
-
- // Make sure the newly-created LOAD is in the same position as Ld in
- // terms of dependency. We create a TokenFactor for Ld and ResNode,
- // and update uses of Ld's output chain to use the TokenFactor.
- if (Ld->hasAnyUseOfValue(1)) {
- SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
- SDValue(Ld, 1), SDValue(ResNode.getNode(), 1));
- DAG.ReplaceAllUsesOfValueWith(SDValue(Ld, 1), NewChain);
- DAG.UpdateNodeOperands(NewChain.getNode(), SDValue(Ld, 1),
- SDValue(ResNode.getNode(), 1));
- }
-
- return DAG.getBitcast(VT, ResNode);
- }
- }
-
- // Emit a zeroed vector and insert the desired subvector on its
- // first half.
- SDValue Zeros = getZeroVector(VT, Subtarget, DAG, dl);
- SDValue InsV = insert128BitVector(Zeros, V1.getOperand(0), 0, DAG, dl);
- return DCI.CombineTo(N, InsV);
- }
-
- return SDValue();
-}
-
// Attempt to match a combined shuffle mask against supported unary shuffle
// instructions.
// TODO: Investigate sharing more of this with shuffle lowering.
-static bool matchUnaryVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
+static bool matchUnaryVectorShuffle(MVT MaskVT, ArrayRef<int> Mask,
+ bool FloatDomain,
const X86Subtarget &Subtarget,
- unsigned &Shuffle, MVT &ShuffleVT) {
- bool FloatDomain = SrcVT.isFloatingPoint() ||
- (!Subtarget.hasAVX2() && SrcVT.is256BitVector());
+ unsigned &Shuffle, MVT &SrcVT, MVT &DstVT) {
+ unsigned NumMaskElts = Mask.size();
+ unsigned MaskEltSize = MaskVT.getScalarSizeInBits();
- // Match a 128-bit integer vector against a VZEXT_MOVL (MOVQ) instruction.
- if (!FloatDomain && SrcVT.is128BitVector() &&
- isTargetShuffleEquivalent(Mask, {0, SM_SentinelZero})) {
+ // Match against a VZEXT_MOVL instruction, SSE1 only supports 32-bits (MOVSS).
+ if (((MaskEltSize == 32) || (MaskEltSize == 64 && Subtarget.hasSSE2())) &&
+ isUndefOrEqual(Mask[0], 0) &&
+ isUndefOrZeroInRange(Mask, 1, NumMaskElts - 1)) {
Shuffle = X86ISD::VZEXT_MOVL;
- ShuffleVT = MVT::v2i64;
+ SrcVT = DstVT = !Subtarget.hasSSE2() ? MVT::v4f32 : MaskVT;
return true;
}
+ // Match against a VZEXT instruction.
+ // TODO: Add 256/512-bit vector support.
+ if (!FloatDomain && MaskVT.is128BitVector() && Subtarget.hasSSE41()) {
+ unsigned MaxScale = 64 / MaskEltSize;
+ for (unsigned Scale = 2; Scale <= MaxScale; Scale *= 2) {
+ bool Match = true;
+ unsigned NumDstElts = NumMaskElts / Scale;
+ for (unsigned i = 0; i != NumDstElts && Match; ++i) {
+ Match &= isUndefOrEqual(Mask[i * Scale], (int)i);
+ Match &= isUndefOrZeroInRange(Mask, (i * Scale) + 1, Scale - 1);
+ }
+ if (Match) {
+ SrcVT = MaskVT;
+ DstVT = MVT::getIntegerVT(Scale * MaskEltSize);
+ DstVT = MVT::getVectorVT(DstVT, NumDstElts);
+ Shuffle = X86ISD::VZEXT;
+ return true;
+ }
+ }
+ }
+
// Check if we have SSE3 which will let us use MOVDDUP etc. The
// instructions are no slower than UNPCKLPD but has the option to
// fold the input operand into even an unaligned memory load.
- if (SrcVT.is128BitVector() && Subtarget.hasSSE3() && FloatDomain) {
+ if (MaskVT.is128BitVector() && Subtarget.hasSSE3() && FloatDomain) {
if (isTargetShuffleEquivalent(Mask, {0, 0})) {
Shuffle = X86ISD::MOVDDUP;
- ShuffleVT = MVT::v2f64;
+ SrcVT = DstVT = MVT::v2f64;
return true;
}
if (isTargetShuffleEquivalent(Mask, {0, 0, 2, 2})) {
Shuffle = X86ISD::MOVSLDUP;
- ShuffleVT = MVT::v4f32;
+ SrcVT = DstVT = MVT::v4f32;
return true;
}
if (isTargetShuffleEquivalent(Mask, {1, 1, 3, 3})) {
Shuffle = X86ISD::MOVSHDUP;
- ShuffleVT = MVT::v4f32;
+ SrcVT = DstVT = MVT::v4f32;
return true;
}
}
- if (SrcVT.is256BitVector() && FloatDomain) {
+ if (MaskVT.is256BitVector() && FloatDomain) {
assert(Subtarget.hasAVX() && "AVX required for 256-bit vector shuffles");
if (isTargetShuffleEquivalent(Mask, {0, 0, 2, 2})) {
Shuffle = X86ISD::MOVDDUP;
- ShuffleVT = MVT::v4f64;
+ SrcVT = DstVT = MVT::v4f64;
return true;
}
if (isTargetShuffleEquivalent(Mask, {0, 0, 2, 2, 4, 4, 6, 6})) {
Shuffle = X86ISD::MOVSLDUP;
- ShuffleVT = MVT::v8f32;
+ SrcVT = DstVT = MVT::v8f32;
return true;
}
if (isTargetShuffleEquivalent(Mask, {1, 1, 3, 3, 5, 5, 7, 7})) {
Shuffle = X86ISD::MOVSHDUP;
- ShuffleVT = MVT::v8f32;
+ SrcVT = DstVT = MVT::v8f32;
return true;
}
}
- if (SrcVT.is512BitVector() && FloatDomain) {
+ if (MaskVT.is512BitVector() && FloatDomain) {
assert(Subtarget.hasAVX512() &&
"AVX512 required for 512-bit vector shuffles");
if (isTargetShuffleEquivalent(Mask, {0, 0, 2, 2, 4, 4, 6, 6})) {
Shuffle = X86ISD::MOVDDUP;
- ShuffleVT = MVT::v8f64;
+ SrcVT = DstVT = MVT::v8f64;
return true;
}
if (isTargetShuffleEquivalent(
Mask, {0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14})) {
Shuffle = X86ISD::MOVSLDUP;
- ShuffleVT = MVT::v16f32;
+ SrcVT = DstVT = MVT::v16f32;
return true;
}
if (isTargetShuffleEquivalent(
Mask, {1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15})) {
Shuffle = X86ISD::MOVSHDUP;
- ShuffleVT = MVT::v16f32;
+ SrcVT = DstVT = MVT::v16f32;
return true;
}
}
// Attempt to match against broadcast-from-vector.
if (Subtarget.hasAVX2()) {
- unsigned NumElts = Mask.size();
- SmallVector<int, 64> BroadcastMask(NumElts, 0);
+ SmallVector<int, 64> BroadcastMask(NumMaskElts, 0);
if (isTargetShuffleEquivalent(Mask, BroadcastMask)) {
- unsigned EltSize = SrcVT.getSizeInBits() / NumElts;
- ShuffleVT = FloatDomain ? MVT::getFloatingPointVT(EltSize)
- : MVT::getIntegerVT(EltSize);
- ShuffleVT = MVT::getVectorVT(ShuffleVT, NumElts);
+ SrcVT = DstVT = MaskVT;
Shuffle = X86ISD::VBROADCAST;
return true;
}
@@ -24882,19 +26342,44 @@ static bool matchUnaryVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
// Attempt to match a combined shuffle mask against supported unary immediate
// permute instructions.
// TODO: Investigate sharing more of this with shuffle lowering.
-static bool matchPermuteVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
- const X86Subtarget &Subtarget,
- unsigned &Shuffle, MVT &ShuffleVT,
- unsigned &PermuteImm) {
- // Ensure we don't contain any zero elements.
- for (int M : Mask) {
- if (M == SM_SentinelZero)
- return false;
- assert(SM_SentinelUndef <= M && M < (int)Mask.size() &&
- "Expected unary shuffle");
+static bool matchUnaryPermuteVectorShuffle(MVT MaskVT, ArrayRef<int> Mask,
+ bool FloatDomain,
+ const X86Subtarget &Subtarget,
+ unsigned &Shuffle, MVT &ShuffleVT,
+ unsigned &PermuteImm) {
+ unsigned NumMaskElts = Mask.size();
+
+ bool ContainsZeros = false;
+ SmallBitVector Zeroable(NumMaskElts, false);
+ for (unsigned i = 0; i != NumMaskElts; ++i) {
+ int M = Mask[i];
+ Zeroable[i] = isUndefOrZero(M);
+ ContainsZeros |= (M == SM_SentinelZero);
+ }
+
+ // Attempt to match against byte/bit shifts.
+ // FIXME: Add 512-bit support.
+ if (!FloatDomain && ((MaskVT.is128BitVector() && Subtarget.hasSSE2()) ||
+ (MaskVT.is256BitVector() && Subtarget.hasAVX2()))) {
+ int ShiftAmt = matchVectorShuffleAsShift(ShuffleVT, Shuffle,
+ MaskVT.getScalarSizeInBits(), Mask,
+ 0, Zeroable, Subtarget);
+ if (0 < ShiftAmt) {
+ PermuteImm = (unsigned)ShiftAmt;
+ return true;
+ }
}
- unsigned MaskScalarSizeInBits = SrcVT.getSizeInBits() / Mask.size();
+ // Ensure we don't contain any zero elements.
+ if (ContainsZeros)
+ return false;
+
+ assert(llvm::all_of(Mask, [&](int M) {
+ return SM_SentinelUndef <= M && M < (int)NumMaskElts;
+ }) && "Expected unary shuffle");
+
+ unsigned InputSizeInBits = MaskVT.getSizeInBits();
+ unsigned MaskScalarSizeInBits = InputSizeInBits / Mask.size();
MVT MaskEltVT = MVT::getIntegerVT(MaskScalarSizeInBits);
// Handle PSHUFLW/PSHUFHW repeated patterns.
@@ -24908,7 +26393,7 @@ static bool matchPermuteVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
if (isUndefOrInRange(LoMask, 0, 4) &&
isSequentialOrUndefInRange(HiMask, 0, 4, 4)) {
Shuffle = X86ISD::PSHUFLW;
- ShuffleVT = MVT::getVectorVT(MVT::i16, SrcVT.getSizeInBits() / 16);
+ ShuffleVT = MVT::getVectorVT(MVT::i16, InputSizeInBits / 16);
PermuteImm = getV4X86ShuffleImm(LoMask);
return true;
}
@@ -24922,7 +26407,7 @@ static bool matchPermuteVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
OffsetHiMask[i] = (HiMask[i] < 0 ? HiMask[i] : HiMask[i] - 4);
Shuffle = X86ISD::PSHUFHW;
- ShuffleVT = MVT::getVectorVT(MVT::i16, SrcVT.getSizeInBits() / 16);
+ ShuffleVT = MVT::getVectorVT(MVT::i16, InputSizeInBits / 16);
PermuteImm = getV4X86ShuffleImm(OffsetHiMask);
return true;
}
@@ -24938,24 +26423,23 @@ static bool matchPermuteVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
// AVX introduced the VPERMILPD/VPERMILPS float permutes, before then we
// had to use 2-input SHUFPD/SHUFPS shuffles (not handled here).
- bool FloatDomain = SrcVT.isFloatingPoint();
if (FloatDomain && !Subtarget.hasAVX())
return false;
// Pre-AVX2 we must use float shuffles on 256-bit vectors.
- if (SrcVT.is256BitVector() && !Subtarget.hasAVX2())
+ if (MaskVT.is256BitVector() && !Subtarget.hasAVX2())
FloatDomain = true;
// Check for lane crossing permutes.
if (is128BitLaneCrossingShuffleMask(MaskEltVT, Mask)) {
// PERMPD/PERMQ permutes within a 256-bit vector (AVX2+).
- if (Subtarget.hasAVX2() && SrcVT.is256BitVector() && Mask.size() == 4) {
+ if (Subtarget.hasAVX2() && MaskVT.is256BitVector() && Mask.size() == 4) {
Shuffle = X86ISD::VPERMI;
ShuffleVT = (FloatDomain ? MVT::v4f64 : MVT::v4i64);
PermuteImm = getV4X86ShuffleImm(Mask);
return true;
}
- if (Subtarget.hasAVX512() && SrcVT.is512BitVector() && Mask.size() == 8) {
+ if (Subtarget.hasAVX512() && MaskVT.is512BitVector() && Mask.size() == 8) {
SmallVector<int, 4> RepeatedMask;
if (is256BitLaneRepeatedShuffleMask(MVT::v8f64, Mask, RepeatedMask)) {
Shuffle = X86ISD::VPERMI;
@@ -24994,7 +26478,7 @@ static bool matchPermuteVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
Shuffle = (FloatDomain ? X86ISD::VPERMILPI : X86ISD::PSHUFD);
ShuffleVT = (FloatDomain ? MVT::f32 : MVT::i32);
- ShuffleVT = MVT::getVectorVT(ShuffleVT, SrcVT.getSizeInBits() / 32);
+ ShuffleVT = MVT::getVectorVT(ShuffleVT, InputSizeInBits / 32);
PermuteImm = getV4X86ShuffleImm(WordMask);
return true;
}
@@ -25002,47 +26486,259 @@ static bool matchPermuteVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
// Attempt to match a combined unary shuffle mask against supported binary
// shuffle instructions.
// TODO: Investigate sharing more of this with shuffle lowering.
-static bool matchBinaryVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
- unsigned &Shuffle, MVT &ShuffleVT) {
- bool FloatDomain = SrcVT.isFloatingPoint();
+static bool matchBinaryVectorShuffle(MVT MaskVT, ArrayRef<int> Mask,
+ bool FloatDomain, SDValue &V1, SDValue &V2,
+ const X86Subtarget &Subtarget,
+ unsigned &Shuffle, MVT &ShuffleVT,
+ bool IsUnary) {
+ unsigned EltSizeInBits = MaskVT.getScalarSizeInBits();
- if (SrcVT.is128BitVector()) {
+ if (MaskVT.is128BitVector()) {
if (isTargetShuffleEquivalent(Mask, {0, 0}) && FloatDomain) {
+ V2 = V1;
Shuffle = X86ISD::MOVLHPS;
ShuffleVT = MVT::v4f32;
return true;
}
if (isTargetShuffleEquivalent(Mask, {1, 1}) && FloatDomain) {
+ V2 = V1;
Shuffle = X86ISD::MOVHLPS;
ShuffleVT = MVT::v4f32;
return true;
}
- if (isTargetShuffleEquivalent(Mask, {0, 0, 1, 1}) && FloatDomain) {
- Shuffle = X86ISD::UNPCKL;
- ShuffleVT = MVT::v4f32;
+ if (isTargetShuffleEquivalent(Mask, {0, 3}) && Subtarget.hasSSE2() &&
+ (FloatDomain || !Subtarget.hasSSE41())) {
+ std::swap(V1, V2);
+ Shuffle = X86ISD::MOVSD;
+ ShuffleVT = MaskVT;
return true;
}
- if (isTargetShuffleEquivalent(Mask, {2, 2, 3, 3}) && FloatDomain) {
- Shuffle = X86ISD::UNPCKH;
- ShuffleVT = MVT::v4f32;
+ if (isTargetShuffleEquivalent(Mask, {4, 1, 2, 3}) &&
+ (FloatDomain || !Subtarget.hasSSE41())) {
+ Shuffle = X86ISD::MOVSS;
+ ShuffleVT = MaskVT;
+ return true;
+ }
+ }
+
+ // Attempt to match against either a unary or binary UNPCKL/UNPCKH shuffle.
+ if ((MaskVT == MVT::v4f32 && Subtarget.hasSSE1()) ||
+ (MaskVT.is128BitVector() && Subtarget.hasSSE2()) ||
+ (MaskVT.is256BitVector() && 32 <= EltSizeInBits && Subtarget.hasAVX()) ||
+ (MaskVT.is256BitVector() && Subtarget.hasAVX2()) ||
+ (MaskVT.is512BitVector() && Subtarget.hasAVX512())) {
+ MVT LegalVT = MaskVT;
+ if (LegalVT.is256BitVector() && !Subtarget.hasAVX2())
+ LegalVT = (32 == EltSizeInBits ? MVT::v8f32 : MVT::v4f64);
+
+ SmallVector<int, 64> Unpckl, Unpckh;
+ if (IsUnary) {
+ createUnpackShuffleMask(MaskVT, Unpckl, true, true);
+ if (isTargetShuffleEquivalent(Mask, Unpckl)) {
+ V2 = V1;
+ Shuffle = X86ISD::UNPCKL;
+ ShuffleVT = LegalVT;
+ return true;
+ }
+
+ createUnpackShuffleMask(MaskVT, Unpckh, false, true);
+ if (isTargetShuffleEquivalent(Mask, Unpckh)) {
+ V2 = V1;
+ Shuffle = X86ISD::UNPCKH;
+ ShuffleVT = LegalVT;
+ return true;
+ }
+ } else {
+ createUnpackShuffleMask(MaskVT, Unpckl, true, false);
+ if (isTargetShuffleEquivalent(Mask, Unpckl)) {
+ Shuffle = X86ISD::UNPCKL;
+ ShuffleVT = LegalVT;
+ return true;
+ }
+
+ createUnpackShuffleMask(MaskVT, Unpckh, false, false);
+ if (isTargetShuffleEquivalent(Mask, Unpckh)) {
+ Shuffle = X86ISD::UNPCKH;
+ ShuffleVT = LegalVT;
+ return true;
+ }
+
+ ShuffleVectorSDNode::commuteMask(Unpckl);
+ if (isTargetShuffleEquivalent(Mask, Unpckl)) {
+ std::swap(V1, V2);
+ Shuffle = X86ISD::UNPCKL;
+ ShuffleVT = LegalVT;
+ return true;
+ }
+
+ ShuffleVectorSDNode::commuteMask(Unpckh);
+ if (isTargetShuffleEquivalent(Mask, Unpckh)) {
+ std::swap(V1, V2);
+ Shuffle = X86ISD::UNPCKH;
+ ShuffleVT = LegalVT;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool matchBinaryPermuteVectorShuffle(MVT MaskVT, ArrayRef<int> Mask,
+ bool FloatDomain,
+ SDValue &V1, SDValue &V2,
+ SDLoc &DL, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget,
+ unsigned &Shuffle, MVT &ShuffleVT,
+ unsigned &PermuteImm) {
+ unsigned NumMaskElts = Mask.size();
+
+ // Attempt to match against PALIGNR byte rotate.
+ if (!FloatDomain && ((MaskVT.is128BitVector() && Subtarget.hasSSSE3()) ||
+ (MaskVT.is256BitVector() && Subtarget.hasAVX2()))) {
+ int ByteRotation = matchVectorShuffleAsByteRotate(MaskVT, V1, V2, Mask);
+ if (0 < ByteRotation) {
+ Shuffle = X86ISD::PALIGNR;
+ ShuffleVT = MVT::getVectorVT(MVT::i8, MaskVT.getSizeInBits() / 8);
+ PermuteImm = ByteRotation;
+ return true;
+ }
+ }
+
+ // Attempt to combine to X86ISD::BLENDI.
+ if (NumMaskElts <= 8 && ((Subtarget.hasSSE41() && MaskVT.is128BitVector()) ||
+ (Subtarget.hasAVX() && MaskVT.is256BitVector()))) {
+ // Determine a type compatible with X86ISD::BLENDI.
+ // TODO - add 16i16 support (requires lane duplication).
+ MVT BlendVT = MaskVT;
+ if (Subtarget.hasAVX2()) {
+ if (BlendVT == MVT::v4i64)
+ BlendVT = MVT::v8i32;
+ else if (BlendVT == MVT::v2i64)
+ BlendVT = MVT::v4i32;
+ } else {
+ if (BlendVT == MVT::v2i64 || BlendVT == MVT::v4i32)
+ BlendVT = MVT::v8i16;
+ else if (BlendVT == MVT::v4i64)
+ BlendVT = MVT::v4f64;
+ else if (BlendVT == MVT::v8i32)
+ BlendVT = MVT::v8f32;
+ }
+
+ unsigned BlendSize = BlendVT.getVectorNumElements();
+ unsigned MaskRatio = BlendSize / NumMaskElts;
+
+ // Can we blend with zero?
+ if (isSequentialOrUndefOrZeroInRange(Mask, /*Pos*/ 0, /*Size*/ NumMaskElts,
+ /*Low*/ 0) &&
+ NumMaskElts <= BlendVT.getVectorNumElements()) {
+ PermuteImm = 0;
+ for (unsigned i = 0; i != BlendSize; ++i)
+ if (Mask[i / MaskRatio] < 0)
+ PermuteImm |= 1u << i;
+
+ V2 = getZeroVector(BlendVT, Subtarget, DAG, DL);
+ Shuffle = X86ISD::BLENDI;
+ ShuffleVT = BlendVT;
return true;
}
- if (isTargetShuffleEquivalent(Mask, {0, 0, 1, 1, 2, 2, 3, 3}) ||
- isTargetShuffleEquivalent(
- Mask, {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7})) {
- Shuffle = X86ISD::UNPCKL;
- ShuffleVT = Mask.size() == 8 ? MVT::v8i16 : MVT::v16i8;
+
+ // Attempt to match as a binary blend.
+ if (NumMaskElts <= BlendVT.getVectorNumElements()) {
+ bool MatchBlend = true;
+ for (int i = 0; i != (int)NumMaskElts; ++i) {
+ int M = Mask[i];
+ if (M == SM_SentinelUndef)
+ continue;
+ else if (M == SM_SentinelZero)
+ MatchBlend = false;
+ else if ((M != i) && (M != (i + (int)NumMaskElts)))
+ MatchBlend = false;
+ }
+
+ if (MatchBlend) {
+ PermuteImm = 0;
+ for (unsigned i = 0; i != BlendSize; ++i)
+ if ((int)NumMaskElts <= Mask[i / MaskRatio])
+ PermuteImm |= 1u << i;
+
+ Shuffle = X86ISD::BLENDI;
+ ShuffleVT = BlendVT;
+ return true;
+ }
+ }
+ }
+
+ // Attempt to combine to INSERTPS.
+ if (Subtarget.hasSSE41() && MaskVT == MVT::v4f32) {
+ SmallBitVector Zeroable(4, false);
+ for (unsigned i = 0; i != NumMaskElts; ++i)
+ if (Mask[i] < 0)
+ Zeroable[i] = true;
+
+ if (Zeroable.any() &&
+ matchVectorShuffleAsInsertPS(V1, V2, PermuteImm, Zeroable, Mask, DAG)) {
+ Shuffle = X86ISD::INSERTPS;
+ ShuffleVT = MVT::v4f32;
return true;
}
- if (isTargetShuffleEquivalent(Mask, {4, 4, 5, 5, 6, 6, 7, 7}) ||
- isTargetShuffleEquivalent(Mask, {8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13,
- 13, 14, 14, 15, 15})) {
- Shuffle = X86ISD::UNPCKH;
- ShuffleVT = Mask.size() == 8 ? MVT::v8i16 : MVT::v16i8;
+ }
+
+ // Attempt to combine to SHUFPD.
+ if ((MaskVT == MVT::v2f64 && Subtarget.hasSSE2()) ||
+ (MaskVT == MVT::v4f64 && Subtarget.hasAVX()) ||
+ (MaskVT == MVT::v8f64 && Subtarget.hasAVX512())) {
+ if (matchVectorShuffleWithSHUFPD(MaskVT, V1, V2, PermuteImm, Mask)) {
+ Shuffle = X86ISD::SHUFP;
+ ShuffleVT = MaskVT;
return true;
}
}
+ // Attempt to combine to SHUFPS.
+ if ((MaskVT == MVT::v4f32 && Subtarget.hasSSE1()) ||
+ (MaskVT == MVT::v8f32 && Subtarget.hasAVX()) ||
+ (MaskVT == MVT::v16f32 && Subtarget.hasAVX512())) {
+ SmallVector<int, 4> RepeatedMask;
+ if (isRepeatedTargetShuffleMask(128, MaskVT, Mask, RepeatedMask)) {
+ auto MatchHalf = [&](unsigned Offset, int &S0, int &S1) {
+ int M0 = RepeatedMask[Offset];
+ int M1 = RepeatedMask[Offset + 1];
+
+ if (isUndefInRange(RepeatedMask, Offset, 2)) {
+ return DAG.getUNDEF(MaskVT);
+ } else if (isUndefOrZeroInRange(RepeatedMask, Offset, 2)) {
+ S0 = (SM_SentinelUndef == M0 ? -1 : 0);
+ S1 = (SM_SentinelUndef == M1 ? -1 : 1);
+ return getZeroVector(MaskVT, Subtarget, DAG, DL);
+ } else if (isUndefOrInRange(M0, 0, 4) && isUndefOrInRange(M1, 0, 4)) {
+ S0 = (SM_SentinelUndef == M0 ? -1 : M0 & 3);
+ S1 = (SM_SentinelUndef == M1 ? -1 : M1 & 3);
+ return V1;
+ } else if (isUndefOrInRange(M0, 4, 8) && isUndefOrInRange(M1, 4, 8)) {
+ S0 = (SM_SentinelUndef == M0 ? -1 : M0 & 3);
+ S1 = (SM_SentinelUndef == M1 ? -1 : M1 & 3);
+ return V2;
+ }
+
+ return SDValue();
+ };
+
+ int ShufMask[4] = {-1, -1, -1, -1};
+ SDValue Lo = MatchHalf(0, ShufMask[0], ShufMask[1]);
+ SDValue Hi = MatchHalf(2, ShufMask[2], ShufMask[3]);
+
+ if (Lo && Hi) {
+ V1 = Lo;
+ V2 = Hi;
+ Shuffle = X86ISD::SHUFP;
+ ShuffleVT = MaskVT;
+ PermuteImm = getV4X86ShuffleImm(ShufMask);
+ return true;
+ }
+ }
+ }
+
return false;
}
@@ -25055,33 +26751,44 @@ static bool matchBinaryVectorShuffle(MVT SrcVT, ArrayRef<int> Mask,
/// into either a single instruction if there is a special purpose instruction
/// for this operation, or into a PSHUFB instruction which is a fully general
/// instruction but should only be used to replace chains over a certain depth.
-static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
+static bool combineX86ShuffleChain(ArrayRef<SDValue> Inputs, SDValue Root,
ArrayRef<int> BaseMask, int Depth,
bool HasVariableMask, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
assert(!BaseMask.empty() && "Cannot combine an empty shuffle mask!");
+ assert((Inputs.size() == 1 || Inputs.size() == 2) &&
+ "Unexpected number of shuffle inputs!");
- // Find the operand that enters the chain. Note that multiple uses are OK
- // here, we're not going to remove the operand we find.
- Input = peekThroughBitcasts(Input);
+ // Find the inputs that enter the chain. Note that multiple uses are OK
+ // here, we're not going to remove the operands we find.
+ bool UnaryShuffle = (Inputs.size() == 1);
+ SDValue V1 = peekThroughBitcasts(Inputs[0]);
+ SDValue V2 = (UnaryShuffle ? V1 : peekThroughBitcasts(Inputs[1]));
- MVT VT = Input.getSimpleValueType();
+ MVT VT1 = V1.getSimpleValueType();
+ MVT VT2 = V2.getSimpleValueType();
MVT RootVT = Root.getSimpleValueType();
- SDLoc DL(Root);
+ assert(VT1.getSizeInBits() == RootVT.getSizeInBits() &&
+ VT2.getSizeInBits() == RootVT.getSizeInBits() &&
+ "Vector size mismatch");
+ SDLoc DL(Root);
SDValue Res;
unsigned NumBaseMaskElts = BaseMask.size();
if (NumBaseMaskElts == 1) {
assert(BaseMask[0] == 0 && "Invalid shuffle index found!");
- DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Input),
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, V1),
/*AddTo*/ true);
return true;
}
unsigned RootSizeInBits = RootVT.getSizeInBits();
+ unsigned NumRootElts = RootVT.getVectorNumElements();
unsigned BaseMaskEltSizeInBits = RootSizeInBits / NumBaseMaskElts;
+ bool FloatDomain = VT1.isFloatingPoint() || VT2.isFloatingPoint() ||
+ (RootVT.is256BitVector() && !Subtarget.hasAVX2());
// Don't combine if we are a AVX512/EVEX target and the mask element size
// is different from the root element size - this would prevent writemasks
@@ -25089,26 +26796,25 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
// TODO - this currently prevents all lane shuffles from occurring.
// TODO - check for writemasks usage instead of always preventing combining.
// TODO - attempt to narrow Mask back to writemask size.
- if (RootVT.getScalarSizeInBits() != BaseMaskEltSizeInBits &&
- (RootSizeInBits == 512 ||
- (Subtarget.hasVLX() && RootSizeInBits >= 128))) {
+ bool IsEVEXShuffle =
+ RootSizeInBits == 512 || (Subtarget.hasVLX() && RootSizeInBits >= 128);
+ if (IsEVEXShuffle && (RootVT.getScalarSizeInBits() != BaseMaskEltSizeInBits))
return false;
- }
// TODO - handle 128/256-bit lane shuffles of 512-bit vectors.
// Handle 128-bit lane shuffles of 256-bit vectors.
- if (VT.is256BitVector() && NumBaseMaskElts == 2 &&
+ // TODO - this should support binary shuffles.
+ if (UnaryShuffle && RootVT.is256BitVector() && NumBaseMaskElts == 2 &&
!isSequentialOrUndefOrZeroInRange(BaseMask, 0, 2, 0)) {
if (Depth == 1 && Root.getOpcode() == X86ISD::VPERM2X128)
return false; // Nothing to do!
- MVT ShuffleVT = (VT.isFloatingPoint() || !Subtarget.hasAVX2() ? MVT::v4f64
- : MVT::v4i64);
+ MVT ShuffleVT = (FloatDomain ? MVT::v4f64 : MVT::v4i64);
unsigned PermMask = 0;
PermMask |= ((BaseMask[0] < 0 ? 0x8 : (BaseMask[0] & 1)) << 0);
PermMask |= ((BaseMask[1] < 0 ? 0x8 : (BaseMask[1] & 1)) << 4);
- Res = DAG.getBitcast(ShuffleVT, Input);
+ Res = DAG.getBitcast(ShuffleVT, V1);
DCI.AddToWorklist(Res.getNode());
Res = DAG.getNode(X86ISD::VPERM2X128, DL, ShuffleVT, Res,
DAG.getUNDEF(ShuffleVT),
@@ -25134,144 +26840,234 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
unsigned MaskEltSizeInBits = RootSizeInBits / NumMaskElts;
// Determine the effective mask value type.
- bool FloatDomain =
- (VT.isFloatingPoint() || (VT.is256BitVector() && !Subtarget.hasAVX2())) &&
- (32 <= MaskEltSizeInBits);
+ FloatDomain &= (32 <= MaskEltSizeInBits);
MVT MaskVT = FloatDomain ? MVT::getFloatingPointVT(MaskEltSizeInBits)
: MVT::getIntegerVT(MaskEltSizeInBits);
MaskVT = MVT::getVectorVT(MaskVT, NumMaskElts);
+ // Only allow legal mask types.
+ if (!DAG.getTargetLoweringInfo().isTypeLegal(MaskVT))
+ return false;
+
// Attempt to match the mask against known shuffle patterns.
- MVT ShuffleVT;
+ MVT ShuffleSrcVT, ShuffleVT;
unsigned Shuffle, PermuteImm;
- if (matchUnaryVectorShuffle(VT, Mask, Subtarget, Shuffle, ShuffleVT)) {
- if (Depth == 1 && Root.getOpcode() == Shuffle)
- return false; // Nothing to do!
- Res = DAG.getBitcast(ShuffleVT, Input);
- DCI.AddToWorklist(Res.getNode());
- Res = DAG.getNode(Shuffle, DL, ShuffleVT, Res);
- DCI.AddToWorklist(Res.getNode());
- DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
- /*AddTo*/ true);
- return true;
+ if (UnaryShuffle) {
+ // If we are shuffling a X86ISD::VZEXT_LOAD then we can use the load
+ // directly if we don't shuffle the lower element and we shuffle the upper
+ // (zero) elements within themselves.
+ if (V1.getOpcode() == X86ISD::VZEXT_LOAD &&
+ (V1.getScalarValueSizeInBits() % MaskEltSizeInBits) == 0) {
+ unsigned Scale = V1.getScalarValueSizeInBits() / MaskEltSizeInBits;
+ ArrayRef<int> HiMask(Mask.data() + Scale, NumMaskElts - Scale);
+ if (isSequentialOrUndefInRange(Mask, 0, Scale, 0) &&
+ isUndefOrZeroOrInRange(HiMask, Scale, NumMaskElts)) {
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, V1),
+ /*AddTo*/ true);
+ return true;
+ }
+ }
+
+ if (matchUnaryVectorShuffle(MaskVT, Mask, FloatDomain, Subtarget, Shuffle,
+ ShuffleSrcVT, ShuffleVT)) {
+ if (Depth == 1 && Root.getOpcode() == Shuffle)
+ return false; // Nothing to do!
+ if (IsEVEXShuffle && (NumRootElts != ShuffleVT.getVectorNumElements()))
+ return false; // AVX512 Writemask clash.
+ Res = DAG.getBitcast(ShuffleSrcVT, V1);
+ DCI.AddToWorklist(Res.getNode());
+ Res = DAG.getNode(Shuffle, DL, ShuffleVT, Res);
+ DCI.AddToWorklist(Res.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
+ /*AddTo*/ true);
+ return true;
+ }
+
+ if (matchUnaryPermuteVectorShuffle(MaskVT, Mask, FloatDomain, Subtarget,
+ Shuffle, ShuffleVT, PermuteImm)) {
+ if (Depth == 1 && Root.getOpcode() == Shuffle)
+ return false; // Nothing to do!
+ if (IsEVEXShuffle && (NumRootElts != ShuffleVT.getVectorNumElements()))
+ return false; // AVX512 Writemask clash.
+ Res = DAG.getBitcast(ShuffleVT, V1);
+ DCI.AddToWorklist(Res.getNode());
+ Res = DAG.getNode(Shuffle, DL, ShuffleVT, Res,
+ DAG.getConstant(PermuteImm, DL, MVT::i8));
+ DCI.AddToWorklist(Res.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
+ /*AddTo*/ true);
+ return true;
+ }
}
- if (matchPermuteVectorShuffle(VT, Mask, Subtarget, Shuffle, ShuffleVT,
- PermuteImm)) {
+ if (matchBinaryVectorShuffle(MaskVT, Mask, FloatDomain, V1, V2, Subtarget,
+ Shuffle, ShuffleVT, UnaryShuffle)) {
if (Depth == 1 && Root.getOpcode() == Shuffle)
return false; // Nothing to do!
- Res = DAG.getBitcast(ShuffleVT, Input);
- DCI.AddToWorklist(Res.getNode());
- Res = DAG.getNode(Shuffle, DL, ShuffleVT, Res,
- DAG.getConstant(PermuteImm, DL, MVT::i8));
+ if (IsEVEXShuffle && (NumRootElts != ShuffleVT.getVectorNumElements()))
+ return false; // AVX512 Writemask clash.
+ V1 = DAG.getBitcast(ShuffleVT, V1);
+ DCI.AddToWorklist(V1.getNode());
+ V2 = DAG.getBitcast(ShuffleVT, V2);
+ DCI.AddToWorklist(V2.getNode());
+ Res = DAG.getNode(Shuffle, DL, ShuffleVT, V1, V2);
DCI.AddToWorklist(Res.getNode());
DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
/*AddTo*/ true);
return true;
}
- if (matchBinaryVectorShuffle(VT, Mask, Shuffle, ShuffleVT)) {
+ if (matchBinaryPermuteVectorShuffle(MaskVT, Mask, FloatDomain, V1, V2, DL,
+ DAG, Subtarget, Shuffle, ShuffleVT,
+ PermuteImm)) {
if (Depth == 1 && Root.getOpcode() == Shuffle)
return false; // Nothing to do!
- Res = DAG.getBitcast(ShuffleVT, Input);
- DCI.AddToWorklist(Res.getNode());
- Res = DAG.getNode(Shuffle, DL, ShuffleVT, Res, Res);
+ if (IsEVEXShuffle && (NumRootElts != ShuffleVT.getVectorNumElements()))
+ return false; // AVX512 Writemask clash.
+ V1 = DAG.getBitcast(ShuffleVT, V1);
+ DCI.AddToWorklist(V1.getNode());
+ V2 = DAG.getBitcast(ShuffleVT, V2);
+ DCI.AddToWorklist(V2.getNode());
+ Res = DAG.getNode(Shuffle, DL, ShuffleVT, V1, V2,
+ DAG.getConstant(PermuteImm, DL, MVT::i8));
DCI.AddToWorklist(Res.getNode());
DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
/*AddTo*/ true);
return true;
}
- // Attempt to blend with zero.
- if (NumMaskElts <= 8 &&
- ((Subtarget.hasSSE41() && VT.is128BitVector()) ||
- (Subtarget.hasAVX() && VT.is256BitVector()))) {
- // Convert VT to a type compatible with X86ISD::BLENDI.
- // TODO - add 16i16 support (requires lane duplication).
- MVT ShuffleVT = MaskVT;
- if (Subtarget.hasAVX2()) {
- if (ShuffleVT == MVT::v4i64)
- ShuffleVT = MVT::v8i32;
- else if (ShuffleVT == MVT::v2i64)
- ShuffleVT = MVT::v4i32;
- } else {
- if (ShuffleVT == MVT::v2i64 || ShuffleVT == MVT::v4i32)
- ShuffleVT = MVT::v8i16;
- else if (ShuffleVT == MVT::v4i64)
- ShuffleVT = MVT::v4f64;
- else if (ShuffleVT == MVT::v8i32)
- ShuffleVT = MVT::v8f32;
- }
-
- if (isSequentialOrUndefOrZeroInRange(Mask, /*Pos*/ 0, /*Size*/ NumMaskElts,
- /*Low*/ 0) &&
- NumMaskElts <= ShuffleVT.getVectorNumElements()) {
- unsigned BlendMask = 0;
- unsigned ShuffleSize = ShuffleVT.getVectorNumElements();
- unsigned MaskRatio = ShuffleSize / NumMaskElts;
-
- if (Depth == 1 && Root.getOpcode() == X86ISD::BLENDI)
- return false;
-
- for (unsigned i = 0; i != ShuffleSize; ++i)
- if (Mask[i / MaskRatio] < 0)
- BlendMask |= 1u << i;
+ // Don't try to re-form single instruction chains under any circumstances now
+ // that we've done encoding canonicalization for them.
+ if (Depth < 2)
+ return false;
- SDValue Zero = getZeroVector(ShuffleVT, Subtarget, DAG, DL);
- Res = DAG.getBitcast(ShuffleVT, Input);
+ bool MaskContainsZeros =
+ any_of(Mask, [](int M) { return M == SM_SentinelZero; });
+
+ if (is128BitLaneCrossingShuffleMask(MaskVT, Mask)) {
+ // If we have a single input lane-crossing shuffle then lower to VPERMV.
+ if (UnaryShuffle && (Depth >= 3 || HasVariableMask) && !MaskContainsZeros &&
+ ((Subtarget.hasAVX2() &&
+ (MaskVT == MVT::v8f32 || MaskVT == MVT::v8i32)) ||
+ (Subtarget.hasAVX512() &&
+ (MaskVT == MVT::v8f64 || MaskVT == MVT::v8i64 ||
+ MaskVT == MVT::v16f32 || MaskVT == MVT::v16i32)) ||
+ (Subtarget.hasBWI() && MaskVT == MVT::v32i16) ||
+ (Subtarget.hasBWI() && Subtarget.hasVLX() && MaskVT == MVT::v16i16) ||
+ (Subtarget.hasVBMI() && MaskVT == MVT::v64i8) ||
+ (Subtarget.hasVBMI() && Subtarget.hasVLX() && MaskVT == MVT::v32i8))) {
+ MVT VPermMaskSVT = MVT::getIntegerVT(MaskEltSizeInBits);
+ MVT VPermMaskVT = MVT::getVectorVT(VPermMaskSVT, NumMaskElts);
+ SDValue VPermMask = getConstVector(Mask, VPermMaskVT, DAG, DL, true);
+ DCI.AddToWorklist(VPermMask.getNode());
+ Res = DAG.getBitcast(MaskVT, V1);
DCI.AddToWorklist(Res.getNode());
- Res = DAG.getNode(X86ISD::BLENDI, DL, ShuffleVT, Res, Zero,
- DAG.getConstant(BlendMask, DL, MVT::i8));
+ Res = DAG.getNode(X86ISD::VPERMV, DL, MaskVT, VPermMask, Res);
DCI.AddToWorklist(Res.getNode());
DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
/*AddTo*/ true);
return true;
}
- }
- // Attempt to combine to INSERTPS.
- if (Subtarget.hasSSE41() && NumMaskElts == 4 &&
- (VT == MVT::v2f64 || VT == MVT::v4f32)) {
- SmallBitVector Zeroable(4, false);
- for (unsigned i = 0; i != NumMaskElts; ++i)
- if (Mask[i] < 0)
- Zeroable[i] = true;
+ // Lower a unary+zero lane-crossing shuffle as VPERMV3 with a zero
+ // vector as the second source.
+ if (UnaryShuffle && (Depth >= 3 || HasVariableMask) &&
+ ((Subtarget.hasAVX512() &&
+ (MaskVT == MVT::v8f64 || MaskVT == MVT::v8i64 ||
+ MaskVT == MVT::v16f32 || MaskVT == MVT::v16i32)) ||
+ (Subtarget.hasVLX() &&
+ (MaskVT == MVT::v4f64 || MaskVT == MVT::v4i64 ||
+ MaskVT == MVT::v8f32 || MaskVT == MVT::v8i32)) ||
+ (Subtarget.hasBWI() && MaskVT == MVT::v32i16) ||
+ (Subtarget.hasBWI() && Subtarget.hasVLX() && MaskVT == MVT::v16i16) ||
+ (Subtarget.hasVBMI() && MaskVT == MVT::v64i8) ||
+ (Subtarget.hasVBMI() && Subtarget.hasVLX() && MaskVT == MVT::v32i8))) {
+ // Adjust shuffle mask - replace SM_SentinelZero with second source index.
+ for (unsigned i = 0; i != NumMaskElts; ++i)
+ if (Mask[i] == SM_SentinelZero)
+ Mask[i] = NumMaskElts + i;
+
+ MVT VPermMaskSVT = MVT::getIntegerVT(MaskEltSizeInBits);
+ MVT VPermMaskVT = MVT::getVectorVT(VPermMaskSVT, NumMaskElts);
+ SDValue VPermMask = getConstVector(Mask, VPermMaskVT, DAG, DL, true);
+ DCI.AddToWorklist(VPermMask.getNode());
+ Res = DAG.getBitcast(MaskVT, V1);
+ DCI.AddToWorklist(Res.getNode());
+ SDValue Zero = getZeroVector(MaskVT, Subtarget, DAG, DL);
+ DCI.AddToWorklist(Zero.getNode());
+ Res = DAG.getNode(X86ISD::VPERMV3, DL, MaskVT, Res, VPermMask, Zero);
+ DCI.AddToWorklist(Res.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
+ /*AddTo*/ true);
+ return true;
+ }
- unsigned InsertPSMask;
- SDValue V1 = Input, V2 = Input;
- if (Zeroable.any() && matchVectorShuffleAsInsertPS(V1, V2, InsertPSMask,
- Zeroable, Mask, DAG)) {
- if (Depth == 1 && Root.getOpcode() == X86ISD::INSERTPS)
- return false; // Nothing to do!
- V1 = DAG.getBitcast(MVT::v4f32, V1);
+ // If we have a dual input lane-crossing shuffle then lower to VPERMV3.
+ if ((Depth >= 3 || HasVariableMask) && !MaskContainsZeros &&
+ ((Subtarget.hasAVX512() &&
+ (MaskVT == MVT::v8f64 || MaskVT == MVT::v8i64 ||
+ MaskVT == MVT::v16f32 || MaskVT == MVT::v16i32)) ||
+ (Subtarget.hasVLX() &&
+ (MaskVT == MVT::v4f64 || MaskVT == MVT::v4i64 ||
+ MaskVT == MVT::v8f32 || MaskVT == MVT::v8i32)) ||
+ (Subtarget.hasBWI() && MaskVT == MVT::v32i16) ||
+ (Subtarget.hasBWI() && Subtarget.hasVLX() && MaskVT == MVT::v16i16) ||
+ (Subtarget.hasVBMI() && MaskVT == MVT::v64i8) ||
+ (Subtarget.hasVBMI() && Subtarget.hasVLX() && MaskVT == MVT::v32i8))) {
+ MVT VPermMaskSVT = MVT::getIntegerVT(MaskEltSizeInBits);
+ MVT VPermMaskVT = MVT::getVectorVT(VPermMaskSVT, NumMaskElts);
+ SDValue VPermMask = getConstVector(Mask, VPermMaskVT, DAG, DL, true);
+ DCI.AddToWorklist(VPermMask.getNode());
+ V1 = DAG.getBitcast(MaskVT, V1);
DCI.AddToWorklist(V1.getNode());
- V2 = DAG.getBitcast(MVT::v4f32, V2);
+ V2 = DAG.getBitcast(MaskVT, V2);
DCI.AddToWorklist(V2.getNode());
- Res = DAG.getNode(X86ISD::INSERTPS, DL, MVT::v4f32, V1, V2,
- DAG.getConstant(InsertPSMask, DL, MVT::i8));
+ Res = DAG.getNode(X86ISD::VPERMV3, DL, MaskVT, V1, VPermMask, V2);
DCI.AddToWorklist(Res.getNode());
DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
/*AddTo*/ true);
return true;
}
- }
-
- // Don't try to re-form single instruction chains under any circumstances now
- // that we've done encoding canonicalization for them.
- if (Depth < 2)
- return false;
-
- if (is128BitLaneCrossingShuffleMask(MaskVT, Mask))
return false;
+ }
- bool MaskContainsZeros =
- llvm::any_of(Mask, [](int M) { return M == SM_SentinelZero; });
+ // See if we can combine a single input shuffle with zeros to a bit-mask,
+ // which is much simpler than any shuffle.
+ if (UnaryShuffle && MaskContainsZeros && (Depth >= 3 || HasVariableMask) &&
+ isSequentialOrUndefOrZeroInRange(Mask, 0, NumMaskElts, 0) &&
+ DAG.getTargetLoweringInfo().isTypeLegal(MaskVT)) {
+ APInt Zero = APInt::getNullValue(MaskEltSizeInBits);
+ APInt AllOnes = APInt::getAllOnesValue(MaskEltSizeInBits);
+ SmallBitVector UndefElts(NumMaskElts, false);
+ SmallVector<APInt, 64> EltBits(NumMaskElts, Zero);
+ for (unsigned i = 0; i != NumMaskElts; ++i) {
+ int M = Mask[i];
+ if (M == SM_SentinelUndef) {
+ UndefElts[i] = true;
+ continue;
+ }
+ if (M == SM_SentinelZero)
+ continue;
+ EltBits[i] = AllOnes;
+ }
+ SDValue BitMask = getConstVector(EltBits, UndefElts, MaskVT, DAG, DL);
+ DCI.AddToWorklist(BitMask.getNode());
+ Res = DAG.getBitcast(MaskVT, V1);
+ DCI.AddToWorklist(Res.getNode());
+ unsigned AndOpcode =
+ FloatDomain ? unsigned(X86ISD::FAND) : unsigned(ISD::AND);
+ Res = DAG.getNode(AndOpcode, DL, MaskVT, Res, BitMask);
+ DCI.AddToWorklist(Res.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
+ /*AddTo*/ true);
+ return true;
+ }
// If we have a single input shuffle with different shuffle patterns in the
// the 128-bit lanes use the variable mask to VPERMILPS.
// TODO Combine other mask types at higher depths.
- if (HasVariableMask && !MaskContainsZeros &&
+ if (UnaryShuffle && HasVariableMask && !MaskContainsZeros &&
((MaskVT == MVT::v8f32 && Subtarget.hasAVX()) ||
(MaskVT == MVT::v16f32 && Subtarget.hasAVX512()))) {
SmallVector<SDValue, 16> VPermIdx;
@@ -25283,7 +27079,7 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
MVT VPermMaskVT = MVT::getVectorVT(MVT::i32, NumMaskElts);
SDValue VPermMask = DAG.getBuildVector(VPermMaskVT, DL, VPermIdx);
DCI.AddToWorklist(VPermMask.getNode());
- Res = DAG.getBitcast(MaskVT, Input);
+ Res = DAG.getBitcast(MaskVT, V1);
DCI.AddToWorklist(Res.getNode());
Res = DAG.getNode(X86ISD::VPERMILPV, DL, MaskVT, Res, VPermMask);
DCI.AddToWorklist(Res.getNode());
@@ -25292,17 +27088,60 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
return true;
}
+ // With XOP, binary shuffles of 128/256-bit floating point vectors can combine
+ // to VPERMIL2PD/VPERMIL2PS.
+ if ((Depth >= 3 || HasVariableMask) && Subtarget.hasXOP() &&
+ (MaskVT == MVT::v2f64 || MaskVT == MVT::v4f64 || MaskVT == MVT::v4f32 ||
+ MaskVT == MVT::v8f32)) {
+ // VPERMIL2 Operation.
+ // Bits[3] - Match Bit.
+ // Bits[2:1] - (Per Lane) PD Shuffle Mask.
+ // Bits[2:0] - (Per Lane) PS Shuffle Mask.
+ unsigned NumLanes = MaskVT.getSizeInBits() / 128;
+ unsigned NumEltsPerLane = NumMaskElts / NumLanes;
+ SmallVector<int, 8> VPerm2Idx;
+ MVT MaskIdxSVT = MVT::getIntegerVT(MaskVT.getScalarSizeInBits());
+ MVT MaskIdxVT = MVT::getVectorVT(MaskIdxSVT, NumMaskElts);
+ unsigned M2ZImm = 0;
+ for (int M : Mask) {
+ if (M == SM_SentinelUndef) {
+ VPerm2Idx.push_back(-1);
+ continue;
+ }
+ if (M == SM_SentinelZero) {
+ M2ZImm = 2;
+ VPerm2Idx.push_back(8);
+ continue;
+ }
+ int Index = (M % NumEltsPerLane) + ((M / NumMaskElts) * NumEltsPerLane);
+ Index = (MaskVT.getScalarSizeInBits() == 64 ? Index << 1 : Index);
+ VPerm2Idx.push_back(Index);
+ }
+ V1 = DAG.getBitcast(MaskVT, V1);
+ DCI.AddToWorklist(V1.getNode());
+ V2 = DAG.getBitcast(MaskVT, V2);
+ DCI.AddToWorklist(V2.getNode());
+ SDValue VPerm2MaskOp = getConstVector(VPerm2Idx, MaskIdxVT, DAG, DL, true);
+ DCI.AddToWorklist(VPerm2MaskOp.getNode());
+ Res = DAG.getNode(X86ISD::VPERMIL2, DL, MaskVT, V1, V2, VPerm2MaskOp,
+ DAG.getConstant(M2ZImm, DL, MVT::i8));
+ DCI.AddToWorklist(Res.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
+ /*AddTo*/ true);
+ return true;
+ }
+
// If we have 3 or more shuffle instructions or a chain involving a variable
// mask, we can replace them with a single PSHUFB instruction profitably.
// Intel's manuals suggest only using PSHUFB if doing so replacing 5
// instructions, but in practice PSHUFB tends to be *very* fast so we're
// more aggressive.
- if ((Depth >= 3 || HasVariableMask) &&
- ((VT.is128BitVector() && Subtarget.hasSSSE3()) ||
- (VT.is256BitVector() && Subtarget.hasAVX2()) ||
- (VT.is512BitVector() && Subtarget.hasBWI()))) {
+ if (UnaryShuffle && (Depth >= 3 || HasVariableMask) &&
+ ((RootVT.is128BitVector() && Subtarget.hasSSSE3()) ||
+ (RootVT.is256BitVector() && Subtarget.hasAVX2()) ||
+ (RootVT.is512BitVector() && Subtarget.hasBWI()))) {
SmallVector<SDValue, 16> PSHUFBMask;
- int NumBytes = VT.getSizeInBits() / 8;
+ int NumBytes = RootVT.getSizeInBits() / 8;
int Ratio = NumBytes / NumMaskElts;
for (int i = 0; i < NumBytes; ++i) {
int M = Mask[i / Ratio];
@@ -25319,7 +27158,7 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
PSHUFBMask.push_back(DAG.getConstant(M, DL, MVT::i8));
}
MVT ByteVT = MVT::getVectorVT(MVT::i8, NumBytes);
- Res = DAG.getBitcast(ByteVT, Input);
+ Res = DAG.getBitcast(ByteVT, V1);
DCI.AddToWorklist(Res.getNode());
SDValue PSHUFBMaskOp = DAG.getBuildVector(ByteVT, DL, PSHUFBMask);
DCI.AddToWorklist(PSHUFBMaskOp.getNode());
@@ -25330,10 +27169,135 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
return true;
}
+ // With XOP, if we have a 128-bit binary input shuffle we can always combine
+ // to VPPERM. We match the depth requirement of PSHUFB - VPPERM is never
+ // slower than PSHUFB on targets that support both.
+ if ((Depth >= 3 || HasVariableMask) && RootVT.is128BitVector() &&
+ Subtarget.hasXOP()) {
+ // VPPERM Mask Operation
+ // Bits[4:0] - Byte Index (0 - 31)
+ // Bits[7:5] - Permute Operation (0 - Source byte, 4 - ZERO)
+ SmallVector<SDValue, 16> VPPERMMask;
+ int NumBytes = 16;
+ int Ratio = NumBytes / NumMaskElts;
+ for (int i = 0; i < NumBytes; ++i) {
+ int M = Mask[i / Ratio];
+ if (M == SM_SentinelUndef) {
+ VPPERMMask.push_back(DAG.getUNDEF(MVT::i8));
+ continue;
+ }
+ if (M == SM_SentinelZero) {
+ VPPERMMask.push_back(DAG.getConstant(128, DL, MVT::i8));
+ continue;
+ }
+ M = Ratio * M + i % Ratio;
+ VPPERMMask.push_back(DAG.getConstant(M, DL, MVT::i8));
+ }
+ MVT ByteVT = MVT::v16i8;
+ V1 = DAG.getBitcast(ByteVT, V1);
+ DCI.AddToWorklist(V1.getNode());
+ V2 = DAG.getBitcast(ByteVT, V2);
+ DCI.AddToWorklist(V2.getNode());
+ SDValue VPPERMMaskOp = DAG.getBuildVector(ByteVT, DL, VPPERMMask);
+ DCI.AddToWorklist(VPPERMMaskOp.getNode());
+ Res = DAG.getNode(X86ISD::VPPERM, DL, ByteVT, V1, V2, VPPERMMaskOp);
+ DCI.AddToWorklist(Res.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(RootVT, Res),
+ /*AddTo*/ true);
+ return true;
+ }
+
// Failed to find any combines.
return false;
}
+// Attempt to constant fold all of the constant source ops.
+// Returns true if the entire shuffle is folded to a constant.
+// TODO: Extend this to merge multiple constant Ops and update the mask.
+static bool combineX86ShufflesConstants(const SmallVectorImpl<SDValue> &Ops,
+ ArrayRef<int> Mask, SDValue Root,
+ bool HasVariableMask, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
+ MVT VT = Root.getSimpleValueType();
+
+ unsigned SizeInBits = VT.getSizeInBits();
+ unsigned NumMaskElts = Mask.size();
+ unsigned MaskSizeInBits = SizeInBits / NumMaskElts;
+ unsigned NumOps = Ops.size();
+
+ // Extract constant bits from each source op.
+ bool OneUseConstantOp = false;
+ SmallVector<SmallBitVector, 4> UndefEltsOps(NumOps);
+ SmallVector<SmallVector<APInt, 8>, 4> RawBitsOps(NumOps);
+ for (unsigned i = 0; i != NumOps; ++i) {
+ SDValue SrcOp = Ops[i];
+ OneUseConstantOp |= SrcOp.hasOneUse();
+ if (!getTargetConstantBitsFromNode(SrcOp, MaskSizeInBits, UndefEltsOps[i],
+ RawBitsOps[i]))
+ return false;
+ }
+
+ // Only fold if at least one of the constants is only used once or
+ // the combined shuffle has included a variable mask shuffle, this
+ // is to avoid constant pool bloat.
+ if (!OneUseConstantOp && !HasVariableMask)
+ return false;
+
+ // Shuffle the constant bits according to the mask.
+ SmallBitVector UndefElts(NumMaskElts, false);
+ SmallBitVector ZeroElts(NumMaskElts, false);
+ SmallBitVector ConstantElts(NumMaskElts, false);
+ SmallVector<APInt, 8> ConstantBitData(NumMaskElts,
+ APInt::getNullValue(MaskSizeInBits));
+ for (unsigned i = 0; i != NumMaskElts; ++i) {
+ int M = Mask[i];
+ if (M == SM_SentinelUndef) {
+ UndefElts[i] = true;
+ continue;
+ } else if (M == SM_SentinelZero) {
+ ZeroElts[i] = true;
+ continue;
+ }
+ assert(0 <= M && M < (int)(NumMaskElts * NumOps));
+
+ unsigned SrcOpIdx = (unsigned)M / NumMaskElts;
+ unsigned SrcMaskIdx = (unsigned)M % NumMaskElts;
+
+ auto &SrcUndefElts = UndefEltsOps[SrcOpIdx];
+ if (SrcUndefElts[SrcMaskIdx]) {
+ UndefElts[i] = true;
+ continue;
+ }
+
+ auto &SrcEltBits = RawBitsOps[SrcOpIdx];
+ APInt &Bits = SrcEltBits[SrcMaskIdx];
+ if (!Bits) {
+ ZeroElts[i] = true;
+ continue;
+ }
+
+ ConstantElts[i] = true;
+ ConstantBitData[i] = Bits;
+ }
+ assert((UndefElts | ZeroElts | ConstantElts).count() == NumMaskElts);
+
+ // Create the constant data.
+ MVT MaskSVT;
+ if (VT.isFloatingPoint() && (MaskSizeInBits == 32 || MaskSizeInBits == 64))
+ MaskSVT = MVT::getFloatingPointVT(MaskSizeInBits);
+ else
+ MaskSVT = MVT::getIntegerVT(MaskSizeInBits);
+
+ MVT MaskVT = MVT::getVectorVT(MaskSVT, NumMaskElts);
+
+ SDLoc DL(Root);
+ SDValue CstOp = getConstVector(ConstantBitData, UndefElts, MaskVT, DAG, DL);
+ DCI.AddToWorklist(CstOp.getNode());
+ DCI.CombineTo(Root.getNode(), DAG.getBitcast(VT, CstOp));
+ return true;
+}
+
/// \brief Fully generic combining of x86 shuffle instructions.
///
/// This should be the last combine run over the x86 shuffle instructions. Once
@@ -25350,7 +27314,7 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
/// instructions, and replace them with the slightly more expensive SSSE3
/// PSHUFB instruction if available. We do this as the last combining step
/// to ensure we avoid using PSHUFB if we can implement the shuffle with
-/// a suitable short sequence of other instructions. The PHUFB will either
+/// a suitable short sequence of other instructions. The PSHUFB will either
/// use a register or have to read from memory and so is slightly (but only
/// slightly) more expensive than the other shuffle instructions.
///
@@ -25363,7 +27327,8 @@ static bool combineX86ShuffleChain(SDValue Input, SDValue Root,
/// would simplify under the threshold for PSHUFB formation because of
/// combine-ordering. To fix this, we should do the redundant instruction
/// combining in this recursive walk.
-static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
+static bool combineX86ShufflesRecursively(ArrayRef<SDValue> SrcOps,
+ int SrcOpIndex, SDValue Root,
ArrayRef<int> RootMask,
int Depth, bool HasVariableMask,
SelectionDAG &DAG,
@@ -25375,8 +27340,8 @@ static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
return false;
// Directly rip through bitcasts to find the underlying operand.
- while (Op.getOpcode() == ISD::BITCAST && Op.getOperand(0).hasOneUse())
- Op = Op.getOperand(0);
+ SDValue Op = SrcOps[SrcOpIndex];
+ Op = peekThroughOneUseBitcasts(Op);
MVT VT = Op.getSimpleValueType();
if (!VT.isVector())
@@ -25393,8 +27358,27 @@ static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
if (!resolveTargetShuffleInputs(Op, Input0, Input1, OpMask))
return false;
- assert(VT.getVectorNumElements() == OpMask.size() &&
- "Different mask size from vector size!");
+ // Add the inputs to the Ops list, avoiding duplicates.
+ SmallVector<SDValue, 8> Ops(SrcOps.begin(), SrcOps.end());
+
+ int InputIdx0 = -1, InputIdx1 = -1;
+ for (int i = 0, e = Ops.size(); i < e; ++i) {
+ SDValue BC = peekThroughBitcasts(Ops[i]);
+ if (Input0 && BC == peekThroughBitcasts(Input0))
+ InputIdx0 = i;
+ if (Input1 && BC == peekThroughBitcasts(Input1))
+ InputIdx1 = i;
+ }
+
+ if (Input0 && InputIdx0 < 0) {
+ InputIdx0 = SrcOpIndex;
+ Ops[SrcOpIndex] = Input0;
+ }
+ if (Input1 && InputIdx1 < 0) {
+ InputIdx1 = Ops.size();
+ Ops.push_back(Input1);
+ }
+
assert(((RootMask.size() > OpMask.size() &&
RootMask.size() % OpMask.size() == 0) ||
(OpMask.size() > RootMask.size() &&
@@ -25424,6 +27408,17 @@ static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
}
int RootMaskedIdx = RootMask[RootIdx] * RootRatio + i % RootRatio;
+
+ // Just insert the scaled root mask value if it references an input other
+ // than the SrcOp we're currently inserting.
+ if ((RootMaskedIdx < (SrcOpIndex * MaskWidth)) ||
+ (((SrcOpIndex + 1) * MaskWidth) <= RootMaskedIdx)) {
+ Mask.push_back(RootMaskedIdx);
+ continue;
+ }
+
+ RootMaskedIdx %= MaskWidth;
+
int OpIdx = RootMaskedIdx / OpRatio;
if (OpMask[OpIdx] < 0) {
// The incoming lanes are zero or undef, it doesn't matter which ones we
@@ -25432,17 +27427,27 @@ static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
continue;
}
- // Ok, we have non-zero lanes, map them through.
- Mask.push_back(OpMask[OpIdx] * OpRatio +
- RootMaskedIdx % OpRatio);
+ // Ok, we have non-zero lanes, map them through to one of the Op's inputs.
+ int OpMaskedIdx = OpMask[OpIdx] * OpRatio + RootMaskedIdx % OpRatio;
+ OpMaskedIdx %= MaskWidth;
+
+ if (OpMask[OpIdx] < (int)OpMask.size()) {
+ assert(0 <= InputIdx0 && "Unknown target shuffle input");
+ OpMaskedIdx += InputIdx0 * MaskWidth;
+ } else {
+ assert(0 <= InputIdx1 && "Unknown target shuffle input");
+ OpMaskedIdx += InputIdx1 * MaskWidth;
+ }
+
+ Mask.push_back(OpMaskedIdx);
}
// Handle the all undef/zero cases early.
- if (llvm::all_of(Mask, [](int Idx) { return Idx == SM_SentinelUndef; })) {
+ if (all_of(Mask, [](int Idx) { return Idx == SM_SentinelUndef; })) {
DCI.CombineTo(Root.getNode(), DAG.getUNDEF(Root.getValueType()));
return true;
}
- if (llvm::all_of(Mask, [](int Idx) { return Idx < 0; })) {
+ if (all_of(Mask, [](int Idx) { return Idx < 0; })) {
// TODO - should we handle the mixed zero/undef case as well? Just returning
// a zero mask will lose information on undef elements possibly reducing
// future combine possibilities.
@@ -25451,30 +27456,40 @@ static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
return true;
}
- int MaskSize = Mask.size();
- bool UseInput0 = std::any_of(Mask.begin(), Mask.end(),
- [MaskSize](int Idx) { return 0 <= Idx && Idx < MaskSize; });
- bool UseInput1 = std::any_of(Mask.begin(), Mask.end(),
- [MaskSize](int Idx) { return MaskSize <= Idx; });
-
- // At the moment we can only combine unary shuffle mask cases.
- if (UseInput0 && UseInput1)
- return false;
- else if (UseInput1) {
- std::swap(Input0, Input1);
- ShuffleVectorSDNode::commuteMask(Mask);
+ // Remove unused shuffle source ops.
+ SmallVector<SDValue, 8> UsedOps;
+ for (int i = 0, e = Ops.size(); i < e; ++i) {
+ int lo = UsedOps.size() * MaskWidth;
+ int hi = lo + MaskWidth;
+ if (any_of(Mask, [lo, hi](int i) { return (lo <= i) && (i < hi); })) {
+ UsedOps.push_back(Ops[i]);
+ continue;
+ }
+ for (int &M : Mask)
+ if (lo <= M)
+ M -= MaskWidth;
}
-
- assert(Input0 && "Shuffle with no inputs detected");
+ assert(!UsedOps.empty() && "Shuffle with no inputs detected");
+ Ops = UsedOps;
HasVariableMask |= isTargetShuffleVariableMask(Op.getOpcode());
- // See if we can recurse into Input0 (if it's a target shuffle).
- if (Op->isOnlyUserOf(Input0.getNode()) &&
- combineX86ShufflesRecursively(Input0, Root, Mask, Depth + 1,
- HasVariableMask, DAG, DCI, Subtarget))
+ // See if we can recurse into each shuffle source op (if it's a target shuffle).
+ for (int i = 0, e = Ops.size(); i < e; ++i)
+ if (Ops[i].getNode()->hasOneUse() || Op->isOnlyUserOf(Ops[i].getNode()))
+ if (combineX86ShufflesRecursively(Ops, i, Root, Mask, Depth + 1,
+ HasVariableMask, DAG, DCI, Subtarget))
+ return true;
+
+ // Attempt to constant fold all of the constant source ops.
+ if (combineX86ShufflesConstants(Ops, Mask, Root, HasVariableMask, DAG, DCI,
+ Subtarget))
return true;
+ // We can only combine unary and binary shuffle mask cases.
+ if (Ops.size() > 2)
+ return false;
+
// Minor canonicalization of the accumulated shuffle mask to make it easier
// to match below. All this does is detect masks with sequential pairs of
// elements, and shrink them to the half-width mask. It does this in a loop
@@ -25485,7 +27500,14 @@ static bool combineX86ShufflesRecursively(SDValue Op, SDValue Root,
Mask = std::move(WidenedMask);
}
- return combineX86ShuffleChain(Input0, Root, Mask, Depth, HasVariableMask, DAG,
+ // Canonicalization of binary shuffle masks to improve pattern matching by
+ // commuting the inputs.
+ if (Ops.size() == 2 && canonicalizeShuffleMaskWithCommute(Mask)) {
+ ShuffleVectorSDNode::commuteMask(Mask);
+ std::swap(Ops[0], Ops[1]);
+ }
+
+ return combineX86ShuffleChain(Ops, Root, Mask, Depth, HasVariableMask, DAG,
DCI, Subtarget);
}
@@ -25612,7 +27634,7 @@ combineRedundantDWordShuffle(SDValue N, MutableArrayRef<int> Mask,
Chain.push_back(V);
- // Fallthrough!
+ LLVM_FALLTHROUGH;
case ISD::BITCAST:
V = V.getOperand(0);
continue;
@@ -25742,7 +27764,8 @@ static SDValue combineTargetShuffle(SDValue N, SelectionDAG &DAG,
MVT VT = N.getSimpleValueType();
SmallVector<int, 4> Mask;
- switch (N.getOpcode()) {
+ unsigned Opcode = N.getOpcode();
+ switch (Opcode) {
case X86ISD::PSHUFD:
case X86ISD::PSHUFLW:
case X86ISD::PSHUFHW:
@@ -25750,6 +27773,17 @@ static SDValue combineTargetShuffle(SDValue N, SelectionDAG &DAG,
assert(Mask.size() == 4);
break;
case X86ISD::UNPCKL: {
+ auto Op0 = N.getOperand(0);
+ auto Op1 = N.getOperand(1);
+ unsigned Opcode0 = Op0.getOpcode();
+ unsigned Opcode1 = Op1.getOpcode();
+
+ // Combine X86ISD::UNPCKL with 2 X86ISD::FHADD inputs into a single
+ // X86ISD::FHADD. This is generated by UINT_TO_FP v2f64 scalarization.
+ // TODO: Add other horizontal operations as required.
+ if (VT == MVT::v2f64 && Opcode0 == Opcode1 && Opcode0 == X86ISD::FHADD)
+ return DAG.getNode(Opcode0, DL, VT, Op0.getOperand(0), Op1.getOperand(0));
+
// Combine X86ISD::UNPCKL and ISD::VECTOR_SHUFFLE into X86ISD::UNPCKH, in
// which X86ISD::UNPCKL has a ISD::UNDEF operand, and ISD::VECTOR_SHUFFLE
// moves upper half elements into the lower half part. For example:
@@ -25767,9 +27801,7 @@ static SDValue combineTargetShuffle(SDValue N, SelectionDAG &DAG,
if (!VT.is128BitVector())
return SDValue();
- auto Op0 = N.getOperand(0);
- auto Op1 = N.getOperand(1);
- if (Op0.isUndef() && Op1.getNode()->getOpcode() == ISD::VECTOR_SHUFFLE) {
+ if (Op0.isUndef() && Opcode1 == ISD::VECTOR_SHUFFLE) {
ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Op1.getNode())->getMask();
unsigned NumElts = VT.getVectorNumElements();
@@ -25806,44 +27838,31 @@ static SDValue combineTargetShuffle(SDValue N, SelectionDAG &DAG,
return DAG.getNode(X86ISD::BLENDI, DL, VT, V1, V0, NewMask);
}
- // Attempt to merge blend(insertps(x,y),zero).
- if (V0.getOpcode() == X86ISD::INSERTPS ||
- V1.getOpcode() == X86ISD::INSERTPS) {
- assert(VT == MVT::v4f32 && "INSERTPS ValueType must be MVT::v4f32");
-
- // Determine which elements are known to be zero.
- SmallVector<int, 8> TargetMask;
- SmallVector<SDValue, 2> BlendOps;
- if (!setTargetShuffleZeroElements(N, TargetMask, BlendOps))
- return SDValue();
-
- // Helper function to take inner insertps node and attempt to
- // merge the blend with zero into its zero mask.
- auto MergeInsertPSAndBlend = [&](SDValue V, int Offset) {
- if (V.getOpcode() != X86ISD::INSERTPS)
- return SDValue();
- SDValue Op0 = V.getOperand(0);
- SDValue Op1 = V.getOperand(1);
- SDValue Op2 = V.getOperand(2);
- unsigned InsertPSMask = cast<ConstantSDNode>(Op2)->getZExtValue();
-
- // Check each element of the blend node's target mask - must either
- // be zeroable (and update the zero mask) or selects the element from
- // the inner insertps node.
- for (int i = 0; i != 4; ++i)
- if (TargetMask[i] < 0)
- InsertPSMask |= (1u << i);
- else if (TargetMask[i] != (i + Offset))
- return SDValue();
- return DAG.getNode(X86ISD::INSERTPS, DL, MVT::v4f32, Op0, Op1,
- DAG.getConstant(InsertPSMask, DL, MVT::i8));
- };
-
- if (SDValue V = MergeInsertPSAndBlend(V0, 0))
- return V;
- if (SDValue V = MergeInsertPSAndBlend(V1, 4))
- return V;
+ return SDValue();
+ }
+ case X86ISD::MOVSD:
+ case X86ISD::MOVSS: {
+ bool isFloat = VT.isFloatingPoint();
+ SDValue V0 = peekThroughBitcasts(N->getOperand(0));
+ SDValue V1 = peekThroughBitcasts(N->getOperand(1));
+ bool isFloat0 = V0.getSimpleValueType().isFloatingPoint();
+ bool isFloat1 = V1.getSimpleValueType().isFloatingPoint();
+ bool isZero0 = ISD::isBuildVectorAllZeros(V0.getNode());
+ bool isZero1 = ISD::isBuildVectorAllZeros(V1.getNode());
+ assert(!(isZero0 && isZero1) && "Zeroable shuffle detected.");
+
+ // We often lower to MOVSD/MOVSS from integer as well as native float
+ // types; remove unnecessary domain-crossing bitcasts if we can to make it
+ // easier to combine shuffles later on. We've already accounted for the
+ // domain switching cost when we decided to lower with it.
+ if ((isFloat != isFloat0 || isZero0) && (isFloat != isFloat1 || isZero1)) {
+ MVT NewVT = isFloat ? (X86ISD::MOVSD == Opcode ? MVT::v2i64 : MVT::v4i32)
+ : (X86ISD::MOVSD == Opcode ? MVT::v2f64 : MVT::v4f32);
+ V0 = DAG.getBitcast(NewVT, V0);
+ V1 = DAG.getBitcast(NewVT, V1);
+ return DAG.getBitcast(VT, DAG.getNode(Opcode, DL, NewVT, V0, V1));
}
+
return SDValue();
}
case X86ISD::INSERTPS: {
@@ -25976,9 +27995,7 @@ static SDValue combineTargetShuffle(SDValue N, SelectionDAG &DAG,
V.getOpcode() == X86ISD::PSHUFHW) &&
V.getOpcode() != N.getOpcode() &&
V.hasOneUse()) {
- SDValue D = V.getOperand(0);
- while (D.getOpcode() == ISD::BITCAST && D.hasOneUse())
- D = D.getOperand(0);
+ SDValue D = peekThroughOneUseBitcasts(V.getOperand(0));
if (D.getOpcode() == X86ISD::PSHUFD && D.hasOneUse()) {
SmallVector<int, 4> VMask = getPSHUFShuffleMask(V);
SmallVector<int, 4> DMask = getPSHUFShuffleMask(D);
@@ -26017,31 +28034,32 @@ static SDValue combineTargetShuffle(SDValue N, SelectionDAG &DAG,
return SDValue();
}
-/// \brief Try to combine a shuffle into a target-specific add-sub node.
+/// Returns true iff the shuffle node \p N can be replaced with ADDSUB
+/// operation. If true is returned then the operands of ADDSUB operation
+/// are written to the parameters \p Opnd0 and \p Opnd1.
///
-/// We combine this directly on the abstract vector shuffle nodes so it is
-/// easier to generically match. We also insert dummy vector shuffle nodes for
-/// the operands which explicitly discard the lanes which are unused by this
-/// operation to try to flow through the rest of the combiner the fact that
-/// they're unused.
-static SDValue combineShuffleToAddSub(SDNode *N, const X86Subtarget &Subtarget,
- SelectionDAG &DAG) {
- SDLoc DL(N);
+/// We combine shuffle to ADDSUB directly on the abstract vector shuffle nodes
+/// so it is easier to generically match. We also insert dummy vector shuffle
+/// nodes for the operands which explicitly discard the lanes which are unused
+/// by this operation to try to flow through the rest of the combiner
+/// the fact that they're unused.
+static bool isAddSub(SDNode *N, const X86Subtarget &Subtarget,
+ SDValue &Opnd0, SDValue &Opnd1) {
+
EVT VT = N->getValueType(0);
if ((!Subtarget.hasSSE3() || (VT != MVT::v4f32 && VT != MVT::v2f64)) &&
- (!Subtarget.hasAVX() || (VT != MVT::v8f32 && VT != MVT::v4f64)))
- return SDValue();
+ (!Subtarget.hasAVX() || (VT != MVT::v8f32 && VT != MVT::v4f64)) &&
+ (!Subtarget.hasAVX512() || (VT != MVT::v16f32 && VT != MVT::v8f64)))
+ return false;
// We only handle target-independent shuffles.
// FIXME: It would be easy and harmless to use the target shuffle mask
// extraction tool to support more.
if (N->getOpcode() != ISD::VECTOR_SHUFFLE)
- return SDValue();
+ return false;
- auto *SVN = cast<ShuffleVectorSDNode>(N);
- SmallVector<int, 8> Mask;
- for (int M : SVN->getMask())
- Mask.push_back(M);
+ ArrayRef<int> OrigMask = cast<ShuffleVectorSDNode>(N)->getMask();
+ SmallVector<int, 16> Mask(OrigMask.begin(), OrigMask.end());
SDValue V1 = N->getOperand(0);
SDValue V2 = N->getOperand(1);
@@ -26052,27 +28070,102 @@ static SDValue combineShuffleToAddSub(SDNode *N, const X86Subtarget &Subtarget,
ShuffleVectorSDNode::commuteMask(Mask);
std::swap(V1, V2);
} else if (V1.getOpcode() != ISD::FSUB || V2.getOpcode() != ISD::FADD)
- return SDValue();
+ return false;
// If there are other uses of these operations we can't fold them.
if (!V1->hasOneUse() || !V2->hasOneUse())
- return SDValue();
+ return false;
// Ensure that both operations have the same operands. Note that we can
// commute the FADD operands.
SDValue LHS = V1->getOperand(0), RHS = V1->getOperand(1);
if ((V2->getOperand(0) != LHS || V2->getOperand(1) != RHS) &&
(V2->getOperand(0) != RHS || V2->getOperand(1) != LHS))
- return SDValue();
+ return false;
// We're looking for blends between FADD and FSUB nodes. We insist on these
// nodes being lined up in a specific expected pattern.
if (!(isShuffleEquivalent(V1, V2, Mask, {0, 3}) ||
isShuffleEquivalent(V1, V2, Mask, {0, 5, 2, 7}) ||
- isShuffleEquivalent(V1, V2, Mask, {0, 9, 2, 11, 4, 13, 6, 15})))
+ isShuffleEquivalent(V1, V2, Mask, {0, 9, 2, 11, 4, 13, 6, 15}) ||
+ isShuffleEquivalent(V1, V2, Mask, {0, 17, 2, 19, 4, 21, 6, 23,
+ 8, 25, 10, 27, 12, 29, 14, 31})))
+ return false;
+
+ Opnd0 = LHS;
+ Opnd1 = RHS;
+ return true;
+}
+
+/// \brief Try to combine a shuffle into a target-specific add-sub or
+/// mul-add-sub node.
+static SDValue combineShuffleToAddSubOrFMAddSub(SDNode *N,
+ const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) {
+ SDValue Opnd0, Opnd1;
+ if (!isAddSub(N, Subtarget, Opnd0, Opnd1))
return SDValue();
- return DAG.getNode(X86ISD::ADDSUB, DL, VT, LHS, RHS);
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ // Try to generate X86ISD::FMADDSUB node here.
+ SDValue Opnd2;
+ if (isFMAddSub(Subtarget, DAG, Opnd0, Opnd1, Opnd2))
+ return DAG.getNode(X86ISD::FMADDSUB, DL, VT, Opnd0, Opnd1, Opnd2);
+
+ // Do not generate X86ISD::ADDSUB node for 512-bit types even though
+ // the ADDSUB idiom has been successfully recognized. There are no known
+ // X86 targets with 512-bit ADDSUB instructions!
+ if (VT.is512BitVector())
+ return SDValue();
+
+ return DAG.getNode(X86ISD::ADDSUB, DL, VT, Opnd0, Opnd1);
+}
+
+// We are looking for a shuffle where both sources are concatenated with undef
+// and have a width that is half of the output's width. AVX2 has VPERMD/Q, so
+// if we can express this as a single-source shuffle, that's preferable.
+static SDValue combineShuffleOfConcatUndef(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ if (!Subtarget.hasAVX2() || !isa<ShuffleVectorSDNode>(N))
+ return SDValue();
+
+ EVT VT = N->getValueType(0);
+
+ // We only care about shuffles of 128/256-bit vectors of 32/64-bit values.
+ if (!VT.is128BitVector() && !VT.is256BitVector())
+ return SDValue();
+
+ if (VT.getVectorElementType() != MVT::i32 &&
+ VT.getVectorElementType() != MVT::i64 &&
+ VT.getVectorElementType() != MVT::f32 &&
+ VT.getVectorElementType() != MVT::f64)
+ return SDValue();
+
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+
+ // Check that both sources are concats with undef.
+ if (N0.getOpcode() != ISD::CONCAT_VECTORS ||
+ N1.getOpcode() != ISD::CONCAT_VECTORS || N0.getNumOperands() != 2 ||
+ N1.getNumOperands() != 2 || !N0.getOperand(1).isUndef() ||
+ !N1.getOperand(1).isUndef())
+ return SDValue();
+
+ // Construct the new shuffle mask. Elements from the first source retain their
+ // index, but elements from the second source no longer need to skip an undef.
+ SmallVector<int, 8> Mask;
+ int NumElts = VT.getVectorNumElements();
+
+ ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N);
+ for (int Elt : SVOp->getMask())
+ Mask.push_back(Elt < NumElts ? Elt : (Elt - NumElts / 2));
+
+ SDLoc DL(N);
+ SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, N0.getOperand(0),
+ N1.getOperand(0));
+ return DAG.getVectorShuffle(VT, DL, Concat, DAG.getUNDEF(VT), Mask);
}
static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG,
@@ -26089,14 +28182,9 @@ static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG,
// If we have legalized the vector types, look for blends of FADD and FSUB
// nodes that we can fuse into an ADDSUB node.
if (TLI.isTypeLegal(VT))
- if (SDValue AddSub = combineShuffleToAddSub(N, Subtarget, DAG))
+ if (SDValue AddSub = combineShuffleToAddSubOrFMAddSub(N, Subtarget, DAG))
return AddSub;
- // Combine 256-bit vector shuffles. This is only profitable when in AVX mode
- if (TLI.isTypeLegal(VT) && Subtarget.hasFp256() && VT.is256BitVector() &&
- N->getOpcode() == ISD::VECTOR_SHUFFLE)
- return combineShuffle256(N, DAG, DCI, Subtarget);
-
// During Type Legalization, when promoting illegal vector types,
// the backend might introduce new shuffle dag nodes and bitcasts.
//
@@ -26127,13 +28215,18 @@ static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG,
bool CanFold = false;
switch (Opcode) {
default : break;
- case ISD::ADD :
- case ISD::FADD :
- case ISD::SUB :
- case ISD::FSUB :
- case ISD::MUL :
- case ISD::FMUL :
- CanFold = true;
+ case ISD::ADD:
+ case ISD::SUB:
+ case ISD::MUL:
+ // isOperationLegal lies for integer ops on floating point types.
+ CanFold = VT.isInteger();
+ break;
+ case ISD::FADD:
+ case ISD::FSUB:
+ case ISD::FMUL:
+ // isOperationLegal lies for floating point ops on integer types.
+ CanFold = VT.isFloatingPoint();
+ break;
}
unsigned SVTNumElts = SVT.getVectorNumElements();
@@ -26162,9 +28255,18 @@ static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG,
if (SDValue LD = EltsFromConsecutiveLoads(VT, Elts, dl, DAG, true))
return LD;
+ // For AVX2, we sometimes want to combine
+ // (vector_shuffle <mask> (concat_vectors t1, undef)
+ // (concat_vectors t2, undef))
+ // Into:
+ // (vector_shuffle <mask> (concat_vectors t1, t2), undef)
+ // Since the latter can be efficiently lowered with VPERMD/VPERMQ
+ if (SDValue ShufConcat = combineShuffleOfConcatUndef(N, DAG, Subtarget))
+ return ShufConcat;
+
if (isTargetShuffle(N->getOpcode())) {
- if (SDValue Shuffle =
- combineTargetShuffle(SDValue(N, 0), DAG, DCI, Subtarget))
+ SDValue Op(N, 0);
+ if (SDValue Shuffle = combineTargetShuffle(Op, DAG, DCI, Subtarget))
return Shuffle;
// Try recursively combining arbitrary sequences of x86 shuffle
@@ -26174,8 +28276,8 @@ static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG,
// a particular chain.
SmallVector<int, 1> NonceMask; // Just a placeholder.
NonceMask.push_back(0);
- if (combineX86ShufflesRecursively(SDValue(N, 0), SDValue(N, 0), NonceMask,
- /*Depth*/ 1, /*HasPSHUFB*/ false, DAG,
+ if (combineX86ShufflesRecursively({Op}, 0, Op, NonceMask,
+ /*Depth*/ 1, /*HasVarMask*/ false, DAG,
DCI, Subtarget))
return SDValue(); // This routine will use CombineTo to replace N.
}
@@ -26305,11 +28407,10 @@ static SDValue combineBitcast(SDNode *N, SelectionDAG &DAG,
}
// Convert a bitcasted integer logic operation that has one bitcasted
- // floating-point operand and one constant operand into a floating-point
- // logic operation. This may create a load of the constant, but that is
- // cheaper than materializing the constant in an integer register and
- // transferring it to an SSE register or transferring the SSE operand to
- // integer register and back.
+ // floating-point operand into a floating-point logic operation. This may
+ // create a load of a constant, but that is cheaper than materializing the
+ // constant in an integer register and transferring it to an SSE register or
+ // transferring the SSE operand to integer register and back.
unsigned FPOpcode;
switch (N0.getOpcode()) {
case ISD::AND: FPOpcode = X86ISD::FAND; break;
@@ -26317,25 +28418,238 @@ static SDValue combineBitcast(SDNode *N, SelectionDAG &DAG,
case ISD::XOR: FPOpcode = X86ISD::FXOR; break;
default: return SDValue();
}
- if (((Subtarget.hasSSE1() && VT == MVT::f32) ||
- (Subtarget.hasSSE2() && VT == MVT::f64)) &&
- isa<ConstantSDNode>(N0.getOperand(1)) &&
- N0.getOperand(0).getOpcode() == ISD::BITCAST &&
- N0.getOperand(0).getOperand(0).getValueType() == VT) {
- SDValue N000 = N0.getOperand(0).getOperand(0);
- SDValue FPConst = DAG.getBitcast(VT, N0.getOperand(1));
- return DAG.getNode(FPOpcode, SDLoc(N0), VT, N000, FPConst);
+
+ if (!((Subtarget.hasSSE1() && VT == MVT::f32) ||
+ (Subtarget.hasSSE2() && VT == MVT::f64)))
+ return SDValue();
+
+ SDValue LogicOp0 = N0.getOperand(0);
+ SDValue LogicOp1 = N0.getOperand(1);
+ SDLoc DL0(N0);
+
+ // bitcast(logic(bitcast(X), Y)) --> logic'(X, bitcast(Y))
+ if (N0.hasOneUse() && LogicOp0.getOpcode() == ISD::BITCAST &&
+ LogicOp0.hasOneUse() && LogicOp0.getOperand(0).getValueType() == VT &&
+ !isa<ConstantSDNode>(LogicOp0.getOperand(0))) {
+ SDValue CastedOp1 = DAG.getBitcast(VT, LogicOp1);
+ return DAG.getNode(FPOpcode, DL0, VT, LogicOp0.getOperand(0), CastedOp1);
+ }
+ // bitcast(logic(X, bitcast(Y))) --> logic'(bitcast(X), Y)
+ if (N0.hasOneUse() && LogicOp1.getOpcode() == ISD::BITCAST &&
+ LogicOp1.hasOneUse() && LogicOp1.getOperand(0).getValueType() == VT &&
+ !isa<ConstantSDNode>(LogicOp1.getOperand(0))) {
+ SDValue CastedOp0 = DAG.getBitcast(VT, LogicOp0);
+ return DAG.getNode(FPOpcode, DL0, VT, LogicOp1.getOperand(0), CastedOp0);
}
return SDValue();
}
+// Match a binop + shuffle pyramid that represents a horizontal reduction over
+// the elements of a vector.
+// Returns the vector that is being reduced on, or SDValue() if a reduction
+// was not matched.
+static SDValue matchBinOpReduction(SDNode *Extract, ISD::NodeType BinOp) {
+ // The pattern must end in an extract from index 0.
+ if ((Extract->getOpcode() != ISD::EXTRACT_VECTOR_ELT) ||
+ !isNullConstant(Extract->getOperand(1)))
+ return SDValue();
+
+ unsigned Stages =
+ Log2_32(Extract->getOperand(0).getValueType().getVectorNumElements());
+
+ SDValue Op = Extract->getOperand(0);
+ // At each stage, we're looking for something that looks like:
+ // %s = shufflevector <8 x i32> %op, <8 x i32> undef,
+ // <8 x i32> <i32 2, i32 3, i32 undef, i32 undef,
+ // i32 undef, i32 undef, i32 undef, i32 undef>
+ // %a = binop <8 x i32> %op, %s
+ // Where the mask changes according to the stage. E.g. for a 3-stage pyramid,
+ // we expect something like:
+ // <4,5,6,7,u,u,u,u>
+ // <2,3,u,u,u,u,u,u>
+ // <1,u,u,u,u,u,u,u>
+ for (unsigned i = 0; i < Stages; ++i) {
+ if (Op.getOpcode() != BinOp)
+ return SDValue();
+
+ ShuffleVectorSDNode *Shuffle =
+ dyn_cast<ShuffleVectorSDNode>(Op.getOperand(0).getNode());
+ if (Shuffle) {
+ Op = Op.getOperand(1);
+ } else {
+ Shuffle = dyn_cast<ShuffleVectorSDNode>(Op.getOperand(1).getNode());
+ Op = Op.getOperand(0);
+ }
+
+ // The first operand of the shuffle should be the same as the other operand
+ // of the add.
+ if (!Shuffle || (Shuffle->getOperand(0) != Op))
+ return SDValue();
+
+ // Verify the shuffle has the expected (at this stage of the pyramid) mask.
+ for (int Index = 0, MaskEnd = 1 << i; Index < MaskEnd; ++Index)
+ if (Shuffle->getMaskElt(Index) != MaskEnd + Index)
+ return SDValue();
+ }
+
+ return Op;
+}
+
+// Given a select, detect the following pattern:
+// 1: %2 = zext <N x i8> %0 to <N x i32>
+// 2: %3 = zext <N x i8> %1 to <N x i32>
+// 3: %4 = sub nsw <N x i32> %2, %3
+// 4: %5 = icmp sgt <N x i32> %4, [0 x N] or [-1 x N]
+// 5: %6 = sub nsw <N x i32> zeroinitializer, %4
+// 6: %7 = select <N x i1> %5, <N x i32> %4, <N x i32> %6
+// This is useful as it is the input into a SAD pattern.
+static bool detectZextAbsDiff(const SDValue &Select, SDValue &Op0,
+ SDValue &Op1) {
+ // Check the condition of the select instruction is greater-than.
+ SDValue SetCC = Select->getOperand(0);
+ if (SetCC.getOpcode() != ISD::SETCC)
+ return false;
+ ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get();
+ if (CC != ISD::SETGT)
+ return false;
+
+ SDValue SelectOp1 = Select->getOperand(1);
+ SDValue SelectOp2 = Select->getOperand(2);
+
+ // The second operand of the select should be the negation of the first
+ // operand, which is implemented as 0 - SelectOp1.
+ if (!(SelectOp2.getOpcode() == ISD::SUB &&
+ ISD::isBuildVectorAllZeros(SelectOp2.getOperand(0).getNode()) &&
+ SelectOp2.getOperand(1) == SelectOp1))
+ return false;
+
+ // The first operand of SetCC is the first operand of the select, which is the
+ // difference between the two input vectors.
+ if (SetCC.getOperand(0) != SelectOp1)
+ return false;
+
+ // The second operand of the comparison can be either -1 or 0.
+ if (!(ISD::isBuildVectorAllZeros(SetCC.getOperand(1).getNode()) ||
+ ISD::isBuildVectorAllOnes(SetCC.getOperand(1).getNode())))
+ return false;
+
+ // The first operand of the select is the difference between the two input
+ // vectors.
+ if (SelectOp1.getOpcode() != ISD::SUB)
+ return false;
+
+ Op0 = SelectOp1.getOperand(0);
+ Op1 = SelectOp1.getOperand(1);
+
+ // Check if the operands of the sub are zero-extended from vectors of i8.
+ if (Op0.getOpcode() != ISD::ZERO_EXTEND ||
+ Op0.getOperand(0).getValueType().getVectorElementType() != MVT::i8 ||
+ Op1.getOpcode() != ISD::ZERO_EXTEND ||
+ Op1.getOperand(0).getValueType().getVectorElementType() != MVT::i8)
+ return false;
+
+ return true;
+}
+
+// Given two zexts of <k x i8> to <k x i32>, create a PSADBW of the inputs
+// to these zexts.
+static SDValue createPSADBW(SelectionDAG &DAG, const SDValue &Zext0,
+ const SDValue &Zext1, const SDLoc &DL) {
+
+ // Find the appropriate width for the PSADBW.
+ EVT InVT = Zext0.getOperand(0).getValueType();
+ unsigned RegSize = std::max(128u, InVT.getSizeInBits());
+
+ // "Zero-extend" the i8 vectors. This is not a per-element zext, rather we
+ // fill in the missing vector elements with 0.
+ unsigned NumConcat = RegSize / InVT.getSizeInBits();
+ SmallVector<SDValue, 16> Ops(NumConcat, DAG.getConstant(0, DL, InVT));
+ Ops[0] = Zext0.getOperand(0);
+ MVT ExtendedVT = MVT::getVectorVT(MVT::i8, RegSize / 8);
+ SDValue SadOp0 = DAG.getNode(ISD::CONCAT_VECTORS, DL, ExtendedVT, Ops);
+ Ops[0] = Zext1.getOperand(0);
+ SDValue SadOp1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, ExtendedVT, Ops);
+
+ // Actually build the SAD
+ MVT SadVT = MVT::getVectorVT(MVT::i64, RegSize / 64);
+ return DAG.getNode(X86ISD::PSADBW, DL, SadVT, SadOp0, SadOp1);
+}
+
+static SDValue combineBasicSADPattern(SDNode *Extract, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ // PSADBW is only supported on SSE2 and up.
+ if (!Subtarget.hasSSE2())
+ return SDValue();
+
+ // Verify the type we're extracting from is appropriate
+ // TODO: There's nothing special about i32, any integer type above i16 should
+ // work just as well.
+ EVT VT = Extract->getOperand(0).getValueType();
+ if (!VT.isSimple() || !(VT.getVectorElementType() == MVT::i32))
+ return SDValue();
+
+ unsigned RegSize = 128;
+ if (Subtarget.hasBWI())
+ RegSize = 512;
+ else if (Subtarget.hasAVX2())
+ RegSize = 256;
+
+ // We only handle v16i32 for SSE2 / v32i32 for AVX2 / v64i32 for AVX512.
+ // TODO: We should be able to handle larger vectors by splitting them before
+ // feeding them into several SADs, and then reducing over those.
+ if (VT.getSizeInBits() / 4 > RegSize)
+ return SDValue();
+
+ // Match shuffle + add pyramid.
+ SDValue Root = matchBinOpReduction(Extract, ISD::ADD);
+
+ // If there was a match, we want Root to be a select that is the root of an
+ // abs-diff pattern.
+ if (!Root || (Root.getOpcode() != ISD::VSELECT))
+ return SDValue();
+
+ // Check whether we have an abs-diff pattern feeding into the select.
+ SDValue Zext0, Zext1;
+ if (!detectZextAbsDiff(Root, Zext0, Zext1))
+ return SDValue();
+
+ // Create the SAD instruction
+ SDLoc DL(Extract);
+ SDValue SAD = createPSADBW(DAG, Zext0, Zext1, DL);
+
+ // If the original vector was wider than 8 elements, sum over the results
+ // in the SAD vector.
+ unsigned Stages = Log2_32(VT.getVectorNumElements());
+ MVT SadVT = SAD.getSimpleValueType();
+ if (Stages > 3) {
+ unsigned SadElems = SadVT.getVectorNumElements();
+
+ for(unsigned i = Stages - 3; i > 0; --i) {
+ SmallVector<int, 16> Mask(SadElems, -1);
+ for(unsigned j = 0, MaskEnd = 1 << (i - 1); j < MaskEnd; ++j)
+ Mask[j] = MaskEnd + j;
+
+ SDValue Shuffle =
+ DAG.getVectorShuffle(SadVT, DL, SAD, DAG.getUNDEF(SadVT), Mask);
+ SAD = DAG.getNode(ISD::ADD, DL, SadVT, SAD, Shuffle);
+ }
+ }
+
+ // Return the lowest i32.
+ MVT ResVT = MVT::getVectorVT(MVT::i32, SadVT.getSizeInBits() / 32);
+ SAD = DAG.getNode(ISD::BITCAST, DL, ResVT, SAD);
+ return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, SAD,
+ Extract->getOperand(1));
+}
+
/// Detect vector gather/scatter index generation and convert it from being a
/// bunch of shuffles and extracts into a somewhat faster sequence.
/// For i686, the best sequence is apparently storing the value and loading
/// scalars back, while for x64 we should use 64-bit extracts and shifts.
static SDValue combineExtractVectorElt(SDNode *N, SelectionDAG &DAG,
- TargetLowering::DAGCombinerInfo &DCI) {
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
if (SDValue NewOp = XFormVExtractWithShuffleIntoLoad(N, DAG, DCI))
return NewOp;
@@ -26347,7 +28661,7 @@ static SDValue combineExtractVectorElt(SDNode *N, SelectionDAG &DAG,
InputVector.getValueType() == MVT::v2i32 &&
isa<ConstantSDNode>(N->getOperand(1)) &&
N->getConstantOperandVal(1) == 0) {
- SDValue MMXSrc = InputVector.getNode()->getOperand(0);
+ SDValue MMXSrc = InputVector.getOperand(0);
// The bitcast source is a direct mmx result.
if (MMXSrc.getValueType() == MVT::x86mmx)
@@ -26366,6 +28680,13 @@ static SDValue combineExtractVectorElt(SDNode *N, SelectionDAG &DAG,
uint64_t Res = (InputValue >> ExtractedElt) & 1;
return DAG.getConstant(Res, dl, MVT::i1);
}
+
+ // Check whether this extract is the root of a sum of absolute differences
+ // pattern. This has to be done here because we really want it to happen
+ // pre-legalization,
+ if (SDValue SAD = combineBasicSADPattern(N, DAG, Subtarget))
+ return SAD;
+
// Only operate on vectors of 4 elements, where the alternative shuffling
// gets to be more expensive.
if (InputVector.getValueType() != MVT::v4i32)
@@ -26467,6 +28788,310 @@ static SDValue combineExtractVectorElt(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+/// If a vector select has an operand that is -1 or 0, try to simplify the
+/// select to a bitwise logic operation.
+static SDValue
+combineVSelectWithAllOnesOrZeros(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
+ SDValue Cond = N->getOperand(0);
+ SDValue LHS = N->getOperand(1);
+ SDValue RHS = N->getOperand(2);
+ EVT VT = LHS.getValueType();
+ EVT CondVT = Cond.getValueType();
+ SDLoc DL(N);
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+
+ if (N->getOpcode() != ISD::VSELECT)
+ return SDValue();
+
+ assert(CondVT.isVector() && "Vector select expects a vector selector!");
+
+ bool FValIsAllZeros = ISD::isBuildVectorAllZeros(LHS.getNode());
+ // Check if the first operand is all zeros and Cond type is vXi1.
+ // This situation only applies to avx512.
+ if (FValIsAllZeros && Subtarget.hasAVX512() && Cond.hasOneUse() &&
+ CondVT.getVectorElementType() == MVT::i1) {
+ //Invert the cond to not(cond) : xor(op,allones)=not(op)
+ SDValue CondNew = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
+ DAG.getConstant(APInt::getAllOnesValue(CondVT.getScalarSizeInBits()),
+ DL, CondVT));
+ //Vselect cond, op1, op2 = Vselect not(cond), op2, op1
+ return DAG.getNode(ISD::VSELECT, DL, VT, CondNew, RHS, LHS);
+ }
+
+ // To use the condition operand as a bitwise mask, it must have elements that
+ // are the same size as the select elements. Ie, the condition operand must
+ // have already been promoted from the IR select condition type <N x i1>.
+ // Don't check if the types themselves are equal because that excludes
+ // vector floating-point selects.
+ if (CondVT.getScalarSizeInBits() != VT.getScalarSizeInBits())
+ return SDValue();
+
+ bool TValIsAllOnes = ISD::isBuildVectorAllOnes(LHS.getNode());
+ FValIsAllZeros = ISD::isBuildVectorAllZeros(RHS.getNode());
+
+ // Try to invert the condition if true value is not all 1s and false value is
+ // not all 0s.
+ if (!TValIsAllOnes && !FValIsAllZeros &&
+ // Check if the selector will be produced by CMPP*/PCMP*.
+ Cond.getOpcode() == ISD::SETCC &&
+ // Check if SETCC has already been promoted.
+ TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT) ==
+ CondVT) {
+ bool TValIsAllZeros = ISD::isBuildVectorAllZeros(LHS.getNode());
+ bool FValIsAllOnes = ISD::isBuildVectorAllOnes(RHS.getNode());
+
+ if (TValIsAllZeros || FValIsAllOnes) {
+ SDValue CC = Cond.getOperand(2);
+ ISD::CondCode NewCC =
+ ISD::getSetCCInverse(cast<CondCodeSDNode>(CC)->get(),
+ Cond.getOperand(0).getValueType().isInteger());
+ Cond = DAG.getSetCC(DL, CondVT, Cond.getOperand(0), Cond.getOperand(1),
+ NewCC);
+ std::swap(LHS, RHS);
+ TValIsAllOnes = FValIsAllOnes;
+ FValIsAllZeros = TValIsAllZeros;
+ }
+ }
+
+ // vselect Cond, 111..., 000... -> Cond
+ if (TValIsAllOnes && FValIsAllZeros)
+ return DAG.getBitcast(VT, Cond);
+
+ if (!DCI.isBeforeLegalize() && !TLI.isTypeLegal(CondVT))
+ return SDValue();
+
+ // vselect Cond, 111..., X -> or Cond, X
+ if (TValIsAllOnes) {
+ SDValue CastRHS = DAG.getBitcast(CondVT, RHS);
+ SDValue Or = DAG.getNode(ISD::OR, DL, CondVT, Cond, CastRHS);
+ return DAG.getBitcast(VT, Or);
+ }
+
+ // vselect Cond, X, 000... -> and Cond, X
+ if (FValIsAllZeros) {
+ SDValue CastLHS = DAG.getBitcast(CondVT, LHS);
+ SDValue And = DAG.getNode(ISD::AND, DL, CondVT, Cond, CastLHS);
+ return DAG.getBitcast(VT, And);
+ }
+
+ return SDValue();
+}
+
+static SDValue combineSelectOfTwoConstants(SDNode *N, SelectionDAG &DAG) {
+ SDValue Cond = N->getOperand(0);
+ SDValue LHS = N->getOperand(1);
+ SDValue RHS = N->getOperand(2);
+ SDLoc DL(N);
+
+ auto *TrueC = dyn_cast<ConstantSDNode>(LHS);
+ auto *FalseC = dyn_cast<ConstantSDNode>(RHS);
+ if (!TrueC || !FalseC)
+ return SDValue();
+
+ // Don't do this for crazy integer types.
+ if (!DAG.getTargetLoweringInfo().isTypeLegal(LHS.getValueType()))
+ return SDValue();
+
+ // If this is efficiently invertible, canonicalize the LHSC/RHSC values
+ // so that TrueC (the true value) is larger than FalseC.
+ bool NeedsCondInvert = false;
+ if (TrueC->getAPIntValue().ult(FalseC->getAPIntValue()) &&
+ // Efficiently invertible.
+ (Cond.getOpcode() == ISD::SETCC || // setcc -> invertible.
+ (Cond.getOpcode() == ISD::XOR && // xor(X, C) -> invertible.
+ isa<ConstantSDNode>(Cond.getOperand(1))))) {
+ NeedsCondInvert = true;
+ std::swap(TrueC, FalseC);
+ }
+
+ // Optimize C ? 8 : 0 -> zext(C) << 3. Likewise for any pow2/0.
+ if (FalseC->getAPIntValue() == 0 && TrueC->getAPIntValue().isPowerOf2()) {
+ if (NeedsCondInvert) // Invert the condition if needed.
+ Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
+ DAG.getConstant(1, DL, Cond.getValueType()));
+
+ // Zero extend the condition if needed.
+ Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, LHS.getValueType(), Cond);
+
+ unsigned ShAmt = TrueC->getAPIntValue().logBase2();
+ return DAG.getNode(ISD::SHL, DL, LHS.getValueType(), Cond,
+ DAG.getConstant(ShAmt, DL, MVT::i8));
+ }
+
+ // Optimize Cond ? cst+1 : cst -> zext(setcc(C)+cst.
+ if (FalseC->getAPIntValue() + 1 == TrueC->getAPIntValue()) {
+ if (NeedsCondInvert) // Invert the condition if needed.
+ Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
+ DAG.getConstant(1, DL, Cond.getValueType()));
+
+ // Zero extend the condition if needed.
+ Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, FalseC->getValueType(0), Cond);
+ return DAG.getNode(ISD::ADD, DL, Cond.getValueType(), Cond,
+ SDValue(FalseC, 0));
+ }
+
+ // Optimize cases that will turn into an LEA instruction. This requires
+ // an i32 or i64 and an efficient multiplier (1, 2, 3, 4, 5, 8, 9).
+ if (N->getValueType(0) == MVT::i32 || N->getValueType(0) == MVT::i64) {
+ uint64_t Diff = TrueC->getZExtValue() - FalseC->getZExtValue();
+ if (N->getValueType(0) == MVT::i32)
+ Diff = (unsigned)Diff;
+
+ bool isFastMultiplier = false;
+ if (Diff < 10) {
+ switch ((unsigned char)Diff) {
+ default:
+ break;
+ case 1: // result = add base, cond
+ case 2: // result = lea base( , cond*2)
+ case 3: // result = lea base(cond, cond*2)
+ case 4: // result = lea base( , cond*4)
+ case 5: // result = lea base(cond, cond*4)
+ case 8: // result = lea base( , cond*8)
+ case 9: // result = lea base(cond, cond*8)
+ isFastMultiplier = true;
+ break;
+ }
+ }
+
+ if (isFastMultiplier) {
+ APInt Diff = TrueC->getAPIntValue() - FalseC->getAPIntValue();
+ if (NeedsCondInvert) // Invert the condition if needed.
+ Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
+ DAG.getConstant(1, DL, Cond.getValueType()));
+
+ // Zero extend the condition if needed.
+ Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, FalseC->getValueType(0), Cond);
+ // Scale the condition by the difference.
+ if (Diff != 1)
+ Cond = DAG.getNode(ISD::MUL, DL, Cond.getValueType(), Cond,
+ DAG.getConstant(Diff, DL, Cond.getValueType()));
+
+ // Add the base if non-zero.
+ if (FalseC->getAPIntValue() != 0)
+ Cond = DAG.getNode(ISD::ADD, DL, Cond.getValueType(), Cond,
+ SDValue(FalseC, 0));
+ return Cond;
+ }
+ }
+
+ return SDValue();
+}
+
+// If this is a bitcasted op that can be represented as another type, push the
+// the bitcast to the inputs. This allows more opportunities for pattern
+// matching masked instructions. This is called when we know that the operation
+// is used as one of the inputs of a vselect.
+static bool combineBitcastForMaskedOp(SDValue OrigOp, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI) {
+ // Make sure we have a bitcast.
+ if (OrigOp.getOpcode() != ISD::BITCAST)
+ return false;
+
+ SDValue Op = OrigOp.getOperand(0);
+
+ // If the operation is used by anything other than the bitcast, we shouldn't
+ // do this combine as that would replicate the operation.
+ if (!Op.hasOneUse())
+ return false;
+
+ MVT VT = OrigOp.getSimpleValueType();
+ MVT EltVT = VT.getVectorElementType();
+ SDLoc DL(Op.getNode());
+
+ auto BitcastAndCombineShuffle = [&](unsigned Opcode, SDValue Op0, SDValue Op1,
+ SDValue Op2) {
+ Op0 = DAG.getBitcast(VT, Op0);
+ DCI.AddToWorklist(Op0.getNode());
+ Op1 = DAG.getBitcast(VT, Op1);
+ DCI.AddToWorklist(Op1.getNode());
+ DCI.CombineTo(OrigOp.getNode(),
+ DAG.getNode(Opcode, DL, VT, Op0, Op1, Op2));
+ return true;
+ };
+
+ unsigned Opcode = Op.getOpcode();
+ switch (Opcode) {
+ case X86ISD::PALIGNR:
+ // PALIGNR can be converted to VALIGND/Q for 128-bit vectors.
+ if (!VT.is128BitVector())
+ return false;
+ Opcode = X86ISD::VALIGN;
+ LLVM_FALLTHROUGH;
+ case X86ISD::VALIGN: {
+ if (EltVT != MVT::i32 && EltVT != MVT::i64)
+ return false;
+ uint64_t Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ MVT OpEltVT = Op.getSimpleValueType().getVectorElementType();
+ unsigned ShiftAmt = Imm * OpEltVT.getSizeInBits();
+ unsigned EltSize = EltVT.getSizeInBits();
+ // Make sure we can represent the same shift with the new VT.
+ if ((ShiftAmt % EltSize) != 0)
+ return false;
+ Imm = ShiftAmt / EltSize;
+ return BitcastAndCombineShuffle(Opcode, Op.getOperand(0), Op.getOperand(1),
+ DAG.getConstant(Imm, DL, MVT::i8));
+ }
+ case X86ISD::SHUF128: {
+ if (EltVT.getSizeInBits() != 32 && EltVT.getSizeInBits() != 64)
+ return false;
+ // Only change element size, not type.
+ if (VT.isInteger() != Op.getSimpleValueType().isInteger())
+ return false;
+ return BitcastAndCombineShuffle(Opcode, Op.getOperand(0), Op.getOperand(1),
+ Op.getOperand(2));
+ }
+ case ISD::INSERT_SUBVECTOR: {
+ unsigned EltSize = EltVT.getSizeInBits();
+ if (EltSize != 32 && EltSize != 64)
+ return false;
+ MVT OpEltVT = Op.getSimpleValueType().getVectorElementType();
+ // Only change element size, not type.
+ if (VT.isInteger() != OpEltVT.isInteger())
+ return false;
+ uint64_t Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ Imm = (Imm * OpEltVT.getSizeInBits()) / EltSize;
+ SDValue Op0 = DAG.getBitcast(VT, Op.getOperand(0));
+ DCI.AddToWorklist(Op0.getNode());
+ // Op1 needs to be bitcasted to a smaller vector with the same element type.
+ SDValue Op1 = Op.getOperand(1);
+ MVT Op1VT = MVT::getVectorVT(EltVT,
+ Op1.getSimpleValueType().getSizeInBits() / EltSize);
+ Op1 = DAG.getBitcast(Op1VT, Op1);
+ DCI.AddToWorklist(Op1.getNode());
+ DCI.CombineTo(OrigOp.getNode(),
+ DAG.getNode(Opcode, DL, VT, Op0, Op1,
+ DAG.getConstant(Imm, DL, MVT::i8)));
+ return true;
+ }
+ case ISD::EXTRACT_SUBVECTOR: {
+ unsigned EltSize = EltVT.getSizeInBits();
+ if (EltSize != 32 && EltSize != 64)
+ return false;
+ MVT OpEltVT = Op.getSimpleValueType().getVectorElementType();
+ // Only change element size, not type.
+ if (VT.isInteger() != OpEltVT.isInteger())
+ return false;
+ uint64_t Imm = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
+ Imm = (Imm * OpEltVT.getSizeInBits()) / EltSize;
+ // Op0 needs to be bitcasted to a larger vector with the same element type.
+ SDValue Op0 = Op.getOperand(0);
+ MVT Op0VT = MVT::getVectorVT(EltVT,
+ Op0.getSimpleValueType().getSizeInBits() / EltSize);
+ Op0 = DAG.getBitcast(Op0VT, Op0);
+ DCI.AddToWorklist(Op0.getNode());
+ DCI.CombineTo(OrigOp.getNode(),
+ DAG.getNode(Opcode, DL, VT, Op0,
+ DAG.getConstant(Imm, DL, MVT::i8)));
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Do target-specific dag combines on SELECT and VSELECT nodes.
static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
@@ -26477,6 +29102,7 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
SDValue LHS = N->getOperand(1);
SDValue RHS = N->getOperand(2);
EVT VT = LHS.getValueType();
+ EVT CondVT = Cond.getValueType();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
// If we have SSE[12] support, try to form min/max nodes. SSE min/max
@@ -26625,117 +29251,24 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(Opcode, DL, N->getValueType(0), LHS, RHS);
}
- EVT CondVT = Cond.getValueType();
- if (Subtarget.hasAVX512() && VT.isVector() && CondVT.isVector() &&
- CondVT.getVectorElementType() == MVT::i1) {
- // v16i8 (select v16i1, v16i8, v16i8) does not have a proper
- // lowering on KNL. In this case we convert it to
- // v16i8 (select v16i8, v16i8, v16i8) and use AVX instruction.
- // The same situation for all 128 and 256-bit vectors of i8 and i16.
- // Since SKX these selects have a proper lowering.
- EVT OpVT = LHS.getValueType();
- if ((OpVT.is128BitVector() || OpVT.is256BitVector()) &&
- (OpVT.getVectorElementType() == MVT::i8 ||
- OpVT.getVectorElementType() == MVT::i16) &&
- !(Subtarget.hasBWI() && Subtarget.hasVLX())) {
- Cond = DAG.getNode(ISD::SIGN_EXTEND, DL, OpVT, Cond);
- DCI.AddToWorklist(Cond.getNode());
- return DAG.getNode(N->getOpcode(), DL, OpVT, Cond, LHS, RHS);
- }
+ // v16i8 (select v16i1, v16i8, v16i8) does not have a proper
+ // lowering on KNL. In this case we convert it to
+ // v16i8 (select v16i8, v16i8, v16i8) and use AVX instruction.
+ // The same situation for all 128 and 256-bit vectors of i8 and i16.
+ // Since SKX these selects have a proper lowering.
+ if (Subtarget.hasAVX512() && CondVT.isVector() &&
+ CondVT.getVectorElementType() == MVT::i1 &&
+ (VT.is128BitVector() || VT.is256BitVector()) &&
+ (VT.getVectorElementType() == MVT::i8 ||
+ VT.getVectorElementType() == MVT::i16) &&
+ !(Subtarget.hasBWI() && Subtarget.hasVLX())) {
+ Cond = DAG.getNode(ISD::SIGN_EXTEND, DL, VT, Cond);
+ DCI.AddToWorklist(Cond.getNode());
+ return DAG.getNode(N->getOpcode(), DL, VT, Cond, LHS, RHS);
}
- // If this is a select between two integer constants, try to do some
- // optimizations.
- if (ConstantSDNode *TrueC = dyn_cast<ConstantSDNode>(LHS)) {
- if (ConstantSDNode *FalseC = dyn_cast<ConstantSDNode>(RHS))
- // Don't do this for crazy integer types.
- if (DAG.getTargetLoweringInfo().isTypeLegal(LHS.getValueType())) {
- // If this is efficiently invertible, canonicalize the LHSC/RHSC values
- // so that TrueC (the true value) is larger than FalseC.
- bool NeedsCondInvert = false;
-
- if (TrueC->getAPIntValue().ult(FalseC->getAPIntValue()) &&
- // Efficiently invertible.
- (Cond.getOpcode() == ISD::SETCC || // setcc -> invertible.
- (Cond.getOpcode() == ISD::XOR && // xor(X, C) -> invertible.
- isa<ConstantSDNode>(Cond.getOperand(1))))) {
- NeedsCondInvert = true;
- std::swap(TrueC, FalseC);
- }
-
- // Optimize C ? 8 : 0 -> zext(C) << 3. Likewise for any pow2/0.
- if (FalseC->getAPIntValue() == 0 &&
- TrueC->getAPIntValue().isPowerOf2()) {
- if (NeedsCondInvert) // Invert the condition if needed.
- Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
- DAG.getConstant(1, DL, Cond.getValueType()));
-
- // Zero extend the condition if needed.
- Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, LHS.getValueType(), Cond);
-
- unsigned ShAmt = TrueC->getAPIntValue().logBase2();
- return DAG.getNode(ISD::SHL, DL, LHS.getValueType(), Cond,
- DAG.getConstant(ShAmt, DL, MVT::i8));
- }
-
- // Optimize Cond ? cst+1 : cst -> zext(setcc(C)+cst.
- if (FalseC->getAPIntValue()+1 == TrueC->getAPIntValue()) {
- if (NeedsCondInvert) // Invert the condition if needed.
- Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
- DAG.getConstant(1, DL, Cond.getValueType()));
-
- // Zero extend the condition if needed.
- Cond = DAG.getNode(ISD::ZERO_EXTEND, DL,
- FalseC->getValueType(0), Cond);
- return DAG.getNode(ISD::ADD, DL, Cond.getValueType(), Cond,
- SDValue(FalseC, 0));
- }
- // Optimize cases that will turn into an LEA instruction. This requires
- // an i32 or i64 and an efficient multiplier (1, 2, 3, 4, 5, 8, 9).
- if (N->getValueType(0) == MVT::i32 || N->getValueType(0) == MVT::i64) {
- uint64_t Diff = TrueC->getZExtValue()-FalseC->getZExtValue();
- if (N->getValueType(0) == MVT::i32) Diff = (unsigned)Diff;
-
- bool isFastMultiplier = false;
- if (Diff < 10) {
- switch ((unsigned char)Diff) {
- default: break;
- case 1: // result = add base, cond
- case 2: // result = lea base( , cond*2)
- case 3: // result = lea base(cond, cond*2)
- case 4: // result = lea base( , cond*4)
- case 5: // result = lea base(cond, cond*4)
- case 8: // result = lea base( , cond*8)
- case 9: // result = lea base(cond, cond*8)
- isFastMultiplier = true;
- break;
- }
- }
-
- if (isFastMultiplier) {
- APInt Diff = TrueC->getAPIntValue()-FalseC->getAPIntValue();
- if (NeedsCondInvert) // Invert the condition if needed.
- Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond,
- DAG.getConstant(1, DL, Cond.getValueType()));
-
- // Zero extend the condition if needed.
- Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, FalseC->getValueType(0),
- Cond);
- // Scale the condition by the difference.
- if (Diff != 1)
- Cond = DAG.getNode(ISD::MUL, DL, Cond.getValueType(), Cond,
- DAG.getConstant(Diff, DL,
- Cond.getValueType()));
-
- // Add the base if non-zero.
- if (FalseC->getAPIntValue() != 0)
- Cond = DAG.getNode(ISD::ADD, DL, Cond.getValueType(), Cond,
- SDValue(FalseC, 0));
- return Cond;
- }
- }
- }
- }
+ if (SDValue V = combineSelectOfTwoConstants(N, DAG))
+ return V;
// Canonicalize max and min:
// (x > y) ? x : y -> (x >= y) ? x : y
@@ -26832,53 +29365,8 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
}
}
- // Simplify vector selection if condition value type matches vselect
- // operand type
- if (N->getOpcode() == ISD::VSELECT && CondVT == VT) {
- assert(Cond.getValueType().isVector() &&
- "vector select expects a vector selector!");
-
- bool TValIsAllOnes = ISD::isBuildVectorAllOnes(LHS.getNode());
- bool FValIsAllZeros = ISD::isBuildVectorAllZeros(RHS.getNode());
-
- // Try invert the condition if true value is not all 1s and false value
- // is not all 0s.
- if (!TValIsAllOnes && !FValIsAllZeros &&
- // Check if the selector will be produced by CMPP*/PCMP*
- Cond.getOpcode() == ISD::SETCC &&
- // Check if SETCC has already been promoted
- TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT) ==
- CondVT) {
- bool TValIsAllZeros = ISD::isBuildVectorAllZeros(LHS.getNode());
- bool FValIsAllOnes = ISD::isBuildVectorAllOnes(RHS.getNode());
-
- if (TValIsAllZeros || FValIsAllOnes) {
- SDValue CC = Cond.getOperand(2);
- ISD::CondCode NewCC =
- ISD::getSetCCInverse(cast<CondCodeSDNode>(CC)->get(),
- Cond.getOperand(0).getValueType().isInteger());
- Cond = DAG.getSetCC(DL, CondVT, Cond.getOperand(0), Cond.getOperand(1), NewCC);
- std::swap(LHS, RHS);
- TValIsAllOnes = FValIsAllOnes;
- FValIsAllZeros = TValIsAllZeros;
- }
- }
-
- if (TValIsAllOnes || FValIsAllZeros) {
- SDValue Ret;
-
- if (TValIsAllOnes && FValIsAllZeros)
- Ret = Cond;
- else if (TValIsAllOnes)
- Ret =
- DAG.getNode(ISD::OR, DL, CondVT, Cond, DAG.getBitcast(CondVT, RHS));
- else if (FValIsAllZeros)
- Ret = DAG.getNode(ISD::AND, DL, CondVT, Cond,
- DAG.getBitcast(CondVT, LHS));
-
- return DAG.getBitcast(VT, Ret);
- }
- }
+ if (SDValue V = combineVSelectWithAllOnesOrZeros(N, DAG, DCI, Subtarget))
+ return V;
// If this is a *dynamic* select (non-constant condition) and we can match
// this node with one of the variable blend instructions, restructure the
@@ -26887,7 +29375,7 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
if (N->getOpcode() == ISD::VSELECT && DCI.isBeforeLegalizeOps() &&
!DCI.isBeforeLegalize() &&
!ISD::isBuildVectorOfConstantSDNodes(Cond.getNode())) {
- unsigned BitWidth = Cond.getValueType().getScalarSizeInBits();
+ unsigned BitWidth = Cond.getScalarValueSizeInBits();
// Don't optimize vector selects that map to mask-registers.
if (BitWidth == 1)
@@ -26965,6 +29453,17 @@ static SDValue combineSelect(SDNode *N, SelectionDAG &DAG,
}
}
+ // Look for vselects with LHS/RHS being bitcasted from an operation that
+ // can be executed on another type. Push the bitcast to the inputs of
+ // the operation. This exposes opportunities for using masking instructions.
+ if (N->getOpcode() == ISD::VSELECT && !DCI.isBeforeLegalizeOps() &&
+ CondVT.getVectorElementType() == MVT::i1) {
+ if (combineBitcastForMaskedOp(LHS, DAG, DCI))
+ return SDValue(N, 0);
+ if (combineBitcastForMaskedOp(RHS, DAG, DCI))
+ return SDValue(N, 0);
+ }
+
return SDValue();
}
@@ -26981,6 +29480,12 @@ static SDValue combineSetCCAtomicArith(SDValue Cmp, X86::CondCode &CC,
(Cmp.getOpcode() == X86ISD::SUB && !Cmp->hasAnyUseOfValue(0))))
return SDValue();
+ // Can't replace the cmp if it has more uses than the one we're looking at.
+ // FIXME: We would like to be able to handle this, but would need to make sure
+ // all uses were updated.
+ if (!Cmp.hasOneUse())
+ return SDValue();
+
// This only applies to variations of the common case:
// (icmp slt x, 0) -> (icmp sle (add x, 1), 0)
// (icmp sge x, 0) -> (icmp sgt (add x, 1), 0)
@@ -27088,7 +29593,6 @@ static SDValue checkBoolTestSetCCCombine(SDValue Cmp, X86::CondCode &CC) {
// Skip (zext $x), (trunc $x), or (and $x, 1) node.
while (SetCC.getOpcode() == ISD::ZERO_EXTEND ||
SetCC.getOpcode() == ISD::TRUNCATE ||
- SetCC.getOpcode() == ISD::AssertZext ||
SetCC.getOpcode() == ISD::AND) {
if (SetCC.getOpcode() == ISD::AND) {
int OpIdx = -1;
@@ -27114,7 +29618,7 @@ static SDValue checkBoolTestSetCCCombine(SDValue Cmp, X86::CondCode &CC) {
break;
assert(X86::CondCode(SetCC.getConstantOperandVal(0)) == X86::COND_B &&
"Invalid use of SETCC_CARRY!");
- // FALL THROUGH
+ LLVM_FALLTHROUGH;
case X86ISD::SETCC:
// Set the condition code or opposite one if necessary.
CC = X86::CondCode(SetCC.getConstantOperandVal(0));
@@ -27187,7 +29691,7 @@ static bool checkBoolTestAndOrSetCCCombine(SDValue Cond, X86::CondCode &CC0,
case ISD::AND:
case X86ISD::AND:
isAnd = true;
- // fallthru
+ LLVM_FALLTHROUGH;
case ISD::OR:
case X86ISD::OR:
SetCC0 = Cond->getOperand(0);
@@ -27270,8 +29774,7 @@ static SDValue combineCMov(SDNode *N, SelectionDAG &DAG,
// This is efficient for any integer data type (including i8/i16) and
// shift amount.
if (FalseC->getAPIntValue() == 0 && TrueC->getAPIntValue().isPowerOf2()) {
- Cond = DAG.getNode(X86ISD::SETCC, DL, MVT::i8,
- DAG.getConstant(CC, DL, MVT::i8), Cond);
+ Cond = getSETCC(CC, Cond, DL, DAG);
// Zero extend the condition if needed.
Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, TrueC->getValueType(0), Cond);
@@ -27287,8 +29790,7 @@ static SDValue combineCMov(SDNode *N, SelectionDAG &DAG,
// Optimize Cond ? cst+1 : cst -> zext(setcc(C)+cst. This is efficient
// for any integer data type, including i8/i16.
if (FalseC->getAPIntValue()+1 == TrueC->getAPIntValue()) {
- Cond = DAG.getNode(X86ISD::SETCC, DL, MVT::i8,
- DAG.getConstant(CC, DL, MVT::i8), Cond);
+ Cond = getSETCC(CC, Cond, DL, DAG);
// Zero extend the condition if needed.
Cond = DAG.getNode(ISD::ZERO_EXTEND, DL,
@@ -27325,8 +29827,7 @@ static SDValue combineCMov(SDNode *N, SelectionDAG &DAG,
if (isFastMultiplier) {
APInt Diff = TrueC->getAPIntValue()-FalseC->getAPIntValue();
- Cond = DAG.getNode(X86ISD::SETCC, DL, MVT::i8,
- DAG.getConstant(CC, DL, MVT::i8), Cond);
+ Cond = getSETCC(CC, Cond, DL ,DAG);
// Zero extend the condition if needed.
Cond = DAG.getNode(ISD::ZERO_EXTEND, DL, FalseC->getValueType(0),
Cond);
@@ -27525,10 +30026,17 @@ static bool canReduceVMulWidth(SDNode *N, SelectionDAG &DAG, ShrinkMode &Mode) {
/// generate pmullw+pmulhuw for it (MULU16 mode).
static SDValue reduceVMULWidth(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
- // pmulld is supported since SSE41. It is better to use pmulld
- // instead of pmullw+pmulhw.
+ // Check for legality
// pmullw/pmulhw are not supported by SSE.
- if (Subtarget.hasSSE41() || !Subtarget.hasSSE2())
+ if (!Subtarget.hasSSE2())
+ return SDValue();
+
+ // Check for profitability
+ // pmulld is supported since SSE41. It is better to use pmulld
+ // instead of pmullw+pmulhw, except for subtargets where pmulld is slower than
+ // the expansion.
+ bool OptForMinSize = DAG.getMachineFunction().getFunction()->optForMinSize();
+ if (Subtarget.hasSSE41() && (OptForMinSize || !Subtarget.isPMULLDSlow()))
return SDValue();
ShrinkMode Mode;
@@ -27591,7 +30099,12 @@ static SDValue reduceVMULWidth(SDNode *N, SelectionDAG &DAG,
// <4 x i16> undef).
//
// Legalize the operands of mul.
- SmallVector<SDValue, 16> Ops(RegSize / ReducedVT.getSizeInBits(),
+ // FIXME: We may be able to handle non-concatenated vectors by insertion.
+ unsigned ReducedSizeInBits = ReducedVT.getSizeInBits();
+ if ((RegSize % ReducedSizeInBits) != 0)
+ return SDValue();
+
+ SmallVector<SDValue, 16> Ops(RegSize / ReducedSizeInBits,
DAG.getUNDEF(ReducedVT));
Ops[0] = NewN0;
NewN0 = DAG.getNode(ISD::CONCAT_VECTORS, DL, OpsVT, Ops);
@@ -27851,7 +30364,7 @@ static SDValue performShiftToAllZeros(SDNode *N, SelectionDAG &DAG,
if (auto *AmtSplat = AmtBV->getConstantSplatNode()) {
const APInt &ShiftAmt = AmtSplat->getAPIntValue();
unsigned MaxAmount =
- VT.getSimpleVT().getVectorElementType().getSizeInBits();
+ VT.getSimpleVT().getScalarSizeInBits();
// SSE2/AVX2 logical shifts always return a vector of 0s
// if the shift amount is bigger than or equal to
@@ -27883,6 +30396,45 @@ static SDValue combineShift(SDNode* N, SelectionDAG &DAG,
return SDValue();
}
+static SDValue combineVectorShift(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
+ assert((X86ISD::VSHLI == N->getOpcode() || X86ISD::VSRLI == N->getOpcode()) &&
+ "Unexpected opcode");
+ EVT VT = N->getValueType(0);
+ unsigned NumBitsPerElt = VT.getScalarSizeInBits();
+
+ // This fails for mask register (vXi1) shifts.
+ if ((NumBitsPerElt % 8) != 0)
+ return SDValue();
+
+ // Out of range logical bit shifts are guaranteed to be zero.
+ APInt ShiftVal = cast<ConstantSDNode>(N->getOperand(1))->getAPIntValue();
+ if (ShiftVal.zextOrTrunc(8).uge(NumBitsPerElt))
+ return getZeroVector(VT.getSimpleVT(), Subtarget, DAG, SDLoc(N));
+
+ // Shift N0 by zero -> N0.
+ if (!ShiftVal)
+ return N->getOperand(0);
+
+ // Shift zero -> zero.
+ if (ISD::isBuildVectorAllZeros(N->getOperand(0).getNode()))
+ return getZeroVector(VT.getSimpleVT(), Subtarget, DAG, SDLoc(N));
+
+ // We can decode 'whole byte' logical bit shifts as shuffles.
+ if ((ShiftVal.getZExtValue() % 8) == 0) {
+ SDValue Op(N, 0);
+ SmallVector<int, 1> NonceMask; // Just a placeholder.
+ NonceMask.push_back(0);
+ if (combineX86ShufflesRecursively({Op}, 0, Op, NonceMask,
+ /*Depth*/ 1, /*HasVarMask*/ false, DAG,
+ DCI, Subtarget))
+ return SDValue(); // This routine will use CombineTo to replace N.
+ }
+
+ return SDValue();
+}
+
/// Recognize the distinctive (AND (setcc ...) (setcc ..)) where both setccs
/// reference the same FP CMP, and rewrite for CMPEQSS and friends. Likewise for
/// OR -> CMPNEQSS.
@@ -27943,7 +30495,7 @@ static SDValue combineCompareEqual(SDNode *N, SelectionDAG &DAG,
// See X86ATTInstPrinter.cpp:printSSECC().
unsigned x86cc = (cc0 == X86::COND_E) ? 0 : 4;
if (Subtarget.hasAVX512()) {
- SDValue FSetCC = DAG.getNode(X86ISD::FSETCC, DL, MVT::i1, CMP00,
+ SDValue FSetCC = DAG.getNode(X86ISD::FSETCCM, DL, MVT::i1, CMP00,
CMP01,
DAG.getConstant(x86cc, DL, MVT::i8));
if (N->getValueType(0) != MVT::i1)
@@ -27995,9 +30547,7 @@ static SDValue combineANDXORWithAllOnesIntoANDNP(SDNode *N, SelectionDAG &DAG) {
SDValue N1 = N->getOperand(1);
SDLoc DL(N);
- if (VT != MVT::v2i64 && VT != MVT::v4i64 &&
- VT != MVT::v8i64 && VT != MVT::v16i32 &&
- VT != MVT::v4i32 && VT != MVT::v8i32) // Legal with VLX
+ if (VT != MVT::v2i64 && VT != MVT::v4i64 && VT != MVT::v8i64)
return SDValue();
// Canonicalize XOR to the left.
@@ -28111,95 +30661,6 @@ static SDValue WidenMaskArithmetic(SDNode *N, SelectionDAG &DAG,
}
}
-static SDValue combineVectorZext(SDNode *N, SelectionDAG &DAG,
- TargetLowering::DAGCombinerInfo &DCI,
- const X86Subtarget &Subtarget) {
- SDValue N0 = N->getOperand(0);
- SDValue N1 = N->getOperand(1);
- SDLoc DL(N);
-
- // A vector zext_in_reg may be represented as a shuffle,
- // feeding into a bitcast (this represents anyext) feeding into
- // an and with a mask.
- // We'd like to try to combine that into a shuffle with zero
- // plus a bitcast, removing the and.
- if (N0.getOpcode() != ISD::BITCAST ||
- N0.getOperand(0).getOpcode() != ISD::VECTOR_SHUFFLE)
- return SDValue();
-
- // The other side of the AND should be a splat of 2^C, where C
- // is the number of bits in the source type.
- N1 = peekThroughBitcasts(N1);
- if (N1.getOpcode() != ISD::BUILD_VECTOR)
- return SDValue();
- BuildVectorSDNode *Vector = cast<BuildVectorSDNode>(N1);
-
- ShuffleVectorSDNode *Shuffle = cast<ShuffleVectorSDNode>(N0.getOperand(0));
- EVT SrcType = Shuffle->getValueType(0);
-
- // We expect a single-source shuffle
- if (!Shuffle->getOperand(1)->isUndef())
- return SDValue();
-
- unsigned SrcSize = SrcType.getScalarSizeInBits();
- unsigned NumElems = SrcType.getVectorNumElements();
-
- APInt SplatValue, SplatUndef;
- unsigned SplatBitSize;
- bool HasAnyUndefs;
- if (!Vector->isConstantSplat(SplatValue, SplatUndef,
- SplatBitSize, HasAnyUndefs))
- return SDValue();
-
- unsigned ResSize = N1.getValueType().getScalarSizeInBits();
- // Make sure the splat matches the mask we expect
- if (SplatBitSize > ResSize ||
- (SplatValue + 1).exactLogBase2() != (int)SrcSize)
- return SDValue();
-
- // Make sure the input and output size make sense
- if (SrcSize >= ResSize || ResSize % SrcSize)
- return SDValue();
-
- // We expect a shuffle of the form <0, u, u, u, 1, u, u, u...>
- // The number of u's between each two values depends on the ratio between
- // the source and dest type.
- unsigned ZextRatio = ResSize / SrcSize;
- bool IsZext = true;
- for (unsigned i = 0; i != NumElems; ++i) {
- if (i % ZextRatio) {
- if (Shuffle->getMaskElt(i) > 0) {
- // Expected undef
- IsZext = false;
- break;
- }
- } else {
- if (Shuffle->getMaskElt(i) != (int)(i / ZextRatio)) {
- // Expected element number
- IsZext = false;
- break;
- }
- }
- }
-
- if (!IsZext)
- return SDValue();
-
- // Ok, perform the transformation - replace the shuffle with
- // a shuffle of the form <0, k, k, k, 1, k, k, k> with zero
- // (instead of undef) where the k elements come from the zero vector.
- SmallVector<int, 8> Mask;
- for (unsigned i = 0; i != NumElems; ++i)
- if (i % ZextRatio)
- Mask.push_back(NumElems);
- else
- Mask.push_back(i / ZextRatio);
-
- SDValue NewShuffle = DAG.getVectorShuffle(Shuffle->getValueType(0), DL,
- Shuffle->getOperand(0), DAG.getConstant(0, DL, SrcType), Mask);
- return DAG.getBitcast(N0.getValueType(), NewShuffle);
-}
-
/// If both input operands of a logic op are being cast from floating point
/// types, try to convert this into a floating point logic node to avoid
/// unnecessary moves from SSE to integer registers.
@@ -28255,7 +30716,7 @@ static SDValue combinePCMPAnd1(SDNode *N, SelectionDAG &DAG) {
// masked compare nodes, so they should not make it here.
EVT VT0 = Op0.getValueType();
EVT VT1 = Op1.getValueType();
- unsigned EltBitWidth = VT0.getScalarType().getSizeInBits();
+ unsigned EltBitWidth = VT0.getScalarSizeInBits();
if (VT0 != VT1 || EltBitWidth == 8)
return SDValue();
@@ -28277,9 +30738,6 @@ static SDValue combineAnd(SDNode *N, SelectionDAG &DAG,
if (DCI.isBeforeLegalizeOps())
return SDValue();
- if (SDValue Zext = combineVectorZext(N, DAG, DCI, Subtarget))
- return Zext;
-
if (SDValue R = combineCompareEqual(N, DAG, DCI, Subtarget))
return R;
@@ -28297,6 +30755,17 @@ static SDValue combineAnd(SDNode *N, SelectionDAG &DAG,
SDValue N1 = N->getOperand(1);
SDLoc DL(N);
+ // Attempt to recursively combine a bitmask AND with shuffles.
+ if (VT.isVector() && (VT.getScalarSizeInBits() % 8) == 0) {
+ SDValue Op(N, 0);
+ SmallVector<int, 1> NonceMask; // Just a placeholder.
+ NonceMask.push_back(0);
+ if (combineX86ShufflesRecursively({Op}, 0, Op, NonceMask,
+ /*Depth*/ 1, /*HasVarMask*/ false, DAG,
+ DCI, Subtarget))
+ return SDValue(); // This routine will use CombineTo to replace N.
+ }
+
// Create BEXTR instructions
// BEXTR is ((X >> imm) & (2**size-1))
if (VT != MVT::i32 && VT != MVT::i64)
@@ -28372,7 +30841,7 @@ static SDValue combineLogicBlendIntoPBLENDV(SDNode *N, SelectionDAG &DAG,
// Validate that the Mask operand is a vector sra node.
// FIXME: what to do for bytes, since there is a psignb/pblendvb, but
// there is no psrai.b
- unsigned EltBits = MaskVT.getVectorElementType().getSizeInBits();
+ unsigned EltBits = MaskVT.getScalarSizeInBits();
unsigned SraAmt = ~0;
if (Mask.getOpcode() == ISD::SRA) {
if (auto *AmtBV = dyn_cast<BuildVectorSDNode>(Mask.getOperand(1)))
@@ -28450,6 +30919,114 @@ static SDValue combineLogicBlendIntoPBLENDV(SDNode *N, SelectionDAG &DAG,
return DAG.getBitcast(VT, Mask);
}
+// Helper function for combineOrCmpEqZeroToCtlzSrl
+// Transforms:
+// seteq(cmp x, 0)
+// into:
+// srl(ctlz x), log2(bitsize(x))
+// Input pattern is checked by caller.
+static SDValue lowerX86CmpEqZeroToCtlzSrl(SDValue Op, EVT ExtTy,
+ SelectionDAG &DAG) {
+ SDValue Cmp = Op.getOperand(1);
+ EVT VT = Cmp.getOperand(0).getValueType();
+ unsigned Log2b = Log2_32(VT.getSizeInBits());
+ SDLoc dl(Op);
+ SDValue Clz = DAG.getNode(ISD::CTLZ, dl, VT, Cmp->getOperand(0));
+ // The result of the shift is true or false, and on X86, the 32-bit
+ // encoding of shr and lzcnt is more desirable.
+ SDValue Trunc = DAG.getZExtOrTrunc(Clz, dl, MVT::i32);
+ SDValue Scc = DAG.getNode(ISD::SRL, dl, MVT::i32, Trunc,
+ DAG.getConstant(Log2b, dl, VT));
+ return DAG.getZExtOrTrunc(Scc, dl, ExtTy);
+}
+
+// Try to transform:
+// zext(or(setcc(eq, (cmp x, 0)), setcc(eq, (cmp y, 0))))
+// into:
+// srl(or(ctlz(x), ctlz(y)), log2(bitsize(x))
+// Will also attempt to match more generic cases, eg:
+// zext(or(or(setcc(eq, cmp 0), setcc(eq, cmp 0)), setcc(eq, cmp 0)))
+// Only applies if the target supports the FastLZCNT feature.
+static SDValue combineOrCmpEqZeroToCtlzSrl(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
+ if (DCI.isBeforeLegalize() || !Subtarget.getTargetLowering()->isCtlzFast())
+ return SDValue();
+
+ auto isORCandidate = [](SDValue N) {
+ return (N->getOpcode() == ISD::OR && N->hasOneUse());
+ };
+
+ // Check the zero extend is extending to 32-bit or more. The code generated by
+ // srl(ctlz) for 16-bit or less variants of the pattern would require extra
+ // instructions to clear the upper bits.
+ if (!N->hasOneUse() || !N->getSimpleValueType(0).bitsGE(MVT::i32) ||
+ !isORCandidate(N->getOperand(0)))
+ return SDValue();
+
+ // Check the node matches: setcc(eq, cmp 0)
+ auto isSetCCCandidate = [](SDValue N) {
+ return N->getOpcode() == X86ISD::SETCC && N->hasOneUse() &&
+ X86::CondCode(N->getConstantOperandVal(0)) == X86::COND_E &&
+ N->getOperand(1).getOpcode() == X86ISD::CMP &&
+ N->getOperand(1).getConstantOperandVal(1) == 0 &&
+ N->getOperand(1).getValueType().bitsGE(MVT::i32);
+ };
+
+ SDNode *OR = N->getOperand(0).getNode();
+ SDValue LHS = OR->getOperand(0);
+ SDValue RHS = OR->getOperand(1);
+
+ // Save nodes matching or(or, setcc(eq, cmp 0)).
+ SmallVector<SDNode *, 2> ORNodes;
+ while (((isORCandidate(LHS) && isSetCCCandidate(RHS)) ||
+ (isORCandidate(RHS) && isSetCCCandidate(LHS)))) {
+ ORNodes.push_back(OR);
+ OR = (LHS->getOpcode() == ISD::OR) ? LHS.getNode() : RHS.getNode();
+ LHS = OR->getOperand(0);
+ RHS = OR->getOperand(1);
+ }
+
+ // The last OR node should match or(setcc(eq, cmp 0), setcc(eq, cmp 0)).
+ if (!(isSetCCCandidate(LHS) && isSetCCCandidate(RHS)) ||
+ !isORCandidate(SDValue(OR, 0)))
+ return SDValue();
+
+ // We have a or(setcc(eq, cmp 0), setcc(eq, cmp 0)) pattern, try to lower it
+ // to
+ // or(srl(ctlz),srl(ctlz)).
+ // The dag combiner can then fold it into:
+ // srl(or(ctlz, ctlz)).
+ EVT VT = OR->getValueType(0);
+ SDValue NewLHS = lowerX86CmpEqZeroToCtlzSrl(LHS, VT, DAG);
+ SDValue Ret, NewRHS;
+ if (NewLHS && (NewRHS = lowerX86CmpEqZeroToCtlzSrl(RHS, VT, DAG)))
+ Ret = DAG.getNode(ISD::OR, SDLoc(OR), VT, NewLHS, NewRHS);
+
+ if (!Ret)
+ return SDValue();
+
+ // Try to lower nodes matching the or(or, setcc(eq, cmp 0)) pattern.
+ while (ORNodes.size() > 0) {
+ OR = ORNodes.pop_back_val();
+ LHS = OR->getOperand(0);
+ RHS = OR->getOperand(1);
+ // Swap rhs with lhs to match or(setcc(eq, cmp, 0), or).
+ if (RHS->getOpcode() == ISD::OR)
+ std::swap(LHS, RHS);
+ EVT VT = OR->getValueType(0);
+ SDValue NewRHS = lowerX86CmpEqZeroToCtlzSrl(RHS, VT, DAG);
+ if (!NewRHS)
+ return SDValue();
+ Ret = DAG.getNode(ISD::OR, SDLoc(OR), VT, Ret, NewRHS);
+ }
+
+ if (Ret)
+ Ret = DAG.getNode(ISD::ZERO_EXTEND, SDLoc(N), N->getValueType(0), Ret);
+
+ return Ret;
+}
+
static SDValue combineOr(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
@@ -28505,18 +31082,23 @@ static SDValue combineOr(SDNode *N, SelectionDAG &DAG,
unsigned Opc = X86ISD::SHLD;
SDValue Op0 = N0.getOperand(0);
SDValue Op1 = N1.getOperand(0);
- if (ShAmt0.getOpcode() == ISD::SUB) {
+ if (ShAmt0.getOpcode() == ISD::SUB ||
+ ShAmt0.getOpcode() == ISD::XOR) {
Opc = X86ISD::SHRD;
std::swap(Op0, Op1);
std::swap(ShAmt0, ShAmt1);
}
+ // OR( SHL( X, C ), SRL( Y, 32 - C ) ) -> SHLD( X, Y, C )
+ // OR( SRL( X, C ), SHL( Y, 32 - C ) ) -> SHRD( X, Y, C )
+ // OR( SHL( X, C ), SRL( SRL( Y, 1 ), XOR( C, 31 ) ) ) -> SHLD( X, Y, C )
+ // OR( SRL( X, C ), SHL( SHL( Y, 1 ), XOR( C, 31 ) ) ) -> SHRD( X, Y, C )
unsigned Bits = VT.getSizeInBits();
if (ShAmt1.getOpcode() == ISD::SUB) {
SDValue Sum = ShAmt1.getOperand(0);
if (ConstantSDNode *SumC = dyn_cast<ConstantSDNode>(Sum)) {
SDValue ShAmt1Op1 = ShAmt1.getOperand(1);
- if (ShAmt1Op1.getNode()->getOpcode() == ISD::TRUNCATE)
+ if (ShAmt1Op1.getOpcode() == ISD::TRUNCATE)
ShAmt1Op1 = ShAmt1Op1.getOperand(0);
if (SumC->getSExtValue() == Bits && ShAmt1Op1 == ShAmt0)
return DAG.getNode(Opc, DL, VT,
@@ -28526,18 +31108,39 @@ static SDValue combineOr(SDNode *N, SelectionDAG &DAG,
}
} else if (ConstantSDNode *ShAmt1C = dyn_cast<ConstantSDNode>(ShAmt1)) {
ConstantSDNode *ShAmt0C = dyn_cast<ConstantSDNode>(ShAmt0);
- if (ShAmt0C &&
- ShAmt0C->getSExtValue() + ShAmt1C->getSExtValue() == Bits)
+ if (ShAmt0C && (ShAmt0C->getSExtValue() + ShAmt1C->getSExtValue()) == Bits)
return DAG.getNode(Opc, DL, VT,
N0.getOperand(0), N1.getOperand(0),
DAG.getNode(ISD::TRUNCATE, DL,
MVT::i8, ShAmt0));
+ } else if (ShAmt1.getOpcode() == ISD::XOR) {
+ SDValue Mask = ShAmt1.getOperand(1);
+ if (ConstantSDNode *MaskC = dyn_cast<ConstantSDNode>(Mask)) {
+ unsigned InnerShift = (X86ISD::SHLD == Opc ? ISD::SRL : ISD::SHL);
+ SDValue ShAmt1Op0 = ShAmt1.getOperand(0);
+ if (ShAmt1Op0.getOpcode() == ISD::TRUNCATE)
+ ShAmt1Op0 = ShAmt1Op0.getOperand(0);
+ if (MaskC->getSExtValue() == (Bits - 1) && ShAmt1Op0 == ShAmt0) {
+ if (Op1.getOpcode() == InnerShift &&
+ isa<ConstantSDNode>(Op1.getOperand(1)) &&
+ Op1.getConstantOperandVal(1) == 1) {
+ return DAG.getNode(Opc, DL, VT, Op0, Op1.getOperand(0),
+ DAG.getNode(ISD::TRUNCATE, DL, MVT::i8, ShAmt0));
+ }
+ // Test for ADD( Y, Y ) as an equivalent to SHL( Y, 1 ).
+ if (InnerShift == ISD::SHL && Op1.getOpcode() == ISD::ADD &&
+ Op1.getOperand(0) == Op1.getOperand(1)) {
+ return DAG.getNode(Opc, DL, VT, Op0, Op1.getOperand(0),
+ DAG.getNode(ISD::TRUNCATE, DL, MVT::i8, ShAmt0));
+ }
+ }
+ }
}
return SDValue();
}
-// Generate NEG and CMOV for integer abs.
+/// Generate NEG and CMOV for integer abs.
static SDValue combineIntegerAbs(SDNode *N, SelectionDAG &DAG) {
EVT VT = N->getValueType(0);
@@ -28553,21 +31156,19 @@ static SDValue combineIntegerAbs(SDNode *N, SelectionDAG &DAG) {
// Check pattern of XOR(ADD(X,Y), Y) where Y is SRA(X, size(X)-1)
// and change it to SUB and CMOV.
if (VT.isInteger() && N->getOpcode() == ISD::XOR &&
- N0.getOpcode() == ISD::ADD &&
- N0.getOperand(1) == N1 &&
- N1.getOpcode() == ISD::SRA &&
- N1.getOperand(0) == N0.getOperand(0))
- if (ConstantSDNode *Y1C = dyn_cast<ConstantSDNode>(N1.getOperand(1)))
- if (Y1C->getAPIntValue() == VT.getSizeInBits()-1) {
- // Generate SUB & CMOV.
- SDValue Neg = DAG.getNode(X86ISD::SUB, DL, DAG.getVTList(VT, MVT::i32),
- DAG.getConstant(0, DL, VT), N0.getOperand(0));
-
- SDValue Ops[] = { N0.getOperand(0), Neg,
- DAG.getConstant(X86::COND_GE, DL, MVT::i8),
- SDValue(Neg.getNode(), 1) };
- return DAG.getNode(X86ISD::CMOV, DL, DAG.getVTList(VT, MVT::Glue), Ops);
- }
+ N0.getOpcode() == ISD::ADD && N0.getOperand(1) == N1 &&
+ N1.getOpcode() == ISD::SRA && N1.getOperand(0) == N0.getOperand(0)) {
+ auto *Y1C = dyn_cast<ConstantSDNode>(N1.getOperand(1));
+ if (Y1C && Y1C->getAPIntValue() == VT.getSizeInBits() - 1) {
+ // Generate SUB & CMOV.
+ SDValue Neg = DAG.getNode(X86ISD::SUB, DL, DAG.getVTList(VT, MVT::i32),
+ DAG.getConstant(0, DL, VT), N0.getOperand(0));
+ SDValue Ops[] = {N0.getOperand(0), Neg,
+ DAG.getConstant(X86::COND_GE, DL, MVT::i8),
+ SDValue(Neg.getNode(), 1)};
+ return DAG.getNode(X86ISD::CMOV, DL, DAG.getVTList(VT, MVT::Glue), Ops);
+ }
+ }
return SDValue();
}
@@ -28671,28 +31272,6 @@ static SDValue foldVectorXorShiftIntoCmp(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(X86ISD::PCMPGT, SDLoc(N), VT, Shift.getOperand(0), Ones);
}
-static SDValue combineXor(SDNode *N, SelectionDAG &DAG,
- TargetLowering::DAGCombinerInfo &DCI,
- const X86Subtarget &Subtarget) {
- if (SDValue Cmp = foldVectorXorShiftIntoCmp(N, DAG, Subtarget))
- return Cmp;
-
- if (DCI.isBeforeLegalizeOps())
- return SDValue();
-
- if (SDValue RV = foldXorTruncShiftIntoCmp(N, DAG))
- return RV;
-
- if (Subtarget.hasCMov())
- if (SDValue RV = combineIntegerAbs(N, DAG))
- return RV;
-
- if (SDValue FPLogic = convertIntLogicToFPLogic(N, DAG, Subtarget))
- return FPLogic;
-
- return SDValue();
-}
-
/// This function detects the AVG pattern between vectors of unsigned i8/i16,
/// which is c = (a + b + 1) / 2, and replace this operation with the efficient
/// X86ISD::AVG instruction.
@@ -28717,7 +31296,7 @@ static SDValue detectAVGPattern(SDValue In, EVT VT, SelectionDAG &DAG,
if (!Subtarget.hasSSE2())
return SDValue();
- if (Subtarget.hasAVX512()) {
+ if (Subtarget.hasBWI()) {
if (VT.getSizeInBits() > 512)
return SDValue();
} else if (Subtarget.hasAVX2()) {
@@ -28999,6 +31578,11 @@ static SDValue combineMaskedLoad(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
MaskedLoadSDNode *Mld = cast<MaskedLoadSDNode>(N);
+
+ // TODO: Expanding load with constant mask may be optimized as well.
+ if (Mld->isExpandingLoad())
+ return SDValue();
+
if (Mld->getExtensionType() == ISD::NON_EXTLOAD) {
if (SDValue ScalarLoad = reduceMaskedLoadToScalarLoad(Mld, DAG, DCI))
return ScalarLoad;
@@ -29018,8 +31602,8 @@ static SDValue combineMaskedLoad(SDNode *N, SelectionDAG &DAG,
SDLoc dl(Mld);
assert(LdVT != VT && "Cannot extend to the same type");
- unsigned ToSz = VT.getVectorElementType().getSizeInBits();
- unsigned FromSz = LdVT.getVectorElementType().getSizeInBits();
+ unsigned ToSz = VT.getScalarSizeInBits();
+ unsigned FromSz = LdVT.getScalarSizeInBits();
// From/To sizes and ElemCount must be pow of two.
assert (isPowerOf2_32(NumElems * FromSz * ToSz) &&
"Unexpected size for extending masked load");
@@ -29114,6 +31698,10 @@ static SDValue reduceMaskedStoreToScalarStore(MaskedStoreSDNode *MS,
static SDValue combineMaskedStore(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
MaskedStoreSDNode *Mst = cast<MaskedStoreSDNode>(N);
+
+ if (Mst->isCompressingStore())
+ return SDValue();
+
if (!Mst->isTruncatingStore())
return reduceMaskedStoreToScalarStore(Mst, DAG);
@@ -29124,8 +31712,8 @@ static SDValue combineMaskedStore(SDNode *N, SelectionDAG &DAG,
SDLoc dl(Mst);
assert(StVT != VT && "Cannot truncate to the same type");
- unsigned FromSz = VT.getVectorElementType().getSizeInBits();
- unsigned ToSz = StVT.getVectorElementType().getSizeInBits();
+ unsigned FromSz = VT.getScalarSizeInBits();
+ unsigned ToSz = StVT.getScalarSizeInBits();
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
@@ -29253,8 +31841,8 @@ static SDValue combineStore(SDNode *N, SelectionDAG &DAG,
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
unsigned NumElems = VT.getVectorNumElements();
assert(StVT != VT && "Cannot truncate to the same type");
- unsigned FromSz = VT.getVectorElementType().getSizeInBits();
- unsigned ToSz = StVT.getVectorElementType().getSizeInBits();
+ unsigned FromSz = VT.getScalarSizeInBits();
+ unsigned ToSz = StVT.getScalarSizeInBits();
// The truncating store is legal in some cases. For example
// vpmovqb, vpmovqw, vpmovqd, vpmovdb, vpmovdw
@@ -29596,6 +32184,83 @@ static SDValue combineFaddFsub(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+/// Attempt to pre-truncate inputs to arithmetic ops if it will simplify
+/// the codegen.
+/// e.g. TRUNC( BINOP( X, Y ) ) --> BINOP( TRUNC( X ), TRUNC( Y ) )
+static SDValue combineTruncatedArithmetic(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget,
+ SDLoc &DL) {
+ assert(N->getOpcode() == ISD::TRUNCATE && "Wrong opcode");
+ SDValue Src = N->getOperand(0);
+ unsigned Opcode = Src.getOpcode();
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+
+ EVT VT = N->getValueType(0);
+ EVT SrcVT = Src.getValueType();
+
+ auto IsRepeatedOpOrOneUseConstant = [](SDValue Op0, SDValue Op1) {
+ // TODO: Add extra cases where we can truncate both inputs for the
+ // cost of one (or none).
+ // e.g. TRUNC( BINOP( EXT( X ), EXT( Y ) ) ) --> BINOP( X, Y )
+ if (Op0 == Op1)
+ return true;
+
+ SDValue BC0 = peekThroughOneUseBitcasts(Op0);
+ SDValue BC1 = peekThroughOneUseBitcasts(Op1);
+ return ISD::isBuildVectorOfConstantSDNodes(BC0.getNode()) ||
+ ISD::isBuildVectorOfConstantSDNodes(BC1.getNode());
+ };
+
+ auto TruncateArithmetic = [&](SDValue N0, SDValue N1) {
+ SDValue Trunc0 = DAG.getNode(ISD::TRUNCATE, DL, VT, N0);
+ SDValue Trunc1 = DAG.getNode(ISD::TRUNCATE, DL, VT, N1);
+ return DAG.getNode(Opcode, DL, VT, Trunc0, Trunc1);
+ };
+
+ // Don't combine if the operation has other uses.
+ if (!N->isOnlyUserOf(Src.getNode()))
+ return SDValue();
+
+ // Only support vector truncation for now.
+ // TODO: i64 scalar math would benefit as well.
+ if (!VT.isVector())
+ return SDValue();
+
+ // In most cases its only worth pre-truncating if we're only facing the cost
+ // of one truncation.
+ // i.e. if one of the inputs will constant fold or the input is repeated.
+ switch (Opcode) {
+ case ISD::AND:
+ case ISD::XOR:
+ case ISD::OR: {
+ SDValue Op0 = Src.getOperand(0);
+ SDValue Op1 = Src.getOperand(1);
+ if (TLI.isOperationLegalOrPromote(Opcode, VT) &&
+ IsRepeatedOpOrOneUseConstant(Op0, Op1))
+ return TruncateArithmetic(Op0, Op1);
+ break;
+ }
+
+ case ISD::MUL:
+ // X86 is rubbish at scalar and vector i64 multiplies (until AVX512DQ) - its
+ // better to truncate if we have the chance.
+ if (SrcVT.getScalarType() == MVT::i64 && TLI.isOperationLegal(Opcode, VT) &&
+ !TLI.isOperationLegal(Opcode, SrcVT))
+ return TruncateArithmetic(Src.getOperand(0), Src.getOperand(1));
+ LLVM_FALLTHROUGH;
+ case ISD::ADD: {
+ SDValue Op0 = Src.getOperand(0);
+ SDValue Op1 = Src.getOperand(1);
+ if (TLI.isOperationLegal(Opcode, VT) &&
+ IsRepeatedOpOrOneUseConstant(Op0, Op1))
+ return TruncateArithmetic(Op0, Op1);
+ break;
+ }
+ }
+
+ return SDValue();
+}
+
/// Truncate a group of v4i32 into v16i8/v8i16 using X86ISD::PACKUS.
static SDValue
combineVectorTruncationWithPACKUS(SDNode *N, SelectionDAG &DAG,
@@ -29653,7 +32318,8 @@ combineVectorTruncationWithPACKUS(SDNode *N, SelectionDAG &DAG,
/// Truncate a group of v4i32 into v8i16 using X86ISD::PACKSS.
static SDValue
-combineVectorTruncationWithPACKSS(SDNode *N, SelectionDAG &DAG,
+combineVectorTruncationWithPACKSS(SDNode *N, const X86Subtarget &Subtarget,
+ SelectionDAG &DAG,
SmallVector<SDValue, 8> &Regs) {
assert(Regs.size() > 0 && Regs[0].getValueType() == MVT::v4i32);
EVT OutVT = N->getValueType(0);
@@ -29662,8 +32328,10 @@ combineVectorTruncationWithPACKSS(SDNode *N, SelectionDAG &DAG,
// Shift left by 16 bits, then arithmetic-shift right by 16 bits.
SDValue ShAmt = DAG.getConstant(16, DL, MVT::i32);
for (auto &Reg : Regs) {
- Reg = getTargetVShiftNode(X86ISD::VSHLI, DL, MVT::v4i32, Reg, ShAmt, DAG);
- Reg = getTargetVShiftNode(X86ISD::VSRAI, DL, MVT::v4i32, Reg, ShAmt, DAG);
+ Reg = getTargetVShiftNode(X86ISD::VSHLI, DL, MVT::v4i32, Reg, ShAmt,
+ Subtarget, DAG);
+ Reg = getTargetVShiftNode(X86ISD::VSRAI, DL, MVT::v4i32, Reg, ShAmt,
+ Subtarget, DAG);
}
for (unsigned i = 0, e = Regs.size() / 2; i < e; i++)
@@ -29681,7 +32349,7 @@ combineVectorTruncationWithPACKSS(SDNode *N, SelectionDAG &DAG,
/// X86ISD::PACKUS/X86ISD::PACKSS operations. We do it here because after type
/// legalization the truncation will be translated into a BUILD_VECTOR with each
/// element that is extracted from a vector and then truncated, and it is
-/// diffcult to do this optimization based on them.
+/// difficult to do this optimization based on them.
static SDValue combineVectorTruncation(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
EVT OutVT = N->getValueType(0);
@@ -29732,17 +32400,60 @@ static SDValue combineVectorTruncation(SDNode *N, SelectionDAG &DAG,
if (Subtarget.hasSSE41() || OutSVT == MVT::i8)
return combineVectorTruncationWithPACKUS(N, DAG, SubVec);
else if (InSVT == MVT::i32)
- return combineVectorTruncationWithPACKSS(N, DAG, SubVec);
+ return combineVectorTruncationWithPACKSS(N, Subtarget, DAG, SubVec);
else
return SDValue();
}
+/// This function transforms vector truncation of 'all or none' bits values.
+/// vXi16/vXi32/vXi64 to vXi8/vXi16/vXi32 into X86ISD::PACKSS operations.
+static SDValue combineVectorSignBitsTruncation(SDNode *N, SDLoc &DL,
+ SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ // Requires SSE2 but AVX512 has fast truncate.
+ if (!Subtarget.hasSSE2() || Subtarget.hasAVX512())
+ return SDValue();
+
+ if (!N->getValueType(0).isVector() || !N->getValueType(0).isSimple())
+ return SDValue();
+
+ SDValue In = N->getOperand(0);
+ if (!In.getValueType().isSimple())
+ return SDValue();
+
+ MVT VT = N->getValueType(0).getSimpleVT();
+ MVT SVT = VT.getScalarType();
+
+ MVT InVT = In.getValueType().getSimpleVT();
+ MVT InSVT = InVT.getScalarType();
+
+ // Use PACKSS if the input is a splatted sign bit.
+ // e.g. Comparison result, sext_in_reg, etc.
+ unsigned NumSignBits = DAG.ComputeNumSignBits(In);
+ if (NumSignBits != InSVT.getSizeInBits())
+ return SDValue();
+
+ // Check we have a truncation suited for PACKSS.
+ if (!VT.is128BitVector() && !VT.is256BitVector())
+ return SDValue();
+ if (SVT != MVT::i8 && SVT != MVT::i16 && SVT != MVT::i32)
+ return SDValue();
+ if (InSVT != MVT::i16 && InSVT != MVT::i32 && InSVT != MVT::i64)
+ return SDValue();
+
+ return truncateVectorCompareWithPACKSS(VT, In, DL, DAG, Subtarget);
+}
+
static SDValue combineTruncate(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
EVT VT = N->getValueType(0);
SDValue Src = N->getOperand(0);
SDLoc DL(N);
+ // Attempt to pre-truncate inputs to arithmetic ops instead.
+ if (SDValue V = combineTruncatedArithmetic(N, DAG, Subtarget, DL))
+ return V;
+
// Try to detect AVG pattern first.
if (SDValue Avg = detectAVGPattern(Src, VT, DAG, Subtarget, DL))
return Avg;
@@ -29755,15 +32466,75 @@ static SDValue combineTruncate(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(X86ISD::MMX_MOVD2W, DL, MVT::i32, BCSrc);
}
+ // Try to truncate extended sign bits with PACKSS.
+ if (SDValue V = combineVectorSignBitsTruncation(N, DL, DAG, Subtarget))
+ return V;
+
return combineVectorTruncation(N, DAG, Subtarget);
}
+/// Returns the negated value if the node \p N flips sign of FP value.
+///
+/// FP-negation node may have different forms: FNEG(x) or FXOR (x, 0x80000000).
+/// AVX512F does not have FXOR, so FNEG is lowered as
+/// (bitcast (xor (bitcast x), (bitcast ConstantFP(0x80000000)))).
+/// In this case we go though all bitcasts.
+static SDValue isFNEG(SDNode *N) {
+ if (N->getOpcode() == ISD::FNEG)
+ return N->getOperand(0);
+
+ SDValue Op = peekThroughBitcasts(SDValue(N, 0));
+ if (Op.getOpcode() != X86ISD::FXOR && Op.getOpcode() != ISD::XOR)
+ return SDValue();
+
+ SDValue Op1 = peekThroughBitcasts(Op.getOperand(1));
+ if (!Op1.getValueType().isFloatingPoint())
+ return SDValue();
+
+ SDValue Op0 = peekThroughBitcasts(Op.getOperand(0));
+
+ unsigned EltBits = Op1.getScalarValueSizeInBits();
+ auto isSignBitValue = [&](const ConstantFP *C) {
+ return C->getValueAPF().bitcastToAPInt() == APInt::getSignBit(EltBits);
+ };
+
+ // There is more than one way to represent the same constant on
+ // the different X86 targets. The type of the node may also depend on size.
+ // - load scalar value and broadcast
+ // - BUILD_VECTOR node
+ // - load from a constant pool.
+ // We check all variants here.
+ if (Op1.getOpcode() == X86ISD::VBROADCAST) {
+ if (auto *C = getTargetConstantFromNode(Op1.getOperand(0)))
+ if (isSignBitValue(cast<ConstantFP>(C)))
+ return Op0;
+
+ } else if (BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(Op1)) {
+ if (ConstantFPSDNode *CN = BV->getConstantFPSplatNode())
+ if (isSignBitValue(CN->getConstantFPValue()))
+ return Op0;
+
+ } else if (auto *C = getTargetConstantFromNode(Op1)) {
+ if (C->getType()->isVectorTy()) {
+ if (auto *SplatV = C->getSplatValue())
+ if (isSignBitValue(cast<ConstantFP>(SplatV)))
+ return Op0;
+ } else if (auto *FPConst = dyn_cast<ConstantFP>(C))
+ if (isSignBitValue(FPConst))
+ return Op0;
+ }
+ return SDValue();
+}
+
/// Do target-specific dag combines on floating point negations.
static SDValue combineFneg(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
- EVT VT = N->getValueType(0);
+ EVT OrigVT = N->getValueType(0);
+ SDValue Arg = isFNEG(N);
+ assert(Arg.getNode() && "N is expected to be an FNEG node");
+
+ EVT VT = Arg.getValueType();
EVT SVT = VT.getScalarType();
- SDValue Arg = N->getOperand(0);
SDLoc DL(N);
// Let legalize expand this if it isn't a legal type yet.
@@ -29776,70 +32547,182 @@ static SDValue combineFneg(SDNode *N, SelectionDAG &DAG,
if (Arg.getOpcode() == ISD::FMUL && (SVT == MVT::f32 || SVT == MVT::f64) &&
Arg->getFlags()->hasNoSignedZeros() && Subtarget.hasAnyFMA()) {
SDValue Zero = DAG.getConstantFP(0.0, DL, VT);
- return DAG.getNode(X86ISD::FNMSUB, DL, VT, Arg.getOperand(0),
- Arg.getOperand(1), Zero);
+ SDValue NewNode = DAG.getNode(X86ISD::FNMSUB, DL, VT, Arg.getOperand(0),
+ Arg.getOperand(1), Zero);
+ return DAG.getBitcast(OrigVT, NewNode);
}
- // If we're negating a FMA node, then we can adjust the
+ // If we're negating an FMA node, then we can adjust the
// instruction to include the extra negation.
+ unsigned NewOpcode = 0;
if (Arg.hasOneUse()) {
switch (Arg.getOpcode()) {
- case X86ISD::FMADD:
- return DAG.getNode(X86ISD::FNMSUB, DL, VT, Arg.getOperand(0),
- Arg.getOperand(1), Arg.getOperand(2));
- case X86ISD::FMSUB:
- return DAG.getNode(X86ISD::FNMADD, DL, VT, Arg.getOperand(0),
- Arg.getOperand(1), Arg.getOperand(2));
- case X86ISD::FNMADD:
- return DAG.getNode(X86ISD::FMSUB, DL, VT, Arg.getOperand(0),
- Arg.getOperand(1), Arg.getOperand(2));
- case X86ISD::FNMSUB:
- return DAG.getNode(X86ISD::FMADD, DL, VT, Arg.getOperand(0),
- Arg.getOperand(1), Arg.getOperand(2));
- }
- }
+ case X86ISD::FMADD: NewOpcode = X86ISD::FNMSUB; break;
+ case X86ISD::FMSUB: NewOpcode = X86ISD::FNMADD; break;
+ case X86ISD::FNMADD: NewOpcode = X86ISD::FMSUB; break;
+ case X86ISD::FNMSUB: NewOpcode = X86ISD::FMADD; break;
+ case X86ISD::FMADD_RND: NewOpcode = X86ISD::FNMSUB_RND; break;
+ case X86ISD::FMSUB_RND: NewOpcode = X86ISD::FNMADD_RND; break;
+ case X86ISD::FNMADD_RND: NewOpcode = X86ISD::FMSUB_RND; break;
+ case X86ISD::FNMSUB_RND: NewOpcode = X86ISD::FMADD_RND; break;
+ // We can't handle scalar intrinsic node here because it would only
+ // invert one element and not the whole vector. But we could try to handle
+ // a negation of the lower element only.
+ }
+ }
+ if (NewOpcode)
+ return DAG.getBitcast(OrigVT, DAG.getNode(NewOpcode, DL, VT,
+ Arg.getNode()->ops()));
+
return SDValue();
}
static SDValue lowerX86FPLogicOp(SDNode *N, SelectionDAG &DAG,
- const X86Subtarget &Subtarget) {
- EVT VT = N->getValueType(0);
- if (VT.is512BitVector() && !Subtarget.hasDQI()) {
- // VXORPS, VORPS, VANDPS, VANDNPS are supported only under DQ extention.
- // These logic operations may be executed in the integer domain.
+ const X86Subtarget &Subtarget) {
+ MVT VT = N->getSimpleValueType(0);
+ // If we have integer vector types available, use the integer opcodes.
+ if (VT.isVector() && Subtarget.hasSSE2()) {
SDLoc dl(N);
- MVT IntScalar = MVT::getIntegerVT(VT.getScalarSizeInBits());
- MVT IntVT = MVT::getVectorVT(IntScalar, VT.getVectorNumElements());
+
+ MVT IntVT = MVT::getVectorVT(MVT::i64, VT.getSizeInBits() / 64);
SDValue Op0 = DAG.getBitcast(IntVT, N->getOperand(0));
SDValue Op1 = DAG.getBitcast(IntVT, N->getOperand(1));
- unsigned IntOpcode = 0;
+ unsigned IntOpcode;
switch (N->getOpcode()) {
- default: llvm_unreachable("Unexpected FP logic op");
- case X86ISD::FOR: IntOpcode = ISD::OR; break;
- case X86ISD::FXOR: IntOpcode = ISD::XOR; break;
- case X86ISD::FAND: IntOpcode = ISD::AND; break;
- case X86ISD::FANDN: IntOpcode = X86ISD::ANDNP; break;
+ default: llvm_unreachable("Unexpected FP logic op");
+ case X86ISD::FOR: IntOpcode = ISD::OR; break;
+ case X86ISD::FXOR: IntOpcode = ISD::XOR; break;
+ case X86ISD::FAND: IntOpcode = ISD::AND; break;
+ case X86ISD::FANDN: IntOpcode = X86ISD::ANDNP; break;
}
SDValue IntOp = DAG.getNode(IntOpcode, dl, IntVT, Op0, Op1);
return DAG.getBitcast(VT, IntOp);
}
return SDValue();
}
+
+static SDValue combineXor(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
+ if (SDValue Cmp = foldVectorXorShiftIntoCmp(N, DAG, Subtarget))
+ return Cmp;
+
+ if (DCI.isBeforeLegalizeOps())
+ return SDValue();
+
+ if (SDValue RV = foldXorTruncShiftIntoCmp(N, DAG))
+ return RV;
+
+ if (Subtarget.hasCMov())
+ if (SDValue RV = combineIntegerAbs(N, DAG))
+ return RV;
+
+ if (SDValue FPLogic = convertIntLogicToFPLogic(N, DAG, Subtarget))
+ return FPLogic;
+
+ if (isFNEG(N))
+ return combineFneg(N, DAG, Subtarget);
+ return SDValue();
+}
+
+
+static bool isNullFPScalarOrVectorConst(SDValue V) {
+ return isNullFPConstant(V) || ISD::isBuildVectorAllZeros(V.getNode());
+}
+
+/// If a value is a scalar FP zero or a vector FP zero (potentially including
+/// undefined elements), return a zero constant that may be used to fold away
+/// that value. In the case of a vector, the returned constant will not contain
+/// undefined elements even if the input parameter does. This makes it suitable
+/// to be used as a replacement operand with operations (eg, bitwise-and) where
+/// an undef should not propagate.
+static SDValue getNullFPConstForNullVal(SDValue V, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ if (!isNullFPScalarOrVectorConst(V))
+ return SDValue();
+
+ if (V.getValueType().isVector())
+ return getZeroVector(V.getSimpleValueType(), Subtarget, DAG, SDLoc(V));
+
+ return V;
+}
+
+static SDValue combineFAndFNotToFAndn(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ // Vector types are handled in combineANDXORWithAllOnesIntoANDNP().
+ if (!((VT == MVT::f32 && Subtarget.hasSSE1()) ||
+ (VT == MVT::f64 && Subtarget.hasSSE2())))
+ return SDValue();
+
+ auto isAllOnesConstantFP = [](SDValue V) {
+ auto *C = dyn_cast<ConstantFPSDNode>(V);
+ return C && C->getConstantFPValue()->isAllOnesValue();
+ };
+
+ // fand (fxor X, -1), Y --> fandn X, Y
+ if (N0.getOpcode() == X86ISD::FXOR && isAllOnesConstantFP(N0.getOperand(1)))
+ return DAG.getNode(X86ISD::FANDN, DL, VT, N0.getOperand(0), N1);
+
+ // fand X, (fxor Y, -1) --> fandn Y, X
+ if (N1.getOpcode() == X86ISD::FXOR && isAllOnesConstantFP(N1.getOperand(1)))
+ return DAG.getNode(X86ISD::FANDN, DL, VT, N1.getOperand(0), N0);
+
+ return SDValue();
+}
+
+/// Do target-specific dag combines on X86ISD::FAND nodes.
+static SDValue combineFAnd(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ // FAND(0.0, x) -> 0.0
+ if (SDValue V = getNullFPConstForNullVal(N->getOperand(0), DAG, Subtarget))
+ return V;
+
+ // FAND(x, 0.0) -> 0.0
+ if (SDValue V = getNullFPConstForNullVal(N->getOperand(1), DAG, Subtarget))
+ return V;
+
+ if (SDValue V = combineFAndFNotToFAndn(N, DAG, Subtarget))
+ return V;
+
+ return lowerX86FPLogicOp(N, DAG, Subtarget);
+}
+
+/// Do target-specific dag combines on X86ISD::FANDN nodes.
+static SDValue combineFAndn(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ // FANDN(0.0, x) -> x
+ if (isNullFPScalarOrVectorConst(N->getOperand(0)))
+ return N->getOperand(1);
+
+ // FANDN(x, 0.0) -> 0.0
+ if (SDValue V = getNullFPConstForNullVal(N->getOperand(1), DAG, Subtarget))
+ return V;
+
+ return lowerX86FPLogicOp(N, DAG, Subtarget);
+}
+
/// Do target-specific dag combines on X86ISD::FOR and X86ISD::FXOR nodes.
static SDValue combineFOr(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
assert(N->getOpcode() == X86ISD::FOR || N->getOpcode() == X86ISD::FXOR);
// F[X]OR(0.0, x) -> x
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N->getOperand(0)))
- if (C->getValueAPF().isPosZero())
- return N->getOperand(1);
+ if (isNullFPScalarOrVectorConst(N->getOperand(0)))
+ return N->getOperand(1);
// F[X]OR(x, 0.0) -> x
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N->getOperand(1)))
- if (C->getValueAPF().isPosZero())
- return N->getOperand(0);
+ if (isNullFPScalarOrVectorConst(N->getOperand(1)))
+ return N->getOperand(0);
+
+ if (isFNEG(N))
+ if (SDValue NewVal = combineFneg(N, DAG, Subtarget))
+ return NewVal;
return lowerX86FPLogicOp(N, DAG, Subtarget);
}
@@ -29921,38 +32804,6 @@ static SDValue combineFMinNumFMaxNum(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(SelectOpcode, DL, VT, IsOp0Nan, Op1, MinOrMax);
}
-/// Do target-specific dag combines on X86ISD::FAND nodes.
-static SDValue combineFAnd(SDNode *N, SelectionDAG &DAG,
- const X86Subtarget &Subtarget) {
- // FAND(0.0, x) -> 0.0
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N->getOperand(0)))
- if (C->getValueAPF().isPosZero())
- return N->getOperand(0);
-
- // FAND(x, 0.0) -> 0.0
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N->getOperand(1)))
- if (C->getValueAPF().isPosZero())
- return N->getOperand(1);
-
- return lowerX86FPLogicOp(N, DAG, Subtarget);
-}
-
-/// Do target-specific dag combines on X86ISD::FANDN nodes
-static SDValue combineFAndn(SDNode *N, SelectionDAG &DAG,
- const X86Subtarget &Subtarget) {
- // FANDN(0.0, x) -> x
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N->getOperand(0)))
- if (C->getValueAPF().isPosZero())
- return N->getOperand(1);
-
- // FANDN(x, 0.0) -> 0.0
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N->getOperand(1)))
- if (C->getValueAPF().isPosZero())
- return N->getOperand(1);
-
- return lowerX86FPLogicOp(N, DAG, Subtarget);
-}
-
static SDValue combineBT(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI) {
// BT ignores high bits in the bit index operand.
@@ -29971,17 +32822,6 @@ static SDValue combineBT(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
-static SDValue combineVZextMovl(SDNode *N, SelectionDAG &DAG) {
- SDValue Op = peekThroughBitcasts(N->getOperand(0));
- EVT VT = N->getValueType(0), OpVT = Op.getValueType();
- if (Op.getOpcode() == X86ISD::VZEXT_LOAD &&
- VT.getVectorElementType().getSizeInBits() ==
- OpVT.getVectorElementType().getSizeInBits()) {
- return DAG.getBitcast(VT, Op);
- }
- return SDValue();
-}
-
static SDValue combineSignExtendInReg(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
EVT VT = N->getValueType(0);
@@ -30018,19 +32858,32 @@ static SDValue combineSignExtendInReg(SDNode *N, SelectionDAG &DAG,
}
/// sext(add_nsw(x, C)) --> add(sext(x), C_sext)
-/// Promoting a sign extension ahead of an 'add nsw' exposes opportunities
-/// to combine math ops, use an LEA, or use a complex addressing mode. This can
-/// eliminate extend, add, and shift instructions.
-static SDValue promoteSextBeforeAddNSW(SDNode *Sext, SelectionDAG &DAG,
- const X86Subtarget &Subtarget) {
+/// zext(add_nuw(x, C)) --> add(zext(x), C_zext)
+/// Promoting a sign/zero extension ahead of a no overflow 'add' exposes
+/// opportunities to combine math ops, use an LEA, or use a complex addressing
+/// mode. This can eliminate extend, add, and shift instructions.
+static SDValue promoteExtBeforeAdd(SDNode *Ext, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ if (Ext->getOpcode() != ISD::SIGN_EXTEND &&
+ Ext->getOpcode() != ISD::ZERO_EXTEND)
+ return SDValue();
+
// TODO: This should be valid for other integer types.
- EVT VT = Sext->getValueType(0);
+ EVT VT = Ext->getValueType(0);
if (VT != MVT::i64)
return SDValue();
- // We need an 'add nsw' feeding into the 'sext'.
- SDValue Add = Sext->getOperand(0);
- if (Add.getOpcode() != ISD::ADD || !Add->getFlags()->hasNoSignedWrap())
+ SDValue Add = Ext->getOperand(0);
+ if (Add.getOpcode() != ISD::ADD)
+ return SDValue();
+
+ bool Sext = Ext->getOpcode() == ISD::SIGN_EXTEND;
+ bool NSW = Add->getFlags()->hasNoSignedWrap();
+ bool NUW = Add->getFlags()->hasNoUnsignedWrap();
+
+ // We need an 'add nsw' feeding into the 'sext' or 'add nuw' feeding
+ // into the 'zext'
+ if ((Sext && !NSW) || (!Sext && !NUW))
return SDValue();
// Having a constant operand to the 'add' ensures that we are not increasing
@@ -30046,7 +32899,7 @@ static SDValue promoteSextBeforeAddNSW(SDNode *Sext, SelectionDAG &DAG,
// of single 'add' instructions, but the cost model for selecting an LEA
// currently has a high threshold.
bool HasLEAPotential = false;
- for (auto *User : Sext->uses()) {
+ for (auto *User : Ext->uses()) {
if (User->getOpcode() == ISD::ADD || User->getOpcode() == ISD::SHL) {
HasLEAPotential = true;
break;
@@ -30055,17 +32908,18 @@ static SDValue promoteSextBeforeAddNSW(SDNode *Sext, SelectionDAG &DAG,
if (!HasLEAPotential)
return SDValue();
- // Everything looks good, so pull the 'sext' ahead of the 'add'.
- int64_t AddConstant = AddOp1->getSExtValue();
+ // Everything looks good, so pull the '{s|z}ext' ahead of the 'add'.
+ int64_t AddConstant = Sext ? AddOp1->getSExtValue() : AddOp1->getZExtValue();
SDValue AddOp0 = Add.getOperand(0);
- SDValue NewSext = DAG.getNode(ISD::SIGN_EXTEND, SDLoc(Sext), VT, AddOp0);
+ SDValue NewExt = DAG.getNode(Ext->getOpcode(), SDLoc(Ext), VT, AddOp0);
SDValue NewConstant = DAG.getConstant(AddConstant, SDLoc(Add), VT);
// The wider add is guaranteed to not wrap because both operands are
// sign-extended.
SDNodeFlags Flags;
- Flags.setNoSignedWrap(true);
- return DAG.getNode(ISD::ADD, SDLoc(Add), VT, NewSext, NewConstant, &Flags);
+ Flags.setNoSignedWrap(NSW);
+ Flags.setNoUnsignedWrap(NUW);
+ return DAG.getNode(ISD::ADD, SDLoc(Add), VT, NewExt, NewConstant, &Flags);
}
/// (i8,i32 {s/z}ext ({s/u}divrem (i8 x, i8 y)) ->
@@ -30157,18 +33011,17 @@ static SDValue combineToExtendVectorInReg(SDNode *N, SelectionDAG &DAG,
// ISD::*_EXTEND_VECTOR_INREG which ensures lowering to X86ISD::V*EXT.
// Also use this if we don't have SSE41 to allow the legalizer do its job.
if (!Subtarget.hasSSE41() || VT.is128BitVector() ||
- (VT.is256BitVector() && Subtarget.hasInt256())) {
+ (VT.is256BitVector() && Subtarget.hasInt256()) ||
+ (VT.is512BitVector() && Subtarget.hasAVX512())) {
SDValue ExOp = ExtendVecSize(DL, N0, VT.getSizeInBits());
return Opcode == ISD::SIGN_EXTEND
? DAG.getSignExtendVectorInReg(ExOp, DL, VT)
: DAG.getZeroExtendVectorInReg(ExOp, DL, VT);
}
- // On pre-AVX2 targets, split into 128-bit nodes of
- // ISD::*_EXTEND_VECTOR_INREG.
- if (!Subtarget.hasInt256() && !(VT.getSizeInBits() % 128)) {
- unsigned NumVecs = VT.getSizeInBits() / 128;
- unsigned NumSubElts = 128 / SVT.getSizeInBits();
+ auto SplitAndExtendInReg = [&](unsigned SplitSize) {
+ unsigned NumVecs = VT.getSizeInBits() / SplitSize;
+ unsigned NumSubElts = SplitSize / SVT.getSizeInBits();
EVT SubVT = EVT::getVectorVT(*DAG.getContext(), SVT, NumSubElts);
EVT InSubVT = EVT::getVectorVT(*DAG.getContext(), InSVT, NumSubElts);
@@ -30176,14 +33029,24 @@ static SDValue combineToExtendVectorInReg(SDNode *N, SelectionDAG &DAG,
for (unsigned i = 0, Offset = 0; i != NumVecs; ++i, Offset += NumSubElts) {
SDValue SrcVec = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, InSubVT, N0,
DAG.getIntPtrConstant(Offset, DL));
- SrcVec = ExtendVecSize(DL, SrcVec, 128);
+ SrcVec = ExtendVecSize(DL, SrcVec, SplitSize);
SrcVec = Opcode == ISD::SIGN_EXTEND
? DAG.getSignExtendVectorInReg(SrcVec, DL, SubVT)
: DAG.getZeroExtendVectorInReg(SrcVec, DL, SubVT);
Opnds.push_back(SrcVec);
}
return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Opnds);
- }
+ };
+
+ // On pre-AVX2 targets, split into 128-bit nodes of
+ // ISD::*_EXTEND_VECTOR_INREG.
+ if (!Subtarget.hasInt256() && !(VT.getSizeInBits() % 128))
+ return SplitAndExtendInReg(128);
+
+ // On pre-AVX512 targets, split into 256-bit nodes of
+ // ISD::*_EXTEND_VECTOR_INREG.
+ if (!Subtarget.hasAVX512() && !(VT.getSizeInBits() % 256))
+ return SplitAndExtendInReg(256);
return SDValue();
}
@@ -30216,7 +33079,7 @@ static SDValue combineSext(SDNode *N, SelectionDAG &DAG,
if (SDValue R = WidenMaskArithmetic(N, DAG, DCI, Subtarget))
return R;
- if (SDValue NewAdd = promoteSextBeforeAddNSW(N, DAG, Subtarget))
+ if (SDValue NewAdd = promoteExtBeforeAdd(N, DAG, Subtarget))
return NewAdd;
return SDValue();
@@ -30239,26 +33102,58 @@ static SDValue combineFMA(SDNode *N, SelectionDAG &DAG,
SDValue B = N->getOperand(1);
SDValue C = N->getOperand(2);
- bool NegA = (A.getOpcode() == ISD::FNEG);
- bool NegB = (B.getOpcode() == ISD::FNEG);
- bool NegC = (C.getOpcode() == ISD::FNEG);
+ auto invertIfNegative = [](SDValue &V) {
+ if (SDValue NegVal = isFNEG(V.getNode())) {
+ V = NegVal;
+ return true;
+ }
+ return false;
+ };
+
+ // Do not convert the passthru input of scalar intrinsics.
+ // FIXME: We could allow negations of the lower element only.
+ bool NegA = N->getOpcode() != X86ISD::FMADDS1_RND && invertIfNegative(A);
+ bool NegB = invertIfNegative(B);
+ bool NegC = N->getOpcode() != X86ISD::FMADDS3_RND && invertIfNegative(C);
// Negative multiplication when NegA xor NegB
bool NegMul = (NegA != NegB);
- if (NegA)
- A = A.getOperand(0);
- if (NegB)
- B = B.getOperand(0);
- if (NegC)
- C = C.getOperand(0);
- unsigned Opcode;
+ unsigned NewOpcode;
if (!NegMul)
- Opcode = (!NegC) ? X86ISD::FMADD : X86ISD::FMSUB;
+ NewOpcode = (!NegC) ? X86ISD::FMADD : X86ISD::FMSUB;
else
- Opcode = (!NegC) ? X86ISD::FNMADD : X86ISD::FNMSUB;
+ NewOpcode = (!NegC) ? X86ISD::FNMADD : X86ISD::FNMSUB;
+
+
+ if (N->getOpcode() == X86ISD::FMADD_RND) {
+ switch (NewOpcode) {
+ case X86ISD::FMADD: NewOpcode = X86ISD::FMADD_RND; break;
+ case X86ISD::FMSUB: NewOpcode = X86ISD::FMSUB_RND; break;
+ case X86ISD::FNMADD: NewOpcode = X86ISD::FNMADD_RND; break;
+ case X86ISD::FNMSUB: NewOpcode = X86ISD::FNMSUB_RND; break;
+ }
+ } else if (N->getOpcode() == X86ISD::FMADDS1_RND) {
+ switch (NewOpcode) {
+ case X86ISD::FMADD: NewOpcode = X86ISD::FMADDS1_RND; break;
+ case X86ISD::FMSUB: NewOpcode = X86ISD::FMSUBS1_RND; break;
+ case X86ISD::FNMADD: NewOpcode = X86ISD::FNMADDS1_RND; break;
+ case X86ISD::FNMSUB: NewOpcode = X86ISD::FNMSUBS1_RND; break;
+ }
+ } else if (N->getOpcode() == X86ISD::FMADDS3_RND) {
+ switch (NewOpcode) {
+ case X86ISD::FMADD: NewOpcode = X86ISD::FMADDS3_RND; break;
+ case X86ISD::FMSUB: NewOpcode = X86ISD::FMSUBS3_RND; break;
+ case X86ISD::FNMADD: NewOpcode = X86ISD::FNMADDS3_RND; break;
+ case X86ISD::FNMSUB: NewOpcode = X86ISD::FNMSUBS3_RND; break;
+ }
+ } else {
+ assert((N->getOpcode() == X86ISD::FMADD || N->getOpcode() == ISD::FMA) &&
+ "Unexpected opcode!");
+ return DAG.getNode(NewOpcode, dl, VT, A, B, C);
+ }
- return DAG.getNode(Opcode, dl, VT, A, B, C);
+ return DAG.getNode(NewOpcode, dl, VT, A, B, C, N->getOperand(3));
}
static SDValue combineZext(SDNode *N, SelectionDAG &DAG,
@@ -30308,6 +33203,12 @@ static SDValue combineZext(SDNode *N, SelectionDAG &DAG,
if (SDValue DivRem8 = getDivRem8(N, DAG))
return DivRem8;
+ if (SDValue NewAdd = promoteExtBeforeAdd(N, DAG, Subtarget))
+ return NewAdd;
+
+ if (SDValue R = combineOrCmpEqZeroToCtlzSrl(N, DAG, DCI, Subtarget))
+ return R;
+
return SDValue();
}
@@ -30443,10 +33344,8 @@ static SDValue combineX86SetCC(SDNode *N, SelectionDAG &DAG,
return MaterializeSETB(DL, EFLAGS, DAG, N->getSimpleValueType(0));
// Try to simplify the EFLAGS and condition code operands.
- if (SDValue Flags = combineSetCCEFLAGS(EFLAGS, CC, DAG)) {
- SDValue Cond = DAG.getConstant(CC, DL, MVT::i8);
- return DAG.getNode(X86ISD::SETCC, DL, N->getVTList(), Cond, Flags);
- }
+ if (SDValue Flags = combineSetCCEFLAGS(EFLAGS, CC, DAG))
+ return getSETCC(CC, Flags, DL, DAG);
return SDValue();
}
@@ -30539,6 +33438,12 @@ static SDValue combineUIntToFP(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(ISD::SINT_TO_FP, dl, VT, P);
}
+ // Since UINT_TO_FP is legal (it's marked custom), dag combiner won't
+ // optimize it to a SINT_TO_FP when the sign bit is known zero. Perform
+ // the optimization here.
+ if (DAG.SignBitIsZero(Op0))
+ return DAG.getNode(ISD::SINT_TO_FP, SDLoc(N), VT, Op0);
+
return SDValue();
}
@@ -30555,9 +33460,12 @@ static SDValue combineSIntToFP(SDNode *N, SelectionDAG &DAG,
EVT InVT = Op0.getValueType();
EVT InSVT = InVT.getScalarType();
+ // SINT_TO_FP(vXi1) -> SINT_TO_FP(SEXT(vXi1 to vXi32))
// SINT_TO_FP(vXi8) -> SINT_TO_FP(SEXT(vXi8 to vXi32))
// SINT_TO_FP(vXi16) -> SINT_TO_FP(SEXT(vXi16 to vXi32))
- if (InVT.isVector() && (InSVT == MVT::i8 || InSVT == MVT::i16)) {
+ if (InVT.isVector() &&
+ (InSVT == MVT::i8 || InSVT == MVT::i16 ||
+ (InSVT == MVT::i1 && !DAG.getTargetLoweringInfo().isTypeLegal(InVT)))) {
SDLoc dl(N);
EVT DstVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32,
InVT.getVectorNumElements());
@@ -30565,6 +33473,23 @@ static SDValue combineSIntToFP(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(ISD::SINT_TO_FP, dl, VT, P);
}
+ // Without AVX512DQ we only support i64 to float scalar conversion. For both
+ // vectors and scalars, see if we know that the upper bits are all the sign
+ // bit, in which case we can truncate the input to i32 and convert from that.
+ if (InVT.getScalarSizeInBits() > 32 && !Subtarget.hasDQI()) {
+ unsigned BitWidth = InVT.getScalarSizeInBits();
+ unsigned NumSignBits = DAG.ComputeNumSignBits(Op0);
+ if (NumSignBits >= (BitWidth - 31)) {
+ EVT TruncVT = EVT::getIntegerVT(*DAG.getContext(), 32);
+ if (InVT.isVector())
+ TruncVT = EVT::getVectorVT(*DAG.getContext(), TruncVT,
+ InVT.getVectorNumElements());
+ SDLoc dl(N);
+ SDValue Trunc = DAG.getNode(ISD::TRUNCATE, dl, TruncVT, Op0);
+ return DAG.getNode(ISD::SINT_TO_FP, dl, VT, Trunc);
+ }
+ }
+
// Transform (SINT_TO_FP (i64 ...)) into an x87 operation if we have
// a 32-bit target where SSE doesn't support i64->FP operations.
if (!Subtarget.useSoftFloat() && Op0.getOpcode() == ISD::LOAD) {
@@ -30654,13 +33579,15 @@ static SDValue OptimizeConditionalInDecrement(SDNode *N, SelectionDAG &DAG) {
DAG.getConstant(0, DL, OtherVal.getValueType()), NewCmp);
}
-static SDValue detectSADPattern(SDNode *N, SelectionDAG &DAG,
- const X86Subtarget &Subtarget) {
+static SDValue combineLoopSADPattern(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
SDLoc DL(N);
EVT VT = N->getValueType(0);
SDValue Op0 = N->getOperand(0);
SDValue Op1 = N->getOperand(1);
+ // TODO: There's nothing special about i32, any integer type above i16 should
+ // work just as well.
if (!VT.isVector() || !VT.isSimple() ||
!(VT.getVectorElementType() == MVT::i32))
return SDValue();
@@ -30672,24 +33599,13 @@ static SDValue detectSADPattern(SDNode *N, SelectionDAG &DAG,
RegSize = 256;
// We only handle v16i32 for SSE2 / v32i32 for AVX2 / v64i32 for AVX512.
+ // TODO: We should be able to handle larger vectors by splitting them before
+ // feeding them into several SADs, and then reducing over those.
if (VT.getSizeInBits() / 4 > RegSize)
return SDValue();
- // Detect the following pattern:
- //
- // 1: %2 = zext <N x i8> %0 to <N x i32>
- // 2: %3 = zext <N x i8> %1 to <N x i32>
- // 3: %4 = sub nsw <N x i32> %2, %3
- // 4: %5 = icmp sgt <N x i32> %4, [0 x N] or [-1 x N]
- // 5: %6 = sub nsw <N x i32> zeroinitializer, %4
- // 6: %7 = select <N x i1> %5, <N x i32> %4, <N x i32> %6
- // 7: %8 = add nsw <N x i32> %7, %vec.phi
- //
- // The last instruction must be a reduction add. The instructions 3-6 forms an
- // ABSDIFF pattern.
-
- // The two operands of reduction add are from PHI and a select-op as in line 7
- // above.
+ // We know N is a reduction add, which means one of its operands is a phi.
+ // To match SAD, we need the other operand to be a vector select.
SDValue SelectOp, Phi;
if (Op0.getOpcode() == ISD::VSELECT) {
SelectOp = Op0;
@@ -30700,77 +33616,22 @@ static SDValue detectSADPattern(SDNode *N, SelectionDAG &DAG,
} else
return SDValue();
- // Check the condition of the select instruction is greater-than.
- SDValue SetCC = SelectOp->getOperand(0);
- if (SetCC.getOpcode() != ISD::SETCC)
- return SDValue();
- ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get();
- if (CC != ISD::SETGT)
- return SDValue();
-
- Op0 = SelectOp->getOperand(1);
- Op1 = SelectOp->getOperand(2);
-
- // The second operand of SelectOp Op1 is the negation of the first operand
- // Op0, which is implemented as 0 - Op0.
- if (!(Op1.getOpcode() == ISD::SUB &&
- ISD::isBuildVectorAllZeros(Op1.getOperand(0).getNode()) &&
- Op1.getOperand(1) == Op0))
- return SDValue();
-
- // The first operand of SetCC is the first operand of SelectOp, which is the
- // difference between two input vectors.
- if (SetCC.getOperand(0) != Op0)
- return SDValue();
-
- // The second operand of > comparison can be either -1 or 0.
- if (!(ISD::isBuildVectorAllZeros(SetCC.getOperand(1).getNode()) ||
- ISD::isBuildVectorAllOnes(SetCC.getOperand(1).getNode())))
- return SDValue();
-
- // The first operand of SelectOp is the difference between two input vectors.
- if (Op0.getOpcode() != ISD::SUB)
- return SDValue();
-
- Op1 = Op0.getOperand(1);
- Op0 = Op0.getOperand(0);
-
- // Check if the operands of the diff are zero-extended from vectors of i8.
- if (Op0.getOpcode() != ISD::ZERO_EXTEND ||
- Op0.getOperand(0).getValueType().getVectorElementType() != MVT::i8 ||
- Op1.getOpcode() != ISD::ZERO_EXTEND ||
- Op1.getOperand(0).getValueType().getVectorElementType() != MVT::i8)
+ // Check whether we have an abs-diff pattern feeding into the select.
+ if(!detectZextAbsDiff(SelectOp, Op0, Op1))
return SDValue();
// SAD pattern detected. Now build a SAD instruction and an addition for
- // reduction. Note that the number of elments of the result of SAD is less
+ // reduction. Note that the number of elements of the result of SAD is less
// than the number of elements of its input. Therefore, we could only update
// part of elements in the reduction vector.
-
- // Legalize the type of the inputs of PSADBW.
- EVT InVT = Op0.getOperand(0).getValueType();
- if (InVT.getSizeInBits() <= 128)
- RegSize = 128;
- else if (InVT.getSizeInBits() <= 256)
- RegSize = 256;
-
- unsigned NumConcat = RegSize / InVT.getSizeInBits();
- SmallVector<SDValue, 16> Ops(NumConcat, DAG.getConstant(0, DL, InVT));
- Ops[0] = Op0.getOperand(0);
- MVT ExtendedVT = MVT::getVectorVT(MVT::i8, RegSize / 8);
- Op0 = DAG.getNode(ISD::CONCAT_VECTORS, DL, ExtendedVT, Ops);
- Ops[0] = Op1.getOperand(0);
- Op1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, ExtendedVT, Ops);
+ SDValue Sad = createPSADBW(DAG, Op0, Op1, DL);
// The output of PSADBW is a vector of i64.
- MVT SadVT = MVT::getVectorVT(MVT::i64, RegSize / 64);
- SDValue Sad = DAG.getNode(X86ISD::PSADBW, DL, SadVT, Op0, Op1);
-
// We need to turn the vector of i64 into a vector of i32.
// If the reduction vector is at least as wide as the psadbw result, just
// bitcast. If it's narrower, truncate - the high i32 of each i64 is zero
// anyway.
- MVT ResVT = MVT::getVectorVT(MVT::i32, RegSize / 32);
+ MVT ResVT = MVT::getVectorVT(MVT::i32, Sad.getValueSizeInBits() / 32);
if (VT.getSizeInBits() >= ResVT.getSizeInBits())
Sad = DAG.getNode(ISD::BITCAST, DL, ResVT, Sad);
else
@@ -30793,7 +33654,7 @@ static SDValue combineAdd(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
const SDNodeFlags *Flags = &cast<BinaryWithFlagsSDNode>(N)->Flags;
if (Flags->hasVectorReduction()) {
- if (SDValue Sad = detectSADPattern(N, DAG, Subtarget))
+ if (SDValue Sad = combineLoopSADPattern(N, DAG, Subtarget))
return Sad;
}
EVT VT = N->getValueType(0);
@@ -30832,20 +33693,21 @@ static SDValue combineSub(SDNode *N, SelectionDAG &DAG,
}
}
- // Try to synthesize horizontal adds from adds of shuffles.
+ // Try to synthesize horizontal subs from subs of shuffles.
EVT VT = N->getValueType(0);
if (((Subtarget.hasSSSE3() && (VT == MVT::v8i16 || VT == MVT::v4i32)) ||
(Subtarget.hasInt256() && (VT == MVT::v16i16 || VT == MVT::v8i32))) &&
- isHorizontalBinOp(Op0, Op1, true))
+ isHorizontalBinOp(Op0, Op1, false))
return DAG.getNode(X86ISD::HSUB, SDLoc(N), VT, Op0, Op1);
return OptimizeConditionalInDecrement(N, DAG);
}
-static SDValue combineVZext(SDNode *N, SelectionDAG &DAG,
- TargetLowering::DAGCombinerInfo &DCI,
- const X86Subtarget &Subtarget) {
+static SDValue combineVSZext(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const X86Subtarget &Subtarget) {
SDLoc DL(N);
+ unsigned Opcode = N->getOpcode();
MVT VT = N->getSimpleValueType(0);
MVT SVT = VT.getVectorElementType();
SDValue Op = N->getOperand(0);
@@ -30854,25 +33716,28 @@ static SDValue combineVZext(SDNode *N, SelectionDAG &DAG,
unsigned InputBits = OpEltVT.getSizeInBits() * VT.getVectorNumElements();
// Perform any constant folding.
+ // FIXME: Reduce constant pool usage and don't fold when OptSize is enabled.
if (ISD::isBuildVectorOfConstantSDNodes(Op.getNode())) {
- SmallVector<SDValue, 4> Vals;
- for (int i = 0, e = VT.getVectorNumElements(); i != e; ++i) {
+ unsigned NumDstElts = VT.getVectorNumElements();
+ SmallBitVector Undefs(NumDstElts, false);
+ SmallVector<APInt, 4> Vals(NumDstElts, APInt(SVT.getSizeInBits(), 0));
+ for (unsigned i = 0; i != NumDstElts; ++i) {
SDValue OpElt = Op.getOperand(i);
if (OpElt.getOpcode() == ISD::UNDEF) {
- Vals.push_back(DAG.getUNDEF(SVT));
+ Undefs[i] = true;
continue;
}
APInt Cst = cast<ConstantSDNode>(OpElt.getNode())->getAPIntValue();
- assert(Cst.getBitWidth() == OpEltVT.getSizeInBits());
- Cst = Cst.zextOrTrunc(SVT.getSizeInBits());
- Vals.push_back(DAG.getConstant(Cst, DL, SVT));
+ Vals[i] = Opcode == X86ISD::VZEXT ? Cst.zextOrTrunc(SVT.getSizeInBits())
+ : Cst.sextOrTrunc(SVT.getSizeInBits());
}
- return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Vals);
+ return getConstVector(Vals, Undefs, VT, DAG, DL);
}
// (vzext (bitcast (vzext (x)) -> (vzext x)
+ // TODO: (vsext (bitcast (vsext (x)) -> (vsext x)
SDValue V = peekThroughBitcasts(Op);
- if (V != Op && V.getOpcode() == X86ISD::VZEXT) {
+ if (Opcode == X86ISD::VZEXT && V != Op && V.getOpcode() == X86ISD::VZEXT) {
MVT InnerVT = V.getSimpleValueType();
MVT InnerEltVT = InnerVT.getVectorElementType();
@@ -30897,7 +33762,9 @@ static SDValue combineVZext(SDNode *N, SelectionDAG &DAG,
// Check if we can bypass extracting and re-inserting an element of an input
// vector. Essentially:
// (bitcast (sclr2vec (ext_vec_elt x))) -> (bitcast x)
- if (V.getOpcode() == ISD::SCALAR_TO_VECTOR &&
+ // TODO: Add X86ISD::VSEXT support
+ if (Opcode == X86ISD::VZEXT &&
+ V.getOpcode() == ISD::SCALAR_TO_VECTOR &&
V.getOperand(0).getOpcode() == ISD::EXTRACT_VECTOR_ELT &&
V.getOperand(0).getSimpleValueType().getSizeInBits() == InputBits) {
SDValue ExtractedV = V.getOperand(0);
@@ -30976,7 +33843,8 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
SelectionDAG &DAG = DCI.DAG;
switch (N->getOpcode()) {
default: break;
- case ISD::EXTRACT_VECTOR_ELT: return combineExtractVectorElt(N, DAG, DCI);
+ case ISD::EXTRACT_VECTOR_ELT:
+ return combineExtractVectorElt(N, DAG, DCI, Subtarget);
case ISD::VSELECT:
case ISD::SELECT:
case X86ISD::SHRUNKBLEND: return combineSelect(N, DAG, DCI, Subtarget);
@@ -31002,16 +33870,15 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
case ISD::FSUB: return combineFaddFsub(N, DAG, Subtarget);
case ISD::FNEG: return combineFneg(N, DAG, Subtarget);
case ISD::TRUNCATE: return combineTruncate(N, DAG, Subtarget);
+ case X86ISD::FAND: return combineFAnd(N, DAG, Subtarget);
+ case X86ISD::FANDN: return combineFAndn(N, DAG, Subtarget);
case X86ISD::FXOR:
case X86ISD::FOR: return combineFOr(N, DAG, Subtarget);
case X86ISD::FMIN:
case X86ISD::FMAX: return combineFMinFMax(N, DAG);
case ISD::FMINNUM:
case ISD::FMAXNUM: return combineFMinNumFMaxNum(N, DAG, Subtarget);
- case X86ISD::FAND: return combineFAnd(N, DAG, Subtarget);
- case X86ISD::FANDN: return combineFAndn(N, DAG, Subtarget);
case X86ISD::BT: return combineBT(N, DAG, DCI);
- case X86ISD::VZEXT_MOVL: return combineVZextMovl(N, DAG);
case ISD::ANY_EXTEND:
case ISD::ZERO_EXTEND: return combineZext(N, DAG, DCI, Subtarget);
case ISD::SIGN_EXTEND: return combineSext(N, DAG, DCI, Subtarget);
@@ -31019,7 +33886,10 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
case ISD::SETCC: return combineSetCC(N, DAG, Subtarget);
case X86ISD::SETCC: return combineX86SetCC(N, DAG, DCI, Subtarget);
case X86ISD::BRCOND: return combineBrCond(N, DAG, DCI, Subtarget);
- case X86ISD::VZEXT: return combineVZext(N, DAG, DCI, Subtarget);
+ case X86ISD::VSHLI:
+ case X86ISD::VSRLI: return combineVectorShift(N, DAG, DCI, Subtarget);
+ case X86ISD::VSEXT:
+ case X86ISD::VZEXT: return combineVSZext(N, DAG, DCI, Subtarget);
case X86ISD::SHUFP: // Handle all target specific shuffles
case X86ISD::INSERTPS:
case X86ISD::PALIGNR:
@@ -31043,11 +33913,17 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
case X86ISD::VPERMI:
case X86ISD::VPERMV:
case X86ISD::VPERMV3:
+ case X86ISD::VPERMIV3:
case X86ISD::VPERMIL2:
case X86ISD::VPERMILPI:
case X86ISD::VPERMILPV:
case X86ISD::VPERM2X128:
+ case X86ISD::VZEXT_MOVL:
case ISD::VECTOR_SHUFFLE: return combineShuffle(N, DAG, DCI,Subtarget);
+ case X86ISD::FMADD:
+ case X86ISD::FMADD_RND:
+ case X86ISD::FMADDS1_RND:
+ case X86ISD::FMADDS3_RND:
case ISD::FMA: return combineFMA(N, DAG, Subtarget);
case ISD::MGATHER:
case ISD::MSCATTER: return combineGatherScatter(N, DAG);
@@ -31133,7 +34009,7 @@ bool X86TargetLowering::IsDesirableToPromoteOp(SDValue Op, EVT &PVT) const {
case ISD::OR:
case ISD::XOR:
Commute = true;
- // fallthrough
+ LLVM_FALLTHROUGH;
case ISD::SUB: {
SDValue N0 = Op.getOperand(0);
SDValue N1 = Op.getOperand(1);
@@ -31280,9 +34156,11 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const {
case 'u':
case 'y':
case 'x':
+ case 'v':
case 'Y':
case 'l':
return C_RegisterClass;
+ case 'k': // AVX512 masking registers.
case 'a':
case 'b':
case 'c':
@@ -31306,6 +34184,19 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const {
break;
}
}
+ else if (Constraint.size() == 2) {
+ switch (Constraint[0]) {
+ default:
+ break;
+ case 'Y':
+ switch (Constraint[1]) {
+ default:
+ break;
+ case 'k':
+ return C_Register;
+ }
+ }
+ }
return TargetLowering::getConstraintType(Constraint);
}
@@ -31349,12 +34240,28 @@ TargetLowering::ConstraintWeight
if (type->isX86_MMXTy() && Subtarget.hasMMX())
weight = CW_SpecificReg;
break;
- case 'x':
case 'Y':
+ // Other "Y<x>" (e.g. "Yk") constraints should be implemented below.
+ if (constraint[1] == 'k') {
+ // Support for 'Yk' (similarly to the 'k' variant below).
+ weight = CW_SpecificReg;
+ break;
+ }
+ // Else fall through (handle "Y" constraint).
+ LLVM_FALLTHROUGH;
+ case 'v':
+ if ((type->getPrimitiveSizeInBits() == 512) && Subtarget.hasAVX512())
+ weight = CW_Register;
+ LLVM_FALLTHROUGH;
+ case 'x':
if (((type->getPrimitiveSizeInBits() == 128) && Subtarget.hasSSE1()) ||
((type->getPrimitiveSizeInBits() == 256) && Subtarget.hasFp256()))
weight = CW_Register;
break;
+ case 'k':
+ // Enable conditional vector operations using %k<#> registers.
+ weight = CW_SpecificReg;
+ break;
case 'I':
if (ConstantInt *C = dyn_cast<ConstantInt>(info.CallOperandVal)) {
if (C->getZExtValue() <= 31)
@@ -31601,60 +34508,21 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
/// Check if \p RC is a general purpose register class.
/// I.e., GR* or one of their variant.
static bool isGRClass(const TargetRegisterClass &RC) {
- switch (RC.getID()) {
- case X86::GR8RegClassID:
- case X86::GR8_ABCD_LRegClassID:
- case X86::GR8_ABCD_HRegClassID:
- case X86::GR8_NOREXRegClassID:
- case X86::GR16RegClassID:
- case X86::GR16_ABCDRegClassID:
- case X86::GR16_NOREXRegClassID:
- case X86::GR32RegClassID:
- case X86::GR32_ABCDRegClassID:
- case X86::GR32_TCRegClassID:
- case X86::GR32_NOREXRegClassID:
- case X86::GR32_NOAXRegClassID:
- case X86::GR32_NOSPRegClassID:
- case X86::GR32_NOREX_NOSPRegClassID:
- case X86::GR32_ADRegClassID:
- case X86::GR64RegClassID:
- case X86::GR64_ABCDRegClassID:
- case X86::GR64_TCRegClassID:
- case X86::GR64_TCW64RegClassID:
- case X86::GR64_NOREXRegClassID:
- case X86::GR64_NOSPRegClassID:
- case X86::GR64_NOREX_NOSPRegClassID:
- case X86::LOW32_ADDR_ACCESSRegClassID:
- case X86::LOW32_ADDR_ACCESS_RBPRegClassID:
- return true;
- default:
- return false;
- }
+ return RC.hasSuperClassEq(&X86::GR8RegClass) ||
+ RC.hasSuperClassEq(&X86::GR16RegClass) ||
+ RC.hasSuperClassEq(&X86::GR32RegClass) ||
+ RC.hasSuperClassEq(&X86::GR64RegClass) ||
+ RC.hasSuperClassEq(&X86::LOW32_ADDR_ACCESS_RBPRegClass);
}
/// Check if \p RC is a vector register class.
/// I.e., FR* / VR* or one of their variant.
static bool isFRClass(const TargetRegisterClass &RC) {
- switch (RC.getID()) {
- case X86::FR32RegClassID:
- case X86::FR32XRegClassID:
- case X86::FR64RegClassID:
- case X86::FR64XRegClassID:
- case X86::FR128RegClassID:
- case X86::VR64RegClassID:
- case X86::VR128RegClassID:
- case X86::VR128LRegClassID:
- case X86::VR128HRegClassID:
- case X86::VR128XRegClassID:
- case X86::VR256RegClassID:
- case X86::VR256LRegClassID:
- case X86::VR256HRegClassID:
- case X86::VR256XRegClassID:
- case X86::VR512RegClassID:
- return true;
- default:
- return false;
- }
+ return RC.hasSuperClassEq(&X86::FR32XRegClass) ||
+ RC.hasSuperClassEq(&X86::FR64XRegClass) ||
+ RC.hasSuperClassEq(&X86::VR128XRegClass) ||
+ RC.hasSuperClassEq(&X86::VR256XRegClass) ||
+ RC.hasSuperClassEq(&X86::VR512RegClass);
}
std::pair<unsigned, const TargetRegisterClass *>
@@ -31670,6 +34538,24 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
// TODO: Slight differences here in allocation order and leaving
// RIP in the class. Do they matter any more here than they do
// in the normal allocation?
+ case 'k':
+ if (Subtarget.hasAVX512()) {
+ // Only supported in AVX512 or later.
+ switch (VT.SimpleTy) {
+ default: break;
+ case MVT::i32:
+ return std::make_pair(0U, &X86::VK32RegClass);
+ case MVT::i16:
+ return std::make_pair(0U, &X86::VK16RegClass);
+ case MVT::i8:
+ return std::make_pair(0U, &X86::VK8RegClass);
+ case MVT::i1:
+ return std::make_pair(0U, &X86::VK1RegClass);
+ case MVT::i64:
+ return std::make_pair(0U, &X86::VK64RegClass);
+ }
+ }
+ break;
case 'q': // GENERAL_REGS in 64-bit mode, Q_REGS in 32-bit mode.
if (Subtarget.is64Bit()) {
if (VT == MVT::i32 || VT == MVT::f32)
@@ -31723,18 +34609,24 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
return std::make_pair(0U, &X86::VR64RegClass);
case 'Y': // SSE_REGS if SSE2 allowed
if (!Subtarget.hasSSE2()) break;
- // FALL THROUGH.
+ LLVM_FALLTHROUGH;
+ case 'v':
case 'x': // SSE_REGS if SSE1 allowed or AVX_REGS if AVX allowed
if (!Subtarget.hasSSE1()) break;
+ bool VConstraint = (Constraint[0] == 'v');
switch (VT.SimpleTy) {
default: break;
// Scalar SSE types.
case MVT::f32:
case MVT::i32:
+ if (VConstraint && Subtarget.hasAVX512() && Subtarget.hasVLX())
+ return std::make_pair(0U, &X86::FR32XRegClass);
return std::make_pair(0U, &X86::FR32RegClass);
case MVT::f64:
case MVT::i64:
+ if (VConstraint && Subtarget.hasVLX())
+ return std::make_pair(0U, &X86::FR64XRegClass);
return std::make_pair(0U, &X86::FR64RegClass);
// TODO: Handle f128 and i128 in FR128RegClass after it is tested well.
// Vector types.
@@ -31744,6 +34636,8 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
+ if (VConstraint && Subtarget.hasVLX())
+ return std::make_pair(0U, &X86::VR128XRegClass);
return std::make_pair(0U, &X86::VR128RegClass);
// AVX types.
case MVT::v32i8:
@@ -31752,6 +34646,8 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
case MVT::v4i64:
case MVT::v8f32:
case MVT::v4f64:
+ if (VConstraint && Subtarget.hasVLX())
+ return std::make_pair(0U, &X86::VR256XRegClass);
return std::make_pair(0U, &X86::VR256RegClass);
case MVT::v8f64:
case MVT::v16f32:
@@ -31761,6 +34657,29 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
}
break;
}
+ } else if (Constraint.size() == 2 && Constraint[0] == 'Y') {
+ switch (Constraint[1]) {
+ default:
+ break;
+ case 'k':
+ // This register class doesn't allocate k0 for masked vector operation.
+ if (Subtarget.hasAVX512()) { // Only supported in AVX512.
+ switch (VT.SimpleTy) {
+ default: break;
+ case MVT::i32:
+ return std::make_pair(0U, &X86::VK32WMRegClass);
+ case MVT::i16:
+ return std::make_pair(0U, &X86::VK16WMRegClass);
+ case MVT::i8:
+ return std::make_pair(0U, &X86::VK8WMRegClass);
+ case MVT::i1:
+ return std::make_pair(0U, &X86::VK1WMRegClass);
+ case MVT::i64:
+ return std::make_pair(0U, &X86::VK64WMRegClass);
+ }
+ }
+ break;
+ }
}
// Use the default implementation in TargetLowering to convert the register
@@ -31954,3 +34873,7 @@ void X86TargetLowering::insertCopiesSplitCSR(
.addReg(NewVR);
}
}
+
+bool X86TargetLowering::supportSwiftError() const {
+ return Subtarget.is64Bit();
+}
diff --git a/contrib/llvm/lib/Target/X86/X86ISelLowering.h b/contrib/llvm/lib/Target/X86/X86ISelLowering.h
index d826f1e..37f9353 100644
--- a/contrib/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/contrib/llvm/lib/Target/X86/X86ISelLowering.h
@@ -95,7 +95,7 @@ namespace llvm {
SETCC,
/// X86 Select
- SELECT,
+ SELECT, SELECTS,
// Same as SETCC except it's materialized with a sbb and the value is all
// one's or all zero's.
@@ -106,6 +106,10 @@ namespace llvm {
/// 0s or 1s. Generally DTRT for C/C++ with NaNs.
FSETCC,
+ /// X86 FP SETCC, similar to above, but with output as an i1 mask and
+ /// with optional rounding mode.
+ FSETCCM, FSETCCM_RND,
+
/// X86 conditional moves. Operand 0 and operand 1 are the two values
/// to select from. Operand 2 is the condition code, and operand 3 is the
/// flag operand produced by a CMP or TEST instruction. It also writes a
@@ -135,8 +139,9 @@ namespace llvm {
/// at function entry, used for PIC code.
GlobalBaseReg,
- /// A wrapper node for TargetConstantPool,
- /// TargetExternalSymbol, and TargetGlobalAddress.
+ /// A wrapper node for TargetConstantPool, TargetJumpTable,
+ /// TargetExternalSymbol, TargetGlobalAddress, TargetGlobalTLSAddress,
+ /// MCSymbol and TargetBlockAddress.
Wrapper,
/// Special wrapper used under X86-64 PIC mode for RIP
@@ -205,12 +210,12 @@ namespace llvm {
FDIV_RND,
FMAX_RND,
FMIN_RND,
- FSQRT_RND,
+ FSQRT_RND, FSQRTS_RND,
// FP vector get exponent.
- FGETEXP_RND,
+ FGETEXP_RND, FGETEXPS_RND,
// Extract Normalized Mantissas.
- VGETMANT,
+ VGETMANT, VGETMANTS,
// FP Scale.
SCALEF,
SCALEFS,
@@ -251,7 +256,7 @@ namespace llvm {
/// in order to obtain suitable precision.
FRSQRT, FRCP,
FRSQRTS, FRCPS,
-
+
// Thread Local Storage.
TLSADDR,
@@ -293,13 +298,10 @@ namespace llvm {
VTRUNCUS, VTRUNCS,
// Vector FP extend.
- VFPEXT,
+ VFPEXT, VFPEXT_RND, VFPEXTS_RND,
// Vector FP round.
- VFPROUND,
-
- // Vector signed/unsigned integer to double.
- CVTDQ2PD, CVTUDQ2PD,
+ VFPROUND, VFPROUND_RND, VFPROUNDS_RND,
// Convert a vector to mask, set bits base on MSB.
CVT2MASK,
@@ -426,9 +428,9 @@ namespace llvm {
// Range Restriction Calculation For Packed Pairs of Float32/64 values.
VRANGE,
// Reduce - Perform Reduction Transformation on scalar\packed FP.
- VREDUCE,
+ VREDUCE, VREDUCES,
// RndScale - Round FP Values To Include A Given Number Of Fraction Bits.
- VRNDSCALE,
+ VRNDSCALE, VRNDSCALES,
// Tests Types Of a FP Values for packed types.
VFPCLASS,
// Tests Types Of a FP Values for scalar types.
@@ -486,19 +488,33 @@ namespace llvm {
FMADDSUB_RND,
FMSUBADD_RND,
+ // Scalar intrinsic FMA with rounding mode.
+ // Two versions, passthru bits on op1 or op3.
+ FMADDS1_RND, FMADDS3_RND,
+ FNMADDS1_RND, FNMADDS3_RND,
+ FMSUBS1_RND, FMSUBS3_RND,
+ FNMSUBS1_RND, FNMSUBS3_RND,
+
// Compress and expand.
COMPRESS,
EXPAND,
- // Convert Unsigned/Integer to Scalar Floating-Point Value
- // with rounding mode.
- SINT_TO_FP_RND,
- UINT_TO_FP_RND,
+ // Convert Unsigned/Integer to Floating-Point Value with rounding mode.
+ SINT_TO_FP_RND, UINT_TO_FP_RND,
+ SCALAR_SINT_TO_FP_RND, SCALAR_UINT_TO_FP_RND,
// Vector float/double to signed/unsigned integer.
- FP_TO_SINT_RND, FP_TO_UINT_RND,
+ CVTP2SI, CVTP2UI, CVTP2SI_RND, CVTP2UI_RND,
// Scalar float/double to signed/unsigned integer.
- SCALAR_FP_TO_SINT_RND, SCALAR_FP_TO_UINT_RND,
+ CVTS2SI_RND, CVTS2UI_RND,
+
+ // Vector float/double to signed/unsigned integer with truncation.
+ CVTTP2SI, CVTTP2UI, CVTTP2SI_RND, CVTTP2UI_RND,
+ // Scalar float/double to signed/unsigned integer with truncation.
+ CVTTS2SI_RND, CVTTS2UI_RND,
+
+ // Vector signed/unsigned integer to float/double.
+ CVTSI2P, CVTUI2P,
// Save xmm argument registers to the stack, according to %al. An operator
// is needed so that this can be expanded with control flow.
@@ -537,7 +553,10 @@ namespace llvm {
XTEST,
// ERI instructions.
- RSQRT28, RCP28, EXP2,
+ RSQRT28, RSQRT28S, RCP28, RCP28S, EXP2,
+
+ // Conversions between float and half-float.
+ CVTPS2PH, CVTPH2PS,
// Compare and swap.
LCMPXCHG_DAG = ISD::FIRST_TARGET_MEMORY_OPCODE,
@@ -587,7 +606,12 @@ namespace llvm {
/// This instruction grabs the address of the next argument
/// from a va_list. (reads and modifies the va_list in memory)
- VAARG_64
+ VAARG_64,
+
+ // Vector truncating store with unsigned/signed saturation
+ VTRUNCSTOREUS, VTRUNCSTORES,
+ // Vector truncating masked store with unsigned/signed saturation
+ VMTRUNCSTOREUS, VMTRUNCSTORES
// WARNING: Do not add anything in the end unless you want the node to
// have memop! In fact, starting from FIRST_TARGET_MEMORY_OPCODE all
@@ -760,10 +784,28 @@ namespace llvm {
bool isCheapToSpeculateCtlz() const override;
+ bool isCtlzFast() const override;
+
bool hasBitPreservingFPLogic(EVT VT) const override {
return VT == MVT::f32 || VT == MVT::f64 || VT.isVector();
}
+ bool isMultiStoresCheaperThanBitsMerge(EVT LTy, EVT HTy) const override {
+ // If the pair to store is a mixture of float and int values, we will
+ // save two bitwise instructions and one float-to-int instruction and
+ // increase one store instruction. There is potentially a more
+ // significant benefit because it avoids the float->int domain switch
+ // for input value. So It is more likely a win.
+ if ((LTy.isFloatingPoint() && HTy.isInteger()) ||
+ (LTy.isInteger() && HTy.isFloatingPoint()))
+ return true;
+ // If the pair only contains int values, we will save two bitwise
+ // instructions and increase one store instruction (costing one more
+ // store buffer). Since the benefit is more blurred so we leave
+ // such pair out until we get testcase to prove it is a win.
+ return false;
+ }
+
bool hasAndNotCompare(SDValue Y) const override;
/// Return the value type to use for ISD::SETCC.
@@ -995,10 +1037,16 @@ namespace llvm {
bool isIntDivCheap(EVT VT, AttributeSet Attr) const override;
- bool supportSwiftError() const override {
- return true;
- }
+ bool supportSwiftError() const override;
+ unsigned getMaxSupportedInterleaveFactor() const override { return 4; }
+
+ /// \brief Lower interleaved load(s) into target specific
+ /// instructions/intrinsics.
+ bool lowerInterleavedLoad(LoadInst *LI,
+ ArrayRef<ShuffleVectorInst *> Shuffles,
+ ArrayRef<unsigned> Indices,
+ unsigned Factor) const override;
protected:
std::pair<const TargetRegisterClass *, uint8_t>
findRepresentativeClass(const TargetRegisterInfo *TRI,
@@ -1032,7 +1080,7 @@ namespace llvm {
SDValue LowerMemArgument(SDValue Chain, CallingConv::ID CallConv,
const SmallVectorImpl<ISD::InputArg> &ArgInfo,
const SDLoc &dl, SelectionDAG &DAG,
- const CCValAssign &VA, MachineFrameInfo *MFI,
+ const CCValAssign &VA, MachineFrameInfo &MFI,
unsigned i) const;
SDValue LowerMemOpCallTo(SDValue Chain, SDValue StackPtr, SDValue Arg,
const SDLoc &dl, SelectionDAG &DAG,
@@ -1073,8 +1121,9 @@ namespace llvm {
SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
SDValue ExtractBitFromMaskVector(SDValue Op, SelectionDAG &DAG) const;
SDValue InsertBitToMaskVector(SDValue Op, SelectionDAG &DAG) const;
-
SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
+
+ unsigned getGlobalWrapperKind(const GlobalValue *GV = nullptr) const;
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(const GlobalValue *GV, const SDLoc &dl,
@@ -1082,14 +1131,15 @@ namespace llvm {
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const;
+
SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerUINT_TO_FP_i64(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerUINT_TO_FP_i32(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerUINT_TO_FP_vec(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerTRUNCATE(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerFP_TO_UINT(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerFP_TO_INT(SDValue Op, const X86Subtarget &Subtarget,
+ SelectionDAG &DAG) const;
SDValue LowerToBT(SDValue And, ISD::CondCode CC, const SDLoc &dl,
SelectionDAG &DAG) const;
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
@@ -1101,6 +1151,7 @@ namespace llvm {
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
@@ -1219,14 +1270,17 @@ namespace llvm {
/// Convert a comparison if required by the subtarget.
SDValue ConvertCmpIfNecessary(SDValue Cmp, SelectionDAG &DAG) const;
+ /// Check if replacement of SQRT with RSQRT should be disabled.
+ bool isFsqrtCheap(SDValue Operand, SelectionDAG &DAG) const override;
+
/// Use rsqrt* to speed up sqrt calculations.
- SDValue getRsqrtEstimate(SDValue Operand, DAGCombinerInfo &DCI,
- unsigned &RefinementSteps,
- bool &UseOneConstNR) const override;
+ SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps, bool &UseOneConstNR,
+ bool Reciprocal) const override;
/// Use rcp* to speed up fdiv calculations.
- SDValue getRecipEstimate(SDValue Operand, DAGCombinerInfo &DCI,
- unsigned &RefinementSteps) const override;
+ SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled,
+ int &RefinementSteps) const override;
/// Reassociate floating point divisions into multiply by reciprocal.
unsigned combineRepeatedFPDivisors() const override;
@@ -1236,6 +1290,93 @@ namespace llvm {
FastISel *createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo);
} // end namespace X86
+
+ // Base class for all X86 non-masked store operations.
+ class X86StoreSDNode : public MemSDNode {
+ public:
+ X86StoreSDNode(unsigned Opcode, unsigned Order, const DebugLoc &dl,
+ SDVTList VTs, EVT MemVT,
+ MachineMemOperand *MMO)
+ :MemSDNode(Opcode, Order, dl, VTs, MemVT, MMO) {}
+ const SDValue &getValue() const { return getOperand(1); }
+ const SDValue &getBasePtr() const { return getOperand(2); }
+
+ static bool classof(const SDNode *N) {
+ return N->getOpcode() == X86ISD::VTRUNCSTORES ||
+ N->getOpcode() == X86ISD::VTRUNCSTOREUS;
+ }
+ };
+
+ // Base class for all X86 masked store operations.
+ // The class has the same order of operands as MaskedStoreSDNode for
+ // convenience.
+ class X86MaskedStoreSDNode : public MemSDNode {
+ public:
+ X86MaskedStoreSDNode(unsigned Opcode, unsigned Order,
+ const DebugLoc &dl, SDVTList VTs, EVT MemVT,
+ MachineMemOperand *MMO)
+ : MemSDNode(Opcode, Order, dl, VTs, MemVT, MMO) {}
+
+ const SDValue &getBasePtr() const { return getOperand(1); }
+ const SDValue &getMask() const { return getOperand(2); }
+ const SDValue &getValue() const { return getOperand(3); }
+
+ static bool classof(const SDNode *N) {
+ return N->getOpcode() == X86ISD::VMTRUNCSTORES ||
+ N->getOpcode() == X86ISD::VMTRUNCSTOREUS;
+ }
+ };
+
+ // X86 Truncating Store with Signed saturation.
+ class TruncSStoreSDNode : public X86StoreSDNode {
+ public:
+ TruncSStoreSDNode(unsigned Order, const DebugLoc &dl,
+ SDVTList VTs, EVT MemVT, MachineMemOperand *MMO)
+ : X86StoreSDNode(X86ISD::VTRUNCSTORES, Order, dl, VTs, MemVT, MMO) {}
+
+ static bool classof(const SDNode *N) {
+ return N->getOpcode() == X86ISD::VTRUNCSTORES;
+ }
+ };
+
+ // X86 Truncating Store with Unsigned saturation.
+ class TruncUSStoreSDNode : public X86StoreSDNode {
+ public:
+ TruncUSStoreSDNode(unsigned Order, const DebugLoc &dl,
+ SDVTList VTs, EVT MemVT, MachineMemOperand *MMO)
+ : X86StoreSDNode(X86ISD::VTRUNCSTOREUS, Order, dl, VTs, MemVT, MMO) {}
+
+ static bool classof(const SDNode *N) {
+ return N->getOpcode() == X86ISD::VTRUNCSTOREUS;
+ }
+ };
+
+ // X86 Truncating Masked Store with Signed saturation.
+ class MaskedTruncSStoreSDNode : public X86MaskedStoreSDNode {
+ public:
+ MaskedTruncSStoreSDNode(unsigned Order,
+ const DebugLoc &dl, SDVTList VTs, EVT MemVT,
+ MachineMemOperand *MMO)
+ : X86MaskedStoreSDNode(X86ISD::VMTRUNCSTORES, Order, dl, VTs, MemVT, MMO) {}
+
+ static bool classof(const SDNode *N) {
+ return N->getOpcode() == X86ISD::VMTRUNCSTORES;
+ }
+ };
+
+ // X86 Truncating Masked Store with Unsigned saturation.
+ class MaskedTruncUSStoreSDNode : public X86MaskedStoreSDNode {
+ public:
+ MaskedTruncUSStoreSDNode(unsigned Order,
+ const DebugLoc &dl, SDVTList VTs, EVT MemVT,
+ MachineMemOperand *MMO)
+ : X86MaskedStoreSDNode(X86ISD::VMTRUNCSTOREUS, Order, dl, VTs, MemVT, MMO) {}
+
+ static bool classof(const SDNode *N) {
+ return N->getOpcode() == X86ISD::VMTRUNCSTOREUS;
+ }
+ };
+
} // end namespace llvm
#endif // LLVM_LIB_TARGET_X86_X86ISELLOWERING_H
diff --git a/contrib/llvm/lib/Target/X86/X86InstrAVX512.td b/contrib/llvm/lib/Target/X86/X86InstrAVX512.td
index 803a7e3..230d170 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrAVX512.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrAVX512.td
@@ -77,15 +77,15 @@ class X86VectorVTInfo<int numelts, ValueType eltvt, RegisterClass rc,
!if (!eq (TypeVariantName, "i"),
!if (!eq (Size, 128), "v2i64",
!if (!eq (Size, 256), "v4i64",
- VTName)), VTName));
+ !if (!eq (Size, 512), "v8i64",
+ VTName))), VTName));
PatFrag AlignedLdFrag = !cast<PatFrag>("alignedload" #
- !if (!eq (TypeVariantName, "i"),
- !if (!eq (Size, 128), "v2i64",
- !if (!eq (Size, 256), "v4i64",
- !if (!eq (Size, 512),
- !if (!eq (EltSize, 64), "v8i64", "v16i32"),
- VTName))), VTName));
+ !if (!eq (TypeVariantName, "i"),
+ !if (!eq (Size, 128), "v2i64",
+ !if (!eq (Size, 256), "v4i64",
+ !if (!eq (Size, 512), "v8i64",
+ VTName))), VTName));
PatFrag ScalarLdFrag = !cast<PatFrag>("load" # EltVT);
@@ -122,6 +122,10 @@ class X86VectorVTInfo<int numelts, ValueType eltvt, RegisterClass rc,
RegisterClass FRC = !if (!eq (EltTypeName, "f32"), FR32X, FR64X);
+ // A vector tye of the same width with element type i64. This is used to
+ // create patterns for logic ops.
+ ValueType i64VT = !cast<ValueType>("v" # !srl(Size, 6) # "i64");
+
// A vector type of the same width with element type i32. This is used to
// create the canonical constant zero node ImmAllZerosV.
ValueType i32VT = !cast<ValueType>("v" # !srl(Size, 5) # "i32");
@@ -194,7 +198,8 @@ multiclass AVX512_maskable_custom<bits<8> O, Format F,
list<dag> ZeroMaskingPattern,
string MaskingConstraint = "",
InstrItinClass itin = NoItinerary,
- bit IsCommutable = 0> {
+ bit IsCommutable = 0,
+ bit IsKCommutable = 0> {
let isCommutable = IsCommutable in
def NAME: AVX512<O, F, Outs, Ins,
OpcodeStr#"\t{"#AttSrcAsm#", $dst|"#
@@ -202,7 +207,7 @@ multiclass AVX512_maskable_custom<bits<8> O, Format F,
Pattern, itin>;
// Prefer over VMOV*rrk Pat<>
- let AddedComplexity = 20 in
+ let AddedComplexity = 20, isCommutable = IsKCommutable in
def NAME#k: AVX512<O, F, Outs, MaskingIns,
OpcodeStr#"\t{"#AttSrcAsm#", $dst {${mask}}|"#
"$dst {${mask}}, "#IntelSrcAsm#"}",
@@ -210,8 +215,11 @@ multiclass AVX512_maskable_custom<bits<8> O, Format F,
EVEX_K {
// In case of the 3src subclass this is overridden with a let.
string Constraints = MaskingConstraint;
- }
- let AddedComplexity = 30 in // Prefer over VMOV*rrkz Pat<>
+ }
+
+ // Zero mask does not add any restrictions to commute operands transformation.
+ // So, it is Ok to use IsCommutable instead of IsKCommutable.
+ let AddedComplexity = 30, isCommutable = IsCommutable in // Prefer over VMOV*rrkz Pat<>
def NAME#kz: AVX512<O, F, Outs, ZeroMaskingIns,
OpcodeStr#"\t{"#AttSrcAsm#", $dst {${mask}} {z}|"#
"$dst {${mask}} {z}, "#IntelSrcAsm#"}",
@@ -231,14 +239,16 @@ multiclass AVX512_maskable_common<bits<8> O, Format F, X86VectorVTInfo _,
SDNode Select = vselect,
string MaskingConstraint = "",
InstrItinClass itin = NoItinerary,
- bit IsCommutable = 0> :
+ bit IsCommutable = 0,
+ bit IsKCommutable = 0> :
AVX512_maskable_custom<O, F, Outs, Ins, MaskingIns, ZeroMaskingIns, OpcodeStr,
AttSrcAsm, IntelSrcAsm,
[(set _.RC:$dst, RHS)],
[(set _.RC:$dst, MaskingRHS)],
[(set _.RC:$dst,
(Select _.KRCWM:$mask, RHS, _.ImmAllZerosV))],
- MaskingConstraint, NoItinerary, IsCommutable>;
+ MaskingConstraint, NoItinerary, IsCommutable,
+ IsKCommutable>;
// This multiclass generates the unconditional/non-masking, the masking and
// the zero-masking variant of the vector instruction. In the masking case, the
@@ -248,13 +258,14 @@ multiclass AVX512_maskable<bits<8> O, Format F, X86VectorVTInfo _,
string AttSrcAsm, string IntelSrcAsm,
dag RHS,
InstrItinClass itin = NoItinerary,
- bit IsCommutable = 0, SDNode Select = vselect> :
+ bit IsCommutable = 0, bit IsKCommutable = 0,
+ SDNode Select = vselect> :
AVX512_maskable_common<O, F, _, Outs, Ins,
!con((ins _.RC:$src0, _.KRCWM:$mask), Ins),
!con((ins _.KRCWM:$mask), Ins),
OpcodeStr, AttSrcAsm, IntelSrcAsm, RHS,
(Select _.KRCWM:$mask, RHS, _.RC:$src0), Select,
- "$src0 = $dst", itin, IsCommutable>;
+ "$src0 = $dst", itin, IsCommutable, IsKCommutable>;
// This multiclass generates the unconditional/non-masking, the masking and
// the zero-masking variant of the scalar instruction.
@@ -278,41 +289,29 @@ multiclass AVX512_maskable_scalar<bits<8> O, Format F, X86VectorVTInfo _,
multiclass AVX512_maskable_3src<bits<8> O, Format F, X86VectorVTInfo _,
dag Outs, dag NonTiedIns, string OpcodeStr,
string AttSrcAsm, string IntelSrcAsm,
- dag RHS> :
+ dag RHS, bit IsCommutable = 0,
+ bit IsKCommutable = 0> :
AVX512_maskable_common<O, F, _, Outs,
!con((ins _.RC:$src1), NonTiedIns),
!con((ins _.RC:$src1, _.KRCWM:$mask), NonTiedIns),
!con((ins _.RC:$src1, _.KRCWM:$mask), NonTiedIns),
OpcodeStr, AttSrcAsm, IntelSrcAsm, RHS,
- (vselect _.KRCWM:$mask, RHS, _.RC:$src1)>;
-
-// Similar to AVX512_maskable_3rc but in this case the input VT for the tied
-// operand differs from the output VT. This requires a bitconvert on
-// the preserved vector going into the vselect.
-multiclass AVX512_maskable_3src_cast<bits<8> O, Format F, X86VectorVTInfo OutVT,
- X86VectorVTInfo InVT,
- dag Outs, dag NonTiedIns, string OpcodeStr,
- string AttSrcAsm, string IntelSrcAsm,
- dag RHS> :
- AVX512_maskable_common<O, F, OutVT, Outs,
- !con((ins InVT.RC:$src1), NonTiedIns),
- !con((ins InVT.RC:$src1, InVT.KRCWM:$mask), NonTiedIns),
- !con((ins InVT.RC:$src1, InVT.KRCWM:$mask), NonTiedIns),
- OpcodeStr, AttSrcAsm, IntelSrcAsm, RHS,
- (vselect InVT.KRCWM:$mask, RHS,
- (bitconvert InVT.RC:$src1))>;
+ (vselect _.KRCWM:$mask, RHS, _.RC:$src1),
+ vselect, "", NoItinerary, IsCommutable, IsKCommutable>;
multiclass AVX512_maskable_3src_scalar<bits<8> O, Format F, X86VectorVTInfo _,
dag Outs, dag NonTiedIns, string OpcodeStr,
string AttSrcAsm, string IntelSrcAsm,
- dag RHS> :
+ dag RHS, bit IsCommutable = 0,
+ bit IsKCommutable = 0> :
AVX512_maskable_common<O, F, _, Outs,
!con((ins _.RC:$src1), NonTiedIns),
!con((ins _.RC:$src1, _.KRCWM:$mask), NonTiedIns),
!con((ins _.RC:$src1, _.KRCWM:$mask), NonTiedIns),
OpcodeStr, AttSrcAsm, IntelSrcAsm, RHS,
(X86selects _.KRCWM:$mask, RHS, _.RC:$src1),
- X86selects>;
+ X86selects, "", NoItinerary, IsCommutable,
+ IsKCommutable>;
multiclass AVX512_maskable_in_asm<bits<8> O, Format F, X86VectorVTInfo _,
dag Outs, dag Ins,
@@ -334,7 +333,9 @@ multiclass AVX512_maskable_custom_cmp<bits<8> O, Format F,
string OpcodeStr,
string AttSrcAsm, string IntelSrcAsm,
list<dag> Pattern,
- list<dag> MaskingPattern> {
+ list<dag> MaskingPattern,
+ bit IsCommutable = 0> {
+ let isCommutable = IsCommutable in
def NAME: AVX512<O, F, Outs, Ins,
OpcodeStr#"\t{"#AttSrcAsm#", $dst|"#
"$dst, "#IntelSrcAsm#"}",
@@ -351,20 +352,21 @@ multiclass AVX512_maskable_common_cmp<bits<8> O, Format F, X86VectorVTInfo _,
dag Ins, dag MaskingIns,
string OpcodeStr,
string AttSrcAsm, string IntelSrcAsm,
- dag RHS, dag MaskingRHS> :
+ dag RHS, dag MaskingRHS,
+ bit IsCommutable = 0> :
AVX512_maskable_custom_cmp<O, F, Outs, Ins, MaskingIns, OpcodeStr,
AttSrcAsm, IntelSrcAsm,
[(set _.KRC:$dst, RHS)],
- [(set _.KRC:$dst, MaskingRHS)]>;
+ [(set _.KRC:$dst, MaskingRHS)], IsCommutable>;
multiclass AVX512_maskable_cmp<bits<8> O, Format F, X86VectorVTInfo _,
dag Outs, dag Ins, string OpcodeStr,
string AttSrcAsm, string IntelSrcAsm,
- dag RHS> :
+ dag RHS, bit IsCommutable = 0> :
AVX512_maskable_common_cmp<O, F, _, Outs, Ins,
!con((ins _.KRCWM:$mask), Ins),
OpcodeStr, AttSrcAsm, IntelSrcAsm, RHS,
- (and _.KRCWM:$mask, RHS)>;
+ (and _.KRCWM:$mask, RHS), IsCommutable>;
multiclass AVX512_maskable_cmp_alt<bits<8> O, Format F, X86VectorVTInfo _,
dag Outs, dag Ins, string OpcodeStr,
@@ -373,6 +375,27 @@ multiclass AVX512_maskable_cmp_alt<bits<8> O, Format F, X86VectorVTInfo _,
Ins, !con((ins _.KRCWM:$mask),Ins), OpcodeStr,
AttSrcAsm, IntelSrcAsm, [],[]>;
+// This multiclass generates the unconditional/non-masking, the masking and
+// the zero-masking variant of the vector instruction. In the masking case, the
+// perserved vector elements come from a new dummy input operand tied to $dst.
+multiclass AVX512_maskable_logic<bits<8> O, Format F, X86VectorVTInfo _,
+ dag Outs, dag Ins, string OpcodeStr,
+ string AttSrcAsm, string IntelSrcAsm,
+ dag RHS, dag MaskedRHS,
+ InstrItinClass itin = NoItinerary,
+ bit IsCommutable = 0, SDNode Select = vselect> :
+ AVX512_maskable_custom<O, F, Outs, Ins,
+ !con((ins _.RC:$src0, _.KRCWM:$mask), Ins),
+ !con((ins _.KRCWM:$mask), Ins),
+ OpcodeStr, AttSrcAsm, IntelSrcAsm,
+ [(set _.RC:$dst, RHS)],
+ [(set _.RC:$dst,
+ (Select _.KRCWM:$mask, MaskedRHS, _.RC:$src0))],
+ [(set _.RC:$dst,
+ (Select _.KRCWM:$mask, MaskedRHS,
+ _.ImmAllZerosV))],
+ "$src0 = $dst", itin, IsCommutable>;
+
// Bitcasts between 512-bit vector types. Return the original type since
// no instruction is needed for the conversion.
def : Pat<(v8f64 (bitconvert (v8i64 VR512:$src))), (v8f64 VR512:$src)>;
@@ -420,6 +443,22 @@ def AVX512_512_SETALLONES : I<0, Pseudo, (outs VR512:$dst), (ins), "",
[(set VR512:$dst, (v16i32 immAllOnesV))]>;
}
+// Alias instructions that allow VPTERNLOG to be used with a mask to create
+// a mix of all ones and all zeros elements. This is done this way to force
+// the same register to be used as input for all three sources.
+let isPseudo = 1, Predicates = [HasAVX512] in {
+def AVX512_512_SEXT_MASK_32 : I<0, Pseudo, (outs VR512:$dst),
+ (ins VK16WM:$mask), "",
+ [(set VR512:$dst, (vselect (v16i1 VK16WM:$mask),
+ (v16i32 immAllOnesV),
+ (v16i32 immAllZerosV)))]>;
+def AVX512_512_SEXT_MASK_64 : I<0, Pseudo, (outs VR512:$dst),
+ (ins VK8WM:$mask), "",
+ [(set VR512:$dst, (vselect (v8i1 VK8WM:$mask),
+ (bc_v8i64 (v16i32 immAllOnesV)),
+ (bc_v8i64 (v16i32 immAllZerosV))))]>;
+}
+
let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1,
isPseudo = 1, Predicates = [HasVLX], SchedRW = [WriteZero] in {
def AVX512_128_SET0 : I<0, Pseudo, (outs VR128X:$dst), (ins), "",
@@ -428,6 +467,16 @@ def AVX512_256_SET0 : I<0, Pseudo, (outs VR256X:$dst), (ins), "",
[(set VR256X:$dst, (v8i32 immAllZerosV))]>;
}
+// Alias instructions that map fld0 to xorps for sse or vxorps for avx.
+// This is expanded by ExpandPostRAPseudos.
+let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1,
+ isPseudo = 1, SchedRW = [WriteZero], Predicates = [HasVLX, HasDQI] in {
+ def AVX512_FsFLD0SS : I<0, Pseudo, (outs FR32X:$dst), (ins), "",
+ [(set FR32X:$dst, fp32imm0)]>;
+ def AVX512_FsFLD0SD : I<0, Pseudo, (outs FR64X:$dst), (ins), "",
+ [(set FR64X:$dst, fpimm0)]>;
+}
+
//===----------------------------------------------------------------------===//
// AVX-512 - VECTOR INSERT
//
@@ -548,25 +597,28 @@ defm : vinsert_for_size_lowering<"VINSERTI64x4Z", v32i8x_info, v64i8_info,
vinsert256_insert, INSERT_get_vinsert256_imm, [HasAVX512]>;
// vinsertps - insert f32 to XMM
-def VINSERTPSzrr : AVX512AIi8<0x21, MRMSrcReg, (outs VR128X:$dst),
+let ExeDomain = SSEPackedSingle in {
+def VINSERTPSZrr : AVX512AIi8<0x21, MRMSrcReg, (outs VR128X:$dst),
(ins VR128X:$src1, VR128X:$src2, u8imm:$src3),
"vinsertps\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}",
[(set VR128X:$dst, (X86insertps VR128X:$src1, VR128X:$src2, imm:$src3))]>,
EVEX_4V;
-def VINSERTPSzrm: AVX512AIi8<0x21, MRMSrcMem, (outs VR128X:$dst),
+def VINSERTPSZrm: AVX512AIi8<0x21, MRMSrcMem, (outs VR128X:$dst),
(ins VR128X:$src1, f32mem:$src2, u8imm:$src3),
"vinsertps\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}",
[(set VR128X:$dst, (X86insertps VR128X:$src1,
(v4f32 (scalar_to_vector (loadf32 addr:$src2))),
imm:$src3))]>, EVEX_4V, EVEX_CD8<32, CD8VT1>;
+}
//===----------------------------------------------------------------------===//
// AVX-512 VECTOR EXTRACT
//---
multiclass vextract_for_size<int Opcode,
- X86VectorVTInfo From, X86VectorVTInfo To,
- PatFrag vextract_extract> {
+ X86VectorVTInfo From, X86VectorVTInfo To,
+ PatFrag vextract_extract,
+ SDNodeXForm EXTRACT_get_vextract_imm> {
let hasSideEffects = 0, ExeDomain = To.ExeDomain in {
// use AVX512_maskable_in_asm (AVX512_maskable can't be used due to
@@ -597,32 +649,23 @@ multiclass vextract_for_size<int Opcode,
[]>, EVEX_K, EVEX;
}
- // Intrinsic call with masking.
- def : Pat<(!cast<Intrinsic>("int_x86_avx512_mask_vextract" # To.EltTypeName #
- "x" # To.NumElts # "_" # From.Size)
- From.RC:$src1, (iPTR imm:$idx), To.RC:$src0, To.MRC:$mask),
+ def : Pat<(To.VT (vselect To.KRCWM:$mask,
+ (vextract_extract:$ext (From.VT From.RC:$src1),
+ (iPTR imm)),
+ To.RC:$src0)),
(!cast<Instruction>(NAME # To.EltSize # "x" # To.NumElts #
From.ZSuffix # "rrk")
- To.RC:$src0,
- (COPY_TO_REGCLASS To.MRC:$mask, To.KRCWM),
- From.RC:$src1, imm:$idx)>;
-
- // Intrinsic call with zero-masking.
- def : Pat<(!cast<Intrinsic>("int_x86_avx512_mask_vextract" # To.EltTypeName #
- "x" # To.NumElts # "_" # From.Size)
- From.RC:$src1, (iPTR imm:$idx), To.ImmAllZerosV, To.MRC:$mask),
- (!cast<Instruction>(NAME # To.EltSize # "x" # To.NumElts #
- From.ZSuffix # "rrkz")
- (COPY_TO_REGCLASS To.MRC:$mask, To.KRCWM),
- From.RC:$src1, imm:$idx)>;
+ To.RC:$src0, To.KRCWM:$mask, From.RC:$src1,
+ (EXTRACT_get_vextract_imm To.RC:$ext))>;
- // Intrinsic call without masking.
- def : Pat<(!cast<Intrinsic>("int_x86_avx512_mask_vextract" # To.EltTypeName #
- "x" # To.NumElts # "_" # From.Size)
- From.RC:$src1, (iPTR imm:$idx), To.ImmAllZerosV, (i8 -1)),
+ def : Pat<(To.VT (vselect To.KRCWM:$mask,
+ (vextract_extract:$ext (From.VT From.RC:$src1),
+ (iPTR imm)),
+ To.ImmAllZerosV)),
(!cast<Instruction>(NAME # To.EltSize # "x" # To.NumElts #
- From.ZSuffix # "rr")
- From.RC:$src1, imm:$idx)>;
+ From.ZSuffix # "rrkz")
+ To.KRCWM:$mask, From.RC:$src1,
+ (EXTRACT_get_vextract_imm To.RC:$ext))>;
}
// Codegen pattern for the alternative types
@@ -642,39 +685,45 @@ multiclass vextract_for_size_lowering<string InstrStr, X86VectorVTInfo From,
}
multiclass vextract_for_type<ValueType EltVT32, int Opcode128,
- ValueType EltVT64, int Opcode256> {
+ ValueType EltVT64, int Opcode256> {
defm NAME # "32x4Z" : vextract_for_size<Opcode128,
X86VectorVTInfo<16, EltVT32, VR512>,
X86VectorVTInfo< 4, EltVT32, VR128X>,
- vextract128_extract>,
+ vextract128_extract,
+ EXTRACT_get_vextract128_imm>,
EVEX_V512, EVEX_CD8<32, CD8VT4>;
defm NAME # "64x4Z" : vextract_for_size<Opcode256,
X86VectorVTInfo< 8, EltVT64, VR512>,
X86VectorVTInfo< 4, EltVT64, VR256X>,
- vextract256_extract>,
+ vextract256_extract,
+ EXTRACT_get_vextract256_imm>,
VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT4>;
let Predicates = [HasVLX] in
defm NAME # "32x4Z256" : vextract_for_size<Opcode128,
X86VectorVTInfo< 8, EltVT32, VR256X>,
X86VectorVTInfo< 4, EltVT32, VR128X>,
- vextract128_extract>,
+ vextract128_extract,
+ EXTRACT_get_vextract128_imm>,
EVEX_V256, EVEX_CD8<32, CD8VT4>;
let Predicates = [HasVLX, HasDQI] in
defm NAME # "64x2Z256" : vextract_for_size<Opcode128,
X86VectorVTInfo< 4, EltVT64, VR256X>,
X86VectorVTInfo< 2, EltVT64, VR128X>,
- vextract128_extract>,
+ vextract128_extract,
+ EXTRACT_get_vextract128_imm>,
VEX_W, EVEX_V256, EVEX_CD8<64, CD8VT2>;
let Predicates = [HasDQI] in {
defm NAME # "64x2Z" : vextract_for_size<Opcode128,
X86VectorVTInfo< 8, EltVT64, VR512>,
X86VectorVTInfo< 2, EltVT64, VR128X>,
- vextract128_extract>,
+ vextract128_extract,
+ EXTRACT_get_vextract128_imm>,
VEX_W, EVEX_V512, EVEX_CD8<64, CD8VT2>;
defm NAME # "32x8Z" : vextract_for_size<Opcode256,
X86VectorVTInfo<16, EltVT32, VR512>,
X86VectorVTInfo< 8, EltVT32, VR256X>,
- vextract256_extract>,
+ vextract256_extract,
+ EXTRACT_get_vextract256_imm>,
EVEX_V512, EVEX_CD8<32, CD8VT8>;
}
}
@@ -986,6 +1035,25 @@ multiclass avx512_subvec_broadcast_rm<bits<8> opc, string OpcodeStr,
AVX5128IBase, EVEX;
}
+let Predicates = [HasVLX, HasBWI] in {
+ // loadi16 is tricky to fold, because !isTypeDesirableForOp, justifiably.
+ // This means we'll encounter truncated i32 loads; match that here.
+ def : Pat<(v8i16 (X86VBroadcast (i16 (trunc (i32 (load addr:$src)))))),
+ (VPBROADCASTWZ128m addr:$src)>;
+ def : Pat<(v16i16 (X86VBroadcast (i16 (trunc (i32 (load addr:$src)))))),
+ (VPBROADCASTWZ256m addr:$src)>;
+ def : Pat<(v8i16 (X86VBroadcast
+ (i16 (trunc (i32 (zextloadi16 addr:$src)))))),
+ (VPBROADCASTWZ128m addr:$src)>;
+ def : Pat<(v16i16 (X86VBroadcast
+ (i16 (trunc (i32 (zextloadi16 addr:$src)))))),
+ (VPBROADCASTWZ256m addr:$src)>;
+}
+
+//===----------------------------------------------------------------------===//
+// AVX-512 BROADCAST SUBVECTORS
+//
+
defm VBROADCASTI32X4 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti32x4",
v16i32_info, v4i32x_info>,
EVEX_V512, EVEX_CD8<32, CD8VT4>;
@@ -999,6 +1067,79 @@ defm VBROADCASTF64X4 : avx512_subvec_broadcast_rm<0x1b, "vbroadcastf64x4",
v8f64_info, v4f64x_info>, VEX_W,
EVEX_V512, EVEX_CD8<64, CD8VT4>;
+let Predicates = [HasAVX512] in {
+def : Pat<(v32i16 (X86SubVBroadcast (bc_v16i16 (loadv4i64 addr:$src)))),
+ (VBROADCASTI64X4rm addr:$src)>;
+def : Pat<(v64i8 (X86SubVBroadcast (bc_v32i8 (loadv4i64 addr:$src)))),
+ (VBROADCASTI64X4rm addr:$src)>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v16f32 (X86SubVBroadcast (v8f32 VR256X:$src))),
+ (VINSERTF64x4Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v8f32 VR256X:$src), 1)>;
+def : Pat<(v8f64 (X86SubVBroadcast (v4f64 VR256X:$src))),
+ (VINSERTF64x4Zrr (INSERT_SUBREG (v8f64 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v4f64 VR256X:$src), 1)>;
+def : Pat<(v8i64 (X86SubVBroadcast (v4i64 VR256X:$src))),
+ (VINSERTI64x4Zrr (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v4i64 VR256X:$src), 1)>;
+def : Pat<(v16i32 (X86SubVBroadcast (v8i32 VR256X:$src))),
+ (VINSERTI64x4Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v8i32 VR256X:$src), 1)>;
+def : Pat<(v32i16 (X86SubVBroadcast (v16i16 VR256X:$src))),
+ (VINSERTI64x4Zrr (INSERT_SUBREG (v32i16 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v16i16 VR256X:$src), 1)>;
+def : Pat<(v64i8 (X86SubVBroadcast (v32i8 VR256X:$src))),
+ (VINSERTI64x4Zrr (INSERT_SUBREG (v64i8 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v32i8 VR256X:$src), 1)>;
+
+def : Pat<(v32i16 (X86SubVBroadcast (bc_v8i16 (loadv2i64 addr:$src)))),
+ (VBROADCASTI32X4rm addr:$src)>;
+def : Pat<(v64i8 (X86SubVBroadcast (bc_v16i8 (loadv2i64 addr:$src)))),
+ (VBROADCASTI32X4rm addr:$src)>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v8f64 (X86SubVBroadcast (v2f64 VR128X:$src))),
+ (VINSERTF64x4Zrr
+ (VINSERTF32x4Zrr (INSERT_SUBREG (v8f64 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v8f64 (VINSERTF32x4Zrr (INSERT_SUBREG (v8f64 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+def : Pat<(v8i64 (X86SubVBroadcast (v2i64 VR128X:$src))),
+ (VINSERTI64x4Zrr
+ (VINSERTI32x4Zrr (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v8i64 (VINSERTI32x4Zrr (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+
+def : Pat<(v32i16 (X86SubVBroadcast (v8i16 VR128X:$src))),
+ (VINSERTI64x4Zrr
+ (VINSERTI32x4Zrr (INSERT_SUBREG (v32i16 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v32i16 (VINSERTI32x4Zrr (INSERT_SUBREG (v32i16 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+def : Pat<(v64i8 (X86SubVBroadcast (v16i8 VR128X:$src))),
+ (VINSERTI64x4Zrr
+ (VINSERTI32x4Zrr (INSERT_SUBREG (v64i8 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v64i8 (VINSERTI32x4Zrr (INSERT_SUBREG (v64i8 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+}
+
let Predicates = [HasVLX] in {
defm VBROADCASTI32X4Z256 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti32x4",
v8i32x_info, v4i32x_info>,
@@ -1006,7 +1147,28 @@ defm VBROADCASTI32X4Z256 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti32x4",
defm VBROADCASTF32X4Z256 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf32x4",
v8f32x_info, v4f32x_info>,
EVEX_V256, EVEX_CD8<32, CD8VT4>;
+
+def : Pat<(v16i16 (X86SubVBroadcast (bc_v8i16 (loadv2i64 addr:$src)))),
+ (VBROADCASTI32X4Z256rm addr:$src)>;
+def : Pat<(v32i8 (X86SubVBroadcast (bc_v16i8 (loadv2i64 addr:$src)))),
+ (VBROADCASTI32X4Z256rm addr:$src)>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v8f32 (X86SubVBroadcast (v4f32 VR128X:$src))),
+ (VINSERTF32x4Z256rr (INSERT_SUBREG (v8f32 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v4f32 VR128X:$src), 1)>;
+def : Pat<(v8i32 (X86SubVBroadcast (v4i32 VR128X:$src))),
+ (VINSERTI32x4Z256rr (INSERT_SUBREG (v8i32 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v4i32 VR128X:$src), 1)>;
+def : Pat<(v16i16 (X86SubVBroadcast (v8i16 VR128X:$src))),
+ (VINSERTI32x4Z256rr (INSERT_SUBREG (v16i16 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v8i16 VR128X:$src), 1)>;
+def : Pat<(v32i8 (X86SubVBroadcast (v16i8 VR128X:$src))),
+ (VINSERTI32x4Z256rr (INSERT_SUBREG (v32i8 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v16i8 VR128X:$src), 1)>;
}
+
let Predicates = [HasVLX, HasDQI] in {
defm VBROADCASTI64X2Z128 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti64x2",
v4i64x_info, v2i64x_info>, VEX_W,
@@ -1014,7 +1176,73 @@ defm VBROADCASTI64X2Z128 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti64x2",
defm VBROADCASTF64X2Z128 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf64x2",
v4f64x_info, v2f64x_info>, VEX_W,
EVEX_V256, EVEX_CD8<64, CD8VT2>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v4f64 (X86SubVBroadcast (v2f64 VR128X:$src))),
+ (VINSERTF64x2Z256rr (INSERT_SUBREG (v4f64 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v2f64 VR128X:$src), 1)>;
+def : Pat<(v4i64 (X86SubVBroadcast (v2i64 VR128X:$src))),
+ (VINSERTI64x2Z256rr (INSERT_SUBREG (v4i64 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v2i64 VR128X:$src), 1)>;
}
+
+let Predicates = [HasVLX, NoDQI] in {
+def : Pat<(v4f64 (X86SubVBroadcast (loadv2f64 addr:$src))),
+ (VBROADCASTF32X4Z256rm addr:$src)>;
+def : Pat<(v4i64 (X86SubVBroadcast (loadv2i64 addr:$src))),
+ (VBROADCASTI32X4Z256rm addr:$src)>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v4f64 (X86SubVBroadcast (v2f64 VR128X:$src))),
+ (VINSERTF32x4Z256rr (INSERT_SUBREG (v4f64 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v2f64 VR128X:$src), 1)>;
+def : Pat<(v4i64 (X86SubVBroadcast (v2i64 VR128X:$src))),
+ (VINSERTI32x4Z256rr (INSERT_SUBREG (v4i64 (IMPLICIT_DEF)), VR128X:$src, sub_xmm),
+ (v2i64 VR128X:$src), 1)>;
+}
+
+let Predicates = [HasAVX512, NoDQI] in {
+def : Pat<(v8f64 (X86SubVBroadcast (loadv2f64 addr:$src))),
+ (VBROADCASTF32X4rm addr:$src)>;
+def : Pat<(v8i64 (X86SubVBroadcast (loadv2i64 addr:$src))),
+ (VBROADCASTI32X4rm addr:$src)>;
+
+def : Pat<(v16f32 (X86SubVBroadcast (v4f32 VR128X:$src))),
+ (VINSERTF64x4Zrr
+ (VINSERTF32x4Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v16f32 (VINSERTF32x4Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+def : Pat<(v16i32 (X86SubVBroadcast (v4i32 VR128X:$src))),
+ (VINSERTI64x4Zrr
+ (VINSERTI32x4Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v16i32 (VINSERTI32x4Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+
+def : Pat<(v16f32 (X86SubVBroadcast (loadv8f32 addr:$src))),
+ (VBROADCASTF64X4rm addr:$src)>;
+def : Pat<(v16i32 (X86SubVBroadcast (bc_v8i32 (loadv4i64 addr:$src)))),
+ (VBROADCASTI64X4rm addr:$src)>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v16f32 (X86SubVBroadcast (v8f32 VR256X:$src))),
+ (VINSERTF64x4Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v8f32 VR256X:$src), 1)>;
+def : Pat<(v16i32 (X86SubVBroadcast (v8i32 VR256X:$src))),
+ (VINSERTI64x4Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v8i32 VR256X:$src), 1)>;
+}
+
let Predicates = [HasDQI] in {
defm VBROADCASTI64X2 : avx512_subvec_broadcast_rm<0x5a, "vbroadcasti64x2",
v8i64_info, v2i64x_info>, VEX_W,
@@ -1028,6 +1256,34 @@ defm VBROADCASTF64X2 : avx512_subvec_broadcast_rm<0x1a, "vbroadcastf64x2",
defm VBROADCASTF32X8 : avx512_subvec_broadcast_rm<0x1b, "vbroadcastf32x8",
v16f32_info, v8f32x_info>,
EVEX_V512, EVEX_CD8<32, CD8VT8>;
+
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+def : Pat<(v16f32 (X86SubVBroadcast (v8f32 VR256X:$src))),
+ (VINSERTF32x8Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v8f32 VR256X:$src), 1)>;
+def : Pat<(v16i32 (X86SubVBroadcast (v8i32 VR256X:$src))),
+ (VINSERTI32x8Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)), VR256X:$src, sub_ymm),
+ (v8i32 VR256X:$src), 1)>;
+
+def : Pat<(v16f32 (X86SubVBroadcast (v4f32 VR128X:$src))),
+ (VINSERTF32x8Zrr
+ (VINSERTF32x4Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v16f32 (VINSERTF32x4Zrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
+def : Pat<(v16i32 (X86SubVBroadcast (v4i32 VR128X:$src))),
+ (VINSERTI32x8Zrr
+ (VINSERTI32x4Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1),
+ (EXTRACT_SUBREG
+ (v16i32 (VINSERTI32x4Zrr (INSERT_SUBREG (v16i32 (IMPLICIT_DEF)),
+ VR128X:$src, sub_xmm),
+ VR128X:$src, 1)), sub_ymm), 1)>;
}
multiclass avx512_common_broadcast_32x2<bits<8> opc, string OpcodeStr,
@@ -1049,10 +1305,10 @@ multiclass avx512_common_broadcast_i32x2<bits<8> opc, string OpcodeStr,
EVEX_V128;
}
-defm VPBROADCASTI32X2 : avx512_common_broadcast_i32x2<0x59, "vbroadcasti32x2",
- avx512vl_i32_info, avx512vl_i64_info>;
-defm VPBROADCASTF32X2 : avx512_common_broadcast_32x2<0x19, "vbroadcastf32x2",
- avx512vl_f32_info, avx512vl_f64_info>;
+defm VBROADCASTI32X2 : avx512_common_broadcast_i32x2<0x59, "vbroadcasti32x2",
+ avx512vl_i32_info, avx512vl_i64_info>;
+defm VBROADCASTF32X2 : avx512_common_broadcast_32x2<0x19, "vbroadcastf32x2",
+ avx512vl_f32_info, avx512vl_f64_info>;
def : Pat<(v16f32 (X86VBroadcast (v16f32 VR512:$src))),
(VBROADCASTSSZr (EXTRACT_SUBREG (v16f32 VR512:$src), sub_xmm))>;
@@ -1091,112 +1347,105 @@ defm VPBROADCASTMB2Q : avx512_mask_broadcast<0x2A, "vpbroadcastmb2q",
//===----------------------------------------------------------------------===//
// -- VPERMI2 - 3 source operands form --
-multiclass avx512_perm_i<bits<8> opc, string OpcodeStr,
- X86VectorVTInfo _, X86VectorVTInfo IdxVT> {
-let Constraints = "$src1 = $dst" in {
- defm rr: AVX512_maskable_3src_cast<opc, MRMSrcReg, _, IdxVT, (outs _.RC:$dst),
+multiclass avx512_perm_i<bits<8> opc, string OpcodeStr, X86VectorVTInfo _> {
+let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
+ // The index operand in the pattern should really be an integer type. However,
+ // if we do that and it happens to come from a bitcast, then it becomes
+ // difficult to find the bitcast needed to convert the index to the
+ // destination type for the passthru since it will be folded with the bitcast
+ // of the index operand.
+ defm rr: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (X86VPermi2X IdxVT.RC:$src1, _.RC:$src2, _.RC:$src3))>, EVEX_4V,
+ (_.VT (X86VPermi2X _.RC:$src1, _.RC:$src2, _.RC:$src3)), 1>, EVEX_4V,
AVX5128IBase;
- defm rm: AVX512_maskable_3src_cast<opc, MRMSrcMem, _, IdxVT, (outs _.RC:$dst),
+ defm rm: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.MemOp:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (X86VPermi2X IdxVT.RC:$src1, _.RC:$src2,
- (_.VT (bitconvert (_.LdFrag addr:$src3)))))>,
+ (_.VT (X86VPermi2X _.RC:$src1, _.RC:$src2,
+ (_.VT (bitconvert (_.LdFrag addr:$src3))))), 1>,
EVEX_4V, AVX5128IBase;
}
}
multiclass avx512_perm_i_mb<bits<8> opc, string OpcodeStr,
- X86VectorVTInfo _, X86VectorVTInfo IdxVT> {
- let Constraints = "$src1 = $dst" in
- defm rmb: AVX512_maskable_3src_cast<opc, MRMSrcMem, _, IdxVT, (outs _.RC:$dst),
+ X86VectorVTInfo _> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in
+ defm rmb: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.ScalarMemOp:$src3),
OpcodeStr, !strconcat("${src3}", _.BroadcastStr,", $src2"),
!strconcat("$src2, ${src3}", _.BroadcastStr ),
- (_.VT (X86VPermi2X IdxVT.RC:$src1,
- _.RC:$src2,(_.VT (X86VBroadcast (_.ScalarLdFrag addr:$src3)))))>,
- AVX5128IBase, EVEX_4V, EVEX_B;
+ (_.VT (X86VPermi2X _.RC:$src1,
+ _.RC:$src2,(_.VT (X86VBroadcast (_.ScalarLdFrag addr:$src3))))),
+ 1>, AVX5128IBase, EVEX_4V, EVEX_B;
}
multiclass avx512_perm_i_sizes<bits<8> opc, string OpcodeStr,
- AVX512VLVectorVTInfo VTInfo,
- AVX512VLVectorVTInfo ShuffleMask> {
- defm NAME: avx512_perm_i<opc, OpcodeStr, VTInfo.info512,
- ShuffleMask.info512>,
- avx512_perm_i_mb<opc, OpcodeStr, VTInfo.info512,
- ShuffleMask.info512>, EVEX_V512;
+ AVX512VLVectorVTInfo VTInfo> {
+ defm NAME: avx512_perm_i<opc, OpcodeStr, VTInfo.info512>,
+ avx512_perm_i_mb<opc, OpcodeStr, VTInfo.info512>, EVEX_V512;
let Predicates = [HasVLX] in {
- defm NAME#128: avx512_perm_i<opc, OpcodeStr, VTInfo.info128,
- ShuffleMask.info128>,
- avx512_perm_i_mb<opc, OpcodeStr, VTInfo.info128,
- ShuffleMask.info128>, EVEX_V128;
- defm NAME#256: avx512_perm_i<opc, OpcodeStr, VTInfo.info256,
- ShuffleMask.info256>,
- avx512_perm_i_mb<opc, OpcodeStr, VTInfo.info256,
- ShuffleMask.info256>, EVEX_V256;
+ defm NAME#128: avx512_perm_i<opc, OpcodeStr, VTInfo.info128>,
+ avx512_perm_i_mb<opc, OpcodeStr, VTInfo.info128>, EVEX_V128;
+ defm NAME#256: avx512_perm_i<opc, OpcodeStr, VTInfo.info256>,
+ avx512_perm_i_mb<opc, OpcodeStr, VTInfo.info256>, EVEX_V256;
}
}
multiclass avx512_perm_i_sizes_bw<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo VTInfo,
- AVX512VLVectorVTInfo Idx,
Predicate Prd> {
let Predicates = [Prd] in
- defm NAME: avx512_perm_i<opc, OpcodeStr, VTInfo.info512,
- Idx.info512>, EVEX_V512;
+ defm NAME: avx512_perm_i<opc, OpcodeStr, VTInfo.info512>, EVEX_V512;
let Predicates = [Prd, HasVLX] in {
- defm NAME#128: avx512_perm_i<opc, OpcodeStr, VTInfo.info128,
- Idx.info128>, EVEX_V128;
- defm NAME#256: avx512_perm_i<opc, OpcodeStr, VTInfo.info256,
- Idx.info256>, EVEX_V256;
+ defm NAME#128: avx512_perm_i<opc, OpcodeStr, VTInfo.info128>, EVEX_V128;
+ defm NAME#256: avx512_perm_i<opc, OpcodeStr, VTInfo.info256>, EVEX_V256;
}
}
defm VPERMI2D : avx512_perm_i_sizes<0x76, "vpermi2d",
- avx512vl_i32_info, avx512vl_i32_info>, EVEX_CD8<32, CD8VF>;
+ avx512vl_i32_info>, EVEX_CD8<32, CD8VF>;
defm VPERMI2Q : avx512_perm_i_sizes<0x76, "vpermi2q",
- avx512vl_i64_info, avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>;
+ avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>;
defm VPERMI2W : avx512_perm_i_sizes_bw<0x75, "vpermi2w",
- avx512vl_i16_info, avx512vl_i16_info, HasBWI>,
+ avx512vl_i16_info, HasBWI>,
VEX_W, EVEX_CD8<16, CD8VF>;
defm VPERMI2B : avx512_perm_i_sizes_bw<0x75, "vpermi2b",
- avx512vl_i8_info, avx512vl_i8_info, HasVBMI>,
+ avx512vl_i8_info, HasVBMI>,
EVEX_CD8<8, CD8VF>;
defm VPERMI2PS : avx512_perm_i_sizes<0x77, "vpermi2ps",
- avx512vl_f32_info, avx512vl_i32_info>, EVEX_CD8<32, CD8VF>;
+ avx512vl_f32_info>, EVEX_CD8<32, CD8VF>;
defm VPERMI2PD : avx512_perm_i_sizes<0x77, "vpermi2pd",
- avx512vl_f64_info, avx512vl_i64_info>, VEX_W, EVEX_CD8<64, CD8VF>;
+ avx512vl_f64_info>, VEX_W, EVEX_CD8<64, CD8VF>;
// VPERMT2
multiclass avx512_perm_t<bits<8> opc, string OpcodeStr,
X86VectorVTInfo _, X86VectorVTInfo IdxVT> {
-let Constraints = "$src1 = $dst" in {
+let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm rr: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins IdxVT.RC:$src2, _.RC:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (X86VPermt2 _.RC:$src1, IdxVT.RC:$src2, _.RC:$src3))>, EVEX_4V,
- AVX5128IBase;
+ (_.VT (X86VPermt2 _.RC:$src1, IdxVT.RC:$src2, _.RC:$src3)), 1>,
+ EVEX_4V, AVX5128IBase;
defm rm: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins IdxVT.RC:$src2, _.MemOp:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
(_.VT (X86VPermt2 _.RC:$src1, IdxVT.RC:$src2,
- (bitconvert (_.LdFrag addr:$src3))))>,
+ (bitconvert (_.LdFrag addr:$src3)))), 1>,
EVEX_4V, AVX5128IBase;
}
}
multiclass avx512_perm_t_mb<bits<8> opc, string OpcodeStr,
X86VectorVTInfo _, X86VectorVTInfo IdxVT> {
- let Constraints = "$src1 = $dst" in
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in
defm rmb: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins IdxVT.RC:$src2, _.ScalarMemOp:$src3),
OpcodeStr, !strconcat("${src3}", _.BroadcastStr,", $src2"),
!strconcat("$src2, ${src3}", _.BroadcastStr ),
(_.VT (X86VPermt2 _.RC:$src1,
- IdxVT.RC:$src2,(_.VT (X86VBroadcast (_.ScalarLdFrag addr:$src3)))))>,
- AVX5128IBase, EVEX_4V, EVEX_B;
+ IdxVT.RC:$src2,(_.VT (X86VBroadcast (_.ScalarLdFrag addr:$src3))))),
+ 1>, AVX5128IBase, EVEX_4V, EVEX_B;
}
multiclass avx512_perm_t_sizes<bits<8> opc, string OpcodeStr,
@@ -1252,8 +1501,7 @@ defm VPERMT2PD : avx512_perm_t_sizes<0x7F, "vpermt2pd",
// AVX-512 - BLEND using mask
//
multiclass avx512_blendmask<bits<8> opc, string OpcodeStr, X86VectorVTInfo _> {
- let ExeDomain = _.ExeDomain in {
- let hasSideEffects = 0 in
+ let ExeDomain = _.ExeDomain, hasSideEffects = 0 in {
def rr : AVX5128I<opc, MRMSrcReg, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2),
!strconcat(OpcodeStr,
@@ -1263,16 +1511,13 @@ multiclass avx512_blendmask<bits<8> opc, string OpcodeStr, X86VectorVTInfo _> {
(ins _.KRCWM:$mask, _.RC:$src1, _.RC:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, ${dst} {${mask}}|${dst} {${mask}}, $src1, $src2}"),
- [(set _.RC:$dst, (vselect _.KRCWM:$mask,
- (_.VT _.RC:$src2),
- (_.VT _.RC:$src1)))]>, EVEX_4V, EVEX_K;
- let hasSideEffects = 0 in
+ []>, EVEX_4V, EVEX_K;
def rrkz : AVX5128I<opc, MRMSrcReg, (outs _.RC:$dst),
(ins _.KRCWM:$mask, _.RC:$src1, _.RC:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, ${dst} {${mask}} {z}|${dst} {${mask}} {z}, $src1, $src2}"),
[]>, EVEX_4V, EVEX_KZ;
- let mayLoad = 1, hasSideEffects = 0 in
+ let mayLoad = 1 in {
def rm : AVX5128I<opc, MRMSrcMem, (outs _.RC:$dst),
(ins _.RC:$src1, _.MemOp:$src2),
!strconcat(OpcodeStr,
@@ -1282,38 +1527,32 @@ multiclass avx512_blendmask<bits<8> opc, string OpcodeStr, X86VectorVTInfo _> {
(ins _.KRCWM:$mask, _.RC:$src1, _.MemOp:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, ${dst} {${mask}}|${dst} {${mask}}, $src1, $src2}"),
- [(set _.RC:$dst, (vselect _.KRCWM:$mask,
- (_.VT (bitconvert (_.LdFrag addr:$src2))),
- (_.VT _.RC:$src1)))]>,
- EVEX_4V, EVEX_K, EVEX_CD8<_.EltSize, CD8VF>;
- let mayLoad = 1, hasSideEffects = 0 in
+ []>, EVEX_4V, EVEX_K, EVEX_CD8<_.EltSize, CD8VF>;
def rmkz : AVX5128I<opc, MRMSrcMem, (outs _.RC:$dst),
(ins _.KRCWM:$mask, _.RC:$src1, _.MemOp:$src2),
!strconcat(OpcodeStr,
"\t{$src2, $src1, ${dst} {${mask}} {z}|${dst} {${mask}} {z}, $src1, $src2}"),
[]>, EVEX_4V, EVEX_KZ, EVEX_CD8<_.EltSize, CD8VF>;
}
+ }
}
multiclass avx512_blendmask_rmb<bits<8> opc, string OpcodeStr, X86VectorVTInfo _> {
+ let mayLoad = 1, hasSideEffects = 0 in {
def rmbk : AVX5128I<opc, MRMSrcMem, (outs _.RC:$dst),
(ins _.KRCWM:$mask, _.RC:$src1, _.ScalarMemOp:$src2),
!strconcat(OpcodeStr,
"\t{${src2}", _.BroadcastStr, ", $src1, $dst {${mask}}|",
"$dst {${mask}}, $src1, ${src2}", _.BroadcastStr, "}"),
- [(set _.RC:$dst,(vselect _.KRCWM:$mask,
- (X86VBroadcast (_.ScalarLdFrag addr:$src2)),
- (_.VT _.RC:$src1)))]>,
- EVEX_4V, EVEX_K, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>;
+ []>, EVEX_4V, EVEX_K, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>;
- let mayLoad = 1, hasSideEffects = 0 in
def rmb : AVX5128I<opc, MRMSrcMem, (outs _.RC:$dst),
(ins _.RC:$src1, _.ScalarMemOp:$src2),
!strconcat(OpcodeStr,
"\t{${src2}", _.BroadcastStr, ", $src1, $dst|",
"$dst, $src1, ${src2}", _.BroadcastStr, "}"),
[]>, EVEX_4V, EVEX_B, EVEX_CD8<_.EltSize, CD8VF>;
-
+ }
}
multiclass blendmask_dq <bits<8> opc, string OpcodeStr,
@@ -1349,21 +1588,6 @@ defm VPBLENDMB : blendmask_bw <0x66, "vpblendmb", avx512vl_i8_info>;
defm VPBLENDMW : blendmask_bw <0x66, "vpblendmw", avx512vl_i16_info>, VEX_W;
-let Predicates = [HasAVX512, NoVLX] in {
-def : Pat<(v8f32 (vselect (v8i1 VK8WM:$mask), (v8f32 VR256X:$src1),
- (v8f32 VR256X:$src2))),
- (EXTRACT_SUBREG
- (v16f32 (VBLENDMPSZrrk (COPY_TO_REGCLASS VK8WM:$mask, VK16WM),
- (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)),
- (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>;
-
-def : Pat<(v8i32 (vselect (v8i1 VK8WM:$mask), (v8i32 VR256X:$src1),
- (v8i32 VR256X:$src2))),
- (EXTRACT_SUBREG
- (v16i32 (VPBLENDMDZrrk (COPY_TO_REGCLASS VK8WM:$mask, VK16WM),
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)),
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>;
-}
//===----------------------------------------------------------------------===//
// Compare Instructions
//===----------------------------------------------------------------------===//
@@ -1421,6 +1645,7 @@ multiclass avx512_cmp_scalar<X86VectorVTInfo _, SDNode OpNode, SDNode OpNodeRnd>
}// let isAsmParserOnly = 1, hasSideEffects = 0
let isCodeGenOnly = 1 in {
+ let isCommutable = 1 in
def rr : AVX512Ii8<0xC2, MRMSrcReg,
(outs _.KRC:$dst), (ins _.FRC:$src1, _.FRC:$src2, AVXCC:$cc),
!strconcat("vcmp${cc}", _.Suffix,
@@ -1449,7 +1674,8 @@ let Predicates = [HasAVX512] in {
}
multiclass avx512_icmp_packed<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, bit IsCommutable> {
+ let isCommutable = IsCommutable in
def rr : AVX512BI<opc, MRMSrcReg,
(outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
@@ -1480,8 +1706,8 @@ multiclass avx512_icmp_packed<bits<8> opc, string OpcodeStr, SDNode OpNode,
}
multiclass avx512_icmp_packed_rmb<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> :
- avx512_icmp_packed<opc, OpcodeStr, OpNode, _> {
+ X86VectorVTInfo _, bit IsCommutable> :
+ avx512_icmp_packed<opc, OpcodeStr, OpNode, _, IsCommutable> {
def rmb : AVX512BI<opc, MRMSrcMem,
(outs _.KRC:$dst), (ins _.RC:$src1, _.ScalarMemOp:$src2),
!strconcat(OpcodeStr, "\t{${src2}", _.BroadcastStr, ", $src1, $dst",
@@ -1503,48 +1729,49 @@ multiclass avx512_icmp_packed_rmb<bits<8> opc, string OpcodeStr, SDNode OpNode,
}
multiclass avx512_icmp_packed_vl<bits<8> opc, string OpcodeStr, SDNode OpNode,
- AVX512VLVectorVTInfo VTInfo, Predicate prd> {
+ AVX512VLVectorVTInfo VTInfo, Predicate prd,
+ bit IsCommutable = 0> {
let Predicates = [prd] in
- defm Z : avx512_icmp_packed<opc, OpcodeStr, OpNode, VTInfo.info512>,
- EVEX_V512;
+ defm Z : avx512_icmp_packed<opc, OpcodeStr, OpNode, VTInfo.info512,
+ IsCommutable>, EVEX_V512;
let Predicates = [prd, HasVLX] in {
- defm Z256 : avx512_icmp_packed<opc, OpcodeStr, OpNode, VTInfo.info256>,
- EVEX_V256;
- defm Z128 : avx512_icmp_packed<opc, OpcodeStr, OpNode, VTInfo.info128>,
- EVEX_V128;
+ defm Z256 : avx512_icmp_packed<opc, OpcodeStr, OpNode, VTInfo.info256,
+ IsCommutable>, EVEX_V256;
+ defm Z128 : avx512_icmp_packed<opc, OpcodeStr, OpNode, VTInfo.info128,
+ IsCommutable>, EVEX_V128;
}
}
multiclass avx512_icmp_packed_rmb_vl<bits<8> opc, string OpcodeStr,
SDNode OpNode, AVX512VLVectorVTInfo VTInfo,
- Predicate prd> {
+ Predicate prd, bit IsCommutable = 0> {
let Predicates = [prd] in
- defm Z : avx512_icmp_packed_rmb<opc, OpcodeStr, OpNode, VTInfo.info512>,
- EVEX_V512;
+ defm Z : avx512_icmp_packed_rmb<opc, OpcodeStr, OpNode, VTInfo.info512,
+ IsCommutable>, EVEX_V512;
let Predicates = [prd, HasVLX] in {
- defm Z256 : avx512_icmp_packed_rmb<opc, OpcodeStr, OpNode, VTInfo.info256>,
- EVEX_V256;
- defm Z128 : avx512_icmp_packed_rmb<opc, OpcodeStr, OpNode, VTInfo.info128>,
- EVEX_V128;
+ defm Z256 : avx512_icmp_packed_rmb<opc, OpcodeStr, OpNode, VTInfo.info256,
+ IsCommutable>, EVEX_V256;
+ defm Z128 : avx512_icmp_packed_rmb<opc, OpcodeStr, OpNode, VTInfo.info128,
+ IsCommutable>, EVEX_V128;
}
}
defm VPCMPEQB : avx512_icmp_packed_vl<0x74, "vpcmpeqb", X86pcmpeqm,
- avx512vl_i8_info, HasBWI>,
+ avx512vl_i8_info, HasBWI, 1>,
EVEX_CD8<8, CD8VF>;
defm VPCMPEQW : avx512_icmp_packed_vl<0x75, "vpcmpeqw", X86pcmpeqm,
- avx512vl_i16_info, HasBWI>,
+ avx512vl_i16_info, HasBWI, 1>,
EVEX_CD8<16, CD8VF>;
defm VPCMPEQD : avx512_icmp_packed_rmb_vl<0x76, "vpcmpeqd", X86pcmpeqm,
- avx512vl_i32_info, HasAVX512>,
+ avx512vl_i32_info, HasAVX512, 1>,
EVEX_CD8<32, CD8VF>;
defm VPCMPEQQ : avx512_icmp_packed_rmb_vl<0x29, "vpcmpeqq", X86pcmpeqm,
- avx512vl_i64_info, HasAVX512>,
+ avx512vl_i64_info, HasAVX512, 1>,
T8PD, VEX_W, EVEX_CD8<64, CD8VF>;
defm VPCMPGTB : avx512_icmp_packed_vl<0x64, "vpcmpgtb", X86pcmpgtm,
@@ -1563,18 +1790,21 @@ defm VPCMPGTQ : avx512_icmp_packed_rmb_vl<0x37, "vpcmpgtq", X86pcmpgtm,
avx512vl_i64_info, HasAVX512>,
T8PD, VEX_W, EVEX_CD8<64, CD8VF>;
+let Predicates = [HasAVX512, NoVLX] in {
def : Pat<(v8i1 (X86pcmpgtm (v8i32 VR256X:$src1), (v8i32 VR256X:$src2))),
(COPY_TO_REGCLASS (VPCMPGTDZrr
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)),
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm))), VK8)>;
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src2, sub_ymm))), VK8)>;
def : Pat<(v8i1 (X86pcmpeqm (v8i32 VR256X:$src1), (v8i32 VR256X:$src2))),
(COPY_TO_REGCLASS (VPCMPEQDZrr
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)),
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm))), VK8)>;
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src2, sub_ymm))), VK8)>;
+}
multiclass avx512_icmp_cc<bits<8> opc, string Suffix, SDNode OpNode,
X86VectorVTInfo _> {
+ let isCommutable = 1 in
def rri : AVX512AIi8<opc, MRMSrcReg,
(outs _.KRC:$dst), (ins _.RC:$src1, _.RC:$src2, AVX512ICC:$cc),
!strconcat("vpcmp${cc}", Suffix,
@@ -1740,7 +1970,7 @@ multiclass avx512_vcmp_common<X86VectorVTInfo _> {
"$src2, $src1", "$src1, $src2",
(X86cmpm (_.VT _.RC:$src1),
(_.VT _.RC:$src2),
- imm:$cc)>;
+ imm:$cc), 1>;
defm rmi : AVX512_maskable_cmp<0xC2, MRMSrcMem, _,
(outs _.KRC:$dst),(ins _.RC:$src1, _.MemOp:$src2, AVXCC:$cc),
@@ -1824,18 +2054,18 @@ defm VCMPPS : avx512_vcmp<avx512vl_f32_info>,
def : Pat<(v8i1 (X86cmpm (v8f32 VR256X:$src1), (v8f32 VR256X:$src2), imm:$cc)),
(COPY_TO_REGCLASS (VCMPPSZrri
- (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)),
- (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)),
+ (v16f32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)),
+ (v16f32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src2, sub_ymm)),
imm:$cc), VK8)>;
def : Pat<(v8i1 (X86cmpm (v8i32 VR256X:$src1), (v8i32 VR256X:$src2), imm:$cc)),
(COPY_TO_REGCLASS (VPCMPDZrri
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)),
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src2, sub_ymm)),
imm:$cc), VK8)>;
def : Pat<(v8i1 (X86cmpmu (v8i32 VR256X:$src1), (v8i32 VR256X:$src2), imm:$cc)),
(COPY_TO_REGCLASS (VPCMPUDZrri
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)),
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src2, sub_ymm)),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src2, sub_ymm)),
imm:$cc), VK8)>;
// ----------------------------------------------------------------
@@ -2011,34 +2241,38 @@ let Predicates = [HasBWI] in {
}
// GR from/to mask register
-let Predicates = [HasDQI] in {
- def : Pat<(v8i1 (bitconvert (i8 GR8:$src))),
- (KMOVBkr (SUBREG_TO_REG (i32 0), GR8:$src, sub_8bit))>;
- def : Pat<(i8 (bitconvert (v8i1 VK8:$src))),
- (EXTRACT_SUBREG (KMOVBrk VK8:$src), sub_8bit)>;
- def : Pat<(i32 (zext (i8 (bitconvert (v8i1 VK8:$src))))),
- (KMOVBrk VK8:$src)>;
- def : Pat<(i32 (anyext (i8 (bitconvert (v8i1 VK8:$src))))),
- (KMOVBrk VK8:$src)>;
-}
-let Predicates = [HasAVX512] in {
- def : Pat<(v16i1 (bitconvert (i16 GR16:$src))),
- (KMOVWkr (SUBREG_TO_REG (i32 0), GR16:$src, sub_16bit))>;
- def : Pat<(i16 (bitconvert (v16i1 VK16:$src))),
- (EXTRACT_SUBREG (KMOVWrk VK16:$src), sub_16bit)>;
- def : Pat<(i32 (zext (i16 (bitconvert (v16i1 VK16:$src))))),
- (KMOVWrk VK16:$src)>;
- def : Pat<(i32 (anyext (i16 (bitconvert (v16i1 VK16:$src))))),
- (KMOVWrk VK16:$src)>;
-}
-let Predicates = [HasBWI] in {
- def : Pat<(v32i1 (bitconvert (i32 GR32:$src))), (KMOVDkr GR32:$src)>;
- def : Pat<(i32 (bitconvert (v32i1 VK32:$src))), (KMOVDrk VK32:$src)>;
-}
-let Predicates = [HasBWI] in {
- def : Pat<(v64i1 (bitconvert (i64 GR64:$src))), (KMOVQkr GR64:$src)>;
- def : Pat<(i64 (bitconvert (v64i1 VK64:$src))), (KMOVQrk VK64:$src)>;
-}
+def : Pat<(v16i1 (bitconvert (i16 GR16:$src))),
+ (COPY_TO_REGCLASS GR16:$src, VK16)>;
+def : Pat<(i16 (bitconvert (v16i1 VK16:$src))),
+ (COPY_TO_REGCLASS VK16:$src, GR16)>;
+
+def : Pat<(v8i1 (bitconvert (i8 GR8:$src))),
+ (COPY_TO_REGCLASS GR8:$src, VK8)>;
+def : Pat<(i8 (bitconvert (v8i1 VK8:$src))),
+ (COPY_TO_REGCLASS VK8:$src, GR8)>;
+
+def : Pat<(i32 (zext (i16 (bitconvert (v16i1 VK16:$src))))),
+ (KMOVWrk VK16:$src)>;
+def : Pat<(i32 (anyext (i16 (bitconvert (v16i1 VK16:$src))))),
+ (i32 (INSERT_SUBREG (IMPLICIT_DEF),
+ (i16 (COPY_TO_REGCLASS VK16:$src, GR16)), sub_16bit))>;
+
+def : Pat<(i32 (zext (i8 (bitconvert (v8i1 VK8:$src))))),
+ (MOVZX32rr8 (COPY_TO_REGCLASS VK8:$src, GR8))>, Requires<[NoDQI]>;
+def : Pat<(i32 (zext (i8 (bitconvert (v8i1 VK8:$src))))),
+ (KMOVBrk VK8:$src)>, Requires<[HasDQI]>;
+def : Pat<(i32 (anyext (i8 (bitconvert (v8i1 VK8:$src))))),
+ (i32 (INSERT_SUBREG (IMPLICIT_DEF),
+ (i8 (COPY_TO_REGCLASS VK8:$src, GR8)), sub_8bit))>;
+
+def : Pat<(v32i1 (bitconvert (i32 GR32:$src))),
+ (COPY_TO_REGCLASS GR32:$src, VK32)>;
+def : Pat<(i32 (bitconvert (v32i1 VK32:$src))),
+ (COPY_TO_REGCLASS VK32:$src, GR32)>;
+def : Pat<(v64i1 (bitconvert (i64 GR64:$src))),
+ (COPY_TO_REGCLASS GR64:$src, VK64)>;
+def : Pat<(i64 (bitconvert (v64i1 VK64:$src))),
+ (COPY_TO_REGCLASS VK64:$src, GR64)>;
// Load/store kreg
let Predicates = [HasDQI] in {
@@ -2104,65 +2338,58 @@ let Predicates = [HasBWI] in {
(KMOVQkm addr:$src)>;
}
-def assertzext_i1 : PatFrag<(ops node:$src), (assertzext node:$src), [{
- return cast<VTSDNode>(N->getOperand(1))->getVT() == MVT::i1;
-}]>;
-
let Predicates = [HasAVX512] in {
def : Pat<(i1 (trunc (i64 GR64:$src))),
- (COPY_TO_REGCLASS (i16 (EXTRACT_SUBREG (AND64ri8 $src, (i64 1)),
- sub_16bit)), VK1)>;
-
- def : Pat<(i1 (trunc (i64 (assertzext_i1 GR64:$src)))),
- (COPY_TO_REGCLASS (i16 (EXTRACT_SUBREG $src, sub_16bit)), VK1)>;
+ (COPY_TO_REGCLASS (KMOVWkr (AND32ri8 (EXTRACT_SUBREG $src, sub_32bit),
+ (i32 1))), VK1)>;
def : Pat<(i1 (trunc (i32 GR32:$src))),
- (COPY_TO_REGCLASS (i16 (EXTRACT_SUBREG (AND32ri8 $src, (i32 1)),
- sub_16bit)), VK1)>;
+ (COPY_TO_REGCLASS (KMOVWkr (AND32ri8 $src, (i32 1))), VK1)>;
def : Pat<(i1 (trunc (i32 (assertzext_i1 GR32:$src)))),
- (COPY_TO_REGCLASS (i16 (EXTRACT_SUBREG $src, sub_16bit)), VK1)>;
+ (COPY_TO_REGCLASS GR32:$src, VK1)>;
def : Pat<(i1 (trunc (i8 GR8:$src))),
- (COPY_TO_REGCLASS (i16 (SUBREG_TO_REG (i64 0), (AND8ri $src, (i8 1)),
- sub_8bit)), VK1)>;
-
- def : Pat<(i1 (trunc (i8 (assertzext_i1 GR8:$src)))),
- (COPY_TO_REGCLASS (i16 (SUBREG_TO_REG (i64 0), $src, sub_8bit)), VK1)>;
+ (COPY_TO_REGCLASS
+ (KMOVWkr (AND32ri8 (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ GR8:$src, sub_8bit), (i32 1))),
+ VK1)>;
def : Pat<(i1 (trunc (i16 GR16:$src))),
- (COPY_TO_REGCLASS (AND16ri GR16:$src, (i16 1)), VK1)>;
-
- def : Pat<(i1 (trunc (i16 (assertzext_i1 GR16:$src)))),
- (COPY_TO_REGCLASS $src, VK1)>;
+ (COPY_TO_REGCLASS
+ (KMOVWkr (AND32ri8 (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ GR16:$src, sub_16bit), (i32 1))),
+ VK1)>;
def : Pat<(i32 (zext VK1:$src)),
- (i32 (SUBREG_TO_REG (i64 0), (i16 (COPY_TO_REGCLASS $src, GR16)),
- sub_16bit))>;
+ (AND32ri8 (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), (i32 1))>;
def : Pat<(i32 (anyext VK1:$src)),
- (i32 (SUBREG_TO_REG (i64 0), (i16 (COPY_TO_REGCLASS $src, GR16)),
- sub_16bit))>;
+ (COPY_TO_REGCLASS VK1:$src, GR32)>;
def : Pat<(i8 (zext VK1:$src)),
- (i8 (EXTRACT_SUBREG (i16 (COPY_TO_REGCLASS VK1:$src, GR16)), sub_8bit))>;
+ (EXTRACT_SUBREG
+ (AND32ri8 (KMOVWrk
+ (COPY_TO_REGCLASS VK1:$src, VK16)), (i32 1)), sub_8bit)>;
def : Pat<(i8 (anyext VK1:$src)),
- (i8 (EXTRACT_SUBREG (i16 (COPY_TO_REGCLASS $src, GR16)), sub_8bit))>;
+ (EXTRACT_SUBREG (i32 (COPY_TO_REGCLASS VK1:$src, GR32)), sub_8bit)>;
def : Pat<(i64 (zext VK1:$src)),
- (i64 (SUBREG_TO_REG (i64 0), (i16 (COPY_TO_REGCLASS $src, GR16)),
- sub_16bit))>;
+ (AND64ri8 (SUBREG_TO_REG (i64 0),
+ (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), sub_32bit), (i64 1))>;
def : Pat<(i64 (anyext VK1:$src)),
- (i64 (SUBREG_TO_REG (i64 0), (i16 (COPY_TO_REGCLASS $src, GR16)),
- sub_16bit))>;
+ (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
+ (i32 (COPY_TO_REGCLASS VK1:$src, GR32)), sub_32bit)>;
def : Pat<(i16 (zext VK1:$src)),
- (COPY_TO_REGCLASS $src, GR16)>;
+ (EXTRACT_SUBREG
+ (AND32ri8 (KMOVWrk (COPY_TO_REGCLASS VK1:$src, VK16)), (i32 1)),
+ sub_16bit)>;
def : Pat<(i16 (anyext VK1:$src)),
- (i16 (COPY_TO_REGCLASS $src, GR16))>;
+ (EXTRACT_SUBREG (i32 (COPY_TO_REGCLASS VK1:$src, GR32)), sub_16bit)>;
}
def : Pat<(v16i1 (scalar_to_vector VK1:$src)),
(COPY_TO_REGCLASS VK1:$src, VK16)>;
@@ -2181,34 +2408,12 @@ def : Pat<(store (i1 -1), addr:$dst), (MOV8mi addr:$dst, (i8 1))>;
def : Pat<(store (i1 1), addr:$dst), (MOV8mi addr:$dst, (i8 1))>;
def : Pat<(store (i1 0), addr:$dst), (MOV8mi addr:$dst, (i8 0))>;
-// With AVX-512 only, 8-bit mask is promoted to 16-bit mask.
-let Predicates = [HasAVX512, NoDQI] in {
- // GR from/to 8-bit mask without native support
- def : Pat<(v8i1 (bitconvert (i8 GR8:$src))),
- (COPY_TO_REGCLASS
- (KMOVWkr (SUBREG_TO_REG (i32 0), GR8:$src, sub_8bit)), VK8)>;
- def : Pat<(i8 (bitconvert (v8i1 VK8:$src))),
- (EXTRACT_SUBREG
- (KMOVWrk (COPY_TO_REGCLASS VK8:$src, VK16)),
- sub_8bit)>;
- def : Pat<(i32 (zext (i8 (bitconvert (v8i1 VK8:$src))))),
- (KMOVWrk (COPY_TO_REGCLASS VK8:$src, VK16))>;
- def : Pat<(i32 (anyext (i8 (bitconvert (v8i1 VK8:$src))))),
- (KMOVWrk (COPY_TO_REGCLASS VK8:$src, VK16))>;
-}
-
-let Predicates = [HasAVX512] in {
- def : Pat<(i1 (X86Vextract VK16:$src, (iPTR 0))),
- (COPY_TO_REGCLASS VK16:$src, VK1)>;
- def : Pat<(i1 (X86Vextract VK8:$src, (iPTR 0))),
- (COPY_TO_REGCLASS VK8:$src, VK1)>;
-}
-let Predicates = [HasBWI] in {
- def : Pat<(i1 (X86Vextract VK32:$src, (iPTR 0))),
- (COPY_TO_REGCLASS VK32:$src, VK1)>;
- def : Pat<(i1 (X86Vextract VK64:$src, (iPTR 0))),
- (COPY_TO_REGCLASS VK64:$src, VK1)>;
-}
+def : Pat<(i1 (X86Vextract VK64:$src, (iPTR 0))), (COPY_TO_REGCLASS VK64:$src, VK1)>;
+def : Pat<(i1 (X86Vextract VK32:$src, (iPTR 0))), (COPY_TO_REGCLASS VK32:$src, VK1)>;
+def : Pat<(i1 (X86Vextract VK16:$src, (iPTR 0))), (COPY_TO_REGCLASS VK16:$src, VK1)>;
+def : Pat<(i1 (X86Vextract VK8:$src, (iPTR 0))), (COPY_TO_REGCLASS VK8:$src, VK1)>;
+def : Pat<(i1 (X86Vextract VK4:$src, (iPTR 0))), (COPY_TO_REGCLASS VK4:$src, VK1)>;
+def : Pat<(i1 (X86Vextract VK2:$src, (iPTR 0))), (COPY_TO_REGCLASS VK2:$src, VK1)>;
// Mask unary operation
// - KNOT
@@ -2233,7 +2438,7 @@ multiclass avx512_mask_unop_all<bits<8> opc, string OpcodeStr,
HasBWI>, VEX, PS, VEX_W;
}
-defm KNOT : avx512_mask_unop_all<0x44, "knot", not>;
+defm KNOT : avx512_mask_unop_all<0x44, "knot", vnot>;
multiclass avx512_mask_unop_int<string IntName, string InstName> {
let Predicates = [HasAVX512] in
@@ -2244,27 +2449,15 @@ multiclass avx512_mask_unop_int<string IntName, string InstName> {
}
defm : avx512_mask_unop_int<"knot", "KNOT">;
-let Predicates = [HasDQI] in
-def : Pat<(xor VK8:$src1, (v8i1 immAllOnesV)), (KNOTBrr VK8:$src1)>;
-let Predicates = [HasAVX512] in
-def : Pat<(xor VK16:$src1, (v16i1 immAllOnesV)), (KNOTWrr VK16:$src1)>;
-let Predicates = [HasBWI] in
-def : Pat<(xor VK32:$src1, (v32i1 immAllOnesV)), (KNOTDrr VK32:$src1)>;
-let Predicates = [HasBWI] in
-def : Pat<(xor VK64:$src1, (v64i1 immAllOnesV)), (KNOTQrr VK64:$src1)>;
-
// KNL does not support KMOVB, 8-bit mask is promoted to 16-bit
-let Predicates = [HasAVX512, NoDQI] in {
-def : Pat<(xor VK8:$src1, (v8i1 immAllOnesV)),
- (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK8:$src1, VK16)), VK8)>;
-def : Pat<(not VK8:$src),
- (COPY_TO_REGCLASS
- (KNOTWrr (COPY_TO_REGCLASS VK8:$src, VK16)), VK8)>;
-}
-def : Pat<(xor VK4:$src1, (v4i1 immAllOnesV)),
- (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK4:$src1, VK16)), VK4)>;
-def : Pat<(xor VK2:$src1, (v2i1 immAllOnesV)),
- (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK2:$src1, VK16)), VK2)>;
+let Predicates = [HasAVX512, NoDQI] in
+def : Pat<(vnot VK8:$src),
+ (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK8:$src, VK16)), VK8)>;
+
+def : Pat<(vnot VK4:$src),
+ (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK4:$src, VK16)), VK4)>;
+def : Pat<(vnot VK2:$src),
+ (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK2:$src, VK16)), VK2)>;
// Mask binary operation
// - KAND, KANDN, KOR, KXNOR, KXOR
@@ -2293,13 +2486,16 @@ multiclass avx512_mask_binop_all<bits<8> opc, string OpcodeStr,
def andn : PatFrag<(ops node:$i0, node:$i1), (and (not node:$i0), node:$i1)>;
def xnor : PatFrag<(ops node:$i0, node:$i1), (not (xor node:$i0, node:$i1))>;
+// These nodes use 'vnot' instead of 'not' to support vectors.
+def vandn : PatFrag<(ops node:$i0, node:$i1), (and (vnot node:$i0), node:$i1)>;
+def vxnor : PatFrag<(ops node:$i0, node:$i1), (vnot (xor node:$i0, node:$i1))>;
-defm KAND : avx512_mask_binop_all<0x41, "kand", and, 1>;
-defm KOR : avx512_mask_binop_all<0x45, "kor", or, 1>;
-defm KXNOR : avx512_mask_binop_all<0x46, "kxnor", xnor, 1>;
-defm KXOR : avx512_mask_binop_all<0x47, "kxor", xor, 1>;
-defm KANDN : avx512_mask_binop_all<0x42, "kandn", andn, 0>;
-defm KADD : avx512_mask_binop_all<0x4A, "kadd", add, 1, HasDQI>;
+defm KAND : avx512_mask_binop_all<0x41, "kand", and, 1>;
+defm KOR : avx512_mask_binop_all<0x45, "kor", or, 1>;
+defm KXNOR : avx512_mask_binop_all<0x46, "kxnor", vxnor, 1>;
+defm KXOR : avx512_mask_binop_all<0x47, "kxor", xor, 1>;
+defm KANDN : avx512_mask_binop_all<0x42, "kandn", vandn, 0>;
+defm KADD : avx512_mask_binop_all<0x4A, "kadd", add, 1, HasDQI>;
multiclass avx512_mask_binop_int<string IntName, string InstName> {
let Predicates = [HasAVX512] in
@@ -2316,11 +2512,12 @@ defm : avx512_mask_binop_int<"kor", "KOR">;
defm : avx512_mask_binop_int<"kxnor", "KXNOR">;
defm : avx512_mask_binop_int<"kxor", "KXOR">;
-multiclass avx512_binop_pat<SDPatternOperator OpNode, Instruction Inst> {
+multiclass avx512_binop_pat<SDPatternOperator VOpNode, SDPatternOperator OpNode,
+ Instruction Inst> {
// With AVX512F, 8-bit mask is promoted to 16-bit mask,
// for the DQI set, this type is legal and KxxxB instruction is used
let Predicates = [NoDQI] in
- def : Pat<(OpNode VK8:$src1, VK8:$src2),
+ def : Pat<(VOpNode VK8:$src1, VK8:$src2),
(COPY_TO_REGCLASS
(Inst (COPY_TO_REGCLASS VK8:$src1, VK16),
(COPY_TO_REGCLASS VK8:$src2, VK16)), VK8)>;
@@ -2330,47 +2527,21 @@ multiclass avx512_binop_pat<SDPatternOperator OpNode, Instruction Inst> {
(COPY_TO_REGCLASS (Inst
(COPY_TO_REGCLASS VK1:$src1, VK16),
(COPY_TO_REGCLASS VK1:$src2, VK16)), VK1)>;
- def : Pat<(OpNode VK2:$src1, VK2:$src2),
+ def : Pat<(VOpNode VK2:$src1, VK2:$src2),
(COPY_TO_REGCLASS (Inst
(COPY_TO_REGCLASS VK2:$src1, VK16),
(COPY_TO_REGCLASS VK2:$src2, VK16)), VK1)>;
- def : Pat<(OpNode VK4:$src1, VK4:$src2),
+ def : Pat<(VOpNode VK4:$src1, VK4:$src2),
(COPY_TO_REGCLASS (Inst
(COPY_TO_REGCLASS VK4:$src1, VK16),
(COPY_TO_REGCLASS VK4:$src2, VK16)), VK1)>;
}
-defm : avx512_binop_pat<and, KANDWrr>;
-defm : avx512_binop_pat<andn, KANDNWrr>;
-defm : avx512_binop_pat<or, KORWrr>;
-defm : avx512_binop_pat<xnor, KXNORWrr>;
-defm : avx512_binop_pat<xor, KXORWrr>;
-
-def : Pat<(xor (xor VK16:$src1, VK16:$src2), (v16i1 immAllOnesV)),
- (KXNORWrr VK16:$src1, VK16:$src2)>;
-def : Pat<(xor (xor VK8:$src1, VK8:$src2), (v8i1 immAllOnesV)),
- (KXNORBrr VK8:$src1, VK8:$src2)>, Requires<[HasDQI]>;
-def : Pat<(xor (xor VK32:$src1, VK32:$src2), (v32i1 immAllOnesV)),
- (KXNORDrr VK32:$src1, VK32:$src2)>, Requires<[HasBWI]>;
-def : Pat<(xor (xor VK64:$src1, VK64:$src2), (v64i1 immAllOnesV)),
- (KXNORQrr VK64:$src1, VK64:$src2)>, Requires<[HasBWI]>;
-
-let Predicates = [NoDQI] in
-def : Pat<(xor (xor VK8:$src1, VK8:$src2), (v8i1 immAllOnesV)),
- (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK8:$src1, VK16),
- (COPY_TO_REGCLASS VK8:$src2, VK16)), VK8)>;
-
-def : Pat<(xor (xor VK4:$src1, VK4:$src2), (v4i1 immAllOnesV)),
- (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK4:$src1, VK16),
- (COPY_TO_REGCLASS VK4:$src2, VK16)), VK4)>;
-
-def : Pat<(xor (xor VK2:$src1, VK2:$src2), (v2i1 immAllOnesV)),
- (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK2:$src1, VK16),
- (COPY_TO_REGCLASS VK2:$src2, VK16)), VK2)>;
-
-def : Pat<(xor (xor VK1:$src1, VK1:$src2), (i1 1)),
- (COPY_TO_REGCLASS (KXNORWrr (COPY_TO_REGCLASS VK1:$src1, VK16),
- (COPY_TO_REGCLASS VK1:$src2, VK16)), VK1)>;
+defm : avx512_binop_pat<and, and, KANDWrr>;
+defm : avx512_binop_pat<vandn, andn, KANDNWrr>;
+defm : avx512_binop_pat<or, or, KORWrr>;
+defm : avx512_binop_pat<vxnor, xnor, KXNORWrr>;
+defm : avx512_binop_pat<xor, xor, KXORWrr>;
// Mask unpacking
multiclass avx512_mask_unpck<string Suffix,RegisterClass KRC, ValueType VT,
@@ -2466,6 +2637,8 @@ defm KSET1 : avx512_mask_setop_w<immAllOnesV>;
// With AVX-512 only, 8-bit mask is promoted to 16-bit mask.
let Predicates = [HasAVX512] in {
def : Pat<(v8i1 immAllZerosV), (COPY_TO_REGCLASS (KSET0W), VK8)>;
+ def : Pat<(v4i1 immAllZerosV), (COPY_TO_REGCLASS (KSET0W), VK4)>;
+ def : Pat<(v2i1 immAllZerosV), (COPY_TO_REGCLASS (KSET0W), VK2)>;
def : Pat<(v8i1 immAllOnesV), (COPY_TO_REGCLASS (KSET1W), VK8)>;
def : Pat<(v4i1 immAllOnesV), (COPY_TO_REGCLASS (KSET1W), VK4)>;
def : Pat<(v2i1 immAllOnesV), (COPY_TO_REGCLASS (KSET1W), VK2)>;
@@ -2519,15 +2692,24 @@ def : Pat<(v16i1 (extract_subvector (v32i1 VK32:$src), (iPTR 16))),
def : Pat<(v32i1 (extract_subvector (v64i1 VK64:$src), (iPTR 32))),
(v32i1 (COPY_TO_REGCLASS (KSHIFTRQri VK64:$src, (i8 32)), VK32))>;
-def : Pat<(v8i1 (X86vshli VK8:$src, (i8 imm:$imm))),
- (v8i1 (COPY_TO_REGCLASS
- (KSHIFTLWri (COPY_TO_REGCLASS VK8:$src, VK16),
- (I8Imm $imm)), VK8))>, Requires<[HasAVX512, NoDQI]>;
-def : Pat<(v4i1 (X86vshli VK4:$src, (i8 imm:$imm))),
- (v4i1 (COPY_TO_REGCLASS
- (KSHIFTLWri (COPY_TO_REGCLASS VK4:$src, VK16),
- (I8Imm $imm)), VK4))>, Requires<[HasAVX512]>;
+// Patterns for kmask shift
+multiclass mask_shift_lowering<RegisterClass RC, ValueType VT> {
+ def : Pat<(VT (X86vshli RC:$src, (i8 imm:$imm))),
+ (VT (COPY_TO_REGCLASS
+ (KSHIFTLWri (COPY_TO_REGCLASS RC:$src, VK16),
+ (I8Imm $imm)),
+ RC))>;
+ def : Pat<(VT (X86vsrli RC:$src, (i8 imm:$imm))),
+ (VT (COPY_TO_REGCLASS
+ (KSHIFTRWri (COPY_TO_REGCLASS RC:$src, VK16),
+ (I8Imm $imm)),
+ RC))>;
+}
+
+defm : mask_shift_lowering<VK8, v8i1>, Requires<[HasAVX512, NoDQI]>;
+defm : mask_shift_lowering<VK4, v4i1>, Requires<[HasAVX512]>;
+defm : mask_shift_lowering<VK2, v2i1>, Requires<[HasAVX512]>;
//===----------------------------------------------------------------------===//
// AVX-512 - Aligned and unaligned load and store
//
@@ -2535,7 +2717,6 @@ def : Pat<(v4i1 (X86vshli VK4:$src, (i8 imm:$imm))),
multiclass avx512_load<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
PatFrag ld_frag, PatFrag mload,
- bit IsReMaterializable = 1,
SDPatternOperator SelectOprr = vselect> {
let hasSideEffects = 0 in {
def rr : AVX512PI<opc, MRMSrcReg, (outs _.RC:$dst), (ins _.RC:$src),
@@ -2545,12 +2726,12 @@ multiclass avx512_load<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
(ins _.KRCWM:$mask, _.RC:$src),
!strconcat(OpcodeStr, "\t{$src, ${dst} {${mask}} {z}|",
"${dst} {${mask}} {z}, $src}"),
- [(set _.RC:$dst, (_.VT (vselect _.KRCWM:$mask,
+ [(set _.RC:$dst, (_.VT (SelectOprr _.KRCWM:$mask,
(_.VT _.RC:$src),
_.ImmAllZerosV)))], _.ExeDomain>,
EVEX, EVEX_KZ;
- let canFoldAsLoad = 1, isReMaterializable = IsReMaterializable,
+ let canFoldAsLoad = 1, isReMaterializable = 1,
SchedRW = [WriteLoad] in
def rm : AVX512PI<opc, MRMSrcMem, (outs _.RC:$dst), (ins _.MemOp:$src),
!strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
@@ -2598,37 +2779,32 @@ multiclass avx512_load<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
multiclass avx512_alignedload_vl<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo _,
- Predicate prd,
- bit IsReMaterializable = 1> {
+ Predicate prd> {
let Predicates = [prd] in
defm Z : avx512_load<opc, OpcodeStr, _.info512, _.info512.AlignedLdFrag,
- masked_load_aligned512, IsReMaterializable>, EVEX_V512;
+ masked_load_aligned512>, EVEX_V512;
let Predicates = [prd, HasVLX] in {
defm Z256 : avx512_load<opc, OpcodeStr, _.info256, _.info256.AlignedLdFrag,
- masked_load_aligned256, IsReMaterializable>, EVEX_V256;
+ masked_load_aligned256>, EVEX_V256;
defm Z128 : avx512_load<opc, OpcodeStr, _.info128, _.info128.AlignedLdFrag,
- masked_load_aligned128, IsReMaterializable>, EVEX_V128;
+ masked_load_aligned128>, EVEX_V128;
}
}
multiclass avx512_load_vl<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo _,
Predicate prd,
- bit IsReMaterializable = 1,
SDPatternOperator SelectOprr = vselect> {
let Predicates = [prd] in
defm Z : avx512_load<opc, OpcodeStr, _.info512, _.info512.LdFrag,
- masked_load_unaligned, IsReMaterializable,
- SelectOprr>, EVEX_V512;
+ masked_load_unaligned, SelectOprr>, EVEX_V512;
let Predicates = [prd, HasVLX] in {
defm Z256 : avx512_load<opc, OpcodeStr, _.info256, _.info256.LdFrag,
- masked_load_unaligned, IsReMaterializable,
- SelectOprr>, EVEX_V256;
+ masked_load_unaligned, SelectOprr>, EVEX_V256;
defm Z128 : avx512_load<opc, OpcodeStr, _.info128, _.info128.LdFrag,
- masked_load_unaligned, IsReMaterializable,
- SelectOprr>, EVEX_V128;
+ masked_load_unaligned, SelectOprr>, EVEX_V128;
}
}
@@ -2704,11 +2880,11 @@ defm VMOVAPD : avx512_alignedload_vl<0x28, "vmovapd", avx512vl_f64_info,
HasAVX512>, PD, VEX_W, EVEX_CD8<64, CD8VF>;
defm VMOVUPS : avx512_load_vl<0x10, "vmovups", avx512vl_f32_info, HasAVX512,
- 1, null_frag>,
+ null_frag>,
avx512_store_vl<0x11, "vmovups", avx512vl_f32_info, HasAVX512>,
PS, EVEX_CD8<32, CD8VF>;
-defm VMOVUPD : avx512_load_vl<0x10, "vmovupd", avx512vl_f64_info, HasAVX512, 0,
+defm VMOVUPD : avx512_load_vl<0x10, "vmovupd", avx512vl_f64_info, HasAVX512,
null_frag>,
avx512_store_vl<0x11, "vmovupd", avx512vl_f64_info, HasAVX512>,
PD, VEX_W, EVEX_CD8<64, CD8VF>;
@@ -2732,15 +2908,41 @@ defm VMOVDQU16 : avx512_load_vl<0x6F, "vmovdqu16", avx512vl_i16_info, HasBWI>,
HasBWI>, XD, VEX_W, EVEX_CD8<16, CD8VF>;
defm VMOVDQU32 : avx512_load_vl<0x6F, "vmovdqu32", avx512vl_i32_info, HasAVX512,
- 1, null_frag>,
+ null_frag>,
avx512_store_vl<0x7F, "vmovdqu32", avx512vl_i32_info,
HasAVX512>, XS, EVEX_CD8<32, CD8VF>;
defm VMOVDQU64 : avx512_load_vl<0x6F, "vmovdqu64", avx512vl_i64_info, HasAVX512,
- 1, null_frag>,
+ null_frag>,
avx512_store_vl<0x7F, "vmovdqu64", avx512vl_i64_info,
HasAVX512>, XS, VEX_W, EVEX_CD8<64, CD8VF>;
+// Special instructions to help with spilling when we don't have VLX. We need
+// to load or store from a ZMM register instead. These are converted in
+// expandPostRAPseudos.
+let isReMaterializable = 1, canFoldAsLoad = 1,
+ isPseudo = 1, SchedRW = [WriteLoad], mayLoad = 1, hasSideEffects = 0 in {
+def VMOVAPSZ128rm_NOVLX : I<0, Pseudo, (outs VR128X:$dst), (ins f128mem:$src),
+ "", []>;
+def VMOVAPSZ256rm_NOVLX : I<0, Pseudo, (outs VR256X:$dst), (ins f256mem:$src),
+ "", []>;
+def VMOVUPSZ128rm_NOVLX : I<0, Pseudo, (outs VR128X:$dst), (ins f128mem:$src),
+ "", []>;
+def VMOVUPSZ256rm_NOVLX : I<0, Pseudo, (outs VR256X:$dst), (ins f256mem:$src),
+ "", []>;
+}
+
+let isPseudo = 1, mayStore = 1, hasSideEffects = 0 in {
+def VMOVAPSZ128mr_NOVLX : I<0, Pseudo, (outs), (ins f128mem:$dst, VR128X:$src),
+ "", []>;
+def VMOVAPSZ256mr_NOVLX : I<0, Pseudo, (outs), (ins f256mem:$dst, VR256X:$src),
+ "", []>;
+def VMOVUPSZ128mr_NOVLX : I<0, Pseudo, (outs), (ins f128mem:$dst, VR128X:$src),
+ "", []>;
+def VMOVUPSZ256mr_NOVLX : I<0, Pseudo, (outs), (ins f256mem:$dst, VR256X:$src),
+ "", []>;
+}
+
def : Pat<(v8i64 (vselect VK8WM:$mask, (bc_v8i64 (v16i32 immAllZerosV)),
(v8i64 VR512:$src))),
(VMOVDQA64Zrrkz (COPY_TO_REGCLASS (KNOTWrr (COPY_TO_REGCLASS VK8:$mask, VK16)),
@@ -2761,6 +2963,52 @@ def : Pat<(v16i32 (vselect (xor VK16:$mask, (v16i1 immAllOnesV)),
(v16i32 VR512:$src))),
(VMOVDQA32Zrrkz VK16WM:$mask, VR512:$src)>;
+// Patterns for handling v8i1 selects of 256-bit vectors when VLX isn't
+// available. Use a 512-bit operation and extract.
+let Predicates = [HasAVX512, NoVLX] in {
+def : Pat<(v8f32 (vselect (v8i1 VK8WM:$mask), (v8f32 VR256X:$src1),
+ (v8f32 VR256X:$src0))),
+ (EXTRACT_SUBREG
+ (v16f32
+ (VMOVAPSZrrk
+ (v16f32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src0, sub_ymm)),
+ (COPY_TO_REGCLASS VK8WM:$mask, VK16WM),
+ (v16f32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)))),
+ sub_ymm)>;
+
+def : Pat<(v8i32 (vselect (v8i1 VK8WM:$mask), (v8i32 VR256X:$src1),
+ (v8i32 VR256X:$src0))),
+ (EXTRACT_SUBREG
+ (v16i32
+ (VMOVDQA32Zrrk
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src0, sub_ymm)),
+ (COPY_TO_REGCLASS VK8WM:$mask, VK16WM),
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF), VR256X:$src1, sub_ymm)))),
+ sub_ymm)>;
+}
+
+let Predicates = [HasVLX, NoBWI] in {
+ // 128-bit load/store without BWI.
+ def : Pat<(alignedstore (v8i16 VR128X:$src), addr:$dst),
+ (VMOVDQA32Z128mr addr:$dst, VR128X:$src)>;
+ def : Pat<(alignedstore (v16i8 VR128X:$src), addr:$dst),
+ (VMOVDQA32Z128mr addr:$dst, VR128X:$src)>;
+ def : Pat<(store (v8i16 VR128X:$src), addr:$dst),
+ (VMOVDQU32Z128mr addr:$dst, VR128X:$src)>;
+ def : Pat<(store (v16i8 VR128X:$src), addr:$dst),
+ (VMOVDQU32Z128mr addr:$dst, VR128X:$src)>;
+
+ // 256-bit load/store without BWI.
+ def : Pat<(alignedstore256 (v16i16 VR256X:$src), addr:$dst),
+ (VMOVDQA32Z256mr addr:$dst, VR256X:$src)>;
+ def : Pat<(alignedstore256 (v32i8 VR256X:$src), addr:$dst),
+ (VMOVDQA32Z256mr addr:$dst, VR256X:$src)>;
+ def : Pat<(store (v16i16 VR256X:$src), addr:$dst),
+ (VMOVDQU32Z256mr addr:$dst, VR256X:$src)>;
+ def : Pat<(store (v32i8 VR256X:$src), addr:$dst),
+ (VMOVDQU32Z256mr addr:$dst, VR256X:$src)>;
+}
+
let Predicates = [HasVLX] in {
// Special patterns for storing subvector extracts of lower 128-bits of 256.
// Its cheaper to just use VMOVAPS/VMOVUPS instead of VEXTRACTF128mr
@@ -2844,23 +3092,23 @@ let Predicates = [HasVLX] in {
// Special patterns for storing subvector extracts of lower 256-bits of 512.
// Its cheaper to just use VMOVAPS/VMOVUPS instead of VEXTRACTF128mr
- def : Pat<(alignedstore (v4f64 (extract_subvector
- (v8f64 VR512:$src), (iPTR 0))), addr:$dst),
+ def : Pat<(alignedstore256 (v4f64 (extract_subvector
+ (v8f64 VR512:$src), (iPTR 0))), addr:$dst),
(VMOVAPDZ256mr addr:$dst, (v4f64 (EXTRACT_SUBREG VR512:$src,sub_ymm)))>;
def : Pat<(alignedstore (v8f32 (extract_subvector
(v16f32 VR512:$src), (iPTR 0))), addr:$dst),
(VMOVAPSZ256mr addr:$dst, (v8f32 (EXTRACT_SUBREG VR512:$src,sub_ymm)))>;
- def : Pat<(alignedstore (v4i64 (extract_subvector
- (v8i64 VR512:$src), (iPTR 0))), addr:$dst),
+ def : Pat<(alignedstore256 (v4i64 (extract_subvector
+ (v8i64 VR512:$src), (iPTR 0))), addr:$dst),
(VMOVDQA64Z256mr addr:$dst, (v4i64 (EXTRACT_SUBREG VR512:$src,sub_ymm)))>;
- def : Pat<(alignedstore (v8i32 (extract_subvector
- (v16i32 VR512:$src), (iPTR 0))), addr:$dst),
+ def : Pat<(alignedstore256 (v8i32 (extract_subvector
+ (v16i32 VR512:$src), (iPTR 0))), addr:$dst),
(VMOVDQA32Z256mr addr:$dst, (v8i32 (EXTRACT_SUBREG VR512:$src,sub_ymm)))>;
- def : Pat<(alignedstore (v16i16 (extract_subvector
- (v32i16 VR512:$src), (iPTR 0))), addr:$dst),
+ def : Pat<(alignedstore256 (v16i16 (extract_subvector
+ (v32i16 VR512:$src), (iPTR 0))), addr:$dst),
(VMOVDQA32Z256mr addr:$dst, (v16i16 (EXTRACT_SUBREG VR512:$src,sub_ymm)))>;
- def : Pat<(alignedstore (v32i8 (extract_subvector
- (v64i8 VR512:$src), (iPTR 0))), addr:$dst),
+ def : Pat<(alignedstore256 (v32i8 (extract_subvector
+ (v64i8 VR512:$src), (iPTR 0))), addr:$dst),
(VMOVDQA32Z256mr addr:$dst, (v32i8 (EXTRACT_SUBREG VR512:$src,sub_ymm)))>;
def : Pat<(store (v4f64 (extract_subvector
@@ -2886,6 +3134,7 @@ let Predicates = [HasVLX] in {
// Move Int Doubleword to Packed Double Int
//
+let ExeDomain = SSEPackedInt in {
def VMOVDI2PDIZrr : AVX512BI<0x6E, MRMSrcReg, (outs VR128X:$dst), (ins GR32:$src),
"vmovd\t{$src, $dst|$dst, $src}",
[(set VR128X:$dst,
@@ -2921,10 +3170,11 @@ def VMOVSDto64Zmr : AVX512BI<0x7E, MRMDestMem, (outs), (ins i64mem:$dst, FR64X:$
IIC_SSE_MOVDQ>, EVEX, VEX_W, Sched<[WriteStore]>,
EVEX_CD8<64, CD8VT1>;
}
+} // ExeDomain = SSEPackedInt
// Move Int Doubleword to Single Scalar
//
-let isCodeGenOnly = 1 in {
+let ExeDomain = SSEPackedInt, isCodeGenOnly = 1 in {
def VMOVDI2SSZrr : AVX512BI<0x6E, MRMSrcReg, (outs FR32X:$dst), (ins GR32:$src),
"vmovd\t{$src, $dst|$dst, $src}",
[(set FR32X:$dst, (bitconvert GR32:$src))],
@@ -2934,10 +3184,11 @@ def VMOVDI2SSZrm : AVX512BI<0x6E, MRMSrcMem, (outs FR32X:$dst), (ins i32mem:$sr
"vmovd\t{$src, $dst|$dst, $src}",
[(set FR32X:$dst, (bitconvert (loadi32 addr:$src)))],
IIC_SSE_MOVDQ>, EVEX, EVEX_CD8<32, CD8VT1>;
-}
+} // ExeDomain = SSEPackedInt, isCodeGenOnly = 1
// Move doubleword from xmm register to r/m32
//
+let ExeDomain = SSEPackedInt in {
def VMOVPDI2DIZrr : AVX512BI<0x7E, MRMDestReg, (outs GR32:$dst), (ins VR128X:$src),
"vmovd\t{$src, $dst|$dst, $src}",
[(set GR32:$dst, (extractelt (v4i32 VR128X:$src),
@@ -2949,9 +3200,11 @@ def VMOVPDI2DIZmr : AVX512BI<0x7E, MRMDestMem, (outs),
[(store (i32 (extractelt (v4i32 VR128X:$src),
(iPTR 0))), addr:$dst)], IIC_SSE_MOVDQ>,
EVEX, EVEX_CD8<32, CD8VT1>;
+} // ExeDomain = SSEPackedInt
// Move quadword from xmm1 register to r/m64
//
+let ExeDomain = SSEPackedInt in {
def VMOVPQIto64Zrr : I<0x7E, MRMDestReg, (outs GR64:$dst), (ins VR128X:$src),
"vmovq\t{$src, $dst|$dst, $src}",
[(set GR64:$dst, (extractelt (v2i64 VR128X:$src),
@@ -2978,10 +3231,11 @@ def VMOVPQI2QIZrr : AVX512BI<0xD6, MRMDestReg, (outs VR128X:$dst),
(ins VR128X:$src),
"vmovq.s\t{$src, $dst|$dst, $src}",[]>,
EVEX, VEX_W;
+} // ExeDomain = SSEPackedInt
// Move Scalar Single to Double Int
//
-let isCodeGenOnly = 1 in {
+let ExeDomain = SSEPackedInt, isCodeGenOnly = 1 in {
def VMOVSS2DIZrr : AVX512BI<0x7E, MRMDestReg, (outs GR32:$dst),
(ins FR32X:$src),
"vmovd\t{$src, $dst|$dst, $src}",
@@ -2992,54 +3246,71 @@ def VMOVSS2DIZmr : AVX512BI<0x7E, MRMDestMem, (outs),
"vmovd\t{$src, $dst|$dst, $src}",
[(store (i32 (bitconvert FR32X:$src)), addr:$dst)],
IIC_SSE_MOVDQ>, EVEX, EVEX_CD8<32, CD8VT1>;
-}
+} // ExeDomain = SSEPackedInt, isCodeGenOnly = 1
// Move Quadword Int to Packed Quadword Int
//
+let ExeDomain = SSEPackedInt in {
def VMOVQI2PQIZrm : AVX512XSI<0x7E, MRMSrcMem, (outs VR128X:$dst),
(ins i64mem:$src),
"vmovq\t{$src, $dst|$dst, $src}",
[(set VR128X:$dst,
(v2i64 (scalar_to_vector (loadi64 addr:$src))))]>,
EVEX, VEX_W, EVEX_CD8<8, CD8VT8>;
+} // ExeDomain = SSEPackedInt
//===----------------------------------------------------------------------===//
// AVX-512 MOVSS, MOVSD
//===----------------------------------------------------------------------===//
-multiclass avx512_move_scalar <string asm, SDNode OpNode,
+multiclass avx512_move_scalar<string asm, SDNode OpNode,
X86VectorVTInfo _> {
- defm rr_Int : AVX512_maskable_scalar<0x10, MRMSrcReg, _, (outs _.RC:$dst),
- (ins _.RC:$src1, _.RC:$src2),
- asm, "$src2, $src1","$src1, $src2",
- (_.VT (OpNode (_.VT _.RC:$src1),
- (_.VT _.RC:$src2))),
- IIC_SSE_MOV_S_RR>, EVEX_4V;
- let Constraints = "$src1 = $dst" in
- defm rm_Int : AVX512_maskable_3src_scalar<0x10, MRMSrcMem, _,
- (outs _.RC:$dst),
- (ins _.ScalarMemOp:$src),
- asm,"$src","$src",
- (_.VT (OpNode (_.VT _.RC:$src1),
- (_.VT (scalar_to_vector
- (_.ScalarLdFrag addr:$src)))))>, EVEX;
- let isCodeGenOnly = 1 in {
- def rr : AVX512PI<0x10, MRMSrcReg, (outs _.RC:$dst),
- (ins _.RC:$src1, _.FRC:$src2),
- !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
- [(set _.RC:$dst, (_.VT (OpNode _.RC:$src1,
- (scalar_to_vector _.FRC:$src2))))],
- _.ExeDomain,IIC_SSE_MOV_S_RR>, EVEX_4V;
- def rm : AVX512PI<0x10, MRMSrcMem, (outs _.FRC:$dst), (ins _.ScalarMemOp:$src),
- !strconcat(asm, "\t{$src, $dst|$dst, $src}"),
- [(set _.FRC:$dst, (_.ScalarLdFrag addr:$src))],
- _.ExeDomain, IIC_SSE_MOV_S_RM>, EVEX;
+ def rr : AVX512PI<0x10, MRMSrcReg, (outs _.RC:$dst),
+ (ins _.RC:$src1, _.FRC:$src2),
+ !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+ [(set _.RC:$dst, (_.VT (OpNode _.RC:$src1,
+ (scalar_to_vector _.FRC:$src2))))],
+ _.ExeDomain,IIC_SSE_MOV_S_RR>, EVEX_4V;
+ def rrkz : AVX512PI<0x10, MRMSrcReg, (outs _.RC:$dst),
+ (ins _.KRCWM:$mask, _.RC:$src1, _.RC:$src2),
+ !strconcat(asm, "\t{$src2, $src1, $dst {${mask}} {z}|",
+ "$dst {${mask}} {z}, $src1, $src2}"),
+ [(set _.RC:$dst, (_.VT (X86selects _.KRCWM:$mask,
+ (_.VT (OpNode _.RC:$src1, _.RC:$src2)),
+ _.ImmAllZerosV)))],
+ _.ExeDomain,IIC_SSE_MOV_S_RR>, EVEX_4V, EVEX_KZ;
+ let Constraints = "$src0 = $dst" in
+ def rrk : AVX512PI<0x10, MRMSrcReg, (outs _.RC:$dst),
+ (ins _.RC:$src0, _.KRCWM:$mask, _.RC:$src1, _.RC:$src2),
+ !strconcat(asm, "\t{$src2, $src1, $dst {${mask}}|",
+ "$dst {${mask}}, $src1, $src2}"),
+ [(set _.RC:$dst, (_.VT (X86selects _.KRCWM:$mask,
+ (_.VT (OpNode _.RC:$src1, _.RC:$src2)),
+ (_.VT _.RC:$src0))))],
+ _.ExeDomain,IIC_SSE_MOV_S_RR>, EVEX_4V, EVEX_K;
+ let canFoldAsLoad = 1, isReMaterializable = 1 in
+ def rm : AVX512PI<0x10, MRMSrcMem, (outs _.FRC:$dst), (ins _.ScalarMemOp:$src),
+ !strconcat(asm, "\t{$src, $dst|$dst, $src}"),
+ [(set _.FRC:$dst, (_.ScalarLdFrag addr:$src))],
+ _.ExeDomain, IIC_SSE_MOV_S_RM>, EVEX;
+ let mayLoad = 1, hasSideEffects = 0 in {
+ let Constraints = "$src0 = $dst" in
+ def rmk : AVX512PI<0x10, MRMSrcMem, (outs _.RC:$dst),
+ (ins _.RC:$src0, _.KRCWM:$mask, _.ScalarMemOp:$src),
+ !strconcat(asm, "\t{$src, $dst {${mask}}|",
+ "$dst {${mask}}, $src}"),
+ [], _.ExeDomain, IIC_SSE_MOV_S_RM>, EVEX, EVEX_K;
+ def rmkz : AVX512PI<0x10, MRMSrcMem, (outs _.RC:$dst),
+ (ins _.KRCWM:$mask, _.ScalarMemOp:$src),
+ !strconcat(asm, "\t{$src, $dst {${mask}} {z}|",
+ "$dst {${mask}} {z}, $src}"),
+ [], _.ExeDomain, IIC_SSE_MOV_S_RM>, EVEX, EVEX_KZ;
}
def mr: AVX512PI<0x11, MRMDestMem, (outs), (ins _.ScalarMemOp:$dst, _.FRC:$src),
!strconcat(asm, "\t{$src, $dst|$dst, $src}"),
[(store _.FRC:$src, addr:$dst)], _.ExeDomain, IIC_SSE_MOV_S_MR>,
EVEX;
- let mayStore = 1 in
+ let mayStore = 1, hasSideEffects = 0 in
def mrk: AVX512PI<0x11, MRMDestMem, (outs),
(ins _.ScalarMemOp:$dst, VK1WM:$mask, _.FRC:$src),
!strconcat(asm, "\t{$src, $dst {${mask}}|$dst {${mask}}, $src}"),
@@ -3052,12 +3323,99 @@ defm VMOVSSZ : avx512_move_scalar<"vmovss", X86Movss, f32x_info>,
defm VMOVSDZ : avx512_move_scalar<"vmovsd", X86Movsd, f64x_info>,
VEX_LIG, XD, VEX_W, EVEX_CD8<64, CD8VT1>;
+
+multiclass avx512_move_scalar_lowering<string InstrStr, SDNode OpNode,
+ PatLeaf ZeroFP, X86VectorVTInfo _> {
+
+def : Pat<(_.VT (OpNode _.RC:$src0,
+ (_.VT (scalar_to_vector
+ (_.EltVT (X86selects (i1 (trunc GR32:$mask)),
+ (_.EltVT _.FRC:$src1),
+ (_.EltVT _.FRC:$src2))))))),
+ (COPY_TO_REGCLASS (!cast<Instruction>(InstrStr#rrk)
+ (COPY_TO_REGCLASS _.FRC:$src2, _.RC),
+ (COPY_TO_REGCLASS GR32:$mask, VK1WM),
+ (_.VT _.RC:$src0),
+ (COPY_TO_REGCLASS _.FRC:$src1, _.RC)),
+ _.RC)>;
+
+def : Pat<(_.VT (OpNode _.RC:$src0,
+ (_.VT (scalar_to_vector
+ (_.EltVT (X86selects (i1 (trunc GR32:$mask)),
+ (_.EltVT _.FRC:$src1),
+ (_.EltVT ZeroFP))))))),
+ (COPY_TO_REGCLASS (!cast<Instruction>(InstrStr#rrkz)
+ (COPY_TO_REGCLASS GR32:$mask, VK1WM),
+ (_.VT _.RC:$src0),
+ (COPY_TO_REGCLASS _.FRC:$src1, _.RC)),
+ _.RC)>;
+
+}
+
+multiclass avx512_store_scalar_lowering<string InstrStr, AVX512VLVectorVTInfo _,
+ dag Mask, RegisterClass MaskRC> {
+
+def : Pat<(masked_store addr:$dst, Mask,
+ (_.info512.VT (insert_subvector undef,
+ (_.info256.VT (insert_subvector undef,
+ (_.info128.VT _.info128.RC:$src),
+ (i64 0))),
+ (i64 0)))),
+ (!cast<Instruction>(InstrStr#mrk) addr:$dst,
+ (i1 (COPY_TO_REGCLASS MaskRC:$mask, VK1WM)),
+ (COPY_TO_REGCLASS _.info128.RC:$src, _.info128.FRC))>;
+
+}
+
+multiclass avx512_load_scalar_lowering<string InstrStr, AVX512VLVectorVTInfo _,
+ dag Mask, RegisterClass MaskRC> {
+
+def : Pat<(_.info128.VT (extract_subvector
+ (_.info512.VT (masked_load addr:$srcAddr, Mask,
+ (_.info512.VT (bitconvert
+ (v16i32 immAllZerosV))))),
+ (i64 0))),
+ (!cast<Instruction>(InstrStr#rmkz)
+ (i1 (COPY_TO_REGCLASS MaskRC:$mask, VK1WM)),
+ addr:$srcAddr)>;
+
+def : Pat<(_.info128.VT (extract_subvector
+ (_.info512.VT (masked_load addr:$srcAddr, Mask,
+ (_.info512.VT (insert_subvector undef,
+ (_.info256.VT (insert_subvector undef,
+ (_.info128.VT (X86vzmovl _.info128.RC:$src)),
+ (i64 0))),
+ (i64 0))))),
+ (i64 0))),
+ (!cast<Instruction>(InstrStr#rmk) _.info128.RC:$src,
+ (i1 (COPY_TO_REGCLASS MaskRC:$mask, VK1WM)),
+ addr:$srcAddr)>;
+
+}
+
+defm : avx512_move_scalar_lowering<"VMOVSSZ", X86Movss, fp32imm0, v4f32x_info>;
+defm : avx512_move_scalar_lowering<"VMOVSDZ", X86Movsd, fp64imm0, v2f64x_info>;
+
+defm : avx512_store_scalar_lowering<"VMOVSSZ", avx512vl_f32_info,
+ (v16i1 (bitconvert (i16 (trunc (and GR32:$mask, (i32 1)))))), GR32>;
+defm : avx512_store_scalar_lowering<"VMOVSSZ", avx512vl_f32_info,
+ (v16i1 (bitconvert (i16 (and GR16:$mask, (i16 1))))), GR16>;
+defm : avx512_store_scalar_lowering<"VMOVSDZ", avx512vl_f64_info,
+ (v8i1 (bitconvert (i8 (and GR8:$mask, (i8 1))))), GR8>;
+
+defm : avx512_load_scalar_lowering<"VMOVSSZ", avx512vl_f32_info,
+ (v16i1 (bitconvert (i16 (trunc (and GR32:$mask, (i32 1)))))), GR32>;
+defm : avx512_load_scalar_lowering<"VMOVSSZ", avx512vl_f32_info,
+ (v16i1 (bitconvert (i16 (and GR16:$mask, (i16 1))))), GR16>;
+defm : avx512_load_scalar_lowering<"VMOVSDZ", avx512vl_f64_info,
+ (v8i1 (bitconvert (i8 (and GR8:$mask, (i8 1))))), GR8>;
+
def : Pat<(f32 (X86selects VK1WM:$mask, (f32 FR32X:$src1), (f32 FR32X:$src2))),
- (COPY_TO_REGCLASS (VMOVSSZrr_Intk (COPY_TO_REGCLASS FR32X:$src2, VR128X),
+ (COPY_TO_REGCLASS (VMOVSSZrrk (COPY_TO_REGCLASS FR32X:$src2, VR128X),
VK1WM:$mask, (v4f32 (IMPLICIT_DEF)),(COPY_TO_REGCLASS FR32X:$src1, VR128X)), FR32X)>;
def : Pat<(f64 (X86selects VK1WM:$mask, (f64 FR64X:$src1), (f64 FR64X:$src2))),
- (COPY_TO_REGCLASS (VMOVSDZrr_Intk (COPY_TO_REGCLASS FR64X:$src2, VR128X),
+ (COPY_TO_REGCLASS (VMOVSDZrrk (COPY_TO_REGCLASS FR64X:$src2, VR128X),
VK1WM:$mask, (v2f64 (IMPLICIT_DEF)), (COPY_TO_REGCLASS FR64X:$src1, VR128X)), FR64X)>;
def : Pat<(int_x86_avx512_mask_store_ss addr:$dst, VR128X:$src, GR8:$mask),
@@ -3088,6 +3446,7 @@ let Predicates = [HasAVX512] in {
(VMOVSSZrr (v4i32 (V_SET0)), (COPY_TO_REGCLASS VR128X:$src, FR32X))>;
def : Pat<(v2f64 (X86vzmovl (v2f64 (scalar_to_vector FR64X:$src)))),
(VMOVSDZrr (v2f64 (V_SET0)), FR64X:$src)>;
+ }
// Move low f32 and clear high bits.
def : Pat<(v8f32 (X86vzmovl (v8f32 VR256X:$src))),
@@ -3097,8 +3456,15 @@ let Predicates = [HasAVX512] in {
def : Pat<(v8i32 (X86vzmovl (v8i32 VR256X:$src))),
(SUBREG_TO_REG (i32 0),
(VMOVSSZrr (v4i32 (V_SET0)),
- (EXTRACT_SUBREG (v8i32 VR256X:$src), sub_xmm)), sub_xmm)>;
- }
+ (EXTRACT_SUBREG (v8i32 VR256X:$src), sub_xmm)), sub_xmm)>;
+ def : Pat<(v16f32 (X86vzmovl (v16f32 VR512:$src))),
+ (SUBREG_TO_REG (i32 0),
+ (VMOVSSZrr (v4f32 (V_SET0)),
+ (EXTRACT_SUBREG (v16f32 VR512:$src), sub_xmm)), sub_xmm)>;
+ def : Pat<(v16i32 (X86vzmovl (v16i32 VR512:$src))),
+ (SUBREG_TO_REG (i32 0),
+ (VMOVSSZrr (v4i32 (V_SET0)),
+ (EXTRACT_SUBREG (v16i32 VR512:$src), sub_xmm)), sub_xmm)>;
let AddedComplexity = 20 in {
// MOVSSrm zeros the high parts of the register; represent this
@@ -3109,6 +3475,8 @@ let Predicates = [HasAVX512] in {
(COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)>;
def : Pat<(v4f32 (X86vzmovl (loadv4f32 addr:$src))),
(COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)>;
+ def : Pat<(v4f32 (X86vzload addr:$src)),
+ (COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)>;
// MOVSDrm zeros the high parts of the register; represent this
// with SUBREG_TO_REG. The AVX versions also write: DST[255:128] <- 0
@@ -3131,6 +3499,8 @@ let Predicates = [HasAVX512] in {
def : Pat<(v8f32 (X86vzmovl (insert_subvector undef,
(v4f32 (scalar_to_vector (loadf32 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVSSZrm addr:$src), sub_xmm)>;
+ def : Pat<(v8f32 (X86vzload addr:$src)),
+ (SUBREG_TO_REG (i32 0), (VMOVSSZrm addr:$src), sub_xmm)>;
def : Pat<(v4f64 (X86vzmovl (insert_subvector undef,
(v2f64 (scalar_to_vector (loadf64 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVSDZrm addr:$src), sub_xmm)>;
@@ -3145,6 +3515,8 @@ let Predicates = [HasAVX512] in {
def : Pat<(v16f32 (X86vzmovl (insert_subvector undef,
(v4f32 (scalar_to_vector (loadf32 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVSSZrm addr:$src), sub_xmm)>;
+ def : Pat<(v16f32 (X86vzload addr:$src)),
+ (SUBREG_TO_REG (i32 0), (VMOVSSZrm addr:$src), sub_xmm)>;
def : Pat<(v8f64 (X86vzmovl (insert_subvector undef,
(v2f64 (scalar_to_vector (loadf64 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVSDZrm addr:$src), sub_xmm)>;
@@ -3168,10 +3540,17 @@ let Predicates = [HasAVX512] in {
(SUBREG_TO_REG (i32 0),
(VMOVSDZrr (v2f64 (V_SET0)),
(EXTRACT_SUBREG (v4f64 VR256X:$src), sub_xmm)), sub_xmm)>;
+ def : Pat<(v8f64 (X86vzmovl (v8f64 VR512:$src))),
+ (SUBREG_TO_REG (i32 0),
+ (VMOVSDZrr (v2f64 (V_SET0)),
+ (EXTRACT_SUBREG (v8f64 VR512:$src), sub_xmm)), sub_xmm)>;
def : Pat<(v4i64 (X86vzmovl (v4i64 VR256X:$src))),
(SUBREG_TO_REG (i32 0), (VMOVSDZrr (v2i64 (V_SET0)),
(EXTRACT_SUBREG (v4i64 VR256X:$src), sub_xmm)), sub_xmm)>;
+ def : Pat<(v8i64 (X86vzmovl (v8i64 VR512:$src))),
+ (SUBREG_TO_REG (i32 0), (VMOVSDZrr (v2i64 (V_SET0)),
+ (EXTRACT_SUBREG (v8i64 VR512:$src), sub_xmm)), sub_xmm)>;
// Extract and store.
def : Pat<(store (f32 (extractelt (v4f32 VR128X:$src), (iPTR 0))),
@@ -3238,15 +3617,6 @@ def VMOVZPQILo2PQIZrr : AVX512XSI<0x7E, MRMSrcReg, (outs VR128X:$dst),
(v2i64 VR128X:$src))))],
IIC_SSE_MOVQ_RR>, EVEX, VEX_W;
-let AddedComplexity = 20 , isCodeGenOnly = 1 in
-def VMOVZPQILo2PQIZrm : AVX512XSI<0x7E, MRMSrcMem, (outs VR128X:$dst),
- (ins i128mem:$src),
- "vmovq\t{$src, $dst|$dst, $src}",
- [(set VR128X:$dst, (v2i64 (X86vzmovl
- (loadv2i64 addr:$src))))],
- IIC_SSE_MOVDQ>, EVEX, VEX_W,
- EVEX_CD8<8, CD8VT8>;
-
let Predicates = [HasAVX512] in {
let AddedComplexity = 15 in {
def : Pat<(v4i32 (X86vzmovl (v4i32 (scalar_to_vector GR32:$src)))),
@@ -3258,34 +3628,46 @@ let Predicates = [HasAVX512] in {
def : Pat<(v4i64 (X86vzmovl (insert_subvector undef,
(v2i64 (scalar_to_vector GR64:$src)),(iPTR 0)))),
(SUBREG_TO_REG (i64 0), (VMOV64toPQIZrr GR64:$src), sub_xmm)>;
+
+ def : Pat<(v8i64 (X86vzmovl (insert_subvector undef,
+ (v2i64 (scalar_to_vector GR64:$src)),(iPTR 0)))),
+ (SUBREG_TO_REG (i64 0), (VMOV64toPQIZrr GR64:$src), sub_xmm)>;
}
// AVX 128-bit movd/movq instruction write zeros in the high 128-bit part.
let AddedComplexity = 20 in {
def : Pat<(v4i32 (X86vzmovl (v4i32 (scalar_to_vector (loadi32 addr:$src))))),
(VMOVDI2PDIZrm addr:$src)>;
-
def : Pat<(v4i32 (X86vzmovl (bc_v4i32 (loadv4f32 addr:$src)))),
(VMOVDI2PDIZrm addr:$src)>;
def : Pat<(v4i32 (X86vzmovl (bc_v4i32 (loadv2i64 addr:$src)))),
(VMOVDI2PDIZrm addr:$src)>;
+ def : Pat<(v4i32 (X86vzload addr:$src)),
+ (VMOVDI2PDIZrm addr:$src)>;
+ def : Pat<(v8i32 (X86vzload addr:$src)),
+ (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrm addr:$src), sub_xmm)>;
def : Pat<(v2i64 (X86vzmovl (loadv2i64 addr:$src))),
- (VMOVZPQILo2PQIZrm addr:$src)>;
+ (VMOVQI2PQIZrm addr:$src)>;
def : Pat<(v2f64 (X86vzmovl (v2f64 VR128X:$src))),
- (VMOVZPQILo2PQIZrr VR128X:$src)>;
+ (VMOVZPQILo2PQIZrr VR128X:$src)>;
def : Pat<(v2i64 (X86vzload addr:$src)),
- (VMOVZPQILo2PQIZrm addr:$src)>;
+ (VMOVQI2PQIZrm addr:$src)>;
def : Pat<(v4i64 (X86vzload addr:$src)),
- (SUBREG_TO_REG (i64 0), (VMOVZPQILo2PQIZrm addr:$src), sub_xmm)>;
+ (SUBREG_TO_REG (i64 0), (VMOVQI2PQIZrm addr:$src), sub_xmm)>;
}
// Use regular 128-bit instructions to match 256-bit scalar_to_vec+zext.
def : Pat<(v8i32 (X86vzmovl (insert_subvector undef,
(v4i32 (scalar_to_vector GR32:$src)),(iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrr GR32:$src), sub_xmm)>;
+ def : Pat<(v16i32 (X86vzmovl (insert_subvector undef,
+ (v4i32 (scalar_to_vector GR32:$src)),(iPTR 0)))),
+ (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrr GR32:$src), sub_xmm)>;
// Use regular 128-bit instructions to match 512-bit scalar_to_vec+zext.
+ def : Pat<(v16i32 (X86vzload addr:$src)),
+ (SUBREG_TO_REG (i32 0), (VMOVDI2PDIZrm addr:$src), sub_xmm)>;
def : Pat<(v8i64 (X86vzload addr:$src)),
- (SUBREG_TO_REG (i64 0), (VMOVZPQILo2PQIZrm addr:$src), sub_xmm)>;
+ (SUBREG_TO_REG (i64 0), (VMOVQI2PQIZrm addr:$src), sub_xmm)>;
}
def : Pat<(v16i32 (X86Vinsert (v16i32 immAllZerosV), GR32:$src2, (iPTR 0))),
@@ -3366,11 +3748,11 @@ let Predicates = [HasAVX512], AddedComplexity = 400 in {
(VMOVNTDQAZrm addr:$src)>;
def : Pat<(v8i64 (alignednontemporalload addr:$src)),
(VMOVNTDQAZrm addr:$src)>;
- def : Pat<(v16i32 (alignednontemporalload addr:$src)),
+ def : Pat<(v16i32 (bitconvert (v8i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZrm addr:$src)>;
- def : Pat<(v32i16 (alignednontemporalload addr:$src)),
+ def : Pat<(v32i16 (bitconvert (v8i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZrm addr:$src)>;
- def : Pat<(v64i8 (alignednontemporalload addr:$src)),
+ def : Pat<(v64i8 (bitconvert (v8i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZrm addr:$src)>;
}
@@ -3388,11 +3770,11 @@ let Predicates = [HasVLX], AddedComplexity = 400 in {
(VMOVNTDQAZ256rm addr:$src)>;
def : Pat<(v4i64 (alignednontemporalload addr:$src)),
(VMOVNTDQAZ256rm addr:$src)>;
- def : Pat<(v8i32 (alignednontemporalload addr:$src)),
+ def : Pat<(v8i32 (bitconvert (v2i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZ256rm addr:$src)>;
- def : Pat<(v16i16 (alignednontemporalload addr:$src)),
+ def : Pat<(v16i16 (bitconvert (v2i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZ256rm addr:$src)>;
- def : Pat<(v32i8 (alignednontemporalload addr:$src)),
+ def : Pat<(v32i8 (bitconvert (v2i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZ256rm addr:$src)>;
def : Pat<(alignednontemporalstore (v4i32 VR128X:$src), addr:$dst),
@@ -3408,11 +3790,11 @@ let Predicates = [HasVLX], AddedComplexity = 400 in {
(VMOVNTDQAZ128rm addr:$src)>;
def : Pat<(v2i64 (alignednontemporalload addr:$src)),
(VMOVNTDQAZ128rm addr:$src)>;
- def : Pat<(v4i32 (alignednontemporalload addr:$src)),
+ def : Pat<(v4i32 (bitconvert (v2i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZ128rm addr:$src)>;
- def : Pat<(v8i16 (alignednontemporalload addr:$src)),
+ def : Pat<(v8i16 (bitconvert (v2i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZ128rm addr:$src)>;
- def : Pat<(v16i8 (alignednontemporalload addr:$src)),
+ def : Pat<(v16i8 (bitconvert (v2i64 (alignednontemporalload addr:$src)))),
(VMOVNTDQAZ128rm addr:$src)>;
}
@@ -3563,10 +3945,10 @@ multiclass avx512_binop_rm2<bits<8> opc, string OpcodeStr, OpndItins itins,
AVX512BIBase, EVEX_4V;
defm rmb : AVX512_maskable<opc, MRMSrcMem, _Dst, (outs _Dst.RC:$dst),
- (ins _Src.RC:$src1, _Dst.ScalarMemOp:$src2),
+ (ins _Src.RC:$src1, _Brdct.ScalarMemOp:$src2),
OpcodeStr,
"${src2}"##_Brdct.BroadcastStr##", $src1",
- "$src1, ${src2}"##_Dst.BroadcastStr,
+ "$src1, ${src2}"##_Brdct.BroadcastStr,
(_Dst.VT (OpNode (_Src.VT _Src.RC:$src1), (bitconvert
(_Brdct.VT (X86VBroadcast
(_Brdct.ScalarLdFrag addr:$src2)))))),
@@ -3646,13 +4028,14 @@ multiclass avx512_packs_rmb<bits<8> opc, string OpcodeStr, SDNode OpNode,
multiclass avx512_packs_rm<bits<8> opc, string OpcodeStr,
SDNode OpNode,X86VectorVTInfo _Src,
- X86VectorVTInfo _Dst> {
+ X86VectorVTInfo _Dst, bit IsCommutable = 0> {
defm rr : AVX512_maskable<opc, MRMSrcReg, _Dst, (outs _Dst.RC:$dst),
(ins _Src.RC:$src1, _Src.RC:$src2), OpcodeStr,
"$src2, $src1","$src1, $src2",
(_Dst.VT (OpNode
(_Src.VT _Src.RC:$src1),
- (_Src.VT _Src.RC:$src2)))>,
+ (_Src.VT _Src.RC:$src2))),
+ NoItinerary, IsCommutable>,
EVEX_CD8<_Src.EltSize, CD8VF>, EVEX_4V;
defm rm : AVX512_maskable<opc, MRMSrcMem, _Dst, (outs _Dst.RC:$dst),
(ins _Src.RC:$src1, _Src.MemOp:$src2), OpcodeStr,
@@ -3695,15 +4078,15 @@ multiclass avx512_packs_all_i16_i8<bits<8> opc, string OpcodeStr,
multiclass avx512_vpmadd<bits<8> opc, string OpcodeStr,
SDNode OpNode, AVX512VLVectorVTInfo _Src,
- AVX512VLVectorVTInfo _Dst> {
+ AVX512VLVectorVTInfo _Dst, bit IsCommutable = 0> {
let Predicates = [HasBWI] in
defm NAME#Z : avx512_packs_rm<opc, OpcodeStr, OpNode, _Src.info512,
- _Dst.info512>, EVEX_V512;
+ _Dst.info512, IsCommutable>, EVEX_V512;
let Predicates = [HasBWI, HasVLX] in {
defm NAME#Z256 : avx512_packs_rm<opc, OpcodeStr, OpNode, _Src.info256,
- _Dst.info256>, EVEX_V256;
+ _Dst.info256, IsCommutable>, EVEX_V256;
defm NAME#Z128 : avx512_packs_rm<opc, OpcodeStr, OpNode, _Src.info128,
- _Dst.info128>, EVEX_V128;
+ _Dst.info128, IsCommutable>, EVEX_V128;
}
}
@@ -3715,7 +4098,7 @@ defm VPACKUSWB : avx512_packs_all_i16_i8 <0x67, "vpackuswb", X86Packus>, AVX512B
defm VPMADDUBSW : avx512_vpmadd<0x04, "vpmaddubsw", X86vpmaddubsw,
avx512vl_i8_info, avx512vl_i16_info>, AVX512BIBase, T8PD;
defm VPMADDWD : avx512_vpmadd<0xF5, "vpmaddwd", X86vpmaddwd,
- avx512vl_i16_info, avx512vl_i32_info>, AVX512BIBase;
+ avx512vl_i16_info, avx512vl_i32_info, 1>, AVX512BIBase;
defm VPMAXSB : avx512_binop_rm_vl_b<0x3C, "vpmaxsb", smax,
SSE_INTALU_ITINS_P, HasBWI, 1>, T8PD;
@@ -3744,17 +4127,119 @@ defm VPMINUW : avx512_binop_rm_vl_w<0x3A, "vpminuw", umin,
SSE_INTALU_ITINS_P, HasBWI, 1>, T8PD;
defm VPMINU : avx512_binop_rm_vl_dq<0x3B, 0x3B, "vpminu", umin,
SSE_INTALU_ITINS_P, HasAVX512, 1>, T8PD;
+
+// PMULLQ: Use 512bit version to implement 128/256 bit in case NoVLX.
+let Predicates = [HasDQI, NoVLX] in {
+ def : Pat<(v4i64 (mul (v4i64 VR256X:$src1), (v4i64 VR256X:$src2))),
+ (EXTRACT_SUBREG
+ (VPMULLQZrr
+ (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), VR256X:$src1, sub_ymm),
+ (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), VR256X:$src2, sub_ymm)),
+ sub_ymm)>;
+
+ def : Pat<(v2i64 (mul (v2i64 VR128X:$src1), (v2i64 VR128X:$src2))),
+ (EXTRACT_SUBREG
+ (VPMULLQZrr
+ (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), VR128X:$src1, sub_xmm),
+ (INSERT_SUBREG (v8i64 (IMPLICIT_DEF)), VR128X:$src2, sub_xmm)),
+ sub_xmm)>;
+}
+
//===----------------------------------------------------------------------===//
// AVX-512 Logical Instructions
//===----------------------------------------------------------------------===//
-defm VPAND : avx512_binop_rm_vl_dq<0xDB, 0xDB, "vpand", and,
+multiclass avx512_logic_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ X86VectorVTInfo _, OpndItins itins,
+ bit IsCommutable = 0> {
+ defm rr : AVX512_maskable_logic<opc, MRMSrcReg, _, (outs _.RC:$dst),
+ (ins _.RC:$src1, _.RC:$src2), OpcodeStr,
+ "$src2, $src1", "$src1, $src2",
+ (_.i64VT (OpNode (bitconvert (_.VT _.RC:$src1)),
+ (bitconvert (_.VT _.RC:$src2)))),
+ (_.VT (bitconvert (_.i64VT (OpNode _.RC:$src1,
+ _.RC:$src2)))),
+ itins.rr, IsCommutable>,
+ AVX512BIBase, EVEX_4V;
+
+ defm rm : AVX512_maskable_logic<opc, MRMSrcMem, _, (outs _.RC:$dst),
+ (ins _.RC:$src1, _.MemOp:$src2), OpcodeStr,
+ "$src2, $src1", "$src1, $src2",
+ (_.i64VT (OpNode (bitconvert (_.VT _.RC:$src1)),
+ (bitconvert (_.LdFrag addr:$src2)))),
+ (_.VT (bitconvert (_.i64VT (OpNode _.RC:$src1,
+ (bitconvert (_.LdFrag addr:$src2)))))),
+ itins.rm>,
+ AVX512BIBase, EVEX_4V;
+}
+
+multiclass avx512_logic_rmb<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ X86VectorVTInfo _, OpndItins itins,
+ bit IsCommutable = 0> :
+ avx512_logic_rm<opc, OpcodeStr, OpNode, _, itins, IsCommutable> {
+ defm rmb : AVX512_maskable_logic<opc, MRMSrcMem, _, (outs _.RC:$dst),
+ (ins _.RC:$src1, _.ScalarMemOp:$src2), OpcodeStr,
+ "${src2}"##_.BroadcastStr##", $src1",
+ "$src1, ${src2}"##_.BroadcastStr,
+ (_.i64VT (OpNode _.RC:$src1,
+ (bitconvert
+ (_.VT (X86VBroadcast
+ (_.ScalarLdFrag addr:$src2)))))),
+ (_.VT (bitconvert (_.i64VT (OpNode _.RC:$src1,
+ (bitconvert
+ (_.VT (X86VBroadcast
+ (_.ScalarLdFrag addr:$src2)))))))),
+ itins.rm>,
+ AVX512BIBase, EVEX_4V, EVEX_B;
+}
+
+multiclass avx512_logic_rmb_vl<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ AVX512VLVectorVTInfo VTInfo, OpndItins itins,
+ Predicate prd, bit IsCommutable = 0> {
+ let Predicates = [prd] in
+ defm Z : avx512_logic_rmb<opc, OpcodeStr, OpNode, VTInfo.info512, itins,
+ IsCommutable>, EVEX_V512;
+
+ let Predicates = [prd, HasVLX] in {
+ defm Z256 : avx512_logic_rmb<opc, OpcodeStr, OpNode, VTInfo.info256, itins,
+ IsCommutable>, EVEX_V256;
+ defm Z128 : avx512_logic_rmb<opc, OpcodeStr, OpNode, VTInfo.info128, itins,
+ IsCommutable>, EVEX_V128;
+ }
+}
+
+multiclass avx512_logic_rm_vl_d<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ OpndItins itins, Predicate prd,
+ bit IsCommutable = 0> {
+ defm NAME : avx512_logic_rmb_vl<opc, OpcodeStr, OpNode, avx512vl_i32_info,
+ itins, prd, IsCommutable>, EVEX_CD8<32, CD8VF>;
+}
+
+multiclass avx512_logic_rm_vl_q<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ OpndItins itins, Predicate prd,
+ bit IsCommutable = 0> {
+ defm NAME : avx512_logic_rmb_vl<opc, OpcodeStr, OpNode, avx512vl_i64_info,
+ itins, prd, IsCommutable>,
+ VEX_W, EVEX_CD8<64, CD8VF>;
+}
+
+multiclass avx512_logic_rm_vl_dq<bits<8> opc_d, bits<8> opc_q, string OpcodeStr,
+ SDNode OpNode, OpndItins itins, Predicate prd,
+ bit IsCommutable = 0> {
+ defm Q : avx512_logic_rm_vl_q<opc_q, OpcodeStr#"q", OpNode, itins, prd,
+ IsCommutable>;
+
+ defm D : avx512_logic_rm_vl_d<opc_d, OpcodeStr#"d", OpNode, itins, prd,
+ IsCommutable>;
+}
+
+defm VPAND : avx512_logic_rm_vl_dq<0xDB, 0xDB, "vpand", and,
SSE_INTALU_ITINS_P, HasAVX512, 1>;
-defm VPOR : avx512_binop_rm_vl_dq<0xEB, 0xEB, "vpor", or,
+defm VPOR : avx512_logic_rm_vl_dq<0xEB, 0xEB, "vpor", or,
SSE_INTALU_ITINS_P, HasAVX512, 1>;
-defm VPXOR : avx512_binop_rm_vl_dq<0xEF, 0xEF, "vpxor", xor,
+defm VPXOR : avx512_logic_rm_vl_dq<0xEF, 0xEF, "vpxor", xor,
SSE_INTALU_ITINS_P, HasAVX512, 1>;
-defm VPANDN : avx512_binop_rm_vl_dq<0xDF, 0xDF, "vpandn", X86andnp,
+defm VPANDN : avx512_logic_rm_vl_dq<0xDF, 0xDF, "vpandn", X86andnp,
SSE_INTALU_ITINS_P, HasAVX512, 0>;
//===----------------------------------------------------------------------===//
@@ -3763,13 +4248,13 @@ defm VPANDN : avx512_binop_rm_vl_dq<0xDF, 0xDF, "vpandn", X86andnp,
multiclass avx512_fp_scalar<bits<8> opc, string OpcodeStr,X86VectorVTInfo _,
SDNode OpNode, SDNode VecNode, OpndItins itins,
bit IsCommutable> {
-
+ let ExeDomain = _.ExeDomain in {
defm rr_Int : AVX512_maskable_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2), OpcodeStr,
"$src2, $src1", "$src1, $src2",
(VecNode (_.VT _.RC:$src1), (_.VT _.RC:$src2),
(i32 FROUND_CURRENT)),
- itins.rr, IsCommutable>;
+ itins.rr>;
defm rm_Int : AVX512_maskable_scalar<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.ScalarMemOp:$src2), OpcodeStr,
@@ -3777,25 +4262,27 @@ multiclass avx512_fp_scalar<bits<8> opc, string OpcodeStr,X86VectorVTInfo _,
(VecNode (_.VT _.RC:$src1),
(_.VT (scalar_to_vector (_.ScalarLdFrag addr:$src2))),
(i32 FROUND_CURRENT)),
- itins.rm, IsCommutable>;
- let isCodeGenOnly = 1, isCommutable = IsCommutable,
- Predicates = [HasAVX512] in {
+ itins.rm>;
+ let isCodeGenOnly = 1, Predicates = [HasAVX512] in {
def rr : I< opc, MRMSrcReg, (outs _.FRC:$dst),
(ins _.FRC:$src1, _.FRC:$src2),
OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}",
[(set _.FRC:$dst, (OpNode _.FRC:$src1, _.FRC:$src2))],
- itins.rr>;
+ itins.rr> {
+ let isCommutable = IsCommutable;
+ }
def rm : I< opc, MRMSrcMem, (outs _.FRC:$dst),
(ins _.FRC:$src1, _.ScalarMemOp:$src2),
OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}",
[(set _.FRC:$dst, (OpNode _.FRC:$src1,
(_.ScalarLdFrag addr:$src2)))], itins.rm>;
}
+ }
}
multiclass avx512_fp_scalar_round<bits<8> opc, string OpcodeStr,X86VectorVTInfo _,
SDNode VecNode, OpndItins itins, bit IsCommutable = 0> {
-
+ let ExeDomain = _.ExeDomain in
defm rrb : AVX512_maskable_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2, AVX512RC:$rc), OpcodeStr,
"$rc, $src2, $src1", "$src1, $src2, $rc",
@@ -3805,7 +4292,7 @@ multiclass avx512_fp_scalar_round<bits<8> opc, string OpcodeStr,X86VectorVTInfo
}
multiclass avx512_fp_scalar_sae<bits<8> opc, string OpcodeStr,X86VectorVTInfo _,
SDNode VecNode, OpndItins itins, bit IsCommutable> {
-
+ let ExeDomain = _.ExeDomain in
defm rrb : AVX512_maskable_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2), OpcodeStr,
"{sae}, $src2, $src1", "$src1, $src2, {sae}",
@@ -3843,9 +4330,9 @@ multiclass avx512_binop_s_sae<bits<8> opc, string OpcodeStr, SDNode OpNode,
XD, VEX_W, EVEX_4V, VEX_LIG, EVEX_CD8<64, CD8VT1>;
}
defm VADD : avx512_binop_s_round<0x58, "vadd", fadd, X86faddRnd, SSE_ALU_ITINS_S, 1>;
-defm VMUL : avx512_binop_s_round<0x59, "vmul", fmul, X86fmulRnd, SSE_ALU_ITINS_S, 1>;
+defm VMUL : avx512_binop_s_round<0x59, "vmul", fmul, X86fmulRnd, SSE_MUL_ITINS_S, 1>;
defm VSUB : avx512_binop_s_round<0x5C, "vsub", fsub, X86fsubRnd, SSE_ALU_ITINS_S, 0>;
-defm VDIV : avx512_binop_s_round<0x5E, "vdiv", fdiv, X86fdivRnd, SSE_ALU_ITINS_S, 0>;
+defm VDIV : avx512_binop_s_round<0x5E, "vdiv", fdiv, X86fdivRnd, SSE_DIV_ITINS_S, 0>;
defm VMIN : avx512_binop_s_sae <0x5D, "vmin", X86fmin, X86fminRnd, SSE_ALU_ITINS_S, 0>;
defm VMAX : avx512_binop_s_sae <0x5F, "vmax", X86fmax, X86fmaxRnd, SSE_ALU_ITINS_S, 0>;
@@ -3853,12 +4340,14 @@ defm VMAX : avx512_binop_s_sae <0x5F, "vmax", X86fmax, X86fmaxRnd, SSE_ALU_ITIN
// X86fminc and X86fmaxc instead of X86fmin and X86fmax
multiclass avx512_comutable_binop_s<bits<8> opc, string OpcodeStr,
X86VectorVTInfo _, SDNode OpNode, OpndItins itins> {
- let isCodeGenOnly = 1, isCommutable =1, Predicates = [HasAVX512] in {
+ let isCodeGenOnly = 1, Predicates = [HasAVX512] in {
def rr : I< opc, MRMSrcReg, (outs _.FRC:$dst),
(ins _.FRC:$src1, _.FRC:$src2),
OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}",
[(set _.FRC:$dst, (OpNode _.FRC:$src1, _.FRC:$src2))],
- itins.rr>;
+ itins.rr> {
+ let isCommutable = 1;
+ }
def rm : I< opc, MRMSrcMem, (outs _.FRC:$dst),
(ins _.FRC:$src1, _.ScalarMemOp:$src2),
OpcodeStr#"\t{$src2, $src1, $dst|$dst, $src1, $src2}",
@@ -3882,27 +4371,35 @@ defm VMAXCSDZ : avx512_comutable_binop_s<0x5F, "vmaxsd", f64x_info, X86fmaxc,
SSE_ALU_ITINS_S.d>, XD, VEX_W, EVEX_4V, VEX_LIG,
EVEX_CD8<64, CD8VT1>;
-multiclass avx512_fp_packed<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _, bit IsCommutable> {
+multiclass avx512_fp_packed<bits<8> opc, string OpcodeStr, SDPatternOperator OpNode,
+ X86VectorVTInfo _, OpndItins itins,
+ bit IsCommutable> {
+ let ExeDomain = _.ExeDomain, hasSideEffects = 0 in {
defm rr: AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2), OpcodeStr##_.Suffix,
"$src2, $src1", "$src1, $src2",
- (_.VT (OpNode _.RC:$src1, _.RC:$src2))>, EVEX_4V;
- defm rm: AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
- (ins _.RC:$src1, _.MemOp:$src2), OpcodeStr##_.Suffix,
- "$src2, $src1", "$src1, $src2",
- (OpNode _.RC:$src1, (_.LdFrag addr:$src2))>, EVEX_4V;
- defm rmb: AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
- (ins _.RC:$src1, _.ScalarMemOp:$src2), OpcodeStr##_.Suffix,
- "${src2}"##_.BroadcastStr##", $src1",
- "$src1, ${src2}"##_.BroadcastStr,
- (OpNode _.RC:$src1, (_.VT (X86VBroadcast
- (_.ScalarLdFrag addr:$src2))))>,
- EVEX_4V, EVEX_B;
+ (_.VT (OpNode _.RC:$src1, _.RC:$src2)), itins.rr,
+ IsCommutable>, EVEX_4V;
+ let mayLoad = 1 in {
+ defm rm: AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
+ (ins _.RC:$src1, _.MemOp:$src2), OpcodeStr##_.Suffix,
+ "$src2, $src1", "$src1, $src2",
+ (OpNode _.RC:$src1, (_.LdFrag addr:$src2)), itins.rm>,
+ EVEX_4V;
+ defm rmb: AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
+ (ins _.RC:$src1, _.ScalarMemOp:$src2), OpcodeStr##_.Suffix,
+ "${src2}"##_.BroadcastStr##", $src1",
+ "$src1, ${src2}"##_.BroadcastStr,
+ (OpNode _.RC:$src1, (_.VT (X86VBroadcast
+ (_.ScalarLdFrag addr:$src2)))),
+ itins.rm>, EVEX_4V, EVEX_B;
+ }
+ }
}
-multiclass avx512_fp_round_packed<bits<8> opc, string OpcodeStr, SDNode OpNodeRnd,
- X86VectorVTInfo _> {
+multiclass avx512_fp_round_packed<bits<8> opc, string OpcodeStr, SDPatternOperator OpNodeRnd,
+ X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in
defm rb: AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2, AVX512RC:$rc), OpcodeStr##_.Suffix,
"$rc, $src2, $src1", "$src1, $src2, $rc",
@@ -3911,8 +4408,9 @@ multiclass avx512_fp_round_packed<bits<8> opc, string OpcodeStr, SDNode OpNodeRn
}
-multiclass avx512_fp_sae_packed<bits<8> opc, string OpcodeStr, SDNode OpNodeRnd,
- X86VectorVTInfo _> {
+multiclass avx512_fp_sae_packed<bits<8> opc, string OpcodeStr, SDPatternOperator OpNodeRnd,
+ X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in
defm rb: AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2), OpcodeStr##_.Suffix,
"{sae}, $src2, $src1", "$src1, $src2, {sae}",
@@ -3920,30 +4418,31 @@ multiclass avx512_fp_sae_packed<bits<8> opc, string OpcodeStr, SDNode OpNodeRnd,
EVEX_4V, EVEX_B;
}
-multiclass avx512_fp_binop_p<bits<8> opc, string OpcodeStr, SDNode OpNode,
- Predicate prd, bit IsCommutable = 0> {
+multiclass avx512_fp_binop_p<bits<8> opc, string OpcodeStr, SDPatternOperator OpNode,
+ Predicate prd, SizeItins itins,
+ bit IsCommutable = 0> {
let Predicates = [prd] in {
defm PSZ : avx512_fp_packed<opc, OpcodeStr, OpNode, v16f32_info,
- IsCommutable>, EVEX_V512, PS,
+ itins.s, IsCommutable>, EVEX_V512, PS,
EVEX_CD8<32, CD8VF>;
defm PDZ : avx512_fp_packed<opc, OpcodeStr, OpNode, v8f64_info,
- IsCommutable>, EVEX_V512, PD, VEX_W,
+ itins.d, IsCommutable>, EVEX_V512, PD, VEX_W,
EVEX_CD8<64, CD8VF>;
}
// Define only if AVX512VL feature is present.
let Predicates = [prd, HasVLX] in {
defm PSZ128 : avx512_fp_packed<opc, OpcodeStr, OpNode, v4f32x_info,
- IsCommutable>, EVEX_V128, PS,
+ itins.s, IsCommutable>, EVEX_V128, PS,
EVEX_CD8<32, CD8VF>;
defm PSZ256 : avx512_fp_packed<opc, OpcodeStr, OpNode, v8f32x_info,
- IsCommutable>, EVEX_V256, PS,
+ itins.s, IsCommutable>, EVEX_V256, PS,
EVEX_CD8<32, CD8VF>;
defm PDZ128 : avx512_fp_packed<opc, OpcodeStr, OpNode, v2f64x_info,
- IsCommutable>, EVEX_V128, PD, VEX_W,
+ itins.d, IsCommutable>, EVEX_V128, PD, VEX_W,
EVEX_CD8<64, CD8VF>;
defm PDZ256 : avx512_fp_packed<opc, OpcodeStr, OpNode, v4f64x_info,
- IsCommutable>, EVEX_V256, PD, VEX_W,
+ itins.d, IsCommutable>, EVEX_V256, PD, VEX_W,
EVEX_CD8<64, CD8VF>;
}
}
@@ -3962,26 +4461,140 @@ multiclass avx512_fp_binop_p_sae<bits<8> opc, string OpcodeStr, SDNode OpNodeRnd
EVEX_V512, PD, VEX_W,EVEX_CD8<64, CD8VF>;
}
-defm VADD : avx512_fp_binop_p<0x58, "vadd", fadd, HasAVX512, 1>,
+defm VADD : avx512_fp_binop_p<0x58, "vadd", fadd, HasAVX512,
+ SSE_ALU_ITINS_P, 1>,
avx512_fp_binop_p_round<0x58, "vadd", X86faddRnd>;
-defm VMUL : avx512_fp_binop_p<0x59, "vmul", fmul, HasAVX512, 1>,
+defm VMUL : avx512_fp_binop_p<0x59, "vmul", fmul, HasAVX512,
+ SSE_MUL_ITINS_P, 1>,
avx512_fp_binop_p_round<0x59, "vmul", X86fmulRnd>;
-defm VSUB : avx512_fp_binop_p<0x5C, "vsub", fsub, HasAVX512>,
+defm VSUB : avx512_fp_binop_p<0x5C, "vsub", fsub, HasAVX512, SSE_ALU_ITINS_P>,
avx512_fp_binop_p_round<0x5C, "vsub", X86fsubRnd>;
-defm VDIV : avx512_fp_binop_p<0x5E, "vdiv", fdiv, HasAVX512>,
+defm VDIV : avx512_fp_binop_p<0x5E, "vdiv", fdiv, HasAVX512, SSE_DIV_ITINS_P>,
avx512_fp_binop_p_round<0x5E, "vdiv", X86fdivRnd>;
-defm VMIN : avx512_fp_binop_p<0x5D, "vmin", X86fmin, HasAVX512, 0>,
+defm VMIN : avx512_fp_binop_p<0x5D, "vmin", X86fmin, HasAVX512,
+ SSE_ALU_ITINS_P, 0>,
avx512_fp_binop_p_sae<0x5D, "vmin", X86fminRnd>;
-defm VMAX : avx512_fp_binop_p<0x5F, "vmax", X86fmax, HasAVX512, 0>,
+defm VMAX : avx512_fp_binop_p<0x5F, "vmax", X86fmax, HasAVX512,
+ SSE_ALU_ITINS_P, 0>,
avx512_fp_binop_p_sae<0x5F, "vmax", X86fmaxRnd>;
let isCodeGenOnly = 1 in {
- defm VMINC : avx512_fp_binop_p<0x5D, "vmin", X86fminc, HasAVX512, 1>;
- defm VMAXC : avx512_fp_binop_p<0x5F, "vmax", X86fmaxc, HasAVX512, 1>;
+ defm VMINC : avx512_fp_binop_p<0x5D, "vmin", X86fminc, HasAVX512,
+ SSE_ALU_ITINS_P, 1>;
+ defm VMAXC : avx512_fp_binop_p<0x5F, "vmax", X86fmaxc, HasAVX512,
+ SSE_ALU_ITINS_P, 1>;
+}
+defm VAND : avx512_fp_binop_p<0x54, "vand", null_frag, HasDQI,
+ SSE_ALU_ITINS_P, 1>;
+defm VANDN : avx512_fp_binop_p<0x55, "vandn", null_frag, HasDQI,
+ SSE_ALU_ITINS_P, 0>;
+defm VOR : avx512_fp_binop_p<0x56, "vor", null_frag, HasDQI,
+ SSE_ALU_ITINS_P, 1>;
+defm VXOR : avx512_fp_binop_p<0x57, "vxor", null_frag, HasDQI,
+ SSE_ALU_ITINS_P, 1>;
+
+// Patterns catch floating point selects with bitcasted integer logic ops.
+multiclass avx512_fp_logical_lowering<string InstrStr, SDNode OpNode,
+ X86VectorVTInfo _, Predicate prd> {
+let Predicates = [prd] in {
+ // Masked register-register logical operations.
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (bitconvert (_.i64VT (OpNode _.RC:$src1, _.RC:$src2))),
+ _.RC:$src0)),
+ (!cast<Instruction>(InstrStr#rrk) _.RC:$src0, _.KRCWM:$mask,
+ _.RC:$src1, _.RC:$src2)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (bitconvert (_.i64VT (OpNode _.RC:$src1, _.RC:$src2))),
+ _.ImmAllZerosV)),
+ (!cast<Instruction>(InstrStr#rrkz) _.KRCWM:$mask, _.RC:$src1,
+ _.RC:$src2)>;
+ // Masked register-memory logical operations.
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (bitconvert (_.i64VT (OpNode _.RC:$src1,
+ (load addr:$src2)))),
+ _.RC:$src0)),
+ (!cast<Instruction>(InstrStr#rmk) _.RC:$src0, _.KRCWM:$mask,
+ _.RC:$src1, addr:$src2)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (bitconvert (_.i64VT (OpNode _.RC:$src1, (load addr:$src2)))),
+ _.ImmAllZerosV)),
+ (!cast<Instruction>(InstrStr#rmkz) _.KRCWM:$mask, _.RC:$src1,
+ addr:$src2)>;
+ // Register-broadcast logical operations.
+ def : Pat<(_.i64VT (OpNode _.RC:$src1,
+ (bitconvert (_.VT (X86VBroadcast
+ (_.ScalarLdFrag addr:$src2)))))),
+ (!cast<Instruction>(InstrStr#rmb) _.RC:$src1, addr:$src2)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (bitconvert
+ (_.i64VT (OpNode _.RC:$src1,
+ (bitconvert (_.VT
+ (X86VBroadcast
+ (_.ScalarLdFrag addr:$src2))))))),
+ _.RC:$src0)),
+ (!cast<Instruction>(InstrStr#rmbk) _.RC:$src0, _.KRCWM:$mask,
+ _.RC:$src1, addr:$src2)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (bitconvert
+ (_.i64VT (OpNode _.RC:$src1,
+ (bitconvert (_.VT
+ (X86VBroadcast
+ (_.ScalarLdFrag addr:$src2))))))),
+ _.ImmAllZerosV)),
+ (!cast<Instruction>(InstrStr#rmbkz) _.KRCWM:$mask,
+ _.RC:$src1, addr:$src2)>;
+}
+}
+
+multiclass avx512_fp_logical_lowering_sizes<string InstrStr, SDNode OpNode> {
+ defm : avx512_fp_logical_lowering<InstrStr#DZ128, OpNode, v4f32x_info, HasVLX>;
+ defm : avx512_fp_logical_lowering<InstrStr#QZ128, OpNode, v2f64x_info, HasVLX>;
+ defm : avx512_fp_logical_lowering<InstrStr#DZ256, OpNode, v8f32x_info, HasVLX>;
+ defm : avx512_fp_logical_lowering<InstrStr#QZ256, OpNode, v4f64x_info, HasVLX>;
+ defm : avx512_fp_logical_lowering<InstrStr#DZ, OpNode, v16f32_info, HasAVX512>;
+ defm : avx512_fp_logical_lowering<InstrStr#QZ, OpNode, v8f64_info, HasAVX512>;
+}
+
+defm : avx512_fp_logical_lowering_sizes<"VPAND", and>;
+defm : avx512_fp_logical_lowering_sizes<"VPOR", or>;
+defm : avx512_fp_logical_lowering_sizes<"VPXOR", xor>;
+defm : avx512_fp_logical_lowering_sizes<"VPANDN", X86andnp>;
+
+let Predicates = [HasVLX,HasDQI] in {
+ // Use packed logical operations for scalar ops.
+ def : Pat<(f64 (X86fand FR64X:$src1, FR64X:$src2)),
+ (COPY_TO_REGCLASS (VANDPDZ128rr
+ (COPY_TO_REGCLASS FR64X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR64X:$src2, VR128X)), FR64X)>;
+ def : Pat<(f64 (X86for FR64X:$src1, FR64X:$src2)),
+ (COPY_TO_REGCLASS (VORPDZ128rr
+ (COPY_TO_REGCLASS FR64X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR64X:$src2, VR128X)), FR64X)>;
+ def : Pat<(f64 (X86fxor FR64X:$src1, FR64X:$src2)),
+ (COPY_TO_REGCLASS (VXORPDZ128rr
+ (COPY_TO_REGCLASS FR64X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR64X:$src2, VR128X)), FR64X)>;
+ def : Pat<(f64 (X86fandn FR64X:$src1, FR64X:$src2)),
+ (COPY_TO_REGCLASS (VANDNPDZ128rr
+ (COPY_TO_REGCLASS FR64X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR64X:$src2, VR128X)), FR64X)>;
+
+ def : Pat<(f32 (X86fand FR32X:$src1, FR32X:$src2)),
+ (COPY_TO_REGCLASS (VANDPSZ128rr
+ (COPY_TO_REGCLASS FR32X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR32X:$src2, VR128X)), FR32X)>;
+ def : Pat<(f32 (X86for FR32X:$src1, FR32X:$src2)),
+ (COPY_TO_REGCLASS (VORPSZ128rr
+ (COPY_TO_REGCLASS FR32X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR32X:$src2, VR128X)), FR32X)>;
+ def : Pat<(f32 (X86fxor FR32X:$src1, FR32X:$src2)),
+ (COPY_TO_REGCLASS (VXORPSZ128rr
+ (COPY_TO_REGCLASS FR32X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR32X:$src2, VR128X)), FR32X)>;
+ def : Pat<(f32 (X86fandn FR32X:$src1, FR32X:$src2)),
+ (COPY_TO_REGCLASS (VANDNPSZ128rr
+ (COPY_TO_REGCLASS FR32X:$src1, VR128X),
+ (COPY_TO_REGCLASS FR32X:$src2, VR128X)), FR32X)>;
}
-defm VAND : avx512_fp_binop_p<0x54, "vand", X86fand, HasDQI, 1>;
-defm VANDN : avx512_fp_binop_p<0x55, "vandn", X86fandn, HasDQI, 0>;
-defm VOR : avx512_fp_binop_p<0x56, "vor", X86for, HasDQI, 1>;
-defm VXOR : avx512_fp_binop_p<0x57, "vxor", X86fxor, HasDQI, 1>;
multiclass avx512_fp_scalef_p<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo _> {
@@ -4157,6 +4770,7 @@ defm VPTESTNM : avx512_vptest_all_forms<0x26, 0x27, "vptestnm", X86testnm>, T8X
//===----------------------------------------------------------------------===//
multiclass avx512_shift_rmi<bits<8> opc, Format ImmFormR, Format ImmFormM,
string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in {
defm ri : AVX512_maskable<opc, ImmFormR, _, (outs _.RC:$dst),
(ins _.RC:$src1, u8imm:$src2), OpcodeStr,
"$src2, $src1", "$src1, $src2",
@@ -4168,10 +4782,12 @@ multiclass avx512_shift_rmi<bits<8> opc, Format ImmFormR, Format ImmFormM,
(_.VT (OpNode (_.VT (bitconvert (_.LdFrag addr:$src1))),
(i8 imm:$src2))),
SSE_INTSHIFT_ITINS_P.rm>;
+ }
}
multiclass avx512_shift_rmbi<bits<8> opc, Format ImmFormM,
string OpcodeStr, SDNode OpNode, X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in
defm mbi : AVX512_maskable<opc, ImmFormM, _, (outs _.RC:$dst),
(ins _.ScalarMemOp:$src1, u8imm:$src2), OpcodeStr,
"$src2, ${src1}"##_.BroadcastStr, "${src1}"##_.BroadcastStr##", $src2",
@@ -4182,6 +4798,7 @@ multiclass avx512_shift_rmbi<bits<8> opc, Format ImmFormM,
multiclass avx512_shift_rrm<bits<8> opc, string OpcodeStr, SDNode OpNode,
ValueType SrcVT, PatFrag bc_frag, X86VectorVTInfo _> {
// src2 is always 128-bit
+ let ExeDomain = _.ExeDomain in {
defm rr : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, VR128X:$src2), OpcodeStr,
"$src2, $src1", "$src1, $src2",
@@ -4193,6 +4810,7 @@ multiclass avx512_shift_rrm<bits<8> opc, string OpcodeStr, SDNode OpNode,
(_.VT (OpNode _.RC:$src1, (bc_frag (loadv2i64 addr:$src2)))),
SSE_INTSHIFT_ITINS_P.rm>, AVX512BIBase,
EVEX_4V;
+ }
}
multiclass avx512_shift_sizes<bits<8> opc, string OpcodeStr, SDNode OpNode,
@@ -4286,6 +4904,7 @@ defm VPSRL : avx512_shift_types<0xD2, 0xD3, 0xD1, "vpsrl", X86vsrl>;
//===-------------------------------------------------------------------===//
multiclass avx512_var_shift<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in {
defm rr : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2), OpcodeStr,
"$src2, $src1", "$src1, $src2",
@@ -4298,10 +4917,12 @@ multiclass avx512_var_shift<bits<8> opc, string OpcodeStr, SDNode OpNode,
(_.VT (bitconvert (_.LdFrag addr:$src2))))),
SSE_INTSHIFT_ITINS_P.rm>, AVX5128IBase, EVEX_4V,
EVEX_CD8<_.EltSize, CD8VF>;
+ }
}
multiclass avx512_var_shift_mb<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in
defm rmb : AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.ScalarMemOp:$src2), OpcodeStr,
"${src2}"##_.BroadcastStr##", $src1",
@@ -4375,9 +4996,6 @@ defm VPSLLV : avx512_var_shift_types<0x47, "vpsllv", shl>,
defm VPSRAV : avx512_var_shift_types<0x46, "vpsrav", sra>,
avx512_var_shift_w<0x11, "vpsravw", sra>,
avx512_var_shift_w_lowering<avx512vl_i16_info, sra>;
-let isCodeGenOnly = 1 in
- defm VPSRAV_Int : avx512_var_shift_types<0x46, "vpsrav", X86vsrav>,
- avx512_var_shift_w<0x11, "vpsravw", X86vsrav>;
defm VPSRLV : avx512_var_shift_types<0x45, "vpsrlv", srl>,
avx512_var_shift_w<0x10, "vpsrlvw", srl>,
@@ -4385,6 +5003,76 @@ defm VPSRLV : avx512_var_shift_types<0x45, "vpsrlv", srl>,
defm VPRORV : avx512_var_shift_types<0x14, "vprorv", rotr>;
defm VPROLV : avx512_var_shift_types<0x15, "vprolv", rotl>;
+// Special handing for handling VPSRAV intrinsics.
+multiclass avx512_var_shift_int_lowering<string InstrStr, X86VectorVTInfo _,
+ list<Predicate> p> {
+ let Predicates = p in {
+ def : Pat<(_.VT (X86vsrav _.RC:$src1, _.RC:$src2)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix#rr) _.RC:$src1,
+ _.RC:$src2)>;
+ def : Pat<(_.VT (X86vsrav _.RC:$src1, (bitconvert (_.LdFrag addr:$src2)))),
+ (!cast<Instruction>(InstrStr#_.ZSuffix##rm)
+ _.RC:$src1, addr:$src2)>;
+ let AddedComplexity = 20 in {
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (X86vsrav _.RC:$src1, _.RC:$src2), _.RC:$src0)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix#rrk) _.RC:$src0,
+ _.KRC:$mask, _.RC:$src1, _.RC:$src2)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (X86vsrav _.RC:$src1, (bitconvert (_.LdFrag addr:$src2))),
+ _.RC:$src0)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix##rmk) _.RC:$src0,
+ _.KRC:$mask, _.RC:$src1, addr:$src2)>;
+ }
+ let AddedComplexity = 30 in {
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (X86vsrav _.RC:$src1, _.RC:$src2), _.ImmAllZerosV)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix#rrkz) _.KRC:$mask,
+ _.RC:$src1, _.RC:$src2)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (X86vsrav _.RC:$src1, (bitconvert (_.LdFrag addr:$src2))),
+ _.ImmAllZerosV)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix##rmkz) _.KRC:$mask,
+ _.RC:$src1, addr:$src2)>;
+ }
+ }
+}
+
+multiclass avx512_var_shift_int_lowering_mb<string InstrStr, X86VectorVTInfo _,
+ list<Predicate> p> :
+ avx512_var_shift_int_lowering<InstrStr, _, p> {
+ let Predicates = p in {
+ def : Pat<(_.VT (X86vsrav _.RC:$src1,
+ (X86VBroadcast (_.ScalarLdFrag addr:$src2)))),
+ (!cast<Instruction>(InstrStr#_.ZSuffix##rmb)
+ _.RC:$src1, addr:$src2)>;
+ let AddedComplexity = 20 in
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (X86vsrav _.RC:$src1,
+ (X86VBroadcast (_.ScalarLdFrag addr:$src2))),
+ _.RC:$src0)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix##rmbk) _.RC:$src0,
+ _.KRC:$mask, _.RC:$src1, addr:$src2)>;
+ let AddedComplexity = 30 in
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (X86vsrav _.RC:$src1,
+ (X86VBroadcast (_.ScalarLdFrag addr:$src2))),
+ _.ImmAllZerosV)),
+ (!cast<Instruction>(InstrStr#_.ZSuffix##rmbkz) _.KRC:$mask,
+ _.RC:$src1, addr:$src2)>;
+ }
+}
+
+defm : avx512_var_shift_int_lowering<"VPSRAVW", v8i16x_info, [HasVLX, HasBWI]>;
+defm : avx512_var_shift_int_lowering<"VPSRAVW", v16i16x_info, [HasVLX, HasBWI]>;
+defm : avx512_var_shift_int_lowering<"VPSRAVW", v32i16_info, [HasBWI]>;
+defm : avx512_var_shift_int_lowering_mb<"VPSRAVD", v4i32x_info, [HasVLX]>;
+defm : avx512_var_shift_int_lowering_mb<"VPSRAVD", v8i32x_info, [HasVLX]>;
+defm : avx512_var_shift_int_lowering_mb<"VPSRAVD", v16i32_info, [HasAVX512]>;
+defm : avx512_var_shift_int_lowering_mb<"VPSRAVQ", v2i64x_info, [HasVLX]>;
+defm : avx512_var_shift_int_lowering_mb<"VPSRAVQ", v4i64x_info, [HasVLX]>;
+defm : avx512_var_shift_int_lowering_mb<"VPSRAVQ", v8i64_info, [HasAVX512]>;
+
//===-------------------------------------------------------------------===//
// 1-src variable permutation VPERMW/D/Q
//===-------------------------------------------------------------------===//
@@ -4501,8 +5189,10 @@ multiclass avx512_permil<string OpcodeStr, bits<8> OpcImm, bits<8> OpcVar,
EVEX, AVX512AIi8Base, EVEX_CD8<_.info128.EltSize, CD8VF>;
}
+let ExeDomain = SSEPackedSingle in
defm VPERMILPS : avx512_permil<"vpermilps", 0x04, 0x0C, avx512vl_f32_info,
avx512vl_i32_info>;
+let ExeDomain = SSEPackedDouble in
defm VPERMILPD : avx512_permil<"vpermilpd", 0x05, 0x0D, avx512vl_f64_info,
avx512vl_i64_info>, VEX_W;
//===----------------------------------------------------------------------===//
@@ -4666,61 +5356,71 @@ let Predicates = [HasAVX512] in {
// FMA - Fused Multiply Operations
//
-let Constraints = "$src1 = $dst" in {
multiclass avx512_fma3p_213_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, string Suff> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm r: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (OpNode _.RC:$src1, _.RC:$src2, _.RC:$src3))>,
+ (_.VT (OpNode _.RC:$src2, _.RC:$src1, _.RC:$src3)), 1, 1>,
AVX512FMA3Base;
defm m: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.MemOp:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (OpNode _.RC:$src1, _.RC:$src2, (_.LdFrag addr:$src3)))>,
+ (_.VT (OpNode _.RC:$src2, _.RC:$src1, (_.LdFrag addr:$src3))), 1, 0>,
AVX512FMA3Base;
defm mb: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.ScalarMemOp:$src3),
OpcodeStr, !strconcat("${src3}", _.BroadcastStr,", $src2"),
!strconcat("$src2, ${src3}", _.BroadcastStr ),
- (OpNode _.RC:$src1,
- _.RC:$src2,(_.VT (X86VBroadcast (_.ScalarLdFrag addr:$src3))))>,
+ (OpNode _.RC:$src2,
+ _.RC:$src1,(_.VT (X86VBroadcast (_.ScalarLdFrag addr:$src3)))), 1, 0>,
AVX512FMA3Base, EVEX_B;
+ }
+
+ // Additional pattern for folding broadcast nodes in other orders.
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (OpNode _.RC:$src1, _.RC:$src2,
+ (X86VBroadcast (_.ScalarLdFrag addr:$src3))),
+ _.RC:$src1)),
+ (!cast<Instruction>(NAME#Suff#_.ZSuffix#mbk) _.RC:$src1,
+ _.KRCWM:$mask, _.RC:$src2, addr:$src3)>;
}
multiclass avx512_fma3_213_round<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, string Suff> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in
defm rb: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, AVX512RC:$rc),
OpcodeStr, "$rc, $src3, $src2", "$src2, $src3, $rc",
- (_.VT ( OpNode _.RC:$src1, _.RC:$src2, _.RC:$src3, (i32 imm:$rc)))>,
+ (_.VT ( OpNode _.RC:$src2, _.RC:$src1, _.RC:$src3, (i32 imm:$rc))), 1, 1>,
AVX512FMA3Base, EVEX_B, EVEX_RC;
}
-} // Constraints = "$src1 = $dst"
multiclass avx512_fma3p_213_common<bits<8> opc, string OpcodeStr, SDNode OpNode,
- SDNode OpNodeRnd, AVX512VLVectorVTInfo _> {
+ SDNode OpNodeRnd, AVX512VLVectorVTInfo _,
+ string Suff> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_fma3p_213_rm<opc, OpcodeStr, OpNode, _.info512>,
- avx512_fma3_213_round<opc, OpcodeStr, OpNodeRnd, _.info512>,
- EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>;
+ defm Z : avx512_fma3p_213_rm<opc, OpcodeStr, OpNode, _.info512, Suff>,
+ avx512_fma3_213_round<opc, OpcodeStr, OpNodeRnd, _.info512,
+ Suff>, EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>;
}
let Predicates = [HasVLX, HasAVX512] in {
- defm Z256 : avx512_fma3p_213_rm<opc, OpcodeStr, OpNode, _.info256>,
+ defm Z256 : avx512_fma3p_213_rm<opc, OpcodeStr, OpNode, _.info256, Suff>,
EVEX_V256, EVEX_CD8<_.info256.EltSize, CD8VF>;
- defm Z128 : avx512_fma3p_213_rm<opc, OpcodeStr, OpNode, _.info128>,
+ defm Z128 : avx512_fma3p_213_rm<opc, OpcodeStr, OpNode, _.info128, Suff>,
EVEX_V128, EVEX_CD8<_.info128.EltSize, CD8VF>;
}
}
multiclass avx512_fma3p_213_f<bits<8> opc, string OpcodeStr, SDNode OpNode,
- SDNode OpNodeRnd > {
+ SDNode OpNodeRnd > {
defm PS : avx512_fma3p_213_common<opc, OpcodeStr#"ps", OpNode, OpNodeRnd,
- avx512vl_f32_info>;
+ avx512vl_f32_info, "PS">;
defm PD : avx512_fma3p_213_common<opc, OpcodeStr#"pd", OpNode, OpNodeRnd,
- avx512vl_f64_info>, VEX_W;
+ avx512vl_f64_info, "PD">, VEX_W;
}
defm VFMADD213 : avx512_fma3p_213_f<0xA8, "vfmadd213", X86Fmadd, X86FmaddRnd>;
@@ -4731,19 +5431,19 @@ defm VFNMADD213 : avx512_fma3p_213_f<0xAC, "vfnmadd213", X86Fnmadd, X86FnmaddR
defm VFNMSUB213 : avx512_fma3p_213_f<0xAE, "vfnmsub213", X86Fnmsub, X86FnmsubRnd>;
-let Constraints = "$src1 = $dst" in {
multiclass avx512_fma3p_231_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, string Suff> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm r: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (OpNode _.RC:$src2, _.RC:$src3, _.RC:$src1))>,
+ (_.VT (OpNode _.RC:$src2, _.RC:$src3, _.RC:$src1)), 1, 1>,
AVX512FMA3Base;
defm m: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.MemOp:$src3),
OpcodeStr, "$src3, $src2", "$src2, $src3",
- (_.VT (OpNode _.RC:$src2, (_.LdFrag addr:$src3), _.RC:$src1))>,
+ (_.VT (OpNode _.RC:$src2, (_.LdFrag addr:$src3), _.RC:$src1)), 1, 0>,
AVX512FMA3Base;
defm mb: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
@@ -4752,40 +5452,60 @@ multiclass avx512_fma3p_231_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
"$src2, ${src3}"##_.BroadcastStr,
(_.VT (OpNode _.RC:$src2,
(_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src3))),
- _.RC:$src1))>, AVX512FMA3Base, EVEX_B;
+ _.RC:$src1)), 1, 0>, AVX512FMA3Base, EVEX_B;
+ }
+
+ // Additional patterns for folding broadcast nodes in other orders.
+ def : Pat<(_.VT (OpNode (X86VBroadcast (_.ScalarLdFrag addr:$src3)),
+ _.RC:$src2, _.RC:$src1)),
+ (!cast<Instruction>(NAME#Suff#_.ZSuffix#mb) _.RC:$src1,
+ _.RC:$src2, addr:$src3)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (OpNode (X86VBroadcast (_.ScalarLdFrag addr:$src3)),
+ _.RC:$src2, _.RC:$src1),
+ _.RC:$src1)),
+ (!cast<Instruction>(NAME#Suff#_.ZSuffix#mbk) _.RC:$src1,
+ _.KRCWM:$mask, _.RC:$src2, addr:$src3)>;
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (OpNode (X86VBroadcast (_.ScalarLdFrag addr:$src3)),
+ _.RC:$src2, _.RC:$src1),
+ _.ImmAllZerosV)),
+ (!cast<Instruction>(NAME#Suff#_.ZSuffix#mbkz) _.RC:$src1,
+ _.KRCWM:$mask, _.RC:$src2, addr:$src3)>;
}
multiclass avx512_fma3_231_round<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, string Suff> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in
defm rb: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, AVX512RC:$rc),
OpcodeStr, "$rc, $src3, $src2", "$src2, $src3, $rc",
- (_.VT ( OpNode _.RC:$src2, _.RC:$src3, _.RC:$src1, (i32 imm:$rc)))>,
+ (_.VT ( OpNode _.RC:$src2, _.RC:$src3, _.RC:$src1, (i32 imm:$rc))), 1, 1>,
AVX512FMA3Base, EVEX_B, EVEX_RC;
}
-} // Constraints = "$src1 = $dst"
multiclass avx512_fma3p_231_common<bits<8> opc, string OpcodeStr, SDNode OpNode,
- SDNode OpNodeRnd, AVX512VLVectorVTInfo _> {
+ SDNode OpNodeRnd, AVX512VLVectorVTInfo _,
+ string Suff> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_fma3p_231_rm<opc, OpcodeStr, OpNode, _.info512>,
- avx512_fma3_231_round<opc, OpcodeStr, OpNodeRnd, _.info512>,
- EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>;
+ defm Z : avx512_fma3p_231_rm<opc, OpcodeStr, OpNode, _.info512, Suff>,
+ avx512_fma3_231_round<opc, OpcodeStr, OpNodeRnd, _.info512,
+ Suff>, EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>;
}
let Predicates = [HasVLX, HasAVX512] in {
- defm Z256 : avx512_fma3p_231_rm<opc, OpcodeStr, OpNode, _.info256>,
+ defm Z256 : avx512_fma3p_231_rm<opc, OpcodeStr, OpNode, _.info256, Suff>,
EVEX_V256, EVEX_CD8<_.info256.EltSize, CD8VF>;
- defm Z128 : avx512_fma3p_231_rm<opc, OpcodeStr, OpNode, _.info128>,
+ defm Z128 : avx512_fma3p_231_rm<opc, OpcodeStr, OpNode, _.info128, Suff>,
EVEX_V128, EVEX_CD8<_.info128.EltSize, CD8VF>;
}
}
multiclass avx512_fma3p_231_f<bits<8> opc, string OpcodeStr, SDNode OpNode,
- SDNode OpNodeRnd > {
+ SDNode OpNodeRnd > {
defm PS : avx512_fma3p_231_common<opc, OpcodeStr#"ps", OpNode, OpNodeRnd,
- avx512vl_f32_info>;
+ avx512vl_f32_info, "PS">;
defm PD : avx512_fma3p_231_common<opc, OpcodeStr#"pd", OpNode, OpNodeRnd,
- avx512vl_f64_info>, VEX_W;
+ avx512vl_f64_info, "PD">, VEX_W;
}
defm VFMADD231 : avx512_fma3p_231_f<0xB8, "vfmadd231", X86Fmadd, X86FmaddRnd>;
@@ -4795,61 +5515,71 @@ defm VFMSUBADD231 : avx512_fma3p_231_f<0xB7, "vfmsubadd231", X86Fmsubadd, X86Fms
defm VFNMADD231 : avx512_fma3p_231_f<0xBC, "vfnmadd231", X86Fnmadd, X86FnmaddRnd>;
defm VFNMSUB231 : avx512_fma3p_231_f<0xBE, "vfnmsub231", X86Fnmsub, X86FnmsubRnd>;
-let Constraints = "$src1 = $dst" in {
multiclass avx512_fma3p_132_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, string Suff> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm r: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
- (ins _.RC:$src3, _.RC:$src2),
- OpcodeStr, "$src2, $src3", "$src3, $src2",
- (_.VT (OpNode _.RC:$src1, _.RC:$src2, _.RC:$src3))>,
+ (ins _.RC:$src2, _.RC:$src3),
+ OpcodeStr, "$src3, $src2", "$src2, $src3",
+ (_.VT (OpNode _.RC:$src1, _.RC:$src3, _.RC:$src2)), 1, 1>,
AVX512FMA3Base;
defm m: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
- (ins _.RC:$src3, _.MemOp:$src2),
- OpcodeStr, "$src2, $src3", "$src3, $src2",
- (_.VT (OpNode _.RC:$src1, (_.LdFrag addr:$src2), _.RC:$src3))>,
+ (ins _.RC:$src2, _.MemOp:$src3),
+ OpcodeStr, "$src3, $src2", "$src2, $src3",
+ (_.VT (OpNode _.RC:$src1, (_.LdFrag addr:$src3), _.RC:$src2)), 1, 0>,
AVX512FMA3Base;
defm mb: AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
- (ins _.RC:$src3, _.ScalarMemOp:$src2),
- OpcodeStr, "${src2}"##_.BroadcastStr##", $src3",
- "$src3, ${src2}"##_.BroadcastStr,
+ (ins _.RC:$src2, _.ScalarMemOp:$src3),
+ OpcodeStr, "${src3}"##_.BroadcastStr##", $src2",
+ "$src2, ${src3}"##_.BroadcastStr,
(_.VT (OpNode _.RC:$src1,
- (_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src2))),
- _.RC:$src3))>, AVX512FMA3Base, EVEX_B;
+ (_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src3))),
+ _.RC:$src2)), 1, 0>, AVX512FMA3Base, EVEX_B;
+ }
+
+ // Additional patterns for folding broadcast nodes in other orders.
+ def : Pat<(_.VT (vselect _.KRCWM:$mask,
+ (OpNode (X86VBroadcast (_.ScalarLdFrag addr:$src3)),
+ _.RC:$src1, _.RC:$src2),
+ _.RC:$src1)),
+ (!cast<Instruction>(NAME#Suff#_.ZSuffix#mbk) _.RC:$src1,
+ _.KRCWM:$mask, _.RC:$src2, addr:$src3)>;
}
multiclass avx512_fma3_132_round<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
+ X86VectorVTInfo _, string Suff> {
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in
defm rb: AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
- (ins _.RC:$src3, _.RC:$src2, AVX512RC:$rc),
- OpcodeStr, "$rc, $src2, $src3", "$src3, $src2, $rc",
- (_.VT ( OpNode _.RC:$src1, _.RC:$src2, _.RC:$src3, (i32 imm:$rc)))>,
+ (ins _.RC:$src2, _.RC:$src3, AVX512RC:$rc),
+ OpcodeStr, "$rc, $src3, $src2", "$src2, $src3, $rc",
+ (_.VT ( OpNode _.RC:$src1, _.RC:$src3, _.RC:$src2, (i32 imm:$rc))), 1, 1>,
AVX512FMA3Base, EVEX_B, EVEX_RC;
}
-} // Constraints = "$src1 = $dst"
multiclass avx512_fma3p_132_common<bits<8> opc, string OpcodeStr, SDNode OpNode,
- SDNode OpNodeRnd, AVX512VLVectorVTInfo _> {
+ SDNode OpNodeRnd, AVX512VLVectorVTInfo _,
+ string Suff> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_fma3p_132_rm<opc, OpcodeStr, OpNode, _.info512>,
- avx512_fma3_132_round<opc, OpcodeStr, OpNodeRnd, _.info512>,
- EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>;
+ defm Z : avx512_fma3p_132_rm<opc, OpcodeStr, OpNode, _.info512, Suff>,
+ avx512_fma3_132_round<opc, OpcodeStr, OpNodeRnd, _.info512,
+ Suff>, EVEX_V512, EVEX_CD8<_.info512.EltSize, CD8VF>;
}
let Predicates = [HasVLX, HasAVX512] in {
- defm Z256 : avx512_fma3p_132_rm<opc, OpcodeStr, OpNode, _.info256>,
+ defm Z256 : avx512_fma3p_132_rm<opc, OpcodeStr, OpNode, _.info256, Suff>,
EVEX_V256, EVEX_CD8<_.info256.EltSize, CD8VF>;
- defm Z128 : avx512_fma3p_132_rm<opc, OpcodeStr, OpNode, _.info128>,
+ defm Z128 : avx512_fma3p_132_rm<opc, OpcodeStr, OpNode, _.info128, Suff>,
EVEX_V128, EVEX_CD8<_.info128.EltSize, CD8VF>;
}
}
multiclass avx512_fma3p_132_f<bits<8> opc, string OpcodeStr, SDNode OpNode,
- SDNode OpNodeRnd > {
+ SDNode OpNodeRnd > {
defm PS : avx512_fma3p_132_common<opc, OpcodeStr#"ps", OpNode, OpNodeRnd,
- avx512vl_f32_info>;
+ avx512vl_f32_info, "PS">;
defm PD : avx512_fma3p_132_common<opc, OpcodeStr#"pd", OpNode, OpNodeRnd,
- avx512vl_f64_info>, VEX_W;
+ avx512vl_f64_info, "PD">, VEX_W;
}
defm VFMADD132 : avx512_fma3p_132_f<0x98, "vfmadd132", X86Fmadd, X86FmaddRnd>;
@@ -4866,18 +5596,18 @@ multiclass avx512_fma3s_common<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
dag RHS_r, dag RHS_m > {
defm r_Int: AVX512_maskable_3src_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3), OpcodeStr,
- "$src3, $src2", "$src2, $src3", RHS_VEC_r>, AVX512FMA3Base;
+ "$src3, $src2", "$src2, $src3", RHS_VEC_r, 1, 1>, AVX512FMA3Base;
defm m_Int: AVX512_maskable_3src_scalar<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.ScalarMemOp:$src3), OpcodeStr,
- "$src3, $src2", "$src2, $src3", RHS_VEC_m>, AVX512FMA3Base;
+ "$src3, $src2", "$src2, $src3", RHS_VEC_m, 1, 1>, AVX512FMA3Base;
defm rb_Int: AVX512_maskable_3src_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, AVX512RC:$rc),
- OpcodeStr, "$rc, $src3, $src2", "$src2, $src3, $rc", RHS_VEC_rb>,
+ OpcodeStr, "$rc, $src3, $src2", "$src2, $src3, $rc", RHS_VEC_rb, 1, 1>,
AVX512FMA3Base, EVEX_B, EVEX_RC;
- let isCodeGenOnly = 1 in {
+ let isCodeGenOnly = 1, isCommutable = 1 in {
def r : AVX512FMA3<opc, MRMSrcReg, (outs _.FRC:$dst),
(ins _.FRC:$src1, _.FRC:$src2, _.FRC:$src3),
!strconcat(OpcodeStr,
@@ -4893,38 +5623,40 @@ multiclass avx512_fma3s_common<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
}// Constraints = "$src1 = $dst"
multiclass avx512_fma3s_all<bits<8> opc213, bits<8> opc231, bits<8> opc132,
- string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd, X86VectorVTInfo _ ,
- string SUFF> {
-
- defm NAME#213#SUFF: avx512_fma3s_common<opc213, OpcodeStr#"213"#_.Suffix , _ ,
- (_.VT (OpNodeRnd _.RC:$src2, _.RC:$src1, _.RC:$src3, (i32 FROUND_CURRENT))),
- (_.VT (OpNodeRnd _.RC:$src2, _.RC:$src1,
+ string OpcodeStr, SDNode OpNode, SDNode OpNodeRnds1,
+ SDNode OpNodeRnds3, X86VectorVTInfo _ , string SUFF> {
+
+ defm NAME#213#SUFF#Z: avx512_fma3s_common<opc213, OpcodeStr#"213"#_.Suffix , _ ,
+ // Operands for intrinsic are in 123 order to preserve passthu
+ // semantics.
+ (_.VT (OpNodeRnds1 _.RC:$src1, _.RC:$src2, _.RC:$src3, (i32 FROUND_CURRENT))),
+ (_.VT (OpNodeRnds1 _.RC:$src1, _.RC:$src2,
(_.VT (scalar_to_vector(_.ScalarLdFrag addr:$src3))), (i32 FROUND_CURRENT))),
- (_.VT ( OpNodeRnd _.RC:$src2, _.RC:$src1, _.RC:$src3,
+ (_.VT (OpNodeRnds1 _.RC:$src1, _.RC:$src2, _.RC:$src3,
(i32 imm:$rc))),
(set _.FRC:$dst, (_.EltVT (OpNode _.FRC:$src2, _.FRC:$src1,
_.FRC:$src3))),
(set _.FRC:$dst, (_.EltVT (OpNode _.FRC:$src2, _.FRC:$src1,
(_.ScalarLdFrag addr:$src3))))>;
- defm NAME#231#SUFF: avx512_fma3s_common<opc231, OpcodeStr#"231"#_.Suffix , _ ,
- (_.VT (OpNodeRnd _.RC:$src2, _.RC:$src3, _.RC:$src1, (i32 FROUND_CURRENT))),
- (_.VT (OpNodeRnd _.RC:$src2,
+ defm NAME#231#SUFF#Z: avx512_fma3s_common<opc231, OpcodeStr#"231"#_.Suffix , _ ,
+ (_.VT (OpNodeRnds3 _.RC:$src2, _.RC:$src3, _.RC:$src1, (i32 FROUND_CURRENT))),
+ (_.VT (OpNodeRnds3 _.RC:$src2,
(_.VT (scalar_to_vector(_.ScalarLdFrag addr:$src3))),
_.RC:$src1, (i32 FROUND_CURRENT))),
- (_.VT ( OpNodeRnd _.RC:$src2, _.RC:$src3, _.RC:$src1,
+ (_.VT ( OpNodeRnds3 _.RC:$src2, _.RC:$src3, _.RC:$src1,
(i32 imm:$rc))),
(set _.FRC:$dst, (_.EltVT (OpNode _.FRC:$src2, _.FRC:$src3,
_.FRC:$src1))),
(set _.FRC:$dst, (_.EltVT (OpNode _.FRC:$src2,
(_.ScalarLdFrag addr:$src3), _.FRC:$src1)))>;
- defm NAME#132#SUFF: avx512_fma3s_common<opc132, OpcodeStr#"132"#_.Suffix , _ ,
- (_.VT (OpNodeRnd _.RC:$src1, _.RC:$src3, _.RC:$src2, (i32 FROUND_CURRENT))),
- (_.VT (OpNodeRnd _.RC:$src1,
+ defm NAME#132#SUFF#Z: avx512_fma3s_common<opc132, OpcodeStr#"132"#_.Suffix , _ ,
+ (_.VT (OpNodeRnds1 _.RC:$src1, _.RC:$src3, _.RC:$src2, (i32 FROUND_CURRENT))),
+ (_.VT (OpNodeRnds1 _.RC:$src1,
(_.VT (scalar_to_vector(_.ScalarLdFrag addr:$src3))),
_.RC:$src2, (i32 FROUND_CURRENT))),
- (_.VT ( OpNodeRnd _.RC:$src1, _.RC:$src3, _.RC:$src2,
+ (_.VT (OpNodeRnds1 _.RC:$src1, _.RC:$src3, _.RC:$src2,
(i32 imm:$rc))),
(set _.FRC:$dst, (_.EltVT (OpNode _.FRC:$src1, _.FRC:$src3,
_.FRC:$src2))),
@@ -4933,21 +5665,26 @@ multiclass avx512_fma3s_all<bits<8> opc213, bits<8> opc231, bits<8> opc132,
}
multiclass avx512_fma3s<bits<8> opc213, bits<8> opc231, bits<8> opc132,
- string OpcodeStr, SDNode OpNode, SDNode OpNodeRnd>{
+ string OpcodeStr, SDNode OpNode, SDNode OpNodeRnds1,
+ SDNode OpNodeRnds3> {
let Predicates = [HasAVX512] in {
defm NAME : avx512_fma3s_all<opc213, opc231, opc132, OpcodeStr, OpNode,
- OpNodeRnd, f32x_info, "SS">,
- EVEX_CD8<32, CD8VT1>, VEX_LIG;
+ OpNodeRnds1, OpNodeRnds3, f32x_info, "SS">,
+ EVEX_CD8<32, CD8VT1>, VEX_LIG;
defm NAME : avx512_fma3s_all<opc213, opc231, opc132, OpcodeStr, OpNode,
- OpNodeRnd, f64x_info, "SD">,
- EVEX_CD8<64, CD8VT1>, VEX_LIG, VEX_W;
+ OpNodeRnds1, OpNodeRnds3, f64x_info, "SD">,
+ EVEX_CD8<64, CD8VT1>, VEX_LIG, VEX_W;
}
}
-defm VFMADD : avx512_fma3s<0xA9, 0xB9, 0x99, "vfmadd", X86Fmadd, X86FmaddRnd>;
-defm VFMSUB : avx512_fma3s<0xAB, 0xBB, 0x9B, "vfmsub", X86Fmsub, X86FmsubRnd>;
-defm VFNMADD : avx512_fma3s<0xAD, 0xBD, 0x9D, "vfnmadd", X86Fnmadd, X86FnmaddRnd>;
-defm VFNMSUB : avx512_fma3s<0xAF, 0xBF, 0x9F, "vfnmsub", X86Fnmsub, X86FnmsubRnd>;
+defm VFMADD : avx512_fma3s<0xA9, 0xB9, 0x99, "vfmadd", X86Fmadd, X86FmaddRnds1,
+ X86FmaddRnds3>;
+defm VFMSUB : avx512_fma3s<0xAB, 0xBB, 0x9B, "vfmsub", X86Fmsub, X86FmsubRnds1,
+ X86FmsubRnds3>;
+defm VFNMADD : avx512_fma3s<0xAD, 0xBD, 0x9D, "vfnmadd", X86Fnmadd,
+ X86FnmaddRnds1, X86FnmaddRnds3>;
+defm VFNMSUB : avx512_fma3s<0xAF, 0xBF, 0x9F, "vfnmsub", X86Fnmsub,
+ X86FnmsubRnds1, X86FnmsubRnds3>;
//===----------------------------------------------------------------------===//
// AVX-512 Packed Multiply of Unsigned 52-bit Integers and Add the Low 52-bit IFMA
@@ -5067,6 +5804,11 @@ defm VCVTSI642SDZ: avx512_vcvtsi_common<0x2A, X86SintToFpRnd, GR64,
v2f64x_info, i64mem, loadi64, "cvtsi2sd{q}">,
XD, VEX_W, EVEX_CD8<64, CD8VT1>;
+def : InstAlias<"vcvtsi2ss\t{$src, $src1, $dst|$dst, $src1, $src}",
+ (VCVTSI2SSZrm FR64X:$dst, FR64X:$src1, i32mem:$src), 0>;
+def : InstAlias<"vcvtsi2sd\t{$src, $src1, $dst|$dst, $src1, $src}",
+ (VCVTSI2SDZrm FR64X:$dst, FR64X:$src1, i32mem:$src), 0>;
+
def : Pat<(f32 (sint_to_fp (loadi32 addr:$src))),
(VCVTSI2SSZrm (f32 (IMPLICIT_DEF)), addr:$src)>;
def : Pat<(f32 (sint_to_fp (loadi64 addr:$src))),
@@ -5098,6 +5840,11 @@ defm VCVTUSI642SDZ : avx512_vcvtsi_common<0x7B, X86UintToFpRnd, GR64,
v2f64x_info, i64mem, loadi64, "cvtusi2sd{q}">,
XD, VEX_W, EVEX_CD8<64, CD8VT1>;
+def : InstAlias<"vcvtusi2ss\t{$src, $src1, $dst|$dst, $src1, $src}",
+ (VCVTUSI2SSZrm FR64X:$dst, FR64X:$src1, i32mem:$src), 0>;
+def : InstAlias<"vcvtusi2sd\t{$src, $src1, $dst|$dst, $src1, $src}",
+ (VCVTUSI2SDZrm FR64X:$dst, FR64X:$src1, i32mem:$src), 0>;
+
def : Pat<(f32 (uint_to_fp (loadi32 addr:$src))),
(VCVTUSI2SSZrm (f32 (IMPLICIT_DEF)), addr:$src)>;
def : Pat<(f32 (uint_to_fp (loadi64 addr:$src))),
@@ -5170,106 +5917,158 @@ defm VCVTSD2USI64Z: avx512_cvt_s_int_round<0x79, f64x_info, i64x_info,
// Therefore, the SSE intrinsics are mapped to the AVX512 instructions.
let Predicates = [HasAVX512] in {
def : Pat<(i32 (int_x86_sse_cvtss2si (v4f32 VR128X:$src))),
- (VCVTSS2SIZrr (COPY_TO_REGCLASS VR128X:$src, FR32X))>;
+ (VCVTSS2SIZrr VR128X:$src)>;
+ def : Pat<(i32 (int_x86_sse_cvtss2si (sse_load_f32 addr:$src))),
+ (VCVTSS2SIZrm addr:$src)>;
def : Pat<(i64 (int_x86_sse_cvtss2si64 (v4f32 VR128X:$src))),
- (VCVTSS2SI64Zrr (COPY_TO_REGCLASS VR128X:$src, FR32X))>;
+ (VCVTSS2SI64Zrr VR128X:$src)>;
+ def : Pat<(i64 (int_x86_sse_cvtss2si64 (sse_load_f32 addr:$src))),
+ (VCVTSS2SI64Zrm addr:$src)>;
def : Pat<(i32 (int_x86_sse2_cvtsd2si (v2f64 VR128X:$src))),
- (VCVTSD2SIZrr (COPY_TO_REGCLASS VR128X:$src, FR64X))>;
+ (VCVTSD2SIZrr VR128X:$src)>;
+ def : Pat<(i32 (int_x86_sse2_cvtsd2si (sse_load_f64 addr:$src))),
+ (VCVTSD2SIZrm addr:$src)>;
def : Pat<(i64 (int_x86_sse2_cvtsd2si64 (v2f64 VR128X:$src))),
- (VCVTSD2SI64Zrr (COPY_TO_REGCLASS VR128X:$src, FR64X))>;
+ (VCVTSD2SI64Zrr VR128X:$src)>;
+ def : Pat<(i64 (int_x86_sse2_cvtsd2si64 (sse_load_f64 addr:$src))),
+ (VCVTSD2SI64Zrm addr:$src)>;
} // HasAVX512
-let isCodeGenOnly = 1 , Predicates = [HasAVX512] in {
- defm Int_VCVTSI2SSZ : sse12_cvt_sint_3addr<0x2A, GR32, VR128X,
- int_x86_sse_cvtsi2ss, i32mem, loadi32, "cvtsi2ss{l}",
- SSE_CVT_Scalar, 0>, XS, EVEX_4V;
- defm Int_VCVTSI2SS64Z : sse12_cvt_sint_3addr<0x2A, GR64, VR128X,
- int_x86_sse_cvtsi642ss, i64mem, loadi64, "cvtsi2ss{q}",
- SSE_CVT_Scalar, 0>, XS, EVEX_4V, VEX_W;
- defm Int_VCVTSI2SDZ : sse12_cvt_sint_3addr<0x2A, GR32, VR128X,
- int_x86_sse2_cvtsi2sd, i32mem, loadi32, "cvtsi2sd{l}",
- SSE_CVT_Scalar, 0>, XD, EVEX_4V;
- defm Int_VCVTSI2SD64Z : sse12_cvt_sint_3addr<0x2A, GR64, VR128X,
- int_x86_sse2_cvtsi642sd, i64mem, loadi64, "cvtsi2sd{q}",
- SSE_CVT_Scalar, 0>, XD, EVEX_4V, VEX_W;
-
- defm Int_VCVTUSI2SDZ : sse12_cvt_sint_3addr<0x7B, GR32, VR128X,
- int_x86_avx512_cvtusi2sd, i32mem, loadi32, "cvtusi2sd{l}",
- SSE_CVT_Scalar, 0>, XD, EVEX_4V;
-} // isCodeGenOnly = 1, Predicates = [HasAVX512]
+let Predicates = [HasAVX512] in {
+ def : Pat<(int_x86_sse_cvtsi2ss VR128X:$src1, GR32:$src2),
+ (VCVTSI2SSZrr_Int VR128X:$src1, GR32:$src2)>;
+ def : Pat<(int_x86_sse_cvtsi2ss VR128X:$src1, (loadi32 addr:$src2)),
+ (VCVTSI2SSZrm_Int VR128X:$src1, addr:$src2)>;
+ def : Pat<(int_x86_sse_cvtsi642ss VR128X:$src1, GR64:$src2),
+ (VCVTSI642SSZrr_Int VR128X:$src1, GR64:$src2)>;
+ def : Pat<(int_x86_sse_cvtsi642ss VR128X:$src1, (loadi64 addr:$src2)),
+ (VCVTSI642SSZrm_Int VR128X:$src1, addr:$src2)>;
+ def : Pat<(int_x86_sse2_cvtsi2sd VR128X:$src1, GR32:$src2),
+ (VCVTSI2SDZrr_Int VR128X:$src1, GR32:$src2)>;
+ def : Pat<(int_x86_sse2_cvtsi2sd VR128X:$src1, (loadi32 addr:$src2)),
+ (VCVTSI2SDZrm_Int VR128X:$src1, addr:$src2)>;
+ def : Pat<(int_x86_sse2_cvtsi642sd VR128X:$src1, GR64:$src2),
+ (VCVTSI642SDZrr_Int VR128X:$src1, GR64:$src2)>;
+ def : Pat<(int_x86_sse2_cvtsi642sd VR128X:$src1, (loadi64 addr:$src2)),
+ (VCVTSI642SDZrm_Int VR128X:$src1, addr:$src2)>;
+ def : Pat<(int_x86_avx512_cvtusi2sd VR128X:$src1, GR32:$src2),
+ (VCVTUSI2SDZrr_Int VR128X:$src1, GR32:$src2)>;
+ def : Pat<(int_x86_avx512_cvtusi2sd VR128X:$src1, (loadi32 addr:$src2)),
+ (VCVTUSI2SDZrm_Int VR128X:$src1, addr:$src2)>;
+} // Predicates = [HasAVX512]
+
+// Patterns used for matching vcvtsi2s{s,d} intrinsic sequences from clang
+// which produce unnecessary vmovs{s,d} instructions
+let Predicates = [HasAVX512] in {
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128X:$dst),
+ (v4f32 (scalar_to_vector (f32 (sint_to_fp GR64:$src)))))),
+ (VCVTSI642SSZrr_Int VR128X:$dst, GR64:$src)>;
+
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128X:$dst),
+ (v4f32 (scalar_to_vector (f32 (sint_to_fp GR32:$src)))))),
+ (VCVTSI2SSZrr_Int VR128X:$dst, GR32:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128X:$dst),
+ (v2f64 (scalar_to_vector (f64 (sint_to_fp GR64:$src)))))),
+ (VCVTSI642SDZrr_Int VR128X:$dst, GR64:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128X:$dst),
+ (v2f64 (scalar_to_vector (f64 (sint_to_fp GR32:$src)))))),
+ (VCVTSI2SDZrr_Int VR128X:$dst, GR32:$src)>;
+} // Predicates = [HasAVX512]
// Convert float/double to signed/unsigned int 32/64 with truncation
multiclass avx512_cvt_s_all<bits<8> opc, string asm, X86VectorVTInfo _SrcRC,
X86VectorVTInfo _DstRC, SDNode OpNode,
- SDNode OpNodeRnd>{
+ SDNode OpNodeRnd, string aliasStr>{
let Predicates = [HasAVX512] in {
- def rr : SI<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.FRC:$src),
+ def rr : AVX512<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.FRC:$src),
!strconcat(asm,"\t{$src, $dst|$dst, $src}"),
[(set _DstRC.RC:$dst, (OpNode _SrcRC.FRC:$src))]>, EVEX;
- def rb : SI<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.FRC:$src),
+ let hasSideEffects = 0 in
+ def rb : AVX512<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.FRC:$src),
!strconcat(asm,"\t{{sae}, $src, $dst|$dst, $src, {sae}}"),
[]>, EVEX, EVEX_B;
- def rm : SI<opc, MRMSrcMem, (outs _DstRC.RC:$dst), (ins _SrcRC.ScalarMemOp:$src),
+ def rm : AVX512<opc, MRMSrcMem, (outs _DstRC.RC:$dst), (ins _SrcRC.ScalarMemOp:$src),
!strconcat(asm,"\t{$src, $dst|$dst, $src}"),
[(set _DstRC.RC:$dst, (OpNode (_SrcRC.ScalarLdFrag addr:$src)))]>,
EVEX;
+ def : InstAlias<asm # aliasStr # "\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "rr") _DstRC.RC:$dst, _SrcRC.FRC:$src), 0>;
+ def : InstAlias<asm # aliasStr # "\t\t{{sae}, $src, $dst|$dst, $src, {sae}}",
+ (!cast<Instruction>(NAME # "rb") _DstRC.RC:$dst, _SrcRC.FRC:$src), 0>;
+ def : InstAlias<asm # aliasStr # "\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "rm") _DstRC.RC:$dst,
+ _SrcRC.ScalarMemOp:$src), 0>;
+
let isCodeGenOnly = 1 in {
- def rr_Int : SI<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.RC:$src),
- !strconcat(asm,"\t{$src, $dst|$dst, $src}"),
- [(set _DstRC.RC:$dst, (OpNodeRnd (_SrcRC.VT _SrcRC.RC:$src),
- (i32 FROUND_CURRENT)))]>, EVEX, VEX_LIG;
- def rb_Int : SI<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.RC:$src),
- !strconcat(asm,"\t{{sae}, $src, $dst|$dst, $src, {sae}}"),
- [(set _DstRC.RC:$dst, (OpNodeRnd (_SrcRC.VT _SrcRC.RC:$src),
- (i32 FROUND_NO_EXC)))]>,
- EVEX,VEX_LIG , EVEX_B;
- let mayLoad = 1, hasSideEffects = 0 in
- def rm_Int : SI<opc, MRMSrcMem, (outs _DstRC.RC:$dst),
- (ins _SrcRC.MemOp:$src),
- !strconcat(asm,"\t{$src, $dst|$dst, $src}"),
- []>, EVEX, VEX_LIG;
+ def rr_Int : AVX512<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.RC:$src),
+ !strconcat(asm,"\t{$src, $dst|$dst, $src}"),
+ [(set _DstRC.RC:$dst, (OpNodeRnd (_SrcRC.VT _SrcRC.RC:$src),
+ (i32 FROUND_CURRENT)))]>, EVEX, VEX_LIG;
+ def rb_Int : AVX512<opc, MRMSrcReg, (outs _DstRC.RC:$dst), (ins _SrcRC.RC:$src),
+ !strconcat(asm,"\t{{sae}, $src, $dst|$dst, $src, {sae}}"),
+ [(set _DstRC.RC:$dst, (OpNodeRnd (_SrcRC.VT _SrcRC.RC:$src),
+ (i32 FROUND_NO_EXC)))]>,
+ EVEX,VEX_LIG , EVEX_B;
+ let mayLoad = 1, hasSideEffects = 0 in
+ def rm_Int : AVX512<opc, MRMSrcMem, (outs _DstRC.RC:$dst),
+ (ins _SrcRC.MemOp:$src),
+ !strconcat(asm,"\t{$src, $dst|$dst, $src}"),
+ []>, EVEX, VEX_LIG;
} // isCodeGenOnly = 1
} //HasAVX512
}
-defm VCVTTSS2SIZ: avx512_cvt_s_all<0x2C, "cvttss2si", f32x_info, i32x_info,
- fp_to_sint,X86cvtts2IntRnd>,
+defm VCVTTSS2SIZ: avx512_cvt_s_all<0x2C, "vcvttss2si", f32x_info, i32x_info,
+ fp_to_sint, X86cvtts2IntRnd, "{l}">,
XS, EVEX_CD8<32, CD8VT1>;
-defm VCVTTSS2SI64Z: avx512_cvt_s_all<0x2C, "cvttss2si", f32x_info, i64x_info,
- fp_to_sint,X86cvtts2IntRnd>,
+defm VCVTTSS2SI64Z: avx512_cvt_s_all<0x2C, "vcvttss2si", f32x_info, i64x_info,
+ fp_to_sint, X86cvtts2IntRnd, "{q}">,
VEX_W, XS, EVEX_CD8<32, CD8VT1>;
-defm VCVTTSD2SIZ: avx512_cvt_s_all<0x2C, "cvttsd2si", f64x_info, i32x_info,
- fp_to_sint,X86cvtts2IntRnd>,
+defm VCVTTSD2SIZ: avx512_cvt_s_all<0x2C, "vcvttsd2si", f64x_info, i32x_info,
+ fp_to_sint, X86cvtts2IntRnd, "{l}">,
XD, EVEX_CD8<64, CD8VT1>;
-defm VCVTTSD2SI64Z: avx512_cvt_s_all<0x2C, "cvttsd2si", f64x_info, i64x_info,
- fp_to_sint,X86cvtts2IntRnd>,
+defm VCVTTSD2SI64Z: avx512_cvt_s_all<0x2C, "vcvttsd2si", f64x_info, i64x_info,
+ fp_to_sint, X86cvtts2IntRnd, "{q}">,
VEX_W, XD, EVEX_CD8<64, CD8VT1>;
-defm VCVTTSS2USIZ: avx512_cvt_s_all<0x78, "cvttss2usi", f32x_info, i32x_info,
- fp_to_uint,X86cvtts2UIntRnd>,
+defm VCVTTSS2USIZ: avx512_cvt_s_all<0x78, "vcvttss2usi", f32x_info, i32x_info,
+ fp_to_uint, X86cvtts2UIntRnd, "{l}">,
XS, EVEX_CD8<32, CD8VT1>;
-defm VCVTTSS2USI64Z: avx512_cvt_s_all<0x78, "cvttss2usi", f32x_info, i64x_info,
- fp_to_uint,X86cvtts2UIntRnd>,
+defm VCVTTSS2USI64Z: avx512_cvt_s_all<0x78, "vcvttss2usi", f32x_info, i64x_info,
+ fp_to_uint, X86cvtts2UIntRnd, "{q}">,
XS,VEX_W, EVEX_CD8<32, CD8VT1>;
-defm VCVTTSD2USIZ: avx512_cvt_s_all<0x78, "cvttsd2usi", f64x_info, i32x_info,
- fp_to_uint,X86cvtts2UIntRnd>,
+defm VCVTTSD2USIZ: avx512_cvt_s_all<0x78, "vcvttsd2usi", f64x_info, i32x_info,
+ fp_to_uint, X86cvtts2UIntRnd, "{l}">,
XD, EVEX_CD8<64, CD8VT1>;
-defm VCVTTSD2USI64Z: avx512_cvt_s_all<0x78, "cvttsd2usi", f64x_info, i64x_info,
- fp_to_uint,X86cvtts2UIntRnd>,
+defm VCVTTSD2USI64Z: avx512_cvt_s_all<0x78, "vcvttsd2usi", f64x_info, i64x_info,
+ fp_to_uint, X86cvtts2UIntRnd, "{q}">,
XD, VEX_W, EVEX_CD8<64, CD8VT1>;
let Predicates = [HasAVX512] in {
def : Pat<(i32 (int_x86_sse_cvttss2si (v4f32 VR128X:$src))),
- (VCVTTSS2SIZrr_Int (COPY_TO_REGCLASS VR128X:$src, FR32X))>;
+ (VCVTTSS2SIZrr_Int VR128X:$src)>;
+ def : Pat<(i32 (int_x86_sse_cvttss2si (sse_load_f32 addr:$src))),
+ (VCVTTSS2SIZrm_Int addr:$src)>;
def : Pat<(i64 (int_x86_sse_cvttss2si64 (v4f32 VR128X:$src))),
- (VCVTTSS2SI64Zrr_Int (COPY_TO_REGCLASS VR128X:$src, FR32X))>;
+ (VCVTTSS2SI64Zrr_Int VR128X:$src)>;
+ def : Pat<(i64 (int_x86_sse_cvttss2si64 (sse_load_f32 addr:$src))),
+ (VCVTTSS2SI64Zrm_Int addr:$src)>;
def : Pat<(i32 (int_x86_sse2_cvttsd2si (v2f64 VR128X:$src))),
- (VCVTTSD2SIZrr_Int (COPY_TO_REGCLASS VR128X:$src, FR64X))>;
+ (VCVTTSD2SIZrr_Int VR128X:$src)>;
+ def : Pat<(i32 (int_x86_sse2_cvttsd2si (sse_load_f64 addr:$src))),
+ (VCVTTSD2SIZrm_Int addr:$src)>;
def : Pat<(i64 (int_x86_sse2_cvttsd2si64 (v2f64 VR128X:$src))),
- (VCVTTSD2SI64Zrr_Int (COPY_TO_REGCLASS VR128X:$src, FR64X))>;
-
+ (VCVTTSD2SI64Zrr_Int VR128X:$src)>;
+ def : Pat<(i64 (int_x86_sse2_cvttsd2si64 (sse_load_f64 addr:$src))),
+ (VCVTTSD2SI64Zrm_Int addr:$src)>;
} // HasAVX512
//===----------------------------------------------------------------------===//
// AVX-512 Convert form float to double and back
@@ -5280,14 +6079,16 @@ multiclass avx512_cvt_fp_scalar<bits<8> opc, string OpcodeStr, X86VectorVTInfo _
(ins _.RC:$src1, _Src.RC:$src2), OpcodeStr,
"$src2, $src1", "$src1, $src2",
(_.VT (OpNode (_.VT _.RC:$src1),
- (_Src.VT _Src.RC:$src2)))>,
+ (_Src.VT _Src.RC:$src2),
+ (i32 FROUND_CURRENT)))>,
EVEX_4V, VEX_LIG, Sched<[WriteCvtF2F]>;
defm rm : AVX512_maskable_scalar<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _Src.RC:$src1, _Src.ScalarMemOp:$src2), OpcodeStr,
"$src2, $src1", "$src1, $src2",
(_.VT (OpNode (_.VT _.RC:$src1),
(_Src.VT (scalar_to_vector
- (_Src.ScalarLdFrag addr:$src2)))))>,
+ (_Src.ScalarLdFrag addr:$src2))),
+ (i32 FROUND_CURRENT)))>,
EVEX_4V, VEX_LIG, Sched<[WriteCvtF2FLd, ReadAfterLd]>;
}
@@ -5314,36 +6115,35 @@ multiclass avx512_cvt_fp_rc_scalar<bits<8> opc, string OpcodeStr, X86VectorVTInf
EVEX_4V, VEX_LIG, Sched<[WriteCvtF2FLd, ReadAfterLd]>,
EVEX_B, EVEX_RC;
}
-multiclass avx512_cvt_fp_scalar_sd2ss<bits<8> opc, string OpcodeStr, SDNode OpNode,
+multiclass avx512_cvt_fp_scalar_sd2ss<bits<8> opc, string OpcodeStr,
SDNode OpNodeRnd, X86VectorVTInfo _src,
X86VectorVTInfo _dst> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_cvt_fp_scalar<opc, OpcodeStr, _dst, _src, OpNode>,
+ defm Z : avx512_cvt_fp_scalar<opc, OpcodeStr, _dst, _src, OpNodeRnd>,
avx512_cvt_fp_rc_scalar<opc, OpcodeStr, _dst, _src,
- OpNodeRnd>, VEX_W, EVEX_CD8<64, CD8VT1>,
- EVEX_V512, XD;
+ OpNodeRnd>, VEX_W, EVEX_CD8<64, CD8VT1>, XD;
}
}
-multiclass avx512_cvt_fp_scalar_ss2sd<bits<8> opc, string OpcodeStr, SDNode OpNode,
+multiclass avx512_cvt_fp_scalar_ss2sd<bits<8> opc, string OpcodeStr,
SDNode OpNodeRnd, X86VectorVTInfo _src,
X86VectorVTInfo _dst> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_cvt_fp_scalar<opc, OpcodeStr, _dst, _src, OpNode>,
+ defm Z : avx512_cvt_fp_scalar<opc, OpcodeStr, _dst, _src, OpNodeRnd>,
avx512_cvt_fp_sae_scalar<opc, OpcodeStr, _dst, _src, OpNodeRnd>,
- EVEX_CD8<32, CD8VT1>, XS, EVEX_V512;
+ EVEX_CD8<32, CD8VT1>, XS;
}
}
-defm VCVTSD2SS : avx512_cvt_fp_scalar_sd2ss<0x5A, "vcvtsd2ss", X86fround,
+defm VCVTSD2SS : avx512_cvt_fp_scalar_sd2ss<0x5A, "vcvtsd2ss",
X86froundRnd, f64x_info, f32x_info>;
-defm VCVTSS2SD : avx512_cvt_fp_scalar_ss2sd<0x5A, "vcvtss2sd", X86fpext,
+defm VCVTSS2SD : avx512_cvt_fp_scalar_ss2sd<0x5A, "vcvtss2sd",
X86fpextRnd,f32x_info, f64x_info >;
-def : Pat<(f64 (fextend FR32X:$src)),
+def : Pat<(f64 (fpextend FR32X:$src)),
(COPY_TO_REGCLASS (VCVTSS2SDZrr (COPY_TO_REGCLASS FR32X:$src, VR128X),
(COPY_TO_REGCLASS FR32X:$src, VR128X)), VR128X)>,
Requires<[HasAVX512]>;
-def : Pat<(f64 (fextend (loadf32 addr:$src))),
+def : Pat<(f64 (fpextend (loadf32 addr:$src))),
(COPY_TO_REGCLASS (VCVTSS2SDZrm (v4f32 (IMPLICIT_DEF)), addr:$src), VR128X)>,
Requires<[HasAVX512]>;
@@ -5356,10 +6156,25 @@ def : Pat<(f64 (extloadf32 addr:$src)),
(COPY_TO_REGCLASS (VMOVSSZrm addr:$src), VR128X)), VR128X)>,
Requires<[HasAVX512, OptForSpeed]>;
-def : Pat<(f32 (fround FR64X:$src)),
+def : Pat<(f32 (fpround FR64X:$src)),
(COPY_TO_REGCLASS (VCVTSD2SSZrr (COPY_TO_REGCLASS FR64X:$src, VR128X),
(COPY_TO_REGCLASS FR64X:$src, VR128X)), VR128X)>,
Requires<[HasAVX512]>;
+
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128X:$dst),
+ (v4f32 (scalar_to_vector
+ (f32 (fpround (f64 (extractelt VR128X:$src, (iPTR 0))))))))),
+ (VCVTSD2SSZrr VR128X:$dst, VR128X:$src)>,
+ Requires<[HasAVX512]>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128X:$dst),
+ (v2f64 (scalar_to_vector
+ (f64 (fpextend (f32 (extractelt VR128X:$src, (iPTR 0))))))))),
+ (VCVTSS2SDZrr VR128X:$dst, VR128X:$src)>,
+ Requires<[HasAVX512]>;
+
//===----------------------------------------------------------------------===//
// AVX-512 Vector convert from signed/unsigned integer to float/double
// and from float/double to signed/unsigned integer
@@ -5368,14 +6183,14 @@ def : Pat<(f32 (fround FR64X:$src)),
multiclass avx512_vcvt_fp<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
X86VectorVTInfo _Src, SDNode OpNode,
string Broadcast = _.BroadcastStr,
- string Alias = ""> {
+ string Alias = "", X86MemOperand MemOp = _Src.MemOp> {
defm rr : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _Src.RC:$src), OpcodeStr, "$src", "$src",
(_.VT (OpNode (_Src.VT _Src.RC:$src)))>, EVEX;
defm rm : AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
- (ins _Src.MemOp:$src), OpcodeStr#Alias, "$src", "$src",
+ (ins MemOp:$src), OpcodeStr#Alias, "$src", "$src",
(_.VT (OpNode (_Src.VT
(bitconvert (_Src.LdFrag addr:$src)))))>, EVEX;
@@ -5410,14 +6225,14 @@ multiclass avx512_vcvt_fp_rc<bits<8> opc, string OpcodeStr, X86VectorVTInfo _,
// Extend Float to Double
multiclass avx512_cvtps2pd<bits<8> opc, string OpcodeStr> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8f64_info, v8f32x_info, fextend>,
+ defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8f64_info, v8f32x_info, fpextend>,
avx512_vcvt_fp_sae<opc, OpcodeStr, v8f64_info, v8f32x_info,
X86vfpextRnd>, EVEX_V512;
}
let Predicates = [HasVLX] in {
defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v2f64x_info, v4f32x_info,
- X86vfpext, "{1to2}">, EVEX_V128;
- defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4f64x_info, v4f32x_info, fextend>,
+ X86vfpext, "{1to2}", "", f64mem>, EVEX_V128;
+ defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4f64x_info, v4f32x_info, fpextend>,
EVEX_V256;
}
}
@@ -5425,15 +6240,24 @@ multiclass avx512_cvtps2pd<bits<8> opc, string OpcodeStr> {
// Truncate Double to Float
multiclass avx512_cvtpd2ps<bits<8> opc, string OpcodeStr> {
let Predicates = [HasAVX512] in {
- defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8f32x_info, v8f64_info, fround>,
+ defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8f32x_info, v8f64_info, fpround>,
avx512_vcvt_fp_rc<opc, OpcodeStr, v8f32x_info, v8f64_info,
X86vfproundRnd>, EVEX_V512;
}
let Predicates = [HasVLX] in {
defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v4f32x_info, v2f64x_info,
X86vfpround, "{1to2}", "{x}">, EVEX_V128;
- defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4f32x_info, v4f64x_info, fround,
+ defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4f32x_info, v4f64x_info, fpround,
"{1to4}", "{y}">, EVEX_V256;
+
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rr") VR128X:$dst, VR128X:$src), 0>;
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rm") VR128X:$dst, f128mem:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rr") VR128X:$dst, VR256X:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rm") VR128X:$dst, f256mem:$src), 0>;
}
}
@@ -5446,6 +6270,12 @@ def : Pat<(v8f64 (extloadv8f32 addr:$src)),
(VCVTPS2PDZrm addr:$src)>;
let Predicates = [HasVLX] in {
+ let AddedComplexity = 15 in
+ def : Pat<(X86vzmovl (v2f64 (bitconvert
+ (v4f32 (X86vfpround (v2f64 VR128X:$src)))))),
+ (VCVTPD2PSZ128rr VR128X:$src)>;
+ def : Pat<(v2f64 (extloadv2f32 addr:$src)),
+ (VCVTPS2PDZ128rm addr:$src)>;
def : Pat<(v4f64 (extloadv4f32 addr:$src)),
(VCVTPS2PDZ256rm addr:$src)>;
}
@@ -5460,7 +6290,7 @@ multiclass avx512_cvtdq2pd<bits<8> opc, string OpcodeStr, SDNode OpNode,
let Predicates = [HasVLX] in {
defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v2f64x_info, v4i32x_info,
- OpNode128, "{1to2}">, EVEX_V128;
+ OpNode128, "{1to2}", "", i64mem>, EVEX_V128;
defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4f64x_info, v4i32x_info, OpNode>,
EVEX_V256;
}
@@ -5515,8 +6345,8 @@ multiclass avx512_cvtps2dq<bits<8> opc, string OpcodeStr,
}
// Convert Double to Signed/Unsigned Doubleword with truncation
-multiclass avx512_cvttpd2dq<bits<8> opc, string OpcodeStr,
- SDNode OpNode, SDNode OpNodeRnd> {
+multiclass avx512_cvttpd2dq<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ SDNode OpNode128, SDNode OpNodeRnd> {
let Predicates = [HasAVX512] in {
defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8i32x_info, v8f64_info, OpNode>,
avx512_vcvt_fp_sae<opc, OpcodeStr, v8i32x_info, v8f64_info,
@@ -5524,13 +6354,22 @@ multiclass avx512_cvttpd2dq<bits<8> opc, string OpcodeStr,
}
let Predicates = [HasVLX] in {
// we need "x"/"y" suffixes in order to distinguish between 128 and 256
- // memory forms of these instructions in Asm Parcer. They have the same
+ // memory forms of these instructions in Asm Parser. They have the same
// dest type - 'v4i32x_info'. We also specify the broadcast string explicitly
// due to the same reason.
- defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v4i32x_info, v2f64x_info, OpNode,
- "{1to2}", "{x}">, EVEX_V128;
+ defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v4i32x_info, v2f64x_info,
+ OpNode128, "{1to2}", "{x}">, EVEX_V128;
defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4i32x_info, v4f64x_info, OpNode,
"{1to4}", "{y}">, EVEX_V256;
+
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rr") VR128X:$dst, VR128X:$src), 0>;
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rm") VR128X:$dst, i128mem:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rr") VR128X:$dst, VR256X:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rm") VR128X:$dst, i256mem:$src), 0>;
}
}
@@ -5551,6 +6390,15 @@ multiclass avx512_cvtpd2dq<bits<8> opc, string OpcodeStr,
"{1to2}", "{x}">, EVEX_V128;
defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4i32x_info, v4f64x_info, OpNode,
"{1to4}", "{y}">, EVEX_V256;
+
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rr") VR128X:$dst, VR128X:$src), 0>;
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rm") VR128X:$dst, f128mem:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rr") VR128X:$dst, VR256X:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rm") VR128X:$dst, f256mem:$src), 0>;
}
}
@@ -5614,15 +6462,15 @@ multiclass avx512_cvtps2qq<bits<8> opc, string OpcodeStr,
// Explicitly specified broadcast string, since we take only 2 elements
// from v4f32x_info source
defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v2i64x_info, v4f32x_info, OpNode,
- "{1to2}">, EVEX_V128;
+ "{1to2}", "", f64mem>, EVEX_V128;
defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4i64x_info, v4f32x_info, OpNode>,
EVEX_V256;
}
}
// Convert Float to Signed/Unsigned Quardword with truncation
-multiclass avx512_cvttps2qq<bits<8> opc, string OpcodeStr,
- SDNode OpNode, SDNode OpNodeRnd> {
+multiclass avx512_cvttps2qq<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ SDNode OpNode128, SDNode OpNodeRnd> {
let Predicates = [HasDQI] in {
defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8i64_info, v8f32x_info, OpNode>,
avx512_vcvt_fp_sae<opc, OpcodeStr, v8i64_info, v8f32x_info,
@@ -5631,16 +6479,16 @@ multiclass avx512_cvttps2qq<bits<8> opc, string OpcodeStr,
let Predicates = [HasDQI, HasVLX] in {
// Explicitly specified broadcast string, since we take only 2 elements
// from v4f32x_info source
- defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v2i64x_info, v4f32x_info, OpNode,
- "{1to2}">, EVEX_V128;
+ defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v2i64x_info, v4f32x_info, OpNode128,
+ "{1to2}", "", f64mem>, EVEX_V128;
defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4i64x_info, v4f32x_info, OpNode>,
EVEX_V256;
}
}
// Convert Signed/Unsigned Quardword to Float
-multiclass avx512_cvtqq2ps<bits<8> opc, string OpcodeStr,
- SDNode OpNode, SDNode OpNodeRnd> {
+multiclass avx512_cvtqq2ps<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ SDNode OpNode128, SDNode OpNodeRnd> {
let Predicates = [HasDQI] in {
defm Z : avx512_vcvt_fp<opc, OpcodeStr, v8f32x_info, v8i64_info, OpNode>,
avx512_vcvt_fp_rc<opc, OpcodeStr, v8f32x_info, v8i64_info,
@@ -5651,37 +6499,46 @@ multiclass avx512_cvtqq2ps<bits<8> opc, string OpcodeStr,
// memory forms of these instructions in Asm Parcer. They have the same
// dest type - 'v4i32x_info'. We also specify the broadcast string explicitly
// due to the same reason.
- defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v4f32x_info, v2i64x_info, OpNode,
+ defm Z128 : avx512_vcvt_fp<opc, OpcodeStr, v4f32x_info, v2i64x_info, OpNode128,
"{1to2}", "{x}">, EVEX_V128;
defm Z256 : avx512_vcvt_fp<opc, OpcodeStr, v4f32x_info, v4i64x_info, OpNode,
"{1to4}", "{y}">, EVEX_V256;
+
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rr") VR128X:$dst, VR128X:$src), 0>;
+ def : InstAlias<OpcodeStr##"x\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z128rm") VR128X:$dst, i128mem:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rr") VR128X:$dst, VR256X:$src), 0>;
+ def : InstAlias<OpcodeStr##"y\t{$src, $dst|$dst, $src}",
+ (!cast<Instruction>(NAME # "Z256rm") VR128X:$dst, i256mem:$src), 0>;
}
}
-defm VCVTDQ2PD : avx512_cvtdq2pd<0xE6, "vcvtdq2pd", sint_to_fp, X86cvtdq2pd>, XS,
- EVEX_CD8<32, CD8VH>;
+defm VCVTDQ2PD : avx512_cvtdq2pd<0xE6, "vcvtdq2pd", sint_to_fp, X86VSintToFP>,
+ XS, EVEX_CD8<32, CD8VH>;
defm VCVTDQ2PS : avx512_cvtdq2ps<0x5B, "vcvtdq2ps", sint_to_fp,
X86VSintToFpRnd>,
PS, EVEX_CD8<32, CD8VF>;
defm VCVTTPS2DQ : avx512_cvttps2dq<0x5B, "vcvttps2dq", fp_to_sint,
- X86VFpToSintRnd>,
+ X86cvttp2siRnd>,
XS, EVEX_CD8<32, CD8VF>;
-defm VCVTTPD2DQ : avx512_cvttpd2dq<0xE6, "vcvttpd2dq", fp_to_sint,
- X86VFpToSintRnd>,
+defm VCVTTPD2DQ : avx512_cvttpd2dq<0xE6, "vcvttpd2dq", fp_to_sint, X86cvttp2si,
+ X86cvttp2siRnd>,
PD, VEX_W, EVEX_CD8<64, CD8VF>;
defm VCVTTPS2UDQ : avx512_cvttps2dq<0x78, "vcvttps2udq", fp_to_uint,
- X86VFpToUintRnd>, PS,
+ X86cvttp2uiRnd>, PS,
EVEX_CD8<32, CD8VF>;
defm VCVTTPD2UDQ : avx512_cvttpd2dq<0x78, "vcvttpd2udq", fp_to_uint,
- X86VFpToUintRnd>, PS, VEX_W,
+ X86cvttp2ui, X86cvttp2uiRnd>, PS, VEX_W,
EVEX_CD8<64, CD8VF>;
-defm VCVTUDQ2PD : avx512_cvtdq2pd<0x7A, "vcvtudq2pd", uint_to_fp, X86cvtudq2pd>,
+defm VCVTUDQ2PD : avx512_cvtdq2pd<0x7A, "vcvtudq2pd", uint_to_fp, X86VUintToFP>,
XS, EVEX_CD8<32, CD8VH>;
defm VCVTUDQ2PS : avx512_cvtdq2ps<0x7A, "vcvtudq2ps", uint_to_fp,
@@ -5717,18 +6574,18 @@ defm VCVTPS2UQQ : avx512_cvtps2qq<0x79, "vcvtps2uqq", X86cvtp2UInt,
X86cvtp2UIntRnd>, PD, EVEX_CD8<32, CD8VH>;
defm VCVTTPD2QQ : avx512_cvttpd2qq<0x7A, "vcvttpd2qq", fp_to_sint,
- X86VFpToSintRnd>, VEX_W,
+ X86cvttp2siRnd>, VEX_W,
PD, EVEX_CD8<64, CD8VF>;
-defm VCVTTPS2QQ : avx512_cvttps2qq<0x7A, "vcvttps2qq", fp_to_sint,
- X86VFpToSintRnd>, PD, EVEX_CD8<32, CD8VH>;
+defm VCVTTPS2QQ : avx512_cvttps2qq<0x7A, "vcvttps2qq", fp_to_sint, X86cvttp2si,
+ X86cvttp2siRnd>, PD, EVEX_CD8<32, CD8VH>;
defm VCVTTPD2UQQ : avx512_cvttpd2qq<0x78, "vcvttpd2uqq", fp_to_uint,
- X86VFpToUintRnd>, VEX_W,
+ X86cvttp2uiRnd>, VEX_W,
PD, EVEX_CD8<64, CD8VF>;
-defm VCVTTPS2UQQ : avx512_cvttps2qq<0x78, "vcvttps2uqq", fp_to_uint,
- X86VFpToUintRnd>, PD, EVEX_CD8<32, CD8VH>;
+defm VCVTTPS2UQQ : avx512_cvttps2qq<0x78, "vcvttps2uqq", fp_to_uint, X86cvttp2ui,
+ X86cvttp2uiRnd>, PD, EVEX_CD8<32, CD8VH>;
defm VCVTQQ2PD : avx512_cvtqq2pd<0xE6, "vcvtqq2pd", sint_to_fp,
X86VSintToFpRnd>, VEX_W, XS, EVEX_CD8<64, CD8VF>;
@@ -5736,45 +6593,151 @@ defm VCVTQQ2PD : avx512_cvtqq2pd<0xE6, "vcvtqq2pd", sint_to_fp,
defm VCVTUQQ2PD : avx512_cvtqq2pd<0x7A, "vcvtuqq2pd", uint_to_fp,
X86VUintToFpRnd>, VEX_W, XS, EVEX_CD8<64, CD8VF>;
-defm VCVTQQ2PS : avx512_cvtqq2ps<0x5B, "vcvtqq2ps", sint_to_fp,
+defm VCVTQQ2PS : avx512_cvtqq2ps<0x5B, "vcvtqq2ps", sint_to_fp, X86VSintToFP,
X86VSintToFpRnd>, VEX_W, PS, EVEX_CD8<64, CD8VF>;
-defm VCVTUQQ2PS : avx512_cvtqq2ps<0x7A, "vcvtuqq2ps", uint_to_fp,
+defm VCVTUQQ2PS : avx512_cvtqq2ps<0x7A, "vcvtuqq2ps", uint_to_fp, X86VUintToFP,
X86VUintToFpRnd>, VEX_W, XD, EVEX_CD8<64, CD8VF>;
let Predicates = [HasAVX512, NoVLX] in {
def : Pat<(v8i32 (fp_to_uint (v8f32 VR256X:$src1))),
(EXTRACT_SUBREG (v16i32 (VCVTTPS2UDQZrr
- (v16f32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>;
+ (v16f32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_ymm)>;
def : Pat<(v4i32 (fp_to_uint (v4f32 VR128X:$src1))),
(EXTRACT_SUBREG (v16i32 (VCVTTPS2UDQZrr
- (v16f32 (SUBREG_TO_REG (i32 0), VR128X:$src1, sub_xmm)))), sub_xmm)>;
+ (v16f32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
def : Pat<(v4i32 (fp_to_uint (v4f64 VR256X:$src1))),
(EXTRACT_SUBREG (v8i32 (VCVTTPD2UDQZrr
- (v8f64 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_xmm)>;
+ (v8f64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_xmm)>;
+
+def : Pat<(v4i32 (X86cvttp2ui (v2f64 VR128X:$src))),
+ (EXTRACT_SUBREG (v8i32 (VCVTTPD2UDQZrr
+ (v8f64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src, sub_xmm)))), sub_xmm)>;
def : Pat<(v8f32 (uint_to_fp (v8i32 VR256X:$src1))),
(EXTRACT_SUBREG (v16f32 (VCVTUDQ2PSZrr
- (v16i32 (SUBREG_TO_REG (i32 0), VR256X:$src1, sub_ymm)))), sub_ymm)>;
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_ymm)>;
def : Pat<(v4f32 (uint_to_fp (v4i32 VR128X:$src1))),
(EXTRACT_SUBREG (v16f32 (VCVTUDQ2PSZrr
- (v16i32 (SUBREG_TO_REG (i32 0), VR128X:$src1, sub_xmm)))), sub_xmm)>;
+ (v16i32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
def : Pat<(v4f64 (uint_to_fp (v4i32 VR128X:$src1))),
(EXTRACT_SUBREG (v8f64 (VCVTUDQ2PDZrr
- (v8i32 (SUBREG_TO_REG (i32 0), VR128X:$src1, sub_xmm)))), sub_ymm)>;
+ (v8i32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_ymm)>;
+
+def : Pat<(v2f64 (X86VUintToFP (v4i32 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8f64 (VCVTUDQ2PDZrr
+ (v8i32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
+}
+
+let Predicates = [HasAVX512, HasVLX] in {
+ let AddedComplexity = 15 in {
+ def : Pat<(X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvtp2Int (v2f64 VR128X:$src)))))),
+ (VCVTPD2DQZ128rr VR128X:$src)>;
+ def : Pat<(v4i32 (bitconvert (X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvtp2UInt (v2f64 VR128X:$src)))))))),
+ (VCVTPD2UDQZ128rr VR128X:$src)>;
+ def : Pat<(X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvttp2si (v2f64 VR128X:$src)))))),
+ (VCVTTPD2DQZ128rr VR128X:$src)>;
+ def : Pat<(v4i32 (bitconvert (X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvttp2ui (v2f64 VR128X:$src)))))))),
+ (VCVTTPD2UDQZ128rr VR128X:$src)>;
+ }
}
let Predicates = [HasAVX512] in {
- def : Pat<(v8f32 (fround (loadv8f64 addr:$src))),
+ def : Pat<(v8f32 (fpround (loadv8f64 addr:$src))),
(VCVTPD2PSZrm addr:$src)>;
def : Pat<(v8f64 (extloadv8f32 addr:$src)),
(VCVTPS2PDZrm addr:$src)>;
}
+let Predicates = [HasDQI, HasVLX] in {
+ let AddedComplexity = 15 in {
+ def : Pat<(X86vzmovl (v2f64 (bitconvert
+ (v4f32 (X86VSintToFP (v2i64 VR128X:$src)))))),
+ (VCVTQQ2PSZ128rr VR128X:$src)>;
+ def : Pat<(X86vzmovl (v2f64 (bitconvert
+ (v4f32 (X86VUintToFP (v2i64 VR128X:$src)))))),
+ (VCVTUQQ2PSZ128rr VR128X:$src)>;
+ }
+}
+
+let Predicates = [HasDQI, NoVLX] in {
+def : Pat<(v2i64 (fp_to_sint (v2f64 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8i64 (VCVTTPD2QQZrr
+ (v8f64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
+
+def : Pat<(v4i64 (fp_to_sint (v4f32 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8i64 (VCVTTPS2QQZrr
+ (v8f32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_ymm)>;
+
+def : Pat<(v4i64 (fp_to_sint (v4f64 VR256X:$src1))),
+ (EXTRACT_SUBREG (v8i64 (VCVTTPD2QQZrr
+ (v8f64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_ymm)>;
+
+def : Pat<(v2i64 (fp_to_uint (v2f64 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8i64 (VCVTTPD2UQQZrr
+ (v8f64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
+
+def : Pat<(v4i64 (fp_to_uint (v4f32 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8i64 (VCVTTPS2UQQZrr
+ (v8f32 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_ymm)>;
+
+def : Pat<(v4i64 (fp_to_uint (v4f64 VR256X:$src1))),
+ (EXTRACT_SUBREG (v8i64 (VCVTTPD2UQQZrr
+ (v8f64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_ymm)>;
+
+def : Pat<(v4f32 (sint_to_fp (v4i64 VR256X:$src1))),
+ (EXTRACT_SUBREG (v8f32 (VCVTQQ2PSZrr
+ (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_xmm)>;
+
+def : Pat<(v2f64 (sint_to_fp (v2i64 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8f64 (VCVTQQ2PDZrr
+ (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
+
+def : Pat<(v4f64 (sint_to_fp (v4i64 VR256X:$src1))),
+ (EXTRACT_SUBREG (v8f64 (VCVTQQ2PDZrr
+ (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_ymm)>;
+
+def : Pat<(v4f32 (uint_to_fp (v4i64 VR256X:$src1))),
+ (EXTRACT_SUBREG (v8f32 (VCVTUQQ2PSZrr
+ (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_xmm)>;
+
+def : Pat<(v2f64 (uint_to_fp (v2i64 VR128X:$src1))),
+ (EXTRACT_SUBREG (v8f64 (VCVTUQQ2PDZrr
+ (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR128X:$src1, sub_xmm)))), sub_xmm)>;
+
+def : Pat<(v4f64 (uint_to_fp (v4i64 VR256X:$src1))),
+ (EXTRACT_SUBREG (v8f64 (VCVTUQQ2PDZrr
+ (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
+ VR256X:$src1, sub_ymm)))), sub_ymm)>;
+}
+
//===----------------------------------------------------------------------===//
// Half precision conversion instructions
//===----------------------------------------------------------------------===//
@@ -5816,14 +6779,13 @@ multiclass avx512_cvtps2ph<X86VectorVTInfo _dest, X86VectorVTInfo _src,
(ins _src.RC:$src1, i32u8imm:$src2),
"vcvtps2ph", "$src2, $src1", "$src1, $src2",
(X86cvtps2ph (_src.VT _src.RC:$src1),
- (i32 imm:$src2),
- (i32 FROUND_CURRENT)),
- NoItinerary, 0, X86select>, AVX512AIi8Base;
+ (i32 imm:$src2)),
+ NoItinerary, 0, 0, X86select>, AVX512AIi8Base;
def mr : AVX512AIi8<0x1D, MRMDestMem, (outs),
(ins x86memop:$dst, _src.RC:$src1, i32u8imm:$src2),
"vcvtps2ph\t{$src2, $src1, $dst|$dst, $src1, $src2}",
[(store (_dest.VT (X86cvtps2ph (_src.VT _src.RC:$src1),
- (i32 imm:$src2), (i32 FROUND_CURRENT) )),
+ (i32 imm:$src2))),
addr:$dst)]>;
let hasSideEffects = 0, mayStore = 1 in
def mrk : AVX512AIi8<0x1D, MRMDestMem, (outs),
@@ -5832,13 +6794,12 @@ multiclass avx512_cvtps2ph<X86VectorVTInfo _dest, X86VectorVTInfo _src,
[]>, EVEX_K;
}
multiclass avx512_cvtps2ph_sae<X86VectorVTInfo _dest, X86VectorVTInfo _src> {
- defm rb : AVX512_maskable<0x1D, MRMDestReg, _dest ,(outs _dest.RC:$dst),
+ let hasSideEffects = 0 in
+ defm rb : AVX512_maskable_in_asm<0x1D, MRMDestReg, _dest,
+ (outs _dest.RC:$dst),
(ins _src.RC:$src1, i32u8imm:$src2),
"vcvtps2ph", "$src2, {sae}, $src1", "$src1, {sae}, $src2",
- (X86cvtps2ph (_src.VT _src.RC:$src1),
- (i32 imm:$src2),
- (i32 FROUND_NO_EXC)),
- NoItinerary, 0, X86select>, EVEX_B, AVX512AIi8Base;
+ []>, EVEX_B, AVX512AIi8Base;
}
let Predicates = [HasAVX512] in {
defm VCVTPS2PHZ : avx512_cvtps2ph<v16i16x_info, v16f32_info, f256mem>,
@@ -5852,25 +6813,72 @@ let Predicates = [HasAVX512] in {
}
}
+// Patterns for matching conversions from float to half-float and vice versa.
+let Predicates = [HasVLX] in {
+ // Use MXCSR.RC for rounding instead of explicitly specifying the default
+ // rounding mode (Nearest-Even, encoded as 0). Both are equivalent in the
+ // configurations we support (the default). However, falling back to MXCSR is
+ // more consistent with other instructions, which are always controlled by it.
+ // It's encoded as 0b100.
+ def : Pat<(fp_to_f16 FR32X:$src),
+ (i16 (EXTRACT_SUBREG (VMOVPDI2DIZrr (VCVTPS2PHZ128rr
+ (COPY_TO_REGCLASS FR32X:$src, VR128X), 4)), sub_16bit))>;
+
+ def : Pat<(f16_to_fp GR16:$src),
+ (f32 (COPY_TO_REGCLASS (VCVTPH2PSZ128rr
+ (COPY_TO_REGCLASS (MOVSX32rr16 GR16:$src), VR128X)), FR32X)) >;
+
+ def : Pat<(f16_to_fp (i16 (fp_to_f16 FR32X:$src))),
+ (f32 (COPY_TO_REGCLASS (VCVTPH2PSZ128rr
+ (VCVTPS2PHZ128rr (COPY_TO_REGCLASS FR32X:$src, VR128X), 4)), FR32X)) >;
+}
+
+// Patterns for matching float to half-float conversion when AVX512 is supported
+// but F16C isn't. In that case we have to use 512-bit vectors.
+let Predicates = [HasAVX512, NoVLX, NoF16C] in {
+ def : Pat<(fp_to_f16 FR32X:$src),
+ (i16 (EXTRACT_SUBREG
+ (VMOVPDI2DIZrr
+ (v8i16 (EXTRACT_SUBREG
+ (VCVTPS2PHZrr
+ (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)),
+ (v4f32 (COPY_TO_REGCLASS FR32X:$src, VR128X)),
+ sub_xmm), 4), sub_xmm))), sub_16bit))>;
+
+ def : Pat<(f16_to_fp GR16:$src),
+ (f32 (COPY_TO_REGCLASS
+ (v4f32 (EXTRACT_SUBREG
+ (VCVTPH2PSZrr
+ (INSERT_SUBREG (v16i16 (IMPLICIT_DEF)),
+ (v8i16 (COPY_TO_REGCLASS (MOVSX32rr16 GR16:$src), VR128X)),
+ sub_xmm)), sub_xmm)), FR32X))>;
+
+ def : Pat<(f16_to_fp (i16 (fp_to_f16 FR32X:$src))),
+ (f32 (COPY_TO_REGCLASS
+ (v4f32 (EXTRACT_SUBREG
+ (VCVTPH2PSZrr
+ (VCVTPS2PHZrr (INSERT_SUBREG (v16f32 (IMPLICIT_DEF)),
+ (v4f32 (COPY_TO_REGCLASS FR32X:$src, VR128X)),
+ sub_xmm), 4)), sub_xmm)), FR32X))>;
+}
+
// Unordered/Ordered scalar fp compare with Sea and set EFLAGS
-multiclass avx512_ord_cmp_sae<bits<8> opc, X86VectorVTInfo _, SDNode OpNode,
+multiclass avx512_ord_cmp_sae<bits<8> opc, X86VectorVTInfo _,
string OpcodeStr> {
def rb: AVX512<opc, MRMSrcReg, (outs), (ins _.RC:$src1, _.RC:$src2),
!strconcat(OpcodeStr, "\t{{sae}, $src2, $src1|$src1, $src2, {sae}}"),
- [(set EFLAGS, (OpNode (_.VT _.RC:$src1), _.RC:$src2,
- (i32 FROUND_NO_EXC)))],
- IIC_SSE_COMIS_RR>, EVEX, EVEX_B, VEX_LIG, EVEX_V128,
+ [], IIC_SSE_COMIS_RR>, EVEX, EVEX_B, VEX_LIG, EVEX_V128,
Sched<[WriteFAdd]>;
}
let Defs = [EFLAGS], Predicates = [HasAVX512] in {
- defm VUCOMISSZ : avx512_ord_cmp_sae<0x2E, v4f32x_info, X86ucomiSae, "vucomiss">,
+ defm VUCOMISSZ : avx512_ord_cmp_sae<0x2E, v4f32x_info, "vucomiss">,
AVX512PSIi8Base, EVEX_CD8<32, CD8VT1>;
- defm VUCOMISDZ : avx512_ord_cmp_sae<0x2E, v2f64x_info, X86ucomiSae, "vucomisd">,
+ defm VUCOMISDZ : avx512_ord_cmp_sae<0x2E, v2f64x_info, "vucomisd">,
AVX512PDIi8Base, VEX_W, EVEX_CD8<64, CD8VT1>;
- defm VCOMISSZ : avx512_ord_cmp_sae<0x2F, v4f32x_info, X86comiSae, "vcomiss">,
+ defm VCOMISSZ : avx512_ord_cmp_sae<0x2F, v4f32x_info, "vcomiss">,
AVX512PSIi8Base, EVEX_CD8<32, CD8VT1>;
- defm VCOMISDZ : avx512_ord_cmp_sae<0x2F, v2f64x_info, X86comiSae, "vcomisd">,
+ defm VCOMISDZ : avx512_ord_cmp_sae<0x2F, v2f64x_info, "vcomisd">,
AVX512PDIi8Base, VEX_W, EVEX_CD8<64, CD8VT1>;
}
@@ -5890,18 +6898,18 @@ let Defs = [EFLAGS], Predicates = [HasAVX512] in {
VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>;
}
let isCodeGenOnly = 1 in {
- defm Int_VUCOMISSZ : sse12_ord_cmp<0x2E, VR128X, X86ucomi, v4f32, f128mem,
- load, "ucomiss">, PS, EVEX, VEX_LIG,
+ defm Int_VUCOMISSZ : sse12_ord_cmp_int<0x2E, VR128X, X86ucomi, v4f32, ssmem,
+ sse_load_f32, "ucomiss">, PS, EVEX, VEX_LIG,
EVEX_CD8<32, CD8VT1>;
- defm Int_VUCOMISDZ : sse12_ord_cmp<0x2E, VR128X, X86ucomi, v2f64, f128mem,
- load, "ucomisd">, PD, EVEX,
+ defm Int_VUCOMISDZ : sse12_ord_cmp_int<0x2E, VR128X, X86ucomi, v2f64, sdmem,
+ sse_load_f64, "ucomisd">, PD, EVEX,
VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>;
- defm Int_VCOMISSZ : sse12_ord_cmp<0x2F, VR128X, X86comi, v4f32, f128mem,
- load, "comiss">, PS, EVEX, VEX_LIG,
+ defm Int_VCOMISSZ : sse12_ord_cmp_int<0x2F, VR128X, X86comi, v4f32, ssmem,
+ sse_load_f32, "comiss">, PS, EVEX, VEX_LIG,
EVEX_CD8<32, CD8VT1>;
- defm Int_VCOMISDZ : sse12_ord_cmp<0x2F, VR128X, X86comi, v2f64, f128mem,
- load, "comisd">, PD, EVEX,
+ defm Int_VCOMISDZ : sse12_ord_cmp_int<0x2F, VR128X, X86comi, v2f64, sdmem,
+ sse_load_f64, "comisd">, PD, EVEX,
VEX_LIG, VEX_W, EVEX_CD8<64, CD8VT1>;
}
}
@@ -6275,7 +7283,7 @@ defm VRNDSCALESD : avx512_rndscale_scalar<0x0B, "vrndscalesd", f64x_info>, VEX_W
multiclass avx512_trunc_common<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo SrcInfo, X86VectorVTInfo DestInfo,
X86MemOperand x86memop> {
-
+ let ExeDomain = DestInfo.ExeDomain in
defm rr : AVX512_maskable<opc, MRMDestReg, DestInfo, (outs DestInfo.RC:$dst),
(ins SrcInfo.RC:$src1), OpcodeStr ,"$src1", "$src1",
(DestInfo.VT (OpNode (SrcInfo.VT SrcInfo.RC:$src1)))>,
@@ -6301,7 +7309,8 @@ multiclass avx512_trunc_common<bits<8> opc, string OpcodeStr, SDNode OpNode,
DestInfo.KRCWM:$mask ,
SrcInfo.RC:$src1)>;
- let mayStore = 1, mayLoad = 1, hasSideEffects = 0 in {
+ let mayStore = 1, mayLoad = 1, hasSideEffects = 0,
+ ExeDomain = DestInfo.ExeDomain in {
def mr : AVX512XS8I<opc, MRMDestMem, (outs),
(ins x86memop:$dst, SrcInfo.RC:$src),
OpcodeStr # "\t{$src, $dst|$dst, $src}",
@@ -6328,23 +7337,6 @@ multiclass avx512_trunc_mr_lowering<X86VectorVTInfo SrcInfo,
addr:$dst, SrcInfo.KRCWM:$mask, SrcInfo.RC:$src)>;
}
-multiclass avx512_trunc_sat_mr_lowering<X86VectorVTInfo SrcInfo,
- X86VectorVTInfo DestInfo, string sat > {
-
- def: Pat<(!cast<Intrinsic>("int_x86_avx512_mask_pmov"#sat#"_"#SrcInfo.Suffix#
- DestInfo.Suffix#"_mem_"#SrcInfo.Size)
- addr:$ptr, (SrcInfo.VT SrcInfo.RC:$src), SrcInfo.MRC:$mask),
- (!cast<Instruction>(NAME#SrcInfo.ZSuffix##mrk) addr:$ptr,
- (COPY_TO_REGCLASS SrcInfo.MRC:$mask, SrcInfo.KRCWM),
- (SrcInfo.VT SrcInfo.RC:$src))>;
-
- def: Pat<(!cast<Intrinsic>("int_x86_avx512_mask_pmov"#sat#"_"#SrcInfo.Suffix#
- DestInfo.Suffix#"_mem_"#SrcInfo.Size)
- addr:$ptr, (SrcInfo.VT SrcInfo.RC:$src), -1),
- (!cast<Instruction>(NAME#SrcInfo.ZSuffix##mr) addr:$ptr,
- (SrcInfo.VT SrcInfo.RC:$src))>;
-}
-
multiclass avx512_trunc<bits<8> opc, string OpcodeStr, SDNode OpNode,
AVX512VLVectorVTInfo VTSrcInfo, X86VectorVTInfo DestInfoZ128,
X86VectorVTInfo DestInfoZ256, X86VectorVTInfo DestInfoZ,
@@ -6370,140 +7362,111 @@ multiclass avx512_trunc<bits<8> opc, string OpcodeStr, SDNode OpNode,
truncFrag, mtruncFrag>, EVEX_V512;
}
-multiclass avx512_trunc_sat<bits<8> opc, string OpcodeStr, SDNode OpNode,
- AVX512VLVectorVTInfo VTSrcInfo, X86VectorVTInfo DestInfoZ128,
- X86VectorVTInfo DestInfoZ256, X86VectorVTInfo DestInfoZ,
- X86MemOperand x86memopZ128, X86MemOperand x86memopZ256,
- X86MemOperand x86memopZ, string sat, Predicate prd = HasAVX512>{
-
- let Predicates = [HasVLX, prd] in {
- defm Z128: avx512_trunc_common<opc, OpcodeStr, OpNode, VTSrcInfo.info128,
- DestInfoZ128, x86memopZ128>,
- avx512_trunc_sat_mr_lowering<VTSrcInfo.info128, DestInfoZ128,
- sat>, EVEX_V128;
-
- defm Z256: avx512_trunc_common<opc, OpcodeStr, OpNode, VTSrcInfo.info256,
- DestInfoZ256, x86memopZ256>,
- avx512_trunc_sat_mr_lowering<VTSrcInfo.info256, DestInfoZ256,
- sat>, EVEX_V256;
- }
- let Predicates = [prd] in
- defm Z: avx512_trunc_common<opc, OpcodeStr, OpNode, VTSrcInfo.info512,
- DestInfoZ, x86memopZ>,
- avx512_trunc_sat_mr_lowering<VTSrcInfo.info512, DestInfoZ,
- sat>, EVEX_V512;
-}
-
-multiclass avx512_trunc_qb<bits<8> opc, string OpcodeStr, SDNode OpNode> {
+multiclass avx512_trunc_qb<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ PatFrag StoreNode, PatFrag MaskedStoreNode> {
defm NAME: avx512_trunc<opc, OpcodeStr, OpNode, avx512vl_i64_info,
v16i8x_info, v16i8x_info, v16i8x_info, i16mem, i32mem, i64mem,
- truncstorevi8, masked_truncstorevi8>, EVEX_CD8<8, CD8VO>;
-}
-multiclass avx512_trunc_sat_qb<bits<8> opc, string sat, SDNode OpNode> {
- defm NAME: avx512_trunc_sat<opc, "vpmov"##sat##"qb", OpNode, avx512vl_i64_info,
- v16i8x_info, v16i8x_info, v16i8x_info, i16mem, i32mem, i64mem,
- sat>, EVEX_CD8<8, CD8VO>;
+ StoreNode, MaskedStoreNode>, EVEX_CD8<8, CD8VO>;
}
-multiclass avx512_trunc_qw<bits<8> opc, string OpcodeStr, SDNode OpNode> {
+multiclass avx512_trunc_qw<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ PatFrag StoreNode, PatFrag MaskedStoreNode> {
defm NAME: avx512_trunc<opc, OpcodeStr, OpNode, avx512vl_i64_info,
v8i16x_info, v8i16x_info, v8i16x_info, i32mem, i64mem, i128mem,
- truncstorevi16, masked_truncstorevi16>, EVEX_CD8<16, CD8VQ>;
-}
-multiclass avx512_trunc_sat_qw<bits<8> opc, string sat, SDNode OpNode> {
- defm NAME: avx512_trunc_sat<opc, "vpmov"##sat##"qw", OpNode, avx512vl_i64_info,
- v8i16x_info, v8i16x_info, v8i16x_info, i32mem, i64mem, i128mem,
- sat>, EVEX_CD8<16, CD8VQ>;
+ StoreNode, MaskedStoreNode>, EVEX_CD8<16, CD8VQ>;
}
-multiclass avx512_trunc_qd<bits<8> opc, string OpcodeStr, SDNode OpNode> {
+multiclass avx512_trunc_qd<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ PatFrag StoreNode, PatFrag MaskedStoreNode> {
defm NAME: avx512_trunc<opc, OpcodeStr, OpNode, avx512vl_i64_info,
v4i32x_info, v4i32x_info, v8i32x_info, i64mem, i128mem, i256mem,
- truncstorevi32, masked_truncstorevi32>, EVEX_CD8<32, CD8VH>;
-}
-multiclass avx512_trunc_sat_qd<bits<8> opc, string sat, SDNode OpNode> {
- defm NAME: avx512_trunc_sat<opc, "vpmov"##sat##"qd", OpNode, avx512vl_i64_info,
- v4i32x_info, v4i32x_info, v8i32x_info, i64mem, i128mem, i256mem,
- sat>, EVEX_CD8<32, CD8VH>;
+ StoreNode, MaskedStoreNode>, EVEX_CD8<32, CD8VH>;
}
-multiclass avx512_trunc_db<bits<8> opc, string OpcodeStr, SDNode OpNode> {
+multiclass avx512_trunc_db<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ PatFrag StoreNode, PatFrag MaskedStoreNode> {
defm NAME: avx512_trunc<opc, OpcodeStr, OpNode, avx512vl_i32_info,
v16i8x_info, v16i8x_info, v16i8x_info, i32mem, i64mem, i128mem,
- truncstorevi8, masked_truncstorevi8>, EVEX_CD8<8, CD8VQ>;
-}
-multiclass avx512_trunc_sat_db<bits<8> opc, string sat, SDNode OpNode> {
- defm NAME: avx512_trunc_sat<opc, "vpmov"##sat##"db", OpNode, avx512vl_i32_info,
- v16i8x_info, v16i8x_info, v16i8x_info, i32mem, i64mem, i128mem,
- sat>, EVEX_CD8<8, CD8VQ>;
+ StoreNode, MaskedStoreNode>, EVEX_CD8<8, CD8VQ>;
}
-multiclass avx512_trunc_dw<bits<8> opc, string OpcodeStr, SDNode OpNode> {
+multiclass avx512_trunc_dw<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ PatFrag StoreNode, PatFrag MaskedStoreNode> {
defm NAME: avx512_trunc<opc, OpcodeStr, OpNode, avx512vl_i32_info,
v8i16x_info, v8i16x_info, v16i16x_info, i64mem, i128mem, i256mem,
- truncstorevi16, masked_truncstorevi16>, EVEX_CD8<16, CD8VH>;
-}
-multiclass avx512_trunc_sat_dw<bits<8> opc, string sat, SDNode OpNode> {
- defm NAME: avx512_trunc_sat<opc, "vpmov"##sat##"dw", OpNode, avx512vl_i32_info,
- v8i16x_info, v8i16x_info, v16i16x_info, i64mem, i128mem, i256mem,
- sat>, EVEX_CD8<16, CD8VH>;
+ StoreNode, MaskedStoreNode>, EVEX_CD8<16, CD8VH>;
}
-multiclass avx512_trunc_wb<bits<8> opc, string OpcodeStr, SDNode OpNode> {
+multiclass avx512_trunc_wb<bits<8> opc, string OpcodeStr, SDNode OpNode,
+ PatFrag StoreNode, PatFrag MaskedStoreNode> {
defm NAME: avx512_trunc<opc, OpcodeStr, OpNode, avx512vl_i16_info,
v16i8x_info, v16i8x_info, v32i8x_info, i64mem, i128mem, i256mem,
- truncstorevi8, masked_truncstorevi8,HasBWI>, EVEX_CD8<16, CD8VH>;
-}
-multiclass avx512_trunc_sat_wb<bits<8> opc, string sat, SDNode OpNode> {
- defm NAME: avx512_trunc_sat<opc, "vpmov"##sat##"wb", OpNode, avx512vl_i16_info,
- v16i8x_info, v16i8x_info, v32i8x_info, i64mem, i128mem, i256mem,
- sat, HasBWI>, EVEX_CD8<16, CD8VH>;
-}
-
-defm VPMOVQB : avx512_trunc_qb<0x32, "vpmovqb", X86vtrunc>;
-defm VPMOVSQB : avx512_trunc_sat_qb<0x22, "s", X86vtruncs>;
-defm VPMOVUSQB : avx512_trunc_sat_qb<0x12, "us", X86vtruncus>;
-
-defm VPMOVQW : avx512_trunc_qw<0x34, "vpmovqw", X86vtrunc>;
-defm VPMOVSQW : avx512_trunc_sat_qw<0x24, "s", X86vtruncs>;
-defm VPMOVUSQW : avx512_trunc_sat_qw<0x14, "us", X86vtruncus>;
-
-defm VPMOVQD : avx512_trunc_qd<0x35, "vpmovqd", X86vtrunc>;
-defm VPMOVSQD : avx512_trunc_sat_qd<0x25, "s", X86vtruncs>;
-defm VPMOVUSQD : avx512_trunc_sat_qd<0x15, "us", X86vtruncus>;
-
-defm VPMOVDB : avx512_trunc_db<0x31, "vpmovdb", X86vtrunc>;
-defm VPMOVSDB : avx512_trunc_sat_db<0x21, "s", X86vtruncs>;
-defm VPMOVUSDB : avx512_trunc_sat_db<0x11, "us", X86vtruncus>;
-
-defm VPMOVDW : avx512_trunc_dw<0x33, "vpmovdw", X86vtrunc>;
-defm VPMOVSDW : avx512_trunc_sat_dw<0x23, "s", X86vtruncs>;
-defm VPMOVUSDW : avx512_trunc_sat_dw<0x13, "us", X86vtruncus>;
-
-defm VPMOVWB : avx512_trunc_wb<0x30, "vpmovwb", X86vtrunc>;
-defm VPMOVSWB : avx512_trunc_sat_wb<0x20, "s", X86vtruncs>;
-defm VPMOVUSWB : avx512_trunc_sat_wb<0x10, "us", X86vtruncus>;
+ StoreNode, MaskedStoreNode, HasBWI>, EVEX_CD8<16, CD8VH>;
+}
+
+defm VPMOVQB : avx512_trunc_qb<0x32, "vpmovqb", X86vtrunc,
+ truncstorevi8, masked_truncstorevi8>;
+defm VPMOVSQB : avx512_trunc_qb<0x22, "vpmovsqb", X86vtruncs,
+ truncstore_s_vi8, masked_truncstore_s_vi8>;
+defm VPMOVUSQB : avx512_trunc_qb<0x12, "vpmovusqb", X86vtruncus,
+ truncstore_us_vi8, masked_truncstore_us_vi8>;
+
+defm VPMOVQW : avx512_trunc_qw<0x34, "vpmovqw", X86vtrunc,
+ truncstorevi16, masked_truncstorevi16>;
+defm VPMOVSQW : avx512_trunc_qw<0x24, "vpmovsqw", X86vtruncs,
+ truncstore_s_vi16, masked_truncstore_s_vi16>;
+defm VPMOVUSQW : avx512_trunc_qw<0x14, "vpmovusqw", X86vtruncus,
+ truncstore_us_vi16, masked_truncstore_us_vi16>;
+
+defm VPMOVQD : avx512_trunc_qd<0x35, "vpmovqd", X86vtrunc,
+ truncstorevi32, masked_truncstorevi32>;
+defm VPMOVSQD : avx512_trunc_qd<0x25, "vpmovsqd", X86vtruncs,
+ truncstore_s_vi32, masked_truncstore_s_vi32>;
+defm VPMOVUSQD : avx512_trunc_qd<0x15, "vpmovusqd", X86vtruncus,
+ truncstore_us_vi32, masked_truncstore_us_vi32>;
+
+defm VPMOVDB : avx512_trunc_db<0x31, "vpmovdb", X86vtrunc,
+ truncstorevi8, masked_truncstorevi8>;
+defm VPMOVSDB : avx512_trunc_db<0x21, "vpmovsdb", X86vtruncs,
+ truncstore_s_vi8, masked_truncstore_s_vi8>;
+defm VPMOVUSDB : avx512_trunc_db<0x11, "vpmovusdb", X86vtruncus,
+ truncstore_us_vi8, masked_truncstore_us_vi8>;
+
+defm VPMOVDW : avx512_trunc_dw<0x33, "vpmovdw", X86vtrunc,
+ truncstorevi16, masked_truncstorevi16>;
+defm VPMOVSDW : avx512_trunc_dw<0x23, "vpmovsdw", X86vtruncs,
+ truncstore_s_vi16, masked_truncstore_s_vi16>;
+defm VPMOVUSDW : avx512_trunc_dw<0x13, "vpmovusdw", X86vtruncus,
+ truncstore_us_vi16, masked_truncstore_us_vi16>;
+
+defm VPMOVWB : avx512_trunc_wb<0x30, "vpmovwb", X86vtrunc,
+ truncstorevi8, masked_truncstorevi8>;
+defm VPMOVSWB : avx512_trunc_wb<0x20, "vpmovswb", X86vtruncs,
+ truncstore_s_vi8, masked_truncstore_s_vi8>;
+defm VPMOVUSWB : avx512_trunc_wb<0x10, "vpmovuswb", X86vtruncus,
+ truncstore_us_vi8, masked_truncstore_us_vi8>;
let Predicates = [HasAVX512, NoVLX] in {
def: Pat<(v8i16 (X86vtrunc (v8i32 VR256X:$src))),
(v8i16 (EXTRACT_SUBREG
- (v16i16 (VPMOVDWZrr (v16i32 (SUBREG_TO_REG (i32 0),
+ (v16i16 (VPMOVDWZrr (v16i32 (INSERT_SUBREG (IMPLICIT_DEF),
VR256X:$src, sub_ymm)))), sub_xmm))>;
def: Pat<(v4i32 (X86vtrunc (v4i64 VR256X:$src))),
(v4i32 (EXTRACT_SUBREG
- (v8i32 (VPMOVQDZrr (v8i64 (SUBREG_TO_REG (i32 0),
+ (v8i32 (VPMOVQDZrr (v8i64 (INSERT_SUBREG (IMPLICIT_DEF),
VR256X:$src, sub_ymm)))), sub_xmm))>;
}
let Predicates = [HasBWI, NoVLX] in {
def: Pat<(v16i8 (X86vtrunc (v16i16 VR256X:$src))),
- (v16i8 (EXTRACT_SUBREG (VPMOVWBZrr (v32i16 (SUBREG_TO_REG (i32 0),
+ (v16i8 (EXTRACT_SUBREG (VPMOVWBZrr (v32i16 (INSERT_SUBREG (IMPLICIT_DEF),
VR256X:$src, sub_ymm))), sub_xmm))>;
}
multiclass avx512_extend_common<bits<8> opc, string OpcodeStr,
X86VectorVTInfo DestInfo, X86VectorVTInfo SrcInfo,
X86MemOperand x86memop, PatFrag LdFrag, SDPatternOperator OpNode>{
+ let ExeDomain = DestInfo.ExeDomain in {
defm rr : AVX512_maskable<opc, MRMSrcReg, DestInfo, (outs DestInfo.RC:$dst),
(ins SrcInfo.RC:$src), OpcodeStr ,"$src", "$src",
(DestInfo.VT (OpNode (SrcInfo.VT SrcInfo.RC:$src)))>,
@@ -6513,6 +7476,7 @@ multiclass avx512_extend_common<bits<8> opc, string OpcodeStr,
(ins x86memop:$src), OpcodeStr ,"$src", "$src",
(DestInfo.VT (LdFrag addr:$src))>,
EVEX;
+ }
}
multiclass avx512_extend_BW<bits<8> opc, string OpcodeStr,
@@ -6685,6 +7649,150 @@ let Predicates = [HasAVX512] in {
defm : avx512_ext_lowering<"DQZ", v8i64_info, v8i32x_info, extloadvi32>;
}
+multiclass AVX512_pmovx_patterns<string OpcPrefix, string ExtTy,
+ SDNode ExtOp, PatFrag ExtLoad16> {
+ // 128-bit patterns
+ let Predicates = [HasVLX, HasBWI] in {
+ def : Pat<(v8i16 (ExtOp (bc_v16i8 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BWZ128rm) addr:$src)>;
+ def : Pat<(v8i16 (ExtOp (bc_v16i8 (v2f64 (scalar_to_vector (loadf64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BWZ128rm) addr:$src)>;
+ def : Pat<(v8i16 (ExtOp (v16i8 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZ128rm) addr:$src)>;
+ def : Pat<(v8i16 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZ128rm) addr:$src)>;
+ def : Pat<(v8i16 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZ128rm) addr:$src)>;
+ }
+ let Predicates = [HasVLX] in {
+ def : Pat<(v4i32 (ExtOp (bc_v16i8 (v4i32 (scalar_to_vector (loadi32 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (v16i8 (vzmovl_v4i32 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZ128rm) addr:$src)>;
+
+ def : Pat<(v2i64 (ExtOp (bc_v16i8 (v4i32 (scalar_to_vector (ExtLoad16 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (v16i8 (vzmovl_v4i32 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZ128rm) addr:$src)>;
+
+ def : Pat<(v4i32 (ExtOp (bc_v8i16 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#WDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (bc_v8i16 (v2f64 (scalar_to_vector (loadf64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#WDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (v8i16 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (v8i16 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZ128rm) addr:$src)>;
+ def : Pat<(v4i32 (ExtOp (bc_v8i16 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZ128rm) addr:$src)>;
+
+ def : Pat<(v2i64 (ExtOp (bc_v8i16 (v4i32 (scalar_to_vector (loadi32 addr:$src)))))),
+ (!cast<I>(OpcPrefix#WQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (v8i16 (vzmovl_v4i32 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (v8i16 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (bc_v8i16 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZ128rm) addr:$src)>;
+
+ def : Pat<(v2i64 (ExtOp (bc_v4i32 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#DQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (bc_v4i32 (v2f64 (scalar_to_vector (loadf64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#DQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (v4i32 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (v4i32 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZ128rm) addr:$src)>;
+ def : Pat<(v2i64 (ExtOp (bc_v4i32 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZ128rm) addr:$src)>;
+ }
+ // 256-bit patterns
+ let Predicates = [HasVLX, HasBWI] in {
+ def : Pat<(v16i16 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZ256rm) addr:$src)>;
+ def : Pat<(v16i16 (ExtOp (v16i8 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZ256rm) addr:$src)>;
+ def : Pat<(v16i16 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZ256rm) addr:$src)>;
+ }
+ let Predicates = [HasVLX] in {
+ def : Pat<(v8i32 (ExtOp (bc_v16i8 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BDZ256rm) addr:$src)>;
+ def : Pat<(v8i32 (ExtOp (v16i8 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZ256rm) addr:$src)>;
+ def : Pat<(v8i32 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZ256rm) addr:$src)>;
+ def : Pat<(v8i32 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZ256rm) addr:$src)>;
+
+ def : Pat<(v4i64 (ExtOp (bc_v16i8 (v4i32 (scalar_to_vector (loadi32 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (v16i8 (vzmovl_v4i32 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZ256rm) addr:$src)>;
+
+ def : Pat<(v8i32 (ExtOp (bc_v8i16 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZ256rm) addr:$src)>;
+ def : Pat<(v8i32 (ExtOp (v8i16 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZ256rm) addr:$src)>;
+ def : Pat<(v8i32 (ExtOp (v8i16 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZ256rm) addr:$src)>;
+
+ def : Pat<(v4i64 (ExtOp (bc_v8i16 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#WQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (v8i16 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (v8i16 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (bc_v8i16 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZ256rm) addr:$src)>;
+
+ def : Pat<(v4i64 (ExtOp (bc_v4i32 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (v4i32 (vzmovl_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZ256rm) addr:$src)>;
+ def : Pat<(v4i64 (ExtOp (v4i32 (vzload_v2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZ256rm) addr:$src)>;
+ }
+ // 512-bit patterns
+ let Predicates = [HasBWI] in {
+ def : Pat<(v32i16 (ExtOp (bc_v32i8 (loadv4i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BWZrm) addr:$src)>;
+ }
+ let Predicates = [HasAVX512] in {
+ def : Pat<(v16i32 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BDZrm) addr:$src)>;
+
+ def : Pat<(v8i64 (ExtOp (bc_v16i8 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+ (!cast<I>(OpcPrefix#BQZrm) addr:$src)>;
+ def : Pat<(v8i64 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#BQZrm) addr:$src)>;
+
+ def : Pat<(v16i32 (ExtOp (bc_v16i16 (loadv4i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WDZrm) addr:$src)>;
+
+ def : Pat<(v8i64 (ExtOp (bc_v8i16 (loadv2i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#WQZrm) addr:$src)>;
+
+ def : Pat<(v8i64 (ExtOp (bc_v8i32 (loadv4i64 addr:$src)))),
+ (!cast<I>(OpcPrefix#DQZrm) addr:$src)>;
+ }
+}
+
+defm : AVX512_pmovx_patterns<"VPMOVSX", "s", X86vsext, extloadi32i16>;
+defm : AVX512_pmovx_patterns<"VPMOVZX", "z", X86vzext, loadi16_anyext>;
+
//===----------------------------------------------------------------------===//
// GATHER - SCATTER Operations
@@ -6859,8 +7967,14 @@ defm VSCATTERPF1QPD: avx512_gather_scatter_prefetch<0xC7, MRM6m, "vscatterpf1qpd
VK8WM, vz512mem>, EVEX_V512, VEX_W, EVEX_CD8<64, CD8VT1>;
// Helper fragments to match sext vXi1 to vXiY.
-def v16i1sextv16i32 : PatLeaf<(v16i32 (X86vsrai VR512:$src, (i8 31)))>;
-def v8i1sextv8i64 : PatLeaf<(v8i64 (X86vsrai VR512:$src, (i8 63)))>;
+def v64i1sextv64i8 : PatLeaf<(v64i8
+ (X86vsext
+ (v64i1 (X86pcmpgtm
+ (bc_v64i8 (v16i32 immAllZerosV)),
+ VR512:$src))))>;
+def v32i1sextv32i16 : PatLeaf<(v32i16 (X86vsrai VR512:$src, (i8 15)))>;
+def v16i1sextv16i32 : PatLeaf<(v16i32 (X86vsrai VR512:$src, (i8 31)))>;
+def v8i1sextv8i64 : PatLeaf<(v8i64 (X86vsrai VR512:$src, (i8 63)))>;
multiclass cvt_by_vec_width<bits<8> opc, X86VectorVTInfo Vec, string OpcodeStr > {
def rr : AVX512XS8I<opc, MRMSrcReg, (outs Vec.RC:$dst), (ins Vec.KRC:$src),
@@ -6941,7 +8055,7 @@ defm VPMOVQ2M : avx512_convert_vector_to_mask<0x39, "vpmovq2m",
// AVX-512 - COMPRESS and EXPAND
//
-multiclass compress_by_vec_width<bits<8> opc, X86VectorVTInfo _,
+multiclass compress_by_vec_width_common<bits<8> opc, X86VectorVTInfo _,
string OpcodeStr> {
defm rr : AVX512_maskable<opc, MRMDestReg, _, (outs _.RC:$dst),
(ins _.RC:$src1), OpcodeStr, "$src1", "$src1",
@@ -6956,19 +8070,28 @@ multiclass compress_by_vec_width<bits<8> opc, X86VectorVTInfo _,
def mrk : AVX5128I<opc, MRMDestMem, (outs),
(ins _.MemOp:$dst, _.KRCWM:$mask, _.RC:$src),
OpcodeStr # "\t{$src, $dst {${mask}}|$dst {${mask}}, $src}",
- [(store (_.VT (vselect _.KRCWM:$mask,
- (_.VT (X86compress _.RC:$src)), _.ImmAllZerosV)),
- addr:$dst)]>,
+ []>,
EVEX_K, EVEX_CD8<_.EltSize, CD8VT1>;
}
+multiclass compress_by_vec_width_lowering<X86VectorVTInfo _ > {
+
+ def : Pat<(X86mCompressingStore addr:$dst, _.KRCWM:$mask,
+ (_.VT _.RC:$src)),
+ (!cast<Instruction>(NAME#_.ZSuffix##mrk)
+ addr:$dst, _.KRCWM:$mask, _.RC:$src)>;
+}
+
multiclass compress_by_elt_width<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo VTInfo> {
- defm Z : compress_by_vec_width<opc, VTInfo.info512, OpcodeStr>, EVEX_V512;
+ defm Z : compress_by_vec_width_common<opc, VTInfo.info512, OpcodeStr>,
+ compress_by_vec_width_lowering<VTInfo.info512>, EVEX_V512;
let Predicates = [HasVLX] in {
- defm Z256 : compress_by_vec_width<opc, VTInfo.info256, OpcodeStr>, EVEX_V256;
- defm Z128 : compress_by_vec_width<opc, VTInfo.info128, OpcodeStr>, EVEX_V128;
+ defm Z256 : compress_by_vec_width_common<opc, VTInfo.info256, OpcodeStr>,
+ compress_by_vec_width_lowering<VTInfo.info256>, EVEX_V256;
+ defm Z128 : compress_by_vec_width_common<opc, VTInfo.info128, OpcodeStr>,
+ compress_by_vec_width_lowering<VTInfo.info128>, EVEX_V128;
}
}
@@ -6995,13 +8118,28 @@ multiclass expand_by_vec_width<bits<8> opc, X86VectorVTInfo _,
AVX5128IBase, EVEX_CD8<_.EltSize, CD8VT1>;
}
+multiclass expand_by_vec_width_lowering<X86VectorVTInfo _ > {
+
+ def : Pat<(_.VT (X86mExpandingLoad addr:$src, _.KRCWM:$mask, undef)),
+ (!cast<Instruction>(NAME#_.ZSuffix##rmkz)
+ _.KRCWM:$mask, addr:$src)>;
+
+ def : Pat<(_.VT (X86mExpandingLoad addr:$src, _.KRCWM:$mask,
+ (_.VT _.RC:$src0))),
+ (!cast<Instruction>(NAME#_.ZSuffix##rmk)
+ _.RC:$src0, _.KRCWM:$mask, addr:$src)>;
+}
+
multiclass expand_by_elt_width<bits<8> opc, string OpcodeStr,
AVX512VLVectorVTInfo VTInfo> {
- defm Z : expand_by_vec_width<opc, VTInfo.info512, OpcodeStr>, EVEX_V512;
+ defm Z : expand_by_vec_width<opc, VTInfo.info512, OpcodeStr>,
+ expand_by_vec_width_lowering<VTInfo.info512>, EVEX_V512;
let Predicates = [HasVLX] in {
- defm Z256 : expand_by_vec_width<opc, VTInfo.info256, OpcodeStr>, EVEX_V256;
- defm Z128 : expand_by_vec_width<opc, VTInfo.info128, OpcodeStr>, EVEX_V128;
+ defm Z256 : expand_by_vec_width<opc, VTInfo.info256, OpcodeStr>,
+ expand_by_vec_width_lowering<VTInfo.info256>, EVEX_V256;
+ defm Z128 : expand_by_vec_width<opc, VTInfo.info128, OpcodeStr>,
+ expand_by_vec_width_lowering<VTInfo.info128>, EVEX_V128;
}
}
@@ -7019,7 +8157,8 @@ defm VEXPANDPD : expand_by_elt_width <0x88, "vexpandpd", avx512vl_f64_info>,
// op(broadcast(eltVt),imm)
//all instruction created with FROUND_CURRENT
multiclass avx512_unary_fp_packed_imm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _>{
+ X86VectorVTInfo _>{
+ let ExeDomain = _.ExeDomain in {
defm rri : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, i32u8imm:$src2),
OpcodeStr##_.Suffix, "$src2, $src1", "$src1, $src2",
@@ -7039,11 +8178,13 @@ multiclass avx512_unary_fp_packed_imm<bits<8> opc, string OpcodeStr, SDNode OpNo
(OpNode (_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src1))),
(i32 imm:$src2),
(i32 FROUND_CURRENT))>, EVEX_B;
+ }
}
//handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm),{sae}
multiclass avx512_unary_fp_sae_packed_imm<bits<8> opc, string OpcodeStr,
SDNode OpNode, X86VectorVTInfo _>{
+ let ExeDomain = _.ExeDomain in
defm rrib : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, i32u8imm:$src2),
OpcodeStr##_.Suffix, "$src2, {sae}, $src1",
@@ -7073,7 +8214,8 @@ multiclass avx512_common_unary_fp_sae_packed_imm<string OpcodeStr,
// op(reg_vec2,broadcast(eltVt),imm)
//all instruction created with FROUND_CURRENT
multiclass avx512_fp_packed_imm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _>{
+ X86VectorVTInfo _>{
+ let ExeDomain = _.ExeDomain in {
defm rri : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2, i32u8imm:$src3),
OpcodeStr, "$src3, $src2, $src1", "$src1, $src2, $src3",
@@ -7096,13 +8238,14 @@ multiclass avx512_fp_packed_imm<bits<8> opc, string OpcodeStr, SDNode OpNode,
(_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src2))),
(i32 imm:$src3),
(i32 FROUND_CURRENT))>, EVEX_B;
+ }
}
//handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm)
// op(reg_vec2,mem_vec,imm)
multiclass avx512_3Op_rm_imm8<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo DestInfo, X86VectorVTInfo SrcInfo>{
-
+ let ExeDomain = DestInfo.ExeDomain in {
defm rri : AVX512_maskable<opc, MRMSrcReg, DestInfo, (outs DestInfo.RC:$dst),
(ins SrcInfo.RC:$src1, SrcInfo.RC:$src2, u8imm:$src3),
OpcodeStr, "$src3, $src2, $src1", "$src1, $src2, $src3",
@@ -7116,6 +8259,7 @@ multiclass avx512_3Op_rm_imm8<bits<8> opc, string OpcodeStr, SDNode OpNode,
(SrcInfo.VT (bitconvert
(SrcInfo.LdFrag addr:$src2))),
(i8 imm:$src3)))>;
+ }
}
//handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm)
@@ -7125,6 +8269,7 @@ multiclass avx512_3Op_imm8<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo _>:
avx512_3Op_rm_imm8<opc, OpcodeStr, OpNode, _, _>{
+ let ExeDomain = _.ExeDomain in
defm rmbi : AVX512_maskable<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.ScalarMemOp:$src2, u8imm:$src3),
OpcodeStr, "$src3, ${src2}"##_.BroadcastStr##", $src1",
@@ -7138,8 +8283,8 @@ multiclass avx512_3Op_imm8<bits<8> opc, string OpcodeStr, SDNode OpNode,
// op(reg_vec2,mem_scalar,imm)
//all instruction created with FROUND_CURRENT
multiclass avx512_fp_scalar_imm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _> {
-
+ X86VectorVTInfo _> {
+ let ExeDomain = _.ExeDomain in {
defm rri : AVX512_maskable_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2, i32u8imm:$src3),
OpcodeStr, "$src3, $src2, $src1", "$src1, $src2, $src3",
@@ -7148,25 +8293,20 @@ multiclass avx512_fp_scalar_imm<bits<8> opc, string OpcodeStr, SDNode OpNode,
(i32 imm:$src3),
(i32 FROUND_CURRENT))>;
defm rmi : AVX512_maskable_scalar<opc, MRMSrcMem, _, (outs _.RC:$dst),
- (ins _.RC:$src1, _.MemOp:$src2, i32u8imm:$src3),
+ (ins _.RC:$src1, _.ScalarMemOp:$src2, i32u8imm:$src3),
OpcodeStr, "$src3, $src2, $src1", "$src1, $src2, $src3",
(OpNode (_.VT _.RC:$src1),
(_.VT (scalar_to_vector
(_.ScalarLdFrag addr:$src2))),
(i32 imm:$src3),
(i32 FROUND_CURRENT))>;
-
- let isAsmParserOnly = 1, mayLoad = 1, hasSideEffects = 0 in {
- defm rmi_alt :AVX512_maskable_in_asm<opc, MRMSrcMem, _, (outs _.FRC:$dst),
- (ins _.FRC:$src1, _.ScalarMemOp:$src2, u8imm:$src3),
- OpcodeStr, "$src3, $src2, $src1", "$src1, $src2, $src3",
- []>;
}
}
//handle instruction reg_vec1 = op(reg_vec2,reg_vec3,imm),{sae}
multiclass avx512_fp_sae_packed_imm<bits<8> opc, string OpcodeStr,
SDNode OpNode, X86VectorVTInfo _>{
+ let ExeDomain = _.ExeDomain in
defm rrib : AVX512_maskable<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src1, _.RC:$src2, i32u8imm:$src3),
OpcodeStr, "$src3, {sae}, $src2, $src1",
@@ -7439,14 +8579,64 @@ multiclass avx512_unary_rm_vl_all<bits<8> opc_b, bits<8> opc_w,
defm VPABS : avx512_unary_rm_vl_all<0x1C, 0x1D, 0x1E, 0x1F, "vpabs", X86Abs>;
+def avx512_v16i1sextv16i8 : PatLeaf<(v16i8 (X86pcmpgt (bc_v16i8 (v4i32 immAllZerosV)),
+ VR128X:$src))>;
+def avx512_v8i1sextv8i16 : PatLeaf<(v8i16 (X86vsrai VR128X:$src, (i8 15)))>;
+def avx512_v4i1sextv4i32 : PatLeaf<(v4i32 (X86vsrai VR128X:$src, (i8 31)))>;
+def avx512_v32i1sextv32i8 : PatLeaf<(v32i8 (X86pcmpgt (bc_v32i8 (v8i32 immAllZerosV)),
+ VR256X:$src))>;
+def avx512_v16i1sextv16i16: PatLeaf<(v16i16 (X86vsrai VR256X:$src, (i8 15)))>;
+def avx512_v8i1sextv8i32 : PatLeaf<(v8i32 (X86vsrai VR256X:$src, (i8 31)))>;
+
+let Predicates = [HasBWI, HasVLX] in {
+ def : Pat<(xor
+ (bc_v2i64 (avx512_v16i1sextv16i8)),
+ (bc_v2i64 (add (v16i8 VR128X:$src), (avx512_v16i1sextv16i8)))),
+ (VPABSBZ128rr VR128X:$src)>;
+ def : Pat<(xor
+ (bc_v2i64 (avx512_v8i1sextv8i16)),
+ (bc_v2i64 (add (v8i16 VR128X:$src), (avx512_v8i1sextv8i16)))),
+ (VPABSWZ128rr VR128X:$src)>;
+ def : Pat<(xor
+ (bc_v4i64 (avx512_v32i1sextv32i8)),
+ (bc_v4i64 (add (v32i8 VR256X:$src), (avx512_v32i1sextv32i8)))),
+ (VPABSBZ256rr VR256X:$src)>;
+ def : Pat<(xor
+ (bc_v4i64 (avx512_v16i1sextv16i16)),
+ (bc_v4i64 (add (v16i16 VR256X:$src), (avx512_v16i1sextv16i16)))),
+ (VPABSWZ256rr VR256X:$src)>;
+}
+let Predicates = [HasAVX512, HasVLX] in {
+ def : Pat<(xor
+ (bc_v2i64 (avx512_v4i1sextv4i32)),
+ (bc_v2i64 (add (v4i32 VR128X:$src), (avx512_v4i1sextv4i32)))),
+ (VPABSDZ128rr VR128X:$src)>;
+ def : Pat<(xor
+ (bc_v4i64 (avx512_v8i1sextv8i32)),
+ (bc_v4i64 (add (v8i32 VR256X:$src), (avx512_v8i1sextv8i32)))),
+ (VPABSDZ256rr VR256X:$src)>;
+}
+
+let Predicates = [HasAVX512] in {
def : Pat<(xor
- (bc_v16i32 (v16i1sextv16i32)),
- (bc_v16i32 (add (v16i32 VR512:$src), (v16i1sextv16i32)))),
+ (bc_v8i64 (v16i1sextv16i32)),
+ (bc_v8i64 (add (v16i32 VR512:$src), (v16i1sextv16i32)))),
(VPABSDZrr VR512:$src)>;
def : Pat<(xor
(bc_v8i64 (v8i1sextv8i64)),
(bc_v8i64 (add (v8i64 VR512:$src), (v8i1sextv8i64)))),
(VPABSQZrr VR512:$src)>;
+}
+let Predicates = [HasBWI] in {
+def : Pat<(xor
+ (bc_v8i64 (v64i1sextv64i8)),
+ (bc_v8i64 (add (v64i8 VR512:$src), (v64i1sextv64i8)))),
+ (VPABSBZrr VR512:$src)>;
+def : Pat<(xor
+ (bc_v8i64 (v32i1sextv32i16)),
+ (bc_v8i64 (add (v32i16 VR512:$src), (v32i1sextv32i16)))),
+ (VPABSWZrr VR512:$src)>;
+}
multiclass avx512_ctlz<bits<8> opc, string OpcodeStr, Predicate prd>{
@@ -7503,16 +8693,44 @@ multiclass avx512_movddup<bits<8> opc, string OpcodeStr, SDNode OpNode>{
defm VMOVDDUP : avx512_movddup<0x12, "vmovddup", X86Movddup>;
+let Predicates = [HasVLX] in {
def : Pat<(X86Movddup (loadv2f64 addr:$src)),
- (VMOVDDUPZ128rm addr:$src)>, Requires<[HasAVX512, HasVLX]>;
+ (VMOVDDUPZ128rm addr:$src)>;
def : Pat<(v2f64 (X86VBroadcast (loadf64 addr:$src))),
- (VMOVDDUPZ128rm addr:$src)>, Requires<[HasAVX512, HasVLX]>;
+ (VMOVDDUPZ128rm addr:$src)>;
+def : Pat<(v2f64 (X86VBroadcast f64:$src)),
+ (VMOVDDUPZ128rr (COPY_TO_REGCLASS FR64X:$src, VR128X))>;
+
+def : Pat<(vselect (v2i1 VK2WM:$mask), (X86Movddup (loadv2f64 addr:$src)),
+ (v2f64 VR128X:$src0)),
+ (VMOVDDUPZ128rmk VR128X:$src0, VK2WM:$mask, addr:$src)>;
+def : Pat<(vselect (v2i1 VK2WM:$mask), (X86Movddup (loadv2f64 addr:$src)),
+ (bitconvert (v4i32 immAllZerosV))),
+ (VMOVDDUPZ128rmkz VK2WM:$mask, addr:$src)>;
+
+def : Pat<(vselect (v2i1 VK2WM:$mask), (v2f64 (X86VBroadcast f64:$src)),
+ (v2f64 VR128X:$src0)),
+ (VMOVDDUPZ128rrk VR128X:$src0, VK2WM:$mask,
+ (COPY_TO_REGCLASS FR64X:$src, VR128X))>;
+def : Pat<(vselect (v2i1 VK2WM:$mask), (v2f64 (X86VBroadcast f64:$src)),
+ (bitconvert (v4i32 immAllZerosV))),
+ (VMOVDDUPZ128rrkz VK2WM:$mask, (COPY_TO_REGCLASS FR64X:$src, VR128X))>;
+
+def : Pat<(vselect (v2i1 VK2WM:$mask), (v2f64 (X86VBroadcast (loadf64 addr:$src))),
+ (v2f64 VR128X:$src0)),
+ (VMOVDDUPZ128rmk VR128X:$src0, VK2WM:$mask, addr:$src)>;
+def : Pat<(vselect (v2i1 VK2WM:$mask), (v2f64 (X86VBroadcast (loadf64 addr:$src))),
+ (bitconvert (v4i32 immAllZerosV))),
+ (VMOVDDUPZ128rmkz VK2WM:$mask, addr:$src)>;
+}
//===----------------------------------------------------------------------===//
// AVX-512 - Unpack Instructions
//===----------------------------------------------------------------------===//
-defm VUNPCKH : avx512_fp_binop_p<0x15, "vunpckh", X86Unpckh, HasAVX512>;
-defm VUNPCKL : avx512_fp_binop_p<0x14, "vunpckl", X86Unpckl, HasAVX512>;
+defm VUNPCKH : avx512_fp_binop_p<0x15, "vunpckh", X86Unpckh, HasAVX512,
+ SSE_ALU_ITINS_S>;
+defm VUNPCKL : avx512_fp_binop_p<0x14, "vunpckl", X86Unpckl, HasAVX512,
+ SSE_ALU_ITINS_S>;
defm VPUNPCKLBW : avx512_binop_rm_vl_b<0x60, "vpunpcklbw", X86Unpckl,
SSE_INTALU_ITINS_P, HasBWI>;
@@ -7730,22 +8948,22 @@ defm VPSADBW : avx512_psadbw_packed_all<0xf6, X86psadbw, "vpsadbw",
HasBWI>, EVEX_4V;
multiclass avx512_ternlog<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _>{
- let Constraints = "$src1 = $dst" in {
+ X86VectorVTInfo _>{
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm rri : AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, u8imm:$src4),
OpcodeStr, "$src4, $src3, $src2", "$src2, $src3, $src4",
(OpNode (_.VT _.RC:$src1),
(_.VT _.RC:$src2),
(_.VT _.RC:$src3),
- (i8 imm:$src4))>, AVX512AIi8Base, EVEX_4V;
+ (i8 imm:$src4)), 1, 1>, AVX512AIi8Base, EVEX_4V;
defm rmi : AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.MemOp:$src3, u8imm:$src4),
OpcodeStr, "$src4, $src3, $src2", "$src2, $src3, $src4",
(OpNode (_.VT _.RC:$src1),
(_.VT _.RC:$src2),
(_.VT (bitconvert (_.LdFrag addr:$src3))),
- (i8 imm:$src4))>,
+ (i8 imm:$src4)), 1, 0>,
AVX512AIi8Base, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>;
defm rmbi : AVX512_maskable_3src<opc, MRMSrcMem, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.ScalarMemOp:$src3, u8imm:$src4),
@@ -7754,7 +8972,7 @@ multiclass avx512_ternlog<bits<8> opc, string OpcodeStr, SDNode OpNode,
(OpNode (_.VT _.RC:$src1),
(_.VT _.RC:$src2),
(_.VT (X86VBroadcast(_.ScalarLdFrag addr:$src3))),
- (i8 imm:$src4))>, EVEX_B,
+ (i8 imm:$src4)), 1, 0>, EVEX_B,
AVX512AIi8Base, EVEX_4V, EVEX_CD8<_.EltSize, CD8VF>;
}// Constraints = "$src1 = $dst"
}
@@ -7776,8 +8994,8 @@ defm VPTERNLOGQ : avx512_common_ternlog<"vpternlogq", avx512vl_i64_info>, VEX_W;
//===----------------------------------------------------------------------===//
multiclass avx512_fixupimm_packed<bits<8> opc, string OpcodeStr, SDNode OpNode,
- X86VectorVTInfo _>{
- let Constraints = "$src1 = $dst" in {
+ X86VectorVTInfo _>{
+ let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm rri : AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, i32u8imm:$src4),
OpcodeStr##_.Suffix, "$src4, $src3, $src2", "$src2, $src3, $src4",
@@ -7807,8 +9025,8 @@ multiclass avx512_fixupimm_packed<bits<8> opc, string OpcodeStr, SDNode OpNode,
}
multiclass avx512_fixupimm_packed_sae<bits<8> opc, string OpcodeStr,
- SDNode OpNode, X86VectorVTInfo _>{
-let Constraints = "$src1 = $dst" in {
+ SDNode OpNode, X86VectorVTInfo _>{
+let Constraints = "$src1 = $dst", ExeDomain = _.ExeDomain in {
defm rrib : AVX512_maskable_3src<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, i32u8imm:$src4),
OpcodeStr##_.Suffix, "$src4, {sae}, $src3, $src2",
@@ -7823,7 +9041,8 @@ let Constraints = "$src1 = $dst" in {
multiclass avx512_fixupimm_scalar<bits<8> opc, string OpcodeStr, SDNode OpNode,
X86VectorVTInfo _, X86VectorVTInfo _src3VT> {
- let Constraints = "$src1 = $dst" , Predicates = [HasAVX512] in {
+ let Constraints = "$src1 = $dst" , Predicates = [HasAVX512],
+ ExeDomain = _.ExeDomain in {
defm rri : AVX512_maskable_3src_scalar<opc, MRMSrcReg, _, (outs _.RC:$dst),
(ins _.RC:$src2, _.RC:$src3, i32u8imm:$src4),
OpcodeStr##_.Suffix, "$src4, $src3, $src2", "$src2, $src3, $src4",
@@ -7877,3 +9096,135 @@ defm VFIXUPIMMPS : avx512_fixupimm_packed_all<avx512vl_f32_info>,
EVEX_CD8<32, CD8VF>;
defm VFIXUPIMMPD : avx512_fixupimm_packed_all<avx512vl_f64_info>,
EVEX_CD8<64, CD8VF>, VEX_W;
+
+
+
+// Patterns used to select SSE scalar fp arithmetic instructions from
+// either:
+//
+// (1) a scalar fp operation followed by a blend
+//
+// The effect is that the backend no longer emits unnecessary vector
+// insert instructions immediately after SSE scalar fp instructions
+// like addss or mulss.
+//
+// For example, given the following code:
+// __m128 foo(__m128 A, __m128 B) {
+// A[0] += B[0];
+// return A;
+// }
+//
+// Previously we generated:
+// addss %xmm0, %xmm1
+// movss %xmm1, %xmm0
+//
+// We now generate:
+// addss %xmm1, %xmm0
+//
+// (2) a vector packed single/double fp operation followed by a vector insert
+//
+// The effect is that the backend converts the packed fp instruction
+// followed by a vector insert into a single SSE scalar fp instruction.
+//
+// For example, given the following code:
+// __m128 foo(__m128 A, __m128 B) {
+// __m128 C = A + B;
+// return (__m128) {c[0], a[1], a[2], a[3]};
+// }
+//
+// Previously we generated:
+// addps %xmm0, %xmm1
+// movss %xmm1, %xmm0
+//
+// We now generate:
+// addss %xmm1, %xmm0
+
+// TODO: Some canonicalization in lowering would simplify the number of
+// patterns we have to try to match.
+multiclass AVX512_scalar_math_f32_patterns<SDNode Op, string OpcPrefix> {
+ let Predicates = [HasAVX512] in {
+ // extracted scalar math op with insert via movss
+ def : Pat<(v4f32 (X86Movss (v4f32 VR128X:$dst), (v4f32 (scalar_to_vector
+ (Op (f32 (extractelt (v4f32 VR128X:$dst), (iPTR 0))),
+ FR32X:$src))))),
+ (!cast<I>("V"#OpcPrefix#SSZrr_Int) v4f32:$dst,
+ (COPY_TO_REGCLASS FR32X:$src, VR128X))>;
+
+ // extracted scalar math op with insert via blend
+ def : Pat<(v4f32 (X86Blendi (v4f32 VR128X:$dst), (v4f32 (scalar_to_vector
+ (Op (f32 (extractelt (v4f32 VR128X:$dst), (iPTR 0))),
+ FR32X:$src))), (i8 1))),
+ (!cast<I>("V"#OpcPrefix#SSZrr_Int) v4f32:$dst,
+ (COPY_TO_REGCLASS FR32X:$src, VR128X))>;
+
+ // vector math op with insert via movss
+ def : Pat<(v4f32 (X86Movss (v4f32 VR128X:$dst),
+ (Op (v4f32 VR128X:$dst), (v4f32 VR128X:$src)))),
+ (!cast<I>("V"#OpcPrefix#SSZrr_Int) v4f32:$dst, v4f32:$src)>;
+
+ // vector math op with insert via blend
+ def : Pat<(v4f32 (X86Blendi (v4f32 VR128X:$dst),
+ (Op (v4f32 VR128X:$dst), (v4f32 VR128X:$src)), (i8 1))),
+ (!cast<I>("V"#OpcPrefix#SSZrr_Int) v4f32:$dst, v4f32:$src)>;
+
+ // extracted masked scalar math op with insert via movss
+ def : Pat<(X86Movss (v4f32 VR128X:$src1),
+ (scalar_to_vector
+ (X86selects VK1WM:$mask,
+ (Op (f32 (extractelt (v4f32 VR128X:$src1), (iPTR 0))),
+ FR32X:$src2),
+ FR32X:$src0))),
+ (!cast<I>("V"#OpcPrefix#SSZrr_Intk) (COPY_TO_REGCLASS FR32X:$src0, VR128X),
+ VK1WM:$mask, v4f32:$src1,
+ (COPY_TO_REGCLASS FR32X:$src2, VR128X))>;
+ }
+}
+
+defm : AVX512_scalar_math_f32_patterns<fadd, "ADD">;
+defm : AVX512_scalar_math_f32_patterns<fsub, "SUB">;
+defm : AVX512_scalar_math_f32_patterns<fmul, "MUL">;
+defm : AVX512_scalar_math_f32_patterns<fdiv, "DIV">;
+
+multiclass AVX512_scalar_math_f64_patterns<SDNode Op, string OpcPrefix> {
+ let Predicates = [HasAVX512] in {
+ // extracted scalar math op with insert via movsd
+ def : Pat<(v2f64 (X86Movsd (v2f64 VR128X:$dst), (v2f64 (scalar_to_vector
+ (Op (f64 (extractelt (v2f64 VR128X:$dst), (iPTR 0))),
+ FR64X:$src))))),
+ (!cast<I>("V"#OpcPrefix#SDZrr_Int) v2f64:$dst,
+ (COPY_TO_REGCLASS FR64X:$src, VR128X))>;
+
+ // extracted scalar math op with insert via blend
+ def : Pat<(v2f64 (X86Blendi (v2f64 VR128X:$dst), (v2f64 (scalar_to_vector
+ (Op (f64 (extractelt (v2f64 VR128X:$dst), (iPTR 0))),
+ FR64X:$src))), (i8 1))),
+ (!cast<I>("V"#OpcPrefix#SDZrr_Int) v2f64:$dst,
+ (COPY_TO_REGCLASS FR64X:$src, VR128X))>;
+
+ // vector math op with insert via movsd
+ def : Pat<(v2f64 (X86Movsd (v2f64 VR128X:$dst),
+ (Op (v2f64 VR128X:$dst), (v2f64 VR128X:$src)))),
+ (!cast<I>("V"#OpcPrefix#SDZrr_Int) v2f64:$dst, v2f64:$src)>;
+
+ // vector math op with insert via blend
+ def : Pat<(v2f64 (X86Blendi (v2f64 VR128X:$dst),
+ (Op (v2f64 VR128X:$dst), (v2f64 VR128X:$src)), (i8 1))),
+ (!cast<I>("V"#OpcPrefix#SDZrr_Int) v2f64:$dst, v2f64:$src)>;
+
+ // extracted masked scalar math op with insert via movss
+ def : Pat<(X86Movsd (v2f64 VR128X:$src1),
+ (scalar_to_vector
+ (X86selects VK1WM:$mask,
+ (Op (f64 (extractelt (v2f64 VR128X:$src1), (iPTR 0))),
+ FR64X:$src2),
+ FR64X:$src0))),
+ (!cast<I>("V"#OpcPrefix#SDZrr_Intk) (COPY_TO_REGCLASS FR64X:$src0, VR128X),
+ VK1WM:$mask, v2f64:$src1,
+ (COPY_TO_REGCLASS FR64X:$src2, VR128X))>;
+ }
+}
+
+defm : AVX512_scalar_math_f64_patterns<fadd, "ADD">;
+defm : AVX512_scalar_math_f64_patterns<fsub, "SUB">;
+defm : AVX512_scalar_math_f64_patterns<fmul, "MUL">;
+defm : AVX512_scalar_math_f64_patterns<fdiv, "DIV">;
diff --git a/contrib/llvm/lib/Target/X86/X86InstrArithmetic.td b/contrib/llvm/lib/Target/X86/X86InstrArithmetic.td
index 1a2e786..bfd21c0 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrArithmetic.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrArithmetic.td
@@ -625,7 +625,7 @@ def Xi32 : X86TypeInfo<i32, "l", GR32, loadi32, i32mem,
Imm32, i32imm, imm32_su, i32i8imm, i32immSExt8_su,
1, OpSize32, 0>;
def Xi64 : X86TypeInfo<i64, "q", GR64, loadi64, i64mem,
- Imm32S, i64i32imm, i64immSExt32, i64i8imm, i64immSExt8,
+ Imm32S, i64i32imm, i64immSExt32_su, i64i8imm, i64immSExt8_su,
1, OpSizeFixed, 1>;
/// ITy - This instruction base class takes the type info for the instruction.
diff --git a/contrib/llvm/lib/Target/X86/X86InstrBuilder.h b/contrib/llvm/lib/Target/X86/X86InstrBuilder.h
index bcea6fa..ba970bc 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrBuilder.h
+++ b/contrib/llvm/lib/Target/X86/X86InstrBuilder.h
@@ -24,9 +24,15 @@
#ifndef LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H
#define LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include <cassert>
namespace llvm {
@@ -57,12 +63,11 @@ struct X86AddressMode {
Base.Reg = 0;
}
-
void getFullAddress(SmallVectorImpl<MachineOperand> &MO) {
assert(Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8);
if (BaseType == X86AddressMode::RegBase)
- MO.push_back(MachineOperand::CreateReg(Base.Reg, false, false,
+ MO.push_back(MachineOperand::CreateReg(Base.Reg, false, false, false,
false, false, false, 0, false));
else {
assert(BaseType == X86AddressMode::FrameIndexBase);
@@ -70,44 +75,45 @@ struct X86AddressMode {
}
MO.push_back(MachineOperand::CreateImm(Scale));
- MO.push_back(MachineOperand::CreateReg(IndexReg, false, false,
- false, false, false, 0, false));
+ MO.push_back(MachineOperand::CreateReg(IndexReg, false, false, false, false,
+ false, false, 0, false));
if (GV)
MO.push_back(MachineOperand::CreateGA(GV, Disp, GVOpFlags));
else
MO.push_back(MachineOperand::CreateImm(Disp));
- MO.push_back(MachineOperand::CreateReg(0, false, false,
- false, false, false, 0, false));
+ MO.push_back(MachineOperand::CreateReg(0, false, false, false, false, false,
+ false, 0, false));
}
};
/// Compute the addressing mode from an machine instruction starting with the
/// given operand.
-static inline X86AddressMode getAddressFromInstr(MachineInstr *MI,
+static inline X86AddressMode getAddressFromInstr(const MachineInstr *MI,
unsigned Operand) {
X86AddressMode AM;
- MachineOperand &Op = MI->getOperand(Operand);
- if (Op.isReg()) {
+ const MachineOperand &Op0 = MI->getOperand(Operand);
+ if (Op0.isReg()) {
AM.BaseType = X86AddressMode::RegBase;
- AM.Base.Reg = Op.getReg();
+ AM.Base.Reg = Op0.getReg();
} else {
AM.BaseType = X86AddressMode::FrameIndexBase;
- AM.Base.FrameIndex = Op.getIndex();
- }
- Op = MI->getOperand(Operand + 1);
- if (Op.isImm())
- AM.Scale = Op.getImm();
- Op = MI->getOperand(Operand + 2);
- if (Op.isImm())
- AM.IndexReg = Op.getImm();
- Op = MI->getOperand(Operand + 3);
- if (Op.isGlobal()) {
- AM.GV = Op.getGlobal();
- } else {
- AM.Disp = Op.getImm();
+ AM.Base.FrameIndex = Op0.getIndex();
}
+
+ const MachineOperand &Op1 = MI->getOperand(Operand + 1);
+ AM.Scale = Op1.getImm();
+
+ const MachineOperand &Op2 = MI->getOperand(Operand + 2);
+ AM.IndexReg = Op2.getReg();
+
+ const MachineOperand &Op3 = MI->getOperand(Operand + 3);
+ if (Op3.isGlobal())
+ AM.GV = Op3.getGlobal();
+ else
+ AM.Disp = Op3.getImm();
+
return AM;
}
@@ -122,12 +128,28 @@ addDirectMem(const MachineInstrBuilder &MIB, unsigned Reg) {
return MIB.addReg(Reg).addImm(1).addReg(0).addImm(0).addReg(0);
}
+/// Replace the address used in the instruction with the direct memory
+/// reference.
+static inline void setDirectAddressInInstr(MachineInstr *MI, unsigned Operand,
+ unsigned Reg) {
+ // Direct memory address is in a form of: Reg, 1 (Scale), NoReg, 0, NoReg.
+ MI->getOperand(Operand).setReg(Reg);
+ MI->getOperand(Operand + 1).setImm(1);
+ MI->getOperand(Operand + 2).setReg(0);
+ MI->getOperand(Operand + 3).setImm(0);
+ MI->getOperand(Operand + 4).setReg(0);
+}
static inline const MachineInstrBuilder &
addOffset(const MachineInstrBuilder &MIB, int Offset) {
return MIB.addImm(1).addReg(0).addImm(Offset).addReg(0);
}
+static inline const MachineInstrBuilder &
+addOffset(const MachineInstrBuilder &MIB, const MachineOperand& Offset) {
+ return MIB.addImm(1).addReg(0).addOperand(Offset).addReg(0);
+}
+
/// addRegOffset - This function is used to add a memory reference of the form
/// [Reg + Offset], i.e., one with no scale or index, but with a
/// displacement. An example is: DWORD PTR [EAX + 4].
@@ -177,7 +199,7 @@ static inline const MachineInstrBuilder &
addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0) {
MachineInstr *MI = MIB;
MachineFunction &MF = *MI->getParent()->getParent();
- MachineFrameInfo &MFI = *MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const MCInstrDesc &MCID = MI->getDesc();
auto Flags = MachineMemOperand::MONone;
if (MCID.mayLoad())
@@ -206,6 +228,6 @@ addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI,
.addConstantPoolIndex(CPI, 0, OpFlags).addReg(0);
}
-} // End llvm namespace
+} // end namespace llvm
-#endif
+#endif // LLVM_LIB_TARGET_X86_X86INSTRBUILDER_H
diff --git a/contrib/llvm/lib/Target/X86/X86InstrCompiler.td b/contrib/llvm/lib/Target/X86/X86InstrCompiler.td
index 925f4ef..3c27eb8 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -723,7 +723,7 @@ defm LOCK_DEC : LOCK_ArithUnOp<0xFE, 0xFF, MRM1m, -1, "dec">;
multiclass LCMPXCHG_UnOp<bits<8> Opc, Format Form, string mnemonic,
SDPatternOperator frag, X86MemOperand x86memop,
InstrItinClass itin> {
-let isCodeGenOnly = 1 in {
+let isCodeGenOnly = 1, usesCustomInserter = 1 in {
def NAME : I<Opc, Form, (outs), (ins x86memop:$ptr),
!strconcat(mnemonic, "\t$ptr"),
[(frag addr:$ptr)], itin>, TB, LOCK;
@@ -1025,53 +1025,6 @@ def : Pat<(store (i32 -1), addr:$dst), (OR32mi8 addr:$dst, -1)>;
def : Pat<(store (i64 -1), addr:$dst), (OR64mi8 addr:$dst, -1)>;
}
-// ConstantPool GlobalAddress, ExternalSymbol, and JumpTable
-def : Pat<(i32 (X86Wrapper tconstpool :$dst)), (MOV32ri tconstpool :$dst)>;
-def : Pat<(i32 (X86Wrapper tjumptable :$dst)), (MOV32ri tjumptable :$dst)>;
-def : Pat<(i32 (X86Wrapper tglobaltlsaddr:$dst)),(MOV32ri tglobaltlsaddr:$dst)>;
-def : Pat<(i32 (X86Wrapper tglobaladdr :$dst)), (MOV32ri tglobaladdr :$dst)>;
-def : Pat<(i32 (X86Wrapper texternalsym:$dst)), (MOV32ri texternalsym:$dst)>;
-def : Pat<(i32 (X86Wrapper mcsym:$dst)), (MOV32ri mcsym:$dst)>;
-def : Pat<(i32 (X86Wrapper tblockaddress:$dst)), (MOV32ri tblockaddress:$dst)>;
-
-def : Pat<(add GR32:$src1, (X86Wrapper tconstpool:$src2)),
- (ADD32ri GR32:$src1, tconstpool:$src2)>;
-def : Pat<(add GR32:$src1, (X86Wrapper tjumptable:$src2)),
- (ADD32ri GR32:$src1, tjumptable:$src2)>;
-def : Pat<(add GR32:$src1, (X86Wrapper tglobaladdr :$src2)),
- (ADD32ri GR32:$src1, tglobaladdr:$src2)>;
-def : Pat<(add GR32:$src1, (X86Wrapper texternalsym:$src2)),
- (ADD32ri GR32:$src1, texternalsym:$src2)>;
-def : Pat<(add GR32:$src1, (X86Wrapper mcsym:$src2)),
- (ADD32ri GR32:$src1, mcsym:$src2)>;
-def : Pat<(add GR32:$src1, (X86Wrapper tblockaddress:$src2)),
- (ADD32ri GR32:$src1, tblockaddress:$src2)>;
-
-def : Pat<(store (i32 (X86Wrapper tglobaladdr:$src)), addr:$dst),
- (MOV32mi addr:$dst, tglobaladdr:$src)>;
-def : Pat<(store (i32 (X86Wrapper texternalsym:$src)), addr:$dst),
- (MOV32mi addr:$dst, texternalsym:$src)>;
-def : Pat<(store (i32 (X86Wrapper mcsym:$src)), addr:$dst),
- (MOV32mi addr:$dst, mcsym:$src)>;
-def : Pat<(store (i32 (X86Wrapper tblockaddress:$src)), addr:$dst),
- (MOV32mi addr:$dst, tblockaddress:$src)>;
-
-// ConstantPool GlobalAddress, ExternalSymbol, and JumpTable when not in small
-// code model mode, should use 'movabs'. FIXME: This is really a hack, the
-// 'movabs' predicate should handle this sort of thing.
-def : Pat<(i64 (X86Wrapper tconstpool :$dst)),
- (MOV64ri tconstpool :$dst)>, Requires<[FarData]>;
-def : Pat<(i64 (X86Wrapper tjumptable :$dst)),
- (MOV64ri tjumptable :$dst)>, Requires<[FarData]>;
-def : Pat<(i64 (X86Wrapper tglobaladdr :$dst)),
- (MOV64ri tglobaladdr :$dst)>, Requires<[FarData]>;
-def : Pat<(i64 (X86Wrapper texternalsym:$dst)),
- (MOV64ri texternalsym:$dst)>, Requires<[FarData]>;
-def : Pat<(i64 (X86Wrapper mcsym:$dst)),
- (MOV64ri mcsym:$dst)>, Requires<[FarData]>;
-def : Pat<(i64 (X86Wrapper tblockaddress:$dst)),
- (MOV64ri tblockaddress:$dst)>, Requires<[FarData]>;
-
// In kernel code model, we can get the address of a label
// into a register with 'movq'. FIXME: This is a hack, the 'imm' predicate of
// the MOV64ri32 should accept these.
@@ -1289,15 +1242,13 @@ def : Pat<(i64 (anyext GR32:$src)),
// Any instruction that defines a 32-bit result leaves the high half of the
// register. Truncate can be lowered to EXTRACT_SUBREG. CopyFromReg may
-// be copying from a truncate. And x86's cmov doesn't do anything if the
-// condition is false. But any other 32-bit operation will zero-extend
+// be copying from a truncate. Any other 32-bit operation will zero-extend
// up to 64 bits.
def def32 : PatLeaf<(i32 GR32:$src), [{
return N->getOpcode() != ISD::TRUNCATE &&
N->getOpcode() != TargetOpcode::EXTRACT_SUBREG &&
N->getOpcode() != ISD::CopyFromReg &&
- N->getOpcode() != ISD::AssertSext &&
- N->getOpcode() != X86ISD::CMOV;
+ N->getOpcode() != ISD::AssertSext;
}]>;
// In the case of a 32-bit def that is known to implicitly zero-extend,
@@ -1711,6 +1662,22 @@ defm : MaskedShiftAmountPats<sra, "SAR">;
defm : MaskedShiftAmountPats<rotl, "ROL">;
defm : MaskedShiftAmountPats<rotr, "ROR">;
+// Double shift amount is implicitly masked.
+multiclass MaskedDoubleShiftAmountPats<SDNode frag, string name> {
+ // (shift x (and y, 31)) ==> (shift x, y)
+ def : Pat<(frag GR16:$src1, GR16:$src2, (and CL, immShift32)),
+ (!cast<Instruction>(name # "16rrCL") GR16:$src1, GR16:$src2)>;
+ def : Pat<(frag GR32:$src1, GR32:$src2, (and CL, immShift32)),
+ (!cast<Instruction>(name # "32rrCL") GR32:$src1, GR32:$src2)>;
+
+ // (shift x (and y, 63)) ==> (shift x, y)
+ def : Pat<(frag GR64:$src1, GR64:$src2, (and CL, immShift64)),
+ (!cast<Instruction>(name # "64rrCL") GR64:$src1, GR64:$src2)>;
+}
+
+defm : MaskedDoubleShiftAmountPats<X86shld, "SHLD">;
+defm : MaskedDoubleShiftAmountPats<X86shrd, "SHRD">;
+
// (anyext (setcc_carry)) -> (setcc_carry)
def : Pat<(i16 (anyext (i8 (X86setcc_c X86_COND_B, EFLAGS)))),
(SETB_C16r)>;
@@ -1719,9 +1686,6 @@ def : Pat<(i32 (anyext (i8 (X86setcc_c X86_COND_B, EFLAGS)))),
def : Pat<(i32 (anyext (i16 (X86setcc_c X86_COND_B, EFLAGS)))),
(SETB_C32r)>;
-
-
-
//===----------------------------------------------------------------------===//
// EFLAGS-defining Patterns
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/lib/Target/X86/X86InstrControl.td b/contrib/llvm/lib/Target/X86/X86InstrControl.td
index bb5f911..2f260c4 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrControl.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrControl.td
@@ -239,7 +239,6 @@ let isCall = 1 in
// Tail call stuff.
-
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
isCodeGenOnly = 1, SchedRW = [WriteJumpLd] in
let Uses = [ESP] in {
@@ -257,6 +256,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
(ins i32imm_pcrel:$dst),
"jmp\t$dst",
[], IIC_JMP_REL>;
+
def TAILJMPr : I<0xFF, MRM4r, (outs), (ins ptr_rc_tailcall:$dst),
"", [], IIC_JMP_REG>; // FIXME: Remove encoding when JIT is dead.
let mayLoad = 1 in
@@ -296,17 +296,18 @@ let isCall = 1, Uses = [RSP], SchedRW = [WriteJump] in {
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
isCodeGenOnly = 1, Uses = [RSP], usesCustomInserter = 1,
SchedRW = [WriteJump] in {
- def TCRETURNdi64 : PseudoI<(outs),
- (ins i64i32imm_pcrel:$dst, i32imm:$offset),
- []>;
- def TCRETURNri64 : PseudoI<(outs),
- (ins ptr_rc_tailcall:$dst, i32imm:$offset), []>;
+ def TCRETURNdi64 : PseudoI<(outs),
+ (ins i64i32imm_pcrel:$dst, i32imm:$offset),
+ []>;
+ def TCRETURNri64 : PseudoI<(outs),
+ (ins ptr_rc_tailcall:$dst, i32imm:$offset), []>;
let mayLoad = 1 in
- def TCRETURNmi64 : PseudoI<(outs),
- (ins i64mem_TC:$dst, i32imm:$offset), []>;
+ def TCRETURNmi64 : PseudoI<(outs),
+ (ins i64mem_TC:$dst, i32imm:$offset), []>;
def TAILJMPd64 : Ii32PCRel<0xE9, RawFrm, (outs), (ins i64i32imm_pcrel:$dst),
"jmp\t$dst", [], IIC_JMP_REL>;
+
def TAILJMPr64 : I<0xFF, MRM4r, (outs), (ins ptr_rc_tailcall:$dst),
"jmp{q}\t{*}$dst", [], IIC_JMP_MEM>;
@@ -314,11 +315,8 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
def TAILJMPm64 : I<0xFF, MRM4m, (outs), (ins i64mem_TC:$dst),
"jmp{q}\t{*}$dst", [], IIC_JMP_MEM>;
- // Win64 wants jumps leaving the function to have a REX_W prefix.
+ // Win64 wants indirect jumps leaving the function to have a REX_W prefix.
let hasREX_WPrefix = 1 in {
- def TAILJMPd64_REX : Ii32PCRel<0xE9, RawFrm, (outs),
- (ins i64i32imm_pcrel:$dst),
- "rex64 jmp\t$dst", [], IIC_JMP_REL>;
def TAILJMPr64_REX : I<0xFF, MRM4r, (outs), (ins ptr_rc_tailcall:$dst),
"rex64 jmp{q}\t{*}$dst", [], IIC_JMP_MEM>;
diff --git a/contrib/llvm/lib/Target/X86/X86InstrFMA.td b/contrib/llvm/lib/Target/X86/X86InstrFMA.td
index fd800cf..4b19f80 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrFMA.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrFMA.td
@@ -39,7 +39,6 @@ multiclass fma3p_rm<bits<8> opc, string OpcodeStr,
PatFrag MemFrag128, PatFrag MemFrag256,
ValueType OpVT128, ValueType OpVT256,
SDPatternOperator Op = null_frag> {
- let usesCustomInserter = 1 in
def r : FMA3<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
@@ -55,8 +54,7 @@ multiclass fma3p_rm<bits<8> opc, string OpcodeStr,
[(set VR128:$dst, (OpVT128 (Op VR128:$src2, VR128:$src1,
(MemFrag128 addr:$src3))))]>;
- let usesCustomInserter = 1 in
- def rY : FMA3<opc, MRMSrcReg, (outs VR256:$dst),
+ def Yr : FMA3<opc, MRMSrcReg, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
@@ -64,7 +62,7 @@ multiclass fma3p_rm<bits<8> opc, string OpcodeStr,
VR256:$src3)))]>, VEX_L;
let mayLoad = 1 in
- def mY : FMA3<opc, MRMSrcMem, (outs VR256:$dst),
+ def Ym : FMA3<opc, MRMSrcMem, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, f256mem:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
@@ -74,60 +72,61 @@ multiclass fma3p_rm<bits<8> opc, string OpcodeStr,
}
multiclass fma3p_forms<bits<8> opc132, bits<8> opc213, bits<8> opc231,
- string OpcodeStr, string PackTy,
+ string OpcodeStr, string PackTy, string Suff,
PatFrag MemFrag128, PatFrag MemFrag256,
SDNode Op, ValueType OpTy128, ValueType OpTy256> {
- defm r213 : fma3p_rm<opc213,
- !strconcat(OpcodeStr, "213", PackTy),
- MemFrag128, MemFrag256, OpTy128, OpTy256, Op>;
- defm r132 : fma3p_rm<opc132,
- !strconcat(OpcodeStr, "132", PackTy),
- MemFrag128, MemFrag256, OpTy128, OpTy256>;
- defm r231 : fma3p_rm<opc231,
- !strconcat(OpcodeStr, "231", PackTy),
- MemFrag128, MemFrag256, OpTy128, OpTy256>;
+ defm NAME#213#Suff : fma3p_rm<opc213,
+ !strconcat(OpcodeStr, "213", PackTy),
+ MemFrag128, MemFrag256, OpTy128, OpTy256, Op>;
+ defm NAME#132#Suff : fma3p_rm<opc132,
+ !strconcat(OpcodeStr, "132", PackTy),
+ MemFrag128, MemFrag256, OpTy128, OpTy256>;
+ defm NAME#231#Suff : fma3p_rm<opc231,
+ !strconcat(OpcodeStr, "231", PackTy),
+ MemFrag128, MemFrag256, OpTy128, OpTy256>;
}
// Fused Multiply-Add
let ExeDomain = SSEPackedSingle in {
- defm VFMADDPS : fma3p_forms<0x98, 0xA8, 0xB8, "vfmadd", "ps", loadv4f32,
- loadv8f32, X86Fmadd, v4f32, v8f32>;
- defm VFMSUBPS : fma3p_forms<0x9A, 0xAA, 0xBA, "vfmsub", "ps", loadv4f32,
- loadv8f32, X86Fmsub, v4f32, v8f32>;
- defm VFMADDSUBPS : fma3p_forms<0x96, 0xA6, 0xB6, "vfmaddsub", "ps",
- loadv4f32, loadv8f32, X86Fmaddsub,
- v4f32, v8f32>;
- defm VFMSUBADDPS : fma3p_forms<0x97, 0xA7, 0xB7, "vfmsubadd", "ps",
- loadv4f32, loadv8f32, X86Fmsubadd,
- v4f32, v8f32>;
+ defm VFMADD : fma3p_forms<0x98, 0xA8, 0xB8, "vfmadd", "ps", "PS",
+ loadv4f32, loadv8f32, X86Fmadd, v4f32, v8f32>;
+ defm VFMSUB : fma3p_forms<0x9A, 0xAA, 0xBA, "vfmsub", "ps", "PS",
+ loadv4f32, loadv8f32, X86Fmsub, v4f32, v8f32>;
+ defm VFMADDSUB : fma3p_forms<0x96, 0xA6, 0xB6, "vfmaddsub", "ps", "PS",
+ loadv4f32, loadv8f32, X86Fmaddsub,
+ v4f32, v8f32>;
+ defm VFMSUBADD : fma3p_forms<0x97, 0xA7, 0xB7, "vfmsubadd", "ps", "PS",
+ loadv4f32, loadv8f32, X86Fmsubadd,
+ v4f32, v8f32>;
}
let ExeDomain = SSEPackedDouble in {
- defm VFMADDPD : fma3p_forms<0x98, 0xA8, 0xB8, "vfmadd", "pd", loadv2f64,
- loadv4f64, X86Fmadd, v2f64, v4f64>, VEX_W;
- defm VFMSUBPD : fma3p_forms<0x9A, 0xAA, 0xBA, "vfmsub", "pd", loadv2f64,
- loadv4f64, X86Fmsub, v2f64, v4f64>, VEX_W;
- defm VFMADDSUBPD : fma3p_forms<0x96, 0xA6, 0xB6, "vfmaddsub", "pd",
- loadv2f64, loadv4f64, X86Fmaddsub,
- v2f64, v4f64>, VEX_W;
- defm VFMSUBADDPD : fma3p_forms<0x97, 0xA7, 0xB7, "vfmsubadd", "pd",
- loadv2f64, loadv4f64, X86Fmsubadd,
- v2f64, v4f64>, VEX_W;
+ defm VFMADD : fma3p_forms<0x98, 0xA8, 0xB8, "vfmadd", "pd", "PD",
+ loadv2f64, loadv4f64, X86Fmadd, v2f64,
+ v4f64>, VEX_W;
+ defm VFMSUB : fma3p_forms<0x9A, 0xAA, 0xBA, "vfmsub", "pd", "PD",
+ loadv2f64, loadv4f64, X86Fmsub, v2f64,
+ v4f64>, VEX_W;
+ defm VFMADDSUB : fma3p_forms<0x96, 0xA6, 0xB6, "vfmaddsub", "pd", "PD",
+ loadv2f64, loadv4f64, X86Fmaddsub,
+ v2f64, v4f64>, VEX_W;
+ defm VFMSUBADD : fma3p_forms<0x97, 0xA7, 0xB7, "vfmsubadd", "pd", "PD",
+ loadv2f64, loadv4f64, X86Fmsubadd,
+ v2f64, v4f64>, VEX_W;
}
// Fused Negative Multiply-Add
let ExeDomain = SSEPackedSingle in {
- defm VFNMADDPS : fma3p_forms<0x9C, 0xAC, 0xBC, "vfnmadd", "ps", loadv4f32,
- loadv8f32, X86Fnmadd, v4f32, v8f32>;
- defm VFNMSUBPS : fma3p_forms<0x9E, 0xAE, 0xBE, "vfnmsub", "ps", loadv4f32,
- loadv8f32, X86Fnmsub, v4f32, v8f32>;
+ defm VFNMADD : fma3p_forms<0x9C, 0xAC, 0xBC, "vfnmadd", "ps", "PS", loadv4f32,
+ loadv8f32, X86Fnmadd, v4f32, v8f32>;
+ defm VFNMSUB : fma3p_forms<0x9E, 0xAE, 0xBE, "vfnmsub", "ps", "PS", loadv4f32,
+ loadv8f32, X86Fnmsub, v4f32, v8f32>;
}
let ExeDomain = SSEPackedDouble in {
- defm VFNMADDPD : fma3p_forms<0x9C, 0xAC, 0xBC, "vfnmadd", "pd", loadv2f64,
- loadv4f64, X86Fnmadd, v2f64, v4f64>, VEX_W;
- defm VFNMSUBPD : fma3p_forms<0x9E, 0xAE, 0xBE, "vfnmsub", "pd",
- loadv2f64, loadv4f64, X86Fnmsub, v2f64,
- v4f64>, VEX_W;
+ defm VFNMADD : fma3p_forms<0x9C, 0xAC, 0xBC, "vfnmadd", "pd", "PD", loadv2f64,
+ loadv4f64, X86Fnmadd, v2f64, v4f64>, VEX_W;
+ defm VFNMSUB : fma3p_forms<0x9E, 0xAE, 0xBE, "vfnmsub", "pd", "PD", loadv2f64,
+ loadv4f64, X86Fnmsub, v2f64, v4f64>, VEX_W;
}
// All source register operands of FMA opcodes defined in fma3s_rm multiclass
@@ -143,7 +142,6 @@ let Constraints = "$src1 = $dst", isCommutable = 1, hasSideEffects = 0 in
multiclass fma3s_rm<bits<8> opc, string OpcodeStr,
X86MemOperand x86memop, RegisterClass RC,
SDPatternOperator OpNode = null_frag> {
- let usesCustomInserter = 1 in
def r : FMA3<opc, MRMSrcReg, (outs RC:$dst),
(ins RC:$src1, RC:$src2, RC:$src3),
!strconcat(OpcodeStr,
@@ -191,13 +189,15 @@ multiclass fma3s_rm_int<bits<8> opc, string OpcodeStr,
}
multiclass fma3s_forms<bits<8> opc132, bits<8> opc213, bits<8> opc231,
- string OpStr, string PackTy,
+ string OpStr, string PackTy, string Suff,
SDNode OpNode, RegisterClass RC,
X86MemOperand x86memop> {
- defm r132 : fma3s_rm<opc132, !strconcat(OpStr, "132", PackTy), x86memop, RC>;
- defm r213 : fma3s_rm<opc213, !strconcat(OpStr, "213", PackTy), x86memop, RC,
- OpNode>;
- defm r231 : fma3s_rm<opc231, !strconcat(OpStr, "231", PackTy), x86memop, RC>;
+ defm NAME#132#Suff : fma3s_rm<opc132, !strconcat(OpStr, "132", PackTy),
+ x86memop, RC>;
+ defm NAME#213#Suff : fma3s_rm<opc213, !strconcat(OpStr, "213", PackTy),
+ x86memop, RC, OpNode>;
+ defm NAME#231#Suff : fma3s_rm<opc231, !strconcat(OpStr, "231", PackTy),
+ x86memop, RC>;
}
// The FMA 213 form is created for lowering of scalar FMA intrinscis
@@ -210,42 +210,45 @@ multiclass fma3s_forms<bits<8> opc132, bits<8> opc213, bits<8> opc231,
// form of FMA*_Int instructions is done using an optimistic assumption that
// such analysis will be implemented eventually.
multiclass fma3s_int_forms<bits<8> opc132, bits<8> opc213, bits<8> opc231,
- string OpStr, string PackTy,
+ string OpStr, string PackTy, string Suff,
RegisterClass RC, Operand memop> {
- defm r132 : fma3s_rm_int<opc132, !strconcat(OpStr, "132", PackTy),
- memop, RC>;
- defm r213 : fma3s_rm_int<opc213, !strconcat(OpStr, "213", PackTy),
- memop, RC>;
- defm r231 : fma3s_rm_int<opc231, !strconcat(OpStr, "231", PackTy),
- memop, RC>;
+ defm NAME#132#Suff : fma3s_rm_int<opc132, !strconcat(OpStr, "132", PackTy),
+ memop, RC>;
+ defm NAME#213#Suff : fma3s_rm_int<opc213, !strconcat(OpStr, "213", PackTy),
+ memop, RC>;
+ defm NAME#231#Suff : fma3s_rm_int<opc231, !strconcat(OpStr, "231", PackTy),
+ memop, RC>;
}
multiclass fma3s<bits<8> opc132, bits<8> opc213, bits<8> opc231,
string OpStr, Intrinsic IntF32, Intrinsic IntF64,
SDNode OpNode> {
let ExeDomain = SSEPackedSingle in
- defm SS : fma3s_forms<opc132, opc213, opc231, OpStr, "ss", OpNode,
- FR32, f32mem>,
- fma3s_int_forms<opc132, opc213, opc231, OpStr, "ss", VR128, ssmem>;
+ defm NAME : fma3s_forms<opc132, opc213, opc231, OpStr, "ss", "SS", OpNode,
+ FR32, f32mem>,
+ fma3s_int_forms<opc132, opc213, opc231, OpStr, "ss", "SS",
+ VR128, ssmem>;
let ExeDomain = SSEPackedDouble in
- defm SD : fma3s_forms<opc132, opc213, opc231, OpStr, "sd", OpNode,
+ defm NAME : fma3s_forms<opc132, opc213, opc231, OpStr, "sd", "SD", OpNode,
FR64, f64mem>,
- fma3s_int_forms<opc132, opc213, opc231, OpStr, "sd", VR128, sdmem>,
- VEX_W;
+ fma3s_int_forms<opc132, opc213, opc231, OpStr, "sd", "SD",
+ VR128, sdmem>, VEX_W;
// These patterns use the 123 ordering, instead of 213, even though
// they match the intrinsic to the 213 version of the instruction.
// This is because src1 is tied to dest, and the scalar intrinsics
// require the pass-through values to come from the first source
// operand, not the second.
- def : Pat<(IntF32 VR128:$src1, VR128:$src2, VR128:$src3),
- (COPY_TO_REGCLASS(!cast<Instruction>(NAME#"SSr213r_Int")
- $src1, $src2, $src3), VR128)>;
+ let Predicates = [HasFMA] in {
+ def : Pat<(IntF32 VR128:$src1, VR128:$src2, VR128:$src3),
+ (COPY_TO_REGCLASS(!cast<Instruction>(NAME#"213SSr_Int")
+ $src1, $src2, $src3), VR128)>;
- def : Pat<(IntF64 VR128:$src1, VR128:$src2, VR128:$src3),
- (COPY_TO_REGCLASS(!cast<Instruction>(NAME#"SDr213r_Int")
- $src1, $src2, $src3), VR128)>;
+ def : Pat<(IntF64 VR128:$src1, VR128:$src2, VR128:$src3),
+ (COPY_TO_REGCLASS(!cast<Instruction>(NAME#"213SDr_Int")
+ $src1, $src2, $src3), VR128)>;
+ }
}
defm VFMADD : fma3s<0x99, 0xA9, 0xB9, "vfmadd", int_x86_fma_vfmadd_ss,
@@ -268,18 +271,18 @@ multiclass fma4s<bits<8> opc, string OpcodeStr, RegisterClass RC,
X86MemOperand x86memop, ValueType OpVT, SDNode OpNode,
PatFrag mem_frag> {
let isCommutable = 1 in
- def rr : FMA4<opc, MRMSrcReg, (outs RC:$dst),
+ def rr : FMA4<opc, MRMSrcRegOp4, (outs RC:$dst),
(ins RC:$src1, RC:$src2, RC:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set RC:$dst,
- (OpVT (OpNode RC:$src1, RC:$src2, RC:$src3)))]>, VEX_W, VEX_LIG, MemOp4;
- def rm : FMA4<opc, MRMSrcMem, (outs RC:$dst),
+ (OpVT (OpNode RC:$src1, RC:$src2, RC:$src3)))]>, VEX_W, VEX_LIG;
+ def rm : FMA4<opc, MRMSrcMemOp4, (outs RC:$dst),
(ins RC:$src1, RC:$src2, x86memop:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set RC:$dst, (OpNode RC:$src1, RC:$src2,
- (mem_frag addr:$src3)))]>, VEX_W, VEX_LIG, MemOp4;
+ (mem_frag addr:$src3)))]>, VEX_W, VEX_LIG;
def mr : FMA4<opc, MRMSrcMem, (outs RC:$dst),
(ins RC:$src1, x86memop:$src2, RC:$src3),
!strconcat(OpcodeStr,
@@ -298,19 +301,18 @@ let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
multiclass fma4s_int<bits<8> opc, string OpcodeStr, Operand memop,
ComplexPattern mem_cpat, Intrinsic Int> {
let isCodeGenOnly = 1 in {
- let isCommutable = 1 in
- def rr_Int : FMA4<opc, MRMSrcReg, (outs VR128:$dst),
+ def rr_Int : FMA4<opc, MRMSrcRegOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
- (Int VR128:$src1, VR128:$src2, VR128:$src3))]>, VEX_W, VEX_LIG, MemOp4;
- def rm_Int : FMA4<opc, MRMSrcMem, (outs VR128:$dst),
+ (Int VR128:$src1, VR128:$src2, VR128:$src3))]>, VEX_W, VEX_LIG;
+ def rm_Int : FMA4<opc, MRMSrcMemOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, memop:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst, (Int VR128:$src1, VR128:$src2,
- mem_cpat:$src3))]>, VEX_W, VEX_LIG, MemOp4;
+ mem_cpat:$src3))]>, VEX_W, VEX_LIG;
def mr_Int : FMA4<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, memop:$src2, VR128:$src3),
!strconcat(OpcodeStr,
@@ -324,19 +326,19 @@ multiclass fma4p<bits<8> opc, string OpcodeStr, SDNode OpNode,
ValueType OpVT128, ValueType OpVT256,
PatFrag ld_frag128, PatFrag ld_frag256> {
let isCommutable = 1 in
- def rr : FMA4<opc, MRMSrcReg, (outs VR128:$dst),
+ def rr : FMA4<opc, MRMSrcRegOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(OpVT128 (OpNode VR128:$src1, VR128:$src2, VR128:$src3)))]>,
- VEX_W, MemOp4;
- def rm : FMA4<opc, MRMSrcMem, (outs VR128:$dst),
+ VEX_W;
+ def rm : FMA4<opc, MRMSrcMemOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, f128mem:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst, (OpNode VR128:$src1, VR128:$src2,
- (ld_frag128 addr:$src3)))]>, VEX_W, MemOp4;
+ (ld_frag128 addr:$src3)))]>, VEX_W;
def mr : FMA4<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, f128mem:$src2, VR128:$src3),
!strconcat(OpcodeStr,
@@ -344,20 +346,20 @@ multiclass fma4p<bits<8> opc, string OpcodeStr, SDNode OpNode,
[(set VR128:$dst,
(OpNode VR128:$src1, (ld_frag128 addr:$src2), VR128:$src3))]>;
let isCommutable = 1 in
- def rrY : FMA4<opc, MRMSrcReg, (outs VR256:$dst),
+ def Yrr : FMA4<opc, MRMSrcRegOp4, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR256:$dst,
(OpVT256 (OpNode VR256:$src1, VR256:$src2, VR256:$src3)))]>,
- VEX_W, MemOp4, VEX_L;
- def rmY : FMA4<opc, MRMSrcMem, (outs VR256:$dst),
+ VEX_W, VEX_L;
+ def Yrm : FMA4<opc, MRMSrcMemOp4, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, f256mem:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR256:$dst, (OpNode VR256:$src1, VR256:$src2,
- (ld_frag256 addr:$src3)))]>, VEX_W, MemOp4, VEX_L;
- def mrY : FMA4<opc, MRMSrcMem, (outs VR256:$dst),
+ (ld_frag256 addr:$src3)))]>, VEX_W, VEX_L;
+ def Ymr : FMA4<opc, MRMSrcMem, (outs VR256:$dst),
(ins VR256:$src1, f256mem:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
@@ -369,7 +371,7 @@ let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in {
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"), []>;
- def rrY_REV : FMA4<opc, MRMSrcReg, (outs VR256:$dst),
+ def Yrr_REV : FMA4<opc, MRMSrcReg, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"), []>,
diff --git a/contrib/llvm/lib/Target/X86/X86InstrFMA3Info.cpp b/contrib/llvm/lib/Target/X86/X86InstrFMA3Info.cpp
new file mode 100644
index 0000000..db83497
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86InstrFMA3Info.cpp
@@ -0,0 +1,285 @@
+//===-- X86InstrFMA3Info.cpp - X86 FMA3 Instruction Information -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of the classes providing information
+// about existing X86 FMA3 opcodes, classifying and grouping them.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86InstrFMA3Info.h"
+#include "X86InstrInfo.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Threading.h"
+using namespace llvm;
+
+/// This flag is used in the method llvm::call_once() used below to make the
+/// initialization of the map 'OpcodeToGroup' thread safe.
+LLVM_DEFINE_ONCE_FLAG(InitGroupsOnceFlag);
+
+static ManagedStatic<X86InstrFMA3Info> X86InstrFMA3InfoObj;
+X86InstrFMA3Info *X86InstrFMA3Info::getX86InstrFMA3Info() {
+ return &*X86InstrFMA3InfoObj;
+}
+
+void X86InstrFMA3Info::initRMGroup(const uint16_t *RegOpcodes,
+ const uint16_t *MemOpcodes, unsigned Attr) {
+ // Create a new instance of this class that would hold a group of FMA opcodes.
+ X86InstrFMA3Group *G = new X86InstrFMA3Group(RegOpcodes, MemOpcodes, Attr);
+
+ // Add the references from indvidual opcodes to the group holding them.
+ assert((!OpcodeToGroup[RegOpcodes[0]] && !OpcodeToGroup[RegOpcodes[1]] &&
+ !OpcodeToGroup[RegOpcodes[2]] && !OpcodeToGroup[MemOpcodes[0]] &&
+ !OpcodeToGroup[MemOpcodes[1]] && !OpcodeToGroup[MemOpcodes[2]]) &&
+ "Duplication or rewrite of elements in OpcodeToGroup.");
+ OpcodeToGroup[RegOpcodes[0]] = G;
+ OpcodeToGroup[RegOpcodes[1]] = G;
+ OpcodeToGroup[RegOpcodes[2]] = G;
+ OpcodeToGroup[MemOpcodes[0]] = G;
+ OpcodeToGroup[MemOpcodes[1]] = G;
+ OpcodeToGroup[MemOpcodes[2]] = G;
+}
+
+void X86InstrFMA3Info::initRGroup(const uint16_t *RegOpcodes, unsigned Attr) {
+ // Create a new instance of this class that would hold a group of FMA opcodes.
+ X86InstrFMA3Group *G = new X86InstrFMA3Group(RegOpcodes, nullptr, Attr);
+
+ // Add the references from indvidual opcodes to the group holding them.
+ assert((!OpcodeToGroup[RegOpcodes[0]] && !OpcodeToGroup[RegOpcodes[1]] &&
+ !OpcodeToGroup[RegOpcodes[2]]) &&
+ "Duplication or rewrite of elements in OpcodeToGroup.");
+ OpcodeToGroup[RegOpcodes[0]] = G;
+ OpcodeToGroup[RegOpcodes[1]] = G;
+ OpcodeToGroup[RegOpcodes[2]] = G;
+}
+
+void X86InstrFMA3Info::initMGroup(const uint16_t *MemOpcodes, unsigned Attr) {
+ // Create a new instance of this class that would hold a group of FMA opcodes.
+ X86InstrFMA3Group *G = new X86InstrFMA3Group(nullptr, MemOpcodes, Attr);
+
+ // Add the references from indvidual opcodes to the group holding them.
+ assert((!OpcodeToGroup[MemOpcodes[0]] && !OpcodeToGroup[MemOpcodes[1]] &&
+ !OpcodeToGroup[MemOpcodes[2]]) &&
+ "Duplication or rewrite of elements in OpcodeToGroup.");
+ OpcodeToGroup[MemOpcodes[0]] = G;
+ OpcodeToGroup[MemOpcodes[1]] = G;
+ OpcodeToGroup[MemOpcodes[2]] = G;
+}
+
+#define FMA3RM(R132, R213, R231, M132, M213, M231) \
+ static const uint16_t Reg##R132[3] = {X86::R132, X86::R213, X86::R231}; \
+ static const uint16_t Mem##R132[3] = {X86::M132, X86::M213, X86::M231}; \
+ initRMGroup(Reg##R132, Mem##R132);
+
+#define FMA3RMA(R132, R213, R231, M132, M213, M231, Attrs) \
+ static const uint16_t Reg##R132[3] = {X86::R132, X86::R213, X86::R231}; \
+ static const uint16_t Mem##R132[3] = {X86::M132, X86::M213, X86::M231}; \
+ initRMGroup(Reg##R132, Mem##R132, (Attrs));
+
+#define FMA3R(R132, R213, R231) \
+ static const uint16_t Reg##R132[3] = {X86::R132, X86::R213, X86::R231}; \
+ initRGroup(Reg##R132);
+
+#define FMA3RA(R132, R213, R231, Attrs) \
+ static const uint16_t Reg##R132[3] = {X86::R132, X86::R213, X86::R231}; \
+ initRGroup(Reg##R132, (Attrs));
+
+#define FMA3M(M132, M213, M231) \
+ static const uint16_t Mem##M132[3] = {X86::M132, X86::M213, X86::M231}; \
+ initMGroup(Mem##M132);
+
+#define FMA3MA(M132, M213, M231, Attrs) \
+ static const uint16_t Mem##M132[3] = {X86::M132, X86::M213, X86::M231}; \
+ initMGroup(Mem##M132, (Attrs));
+
+#define FMA3_AVX2_VECTOR_GROUP(Name) \
+ FMA3RM(Name##132PSr, Name##213PSr, Name##231PSr, \
+ Name##132PSm, Name##213PSm, Name##231PSm); \
+ FMA3RM(Name##132PDr, Name##213PDr, Name##231PDr, \
+ Name##132PDm, Name##213PDm, Name##231PDm); \
+ FMA3RM(Name##132PSYr, Name##213PSYr, Name##231PSYr, \
+ Name##132PSYm, Name##213PSYm, Name##231PSYm); \
+ FMA3RM(Name##132PDYr, Name##213PDYr, Name##231PDYr, \
+ Name##132PDYm, Name##213PDYm, Name##231PDYm);
+
+#define FMA3_AVX2_SCALAR_GROUP(Name) \
+ FMA3RM(Name##132SSr, Name##213SSr, Name##231SSr, \
+ Name##132SSm, Name##213SSm, Name##231SSm); \
+ FMA3RM(Name##132SDr, Name##213SDr, Name##231SDr, \
+ Name##132SDm, Name##213SDm, Name##231SDm); \
+ FMA3RMA(Name##132SSr_Int, Name##213SSr_Int, Name##231SSr_Int, \
+ Name##132SSm_Int, Name##213SSm_Int, Name##231SSm_Int, \
+ X86InstrFMA3Group::X86FMA3Intrinsic); \
+ FMA3RMA(Name##132SDr_Int, Name##213SDr_Int, Name##231SDr_Int, \
+ Name##132SDm_Int, Name##213SDm_Int, Name##231SDm_Int, \
+ X86InstrFMA3Group::X86FMA3Intrinsic);
+
+#define FMA3_AVX2_FULL_GROUP(Name) \
+ FMA3_AVX2_VECTOR_GROUP(Name); \
+ FMA3_AVX2_SCALAR_GROUP(Name);
+
+#define FMA3_AVX512_VECTOR_GROUP(Name) \
+ FMA3RM(Name##132PSZ128r, Name##213PSZ128r, Name##231PSZ128r, \
+ Name##132PSZ128m, Name##213PSZ128m, Name##231PSZ128m); \
+ FMA3RM(Name##132PDZ128r, Name##213PDZ128r, Name##231PDZ128r, \
+ Name##132PDZ128m, Name##213PDZ128m, Name##231PDZ128m); \
+ FMA3RM(Name##132PSZ256r, Name##213PSZ256r, Name##231PSZ256r, \
+ Name##132PSZ256m, Name##213PSZ256m, Name##231PSZ256m); \
+ FMA3RM(Name##132PDZ256r, Name##213PDZ256r, Name##231PDZ256r, \
+ Name##132PDZ256m, Name##213PDZ256m, Name##231PDZ256m); \
+ FMA3RM(Name##132PSZr, Name##213PSZr, Name##231PSZr, \
+ Name##132PSZm, Name##213PSZm, Name##231PSZm); \
+ FMA3RM(Name##132PDZr, Name##213PDZr, Name##231PDZr, \
+ Name##132PDZm, Name##213PDZm, Name##231PDZm); \
+ FMA3RMA(Name##132PSZ128rk, Name##213PSZ128rk, Name##231PSZ128rk, \
+ Name##132PSZ128mk, Name##213PSZ128mk, Name##231PSZ128mk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132PDZ128rk, Name##213PDZ128rk, Name##231PDZ128rk, \
+ Name##132PDZ128mk, Name##213PDZ128mk, Name##231PDZ128mk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132PSZ256rk, Name##213PSZ256rk, Name##231PSZ256rk, \
+ Name##132PSZ256mk, Name##213PSZ256mk, Name##231PSZ256mk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132PDZ256rk, Name##213PDZ256rk, Name##231PDZ256rk, \
+ Name##132PDZ256mk, Name##213PDZ256mk, Name##231PDZ256mk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132PSZrk, Name##213PSZrk, Name##231PSZrk, \
+ Name##132PSZmk, Name##213PSZmk, Name##231PSZmk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132PDZrk, Name##213PDZrk, Name##231PDZrk, \
+ Name##132PDZmk, Name##213PDZmk, Name##231PDZmk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132PSZ128rkz, Name##213PSZ128rkz, Name##231PSZ128rkz, \
+ Name##132PSZ128mkz, Name##213PSZ128mkz, Name##231PSZ128mkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RMA(Name##132PDZ128rkz, Name##213PDZ128rkz, Name##231PDZ128rkz, \
+ Name##132PDZ128mkz, Name##213PDZ128mkz, Name##231PDZ128mkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RMA(Name##132PSZ256rkz, Name##213PSZ256rkz, Name##231PSZ256rkz, \
+ Name##132PSZ256mkz, Name##213PSZ256mkz, Name##231PSZ256mkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RMA(Name##132PDZ256rkz, Name##213PDZ256rkz, Name##231PDZ256rkz, \
+ Name##132PDZ256mkz, Name##213PDZ256mkz, Name##231PDZ256mkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RMA(Name##132PSZrkz, Name##213PSZrkz, Name##231PSZrkz, \
+ Name##132PSZmkz, Name##213PSZmkz, Name##231PSZmkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RMA(Name##132PDZrkz, Name##213PDZrkz, Name##231PDZrkz, \
+ Name##132PDZmkz, Name##213PDZmkz, Name##231PDZmkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3R(Name##132PSZrb, Name##213PSZrb, Name##231PSZrb); \
+ FMA3R(Name##132PDZrb, Name##213PDZrb, Name##231PDZrb); \
+ FMA3RA(Name##132PSZrbk, Name##213PSZrbk, Name##231PSZrbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RA(Name##132PDZrbk, Name##213PDZrbk, Name##231PDZrbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RA(Name##132PSZrbkz, Name##213PSZrbkz, Name##231PSZrbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RA(Name##132PDZrbkz, Name##213PDZrbkz, Name##231PDZrbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3M(Name##132PSZ128mb, Name##213PSZ128mb, Name##231PSZ128mb); \
+ FMA3M(Name##132PDZ128mb, Name##213PDZ128mb, Name##231PDZ128mb); \
+ FMA3M(Name##132PSZ256mb, Name##213PSZ256mb, Name##231PSZ256mb); \
+ FMA3M(Name##132PDZ256mb, Name##213PDZ256mb, Name##231PDZ256mb); \
+ FMA3M(Name##132PSZmb, Name##213PSZmb, Name##231PSZmb); \
+ FMA3M(Name##132PDZmb, Name##213PDZmb, Name##231PDZmb); \
+ FMA3MA(Name##132PSZ128mbk, Name##213PSZ128mbk, Name##231PSZ128mbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3MA(Name##132PDZ128mbk, Name##213PDZ128mbk, Name##231PDZ128mbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3MA(Name##132PSZ256mbk, Name##213PSZ256mbk, Name##231PSZ256mbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3MA(Name##132PDZ256mbk, Name##213PDZ256mbk, Name##231PDZ256mbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3MA(Name##132PSZmbk, Name##213PSZmbk, Name##231PSZmbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3MA(Name##132PDZmbk, Name##213PDZmbk, Name##231PDZmbk, \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3MA(Name##132PSZ128mbkz, Name##213PSZ128mbkz, Name##231PSZ128mbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3MA(Name##132PDZ128mbkz, Name##213PDZ128mbkz, Name##231PDZ128mbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3MA(Name##132PSZ256mbkz, Name##213PSZ256mbkz, Name##231PSZ256mbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3MA(Name##132PDZ256mbkz, Name##213PDZ256mbkz, Name##231PDZ256mbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3MA(Name##132PSZmbkz, Name##213PSZmbkz, Name##231PSZmbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3MA(Name##132PDZmbkz, Name##213PDZmbkz, Name##231PDZmbkz, \
+ X86InstrFMA3Group::X86FMA3KZeroMasked);
+
+#define FMA3_AVX512_SCALAR_GROUP(Name) \
+ FMA3RM(Name##132SSZr, Name##213SSZr, Name##231SSZr, \
+ Name##132SSZm, Name##213SSZm, Name##231SSZm); \
+ FMA3RM(Name##132SDZr, Name##213SDZr, Name##231SDZr, \
+ Name##132SDZm, Name##213SDZm, Name##231SDZm); \
+ FMA3RMA(Name##132SSZr_Int, Name##213SSZr_Int, Name##231SSZr_Int, \
+ Name##132SSZm_Int, Name##213SSZm_Int, Name##231SSZm_Int, \
+ X86InstrFMA3Group::X86FMA3Intrinsic); \
+ FMA3RMA(Name##132SDZr_Int, Name##213SDZr_Int, Name##231SDZr_Int, \
+ Name##132SDZm_Int, Name##213SDZm_Int, Name##231SDZm_Int, \
+ X86InstrFMA3Group::X86FMA3Intrinsic); \
+ FMA3RMA(Name##132SSZr_Intk, Name##213SSZr_Intk, Name##231SSZr_Intk, \
+ Name##132SSZm_Intk, Name##213SSZm_Intk, Name##231SSZm_Intk, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132SDZr_Intk, Name##213SDZr_Intk, Name##231SDZr_Intk, \
+ Name##132SDZm_Intk, Name##213SDZm_Intk, Name##231SDZm_Intk, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RMA(Name##132SSZr_Intkz, Name##213SSZr_Intkz, Name##231SSZr_Intkz, \
+ Name##132SSZm_Intkz, Name##213SSZm_Intkz, Name##231SSZm_Intkz, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RMA(Name##132SDZr_Intkz, Name##213SDZr_Intkz, Name##231SDZr_Intkz, \
+ Name##132SDZm_Intkz, Name##213SDZm_Intkz, Name##231SDZm_Intkz, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RA(Name##132SSZrb_Int, Name##213SSZrb_Int, Name##231SSZrb_Int, \
+ X86InstrFMA3Group::X86FMA3Intrinsic); \
+ FMA3RA(Name##132SDZrb_Int, Name##213SDZrb_Int, Name##231SDZrb_Int, \
+ X86InstrFMA3Group::X86FMA3Intrinsic); \
+ FMA3RA(Name##132SSZrb_Intk, Name##213SSZrb_Intk, Name##231SSZrb_Intk, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RA(Name##132SDZrb_Intk, Name##213SDZrb_Intk, Name##231SDZrb_Intk, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KMergeMasked); \
+ FMA3RA(Name##132SSZrb_Intkz, Name##213SSZrb_Intkz, Name##231SSZrb_Intkz, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KZeroMasked); \
+ FMA3RA(Name##132SDZrb_Intkz, Name##213SDZrb_Intkz, Name##231SDZrb_Intkz, \
+ X86InstrFMA3Group::X86FMA3Intrinsic | \
+ X86InstrFMA3Group::X86FMA3KZeroMasked);
+
+#define FMA3_AVX512_FULL_GROUP(Name) \
+ FMA3_AVX512_VECTOR_GROUP(Name); \
+ FMA3_AVX512_SCALAR_GROUP(Name);
+
+void X86InstrFMA3Info::initGroupsOnceImpl() {
+ FMA3_AVX2_FULL_GROUP(VFMADD);
+ FMA3_AVX2_FULL_GROUP(VFMSUB);
+ FMA3_AVX2_FULL_GROUP(VFNMADD);
+ FMA3_AVX2_FULL_GROUP(VFNMSUB);
+
+ FMA3_AVX2_VECTOR_GROUP(VFMADDSUB);
+ FMA3_AVX2_VECTOR_GROUP(VFMSUBADD);
+
+ FMA3_AVX512_FULL_GROUP(VFMADD);
+ FMA3_AVX512_FULL_GROUP(VFMSUB);
+ FMA3_AVX512_FULL_GROUP(VFNMADD);
+ FMA3_AVX512_FULL_GROUP(VFNMSUB);
+
+ FMA3_AVX512_VECTOR_GROUP(VFMADDSUB);
+ FMA3_AVX512_VECTOR_GROUP(VFMSUBADD);
+}
+
+void X86InstrFMA3Info::initGroupsOnce() {
+ llvm::call_once(InitGroupsOnceFlag,
+ []() { getX86InstrFMA3Info()->initGroupsOnceImpl(); });
+}
diff --git a/contrib/llvm/lib/Target/X86/X86InstrFMA3Info.h b/contrib/llvm/lib/Target/X86/X86InstrFMA3Info.h
new file mode 100644
index 0000000..025cee3
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86InstrFMA3Info.h
@@ -0,0 +1,315 @@
+//===-- X86InstrFMA3Info.h - X86 FMA3 Instruction Information -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of the classes providing information
+// about existing X86 FMA3 opcodes, classifying and grouping them.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
+#define LLVM_LIB_TARGET_X86_UTILS_X86INSTRFMA3INFO_H
+
+#include "X86.h"
+#include "llvm/ADT/DenseMap.h"
+#include <cassert>
+#include <set>
+
+namespace llvm {
+/// This class is used to group {132, 213, 231} forms of FMA opcodes together.
+/// Each of the groups has either 3 register opcodes, 3 memory opcodes,
+/// or 6 register and memory opcodes. Also, each group has an attrubutes field
+/// describing it.
+class X86InstrFMA3Group {
+private:
+ /// Reference to an array holding 3 forms of register FMA opcodes.
+ /// It may be set to nullptr if the group of FMA opcodes does not have
+ /// any register form opcodes.
+ const uint16_t *RegOpcodes;
+
+ /// Reference to an array holding 3 forms of memory FMA opcodes.
+ /// It may be set to nullptr if the group of FMA opcodes does not have
+ /// any register form opcodes.
+ const uint16_t *MemOpcodes;
+
+ /// This bitfield specifies the attributes associated with the created
+ /// FMA groups of opcodes.
+ unsigned Attributes;
+
+ static const unsigned Form132 = 0;
+ static const unsigned Form213 = 1;
+ static const unsigned Form231 = 2;
+
+public:
+ /// This bit must be set in the 'Attributes' field of FMA group if such
+ /// group of FMA opcodes consists of FMA intrinsic opcodes.
+ static const unsigned X86FMA3Intrinsic = 0x1;
+
+ /// This bit must be set in the 'Attributes' field of FMA group if such
+ /// group of FMA opcodes consists of AVX512 opcodes accepting a k-mask and
+ /// passing the elements from the 1st operand to the result of the operation
+ /// when the correpondings bits in the k-mask are unset.
+ static const unsigned X86FMA3KMergeMasked = 0x2;
+
+ /// This bit must be set in the 'Attributes' field of FMA group if such
+ /// group of FMA opcodes consists of AVX512 opcodes accepting a k-zeromask.
+ static const unsigned X86FMA3KZeroMasked = 0x4;
+
+ /// Constructor. Creates a new group of FMA opcodes with three register form
+ /// FMA opcodes \p RegOpcodes and three memory form FMA opcodes \p MemOpcodes.
+ /// The parameters \p RegOpcodes and \p MemOpcodes may be set to nullptr,
+ /// which means that the created group of FMA opcodes does not have the
+ /// corresponding (register or memory) opcodes.
+ /// The parameter \p Attr specifies the attributes describing the created
+ /// group.
+ X86InstrFMA3Group(const uint16_t *RegOpcodes, const uint16_t *MemOpcodes,
+ unsigned Attr)
+ : RegOpcodes(RegOpcodes), MemOpcodes(MemOpcodes), Attributes(Attr) {
+ assert((RegOpcodes || MemOpcodes) &&
+ "Cannot create a group not having any opcodes.");
+ }
+
+ /// Returns a memory form opcode that is the equivalent of the given register
+ /// form opcode \p RegOpcode. 0 is returned if the group does not have
+ /// either register of memory opcodes.
+ unsigned getMemOpcode(unsigned RegOpcode) const {
+ if (!RegOpcodes || !MemOpcodes)
+ return 0;
+ for (unsigned Form = 0; Form < 3; Form++)
+ if (RegOpcodes[Form] == RegOpcode)
+ return MemOpcodes[Form];
+ return 0;
+ }
+
+ /// Returns the 132 form of FMA register opcode.
+ unsigned getReg132Opcode() const {
+ assert(RegOpcodes && "The group does not have register opcodes.");
+ return RegOpcodes[Form132];
+ }
+
+ /// Returns the 213 form of FMA register opcode.
+ unsigned getReg213Opcode() const {
+ assert(RegOpcodes && "The group does not have register opcodes.");
+ return RegOpcodes[Form213];
+ }
+
+ /// Returns the 231 form of FMA register opcode.
+ unsigned getReg231Opcode() const {
+ assert(RegOpcodes && "The group does not have register opcodes.");
+ return RegOpcodes[Form231];
+ }
+
+ /// Returns the 132 form of FMA memory opcode.
+ unsigned getMem132Opcode() const {
+ assert(MemOpcodes && "The group does not have memory opcodes.");
+ return MemOpcodes[Form132];
+ }
+
+ /// Returns the 213 form of FMA memory opcode.
+ unsigned getMem213Opcode() const {
+ assert(MemOpcodes && "The group does not have memory opcodes.");
+ return MemOpcodes[Form213];
+ }
+
+ /// Returns the 231 form of FMA memory opcode.
+ unsigned getMem231Opcode() const {
+ assert(MemOpcodes && "The group does not have memory opcodes.");
+ return MemOpcodes[Form231];
+ }
+
+ /// Returns true iff the group of FMA opcodes holds intrinsic opcodes.
+ bool isIntrinsic() const { return (Attributes & X86FMA3Intrinsic) != 0; }
+
+ /// Returns true iff the group of FMA opcodes holds k-merge-masked opcodes.
+ bool isKMergeMasked() const {
+ return (Attributes & X86FMA3KMergeMasked) != 0;
+ }
+
+ /// Returns true iff the group of FMA opcodes holds k-zero-masked opcodes.
+ bool isKZeroMasked() const { return (Attributes & X86FMA3KZeroMasked) != 0; }
+
+ /// Returns true iff the group of FMA opcodes holds any of k-masked opcodes.
+ bool isKMasked() const {
+ return (Attributes & (X86FMA3KMergeMasked | X86FMA3KZeroMasked)) != 0;
+ }
+
+ /// Returns true iff the given \p Opcode is a register opcode from the
+ /// groups of FMA opcodes.
+ bool isRegOpcodeFromGroup(unsigned Opcode) const {
+ if (!RegOpcodes)
+ return false;
+ for (unsigned Form = 0; Form < 3; Form++)
+ if (Opcode == RegOpcodes[Form])
+ return true;
+ return false;
+ }
+
+ /// Returns true iff the given \p Opcode is a memory opcode from the
+ /// groups of FMA opcodes.
+ bool isMemOpcodeFromGroup(unsigned Opcode) const {
+ if (!MemOpcodes)
+ return false;
+ for (unsigned Form = 0; Form < 3; Form++)
+ if (Opcode == MemOpcodes[Form])
+ return true;
+ return false;
+ }
+};
+
+/// This class provides information about all existing FMA3 opcodes
+///
+class X86InstrFMA3Info {
+private:
+ /// A map that is used to find the group of FMA opcodes using any FMA opcode
+ /// from the group.
+ DenseMap<unsigned, const X86InstrFMA3Group *> OpcodeToGroup;
+
+ /// Creates groups of FMA opcodes and initializes Opcode-to-Group map.
+ /// This method can be called many times, but the actual initialization is
+ /// called only once.
+ static void initGroupsOnce();
+
+ /// Creates groups of FMA opcodes and initializes Opcode-to-Group map.
+ /// This method must be called ONLY from initGroupsOnce(). Otherwise, such
+ /// call is not thread safe.
+ void initGroupsOnceImpl();
+
+ /// Creates one group of FMA opcodes having the register opcodes
+ /// \p RegOpcodes and memory opcodes \p MemOpcodes. The parameter \p Attr
+ /// specifies the attributes describing the created group.
+ void initRMGroup(const uint16_t *RegOpcodes,
+ const uint16_t *MemOpcodes, unsigned Attr = 0);
+
+ /// Creates one group of FMA opcodes having only the register opcodes
+ /// \p RegOpcodes. The parameter \p Attr specifies the attributes describing
+ /// the created group.
+ void initRGroup(const uint16_t *RegOpcodes, unsigned Attr = 0);
+
+ /// Creates one group of FMA opcodes having only the memory opcodes
+ /// \p MemOpcodes. The parameter \p Attr specifies the attributes describing
+ /// the created group.
+ void initMGroup(const uint16_t *MemOpcodes, unsigned Attr = 0);
+
+public:
+ /// Returns the reference to an object of this class. It is assumed that
+ /// only one object may exist.
+ static X86InstrFMA3Info *getX86InstrFMA3Info();
+
+ /// Constructor. Just creates an object of the class.
+ X86InstrFMA3Info() {}
+
+ /// Destructor. Deallocates the memory used for FMA3 Groups.
+ ~X86InstrFMA3Info() {
+ std::set<const X86InstrFMA3Group *> DeletedGroups;
+ auto E = OpcodeToGroup.end();
+ for (auto I = OpcodeToGroup.begin(); I != E; I++) {
+ const X86InstrFMA3Group *G = I->second;
+ if (DeletedGroups.find(G) == DeletedGroups.end()) {
+ DeletedGroups.insert(G);
+ delete G;
+ }
+ }
+ }
+
+ /// Returns a reference to a group of FMA3 opcodes to where the given
+ /// \p Opcode is included. If the given \p Opcode is not recognized as FMA3
+ /// and not included into any FMA3 group, then nullptr is returned.
+ static const X86InstrFMA3Group *getFMA3Group(unsigned Opcode) {
+ // Ensure that the groups of opcodes are initialized.
+ initGroupsOnce();
+
+ // Find the group including the given opcode.
+ const X86InstrFMA3Info *FMA3Info = getX86InstrFMA3Info();
+ auto I = FMA3Info->OpcodeToGroup.find(Opcode);
+ if (I == FMA3Info->OpcodeToGroup.end())
+ return nullptr;
+
+ return I->second;
+ }
+
+ /// Returns true iff the given \p Opcode is recognized as FMA3 by this class.
+ static bool isFMA3(unsigned Opcode) {
+ return getFMA3Group(Opcode) != nullptr;
+ }
+
+ /// Iterator that is used to walk on FMA register opcodes having memory
+ /// form equivalents.
+ class rm_iterator {
+ private:
+ /// Iterator associated with the OpcodeToGroup map. It must always be
+ /// initialized with an entry from OpcodeToGroup for which I->first
+ /// points to a register FMA opcode and I->second points to a group of
+ /// FMA opcodes having memory form equivalent of I->first.
+ DenseMap<unsigned, const X86InstrFMA3Group *>::const_iterator I;
+
+ public:
+ /// Constructor. Creates rm_iterator. The parameter \p I must be an
+ /// iterator to OpcodeToGroup map entry having I->first pointing to
+ /// register form FMA opcode and I->second pointing to a group of FMA
+ /// opcodes holding memory form equivalent for I->fist.
+ rm_iterator(DenseMap<unsigned, const X86InstrFMA3Group *>::const_iterator I)
+ : I(I) {}
+
+ /// Returns the register form FMA opcode.
+ unsigned getRegOpcode() const { return I->first; };
+
+ /// Returns the memory form equivalent opcode for FMA register opcode
+ /// referenced by I->first.
+ unsigned getMemOpcode() const {
+ unsigned Opcode = I->first;
+ const X86InstrFMA3Group *Group = I->second;
+ return Group->getMemOpcode(Opcode);
+ }
+
+ /// Returns a reference to a group of FMA opcodes.
+ const X86InstrFMA3Group *getGroup() const { return I->second; }
+
+ bool operator==(const rm_iterator &OtherIt) const { return I == OtherIt.I; }
+ bool operator!=(const rm_iterator &OtherIt) const { return I != OtherIt.I; }
+
+ /// Increment. Advances the 'I' iterator to the next OpcodeToGroup entry
+ /// having I->first pointing to register form FMA and I->second pointing
+ /// to a group of FMA opcodes holding memory form equivalen for I->first.
+ rm_iterator &operator++() {
+ auto E = getX86InstrFMA3Info()->OpcodeToGroup.end();
+ for (++I; I != E; ++I) {
+ unsigned RegOpcode = I->first;
+ const X86InstrFMA3Group *Group = I->second;
+ if (Group->getMemOpcode(RegOpcode) != 0)
+ break;
+ }
+ return *this;
+ }
+ };
+
+ /// Returns rm_iterator pointing to the first entry of OpcodeToGroup map
+ /// with a register FMA opcode having memory form opcode equivalent.
+ static rm_iterator rm_begin() {
+ initGroupsOnce();
+ const X86InstrFMA3Info *FMA3Info = getX86InstrFMA3Info();
+ auto I = FMA3Info->OpcodeToGroup.begin();
+ auto E = FMA3Info->OpcodeToGroup.end();
+ while (I != E) {
+ unsigned Opcode = I->first;
+ const X86InstrFMA3Group *G = I->second;
+ if (G->getMemOpcode(Opcode) != 0)
+ break;
+ I++;
+ }
+ return rm_iterator(I);
+ }
+
+ /// Returns the last rm_iterator.
+ static rm_iterator rm_end() {
+ initGroupsOnce();
+ return rm_iterator(getX86InstrFMA3Info()->OpcodeToGroup.end());
+ }
+};
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/X86/X86InstrFPStack.td b/contrib/llvm/lib/Target/X86/X86InstrFPStack.td
index 078dab4..10f3839 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrFPStack.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrFPStack.td
@@ -711,19 +711,19 @@ def : Pat<(X86fildflag addr:$src, i64), (ILD_Fp64m64 addr:$src)>;
// FP extensions map onto simple pseudo-value conversions if they are to/from
// the FP stack.
-def : Pat<(f64 (fextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP64)>,
+def : Pat<(f64 (fpextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP64)>,
Requires<[FPStackf32]>;
-def : Pat<(f80 (fextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP80)>,
+def : Pat<(f80 (fpextend RFP32:$src)), (COPY_TO_REGCLASS RFP32:$src, RFP80)>,
Requires<[FPStackf32]>;
-def : Pat<(f80 (fextend RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP80)>,
+def : Pat<(f80 (fpextend RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP80)>,
Requires<[FPStackf64]>;
// FP truncations map onto simple pseudo-value conversions if they are to/from
// the FP stack. We have validated that only value-preserving truncations make
// it through isel.
-def : Pat<(f32 (fround RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP32)>,
+def : Pat<(f32 (fpround RFP64:$src)), (COPY_TO_REGCLASS RFP64:$src, RFP32)>,
Requires<[FPStackf32]>;
-def : Pat<(f32 (fround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP32)>,
+def : Pat<(f32 (fpround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP32)>,
Requires<[FPStackf32]>;
-def : Pat<(f64 (fround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP64)>,
+def : Pat<(f64 (fpround RFP80:$src)), (COPY_TO_REGCLASS RFP80:$src, RFP64)>,
Requires<[FPStackf64]>;
diff --git a/contrib/llvm/lib/Target/X86/X86InstrFormats.td b/contrib/llvm/lib/Target/X86/X86InstrFormats.td
index 5183adc..610756a 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrFormats.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrFormats.td
@@ -18,43 +18,53 @@ class Format<bits<7> val> {
bits<7> Value = val;
}
-def Pseudo : Format<0>; def RawFrm : Format<1>;
-def AddRegFrm : Format<2>; def MRMDestReg : Format<3>;
-def MRMDestMem : Format<4>; def MRMSrcReg : Format<5>;
-def MRMSrcMem : Format<6>; def RawFrmMemOffs : Format<7>;
-def RawFrmSrc : Format<8>; def RawFrmDst : Format<9>;
-def RawFrmDstSrc: Format<10>;
-def RawFrmImm8 : Format<11>;
-def RawFrmImm16 : Format<12>;
-def MRMXr : Format<14>; def MRMXm : Format<15>;
-def MRM0r : Format<16>; def MRM1r : Format<17>; def MRM2r : Format<18>;
-def MRM3r : Format<19>; def MRM4r : Format<20>; def MRM5r : Format<21>;
-def MRM6r : Format<22>; def MRM7r : Format<23>;
-def MRM0m : Format<24>; def MRM1m : Format<25>; def MRM2m : Format<26>;
-def MRM3m : Format<27>; def MRM4m : Format<28>; def MRM5m : Format<29>;
-def MRM6m : Format<30>; def MRM7m : Format<31>;
-def MRM_C0 : Format<32>; def MRM_C1 : Format<33>; def MRM_C2 : Format<34>;
-def MRM_C3 : Format<35>; def MRM_C4 : Format<36>; def MRM_C5 : Format<37>;
-def MRM_C6 : Format<38>; def MRM_C7 : Format<39>; def MRM_C8 : Format<40>;
-def MRM_C9 : Format<41>; def MRM_CA : Format<42>; def MRM_CB : Format<43>;
-def MRM_CC : Format<44>; def MRM_CD : Format<45>; def MRM_CE : Format<46>;
-def MRM_CF : Format<47>; def MRM_D0 : Format<48>; def MRM_D1 : Format<49>;
-def MRM_D2 : Format<50>; def MRM_D3 : Format<51>; def MRM_D4 : Format<52>;
-def MRM_D5 : Format<53>; def MRM_D6 : Format<54>; def MRM_D7 : Format<55>;
-def MRM_D8 : Format<56>; def MRM_D9 : Format<57>; def MRM_DA : Format<58>;
-def MRM_DB : Format<59>; def MRM_DC : Format<60>; def MRM_DD : Format<61>;
-def MRM_DE : Format<62>; def MRM_DF : Format<63>; def MRM_E0 : Format<64>;
-def MRM_E1 : Format<65>; def MRM_E2 : Format<66>; def MRM_E3 : Format<67>;
-def MRM_E4 : Format<68>; def MRM_E5 : Format<69>; def MRM_E6 : Format<70>;
-def MRM_E7 : Format<71>; def MRM_E8 : Format<72>; def MRM_E9 : Format<73>;
-def MRM_EA : Format<74>; def MRM_EB : Format<75>; def MRM_EC : Format<76>;
-def MRM_ED : Format<77>; def MRM_EE : Format<78>; def MRM_EF : Format<79>;
-def MRM_F0 : Format<80>; def MRM_F1 : Format<81>; def MRM_F2 : Format<82>;
-def MRM_F3 : Format<83>; def MRM_F4 : Format<84>; def MRM_F5 : Format<85>;
-def MRM_F6 : Format<86>; def MRM_F7 : Format<87>; def MRM_F8 : Format<88>;
-def MRM_F9 : Format<89>; def MRM_FA : Format<90>; def MRM_FB : Format<91>;
-def MRM_FC : Format<92>; def MRM_FD : Format<93>; def MRM_FE : Format<94>;
-def MRM_FF : Format<95>;
+def Pseudo : Format<0>;
+def RawFrm : Format<1>;
+def AddRegFrm : Format<2>;
+def RawFrmMemOffs : Format<3>;
+def RawFrmSrc : Format<4>;
+def RawFrmDst : Format<5>;
+def RawFrmDstSrc : Format<6>;
+def RawFrmImm8 : Format<7>;
+def RawFrmImm16 : Format<8>;
+def MRMDestMem : Format<32>;
+def MRMSrcMem : Format<33>;
+def MRMSrcMem4VOp3 : Format<34>;
+def MRMSrcMemOp4 : Format<35>;
+def MRMXm : Format<39>;
+def MRM0m : Format<40>; def MRM1m : Format<41>; def MRM2m : Format<42>;
+def MRM3m : Format<43>; def MRM4m : Format<44>; def MRM5m : Format<45>;
+def MRM6m : Format<46>; def MRM7m : Format<47>;
+def MRMDestReg : Format<48>;
+def MRMSrcReg : Format<49>;
+def MRMSrcReg4VOp3 : Format<50>;
+def MRMSrcRegOp4 : Format<51>;
+def MRMXr : Format<55>;
+def MRM0r : Format<56>; def MRM1r : Format<57>; def MRM2r : Format<58>;
+def MRM3r : Format<59>; def MRM4r : Format<60>; def MRM5r : Format<61>;
+def MRM6r : Format<62>; def MRM7r : Format<63>;
+def MRM_C0 : Format<64>; def MRM_C1 : Format<65>; def MRM_C2 : Format<66>;
+def MRM_C3 : Format<67>; def MRM_C4 : Format<68>; def MRM_C5 : Format<69>;
+def MRM_C6 : Format<70>; def MRM_C7 : Format<71>; def MRM_C8 : Format<72>;
+def MRM_C9 : Format<73>; def MRM_CA : Format<74>; def MRM_CB : Format<75>;
+def MRM_CC : Format<76>; def MRM_CD : Format<77>; def MRM_CE : Format<78>;
+def MRM_CF : Format<79>; def MRM_D0 : Format<80>; def MRM_D1 : Format<81>;
+def MRM_D2 : Format<82>; def MRM_D3 : Format<83>; def MRM_D4 : Format<84>;
+def MRM_D5 : Format<85>; def MRM_D6 : Format<86>; def MRM_D7 : Format<87>;
+def MRM_D8 : Format<88>; def MRM_D9 : Format<89>; def MRM_DA : Format<90>;
+def MRM_DB : Format<91>; def MRM_DC : Format<92>; def MRM_DD : Format<93>;
+def MRM_DE : Format<94>; def MRM_DF : Format<95>; def MRM_E0 : Format<96>;
+def MRM_E1 : Format<97>; def MRM_E2 : Format<98>; def MRM_E3 : Format<99>;
+def MRM_E4 : Format<100>; def MRM_E5 : Format<101>; def MRM_E6 : Format<102>;
+def MRM_E7 : Format<103>; def MRM_E8 : Format<104>; def MRM_E9 : Format<105>;
+def MRM_EA : Format<106>; def MRM_EB : Format<107>; def MRM_EC : Format<108>;
+def MRM_ED : Format<109>; def MRM_EE : Format<110>; def MRM_EF : Format<111>;
+def MRM_F0 : Format<112>; def MRM_F1 : Format<113>; def MRM_F2 : Format<114>;
+def MRM_F3 : Format<115>; def MRM_F4 : Format<116>; def MRM_F5 : Format<117>;
+def MRM_F6 : Format<118>; def MRM_F7 : Format<119>; def MRM_F8 : Format<120>;
+def MRM_F9 : Format<121>; def MRM_FA : Format<122>; def MRM_FB : Format<123>;
+def MRM_FC : Format<124>; def MRM_FD : Format<125>; def MRM_FE : Format<126>;
+def MRM_FF : Format<127>;
// ImmType - This specifies the immediate type used by an instruction. This is
// part of the ad-hoc solution used to emit machine instruction encodings by our
@@ -65,12 +75,13 @@ class ImmType<bits<4> val> {
def NoImm : ImmType<0>;
def Imm8 : ImmType<1>;
def Imm8PCRel : ImmType<2>;
-def Imm16 : ImmType<3>;
-def Imm16PCRel : ImmType<4>;
-def Imm32 : ImmType<5>;
-def Imm32PCRel : ImmType<6>;
-def Imm32S : ImmType<7>;
-def Imm64 : ImmType<8>;
+def Imm8Reg : ImmType<3>; // Register encoded in [7:4].
+def Imm16 : ImmType<4>;
+def Imm16PCRel : ImmType<5>;
+def Imm32 : ImmType<6>;
+def Imm32PCRel : ImmType<7>;
+def Imm32S : ImmType<8>;
+def Imm64 : ImmType<9>;
// FPFormat - This specifies what form this FP instruction has. This is used by
// the Floating-Point stackifier pass.
@@ -190,8 +201,6 @@ class TAXD : TA { Prefix OpPrefix = XD; }
class VEX { Encoding OpEnc = EncVEX; }
class VEX_W { bit hasVEX_WPrefix = 1; }
class VEX_4V : VEX { bit hasVEX_4V = 1; }
-class VEX_4VOp3 : VEX { bit hasVEX_4VOp3 = 1; }
-class VEX_I8IMM { bit hasVEX_i8ImmReg = 1; }
class VEX_L { bit hasVEX_L = 1; }
class VEX_LIG { bit ignoresVEX_L = 1; }
class EVEX : VEX { Encoding OpEnc = EncEVEX; }
@@ -212,10 +221,8 @@ class EVEX_CD8<int esize, CD8VForm form> {
}
class Has3DNow0F0FOpcode { bit has3DNow0F0FOpcode = 1; }
-class MemOp4 { bit hasMemOp4Prefix = 1; }
class XOP { Encoding OpEnc = EncXOP; }
class XOP_4V : XOP { bit hasVEX_4V = 1; }
-class XOP_4VOp3 : XOP { bit hasVEX_4VOp3 = 1; }
class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
string AsmStr,
@@ -265,10 +272,6 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
bits<2> OpEncBits = OpEnc.Value;
bit hasVEX_WPrefix = 0; // Does this inst set the VEX_W field?
bit hasVEX_4V = 0; // Does this inst require the VEX.VVVV field?
- bit hasVEX_4VOp3 = 0; // Does this inst require the VEX.VVVV field to
- // encode the third operand?
- bit hasVEX_i8ImmReg = 0; // Does this inst require the last source register
- // to be encoded in a immediate field?
bit hasVEX_L = 0; // Does this inst use large (256-bit) registers?
bit ignoresVEX_L = 0; // Does this instruction ignore the L-bit
bit hasEVEX_K = 0; // Does this inst require masking?
@@ -280,7 +283,6 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
// assigning to bits<7>.
int CD8_EltSize = 0; // Compressed disp8 form - element-size in bytes.
bit has3DNow0F0FOpcode =0;// Wacky 3dNow! encoding?
- bit hasMemOp4Prefix = 0; // Same bit as VEX_W, but used for swapping operands
bit hasEVEX_RC = 0; // Explicitly specified rounding control in FP instruction.
bits<2> EVEX_LL;
@@ -317,19 +319,15 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
let TSFlags{38-31} = Opcode;
let TSFlags{39} = hasVEX_WPrefix;
let TSFlags{40} = hasVEX_4V;
- let TSFlags{41} = hasVEX_4VOp3;
- let TSFlags{42} = hasVEX_i8ImmReg;
- let TSFlags{43} = hasVEX_L;
- let TSFlags{44} = ignoresVEX_L;
- let TSFlags{45} = hasEVEX_K;
- let TSFlags{46} = hasEVEX_Z;
- let TSFlags{47} = hasEVEX_L2;
- let TSFlags{48} = hasEVEX_B;
+ let TSFlags{41} = hasVEX_L;
+ let TSFlags{42} = hasEVEX_K;
+ let TSFlags{43} = hasEVEX_Z;
+ let TSFlags{44} = hasEVEX_L2;
+ let TSFlags{45} = hasEVEX_B;
// If we run out of TSFlags bits, it's possible to encode this in 3 bits.
- let TSFlags{55-49} = CD8_Scale;
- let TSFlags{56} = has3DNow0F0FOpcode;
- let TSFlags{57} = hasMemOp4Prefix;
- let TSFlags{58} = hasEVEX_RC;
+ let TSFlags{52-46} = CD8_Scale;
+ let TSFlags{53} = has3DNow0F0FOpcode;
+ let TSFlags{54} = hasEVEX_RC;
}
class PseudoI<dag oops, dag iops, list<dag> pattern>
@@ -351,6 +349,13 @@ class Ii8 <bits<8> o, Format f, dag outs, dag ins, string asm,
let Pattern = pattern;
let CodeSize = 3;
}
+class Ii8Reg<bits<8> o, Format f, dag outs, dag ins, string asm,
+ list<dag> pattern, InstrItinClass itin = NoItinerary,
+ Domain d = GenericDomain>
+ : X86Inst<o, f, Imm8Reg, outs, ins, asm, itin, d> {
+ let Pattern = pattern;
+ let CodeSize = 3;
+}
class Ii8PCRel<bits<8> o, Format f, dag outs, dag ins, string asm,
list<dag> pattern, InstrItinClass itin = NoItinerary>
: X86Inst<o, f, Imm8PCRel, outs, ins, asm, itin> {
@@ -785,7 +790,6 @@ class AVX512AIi8<bits<8> o, Format F, dag outs, dag ins, string asm,
: Ii8<o, F, outs, ins, asm, pattern, itin, SSEPackedInt>, TAPD,
Requires<[HasAVX512]>;
class AVX512AIi8Base : TAPD {
- Domain ExeDomain = SSEPackedInt;
ImmType ImmT = Imm8;
}
class AVX512Ii8<bits<8> o, Format F, dag outs, dag ins, string asm,
@@ -850,8 +854,8 @@ class FMA3<bits<8> o, Format F, dag outs, dag ins, string asm,
// FMA4 Instruction Templates
class FMA4<bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag>pattern, InstrItinClass itin = NoItinerary>
- : Ii8<o, F, outs, ins, asm, pattern, itin>, TAPD,
- VEX_4V, VEX_I8IMM, FMASC, Requires<[HasFMA4]>;
+ : Ii8Reg<o, F, outs, ins, asm, pattern, itin>, TAPD,
+ VEX_4V, FMASC, Requires<[HasFMA4]>;
// XOP 2, 3 and 4 Operand Instruction Template
class IXOP<bits<8> o, Format F, dag outs, dag ins, string asm,
@@ -859,17 +863,22 @@ class IXOP<bits<8> o, Format F, dag outs, dag ins, string asm,
: I<o, F, outs, ins, asm, pattern, itin, SSEPackedDouble>,
XOP9, Requires<[HasXOP]>;
-// XOP 2, 3 and 4 Operand Instruction Templates with imm byte
+// XOP 2 and 3 Operand Instruction Templates with imm byte
class IXOPi8<bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag> pattern, InstrItinClass itin = NoItinerary>
: Ii8<o, F, outs, ins, asm, pattern, itin, SSEPackedDouble>,
XOP8, Requires<[HasXOP]>;
+// XOP 4 Operand Instruction Templates with imm byte
+class IXOPi8Reg<bits<8> o, Format F, dag outs, dag ins, string asm,
+ list<dag> pattern, InstrItinClass itin = NoItinerary>
+ : Ii8Reg<o, F, outs, ins, asm, pattern, itin, SSEPackedDouble>,
+ XOP8, Requires<[HasXOP]>;
// XOP 5 operand instruction (VEX encoding!)
class IXOP5<bits<8> o, Format F, dag outs, dag ins, string asm,
list<dag>pattern, InstrItinClass itin = NoItinerary>
- : Ii8<o, F, outs, ins, asm, pattern, itin, SSEPackedInt>, TAPD,
- VEX_4V, VEX_I8IMM, Requires<[HasXOP]>;
+ : Ii8Reg<o, F, outs, ins, asm, pattern, itin, SSEPackedInt>, TAPD,
+ VEX_4V, Requires<[HasXOP]>;
// X86-64 Instruction templates...
//
diff --git a/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td b/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
index ea54f04..c5689d7 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
@@ -29,7 +29,6 @@ def MMX_X86movw2d : SDNode<"X86ISD::MMX_MOVW2D", SDTypeProfile<1, 1,
def load_mmx : PatFrag<(ops node:$ptr), (x86mmx (load node:$ptr))>;
def load_mvmmx : PatFrag<(ops node:$ptr),
(x86mmx (MMX_X86movw2d (load node:$ptr)))>;
-def bc_mmx : PatFrag<(ops node:$in), (x86mmx (bitconvert node:$in))>;
//===----------------------------------------------------------------------===//
// SSE specific DAG Nodes.
@@ -56,8 +55,7 @@ def X86for : SDNode<"X86ISD::FOR", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative]>;
def X86fxor : SDNode<"X86ISD::FXOR", SDTFPBinOp,
[SDNPCommutative, SDNPAssociative]>;
-def X86fandn : SDNode<"X86ISD::FANDN", SDTFPBinOp,
- [SDNPCommutative, SDNPAssociative]>;
+def X86fandn : SDNode<"X86ISD::FANDN", SDTFPBinOp>;
def X86frsqrt : SDNode<"X86ISD::FRSQRT", SDTFPUnaryOp>;
def X86frcp : SDNode<"X86ISD::FRCP", SDTFPUnaryOp>;
def X86frsqrt14s: SDNode<"X86ISD::FRSQRTS", SDTFPBinOp>;
@@ -67,16 +65,8 @@ def X86fhsub : SDNode<"X86ISD::FHSUB", SDTFPBinOp>;
def X86hadd : SDNode<"X86ISD::HADD", SDTIntBinOp>;
def X86hsub : SDNode<"X86ISD::HSUB", SDTIntBinOp>;
def X86comi : SDNode<"X86ISD::COMI", SDTX86CmpTest>;
-def X86comiSae : SDNode<"X86ISD::COMI", SDTX86CmpTestSae>;
def X86ucomi : SDNode<"X86ISD::UCOMI", SDTX86CmpTest>;
-def X86ucomiSae: SDNode<"X86ISD::UCOMI", SDTX86CmpTestSae>;
def X86cmps : SDNode<"X86ISD::FSETCC", SDTX86Cmps>;
-def X86cvtdq2pd: SDNode<"X86ISD::CVTDQ2PD",
- SDTypeProfile<1, 1, [SDTCisVT<0, v2f64>,
- SDTCisVT<1, v4i32>]>>;
-def X86cvtudq2pd: SDNode<"X86ISD::CVTUDQ2PD",
- SDTypeProfile<1, 1, [SDTCisVT<0, v2f64>,
- SDTCisVT<1, v4i32>]>>;
def X86pshufb : SDNode<"X86ISD::PSHUFB",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, i8>, SDTCisSameAs<0,1>,
SDTCisSameAs<0,2>]>>;
@@ -84,7 +74,7 @@ def X86psadbw : SDNode<"X86ISD::PSADBW",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, i64>,
SDTCVecEltisVT<1, i8>,
SDTCisSameSizeAs<0,1>,
- SDTCisSameAs<1,2>]>>;
+ SDTCisSameAs<1,2>]>, [SDNPCommutative]>;
def X86dbpsadbw : SDNode<"X86ISD::DBPSADBW",
SDTypeProfile<1, 3, [SDTCVecEltisVT<0, i16>,
SDTCVecEltisVT<1, i8>,
@@ -144,25 +134,14 @@ def X86vfpround: SDNode<"X86ISD::VFPROUND",
SDTCVecEltisVT<1, f64>,
SDTCisSameSizeAs<0, 1>]>>;
-def X86fround: SDNode<"X86ISD::VFPROUND",
- SDTypeProfile<1, 2, [SDTCVecEltisVT<0, f32>,
- SDTCisSameAs<0, 1>,
- SDTCVecEltisVT<2, f64>,
- SDTCisSameSizeAs<0, 2>]>>;
-def X86froundRnd: SDNode<"X86ISD::VFPROUND",
+def X86froundRnd: SDNode<"X86ISD::VFPROUNDS_RND",
SDTypeProfile<1, 3, [SDTCVecEltisVT<0, f32>,
SDTCisSameAs<0, 1>,
SDTCVecEltisVT<2, f64>,
SDTCisSameSizeAs<0, 2>,
SDTCisVT<3, i32>]>>;
-def X86fpext : SDNode<"X86ISD::VFPEXT",
- SDTypeProfile<1, 2, [SDTCVecEltisVT<0, f64>,
- SDTCisSameAs<0, 1>,
- SDTCVecEltisVT<2, f32>,
- SDTCisSameSizeAs<0, 2>]>>;
-
-def X86fpextRnd : SDNode<"X86ISD::VFPEXT",
+def X86fpextRnd : SDNode<"X86ISD::VFPEXTS_RND",
SDTypeProfile<1, 3, [SDTCVecEltisVT<0, f64>,
SDTCisSameAs<0, 1>,
SDTCVecEltisVT<2, f32>,
@@ -176,7 +155,8 @@ def X86pcmpeq : SDNode<"X86ISD::PCMPEQ", SDTIntBinOp, [SDNPCommutative]>;
def X86pcmpgt : SDNode<"X86ISD::PCMPGT", SDTIntBinOp>;
def X86IntCmpMask : SDTypeProfile<1, 2,
- [SDTCisVec<0>, SDTCisSameAs<1, 2>, SDTCisInt<1>]>;
+ [SDTCisVec<0>, SDTCVecEltisVT<0, i1>, SDTCisSameAs<1, 2>, SDTCisInt<1>,
+ SDTCisSameNumEltsAs<0, 1>]>;
def X86pcmpeqm : SDNode<"X86ISD::PCMPEQM", X86IntCmpMask, [SDNPCommutative]>;
def X86pcmpgtm : SDNode<"X86ISD::PCMPGTM", X86IntCmpMask>;
@@ -188,19 +168,19 @@ def X86CmpMaskCCRound :
SDTypeProfile<1, 4, [SDTCisVec<0>,SDTCVecEltisVT<0, i1>,
SDTCisVec<1>, SDTCisSameAs<2, 1>,
SDTCisSameNumEltsAs<0, 1>, SDTCisVT<3, i8>,
- SDTCisInt<4>]>;
+ SDTCisVT<4, i32>]>;
def X86CmpMaskCCScalar :
SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<1, 2>, SDTCisVT<3, i8>]>;
def X86CmpMaskCCScalarRound :
SDTypeProfile<1, 4, [SDTCisInt<0>, SDTCisSameAs<1, 2>, SDTCisVT<3, i8>,
- SDTCisInt<4>]>;
+ SDTCisVT<4, i32>]>;
def X86cmpm : SDNode<"X86ISD::CMPM", X86CmpMaskCC>;
def X86cmpmRnd : SDNode<"X86ISD::CMPM_RND", X86CmpMaskCCRound>;
def X86cmpmu : SDNode<"X86ISD::CMPMU", X86CmpMaskCC>;
-def X86cmpms : SDNode<"X86ISD::FSETCC", X86CmpMaskCCScalar>;
-def X86cmpmsRnd : SDNode<"X86ISD::FSETCC", X86CmpMaskCCScalarRound>;
+def X86cmpms : SDNode<"X86ISD::FSETCCM", X86CmpMaskCCScalar>;
+def X86cmpmsRnd : SDNode<"X86ISD::FSETCCM_RND", X86CmpMaskCCScalarRound>;
def X86vshl : SDNode<"X86ISD::VSHL",
SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0,1>,
@@ -212,7 +192,9 @@ def X86vsra : SDNode<"X86ISD::VSRA",
SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0,1>,
SDTCisVec<2>]>>;
-def X86vsrav : SDNode<"X86ISD::VSRAV" , SDTIntShiftOp>;
+def X86vsrav : SDNode<"X86ISD::VSRAV" ,
+ SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0,1>,
+ SDTCisSameAs<0,2>]>>;
def X86vshli : SDNode<"X86ISD::VSHLI", SDTIntShiftOp>;
def X86vsrli : SDNode<"X86ISD::VSRLI", SDTIntShiftOp>;
@@ -261,12 +243,12 @@ def SDTX86Testm : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisVec<1>,
SDTCisSameAs<2, 1>, SDTCVecEltisVT<0, i1>,
SDTCisSameNumEltsAs<0, 1>]>;
-def X86addus : SDNode<"X86ISD::ADDUS", SDTIntBinOp>;
+def X86addus : SDNode<"X86ISD::ADDUS", SDTIntBinOp, [SDNPCommutative]>;
def X86subus : SDNode<"X86ISD::SUBUS", SDTIntBinOp>;
-def X86adds : SDNode<"X86ISD::ADDS", SDTIntBinOp>;
+def X86adds : SDNode<"X86ISD::ADDS", SDTIntBinOp, [SDNPCommutative]>;
def X86subs : SDNode<"X86ISD::SUBS", SDTIntBinOp>;
-def X86mulhrs : SDNode<"X86ISD::MULHRS" , SDTIntBinOp>;
-def X86avg : SDNode<"X86ISD::AVG" , SDTIntBinOp>;
+def X86mulhrs : SDNode<"X86ISD::MULHRS", SDTIntBinOp, [SDNPCommutative]>;
+def X86avg : SDNode<"X86ISD::AVG" , SDTIntBinOp, [SDNPCommutative]>;
def X86ptest : SDNode<"X86ISD::PTEST", SDTX86CmpPTest>;
def X86testp : SDNode<"X86ISD::TESTP", SDTX86CmpPTest>;
def X86kortest : SDNode<"X86ISD::KORTEST", SDTX86CmpPTest>;
@@ -283,7 +265,7 @@ def X86select : SDNode<"X86ISD::SELECT",
SDTCisSameAs<2, 3>,
SDTCisSameNumEltsAs<0, 1>]>>;
-def X86selects : SDNode<"X86ISD::SELECT",
+def X86selects : SDNode<"X86ISD::SELECTS",
SDTypeProfile<1, 3, [SDTCisVT<1, i1>,
SDTCisSameAs<0, 2>,
SDTCisSameAs<2, 3>]>>;
@@ -292,12 +274,14 @@ def X86pmuludq : SDNode<"X86ISD::PMULUDQ",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, i64>,
SDTCVecEltisVT<1, i32>,
SDTCisSameSizeAs<0,1>,
- SDTCisSameAs<1,2>]>>;
+ SDTCisSameAs<1,2>]>,
+ [SDNPCommutative]>;
def X86pmuldq : SDNode<"X86ISD::PMULDQ",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, i64>,
SDTCVecEltisVT<1, i32>,
SDTCisSameSizeAs<0,1>,
- SDTCisSameAs<1,2>]>>;
+ SDTCisSameAs<1,2>]>,
+ [SDNPCommutative]>;
def X86extrqi : SDNode<"X86ISD::EXTRQI",
SDTypeProfile<1, 3, [SDTCisVT<0, v2i64>, SDTCisSameAs<0,1>,
@@ -393,7 +377,7 @@ def X86Unpckl : SDNode<"X86ISD::UNPCKL", SDTShuff2Op>;
def X86Unpckh : SDNode<"X86ISD::UNPCKH", SDTShuff2Op>;
def X86vpmaddubsw : SDNode<"X86ISD::VPMADDUBSW" , SDTPack>;
-def X86vpmaddwd : SDNode<"X86ISD::VPMADDWD" , SDTPack>;
+def X86vpmaddwd : SDNode<"X86ISD::VPMADDWD" , SDTPack, [SDNPCommutative]>;
def X86VPermilpv : SDNode<"X86ISD::VPERMILPV", SDTShuff2OpM>;
def X86VPermilpi : SDNode<"X86ISD::VPERMILPI", SDTShuff2OpI>;
@@ -410,10 +394,12 @@ def X86VPermt2 : SDNode<"X86ISD::VPERMV3",
SDTCisSameSizeAs<0,2>,
SDTCisSameAs<0,3>]>, []>;
+// Even though the index operand should be integer, we need to make it match the
+// destination type so that we can pattern match the masked version where the
+// index is also the passthru operand.
def X86VPermi2X : SDNode<"X86ISD::VPERMIV3",
- SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisInt<1>,
- SDTCisVec<1>, SDTCisSameNumEltsAs<0, 1>,
- SDTCisSameSizeAs<0,1>,
+ SDTypeProfile<1, 3, [SDTCisVec<0>,
+ SDTCisSameAs<0,1>,
SDTCisSameAs<0,2>,
SDTCisSameAs<0,3>]>, []>;
@@ -462,9 +448,9 @@ def X86scalef : SDNode<"X86ISD::SCALEF", SDTFPBinOpRound>;
def X86scalefs : SDNode<"X86ISD::SCALEFS", SDTFPBinOpRound>;
def X86fminRnd : SDNode<"X86ISD::FMIN_RND", SDTFPBinOpRound>;
def X86fsqrtRnd : SDNode<"X86ISD::FSQRT_RND", SDTFPUnaryOpRound>;
-def X86fsqrtRnds : SDNode<"X86ISD::FSQRT_RND", SDTFPBinOpRound>;
+def X86fsqrtRnds : SDNode<"X86ISD::FSQRTS_RND", SDTFPBinOpRound>;
def X86fgetexpRnd : SDNode<"X86ISD::FGETEXP_RND", SDTFPUnaryOpRound>;
-def X86fgetexpRnds : SDNode<"X86ISD::FGETEXP_RND", SDTFPBinOpRound>;
+def X86fgetexpRnds : SDNode<"X86ISD::FGETEXPS_RND", SDTFPBinOpRound>;
def X86Fmadd : SDNode<"X86ISD::FMADD", SDTFma>;
def X86Fnmadd : SDNode<"X86ISD::FNMADD", SDTFma>;
@@ -480,6 +466,18 @@ def X86FnmsubRnd : SDNode<"X86ISD::FNMSUB_RND", SDTFmaRound>;
def X86FmaddsubRnd : SDNode<"X86ISD::FMADDSUB_RND", SDTFmaRound>;
def X86FmsubaddRnd : SDNode<"X86ISD::FMSUBADD_RND", SDTFmaRound>;
+// Scalar FMA intrinsics with passthru bits in operand 1.
+def X86FmaddRnds1 : SDNode<"X86ISD::FMADDS1_RND", SDTFmaRound>;
+def X86FnmaddRnds1 : SDNode<"X86ISD::FNMADDS1_RND", SDTFmaRound>;
+def X86FmsubRnds1 : SDNode<"X86ISD::FMSUBS1_RND", SDTFmaRound>;
+def X86FnmsubRnds1 : SDNode<"X86ISD::FNMSUBS1_RND", SDTFmaRound>;
+
+// Scalar FMA intrinsics with passthru bits in operand 3.
+def X86FmaddRnds3 : SDNode<"X86ISD::FMADDS3_RND", SDTFmaRound>;
+def X86FnmaddRnds3 : SDNode<"X86ISD::FNMADDS3_RND", SDTFmaRound>;
+def X86FmsubRnds3 : SDNode<"X86ISD::FMSUBS3_RND", SDTFmaRound>;
+def X86FnmsubRnds3 : SDNode<"X86ISD::FNMSUBS3_RND", SDTFmaRound>;
+
def x86vpmadd52l : SDNode<"X86ISD::VPMADD52L", SDTFma>;
def x86vpmadd52h : SDNode<"X86ISD::VPMADD52H", SDTFma>;
@@ -487,11 +485,11 @@ def X86rsqrt28 : SDNode<"X86ISD::RSQRT28", SDTFPUnaryOpRound>;
def X86rcp28 : SDNode<"X86ISD::RCP28", SDTFPUnaryOpRound>;
def X86exp2 : SDNode<"X86ISD::EXP2", SDTFPUnaryOpRound>;
-def X86rsqrt28s : SDNode<"X86ISD::RSQRT28", SDTFPBinOpRound>;
-def X86rcp28s : SDNode<"X86ISD::RCP28", SDTFPBinOpRound>;
-def X86RndScales : SDNode<"X86ISD::VRNDSCALE", SDTFPBinOpImmRound>;
-def X86Reduces : SDNode<"X86ISD::VREDUCE", SDTFPBinOpImmRound>;
-def X86GetMants : SDNode<"X86ISD::VGETMANT", SDTFPBinOpImmRound>;
+def X86rsqrt28s : SDNode<"X86ISD::RSQRT28S", SDTFPBinOpRound>;
+def X86rcp28s : SDNode<"X86ISD::RCP28S", SDTFPBinOpRound>;
+def X86RndScales : SDNode<"X86ISD::VRNDSCALES", SDTFPBinOpImmRound>;
+def X86Reduces : SDNode<"X86ISD::VREDUCES", SDTFPBinOpImmRound>;
+def X86GetMants : SDNode<"X86ISD::VGETMANTS", SDTFPBinOpImmRound>;
def SDT_PCMPISTRI : SDTypeProfile<2, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
SDTCisVT<2, v16i8>, SDTCisVT<3, v16i8>,
@@ -515,59 +513,69 @@ def SDTintToFPRound: SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisFP<0>,
def SDTFloatToInt: SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>,
SDTCisInt<0>, SDTCisFP<1>]>;
-
def SDTFloatToIntRnd: SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisVec<1>,
SDTCisInt<0>, SDTCisFP<1>,
SDTCisVT<2, i32>]>;
def SDTSFloatToIntRnd: SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisFP<1>,
SDTCisVec<1>, SDTCisVT<2, i32>]>;
+
+def SDTVintToFP: SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>,
+ SDTCisFP<0>, SDTCisInt<1>]>;
def SDTVintToFPRound: SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisVec<1>,
SDTCisFP<0>, SDTCisInt<1>,
SDTCisVT<2, i32>]>;
// Scalar
-def X86SintToFpRnd : SDNode<"X86ISD::SINT_TO_FP_RND", SDTintToFPRound>;
-def X86UintToFpRnd : SDNode<"X86ISD::UINT_TO_FP_RND", SDTintToFPRound>;
+def X86SintToFpRnd : SDNode<"X86ISD::SCALAR_SINT_TO_FP_RND", SDTintToFPRound>;
+def X86UintToFpRnd : SDNode<"X86ISD::SCALAR_UINT_TO_FP_RND", SDTintToFPRound>;
-def X86cvtts2IntRnd : SDNode<"X86ISD::FP_TO_SINT_RND", SDTSFloatToIntRnd>;
-def X86cvtts2UIntRnd : SDNode<"X86ISD::FP_TO_UINT_RND", SDTSFloatToIntRnd>;
+def X86cvtts2IntRnd : SDNode<"X86ISD::CVTTS2SI_RND", SDTSFloatToIntRnd>;
+def X86cvtts2UIntRnd : SDNode<"X86ISD::CVTTS2UI_RND", SDTSFloatToIntRnd>;
-def X86cvts2si : SDNode<"X86ISD::SCALAR_FP_TO_SINT_RND", SDTSFloatToIntRnd>;
-def X86cvts2usi : SDNode<"X86ISD::SCALAR_FP_TO_UINT_RND", SDTSFloatToIntRnd>;
+def X86cvts2si : SDNode<"X86ISD::CVTS2SI_RND", SDTSFloatToIntRnd>;
+def X86cvts2usi : SDNode<"X86ISD::CVTS2UI_RND", SDTSFloatToIntRnd>;
// Vector with rounding mode
// cvtt fp-to-int staff
-def X86VFpToSintRnd : SDNode<"ISD::FP_TO_SINT", SDTFloatToIntRnd>;
-def X86VFpToUintRnd : SDNode<"ISD::FP_TO_UINT", SDTFloatToIntRnd>;
+def X86cvttp2siRnd : SDNode<"X86ISD::CVTTP2SI_RND", SDTFloatToIntRnd>;
+def X86cvttp2uiRnd : SDNode<"X86ISD::CVTTP2UI_RND", SDTFloatToIntRnd>;
-def X86VSintToFpRnd : SDNode<"ISD::SINT_TO_FP", SDTVintToFPRound>;
-def X86VUintToFpRnd : SDNode<"ISD::UINT_TO_FP", SDTVintToFPRound>;
+def X86VSintToFpRnd : SDNode<"X86ISD::SINT_TO_FP_RND", SDTVintToFPRound>;
+def X86VUintToFpRnd : SDNode<"X86ISD::UINT_TO_FP_RND", SDTVintToFPRound>;
// cvt fp-to-int staff
-def X86cvtp2IntRnd : SDNode<"X86ISD::FP_TO_SINT_RND", SDTFloatToIntRnd>;
-def X86cvtp2UIntRnd : SDNode<"X86ISD::FP_TO_UINT_RND", SDTFloatToIntRnd>;
+def X86cvtp2IntRnd : SDNode<"X86ISD::CVTP2SI_RND", SDTFloatToIntRnd>;
+def X86cvtp2UIntRnd : SDNode<"X86ISD::CVTP2UI_RND", SDTFloatToIntRnd>;
// Vector without rounding mode
-def X86cvtp2Int : SDNode<"X86ISD::FP_TO_SINT_RND", SDTFloatToInt>;
-def X86cvtp2UInt : SDNode<"X86ISD::FP_TO_UINT_RND", SDTFloatToInt>;
-def X86cvtph2ps : SDNode<"ISD::FP16_TO_FP",
+// cvtt fp-to-int staff
+def X86cvttp2si : SDNode<"X86ISD::CVTTP2SI", SDTFloatToInt>;
+def X86cvttp2ui : SDNode<"X86ISD::CVTTP2UI", SDTFloatToInt>;
+
+def X86VSintToFP : SDNode<"X86ISD::CVTSI2P", SDTVintToFP>;
+def X86VUintToFP : SDNode<"X86ISD::CVTUI2P", SDTVintToFP>;
+
+// cvt int-to-fp staff
+def X86cvtp2Int : SDNode<"X86ISD::CVTP2SI", SDTFloatToInt>;
+def X86cvtp2UInt : SDNode<"X86ISD::CVTP2UI", SDTFloatToInt>;
+
+def X86cvtph2ps : SDNode<"X86ISD::CVTPH2PS",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, f32>,
SDTCVecEltisVT<1, i16>,
SDTCisVT<2, i32>]> >;
-def X86cvtps2ph : SDNode<"ISD::FP_TO_FP16",
- SDTypeProfile<1, 3, [SDTCVecEltisVT<0, i16>,
+def X86cvtps2ph : SDNode<"X86ISD::CVTPS2PH",
+ SDTypeProfile<1, 2, [SDTCVecEltisVT<0, i16>,
SDTCVecEltisVT<1, f32>,
- SDTCisVT<2, i32>,
- SDTCisVT<3, i32>]> >;
-def X86vfpextRnd : SDNode<"X86ISD::VFPEXT",
+ SDTCisVT<2, i32>]> >;
+def X86vfpextRnd : SDNode<"X86ISD::VFPEXT_RND",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, f64>,
SDTCVecEltisVT<1, f32>,
SDTCisOpSmallerThanOp<1, 0>,
SDTCisVT<2, i32>]>>;
-def X86vfproundRnd: SDNode<"X86ISD::VFPROUND",
+def X86vfproundRnd: SDNode<"X86ISD::VFPROUND_RND",
SDTypeProfile<1, 2, [SDTCVecEltisVT<0, f32>,
SDTCVecEltisVT<1, f64>,
SDTCisOpSmallerThanOp<0, 1>,
@@ -621,9 +629,6 @@ def loadv4i64 : PatFrag<(ops node:$ptr), (v4i64 (load node:$ptr))>;
// 512-bit load pattern fragments
def loadv16f32 : PatFrag<(ops node:$ptr), (v16f32 (load node:$ptr))>;
def loadv8f64 : PatFrag<(ops node:$ptr), (v8f64 (load node:$ptr))>;
-def loadv64i8 : PatFrag<(ops node:$ptr), (v64i8 (load node:$ptr))>;
-def loadv32i16 : PatFrag<(ops node:$ptr), (v32i16 (load node:$ptr))>;
-def loadv16i32 : PatFrag<(ops node:$ptr), (v16i32 (load node:$ptr))>;
def loadv8i64 : PatFrag<(ops node:$ptr), (v8i64 (load node:$ptr))>;
// 128-/256-/512-bit extload pattern fragments
@@ -631,15 +636,6 @@ def extloadv2f32 : PatFrag<(ops node:$ptr), (v2f64 (extloadvf32 node:$ptr))>;
def extloadv4f32 : PatFrag<(ops node:$ptr), (v4f64 (extloadvf32 node:$ptr))>;
def extloadv8f32 : PatFrag<(ops node:$ptr), (v8f64 (extloadvf32 node:$ptr))>;
-// These are needed to match a scalar load that is used in a vector-only
-// math instruction such as the FP logical ops: andps, andnps, orps, xorps.
-// The memory operand is required to be a 128-bit load, so it must be converted
-// from a vector to a scalar.
-def loadf32_128 : PatFrag<(ops node:$ptr),
- (f32 (extractelt (loadv4f32 node:$ptr), (iPTR 0)))>;
-def loadf64_128 : PatFrag<(ops node:$ptr),
- (f64 (extractelt (loadv2f64 node:$ptr), (iPTR 0)))>;
-
// Like 'store', but always requires 128-bit vector alignment.
def alignedstore : PatFrag<(ops node:$val, node:$ptr),
(store node:$val, node:$ptr), [{
@@ -673,11 +669,6 @@ def alignedload512 : PatFrag<(ops node:$ptr), (load node:$ptr), [{
return cast<LoadSDNode>(N)->getAlignment() >= 64;
}]>;
-def alignedloadfsf32 : PatFrag<(ops node:$ptr),
- (f32 (alignedload node:$ptr))>;
-def alignedloadfsf64 : PatFrag<(ops node:$ptr),
- (f64 (alignedload node:$ptr))>;
-
// 128-bit aligned load pattern fragments
// NOTE: all 128-bit integer vector loads are promoted to v2i64
def alignedloadv4f32 : PatFrag<(ops node:$ptr),
@@ -699,8 +690,6 @@ def alignedloadv4i64 : PatFrag<(ops node:$ptr),
// 512-bit aligned load pattern fragments
def alignedloadv16f32 : PatFrag<(ops node:$ptr),
(v16f32 (alignedload512 node:$ptr))>;
-def alignedloadv16i32 : PatFrag<(ops node:$ptr),
- (v16i32 (alignedload512 node:$ptr))>;
def alignedloadv8f64 : PatFrag<(ops node:$ptr),
(v8f64 (alignedload512 node:$ptr))>;
def alignedloadv8i64 : PatFrag<(ops node:$ptr),
@@ -717,9 +706,6 @@ def memop : PatFrag<(ops node:$ptr), (load node:$ptr), [{
|| cast<LoadSDNode>(N)->getAlignment() >= 16;
}]>;
-def memopfsf32 : PatFrag<(ops node:$ptr), (f32 (memop node:$ptr))>;
-def memopfsf64 : PatFrag<(ops node:$ptr), (f64 (memop node:$ptr))>;
-
// 128-bit memop pattern fragments
// NOTE: all 128-bit integer vector loads are promoted to v2i64
def memopv4f32 : PatFrag<(ops node:$ptr), (v4f32 (memop node:$ptr))>;
@@ -853,6 +839,7 @@ def bc_v4i64 : PatFrag<(ops node:$in), (v4i64 (bitconvert node:$in))>;
def bc_v8f32 : PatFrag<(ops node:$in), (v8f32 (bitconvert node:$in))>;
// 512-bit bitconvert pattern fragments
+def bc_v64i8 : PatFrag<(ops node:$in), (v64i8 (bitconvert node:$in))>;
def bc_v16i32 : PatFrag<(ops node:$in), (v16i32 (bitconvert node:$in))>;
def bc_v8i64 : PatFrag<(ops node:$in), (v8i64 (bitconvert node:$in))>;
def bc_v8f64 : PatFrag<(ops node:$in), (v8f64 (bitconvert node:$in))>;
@@ -873,6 +860,10 @@ def fp32imm0 : PatLeaf<(f32 fpimm), [{
return N->isExactlyValue(+0.0);
}]>;
+def fp64imm0 : PatLeaf<(f64 fpimm), [{
+ return N->isExactlyValue(+0.0);
+}]>;
+
def I8Imm : SDNodeXForm<imm, [{
// Transformation function: get the low 8 bits.
return getI8Imm((uint8_t)N->getZExtValue(), SDLoc(N));
@@ -940,30 +931,36 @@ def vinsert256_insert : PatFrag<(ops node:$bigvec, node:$smallvec,
return X86::isVINSERT256Index(N);
}], INSERT_get_vinsert256_imm>;
-def masked_load_aligned128 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+def X86mload : PatFrag<(ops node:$src1, node:$src2, node:$src3),
(masked_load node:$src1, node:$src2, node:$src3), [{
- if (auto *Load = dyn_cast<MaskedLoadSDNode>(N))
- return Load->getAlignment() >= 16;
- return false;
+ return !cast<MaskedLoadSDNode>(N)->isExpandingLoad() &&
+ cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::NON_EXTLOAD;
+}]>;
+
+def masked_load_aligned128 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86mload node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedLoadSDNode>(N)->getAlignment() >= 16;
}]>;
def masked_load_aligned256 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
- (masked_load node:$src1, node:$src2, node:$src3), [{
- if (auto *Load = dyn_cast<MaskedLoadSDNode>(N))
- return Load->getAlignment() >= 32;
- return false;
+ (X86mload node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedLoadSDNode>(N)->getAlignment() >= 32;
}]>;
def masked_load_aligned512 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
- (masked_load node:$src1, node:$src2, node:$src3), [{
- if (auto *Load = dyn_cast<MaskedLoadSDNode>(N))
- return Load->getAlignment() >= 64;
- return false;
+ (X86mload node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedLoadSDNode>(N)->getAlignment() >= 64;
}]>;
def masked_load_unaligned : PatFrag<(ops node:$src1, node:$src2, node:$src3),
(masked_load node:$src1, node:$src2, node:$src3), [{
- return isa<MaskedLoadSDNode>(N);
+ return !cast<MaskedLoadSDNode>(N)->isExpandingLoad() &&
+ cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::NON_EXTLOAD;
+}]>;
+
+def X86mExpandingLoad : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (masked_load node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedLoadSDNode>(N)->isExpandingLoad();
}]>;
// Masked store fragments.
@@ -971,33 +968,34 @@ def masked_load_unaligned : PatFrag<(ops node:$src1, node:$src2, node:$src3),
// do not support vector types (llvm-tblgen will fail).
def X86mstore : PatFrag<(ops node:$src1, node:$src2, node:$src3),
(masked_store node:$src1, node:$src2, node:$src3), [{
- return !cast<MaskedStoreSDNode>(N)->isTruncatingStore();
+ return (!cast<MaskedStoreSDNode>(N)->isTruncatingStore()) &&
+ (!cast<MaskedStoreSDNode>(N)->isCompressingStore());
}]>;
def masked_store_aligned128 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
(X86mstore node:$src1, node:$src2, node:$src3), [{
- if (auto *Store = dyn_cast<MaskedStoreSDNode>(N))
- return Store->getAlignment() >= 16;
- return false;
+ return cast<MaskedStoreSDNode>(N)->getAlignment() >= 16;
}]>;
def masked_store_aligned256 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
(X86mstore node:$src1, node:$src2, node:$src3), [{
- if (auto *Store = dyn_cast<MaskedStoreSDNode>(N))
- return Store->getAlignment() >= 32;
- return false;
+ return cast<MaskedStoreSDNode>(N)->getAlignment() >= 32;
}]>;
def masked_store_aligned512 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
(X86mstore node:$src1, node:$src2, node:$src3), [{
- if (auto *Store = dyn_cast<MaskedStoreSDNode>(N))
- return Store->getAlignment() >= 64;
- return false;
+ return cast<MaskedStoreSDNode>(N)->getAlignment() >= 64;
}]>;
def masked_store_unaligned : PatFrag<(ops node:$src1, node:$src2, node:$src3),
- (X86mstore node:$src1, node:$src2, node:$src3), [{
- return isa<MaskedStoreSDNode>(N);
+ (masked_store node:$src1, node:$src2, node:$src3), [{
+ return (!cast<MaskedStoreSDNode>(N)->isTruncatingStore()) &&
+ (!cast<MaskedStoreSDNode>(N)->isCompressingStore());
+}]>;
+
+def X86mCompressingStore : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (masked_store node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedStoreSDNode>(N)->isCompressingStore();
}]>;
// masked truncstore fragments
@@ -1022,3 +1020,80 @@ def masked_truncstorevi32 :
(X86mtruncstore node:$src1, node:$src2, node:$src3), [{
return cast<MaskedStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32;
}]>;
+
+def X86TruncSStore : SDNode<"X86ISD::VTRUNCSTORES", SDTStore,
+ [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
+def X86TruncUSStore : SDNode<"X86ISD::VTRUNCSTOREUS", SDTStore,
+ [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
+def X86MTruncSStore : SDNode<"X86ISD::VMTRUNCSTORES", SDTMaskedStore,
+ [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
+def X86MTruncUSStore : SDNode<"X86ISD::VMTRUNCSTOREUS", SDTMaskedStore,
+ [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
+def truncstore_s_vi8 : PatFrag<(ops node:$val, node:$ptr),
+ (X86TruncSStore node:$val, node:$ptr), [{
+ return cast<TruncSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8;
+}]>;
+
+def truncstore_us_vi8 : PatFrag<(ops node:$val, node:$ptr),
+ (X86TruncUSStore node:$val, node:$ptr), [{
+ return cast<TruncUSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8;
+}]>;
+
+def truncstore_s_vi16 : PatFrag<(ops node:$val, node:$ptr),
+ (X86TruncSStore node:$val, node:$ptr), [{
+ return cast<TruncSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16;
+}]>;
+
+def truncstore_us_vi16 : PatFrag<(ops node:$val, node:$ptr),
+ (X86TruncUSStore node:$val, node:$ptr), [{
+ return cast<TruncUSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16;
+}]>;
+
+def truncstore_s_vi32 : PatFrag<(ops node:$val, node:$ptr),
+ (X86TruncSStore node:$val, node:$ptr), [{
+ return cast<TruncSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32;
+}]>;
+
+def truncstore_us_vi32 : PatFrag<(ops node:$val, node:$ptr),
+ (X86TruncUSStore node:$val, node:$ptr), [{
+ return cast<TruncUSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32;
+}]>;
+
+def masked_truncstore_s_vi8 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86MTruncSStore node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedTruncSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8;
+}]>;
+
+def masked_truncstore_us_vi8 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86MTruncUSStore node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedTruncUSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8;
+}]>;
+
+def masked_truncstore_s_vi16 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86MTruncSStore node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedTruncSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16;
+}]>;
+
+def masked_truncstore_us_vi16 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86MTruncUSStore node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedTruncUSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16;
+}]>;
+
+def masked_truncstore_s_vi32 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86MTruncSStore node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedTruncSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32;
+}]>;
+
+def masked_truncstore_us_vi32 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
+ (X86MTruncUSStore node:$src1, node:$src2, node:$src3), [{
+ return cast<MaskedTruncUSStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32;
+}]>;
+
+def assertzext_i1 :
+ PatFrag<(ops node:$src), (assertzext node:$src), [{
+ return cast<VTSDNode>(N->getOperand(1))->getVT() == MVT::i1;
+}]>;
diff --git a/contrib/llvm/lib/Target/X86/X86InstrInfo.cpp b/contrib/llvm/lib/Target/X86/X86InstrInfo.cpp
index 5f0aab9..627b612 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/contrib/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -68,7 +68,7 @@ static cl::opt<unsigned>
UndefRegClearance("undef-reg-clearance",
cl::desc("How many idle instructions we would like before "
"certain undef register reads"),
- cl::init(64), cl::Hidden);
+ cl::init(128), cl::Hidden);
enum {
// Select which memory operand is being unfolded.
@@ -228,12 +228,16 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::SBB64ri32, X86::SBB64mi32, 0 },
{ X86::SBB64ri8, X86::SBB64mi8, 0 },
{ X86::SBB64rr, X86::SBB64mr, 0 },
+ { X86::SHL16r1, X86::SHL16m1, 0 },
{ X86::SHL16rCL, X86::SHL16mCL, 0 },
{ X86::SHL16ri, X86::SHL16mi, 0 },
+ { X86::SHL32r1, X86::SHL32m1, 0 },
{ X86::SHL32rCL, X86::SHL32mCL, 0 },
{ X86::SHL32ri, X86::SHL32mi, 0 },
+ { X86::SHL64r1, X86::SHL64m1, 0 },
{ X86::SHL64rCL, X86::SHL64mCL, 0 },
{ X86::SHL64ri, X86::SHL64mi, 0 },
+ { X86::SHL8r1, X86::SHL8m1, 0 },
{ X86::SHL8rCL, X86::SHL8mCL, 0 },
{ X86::SHL8ri, X86::SHL8mi, 0 },
{ X86::SHLD16rrCL, X86::SHLD16mrCL, 0 },
@@ -335,6 +339,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::MOVAPDrr, X86::MOVAPDmr, TB_FOLDED_STORE | TB_ALIGN_16 },
{ X86::MOVAPSrr, X86::MOVAPSmr, TB_FOLDED_STORE | TB_ALIGN_16 },
{ X86::MOVDQArr, X86::MOVDQAmr, TB_FOLDED_STORE | TB_ALIGN_16 },
+ { X86::MOVDQUrr, X86::MOVDQUmr, TB_FOLDED_STORE },
{ X86::MOVPDI2DIrr, X86::MOVPDI2DImr, TB_FOLDED_STORE },
{ X86::MOVPQIto64rr,X86::MOVPQI2QImr, TB_FOLDED_STORE },
{ X86::MOVSDto64rr, X86::MOVSDto64mr, TB_FOLDED_STORE },
@@ -380,6 +385,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVAPDrr, X86::VMOVAPDmr, TB_FOLDED_STORE | TB_ALIGN_16 },
{ X86::VMOVAPSrr, X86::VMOVAPSmr, TB_FOLDED_STORE | TB_ALIGN_16 },
{ X86::VMOVDQArr, X86::VMOVDQAmr, TB_FOLDED_STORE | TB_ALIGN_16 },
+ { X86::VMOVDQUrr, X86::VMOVDQUmr, TB_FOLDED_STORE },
{ X86::VMOVPDI2DIrr,X86::VMOVPDI2DImr, TB_FOLDED_STORE },
{ X86::VMOVPQIto64rr, X86::VMOVPQI2QImr,TB_FOLDED_STORE },
{ X86::VMOVSDto64rr,X86::VMOVSDto64mr, TB_FOLDED_STORE },
@@ -394,10 +400,20 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVAPDYrr, X86::VMOVAPDYmr, TB_FOLDED_STORE | TB_ALIGN_32 },
{ X86::VMOVAPSYrr, X86::VMOVAPSYmr, TB_FOLDED_STORE | TB_ALIGN_32 },
{ X86::VMOVDQAYrr, X86::VMOVDQAYmr, TB_FOLDED_STORE | TB_ALIGN_32 },
+ { X86::VMOVDQUYrr, X86::VMOVDQUYmr, TB_FOLDED_STORE },
{ X86::VMOVUPDYrr, X86::VMOVUPDYmr, TB_FOLDED_STORE },
{ X86::VMOVUPSYrr, X86::VMOVUPSYmr, TB_FOLDED_STORE },
// AVX-512 foldable instructions
+ { X86::VEXTRACTF32x4Zrr,X86::VEXTRACTF32x4Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTF32x8Zrr,X86::VEXTRACTF32x8Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTF64x2Zrr,X86::VEXTRACTF64x2Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTF64x4Zrr,X86::VEXTRACTF64x4Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTI32x4Zrr,X86::VEXTRACTI32x4Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTI32x8Zrr,X86::VEXTRACTI32x8Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTI64x2Zrr,X86::VEXTRACTI64x2Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTI64x4Zrr,X86::VEXTRACTI64x4Zmr, TB_FOLDED_STORE },
+ { X86::VEXTRACTPSZrr, X86::VEXTRACTPSZmr, TB_FOLDED_STORE },
{ X86::VMOVPDI2DIZrr, X86::VMOVPDI2DIZmr, TB_FOLDED_STORE },
{ X86::VMOVAPDZrr, X86::VMOVAPDZmr, TB_FOLDED_STORE | TB_ALIGN_64 },
{ X86::VMOVAPSZrr, X86::VMOVAPSZmr, TB_FOLDED_STORE | TB_ALIGN_64 },
@@ -409,8 +425,27 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVDQU16Zrr, X86::VMOVDQU16Zmr, TB_FOLDED_STORE },
{ X86::VMOVDQU32Zrr, X86::VMOVDQU32Zmr, TB_FOLDED_STORE },
{ X86::VMOVDQU64Zrr, X86::VMOVDQU64Zmr, TB_FOLDED_STORE },
+ { X86::VPMOVDBZrr, X86::VPMOVDBZmr, TB_FOLDED_STORE },
+ { X86::VPMOVDWZrr, X86::VPMOVDWZmr, TB_FOLDED_STORE },
+ { X86::VPMOVQDZrr, X86::VPMOVQDZmr, TB_FOLDED_STORE },
+ { X86::VPMOVQWZrr, X86::VPMOVQWZmr, TB_FOLDED_STORE },
+ { X86::VPMOVWBZrr, X86::VPMOVWBZmr, TB_FOLDED_STORE },
+ { X86::VPMOVSDBZrr, X86::VPMOVSDBZmr, TB_FOLDED_STORE },
+ { X86::VPMOVSDWZrr, X86::VPMOVSDWZmr, TB_FOLDED_STORE },
+ { X86::VPMOVSQDZrr, X86::VPMOVSQDZmr, TB_FOLDED_STORE },
+ { X86::VPMOVSQWZrr, X86::VPMOVSQWZmr, TB_FOLDED_STORE },
+ { X86::VPMOVSWBZrr, X86::VPMOVSWBZmr, TB_FOLDED_STORE },
+ { X86::VPMOVUSDBZrr, X86::VPMOVUSDBZmr, TB_FOLDED_STORE },
+ { X86::VPMOVUSDWZrr, X86::VPMOVUSDWZmr, TB_FOLDED_STORE },
+ { X86::VPMOVUSQDZrr, X86::VPMOVUSQDZmr, TB_FOLDED_STORE },
+ { X86::VPMOVUSQWZrr, X86::VPMOVUSQWZmr, TB_FOLDED_STORE },
+ { X86::VPMOVUSWBZrr, X86::VPMOVUSWBZmr, TB_FOLDED_STORE },
// AVX-512 foldable instructions (256-bit versions)
+ { X86::VEXTRACTF32x4Z256rr,X86::VEXTRACTF32x4Z256mr, TB_FOLDED_STORE },
+ { X86::VEXTRACTF64x2Z256rr,X86::VEXTRACTF64x2Z256mr, TB_FOLDED_STORE },
+ { X86::VEXTRACTI32x4Z256rr,X86::VEXTRACTI32x4Z256mr, TB_FOLDED_STORE },
+ { X86::VEXTRACTI64x2Z256rr,X86::VEXTRACTI64x2Z256mr, TB_FOLDED_STORE },
{ X86::VMOVAPDZ256rr, X86::VMOVAPDZ256mr, TB_FOLDED_STORE | TB_ALIGN_32 },
{ X86::VMOVAPSZ256rr, X86::VMOVAPSZ256mr, TB_FOLDED_STORE | TB_ALIGN_32 },
{ X86::VMOVDQA32Z256rr, X86::VMOVDQA32Z256mr, TB_FOLDED_STORE | TB_ALIGN_32 },
@@ -421,6 +456,15 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVDQU16Z256rr, X86::VMOVDQU16Z256mr, TB_FOLDED_STORE },
{ X86::VMOVDQU32Z256rr, X86::VMOVDQU32Z256mr, TB_FOLDED_STORE },
{ X86::VMOVDQU64Z256rr, X86::VMOVDQU64Z256mr, TB_FOLDED_STORE },
+ { X86::VPMOVDWZ256rr, X86::VPMOVDWZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVQDZ256rr, X86::VPMOVQDZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVWBZ256rr, X86::VPMOVWBZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVSDWZ256rr, X86::VPMOVSDWZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVSQDZ256rr, X86::VPMOVSQDZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVSWBZ256rr, X86::VPMOVSWBZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVUSDWZ256rr, X86::VPMOVUSDWZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVUSQDZ256rr, X86::VPMOVUSQDZ256mr, TB_FOLDED_STORE },
+ { X86::VPMOVUSWBZ256rr, X86::VPMOVUSWBZ256mr, TB_FOLDED_STORE },
// AVX-512 foldable instructions (128-bit versions)
{ X86::VMOVAPDZ128rr, X86::VMOVAPDZ128mr, TB_FOLDED_STORE | TB_ALIGN_16 },
@@ -471,26 +515,26 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::IMUL32rri8, X86::IMUL32rmi8, 0 },
{ X86::IMUL64rri32, X86::IMUL64rmi32, 0 },
{ X86::IMUL64rri8, X86::IMUL64rmi8, 0 },
- { X86::Int_COMISDrr, X86::Int_COMISDrm, 0 },
- { X86::Int_COMISSrr, X86::Int_COMISSrm, 0 },
- { X86::CVTSD2SI64rr, X86::CVTSD2SI64rm, 0 },
- { X86::CVTSD2SIrr, X86::CVTSD2SIrm, 0 },
- { X86::CVTSS2SI64rr, X86::CVTSS2SI64rm, 0 },
- { X86::CVTSS2SIrr, X86::CVTSS2SIrm, 0 },
- { X86::CVTDQ2PDrr, X86::CVTDQ2PDrm, TB_ALIGN_16 },
+ { X86::Int_COMISDrr, X86::Int_COMISDrm, TB_NO_REVERSE },
+ { X86::Int_COMISSrr, X86::Int_COMISSrm, TB_NO_REVERSE },
+ { X86::CVTSD2SI64rr, X86::CVTSD2SI64rm, TB_NO_REVERSE },
+ { X86::CVTSD2SIrr, X86::CVTSD2SIrm, TB_NO_REVERSE },
+ { X86::CVTSS2SI64rr, X86::CVTSS2SI64rm, TB_NO_REVERSE },
+ { X86::CVTSS2SIrr, X86::CVTSS2SIrm, TB_NO_REVERSE },
+ { X86::CVTDQ2PDrr, X86::CVTDQ2PDrm, TB_NO_REVERSE },
{ X86::CVTDQ2PSrr, X86::CVTDQ2PSrm, TB_ALIGN_16 },
{ X86::CVTPD2DQrr, X86::CVTPD2DQrm, TB_ALIGN_16 },
{ X86::CVTPD2PSrr, X86::CVTPD2PSrm, TB_ALIGN_16 },
{ X86::CVTPS2DQrr, X86::CVTPS2DQrm, TB_ALIGN_16 },
- { X86::CVTPS2PDrr, X86::CVTPS2PDrm, TB_ALIGN_16 },
+ { X86::CVTPS2PDrr, X86::CVTPS2PDrm, TB_NO_REVERSE },
{ X86::CVTTPD2DQrr, X86::CVTTPD2DQrm, TB_ALIGN_16 },
{ X86::CVTTPS2DQrr, X86::CVTTPS2DQrm, TB_ALIGN_16 },
- { X86::Int_CVTTSD2SI64rr,X86::Int_CVTTSD2SI64rm, 0 },
- { X86::Int_CVTTSD2SIrr, X86::Int_CVTTSD2SIrm, 0 },
- { X86::Int_CVTTSS2SI64rr,X86::Int_CVTTSS2SI64rm, 0 },
- { X86::Int_CVTTSS2SIrr, X86::Int_CVTTSS2SIrm, 0 },
- { X86::Int_UCOMISDrr, X86::Int_UCOMISDrm, 0 },
- { X86::Int_UCOMISSrr, X86::Int_UCOMISSrm, 0 },
+ { X86::Int_CVTTSD2SI64rr,X86::Int_CVTTSD2SI64rm, TB_NO_REVERSE },
+ { X86::Int_CVTTSD2SIrr, X86::Int_CVTTSD2SIrm, TB_NO_REVERSE },
+ { X86::Int_CVTTSS2SI64rr,X86::Int_CVTTSS2SI64rm, TB_NO_REVERSE },
+ { X86::Int_CVTTSS2SIrr, X86::Int_CVTTSS2SIrm, TB_NO_REVERSE },
+ { X86::Int_UCOMISDrr, X86::Int_UCOMISDrm, TB_NO_REVERSE },
+ { X86::Int_UCOMISSrr, X86::Int_UCOMISSrm, TB_NO_REVERSE },
{ X86::MOV16rr, X86::MOV16rm, 0 },
{ X86::MOV32rr, X86::MOV32rm, 0 },
{ X86::MOV64rr, X86::MOV64rm, 0 },
@@ -499,10 +543,11 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::MOV8rr, X86::MOV8rm, 0 },
{ X86::MOVAPDrr, X86::MOVAPDrm, TB_ALIGN_16 },
{ X86::MOVAPSrr, X86::MOVAPSrm, TB_ALIGN_16 },
- { X86::MOVDDUPrr, X86::MOVDDUPrm, 0 },
+ { X86::MOVDDUPrr, X86::MOVDDUPrm, TB_NO_REVERSE },
{ X86::MOVDI2PDIrr, X86::MOVDI2PDIrm, 0 },
{ X86::MOVDI2SSrr, X86::MOVDI2SSrm, 0 },
{ X86::MOVDQArr, X86::MOVDQArm, TB_ALIGN_16 },
+ { X86::MOVDQUrr, X86::MOVDQUrm, 0 },
{ X86::MOVSHDUPrr, X86::MOVSHDUPrm, TB_ALIGN_16 },
{ X86::MOVSLDUPrr, X86::MOVSLDUPrm, TB_ALIGN_16 },
{ X86::MOVSX16rr8, X86::MOVSX16rm8, 0 },
@@ -511,51 +556,53 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::MOVSX64rr16, X86::MOVSX64rm16, 0 },
{ X86::MOVSX64rr32, X86::MOVSX64rm32, 0 },
{ X86::MOVSX64rr8, X86::MOVSX64rm8, 0 },
- { X86::MOVUPDrr, X86::MOVUPDrm, TB_ALIGN_16 },
+ { X86::MOVUPDrr, X86::MOVUPDrm, 0 },
{ X86::MOVUPSrr, X86::MOVUPSrm, 0 },
- { X86::MOVZPQILo2PQIrr, X86::MOVZPQILo2PQIrm, TB_ALIGN_16 },
+ { X86::MOVZPQILo2PQIrr, X86::MOVQI2PQIrm, TB_NO_REVERSE },
{ X86::MOVZX16rr8, X86::MOVZX16rm8, 0 },
{ X86::MOVZX32rr16, X86::MOVZX32rm16, 0 },
{ X86::MOVZX32_NOREXrr8, X86::MOVZX32_NOREXrm8, 0 },
{ X86::MOVZX32rr8, X86::MOVZX32rm8, 0 },
- { X86::PABSBrr128, X86::PABSBrm128, TB_ALIGN_16 },
- { X86::PABSDrr128, X86::PABSDrm128, TB_ALIGN_16 },
- { X86::PABSWrr128, X86::PABSWrm128, TB_ALIGN_16 },
+ { X86::PABSBrr, X86::PABSBrm, TB_ALIGN_16 },
+ { X86::PABSDrr, X86::PABSDrm, TB_ALIGN_16 },
+ { X86::PABSWrr, X86::PABSWrm, TB_ALIGN_16 },
{ X86::PCMPESTRIrr, X86::PCMPESTRIrm, TB_ALIGN_16 },
{ X86::PCMPESTRM128rr, X86::PCMPESTRM128rm, TB_ALIGN_16 },
{ X86::PCMPISTRIrr, X86::PCMPISTRIrm, TB_ALIGN_16 },
{ X86::PCMPISTRM128rr, X86::PCMPISTRM128rm, TB_ALIGN_16 },
{ X86::PHMINPOSUWrr128, X86::PHMINPOSUWrm128, TB_ALIGN_16 },
- { X86::PMOVSXBDrr, X86::PMOVSXBDrm, TB_ALIGN_16 },
- { X86::PMOVSXBQrr, X86::PMOVSXBQrm, TB_ALIGN_16 },
- { X86::PMOVSXBWrr, X86::PMOVSXBWrm, TB_ALIGN_16 },
- { X86::PMOVSXDQrr, X86::PMOVSXDQrm, TB_ALIGN_16 },
- { X86::PMOVSXWDrr, X86::PMOVSXWDrm, TB_ALIGN_16 },
- { X86::PMOVSXWQrr, X86::PMOVSXWQrm, TB_ALIGN_16 },
- { X86::PMOVZXBDrr, X86::PMOVZXBDrm, TB_ALIGN_16 },
- { X86::PMOVZXBQrr, X86::PMOVZXBQrm, TB_ALIGN_16 },
- { X86::PMOVZXBWrr, X86::PMOVZXBWrm, TB_ALIGN_16 },
- { X86::PMOVZXDQrr, X86::PMOVZXDQrm, TB_ALIGN_16 },
- { X86::PMOVZXWDrr, X86::PMOVZXWDrm, TB_ALIGN_16 },
- { X86::PMOVZXWQrr, X86::PMOVZXWQrm, TB_ALIGN_16 },
+ { X86::PMOVSXBDrr, X86::PMOVSXBDrm, TB_NO_REVERSE },
+ { X86::PMOVSXBQrr, X86::PMOVSXBQrm, TB_NO_REVERSE },
+ { X86::PMOVSXBWrr, X86::PMOVSXBWrm, TB_NO_REVERSE },
+ { X86::PMOVSXDQrr, X86::PMOVSXDQrm, TB_NO_REVERSE },
+ { X86::PMOVSXWDrr, X86::PMOVSXWDrm, TB_NO_REVERSE },
+ { X86::PMOVSXWQrr, X86::PMOVSXWQrm, TB_NO_REVERSE },
+ { X86::PMOVZXBDrr, X86::PMOVZXBDrm, TB_NO_REVERSE },
+ { X86::PMOVZXBQrr, X86::PMOVZXBQrm, TB_NO_REVERSE },
+ { X86::PMOVZXBWrr, X86::PMOVZXBWrm, TB_NO_REVERSE },
+ { X86::PMOVZXDQrr, X86::PMOVZXDQrm, TB_NO_REVERSE },
+ { X86::PMOVZXWDrr, X86::PMOVZXWDrm, TB_NO_REVERSE },
+ { X86::PMOVZXWQrr, X86::PMOVZXWQrm, TB_NO_REVERSE },
{ X86::PSHUFDri, X86::PSHUFDmi, TB_ALIGN_16 },
{ X86::PSHUFHWri, X86::PSHUFHWmi, TB_ALIGN_16 },
{ X86::PSHUFLWri, X86::PSHUFLWmi, TB_ALIGN_16 },
{ X86::PTESTrr, X86::PTESTrm, TB_ALIGN_16 },
{ X86::RCPPSr, X86::RCPPSm, TB_ALIGN_16 },
{ X86::RCPSSr, X86::RCPSSm, 0 },
- { X86::RCPSSr_Int, X86::RCPSSm_Int, 0 },
+ { X86::RCPSSr_Int, X86::RCPSSm_Int, TB_NO_REVERSE },
{ X86::ROUNDPDr, X86::ROUNDPDm, TB_ALIGN_16 },
{ X86::ROUNDPSr, X86::ROUNDPSm, TB_ALIGN_16 },
+ { X86::ROUNDSDr, X86::ROUNDSDm, 0 },
+ { X86::ROUNDSSr, X86::ROUNDSSm, 0 },
{ X86::RSQRTPSr, X86::RSQRTPSm, TB_ALIGN_16 },
{ X86::RSQRTSSr, X86::RSQRTSSm, 0 },
- { X86::RSQRTSSr_Int, X86::RSQRTSSm_Int, 0 },
+ { X86::RSQRTSSr_Int, X86::RSQRTSSm_Int, TB_NO_REVERSE },
{ X86::SQRTPDr, X86::SQRTPDm, TB_ALIGN_16 },
{ X86::SQRTPSr, X86::SQRTPSm, TB_ALIGN_16 },
{ X86::SQRTSDr, X86::SQRTSDm, 0 },
- { X86::SQRTSDr_Int, X86::SQRTSDm_Int, 0 },
+ { X86::SQRTSDr_Int, X86::SQRTSDm_Int, TB_NO_REVERSE },
{ X86::SQRTSSr, X86::SQRTSSm, 0 },
- { X86::SQRTSSr_Int, X86::SQRTSSm_Int, 0 },
+ { X86::SQRTSSr_Int, X86::SQRTSSm_Int, TB_NO_REVERSE },
{ X86::TEST16rr, X86::TEST16rm, 0 },
{ X86::TEST32rr, X86::TEST32rm, 0 },
{ X86::TEST64rr, X86::TEST64rm, 0 },
@@ -586,46 +633,47 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::PSWAPDrr, X86::PSWAPDrm, 0 },
// AVX 128-bit versions of foldable instructions
- { X86::Int_VCOMISDrr, X86::Int_VCOMISDrm, 0 },
- { X86::Int_VCOMISSrr, X86::Int_VCOMISSrm, 0 },
- { X86::Int_VUCOMISDrr, X86::Int_VUCOMISDrm, 0 },
- { X86::Int_VUCOMISSrr, X86::Int_VUCOMISSrm, 0 },
+ { X86::Int_VCOMISDrr, X86::Int_VCOMISDrm, TB_NO_REVERSE },
+ { X86::Int_VCOMISSrr, X86::Int_VCOMISSrm, TB_NO_REVERSE },
+ { X86::Int_VUCOMISDrr, X86::Int_VUCOMISDrm, TB_NO_REVERSE },
+ { X86::Int_VUCOMISSrr, X86::Int_VUCOMISSrm, TB_NO_REVERSE },
{ X86::VCVTTSD2SI64rr, X86::VCVTTSD2SI64rm, 0 },
- { X86::Int_VCVTTSD2SI64rr,X86::Int_VCVTTSD2SI64rm,0 },
+ { X86::Int_VCVTTSD2SI64rr,X86::Int_VCVTTSD2SI64rm,TB_NO_REVERSE },
{ X86::VCVTTSD2SIrr, X86::VCVTTSD2SIrm, 0 },
- { X86::Int_VCVTTSD2SIrr,X86::Int_VCVTTSD2SIrm, 0 },
+ { X86::Int_VCVTTSD2SIrr,X86::Int_VCVTTSD2SIrm, TB_NO_REVERSE },
{ X86::VCVTTSS2SI64rr, X86::VCVTTSS2SI64rm, 0 },
- { X86::Int_VCVTTSS2SI64rr,X86::Int_VCVTTSS2SI64rm,0 },
+ { X86::Int_VCVTTSS2SI64rr,X86::Int_VCVTTSS2SI64rm,TB_NO_REVERSE },
{ X86::VCVTTSS2SIrr, X86::VCVTTSS2SIrm, 0 },
- { X86::Int_VCVTTSS2SIrr,X86::Int_VCVTTSS2SIrm, 0 },
- { X86::VCVTSD2SI64rr, X86::VCVTSD2SI64rm, 0 },
- { X86::VCVTSD2SIrr, X86::VCVTSD2SIrm, 0 },
- { X86::VCVTSS2SI64rr, X86::VCVTSS2SI64rm, 0 },
- { X86::VCVTSS2SIrr, X86::VCVTSS2SIrm, 0 },
- { X86::VCVTDQ2PDrr, X86::VCVTDQ2PDrm, 0 },
+ { X86::Int_VCVTTSS2SIrr,X86::Int_VCVTTSS2SIrm, TB_NO_REVERSE },
+ { X86::VCVTSD2SI64rr, X86::VCVTSD2SI64rm, TB_NO_REVERSE },
+ { X86::VCVTSD2SIrr, X86::VCVTSD2SIrm, TB_NO_REVERSE },
+ { X86::VCVTSS2SI64rr, X86::VCVTSS2SI64rm, TB_NO_REVERSE },
+ { X86::VCVTSS2SIrr, X86::VCVTSS2SIrm, TB_NO_REVERSE },
+ { X86::VCVTDQ2PDrr, X86::VCVTDQ2PDrm, TB_NO_REVERSE },
{ X86::VCVTDQ2PSrr, X86::VCVTDQ2PSrm, 0 },
- { X86::VCVTPD2DQrr, X86::VCVTPD2DQXrm, 0 },
- { X86::VCVTPD2PSrr, X86::VCVTPD2PSXrm, 0 },
+ { X86::VCVTPD2DQrr, X86::VCVTPD2DQrm, 0 },
+ { X86::VCVTPD2PSrr, X86::VCVTPD2PSrm, 0 },
{ X86::VCVTPS2DQrr, X86::VCVTPS2DQrm, 0 },
- { X86::VCVTPS2PDrr, X86::VCVTPS2PDrm, 0 },
- { X86::VCVTTPD2DQrr, X86::VCVTTPD2DQXrm, 0 },
+ { X86::VCVTPS2PDrr, X86::VCVTPS2PDrm, TB_NO_REVERSE },
+ { X86::VCVTTPD2DQrr, X86::VCVTTPD2DQrm, 0 },
{ X86::VCVTTPS2DQrr, X86::VCVTTPS2DQrm, 0 },
{ X86::VMOV64toPQIrr, X86::VMOVQI2PQIrm, 0 },
{ X86::VMOV64toSDrr, X86::VMOV64toSDrm, 0 },
{ X86::VMOVAPDrr, X86::VMOVAPDrm, TB_ALIGN_16 },
{ X86::VMOVAPSrr, X86::VMOVAPSrm, TB_ALIGN_16 },
- { X86::VMOVDDUPrr, X86::VMOVDDUPrm, 0 },
+ { X86::VMOVDDUPrr, X86::VMOVDDUPrm, TB_NO_REVERSE },
{ X86::VMOVDI2PDIrr, X86::VMOVDI2PDIrm, 0 },
{ X86::VMOVDI2SSrr, X86::VMOVDI2SSrm, 0 },
{ X86::VMOVDQArr, X86::VMOVDQArm, TB_ALIGN_16 },
+ { X86::VMOVDQUrr, X86::VMOVDQUrm, 0 },
{ X86::VMOVSLDUPrr, X86::VMOVSLDUPrm, 0 },
{ X86::VMOVSHDUPrr, X86::VMOVSHDUPrm, 0 },
{ X86::VMOVUPDrr, X86::VMOVUPDrm, 0 },
{ X86::VMOVUPSrr, X86::VMOVUPSrm, 0 },
- { X86::VMOVZPQILo2PQIrr,X86::VMOVZPQILo2PQIrm, TB_ALIGN_16 },
- { X86::VPABSBrr128, X86::VPABSBrm128, 0 },
- { X86::VPABSDrr128, X86::VPABSDrm128, 0 },
- { X86::VPABSWrr128, X86::VPABSWrm128, 0 },
+ { X86::VMOVZPQILo2PQIrr,X86::VMOVQI2PQIrm, TB_NO_REVERSE },
+ { X86::VPABSBrr, X86::VPABSBrm, 0 },
+ { X86::VPABSDrr, X86::VPABSDrm, 0 },
+ { X86::VPABSWrr, X86::VPABSWrm, 0 },
{ X86::VPCMPESTRIrr, X86::VPCMPESTRIrm, 0 },
{ X86::VPCMPESTRM128rr, X86::VPCMPESTRM128rm, 0 },
{ X86::VPCMPISTRIrr, X86::VPCMPISTRIrm, 0 },
@@ -633,18 +681,18 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPHMINPOSUWrr128, X86::VPHMINPOSUWrm128, 0 },
{ X86::VPERMILPDri, X86::VPERMILPDmi, 0 },
{ X86::VPERMILPSri, X86::VPERMILPSmi, 0 },
- { X86::VPMOVSXBDrr, X86::VPMOVSXBDrm, 0 },
- { X86::VPMOVSXBQrr, X86::VPMOVSXBQrm, 0 },
- { X86::VPMOVSXBWrr, X86::VPMOVSXBWrm, 0 },
- { X86::VPMOVSXDQrr, X86::VPMOVSXDQrm, 0 },
- { X86::VPMOVSXWDrr, X86::VPMOVSXWDrm, 0 },
- { X86::VPMOVSXWQrr, X86::VPMOVSXWQrm, 0 },
- { X86::VPMOVZXBDrr, X86::VPMOVZXBDrm, 0 },
- { X86::VPMOVZXBQrr, X86::VPMOVZXBQrm, 0 },
- { X86::VPMOVZXBWrr, X86::VPMOVZXBWrm, 0 },
- { X86::VPMOVZXDQrr, X86::VPMOVZXDQrm, 0 },
- { X86::VPMOVZXWDrr, X86::VPMOVZXWDrm, 0 },
- { X86::VPMOVZXWQrr, X86::VPMOVZXWQrm, 0 },
+ { X86::VPMOVSXBDrr, X86::VPMOVSXBDrm, TB_NO_REVERSE },
+ { X86::VPMOVSXBQrr, X86::VPMOVSXBQrm, TB_NO_REVERSE },
+ { X86::VPMOVSXBWrr, X86::VPMOVSXBWrm, TB_NO_REVERSE },
+ { X86::VPMOVSXDQrr, X86::VPMOVSXDQrm, TB_NO_REVERSE },
+ { X86::VPMOVSXWDrr, X86::VPMOVSXWDrm, TB_NO_REVERSE },
+ { X86::VPMOVSXWQrr, X86::VPMOVSXWQrm, TB_NO_REVERSE },
+ { X86::VPMOVZXBDrr, X86::VPMOVZXBDrm, TB_NO_REVERSE },
+ { X86::VPMOVZXBQrr, X86::VPMOVZXBQrm, TB_NO_REVERSE },
+ { X86::VPMOVZXBWrr, X86::VPMOVZXBWrm, TB_NO_REVERSE },
+ { X86::VPMOVZXDQrr, X86::VPMOVZXDQrm, TB_NO_REVERSE },
+ { X86::VPMOVZXWDrr, X86::VPMOVZXWDrm, TB_NO_REVERSE },
+ { X86::VPMOVZXWQrr, X86::VPMOVZXWQrm, TB_NO_REVERSE },
{ X86::VPSHUFDri, X86::VPSHUFDmi, 0 },
{ X86::VPSHUFHWri, X86::VPSHUFHWmi, 0 },
{ X86::VPSHUFLWri, X86::VPSHUFLWmi, 0 },
@@ -661,18 +709,19 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VUCOMISSrr, X86::VUCOMISSrm, 0 },
// AVX 256-bit foldable instructions
- { X86::VCVTDQ2PDYrr, X86::VCVTDQ2PDYrm, 0 },
+ { X86::VCVTDQ2PDYrr, X86::VCVTDQ2PDYrm, TB_NO_REVERSE },
{ X86::VCVTDQ2PSYrr, X86::VCVTDQ2PSYrm, 0 },
{ X86::VCVTPD2DQYrr, X86::VCVTPD2DQYrm, 0 },
{ X86::VCVTPD2PSYrr, X86::VCVTPD2PSYrm, 0 },
{ X86::VCVTPS2DQYrr, X86::VCVTPS2DQYrm, 0 },
- { X86::VCVTPS2PDYrr, X86::VCVTPS2PDYrm, 0 },
+ { X86::VCVTPS2PDYrr, X86::VCVTPS2PDYrm, TB_NO_REVERSE },
{ X86::VCVTTPD2DQYrr, X86::VCVTTPD2DQYrm, 0 },
{ X86::VCVTTPS2DQYrr, X86::VCVTTPS2DQYrm, 0 },
{ X86::VMOVAPDYrr, X86::VMOVAPDYrm, TB_ALIGN_32 },
{ X86::VMOVAPSYrr, X86::VMOVAPSYrm, TB_ALIGN_32 },
{ X86::VMOVDDUPYrr, X86::VMOVDDUPYrm, 0 },
{ X86::VMOVDQAYrr, X86::VMOVDQAYrm, TB_ALIGN_32 },
+ { X86::VMOVDQUYrr, X86::VMOVDQUYrm, 0 },
{ X86::VMOVSLDUPYrr, X86::VMOVSLDUPYrm, 0 },
{ X86::VMOVSHDUPYrr, X86::VMOVSHDUPYrm, 0 },
{ X86::VMOVUPDYrr, X86::VMOVUPDYrm, 0 },
@@ -699,31 +748,31 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VBROADCASTSSrr, X86::VBROADCASTSSrm, TB_NO_REVERSE },
{ X86::VBROADCASTSSYrr, X86::VBROADCASTSSYrm, TB_NO_REVERSE },
{ X86::VBROADCASTSDYrr, X86::VBROADCASTSDYrm, TB_NO_REVERSE },
- { X86::VPABSBrr256, X86::VPABSBrm256, 0 },
- { X86::VPABSDrr256, X86::VPABSDrm256, 0 },
- { X86::VPABSWrr256, X86::VPABSWrm256, 0 },
- { X86::VPBROADCASTBrr, X86::VPBROADCASTBrm, 0 },
- { X86::VPBROADCASTBYrr, X86::VPBROADCASTBYrm, 0 },
- { X86::VPBROADCASTDrr, X86::VPBROADCASTDrm, 0 },
- { X86::VPBROADCASTDYrr, X86::VPBROADCASTDYrm, 0 },
- { X86::VPBROADCASTQrr, X86::VPBROADCASTQrm, 0 },
- { X86::VPBROADCASTQYrr, X86::VPBROADCASTQYrm, 0 },
- { X86::VPBROADCASTWrr, X86::VPBROADCASTWrm, 0 },
- { X86::VPBROADCASTWYrr, X86::VPBROADCASTWYrm, 0 },
+ { X86::VPABSBYrr, X86::VPABSBYrm, 0 },
+ { X86::VPABSDYrr, X86::VPABSDYrm, 0 },
+ { X86::VPABSWYrr, X86::VPABSWYrm, 0 },
+ { X86::VPBROADCASTBrr, X86::VPBROADCASTBrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTBYrr, X86::VPBROADCASTBYrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTDrr, X86::VPBROADCASTDrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTDYrr, X86::VPBROADCASTDYrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTQrr, X86::VPBROADCASTQrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTQYrr, X86::VPBROADCASTQYrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTWrr, X86::VPBROADCASTWrm, TB_NO_REVERSE },
+ { X86::VPBROADCASTWYrr, X86::VPBROADCASTWYrm, TB_NO_REVERSE },
{ X86::VPERMPDYri, X86::VPERMPDYmi, 0 },
{ X86::VPERMQYri, X86::VPERMQYmi, 0 },
- { X86::VPMOVSXBDYrr, X86::VPMOVSXBDYrm, 0 },
- { X86::VPMOVSXBQYrr, X86::VPMOVSXBQYrm, 0 },
+ { X86::VPMOVSXBDYrr, X86::VPMOVSXBDYrm, TB_NO_REVERSE },
+ { X86::VPMOVSXBQYrr, X86::VPMOVSXBQYrm, TB_NO_REVERSE },
{ X86::VPMOVSXBWYrr, X86::VPMOVSXBWYrm, 0 },
{ X86::VPMOVSXDQYrr, X86::VPMOVSXDQYrm, 0 },
{ X86::VPMOVSXWDYrr, X86::VPMOVSXWDYrm, 0 },
- { X86::VPMOVSXWQYrr, X86::VPMOVSXWQYrm, 0 },
- { X86::VPMOVZXBDYrr, X86::VPMOVZXBDYrm, 0 },
- { X86::VPMOVZXBQYrr, X86::VPMOVZXBQYrm, 0 },
+ { X86::VPMOVSXWQYrr, X86::VPMOVSXWQYrm, TB_NO_REVERSE },
+ { X86::VPMOVZXBDYrr, X86::VPMOVZXBDYrm, TB_NO_REVERSE },
+ { X86::VPMOVZXBQYrr, X86::VPMOVZXBQYrm, TB_NO_REVERSE },
{ X86::VPMOVZXBWYrr, X86::VPMOVZXBWYrm, 0 },
{ X86::VPMOVZXDQYrr, X86::VPMOVZXDQYrm, 0 },
{ X86::VPMOVZXWDYrr, X86::VPMOVZXWDYrm, 0 },
- { X86::VPMOVZXWQYrr, X86::VPMOVZXWQYrm, 0 },
+ { X86::VPMOVZXWQYrr, X86::VPMOVZXWQYrm, TB_NO_REVERSE },
{ X86::VPSHUFDYri, X86::VPSHUFDYmi, 0 },
{ X86::VPSHUFHWYri, X86::VPSHUFHWYmi, 0 },
{ X86::VPSHUFLWYri, X86::VPSHUFLWYmi, 0 },
@@ -817,7 +866,12 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::TZMSK64rr, X86::TZMSK64rm, 0 },
// AVX-512 foldable instructions
+ { X86::VBROADCASTSSZr, X86::VBROADCASTSSZm, TB_NO_REVERSE },
+ { X86::VBROADCASTSSZr_s, X86::VBROADCASTSSZm, TB_NO_REVERSE },
+ { X86::VBROADCASTSDZr, X86::VBROADCASTSDZm, TB_NO_REVERSE },
+ { X86::VBROADCASTSDZr_s, X86::VBROADCASTSDZm, TB_NO_REVERSE },
{ X86::VMOV64toPQIZrr, X86::VMOVQI2PQIZrm, 0 },
+ { X86::VMOVZPQILo2PQIZrr,X86::VMOVQI2PQIZrm, TB_NO_REVERSE },
{ X86::VMOVDI2SSZrr, X86::VMOVDI2SSZrm, 0 },
{ X86::VMOVAPDZrr, X86::VMOVAPDZrm, TB_ALIGN_64 },
{ X86::VMOVAPSZrr, X86::VMOVAPSZrm, TB_ALIGN_64 },
@@ -831,12 +885,31 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVUPSZrr, X86::VMOVUPSZrm, 0 },
{ X86::VPABSDZrr, X86::VPABSDZrm, 0 },
{ X86::VPABSQZrr, X86::VPABSQZrm, 0 },
- { X86::VBROADCASTSSZr, X86::VBROADCASTSSZm, TB_NO_REVERSE },
- { X86::VBROADCASTSSZr_s, X86::VBROADCASTSSZm, TB_NO_REVERSE },
- { X86::VBROADCASTSDZr, X86::VBROADCASTSDZm, TB_NO_REVERSE },
- { X86::VBROADCASTSDZr_s, X86::VBROADCASTSDZm, TB_NO_REVERSE },
+ { X86::VPERMILPDZri, X86::VPERMILPDZmi, 0 },
+ { X86::VPERMILPSZri, X86::VPERMILPSZmi, 0 },
+ { X86::VPERMPDZri, X86::VPERMPDZmi, 0 },
+ { X86::VPERMQZri, X86::VPERMQZmi, 0 },
+ { X86::VPMOVSXBDZrr, X86::VPMOVSXBDZrm, 0 },
+ { X86::VPMOVSXBQZrr, X86::VPMOVSXBQZrm, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZrr, X86::VPMOVSXBWZrm, 0 },
+ { X86::VPMOVSXDQZrr, X86::VPMOVSXDQZrm, 0 },
+ { X86::VPMOVSXWDZrr, X86::VPMOVSXWDZrm, 0 },
+ { X86::VPMOVSXWQZrr, X86::VPMOVSXWQZrm, 0 },
+ { X86::VPMOVZXBDZrr, X86::VPMOVZXBDZrm, 0 },
+ { X86::VPMOVZXBQZrr, X86::VPMOVZXBQZrm, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZrr, X86::VPMOVZXBWZrm, 0 },
+ { X86::VPMOVZXDQZrr, X86::VPMOVZXDQZrm, 0 },
+ { X86::VPMOVZXWDZrr, X86::VPMOVZXWDZrm, 0 },
+ { X86::VPMOVZXWQZrr, X86::VPMOVZXWQZrm, 0 },
+ { X86::VPSHUFDZri, X86::VPSHUFDZmi, 0 },
+ { X86::VPSHUFHWZri, X86::VPSHUFHWZmi, 0 },
+ { X86::VPSHUFLWZri, X86::VPSHUFLWZmi, 0 },
// AVX-512 foldable instructions (256-bit versions)
+ { X86::VBROADCASTSSZ256r, X86::VBROADCASTSSZ256m, TB_NO_REVERSE },
+ { X86::VBROADCASTSSZ256r_s, X86::VBROADCASTSSZ256m, TB_NO_REVERSE },
+ { X86::VBROADCASTSDZ256r, X86::VBROADCASTSDZ256m, TB_NO_REVERSE },
+ { X86::VBROADCASTSDZ256r_s, X86::VBROADCASTSDZ256m, TB_NO_REVERSE },
{ X86::VMOVAPDZ256rr, X86::VMOVAPDZ256rm, TB_ALIGN_32 },
{ X86::VMOVAPSZ256rr, X86::VMOVAPSZ256rm, TB_ALIGN_32 },
{ X86::VMOVDQA32Z256rr, X86::VMOVDQA32Z256rm, TB_ALIGN_32 },
@@ -847,12 +920,29 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVDQU64Z256rr, X86::VMOVDQU64Z256rm, 0 },
{ X86::VMOVUPDZ256rr, X86::VMOVUPDZ256rm, 0 },
{ X86::VMOVUPSZ256rr, X86::VMOVUPSZ256rm, 0 },
- { X86::VBROADCASTSSZ256r, X86::VBROADCASTSSZ256m, TB_NO_REVERSE },
- { X86::VBROADCASTSSZ256r_s, X86::VBROADCASTSSZ256m, TB_NO_REVERSE },
- { X86::VBROADCASTSDZ256r, X86::VBROADCASTSDZ256m, TB_NO_REVERSE },
- { X86::VBROADCASTSDZ256r_s, X86::VBROADCASTSDZ256m, TB_NO_REVERSE },
+ { X86::VPERMILPDZ256ri, X86::VPERMILPDZ256mi, 0 },
+ { X86::VPERMILPSZ256ri, X86::VPERMILPSZ256mi, 0 },
+ { X86::VPERMPDZ256ri, X86::VPERMPDZ256mi, 0 },
+ { X86::VPERMQZ256ri, X86::VPERMQZ256mi, 0 },
+ { X86::VPMOVSXBDZ256rr, X86::VPMOVSXBDZ256rm, TB_NO_REVERSE },
+ { X86::VPMOVSXBQZ256rr, X86::VPMOVSXBQZ256rm, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZ256rr, X86::VPMOVSXBWZ256rm, 0 },
+ { X86::VPMOVSXDQZ256rr, X86::VPMOVSXDQZ256rm, 0 },
+ { X86::VPMOVSXWDZ256rr, X86::VPMOVSXWDZ256rm, 0 },
+ { X86::VPMOVSXWQZ256rr, X86::VPMOVSXWQZ256rm, TB_NO_REVERSE },
+ { X86::VPMOVZXBDZ256rr, X86::VPMOVZXBDZ256rm, TB_NO_REVERSE },
+ { X86::VPMOVZXBQZ256rr, X86::VPMOVZXBQZ256rm, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZ256rr, X86::VPMOVZXBWZ256rm, 0 },
+ { X86::VPMOVZXDQZ256rr, X86::VPMOVZXDQZ256rm, 0 },
+ { X86::VPMOVZXWDZ256rr, X86::VPMOVZXWDZ256rm, 0 },
+ { X86::VPMOVZXWQZ256rr, X86::VPMOVZXWQZ256rm, TB_NO_REVERSE },
+ { X86::VPSHUFDZ256ri, X86::VPSHUFDZ256mi, 0 },
+ { X86::VPSHUFHWZ256ri, X86::VPSHUFHWZ256mi, 0 },
+ { X86::VPSHUFLWZ256ri, X86::VPSHUFLWZ256mi, 0 },
// AVX-512 foldable instructions (128-bit versions)
+ { X86::VBROADCASTSSZ128r, X86::VBROADCASTSSZ128m, TB_NO_REVERSE },
+ { X86::VBROADCASTSSZ128r_s, X86::VBROADCASTSSZ128m, TB_NO_REVERSE },
{ X86::VMOVAPDZ128rr, X86::VMOVAPDZ128rm, TB_ALIGN_16 },
{ X86::VMOVAPSZ128rr, X86::VMOVAPSZ128rm, TB_ALIGN_16 },
{ X86::VMOVDQA32Z128rr, X86::VMOVDQA32Z128rm, TB_ALIGN_16 },
@@ -863,8 +953,24 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VMOVDQU64Z128rr, X86::VMOVDQU64Z128rm, 0 },
{ X86::VMOVUPDZ128rr, X86::VMOVUPDZ128rm, 0 },
{ X86::VMOVUPSZ128rr, X86::VMOVUPSZ128rm, 0 },
- { X86::VBROADCASTSSZ128r, X86::VBROADCASTSSZ128m, TB_NO_REVERSE },
- { X86::VBROADCASTSSZ128r_s, X86::VBROADCASTSSZ128m, TB_NO_REVERSE },
+ { X86::VPERMILPDZ128ri, X86::VPERMILPDZ128mi, 0 },
+ { X86::VPERMILPSZ128ri, X86::VPERMILPSZ128mi, 0 },
+ { X86::VPMOVSXBDZ128rr, X86::VPMOVSXBDZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVSXBQZ128rr, X86::VPMOVSXBQZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZ128rr, X86::VPMOVSXBWZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVSXDQZ128rr, X86::VPMOVSXDQZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVSXWDZ128rr, X86::VPMOVSXWDZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVSXWQZ128rr, X86::VPMOVSXWQZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVZXBDZ128rr, X86::VPMOVZXBDZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVZXBQZ128rr, X86::VPMOVZXBQZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZ128rr, X86::VPMOVZXBWZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVZXDQZ128rr, X86::VPMOVZXDQZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVZXWDZ128rr, X86::VPMOVZXWDZ128rm, TB_NO_REVERSE },
+ { X86::VPMOVZXWQZ128rr, X86::VPMOVZXWQZ128rm, TB_NO_REVERSE },
+ { X86::VPSHUFDZ128ri, X86::VPSHUFDZ128mi, 0 },
+ { X86::VPSHUFHWZ128ri, X86::VPSHUFHWZ128mi, 0 },
+ { X86::VPSHUFLWZ128ri, X86::VPSHUFLWZ128mi, 0 },
+
// F16C foldable instructions
{ X86::VCVTPH2PSrr, X86::VCVTPH2PSrm, 0 },
{ X86::VCVTPH2PSYrr, X86::VCVTPH2PSYrm, 0 },
@@ -896,9 +1002,9 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::ADDPDrr, X86::ADDPDrm, TB_ALIGN_16 },
{ X86::ADDPSrr, X86::ADDPSrm, TB_ALIGN_16 },
{ X86::ADDSDrr, X86::ADDSDrm, 0 },
- { X86::ADDSDrr_Int, X86::ADDSDrm_Int, 0 },
+ { X86::ADDSDrr_Int, X86::ADDSDrm_Int, TB_NO_REVERSE },
{ X86::ADDSSrr, X86::ADDSSrm, 0 },
- { X86::ADDSSrr_Int, X86::ADDSSrm_Int, 0 },
+ { X86::ADDSSrr_Int, X86::ADDSSrm_Int, TB_NO_REVERSE },
{ X86::ADDSUBPDrr, X86::ADDSUBPDrm, TB_ALIGN_16 },
{ X86::ADDSUBPSrr, X86::ADDSUBPSrm, TB_ALIGN_16 },
{ X86::AND16rr, X86::AND16rm, 0 },
@@ -970,24 +1076,11 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::DIVPDrr, X86::DIVPDrm, TB_ALIGN_16 },
{ X86::DIVPSrr, X86::DIVPSrm, TB_ALIGN_16 },
{ X86::DIVSDrr, X86::DIVSDrm, 0 },
- { X86::DIVSDrr_Int, X86::DIVSDrm_Int, 0 },
+ { X86::DIVSDrr_Int, X86::DIVSDrm_Int, TB_NO_REVERSE },
{ X86::DIVSSrr, X86::DIVSSrm, 0 },
- { X86::DIVSSrr_Int, X86::DIVSSrm_Int, 0 },
+ { X86::DIVSSrr_Int, X86::DIVSSrm_Int, TB_NO_REVERSE },
{ X86::DPPDrri, X86::DPPDrmi, TB_ALIGN_16 },
{ X86::DPPSrri, X86::DPPSrmi, TB_ALIGN_16 },
-
- // Do not fold Fs* scalar logical op loads because there are no scalar
- // load variants for these instructions. When folded, the load is required
- // to be 128-bits, so the load size would not match.
-
- { X86::FvANDNPDrr, X86::FvANDNPDrm, TB_ALIGN_16 },
- { X86::FvANDNPSrr, X86::FvANDNPSrm, TB_ALIGN_16 },
- { X86::FvANDPDrr, X86::FvANDPDrm, TB_ALIGN_16 },
- { X86::FvANDPSrr, X86::FvANDPSrm, TB_ALIGN_16 },
- { X86::FvORPDrr, X86::FvORPDrm, TB_ALIGN_16 },
- { X86::FvORPSrr, X86::FvORPSrm, TB_ALIGN_16 },
- { X86::FvXORPDrr, X86::FvXORPDrm, TB_ALIGN_16 },
- { X86::FvXORPSrr, X86::FvXORPSrm, TB_ALIGN_16 },
{ X86::HADDPDrr, X86::HADDPDrm, TB_ALIGN_16 },
{ X86::HADDPSrr, X86::HADDPSrm, TB_ALIGN_16 },
{ X86::HSUBPDrr, X86::HSUBPDrm, TB_ALIGN_16 },
@@ -995,34 +1088,42 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::IMUL16rr, X86::IMUL16rm, 0 },
{ X86::IMUL32rr, X86::IMUL32rm, 0 },
{ X86::IMUL64rr, X86::IMUL64rm, 0 },
- { X86::Int_CMPSDrr, X86::Int_CMPSDrm, 0 },
- { X86::Int_CMPSSrr, X86::Int_CMPSSrm, 0 },
- { X86::Int_CVTSD2SSrr, X86::Int_CVTSD2SSrm, 0 },
+ { X86::Int_CMPSDrr, X86::Int_CMPSDrm, TB_NO_REVERSE },
+ { X86::Int_CMPSSrr, X86::Int_CMPSSrm, TB_NO_REVERSE },
+ { X86::Int_CVTSD2SSrr, X86::Int_CVTSD2SSrm, TB_NO_REVERSE },
{ X86::Int_CVTSI2SD64rr,X86::Int_CVTSI2SD64rm, 0 },
{ X86::Int_CVTSI2SDrr, X86::Int_CVTSI2SDrm, 0 },
{ X86::Int_CVTSI2SS64rr,X86::Int_CVTSI2SS64rm, 0 },
{ X86::Int_CVTSI2SSrr, X86::Int_CVTSI2SSrm, 0 },
- { X86::Int_CVTSS2SDrr, X86::Int_CVTSS2SDrm, 0 },
+ { X86::Int_CVTSS2SDrr, X86::Int_CVTSS2SDrm, TB_NO_REVERSE },
{ X86::MAXPDrr, X86::MAXPDrm, TB_ALIGN_16 },
+ { X86::MAXCPDrr, X86::MAXCPDrm, TB_ALIGN_16 },
{ X86::MAXPSrr, X86::MAXPSrm, TB_ALIGN_16 },
+ { X86::MAXCPSrr, X86::MAXCPSrm, TB_ALIGN_16 },
{ X86::MAXSDrr, X86::MAXSDrm, 0 },
- { X86::MAXSDrr_Int, X86::MAXSDrm_Int, 0 },
+ { X86::MAXCSDrr, X86::MAXCSDrm, 0 },
+ { X86::MAXSDrr_Int, X86::MAXSDrm_Int, TB_NO_REVERSE },
{ X86::MAXSSrr, X86::MAXSSrm, 0 },
- { X86::MAXSSrr_Int, X86::MAXSSrm_Int, 0 },
+ { X86::MAXCSSrr, X86::MAXCSSrm, 0 },
+ { X86::MAXSSrr_Int, X86::MAXSSrm_Int, TB_NO_REVERSE },
{ X86::MINPDrr, X86::MINPDrm, TB_ALIGN_16 },
+ { X86::MINCPDrr, X86::MINCPDrm, TB_ALIGN_16 },
{ X86::MINPSrr, X86::MINPSrm, TB_ALIGN_16 },
+ { X86::MINCPSrr, X86::MINCPSrm, TB_ALIGN_16 },
{ X86::MINSDrr, X86::MINSDrm, 0 },
- { X86::MINSDrr_Int, X86::MINSDrm_Int, 0 },
+ { X86::MINCSDrr, X86::MINCSDrm, 0 },
+ { X86::MINSDrr_Int, X86::MINSDrm_Int, TB_NO_REVERSE },
{ X86::MINSSrr, X86::MINSSrm, 0 },
- { X86::MINSSrr_Int, X86::MINSSrm_Int, 0 },
+ { X86::MINCSSrr, X86::MINCSSrm, 0 },
+ { X86::MINSSrr_Int, X86::MINSSrm_Int, TB_NO_REVERSE },
{ X86::MOVLHPSrr, X86::MOVHPSrm, TB_NO_REVERSE },
{ X86::MPSADBWrri, X86::MPSADBWrmi, TB_ALIGN_16 },
{ X86::MULPDrr, X86::MULPDrm, TB_ALIGN_16 },
{ X86::MULPSrr, X86::MULPSrm, TB_ALIGN_16 },
{ X86::MULSDrr, X86::MULSDrm, 0 },
- { X86::MULSDrr_Int, X86::MULSDrm_Int, 0 },
+ { X86::MULSDrr_Int, X86::MULSDrm_Int, TB_NO_REVERSE },
{ X86::MULSSrr, X86::MULSSrm, 0 },
- { X86::MULSSrr_Int, X86::MULSSrm_Int, 0 },
+ { X86::MULSSrr_Int, X86::MULSSrm_Int, TB_NO_REVERSE },
{ X86::OR16rr, X86::OR16rm, 0 },
{ X86::OR32rr, X86::OR32rm, 0 },
{ X86::OR64rr, X86::OR64rm, 0 },
@@ -1067,7 +1168,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::PINSRDrr, X86::PINSRDrm, 0 },
{ X86::PINSRQrr, X86::PINSRQrm, 0 },
{ X86::PINSRWrri, X86::PINSRWrmi, 0 },
- { X86::PMADDUBSWrr128, X86::PMADDUBSWrm128, TB_ALIGN_16 },
+ { X86::PMADDUBSWrr, X86::PMADDUBSWrm, TB_ALIGN_16 },
{ X86::PMADDWDrr, X86::PMADDWDrm, TB_ALIGN_16 },
{ X86::PMAXSWrr, X86::PMAXSWrm, TB_ALIGN_16 },
{ X86::PMAXUBrr, X86::PMAXUBrm, TB_ALIGN_16 },
@@ -1082,7 +1183,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::PMAXUDrr, X86::PMAXUDrm, TB_ALIGN_16 },
{ X86::PMAXUWrr, X86::PMAXUWrm, TB_ALIGN_16 },
{ X86::PMULDQrr, X86::PMULDQrm, TB_ALIGN_16 },
- { X86::PMULHRSWrr128, X86::PMULHRSWrm128, TB_ALIGN_16 },
+ { X86::PMULHRSWrr, X86::PMULHRSWrm, TB_ALIGN_16 },
{ X86::PMULHUWrr, X86::PMULHUWrm, TB_ALIGN_16 },
{ X86::PMULHWrr, X86::PMULHWrm, TB_ALIGN_16 },
{ X86::PMULLDrr, X86::PMULLDrm, TB_ALIGN_16 },
@@ -1119,8 +1220,8 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::PUNPCKLQDQrr, X86::PUNPCKLQDQrm, TB_ALIGN_16 },
{ X86::PUNPCKLWDrr, X86::PUNPCKLWDrm, TB_ALIGN_16 },
{ X86::PXORrr, X86::PXORrm, TB_ALIGN_16 },
- { X86::ROUNDSDr, X86::ROUNDSDm, 0 },
- { X86::ROUNDSSr, X86::ROUNDSSm, 0 },
+ { X86::ROUNDSDr_Int, X86::ROUNDSDm_Int, TB_NO_REVERSE },
+ { X86::ROUNDSSr_Int, X86::ROUNDSSm_Int, TB_NO_REVERSE },
{ X86::SBB32rr, X86::SBB32rm, 0 },
{ X86::SBB64rr, X86::SBB64rm, 0 },
{ X86::SHUFPDrri, X86::SHUFPDrmi, TB_ALIGN_16 },
@@ -1132,9 +1233,9 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::SUBPDrr, X86::SUBPDrm, TB_ALIGN_16 },
{ X86::SUBPSrr, X86::SUBPSrm, TB_ALIGN_16 },
{ X86::SUBSDrr, X86::SUBSDrm, 0 },
- { X86::SUBSDrr_Int, X86::SUBSDrm_Int, 0 },
+ { X86::SUBSDrr_Int, X86::SUBSDrm_Int, TB_NO_REVERSE },
{ X86::SUBSSrr, X86::SUBSSrm, 0 },
- { X86::SUBSSrr_Int, X86::SUBSSrm_Int, 0 },
+ { X86::SUBSSrr_Int, X86::SUBSSrm_Int, TB_NO_REVERSE },
// FIXME: TEST*rr -> swapped operand of TEST*mr.
{ X86::UNPCKHPDrr, X86::UNPCKHPDrm, TB_ALIGN_16 },
{ X86::UNPCKHPSrr, X86::UNPCKHPSrm, TB_ALIGN_16 },
@@ -1240,7 +1341,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
// AVX 128-bit versions of foldable instructions
{ X86::VCVTSD2SSrr, X86::VCVTSD2SSrm, 0 },
- { X86::Int_VCVTSD2SSrr, X86::Int_VCVTSD2SSrm, 0 },
+ { X86::Int_VCVTSD2SSrr, X86::Int_VCVTSD2SSrm, TB_NO_REVERSE },
{ X86::VCVTSI2SD64rr, X86::VCVTSI2SD64rm, 0 },
{ X86::Int_VCVTSI2SD64rr, X86::Int_VCVTSI2SD64rm, 0 },
{ X86::VCVTSI2SDrr, X86::VCVTSI2SDrm, 0 },
@@ -1250,21 +1351,13 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VCVTSI2SSrr, X86::VCVTSI2SSrm, 0 },
{ X86::Int_VCVTSI2SSrr, X86::Int_VCVTSI2SSrm, 0 },
{ X86::VCVTSS2SDrr, X86::VCVTSS2SDrm, 0 },
- { X86::Int_VCVTSS2SDrr, X86::Int_VCVTSS2SDrm, 0 },
- { X86::VRCPSSr, X86::VRCPSSm, 0 },
- { X86::VRCPSSr_Int, X86::VRCPSSm_Int, 0 },
- { X86::VRSQRTSSr, X86::VRSQRTSSm, 0 },
- { X86::VRSQRTSSr_Int, X86::VRSQRTSSm_Int, 0 },
- { X86::VSQRTSDr, X86::VSQRTSDm, 0 },
- { X86::VSQRTSDr_Int, X86::VSQRTSDm_Int, 0 },
- { X86::VSQRTSSr, X86::VSQRTSSm, 0 },
- { X86::VSQRTSSr_Int, X86::VSQRTSSm_Int, 0 },
+ { X86::Int_VCVTSS2SDrr, X86::Int_VCVTSS2SDrm, TB_NO_REVERSE },
{ X86::VADDPDrr, X86::VADDPDrm, 0 },
{ X86::VADDPSrr, X86::VADDPSrm, 0 },
{ X86::VADDSDrr, X86::VADDSDrm, 0 },
- { X86::VADDSDrr_Int, X86::VADDSDrm_Int, 0 },
+ { X86::VADDSDrr_Int, X86::VADDSDrm_Int, TB_NO_REVERSE },
{ X86::VADDSSrr, X86::VADDSSrm, 0 },
- { X86::VADDSSrr_Int, X86::VADDSSrm_Int, 0 },
+ { X86::VADDSSrr_Int, X86::VADDSSrm_Int, TB_NO_REVERSE },
{ X86::VADDSUBPDrr, X86::VADDSUBPDrm, 0 },
{ X86::VADDSUBPSrr, X86::VADDSUBPSrm, 0 },
{ X86::VANDNPDrr, X86::VANDNPDrm, 0 },
@@ -1282,48 +1375,45 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VDIVPDrr, X86::VDIVPDrm, 0 },
{ X86::VDIVPSrr, X86::VDIVPSrm, 0 },
{ X86::VDIVSDrr, X86::VDIVSDrm, 0 },
- { X86::VDIVSDrr_Int, X86::VDIVSDrm_Int, 0 },
+ { X86::VDIVSDrr_Int, X86::VDIVSDrm_Int, TB_NO_REVERSE },
{ X86::VDIVSSrr, X86::VDIVSSrm, 0 },
- { X86::VDIVSSrr_Int, X86::VDIVSSrm_Int, 0 },
+ { X86::VDIVSSrr_Int, X86::VDIVSSrm_Int, TB_NO_REVERSE },
{ X86::VDPPDrri, X86::VDPPDrmi, 0 },
{ X86::VDPPSrri, X86::VDPPSrmi, 0 },
- // Do not fold VFs* loads because there are no scalar load variants for
- // these instructions. When folded, the load is required to be 128-bits, so
- // the load size would not match.
- { X86::VFvANDNPDrr, X86::VFvANDNPDrm, 0 },
- { X86::VFvANDNPSrr, X86::VFvANDNPSrm, 0 },
- { X86::VFvANDPDrr, X86::VFvANDPDrm, 0 },
- { X86::VFvANDPSrr, X86::VFvANDPSrm, 0 },
- { X86::VFvORPDrr, X86::VFvORPDrm, 0 },
- { X86::VFvORPSrr, X86::VFvORPSrm, 0 },
- { X86::VFvXORPDrr, X86::VFvXORPDrm, 0 },
- { X86::VFvXORPSrr, X86::VFvXORPSrm, 0 },
{ X86::VHADDPDrr, X86::VHADDPDrm, 0 },
{ X86::VHADDPSrr, X86::VHADDPSrm, 0 },
{ X86::VHSUBPDrr, X86::VHSUBPDrm, 0 },
{ X86::VHSUBPSrr, X86::VHSUBPSrm, 0 },
- { X86::Int_VCMPSDrr, X86::Int_VCMPSDrm, 0 },
- { X86::Int_VCMPSSrr, X86::Int_VCMPSSrm, 0 },
+ { X86::Int_VCMPSDrr, X86::Int_VCMPSDrm, TB_NO_REVERSE },
+ { X86::Int_VCMPSSrr, X86::Int_VCMPSSrm, TB_NO_REVERSE },
+ { X86::VMAXCPDrr, X86::VMAXCPDrm, 0 },
+ { X86::VMAXCPSrr, X86::VMAXCPSrm, 0 },
+ { X86::VMAXCSDrr, X86::VMAXCSDrm, 0 },
+ { X86::VMAXCSSrr, X86::VMAXCSSrm, 0 },
{ X86::VMAXPDrr, X86::VMAXPDrm, 0 },
{ X86::VMAXPSrr, X86::VMAXPSrm, 0 },
{ X86::VMAXSDrr, X86::VMAXSDrm, 0 },
- { X86::VMAXSDrr_Int, X86::VMAXSDrm_Int, 0 },
+ { X86::VMAXSDrr_Int, X86::VMAXSDrm_Int, TB_NO_REVERSE },
{ X86::VMAXSSrr, X86::VMAXSSrm, 0 },
- { X86::VMAXSSrr_Int, X86::VMAXSSrm_Int, 0 },
+ { X86::VMAXSSrr_Int, X86::VMAXSSrm_Int, TB_NO_REVERSE },
+ { X86::VMINCPDrr, X86::VMINCPDrm, 0 },
+ { X86::VMINCPSrr, X86::VMINCPSrm, 0 },
+ { X86::VMINCSDrr, X86::VMINCSDrm, 0 },
+ { X86::VMINCSSrr, X86::VMINCSSrm, 0 },
{ X86::VMINPDrr, X86::VMINPDrm, 0 },
{ X86::VMINPSrr, X86::VMINPSrm, 0 },
{ X86::VMINSDrr, X86::VMINSDrm, 0 },
- { X86::VMINSDrr_Int, X86::VMINSDrm_Int, 0 },
+ { X86::VMINSDrr_Int, X86::VMINSDrm_Int, TB_NO_REVERSE },
{ X86::VMINSSrr, X86::VMINSSrm, 0 },
- { X86::VMINSSrr_Int, X86::VMINSSrm_Int, 0 },
+ { X86::VMINSSrr_Int, X86::VMINSSrm_Int, TB_NO_REVERSE },
{ X86::VMOVLHPSrr, X86::VMOVHPSrm, TB_NO_REVERSE },
{ X86::VMPSADBWrri, X86::VMPSADBWrmi, 0 },
{ X86::VMULPDrr, X86::VMULPDrm, 0 },
{ X86::VMULPSrr, X86::VMULPSrm, 0 },
{ X86::VMULSDrr, X86::VMULSDrm, 0 },
- { X86::VMULSDrr_Int, X86::VMULSDrm_Int, 0 },
+ { X86::VMULSDrr_Int, X86::VMULSDrm_Int, TB_NO_REVERSE },
{ X86::VMULSSrr, X86::VMULSSrm, 0 },
- { X86::VMULSSrr_Int, X86::VMULSSrm_Int, 0 },
+ { X86::VMULSSrr_Int, X86::VMULSSrm_Int, TB_NO_REVERSE },
{ X86::VORPDrr, X86::VORPDrm, 0 },
{ X86::VORPSrr, X86::VORPSrm, 0 },
{ X86::VPACKSSDWrr, X86::VPACKSSDWrm, 0 },
@@ -1366,7 +1456,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPINSRDrr, X86::VPINSRDrm, 0 },
{ X86::VPINSRQrr, X86::VPINSRQrm, 0 },
{ X86::VPINSRWrri, X86::VPINSRWrmi, 0 },
- { X86::VPMADDUBSWrr128, X86::VPMADDUBSWrm128, 0 },
+ { X86::VPMADDUBSWrr, X86::VPMADDUBSWrm, 0 },
{ X86::VPMADDWDrr, X86::VPMADDWDrm, 0 },
{ X86::VPMAXSWrr, X86::VPMAXSWrm, 0 },
{ X86::VPMAXUBrr, X86::VPMAXUBrm, 0 },
@@ -1381,7 +1471,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPMAXUDrr, X86::VPMAXUDrm, 0 },
{ X86::VPMAXUWrr, X86::VPMAXUWrm, 0 },
{ X86::VPMULDQrr, X86::VPMULDQrm, 0 },
- { X86::VPMULHRSWrr128, X86::VPMULHRSWrm128, 0 },
+ { X86::VPMULHRSWrr, X86::VPMULHRSWrm, 0 },
{ X86::VPMULHUWrr, X86::VPMULHUWrm, 0 },
{ X86::VPMULHWrr, X86::VPMULHWrm, 0 },
{ X86::VPMULLDrr, X86::VPMULLDrm, 0 },
@@ -1418,16 +1508,26 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPUNPCKLQDQrr, X86::VPUNPCKLQDQrm, 0 },
{ X86::VPUNPCKLWDrr, X86::VPUNPCKLWDrm, 0 },
{ X86::VPXORrr, X86::VPXORrm, 0 },
+ { X86::VRCPSSr, X86::VRCPSSm, 0 },
+ { X86::VRCPSSr_Int, X86::VRCPSSm_Int, TB_NO_REVERSE },
+ { X86::VRSQRTSSr, X86::VRSQRTSSm, 0 },
+ { X86::VRSQRTSSr_Int, X86::VRSQRTSSm_Int, TB_NO_REVERSE },
{ X86::VROUNDSDr, X86::VROUNDSDm, 0 },
+ { X86::VROUNDSDr_Int, X86::VROUNDSDm_Int, TB_NO_REVERSE },
{ X86::VROUNDSSr, X86::VROUNDSSm, 0 },
+ { X86::VROUNDSSr_Int, X86::VROUNDSSm_Int, TB_NO_REVERSE },
{ X86::VSHUFPDrri, X86::VSHUFPDrmi, 0 },
{ X86::VSHUFPSrri, X86::VSHUFPSrmi, 0 },
+ { X86::VSQRTSDr, X86::VSQRTSDm, 0 },
+ { X86::VSQRTSDr_Int, X86::VSQRTSDm_Int, TB_NO_REVERSE },
+ { X86::VSQRTSSr, X86::VSQRTSSm, 0 },
+ { X86::VSQRTSSr_Int, X86::VSQRTSSm_Int, TB_NO_REVERSE },
{ X86::VSUBPDrr, X86::VSUBPDrm, 0 },
{ X86::VSUBPSrr, X86::VSUBPSrm, 0 },
{ X86::VSUBSDrr, X86::VSUBSDrm, 0 },
- { X86::VSUBSDrr_Int, X86::VSUBSDrm_Int, 0 },
+ { X86::VSUBSDrr_Int, X86::VSUBSDrm_Int, TB_NO_REVERSE },
{ X86::VSUBSSrr, X86::VSUBSSrm, 0 },
- { X86::VSUBSSrr_Int, X86::VSUBSSrm_Int, 0 },
+ { X86::VSUBSSrr_Int, X86::VSUBSSrm_Int, TB_NO_REVERSE },
{ X86::VUNPCKHPDrr, X86::VUNPCKHPDrm, 0 },
{ X86::VUNPCKHPSrr, X86::VUNPCKHPSrm, 0 },
{ X86::VUNPCKLPDrr, X86::VUNPCKLPDrm, 0 },
@@ -1458,8 +1558,12 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VHSUBPDYrr, X86::VHSUBPDYrm, 0 },
{ X86::VHSUBPSYrr, X86::VHSUBPSYrm, 0 },
{ X86::VINSERTF128rr, X86::VINSERTF128rm, 0 },
+ { X86::VMAXCPDYrr, X86::VMAXCPDYrm, 0 },
+ { X86::VMAXCPSYrr, X86::VMAXCPSYrm, 0 },
{ X86::VMAXPDYrr, X86::VMAXPDYrm, 0 },
{ X86::VMAXPSYrr, X86::VMAXPSYrm, 0 },
+ { X86::VMINCPDYrr, X86::VMINCPDYrm, 0 },
+ { X86::VMINCPSYrr, X86::VMINCPSYrm, 0 },
{ X86::VMINPDYrr, X86::VMINPDYrm, 0 },
{ X86::VMINPSYrr, X86::VMINPSYrm, 0 },
{ X86::VMULPDYrr, X86::VMULPDYrm, 0 },
@@ -1520,7 +1624,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPHSUBDYrr, X86::VPHSUBDYrm, 0 },
{ X86::VPHSUBSWrr256, X86::VPHSUBSWrm256, 0 },
{ X86::VPHSUBWYrr, X86::VPHSUBWYrm, 0 },
- { X86::VPMADDUBSWrr256, X86::VPMADDUBSWrm256, 0 },
+ { X86::VPMADDUBSWYrr, X86::VPMADDUBSWYrm, 0 },
{ X86::VPMADDWDYrr, X86::VPMADDWDYrm, 0 },
{ X86::VPMAXSWYrr, X86::VPMAXSWYrm, 0 },
{ X86::VPMAXUBYrr, X86::VPMAXUBYrm, 0 },
@@ -1536,7 +1640,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPMAXUWYrr, X86::VPMAXUWYrm, 0 },
{ X86::VMPSADBWYrri, X86::VMPSADBWYrmi, 0 },
{ X86::VPMULDQYrr, X86::VPMULDQYrm, 0 },
- { X86::VPMULHRSWrr256, X86::VPMULHRSWrm256, 0 },
+ { X86::VPMULHRSWYrr, X86::VPMULHRSWYrm, 0 },
{ X86::VPMULHUWYrr, X86::VPMULHUWYrm, 0 },
{ X86::VPMULHWYrr, X86::VPMULHWYrm, 0 },
{ X86::VPMULLDYrr, X86::VPMULLDYrm, 0 },
@@ -1559,8 +1663,6 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPSRAWYrr, X86::VPSRAWYrm, 0 },
{ X86::VPSRAVDrr, X86::VPSRAVDrm, 0 },
{ X86::VPSRAVDYrr, X86::VPSRAVDYrm, 0 },
- { X86::VPSRAVD_Intrr, X86::VPSRAVD_Intrm, 0 },
- { X86::VPSRAVD_IntYrr, X86::VPSRAVD_IntYrm, 0 },
{ X86::VPSRLDYrr, X86::VPSRLDYrm, 0 },
{ X86::VPSRLQYrr, X86::VPSRLQYrm, 0 },
{ X86::VPSRLWYrr, X86::VPSRLWYrm, 0 },
@@ -1588,37 +1690,45 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
// FMA4 foldable patterns
{ X86::VFMADDSS4rr, X86::VFMADDSS4mr, TB_ALIGN_NONE },
+ { X86::VFMADDSS4rr_Int, X86::VFMADDSS4mr_Int, TB_NO_REVERSE },
{ X86::VFMADDSD4rr, X86::VFMADDSD4mr, TB_ALIGN_NONE },
+ { X86::VFMADDSD4rr_Int, X86::VFMADDSD4mr_Int, TB_NO_REVERSE },
{ X86::VFMADDPS4rr, X86::VFMADDPS4mr, TB_ALIGN_NONE },
{ X86::VFMADDPD4rr, X86::VFMADDPD4mr, TB_ALIGN_NONE },
- { X86::VFMADDPS4rrY, X86::VFMADDPS4mrY, TB_ALIGN_NONE },
- { X86::VFMADDPD4rrY, X86::VFMADDPD4mrY, TB_ALIGN_NONE },
+ { X86::VFMADDPS4Yrr, X86::VFMADDPS4Ymr, TB_ALIGN_NONE },
+ { X86::VFMADDPD4Yrr, X86::VFMADDPD4Ymr, TB_ALIGN_NONE },
{ X86::VFNMADDSS4rr, X86::VFNMADDSS4mr, TB_ALIGN_NONE },
+ { X86::VFNMADDSS4rr_Int, X86::VFNMADDSS4mr_Int, TB_NO_REVERSE },
{ X86::VFNMADDSD4rr, X86::VFNMADDSD4mr, TB_ALIGN_NONE },
+ { X86::VFNMADDSD4rr_Int, X86::VFNMADDSD4mr_Int, TB_NO_REVERSE },
{ X86::VFNMADDPS4rr, X86::VFNMADDPS4mr, TB_ALIGN_NONE },
{ X86::VFNMADDPD4rr, X86::VFNMADDPD4mr, TB_ALIGN_NONE },
- { X86::VFNMADDPS4rrY, X86::VFNMADDPS4mrY, TB_ALIGN_NONE },
- { X86::VFNMADDPD4rrY, X86::VFNMADDPD4mrY, TB_ALIGN_NONE },
+ { X86::VFNMADDPS4Yrr, X86::VFNMADDPS4Ymr, TB_ALIGN_NONE },
+ { X86::VFNMADDPD4Yrr, X86::VFNMADDPD4Ymr, TB_ALIGN_NONE },
{ X86::VFMSUBSS4rr, X86::VFMSUBSS4mr, TB_ALIGN_NONE },
+ { X86::VFMSUBSS4rr_Int, X86::VFMSUBSS4mr_Int, TB_NO_REVERSE },
{ X86::VFMSUBSD4rr, X86::VFMSUBSD4mr, TB_ALIGN_NONE },
+ { X86::VFMSUBSD4rr_Int, X86::VFMSUBSD4mr_Int, TB_NO_REVERSE },
{ X86::VFMSUBPS4rr, X86::VFMSUBPS4mr, TB_ALIGN_NONE },
{ X86::VFMSUBPD4rr, X86::VFMSUBPD4mr, TB_ALIGN_NONE },
- { X86::VFMSUBPS4rrY, X86::VFMSUBPS4mrY, TB_ALIGN_NONE },
- { X86::VFMSUBPD4rrY, X86::VFMSUBPD4mrY, TB_ALIGN_NONE },
+ { X86::VFMSUBPS4Yrr, X86::VFMSUBPS4Ymr, TB_ALIGN_NONE },
+ { X86::VFMSUBPD4Yrr, X86::VFMSUBPD4Ymr, TB_ALIGN_NONE },
{ X86::VFNMSUBSS4rr, X86::VFNMSUBSS4mr, TB_ALIGN_NONE },
+ { X86::VFNMSUBSS4rr_Int, X86::VFNMSUBSS4mr_Int, TB_NO_REVERSE },
{ X86::VFNMSUBSD4rr, X86::VFNMSUBSD4mr, TB_ALIGN_NONE },
+ { X86::VFNMSUBSD4rr_Int, X86::VFNMSUBSD4mr_Int, TB_NO_REVERSE },
{ X86::VFNMSUBPS4rr, X86::VFNMSUBPS4mr, TB_ALIGN_NONE },
{ X86::VFNMSUBPD4rr, X86::VFNMSUBPD4mr, TB_ALIGN_NONE },
- { X86::VFNMSUBPS4rrY, X86::VFNMSUBPS4mrY, TB_ALIGN_NONE },
- { X86::VFNMSUBPD4rrY, X86::VFNMSUBPD4mrY, TB_ALIGN_NONE },
+ { X86::VFNMSUBPS4Yrr, X86::VFNMSUBPS4Ymr, TB_ALIGN_NONE },
+ { X86::VFNMSUBPD4Yrr, X86::VFNMSUBPD4Ymr, TB_ALIGN_NONE },
{ X86::VFMADDSUBPS4rr, X86::VFMADDSUBPS4mr, TB_ALIGN_NONE },
{ X86::VFMADDSUBPD4rr, X86::VFMADDSUBPD4mr, TB_ALIGN_NONE },
- { X86::VFMADDSUBPS4rrY, X86::VFMADDSUBPS4mrY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPD4rrY, X86::VFMADDSUBPD4mrY, TB_ALIGN_NONE },
+ { X86::VFMADDSUBPS4Yrr, X86::VFMADDSUBPS4Ymr, TB_ALIGN_NONE },
+ { X86::VFMADDSUBPD4Yrr, X86::VFMADDSUBPD4Ymr, TB_ALIGN_NONE },
{ X86::VFMSUBADDPS4rr, X86::VFMSUBADDPS4mr, TB_ALIGN_NONE },
{ X86::VFMSUBADDPD4rr, X86::VFMSUBADDPD4mr, TB_ALIGN_NONE },
- { X86::VFMSUBADDPS4rrY, X86::VFMSUBADDPS4mrY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPD4rrY, X86::VFMSUBADDPD4mrY, TB_ALIGN_NONE },
+ { X86::VFMSUBADDPS4Yrr, X86::VFMSUBADDPS4Ymr, TB_ALIGN_NONE },
+ { X86::VFMSUBADDPD4Yrr, X86::VFMSUBADDPD4Ymr, TB_ALIGN_NONE },
// XOP foldable instructions
{ X86::VPCMOVrrr, X86::VPCMOVrmr, 0 },
@@ -1678,38 +1788,107 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::ADOX64rr, X86::ADOX64rm, 0 },
// AVX-512 foldable instructions
- { X86::VADDPSZrr, X86::VADDPSZrm, 0 },
{ X86::VADDPDZrr, X86::VADDPDZrm, 0 },
- { X86::VADDSSZrr, X86::VADDSSZrm, 0 },
- { X86::VADDSSZrr_Int, X86::VADDSSZrm_Int, 0 },
+ { X86::VADDPSZrr, X86::VADDPSZrm, 0 },
{ X86::VADDSDZrr, X86::VADDSDZrm, 0 },
- { X86::VADDSDZrr_Int, X86::VADDSDZrm_Int, 0 },
- { X86::VSUBPSZrr, X86::VSUBPSZrm, 0 },
- { X86::VSUBPDZrr, X86::VSUBPDZrm, 0 },
- { X86::VSUBSSZrr, X86::VSUBSSZrm, 0 },
- { X86::VSUBSSZrr_Int, X86::VSUBSSZrm_Int, 0 },
- { X86::VSUBSDZrr, X86::VSUBSDZrm, 0 },
- { X86::VSUBSDZrr_Int, X86::VSUBSDZrm_Int, 0 },
- { X86::VMULPSZrr, X86::VMULPSZrm, 0 },
- { X86::VMULPDZrr, X86::VMULPDZrm, 0 },
- { X86::VMULSSZrr, X86::VMULSSZrm, 0 },
- { X86::VMULSSZrr_Int, X86::VMULSSZrm_Int, 0 },
- { X86::VMULSDZrr, X86::VMULSDZrm, 0 },
- { X86::VMULSDZrr_Int, X86::VMULSDZrm_Int, 0 },
- { X86::VDIVPSZrr, X86::VDIVPSZrm, 0 },
+ { X86::VADDSDZrr_Int, X86::VADDSDZrm_Int, TB_NO_REVERSE },
+ { X86::VADDSSZrr, X86::VADDSSZrm, 0 },
+ { X86::VADDSSZrr_Int, X86::VADDSSZrm_Int, TB_NO_REVERSE },
+ { X86::VALIGNDZrri, X86::VALIGNDZrmi, 0 },
+ { X86::VALIGNQZrri, X86::VALIGNQZrmi, 0 },
+ { X86::VANDNPDZrr, X86::VANDNPDZrm, 0 },
+ { X86::VANDNPSZrr, X86::VANDNPSZrm, 0 },
+ { X86::VANDPDZrr, X86::VANDPDZrm, 0 },
+ { X86::VANDPSZrr, X86::VANDPSZrm, 0 },
+ { X86::VBROADCASTSSZrkz, X86::VBROADCASTSSZmkz, TB_NO_REVERSE },
+ { X86::VBROADCASTSDZrkz, X86::VBROADCASTSDZmkz, TB_NO_REVERSE },
+ { X86::VCMPPDZrri, X86::VCMPPDZrmi, 0 },
+ { X86::VCMPPSZrri, X86::VCMPPSZrmi, 0 },
+ { X86::VCMPSDZrr, X86::VCMPSDZrm, 0 },
+ { X86::VCMPSDZrr_Int, X86::VCMPSDZrm_Int, TB_NO_REVERSE },
+ { X86::VCMPSSZrr, X86::VCMPSSZrm, 0 },
+ { X86::VCMPSSZrr_Int, X86::VCMPSSZrm_Int, TB_NO_REVERSE },
{ X86::VDIVPDZrr, X86::VDIVPDZrm, 0 },
- { X86::VDIVSSZrr, X86::VDIVSSZrm, 0 },
- { X86::VDIVSSZrr_Int, X86::VDIVSSZrm_Int, 0 },
+ { X86::VDIVPSZrr, X86::VDIVPSZrm, 0 },
{ X86::VDIVSDZrr, X86::VDIVSDZrm, 0 },
- { X86::VDIVSDZrr_Int, X86::VDIVSDZrm_Int, 0 },
- { X86::VMINPSZrr, X86::VMINPSZrm, 0 },
- { X86::VMINPDZrr, X86::VMINPDZrm, 0 },
- { X86::VMAXPSZrr, X86::VMAXPSZrm, 0 },
+ { X86::VDIVSDZrr_Int, X86::VDIVSDZrm_Int, TB_NO_REVERSE },
+ { X86::VDIVSSZrr, X86::VDIVSSZrm, 0 },
+ { X86::VDIVSSZrr_Int, X86::VDIVSSZrm_Int, TB_NO_REVERSE },
+ { X86::VINSERTF32x4Zrr, X86::VINSERTF32x4Zrm, 0 },
+ { X86::VINSERTF32x8Zrr, X86::VINSERTF32x8Zrm, 0 },
+ { X86::VINSERTF64x2Zrr, X86::VINSERTF64x2Zrm, 0 },
+ { X86::VINSERTF64x4Zrr, X86::VINSERTF64x4Zrm, 0 },
+ { X86::VINSERTI32x4Zrr, X86::VINSERTI32x4Zrm, 0 },
+ { X86::VINSERTI32x8Zrr, X86::VINSERTI32x8Zrm, 0 },
+ { X86::VINSERTI64x2Zrr, X86::VINSERTI64x2Zrm, 0 },
+ { X86::VINSERTI64x4Zrr, X86::VINSERTI64x4Zrm, 0 },
+ { X86::VMAXCPDZrr, X86::VMAXCPDZrm, 0 },
+ { X86::VMAXCPSZrr, X86::VMAXCPSZrm, 0 },
+ { X86::VMAXCSDZrr, X86::VMAXCSDZrm, 0 },
+ { X86::VMAXCSSZrr, X86::VMAXCSSZrm, 0 },
{ X86::VMAXPDZrr, X86::VMAXPDZrm, 0 },
+ { X86::VMAXPSZrr, X86::VMAXPSZrm, 0 },
+ { X86::VMAXSDZrr, X86::VMAXSDZrm, 0 },
+ { X86::VMAXSDZrr_Int, X86::VMAXSDZrm_Int, TB_NO_REVERSE },
+ { X86::VMAXSSZrr, X86::VMAXSSZrm, 0 },
+ { X86::VMAXSSZrr_Int, X86::VMAXSSZrm_Int, TB_NO_REVERSE },
+ { X86::VMINCPDZrr, X86::VMINCPDZrm, 0 },
+ { X86::VMINCPSZrr, X86::VMINCPSZrm, 0 },
+ { X86::VMINCSDZrr, X86::VMINCSDZrm, 0 },
+ { X86::VMINCSSZrr, X86::VMINCSSZrm, 0 },
+ { X86::VMINPDZrr, X86::VMINPDZrm, 0 },
+ { X86::VMINPSZrr, X86::VMINPSZrm, 0 },
+ { X86::VMINSDZrr, X86::VMINSDZrm, 0 },
+ { X86::VMINSDZrr_Int, X86::VMINSDZrm_Int, TB_NO_REVERSE },
+ { X86::VMINSSZrr, X86::VMINSSZrm, 0 },
+ { X86::VMINSSZrr_Int, X86::VMINSSZrm_Int, TB_NO_REVERSE },
+ { X86::VMULPDZrr, X86::VMULPDZrm, 0 },
+ { X86::VMULPSZrr, X86::VMULPSZrm, 0 },
+ { X86::VMULSDZrr, X86::VMULSDZrm, 0 },
+ { X86::VMULSDZrr_Int, X86::VMULSDZrm_Int, TB_NO_REVERSE },
+ { X86::VMULSSZrr, X86::VMULSSZrm, 0 },
+ { X86::VMULSSZrr_Int, X86::VMULSSZrm_Int, TB_NO_REVERSE },
+ { X86::VORPDZrr, X86::VORPDZrm, 0 },
+ { X86::VORPSZrr, X86::VORPSZrm, 0 },
+ { X86::VPADDBZrr, X86::VPADDBZrm, 0 },
{ X86::VPADDDZrr, X86::VPADDDZrm, 0 },
{ X86::VPADDQZrr, X86::VPADDQZrm, 0 },
- { X86::VPERMPDZri, X86::VPERMPDZmi, 0 },
+ { X86::VPADDSBZrr, X86::VPADDSBZrm, 0 },
+ { X86::VPADDSWZrr, X86::VPADDSWZrm, 0 },
+ { X86::VPADDUSBZrr, X86::VPADDUSBZrm, 0 },
+ { X86::VPADDUSWZrr, X86::VPADDUSWZrm, 0 },
+ { X86::VPADDWZrr, X86::VPADDWZrm, 0 },
+ { X86::VPALIGNRZrri, X86::VPALIGNRZrmi, 0 },
+ { X86::VPANDDZrr, X86::VPANDDZrm, 0 },
+ { X86::VPANDNDZrr, X86::VPANDNDZrm, 0 },
+ { X86::VPANDNQZrr, X86::VPANDNQZrm, 0 },
+ { X86::VPANDQZrr, X86::VPANDQZrm, 0 },
+ { X86::VPCMPBZrri, X86::VPCMPBZrmi, 0 },
+ { X86::VPCMPDZrri, X86::VPCMPDZrmi, 0 },
+ { X86::VPCMPEQBZrr, X86::VPCMPEQBZrm, 0 },
+ { X86::VPCMPEQDZrr, X86::VPCMPEQDZrm, 0 },
+ { X86::VPCMPEQQZrr, X86::VPCMPEQQZrm, 0 },
+ { X86::VPCMPEQWZrr, X86::VPCMPEQWZrm, 0 },
+ { X86::VPCMPGTBZrr, X86::VPCMPGTBZrm, 0 },
+ { X86::VPCMPGTDZrr, X86::VPCMPGTDZrm, 0 },
+ { X86::VPCMPGTQZrr, X86::VPCMPGTQZrm, 0 },
+ { X86::VPCMPGTWZrr, X86::VPCMPGTWZrm, 0 },
+ { X86::VPCMPQZrri, X86::VPCMPQZrmi, 0 },
+ { X86::VPCMPUBZrri, X86::VPCMPUBZrmi, 0 },
+ { X86::VPCMPUDZrri, X86::VPCMPUDZrmi, 0 },
+ { X86::VPCMPUQZrri, X86::VPCMPUQZrmi, 0 },
+ { X86::VPCMPUWZrri, X86::VPCMPUWZrmi, 0 },
+ { X86::VPCMPWZrri, X86::VPCMPWZrmi, 0 },
+ { X86::VPERMBZrr, X86::VPERMBZrm, 0 },
+ { X86::VPERMDZrr, X86::VPERMDZrm, 0 },
+ { X86::VPERMILPDZrr, X86::VPERMILPDZrm, 0 },
+ { X86::VPERMILPSZrr, X86::VPERMILPSZrm, 0 },
+ { X86::VPERMPDZrr, X86::VPERMPDZrm, 0 },
{ X86::VPERMPSZrr, X86::VPERMPSZrm, 0 },
+ { X86::VPERMQZrr, X86::VPERMQZrm, 0 },
+ { X86::VPERMWZrr, X86::VPERMWZrm, 0 },
+ { X86::VPMADDUBSWZrr, X86::VPMADDUBSWZrm, 0 },
+ { X86::VPMADDWDZrr, X86::VPMADDWDZrm, 0 },
{ X86::VPMAXSDZrr, X86::VPMAXSDZrm, 0 },
{ X86::VPMAXSQZrr, X86::VPMAXSQZrm, 0 },
{ X86::VPMAXUDZrr, X86::VPMAXUDZrm, 0 },
@@ -1719,31 +1898,297 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPMINUDZrr, X86::VPMINUDZrm, 0 },
{ X86::VPMINUQZrr, X86::VPMINUQZrm, 0 },
{ X86::VPMULDQZrr, X86::VPMULDQZrm, 0 },
+ { X86::VPMULUDQZrr, X86::VPMULUDQZrm, 0 },
+ { X86::VPORDZrr, X86::VPORDZrm, 0 },
+ { X86::VPORQZrr, X86::VPORQZrm, 0 },
+ { X86::VPSHUFBZrr, X86::VPSHUFBZrm, 0 },
{ X86::VPSLLVDZrr, X86::VPSLLVDZrm, 0 },
{ X86::VPSLLVQZrr, X86::VPSLLVQZrm, 0 },
{ X86::VPSRAVDZrr, X86::VPSRAVDZrm, 0 },
{ X86::VPSRLVDZrr, X86::VPSRLVDZrm, 0 },
{ X86::VPSRLVQZrr, X86::VPSRLVQZrm, 0 },
+ { X86::VPSUBBZrr, X86::VPSUBBZrm, 0 },
{ X86::VPSUBDZrr, X86::VPSUBDZrm, 0 },
{ X86::VPSUBQZrr, X86::VPSUBQZrm, 0 },
+ { X86::VPSUBSBZrr, X86::VPSUBSBZrm, 0 },
+ { X86::VPSUBSWZrr, X86::VPSUBSWZrm, 0 },
+ { X86::VPSUBUSBZrr, X86::VPSUBUSBZrm, 0 },
+ { X86::VPSUBUSWZrr, X86::VPSUBUSWZrm, 0 },
+ { X86::VPSUBWZrr, X86::VPSUBWZrm, 0 },
+ { X86::VPUNPCKHBWZrr, X86::VPUNPCKHBWZrm, 0 },
+ { X86::VPUNPCKHDQZrr, X86::VPUNPCKHDQZrm, 0 },
+ { X86::VPUNPCKHQDQZrr, X86::VPUNPCKHQDQZrm, 0 },
+ { X86::VPUNPCKHWDZrr, X86::VPUNPCKHWDZrm, 0 },
+ { X86::VPUNPCKLBWZrr, X86::VPUNPCKLBWZrm, 0 },
+ { X86::VPUNPCKLDQZrr, X86::VPUNPCKLDQZrm, 0 },
+ { X86::VPUNPCKLQDQZrr, X86::VPUNPCKLQDQZrm, 0 },
+ { X86::VPUNPCKLWDZrr, X86::VPUNPCKLWDZrm, 0 },
+ { X86::VPXORDZrr, X86::VPXORDZrm, 0 },
+ { X86::VPXORQZrr, X86::VPXORQZrm, 0 },
{ X86::VSHUFPDZrri, X86::VSHUFPDZrmi, 0 },
{ X86::VSHUFPSZrri, X86::VSHUFPSZrmi, 0 },
- { X86::VALIGNQZrri, X86::VALIGNQZrmi, 0 },
- { X86::VALIGNDZrri, X86::VALIGNDZrmi, 0 },
- { X86::VPMULUDQZrr, X86::VPMULUDQZrm, 0 },
- { X86::VBROADCASTSSZrkz, X86::VBROADCASTSSZmkz, TB_NO_REVERSE },
- { X86::VBROADCASTSDZrkz, X86::VBROADCASTSDZmkz, TB_NO_REVERSE },
-
- // AVX-512{F,VL} foldable instructions
- { X86::VBROADCASTSSZ256rkz, X86::VBROADCASTSSZ256mkz, TB_NO_REVERSE },
- { X86::VBROADCASTSDZ256rkz, X86::VBROADCASTSDZ256mkz, TB_NO_REVERSE },
- { X86::VBROADCASTSSZ128rkz, X86::VBROADCASTSSZ128mkz, TB_NO_REVERSE },
+ { X86::VSUBPDZrr, X86::VSUBPDZrm, 0 },
+ { X86::VSUBPSZrr, X86::VSUBPSZrm, 0 },
+ { X86::VSUBSDZrr, X86::VSUBSDZrm, 0 },
+ { X86::VSUBSDZrr_Int, X86::VSUBSDZrm_Int, TB_NO_REVERSE },
+ { X86::VSUBSSZrr, X86::VSUBSSZrm, 0 },
+ { X86::VSUBSSZrr_Int, X86::VSUBSSZrm_Int, TB_NO_REVERSE },
+ { X86::VUNPCKHPDZrr, X86::VUNPCKHPDZrm, 0 },
+ { X86::VUNPCKHPSZrr, X86::VUNPCKHPSZrm, 0 },
+ { X86::VUNPCKLPDZrr, X86::VUNPCKLPDZrm, 0 },
+ { X86::VUNPCKLPSZrr, X86::VUNPCKLPSZrm, 0 },
+ { X86::VXORPDZrr, X86::VXORPDZrm, 0 },
+ { X86::VXORPSZrr, X86::VXORPSZrm, 0 },
// AVX-512{F,VL} foldable instructions
{ X86::VADDPDZ128rr, X86::VADDPDZ128rm, 0 },
{ X86::VADDPDZ256rr, X86::VADDPDZ256rm, 0 },
{ X86::VADDPSZ128rr, X86::VADDPSZ128rm, 0 },
{ X86::VADDPSZ256rr, X86::VADDPSZ256rm, 0 },
+ { X86::VALIGNDZ128rri, X86::VALIGNDZ128rmi, 0 },
+ { X86::VALIGNDZ256rri, X86::VALIGNDZ256rmi, 0 },
+ { X86::VALIGNQZ128rri, X86::VALIGNQZ128rmi, 0 },
+ { X86::VALIGNQZ256rri, X86::VALIGNQZ256rmi, 0 },
+ { X86::VANDNPDZ128rr, X86::VANDNPDZ128rm, 0 },
+ { X86::VANDNPDZ256rr, X86::VANDNPDZ256rm, 0 },
+ { X86::VANDNPSZ128rr, X86::VANDNPSZ128rm, 0 },
+ { X86::VANDNPSZ256rr, X86::VANDNPSZ256rm, 0 },
+ { X86::VANDPDZ128rr, X86::VANDPDZ128rm, 0 },
+ { X86::VANDPDZ256rr, X86::VANDPDZ256rm, 0 },
+ { X86::VANDPSZ128rr, X86::VANDPSZ128rm, 0 },
+ { X86::VANDPSZ256rr, X86::VANDPSZ256rm, 0 },
+ { X86::VBROADCASTSSZ128rkz, X86::VBROADCASTSSZ128mkz, TB_NO_REVERSE },
+ { X86::VBROADCASTSSZ256rkz, X86::VBROADCASTSSZ256mkz, TB_NO_REVERSE },
+ { X86::VBROADCASTSDZ256rkz, X86::VBROADCASTSDZ256mkz, TB_NO_REVERSE },
+ { X86::VCMPPDZ128rri, X86::VCMPPDZ128rmi, 0 },
+ { X86::VCMPPDZ256rri, X86::VCMPPDZ256rmi, 0 },
+ { X86::VCMPPSZ128rri, X86::VCMPPSZ128rmi, 0 },
+ { X86::VCMPPSZ256rri, X86::VCMPPSZ256rmi, 0 },
+ { X86::VDIVPDZ128rr, X86::VDIVPDZ128rm, 0 },
+ { X86::VDIVPDZ256rr, X86::VDIVPDZ256rm, 0 },
+ { X86::VDIVPSZ128rr, X86::VDIVPSZ128rm, 0 },
+ { X86::VDIVPSZ256rr, X86::VDIVPSZ256rm, 0 },
+ { X86::VINSERTF32x4Z256rr,X86::VINSERTF32x4Z256rm, 0 },
+ { X86::VINSERTF64x2Z256rr,X86::VINSERTF64x2Z256rm, 0 },
+ { X86::VINSERTI32x4Z256rr,X86::VINSERTI32x4Z256rm, 0 },
+ { X86::VINSERTI64x2Z256rr,X86::VINSERTI64x2Z256rm, 0 },
+ { X86::VMAXCPDZ128rr, X86::VMAXCPDZ128rm, 0 },
+ { X86::VMAXCPDZ256rr, X86::VMAXCPDZ256rm, 0 },
+ { X86::VMAXCPSZ128rr, X86::VMAXCPSZ128rm, 0 },
+ { X86::VMAXCPSZ256rr, X86::VMAXCPSZ256rm, 0 },
+ { X86::VMAXPDZ128rr, X86::VMAXPDZ128rm, 0 },
+ { X86::VMAXPDZ256rr, X86::VMAXPDZ256rm, 0 },
+ { X86::VMAXPSZ128rr, X86::VMAXPSZ128rm, 0 },
+ { X86::VMAXPSZ256rr, X86::VMAXPSZ256rm, 0 },
+ { X86::VMINCPDZ128rr, X86::VMINCPDZ128rm, 0 },
+ { X86::VMINCPDZ256rr, X86::VMINCPDZ256rm, 0 },
+ { X86::VMINCPSZ128rr, X86::VMINCPSZ128rm, 0 },
+ { X86::VMINCPSZ256rr, X86::VMINCPSZ256rm, 0 },
+ { X86::VMINPDZ128rr, X86::VMINPDZ128rm, 0 },
+ { X86::VMINPDZ256rr, X86::VMINPDZ256rm, 0 },
+ { X86::VMINPSZ128rr, X86::VMINPSZ128rm, 0 },
+ { X86::VMINPSZ256rr, X86::VMINPSZ256rm, 0 },
+ { X86::VMULPDZ128rr, X86::VMULPDZ128rm, 0 },
+ { X86::VMULPDZ256rr, X86::VMULPDZ256rm, 0 },
+ { X86::VMULPSZ128rr, X86::VMULPSZ128rm, 0 },
+ { X86::VMULPSZ256rr, X86::VMULPSZ256rm, 0 },
+ { X86::VORPDZ128rr, X86::VORPDZ128rm, 0 },
+ { X86::VORPDZ256rr, X86::VORPDZ256rm, 0 },
+ { X86::VORPSZ128rr, X86::VORPSZ128rm, 0 },
+ { X86::VORPSZ256rr, X86::VORPSZ256rm, 0 },
+ { X86::VPADDBZ128rr, X86::VPADDBZ128rm, 0 },
+ { X86::VPADDBZ256rr, X86::VPADDBZ256rm, 0 },
+ { X86::VPADDDZ128rr, X86::VPADDDZ128rm, 0 },
+ { X86::VPADDDZ256rr, X86::VPADDDZ256rm, 0 },
+ { X86::VPADDQZ128rr, X86::VPADDQZ128rm, 0 },
+ { X86::VPADDQZ256rr, X86::VPADDQZ256rm, 0 },
+ { X86::VPADDSBZ128rr, X86::VPADDSBZ128rm, 0 },
+ { X86::VPADDSBZ256rr, X86::VPADDSBZ256rm, 0 },
+ { X86::VPADDSWZ128rr, X86::VPADDSWZ128rm, 0 },
+ { X86::VPADDSWZ256rr, X86::VPADDSWZ256rm, 0 },
+ { X86::VPADDUSBZ128rr, X86::VPADDUSBZ128rm, 0 },
+ { X86::VPADDUSBZ256rr, X86::VPADDUSBZ256rm, 0 },
+ { X86::VPADDUSWZ128rr, X86::VPADDUSWZ128rm, 0 },
+ { X86::VPADDUSWZ256rr, X86::VPADDUSWZ256rm, 0 },
+ { X86::VPADDWZ128rr, X86::VPADDWZ128rm, 0 },
+ { X86::VPADDWZ256rr, X86::VPADDWZ256rm, 0 },
+ { X86::VPALIGNRZ128rri, X86::VPALIGNRZ128rmi, 0 },
+ { X86::VPALIGNRZ256rri, X86::VPALIGNRZ256rmi, 0 },
+ { X86::VPANDDZ128rr, X86::VPANDDZ128rm, 0 },
+ { X86::VPANDDZ256rr, X86::VPANDDZ256rm, 0 },
+ { X86::VPANDNDZ128rr, X86::VPANDNDZ128rm, 0 },
+ { X86::VPANDNDZ256rr, X86::VPANDNDZ256rm, 0 },
+ { X86::VPANDNQZ128rr, X86::VPANDNQZ128rm, 0 },
+ { X86::VPANDNQZ256rr, X86::VPANDNQZ256rm, 0 },
+ { X86::VPANDQZ128rr, X86::VPANDQZ128rm, 0 },
+ { X86::VPANDQZ256rr, X86::VPANDQZ256rm, 0 },
+ { X86::VPCMPBZ128rri, X86::VPCMPBZ128rmi, 0 },
+ { X86::VPCMPBZ256rri, X86::VPCMPBZ256rmi, 0 },
+ { X86::VPCMPDZ128rri, X86::VPCMPDZ128rmi, 0 },
+ { X86::VPCMPDZ256rri, X86::VPCMPDZ256rmi, 0 },
+ { X86::VPCMPEQBZ128rr, X86::VPCMPEQBZ128rm, 0 },
+ { X86::VPCMPEQBZ256rr, X86::VPCMPEQBZ256rm, 0 },
+ { X86::VPCMPEQDZ128rr, X86::VPCMPEQDZ128rm, 0 },
+ { X86::VPCMPEQDZ256rr, X86::VPCMPEQDZ256rm, 0 },
+ { X86::VPCMPEQQZ128rr, X86::VPCMPEQQZ128rm, 0 },
+ { X86::VPCMPEQQZ256rr, X86::VPCMPEQQZ256rm, 0 },
+ { X86::VPCMPEQWZ128rr, X86::VPCMPEQWZ128rm, 0 },
+ { X86::VPCMPEQWZ256rr, X86::VPCMPEQWZ256rm, 0 },
+ { X86::VPCMPGTBZ128rr, X86::VPCMPGTBZ128rm, 0 },
+ { X86::VPCMPGTBZ256rr, X86::VPCMPGTBZ256rm, 0 },
+ { X86::VPCMPGTDZ128rr, X86::VPCMPGTDZ128rm, 0 },
+ { X86::VPCMPGTDZ256rr, X86::VPCMPGTDZ256rm, 0 },
+ { X86::VPCMPGTQZ128rr, X86::VPCMPGTQZ128rm, 0 },
+ { X86::VPCMPGTQZ256rr, X86::VPCMPGTQZ256rm, 0 },
+ { X86::VPCMPGTWZ128rr, X86::VPCMPGTWZ128rm, 0 },
+ { X86::VPCMPGTWZ256rr, X86::VPCMPGTWZ256rm, 0 },
+ { X86::VPCMPQZ128rri, X86::VPCMPQZ128rmi, 0 },
+ { X86::VPCMPQZ256rri, X86::VPCMPQZ256rmi, 0 },
+ { X86::VPCMPUBZ128rri, X86::VPCMPUBZ128rmi, 0 },
+ { X86::VPCMPUBZ256rri, X86::VPCMPUBZ256rmi, 0 },
+ { X86::VPCMPUDZ128rri, X86::VPCMPUDZ128rmi, 0 },
+ { X86::VPCMPUDZ256rri, X86::VPCMPUDZ256rmi, 0 },
+ { X86::VPCMPUQZ128rri, X86::VPCMPUQZ128rmi, 0 },
+ { X86::VPCMPUQZ256rri, X86::VPCMPUQZ256rmi, 0 },
+ { X86::VPCMPUWZ128rri, X86::VPCMPUWZ128rmi, 0 },
+ { X86::VPCMPUWZ256rri, X86::VPCMPUWZ256rmi, 0 },
+ { X86::VPCMPWZ128rri, X86::VPCMPWZ128rmi, 0 },
+ { X86::VPCMPWZ256rri, X86::VPCMPWZ256rmi, 0 },
+ { X86::VPERMBZ128rr, X86::VPERMBZ128rm, 0 },
+ { X86::VPERMBZ256rr, X86::VPERMBZ256rm, 0 },
+ { X86::VPERMDZ256rr, X86::VPERMDZ256rm, 0 },
+ { X86::VPERMILPDZ128rr, X86::VPERMILPDZ128rm, 0 },
+ { X86::VPERMILPDZ256rr, X86::VPERMILPDZ256rm, 0 },
+ { X86::VPERMILPSZ128rr, X86::VPERMILPSZ128rm, 0 },
+ { X86::VPERMILPSZ256rr, X86::VPERMILPSZ256rm, 0 },
+ { X86::VPERMPDZ256rr, X86::VPERMPDZ256rm, 0 },
+ { X86::VPERMPSZ256rr, X86::VPERMPSZ256rm, 0 },
+ { X86::VPERMQZ256rr, X86::VPERMQZ256rm, 0 },
+ { X86::VPERMWZ128rr, X86::VPERMWZ128rm, 0 },
+ { X86::VPERMWZ256rr, X86::VPERMWZ256rm, 0 },
+ { X86::VPMADDUBSWZ128rr, X86::VPMADDUBSWZ128rm, 0 },
+ { X86::VPMADDUBSWZ256rr, X86::VPMADDUBSWZ256rm, 0 },
+ { X86::VPMADDWDZ128rr, X86::VPMADDWDZ128rm, 0 },
+ { X86::VPMADDWDZ256rr, X86::VPMADDWDZ256rm, 0 },
+ { X86::VPORDZ128rr, X86::VPORDZ128rm, 0 },
+ { X86::VPORDZ256rr, X86::VPORDZ256rm, 0 },
+ { X86::VPORQZ128rr, X86::VPORQZ128rm, 0 },
+ { X86::VPORQZ256rr, X86::VPORQZ256rm, 0 },
+ { X86::VPSHUFBZ128rr, X86::VPSHUFBZ128rm, 0 },
+ { X86::VPSHUFBZ256rr, X86::VPSHUFBZ256rm, 0 },
+ { X86::VPSUBBZ128rr, X86::VPSUBBZ128rm, 0 },
+ { X86::VPSUBBZ256rr, X86::VPSUBBZ256rm, 0 },
+ { X86::VPSUBDZ128rr, X86::VPSUBDZ128rm, 0 },
+ { X86::VPSUBDZ256rr, X86::VPSUBDZ256rm, 0 },
+ { X86::VPSUBQZ128rr, X86::VPSUBQZ128rm, 0 },
+ { X86::VPSUBQZ256rr, X86::VPSUBQZ256rm, 0 },
+ { X86::VPSUBSBZ128rr, X86::VPSUBSBZ128rm, 0 },
+ { X86::VPSUBSBZ256rr, X86::VPSUBSBZ256rm, 0 },
+ { X86::VPSUBSWZ128rr, X86::VPSUBSWZ128rm, 0 },
+ { X86::VPSUBSWZ256rr, X86::VPSUBSWZ256rm, 0 },
+ { X86::VPSUBUSBZ128rr, X86::VPSUBUSBZ128rm, 0 },
+ { X86::VPSUBUSBZ256rr, X86::VPSUBUSBZ256rm, 0 },
+ { X86::VPSUBUSWZ128rr, X86::VPSUBUSWZ128rm, 0 },
+ { X86::VPSUBUSWZ256rr, X86::VPSUBUSWZ256rm, 0 },
+ { X86::VPSUBWZ128rr, X86::VPSUBWZ128rm, 0 },
+ { X86::VPSUBWZ256rr, X86::VPSUBWZ256rm, 0 },
+ { X86::VPUNPCKHBWZ128rr, X86::VPUNPCKHBWZ128rm, 0 },
+ { X86::VPUNPCKHBWZ256rr, X86::VPUNPCKHBWZ256rm, 0 },
+ { X86::VPUNPCKHDQZ128rr, X86::VPUNPCKHDQZ128rm, 0 },
+ { X86::VPUNPCKHDQZ256rr, X86::VPUNPCKHDQZ256rm, 0 },
+ { X86::VPUNPCKHQDQZ128rr, X86::VPUNPCKHQDQZ128rm, 0 },
+ { X86::VPUNPCKHQDQZ256rr, X86::VPUNPCKHQDQZ256rm, 0 },
+ { X86::VPUNPCKHWDZ128rr, X86::VPUNPCKHWDZ128rm, 0 },
+ { X86::VPUNPCKHWDZ256rr, X86::VPUNPCKHWDZ256rm, 0 },
+ { X86::VPUNPCKLBWZ128rr, X86::VPUNPCKLBWZ128rm, 0 },
+ { X86::VPUNPCKLBWZ256rr, X86::VPUNPCKLBWZ256rm, 0 },
+ { X86::VPUNPCKLDQZ128rr, X86::VPUNPCKLDQZ128rm, 0 },
+ { X86::VPUNPCKLDQZ256rr, X86::VPUNPCKLDQZ256rm, 0 },
+ { X86::VPUNPCKLQDQZ128rr, X86::VPUNPCKLQDQZ128rm, 0 },
+ { X86::VPUNPCKLQDQZ256rr, X86::VPUNPCKLQDQZ256rm, 0 },
+ { X86::VPUNPCKLWDZ128rr, X86::VPUNPCKLWDZ128rm, 0 },
+ { X86::VPUNPCKLWDZ256rr, X86::VPUNPCKLWDZ256rm, 0 },
+ { X86::VPXORDZ128rr, X86::VPXORDZ128rm, 0 },
+ { X86::VPXORDZ256rr, X86::VPXORDZ256rm, 0 },
+ { X86::VPXORQZ128rr, X86::VPXORQZ128rm, 0 },
+ { X86::VPXORQZ256rr, X86::VPXORQZ256rm, 0 },
+ { X86::VSUBPDZ128rr, X86::VSUBPDZ128rm, 0 },
+ { X86::VSUBPDZ256rr, X86::VSUBPDZ256rm, 0 },
+ { X86::VSUBPSZ128rr, X86::VSUBPSZ128rm, 0 },
+ { X86::VSUBPSZ256rr, X86::VSUBPSZ256rm, 0 },
+ { X86::VUNPCKHPDZ128rr, X86::VUNPCKHPDZ128rm, 0 },
+ { X86::VUNPCKHPDZ256rr, X86::VUNPCKHPDZ256rm, 0 },
+ { X86::VUNPCKHPSZ128rr, X86::VUNPCKHPSZ128rm, 0 },
+ { X86::VUNPCKHPSZ256rr, X86::VUNPCKHPSZ256rm, 0 },
+ { X86::VUNPCKLPDZ128rr, X86::VUNPCKLPDZ128rm, 0 },
+ { X86::VUNPCKLPDZ256rr, X86::VUNPCKLPDZ256rm, 0 },
+ { X86::VUNPCKLPSZ128rr, X86::VUNPCKLPSZ128rm, 0 },
+ { X86::VUNPCKLPSZ256rr, X86::VUNPCKLPSZ256rm, 0 },
+ { X86::VXORPDZ128rr, X86::VXORPDZ128rm, 0 },
+ { X86::VXORPDZ256rr, X86::VXORPDZ256rm, 0 },
+ { X86::VXORPSZ128rr, X86::VXORPSZ128rm, 0 },
+ { X86::VXORPSZ256rr, X86::VXORPSZ256rm, 0 },
+
+ // AVX-512 masked foldable instructions
+ { X86::VPERMILPDZrikz, X86::VPERMILPDZmikz, 0 },
+ { X86::VPERMILPSZrikz, X86::VPERMILPSZmikz, 0 },
+ { X86::VPERMPDZrikz, X86::VPERMPDZmikz, 0 },
+ { X86::VPERMQZrikz, X86::VPERMQZmikz, 0 },
+ { X86::VPMOVSXBDZrrkz, X86::VPMOVSXBDZrmkz, 0 },
+ { X86::VPMOVSXBQZrrkz, X86::VPMOVSXBQZrmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZrrkz, X86::VPMOVSXBWZrmkz, 0 },
+ { X86::VPMOVSXDQZrrkz, X86::VPMOVSXDQZrmkz, 0 },
+ { X86::VPMOVSXWDZrrkz, X86::VPMOVSXWDZrmkz, 0 },
+ { X86::VPMOVSXWQZrrkz, X86::VPMOVSXWQZrmkz, 0 },
+ { X86::VPMOVZXBDZrrkz, X86::VPMOVZXBDZrmkz, 0 },
+ { X86::VPMOVZXBQZrrkz, X86::VPMOVZXBQZrmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZrrkz, X86::VPMOVZXBWZrmkz, 0 },
+ { X86::VPMOVZXDQZrrkz, X86::VPMOVZXDQZrmkz, 0 },
+ { X86::VPMOVZXWDZrrkz, X86::VPMOVZXWDZrmkz, 0 },
+ { X86::VPMOVZXWQZrrkz, X86::VPMOVZXWQZrmkz, 0 },
+ { X86::VPSHUFDZrikz, X86::VPSHUFDZmikz, 0 },
+ { X86::VPSHUFHWZrikz, X86::VPSHUFHWZmikz, 0 },
+ { X86::VPSHUFLWZrikz, X86::VPSHUFLWZmikz, 0 },
+
+ // AVX-512VL 256-bit masked foldable instructions
+ { X86::VPERMILPDZ256rikz, X86::VPERMILPDZ256mikz, 0 },
+ { X86::VPERMILPSZ256rikz, X86::VPERMILPSZ256mikz, 0 },
+ { X86::VPERMPDZ256rikz, X86::VPERMPDZ256mikz, 0 },
+ { X86::VPERMQZ256rikz, X86::VPERMQZ256mikz, 0 },
+ { X86::VPMOVSXBDZ256rrkz, X86::VPMOVSXBDZ256rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXBQZ256rrkz, X86::VPMOVSXBQZ256rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZ256rrkz, X86::VPMOVSXBWZ256rmkz, 0 },
+ { X86::VPMOVSXDQZ256rrkz, X86::VPMOVSXDQZ256rmkz, 0 },
+ { X86::VPMOVSXWDZ256rrkz, X86::VPMOVSXWDZ256rmkz, 0 },
+ { X86::VPMOVSXWQZ256rrkz, X86::VPMOVSXWQZ256rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBDZ256rrkz, X86::VPMOVZXBDZ256rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBQZ256rrkz, X86::VPMOVZXBQZ256rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZ256rrkz, X86::VPMOVZXBWZ256rmkz, 0 },
+ { X86::VPMOVZXDQZ256rrkz, X86::VPMOVZXDQZ256rmkz, 0 },
+ { X86::VPMOVZXWDZ256rrkz, X86::VPMOVZXWDZ256rmkz, 0 },
+ { X86::VPMOVZXWQZ256rrkz, X86::VPMOVZXWQZ256rmkz, TB_NO_REVERSE },
+ { X86::VPSHUFDZ256rikz, X86::VPSHUFDZ256mikz, 0 },
+ { X86::VPSHUFHWZ256rikz, X86::VPSHUFHWZ256mikz, 0 },
+ { X86::VPSHUFLWZ256rikz, X86::VPSHUFLWZ256mikz, 0 },
+
+ // AVX-512VL 128-bit masked foldable instructions
+ { X86::VPERMILPDZ128rikz, X86::VPERMILPDZ128mikz, 0 },
+ { X86::VPERMILPSZ128rikz, X86::VPERMILPSZ128mikz, 0 },
+ { X86::VPMOVSXBDZ128rrkz, X86::VPMOVSXBDZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXBQZ128rrkz, X86::VPMOVSXBQZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZ128rrkz, X86::VPMOVSXBWZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXDQZ128rrkz, X86::VPMOVSXDQZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXWDZ128rrkz, X86::VPMOVSXWDZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVSXWQZ128rrkz, X86::VPMOVSXWQZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBDZ128rrkz, X86::VPMOVZXBDZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBQZ128rrkz, X86::VPMOVZXBQZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZ128rrkz, X86::VPMOVZXBWZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXDQZ128rrkz, X86::VPMOVZXDQZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXWDZ128rrkz, X86::VPMOVZXWDZ128rmkz, TB_NO_REVERSE },
+ { X86::VPMOVZXWQZ128rrkz, X86::VPMOVZXWQZ128rmkz, TB_NO_REVERSE },
+ { X86::VPSHUFDZ128rikz, X86::VPSHUFDZ128mikz, 0 },
+ { X86::VPSHUFHWZ128rikz, X86::VPSHUFHWZ128mikz, 0 },
+ { X86::VPSHUFLWZ128rikz, X86::VPSHUFLWZ128mikz, 0 },
// AES foldable instructions
{ X86::AESDECLASTrr, X86::AESDECLASTrm, TB_ALIGN_16 },
@@ -1773,170 +2218,47 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
}
static const X86MemoryFoldTableEntry MemoryFoldTable3[] = {
- // FMA foldable instructions
- { X86::VFMADDSSr231r, X86::VFMADDSSr231m, TB_ALIGN_NONE },
- { X86::VFMADDSSr231r_Int, X86::VFMADDSSr231m_Int, TB_ALIGN_NONE },
- { X86::VFMADDSDr231r, X86::VFMADDSDr231m, TB_ALIGN_NONE },
- { X86::VFMADDSDr231r_Int, X86::VFMADDSDr231m_Int, TB_ALIGN_NONE },
- { X86::VFMADDSSr132r, X86::VFMADDSSr132m, TB_ALIGN_NONE },
- { X86::VFMADDSSr132r_Int, X86::VFMADDSSr132m_Int, TB_ALIGN_NONE },
- { X86::VFMADDSDr132r, X86::VFMADDSDr132m, TB_ALIGN_NONE },
- { X86::VFMADDSDr132r_Int, X86::VFMADDSDr132m_Int, TB_ALIGN_NONE },
- { X86::VFMADDSSr213r, X86::VFMADDSSr213m, TB_ALIGN_NONE },
- { X86::VFMADDSSr213r_Int, X86::VFMADDSSr213m_Int, TB_ALIGN_NONE },
- { X86::VFMADDSDr213r, X86::VFMADDSDr213m, TB_ALIGN_NONE },
- { X86::VFMADDSDr213r_Int, X86::VFMADDSDr213m_Int, TB_ALIGN_NONE },
-
- { X86::VFMADDPSr231r, X86::VFMADDPSr231m, TB_ALIGN_NONE },
- { X86::VFMADDPDr231r, X86::VFMADDPDr231m, TB_ALIGN_NONE },
- { X86::VFMADDPSr132r, X86::VFMADDPSr132m, TB_ALIGN_NONE },
- { X86::VFMADDPDr132r, X86::VFMADDPDr132m, TB_ALIGN_NONE },
- { X86::VFMADDPSr213r, X86::VFMADDPSr213m, TB_ALIGN_NONE },
- { X86::VFMADDPDr213r, X86::VFMADDPDr213m, TB_ALIGN_NONE },
- { X86::VFMADDPSr231rY, X86::VFMADDPSr231mY, TB_ALIGN_NONE },
- { X86::VFMADDPDr231rY, X86::VFMADDPDr231mY, TB_ALIGN_NONE },
- { X86::VFMADDPSr132rY, X86::VFMADDPSr132mY, TB_ALIGN_NONE },
- { X86::VFMADDPDr132rY, X86::VFMADDPDr132mY, TB_ALIGN_NONE },
- { X86::VFMADDPSr213rY, X86::VFMADDPSr213mY, TB_ALIGN_NONE },
- { X86::VFMADDPDr213rY, X86::VFMADDPDr213mY, TB_ALIGN_NONE },
-
- { X86::VFNMADDSSr231r, X86::VFNMADDSSr231m, TB_ALIGN_NONE },
- { X86::VFNMADDSSr231r_Int, X86::VFNMADDSSr231m_Int, TB_ALIGN_NONE },
- { X86::VFNMADDSDr231r, X86::VFNMADDSDr231m, TB_ALIGN_NONE },
- { X86::VFNMADDSDr231r_Int, X86::VFNMADDSDr231m_Int, TB_ALIGN_NONE },
- { X86::VFNMADDSSr132r, X86::VFNMADDSSr132m, TB_ALIGN_NONE },
- { X86::VFNMADDSSr132r_Int, X86::VFNMADDSSr132m_Int, TB_ALIGN_NONE },
- { X86::VFNMADDSDr132r, X86::VFNMADDSDr132m, TB_ALIGN_NONE },
- { X86::VFNMADDSDr132r_Int, X86::VFNMADDSDr132m_Int, TB_ALIGN_NONE },
- { X86::VFNMADDSSr213r, X86::VFNMADDSSr213m, TB_ALIGN_NONE },
- { X86::VFNMADDSSr213r_Int, X86::VFNMADDSSr213m_Int, TB_ALIGN_NONE },
- { X86::VFNMADDSDr213r, X86::VFNMADDSDr213m, TB_ALIGN_NONE },
- { X86::VFNMADDSDr213r_Int, X86::VFNMADDSDr213m_Int, TB_ALIGN_NONE },
-
- { X86::VFNMADDPSr231r, X86::VFNMADDPSr231m, TB_ALIGN_NONE },
- { X86::VFNMADDPDr231r, X86::VFNMADDPDr231m, TB_ALIGN_NONE },
- { X86::VFNMADDPSr132r, X86::VFNMADDPSr132m, TB_ALIGN_NONE },
- { X86::VFNMADDPDr132r, X86::VFNMADDPDr132m, TB_ALIGN_NONE },
- { X86::VFNMADDPSr213r, X86::VFNMADDPSr213m, TB_ALIGN_NONE },
- { X86::VFNMADDPDr213r, X86::VFNMADDPDr213m, TB_ALIGN_NONE },
- { X86::VFNMADDPSr231rY, X86::VFNMADDPSr231mY, TB_ALIGN_NONE },
- { X86::VFNMADDPDr231rY, X86::VFNMADDPDr231mY, TB_ALIGN_NONE },
- { X86::VFNMADDPSr132rY, X86::VFNMADDPSr132mY, TB_ALIGN_NONE },
- { X86::VFNMADDPDr132rY, X86::VFNMADDPDr132mY, TB_ALIGN_NONE },
- { X86::VFNMADDPSr213rY, X86::VFNMADDPSr213mY, TB_ALIGN_NONE },
- { X86::VFNMADDPDr213rY, X86::VFNMADDPDr213mY, TB_ALIGN_NONE },
-
- { X86::VFMSUBSSr231r, X86::VFMSUBSSr231m, TB_ALIGN_NONE },
- { X86::VFMSUBSSr231r_Int, X86::VFMSUBSSr231m_Int, TB_ALIGN_NONE },
- { X86::VFMSUBSDr231r, X86::VFMSUBSDr231m, TB_ALIGN_NONE },
- { X86::VFMSUBSDr231r_Int, X86::VFMSUBSDr231m_Int, TB_ALIGN_NONE },
- { X86::VFMSUBSSr132r, X86::VFMSUBSSr132m, TB_ALIGN_NONE },
- { X86::VFMSUBSSr132r_Int, X86::VFMSUBSSr132m_Int, TB_ALIGN_NONE },
- { X86::VFMSUBSDr132r, X86::VFMSUBSDr132m, TB_ALIGN_NONE },
- { X86::VFMSUBSDr132r_Int, X86::VFMSUBSDr132m_Int, TB_ALIGN_NONE },
- { X86::VFMSUBSSr213r, X86::VFMSUBSSr213m, TB_ALIGN_NONE },
- { X86::VFMSUBSSr213r_Int, X86::VFMSUBSSr213m_Int, TB_ALIGN_NONE },
- { X86::VFMSUBSDr213r, X86::VFMSUBSDr213m, TB_ALIGN_NONE },
- { X86::VFMSUBSDr213r_Int, X86::VFMSUBSDr213m_Int, TB_ALIGN_NONE },
-
- { X86::VFMSUBPSr231r, X86::VFMSUBPSr231m, TB_ALIGN_NONE },
- { X86::VFMSUBPDr231r, X86::VFMSUBPDr231m, TB_ALIGN_NONE },
- { X86::VFMSUBPSr132r, X86::VFMSUBPSr132m, TB_ALIGN_NONE },
- { X86::VFMSUBPDr132r, X86::VFMSUBPDr132m, TB_ALIGN_NONE },
- { X86::VFMSUBPSr213r, X86::VFMSUBPSr213m, TB_ALIGN_NONE },
- { X86::VFMSUBPDr213r, X86::VFMSUBPDr213m, TB_ALIGN_NONE },
- { X86::VFMSUBPSr231rY, X86::VFMSUBPSr231mY, TB_ALIGN_NONE },
- { X86::VFMSUBPDr231rY, X86::VFMSUBPDr231mY, TB_ALIGN_NONE },
- { X86::VFMSUBPSr132rY, X86::VFMSUBPSr132mY, TB_ALIGN_NONE },
- { X86::VFMSUBPDr132rY, X86::VFMSUBPDr132mY, TB_ALIGN_NONE },
- { X86::VFMSUBPSr213rY, X86::VFMSUBPSr213mY, TB_ALIGN_NONE },
- { X86::VFMSUBPDr213rY, X86::VFMSUBPDr213mY, TB_ALIGN_NONE },
-
- { X86::VFNMSUBSSr231r, X86::VFNMSUBSSr231m, TB_ALIGN_NONE },
- { X86::VFNMSUBSSr231r_Int, X86::VFNMSUBSSr231m_Int, TB_ALIGN_NONE },
- { X86::VFNMSUBSDr231r, X86::VFNMSUBSDr231m, TB_ALIGN_NONE },
- { X86::VFNMSUBSDr231r_Int, X86::VFNMSUBSDr231m_Int, TB_ALIGN_NONE },
- { X86::VFNMSUBSSr132r, X86::VFNMSUBSSr132m, TB_ALIGN_NONE },
- { X86::VFNMSUBSSr132r_Int, X86::VFNMSUBSSr132m_Int, TB_ALIGN_NONE },
- { X86::VFNMSUBSDr132r, X86::VFNMSUBSDr132m, TB_ALIGN_NONE },
- { X86::VFNMSUBSDr132r_Int, X86::VFNMSUBSDr132m_Int, TB_ALIGN_NONE },
- { X86::VFNMSUBSSr213r, X86::VFNMSUBSSr213m, TB_ALIGN_NONE },
- { X86::VFNMSUBSSr213r_Int, X86::VFNMSUBSSr213m_Int, TB_ALIGN_NONE },
- { X86::VFNMSUBSDr213r, X86::VFNMSUBSDr213m, TB_ALIGN_NONE },
- { X86::VFNMSUBSDr213r_Int, X86::VFNMSUBSDr213m_Int, TB_ALIGN_NONE },
-
- { X86::VFNMSUBPSr231r, X86::VFNMSUBPSr231m, TB_ALIGN_NONE },
- { X86::VFNMSUBPDr231r, X86::VFNMSUBPDr231m, TB_ALIGN_NONE },
- { X86::VFNMSUBPSr132r, X86::VFNMSUBPSr132m, TB_ALIGN_NONE },
- { X86::VFNMSUBPDr132r, X86::VFNMSUBPDr132m, TB_ALIGN_NONE },
- { X86::VFNMSUBPSr213r, X86::VFNMSUBPSr213m, TB_ALIGN_NONE },
- { X86::VFNMSUBPDr213r, X86::VFNMSUBPDr213m, TB_ALIGN_NONE },
- { X86::VFNMSUBPSr231rY, X86::VFNMSUBPSr231mY, TB_ALIGN_NONE },
- { X86::VFNMSUBPDr231rY, X86::VFNMSUBPDr231mY, TB_ALIGN_NONE },
- { X86::VFNMSUBPSr132rY, X86::VFNMSUBPSr132mY, TB_ALIGN_NONE },
- { X86::VFNMSUBPDr132rY, X86::VFNMSUBPDr132mY, TB_ALIGN_NONE },
- { X86::VFNMSUBPSr213rY, X86::VFNMSUBPSr213mY, TB_ALIGN_NONE },
- { X86::VFNMSUBPDr213rY, X86::VFNMSUBPDr213mY, TB_ALIGN_NONE },
-
- { X86::VFMADDSUBPSr231r, X86::VFMADDSUBPSr231m, TB_ALIGN_NONE },
- { X86::VFMADDSUBPDr231r, X86::VFMADDSUBPDr231m, TB_ALIGN_NONE },
- { X86::VFMADDSUBPSr132r, X86::VFMADDSUBPSr132m, TB_ALIGN_NONE },
- { X86::VFMADDSUBPDr132r, X86::VFMADDSUBPDr132m, TB_ALIGN_NONE },
- { X86::VFMADDSUBPSr213r, X86::VFMADDSUBPSr213m, TB_ALIGN_NONE },
- { X86::VFMADDSUBPDr213r, X86::VFMADDSUBPDr213m, TB_ALIGN_NONE },
- { X86::VFMADDSUBPSr231rY, X86::VFMADDSUBPSr231mY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPDr231rY, X86::VFMADDSUBPDr231mY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPSr132rY, X86::VFMADDSUBPSr132mY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPDr132rY, X86::VFMADDSUBPDr132mY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPSr213rY, X86::VFMADDSUBPSr213mY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPDr213rY, X86::VFMADDSUBPDr213mY, TB_ALIGN_NONE },
-
- { X86::VFMSUBADDPSr231r, X86::VFMSUBADDPSr231m, TB_ALIGN_NONE },
- { X86::VFMSUBADDPDr231r, X86::VFMSUBADDPDr231m, TB_ALIGN_NONE },
- { X86::VFMSUBADDPSr132r, X86::VFMSUBADDPSr132m, TB_ALIGN_NONE },
- { X86::VFMSUBADDPDr132r, X86::VFMSUBADDPDr132m, TB_ALIGN_NONE },
- { X86::VFMSUBADDPSr213r, X86::VFMSUBADDPSr213m, TB_ALIGN_NONE },
- { X86::VFMSUBADDPDr213r, X86::VFMSUBADDPDr213m, TB_ALIGN_NONE },
- { X86::VFMSUBADDPSr231rY, X86::VFMSUBADDPSr231mY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPDr231rY, X86::VFMSUBADDPDr231mY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPSr132rY, X86::VFMSUBADDPSr132mY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPDr132rY, X86::VFMSUBADDPDr132mY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPSr213rY, X86::VFMSUBADDPSr213mY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPDr213rY, X86::VFMSUBADDPDr213mY, TB_ALIGN_NONE },
-
// FMA4 foldable patterns
{ X86::VFMADDSS4rr, X86::VFMADDSS4rm, TB_ALIGN_NONE },
+ { X86::VFMADDSS4rr_Int, X86::VFMADDSS4rm_Int, TB_NO_REVERSE },
{ X86::VFMADDSD4rr, X86::VFMADDSD4rm, TB_ALIGN_NONE },
+ { X86::VFMADDSD4rr_Int, X86::VFMADDSD4rm_Int, TB_NO_REVERSE },
{ X86::VFMADDPS4rr, X86::VFMADDPS4rm, TB_ALIGN_NONE },
{ X86::VFMADDPD4rr, X86::VFMADDPD4rm, TB_ALIGN_NONE },
- { X86::VFMADDPS4rrY, X86::VFMADDPS4rmY, TB_ALIGN_NONE },
- { X86::VFMADDPD4rrY, X86::VFMADDPD4rmY, TB_ALIGN_NONE },
+ { X86::VFMADDPS4Yrr, X86::VFMADDPS4Yrm, TB_ALIGN_NONE },
+ { X86::VFMADDPD4Yrr, X86::VFMADDPD4Yrm, TB_ALIGN_NONE },
{ X86::VFNMADDSS4rr, X86::VFNMADDSS4rm, TB_ALIGN_NONE },
+ { X86::VFNMADDSS4rr_Int, X86::VFNMADDSS4rm_Int, TB_NO_REVERSE },
{ X86::VFNMADDSD4rr, X86::VFNMADDSD4rm, TB_ALIGN_NONE },
+ { X86::VFNMADDSD4rr_Int, X86::VFNMADDSD4rm_Int, TB_NO_REVERSE },
{ X86::VFNMADDPS4rr, X86::VFNMADDPS4rm, TB_ALIGN_NONE },
{ X86::VFNMADDPD4rr, X86::VFNMADDPD4rm, TB_ALIGN_NONE },
- { X86::VFNMADDPS4rrY, X86::VFNMADDPS4rmY, TB_ALIGN_NONE },
- { X86::VFNMADDPD4rrY, X86::VFNMADDPD4rmY, TB_ALIGN_NONE },
+ { X86::VFNMADDPS4Yrr, X86::VFNMADDPS4Yrm, TB_ALIGN_NONE },
+ { X86::VFNMADDPD4Yrr, X86::VFNMADDPD4Yrm, TB_ALIGN_NONE },
{ X86::VFMSUBSS4rr, X86::VFMSUBSS4rm, TB_ALIGN_NONE },
+ { X86::VFMSUBSS4rr_Int, X86::VFMSUBSS4rm_Int, TB_NO_REVERSE },
{ X86::VFMSUBSD4rr, X86::VFMSUBSD4rm, TB_ALIGN_NONE },
+ { X86::VFMSUBSD4rr_Int, X86::VFMSUBSD4rm_Int, TB_NO_REVERSE },
{ X86::VFMSUBPS4rr, X86::VFMSUBPS4rm, TB_ALIGN_NONE },
{ X86::VFMSUBPD4rr, X86::VFMSUBPD4rm, TB_ALIGN_NONE },
- { X86::VFMSUBPS4rrY, X86::VFMSUBPS4rmY, TB_ALIGN_NONE },
- { X86::VFMSUBPD4rrY, X86::VFMSUBPD4rmY, TB_ALIGN_NONE },
+ { X86::VFMSUBPS4Yrr, X86::VFMSUBPS4Yrm, TB_ALIGN_NONE },
+ { X86::VFMSUBPD4Yrr, X86::VFMSUBPD4Yrm, TB_ALIGN_NONE },
{ X86::VFNMSUBSS4rr, X86::VFNMSUBSS4rm, TB_ALIGN_NONE },
+ { X86::VFNMSUBSS4rr_Int, X86::VFNMSUBSS4rm_Int, TB_NO_REVERSE },
{ X86::VFNMSUBSD4rr, X86::VFNMSUBSD4rm, TB_ALIGN_NONE },
+ { X86::VFNMSUBSD4rr_Int, X86::VFNMSUBSD4rm_Int, TB_NO_REVERSE },
{ X86::VFNMSUBPS4rr, X86::VFNMSUBPS4rm, TB_ALIGN_NONE },
{ X86::VFNMSUBPD4rr, X86::VFNMSUBPD4rm, TB_ALIGN_NONE },
- { X86::VFNMSUBPS4rrY, X86::VFNMSUBPS4rmY, TB_ALIGN_NONE },
- { X86::VFNMSUBPD4rrY, X86::VFNMSUBPD4rmY, TB_ALIGN_NONE },
+ { X86::VFNMSUBPS4Yrr, X86::VFNMSUBPS4Yrm, TB_ALIGN_NONE },
+ { X86::VFNMSUBPD4Yrr, X86::VFNMSUBPD4Yrm, TB_ALIGN_NONE },
{ X86::VFMADDSUBPS4rr, X86::VFMADDSUBPS4rm, TB_ALIGN_NONE },
{ X86::VFMADDSUBPD4rr, X86::VFMADDSUBPD4rm, TB_ALIGN_NONE },
- { X86::VFMADDSUBPS4rrY, X86::VFMADDSUBPS4rmY, TB_ALIGN_NONE },
- { X86::VFMADDSUBPD4rrY, X86::VFMADDSUBPD4rmY, TB_ALIGN_NONE },
+ { X86::VFMADDSUBPS4Yrr, X86::VFMADDSUBPS4Yrm, TB_ALIGN_NONE },
+ { X86::VFMADDSUBPD4Yrr, X86::VFMADDSUBPD4Yrm, TB_ALIGN_NONE },
{ X86::VFMSUBADDPS4rr, X86::VFMSUBADDPS4rm, TB_ALIGN_NONE },
{ X86::VFMSUBADDPD4rr, X86::VFMSUBADDPD4rm, TB_ALIGN_NONE },
- { X86::VFMSUBADDPS4rrY, X86::VFMSUBADDPS4rmY, TB_ALIGN_NONE },
- { X86::VFMSUBADDPD4rrY, X86::VFMSUBADDPD4rmY, TB_ALIGN_NONE },
+ { X86::VFMSUBADDPS4Yrr, X86::VFMSUBADDPS4Yrm, TB_ALIGN_NONE },
+ { X86::VFMSUBADDPD4Yrr, X86::VFMSUBADDPD4Yrm, TB_ALIGN_NONE },
// XOP foldable instructions
{ X86::VPCMOVrrr, X86::VPCMOVrrm, 0 },
@@ -1947,11 +2269,7 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VPERMIL2PSrrY, X86::VPERMIL2PSrmY, 0 },
{ X86::VPPERMrrr, X86::VPPERMrrm, 0 },
- // AVX-512 VPERMI instructions with 3 source operands.
- { X86::VPERMI2Drr, X86::VPERMI2Drm, 0 },
- { X86::VPERMI2Qrr, X86::VPERMI2Qrm, 0 },
- { X86::VPERMI2PSrr, X86::VPERMI2PSrm, 0 },
- { X86::VPERMI2PDrr, X86::VPERMI2PDrm, 0 },
+ // AVX-512 instructions with 3 source operands.
{ X86::VBLENDMPDZrr, X86::VBLENDMPDZrm, 0 },
{ X86::VBLENDMPSZrr, X86::VBLENDMPSZrm, 0 },
{ X86::VPBLENDMDZrr, X86::VPBLENDMDZrm, 0 },
@@ -1961,45 +2279,349 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
{ X86::VBROADCASTSSZ256rk, X86::VBROADCASTSSZ256mk, TB_NO_REVERSE },
{ X86::VBROADCASTSDZ256rk, X86::VBROADCASTSDZ256mk, TB_NO_REVERSE },
{ X86::VBROADCASTSSZ128rk, X86::VBROADCASTSSZ128mk, TB_NO_REVERSE },
- // AVX-512 arithmetic instructions
- { X86::VADDPSZrrkz, X86::VADDPSZrmkz, 0 },
+ { X86::VPERMI2Brr, X86::VPERMI2Brm, 0 },
+ { X86::VPERMI2Drr, X86::VPERMI2Drm, 0 },
+ { X86::VPERMI2PSrr, X86::VPERMI2PSrm, 0 },
+ { X86::VPERMI2PDrr, X86::VPERMI2PDrm, 0 },
+ { X86::VPERMI2Qrr, X86::VPERMI2Qrm, 0 },
+ { X86::VPERMI2Wrr, X86::VPERMI2Wrm, 0 },
+ { X86::VPERMT2Brr, X86::VPERMT2Brm, 0 },
+ { X86::VPERMT2Drr, X86::VPERMT2Drm, 0 },
+ { X86::VPERMT2PSrr, X86::VPERMT2PSrm, 0 },
+ { X86::VPERMT2PDrr, X86::VPERMT2PDrm, 0 },
+ { X86::VPERMT2Qrr, X86::VPERMT2Qrm, 0 },
+ { X86::VPERMT2Wrr, X86::VPERMT2Wrm, 0 },
+ { X86::VPTERNLOGDZrri, X86::VPTERNLOGDZrmi, 0 },
+ { X86::VPTERNLOGQZrri, X86::VPTERNLOGQZrmi, 0 },
+
+ // AVX-512VL 256-bit instructions with 3 source operands.
+ { X86::VPERMI2B256rr, X86::VPERMI2B256rm, 0 },
+ { X86::VPERMI2D256rr, X86::VPERMI2D256rm, 0 },
+ { X86::VPERMI2PD256rr, X86::VPERMI2PD256rm, 0 },
+ { X86::VPERMI2PS256rr, X86::VPERMI2PS256rm, 0 },
+ { X86::VPERMI2Q256rr, X86::VPERMI2Q256rm, 0 },
+ { X86::VPERMI2W256rr, X86::VPERMI2W256rm, 0 },
+ { X86::VPERMT2B256rr, X86::VPERMT2B256rm, 0 },
+ { X86::VPERMT2D256rr, X86::VPERMT2D256rm, 0 },
+ { X86::VPERMT2PD256rr, X86::VPERMT2PD256rm, 0 },
+ { X86::VPERMT2PS256rr, X86::VPERMT2PS256rm, 0 },
+ { X86::VPERMT2Q256rr, X86::VPERMT2Q256rm, 0 },
+ { X86::VPERMT2W256rr, X86::VPERMT2W256rm, 0 },
+ { X86::VPTERNLOGDZ256rri, X86::VPTERNLOGDZ256rmi, 0 },
+ { X86::VPTERNLOGQZ256rri, X86::VPTERNLOGQZ256rmi, 0 },
+
+ // AVX-512VL 128-bit instructions with 3 source operands.
+ { X86::VPERMI2B128rr, X86::VPERMI2B128rm, 0 },
+ { X86::VPERMI2D128rr, X86::VPERMI2D128rm, 0 },
+ { X86::VPERMI2PD128rr, X86::VPERMI2PD128rm, 0 },
+ { X86::VPERMI2PS128rr, X86::VPERMI2PS128rm, 0 },
+ { X86::VPERMI2Q128rr, X86::VPERMI2Q128rm, 0 },
+ { X86::VPERMI2W128rr, X86::VPERMI2W128rm, 0 },
+ { X86::VPERMT2B128rr, X86::VPERMT2B128rm, 0 },
+ { X86::VPERMT2D128rr, X86::VPERMT2D128rm, 0 },
+ { X86::VPERMT2PD128rr, X86::VPERMT2PD128rm, 0 },
+ { X86::VPERMT2PS128rr, X86::VPERMT2PS128rm, 0 },
+ { X86::VPERMT2Q128rr, X86::VPERMT2Q128rm, 0 },
+ { X86::VPERMT2W128rr, X86::VPERMT2W128rm, 0 },
+ { X86::VPTERNLOGDZ128rri, X86::VPTERNLOGDZ128rmi, 0 },
+ { X86::VPTERNLOGQZ128rri, X86::VPTERNLOGQZ128rmi, 0 },
+
+ // AVX-512 masked instructions
{ X86::VADDPDZrrkz, X86::VADDPDZrmkz, 0 },
- { X86::VSUBPSZrrkz, X86::VSUBPSZrmkz, 0 },
- { X86::VSUBPDZrrkz, X86::VSUBPDZrmkz, 0 },
- { X86::VMULPSZrrkz, X86::VMULPSZrmkz, 0 },
- { X86::VMULPDZrrkz, X86::VMULPDZrmkz, 0 },
- { X86::VDIVPSZrrkz, X86::VDIVPSZrmkz, 0 },
+ { X86::VADDPSZrrkz, X86::VADDPSZrmkz, 0 },
+ { X86::VALIGNDZrrikz, X86::VALIGNDZrmikz, 0 },
+ { X86::VALIGNQZrrikz, X86::VALIGNQZrmikz, 0 },
+ { X86::VANDNPDZrrkz, X86::VANDNPDZrmkz, 0 },
+ { X86::VANDNPSZrrkz, X86::VANDNPSZrmkz, 0 },
+ { X86::VANDPDZrrkz, X86::VANDPDZrmkz, 0 },
+ { X86::VANDPSZrrkz, X86::VANDPSZrmkz, 0 },
{ X86::VDIVPDZrrkz, X86::VDIVPDZrmkz, 0 },
- { X86::VMINPSZrrkz, X86::VMINPSZrmkz, 0 },
- { X86::VMINPDZrrkz, X86::VMINPDZrmkz, 0 },
- { X86::VMAXPSZrrkz, X86::VMAXPSZrmkz, 0 },
+ { X86::VDIVPSZrrkz, X86::VDIVPSZrmkz, 0 },
+ { X86::VINSERTF32x4Zrrkz, X86::VINSERTF32x4Zrmkz, 0 },
+ { X86::VINSERTF32x8Zrrkz, X86::VINSERTF32x8Zrmkz, 0 },
+ { X86::VINSERTF64x2Zrrkz, X86::VINSERTF64x2Zrmkz, 0 },
+ { X86::VINSERTF64x4Zrrkz, X86::VINSERTF64x4Zrmkz, 0 },
+ { X86::VINSERTI32x4Zrrkz, X86::VINSERTI32x4Zrmkz, 0 },
+ { X86::VINSERTI32x8Zrrkz, X86::VINSERTI32x8Zrmkz, 0 },
+ { X86::VINSERTI64x2Zrrkz, X86::VINSERTI64x2Zrmkz, 0 },
+ { X86::VINSERTI64x4Zrrkz, X86::VINSERTI64x4Zrmkz, 0 },
+ { X86::VMAXCPDZrrkz, X86::VMAXCPDZrmkz, 0 },
+ { X86::VMAXCPSZrrkz, X86::VMAXCPSZrmkz, 0 },
{ X86::VMAXPDZrrkz, X86::VMAXPDZrmkz, 0 },
- // AVX-512{F,VL} arithmetic instructions 256-bit
- { X86::VADDPSZ256rrkz, X86::VADDPSZ256rmkz, 0 },
+ { X86::VMAXPSZrrkz, X86::VMAXPSZrmkz, 0 },
+ { X86::VMINCPDZrrkz, X86::VMINCPDZrmkz, 0 },
+ { X86::VMINCPSZrrkz, X86::VMINCPSZrmkz, 0 },
+ { X86::VMINPDZrrkz, X86::VMINPDZrmkz, 0 },
+ { X86::VMINPSZrrkz, X86::VMINPSZrmkz, 0 },
+ { X86::VMULPDZrrkz, X86::VMULPDZrmkz, 0 },
+ { X86::VMULPSZrrkz, X86::VMULPSZrmkz, 0 },
+ { X86::VORPDZrrkz, X86::VORPDZrmkz, 0 },
+ { X86::VORPSZrrkz, X86::VORPSZrmkz, 0 },
+ { X86::VPADDBZrrkz, X86::VPADDBZrmkz, 0 },
+ { X86::VPADDDZrrkz, X86::VPADDDZrmkz, 0 },
+ { X86::VPADDQZrrkz, X86::VPADDQZrmkz, 0 },
+ { X86::VPADDSBZrrkz, X86::VPADDSBZrmkz, 0 },
+ { X86::VPADDSWZrrkz, X86::VPADDSWZrmkz, 0 },
+ { X86::VPADDUSBZrrkz, X86::VPADDUSBZrmkz, 0 },
+ { X86::VPADDUSWZrrkz, X86::VPADDUSWZrmkz, 0 },
+ { X86::VPADDWZrrkz, X86::VPADDWZrmkz, 0 },
+ { X86::VPALIGNRZrrikz, X86::VPALIGNRZrmikz, 0 },
+ { X86::VPANDDZrrkz, X86::VPANDDZrmkz, 0 },
+ { X86::VPANDNDZrrkz, X86::VPANDNDZrmkz, 0 },
+ { X86::VPANDNQZrrkz, X86::VPANDNQZrmkz, 0 },
+ { X86::VPANDQZrrkz, X86::VPANDQZrmkz, 0 },
+ { X86::VPERMBZrrkz, X86::VPERMBZrmkz, 0 },
+ { X86::VPERMDZrrkz, X86::VPERMDZrmkz, 0 },
+ { X86::VPERMILPDZrrkz, X86::VPERMILPDZrmkz, 0 },
+ { X86::VPERMILPSZrrkz, X86::VPERMILPSZrmkz, 0 },
+ { X86::VPERMPDZrrkz, X86::VPERMPDZrmkz, 0 },
+ { X86::VPERMPSZrrkz, X86::VPERMPSZrmkz, 0 },
+ { X86::VPERMQZrrkz, X86::VPERMQZrmkz, 0 },
+ { X86::VPERMWZrrkz, X86::VPERMWZrmkz, 0 },
+ { X86::VPMADDUBSWZrrkz, X86::VPMADDUBSWZrmkz, 0 },
+ { X86::VPMADDWDZrrkz, X86::VPMADDWDZrmkz, 0 },
+ { X86::VPORDZrrkz, X86::VPORDZrmkz, 0 },
+ { X86::VPORQZrrkz, X86::VPORQZrmkz, 0 },
+ { X86::VPSHUFBZrrkz, X86::VPSHUFBZrmkz, 0 },
+ { X86::VPSUBBZrrkz, X86::VPSUBBZrmkz, 0 },
+ { X86::VPSUBDZrrkz, X86::VPSUBDZrmkz, 0 },
+ { X86::VPSUBQZrrkz, X86::VPSUBQZrmkz, 0 },
+ { X86::VPSUBSBZrrkz, X86::VPSUBSBZrmkz, 0 },
+ { X86::VPSUBSWZrrkz, X86::VPSUBSWZrmkz, 0 },
+ { X86::VPSUBUSBZrrkz, X86::VPSUBUSBZrmkz, 0 },
+ { X86::VPSUBUSWZrrkz, X86::VPSUBUSWZrmkz, 0 },
+ { X86::VPSUBWZrrkz, X86::VPSUBWZrmkz, 0 },
+ { X86::VPUNPCKHBWZrrkz, X86::VPUNPCKHBWZrmkz, 0 },
+ { X86::VPUNPCKHDQZrrkz, X86::VPUNPCKHDQZrmkz, 0 },
+ { X86::VPUNPCKHQDQZrrkz, X86::VPUNPCKHQDQZrmkz, 0 },
+ { X86::VPUNPCKHWDZrrkz, X86::VPUNPCKHWDZrmkz, 0 },
+ { X86::VPUNPCKLBWZrrkz, X86::VPUNPCKLBWZrmkz, 0 },
+ { X86::VPUNPCKLDQZrrkz, X86::VPUNPCKLDQZrmkz, 0 },
+ { X86::VPUNPCKLQDQZrrkz, X86::VPUNPCKLQDQZrmkz, 0 },
+ { X86::VPUNPCKLWDZrrkz, X86::VPUNPCKLWDZrmkz, 0 },
+ { X86::VPXORDZrrkz, X86::VPXORDZrmkz, 0 },
+ { X86::VPXORQZrrkz, X86::VPXORQZrmkz, 0 },
+ { X86::VSUBPDZrrkz, X86::VSUBPDZrmkz, 0 },
+ { X86::VSUBPSZrrkz, X86::VSUBPSZrmkz, 0 },
+ { X86::VUNPCKHPDZrrkz, X86::VUNPCKHPDZrmkz, 0 },
+ { X86::VUNPCKHPSZrrkz, X86::VUNPCKHPSZrmkz, 0 },
+ { X86::VUNPCKLPDZrrkz, X86::VUNPCKLPDZrmkz, 0 },
+ { X86::VUNPCKLPSZrrkz, X86::VUNPCKLPSZrmkz, 0 },
+ { X86::VXORPDZrrkz, X86::VXORPDZrmkz, 0 },
+ { X86::VXORPSZrrkz, X86::VXORPSZrmkz, 0 },
+
+ // AVX-512{F,VL} masked arithmetic instructions 256-bit
{ X86::VADDPDZ256rrkz, X86::VADDPDZ256rmkz, 0 },
- { X86::VSUBPSZ256rrkz, X86::VSUBPSZ256rmkz, 0 },
- { X86::VSUBPDZ256rrkz, X86::VSUBPDZ256rmkz, 0 },
- { X86::VMULPSZ256rrkz, X86::VMULPSZ256rmkz, 0 },
- { X86::VMULPDZ256rrkz, X86::VMULPDZ256rmkz, 0 },
- { X86::VDIVPSZ256rrkz, X86::VDIVPSZ256rmkz, 0 },
+ { X86::VADDPSZ256rrkz, X86::VADDPSZ256rmkz, 0 },
+ { X86::VALIGNDZ256rrikz, X86::VALIGNDZ256rmikz, 0 },
+ { X86::VALIGNQZ256rrikz, X86::VALIGNQZ256rmikz, 0 },
+ { X86::VANDNPDZ256rrkz, X86::VANDNPDZ256rmkz, 0 },
+ { X86::VANDNPSZ256rrkz, X86::VANDNPSZ256rmkz, 0 },
+ { X86::VANDPDZ256rrkz, X86::VANDPDZ256rmkz, 0 },
+ { X86::VANDPSZ256rrkz, X86::VANDPSZ256rmkz, 0 },
{ X86::VDIVPDZ256rrkz, X86::VDIVPDZ256rmkz, 0 },
- { X86::VMINPSZ256rrkz, X86::VMINPSZ256rmkz, 0 },
- { X86::VMINPDZ256rrkz, X86::VMINPDZ256rmkz, 0 },
- { X86::VMAXPSZ256rrkz, X86::VMAXPSZ256rmkz, 0 },
+ { X86::VDIVPSZ256rrkz, X86::VDIVPSZ256rmkz, 0 },
+ { X86::VINSERTF32x4Z256rrkz, X86::VINSERTF32x4Z256rmkz, 0 },
+ { X86::VINSERTF64x2Z256rrkz, X86::VINSERTF64x2Z256rmkz, 0 },
+ { X86::VINSERTI32x4Z256rrkz, X86::VINSERTI32x4Z256rmkz, 0 },
+ { X86::VINSERTI64x2Z256rrkz, X86::VINSERTI64x2Z256rmkz, 0 },
+ { X86::VMAXCPDZ256rrkz, X86::VMAXCPDZ256rmkz, 0 },
+ { X86::VMAXCPSZ256rrkz, X86::VMAXCPSZ256rmkz, 0 },
{ X86::VMAXPDZ256rrkz, X86::VMAXPDZ256rmkz, 0 },
- // AVX-512{F,VL} arithmetic instructions 128-bit
- { X86::VADDPSZ128rrkz, X86::VADDPSZ128rmkz, 0 },
+ { X86::VMAXPSZ256rrkz, X86::VMAXPSZ256rmkz, 0 },
+ { X86::VMINCPDZ256rrkz, X86::VMINCPDZ256rmkz, 0 },
+ { X86::VMINCPSZ256rrkz, X86::VMINCPSZ256rmkz, 0 },
+ { X86::VMINPDZ256rrkz, X86::VMINPDZ256rmkz, 0 },
+ { X86::VMINPSZ256rrkz, X86::VMINPSZ256rmkz, 0 },
+ { X86::VMULPDZ256rrkz, X86::VMULPDZ256rmkz, 0 },
+ { X86::VMULPSZ256rrkz, X86::VMULPSZ256rmkz, 0 },
+ { X86::VORPDZ256rrkz, X86::VORPDZ256rmkz, 0 },
+ { X86::VORPSZ256rrkz, X86::VORPSZ256rmkz, 0 },
+ { X86::VPADDBZ256rrkz, X86::VPADDBZ256rmkz, 0 },
+ { X86::VPADDDZ256rrkz, X86::VPADDDZ256rmkz, 0 },
+ { X86::VPADDQZ256rrkz, X86::VPADDQZ256rmkz, 0 },
+ { X86::VPADDSBZ256rrkz, X86::VPADDSBZ256rmkz, 0 },
+ { X86::VPADDSWZ256rrkz, X86::VPADDSWZ256rmkz, 0 },
+ { X86::VPADDUSBZ256rrkz, X86::VPADDUSBZ256rmkz, 0 },
+ { X86::VPADDUSWZ256rrkz, X86::VPADDUSWZ256rmkz, 0 },
+ { X86::VPADDWZ256rrkz, X86::VPADDWZ256rmkz, 0 },
+ { X86::VPALIGNRZ256rrikz, X86::VPALIGNRZ256rmikz, 0 },
+ { X86::VPANDDZ256rrkz, X86::VPANDDZ256rmkz, 0 },
+ { X86::VPANDNDZ256rrkz, X86::VPANDNDZ256rmkz, 0 },
+ { X86::VPANDNQZ256rrkz, X86::VPANDNQZ256rmkz, 0 },
+ { X86::VPANDQZ256rrkz, X86::VPANDQZ256rmkz, 0 },
+ { X86::VPERMBZ256rrkz, X86::VPERMBZ256rmkz, 0 },
+ { X86::VPERMDZ256rrkz, X86::VPERMDZ256rmkz, 0 },
+ { X86::VPERMILPDZ256rrkz, X86::VPERMILPDZ256rmkz, 0 },
+ { X86::VPERMILPSZ256rrkz, X86::VPERMILPSZ256rmkz, 0 },
+ { X86::VPERMPDZ256rrkz, X86::VPERMPDZ256rmkz, 0 },
+ { X86::VPERMPSZ256rrkz, X86::VPERMPSZ256rmkz, 0 },
+ { X86::VPERMQZ256rrkz, X86::VPERMQZ256rmkz, 0 },
+ { X86::VPERMWZ256rrkz, X86::VPERMWZ256rmkz, 0 },
+ { X86::VPMADDUBSWZ256rrkz, X86::VPMADDUBSWZ256rmkz, 0 },
+ { X86::VPMADDWDZ256rrkz, X86::VPMADDWDZ256rmkz, 0 },
+ { X86::VPORDZ256rrkz, X86::VPORDZ256rmkz, 0 },
+ { X86::VPORQZ256rrkz, X86::VPORQZ256rmkz, 0 },
+ { X86::VPSHUFBZ256rrkz, X86::VPSHUFBZ256rmkz, 0 },
+ { X86::VPSUBBZ256rrkz, X86::VPSUBBZ256rmkz, 0 },
+ { X86::VPSUBDZ256rrkz, X86::VPSUBDZ256rmkz, 0 },
+ { X86::VPSUBQZ256rrkz, X86::VPSUBQZ256rmkz, 0 },
+ { X86::VPSUBSBZ256rrkz, X86::VPSUBSBZ256rmkz, 0 },
+ { X86::VPSUBSWZ256rrkz, X86::VPSUBSWZ256rmkz, 0 },
+ { X86::VPSUBUSBZ256rrkz, X86::VPSUBUSBZ256rmkz, 0 },
+ { X86::VPSUBUSWZ256rrkz, X86::VPSUBUSWZ256rmkz, 0 },
+ { X86::VPSUBWZ256rrkz, X86::VPSUBWZ256rmkz, 0 },
+ { X86::VPUNPCKHBWZ256rrkz, X86::VPUNPCKHBWZ256rmkz, 0 },
+ { X86::VPUNPCKHDQZ256rrkz, X86::VPUNPCKHDQZ256rmkz, 0 },
+ { X86::VPUNPCKHQDQZ256rrkz, X86::VPUNPCKHQDQZ256rmkz, 0 },
+ { X86::VPUNPCKHWDZ256rrkz, X86::VPUNPCKHWDZ256rmkz, 0 },
+ { X86::VPUNPCKLBWZ256rrkz, X86::VPUNPCKLBWZ256rmkz, 0 },
+ { X86::VPUNPCKLDQZ256rrkz, X86::VPUNPCKLDQZ256rmkz, 0 },
+ { X86::VPUNPCKLQDQZ256rrkz, X86::VPUNPCKLQDQZ256rmkz, 0 },
+ { X86::VPUNPCKLWDZ256rrkz, X86::VPUNPCKLWDZ256rmkz, 0 },
+ { X86::VPXORDZ256rrkz, X86::VPXORDZ256rmkz, 0 },
+ { X86::VPXORQZ256rrkz, X86::VPXORQZ256rmkz, 0 },
+ { X86::VSUBPDZ256rrkz, X86::VSUBPDZ256rmkz, 0 },
+ { X86::VSUBPSZ256rrkz, X86::VSUBPSZ256rmkz, 0 },
+ { X86::VUNPCKHPDZ256rrkz, X86::VUNPCKHPDZ256rmkz, 0 },
+ { X86::VUNPCKHPSZ256rrkz, X86::VUNPCKHPSZ256rmkz, 0 },
+ { X86::VUNPCKLPDZ256rrkz, X86::VUNPCKLPDZ256rmkz, 0 },
+ { X86::VUNPCKLPSZ256rrkz, X86::VUNPCKLPSZ256rmkz, 0 },
+ { X86::VXORPDZ256rrkz, X86::VXORPDZ256rmkz, 0 },
+ { X86::VXORPSZ256rrkz, X86::VXORPSZ256rmkz, 0 },
+
+ // AVX-512{F,VL} masked arithmetic instructions 128-bit
{ X86::VADDPDZ128rrkz, X86::VADDPDZ128rmkz, 0 },
- { X86::VSUBPSZ128rrkz, X86::VSUBPSZ128rmkz, 0 },
- { X86::VSUBPDZ128rrkz, X86::VSUBPDZ128rmkz, 0 },
- { X86::VMULPSZ128rrkz, X86::VMULPSZ128rmkz, 0 },
- { X86::VMULPDZ128rrkz, X86::VMULPDZ128rmkz, 0 },
- { X86::VDIVPSZ128rrkz, X86::VDIVPSZ128rmkz, 0 },
+ { X86::VADDPSZ128rrkz, X86::VADDPSZ128rmkz, 0 },
+ { X86::VALIGNDZ128rrikz, X86::VALIGNDZ128rmikz, 0 },
+ { X86::VALIGNQZ128rrikz, X86::VALIGNQZ128rmikz, 0 },
+ { X86::VANDNPDZ128rrkz, X86::VANDNPDZ128rmkz, 0 },
+ { X86::VANDNPSZ128rrkz, X86::VANDNPSZ128rmkz, 0 },
+ { X86::VANDPDZ128rrkz, X86::VANDPDZ128rmkz, 0 },
+ { X86::VANDPSZ128rrkz, X86::VANDPSZ128rmkz, 0 },
{ X86::VDIVPDZ128rrkz, X86::VDIVPDZ128rmkz, 0 },
- { X86::VMINPSZ128rrkz, X86::VMINPSZ128rmkz, 0 },
- { X86::VMINPDZ128rrkz, X86::VMINPDZ128rmkz, 0 },
+ { X86::VDIVPSZ128rrkz, X86::VDIVPSZ128rmkz, 0 },
+ { X86::VMAXCPDZ128rrkz, X86::VMAXCPDZ128rmkz, 0 },
+ { X86::VMAXCPSZ128rrkz, X86::VMAXCPSZ128rmkz, 0 },
+ { X86::VMAXPDZ128rrkz, X86::VMAXPDZ128rmkz, 0 },
{ X86::VMAXPSZ128rrkz, X86::VMAXPSZ128rmkz, 0 },
- { X86::VMAXPDZ128rrkz, X86::VMAXPDZ128rmkz, 0 }
+ { X86::VMINCPDZ128rrkz, X86::VMINCPDZ128rmkz, 0 },
+ { X86::VMINCPSZ128rrkz, X86::VMINCPSZ128rmkz, 0 },
+ { X86::VMINPDZ128rrkz, X86::VMINPDZ128rmkz, 0 },
+ { X86::VMINPSZ128rrkz, X86::VMINPSZ128rmkz, 0 },
+ { X86::VMULPDZ128rrkz, X86::VMULPDZ128rmkz, 0 },
+ { X86::VMULPSZ128rrkz, X86::VMULPSZ128rmkz, 0 },
+ { X86::VORPDZ128rrkz, X86::VORPDZ128rmkz, 0 },
+ { X86::VORPSZ128rrkz, X86::VORPSZ128rmkz, 0 },
+ { X86::VPADDBZ128rrkz, X86::VPADDBZ128rmkz, 0 },
+ { X86::VPADDDZ128rrkz, X86::VPADDDZ128rmkz, 0 },
+ { X86::VPADDQZ128rrkz, X86::VPADDQZ128rmkz, 0 },
+ { X86::VPADDSBZ128rrkz, X86::VPADDSBZ128rmkz, 0 },
+ { X86::VPADDSWZ128rrkz, X86::VPADDSWZ128rmkz, 0 },
+ { X86::VPADDUSBZ128rrkz, X86::VPADDUSBZ128rmkz, 0 },
+ { X86::VPADDUSWZ128rrkz, X86::VPADDUSWZ128rmkz, 0 },
+ { X86::VPADDWZ128rrkz, X86::VPADDWZ128rmkz, 0 },
+ { X86::VPALIGNRZ128rrikz, X86::VPALIGNRZ128rmikz, 0 },
+ { X86::VPANDDZ128rrkz, X86::VPANDDZ128rmkz, 0 },
+ { X86::VPANDNDZ128rrkz, X86::VPANDNDZ128rmkz, 0 },
+ { X86::VPANDNQZ128rrkz, X86::VPANDNQZ128rmkz, 0 },
+ { X86::VPANDQZ128rrkz, X86::VPANDQZ128rmkz, 0 },
+ { X86::VPERMBZ128rrkz, X86::VPERMBZ128rmkz, 0 },
+ { X86::VPERMILPDZ128rrkz, X86::VPERMILPDZ128rmkz, 0 },
+ { X86::VPERMILPSZ128rrkz, X86::VPERMILPSZ128rmkz, 0 },
+ { X86::VPERMWZ128rrkz, X86::VPERMWZ128rmkz, 0 },
+ { X86::VPMADDUBSWZ128rrkz, X86::VPMADDUBSWZ128rmkz, 0 },
+ { X86::VPMADDWDZ128rrkz, X86::VPMADDWDZ128rmkz, 0 },
+ { X86::VPORDZ128rrkz, X86::VPORDZ128rmkz, 0 },
+ { X86::VPORQZ128rrkz, X86::VPORQZ128rmkz, 0 },
+ { X86::VPSHUFBZ128rrkz, X86::VPSHUFBZ128rmkz, 0 },
+ { X86::VPSUBBZ128rrkz, X86::VPSUBBZ128rmkz, 0 },
+ { X86::VPSUBDZ128rrkz, X86::VPSUBDZ128rmkz, 0 },
+ { X86::VPSUBQZ128rrkz, X86::VPSUBQZ128rmkz, 0 },
+ { X86::VPSUBSBZ128rrkz, X86::VPSUBSBZ128rmkz, 0 },
+ { X86::VPSUBSWZ128rrkz, X86::VPSUBSWZ128rmkz, 0 },
+ { X86::VPSUBUSBZ128rrkz, X86::VPSUBUSBZ128rmkz, 0 },
+ { X86::VPSUBUSWZ128rrkz, X86::VPSUBUSWZ128rmkz, 0 },
+ { X86::VPSUBWZ128rrkz, X86::VPSUBWZ128rmkz, 0 },
+ { X86::VPUNPCKHBWZ128rrkz, X86::VPUNPCKHBWZ128rmkz, 0 },
+ { X86::VPUNPCKHDQZ128rrkz, X86::VPUNPCKHDQZ128rmkz, 0 },
+ { X86::VPUNPCKHQDQZ128rrkz, X86::VPUNPCKHQDQZ128rmkz, 0 },
+ { X86::VPUNPCKHWDZ128rrkz, X86::VPUNPCKHWDZ128rmkz, 0 },
+ { X86::VPUNPCKLBWZ128rrkz, X86::VPUNPCKLBWZ128rmkz, 0 },
+ { X86::VPUNPCKLDQZ128rrkz, X86::VPUNPCKLDQZ128rmkz, 0 },
+ { X86::VPUNPCKLQDQZ128rrkz, X86::VPUNPCKLQDQZ128rmkz, 0 },
+ { X86::VPUNPCKLWDZ128rrkz, X86::VPUNPCKLWDZ128rmkz, 0 },
+ { X86::VPXORDZ128rrkz, X86::VPXORDZ128rmkz, 0 },
+ { X86::VPXORQZ128rrkz, X86::VPXORQZ128rmkz, 0 },
+ { X86::VSUBPDZ128rrkz, X86::VSUBPDZ128rmkz, 0 },
+ { X86::VSUBPSZ128rrkz, X86::VSUBPSZ128rmkz, 0 },
+ { X86::VUNPCKHPDZ128rrkz, X86::VUNPCKHPDZ128rmkz, 0 },
+ { X86::VUNPCKHPSZ128rrkz, X86::VUNPCKHPSZ128rmkz, 0 },
+ { X86::VUNPCKLPDZ128rrkz, X86::VUNPCKLPDZ128rmkz, 0 },
+ { X86::VUNPCKLPSZ128rrkz, X86::VUNPCKLPSZ128rmkz, 0 },
+ { X86::VXORPDZ128rrkz, X86::VXORPDZ128rmkz, 0 },
+ { X86::VXORPSZ128rrkz, X86::VXORPSZ128rmkz, 0 },
+
+ // AVX-512 masked foldable instructions
+ { X86::VPERMILPDZrik, X86::VPERMILPDZmik, 0 },
+ { X86::VPERMILPSZrik, X86::VPERMILPSZmik, 0 },
+ { X86::VPERMPDZrik, X86::VPERMPDZmik, 0 },
+ { X86::VPERMQZrik, X86::VPERMQZmik, 0 },
+ { X86::VPMOVSXBDZrrk, X86::VPMOVSXBDZrmk, 0 },
+ { X86::VPMOVSXBQZrrk, X86::VPMOVSXBQZrmk, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZrrk, X86::VPMOVSXBWZrmk, 0 },
+ { X86::VPMOVSXDQZrrk, X86::VPMOVSXDQZrmk, 0 },
+ { X86::VPMOVSXWDZrrk, X86::VPMOVSXWDZrmk, 0 },
+ { X86::VPMOVSXWQZrrk, X86::VPMOVSXWQZrmk, 0 },
+ { X86::VPMOVZXBDZrrk, X86::VPMOVZXBDZrmk, 0 },
+ { X86::VPMOVZXBQZrrk, X86::VPMOVZXBQZrmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZrrk, X86::VPMOVZXBWZrmk, 0 },
+ { X86::VPMOVZXDQZrrk, X86::VPMOVZXDQZrmk, 0 },
+ { X86::VPMOVZXWDZrrk, X86::VPMOVZXWDZrmk, 0 },
+ { X86::VPMOVZXWQZrrk, X86::VPMOVZXWQZrmk, 0 },
+ { X86::VPSHUFDZrik, X86::VPSHUFDZmik, 0 },
+ { X86::VPSHUFHWZrik, X86::VPSHUFHWZmik, 0 },
+ { X86::VPSHUFLWZrik, X86::VPSHUFLWZmik, 0 },
+
+ // AVX-512VL 256-bit masked foldable instructions
+ { X86::VPERMILPDZ256rik, X86::VPERMILPDZ256mik, 0 },
+ { X86::VPERMILPSZ256rik, X86::VPERMILPSZ256mik, 0 },
+ { X86::VPERMPDZ256rik, X86::VPERMPDZ256mik, 0 },
+ { X86::VPERMQZ256rik, X86::VPERMQZ256mik, 0 },
+ { X86::VPMOVSXBDZ256rrk, X86::VPMOVSXBDZ256rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXBQZ256rrk, X86::VPMOVSXBQZ256rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZ256rrk, X86::VPMOVSXBWZ256rmk, 0 },
+ { X86::VPMOVSXDQZ256rrk, X86::VPMOVSXDQZ256rmk, 0 },
+ { X86::VPMOVSXWDZ256rrk, X86::VPMOVSXWDZ256rmk, 0 },
+ { X86::VPMOVSXWQZ256rrk, X86::VPMOVSXWQZ256rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBDZ256rrk, X86::VPMOVZXBDZ256rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBQZ256rrk, X86::VPMOVZXBQZ256rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZ256rrk, X86::VPMOVZXBWZ256rmk, 0 },
+ { X86::VPMOVZXDQZ256rrk, X86::VPMOVZXDQZ256rmk, 0 },
+ { X86::VPMOVZXWDZ256rrk, X86::VPMOVZXWDZ256rmk, 0 },
+ { X86::VPMOVZXWQZ256rrk, X86::VPMOVZXWQZ256rmk, TB_NO_REVERSE },
+ { X86::VPSHUFDZ256rik, X86::VPSHUFDZ256mik, 0 },
+ { X86::VPSHUFHWZ256rik, X86::VPSHUFHWZ256mik, 0 },
+ { X86::VPSHUFLWZ256rik, X86::VPSHUFLWZ256mik, 0 },
+
+ // AVX-512VL 128-bit masked foldable instructions
+ { X86::VPERMILPDZ128rik, X86::VPERMILPDZ128mik, 0 },
+ { X86::VPERMILPSZ128rik, X86::VPERMILPSZ128mik, 0 },
+ { X86::VPMOVSXBDZ128rrk, X86::VPMOVSXBDZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXBQZ128rrk, X86::VPMOVSXBQZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXBWZ128rrk, X86::VPMOVSXBWZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXDQZ128rrk, X86::VPMOVSXDQZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXWDZ128rrk, X86::VPMOVSXWDZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVSXWQZ128rrk, X86::VPMOVSXWQZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBDZ128rrk, X86::VPMOVZXBDZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBQZ128rrk, X86::VPMOVZXBQZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXBWZ128rrk, X86::VPMOVZXBWZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXDQZ128rrk, X86::VPMOVZXDQZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXWDZ128rrk, X86::VPMOVZXWDZ128rmk, TB_NO_REVERSE },
+ { X86::VPMOVZXWQZ128rrk, X86::VPMOVZXWQZ128rmk, TB_NO_REVERSE },
+ { X86::VPSHUFDZ128rik, X86::VPSHUFDZ128mik, 0 },
+ { X86::VPSHUFHWZ128rik, X86::VPSHUFHWZ128mik, 0 },
+ { X86::VPSHUFLWZ128rik, X86::VPSHUFLWZ128mik, 0 },
};
for (X86MemoryFoldTableEntry Entry : MemoryFoldTable3) {
@@ -2008,47 +2630,348 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
// Index 3, folded load
Entry.Flags | TB_INDEX_3 | TB_FOLDED_LOAD);
}
+ auto I = X86InstrFMA3Info::rm_begin();
+ auto E = X86InstrFMA3Info::rm_end();
+ for (; I != E; ++I) {
+ if (!I.getGroup()->isKMasked()) {
+ // Intrinsic forms need to pass TB_NO_REVERSE.
+ if (I.getGroup()->isIntrinsic()) {
+ AddTableEntry(RegOp2MemOpTable3, MemOp2RegOpTable,
+ I.getRegOpcode(), I.getMemOpcode(),
+ TB_ALIGN_NONE | TB_INDEX_3 | TB_FOLDED_LOAD | TB_NO_REVERSE);
+ } else {
+ AddTableEntry(RegOp2MemOpTable3, MemOp2RegOpTable,
+ I.getRegOpcode(), I.getMemOpcode(),
+ TB_ALIGN_NONE | TB_INDEX_3 | TB_FOLDED_LOAD);
+ }
+ }
+ }
static const X86MemoryFoldTableEntry MemoryFoldTable4[] = {
- // AVX-512 foldable instructions
- { X86::VADDPSZrrk, X86::VADDPSZrmk, 0 },
+ // AVX-512 foldable masked instructions
{ X86::VADDPDZrrk, X86::VADDPDZrmk, 0 },
- { X86::VSUBPSZrrk, X86::VSUBPSZrmk, 0 },
- { X86::VSUBPDZrrk, X86::VSUBPDZrmk, 0 },
- { X86::VMULPSZrrk, X86::VMULPSZrmk, 0 },
- { X86::VMULPDZrrk, X86::VMULPDZrmk, 0 },
- { X86::VDIVPSZrrk, X86::VDIVPSZrmk, 0 },
+ { X86::VADDPSZrrk, X86::VADDPSZrmk, 0 },
+ { X86::VALIGNDZrrik, X86::VALIGNDZrmik, 0 },
+ { X86::VALIGNQZrrik, X86::VALIGNQZrmik, 0 },
+ { X86::VANDNPDZrrk, X86::VANDNPDZrmk, 0 },
+ { X86::VANDNPSZrrk, X86::VANDNPSZrmk, 0 },
+ { X86::VANDPDZrrk, X86::VANDPDZrmk, 0 },
+ { X86::VANDPSZrrk, X86::VANDPSZrmk, 0 },
{ X86::VDIVPDZrrk, X86::VDIVPDZrmk, 0 },
- { X86::VMINPSZrrk, X86::VMINPSZrmk, 0 },
- { X86::VMINPDZrrk, X86::VMINPDZrmk, 0 },
- { X86::VMAXPSZrrk, X86::VMAXPSZrmk, 0 },
+ { X86::VDIVPSZrrk, X86::VDIVPSZrmk, 0 },
+ { X86::VINSERTF32x4Zrrk, X86::VINSERTF32x4Zrmk, 0 },
+ { X86::VINSERTF32x8Zrrk, X86::VINSERTF32x8Zrmk, 0 },
+ { X86::VINSERTF64x2Zrrk, X86::VINSERTF64x2Zrmk, 0 },
+ { X86::VINSERTF64x4Zrrk, X86::VINSERTF64x4Zrmk, 0 },
+ { X86::VINSERTI32x4Zrrk, X86::VINSERTI32x4Zrmk, 0 },
+ { X86::VINSERTI32x8Zrrk, X86::VINSERTI32x8Zrmk, 0 },
+ { X86::VINSERTI64x2Zrrk, X86::VINSERTI64x2Zrmk, 0 },
+ { X86::VINSERTI64x4Zrrk, X86::VINSERTI64x4Zrmk, 0 },
+ { X86::VMAXCPDZrrk, X86::VMAXCPDZrmk, 0 },
+ { X86::VMAXCPSZrrk, X86::VMAXCPSZrmk, 0 },
{ X86::VMAXPDZrrk, X86::VMAXPDZrmk, 0 },
- // AVX-512{F,VL} foldable instructions 256-bit
- { X86::VADDPSZ256rrk, X86::VADDPSZ256rmk, 0 },
+ { X86::VMAXPSZrrk, X86::VMAXPSZrmk, 0 },
+ { X86::VMINCPDZrrk, X86::VMINCPDZrmk, 0 },
+ { X86::VMINCPSZrrk, X86::VMINCPSZrmk, 0 },
+ { X86::VMINPDZrrk, X86::VMINPDZrmk, 0 },
+ { X86::VMINPSZrrk, X86::VMINPSZrmk, 0 },
+ { X86::VMULPDZrrk, X86::VMULPDZrmk, 0 },
+ { X86::VMULPSZrrk, X86::VMULPSZrmk, 0 },
+ { X86::VORPDZrrk, X86::VORPDZrmk, 0 },
+ { X86::VORPSZrrk, X86::VORPSZrmk, 0 },
+ { X86::VPADDBZrrk, X86::VPADDBZrmk, 0 },
+ { X86::VPADDDZrrk, X86::VPADDDZrmk, 0 },
+ { X86::VPADDQZrrk, X86::VPADDQZrmk, 0 },
+ { X86::VPADDSBZrrk, X86::VPADDSBZrmk, 0 },
+ { X86::VPADDSWZrrk, X86::VPADDSWZrmk, 0 },
+ { X86::VPADDUSBZrrk, X86::VPADDUSBZrmk, 0 },
+ { X86::VPADDUSWZrrk, X86::VPADDUSWZrmk, 0 },
+ { X86::VPADDWZrrk, X86::VPADDWZrmk, 0 },
+ { X86::VPALIGNRZrrik, X86::VPALIGNRZrmik, 0 },
+ { X86::VPANDDZrrk, X86::VPANDDZrmk, 0 },
+ { X86::VPANDNDZrrk, X86::VPANDNDZrmk, 0 },
+ { X86::VPANDNQZrrk, X86::VPANDNQZrmk, 0 },
+ { X86::VPANDQZrrk, X86::VPANDQZrmk, 0 },
+ { X86::VPERMBZrrk, X86::VPERMBZrmk, 0 },
+ { X86::VPERMDZrrk, X86::VPERMDZrmk, 0 },
+ { X86::VPERMI2Brrk, X86::VPERMI2Brmk, 0 },
+ { X86::VPERMI2Drrk, X86::VPERMI2Drmk, 0 },
+ { X86::VPERMI2PSrrk, X86::VPERMI2PSrmk, 0 },
+ { X86::VPERMI2PDrrk, X86::VPERMI2PDrmk, 0 },
+ { X86::VPERMI2Qrrk, X86::VPERMI2Qrmk, 0 },
+ { X86::VPERMI2Wrrk, X86::VPERMI2Wrmk, 0 },
+ { X86::VPERMILPDZrrk, X86::VPERMILPDZrmk, 0 },
+ { X86::VPERMILPSZrrk, X86::VPERMILPSZrmk, 0 },
+ { X86::VPERMPDZrrk, X86::VPERMPDZrmk, 0 },
+ { X86::VPERMPSZrrk, X86::VPERMPSZrmk, 0 },
+ { X86::VPERMQZrrk, X86::VPERMQZrmk, 0 },
+ { X86::VPERMT2Brrk, X86::VPERMT2Brmk, 0 },
+ { X86::VPERMT2Drrk, X86::VPERMT2Drmk, 0 },
+ { X86::VPERMT2PSrrk, X86::VPERMT2PSrmk, 0 },
+ { X86::VPERMT2PDrrk, X86::VPERMT2PDrmk, 0 },
+ { X86::VPERMT2Qrrk, X86::VPERMT2Qrmk, 0 },
+ { X86::VPERMT2Wrrk, X86::VPERMT2Wrmk, 0 },
+ { X86::VPERMWZrrk, X86::VPERMWZrmk, 0 },
+ { X86::VPMADDUBSWZrrk, X86::VPMADDUBSWZrmk, 0 },
+ { X86::VPMADDWDZrrk, X86::VPMADDWDZrmk, 0 },
+ { X86::VPORDZrrk, X86::VPORDZrmk, 0 },
+ { X86::VPORQZrrk, X86::VPORQZrmk, 0 },
+ { X86::VPSHUFBZrrk, X86::VPSHUFBZrmk, 0 },
+ { X86::VPSUBBZrrk, X86::VPSUBBZrmk, 0 },
+ { X86::VPSUBDZrrk, X86::VPSUBDZrmk, 0 },
+ { X86::VPSUBQZrrk, X86::VPSUBQZrmk, 0 },
+ { X86::VPSUBSBZrrk, X86::VPSUBSBZrmk, 0 },
+ { X86::VPSUBSWZrrk, X86::VPSUBSWZrmk, 0 },
+ { X86::VPSUBUSBZrrk, X86::VPSUBUSBZrmk, 0 },
+ { X86::VPSUBUSWZrrk, X86::VPSUBUSWZrmk, 0 },
+ { X86::VPTERNLOGDZrrik, X86::VPTERNLOGDZrmik, 0 },
+ { X86::VPTERNLOGQZrrik, X86::VPTERNLOGQZrmik, 0 },
+ { X86::VPUNPCKHBWZrrk, X86::VPUNPCKHBWZrmk, 0 },
+ { X86::VPUNPCKHDQZrrk, X86::VPUNPCKHDQZrmk, 0 },
+ { X86::VPUNPCKHQDQZrrk, X86::VPUNPCKHQDQZrmk, 0 },
+ { X86::VPUNPCKHWDZrrk, X86::VPUNPCKHWDZrmk, 0 },
+ { X86::VPUNPCKLBWZrrk, X86::VPUNPCKLBWZrmk, 0 },
+ { X86::VPUNPCKLDQZrrk, X86::VPUNPCKLDQZrmk, 0 },
+ { X86::VPUNPCKLQDQZrrk, X86::VPUNPCKLQDQZrmk, 0 },
+ { X86::VPUNPCKLWDZrrk, X86::VPUNPCKLWDZrmk, 0 },
+ { X86::VPXORDZrrk, X86::VPXORDZrmk, 0 },
+ { X86::VPXORQZrrk, X86::VPXORQZrmk, 0 },
+ { X86::VSUBPDZrrk, X86::VSUBPDZrmk, 0 },
+ { X86::VSUBPSZrrk, X86::VSUBPSZrmk, 0 },
+ { X86::VUNPCKHPDZrrk, X86::VUNPCKHPDZrmk, 0 },
+ { X86::VUNPCKHPSZrrk, X86::VUNPCKHPSZrmk, 0 },
+ { X86::VUNPCKLPDZrrk, X86::VUNPCKLPDZrmk, 0 },
+ { X86::VUNPCKLPSZrrk, X86::VUNPCKLPSZrmk, 0 },
+ { X86::VXORPDZrrk, X86::VXORPDZrmk, 0 },
+ { X86::VXORPSZrrk, X86::VXORPSZrmk, 0 },
+
+ // AVX-512{F,VL} foldable masked instructions 256-bit
{ X86::VADDPDZ256rrk, X86::VADDPDZ256rmk, 0 },
- { X86::VSUBPSZ256rrk, X86::VSUBPSZ256rmk, 0 },
- { X86::VSUBPDZ256rrk, X86::VSUBPDZ256rmk, 0 },
- { X86::VMULPSZ256rrk, X86::VMULPSZ256rmk, 0 },
- { X86::VMULPDZ256rrk, X86::VMULPDZ256rmk, 0 },
- { X86::VDIVPSZ256rrk, X86::VDIVPSZ256rmk, 0 },
+ { X86::VADDPSZ256rrk, X86::VADDPSZ256rmk, 0 },
+ { X86::VALIGNDZ256rrik, X86::VALIGNDZ256rmik, 0 },
+ { X86::VALIGNQZ256rrik, X86::VALIGNQZ256rmik, 0 },
+ { X86::VANDNPDZ256rrk, X86::VANDNPDZ256rmk, 0 },
+ { X86::VANDNPSZ256rrk, X86::VANDNPSZ256rmk, 0 },
+ { X86::VANDPDZ256rrk, X86::VANDPDZ256rmk, 0 },
+ { X86::VANDPSZ256rrk, X86::VANDPSZ256rmk, 0 },
{ X86::VDIVPDZ256rrk, X86::VDIVPDZ256rmk, 0 },
- { X86::VMINPSZ256rrk, X86::VMINPSZ256rmk, 0 },
- { X86::VMINPDZ256rrk, X86::VMINPDZ256rmk, 0 },
- { X86::VMAXPSZ256rrk, X86::VMAXPSZ256rmk, 0 },
+ { X86::VDIVPSZ256rrk, X86::VDIVPSZ256rmk, 0 },
+ { X86::VINSERTF32x4Z256rrk,X86::VINSERTF32x4Z256rmk, 0 },
+ { X86::VINSERTF64x2Z256rrk,X86::VINSERTF64x2Z256rmk, 0 },
+ { X86::VINSERTI32x4Z256rrk,X86::VINSERTI32x4Z256rmk, 0 },
+ { X86::VINSERTI64x2Z256rrk,X86::VINSERTI64x2Z256rmk, 0 },
+ { X86::VMAXCPDZ256rrk, X86::VMAXCPDZ256rmk, 0 },
+ { X86::VMAXCPSZ256rrk, X86::VMAXCPSZ256rmk, 0 },
{ X86::VMAXPDZ256rrk, X86::VMAXPDZ256rmk, 0 },
+ { X86::VMAXPSZ256rrk, X86::VMAXPSZ256rmk, 0 },
+ { X86::VMINCPDZ256rrk, X86::VMINCPDZ256rmk, 0 },
+ { X86::VMINCPSZ256rrk, X86::VMINCPSZ256rmk, 0 },
+ { X86::VMINPDZ256rrk, X86::VMINPDZ256rmk, 0 },
+ { X86::VMINPSZ256rrk, X86::VMINPSZ256rmk, 0 },
+ { X86::VMULPDZ256rrk, X86::VMULPDZ256rmk, 0 },
+ { X86::VMULPSZ256rrk, X86::VMULPSZ256rmk, 0 },
+ { X86::VORPDZ256rrk, X86::VORPDZ256rmk, 0 },
+ { X86::VORPSZ256rrk, X86::VORPSZ256rmk, 0 },
+ { X86::VPADDBZ256rrk, X86::VPADDBZ256rmk, 0 },
+ { X86::VPADDDZ256rrk, X86::VPADDDZ256rmk, 0 },
+ { X86::VPADDQZ256rrk, X86::VPADDQZ256rmk, 0 },
+ { X86::VPADDSBZ256rrk, X86::VPADDSBZ256rmk, 0 },
+ { X86::VPADDSWZ256rrk, X86::VPADDSWZ256rmk, 0 },
+ { X86::VPADDUSBZ256rrk, X86::VPADDUSBZ256rmk, 0 },
+ { X86::VPADDUSWZ256rrk, X86::VPADDUSWZ256rmk, 0 },
+ { X86::VPADDWZ256rrk, X86::VPADDWZ256rmk, 0 },
+ { X86::VPALIGNRZ256rrik, X86::VPALIGNRZ256rmik, 0 },
+ { X86::VPANDDZ256rrk, X86::VPANDDZ256rmk, 0 },
+ { X86::VPANDNDZ256rrk, X86::VPANDNDZ256rmk, 0 },
+ { X86::VPANDNQZ256rrk, X86::VPANDNQZ256rmk, 0 },
+ { X86::VPANDQZ256rrk, X86::VPANDQZ256rmk, 0 },
+ { X86::VPERMBZ256rrk, X86::VPERMBZ256rmk, 0 },
+ { X86::VPERMDZ256rrk, X86::VPERMDZ256rmk, 0 },
+ { X86::VPERMI2B256rrk, X86::VPERMI2B256rmk, 0 },
+ { X86::VPERMI2D256rrk, X86::VPERMI2D256rmk, 0 },
+ { X86::VPERMI2PD256rrk, X86::VPERMI2PD256rmk, 0 },
+ { X86::VPERMI2PS256rrk, X86::VPERMI2PS256rmk, 0 },
+ { X86::VPERMI2Q256rrk, X86::VPERMI2Q256rmk, 0 },
+ { X86::VPERMI2W256rrk, X86::VPERMI2W256rmk, 0 },
+ { X86::VPERMILPDZ256rrk, X86::VPERMILPDZ256rmk, 0 },
+ { X86::VPERMILPSZ256rrk, X86::VPERMILPSZ256rmk, 0 },
+ { X86::VPERMPDZ256rrk, X86::VPERMPDZ256rmk, 0 },
+ { X86::VPERMPSZ256rrk, X86::VPERMPSZ256rmk, 0 },
+ { X86::VPERMQZ256rrk, X86::VPERMQZ256rmk, 0 },
+ { X86::VPERMT2B256rrk, X86::VPERMT2B256rmk, 0 },
+ { X86::VPERMT2D256rrk, X86::VPERMT2D256rmk, 0 },
+ { X86::VPERMT2PD256rrk, X86::VPERMT2PD256rmk, 0 },
+ { X86::VPERMT2PS256rrk, X86::VPERMT2PS256rmk, 0 },
+ { X86::VPERMT2Q256rrk, X86::VPERMT2Q256rmk, 0 },
+ { X86::VPERMT2W256rrk, X86::VPERMT2W256rmk, 0 },
+ { X86::VPERMWZ256rrk, X86::VPERMWZ256rmk, 0 },
+ { X86::VPMADDUBSWZ256rrk, X86::VPMADDUBSWZ256rmk, 0 },
+ { X86::VPMADDWDZ256rrk, X86::VPMADDWDZ256rmk, 0 },
+ { X86::VPORDZ256rrk, X86::VPORDZ256rmk, 0 },
+ { X86::VPORQZ256rrk, X86::VPORQZ256rmk, 0 },
+ { X86::VPSHUFBZ256rrk, X86::VPSHUFBZ256rmk, 0 },
+ { X86::VPSUBBZ256rrk, X86::VPSUBBZ256rmk, 0 },
+ { X86::VPSUBDZ256rrk, X86::VPSUBDZ256rmk, 0 },
+ { X86::VPSUBQZ256rrk, X86::VPSUBQZ256rmk, 0 },
+ { X86::VPSUBSBZ256rrk, X86::VPSUBSBZ256rmk, 0 },
+ { X86::VPSUBSWZ256rrk, X86::VPSUBSWZ256rmk, 0 },
+ { X86::VPSUBUSBZ256rrk, X86::VPSUBUSBZ256rmk, 0 },
+ { X86::VPSUBUSWZ256rrk, X86::VPSUBUSWZ256rmk, 0 },
+ { X86::VPSUBWZ256rrk, X86::VPSUBWZ256rmk, 0 },
+ { X86::VPTERNLOGDZ256rrik, X86::VPTERNLOGDZ256rmik, 0 },
+ { X86::VPTERNLOGQZ256rrik, X86::VPTERNLOGQZ256rmik, 0 },
+ { X86::VPUNPCKHBWZ256rrk, X86::VPUNPCKHBWZ256rmk, 0 },
+ { X86::VPUNPCKHDQZ256rrk, X86::VPUNPCKHDQZ256rmk, 0 },
+ { X86::VPUNPCKHQDQZ256rrk, X86::VPUNPCKHQDQZ256rmk, 0 },
+ { X86::VPUNPCKHWDZ256rrk, X86::VPUNPCKHWDZ256rmk, 0 },
+ { X86::VPUNPCKLBWZ256rrk, X86::VPUNPCKLBWZ256rmk, 0 },
+ { X86::VPUNPCKLDQZ256rrk, X86::VPUNPCKLDQZ256rmk, 0 },
+ { X86::VPUNPCKLQDQZ256rrk, X86::VPUNPCKLQDQZ256rmk, 0 },
+ { X86::VPUNPCKLWDZ256rrk, X86::VPUNPCKLWDZ256rmk, 0 },
+ { X86::VPXORDZ256rrk, X86::VPXORDZ256rmk, 0 },
+ { X86::VPXORQZ256rrk, X86::VPXORQZ256rmk, 0 },
+ { X86::VSUBPDZ256rrk, X86::VSUBPDZ256rmk, 0 },
+ { X86::VSUBPSZ256rrk, X86::VSUBPSZ256rmk, 0 },
+ { X86::VUNPCKHPDZ256rrk, X86::VUNPCKHPDZ256rmk, 0 },
+ { X86::VUNPCKHPSZ256rrk, X86::VUNPCKHPSZ256rmk, 0 },
+ { X86::VUNPCKLPDZ256rrk, X86::VUNPCKLPDZ256rmk, 0 },
+ { X86::VUNPCKLPSZ256rrk, X86::VUNPCKLPSZ256rmk, 0 },
+ { X86::VXORPDZ256rrk, X86::VXORPDZ256rmk, 0 },
+ { X86::VXORPSZ256rrk, X86::VXORPSZ256rmk, 0 },
+
// AVX-512{F,VL} foldable instructions 128-bit
- { X86::VADDPSZ128rrk, X86::VADDPSZ128rmk, 0 },
{ X86::VADDPDZ128rrk, X86::VADDPDZ128rmk, 0 },
- { X86::VSUBPSZ128rrk, X86::VSUBPSZ128rmk, 0 },
- { X86::VSUBPDZ128rrk, X86::VSUBPDZ128rmk, 0 },
- { X86::VMULPSZ128rrk, X86::VMULPSZ128rmk, 0 },
- { X86::VMULPDZ128rrk, X86::VMULPDZ128rmk, 0 },
- { X86::VDIVPSZ128rrk, X86::VDIVPSZ128rmk, 0 },
+ { X86::VADDPSZ128rrk, X86::VADDPSZ128rmk, 0 },
+ { X86::VALIGNDZ128rrik, X86::VALIGNDZ128rmik, 0 },
+ { X86::VALIGNQZ128rrik, X86::VALIGNQZ128rmik, 0 },
+ { X86::VANDNPDZ128rrk, X86::VANDNPDZ128rmk, 0 },
+ { X86::VANDNPSZ128rrk, X86::VANDNPSZ128rmk, 0 },
+ { X86::VANDPDZ128rrk, X86::VANDPDZ128rmk, 0 },
+ { X86::VANDPSZ128rrk, X86::VANDPSZ128rmk, 0 },
{ X86::VDIVPDZ128rrk, X86::VDIVPDZ128rmk, 0 },
- { X86::VMINPSZ128rrk, X86::VMINPSZ128rmk, 0 },
- { X86::VMINPDZ128rrk, X86::VMINPDZ128rmk, 0 },
+ { X86::VDIVPSZ128rrk, X86::VDIVPSZ128rmk, 0 },
+ { X86::VMAXCPDZ128rrk, X86::VMAXCPDZ128rmk, 0 },
+ { X86::VMAXCPSZ128rrk, X86::VMAXCPSZ128rmk, 0 },
+ { X86::VMAXPDZ128rrk, X86::VMAXPDZ128rmk, 0 },
{ X86::VMAXPSZ128rrk, X86::VMAXPSZ128rmk, 0 },
- { X86::VMAXPDZ128rrk, X86::VMAXPDZ128rmk, 0 }
+ { X86::VMINCPDZ128rrk, X86::VMINCPDZ128rmk, 0 },
+ { X86::VMINCPSZ128rrk, X86::VMINCPSZ128rmk, 0 },
+ { X86::VMINPDZ128rrk, X86::VMINPDZ128rmk, 0 },
+ { X86::VMINPSZ128rrk, X86::VMINPSZ128rmk, 0 },
+ { X86::VMULPDZ128rrk, X86::VMULPDZ128rmk, 0 },
+ { X86::VMULPSZ128rrk, X86::VMULPSZ128rmk, 0 },
+ { X86::VORPDZ128rrk, X86::VORPDZ128rmk, 0 },
+ { X86::VORPSZ128rrk, X86::VORPSZ128rmk, 0 },
+ { X86::VPADDBZ128rrk, X86::VPADDBZ128rmk, 0 },
+ { X86::VPADDDZ128rrk, X86::VPADDDZ128rmk, 0 },
+ { X86::VPADDQZ128rrk, X86::VPADDQZ128rmk, 0 },
+ { X86::VPADDSBZ128rrk, X86::VPADDSBZ128rmk, 0 },
+ { X86::VPADDSWZ128rrk, X86::VPADDSWZ128rmk, 0 },
+ { X86::VPADDUSBZ128rrk, X86::VPADDUSBZ128rmk, 0 },
+ { X86::VPADDUSWZ128rrk, X86::VPADDUSWZ128rmk, 0 },
+ { X86::VPADDWZ128rrk, X86::VPADDWZ128rmk, 0 },
+ { X86::VPALIGNRZ128rrik, X86::VPALIGNRZ128rmik, 0 },
+ { X86::VPANDDZ128rrk, X86::VPANDDZ128rmk, 0 },
+ { X86::VPANDNDZ128rrk, X86::VPANDNDZ128rmk, 0 },
+ { X86::VPANDNQZ128rrk, X86::VPANDNQZ128rmk, 0 },
+ { X86::VPANDQZ128rrk, X86::VPANDQZ128rmk, 0 },
+ { X86::VPERMBZ128rrk, X86::VPERMBZ128rmk, 0 },
+ { X86::VPERMI2B128rrk, X86::VPERMI2B128rmk, 0 },
+ { X86::VPERMI2D128rrk, X86::VPERMI2D128rmk, 0 },
+ { X86::VPERMI2PD128rrk, X86::VPERMI2PD128rmk, 0 },
+ { X86::VPERMI2PS128rrk, X86::VPERMI2PS128rmk, 0 },
+ { X86::VPERMI2Q128rrk, X86::VPERMI2Q128rmk, 0 },
+ { X86::VPERMI2W128rrk, X86::VPERMI2W128rmk, 0 },
+ { X86::VPERMILPDZ128rrk, X86::VPERMILPDZ128rmk, 0 },
+ { X86::VPERMILPSZ128rrk, X86::VPERMILPSZ128rmk, 0 },
+ { X86::VPERMT2B128rrk, X86::VPERMT2B128rmk, 0 },
+ { X86::VPERMT2D128rrk, X86::VPERMT2D128rmk, 0 },
+ { X86::VPERMT2PD128rrk, X86::VPERMT2PD128rmk, 0 },
+ { X86::VPERMT2PS128rrk, X86::VPERMT2PS128rmk, 0 },
+ { X86::VPERMT2Q128rrk, X86::VPERMT2Q128rmk, 0 },
+ { X86::VPERMT2W128rrk, X86::VPERMT2W128rmk, 0 },
+ { X86::VPERMWZ128rrk, X86::VPERMWZ128rmk, 0 },
+ { X86::VPMADDUBSWZ128rrk, X86::VPMADDUBSWZ128rmk, 0 },
+ { X86::VPMADDWDZ128rrk, X86::VPMADDWDZ128rmk, 0 },
+ { X86::VPORDZ128rrk, X86::VPORDZ128rmk, 0 },
+ { X86::VPORQZ128rrk, X86::VPORQZ128rmk, 0 },
+ { X86::VPSHUFBZ128rrk, X86::VPSHUFBZ128rmk, 0 },
+ { X86::VPSUBBZ128rrk, X86::VPSUBBZ128rmk, 0 },
+ { X86::VPSUBDZ128rrk, X86::VPSUBDZ128rmk, 0 },
+ { X86::VPSUBQZ128rrk, X86::VPSUBQZ128rmk, 0 },
+ { X86::VPSUBSBZ128rrk, X86::VPSUBSBZ128rmk, 0 },
+ { X86::VPSUBSWZ128rrk, X86::VPSUBSWZ128rmk, 0 },
+ { X86::VPSUBUSBZ128rrk, X86::VPSUBUSBZ128rmk, 0 },
+ { X86::VPSUBUSWZ128rrk, X86::VPSUBUSWZ128rmk, 0 },
+ { X86::VPSUBWZ128rrk, X86::VPSUBWZ128rmk, 0 },
+ { X86::VPTERNLOGDZ128rrik, X86::VPTERNLOGDZ128rmik, 0 },
+ { X86::VPTERNLOGQZ128rrik, X86::VPTERNLOGQZ128rmik, 0 },
+ { X86::VPUNPCKHBWZ128rrk, X86::VPUNPCKHBWZ128rmk, 0 },
+ { X86::VPUNPCKHDQZ128rrk, X86::VPUNPCKHDQZ128rmk, 0 },
+ { X86::VPUNPCKHQDQZ128rrk, X86::VPUNPCKHQDQZ128rmk, 0 },
+ { X86::VPUNPCKHWDZ128rrk, X86::VPUNPCKHWDZ128rmk, 0 },
+ { X86::VPUNPCKLBWZ128rrk, X86::VPUNPCKLBWZ128rmk, 0 },
+ { X86::VPUNPCKLDQZ128rrk, X86::VPUNPCKLDQZ128rmk, 0 },
+ { X86::VPUNPCKLQDQZ128rrk, X86::VPUNPCKLQDQZ128rmk, 0 },
+ { X86::VPUNPCKLWDZ128rrk, X86::VPUNPCKLWDZ128rmk, 0 },
+ { X86::VPXORDZ128rrk, X86::VPXORDZ128rmk, 0 },
+ { X86::VPXORQZ128rrk, X86::VPXORQZ128rmk, 0 },
+ { X86::VSUBPDZ128rrk, X86::VSUBPDZ128rmk, 0 },
+ { X86::VSUBPSZ128rrk, X86::VSUBPSZ128rmk, 0 },
+ { X86::VUNPCKHPDZ128rrk, X86::VUNPCKHPDZ128rmk, 0 },
+ { X86::VUNPCKHPSZ128rrk, X86::VUNPCKHPSZ128rmk, 0 },
+ { X86::VUNPCKLPDZ128rrk, X86::VUNPCKLPDZ128rmk, 0 },
+ { X86::VUNPCKLPSZ128rrk, X86::VUNPCKLPSZ128rmk, 0 },
+ { X86::VXORPDZ128rrk, X86::VXORPDZ128rmk, 0 },
+ { X86::VXORPSZ128rrk, X86::VXORPSZ128rmk, 0 },
+
+ // 512-bit three source instructions with zero masking.
+ { X86::VPERMI2Brrkz, X86::VPERMI2Brmkz, 0 },
+ { X86::VPERMI2Drrkz, X86::VPERMI2Drmkz, 0 },
+ { X86::VPERMI2PSrrkz, X86::VPERMI2PSrmkz, 0 },
+ { X86::VPERMI2PDrrkz, X86::VPERMI2PDrmkz, 0 },
+ { X86::VPERMI2Qrrkz, X86::VPERMI2Qrmkz, 0 },
+ { X86::VPERMI2Wrrkz, X86::VPERMI2Wrmkz, 0 },
+ { X86::VPERMT2Brrkz, X86::VPERMT2Brmkz, 0 },
+ { X86::VPERMT2Drrkz, X86::VPERMT2Drmkz, 0 },
+ { X86::VPERMT2PSrrkz, X86::VPERMT2PSrmkz, 0 },
+ { X86::VPERMT2PDrrkz, X86::VPERMT2PDrmkz, 0 },
+ { X86::VPERMT2Qrrkz, X86::VPERMT2Qrmkz, 0 },
+ { X86::VPERMT2Wrrkz, X86::VPERMT2Wrmkz, 0 },
+ { X86::VPTERNLOGDZrrikz, X86::VPTERNLOGDZrmikz, 0 },
+ { X86::VPTERNLOGQZrrikz, X86::VPTERNLOGQZrmikz, 0 },
+
+ // 256-bit three source instructions with zero masking.
+ { X86::VPERMI2B256rrkz, X86::VPERMI2B256rmkz, 0 },
+ { X86::VPERMI2D256rrkz, X86::VPERMI2D256rmkz, 0 },
+ { X86::VPERMI2PD256rrkz, X86::VPERMI2PD256rmkz, 0 },
+ { X86::VPERMI2PS256rrkz, X86::VPERMI2PS256rmkz, 0 },
+ { X86::VPERMI2Q256rrkz, X86::VPERMI2Q256rmkz, 0 },
+ { X86::VPERMI2W256rrkz, X86::VPERMI2W256rmkz, 0 },
+ { X86::VPERMT2B256rrkz, X86::VPERMT2B256rmkz, 0 },
+ { X86::VPERMT2D256rrkz, X86::VPERMT2D256rmkz, 0 },
+ { X86::VPERMT2PD256rrkz, X86::VPERMT2PD256rmkz, 0 },
+ { X86::VPERMT2PS256rrkz, X86::VPERMT2PS256rmkz, 0 },
+ { X86::VPERMT2Q256rrkz, X86::VPERMT2Q256rmkz, 0 },
+ { X86::VPERMT2W256rrkz, X86::VPERMT2W256rmkz, 0 },
+ { X86::VPTERNLOGDZ256rrikz,X86::VPTERNLOGDZ256rmikz, 0 },
+ { X86::VPTERNLOGQZ256rrikz,X86::VPTERNLOGQZ256rmikz, 0 },
+
+ // 128-bit three source instructions with zero masking.
+ { X86::VPERMI2B128rrkz, X86::VPERMI2B128rmkz, 0 },
+ { X86::VPERMI2D128rrkz, X86::VPERMI2D128rmkz, 0 },
+ { X86::VPERMI2PD128rrkz, X86::VPERMI2PD128rmkz, 0 },
+ { X86::VPERMI2PS128rrkz, X86::VPERMI2PS128rmkz, 0 },
+ { X86::VPERMI2Q128rrkz, X86::VPERMI2Q128rmkz, 0 },
+ { X86::VPERMI2W128rrkz, X86::VPERMI2W128rmkz, 0 },
+ { X86::VPERMT2B128rrkz, X86::VPERMT2B128rmkz, 0 },
+ { X86::VPERMT2D128rrkz, X86::VPERMT2D128rmkz, 0 },
+ { X86::VPERMT2PD128rrkz, X86::VPERMT2PD128rmkz, 0 },
+ { X86::VPERMT2PS128rrkz, X86::VPERMT2PS128rmkz, 0 },
+ { X86::VPERMT2Q128rrkz, X86::VPERMT2Q128rmkz, 0 },
+ { X86::VPERMT2W128rrkz, X86::VPERMT2W128rmkz, 0 },
+ { X86::VPTERNLOGDZ128rrikz,X86::VPTERNLOGDZ128rmikz, 0 },
+ { X86::VPTERNLOGQZ128rrikz,X86::VPTERNLOGQZ128rmikz, 0 },
};
for (X86MemoryFoldTableEntry Entry : MemoryFoldTable4) {
@@ -2057,21 +2980,35 @@ X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
// Index 4, folded load
Entry.Flags | TB_INDEX_4 | TB_FOLDED_LOAD);
}
+ for (I = X86InstrFMA3Info::rm_begin(); I != E; ++I) {
+ if (I.getGroup()->isKMasked()) {
+ // Intrinsics need to pass TB_NO_REVERSE.
+ if (I.getGroup()->isIntrinsic()) {
+ AddTableEntry(RegOp2MemOpTable4, MemOp2RegOpTable,
+ I.getRegOpcode(), I.getMemOpcode(),
+ TB_ALIGN_NONE | TB_INDEX_4 | TB_FOLDED_LOAD | TB_NO_REVERSE);
+ } else {
+ AddTableEntry(RegOp2MemOpTable4, MemOp2RegOpTable,
+ I.getRegOpcode(), I.getMemOpcode(),
+ TB_ALIGN_NONE | TB_INDEX_4 | TB_FOLDED_LOAD);
+ }
+ }
+ }
}
void
X86InstrInfo::AddTableEntry(RegOp2MemOpTableType &R2MTable,
MemOp2RegOpTableType &M2RTable,
uint16_t RegOp, uint16_t MemOp, uint16_t Flags) {
- if ((Flags & TB_NO_FORWARD) == 0) {
- assert(!R2MTable.count(RegOp) && "Duplicate entry!");
- R2MTable[RegOp] = std::make_pair(MemOp, Flags);
- }
- if ((Flags & TB_NO_REVERSE) == 0) {
- assert(!M2RTable.count(MemOp) &&
- "Duplicated entries in unfolding maps?");
- M2RTable[MemOp] = std::make_pair(RegOp, Flags);
- }
+ if ((Flags & TB_NO_FORWARD) == 0) {
+ assert(!R2MTable.count(RegOp) && "Duplicate entry!");
+ R2MTable[RegOp] = std::make_pair(MemOp, Flags);
+ }
+ if ((Flags & TB_NO_REVERSE) == 0) {
+ assert(!M2RTable.count(MemOp) &&
+ "Duplicated entries in unfolding maps?");
+ M2RTable[MemOp] = std::make_pair(RegOp, Flags);
+ }
}
bool
@@ -2235,9 +3172,13 @@ static bool isFrameLoadOpcode(int Opcode) {
case X86::VMOVAPSZrm:
case X86::VMOVAPSZ128rm:
case X86::VMOVAPSZ256rm:
+ case X86::VMOVAPSZ128rm_NOVLX:
+ case X86::VMOVAPSZ256rm_NOVLX:
case X86::VMOVUPSZrm:
case X86::VMOVUPSZ128rm:
case X86::VMOVUPSZ256rm:
+ case X86::VMOVUPSZ128rm_NOVLX:
+ case X86::VMOVUPSZ256rm_NOVLX:
case X86::VMOVAPDZrm:
case X86::VMOVAPDZ128rm:
case X86::VMOVAPDZ256rm:
@@ -2305,9 +3246,13 @@ static bool isFrameStoreOpcode(int Opcode) {
case X86::VMOVUPSZmr:
case X86::VMOVUPSZ128mr:
case X86::VMOVUPSZ256mr:
+ case X86::VMOVUPSZ128mr_NOVLX:
+ case X86::VMOVUPSZ256mr_NOVLX:
case X86::VMOVAPSZmr:
case X86::VMOVAPSZ128mr:
case X86::VMOVAPSZ256mr:
+ case X86::VMOVAPSZ128mr_NOVLX:
+ case X86::VMOVAPSZ256mr_NOVLX:
case X86::VMOVUPDZmr:
case X86::VMOVUPDZ128mr:
case X86::VMOVUPDZ256mr:
@@ -2409,6 +3354,7 @@ bool X86InstrInfo::isReallyTriviallyReMaterializable(const MachineInstr &MI,
switch (MI.getOpcode()) {
default: break;
case X86::MOV8rm:
+ case X86::MOV8rm_NOREX:
case X86::MOV16rm:
case X86::MOV32rm:
case X86::MOV64rm:
@@ -2418,6 +3364,7 @@ bool X86InstrInfo::isReallyTriviallyReMaterializable(const MachineInstr &MI,
case X86::MOVAPSrm:
case X86::MOVUPSrm:
case X86::MOVAPDrm:
+ case X86::MOVUPDrm:
case X86::MOVDQArm:
case X86::MOVDQUrm:
case X86::VMOVSSrm:
@@ -2425,25 +3372,27 @@ bool X86InstrInfo::isReallyTriviallyReMaterializable(const MachineInstr &MI,
case X86::VMOVAPSrm:
case X86::VMOVUPSrm:
case X86::VMOVAPDrm:
+ case X86::VMOVUPDrm:
case X86::VMOVDQArm:
case X86::VMOVDQUrm:
case X86::VMOVAPSYrm:
case X86::VMOVUPSYrm:
case X86::VMOVAPDYrm:
+ case X86::VMOVUPDYrm:
case X86::VMOVDQAYrm:
case X86::VMOVDQUYrm:
case X86::MMX_MOVD64rm:
case X86::MMX_MOVQ64rm:
- case X86::FsVMOVAPSrm:
- case X86::FsVMOVAPDrm:
- case X86::FsMOVAPSrm:
- case X86::FsMOVAPDrm:
// AVX-512
+ case X86::VMOVSSZrm:
+ case X86::VMOVSDZrm:
case X86::VMOVAPDZ128rm:
case X86::VMOVAPDZ256rm:
case X86::VMOVAPDZrm:
case X86::VMOVAPSZ128rm:
case X86::VMOVAPSZ256rm:
+ case X86::VMOVAPSZ128rm_NOVLX:
+ case X86::VMOVAPSZ256rm_NOVLX:
case X86::VMOVAPSZrm:
case X86::VMOVDQA32Z128rm:
case X86::VMOVDQA32Z256rm:
@@ -2463,15 +3412,20 @@ bool X86InstrInfo::isReallyTriviallyReMaterializable(const MachineInstr &MI,
case X86::VMOVDQU8Z128rm:
case X86::VMOVDQU8Z256rm:
case X86::VMOVDQU8Zrm:
+ case X86::VMOVUPDZ128rm:
+ case X86::VMOVUPDZ256rm:
+ case X86::VMOVUPDZrm:
case X86::VMOVUPSZ128rm:
case X86::VMOVUPSZ256rm:
+ case X86::VMOVUPSZ128rm_NOVLX:
+ case X86::VMOVUPSZ256rm_NOVLX:
case X86::VMOVUPSZrm: {
// Loads from constant pools are trivially rematerializable.
if (MI.getOperand(1 + X86::AddrBaseReg).isReg() &&
MI.getOperand(1 + X86::AddrScaleAmt).isImm() &&
MI.getOperand(1 + X86::AddrIndexReg).isReg() &&
MI.getOperand(1 + X86::AddrIndexReg).getReg() == 0 &&
- MI.isInvariantLoad(AA)) {
+ MI.isDereferenceableInvariantLoad(AA)) {
unsigned BaseReg = MI.getOperand(1 + X86::AddrBaseReg).getReg();
if (BaseReg == 0 || BaseReg == X86::RIP)
return true;
@@ -2694,24 +3648,8 @@ bool X86InstrInfo::classifyLEAReg(MachineInstr &MI, const MachineOperand &Src,
ImplicitOp.setImplicit();
NewSrc = getX86SubSuperRegister(Src.getReg(), 64);
- MachineBasicBlock::LivenessQueryResult LQR =
- MI.getParent()->computeRegisterLiveness(&getRegisterInfo(), NewSrc, MI);
-
- switch (LQR) {
- case MachineBasicBlock::LQR_Unknown:
- // We can't give sane liveness flags to the instruction, abandon LEA
- // formation.
- return false;
- case MachineBasicBlock::LQR_Live:
- isKill = MI.killsRegister(SrcReg);
- isUndef = false;
- break;
- default:
- // The physreg itself is dead, so we have to use it as an <undef>.
- isKill = false;
- isUndef = true;
- break;
- }
+ isKill = Src.isKill();
+ isUndef = Src.isUndef();
} else {
// Virtual register of the wrong class, we have to create a temporary 64-bit
// vreg to feed into the LEA.
@@ -3079,7 +4017,7 @@ X86InstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
NewMI = addOffset(BuildMI(MF, MI.getDebugLoc(), get(X86::LEA64r))
.addOperand(Dest)
.addOperand(Src),
- MI.getOperand(2).getImm());
+ MI.getOperand(2));
break;
case X86::ADD32ri:
case X86::ADD32ri8:
@@ -3102,7 +4040,7 @@ X86InstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
if (ImplicitOp.getReg() != 0)
MIB.addOperand(ImplicitOp);
- NewMI = addOffset(MIB, MI.getOperand(2).getImm());
+ NewMI = addOffset(MIB, MI.getOperand(2));
break;
}
case X86::ADD16ri:
@@ -3116,7 +4054,7 @@ X86InstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
NewMI = addOffset(BuildMI(MF, MI.getDebugLoc(), get(X86::LEA16r))
.addOperand(Dest)
.addOperand(Src),
- MI.getOperand(2).getImm());
+ MI.getOperand(2));
break;
}
@@ -3133,156 +4071,236 @@ X86InstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI,
return NewMI;
}
-/// Returns true if the given instruction opcode is FMA3.
-/// Otherwise, returns false.
-/// The second parameter is optional and is used as the second return from
-/// the function. It is set to true if the given instruction has FMA3 opcode
-/// that is used for lowering of scalar FMA intrinsics, and it is set to false
-/// otherwise.
-static bool isFMA3(unsigned Opcode, bool *IsIntrinsic = nullptr) {
- if (IsIntrinsic)
- *IsIntrinsic = false;
+/// This determines which of three possible cases of a three source commute
+/// the source indexes correspond to taking into account any mask operands.
+/// All prevents commuting a passthru operand. Returns -1 if the commute isn't
+/// possible.
+/// Case 0 - Possible to commute the first and second operands.
+/// Case 1 - Possible to commute the first and third operands.
+/// Case 2 - Possible to commute the second and third operands.
+static int getThreeSrcCommuteCase(uint64_t TSFlags, unsigned SrcOpIdx1,
+ unsigned SrcOpIdx2) {
+ // Put the lowest index to SrcOpIdx1 to simplify the checks below.
+ if (SrcOpIdx1 > SrcOpIdx2)
+ std::swap(SrcOpIdx1, SrcOpIdx2);
- switch (Opcode) {
- case X86::VFMADDSDr132r: case X86::VFMADDSDr132m:
- case X86::VFMADDSSr132r: case X86::VFMADDSSr132m:
- case X86::VFMSUBSDr132r: case X86::VFMSUBSDr132m:
- case X86::VFMSUBSSr132r: case X86::VFMSUBSSr132m:
- case X86::VFNMADDSDr132r: case X86::VFNMADDSDr132m:
- case X86::VFNMADDSSr132r: case X86::VFNMADDSSr132m:
- case X86::VFNMSUBSDr132r: case X86::VFNMSUBSDr132m:
- case X86::VFNMSUBSSr132r: case X86::VFNMSUBSSr132m:
-
- case X86::VFMADDSDr213r: case X86::VFMADDSDr213m:
- case X86::VFMADDSSr213r: case X86::VFMADDSSr213m:
- case X86::VFMSUBSDr213r: case X86::VFMSUBSDr213m:
- case X86::VFMSUBSSr213r: case X86::VFMSUBSSr213m:
- case X86::VFNMADDSDr213r: case X86::VFNMADDSDr213m:
- case X86::VFNMADDSSr213r: case X86::VFNMADDSSr213m:
- case X86::VFNMSUBSDr213r: case X86::VFNMSUBSDr213m:
- case X86::VFNMSUBSSr213r: case X86::VFNMSUBSSr213m:
-
- case X86::VFMADDSDr231r: case X86::VFMADDSDr231m:
- case X86::VFMADDSSr231r: case X86::VFMADDSSr231m:
- case X86::VFMSUBSDr231r: case X86::VFMSUBSDr231m:
- case X86::VFMSUBSSr231r: case X86::VFMSUBSSr231m:
- case X86::VFNMADDSDr231r: case X86::VFNMADDSDr231m:
- case X86::VFNMADDSSr231r: case X86::VFNMADDSSr231m:
- case X86::VFNMSUBSDr231r: case X86::VFNMSUBSDr231m:
- case X86::VFNMSUBSSr231r: case X86::VFNMSUBSSr231m:
-
- case X86::VFMADDSUBPDr132r: case X86::VFMADDSUBPDr132m:
- case X86::VFMADDSUBPSr132r: case X86::VFMADDSUBPSr132m:
- case X86::VFMSUBADDPDr132r: case X86::VFMSUBADDPDr132m:
- case X86::VFMSUBADDPSr132r: case X86::VFMSUBADDPSr132m:
- case X86::VFMADDSUBPDr132rY: case X86::VFMADDSUBPDr132mY:
- case X86::VFMADDSUBPSr132rY: case X86::VFMADDSUBPSr132mY:
- case X86::VFMSUBADDPDr132rY: case X86::VFMSUBADDPDr132mY:
- case X86::VFMSUBADDPSr132rY: case X86::VFMSUBADDPSr132mY:
-
- case X86::VFMADDPDr132r: case X86::VFMADDPDr132m:
- case X86::VFMADDPSr132r: case X86::VFMADDPSr132m:
- case X86::VFMSUBPDr132r: case X86::VFMSUBPDr132m:
- case X86::VFMSUBPSr132r: case X86::VFMSUBPSr132m:
- case X86::VFNMADDPDr132r: case X86::VFNMADDPDr132m:
- case X86::VFNMADDPSr132r: case X86::VFNMADDPSr132m:
- case X86::VFNMSUBPDr132r: case X86::VFNMSUBPDr132m:
- case X86::VFNMSUBPSr132r: case X86::VFNMSUBPSr132m:
- case X86::VFMADDPDr132rY: case X86::VFMADDPDr132mY:
- case X86::VFMADDPSr132rY: case X86::VFMADDPSr132mY:
- case X86::VFMSUBPDr132rY: case X86::VFMSUBPDr132mY:
- case X86::VFMSUBPSr132rY: case X86::VFMSUBPSr132mY:
- case X86::VFNMADDPDr132rY: case X86::VFNMADDPDr132mY:
- case X86::VFNMADDPSr132rY: case X86::VFNMADDPSr132mY:
- case X86::VFNMSUBPDr132rY: case X86::VFNMSUBPDr132mY:
- case X86::VFNMSUBPSr132rY: case X86::VFNMSUBPSr132mY:
-
- case X86::VFMADDSUBPDr213r: case X86::VFMADDSUBPDr213m:
- case X86::VFMADDSUBPSr213r: case X86::VFMADDSUBPSr213m:
- case X86::VFMSUBADDPDr213r: case X86::VFMSUBADDPDr213m:
- case X86::VFMSUBADDPSr213r: case X86::VFMSUBADDPSr213m:
- case X86::VFMADDSUBPDr213rY: case X86::VFMADDSUBPDr213mY:
- case X86::VFMADDSUBPSr213rY: case X86::VFMADDSUBPSr213mY:
- case X86::VFMSUBADDPDr213rY: case X86::VFMSUBADDPDr213mY:
- case X86::VFMSUBADDPSr213rY: case X86::VFMSUBADDPSr213mY:
-
- case X86::VFMADDPDr213r: case X86::VFMADDPDr213m:
- case X86::VFMADDPSr213r: case X86::VFMADDPSr213m:
- case X86::VFMSUBPDr213r: case X86::VFMSUBPDr213m:
- case X86::VFMSUBPSr213r: case X86::VFMSUBPSr213m:
- case X86::VFNMADDPDr213r: case X86::VFNMADDPDr213m:
- case X86::VFNMADDPSr213r: case X86::VFNMADDPSr213m:
- case X86::VFNMSUBPDr213r: case X86::VFNMSUBPDr213m:
- case X86::VFNMSUBPSr213r: case X86::VFNMSUBPSr213m:
- case X86::VFMADDPDr213rY: case X86::VFMADDPDr213mY:
- case X86::VFMADDPSr213rY: case X86::VFMADDPSr213mY:
- case X86::VFMSUBPDr213rY: case X86::VFMSUBPDr213mY:
- case X86::VFMSUBPSr213rY: case X86::VFMSUBPSr213mY:
- case X86::VFNMADDPDr213rY: case X86::VFNMADDPDr213mY:
- case X86::VFNMADDPSr213rY: case X86::VFNMADDPSr213mY:
- case X86::VFNMSUBPDr213rY: case X86::VFNMSUBPDr213mY:
- case X86::VFNMSUBPSr213rY: case X86::VFNMSUBPSr213mY:
-
- case X86::VFMADDSUBPDr231r: case X86::VFMADDSUBPDr231m:
- case X86::VFMADDSUBPSr231r: case X86::VFMADDSUBPSr231m:
- case X86::VFMSUBADDPDr231r: case X86::VFMSUBADDPDr231m:
- case X86::VFMSUBADDPSr231r: case X86::VFMSUBADDPSr231m:
- case X86::VFMADDSUBPDr231rY: case X86::VFMADDSUBPDr231mY:
- case X86::VFMADDSUBPSr231rY: case X86::VFMADDSUBPSr231mY:
- case X86::VFMSUBADDPDr231rY: case X86::VFMSUBADDPDr231mY:
- case X86::VFMSUBADDPSr231rY: case X86::VFMSUBADDPSr231mY:
-
- case X86::VFMADDPDr231r: case X86::VFMADDPDr231m:
- case X86::VFMADDPSr231r: case X86::VFMADDPSr231m:
- case X86::VFMSUBPDr231r: case X86::VFMSUBPDr231m:
- case X86::VFMSUBPSr231r: case X86::VFMSUBPSr231m:
- case X86::VFNMADDPDr231r: case X86::VFNMADDPDr231m:
- case X86::VFNMADDPSr231r: case X86::VFNMADDPSr231m:
- case X86::VFNMSUBPDr231r: case X86::VFNMSUBPDr231m:
- case X86::VFNMSUBPSr231r: case X86::VFNMSUBPSr231m:
- case X86::VFMADDPDr231rY: case X86::VFMADDPDr231mY:
- case X86::VFMADDPSr231rY: case X86::VFMADDPSr231mY:
- case X86::VFMSUBPDr231rY: case X86::VFMSUBPDr231mY:
- case X86::VFMSUBPSr231rY: case X86::VFMSUBPSr231mY:
- case X86::VFNMADDPDr231rY: case X86::VFNMADDPDr231mY:
- case X86::VFNMADDPSr231rY: case X86::VFNMADDPSr231mY:
- case X86::VFNMSUBPDr231rY: case X86::VFNMSUBPDr231mY:
- case X86::VFNMSUBPSr231rY: case X86::VFNMSUBPSr231mY:
- return true;
+ unsigned Op1 = 1, Op2 = 2, Op3 = 3;
+ if (X86II::isKMasked(TSFlags)) {
+ // The k-mask operand cannot be commuted.
+ if (SrcOpIdx1 == 2)
+ return -1;
+
+ // For k-zero-masked operations it is Ok to commute the first vector
+ // operand.
+ // For regular k-masked operations a conservative choice is done as the
+ // elements of the first vector operand, for which the corresponding bit
+ // in the k-mask operand is set to 0, are copied to the result of the
+ // instruction.
+ // TODO/FIXME: The commute still may be legal if it is known that the
+ // k-mask operand is set to either all ones or all zeroes.
+ // It is also Ok to commute the 1st operand if all users of MI use only
+ // the elements enabled by the k-mask operand. For example,
+ // v4 = VFMADD213PSZrk v1, k, v2, v3; // v1[i] = k[i] ? v2[i]*v1[i]+v3[i]
+ // : v1[i];
+ // VMOVAPSZmrk <mem_addr>, k, v4; // this is the ONLY user of v4 ->
+ // // Ok, to commute v1 in FMADD213PSZrk.
+ if (X86II::isKMergeMasked(TSFlags) && SrcOpIdx1 == Op1)
+ return -1;
+ Op2++;
+ Op3++;
+ }
+
+ if (SrcOpIdx1 == Op1 && SrcOpIdx2 == Op2)
+ return 0;
+ if (SrcOpIdx1 == Op1 && SrcOpIdx2 == Op3)
+ return 1;
+ if (SrcOpIdx1 == Op2 && SrcOpIdx2 == Op3)
+ return 2;
+ return -1;
+}
- case X86::VFMADDSDr132r_Int: case X86::VFMADDSDr132m_Int:
- case X86::VFMADDSSr132r_Int: case X86::VFMADDSSr132m_Int:
- case X86::VFMSUBSDr132r_Int: case X86::VFMSUBSDr132m_Int:
- case X86::VFMSUBSSr132r_Int: case X86::VFMSUBSSr132m_Int:
- case X86::VFNMADDSDr132r_Int: case X86::VFNMADDSDr132m_Int:
- case X86::VFNMADDSSr132r_Int: case X86::VFNMADDSSr132m_Int:
- case X86::VFNMSUBSDr132r_Int: case X86::VFNMSUBSDr132m_Int:
- case X86::VFNMSUBSSr132r_Int: case X86::VFNMSUBSSr132m_Int:
-
- case X86::VFMADDSDr213r_Int: case X86::VFMADDSDr213m_Int:
- case X86::VFMADDSSr213r_Int: case X86::VFMADDSSr213m_Int:
- case X86::VFMSUBSDr213r_Int: case X86::VFMSUBSDr213m_Int:
- case X86::VFMSUBSSr213r_Int: case X86::VFMSUBSSr213m_Int:
- case X86::VFNMADDSDr213r_Int: case X86::VFNMADDSDr213m_Int:
- case X86::VFNMADDSSr213r_Int: case X86::VFNMADDSSr213m_Int:
- case X86::VFNMSUBSDr213r_Int: case X86::VFNMSUBSDr213m_Int:
- case X86::VFNMSUBSSr213r_Int: case X86::VFNMSUBSSr213m_Int:
-
- case X86::VFMADDSDr231r_Int: case X86::VFMADDSDr231m_Int:
- case X86::VFMADDSSr231r_Int: case X86::VFMADDSSr231m_Int:
- case X86::VFMSUBSDr231r_Int: case X86::VFMSUBSDr231m_Int:
- case X86::VFMSUBSSr231r_Int: case X86::VFMSUBSSr231m_Int:
- case X86::VFNMADDSDr231r_Int: case X86::VFNMADDSDr231m_Int:
- case X86::VFNMADDSSr231r_Int: case X86::VFNMADDSSr231m_Int:
- case X86::VFNMSUBSDr231r_Int: case X86::VFNMSUBSDr231m_Int:
- case X86::VFNMSUBSSr231r_Int: case X86::VFNMSUBSSr231m_Int:
- if (IsIntrinsic)
- *IsIntrinsic = true;
- return true;
- default:
- return false;
+unsigned X86InstrInfo::getFMA3OpcodeToCommuteOperands(
+ const MachineInstr &MI, unsigned SrcOpIdx1, unsigned SrcOpIdx2,
+ const X86InstrFMA3Group &FMA3Group) const {
+
+ unsigned Opc = MI.getOpcode();
+
+ // Put the lowest index to SrcOpIdx1 to simplify the checks below.
+ if (SrcOpIdx1 > SrcOpIdx2)
+ std::swap(SrcOpIdx1, SrcOpIdx2);
+
+ // TODO: Commuting the 1st operand of FMA*_Int requires some additional
+ // analysis. The commute optimization is legal only if all users of FMA*_Int
+ // use only the lowest element of the FMA*_Int instruction. Such analysis are
+ // not implemented yet. So, just return 0 in that case.
+ // When such analysis are available this place will be the right place for
+ // calling it.
+ if (FMA3Group.isIntrinsic() && SrcOpIdx1 == 1)
+ return 0;
+
+ // Determine which case this commute is or if it can't be done.
+ int Case = getThreeSrcCommuteCase(MI.getDesc().TSFlags, SrcOpIdx1, SrcOpIdx2);
+ if (Case < 0)
+ return 0;
+
+ // Define the FMA forms mapping array that helps to map input FMA form
+ // to output FMA form to preserve the operation semantics after
+ // commuting the operands.
+ const unsigned Form132Index = 0;
+ const unsigned Form213Index = 1;
+ const unsigned Form231Index = 2;
+ static const unsigned FormMapping[][3] = {
+ // 0: SrcOpIdx1 == 1 && SrcOpIdx2 == 2;
+ // FMA132 A, C, b; ==> FMA231 C, A, b;
+ // FMA213 B, A, c; ==> FMA213 A, B, c;
+ // FMA231 C, A, b; ==> FMA132 A, C, b;
+ { Form231Index, Form213Index, Form132Index },
+ // 1: SrcOpIdx1 == 1 && SrcOpIdx2 == 3;
+ // FMA132 A, c, B; ==> FMA132 B, c, A;
+ // FMA213 B, a, C; ==> FMA231 C, a, B;
+ // FMA231 C, a, B; ==> FMA213 B, a, C;
+ { Form132Index, Form231Index, Form213Index },
+ // 2: SrcOpIdx1 == 2 && SrcOpIdx2 == 3;
+ // FMA132 a, C, B; ==> FMA213 a, B, C;
+ // FMA213 b, A, C; ==> FMA132 b, C, A;
+ // FMA231 c, A, B; ==> FMA231 c, B, A;
+ { Form213Index, Form132Index, Form231Index }
+ };
+
+ unsigned FMAForms[3];
+ if (FMA3Group.isRegOpcodeFromGroup(Opc)) {
+ FMAForms[0] = FMA3Group.getReg132Opcode();
+ FMAForms[1] = FMA3Group.getReg213Opcode();
+ FMAForms[2] = FMA3Group.getReg231Opcode();
+ } else {
+ FMAForms[0] = FMA3Group.getMem132Opcode();
+ FMAForms[1] = FMA3Group.getMem213Opcode();
+ FMAForms[2] = FMA3Group.getMem231Opcode();
+ }
+ unsigned FormIndex;
+ for (FormIndex = 0; FormIndex < 3; FormIndex++)
+ if (Opc == FMAForms[FormIndex])
+ break;
+
+ // Everything is ready, just adjust the FMA opcode and return it.
+ FormIndex = FormMapping[Case][FormIndex];
+ return FMAForms[FormIndex];
+}
+
+static bool commuteVPTERNLOG(MachineInstr &MI, unsigned SrcOpIdx1,
+ unsigned SrcOpIdx2) {
+ uint64_t TSFlags = MI.getDesc().TSFlags;
+
+ // Determine which case this commute is or if it can't be done.
+ int Case = getThreeSrcCommuteCase(TSFlags, SrcOpIdx1, SrcOpIdx2);
+ if (Case < 0)
+ return false;
+
+ // For each case we need to swap two pairs of bits in the final immediate.
+ static const uint8_t SwapMasks[3][4] = {
+ { 0x04, 0x10, 0x08, 0x20 }, // Swap bits 2/4 and 3/5.
+ { 0x02, 0x10, 0x08, 0x40 }, // Swap bits 1/4 and 3/6.
+ { 0x02, 0x04, 0x20, 0x40 }, // Swap bits 1/2 and 5/6.
+ };
+
+ uint8_t Imm = MI.getOperand(MI.getNumOperands()-1).getImm();
+ // Clear out the bits we are swapping.
+ uint8_t NewImm = Imm & ~(SwapMasks[Case][0] | SwapMasks[Case][1] |
+ SwapMasks[Case][2] | SwapMasks[Case][3]);
+ // If the immediate had a bit of the pair set, then set the opposite bit.
+ if (Imm & SwapMasks[Case][0]) NewImm |= SwapMasks[Case][1];
+ if (Imm & SwapMasks[Case][1]) NewImm |= SwapMasks[Case][0];
+ if (Imm & SwapMasks[Case][2]) NewImm |= SwapMasks[Case][3];
+ if (Imm & SwapMasks[Case][3]) NewImm |= SwapMasks[Case][2];
+ MI.getOperand(MI.getNumOperands()-1).setImm(NewImm);
+
+ return true;
+}
+
+// Returns true if this is a VPERMI2 or VPERMT2 instrution that can be
+// commuted.
+static bool isCommutableVPERMV3Instruction(unsigned Opcode) {
+#define VPERM_CASES(Suffix) \
+ case X86::VPERMI2##Suffix##128rr: case X86::VPERMT2##Suffix##128rr: \
+ case X86::VPERMI2##Suffix##256rr: case X86::VPERMT2##Suffix##256rr: \
+ case X86::VPERMI2##Suffix##rr: case X86::VPERMT2##Suffix##rr: \
+ case X86::VPERMI2##Suffix##128rm: case X86::VPERMT2##Suffix##128rm: \
+ case X86::VPERMI2##Suffix##256rm: case X86::VPERMT2##Suffix##256rm: \
+ case X86::VPERMI2##Suffix##rm: case X86::VPERMT2##Suffix##rm: \
+ case X86::VPERMI2##Suffix##128rrkz: case X86::VPERMT2##Suffix##128rrkz: \
+ case X86::VPERMI2##Suffix##256rrkz: case X86::VPERMT2##Suffix##256rrkz: \
+ case X86::VPERMI2##Suffix##rrkz: case X86::VPERMT2##Suffix##rrkz: \
+ case X86::VPERMI2##Suffix##128rmkz: case X86::VPERMT2##Suffix##128rmkz: \
+ case X86::VPERMI2##Suffix##256rmkz: case X86::VPERMT2##Suffix##256rmkz: \
+ case X86::VPERMI2##Suffix##rmkz: case X86::VPERMT2##Suffix##rmkz:
+
+#define VPERM_CASES_BROADCAST(Suffix) \
+ VPERM_CASES(Suffix) \
+ case X86::VPERMI2##Suffix##128rmb: case X86::VPERMT2##Suffix##128rmb: \
+ case X86::VPERMI2##Suffix##256rmb: case X86::VPERMT2##Suffix##256rmb: \
+ case X86::VPERMI2##Suffix##rmb: case X86::VPERMT2##Suffix##rmb: \
+ case X86::VPERMI2##Suffix##128rmbkz: case X86::VPERMT2##Suffix##128rmbkz: \
+ case X86::VPERMI2##Suffix##256rmbkz: case X86::VPERMT2##Suffix##256rmbkz: \
+ case X86::VPERMI2##Suffix##rmbkz: case X86::VPERMT2##Suffix##rmbkz:
+
+ switch (Opcode) {
+ default: return false;
+ VPERM_CASES(B)
+ VPERM_CASES_BROADCAST(D)
+ VPERM_CASES_BROADCAST(PD)
+ VPERM_CASES_BROADCAST(PS)
+ VPERM_CASES_BROADCAST(Q)
+ VPERM_CASES(W)
+ return true;
}
- llvm_unreachable("Opcode not handled by the switch");
+#undef VPERM_CASES_BROADCAST
+#undef VPERM_CASES
+}
+
+// Returns commuted opcode for VPERMI2 and VPERMT2 instructions by switching
+// from the I opcod to the T opcode and vice versa.
+static unsigned getCommutedVPERMV3Opcode(unsigned Opcode) {
+#define VPERM_CASES(Orig, New) \
+ case X86::Orig##128rr: return X86::New##128rr; \
+ case X86::Orig##128rrkz: return X86::New##128rrkz; \
+ case X86::Orig##128rm: return X86::New##128rm; \
+ case X86::Orig##128rmkz: return X86::New##128rmkz; \
+ case X86::Orig##256rr: return X86::New##256rr; \
+ case X86::Orig##256rrkz: return X86::New##256rrkz; \
+ case X86::Orig##256rm: return X86::New##256rm; \
+ case X86::Orig##256rmkz: return X86::New##256rmkz; \
+ case X86::Orig##rr: return X86::New##rr; \
+ case X86::Orig##rrkz: return X86::New##rrkz; \
+ case X86::Orig##rm: return X86::New##rm; \
+ case X86::Orig##rmkz: return X86::New##rmkz;
+
+#define VPERM_CASES_BROADCAST(Orig, New) \
+ VPERM_CASES(Orig, New) \
+ case X86::Orig##128rmb: return X86::New##128rmb; \
+ case X86::Orig##128rmbkz: return X86::New##128rmbkz; \
+ case X86::Orig##256rmb: return X86::New##256rmb; \
+ case X86::Orig##256rmbkz: return X86::New##256rmbkz; \
+ case X86::Orig##rmb: return X86::New##rmb; \
+ case X86::Orig##rmbkz: return X86::New##rmbkz;
+
+ switch (Opcode) {
+ VPERM_CASES(VPERMI2B, VPERMT2B)
+ VPERM_CASES_BROADCAST(VPERMI2D, VPERMT2D)
+ VPERM_CASES_BROADCAST(VPERMI2PD, VPERMT2PD)
+ VPERM_CASES_BROADCAST(VPERMI2PS, VPERMT2PS)
+ VPERM_CASES_BROADCAST(VPERMI2Q, VPERMT2Q)
+ VPERM_CASES(VPERMI2W, VPERMT2W)
+ VPERM_CASES(VPERMT2B, VPERMI2B)
+ VPERM_CASES_BROADCAST(VPERMT2D, VPERMI2D)
+ VPERM_CASES_BROADCAST(VPERMT2PD, VPERMI2PD)
+ VPERM_CASES_BROADCAST(VPERMT2PS, VPERMI2PS)
+ VPERM_CASES_BROADCAST(VPERMT2Q, VPERMI2Q)
+ VPERM_CASES(VPERMT2W, VPERMI2W)
+ }
+
+ llvm_unreachable("Unreachable!");
+#undef VPERM_CASES_BROADCAST
+#undef VPERM_CASES
}
MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
@@ -3352,6 +4370,39 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
OpIdx1, OpIdx2);
}
+ case X86::MOVSDrr:
+ case X86::MOVSSrr:
+ case X86::VMOVSDrr:
+ case X86::VMOVSSrr:{
+ // On SSE41 or later we can commute a MOVSS/MOVSD to a BLENDPS/BLENDPD.
+ if (!Subtarget.hasSSE41())
+ return nullptr;
+
+ unsigned Mask, Opc;
+ switch (MI.getOpcode()) {
+ default: llvm_unreachable("Unreachable!");
+ case X86::MOVSDrr: Opc = X86::BLENDPDrri; Mask = 0x02; break;
+ case X86::MOVSSrr: Opc = X86::BLENDPSrri; Mask = 0x0E; break;
+ case X86::VMOVSDrr: Opc = X86::VBLENDPDrri; Mask = 0x02; break;
+ case X86::VMOVSSrr: Opc = X86::VBLENDPSrri; Mask = 0x0E; break;
+ }
+
+ // MOVSD/MOVSS's 2nd operand is a FR64/FR32 reg class - we need to copy
+ // this over to a VR128 class like the 1st operand to use a BLENDPD/BLENDPS.
+ auto &MRI = MI.getParent()->getParent()->getRegInfo();
+ auto VR128RC = MRI.getRegClass(MI.getOperand(1).getReg());
+ unsigned VR128 = MRI.createVirtualRegister(VR128RC);
+ BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), get(TargetOpcode::COPY),
+ VR128)
+ .addReg(MI.getOperand(2).getReg());
+
+ auto &WorkingMI = cloneIfNew(MI);
+ WorkingMI.setDesc(get(Opc));
+ WorkingMI.getOperand(2).setReg(VR128);
+ WorkingMI.addOperand(MachineOperand::CreateImm(Mask));
+ return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
+ OpIdx1, OpIdx2);
+ }
case X86::PCLMULQDQrr:
case X86::VPCLMULQDQrr:{
// SRC1 64bits = Imm[0] ? SRC1[127:64] : SRC1[63:0]
@@ -3364,12 +4415,24 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
OpIdx1, OpIdx2);
}
+ case X86::CMPSDrr:
+ case X86::CMPSSrr:
case X86::CMPPDrri:
case X86::CMPPSrri:
+ case X86::VCMPSDrr:
+ case X86::VCMPSSrr:
case X86::VCMPPDrri:
case X86::VCMPPSrri:
case X86::VCMPPDYrri:
- case X86::VCMPPSYrri: {
+ case X86::VCMPPSYrri:
+ case X86::VCMPSDZrr:
+ case X86::VCMPSSZrr:
+ case X86::VCMPPDZrri:
+ case X86::VCMPPSZrri:
+ case X86::VCMPPDZ128rri:
+ case X86::VCMPPSZ128rri:
+ case X86::VCMPPDZ256rri:
+ case X86::VCMPPSZ256rri: {
// Float comparison can be safely commuted for
// Ordered/Unordered/Equal/NotEqual tests
unsigned Imm = MI.getOperand(3).getImm() & 0x7;
@@ -3383,6 +4446,37 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
return nullptr;
}
}
+ case X86::VPCMPBZ128rri: case X86::VPCMPUBZ128rri:
+ case X86::VPCMPBZ256rri: case X86::VPCMPUBZ256rri:
+ case X86::VPCMPBZrri: case X86::VPCMPUBZrri:
+ case X86::VPCMPDZ128rri: case X86::VPCMPUDZ128rri:
+ case X86::VPCMPDZ256rri: case X86::VPCMPUDZ256rri:
+ case X86::VPCMPDZrri: case X86::VPCMPUDZrri:
+ case X86::VPCMPQZ128rri: case X86::VPCMPUQZ128rri:
+ case X86::VPCMPQZ256rri: case X86::VPCMPUQZ256rri:
+ case X86::VPCMPQZrri: case X86::VPCMPUQZrri:
+ case X86::VPCMPWZ128rri: case X86::VPCMPUWZ128rri:
+ case X86::VPCMPWZ256rri: case X86::VPCMPUWZ256rri:
+ case X86::VPCMPWZrri: case X86::VPCMPUWZrri: {
+ // Flip comparison mode immediate (if necessary).
+ unsigned Imm = MI.getOperand(3).getImm() & 0x7;
+ switch (Imm) {
+ default: llvm_unreachable("Unreachable!");
+ case 0x01: Imm = 0x06; break; // LT -> NLE
+ case 0x02: Imm = 0x05; break; // LE -> NLT
+ case 0x05: Imm = 0x02; break; // NLT -> LE
+ case 0x06: Imm = 0x01; break; // NLE -> LT
+ case 0x00: // EQ
+ case 0x03: // FALSE
+ case 0x04: // NE
+ case 0x07: // TRUE
+ break;
+ }
+ auto &WorkingMI = cloneIfNew(MI);
+ WorkingMI.getOperand(3).setImm(Imm);
+ return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
+ OpIdx1, OpIdx2);
+ }
case X86::VPCOMBri: case X86::VPCOMUBri:
case X86::VPCOMDri: case X86::VPCOMUDri:
case X86::VPCOMQri: case X86::VPCOMUQri:
@@ -3390,6 +4484,7 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
// Flip comparison mode immediate (if necessary).
unsigned Imm = MI.getOperand(3).getImm() & 0x7;
switch (Imm) {
+ default: llvm_unreachable("Unreachable!");
case 0x00: Imm = 0x02; break; // LT -> GT
case 0x01: Imm = 0x03; break; // LE -> GE
case 0x02: Imm = 0x00; break; // GT -> LT
@@ -3398,7 +4493,6 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
case 0x05: // NE
case 0x06: // FALSE
case 0x07: // TRUE
- default:
break;
}
auto &WorkingMI = cloneIfNew(MI);
@@ -3417,6 +4511,22 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
OpIdx1, OpIdx2);
}
+ case X86::MOVHLPSrr:
+ case X86::UNPCKHPDrr: {
+ if (!Subtarget.hasSSE2())
+ return nullptr;
+
+ unsigned Opc = MI.getOpcode();
+ switch (Opc) {
+ default: llvm_unreachable("Unreachable!");
+ case X86::MOVHLPSrr: Opc = X86::UNPCKHPDrr; break;
+ case X86::UNPCKHPDrr: Opc = X86::MOVHLPSrr; break;
+ }
+ auto &WorkingMI = cloneIfNew(MI);
+ WorkingMI.setDesc(get(Opc));
+ return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
+ OpIdx1, OpIdx2);
+ }
case X86::CMOVB16rr: case X86::CMOVB32rr: case X86::CMOVB64rr:
case X86::CMOVAE16rr: case X86::CMOVAE32rr: case X86::CMOVAE64rr:
case X86::CMOVE16rr: case X86::CMOVE32rr: case X86::CMOVE64rr:
@@ -3490,9 +4600,44 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
OpIdx1, OpIdx2);
}
- default:
- if (isFMA3(MI.getOpcode())) {
- unsigned Opc = getFMA3OpcodeToCommuteOperands(MI, OpIdx1, OpIdx2);
+ case X86::VPTERNLOGDZrri: case X86::VPTERNLOGDZrmi:
+ case X86::VPTERNLOGDZ128rri: case X86::VPTERNLOGDZ128rmi:
+ case X86::VPTERNLOGDZ256rri: case X86::VPTERNLOGDZ256rmi:
+ case X86::VPTERNLOGQZrri: case X86::VPTERNLOGQZrmi:
+ case X86::VPTERNLOGQZ128rri: case X86::VPTERNLOGQZ128rmi:
+ case X86::VPTERNLOGQZ256rri: case X86::VPTERNLOGQZ256rmi:
+ case X86::VPTERNLOGDZrrik: case X86::VPTERNLOGDZrmik:
+ case X86::VPTERNLOGDZ128rrik: case X86::VPTERNLOGDZ128rmik:
+ case X86::VPTERNLOGDZ256rrik: case X86::VPTERNLOGDZ256rmik:
+ case X86::VPTERNLOGQZrrik: case X86::VPTERNLOGQZrmik:
+ case X86::VPTERNLOGQZ128rrik: case X86::VPTERNLOGQZ128rmik:
+ case X86::VPTERNLOGQZ256rrik: case X86::VPTERNLOGQZ256rmik:
+ case X86::VPTERNLOGDZrrikz: case X86::VPTERNLOGDZrmikz:
+ case X86::VPTERNLOGDZ128rrikz: case X86::VPTERNLOGDZ128rmikz:
+ case X86::VPTERNLOGDZ256rrikz: case X86::VPTERNLOGDZ256rmikz:
+ case X86::VPTERNLOGQZrrikz: case X86::VPTERNLOGQZrmikz:
+ case X86::VPTERNLOGQZ128rrikz: case X86::VPTERNLOGQZ128rmikz:
+ case X86::VPTERNLOGQZ256rrikz: case X86::VPTERNLOGQZ256rmikz: {
+ auto &WorkingMI = cloneIfNew(MI);
+ if (!commuteVPTERNLOG(WorkingMI, OpIdx1, OpIdx2))
+ return nullptr;
+ return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
+ OpIdx1, OpIdx2);
+ }
+ default: {
+ if (isCommutableVPERMV3Instruction(MI.getOpcode())) {
+ unsigned Opc = getCommutedVPERMV3Opcode(MI.getOpcode());
+ auto &WorkingMI = cloneIfNew(MI);
+ WorkingMI.setDesc(get(Opc));
+ return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
+ OpIdx1, OpIdx2);
+ }
+
+ const X86InstrFMA3Group *FMA3Group =
+ X86InstrFMA3Info::getFMA3Group(MI.getOpcode());
+ if (FMA3Group) {
+ unsigned Opc =
+ getFMA3OpcodeToCommuteOperands(MI, OpIdx1, OpIdx2, *FMA3Group);
if (Opc == 0)
return nullptr;
auto &WorkingMI = cloneIfNew(MI);
@@ -3503,22 +4648,54 @@ MachineInstr *X86InstrInfo::commuteInstructionImpl(MachineInstr &MI, bool NewMI,
return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
}
+ }
}
-bool X86InstrInfo::findFMA3CommutedOpIndices(MachineInstr &MI,
- unsigned &SrcOpIdx1,
- unsigned &SrcOpIdx2) const {
+bool X86InstrInfo::findFMA3CommutedOpIndices(
+ const MachineInstr &MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2,
+ const X86InstrFMA3Group &FMA3Group) const {
- unsigned RegOpsNum = isMem(MI, 3) ? 2 : 3;
+ if (!findThreeSrcCommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2))
+ return false;
+
+ // Check if we can adjust the opcode to preserve the semantics when
+ // commute the register operands.
+ return getFMA3OpcodeToCommuteOperands(MI, SrcOpIdx1, SrcOpIdx2, FMA3Group) != 0;
+}
+
+bool X86InstrInfo::findThreeSrcCommutedOpIndices(const MachineInstr &MI,
+ unsigned &SrcOpIdx1,
+ unsigned &SrcOpIdx2) const {
+ uint64_t TSFlags = MI.getDesc().TSFlags;
+
+ unsigned FirstCommutableVecOp = 1;
+ unsigned LastCommutableVecOp = 3;
+ unsigned KMaskOp = 0;
+ if (X86II::isKMasked(TSFlags)) {
+ // The k-mask operand has index = 2 for masked and zero-masked operations.
+ KMaskOp = 2;
+
+ // The operand with index = 1 is used as a source for those elements for
+ // which the corresponding bit in the k-mask is set to 0.
+ if (X86II::isKMergeMasked(TSFlags))
+ FirstCommutableVecOp = 3;
+
+ LastCommutableVecOp++;
+ }
+
+ if (isMem(MI, LastCommutableVecOp))
+ LastCommutableVecOp--;
// Only the first RegOpsNum operands are commutable.
// Also, the value 'CommuteAnyOperandIndex' is valid here as it means
// that the operand is not specified/fixed.
if (SrcOpIdx1 != CommuteAnyOperandIndex &&
- (SrcOpIdx1 < 1 || SrcOpIdx1 > RegOpsNum))
+ (SrcOpIdx1 < FirstCommutableVecOp || SrcOpIdx1 > LastCommutableVecOp ||
+ SrcOpIdx1 == KMaskOp))
return false;
if (SrcOpIdx2 != CommuteAnyOperandIndex &&
- (SrcOpIdx2 < 1 || SrcOpIdx2 > RegOpsNum))
+ (SrcOpIdx2 < FirstCommutableVecOp || SrcOpIdx2 > LastCommutableVecOp ||
+ SrcOpIdx2 == KMaskOp))
return false;
// Look for two different register operands assumed to be commutable
@@ -3533,7 +4710,7 @@ bool X86InstrInfo::findFMA3CommutedOpIndices(MachineInstr &MI,
if (SrcOpIdx1 == SrcOpIdx2)
// Both of operands are not fixed. By default set one of commutable
// operands to the last register operand of the instruction.
- CommutableOpIdx2 = RegOpsNum;
+ CommutableOpIdx2 = LastCommutableVecOp;
else if (SrcOpIdx2 == CommuteAnyOperandIndex)
// Only one of operands is not fixed.
CommutableOpIdx2 = SrcOpIdx1;
@@ -3541,7 +4718,12 @@ bool X86InstrInfo::findFMA3CommutedOpIndices(MachineInstr &MI,
// CommutableOpIdx2 is well defined now. Let's choose another commutable
// operand and assign its index to CommutableOpIdx1.
unsigned Op2Reg = MI.getOperand(CommutableOpIdx2).getReg();
- for (CommutableOpIdx1 = RegOpsNum; CommutableOpIdx1 > 0; CommutableOpIdx1--) {
+ for (CommutableOpIdx1 = LastCommutableVecOp;
+ CommutableOpIdx1 >= FirstCommutableVecOp; CommutableOpIdx1--) {
+ // Just ignore and skip the k-mask operand.
+ if (CommutableOpIdx1 == KMaskOp)
+ continue;
+
// The commuted operands must have different registers.
// Otherwise, the commute transformation does not change anything and
// is useless then.
@@ -3550,7 +4732,7 @@ bool X86InstrInfo::findFMA3CommutedOpIndices(MachineInstr &MI,
}
// No appropriate commutable operands were found.
- if (CommutableOpIdx1 == 0)
+ if (CommutableOpIdx1 < FirstCommutableVecOp)
return false;
// Assign the found pair of commutable indices to SrcOpIdx1 and SrcOpidx2
@@ -3560,208 +4742,34 @@ bool X86InstrInfo::findFMA3CommutedOpIndices(MachineInstr &MI,
return false;
}
- // Check if we can adjust the opcode to preserve the semantics when
- // commute the register operands.
- return getFMA3OpcodeToCommuteOperands(MI, SrcOpIdx1, SrcOpIdx2) != 0;
-}
-
-unsigned X86InstrInfo::getFMA3OpcodeToCommuteOperands(
- MachineInstr &MI, unsigned SrcOpIdx1, unsigned SrcOpIdx2) const {
- unsigned Opc = MI.getOpcode();
-
- // Define the array that holds FMA opcodes in groups
- // of 3 opcodes(132, 213, 231) in each group.
- static const uint16_t RegularOpcodeGroups[][3] = {
- { X86::VFMADDSSr132r, X86::VFMADDSSr213r, X86::VFMADDSSr231r },
- { X86::VFMADDSDr132r, X86::VFMADDSDr213r, X86::VFMADDSDr231r },
- { X86::VFMADDPSr132r, X86::VFMADDPSr213r, X86::VFMADDPSr231r },
- { X86::VFMADDPDr132r, X86::VFMADDPDr213r, X86::VFMADDPDr231r },
- { X86::VFMADDPSr132rY, X86::VFMADDPSr213rY, X86::VFMADDPSr231rY },
- { X86::VFMADDPDr132rY, X86::VFMADDPDr213rY, X86::VFMADDPDr231rY },
- { X86::VFMADDSSr132m, X86::VFMADDSSr213m, X86::VFMADDSSr231m },
- { X86::VFMADDSDr132m, X86::VFMADDSDr213m, X86::VFMADDSDr231m },
- { X86::VFMADDPSr132m, X86::VFMADDPSr213m, X86::VFMADDPSr231m },
- { X86::VFMADDPDr132m, X86::VFMADDPDr213m, X86::VFMADDPDr231m },
- { X86::VFMADDPSr132mY, X86::VFMADDPSr213mY, X86::VFMADDPSr231mY },
- { X86::VFMADDPDr132mY, X86::VFMADDPDr213mY, X86::VFMADDPDr231mY },
-
- { X86::VFMSUBSSr132r, X86::VFMSUBSSr213r, X86::VFMSUBSSr231r },
- { X86::VFMSUBSDr132r, X86::VFMSUBSDr213r, X86::VFMSUBSDr231r },
- { X86::VFMSUBPSr132r, X86::VFMSUBPSr213r, X86::VFMSUBPSr231r },
- { X86::VFMSUBPDr132r, X86::VFMSUBPDr213r, X86::VFMSUBPDr231r },
- { X86::VFMSUBPSr132rY, X86::VFMSUBPSr213rY, X86::VFMSUBPSr231rY },
- { X86::VFMSUBPDr132rY, X86::VFMSUBPDr213rY, X86::VFMSUBPDr231rY },
- { X86::VFMSUBSSr132m, X86::VFMSUBSSr213m, X86::VFMSUBSSr231m },
- { X86::VFMSUBSDr132m, X86::VFMSUBSDr213m, X86::VFMSUBSDr231m },
- { X86::VFMSUBPSr132m, X86::VFMSUBPSr213m, X86::VFMSUBPSr231m },
- { X86::VFMSUBPDr132m, X86::VFMSUBPDr213m, X86::VFMSUBPDr231m },
- { X86::VFMSUBPSr132mY, X86::VFMSUBPSr213mY, X86::VFMSUBPSr231mY },
- { X86::VFMSUBPDr132mY, X86::VFMSUBPDr213mY, X86::VFMSUBPDr231mY },
-
- { X86::VFNMADDSSr132r, X86::VFNMADDSSr213r, X86::VFNMADDSSr231r },
- { X86::VFNMADDSDr132r, X86::VFNMADDSDr213r, X86::VFNMADDSDr231r },
- { X86::VFNMADDPSr132r, X86::VFNMADDPSr213r, X86::VFNMADDPSr231r },
- { X86::VFNMADDPDr132r, X86::VFNMADDPDr213r, X86::VFNMADDPDr231r },
- { X86::VFNMADDPSr132rY, X86::VFNMADDPSr213rY, X86::VFNMADDPSr231rY },
- { X86::VFNMADDPDr132rY, X86::VFNMADDPDr213rY, X86::VFNMADDPDr231rY },
- { X86::VFNMADDSSr132m, X86::VFNMADDSSr213m, X86::VFNMADDSSr231m },
- { X86::VFNMADDSDr132m, X86::VFNMADDSDr213m, X86::VFNMADDSDr231m },
- { X86::VFNMADDPSr132m, X86::VFNMADDPSr213m, X86::VFNMADDPSr231m },
- { X86::VFNMADDPDr132m, X86::VFNMADDPDr213m, X86::VFNMADDPDr231m },
- { X86::VFNMADDPSr132mY, X86::VFNMADDPSr213mY, X86::VFNMADDPSr231mY },
- { X86::VFNMADDPDr132mY, X86::VFNMADDPDr213mY, X86::VFNMADDPDr231mY },
-
- { X86::VFNMSUBSSr132r, X86::VFNMSUBSSr213r, X86::VFNMSUBSSr231r },
- { X86::VFNMSUBSDr132r, X86::VFNMSUBSDr213r, X86::VFNMSUBSDr231r },
- { X86::VFNMSUBPSr132r, X86::VFNMSUBPSr213r, X86::VFNMSUBPSr231r },
- { X86::VFNMSUBPDr132r, X86::VFNMSUBPDr213r, X86::VFNMSUBPDr231r },
- { X86::VFNMSUBPSr132rY, X86::VFNMSUBPSr213rY, X86::VFNMSUBPSr231rY },
- { X86::VFNMSUBPDr132rY, X86::VFNMSUBPDr213rY, X86::VFNMSUBPDr231rY },
- { X86::VFNMSUBSSr132m, X86::VFNMSUBSSr213m, X86::VFNMSUBSSr231m },
- { X86::VFNMSUBSDr132m, X86::VFNMSUBSDr213m, X86::VFNMSUBSDr231m },
- { X86::VFNMSUBPSr132m, X86::VFNMSUBPSr213m, X86::VFNMSUBPSr231m },
- { X86::VFNMSUBPDr132m, X86::VFNMSUBPDr213m, X86::VFNMSUBPDr231m },
- { X86::VFNMSUBPSr132mY, X86::VFNMSUBPSr213mY, X86::VFNMSUBPSr231mY },
- { X86::VFNMSUBPDr132mY, X86::VFNMSUBPDr213mY, X86::VFNMSUBPDr231mY },
-
- { X86::VFMADDSUBPSr132r, X86::VFMADDSUBPSr213r, X86::VFMADDSUBPSr231r },
- { X86::VFMADDSUBPDr132r, X86::VFMADDSUBPDr213r, X86::VFMADDSUBPDr231r },
- { X86::VFMADDSUBPSr132rY, X86::VFMADDSUBPSr213rY, X86::VFMADDSUBPSr231rY },
- { X86::VFMADDSUBPDr132rY, X86::VFMADDSUBPDr213rY, X86::VFMADDSUBPDr231rY },
- { X86::VFMADDSUBPSr132m, X86::VFMADDSUBPSr213m, X86::VFMADDSUBPSr231m },
- { X86::VFMADDSUBPDr132m, X86::VFMADDSUBPDr213m, X86::VFMADDSUBPDr231m },
- { X86::VFMADDSUBPSr132mY, X86::VFMADDSUBPSr213mY, X86::VFMADDSUBPSr231mY },
- { X86::VFMADDSUBPDr132mY, X86::VFMADDSUBPDr213mY, X86::VFMADDSUBPDr231mY },
-
- { X86::VFMSUBADDPSr132r, X86::VFMSUBADDPSr213r, X86::VFMSUBADDPSr231r },
- { X86::VFMSUBADDPDr132r, X86::VFMSUBADDPDr213r, X86::VFMSUBADDPDr231r },
- { X86::VFMSUBADDPSr132rY, X86::VFMSUBADDPSr213rY, X86::VFMSUBADDPSr231rY },
- { X86::VFMSUBADDPDr132rY, X86::VFMSUBADDPDr213rY, X86::VFMSUBADDPDr231rY },
- { X86::VFMSUBADDPSr132m, X86::VFMSUBADDPSr213m, X86::VFMSUBADDPSr231m },
- { X86::VFMSUBADDPDr132m, X86::VFMSUBADDPDr213m, X86::VFMSUBADDPDr231m },
- { X86::VFMSUBADDPSr132mY, X86::VFMSUBADDPSr213mY, X86::VFMSUBADDPSr231mY },
- { X86::VFMSUBADDPDr132mY, X86::VFMSUBADDPDr213mY, X86::VFMSUBADDPDr231mY }
- };
-
- // Define the array that holds FMA*_Int opcodes in groups
- // of 3 opcodes(132, 213, 231) in each group.
- static const uint16_t IntrinOpcodeGroups[][3] = {
- { X86::VFMADDSSr132r_Int, X86::VFMADDSSr213r_Int, X86::VFMADDSSr231r_Int },
- { X86::VFMADDSDr132r_Int, X86::VFMADDSDr213r_Int, X86::VFMADDSDr231r_Int },
- { X86::VFMADDSSr132m_Int, X86::VFMADDSSr213m_Int, X86::VFMADDSSr231m_Int },
- { X86::VFMADDSDr132m_Int, X86::VFMADDSDr213m_Int, X86::VFMADDSDr231m_Int },
-
- { X86::VFMSUBSSr132r_Int, X86::VFMSUBSSr213r_Int, X86::VFMSUBSSr231r_Int },
- { X86::VFMSUBSDr132r_Int, X86::VFMSUBSDr213r_Int, X86::VFMSUBSDr231r_Int },
- { X86::VFMSUBSSr132m_Int, X86::VFMSUBSSr213m_Int, X86::VFMSUBSSr231m_Int },
- { X86::VFMSUBSDr132m_Int, X86::VFMSUBSDr213m_Int, X86::VFMSUBSDr231m_Int },
-
- { X86::VFNMADDSSr132r_Int, X86::VFNMADDSSr213r_Int, X86::VFNMADDSSr231r_Int },
- { X86::VFNMADDSDr132r_Int, X86::VFNMADDSDr213r_Int, X86::VFNMADDSDr231r_Int },
- { X86::VFNMADDSSr132m_Int, X86::VFNMADDSSr213m_Int, X86::VFNMADDSSr231m_Int },
- { X86::VFNMADDSDr132m_Int, X86::VFNMADDSDr213m_Int, X86::VFNMADDSDr231m_Int },
-
- { X86::VFNMSUBSSr132r_Int, X86::VFNMSUBSSr213r_Int, X86::VFNMSUBSSr231r_Int },
- { X86::VFNMSUBSDr132r_Int, X86::VFNMSUBSDr213r_Int, X86::VFNMSUBSDr231r_Int },
- { X86::VFNMSUBSSr132m_Int, X86::VFNMSUBSSr213m_Int, X86::VFNMSUBSSr231m_Int },
- { X86::VFNMSUBSDr132m_Int, X86::VFNMSUBSDr213m_Int, X86::VFNMSUBSDr231m_Int },
- };
-
- const unsigned Form132Index = 0;
- const unsigned Form213Index = 1;
- const unsigned Form231Index = 2;
- const unsigned FormsNum = 3;
-
- bool IsIntrinOpcode;
- isFMA3(Opc, &IsIntrinOpcode);
-
- size_t GroupsNum;
- const uint16_t (*OpcodeGroups)[3];
- if (IsIntrinOpcode) {
- GroupsNum = array_lengthof(IntrinOpcodeGroups);
- OpcodeGroups = IntrinOpcodeGroups;
- } else {
- GroupsNum = array_lengthof(RegularOpcodeGroups);
- OpcodeGroups = RegularOpcodeGroups;
- }
-
- const uint16_t *FoundOpcodesGroup = nullptr;
- size_t FormIndex;
-
- // Look for the input opcode in the corresponding opcodes table.
- for (size_t GroupIndex = 0; GroupIndex < GroupsNum && !FoundOpcodesGroup;
- ++GroupIndex) {
- for (FormIndex = 0; FormIndex < FormsNum; ++FormIndex) {
- if (OpcodeGroups[GroupIndex][FormIndex] == Opc) {
- FoundOpcodesGroup = OpcodeGroups[GroupIndex];
- break;
- }
- }
- }
-
- // The input opcode does not match with any of the opcodes from the tables.
- // The unsupported FMA opcode must be added to one of the two opcode groups
- // defined above.
- assert(FoundOpcodesGroup != nullptr && "Unexpected FMA3 opcode");
-
- // Put the lowest index to SrcOpIdx1 to simplify the checks below.
- if (SrcOpIdx1 > SrcOpIdx2)
- std::swap(SrcOpIdx1, SrcOpIdx2);
-
- // TODO: Commuting the 1st operand of FMA*_Int requires some additional
- // analysis. The commute optimization is legal only if all users of FMA*_Int
- // use only the lowest element of the FMA*_Int instruction. Such analysis are
- // not implemented yet. So, just return 0 in that case.
- // When such analysis are available this place will be the right place for
- // calling it.
- if (IsIntrinOpcode && SrcOpIdx1 == 1)
- return 0;
-
- unsigned Case;
- if (SrcOpIdx1 == 1 && SrcOpIdx2 == 2)
- Case = 0;
- else if (SrcOpIdx1 == 1 && SrcOpIdx2 == 3)
- Case = 1;
- else if (SrcOpIdx1 == 2 && SrcOpIdx2 == 3)
- Case = 2;
- else
- return 0;
-
- // Define the FMA forms mapping array that helps to map input FMA form
- // to output FMA form to preserve the operation semantics after
- // commuting the operands.
- static const unsigned FormMapping[][3] = {
- // 0: SrcOpIdx1 == 1 && SrcOpIdx2 == 2;
- // FMA132 A, C, b; ==> FMA231 C, A, b;
- // FMA213 B, A, c; ==> FMA213 A, B, c;
- // FMA231 C, A, b; ==> FMA132 A, C, b;
- { Form231Index, Form213Index, Form132Index },
- // 1: SrcOpIdx1 == 1 && SrcOpIdx2 == 3;
- // FMA132 A, c, B; ==> FMA132 B, c, A;
- // FMA213 B, a, C; ==> FMA231 C, a, B;
- // FMA231 C, a, B; ==> FMA213 B, a, C;
- { Form132Index, Form231Index, Form213Index },
- // 2: SrcOpIdx1 == 2 && SrcOpIdx2 == 3;
- // FMA132 a, C, B; ==> FMA213 a, B, C;
- // FMA213 b, A, C; ==> FMA132 b, C, A;
- // FMA231 c, A, B; ==> FMA231 c, B, A;
- { Form213Index, Form132Index, Form231Index }
- };
-
- // Everything is ready, just adjust the FMA opcode and return it.
- FormIndex = FormMapping[Case][FormIndex];
- return FoundOpcodesGroup[FormIndex];
+ return true;
}
bool X86InstrInfo::findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx1,
unsigned &SrcOpIdx2) const {
+ const MCInstrDesc &Desc = MI.getDesc();
+ if (!Desc.isCommutable())
+ return false;
+
switch (MI.getOpcode()) {
+ case X86::CMPSDrr:
+ case X86::CMPSSrr:
case X86::CMPPDrri:
case X86::CMPPSrri:
+ case X86::VCMPSDrr:
+ case X86::VCMPSSrr:
case X86::VCMPPDrri:
case X86::VCMPPSrri:
case X86::VCMPPDYrri:
- case X86::VCMPPSYrri: {
+ case X86::VCMPPSYrri:
+ case X86::VCMPSDZrr:
+ case X86::VCMPSSZrr:
+ case X86::VCMPPDZrri:
+ case X86::VCMPPSZrri:
+ case X86::VCMPPDZ128rri:
+ case X86::VCMPPSZ128rri:
+ case X86::VCMPPDZ256rri:
+ case X86::VCMPPSZ256rri: {
// Float comparison can be safely commuted for
// Ordered/Unordered/Equal/NotEqual tests
unsigned Imm = MI.getOperand(3).getImm() & 0x7;
@@ -3776,9 +4784,73 @@ bool X86InstrInfo::findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx1,
}
return false;
}
+ case X86::MOVSDrr:
+ case X86::MOVSSrr:
+ case X86::VMOVSDrr:
+ case X86::VMOVSSrr: {
+ if (Subtarget.hasSSE41())
+ return TargetInstrInfo::findCommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2);
+ return false;
+ }
+ case X86::VPTERNLOGDZrri: case X86::VPTERNLOGDZrmi:
+ case X86::VPTERNLOGDZ128rri: case X86::VPTERNLOGDZ128rmi:
+ case X86::VPTERNLOGDZ256rri: case X86::VPTERNLOGDZ256rmi:
+ case X86::VPTERNLOGQZrri: case X86::VPTERNLOGQZrmi:
+ case X86::VPTERNLOGQZ128rri: case X86::VPTERNLOGQZ128rmi:
+ case X86::VPTERNLOGQZ256rri: case X86::VPTERNLOGQZ256rmi:
+ case X86::VPTERNLOGDZrrik: case X86::VPTERNLOGDZrmik:
+ case X86::VPTERNLOGDZ128rrik: case X86::VPTERNLOGDZ128rmik:
+ case X86::VPTERNLOGDZ256rrik: case X86::VPTERNLOGDZ256rmik:
+ case X86::VPTERNLOGQZrrik: case X86::VPTERNLOGQZrmik:
+ case X86::VPTERNLOGQZ128rrik: case X86::VPTERNLOGQZ128rmik:
+ case X86::VPTERNLOGQZ256rrik: case X86::VPTERNLOGQZ256rmik:
+ case X86::VPTERNLOGDZrrikz: case X86::VPTERNLOGDZrmikz:
+ case X86::VPTERNLOGDZ128rrikz: case X86::VPTERNLOGDZ128rmikz:
+ case X86::VPTERNLOGDZ256rrikz: case X86::VPTERNLOGDZ256rmikz:
+ case X86::VPTERNLOGQZrrikz: case X86::VPTERNLOGQZrmikz:
+ case X86::VPTERNLOGQZ128rrikz: case X86::VPTERNLOGQZ128rmikz:
+ case X86::VPTERNLOGQZ256rrikz: case X86::VPTERNLOGQZ256rmikz:
+ return findThreeSrcCommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2);
default:
- if (isFMA3(MI.getOpcode()))
- return findFMA3CommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2);
+ const X86InstrFMA3Group *FMA3Group =
+ X86InstrFMA3Info::getFMA3Group(MI.getOpcode());
+ if (FMA3Group)
+ return findFMA3CommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2, *FMA3Group);
+
+ // Handled masked instructions since we need to skip over the mask input
+ // and the preserved input.
+ if (Desc.TSFlags & X86II::EVEX_K) {
+ // First assume that the first input is the mask operand and skip past it.
+ unsigned CommutableOpIdx1 = Desc.getNumDefs() + 1;
+ unsigned CommutableOpIdx2 = Desc.getNumDefs() + 2;
+ // Check if the first input is tied. If there isn't one then we only
+ // need to skip the mask operand which we did above.
+ if ((MI.getDesc().getOperandConstraint(Desc.getNumDefs(),
+ MCOI::TIED_TO) != -1)) {
+ // If this is zero masking instruction with a tied operand, we need to
+ // move the first index back to the first input since this must
+ // be a 3 input instruction and we want the first two non-mask inputs.
+ // Otherwise this is a 2 input instruction with a preserved input and
+ // mask, so we need to move the indices to skip one more input.
+ if (Desc.TSFlags & X86II::EVEX_Z)
+ --CommutableOpIdx1;
+ else {
+ ++CommutableOpIdx1;
+ ++CommutableOpIdx2;
+ }
+ }
+
+ if (!fixCommutedOpIndices(SrcOpIdx1, SrcOpIdx2,
+ CommutableOpIdx1, CommutableOpIdx2))
+ return false;
+
+ if (!MI.getOperand(SrcOpIdx1).isReg() ||
+ !MI.getOperand(SrcOpIdx2).isReg())
+ // No idea.
+ return false;
+ return true;
+ }
+
return TargetInstrInfo::findCommutedOpIndices(MI, SrcOpIdx1, SrcOpIdx2);
}
return false;
@@ -4296,7 +5368,10 @@ bool X86InstrInfo::analyzeBranchPredicate(MachineBasicBlock &MBB,
return true;
}
-unsigned X86InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned X86InstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
@@ -4316,15 +5391,17 @@ unsigned X86InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return Count;
}
-unsigned X86InstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned X86InstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"X86 branch conditions have one component!");
+ assert(!BytesAdded && "code size not handled");
if (Cond.empty()) {
// Unconditional branch?
@@ -4430,16 +5507,63 @@ static bool isHReg(unsigned Reg) {
}
// Try and copy between VR128/VR64 and GR64 registers.
-static unsigned CopyToFromAsymmetricReg(unsigned DestReg, unsigned SrcReg,
+static unsigned CopyToFromAsymmetricReg(unsigned &DestReg, unsigned &SrcReg,
const X86Subtarget &Subtarget) {
+ bool HasAVX = Subtarget.hasAVX();
+ bool HasAVX512 = Subtarget.hasAVX512();
+
+ // SrcReg(MaskReg) -> DestReg(GR64)
+ // SrcReg(MaskReg) -> DestReg(GR32)
+ // SrcReg(MaskReg) -> DestReg(GR16)
+ // SrcReg(MaskReg) -> DestReg(GR8)
+
+ // All KMASK RegClasses hold the same k registers, can be tested against anyone.
+ if (X86::VK16RegClass.contains(SrcReg)) {
+ if (X86::GR64RegClass.contains(DestReg)) {
+ assert(Subtarget.hasBWI());
+ return X86::KMOVQrk;
+ }
+ if (X86::GR32RegClass.contains(DestReg))
+ return Subtarget.hasBWI() ? X86::KMOVDrk : X86::KMOVWrk;
+ if (X86::GR16RegClass.contains(DestReg)) {
+ DestReg = getX86SubSuperRegister(DestReg, 32);
+ return X86::KMOVWrk;
+ }
+ if (X86::GR8RegClass.contains(DestReg)) {
+ DestReg = getX86SubSuperRegister(DestReg, 32);
+ return Subtarget.hasDQI() ? X86::KMOVBrk : X86::KMOVWrk;
+ }
+ }
+
+ // SrcReg(GR64) -> DestReg(MaskReg)
+ // SrcReg(GR32) -> DestReg(MaskReg)
+ // SrcReg(GR16) -> DestReg(MaskReg)
+ // SrcReg(GR8) -> DestReg(MaskReg)
+
+ // All KMASK RegClasses hold the same k registers, can be tested against anyone.
+ if (X86::VK16RegClass.contains(DestReg)) {
+ if (X86::GR64RegClass.contains(SrcReg)) {
+ assert(Subtarget.hasBWI());
+ return X86::KMOVQkr;
+ }
+ if (X86::GR32RegClass.contains(SrcReg))
+ return Subtarget.hasBWI() ? X86::KMOVDkr : X86::KMOVWkr;
+ if (X86::GR16RegClass.contains(SrcReg)) {
+ SrcReg = getX86SubSuperRegister(SrcReg, 32);
+ return X86::KMOVWkr;
+ }
+ if (X86::GR8RegClass.contains(SrcReg)) {
+ SrcReg = getX86SubSuperRegister(SrcReg, 32);
+ return Subtarget.hasDQI() ? X86::KMOVBkr : X86::KMOVWkr;
+ }
+ }
+
// SrcReg(VR128) -> DestReg(GR64)
// SrcReg(VR64) -> DestReg(GR64)
// SrcReg(GR64) -> DestReg(VR128)
// SrcReg(GR64) -> DestReg(VR64)
- bool HasAVX = Subtarget.hasAVX();
- bool HasAVX512 = Subtarget.hasAVX512();
if (X86::GR64RegClass.contains(DestReg)) {
if (X86::VR128XRegClass.contains(SrcReg))
// Copy from a VR128 register to a GR64 register.
@@ -4479,96 +5603,13 @@ static unsigned CopyToFromAsymmetricReg(unsigned DestReg, unsigned SrcReg,
return 0;
}
-static bool isMaskRegClass(const TargetRegisterClass *RC) {
- // All KMASK RegClasses hold the same k registers, can be tested against anyone.
- return X86::VK16RegClass.hasSubClassEq(RC);
-}
-
-static bool MaskRegClassContains(unsigned Reg) {
- // All KMASK RegClasses hold the same k registers, can be tested against anyone.
- return X86::VK16RegClass.contains(Reg);
-}
-
-static bool GRRegClassContains(unsigned Reg) {
- return X86::GR64RegClass.contains(Reg) ||
- X86::GR32RegClass.contains(Reg) ||
- X86::GR16RegClass.contains(Reg) ||
- X86::GR8RegClass.contains(Reg);
-}
-static
-unsigned copyPhysRegOpcode_AVX512_DQ(unsigned& DestReg, unsigned& SrcReg) {
- if (MaskRegClassContains(SrcReg) && X86::GR8RegClass.contains(DestReg)) {
- DestReg = getX86SubSuperRegister(DestReg, 32);
- return X86::KMOVBrk;
- }
- if (MaskRegClassContains(DestReg) && X86::GR8RegClass.contains(SrcReg)) {
- SrcReg = getX86SubSuperRegister(SrcReg, 32);
- return X86::KMOVBkr;
- }
- return 0;
-}
-
-static
-unsigned copyPhysRegOpcode_AVX512_BW(unsigned& DestReg, unsigned& SrcReg) {
- if (MaskRegClassContains(SrcReg) && MaskRegClassContains(DestReg))
- return X86::KMOVQkk;
- if (MaskRegClassContains(SrcReg) && X86::GR32RegClass.contains(DestReg))
- return X86::KMOVDrk;
- if (MaskRegClassContains(SrcReg) && X86::GR64RegClass.contains(DestReg))
- return X86::KMOVQrk;
- if (MaskRegClassContains(DestReg) && X86::GR32RegClass.contains(SrcReg))
- return X86::KMOVDkr;
- if (MaskRegClassContains(DestReg) && X86::GR64RegClass.contains(SrcReg))
- return X86::KMOVQkr;
- return 0;
-}
-
-static
-unsigned copyPhysRegOpcode_AVX512(unsigned& DestReg, unsigned& SrcReg,
- const X86Subtarget &Subtarget)
-{
- if (Subtarget.hasDQI())
- if (auto Opc = copyPhysRegOpcode_AVX512_DQ(DestReg, SrcReg))
- return Opc;
- if (Subtarget.hasBWI())
- if (auto Opc = copyPhysRegOpcode_AVX512_BW(DestReg, SrcReg))
- return Opc;
- if (X86::VR128XRegClass.contains(DestReg, SrcReg)) {
- if (Subtarget.hasVLX())
- return X86::VMOVAPSZ128rr;
- DestReg = get512BitSuperRegister(DestReg);
- SrcReg = get512BitSuperRegister(SrcReg);
- return X86::VMOVAPSZrr;
- }
- if (X86::VR256XRegClass.contains(DestReg, SrcReg)) {
- if (Subtarget.hasVLX())
- return X86::VMOVAPSZ256rr;
- DestReg = get512BitSuperRegister(DestReg);
- SrcReg = get512BitSuperRegister(SrcReg);
- return X86::VMOVAPSZrr;
- }
- if (X86::VR512RegClass.contains(DestReg, SrcReg))
- return X86::VMOVAPSZrr;
- if (MaskRegClassContains(DestReg) && MaskRegClassContains(SrcReg))
- return X86::KMOVWkk;
- if (MaskRegClassContains(DestReg) && GRRegClassContains(SrcReg)) {
- SrcReg = getX86SubSuperRegister(SrcReg, 32);
- return X86::KMOVWkr;
- }
- if (GRRegClassContains(DestReg) && MaskRegClassContains(SrcReg)) {
- DestReg = getX86SubSuperRegister(DestReg, 32);
- return X86::KMOVWrk;
- }
- return 0;
-}
-
void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg,
unsigned SrcReg, bool KillSrc) const {
// First deal with the normal symmetric copies.
bool HasAVX = Subtarget.hasAVX();
- bool HasAVX512 = Subtarget.hasAVX512();
+ bool HasVLX = Subtarget.hasVLX();
unsigned Opc = 0;
if (X86::GR64RegClass.contains(DestReg, SrcReg))
Opc = X86::MOV64rr;
@@ -4590,12 +5631,41 @@ void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
}
else if (X86::VR64RegClass.contains(DestReg, SrcReg))
Opc = X86::MMX_MOVQ64rr;
- else if (HasAVX512)
- Opc = copyPhysRegOpcode_AVX512(DestReg, SrcReg, Subtarget);
- else if (X86::VR128RegClass.contains(DestReg, SrcReg))
- Opc = HasAVX ? X86::VMOVAPSrr : X86::MOVAPSrr;
- else if (X86::VR256RegClass.contains(DestReg, SrcReg))
- Opc = X86::VMOVAPSYrr;
+ else if (X86::VR128XRegClass.contains(DestReg, SrcReg)) {
+ if (HasVLX)
+ Opc = X86::VMOVAPSZ128rr;
+ else if (X86::VR128RegClass.contains(DestReg, SrcReg))
+ Opc = HasAVX ? X86::VMOVAPSrr : X86::MOVAPSrr;
+ else {
+ // If this an extended register and we don't have VLX we need to use a
+ // 512-bit move.
+ Opc = X86::VMOVAPSZrr;
+ const TargetRegisterInfo *TRI = &getRegisterInfo();
+ DestReg = TRI->getMatchingSuperReg(DestReg, X86::sub_xmm,
+ &X86::VR512RegClass);
+ SrcReg = TRI->getMatchingSuperReg(SrcReg, X86::sub_xmm,
+ &X86::VR512RegClass);
+ }
+ } else if (X86::VR256XRegClass.contains(DestReg, SrcReg)) {
+ if (HasVLX)
+ Opc = X86::VMOVAPSZ256rr;
+ else if (X86::VR256RegClass.contains(DestReg, SrcReg))
+ Opc = X86::VMOVAPSYrr;
+ else {
+ // If this an extended register and we don't have VLX we need to use a
+ // 512-bit move.
+ Opc = X86::VMOVAPSZrr;
+ const TargetRegisterInfo *TRI = &getRegisterInfo();
+ DestReg = TRI->getMatchingSuperReg(DestReg, X86::sub_ymm,
+ &X86::VR512RegClass);
+ SrcReg = TRI->getMatchingSuperReg(SrcReg, X86::sub_ymm,
+ &X86::VR512RegClass);
+ }
+ } else if (X86::VR512RegClass.contains(DestReg, SrcReg))
+ Opc = X86::VMOVAPSZrr;
+ // All KMASK RegClasses hold the same k registers, can be tested against anyone.
+ else if (X86::VK16RegClass.contains(DestReg, SrcReg))
+ Opc = Subtarget.hasBWI() ? X86::KMOVQkk : X86::KMOVWkk;
if (!Opc)
Opc = CopyToFromAsymmetricReg(DestReg, SrcReg, Subtarget);
@@ -4708,37 +5778,15 @@ void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
llvm_unreachable("Cannot emit physreg copy instruction");
}
-static unsigned getLoadStoreMaskRegOpcode(const TargetRegisterClass *RC,
- bool load) {
- switch (RC->getSize()) {
- default:
- llvm_unreachable("Unknown spill size");
- case 2:
- return load ? X86::KMOVWkm : X86::KMOVWmk;
- case 4:
- return load ? X86::KMOVDkm : X86::KMOVDmk;
- case 8:
- return load ? X86::KMOVQkm : X86::KMOVQmk;
- }
-}
-
static unsigned getLoadStoreRegOpcode(unsigned Reg,
const TargetRegisterClass *RC,
bool isStackAligned,
const X86Subtarget &STI,
bool load) {
- if (STI.hasAVX512()) {
- if (isMaskRegClass(RC))
- return getLoadStoreMaskRegOpcode(RC, load);
- if (RC->getSize() == 4 && X86::FR32XRegClass.hasSubClassEq(RC))
- return load ? X86::VMOVSSZrm : X86::VMOVSSZmr;
- if (RC->getSize() == 8 && X86::FR64XRegClass.hasSubClassEq(RC))
- return load ? X86::VMOVSDZrm : X86::VMOVSDZmr;
- if (X86::VR512RegClass.hasSubClassEq(RC))
- return load ? X86::VMOVUPSZrm : X86::VMOVUPSZmr;
- }
-
bool HasAVX = STI.hasAVX();
+ bool HasAVX512 = STI.hasAVX512();
+ bool HasVLX = STI.hasVLX();
+
switch (RC->getSize()) {
default:
llvm_unreachable("Unknown spill size");
@@ -4751,69 +5799,85 @@ static unsigned getLoadStoreRegOpcode(unsigned Reg,
return load ? X86::MOV8rm_NOREX : X86::MOV8mr_NOREX;
return load ? X86::MOV8rm : X86::MOV8mr;
case 2:
+ if (X86::VK16RegClass.hasSubClassEq(RC))
+ return load ? X86::KMOVWkm : X86::KMOVWmk;
assert(X86::GR16RegClass.hasSubClassEq(RC) && "Unknown 2-byte regclass");
return load ? X86::MOV16rm : X86::MOV16mr;
case 4:
if (X86::GR32RegClass.hasSubClassEq(RC))
return load ? X86::MOV32rm : X86::MOV32mr;
- if (X86::FR32RegClass.hasSubClassEq(RC))
+ if (X86::FR32XRegClass.hasSubClassEq(RC))
return load ?
- (HasAVX ? X86::VMOVSSrm : X86::MOVSSrm) :
- (HasAVX ? X86::VMOVSSmr : X86::MOVSSmr);
+ (HasAVX512 ? X86::VMOVSSZrm : HasAVX ? X86::VMOVSSrm : X86::MOVSSrm) :
+ (HasAVX512 ? X86::VMOVSSZmr : HasAVX ? X86::VMOVSSmr : X86::MOVSSmr);
if (X86::RFP32RegClass.hasSubClassEq(RC))
return load ? X86::LD_Fp32m : X86::ST_Fp32m;
+ if (X86::VK32RegClass.hasSubClassEq(RC))
+ return load ? X86::KMOVDkm : X86::KMOVDmk;
llvm_unreachable("Unknown 4-byte regclass");
case 8:
if (X86::GR64RegClass.hasSubClassEq(RC))
return load ? X86::MOV64rm : X86::MOV64mr;
- if (X86::FR64RegClass.hasSubClassEq(RC))
+ if (X86::FR64XRegClass.hasSubClassEq(RC))
return load ?
- (HasAVX ? X86::VMOVSDrm : X86::MOVSDrm) :
- (HasAVX ? X86::VMOVSDmr : X86::MOVSDmr);
+ (HasAVX512 ? X86::VMOVSDZrm : HasAVX ? X86::VMOVSDrm : X86::MOVSDrm) :
+ (HasAVX512 ? X86::VMOVSDZmr : HasAVX ? X86::VMOVSDmr : X86::MOVSDmr);
if (X86::VR64RegClass.hasSubClassEq(RC))
return load ? X86::MMX_MOVQ64rm : X86::MMX_MOVQ64mr;
if (X86::RFP64RegClass.hasSubClassEq(RC))
return load ? X86::LD_Fp64m : X86::ST_Fp64m;
+ if (X86::VK64RegClass.hasSubClassEq(RC))
+ return load ? X86::KMOVQkm : X86::KMOVQmk;
llvm_unreachable("Unknown 8-byte regclass");
case 10:
assert(X86::RFP80RegClass.hasSubClassEq(RC) && "Unknown 10-byte regclass");
return load ? X86::LD_Fp80m : X86::ST_FpP80m;
case 16: {
- assert((X86::VR128RegClass.hasSubClassEq(RC) ||
- X86::VR128XRegClass.hasSubClassEq(RC))&& "Unknown 16-byte regclass");
+ assert(X86::VR128XRegClass.hasSubClassEq(RC) && "Unknown 16-byte regclass");
// If stack is realigned we can use aligned stores.
- if (X86::VR128RegClass.hasSubClassEq(RC)) {
- if (isStackAligned)
- return load ? (HasAVX ? X86::VMOVAPSrm : X86::MOVAPSrm)
- : (HasAVX ? X86::VMOVAPSmr : X86::MOVAPSmr);
- else
- return load ? (HasAVX ? X86::VMOVUPSrm : X86::MOVUPSrm)
- : (HasAVX ? X86::VMOVUPSmr : X86::MOVUPSmr);
- }
- assert(STI.hasVLX() && "Using extended register requires VLX");
if (isStackAligned)
- return load ? X86::VMOVAPSZ128rm : X86::VMOVAPSZ128mr;
+ return load ?
+ (HasVLX ? X86::VMOVAPSZ128rm :
+ HasAVX512 ? X86::VMOVAPSZ128rm_NOVLX :
+ HasAVX ? X86::VMOVAPSrm :
+ X86::MOVAPSrm):
+ (HasVLX ? X86::VMOVAPSZ128mr :
+ HasAVX512 ? X86::VMOVAPSZ128mr_NOVLX :
+ HasAVX ? X86::VMOVAPSmr :
+ X86::MOVAPSmr);
else
- return load ? X86::VMOVUPSZ128rm : X86::VMOVUPSZ128mr;
+ return load ?
+ (HasVLX ? X86::VMOVUPSZ128rm :
+ HasAVX512 ? X86::VMOVUPSZ128rm_NOVLX :
+ HasAVX ? X86::VMOVUPSrm :
+ X86::MOVUPSrm):
+ (HasVLX ? X86::VMOVUPSZ128mr :
+ HasAVX512 ? X86::VMOVUPSZ128mr_NOVLX :
+ HasAVX ? X86::VMOVUPSmr :
+ X86::MOVUPSmr);
}
case 32:
- assert((X86::VR256RegClass.hasSubClassEq(RC) ||
- X86::VR256XRegClass.hasSubClassEq(RC)) && "Unknown 32-byte regclass");
+ assert(X86::VR256XRegClass.hasSubClassEq(RC) && "Unknown 32-byte regclass");
// If stack is realigned we can use aligned stores.
- if (X86::VR256RegClass.hasSubClassEq(RC)) {
- if (isStackAligned)
- return load ? X86::VMOVAPSYrm : X86::VMOVAPSYmr;
- else
- return load ? X86::VMOVUPSYrm : X86::VMOVUPSYmr;
- }
- assert(STI.hasVLX() && "Using extended register requires VLX");
if (isStackAligned)
- return load ? X86::VMOVAPSZ256rm : X86::VMOVAPSZ256mr;
+ return load ?
+ (HasVLX ? X86::VMOVAPSZ256rm :
+ HasAVX512 ? X86::VMOVAPSZ256rm_NOVLX :
+ X86::VMOVAPSYrm) :
+ (HasVLX ? X86::VMOVAPSZ256mr :
+ HasAVX512 ? X86::VMOVAPSZ256mr_NOVLX :
+ X86::VMOVAPSYmr);
else
- return load ? X86::VMOVUPSZ256rm : X86::VMOVUPSZ256mr;
+ return load ?
+ (HasVLX ? X86::VMOVUPSZ256rm :
+ HasAVX512 ? X86::VMOVUPSZ256rm_NOVLX :
+ X86::VMOVUPSYrm) :
+ (HasVLX ? X86::VMOVUPSZ256mr :
+ HasAVX512 ? X86::VMOVUPSZ256mr_NOVLX :
+ X86::VMOVUPSYmr);
case 64:
assert(X86::VR512RegClass.hasSubClassEq(RC) && "Unknown 64-byte regclass");
- assert(STI.hasVLX() && "Using 512-bit register requires AVX512");
+ assert(STI.hasAVX512() && "Using 512-bit register requires AVX512");
if (isStackAligned)
return load ? X86::VMOVAPSZrm : X86::VMOVAPSZmr;
else
@@ -4851,8 +5915,7 @@ bool X86InstrInfo::getMemOpBaseRegImmOfs(MachineInstr &MemOp, unsigned &BaseReg,
Offset = DispMO.getImm();
- return MemOp.getOperand(MemRefBegin + X86::AddrIndexReg).getReg() ==
- X86::NoRegister;
+ return true;
}
static unsigned getStoreRegOpcode(unsigned SrcReg,
@@ -4876,7 +5939,7 @@ void X86InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
const MachineFunction &MF = *MBB.getParent();
- assert(MF.getFrameInfo()->getObjectSize(FrameIdx) >= RC->getSize() &&
+ assert(MF.getFrameInfo().getObjectSize(FrameIdx) >= RC->getSize() &&
"Stack slot too small for store");
unsigned Alignment = std::max<uint32_t>(RC->getSize(), 16);
bool isAligned =
@@ -4954,6 +6017,8 @@ bool X86InstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
case X86::CMP16ri:
case X86::CMP16ri8:
case X86::CMP8ri:
+ if (!MI.getOperand(1).isImm())
+ return false;
SrcReg = MI.getOperand(0).getReg();
SrcReg2 = 0;
CmpMask = ~0;
@@ -4985,6 +6050,8 @@ bool X86InstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
case X86::SUB16ri:
case X86::SUB16ri8:
case X86::SUB8ri:
+ if (!MI.getOperand(2).isImm())
+ return false;
SrcReg = MI.getOperand(1).getReg();
SrcReg2 = 0;
CmpMask = ~0;
@@ -5263,9 +6330,9 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg,
// If the definition is in this basic block, RE points to the definition;
// otherwise, RE is the rend of the basic block.
MachineBasicBlock::reverse_iterator
- RI = MachineBasicBlock::reverse_iterator(I),
+ RI = ++I.getReverse(),
RE = CmpInstr.getParent() == MI->getParent()
- ? MachineBasicBlock::reverse_iterator(++Def) /* points to MI */
+ ? Def.getReverse() /* points to MI */
: CmpInstr.getParent()->rend();
MachineInstr *Movr0Inst = nullptr;
for (; RI != RE; ++RI) {
@@ -5411,9 +6478,8 @@ bool X86InstrInfo::optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg,
if (Movr0Inst) {
// Look backwards until we find a def that doesn't use the current EFLAGS.
Def = Sub;
- MachineBasicBlock::reverse_iterator
- InsertI = MachineBasicBlock::reverse_iterator(++Def),
- InsertE = Sub->getParent()->rend();
+ MachineBasicBlock::reverse_iterator InsertI = Def.getReverse(),
+ InsertE = Sub->getParent()->rend();
for (; InsertI != InsertE; ++InsertI) {
MachineInstr *Instr = &*InsertI;
if (!Instr->readsRegister(X86::EFLAGS, TRI) &&
@@ -5455,14 +6521,6 @@ MachineInstr *X86InstrInfo::optimizeLoadInstr(MachineInstr &MI,
const MachineRegisterInfo *MRI,
unsigned &FoldAsLoadDefReg,
MachineInstr *&DefMI) const {
- if (FoldAsLoadDefReg == 0)
- return nullptr;
- // To be conservative, if there exists another load, clear the load candidate.
- if (MI.mayLoad()) {
- FoldAsLoadDefReg = 0;
- return nullptr;
- }
-
// Check whether we can move DefMI here.
DefMI = MRI->getVRegDef(FoldAsLoadDefReg);
assert(DefMI);
@@ -5471,27 +6529,24 @@ MachineInstr *X86InstrInfo::optimizeLoadInstr(MachineInstr &MI,
return nullptr;
// Collect information about virtual register operands of MI.
- unsigned SrcOperandId = 0;
- bool FoundSrcOperand = false;
- for (unsigned i = 0, e = MI.getDesc().getNumOperands(); i != e; ++i) {
+ SmallVector<unsigned, 1> SrcOperandIds;
+ for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI.getOperand(i);
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
if (Reg != FoldAsLoadDefReg)
continue;
- // Do not fold if we have a subreg use or a def or multiple uses.
- if (MO.getSubReg() || MO.isDef() || FoundSrcOperand)
+ // Do not fold if we have a subreg use or a def.
+ if (MO.getSubReg() || MO.isDef())
return nullptr;
-
- SrcOperandId = i;
- FoundSrcOperand = true;
+ SrcOperandIds.push_back(i);
}
- if (!FoundSrcOperand)
+ if (SrcOperandIds.empty())
return nullptr;
// Check whether we can fold the def into SrcOperandId.
- if (MachineInstr *FoldMI = foldMemoryOperand(MI, SrcOperandId, *DefMI)) {
+ if (MachineInstr *FoldMI = foldMemoryOperand(MI, SrcOperandIds, *DefMI)) {
FoldAsLoadDefReg = 0;
return FoldMI;
}
@@ -5553,7 +6608,9 @@ static bool expandMOV32r1(MachineInstrBuilder &MIB, const TargetInstrInfo &TII,
return true;
}
-bool X86InstrInfo::ExpandMOVImmSExti8(MachineInstrBuilder &MIB) const {
+static bool ExpandMOVImmSExti8(MachineInstrBuilder &MIB,
+ const TargetInstrInfo &TII,
+ const X86Subtarget &Subtarget) {
MachineBasicBlock &MBB = *MIB->getParent();
DebugLoc DL = MIB->getDebugLoc();
int64_t Imm = MIB->getOperand(1).getImm();
@@ -5570,23 +6627,23 @@ bool X86InstrInfo::ExpandMOVImmSExti8(MachineInstrBuilder &MIB) const {
X86MachineFunctionInfo *X86FI =
MBB.getParent()->getInfo<X86MachineFunctionInfo>();
if (X86FI->getUsesRedZone()) {
- MIB->setDesc(get(MIB->getOpcode() == X86::MOV32ImmSExti8 ? X86::MOV32ri
- : X86::MOV64ri));
+ MIB->setDesc(TII.get(MIB->getOpcode() ==
+ X86::MOV32ImmSExti8 ? X86::MOV32ri : X86::MOV64ri));
return true;
}
// 64-bit mode doesn't have 32-bit push/pop, so use 64-bit operations and
// widen the register if necessary.
StackAdjustment = 8;
- BuildMI(MBB, I, DL, get(X86::PUSH64i8)).addImm(Imm);
- MIB->setDesc(get(X86::POP64r));
+ BuildMI(MBB, I, DL, TII.get(X86::PUSH64i8)).addImm(Imm);
+ MIB->setDesc(TII.get(X86::POP64r));
MIB->getOperand(0)
.setReg(getX86SubSuperRegister(MIB->getOperand(0).getReg(), 64));
} else {
assert(MIB->getOpcode() == X86::MOV32ImmSExti8);
StackAdjustment = 4;
- BuildMI(MBB, I, DL, get(X86::PUSH32i8)).addImm(Imm);
- MIB->setDesc(get(X86::POP32r));
+ BuildMI(MBB, I, DL, TII.get(X86::PUSH32i8)).addImm(Imm);
+ MIB->setDesc(TII.get(X86::POP32r));
}
// Build CFI if necessary.
@@ -5616,7 +6673,9 @@ static void expandLoadStackGuard(MachineInstrBuilder &MIB,
unsigned Reg = MIB->getOperand(0).getReg();
const GlobalValue *GV =
cast<GlobalValue>((*MIB->memoperands_begin())->getValue());
- auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant;
+ auto Flags = MachineMemOperand::MOLoad |
+ MachineMemOperand::MODereferenceable |
+ MachineMemOperand::MOInvariant;
MachineMemOperand *MMO = MBB.getParent()->getMachineMemOperand(
MachinePointerInfo::getGOT(*MBB.getParent()), Flags, 8, 8);
MachineBasicBlock::iterator I = MIB.getInstr();
@@ -5629,6 +6688,53 @@ static void expandLoadStackGuard(MachineInstrBuilder &MIB,
MIB.addReg(Reg, RegState::Kill).addImm(1).addReg(0).addImm(0).addReg(0);
}
+// This is used to handle spills for 128/256-bit registers when we have AVX512,
+// but not VLX. If it uses an extended register we need to use an instruction
+// that loads the lower 128/256-bit, but is available with only AVX512F.
+static bool expandNOVLXLoad(MachineInstrBuilder &MIB,
+ const TargetRegisterInfo *TRI,
+ const MCInstrDesc &LoadDesc,
+ const MCInstrDesc &BroadcastDesc,
+ unsigned SubIdx) {
+ unsigned DestReg = MIB->getOperand(0).getReg();
+ // Check if DestReg is XMM16-31 or YMM16-31.
+ if (TRI->getEncodingValue(DestReg) < 16) {
+ // We can use a normal VEX encoded load.
+ MIB->setDesc(LoadDesc);
+ } else {
+ // Use a 128/256-bit VBROADCAST instruction.
+ MIB->setDesc(BroadcastDesc);
+ // Change the destination to a 512-bit register.
+ DestReg = TRI->getMatchingSuperReg(DestReg, SubIdx, &X86::VR512RegClass);
+ MIB->getOperand(0).setReg(DestReg);
+ }
+ return true;
+}
+
+// This is used to handle spills for 128/256-bit registers when we have AVX512,
+// but not VLX. If it uses an extended register we need to use an instruction
+// that stores the lower 128/256-bit, but is available with only AVX512F.
+static bool expandNOVLXStore(MachineInstrBuilder &MIB,
+ const TargetRegisterInfo *TRI,
+ const MCInstrDesc &StoreDesc,
+ const MCInstrDesc &ExtractDesc,
+ unsigned SubIdx) {
+ unsigned SrcReg = MIB->getOperand(X86::AddrNumOperands).getReg();
+ // Check if DestReg is XMM16-31 or YMM16-31.
+ if (TRI->getEncodingValue(SrcReg) < 16) {
+ // We can use a normal VEX encoded store.
+ MIB->setDesc(StoreDesc);
+ } else {
+ // Use a VEXTRACTF instruction.
+ MIB->setDesc(ExtractDesc);
+ // Change the destination to a 512-bit register.
+ SrcReg = TRI->getMatchingSuperReg(SrcReg, SubIdx, &X86::VR512RegClass);
+ MIB->getOperand(X86::AddrNumOperands).setReg(SrcReg);
+ MIB.addImm(0x0); // Append immediate to extract from the lower bits.
+ }
+
+ return true;
+}
bool X86InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
bool HasAVX = Subtarget.hasAVX();
MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
@@ -5641,7 +6747,7 @@ bool X86InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
return expandMOV32r1(MIB, *this, /*MinusOne=*/ true);
case X86::MOV32ImmSExti8:
case X86::MOV64ImmSExti8:
- return ExpandMOVImmSExti8(MIB);
+ return ExpandMOVImmSExti8(MIB, *this, Subtarget);
case X86::SETB_C8r:
return Expand2AddrUndef(MIB, get(X86::SBB8rr));
case X86::SETB_C16r:
@@ -5663,6 +6769,9 @@ bool X86InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
return Expand2AddrUndef(MIB, get(X86::VPXORDZ256rr));
case X86::AVX512_512_SET0:
return Expand2AddrUndef(MIB, get(X86::VPXORDZrr));
+ case X86::AVX512_FsFLD0SS:
+ case X86::AVX512_FsFLD0SD:
+ return Expand2AddrUndef(MIB, get(X86::VXORPSZ128rr));
case X86::V_SETALLONES:
return Expand2AddrUndef(MIB, get(HasAVX ? X86::VPCMPEQDrr : X86::PCMPEQDrr));
case X86::AVX2_SETALLONES:
@@ -5676,6 +6785,45 @@ bool X86InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
.addReg(Reg, RegState::Undef).addImm(0xff);
return true;
}
+ case X86::AVX512_512_SEXT_MASK_32:
+ case X86::AVX512_512_SEXT_MASK_64: {
+ unsigned Reg = MIB->getOperand(0).getReg();
+ unsigned MaskReg = MIB->getOperand(1).getReg();
+ unsigned MaskState = getRegState(MIB->getOperand(1));
+ unsigned Opc = (MI.getOpcode() == X86::AVX512_512_SEXT_MASK_64) ?
+ X86::VPTERNLOGQZrrikz : X86::VPTERNLOGDZrrikz;
+ MI.RemoveOperand(1);
+ MIB->setDesc(get(Opc));
+ // VPTERNLOG needs 3 register inputs and an immediate.
+ // 0xff will return 1s for any input.
+ MIB.addReg(Reg, RegState::Undef).addReg(MaskReg, MaskState)
+ .addReg(Reg, RegState::Undef).addReg(Reg, RegState::Undef).addImm(0xff);
+ return true;
+ }
+ case X86::VMOVAPSZ128rm_NOVLX:
+ return expandNOVLXLoad(MIB, &getRegisterInfo(), get(X86::VMOVAPSrm),
+ get(X86::VBROADCASTF32X4rm), X86::sub_xmm);
+ case X86::VMOVUPSZ128rm_NOVLX:
+ return expandNOVLXLoad(MIB, &getRegisterInfo(), get(X86::VMOVUPSrm),
+ get(X86::VBROADCASTF32X4rm), X86::sub_xmm);
+ case X86::VMOVAPSZ256rm_NOVLX:
+ return expandNOVLXLoad(MIB, &getRegisterInfo(), get(X86::VMOVAPSYrm),
+ get(X86::VBROADCASTF64X4rm), X86::sub_ymm);
+ case X86::VMOVUPSZ256rm_NOVLX:
+ return expandNOVLXLoad(MIB, &getRegisterInfo(), get(X86::VMOVUPSYrm),
+ get(X86::VBROADCASTF64X4rm), X86::sub_ymm);
+ case X86::VMOVAPSZ128mr_NOVLX:
+ return expandNOVLXStore(MIB, &getRegisterInfo(), get(X86::VMOVAPSmr),
+ get(X86::VEXTRACTF32x4Zmr), X86::sub_xmm);
+ case X86::VMOVUPSZ128mr_NOVLX:
+ return expandNOVLXStore(MIB, &getRegisterInfo(), get(X86::VMOVUPSmr),
+ get(X86::VEXTRACTF32x4Zmr), X86::sub_xmm);
+ case X86::VMOVAPSZ256mr_NOVLX:
+ return expandNOVLXStore(MIB, &getRegisterInfo(), get(X86::VMOVAPSYmr),
+ get(X86::VEXTRACTF64x4Zmr), X86::sub_ymm);
+ case X86::VMOVUPSZ256mr_NOVLX:
+ return expandNOVLXStore(MIB, &getRegisterInfo(), get(X86::VMOVUPSYmr),
+ get(X86::VEXTRACTF64x4Zmr), X86::sub_ymm);
case X86::TEST8ri_NOREX:
MI.setDesc(get(X86::TEST8ri));
return true;
@@ -5801,6 +6949,7 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom(
switch (MI.getOpcode()) {
case X86::INSERTPSrr:
case X86::VINSERTPSrr:
+ case X86::VINSERTPSZrr:
// Attempt to convert the load of inserted vector into a fold load
// of a single float.
if (OpNum == 2) {
@@ -5814,8 +6963,9 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom(
int PtrOffset = SrcIdx * 4;
unsigned NewImm = (DstIdx << 4) | ZMask;
unsigned NewOpCode =
- (MI.getOpcode() == X86::VINSERTPSrr ? X86::VINSERTPSrm
- : X86::INSERTPSrm);
+ (MI.getOpcode() == X86::VINSERTPSZrr) ? X86::VINSERTPSZrm :
+ (MI.getOpcode() == X86::VINSERTPSrr) ? X86::VINSERTPSrm :
+ X86::INSERTPSrm;
MachineInstr *NewMI =
FuseInst(MF, NewOpCode, OpNum, MOs, InsertPt, MI, *this, PtrOffset);
NewMI->getOperand(NewMI->getNumOperands() - 1).setImm(NewImm);
@@ -5825,6 +6975,7 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom(
break;
case X86::MOVHLPSrr:
case X86::VMOVHLPSrr:
+ case X86::VMOVHLPSZrr:
// Move the upper 64-bits of the second operand to the lower 64-bits.
// To fold the load, adjust the pointer to the upper and use (V)MOVLPS.
// TODO: In most cases AVX doesn't have a 8-byte alignment requirement.
@@ -5832,8 +6983,9 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom(
unsigned RCSize = getRegClass(MI.getDesc(), OpNum, &RI, MF)->getSize();
if (Size <= RCSize && 8 <= Align) {
unsigned NewOpCode =
- (MI.getOpcode() == X86::VMOVHLPSrr ? X86::VMOVLPSrm
- : X86::MOVLPSrm);
+ (MI.getOpcode() == X86::VMOVHLPSZrr) ? X86::VMOVLPSZ128rm :
+ (MI.getOpcode() == X86::VMOVHLPSrr) ? X86::VMOVLPSrm :
+ X86::MOVLPSrm;
MachineInstr *NewMI =
FuseInst(MF, NewOpCode, OpNum, MOs, InsertPt, MI, *this, 8);
return NewMI;
@@ -6042,12 +7194,8 @@ static bool hasPartialRegUpdate(unsigned Opcode) {
case X86::CVTSI2SD64rm:
case X86::CVTSD2SSrr:
case X86::CVTSD2SSrm:
- case X86::Int_CVTSD2SSrr:
- case X86::Int_CVTSD2SSrm:
case X86::CVTSS2SDrr:
case X86::CVTSS2SDrm:
- case X86::Int_CVTSS2SDrr:
- case X86::Int_CVTSS2SDrm:
case X86::MOVHPDrm:
case X86::MOVHPSrm:
case X86::MOVLPDrm:
@@ -6058,10 +7206,8 @@ static bool hasPartialRegUpdate(unsigned Opcode) {
case X86::RCPSSm_Int:
case X86::ROUNDSDr:
case X86::ROUNDSDm:
- case X86::ROUNDSDr_Int:
case X86::ROUNDSSr:
case X86::ROUNDSSm:
- case X86::ROUNDSSr_Int:
case X86::RSQRTSSr:
case X86::RSQRTSSm:
case X86::RSQRTSSr_Int:
@@ -6134,28 +7280,95 @@ static bool hasUndefRegUpdate(unsigned Opcode) {
case X86::Int_VCVTSS2SDrr:
case X86::Int_VCVTSS2SDrm:
case X86::VRCPSSr:
+ case X86::VRCPSSr_Int:
case X86::VRCPSSm:
case X86::VRCPSSm_Int:
case X86::VROUNDSDr:
case X86::VROUNDSDm:
case X86::VROUNDSDr_Int:
+ case X86::VROUNDSDm_Int:
case X86::VROUNDSSr:
case X86::VROUNDSSm:
case X86::VROUNDSSr_Int:
+ case X86::VROUNDSSm_Int:
case X86::VRSQRTSSr:
+ case X86::VRSQRTSSr_Int:
case X86::VRSQRTSSm:
case X86::VRSQRTSSm_Int:
case X86::VSQRTSSr:
+ case X86::VSQRTSSr_Int:
case X86::VSQRTSSm:
case X86::VSQRTSSm_Int:
case X86::VSQRTSDr:
+ case X86::VSQRTSDr_Int:
case X86::VSQRTSDm:
case X86::VSQRTSDm_Int:
- // AVX-512
+ // AVX-512
+ case X86::VCVTSI2SSZrr:
+ case X86::VCVTSI2SSZrm:
+ case X86::VCVTSI2SSZrr_Int:
+ case X86::VCVTSI2SSZrrb_Int:
+ case X86::VCVTSI2SSZrm_Int:
+ case X86::VCVTSI642SSZrr:
+ case X86::VCVTSI642SSZrm:
+ case X86::VCVTSI642SSZrr_Int:
+ case X86::VCVTSI642SSZrrb_Int:
+ case X86::VCVTSI642SSZrm_Int:
+ case X86::VCVTSI2SDZrr:
+ case X86::VCVTSI2SDZrm:
+ case X86::VCVTSI2SDZrr_Int:
+ case X86::VCVTSI2SDZrrb_Int:
+ case X86::VCVTSI2SDZrm_Int:
+ case X86::VCVTSI642SDZrr:
+ case X86::VCVTSI642SDZrm:
+ case X86::VCVTSI642SDZrr_Int:
+ case X86::VCVTSI642SDZrrb_Int:
+ case X86::VCVTSI642SDZrm_Int:
+ case X86::VCVTUSI2SSZrr:
+ case X86::VCVTUSI2SSZrm:
+ case X86::VCVTUSI2SSZrr_Int:
+ case X86::VCVTUSI2SSZrrb_Int:
+ case X86::VCVTUSI2SSZrm_Int:
+ case X86::VCVTUSI642SSZrr:
+ case X86::VCVTUSI642SSZrm:
+ case X86::VCVTUSI642SSZrr_Int:
+ case X86::VCVTUSI642SSZrrb_Int:
+ case X86::VCVTUSI642SSZrm_Int:
+ case X86::VCVTUSI2SDZrr:
+ case X86::VCVTUSI2SDZrm:
+ case X86::VCVTUSI2SDZrr_Int:
+ case X86::VCVTUSI2SDZrm_Int:
+ case X86::VCVTUSI642SDZrr:
+ case X86::VCVTUSI642SDZrm:
+ case X86::VCVTUSI642SDZrr_Int:
+ case X86::VCVTUSI642SDZrrb_Int:
+ case X86::VCVTUSI642SDZrm_Int:
case X86::VCVTSD2SSZrr:
+ case X86::VCVTSD2SSZrrb:
case X86::VCVTSD2SSZrm:
case X86::VCVTSS2SDZrr:
+ case X86::VCVTSS2SDZrrb:
case X86::VCVTSS2SDZrm:
+ case X86::VRNDSCALESDr:
+ case X86::VRNDSCALESDrb:
+ case X86::VRNDSCALESDm:
+ case X86::VRNDSCALESSr:
+ case X86::VRNDSCALESSrb:
+ case X86::VRNDSCALESSm:
+ case X86::VRCP14SSrr:
+ case X86::VRCP14SSrm:
+ case X86::VRSQRT14SSrr:
+ case X86::VRSQRT14SSrm:
+ case X86::VSQRTSSZr:
+ case X86::VSQRTSSZr_Int:
+ case X86::VSQRTSSZrb_Int:
+ case X86::VSQRTSSZm:
+ case X86::VSQRTSSZm_Int:
+ case X86::VSQRTSDZr:
+ case X86::VSQRTSDZr_Int:
+ case X86::VSQRTSDZrb_Int:
+ case X86::VSQRTSDZm:
+ case X86::VSQRTSDZm_Int:
return true;
}
@@ -6233,9 +7446,17 @@ X86InstrInfo::foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI,
if (!MF.getFunction()->optForSize() && hasPartialRegUpdate(MI.getOpcode()))
return nullptr;
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- unsigned Size = MFI->getObjectSize(FrameIndex);
- unsigned Alignment = MFI->getObjectAlignment(FrameIndex);
+ // Don't fold subreg spills, or reloads that use a high subreg.
+ for (auto Op : Ops) {
+ MachineOperand &MO = MI.getOperand(Op);
+ auto SubReg = MO.getSubReg();
+ if (SubReg && (MO.isDef() || SubReg == X86::sub_8bit_hi))
+ return nullptr;
+ }
+
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ unsigned Size = MFI.getObjectSize(FrameIndex);
+ unsigned Alignment = MFI.getObjectAlignment(FrameIndex);
// If the function stack isn't realigned we don't want to fold instructions
// that need increased alignment.
if (!RI.needsStackRealignment(MF))
@@ -6295,15 +7516,26 @@ static bool isNonFoldablePartialRegisterLoad(const MachineInstr &LoadMI,
// instruction isn't scalar (SS).
switch (UserOpc) {
case X86::ADDSSrr_Int: case X86::VADDSSrr_Int: case X86::VADDSSZrr_Int:
+ case X86::Int_CMPSSrr: case X86::Int_VCMPSSrr: case X86::VCMPSSZrr_Int:
case X86::DIVSSrr_Int: case X86::VDIVSSrr_Int: case X86::VDIVSSZrr_Int:
+ case X86::MAXSSrr_Int: case X86::VMAXSSrr_Int: case X86::VMAXSSZrr_Int:
+ case X86::MINSSrr_Int: case X86::VMINSSrr_Int: case X86::VMINSSZrr_Int:
case X86::MULSSrr_Int: case X86::VMULSSrr_Int: case X86::VMULSSZrr_Int:
case X86::SUBSSrr_Int: case X86::VSUBSSrr_Int: case X86::VSUBSSZrr_Int:
- case X86::VFMADDSSr132r_Int: case X86::VFNMADDSSr132r_Int:
- case X86::VFMADDSSr213r_Int: case X86::VFNMADDSSr213r_Int:
- case X86::VFMADDSSr231r_Int: case X86::VFNMADDSSr231r_Int:
- case X86::VFMSUBSSr132r_Int: case X86::VFNMSUBSSr132r_Int:
- case X86::VFMSUBSSr213r_Int: case X86::VFNMSUBSSr213r_Int:
- case X86::VFMSUBSSr231r_Int: case X86::VFNMSUBSSr231r_Int:
+ case X86::VFMADDSS4rr_Int: case X86::VFNMADDSS4rr_Int:
+ case X86::VFMSUBSS4rr_Int: case X86::VFNMSUBSS4rr_Int:
+ case X86::VFMADD132SSr_Int: case X86::VFNMADD132SSr_Int:
+ case X86::VFMADD213SSr_Int: case X86::VFNMADD213SSr_Int:
+ case X86::VFMADD231SSr_Int: case X86::VFNMADD231SSr_Int:
+ case X86::VFMSUB132SSr_Int: case X86::VFNMSUB132SSr_Int:
+ case X86::VFMSUB213SSr_Int: case X86::VFNMSUB213SSr_Int:
+ case X86::VFMSUB231SSr_Int: case X86::VFNMSUB231SSr_Int:
+ case X86::VFMADD132SSZr_Int: case X86::VFNMADD132SSZr_Int:
+ case X86::VFMADD213SSZr_Int: case X86::VFNMADD213SSZr_Int:
+ case X86::VFMADD231SSZr_Int: case X86::VFNMADD231SSZr_Int:
+ case X86::VFMSUB132SSZr_Int: case X86::VFNMSUB132SSZr_Int:
+ case X86::VFMSUB213SSZr_Int: case X86::VFNMSUB213SSZr_Int:
+ case X86::VFMSUB231SSZr_Int: case X86::VFNMSUB231SSZr_Int:
return false;
default:
return true;
@@ -6317,15 +7549,26 @@ static bool isNonFoldablePartialRegisterLoad(const MachineInstr &LoadMI,
// instruction isn't scalar (SD).
switch (UserOpc) {
case X86::ADDSDrr_Int: case X86::VADDSDrr_Int: case X86::VADDSDZrr_Int:
+ case X86::Int_CMPSDrr: case X86::Int_VCMPSDrr: case X86::VCMPSDZrr_Int:
case X86::DIVSDrr_Int: case X86::VDIVSDrr_Int: case X86::VDIVSDZrr_Int:
+ case X86::MAXSDrr_Int: case X86::VMAXSDrr_Int: case X86::VMAXSDZrr_Int:
+ case X86::MINSDrr_Int: case X86::VMINSDrr_Int: case X86::VMINSDZrr_Int:
case X86::MULSDrr_Int: case X86::VMULSDrr_Int: case X86::VMULSDZrr_Int:
case X86::SUBSDrr_Int: case X86::VSUBSDrr_Int: case X86::VSUBSDZrr_Int:
- case X86::VFMADDSDr132r_Int: case X86::VFNMADDSDr132r_Int:
- case X86::VFMADDSDr213r_Int: case X86::VFNMADDSDr213r_Int:
- case X86::VFMADDSDr231r_Int: case X86::VFNMADDSDr231r_Int:
- case X86::VFMSUBSDr132r_Int: case X86::VFNMSUBSDr132r_Int:
- case X86::VFMSUBSDr213r_Int: case X86::VFNMSUBSDr213r_Int:
- case X86::VFMSUBSDr231r_Int: case X86::VFNMSUBSDr231r_Int:
+ case X86::VFMADDSD4rr_Int: case X86::VFNMADDSD4rr_Int:
+ case X86::VFMSUBSD4rr_Int: case X86::VFNMSUBSD4rr_Int:
+ case X86::VFMADD132SDr_Int: case X86::VFNMADD132SDr_Int:
+ case X86::VFMADD213SDr_Int: case X86::VFNMADD213SDr_Int:
+ case X86::VFMADD231SDr_Int: case X86::VFNMADD231SDr_Int:
+ case X86::VFMSUB132SDr_Int: case X86::VFNMSUB132SDr_Int:
+ case X86::VFMSUB213SDr_Int: case X86::VFNMSUB213SDr_Int:
+ case X86::VFMSUB231SDr_Int: case X86::VFNMSUB231SDr_Int:
+ case X86::VFMADD132SDZr_Int: case X86::VFNMADD132SDZr_Int:
+ case X86::VFMADD213SDZr_Int: case X86::VFNMADD213SDZr_Int:
+ case X86::VFMADD231SDZr_Int: case X86::VFNMADD231SDZr_Int:
+ case X86::VFMSUB132SDZr_Int: case X86::VFNMSUB132SDZr_Int:
+ case X86::VFMSUB213SDZr_Int: case X86::VFNMSUB213SDZr_Int:
+ case X86::VFMSUB231SDZr_Int: case X86::VFNMSUB231SDZr_Int:
return false;
default:
return true;
@@ -6339,6 +7582,14 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl(
MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops,
MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI,
LiveIntervals *LIS) const {
+
+ // TODO: Support the case where LoadMI loads a wide register, but MI
+ // only uses a subreg.
+ for (auto Op : Ops) {
+ if (MI.getOperand(Op).getSubReg())
+ return nullptr;
+ }
+
// If loading from a FrameIndex, fold directly from the FrameIndex.
unsigned NumOps = LoadMI.getDesc().getNumOperands();
int FrameIndex;
@@ -6376,9 +7627,11 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl(
Alignment = 16;
break;
case X86::FsFLD0SD:
+ case X86::AVX512_FsFLD0SD:
Alignment = 8;
break;
case X86::FsFLD0SS:
+ case X86::AVX512_FsFLD0SS:
Alignment = 4;
break;
default:
@@ -6415,7 +7668,9 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl(
case X86::AVX512_512_SET0:
case X86::AVX512_512_SETALLONES:
case X86::FsFLD0SD:
- case X86::FsFLD0SS: {
+ case X86::AVX512_FsFLD0SD:
+ case X86::FsFLD0SS:
+ case X86::AVX512_FsFLD0SS: {
// Folding a V_SET0 or V_SETALLONES as a load, to ease register pressure.
// Create a constant-pool entry and operands to load from it.
@@ -6441,9 +7696,9 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl(
MachineConstantPool &MCP = *MF.getConstantPool();
Type *Ty;
unsigned Opc = LoadMI.getOpcode();
- if (Opc == X86::FsFLD0SS)
+ if (Opc == X86::FsFLD0SS || Opc == X86::AVX512_FsFLD0SS)
Ty = Type::getFloatTy(MF.getFunction()->getContext());
- else if (Opc == X86::FsFLD0SD)
+ else if (Opc == X86::FsFLD0SD || Opc == X86::AVX512_FsFLD0SD)
Ty = Type::getDoubleTy(MF.getFunction()->getContext());
else if (Opc == X86::AVX512_512_SET0 || Opc == X86::AVX512_512_SETALLONES)
Ty = VectorType::get(Type::getInt32Ty(MF.getFunction()->getContext()),16);
@@ -6649,7 +7904,7 @@ X86InstrInfo::unfoldMemoryOperand(SelectionDAG &DAG, SDNode *N,
return false;
// FIXME: If a VR128 can have size 32, we should be checking if a 32-byte
// memory access is slow above.
- unsigned Alignment = RC->getSize() == 32 ? 32 : 16;
+ unsigned Alignment = std::max<uint32_t>(RC->getSize(), 16);
bool isAligned = (*MMOs.first) &&
(*MMOs.first)->getAlignment() >= Alignment;
Load = DAG.getMachineNode(getLoadRegOpcode(0, RC, isAligned, Subtarget), dl,
@@ -6694,7 +7949,7 @@ X86InstrInfo::unfoldMemoryOperand(SelectionDAG &DAG, SDNode *N,
return false;
// FIXME: If a VR128 can have size 32, we should be checking if a 32-byte
// memory access is slow above.
- unsigned Alignment = RC->getSize() == 32 ? 32 : 16;
+ unsigned Alignment = std::max<uint32_t>(RC->getSize(), 16);
bool isAligned = (*MMOs.first) &&
(*MMOs.first)->getAlignment() >= Alignment;
SDNode *Store =
@@ -6746,8 +8001,6 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
case X86::MOVSDrm:
case X86::MMX_MOVD64rm:
case X86::MMX_MOVQ64rm:
- case X86::FsMOVAPSrm:
- case X86::FsMOVAPDrm:
case X86::MOVAPSrm:
case X86::MOVUPSrm:
case X86::MOVAPDrm:
@@ -6757,8 +8010,6 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
// AVX load instructions
case X86::VMOVSSrm:
case X86::VMOVSDrm:
- case X86::FsVMOVAPSrm:
- case X86::FsVMOVAPDrm:
case X86::VMOVAPSrm:
case X86::VMOVUPSrm:
case X86::VMOVAPDrm:
@@ -6776,6 +8027,8 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
case X86::VMOVSDZrm:
case X86::VMOVAPSZ128rm:
case X86::VMOVUPSZ128rm:
+ case X86::VMOVAPSZ128rm_NOVLX:
+ case X86::VMOVUPSZ128rm_NOVLX:
case X86::VMOVAPDZ128rm:
case X86::VMOVUPDZ128rm:
case X86::VMOVDQU8Z128rm:
@@ -6786,6 +8039,8 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
case X86::VMOVDQU64Z128rm:
case X86::VMOVAPSZ256rm:
case X86::VMOVUPSZ256rm:
+ case X86::VMOVAPSZ256rm_NOVLX:
+ case X86::VMOVUPSZ256rm_NOVLX:
case X86::VMOVAPDZ256rm:
case X86::VMOVUPDZ256rm:
case X86::VMOVDQU8Z256rm:
@@ -6823,8 +8078,6 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
case X86::MOVSDrm:
case X86::MMX_MOVD64rm:
case X86::MMX_MOVQ64rm:
- case X86::FsMOVAPSrm:
- case X86::FsMOVAPDrm:
case X86::MOVAPSrm:
case X86::MOVUPSrm:
case X86::MOVAPDrm:
@@ -6834,8 +8087,6 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
// AVX load instructions
case X86::VMOVSSrm:
case X86::VMOVSDrm:
- case X86::FsVMOVAPSrm:
- case X86::FsVMOVAPDrm:
case X86::VMOVAPSrm:
case X86::VMOVUPSrm:
case X86::VMOVAPDrm:
@@ -6853,6 +8104,8 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
case X86::VMOVSDZrm:
case X86::VMOVAPSZ128rm:
case X86::VMOVUPSZ128rm:
+ case X86::VMOVAPSZ128rm_NOVLX:
+ case X86::VMOVUPSZ128rm_NOVLX:
case X86::VMOVAPDZ128rm:
case X86::VMOVUPDZ128rm:
case X86::VMOVDQU8Z128rm:
@@ -6863,6 +8116,8 @@ X86InstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
case X86::VMOVDQU64Z128rm:
case X86::VMOVAPSZ256rm:
case X86::VMOVUPSZ256rm:
+ case X86::VMOVAPSZ256rm_NOVLX:
+ case X86::VMOVUPSZ256rm_NOVLX:
case X86::VMOVAPDZ256rm:
case X86::VMOVUPDZ256rm:
case X86::VMOVDQU8Z256rm:
@@ -6960,8 +8215,8 @@ bool X86InstrInfo::shouldScheduleLoadsNear(SDNode *Load1, SDNode *Load2,
return true;
}
-bool X86InstrInfo::shouldScheduleAdjacent(MachineInstr &First,
- MachineInstr &Second) const {
+bool X86InstrInfo::shouldScheduleAdjacent(const MachineInstr &First,
+ const MachineInstr &Second) const {
// Check if this processor supports macro-fusion. Since this is a minor
// heuristic, we haven't specifically reserved a feature. hasAVX is a decent
// proxy for SandyBridge+.
@@ -7120,7 +8375,7 @@ bool X86InstrInfo::shouldScheduleAdjacent(MachineInstr &First,
}
bool X86InstrInfo::
-ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 1 && "Invalid X86 branch condition!");
X86::CondCode CC = static_cast<X86::CondCode>(Cond[0].getImm());
Cond[0].setImm(GetOppositeBranchCondition(CC));
@@ -7168,7 +8423,10 @@ static const uint16_t ReplaceableInstrs[][3] = {
{ X86::MOVAPSrr, X86::MOVAPDrr, X86::MOVDQArr },
{ X86::MOVUPSmr, X86::MOVUPDmr, X86::MOVDQUmr },
{ X86::MOVUPSrm, X86::MOVUPDrm, X86::MOVDQUrm },
- { X86::MOVLPSmr, X86::MOVLPDmr, X86::MOVPQI2QImr },
+ { X86::MOVLPSmr, X86::MOVLPDmr, X86::MOVPQI2QImr },
+ { X86::MOVSSmr, X86::MOVSSmr, X86::MOVPDI2DImr },
+ { X86::MOVSDrm, X86::MOVSDrm, X86::MOVQI2PQIrm },
+ { X86::MOVSSrm, X86::MOVSSrm, X86::MOVDI2PDIrm },
{ X86::MOVNTPSmr, X86::MOVNTPDmr, X86::MOVNTDQmr },
{ X86::ANDNPSrm, X86::ANDNPDrm, X86::PANDNrm },
{ X86::ANDNPSrr, X86::ANDNPDrr, X86::PANDNrr },
@@ -7184,7 +8442,10 @@ static const uint16_t ReplaceableInstrs[][3] = {
{ X86::VMOVAPSrr, X86::VMOVAPDrr, X86::VMOVDQArr },
{ X86::VMOVUPSmr, X86::VMOVUPDmr, X86::VMOVDQUmr },
{ X86::VMOVUPSrm, X86::VMOVUPDrm, X86::VMOVDQUrm },
- { X86::VMOVLPSmr, X86::VMOVLPDmr, X86::VMOVPQI2QImr },
+ { X86::VMOVLPSmr, X86::VMOVLPDmr, X86::VMOVPQI2QImr },
+ { X86::VMOVSSmr, X86::VMOVSSmr, X86::VMOVPDI2DImr },
+ { X86::VMOVSDrm, X86::VMOVSDrm, X86::VMOVQI2PQIrm },
+ { X86::VMOVSSrm, X86::VMOVSSrm, X86::VMOVDI2PDIrm },
{ X86::VMOVNTPSmr, X86::VMOVNTPDmr, X86::VMOVNTDQmr },
{ X86::VANDNPSrm, X86::VANDNPDrm, X86::VPANDNrm },
{ X86::VANDNPSrr, X86::VANDNPDrr, X86::VPANDNrr },
@@ -7200,7 +8461,26 @@ static const uint16_t ReplaceableInstrs[][3] = {
{ X86::VMOVAPSYrr, X86::VMOVAPDYrr, X86::VMOVDQAYrr },
{ X86::VMOVUPSYmr, X86::VMOVUPDYmr, X86::VMOVDQUYmr },
{ X86::VMOVUPSYrm, X86::VMOVUPDYrm, X86::VMOVDQUYrm },
- { X86::VMOVNTPSYmr, X86::VMOVNTPDYmr, X86::VMOVNTDQYmr }
+ { X86::VMOVNTPSYmr, X86::VMOVNTPDYmr, X86::VMOVNTDQYmr },
+ // AVX512 support
+ { X86::VMOVLPSZ128mr, X86::VMOVLPDZ128mr, X86::VMOVPQI2QIZmr },
+ { X86::VMOVNTPSZ128mr, X86::VMOVNTPDZ128mr, X86::VMOVNTDQZ128mr },
+ { X86::VMOVNTPSZ128mr, X86::VMOVNTPDZ128mr, X86::VMOVNTDQZ128mr },
+ { X86::VMOVNTPSZmr, X86::VMOVNTPDZmr, X86::VMOVNTDQZmr },
+ { X86::VMOVSDZmr, X86::VMOVSDZmr, X86::VMOVPQI2QIZmr },
+ { X86::VMOVSSZmr, X86::VMOVSSZmr, X86::VMOVPDI2DIZmr },
+ { X86::VMOVSDZrm, X86::VMOVSDZrm, X86::VMOVQI2PQIZrm },
+ { X86::VMOVSSZrm, X86::VMOVSSZrm, X86::VMOVDI2PDIZrm },
+ { X86::VBROADCASTSSZ128r, X86::VBROADCASTSSZ128r, X86::VPBROADCASTDZ128r },
+ { X86::VBROADCASTSSZ128m, X86::VBROADCASTSSZ128m, X86::VPBROADCASTDZ128m },
+ { X86::VBROADCASTSSZ256r, X86::VBROADCASTSSZ256r, X86::VPBROADCASTDZ256r },
+ { X86::VBROADCASTSSZ256m, X86::VBROADCASTSSZ256m, X86::VPBROADCASTDZ256m },
+ { X86::VBROADCASTSSZr, X86::VBROADCASTSSZr, X86::VPBROADCASTDZr },
+ { X86::VBROADCASTSSZm, X86::VBROADCASTSSZm, X86::VPBROADCASTDZm },
+ { X86::VBROADCASTSDZ256r, X86::VBROADCASTSDZ256r, X86::VPBROADCASTQZ256r },
+ { X86::VBROADCASTSDZ256m, X86::VBROADCASTSDZ256m, X86::VPBROADCASTQZ256m },
+ { X86::VBROADCASTSDZr, X86::VBROADCASTSDZr, X86::VPBROADCASTQZr },
+ { X86::VBROADCASTSDZm, X86::VBROADCASTSDZm, X86::VPBROADCASTQZm },
};
static const uint16_t ReplaceableInstrsAVX2[][3] = {
@@ -7224,22 +8504,257 @@ static const uint16_t ReplaceableInstrsAVX2[][3] = {
{ X86::VBROADCASTSSYrr, X86::VBROADCASTSSYrr, X86::VPBROADCASTDYrr},
{ X86::VBROADCASTSSYrm, X86::VBROADCASTSSYrm, X86::VPBROADCASTDYrm},
{ X86::VBROADCASTSDYrr, X86::VBROADCASTSDYrr, X86::VPBROADCASTQYrr},
- { X86::VBROADCASTSDYrm, X86::VBROADCASTSDYrm, X86::VPBROADCASTQYrm}
+ { X86::VBROADCASTSDYrm, X86::VBROADCASTSDYrm, X86::VPBROADCASTQYrm},
+ { X86::VBROADCASTF128, X86::VBROADCASTF128, X86::VBROADCASTI128 },
+};
+
+static const uint16_t ReplaceableInstrsAVX512[][4] = {
+ // Two integer columns for 64-bit and 32-bit elements.
+ //PackedSingle PackedDouble PackedInt PackedInt
+ { X86::VMOVAPSZ128mr, X86::VMOVAPDZ128mr, X86::VMOVDQA64Z128mr, X86::VMOVDQA32Z128mr },
+ { X86::VMOVAPSZ128rm, X86::VMOVAPDZ128rm, X86::VMOVDQA64Z128rm, X86::VMOVDQA32Z128rm },
+ { X86::VMOVAPSZ128rr, X86::VMOVAPDZ128rr, X86::VMOVDQA64Z128rr, X86::VMOVDQA32Z128rr },
+ { X86::VMOVUPSZ128mr, X86::VMOVUPDZ128mr, X86::VMOVDQU64Z128mr, X86::VMOVDQU32Z128mr },
+ { X86::VMOVUPSZ128rm, X86::VMOVUPDZ128rm, X86::VMOVDQU64Z128rm, X86::VMOVDQU32Z128rm },
+ { X86::VMOVAPSZ256mr, X86::VMOVAPDZ256mr, X86::VMOVDQA64Z256mr, X86::VMOVDQA32Z256mr },
+ { X86::VMOVAPSZ256rm, X86::VMOVAPDZ256rm, X86::VMOVDQA64Z256rm, X86::VMOVDQA32Z256rm },
+ { X86::VMOVAPSZ256rr, X86::VMOVAPDZ256rr, X86::VMOVDQA64Z256rr, X86::VMOVDQA32Z256rr },
+ { X86::VMOVUPSZ256mr, X86::VMOVUPDZ256mr, X86::VMOVDQU64Z256mr, X86::VMOVDQU32Z256mr },
+ { X86::VMOVUPSZ256rm, X86::VMOVUPDZ256rm, X86::VMOVDQU64Z256rm, X86::VMOVDQU32Z256rm },
+ { X86::VMOVAPSZmr, X86::VMOVAPDZmr, X86::VMOVDQA64Zmr, X86::VMOVDQA32Zmr },
+ { X86::VMOVAPSZrm, X86::VMOVAPDZrm, X86::VMOVDQA64Zrm, X86::VMOVDQA32Zrm },
+ { X86::VMOVAPSZrr, X86::VMOVAPDZrr, X86::VMOVDQA64Zrr, X86::VMOVDQA32Zrr },
+ { X86::VMOVUPSZmr, X86::VMOVUPDZmr, X86::VMOVDQU64Zmr, X86::VMOVDQU32Zmr },
+ { X86::VMOVUPSZrm, X86::VMOVUPDZrm, X86::VMOVDQU64Zrm, X86::VMOVDQU32Zrm },
+};
+
+static const uint16_t ReplaceableInstrsAVX512DQ[][4] = {
+ // Two integer columns for 64-bit and 32-bit elements.
+ //PackedSingle PackedDouble PackedInt PackedInt
+ { X86::VANDNPSZ128rm, X86::VANDNPDZ128rm, X86::VPANDNQZ128rm, X86::VPANDNDZ128rm },
+ { X86::VANDNPSZ128rr, X86::VANDNPDZ128rr, X86::VPANDNQZ128rr, X86::VPANDNDZ128rr },
+ { X86::VANDPSZ128rm, X86::VANDPDZ128rm, X86::VPANDQZ128rm, X86::VPANDDZ128rm },
+ { X86::VANDPSZ128rr, X86::VANDPDZ128rr, X86::VPANDQZ128rr, X86::VPANDDZ128rr },
+ { X86::VORPSZ128rm, X86::VORPDZ128rm, X86::VPORQZ128rm, X86::VPORDZ128rm },
+ { X86::VORPSZ128rr, X86::VORPDZ128rr, X86::VPORQZ128rr, X86::VPORDZ128rr },
+ { X86::VXORPSZ128rm, X86::VXORPDZ128rm, X86::VPXORQZ128rm, X86::VPXORDZ128rm },
+ { X86::VXORPSZ128rr, X86::VXORPDZ128rr, X86::VPXORQZ128rr, X86::VPXORDZ128rr },
+ { X86::VANDNPSZ256rm, X86::VANDNPDZ256rm, X86::VPANDNQZ256rm, X86::VPANDNDZ256rm },
+ { X86::VANDNPSZ256rr, X86::VANDNPDZ256rr, X86::VPANDNQZ256rr, X86::VPANDNDZ256rr },
+ { X86::VANDPSZ256rm, X86::VANDPDZ256rm, X86::VPANDQZ256rm, X86::VPANDDZ256rm },
+ { X86::VANDPSZ256rr, X86::VANDPDZ256rr, X86::VPANDQZ256rr, X86::VPANDDZ256rr },
+ { X86::VORPSZ256rm, X86::VORPDZ256rm, X86::VPORQZ256rm, X86::VPORDZ256rm },
+ { X86::VORPSZ256rr, X86::VORPDZ256rr, X86::VPORQZ256rr, X86::VPORDZ256rr },
+ { X86::VXORPSZ256rm, X86::VXORPDZ256rm, X86::VPXORQZ256rm, X86::VPXORDZ256rm },
+ { X86::VXORPSZ256rr, X86::VXORPDZ256rr, X86::VPXORQZ256rr, X86::VPXORDZ256rr },
+ { X86::VANDNPSZrm, X86::VANDNPDZrm, X86::VPANDNQZrm, X86::VPANDNDZrm },
+ { X86::VANDNPSZrr, X86::VANDNPDZrr, X86::VPANDNQZrr, X86::VPANDNDZrr },
+ { X86::VANDPSZrm, X86::VANDPDZrm, X86::VPANDQZrm, X86::VPANDDZrm },
+ { X86::VANDPSZrr, X86::VANDPDZrr, X86::VPANDQZrr, X86::VPANDDZrr },
+ { X86::VORPSZrm, X86::VORPDZrm, X86::VPORQZrm, X86::VPORDZrm },
+ { X86::VORPSZrr, X86::VORPDZrr, X86::VPORQZrr, X86::VPORDZrr },
+ { X86::VXORPSZrm, X86::VXORPDZrm, X86::VPXORQZrm, X86::VPXORDZrm },
+ { X86::VXORPSZrr, X86::VXORPDZrr, X86::VPXORQZrr, X86::VPXORDZrr },
+};
+
+static const uint16_t ReplaceableInstrsAVX512DQMasked[][4] = {
+ // Two integer columns for 64-bit and 32-bit elements.
+ //PackedSingle PackedDouble
+ //PackedInt PackedInt
+ { X86::VANDNPSZ128rmk, X86::VANDNPDZ128rmk,
+ X86::VPANDNQZ128rmk, X86::VPANDNDZ128rmk },
+ { X86::VANDNPSZ128rmkz, X86::VANDNPDZ128rmkz,
+ X86::VPANDNQZ128rmkz, X86::VPANDNDZ128rmkz },
+ { X86::VANDNPSZ128rrk, X86::VANDNPDZ128rrk,
+ X86::VPANDNQZ128rrk, X86::VPANDNDZ128rrk },
+ { X86::VANDNPSZ128rrkz, X86::VANDNPDZ128rrkz,
+ X86::VPANDNQZ128rrkz, X86::VPANDNDZ128rrkz },
+ { X86::VANDPSZ128rmk, X86::VANDPDZ128rmk,
+ X86::VPANDQZ128rmk, X86::VPANDDZ128rmk },
+ { X86::VANDPSZ128rmkz, X86::VANDPDZ128rmkz,
+ X86::VPANDQZ128rmkz, X86::VPANDDZ128rmkz },
+ { X86::VANDPSZ128rrk, X86::VANDPDZ128rrk,
+ X86::VPANDQZ128rrk, X86::VPANDDZ128rrk },
+ { X86::VANDPSZ128rrkz, X86::VANDPDZ128rrkz,
+ X86::VPANDQZ128rrkz, X86::VPANDDZ128rrkz },
+ { X86::VORPSZ128rmk, X86::VORPDZ128rmk,
+ X86::VPORQZ128rmk, X86::VPORDZ128rmk },
+ { X86::VORPSZ128rmkz, X86::VORPDZ128rmkz,
+ X86::VPORQZ128rmkz, X86::VPORDZ128rmkz },
+ { X86::VORPSZ128rrk, X86::VORPDZ128rrk,
+ X86::VPORQZ128rrk, X86::VPORDZ128rrk },
+ { X86::VORPSZ128rrkz, X86::VORPDZ128rrkz,
+ X86::VPORQZ128rrkz, X86::VPORDZ128rrkz },
+ { X86::VXORPSZ128rmk, X86::VXORPDZ128rmk,
+ X86::VPXORQZ128rmk, X86::VPXORDZ128rmk },
+ { X86::VXORPSZ128rmkz, X86::VXORPDZ128rmkz,
+ X86::VPXORQZ128rmkz, X86::VPXORDZ128rmkz },
+ { X86::VXORPSZ128rrk, X86::VXORPDZ128rrk,
+ X86::VPXORQZ128rrk, X86::VPXORDZ128rrk },
+ { X86::VXORPSZ128rrkz, X86::VXORPDZ128rrkz,
+ X86::VPXORQZ128rrkz, X86::VPXORDZ128rrkz },
+ { X86::VANDNPSZ256rmk, X86::VANDNPDZ256rmk,
+ X86::VPANDNQZ256rmk, X86::VPANDNDZ256rmk },
+ { X86::VANDNPSZ256rmkz, X86::VANDNPDZ256rmkz,
+ X86::VPANDNQZ256rmkz, X86::VPANDNDZ256rmkz },
+ { X86::VANDNPSZ256rrk, X86::VANDNPDZ256rrk,
+ X86::VPANDNQZ256rrk, X86::VPANDNDZ256rrk },
+ { X86::VANDNPSZ256rrkz, X86::VANDNPDZ256rrkz,
+ X86::VPANDNQZ256rrkz, X86::VPANDNDZ256rrkz },
+ { X86::VANDPSZ256rmk, X86::VANDPDZ256rmk,
+ X86::VPANDQZ256rmk, X86::VPANDDZ256rmk },
+ { X86::VANDPSZ256rmkz, X86::VANDPDZ256rmkz,
+ X86::VPANDQZ256rmkz, X86::VPANDDZ256rmkz },
+ { X86::VANDPSZ256rrk, X86::VANDPDZ256rrk,
+ X86::VPANDQZ256rrk, X86::VPANDDZ256rrk },
+ { X86::VANDPSZ256rrkz, X86::VANDPDZ256rrkz,
+ X86::VPANDQZ256rrkz, X86::VPANDDZ256rrkz },
+ { X86::VORPSZ256rmk, X86::VORPDZ256rmk,
+ X86::VPORQZ256rmk, X86::VPORDZ256rmk },
+ { X86::VORPSZ256rmkz, X86::VORPDZ256rmkz,
+ X86::VPORQZ256rmkz, X86::VPORDZ256rmkz },
+ { X86::VORPSZ256rrk, X86::VORPDZ256rrk,
+ X86::VPORQZ256rrk, X86::VPORDZ256rrk },
+ { X86::VORPSZ256rrkz, X86::VORPDZ256rrkz,
+ X86::VPORQZ256rrkz, X86::VPORDZ256rrkz },
+ { X86::VXORPSZ256rmk, X86::VXORPDZ256rmk,
+ X86::VPXORQZ256rmk, X86::VPXORDZ256rmk },
+ { X86::VXORPSZ256rmkz, X86::VXORPDZ256rmkz,
+ X86::VPXORQZ256rmkz, X86::VPXORDZ256rmkz },
+ { X86::VXORPSZ256rrk, X86::VXORPDZ256rrk,
+ X86::VPXORQZ256rrk, X86::VPXORDZ256rrk },
+ { X86::VXORPSZ256rrkz, X86::VXORPDZ256rrkz,
+ X86::VPXORQZ256rrkz, X86::VPXORDZ256rrkz },
+ { X86::VANDNPSZrmk, X86::VANDNPDZrmk,
+ X86::VPANDNQZrmk, X86::VPANDNDZrmk },
+ { X86::VANDNPSZrmkz, X86::VANDNPDZrmkz,
+ X86::VPANDNQZrmkz, X86::VPANDNDZrmkz },
+ { X86::VANDNPSZrrk, X86::VANDNPDZrrk,
+ X86::VPANDNQZrrk, X86::VPANDNDZrrk },
+ { X86::VANDNPSZrrkz, X86::VANDNPDZrrkz,
+ X86::VPANDNQZrrkz, X86::VPANDNDZrrkz },
+ { X86::VANDPSZrmk, X86::VANDPDZrmk,
+ X86::VPANDQZrmk, X86::VPANDDZrmk },
+ { X86::VANDPSZrmkz, X86::VANDPDZrmkz,
+ X86::VPANDQZrmkz, X86::VPANDDZrmkz },
+ { X86::VANDPSZrrk, X86::VANDPDZrrk,
+ X86::VPANDQZrrk, X86::VPANDDZrrk },
+ { X86::VANDPSZrrkz, X86::VANDPDZrrkz,
+ X86::VPANDQZrrkz, X86::VPANDDZrrkz },
+ { X86::VORPSZrmk, X86::VORPDZrmk,
+ X86::VPORQZrmk, X86::VPORDZrmk },
+ { X86::VORPSZrmkz, X86::VORPDZrmkz,
+ X86::VPORQZrmkz, X86::VPORDZrmkz },
+ { X86::VORPSZrrk, X86::VORPDZrrk,
+ X86::VPORQZrrk, X86::VPORDZrrk },
+ { X86::VORPSZrrkz, X86::VORPDZrrkz,
+ X86::VPORQZrrkz, X86::VPORDZrrkz },
+ { X86::VXORPSZrmk, X86::VXORPDZrmk,
+ X86::VPXORQZrmk, X86::VPXORDZrmk },
+ { X86::VXORPSZrmkz, X86::VXORPDZrmkz,
+ X86::VPXORQZrmkz, X86::VPXORDZrmkz },
+ { X86::VXORPSZrrk, X86::VXORPDZrrk,
+ X86::VPXORQZrrk, X86::VPXORDZrrk },
+ { X86::VXORPSZrrkz, X86::VXORPDZrrkz,
+ X86::VPXORQZrrkz, X86::VPXORDZrrkz },
+ // Broadcast loads can be handled the same as masked operations to avoid
+ // changing element size.
+ { X86::VANDNPSZ128rmb, X86::VANDNPDZ128rmb,
+ X86::VPANDNQZ128rmb, X86::VPANDNDZ128rmb },
+ { X86::VANDPSZ128rmb, X86::VANDPDZ128rmb,
+ X86::VPANDQZ128rmb, X86::VPANDDZ128rmb },
+ { X86::VORPSZ128rmb, X86::VORPDZ128rmb,
+ X86::VPORQZ128rmb, X86::VPORDZ128rmb },
+ { X86::VXORPSZ128rmb, X86::VXORPDZ128rmb,
+ X86::VPXORQZ128rmb, X86::VPXORDZ128rmb },
+ { X86::VANDNPSZ256rmb, X86::VANDNPDZ256rmb,
+ X86::VPANDNQZ256rmb, X86::VPANDNDZ256rmb },
+ { X86::VANDPSZ256rmb, X86::VANDPDZ256rmb,
+ X86::VPANDQZ256rmb, X86::VPANDDZ256rmb },
+ { X86::VORPSZ256rmb, X86::VORPDZ256rmb,
+ X86::VPORQZ256rmb, X86::VPORDZ256rmb },
+ { X86::VXORPSZ256rmb, X86::VXORPDZ256rmb,
+ X86::VPXORQZ256rmb, X86::VPXORDZ256rmb },
+ { X86::VANDNPSZrmb, X86::VANDNPDZrmb,
+ X86::VPANDNQZrmb, X86::VPANDNDZrmb },
+ { X86::VANDPSZrmb, X86::VANDPDZrmb,
+ X86::VPANDQZrmb, X86::VPANDDZrmb },
+ { X86::VANDPSZrmb, X86::VANDPDZrmb,
+ X86::VPANDQZrmb, X86::VPANDDZrmb },
+ { X86::VORPSZrmb, X86::VORPDZrmb,
+ X86::VPORQZrmb, X86::VPORDZrmb },
+ { X86::VXORPSZrmb, X86::VXORPDZrmb,
+ X86::VPXORQZrmb, X86::VPXORDZrmb },
+ { X86::VANDNPSZ128rmbk, X86::VANDNPDZ128rmbk,
+ X86::VPANDNQZ128rmbk, X86::VPANDNDZ128rmbk },
+ { X86::VANDPSZ128rmbk, X86::VANDPDZ128rmbk,
+ X86::VPANDQZ128rmbk, X86::VPANDDZ128rmbk },
+ { X86::VORPSZ128rmbk, X86::VORPDZ128rmbk,
+ X86::VPORQZ128rmbk, X86::VPORDZ128rmbk },
+ { X86::VXORPSZ128rmbk, X86::VXORPDZ128rmbk,
+ X86::VPXORQZ128rmbk, X86::VPXORDZ128rmbk },
+ { X86::VANDNPSZ256rmbk, X86::VANDNPDZ256rmbk,
+ X86::VPANDNQZ256rmbk, X86::VPANDNDZ256rmbk },
+ { X86::VANDPSZ256rmbk, X86::VANDPDZ256rmbk,
+ X86::VPANDQZ256rmbk, X86::VPANDDZ256rmbk },
+ { X86::VORPSZ256rmbk, X86::VORPDZ256rmbk,
+ X86::VPORQZ256rmbk, X86::VPORDZ256rmbk },
+ { X86::VXORPSZ256rmbk, X86::VXORPDZ256rmbk,
+ X86::VPXORQZ256rmbk, X86::VPXORDZ256rmbk },
+ { X86::VANDNPSZrmbk, X86::VANDNPDZrmbk,
+ X86::VPANDNQZrmbk, X86::VPANDNDZrmbk },
+ { X86::VANDPSZrmbk, X86::VANDPDZrmbk,
+ X86::VPANDQZrmbk, X86::VPANDDZrmbk },
+ { X86::VANDPSZrmbk, X86::VANDPDZrmbk,
+ X86::VPANDQZrmbk, X86::VPANDDZrmbk },
+ { X86::VORPSZrmbk, X86::VORPDZrmbk,
+ X86::VPORQZrmbk, X86::VPORDZrmbk },
+ { X86::VXORPSZrmbk, X86::VXORPDZrmbk,
+ X86::VPXORQZrmbk, X86::VPXORDZrmbk },
+ { X86::VANDNPSZ128rmbkz,X86::VANDNPDZ128rmbkz,
+ X86::VPANDNQZ128rmbkz,X86::VPANDNDZ128rmbkz},
+ { X86::VANDPSZ128rmbkz, X86::VANDPDZ128rmbkz,
+ X86::VPANDQZ128rmbkz, X86::VPANDDZ128rmbkz },
+ { X86::VORPSZ128rmbkz, X86::VORPDZ128rmbkz,
+ X86::VPORQZ128rmbkz, X86::VPORDZ128rmbkz },
+ { X86::VXORPSZ128rmbkz, X86::VXORPDZ128rmbkz,
+ X86::VPXORQZ128rmbkz, X86::VPXORDZ128rmbkz },
+ { X86::VANDNPSZ256rmbkz,X86::VANDNPDZ256rmbkz,
+ X86::VPANDNQZ256rmbkz,X86::VPANDNDZ256rmbkz},
+ { X86::VANDPSZ256rmbkz, X86::VANDPDZ256rmbkz,
+ X86::VPANDQZ256rmbkz, X86::VPANDDZ256rmbkz },
+ { X86::VORPSZ256rmbkz, X86::VORPDZ256rmbkz,
+ X86::VPORQZ256rmbkz, X86::VPORDZ256rmbkz },
+ { X86::VXORPSZ256rmbkz, X86::VXORPDZ256rmbkz,
+ X86::VPXORQZ256rmbkz, X86::VPXORDZ256rmbkz },
+ { X86::VANDNPSZrmbkz, X86::VANDNPDZrmbkz,
+ X86::VPANDNQZrmbkz, X86::VPANDNDZrmbkz },
+ { X86::VANDPSZrmbkz, X86::VANDPDZrmbkz,
+ X86::VPANDQZrmbkz, X86::VPANDDZrmbkz },
+ { X86::VANDPSZrmbkz, X86::VANDPDZrmbkz,
+ X86::VPANDQZrmbkz, X86::VPANDDZrmbkz },
+ { X86::VORPSZrmbkz, X86::VORPDZrmbkz,
+ X86::VPORQZrmbkz, X86::VPORDZrmbkz },
+ { X86::VXORPSZrmbkz, X86::VXORPDZrmbkz,
+ X86::VPXORQZrmbkz, X86::VPXORDZrmbkz },
};
// FIXME: Some shuffle and unpack instructions have equivalents in different
// domains, but they require a bit more work than just switching opcodes.
-static const uint16_t *lookup(unsigned opcode, unsigned domain) {
- for (const uint16_t (&Row)[3] : ReplaceableInstrs)
+static const uint16_t *lookup(unsigned opcode, unsigned domain,
+ ArrayRef<uint16_t[3]> Table) {
+ for (const uint16_t (&Row)[3] : Table)
if (Row[domain-1] == opcode)
return Row;
return nullptr;
}
-static const uint16_t *lookupAVX2(unsigned opcode, unsigned domain) {
- for (const uint16_t (&Row)[3] : ReplaceableInstrsAVX2)
- if (Row[domain-1] == opcode)
+static const uint16_t *lookupAVX512(unsigned opcode, unsigned domain,
+ ArrayRef<uint16_t[4]> Table) {
+ // If this is the integer domain make sure to check both integer columns.
+ for (const uint16_t (&Row)[4] : Table)
+ if (Row[domain-1] == opcode || (domain == 3 && Row[3] == opcode))
return Row;
return nullptr;
}
@@ -7247,12 +8762,25 @@ static const uint16_t *lookupAVX2(unsigned opcode, unsigned domain) {
std::pair<uint16_t, uint16_t>
X86InstrInfo::getExecutionDomain(const MachineInstr &MI) const {
uint16_t domain = (MI.getDesc().TSFlags >> X86II::SSEDomainShift) & 3;
- bool hasAVX2 = Subtarget.hasAVX2();
+ unsigned opcode = MI.getOpcode();
uint16_t validDomains = 0;
- if (domain && lookup(MI.getOpcode(), domain))
- validDomains = 0xe;
- else if (domain && lookupAVX2(MI.getOpcode(), domain))
- validDomains = hasAVX2 ? 0xe : 0x6;
+ if (domain) {
+ if (lookup(MI.getOpcode(), domain, ReplaceableInstrs)) {
+ validDomains = 0xe;
+ } else if (lookup(opcode, domain, ReplaceableInstrsAVX2)) {
+ validDomains = Subtarget.hasAVX2() ? 0xe : 0x6;
+ } else if (lookupAVX512(opcode, domain, ReplaceableInstrsAVX512)) {
+ validDomains = 0xe;
+ } else if (lookupAVX512(opcode, domain, ReplaceableInstrsAVX512DQ)) {
+ validDomains = Subtarget.hasDQI() ? 0xe : 0x8;
+ } else if (const uint16_t *table = lookupAVX512(opcode, domain,
+ ReplaceableInstrsAVX512DQMasked)) {
+ if (domain == 1 || (domain == 3 && table[3] == opcode))
+ validDomains = Subtarget.hasDQI() ? 0xa : 0x8;
+ else
+ validDomains = Subtarget.hasDQI() ? 0xc : 0x8;
+ }
+ }
return std::make_pair(domain, validDomains);
}
@@ -7260,11 +8788,32 @@ void X86InstrInfo::setExecutionDomain(MachineInstr &MI, unsigned Domain) const {
assert(Domain>0 && Domain<4 && "Invalid execution domain");
uint16_t dom = (MI.getDesc().TSFlags >> X86II::SSEDomainShift) & 3;
assert(dom && "Not an SSE instruction");
- const uint16_t *table = lookup(MI.getOpcode(), dom);
+ const uint16_t *table = lookup(MI.getOpcode(), dom, ReplaceableInstrs);
if (!table) { // try the other table
assert((Subtarget.hasAVX2() || Domain < 3) &&
"256-bit vector operations only available in AVX2");
- table = lookupAVX2(MI.getOpcode(), dom);
+ table = lookup(MI.getOpcode(), dom, ReplaceableInstrsAVX2);
+ }
+ if (!table) { // try the AVX512 table
+ assert(Subtarget.hasAVX512() && "Requires AVX-512");
+ table = lookupAVX512(MI.getOpcode(), dom, ReplaceableInstrsAVX512);
+ // Don't change integer Q instructions to D instructions.
+ if (table && Domain == 3 && table[3] == MI.getOpcode())
+ Domain = 4;
+ }
+ if (!table) { // try the AVX512DQ table
+ assert((Subtarget.hasDQI() || Domain >= 3) && "Requires AVX-512DQ");
+ table = lookupAVX512(MI.getOpcode(), dom, ReplaceableInstrsAVX512DQ);
+ // Don't change integer Q instructions to D instructions and
+ // use D intructions if we started with a PS instruction.
+ if (table && Domain == 3 && (dom == 1 || table[3] == MI.getOpcode()))
+ Domain = 4;
+ }
+ if (!table) { // try the AVX512DQMasked table
+ assert((Subtarget.hasDQI() || Domain >= 3) && "Requires AVX-512DQ");
+ table = lookupAVX512(MI.getOpcode(), dom, ReplaceableInstrsAVX512DQMasked);
+ if (table && Domain == 3 && (dom == 1 || table[3] == MI.getOpcode()))
+ Domain = 4;
}
assert(table && "Cannot change domain");
MI.setDesc(get(table[Domain - 1]));
@@ -7275,32 +8824,6 @@ void X86InstrInfo::getNoopForMachoTarget(MCInst &NopInst) const {
NopInst.setOpcode(X86::NOOP);
}
-// This code must remain in sync with getJumpInstrTableEntryBound in this class!
-// In particular, getJumpInstrTableEntryBound must always return an upper bound
-// on the encoding lengths of the instructions generated by
-// getUnconditionalBranch and getTrap.
-void X86InstrInfo::getUnconditionalBranch(
- MCInst &Branch, const MCSymbolRefExpr *BranchTarget) const {
- Branch.setOpcode(X86::JMP_1);
- Branch.addOperand(MCOperand::createExpr(BranchTarget));
-}
-
-// This code must remain in sync with getJumpInstrTableEntryBound in this class!
-// In particular, getJumpInstrTableEntryBound must always return an upper bound
-// on the encoding lengths of the instructions generated by
-// getUnconditionalBranch and getTrap.
-void X86InstrInfo::getTrap(MCInst &MI) const {
- MI.setOpcode(X86::TRAP);
-}
-
-// See getTrap and getUnconditionalBranch for conditions on the value returned
-// by this function.
-unsigned X86InstrInfo::getJumpInstrTableEntryBound() const {
- // 5 bytes suffice: JMP_4 Symbol@PLT is uses 1 byte (E9) for the JMP_4 and 4
- // bytes for the symbol offset. And TRAP is ud2, which is two bytes (0F 0B).
- return 5;
-}
-
bool X86InstrInfo::isHighLatencyDef(int opc) const {
switch (opc) {
default: return false;
@@ -7934,6 +9457,28 @@ X86InstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
return makeArrayRef(TargetFlags);
}
+bool X86InstrInfo::isTailCall(const MachineInstr &Inst) const {
+ switch (Inst.getOpcode()) {
+ case X86::TCRETURNdi:
+ case X86::TCRETURNmi:
+ case X86::TCRETURNri:
+ case X86::TCRETURNdi64:
+ case X86::TCRETURNmi64:
+ case X86::TCRETURNri64:
+ case X86::TAILJMPd:
+ case X86::TAILJMPm:
+ case X86::TAILJMPr:
+ case X86::TAILJMPd64:
+ case X86::TAILJMPm64:
+ case X86::TAILJMPr64:
+ case X86::TAILJMPm64_REX:
+ case X86::TAILJMPr64_REX:
+ return true;
+ default:
+ return false;
+ }
+}
+
namespace {
/// Create Global Base Reg pass. This initializes the PIC
/// global base register for x86-32.
@@ -7991,7 +9536,7 @@ namespace {
return true;
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "X86 PIC Global Base Reg Initialization";
}
@@ -8105,7 +9650,7 @@ namespace {
return Copy;
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Local Dynamic TLS Access Clean-up";
}
diff --git a/contrib/llvm/lib/Target/X86/X86InstrInfo.h b/contrib/llvm/lib/Target/X86/X86InstrInfo.h
index a8a9f62..acfdef4 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrInfo.h
+++ b/contrib/llvm/lib/Target/X86/X86InstrInfo.h
@@ -15,6 +15,7 @@
#define LLVM_LIB_TARGET_X86_X86INSTRINFO_H
#include "MCTargetDesc/X86BaseInfo.h"
+#include "X86InstrFMA3Info.h"
#include "X86RegisterInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Target/TargetInstrInfo.h"
@@ -265,7 +266,7 @@ public:
unsigned &SrcOpIdx2) const override;
/// Returns true if the routine could find two commutable operands
- /// in the given FMA instruction. Otherwise, returns false.
+ /// in the given FMA instruction \p MI. Otherwise, returns false.
///
/// \p SrcOpIdx1 and \p SrcOpIdx2 are INPUT and OUTPUT arguments.
/// The output indices of the commuted operands are returned in these
@@ -274,10 +275,12 @@ public:
/// value 'CommuteAnyOperandIndex' which means that the corresponding
/// operand index is not set and this method is free to pick any of
/// available commutable operands.
+ /// The parameter \p FMA3Group keeps the reference to the group of relative
+ /// FMA3 opcodes including register/memory forms of 132/213/231 opcodes.
///
/// For example, calling this method this way:
/// unsigned Idx1 = 1, Idx2 = CommuteAnyOperandIndex;
- /// findFMA3CommutedOpIndices(MI, Idx1, Idx2);
+ /// findFMA3CommutedOpIndices(MI, Idx1, Idx2, FMA3Group);
/// can be interpreted as a query asking if the operand #1 can be swapped
/// with any other available operand (e.g. operand #2, operand #3, etc.).
///
@@ -286,21 +289,30 @@ public:
/// FMA213 #1, #2, #3
/// results into instruction with adjusted opcode:
/// FMA231 #3, #2, #1
- bool findFMA3CommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx1,
- unsigned &SrcOpIdx2) const;
+ bool findFMA3CommutedOpIndices(const MachineInstr &MI,
+ unsigned &SrcOpIdx1,
+ unsigned &SrcOpIdx2,
+ const X86InstrFMA3Group &FMA3Group) const;
/// Returns an adjusted FMA opcode that must be used in FMA instruction that
- /// performs the same computations as the given MI but which has the operands
- /// \p SrcOpIdx1 and \p SrcOpIdx2 commuted.
+ /// performs the same computations as the given \p MI but which has the
+ /// operands \p SrcOpIdx1 and \p SrcOpIdx2 commuted.
/// It may return 0 if it is unsafe to commute the operands.
+ /// Note that a machine instruction (instead of its opcode) is passed as the
+ /// first parameter to make it possible to analyze the instruction's uses and
+ /// commute the first operand of FMA even when it seems unsafe when you look
+ /// at the opcode. For example, it is Ok to commute the first operand of
+ /// VFMADD*SD_Int, if ONLY the lowest 64-bit element of the result is used.
///
/// The returned FMA opcode may differ from the opcode in the given \p MI.
/// For example, commuting the operands #1 and #3 in the following FMA
/// FMA213 #1, #2, #3
/// results into instruction with adjusted opcode:
/// FMA231 #3, #2, #1
- unsigned getFMA3OpcodeToCommuteOperands(MachineInstr &MI, unsigned SrcOpIdx1,
- unsigned SrcOpIdx2) const;
+ unsigned getFMA3OpcodeToCommuteOperands(const MachineInstr &MI,
+ unsigned SrcOpIdx1,
+ unsigned SrcOpIdx2,
+ const X86InstrFMA3Group &FMA3Group) const;
// Branch analysis.
bool isUnpredicatedTerminator(const MachineInstr &MI) const override;
@@ -316,10 +328,12 @@ public:
TargetInstrInfo::MachineBranchPredicate &MBP,
bool AllowModify = false) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
bool canInsertSelect(const MachineBasicBlock&, ArrayRef<MachineOperand> Cond,
unsigned, unsigned, int&, int&, int&) const override;
void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
@@ -357,6 +371,10 @@ public:
bool expandPostRAPseudo(MachineInstr &MI) const override;
+ /// Check whether the target can fold a load that feeds a subreg operand
+ /// (or a subreg operand that feeds a store).
+ bool isSubregFoldable() const override { return true; }
+
/// foldMemoryOperand - If this target supports it, fold a load or store of
/// the specified stack slot into the specified machine instruction for the
/// specified operand(s). If this is possible, the target should perform the
@@ -418,13 +436,13 @@ public:
int64_t Offset1, int64_t Offset2,
unsigned NumLoads) const override;
- bool shouldScheduleAdjacent(MachineInstr &First,
- MachineInstr &Second) const override;
+ bool shouldScheduleAdjacent(const MachineInstr &First,
+ const MachineInstr &Second) const override;
void getNoopForMachoTarget(MCInst &NopInst) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
/// isSafeToMoveRegClassDefs - Return true if it's safe to move a machine
/// instruction that defines the specified register class.
@@ -467,14 +485,6 @@ public:
unsigned Size, unsigned Alignment,
bool AllowCommute) const;
- void
- getUnconditionalBranch(MCInst &Branch,
- const MCSymbolRefExpr *BranchTarget) const override;
-
- void getTrap(MCInst &MI) const override;
-
- unsigned getJumpInstrTableEntryBound() const override;
-
bool isHighLatencyDef(int opc) const override;
bool hasHighOperandLatency(const TargetSchedModel &SchedModel,
@@ -529,6 +539,8 @@ public:
ArrayRef<std::pair<unsigned, const char *>>
getSerializableDirectMachineOperandTargetFlags() const override;
+ bool isTailCall(const MachineInstr &Inst) const override;
+
protected:
/// Commutes the operands in the given instruction by changing the operands
/// order and/or changing the instruction's opcode and/or the immediate value
@@ -564,8 +576,24 @@ private:
bool isFrameOperand(const MachineInstr &MI, unsigned int Op,
int &FrameIndex) const;
- /// Expand the MOVImmSExti8 pseudo-instructions.
- bool ExpandMOVImmSExti8(MachineInstrBuilder &MIB) const;
+ /// Returns true iff the routine could find two commutable operands in the
+ /// given machine instruction with 3 vector inputs.
+ /// The 'SrcOpIdx1' and 'SrcOpIdx2' are INPUT and OUTPUT arguments. Their
+ /// input values can be re-defined in this method only if the input values
+ /// are not pre-defined, which is designated by the special value
+ /// 'CommuteAnyOperandIndex' assigned to it.
+ /// If both of indices are pre-defined and refer to some operands, then the
+ /// method simply returns true if the corresponding operands are commutable
+ /// and returns false otherwise.
+ ///
+ /// For example, calling this method this way:
+ /// unsigned Op1 = 1, Op2 = CommuteAnyOperandIndex;
+ /// findThreeSrcCommutedOpIndices(MI, Op1, Op2);
+ /// can be interpreted as a query asking to find an operand that would be
+ /// commutable with the operand#1.
+ bool findThreeSrcCommutedOpIndices(const MachineInstr &MI,
+ unsigned &SrcOpIdx1,
+ unsigned &SrcOpIdx2) const;
};
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/X86/X86InstrInfo.td b/contrib/llvm/lib/Target/X86/X86InstrInfo.td
index b19a8f3..3803671 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrInfo.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrInfo.td
@@ -765,6 +765,12 @@ def tls64baseaddr : ComplexPattern<i64, 5, "selectTLSADDRAddr",
def vectoraddr : ComplexPattern<iPTR, 5, "selectVectorAddr", [],[SDNPWantParent]>;
+// A relocatable immediate is either an immediate operand or an operand that can
+// be relocated by the linker to an immediate, such as a regular symbol in
+// non-PIC code.
+def relocImm : ComplexPattern<iAny, 1, "selectRelocImm", [imm, X86Wrapper], [],
+ 0>;
+
//===----------------------------------------------------------------------===//
// X86 Instruction Predicate Definitions.
def TruePredicate : Predicate<"true">;
@@ -832,6 +838,7 @@ def HasTBM : Predicate<"Subtarget->hasTBM()">;
def HasMOVBE : Predicate<"Subtarget->hasMOVBE()">;
def HasRDRAND : Predicate<"Subtarget->hasRDRAND()">;
def HasF16C : Predicate<"Subtarget->hasF16C()">;
+def NoF16C : Predicate<"!Subtarget->hasF16C()">;
def HasFSGSBase : Predicate<"Subtarget->hasFSGSBase()">;
def HasLZCNT : Predicate<"Subtarget->hasLZCNT()">;
def HasBMI : Predicate<"Subtarget->hasBMI()">;
@@ -876,8 +883,6 @@ def IsNaCl : Predicate<"Subtarget->isTargetNaCl()">;
def NotNaCl : Predicate<"!Subtarget->isTargetNaCl()">;
def SmallCode : Predicate<"TM.getCodeModel() == CodeModel::Small">;
def KernelCode : Predicate<"TM.getCodeModel() == CodeModel::Kernel">;
-def FarData : Predicate<"TM.getCodeModel() != CodeModel::Small &&"
- "TM.getCodeModel() != CodeModel::Kernel">;
def NearData : Predicate<"TM.getCodeModel() == CodeModel::Small ||"
"TM.getCodeModel() == CodeModel::Kernel">;
def IsNotPIC : Predicate<"!TM.isPositionIndependent()">;
@@ -889,6 +894,7 @@ def CallImmAddr : Predicate<"Subtarget->isLegalToCallImmediateAddr()">;
def FavorMemIndirectCall : Predicate<"!Subtarget->callRegIndirect()">;
def NotSlowIncDec : Predicate<"!Subtarget->slowIncDec()">;
def HasFastMem32 : Predicate<"!Subtarget->isUnalignedMem32Slow()">;
+def HasFastLZCNT : Predicate<"Subtarget->hasFastLZCNT()">;
def HasMFence : Predicate<"Subtarget->hasMFence()">;
//===----------------------------------------------------------------------===//
@@ -923,6 +929,7 @@ def X86_COND_S : PatLeaf<(i8 15)>;
def i16immSExt8 : ImmLeaf<i16, [{ return isInt<8>(Imm); }]>;
def i32immSExt8 : ImmLeaf<i32, [{ return isInt<8>(Imm); }]>;
def i64immSExt8 : ImmLeaf<i64, [{ return isInt<8>(Imm); }]>;
+def i64immSExt32 : ImmLeaf<i64, [{ return isInt<32>(Imm); }]>;
// If we have multiple users of an immediate, it's much smaller to reuse
// the register, rather than encode the immediate in every instruction.
@@ -941,13 +948,16 @@ def i64immSExt8 : ImmLeaf<i64, [{ return isInt<8>(Imm); }]>;
// Eventually, it would be nice to allow ConstantHoisting to merge constants
// globally for potentially added savings.
//
-def imm8_su : PatLeaf<(i8 imm), [{
+def imm8_su : PatLeaf<(i8 relocImm), [{
+ return !shouldAvoidImmediateInstFormsForSize(N);
+}]>;
+def imm16_su : PatLeaf<(i16 relocImm), [{
return !shouldAvoidImmediateInstFormsForSize(N);
}]>;
-def imm16_su : PatLeaf<(i16 imm), [{
+def imm32_su : PatLeaf<(i32 relocImm), [{
return !shouldAvoidImmediateInstFormsForSize(N);
}]>;
-def imm32_su : PatLeaf<(i32 imm), [{
+def i64immSExt32_su : PatLeaf<(i64immSExt32), [{
return !shouldAvoidImmediateInstFormsForSize(N);
}]>;
@@ -957,10 +967,9 @@ def i16immSExt8_su : PatLeaf<(i16immSExt8), [{
def i32immSExt8_su : PatLeaf<(i32immSExt8), [{
return !shouldAvoidImmediateInstFormsForSize(N);
}]>;
-
-
-def i64immSExt32 : ImmLeaf<i64, [{ return isInt<32>(Imm); }]>;
-
+def i64immSExt8_su : PatLeaf<(i64immSExt8), [{
+ return !shouldAvoidImmediateInstFormsForSize(N);
+}]>;
// i64immZExt32 predicate - True if the 64-bit immediate fits in a 32-bit
// unsigned field.
@@ -1375,7 +1384,7 @@ def MOV16ri : Ii16<0xB8, AddRegFrm, (outs GR16:$dst), (ins i16imm:$src),
[(set GR16:$dst, imm:$src)], IIC_MOV>, OpSize16;
def MOV32ri : Ii32<0xB8, AddRegFrm, (outs GR32:$dst), (ins i32imm:$src),
"mov{l}\t{$src, $dst|$dst, $src}",
- [(set GR32:$dst, imm:$src)], IIC_MOV>, OpSize32;
+ [(set GR32:$dst, relocImm:$src)], IIC_MOV>, OpSize32;
def MOV64ri32 : RIi32S<0xC7, MRM0r, (outs GR64:$dst), (ins i64i32imm:$src),
"mov{q}\t{$src, $dst|$dst, $src}",
[(set GR64:$dst, i64immSExt32:$src)], IIC_MOV>;
@@ -1383,7 +1392,7 @@ def MOV64ri32 : RIi32S<0xC7, MRM0r, (outs GR64:$dst), (ins i64i32imm:$src),
let isReMaterializable = 1 in {
def MOV64ri : RIi64<0xB8, AddRegFrm, (outs GR64:$dst), (ins i64imm:$src),
"movabs{q}\t{$src, $dst|$dst, $src}",
- [(set GR64:$dst, imm:$src)], IIC_MOV>;
+ [(set GR64:$dst, relocImm:$src)], IIC_MOV>;
}
// Longer forms that use a ModR/M byte. Needed for disassembler
@@ -1409,7 +1418,7 @@ def MOV32mi : Ii32<0xC7, MRM0m, (outs), (ins i32mem:$dst, i32imm:$src),
[(store (i32 imm32_su:$src), addr:$dst)], IIC_MOV_MEM>, OpSize32;
def MOV64mi32 : RIi32S<0xC7, MRM0m, (outs), (ins i64mem:$dst, i64i32imm:$src),
"mov{q}\t{$src, $dst|$dst, $src}",
- [(store i64immSExt32:$src, addr:$dst)], IIC_MOV_MEM>;
+ [(store i64immSExt32_su:$src, addr:$dst)], IIC_MOV_MEM>;
} // SchedRW
let hasSideEffects = 0 in {
@@ -2251,14 +2260,14 @@ let Predicates = [HasBMI] in {
multiclass bmi_bextr_bzhi<bits<8> opc, string mnemonic, RegisterClass RC,
X86MemOperand x86memop, Intrinsic Int,
PatFrag ld_frag> {
- def rr : I<opc, MRMSrcReg, (outs RC:$dst), (ins RC:$src1, RC:$src2),
+ def rr : I<opc, MRMSrcReg4VOp3, (outs RC:$dst), (ins RC:$src1, RC:$src2),
!strconcat(mnemonic, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set RC:$dst, (Int RC:$src1, RC:$src2)), (implicit EFLAGS)]>,
- T8PS, VEX_4VOp3;
- def rm : I<opc, MRMSrcMem, (outs RC:$dst), (ins x86memop:$src1, RC:$src2),
+ T8PS, VEX;
+ def rm : I<opc, MRMSrcMem4VOp3, (outs RC:$dst), (ins x86memop:$src1, RC:$src2),
!strconcat(mnemonic, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set RC:$dst, (Int (ld_frag addr:$src1), RC:$src2)),
- (implicit EFLAGS)]>, T8PS, VEX_4VOp3;
+ (implicit EFLAGS)]>, T8PS, VEX;
}
let Predicates = [HasBMI], Defs = [EFLAGS] in {
@@ -2626,6 +2635,12 @@ def : MnemonicAlias<"ret", "retw", "att">, Requires<[In16BitMode]>;
def : MnemonicAlias<"ret", "retl", "att">, Requires<[In32BitMode]>;
def : MnemonicAlias<"ret", "retq", "att">, Requires<[In64BitMode]>;
+// Apply 'ret' behavior to 'retn'
+def : MnemonicAlias<"retn", "retw", "att">, Requires<[In16BitMode]>;
+def : MnemonicAlias<"retn", "retl", "att">, Requires<[In32BitMode]>;
+def : MnemonicAlias<"retn", "retq", "att">, Requires<[In64BitMode]>;
+def : MnemonicAlias<"retn", "ret", "intel">;
+
def : MnemonicAlias<"sal", "shl", "intel">;
def : MnemonicAlias<"salb", "shlb", "att">;
def : MnemonicAlias<"salw", "shlw", "att">;
diff --git a/contrib/llvm/lib/Target/X86/X86InstrMMX.td b/contrib/llvm/lib/Target/X86/X86InstrMMX.td
index 8d70691..0bb1068 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrMMX.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrMMX.td
@@ -150,8 +150,9 @@ multiclass SS3I_unop_rm_int_mm<bits<8> opc, string OpcodeStr,
/// Binary MMX instructions requiring SSSE3.
let ImmT = NoImm, Constraints = "$src1 = $dst" in {
multiclass SS3I_binop_rm_int_mm<bits<8> opc, string OpcodeStr,
- Intrinsic IntId64, OpndItins itins> {
- let isCommutable = 0 in
+ Intrinsic IntId64, OpndItins itins,
+ bit Commutable = 0> {
+ let isCommutable = Commutable in
def rr64 : MMXSS38I<opc, MRMSrcReg, (outs VR64:$dst),
(ins VR64:$src1, VR64:$src2),
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
@@ -418,9 +419,9 @@ defm MMX_PMULHUW : MMXI_binop_rm_int<0xE4, "pmulhuw", int_x86_mmx_pmulhu_w,
let Predicates = [HasSSE2] in
defm MMX_PMULUDQ : MMXI_binop_rm_int<0xF4, "pmuludq", int_x86_mmx_pmulu_dq,
MMX_PMUL_ITINS, 1>;
-let isCommutable = 1 in
defm MMX_PMULHRSW : SS3I_binop_rm_int_mm<0x0B, "pmulhrsw",
- int_x86_ssse3_pmul_hr_sw, MMX_PMUL_ITINS>;
+ int_x86_ssse3_pmul_hr_sw,
+ MMX_PMUL_ITINS, 1>;
// -- Miscellanea
defm MMX_PMADDWD : MMXI_binop_rm_int<0xF5, "pmaddwd", int_x86_mmx_pmadd_wd,
diff --git a/contrib/llvm/lib/Target/X86/X86InstrSSE.td b/contrib/llvm/lib/Target/X86/X86InstrSSE.td
index f91764a..1812d01 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrSSE.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrSSE.td
@@ -33,7 +33,6 @@ class ShiftOpndItins<InstrItinClass arg_rr, InstrItinClass arg_rm,
InstrItinClass ri = arg_ri;
}
-
// scalar
let Sched = WriteFAdd in {
def SSE_ALU_F32S : OpndItins<
@@ -259,26 +258,24 @@ multiclass sse12_fp_scalar<bits<8> opc, string OpcodeStr, SDNode OpNode,
}
/// sse12_fp_scalar_int - SSE 1 & 2 scalar instructions intrinsics class
-multiclass sse12_fp_scalar_int<bits<8> opc, string OpcodeStr, RegisterClass RC,
- string asm, string SSEVer, string FPSizeStr,
- Operand memopr, ComplexPattern mem_cpat,
- Domain d, OpndItins itins, bit Is2Addr = 1> {
-let isCodeGenOnly = 1 in {
+multiclass sse12_fp_scalar_int<bits<8> opc, string OpcodeStr,
+ SDPatternOperator Int, RegisterClass RC,
+ string asm, Operand memopr,
+ ComplexPattern mem_cpat, Domain d,
+ OpndItins itins, bit Is2Addr = 1> {
+let isCodeGenOnly = 1, hasSideEffects = 0 in {
def rr_Int : SI_Int<opc, MRMSrcReg, (outs RC:$dst), (ins RC:$src1, RC:$src2),
!if(Is2Addr,
!strconcat(asm, "\t{$src2, $dst|$dst, $src2}"),
!strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (!cast<Intrinsic>(
- !strconcat("int_x86_sse", SSEVer, "_", OpcodeStr, FPSizeStr))
- RC:$src1, RC:$src2))], itins.rr, d>,
+ [(set RC:$dst, (Int RC:$src1, RC:$src2))], itins.rr, d>,
Sched<[itins.Sched]>;
+ let mayLoad = 1 in
def rm_Int : SI_Int<opc, MRMSrcMem, (outs RC:$dst), (ins RC:$src1, memopr:$src2),
!if(Is2Addr,
!strconcat(asm, "\t{$src2, $dst|$dst, $src2}"),
!strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (!cast<Intrinsic>(!strconcat("int_x86_sse",
- SSEVer, "_", OpcodeStr, FPSizeStr))
- RC:$src1, mem_cpat:$src2))], itins.rm, d>,
+ [(set RC:$dst, (Int RC:$src1, mem_cpat:$src2))], itins.rm, d>,
Sched<[itins.Sched.Folded, ReadAfterLd]>;
}
}
@@ -372,13 +369,9 @@ def : Pat<(insert_subvector undef, (v16i8 VR128:$src), (iPTR 0)),
// Implicitly promote a 32-bit scalar to a vector.
def : Pat<(v4f32 (scalar_to_vector FR32:$src)),
(COPY_TO_REGCLASS FR32:$src, VR128)>;
-def : Pat<(v8f32 (scalar_to_vector FR32:$src)),
- (COPY_TO_REGCLASS FR32:$src, VR128)>;
// Implicitly promote a 64-bit scalar to a vector.
def : Pat<(v2f64 (scalar_to_vector FR64:$src)),
(COPY_TO_REGCLASS FR64:$src, VR128)>;
-def : Pat<(v4f64 (scalar_to_vector FR64:$src)),
- (COPY_TO_REGCLASS FR64:$src, VR128)>;
// Bitcasts between 128-bit vector types. Return the original type since
// no instruction is needed for the conversion
@@ -453,9 +446,9 @@ def : Pat<(v4f64 (bitconvert (v8f32 VR256:$src))), (v4f64 VR256:$src)>;
let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1,
isPseudo = 1, SchedRW = [WriteZero] in {
def FsFLD0SS : I<0, Pseudo, (outs FR32:$dst), (ins), "",
- [(set FR32:$dst, fp32imm0)]>, Requires<[HasSSE1]>;
+ [(set FR32:$dst, fp32imm0)]>, Requires<[HasSSE1, NoVLX_Or_NoDQI]>;
def FsFLD0SD : I<0, Pseudo, (outs FR64:$dst), (ins), "",
- [(set FR64:$dst, fpimm0)]>, Requires<[HasSSE2]>;
+ [(set FR64:$dst, fpimm0)]>, Requires<[HasSSE2, NoVLX_Or_NoDQI]>;
}
//===----------------------------------------------------------------------===//
@@ -512,6 +505,7 @@ let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1,
multiclass sse12_move_rr<RegisterClass RC, SDNode OpNode, ValueType vt,
X86MemOperand x86memop, string base_opc,
string asm_opr, Domain d = GenericDomain> {
+ let isCommutable = 1 in
def rr : SI<0x10, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, RC:$src2),
!strconcat(base_opc, asm_opr),
@@ -590,6 +584,8 @@ let Predicates = [UseAVX] in {
(COPY_TO_REGCLASS (VMOVSSrm addr:$src), VR128)>;
def : Pat<(v4f32 (X86vzmovl (loadv4f32 addr:$src))),
(COPY_TO_REGCLASS (VMOVSSrm addr:$src), VR128)>;
+ def : Pat<(v4f32 (X86vzload addr:$src)),
+ (COPY_TO_REGCLASS (VMOVSSrm addr:$src), VR128)>;
// MOVSDrm zeros the high parts of the register; represent this
// with SUBREG_TO_REG. The AVX versions also write: DST[255:128] <- 0
@@ -609,6 +605,8 @@ let Predicates = [UseAVX] in {
def : Pat<(v8f32 (X86vzmovl (insert_subvector undef,
(v4f32 (scalar_to_vector (loadf32 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVSSrm addr:$src), sub_xmm)>;
+ def : Pat<(v8f32 (X86vzload addr:$src)),
+ (SUBREG_TO_REG (i32 0), (VMOVSSrm addr:$src), sub_xmm)>;
def : Pat<(v4f64 (X86vzmovl (insert_subvector undef,
(v2f64 (scalar_to_vector (loadf64 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVSDrm addr:$src), sub_xmm)>;
@@ -697,6 +695,8 @@ let Predicates = [UseSSE1] in {
(COPY_TO_REGCLASS (MOVSSrm addr:$src), VR128)>;
def : Pat<(v4f32 (X86vzmovl (loadv4f32 addr:$src))),
(COPY_TO_REGCLASS (MOVSSrm addr:$src), VR128)>;
+ def : Pat<(v4f32 (X86vzload addr:$src)),
+ (COPY_TO_REGCLASS (MOVSSrm addr:$src), VR128)>;
}
// Extract and store.
@@ -771,13 +771,12 @@ def : InstAlias<"vmovsd\t{$src2, $src1, $dst|$dst, $src1, $src2}",
multiclass sse12_mov_packed<bits<8> opc, RegisterClass RC,
X86MemOperand x86memop, PatFrag ld_frag,
string asm, Domain d,
- OpndItins itins,
- bit IsReMaterializable = 1> {
+ OpndItins itins> {
let hasSideEffects = 0 in
def rr : PI<opc, MRMSrcReg, (outs RC:$dst), (ins RC:$src),
!strconcat(asm, "\t{$src, $dst|$dst, $src}"), [], itins.rr, d>,
Sched<[WriteFShuffle]>;
-let canFoldAsLoad = 1, isReMaterializable = IsReMaterializable in
+let canFoldAsLoad = 1, isReMaterializable = 1 in
def rm : PI<opc, MRMSrcMem, (outs RC:$dst), (ins x86memop:$src),
!strconcat(asm, "\t{$src, $dst|$dst, $src}"),
[(set RC:$dst, (ld_frag addr:$src))], itins.rm, d>,
@@ -795,7 +794,7 @@ defm VMOVUPS : sse12_mov_packed<0x10, VR128, f128mem, loadv4f32,
"movups", SSEPackedSingle, SSE_MOVU_ITINS>,
PS, VEX;
defm VMOVUPD : sse12_mov_packed<0x10, VR128, f128mem, loadv2f64,
- "movupd", SSEPackedDouble, SSE_MOVU_ITINS, 0>,
+ "movupd", SSEPackedDouble, SSE_MOVU_ITINS>,
PD, VEX;
defm VMOVAPSY : sse12_mov_packed<0x28, VR256, f256mem, alignedloadv8f32,
@@ -808,7 +807,7 @@ defm VMOVUPSY : sse12_mov_packed<0x10, VR256, f256mem, loadv8f32,
"movups", SSEPackedSingle, SSE_MOVU_ITINS>,
PS, VEX, VEX_L;
defm VMOVUPDY : sse12_mov_packed<0x10, VR256, f256mem, loadv4f64,
- "movupd", SSEPackedDouble, SSE_MOVU_ITINS, 0>,
+ "movupd", SSEPackedDouble, SSE_MOVU_ITINS>,
PD, VEX, VEX_L;
}
@@ -825,7 +824,7 @@ defm MOVAPD : sse12_mov_packed<0x28, VR128, f128mem, alignedloadv2f64,
"movapd", SSEPackedDouble, SSE_MOVA_ITINS>,
PD;
defm MOVUPD : sse12_mov_packed<0x10, VR128, f128mem, loadv2f64,
- "movupd", SSEPackedDouble, SSE_MOVU_ITINS, 0>,
+ "movupd", SSEPackedDouble, SSE_MOVU_ITINS>,
PD;
}
@@ -1028,7 +1027,7 @@ let Predicates = [HasAVX, NoVLX] in {
(VMOVUPSmr addr:$dst, (v16i8 (EXTRACT_SUBREG VR256:$src,sub_xmm)))>;
}
-let Predicates = [HasAVX, NoVLX_Or_NoBWI] in {
+let Predicates = [HasAVX, NoVLX] in {
// 128-bit load/store
def : Pat<(alignedstore (v8i16 VR128:$src), addr:$dst),
(VMOVAPSmr addr:$dst, VR128:$src)>;
@@ -1077,29 +1076,6 @@ let Predicates = [UseSSE1] in {
(MOVUPSmr addr:$dst, VR128:$src)>;
}
-// Alias instruction to load FR32 or FR64 from f128mem using movaps. Upper
-// bits are disregarded. FIXME: Set encoding to pseudo!
-let canFoldAsLoad = 1, isReMaterializable = 1, SchedRW = [WriteLoad] in {
-let isCodeGenOnly = 1 in {
- def FsVMOVAPSrm : VPSI<0x28, MRMSrcMem, (outs FR32:$dst), (ins f128mem:$src),
- "movaps\t{$src, $dst|$dst, $src}",
- [(set FR32:$dst, (alignedloadfsf32 addr:$src))],
- IIC_SSE_MOVA_P_RM>, VEX;
- def FsVMOVAPDrm : VPDI<0x28, MRMSrcMem, (outs FR64:$dst), (ins f128mem:$src),
- "movapd\t{$src, $dst|$dst, $src}",
- [(set FR64:$dst, (alignedloadfsf64 addr:$src))],
- IIC_SSE_MOVA_P_RM>, VEX;
- def FsMOVAPSrm : PSI<0x28, MRMSrcMem, (outs FR32:$dst), (ins f128mem:$src),
- "movaps\t{$src, $dst|$dst, $src}",
- [(set FR32:$dst, (alignedloadfsf32 addr:$src))],
- IIC_SSE_MOVA_P_RM>;
- def FsMOVAPDrm : PDI<0x28, MRMSrcMem, (outs FR64:$dst), (ins f128mem:$src),
- "movapd\t{$src, $dst|$dst, $src}",
- [(set FR64:$dst, (alignedloadfsf64 addr:$src))],
- IIC_SSE_MOVA_P_RM>;
-}
-}
-
//===----------------------------------------------------------------------===//
// SSE 1 & 2 - Move Low packed FP Instructions
//===----------------------------------------------------------------------===//
@@ -1300,6 +1276,7 @@ let Predicates = [UseAVX] in {
def : Pat<(v2f64 (X86Unpckl VR128:$src1,
(scalar_to_vector (loadf64 addr:$src2)))),
(VMOVHPDrm VR128:$src1, addr:$src2)>;
+
// Also handle an i64 load because that may get selected as a faster way to
// load the data.
def : Pat<(v2f64 (X86Unpckl VR128:$src1,
@@ -1307,6 +1284,11 @@ let Predicates = [UseAVX] in {
(VMOVHPDrm VR128:$src1, addr:$src2)>;
def : Pat<(store (f64 (extractelt
+ (bc_v2f64 (v4f32 (X86Movhlps VR128:$src, VR128:$src))),
+ (iPTR 0))), addr:$dst),
+ (VMOVHPDmr addr:$dst, VR128:$src)>;
+
+ def : Pat<(store (f64 (extractelt
(v2f64 (X86VPermilpi VR128:$src, (i8 1))),
(iPTR 0))), addr:$dst),
(VMOVHPDmr addr:$dst, VR128:$src)>;
@@ -1332,6 +1314,7 @@ let Predicates = [UseSSE2] in {
def : Pat<(v2f64 (X86Unpckl VR128:$src1,
(scalar_to_vector (loadf64 addr:$src2)))),
(MOVHPDrm VR128:$src1, addr:$src2)>;
+
// Also handle an i64 load because that may get selected as a faster way to
// load the data.
def : Pat<(v2f64 (X86Unpckl VR128:$src1,
@@ -1339,6 +1322,11 @@ let Predicates = [UseSSE2] in {
(MOVHPDrm VR128:$src1, addr:$src2)>;
def : Pat<(store (f64 (extractelt
+ (bc_v2f64 (v4f32 (X86Movhlps VR128:$src, VR128:$src))),
+ (iPTR 0))), addr:$dst),
+ (MOVHPDmr addr:$dst, VR128:$src)>;
+
+ def : Pat<(store (f64 (extractelt
(v2f64 (X86Shufp VR128:$src, VR128:$src, (i8 1))),
(iPTR 0))), addr:$dst),
(MOVHPDmr addr:$dst, VR128:$src)>;
@@ -1371,6 +1359,7 @@ let Constraints = "$src1 = $dst", AddedComplexity = 20 in {
[(set VR128:$dst,
(v4f32 (X86Movlhps VR128:$src1, VR128:$src2)))],
IIC_SSE_MOV_LH>, Sched<[WriteFShuffle]>;
+ let isCommutable = 1 in
def MOVHLPSrr : PSI<0x12, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2),
"movhlps\t{$src2, $dst|$dst, $src2}",
@@ -1449,15 +1438,18 @@ multiclass sse12_cvt_s<bits<8> opc, RegisterClass SrcRC, RegisterClass DstRC,
itins.rm>, Sched<[itins.Sched.Folded]>;
}
-multiclass sse12_cvt_p<bits<8> opc, RegisterClass SrcRC, RegisterClass DstRC,
- X86MemOperand x86memop, string asm, Domain d,
- OpndItins itins> {
+multiclass sse12_cvt_p<bits<8> opc, RegisterClass RC, X86MemOperand x86memop,
+ ValueType DstTy, ValueType SrcTy, PatFrag ld_frag,
+ string asm, Domain d, OpndItins itins> {
let hasSideEffects = 0 in {
- def rr : I<opc, MRMSrcReg, (outs DstRC:$dst), (ins SrcRC:$src), asm,
- [], itins.rr, d>, Sched<[itins.Sched]>;
+ def rr : I<opc, MRMSrcReg, (outs RC:$dst), (ins RC:$src), asm,
+ [(set RC:$dst, (DstTy (sint_to_fp (SrcTy RC:$src))))],
+ itins.rr, d>, Sched<[itins.Sched]>;
let mayLoad = 1 in
- def rm : I<opc, MRMSrcMem, (outs DstRC:$dst), (ins x86memop:$src), asm,
- [], itins.rm, d>, Sched<[itins.Sched.Folded]>;
+ def rm : I<opc, MRMSrcMem, (outs RC:$dst), (ins x86memop:$src), asm,
+ [(set RC:$dst, (DstTy (sint_to_fp
+ (SrcTy (bitconvert (ld_frag addr:$src))))))],
+ itins.rm, d>, Sched<[itins.Sched.Folded]>;
}
}
@@ -1730,16 +1722,16 @@ defm CVTSS2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, int_x86_sse_cvtss2si64,
ssmem, sse_load_f32, "cvtss2si",
SSE_CVT_SS2SI_64>, XS, REX_W;
-defm VCVTDQ2PS : sse12_cvt_p<0x5B, VR128, VR128, i128mem,
+defm VCVTDQ2PS : sse12_cvt_p<0x5B, VR128, i128mem, v4f32, v4i32, loadv2i64,
"vcvtdq2ps\t{$src, $dst|$dst, $src}",
SSEPackedSingle, SSE_CVT_PS>,
- PS, VEX, Requires<[HasAVX]>;
-defm VCVTDQ2PSY : sse12_cvt_p<0x5B, VR256, VR256, i256mem,
+ PS, VEX, Requires<[HasAVX, NoVLX]>;
+defm VCVTDQ2PSY : sse12_cvt_p<0x5B, VR256, i256mem, v8f32, v8i32, loadv4i64,
"vcvtdq2ps\t{$src, $dst|$dst, $src}",
SSEPackedSingle, SSE_CVT_PS>,
- PS, VEX, VEX_L, Requires<[HasAVX]>;
+ PS, VEX, VEX_L, Requires<[HasAVX, NoVLX]>;
-defm CVTDQ2PS : sse12_cvt_p<0x5B, VR128, VR128, i128mem,
+defm CVTDQ2PS : sse12_cvt_p<0x5B, VR128, i128mem, v4f32, v4i32, memopv2i64,
"cvtdq2ps\t{$src, $dst|$dst, $src}",
SSEPackedSingle, SSE_CVT_PS>,
PS, Requires<[UseSSE2]>;
@@ -1798,16 +1790,16 @@ def VCVTSD2SSrm : I<0x5A, MRMSrcMem, (outs FR32:$dst),
Sched<[WriteCvtF2FLd, ReadAfterLd]>;
}
-def : Pat<(f32 (fround FR64:$src)), (VCVTSD2SSrr FR64:$src, FR64:$src)>,
+def : Pat<(f32 (fpround FR64:$src)), (VCVTSD2SSrr FR64:$src, FR64:$src)>,
Requires<[UseAVX]>;
def CVTSD2SSrr : SDI<0x5A, MRMSrcReg, (outs FR32:$dst), (ins FR64:$src),
"cvtsd2ss\t{$src, $dst|$dst, $src}",
- [(set FR32:$dst, (fround FR64:$src))],
+ [(set FR32:$dst, (fpround FR64:$src))],
IIC_SSE_CVT_Scalar_RR>, Sched<[WriteCvtF2F]>;
def CVTSD2SSrm : I<0x5A, MRMSrcMem, (outs FR32:$dst), (ins f64mem:$src),
"cvtsd2ss\t{$src, $dst|$dst, $src}",
- [(set FR32:$dst, (fround (loadf64 addr:$src)))],
+ [(set FR32:$dst, (fpround (loadf64 addr:$src)))],
IIC_SSE_CVT_Scalar_RM>,
XD,
Requires<[UseSSE2, OptForSize]>, Sched<[WriteCvtF2FLd]>;
@@ -1864,9 +1856,9 @@ def VCVTSS2SDrm : I<0x5A, MRMSrcMem, (outs FR64:$dst),
Sched<[WriteCvtF2FLd, ReadAfterLd]>;
}
-def : Pat<(f64 (fextend FR32:$src)),
+def : Pat<(f64 (fpextend FR32:$src)),
(VCVTSS2SDrr FR32:$src, FR32:$src)>, Requires<[UseAVX]>;
-def : Pat<(fextend (loadf32 addr:$src)),
+def : Pat<(fpextend (loadf32 addr:$src)),
(VCVTSS2SDrm (f32 (IMPLICIT_DEF)), addr:$src)>, Requires<[UseAVX]>;
def : Pat<(extloadf32 addr:$src),
@@ -1878,7 +1870,7 @@ def : Pat<(extloadf32 addr:$src),
def CVTSS2SDrr : I<0x5A, MRMSrcReg, (outs FR64:$dst), (ins FR32:$src),
"cvtss2sd\t{$src, $dst|$dst, $src}",
- [(set FR64:$dst, (fextend FR32:$src))],
+ [(set FR64:$dst, (fpextend FR32:$src))],
IIC_SSE_CVT_Scalar_RR>, XS,
Requires<[UseSSE2]>, Sched<[WriteCvtF2F]>;
def CVTSS2SDrm : I<0x5A, MRMSrcMem, (outs FR64:$dst), (ins f32mem:$src),
@@ -1887,12 +1879,12 @@ def CVTSS2SDrm : I<0x5A, MRMSrcMem, (outs FR64:$dst), (ins f32mem:$src),
IIC_SSE_CVT_Scalar_RM>, XS,
Requires<[UseSSE2, OptForSize]>, Sched<[WriteCvtF2FLd]>;
-// extload f32 -> f64. This matches load+fextend because we have a hack in
+// extload f32 -> f64. This matches load+fpextend because we have a hack in
// the isel (PreprocessForFPConvert) that can introduce loads after dag
// combine.
-// Since these loads aren't folded into the fextend, we have to match it
+// Since these loads aren't folded into the fpextend, we have to match it
// explicitly here.
-def : Pat<(fextend (loadf32 addr:$src)),
+def : Pat<(fpextend (loadf32 addr:$src)),
(CVTSS2SDrm addr:$src)>, Requires<[UseSSE2]>;
def : Pat<(extloadf32 addr:$src),
(CVTSS2SDrr (MOVSSrm addr:$src))>, Requires<[UseSSE2, OptForSpeed]>;
@@ -1930,6 +1922,79 @@ def Int_CVTSS2SDrm: I<0x5A, MRMSrcMem,
}
} // isCodeGenOnly = 1
+// Patterns used for matching (v)cvtsi2ss, (v)cvtsi2sd, (v)cvtsd2ss and
+// (v)cvtss2sd intrinsic sequences from clang which produce unnecessary
+// vmovs{s,d} instructions
+let Predicates = [UseAVX] in {
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128:$dst),
+ (v4f32 (scalar_to_vector
+ (f32 (fpround (f64 (extractelt VR128:$src, (iPTR 0))))))))),
+ (Int_VCVTSD2SSrr VR128:$dst, VR128:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128:$dst),
+ (v2f64 (scalar_to_vector
+ (f64 (fpextend (f32 (extractelt VR128:$src, (iPTR 0))))))))),
+ (Int_VCVTSS2SDrr VR128:$dst, VR128:$src)>;
+
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128:$dst),
+ (v4f32 (scalar_to_vector (f32 (sint_to_fp GR64:$src)))))),
+ (Int_VCVTSI2SS64rr VR128:$dst, GR64:$src)>;
+
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128:$dst),
+ (v4f32 (scalar_to_vector (f32 (sint_to_fp GR32:$src)))))),
+ (Int_VCVTSI2SSrr VR128:$dst, GR32:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128:$dst),
+ (v2f64 (scalar_to_vector (f64 (sint_to_fp GR64:$src)))))),
+ (Int_VCVTSI2SD64rr VR128:$dst, GR64:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128:$dst),
+ (v2f64 (scalar_to_vector (f64 (sint_to_fp GR32:$src)))))),
+ (Int_VCVTSI2SDrr VR128:$dst, GR32:$src)>;
+} // Predicates = [UseAVX]
+
+let Predicates = [UseSSE2] in {
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128:$dst),
+ (v4f32 (scalar_to_vector
+ (f32 (fpround (f64 (extractelt VR128:$src, (iPTR 0))))))))),
+ (Int_CVTSD2SSrr VR128:$dst, VR128:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128:$dst),
+ (v2f64 (scalar_to_vector
+ (f64 (fpextend (f32 (extractelt VR128:$src, (iPTR 0))))))))),
+ (Int_CVTSS2SDrr VR128:$dst, VR128:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128:$dst),
+ (v2f64 (scalar_to_vector (f64 (sint_to_fp GR64:$src)))))),
+ (Int_CVTSI2SD64rr VR128:$dst, GR64:$src)>;
+
+def : Pat<(v2f64 (X86Movsd
+ (v2f64 VR128:$dst),
+ (v2f64 (scalar_to_vector (f64 (sint_to_fp GR32:$src)))))),
+ (Int_CVTSI2SDrr VR128:$dst, GR32:$src)>;
+} // Predicates = [UseSSE2]
+
+let Predicates = [UseSSE1] in {
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128:$dst),
+ (v4f32 (scalar_to_vector (f32 (sint_to_fp GR64:$src)))))),
+ (Int_CVTSI2SS64rr VR128:$dst, GR64:$src)>;
+
+def : Pat<(v4f32 (X86Movss
+ (v4f32 VR128:$dst),
+ (v4f32 (scalar_to_vector (f32 (sint_to_fp GR32:$src)))))),
+ (Int_CVTSI2SSrr VR128:$dst, GR32:$src)>;
+} // Predicates = [UseSSE1]
+
// Convert packed single/double fp to doubleword
def VCVTPS2DQrr : VPDI<0x5B, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvtps2dq\t{$src, $dst|$dst, $src}",
@@ -1962,134 +2027,98 @@ def CVTPS2DQrm : PDI<0x5B, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
// Convert Packed Double FP to Packed DW Integers
-let Predicates = [HasAVX] in {
+let Predicates = [HasAVX, NoVLX] in {
// The assembler can recognize rr 256-bit instructions by seeing a ymm
// register, but the same isn't true when using memory operands instead.
// Provide other assembly rr and rm forms to address this explicitly.
def VCVTPD2DQrr : SDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"vcvtpd2dq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvtpd2dq VR128:$src))]>,
+ [(set VR128:$dst,
+ (v4i32 (X86cvtp2Int (v2f64 VR128:$src))))]>,
VEX, Sched<[WriteCvtF2I]>;
// XMM only
def : InstAlias<"vcvtpd2dqx\t{$src, $dst|$dst, $src}",
(VCVTPD2DQrr VR128:$dst, VR128:$src), 0>;
-def VCVTPD2DQXrm : SDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
- "vcvtpd2dqx\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (int_x86_sse2_cvtpd2dq (loadv2f64 addr:$src)))]>, VEX,
- Sched<[WriteCvtF2ILd]>;
+def VCVTPD2DQrm : SDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
+ "vcvtpd2dq{x}\t{$src, $dst|$dst, $src}",
+ [(set VR128:$dst,
+ (v4i32 (X86cvtp2Int (loadv2f64 addr:$src))))]>, VEX,
+ Sched<[WriteCvtF2ILd]>;
+def : InstAlias<"vcvtpd2dqx\t{$src, $dst|$dst, $src}",
+ (VCVTPD2DQrm VR128:$dst, f128mem:$src), 0>;
// YMM only
def VCVTPD2DQYrr : SDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR256:$src),
- "vcvtpd2dq{y}\t{$src, $dst|$dst, $src}",
+ "vcvtpd2dq\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_avx_cvt_pd2dq_256 VR256:$src))]>, VEX, VEX_L,
- Sched<[WriteCvtF2I]>;
+ (v4i32 (X86cvtp2Int (v4f64 VR256:$src))))]>,
+ VEX, VEX_L, Sched<[WriteCvtF2I]>;
def VCVTPD2DQYrm : SDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f256mem:$src),
"vcvtpd2dq{y}\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_avx_cvt_pd2dq_256 (loadv4f64 addr:$src)))]>,
+ (v4i32 (X86cvtp2Int (loadv4f64 addr:$src))))]>,
VEX, VEX_L, Sched<[WriteCvtF2ILd]>;
-def : InstAlias<"vcvtpd2dq\t{$src, $dst|$dst, $src}",
+def : InstAlias<"vcvtpd2dqy\t{$src, $dst|$dst, $src}",
(VCVTPD2DQYrr VR128:$dst, VR256:$src), 0>;
+def : InstAlias<"vcvtpd2dqy\t{$src, $dst|$dst, $src}",
+ (VCVTPD2DQYrm VR128:$dst, f256mem:$src), 0>;
}
def CVTPD2DQrm : SDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
"cvtpd2dq\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_sse2_cvtpd2dq (memopv2f64 addr:$src)))],
+ (v4i32 (X86cvtp2Int (memopv2f64 addr:$src))))],
IIC_SSE_CVT_PD_RM>, Sched<[WriteCvtF2ILd]>;
def CVTPD2DQrr : SDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvtpd2dq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvtpd2dq VR128:$src))],
+ [(set VR128:$dst,
+ (v4i32 (X86cvtp2Int (v2f64 VR128:$src))))],
IIC_SSE_CVT_PD_RR>, Sched<[WriteCvtF2I]>;
// Convert with truncation packed single/double fp to doubleword
// SSE2 packed instructions with XS prefix
+let Predicates = [HasAVX, NoVLX] in {
def VCVTTPS2DQrr : VS2SI<0x5B, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvttps2dq\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_sse2_cvttps2dq VR128:$src))],
+ (v4i32 (fp_to_sint (v4f32 VR128:$src))))],
IIC_SSE_CVT_PS_RR>, VEX, Sched<[WriteCvtF2I]>;
def VCVTTPS2DQrm : VS2SI<0x5B, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
"cvttps2dq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvttps2dq
- (loadv4f32 addr:$src)))],
+ [(set VR128:$dst,
+ (v4i32 (fp_to_sint (loadv4f32 addr:$src))))],
IIC_SSE_CVT_PS_RM>, VEX, Sched<[WriteCvtF2ILd]>;
def VCVTTPS2DQYrr : VS2SI<0x5B, MRMSrcReg, (outs VR256:$dst), (ins VR256:$src),
"cvttps2dq\t{$src, $dst|$dst, $src}",
[(set VR256:$dst,
- (int_x86_avx_cvtt_ps2dq_256 VR256:$src))],
+ (v8i32 (fp_to_sint (v8f32 VR256:$src))))],
IIC_SSE_CVT_PS_RR>, VEX, VEX_L, Sched<[WriteCvtF2I]>;
def VCVTTPS2DQYrm : VS2SI<0x5B, MRMSrcMem, (outs VR256:$dst), (ins f256mem:$src),
"cvttps2dq\t{$src, $dst|$dst, $src}",
- [(set VR256:$dst, (int_x86_avx_cvtt_ps2dq_256
- (loadv8f32 addr:$src)))],
+ [(set VR256:$dst,
+ (v8i32 (fp_to_sint (loadv8f32 addr:$src))))],
IIC_SSE_CVT_PS_RM>, VEX, VEX_L,
Sched<[WriteCvtF2ILd]>;
+}
def CVTTPS2DQrr : S2SI<0x5B, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvttps2dq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvttps2dq VR128:$src))],
+ [(set VR128:$dst,
+ (v4i32 (fp_to_sint (v4f32 VR128:$src))))],
IIC_SSE_CVT_PS_RR>, Sched<[WriteCvtF2I]>;
def CVTTPS2DQrm : S2SI<0x5B, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
"cvttps2dq\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_sse2_cvttps2dq (memopv4f32 addr:$src)))],
+ (v4i32 (fp_to_sint (memopv4f32 addr:$src))))],
IIC_SSE_CVT_PS_RM>, Sched<[WriteCvtF2ILd]>;
-let Predicates = [HasAVX] in {
- def : Pat<(int_x86_sse2_cvtdq2ps VR128:$src),
- (VCVTDQ2PSrr VR128:$src)>;
- def : Pat<(int_x86_sse2_cvtdq2ps (bc_v4i32 (loadv2i64 addr:$src))),
- (VCVTDQ2PSrm addr:$src)>;
-}
-
-let Predicates = [HasAVX, NoVLX] in {
- def : Pat<(v4f32 (sint_to_fp (v4i32 VR128:$src))),
- (VCVTDQ2PSrr VR128:$src)>;
- def : Pat<(v4f32 (sint_to_fp (bc_v4i32 (loadv2i64 addr:$src)))),
- (VCVTDQ2PSrm addr:$src)>;
-
- def : Pat<(v4i32 (fp_to_sint (v4f32 VR128:$src))),
- (VCVTTPS2DQrr VR128:$src)>;
- def : Pat<(v4i32 (fp_to_sint (loadv4f32 addr:$src))),
- (VCVTTPS2DQrm addr:$src)>;
-
- def : Pat<(v8f32 (sint_to_fp (v8i32 VR256:$src))),
- (VCVTDQ2PSYrr VR256:$src)>;
- def : Pat<(v8f32 (sint_to_fp (bc_v8i32 (loadv4i64 addr:$src)))),
- (VCVTDQ2PSYrm addr:$src)>;
-
- def : Pat<(v8i32 (fp_to_sint (v8f32 VR256:$src))),
- (VCVTTPS2DQYrr VR256:$src)>;
- def : Pat<(v8i32 (fp_to_sint (loadv8f32 addr:$src))),
- (VCVTTPS2DQYrm addr:$src)>;
-}
-
-let Predicates = [UseSSE2] in {
- def : Pat<(v4f32 (sint_to_fp (v4i32 VR128:$src))),
- (CVTDQ2PSrr VR128:$src)>;
- def : Pat<(v4f32 (sint_to_fp (bc_v4i32 (memopv2i64 addr:$src)))),
- (CVTDQ2PSrm addr:$src)>;
-
- def : Pat<(int_x86_sse2_cvtdq2ps VR128:$src),
- (CVTDQ2PSrr VR128:$src)>;
- def : Pat<(int_x86_sse2_cvtdq2ps (bc_v4i32 (memopv2i64 addr:$src))),
- (CVTDQ2PSrm addr:$src)>;
-
- def : Pat<(v4i32 (fp_to_sint (v4f32 VR128:$src))),
- (CVTTPS2DQrr VR128:$src)>;
- def : Pat<(v4i32 (fp_to_sint (memopv4f32 addr:$src))),
- (CVTTPS2DQrm addr:$src)>;
-}
-
+let Predicates = [HasAVX, NoVLX] in
def VCVTTPD2DQrr : VPDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvttpd2dq\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_sse2_cvttpd2dq VR128:$src))],
- IIC_SSE_CVT_PD_RR>, VEX, Sched<[WriteCvtF2I]>;
+ (v4i32 (X86cvttp2si (v2f64 VR128:$src))))],
+ IIC_SSE_CVT_PD_RR>, VEX, Sched<[WriteCvtF2I]>;
// The assembler can recognize rr 256-bit instructions by seeing a ymm
// register, but the same isn't true when using memory operands instead.
@@ -2098,66 +2127,92 @@ def VCVTTPD2DQrr : VPDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
// XMM only
def : InstAlias<"vcvttpd2dqx\t{$src, $dst|$dst, $src}",
(VCVTTPD2DQrr VR128:$dst, VR128:$src), 0>;
-def VCVTTPD2DQXrm : VPDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
- "cvttpd2dqx\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvttpd2dq
- (loadv2f64 addr:$src)))],
- IIC_SSE_CVT_PD_RM>, VEX, Sched<[WriteCvtF2ILd]>;
+let Predicates = [HasAVX, NoVLX] in
+def VCVTTPD2DQrm : VPDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
+ "cvttpd2dq{x}\t{$src, $dst|$dst, $src}",
+ [(set VR128:$dst,
+ (v4i32 (X86cvttp2si (loadv2f64 addr:$src))))],
+ IIC_SSE_CVT_PD_RM>, VEX, Sched<[WriteCvtF2ILd]>;
+def : InstAlias<"vcvttpd2dqx\t{$src, $dst|$dst, $src}",
+ (VCVTTPD2DQrm VR128:$dst, f128mem:$src), 0>;
// YMM only
+let Predicates = [HasAVX, NoVLX] in {
def VCVTTPD2DQYrr : VPDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR256:$src),
- "cvttpd2dq{y}\t{$src, $dst|$dst, $src}",
+ "cvttpd2dq\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_avx_cvtt_pd2dq_256 VR256:$src))],
+ (v4i32 (fp_to_sint (v4f64 VR256:$src))))],
IIC_SSE_CVT_PD_RR>, VEX, VEX_L, Sched<[WriteCvtF2I]>;
def VCVTTPD2DQYrm : VPDI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f256mem:$src),
"cvttpd2dq{y}\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
- (int_x86_avx_cvtt_pd2dq_256 (loadv4f64 addr:$src)))],
+ (v4i32 (fp_to_sint (loadv4f64 addr:$src))))],
IIC_SSE_CVT_PD_RM>, VEX, VEX_L, Sched<[WriteCvtF2ILd]>;
-def : InstAlias<"vcvttpd2dq\t{$src, $dst|$dst, $src}",
+}
+def : InstAlias<"vcvttpd2dqy\t{$src, $dst|$dst, $src}",
(VCVTTPD2DQYrr VR128:$dst, VR256:$src), 0>;
+def : InstAlias<"vcvttpd2dqy\t{$src, $dst|$dst, $src}",
+ (VCVTTPD2DQYrm VR128:$dst, f256mem:$src), 0>;
let Predicates = [HasAVX, NoVLX] in {
- def : Pat<(v4i32 (fp_to_sint (v4f64 VR256:$src))),
- (VCVTTPD2DQYrr VR256:$src)>;
- def : Pat<(v4i32 (fp_to_sint (loadv4f64 addr:$src))),
- (VCVTTPD2DQYrm addr:$src)>;
+ let AddedComplexity = 15 in {
+ def : Pat<(X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvtp2Int (v2f64 VR128:$src)))))),
+ (VCVTPD2DQrr VR128:$src)>;
+ def : Pat<(X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvttp2si (v2f64 VR128:$src)))))),
+ (VCVTTPD2DQrr VR128:$src)>;
+ }
} // Predicates = [HasAVX]
def CVTTPD2DQrr : PDI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvttpd2dq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvttpd2dq VR128:$src))],
+ [(set VR128:$dst,
+ (v4i32 (X86cvttp2si (v2f64 VR128:$src))))],
IIC_SSE_CVT_PD_RR>, Sched<[WriteCvtF2I]>;
def CVTTPD2DQrm : PDI<0xE6, MRMSrcMem, (outs VR128:$dst),(ins f128mem:$src),
"cvttpd2dq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvttpd2dq
- (memopv2f64 addr:$src)))],
- IIC_SSE_CVT_PD_RM>,
- Sched<[WriteCvtF2ILd]>;
+ [(set VR128:$dst,
+ (v4i32 (X86cvttp2si (memopv2f64 addr:$src))))],
+ IIC_SSE_CVT_PD_RM>, Sched<[WriteCvtF2ILd]>;
+
+let Predicates = [UseSSE2] in {
+ let AddedComplexity = 15 in {
+ def : Pat<(X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvtp2Int (v2f64 VR128:$src)))))),
+ (CVTPD2DQrr VR128:$src)>;
+ def : Pat<(X86vzmovl (v2i64 (bitconvert
+ (v4i32 (X86cvttp2si (v2f64 VR128:$src)))))),
+ (CVTTPD2DQrr VR128:$src)>;
+ }
+} // Predicates = [UseSSE2]
// Convert packed single to packed double
-let Predicates = [HasAVX] in {
+let Predicates = [HasAVX, NoVLX] in {
// SSE2 instructions without OpSize prefix
def VCVTPS2PDrr : I<0x5A, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"vcvtps2pd\t{$src, $dst|$dst, $src}",
- [], IIC_SSE_CVT_PD_RR>, PS, VEX, Sched<[WriteCvtF2F]>;
+ [(set VR128:$dst, (v2f64 (X86vfpext (v4f32 VR128:$src))))],
+ IIC_SSE_CVT_PD_RR>, PS, VEX, Sched<[WriteCvtF2F]>;
def VCVTPS2PDrm : I<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f64mem:$src),
"vcvtps2pd\t{$src, $dst|$dst, $src}",
[(set VR128:$dst, (v2f64 (extloadv2f32 addr:$src)))],
IIC_SSE_CVT_PD_RM>, PS, VEX, Sched<[WriteCvtF2FLd]>;
def VCVTPS2PDYrr : I<0x5A, MRMSrcReg, (outs VR256:$dst), (ins VR128:$src),
"vcvtps2pd\t{$src, $dst|$dst, $src}",
- [], IIC_SSE_CVT_PD_RR>, PS, VEX, VEX_L, Sched<[WriteCvtF2F]>;
+ [(set VR256:$dst, (v4f64 (fpextend (v4f32 VR128:$src))))],
+ IIC_SSE_CVT_PD_RR>, PS, VEX, VEX_L, Sched<[WriteCvtF2F]>;
def VCVTPS2PDYrm : I<0x5A, MRMSrcMem, (outs VR256:$dst), (ins f128mem:$src),
"vcvtps2pd\t{$src, $dst|$dst, $src}",
- [], IIC_SSE_CVT_PD_RM>, PS, VEX, VEX_L, Sched<[WriteCvtF2FLd]>;
+ [(set VR256:$dst, (v4f64 (extloadv4f32 addr:$src)))],
+ IIC_SSE_CVT_PD_RM>, PS, VEX, VEX_L, Sched<[WriteCvtF2FLd]>;
}
let Predicates = [UseSSE2] in {
def CVTPS2PDrr : I<0x5A, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvtps2pd\t{$src, $dst|$dst, $src}",
- [], IIC_SSE_CVT_PD_RR>, PS, Sched<[WriteCvtF2F]>;
+ [(set VR128:$dst, (v2f64 (X86vfpext (v4f32 VR128:$src))))],
+ IIC_SSE_CVT_PD_RR>, PS, Sched<[WriteCvtF2F]>;
def CVTPS2PDrm : I<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f64mem:$src),
"cvtps2pd\t{$src, $dst|$dst, $src}",
[(set VR128:$dst, (v2f64 (extloadv2f32 addr:$src)))],
@@ -2165,136 +2220,118 @@ def CVTPS2PDrm : I<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f64mem:$src),
}
// Convert Packed DW Integers to Packed Double FP
-let Predicates = [HasAVX] in {
+let Predicates = [HasAVX, NoVLX] in {
let hasSideEffects = 0, mayLoad = 1 in
def VCVTDQ2PDrm : S2SI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins i64mem:$src),
"vcvtdq2pd\t{$src, $dst|$dst, $src}",
- []>, VEX, Sched<[WriteCvtI2FLd]>;
+ [(set VR128:$dst,
+ (v2f64 (X86VSintToFP (bc_v4i32 (loadv2i64 addr:$src)))))]>,
+ VEX, Sched<[WriteCvtI2FLd]>;
def VCVTDQ2PDrr : S2SI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"vcvtdq2pd\t{$src, $dst|$dst, $src}",
- []>, VEX, Sched<[WriteCvtI2F]>;
+ [(set VR128:$dst,
+ (v2f64 (X86VSintToFP (v4i32 VR128:$src))))]>,
+ VEX, Sched<[WriteCvtI2F]>;
def VCVTDQ2PDYrm : S2SI<0xE6, MRMSrcMem, (outs VR256:$dst), (ins i128mem:$src),
"vcvtdq2pd\t{$src, $dst|$dst, $src}",
- []>, VEX, VEX_L, Sched<[WriteCvtI2FLd]>;
+ [(set VR256:$dst,
+ (v4f64 (sint_to_fp (bc_v4i32 (loadv2i64 addr:$src)))))]>,
+ VEX, VEX_L, Sched<[WriteCvtI2FLd]>;
def VCVTDQ2PDYrr : S2SI<0xE6, MRMSrcReg, (outs VR256:$dst), (ins VR128:$src),
"vcvtdq2pd\t{$src, $dst|$dst, $src}",
- []>, VEX, VEX_L, Sched<[WriteCvtI2F]>;
+ [(set VR256:$dst,
+ (v4f64 (sint_to_fp (v4i32 VR128:$src))))]>,
+ VEX, VEX_L, Sched<[WriteCvtI2F]>;
}
let hasSideEffects = 0, mayLoad = 1 in
def CVTDQ2PDrm : S2SI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins i64mem:$src),
- "cvtdq2pd\t{$src, $dst|$dst, $src}", [],
+ "cvtdq2pd\t{$src, $dst|$dst, $src}",
+ [(set VR128:$dst,
+ (v2f64 (X86VSintToFP (bc_v4i32 (loadv2i64 addr:$src)))))],
IIC_SSE_CVT_PD_RR>, Sched<[WriteCvtI2FLd]>;
def CVTDQ2PDrr : S2SI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
- "cvtdq2pd\t{$src, $dst|$dst, $src}", [],
+ "cvtdq2pd\t{$src, $dst|$dst, $src}",
+ [(set VR128:$dst,
+ (v2f64 (X86VSintToFP (v4i32 VR128:$src))))],
IIC_SSE_CVT_PD_RM>, Sched<[WriteCvtI2F]>;
// AVX register conversion intrinsics
-let Predicates = [HasAVX] in {
- def : Pat<(v2f64 (X86cvtdq2pd (v4i32 VR128:$src))),
- (VCVTDQ2PDrr VR128:$src)>;
- def : Pat<(v2f64 (X86cvtdq2pd (bc_v4i32 (loadv2i64 addr:$src)))),
- (VCVTDQ2PDrm addr:$src)>;
- def : Pat<(v2f64 (X86cvtdq2pd (bc_v4i32 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+let Predicates = [HasAVX, NoVLX] in {
+ def : Pat<(v2f64 (X86VSintToFP (bc_v4i32 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
(VCVTDQ2PDrm addr:$src)>;
-
- def : Pat<(v4f64 (sint_to_fp (v4i32 VR128:$src))),
- (VCVTDQ2PDYrr VR128:$src)>;
- def : Pat<(v4f64 (sint_to_fp (bc_v4i32 (loadv2i64 addr:$src)))),
- (VCVTDQ2PDYrm addr:$src)>;
-} // Predicates = [HasAVX]
+} // Predicates = [HasAVX, NoVLX]
// SSE2 register conversion intrinsics
-let Predicates = [HasSSE2] in {
- def : Pat<(v2f64 (X86cvtdq2pd (v4i32 VR128:$src))),
- (CVTDQ2PDrr VR128:$src)>;
- def : Pat<(v2f64 (X86cvtdq2pd (bc_v4i32 (loadv2i64 addr:$src)))),
- (CVTDQ2PDrm addr:$src)>;
- def : Pat<(v2f64 (X86cvtdq2pd (bc_v4i32 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
+let Predicates = [UseSSE2] in {
+ def : Pat<(v2f64 (X86VSintToFP (bc_v4i32 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
(CVTDQ2PDrm addr:$src)>;
-} // Predicates = [HasSSE2]
+} // Predicates = [UseSSE2]
// Convert packed double to packed single
// The assembler can recognize rr 256-bit instructions by seeing a ymm
// register, but the same isn't true when using memory operands instead.
// Provide other assembly rr and rm forms to address this explicitly.
+let Predicates = [HasAVX, NoVLX] in
def VCVTPD2PSrr : VPDI<0x5A, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvtpd2ps\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvtpd2ps VR128:$src))],
+ [(set VR128:$dst, (X86vfpround (v2f64 VR128:$src)))],
IIC_SSE_CVT_PD_RR>, VEX, Sched<[WriteCvtF2F]>;
// XMM only
def : InstAlias<"vcvtpd2psx\t{$src, $dst|$dst, $src}",
(VCVTPD2PSrr VR128:$dst, VR128:$src), 0>;
-def VCVTPD2PSXrm : VPDI<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
- "cvtpd2psx\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (int_x86_sse2_cvtpd2ps (loadv2f64 addr:$src)))],
- IIC_SSE_CVT_PD_RM>, VEX, Sched<[WriteCvtF2FLd]>;
+let Predicates = [HasAVX, NoVLX] in
+def VCVTPD2PSrm : VPDI<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
+ "cvtpd2ps{x}\t{$src, $dst|$dst, $src}",
+ [(set VR128:$dst, (X86vfpround (loadv2f64 addr:$src)))],
+ IIC_SSE_CVT_PD_RM>, VEX, Sched<[WriteCvtF2FLd]>;
+def : InstAlias<"vcvtpd2psx\t{$src, $dst|$dst, $src}",
+ (VCVTPD2PSrm VR128:$dst, f128mem:$src), 0>;
// YMM only
+let Predicates = [HasAVX, NoVLX] in {
def VCVTPD2PSYrr : VPDI<0x5A, MRMSrcReg, (outs VR128:$dst), (ins VR256:$src),
- "cvtpd2ps{y}\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (int_x86_avx_cvt_pd2_ps_256 VR256:$src))],
+ "cvtpd2ps\t{$src, $dst|$dst, $src}",
+ [(set VR128:$dst, (fpround VR256:$src))],
IIC_SSE_CVT_PD_RR>, VEX, VEX_L, Sched<[WriteCvtF2F]>;
def VCVTPD2PSYrm : VPDI<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f256mem:$src),
"cvtpd2ps{y}\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (int_x86_avx_cvt_pd2_ps_256 (loadv4f64 addr:$src)))],
+ [(set VR128:$dst, (fpround (loadv4f64 addr:$src)))],
IIC_SSE_CVT_PD_RM>, VEX, VEX_L, Sched<[WriteCvtF2FLd]>;
-def : InstAlias<"vcvtpd2ps\t{$src, $dst|$dst, $src}",
+}
+def : InstAlias<"vcvtpd2psy\t{$src, $dst|$dst, $src}",
(VCVTPD2PSYrr VR128:$dst, VR256:$src), 0>;
+def : InstAlias<"vcvtpd2psy\t{$src, $dst|$dst, $src}",
+ (VCVTPD2PSYrm VR128:$dst, f256mem:$src), 0>;
def CVTPD2PSrr : PDI<0x5A, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"cvtpd2ps\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (int_x86_sse2_cvtpd2ps VR128:$src))],
+ [(set VR128:$dst, (X86vfpround (v2f64 VR128:$src)))],
IIC_SSE_CVT_PD_RR>, Sched<[WriteCvtF2F]>;
def CVTPD2PSrm : PDI<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src),
"cvtpd2ps\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (int_x86_sse2_cvtpd2ps (memopv2f64 addr:$src)))],
+ [(set VR128:$dst, (X86vfpround (memopv2f64 addr:$src)))],
IIC_SSE_CVT_PD_RM>, Sched<[WriteCvtF2FLd]>;
-
// AVX 256-bit register conversion intrinsics
// FIXME: Migrate SSE conversion intrinsics matching to use patterns as below
// whenever possible to avoid declaring two versions of each one.
-let Predicates = [HasAVX] in {
- def : Pat<(int_x86_avx_cvtdq2_ps_256 VR256:$src),
- (VCVTDQ2PSYrr VR256:$src)>;
- def : Pat<(int_x86_avx_cvtdq2_ps_256 (bitconvert (loadv4i64 addr:$src))),
- (VCVTDQ2PSYrm addr:$src)>;
-}
let Predicates = [HasAVX, NoVLX] in {
- // Match fround and fextend for 128/256-bit conversions
- def : Pat<(v4f32 (X86vfpround (v2f64 VR128:$src))),
+ // Match fpround and fpextend for 128/256-bit conversions
+ let AddedComplexity = 15 in
+ def : Pat<(X86vzmovl (v2f64 (bitconvert
+ (v4f32 (X86vfpround (v2f64 VR128:$src)))))),
(VCVTPD2PSrr VR128:$src)>;
- def : Pat<(v4f32 (X86vfpround (loadv2f64 addr:$src))),
- (VCVTPD2PSXrm addr:$src)>;
- def : Pat<(v4f32 (fround (v4f64 VR256:$src))),
- (VCVTPD2PSYrr VR256:$src)>;
- def : Pat<(v4f32 (fround (loadv4f64 addr:$src))),
- (VCVTPD2PSYrm addr:$src)>;
-
- def : Pat<(v2f64 (X86vfpext (v4f32 VR128:$src))),
- (VCVTPS2PDrr VR128:$src)>;
- def : Pat<(v4f64 (fextend (v4f32 VR128:$src))),
- (VCVTPS2PDYrr VR128:$src)>;
- def : Pat<(v4f64 (extloadv4f32 addr:$src)),
- (VCVTPS2PDYrm addr:$src)>;
}
let Predicates = [UseSSE2] in {
- // Match fround and fextend for 128 conversions
- def : Pat<(v4f32 (X86vfpround (v2f64 VR128:$src))),
+ // Match fpround and fpextend for 128 conversions
+ let AddedComplexity = 15 in
+ def : Pat<(X86vzmovl (v2f64 (bitconvert
+ (v4f32 (X86vfpround (v2f64 VR128:$src)))))),
(CVTPD2PSrr VR128:$src)>;
- def : Pat<(v4f32 (X86vfpround (memopv2f64 addr:$src))),
- (CVTPD2PSrm addr:$src)>;
-
- def : Pat<(v2f64 (X86vfpext (v4f32 VR128:$src))),
- (CVTPS2PDrr VR128:$src)>;
}
//===----------------------------------------------------------------------===//
@@ -2306,6 +2343,7 @@ multiclass sse12_cmp_scalar<RegisterClass RC, X86MemOperand x86memop,
Operand CC, SDNode OpNode, ValueType VT,
PatFrag ld_frag, string asm, string asm_alt,
OpndItins itins, ImmLeaf immLeaf> {
+ let isCommutable = 1 in
def rr : SIi8<0xC2, MRMSrcReg,
(outs RC:$dst), (ins RC:$src1, RC:$src2, CC:$cc), asm,
[(set RC:$dst, (OpNode (VT RC:$src1), RC:$src2, immLeaf:$cc))],
@@ -2351,9 +2389,9 @@ let Constraints = "$src1 = $dst" in {
SSE_ALU_F64S, i8immZExt3>, XD;
}
-multiclass sse12_cmp_scalar_int<X86MemOperand x86memop, Operand CC,
+multiclass sse12_cmp_scalar_int<Operand memop, Operand CC,
Intrinsic Int, string asm, OpndItins itins,
- ImmLeaf immLeaf> {
+ ImmLeaf immLeaf, ComplexPattern mem_cpat> {
def rr : SIi8<0xC2, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src, CC:$cc), asm,
[(set VR128:$dst, (Int VR128:$src1,
@@ -2361,30 +2399,30 @@ multiclass sse12_cmp_scalar_int<X86MemOperand x86memop, Operand CC,
itins.rr>,
Sched<[itins.Sched]>;
def rm : SIi8<0xC2, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, x86memop:$src, CC:$cc), asm,
+ (ins VR128:$src1, memop:$src, CC:$cc), asm,
[(set VR128:$dst, (Int VR128:$src1,
- (load addr:$src), immLeaf:$cc))],
+ mem_cpat:$src, immLeaf:$cc))],
itins.rm>,
Sched<[itins.Sched.Folded, ReadAfterLd]>;
}
let isCodeGenOnly = 1 in {
// Aliases to match intrinsics which expect XMM operand(s).
- defm Int_VCMPSS : sse12_cmp_scalar_int<f32mem, AVXCC, int_x86_sse_cmp_ss,
+ defm Int_VCMPSS : sse12_cmp_scalar_int<ssmem, AVXCC, int_x86_sse_cmp_ss,
"cmp${cc}ss\t{$src, $src1, $dst|$dst, $src1, $src}",
- SSE_ALU_F32S, i8immZExt5>,
+ SSE_ALU_F32S, i8immZExt5, sse_load_f32>,
XS, VEX_4V;
- defm Int_VCMPSD : sse12_cmp_scalar_int<f64mem, AVXCC, int_x86_sse2_cmp_sd,
+ defm Int_VCMPSD : sse12_cmp_scalar_int<sdmem, AVXCC, int_x86_sse2_cmp_sd,
"cmp${cc}sd\t{$src, $src1, $dst|$dst, $src1, $src}",
- SSE_ALU_F32S, i8immZExt5>, // same latency as f32
+ SSE_ALU_F32S, i8immZExt5, sse_load_f64>, // same latency as f32
XD, VEX_4V;
let Constraints = "$src1 = $dst" in {
- defm Int_CMPSS : sse12_cmp_scalar_int<f32mem, SSECC, int_x86_sse_cmp_ss,
+ defm Int_CMPSS : sse12_cmp_scalar_int<ssmem, SSECC, int_x86_sse_cmp_ss,
"cmp${cc}ss\t{$src, $dst|$dst, $src}",
- SSE_ALU_F32S, i8immZExt3>, XS;
- defm Int_CMPSD : sse12_cmp_scalar_int<f64mem, SSECC, int_x86_sse2_cmp_sd,
+ SSE_ALU_F32S, i8immZExt3, sse_load_f32>, XS;
+ defm Int_CMPSD : sse12_cmp_scalar_int<sdmem, SSECC, int_x86_sse2_cmp_sd,
"cmp${cc}sd\t{$src, $dst|$dst, $src}",
- SSE_ALU_F64S, i8immZExt3>,
+ SSE_ALU_F64S, i8immZExt3, sse_load_f64>,
XD;
}
}
@@ -2407,6 +2445,23 @@ multiclass sse12_ord_cmp<bits<8> opc, RegisterClass RC, SDNode OpNode,
Sched<[WriteFAddLd, ReadAfterLd]>;
}
+// sse12_ord_cmp_int - Intrinsic version of sse12_ord_cmp
+multiclass sse12_ord_cmp_int<bits<8> opc, RegisterClass RC, SDNode OpNode,
+ ValueType vt, Operand memop,
+ ComplexPattern mem_cpat, string OpcodeStr> {
+ def rr: SI<opc, MRMSrcReg, (outs), (ins RC:$src1, RC:$src2),
+ !strconcat(OpcodeStr, "\t{$src2, $src1|$src1, $src2}"),
+ [(set EFLAGS, (OpNode (vt RC:$src1), RC:$src2))],
+ IIC_SSE_COMIS_RR>,
+ Sched<[WriteFAdd]>;
+ def rm: SI<opc, MRMSrcMem, (outs), (ins RC:$src1, memop:$src2),
+ !strconcat(OpcodeStr, "\t{$src2, $src1|$src1, $src2}"),
+ [(set EFLAGS, (OpNode (vt RC:$src1),
+ mem_cpat:$src2))],
+ IIC_SSE_COMIS_RM>,
+ Sched<[WriteFAddLd, ReadAfterLd]>;
+}
+
let Defs = [EFLAGS] in {
defm VUCOMISS : sse12_ord_cmp<0x2E, FR32, X86cmp, f32, f32mem, loadf32,
"ucomiss">, PS, VEX, VEX_LIG;
@@ -2420,15 +2475,15 @@ let Defs = [EFLAGS] in {
}
let isCodeGenOnly = 1 in {
- defm Int_VUCOMISS : sse12_ord_cmp<0x2E, VR128, X86ucomi, v4f32, f128mem,
- load, "ucomiss">, PS, VEX;
- defm Int_VUCOMISD : sse12_ord_cmp<0x2E, VR128, X86ucomi, v2f64, f128mem,
- load, "ucomisd">, PD, VEX;
-
- defm Int_VCOMISS : sse12_ord_cmp<0x2F, VR128, X86comi, v4f32, f128mem,
- load, "comiss">, PS, VEX;
- defm Int_VCOMISD : sse12_ord_cmp<0x2F, VR128, X86comi, v2f64, f128mem,
- load, "comisd">, PD, VEX;
+ defm Int_VUCOMISS : sse12_ord_cmp_int<0x2E, VR128, X86ucomi, v4f32, ssmem,
+ sse_load_f32, "ucomiss">, PS, VEX;
+ defm Int_VUCOMISD : sse12_ord_cmp_int<0x2E, VR128, X86ucomi, v2f64, sdmem,
+ sse_load_f64, "ucomisd">, PD, VEX;
+
+ defm Int_VCOMISS : sse12_ord_cmp_int<0x2F, VR128, X86comi, v4f32, ssmem,
+ sse_load_f32, "comiss">, PS, VEX;
+ defm Int_VCOMISD : sse12_ord_cmp_int<0x2F, VR128, X86comi, v2f64, sdmem,
+ sse_load_f64, "comisd">, PD, VEX;
}
defm UCOMISS : sse12_ord_cmp<0x2E, FR32, X86cmp, f32, f32mem, loadf32,
"ucomiss">, PS;
@@ -2443,15 +2498,15 @@ let Defs = [EFLAGS] in {
}
let isCodeGenOnly = 1 in {
- defm Int_UCOMISS : sse12_ord_cmp<0x2E, VR128, X86ucomi, v4f32, f128mem,
- load, "ucomiss">, PS;
- defm Int_UCOMISD : sse12_ord_cmp<0x2E, VR128, X86ucomi, v2f64, f128mem,
- load, "ucomisd">, PD;
-
- defm Int_COMISS : sse12_ord_cmp<0x2F, VR128, X86comi, v4f32, f128mem, load,
- "comiss">, PS;
- defm Int_COMISD : sse12_ord_cmp<0x2F, VR128, X86comi, v2f64, f128mem, load,
- "comisd">, PD;
+ defm Int_UCOMISS : sse12_ord_cmp_int<0x2E, VR128, X86ucomi, v4f32, ssmem,
+ sse_load_f32, "ucomiss">, PS;
+ defm Int_UCOMISD : sse12_ord_cmp_int<0x2E, VR128, X86ucomi, v2f64, sdmem,
+ sse_load_f64, "ucomisd">, PD;
+
+ defm Int_COMISS : sse12_ord_cmp_int<0x2F, VR128, X86comi, v4f32, ssmem,
+ sse_load_f32, "comiss">, PS;
+ defm Int_COMISD : sse12_ord_cmp_int<0x2F, VR128, X86comi, v2f64, sdmem,
+ sse_load_f64, "comisd">, PD;
}
} // Defs = [EFLAGS]
@@ -2641,7 +2696,8 @@ let Predicates = [UseSSE2] in {
multiclass sse12_unpack_interleave<bits<8> opc, SDNode OpNode, ValueType vt,
PatFrag mem_frag, RegisterClass RC,
X86MemOperand x86memop, string asm,
- Domain d> {
+ Domain d, bit IsCommutable = 0> {
+ let isCommutable = IsCommutable in
def rr : PI<opc, MRMSrcReg,
(outs RC:$dst), (ins RC:$src1, RC:$src2),
asm, [(set RC:$dst,
@@ -2689,7 +2745,7 @@ let Constraints = "$src1 = $dst" in {
SSEPackedSingle>, PS;
defm UNPCKHPD: sse12_unpack_interleave<0x15, X86Unpckh, v2f64, memopv2f64,
VR128, f128mem, "unpckhpd\t{$src2, $dst|$dst, $src2}",
- SSEPackedDouble>, PD;
+ SSEPackedDouble, 1>, PD;
defm UNPCKLPS: sse12_unpack_interleave<0x14, X86Unpckl, v4f32, memopv4f32,
VR128, f128mem, "unpcklps\t{$src2, $dst|$dst, $src2}",
SSEPackedSingle>, PS;
@@ -2810,84 +2866,6 @@ defm PANDN : PDI_binop_all<0xDF, "pandn", X86andnp, v2i64, v4i64,
// SSE 1 & 2 - Logical Instructions
//===----------------------------------------------------------------------===//
-// Multiclass for scalars using the X86 logical operation aliases for FP.
-multiclass sse12_fp_packed_scalar_logical_alias<
- bits<8> opc, string OpcodeStr, SDNode OpNode, OpndItins itins> {
- defm V#NAME#PS : sse12_fp_packed<opc, !strconcat(OpcodeStr, "ps"), OpNode,
- FR32, f32, f128mem, loadf32_128, SSEPackedSingle, itins, 0>,
- PS, VEX_4V;
-
- defm V#NAME#PD : sse12_fp_packed<opc, !strconcat(OpcodeStr, "pd"), OpNode,
- FR64, f64, f128mem, loadf64_128, SSEPackedDouble, itins, 0>,
- PD, VEX_4V;
-
- let Constraints = "$src1 = $dst" in {
- defm PS : sse12_fp_packed<opc, !strconcat(OpcodeStr, "ps"), OpNode, FR32,
- f32, f128mem, memopfsf32_128, SSEPackedSingle, itins>, PS;
-
- defm PD : sse12_fp_packed<opc, !strconcat(OpcodeStr, "pd"), OpNode, FR64,
- f64, f128mem, memopfsf64_128, SSEPackedDouble, itins>, PD;
- }
-}
-
-let isCodeGenOnly = 1 in {
- defm FsAND : sse12_fp_packed_scalar_logical_alias<0x54, "and", X86fand,
- SSE_BIT_ITINS_P>;
- defm FsOR : sse12_fp_packed_scalar_logical_alias<0x56, "or", X86for,
- SSE_BIT_ITINS_P>;
- defm FsXOR : sse12_fp_packed_scalar_logical_alias<0x57, "xor", X86fxor,
- SSE_BIT_ITINS_P>;
-
- let isCommutable = 0 in
- defm FsANDN : sse12_fp_packed_scalar_logical_alias<0x55, "andn", X86fandn,
- SSE_BIT_ITINS_P>;
-}
-
-// Multiclass for vectors using the X86 logical operation aliases for FP.
-multiclass sse12_fp_packed_vector_logical_alias<
- bits<8> opc, string OpcodeStr, SDNode OpNode, OpndItins itins> {
- let Predicates = [HasAVX, NoVLX_Or_NoDQI] in {
- defm V#NAME#PS : sse12_fp_packed<opc, !strconcat(OpcodeStr, "ps"), OpNode,
- VR128, v4f32, f128mem, loadv4f32, SSEPackedSingle, itins, 0>,
- PS, VEX_4V;
-
- defm V#NAME#PD : sse12_fp_packed<opc, !strconcat(OpcodeStr, "pd"), OpNode,
- VR128, v2f64, f128mem, loadv2f64, SSEPackedDouble, itins, 0>,
- PD, VEX_4V;
-
- defm V#NAME#PSY : sse12_fp_packed<opc, !strconcat(OpcodeStr, "ps"), OpNode,
- VR256, v8f32, f256mem, loadv8f32, SSEPackedSingle, itins, 0>,
- PS, VEX_4V, VEX_L;
-
- defm V#NAME#PDY : sse12_fp_packed<opc, !strconcat(OpcodeStr, "pd"), OpNode,
- VR256, v4f64, f256mem, loadv4f64, SSEPackedDouble, itins, 0>,
- PD, VEX_4V, VEX_L;
- }
-
- let Constraints = "$src1 = $dst" in {
- defm PS : sse12_fp_packed<opc, !strconcat(OpcodeStr, "ps"), OpNode, VR128,
- v4f32, f128mem, memopv4f32, SSEPackedSingle, itins>,
- PS;
-
- defm PD : sse12_fp_packed<opc, !strconcat(OpcodeStr, "pd"), OpNode, VR128,
- v2f64, f128mem, memopv2f64, SSEPackedDouble, itins>,
- PD;
- }
-}
-
-let isCodeGenOnly = 1 in {
- defm FvAND : sse12_fp_packed_vector_logical_alias<0x54, "and", X86fand,
- SSE_BIT_ITINS_P>;
- defm FvOR : sse12_fp_packed_vector_logical_alias<0x56, "or", X86for,
- SSE_BIT_ITINS_P>;
- defm FvXOR : sse12_fp_packed_vector_logical_alias<0x57, "xor", X86fxor,
- SSE_BIT_ITINS_P>;
-
- let isCommutable = 0 in
- defm FvANDN : sse12_fp_packed_vector_logical_alias<0x55, "andn", X86fandn,
- SSE_BIT_ITINS_P>;
-}
-
/// sse12_fp_packed_logical - SSE 1 & 2 packed FP logical ops
///
multiclass sse12_fp_packed_logical<bits<8> opc, string OpcodeStr,
@@ -2895,7 +2873,8 @@ multiclass sse12_fp_packed_logical<bits<8> opc, string OpcodeStr,
let Predicates = [HasAVX, NoVLX] in {
defm V#NAME#PSY : sse12_fp_packed_logical_rm<opc, VR256, SSEPackedSingle,
!strconcat(OpcodeStr, "ps"), f256mem,
- [(set VR256:$dst, (v4i64 (OpNode VR256:$src1, VR256:$src2)))],
+ [(set VR256:$dst, (OpNode (bc_v4i64 (v8f32 VR256:$src1)),
+ (bc_v4i64 (v8f32 VR256:$src2))))],
[(set VR256:$dst, (OpNode (bc_v4i64 (v8f32 VR256:$src1)),
(loadv4i64 addr:$src2)))], 0>, PS, VEX_4V, VEX_L;
@@ -2907,12 +2886,10 @@ multiclass sse12_fp_packed_logical<bits<8> opc, string OpcodeStr,
(loadv4i64 addr:$src2)))], 0>,
PD, VEX_4V, VEX_L;
- // In AVX no need to add a pattern for 128-bit logical rr ps, because they
- // are all promoted to v2i64, and the patterns are covered by the int
- // version. This is needed in SSE only, because v2i64 isn't supported on
- // SSE1, but only on SSE2.
defm V#NAME#PS : sse12_fp_packed_logical_rm<opc, VR128, SSEPackedSingle,
- !strconcat(OpcodeStr, "ps"), f128mem, [],
+ !strconcat(OpcodeStr, "ps"), f128mem,
+ [(set VR128:$dst, (OpNode (bc_v2i64 (v4f32 VR128:$src1)),
+ (bc_v2i64 (v4f32 VR128:$src2))))],
[(set VR128:$dst, (OpNode (bc_v2i64 (v4f32 VR128:$src1)),
(loadv2i64 addr:$src2)))], 0>, PS, VEX_4V;
@@ -2928,7 +2905,8 @@ multiclass sse12_fp_packed_logical<bits<8> opc, string OpcodeStr,
let Constraints = "$src1 = $dst" in {
defm PS : sse12_fp_packed_logical_rm<opc, VR128, SSEPackedSingle,
!strconcat(OpcodeStr, "ps"), f128mem,
- [(set VR128:$dst, (v2i64 (OpNode VR128:$src1, VR128:$src2)))],
+ [(set VR128:$dst, (OpNode (bc_v2i64 (v4f32 VR128:$src1)),
+ (bc_v2i64 (v4f32 VR128:$src2))))],
[(set VR128:$dst, (OpNode (bc_v2i64 (v4f32 VR128:$src1)),
(memopv2i64 addr:$src2)))]>, PS;
@@ -2947,19 +2925,124 @@ defm XOR : sse12_fp_packed_logical<0x57, "xor", xor>;
let isCommutable = 0 in
defm ANDN : sse12_fp_packed_logical<0x55, "andn", X86andnp>;
-// AVX1 requires type coercions in order to fold loads directly into logical
-// operations.
+// If only AVX1 is supported, we need to handle integer operations with
+// floating point instructions since the integer versions aren't available.
let Predicates = [HasAVX1Only] in {
- def : Pat<(bc_v8f32 (and VR256:$src1, (loadv4i64 addr:$src2))),
+ def : Pat<(v4i64 (and VR256:$src1, VR256:$src2)),
+ (VANDPSYrr VR256:$src1, VR256:$src2)>;
+ def : Pat<(v4i64 (or VR256:$src1, VR256:$src2)),
+ (VORPSYrr VR256:$src1, VR256:$src2)>;
+ def : Pat<(v4i64 (xor VR256:$src1, VR256:$src2)),
+ (VXORPSYrr VR256:$src1, VR256:$src2)>;
+ def : Pat<(v4i64 (X86andnp VR256:$src1, VR256:$src2)),
+ (VANDNPSYrr VR256:$src1, VR256:$src2)>;
+
+ def : Pat<(and VR256:$src1, (loadv4i64 addr:$src2)),
(VANDPSYrm VR256:$src1, addr:$src2)>;
- def : Pat<(bc_v8f32 (or VR256:$src1, (loadv4i64 addr:$src2))),
+ def : Pat<(or VR256:$src1, (loadv4i64 addr:$src2)),
(VORPSYrm VR256:$src1, addr:$src2)>;
- def : Pat<(bc_v8f32 (xor VR256:$src1, (loadv4i64 addr:$src2))),
+ def : Pat<(xor VR256:$src1, (loadv4i64 addr:$src2)),
(VXORPSYrm VR256:$src1, addr:$src2)>;
- def : Pat<(bc_v8f32 (X86andnp VR256:$src1, (loadv4i64 addr:$src2))),
+ def : Pat<(X86andnp VR256:$src1, (loadv4i64 addr:$src2)),
(VANDNPSYrm VR256:$src1, addr:$src2)>;
}
+let Predicates = [HasAVX, NoVLX_Or_NoDQI] in {
+ // Use packed logical operations for scalar ops.
+ def : Pat<(f64 (X86fand FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (VANDPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+ def : Pat<(f64 (X86for FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (VORPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+ def : Pat<(f64 (X86fxor FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (VXORPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+ def : Pat<(f64 (X86fandn FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (VANDNPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+
+ def : Pat<(f32 (X86fand FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (VANDPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+ def : Pat<(f32 (X86for FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (VORPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+ def : Pat<(f32 (X86fxor FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (VXORPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+ def : Pat<(f32 (X86fandn FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (VANDNPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+}
+
+let Predicates = [UseSSE1] in {
+ // Use packed logical operations for scalar ops.
+ def : Pat<(f32 (X86fand FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (ANDPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+ def : Pat<(f32 (X86for FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (ORPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+ def : Pat<(f32 (X86fxor FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (XORPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+ def : Pat<(f32 (X86fandn FR32:$src1, FR32:$src2)),
+ (COPY_TO_REGCLASS (ANDNPSrr
+ (COPY_TO_REGCLASS FR32:$src1, VR128),
+ (COPY_TO_REGCLASS FR32:$src2, VR128)), FR32)>;
+}
+
+let Predicates = [UseSSE2] in {
+ // Use packed logical operations for scalar ops.
+ def : Pat<(f64 (X86fand FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (ANDPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+ def : Pat<(f64 (X86for FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (ORPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+ def : Pat<(f64 (X86fxor FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (XORPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+ def : Pat<(f64 (X86fandn FR64:$src1, FR64:$src2)),
+ (COPY_TO_REGCLASS (ANDNPDrr
+ (COPY_TO_REGCLASS FR64:$src1, VR128),
+ (COPY_TO_REGCLASS FR64:$src2, VR128)), FR64)>;
+}
+
+// Patterns for packed operations when we don't have integer type available.
+def : Pat<(v4f32 (X86fand VR128:$src1, VR128:$src2)),
+ (ANDPSrr VR128:$src1, VR128:$src2)>;
+def : Pat<(v4f32 (X86for VR128:$src1, VR128:$src2)),
+ (ORPSrr VR128:$src1, VR128:$src2)>;
+def : Pat<(v4f32 (X86fxor VR128:$src1, VR128:$src2)),
+ (XORPSrr VR128:$src1, VR128:$src2)>;
+def : Pat<(v4f32 (X86fandn VR128:$src1, VR128:$src2)),
+ (ANDNPSrr VR128:$src1, VR128:$src2)>;
+
+def : Pat<(X86fand VR128:$src1, (memopv4f32 addr:$src2)),
+ (ANDPSrm VR128:$src1, addr:$src2)>;
+def : Pat<(X86for VR128:$src1, (memopv4f32 addr:$src2)),
+ (ORPSrm VR128:$src1, addr:$src2)>;
+def : Pat<(X86fxor VR128:$src1, (memopv4f32 addr:$src2)),
+ (XORPSrm VR128:$src1, addr:$src2)>;
+def : Pat<(X86fandn VR128:$src1, (memopv4f32 addr:$src2)),
+ (ANDNPSrm VR128:$src1, addr:$src2)>;
+
//===----------------------------------------------------------------------===//
// SSE 1 & 2 - Arithmetic Instructions
//===----------------------------------------------------------------------===//
@@ -3025,20 +3108,22 @@ multiclass basic_sse12_fp_binop_s<bits<8> opc, string OpcodeStr, SDNode OpNode,
}
multiclass basic_sse12_fp_binop_s_int<bits<8> opc, string OpcodeStr,
+ SDPatternOperator IntSS,
+ SDPatternOperator IntSD,
SizeItins itins> {
- defm V#NAME#SS : sse12_fp_scalar_int<opc, OpcodeStr, VR128,
- !strconcat(OpcodeStr, "ss"), "", "_ss", ssmem, sse_load_f32,
+ defm V#NAME#SS : sse12_fp_scalar_int<opc, OpcodeStr, IntSS, VR128,
+ !strconcat(OpcodeStr, "ss"), ssmem, sse_load_f32,
SSEPackedSingle, itins.s, 0>, XS, VEX_4V, VEX_LIG;
- defm V#NAME#SD : sse12_fp_scalar_int<opc, OpcodeStr, VR128,
- !strconcat(OpcodeStr, "sd"), "2", "_sd", sdmem, sse_load_f64,
+ defm V#NAME#SD : sse12_fp_scalar_int<opc, OpcodeStr, IntSD, VR128,
+ !strconcat(OpcodeStr, "sd"), sdmem, sse_load_f64,
SSEPackedDouble, itins.d, 0>, XD, VEX_4V, VEX_LIG;
let Constraints = "$src1 = $dst" in {
- defm SS : sse12_fp_scalar_int<opc, OpcodeStr, VR128,
- !strconcat(OpcodeStr, "ss"), "", "_ss", ssmem, sse_load_f32,
+ defm SS : sse12_fp_scalar_int<opc, OpcodeStr, IntSS, VR128,
+ !strconcat(OpcodeStr, "ss"), ssmem, sse_load_f32,
SSEPackedSingle, itins.s>, XS;
- defm SD : sse12_fp_scalar_int<opc, OpcodeStr, VR128,
- !strconcat(OpcodeStr, "sd"), "2", "_sd", sdmem, sse_load_f64,
+ defm SD : sse12_fp_scalar_int<opc, OpcodeStr, IntSD, VR128,
+ !strconcat(OpcodeStr, "sd"), sdmem, sse_load_f64,
SSEPackedDouble, itins.d>, XD;
}
}
@@ -3046,23 +3131,29 @@ multiclass basic_sse12_fp_binop_s_int<bits<8> opc, string OpcodeStr,
// Binary Arithmetic instructions
defm ADD : basic_sse12_fp_binop_p<0x58, "add", fadd, SSE_ALU_ITINS_P>,
basic_sse12_fp_binop_s<0x58, "add", fadd, SSE_ALU_ITINS_S>,
- basic_sse12_fp_binop_s_int<0x58, "add", SSE_ALU_ITINS_S>;
+ basic_sse12_fp_binop_s_int<0x58, "add", null_frag, null_frag,
+ SSE_ALU_ITINS_S>;
defm MUL : basic_sse12_fp_binop_p<0x59, "mul", fmul, SSE_MUL_ITINS_P>,
basic_sse12_fp_binop_s<0x59, "mul", fmul, SSE_MUL_ITINS_S>,
- basic_sse12_fp_binop_s_int<0x59, "mul", SSE_MUL_ITINS_S>;
+ basic_sse12_fp_binop_s_int<0x59, "mul", null_frag, null_frag,
+ SSE_MUL_ITINS_S>;
let isCommutable = 0 in {
defm SUB : basic_sse12_fp_binop_p<0x5C, "sub", fsub, SSE_ALU_ITINS_P>,
basic_sse12_fp_binop_s<0x5C, "sub", fsub, SSE_ALU_ITINS_S>,
- basic_sse12_fp_binop_s_int<0x5C, "sub", SSE_ALU_ITINS_S>;
+ basic_sse12_fp_binop_s_int<0x5C, "sub", null_frag, null_frag,
+ SSE_ALU_ITINS_S>;
defm DIV : basic_sse12_fp_binop_p<0x5E, "div", fdiv, SSE_DIV_ITINS_P>,
basic_sse12_fp_binop_s<0x5E, "div", fdiv, SSE_DIV_ITINS_S>,
- basic_sse12_fp_binop_s_int<0x5E, "div", SSE_DIV_ITINS_S>;
+ basic_sse12_fp_binop_s_int<0x5E, "div", null_frag, null_frag,
+ SSE_DIV_ITINS_S>;
defm MAX : basic_sse12_fp_binop_p<0x5F, "max", X86fmax, SSE_ALU_ITINS_P>,
basic_sse12_fp_binop_s<0x5F, "max", X86fmax, SSE_ALU_ITINS_S>,
- basic_sse12_fp_binop_s_int<0x5F, "max", SSE_ALU_ITINS_S>;
+ basic_sse12_fp_binop_s_int<0x5F, "max", int_x86_sse_max_ss,
+ int_x86_sse2_max_sd, SSE_ALU_ITINS_S>;
defm MIN : basic_sse12_fp_binop_p<0x5D, "min", X86fmin, SSE_ALU_ITINS_P>,
basic_sse12_fp_binop_s<0x5D, "min", X86fmin, SSE_ALU_ITINS_S>,
- basic_sse12_fp_binop_s_int<0x5D, "min", SSE_ALU_ITINS_S>;
+ basic_sse12_fp_binop_s_int<0x5D, "min", int_x86_sse_min_ss,
+ int_x86_sse2_min_sd, SSE_ALU_ITINS_S>;
}
let isCodeGenOnly = 1 in {
@@ -3145,9 +3236,15 @@ multiclass scalar_math_f32_patterns<SDNode Op, string OpcPrefix> {
}
- // Repeat everything for AVX, except for the movss + scalar combo...
- // because that one shouldn't occur with AVX codegen?
- let Predicates = [HasAVX] in {
+ // Repeat everything for AVX.
+ let Predicates = [UseAVX] in {
+ // extracted scalar math op with insert via movss
+ def : Pat<(v4f32 (X86Movss (v4f32 VR128:$dst), (v4f32 (scalar_to_vector
+ (Op (f32 (extractelt (v4f32 VR128:$dst), (iPTR 0))),
+ FR32:$src))))),
+ (!cast<I>("V"#OpcPrefix#SSrr_Int) v4f32:$dst,
+ (COPY_TO_REGCLASS FR32:$src, VR128))>;
+
// extracted scalar math op with insert via blend
def : Pat<(v4f32 (X86Blendi (v4f32 VR128:$dst), (v4f32 (scalar_to_vector
(Op (f32 (extractelt (v4f32 VR128:$dst), (iPTR 0))),
@@ -3203,7 +3300,7 @@ multiclass scalar_math_f64_patterns<SDNode Op, string OpcPrefix> {
}
// Repeat everything for AVX.
- let Predicates = [HasAVX] in {
+ let Predicates = [UseAVX] in {
// extracted scalar math op with insert via movsd
def : Pat<(v2f64 (X86Movsd (v2f64 VR128:$dst), (v2f64 (scalar_to_vector
(Op (f64 (extractelt (v2f64 VR128:$dst), (iPTR 0))),
@@ -3287,8 +3384,8 @@ def SSE_RCPS : OpndItins<
/// the HW instructions are 2 operand / destructive.
multiclass sse_fp_unop_s<bits<8> opc, string OpcodeStr, RegisterClass RC,
ValueType vt, ValueType ScalarVT,
- X86MemOperand x86memop, Operand vec_memop,
- ComplexPattern mem_cpat, Intrinsic Intr,
+ X86MemOperand x86memop,
+ Intrinsic Intr,
SDNode OpNode, Domain d, OpndItins itins,
Predicate target, string Suffix> {
let hasSideEffects = 0 in {
@@ -3308,23 +3405,17 @@ multiclass sse_fp_unop_s<bits<8> opc, string OpcodeStr, RegisterClass RC,
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
[]>, Sched<[itins.Sched.Folded, ReadAfterLd]>;
let mayLoad = 1 in
- def m_Int : I<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, vec_memop:$src2),
+ def m_Int : I<opc, MRMSrcMem, (outs VR128:$dst), (ins VR128:$src1, x86memop:$src2),
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
[]>, Sched<[itins.Sched.Folded, ReadAfterLd]>;
}
}
let Predicates = [target] in {
- def : Pat<(vt (OpNode mem_cpat:$src)),
- (vt (COPY_TO_REGCLASS (vt (!cast<Instruction>(NAME#Suffix##m_Int)
- (vt (IMPLICIT_DEF)), mem_cpat:$src)), RC))>;
// These are unary operations, but they are modeled as having 2 source operands
// because the high elements of the destination are unchanged in SSE.
def : Pat<(Intr VR128:$src),
(!cast<Instruction>(NAME#Suffix##r_Int) VR128:$src, VR128:$src)>;
- def : Pat<(Intr (load addr:$src)),
- (vt (COPY_TO_REGCLASS(!cast<Instruction>(NAME#Suffix##m)
- addr:$src), VR128))>;
}
// We don't want to fold scalar loads into these instructions unless
// optimizing for size. This is because the folded instruction will have a
@@ -3334,16 +3425,15 @@ multiclass sse_fp_unop_s<bits<8> opc, string OpcodeStr, RegisterClass RC,
// which has a clobber before the rcp, vs.
// rcpss mem, %xmm0
let Predicates = [target, OptForSize] in {
- def : Pat<(Intr mem_cpat:$src),
+ def : Pat<(Intr (scalar_to_vector (ScalarVT (load addr:$src2)))),
(!cast<Instruction>(NAME#Suffix##m_Int)
- (vt (IMPLICIT_DEF)), mem_cpat:$src)>;
+ (vt (IMPLICIT_DEF)), addr:$src2)>;
}
}
multiclass avx_fp_unop_s<bits<8> opc, string OpcodeStr, RegisterClass RC,
ValueType vt, ValueType ScalarVT,
- X86MemOperand x86memop, Operand vec_memop,
- ComplexPattern mem_cpat,
+ X86MemOperand x86memop,
Intrinsic Intr, SDNode OpNode, Domain d,
OpndItins itins, string Suffix> {
let hasSideEffects = 0 in {
@@ -3361,7 +3451,7 @@ multiclass avx_fp_unop_s<bits<8> opc, string OpcodeStr, RegisterClass RC,
[]>, Sched<[itins.Sched.Folded]>;
let mayLoad = 1 in
def m_Int : I<opc, MRMSrcMem, (outs VR128:$dst),
- (ins VR128:$src1, vec_memop:$src2),
+ (ins VR128:$src1, x86memop:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[]>, Sched<[itins.Sched.Folded, ReadAfterLd]>;
}
@@ -3382,21 +3472,18 @@ multiclass avx_fp_unop_s<bits<8> opc, string OpcodeStr, RegisterClass RC,
}
let Predicates = [HasAVX] in {
def : Pat<(Intr VR128:$src),
- (!cast<Instruction>("V"#NAME#Suffix##r_Int) (vt (IMPLICIT_DEF)),
+ (!cast<Instruction>("V"#NAME#Suffix##r_Int) VR128:$src,
VR128:$src)>;
}
let Predicates = [HasAVX, OptForSize] in {
- def : Pat<(Intr mem_cpat:$src),
+ def : Pat<(Intr (scalar_to_vector (ScalarVT (load addr:$src2)))),
(!cast<Instruction>("V"#NAME#Suffix##m_Int)
- (vt (IMPLICIT_DEF)), mem_cpat:$src)>;
+ (vt (IMPLICIT_DEF)), addr:$src2)>;
}
let Predicates = [UseAVX, OptForSize] in {
def : Pat<(ScalarVT (OpNode (load addr:$src))),
(!cast<Instruction>("V"#NAME#Suffix##m) (ScalarVT (IMPLICIT_DEF)),
addr:$src)>;
- def : Pat<(vt (OpNode mem_cpat:$src)),
- (!cast<Instruction>("V"#NAME#Suffix##m_Int) (vt (IMPLICIT_DEF)),
- mem_cpat:$src)>;
}
}
@@ -3475,11 +3562,10 @@ let Predicates = [HasAVX] in {
multiclass sse1_fp_unop_s<bits<8> opc, string OpcodeStr, SDNode OpNode,
OpndItins itins> {
defm SS : sse_fp_unop_s<opc, OpcodeStr##ss, FR32, v4f32, f32, f32mem,
- ssmem, sse_load_f32,
!cast<Intrinsic>("int_x86_sse_"##OpcodeStr##_ss), OpNode,
SSEPackedSingle, itins, UseSSE1, "SS">, XS;
defm V#NAME#SS : avx_fp_unop_s<opc, "v"#OpcodeStr##ss, FR32, v4f32, f32,
- f32mem, ssmem, sse_load_f32,
+ f32mem,
!cast<Intrinsic>("int_x86_sse_"##OpcodeStr##_ss), OpNode,
SSEPackedSingle, itins, "SS">, XS, VEX_4V, VEX_LIG;
}
@@ -3487,11 +3573,10 @@ multiclass sse1_fp_unop_s<bits<8> opc, string OpcodeStr, SDNode OpNode,
multiclass sse2_fp_unop_s<bits<8> opc, string OpcodeStr, SDNode OpNode,
OpndItins itins> {
defm SD : sse_fp_unop_s<opc, OpcodeStr##sd, FR64, v2f64, f64, f64mem,
- sdmem, sse_load_f64,
!cast<Intrinsic>("int_x86_sse2_"##OpcodeStr##_sd),
OpNode, SSEPackedDouble, itins, UseSSE2, "SD">, XD;
defm V#NAME#SD : avx_fp_unop_s<opc, "v"#OpcodeStr##sd, FR64, v2f64, f64,
- f64mem, sdmem, sse_load_f64,
+ f64mem,
!cast<Intrinsic>("int_x86_sse2_"##OpcodeStr##_sd),
OpNode, SSEPackedDouble, itins, "SD">,
XD, VEX_4V, VEX_LIG;
@@ -3805,13 +3890,14 @@ def VMOVDQUYmr : I<0x7F, MRMDestMem, (outs), (ins i256mem:$dst, VR256:$src),
}
let SchedRW = [WriteMove] in {
-let hasSideEffects = 0 in
+let hasSideEffects = 0 in {
def MOVDQArr : PDI<0x6F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"movdqa\t{$src, $dst|$dst, $src}", [], IIC_SSE_MOVA_P_RR>;
def MOVDQUrr : I<0x6F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
"movdqu\t{$src, $dst|$dst, $src}",
[], IIC_SSE_MOVU_P_RR>, XS, Requires<[UseSSE2]>;
+}
// For Disassembler
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in {
@@ -3874,85 +3960,12 @@ def SSE_PMADD : OpndItins<
let ExeDomain = SSEPackedInt in { // SSE integer instructions
-multiclass PDI_binop_rm_int<bits<8> opc, string OpcodeStr, Intrinsic IntId,
- RegisterClass RC, PatFrag memop_frag,
- X86MemOperand x86memop,
- OpndItins itins,
- bit IsCommutable = 0,
- bit Is2Addr = 1> {
- let isCommutable = IsCommutable in
- def rr : PDI<opc, MRMSrcReg, (outs RC:$dst),
- (ins RC:$src1, RC:$src2),
- !if(Is2Addr,
- !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
- !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (IntId RC:$src1, RC:$src2))], itins.rr>,
- Sched<[itins.Sched]>;
- def rm : PDI<opc, MRMSrcMem, (outs RC:$dst),
- (ins RC:$src1, x86memop:$src2),
- !if(Is2Addr,
- !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
- !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (IntId RC:$src1, (bitconvert (memop_frag addr:$src2))))],
- itins.rm>, Sched<[itins.Sched.Folded, ReadAfterLd]>;
-}
-
-multiclass PDI_binop_all_int<bits<8> opc, string OpcodeStr, Intrinsic IntId128,
- Intrinsic IntId256, OpndItins itins,
- bit IsCommutable = 0> {
-let Predicates = [HasAVX] in
- defm V#NAME : PDI_binop_rm_int<opc, !strconcat("v", OpcodeStr), IntId128,
- VR128, loadv2i64, i128mem, itins,
- IsCommutable, 0>, VEX_4V;
-
-let Constraints = "$src1 = $dst" in
- defm NAME : PDI_binop_rm_int<opc, OpcodeStr, IntId128, VR128, memopv2i64,
- i128mem, itins, IsCommutable, 1>;
-
-let Predicates = [HasAVX2] in
- defm V#NAME#Y : PDI_binop_rm_int<opc, !strconcat("v", OpcodeStr), IntId256,
- VR256, loadv4i64, i256mem, itins,
- IsCommutable, 0>, VEX_4V, VEX_L;
-}
-
-multiclass PDI_binop_rmi<bits<8> opc, bits<8> opc2, Format ImmForm,
- string OpcodeStr, SDNode OpNode,
- SDNode OpNode2, RegisterClass RC,
- ValueType DstVT, ValueType SrcVT,
- PatFrag ld_frag, ShiftOpndItins itins,
- bit Is2Addr = 1> {
- // src2 is always 128-bit
- def rr : PDI<opc, MRMSrcReg, (outs RC:$dst),
- (ins RC:$src1, VR128:$src2),
- !if(Is2Addr,
- !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
- !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (DstVT (OpNode RC:$src1, (SrcVT VR128:$src2))))],
- itins.rr>, Sched<[WriteVecShift]>;
- def rm : PDI<opc, MRMSrcMem, (outs RC:$dst),
- (ins RC:$src1, i128mem:$src2),
- !if(Is2Addr,
- !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
- !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (DstVT (OpNode RC:$src1,
- (SrcVT (bitconvert (ld_frag addr:$src2))))))], itins.rm>,
- Sched<[WriteVecShiftLd, ReadAfterLd]>;
- def ri : PDIi8<opc2, ImmForm, (outs RC:$dst),
- (ins RC:$src1, u8imm:$src2),
- !if(Is2Addr,
- !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
- !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (DstVT (OpNode2 RC:$src1, (i8 imm:$src2))))], itins.ri>,
- Sched<[WriteVecShift]>;
-}
-
/// PDI_binop_rm2 - Simple SSE2 binary operator with different src and dst types
multiclass PDI_binop_rm2<bits<8> opc, string OpcodeStr, SDNode OpNode,
ValueType DstVT, ValueType SrcVT, RegisterClass RC,
PatFrag memop_frag, X86MemOperand x86memop,
- OpndItins itins,
- bit IsCommutable = 0, bit Is2Addr = 1> {
- let isCommutable = IsCommutable in
+ OpndItins itins, bit Is2Addr = 1> {
+ let isCommutable = 1 in
def rr : PDI<opc, MRMSrcReg, (outs RC:$dst),
(ins RC:$src1, RC:$src2),
!if(Is2Addr,
@@ -3984,9 +3997,9 @@ defm PADDSB : PDI_binop_all<0xEC, "paddsb", X86adds, v16i8, v32i8,
defm PADDSW : PDI_binop_all<0xED, "paddsw", X86adds, v8i16, v16i16,
SSE_INTALU_ITINS_P, 1, NoVLX_Or_NoBWI>;
defm PADDUSB : PDI_binop_all<0xDC, "paddusb", X86addus, v16i8, v32i8,
- SSE_INTALU_ITINS_P, 0, NoVLX_Or_NoBWI>;
+ SSE_INTALU_ITINS_P, 1, NoVLX_Or_NoBWI>;
defm PADDUSW : PDI_binop_all<0xDD, "paddusw", X86addus, v8i16, v16i16,
- SSE_INTALU_ITINS_P, 0, NoVLX_Or_NoBWI>;
+ SSE_INTALU_ITINS_P, 1, NoVLX_Or_NoBWI>;
defm PMULLW : PDI_binop_all<0xD5, "pmullw", mul, v8i16, v16i16,
SSE_INTMUL_ITINS_P, 1, NoVLX_Or_NoBWI>;
defm PMULHUW : PDI_binop_all<0xE4, "pmulhuw", mulhu, v8i16, v16i16,
@@ -4022,184 +4035,141 @@ defm PAVGB : PDI_binop_all<0xE0, "pavgb", X86avg, v16i8, v32i8,
defm PAVGW : PDI_binop_all<0xE3, "pavgw", X86avg, v8i16, v16i16,
SSE_INTALU_ITINS_P, 1, NoVLX_Or_NoBWI>;
-// Intrinsic forms
-defm PMADDWD : PDI_binop_all_int<0xF5, "pmaddwd", int_x86_sse2_pmadd_wd,
- int_x86_avx2_pmadd_wd, SSE_PMADD, 1>;
+let Predicates = [HasAVX, NoVLX_Or_NoBWI] in
+defm VPMADDWD : PDI_binop_rm2<0xF5, "vpmaddwd", X86vpmaddwd, v4i32, v8i16, VR128,
+ loadv2i64, i128mem, SSE_PMADD, 0>, VEX_4V;
+
+let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in
+defm VPMADDWDY : PDI_binop_rm2<0xF5, "vpmaddwd", X86vpmaddwd, v8i32, v16i16,
+ VR256, loadv4i64, i256mem, SSE_PMADD,
+ 0>, VEX_4V, VEX_L;
+let Constraints = "$src1 = $dst" in
+defm PMADDWD : PDI_binop_rm2<0xF5, "pmaddwd", X86vpmaddwd, v4i32, v8i16, VR128,
+ memopv2i64, i128mem, SSE_PMADD>;
let Predicates = [HasAVX, NoVLX_Or_NoBWI] in
defm VPSADBW : PDI_binop_rm2<0xF6, "vpsadbw", X86psadbw, v2i64, v16i8, VR128,
- loadv2i64, i128mem, SSE_INTMUL_ITINS_P, 1, 0>,
+ loadv2i64, i128mem, SSE_INTMUL_ITINS_P, 0>,
VEX_4V;
let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in
defm VPSADBWY : PDI_binop_rm2<0xF6, "vpsadbw", X86psadbw, v4i64, v32i8, VR256,
- loadv4i64, i256mem, SSE_INTMUL_ITINS_P, 1, 0>,
+ loadv4i64, i256mem, SSE_INTMUL_ITINS_P, 0>,
VEX_4V, VEX_L;
let Constraints = "$src1 = $dst" in
defm PSADBW : PDI_binop_rm2<0xF6, "psadbw", X86psadbw, v2i64, v16i8, VR128,
- memopv2i64, i128mem, SSE_INTALU_ITINS_P, 1>;
+ memopv2i64, i128mem, SSE_INTALU_ITINS_P>;
let Predicates = [HasAVX, NoVLX] in
defm VPMULUDQ : PDI_binop_rm2<0xF4, "vpmuludq", X86pmuludq, v2i64, v4i32, VR128,
- loadv2i64, i128mem, SSE_INTMUL_ITINS_P, 1, 0>,
+ loadv2i64, i128mem, SSE_INTMUL_ITINS_P, 0>,
VEX_4V;
let Predicates = [HasAVX2, NoVLX] in
defm VPMULUDQY : PDI_binop_rm2<0xF4, "vpmuludq", X86pmuludq, v4i64, v8i32,
VR256, loadv4i64, i256mem,
- SSE_INTMUL_ITINS_P, 1, 0>, VEX_4V, VEX_L;
+ SSE_INTMUL_ITINS_P, 0>, VEX_4V, VEX_L;
let Constraints = "$src1 = $dst" in
defm PMULUDQ : PDI_binop_rm2<0xF4, "pmuludq", X86pmuludq, v2i64, v4i32, VR128,
- memopv2i64, i128mem, SSE_INTMUL_ITINS_P, 1>;
+ memopv2i64, i128mem, SSE_INTMUL_ITINS_P>;
//===---------------------------------------------------------------------===//
// SSE2 - Packed Integer Logical Instructions
//===---------------------------------------------------------------------===//
-let Predicates = [HasAVX, NoVLX] in {
-defm VPSLLD : PDI_binop_rmi<0xF2, 0x72, MRM6r, "vpslld", X86vshl, X86vshli,
- VR128, v4i32, v4i32, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-defm VPSLLQ : PDI_binop_rmi<0xF3, 0x73, MRM6r, "vpsllq", X86vshl, X86vshli,
- VR128, v2i64, v2i64, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-
-defm VPSRLD : PDI_binop_rmi<0xD2, 0x72, MRM2r, "vpsrld", X86vsrl, X86vsrli,
- VR128, v4i32, v4i32, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-defm VPSRLQ : PDI_binop_rmi<0xD3, 0x73, MRM2r, "vpsrlq", X86vsrl, X86vsrli,
- VR128, v2i64, v2i64, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-
-defm VPSRAD : PDI_binop_rmi<0xE2, 0x72, MRM4r, "vpsrad", X86vsra, X86vsrai,
- VR128, v4i32, v4i32, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-} // Predicates = [HasAVX, NoVLX]
+multiclass PDI_binop_rmi<bits<8> opc, bits<8> opc2, Format ImmForm,
+ string OpcodeStr, SDNode OpNode,
+ SDNode OpNode2, RegisterClass RC,
+ ValueType DstVT, ValueType SrcVT,
+ PatFrag ld_frag, bit Is2Addr = 1> {
+ // src2 is always 128-bit
+ def rr : PDI<opc, MRMSrcReg, (outs RC:$dst),
+ (ins RC:$src1, VR128:$src2),
+ !if(Is2Addr,
+ !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
+ !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
+ [(set RC:$dst, (DstVT (OpNode RC:$src1, (SrcVT VR128:$src2))))],
+ SSE_INTSHIFT_ITINS_P.rr>, Sched<[WriteVecShift]>;
+ def rm : PDI<opc, MRMSrcMem, (outs RC:$dst),
+ (ins RC:$src1, i128mem:$src2),
+ !if(Is2Addr,
+ !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
+ !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
+ [(set RC:$dst, (DstVT (OpNode RC:$src1,
+ (SrcVT (bitconvert (ld_frag addr:$src2))))))],
+ SSE_INTSHIFT_ITINS_P.rm>, Sched<[WriteVecShiftLd, ReadAfterLd]>;
+ def ri : PDIi8<opc2, ImmForm, (outs RC:$dst),
+ (ins RC:$src1, u8imm:$src2),
+ !if(Is2Addr,
+ !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
+ !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
+ [(set RC:$dst, (DstVT (OpNode2 RC:$src1, (i8 imm:$src2))))],
+ SSE_INTSHIFT_ITINS_P.ri>, Sched<[WriteVecShift]>;
+}
-let Predicates = [HasAVX, NoVLX_Or_NoBWI] in {
-defm VPSLLW : PDI_binop_rmi<0xF1, 0x71, MRM6r, "vpsllw", X86vshl, X86vshli,
- VR128, v8i16, v8i16, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-defm VPSRLW : PDI_binop_rmi<0xD1, 0x71, MRM2r, "vpsrlw", X86vsrl, X86vsrli,
- VR128, v8i16, v8i16, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-defm VPSRAW : PDI_binop_rmi<0xE1, 0x71, MRM4r, "vpsraw", X86vsra, X86vsrai,
- VR128, v8i16, v8i16, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V;
-} // Predicates = [HasAVX, NoVLX_Or_NoBWI]
-
-
-let ExeDomain = SSEPackedInt, SchedRW = [WriteVecShift] ,
- Predicates = [HasAVX, NoVLX_Or_NoBWI]in {
- // 128-bit logical shifts.
- def VPSLLDQri : PDIi8<0x73, MRM7r,
- (outs VR128:$dst), (ins VR128:$src1, u8imm:$src2),
- "vpslldq\t{$src2, $src1, $dst|$dst, $src1, $src2}",
- [(set VR128:$dst,
- (v16i8 (X86vshldq VR128:$src1, (i8 imm:$src2))))]>,
- VEX_4V;
- def VPSRLDQri : PDIi8<0x73, MRM3r,
- (outs VR128:$dst), (ins VR128:$src1, u8imm:$src2),
- "vpsrldq\t{$src2, $src1, $dst|$dst, $src1, $src2}",
- [(set VR128:$dst,
- (v16i8 (X86vshrdq VR128:$src1, (i8 imm:$src2))))]>,
- VEX_4V;
- // PSRADQri doesn't exist in SSE[1-3].
-} // Predicates = [HasAVX, NoVLX_Or_NoBWI]
+multiclass PDI_binop_rmi_all<bits<8> opc, bits<8> opc2, Format ImmForm,
+ string OpcodeStr, SDNode OpNode,
+ SDNode OpNode2, ValueType DstVT128,
+ ValueType DstVT256, ValueType SrcVT,
+ Predicate prd> {
+let Predicates = [HasAVX, prd] in
+ defm V#NAME : PDI_binop_rmi<opc, opc2, ImmForm, !strconcat("v", OpcodeStr),
+ OpNode, OpNode2, VR128, DstVT128, SrcVT,
+ loadv2i64, 0>, VEX_4V;
+let Predicates = [HasAVX2, prd] in
+ defm V#NAME#Y : PDI_binop_rmi<opc, opc2, ImmForm, !strconcat("v", OpcodeStr),
+ OpNode, OpNode2, VR256, DstVT256, SrcVT,
+ loadv2i64, 0>, VEX_4V, VEX_L;
+let Constraints = "$src1 = $dst" in
+ defm NAME : PDI_binop_rmi<opc, opc2, ImmForm, OpcodeStr, OpNode, OpNode2,
+ VR128, DstVT128, SrcVT, memopv2i64>;
+}
-let Predicates = [HasAVX2, NoVLX] in {
-defm VPSLLDY : PDI_binop_rmi<0xF2, 0x72, MRM6r, "vpslld", X86vshl, X86vshli,
- VR256, v8i32, v4i32, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-defm VPSLLQY : PDI_binop_rmi<0xF3, 0x73, MRM6r, "vpsllq", X86vshl, X86vshli,
- VR256, v4i64, v2i64, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-
-defm VPSRLDY : PDI_binop_rmi<0xD2, 0x72, MRM2r, "vpsrld", X86vsrl, X86vsrli,
- VR256, v8i32, v4i32, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-defm VPSRLQY : PDI_binop_rmi<0xD3, 0x73, MRM2r, "vpsrlq", X86vsrl, X86vsrli,
- VR256, v4i64, v2i64, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-
-defm VPSRADY : PDI_binop_rmi<0xE2, 0x72, MRM4r, "vpsrad", X86vsra, X86vsrai,
- VR256, v8i32, v4i32, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-}// Predicates = [HasAVX2, NoVLX]
+multiclass PDI_binop_ri<bits<8> opc, Format ImmForm, string OpcodeStr,
+ SDNode OpNode, RegisterClass RC, ValueType VT,
+ bit Is2Addr = 1> {
+ def ri : PDIi8<opc, ImmForm, (outs RC:$dst), (ins RC:$src1, u8imm:$src2),
+ !if(Is2Addr,
+ !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
+ !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
+ [(set RC:$dst, (VT (OpNode RC:$src1, (i8 imm:$src2))))],
+ IIC_SSE_INTSHDQ_P_RI>, Sched<[WriteVecShift]>;
+}
-let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
-defm VPSLLWY : PDI_binop_rmi<0xF1, 0x71, MRM6r, "vpsllw", X86vshl, X86vshli,
- VR256, v16i16, v8i16, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-defm VPSRLWY : PDI_binop_rmi<0xD1, 0x71, MRM2r, "vpsrlw", X86vsrl, X86vsrli,
- VR256, v16i16, v8i16, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-defm VPSRAWY : PDI_binop_rmi<0xE1, 0x71, MRM4r, "vpsraw", X86vsra, X86vsrai,
- VR256, v16i16, v8i16, loadv2i64,
- SSE_INTSHIFT_ITINS_P, 0>, VEX_4V, VEX_L;
-}// Predicates = [HasAVX2, NoVLX_Or_NoBWI]
-
-let ExeDomain = SSEPackedInt, SchedRW = [WriteVecShift], hasSideEffects = 0 ,
- Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
- // 256-bit logical shifts.
- def VPSLLDQYri : PDIi8<0x73, MRM7r,
- (outs VR256:$dst), (ins VR256:$src1, u8imm:$src2),
- "vpslldq\t{$src2, $src1, $dst|$dst, $src1, $src2}",
- [(set VR256:$dst,
- (v32i8 (X86vshldq VR256:$src1, (i8 imm:$src2))))]>,
- VEX_4V, VEX_L;
- def VPSRLDQYri : PDIi8<0x73, MRM3r,
- (outs VR256:$dst), (ins VR256:$src1, u8imm:$src2),
- "vpsrldq\t{$src2, $src1, $dst|$dst, $src1, $src2}",
- [(set VR256:$dst,
- (v32i8 (X86vshrdq VR256:$src1, (i8 imm:$src2))))]>,
- VEX_4V, VEX_L;
- // PSRADQYri doesn't exist in SSE[1-3].
-} // Predicates = [HasAVX2, NoVLX_Or_NoBWI]
+multiclass PDI_binop_ri_all<bits<8> opc, Format ImmForm, string OpcodeStr,
+ SDNode OpNode> {
+let Predicates = [HasAVX, NoVLX_Or_NoBWI] in
+ defm V#NAME : PDI_binop_ri<opc, ImmForm, !strconcat("v", OpcodeStr), OpNode,
+ VR128, v16i8, 0>, VEX_4V;
+let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in
+ defm V#NAME#Y : PDI_binop_ri<opc, ImmForm, !strconcat("v", OpcodeStr), OpNode,
+ VR256, v32i8, 0>, VEX_4V, VEX_L;
+let Constraints = "$src1 = $dst" in
+ defm NAME : PDI_binop_ri<opc, ImmForm, OpcodeStr, OpNode, VR128, v16i8>;
+}
-let Constraints = "$src1 = $dst" in {
-defm PSLLW : PDI_binop_rmi<0xF1, 0x71, MRM6r, "psllw", X86vshl, X86vshli,
- VR128, v8i16, v8i16, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-defm PSLLD : PDI_binop_rmi<0xF2, 0x72, MRM6r, "pslld", X86vshl, X86vshli,
- VR128, v4i32, v4i32, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-defm PSLLQ : PDI_binop_rmi<0xF3, 0x73, MRM6r, "psllq", X86vshl, X86vshli,
- VR128, v2i64, v2i64, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-
-defm PSRLW : PDI_binop_rmi<0xD1, 0x71, MRM2r, "psrlw", X86vsrl, X86vsrli,
- VR128, v8i16, v8i16, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-defm PSRLD : PDI_binop_rmi<0xD2, 0x72, MRM2r, "psrld", X86vsrl, X86vsrli,
- VR128, v4i32, v4i32, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-defm PSRLQ : PDI_binop_rmi<0xD3, 0x73, MRM2r, "psrlq", X86vsrl, X86vsrli,
- VR128, v2i64, v2i64, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-
-defm PSRAW : PDI_binop_rmi<0xE1, 0x71, MRM4r, "psraw", X86vsra, X86vsrai,
- VR128, v8i16, v8i16, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-defm PSRAD : PDI_binop_rmi<0xE2, 0x72, MRM4r, "psrad", X86vsra, X86vsrai,
- VR128, v4i32, v4i32, memopv2i64,
- SSE_INTSHIFT_ITINS_P>;
-
-let ExeDomain = SSEPackedInt, SchedRW = [WriteVecShift], hasSideEffects = 0 in {
- // 128-bit logical shifts.
- def PSLLDQri : PDIi8<0x73, MRM7r,
- (outs VR128:$dst), (ins VR128:$src1, u8imm:$src2),
- "pslldq\t{$src2, $dst|$dst, $src2}",
- [(set VR128:$dst,
- (v16i8 (X86vshldq VR128:$src1, (i8 imm:$src2))))],
- IIC_SSE_INTSHDQ_P_RI>;
- def PSRLDQri : PDIi8<0x73, MRM3r,
- (outs VR128:$dst), (ins VR128:$src1, u8imm:$src2),
- "psrldq\t{$src2, $dst|$dst, $src2}",
- [(set VR128:$dst,
- (v16i8 (X86vshrdq VR128:$src1, (i8 imm:$src2))))],
- IIC_SSE_INTSHDQ_P_RI>;
+let ExeDomain = SSEPackedInt in {
+ defm PSLLW : PDI_binop_rmi_all<0xF1, 0x71, MRM6r, "psllw", X86vshl, X86vshli,
+ v8i16, v16i16, v8i16, NoVLX_Or_NoBWI>;
+ defm PSLLD : PDI_binop_rmi_all<0xF2, 0x72, MRM6r, "pslld", X86vshl, X86vshli,
+ v4i32, v8i32, v4i32, NoVLX>;
+ defm PSLLQ : PDI_binop_rmi_all<0xF3, 0x73, MRM6r, "psllq", X86vshl, X86vshli,
+ v2i64, v4i64, v2i64, NoVLX>;
+
+ defm PSRLW : PDI_binop_rmi_all<0xD1, 0x71, MRM2r, "psrlw", X86vsrl, X86vsrli,
+ v8i16, v16i16, v8i16, NoVLX_Or_NoBWI>;
+ defm PSRLD : PDI_binop_rmi_all<0xD2, 0x72, MRM2r, "psrld", X86vsrl, X86vsrli,
+ v4i32, v8i32, v4i32, NoVLX>;
+ defm PSRLQ : PDI_binop_rmi_all<0xD3, 0x73, MRM2r, "psrlq", X86vsrl, X86vsrli,
+ v2i64, v4i64, v2i64, NoVLX>;
+
+ defm PSRAW : PDI_binop_rmi_all<0xE1, 0x71, MRM4r, "psraw", X86vsra, X86vsrai,
+ v8i16, v16i16, v8i16, NoVLX_Or_NoBWI>;
+ defm PSRAD : PDI_binop_rmi_all<0xE2, 0x72, MRM4r, "psrad", X86vsra, X86vsrai,
+ v4i32, v8i32, v4i32, NoVLX>;
+
+ defm PSLLDQ : PDI_binop_ri_all<0x73, MRM7r, "pslldq", X86vshldq>;
+ defm PSRLDQ : PDI_binop_ri_all<0x73, MRM3r, "psrldq", X86vshrdq>;
// PSRADQri doesn't exist in SSE[1-3].
-}
-} // Constraints = "$src1 = $dst"
+} // ExeDomain = SSEPackedInt
//===---------------------------------------------------------------------===//
// SSE2 - Packed Integer Comparison Instructions
@@ -4651,6 +4621,7 @@ def MASKMOVDQU64 : PDI<0xF7, MRMSrcReg, (outs), (ins VR128:$src, VR128:$mask),
//===---------------------------------------------------------------------===//
// Move Int Doubleword to Packed Double Int
//
+let ExeDomain = SSEPackedInt in {
def VMOVDI2PDIrr : VS2I<0x6E, MRMSrcReg, (outs VR128:$dst), (ins GR32:$src),
"movd\t{$src, $dst|$dst, $src}",
[(set VR128:$dst,
@@ -4701,11 +4672,12 @@ def MOV64toSDrr : RS2I<0x6E, MRMSrcReg, (outs FR64:$dst), (ins GR64:$src),
"mov{d|q}\t{$src, $dst|$dst, $src}",
[(set FR64:$dst, (bitconvert GR64:$src))],
IIC_SSE_MOVDQ>, Sched<[WriteMove]>;
+} // ExeDomain = SSEPackedInt
//===---------------------------------------------------------------------===//
// Move Int Doubleword to Single Scalar
//
-let isCodeGenOnly = 1 in {
+let ExeDomain = SSEPackedInt, isCodeGenOnly = 1 in {
def VMOVDI2SSrr : VS2I<0x6E, MRMSrcReg, (outs FR32:$dst), (ins GR32:$src),
"movd\t{$src, $dst|$dst, $src}",
[(set FR32:$dst, (bitconvert GR32:$src))],
@@ -4725,11 +4697,12 @@ let isCodeGenOnly = 1 in {
"movd\t{$src, $dst|$dst, $src}",
[(set FR32:$dst, (bitconvert (loadi32 addr:$src)))],
IIC_SSE_MOVDQ>, Sched<[WriteLoad]>;
-}
+} // ExeDomain = SSEPackedInt, isCodeGenOnly = 1
//===---------------------------------------------------------------------===//
// Move Packed Doubleword Int to Packed Double Int
//
+let ExeDomain = SSEPackedInt in {
def VMOVPDI2DIrr : VS2I<0x7E, MRMDestReg, (outs GR32:$dst), (ins VR128:$src),
"movd\t{$src, $dst|$dst, $src}",
[(set GR32:$dst, (extractelt (v4i32 VR128:$src),
@@ -4751,6 +4724,7 @@ def MOVPDI2DImr : S2I<0x7E, MRMDestMem, (outs), (ins i32mem:$dst, VR128:$src),
[(store (i32 (extractelt (v4i32 VR128:$src),
(iPTR 0))), addr:$dst)],
IIC_SSE_MOVDQ>, Sched<[WriteStore]>;
+} // ExeDomain = SSEPackedInt
def : Pat<(v8i32 (X86Vinsert (v8i32 immAllZerosV), GR32:$src2, (iPTR 0))),
(SUBREG_TO_REG (i32 0), (VMOVDI2PDIrr GR32:$src2), sub_xmm)>;
@@ -4767,6 +4741,7 @@ def : Pat<(v4i64 (X86Vinsert undef, GR64:$src2, (iPTR 0))),
//===---------------------------------------------------------------------===//
// Move Packed Doubleword Int first element to Doubleword Int
//
+let ExeDomain = SSEPackedInt in {
let SchedRW = [WriteMove] in {
def VMOVPQIto64rr : VRS2I<0x7E, MRMDestReg, (outs GR64:$dst), (ins VR128:$src),
"movq\t{$src, $dst|$dst, $src}",
@@ -4791,11 +4766,12 @@ let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0, mayStore = 1 in
def MOVPQIto64rm : RS2I<0x7E, MRMDestMem, (outs), (ins i64mem:$dst, VR128:$src),
"mov{d|q}\t{$src, $dst|$dst, $src}",
[], IIC_SSE_MOVDQ>, Sched<[WriteStore]>;
+} // ExeDomain = SSEPackedInt
//===---------------------------------------------------------------------===//
// Bitcast FR64 <-> GR64
//
-let isCodeGenOnly = 1 in {
+let ExeDomain = SSEPackedInt, isCodeGenOnly = 1 in {
let Predicates = [UseAVX] in
def VMOV64toSDrm : VS2SI<0x7E, MRMSrcMem, (outs FR64:$dst), (ins i64mem:$src),
"movq\t{$src, $dst|$dst, $src}",
@@ -4822,12 +4798,12 @@ let isCodeGenOnly = 1 in {
"movq\t{$src, $dst|$dst, $src}",
[(store (i64 (bitconvert FR64:$src)), addr:$dst)],
IIC_SSE_MOVDQ>, Sched<[WriteStore]>;
-}
+} // ExeDomain = SSEPackedInt, isCodeGenOnly = 1
//===---------------------------------------------------------------------===//
// Move Scalar Single to Double Int
//
-let isCodeGenOnly = 1 in {
+let ExeDomain = SSEPackedInt, isCodeGenOnly = 1 in {
def VMOVSS2DIrr : VS2I<0x7E, MRMDestReg, (outs GR32:$dst), (ins FR32:$src),
"movd\t{$src, $dst|$dst, $src}",
[(set GR32:$dst, (bitconvert FR32:$src))],
@@ -4844,7 +4820,7 @@ let isCodeGenOnly = 1 in {
"movd\t{$src, $dst|$dst, $src}",
[(store (i32 (bitconvert FR32:$src)), addr:$dst)],
IIC_SSE_MOVDQ>, Sched<[WriteStore]>;
-}
+} // ExeDomain = SSEPackedInt, isCodeGenOnly = 1
let Predicates = [UseAVX] in {
let AddedComplexity = 15 in {
@@ -4867,9 +4843,13 @@ let Predicates = [UseAVX] in {
(VMOVDI2PDIrm addr:$src)>;
def : Pat<(v4i32 (X86vzmovl (bc_v4i32 (loadv2i64 addr:$src)))),
(VMOVDI2PDIrm addr:$src)>;
+ def : Pat<(v4i32 (X86vzload addr:$src)),
+ (VMOVDI2PDIrm addr:$src)>;
def : Pat<(v8i32 (X86vzmovl (insert_subvector undef,
(v4i32 (scalar_to_vector (loadi32 addr:$src))), (iPTR 0)))),
(SUBREG_TO_REG (i32 0), (VMOVDI2PDIrm addr:$src), sub_xmm)>;
+ def : Pat<(v8i32 (X86vzload addr:$src)),
+ (SUBREG_TO_REG (i64 0), (VMOVDI2PDIrm addr:$src), sub_xmm)>;
}
// Use regular 128-bit instructions to match 256-bit scalar_to_vec+zext.
def : Pat<(v8i32 (X86vzmovl (insert_subvector undef,
@@ -4892,6 +4872,8 @@ let Predicates = [UseSSE2] in {
(MOVDI2PDIrm addr:$src)>;
def : Pat<(v4i32 (X86vzmovl (bc_v4i32 (loadv2i64 addr:$src)))),
(MOVDI2PDIrm addr:$src)>;
+ def : Pat<(v4i32 (X86vzload addr:$src)),
+ (MOVDI2PDIrm addr:$src)>;
}
}
@@ -4960,43 +4942,30 @@ def MOVPQI2QIrr : S2I<0xD6, MRMDestReg, (outs VR128:$dst), (ins VR128:$src),
def : InstAlias<"vmovq\t{$src, $dst|$dst, $src}",
(VMOVPQI2QIrr VR128L:$dst, VR128H:$src), 0>;
-//===---------------------------------------------------------------------===//
-// Store / copy lower 64-bits of a XMM register.
-//
-let ExeDomain = SSEPackedInt, isCodeGenOnly = 1, AddedComplexity = 20 in {
-def VMOVZQI2PQIrm : I<0x7E, MRMSrcMem, (outs VR128:$dst), (ins i64mem:$src),
- "vmovq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (v2i64 (X86vzmovl (v2i64 (scalar_to_vector
- (loadi64 addr:$src))))))],
- IIC_SSE_MOVDQ>,
- XS, VEX, Requires<[UseAVX]>, Sched<[WriteLoad]>;
-
-def MOVZQI2PQIrm : I<0x7E, MRMSrcMem, (outs VR128:$dst), (ins i64mem:$src),
- "movq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst,
- (v2i64 (X86vzmovl (v2i64 (scalar_to_vector
- (loadi64 addr:$src))))))],
- IIC_SSE_MOVDQ>,
- XS, Requires<[UseSSE2]>, Sched<[WriteLoad]>;
-} // ExeDomain, isCodeGenOnly, AddedComplexity
-
let Predicates = [UseAVX], AddedComplexity = 20 in {
+ def : Pat<(v2i64 (X86vzmovl (v2i64 (scalar_to_vector (loadi64 addr:$src))))),
+ (VMOVQI2PQIrm addr:$src)>;
+ def : Pat<(v2i64 (X86vzmovl (loadv2i64 addr:$src))),
+ (VMOVQI2PQIrm addr:$src)>;
def : Pat<(v2i64 (X86vzmovl (bc_v2i64 (loadv4f32 addr:$src)))),
- (VMOVZQI2PQIrm addr:$src)>;
+ (VMOVQI2PQIrm addr:$src)>;
def : Pat<(v2i64 (X86vzload addr:$src)),
- (VMOVZQI2PQIrm addr:$src)>;
+ (VMOVQI2PQIrm addr:$src)>;
def : Pat<(v4i64 (X86vzmovl (insert_subvector undef,
(v2i64 (scalar_to_vector (loadi64 addr:$src))), (iPTR 0)))),
- (SUBREG_TO_REG (i64 0), (VMOVZQI2PQIrm addr:$src), sub_xmm)>;
+ (SUBREG_TO_REG (i64 0), (VMOVQI2PQIrm addr:$src), sub_xmm)>;
def : Pat<(v4i64 (X86vzload addr:$src)),
- (SUBREG_TO_REG (i64 0), (VMOVZQI2PQIrm addr:$src), sub_xmm)>;
+ (SUBREG_TO_REG (i64 0), (VMOVQI2PQIrm addr:$src), sub_xmm)>;
}
let Predicates = [UseSSE2], AddedComplexity = 20 in {
+ def : Pat<(v2i64 (X86vzmovl (v2i64 (scalar_to_vector (loadi64 addr:$src))))),
+ (MOVQI2PQIrm addr:$src)>;
+ def : Pat<(v2i64 (X86vzmovl (loadv2i64 addr:$src))),
+ (MOVQI2PQIrm addr:$src)>;
def : Pat<(v2i64 (X86vzmovl (bc_v2i64 (loadv4f32 addr:$src)))),
- (MOVZQI2PQIrm addr:$src)>;
- def : Pat<(v2i64 (X86vzload addr:$src)), (MOVZQI2PQIrm addr:$src)>;
+ (MOVQI2PQIrm addr:$src)>;
+ def : Pat<(v2i64 (X86vzload addr:$src)), (MOVQI2PQIrm addr:$src)>;
}
//===---------------------------------------------------------------------===//
@@ -5018,24 +4987,6 @@ def MOVZPQILo2PQIrr : I<0x7E, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src),
XS, Requires<[UseSSE2]>;
} // ExeDomain, SchedRW
-let ExeDomain = SSEPackedInt, isCodeGenOnly = 1, SchedRW = [WriteVecLogicLd] in {
-let AddedComplexity = 20 in
-def VMOVZPQILo2PQIrm : I<0x7E, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src),
- "vmovq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (v2i64 (X86vzmovl
- (loadv2i64 addr:$src))))],
- IIC_SSE_MOVDQ>,
- XS, VEX, Requires<[UseAVX]>;
-let AddedComplexity = 20 in {
-def MOVZPQILo2PQIrm : I<0x7E, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src),
- "movq\t{$src, $dst|$dst, $src}",
- [(set VR128:$dst, (v2i64 (X86vzmovl
- (loadv2i64 addr:$src))))],
- IIC_SSE_MOVDQ>,
- XS, Requires<[UseSSE2]>;
-}
-} // ExeDomain, isCodeGenOnly, SchedRW
-
let AddedComplexity = 20 in {
let Predicates = [UseAVX] in {
def : Pat<(v2f64 (X86vzmovl (v2f64 VR128:$src))),
@@ -5167,12 +5118,12 @@ let Predicates = [HasAVX] in {
(VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>;
}
-let Predicates = [UseAVX, OptForSize] in {
- def : Pat<(v2f64 (X86VBroadcast (loadf64 addr:$src))),
- (VMOVDDUPrm addr:$src)>;
- def : Pat<(v2i64 (X86VBroadcast (loadi64 addr:$src))),
- (VMOVDDUPrm addr:$src)>;
-}
+let Predicates = [HasAVX, NoVLX] in
+def : Pat<(v2f64 (X86VBroadcast (loadf64 addr:$src))),
+ (VMOVDDUPrm addr:$src)>;
+let Predicates = [HasAVX1Only] in
+def : Pat<(v2i64 (X86VBroadcast (loadi64 addr:$src))),
+ (VMOVDDUPrm addr:$src)>;
let Predicates = [UseSSE3] in {
def : Pat<(X86Movddup (memopv2f64 addr:$src)),
@@ -5370,35 +5321,35 @@ let Constraints = "$src1 = $dst" in {
/// SS3I_unop_rm_int - Simple SSSE3 unary op whose type can be v*{i8,i16,i32}.
multiclass SS3I_unop_rm<bits<8> opc, string OpcodeStr, ValueType vt,
SDNode OpNode, PatFrag ld_frag> {
- def rr128 : SS38I<opc, MRMSrcReg, (outs VR128:$dst),
- (ins VR128:$src),
- !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
- [(set VR128:$dst, (vt (OpNode VR128:$src)))],
- IIC_SSE_PABS_RR>, Sched<[WriteVecALU]>;
+ def rr : SS38I<opc, MRMSrcReg, (outs VR128:$dst),
+ (ins VR128:$src),
+ !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
+ [(set VR128:$dst, (vt (OpNode VR128:$src)))],
+ IIC_SSE_PABS_RR>, Sched<[WriteVecALU]>;
- def rm128 : SS38I<opc, MRMSrcMem, (outs VR128:$dst),
- (ins i128mem:$src),
- !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
- [(set VR128:$dst,
- (vt (OpNode (bitconvert (ld_frag addr:$src)))))],
- IIC_SSE_PABS_RM>, Sched<[WriteVecALULd]>;
+ def rm : SS38I<opc, MRMSrcMem, (outs VR128:$dst),
+ (ins i128mem:$src),
+ !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
+ [(set VR128:$dst,
+ (vt (OpNode (bitconvert (ld_frag addr:$src)))))],
+ IIC_SSE_PABS_RM>, Sched<[WriteVecALULd]>;
}
/// SS3I_unop_rm_int_y - Simple SSSE3 unary op whose type can be v*{i8,i16,i32}.
multiclass SS3I_unop_rm_y<bits<8> opc, string OpcodeStr, ValueType vt,
SDNode OpNode> {
- def rr256 : SS38I<opc, MRMSrcReg, (outs VR256:$dst),
- (ins VR256:$src),
- !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
- [(set VR256:$dst, (vt (OpNode VR256:$src)))]>,
- Sched<[WriteVecALU]>;
+ def Yrr : SS38I<opc, MRMSrcReg, (outs VR256:$dst),
+ (ins VR256:$src),
+ !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
+ [(set VR256:$dst, (vt (OpNode VR256:$src)))]>,
+ Sched<[WriteVecALU]>;
- def rm256 : SS38I<opc, MRMSrcMem, (outs VR256:$dst),
- (ins i256mem:$src),
- !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
- [(set VR256:$dst,
- (vt (OpNode (bitconvert (loadv4i64 addr:$src)))))]>,
- Sched<[WriteVecALULd]>;
+ def Yrm : SS38I<opc, MRMSrcMem, (outs VR256:$dst),
+ (ins i256mem:$src),
+ !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"),
+ [(set VR256:$dst,
+ (vt (OpNode (bitconvert (loadv4i64 addr:$src)))))]>,
+ Sched<[WriteVecALULd]>;
}
// Helper fragments to match sext vXi1 to vXiY.
@@ -5419,19 +5370,21 @@ let Predicates = [HasAVX, NoVLX] in {
defm VPABSD : SS3I_unop_rm<0x1E, "vpabsd", v4i32, X86Abs, loadv2i64>, VEX;
}
-let Predicates = [HasAVX] in {
+let Predicates = [HasAVX, NoVLX_Or_NoBWI] in {
def : Pat<(xor
(bc_v2i64 (v16i1sextv16i8)),
(bc_v2i64 (add (v16i8 VR128:$src), (v16i1sextv16i8)))),
- (VPABSBrr128 VR128:$src)>;
+ (VPABSBrr VR128:$src)>;
def : Pat<(xor
(bc_v2i64 (v8i1sextv8i16)),
(bc_v2i64 (add (v8i16 VR128:$src), (v8i1sextv8i16)))),
- (VPABSWrr128 VR128:$src)>;
+ (VPABSWrr VR128:$src)>;
+}
+let Predicates = [HasAVX, NoVLX] in {
def : Pat<(xor
(bc_v2i64 (v4i1sextv4i32)),
(bc_v2i64 (add (v4i32 VR128:$src), (v4i1sextv4i32)))),
- (VPABSDrr128 VR128:$src)>;
+ (VPABSDrr VR128:$src)>;
}
let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
@@ -5442,19 +5395,21 @@ let Predicates = [HasAVX2, NoVLX] in {
defm VPABSD : SS3I_unop_rm_y<0x1E, "vpabsd", v8i32, X86Abs>, VEX, VEX_L;
}
-let Predicates = [HasAVX2] in {
+let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
def : Pat<(xor
(bc_v4i64 (v32i1sextv32i8)),
(bc_v4i64 (add (v32i8 VR256:$src), (v32i1sextv32i8)))),
- (VPABSBrr256 VR256:$src)>;
+ (VPABSBYrr VR256:$src)>;
def : Pat<(xor
(bc_v4i64 (v16i1sextv16i16)),
(bc_v4i64 (add (v16i16 VR256:$src), (v16i1sextv16i16)))),
- (VPABSWrr256 VR256:$src)>;
+ (VPABSWYrr VR256:$src)>;
+}
+let Predicates = [HasAVX2, NoVLX] in {
def : Pat<(xor
(bc_v4i64 (v8i1sextv8i32)),
(bc_v4i64 (add (v8i32 VR256:$src), (v8i1sextv8i32)))),
- (VPABSDrr256 VR256:$src)>;
+ (VPABSDYrr VR256:$src)>;
}
defm PABSB : SS3I_unop_rm<0x1C, "pabsb", v16i8, X86Abs, memopv2i64>;
@@ -5465,15 +5420,15 @@ let Predicates = [UseSSSE3] in {
def : Pat<(xor
(bc_v2i64 (v16i1sextv16i8)),
(bc_v2i64 (add (v16i8 VR128:$src), (v16i1sextv16i8)))),
- (PABSBrr128 VR128:$src)>;
+ (PABSBrr VR128:$src)>;
def : Pat<(xor
(bc_v2i64 (v8i1sextv8i16)),
(bc_v2i64 (add (v8i16 VR128:$src), (v8i1sextv8i16)))),
- (PABSWrr128 VR128:$src)>;
+ (PABSWrr VR128:$src)>;
def : Pat<(xor
(bc_v2i64 (v4i1sextv4i32)),
(bc_v2i64 (add (v4i32 VR128:$src), (v4i1sextv4i32)))),
- (PABSDrr128 VR128:$src)>;
+ (PABSDrr VR128:$src)>;
}
//===---------------------------------------------------------------------===//
@@ -5506,16 +5461,16 @@ def SSE_PMULHRSW : OpndItins<
/// SS3I_binop_rm - Simple SSSE3 bin op
multiclass SS3I_binop_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
- ValueType OpVT, RegisterClass RC, PatFrag memop_frag,
- X86MemOperand x86memop, OpndItins itins,
- bit Is2Addr = 1> {
+ ValueType DstVT, ValueType OpVT, RegisterClass RC,
+ PatFrag memop_frag, X86MemOperand x86memop,
+ OpndItins itins, bit Is2Addr = 1> {
let isCommutable = 1 in
def rr : SS38I<opc, MRMSrcReg, (outs RC:$dst),
(ins RC:$src1, RC:$src2),
!if(Is2Addr,
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
- [(set RC:$dst, (OpVT (OpNode RC:$src1, RC:$src2)))], itins.rr>,
+ [(set RC:$dst, (DstVT (OpNode (OpVT RC:$src1), RC:$src2)))], itins.rr>,
Sched<[itins.Sched]>;
def rm : SS38I<opc, MRMSrcMem, (outs RC:$dst),
(ins RC:$src1, x86memop:$src2),
@@ -5523,7 +5478,7 @@ multiclass SS3I_binop_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
!strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")),
[(set RC:$dst,
- (OpVT (OpNode RC:$src1,
+ (DstVT (OpNode (OpVT RC:$src1),
(bitconvert (memop_frag addr:$src2)))))], itins.rm>,
Sched<[itins.Sched.Folded, ReadAfterLd]>;
}
@@ -5568,18 +5523,32 @@ multiclass SS3I_binop_rm_int_y<bits<8> opc, string OpcodeStr,
Sched<[Sched.Folded, ReadAfterLd]>;
}
+let ImmT = NoImm, Predicates = [HasAVX, NoVLX_Or_NoBWI] in {
+let isCommutable = 0 in {
+ defm VPSHUFB : SS3I_binop_rm<0x00, "vpshufb", X86pshufb, v16i8, v16i8,
+ VR128, loadv2i64, i128mem,
+ SSE_PSHUFB, 0>, VEX_4V;
+ defm VPMADDUBSW : SS3I_binop_rm<0x04, "vpmaddubsw", X86vpmaddubsw, v8i16,
+ v16i8, VR128, loadv2i64, i128mem,
+ SSE_PMADD, 0>, VEX_4V;
+}
+defm VPMULHRSW : SS3I_binop_rm<0x0B, "vpmulhrsw", X86mulhrs, v8i16, v8i16,
+ VR128, loadv2i64, i128mem,
+ SSE_PMULHRSW, 0>, VEX_4V;
+}
+
let ImmT = NoImm, Predicates = [HasAVX] in {
let isCommutable = 0 in {
- defm VPHADDW : SS3I_binop_rm<0x01, "vphaddw", X86hadd, v8i16, VR128,
+ defm VPHADDW : SS3I_binop_rm<0x01, "vphaddw", X86hadd, v8i16, v8i16, VR128,
loadv2i64, i128mem,
SSE_PHADDSUBW, 0>, VEX_4V;
- defm VPHADDD : SS3I_binop_rm<0x02, "vphaddd", X86hadd, v4i32, VR128,
+ defm VPHADDD : SS3I_binop_rm<0x02, "vphaddd", X86hadd, v4i32, v4i32, VR128,
loadv2i64, i128mem,
SSE_PHADDSUBD, 0>, VEX_4V;
- defm VPHSUBW : SS3I_binop_rm<0x05, "vphsubw", X86hsub, v8i16, VR128,
+ defm VPHSUBW : SS3I_binop_rm<0x05, "vphsubw", X86hsub, v8i16, v8i16, VR128,
loadv2i64, i128mem,
SSE_PHADDSUBW, 0>, VEX_4V;
- defm VPHSUBD : SS3I_binop_rm<0x06, "vphsubd", X86hsub, v4i32, VR128,
+ defm VPHSUBD : SS3I_binop_rm<0x06, "vphsubd", X86hsub, v4i32, v4i32, VR128,
loadv2i64, i128mem,
SSE_PHADDSUBD, 0>, VEX_4V;
defm VPSIGNB : SS3I_binop_rm_int<0x08, "vpsignb",
@@ -5591,36 +5560,41 @@ let isCommutable = 0 in {
defm VPSIGND : SS3I_binop_rm_int<0x0A, "vpsignd",
int_x86_ssse3_psign_d_128,
SSE_PSIGN, loadv2i64, 0>, VEX_4V;
- defm VPSHUFB : SS3I_binop_rm<0x00, "vpshufb", X86pshufb, v16i8, VR128,
- loadv2i64, i128mem,
- SSE_PSHUFB, 0>, VEX_4V;
defm VPHADDSW : SS3I_binop_rm_int<0x03, "vphaddsw",
int_x86_ssse3_phadd_sw_128,
SSE_PHADDSUBSW, loadv2i64, 0>, VEX_4V;
defm VPHSUBSW : SS3I_binop_rm_int<0x07, "vphsubsw",
int_x86_ssse3_phsub_sw_128,
SSE_PHADDSUBSW, loadv2i64, 0>, VEX_4V;
- defm VPMADDUBSW : SS3I_binop_rm_int<0x04, "vpmaddubsw",
- int_x86_ssse3_pmadd_ub_sw_128,
- SSE_PMADD, loadv2i64, 0>, VEX_4V;
}
-defm VPMULHRSW : SS3I_binop_rm_int<0x0B, "vpmulhrsw",
- int_x86_ssse3_pmul_hr_sw_128,
- SSE_PMULHRSW, loadv2i64, 0>, VEX_4V;
+}
+
+let ImmT = NoImm, Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
+let isCommutable = 0 in {
+ defm VPSHUFBY : SS3I_binop_rm<0x00, "vpshufb", X86pshufb, v32i8, v32i8,
+ VR256, loadv4i64, i256mem,
+ SSE_PSHUFB, 0>, VEX_4V, VEX_L;
+ defm VPMADDUBSWY : SS3I_binop_rm<0x04, "vpmaddubsw", X86vpmaddubsw, v16i16,
+ v32i8, VR256, loadv4i64, i256mem,
+ SSE_PMADD, 0>, VEX_4V, VEX_L;
+}
+defm VPMULHRSWY : SS3I_binop_rm<0x0B, "vpmulhrsw", X86mulhrs, v16i16, v16i16,
+ VR256, loadv4i64, i256mem,
+ SSE_PMULHRSW, 0>, VEX_4V, VEX_L;
}
let ImmT = NoImm, Predicates = [HasAVX2] in {
let isCommutable = 0 in {
- defm VPHADDWY : SS3I_binop_rm<0x01, "vphaddw", X86hadd, v16i16, VR256,
- loadv4i64, i256mem,
+ defm VPHADDWY : SS3I_binop_rm<0x01, "vphaddw", X86hadd, v16i16, v16i16,
+ VR256, loadv4i64, i256mem,
SSE_PHADDSUBW, 0>, VEX_4V, VEX_L;
- defm VPHADDDY : SS3I_binop_rm<0x02, "vphaddd", X86hadd, v8i32, VR256,
+ defm VPHADDDY : SS3I_binop_rm<0x02, "vphaddd", X86hadd, v8i32, v8i32, VR256,
loadv4i64, i256mem,
SSE_PHADDSUBW, 0>, VEX_4V, VEX_L;
- defm VPHSUBWY : SS3I_binop_rm<0x05, "vphsubw", X86hsub, v16i16, VR256,
- loadv4i64, i256mem,
+ defm VPHSUBWY : SS3I_binop_rm<0x05, "vphsubw", X86hsub, v16i16, v16i16,
+ VR256, loadv4i64, i256mem,
SSE_PHADDSUBW, 0>, VEX_4V, VEX_L;
- defm VPHSUBDY : SS3I_binop_rm<0x06, "vphsubd", X86hsub, v8i32, VR256,
+ defm VPHSUBDY : SS3I_binop_rm<0x06, "vphsubd", X86hsub, v8i32, v8i32, VR256,
loadv4i64, i256mem,
SSE_PHADDSUBW, 0>, VEX_4V, VEX_L;
defm VPSIGNBY : SS3I_binop_rm_int_y<0x08, "vpsignb", int_x86_avx2_psign_b,
@@ -5629,34 +5603,25 @@ let isCommutable = 0 in {
WriteVecALU>, VEX_4V, VEX_L;
defm VPSIGNDY : SS3I_binop_rm_int_y<0x0A, "vpsignd", int_x86_avx2_psign_d,
WriteVecALU>, VEX_4V, VEX_L;
- defm VPSHUFBY : SS3I_binop_rm<0x00, "vpshufb", X86pshufb, v32i8, VR256,
- loadv4i64, i256mem,
- SSE_PSHUFB, 0>, VEX_4V, VEX_L;
defm VPHADDSW : SS3I_binop_rm_int_y<0x03, "vphaddsw",
int_x86_avx2_phadd_sw,
WriteVecALU>, VEX_4V, VEX_L;
defm VPHSUBSW : SS3I_binop_rm_int_y<0x07, "vphsubsw",
int_x86_avx2_phsub_sw,
WriteVecALU>, VEX_4V, VEX_L;
- defm VPMADDUBSW : SS3I_binop_rm_int_y<0x04, "vpmaddubsw",
- int_x86_avx2_pmadd_ub_sw,
- WriteVecIMul>, VEX_4V, VEX_L;
}
-defm VPMULHRSW : SS3I_binop_rm_int_y<0x0B, "vpmulhrsw",
- int_x86_avx2_pmul_hr_sw,
- WriteVecIMul>, VEX_4V, VEX_L;
}
// None of these have i8 immediate fields.
let ImmT = NoImm, Constraints = "$src1 = $dst" in {
let isCommutable = 0 in {
- defm PHADDW : SS3I_binop_rm<0x01, "phaddw", X86hadd, v8i16, VR128,
+ defm PHADDW : SS3I_binop_rm<0x01, "phaddw", X86hadd, v8i16, v8i16, VR128,
memopv2i64, i128mem, SSE_PHADDSUBW>;
- defm PHADDD : SS3I_binop_rm<0x02, "phaddd", X86hadd, v4i32, VR128,
+ defm PHADDD : SS3I_binop_rm<0x02, "phaddd", X86hadd, v4i32, v4i32, VR128,
memopv2i64, i128mem, SSE_PHADDSUBD>;
- defm PHSUBW : SS3I_binop_rm<0x05, "phsubw", X86hsub, v8i16, VR128,
+ defm PHSUBW : SS3I_binop_rm<0x05, "phsubw", X86hsub, v8i16, v8i16, VR128,
memopv2i64, i128mem, SSE_PHADDSUBW>;
- defm PHSUBD : SS3I_binop_rm<0x06, "phsubd", X86hsub, v4i32, VR128,
+ defm PHSUBD : SS3I_binop_rm<0x06, "phsubd", X86hsub, v4i32, v4i32, VR128,
memopv2i64, i128mem, SSE_PHADDSUBD>;
defm PSIGNB : SS3I_binop_rm_int<0x08, "psignb", int_x86_ssse3_psign_b_128,
SSE_PSIGN, memopv2i64>;
@@ -5664,7 +5629,7 @@ let isCommutable = 0 in {
SSE_PSIGN, memopv2i64>;
defm PSIGND : SS3I_binop_rm_int<0x0A, "psignd", int_x86_ssse3_psign_d_128,
SSE_PSIGN, memopv2i64>;
- defm PSHUFB : SS3I_binop_rm<0x00, "pshufb", X86pshufb, v16i8, VR128,
+ defm PSHUFB : SS3I_binop_rm<0x00, "pshufb", X86pshufb, v16i8, v16i8, VR128,
memopv2i64, i128mem, SSE_PSHUFB>;
defm PHADDSW : SS3I_binop_rm_int<0x03, "phaddsw",
int_x86_ssse3_phadd_sw_128,
@@ -5672,13 +5637,12 @@ let isCommutable = 0 in {
defm PHSUBSW : SS3I_binop_rm_int<0x07, "phsubsw",
int_x86_ssse3_phsub_sw_128,
SSE_PHADDSUBSW, memopv2i64>;
- defm PMADDUBSW : SS3I_binop_rm_int<0x04, "pmaddubsw",
- int_x86_ssse3_pmadd_ub_sw_128,
- SSE_PMADD, memopv2i64>;
+ defm PMADDUBSW : SS3I_binop_rm<0x04, "pmaddubsw", X86vpmaddubsw, v8i16,
+ v16i8, VR128, memopv2i64, i128mem,
+ SSE_PMADD>;
}
-defm PMULHRSW : SS3I_binop_rm_int<0x0B, "pmulhrsw",
- int_x86_ssse3_pmul_hr_sw_128,
- SSE_PMULHRSW, memopv2i64>;
+defm PMULHRSW : SS3I_binop_rm<0x0B, "pmulhrsw", X86mulhrs, v8i16, v8i16,
+ VR128, memopv2i64, i128mem, SSE_PMULHRSW>;
}
//===---------------------------------------------------------------------===//
@@ -5895,8 +5859,6 @@ multiclass SS41I_pmovx_avx2_patterns<string OpcPrefix, string ExtTy, SDNode ExtO
(!cast<I>(OpcPrefix#BWYrm) addr:$src)>;
def : Pat<(v16i16 (ExtOp (v16i8 (vzload_v2i64 addr:$src)))),
(!cast<I>(OpcPrefix#BWYrm) addr:$src)>;
- def : Pat<(v16i16 (ExtOp (bc_v16i8 (loadv2i64 addr:$src)))),
- (!cast<I>(OpcPrefix#BWYrm) addr:$src)>;
}
let Predicates = [HasAVX, NoVLX] in {
def : Pat<(v8i32 (ExtOp (bc_v16i8 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
@@ -5923,8 +5885,6 @@ multiclass SS41I_pmovx_avx2_patterns<string OpcPrefix, string ExtTy, SDNode ExtO
(!cast<I>(OpcPrefix#WDYrm) addr:$src)>;
def : Pat<(v8i32 (ExtOp (v8i16 (vzload_v2i64 addr:$src)))),
(!cast<I>(OpcPrefix#WDYrm) addr:$src)>;
- def : Pat<(v8i32 (ExtOp (bc_v8i16 (loadv2i64 addr:$src)))),
- (!cast<I>(OpcPrefix#WDYrm) addr:$src)>;
def : Pat<(v4i64 (ExtOp (bc_v8i16 (v2i64 (scalar_to_vector (loadi64 addr:$src)))))),
(!cast<I>(OpcPrefix#WQYrm) addr:$src)>;
@@ -5941,8 +5901,6 @@ multiclass SS41I_pmovx_avx2_patterns<string OpcPrefix, string ExtTy, SDNode ExtO
(!cast<I>(OpcPrefix#DQYrm) addr:$src)>;
def : Pat<(v4i64 (ExtOp (v4i32 (vzload_v2i64 addr:$src)))),
(!cast<I>(OpcPrefix#DQYrm) addr:$src)>;
- def : Pat<(v4i64 (ExtOp (bc_v4i32 (loadv2i64 addr:$src)))),
- (!cast<I>(OpcPrefix#DQYrm) addr:$src)>;
}
}
@@ -6342,10 +6300,10 @@ let Predicates = [UseAVX] in {
// SSE4.1 - Round Instructions
//===----------------------------------------------------------------------===//
-multiclass sse41_fp_unop_rm<bits<8> opcps, bits<8> opcpd, string OpcodeStr,
- X86MemOperand x86memop, RegisterClass RC,
- PatFrag mem_frag32, PatFrag mem_frag64,
- Intrinsic V4F32Int, Intrinsic V2F64Int> {
+multiclass sse41_fp_unop_p<bits<8> opcps, bits<8> opcpd, string OpcodeStr,
+ X86MemOperand x86memop, RegisterClass RC,
+ PatFrag mem_frag32, PatFrag mem_frag64,
+ Intrinsic V4F32Int, Intrinsic V2F64Int> {
let ExeDomain = SSEPackedSingle in {
// Intrinsic operation, reg.
// Vector intrinsic operation, reg
@@ -6386,24 +6344,73 @@ let ExeDomain = SSEPackedDouble in {
} // ExeDomain = SSEPackedDouble
}
-multiclass sse41_fp_binop_rm<bits<8> opcss, bits<8> opcsd,
- string OpcodeStr,
- Intrinsic F32Int,
- Intrinsic F64Int, bit Is2Addr = 1> {
-let ExeDomain = GenericDomain in {
- // Operation, reg.
- let hasSideEffects = 0 in
+multiclass avx_fp_unop_rm<bits<8> opcss, bits<8> opcsd,
+ string OpcodeStr> {
+let ExeDomain = GenericDomain, hasSideEffects = 0 in {
def SSr : SS4AIi8<opcss, MRMSrcReg,
- (outs FR32:$dst), (ins FR32:$src1, FR32:$src2, i32u8imm:$src3),
- !if(Is2Addr,
- !strconcat(OpcodeStr,
- "ss\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
- !strconcat(OpcodeStr,
- "ss\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
+ (outs FR32:$dst), (ins FR32:$src1, FR32:$src2, i32u8imm:$src3),
+ !strconcat(OpcodeStr,
+ "ss\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[]>, Sched<[WriteFAdd]>;
- // Intrinsic operation, reg.
- let isCodeGenOnly = 1 in
+ let mayLoad = 1 in
+ def SSm : SS4AIi8<opcss, MRMSrcMem,
+ (outs FR32:$dst), (ins FR32:$src1, f32mem:$src2, i32u8imm:$src3),
+ !strconcat(OpcodeStr,
+ "ss\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
+ []>, Sched<[WriteFAddLd, ReadAfterLd]>;
+
+ def SDr : SS4AIi8<opcsd, MRMSrcReg,
+ (outs FR64:$dst), (ins FR64:$src1, FR64:$src2, i32u8imm:$src3),
+ !strconcat(OpcodeStr,
+ "sd\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
+ []>, Sched<[WriteFAdd]>;
+
+ let mayLoad = 1 in
+ def SDm : SS4AIi8<opcsd, MRMSrcMem,
+ (outs FR64:$dst), (ins FR64:$src1, f64mem:$src2, i32u8imm:$src3),
+ !strconcat(OpcodeStr,
+ "sd\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
+ []>, Sched<[WriteFAddLd, ReadAfterLd]>;
+} // ExeDomain = GenericDomain, hasSideEffects = 0
+}
+
+multiclass sse41_fp_unop_s<bits<8> opcss, bits<8> opcsd,
+ string OpcodeStr> {
+let ExeDomain = GenericDomain, hasSideEffects = 0 in {
+ def SSr : SS4AIi8<opcss, MRMSrcReg,
+ (outs FR32:$dst), (ins FR32:$src1, i32u8imm:$src2),
+ !strconcat(OpcodeStr,
+ "ss\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+ []>, Sched<[WriteFAdd]>;
+
+ let mayLoad = 1 in
+ def SSm : SS4AIi8<opcss, MRMSrcMem,
+ (outs FR32:$dst), (ins f32mem:$src1, i32u8imm:$src2),
+ !strconcat(OpcodeStr,
+ "ss\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+ []>, Sched<[WriteFAddLd, ReadAfterLd]>;
+
+ def SDr : SS4AIi8<opcsd, MRMSrcReg,
+ (outs FR64:$dst), (ins FR64:$src1, i32u8imm:$src2),
+ !strconcat(OpcodeStr,
+ "sd\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+ []>, Sched<[WriteFAdd]>;
+
+ let mayLoad = 1 in
+ def SDm : SS4AIi8<opcsd, MRMSrcMem,
+ (outs FR64:$dst), (ins f64mem:$src1, i32u8imm:$src2),
+ !strconcat(OpcodeStr,
+ "sd\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+ []>, Sched<[WriteFAddLd, ReadAfterLd]>;
+} // ExeDomain = GenericDomain, hasSideEffects = 0
+}
+
+multiclass sse41_fp_binop_s<bits<8> opcss, bits<8> opcsd,
+ string OpcodeStr,
+ Intrinsic F32Int,
+ Intrinsic F64Int, bit Is2Addr = 1> {
+let ExeDomain = GenericDomain, isCodeGenOnly = 1 in {
def SSr_Int : SS4AIi8<opcss, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2, i32u8imm:$src3),
!if(Is2Addr,
@@ -6414,8 +6421,7 @@ let ExeDomain = GenericDomain in {
[(set VR128:$dst, (F32Int VR128:$src1, VR128:$src2, imm:$src3))]>,
Sched<[WriteFAdd]>;
- // Intrinsic operation, mem.
- def SSm : SS4AIi8<opcss, MRMSrcMem,
+ def SSm_Int : SS4AIi8<opcss, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, ssmem:$src2, i32u8imm:$src3),
!if(Is2Addr,
!strconcat(OpcodeStr,
@@ -6426,19 +6432,6 @@ let ExeDomain = GenericDomain in {
(F32Int VR128:$src1, sse_load_f32:$src2, imm:$src3))]>,
Sched<[WriteFAddLd, ReadAfterLd]>;
- // Operation, reg.
- let hasSideEffects = 0 in
- def SDr : SS4AIi8<opcsd, MRMSrcReg,
- (outs FR64:$dst), (ins FR64:$src1, FR64:$src2, i32u8imm:$src3),
- !if(Is2Addr,
- !strconcat(OpcodeStr,
- "sd\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
- !strconcat(OpcodeStr,
- "sd\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
- []>, Sched<[WriteFAdd]>;
-
- // Intrinsic operation, reg.
- let isCodeGenOnly = 1 in
def SDr_Int : SS4AIi8<opcsd, MRMSrcReg,
(outs VR128:$dst), (ins VR128:$src1, VR128:$src2, i32u8imm:$src3),
!if(Is2Addr,
@@ -6449,8 +6442,7 @@ let ExeDomain = GenericDomain in {
[(set VR128:$dst, (F64Int VR128:$src1, VR128:$src2, imm:$src3))]>,
Sched<[WriteFAdd]>;
- // Intrinsic operation, mem.
- def SDm : SS4AIi8<opcsd, MRMSrcMem,
+ def SDm_Int : SS4AIi8<opcsd, MRMSrcMem,
(outs VR128:$dst), (ins VR128:$src1, sdmem:$src2, i32u8imm:$src3),
!if(Is2Addr,
!strconcat(OpcodeStr,
@@ -6460,23 +6452,24 @@ let ExeDomain = GenericDomain in {
[(set VR128:$dst,
(F64Int VR128:$src1, sse_load_f64:$src2, imm:$src3))]>,
Sched<[WriteFAddLd, ReadAfterLd]>;
-} // ExeDomain = GenericDomain
+} // ExeDomain = GenericDomain, isCodeGenOnly = 1
}
// FP round - roundss, roundps, roundsd, roundpd
let Predicates = [HasAVX] in {
// Intrinsic form
- defm VROUND : sse41_fp_unop_rm<0x08, 0x09, "vround", f128mem, VR128,
- loadv4f32, loadv2f64,
- int_x86_sse41_round_ps,
- int_x86_sse41_round_pd>, VEX;
- defm VROUNDY : sse41_fp_unop_rm<0x08, 0x09, "vround", f256mem, VR256,
- loadv8f32, loadv4f64,
- int_x86_avx_round_ps_256,
- int_x86_avx_round_pd_256>, VEX, VEX_L;
- defm VROUND : sse41_fp_binop_rm<0x0A, 0x0B, "vround",
- int_x86_sse41_round_ss,
- int_x86_sse41_round_sd, 0>, VEX_4V, VEX_LIG;
+ defm VROUND : sse41_fp_unop_p<0x08, 0x09, "vround", f128mem, VR128,
+ loadv4f32, loadv2f64,
+ int_x86_sse41_round_ps,
+ int_x86_sse41_round_pd>, VEX;
+ defm VROUNDY : sse41_fp_unop_p<0x08, 0x09, "vround", f256mem, VR256,
+ loadv8f32, loadv4f64,
+ int_x86_avx_round_ps_256,
+ int_x86_avx_round_pd_256>, VEX, VEX_L;
+ defm VROUND : sse41_fp_binop_s<0x0A, 0x0B, "vround",
+ int_x86_sse41_round_ss,
+ int_x86_sse41_round_sd, 0>, VEX_4V, VEX_LIG;
+ defm VROUND : avx_fp_unop_rm<0x0A, 0x0B, "vround">, VEX_4V, VEX_LIG;
}
let Predicates = [UseAVX] in {
@@ -6548,34 +6541,37 @@ let Predicates = [HasAVX] in {
(VROUNDYPDr VR256:$src, (i32 0xB))>;
}
-defm ROUND : sse41_fp_unop_rm<0x08, 0x09, "round", f128mem, VR128,
- memopv4f32, memopv2f64,
- int_x86_sse41_round_ps, int_x86_sse41_round_pd>;
+defm ROUND : sse41_fp_unop_p<0x08, 0x09, "round", f128mem, VR128,
+ memopv4f32, memopv2f64, int_x86_sse41_round_ps,
+ int_x86_sse41_round_pd>;
+
+defm ROUND : sse41_fp_unop_s<0x0A, 0x0B, "round">;
+
let Constraints = "$src1 = $dst" in
-defm ROUND : sse41_fp_binop_rm<0x0A, 0x0B, "round",
+defm ROUND : sse41_fp_binop_s<0x0A, 0x0B, "round",
int_x86_sse41_round_ss, int_x86_sse41_round_sd>;
let Predicates = [UseSSE41] in {
def : Pat<(ffloor FR32:$src),
- (ROUNDSSr (f32 (IMPLICIT_DEF)), FR32:$src, (i32 0x9))>;
+ (ROUNDSSr FR32:$src, (i32 0x9))>;
def : Pat<(f64 (ffloor FR64:$src)),
- (ROUNDSDr (f64 (IMPLICIT_DEF)), FR64:$src, (i32 0x9))>;
+ (ROUNDSDr FR64:$src, (i32 0x9))>;
def : Pat<(f32 (fnearbyint FR32:$src)),
- (ROUNDSSr (f32 (IMPLICIT_DEF)), FR32:$src, (i32 0xC))>;
+ (ROUNDSSr FR32:$src, (i32 0xC))>;
def : Pat<(f64 (fnearbyint FR64:$src)),
- (ROUNDSDr (f64 (IMPLICIT_DEF)), FR64:$src, (i32 0xC))>;
+ (ROUNDSDr FR64:$src, (i32 0xC))>;
def : Pat<(f32 (fceil FR32:$src)),
- (ROUNDSSr (f32 (IMPLICIT_DEF)), FR32:$src, (i32 0xA))>;
+ (ROUNDSSr FR32:$src, (i32 0xA))>;
def : Pat<(f64 (fceil FR64:$src)),
- (ROUNDSDr (f64 (IMPLICIT_DEF)), FR64:$src, (i32 0xA))>;
+ (ROUNDSDr FR64:$src, (i32 0xA))>;
def : Pat<(f32 (frint FR32:$src)),
- (ROUNDSSr (f32 (IMPLICIT_DEF)), FR32:$src, (i32 0x4))>;
+ (ROUNDSSr FR32:$src, (i32 0x4))>;
def : Pat<(f64 (frint FR64:$src)),
- (ROUNDSDr (f64 (IMPLICIT_DEF)), FR64:$src, (i32 0x4))>;
+ (ROUNDSDr FR64:$src, (i32 0x4))>;
def : Pat<(f32 (ftrunc FR32:$src)),
- (ROUNDSSr (f32 (IMPLICIT_DEF)), FR32:$src, (i32 0xB))>;
+ (ROUNDSSr FR32:$src, (i32 0xB))>;
def : Pat<(f64 (ftrunc FR64:$src)),
- (ROUNDSDr (f64 (IMPLICIT_DEF)), FR64:$src, (i32 0xB))>;
+ (ROUNDSDr FR64:$src, (i32 0xB))>;
def : Pat<(v4f32 (ffloor VR128:$src)),
(ROUNDPSr VR128:$src, (i32 0x9))>;
@@ -6867,10 +6863,10 @@ let Constraints = "$src1 = $dst" in {
let Predicates = [HasAVX, NoVLX] in {
defm VPMULLD : SS48I_binop_rm<0x40, "vpmulld", mul, v4i32, VR128,
- memopv2i64, i128mem, 0, SSE_PMULLD_ITINS>,
+ loadv2i64, i128mem, 0, SSE_PMULLD_ITINS>,
VEX_4V;
defm VPCMPEQQ : SS48I_binop_rm<0x29, "vpcmpeqq", X86pcmpeq, v2i64, VR128,
- memopv2i64, i128mem, 0, SSE_INTALU_ITINS_P>,
+ loadv2i64, i128mem, 0, SSE_INTALU_ITINS_P>,
VEX_4V;
}
let Predicates = [HasAVX2] in {
@@ -7029,22 +7025,22 @@ multiclass SS41I_quaternary_int_avx<bits<8> opc, string OpcodeStr,
RegisterClass RC, X86MemOperand x86memop,
PatFrag mem_frag, Intrinsic IntId,
X86FoldableSchedWrite Sched> {
- def rr : Ii8<opc, MRMSrcReg, (outs RC:$dst),
+ def rr : Ii8Reg<opc, MRMSrcReg, (outs RC:$dst),
(ins RC:$src1, RC:$src2, RC:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set RC:$dst, (IntId RC:$src1, RC:$src2, RC:$src3))],
- NoItinerary, SSEPackedInt>, TAPD, VEX_4V, VEX_I8IMM,
+ NoItinerary, SSEPackedInt>, TAPD, VEX_4V,
Sched<[Sched]>;
- def rm : Ii8<opc, MRMSrcMem, (outs RC:$dst),
+ def rm : Ii8Reg<opc, MRMSrcMem, (outs RC:$dst),
(ins RC:$src1, x86memop:$src2, RC:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set RC:$dst,
(IntId RC:$src1, (bitconvert (mem_frag addr:$src2)),
RC:$src3))],
- NoItinerary, SSEPackedInt>, TAPD, VEX_4V, VEX_I8IMM,
+ NoItinerary, SSEPackedInt>, TAPD, VEX_4V,
Sched<[Sched.Folded, ReadAfterLd]>;
}
@@ -7139,17 +7135,6 @@ let Predicates = [UseAVX] in {
(VBLENDPDYrri (v4f64 (AVX_SET0)), VR256:$src, (i8 1))>;
}
- def : Pat<(v8f32 (X86vzmovl (insert_subvector undef,
- (v4f32 (scalar_to_vector FR32:$src)), (iPTR 0)))),
- (SUBREG_TO_REG (i32 0),
- (v4f32 (VMOVSSrr (v4f32 (V_SET0)), FR32:$src)),
- sub_xmm)>;
- def : Pat<(v4f64 (X86vzmovl (insert_subvector undef,
- (v2f64 (scalar_to_vector FR64:$src)), (iPTR 0)))),
- (SUBREG_TO_REG (i64 0),
- (v2f64 (VMOVSDrr (v2f64 (V_SET0)), FR64:$src)),
- sub_xmm)>;
-
// These will incur an FP/int domain crossing penalty, but it may be the only
// way without AVX2. Do not add any complexity because we may be able to match
// more optimal patterns defined earlier in this file.
@@ -7744,6 +7729,7 @@ defm : pclmul_alias<"lqlq", 0x00>;
let Predicates = [HasSSE4A] in {
+let ExeDomain = SSEPackedInt in {
let Constraints = "$src = $dst" in {
def EXTRQI : Ii8<0x78, MRMXr, (outs VR128:$dst),
(ins VR128:$src, u8imm:$len, u8imm:$idx),
@@ -7767,6 +7753,7 @@ def INSERTQ : I<0x79, MRMSrcReg, (outs VR128:$dst),
[(set VR128:$dst, (int_x86_sse4a_insertq VR128:$src,
VR128:$mask))]>, XD;
}
+} // ExeDomain = SSEPackedInt
// Non-temporal (unaligned) scalar stores.
let AddedComplexity = 400 in { // Prefer non-temporal versions
@@ -7832,23 +7819,50 @@ let ExeDomain = SSEPackedDouble, Predicates = [HasAVX2, NoVLX] in
def VBROADCASTSDYrr : avx2_broadcast_rr<0x19, "vbroadcastsd", VR256,
v4f64, v2f64, WriteFShuffle256>, VEX_L;
+//===----------------------------------------------------------------------===//
+// VBROADCAST*128 - Load from memory and broadcast 128-bit vector to both
+// halves of a 256-bit vector.
+//
let mayLoad = 1, hasSideEffects = 0, Predicates = [HasAVX2] in
def VBROADCASTI128 : AVX8I<0x5A, MRMSrcMem, (outs VR256:$dst),
(ins i128mem:$src),
"vbroadcasti128\t{$src, $dst|$dst, $src}", []>,
Sched<[WriteLoad]>, VEX, VEX_L;
+let mayLoad = 1, hasSideEffects = 0, Predicates = [HasAVX] in
def VBROADCASTF128 : AVX8I<0x1A, MRMSrcMem, (outs VR256:$dst),
(ins f128mem:$src),
- "vbroadcastf128\t{$src, $dst|$dst, $src}",
- [(set VR256:$dst,
- (int_x86_avx_vbroadcastf128_pd_256 addr:$src))]>,
+ "vbroadcastf128\t{$src, $dst|$dst, $src}", []>,
Sched<[WriteFShuffleLd]>, VEX, VEX_L;
-let Predicates = [HasAVX] in
-def : Pat<(int_x86_avx_vbroadcastf128_ps_256 addr:$src),
+let Predicates = [HasAVX2, NoVLX] in {
+def : Pat<(v4i64 (X86SubVBroadcast (loadv2i64 addr:$src))),
+ (VBROADCASTI128 addr:$src)>;
+def : Pat<(v8i32 (X86SubVBroadcast (bc_v4i32 (loadv2i64 addr:$src)))),
+ (VBROADCASTI128 addr:$src)>;
+def : Pat<(v16i16 (X86SubVBroadcast (bc_v8i16 (loadv2i64 addr:$src)))),
+ (VBROADCASTI128 addr:$src)>;
+def : Pat<(v32i8 (X86SubVBroadcast (bc_v16i8 (loadv2i64 addr:$src)))),
+ (VBROADCASTI128 addr:$src)>;
+}
+
+let Predicates = [HasAVX, NoVLX] in {
+def : Pat<(v4f64 (X86SubVBroadcast (loadv2f64 addr:$src))),
(VBROADCASTF128 addr:$src)>;
+def : Pat<(v8f32 (X86SubVBroadcast (loadv4f32 addr:$src))),
+ (VBROADCASTF128 addr:$src)>;
+}
+let Predicates = [HasAVX1Only] in {
+def : Pat<(v4i64 (X86SubVBroadcast (loadv2i64 addr:$src))),
+ (VBROADCASTF128 addr:$src)>;
+def : Pat<(v8i32 (X86SubVBroadcast (bc_v4i32 (loadv2i64 addr:$src)))),
+ (VBROADCASTF128 addr:$src)>;
+def : Pat<(v16i16 (X86SubVBroadcast (bc_v8i16 (loadv2i64 addr:$src)))),
+ (VBROADCASTF128 addr:$src)>;
+def : Pat<(v32i8 (X86SubVBroadcast (bc_v16i8 (loadv2i64 addr:$src)))),
+ (VBROADCASTF128 addr:$src)>;
+}
//===----------------------------------------------------------------------===//
// VINSERTF128 - Insert packed floating-point values
@@ -7865,63 +7879,29 @@ def VINSERTF128rm : AVXAIi8<0x18, MRMSrcMem, (outs VR256:$dst),
[]>, Sched<[WriteFShuffleLd, ReadAfterLd]>, VEX_4V, VEX_L;
}
-let Predicates = [HasAVX, NoVLX] in {
-def : Pat<(vinsert128_insert:$ins (v8f32 VR256:$src1), (v4f32 VR128:$src2),
- (iPTR imm)),
- (VINSERTF128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v4f64 VR256:$src1), (v2f64 VR128:$src2),
+multiclass vinsert_lowering<string InstrStr, ValueType From, ValueType To,
+ PatFrag memop_frag> {
+ def : Pat<(vinsert128_insert:$ins (To VR256:$src1), (From VR128:$src2),
(iPTR imm)),
- (VINSERTF128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
+ (!cast<Instruction>(InstrStr#rr) VR256:$src1, VR128:$src2,
+ (INSERT_get_vinsert128_imm VR256:$ins))>;
+ def : Pat<(vinsert128_insert:$ins (To VR256:$src1),
+ (From (bitconvert (memop_frag addr:$src2))),
+ (iPTR imm)),
+ (!cast<Instruction>(InstrStr#rm) VR256:$src1, addr:$src2,
+ (INSERT_get_vinsert128_imm VR256:$ins))>;
+}
-def : Pat<(vinsert128_insert:$ins (v8f32 VR256:$src1), (loadv4f32 addr:$src2),
- (iPTR imm)),
- (VINSERTF128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v4f64 VR256:$src1), (loadv2f64 addr:$src2),
- (iPTR imm)),
- (VINSERTF128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
+let Predicates = [HasAVX, NoVLX] in {
+ defm : vinsert_lowering<"VINSERTF128", v4f32, v8f32, loadv4f32>;
+ defm : vinsert_lowering<"VINSERTF128", v2f64, v4f64, loadv2f64>;
}
let Predicates = [HasAVX1Only] in {
-def : Pat<(vinsert128_insert:$ins (v4i64 VR256:$src1), (v2i64 VR128:$src2),
- (iPTR imm)),
- (VINSERTF128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v8i32 VR256:$src1), (v4i32 VR128:$src2),
- (iPTR imm)),
- (VINSERTF128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v32i8 VR256:$src1), (v16i8 VR128:$src2),
- (iPTR imm)),
- (VINSERTF128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v16i16 VR256:$src1), (v8i16 VR128:$src2),
- (iPTR imm)),
- (VINSERTF128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-
-def : Pat<(vinsert128_insert:$ins (v4i64 VR256:$src1), (loadv2i64 addr:$src2),
- (iPTR imm)),
- (VINSERTF128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v8i32 VR256:$src1),
- (bc_v4i32 (loadv2i64 addr:$src2)),
- (iPTR imm)),
- (VINSERTF128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v32i8 VR256:$src1),
- (bc_v16i8 (loadv2i64 addr:$src2)),
- (iPTR imm)),
- (VINSERTF128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v16i16 VR256:$src1),
- (bc_v8i16 (loadv2i64 addr:$src2)),
- (iPTR imm)),
- (VINSERTF128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
+ defm : vinsert_lowering<"VINSERTF128", v2i64, v4i64, loadv2i64>;
+ defm : vinsert_lowering<"VINSERTF128", v4i32, v8i32, loadv2i64>;
+ defm : vinsert_lowering<"VINSERTF128", v8i16, v16i16, loadv2i64>;
+ defm : vinsert_lowering<"VINSERTF128", v16i8, v32i8, loadv2i64>;
}
//===----------------------------------------------------------------------===//
@@ -7939,61 +7919,28 @@ def VEXTRACTF128mr : AVXAIi8<0x19, MRMDestMem, (outs),
[]>, Sched<[WriteStore]>, VEX, VEX_L;
}
+multiclass vextract_lowering<string InstrStr, ValueType From, ValueType To> {
+ def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
+ (To (!cast<Instruction>(InstrStr#rr)
+ (From VR256:$src1),
+ (EXTRACT_get_vextract128_imm VR128:$ext)))>;
+ def : Pat<(store (To (vextract128_extract:$ext (From VR256:$src1),
+ (iPTR imm))), addr:$dst),
+ (!cast<Instruction>(InstrStr#mr) addr:$dst, VR256:$src1,
+ (EXTRACT_get_vextract128_imm VR128:$ext))>;
+}
+
// AVX1 patterns
let Predicates = [HasAVX, NoVLX] in {
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v4f32 (VEXTRACTF128rr
- (v8f32 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v2f64 (VEXTRACTF128rr
- (v4f64 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-
-def : Pat<(store (v4f32 (vextract128_extract:$ext (v8f32 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTF128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v2f64 (vextract128_extract:$ext (v4f64 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTF128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
+ defm : vextract_lowering<"VEXTRACTF128", v8f32, v4f32>;
+ defm : vextract_lowering<"VEXTRACTF128", v4f64, v2f64>;
}
let Predicates = [HasAVX1Only] in {
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v2i64 (VEXTRACTF128rr
- (v4i64 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v4i32 (VEXTRACTF128rr
- (v8i32 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v8i16 (VEXTRACTF128rr
- (v16i16 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v16i8 (VEXTRACTF128rr
- (v32i8 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-
-def : Pat<(store (v2i64 (vextract128_extract:$ext (v4i64 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTF128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v4i32 (vextract128_extract:$ext (v8i32 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTF128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v8i16 (vextract128_extract:$ext (v16i16 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTF128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v16i8 (vextract128_extract:$ext (v32i8 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTF128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
+ defm : vextract_lowering<"VEXTRACTF128", v4i64, v2i64>;
+ defm : vextract_lowering<"VEXTRACTF128", v8i32, v4i32>;
+ defm : vextract_lowering<"VEXTRACTF128", v16i16, v8i16>;
+ defm : vextract_lowering<"VEXTRACTF128", v32i8, v16i8>;
}
//===----------------------------------------------------------------------===//
@@ -8239,7 +8186,7 @@ let Predicates = [HasF16C] in {
}
// Patterns for matching conversions from float to half-float and vice versa.
-let Predicates = [HasF16C] in {
+let Predicates = [HasF16C, NoVLX] in {
// Use MXCSR.RC for rounding instead of explicitly specifying the default
// rounding mode (Nearest-Even, encoded as 0). Both are equivalent in the
// configurations we support (the default). However, falling back to MXCSR is
@@ -8334,7 +8281,7 @@ defm VPBROADCASTD : avx2_broadcast<0x58, "vpbroadcastd", i32mem, loadi32,
defm VPBROADCASTQ : avx2_broadcast<0x59, "vpbroadcastq", i64mem, loadi64,
v2i64, v4i64, NoVLX>;
-let Predicates = [HasAVX2] in {
+let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
// loadi16 is tricky to fold, because !isTypeDesirableForOp, justifiably.
// This means we'll encounter truncated i32 loads; match that here.
def : Pat<(v8i16 (X86VBroadcast (i16 (trunc (i32 (load addr:$src)))))),
@@ -8347,7 +8294,9 @@ let Predicates = [HasAVX2] in {
def : Pat<(v16i16 (X86VBroadcast
(i16 (trunc (i32 (zextloadi16 addr:$src)))))),
(VPBROADCASTWYrm addr:$src)>;
+}
+let Predicates = [HasAVX2] in {
// Provide aliases for broadcast from the same register class that
// automatically does the extract.
def : Pat<(v8f32 (X86VBroadcast (v8f32 VR256:$src))),
@@ -8361,36 +8310,38 @@ let Predicates = [HasAVX2] in {
let Predicates = [HasAVX2, NoVLX] in {
// Provide fallback in case the load node that is used in the patterns above
// is used by additional users, which prevents the pattern selection.
- let AddedComplexity = 20 in {
def : Pat<(v4f32 (X86VBroadcast FR32:$src)),
(VBROADCASTSSrr (COPY_TO_REGCLASS FR32:$src, VR128))>;
def : Pat<(v8f32 (X86VBroadcast FR32:$src)),
(VBROADCASTSSYrr (COPY_TO_REGCLASS FR32:$src, VR128))>;
def : Pat<(v4f64 (X86VBroadcast FR64:$src)),
(VBROADCASTSDYrr (COPY_TO_REGCLASS FR64:$src, VR128))>;
- }
}
-let Predicates = [HasAVX2, NoVLX_Or_NoBWI], AddedComplexity = 20 in {
+let Predicates = [HasAVX2, NoVLX_Or_NoBWI] in {
def : Pat<(v16i8 (X86VBroadcast GR8:$src)),
(VPBROADCASTBrr (COPY_TO_REGCLASS
- (i32 (SUBREG_TO_REG (i32 0), GR8:$src, sub_8bit)),
+ (i32 (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ GR8:$src, sub_8bit)),
VR128))>;
def : Pat<(v32i8 (X86VBroadcast GR8:$src)),
(VPBROADCASTBYrr (COPY_TO_REGCLASS
- (i32 (SUBREG_TO_REG (i32 0), GR8:$src, sub_8bit)),
+ (i32 (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ GR8:$src, sub_8bit)),
VR128))>;
def : Pat<(v8i16 (X86VBroadcast GR16:$src)),
(VPBROADCASTWrr (COPY_TO_REGCLASS
- (i32 (SUBREG_TO_REG (i32 0), GR16:$src, sub_16bit)),
+ (i32 (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ GR16:$src, sub_16bit)),
VR128))>;
def : Pat<(v16i16 (X86VBroadcast GR16:$src)),
(VPBROADCASTWYrr (COPY_TO_REGCLASS
- (i32 (SUBREG_TO_REG (i32 0), GR16:$src, sub_16bit)),
+ (i32 (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ GR16:$src, sub_16bit)),
VR128))>;
}
-let Predicates = [HasAVX2, NoVLX], AddedComplexity = 20 in {
+let Predicates = [HasAVX2, NoVLX] in {
def : Pat<(v4i32 (X86VBroadcast GR32:$src)),
(VBROADCASTSSrr (COPY_TO_REGCLASS GR32:$src, VR128))>;
def : Pat<(v8i32 (X86VBroadcast GR32:$src)),
@@ -8418,13 +8369,13 @@ def : Pat<(v4i32 (X86VBroadcast (loadi32 addr:$src))),
// Provide fallback in case the load node that is used in the patterns above
// is used by additional users, which prevents the pattern selection.
-let Predicates = [HasAVX], AddedComplexity = 20 in {
+let Predicates = [HasAVX, NoVLX] in {
// 128bit broadcasts:
def : Pat<(v2f64 (X86VBroadcast f64:$src)),
(VMOVDDUPrr (COPY_TO_REGCLASS FR64:$src, VR128))>;
}
-let Predicates = [HasAVX, NoVLX], AddedComplexity = 20 in {
+let Predicates = [HasAVX1Only] in {
def : Pat<(v4f32 (X86VBroadcast FR32:$src)),
(VPSHUFDri (COPY_TO_REGCLASS FR32:$src, VR128), 0)>;
def : Pat<(v8f32 (X86VBroadcast FR32:$src)),
@@ -8560,42 +8511,10 @@ def VINSERTI128rm : AVX2AIi8<0x38, MRMSrcMem, (outs VR256:$dst),
}
let Predicates = [HasAVX2, NoVLX] in {
-def : Pat<(vinsert128_insert:$ins (v4i64 VR256:$src1), (v2i64 VR128:$src2),
- (iPTR imm)),
- (VINSERTI128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v8i32 VR256:$src1), (v4i32 VR128:$src2),
- (iPTR imm)),
- (VINSERTI128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v32i8 VR256:$src1), (v16i8 VR128:$src2),
- (iPTR imm)),
- (VINSERTI128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v16i16 VR256:$src1), (v8i16 VR128:$src2),
- (iPTR imm)),
- (VINSERTI128rr VR256:$src1, VR128:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-
-def : Pat<(vinsert128_insert:$ins (v4i64 VR256:$src1), (loadv2i64 addr:$src2),
- (iPTR imm)),
- (VINSERTI128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v8i32 VR256:$src1),
- (bc_v4i32 (loadv2i64 addr:$src2)),
- (iPTR imm)),
- (VINSERTI128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v32i8 VR256:$src1),
- (bc_v16i8 (loadv2i64 addr:$src2)),
- (iPTR imm)),
- (VINSERTI128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
-def : Pat<(vinsert128_insert:$ins (v16i16 VR256:$src1),
- (bc_v8i16 (loadv2i64 addr:$src2)),
- (iPTR imm)),
- (VINSERTI128rm VR256:$src1, addr:$src2,
- (INSERT_get_vinsert128_imm VR256:$ins))>;
+ defm : vinsert_lowering<"VINSERTI128", v2i64, v4i64, loadv2i64>;
+ defm : vinsert_lowering<"VINSERTI128", v4i32, v8i32, loadv2i64>;
+ defm : vinsert_lowering<"VINSERTI128", v8i16, v16i16, loadv2i64>;
+ defm : vinsert_lowering<"VINSERTI128", v16i8, v32i8, loadv2i64>;
}
//===----------------------------------------------------------------------===//
@@ -8612,39 +8531,10 @@ def VEXTRACTI128mr : AVX2AIi8<0x39, MRMDestMem, (outs),
Sched<[WriteStore]>, VEX, VEX_L;
let Predicates = [HasAVX2, NoVLX] in {
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v2i64 (VEXTRACTI128rr
- (v4i64 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v4i32 (VEXTRACTI128rr
- (v8i32 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v8i16 (VEXTRACTI128rr
- (v16i16 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-def : Pat<(vextract128_extract:$ext VR256:$src1, (iPTR imm)),
- (v16i8 (VEXTRACTI128rr
- (v32i8 VR256:$src1),
- (EXTRACT_get_vextract128_imm VR128:$ext)))>;
-
-def : Pat<(store (v2i64 (vextract128_extract:$ext (v4i64 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTI128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v4i32 (vextract128_extract:$ext (v8i32 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTI128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v8i16 (vextract128_extract:$ext (v16i16 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTI128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
-def : Pat<(store (v16i8 (vextract128_extract:$ext (v32i8 VR256:$src1),
- (iPTR imm))), addr:$dst),
- (VEXTRACTI128mr addr:$dst, VR256:$src1,
- (EXTRACT_get_vextract128_imm VR128:$ext))>;
+ defm : vextract_lowering<"VEXTRACTI128", v4i64, v2i64>;
+ defm : vextract_lowering<"VEXTRACTI128", v8i32, v4i32>;
+ defm : vextract_lowering<"VEXTRACTI128", v16i16, v8i16>;
+ defm : vextract_lowering<"VEXTRACTI128", v32i8, v16i8>;
}
//===----------------------------------------------------------------------===//
@@ -8689,12 +8579,12 @@ multiclass maskmov_lowering<string InstrStr, RegisterClass RC, ValueType VT,
def: Pat<(X86mstore addr:$ptr, (MaskVT RC:$mask), (VT RC:$src)),
(!cast<Instruction>(InstrStr#"mr") addr:$ptr, RC:$mask, RC:$src)>;
// masked load
- def: Pat<(VT (masked_load addr:$ptr, (MaskVT RC:$mask), undef)),
+ def: Pat<(VT (X86mload addr:$ptr, (MaskVT RC:$mask), undef)),
(!cast<Instruction>(InstrStr#"rm") RC:$mask, addr:$ptr)>;
- def: Pat<(VT (masked_load addr:$ptr, (MaskVT RC:$mask),
+ def: Pat<(VT (X86mload addr:$ptr, (MaskVT RC:$mask),
(VT (bitconvert (ZeroVT immAllZerosV))))),
(!cast<Instruction>(InstrStr#"rm") RC:$mask, addr:$ptr)>;
- def: Pat<(VT (masked_load addr:$ptr, (MaskVT RC:$mask), (VT RC:$src0))),
+ def: Pat<(VT (X86mload addr:$ptr, (MaskVT RC:$mask), (VT RC:$src0))),
(!cast<Instruction>(BlendStr#"rr")
RC:$src0,
(!cast<Instruction>(InstrStr#"rm") RC:$mask, addr:$ptr),
@@ -8719,6 +8609,51 @@ let Predicates = [HasAVX2] in {
defm : maskmov_lowering<"VPMASKMOVD", VR128, v4i32, v4i32, "VBLENDVPS", v4i32>;
defm : maskmov_lowering<"VPMASKMOVQ", VR128, v2i64, v2i64, "VBLENDVPD", v4i32>;
}
+
+//===----------------------------------------------------------------------===//
+// SubVector Broadcasts
+// Provide fallback in case the load node that is used in the patterns above
+// is used by additional users, which prevents the pattern selection.
+
+let Predicates = [HasAVX2, NoVLX] in {
+def : Pat<(v4i64 (X86SubVBroadcast (v2i64 VR128:$src))),
+ (VINSERTI128rr (INSERT_SUBREG (v4i64 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v2i64 VR128:$src), 1)>;
+def : Pat<(v8i32 (X86SubVBroadcast (v4i32 VR128:$src))),
+ (VINSERTI128rr (INSERT_SUBREG (v8i32 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v4i32 VR128:$src), 1)>;
+def : Pat<(v16i16 (X86SubVBroadcast (v8i16 VR128:$src))),
+ (VINSERTI128rr (INSERT_SUBREG (v16i16 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v8i16 VR128:$src), 1)>;
+def : Pat<(v32i8 (X86SubVBroadcast (v16i8 VR128:$src))),
+ (VINSERTI128rr (INSERT_SUBREG (v32i8 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v16i8 VR128:$src), 1)>;
+}
+
+let Predicates = [HasAVX, NoVLX] in {
+def : Pat<(v4f64 (X86SubVBroadcast (v2f64 VR128:$src))),
+ (VINSERTF128rr (INSERT_SUBREG (v4f64 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v2f64 VR128:$src), 1)>;
+def : Pat<(v8f32 (X86SubVBroadcast (v4f32 VR128:$src))),
+ (VINSERTF128rr (INSERT_SUBREG (v8f32 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v4f32 VR128:$src), 1)>;
+}
+
+let Predicates = [HasAVX1Only] in {
+def : Pat<(v4i64 (X86SubVBroadcast (v2i64 VR128:$src))),
+ (VINSERTF128rr (INSERT_SUBREG (v4i64 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v2i64 VR128:$src), 1)>;
+def : Pat<(v8i32 (X86SubVBroadcast (v4i32 VR128:$src))),
+ (VINSERTF128rr (INSERT_SUBREG (v8i32 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v4i32 VR128:$src), 1)>;
+def : Pat<(v16i16 (X86SubVBroadcast (v8i16 VR128:$src))),
+ (VINSERTF128rr (INSERT_SUBREG (v16i16 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v8i16 VR128:$src), 1)>;
+def : Pat<(v32i8 (X86SubVBroadcast (v16i8 VR128:$src))),
+ (VINSERTF128rr (INSERT_SUBREG (v32i8 (IMPLICIT_DEF)), VR128:$src, sub_xmm),
+ (v16i8 VR128:$src), 1)>;
+}
+
//===----------------------------------------------------------------------===//
// Variable Bit Shifts
//
@@ -8758,23 +8693,35 @@ let Predicates = [HasAVX2, NoVLX] in {
defm VPSRLVD : avx2_var_shift<0x45, "vpsrlvd", srl, v4i32, v8i32>;
defm VPSRLVQ : avx2_var_shift<0x45, "vpsrlvq", srl, v2i64, v4i64>, VEX_W;
defm VPSRAVD : avx2_var_shift<0x46, "vpsravd", sra, v4i32, v8i32>;
- let isCodeGenOnly = 1 in
- defm VPSRAVD_Int : avx2_var_shift<0x46, "vpsravd", X86vsrav, v4i32, v8i32>;
+
+ def : Pat<(v4i32 (X86vsrav VR128:$src1, VR128:$src2)),
+ (VPSRAVDrr VR128:$src1, VR128:$src2)>;
+ def : Pat<(v4i32 (X86vsrav VR128:$src1,
+ (bitconvert (loadv2i64 addr:$src2)))),
+ (VPSRAVDrm VR128:$src1, addr:$src2)>;
+ def : Pat<(v8i32 (X86vsrav VR256:$src1, VR256:$src2)),
+ (VPSRAVDYrr VR256:$src1, VR256:$src2)>;
+ def : Pat<(v8i32 (X86vsrav VR256:$src1,
+ (bitconvert (loadv4i64 addr:$src2)))),
+ (VPSRAVDYrm VR256:$src1, addr:$src2)>;
}
+
+
+
//===----------------------------------------------------------------------===//
// VGATHER - GATHER Operations
multiclass avx2_gather<bits<8> opc, string OpcodeStr, RegisterClass RC256,
X86MemOperand memop128, X86MemOperand memop256> {
- def rm : AVX28I<opc, MRMSrcMem, (outs VR128:$dst, VR128:$mask_wb),
+ def rm : AVX28I<opc, MRMSrcMem4VOp3, (outs VR128:$dst, VR128:$mask_wb),
(ins VR128:$src1, memop128:$src2, VR128:$mask),
!strconcat(OpcodeStr,
"\t{$mask, $src2, $dst|$dst, $src2, $mask}"),
- []>, VEX_4VOp3;
- def Yrm : AVX28I<opc, MRMSrcMem, (outs RC256:$dst, RC256:$mask_wb),
+ []>, VEX;
+ def Yrm : AVX28I<opc, MRMSrcMem4VOp3, (outs RC256:$dst, RC256:$mask_wb),
(ins RC256:$src1, memop256:$src2, RC256:$mask),
!strconcat(OpcodeStr,
"\t{$mask, $src2, $dst|$dst, $src2, $mask}"),
- []>, VEX_4VOp3, VEX_L;
+ []>, VEX, VEX_L;
}
let mayLoad = 1, hasSideEffects = 0, Constraints
diff --git a/contrib/llvm/lib/Target/X86/X86InstrShiftRotate.td b/contrib/llvm/lib/Target/X86/X86InstrShiftRotate.td
index c1df978..e2be735 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrShiftRotate.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrShiftRotate.td
@@ -591,37 +591,38 @@ def ROR64rCL : RI<0xD3, MRM1r, (outs GR64:$dst), (ins GR64:$src1),
def ROR8ri : Ii8<0xC0, MRM1r, (outs GR8 :$dst), (ins GR8 :$src1, u8imm:$src2),
"ror{b}\t{$src2, $dst|$dst, $src2}",
- [(set GR8:$dst, (rotr GR8:$src1, (i8 imm:$src2)))], IIC_SR>;
+ [(set GR8:$dst, (rotr GR8:$src1, (i8 relocImm:$src2)))],
+ IIC_SR>;
def ROR16ri : Ii8<0xC1, MRM1r, (outs GR16:$dst), (ins GR16:$src1, u8imm:$src2),
"ror{w}\t{$src2, $dst|$dst, $src2}",
- [(set GR16:$dst, (rotr GR16:$src1, (i8 imm:$src2)))],
+ [(set GR16:$dst, (rotr GR16:$src1, (i8 relocImm:$src2)))],
IIC_SR>, OpSize16;
def ROR32ri : Ii8<0xC1, MRM1r, (outs GR32:$dst), (ins GR32:$src1, u8imm:$src2),
"ror{l}\t{$src2, $dst|$dst, $src2}",
- [(set GR32:$dst, (rotr GR32:$src1, (i8 imm:$src2)))],
+ [(set GR32:$dst, (rotr GR32:$src1, (i8 relocImm:$src2)))],
IIC_SR>, OpSize32;
def ROR64ri : RIi8<0xC1, MRM1r, (outs GR64:$dst),
(ins GR64:$src1, u8imm:$src2),
"ror{q}\t{$src2, $dst|$dst, $src2}",
- [(set GR64:$dst, (rotr GR64:$src1, (i8 imm:$src2)))],
+ [(set GR64:$dst, (rotr GR64:$src1, (i8 relocImm:$src2)))],
IIC_SR>;
// Rotate by 1
def ROR8r1 : I<0xD0, MRM1r, (outs GR8 :$dst), (ins GR8 :$src1),
"ror{b}\t$dst",
- [(set GR8:$dst, (rotr GR8:$src1, (i8 1)))],
+ [(set GR8:$dst, (rotl GR8:$src1, (i8 7)))],
IIC_SR>;
def ROR16r1 : I<0xD1, MRM1r, (outs GR16:$dst), (ins GR16:$src1),
"ror{w}\t$dst",
- [(set GR16:$dst, (rotr GR16:$src1, (i8 1)))],
+ [(set GR16:$dst, (rotl GR16:$src1, (i8 15)))],
IIC_SR>, OpSize16;
def ROR32r1 : I<0xD1, MRM1r, (outs GR32:$dst), (ins GR32:$src1),
"ror{l}\t$dst",
- [(set GR32:$dst, (rotr GR32:$src1, (i8 1)))],
+ [(set GR32:$dst, (rotl GR32:$src1, (i8 31)))],
IIC_SR>, OpSize32;
def ROR64r1 : RI<0xD1, MRM1r, (outs GR64:$dst), (ins GR64:$src1),
"ror{q}\t$dst",
- [(set GR64:$dst, (rotr GR64:$src1, (i8 1)))],
+ [(set GR64:$dst, (rotl GR64:$src1, (i8 63)))],
IIC_SR>;
} // Constraints = "$src = $dst", SchedRW
@@ -873,19 +874,19 @@ let hasSideEffects = 0 in {
multiclass bmi_shift<string asm, RegisterClass RC, X86MemOperand x86memop> {
let hasSideEffects = 0 in {
- def rr : I<0xF7, MRMSrcReg, (outs RC:$dst), (ins RC:$src1, RC:$src2),
+ def rr : I<0xF7, MRMSrcReg4VOp3, (outs RC:$dst), (ins RC:$src1, RC:$src2),
!strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), []>,
- VEX_4VOp3, Sched<[WriteShift]>;
+ VEX, Sched<[WriteShift]>;
let mayLoad = 1 in
- def rm : I<0xF7, MRMSrcMem, (outs RC:$dst), (ins x86memop:$src1, RC:$src2),
+ def rm : I<0xF7, MRMSrcMem4VOp3,
+ (outs RC:$dst), (ins x86memop:$src1, RC:$src2),
!strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), []>,
- VEX_4VOp3,
- Sched<[WriteShiftLd,
- // x86memop:$src1
- ReadDefault, ReadDefault, ReadDefault, ReadDefault,
- ReadDefault,
- // RC:$src1
- ReadAfterLd]>;
+ VEX, Sched<[WriteShiftLd,
+ // x86memop:$src1
+ ReadDefault, ReadDefault, ReadDefault, ReadDefault,
+ ReadDefault,
+ // RC:$src1
+ ReadAfterLd]>;
}
}
diff --git a/contrib/llvm/lib/Target/X86/X86InstrSystem.td b/contrib/llvm/lib/Target/X86/X86InstrSystem.td
index 6667bd2..9265d64 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrSystem.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrSystem.td
@@ -23,7 +23,7 @@ let Defs = [RAX, RCX, RDX] in
// CPU flow control instructions
-let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in {
+let mayLoad = 1, mayStore = 0, hasSideEffects = 1 in {
def TRAP : I<0x0B, RawFrm, (outs), (ins), "ud2", [(trap)]>, TB;
def UD2B : I<0xB9, RawFrm, (outs), (ins), "ud2b", []>, TB;
}
@@ -481,8 +481,11 @@ let Defs = [EDX, EAX], Uses = [ECX] in
def XGETBV : I<0x01, MRM_D0, (outs), (ins), "xgetbv", []>, TB;
let Uses = [EDX, EAX, ECX] in
- def XSETBV : I<0x01, MRM_D1, (outs), (ins), "xsetbv", []>, TB;
-}
+ def XSETBV : I<0x01, MRM_D1, (outs), (ins),
+ "xsetbv",
+ [(int_x86_xsetbv ECX, EDX, EAX)]>, TB;
+
+} // HasXSAVE
let Uses = [EDX, EAX] in {
let Predicates = [HasXSAVE] in {
diff --git a/contrib/llvm/lib/Target/X86/X86InstrTablesInfo.h b/contrib/llvm/lib/Target/X86/X86InstrTablesInfo.h
new file mode 100755
index 0000000..415a891
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86InstrTablesInfo.h
@@ -0,0 +1,1162 @@
+//===-- X86InstrTablesInfo.h - X86 Instruction Tables -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains related X86 Instruction Information Tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_X86_X86INSTRTABLESINFO_H
+#define LLVM_LIB_TARGET_X86_X86INSTRTABLESINFO_H
+
+using namespace llvm;
+
+struct X86EvexToVexCompressTableEntry {
+ uint16_t EvexOpcode;
+ uint16_t VexOpcode;
+};
+
+
+
+// X86 EVEX encoded instructions that have a VEX 128 encoding
+// (table format: <EVEX opcode, VEX-128 opcode>).
+static const X86EvexToVexCompressTableEntry X86EvexToVex128CompressTable[] = {
+ // EVEX scalar with corresponding VEX.
+ { X86::Int_VCOMISDZrm , X86::Int_VCOMISDrm },
+ { X86::Int_VCOMISDZrr , X86::Int_VCOMISDrr },
+ { X86::Int_VCOMISSZrm , X86::Int_VCOMISSrm },
+ { X86::Int_VCOMISSZrr , X86::Int_VCOMISSrr },
+ { X86::Int_VUCOMISDZrm , X86::Int_VUCOMISDrm },
+ { X86::Int_VUCOMISDZrr , X86::Int_VUCOMISDrr },
+ { X86::Int_VUCOMISSZrm , X86::Int_VUCOMISSrm },
+ { X86::Int_VUCOMISSZrr , X86::Int_VUCOMISSrr },
+ { X86::VADDSDZrm , X86::VADDSDrm },
+ { X86::VADDSDZrm_Int , X86::VADDSDrm_Int },
+ { X86::VADDSDZrr , X86::VADDSDrr },
+ { X86::VADDSDZrr_Int , X86::VADDSDrr_Int },
+ { X86::VADDSSZrm , X86::VADDSSrm },
+ { X86::VADDSSZrm_Int , X86::VADDSSrm_Int },
+ { X86::VADDSSZrr , X86::VADDSSrr },
+ { X86::VADDSSZrr_Int , X86::VADDSSrr_Int },
+ { X86::VCOMISDZrm , X86::VCOMISDrm },
+ { X86::VCOMISDZrr , X86::VCOMISDrr },
+ { X86::VCOMISSZrm , X86::VCOMISSrm },
+ { X86::VCOMISSZrr , X86::VCOMISSrr },
+ { X86::VCVTSD2SI64Zrm , X86::VCVTSD2SI64rm },
+ { X86::VCVTSD2SI64Zrr , X86::VCVTSD2SI64rr },
+ { X86::VCVTSD2SIZrm , X86::VCVTSD2SIrm },
+ { X86::VCVTSD2SIZrr , X86::VCVTSD2SIrr },
+ { X86::VCVTSD2SSZrm , X86::VCVTSD2SSrm },
+ { X86::VCVTSD2SSZrr , X86::VCVTSD2SSrr },
+ { X86::VCVTSI2SDZrm , X86::VCVTSI2SDrm },
+ { X86::VCVTSI2SDZrm_Int , X86::Int_VCVTSI2SDrm },
+ { X86::VCVTSI2SDZrr , X86::VCVTSI2SDrr },
+ { X86::VCVTSI2SDZrr_Int , X86::Int_VCVTSI2SDrr },
+ { X86::VCVTSI2SSZrm , X86::VCVTSI2SSrm },
+ { X86::VCVTSI2SSZrm_Int , X86::Int_VCVTSI2SSrm },
+ { X86::VCVTSI2SSZrr , X86::VCVTSI2SSrr },
+ { X86::VCVTSI2SSZrr_Int , X86::Int_VCVTSI2SSrr },
+ { X86::VCVTSS2SDZrm , X86::VCVTSS2SDrm },
+ { X86::VCVTSS2SDZrr , X86::VCVTSS2SDrr },
+ { X86::VCVTSS2SI64Zrm , X86::VCVTSS2SI64rm },
+ { X86::VCVTSS2SI64Zrr , X86::VCVTSS2SI64rr },
+ { X86::VCVTSS2SIZrm , X86::VCVTSS2SIrm },
+ { X86::VCVTSS2SIZrr , X86::VCVTSS2SIrr },
+ { X86::VCVTTSD2SI64Zrm , X86::VCVTTSD2SI64rm },
+ { X86::VCVTTSD2SI64Zrm_Int , X86::Int_VCVTTSD2SI64rm },
+ { X86::VCVTTSD2SI64Zrr , X86::VCVTTSD2SI64rr },
+ { X86::VCVTTSD2SI64Zrr_Int , X86::Int_VCVTTSD2SI64rr },
+ { X86::VCVTTSD2SIZrm , X86::VCVTTSD2SIrm },
+ { X86::VCVTTSD2SIZrm_Int , X86::Int_VCVTTSD2SIrm },
+ { X86::VCVTTSD2SIZrr , X86::VCVTTSD2SIrr },
+ { X86::VCVTTSD2SIZrr_Int , X86::Int_VCVTTSD2SIrr },
+ { X86::VCVTTSS2SI64Zrm , X86::VCVTTSS2SI64rm },
+ { X86::VCVTTSS2SI64Zrm_Int , X86::Int_VCVTTSS2SI64rm },
+ { X86::VCVTTSS2SI64Zrr , X86::VCVTTSS2SI64rr },
+ { X86::VCVTTSS2SI64Zrr_Int , X86::Int_VCVTTSS2SI64rr },
+ { X86::VCVTTSS2SIZrm , X86::VCVTTSS2SIrm },
+ { X86::VCVTTSS2SIZrm_Int , X86::Int_VCVTTSS2SIrm },
+ { X86::VCVTTSS2SIZrr , X86::VCVTTSS2SIrr },
+ { X86::VCVTTSS2SIZrr_Int , X86::Int_VCVTTSS2SIrr },
+ { X86::VDIVSDZrm , X86::VDIVSDrm },
+ { X86::VDIVSDZrm_Int , X86::VDIVSDrm_Int },
+ { X86::VDIVSDZrr , X86::VDIVSDrr },
+ { X86::VDIVSDZrr_Int , X86::VDIVSDrr_Int },
+ { X86::VDIVSSZrm , X86::VDIVSSrm },
+ { X86::VDIVSSZrm_Int , X86::VDIVSSrm_Int },
+ { X86::VDIVSSZrr , X86::VDIVSSrr },
+ { X86::VDIVSSZrr_Int , X86::VDIVSSrr_Int },
+ { X86::VFMADD132SDZm , X86::VFMADD132SDm },
+ { X86::VFMADD132SDZm_Int , X86::VFMADD132SDm_Int },
+ { X86::VFMADD132SDZr , X86::VFMADD132SDr },
+ { X86::VFMADD132SDZr_Int , X86::VFMADD132SDr_Int },
+ { X86::VFMADD132SSZm , X86::VFMADD132SSm },
+ { X86::VFMADD132SSZm_Int , X86::VFMADD132SSm_Int },
+ { X86::VFMADD132SSZr , X86::VFMADD132SSr },
+ { X86::VFMADD132SSZr_Int , X86::VFMADD132SSr_Int },
+ { X86::VFMADD213SDZm , X86::VFMADD213SDm },
+ { X86::VFMADD213SDZm_Int , X86::VFMADD213SDm_Int },
+ { X86::VFMADD213SDZr , X86::VFMADD213SDr },
+ { X86::VFMADD213SDZr_Int , X86::VFMADD213SDr_Int },
+ { X86::VFMADD213SSZm , X86::VFMADD213SSm },
+ { X86::VFMADD213SSZm_Int , X86::VFMADD213SSm_Int },
+ { X86::VFMADD213SSZr , X86::VFMADD213SSr },
+ { X86::VFMADD213SSZr_Int , X86::VFMADD213SSr_Int },
+ { X86::VFMADD231SDZm , X86::VFMADD231SDm },
+ { X86::VFMADD231SDZm_Int , X86::VFMADD231SDm_Int },
+ { X86::VFMADD231SDZr , X86::VFMADD231SDr },
+ { X86::VFMADD231SDZr_Int , X86::VFMADD231SDr_Int },
+ { X86::VFMADD231SSZm , X86::VFMADD231SSm },
+ { X86::VFMADD231SSZm_Int , X86::VFMADD231SSm_Int },
+ { X86::VFMADD231SSZr , X86::VFMADD231SSr },
+ { X86::VFMADD231SSZr_Int , X86::VFMADD231SSr_Int },
+ { X86::VFMSUB132SDZm , X86::VFMSUB132SDm },
+ { X86::VFMSUB132SDZm_Int , X86::VFMSUB132SDm_Int },
+ { X86::VFMSUB132SDZr , X86::VFMSUB132SDr },
+ { X86::VFMSUB132SDZr_Int , X86::VFMSUB132SDr_Int },
+ { X86::VFMSUB132SSZm , X86::VFMSUB132SSm },
+ { X86::VFMSUB132SSZm_Int , X86::VFMSUB132SSm_Int },
+ { X86::VFMSUB132SSZr , X86::VFMSUB132SSr },
+ { X86::VFMSUB132SSZr_Int , X86::VFMSUB132SSr_Int },
+ { X86::VFMSUB213SDZm , X86::VFMSUB213SDm },
+ { X86::VFMSUB213SDZm_Int , X86::VFMSUB213SDm_Int },
+ { X86::VFMSUB213SDZr , X86::VFMSUB213SDr },
+ { X86::VFMSUB213SDZr_Int , X86::VFMSUB213SDr_Int },
+ { X86::VFMSUB213SSZm , X86::VFMSUB213SSm },
+ { X86::VFMSUB213SSZm_Int , X86::VFMSUB213SSm_Int },
+ { X86::VFMSUB213SSZr , X86::VFMSUB213SSr },
+ { X86::VFMSUB213SSZr_Int , X86::VFMSUB213SSr_Int },
+ { X86::VFMSUB231SDZm , X86::VFMSUB231SDm },
+ { X86::VFMSUB231SDZm_Int , X86::VFMSUB231SDm_Int },
+ { X86::VFMSUB231SDZr , X86::VFMSUB231SDr },
+ { X86::VFMSUB231SDZr_Int , X86::VFMSUB231SDr_Int },
+ { X86::VFMSUB231SSZm , X86::VFMSUB231SSm },
+ { X86::VFMSUB231SSZm_Int , X86::VFMSUB231SSm_Int },
+ { X86::VFMSUB231SSZr , X86::VFMSUB231SSr },
+ { X86::VFMSUB231SSZr_Int , X86::VFMSUB231SSr_Int },
+ { X86::VFNMADD132SDZm , X86::VFNMADD132SDm },
+ { X86::VFNMADD132SDZm_Int , X86::VFNMADD132SDm_Int },
+ { X86::VFNMADD132SDZr , X86::VFNMADD132SDr },
+ { X86::VFNMADD132SDZr_Int , X86::VFNMADD132SDr_Int },
+ { X86::VFNMADD132SSZm , X86::VFNMADD132SSm },
+ { X86::VFNMADD132SSZm_Int , X86::VFNMADD132SSm_Int },
+ { X86::VFNMADD132SSZr , X86::VFNMADD132SSr },
+ { X86::VFNMADD132SSZr_Int , X86::VFNMADD132SSr_Int },
+ { X86::VFNMADD213SDZm , X86::VFNMADD213SDm },
+ { X86::VFNMADD213SDZm_Int , X86::VFNMADD213SDm_Int },
+ { X86::VFNMADD213SDZr , X86::VFNMADD213SDr },
+ { X86::VFNMADD213SDZr_Int , X86::VFNMADD213SDr_Int },
+ { X86::VFNMADD213SSZm , X86::VFNMADD213SSm },
+ { X86::VFNMADD213SSZm_Int , X86::VFNMADD213SSm_Int },
+ { X86::VFNMADD213SSZr , X86::VFNMADD213SSr },
+ { X86::VFNMADD213SSZr_Int , X86::VFNMADD213SSr_Int },
+ { X86::VFNMADD231SDZm , X86::VFNMADD231SDm },
+ { X86::VFNMADD231SDZm_Int , X86::VFNMADD231SDm_Int },
+ { X86::VFNMADD231SDZr , X86::VFNMADD231SDr },
+ { X86::VFNMADD231SDZr_Int , X86::VFNMADD231SDr_Int },
+ { X86::VFNMADD231SSZm , X86::VFNMADD231SSm },
+ { X86::VFNMADD231SSZm_Int , X86::VFNMADD231SSm_Int },
+ { X86::VFNMADD231SSZr , X86::VFNMADD231SSr },
+ { X86::VFNMADD231SSZr_Int , X86::VFNMADD231SSr_Int },
+ { X86::VFNMSUB132SDZm , X86::VFNMSUB132SDm },
+ { X86::VFNMSUB132SDZm_Int , X86::VFNMSUB132SDm_Int },
+ { X86::VFNMSUB132SDZr , X86::VFNMSUB132SDr },
+ { X86::VFNMSUB132SDZr_Int , X86::VFNMSUB132SDr_Int },
+ { X86::VFNMSUB132SSZm , X86::VFNMSUB132SSm },
+ { X86::VFNMSUB132SSZm_Int , X86::VFNMSUB132SSm_Int },
+ { X86::VFNMSUB132SSZr , X86::VFNMSUB132SSr },
+ { X86::VFNMSUB132SSZr_Int , X86::VFNMSUB132SSr_Int },
+ { X86::VFNMSUB213SDZm , X86::VFNMSUB213SDm },
+ { X86::VFNMSUB213SDZm_Int , X86::VFNMSUB213SDm_Int },
+ { X86::VFNMSUB213SDZr , X86::VFNMSUB213SDr },
+ { X86::VFNMSUB213SDZr_Int , X86::VFNMSUB213SDr_Int },
+ { X86::VFNMSUB213SSZm , X86::VFNMSUB213SSm },
+ { X86::VFNMSUB213SSZm_Int , X86::VFNMSUB213SSm_Int },
+ { X86::VFNMSUB213SSZr , X86::VFNMSUB213SSr },
+ { X86::VFNMSUB213SSZr_Int , X86::VFNMSUB213SSr_Int },
+ { X86::VFNMSUB231SDZm , X86::VFNMSUB231SDm },
+ { X86::VFNMSUB231SDZm_Int , X86::VFNMSUB231SDm_Int },
+ { X86::VFNMSUB231SDZr , X86::VFNMSUB231SDr },
+ { X86::VFNMSUB231SDZr_Int , X86::VFNMSUB231SDr_Int },
+ { X86::VFNMSUB231SSZm , X86::VFNMSUB231SSm },
+ { X86::VFNMSUB231SSZm_Int , X86::VFNMSUB231SSm_Int },
+ { X86::VFNMSUB231SSZr , X86::VFNMSUB231SSr },
+ { X86::VFNMSUB231SSZr_Int , X86::VFNMSUB231SSr_Int },
+ { X86::VMAXCSDZrm , X86::VMAXCSDrm },
+ { X86::VMAXCSDZrr , X86::VMAXCSDrr },
+ { X86::VMAXCSSZrm , X86::VMAXCSSrm },
+ { X86::VMAXCSSZrr , X86::VMAXCSSrr },
+ { X86::VMAXSDZrm , X86::VMAXSDrm },
+ { X86::VMAXSDZrm_Int , X86::VMAXSDrm_Int },
+ { X86::VMAXSDZrr , X86::VMAXSDrr },
+ { X86::VMAXSDZrr_Int , X86::VMAXSDrr_Int },
+ { X86::VMAXSSZrm , X86::VMAXSSrm },
+ { X86::VMAXSSZrm_Int , X86::VMAXSSrm_Int },
+ { X86::VMAXSSZrr , X86::VMAXSSrr },
+ { X86::VMAXSSZrr_Int , X86::VMAXSSrr_Int },
+ { X86::VMINCSDZrm , X86::VMINCSDrm },
+ { X86::VMINCSDZrr , X86::VMINCSDrr },
+ { X86::VMINCSSZrm , X86::VMINCSSrm },
+ { X86::VMINCSSZrr , X86::VMINCSSrr },
+ { X86::VMINSDZrm , X86::VMINSDrm },
+ { X86::VMINSDZrm_Int , X86::VMINSDrm_Int },
+ { X86::VMINSDZrr , X86::VMINSDrr },
+ { X86::VMINSDZrr_Int , X86::VMINSDrr_Int },
+ { X86::VMINSSZrm , X86::VMINSSrm },
+ { X86::VMINSSZrm_Int , X86::VMINSSrm_Int },
+ { X86::VMINSSZrr , X86::VMINSSrr },
+ { X86::VMINSSZrr_Int , X86::VMINSSrr_Int },
+ { X86::VMOV64toSDZrr , X86::VMOV64toSDrr },
+ { X86::VMOVDI2SSZrm , X86::VMOVDI2SSrm },
+ { X86::VMOVDI2SSZrr , X86::VMOVDI2SSrr },
+ { X86::VMOVSDZmr , X86::VMOVSDmr },
+ { X86::VMOVSDZrm , X86::VMOVSDrm },
+ { X86::VMOVSDZrr , X86::VMOVSDrr },
+ { X86::VMOVSSZmr , X86::VMOVSSmr },
+ { X86::VMOVSSZrm , X86::VMOVSSrm },
+ { X86::VMOVSSZrr , X86::VMOVSSrr },
+ { X86::VMOVSSZrr_REV , X86::VMOVSSrr_REV },
+ { X86::VMULSDZrm , X86::VMULSDrm },
+ { X86::VMULSDZrm_Int , X86::VMULSDrm_Int },
+ { X86::VMULSDZrr , X86::VMULSDrr },
+ { X86::VMULSDZrr_Int , X86::VMULSDrr_Int },
+ { X86::VMULSSZrm , X86::VMULSSrm },
+ { X86::VMULSSZrm_Int , X86::VMULSSrm_Int },
+ { X86::VMULSSZrr , X86::VMULSSrr },
+ { X86::VMULSSZrr_Int , X86::VMULSSrr_Int },
+ { X86::VSQRTSDZm , X86::VSQRTSDm },
+ { X86::VSQRTSDZm_Int , X86::VSQRTSDm_Int },
+ { X86::VSQRTSDZr , X86::VSQRTSDr },
+ { X86::VSQRTSDZr_Int , X86::VSQRTSDr_Int },
+ { X86::VSQRTSSZm , X86::VSQRTSSm },
+ { X86::VSQRTSSZm_Int , X86::VSQRTSSm_Int },
+ { X86::VSQRTSSZr , X86::VSQRTSSr },
+ { X86::VSQRTSSZr_Int , X86::VSQRTSSr_Int },
+ { X86::VSUBSDZrm , X86::VSUBSDrm },
+ { X86::VSUBSDZrm_Int , X86::VSUBSDrm_Int },
+ { X86::VSUBSDZrr , X86::VSUBSDrr },
+ { X86::VSUBSDZrr_Int , X86::VSUBSDrr_Int },
+ { X86::VSUBSSZrm , X86::VSUBSSrm },
+ { X86::VSUBSSZrm_Int , X86::VSUBSSrm_Int },
+ { X86::VSUBSSZrr , X86::VSUBSSrr },
+ { X86::VSUBSSZrr_Int , X86::VSUBSSrr_Int },
+ { X86::VUCOMISDZrm , X86::VUCOMISDrm },
+ { X86::VUCOMISDZrr , X86::VUCOMISDrr },
+ { X86::VUCOMISSZrm , X86::VUCOMISSrm },
+ { X86::VUCOMISSZrr , X86::VUCOMISSrr },
+
+ { X86::VMOV64toPQIZrr , X86::VMOV64toPQIrr },
+ { X86::VMOV64toSDZrr , X86::VMOV64toSDrr },
+ { X86::VMOVDI2PDIZrm , X86::VMOVDI2PDIrm },
+ { X86::VMOVDI2PDIZrr , X86::VMOVDI2PDIrr },
+ { X86::VMOVLHPSZrr , X86::VMOVLHPSrr },
+ { X86::VMOVHLPSZrr , X86::VMOVHLPSrr },
+ { X86::VMOVPDI2DIZmr , X86::VMOVPDI2DImr },
+ { X86::VMOVPDI2DIZrr , X86::VMOVPDI2DIrr },
+ { X86::VMOVPQI2QIZmr , X86::VMOVPQI2QImr },
+ { X86::VMOVPQIto64Zrr , X86::VMOVPQIto64rr },
+ { X86::VMOVQI2PQIZrm , X86::VMOVQI2PQIrm },
+ { X86::VMOVZPQILo2PQIZrr , X86::VMOVZPQILo2PQIrr },
+
+ { X86::VPEXTRBZmr , X86::VPEXTRBmr },
+ { X86::VPEXTRBZrr , X86::VPEXTRBrr },
+ { X86::VPEXTRDZmr , X86::VPEXTRDmr },
+ { X86::VPEXTRDZrr , X86::VPEXTRDrr },
+ { X86::VPEXTRQZmr , X86::VPEXTRQmr },
+ { X86::VPEXTRQZrr , X86::VPEXTRQrr },
+ { X86::VPEXTRWZmr , X86::VPEXTRWmr },
+ { X86::VPEXTRWZrr , X86::VPEXTRWri },
+
+ { X86::VPINSRBZrm , X86::VPINSRBrm },
+ { X86::VPINSRBZrr , X86::VPINSRBrr },
+ { X86::VPINSRDZrm , X86::VPINSRDrm },
+ { X86::VPINSRDZrr , X86::VPINSRDrr },
+ { X86::VPINSRQZrm , X86::VPINSRQrm },
+ { X86::VPINSRQZrr , X86::VPINSRQrr },
+ { X86::VPINSRWZrm , X86::VPINSRWrmi },
+ { X86::VPINSRWZrr , X86::VPINSRWrri },
+
+ // EVEX 128 with corresponding VEX.
+ { X86::VADDPDZ128rm , X86::VADDPDrm },
+ { X86::VADDPDZ128rr , X86::VADDPDrr },
+ { X86::VADDPSZ128rm , X86::VADDPSrm },
+ { X86::VADDPSZ128rr , X86::VADDPSrr },
+ { X86::VANDNPDZ128rm , X86::VANDNPDrm },
+ { X86::VANDNPDZ128rr , X86::VANDNPDrr },
+ { X86::VANDNPSZ128rm , X86::VANDNPSrm },
+ { X86::VANDNPSZ128rr , X86::VANDNPSrr },
+ { X86::VANDPDZ128rm , X86::VANDPDrm },
+ { X86::VANDPDZ128rr , X86::VANDPDrr },
+ { X86::VANDPSZ128rm , X86::VANDPSrm },
+ { X86::VANDPSZ128rr , X86::VANDPSrr },
+ { X86::VBROADCASTSSZ128m , X86::VBROADCASTSSrm },
+ { X86::VBROADCASTSSZ128r , X86::VBROADCASTSSrr },
+ { X86::VBROADCASTSSZ128r_s , X86::VBROADCASTSSrr },
+ { X86::VCVTDQ2PDZ128rm , X86::VCVTDQ2PDrm },
+ { X86::VCVTDQ2PDZ128rr , X86::VCVTDQ2PDrr },
+ { X86::VCVTDQ2PSZ128rm , X86::VCVTDQ2PSrm },
+ { X86::VCVTDQ2PSZ128rr , X86::VCVTDQ2PSrr },
+ { X86::VCVTPD2DQZ128rm , X86::VCVTPD2DQrm },
+ { X86::VCVTPD2DQZ128rr , X86::VCVTPD2DQrr },
+ { X86::VCVTPD2PSZ128rm , X86::VCVTPD2PSrm },
+ { X86::VCVTPD2PSZ128rr , X86::VCVTPD2PSrr },
+ { X86::VCVTPH2PSZ128rm , X86::VCVTPH2PSrm },
+ { X86::VCVTPH2PSZ128rr , X86::VCVTPH2PSrr },
+ { X86::VCVTPS2DQZ128rm , X86::VCVTPS2DQrm },
+ { X86::VCVTPS2DQZ128rr , X86::VCVTPS2DQrr },
+ { X86::VCVTPS2PDZ128rm , X86::VCVTPS2PDrm },
+ { X86::VCVTPS2PDZ128rr , X86::VCVTPS2PDrr },
+ { X86::VCVTPS2PHZ128mr , X86::VCVTPS2PHmr },
+ { X86::VCVTPS2PHZ128rr , X86::VCVTPS2PHrr },
+ { X86::VCVTTPD2DQZ128rm , X86::VCVTTPD2DQrm },
+ { X86::VCVTTPD2DQZ128rr , X86::VCVTTPD2DQrr },
+ { X86::VCVTTPS2DQZ128rm , X86::VCVTTPS2DQrm },
+ { X86::VCVTTPS2DQZ128rr , X86::VCVTTPS2DQrr },
+ { X86::VDIVPDZ128rm , X86::VDIVPDrm },
+ { X86::VDIVPDZ128rr , X86::VDIVPDrr },
+ { X86::VDIVPSZ128rm , X86::VDIVPSrm },
+ { X86::VDIVPSZ128rr , X86::VDIVPSrr },
+ { X86::VFMADD132PDZ128m , X86::VFMADD132PDm },
+ { X86::VFMADD132PDZ128r , X86::VFMADD132PDr },
+ { X86::VFMADD132PSZ128m , X86::VFMADD132PSm },
+ { X86::VFMADD132PSZ128r , X86::VFMADD132PSr },
+ { X86::VFMADD213PDZ128m , X86::VFMADD213PDm },
+ { X86::VFMADD213PDZ128r , X86::VFMADD213PDr },
+ { X86::VFMADD213PSZ128m , X86::VFMADD213PSm },
+ { X86::VFMADD213PSZ128r , X86::VFMADD213PSr },
+ { X86::VFMADD231PDZ128m , X86::VFMADD231PDm },
+ { X86::VFMADD231PDZ128r , X86::VFMADD231PDr },
+ { X86::VFMADD231PSZ128m , X86::VFMADD231PSm },
+ { X86::VFMADD231PSZ128r , X86::VFMADD231PSr },
+ { X86::VFMADDSUB132PDZ128m , X86::VFMADDSUB132PDm },
+ { X86::VFMADDSUB132PDZ128r , X86::VFMADDSUB132PDr },
+ { X86::VFMADDSUB132PSZ128m , X86::VFMADDSUB132PSm },
+ { X86::VFMADDSUB132PSZ128r , X86::VFMADDSUB132PSr },
+ { X86::VFMADDSUB213PDZ128m , X86::VFMADDSUB213PDm },
+ { X86::VFMADDSUB213PDZ128r , X86::VFMADDSUB213PDr },
+ { X86::VFMADDSUB213PSZ128m , X86::VFMADDSUB213PSm },
+ { X86::VFMADDSUB213PSZ128r , X86::VFMADDSUB213PSr },
+ { X86::VFMADDSUB231PDZ128m , X86::VFMADDSUB231PDm },
+ { X86::VFMADDSUB231PDZ128r , X86::VFMADDSUB231PDr },
+ { X86::VFMADDSUB231PSZ128m , X86::VFMADDSUB231PSm },
+ { X86::VFMADDSUB231PSZ128r , X86::VFMADDSUB231PSr },
+ { X86::VFMSUB132PDZ128m , X86::VFMSUB132PDm },
+ { X86::VFMSUB132PDZ128r , X86::VFMSUB132PDr },
+ { X86::VFMSUB132PSZ128m , X86::VFMSUB132PSm },
+ { X86::VFMSUB132PSZ128r , X86::VFMSUB132PSr },
+ { X86::VFMSUB213PDZ128m , X86::VFMSUB213PDm },
+ { X86::VFMSUB213PDZ128r , X86::VFMSUB213PDr },
+ { X86::VFMSUB213PSZ128m , X86::VFMSUB213PSm },
+ { X86::VFMSUB213PSZ128r , X86::VFMSUB213PSr },
+ { X86::VFMSUB231PDZ128m , X86::VFMSUB231PDm },
+ { X86::VFMSUB231PDZ128r , X86::VFMSUB231PDr },
+ { X86::VFMSUB231PSZ128m , X86::VFMSUB231PSm },
+ { X86::VFMSUB231PSZ128r , X86::VFMSUB231PSr },
+ { X86::VFMSUBADD132PDZ128m , X86::VFMSUBADD132PDm },
+ { X86::VFMSUBADD132PDZ128r , X86::VFMSUBADD132PDr },
+ { X86::VFMSUBADD132PSZ128m , X86::VFMSUBADD132PSm },
+ { X86::VFMSUBADD132PSZ128r , X86::VFMSUBADD132PSr },
+ { X86::VFMSUBADD213PDZ128m , X86::VFMSUBADD213PDm },
+ { X86::VFMSUBADD213PDZ128r , X86::VFMSUBADD213PDr },
+ { X86::VFMSUBADD213PSZ128m , X86::VFMSUBADD213PSm },
+ { X86::VFMSUBADD213PSZ128r , X86::VFMSUBADD213PSr },
+ { X86::VFMSUBADD231PDZ128m , X86::VFMSUBADD231PDm },
+ { X86::VFMSUBADD231PDZ128r , X86::VFMSUBADD231PDr },
+ { X86::VFMSUBADD231PSZ128m , X86::VFMSUBADD231PSm },
+ { X86::VFMSUBADD231PSZ128r , X86::VFMSUBADD231PSr },
+ { X86::VFNMADD132PDZ128m , X86::VFNMADD132PDm },
+ { X86::VFNMADD132PDZ128r , X86::VFNMADD132PDr },
+ { X86::VFNMADD132PSZ128m , X86::VFNMADD132PSm },
+ { X86::VFNMADD132PSZ128r , X86::VFNMADD132PSr },
+ { X86::VFNMADD213PDZ128m , X86::VFNMADD213PDm },
+ { X86::VFNMADD213PDZ128r , X86::VFNMADD213PDr },
+ { X86::VFNMADD213PSZ128m , X86::VFNMADD213PSm },
+ { X86::VFNMADD213PSZ128r , X86::VFNMADD213PSr },
+ { X86::VFNMADD231PDZ128m , X86::VFNMADD231PDm },
+ { X86::VFNMADD231PDZ128r , X86::VFNMADD231PDr },
+ { X86::VFNMADD231PSZ128m , X86::VFNMADD231PSm },
+ { X86::VFNMADD231PSZ128r , X86::VFNMADD231PSr },
+ { X86::VFNMSUB132PDZ128m , X86::VFNMSUB132PDm },
+ { X86::VFNMSUB132PDZ128r , X86::VFNMSUB132PDr },
+ { X86::VFNMSUB132PSZ128m , X86::VFNMSUB132PSm },
+ { X86::VFNMSUB132PSZ128r , X86::VFNMSUB132PSr },
+ { X86::VFNMSUB213PDZ128m , X86::VFNMSUB213PDm },
+ { X86::VFNMSUB213PDZ128r , X86::VFNMSUB213PDr },
+ { X86::VFNMSUB213PSZ128m , X86::VFNMSUB213PSm },
+ { X86::VFNMSUB213PSZ128r , X86::VFNMSUB213PSr },
+ { X86::VFNMSUB231PDZ128m , X86::VFNMSUB231PDm },
+ { X86::VFNMSUB231PDZ128r , X86::VFNMSUB231PDr },
+ { X86::VFNMSUB231PSZ128m , X86::VFNMSUB231PSm },
+ { X86::VFNMSUB231PSZ128r , X86::VFNMSUB231PSr },
+ { X86::VMAXCPDZ128rm , X86::VMAXCPDrm },
+ { X86::VMAXCPDZ128rr , X86::VMAXCPDrr },
+ { X86::VMAXCPSZ128rm , X86::VMAXCPSrm },
+ { X86::VMAXCPSZ128rr , X86::VMAXCPSrr },
+ { X86::VMAXPDZ128rm , X86::VMAXPDrm },
+ { X86::VMAXPDZ128rr , X86::VMAXPDrr },
+ { X86::VMAXPSZ128rm , X86::VMAXPSrm },
+ { X86::VMAXPSZ128rr , X86::VMAXPSrr },
+ { X86::VMINCPDZ128rm , X86::VMINCPDrm },
+ { X86::VMINCPDZ128rr , X86::VMINCPDrr },
+ { X86::VMINCPSZ128rm , X86::VMINCPSrm },
+ { X86::VMINCPSZ128rr , X86::VMINCPSrr },
+ { X86::VMINPDZ128rm , X86::VMINPDrm },
+ { X86::VMINPDZ128rr , X86::VMINPDrr },
+ { X86::VMINPSZ128rm , X86::VMINPSrm },
+ { X86::VMINPSZ128rr , X86::VMINPSrr },
+ { X86::VMOVAPDZ128mr , X86::VMOVAPDmr },
+ { X86::VMOVAPDZ128rm , X86::VMOVAPDrm },
+ { X86::VMOVAPDZ128rr , X86::VMOVAPDrr },
+ { X86::VMOVAPDZ128rr_REV , X86::VMOVAPDrr_REV },
+ { X86::VMOVAPSZ128mr , X86::VMOVAPSmr },
+ { X86::VMOVAPSZ128rm , X86::VMOVAPSrm },
+ { X86::VMOVAPSZ128rr , X86::VMOVAPSrr },
+ { X86::VMOVAPSZ128rr_REV , X86::VMOVAPSrr_REV },
+ { X86::VMOVDDUPZ128rm , X86::VMOVDDUPrm },
+ { X86::VMOVDDUPZ128rr , X86::VMOVDDUPrr },
+ { X86::VMOVDQA32Z128mr , X86::VMOVDQAmr },
+ { X86::VMOVDQA32Z128rm , X86::VMOVDQArm },
+ { X86::VMOVDQA32Z128rr , X86::VMOVDQArr },
+ { X86::VMOVDQA32Z128rr_REV , X86::VMOVDQArr_REV },
+ { X86::VMOVDQA64Z128mr , X86::VMOVDQAmr },
+ { X86::VMOVDQA64Z128rm , X86::VMOVDQArm },
+ { X86::VMOVDQA64Z128rr , X86::VMOVDQArr },
+ { X86::VMOVDQA64Z128rr_REV , X86::VMOVDQArr_REV },
+ { X86::VMOVDQU16Z128mr , X86::VMOVDQUmr },
+ { X86::VMOVDQU16Z128rm , X86::VMOVDQUrm },
+ { X86::VMOVDQU16Z128rr , X86::VMOVDQUrr },
+ { X86::VMOVDQU16Z128rr_REV , X86::VMOVDQUrr_REV },
+ { X86::VMOVDQU32Z128mr , X86::VMOVDQUmr },
+ { X86::VMOVDQU32Z128rm , X86::VMOVDQUrm },
+ { X86::VMOVDQU32Z128rr , X86::VMOVDQUrr },
+ { X86::VMOVDQU32Z128rr_REV , X86::VMOVDQUrr_REV },
+ { X86::VMOVDQU64Z128mr , X86::VMOVDQUmr },
+ { X86::VMOVDQU64Z128rm , X86::VMOVDQUrm },
+ { X86::VMOVDQU64Z128rr , X86::VMOVDQUrr },
+ { X86::VMOVDQU64Z128rr_REV , X86::VMOVDQUrr_REV },
+ { X86::VMOVDQU8Z128mr , X86::VMOVDQUmr },
+ { X86::VMOVDQU8Z128rm , X86::VMOVDQUrm },
+ { X86::VMOVDQU8Z128rr , X86::VMOVDQUrr },
+ { X86::VMOVDQU8Z128rr_REV , X86::VMOVDQUrr_REV },
+ { X86::VMOVHPDZ128mr , X86::VMOVHPDmr },
+ { X86::VMOVHPDZ128rm , X86::VMOVHPDrm },
+ { X86::VMOVHPSZ128mr , X86::VMOVHPSmr },
+ { X86::VMOVHPSZ128rm , X86::VMOVHPSrm },
+ { X86::VMOVLPDZ128mr , X86::VMOVLPDmr },
+ { X86::VMOVLPDZ128rm , X86::VMOVLPDrm },
+ { X86::VMOVLPSZ128mr , X86::VMOVLPSmr },
+ { X86::VMOVLPSZ128rm , X86::VMOVLPSrm },
+ { X86::VMOVNTDQAZ128rm , X86::VMOVNTDQArm },
+ { X86::VMOVNTDQZ128mr , X86::VMOVNTDQmr },
+ { X86::VMOVNTPDZ128mr , X86::VMOVNTPDmr },
+ { X86::VMOVNTPSZ128mr , X86::VMOVNTPSmr },
+ { X86::VMOVSHDUPZ128rm , X86::VMOVSHDUPrm },
+ { X86::VMOVSHDUPZ128rr , X86::VMOVSHDUPrr },
+ { X86::VMOVSLDUPZ128rm , X86::VMOVSLDUPrm },
+ { X86::VMOVSLDUPZ128rr , X86::VMOVSLDUPrr },
+ { X86::VMOVUPDZ128mr , X86::VMOVUPDmr },
+ { X86::VMOVUPDZ128rm , X86::VMOVUPDrm },
+ { X86::VMOVUPDZ128rr , X86::VMOVUPDrr },
+ { X86::VMOVUPDZ128rr_REV , X86::VMOVUPDrr_REV },
+ { X86::VMOVUPSZ128mr , X86::VMOVUPSmr },
+ { X86::VMOVUPSZ128rm , X86::VMOVUPSrm },
+ { X86::VMOVUPSZ128rr , X86::VMOVUPSrr },
+ { X86::VMOVUPSZ128rr_REV , X86::VMOVUPSrr_REV },
+ { X86::VMULPDZ128rm , X86::VMULPDrm },
+ { X86::VMULPDZ128rr , X86::VMULPDrr },
+ { X86::VMULPSZ128rm , X86::VMULPSrm },
+ { X86::VMULPSZ128rr , X86::VMULPSrr },
+ { X86::VORPDZ128rm , X86::VORPDrm },
+ { X86::VORPDZ128rr , X86::VORPDrr },
+ { X86::VORPSZ128rm , X86::VORPSrm },
+ { X86::VORPSZ128rr , X86::VORPSrr },
+ { X86::VPABSBZ128rm , X86::VPABSBrm },
+ { X86::VPABSBZ128rr , X86::VPABSBrr },
+ { X86::VPABSDZ128rm , X86::VPABSDrm },
+ { X86::VPABSDZ128rr , X86::VPABSDrr },
+ { X86::VPABSWZ128rm , X86::VPABSWrm },
+ { X86::VPABSWZ128rr , X86::VPABSWrr },
+ { X86::VPACKSSDWZ128rm , X86::VPACKSSDWrm },
+ { X86::VPACKSSDWZ128rr , X86::VPACKSSDWrr },
+ { X86::VPACKSSWBZ128rm , X86::VPACKSSWBrm },
+ { X86::VPACKSSWBZ128rr , X86::VPACKSSWBrr },
+ { X86::VPACKUSDWZ128rm , X86::VPACKUSDWrm },
+ { X86::VPACKUSDWZ128rr , X86::VPACKUSDWrr },
+ { X86::VPACKUSWBZ128rm , X86::VPACKUSWBrm },
+ { X86::VPACKUSWBZ128rr , X86::VPACKUSWBrr },
+ { X86::VPADDBZ128rm , X86::VPADDBrm },
+ { X86::VPADDBZ128rr , X86::VPADDBrr },
+ { X86::VPADDDZ128rm , X86::VPADDDrm },
+ { X86::VPADDDZ128rr , X86::VPADDDrr },
+ { X86::VPADDQZ128rm , X86::VPADDQrm },
+ { X86::VPADDQZ128rr , X86::VPADDQrr },
+ { X86::VPADDSBZ128rm , X86::VPADDSBrm },
+ { X86::VPADDSBZ128rr , X86::VPADDSBrr },
+ { X86::VPADDSWZ128rm , X86::VPADDSWrm },
+ { X86::VPADDSWZ128rr , X86::VPADDSWrr },
+ { X86::VPADDUSBZ128rm , X86::VPADDUSBrm },
+ { X86::VPADDUSBZ128rr , X86::VPADDUSBrr },
+ { X86::VPADDUSWZ128rm , X86::VPADDUSWrm },
+ { X86::VPADDUSWZ128rr , X86::VPADDUSWrr },
+ { X86::VPADDWZ128rm , X86::VPADDWrm },
+ { X86::VPADDWZ128rr , X86::VPADDWrr },
+ { X86::VPALIGNRZ128rmi , X86::VPALIGNRrmi },
+ { X86::VPALIGNRZ128rri , X86::VPALIGNRrri },
+ { X86::VPANDDZ128rm , X86::VPANDrm },
+ { X86::VPANDDZ128rr , X86::VPANDrr },
+ { X86::VPANDQZ128rm , X86::VPANDrm },
+ { X86::VPANDQZ128rr , X86::VPANDrr },
+ { X86::VPAVGBZ128rm , X86::VPAVGBrm },
+ { X86::VPAVGBZ128rr , X86::VPAVGBrr },
+ { X86::VPAVGWZ128rm , X86::VPAVGWrm },
+ { X86::VPAVGWZ128rr , X86::VPAVGWrr },
+ { X86::VPBROADCASTBZ128m , X86::VPBROADCASTBrm },
+ { X86::VPBROADCASTBZ128r , X86::VPBROADCASTBrr },
+ { X86::VPBROADCASTDZ128m , X86::VPBROADCASTDrm },
+ { X86::VPBROADCASTDZ128r , X86::VPBROADCASTDrr },
+ { X86::VPBROADCASTQZ128m , X86::VPBROADCASTQrm },
+ { X86::VPBROADCASTQZ128r , X86::VPBROADCASTQrr },
+ { X86::VPBROADCASTWZ128m , X86::VPBROADCASTWrm },
+ { X86::VPBROADCASTWZ128r , X86::VPBROADCASTWrr },
+ { X86::VPERMILPDZ128mi , X86::VPERMILPDmi },
+ { X86::VPERMILPDZ128ri , X86::VPERMILPDri },
+ { X86::VPERMILPDZ128rm , X86::VPERMILPDrm },
+ { X86::VPERMILPDZ128rr , X86::VPERMILPDrr },
+ { X86::VPERMILPSZ128mi , X86::VPERMILPSmi },
+ { X86::VPERMILPSZ128ri , X86::VPERMILPSri },
+ { X86::VPERMILPSZ128rm , X86::VPERMILPSrm },
+ { X86::VPERMILPSZ128rr , X86::VPERMILPSrr },
+ { X86::VPMADDUBSWZ128rm , X86::VPMADDUBSWrm },
+ { X86::VPMADDUBSWZ128rr , X86::VPMADDUBSWrr },
+ { X86::VPMADDWDZ128rm , X86::VPMADDWDrm },
+ { X86::VPMADDWDZ128rr , X86::VPMADDWDrr },
+ { X86::VPMAXSBZ128rm , X86::VPMAXSBrm },
+ { X86::VPMAXSBZ128rr , X86::VPMAXSBrr },
+ { X86::VPMAXSDZ128rm , X86::VPMAXSDrm },
+ { X86::VPMAXSDZ128rr , X86::VPMAXSDrr },
+ { X86::VPMAXSWZ128rm , X86::VPMAXSWrm },
+ { X86::VPMAXSWZ128rr , X86::VPMAXSWrr },
+ { X86::VPMAXUBZ128rm , X86::VPMAXUBrm },
+ { X86::VPMAXUBZ128rr , X86::VPMAXUBrr },
+ { X86::VPMAXUDZ128rm , X86::VPMAXUDrm },
+ { X86::VPMAXUDZ128rr , X86::VPMAXUDrr },
+ { X86::VPMAXUWZ128rm , X86::VPMAXUWrm },
+ { X86::VPMAXUWZ128rr , X86::VPMAXUWrr },
+ { X86::VPMINSBZ128rm , X86::VPMINSBrm },
+ { X86::VPMINSBZ128rr , X86::VPMINSBrr },
+ { X86::VPMINSDZ128rm , X86::VPMINSDrm },
+ { X86::VPMINSDZ128rr , X86::VPMINSDrr },
+ { X86::VPMINSWZ128rm , X86::VPMINSWrm },
+ { X86::VPMINSWZ128rr , X86::VPMINSWrr },
+ { X86::VPMINUBZ128rm , X86::VPMINUBrm },
+ { X86::VPMINUBZ128rr , X86::VPMINUBrr },
+ { X86::VPMINUDZ128rm , X86::VPMINUDrm },
+ { X86::VPMINUDZ128rr , X86::VPMINUDrr },
+ { X86::VPMINUWZ128rm , X86::VPMINUWrm },
+ { X86::VPMINUWZ128rr , X86::VPMINUWrr },
+ { X86::VPMOVSXBDZ128rm , X86::VPMOVSXBDrm },
+ { X86::VPMOVSXBDZ128rr , X86::VPMOVSXBDrr },
+ { X86::VPMOVSXBQZ128rm , X86::VPMOVSXBQrm },
+ { X86::VPMOVSXBQZ128rr , X86::VPMOVSXBQrr },
+ { X86::VPMOVSXBWZ128rm , X86::VPMOVSXBWrm },
+ { X86::VPMOVSXBWZ128rr , X86::VPMOVSXBWrr },
+ { X86::VPMOVSXDQZ128rm , X86::VPMOVSXDQrm },
+ { X86::VPMOVSXDQZ128rr , X86::VPMOVSXDQrr },
+ { X86::VPMOVSXWDZ128rm , X86::VPMOVSXWDrm },
+ { X86::VPMOVSXWDZ128rr , X86::VPMOVSXWDrr },
+ { X86::VPMOVSXWQZ128rm , X86::VPMOVSXWQrm },
+ { X86::VPMOVSXWQZ128rr , X86::VPMOVSXWQrr },
+ { X86::VPMOVZXBDZ128rm , X86::VPMOVZXBDrm },
+ { X86::VPMOVZXBDZ128rr , X86::VPMOVZXBDrr },
+ { X86::VPMOVZXBQZ128rm , X86::VPMOVZXBQrm },
+ { X86::VPMOVZXBQZ128rr , X86::VPMOVZXBQrr },
+ { X86::VPMOVZXBWZ128rm , X86::VPMOVZXBWrm },
+ { X86::VPMOVZXBWZ128rr , X86::VPMOVZXBWrr },
+ { X86::VPMOVZXDQZ128rm , X86::VPMOVZXDQrm },
+ { X86::VPMOVZXDQZ128rr , X86::VPMOVZXDQrr },
+ { X86::VPMOVZXWDZ128rm , X86::VPMOVZXWDrm },
+ { X86::VPMOVZXWDZ128rr , X86::VPMOVZXWDrr },
+ { X86::VPMOVZXWQZ128rm , X86::VPMOVZXWQrm },
+ { X86::VPMOVZXWQZ128rr , X86::VPMOVZXWQrr },
+ { X86::VPMULDQZ128rm , X86::VPMULDQrm },
+ { X86::VPMULDQZ128rr , X86::VPMULDQrr },
+ { X86::VPMULHRSWZ128rm , X86::VPMULHRSWrm },
+ { X86::VPMULHRSWZ128rr , X86::VPMULHRSWrr },
+ { X86::VPMULHUWZ128rm , X86::VPMULHUWrm },
+ { X86::VPMULHUWZ128rr , X86::VPMULHUWrr },
+ { X86::VPMULHWZ128rm , X86::VPMULHWrm },
+ { X86::VPMULHWZ128rr , X86::VPMULHWrr },
+ { X86::VPMULLDZ128rm , X86::VPMULLDrm },
+ { X86::VPMULLDZ128rr , X86::VPMULLDrr },
+ { X86::VPMULLWZ128rm , X86::VPMULLWrm },
+ { X86::VPMULLWZ128rr , X86::VPMULLWrr },
+ { X86::VPMULUDQZ128rm , X86::VPMULUDQrm },
+ { X86::VPMULUDQZ128rr , X86::VPMULUDQrr },
+ { X86::VPORDZ128rm , X86::VPORrm },
+ { X86::VPORDZ128rr , X86::VPORrr },
+ { X86::VPORQZ128rm , X86::VPORrm },
+ { X86::VPORQZ128rr , X86::VPORrr },
+ { X86::VPSADBWZ128rm , X86::VPSADBWrm },
+ { X86::VPSADBWZ128rr , X86::VPSADBWrr },
+ { X86::VPSHUFBZ128rm , X86::VPSHUFBrm },
+ { X86::VPSHUFBZ128rr , X86::VPSHUFBrr },
+ { X86::VPSHUFDZ128mi , X86::VPSHUFDmi },
+ { X86::VPSHUFDZ128ri , X86::VPSHUFDri },
+ { X86::VPSHUFHWZ128mi , X86::VPSHUFHWmi },
+ { X86::VPSHUFHWZ128ri , X86::VPSHUFHWri },
+ { X86::VPSHUFLWZ128mi , X86::VPSHUFLWmi },
+ { X86::VPSHUFLWZ128ri , X86::VPSHUFLWri },
+ { X86::VPSLLDQZ128rr , X86::VPSLLDQri },
+ { X86::VPSLLDZ128ri , X86::VPSLLDri },
+ { X86::VPSLLDZ128rm , X86::VPSLLDrm },
+ { X86::VPSLLDZ128rr , X86::VPSLLDrr },
+ { X86::VPSLLQZ128ri , X86::VPSLLQri },
+ { X86::VPSLLQZ128rm , X86::VPSLLQrm },
+ { X86::VPSLLQZ128rr , X86::VPSLLQrr },
+ { X86::VPSLLVDZ128rm , X86::VPSLLVDrm },
+ { X86::VPSLLVDZ128rr , X86::VPSLLVDrr },
+ { X86::VPSLLVQZ128rm , X86::VPSLLVQrm },
+ { X86::VPSLLVQZ128rr , X86::VPSLLVQrr },
+ { X86::VPSLLWZ128ri , X86::VPSLLWri },
+ { X86::VPSLLWZ128rm , X86::VPSLLWrm },
+ { X86::VPSLLWZ128rr , X86::VPSLLWrr },
+ { X86::VPSRADZ128ri , X86::VPSRADri },
+ { X86::VPSRADZ128rm , X86::VPSRADrm },
+ { X86::VPSRADZ128rr , X86::VPSRADrr },
+ { X86::VPSRAVDZ128rm , X86::VPSRAVDrm },
+ { X86::VPSRAVDZ128rr , X86::VPSRAVDrr },
+ { X86::VPSRAWZ128ri , X86::VPSRAWri },
+ { X86::VPSRAWZ128rm , X86::VPSRAWrm },
+ { X86::VPSRAWZ128rr , X86::VPSRAWrr },
+ { X86::VPSRLDQZ128rr , X86::VPSRLDQri },
+ { X86::VPSRLDZ128ri , X86::VPSRLDri },
+ { X86::VPSRLDZ128rm , X86::VPSRLDrm },
+ { X86::VPSRLDZ128rr , X86::VPSRLDrr },
+ { X86::VPSRLQZ128ri , X86::VPSRLQri },
+ { X86::VPSRLQZ128rm , X86::VPSRLQrm },
+ { X86::VPSRLQZ128rr , X86::VPSRLQrr },
+ { X86::VPSRLVDZ128rm , X86::VPSRLVDrm },
+ { X86::VPSRLVDZ128rr , X86::VPSRLVDrr },
+ { X86::VPSRLVQZ128rm , X86::VPSRLVQrm },
+ { X86::VPSRLVQZ128rr , X86::VPSRLVQrr },
+ { X86::VPSRLWZ128ri , X86::VPSRLWri },
+ { X86::VPSRLWZ128rm , X86::VPSRLWrm },
+ { X86::VPSRLWZ128rr , X86::VPSRLWrr },
+ { X86::VPSUBBZ128rm , X86::VPSUBBrm },
+ { X86::VPSUBBZ128rr , X86::VPSUBBrr },
+ { X86::VPSUBDZ128rm , X86::VPSUBDrm },
+ { X86::VPSUBDZ128rr , X86::VPSUBDrr },
+ { X86::VPSUBQZ128rm , X86::VPSUBQrm },
+ { X86::VPSUBQZ128rr , X86::VPSUBQrr },
+ { X86::VPSUBSBZ128rm , X86::VPSUBSBrm },
+ { X86::VPSUBSBZ128rr , X86::VPSUBSBrr },
+ { X86::VPSUBSWZ128rm , X86::VPSUBSWrm },
+ { X86::VPSUBSWZ128rr , X86::VPSUBSWrr },
+ { X86::VPSUBUSBZ128rm , X86::VPSUBUSBrm },
+ { X86::VPSUBUSBZ128rr , X86::VPSUBUSBrr },
+ { X86::VPSUBUSWZ128rm , X86::VPSUBUSWrm },
+ { X86::VPSUBUSWZ128rr , X86::VPSUBUSWrr },
+ { X86::VPSUBWZ128rm , X86::VPSUBWrm },
+ { X86::VPSUBWZ128rr , X86::VPSUBWrr },
+ { X86::VPUNPCKHBWZ128rm , X86::VPUNPCKHBWrm },
+ { X86::VPUNPCKHBWZ128rr , X86::VPUNPCKHBWrr },
+ { X86::VPUNPCKHDQZ128rm , X86::VPUNPCKHDQrm },
+ { X86::VPUNPCKHDQZ128rr , X86::VPUNPCKHDQrr },
+ { X86::VPUNPCKHQDQZ128rm , X86::VPUNPCKHQDQrm },
+ { X86::VPUNPCKHQDQZ128rr , X86::VPUNPCKHQDQrr },
+ { X86::VPUNPCKHWDZ128rm , X86::VPUNPCKHWDrm },
+ { X86::VPUNPCKHWDZ128rr , X86::VPUNPCKHWDrr },
+ { X86::VPUNPCKLBWZ128rm , X86::VPUNPCKLBWrm },
+ { X86::VPUNPCKLBWZ128rr , X86::VPUNPCKLBWrr },
+ { X86::VPUNPCKLDQZ128rm , X86::VPUNPCKLDQrm },
+ { X86::VPUNPCKLDQZ128rr , X86::VPUNPCKLDQrr },
+ { X86::VPUNPCKLQDQZ128rm , X86::VPUNPCKLQDQrm },
+ { X86::VPUNPCKLQDQZ128rr , X86::VPUNPCKLQDQrr },
+ { X86::VPUNPCKLWDZ128rm , X86::VPUNPCKLWDrm },
+ { X86::VPUNPCKLWDZ128rr , X86::VPUNPCKLWDrr },
+ { X86::VPXORDZ128rm , X86::VPXORrm },
+ { X86::VPXORDZ128rr , X86::VPXORrr },
+ { X86::VPXORQZ128rm , X86::VPXORrm },
+ { X86::VPXORQZ128rr , X86::VPXORrr },
+ { X86::VSHUFPDZ128rmi , X86::VSHUFPDrmi },
+ { X86::VSHUFPDZ128rri , X86::VSHUFPDrri },
+ { X86::VSHUFPSZ128rmi , X86::VSHUFPSrmi },
+ { X86::VSHUFPSZ128rri , X86::VSHUFPSrri },
+ { X86::VSQRTPDZ128m , X86::VSQRTPDm },
+ { X86::VSQRTPDZ128r , X86::VSQRTPDr },
+ { X86::VSQRTPSZ128m , X86::VSQRTPSm },
+ { X86::VSQRTPSZ128r , X86::VSQRTPSr },
+ { X86::VSUBPDZ128rm , X86::VSUBPDrm },
+ { X86::VSUBPDZ128rr , X86::VSUBPDrr },
+ { X86::VSUBPSZ128rm , X86::VSUBPSrm },
+ { X86::VSUBPSZ128rr , X86::VSUBPSrr },
+ { X86::VUNPCKHPDZ128rm , X86::VUNPCKHPDrm },
+ { X86::VUNPCKHPDZ128rr , X86::VUNPCKHPDrr },
+ { X86::VUNPCKHPSZ128rm , X86::VUNPCKHPSrm },
+ { X86::VUNPCKHPSZ128rr , X86::VUNPCKHPSrr },
+ { X86::VUNPCKLPDZ128rm , X86::VUNPCKLPDrm },
+ { X86::VUNPCKLPDZ128rr , X86::VUNPCKLPDrr },
+ { X86::VUNPCKLPSZ128rm , X86::VUNPCKLPSrm },
+ { X86::VUNPCKLPSZ128rr , X86::VUNPCKLPSrr },
+ { X86::VXORPDZ128rm , X86::VXORPDrm },
+ { X86::VXORPDZ128rr , X86::VXORPDrr },
+ { X86::VXORPSZ128rm , X86::VXORPSrm },
+ { X86::VXORPSZ128rr , X86::VXORPSrr },
+};
+
+
+// X86 EVEX encoded instructions that have a VEX 256 encoding
+// (table format: <EVEX opcode, VEX-256 opcode>).
+ static const X86EvexToVexCompressTableEntry X86EvexToVex256CompressTable[] = {
+ { X86::VADDPDZ256rm , X86::VADDPDYrm },
+ { X86::VADDPDZ256rr , X86::VADDPDYrr },
+ { X86::VADDPSZ256rm , X86::VADDPSYrm },
+ { X86::VADDPSZ256rr , X86::VADDPSYrr },
+ { X86::VANDNPDZ256rm , X86::VANDNPDYrm },
+ { X86::VANDNPDZ256rr , X86::VANDNPDYrr },
+ { X86::VANDNPSZ256rm , X86::VANDNPSYrm },
+ { X86::VANDNPSZ256rr , X86::VANDNPSYrr },
+ { X86::VANDPDZ256rm , X86::VANDPDYrm },
+ { X86::VANDPDZ256rr , X86::VANDPDYrr },
+ { X86::VANDPSZ256rm , X86::VANDPSYrm },
+ { X86::VANDPSZ256rr , X86::VANDPSYrr },
+ { X86::VBROADCASTSDZ256m , X86::VBROADCASTSDYrm },
+ { X86::VBROADCASTSDZ256r , X86::VBROADCASTSDYrr },
+ { X86::VBROADCASTSDZ256r_s , X86::VBROADCASTSDYrr },
+ { X86::VBROADCASTSSZ256m , X86::VBROADCASTSSYrm },
+ { X86::VBROADCASTSSZ256r , X86::VBROADCASTSSYrr },
+ { X86::VBROADCASTSSZ256r_s , X86::VBROADCASTSSYrr },
+ { X86::VCVTDQ2PDZ256rm , X86::VCVTDQ2PDYrm },
+ { X86::VCVTDQ2PDZ256rr , X86::VCVTDQ2PDYrr },
+ { X86::VCVTDQ2PSZ256rm , X86::VCVTDQ2PSYrm },
+ { X86::VCVTDQ2PSZ256rr , X86::VCVTDQ2PSYrr },
+ { X86::VCVTPD2DQZ256rm , X86::VCVTPD2DQYrm },
+ { X86::VCVTPD2DQZ256rr , X86::VCVTPD2DQYrr },
+ { X86::VCVTPD2PSZ256rm , X86::VCVTPD2PSYrm },
+ { X86::VCVTPD2PSZ256rr , X86::VCVTPD2PSYrr },
+ { X86::VCVTPH2PSZ256rm , X86::VCVTPH2PSYrm },
+ { X86::VCVTPH2PSZ256rr , X86::VCVTPH2PSYrr },
+ { X86::VCVTPS2DQZ256rm , X86::VCVTPS2DQYrm },
+ { X86::VCVTPS2DQZ256rr , X86::VCVTPS2DQYrr },
+ { X86::VCVTPS2PDZ256rm , X86::VCVTPS2PDYrm },
+ { X86::VCVTPS2PDZ256rr , X86::VCVTPS2PDYrr },
+ { X86::VCVTPS2PHZ256mr , X86::VCVTPS2PHYmr },
+ { X86::VCVTPS2PHZ256rr , X86::VCVTPS2PHYrr },
+ { X86::VCVTTPD2DQZ256rm , X86::VCVTTPD2DQYrm },
+ { X86::VCVTTPD2DQZ256rr , X86::VCVTTPD2DQYrr },
+ { X86::VCVTTPS2DQZ256rm , X86::VCVTTPS2DQYrm },
+ { X86::VCVTTPS2DQZ256rr , X86::VCVTTPS2DQYrr },
+ { X86::VDIVPDZ256rm , X86::VDIVPDYrm },
+ { X86::VDIVPDZ256rr , X86::VDIVPDYrr },
+ { X86::VDIVPSZ256rm , X86::VDIVPSYrm },
+ { X86::VDIVPSZ256rr , X86::VDIVPSYrr },
+ { X86::VEXTRACTF32x4Z256mr , X86::VEXTRACTF128mr },
+ { X86::VEXTRACTF64x2Z256mr , X86::VEXTRACTF128mr },
+ { X86::VEXTRACTF32x4Z256rr , X86::VEXTRACTF128rr },
+ { X86::VEXTRACTF64x2Z256rr , X86::VEXTRACTF128rr },
+ { X86::VEXTRACTI32x4Z256mr , X86::VEXTRACTI128mr },
+ { X86::VEXTRACTI64x2Z256mr , X86::VEXTRACTI128mr },
+ { X86::VEXTRACTI32x4Z256rr , X86::VEXTRACTI128rr },
+ { X86::VEXTRACTI64x2Z256rr , X86::VEXTRACTI128rr },
+ { X86::VFMADD132PDZ256m , X86::VFMADD132PDYm },
+ { X86::VFMADD132PDZ256r , X86::VFMADD132PDYr },
+ { X86::VFMADD132PSZ256m , X86::VFMADD132PSYm },
+ { X86::VFMADD132PSZ256r , X86::VFMADD132PSYr },
+ { X86::VFMADD213PDZ256m , X86::VFMADD213PDYm },
+ { X86::VFMADD213PDZ256r , X86::VFMADD213PDYr },
+ { X86::VFMADD213PSZ256m , X86::VFMADD213PSYm },
+ { X86::VFMADD213PSZ256r , X86::VFMADD213PSYr },
+ { X86::VFMADD231PDZ256m , X86::VFMADD231PDYm },
+ { X86::VFMADD231PDZ256r , X86::VFMADD231PDYr },
+ { X86::VFMADD231PSZ256m , X86::VFMADD231PSYm },
+ { X86::VFMADD231PSZ256r , X86::VFMADD231PSYr },
+ { X86::VFMADDSUB132PDZ256m , X86::VFMADDSUB132PDYm },
+ { X86::VFMADDSUB132PDZ256r , X86::VFMADDSUB132PDYr },
+ { X86::VFMADDSUB132PSZ256m , X86::VFMADDSUB132PSYm },
+ { X86::VFMADDSUB132PSZ256r , X86::VFMADDSUB132PSYr },
+ { X86::VFMADDSUB213PDZ256m , X86::VFMADDSUB213PDYm },
+ { X86::VFMADDSUB213PDZ256r , X86::VFMADDSUB213PDYr },
+ { X86::VFMADDSUB213PSZ256m , X86::VFMADDSUB213PSYm },
+ { X86::VFMADDSUB213PSZ256r , X86::VFMADDSUB213PSYr },
+ { X86::VFMADDSUB231PDZ256m , X86::VFMADDSUB231PDYm },
+ { X86::VFMADDSUB231PDZ256r , X86::VFMADDSUB231PDYr },
+ { X86::VFMADDSUB231PSZ256m , X86::VFMADDSUB231PSYm },
+ { X86::VFMADDSUB231PSZ256r , X86::VFMADDSUB231PSYr },
+ { X86::VFMSUB132PDZ256m , X86::VFMSUB132PDYm },
+ { X86::VFMSUB132PDZ256r , X86::VFMSUB132PDYr },
+ { X86::VFMSUB132PSZ256m , X86::VFMSUB132PSYm },
+ { X86::VFMSUB132PSZ256r , X86::VFMSUB132PSYr },
+ { X86::VFMSUB213PDZ256m , X86::VFMSUB213PDYm },
+ { X86::VFMSUB213PDZ256r , X86::VFMSUB213PDYr },
+ { X86::VFMSUB213PSZ256m , X86::VFMSUB213PSYm },
+ { X86::VFMSUB213PSZ256r , X86::VFMSUB213PSYr },
+ { X86::VFMSUB231PDZ256m , X86::VFMSUB231PDYm },
+ { X86::VFMSUB231PDZ256r , X86::VFMSUB231PDYr },
+ { X86::VFMSUB231PSZ256m , X86::VFMSUB231PSYm },
+ { X86::VFMSUB231PSZ256r , X86::VFMSUB231PSYr },
+ { X86::VFMSUBADD132PDZ256m , X86::VFMSUBADD132PDYm },
+ { X86::VFMSUBADD132PDZ256r , X86::VFMSUBADD132PDYr },
+ { X86::VFMSUBADD132PSZ256m , X86::VFMSUBADD132PSYm },
+ { X86::VFMSUBADD132PSZ256r , X86::VFMSUBADD132PSYr },
+ { X86::VFMSUBADD213PDZ256m , X86::VFMSUBADD213PDYm },
+ { X86::VFMSUBADD213PDZ256r , X86::VFMSUBADD213PDYr },
+ { X86::VFMSUBADD213PSZ256m , X86::VFMSUBADD213PSYm },
+ { X86::VFMSUBADD213PSZ256r , X86::VFMSUBADD213PSYr },
+ { X86::VFMSUBADD231PDZ256m , X86::VFMSUBADD231PDYm },
+ { X86::VFMSUBADD231PDZ256r , X86::VFMSUBADD231PDYr },
+ { X86::VFMSUBADD231PSZ256m , X86::VFMSUBADD231PSYm },
+ { X86::VFMSUBADD231PSZ256r , X86::VFMSUBADD231PSYr },
+ { X86::VFNMADD132PDZ256m , X86::VFNMADD132PDYm },
+ { X86::VFNMADD132PDZ256r , X86::VFNMADD132PDYr },
+ { X86::VFNMADD132PSZ256m , X86::VFNMADD132PSYm },
+ { X86::VFNMADD132PSZ256r , X86::VFNMADD132PSYr },
+ { X86::VFNMADD213PDZ256m , X86::VFNMADD213PDYm },
+ { X86::VFNMADD213PDZ256r , X86::VFNMADD213PDYr },
+ { X86::VFNMADD213PSZ256m , X86::VFNMADD213PSYm },
+ { X86::VFNMADD213PSZ256r , X86::VFNMADD213PSYr },
+ { X86::VFNMADD231PDZ256m , X86::VFNMADD231PDYm },
+ { X86::VFNMADD231PDZ256r , X86::VFNMADD231PDYr },
+ { X86::VFNMADD231PSZ256m , X86::VFNMADD231PSYm },
+ { X86::VFNMADD231PSZ256r , X86::VFNMADD231PSYr },
+ { X86::VFNMSUB132PDZ256m , X86::VFNMSUB132PDYm },
+ { X86::VFNMSUB132PDZ256r , X86::VFNMSUB132PDYr },
+ { X86::VFNMSUB132PSZ256m , X86::VFNMSUB132PSYm },
+ { X86::VFNMSUB132PSZ256r , X86::VFNMSUB132PSYr },
+ { X86::VFNMSUB213PDZ256m , X86::VFNMSUB213PDYm },
+ { X86::VFNMSUB213PDZ256r , X86::VFNMSUB213PDYr },
+ { X86::VFNMSUB213PSZ256m , X86::VFNMSUB213PSYm },
+ { X86::VFNMSUB213PSZ256r , X86::VFNMSUB213PSYr },
+ { X86::VFNMSUB231PDZ256m , X86::VFNMSUB231PDYm },
+ { X86::VFNMSUB231PDZ256r , X86::VFNMSUB231PDYr },
+ { X86::VFNMSUB231PSZ256m , X86::VFNMSUB231PSYm },
+ { X86::VFNMSUB231PSZ256r , X86::VFNMSUB231PSYr },
+ { X86::VINSERTF32x4Z256rm , X86::VINSERTF128rm },
+ { X86::VINSERTF64x2Z256rm , X86::VINSERTF128rm },
+ { X86::VINSERTF32x4Z256rr , X86::VINSERTF128rr },
+ { X86::VINSERTF64x2Z256rr , X86::VINSERTF128rr },
+ { X86::VINSERTI32x4Z256rm , X86::VINSERTI128rm },
+ { X86::VINSERTI64x2Z256rm , X86::VINSERTI128rm },
+ { X86::VINSERTI32x4Z256rr , X86::VINSERTI128rr },
+ { X86::VINSERTI64x2Z256rr , X86::VINSERTI128rr },
+ { X86::VMAXCPDZ256rm , X86::VMAXCPDYrm },
+ { X86::VMAXCPDZ256rr , X86::VMAXCPDYrr },
+ { X86::VMAXCPSZ256rm , X86::VMAXCPSYrm },
+ { X86::VMAXCPSZ256rr , X86::VMAXCPSYrr },
+ { X86::VMAXPDZ256rm , X86::VMAXPDYrm },
+ { X86::VMAXPDZ256rr , X86::VMAXPDYrr },
+ { X86::VMAXPSZ256rm , X86::VMAXPSYrm },
+ { X86::VMAXPSZ256rr , X86::VMAXPSYrr },
+ { X86::VMINCPDZ256rm , X86::VMINCPDYrm },
+ { X86::VMINCPDZ256rr , X86::VMINCPDYrr },
+ { X86::VMINCPSZ256rm , X86::VMINCPSYrm },
+ { X86::VMINCPSZ256rr , X86::VMINCPSYrr },
+ { X86::VMINPDZ256rm , X86::VMINPDYrm },
+ { X86::VMINPDZ256rr , X86::VMINPDYrr },
+ { X86::VMINPSZ256rm , X86::VMINPSYrm },
+ { X86::VMINPSZ256rr , X86::VMINPSYrr },
+ { X86::VMOVAPDZ256mr , X86::VMOVAPDYmr },
+ { X86::VMOVAPDZ256rm , X86::VMOVAPDYrm },
+ { X86::VMOVAPDZ256rr , X86::VMOVAPDYrr },
+ { X86::VMOVAPDZ256rr_REV , X86::VMOVAPDYrr_REV },
+ { X86::VMOVAPSZ256mr , X86::VMOVAPSYmr },
+ { X86::VMOVAPSZ256rm , X86::VMOVAPSYrm },
+ { X86::VMOVAPSZ256rr , X86::VMOVAPSYrr },
+ { X86::VMOVAPSZ256rr_REV , X86::VMOVAPSYrr_REV },
+ { X86::VMOVDDUPZ256rm , X86::VMOVDDUPYrm },
+ { X86::VMOVDDUPZ256rr , X86::VMOVDDUPYrr },
+ { X86::VMOVDQA32Z256mr , X86::VMOVDQAYmr },
+ { X86::VMOVDQA32Z256rm , X86::VMOVDQAYrm },
+ { X86::VMOVDQA32Z256rr , X86::VMOVDQAYrr },
+ { X86::VMOVDQA32Z256rr_REV , X86::VMOVDQAYrr_REV },
+ { X86::VMOVDQA64Z256mr , X86::VMOVDQAYmr },
+ { X86::VMOVDQA64Z256rm , X86::VMOVDQAYrm },
+ { X86::VMOVDQA64Z256rr , X86::VMOVDQAYrr },
+ { X86::VMOVDQA64Z256rr_REV , X86::VMOVDQAYrr_REV },
+ { X86::VMOVDQU16Z256mr , X86::VMOVDQUYmr },
+ { X86::VMOVDQU16Z256rm , X86::VMOVDQUYrm },
+ { X86::VMOVDQU16Z256rr , X86::VMOVDQUYrr },
+ { X86::VMOVDQU16Z256rr_REV , X86::VMOVDQUYrr_REV },
+ { X86::VMOVDQU32Z256mr , X86::VMOVDQUYmr },
+ { X86::VMOVDQU32Z256rm , X86::VMOVDQUYrm },
+ { X86::VMOVDQU32Z256rr , X86::VMOVDQUYrr },
+ { X86::VMOVDQU32Z256rr_REV , X86::VMOVDQUYrr_REV },
+ { X86::VMOVDQU64Z256mr , X86::VMOVDQUYmr },
+ { X86::VMOVDQU64Z256rm , X86::VMOVDQUYrm },
+ { X86::VMOVDQU64Z256rr , X86::VMOVDQUYrr },
+ { X86::VMOVDQU64Z256rr_REV , X86::VMOVDQUYrr_REV },
+ { X86::VMOVDQU8Z256mr , X86::VMOVDQUYmr },
+ { X86::VMOVDQU8Z256rm , X86::VMOVDQUYrm },
+ { X86::VMOVDQU8Z256rr , X86::VMOVDQUYrr },
+ { X86::VMOVDQU8Z256rr_REV , X86::VMOVDQUYrr_REV },
+ { X86::VMOVNTDQAZ256rm , X86::VMOVNTDQAYrm },
+ { X86::VMOVNTDQZ256mr , X86::VMOVNTDQYmr },
+ { X86::VMOVNTPDZ256mr , X86::VMOVNTPDYmr },
+ { X86::VMOVNTPSZ256mr , X86::VMOVNTPSYmr },
+ { X86::VMOVSHDUPZ256rm , X86::VMOVSHDUPYrm },
+ { X86::VMOVSHDUPZ256rr , X86::VMOVSHDUPYrr },
+ { X86::VMOVSLDUPZ256rm , X86::VMOVSLDUPYrm },
+ { X86::VMOVSLDUPZ256rr , X86::VMOVSLDUPYrr },
+ { X86::VMOVUPDZ256mr , X86::VMOVUPDYmr },
+ { X86::VMOVUPDZ256rm , X86::VMOVUPDYrm },
+ { X86::VMOVUPDZ256rr , X86::VMOVUPDYrr },
+ { X86::VMOVUPDZ256rr_REV , X86::VMOVUPDYrr_REV },
+ { X86::VMOVUPSZ256mr , X86::VMOVUPSYmr },
+ { X86::VMOVUPSZ256rm , X86::VMOVUPSYrm },
+ { X86::VMOVUPSZ256rr , X86::VMOVUPSYrr },
+ { X86::VMOVUPSZ256rr_REV , X86::VMOVUPSYrr_REV },
+ { X86::VMULPDZ256rm , X86::VMULPDYrm },
+ { X86::VMULPDZ256rr , X86::VMULPDYrr },
+ { X86::VMULPSZ256rm , X86::VMULPSYrm },
+ { X86::VMULPSZ256rr , X86::VMULPSYrr },
+ { X86::VORPDZ256rm , X86::VORPDYrm },
+ { X86::VORPDZ256rr , X86::VORPDYrr },
+ { X86::VORPSZ256rm , X86::VORPSYrm },
+ { X86::VORPSZ256rr , X86::VORPSYrr },
+ { X86::VPABSBZ256rm , X86::VPABSBYrm },
+ { X86::VPABSBZ256rr , X86::VPABSBYrr },
+ { X86::VPABSDZ256rm , X86::VPABSDYrm },
+ { X86::VPABSDZ256rr , X86::VPABSDYrr },
+ { X86::VPABSWZ256rm , X86::VPABSWYrm },
+ { X86::VPABSWZ256rr , X86::VPABSWYrr },
+ { X86::VPACKSSDWZ256rm , X86::VPACKSSDWYrm },
+ { X86::VPACKSSDWZ256rr , X86::VPACKSSDWYrr },
+ { X86::VPACKSSWBZ256rm , X86::VPACKSSWBYrm },
+ { X86::VPACKSSWBZ256rr , X86::VPACKSSWBYrr },
+ { X86::VPACKUSDWZ256rm , X86::VPACKUSDWYrm },
+ { X86::VPACKUSDWZ256rr , X86::VPACKUSDWYrr },
+ { X86::VPACKUSWBZ256rm , X86::VPACKUSWBYrm },
+ { X86::VPACKUSWBZ256rr , X86::VPACKUSWBYrr },
+ { X86::VPADDBZ256rm , X86::VPADDBYrm },
+ { X86::VPADDBZ256rr , X86::VPADDBYrr },
+ { X86::VPADDDZ256rm , X86::VPADDDYrm },
+ { X86::VPADDDZ256rr , X86::VPADDDYrr },
+ { X86::VPADDQZ256rm , X86::VPADDQYrm },
+ { X86::VPADDQZ256rr , X86::VPADDQYrr },
+ { X86::VPADDSBZ256rm , X86::VPADDSBYrm },
+ { X86::VPADDSBZ256rr , X86::VPADDSBYrr },
+ { X86::VPADDSWZ256rm , X86::VPADDSWYrm },
+ { X86::VPADDSWZ256rr , X86::VPADDSWYrr },
+ { X86::VPADDUSBZ256rm , X86::VPADDUSBYrm },
+ { X86::VPADDUSBZ256rr , X86::VPADDUSBYrr },
+ { X86::VPADDUSWZ256rm , X86::VPADDUSWYrm },
+ { X86::VPADDUSWZ256rr , X86::VPADDUSWYrr },
+ { X86::VPADDWZ256rm , X86::VPADDWYrm },
+ { X86::VPADDWZ256rr , X86::VPADDWYrr },
+ { X86::VPALIGNRZ256rmi , X86::VPALIGNRYrmi },
+ { X86::VPALIGNRZ256rri , X86::VPALIGNRYrri },
+ { X86::VPANDDZ256rm , X86::VPANDYrm },
+ { X86::VPANDDZ256rr , X86::VPANDYrr },
+ { X86::VPANDQZ256rm , X86::VPANDYrm },
+ { X86::VPANDQZ256rr , X86::VPANDYrr },
+ { X86::VPAVGBZ256rm , X86::VPAVGBYrm },
+ { X86::VPAVGBZ256rr , X86::VPAVGBYrr },
+ { X86::VPAVGWZ256rm , X86::VPAVGWYrm },
+ { X86::VPAVGWZ256rr , X86::VPAVGWYrr },
+ { X86::VPBROADCASTBZ256m , X86::VPBROADCASTBYrm },
+ { X86::VPBROADCASTBZ256r , X86::VPBROADCASTBYrr },
+ { X86::VPBROADCASTDZ256m , X86::VPBROADCASTDYrm },
+ { X86::VPBROADCASTDZ256r , X86::VPBROADCASTDYrr },
+ { X86::VPBROADCASTQZ256m , X86::VPBROADCASTQYrm },
+ { X86::VPBROADCASTQZ256r , X86::VPBROADCASTQYrr },
+ { X86::VPBROADCASTWZ256m , X86::VPBROADCASTWYrm },
+ { X86::VPBROADCASTWZ256r , X86::VPBROADCASTWYrr },
+ { X86::VPERMDZ256rm , X86::VPERMDYrm },
+ { X86::VPERMDZ256rr , X86::VPERMDYrr },
+ { X86::VPERMILPDZ256mi , X86::VPERMILPDYmi },
+ { X86::VPERMILPDZ256ri , X86::VPERMILPDYri },
+ { X86::VPERMILPDZ256rm , X86::VPERMILPDYrm },
+ { X86::VPERMILPDZ256rr , X86::VPERMILPDYrr },
+ { X86::VPERMILPSZ256mi , X86::VPERMILPSYmi },
+ { X86::VPERMILPSZ256ri , X86::VPERMILPSYri },
+ { X86::VPERMILPSZ256rm , X86::VPERMILPSYrm },
+ { X86::VPERMILPSZ256rr , X86::VPERMILPSYrr },
+ { X86::VPERMPDZ256mi , X86::VPERMPDYmi },
+ { X86::VPERMPDZ256ri , X86::VPERMPDYri },
+ { X86::VPERMPSZ256rm , X86::VPERMPSYrm },
+ { X86::VPERMPSZ256rr , X86::VPERMPSYrr },
+ { X86::VPERMQZ256mi , X86::VPERMQYmi },
+ { X86::VPERMQZ256ri , X86::VPERMQYri },
+ { X86::VPMADDUBSWZ256rm , X86::VPMADDUBSWYrm },
+ { X86::VPMADDUBSWZ256rr , X86::VPMADDUBSWYrr },
+ { X86::VPMADDWDZ256rm , X86::VPMADDWDYrm },
+ { X86::VPMADDWDZ256rr , X86::VPMADDWDYrr },
+ { X86::VPMAXSBZ256rm , X86::VPMAXSBYrm },
+ { X86::VPMAXSBZ256rr , X86::VPMAXSBYrr },
+ { X86::VPMAXSDZ256rm , X86::VPMAXSDYrm },
+ { X86::VPMAXSDZ256rr , X86::VPMAXSDYrr },
+ { X86::VPMAXSWZ256rm , X86::VPMAXSWYrm },
+ { X86::VPMAXSWZ256rr , X86::VPMAXSWYrr },
+ { X86::VPMAXUBZ256rm , X86::VPMAXUBYrm },
+ { X86::VPMAXUBZ256rr , X86::VPMAXUBYrr },
+ { X86::VPMAXUDZ256rm , X86::VPMAXUDYrm },
+ { X86::VPMAXUDZ256rr , X86::VPMAXUDYrr },
+ { X86::VPMAXUWZ256rm , X86::VPMAXUWYrm },
+ { X86::VPMAXUWZ256rr , X86::VPMAXUWYrr },
+ { X86::VPMINSBZ256rm , X86::VPMINSBYrm },
+ { X86::VPMINSBZ256rr , X86::VPMINSBYrr },
+ { X86::VPMINSDZ256rm , X86::VPMINSDYrm },
+ { X86::VPMINSDZ256rr , X86::VPMINSDYrr },
+ { X86::VPMINSWZ256rm , X86::VPMINSWYrm },
+ { X86::VPMINSWZ256rr , X86::VPMINSWYrr },
+ { X86::VPMINUBZ256rm , X86::VPMINUBYrm },
+ { X86::VPMINUBZ256rr , X86::VPMINUBYrr },
+ { X86::VPMINUDZ256rm , X86::VPMINUDYrm },
+ { X86::VPMINUDZ256rr , X86::VPMINUDYrr },
+ { X86::VPMINUWZ256rm , X86::VPMINUWYrm },
+ { X86::VPMINUWZ256rr , X86::VPMINUWYrr },
+ { X86::VPMOVSXBDZ256rm , X86::VPMOVSXBDYrm },
+ { X86::VPMOVSXBDZ256rr , X86::VPMOVSXBDYrr },
+ { X86::VPMOVSXBQZ256rm , X86::VPMOVSXBQYrm },
+ { X86::VPMOVSXBQZ256rr , X86::VPMOVSXBQYrr },
+ { X86::VPMOVSXBWZ256rm , X86::VPMOVSXBWYrm },
+ { X86::VPMOVSXBWZ256rr , X86::VPMOVSXBWYrr },
+ { X86::VPMOVSXDQZ256rm , X86::VPMOVSXDQYrm },
+ { X86::VPMOVSXDQZ256rr , X86::VPMOVSXDQYrr },
+ { X86::VPMOVSXWDZ256rm , X86::VPMOVSXWDYrm },
+ { X86::VPMOVSXWDZ256rr , X86::VPMOVSXWDYrr },
+ { X86::VPMOVSXWQZ256rm , X86::VPMOVSXWQYrm },
+ { X86::VPMOVSXWQZ256rr , X86::VPMOVSXWQYrr },
+ { X86::VPMOVZXBDZ256rm , X86::VPMOVZXBDYrm },
+ { X86::VPMOVZXBDZ256rr , X86::VPMOVZXBDYrr },
+ { X86::VPMOVZXBQZ256rm , X86::VPMOVZXBQYrm },
+ { X86::VPMOVZXBQZ256rr , X86::VPMOVZXBQYrr },
+ { X86::VPMOVZXBWZ256rm , X86::VPMOVZXBWYrm },
+ { X86::VPMOVZXBWZ256rr , X86::VPMOVZXBWYrr },
+ { X86::VPMOVZXDQZ256rm , X86::VPMOVZXDQYrm },
+ { X86::VPMOVZXDQZ256rr , X86::VPMOVZXDQYrr },
+ { X86::VPMOVZXWDZ256rm , X86::VPMOVZXWDYrm },
+ { X86::VPMOVZXWDZ256rr , X86::VPMOVZXWDYrr },
+ { X86::VPMOVZXWQZ256rm , X86::VPMOVZXWQYrm },
+ { X86::VPMOVZXWQZ256rr , X86::VPMOVZXWQYrr },
+ { X86::VPMULDQZ256rm , X86::VPMULDQYrm },
+ { X86::VPMULDQZ256rr , X86::VPMULDQYrr },
+ { X86::VPMULHRSWZ256rm , X86::VPMULHRSWYrm },
+ { X86::VPMULHRSWZ256rr , X86::VPMULHRSWYrr },
+ { X86::VPMULHUWZ256rm , X86::VPMULHUWYrm },
+ { X86::VPMULHUWZ256rr , X86::VPMULHUWYrr },
+ { X86::VPMULHWZ256rm , X86::VPMULHWYrm },
+ { X86::VPMULHWZ256rr , X86::VPMULHWYrr },
+ { X86::VPMULLDZ256rm , X86::VPMULLDYrm },
+ { X86::VPMULLDZ256rr , X86::VPMULLDYrr },
+ { X86::VPMULLWZ256rm , X86::VPMULLWYrm },
+ { X86::VPMULLWZ256rr , X86::VPMULLWYrr },
+ { X86::VPMULUDQZ256rm , X86::VPMULUDQYrm },
+ { X86::VPMULUDQZ256rr , X86::VPMULUDQYrr },
+ { X86::VPORDZ256rm , X86::VPORYrm },
+ { X86::VPORDZ256rr , X86::VPORYrr },
+ { X86::VPORQZ256rm , X86::VPORYrm },
+ { X86::VPORQZ256rr , X86::VPORYrr },
+ { X86::VPSADBWZ256rm , X86::VPSADBWYrm },
+ { X86::VPSADBWZ256rr , X86::VPSADBWYrr },
+ { X86::VPSHUFBZ256rm , X86::VPSHUFBYrm },
+ { X86::VPSHUFBZ256rr , X86::VPSHUFBYrr },
+ { X86::VPSHUFDZ256mi , X86::VPSHUFDYmi },
+ { X86::VPSHUFDZ256ri , X86::VPSHUFDYri },
+ { X86::VPSHUFHWZ256mi , X86::VPSHUFHWYmi },
+ { X86::VPSHUFHWZ256ri , X86::VPSHUFHWYri },
+ { X86::VPSHUFLWZ256mi , X86::VPSHUFLWYmi },
+ { X86::VPSHUFLWZ256ri , X86::VPSHUFLWYri },
+ { X86::VPSLLDQZ256rr , X86::VPSLLDQYri },
+ { X86::VPSLLDZ256ri , X86::VPSLLDYri },
+ { X86::VPSLLDZ256rm , X86::VPSLLDYrm },
+ { X86::VPSLLDZ256rr , X86::VPSLLDYrr },
+ { X86::VPSLLQZ256ri , X86::VPSLLQYri },
+ { X86::VPSLLQZ256rm , X86::VPSLLQYrm },
+ { X86::VPSLLQZ256rr , X86::VPSLLQYrr },
+ { X86::VPSLLVDZ256rm , X86::VPSLLVDYrm },
+ { X86::VPSLLVDZ256rr , X86::VPSLLVDYrr },
+ { X86::VPSLLVQZ256rm , X86::VPSLLVQYrm },
+ { X86::VPSLLVQZ256rr , X86::VPSLLVQYrr },
+ { X86::VPSLLWZ256ri , X86::VPSLLWYri },
+ { X86::VPSLLWZ256rm , X86::VPSLLWYrm },
+ { X86::VPSLLWZ256rr , X86::VPSLLWYrr },
+ { X86::VPSRADZ256ri , X86::VPSRADYri },
+ { X86::VPSRADZ256rm , X86::VPSRADYrm },
+ { X86::VPSRADZ256rr , X86::VPSRADYrr },
+ { X86::VPSRAVDZ256rm , X86::VPSRAVDYrm },
+ { X86::VPSRAVDZ256rr , X86::VPSRAVDYrr },
+ { X86::VPSRAWZ256ri , X86::VPSRAWYri },
+ { X86::VPSRAWZ256rm , X86::VPSRAWYrm },
+ { X86::VPSRAWZ256rr , X86::VPSRAWYrr },
+ { X86::VPSRLDQZ256rr , X86::VPSRLDQYri },
+ { X86::VPSRLDZ256ri , X86::VPSRLDYri },
+ { X86::VPSRLDZ256rm , X86::VPSRLDYrm },
+ { X86::VPSRLDZ256rr , X86::VPSRLDYrr },
+ { X86::VPSRLQZ256ri , X86::VPSRLQYri },
+ { X86::VPSRLQZ256rm , X86::VPSRLQYrm },
+ { X86::VPSRLQZ256rr , X86::VPSRLQYrr },
+ { X86::VPSRLVDZ256rm , X86::VPSRLVDYrm },
+ { X86::VPSRLVDZ256rr , X86::VPSRLVDYrr },
+ { X86::VPSRLVQZ256rm , X86::VPSRLVQYrm },
+ { X86::VPSRLVQZ256rr , X86::VPSRLVQYrr },
+ { X86::VPSRLWZ256ri , X86::VPSRLWYri },
+ { X86::VPSRLWZ256rm , X86::VPSRLWYrm },
+ { X86::VPSRLWZ256rr , X86::VPSRLWYrr },
+ { X86::VPSUBBZ256rm , X86::VPSUBBYrm },
+ { X86::VPSUBBZ256rr , X86::VPSUBBYrr },
+ { X86::VPSUBDZ256rm , X86::VPSUBDYrm },
+ { X86::VPSUBDZ256rr , X86::VPSUBDYrr },
+ { X86::VPSUBQZ256rm , X86::VPSUBQYrm },
+ { X86::VPSUBQZ256rr , X86::VPSUBQYrr },
+ { X86::VPSUBSBZ256rm , X86::VPSUBSBYrm },
+ { X86::VPSUBSBZ256rr , X86::VPSUBSBYrr },
+ { X86::VPSUBSWZ256rm , X86::VPSUBSWYrm },
+ { X86::VPSUBSWZ256rr , X86::VPSUBSWYrr },
+ { X86::VPSUBUSBZ256rm , X86::VPSUBUSBYrm },
+ { X86::VPSUBUSBZ256rr , X86::VPSUBUSBYrr },
+ { X86::VPSUBUSWZ256rm , X86::VPSUBUSWYrm },
+ { X86::VPSUBUSWZ256rr , X86::VPSUBUSWYrr },
+ { X86::VPSUBWZ256rm , X86::VPSUBWYrm },
+ { X86::VPSUBWZ256rr , X86::VPSUBWYrr },
+ { X86::VPUNPCKHBWZ256rm , X86::VPUNPCKHBWYrm },
+ { X86::VPUNPCKHBWZ256rr , X86::VPUNPCKHBWYrr },
+ { X86::VPUNPCKHDQZ256rm , X86::VPUNPCKHDQYrm },
+ { X86::VPUNPCKHDQZ256rr , X86::VPUNPCKHDQYrr },
+ { X86::VPUNPCKHQDQZ256rm , X86::VPUNPCKHQDQYrm },
+ { X86::VPUNPCKHQDQZ256rr , X86::VPUNPCKHQDQYrr },
+ { X86::VPUNPCKHWDZ256rm , X86::VPUNPCKHWDYrm },
+ { X86::VPUNPCKHWDZ256rr , X86::VPUNPCKHWDYrr },
+ { X86::VPUNPCKLBWZ256rm , X86::VPUNPCKLBWYrm },
+ { X86::VPUNPCKLBWZ256rr , X86::VPUNPCKLBWYrr },
+ { X86::VPUNPCKLDQZ256rm , X86::VPUNPCKLDQYrm },
+ { X86::VPUNPCKLDQZ256rr , X86::VPUNPCKLDQYrr },
+ { X86::VPUNPCKLQDQZ256rm , X86::VPUNPCKLQDQYrm },
+ { X86::VPUNPCKLQDQZ256rr , X86::VPUNPCKLQDQYrr },
+ { X86::VPUNPCKLWDZ256rm , X86::VPUNPCKLWDYrm },
+ { X86::VPUNPCKLWDZ256rr , X86::VPUNPCKLWDYrr },
+ { X86::VPXORDZ256rm , X86::VPXORYrm },
+ { X86::VPXORDZ256rr , X86::VPXORYrr },
+ { X86::VPXORQZ256rm , X86::VPXORYrm },
+ { X86::VPXORQZ256rr , X86::VPXORYrr },
+ { X86::VSHUFPDZ256rmi , X86::VSHUFPDYrmi },
+ { X86::VSHUFPDZ256rri , X86::VSHUFPDYrri },
+ { X86::VSHUFPSZ256rmi , X86::VSHUFPSYrmi },
+ { X86::VSHUFPSZ256rri , X86::VSHUFPSYrri },
+ { X86::VSQRTPDZ256m , X86::VSQRTPDYm },
+ { X86::VSQRTPDZ256r , X86::VSQRTPDYr },
+ { X86::VSQRTPSZ256m , X86::VSQRTPSYm },
+ { X86::VSQRTPSZ256r , X86::VSQRTPSYr },
+ { X86::VSUBPDZ256rm , X86::VSUBPDYrm },
+ { X86::VSUBPDZ256rr , X86::VSUBPDYrr },
+ { X86::VSUBPSZ256rm , X86::VSUBPSYrm },
+ { X86::VSUBPSZ256rr , X86::VSUBPSYrr },
+ { X86::VUNPCKHPDZ256rm , X86::VUNPCKHPDYrm },
+ { X86::VUNPCKHPDZ256rr , X86::VUNPCKHPDYrr },
+ { X86::VUNPCKHPSZ256rm , X86::VUNPCKHPSYrm },
+ { X86::VUNPCKHPSZ256rr , X86::VUNPCKHPSYrr },
+ { X86::VUNPCKLPDZ256rm , X86::VUNPCKLPDYrm },
+ { X86::VUNPCKLPDZ256rr , X86::VUNPCKLPDYrr },
+ { X86::VUNPCKLPSZ256rm , X86::VUNPCKLPSYrm },
+ { X86::VUNPCKLPSZ256rr , X86::VUNPCKLPSYrr },
+ { X86::VXORPDZ256rm , X86::VXORPDYrm },
+ { X86::VXORPDZ256rr , X86::VXORPDYrr },
+ { X86::VXORPSZ256rm , X86::VXORPSYrm },
+ { X86::VXORPSZ256rr , X86::VXORPSYrr },
+};
+
+#endif
diff --git a/contrib/llvm/lib/Target/X86/X86InstrXOP.td b/contrib/llvm/lib/Target/X86/X86InstrXOP.td
index f49917b..2b296e1 100644
--- a/contrib/llvm/lib/Target/X86/X86InstrXOP.td
+++ b/contrib/llvm/lib/Target/X86/X86InstrXOP.td
@@ -85,12 +85,12 @@ let ExeDomain = SSEPackedDouble in {
multiclass xop3op<bits<8> opc, string OpcodeStr, SDNode OpNode,
ValueType vt128> {
- def rr : IXOP<opc, MRMSrcReg, (outs VR128:$dst),
+ def rr : IXOP<opc, MRMSrcReg4VOp3, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set VR128:$dst,
(vt128 (OpNode (vt128 VR128:$src1), (vt128 VR128:$src2))))]>,
- XOP_4VOp3, Sched<[WriteVarVecShift]>;
+ XOP, Sched<[WriteVarVecShift]>;
def rm : IXOP<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, i128mem:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
@@ -98,13 +98,20 @@ multiclass xop3op<bits<8> opc, string OpcodeStr, SDNode OpNode,
(vt128 (OpNode (vt128 VR128:$src1),
(vt128 (bitconvert (loadv2i64 addr:$src2))))))]>,
XOP_4V, VEX_W, Sched<[WriteVarVecShift, ReadAfterLd]>;
- def mr : IXOP<opc, MRMSrcMem, (outs VR128:$dst),
+ def mr : IXOP<opc, MRMSrcMem4VOp3, (outs VR128:$dst),
(ins i128mem:$src1, VR128:$src2),
!strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
[(set VR128:$dst,
(vt128 (OpNode (vt128 (bitconvert (loadv2i64 addr:$src1))),
(vt128 VR128:$src2))))]>,
- XOP_4VOp3, Sched<[WriteVarVecShift, ReadAfterLd]>;
+ XOP, Sched<[WriteVarVecShift, ReadAfterLd]>;
+ // For disassembler
+ let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
+ def rr_REV : IXOP<opc, MRMSrcReg, (outs VR128:$dst),
+ (ins VR128:$src1, VR128:$src2),
+ !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+ []>,
+ XOP_4V, VEX_W, Sched<[WriteVarVecShift]>;
}
let ExeDomain = SSEPackedInt in {
@@ -146,19 +153,19 @@ let ExeDomain = SSEPackedInt in {
// Instruction where second source can be memory, but third must be register
multiclass xop4opm2<bits<8> opc, string OpcodeStr, Intrinsic Int> {
let isCommutable = 1 in
- def rr : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
+ def rr : IXOPi8Reg<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
- (Int VR128:$src1, VR128:$src2, VR128:$src3))]>, XOP_4V, VEX_I8IMM;
- def rm : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
+ (Int VR128:$src1, VR128:$src2, VR128:$src3))]>, XOP_4V;
+ def rm : IXOPi8Reg<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, i128mem:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(Int VR128:$src1, (bitconvert (loadv2i64 addr:$src2)),
- VR128:$src3))]>, XOP_4V, VEX_I8IMM;
+ VR128:$src3))]>, XOP_4V;
}
let ExeDomain = SSEPackedInt in {
@@ -224,37 +231,37 @@ let ExeDomain = SSEPackedInt in { // SSE integer instructions
multiclass xop4op<bits<8> opc, string OpcodeStr, SDNode OpNode,
ValueType vt128> {
- def rrr : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
+ def rrr : IXOPi8Reg<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(vt128 (OpNode (vt128 VR128:$src1), (vt128 VR128:$src2),
(vt128 VR128:$src3))))]>,
- XOP_4V, VEX_I8IMM;
- def rrm : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
+ XOP_4V;
+ def rrm : IXOPi8Reg<opc, MRMSrcMemOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, i128mem:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(vt128 (OpNode (vt128 VR128:$src1), (vt128 VR128:$src2),
(vt128 (bitconvert (loadv2i64 addr:$src3))))))]>,
- XOP_4V, VEX_I8IMM, VEX_W, MemOp4;
- def rmr : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
+ XOP_4V, VEX_W;
+ def rmr : IXOPi8Reg<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, i128mem:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(v16i8 (OpNode (vt128 VR128:$src1), (vt128 (bitconvert (loadv2i64 addr:$src2))),
(vt128 VR128:$src3))))]>,
- XOP_4V, VEX_I8IMM;
+ XOP_4V;
// For disassembler
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
- def rrr_REV : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
+ def rrr_REV : IXOPi8Reg<opc, MRMSrcRegOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
- []>, XOP_4V, VEX_I8IMM, VEX_W, MemOp4;
+ []>, XOP_4V, VEX_W;
}
let ExeDomain = SSEPackedInt in {
@@ -265,66 +272,66 @@ let ExeDomain = SSEPackedInt in {
multiclass xop4op_int<bits<8> opc, string OpcodeStr,
Intrinsic Int128, Intrinsic Int256> {
// 128-bit Instruction
- def rrr : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
+ def rrr : IXOPi8Reg<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst, (Int128 VR128:$src1, VR128:$src2, VR128:$src3))]>,
- XOP_4V, VEX_I8IMM;
- def rrm : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
+ XOP_4V;
+ def rrm : IXOPi8Reg<opc, MRMSrcMemOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, i128mem:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(Int128 VR128:$src1, VR128:$src2,
(bitconvert (loadv2i64 addr:$src3))))]>,
- XOP_4V, VEX_I8IMM, VEX_W, MemOp4;
- def rmr : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
+ XOP_4V, VEX_W;
+ def rmr : IXOPi8Reg<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, i128mem:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR128:$dst,
(Int128 VR128:$src1, (bitconvert (loadv2i64 addr:$src2)),
VR128:$src3))]>,
- XOP_4V, VEX_I8IMM;
+ XOP_4V;
// For disassembler
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
- def rrr_REV : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
+ def rrr_REV : IXOPi8Reg<opc, MRMSrcRegOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
- []>, XOP_4V, VEX_I8IMM, VEX_W, MemOp4;
+ []>, XOP_4V, VEX_W;
// 256-bit Instruction
- def rrrY : IXOPi8<opc, MRMSrcReg, (outs VR256:$dst),
+ def rrrY : IXOPi8Reg<opc, MRMSrcReg, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR256:$dst, (Int256 VR256:$src1, VR256:$src2, VR256:$src3))]>,
- XOP_4V, VEX_I8IMM, VEX_L;
- def rrmY : IXOPi8<opc, MRMSrcMem, (outs VR256:$dst),
+ XOP_4V, VEX_L;
+ def rrmY : IXOPi8Reg<opc, MRMSrcMemOp4, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, i256mem:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR256:$dst,
(Int256 VR256:$src1, VR256:$src2,
(bitconvert (loadv4i64 addr:$src3))))]>,
- XOP_4V, VEX_I8IMM, VEX_W, MemOp4, VEX_L;
- def rmrY : IXOPi8<opc, MRMSrcMem, (outs VR256:$dst),
+ XOP_4V, VEX_W, VEX_L;
+ def rmrY : IXOPi8Reg<opc, MRMSrcMem, (outs VR256:$dst),
(ins VR256:$src1, f256mem:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[(set VR256:$dst,
(Int256 VR256:$src1, (bitconvert (loadv4i64 addr:$src2)),
VR256:$src3))]>,
- XOP_4V, VEX_I8IMM, VEX_L;
+ XOP_4V, VEX_L;
// For disassembler
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
- def rrrY_REV : IXOPi8<opc, MRMSrcReg, (outs VR256:$dst),
+ def rrrY_REV : IXOPi8Reg<opc, MRMSrcRegOp4, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3),
!strconcat(OpcodeStr,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
- []>, XOP_4V, VEX_I8IMM, VEX_W, MemOp4, VEX_L;
+ []>, XOP_4V, VEX_W, VEX_L;
}
let ExeDomain = SSEPackedInt in {
@@ -353,7 +360,7 @@ multiclass xop5op<bits<8> opc, string OpcodeStr, SDNode OpNode,
[(set VR128:$dst,
(vt128 (OpNode (vt128 VR128:$src1), (vt128 VR128:$src2),
(id128 VR128:$src3), (i8 imm:$src4))))]>;
- def rm : IXOP5<opc, MRMSrcMem, (outs VR128:$dst),
+ def rm : IXOP5<opc, MRMSrcMemOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, i128mem:$src3, u8imm:$src4),
!strconcat(OpcodeStr,
"\t{$src4, $src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3, $src4}"),
@@ -361,7 +368,7 @@ multiclass xop5op<bits<8> opc, string OpcodeStr, SDNode OpNode,
(vt128 (OpNode (vt128 VR128:$src1), (vt128 VR128:$src2),
(id128 (bitconvert (loadv2i64 addr:$src3))),
(i8 imm:$src4))))]>,
- VEX_W, MemOp4;
+ VEX_W;
def mr : IXOP5<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, f128mem:$src2, VR128:$src3, u8imm:$src4),
!strconcat(OpcodeStr,
@@ -372,11 +379,11 @@ multiclass xop5op<bits<8> opc, string OpcodeStr, SDNode OpNode,
(id128 VR128:$src3), (i8 imm:$src4))))]>;
// For disassembler
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
- def rr_REV : IXOP5<opc, MRMSrcReg, (outs VR128:$dst),
+ def rr_REV : IXOP5<opc, MRMSrcRegOp4, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, VR128:$src3, u8imm:$src4),
!strconcat(OpcodeStr,
"\t{$src4, $src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3, $src4}"),
- []>, VEX_W, MemOp4;
+ []>, VEX_W;
def rrY : IXOP5<opc, MRMSrcReg, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3, u8imm:$src4),
@@ -385,14 +392,14 @@ multiclass xop5op<bits<8> opc, string OpcodeStr, SDNode OpNode,
[(set VR256:$dst,
(vt256 (OpNode (vt256 VR256:$src1), (vt256 VR256:$src2),
(id256 VR256:$src3), (i8 imm:$src4))))]>, VEX_L;
- def rmY : IXOP5<opc, MRMSrcMem, (outs VR256:$dst),
+ def rmY : IXOP5<opc, MRMSrcMemOp4, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, i256mem:$src3, u8imm:$src4),
!strconcat(OpcodeStr,
"\t{$src4, $src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3, $src4}"),
[(set VR256:$dst,
(vt256 (OpNode (vt256 VR256:$src1), (vt256 VR256:$src2),
(id256 (bitconvert (loadv4i64 addr:$src3))),
- (i8 imm:$src4))))]>, VEX_W, MemOp4, VEX_L;
+ (i8 imm:$src4))))]>, VEX_W, VEX_L;
def mrY : IXOP5<opc, MRMSrcMem, (outs VR256:$dst),
(ins VR256:$src1, f256mem:$src2, VR256:$src3, u8imm:$src4),
!strconcat(OpcodeStr,
@@ -403,11 +410,11 @@ multiclass xop5op<bits<8> opc, string OpcodeStr, SDNode OpNode,
(id256 VR256:$src3), (i8 imm:$src4))))]>, VEX_L;
// For disassembler
let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in
- def rrY_REV : IXOP5<opc, MRMSrcReg, (outs VR256:$dst),
+ def rrY_REV : IXOP5<opc, MRMSrcRegOp4, (outs VR256:$dst),
(ins VR256:$src1, VR256:$src2, VR256:$src3, u8imm:$src4),
!strconcat(OpcodeStr,
"\t{$src4, $src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3, $src4}"),
- []>, VEX_W, MemOp4, VEX_L;
+ []>, VEX_W, VEX_L;
}
let ExeDomain = SSEPackedDouble in
diff --git a/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp b/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp
new file mode 100644
index 0000000..d9edf46
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp
@@ -0,0 +1,221 @@
+//===--------- X86InterleavedAccess.cpp ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the X86 implementation of the interleaved accesses
+/// optimization generating X86-specific instructions/intrinsics for
+/// interleaved access groups.
+///
+//===--------------------------------------------------------------------===//
+
+#include "X86ISelLowering.h"
+#include "X86TargetMachine.h"
+
+using namespace llvm;
+
+/// \brief This class holds necessary information to represent an interleaved
+/// access group and supports utilities to lower the group into
+/// X86-specific instructions/intrinsics.
+/// E.g. A group of interleaving access loads (Factor = 2; accessing every
+/// other element)
+/// %wide.vec = load <8 x i32>, <8 x i32>* %ptr
+/// %v0 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <0, 2, 4, 6>
+/// %v1 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <1, 3, 5, 7>
+
+class X86InterleavedAccessGroup {
+ /// \brief Reference to the wide-load instruction of an interleaved access
+ /// group.
+ Instruction *const Inst;
+
+ /// \brief Reference to the shuffle(s), consumer(s) of the (load) 'Inst'.
+ ArrayRef<ShuffleVectorInst *> Shuffles;
+
+ /// \brief Reference to the starting index of each user-shuffle.
+ ArrayRef<unsigned> Indices;
+
+ /// \brief Reference to the interleaving stride in terms of elements.
+ const unsigned Factor;
+
+ /// \brief Reference to the underlying target.
+ const X86Subtarget &Subtarget;
+
+ const DataLayout &DL;
+
+ IRBuilder<> &Builder;
+
+ /// \brief Breaks down a vector \p 'Inst' of N elements into \p NumSubVectors
+ /// sub vectors of type \p T. Returns true and the sub-vectors in
+ /// \p DecomposedVectors if it decomposes the Inst, returns false otherwise.
+ bool decompose(Instruction *Inst, unsigned NumSubVectors, VectorType *T,
+ SmallVectorImpl<Instruction *> &DecomposedVectors);
+
+ /// \brief Performs matrix transposition on a 4x4 matrix \p InputVectors and
+ /// returns the transposed-vectors in \p TransposedVectors.
+ /// E.g.
+ /// InputVectors:
+ /// In-V0 = p1, p2, p3, p4
+ /// In-V1 = q1, q2, q3, q4
+ /// In-V2 = r1, r2, r3, r4
+ /// In-V3 = s1, s2, s3, s4
+ /// OutputVectors:
+ /// Out-V0 = p1, q1, r1, s1
+ /// Out-V1 = p2, q2, r2, s2
+ /// Out-V2 = p3, q3, r3, s3
+ /// Out-V3 = P4, q4, r4, s4
+ void transpose_4x4(ArrayRef<Instruction *> InputVectors,
+ SmallVectorImpl<Value *> &TrasposedVectors);
+
+public:
+ /// In order to form an interleaved access group X86InterleavedAccessGroup
+ /// requires a wide-load instruction \p 'I', a group of interleaved-vectors
+ /// \p Shuffs, reference to the first indices of each interleaved-vector
+ /// \p 'Ind' and the interleaving stride factor \p F. In order to generate
+ /// X86-specific instructions/intrinsics it also requires the underlying
+ /// target information \p STarget.
+ explicit X86InterleavedAccessGroup(Instruction *I,
+ ArrayRef<ShuffleVectorInst *> Shuffs,
+ ArrayRef<unsigned> Ind,
+ const unsigned F,
+ const X86Subtarget &STarget,
+ IRBuilder<> &B)
+ : Inst(I), Shuffles(Shuffs), Indices(Ind), Factor(F), Subtarget(STarget),
+ DL(Inst->getModule()->getDataLayout()), Builder(B) {}
+
+ /// \brief Returns true if this interleaved access group can be lowered into
+ /// x86-specific instructions/intrinsics, false otherwise.
+ bool isSupported() const;
+
+ /// \brief Lowers this interleaved access group into X86-specific
+ /// instructions/intrinsics.
+ bool lowerIntoOptimizedSequence();
+};
+
+bool X86InterleavedAccessGroup::isSupported() const {
+ VectorType *ShuffleVecTy = Shuffles[0]->getType();
+ uint64_t ShuffleVecSize = DL.getTypeSizeInBits(ShuffleVecTy);
+ Type *ShuffleEltTy = ShuffleVecTy->getVectorElementType();
+
+ if (DL.getTypeSizeInBits(Inst->getType()) < Factor * ShuffleVecSize)
+ return false;
+
+ // Currently, lowering is supported for 64 bits on AVX.
+ if (!Subtarget.hasAVX() || ShuffleVecSize != 256 ||
+ DL.getTypeSizeInBits(ShuffleEltTy) != 64 || Factor != 4)
+ return false;
+
+ return true;
+}
+
+bool X86InterleavedAccessGroup::decompose(
+ Instruction *VecInst, unsigned NumSubVectors, VectorType *SubVecTy,
+ SmallVectorImpl<Instruction *> &DecomposedVectors) {
+ Type *VecTy = VecInst->getType();
+ (void)VecTy;
+ assert(VecTy->isVectorTy() &&
+ DL.getTypeSizeInBits(VecTy) >=
+ DL.getTypeSizeInBits(SubVecTy) * NumSubVectors &&
+ "Invalid Inst-size!!!");
+ assert(VecTy->getVectorElementType() == SubVecTy->getVectorElementType() &&
+ "Element type mismatched!!!");
+
+ if (!isa<LoadInst>(VecInst))
+ return false;
+
+ LoadInst *LI = cast<LoadInst>(VecInst);
+ Type *VecBasePtrTy = SubVecTy->getPointerTo(LI->getPointerAddressSpace());
+
+ Value *VecBasePtr =
+ Builder.CreateBitCast(LI->getPointerOperand(), VecBasePtrTy);
+
+ // Generate N loads of T type
+ for (unsigned i = 0; i < NumSubVectors; i++) {
+ // TODO: Support inbounds GEP
+ Value *NewBasePtr = Builder.CreateGEP(VecBasePtr, Builder.getInt32(i));
+ Instruction *NewLoad =
+ Builder.CreateAlignedLoad(NewBasePtr, LI->getAlignment());
+ DecomposedVectors.push_back(NewLoad);
+ }
+
+ return true;
+}
+
+void X86InterleavedAccessGroup::transpose_4x4(
+ ArrayRef<Instruction *> Matrix,
+ SmallVectorImpl<Value *> &TransposedMatrix) {
+ assert(Matrix.size() == 4 && "Invalid matrix size");
+ TransposedMatrix.resize(4);
+
+ // dst = src1[0,1],src2[0,1]
+ uint32_t IntMask1[] = {0, 1, 4, 5};
+ ArrayRef<uint32_t> Mask = makeArrayRef(IntMask1, 4);
+ Value *IntrVec1 = Builder.CreateShuffleVector(Matrix[0], Matrix[2], Mask);
+ Value *IntrVec2 = Builder.CreateShuffleVector(Matrix[1], Matrix[3], Mask);
+
+ // dst = src1[2,3],src2[2,3]
+ uint32_t IntMask2[] = {2, 3, 6, 7};
+ Mask = makeArrayRef(IntMask2, 4);
+ Value *IntrVec3 = Builder.CreateShuffleVector(Matrix[0], Matrix[2], Mask);
+ Value *IntrVec4 = Builder.CreateShuffleVector(Matrix[1], Matrix[3], Mask);
+
+ // dst = src1[0],src2[0],src1[2],src2[2]
+ uint32_t IntMask3[] = {0, 4, 2, 6};
+ Mask = makeArrayRef(IntMask3, 4);
+ TransposedMatrix[0] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, Mask);
+ TransposedMatrix[2] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, Mask);
+
+ // dst = src1[1],src2[1],src1[3],src2[3]
+ uint32_t IntMask4[] = {1, 5, 3, 7};
+ Mask = makeArrayRef(IntMask4, 4);
+ TransposedMatrix[1] = Builder.CreateShuffleVector(IntrVec1, IntrVec2, Mask);
+ TransposedMatrix[3] = Builder.CreateShuffleVector(IntrVec3, IntrVec4, Mask);
+}
+
+// Lowers this interleaved access group into X86-specific
+// instructions/intrinsics.
+bool X86InterleavedAccessGroup::lowerIntoOptimizedSequence() {
+ SmallVector<Instruction *, 4> DecomposedVectors;
+ VectorType *VecTy = Shuffles[0]->getType();
+ // Try to generate target-sized register(/instruction).
+ if (!decompose(Inst, Factor, VecTy, DecomposedVectors))
+ return false;
+
+ SmallVector<Value *, 4> TransposedVectors;
+ // Perform matrix-transposition in order to compute interleaved
+ // results by generating some sort of (optimized) target-specific
+ // instructions.
+ transpose_4x4(DecomposedVectors, TransposedVectors);
+
+ // Now replace the unoptimized-interleaved-vectors with the
+ // transposed-interleaved vectors.
+ for (unsigned i = 0; i < Shuffles.size(); i++)
+ Shuffles[i]->replaceAllUsesWith(TransposedVectors[Indices[i]]);
+
+ return true;
+}
+
+// Lower interleaved load(s) into target specific instructions/
+// intrinsics. Lowering sequence varies depending on the vector-types, factor,
+// number of shuffles and ISA.
+// Currently, lowering is supported for 4x64 bits with Factor = 4 on AVX.
+bool X86TargetLowering::lowerInterleavedLoad(
+ LoadInst *LI, ArrayRef<ShuffleVectorInst *> Shuffles,
+ ArrayRef<unsigned> Indices, unsigned Factor) const {
+ assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() &&
+ "Invalid interleave factor");
+ assert(!Shuffles.empty() && "Empty shufflevector input");
+ assert(Shuffles.size() == Indices.size() &&
+ "Unmatched number of shufflevectors and indices");
+
+ // Create an interleaved access group.
+ IRBuilder<> Builder(LI);
+ X86InterleavedAccessGroup Grp(LI, Shuffles, Indices, Factor, Subtarget,
+ Builder);
+
+ return Grp.isSupported() && Grp.lowerIntoOptimizedSequence();
+}
diff --git a/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h b/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h
index b647d11..63a02af 100644
--- a/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h
+++ b/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h
@@ -21,9 +21,10 @@ namespace llvm {
enum IntrinsicType : uint16_t {
INTR_NO_TYPE,
- GATHER, SCATTER, PREFETCH, RDSEED, RDRAND, RDPMC, RDTSC, XTEST, ADX, FPCLASS, FPCLASSS,
- INTR_TYPE_1OP, INTR_TYPE_2OP, INTR_TYPE_2OP_IMM8, INTR_TYPE_3OP, INTR_TYPE_4OP,
+ GATHER, SCATTER, PREFETCH, RDSEED, RDRAND, RDPMC, RDTSC, XTEST, XGETBV, ADX, FPCLASS, FPCLASSS,
+ INTR_TYPE_1OP, INTR_TYPE_2OP, INTR_TYPE_3OP, INTR_TYPE_4OP,
CMP_MASK, CMP_MASK_CC,CMP_MASK_SCALAR_CC, VSHIFT, COMI, COMI_RM,
+ CVTPD2PS, CVTPD2PS_MASK,
INTR_TYPE_1OP_MASK, INTR_TYPE_1OP_MASK_RM,
INTR_TYPE_2OP_MASK, INTR_TYPE_2OP_MASK_RM, INTR_TYPE_2OP_IMM8_MASK,
INTR_TYPE_3OP_MASK, INTR_TYPE_3OP_MASK_RM, INTR_TYPE_3OP_IMM8_MASK,
@@ -33,7 +34,7 @@ enum IntrinsicType : uint16_t {
INTR_TYPE_SCALAR_MASK_RM, INTR_TYPE_3OP_SCALAR_MASK_RM,
COMPRESS_EXPAND_IN_REG, COMPRESS_TO_MEM, BRCST_SUBVEC_TO_VEC, BRCST32x2_TO_VEC,
TRUNCATE_TO_MEM_VI8, TRUNCATE_TO_MEM_VI16, TRUNCATE_TO_MEM_VI32,
- EXPAND_FROM_MEM, INSERT_SUBVEC,
+ EXPAND_FROM_MEM,
TERLOG_OP_MASK, TERLOG_OP_MASKZ, BROADCASTM, KUNPCK, FIXUPIMM, FIXUPIMM_MASKZ, FIXUPIMMS,
FIXUPIMMS_MASKZ, CONVERT_MASK_TO_VEC, CONVERT_TO_MASK
};
@@ -184,6 +185,79 @@ static const IntrinsicData IntrinsicsWithChain[] = {
X86ISD::VTRUNC, 0),
X86_INTRINSIC_DATA(avx512_mask_pmov_wb_mem_512, TRUNCATE_TO_MEM_VI8,
X86ISD::VTRUNC, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_db_mem_128, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_db_mem_256, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_db_mem_512, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_dw_mem_128, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_dw_mem_256, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_dw_mem_512, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qb_mem_128, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qb_mem_256, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qb_mem_512, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qd_mem_128, TRUNCATE_TO_MEM_VI32,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qd_mem_256, TRUNCATE_TO_MEM_VI32,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qd_mem_512, TRUNCATE_TO_MEM_VI32,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qw_mem_128, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qw_mem_256, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_qw_mem_512, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_wb_mem_128, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_wb_mem_256, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovs_wb_mem_512, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_db_mem_128, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_db_mem_256, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_db_mem_512, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_dw_mem_128, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_dw_mem_256, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_dw_mem_512, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qb_mem_128, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qb_mem_256, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qb_mem_512, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qd_mem_128, TRUNCATE_TO_MEM_VI32,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qd_mem_256, TRUNCATE_TO_MEM_VI32,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qd_mem_512, TRUNCATE_TO_MEM_VI32,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qw_mem_128, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qw_mem_256, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_qw_mem_512, TRUNCATE_TO_MEM_VI16,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_wb_mem_128, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_wb_mem_256, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_pmovus_wb_mem_512, TRUNCATE_TO_MEM_VI8,
+ X86ISD::VTRUNCUS, 0),
+
X86_INTRINSIC_DATA(avx512_scatter_dpd_512, SCATTER, X86::VSCATTERDPDZmr, 0),
X86_INTRINSIC_DATA(avx512_scatter_dpi_512, SCATTER, X86::VPSCATTERDDZmr, 0),
X86_INTRINSIC_DATA(avx512_scatter_dpq_512, SCATTER, X86::VPSCATTERDQZmr, 0),
@@ -228,6 +302,7 @@ static const IntrinsicData IntrinsicsWithChain[] = {
X86_INTRINSIC_DATA(subborrow_u32, ADX, X86ISD::SBB, 0),
X86_INTRINSIC_DATA(subborrow_u64, ADX, X86ISD::SBB, 0),
+ X86_INTRINSIC_DATA(xgetbv, XGETBV, X86::XGETBV, 0),
X86_INTRINSIC_DATA(xtest, XTEST, X86ISD::XTEST, 0),
};
@@ -250,6 +325,11 @@ static const IntrinsicData* getIntrinsicWithChain(uint16_t IntNo) {
* the alphabetical order.
*/
static const IntrinsicData IntrinsicsWithoutChain[] = {
+ X86_INTRINSIC_DATA(avx_cvt_pd2_ps_256,CVTPD2PS, ISD::FP_ROUND, 0),
+ X86_INTRINSIC_DATA(avx_cvt_pd2dq_256, INTR_TYPE_1OP, X86ISD::CVTP2SI, 0),
+ X86_INTRINSIC_DATA(avx_cvtdq2_ps_256, INTR_TYPE_1OP, ISD::SINT_TO_FP, 0),
+ X86_INTRINSIC_DATA(avx_cvtt_pd2dq_256,INTR_TYPE_1OP, ISD::FP_TO_SINT, 0),
+ X86_INTRINSIC_DATA(avx_cvtt_ps2dq_256,INTR_TYPE_1OP, ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx_hadd_pd_256, INTR_TYPE_2OP, X86ISD::FHADD, 0),
X86_INTRINSIC_DATA(avx_hadd_ps_256, INTR_TYPE_2OP, X86ISD::FHADD, 0),
X86_INTRINSIC_DATA(avx_hsub_pd_256, INTR_TYPE_2OP, X86ISD::FHSUB, 0),
@@ -288,8 +368,11 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx2_phadd_w, INTR_TYPE_2OP, X86ISD::HADD, 0),
X86_INTRINSIC_DATA(avx2_phsub_d, INTR_TYPE_2OP, X86ISD::HSUB, 0),
X86_INTRINSIC_DATA(avx2_phsub_w, INTR_TYPE_2OP, X86ISD::HSUB, 0),
+ X86_INTRINSIC_DATA(avx2_pmadd_ub_sw, INTR_TYPE_2OP, X86ISD::VPMADDUBSW, 0),
+ X86_INTRINSIC_DATA(avx2_pmadd_wd, INTR_TYPE_2OP, X86ISD::VPMADDWD, 0),
X86_INTRINSIC_DATA(avx2_pmovmskb, INTR_TYPE_1OP, X86ISD::MOVMSK, 0),
X86_INTRINSIC_DATA(avx2_pmul_dq, INTR_TYPE_2OP, X86ISD::PMULDQ, 0),
+ X86_INTRINSIC_DATA(avx2_pmul_hr_sw, INTR_TYPE_2OP, X86ISD::MULHRS, 0),
X86_INTRINSIC_DATA(avx2_pmulh_w, INTR_TYPE_2OP, ISD::MULHS, 0),
X86_INTRINSIC_DATA(avx2_pmulhu_w, INTR_TYPE_2OP, ISD::MULHU, 0),
X86_INTRINSIC_DATA(avx2_pmulu_dq, INTR_TYPE_2OP, X86ISD::PMULUDQ, 0),
@@ -353,21 +436,20 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_cvtq2mask_128, CONVERT_TO_MASK, X86ISD::CVT2MASK, 0),
X86_INTRINSIC_DATA(avx512_cvtq2mask_256, CONVERT_TO_MASK, X86ISD::CVT2MASK, 0),
X86_INTRINSIC_DATA(avx512_cvtq2mask_512, CONVERT_TO_MASK, X86ISD::CVT2MASK, 0),
- X86_INTRINSIC_DATA(avx512_cvtsi2sd32, INTR_TYPE_3OP, X86ISD::SINT_TO_FP_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvtsi2sd64, INTR_TYPE_3OP, X86ISD::SINT_TO_FP_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvtsi2ss32, INTR_TYPE_3OP, X86ISD::SINT_TO_FP_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvtsi2ss64, INTR_TYPE_3OP, X86ISD::SINT_TO_FP_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttsd2si, INTR_TYPE_2OP, X86ISD::FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttsd2si64, INTR_TYPE_2OP, X86ISD::FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttsd2usi, INTR_TYPE_2OP, X86ISD::FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttsd2usi64, INTR_TYPE_2OP, X86ISD::FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttss2si, INTR_TYPE_2OP, X86ISD::FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttss2si64, INTR_TYPE_2OP, X86ISD::FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttss2usi, INTR_TYPE_2OP, X86ISD::FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvttss2usi64, INTR_TYPE_2OP, X86ISD::FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvtusi2ss, INTR_TYPE_3OP, X86ISD::UINT_TO_FP_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvtusi642sd, INTR_TYPE_3OP, X86ISD::UINT_TO_FP_RND, 0),
- X86_INTRINSIC_DATA(avx512_cvtusi642ss, INTR_TYPE_3OP, X86ISD::UINT_TO_FP_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvtsi2sd64, INTR_TYPE_3OP, X86ISD::SCALAR_SINT_TO_FP_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvtsi2ss32, INTR_TYPE_3OP, X86ISD::SCALAR_SINT_TO_FP_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvtsi2ss64, INTR_TYPE_3OP, X86ISD::SCALAR_SINT_TO_FP_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttsd2si, INTR_TYPE_2OP, X86ISD::CVTTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttsd2si64, INTR_TYPE_2OP, X86ISD::CVTTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttsd2usi, INTR_TYPE_2OP, X86ISD::CVTTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttsd2usi64, INTR_TYPE_2OP, X86ISD::CVTTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttss2si, INTR_TYPE_2OP, X86ISD::CVTTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttss2si64, INTR_TYPE_2OP, X86ISD::CVTTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttss2usi, INTR_TYPE_2OP, X86ISD::CVTTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvttss2usi64, INTR_TYPE_2OP, X86ISD::CVTTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvtusi2ss, INTR_TYPE_3OP, X86ISD::SCALAR_UINT_TO_FP_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvtusi642sd, INTR_TYPE_3OP, X86ISD::SCALAR_UINT_TO_FP_RND, 0),
+ X86_INTRINSIC_DATA(avx512_cvtusi642ss, INTR_TYPE_3OP, X86ISD::SCALAR_UINT_TO_FP_RND, 0),
X86_INTRINSIC_DATA(avx512_cvtw2mask_128, CONVERT_TO_MASK, X86ISD::CVT2MASK, 0),
X86_INTRINSIC_DATA(avx512_cvtw2mask_256, CONVERT_TO_MASK, X86ISD::CVT2MASK, 0),
X86_INTRINSIC_DATA(avx512_cvtw2mask_512, CONVERT_TO_MASK, X86ISD::CVT2MASK, 0),
@@ -377,30 +459,14 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_kunpck_dq, KUNPCK, ISD::CONCAT_VECTORS, 0),
X86_INTRINSIC_DATA(avx512_kunpck_wd, KUNPCK, ISD::CONCAT_VECTORS, 0),
- X86_INTRINSIC_DATA(avx512_mask_add_pd_128, INTR_TYPE_2OP_MASK, ISD::FADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_add_pd_256, INTR_TYPE_2OP_MASK, ISD::FADD, 0),
X86_INTRINSIC_DATA(avx512_mask_add_pd_512, INTR_TYPE_2OP_MASK, ISD::FADD,
X86ISD::FADD_RND),
- X86_INTRINSIC_DATA(avx512_mask_add_ps_128, INTR_TYPE_2OP_MASK, ISD::FADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_add_ps_256, INTR_TYPE_2OP_MASK, ISD::FADD, 0),
X86_INTRINSIC_DATA(avx512_mask_add_ps_512, INTR_TYPE_2OP_MASK, ISD::FADD,
X86ISD::FADD_RND),
- X86_INTRINSIC_DATA(avx512_mask_add_sd_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FADD,
- X86ISD::FADD_RND),
- X86_INTRINSIC_DATA(avx512_mask_add_ss_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FADD,
- X86ISD::FADD_RND),
- X86_INTRINSIC_DATA(avx512_mask_and_pd_128, INTR_TYPE_2OP_MASK, X86ISD::FAND, 0),
- X86_INTRINSIC_DATA(avx512_mask_and_pd_256, INTR_TYPE_2OP_MASK, X86ISD::FAND, 0),
- X86_INTRINSIC_DATA(avx512_mask_and_pd_512, INTR_TYPE_2OP_MASK, X86ISD::FAND, 0),
- X86_INTRINSIC_DATA(avx512_mask_and_ps_128, INTR_TYPE_2OP_MASK, X86ISD::FAND, 0),
- X86_INTRINSIC_DATA(avx512_mask_and_ps_256, INTR_TYPE_2OP_MASK, X86ISD::FAND, 0),
- X86_INTRINSIC_DATA(avx512_mask_and_ps_512, INTR_TYPE_2OP_MASK, X86ISD::FAND, 0),
- X86_INTRINSIC_DATA(avx512_mask_andn_pd_128, INTR_TYPE_2OP_MASK, X86ISD::FANDN, 0),
- X86_INTRINSIC_DATA(avx512_mask_andn_pd_256, INTR_TYPE_2OP_MASK, X86ISD::FANDN, 0),
- X86_INTRINSIC_DATA(avx512_mask_andn_pd_512, INTR_TYPE_2OP_MASK, X86ISD::FANDN, 0),
- X86_INTRINSIC_DATA(avx512_mask_andn_ps_128, INTR_TYPE_2OP_MASK, X86ISD::FANDN, 0),
- X86_INTRINSIC_DATA(avx512_mask_andn_ps_256, INTR_TYPE_2OP_MASK, X86ISD::FANDN, 0),
- X86_INTRINSIC_DATA(avx512_mask_andn_ps_512, INTR_TYPE_2OP_MASK, X86ISD::FANDN, 0),
+ X86_INTRINSIC_DATA(avx512_mask_add_sd_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FADD_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask_add_ss_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FADD_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_broadcastf32x2_256, BRCST32x2_TO_VEC,
X86ISD::VBROADCAST, 0),
X86_INTRINSIC_DATA(avx512_mask_broadcastf32x2_512, BRCST32x2_TO_VEC,
@@ -452,10 +518,10 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_cmp_q_128, CMP_MASK_CC, X86ISD::CMPM, 0),
X86_INTRINSIC_DATA(avx512_mask_cmp_q_256, CMP_MASK_CC, X86ISD::CMPM, 0),
X86_INTRINSIC_DATA(avx512_mask_cmp_q_512, CMP_MASK_CC, X86ISD::CMPM, 0),
- X86_INTRINSIC_DATA(avx512_mask_cmp_sd, CMP_MASK_SCALAR_CC, X86ISD::FSETCC,
- X86ISD::FSETCC),
- X86_INTRINSIC_DATA(avx512_mask_cmp_ss, CMP_MASK_SCALAR_CC, X86ISD::FSETCC,
- X86ISD::FSETCC),
+ X86_INTRINSIC_DATA(avx512_mask_cmp_sd, CMP_MASK_SCALAR_CC,
+ X86ISD::FSETCCM, X86ISD::FSETCCM_RND),
+ X86_INTRINSIC_DATA(avx512_mask_cmp_ss, CMP_MASK_SCALAR_CC,
+ X86ISD::FSETCCM, X86ISD::FSETCCM_RND),
X86_INTRINSIC_DATA(avx512_mask_cmp_w_128, CMP_MASK_CC, X86ISD::CMPM, 0),
X86_INTRINSIC_DATA(avx512_mask_cmp_w_256, CMP_MASK_CC, X86ISD::CMPM, 0),
X86_INTRINSIC_DATA(avx512_mask_cmp_w_512, CMP_MASK_CC, X86ISD::CMPM, 0),
@@ -495,184 +561,168 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::CONFLICT, 0),
X86_INTRINSIC_DATA(avx512_mask_conflict_q_512, INTR_TYPE_1OP_MASK,
X86ISD::CONFLICT, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtdq2pd_128, INTR_TYPE_1OP_MASK,
- X86ISD::CVTDQ2PD, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtdq2pd_256, INTR_TYPE_1OP_MASK,
- ISD::SINT_TO_FP, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtdq2pd_512, INTR_TYPE_1OP_MASK,
- ISD::SINT_TO_FP, 0), // no rm
X86_INTRINSIC_DATA(avx512_mask_cvtdq2ps_128, INTR_TYPE_1OP_MASK,
ISD::SINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtdq2ps_256, INTR_TYPE_1OP_MASK,
ISD::SINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtdq2ps_512, INTR_TYPE_1OP_MASK,
- ISD::SINT_TO_FP, ISD::SINT_TO_FP), //er
+ ISD::SINT_TO_FP, X86ISD::SINT_TO_FP_RND), //er
X86_INTRINSIC_DATA(avx512_mask_cvtpd2dq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2dq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2dq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, X86ISD::FP_TO_SINT_RND),
+ X86ISD::CVTP2SI, X86ISD::CVTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2ps, INTR_TYPE_1OP_MASK,
X86ISD::VFPROUND, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtpd2ps_256, INTR_TYPE_1OP_MASK_RM,
+ X86_INTRINSIC_DATA(avx512_mask_cvtpd2ps_256, CVTPD2PS_MASK,
ISD::FP_ROUND, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtpd2ps_512, INTR_TYPE_1OP_MASK_RM,
- ISD::FP_ROUND, X86ISD::VFPROUND),
+ X86_INTRINSIC_DATA(avx512_mask_cvtpd2ps_512, CVTPD2PS_MASK,
+ ISD::FP_ROUND, X86ISD::VFPROUND_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2qq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2qq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2qq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, X86ISD::FP_TO_SINT_RND),
+ X86ISD::CVTP2SI, X86ISD::CVTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2udq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2udq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2udq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, X86ISD::FP_TO_UINT_RND),
+ X86ISD::CVTP2UI, X86ISD::CVTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2uqq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2uqq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtpd2uqq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, X86ISD::FP_TO_UINT_RND),
+ X86ISD::CVTP2UI, X86ISD::CVTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtps2dq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2dq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2dq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, X86ISD::FP_TO_SINT_RND),
+ X86ISD::CVTP2SI, X86ISD::CVTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtps2pd_128, INTR_TYPE_1OP_MASK,
X86ISD::VFPEXT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2pd_256, INTR_TYPE_1OP_MASK,
ISD::FP_EXTEND, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2pd_512, INTR_TYPE_1OP_MASK,
- ISD::FP_EXTEND, X86ISD::VFPEXT),
+ ISD::FP_EXTEND, X86ISD::VFPEXT_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtps2qq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2qq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, 0),
+ X86ISD::CVTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2qq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_SINT_RND, X86ISD::FP_TO_SINT_RND),
+ X86ISD::CVTP2SI, X86ISD::CVTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtps2udq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2udq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2udq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, X86ISD::FP_TO_UINT_RND),
+ X86ISD::CVTP2UI, X86ISD::CVTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtps2uqq_128, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2uqq_256, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, 0),
+ X86ISD::CVTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtps2uqq_512, INTR_TYPE_1OP_MASK,
- X86ISD::FP_TO_UINT_RND, X86ISD::FP_TO_UINT_RND),
+ X86ISD::CVTP2UI, X86ISD::CVTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtqq2pd_128, INTR_TYPE_1OP_MASK,
ISD::SINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtqq2pd_256, INTR_TYPE_1OP_MASK,
ISD::SINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtqq2pd_512, INTR_TYPE_1OP_MASK,
- ISD::SINT_TO_FP, ISD::SINT_TO_FP),
+ ISD::SINT_TO_FP, X86ISD::SINT_TO_FP_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtqq2ps_128, INTR_TYPE_1OP_MASK,
- ISD::SINT_TO_FP, 0),
+ X86ISD::CVTSI2P, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtqq2ps_256, INTR_TYPE_1OP_MASK,
ISD::SINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtqq2ps_512, INTR_TYPE_1OP_MASK,
- ISD::SINT_TO_FP, ISD::SINT_TO_FP),
+ ISD::SINT_TO_FP, X86ISD::SINT_TO_FP_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtsd2ss_round, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::VFPROUND, 0),
+ X86ISD::VFPROUNDS_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtss2sd_round, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::VFPEXT, 0),
+ X86ISD::VFPEXTS_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2dq_128, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_SINT, 0),
+ X86ISD::CVTTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2dq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2dq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_SINT, ISD::FP_TO_SINT),
+ ISD::FP_TO_SINT, X86ISD::CVTTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2qq_128, INTR_TYPE_1OP_MASK,
ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2qq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2qq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_SINT, ISD::FP_TO_SINT),
+ ISD::FP_TO_SINT, X86ISD::CVTTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2udq_128, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_UINT, 0),
+ X86ISD::CVTTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2udq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_UINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2udq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_UINT, ISD::FP_TO_UINT),
+ ISD::FP_TO_UINT, X86ISD::CVTTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2uqq_128, INTR_TYPE_1OP_MASK,
ISD::FP_TO_UINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2uqq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_UINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttpd2uqq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_UINT, ISD::FP_TO_UINT),
+ ISD::FP_TO_UINT, X86ISD::CVTTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttps2dq_128, INTR_TYPE_1OP_MASK,
ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2dq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2dq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_SINT, ISD::FP_TO_SINT),
+ ISD::FP_TO_SINT, X86ISD::CVTTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttps2qq_128, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_SINT, 0),
+ X86ISD::CVTTP2SI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2qq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2qq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_SINT, ISD::FP_TO_SINT),
+ ISD::FP_TO_SINT, X86ISD::CVTTP2SI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttps2udq_128, INTR_TYPE_1OP_MASK,
ISD::FP_TO_UINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2udq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_UINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2udq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_UINT, ISD::FP_TO_UINT),
+ ISD::FP_TO_UINT, X86ISD::CVTTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvttps2uqq_128, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_UINT, 0),
+ X86ISD::CVTTP2UI, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2uqq_256, INTR_TYPE_1OP_MASK,
ISD::FP_TO_UINT, 0),
X86_INTRINSIC_DATA(avx512_mask_cvttps2uqq_512, INTR_TYPE_1OP_MASK,
- ISD::FP_TO_UINT, ISD::FP_TO_UINT),
- X86_INTRINSIC_DATA(avx512_mask_cvtudq2pd_128, INTR_TYPE_1OP_MASK,
- X86ISD::CVTUDQ2PD, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtudq2pd_256, INTR_TYPE_1OP_MASK,
- ISD::UINT_TO_FP, 0),
- X86_INTRINSIC_DATA(avx512_mask_cvtudq2pd_512, INTR_TYPE_1OP_MASK,
- ISD::UINT_TO_FP, 0), // no rm
+ ISD::FP_TO_UINT, X86ISD::CVTTP2UI_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtudq2ps_128, INTR_TYPE_1OP_MASK,
ISD::UINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtudq2ps_256, INTR_TYPE_1OP_MASK,
ISD::UINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtudq2ps_512, INTR_TYPE_1OP_MASK,
- ISD::UINT_TO_FP, ISD::UINT_TO_FP),
+ ISD::UINT_TO_FP, X86ISD::UINT_TO_FP_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtuqq2pd_128, INTR_TYPE_1OP_MASK,
ISD::UINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtuqq2pd_256, INTR_TYPE_1OP_MASK,
ISD::UINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtuqq2pd_512, INTR_TYPE_1OP_MASK,
- ISD::UINT_TO_FP, ISD::UINT_TO_FP),
+ ISD::UINT_TO_FP, X86ISD::UINT_TO_FP_RND),
X86_INTRINSIC_DATA(avx512_mask_cvtuqq2ps_128, INTR_TYPE_1OP_MASK,
- ISD::UINT_TO_FP, 0),
+ X86ISD::CVTUI2P, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtuqq2ps_256, INTR_TYPE_1OP_MASK,
ISD::UINT_TO_FP, 0),
X86_INTRINSIC_DATA(avx512_mask_cvtuqq2ps_512, INTR_TYPE_1OP_MASK,
- ISD::UINT_TO_FP, ISD::UINT_TO_FP),
+ ISD::UINT_TO_FP, X86ISD::UINT_TO_FP_RND),
X86_INTRINSIC_DATA(avx512_mask_dbpsadbw_128, INTR_TYPE_3OP_IMM8_MASK,
X86ISD::DBPSADBW, 0),
X86_INTRINSIC_DATA(avx512_mask_dbpsadbw_256, INTR_TYPE_3OP_IMM8_MASK,
X86ISD::DBPSADBW, 0),
X86_INTRINSIC_DATA(avx512_mask_dbpsadbw_512, INTR_TYPE_3OP_IMM8_MASK,
X86ISD::DBPSADBW, 0),
- X86_INTRINSIC_DATA(avx512_mask_div_pd_128, INTR_TYPE_2OP_MASK, ISD::FDIV, 0),
- X86_INTRINSIC_DATA(avx512_mask_div_pd_256, INTR_TYPE_2OP_MASK, ISD::FDIV, 0),
X86_INTRINSIC_DATA(avx512_mask_div_pd_512, INTR_TYPE_2OP_MASK, ISD::FDIV,
X86ISD::FDIV_RND),
- X86_INTRINSIC_DATA(avx512_mask_div_ps_128, INTR_TYPE_2OP_MASK, ISD::FDIV, 0),
- X86_INTRINSIC_DATA(avx512_mask_div_ps_256, INTR_TYPE_2OP_MASK, ISD::FDIV, 0),
X86_INTRINSIC_DATA(avx512_mask_div_ps_512, INTR_TYPE_2OP_MASK, ISD::FDIV,
X86ISD::FDIV_RND),
- X86_INTRINSIC_DATA(avx512_mask_div_sd_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FDIV,
- X86ISD::FDIV_RND),
- X86_INTRINSIC_DATA(avx512_mask_div_ss_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FDIV,
- X86ISD::FDIV_RND),
+ X86_INTRINSIC_DATA(avx512_mask_div_sd_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FDIV_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask_div_ss_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FDIV_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_expand_d_128, COMPRESS_EXPAND_IN_REG,
X86ISD::EXPAND, 0),
X86_INTRINSIC_DATA(avx512_mask_expand_d_256, COMPRESS_EXPAND_IN_REG,
@@ -726,9 +776,9 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_getexp_ps_512, INTR_TYPE_1OP_MASK_RM,
X86ISD::FGETEXP_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_getexp_sd, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FGETEXP_RND, 0),
+ X86ISD::FGETEXPS_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_getexp_ss, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FGETEXP_RND, 0),
+ X86ISD::FGETEXPS_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_getmant_pd_128, INTR_TYPE_2OP_MASK_RM,
X86ISD::VGETMANT, 0),
X86_INTRINSIC_DATA(avx512_mask_getmant_pd_256, INTR_TYPE_2OP_MASK_RM,
@@ -742,33 +792,9 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_getmant_ps_512, INTR_TYPE_2OP_MASK_RM,
X86ISD::VGETMANT, 0),
X86_INTRINSIC_DATA(avx512_mask_getmant_sd, INTR_TYPE_3OP_SCALAR_MASK_RM,
- X86ISD::VGETMANT, 0),
+ X86ISD::VGETMANTS, 0),
X86_INTRINSIC_DATA(avx512_mask_getmant_ss, INTR_TYPE_3OP_SCALAR_MASK_RM,
- X86ISD::VGETMANT, 0),
- X86_INTRINSIC_DATA(avx512_mask_insertf32x4_256, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_insertf32x4_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_insertf32x8_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_insertf64x2_256, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_insertf64x2_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_insertf64x4_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_inserti32x4_256, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_inserti32x4_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_inserti32x8_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_inserti64x2_256, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_inserti64x2_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_inserti64x4_512, INSERT_SUBVEC,
- ISD::INSERT_SUBVECTOR, 0),
+ X86ISD::VGETMANTS, 0),
X86_INTRINSIC_DATA(avx512_mask_lzcnt_d_128, INTR_TYPE_1OP_MASK,
ISD::CTLZ, 0),
X86_INTRINSIC_DATA(avx512_mask_lzcnt_d_256, INTR_TYPE_1OP_MASK,
@@ -790,9 +816,9 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_max_ps_512, INTR_TYPE_2OP_MASK, X86ISD::FMAX,
X86ISD::FMAX_RND),
X86_INTRINSIC_DATA(avx512_mask_max_sd_round, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FMAX, X86ISD::FMAX_RND),
+ X86ISD::FMAX_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_max_ss_round, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FMAX, X86ISD::FMAX_RND),
+ X86ISD::FMAX_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_min_pd_128, INTR_TYPE_2OP_MASK, X86ISD::FMIN, 0),
X86_INTRINSIC_DATA(avx512_mask_min_pd_256, INTR_TYPE_2OP_MASK, X86ISD::FMIN, 0),
X86_INTRINSIC_DATA(avx512_mask_min_pd_512, INTR_TYPE_2OP_MASK, X86ISD::FMIN,
@@ -802,31 +828,17 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_min_ps_512, INTR_TYPE_2OP_MASK, X86ISD::FMIN,
X86ISD::FMIN_RND),
X86_INTRINSIC_DATA(avx512_mask_min_sd_round, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FMIN, X86ISD::FMIN_RND),
+ X86ISD::FMIN_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_min_ss_round, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FMIN, X86ISD::FMIN_RND),
- X86_INTRINSIC_DATA(avx512_mask_move_sd, INTR_TYPE_SCALAR_MASK,
- X86ISD::MOVSD, 0),
- X86_INTRINSIC_DATA(avx512_mask_move_ss, INTR_TYPE_SCALAR_MASK,
- X86ISD::MOVSS, 0),
- X86_INTRINSIC_DATA(avx512_mask_mul_pd_128, INTR_TYPE_2OP_MASK, ISD::FMUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_mul_pd_256, INTR_TYPE_2OP_MASK, ISD::FMUL, 0),
+ X86ISD::FMIN_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_mul_pd_512, INTR_TYPE_2OP_MASK, ISD::FMUL,
X86ISD::FMUL_RND),
- X86_INTRINSIC_DATA(avx512_mask_mul_ps_128, INTR_TYPE_2OP_MASK, ISD::FMUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_mul_ps_256, INTR_TYPE_2OP_MASK, ISD::FMUL, 0),
X86_INTRINSIC_DATA(avx512_mask_mul_ps_512, INTR_TYPE_2OP_MASK, ISD::FMUL,
X86ISD::FMUL_RND),
- X86_INTRINSIC_DATA(avx512_mask_mul_sd_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FMUL,
- X86ISD::FMUL_RND),
- X86_INTRINSIC_DATA(avx512_mask_mul_ss_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FMUL,
- X86ISD::FMUL_RND),
- X86_INTRINSIC_DATA(avx512_mask_or_pd_128, INTR_TYPE_2OP_MASK, X86ISD::FOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_or_pd_256, INTR_TYPE_2OP_MASK, X86ISD::FOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_or_pd_512, INTR_TYPE_2OP_MASK, X86ISD::FOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_or_ps_128, INTR_TYPE_2OP_MASK, X86ISD::FOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_or_ps_256, INTR_TYPE_2OP_MASK, X86ISD::FOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_or_ps_512, INTR_TYPE_2OP_MASK, X86ISD::FOR, 0),
+ X86_INTRINSIC_DATA(avx512_mask_mul_sd_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FMUL_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask_mul_ss_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FMUL_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_pabs_b_128, INTR_TYPE_1OP_MASK, X86ISD::ABS, 0),
X86_INTRINSIC_DATA(avx512_mask_pabs_b_256, INTR_TYPE_1OP_MASK, X86ISD::ABS, 0),
X86_INTRINSIC_DATA(avx512_mask_pabs_b_512, INTR_TYPE_1OP_MASK, X86ISD::ABS, 0),
@@ -851,18 +863,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_packuswb_128, INTR_TYPE_2OP_MASK, X86ISD::PACKUS, 0),
X86_INTRINSIC_DATA(avx512_mask_packuswb_256, INTR_TYPE_2OP_MASK, X86ISD::PACKUS, 0),
X86_INTRINSIC_DATA(avx512_mask_packuswb_512, INTR_TYPE_2OP_MASK, X86ISD::PACKUS, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_b_128, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_b_256, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_b_512, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_d_128, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_d_256, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_d_512, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_q_128, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_q_256, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_q_512, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_w_128, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_w_256, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
- X86_INTRINSIC_DATA(avx512_mask_padd_w_512, INTR_TYPE_2OP_MASK, ISD::ADD, 0),
X86_INTRINSIC_DATA(avx512_mask_padds_b_128, INTR_TYPE_2OP_MASK, X86ISD::ADDS, 0),
X86_INTRINSIC_DATA(avx512_mask_padds_b_256, INTR_TYPE_2OP_MASK, X86ISD::ADDS, 0),
X86_INTRINSIC_DATA(avx512_mask_padds_b_512, INTR_TYPE_2OP_MASK, X86ISD::ADDS, 0),
@@ -945,54 +945,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::VPMADDWD, 0),
X86_INTRINSIC_DATA(avx512_mask_pmaddw_d_512, INTR_TYPE_2OP_MASK,
X86ISD::VPMADDWD, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_b_128, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_b_256, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_b_512, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_d_128, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_d_256, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_d_512, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_q_128, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_q_256, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_q_512, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_w_128, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_w_256, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxs_w_512, INTR_TYPE_2OP_MASK, ISD::SMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_b_128, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_b_256, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_b_512, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_d_128, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_d_256, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_d_512, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_q_128, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_q_256, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_q_512, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_w_128, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_w_256, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmaxu_w_512, INTR_TYPE_2OP_MASK, ISD::UMAX, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_b_128, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_b_256, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_b_512, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_d_128, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_d_256, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_d_512, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_q_128, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_q_256, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_q_512, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_w_128, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_w_256, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmins_w_512, INTR_TYPE_2OP_MASK, ISD::SMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_b_128, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_b_256, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_b_512, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_d_128, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_d_256, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_d_512, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_q_128, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_q_256, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_q_512, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_w_128, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_w_256, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
- X86_INTRINSIC_DATA(avx512_mask_pminu_w_512, INTR_TYPE_2OP_MASK, ISD::UMIN, 0),
X86_INTRINSIC_DATA(avx512_mask_pmov_db_128, INTR_TYPE_1OP_MASK,
X86ISD::VTRUNC, 0),
X86_INTRINSIC_DATA(avx512_mask_pmov_db_256, INTR_TYPE_1OP_MASK,
@@ -1065,42 +1017,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::VTRUNCS, 0),
X86_INTRINSIC_DATA(avx512_mask_pmovs_wb_512, INTR_TYPE_1OP_MASK,
X86ISD::VTRUNCS, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_d_128, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_d_256, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_d_512, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_q_128, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_q_256, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_q_512, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_w_128, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_w_256, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxb_w_512, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxd_q_128, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxd_q_256, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxd_q_512, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxw_d_128, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxw_d_256, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxw_d_512, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxw_q_128, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxw_q_256, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovsxw_q_512, INTR_TYPE_1OP_MASK,
- X86ISD::VSEXT, 0),
X86_INTRINSIC_DATA(avx512_mask_pmovus_db_128, INTR_TYPE_1OP_MASK,
X86ISD::VTRUNCUS, 0),
X86_INTRINSIC_DATA(avx512_mask_pmovus_db_256, INTR_TYPE_1OP_MASK,
@@ -1137,48 +1053,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::VTRUNCUS, 0),
X86_INTRINSIC_DATA(avx512_mask_pmovus_wb_512, INTR_TYPE_1OP_MASK,
X86ISD::VTRUNCUS, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_d_128, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_d_256, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_d_512, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_q_128, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_q_256, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_q_512, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_w_128, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_w_256, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxb_w_512, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxd_q_128, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxd_q_256, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxd_q_512, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxw_d_128, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxw_d_256, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxw_d_512, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxw_q_128, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxw_q_256, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmovzxw_q_512, INTR_TYPE_1OP_MASK,
- X86ISD::VZEXT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmul_dq_128, INTR_TYPE_2OP_MASK,
- X86ISD::PMULDQ, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmul_dq_256, INTR_TYPE_2OP_MASK,
- X86ISD::PMULDQ, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmul_dq_512, INTR_TYPE_2OP_MASK,
- X86ISD::PMULDQ, 0),
X86_INTRINSIC_DATA(avx512_mask_pmul_hr_sw_128, INTR_TYPE_2OP_MASK, X86ISD::MULHRS, 0),
X86_INTRINSIC_DATA(avx512_mask_pmul_hr_sw_256, INTR_TYPE_2OP_MASK, X86ISD::MULHRS, 0),
X86_INTRINSIC_DATA(avx512_mask_pmul_hr_sw_512, INTR_TYPE_2OP_MASK, X86ISD::MULHRS, 0),
@@ -1188,27 +1062,12 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_pmulhu_w_128, INTR_TYPE_2OP_MASK, ISD::MULHU, 0),
X86_INTRINSIC_DATA(avx512_mask_pmulhu_w_256, INTR_TYPE_2OP_MASK, ISD::MULHU, 0),
X86_INTRINSIC_DATA(avx512_mask_pmulhu_w_512, INTR_TYPE_2OP_MASK, ISD::MULHU, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_d_128, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_d_256, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_d_512, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_q_128, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_q_256, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_q_512, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_w_128, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_w_256, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmull_w_512, INTR_TYPE_2OP_MASK, ISD::MUL, 0),
X86_INTRINSIC_DATA(avx512_mask_pmultishift_qb_128, INTR_TYPE_2OP_MASK,
X86ISD::MULTISHIFT, 0),
X86_INTRINSIC_DATA(avx512_mask_pmultishift_qb_256, INTR_TYPE_2OP_MASK,
X86ISD::MULTISHIFT, 0),
X86_INTRINSIC_DATA(avx512_mask_pmultishift_qb_512, INTR_TYPE_2OP_MASK,
X86ISD::MULTISHIFT, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmulu_dq_128, INTR_TYPE_2OP_MASK,
- X86ISD::PMULUDQ, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmulu_dq_256, INTR_TYPE_2OP_MASK,
- X86ISD::PMULUDQ, 0),
- X86_INTRINSIC_DATA(avx512_mask_pmulu_dq_512, INTR_TYPE_2OP_MASK,
- X86ISD::PMULUDQ, 0),
X86_INTRINSIC_DATA(avx512_mask_prol_d_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VROTLI, 0),
X86_INTRINSIC_DATA(avx512_mask_prol_d_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VROTLI, 0),
X86_INTRINSIC_DATA(avx512_mask_prol_d_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VROTLI, 0),
@@ -1233,105 +1092,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_prorv_q_128, INTR_TYPE_2OP_MASK, ISD::ROTR, 0),
X86_INTRINSIC_DATA(avx512_mask_prorv_q_256, INTR_TYPE_2OP_MASK, ISD::ROTR, 0),
X86_INTRINSIC_DATA(avx512_mask_prorv_q_512, INTR_TYPE_2OP_MASK, ISD::ROTR, 0),
- X86_INTRINSIC_DATA(avx512_mask_pshuf_b_128, INTR_TYPE_2OP_MASK,
- X86ISD::PSHUFB, 0),
- X86_INTRINSIC_DATA(avx512_mask_pshuf_b_256, INTR_TYPE_2OP_MASK,
- X86ISD::PSHUFB, 0),
- X86_INTRINSIC_DATA(avx512_mask_pshuf_b_512, INTR_TYPE_2OP_MASK,
- X86ISD::PSHUFB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_d, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_d_128, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_d_256, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_di_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_di_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_di_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_q, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_q_128, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_q_256, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_qi_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_qi_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_qi_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_w_128, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_w_256, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_w_512, INTR_TYPE_2OP_MASK, X86ISD::VSHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_wi_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_wi_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psll_wi_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSHLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv_d, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv_q, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv16_hi, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv2_di, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv32hi, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv4_di, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv4_si, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv8_hi, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psllv8_si, INTR_TYPE_2OP_MASK, ISD::SHL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_d, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_d_128, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_d_256, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_di_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_di_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_di_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_q, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_q_128, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_q_256, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_qi_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_qi_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_qi_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_w_128, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_w_256, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_w_512, INTR_TYPE_2OP_MASK, X86ISD::VSRA, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_wi_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_wi_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psra_wi_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRAI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav_d, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav_q, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav_q_128, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav_q_256, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav16_hi, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav32_hi, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav4_si, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav8_hi, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrav8_si, INTR_TYPE_2OP_MASK, X86ISD::VSRAV, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_d, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_d_128, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_d_256, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_di_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_di_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_di_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_q, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_q_128, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_q_256, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_qi_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_qi_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_qi_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_w_128, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_w_256, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_w_512, INTR_TYPE_2OP_MASK, X86ISD::VSRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_wi_128, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_wi_256, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrl_wi_512, INTR_TYPE_2OP_IMM8_MASK, X86ISD::VSRLI, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv_d, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv_q, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv16_hi, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv2_di, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv32hi, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv4_di, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv4_si, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv8_hi, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psrlv8_si, INTR_TYPE_2OP_MASK, ISD::SRL, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_b_128, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_b_256, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_b_512, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_d_128, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_d_256, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_d_512, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_q_128, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_q_256, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_q_512, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_w_128, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_w_256, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_psub_w_512, INTR_TYPE_2OP_MASK, ISD::SUB, 0),
X86_INTRINSIC_DATA(avx512_mask_psubs_b_128, INTR_TYPE_2OP_MASK, X86ISD::SUBS, 0),
X86_INTRINSIC_DATA(avx512_mask_psubs_b_256, INTR_TYPE_2OP_MASK, X86ISD::SUBS, 0),
X86_INTRINSIC_DATA(avx512_mask_psubs_b_512, INTR_TYPE_2OP_MASK, X86ISD::SUBS, 0),
@@ -1370,8 +1130,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_reduce_ps_128, INTR_TYPE_2OP_MASK_RM, X86ISD::VREDUCE, 0),
X86_INTRINSIC_DATA(avx512_mask_reduce_ps_256, INTR_TYPE_2OP_MASK_RM, X86ISD::VREDUCE, 0),
X86_INTRINSIC_DATA(avx512_mask_reduce_ps_512, INTR_TYPE_2OP_MASK_RM, X86ISD::VREDUCE, 0),
- X86_INTRINSIC_DATA(avx512_mask_reduce_sd, INTR_TYPE_SCALAR_MASK_RM, X86ISD::VREDUCE, 0),
- X86_INTRINSIC_DATA(avx512_mask_reduce_ss, INTR_TYPE_SCALAR_MASK_RM, X86ISD::VREDUCE, 0),
+ X86_INTRINSIC_DATA(avx512_mask_reduce_sd, INTR_TYPE_SCALAR_MASK_RM, X86ISD::VREDUCES, 0),
+ X86_INTRINSIC_DATA(avx512_mask_reduce_ss, INTR_TYPE_SCALAR_MASK_RM, X86ISD::VREDUCES, 0),
X86_INTRINSIC_DATA(avx512_mask_rndscale_pd_128, INTR_TYPE_2OP_MASK_RM, X86ISD::VRNDSCALE, 0),
X86_INTRINSIC_DATA(avx512_mask_rndscale_pd_256, INTR_TYPE_2OP_MASK_RM, X86ISD::VRNDSCALE, 0),
X86_INTRINSIC_DATA(avx512_mask_rndscale_pd_512, INTR_TYPE_2OP_MASK_RM, X86ISD::VRNDSCALE, 0),
@@ -1379,9 +1139,9 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_rndscale_ps_256, INTR_TYPE_2OP_MASK_RM, X86ISD::VRNDSCALE, 0),
X86_INTRINSIC_DATA(avx512_mask_rndscale_ps_512, INTR_TYPE_2OP_MASK_RM, X86ISD::VRNDSCALE, 0),
X86_INTRINSIC_DATA(avx512_mask_rndscale_sd, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::VRNDSCALE, 0),
+ X86ISD::VRNDSCALES, 0),
X86_INTRINSIC_DATA(avx512_mask_rndscale_ss, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::VRNDSCALE, 0),
+ X86ISD::VRNDSCALES, 0),
X86_INTRINSIC_DATA(avx512_mask_scalef_pd_128, INTR_TYPE_2OP_MASK_RM,
X86ISD::SCALEF, 0),
X86_INTRINSIC_DATA(avx512_mask_scalef_pd_256, INTR_TYPE_2OP_MASK_RM,
@@ -1414,42 +1174,26 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::SHUF128, 0),
X86_INTRINSIC_DATA(avx512_mask_shuf_i64x2_256, INTR_TYPE_3OP_IMM8_MASK,
X86ISD::SHUF128, 0),
- X86_INTRINSIC_DATA(avx512_mask_shuf_pd_128, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::SHUFP, 0),
- X86_INTRINSIC_DATA(avx512_mask_shuf_pd_256, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::SHUFP, 0),
- X86_INTRINSIC_DATA(avx512_mask_shuf_pd_512, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::SHUFP, 0),
- X86_INTRINSIC_DATA(avx512_mask_shuf_ps_128, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::SHUFP, 0),
- X86_INTRINSIC_DATA(avx512_mask_shuf_ps_256, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::SHUFP, 0),
- X86_INTRINSIC_DATA(avx512_mask_shuf_ps_512, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::SHUFP, 0),
X86_INTRINSIC_DATA(avx512_mask_sqrt_pd_128, INTR_TYPE_1OP_MASK, ISD::FSQRT, 0),
X86_INTRINSIC_DATA(avx512_mask_sqrt_pd_256, INTR_TYPE_1OP_MASK, ISD::FSQRT, 0),
- X86_INTRINSIC_DATA(avx512_mask_sqrt_pd_512, INTR_TYPE_1OP_MASK_RM, ISD::FSQRT,
+ X86_INTRINSIC_DATA(avx512_mask_sqrt_pd_512, INTR_TYPE_1OP_MASK, ISD::FSQRT,
X86ISD::FSQRT_RND),
X86_INTRINSIC_DATA(avx512_mask_sqrt_ps_128, INTR_TYPE_1OP_MASK, ISD::FSQRT, 0),
X86_INTRINSIC_DATA(avx512_mask_sqrt_ps_256, INTR_TYPE_1OP_MASK, ISD::FSQRT, 0),
- X86_INTRINSIC_DATA(avx512_mask_sqrt_ps_512, INTR_TYPE_1OP_MASK_RM, ISD::FSQRT,
+ X86_INTRINSIC_DATA(avx512_mask_sqrt_ps_512, INTR_TYPE_1OP_MASK, ISD::FSQRT,
X86ISD::FSQRT_RND),
X86_INTRINSIC_DATA(avx512_mask_sqrt_sd, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FSQRT_RND, 0),
+ X86ISD::FSQRTS_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_sqrt_ss, INTR_TYPE_SCALAR_MASK_RM,
- X86ISD::FSQRT_RND, 0),
- X86_INTRINSIC_DATA(avx512_mask_sub_pd_128, INTR_TYPE_2OP_MASK, ISD::FSUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_sub_pd_256, INTR_TYPE_2OP_MASK, ISD::FSUB, 0),
+ X86ISD::FSQRTS_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_sub_pd_512, INTR_TYPE_2OP_MASK, ISD::FSUB,
X86ISD::FSUB_RND),
- X86_INTRINSIC_DATA(avx512_mask_sub_ps_128, INTR_TYPE_2OP_MASK, ISD::FSUB, 0),
- X86_INTRINSIC_DATA(avx512_mask_sub_ps_256, INTR_TYPE_2OP_MASK, ISD::FSUB, 0),
X86_INTRINSIC_DATA(avx512_mask_sub_ps_512, INTR_TYPE_2OP_MASK, ISD::FSUB,
X86ISD::FSUB_RND),
- X86_INTRINSIC_DATA(avx512_mask_sub_sd_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FSUB,
- X86ISD::FSUB_RND),
- X86_INTRINSIC_DATA(avx512_mask_sub_ss_round, INTR_TYPE_SCALAR_MASK_RM, ISD::FSUB,
- X86ISD::FSUB_RND),
+ X86_INTRINSIC_DATA(avx512_mask_sub_sd_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FSUB_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask_sub_ss_round, INTR_TYPE_SCALAR_MASK_RM,
+ X86ISD::FSUB_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_ucmp_b_128, CMP_MASK_CC, X86ISD::CMPMU, 0),
X86_INTRINSIC_DATA(avx512_mask_ucmp_b_256, CMP_MASK_CC, X86ISD::CMPMU, 0),
X86_INTRINSIC_DATA(avx512_mask_ucmp_b_512, CMP_MASK_CC, X86ISD::CMPMU, 0),
@@ -1462,30 +1206,18 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_ucmp_w_128, CMP_MASK_CC, X86ISD::CMPMU, 0),
X86_INTRINSIC_DATA(avx512_mask_ucmp_w_256, CMP_MASK_CC, X86ISD::CMPMU, 0),
X86_INTRINSIC_DATA(avx512_mask_ucmp_w_512, CMP_MASK_CC, X86ISD::CMPMU, 0),
- X86_INTRINSIC_DATA(avx512_mask_valign_d_128, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::VALIGN, 0),
- X86_INTRINSIC_DATA(avx512_mask_valign_d_256, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::VALIGN, 0),
- X86_INTRINSIC_DATA(avx512_mask_valign_d_512, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::VALIGN, 0),
- X86_INTRINSIC_DATA(avx512_mask_valign_q_128, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::VALIGN, 0),
- X86_INTRINSIC_DATA(avx512_mask_valign_q_256, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::VALIGN, 0),
- X86_INTRINSIC_DATA(avx512_mask_valign_q_512, INTR_TYPE_3OP_IMM8_MASK,
- X86ISD::VALIGN, 0),
X86_INTRINSIC_DATA(avx512_mask_vcvtph2ps_128, INTR_TYPE_1OP_MASK_RM,
- ISD::FP16_TO_FP, 0),
+ X86ISD::CVTPH2PS, 0),
X86_INTRINSIC_DATA(avx512_mask_vcvtph2ps_256, INTR_TYPE_1OP_MASK_RM,
- ISD::FP16_TO_FP, 0),
+ X86ISD::CVTPH2PS, 0),
X86_INTRINSIC_DATA(avx512_mask_vcvtph2ps_512, INTR_TYPE_1OP_MASK_RM,
- ISD::FP16_TO_FP, 0),
- X86_INTRINSIC_DATA(avx512_mask_vcvtps2ph_128, INTR_TYPE_2OP_MASK_RM,
- ISD::FP_TO_FP16, 0),
- X86_INTRINSIC_DATA(avx512_mask_vcvtps2ph_256, INTR_TYPE_2OP_MASK_RM,
- ISD::FP_TO_FP16, 0),
- X86_INTRINSIC_DATA(avx512_mask_vcvtps2ph_512, INTR_TYPE_2OP_MASK_RM,
- ISD::FP_TO_FP16, 0),
+ X86ISD::CVTPH2PS, 0),
+ X86_INTRINSIC_DATA(avx512_mask_vcvtps2ph_128, INTR_TYPE_2OP_MASK,
+ X86ISD::CVTPS2PH, 0),
+ X86_INTRINSIC_DATA(avx512_mask_vcvtps2ph_256, INTR_TYPE_2OP_MASK,
+ X86ISD::CVTPS2PH, 0),
+ X86_INTRINSIC_DATA(avx512_mask_vcvtps2ph_512, INTR_TYPE_2OP_MASK,
+ X86ISD::CVTPS2PH, 0),
X86_INTRINSIC_DATA(avx512_mask_vfmadd_pd_128, FMA_OP_MASK, X86ISD::FMADD, 0),
X86_INTRINSIC_DATA(avx512_mask_vfmadd_pd_256, FMA_OP_MASK, X86ISD::FMADD, 0),
X86_INTRINSIC_DATA(avx512_mask_vfmadd_pd_512, FMA_OP_MASK, X86ISD::FMADD,
@@ -1495,8 +1227,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_vfmadd_ps_512, FMA_OP_MASK, X86ISD::FMADD,
X86ISD::FMADD_RND),
- X86_INTRINSIC_DATA(avx512_mask_vfmadd_sd, FMA_OP_SCALAR_MASK, X86ISD::FMADD_RND, 0),
- X86_INTRINSIC_DATA(avx512_mask_vfmadd_ss, FMA_OP_SCALAR_MASK, X86ISD::FMADD_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask_vfmadd_sd, FMA_OP_SCALAR_MASK, X86ISD::FMADDS1_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask_vfmadd_ss, FMA_OP_SCALAR_MASK, X86ISD::FMADDS1_RND, 0),
X86_INTRINSIC_DATA(avx512_mask_vfmaddsub_pd_128, FMA_OP_MASK, X86ISD::FMADDSUB, 0),
X86_INTRINSIC_DATA(avx512_mask_vfmaddsub_pd_256, FMA_OP_MASK, X86ISD::FMADDSUB, 0),
X86_INTRINSIC_DATA(avx512_mask_vfmaddsub_pd_512, FMA_OP_MASK, X86ISD::FMADDSUB,
@@ -1555,23 +1287,11 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask_vpermi2var_q_512, VPERM_3OP_MASK,
X86ISD::VPERMIV3, 0),
X86_INTRINSIC_DATA(avx512_mask_vpermi2var_qi_128, VPERM_3OP_MASK,
- X86ISD::VPERMV3, 0),
+ X86ISD::VPERMIV3, 0),
X86_INTRINSIC_DATA(avx512_mask_vpermi2var_qi_256, VPERM_3OP_MASK,
- X86ISD::VPERMV3, 0),
+ X86ISD::VPERMIV3, 0),
X86_INTRINSIC_DATA(avx512_mask_vpermi2var_qi_512, VPERM_3OP_MASK,
- X86ISD::VPERMV3, 0),
- X86_INTRINSIC_DATA(avx512_mask_vpermilvar_pd_128, INTR_TYPE_2OP_MASK,
- X86ISD::VPERMILPV, 0),
- X86_INTRINSIC_DATA(avx512_mask_vpermilvar_pd_256, INTR_TYPE_2OP_MASK,
- X86ISD::VPERMILPV, 0),
- X86_INTRINSIC_DATA(avx512_mask_vpermilvar_pd_512, INTR_TYPE_2OP_MASK,
- X86ISD::VPERMILPV, 0),
- X86_INTRINSIC_DATA(avx512_mask_vpermilvar_ps_128, INTR_TYPE_2OP_MASK,
- X86ISD::VPERMILPV, 0),
- X86_INTRINSIC_DATA(avx512_mask_vpermilvar_ps_256, INTR_TYPE_2OP_MASK,
- X86ISD::VPERMILPV, 0),
- X86_INTRINSIC_DATA(avx512_mask_vpermilvar_ps_512, INTR_TYPE_2OP_MASK,
- X86ISD::VPERMILPV, 0),
+ X86ISD::VPERMIV3, 0),
X86_INTRINSIC_DATA(avx512_mask_vpermt2var_d_128, VPERM_3OP_MASK,
X86ISD::VPERMV3, 0),
X86_INTRINSIC_DATA(avx512_mask_vpermt2var_d_256, VPERM_3OP_MASK,
@@ -1620,12 +1340,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::VPMADD52L, 0),
X86_INTRINSIC_DATA(avx512_mask_vpmadd52l_uq_512 , FMA_OP_MASK,
X86ISD::VPMADD52L, 0),
- X86_INTRINSIC_DATA(avx512_mask_xor_pd_128, INTR_TYPE_2OP_MASK, X86ISD::FXOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_xor_pd_256, INTR_TYPE_2OP_MASK, X86ISD::FXOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_xor_pd_512, INTR_TYPE_2OP_MASK, X86ISD::FXOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_xor_ps_128, INTR_TYPE_2OP_MASK, X86ISD::FXOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_xor_ps_256, INTR_TYPE_2OP_MASK, X86ISD::FXOR, 0),
- X86_INTRINSIC_DATA(avx512_mask_xor_ps_512, INTR_TYPE_2OP_MASK, X86ISD::FXOR, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmadd_pd_128, FMA_OP_MASK3, X86ISD::FMADD, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmadd_pd_256, FMA_OP_MASK3, X86ISD::FMADD, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmadd_pd_512, FMA_OP_MASK3, X86ISD::FMADD,
@@ -1635,8 +1349,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask3_vfmadd_ps_512, FMA_OP_MASK3, X86ISD::FMADD,
X86ISD::FMADD_RND),
- X86_INTRINSIC_DATA(avx512_mask3_vfmadd_sd, FMA_OP_SCALAR_MASK3, X86ISD::FMADD_RND, 0),
- X86_INTRINSIC_DATA(avx512_mask3_vfmadd_ss, FMA_OP_SCALAR_MASK3, X86ISD::FMADD_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask3_vfmadd_sd, FMA_OP_SCALAR_MASK3, X86ISD::FMADDS3_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask3_vfmadd_ss, FMA_OP_SCALAR_MASK3, X86ISD::FMADDS3_RND, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmaddsub_pd_128, FMA_OP_MASK3, X86ISD::FMADDSUB, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmaddsub_pd_256, FMA_OP_MASK3, X86ISD::FMADDSUB, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmaddsub_pd_512, FMA_OP_MASK3, X86ISD::FMADDSUB,
@@ -1654,6 +1368,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask3_vfmsub_ps_256, FMA_OP_MASK3, X86ISD::FMSUB, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmsub_ps_512, FMA_OP_MASK3, X86ISD::FMSUB,
X86ISD::FMSUB_RND),
+ X86_INTRINSIC_DATA(avx512_mask3_vfmsub_sd, FMA_OP_SCALAR_MASK3, X86ISD::FMSUBS3_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask3_vfmsub_ss, FMA_OP_SCALAR_MASK3, X86ISD::FMSUBS3_RND, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmsubadd_pd_128, FMA_OP_MASK3, X86ISD::FMSUBADD, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfmsubadd_pd_256, FMA_OP_MASK3, X86ISD::FMSUBADD, 0),
@@ -1672,6 +1388,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_mask3_vfnmsub_ps_256, FMA_OP_MASK3, X86ISD::FNMSUB, 0),
X86_INTRINSIC_DATA(avx512_mask3_vfnmsub_ps_512, FMA_OP_MASK3, X86ISD::FNMSUB,
X86ISD::FNMSUB_RND),
+ X86_INTRINSIC_DATA(avx512_mask3_vfnmsub_sd, FMA_OP_SCALAR_MASK3, X86ISD::FNMSUBS3_RND, 0),
+ X86_INTRINSIC_DATA(avx512_mask3_vfnmsub_ss, FMA_OP_SCALAR_MASK3, X86ISD::FNMSUBS3_RND, 0),
X86_INTRINSIC_DATA(avx512_maskz_fixupimm_pd_128, FIXUPIMM_MASKZ,
X86ISD::VFIXUPIMM, 0),
X86_INTRINSIC_DATA(avx512_maskz_fixupimm_pd_256, FIXUPIMM_MASKZ,
@@ -1709,8 +1427,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_maskz_vfmadd_ps_512, FMA_OP_MASKZ, X86ISD::FMADD,
X86ISD::FMADD_RND),
- X86_INTRINSIC_DATA(avx512_maskz_vfmadd_sd, FMA_OP_SCALAR_MASKZ, X86ISD::FMADD_RND, 0),
- X86_INTRINSIC_DATA(avx512_maskz_vfmadd_ss, FMA_OP_SCALAR_MASKZ, X86ISD::FMADD_RND, 0),
+ X86_INTRINSIC_DATA(avx512_maskz_vfmadd_sd, FMA_OP_SCALAR_MASKZ, X86ISD::FMADDS1_RND, 0),
+ X86_INTRINSIC_DATA(avx512_maskz_vfmadd_ss, FMA_OP_SCALAR_MASKZ, X86ISD::FMADDS1_RND, 0),
X86_INTRINSIC_DATA(avx512_maskz_vfmaddsub_pd_128, FMA_OP_MASKZ, X86ISD::FMADDSUB, 0),
X86_INTRINSIC_DATA(avx512_maskz_vfmaddsub_pd_256, FMA_OP_MASKZ, X86ISD::FMADDSUB, 0),
X86_INTRINSIC_DATA(avx512_maskz_vfmaddsub_pd_512, FMA_OP_MASKZ, X86ISD::FMADDSUB,
@@ -1768,7 +1486,49 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86ISD::VPMADD52L, 0),
X86_INTRINSIC_DATA(avx512_maskz_vpmadd52l_uq_512, FMA_OP_MASKZ,
X86ISD::VPMADD52L, 0),
+ X86_INTRINSIC_DATA(avx512_pmul_dq_512, INTR_TYPE_2OP, X86ISD::PMULDQ, 0),
+ X86_INTRINSIC_DATA(avx512_pmulu_dq_512, INTR_TYPE_2OP, X86ISD::PMULUDQ, 0),
X86_INTRINSIC_DATA(avx512_psad_bw_512, INTR_TYPE_2OP, X86ISD::PSADBW, 0),
+ X86_INTRINSIC_DATA(avx512_pshuf_b_512, INTR_TYPE_2OP, X86ISD::PSHUFB, 0),
+ X86_INTRINSIC_DATA(avx512_psll_d_512, INTR_TYPE_2OP, X86ISD::VSHL, 0),
+ X86_INTRINSIC_DATA(avx512_psll_q_512, INTR_TYPE_2OP, X86ISD::VSHL, 0),
+ X86_INTRINSIC_DATA(avx512_psll_w_512, INTR_TYPE_2OP, X86ISD::VSHL, 0),
+ X86_INTRINSIC_DATA(avx512_pslli_d_512, VSHIFT, X86ISD::VSHLI, 0),
+ X86_INTRINSIC_DATA(avx512_pslli_q_512, VSHIFT, X86ISD::VSHLI, 0),
+ X86_INTRINSIC_DATA(avx512_pslli_w_512, VSHIFT, X86ISD::VSHLI, 0),
+ X86_INTRINSIC_DATA(avx512_psllv_d_512, INTR_TYPE_2OP, ISD::SHL, 0),
+ X86_INTRINSIC_DATA(avx512_psllv_q_512, INTR_TYPE_2OP, ISD::SHL, 0),
+ X86_INTRINSIC_DATA(avx512_psllv_w_128, INTR_TYPE_2OP, ISD::SHL, 0),
+ X86_INTRINSIC_DATA(avx512_psllv_w_256, INTR_TYPE_2OP, ISD::SHL, 0),
+ X86_INTRINSIC_DATA(avx512_psllv_w_512, INTR_TYPE_2OP, ISD::SHL, 0),
+ X86_INTRINSIC_DATA(avx512_psra_d_512, INTR_TYPE_2OP, X86ISD::VSRA, 0),
+ X86_INTRINSIC_DATA(avx512_psra_q_128, INTR_TYPE_2OP, X86ISD::VSRA, 0),
+ X86_INTRINSIC_DATA(avx512_psra_q_256, INTR_TYPE_2OP, X86ISD::VSRA, 0),
+ X86_INTRINSIC_DATA(avx512_psra_q_512, INTR_TYPE_2OP, X86ISD::VSRA, 0),
+ X86_INTRINSIC_DATA(avx512_psra_w_512, INTR_TYPE_2OP, X86ISD::VSRA, 0),
+ X86_INTRINSIC_DATA(avx512_psrai_d_512, VSHIFT, X86ISD::VSRAI, 0),
+ X86_INTRINSIC_DATA(avx512_psrai_q_128, VSHIFT, X86ISD::VSRAI, 0),
+ X86_INTRINSIC_DATA(avx512_psrai_q_256, VSHIFT, X86ISD::VSRAI, 0),
+ X86_INTRINSIC_DATA(avx512_psrai_q_512, VSHIFT, X86ISD::VSRAI, 0),
+ X86_INTRINSIC_DATA(avx512_psrai_w_512, VSHIFT, X86ISD::VSRAI, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_d_512, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_q_128, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_q_256, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_q_512, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_w_128, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_w_256, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrav_w_512, INTR_TYPE_2OP, X86ISD::VSRAV, 0),
+ X86_INTRINSIC_DATA(avx512_psrl_d_512, INTR_TYPE_2OP, X86ISD::VSRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrl_q_512, INTR_TYPE_2OP, X86ISD::VSRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrl_w_512, INTR_TYPE_2OP, X86ISD::VSRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrli_d_512, VSHIFT, X86ISD::VSRLI, 0),
+ X86_INTRINSIC_DATA(avx512_psrli_q_512, VSHIFT, X86ISD::VSRLI, 0),
+ X86_INTRINSIC_DATA(avx512_psrli_w_512, VSHIFT, X86ISD::VSRLI, 0),
+ X86_INTRINSIC_DATA(avx512_psrlv_d_512, INTR_TYPE_2OP, ISD::SRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrlv_q_512, INTR_TYPE_2OP, ISD::SRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrlv_w_128, INTR_TYPE_2OP, ISD::SRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrlv_w_256, INTR_TYPE_2OP, ISD::SRL, 0),
+ X86_INTRINSIC_DATA(avx512_psrlv_w_512, INTR_TYPE_2OP, ISD::SRL, 0),
X86_INTRINSIC_DATA(avx512_ptestm_b_128, CMP_MASK, X86ISD::TESTM, 0),
X86_INTRINSIC_DATA(avx512_ptestm_b_256, CMP_MASK, X86ISD::TESTM, 0),
X86_INTRINSIC_DATA(avx512_ptestm_b_512, CMP_MASK, X86ISD::TESTM, 0),
@@ -1803,8 +1563,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_rcp14_ss, INTR_TYPE_SCALAR_MASK, X86ISD::FRCPS, 0),
X86_INTRINSIC_DATA(avx512_rcp28_pd, INTR_TYPE_1OP_MASK_RM, X86ISD::RCP28, 0),
X86_INTRINSIC_DATA(avx512_rcp28_ps, INTR_TYPE_1OP_MASK_RM, X86ISD::RCP28, 0),
- X86_INTRINSIC_DATA(avx512_rcp28_sd, INTR_TYPE_SCALAR_MASK_RM, X86ISD::RCP28, 0),
- X86_INTRINSIC_DATA(avx512_rcp28_ss, INTR_TYPE_SCALAR_MASK_RM, X86ISD::RCP28, 0),
+ X86_INTRINSIC_DATA(avx512_rcp28_sd, INTR_TYPE_SCALAR_MASK_RM, X86ISD::RCP28S, 0),
+ X86_INTRINSIC_DATA(avx512_rcp28_ss, INTR_TYPE_SCALAR_MASK_RM, X86ISD::RCP28S, 0),
X86_INTRINSIC_DATA(avx512_rsqrt14_pd_128, INTR_TYPE_1OP_MASK, X86ISD::FRSQRT, 0),
X86_INTRINSIC_DATA(avx512_rsqrt14_pd_256, INTR_TYPE_1OP_MASK, X86ISD::FRSQRT, 0),
X86_INTRINSIC_DATA(avx512_rsqrt14_pd_512, INTR_TYPE_1OP_MASK, X86ISD::FRSQRT, 0),
@@ -1815,26 +1575,20 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(avx512_rsqrt14_ss, INTR_TYPE_SCALAR_MASK, X86ISD::FRSQRTS, 0),
X86_INTRINSIC_DATA(avx512_rsqrt28_pd, INTR_TYPE_1OP_MASK_RM,X86ISD::RSQRT28, 0),
X86_INTRINSIC_DATA(avx512_rsqrt28_ps, INTR_TYPE_1OP_MASK_RM,X86ISD::RSQRT28, 0),
- X86_INTRINSIC_DATA(avx512_rsqrt28_sd, INTR_TYPE_SCALAR_MASK_RM,X86ISD::RSQRT28, 0),
- X86_INTRINSIC_DATA(avx512_rsqrt28_ss, INTR_TYPE_SCALAR_MASK_RM,X86ISD::RSQRT28, 0),
+ X86_INTRINSIC_DATA(avx512_rsqrt28_sd, INTR_TYPE_SCALAR_MASK_RM,X86ISD::RSQRT28S, 0),
+ X86_INTRINSIC_DATA(avx512_rsqrt28_ss, INTR_TYPE_SCALAR_MASK_RM,X86ISD::RSQRT28S, 0),
X86_INTRINSIC_DATA(avx512_vcomi_sd, COMI_RM, X86ISD::COMI, X86ISD::UCOMI),
X86_INTRINSIC_DATA(avx512_vcomi_ss, COMI_RM, X86ISD::COMI, X86ISD::UCOMI),
- X86_INTRINSIC_DATA(avx512_vcvtsd2si32, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtsd2si64, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtsd2usi32, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtsd2usi64, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtss2si32, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtss2si64, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_SINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtss2usi32, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_UINT_RND, 0),
- X86_INTRINSIC_DATA(avx512_vcvtss2usi64, INTR_TYPE_2OP,
- X86ISD::SCALAR_FP_TO_UINT_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtsd2si32, INTR_TYPE_2OP, X86ISD::CVTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtsd2si64, INTR_TYPE_2OP, X86ISD::CVTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtsd2usi32, INTR_TYPE_2OP, X86ISD::CVTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtsd2usi64, INTR_TYPE_2OP, X86ISD::CVTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtss2si32, INTR_TYPE_2OP, X86ISD::CVTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtss2si64, INTR_TYPE_2OP, X86ISD::CVTS2SI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtss2usi32, INTR_TYPE_2OP, X86ISD::CVTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vcvtss2usi64, INTR_TYPE_2OP, X86ISD::CVTS2UI_RND, 0),
+ X86_INTRINSIC_DATA(avx512_vpermilvar_pd_512, INTR_TYPE_2OP, X86ISD::VPERMILPV, 0),
+ X86_INTRINSIC_DATA(avx512_vpermilvar_ps_512, INTR_TYPE_2OP, X86ISD::VPERMILPV, 0),
X86_INTRINSIC_DATA(fma_vfmadd_pd, INTR_TYPE_3OP, X86ISD::FMADD, 0),
X86_INTRINSIC_DATA(fma_vfmadd_pd_256, INTR_TYPE_3OP, X86ISD::FMADD, 0),
X86_INTRINSIC_DATA(fma_vfmadd_ps, INTR_TYPE_3OP, X86ISD::FMADD, 0),
@@ -1883,6 +1637,11 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(sse2_comile_sd, COMI, X86ISD::COMI, ISD::SETLE),
X86_INTRINSIC_DATA(sse2_comilt_sd, COMI, X86ISD::COMI, ISD::SETLT),
X86_INTRINSIC_DATA(sse2_comineq_sd, COMI, X86ISD::COMI, ISD::SETNE),
+ X86_INTRINSIC_DATA(sse2_cvtdq2ps, INTR_TYPE_1OP, ISD::SINT_TO_FP, 0),
+ X86_INTRINSIC_DATA(sse2_cvtpd2dq, INTR_TYPE_1OP, X86ISD::CVTP2SI, 0),
+ X86_INTRINSIC_DATA(sse2_cvtpd2ps, INTR_TYPE_1OP, X86ISD::VFPROUND, 0),
+ X86_INTRINSIC_DATA(sse2_cvttpd2dq, INTR_TYPE_1OP, X86ISD::CVTTP2SI, 0),
+ X86_INTRINSIC_DATA(sse2_cvttps2dq, INTR_TYPE_1OP, ISD::FP_TO_SINT, 0),
X86_INTRINSIC_DATA(sse2_max_pd, INTR_TYPE_2OP, X86ISD::FMAX, 0),
X86_INTRINSIC_DATA(sse2_min_pd, INTR_TYPE_2OP, X86ISD::FMIN, 0),
X86_INTRINSIC_DATA(sse2_movmsk_pd, INTR_TYPE_1OP, X86ISD::MOVMSK, 0),
@@ -1895,6 +1654,7 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(sse2_paddus_w, INTR_TYPE_2OP, X86ISD::ADDUS, 0),
X86_INTRINSIC_DATA(sse2_pavg_b, INTR_TYPE_2OP, X86ISD::AVG, 0),
X86_INTRINSIC_DATA(sse2_pavg_w, INTR_TYPE_2OP, X86ISD::AVG, 0),
+ X86_INTRINSIC_DATA(sse2_pmadd_wd, INTR_TYPE_2OP, X86ISD::VPMADDWD, 0),
X86_INTRINSIC_DATA(sse2_pmovmskb_128, INTR_TYPE_1OP, X86ISD::MOVMSK, 0),
X86_INTRINSIC_DATA(sse2_pmulh_w, INTR_TYPE_2OP, ISD::MULHS, 0),
X86_INTRINSIC_DATA(sse2_pmulhu_w, INTR_TYPE_2OP, ISD::MULHU, 0),
@@ -1943,6 +1703,8 @@ static const IntrinsicData IntrinsicsWithoutChain[] = {
X86_INTRINSIC_DATA(ssse3_phadd_w_128, INTR_TYPE_2OP, X86ISD::HADD, 0),
X86_INTRINSIC_DATA(ssse3_phsub_d_128, INTR_TYPE_2OP, X86ISD::HSUB, 0),
X86_INTRINSIC_DATA(ssse3_phsub_w_128, INTR_TYPE_2OP, X86ISD::HSUB, 0),
+ X86_INTRINSIC_DATA(ssse3_pmadd_ub_sw_128, INTR_TYPE_2OP, X86ISD::VPMADDUBSW, 0),
+ X86_INTRINSIC_DATA(ssse3_pmul_hr_sw_128, INTR_TYPE_2OP, X86ISD::MULHRS, 0),
X86_INTRINSIC_DATA(ssse3_pshuf_b_128, INTR_TYPE_2OP, X86ISD::PSHUFB, 0),
X86_INTRINSIC_DATA(xop_vpcomb, INTR_TYPE_3OP, X86ISD::VPCOM, 0),
X86_INTRINSIC_DATA(xop_vpcomd, INTR_TYPE_3OP, X86ISD::VPCOM, 0),
diff --git a/contrib/llvm/lib/Target/X86/X86MCInstLower.cpp b/contrib/llvm/lib/Target/X86/X86MCInstLower.cpp
index 906e342..feeb2fd 100644
--- a/contrib/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/contrib/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -16,6 +16,7 @@
#include "X86RegisterInfo.h"
#include "X86ShuffleDecodeConstantPool.h"
#include "InstPrinter/X86ATTInstPrinter.h"
+#include "InstPrinter/X86InstComments.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "Utils/X86ShuffleDecode.h"
#include "llvm/ADT/Optional.h"
@@ -41,6 +42,7 @@
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/ELF.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
@@ -68,9 +70,6 @@ public:
private:
MachineModuleInfoMachO &getMachOMMI() const;
- Mangler *getMang() const {
- return AsmPrinter.Mang;
- }
};
} // end anonymous namespace
@@ -499,18 +498,13 @@ ReSimplify:
break;
}
- // TAILJMPd, TAILJMPd64 - Lower to the correct jump instructions.
- case X86::TAILJMPr:
+ // TAILJMPd, TAILJMPd64 - Lower to the correct jump instruction.
+ { unsigned Opcode;
+ case X86::TAILJMPr: Opcode = X86::JMP32r; goto SetTailJmpOpcode;
case X86::TAILJMPd:
- case X86::TAILJMPd64: {
- unsigned Opcode;
- switch (OutMI.getOpcode()) {
- default: llvm_unreachable("Invalid opcode");
- case X86::TAILJMPr: Opcode = X86::JMP32r; break;
- case X86::TAILJMPd:
- case X86::TAILJMPd64: Opcode = X86::JMP_1; break;
- }
+ case X86::TAILJMPd64: Opcode = X86::JMP_1; goto SetTailJmpOpcode;
+ SetTailJmpOpcode:
MCOperand Saved = OutMI.getOperand(0);
OutMI = MCInst();
OutMI.setOpcode(Opcode);
@@ -979,8 +973,7 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
PatchPointOpers opers(&MI);
unsigned ScratchIdx = opers.getNextScratchIdx();
unsigned EncodedBytes = 0;
- const MachineOperand &CalleeMO =
- opers.getMetaOper(PatchPointOpers::TargetPos);
+ const MachineOperand &CalleeMO = opers.getCallTarget();
// Check for null target. If target is non-null (i.e. is non-zero or is
// symbolic) then emit a call.
@@ -1016,7 +1009,7 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
}
// Emit padding.
- unsigned NumBytes = opers.getMetaOper(PatchPointOpers::NBytesPos).getImm();
+ unsigned NumBytes = opers.getNumPatchBytes();
assert(NumBytes >= EncodedBytes &&
"Patchpoint can't request size less than the length of a call.");
@@ -1024,22 +1017,12 @@ void X86AsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
getSubtargetInfo());
}
-void X86AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI,
- SledKind Kind) {
- auto Fn = MI.getParent()->getParent()->getFunction();
- auto Attr = Fn->getFnAttribute("function-instrument");
- bool AlwaysInstrument =
- Attr.isStringAttribute() && Attr.getValueAsString() == "xray-always";
- Sleds.emplace_back(
- XRayFunctionEntry{Sled, CurrentFnSym, Kind, AlwaysInstrument, Fn});
-}
-
void X86AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
X86MCInstLower &MCIL) {
// We want to emit the following pattern:
//
+ // .p2align 1, ...
// .Lxray_sled_N:
- // .palign 2, ...
// jmp .tmpN
// # 9 bytes worth of noops
// .tmpN
@@ -1051,8 +1034,8 @@ void X86AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
// call <relative offset, 32-bits> // 5 bytes
//
auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
+ OutStreamer->EmitCodeAlignment(2);
OutStreamer->EmitLabel(CurSled);
- OutStreamer->EmitCodeAlignment(4);
auto Target = OutContext.createTempSymbol();
// Use a two-byte `jmp`. This version of JMP takes an 8-bit relative offset as
@@ -1074,12 +1057,14 @@ void X86AsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
//
// We should emit the RET followed by sleds.
//
+ // .p2align 1, ...
// .Lxray_sled_N:
// ret # or equivalent instruction
// # 10 bytes worth of noops
//
// This just makes sure that the alignment for the next instruction is 2.
auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
+ OutStreamer->EmitCodeAlignment(2);
OutStreamer->EmitLabel(CurSled);
unsigned OpCode = MI.getOperand(0).getImm();
MCInst Ret;
@@ -1092,29 +1077,37 @@ void X86AsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
recordSled(CurSled, MI, SledKind::FUNCTION_EXIT);
}
-void X86AsmPrinter::EmitXRayTable() {
- if (Sleds.empty())
- return;
- if (Subtarget->isTargetELF()) {
- auto *Section = OutContext.getELFSection(
- "xray_instr_map", ELF::SHT_PROGBITS,
- ELF::SHF_ALLOC | ELF::SHF_GROUP | ELF::SHF_MERGE, 0,
- CurrentFnSym->getName());
- auto PrevSection = OutStreamer->getCurrentSectionOnly();
- OutStreamer->SwitchSection(Section);
- for (const auto &Sled : Sleds) {
- OutStreamer->EmitSymbolValue(Sled.Sled, 8);
- OutStreamer->EmitSymbolValue(CurrentFnSym, 8);
- auto Kind = static_cast<uint8_t>(Sled.Kind);
- OutStreamer->EmitBytes(
- StringRef(reinterpret_cast<const char *>(&Kind), 1));
- OutStreamer->EmitBytes(
- StringRef(reinterpret_cast<const char *>(&Sled.AlwaysInstrument), 1));
- OutStreamer->EmitZeros(14);
- }
- OutStreamer->SwitchSection(PrevSection);
- }
- Sleds.clear();
+void X86AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI, X86MCInstLower &MCIL) {
+ // Like PATCHABLE_RET, we have the actual instruction in the operands to this
+ // instruction so we lower that particular instruction and its operands.
+ // Unlike PATCHABLE_RET though, we put the sled before the JMP, much like how
+ // we do it for PATCHABLE_FUNCTION_ENTER. The sled should be very similar to
+ // the PATCHABLE_FUNCTION_ENTER case, followed by the lowering of the actual
+ // tail call much like how we have it in PATCHABLE_RET.
+ auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
+ OutStreamer->EmitCodeAlignment(2);
+ OutStreamer->EmitLabel(CurSled);
+ auto Target = OutContext.createTempSymbol();
+
+ // Use a two-byte `jmp`. This version of JMP takes an 8-bit relative offset as
+ // an operand (computed as an offset from the jmp instruction).
+ // FIXME: Find another less hacky way do force the relative jump.
+ OutStreamer->EmitBytes("\xeb\x09");
+ EmitNops(*OutStreamer, 9, Subtarget->is64Bit(), getSubtargetInfo());
+ OutStreamer->EmitLabel(Target);
+ recordSled(CurSled, MI, SledKind::TAIL_CALL);
+
+ unsigned OpCode = MI.getOperand(0).getImm();
+ MCInst TC;
+ TC.setOpcode(OpCode);
+
+ // Before emitting the instruction, add a comment to indicate that this is
+ // indeed a tail call.
+ OutStreamer->AddComment("TAILCALL");
+ for (auto &MO : make_range(MI.operands_begin() + 1, MI.operands_end()))
+ if (auto MaybeOperand = MCIL.LowerMachineOperand(&MI, MO))
+ TC.addOperand(MaybeOperand.getValue());
+ OutStreamer->EmitInstruction(TC, getSubtargetInfo());
}
// Returns instruction preceding MBBI in MachineFunction.
@@ -1152,9 +1145,9 @@ static const Constant *getConstantFromPool(const MachineInstr &MI,
return C;
}
-static std::string getShuffleComment(const MachineOperand &DstOp,
- const MachineOperand &SrcOp1,
- const MachineOperand &SrcOp2,
+static std::string getShuffleComment(const MachineInstr *MI,
+ unsigned SrcOp1Idx,
+ unsigned SrcOp2Idx,
ArrayRef<int> Mask) {
std::string Comment;
@@ -1167,7 +1160,10 @@ static std::string getShuffleComment(const MachineOperand &DstOp,
return X86ATTInstPrinter::getRegisterName(RegNum);
};
- // TODO: Add support for specifying an AVX512 style mask register in the comment.
+ const MachineOperand &DstOp = MI->getOperand(0);
+ const MachineOperand &SrcOp1 = MI->getOperand(SrcOp1Idx);
+ const MachineOperand &SrcOp2 = MI->getOperand(SrcOp2Idx);
+
StringRef DstName = DstOp.isReg() ? GetRegisterName(DstOp.getReg()) : "mem";
StringRef Src1Name =
SrcOp1.isReg() ? GetRegisterName(SrcOp1.getReg()) : "mem";
@@ -1182,7 +1178,26 @@ static std::string getShuffleComment(const MachineOperand &DstOp,
ShuffleMask[i] -= e;
raw_string_ostream CS(Comment);
- CS << DstName << " = ";
+ CS << DstName;
+
+ // Handle AVX512 MASK/MASXZ write mask comments.
+ // MASK: zmmX {%kY}
+ // MASKZ: zmmX {%kY} {z}
+ if (SrcOp1Idx > 1) {
+ assert((SrcOp1Idx == 2 || SrcOp1Idx == 3) && "Unexpected writemask");
+
+ const MachineOperand &WriteMaskOp = MI->getOperand(SrcOp1Idx - 1);
+ if (WriteMaskOp.isReg()) {
+ CS << " {%" << GetRegisterName(WriteMaskOp.getReg()) << "}";
+
+ if (SrcOp1Idx == 2) {
+ CS << " {z}";
+ }
+ }
+ }
+
+ CS << " = ";
+
for (int i = 0, e = ShuffleMask.size(); i != e; ++i) {
if (i != 0)
CS << ",";
@@ -1221,6 +1236,13 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
X86MCInstLower MCInstLowering(*MF, *this);
const X86RegisterInfo *RI = MF->getSubtarget<X86Subtarget>().getRegisterInfo();
+ // Add a comment about EVEX-2-VEX compression for AVX-512 instrs that
+ // are compressed from EVEX encoding to VEX encoding.
+ if (TM.Options.MCOptions.ShowMCEncoding) {
+ if (MI->getAsmPrinterFlags() & AC_EVEX_2_VEX)
+ OutStreamer->AddComment("EVEX TO VEX Compression ", false);
+ }
+
switch (MI->getOpcode()) {
case TargetOpcode::DBG_VALUE:
llvm_unreachable("Should be handled target independently");
@@ -1259,7 +1281,6 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
case X86::TAILJMPd64:
case X86::TAILJMPr64_REX:
case X86::TAILJMPm64_REX:
- case X86::TAILJMPd64_REX:
// Lower these as normal, but add some comments.
OutStreamer->AddComment("TAILCALL");
break;
@@ -1364,6 +1385,9 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
case TargetOpcode::PATCHABLE_RET:
return LowerPATCHABLE_RET(*MI, MCInstLowering);
+ case TargetOpcode::PATCHABLE_TAIL_CALL:
+ return LowerPATCHABLE_TAIL_CALL(*MI, MCInstLowering);
+
case X86::MORESTACK_RET:
EmitAndCountInstruction(MCInstBuilder(getRetOpcode(*Subtarget)));
return;
@@ -1377,37 +1401,45 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
return;
case X86::SEH_PushReg:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFIPushReg(RI->getSEHRegNum(MI->getOperand(0).getImm()));
return;
case X86::SEH_SaveReg:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFISaveReg(RI->getSEHRegNum(MI->getOperand(0).getImm()),
MI->getOperand(1).getImm());
return;
case X86::SEH_SaveXMM:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFISaveXMM(RI->getSEHRegNum(MI->getOperand(0).getImm()),
MI->getOperand(1).getImm());
return;
case X86::SEH_StackAlloc:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFIAllocStack(MI->getOperand(0).getImm());
return;
case X86::SEH_SetFrame:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFISetFrame(RI->getSEHRegNum(MI->getOperand(0).getImm()),
MI->getOperand(1).getImm());
return;
case X86::SEH_PushFrame:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFIPushFrame(MI->getOperand(0).getImm());
return;
case X86::SEH_EndPrologue:
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
OutStreamer->EmitWinCFIEndProlog();
return;
case X86::SEH_Epilogue: {
+ assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
MachineBasicBlock::const_iterator MBBI(MI);
// Check if preceded by a call and emit nop if so.
for (MBBI = PrevCrossBBInst(MBBI);
@@ -1463,59 +1495,84 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
assert(MI->getNumOperands() >= 6 &&
"We should always have at least 6 operands!");
- const MachineOperand &DstOp = MI->getOperand(0);
- const MachineOperand &SrcOp = MI->getOperand(SrcIdx);
- const MachineOperand &MaskOp = MI->getOperand(MaskIdx);
+ const MachineOperand &MaskOp = MI->getOperand(MaskIdx);
if (auto *C = getConstantFromPool(*MI, MaskOp)) {
- SmallVector<int, 16> Mask;
+ SmallVector<int, 64> Mask;
DecodePSHUFBMask(C, Mask);
if (!Mask.empty())
- OutStreamer->AddComment(getShuffleComment(DstOp, SrcOp, SrcOp, Mask));
+ OutStreamer->AddComment(getShuffleComment(MI, SrcIdx, SrcIdx, Mask));
}
break;
}
+ case X86::VPERMILPSrm:
+ case X86::VPERMILPSYrm:
+ case X86::VPERMILPSZ128rm:
+ case X86::VPERMILPSZ128rmk:
+ case X86::VPERMILPSZ128rmkz:
+ case X86::VPERMILPSZ256rm:
+ case X86::VPERMILPSZ256rmk:
+ case X86::VPERMILPSZ256rmkz:
+ case X86::VPERMILPSZrm:
+ case X86::VPERMILPSZrmk:
+ case X86::VPERMILPSZrmkz:
case X86::VPERMILPDrm:
case X86::VPERMILPDYrm:
case X86::VPERMILPDZ128rm:
+ case X86::VPERMILPDZ128rmk:
+ case X86::VPERMILPDZ128rmkz:
case X86::VPERMILPDZ256rm:
- case X86::VPERMILPDZrm: {
+ case X86::VPERMILPDZ256rmk:
+ case X86::VPERMILPDZ256rmkz:
+ case X86::VPERMILPDZrm:
+ case X86::VPERMILPDZrmk:
+ case X86::VPERMILPDZrmkz: {
if (!OutStreamer->isVerboseAsm())
break;
- assert(MI->getNumOperands() > 5 &&
- "We should always have at least 5 operands!");
- const MachineOperand &DstOp = MI->getOperand(0);
- const MachineOperand &SrcOp = MI->getOperand(1);
- const MachineOperand &MaskOp = MI->getOperand(5);
-
- if (auto *C = getConstantFromPool(*MI, MaskOp)) {
- SmallVector<int, 8> Mask;
- DecodeVPERMILPMask(C, 64, Mask);
- if (!Mask.empty())
- OutStreamer->AddComment(getShuffleComment(DstOp, SrcOp, SrcOp, Mask));
+ unsigned SrcIdx, MaskIdx;
+ unsigned ElSize;
+ switch (MI->getOpcode()) {
+ default: llvm_unreachable("Invalid opcode");
+ case X86::VPERMILPSrm:
+ case X86::VPERMILPSYrm:
+ case X86::VPERMILPSZ128rm:
+ case X86::VPERMILPSZ256rm:
+ case X86::VPERMILPSZrm:
+ SrcIdx = 1; MaskIdx = 5; ElSize = 32; break;
+ case X86::VPERMILPSZ128rmkz:
+ case X86::VPERMILPSZ256rmkz:
+ case X86::VPERMILPSZrmkz:
+ SrcIdx = 2; MaskIdx = 6; ElSize = 32; break;
+ case X86::VPERMILPSZ128rmk:
+ case X86::VPERMILPSZ256rmk:
+ case X86::VPERMILPSZrmk:
+ SrcIdx = 3; MaskIdx = 7; ElSize = 32; break;
+ case X86::VPERMILPDrm:
+ case X86::VPERMILPDYrm:
+ case X86::VPERMILPDZ128rm:
+ case X86::VPERMILPDZ256rm:
+ case X86::VPERMILPDZrm:
+ SrcIdx = 1; MaskIdx = 5; ElSize = 64; break;
+ case X86::VPERMILPDZ128rmkz:
+ case X86::VPERMILPDZ256rmkz:
+ case X86::VPERMILPDZrmkz:
+ SrcIdx = 2; MaskIdx = 6; ElSize = 64; break;
+ case X86::VPERMILPDZ128rmk:
+ case X86::VPERMILPDZ256rmk:
+ case X86::VPERMILPDZrmk:
+ SrcIdx = 3; MaskIdx = 7; ElSize = 64; break;
}
- break;
- }
- case X86::VPERMILPSrm:
- case X86::VPERMILPSYrm:
- case X86::VPERMILPSZ128rm:
- case X86::VPERMILPSZ256rm:
- case X86::VPERMILPSZrm: {
- if (!OutStreamer->isVerboseAsm())
- break;
- assert(MI->getNumOperands() > 5 &&
- "We should always have at least 5 operands!");
- const MachineOperand &DstOp = MI->getOperand(0);
- const MachineOperand &SrcOp = MI->getOperand(1);
- const MachineOperand &MaskOp = MI->getOperand(5);
+ assert(MI->getNumOperands() >= 6 &&
+ "We should always have at least 6 operands!");
+ const MachineOperand &MaskOp = MI->getOperand(MaskIdx);
if (auto *C = getConstantFromPool(*MI, MaskOp)) {
SmallVector<int, 16> Mask;
- DecodeVPERMILPMask(C, 32, Mask);
+ DecodeVPERMILPMask(C, ElSize, Mask);
if (!Mask.empty())
- OutStreamer->AddComment(getShuffleComment(DstOp, SrcOp, SrcOp, Mask));
+ OutStreamer->AddComment(getShuffleComment(MI, SrcIdx, SrcIdx, Mask));
}
break;
}
@@ -1526,14 +1583,10 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
case X86::VPERMIL2PSrmY: {
if (!OutStreamer->isVerboseAsm())
break;
- assert(MI->getNumOperands() > 7 &&
- "We should always have at least 7 operands!");
- const MachineOperand &DstOp = MI->getOperand(0);
- const MachineOperand &SrcOp1 = MI->getOperand(1);
- const MachineOperand &SrcOp2 = MI->getOperand(2);
- const MachineOperand &MaskOp = MI->getOperand(6);
- const MachineOperand &CtrlOp = MI->getOperand(MI->getNumOperands() - 1);
+ assert(MI->getNumOperands() >= 8 &&
+ "We should always have at least 8 operands!");
+ const MachineOperand &CtrlOp = MI->getOperand(MI->getNumOperands() - 1);
if (!CtrlOp.isImm())
break;
@@ -1544,11 +1597,12 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
case X86::VPERMIL2PDrm: case X86::VPERMIL2PDrmY: ElSize = 64; break;
}
+ const MachineOperand &MaskOp = MI->getOperand(6);
if (auto *C = getConstantFromPool(*MI, MaskOp)) {
SmallVector<int, 16> Mask;
DecodeVPERMIL2PMask(C, (unsigned)CtrlOp.getImm(), ElSize, Mask);
if (!Mask.empty())
- OutStreamer->AddComment(getShuffleComment(DstOp, SrcOp1, SrcOp2, Mask));
+ OutStreamer->AddComment(getShuffleComment(MI, 1, 2, Mask));
}
break;
}
@@ -1556,18 +1610,15 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
case X86::VPPERMrrm: {
if (!OutStreamer->isVerboseAsm())
break;
- assert(MI->getNumOperands() > 6 &&
- "We should always have at least 6 operands!");
- const MachineOperand &DstOp = MI->getOperand(0);
- const MachineOperand &SrcOp1 = MI->getOperand(1);
- const MachineOperand &SrcOp2 = MI->getOperand(2);
- const MachineOperand &MaskOp = MI->getOperand(6);
+ assert(MI->getNumOperands() >= 7 &&
+ "We should always have at least 7 operands!");
+ const MachineOperand &MaskOp = MI->getOperand(6);
if (auto *C = getConstantFromPool(*MI, MaskOp)) {
SmallVector<int, 16> Mask;
DecodeVPPERMMask(C, Mask);
if (!Mask.empty())
- OutStreamer->AddComment(getShuffleComment(DstOp, SrcOp1, SrcOp2, Mask));
+ OutStreamer->AddComment(getShuffleComment(MI, 1, 2, Mask));
}
break;
}
@@ -1605,7 +1656,8 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {
CASE_ALL_MOV_RM()
if (!OutStreamer->isVerboseAsm())
break;
- if (MI->getNumOperands() > 4)
+ if (MI->getNumOperands() <= 4)
+ break;
if (auto *C = getConstantFromPool(*MI, MI->getOperand(4))) {
std::string Comment;
raw_string_ostream CS(Comment);
diff --git a/contrib/llvm/lib/Target/X86/X86OptimizeLEAs.cpp b/contrib/llvm/lib/Target/X86/X86OptimizeLEAs.cpp
index 4da0fdd..e144700 100644
--- a/contrib/llvm/lib/Target/X86/X86OptimizeLEAs.cpp
+++ b/contrib/llvm/lib/Target/X86/X86OptimizeLEAs.cpp
@@ -44,12 +44,6 @@ static cl::opt<bool>
STATISTIC(NumSubstLEAs, "Number of LEA instruction substitutions");
STATISTIC(NumRedundantLEAs, "Number of redundant LEA instructions removed");
-class MemOpKey;
-
-/// \brief Returns a hash table key based on memory operands of \p MI. The
-/// number of the first memory operand of \p MI is specified through \p N.
-static inline MemOpKey getMemOpKey(const MachineInstr &MI, unsigned N);
-
/// \brief Returns true if two machine operands are identical and they are not
/// physical registers.
static inline bool isIdenticalOp(const MachineOperand &MO1,
@@ -63,6 +57,7 @@ static bool isSimilarDispOp(const MachineOperand &MO1,
/// \brief Returns true if the instruction is LEA.
static inline bool isLEA(const MachineInstr &MI);
+namespace {
/// A key based on instruction's memory operands.
class MemOpKey {
public:
@@ -95,6 +90,7 @@ public:
// Address' displacement operand.
const MachineOperand *Disp;
};
+} // end anonymous namespace
/// Provide DenseMapInfo for MemOpKey.
namespace llvm {
@@ -168,6 +164,8 @@ template <> struct DenseMapInfo<MemOpKey> {
};
}
+/// \brief Returns a hash table key based on memory operands of \p MI. The
+/// number of the first memory operand of \p MI is specified through \p N.
static inline MemOpKey getMemOpKey(const MachineInstr &MI, unsigned N) {
assert((isLEA(MI) || MI.mayLoadOrStore()) &&
"The instruction must be a LEA, a load or a store");
@@ -221,7 +219,7 @@ class OptimizeLEAPass : public MachineFunctionPass {
public:
OptimizeLEAPass() : MachineFunctionPass(ID) {}
- const char *getPassName() const override { return "X86 LEA Optimize"; }
+ StringRef getPassName() const override { return "X86 LEA Optimize"; }
/// \brief Loop over all of the basic blocks, replacing address
/// calculations in load and store instructions, if it's already
@@ -237,7 +235,7 @@ private:
/// \brief Choose the best \p LEA instruction from the \p List to replace
/// address calculation in \p MI instruction. Return the address displacement
- /// and the distance between \p MI and the choosen \p BestLEA in
+ /// and the distance between \p MI and the chosen \p BestLEA in
/// \p AddrDispShift and \p Dist.
bool chooseBestLEA(const SmallVectorImpl<MachineInstr *> &List,
const MachineInstr &MI, MachineInstr *&BestLEA,
@@ -551,10 +549,10 @@ bool OptimizeLEAPass::removeRedundantLEAs(MemOpMap &LEAs) {
MachineInstr &Last = **I2;
int64_t AddrDispShift;
- // LEAs should be in occurence order in the list, so we can freely
+ // LEAs should be in occurrence order in the list, so we can freely
// replace later LEAs with earlier ones.
assert(calcInstrDist(First, Last) > 0 &&
- "LEAs must be in occurence order in the list");
+ "LEAs must be in occurrence order in the list");
// Check that the Last LEA instruction can be replaced by the First.
if (!isReplaceable(First, Last, AddrDispShift)) {
diff --git a/contrib/llvm/lib/Target/X86/X86PadShortFunction.cpp b/contrib/llvm/lib/Target/X86/X86PadShortFunction.cpp
index 62a9aaf..3069d1f 100644
--- a/contrib/llvm/lib/Target/X86/X86PadShortFunction.cpp
+++ b/contrib/llvm/lib/Target/X86/X86PadShortFunction.cpp
@@ -57,10 +57,10 @@ namespace {
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "X86 Atom pad short functions";
}
diff --git a/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp b/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp
index 8675063..65f438f 100644
--- a/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp
@@ -128,21 +128,44 @@ X86RegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC,
if (RC == &X86::GR8_NOREXRegClass)
return RC;
+ const X86Subtarget &Subtarget = MF.getSubtarget<X86Subtarget>();
+
const TargetRegisterClass *Super = RC;
TargetRegisterClass::sc_iterator I = RC->getSuperClasses();
do {
switch (Super->getID()) {
+ case X86::FR32RegClassID:
+ case X86::FR64RegClassID:
+ // If AVX-512 isn't supported we should only inflate to these classes.
+ if (!Subtarget.hasAVX512() && Super->getSize() == RC->getSize())
+ return Super;
+ break;
+ case X86::VR128RegClassID:
+ case X86::VR256RegClassID:
+ // If VLX isn't supported we should only inflate to these classes.
+ if (!Subtarget.hasVLX() && Super->getSize() == RC->getSize())
+ return Super;
+ break;
+ case X86::VR128XRegClassID:
+ case X86::VR256XRegClassID:
+ // If VLX isn't support we shouldn't inflate to these classes.
+ if (Subtarget.hasVLX() && Super->getSize() == RC->getSize())
+ return Super;
+ break;
+ case X86::FR32XRegClassID:
+ case X86::FR64XRegClassID:
+ // If AVX-512 isn't support we shouldn't inflate to these classes.
+ if (Subtarget.hasAVX512() && Super->getSize() == RC->getSize())
+ return Super;
+ break;
case X86::GR8RegClassID:
case X86::GR16RegClassID:
case X86::GR32RegClassID:
case X86::GR64RegClassID:
- case X86::FR32RegClassID:
- case X86::FR64RegClassID:
case X86::RFP32RegClassID:
case X86::RFP64RegClassID:
case X86::RFP80RegClassID:
- case X86::VR128RegClassID:
- case X86::VR256RegClassID:
+ case X86::VR512RegClassID:
// Don't return a super-class that would shrink the spill size.
// That can happen with the vector and float classes.
if (Super->getSize() == RC->getSize())
@@ -241,13 +264,14 @@ X86RegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
const MCPhysReg *
X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
+ assert(MF && "MachineFunction required");
+
const X86Subtarget &Subtarget = MF->getSubtarget<X86Subtarget>();
bool HasSSE = Subtarget.hasSSE1();
bool HasAVX = Subtarget.hasAVX();
bool HasAVX512 = Subtarget.hasAVX512();
- bool CallsEHReturn = MF->getMMI().callsEHReturn();
+ bool CallsEHReturn = MF->callsEHReturn();
- assert(MF && "MachineFunction required");
switch (MF->getFunction()->getCallingConv()) {
case CallingConv::GHC:
case CallingConv::HiPE:
@@ -282,11 +306,26 @@ X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
}
case CallingConv::HHVM:
return CSR_64_HHVM_SaveList;
+ case CallingConv::X86_RegCall:
+ if (Is64Bit) {
+ if (IsWin64) {
+ return (HasSSE ? CSR_Win64_RegCall_SaveList :
+ CSR_Win64_RegCall_NoSSE_SaveList);
+ } else {
+ return (HasSSE ? CSR_SysV64_RegCall_SaveList :
+ CSR_SysV64_RegCall_NoSSE_SaveList);
+ }
+ } else {
+ return (HasSSE ? CSR_32_RegCall_SaveList :
+ CSR_32_RegCall_NoSSE_SaveList);
+ }
case CallingConv::Cold:
if (Is64Bit)
return CSR_64_MostRegs_SaveList;
break;
case CallingConv::X86_64_Win64:
+ if (!HasSSE)
+ return CSR_Win64_NoSSE_SaveList;
return CSR_Win64_SaveList;
case CallingConv::X86_64_SysV:
if (CallsEHReturn)
@@ -313,8 +352,11 @@ X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
}
if (Is64Bit) {
- if (IsWin64)
+ if (IsWin64) {
+ if (!HasSSE)
+ return CSR_Win64_NoSSE_SaveList;
return CSR_Win64_SaveList;
+ }
if (CallsEHReturn)
return CSR_64EHRet_SaveList;
if (Subtarget.getTargetLowering()->supportSwiftError() &&
@@ -378,6 +420,19 @@ X86RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
}
case CallingConv::HHVM:
return CSR_64_HHVM_RegMask;
+ case CallingConv::X86_RegCall:
+ if (Is64Bit) {
+ if (IsWin64) {
+ return (HasSSE ? CSR_Win64_RegCall_RegMask :
+ CSR_Win64_RegCall_NoSSE_RegMask);
+ } else {
+ return (HasSSE ? CSR_SysV64_RegCall_RegMask :
+ CSR_SysV64_RegCall_NoSSE_RegMask);
+ }
+ } else {
+ return (HasSSE ? CSR_32_RegCall_RegMask :
+ CSR_32_RegCall_NoSSE_RegMask);
+ }
case CallingConv::Cold:
if (Is64Bit)
return CSR_64_MostRegs_RegMask;
@@ -503,6 +558,8 @@ BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
}
}
+ assert(checkAllSuperRegsMarked(Reserved,
+ {X86::SIL, X86::DIL, X86::BPL, X86::SPL}));
return Reserved;
}
@@ -526,12 +583,12 @@ void X86RegisterInfo::adjustStackMapLiveOutMask(uint32_t *Mask) const {
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//
-static bool CantUseSP(const MachineFrameInfo *MFI) {
- return MFI->hasVarSizedObjects() || MFI->hasOpaqueSPAdjustment();
+static bool CantUseSP(const MachineFrameInfo &MFI) {
+ return MFI.hasVarSizedObjects() || MFI.hasOpaqueSPAdjustment();
}
bool X86RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
if (!EnableBasePointer)
return false;
@@ -549,7 +606,7 @@ bool X86RegisterInfo::canRealignStack(const MachineFunction &MF) const {
if (!TargetRegisterInfo::canRealignStack(MF))
return false;
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const MachineRegisterInfo *MRI = &MF.getRegInfo();
// Stack realignment requires a frame pointer. If we already started
@@ -571,6 +628,35 @@ bool X86RegisterInfo::hasReservedSpillSlot(const MachineFunction &MF,
llvm_unreachable("Unused function on X86. Otherwise need a test case.");
}
+// tryOptimizeLEAtoMOV - helper function that tries to replace a LEA instruction
+// of the form 'lea (%esp), %ebx' --> 'mov %esp, %ebx'.
+// TODO: In this case we should be really trying first to entirely eliminate
+// this instruction which is a plain copy.
+static bool tryOptimizeLEAtoMOV(MachineBasicBlock::iterator II) {
+ MachineInstr &MI = *II;
+ unsigned Opc = II->getOpcode();
+ // Check if this is a LEA of the form 'lea (%esp), %ebx'
+ if ((Opc != X86::LEA32r && Opc != X86::LEA64r && Opc != X86::LEA64_32r) ||
+ MI.getOperand(2).getImm() != 1 ||
+ MI.getOperand(3).getReg() != X86::NoRegister ||
+ MI.getOperand(4).getImm() != 0 ||
+ MI.getOperand(5).getReg() != X86::NoRegister)
+ return false;
+ unsigned BasePtr = MI.getOperand(1).getReg();
+ // In X32 mode, ensure the base-pointer is a 32-bit operand, so the LEA will
+ // be replaced with a 32-bit operand MOV which will zero extend the upper
+ // 32-bits of the super register.
+ if (Opc == X86::LEA64_32r)
+ BasePtr = getX86SubSuperRegister(BasePtr, 32);
+ unsigned NewDestReg = MI.getOperand(0).getReg();
+ const X86InstrInfo *TII =
+ MI.getParent()->getParent()->getSubtarget<X86Subtarget>().getInstrInfo();
+ TII->copyPhysReg(*MI.getParent(), II, MI.getDebugLoc(), NewDestReg, BasePtr,
+ MI.getOperand(1).isKill());
+ MI.eraseFromParent();
+ return true;
+}
+
void
X86RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
@@ -611,19 +697,21 @@ X86RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// For LEA64_32r when BasePtr is 32-bits (X32) we can use full-size 64-bit
// register as source operand, semantic is the same and destination is
// 32-bits. It saves one byte per lea in code since 0x67 prefix is avoided.
+ // Don't change BasePtr since it is used later for stack adjustment.
+ unsigned MachineBasePtr = BasePtr;
if (Opc == X86::LEA64_32r && X86::GR32RegClass.contains(BasePtr))
- BasePtr = getX86SubSuperRegister(BasePtr, 64);
+ MachineBasePtr = getX86SubSuperRegister(BasePtr, 64);
// This must be part of a four operand memory reference. Replace the
- // FrameIndex with base register with EBP. Add an offset to the offset.
- MI.getOperand(FIOperandNum).ChangeToRegister(BasePtr, false);
+ // FrameIndex with base register. Add an offset to the offset.
+ MI.getOperand(FIOperandNum).ChangeToRegister(MachineBasePtr, false);
// Now add the frame object offset to the offset from EBP.
int FIOffset;
if (AfterFPPop) {
// Tail call jmp happens after FP is popped.
- const MachineFrameInfo *MFI = MF.getFrameInfo();
- FIOffset = MFI->getObjectOffset(FrameIndex) - TFI->getOffsetOfLocalArea();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ FIOffset = MFI.getObjectOffset(FrameIndex) - TFI->getOffsetOfLocalArea();
} else
FIOffset = TFI->getFrameIndexReference(MF, FrameIndex, IgnoredFrameReg);
@@ -645,7 +733,8 @@ X86RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int Offset = FIOffset + Imm;
assert((!Is64Bit || isInt<32>((long long)FIOffset + Imm)) &&
"Requesting 64-bit offset in 32-bit immediate!");
- MI.getOperand(FIOperandNum + 3).ChangeToImmediate(Offset);
+ if (Offset != 0 || !tryOptimizeLEAtoMOV(II))
+ MI.getOperand(FIOperandNum + 3).ChangeToImmediate(Offset);
} else {
// Offset is symbolic. This is extremely rare.
uint64_t Offset = FIOffset +
@@ -667,13 +756,3 @@ X86RegisterInfo::getPtrSizedFrameRegister(const MachineFunction &MF) const {
FrameReg = getX86SubSuperRegister(FrameReg, 32);
return FrameReg;
}
-
-unsigned llvm::get512BitSuperRegister(unsigned Reg) {
- if (Reg >= X86::XMM0 && Reg <= X86::XMM31)
- return X86::ZMM0 + (Reg - X86::XMM0);
- if (Reg >= X86::YMM0 && Reg <= X86::YMM31)
- return X86::ZMM0 + (Reg - X86::YMM0);
- if (Reg >= X86::ZMM0 && Reg <= X86::ZMM31)
- return Reg;
- llvm_unreachable("Unexpected SIMD register");
-}
diff --git a/contrib/llvm/lib/Target/X86/X86RegisterInfo.h b/contrib/llvm/lib/Target/X86/X86RegisterInfo.h
index 8d0094c..58fa31e 100644
--- a/contrib/llvm/lib/Target/X86/X86RegisterInfo.h
+++ b/contrib/llvm/lib/Target/X86/X86RegisterInfo.h
@@ -100,7 +100,7 @@ public:
const MCPhysReg *
getCalleeSavedRegs(const MachineFunction* MF) const override;
const MCPhysReg *
- getCalleeSavedRegsViaCopy(const MachineFunction *MF) const override;
+ getCalleeSavedRegsViaCopy(const MachineFunction *MF) const;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID) const override;
const uint32_t *getNoPreservedMask() const override;
@@ -137,9 +137,6 @@ public:
unsigned getSlotSize() const { return SlotSize; }
};
-//get512BitRegister - X86 utility - returns 512-bit super register
-unsigned get512BitSuperRegister(unsigned Reg);
-
} // End llvm namespace
#endif
diff --git a/contrib/llvm/lib/Target/X86/X86RegisterInfo.td b/contrib/llvm/lib/Target/X86/X86RegisterInfo.td
index 373f9b4..372a15a 100644
--- a/contrib/llvm/lib/Target/X86/X86RegisterInfo.td
+++ b/contrib/llvm/lib/Target/X86/X86RegisterInfo.td
@@ -345,6 +345,8 @@ def GR32 : RegisterClass<"X86", [i32], 32,
// GR64 - 64-bit GPRs. This oddly includes RIP, which isn't accurate, since
// RIP isn't really a register and it can't be used anywhere except in an
// address, but it doesn't cause trouble.
+// FIXME: it *does* cause trouble - CheckBaseRegAndIndexReg() has extra
+// tests because of the inclusion of RIP in this register class.
def GR64 : RegisterClass<"X86", [i64], 64,
(add RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11,
RBX, R14, R15, R12, R13, RBP, RSP, RIP)>;
diff --git a/contrib/llvm/lib/Target/X86/X86SelectionDAGInfo.cpp b/contrib/llvm/lib/Target/X86/X86SelectionDAGInfo.cpp
index d02859b..f031a28 100644
--- a/contrib/llvm/lib/Target/X86/X86SelectionDAGInfo.cpp
+++ b/contrib/llvm/lib/Target/X86/X86SelectionDAGInfo.cpp
@@ -31,8 +31,8 @@ bool X86SelectionDAGInfo::isBaseRegConflictPossible(
// alignment requirements. Fall back to generic code if there are any
// dynamic stack adjustments (hopefully rare) and the base pointer would
// conflict if we had to use it.
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- if (!MFI->hasVarSizedObjects() && !MFI->hasOpaqueSPAdjustment())
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ if (!MFI.hasVarSizedObjects() && !MFI.hasOpaqueSPAdjustment())
return false;
const X86RegisterInfo *TRI = static_cast<const X86RegisterInfo *>(
diff --git a/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.cpp b/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.cpp
index 1adc92c..1111552 100644
--- a/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.cpp
+++ b/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.cpp
@@ -14,6 +14,7 @@
#include "X86ShuffleDecodeConstantPool.h"
#include "Utils/X86ShuffleDecode.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/IR/Constants.h"
@@ -23,10 +24,12 @@
namespace llvm {
-void DecodePSHUFBMask(const Constant *C, SmallVectorImpl<int> &ShuffleMask) {
- Type *MaskTy = C->getType();
- // It is not an error for the PSHUFB mask to not be a vector of i8 because the
- // constant pool uniques constants by their bit representation.
+static bool extractConstantMask(const Constant *C, unsigned MaskEltSizeInBits,
+ SmallBitVector &UndefElts,
+ SmallVectorImpl<uint64_t> &RawMask) {
+ // It is not an error for shuffle masks to not be a vector of
+ // MaskEltSizeInBits because the constant pool uniques constants by their
+ // bit representation.
// e.g. the following take up the same space in the constant pool:
// i128 -170141183420855150465331762880109871104
//
@@ -34,165 +37,161 @@ void DecodePSHUFBMask(const Constant *C, SmallVectorImpl<int> &ShuffleMask) {
//
// <4 x i32> <i32 -2147483648, i32 -2147483648,
// i32 -2147483648, i32 -2147483648>
+ Type *CstTy = C->getType();
+ if (!CstTy->isVectorTy())
+ return false;
+
+ Type *CstEltTy = CstTy->getVectorElementType();
+ if (!CstEltTy->isIntegerTy())
+ return false;
+
+ unsigned CstSizeInBits = CstTy->getPrimitiveSizeInBits();
+ unsigned CstEltSizeInBits = CstTy->getScalarSizeInBits();
+ unsigned NumCstElts = CstTy->getVectorNumElements();
+
+ // Extract all the undef/constant element data and pack into single bitsets.
+ APInt UndefBits(CstSizeInBits, 0);
+ APInt MaskBits(CstSizeInBits, 0);
+ for (unsigned i = 0; i != NumCstElts; ++i) {
+ Constant *COp = C->getAggregateElement(i);
+ if (!COp || (!isa<UndefValue>(COp) && !isa<ConstantInt>(COp)))
+ return false;
-#ifndef NDEBUG
- unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
- assert(MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512);
-#endif
+ if (isa<UndefValue>(COp)) {
+ APInt EltUndef = APInt::getLowBitsSet(CstSizeInBits, CstEltSizeInBits);
+ UndefBits |= EltUndef.shl(i * CstEltSizeInBits);
+ continue;
+ }
- if (!MaskTy->isVectorTy())
- return;
- int NumElts = MaskTy->getVectorNumElements();
+ APInt EltBits = cast<ConstantInt>(COp)->getValue();
+ EltBits = EltBits.zextOrTrunc(CstSizeInBits);
+ MaskBits |= EltBits.shl(i * CstEltSizeInBits);
+ }
- Type *EltTy = MaskTy->getVectorElementType();
- if (!EltTy->isIntegerTy())
- return;
+ // Now extract the undef/constant bit data into the raw shuffle masks.
+ assert((CstSizeInBits % MaskEltSizeInBits) == 0 &&
+ "Unaligned shuffle mask size");
- // The shuffle mask requires a byte vector - decode cases with
- // wider elements as well.
- unsigned BitWidth = cast<IntegerType>(EltTy)->getBitWidth();
- if ((BitWidth % 8) != 0)
+ unsigned NumMaskElts = CstSizeInBits / MaskEltSizeInBits;
+ UndefElts = SmallBitVector(NumMaskElts, false);
+ RawMask.resize(NumMaskElts, 0);
+
+ for (unsigned i = 0; i != NumMaskElts; ++i) {
+ APInt EltUndef = UndefBits.lshr(i * MaskEltSizeInBits);
+ EltUndef = EltUndef.zextOrTrunc(MaskEltSizeInBits);
+
+ // Only treat the element as UNDEF if all bits are UNDEF, otherwise
+ // treat it as zero.
+ if (EltUndef.isAllOnesValue()) {
+ UndefElts[i] = true;
+ RawMask[i] = 0;
+ continue;
+ }
+
+ APInt EltBits = MaskBits.lshr(i * MaskEltSizeInBits);
+ EltBits = EltBits.zextOrTrunc(MaskEltSizeInBits);
+ RawMask[i] = EltBits.getZExtValue();
+ }
+
+ return true;
+}
+
+void DecodePSHUFBMask(const Constant *C, SmallVectorImpl<int> &ShuffleMask) {
+ Type *MaskTy = C->getType();
+ unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
+ (void)MaskTySize;
+ assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) &&
+ "Unexpected vector size.");
+
+ // The shuffle mask requires a byte vector.
+ SmallBitVector UndefElts;
+ SmallVector<uint64_t, 32> RawMask;
+ if (!extractConstantMask(C, 8, UndefElts, RawMask))
return;
- int Scale = BitWidth / 8;
- int NumBytes = NumElts * Scale;
- ShuffleMask.reserve(NumBytes);
+ unsigned NumElts = RawMask.size();
+ assert((NumElts == 16 || NumElts == 32 || NumElts == 64) &&
+ "Unexpected number of vector elements.");
- for (int i = 0; i != NumElts; ++i) {
- Constant *COp = C->getAggregateElement(i);
- if (!COp) {
- ShuffleMask.clear();
- return;
- } else if (isa<UndefValue>(COp)) {
- ShuffleMask.append(Scale, SM_SentinelUndef);
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (UndefElts[i]) {
+ ShuffleMask.push_back(SM_SentinelUndef);
continue;
}
- APInt APElt = cast<ConstantInt>(COp)->getValue();
- for (int j = 0; j != Scale; ++j) {
+ uint64_t Element = RawMask[i];
+ // If the high bit (7) of the byte is set, the element is zeroed.
+ if (Element & (1 << 7))
+ ShuffleMask.push_back(SM_SentinelZero);
+ else {
// For AVX vectors with 32 bytes the base of the shuffle is the 16-byte
// lane of the vector we're inside.
- int Base = ((i * Scale) + j) & ~0xf;
-
- uint64_t Element = APElt.getLoBits(8).getZExtValue();
- APElt = APElt.lshr(8);
-
- // If the high bit (7) of the byte is set, the element is zeroed.
- if (Element & (1 << 7))
- ShuffleMask.push_back(SM_SentinelZero);
- else {
- // Only the least significant 4 bits of the byte are used.
- int Index = Base + (Element & 0xf);
- ShuffleMask.push_back(Index);
- }
+ unsigned Base = i & ~0xf;
+
+ // Only the least significant 4 bits of the byte are used.
+ int Index = Base + (Element & 0xf);
+ ShuffleMask.push_back(Index);
}
}
-
- assert(NumBytes == (int)ShuffleMask.size() && "Unexpected shuffle mask size");
}
void DecodeVPERMILPMask(const Constant *C, unsigned ElSize,
SmallVectorImpl<int> &ShuffleMask) {
Type *MaskTy = C->getType();
- // It is not an error for the PSHUFB mask to not be a vector of i8 because the
- // constant pool uniques constants by their bit representation.
- // e.g. the following take up the same space in the constant pool:
- // i128 -170141183420855150465331762880109871104
- //
- // <2 x i64> <i64 -9223372034707292160, i64 -9223372034707292160>
- //
- // <4 x i32> <i32 -2147483648, i32 -2147483648,
- // i32 -2147483648, i32 -2147483648>
-
- if (ElSize != 32 && ElSize != 64)
- return;
-
unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
- if (MaskTySize != 128 && MaskTySize != 256 && MaskTySize != 512)
- return;
-
- // Only support vector types.
- if (!MaskTy->isVectorTy())
+ (void)MaskTySize;
+ assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) &&
+ "Unexpected vector size.");
+ assert((ElSize == 32 || ElSize == 64) && "Unexpected vector element size.");
+
+ // The shuffle mask requires elements the same size as the target.
+ SmallBitVector UndefElts;
+ SmallVector<uint64_t, 8> RawMask;
+ if (!extractConstantMask(C, ElSize, UndefElts, RawMask))
return;
- // Make sure its an integer type.
- Type *VecEltTy = MaskTy->getVectorElementType();
- if (!VecEltTy->isIntegerTy())
- return;
-
- // Support any element type from byte up to element size.
- // This is necessary primarily because 64-bit elements get split to 32-bit
- // in the constant pool on 32-bit target.
- unsigned EltTySize = VecEltTy->getIntegerBitWidth();
- if (EltTySize < 8 || EltTySize > ElSize)
- return;
-
- unsigned NumElements = MaskTySize / ElSize;
- assert((NumElements == 2 || NumElements == 4 || NumElements == 8 ||
- NumElements == 16) &&
+ unsigned NumElts = RawMask.size();
+ unsigned NumEltsPerLane = 128 / ElSize;
+ assert((NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16) &&
"Unexpected number of vector elements.");
- ShuffleMask.reserve(NumElements);
- unsigned NumElementsPerLane = 128 / ElSize;
- unsigned Factor = ElSize / EltTySize;
- for (unsigned i = 0; i < NumElements; ++i) {
- Constant *COp = C->getAggregateElement(i * Factor);
- if (!COp) {
- ShuffleMask.clear();
- return;
- } else if (isa<UndefValue>(COp)) {
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (UndefElts[i]) {
ShuffleMask.push_back(SM_SentinelUndef);
continue;
}
- int Index = i & ~(NumElementsPerLane - 1);
- uint64_t Element = cast<ConstantInt>(COp)->getZExtValue();
+
+ int Index = i & ~(NumEltsPerLane - 1);
+ uint64_t Element = RawMask[i];
if (ElSize == 64)
Index += (Element >> 1) & 0x1;
else
Index += Element & 0x3;
+
ShuffleMask.push_back(Index);
}
-
- // TODO: Handle funny-looking vectors too.
}
void DecodeVPERMIL2PMask(const Constant *C, unsigned M2Z, unsigned ElSize,
SmallVectorImpl<int> &ShuffleMask) {
Type *MaskTy = C->getType();
-
unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
- if (MaskTySize != 128 && MaskTySize != 256)
- return;
+ (void)MaskTySize;
+ assert((MaskTySize == 128 || MaskTySize == 256) && "Unexpected vector size.");
- // Only support vector types.
- if (!MaskTy->isVectorTy())
+ // The shuffle mask requires elements the same size as the target.
+ SmallBitVector UndefElts;
+ SmallVector<uint64_t, 8> RawMask;
+ if (!extractConstantMask(C, ElSize, UndefElts, RawMask))
return;
- // Make sure its an integer type.
- Type *VecEltTy = MaskTy->getVectorElementType();
- if (!VecEltTy->isIntegerTy())
- return;
-
- // Support any element type from byte up to element size.
- // This is necessary primarily because 64-bit elements get split to 32-bit
- // in the constant pool on 32-bit target.
- unsigned EltTySize = VecEltTy->getIntegerBitWidth();
- if (EltTySize < 8 || EltTySize > ElSize)
- return;
-
- unsigned NumElements = MaskTySize / ElSize;
- assert((NumElements == 2 || NumElements == 4 || NumElements == 8) &&
+ unsigned NumElts = RawMask.size();
+ unsigned NumEltsPerLane = 128 / ElSize;
+ assert((NumElts == 2 || NumElts == 4 || NumElts == 8) &&
"Unexpected number of vector elements.");
- ShuffleMask.reserve(NumElements);
- unsigned NumElementsPerLane = 128 / ElSize;
- unsigned Factor = ElSize / EltTySize;
- for (unsigned i = 0; i < NumElements; ++i) {
- Constant *COp = C->getAggregateElement(i * Factor);
- if (!COp) {
- ShuffleMask.clear();
- return;
- } else if (isa<UndefValue>(COp)) {
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (UndefElts[i]) {
ShuffleMask.push_back(SM_SentinelUndef);
continue;
}
@@ -201,7 +200,7 @@ void DecodeVPERMIL2PMask(const Constant *C, unsigned M2Z, unsigned ElSize,
// Bits[3] - Match Bit.
// Bits[2:1] - (Per Lane) PD Shuffle Mask.
// Bits[2:0] - (Per Lane) PS Shuffle Mask.
- uint64_t Selector = cast<ConstantInt>(COp)->getZExtValue();
+ uint64_t Selector = RawMask[i];
unsigned MatchBit = (Selector >> 3) & 0x1;
// M2Z[0:1] MatchBit
@@ -215,51 +214,34 @@ void DecodeVPERMIL2PMask(const Constant *C, unsigned M2Z, unsigned ElSize,
continue;
}
- int Index = i & ~(NumElementsPerLane - 1);
+ int Index = i & ~(NumEltsPerLane - 1);
if (ElSize == 64)
Index += (Selector >> 1) & 0x1;
else
Index += Selector & 0x3;
int Src = (Selector >> 2) & 0x1;
- Index += Src * NumElements;
+ Index += Src * NumElts;
ShuffleMask.push_back(Index);
}
-
- // TODO: Handle funny-looking vectors too.
}
void DecodeVPPERMMask(const Constant *C, SmallVectorImpl<int> &ShuffleMask) {
- Type *MaskTy = C->getType();
- assert(MaskTy->getPrimitiveSizeInBits() == 128);
-
- // Only support vector types.
- if (!MaskTy->isVectorTy())
- return;
-
- // Make sure its an integer type.
- Type *VecEltTy = MaskTy->getVectorElementType();
- if (!VecEltTy->isIntegerTy())
- return;
+ assert(C->getType()->getPrimitiveSizeInBits() == 128 &&
+ "Unexpected vector size.");
- // The shuffle mask requires a byte vector - decode cases with
- // wider elements as well.
- unsigned BitWidth = cast<IntegerType>(VecEltTy)->getBitWidth();
- if ((BitWidth % 8) != 0)
+ // The shuffle mask requires a byte vector.
+ SmallBitVector UndefElts;
+ SmallVector<uint64_t, 32> RawMask;
+ if (!extractConstantMask(C, 8, UndefElts, RawMask))
return;
- int NumElts = MaskTy->getVectorNumElements();
- int Scale = BitWidth / 8;
- int NumBytes = NumElts * Scale;
- ShuffleMask.reserve(NumBytes);
+ unsigned NumElts = RawMask.size();
+ assert(NumElts == 16 && "Unexpected number of vector elements.");
- for (int i = 0; i != NumElts; ++i) {
- Constant *COp = C->getAggregateElement(i);
- if (!COp) {
- ShuffleMask.clear();
- return;
- } else if (isa<UndefValue>(COp)) {
- ShuffleMask.append(Scale, SM_SentinelUndef);
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (UndefElts[i]) {
+ ShuffleMask.push_back(SM_SentinelUndef);
continue;
}
@@ -275,82 +257,77 @@ void DecodeVPPERMMask(const Constant *C, SmallVectorImpl<int> &ShuffleMask) {
// 4 - 00h (zero - fill).
// 5 - FFh (ones - fill).
// 6 - Most significant bit of source byte replicated in all bit positions.
- // 7 - Invert most significant bit of source byte and replicate in all bit positions.
- APInt MaskElt = cast<ConstantInt>(COp)->getValue();
- for (int j = 0; j != Scale; ++j) {
- APInt Index = MaskElt.getLoBits(5);
- APInt PermuteOp = MaskElt.lshr(5).getLoBits(3);
- MaskElt = MaskElt.lshr(8);
-
- if (PermuteOp == 4) {
- ShuffleMask.push_back(SM_SentinelZero);
- continue;
- }
- if (PermuteOp != 0) {
- ShuffleMask.clear();
- return;
- }
- ShuffleMask.push_back((int)Index.getZExtValue());
+ // 7 - Invert most significant bit of source byte and replicate in all bit
+ // positions.
+ uint64_t Element = RawMask[i];
+ uint64_t Index = Element & 0x1F;
+ uint64_t PermuteOp = (Element >> 5) & 0x7;
+
+ if (PermuteOp == 4) {
+ ShuffleMask.push_back(SM_SentinelZero);
+ continue;
+ }
+ if (PermuteOp != 0) {
+ ShuffleMask.clear();
+ return;
}
+ ShuffleMask.push_back((int)Index);
}
-
- assert(NumBytes == (int)ShuffleMask.size() && "Unexpected shuffle mask size");
}
-void DecodeVPERMVMask(const Constant *C, MVT VT,
+void DecodeVPERMVMask(const Constant *C, unsigned ElSize,
SmallVectorImpl<int> &ShuffleMask) {
Type *MaskTy = C->getType();
- if (MaskTy->isVectorTy()) {
- unsigned NumElements = MaskTy->getVectorNumElements();
- if (NumElements == VT.getVectorNumElements()) {
- unsigned EltMaskSize = Log2_64(NumElements);
- for (unsigned i = 0; i < NumElements; ++i) {
- Constant *COp = C->getAggregateElement(i);
- if (!COp || (!isa<UndefValue>(COp) && !isa<ConstantInt>(COp))) {
- ShuffleMask.clear();
- return;
- }
- if (isa<UndefValue>(COp))
- ShuffleMask.push_back(SM_SentinelUndef);
- else {
- APInt Element = cast<ConstantInt>(COp)->getValue();
- Element = Element.getLoBits(EltMaskSize);
- ShuffleMask.push_back(Element.getZExtValue());
- }
- }
- }
+ unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
+ (void)MaskTySize;
+ assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) &&
+ "Unexpected vector size.");
+ assert((ElSize == 8 || ElSize == 16 || ElSize == 32 || ElSize == 64) &&
+ "Unexpected vector element size.");
+
+ // The shuffle mask requires elements the same size as the target.
+ SmallBitVector UndefElts;
+ SmallVector<uint64_t, 8> RawMask;
+ if (!extractConstantMask(C, ElSize, UndefElts, RawMask))
return;
+
+ unsigned NumElts = RawMask.size();
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (UndefElts[i]) {
+ ShuffleMask.push_back(SM_SentinelUndef);
+ continue;
+ }
+ int Index = RawMask[i] & (NumElts - 1);
+ ShuffleMask.push_back(Index);
}
- // Scalar value; just broadcast it
- if (!isa<ConstantInt>(C))
- return;
- uint64_t Element = cast<ConstantInt>(C)->getZExtValue();
- int NumElements = VT.getVectorNumElements();
- Element &= (1 << NumElements) - 1;
- for (int i = 0; i < NumElements; ++i)
- ShuffleMask.push_back(Element);
}
-void DecodeVPERMV3Mask(const Constant *C, MVT VT,
+void DecodeVPERMV3Mask(const Constant *C, unsigned ElSize,
SmallVectorImpl<int> &ShuffleMask) {
Type *MaskTy = C->getType();
- unsigned NumElements = MaskTy->getVectorNumElements();
- if (NumElements == VT.getVectorNumElements()) {
- unsigned EltMaskSize = Log2_64(NumElements * 2);
- for (unsigned i = 0; i < NumElements; ++i) {
- Constant *COp = C->getAggregateElement(i);
- if (!COp) {
- ShuffleMask.clear();
- return;
- }
- if (isa<UndefValue>(COp))
- ShuffleMask.push_back(SM_SentinelUndef);
- else {
- APInt Element = cast<ConstantInt>(COp)->getValue();
- Element = Element.getLoBits(EltMaskSize);
- ShuffleMask.push_back(Element.getZExtValue());
- }
+ unsigned MaskTySize = MaskTy->getPrimitiveSizeInBits();
+ (void)MaskTySize;
+ assert((MaskTySize == 128 || MaskTySize == 256 || MaskTySize == 512) &&
+ "Unexpected vector size.");
+ assert((ElSize == 8 || ElSize == 16 || ElSize == 32 || ElSize == 64) &&
+ "Unexpected vector element size.");
+
+ // The shuffle mask requires elements the same size as the target.
+ SmallBitVector UndefElts;
+ SmallVector<uint64_t, 8> RawMask;
+ if (!extractConstantMask(C, ElSize, UndefElts, RawMask))
+ return;
+
+ unsigned NumElts = RawMask.size();
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ if (UndefElts[i]) {
+ ShuffleMask.push_back(SM_SentinelUndef);
+ continue;
}
+ int Index = RawMask[i] & (NumElts*2 - 1);
+ ShuffleMask.push_back(Index);
}
}
} // llvm namespace
diff --git a/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.h b/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.h
index d2565b8..b703cbb 100644
--- a/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.h
+++ b/contrib/llvm/lib/Target/X86/X86ShuffleDecodeConstantPool.h
@@ -40,11 +40,11 @@ void DecodeVPERMIL2PMask(const Constant *C, unsigned MatchImm, unsigned ElSize,
void DecodeVPPERMMask(const Constant *C, SmallVectorImpl<int> &ShuffleMask);
/// Decode a VPERM W/D/Q/PS/PD mask from an IR-level vector constant.
-void DecodeVPERMVMask(const Constant *C, MVT VT,
+void DecodeVPERMVMask(const Constant *C, unsigned ElSize,
SmallVectorImpl<int> &ShuffleMask);
/// Decode a VPERMT2 W/D/Q/PS/PD mask from an IR-level vector constant.
-void DecodeVPERMV3Mask(const Constant *C, MVT VT,
+void DecodeVPERMV3Mask(const Constant *C, unsigned ElSize,
SmallVectorImpl<int> &ShuffleMask);
} // llvm namespace
diff --git a/contrib/llvm/lib/Target/X86/X86Subtarget.cpp b/contrib/llvm/lib/Target/X86/X86Subtarget.cpp
index 8f77682..586bb7b 100644
--- a/contrib/llvm/lib/Target/X86/X86Subtarget.cpp
+++ b/contrib/llvm/lib/Target/X86/X86Subtarget.cpp
@@ -92,6 +92,10 @@ unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV,
if (TM.getCodeModel() == CodeModel::Large)
return X86II::MO_NO_FLAG;
+ // Absolute symbols can be referenced directly.
+ if (GV && GV->isAbsoluteSymbolRef())
+ return X86II::MO_NO_FLAG;
+
if (TM.shouldAssumeDSOLocal(M, GV))
return classifyLocalReference(GV);
@@ -275,6 +279,7 @@ void X86Subtarget::initializeEnvironment() {
HasMWAITX = false;
HasMPX = false;
IsBTMemSlow = false;
+ IsPMULLDSlow = false;
IsSHLDSlow = false;
IsUAMem16Slow = false;
IsUAMem32Slow = false;
@@ -282,6 +287,9 @@ void X86Subtarget::initializeEnvironment() {
HasCmpxchg16b = false;
UseLeaForSP = false;
HasFastPartialYMMWrite = false;
+ HasFastScalarFSQRT = false;
+ HasFastVectorFSQRT = false;
+ HasFastLZCNT = false;
HasSlowDivide32 = false;
HasSlowDivide64 = false;
PadShortFunctions = false;
@@ -328,6 +336,26 @@ X86Subtarget::X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS,
setPICStyle(PICStyles::GOT);
}
+const CallLowering *X86Subtarget::getCallLowering() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getCallLowering();
+}
+
+const InstructionSelector *X86Subtarget::getInstructionSelector() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getInstructionSelector();
+}
+
+const LegalizerInfo *X86Subtarget::getLegalizerInfo() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getLegalizerInfo();
+}
+
+const RegisterBankInfo *X86Subtarget::getRegBankInfo() const {
+ assert(GISel && "Access to GlobalISel APIs not set");
+ return GISel->getRegBankInfo();
+}
+
bool X86Subtarget::enableEarlyIfConversion() const {
return hasCMov() && X86EarlyIfConv;
}
diff --git a/contrib/llvm/lib/Target/X86/X86Subtarget.h b/contrib/llvm/lib/Target/X86/X86Subtarget.h
index a274b79..d80dc4a 100644
--- a/contrib/llvm/lib/Target/X86/X86Subtarget.h
+++ b/contrib/llvm/lib/Target/X86/X86Subtarget.h
@@ -19,6 +19,7 @@
#include "X86InstrInfo.h"
#include "X86SelectionDAGInfo.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <string>
@@ -177,6 +178,10 @@ protected:
/// True if SHLD instructions are slow.
bool IsSHLDSlow;
+ /// True if the PMULLD instruction is slow compared to PMULLW/PMULHW and
+ // PMULUDQ.
+ bool IsPMULLDSlow;
+
/// True if unaligned memory accesses of 16-bytes are slow.
bool IsUAMem16Slow;
@@ -199,14 +204,25 @@ protected:
/// of a YMM register without clearing the upper part.
bool HasFastPartialYMMWrite;
+ /// True if hardware SQRTSS instruction is at least as fast (latency) as
+ /// RSQRTSS followed by a Newton-Raphson iteration.
+ bool HasFastScalarFSQRT;
+
+ /// True if hardware SQRTPS/VSQRTPS instructions are at least as fast
+ /// (throughput) as RSQRTPS/VRSQRTPS followed by a Newton-Raphson iteration.
+ bool HasFastVectorFSQRT;
+
/// True if 8-bit divisions are significantly faster than
/// 32-bit divisions and should be used when possible.
bool HasSlowDivide32;
- /// True if 16-bit divides are significantly faster than
+ /// True if 32-bit divides are significantly faster than
/// 64-bit divisions and should be used when possible.
bool HasSlowDivide64;
+ /// True if LZCNT instruction is fast.
+ bool HasFastLZCNT;
+
/// True if the short functions should be padded to prevent
/// a stall when returning too early.
bool PadShortFunctions;
@@ -287,6 +303,10 @@ protected:
/// Instruction itineraries for scheduling
InstrItineraryData InstrItins;
+ /// Gather the accessor points to GlobalISel-related APIs.
+ /// This is used to avoid ifndefs spreading around while GISel is
+ /// an optional library.
+ std::unique_ptr<GISelAccessor> GISel;
private:
/// Override the stack alignment.
@@ -315,6 +335,9 @@ public:
X86Subtarget(const Triple &TT, StringRef CPU, StringRef FS,
const X86TargetMachine &TM, unsigned StackAlignOverride);
+ /// This object will take onwership of \p GISelAccessor.
+ void setGISelAccessor(GISelAccessor &GISel) { this->GISel.reset(&GISel); }
+
const X86TargetLowering *getTargetLowering() const override {
return &TLInfo;
}
@@ -342,6 +365,11 @@ public:
/// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
+ /// Methods used by Global ISel
+ const CallLowering *getCallLowering() const override;
+ const InstructionSelector *getInstructionSelector() const override;
+ const LegalizerInfo *getLegalizerInfo() const override;
+ const RegisterBankInfo *getRegBankInfo() const override;
private:
/// Initialize the full set of dependencies so we can use an initializer
/// list for X86Subtarget.
@@ -428,12 +456,16 @@ public:
bool hasMWAITX() const { return HasMWAITX; }
bool isBTMemSlow() const { return IsBTMemSlow; }
bool isSHLDSlow() const { return IsSHLDSlow; }
+ bool isPMULLDSlow() const { return IsPMULLDSlow; }
bool isUnalignedMem16Slow() const { return IsUAMem16Slow; }
bool isUnalignedMem32Slow() const { return IsUAMem32Slow; }
bool hasSSEUnalignedMem() const { return HasSSEUnalignedMem; }
bool hasCmpxchg16b() const { return HasCmpxchg16b; }
bool useLeaForSP() const { return UseLeaForSP; }
bool hasFastPartialYMMWrite() const { return HasFastPartialYMMWrite; }
+ bool hasFastScalarFSQRT() const { return HasFastScalarFSQRT; }
+ bool hasFastVectorFSQRT() const { return HasFastVectorFSQRT; }
+ bool hasFastLZCNT() const { return HasFastLZCNT; }
bool hasSlowDivide32() const { return HasSlowDivide32; }
bool hasSlowDivide64() const { return HasSlowDivide64; }
bool padShortFunctions() const { return PadShortFunctions; }
@@ -450,6 +482,8 @@ public:
bool hasPKU() const { return HasPKU; }
bool hasMPX() const { return HasMPX; }
+ virtual bool isXRaySupported() const override { return is64Bit(); }
+
bool isAtom() const { return X86ProcFamily == IntelAtom; }
bool isSLM() const { return X86ProcFamily == IntelSLM; }
bool useSoftFloat() const { return UseSoftFloat; }
@@ -465,7 +499,7 @@ public:
bool isTargetFreeBSD() const { return TargetTriple.isOSFreeBSD(); }
bool isTargetDragonFly() const { return TargetTriple.isOSDragonFly(); }
bool isTargetSolaris() const { return TargetTriple.isOSSolaris(); }
- bool isTargetPS4() const { return TargetTriple.isPS4(); }
+ bool isTargetPS4() const { return TargetTriple.isPS4CPU(); }
bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); }
diff --git a/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp b/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp
index 50c9c25..aa5cfc6 100644
--- a/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -13,8 +13,12 @@
#include "X86TargetMachine.h"
#include "X86.h"
+#include "X86CallLowering.h"
#include "X86TargetObjectFile.h"
#include "X86TargetTransformInfo.h"
+#include "llvm/CodeGen/GlobalISel/GISelAccessor.h"
+#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
+#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Function.h"
@@ -35,12 +39,14 @@ void initializeWinEHStatePassPass(PassRegistry &);
extern "C" void LLVMInitializeX86Target() {
// Register the target.
- RegisterTargetMachine<X86TargetMachine> X(TheX86_32Target);
- RegisterTargetMachine<X86TargetMachine> Y(TheX86_64Target);
+ RegisterTargetMachine<X86TargetMachine> X(getTheX86_32Target());
+ RegisterTargetMachine<X86TargetMachine> Y(getTheX86_64Target());
PassRegistry &PR = *PassRegistry::getPassRegistry();
+ initializeGlobalISel(PR);
initializeWinEHStatePassPass(PR);
initializeFixupBWInstPassPass(PR);
+ initializeEvexToVexInstPassPass(PR);
}
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
@@ -50,8 +56,12 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
return make_unique<TargetLoweringObjectFileMachO>();
}
+ if (TT.isOSFreeBSD())
+ return make_unique<X86FreeBSDTargetObjectFile>();
if (TT.isOSLinux() || TT.isOSNaCl())
return make_unique<X86LinuxNaClTargetObjectFile>();
+ if (TT.isOSFuchsia())
+ return make_unique<X86FuchsiaTargetObjectFile>();
if (TT.isOSBinFormatELF())
return make_unique<X86ELFTargetObjectFile>();
if (TT.isKnownWindowsMSVCEnvironment() || TT.isWindowsCoreCLREnvironment())
@@ -151,32 +161,47 @@ X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT,
CodeModel::Model CM, CodeGenOpt::Level OL)
: LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options,
getEffectiveRelocModel(TT, RM), CM, OL),
- TLOF(createTLOF(getTargetTriple())),
- Subtarget(TT, CPU, FS, *this, Options.StackAlignmentOverride) {
+ TLOF(createTLOF(getTargetTriple())) {
// Windows stack unwinder gets confused when execution flow "falls through"
// after a call to 'noreturn' function.
// To prevent that, we emit a trap for 'unreachable' IR instructions.
// (which on X86, happens to be the 'ud2' instruction)
// On PS4, the "return address" of a 'noreturn' call must still be within
// the calling function, and TrapUnreachable is an easy way to get that.
- if (Subtarget.isTargetWin64() || Subtarget.isTargetPS4())
+ // The check here for 64-bit windows is a bit icky, but as we're unlikely
+ // to ever want to mix 32 and 64-bit windows code in a single module
+ // this should be fine.
+ if ((TT.isOSWindows() && TT.getArch() == Triple::x86_64) || TT.isPS4())
this->Options.TrapUnreachable = true;
- // By default (and when -ffast-math is on), enable estimate codegen for
- // everything except scalar division. By default, use 1 refinement step for
- // all operations. Defaults may be overridden by using command-line options.
- // Scalar division estimates are disabled because they break too much
- // real-world code. These defaults match GCC behavior.
- this->Options.Reciprocals.setDefaults("sqrtf", true, 1);
- this->Options.Reciprocals.setDefaults("divf", false, 1);
- this->Options.Reciprocals.setDefaults("vec-sqrtf", true, 1);
- this->Options.Reciprocals.setDefaults("vec-divf", true, 1);
-
initAsmInfo();
}
X86TargetMachine::~X86TargetMachine() {}
+#ifdef LLVM_BUILD_GLOBAL_ISEL
+namespace {
+struct X86GISelActualAccessor : public GISelAccessor {
+ std::unique_ptr<CallLowering> CL;
+ X86GISelActualAccessor(CallLowering* CL): CL(CL) {}
+ const CallLowering *getCallLowering() const override {
+ return CL.get();
+ }
+ const InstructionSelector *getInstructionSelector() const override {
+ //TODO: Implement
+ return nullptr;
+ }
+ const LegalizerInfo *getLegalizerInfo() const override {
+ //TODO: Implement
+ return nullptr;
+ }
+ const RegisterBankInfo *getRegBankInfo() const override {
+ //TODO: Implement
+ return nullptr;
+ }
+};
+} // End anonymous namespace.
+#endif
const X86Subtarget *
X86TargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
@@ -216,6 +241,13 @@ X86TargetMachine::getSubtargetImpl(const Function &F) const {
resetTargetOptions(F);
I = llvm::make_unique<X86Subtarget>(TargetTriple, CPU, FS, *this,
Options.StackAlignmentOverride);
+#ifndef LLVM_BUILD_GLOBAL_ISEL
+ GISelAccessor *GISel = new GISelAccessor();
+#else
+ X86GISelActualAccessor *GISel = new X86GISelActualAccessor(
+ new X86CallLowering(*I->getTargetLowering()));
+#endif
+ I->setGISelAccessor(*GISel);
}
return I.get();
}
@@ -254,9 +286,22 @@ public:
return getTM<X86TargetMachine>();
}
+ ScheduleDAGInstrs *
+ createMachineScheduler(MachineSchedContext *C) const override {
+ ScheduleDAGMILive *DAG = createGenericSchedLive(C);
+ DAG->addMutation(createMacroFusionDAGMutation(DAG->TII));
+ return DAG;
+ }
+
void addIRPasses() override;
bool addInstSelector() override;
- bool addILPOpts() override;
+#ifdef LLVM_BUILD_GLOBAL_ISEL
+ bool addIRTranslator() override;
+ bool addLegalizeMachineIR() override;
+ bool addRegBankSelect() override;
+ bool addGlobalInstructionSelect() override;
+#endif
+bool addILPOpts() override;
bool addPreISel() override;
void addPreRegAlloc() override;
void addPostRegAlloc() override;
@@ -273,6 +318,9 @@ void X86PassConfig::addIRPasses() {
addPass(createAtomicExpandPass(&getX86TargetMachine()));
TargetPassConfig::addIRPasses();
+
+ if (TM->getOptLevel() != CodeGenOpt::None)
+ addPass(createInterleavedAccessPass(TM));
}
bool X86PassConfig::addInstSelector() {
@@ -288,6 +336,28 @@ bool X86PassConfig::addInstSelector() {
return false;
}
+#ifdef LLVM_BUILD_GLOBAL_ISEL
+bool X86PassConfig::addIRTranslator() {
+ addPass(new IRTranslator());
+ return false;
+}
+
+bool X86PassConfig::addLegalizeMachineIR() {
+ //TODO: Implement
+ return false;
+}
+
+bool X86PassConfig::addRegBankSelect() {
+ //TODO: Implement
+ return false;
+}
+
+bool X86PassConfig::addGlobalInstructionSelect() {
+ //TODO: Implement
+ return false;
+}
+#endif
+
bool X86PassConfig::addILPOpts() {
addPass(&EarlyIfConverterID);
if (EnableMachineCombinerPass)
@@ -321,7 +391,7 @@ void X86PassConfig::addPreSched2() { addPass(createX86ExpandPseudoPass()); }
void X86PassConfig::addPreEmitPass() {
if (getOptLevel() != CodeGenOpt::None)
- addPass(createExecutionDependencyFixPass(&X86::VR128RegClass));
+ addPass(createExecutionDependencyFixPass(&X86::VR128XRegClass));
if (UseVZeroUpper)
addPass(createX86IssueVZeroUpperPass());
@@ -330,5 +400,6 @@ void X86PassConfig::addPreEmitPass() {
addPass(createX86FixupBWInsts());
addPass(createX86PadShortFunctions());
addPass(createX86FixupLEAs());
+ addPass(createX86EvexToVexInsts());
}
}
diff --git a/contrib/llvm/lib/Target/X86/X86TargetMachine.h b/contrib/llvm/lib/Target/X86/X86TargetMachine.h
index 4734a44..d756d07 100644
--- a/contrib/llvm/lib/Target/X86/X86TargetMachine.h
+++ b/contrib/llvm/lib/Target/X86/X86TargetMachine.h
@@ -24,8 +24,6 @@ class StringRef;
class X86TargetMachine final : public LLVMTargetMachine {
std::unique_ptr<TargetLoweringObjectFile> TLOF;
- X86Subtarget Subtarget;
-
mutable StringMap<std::unique_ptr<X86Subtarget>> SubtargetMap;
public:
diff --git a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp
index d664cff..7f70829 100644
--- a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp
@@ -24,14 +24,13 @@ using namespace llvm;
using namespace dwarf;
const MCExpr *X86_64MachoTargetObjectFile::getTTypeGlobalReference(
- const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
- const TargetMachine &TM, MachineModuleInfo *MMI,
- MCStreamer &Streamer) const {
+ const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM,
+ MachineModuleInfo *MMI, MCStreamer &Streamer) const {
// On Darwin/X86-64, we can reference dwarf symbols with foo@GOTPCREL+4, which
// is an indirect pc-relative reference.
if ((Encoding & DW_EH_PE_indirect) && (Encoding & DW_EH_PE_pcrel)) {
- const MCSymbol *Sym = TM.getSymbol(GV, Mang);
+ const MCSymbol *Sym = TM.getSymbol(GV);
const MCExpr *Res =
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext());
const MCExpr *Four = MCConstantExpr::create(4, getContext());
@@ -39,13 +38,13 @@ const MCExpr *X86_64MachoTargetObjectFile::getTTypeGlobalReference(
}
return TargetLoweringObjectFileMachO::getTTypeGlobalReference(
- GV, Encoding, Mang, TM, MMI, Streamer);
+ GV, Encoding, TM, MMI, Streamer);
}
MCSymbol *X86_64MachoTargetObjectFile::getCFIPersonalitySymbol(
- const GlobalValue *GV, Mangler &Mang, const TargetMachine &TM,
+ const GlobalValue *GV, const TargetMachine &TM,
MachineModuleInfo *MMI) const {
- return TM.getSymbol(GV, Mang);
+ return TM.getSymbol(GV);
}
const MCExpr *X86_64MachoTargetObjectFile::getIndirectSymViaGOTPCRel(
@@ -67,6 +66,20 @@ const MCExpr *X86ELFTargetObjectFile::getDebugThreadLocalSymbol(
}
void
+X86FreeBSDTargetObjectFile::Initialize(MCContext &Ctx,
+ const TargetMachine &TM) {
+ TargetLoweringObjectFileELF::Initialize(Ctx, TM);
+ InitializeELF(TM.Options.UseInitArray);
+}
+
+void
+X86FuchsiaTargetObjectFile::Initialize(MCContext &Ctx,
+ const TargetMachine &TM) {
+ TargetLoweringObjectFileELF::Initialize(Ctx, TM);
+ InitializeELF(TM.Options.UseInitArray);
+}
+
+void
X86LinuxNaClTargetObjectFile::Initialize(MCContext &Ctx,
const TargetMachine &TM) {
TargetLoweringObjectFileELF::Initialize(Ctx, TM);
@@ -74,7 +87,7 @@ X86LinuxNaClTargetObjectFile::Initialize(MCContext &Ctx,
}
const MCExpr *X86WindowsTargetObjectFile::lowerRelativeReference(
- const GlobalValue *LHS, const GlobalValue *RHS, Mangler &Mang,
+ const GlobalValue *LHS, const GlobalValue *RHS,
const TargetMachine &TM) const {
// Our symbols should exist in address space zero, cowardly no-op if
// otherwise.
@@ -95,8 +108,9 @@ const MCExpr *X86WindowsTargetObjectFile::lowerRelativeReference(
cast<GlobalVariable>(RHS)->hasInitializer() || RHS->hasSection())
return nullptr;
- return MCSymbolRefExpr::create(
- TM.getSymbol(LHS, Mang), MCSymbolRefExpr::VK_COFF_IMGREL32, getContext());
+ return MCSymbolRefExpr::create(TM.getSymbol(LHS),
+ MCSymbolRefExpr::VK_COFF_IMGREL32,
+ getContext());
}
static std::string APIntToHexString(const APInt &AI) {
diff --git a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h
index 2e703f1..39d2e84 100644
--- a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h
+++ b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h
@@ -19,15 +19,15 @@ namespace llvm {
/// x86-64.
class X86_64MachoTargetObjectFile : public TargetLoweringObjectFileMachO {
public:
- const MCExpr *
- getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
- Mangler &Mang, const TargetMachine &TM,
- MachineModuleInfo *MMI,
- MCStreamer &Streamer) const override;
+ const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
+ unsigned Encoding,
+ const TargetMachine &TM,
+ MachineModuleInfo *MMI,
+ MCStreamer &Streamer) const override;
// getCFIPersonalitySymbol - The symbol that gets passed to
// .cfi_personality.
- MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, Mangler &Mang,
+ MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV,
const TargetMachine &TM,
MachineModuleInfo *MMI) const override;
@@ -49,6 +49,17 @@ namespace llvm {
const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
};
+ /// X86FreeBSDTargetObjectFile - This implementation is used for FreeBSD
+ /// on x86 and x86-64.
+ class X86FreeBSDTargetObjectFile : public X86ELFTargetObjectFile {
+ void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
+ };
+
+ /// \brief This implementation is used for Fuchsia on x86-64.
+ class X86FuchsiaTargetObjectFile : public X86ELFTargetObjectFile {
+ void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
+ };
+
/// X86LinuxNaClTargetObjectFile - This implementation is used for linux and
/// Native Client on x86 and x86-64.
class X86LinuxNaClTargetObjectFile : public X86ELFTargetObjectFile {
@@ -59,7 +70,6 @@ namespace llvm {
class X86WindowsTargetObjectFile : public TargetLoweringObjectFileCOFF {
const MCExpr *
lowerRelativeReference(const GlobalValue *LHS, const GlobalValue *RHS,
- Mangler &Mang,
const TargetMachine &TM) const override;
/// \brief Given a mergeable constant with the specified size and relocation
diff --git a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
index f44a8c6..5715d82 100644
--- a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
+++ b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
@@ -13,6 +13,31 @@
/// independent and default TTI implementations handle the rest.
///
//===----------------------------------------------------------------------===//
+/// About Cost Model numbers used below it's necessary to say the following:
+/// the numbers correspond to some "generic" X86 CPU instead of usage of
+/// concrete CPU model. Usually the numbers correspond to CPU where the feature
+/// apeared at the first time. For example, if we do Subtarget.hasSSE42() in
+/// the lookups below the cost is based on Nehalem as that was the first CPU
+/// to support that feature level and thus has most likely the worst case cost.
+/// Some examples of other technologies/CPUs:
+/// SSE 3 - Pentium4 / Athlon64
+/// SSE 4.1 - Penryn
+/// SSE 4.2 - Nehalem
+/// AVX - Sandy Bridge
+/// AVX2 - Haswell
+/// AVX-512 - Xeon Phi / Skylake
+/// And some examples of instruction target dependent costs (latency)
+/// divss sqrtss rsqrtss
+/// AMD K7 11-16 19 3
+/// Piledriver 9-24 13-15 5
+/// Jaguar 14 16 2
+/// Pentium II,III 18 30 2
+/// Nehalem 7-14 7-18 3
+/// Haswell 10-13 11 5
+/// TODO: Develop and implement the target dependent cost model and
+/// specialize cost numbers for different Cost Model Targets such as throughput,
+/// code size, latency and uop count.
+//===----------------------------------------------------------------------===//
#include "X86TargetTransformInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
@@ -55,9 +80,12 @@ unsigned X86TTIImpl::getNumberOfRegisters(bool Vector) {
unsigned X86TTIImpl::getRegisterBitWidth(bool Vector) {
if (Vector) {
- if (ST->hasAVX512()) return 512;
- if (ST->hasAVX()) return 256;
- if (ST->hasSSE1()) return 128;
+ if (ST->hasAVX512())
+ return 512;
+ if (ST->hasAVX())
+ return 256;
+ if (ST->hasSSE1())
+ return 128;
return 0;
}
@@ -86,15 +114,62 @@ unsigned X86TTIImpl::getMaxInterleaveFactor(unsigned VF) {
}
int X86TTIImpl::getArithmeticInstrCost(
- unsigned Opcode, Type *Ty, TTI::OperandValueKind Op1Info,
- TTI::OperandValueKind Op2Info, TTI::OperandValueProperties Opd1PropInfo,
- TTI::OperandValueProperties Opd2PropInfo) {
+ unsigned Opcode, Type *Ty,
+ TTI::OperandValueKind Op1Info, TTI::OperandValueKind Op2Info,
+ TTI::OperandValueProperties Opd1PropInfo,
+ TTI::OperandValueProperties Opd2PropInfo,
+ ArrayRef<const Value *> Args) {
// Legalize the type.
std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Ty);
int ISD = TLI->InstructionOpcodeToISD(Opcode);
assert(ISD && "Invalid opcode");
+ static const CostTblEntry SLMCostTable[] = {
+ { ISD::MUL, MVT::v4i32, 11 }, // pmulld
+ { ISD::MUL, MVT::v8i16, 2 }, // pmullw
+ { ISD::MUL, MVT::v16i8, 14 }, // extend/pmullw/trunc sequence.
+ { ISD::FMUL, MVT::f64, 2 }, // mulsd
+ { ISD::FMUL, MVT::v2f64, 4 }, // mulpd
+ { ISD::FMUL, MVT::v4f32, 2 }, // mulps
+ { ISD::FDIV, MVT::f32, 17 }, // divss
+ { ISD::FDIV, MVT::v4f32, 39 }, // divps
+ { ISD::FDIV, MVT::f64, 32 }, // divsd
+ { ISD::FDIV, MVT::v2f64, 69 }, // divpd
+ { ISD::FADD, MVT::v2f64, 2 }, // addpd
+ { ISD::FSUB, MVT::v2f64, 2 }, // subpd
+ // v2i64/v4i64 mul is custom lowered as a series of long
+ // multiplies(3), shifts(3) and adds(2).
+ // slm muldq version throughput is 2
+ { ISD::MUL, MVT::v2i64, 11 },
+ };
+
+ if (ST->isSLM()) {
+ if (Args.size() == 2 && ISD == ISD::MUL && LT.second == MVT::v4i32) {
+ // Check if the operands can be shrinked into a smaller datatype.
+ bool Op1Signed = false;
+ unsigned Op1MinSize = BaseT::minRequiredElementSize(Args[0], Op1Signed);
+ bool Op2Signed = false;
+ unsigned Op2MinSize = BaseT::minRequiredElementSize(Args[1], Op2Signed);
+
+ bool signedMode = Op1Signed | Op2Signed;
+ unsigned OpMinSize = std::max(Op1MinSize, Op2MinSize);
+
+ if (OpMinSize <= 7)
+ return LT.first * 3; // pmullw/sext
+ if (!signedMode && OpMinSize <= 8)
+ return LT.first * 3; // pmullw/zext
+ if (OpMinSize <= 15)
+ return LT.first * 5; // pmullw/pmulhw/pshuf
+ if (!signedMode && OpMinSize <= 16)
+ return LT.first * 5; // pmullw/pmulhw/pshuf
+ }
+ if (const auto *Entry = CostTableLookup(SLMCostTable, ISD,
+ LT.second)) {
+ return LT.first * Entry->Cost;
+ }
+ }
+
if (ISD == ISD::SDIV &&
Op2Info == TargetTransformInfo::OK_UniformConstantValue &&
Opd2PropInfo == TargetTransformInfo::OP_PowerOf2) {
@@ -115,7 +190,39 @@ int X86TTIImpl::getArithmeticInstrCost(
return Cost;
}
+ static const CostTblEntry AVX512BWUniformConstCostTable[] = {
+ { ISD::SHL, MVT::v64i8, 2 }, // psllw + pand.
+ { ISD::SRL, MVT::v64i8, 2 }, // psrlw + pand.
+ { ISD::SRA, MVT::v64i8, 4 }, // psrlw, pand, pxor, psubb.
+
+ { ISD::SDIV, MVT::v32i16, 6 }, // vpmulhw sequence
+ { ISD::UDIV, MVT::v32i16, 6 }, // vpmulhuw sequence
+ };
+
+ if (Op2Info == TargetTransformInfo::OK_UniformConstantValue &&
+ ST->hasBWI()) {
+ if (const auto *Entry = CostTableLookup(AVX512BWUniformConstCostTable, ISD,
+ LT.second))
+ return LT.first * Entry->Cost;
+ }
+
+ static const CostTblEntry AVX512UniformConstCostTable[] = {
+ { ISD::SDIV, MVT::v16i32, 15 }, // vpmuldq sequence
+ { ISD::UDIV, MVT::v16i32, 15 }, // vpmuludq sequence
+ };
+
+ if (Op2Info == TargetTransformInfo::OK_UniformConstantValue &&
+ ST->hasAVX512()) {
+ if (const auto *Entry = CostTableLookup(AVX512UniformConstCostTable, ISD,
+ LT.second))
+ return LT.first * Entry->Cost;
+ }
+
static const CostTblEntry AVX2UniformConstCostTable[] = {
+ { ISD::SHL, MVT::v32i8, 2 }, // psllw + pand.
+ { ISD::SRL, MVT::v32i8, 2 }, // psrlw + pand.
+ { ISD::SRA, MVT::v32i8, 4 }, // psrlw, pand, pxor, psubb.
+
{ ISD::SRA, MVT::v4i64, 4 }, // 2 x psrad + shuffle.
{ ISD::SDIV, MVT::v16i16, 6 }, // vpmulhw sequence
@@ -131,21 +238,136 @@ int X86TTIImpl::getArithmeticInstrCost(
return LT.first * Entry->Cost;
}
+ static const CostTblEntry SSE2UniformConstCostTable[] = {
+ { ISD::SHL, MVT::v16i8, 2 }, // psllw + pand.
+ { ISD::SRL, MVT::v16i8, 2 }, // psrlw + pand.
+ { ISD::SRA, MVT::v16i8, 4 }, // psrlw, pand, pxor, psubb.
+
+ { ISD::SHL, MVT::v32i8, 4 }, // 2*(psllw + pand).
+ { ISD::SRL, MVT::v32i8, 4 }, // 2*(psrlw + pand).
+ { ISD::SRA, MVT::v32i8, 8 }, // 2*(psrlw, pand, pxor, psubb).
+
+ { ISD::SDIV, MVT::v16i16, 12 }, // pmulhw sequence
+ { ISD::SDIV, MVT::v8i16, 6 }, // pmulhw sequence
+ { ISD::UDIV, MVT::v16i16, 12 }, // pmulhuw sequence
+ { ISD::UDIV, MVT::v8i16, 6 }, // pmulhuw sequence
+ { ISD::SDIV, MVT::v8i32, 38 }, // pmuludq sequence
+ { ISD::SDIV, MVT::v4i32, 19 }, // pmuludq sequence
+ { ISD::UDIV, MVT::v8i32, 30 }, // pmuludq sequence
+ { ISD::UDIV, MVT::v4i32, 15 }, // pmuludq sequence
+ };
+
+ if (Op2Info == TargetTransformInfo::OK_UniformConstantValue &&
+ ST->hasSSE2()) {
+ // pmuldq sequence.
+ if (ISD == ISD::SDIV && LT.second == MVT::v8i32 && ST->hasAVX())
+ return LT.first * 30;
+ if (ISD == ISD::SDIV && LT.second == MVT::v4i32 && ST->hasSSE41())
+ return LT.first * 15;
+
+ if (const auto *Entry = CostTableLookup(SSE2UniformConstCostTable, ISD,
+ LT.second))
+ return LT.first * Entry->Cost;
+ }
+
+ static const CostTblEntry AVX2UniformCostTable[] = {
+ // Uniform splats are cheaper for the following instructions.
+ { ISD::SHL, MVT::v16i16, 1 }, // psllw.
+ { ISD::SRL, MVT::v16i16, 1 }, // psrlw.
+ { ISD::SRA, MVT::v16i16, 1 }, // psraw.
+ };
+
+ if (ST->hasAVX2() &&
+ ((Op2Info == TargetTransformInfo::OK_UniformConstantValue) ||
+ (Op2Info == TargetTransformInfo::OK_UniformValue))) {
+ if (const auto *Entry =
+ CostTableLookup(AVX2UniformCostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+ }
+
+ static const CostTblEntry SSE2UniformCostTable[] = {
+ // Uniform splats are cheaper for the following instructions.
+ { ISD::SHL, MVT::v8i16, 1 }, // psllw.
+ { ISD::SHL, MVT::v4i32, 1 }, // pslld
+ { ISD::SHL, MVT::v2i64, 1 }, // psllq.
+
+ { ISD::SRL, MVT::v8i16, 1 }, // psrlw.
+ { ISD::SRL, MVT::v4i32, 1 }, // psrld.
+ { ISD::SRL, MVT::v2i64, 1 }, // psrlq.
+
+ { ISD::SRA, MVT::v8i16, 1 }, // psraw.
+ { ISD::SRA, MVT::v4i32, 1 }, // psrad.
+ };
+
+ if (ST->hasSSE2() &&
+ ((Op2Info == TargetTransformInfo::OK_UniformConstantValue) ||
+ (Op2Info == TargetTransformInfo::OK_UniformValue))) {
+ if (const auto *Entry =
+ CostTableLookup(SSE2UniformCostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+ }
+
+ static const CostTblEntry AVX512DQCostTable[] = {
+ { ISD::MUL, MVT::v2i64, 1 },
+ { ISD::MUL, MVT::v4i64, 1 },
+ { ISD::MUL, MVT::v8i64, 1 }
+ };
+
+ // Look for AVX512DQ lowering tricks for custom cases.
+ if (ST->hasDQI())
+ if (const auto *Entry = CostTableLookup(AVX512DQCostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+
+ static const CostTblEntry AVX512BWCostTable[] = {
+ { ISD::SHL, MVT::v32i16, 1 }, // vpsllvw
+ { ISD::SRL, MVT::v32i16, 1 }, // vpsrlvw
+ { ISD::SRA, MVT::v32i16, 1 }, // vpsravw
+
+ { ISD::SHL, MVT::v64i8, 11 }, // vpblendvb sequence.
+ { ISD::SRL, MVT::v64i8, 11 }, // vpblendvb sequence.
+ { ISD::SRA, MVT::v64i8, 24 }, // vpblendvb sequence.
+
+ { ISD::MUL, MVT::v64i8, 11 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v32i8, 4 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v16i8, 4 }, // extend/pmullw/trunc sequence.
+
+ // Vectorizing division is a bad idea. See the SSE2 table for more comments.
+ { ISD::SDIV, MVT::v64i8, 64*20 },
+ { ISD::SDIV, MVT::v32i16, 32*20 },
+ { ISD::UDIV, MVT::v64i8, 64*20 },
+ { ISD::UDIV, MVT::v32i16, 32*20 }
+ };
+
+ // Look for AVX512BW lowering tricks for custom cases.
+ if (ST->hasBWI())
+ if (const auto *Entry = CostTableLookup(AVX512BWCostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+
static const CostTblEntry AVX512CostTable[] = {
- { ISD::SHL, MVT::v16i32, 1 },
- { ISD::SRL, MVT::v16i32, 1 },
- { ISD::SRA, MVT::v16i32, 1 },
- { ISD::SHL, MVT::v8i64, 1 },
- { ISD::SRL, MVT::v8i64, 1 },
- { ISD::SRA, MVT::v8i64, 1 },
+ { ISD::SHL, MVT::v16i32, 1 },
+ { ISD::SRL, MVT::v16i32, 1 },
+ { ISD::SRA, MVT::v16i32, 1 },
+ { ISD::SHL, MVT::v8i64, 1 },
+ { ISD::SRL, MVT::v8i64, 1 },
+ { ISD::SRA, MVT::v8i64, 1 },
+
+ { ISD::MUL, MVT::v32i8, 13 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v16i8, 5 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v16i32, 1 }, // pmulld
+ { ISD::MUL, MVT::v8i64, 8 }, // 3*pmuludq/3*shift/2*add
+
+ // Vectorizing division is a bad idea. See the SSE2 table for more comments.
+ { ISD::SDIV, MVT::v16i32, 16*20 },
+ { ISD::SDIV, MVT::v8i64, 8*20 },
+ { ISD::UDIV, MVT::v16i32, 16*20 },
+ { ISD::UDIV, MVT::v8i64, 8*20 }
};
- if (ST->hasAVX512()) {
+ if (ST->hasAVX512())
if (const auto *Entry = CostTableLookup(AVX512CostTable, ISD, LT.second))
return LT.first * Entry->Cost;
- }
- static const CostTblEntry AVX2CostTable[] = {
+ static const CostTblEntry AVX2ShiftCostTable[] = {
// Shifts on v4i64/v8i32 on AVX2 is legal even though we declare to
// customize them to detect the cases where shift amount is a scalar one.
{ ISD::SHL, MVT::v4i32, 1 },
@@ -169,11 +391,11 @@ int X86TTIImpl::getArithmeticInstrCost(
// is lowered into a vector multiply (vpmullw).
return LT.first;
- if (const auto *Entry = CostTableLookup(AVX2CostTable, ISD, LT.second))
+ if (const auto *Entry = CostTableLookup(AVX2ShiftCostTable, ISD, LT.second))
return LT.first * Entry->Cost;
}
- static const CostTblEntry XOPCostTable[] = {
+ static const CostTblEntry XOPShiftCostTable[] = {
// 128bit shifts take 1cy, but right shifts require negation beforehand.
{ ISD::SHL, MVT::v16i8, 1 },
{ ISD::SRL, MVT::v16i8, 2 },
@@ -203,87 +425,31 @@ int X86TTIImpl::getArithmeticInstrCost(
};
// Look for XOP lowering tricks.
- if (ST->hasXOP()) {
- if (const auto *Entry = CostTableLookup(XOPCostTable, ISD, LT.second))
- return LT.first * Entry->Cost;
- }
-
- static const CostTblEntry AVX2CustomCostTable[] = {
- { ISD::SHL, MVT::v32i8, 11 }, // vpblendvb sequence.
- { ISD::SHL, MVT::v16i16, 10 }, // extend/vpsrlvd/pack sequence.
-
- { ISD::SRL, MVT::v32i8, 11 }, // vpblendvb sequence.
- { ISD::SRL, MVT::v16i16, 10 }, // extend/vpsrlvd/pack sequence.
-
- { ISD::SRA, MVT::v32i8, 24 }, // vpblendvb sequence.
- { ISD::SRA, MVT::v16i16, 10 }, // extend/vpsravd/pack sequence.
- { ISD::SRA, MVT::v2i64, 4 }, // srl/xor/sub sequence.
- { ISD::SRA, MVT::v4i64, 4 }, // srl/xor/sub sequence.
-
- // Vectorizing division is a bad idea. See the SSE2 table for more comments.
- { ISD::SDIV, MVT::v32i8, 32*20 },
- { ISD::SDIV, MVT::v16i16, 16*20 },
- { ISD::SDIV, MVT::v8i32, 8*20 },
- { ISD::SDIV, MVT::v4i64, 4*20 },
- { ISD::UDIV, MVT::v32i8, 32*20 },
- { ISD::UDIV, MVT::v16i16, 16*20 },
- { ISD::UDIV, MVT::v8i32, 8*20 },
- { ISD::UDIV, MVT::v4i64, 4*20 },
- };
-
- // Look for AVX2 lowering tricks for custom cases.
- if (ST->hasAVX2()) {
- if (const auto *Entry = CostTableLookup(AVX2CustomCostTable, ISD,
- LT.second))
+ if (ST->hasXOP())
+ if (const auto *Entry = CostTableLookup(XOPShiftCostTable, ISD, LT.second))
return LT.first * Entry->Cost;
- }
- static const CostTblEntry
- SSE2UniformConstCostTable[] = {
- // We don't correctly identify costs of casts because they are marked as
- // custom.
- // Constant splats are cheaper for the following instructions.
- { ISD::SHL, MVT::v16i8, 1 }, // psllw.
- { ISD::SHL, MVT::v32i8, 2 }, // psllw.
- { ISD::SHL, MVT::v8i16, 1 }, // psllw.
+ static const CostTblEntry SSE2UniformShiftCostTable[] = {
+ // Uniform splats are cheaper for the following instructions.
{ ISD::SHL, MVT::v16i16, 2 }, // psllw.
- { ISD::SHL, MVT::v4i32, 1 }, // pslld
{ ISD::SHL, MVT::v8i32, 2 }, // pslld
- { ISD::SHL, MVT::v2i64, 1 }, // psllq.
{ ISD::SHL, MVT::v4i64, 2 }, // psllq.
- { ISD::SRL, MVT::v16i8, 1 }, // psrlw.
- { ISD::SRL, MVT::v32i8, 2 }, // psrlw.
- { ISD::SRL, MVT::v8i16, 1 }, // psrlw.
{ ISD::SRL, MVT::v16i16, 2 }, // psrlw.
- { ISD::SRL, MVT::v4i32, 1 }, // psrld.
{ ISD::SRL, MVT::v8i32, 2 }, // psrld.
- { ISD::SRL, MVT::v2i64, 1 }, // psrlq.
{ ISD::SRL, MVT::v4i64, 2 }, // psrlq.
- { ISD::SRA, MVT::v16i8, 4 }, // psrlw, pand, pxor, psubb.
- { ISD::SRA, MVT::v32i8, 8 }, // psrlw, pand, pxor, psubb.
- { ISD::SRA, MVT::v8i16, 1 }, // psraw.
{ ISD::SRA, MVT::v16i16, 2 }, // psraw.
- { ISD::SRA, MVT::v4i32, 1 }, // psrad.
{ ISD::SRA, MVT::v8i32, 2 }, // psrad.
{ ISD::SRA, MVT::v2i64, 4 }, // 2 x psrad + shuffle.
{ ISD::SRA, MVT::v4i64, 8 }, // 2 x psrad + shuffle.
-
- { ISD::SDIV, MVT::v8i16, 6 }, // pmulhw sequence
- { ISD::UDIV, MVT::v8i16, 6 }, // pmulhuw sequence
- { ISD::SDIV, MVT::v4i32, 19 }, // pmuludq sequence
- { ISD::UDIV, MVT::v4i32, 15 }, // pmuludq sequence
};
- if (Op2Info == TargetTransformInfo::OK_UniformConstantValue &&
- ST->hasSSE2()) {
- // pmuldq sequence.
- if (ISD == ISD::SDIV && LT.second == MVT::v4i32 && ST->hasSSE41())
- return LT.first * 15;
-
- if (const auto *Entry = CostTableLookup(SSE2UniformConstCostTable, ISD,
- LT.second))
+ if (ST->hasSSE2() &&
+ ((Op2Info == TargetTransformInfo::OK_UniformConstantValue) ||
+ (Op2Info == TargetTransformInfo::OK_UniformValue))) {
+ if (const auto *Entry =
+ CostTableLookup(SSE2UniformShiftCostTable, ISD, LT.second))
return LT.first * Entry->Cost;
}
@@ -291,60 +457,170 @@ int X86TTIImpl::getArithmeticInstrCost(
Op2Info == TargetTransformInfo::OK_NonUniformConstantValue) {
MVT VT = LT.second;
// Vector shift left by non uniform constant can be lowered
- // into vector multiply (pmullw/pmulld).
- if ((VT == MVT::v8i16 && ST->hasSSE2()) ||
- (VT == MVT::v4i32 && ST->hasSSE41()))
- return LT.first;
-
- // v16i16 and v8i32 shifts by non-uniform constants are lowered into a
- // sequence of extract + two vector multiply + insert.
- if ((VT == MVT::v8i32 || VT == MVT::v16i16) &&
- (ST->hasAVX() && !ST->hasAVX2()))
- ISD = ISD::MUL;
-
- // A vector shift left by non uniform constant is converted
- // into a vector multiply; the new multiply is eventually
- // lowered into a sequence of shuffles and 2 x pmuludq.
- if (VT == MVT::v4i32 && ST->hasSSE2())
+ // into vector multiply.
+ if (((VT == MVT::v8i16 || VT == MVT::v4i32) && ST->hasSSE2()) ||
+ ((VT == MVT::v16i16 || VT == MVT::v8i32) && ST->hasAVX()))
ISD = ISD::MUL;
}
+ static const CostTblEntry AVX2CostTable[] = {
+ { ISD::SHL, MVT::v32i8, 11 }, // vpblendvb sequence.
+ { ISD::SHL, MVT::v16i16, 10 }, // extend/vpsrlvd/pack sequence.
+
+ { ISD::SRL, MVT::v32i8, 11 }, // vpblendvb sequence.
+ { ISD::SRL, MVT::v16i16, 10 }, // extend/vpsrlvd/pack sequence.
+
+ { ISD::SRA, MVT::v32i8, 24 }, // vpblendvb sequence.
+ { ISD::SRA, MVT::v16i16, 10 }, // extend/vpsravd/pack sequence.
+ { ISD::SRA, MVT::v2i64, 4 }, // srl/xor/sub sequence.
+ { ISD::SRA, MVT::v4i64, 4 }, // srl/xor/sub sequence.
+
+ { ISD::SUB, MVT::v32i8, 1 }, // psubb
+ { ISD::ADD, MVT::v32i8, 1 }, // paddb
+ { ISD::SUB, MVT::v16i16, 1 }, // psubw
+ { ISD::ADD, MVT::v16i16, 1 }, // paddw
+ { ISD::SUB, MVT::v8i32, 1 }, // psubd
+ { ISD::ADD, MVT::v8i32, 1 }, // paddd
+ { ISD::SUB, MVT::v4i64, 1 }, // psubq
+ { ISD::ADD, MVT::v4i64, 1 }, // paddq
+
+ { ISD::MUL, MVT::v32i8, 17 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v16i8, 7 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v16i16, 1 }, // pmullw
+ { ISD::MUL, MVT::v8i32, 1 }, // pmulld
+ { ISD::MUL, MVT::v4i64, 8 }, // 3*pmuludq/3*shift/2*add
+
+ { ISD::FDIV, MVT::f32, 7 }, // Haswell from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f32, 7 }, // Haswell from http://www.agner.org/
+ { ISD::FDIV, MVT::v8f32, 14 }, // Haswell from http://www.agner.org/
+ { ISD::FDIV, MVT::f64, 14 }, // Haswell from http://www.agner.org/
+ { ISD::FDIV, MVT::v2f64, 14 }, // Haswell from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f64, 28 }, // Haswell from http://www.agner.org/
+ };
+
+ // Look for AVX2 lowering tricks for custom cases.
+ if (ST->hasAVX2())
+ if (const auto *Entry = CostTableLookup(AVX2CostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+
+ static const CostTblEntry AVX1CostTable[] = {
+ // We don't have to scalarize unsupported ops. We can issue two half-sized
+ // operations and we only need to extract the upper YMM half.
+ // Two ops + 1 extract + 1 insert = 4.
+ { ISD::MUL, MVT::v16i16, 4 },
+ { ISD::MUL, MVT::v8i32, 4 },
+ { ISD::SUB, MVT::v32i8, 4 },
+ { ISD::ADD, MVT::v32i8, 4 },
+ { ISD::SUB, MVT::v16i16, 4 },
+ { ISD::ADD, MVT::v16i16, 4 },
+ { ISD::SUB, MVT::v8i32, 4 },
+ { ISD::ADD, MVT::v8i32, 4 },
+ { ISD::SUB, MVT::v4i64, 4 },
+ { ISD::ADD, MVT::v4i64, 4 },
+
+ // A v4i64 multiply is custom lowered as two split v2i64 vectors that then
+ // are lowered as a series of long multiplies(3), shifts(3) and adds(2)
+ // Because we believe v4i64 to be a legal type, we must also include the
+ // extract+insert in the cost table. Therefore, the cost here is 18
+ // instead of 8.
+ { ISD::MUL, MVT::v4i64, 18 },
+
+ { ISD::MUL, MVT::v32i8, 26 }, // extend/pmullw/trunc sequence.
+
+ { ISD::FDIV, MVT::f32, 14 }, // SNB from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f32, 14 }, // SNB from http://www.agner.org/
+ { ISD::FDIV, MVT::v8f32, 28 }, // SNB from http://www.agner.org/
+ { ISD::FDIV, MVT::f64, 22 }, // SNB from http://www.agner.org/
+ { ISD::FDIV, MVT::v2f64, 22 }, // SNB from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f64, 44 }, // SNB from http://www.agner.org/
+
+ // Vectorizing division is a bad idea. See the SSE2 table for more comments.
+ { ISD::SDIV, MVT::v32i8, 32*20 },
+ { ISD::SDIV, MVT::v16i16, 16*20 },
+ { ISD::SDIV, MVT::v8i32, 8*20 },
+ { ISD::SDIV, MVT::v4i64, 4*20 },
+ { ISD::UDIV, MVT::v32i8, 32*20 },
+ { ISD::UDIV, MVT::v16i16, 16*20 },
+ { ISD::UDIV, MVT::v8i32, 8*20 },
+ { ISD::UDIV, MVT::v4i64, 4*20 },
+ };
+
+ if (ST->hasAVX())
+ if (const auto *Entry = CostTableLookup(AVX1CostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+
+ static const CostTblEntry SSE42CostTable[] = {
+ { ISD::FDIV, MVT::f32, 14 }, // Nehalem from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f32, 14 }, // Nehalem from http://www.agner.org/
+ { ISD::FDIV, MVT::f64, 22 }, // Nehalem from http://www.agner.org/
+ { ISD::FDIV, MVT::v2f64, 22 }, // Nehalem from http://www.agner.org/
+ };
+
+ if (ST->hasSSE42())
+ if (const auto *Entry = CostTableLookup(SSE42CostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+
+ static const CostTblEntry SSE41CostTable[] = {
+ { ISD::SHL, MVT::v16i8, 11 }, // pblendvb sequence.
+ { ISD::SHL, MVT::v32i8, 2*11 }, // pblendvb sequence.
+ { ISD::SHL, MVT::v8i16, 14 }, // pblendvb sequence.
+ { ISD::SHL, MVT::v16i16, 2*14 }, // pblendvb sequence.
+ { ISD::SHL, MVT::v4i32, 4 }, // pslld/paddd/cvttps2dq/pmulld
+ { ISD::SHL, MVT::v8i32, 2*4 }, // pslld/paddd/cvttps2dq/pmulld
+
+ { ISD::SRL, MVT::v16i8, 12 }, // pblendvb sequence.
+ { ISD::SRL, MVT::v32i8, 2*12 }, // pblendvb sequence.
+ { ISD::SRL, MVT::v8i16, 14 }, // pblendvb sequence.
+ { ISD::SRL, MVT::v16i16, 2*14 }, // pblendvb sequence.
+ { ISD::SRL, MVT::v4i32, 11 }, // Shift each lane + blend.
+ { ISD::SRL, MVT::v8i32, 2*11 }, // Shift each lane + blend.
+
+ { ISD::SRA, MVT::v16i8, 24 }, // pblendvb sequence.
+ { ISD::SRA, MVT::v32i8, 2*24 }, // pblendvb sequence.
+ { ISD::SRA, MVT::v8i16, 14 }, // pblendvb sequence.
+ { ISD::SRA, MVT::v16i16, 2*14 }, // pblendvb sequence.
+ { ISD::SRA, MVT::v4i32, 12 }, // Shift each lane + blend.
+ { ISD::SRA, MVT::v8i32, 2*12 }, // Shift each lane + blend.
+
+ { ISD::MUL, MVT::v4i32, 1 } // pmulld
+ };
+
+ if (ST->hasSSE41())
+ if (const auto *Entry = CostTableLookup(SSE41CostTable, ISD, LT.second))
+ return LT.first * Entry->Cost;
+
static const CostTblEntry SSE2CostTable[] = {
// We don't correctly identify costs of casts because they are marked as
// custom.
- // For some cases, where the shift amount is a scalar we would be able
- // to generate better code. Unfortunately, when this is the case the value
- // (the splat) will get hoisted out of the loop, thereby making it invisible
- // to ISel. The cost model must return worst case assumptions because it is
- // used for vectorization and we don't want to make vectorized code worse
- // than scalar code.
{ ISD::SHL, MVT::v16i8, 26 }, // cmpgtb sequence.
- { ISD::SHL, MVT::v32i8, 2*26 }, // cmpgtb sequence.
{ ISD::SHL, MVT::v8i16, 32 }, // cmpgtb sequence.
- { ISD::SHL, MVT::v16i16, 2*32 }, // cmpgtb sequence.
{ ISD::SHL, MVT::v4i32, 2*5 }, // We optimized this using mul.
{ ISD::SHL, MVT::v8i32, 2*2*5 }, // We optimized this using mul.
{ ISD::SHL, MVT::v2i64, 4 }, // splat+shuffle sequence.
{ ISD::SHL, MVT::v4i64, 2*4 }, // splat+shuffle sequence.
{ ISD::SRL, MVT::v16i8, 26 }, // cmpgtb sequence.
- { ISD::SRL, MVT::v32i8, 2*26 }, // cmpgtb sequence.
{ ISD::SRL, MVT::v8i16, 32 }, // cmpgtb sequence.
- { ISD::SRL, MVT::v16i16, 2*32 }, // cmpgtb sequence.
{ ISD::SRL, MVT::v4i32, 16 }, // Shift each lane + blend.
- { ISD::SRL, MVT::v8i32, 2*16 }, // Shift each lane + blend.
{ ISD::SRL, MVT::v2i64, 4 }, // splat+shuffle sequence.
{ ISD::SRL, MVT::v4i64, 2*4 }, // splat+shuffle sequence.
{ ISD::SRA, MVT::v16i8, 54 }, // unpacked cmpgtb sequence.
- { ISD::SRA, MVT::v32i8, 2*54 }, // unpacked cmpgtb sequence.
{ ISD::SRA, MVT::v8i16, 32 }, // cmpgtb sequence.
- { ISD::SRA, MVT::v16i16, 2*32 }, // cmpgtb sequence.
{ ISD::SRA, MVT::v4i32, 16 }, // Shift each lane + blend.
- { ISD::SRA, MVT::v8i32, 2*16 }, // Shift each lane + blend.
{ ISD::SRA, MVT::v2i64, 12 }, // srl/xor/sub sequence.
{ ISD::SRA, MVT::v4i64, 2*12 }, // srl/xor/sub sequence.
+ { ISD::MUL, MVT::v16i8, 12 }, // extend/pmullw/trunc sequence.
+ { ISD::MUL, MVT::v8i16, 1 }, // pmullw
+ { ISD::MUL, MVT::v4i32, 6 }, // 3*pmuludq/4*shuffle
+ { ISD::MUL, MVT::v2i64, 8 }, // 3*pmuludq/3*shift/2*add
+
+ { ISD::FDIV, MVT::f32, 23 }, // Pentium IV from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f32, 39 }, // Pentium IV from http://www.agner.org/
+ { ISD::FDIV, MVT::f64, 38 }, // Pentium IV from http://www.agner.org/
+ { ISD::FDIV, MVT::v2f64, 69 }, // Pentium IV from http://www.agner.org/
+
// It is not a good idea to vectorize division. We have to scalarize it and
// in the process we will often end up having to spilling regular
// registers. The overhead of division is going to dominate most kernels
@@ -352,61 +628,27 @@ int X86TTIImpl::getArithmeticInstrCost(
// generally a bad idea. Assume somewhat arbitrarily that we have to be able
// to hide "20 cycles" for each lane.
{ ISD::SDIV, MVT::v16i8, 16*20 },
- { ISD::SDIV, MVT::v8i16, 8*20 },
- { ISD::SDIV, MVT::v4i32, 4*20 },
- { ISD::SDIV, MVT::v2i64, 2*20 },
+ { ISD::SDIV, MVT::v8i16, 8*20 },
+ { ISD::SDIV, MVT::v4i32, 4*20 },
+ { ISD::SDIV, MVT::v2i64, 2*20 },
{ ISD::UDIV, MVT::v16i8, 16*20 },
- { ISD::UDIV, MVT::v8i16, 8*20 },
- { ISD::UDIV, MVT::v4i32, 4*20 },
- { ISD::UDIV, MVT::v2i64, 2*20 },
+ { ISD::UDIV, MVT::v8i16, 8*20 },
+ { ISD::UDIV, MVT::v4i32, 4*20 },
+ { ISD::UDIV, MVT::v2i64, 2*20 },
};
- if (ST->hasSSE2()) {
+ if (ST->hasSSE2())
if (const auto *Entry = CostTableLookup(SSE2CostTable, ISD, LT.second))
return LT.first * Entry->Cost;
- }
- static const CostTblEntry AVX1CostTable[] = {
- // We don't have to scalarize unsupported ops. We can issue two half-sized
- // operations and we only need to extract the upper YMM half.
- // Two ops + 1 extract + 1 insert = 4.
- { ISD::MUL, MVT::v16i16, 4 },
- { ISD::MUL, MVT::v8i32, 4 },
- { ISD::SUB, MVT::v8i32, 4 },
- { ISD::ADD, MVT::v8i32, 4 },
- { ISD::SUB, MVT::v4i64, 4 },
- { ISD::ADD, MVT::v4i64, 4 },
- // A v4i64 multiply is custom lowered as two split v2i64 vectors that then
- // are lowered as a series of long multiplies(3), shifts(4) and adds(2)
- // Because we believe v4i64 to be a legal type, we must also include the
- // split factor of two in the cost table. Therefore, the cost here is 18
- // instead of 9.
- { ISD::MUL, MVT::v4i64, 18 },
+ static const CostTblEntry SSE1CostTable[] = {
+ { ISD::FDIV, MVT::f32, 17 }, // Pentium III from http://www.agner.org/
+ { ISD::FDIV, MVT::v4f32, 34 }, // Pentium III from http://www.agner.org/
};
- // Look for AVX1 lowering tricks.
- if (ST->hasAVX() && !ST->hasAVX2()) {
- MVT VT = LT.second;
-
- if (const auto *Entry = CostTableLookup(AVX1CostTable, ISD, VT))
+ if (ST->hasSSE1())
+ if (const auto *Entry = CostTableLookup(SSE1CostTable, ISD, LT.second))
return LT.first * Entry->Cost;
- }
-
- // Custom lowering of vectors.
- static const CostTblEntry CustomLowered[] = {
- // A v2i64/v4i64 and multiply is custom lowered as a series of long
- // multiplies(3), shifts(4) and adds(2).
- { ISD::MUL, MVT::v2i64, 9 },
- { ISD::MUL, MVT::v4i64, 9 },
- };
- if (const auto *Entry = CostTableLookup(CustomLowered, ISD, LT.second))
- return LT.first * Entry->Cost;
-
- // Special lowering of v4i32 mul on sse2, sse3: Lower v4i32 mul as 2x shuffle,
- // 2x pmuludq, 2x shuffle.
- if (ISD == ISD::MUL && LT.second == MVT::v4i32 && ST->hasSSE2() &&
- !ST->hasSSE41())
- return LT.first * 6;
// Fallback to the default implementation.
return BaseT::getArithmeticInstrCost(Opcode, Ty, Op1Info, Op2Info);
@@ -414,112 +656,252 @@ int X86TTIImpl::getArithmeticInstrCost(
int X86TTIImpl::getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index,
Type *SubTp) {
- // We only estimate the cost of reverse and alternate shuffles.
- if (Kind != TTI::SK_Reverse && Kind != TTI::SK_Alternate)
- return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
+ // 64-bit packed float vectors (v2f32) are widened to type v4f32.
+ // 64-bit packed integer vectors (v2i32) are promoted to type v2i64.
+ std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Tp);
+
+ // For Broadcasts we are splatting the first element from the first input
+ // register, so only need to reference that input and all the output
+ // registers are the same.
+ if (Kind == TTI::SK_Broadcast)
+ LT.first = 1;
+
+ // We are going to permute multiple sources and the result will be in multiple
+ // destinations. Providing an accurate cost only for splits where the element
+ // type remains the same.
+ if (Kind == TTI::SK_PermuteSingleSrc && LT.first != 1) {
+ MVT LegalVT = LT.second;
+ if (LegalVT.getVectorElementType().getSizeInBits() ==
+ Tp->getVectorElementType()->getPrimitiveSizeInBits() &&
+ LegalVT.getVectorNumElements() < Tp->getVectorNumElements()) {
+
+ unsigned VecTySize = DL.getTypeStoreSize(Tp);
+ unsigned LegalVTSize = LegalVT.getStoreSize();
+ // Number of source vectors after legalization:
+ unsigned NumOfSrcs = (VecTySize + LegalVTSize - 1) / LegalVTSize;
+ // Number of destination vectors after legalization:
+ unsigned NumOfDests = LT.first;
+
+ Type *SingleOpTy = VectorType::get(Tp->getVectorElementType(),
+ LegalVT.getVectorNumElements());
+
+ unsigned NumOfShuffles = (NumOfSrcs - 1) * NumOfDests;
+ return NumOfShuffles *
+ getShuffleCost(TTI::SK_PermuteTwoSrc, SingleOpTy, 0, nullptr);
+ }
- if (Kind == TTI::SK_Reverse) {
- std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Tp);
- int Cost = 1;
- if (LT.second.getSizeInBits() > 128)
- Cost = 3; // Extract + insert + copy.
+ return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
+ }
- // Multiple by the number of parts.
- return Cost * LT.first;
+ // For 2-input shuffles, we must account for splitting the 2 inputs into many.
+ if (Kind == TTI::SK_PermuteTwoSrc && LT.first != 1) {
+ // We assume that source and destination have the same vector type.
+ int NumOfDests = LT.first;
+ int NumOfShufflesPerDest = LT.first * 2 - 1;
+ LT.first = NumOfDests * NumOfShufflesPerDest;
}
- if (Kind == TTI::SK_Alternate) {
- // 64-bit packed float vectors (v2f32) are widened to type v4f32.
- // 64-bit packed integer vectors (v2i32) are promoted to type v2i64.
- std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Tp);
+ static const CostTblEntry AVX512VBMIShuffleTbl[] = {
+ { TTI::SK_Reverse, MVT::v64i8, 1 }, // vpermb
+ { TTI::SK_Reverse, MVT::v32i8, 1 }, // vpermb
- // The backend knows how to generate a single VEX.256 version of
- // instruction VPBLENDW if the target supports AVX2.
- if (ST->hasAVX2() && LT.second == MVT::v16i16)
- return LT.first;
+ { TTI::SK_PermuteSingleSrc, MVT::v64i8, 1 }, // vpermb
+ { TTI::SK_PermuteSingleSrc, MVT::v32i8, 1 }, // vpermb
- static const CostTblEntry AVXAltShuffleTbl[] = {
- {ISD::VECTOR_SHUFFLE, MVT::v4i64, 1}, // vblendpd
- {ISD::VECTOR_SHUFFLE, MVT::v4f64, 1}, // vblendpd
+ { TTI::SK_PermuteTwoSrc, MVT::v64i8, 1 }, // vpermt2b
+ { TTI::SK_PermuteTwoSrc, MVT::v32i8, 1 }, // vpermt2b
+ { TTI::SK_PermuteTwoSrc, MVT::v16i8, 1 } // vpermt2b
+ };
+
+ if (ST->hasVBMI())
+ if (const auto *Entry =
+ CostTableLookup(AVX512VBMIShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- {ISD::VECTOR_SHUFFLE, MVT::v8i32, 1}, // vblendps
- {ISD::VECTOR_SHUFFLE, MVT::v8f32, 1}, // vblendps
+ static const CostTblEntry AVX512BWShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v32i16, 1 }, // vpbroadcastw
+ { TTI::SK_Broadcast, MVT::v64i8, 1 }, // vpbroadcastb
+
+ { TTI::SK_Reverse, MVT::v32i16, 1 }, // vpermw
+ { TTI::SK_Reverse, MVT::v16i16, 1 }, // vpermw
+ { TTI::SK_Reverse, MVT::v64i8, 2 }, // pshufb + vshufi64x2
+
+ { TTI::SK_PermuteSingleSrc, MVT::v32i16, 1 }, // vpermw
+ { TTI::SK_PermuteSingleSrc, MVT::v16i16, 1 }, // vpermw
+ { TTI::SK_PermuteSingleSrc, MVT::v8i16, 1 }, // vpermw
+ { TTI::SK_PermuteSingleSrc, MVT::v64i8, 8 }, // extend to v32i16
+ { TTI::SK_PermuteSingleSrc, MVT::v32i8, 3 }, // vpermw + zext/trunc
+
+ { TTI::SK_PermuteTwoSrc, MVT::v32i16, 1 }, // vpermt2w
+ { TTI::SK_PermuteTwoSrc, MVT::v16i16, 1 }, // vpermt2w
+ { TTI::SK_PermuteTwoSrc, MVT::v8i16, 1 }, // vpermt2w
+ { TTI::SK_PermuteTwoSrc, MVT::v32i8, 3 }, // zext + vpermt2w + trunc
+ { TTI::SK_PermuteTwoSrc, MVT::v64i8, 19 }, // 6 * v32i8 + 1
+ { TTI::SK_PermuteTwoSrc, MVT::v16i8, 3 } // zext + vpermt2w + trunc
+ };
- // This shuffle is custom lowered into a sequence of:
- // 2x vextractf128 , 2x vpblendw , 1x vinsertf128
- {ISD::VECTOR_SHUFFLE, MVT::v16i16, 5},
+ if (ST->hasBWI())
+ if (const auto *Entry =
+ CostTableLookup(AVX512BWShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- // This shuffle is custom lowered into a long sequence of:
- // 2x vextractf128 , 4x vpshufb , 2x vpor , 1x vinsertf128
- {ISD::VECTOR_SHUFFLE, MVT::v32i8, 9}
- };
+ static const CostTblEntry AVX512ShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v8f64, 1 }, // vbroadcastpd
+ { TTI::SK_Broadcast, MVT::v16f32, 1 }, // vbroadcastps
+ { TTI::SK_Broadcast, MVT::v8i64, 1 }, // vpbroadcastq
+ { TTI::SK_Broadcast, MVT::v16i32, 1 }, // vpbroadcastd
+
+ { TTI::SK_Reverse, MVT::v8f64, 1 }, // vpermpd
+ { TTI::SK_Reverse, MVT::v16f32, 1 }, // vpermps
+ { TTI::SK_Reverse, MVT::v8i64, 1 }, // vpermq
+ { TTI::SK_Reverse, MVT::v16i32, 1 }, // vpermd
+
+ { TTI::SK_PermuteSingleSrc, MVT::v8f64, 1 }, // vpermpd
+ { TTI::SK_PermuteSingleSrc, MVT::v4f64, 1 }, // vpermpd
+ { TTI::SK_PermuteSingleSrc, MVT::v2f64, 1 }, // vpermpd
+ { TTI::SK_PermuteSingleSrc, MVT::v16f32, 1 }, // vpermps
+ { TTI::SK_PermuteSingleSrc, MVT::v8f32, 1 }, // vpermps
+ { TTI::SK_PermuteSingleSrc, MVT::v4f32, 1 }, // vpermps
+ { TTI::SK_PermuteSingleSrc, MVT::v8i64, 1 }, // vpermq
+ { TTI::SK_PermuteSingleSrc, MVT::v4i64, 1 }, // vpermq
+ { TTI::SK_PermuteSingleSrc, MVT::v2i64, 1 }, // vpermq
+ { TTI::SK_PermuteSingleSrc, MVT::v16i32, 1 }, // vpermd
+ { TTI::SK_PermuteSingleSrc, MVT::v8i32, 1 }, // vpermd
+ { TTI::SK_PermuteSingleSrc, MVT::v4i32, 1 }, // vpermd
+ { TTI::SK_PermuteSingleSrc, MVT::v16i8, 1 }, // pshufb
+
+ { TTI::SK_PermuteTwoSrc, MVT::v8f64, 1 }, // vpermt2pd
+ { TTI::SK_PermuteTwoSrc, MVT::v16f32, 1 }, // vpermt2ps
+ { TTI::SK_PermuteTwoSrc, MVT::v8i64, 1 }, // vpermt2q
+ { TTI::SK_PermuteTwoSrc, MVT::v16i32, 1 }, // vpermt2d
+ { TTI::SK_PermuteTwoSrc, MVT::v4f64, 1 }, // vpermt2pd
+ { TTI::SK_PermuteTwoSrc, MVT::v8f32, 1 }, // vpermt2ps
+ { TTI::SK_PermuteTwoSrc, MVT::v4i64, 1 }, // vpermt2q
+ { TTI::SK_PermuteTwoSrc, MVT::v8i32, 1 }, // vpermt2d
+ { TTI::SK_PermuteTwoSrc, MVT::v2f64, 1 }, // vpermt2pd
+ { TTI::SK_PermuteTwoSrc, MVT::v4f32, 1 }, // vpermt2ps
+ { TTI::SK_PermuteTwoSrc, MVT::v2i64, 1 }, // vpermt2q
+ { TTI::SK_PermuteTwoSrc, MVT::v4i32, 1 } // vpermt2d
+ };
- if (ST->hasAVX())
- if (const auto *Entry = CostTableLookup(AVXAltShuffleTbl,
- ISD::VECTOR_SHUFFLE, LT.second))
- return LT.first * Entry->Cost;
+ if (ST->hasAVX512())
+ if (const auto *Entry = CostTableLookup(AVX512ShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- static const CostTblEntry SSE41AltShuffleTbl[] = {
- // These are lowered into movsd.
- {ISD::VECTOR_SHUFFLE, MVT::v2i64, 1},
- {ISD::VECTOR_SHUFFLE, MVT::v2f64, 1},
+ static const CostTblEntry AVX2ShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v4f64, 1 }, // vbroadcastpd
+ { TTI::SK_Broadcast, MVT::v8f32, 1 }, // vbroadcastps
+ { TTI::SK_Broadcast, MVT::v4i64, 1 }, // vpbroadcastq
+ { TTI::SK_Broadcast, MVT::v8i32, 1 }, // vpbroadcastd
+ { TTI::SK_Broadcast, MVT::v16i16, 1 }, // vpbroadcastw
+ { TTI::SK_Broadcast, MVT::v32i8, 1 }, // vpbroadcastb
+
+ { TTI::SK_Reverse, MVT::v4f64, 1 }, // vpermpd
+ { TTI::SK_Reverse, MVT::v8f32, 1 }, // vpermps
+ { TTI::SK_Reverse, MVT::v4i64, 1 }, // vpermq
+ { TTI::SK_Reverse, MVT::v8i32, 1 }, // vpermd
+ { TTI::SK_Reverse, MVT::v16i16, 2 }, // vperm2i128 + pshufb
+ { TTI::SK_Reverse, MVT::v32i8, 2 }, // vperm2i128 + pshufb
+
+ { TTI::SK_Alternate, MVT::v16i16, 1 }, // vpblendw
+ { TTI::SK_Alternate, MVT::v32i8, 1 } // vpblendvb
+ };
- // packed float vectors with four elements are lowered into BLENDI dag
- // nodes. A v4i32/v4f32 BLENDI generates a single 'blendps'/'blendpd'.
- {ISD::VECTOR_SHUFFLE, MVT::v4i32, 1},
- {ISD::VECTOR_SHUFFLE, MVT::v4f32, 1},
+ if (ST->hasAVX2())
+ if (const auto *Entry = CostTableLookup(AVX2ShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- // This shuffle generates a single pshufw.
- {ISD::VECTOR_SHUFFLE, MVT::v8i16, 1},
+ static const CostTblEntry AVX1ShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v4f64, 2 }, // vperm2f128 + vpermilpd
+ { TTI::SK_Broadcast, MVT::v8f32, 2 }, // vperm2f128 + vpermilps
+ { TTI::SK_Broadcast, MVT::v4i64, 2 }, // vperm2f128 + vpermilpd
+ { TTI::SK_Broadcast, MVT::v8i32, 2 }, // vperm2f128 + vpermilps
+ { TTI::SK_Broadcast, MVT::v16i16, 3 }, // vpshuflw + vpshufd + vinsertf128
+ { TTI::SK_Broadcast, MVT::v32i8, 2 }, // vpshufb + vinsertf128
+
+ { TTI::SK_Reverse, MVT::v4f64, 2 }, // vperm2f128 + vpermilpd
+ { TTI::SK_Reverse, MVT::v8f32, 2 }, // vperm2f128 + vpermilps
+ { TTI::SK_Reverse, MVT::v4i64, 2 }, // vperm2f128 + vpermilpd
+ { TTI::SK_Reverse, MVT::v8i32, 2 }, // vperm2f128 + vpermilps
+ { TTI::SK_Reverse, MVT::v16i16, 4 }, // vextractf128 + 2*pshufb
+ // + vinsertf128
+ { TTI::SK_Reverse, MVT::v32i8, 4 }, // vextractf128 + 2*pshufb
+ // + vinsertf128
+
+ { TTI::SK_Alternate, MVT::v4i64, 1 }, // vblendpd
+ { TTI::SK_Alternate, MVT::v4f64, 1 }, // vblendpd
+ { TTI::SK_Alternate, MVT::v8i32, 1 }, // vblendps
+ { TTI::SK_Alternate, MVT::v8f32, 1 }, // vblendps
+ { TTI::SK_Alternate, MVT::v16i16, 3 }, // vpand + vpandn + vpor
+ { TTI::SK_Alternate, MVT::v32i8, 3 } // vpand + vpandn + vpor
+ };
- // There is no instruction that matches a v16i8 alternate shuffle.
- // The backend will expand it into the sequence 'pshufb + pshufb + or'.
- {ISD::VECTOR_SHUFFLE, MVT::v16i8, 3}
- };
+ if (ST->hasAVX())
+ if (const auto *Entry = CostTableLookup(AVX1ShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- if (ST->hasSSE41())
- if (const auto *Entry = CostTableLookup(SSE41AltShuffleTbl, ISD::VECTOR_SHUFFLE,
- LT.second))
- return LT.first * Entry->Cost;
+ static const CostTblEntry SSE41ShuffleTbl[] = {
+ { TTI::SK_Alternate, MVT::v2i64, 1 }, // pblendw
+ { TTI::SK_Alternate, MVT::v2f64, 1 }, // movsd
+ { TTI::SK_Alternate, MVT::v4i32, 1 }, // pblendw
+ { TTI::SK_Alternate, MVT::v4f32, 1 }, // blendps
+ { TTI::SK_Alternate, MVT::v8i16, 1 }, // pblendw
+ { TTI::SK_Alternate, MVT::v16i8, 1 } // pblendvb
+ };
- static const CostTblEntry SSSE3AltShuffleTbl[] = {
- {ISD::VECTOR_SHUFFLE, MVT::v2i64, 1}, // movsd
- {ISD::VECTOR_SHUFFLE, MVT::v2f64, 1}, // movsd
+ if (ST->hasSSE41())
+ if (const auto *Entry = CostTableLookup(SSE41ShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- // SSE3 doesn't have 'blendps'. The following shuffles are expanded into
- // the sequence 'shufps + pshufd'
- {ISD::VECTOR_SHUFFLE, MVT::v4i32, 2},
- {ISD::VECTOR_SHUFFLE, MVT::v4f32, 2},
+ static const CostTblEntry SSSE3ShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v8i16, 1 }, // pshufb
+ { TTI::SK_Broadcast, MVT::v16i8, 1 }, // pshufb
- {ISD::VECTOR_SHUFFLE, MVT::v8i16, 3}, // pshufb + pshufb + or
- {ISD::VECTOR_SHUFFLE, MVT::v16i8, 3} // pshufb + pshufb + or
- };
+ { TTI::SK_Reverse, MVT::v8i16, 1 }, // pshufb
+ { TTI::SK_Reverse, MVT::v16i8, 1 }, // pshufb
- if (ST->hasSSSE3())
- if (const auto *Entry = CostTableLookup(SSSE3AltShuffleTbl,
- ISD::VECTOR_SHUFFLE, LT.second))
- return LT.first * Entry->Cost;
+ { TTI::SK_Alternate, MVT::v8i16, 3 }, // pshufb + pshufb + por
+ { TTI::SK_Alternate, MVT::v16i8, 3 } // pshufb + pshufb + por
+ };
- static const CostTblEntry SSEAltShuffleTbl[] = {
- {ISD::VECTOR_SHUFFLE, MVT::v2i64, 1}, // movsd
- {ISD::VECTOR_SHUFFLE, MVT::v2f64, 1}, // movsd
+ if (ST->hasSSSE3())
+ if (const auto *Entry = CostTableLookup(SSSE3ShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- {ISD::VECTOR_SHUFFLE, MVT::v4i32, 2}, // shufps + pshufd
- {ISD::VECTOR_SHUFFLE, MVT::v4f32, 2}, // shufps + pshufd
+ static const CostTblEntry SSE2ShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v2f64, 1 }, // shufpd
+ { TTI::SK_Broadcast, MVT::v2i64, 1 }, // pshufd
+ { TTI::SK_Broadcast, MVT::v4i32, 1 }, // pshufd
+ { TTI::SK_Broadcast, MVT::v8i16, 2 }, // pshuflw + pshufd
+ { TTI::SK_Broadcast, MVT::v16i8, 3 }, // unpck + pshuflw + pshufd
+
+ { TTI::SK_Reverse, MVT::v2f64, 1 }, // shufpd
+ { TTI::SK_Reverse, MVT::v2i64, 1 }, // pshufd
+ { TTI::SK_Reverse, MVT::v4i32, 1 }, // pshufd
+ { TTI::SK_Reverse, MVT::v8i16, 3 }, // pshuflw + pshufhw + pshufd
+ { TTI::SK_Reverse, MVT::v16i8, 9 }, // 2*pshuflw + 2*pshufhw
+ // + 2*pshufd + 2*unpck + packus
+
+ { TTI::SK_Alternate, MVT::v2i64, 1 }, // movsd
+ { TTI::SK_Alternate, MVT::v2f64, 1 }, // movsd
+ { TTI::SK_Alternate, MVT::v4i32, 2 }, // 2*shufps
+ { TTI::SK_Alternate, MVT::v8i16, 3 }, // pand + pandn + por
+ { TTI::SK_Alternate, MVT::v16i8, 3 } // pand + pandn + por
+ };
- // This is expanded into a long sequence of four extract + four insert.
- {ISD::VECTOR_SHUFFLE, MVT::v8i16, 8}, // 4 x pextrw + 4 pinsrw.
+ if (ST->hasSSE2())
+ if (const auto *Entry = CostTableLookup(SSE2ShuffleTbl, Kind, LT.second))
+ return LT.first * Entry->Cost;
- // 8 x (pinsrw + pextrw + and + movb + movzb + or)
- {ISD::VECTOR_SHUFFLE, MVT::v16i8, 48}
- };
+ static const CostTblEntry SSE1ShuffleTbl[] = {
+ { TTI::SK_Broadcast, MVT::v4f32, 1 }, // shufps
+ { TTI::SK_Reverse, MVT::v4f32, 1 }, // shufps
+ { TTI::SK_Alternate, MVT::v4f32, 2 } // 2*shufps
+ };
- // Fall-back (SSE3 and SSE2).
- if (const auto *Entry = CostTableLookup(SSEAltShuffleTbl,
- ISD::VECTOR_SHUFFLE, LT.second))
+ if (ST->hasSSE1())
+ if (const auto *Entry = CostTableLookup(SSE1ShuffleTbl, Kind, LT.second))
return LT.first * Entry->Cost;
- return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
- }
return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
}
@@ -532,6 +914,13 @@ int X86TTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) {
// potential massive combinations (elem_num x src_type x dst_type).
static const TypeConversionCostTblEntry AVX512DQConversionTbl[] = {
+ { ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i64, 1 },
+ { ISD::SINT_TO_FP, MVT::v2f64, MVT::v2i64, 1 },
+ { ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i64, 1 },
+ { ISD::SINT_TO_FP, MVT::v4f64, MVT::v4i64, 1 },
+ { ISD::SINT_TO_FP, MVT::v8f32, MVT::v8i64, 1 },
+ { ISD::SINT_TO_FP, MVT::v8f64, MVT::v8i64, 1 },
+
{ ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i64, 1 },
{ ISD::UINT_TO_FP, MVT::v2f64, MVT::v2i64, 1 },
{ ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i64, 1 },
@@ -539,12 +928,19 @@ int X86TTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) {
{ ISD::UINT_TO_FP, MVT::v8f32, MVT::v8i64, 1 },
{ ISD::UINT_TO_FP, MVT::v8f64, MVT::v8i64, 1 },
- { ISD::FP_TO_UINT, MVT::v2i64, MVT::v2f32, 1 },
- { ISD::FP_TO_UINT, MVT::v4i64, MVT::v4f32, 1 },
- { ISD::FP_TO_UINT, MVT::v8i64, MVT::v8f32, 1 },
- { ISD::FP_TO_UINT, MVT::v2i64, MVT::v2f64, 1 },
- { ISD::FP_TO_UINT, MVT::v4i64, MVT::v4f64, 1 },
- { ISD::FP_TO_UINT, MVT::v8i64, MVT::v8f64, 1 },
+ { ISD::FP_TO_SINT, MVT::v2i64, MVT::v2f32, 1 },
+ { ISD::FP_TO_SINT, MVT::v4i64, MVT::v4f32, 1 },
+ { ISD::FP_TO_SINT, MVT::v8i64, MVT::v8f32, 1 },
+ { ISD::FP_TO_SINT, MVT::v2i64, MVT::v2f64, 1 },
+ { ISD::FP_TO_SINT, MVT::v4i64, MVT::v4f64, 1 },
+ { ISD::FP_TO_SINT, MVT::v8i64, MVT::v8f64, 1 },
+
+ { ISD::FP_TO_UINT, MVT::v2i64, MVT::v2f32, 1 },
+ { ISD::FP_TO_UINT, MVT::v4i64, MVT::v4f32, 1 },
+ { ISD::FP_TO_UINT, MVT::v8i64, MVT::v8f32, 1 },
+ { ISD::FP_TO_UINT, MVT::v2i64, MVT::v2f64, 1 },
+ { ISD::FP_TO_UINT, MVT::v4i64, MVT::v4f64, 1 },
+ { ISD::FP_TO_UINT, MVT::v8i64, MVT::v8f64, 1 },
};
// TODO: For AVX512DQ + AVX512VL, we also have cheap casts for 128-bit and
@@ -779,6 +1175,8 @@ int X86TTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) {
{ ISD::UINT_TO_FP, MVT::v2f64, MVT::v2i64, 2*10 },
{ ISD::UINT_TO_FP, MVT::v4f32, MVT::v2i64, 15 },
+ { ISD::FP_TO_SINT, MVT::v2i32, MVT::v2f64, 3 },
+
{ ISD::ZERO_EXTEND, MVT::v4i16, MVT::v4i8, 1 },
{ ISD::SIGN_EXTEND, MVT::v4i16, MVT::v4i8, 6 },
{ ISD::ZERO_EXTEND, MVT::v4i32, MVT::v4i8, 2 },
@@ -945,6 +1343,12 @@ int X86TTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) {
int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
ArrayRef<Type *> Tys, FastMathFlags FMF) {
+ // Costs should match the codegen from:
+ // BITREVERSE: llvm\test\CodeGen\X86\vector-bitreverse.ll
+ // BSWAP: llvm\test\CodeGen\X86\bswap-vector.ll
+ // CTLZ: llvm\test\CodeGen\X86\vector-lzcnt-*.ll
+ // CTPOP: llvm\test\CodeGen\X86\vector-popcnt-*.ll
+ // CTTZ: llvm\test\CodeGen\X86\vector-tzcnt-*.ll
static const CostTblEntry XOPCostTbl[] = {
{ ISD::BITREVERSE, MVT::v4i64, 4 },
{ ISD::BITREVERSE, MVT::v8i32, 4 },
@@ -966,7 +1370,25 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
{ ISD::BITREVERSE, MVT::v32i8, 5 },
{ ISD::BSWAP, MVT::v4i64, 1 },
{ ISD::BSWAP, MVT::v8i32, 1 },
- { ISD::BSWAP, MVT::v16i16, 1 }
+ { ISD::BSWAP, MVT::v16i16, 1 },
+ { ISD::CTLZ, MVT::v4i64, 23 },
+ { ISD::CTLZ, MVT::v8i32, 18 },
+ { ISD::CTLZ, MVT::v16i16, 14 },
+ { ISD::CTLZ, MVT::v32i8, 9 },
+ { ISD::CTPOP, MVT::v4i64, 7 },
+ { ISD::CTPOP, MVT::v8i32, 11 },
+ { ISD::CTPOP, MVT::v16i16, 9 },
+ { ISD::CTPOP, MVT::v32i8, 6 },
+ { ISD::CTTZ, MVT::v4i64, 10 },
+ { ISD::CTTZ, MVT::v8i32, 14 },
+ { ISD::CTTZ, MVT::v16i16, 12 },
+ { ISD::CTTZ, MVT::v32i8, 9 },
+ { ISD::FSQRT, MVT::f32, 7 }, // Haswell from http://www.agner.org/
+ { ISD::FSQRT, MVT::v4f32, 7 }, // Haswell from http://www.agner.org/
+ { ISD::FSQRT, MVT::v8f32, 14 }, // Haswell from http://www.agner.org/
+ { ISD::FSQRT, MVT::f64, 14 }, // Haswell from http://www.agner.org/
+ { ISD::FSQRT, MVT::v2f64, 14 }, // Haswell from http://www.agner.org/
+ { ISD::FSQRT, MVT::v4f64, 28 }, // Haswell from http://www.agner.org/
};
static const CostTblEntry AVX1CostTbl[] = {
{ ISD::BITREVERSE, MVT::v4i64, 10 },
@@ -975,7 +1397,29 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
{ ISD::BITREVERSE, MVT::v32i8, 10 },
{ ISD::BSWAP, MVT::v4i64, 4 },
{ ISD::BSWAP, MVT::v8i32, 4 },
- { ISD::BSWAP, MVT::v16i16, 4 }
+ { ISD::BSWAP, MVT::v16i16, 4 },
+ { ISD::CTLZ, MVT::v4i64, 46 },
+ { ISD::CTLZ, MVT::v8i32, 36 },
+ { ISD::CTLZ, MVT::v16i16, 28 },
+ { ISD::CTLZ, MVT::v32i8, 18 },
+ { ISD::CTPOP, MVT::v4i64, 14 },
+ { ISD::CTPOP, MVT::v8i32, 22 },
+ { ISD::CTPOP, MVT::v16i16, 18 },
+ { ISD::CTPOP, MVT::v32i8, 12 },
+ { ISD::CTTZ, MVT::v4i64, 20 },
+ { ISD::CTTZ, MVT::v8i32, 28 },
+ { ISD::CTTZ, MVT::v16i16, 24 },
+ { ISD::CTTZ, MVT::v32i8, 18 },
+ { ISD::FSQRT, MVT::f32, 14 }, // SNB from http://www.agner.org/
+ { ISD::FSQRT, MVT::v4f32, 14 }, // SNB from http://www.agner.org/
+ { ISD::FSQRT, MVT::v8f32, 28 }, // SNB from http://www.agner.org/
+ { ISD::FSQRT, MVT::f64, 21 }, // SNB from http://www.agner.org/
+ { ISD::FSQRT, MVT::v2f64, 21 }, // SNB from http://www.agner.org/
+ { ISD::FSQRT, MVT::v4f64, 43 }, // SNB from http://www.agner.org/
+ };
+ static const CostTblEntry SSE42CostTbl[] = {
+ { ISD::FSQRT, MVT::f32, 18 }, // Nehalem from http://www.agner.org/
+ { ISD::FSQRT, MVT::v4f32, 18 }, // Nehalem from http://www.agner.org/
};
static const CostTblEntry SSSE3CostTbl[] = {
{ ISD::BITREVERSE, MVT::v2i64, 5 },
@@ -984,12 +1428,42 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
{ ISD::BITREVERSE, MVT::v16i8, 5 },
{ ISD::BSWAP, MVT::v2i64, 1 },
{ ISD::BSWAP, MVT::v4i32, 1 },
- { ISD::BSWAP, MVT::v8i16, 1 }
+ { ISD::BSWAP, MVT::v8i16, 1 },
+ { ISD::CTLZ, MVT::v2i64, 23 },
+ { ISD::CTLZ, MVT::v4i32, 18 },
+ { ISD::CTLZ, MVT::v8i16, 14 },
+ { ISD::CTLZ, MVT::v16i8, 9 },
+ { ISD::CTPOP, MVT::v2i64, 7 },
+ { ISD::CTPOP, MVT::v4i32, 11 },
+ { ISD::CTPOP, MVT::v8i16, 9 },
+ { ISD::CTPOP, MVT::v16i8, 6 },
+ { ISD::CTTZ, MVT::v2i64, 10 },
+ { ISD::CTTZ, MVT::v4i32, 14 },
+ { ISD::CTTZ, MVT::v8i16, 12 },
+ { ISD::CTTZ, MVT::v16i8, 9 }
};
static const CostTblEntry SSE2CostTbl[] = {
{ ISD::BSWAP, MVT::v2i64, 7 },
{ ISD::BSWAP, MVT::v4i32, 7 },
- { ISD::BSWAP, MVT::v8i16, 7 }
+ { ISD::BSWAP, MVT::v8i16, 7 },
+ { ISD::CTLZ, MVT::v2i64, 25 },
+ { ISD::CTLZ, MVT::v4i32, 26 },
+ { ISD::CTLZ, MVT::v8i16, 20 },
+ { ISD::CTLZ, MVT::v16i8, 17 },
+ { ISD::CTPOP, MVT::v2i64, 12 },
+ { ISD::CTPOP, MVT::v4i32, 15 },
+ { ISD::CTPOP, MVT::v8i16, 13 },
+ { ISD::CTPOP, MVT::v16i8, 10 },
+ { ISD::CTTZ, MVT::v2i64, 14 },
+ { ISD::CTTZ, MVT::v4i32, 18 },
+ { ISD::CTTZ, MVT::v8i16, 16 },
+ { ISD::CTTZ, MVT::v16i8, 13 },
+ { ISD::FSQRT, MVT::f64, 32 }, // Nehalem from http://www.agner.org/
+ { ISD::FSQRT, MVT::v2f64, 32 }, // Nehalem from http://www.agner.org/
+ };
+ static const CostTblEntry SSE1CostTbl[] = {
+ { ISD::FSQRT, MVT::f32, 28 }, // Pentium III from http://www.agner.org/
+ { ISD::FSQRT, MVT::v4f32, 56 }, // Pentium III from http://www.agner.org/
};
unsigned ISD = ISD::DELETED_NODE;
@@ -1002,6 +1476,18 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
case Intrinsic::bswap:
ISD = ISD::BSWAP;
break;
+ case Intrinsic::ctlz:
+ ISD = ISD::CTLZ;
+ break;
+ case Intrinsic::ctpop:
+ ISD = ISD::CTPOP;
+ break;
+ case Intrinsic::cttz:
+ ISD = ISD::CTTZ;
+ break;
+ case Intrinsic::sqrt:
+ ISD = ISD::FSQRT;
+ break;
}
// Legalize the type.
@@ -1021,6 +1507,10 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
if (const auto *Entry = CostTableLookup(AVX1CostTbl, ISD, MTy))
return LT.first * Entry->Cost;
+ if (ST->hasSSE42())
+ if (const auto *Entry = CostTableLookup(SSE42CostTbl, ISD, MTy))
+ return LT.first * Entry->Cost;
+
if (ST->hasSSSE3())
if (const auto *Entry = CostTableLookup(SSSE3CostTbl, ISD, MTy))
return LT.first * Entry->Cost;
@@ -1029,6 +1519,10 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
if (const auto *Entry = CostTableLookup(SSE2CostTbl, ISD, MTy))
return LT.first * Entry->Cost;
+ if (ST->hasSSE1())
+ if (const auto *Entry = CostTableLookup(SSE1CostTbl, ISD, MTy))
+ return LT.first * Entry->Cost;
+
return BaseT::getIntrinsicInstrCost(IID, RetTy, Tys, FMF);
}
@@ -1177,17 +1671,29 @@ int X86TTIImpl::getMaskedMemoryOpCost(unsigned Opcode, Type *SrcTy,
return Cost+LT.first;
}
-int X86TTIImpl::getAddressComputationCost(Type *Ty, bool IsComplex) {
+int X86TTIImpl::getAddressComputationCost(Type *Ty, ScalarEvolution *SE,
+ const SCEV *Ptr) {
// Address computations in vectorized code with non-consecutive addresses will
// likely result in more instructions compared to scalar code where the
// computation can more often be merged into the index mode. The resulting
// extra micro-ops can significantly decrease throughput.
unsigned NumVectorInstToHideOverhead = 10;
- if (Ty->isVectorTy() && IsComplex)
- return NumVectorInstToHideOverhead;
+ // Cost modeling of Strided Access Computation is hidden by the indexing
+ // modes of X86 regardless of the stride value. We dont believe that there
+ // is a difference between constant strided access in gerenal and constant
+ // strided value which is less than or equal to 64.
+ // Even in the case of (loop invariant) stride whose value is not known at
+ // compile time, the address computation will not incur more than one extra
+ // ADD instruction.
+ if (Ty->isVectorTy() && SE) {
+ if (!BaseT::isStridedAccess(Ptr))
+ return NumVectorInstToHideOverhead;
+ if (!BaseT::getConstantStrideStep(SE, Ptr))
+ return 1;
+ }
- return BaseT::getAddressComputationCost(Ty, IsComplex);
+ return BaseT::getAddressComputationCost(Ty, SE, Ptr);
}
int X86TTIImpl::getReductionCost(unsigned Opcode, Type *ValTy,
@@ -1352,7 +1858,7 @@ int X86TTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
// immediates here as the normal path expects bit 31 to be sign extended.
if (Idx == 1 && Imm.getBitWidth() == 64 && isUInt<32>(Imm.getZExtValue()))
return TTI::TCC_Free;
- // Fallthrough
+ LLVM_FALLTHROUGH;
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
@@ -1556,13 +2062,14 @@ int X86TTIImpl::getGatherScatterOpCost(unsigned Opcode, Type *SrcVTy,
// Vector-4 of gather/scatter instruction does not exist on KNL.
// We can extend it to 8 elements, but zeroing upper bits of
// the mask vector will add more instructions. Right now we give the scalar
- // cost of vector-4 for KNL. TODO: Check, maybe the gather/scatter instruction is
- // better in the VariableMask case.
+ // cost of vector-4 for KNL. TODO: Check, maybe the gather/scatter instruction
+ // is better in the VariableMask case.
if (VF == 2 || (VF == 4 && !ST->hasVLX()))
Scalarize = true;
if (Scalarize)
- return getGSScalarCost(Opcode, SrcVTy, VariableMask, Alignment, AddressSpace);
+ return getGSScalarCost(Opcode, SrcVTy, VariableMask, Alignment,
+ AddressSpace);
return getGSVectorCost(Opcode, SrcVTy, Ptr, Alignment, AddressSpace);
}
@@ -1572,8 +2079,8 @@ bool X86TTIImpl::isLegalMaskedLoad(Type *DataTy) {
int DataWidth = isa<PointerType>(ScalarTy) ?
DL.getPointerSizeInBits() : ScalarTy->getPrimitiveSizeInBits();
- return (DataWidth >= 32 && ST->hasAVX()) ||
- (DataWidth >= 8 && ST->hasBWI());
+ return ((DataWidth == 32 || DataWidth == 64) && ST->hasAVX()) ||
+ ((DataWidth == 8 || DataWidth == 16) && ST->hasBWI());
}
bool X86TTIImpl::isLegalMaskedStore(Type *DataType) {
@@ -1598,7 +2105,7 @@ bool X86TTIImpl::isLegalMaskedGather(Type *DataTy) {
DL.getPointerSizeInBits() : ScalarTy->getPrimitiveSizeInBits();
// AVX-512 allows gather and scatter
- return DataWidth >= 32 && ST->hasAVX512();
+ return (DataWidth == 32 || DataWidth == 64) && ST->hasAVX512();
}
bool X86TTIImpl::isLegalMaskedScatter(Type *DataType) {
@@ -1620,3 +2127,122 @@ bool X86TTIImpl::areInlineCompatible(const Function *Caller,
// correct.
return (CallerBits & CalleeBits) == CalleeBits;
}
+
+bool X86TTIImpl::enableInterleavedAccessVectorization() {
+ // TODO: We expect this to be beneficial regardless of arch,
+ // but there are currently some unexplained performance artifacts on Atom.
+ // As a temporary solution, disable on Atom.
+ return !(ST->isAtom() || ST->isSLM());
+}
+
+// Get estimation for interleaved load/store operations and strided load.
+// \p Indices contains indices for strided load.
+// \p Factor - the factor of interleaving.
+// AVX-512 provides 3-src shuffles that significantly reduces the cost.
+int X86TTIImpl::getInterleavedMemoryOpCostAVX512(unsigned Opcode, Type *VecTy,
+ unsigned Factor,
+ ArrayRef<unsigned> Indices,
+ unsigned Alignment,
+ unsigned AddressSpace) {
+
+ // VecTy for interleave memop is <VF*Factor x Elt>.
+ // So, for VF=4, Interleave Factor = 3, Element type = i32 we have
+ // VecTy = <12 x i32>.
+
+ // Calculate the number of memory operations (NumOfMemOps), required
+ // for load/store the VecTy.
+ MVT LegalVT = getTLI()->getTypeLegalizationCost(DL, VecTy).second;
+ unsigned VecTySize = DL.getTypeStoreSize(VecTy);
+ unsigned LegalVTSize = LegalVT.getStoreSize();
+ unsigned NumOfMemOps = (VecTySize + LegalVTSize - 1) / LegalVTSize;
+
+ // Get the cost of one memory operation.
+ Type *SingleMemOpTy = VectorType::get(VecTy->getVectorElementType(),
+ LegalVT.getVectorNumElements());
+ unsigned MemOpCost =
+ getMemoryOpCost(Opcode, SingleMemOpTy, Alignment, AddressSpace);
+
+ if (Opcode == Instruction::Load) {
+ // Kind of shuffle depends on number of loaded values.
+ // If we load the entire data in one register, we can use a 1-src shuffle.
+ // Otherwise, we'll merge 2 sources in each operation.
+ TTI::ShuffleKind ShuffleKind =
+ (NumOfMemOps > 1) ? TTI::SK_PermuteTwoSrc : TTI::SK_PermuteSingleSrc;
+
+ unsigned ShuffleCost =
+ getShuffleCost(ShuffleKind, SingleMemOpTy, 0, nullptr);
+
+ unsigned NumOfLoadsInInterleaveGrp =
+ Indices.size() ? Indices.size() : Factor;
+ Type *ResultTy = VectorType::get(VecTy->getVectorElementType(),
+ VecTy->getVectorNumElements() / Factor);
+ unsigned NumOfResults =
+ getTLI()->getTypeLegalizationCost(DL, ResultTy).first *
+ NumOfLoadsInInterleaveGrp;
+
+ // About a half of the loads may be folded in shuffles when we have only
+ // one result. If we have more than one result, we do not fold loads at all.
+ unsigned NumOfUnfoldedLoads =
+ NumOfResults > 1 ? NumOfMemOps : NumOfMemOps / 2;
+
+ // Get a number of shuffle operations per result.
+ unsigned NumOfShufflesPerResult =
+ std::max((unsigned)1, (unsigned)(NumOfMemOps - 1));
+
+ // The SK_MergeTwoSrc shuffle clobbers one of src operands.
+ // When we have more than one destination, we need additional instructions
+ // to keep sources.
+ unsigned NumOfMoves = 0;
+ if (NumOfResults > 1 && ShuffleKind == TTI::SK_PermuteTwoSrc)
+ NumOfMoves = NumOfResults * NumOfShufflesPerResult / 2;
+
+ int Cost = NumOfResults * NumOfShufflesPerResult * ShuffleCost +
+ NumOfUnfoldedLoads * MemOpCost + NumOfMoves;
+
+ return Cost;
+ }
+
+ // Store.
+ assert(Opcode == Instruction::Store &&
+ "Expected Store Instruction at this point");
+
+ // There is no strided stores meanwhile. And store can't be folded in
+ // shuffle.
+ unsigned NumOfSources = Factor; // The number of values to be merged.
+ unsigned ShuffleCost =
+ getShuffleCost(TTI::SK_PermuteTwoSrc, SingleMemOpTy, 0, nullptr);
+ unsigned NumOfShufflesPerStore = NumOfSources - 1;
+
+ // The SK_MergeTwoSrc shuffle clobbers one of src operands.
+ // We need additional instructions to keep sources.
+ unsigned NumOfMoves = NumOfMemOps * NumOfShufflesPerStore / 2;
+ int Cost = NumOfMemOps * (MemOpCost + NumOfShufflesPerStore * ShuffleCost) +
+ NumOfMoves;
+ return Cost;
+}
+
+int X86TTIImpl::getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy,
+ unsigned Factor,
+ ArrayRef<unsigned> Indices,
+ unsigned Alignment,
+ unsigned AddressSpace) {
+ auto isSupportedOnAVX512 = [](Type *VecTy, bool &RequiresBW) {
+ RequiresBW = false;
+ Type *EltTy = VecTy->getVectorElementType();
+ if (EltTy->isFloatTy() || EltTy->isDoubleTy() || EltTy->isIntegerTy(64) ||
+ EltTy->isIntegerTy(32) || EltTy->isPointerTy())
+ return true;
+ if (EltTy->isIntegerTy(16) || EltTy->isIntegerTy(8)) {
+ RequiresBW = true;
+ return true;
+ }
+ return false;
+ };
+ bool RequiresBW;
+ bool HasAVX512Solution = isSupportedOnAVX512(VecTy, RequiresBW);
+ if (ST->hasAVX512() && HasAVX512Solution && (!RequiresBW || ST->hasBWI()))
+ return getInterleavedMemoryOpCostAVX512(Opcode, VecTy, Factor, Indices,
+ Alignment, AddressSpace);
+ return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices,
+ Alignment, AddressSpace);
+}
diff --git a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h
index ab8046b..ecaaf95 100644
--- a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h
@@ -43,13 +43,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- X86TTIImpl(const X86TTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- X86TTIImpl(X86TTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
/// \name Scalar TTI Implementations
/// @{
TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth);
@@ -67,7 +60,8 @@ public:
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
- TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None);
+ TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None,
+ ArrayRef<const Value *> Args = ArrayRef<const Value *>());
int getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index, Type *SubTp);
int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src);
int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy);
@@ -78,7 +72,8 @@ public:
unsigned AddressSpace);
int getGatherScatterOpCost(unsigned Opcode, Type *DataTy, Value *Ptr,
bool VariableMask, unsigned Alignment);
- int getAddressComputationCost(Type *PtrTy, bool IsComplex);
+ int getAddressComputationCost(Type *PtrTy, ScalarEvolution *SE,
+ const SCEV *Ptr);
int getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
ArrayRef<Type *> Tys, FastMathFlags FMF);
@@ -87,6 +82,13 @@ public:
int getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwiseForm);
+ int getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy,
+ unsigned Factor, ArrayRef<unsigned> Indices,
+ unsigned Alignment, unsigned AddressSpace);
+ int getInterleavedMemoryOpCostAVX512(unsigned Opcode, Type *VecTy,
+ unsigned Factor, ArrayRef<unsigned> Indices,
+ unsigned Alignment, unsigned AddressSpace);
+
int getIntImmCost(int64_t);
int getIntImmCost(const APInt &Imm, Type *Ty);
@@ -100,6 +102,8 @@ public:
bool isLegalMaskedScatter(Type *DataType);
bool areInlineCompatible(const Function *Caller,
const Function *Callee) const;
+
+ bool enableInterleavedAccessVectorization();
private:
int getGSScalarCost(unsigned Opcode, Type *DataTy, bool VariableMask,
unsigned Alignment, unsigned AddressSpace);
diff --git a/contrib/llvm/lib/Target/X86/X86VZeroUpper.cpp b/contrib/llvm/lib/Target/X86/X86VZeroUpper.cpp
index 9320e1e..9766b84 100644
--- a/contrib/llvm/lib/Target/X86/X86VZeroUpper.cpp
+++ b/contrib/llvm/lib/Target/X86/X86VZeroUpper.cpp
@@ -40,9 +40,9 @@ namespace {
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {return "X86 vzeroupper inserter";}
+ StringRef getPassName() const override { return "X86 vzeroupper inserter"; }
private:
diff --git a/contrib/llvm/lib/Target/X86/X86WinAllocaExpander.cpp b/contrib/llvm/lib/Target/X86/X86WinAllocaExpander.cpp
index cc82074..fc08f15 100644
--- a/contrib/llvm/lib/Target/X86/X86WinAllocaExpander.cpp
+++ b/contrib/llvm/lib/Target/X86/X86WinAllocaExpander.cpp
@@ -63,7 +63,7 @@ private:
unsigned SlotSize;
int64_t StackProbeSize;
- const char *getPassName() const override { return "X86 WinAlloca Expander"; }
+ StringRef getPassName() const override { return "X86 WinAlloca Expander"; }
static char ID;
};
@@ -225,6 +225,7 @@ void X86WinAllocaExpander::lower(MachineInstr* MI, Lowering L) {
break;
// Fall through to make any remaining adjustment.
+ LLVM_FALLTHROUGH;
case Sub:
assert(Amount > 0);
if (Amount == SlotSize) {
diff --git a/contrib/llvm/lib/Target/X86/X86WinEHState.cpp b/contrib/llvm/lib/Target/X86/X86WinEHState.cpp
index 99387ed..bc14630 100644
--- a/contrib/llvm/lib/Target/X86/X86WinEHState.cpp
+++ b/contrib/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -57,7 +57,7 @@ public:
void getAnalysisUsage(AnalysisUsage &AU) const override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "Windows 32-bit x86 EH state insertion";
}
diff --git a/contrib/llvm/lib/Target/XCore/Disassembler/XCoreDisassembler.cpp b/contrib/llvm/lib/Target/XCore/Disassembler/XCoreDisassembler.cpp
index 2e8f762..059b75e 100644
--- a/contrib/llvm/lib/Target/XCore/Disassembler/XCoreDisassembler.cpp
+++ b/contrib/llvm/lib/Target/XCore/Disassembler/XCoreDisassembler.cpp
@@ -769,7 +769,7 @@ MCDisassembler::DecodeStatus XCoreDisassembler::getInstruction(
}
namespace llvm {
- extern Target TheXCoreTarget;
+ Target &getTheXCoreTarget();
}
static MCDisassembler *createXCoreDisassembler(const Target &T,
@@ -780,6 +780,6 @@ static MCDisassembler *createXCoreDisassembler(const Target &T,
extern "C" void LLVMInitializeXCoreDisassembler() {
// Register the disassembler.
- TargetRegistry::RegisterMCDisassembler(TheXCoreTarget,
+ TargetRegistry::RegisterMCDisassembler(getTheXCoreTarget(),
createXCoreDisassembler);
}
diff --git a/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp b/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp
index 63ca1e7..c5859b7 100644
--- a/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp
+++ b/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp
@@ -124,26 +124,28 @@ static MCTargetStreamer *createTargetAsmStreamer(MCStreamer &S,
// Force static initialization.
extern "C" void LLVMInitializeXCoreTargetMC() {
// Register the MC asm info.
- RegisterMCAsmInfoFn X(TheXCoreTarget, createXCoreMCAsmInfo);
+ RegisterMCAsmInfoFn X(getTheXCoreTarget(), createXCoreMCAsmInfo);
// Register the MC codegen info.
- TargetRegistry::registerMCAdjustCodeGenOpts(TheXCoreTarget,
+ TargetRegistry::registerMCAdjustCodeGenOpts(getTheXCoreTarget(),
adjustCodeGenOpts);
// Register the MC instruction info.
- TargetRegistry::RegisterMCInstrInfo(TheXCoreTarget, createXCoreMCInstrInfo);
+ TargetRegistry::RegisterMCInstrInfo(getTheXCoreTarget(),
+ createXCoreMCInstrInfo);
// Register the MC register info.
- TargetRegistry::RegisterMCRegInfo(TheXCoreTarget, createXCoreMCRegisterInfo);
+ TargetRegistry::RegisterMCRegInfo(getTheXCoreTarget(),
+ createXCoreMCRegisterInfo);
// Register the MC subtarget info.
- TargetRegistry::RegisterMCSubtargetInfo(TheXCoreTarget,
+ TargetRegistry::RegisterMCSubtargetInfo(getTheXCoreTarget(),
createXCoreMCSubtargetInfo);
// Register the MCInstPrinter
- TargetRegistry::RegisterMCInstPrinter(TheXCoreTarget,
+ TargetRegistry::RegisterMCInstPrinter(getTheXCoreTarget(),
createXCoreMCInstPrinter);
- TargetRegistry::RegisterAsmTargetStreamer(TheXCoreTarget,
+ TargetRegistry::RegisterAsmTargetStreamer(getTheXCoreTarget(),
createTargetAsmStreamer);
}
diff --git a/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.h b/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.h
index 28e0275..ac0f3fe 100644
--- a/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.h
@@ -18,8 +18,7 @@
namespace llvm {
class Target;
-
-extern Target TheXCoreTarget;
+Target &getTheXCoreTarget();
} // End llvm namespace
diff --git a/contrib/llvm/lib/Target/XCore/TargetInfo/XCoreTargetInfo.cpp b/contrib/llvm/lib/Target/XCore/TargetInfo/XCoreTargetInfo.cpp
index c78cde9..df5774c 100644
--- a/contrib/llvm/lib/Target/XCore/TargetInfo/XCoreTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/XCore/TargetInfo/XCoreTargetInfo.cpp
@@ -12,8 +12,11 @@
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
-Target llvm::TheXCoreTarget;
+Target &llvm::getTheXCoreTarget() {
+ static Target TheXCoreTarget;
+ return TheXCoreTarget;
+}
extern "C" void LLVMInitializeXCoreTargetInfo() {
- RegisterTarget<Triple::xcore> X(TheXCoreTarget, "xcore", "XCore");
+ RegisterTarget<Triple::xcore> X(getTheXCoreTarget(), "xcore", "XCore");
}
diff --git a/contrib/llvm/lib/Target/XCore/XCoreAsmPrinter.cpp b/contrib/llvm/lib/Target/XCore/XCoreAsmPrinter.cpp
index be66e6c..b35aa0b 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreAsmPrinter.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreAsmPrinter.cpp
@@ -58,9 +58,7 @@ namespace {
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)), MCInstLowering(*this) {}
- const char *getPassName() const override {
- return "XCore Assembly Printer";
- }
+ StringRef getPassName() const override { return "XCore Assembly Printer"; }
void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
const std::string &directive = ".jmptable");
@@ -115,8 +113,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
return;
const DataLayout &DL = getDataLayout();
- OutStreamer->SwitchSection(
- getObjFileLowering().SectionForGlobal(GV, *Mang, TM));
+ OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(GV, TM));
MCSymbol *GVSym = getSymbol(GV);
const Constant *C = GV->getInitializer();
@@ -140,7 +137,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
GV->hasCommonLinkage())
OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Weak);
- // FALL THROUGH
+ LLVM_FALLTHROUGH;
case GlobalValue::InternalLinkage:
case GlobalValue::PrivateLinkage:
break;
@@ -156,8 +153,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
unsigned Size = DL.getTypeAllocSize(C->getType());
if (MAI->hasDotTypeDotSizeDirective()) {
OutStreamer->EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject);
- OutStreamer->emitELFSize(cast<MCSymbolELF>(GVSym),
- MCConstantExpr::create(Size, OutContext));
+ OutStreamer->emitELFSize(GVSym, MCConstantExpr::create(Size, OutContext));
}
OutStreamer->EmitLabel(GVSym);
@@ -172,7 +168,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
}
void XCoreAsmPrinter::EmitFunctionBodyStart() {
- MCInstLowering.Initialize(Mang, &MF->getContext());
+ MCInstLowering.Initialize(&MF->getContext());
}
/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
@@ -300,5 +296,5 @@ void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Force static initialization.
extern "C" void LLVMInitializeXCoreAsmPrinter() {
- RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget);
+ RegisterAsmPrinter<XCoreAsmPrinter> X(getTheXCoreTarget());
}
diff --git a/contrib/llvm/lib/Target/XCore/XCoreFrameLowering.cpp b/contrib/llvm/lib/Target/XCore/XCoreFrameLowering.cpp
index 75a2eb0..e0e2e03 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreFrameLowering.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreFrameLowering.cpp
@@ -61,8 +61,8 @@ static bool CompareSSIOffset(const StackSlotInfo& a, const StackSlotInfo& b) {
static void EmitDefCfaRegister(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &dl, const TargetInstrInfo &TII,
- MachineModuleInfo *MMI, unsigned DRegNum) {
- unsigned CFIIndex = MMI->addFrameInst(
+ MachineFunction &MF, unsigned DRegNum) {
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaRegister(nullptr, DRegNum));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -71,18 +71,20 @@ static void EmitDefCfaRegister(MachineBasicBlock &MBB,
static void EmitDefCfaOffset(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &dl, const TargetInstrInfo &TII,
- MachineModuleInfo *MMI, int Offset) {
+ int Offset) {
+ MachineFunction &MF = *MBB.getParent();
unsigned CFIIndex =
- MMI->addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -Offset));
+ MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
static void EmitCfiOffset(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, const DebugLoc &dl,
- const TargetInstrInfo &TII, MachineModuleInfo *MMI,
- unsigned DRegNum, int Offset) {
- unsigned CFIIndex = MMI->addFrameInst(
+ const TargetInstrInfo &TII, unsigned DRegNum,
+ int Offset) {
+ MachineFunction &MF = *MBB.getParent();
+ unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, DRegNum, Offset));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
@@ -96,9 +98,8 @@ static void EmitCfiOffset(MachineBasicBlock &MBB,
/// \param [in,out] Adjusted the current SP offset from the top of the frame.
static void IfNeededExtSP(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, const DebugLoc &dl,
- const TargetInstrInfo &TII, MachineModuleInfo *MMI,
- int OffsetFromTop, int &Adjusted, int FrameSize,
- bool emitFrameMoves) {
+ const TargetInstrInfo &TII, int OffsetFromTop,
+ int &Adjusted, int FrameSize, bool emitFrameMoves) {
while (OffsetFromTop > Adjusted) {
assert(Adjusted < FrameSize && "OffsetFromTop is beyond FrameSize");
int remaining = FrameSize - Adjusted;
@@ -107,7 +108,7 @@ static void IfNeededExtSP(MachineBasicBlock &MBB,
BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(OpImm);
Adjusted += OpImm;
if (emitFrameMoves)
- EmitDefCfaOffset(MBB, MBBI, dl, TII, MMI, Adjusted*4);
+ EmitDefCfaOffset(MBB, MBBI, dl, TII, Adjusted*4);
}
}
@@ -136,16 +137,16 @@ static void IfNeededLDAWSP(MachineBasicBlock &MBB,
/// Registers are ordered according to their frame offset.
/// As offsets are negative, the largest offsets will be first.
static void GetSpillList(SmallVectorImpl<StackSlotInfo> &SpillList,
- MachineFrameInfo *MFI, XCoreFunctionInfo *XFI,
+ MachineFrameInfo &MFI, XCoreFunctionInfo *XFI,
bool fetchLR, bool fetchFP) {
if (fetchLR) {
- int Offset = MFI->getObjectOffset(XFI->getLRSpillSlot());
+ int Offset = MFI.getObjectOffset(XFI->getLRSpillSlot());
SpillList.push_back(StackSlotInfo(XFI->getLRSpillSlot(),
Offset,
XCore::LR));
}
if (fetchFP) {
- int Offset = MFI->getObjectOffset(XFI->getFPSpillSlot());
+ int Offset = MFI.getObjectOffset(XFI->getFPSpillSlot());
SpillList.push_back(StackSlotInfo(XFI->getFPSpillSlot(),
Offset,
FramePtr));
@@ -158,16 +159,16 @@ static void GetSpillList(SmallVectorImpl<StackSlotInfo> &SpillList,
/// Registers are ordered according to their frame offset.
/// As offsets are negative, the largest offsets will be first.
static void GetEHSpillList(SmallVectorImpl<StackSlotInfo> &SpillList,
- MachineFrameInfo *MFI, XCoreFunctionInfo *XFI,
+ MachineFrameInfo &MFI, XCoreFunctionInfo *XFI,
const Constant *PersonalityFn,
const TargetLowering *TL) {
assert(XFI->hasEHSpillSlot() && "There are no EH register spill slots");
const int *EHSlot = XFI->getEHSpillSlot();
SpillList.push_back(
- StackSlotInfo(EHSlot[0], MFI->getObjectOffset(EHSlot[0]),
+ StackSlotInfo(EHSlot[0], MFI.getObjectOffset(EHSlot[0]),
TL->getExceptionPointerRegister(PersonalityFn)));
SpillList.push_back(
- StackSlotInfo(EHSlot[0], MFI->getObjectOffset(EHSlot[1]),
+ StackSlotInfo(EHSlot[0], MFI.getObjectOffset(EHSlot[1]),
TL->getExceptionSelectorRegister(PersonalityFn)));
std::sort(SpillList.begin(), SpillList.end(), CompareSSIOffset);
}
@@ -176,7 +177,7 @@ static MachineMemOperand *getFrameIndexMMO(MachineBasicBlock &MBB,
int FrameIndex,
MachineMemOperand::Flags flags) {
MachineFunction *MF = MBB.getParent();
- const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FrameIndex), flags,
MFI.getObjectSize(FrameIndex), MFI.getObjectAlignment(FrameIndex));
@@ -217,14 +218,14 @@ XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti)
bool XCoreFrameLowering::hasFP(const MachineFunction &MF) const {
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
- MF.getFrameInfo()->hasVarSizedObjects();
+ MF.getFrameInfo().hasVarSizedObjects();
}
void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
MachineBasicBlock::iterator MBBI = MBB.begin();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineModuleInfo *MMI = &MF.getMMI();
const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo();
const XCoreInstrInfo &TII = *MF.getSubtarget<XCoreSubtarget>().getInstrInfo();
@@ -233,9 +234,9 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
// to determine the end of the prologue.
DebugLoc dl;
- if (MFI->getMaxAlignment() > getStackAlignment())
+ if (MFI.getMaxAlignment() > getStackAlignment())
report_fatal_error("emitPrologue unsupported alignment: "
- + Twine(MFI->getMaxAlignment()));
+ + Twine(MFI.getMaxAlignment()));
const AttributeSet &PAL = MF.getFunction()->getAttributes();
if (PAL.hasAttrSomewhere(Attribute::Nest))
@@ -244,13 +245,13 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
// Work out frame sizes.
// We will adjust the SP in stages towards the final FrameSize.
- assert(MFI->getStackSize()%4 == 0 && "Misaligned frame size");
- const int FrameSize = MFI->getStackSize() / 4;
+ assert(MFI.getStackSize()%4 == 0 && "Misaligned frame size");
+ const int FrameSize = MFI.getStackSize() / 4;
int Adjusted = 0;
bool saveLR = XFI->hasLRSpillSlot();
bool UseENTSP = saveLR && FrameSize
- && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0);
+ && (MFI.getObjectOffset(XFI->getLRSpillSlot()) == 0);
if (UseENTSP)
saveLR = false;
bool FP = hasFP(MF);
@@ -266,9 +267,9 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
MIB->addRegisterKilled(XCore::LR, MF.getSubtarget().getRegisterInfo(),
true);
if (emitFrameMoves) {
- EmitDefCfaOffset(MBB, MBBI, dl, TII, MMI, Adjusted*4);
+ EmitDefCfaOffset(MBB, MBBI, dl, TII, Adjusted*4);
unsigned DRegNum = MRI->getDwarfRegNum(XCore::LR, true);
- EmitCfiOffset(MBB, MBBI, dl, TII, MMI, DRegNum, 0);
+ EmitCfiOffset(MBB, MBBI, dl, TII, DRegNum, 0);
}
}
@@ -281,7 +282,7 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset");
assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset");
int OffsetFromTop = - SpillList[i].Offset/4;
- IfNeededExtSP(MBB, MBBI, dl, TII, MMI, OffsetFromTop, Adjusted, FrameSize,
+ IfNeededExtSP(MBB, MBBI, dl, TII, OffsetFromTop, Adjusted, FrameSize,
emitFrameMoves);
int Offset = Adjusted - OffsetFromTop;
int Opcode = isImmU6(Offset) ? XCore::STWSP_ru6 : XCore::STWSP_lru6;
@@ -293,12 +294,12 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
MachineMemOperand::MOStore));
if (emitFrameMoves) {
unsigned DRegNum = MRI->getDwarfRegNum(SpillList[i].Reg, true);
- EmitCfiOffset(MBB, MBBI, dl, TII, MMI, DRegNum, SpillList[i].Offset);
+ EmitCfiOffset(MBB, MBBI, dl, TII, DRegNum, SpillList[i].Offset);
}
}
// Complete any remaining Stack adjustment.
- IfNeededExtSP(MBB, MBBI, dl, TII, MMI, FrameSize, Adjusted, FrameSize,
+ IfNeededExtSP(MBB, MBBI, dl, TII, FrameSize, Adjusted, FrameSize,
emitFrameMoves);
assert(Adjusted==FrameSize && "IfNeededExtSP has not completed adjustment");
@@ -306,7 +307,7 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
// Set the FP from the SP.
BuildMI(MBB, MBBI, dl, TII.get(XCore::LDAWSP_ru6), FramePtr).addImm(0);
if (emitFrameMoves)
- EmitDefCfaRegister(MBB, MBBI, dl, TII, MMI,
+ EmitDefCfaRegister(MBB, MBBI, dl, TII, MF,
MRI->getDwarfRegNum(FramePtr, true));
}
@@ -316,9 +317,9 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock::iterator Pos = SpillLabel.first;
++Pos;
const CalleeSavedInfo &CSI = SpillLabel.second;
- int Offset = MFI->getObjectOffset(CSI.getFrameIdx());
+ int Offset = MFI.getObjectOffset(CSI.getFrameIdx());
unsigned DRegNum = MRI->getDwarfRegNum(CSI.getReg(), true);
- EmitCfiOffset(MBB, Pos, dl, TII, MMI, DRegNum, Offset);
+ EmitCfiOffset(MBB, Pos, dl, TII, DRegNum, Offset);
}
if (XFI->hasEHSpillSlot()) {
// The unwinder requires stack slot & CFI offsets for the exception info.
@@ -330,10 +331,10 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
GetEHSpillList(SpillList, MFI, XFI, PersonalityFn,
MF.getSubtarget().getTargetLowering());
assert(SpillList.size()==2 && "Unexpected SpillList size");
- EmitCfiOffset(MBB, MBBI, dl, TII, MMI,
+ EmitCfiOffset(MBB, MBBI, dl, TII,
MRI->getDwarfRegNum(SpillList[0].Reg, true),
SpillList[0].Offset);
- EmitCfiOffset(MBB, MBBI, dl, TII, MMI,
+ EmitCfiOffset(MBB, MBBI, dl, TII,
MRI->getDwarfRegNum(SpillList[1].Reg, true),
SpillList[1].Offset);
}
@@ -342,7 +343,7 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF,
void XCoreFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
const XCoreInstrInfo &TII = *MF.getSubtarget<XCoreSubtarget>().getInstrInfo();
XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
@@ -351,7 +352,7 @@ void XCoreFrameLowering::emitEpilogue(MachineFunction &MF,
// Work out frame sizes.
// We will adjust the SP in stages towards the final FrameSize.
- int RemainingAdj = MFI->getStackSize();
+ int RemainingAdj = MFI.getStackSize();
assert(RemainingAdj%4 == 0 && "Misaligned frame size");
RemainingAdj /= 4;
@@ -377,7 +378,7 @@ void XCoreFrameLowering::emitEpilogue(MachineFunction &MF,
bool restoreLR = XFI->hasLRSpillSlot();
bool UseRETSP = restoreLR && RemainingAdj
- && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0);
+ && (MFI.getObjectOffset(XFI->getLRSpillSlot()) == 0);
if (UseRETSP)
restoreLR = false;
bool FP = hasFP(MF);
@@ -490,8 +491,8 @@ MachineBasicBlock::iterator XCoreFrameLowering::eliminateCallFramePseudoInstr(
if (!hasReservedCallFrame(MF)) {
// Turn the adjcallstackdown instruction into 'extsp <amt>' and the
// adjcallstackup instruction into 'ldaw sp, sp[<amt>]'
- MachineInstr *Old = I;
- uint64_t Amount = Old->getOperand(0).getImm();
+ MachineInstr &Old = *I;
+ uint64_t Amount = Old.getOperand(0).getImm();
if (Amount != 0) {
// We need to keep the stack aligned properly. To do this, we round the
// amount of space needed for the outgoing arguments up to the next
@@ -513,15 +514,14 @@ MachineBasicBlock::iterator XCoreFrameLowering::eliminateCallFramePseudoInstr(
}
MachineInstr *New;
- if (Old->getOpcode() == XCore::ADJCALLSTACKDOWN) {
+ if (Old.getOpcode() == XCore::ADJCALLSTACKDOWN) {
int Opcode = isU6 ? XCore::EXTSP_u6 : XCore::EXTSP_lu6;
- New=BuildMI(MF, Old->getDebugLoc(), TII.get(Opcode))
- .addImm(Amount);
+ New = BuildMI(MF, Old.getDebugLoc(), TII.get(Opcode)).addImm(Amount);
} else {
- assert(Old->getOpcode() == XCore::ADJCALLSTACKUP);
+ assert(Old.getOpcode() == XCore::ADJCALLSTACKUP);
int Opcode = isU6 ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6;
- New=BuildMI(MF, Old->getDebugLoc(), TII.get(Opcode), XCore::SP)
- .addImm(Amount);
+ New = BuildMI(MF, Old.getDebugLoc(), TII.get(Opcode), XCore::SP)
+ .addImm(Amount);
}
// Replace the pseudo instruction with a new instruction...
@@ -543,12 +543,12 @@ void XCoreFrameLowering::determineCalleeSaves(MachineFunction &MF,
bool LRUsed = MRI.isPhysRegModified(XCore::LR);
if (!LRUsed && !MF.getFunction()->isVarArg() &&
- MF.getFrameInfo()->estimateStackSize(MF))
+ MF.getFrameInfo().estimateStackSize(MF))
// If we need to extend the stack it is more efficient to use entsp / retsp.
// We force the LR to be saved so these instructions are used.
LRUsed = true;
- if (MF.getMMI().callsUnwindInit() || MF.getMMI().callsEHReturn()) {
+ if (MF.callsUnwindInit() || MF.callsEHReturn()) {
// The unwinder expects to find spill slots for the exception info regs R0
// & R1. These are used during llvm.eh.return() to 'restore' the exception
// info. N.B. we do not spill or restore R0, R1 during normal operation.
@@ -574,7 +574,7 @@ void XCoreFrameLowering::
processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS) const {
assert(RS && "requiresRegisterScavenging failed");
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterClass *RC = &XCore::GRRegsRegClass;
XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
// Reserve slots close to SP or frame pointer for Scavenging spills.
@@ -582,11 +582,11 @@ processFunctionBeforeFrameFinalized(MachineFunction &MF,
// When using SP for large frames, we may need 2 scratch registers.
// When using FP, for large or small frames, we may need 1 scratch register.
if (XFI->isLargeFrame(MF) || hasFP(MF))
- RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
- RC->getAlignment(),
- false));
+ RS->addScavengingFrameIndex(MFI.CreateStackObject(RC->getSize(),
+ RC->getAlignment(),
+ false));
if (XFI->isLargeFrame(MF) && !hasFP(MF))
- RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
- RC->getAlignment(),
- false));
+ RS->addScavengingFrameIndex(MFI.CreateStackObject(RC->getSize(),
+ RC->getAlignment(),
+ false));
}
diff --git a/contrib/llvm/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp b/contrib/llvm/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp
index bd6baef..4b10e71 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp
@@ -29,10 +29,10 @@ namespace {
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
+ MachineFunctionProperties::Property::NoVRegs);
}
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "XCore FRAME_TO_ARGS_OFFSET Elimination";
}
};
@@ -48,17 +48,17 @@ FunctionPass *llvm::createXCoreFrameToArgsOffsetEliminationPass() {
bool XCoreFTAOElim::runOnMachineFunction(MachineFunction &MF) {
const XCoreInstrInfo &TII =
*static_cast<const XCoreInstrInfo *>(MF.getSubtarget().getInstrInfo());
- unsigned StackSize = MF.getFrameInfo()->getStackSize();
+ unsigned StackSize = MF.getFrameInfo().getStackSize();
for (MachineFunction::iterator MFI = MF.begin(), E = MF.end(); MFI != E;
++MFI) {
MachineBasicBlock &MBB = *MFI;
for (MachineBasicBlock::iterator MBBI = MBB.begin(), EE = MBB.end();
MBBI != EE; ++MBBI) {
if (MBBI->getOpcode() == XCore::FRAME_TO_ARGS_OFFSET) {
- MachineInstr *OldInst = MBBI;
- unsigned Reg = OldInst->getOperand(0).getReg();
+ MachineInstr &OldInst = *MBBI;
+ unsigned Reg = OldInst.getOperand(0).getReg();
MBBI = TII.loadImmediate(MBB, MBBI, Reg, StackSize);
- OldInst->eraseFromParent();
+ OldInst.eraseFromParent();
}
}
}
diff --git a/contrib/llvm/lib/Target/XCore/XCoreISelDAGToDAG.cpp b/contrib/llvm/lib/Target/XCore/XCoreISelDAGToDAG.cpp
index ce25cbc..086d1d5 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreISelDAGToDAG.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreISelDAGToDAG.cpp
@@ -67,7 +67,7 @@ namespace {
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
std::vector<SDValue> &OutOps) override;
- const char *getPassName() const override {
+ StringRef getPassName() const override {
return "XCore DAG->DAG Pattern Instruction Selection";
}
diff --git a/contrib/llvm/lib/Target/XCore/XCoreISelLowering.cpp b/contrib/llvm/lib/Target/XCore/XCoreISelLowering.cpp
index 6f6ac3b..9244d59 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreISelLowering.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreISelLowering.cpp
@@ -1260,7 +1260,7 @@ SDValue XCoreTargetLowering::LowerCCCArguments(
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
@@ -1324,9 +1324,9 @@ SDValue XCoreTargetLowering::LowerCCCArguments(
<< "\n";
}
// Create the frame index object for this incoming parameter...
- int FI = MFI->CreateFixedObject(ObjSize,
- LRSaveSize + VA.getLocMemOffset(),
- true);
+ int FI = MFI.CreateFixedObject(ObjSize,
+ LRSaveSize + VA.getLocMemOffset(),
+ true);
// Create the SelectionDAG nodes corresponding to a load
//from this parameter
@@ -1352,7 +1352,7 @@ SDValue XCoreTargetLowering::LowerCCCArguments(
// address
for (int i = array_lengthof(ArgRegs) - 1; i >= (int)FirstVAReg; --i) {
// Create a stack slot
- int FI = MFI->CreateFixedObject(4, offset, true);
+ int FI = MFI.CreateFixedObject(4, offset, true);
if (i == (int)FirstVAReg) {
XFI->setVarArgsFrameIndex(FI);
}
@@ -1371,8 +1371,8 @@ SDValue XCoreTargetLowering::LowerCCCArguments(
} else {
// This will point to the next argument passed via stack.
XFI->setVarArgsFrameIndex(
- MFI->CreateFixedObject(4, LRSaveSize + CCInfo.getNextStackOffset(),
- true));
+ MFI.CreateFixedObject(4, LRSaveSize + CCInfo.getNextStackOffset(),
+ true));
}
}
@@ -1391,7 +1391,7 @@ SDValue XCoreTargetLowering::LowerCCCArguments(
unsigned Size = ArgDI->Flags.getByValSize();
unsigned Align = std::max(StackSlotSize, ArgDI->Flags.getByValAlign());
// Create a new object on the stack and copy the pointee into it.
- int FI = MFI->CreateStackObject(Size, Align, false);
+ int FI = MFI.CreateStackObject(Size, Align, false);
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
InVals.push_back(FIN);
MemOps.push_back(DAG.getMemcpy(Chain, dl, FIN, ArgDI->SDV,
@@ -1440,7 +1440,7 @@ XCoreTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
XCoreFunctionInfo *XFI =
DAG.getMachineFunction().getInfo<XCoreFunctionInfo>();
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
// CCValAssign - represent the assignment of
// the return value to a location
@@ -1476,7 +1476,7 @@ XCoreTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
int Offset = VA.getLocMemOffset();
unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8;
// Create the frame index object for the memory location.
- int FI = MFI->CreateFixedObject(ObjSize, Offset, false);
+ int FI = MFI.CreateFixedObject(ObjSize, Offset, false);
// Create a SelectionDAG node corresponding to a store
// to this memory location.
diff --git a/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.cpp b/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.cpp
index e0b3e71..7a9c6fc 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.cpp
@@ -184,7 +184,7 @@ static inline XCore::CondCode GetOppositeBranchCondition(XCore::CondCode CC)
/// operands can be passed to other TargetInstrInfo methods to create new
/// branches.
///
-/// Note that RemoveBranch and InsertBranch must be implemented to support
+/// Note that removeBranch and insertBranch must be implemented to support
/// cases where this method returns success.
///
bool XCoreInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
@@ -201,8 +201,8 @@ bool XCoreInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
// Get the last instruction in the block.
- MachineInstr *LastInst = I;
-
+ MachineInstr *LastInst = &*I;
+
// If there is only one terminator instruction, process it.
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
if (IsBRU(LastInst->getOpcode())) {
@@ -224,7 +224,7 @@ bool XCoreInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
}
// Get the instruction before it if it's a terminator.
- MachineInstr *SecondLastInst = I;
+ MachineInstr *SecondLastInst = &*I;
// If there are three terminators, we don't know what sort of block this is.
if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I))
@@ -269,16 +269,18 @@ bool XCoreInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return true;
}
-unsigned XCoreInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned XCoreInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 2 || Cond.size() == 0) &&
"Unexpected number of components!");
-
+ assert(!BytesAdded && "code size not handled");
+
if (!FBB) { // One way branch.
if (Cond.empty()) {
// Unconditional branch
@@ -302,7 +304,9 @@ unsigned XCoreInstrInfo::InsertBranch(MachineBasicBlock &MBB,
}
unsigned
-XCoreInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+XCoreInstrInfo::removeBranch(MachineBasicBlock &MBB, int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end())
return 0;
@@ -363,7 +367,7 @@ void XCoreInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
if (I != MBB.end() && !I->isDebugValue())
DL = I->getDebugLoc();
MachineFunction *MF = MBB.getParent();
- const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FrameIndex),
MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex),
@@ -385,7 +389,7 @@ void XCoreInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
if (I != MBB.end() && !I->isDebugValue())
DL = I->getDebugLoc();
MachineFunction *MF = MBB.getParent();
- const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ const MachineFrameInfo &MFI = MF->getFrameInfo();
MachineMemOperand *MMO = MF->getMachineMemOperand(
MachinePointerInfo::getFixedStack(*MF, FrameIndex),
MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex),
@@ -396,11 +400,9 @@ void XCoreInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
.addMemOperand(MMO);
}
-/// ReverseBranchCondition - Return the inverse opcode of the
-/// specified Branch instruction.
bool XCoreInstrInfo::
-ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
- assert((Cond.size() == 2) &&
+reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
+ assert((Cond.size() == 2) &&
"Invalid XCore branch condition!");
Cond[0].setImm(GetOppositeBranchCondition((XCore::CondCode)Cond[0].getImm()));
return false;
diff --git a/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.h b/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.h
index 783bc6b..a377784 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.h
+++ b/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.h
@@ -55,11 +55,13 @@ public:
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
@@ -77,7 +79,7 @@ public:
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
- bool ReverseBranchCondition(
+ bool reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const override;
// Emit code before MBBI to load immediate value into physical register Reg.
diff --git a/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.td b/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.td
index 8110b91..f1d52d5 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.td
+++ b/contrib/llvm/lib/Target/XCore/XCoreInstrInfo.td
@@ -146,18 +146,10 @@ def immU6 : PatLeaf<(imm), [{
return (uint32_t)N->getZExtValue() < (1 << 6);
}]>;
-def immU10 : PatLeaf<(imm), [{
- return (uint32_t)N->getZExtValue() < (1 << 10);
-}]>;
-
def immU16 : PatLeaf<(imm), [{
return (uint32_t)N->getZExtValue() < (1 << 16);
}]>;
-def immU20 : PatLeaf<(imm), [{
- return (uint32_t)N->getZExtValue() < (1 << 20);
-}]>;
-
def immMskBitp : PatLeaf<(imm), [{ return immMskBitp(N); }]>;
def immBitp : PatLeaf<(imm), [{
diff --git a/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.cpp b/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.cpp
index 03c5fa2..7763ccc 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.cpp
@@ -25,12 +25,9 @@
using namespace llvm;
XCoreMCInstLower::XCoreMCInstLower(class AsmPrinter &asmprinter)
-: Printer(asmprinter) {}
+ : Printer(asmprinter) {}
-void XCoreMCInstLower::Initialize(Mangler *M, MCContext *C) {
- Mang = M;
- Ctx = C;
-}
+void XCoreMCInstLower::Initialize(MCContext *C) { Ctx = C; }
MCOperand XCoreMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
MachineOperandType MOTy,
diff --git a/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.h b/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.h
index 5691478..8fb1593 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.h
+++ b/contrib/llvm/lib/Target/XCore/XCoreMCInstLower.h
@@ -25,11 +25,10 @@ namespace llvm {
class LLVM_LIBRARY_VISIBILITY XCoreMCInstLower {
typedef MachineOperand::MachineOperandType MachineOperandType;
MCContext *Ctx;
- Mangler *Mang;
AsmPrinter &Printer;
public:
XCoreMCInstLower(class AsmPrinter &asmprinter);
- void Initialize(Mangler *mang, MCContext *C);
+ void Initialize(MCContext *C);
void Lower(const MachineInstr *MI, MCInst &OutMI) const;
MCOperand LowerOperand(const MachineOperand& MO, unsigned offset = 0) const;
diff --git a/contrib/llvm/lib/Target/XCore/XCoreMachineFunctionInfo.cpp b/contrib/llvm/lib/Target/XCore/XCoreMachineFunctionInfo.cpp
index 6c77096..e91536c 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreMachineFunctionInfo.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreMachineFunctionInfo.cpp
@@ -17,7 +17,7 @@ void XCoreFunctionInfo::anchor() { }
bool XCoreFunctionInfo::isLargeFrame(const MachineFunction &MF) const {
if (CachedEStackSize == -1) {
- CachedEStackSize = MF.getFrameInfo()->estimateStackSize(MF);
+ CachedEStackSize = MF.getFrameInfo().estimateStackSize(MF);
}
// isLargeFrame() is used when deciding if spill slots should be added to
// allow eliminateFrameIndex() to scavenge registers.
@@ -36,12 +36,12 @@ int XCoreFunctionInfo::createLRSpillSlot(MachineFunction &MF) {
return LRSpillSlot;
}
const TargetRegisterClass *RC = &XCore::GRRegsRegClass;
- MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
if (! MF.getFunction()->isVarArg()) {
// A fixed offset of 0 allows us to save / restore LR using entsp / retsp.
- LRSpillSlot = MFI->CreateFixedObject(RC->getSize(), 0, true);
+ LRSpillSlot = MFI.CreateFixedObject(RC->getSize(), 0, true);
} else {
- LRSpillSlot = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true);
+ LRSpillSlot = MFI.CreateStackObject(RC->getSize(), RC->getAlignment(), true);
}
LRSpillSlotSet = true;
return LRSpillSlot;
@@ -52,8 +52,8 @@ int XCoreFunctionInfo::createFPSpillSlot(MachineFunction &MF) {
return FPSpillSlot;
}
const TargetRegisterClass *RC = &XCore::GRRegsRegClass;
- MachineFrameInfo *MFI = MF.getFrameInfo();
- FPSpillSlot = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ FPSpillSlot = MFI.CreateStackObject(RC->getSize(), RC->getAlignment(), true);
FPSpillSlotSet = true;
return FPSpillSlot;
}
@@ -63,9 +63,9 @@ const int* XCoreFunctionInfo::createEHSpillSlot(MachineFunction &MF) {
return EHSpillSlot;
}
const TargetRegisterClass *RC = &XCore::GRRegsRegClass;
- MachineFrameInfo *MFI = MF.getFrameInfo();
- EHSpillSlot[0] = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true);
- EHSpillSlot[1] = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ EHSpillSlot[0] = MFI.CreateStackObject(RC->getSize(), RC->getAlignment(), true);
+ EHSpillSlot[1] = MFI.CreateStackObject(RC->getSize(), RC->getAlignment(), true);
EHSpillSlotSet = true;
return EHSpillSlot;
}
diff --git a/contrib/llvm/lib/Target/XCore/XCoreRegisterInfo.cpp b/contrib/llvm/lib/Target/XCore/XCoreRegisterInfo.cpp
index 1cfb57d..d34e928 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreRegisterInfo.cpp
@@ -271,8 +271,8 @@ XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
*static_cast<const XCoreInstrInfo *>(MF.getSubtarget().getInstrInfo());
const XCoreFrameLowering *TFI = getFrameLowering(MF);
- int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
- int StackSize = MF.getFrameInfo()->getStackSize();
+ int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex);
+ int StackSize = MF.getFrameInfo().getStackSize();
#ifndef NDEBUG
DEBUG(errs() << "\nFunction : "
diff --git a/contrib/llvm/lib/Target/XCore/XCoreSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/XCore/XCoreSelectionDAGInfo.cpp
index 61fbf0d..c03b0af 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreSelectionDAGInfo.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreSelectionDAGInfo.cpp
@@ -20,7 +20,7 @@ SDValue XCoreSelectionDAGInfo::EmitTargetCodeForMemcpy(
SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
SDValue Size, unsigned Align, bool isVolatile, bool AlwaysInline,
MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const {
- unsigned SizeBitWidth = Size.getValueType().getSizeInBits();
+ unsigned SizeBitWidth = Size.getValueSizeInBits();
// Call __memcpy_4 if the src, dst and size are all 4 byte aligned.
if (!AlwaysInline && (Align & 3) == 0 &&
DAG.MaskedValueIsZero(Size, APInt(SizeBitWidth, 3))) {
diff --git a/contrib/llvm/lib/Target/XCore/XCoreTargetMachine.cpp b/contrib/llvm/lib/Target/XCore/XCoreTargetMachine.cpp
index c3eab80..bf3138f 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreTargetMachine.cpp
@@ -89,7 +89,7 @@ void XCorePassConfig::addPreEmitPass() {
// Force static initialization.
extern "C" void LLVMInitializeXCoreTarget() {
- RegisterTargetMachine<XCoreTargetMachine> X(TheXCoreTarget);
+ RegisterTargetMachine<XCoreTargetMachine> X(getTheXCoreTarget());
}
TargetIRAnalysis XCoreTargetMachine::getTargetIRAnalysis() {
diff --git a/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp b/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp
index abe1ded..ad8693f 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.cpp
@@ -95,11 +95,9 @@ static unsigned getXCoreSectionFlags(SectionKind K, bool IsCPRel) {
return Flags;
}
-MCSection *
-XCoreTargetObjectFile::getExplicitSectionGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
- StringRef SectionName = GV->getSection();
+MCSection *XCoreTargetObjectFile::getExplicitSectionGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ StringRef SectionName = GO->getSection();
// Infer section flags from the section name if we can.
bool IsCPRel = SectionName.startswith(".cp.");
if (IsCPRel && !Kind.isReadOnly())
@@ -108,12 +106,10 @@ XCoreTargetObjectFile::getExplicitSectionGlobal(const GlobalValue *GV,
getXCoreSectionFlags(Kind, IsCPRel));
}
-MCSection *
-XCoreTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
- const TargetMachine &TM) const {
+MCSection *XCoreTargetObjectFile::SelectSectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
- bool UseCPRel = GV->isLocalLinkage(GV->getLinkage());
+ bool UseCPRel = GO->hasLocalLinkage();
if (Kind.isText()) return TextSection;
if (UseCPRel) {
@@ -122,8 +118,8 @@ XCoreTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
if (Kind.isMergeableConst8()) return MergeableConst8Section;
if (Kind.isMergeableConst16()) return MergeableConst16Section;
}
- Type *ObjType = GV->getValueType();
- auto &DL = GV->getParent()->getDataLayout();
+ Type *ObjType = GO->getValueType();
+ auto &DL = GO->getParent()->getDataLayout();
if (TM.getCodeModel() == CodeModel::Small || !ObjType->isSized() ||
DL.getTypeAllocSize(ObjType) < CodeModelLargeSize) {
if (Kind.isReadOnly()) return UseCPRel? ReadOnlySection
diff --git a/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.h b/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.h
index c129d75..5eb423a 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/XCore/XCoreTargetObjectFile.h
@@ -25,12 +25,10 @@ static const unsigned CodeModelLargeSize = 256;
public:
void Initialize(MCContext &Ctx, const TargetMachine &TM) override;
- MCSection *getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
diff --git a/contrib/llvm/lib/Target/XCore/XCoreTargetTransformInfo.h b/contrib/llvm/lib/Target/XCore/XCoreTargetTransformInfo.h
index b2cb889..9617796 100644
--- a/contrib/llvm/lib/Target/XCore/XCoreTargetTransformInfo.h
+++ b/contrib/llvm/lib/Target/XCore/XCoreTargetTransformInfo.h
@@ -41,13 +41,6 @@ public:
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl()),
TLI(ST->getTargetLowering()) {}
- // Provide value semantics. MSVC requires that we spell all of these out.
- XCoreTTIImpl(const XCoreTTIImpl &Arg)
- : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
- XCoreTTIImpl(XCoreTTIImpl &&Arg)
- : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
- TLI(std::move(Arg.TLI)) {}
-
unsigned getNumberOfRegisters(bool Vector) {
if (Vector) {
return 0;
OpenPOWER on IntegriCloud